aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
commitbfef399519ca9b8a4b4c6b563253bad7e0eeffe0 (patch)
treedf8df0b0067b381eab470a3b8f28d14a552a6340
parent6a0372513edbc473b538d2f724efac50405d6fef (diff)
downloadsrc-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.tar.gz
src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.zip
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):vendor/clang/clang-release_34-r197841
Notes
Notes: svn path=/vendor/clang/dist/; revision=259701 svn path=/vendor/clang/clang-release_34-r197841/; revision=259703; tag=vendor/clang/clang-release_34-r197841
-rw-r--r--.clang-format1
-rw-r--r--CMakeLists.txt152
-rw-r--r--CODE_OWNERS.TXT2
-rw-r--r--bindings/python/clang/cindex.py169
-rw-r--r--bindings/python/tests/cindex/test_comment.py40
-rw-r--r--bindings/python/tests/cindex/test_cursor_kind.py11
-rw-r--r--bindings/python/tests/cindex/test_type.py38
-rw-r--r--bindings/xml/comment-xml-schema.rng23
-rw-r--r--docs/AddressSanitizer.rst40
-rw-r--r--docs/CMakeLists.txt51
-rw-r--r--docs/ClangFormat.rst87
-rw-r--r--docs/ClangFormatStyleOptions.rst391
-rw-r--r--docs/ClangTools.rst6
-rw-r--r--docs/CrossCompilation.rst204
-rw-r--r--docs/DataFlowSanitizer.rst158
-rw-r--r--docs/DataFlowSanitizerDesign.rst220
-rw-r--r--docs/InternalsManual.rst23
-rw-r--r--docs/IntroductionToTheClangAST.rst63
-rw-r--r--docs/LanguageExtensions.rst355
-rw-r--r--docs/LeakSanitizer.rst32
-rw-r--r--docs/LibASTMatchersReference.html1093
-rw-r--r--docs/LibTooling.rst2
-rw-r--r--docs/Makefile13
-rw-r--r--docs/MemorySanitizer.rst12
-rw-r--r--docs/Modules.rst88
-rw-r--r--docs/ObjectiveCLiterals.rst6
-rw-r--r--docs/ReleaseNotes.rst316
-rw-r--r--docs/SanitizerSpecialCaseList.rst79
-rw-r--r--docs/ThreadSanitizer.rst16
-rw-r--r--docs/UsersManual.rst264
-rw-r--r--docs/analyzer/DebugChecks.rst17
-rw-r--r--docs/analyzer/IPA.txt2
-rw-r--r--docs/analyzer/conf.py4
-rw-r--r--docs/conf.py4
-rw-r--r--docs/doxygen.cfg.in29
-rw-r--r--docs/doxygen.footer2
-rw-r--r--docs/index.rst5
-rw-r--r--docs/tools/clang.pod69
-rw-r--r--docs/tools/dump_ast_matchers.py73
-rw-r--r--docs/tools/dump_format_style.py143
-rw-r--r--examples/clang-interpreter/Makefile4
-rw-r--r--examples/clang-interpreter/main.cpp13
-rw-r--r--include/clang-c/CXCompilationDatabase.h20
-rw-r--r--include/clang-c/CXString.h2
-rw-r--r--include/clang-c/Index.h72
-rw-r--r--include/clang/ARCMigrate/ARCMT.h2
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h6
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h1
-rw-r--r--include/clang/AST/APValue.h7
-rw-r--r--include/clang/AST/ASTConsumer.h21
-rw-r--r--include/clang/AST/ASTContext.h310
-rw-r--r--include/clang/AST/ASTDiagnostic.h2
-rw-r--r--include/clang/AST/ASTFwd.h28
-rw-r--r--include/clang/AST/ASTImporter.h8
-rw-r--r--include/clang/AST/ASTLambda.h80
-rw-r--r--include/clang/AST/ASTMutationListener.h17
-rw-r--r--include/clang/AST/ASTTypeTraits.h387
-rw-r--r--include/clang/AST/ASTUnresolvedSet.h42
-rw-r--r--include/clang/AST/ASTVector.h55
-rw-r--r--include/clang/AST/Attr.h3
-rw-r--r--include/clang/AST/CXXInheritance.h4
-rw-r--r--include/clang/AST/CanonicalType.h2
-rw-r--r--include/clang/AST/CharUnits.h21
-rw-r--r--include/clang/AST/Comment.h20
-rw-r--r--include/clang/AST/CommentCommandTraits.h5
-rw-r--r--include/clang/AST/CommentCommands.td11
-rw-r--r--include/clang/AST/CommentDiagnostic.h2
-rw-r--r--include/clang/AST/CommentParser.h6
-rw-r--r--include/clang/AST/CommentSema.h9
-rw-r--r--include/clang/AST/Decl.h367
-rw-r--r--include/clang/AST/DeclAccessPair.h9
-rw-r--r--include/clang/AST/DeclBase.h163
-rw-r--r--include/clang/AST/DeclCXX.h1014
-rw-r--r--include/clang/AST/DeclContextInternals.h48
-rw-r--r--include/clang/AST/DeclFriend.h4
-rw-r--r--include/clang/AST/DeclLookups.h22
-rw-r--r--include/clang/AST/DeclObjC.h47
-rw-r--r--include/clang/AST/DeclOpenMP.h26
-rw-r--r--include/clang/AST/DeclTemplate.h691
-rw-r--r--include/clang/AST/DeclarationName.h12
-rw-r--r--include/clang/AST/EvaluatedExprVisitor.h2
-rw-r--r--include/clang/AST/Expr.h245
-rw-r--r--include/clang/AST/ExprCXX.h688
-rw-r--r--include/clang/AST/ExprObjC.h23
-rw-r--r--include/clang/AST/ExternalASTSource.h7
-rw-r--r--include/clang/AST/GlobalDecl.h1
-rw-r--r--include/clang/AST/LambdaMangleContext.h38
-rw-r--r--include/clang/AST/Mangle.h117
-rw-r--r--include/clang/AST/MangleNumberingContext.h59
-rw-r--r--include/clang/AST/NestedNameSpecifier.h6
-rw-r--r--include/clang/AST/ParentMap.h5
-rw-r--r--include/clang/AST/PrettyPrinter.h13
-rw-r--r--include/clang/AST/RawCommentList.h31
-rw-r--r--include/clang/AST/RecordLayout.h55
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h330
-rw-r--r--include/clang/AST/Redeclarable.h52
-rw-r--r--include/clang/AST/Stmt.h104
-rw-r--r--include/clang/AST/StmtCXX.h4
-rw-r--r--include/clang/AST/StmtIterator.h32
-rw-r--r--include/clang/AST/StmtObjC.h9
-rw-r--r--include/clang/AST/StmtOpenMP.h528
-rw-r--r--include/clang/AST/StmtVisitor.h36
-rw-r--r--include/clang/AST/TemplateBase.h108
-rw-r--r--include/clang/AST/Type.h113
-rw-r--r--include/clang/AST/TypeLoc.h142
-rw-r--r--include/clang/AST/TypeNodes.def3
-rw-r--r--include/clang/AST/TypeOrdering.h16
-rw-r--r--include/clang/AST/TypeVisitor.h44
-rw-r--r--include/clang/AST/UnresolvedSet.h15
-rw-r--r--include/clang/AST/VTTBuilder.h49
-rw-r--r--include/clang/AST/VTableBuilder.h301
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h21
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h718
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h786
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h189
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h185
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h151
-rw-r--r--include/clang/ASTMatchers/Dynamic/Registry.h75
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h261
-rw-r--r--include/clang/Analysis/Analyses/Consumed.h264
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h8
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h4
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h22
-rw-r--r--include/clang/Analysis/AnalysisContext.h6
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--include/clang/Analysis/CFG.h90
-rw-r--r--include/clang/Analysis/CallGraph.h4
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h3
-rw-r--r--include/clang/Analysis/Support/BlkExprDeclBitVector.h307
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h107
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtVisitor.h59
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h175
-rw-r--r--include/clang/Basic/ABI.h142
-rw-r--r--include/clang/Basic/Attr.td274
-rw-r--r--include/clang/Basic/AttrKinds.h2
-rw-r--r--include/clang/Basic/Builtins.def471
-rw-r--r--include/clang/Basic/Builtins.h28
-rw-r--r--include/clang/Basic/BuiltinsAArch64.def9
-rw-r--r--include/clang/Basic/BuiltinsARM.def25
-rw-r--r--include/clang/Basic/BuiltinsMips.def712
-rw-r--r--include/clang/Basic/BuiltinsNVPTX.def744
-rw-r--r--include/clang/Basic/BuiltinsX86.def16
-rw-r--r--include/clang/Basic/BuiltinsXCore.def22
-rw-r--r--include/clang/Basic/CapturedStmt.h3
-rw-r--r--include/clang/Basic/DeclNodes.td4
-rw-r--r--include/clang/Basic/Diagnostic.h16
-rw-r--r--include/clang/Basic/Diagnostic.td43
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td16
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td20
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td24
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticGroups.td102
-rw-r--r--include/clang/Basic/DiagnosticIDs.h34
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td66
-rw-r--r--include/clang/Basic/DiagnosticOptions.def1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td81
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td760
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td13
-rw-r--r--include/clang/Basic/FileManager.h36
-rw-r--r--include/clang/Basic/FileSystemStatCache.h47
-rw-r--r--include/clang/Basic/IdentifierTable.h82
-rw-r--r--include/clang/Basic/Lambda.h15
-rw-r--r--include/clang/Basic/LangOptions.def33
-rw-r--r--include/clang/Basic/LangOptions.h7
-rw-r--r--include/clang/Basic/Linkage.h40
-rw-r--r--include/clang/Basic/Module.h57
-rw-r--r--include/clang/Basic/ObjCRuntime.h7
-rw-r--r--include/clang/Basic/OpenMPKinds.def31
-rw-r--r--include/clang/Basic/OpenMPKinds.h28
-rw-r--r--include/clang/Basic/OperatorKinds.h2
-rw-r--r--include/clang/Basic/PartialDiagnostic.h21
-rw-r--r--include/clang/Basic/Sanitizers.def23
-rw-r--r--include/clang/Basic/SourceLocation.h2
-rw-r--r--include/clang/Basic/SourceManager.h58
-rw-r--r--include/clang/Basic/Specifiers.h35
-rw-r--r--include/clang/Basic/StmtNodes.td6
-rw-r--r--include/clang/Basic/TargetBuiltins.h14
-rw-r--r--include/clang/Basic/TargetCXXABI.h24
-rw-r--r--include/clang/Basic/TargetInfo.h47
-rw-r--r--include/clang/Basic/TargetOptions.h3
-rw-r--r--include/clang/Basic/TemplateKinds.h3
-rw-r--r--include/clang/Basic/TokenKinds.def17
-rw-r--r--include/clang/Basic/TypeTraits.h1
-rw-r--r--include/clang/Basic/Visibility.h16
-rw-r--r--include/clang/Basic/arm_neon.td888
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h361
-rw-r--r--include/clang/CodeGen/CodeGenABITypes.h80
-rw-r--r--include/clang/Driver/Action.h14
-rw-r--r--include/clang/Driver/Arg.h133
-rw-r--r--include/clang/Driver/ArgList.h442
-rw-r--r--include/clang/Driver/CC1AsOptions.h13
-rw-r--r--include/clang/Driver/CC1AsOptions.td11
-rw-r--r--include/clang/Driver/CC1Options.td43
-rw-r--r--include/clang/Driver/CLCompatOptions.td255
-rw-r--r--include/clang/Driver/CMakeLists.txt12
-rw-r--r--include/clang/Driver/Compilation.h55
-rw-r--r--include/clang/Driver/Driver.h77
-rw-r--r--include/clang/Driver/DriverDiagnostic.h2
-rw-r--r--include/clang/Driver/Job.h71
-rw-r--r--include/clang/Driver/Makefile8
-rw-r--r--include/clang/Driver/OptParser.td152
-rw-r--r--include/clang/Driver/OptSpecifier.h41
-rw-r--r--include/clang/Driver/OptTable.h161
-rw-r--r--include/clang/Driver/Option.h204
-rw-r--r--include/clang/Driver/Options.h28
-rw-r--r--include/clang/Driver/Options.td535
-rw-r--r--include/clang/Driver/SanitizerArgs.h147
-rw-r--r--include/clang/Driver/Tool.h13
-rw-r--r--include/clang/Driver/ToolChain.h102
-rw-r--r--include/clang/Driver/Types.def2
-rw-r--r--include/clang/Driver/Types.h4
-rw-r--r--include/clang/Driver/Util.h5
-rw-r--r--include/clang/Edit/Commit.h16
-rw-r--r--include/clang/Edit/EditedSource.h9
-rw-r--r--include/clang/Edit/Rewriters.h8
-rw-r--r--include/clang/Format/Format.h286
-rw-r--r--include/clang/Frontend/ASTConsumers.h9
-rw-r--r--include/clang/Frontend/ASTUnit.h14
-rw-r--r--include/clang/Frontend/CodeGenOptions.def14
-rw-r--r--include/clang/Frontend/CodeGenOptions.h12
-rw-r--r--include/clang/Frontend/CompilerInstance.h36
-rw-r--r--include/clang/Frontend/CompilerInvocation.h15
-rw-r--r--include/clang/Frontend/DependencyOutputOptions.h2
-rw-r--r--include/clang/Frontend/FrontendAction.h10
-rw-r--r--include/clang/Frontend/FrontendActions.h10
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h2
-rw-r--r--include/clang/Frontend/FrontendOptions.h33
-rw-r--r--include/clang/Frontend/TextDiagnostic.h3
-rw-r--r--include/clang/Frontend/Utils.h23
-rw-r--r--include/clang/Index/CommentToXML.h50
-rw-r--r--include/clang/Index/USRGeneration.h54
-rw-r--r--include/clang/Lex/DirectoryLookup.h10
-rw-r--r--include/clang/Lex/HeaderSearch.h65
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h8
-rw-r--r--include/clang/Lex/LexDiagnostic.h2
-rw-r--r--include/clang/Lex/Lexer.h69
-rw-r--r--include/clang/Lex/LiteralSupport.h20
-rw-r--r--include/clang/Lex/MacroInfo.h4
-rw-r--r--include/clang/Lex/ModuleLoader.h4
-rw-r--r--include/clang/Lex/ModuleMap.h86
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h56
-rw-r--r--include/clang/Lex/PPCallbacks.h95
-rw-r--r--include/clang/Lex/PPConditionalDirectiveRecord.h5
-rw-r--r--include/clang/Lex/PTHLexer.h2
-rw-r--r--include/clang/Lex/PreprocessingRecord.h3
-rw-r--r--include/clang/Lex/Preprocessor.h79
-rw-r--r--include/clang/Lex/PreprocessorLexer.h6
-rw-r--r--include/clang/Lex/Token.h9
-rw-r--r--include/clang/Lex/TokenLexer.h4
-rw-r--r--include/clang/Parse/CMakeLists.txt9
-rw-r--r--include/clang/Parse/Makefile16
-rw-r--r--include/clang/Parse/ParseDiagnostic.h2
-rw-r--r--include/clang/Parse/Parser.h185
-rw-r--r--include/clang/Rewrite/Core/HTMLRewrite.h2
-rw-r--r--include/clang/Rewrite/Core/Rewriter.h17
-rw-r--r--include/clang/Sema/AnalysisBasedWarnings.h1
-rw-r--r--include/clang/Sema/AttributeList.h233
-rw-r--r--include/clang/Sema/CMakeLists.txt5
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h20
-rw-r--r--include/clang/Sema/DeclSpec.h120
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h24
-rw-r--r--include/clang/Sema/ExternalSemaSource.h44
-rw-r--r--include/clang/Sema/IdentifierResolver.h10
-rw-r--r--include/clang/Sema/Initialization.h117
-rw-r--r--include/clang/Sema/Lookup.h119
-rw-r--r--include/clang/Sema/Makefile7
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h30
-rw-r--r--include/clang/Sema/Overload.h77
-rw-r--r--include/clang/Sema/Ownership.h24
-rw-r--r--include/clang/Sema/Scope.h23
-rw-r--r--include/clang/Sema/ScopeInfo.h269
-rw-r--r--include/clang/Sema/Sema.h970
-rw-r--r--include/clang/Sema/SemaDiagnostic.h2
-rw-r--r--include/clang/Sema/SemaInternal.h39
-rw-r--r--include/clang/Sema/SemaLambda.h39
-rw-r--r--include/clang/Sema/Template.h123
-rw-r--r--include/clang/Sema/TemplateDeduction.h122
-rw-r--r--include/clang/Sema/TypoCorrection.h105
-rw-r--r--include/clang/Serialization/ASTBitCodes.h30
-rw-r--r--include/clang/Serialization/ASTReader.h61
-rw-r--r--include/clang/Serialization/ASTWriter.h23
-rw-r--r--include/clang/Serialization/GlobalModuleIndex.h1
-rw-r--r--include/clang/Serialization/ModuleManager.h6
-rw-r--r--include/clang/Serialization/SerializationDiagnostic.h2
-rw-r--r--include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h223
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def12
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h25
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h (renamed from include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h)11
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h56
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h63
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h64
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h7
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h33
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h48
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h2
-rw-r--r--include/clang/Tooling/ArgumentsAdjusters.h6
-rw-r--r--include/clang/Tooling/CommonOptionsParser.h2
-rw-r--r--include/clang/Tooling/CompilationDatabase.h14
-rw-r--r--include/clang/Tooling/Refactoring.h103
-rw-r--r--include/clang/Tooling/ReplacementsYaml.h88
-rw-r--r--include/clang/Tooling/Tooling.h170
-rw-r--r--lib/ARCMigrate/ARCMT.cpp13
-rw-r--r--lib/ARCMigrate/CMakeLists.txt1
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp57
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp1572
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp11
-rw-r--r--lib/ARCMigrate/Transforms.cpp22
-rw-r--r--lib/ARCMigrate/Transforms.h6
-rw-r--r--lib/AST/APValue.cpp34
-rw-r--r--lib/AST/ASTContext.cpp816
-rw-r--r--lib/AST/ASTDiagnostic.cpp83
-rw-r--r--lib/AST/ASTDumper.cpp219
-rw-r--r--lib/AST/ASTImporter.cpp291
-rw-r--r--lib/AST/ASTTypeTraits.cpp105
-rw-r--r--lib/AST/AttrImpl.cpp1
-rw-r--r--lib/AST/CMakeLists.txt4
-rw-r--r--lib/AST/CXXABI.h8
-rw-r--r--lib/AST/CXXInheritance.cpp14
-rw-r--r--lib/AST/Comment.cpp15
-rw-r--r--lib/AST/CommentCommandTraits.cpp43
-rw-r--r--lib/AST/CommentLexer.cpp21
-rw-r--r--lib/AST/CommentParser.cpp21
-rw-r--r--lib/AST/CommentSema.cpp145
-rw-r--r--lib/AST/Decl.cpp800
-rw-r--r--lib/AST/DeclBase.cpp195
-rw-r--r--lib/AST/DeclCXX.cpp198
-rw-r--r--lib/AST/DeclFriend.cpp5
-rw-r--r--lib/AST/DeclObjC.cpp86
-rw-r--r--lib/AST/DeclOpenMP.cpp11
-rw-r--r--lib/AST/DeclPrinter.cpp29
-rw-r--r--lib/AST/DeclTemplate.cpp357
-rw-r--r--lib/AST/DeclarationName.cpp142
-rw-r--r--lib/AST/DumpXML.cpp1053
-rw-r--r--lib/AST/Expr.cpp462
-rw-r--r--lib/AST/ExprCXX.cpp268
-rw-r--r--lib/AST/ExprClassification.cpp13
-rw-r--r--lib/AST/ExprConstant.cpp1981
-rw-r--r--lib/AST/InheritViz.cpp38
-rw-r--r--lib/AST/ItaniumCXXABI.cpp18
-rw-r--r--lib/AST/ItaniumMangle.cpp577
-rw-r--r--lib/AST/Mangle.cpp153
-rw-r--r--lib/AST/MangleNumberingContext.cpp (renamed from lib/AST/LambdaMangleContext.cpp)28
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp21
-rw-r--r--lib/AST/MicrosoftMangle.cpp992
-rw-r--r--lib/AST/NestedNameSpecifier.cpp3
-rw-r--r--lib/AST/ParentMap.cpp30
-rw-r--r--lib/AST/RawCommentList.cpp106
-rw-r--r--lib/AST/RecordLayout.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp1484
-rw-r--r--lib/AST/Stmt.cpp266
-rw-r--r--lib/AST/StmtIterator.cpp63
-rw-r--r--lib/AST/StmtPrinter.cpp112
-rw-r--r--lib/AST/StmtProfile.cpp75
-rw-r--r--lib/AST/TemplateBase.cpp81
-rw-r--r--lib/AST/Type.cpp128
-rw-r--r--lib/AST/TypeLoc.cpp53
-rw-r--r--lib/AST/TypePrinter.cpp130
-rw-r--r--lib/AST/VTableBuilder.cpp1662
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp425
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp95
-rw-r--r--lib/ASTMatchers/CMakeLists.txt2
-rw-r--r--lib/ASTMatchers/Dynamic/CMakeLists.txt16
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp220
-rw-r--r--lib/ASTMatchers/Dynamic/Makefile13
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h453
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp420
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp345
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp256
-rw-r--r--lib/ASTMatchers/Makefile2
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp39
-rw-r--r--lib/Analysis/CFG.cpp330
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp9
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/Consumed.cpp1521
-rw-r--r--lib/Analysis/FormatString.cpp50
-rw-r--r--lib/Analysis/LiveVariables.cpp3
-rw-r--r--lib/Analysis/PrintfFormatString.cpp31
-rw-r--r--lib/Analysis/ReachableCode.cpp13
-rw-r--r--lib/Analysis/ScanfFormatString.cpp18
-rw-r--r--lib/Analysis/ThreadSafety.cpp160
-rw-r--r--lib/Analysis/UninitializedValues.cpp30
-rw-r--r--lib/Basic/Builtins.cpp32
-rw-r--r--lib/Basic/DiagnosticIDs.cpp104
-rw-r--r--lib/Basic/FileManager.cpp149
-rw-r--r--lib/Basic/FileSystemStatCache.cpp60
-rw-r--r--lib/Basic/IdentifierTable.cpp52
-rw-r--r--lib/Basic/Module.cpp84
-rw-r--r--lib/Basic/ObjCRuntime.cpp8
-rw-r--r--lib/Basic/OpenMPKinds.cpp94
-rw-r--r--lib/Basic/OperatorPrecedence.cpp2
-rw-r--r--lib/Basic/SourceManager.cpp216
-rw-r--r--lib/Basic/TargetInfo.cpp79
-rw-r--r--lib/Basic/Targets.cpp2183
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/CMakeLists.txt13
-rw-r--r--lib/CodeGen/ABIInfo.h147
-rw-r--r--lib/CodeGen/BackendUtil.cpp40
-rw-r--r--lib/CodeGen/CGAtomic.cpp231
-rw-r--r--lib/CodeGen/CGBlocks.cpp40
-rw-r--r--lib/CodeGen/CGBuiltin.cpp2556
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp4
-rw-r--r--lib/CodeGen/CGCXX.cpp249
-rw-r--r--lib/CodeGen/CGCXXABI.cpp42
-rw-r--r--lib/CodeGen/CGCXXABI.h157
-rw-r--r--lib/CodeGen/CGCall.cpp237
-rw-r--r--lib/CodeGen/CGCall.h200
-rw-r--r--lib/CodeGen/CGClass.cpp393
-rw-r--r--lib/CodeGen/CGCleanup.cpp39
-rw-r--r--lib/CodeGen/CGCleanup.h12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1355
-rw-r--r--lib/CodeGen/CGDebugInfo.h176
-rw-r--r--lib/CodeGen/CGDecl.cpp119
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp80
-rw-r--r--lib/CodeGen/CGException.cpp33
-rw-r--r--lib/CodeGen/CGExpr.cpp939
-rw-r--r--lib/CodeGen/CGExprAgg.cpp285
-rw-r--r--lib/CodeGen/CGExprCXX.cpp235
-rw-r--r--lib/CodeGen/CGExprComplex.cpp167
-rw-r--r--lib/CodeGen/CGExprConstant.cpp95
-rw-r--r--lib/CodeGen/CGExprScalar.cpp402
-rw-r--r--lib/CodeGen/CGObjC.cpp30
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp59
-rw-r--r--lib/CodeGen/CGObjCMac.cpp29
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp1
-rw-r--r--lib/CodeGen/CGRTTI.cpp62
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp54
-rw-r--r--lib/CodeGen/CGStmt.cpp184
-rw-r--r--lib/CodeGen/CGVTT.cpp34
-rw-r--r--lib/CodeGen/CGVTables.cpp363
-rw-r--r--lib/CodeGen/CGVTables.h40
-rw-r--r--lib/CodeGen/CGValue.h30
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenABITypes.cpp69
-rw-r--r--lib/CodeGen/CodeGenAction.cpp17
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp152
-rw-r--r--lib/CodeGen/CodeGenFunction.h714
-rw-r--r--lib/CodeGen/CodeGenModule.cpp723
-rw-r--r--lib/CodeGen/CodeGenModule.h120
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp73
-rw-r--r--lib/CodeGen/CodeGenTBAA.h2
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp7
-rw-r--r--lib/CodeGen/CodeGenTypes.h7
-rw-r--r--lib/CodeGen/EHScopeStack.h489
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp514
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp1289
-rw-r--r--lib/CodeGen/MicrosoftVBTables.cpp233
-rw-r--r--lib/CodeGen/MicrosoftVBTables.h129
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp36
-rw-r--r--lib/CodeGen/TargetInfo.cpp842
-rw-r--r--lib/CodeGen/TargetInfo.h34
-rw-r--r--lib/Driver/Action.cpp1
-rw-r--r--lib/Driver/Arg.cpp123
-rw-r--r--lib/Driver/ArgList.cpp423
-rw-r--r--lib/Driver/CC1AsOptions.cpp21
-rw-r--r--lib/Driver/CMakeLists.txt7
-rw-r--r--lib/Driver/Compilation.cpp199
-rw-r--r--lib/Driver/Driver.cpp512
-rw-r--r--lib/Driver/DriverOptions.cpp19
-rw-r--r--lib/Driver/InputInfo.h11
-rw-r--r--lib/Driver/Job.cpp163
-rw-r--r--lib/Driver/OptTable.cpp388
-rw-r--r--lib/Driver/Option.cpp200
-rw-r--r--lib/Driver/SanitizerArgs.cpp389
-rw-r--r--lib/Driver/SanitizerArgs.h220
-rw-r--r--lib/Driver/ToolChain.cpp64
-rw-r--r--lib/Driver/ToolChains.cpp1199
-rw-r--r--lib/Driver/ToolChains.h292
-rw-r--r--lib/Driver/Tools.cpp2230
-rw-r--r--lib/Driver/Tools.h188
-rw-r--r--lib/Driver/Types.cpp17
-rw-r--r--lib/Driver/WindowsToolChain.cpp55
-rw-r--r--lib/Edit/Commit.cpp14
-rw-r--r--lib/Format/BreakableToken.cpp504
-rw-r--r--lib/Format/BreakableToken.h349
-rw-r--r--lib/Format/CMakeLists.txt2
-rw-r--r--lib/Format/ContinuationIndenter.cpp884
-rw-r--r--lib/Format/ContinuationIndenter.h327
-rw-r--r--lib/Format/Encoding.h144
-rw-r--r--lib/Format/Format.cpp2231
-rw-r--r--lib/Format/FormatToken.cpp204
-rw-r--r--lib/Format/FormatToken.h452
-rw-r--r--lib/Format/TokenAnnotator.cpp1096
-rw-r--r--lib/Format/TokenAnnotator.h257
-rw-r--r--lib/Format/UnwrappedLineParser.cpp862
-rw-r--r--lib/Format/UnwrappedLineParser.h163
-rw-r--r--lib/Format/WhitespaceManager.cpp413
-rw-r--r--lib/Format/WhitespaceManager.h182
-rw-r--r--lib/Frontend/ASTConsumers.cpp54
-rw-r--r--lib/Frontend/ASTUnit.cpp294
-rw-r--r--lib/Frontend/CacheTokens.cpp45
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp6
-rw-r--r--lib/Frontend/CompilerInstance.cpp219
-rw-r--r--lib/Frontend/CompilerInvocation.cpp281
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp9
-rw-r--r--lib/Frontend/DependencyFile.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp12
-rw-r--r--lib/Frontend/FrontendActions.cpp27
-rw-r--r--lib/Frontend/FrontendOptions.cpp1
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp24
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp47
-rw-r--r--lib/Frontend/InitPreprocessor.cpp76
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp20
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp97
-rw-r--r--lib/Frontend/TextDiagnostic.cpp64
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp3
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp8
-rw-r--r--lib/FrontendTool/CMakeLists.txt18
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp60
-rw-r--r--lib/Headers/CMakeLists.txt17
-rw-r--r--lib/Headers/Intrin.h784
-rw-r--r--lib/Headers/avx2intrin.h25
-rw-r--r--lib/Headers/avxintrin.h22
-rw-r--r--lib/Headers/cpuid.h126
-rw-r--r--lib/Headers/emmintrin.h36
-rw-r--r--lib/Headers/f16cintrin.h4
-rw-r--r--lib/Headers/immintrin.h4
-rw-r--r--lib/Headers/limits.h6
-rw-r--r--lib/Headers/module.map11
-rw-r--r--lib/Headers/prfchwintrin.h5
-rw-r--r--lib/Headers/rdseedintrin.h4
-rw-r--r--lib/Headers/rtmintrin.h5
-rw-r--r--lib/Headers/shaintrin.h74
-rw-r--r--lib/Headers/smmintrin.h15
-rw-r--r--lib/Headers/tbmintrin.h158
-rw-r--r--lib/Headers/tgmath.h6
-rw-r--r--lib/Headers/unwind.h159
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h18
-rw-r--r--lib/Headers/xopintrin.h393
-rw-r--r--lib/Index/CMakeLists.txt11
-rw-r--r--lib/Index/CommentToXML.cpp1136
-rw-r--r--lib/Index/Makefile13
-rw-r--r--lib/Index/SimpleFormatContext.h (renamed from tools/libclang/SimpleFormatContext.h)8
-rw-r--r--lib/Index/USRGeneration.cpp803
-rw-r--r--lib/Lex/HeaderMap.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp125
-rw-r--r--lib/Lex/Lexer.cpp470
-rw-r--r--lib/Lex/LiteralSupport.cpp156
-rw-r--r--lib/Lex/ModuleMap.cpp392
-rw-r--r--lib/Lex/PPConditionalDirectiveRecord.cpp4
-rw-r--r--lib/Lex/PPDirectives.cpp219
-rw-r--r--lib/Lex/PPExpressions.cpp29
-rw-r--r--lib/Lex/PPLexerChange.cpp86
-rw-r--r--lib/Lex/PPMacroExpansion.cpp280
-rw-r--r--lib/Lex/PTHLexer.cpp89
-rw-r--r--lib/Lex/Pragma.cpp206
-rw-r--r--lib/Lex/PreprocessingRecord.cpp3
-rw-r--r--lib/Lex/Preprocessor.cpp48
-rw-r--r--lib/Lex/PreprocessorLexer.cpp5
-rw-r--r--lib/Lex/TokenLexer.cpp61
-rw-r--r--lib/Lex/UnicodeCharSets.h102
-rwxr-xr-xlib/Makefile8
-rw-r--r--lib/Parse/CMakeLists.txt3
-rw-r--r--lib/Parse/ParseAST.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp548
-rw-r--r--lib/Parse/ParseDecl.cpp723
-rw-r--r--lib/Parse/ParseDeclCXX.cpp421
-rw-r--r--lib/Parse/ParseExpr.cpp172
-rw-r--r--lib/Parse/ParseExprCXX.cpp252
-rw-r--r--lib/Parse/ParseInit.cpp10
-rw-r--r--lib/Parse/ParseObjc.cpp109
-rw-r--r--lib/Parse/ParseOpenMP.cpp347
-rw-r--r--lib/Parse/ParsePragma.cpp85
-rw-r--r--lib/Parse/ParsePragma.h15
-rw-r--r--lib/Parse/ParseStmt.cpp209
-rw-r--r--lib/Parse/ParseTemplate.cpp115
-rw-r--r--lib/Parse/ParseTentative.cpp418
-rw-r--r--lib/Parse/Parser.cpp184
-rw-r--r--lib/Parse/RAIIObjectsForParser.h7
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp5
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp5
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp2
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp10
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp71
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp2
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp208
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp66
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp213
-rw-r--r--lib/Sema/AttributeList.cpp40
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/DeclSpec.cpp100
-rw-r--r--lib/Sema/IdentifierResolver.cpp40
-rw-r--r--lib/Sema/JumpDiagnostics.cpp9
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp31
-rw-r--r--lib/Sema/ScopeInfo.cpp15
-rw-r--r--lib/Sema/Sema.cpp188
-rw-r--r--lib/Sema/SemaAccess.cpp30
-rw-r--r--lib/Sema/SemaAttr.cpp42
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp50
-rw-r--r--lib/Sema/SemaCast.cpp142
-rw-r--r--lib/Sema/SemaChecking.cpp844
-rw-r--r--lib/Sema/SemaCodeComplete.cpp218
-rw-r--r--lib/Sema/SemaDecl.cpp2406
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1965
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2108
-rw-r--r--lib/Sema/SemaDeclObjC.cpp408
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp204
-rw-r--r--lib/Sema/SemaExpr.cpp2496
-rw-r--r--lib/Sema/SemaExprCXX.cpp972
-rw-r--r--lib/Sema/SemaExprMember.cpp175
-rw-r--r--lib/Sema/SemaExprObjC.cpp296
-rw-r--r--lib/Sema/SemaFixItUtils.cpp28
-rw-r--r--lib/Sema/SemaInit.cpp1181
-rw-r--r--lib/Sema/SemaLambda.cpp948
-rw-r--r--lib/Sema/SemaLookup.cpp924
-rw-r--r--lib/Sema/SemaObjCProperty.cpp444
-rw-r--r--lib/Sema/SemaOpenMP.cpp1207
-rw-r--r--lib/Sema/SemaOverload.cpp1531
-rw-r--r--lib/Sema/SemaPseudoObject.cpp39
-rw-r--r--lib/Sema/SemaStmt.cpp573
-rw-r--r--lib/Sema/SemaStmtAsm.cpp11
-rw-r--r--lib/Sema/SemaTemplate.cpp1386
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp699
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp295
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp1403
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp97
-rw-r--r--lib/Sema/SemaType.cpp810
-rw-r--r--lib/Sema/TargetAttributesSema.cpp136
-rw-r--r--lib/Sema/TreeTransform.h691
-rw-r--r--lib/Sema/TypeLocBuilder.cpp136
-rw-r--r--lib/Sema/TypeLocBuilder.h86
-rw-r--r--lib/Serialization/ASTCommon.cpp5
-rw-r--r--lib/Serialization/ASTCommon.h4
-rw-r--r--lib/Serialization/ASTReader.cpp293
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp772
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp145
-rw-r--r--lib/Serialization/ASTWriter.cpp229
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp170
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp110
-rw-r--r--lib/Serialization/GeneratePCH.cpp17
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp8
-rw-r--r--lib/Serialization/ModuleManager.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp365
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp84
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp59
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp63
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td8
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp50
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp226
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp120
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp27
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp220
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp1194
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp90
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp61
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/CommonBugCategories.cpp (renamed from lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp)10
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp143
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp79
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp45
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp59
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp85
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp83
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h45
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp126
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp139
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp36
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp59
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h6
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp212
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp72
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp120
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp29
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp5
-rw-r--r--lib/Tooling/CompilationDatabase.cpp185
-rw-r--r--lib/Tooling/FileMatchTrie.cpp2
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp4
-rw-r--r--lib/Tooling/Refactoring.cpp190
-rw-r--r--lib/Tooling/Tooling.cpp232
-rw-r--r--runtime/compiler-rt/Makefile68
-rw-r--r--runtime/libcxx/Makefile2
-rw-r--r--test/.clang-format2
-rw-r--r--test/ARCMT/Inputs/test1.m.in10
-rw-r--r--test/ARCMT/Inputs/test1.m.in.result10
-rw-r--r--test/ARCMT/checking-in-arc.m51
-rw-r--r--test/ARCMT/checking.m14
-rw-r--r--test/ARCMT/driver-migrate.m3
-rw-r--r--test/ARCMT/lit.local.cfg2
-rw-r--r--test/ARCMT/objcmt-arc-cf-annotations.m2047
-rw-r--r--test/ARCMT/objcmt-arc-cf-annotations.m.result2093
-rw-r--r--test/ARCMT/objcmt-atomic-property.m229
-rw-r--r--test/ARCMT/objcmt-atomic-property.m.result202
-rw-r--r--test/ARCMT/objcmt-deprecated-category.m48
-rw-r--r--test/ARCMT/objcmt-deprecated-category.m.result48
-rw-r--r--test/ARCMT/objcmt-instancetype-2.m103
-rw-r--r--test/ARCMT/objcmt-instancetype-2.m.result103
-rw-r--r--test/ARCMT/objcmt-instancetype.m111
-rw-r--r--test/ARCMT/objcmt-instancetype.m.result111
-rw-r--r--test/ARCMT/objcmt-migrate-all.m135
-rw-r--r--test/ARCMT/objcmt-migrate-all.m.result134
-rw-r--r--test/ARCMT/objcmt-ns-macros.m296
-rw-r--r--test/ARCMT/objcmt-ns-macros.m.result279
-rw-r--r--test/ARCMT/objcmt-ns-nonatomic-iosonly.m236
-rw-r--r--test/ARCMT/objcmt-ns-nonatomic-iosonly.m.result209
-rw-r--r--test/ARCMT/objcmt-ns-returns-inner-pointer.m129
-rw-r--r--test/ARCMT/objcmt-ns-returns-inner-pointer.m.result129
-rw-r--r--test/ARCMT/objcmt-property-availability.m46
-rw-r--r--test/ARCMT/objcmt-property-availability.m.result43
-rw-r--r--test/ARCMT/objcmt-property.m237
-rw-r--r--test/ARCMT/objcmt-property.m.result210
-rw-r--r--test/ARCMT/objcmt-protocol-conformance.m114
-rw-r--r--test/ARCMT/objcmt-protocol-conformance.m.result114
-rw-r--r--test/ARCMT/verify.m2
-rw-r--r--test/ARCMT/whitelisted/Inputs/header1.h1
-rw-r--r--test/ARCMT/whitelisted/header1.h5
-rw-r--r--test/ARCMT/whitelisted/header1.h.result4
-rw-r--r--test/ARCMT/whitelisted/header2.h5
-rw-r--r--test/ARCMT/whitelisted/header2.h.result4
-rw-r--r--test/ARCMT/whitelisted/objcmt-with-whitelist.m12
-rw-r--r--test/ARCMT/with-arc-mode-check.m9
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m13
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m.result12
-rw-r--r--test/ASTMerge/Inputs/lit.local.cfg1
-rw-r--r--test/ASTMerge/category.m2
-rw-r--r--test/ASTMerge/class-template.cpp2
-rw-r--r--test/ASTMerge/class.cpp2
-rw-r--r--test/ASTMerge/enum.c2
-rw-r--r--test/ASTMerge/function.c2
-rw-r--r--test/ASTMerge/interface.m2
-rw-r--r--test/ASTMerge/namespace.cpp2
-rw-r--r--test/ASTMerge/property.m2
-rw-r--r--test/ASTMerge/struct.c2
-rw-r--r--test/ASTMerge/typedef.c2
-rw-r--r--test/ASTMerge/var.c2
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h89
-rw-r--r--test/Analysis/Inputs/system-header-simulator-objc.h1
-rw-r--r--test/Analysis/Inputs/system-header-simulator.h4
-rw-r--r--test/Analysis/MismatchedDeallocator-checker-test.mm3
-rw-r--r--test/Analysis/MismatchedDeallocator-path-notes.cpp2
-rw-r--r--test/Analysis/NSContainers.m88
-rw-r--r--test/Analysis/NewDelete-checker-test.cpp152
-rw-r--r--test/Analysis/NewDelete-path-notes.cpp140
-rw-r--r--test/Analysis/NoReturn.m8
-rw-r--r--test/Analysis/analyzer-config.cpp3
-rw-r--r--test/Analysis/array-struct-region.cpp25
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp1415
-rw-r--r--test/Analysis/blocks.m45
-rw-r--r--test/Analysis/builtin-functions.cpp24
-rw-r--r--test/Analysis/casts.cpp12
-rw-r--r--test/Analysis/casts.m13
-rw-r--r--test/Analysis/cfg.cpp152
-rw-r--r--test/Analysis/conditional-operator.cpp2
-rw-r--r--test/Analysis/conditional-path-notes.c (renamed from test/Analysis/conditional-operator-path-notes.c)501
-rw-r--r--test/Analysis/crash-trace.c19
-rw-r--r--test/Analysis/ctor.mm (renamed from test/Analysis/ctor-inlining.mm)174
-rw-r--r--test/Analysis/cxx-for-range.cpp1668
-rw-r--r--test/Analysis/cxx11-crashes.cpp29
-rw-r--r--test/Analysis/derived-to-base.cpp25
-rw-r--r--test/Analysis/diagnostics/Inputs/include/report-issues-within-main-file.h43
-rw-r--r--test/Analysis/diagnostics/Inputs/include/sys/queue.h1
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.c2
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp2
-rw-r--r--test/Analysis/diagnostics/report-issues-within-main-file.cpp1756
-rw-r--r--test/Analysis/diagnostics/text-diagnostics.c21
-rw-r--r--test/Analysis/diagnostics/undef-value-caller.c2
-rw-r--r--test/Analysis/diagnostics/undef-value-param.c2
-rw-r--r--test/Analysis/diagnostics/undef-value-param.m2
-rw-r--r--test/Analysis/dtor.cpp35
-rw-r--r--test/Analysis/edges-new.mm19628
-rw-r--r--test/Analysis/func.c14
-rw-r--r--test/Analysis/html-diags-multifile.c4
-rw-r--r--test/Analysis/html-diags.c8
-rw-r--r--test/Analysis/identical-expressions.cpp942
-rw-r--r--test/Analysis/initializer.cpp34
-rw-r--r--test/Analysis/initializers-cfg-output.cpp20
-rw-r--r--test/Analysis/inline-plist.c2
-rw-r--r--test/Analysis/inline-unique-reports.c2
-rw-r--r--test/Analysis/inline.c6
-rw-r--r--test/Analysis/inline.cpp16
-rw-r--r--test/Analysis/inlining/DynDispatchBifurcate.m4
-rw-r--r--test/Analysis/inlining/InlineObjCClassMethod.m27
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.c2
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.cpp2
-rw-r--r--test/Analysis/inlining/false-positive-suppression.c8
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c29
-rw-r--r--test/Analysis/inlining/path-notes.c2
-rw-r--r--test/Analysis/inlining/path-notes.cpp488
-rw-r--r--test/Analysis/inlining/path-notes.m1005
-rw-r--r--test/Analysis/inlining/stl.cpp19
-rw-r--r--test/Analysis/lambdas.cpp2
-rw-r--r--test/Analysis/lit.local.cfg2
-rw-r--r--test/Analysis/live-variables.cpp23
-rw-r--r--test/Analysis/live-variables.m24
-rw-r--r--test/Analysis/logical-ops.c12
-rw-r--r--test/Analysis/malloc-plist.c2
-rw-r--r--test/Analysis/malloc.c131
-rw-r--r--test/Analysis/malloc.m15
-rw-r--r--test/Analysis/method-call-path-notes.cpp2
-rw-r--r--test/Analysis/misc-ps-arm.m2
-rw-r--r--test/Analysis/misc-ps-region-store.cpp65
-rw-r--r--test/Analysis/misc-ps.c18
-rw-r--r--test/Analysis/new-with-exceptions.cpp32
-rw-r--r--test/Analysis/new.cpp155
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m6
-rw-r--r--test/Analysis/null-deref-path-notes.m2
-rw-r--r--test/Analysis/nullptr.cpp6
-rw-r--r--test/Analysis/objc-arc.m1874
-rw-r--r--test/Analysis/objc-for.m256
-rw-r--r--test/Analysis/objc-properties.m2
-rw-r--r--test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m2
-rw-r--r--test/Analysis/objc_invalidation.m4
-rw-r--r--test/Analysis/operator-calls.cpp47
-rw-r--r--test/Analysis/out-of-bounds.c12
-rw-r--r--test/Analysis/plist-macros.cpp1597
-rw-r--r--test/Analysis/plist-output-alternate.m10
-rw-r--r--test/Analysis/plist-output.m10
-rw-r--r--test/Analysis/pointer-to-member.cpp1
-rw-r--r--test/Analysis/ptr-arith.c16
-rw-r--r--test/Analysis/ptr-arith.cpp22
-rw-r--r--test/Analysis/rdar-6540084.m4
-rw-r--r--test/Analysis/reference.cpp7
-rw-r--r--test/Analysis/reinterpret-cast.cpp17
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m18
-rw-r--r--test/Analysis/retain-release-path-notes.m1977
-rw-r--r--test/Analysis/retain-release.m98
-rw-r--r--test/Analysis/security-syntax-checks.m3
-rw-r--r--test/Analysis/self-init.m4
-rw-r--r--test/Analysis/simple-stream-checks.c4
-rw-r--r--test/Analysis/stack-addr-ps.cpp4
-rw-r--r--test/Analysis/string.c6
-rw-r--r--test/Analysis/taint-tester.cpp10
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp51
-rw-r--r--test/Analysis/templates.cpp22
-rw-r--r--test/Analysis/temporaries.cpp146
-rw-r--r--test/Analysis/uninit-sometimes.cpp58
-rw-r--r--test/Analysis/uninit-vals-ps-region.m15
-rw-r--r--test/Analysis/unions.cpp61
-rw-r--r--test/Analysis/unix-fns.c108
-rw-r--r--test/Analysis/unreachable-code-path.c19
-rw-r--r--test/Analysis/weak-functions.c117
-rw-r--r--test/CXX/basic/basic.link/p6.cpp53
-rw-r--r--test/CXX/basic/basic.link/p7.cpp73
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp10
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp45
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2.cpp16
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp34
-rw-r--r--test/CXX/class.access/class.friend/p11.cpp80
-rw-r--r--test/CXX/class.access/class.friend/p3-cxx0x.cpp13
-rw-r--r--test/CXX/class.access/class.friend/p6.cpp4
-rw-r--r--test/CXX/class.access/p4.cpp10
-rw-r--r--test/CXX/class.access/p6.cpp4
-rw-r--r--test/CXX/class.derived/class.abstract/p16.cpp4
-rw-r--r--test/CXX/class.derived/class.member.lookup/p7.cpp11
-rw-r--r--test/CXX/class.derived/class.virtual/p3-0x.cpp20
-rw-r--r--test/CXX/class/class.friend/p6.cpp4
-rw-r--r--test/CXX/class/class.nested.type/p1.cpp8
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp30
-rw-r--r--test/CXX/dcl.dcl/dcl.link/p7-2.cpp8
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp12
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp20
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp17
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp74
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp6
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp (renamed from test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp)3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp13
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp10
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp209
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp6
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp2
-rw-r--r--test/CXX/drs/dr0xx.cpp1040
-rw-r--r--test/CXX/drs/dr1xx.cpp1011
-rw-r--r--test/CXX/drs/dr2xx.cpp726
-rw-r--r--test/CXX/drs/dr4xx.cpp32
-rw-r--r--test/CXX/except/except.spec/p14.cpp4
-rw-r--r--test/CXX/except/except.spec/p4.cpp5
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp12
-rw-r--r--test/CXX/expr/expr.const/p3-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.call/p7-0x.cpp7
-rw-r--r--test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp20
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp32
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp31
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp77
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp12
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp25
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp25
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp66
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp8
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp131
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp5
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.sizeof/p1.cpp28
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp9
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p4.cpp4
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p11.cpp22
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p12.cpp21
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p3.cpp2
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p5.cpp4
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p7.cpp4
-rw-r--r--test/CXX/over/over.over/p2-resolve-single-template-id.cpp2
-rw-r--r--test/CXX/over/over.over/p2.cpp3
-rw-r--r--test/CXX/special/class.copy/implicit-move-def.cpp2
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp147
-rw-r--r--test/CXX/special/class.copy/p11.0x.copy.cpp8
-rw-r--r--test/CXX/special/class.copy/p11.0x.move.cpp21
-rw-r--r--test/CXX/special/class.copy/p12-0x.cpp4
-rw-r--r--test/CXX/special/class.copy/p23-cxx11.cpp38
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp2
-rw-r--r--test/CXX/special/class.inhctor/p1.cpp13
-rw-r--r--test/CXX/special/class.inhctor/p4.cpp13
-rw-r--r--test/CXX/special/class.inhctor/p8.cpp4
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp2
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p3.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp35
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp6
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp7
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p4.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p2.cpp12
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p2.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp12
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp203
-rw-r--r--test/CXX/temp/temp.param/p5.cpp9
-rw-r--r--test/CXX/temp/temp.res/temp.local/p6.cpp69
-rw-r--r--test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp37
-rw-r--r--test/CXX/temp/temp.spec/no-body.cpp63
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.inst/p1.cpp11
-rw-r--r--test/CodeCompletion/call.c6
-rw-r--r--test/CodeCompletion/call.cpp4
-rw-r--r--test/CodeCompletion/documentation.cpp4
-rw-r--r--test/CodeCompletion/enum-switch-case-qualified.cpp2
-rw-r--r--test/CodeCompletion/enum-switch-case.c4
-rw-r--r--test/CodeCompletion/enum-switch-case.cpp2
-rw-r--r--test/CodeCompletion/functions.cpp2
-rw-r--r--test/CodeCompletion/member-access.c2
-rw-r--r--test/CodeCompletion/namespace-alias.cpp2
-rw-r--r--test/CodeCompletion/namespace.cpp2
-rw-r--r--test/CodeCompletion/nested-name-specifier.cpp2
-rw-r--r--test/CodeCompletion/objc-expr.m4
-rw-r--r--test/CodeCompletion/operator.cpp2
-rw-r--r--test/CodeCompletion/stdin.c2
-rw-r--r--test/CodeCompletion/tag.c2
-rw-r--r--test/CodeCompletion/tag.cpp2
-rw-r--r--test/CodeCompletion/truncation.c4
-rw-r--r--test/CodeCompletion/using-namespace.cpp2
-rw-r--r--test/CodeCompletion/using.cpp2
-rw-r--r--test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c7
-rw-r--r--test/CodeGen/2004-11-27-InvalidConstantExpr.c10
-rw-r--r--test/CodeGen/2004-11-27-StaticFunctionRedeclare.c8
-rw-r--r--test/CodeGen/2007-02-25-C-DotDotDot.c2
-rw-r--r--test/CodeGen/2007-03-05-DataLayout.c55
-rw-r--r--test/CodeGen/2007-04-14-FNoBuiltin.c7
-rw-r--r--test/CodeGen/2007-05-07-PaddingElements.c4
-rw-r--r--test/CodeGen/2008-01-11-ChainConsistency.c3
-rw-r--r--test/CodeGen/2008-01-25-ByValReadNone.c5
-rw-r--r--test/CodeGen/2008-03-05-syncPtr.c12
-rw-r--r--test/CodeGen/2008-03-24-BitField-And-Alloca.c2
-rw-r--r--test/CodeGen/2008-05-19-AlwaysInline.c3
-rw-r--r--test/CodeGen/2008-07-30-implicit-initialization.c6
-rw-r--r--test/CodeGen/2008-07-31-asm-labels.c6
-rw-r--r--test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c6
-rw-r--r--test/CodeGen/2008-08-07-AlignPadding2.c2
-rw-r--r--test/CodeGen/2010-01-18-Inlined-Debug.c2
-rw-r--r--test/CodeGen/2010-03-5-LexicalScope.c2
-rw-r--r--test/CodeGen/2010-07-08-DeclDebugLineNo.c2
-rw-r--r--test/CodeGen/2010-08-12-asm-aggr-arg.c2
-rw-r--r--test/CodeGen/3dnow-builtins.c50
-rw-r--r--test/CodeGen/Atomics.c4
-rw-r--r--test/CodeGen/PR15826.c19
-rw-r--r--test/CodeGen/PR3589-freestanding-libcalls.c2
-rw-r--r--test/CodeGen/PR5060-align.c2
-rw-r--r--test/CodeGen/_Bool-conversion.c2
-rw-r--r--test/CodeGen/aarch64-arguments.c24
-rw-r--r--test/CodeGen/aarch64-neon-2velem.c1698
-rw-r--r--test/CodeGen/aarch64-neon-across.c271
-rw-r--r--test/CodeGen/aarch64-neon-copy.c1319
-rw-r--r--test/CodeGen/aarch64-neon-crypto.c94
-rw-r--r--test/CodeGen/aarch64-neon-extract.c148
-rw-r--r--test/CodeGen/aarch64-neon-fcvt-intrinsics.c133
-rw-r--r--test/CodeGen/aarch64-neon-intrinsics.c11725
-rw-r--r--test/CodeGen/aarch64-neon-ldst-one.c2047
-rw-r--r--test/CodeGen/aarch64-neon-misc.c2005
-rw-r--r--test/CodeGen/aarch64-neon-perm.c1093
-rw-r--r--test/CodeGen/aarch64-neon-scalar-copy.c173
-rw-r--r--test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c255
-rw-r--r--test/CodeGen/aarch64-neon-shifts.c43
-rw-r--r--test/CodeGen/aarch64-neon-tbl.c463
-rw-r--r--test/CodeGen/aarch64-neon-vcombine.c91
-rw-r--r--test/CodeGen/aarch64-neon-vget-hilo.c176
-rw-r--r--test/CodeGen/aarch64-poly64.c283
-rw-r--r--test/CodeGen/aarch64-varargs.c14
-rw-r--r--test/CodeGen/address-space.c8
-rw-r--r--test/CodeGen/alias.c6
-rw-r--r--test/CodeGen/align-param.c4
-rw-r--r--test/CodeGen/align-x68_64.c11
-rw-r--r--test/CodeGen/alignment.c5
-rw-r--r--test/CodeGen/annotations-var.c4
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c2
-rw-r--r--test/CodeGen/arm-arguments.c122
-rw-r--r--test/CodeGen/arm-asm-diag.c10
-rw-r--r--test/CodeGen/arm-asm-warn.c11
-rw-r--r--test/CodeGen/arm-cc.c8
-rw-r--r--test/CodeGen/arm-clear.c17
-rw-r--r--test/CodeGen/arm-crc32.c63
-rw-r--r--test/CodeGen/arm-interrupt-attr.c38
-rw-r--r--test/CodeGen/arm-neon-shifts.c45
-rw-r--r--test/CodeGen/arm-neon-vget.c124
-rw-r--r--test/CodeGen/arm-pcs.c2
-rw-r--r--test/CodeGen/arm-pnaclcall.c8
-rw-r--r--test/CodeGen/arm_neon_intrinsics.c11636
-rw-r--r--test/CodeGen/asm-label.c12
-rw-r--r--test/CodeGen/assign.c4
-rw-r--r--test/CodeGen/atomic-ops.c7
-rw-r--r--test/CodeGen/atomics-inlining.c90
-rw-r--r--test/CodeGen/attr-availability.c12
-rw-r--r--test/CodeGen/attr-coldhot.c2
-rw-r--r--test/CodeGen/attr-minsize.cpp2
-rw-r--r--test/CodeGen/attr-weakref.c4
-rw-r--r--test/CodeGen/available-externally-suppress.c4
-rw-r--r--test/CodeGen/avx-builtins.c18
-rw-r--r--test/CodeGen/avx-cmp-builtins.c48
-rw-r--r--test/CodeGen/avx2-builtins.c22
-rw-r--r--test/CodeGen/big-atomic-ops.c323
-rw-r--r--test/CodeGen/bitfield-2.c18
-rw-r--r--test/CodeGen/bitfield-assign.c6
-rw-r--r--test/CodeGen/bitfield.c21
-rw-r--r--test/CodeGen/block-byref-aggr.c4
-rw-r--r--test/CodeGen/blocks-2.c18
-rw-r--r--test/CodeGen/blocks.c16
-rw-r--r--test/CodeGen/bool_test.c2
-rw-r--r--test/CodeGen/bounds-checking.c19
-rw-r--r--test/CodeGen/branch-on-bool.c22
-rw-r--r--test/CodeGen/builtin-ms-noop.cpp2
-rw-r--r--test/CodeGen/builtins-arm-exclusive.c112
-rw-r--r--test/CodeGen/builtins-arm.c10
-rw-r--r--test/CodeGen/builtins-mips-msa.c829
-rw-r--r--test/CodeGen/builtins-ms.c9
-rw-r--r--test/CodeGen/builtins-multiprecision.c38
-rw-r--r--test/CodeGen/builtins-nvptx.c9
-rw-r--r--test/CodeGen/builtins-overflow.c175
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c10
-rw-r--r--test/CodeGen/builtins-x86.c12
-rw-r--r--test/CodeGen/builtins.c8
-rw-r--r--test/CodeGen/builtinshufflevector2.c13
-rw-r--r--test/CodeGen/byval-memcpy-elim.c6
-rw-r--r--test/CodeGen/c-strings.c10
-rw-r--r--test/CodeGen/c11atomics-ios.c12
-rw-r--r--test/CodeGen/c11atomics.c29
-rw-r--r--test/CodeGen/capture-complex-expr-in-block.c2
-rw-r--r--test/CodeGen/captured-statements-nested.c126
-rw-r--r--test/CodeGen/captured-statements.c80
-rw-r--r--test/CodeGen/catch-undef-behavior.c4
-rw-r--r--test/CodeGen/char-literal.c6
-rw-r--r--test/CodeGen/complex-convert.c2
-rw-r--r--test/CodeGen/complex-indirect.c2
-rw-r--r--test/CodeGen/complex-init-list.c4
-rw-r--r--test/CodeGen/complex.c9
-rw-r--r--test/CodeGen/compound-assign-overflow.c3
-rw-r--r--test/CodeGen/compound-literal.c4
-rw-r--r--test/CodeGen/const-init.c2
-rw-r--r--test/CodeGen/convertvector.c114
-rw-r--r--test/CodeGen/cxx-default-arg.cpp2
-rw-r--r--test/CodeGen/darwin-string-literals.c4
-rw-r--r--test/CodeGen/debug-info-args.c2
-rw-r--r--test/CodeGen/debug-info-block-decl.c19
-rw-r--r--test/CodeGen/debug-info-enum.c11
-rw-r--r--test/CodeGen/debug-info-limited.c11
-rw-r--r--test/CodeGen/debug-info-version.c8
-rw-r--r--test/CodeGen/debug-info-vla.c3
-rw-r--r--test/CodeGen/decl-in-prototype.c4
-rw-r--r--test/CodeGen/dependent-lib.c15
-rw-r--r--test/CodeGen/designated-initializers.c87
-rw-r--r--test/CodeGen/dllimport-dllexport.c4
-rw-r--r--test/CodeGen/dwarf-version.c14
-rw-r--r--test/CodeGen/exceptions-seh.c18
-rw-r--r--test/CodeGen/exceptions.c4
-rw-r--r--test/CodeGen/exprs.c12
-rw-r--r--test/CodeGen/ext-vector.c15
-rw-r--r--test/CodeGen/fast-math.c2
-rw-r--r--test/CodeGen/finite-math.c2
-rw-r--r--test/CodeGen/fp16-ops.c2
-rw-r--r--test/CodeGen/func-return-member.c6
-rw-r--r--test/CodeGen/function-attributes.c12
-rw-r--r--test/CodeGen/functions.c6
-rw-r--r--test/CodeGen/implicit-arg.c2
-rw-r--r--test/CodeGen/incomplete-function-type.c2
-rw-r--r--test/CodeGen/inline.c91
-rw-r--r--test/CodeGen/inline2.c48
-rw-r--r--test/CodeGen/integer-overflow.c6
-rw-r--r--test/CodeGen/le32-arguments.c18
-rw-r--r--test/CodeGen/le32-libcall-pow.c27
-rw-r--r--test/CodeGen/libcall-declarations.c570
-rw-r--r--test/CodeGen/libcalls-complex.c4
-rw-r--r--test/CodeGen/libcalls-d.c4
-rw-r--r--test/CodeGen/libcalls-ld.c4
-rw-r--r--test/CodeGen/libcalls.c21
-rw-r--r--test/CodeGen/link-bitcode-file.c6
-rw-r--r--test/CodeGen/linkage-redecl.c2
-rw-r--r--test/CodeGen/linux-arm-atomic.c2
-rw-r--r--test/CodeGen/long-double-x86-nacl.c2
-rw-r--r--test/CodeGen/mangle-windows-rtd.c10
-rw-r--r--test/CodeGen/mangle-windows.c34
-rw-r--r--test/CodeGen/may-alias.c25
-rw-r--r--test/CodeGen/microsoft-call-conv-x64.c4
-rw-r--r--test/CodeGen/microsoft-call-conv.c16
-rw-r--r--test/CodeGen/mips-byval-arg.c4
-rw-r--r--test/CodeGen/mips-clobber-reg.c206
-rw-r--r--test/CodeGen/mips-constraints-mem.c2
-rw-r--r--test/CodeGen/mips-inline-asm-modifiers.c11
-rw-r--r--test/CodeGen/mips-target-data.c2
-rw-r--r--test/CodeGen/mips-vector-return.c6
-rw-r--r--test/CodeGen/mips64-class-return.cpp4
-rw-r--r--test/CodeGen/mips64-padding-arg.c24
-rw-r--r--test/CodeGen/mmx-inline-asm-error.c13
-rw-r--r--test/CodeGen/mrtd.c11
-rw-r--r--test/CodeGen/ms-declspecs.c5
-rw-r--r--test/CodeGen/ms-inline-asm-64.c2
-rw-r--r--test/CodeGen/ms-inline-asm.c2
-rw-r--r--test/CodeGen/ms-inline-asm.cpp16
-rw-r--r--test/CodeGen/ms_abi.c20
-rw-r--r--test/CodeGen/mult-alt-generic.c1
-rw-r--r--test/CodeGen/no-opt-volatile-memcpy.c6
-rw-r--r--test/CodeGen/nomathbuiltin.c12
-rw-r--r--test/CodeGen/nvptx-abi.c17
-rw-r--r--test/CodeGen/nvptx-inlineasm-ptx.c40
-rw-r--r--test/CodeGen/object-size.c34
-rw-r--r--test/CodeGen/override-layout.c48
-rw-r--r--test/CodeGen/packed-arrays.c30
-rw-r--r--test/CodeGen/packed-nest-unpacked.c2
-rw-r--r--test/CodeGen/packed-structure.c20
-rw-r--r--test/CodeGen/ppc64-extend.c2
-rw-r--r--test/CodeGen/ppc64-struct-onefloat.c6
-rw-r--r--test/CodeGen/ppc64-struct-onevect.c13
-rw-r--r--test/CodeGen/pr12251.c2
-rw-r--r--test/CodeGen/pr2394.c2
-rw-r--r--test/CodeGen/pr3518.c2
-rw-r--r--test/CodeGen/pr4349.c2
-rw-r--r--test/CodeGen/pr9614.c2
-rw-r--r--test/CodeGen/pragma-comment.c23
-rw-r--r--test/CodeGen/pragma-detect_mismatch.c12
-rw-r--r--test/CodeGen/pragma-pack-2.c4
-rw-r--r--test/CodeGen/pragma-pack-3.c4
-rw-r--r--test/CodeGen/pragma-visibility.c4
-rw-r--r--test/CodeGen/pragma-weak.c88
-rw-r--r--test/CodeGen/predefined-expr.c12
-rw-r--r--test/CodeGen/regparm.c2
-rw-r--r--test/CodeGen/sections.c28
-rw-r--r--test/CodeGen/sha-builtins.c35
-rw-r--r--test/CodeGen/sparcv9-abi.c181
-rw-r--r--test/CodeGen/sret.c2
-rw-r--r--test/CodeGen/sret2.c2
-rw-r--r--test/CodeGen/sse-builtins.c65
-rw-r--r--test/CodeGen/statements.c7
-rw-r--r--test/CodeGen/static-order.c2
-rw-r--r--test/CodeGen/stdcall-fastcall.c30
-rw-r--r--test/CodeGen/string-literal-unicode-conversion.c11
-rw-r--r--test/CodeGen/struct-init.c2
-rw-r--r--test/CodeGen/struct-matching-constraint.c2
-rw-r--r--test/CodeGen/switch-dce.c2
-rw-r--r--test/CodeGen/switch.c20
-rw-r--r--test/CodeGen/systemz-inline-asm.c36
-rw-r--r--test/CodeGen/tbaa-class.cpp64
-rw-r--r--test/CodeGen/tbaa-for-vptr.cpp7
-rw-r--r--test/CodeGen/tbaa-ms-abi.cpp22
-rw-r--r--test/CodeGen/tbaa-struct.cpp8
-rw-r--r--test/CodeGen/tbaa-thread-sanitizer.cpp14
-rw-r--r--test/CodeGen/tbaa.cpp85
-rw-r--r--test/CodeGen/tbm-builtins.c137
-rw-r--r--test/CodeGen/transparent-union.c2
-rw-r--r--test/CodeGen/trapv.c8
-rw-r--r--test/CodeGen/unsigned-overflow.c20
-rw-r--r--test/CodeGen/unsigned-promotion.c24
-rw-r--r--test/CodeGen/unwind-attr.c2
-rw-r--r--test/CodeGen/vector.c7
-rw-r--r--test/CodeGen/visibility.c36
-rw-r--r--test/CodeGen/vla.c12
-rw-r--r--test/CodeGen/vld_dup.c2
-rw-r--r--test/CodeGen/volatile-1.c60
-rw-r--r--test/CodeGen/volatile-2.c16
-rw-r--r--test/CodeGen/volatile-complex.c67
-rw-r--r--test/CodeGen/wchar-const.c4
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c102
-rw-r--r--test/CodeGen/x86_32-arguments-linux.c2
-rw-r--r--test/CodeGen/x86_32-arguments-nommx.c4
-rw-r--r--test/CodeGen/x86_32-arguments-realign.c2
-rw-r--r--test/CodeGen/x86_32-arguments-win32.c18
-rw-r--r--test/CodeGen/x86_32-fpcc-struct-return.c34
-rw-r--r--test/CodeGen/x86_64-arguments-nacl.c30
-rw-r--r--test/CodeGen/x86_64-arguments.c110
-rw-r--r--test/CodeGen/xcore-abi.c129
-rw-r--r--test/CodeGenCUDA/address-spaces.cu6
-rw-r--r--test/CodeGenCUDA/ptx-kernels.cu4
-rw-r--r--test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp2
-rw-r--r--test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp12
-rw-r--r--test/CodeGenCXX/2007-05-03-VectorInit.cpp2
-rw-r--r--test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp2
-rw-r--r--test/CodeGenCXX/DynArrayInit.cpp2
-rw-r--r--test/CodeGenCXX/PR5050-constructor-conversion.cpp4
-rw-r--r--test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp85
-rw-r--r--test/CodeGenCXX/aarch64-neon.cpp13
-rw-r--r--test/CodeGenCXX/abstract-class-ctors-dtors.cpp8
-rw-r--r--test/CodeGenCXX/address-of-fntemplate.cpp4
-rw-r--r--test/CodeGenCXX/alloca-align.cpp6
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp21
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp12
-rw-r--r--test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp4
-rw-r--r--test/CodeGenCXX/apple-kext-linkage.C12
-rw-r--r--test/CodeGenCXX/arm-vaarg.cpp27
-rw-r--r--test/CodeGenCXX/arm.cpp52
-rw-r--r--test/CodeGenCXX/array-construction.cpp4
-rw-r--r--test/CodeGenCXX/array-operator-delete-call.cpp4
-rw-r--r--test/CodeGenCXX/atomic.cpp2
-rw-r--r--test/CodeGenCXX/atomicinit.cpp6
-rw-r--r--test/CodeGenCXX/attr-cleanup.cpp11
-rw-r--r--test/CodeGenCXX/attr.cpp2
-rw-r--r--test/CodeGenCXX/bitfield-layout.cpp4
-rw-r--r--test/CodeGenCXX/bitfield.cpp84
-rw-r--r--test/CodeGenCXX/block-byref-cxx-objc.cpp8
-rw-r--r--test/CodeGenCXX/block-in-ctor-dtor.cpp20
-rw-r--r--test/CodeGenCXX/blocks-cxx11.cpp4
-rw-r--r--test/CodeGenCXX/blocks.cpp28
-rw-r--r--test/CodeGenCXX/bool-bitfield.cpp4
-rw-r--r--test/CodeGenCXX/builtins.cpp21
-rw-r--r--test/CodeGenCXX/c-linkage.cpp6
-rw-r--r--test/CodeGenCXX/c99-variable-length-array.cpp2
-rw-r--r--test/CodeGenCXX/call-arg-zero-temp.cpp4
-rw-r--r--test/CodeGenCXX/captured-statements.cpp189
-rw-r--r--test/CodeGenCXX/cast-conversion.cpp4
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp158
-rw-r--r--test/CodeGenCXX/catch-undef-behavior2.cpp9
-rw-r--r--test/CodeGenCXX/compound-literals.cpp4
-rw-r--r--test/CodeGenCXX/condition.cpp8
-rw-r--r--test/CodeGenCXX/conditional-gnu-ext.cpp8
-rw-r--r--test/CodeGenCXX/conditional-temporaries.cpp6
-rw-r--r--test/CodeGenCXX/const-init-cxx11.cpp110
-rw-r--r--test/CodeGenCXX/const-init-cxx1y.cpp48
-rw-r--r--test/CodeGenCXX/const-init.cpp2
-rw-r--r--test/CodeGenCXX/constructor-attr.cpp2
-rw-r--r--test/CodeGenCXX/constructor-conversion.cpp4
-rw-r--r--test/CodeGenCXX/constructor-default-arg.cpp4
-rw-r--r--test/CodeGenCXX/constructor-destructor-return-this.cpp138
-rw-r--r--test/CodeGenCXX/constructor-for-array-members.cpp4
-rw-r--r--test/CodeGenCXX/constructor-init.cpp16
-rw-r--r--test/CodeGenCXX/constructor-template.cpp4
-rw-r--r--test/CodeGenCXX/constructors.cpp22
-rw-r--r--test/CodeGenCXX/conversion-function.cpp4
-rw-r--r--test/CodeGenCXX/convert-to-fptr.cpp4
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-1.cpp16
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-2.cpp2
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis.cpp2
-rw-r--r--test/CodeGenCXX/copy-constructor-elim-2.cpp6
-rw-r--r--test/CodeGenCXX/copy-constructor-elim.cpp4
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis-2.cpp2
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp45
-rw-r--r--test/CodeGenCXX/copy-initialization.cpp2
-rw-r--r--test/CodeGenCXX/crash.cpp35
-rw-r--r--test/CodeGenCXX/ctor-dtor-alias.cpp163
-rw-r--r--test/CodeGenCXX/cxx-block-objects.cpp4
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-array.cpp12
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-constructors.cpp24
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp107
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp10
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp202
-rw-r--r--test/CodeGenCXX/cxx11-exception-spec.cpp2
-rw-r--r--test/CodeGenCXX/cxx11-initializer-array-new.cpp106
-rw-r--r--test/CodeGenCXX/cxx11-thread-local-reference.cpp4
-rw-r--r--test/CodeGenCXX/cxx11-thread-local.cpp21
-rw-r--r--test/CodeGenCXX/cxx1y-deduced-return-type.cpp32
-rw-r--r--test/CodeGenCXX/cxx1y-init-captures.cpp102
-rw-r--r--test/CodeGenCXX/cxx1y-initializer-aggregate.cpp17
-rw-r--r--test/CodeGenCXX/cxx1y-sized-deallocation.cpp110
-rw-r--r--test/CodeGenCXX/cxx1y-variable-template.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-artificial-arg.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-class-limited.cpp52
-rw-r--r--test/CodeGenCXX/debug-info-class-nolimit.cpp30
-rw-r--r--test/CodeGenCXX/debug-info-class.cpp87
-rw-r--r--test/CodeGenCXX/debug-info-cxx1y.cpp7
-rw-r--r--test/CodeGenCXX/debug-info-decl-nested.cpp61
-rw-r--r--test/CodeGenCXX/debug-info-enum-class.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-enum.cpp40
-rw-r--r--test/CodeGenCXX/debug-info-friend.cpp19
-rw-r--r--test/CodeGenCXX/debug-info-function-context.cpp36
-rw-r--r--test/CodeGenCXX/debug-info-gline-tables-only.cpp10
-rw-r--r--test/CodeGenCXX/debug-info-global-ctor-dtor.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-globalinit.cpp12
-rw-r--r--test/CodeGenCXX/debug-info-limit-type.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-limit.cpp14
-rw-r--r--test/CodeGenCXX/debug-info-limited.cpp33
-rw-r--r--test/CodeGenCXX/debug-info-method.cpp5
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp66
-rw-r--r--test/CodeGenCXX/debug-info-nullptr.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-pubtypes.cpp5
-rw-r--r--test/CodeGenCXX/debug-info-same-line.cpp25
-rw-r--r--test/CodeGenCXX/debug-info-scope.cpp32
-rw-r--r--test/CodeGenCXX/debug-info-static-member.cpp14
-rw-r--r--test/CodeGenCXX/debug-info-template-limit.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp89
-rw-r--r--test/CodeGenCXX/debug-info-template-quals.cpp12
-rw-r--r--test/CodeGenCXX/debug-info-template.cpp138
-rw-r--r--test/CodeGenCXX/debug-info-thunk.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-union-template.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-uuid.cpp19
-rw-r--r--test/CodeGenCXX/debug-info-zero-length-arrays.cpp2
-rw-r--r--test/CodeGenCXX/debug-info.cpp53
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp30
-rw-r--r--test/CodeGenCXX/decl-ref-init.cpp4
-rw-r--r--test/CodeGenCXX/default-arg-temps.cpp6
-rw-r--r--test/CodeGenCXX/default-arguments.cpp8
-rw-r--r--test/CodeGenCXX/default-constructor-for-members.cpp4
-rw-r--r--test/CodeGenCXX/default-constructor-template-member.cpp3
-rw-r--r--test/CodeGenCXX/deferred-global-init.cpp4
-rw-r--r--test/CodeGenCXX/delayed-template-parsing.cpp18
-rw-r--r--test/CodeGenCXX/delete-two-arg.cpp8
-rw-r--r--test/CodeGenCXX/delete.cpp18
-rw-r--r--test/CodeGenCXX/derived-to-base-conv.cpp6
-rw-r--r--test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp2
-rw-r--r--test/CodeGenCXX/destructor-exception-spec.cpp2
-rw-r--r--test/CodeGenCXX/destructors.cpp114
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp20
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls.cpp2
-rw-r--r--test/CodeGenCXX/dynamic_cast-no-rtti.cpp26
-rw-r--r--test/CodeGenCXX/eh.cpp30
-rw-r--r--test/CodeGenCXX/empty-classes.cpp2
-rw-r--r--test/CodeGenCXX/empty-nontrivially-copyable.cpp25
-rw-r--r--test/CodeGenCXX/exceptions.cpp12
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp8
-rw-r--r--test/CodeGenCXX/fastcall.cpp4
-rw-r--r--test/CodeGenCXX/for-range.cpp8
-rw-r--r--test/CodeGenCXX/forward-enum.cpp2
-rw-r--r--test/CodeGenCXX/fp16-mangle.cpp4
-rw-r--r--test/CodeGenCXX/function-template-explicit-specialization.cpp4
-rw-r--r--test/CodeGenCXX/global-array-destruction.cpp2
-rw-r--r--test/CodeGenCXX/global-block-literal-helpers.cpp16
-rw-r--r--test/CodeGenCXX/global-dtor-no-atexit.cpp2
-rw-r--r--test/CodeGenCXX/global-init.cpp4
-rw-r--r--test/CodeGenCXX/goto.cpp2
-rw-r--r--test/CodeGenCXX/implicit-copy-assign-operator.cpp2
-rw-r--r--test/CodeGenCXX/implicit-copy-constructor.cpp2
-rw-r--r--test/CodeGenCXX/implicit-instantiation-1.cpp2
-rw-r--r--test/CodeGenCXX/inheriting-constructor.cpp14
-rw-r--r--test/CodeGenCXX/init-invariant.cpp4
-rw-r--r--test/CodeGenCXX/inline-functions.cpp10
-rw-r--r--test/CodeGenCXX/instantiate-temporaries.cpp4
-rw-r--r--test/CodeGenCXX/invalid.cpp11
-rw-r--r--test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp77
-rw-r--r--test/CodeGenCXX/lambda-expressions-nested-linkage.cpp50
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp28
-rw-r--r--test/CodeGenCXX/linetable-cleanup.cpp36
-rw-r--r--test/CodeGenCXX/linkage.cpp222
-rw-r--r--test/CodeGenCXX/lpad-linetable.cpp69
-rw-r--r--test/CodeGenCXX/lvalue-bitcasts.cpp6
-rw-r--r--test/CodeGenCXX/mangle-98.cpp6
-rw-r--r--test/CodeGenCXX/mangle-address-space.cpp6
-rw-r--r--test/CodeGenCXX/mangle-alias-template.cpp2
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp22
-rw-r--r--test/CodeGenCXX/mangle-extreme.cpp2
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp83
-rw-r--r--test/CodeGenCXX/mangle-local-class-names.cpp30
-rw-r--r--test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp117
-rw-r--r--test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp30
-rw-r--r--test/CodeGenCXX/mangle-ms-back-references.cpp5
-rw-r--r--test/CodeGenCXX/mangle-ms-templates.cpp155
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp273
-rw-r--r--test/CodeGenCXX/mangle-neon-vectors.cpp17
-rw-r--r--test/CodeGenCXX/mangle-nullptr-arg.cpp6
-rw-r--r--test/CodeGenCXX/mangle-ref-qualifiers.cpp10
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp12
-rw-r--r--test/CodeGenCXX/mangle-subst.cpp12
-rw-r--r--test/CodeGenCXX/mangle-system-header.cpp4
-rw-r--r--test/CodeGenCXX/mangle-template.cpp12
-rw-r--r--test/CodeGenCXX/mangle-unnamed.cpp4
-rw-r--r--test/CodeGenCXX/mangle-valist.cpp10
-rw-r--r--test/CodeGenCXX/mangle-variadic-templates.cpp30
-rw-r--r--test/CodeGenCXX/mangle-windows.cpp42
-rw-r--r--test/CodeGenCXX/mangle.cpp252
-rw-r--r--test/CodeGenCXX/member-expressions.cpp2
-rw-r--r--test/CodeGenCXX/member-function-pointer-calls.cpp4
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp5
-rw-r--r--test/CodeGenCXX/member-functions.cpp14
-rw-r--r--test/CodeGenCXX/member-init-anon-union.cpp2
-rw-r--r--test/CodeGenCXX/member-initializers.cpp2
-rw-r--r--test/CodeGenCXX/member-templates.cpp4
-rw-r--r--test/CodeGenCXX/microsoft-abi-alignment-fail.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp23
-rw-r--r--test/CodeGenCXX/microsoft-abi-default-cc.cpp12
-rw-r--r--test/CodeGenCXX/microsoft-abi-exceptions.cpp157
-rwxr-xr-xtest/CodeGenCXX/microsoft-abi-member-pointers.cpp210
-rw-r--r--test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp201
-rw-r--r--test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp90
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp124
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors-alias.cpp9
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors.cpp168
-rw-r--r--test/CodeGenCXX/microsoft-abi-thunks.cpp154
-rw-r--r--test/CodeGenCXX/microsoft-abi-vbtables.cpp479
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp83
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp314
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp108
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp579
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp191
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp324
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp575
-rw-r--r--test/CodeGenCXX/microsoft-interface.cpp16
-rw-r--r--test/CodeGenCXX/microsoft-new.cpp39
-rw-r--r--test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp13
-rw-r--r--test/CodeGenCXX/microsoft-uuidof.cpp94
-rw-r--r--test/CodeGenCXX/move-assignment.cpp26
-rw-r--r--test/CodeGenCXX/ms-integer-static-data-members.cpp35
-rw-r--r--test/CodeGenCXX/new-alias.cpp13
-rw-r--r--test/CodeGenCXX/new-array-init-exceptions.cpp4
-rw-r--r--test/CodeGenCXX/new-array-init.cpp8
-rw-r--r--test/CodeGenCXX/new.cpp106
-rw-r--r--test/CodeGenCXX/no-opt-volatile-memcpy.cpp8
-rw-r--r--test/CodeGenCXX/noexcept.cpp49
-rw-r--r--test/CodeGenCXX/nrvo.cpp18
-rw-r--r--test/CodeGenCXX/override-layout.cpp6
-rw-r--r--test/CodeGenCXX/partial-destruction.cpp6
-rw-r--r--test/CodeGenCXX/pod-member-memcpys.cpp152
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp6
-rw-r--r--test/CodeGenCXX/pr11676.cpp17
-rw-r--r--test/CodeGenCXX/pr11797.cpp2
-rw-r--r--test/CodeGenCXX/pr12251.cpp78
-rw-r--r--test/CodeGenCXX/pr13396.cpp12
-rw-r--r--test/CodeGenCXX/pr9130.cpp2
-rw-r--r--test/CodeGenCXX/pr9965.cpp2
-rw-r--r--test/CodeGenCXX/pragma-visibility.cpp14
-rw-r--r--test/CodeGenCXX/pragma-weak.cpp10
-rw-r--r--test/CodeGenCXX/predefined-expr.cpp22
-rw-r--r--test/CodeGenCXX/ptr-to-member-function.cpp4
-rw-r--r--test/CodeGenCXX/reference-cast.cpp20
-rw-r--r--test/CodeGenCXX/references.cpp18
-rw-r--r--test/CodeGenCXX/return.cpp2
-rw-r--r--test/CodeGenCXX/rtti-layout.cpp2
-rw-r--r--test/CodeGenCXX/runtimecc.cpp6
-rw-r--r--test/CodeGenCXX/rvalue-references.cpp14
-rw-r--r--test/CodeGenCXX/scoped-enums.cpp9
-rw-r--r--test/CodeGenCXX/skip-vtable-pointer-initialization.cpp16
-rw-r--r--test/CodeGenCXX/static-data-member.cpp6
-rw-r--r--test/CodeGenCXX/static-init-1.cpp8
-rw-r--r--test/CodeGenCXX/static-init-4.cpp7
-rw-r--r--test/CodeGenCXX/static-init-pnacl.cpp14
-rw-r--r--test/CodeGenCXX/static-init.cpp16
-rw-r--r--test/CodeGenCXX/static-member-variable-explicit-specialization.cpp89
-rw-r--r--test/CodeGenCXX/stmtexpr.cpp7
-rw-r--r--test/CodeGenCXX/template-anonymous-types.cpp12
-rw-r--r--test/CodeGenCXX/template-dependent-bind-temporary.cpp2
-rw-r--r--test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp4
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp20
-rw-r--r--test/CodeGenCXX/template-linkage.cpp12
-rw-r--r--test/CodeGenCXX/temporaries.cpp243
-rw-r--r--test/CodeGenCXX/thiscall-struct-return.cpp4
-rw-r--r--test/CodeGenCXX/threadsafe-statics-exceptions.cpp2
-rw-r--r--test/CodeGenCXX/throw-expression-cleanup.cpp2
-rw-r--r--test/CodeGenCXX/throw-expressions.cpp26
-rw-r--r--test/CodeGenCXX/thunks-available-externally.cpp11
-rw-r--r--test/CodeGenCXX/thunks.cpp44
-rw-r--r--test/CodeGenCXX/type_visibility.cpp36
-rw-r--r--test/CodeGenCXX/typeid.cpp5
-rw-r--r--test/CodeGenCXX/unknown-anytype.cpp62
-rw-r--r--test/CodeGenCXX/value-init.cpp20
-rw-r--r--test/CodeGenCXX/vararg-conversion-ctor.cpp2
-rw-r--r--test/CodeGenCXX/vararg-non-pod.cpp2
-rw-r--r--test/CodeGenCXX/varargs.cpp4
-rw-r--r--test/CodeGenCXX/variadic-templates.cpp4
-rw-r--r--test/CodeGenCXX/virt-dtor-gen.cpp2
-rw-r--r--test/CodeGenCXX/virtual-base-cast.cpp54
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp22
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp12
-rw-r--r--test/CodeGenCXX/virtual-destructor-calls.cpp8
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp2
-rw-r--r--test/CodeGenCXX/visibility-hidden-extern-templates.cpp6
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp38
-rw-r--r--test/CodeGenCXX/visibility-ms-compat.cpp12
-rw-r--r--test/CodeGenCXX/visibility.cpp258
-rw-r--r--test/CodeGenCXX/vla.cpp2
-rw-r--r--test/CodeGenCXX/volatile.cpp4
-rw-r--r--test/CodeGenCXX/vtable-available-externally.cpp26
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp188
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp139
-rw-r--r--test/CodeGenCXX/vtable-pointer-initialization.cpp10
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp30
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp18
-rw-r--r--test/CodeGenObjC/2010-02-09-DbgSelf.m4
-rw-r--r--test/CodeGenObjC/arc-block-copy-escape.m4
-rw-r--r--test/CodeGenObjC/arc-blocks.m72
-rw-r--r--test/CodeGenObjC/arc-bridged-cast.m8
-rw-r--r--test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m2
-rw-r--r--test/CodeGenObjC/arc-captured-32bit-block-var-layout.m2
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-inlined-layout.m4
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-layout.m4
-rw-r--r--test/CodeGenObjC/arc-exceptions.m4
-rw-r--r--test/CodeGenObjC/arc-foreach.m14
-rw-r--r--test/CodeGenObjC/arc-ivar-layout.m4
-rw-r--r--test/CodeGenObjC/arc-linetable-autorelease.m40
-rw-r--r--test/CodeGenObjC/arc-literals.m8
-rw-r--r--test/CodeGenObjC/arc-loadweakretained-release.m2
-rw-r--r--test/CodeGenObjC/arc-no-arc-exceptions.m22
-rw-r--r--test/CodeGenObjC/arc-precise-lifetime.m55
-rw-r--r--test/CodeGenObjC/arc-property.m2
-rw-r--r--test/CodeGenObjC/arc-related-result-type.m2
-rw-r--r--test/CodeGenObjC/arc-ternary-op.m6
-rw-r--r--test/CodeGenObjC/arc-unopt.m2
-rw-r--r--test/CodeGenObjC/arc-unoptimized-byref-var.m2
-rw-r--r--test/CodeGenObjC/arc-with-atthrow.m2
-rw-r--r--test/CodeGenObjC/arc.m76
-rw-r--r--test/CodeGenObjC/assign.m2
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m4
-rw-r--r--test/CodeGenObjC/auto-property-synthesize-protocol.m2
-rw-r--r--test/CodeGenObjC/autorelease.m2
-rw-r--r--test/CodeGenObjC/bitfield-access.m4
-rw-r--r--test/CodeGenObjC/bitfield-ivar-offsets.m2
-rw-r--r--test/CodeGenObjC/block-6.m2
-rw-r--r--test/CodeGenObjC/block-byref-debuginfo.m14
-rw-r--r--test/CodeGenObjC/block-byref-variable-layout.m2
-rw-r--r--test/CodeGenObjC/block-var-layout.m4
-rw-r--r--test/CodeGenObjC/blocks-1.m4
-rw-r--r--test/CodeGenObjC/blocks.m10
-rw-r--r--test/CodeGenObjC/builtins.m2
-rw-r--r--test/CodeGenObjC/complex-property.m2
-rw-r--r--test/CodeGenObjC/debug-info-block-line.m2
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m23
-rw-r--r--test/CodeGenObjC/debug-info-default-synth-ivar.m2
-rw-r--r--test/CodeGenObjC/debug-info-fwddecl.m2
-rw-r--r--test/CodeGenObjC/debug-info-id-with-protocol.m6
-rw-r--r--test/CodeGenObjC/debug-info-instancetype.m28
-rw-r--r--test/CodeGenObjC/debug-info-lifetime-crash.m23
-rw-r--r--test/CodeGenObjC/debug-info-property-accessors.m56
-rw-r--r--test/CodeGenObjC/debug-info-property4.m2
-rw-r--r--test/CodeGenObjC/debug-info-property5.m2
-rw-r--r--test/CodeGenObjC/debug-info-self.m8
-rw-r--r--test/CodeGenObjC/debuginfo-properties.m35
-rw-r--r--test/CodeGenObjC/designated-initializers.m8
-rw-r--r--test/CodeGenObjC/encode-cstyle-method.m2
-rw-r--r--test/CodeGenObjC/encode-test-6.m18
-rw-r--r--test/CodeGenObjC/encode-test.m2
-rw-r--r--test/CodeGenObjC/exceptions-nonfragile.m2
-rw-r--r--test/CodeGenObjC/exceptions.m8
-rw-r--r--test/CodeGenObjC/extended-block-signature-encode.m2
-rw-r--r--test/CodeGenObjC/fp2ret.m6
-rw-r--r--test/CodeGenObjC/fpret.m6
-rw-r--r--test/CodeGenObjC/gc.m2
-rw-r--r--test/CodeGenObjC/id-isa-codegen.m4
-rw-r--r--test/CodeGenObjC/ivar-base-as-invariant-load.m6
-rw-r--r--test/CodeGenObjC/ivar-invariant.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-array0-struct.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-no-optimize.m8
-rw-r--r--test/CodeGenObjC/local-static-block.m2
-rw-r--r--test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m4
-rw-r--r--test/CodeGenObjC/ns_consume_null_check.m4
-rw-r--r--test/CodeGenObjC/null-objc-empty-vtable.m10
-rw-r--r--test/CodeGenObjC/objc-gc-aggr-assign.m4
-rw-r--r--test/CodeGenObjC/objc-read-weak-byref.m4
-rw-r--r--test/CodeGenObjC/objc2-legacy-dispatch.m8
-rw-r--r--test/CodeGenObjC/objc2-no-write-barrier.m4
-rw-r--r--test/CodeGenObjC/objc2-weak-block-call.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-5.m4
-rw-r--r--test/CodeGenObjC/objfw.m2
-rw-r--r--test/CodeGenObjC/property.m4
-rw-r--r--test/CodeGenObjC/protocol-in-extended-class.m4
-rw-r--r--test/CodeGenObjC/protocols-lazy.m6
-rw-r--r--test/CodeGenObjC/related-result-type.m4
-rw-r--r--test/CodeGenObjC/reorder-synthesized-ivars.m2
-rw-r--r--test/CodeGenObjC/stret_lookup.m29
-rw-r--r--test/CodeGenObjC/synchronized.m6
-rw-r--r--test/CodeGenObjC/tentative-cfconstantstring.m2
-rw-r--r--test/CodeGenObjC/terminate.m4
-rw-r--r--test/CodeGenObjC/x86_64-struct-return-gc.m4
-rw-r--r--test/CodeGenObjCXX/arc-attrs.mm6
-rw-r--r--test/CodeGenObjCXX/arc-blocks.mm2
-rw-r--r--test/CodeGenObjCXX/arc-exceptions.mm10
-rw-r--r--test/CodeGenObjCXX/arc-globals.mm6
-rw-r--r--test/CodeGenObjCXX/arc-mangle.mm18
-rw-r--r--test/CodeGenObjCXX/arc-move.mm6
-rw-r--r--test/CodeGenObjCXX/arc-new-delete.mm8
-rw-r--r--test/CodeGenObjCXX/arc-pseudo-destructors.mm2
-rw-r--r--test/CodeGenObjCXX/arc-references.mm10
-rw-r--r--test/CodeGenObjCXX/arc-special-member-functions.mm34
-rw-r--r--test/CodeGenObjCXX/arc.mm20
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm2
-rw-r--r--test/CodeGenObjCXX/catch-id-type.mm2
-rw-r--r--test/CodeGenObjCXX/encode.mm23
-rw-r--r--test/CodeGenObjCXX/exceptions-legacy.mm4
-rw-r--r--test/CodeGenObjCXX/exceptions.mm2
-rw-r--r--test/CodeGenObjCXX/gc.mm2
-rw-r--r--test/CodeGenObjCXX/implicit-copy-assign-operator.mm2
-rw-r--r--test/CodeGenObjCXX/implicit-copy-constructor.mm2
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm39
-rw-r--r--test/CodeGenObjCXX/literals.mm4
-rw-r--r--test/CodeGenObjCXX/mangle-blocks.mm49
-rw-r--r--test/CodeGenObjCXX/mangle.mm20
-rw-r--r--test/CodeGenObjCXX/message.mm2
-rw-r--r--test/CodeGenObjCXX/nrvo.mm2
-rw-r--r--test/CodeGenObjCXX/objc-container-subscripting-1.mm4
-rw-r--r--test/CodeGenObjCXX/objc-container-subscripting.mm6
-rw-r--r--test/CodeGenObjCXX/property-dot-reference.mm2
-rw-r--r--test/CodeGenObjCXX/property-object-reference-2.mm4
-rw-r--r--test/CodeGenObjCXX/property-objects.mm4
-rw-r--r--test/CodeGenObjCXX/property-reference.mm4
-rw-r--r--test/CodeGenObjCXX/references.mm2
-rw-r--r--test/CodeGenObjCXX/rtti.mm8
-rw-r--r--test/CodeGenObjCXX/unknown-anytype.mm4
-rw-r--r--test/CodeGenOpenCL/address-spaces-mangling.cl30
-rw-r--r--test/CodeGenOpenCL/kernel-attributes.cl2
-rw-r--r--test/CodeGenOpenCL/local.cl4
-rw-r--r--test/CodeGenOpenCL/opencl_types.cl2
-rw-r--r--test/CodeGenOpenCL/ptx-calls.cl4
-rw-r--r--test/CodeGenOpenCL/ptx-kernels.cl4
-rw-r--r--test/CodeGenOpenCL/str_literals.cl9
-rw-r--r--test/CodeGenOpenCL/vector_odd.cl17
-rw-r--r--test/Coverage/codegen-next.m12
-rw-r--r--test/Coverage/html-diagnostics.c3
-rw-r--r--test/Driver/B-opt.c8
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-as1
l---------test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.bfd1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.gold1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as1
l---------test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.bfd1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.gold1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/as1
l---------test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.bfd1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.gold1
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtfastmath.o0
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/as1
l---------test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.bfd1
-rwxr-xr-xtest/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.gold1
-rw-r--r--test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crt0.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbeginS.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtend.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtendS.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/libtest.so0
-rw-r--r--test/Driver/Inputs/file.prof0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/.keep0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/x86_64-pc-linux-gnu/lib/.keep0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/crtbegin.o0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/.keep0
-rw-r--r--test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/x86_64-pc-linux-gnu/lib/.keep0
-rw-r--r--test/Driver/Inputs/lit.local.cfg1
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/bin/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include-fixed/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/backward/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/fp64/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/inclide/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/inclide/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/inclide/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crtn.o0
l---------test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/as1
-rwxr-xr-xtest/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-as1
-rwxr-xr-xtest/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-ld1
l---------test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/ld1
l---------test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/as1
l---------test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/ld1
l---------test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/as1
l---------test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/ld1
-rwxr-xr-xtest/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as1
-rwxr-xr-xtest/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld1
l---------test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/as1
l---------test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/ld1
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/crtbegin.o1
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/lib/.keep0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crti.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crti.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtbegin.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtend.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtbegin.o0
-rw-r--r--test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtend.o0
-rw-r--r--test/Driver/O.c10
-rw-r--r--test/Driver/Wp-args.c4
-rw-r--r--test/Driver/Xarch.c2
-rw-r--r--test/Driver/Xlinker-args.c8
-rw-r--r--test/Driver/aarch64-cpus.c10
-rw-r--r--test/Driver/aarch64-mfpu.c26
-rw-r--r--test/Driver/altivec-asm.S3
-rw-r--r--test/Driver/arc.c12
-rw-r--r--test/Driver/arch.c6
-rw-r--r--test/Driver/arm-alignment.c25
-rw-r--r--test/Driver/arm-cortex-cpus.c37
-rw-r--r--test/Driver/arm-fixed-r9.c4
-rw-r--r--test/Driver/arm-hwdiv.c39
-rw-r--r--test/Driver/arm-mfpmath.c29
-rw-r--r--test/Driver/arm-mfpu.c38
-rw-r--r--test/Driver/arm-restrict-it.c15
-rw-r--r--test/Driver/armv8-crc.c8
-rw-r--r--test/Driver/at_file.c6
-rw-r--r--test/Driver/at_file.c.args2
-rw-r--r--test/Driver/at_file.c.args.utf16lebin0 -> 568 bytes
-rw-r--r--test/Driver/bounds-checking.c6
-rw-r--r--test/Driver/ccc-add-args.c5
-rw-r--r--test/Driver/ccc-as-cpp.c5
-rw-r--r--test/Driver/cl-fallback.c41
-rw-r--r--test/Driver/cl-inputs.c35
-rw-r--r--test/Driver/cl-link.c33
-rw-r--r--test/Driver/cl-options.c238
-rw-r--r--test/Driver/cl-outputs.c107
-rw-r--r--test/Driver/cl-runtime-flags.c89
-rw-r--r--test/Driver/cl.c35
-rw-r--r--test/Driver/clang-g-opts.c11
-rw-r--r--test/Driver/clang-translation.c8
-rw-r--r--test/Driver/clang_f_opts.c78
-rw-r--r--test/Driver/color-diagnostics.c30
-rw-r--r--test/Driver/coverage-ld.c19
-rw-r--r--test/Driver/crash-report.c14
-rw-r--r--test/Driver/cross-linux.c95
-rw-r--r--test/Driver/darwin-as.c12
-rw-r--r--test/Driver/darwin-dsymutil.c2
-rw-r--r--test/Driver/darwin-eabi.c12
-rw-r--r--test/Driver/darwin-ld.c14
-rw-r--r--test/Driver/darwin-objc-defaults.m21
-rw-r--r--test/Driver/darwin-objc-options.m6
-rw-r--r--test/Driver/darwin-sanitizer-ld.c15
-rw-r--r--test/Driver/darwin-verify-debug.c2
-rw-r--r--test/Driver/debug-main-file.S1
-rw-r--r--test/Driver/debug-options-as.c3
-rw-r--r--test/Driver/debug-options.c60
-rw-r--r--test/Driver/debug-unsupported.c22
-rw-r--r--test/Driver/dyld-prefix.c9
-rw-r--r--test/Driver/emit-llvm.c10
-rw-r--r--test/Driver/fast-math.c38
-rw-r--r--test/Driver/fpack-struct.c2
-rw-r--r--test/Driver/frame-pointer.c14
-rw-r--r--test/Driver/freebsd.c4
-rw-r--r--test/Driver/freebsd.cc6
-rw-r--r--test/Driver/fsanitize-blacklist.c18
-rw-r--r--test/Driver/fsanitize.c72
-rw-r--r--test/Driver/gcc-toolchain.cpp10
-rw-r--r--test/Driver/gcc-version-debug.c6
-rw-r--r--test/Driver/gcc_forward.c37
-rw-r--r--test/Driver/gfortran.f90244
-rw-r--r--test/Driver/hexagon-toolchain-elf.c136
-rw-r--r--test/Driver/hexagon-toolchain.c136
-rw-r--r--test/Driver/ident_md.c6
-rw-r--r--test/Driver/immediate-options.c20
-rw-r--r--test/Driver/inhibit-downstream-commands.c2
-rw-r--r--test/Driver/integrated-as.c5
-rw-r--r--test/Driver/integrated-as.s33
-rw-r--r--test/Driver/invalid-o-level.c4
-rw-r--r--test/Driver/le32-toolchain.c4
-rw-r--r--test/Driver/le32-unknown-nacl.cpp4
-rw-r--r--test/Driver/linux-as.c38
-rw-r--r--test/Driver/linux-header-search.cpp55
-rw-r--r--test/Driver/linux-ld.c306
-rw-r--r--test/Driver/lit.local.cfg6
-rw-r--r--test/Driver/lto.c13
-rw-r--r--test/Driver/m_and_mm.c2
-rw-r--r--test/Driver/mips-as.c32
-rw-r--r--test/Driver/mips-cs-header-search.cpp64
-rw-r--r--test/Driver/mips-cs-ld.c298
-rw-r--r--test/Driver/mips-features.c48
-rw-r--r--test/Driver/mips-float.c16
-rw-r--r--test/Driver/mips-fsf.cpp2341
-rw-r--r--test/Driver/mipsel-nacl-defines.cpp45
-rw-r--r--test/Driver/montavista-gcc-toolchain.c6
-rw-r--r--test/Driver/netbsd.c57
-rw-r--r--test/Driver/netbsd.cpp57
-rw-r--r--test/Driver/no-integrated-as-win.c10
-rw-r--r--test/Driver/no-objc-default-synthesize-properties.m6
-rw-r--r--test/Driver/noexecstack.c4
-rw-r--r--test/Driver/nostdincxx.cpp2
-rw-r--r--test/Driver/objc_default_synth.m6
-rw-r--r--test/Driver/openbsd.c28
-rw-r--r--test/Driver/option-aliases.c23
-rw-r--r--test/Driver/parsing.c22
-rw-r--r--test/Driver/pic.c12
-rw-r--r--test/Driver/ppc-features.cpp22
-rw-r--r--test/Driver/pth.c4
-rw-r--r--test/Driver/qa_override.c22
-rw-r--r--test/Driver/r600-mcpu.cl8
-rw-r--r--test/Driver/rewrite-legacy-objc.m8
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/Driver/sanitizer-ld.c35
-rw-r--r--test/Driver/split-debug.c10
-rw-r--r--test/Driver/stack-protector.c6
-rw-r--r--test/Driver/std.cpp18
-rw-r--r--test/Driver/systemz-march.c13
-rw-r--r--test/Driver/target-as.s2
-rw-r--r--test/Driver/target.c6
-rw-r--r--test/Driver/tsan.c10
-rw-r--r--test/Driver/unknown-arg.c19
-rw-r--r--test/Driver/working-directory.c8
-rw-r--r--test/Driver/x86_64-nacl-defines.cpp4
-rw-r--r--test/Driver/x86_features.c8
-rw-r--r--test/Driver/xcore-opts.c13
-rw-r--r--test/FixIt/bridge-cast-in-arc.mm2
-rw-r--r--test/FixIt/fixit-autoreleasepool.m2
-rw-r--r--test/FixIt/fixit-cxx0x.cpp5
-rw-r--r--test/FixIt/fixit-cxx11-attributes.cpp2
-rw-r--r--test/FixIt/fixit-errors-1.c2
-rw-r--r--test/FixIt/fixit-include.c2
-rw-r--r--test/FixIt/fixit-interface-as-param.m2
-rw-r--r--test/FixIt/fixit-objc-message-comma-separator.m2
-rw-r--r--test/FixIt/fixit-objc.m8
-rw-r--r--test/FixIt/fixit-static-object-decl.m12
-rw-r--r--test/FixIt/fixit-unicode-with-utf8-output.c24
-rw-r--r--test/FixIt/fixit-unicode.c39
-rw-r--r--test/FixIt/fixit-uninit.c25
-rw-r--r--test/FixIt/fixit-vexing-parse.cpp2
-rw-r--r--test/FixIt/fixit.c2
-rw-r--r--test/FixIt/fixit.cpp33
-rw-r--r--test/FixIt/format.m10
-rw-r--r--test/FixIt/format.mm4
-rw-r--r--test/FixIt/lit.local.cfg2
-rw-r--r--test/FixIt/messages.cpp2
-rw-r--r--test/FixIt/no-fixit.cpp2
-rw-r--r--test/FixIt/selector-fixit.m41
-rw-r--r--test/FixIt/typo-crash.cpp5
-rw-r--r--test/FixIt/typo-location-bugs.cpp21
-rw-r--r--test/FixIt/typo-using.cpp56
-rw-r--r--test/FixIt/typo.c2
-rw-r--r--test/FixIt/typo.cpp17
-rw-r--r--test/Format/cursor.cpp6
-rw-r--r--test/Format/diagnostic.cpp4
-rw-r--r--test/Format/line-ranges.cpp11
-rw-r--r--test/Format/multiple-inputs-error.cpp6
-rw-r--r--test/Format/style-on-command-line.cpp29
-rw-r--r--test/Frontend/Inputs/lit.local.cfg1
-rw-r--r--test/Frontend/Inputs/rewrite-includes-bom.h1
-rw-r--r--test/Frontend/cc1-return-codes.c4
-rw-r--r--test/Frontend/darwin-eabi.c7
-rw-r--r--test/Frontend/darwin-version.c10
-rw-r--r--test/Frontend/invalid-o-level.c4
-rw-r--r--test/Frontend/ir-support-errors.ll2
-rw-r--r--test/Frontend/mfpmath.c43
-rw-r--r--test/Frontend/mips-long-double.c (renamed from test/Driver/mips-long-double.c)0
-rw-r--r--test/Frontend/print-header-includes.c7
-rw-r--r--test/Frontend/rewrite-includes-bom.c4
-rw-r--r--test/Frontend/rewrite-includes-header-cmd-line.c7
-rw-r--r--test/Frontend/rewrite-includes-invalid-hasinclude.c2
-rw-r--r--test/Frontend/rewrite-includes-warnings.c4
-rw-r--r--test/Frontend/rewrite-includes.c45
-rw-r--r--test/Frontend/verify-fatal.c2
-rw-r--r--test/Frontend/verify.c18
-rw-r--r--test/Frontend/verify2.c2
-rw-r--r--test/Frontend/verify3.c8
-rw-r--r--test/Frontend/x86_64-nacl-types.cpp (renamed from test/Driver/x86_64-nacl-types.cpp)0
-rw-r--r--test/Headers/Inputs/include/complex.h3
-rw-r--r--test/Headers/Inputs/include/math.h1
-rw-r--r--test/Headers/Inputs/include/stdint.h1
-rw-r--r--test/Headers/altivec-header.c6
-rw-r--r--test/Headers/c11.c6
-rw-r--r--test/Headers/c89.c2
-rw-r--r--test/Headers/cxx11.cpp4
-rw-r--r--test/Headers/limits.cpp42
-rw-r--r--test/Headers/ms-intrin.cpp24
-rw-r--r--test/Headers/ms-null-ms-header-vs-stddef.cpp4
-rw-r--r--test/Headers/ms-wchar.c2
-rw-r--r--test/Headers/tgmath.c38
-rw-r--r--test/Headers/x86-intrinsics-headers.c6
-rw-r--r--test/Headers/x86intrin.c91
-rw-r--r--test/Index/Inputs/CommentXML/invalid-function-13.xml13
-rw-r--r--test/Index/Inputs/CommentXML/valid-function-07.xml19
-rw-r--r--test/Index/Inputs/empty.h0
-rw-r--r--test/Index/Inputs/lit.local.cfg1
-rw-r--r--test/Index/Inputs/preamble-with-error.h3
-rw-r--r--test/Index/TestClassDecl.m4
-rw-r--r--test/Index/TestClassForwardDecl.m4
-rw-r--r--test/Index/annotate-comments-objc.m78
-rw-r--r--test/Index/annotate-comments-unterminated.c2
-rw-r--r--test/Index/annotate-comments.cpp10
-rw-r--r--test/Index/annotate-tokens-cxx0x.cpp44
-rw-r--r--test/Index/annotate-tokens.m22
-rw-r--r--test/Index/annotate-toplevel-in-objccontainer.m6
-rw-r--r--test/Index/asm-attribute.c3
-rw-r--r--test/Index/attributes.c10
-rw-r--r--test/Index/availability.c10
-rw-r--r--test/Index/c-index-api-loadTU-test.m14
-rw-r--r--test/Index/c-index-unsupported-warning-test.c3
-rw-r--r--test/Index/cindex-from-source.m2
-rw-r--r--test/Index/comment-custom-block-command.cpp2
-rw-r--r--test/Index/comment-misc-tags.m3
-rw-r--r--test/Index/comment-to-html-xml-conversion.cpp292
-rw-r--r--test/Index/comment-unqualified-objc-pointer.m2
-rw-r--r--test/Index/comment-xml-schema.c31
-rw-r--r--test/Index/complete-documentation-properties.m14
-rw-r--r--test/Index/complete-documentation-templates.cpp14
-rw-r--r--test/Index/complete-documentation.cpp6
-rw-r--r--test/Index/complete-modules.m8
-rw-r--r--test/Index/complete-pch.m2
-rw-r--r--test/Index/complete-preamble.cpp2
-rw-r--r--test/Index/complete-qualified.cpp2
-rw-r--r--test/Index/crash-recovery-modules.m15
-rw-r--r--test/Index/create-tu-fail.c2
-rw-r--r--test/Index/error-on-deserialized.c2
-rw-r--r--test/Index/file-includes.c3
-rw-r--r--test/Index/get-cursor.m24
-rw-r--r--test/Index/index-decls.m19
-rw-r--r--test/Index/index-file.cpp13
-rw-r--r--test/Index/index-module.m2
-rw-r--r--test/Index/overrides.cpp7
-rw-r--r--test/Index/overriding-method-comments.mm10
-rw-r--r--test/Index/pch-with-errors.c4
-rw-r--r--test/Index/pch-with-errors.m6
-rw-r--r--test/Index/pch-with-module.m23
-rw-r--r--test/Index/preamble-reparse-with-BOM.m6
-rw-r--r--test/Index/preamble.c8
-rw-r--r--test/Index/print-type-cxx11.cpp8
-rw-r--r--test/Index/print-type-size.cpp50
-rw-r--r--test/Index/print-type.c5
-rw-r--r--test/Index/print-type.cpp15
-rw-r--r--test/Index/recover-bad-code-rdar_7487294.c2
-rw-r--r--test/Index/retain-comments-from-system-headers.c2
-rw-r--r--test/Index/subclass-comment.mm66
-rw-r--r--test/Index/usrs.m2
-rw-r--r--test/Layout/ms-x86-aligned-tail-padding.cpp502
-rw-r--r--test/Layout/ms-x86-basic-layout.cpp775
-rw-r--r--test/Layout/ms-x86-bitfields-vbases.cpp84
-rw-r--r--test/Layout/ms-x86-empty-base-after-base-with-vbptr.cpp216
-rw-r--r--test/Layout/ms-x86-empty-nonvirtual-bases.cpp174
-rw-r--r--test/Layout/ms-x86-empty-virtual-base.cpp704
-rw-r--r--test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp735
-rw-r--r--test/Layout/ms-x86-misalignedarray.cpp23
-rw-r--r--test/Layout/ms-x86-primary-bases.cpp317
-rw-r--r--test/Layout/ms-x86-size-alignment-fail.cpp123
-rw-r--r--test/Layout/ms-x86-vfvb-alignment.cpp376
-rw-r--r--test/Layout/ms-x86-vfvb-sharing.cpp140
-rw-r--r--test/Layout/ms-x86-vtordisp.cpp170
-rw-r--r--test/Lexer/Inputs/bad-header-guard-defined.h4
-rw-r--r--test/Lexer/Inputs/bad-header-guard.h4
-rw-r--r--test/Lexer/Inputs/different-define.h4
-rw-r--r--test/Lexer/Inputs/good-header-guard.h4
-rw-r--r--test/Lexer/Inputs/multiple.h4
-rw-r--r--test/Lexer/Inputs/no-define.h3
-rw-r--r--test/Lexer/Inputs/out-of-order-define.h7
-rw-r--r--test/Lexer/Inputs/tokens-between-ifndef-and-define.h7
-rw-r--r--test/Lexer/Inputs/unlikely-to-be-header-guard.h5
-rw-r--r--test/Lexer/builtin_redef.c2
-rw-r--r--test/Lexer/char-literal.cpp4
-rw-r--r--test/Lexer/constants.c7
-rw-r--r--test/Lexer/cxx-features.cpp89
-rw-r--r--test/Lexer/cxx0x_raw_string_unterminated.cpp2
-rw-r--r--test/Lexer/cxx1y_binary_literal.cpp1
-rw-r--r--test/Lexer/cxx1y_digit_separators.cpp43
-rw-r--r--test/Lexer/dollar-idents.c2
-rw-r--r--test/Lexer/gnu-flags.c56
-rw-r--r--test/Lexer/has_extension_cxx.cpp20
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp50
-rw-r--r--test/Lexer/header.cpp44
-rw-r--r--test/Lexer/newline-eof-c++11.cpp5
-rw-r--r--test/Lexer/newline-eof-c++98-compat.cpp1
-rw-r--r--test/Lexer/newline-eof.c8
-rw-r--r--test/Lexer/pragma-operators.cpp22
-rw-r--r--test/Lexer/string-literal-errors.cpp2
-rw-r--r--test/Lexer/wchar-signedness.c4
-rw-r--r--test/Makefile3
-rw-r--r--test/Misc/ast-dump-attr.cpp16
-rw-r--r--test/Misc/ast-dump-color.cpp8
-rw-r--r--test/Misc/ast-dump-decl.cpp16
-rw-r--r--test/Misc/ast-dump-stmt.cpp28
-rw-r--r--test/Misc/ast-dump-templates.cpp12
-rw-r--r--test/Misc/caret-diags-scratch-buffer.c2
-rw-r--r--test/Misc/dev-fd-fs.c3
-rw-r--r--test/Misc/diag-format.c3
-rw-r--r--test/Misc/diag-line-wrapping.cpp4
-rw-r--r--test/Misc/diag-macro-backtrace.c2
-rw-r--r--test/Misc/diag-mapping.c6
-rw-r--r--test/Misc/diag-mapping2.c4
-rw-r--r--test/Misc/diag-presumed.c4
-rw-r--r--test/Misc/diag-template-diffing-color.cpp4
-rw-r--r--test/Misc/diag-template-diffing-cxx98.cpp2
-rw-r--r--test/Misc/diag-template-diffing.cpp79
-rw-r--r--test/Misc/diag-trailing-null-bytes.cpp2
-rw-r--r--test/Misc/diag-verify.cpp2
-rw-r--r--test/Misc/error-limit-multiple-notes.cpp2
-rw-r--r--test/Misc/error-limit.c2
-rw-r--r--test/Misc/include-stack-for-note-flag.cpp10
-rw-r--r--test/Misc/languageOptsOpenCL.cl19
-rw-r--r--test/Misc/permissions.cpp15
-rw-r--r--test/Misc/show-diag-options.c4
-rw-r--r--test/Misc/tabstop.c6
-rw-r--r--test/Misc/unprintable.c2
-rw-r--r--test/Misc/warning-flags-tree.c5
-rw-r--r--test/Misc/warning-flags.c21
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/not_cxx.h1
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/not_objc.h1
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/module.map8
-rw-r--r--test/Modules/Inputs/MethodPoolBSub.h1
-rw-r--r--test/Modules/Inputs/MethodPoolBSub2.h3
-rw-r--r--test/Modules/Inputs/System/usr/include/stdio.h2
-rw-r--r--test/Modules/Inputs/cxx-decls-imported.h5
-rw-r--r--test/Modules/Inputs/cxx-decls-unimported.h1
-rw-r--r--test/Modules/Inputs/cxx-templates-a.h50
-rw-r--r--test/Modules/Inputs/cxx-templates-b-impl.h5
-rw-r--r--test/Modules/Inputs/cxx-templates-b.h69
-rw-r--r--test/Modules/Inputs/cxx-templates-c.h7
-rw-r--r--test/Modules/Inputs/cxx-templates-common.h11
-rw-r--r--test/Modules/Inputs/declare-use/a.h4
-rw-r--r--test/Modules/Inputs/declare-use/b.h4
-rw-r--r--test/Modules/Inputs/declare-use/c.h6
-rw-r--r--test/Modules/Inputs/declare-use/d.h6
-rw-r--r--test/Modules/Inputs/declare-use/e.h6
-rw-r--r--test/Modules/Inputs/declare-use/f.h6
-rw-r--r--test/Modules/Inputs/declare-use/g.h6
-rw-r--r--test/Modules/Inputs/declare-use/g1.h1
-rw-r--r--test/Modules/Inputs/declare-use/h.h7
-rw-r--r--test/Modules/Inputs/declare-use/h1.h1
-rw-r--r--test/Modules/Inputs/declare-use/module.map43
-rw-r--r--test/Modules/Inputs/def.h7
-rw-r--r--test/Modules/Inputs/dummy.h3
-rw-r--r--test/Modules/Inputs/incomplete_mod.h1
-rw-r--r--test/Modules/Inputs/incomplete_mod_missing.h2
-rw-r--r--test/Modules/Inputs/initializer_list9
-rw-r--r--test/Modules/Inputs/modular_maps/a.h4
-rw-r--r--test/Modules/Inputs/modular_maps/b.h4
-rw-r--r--test/Modules/Inputs/modular_maps/common.h4
-rw-r--r--test/Modules/Inputs/modular_maps/modulea.map7
-rw-r--r--test/Modules/Inputs/modular_maps/moduleb.map4
-rw-r--r--test/Modules/Inputs/module.map72
-rw-r--r--test/Modules/Inputs/namespaces-top.h5
-rw-r--r--test/Modules/Inputs/odr/a.h13
-rw-r--r--test/Modules/Inputs/odr/b.h9
-rw-r--r--test/Modules/Inputs/odr/module.map6
-rw-r--r--test/Modules/Inputs/pch-used.h2
-rw-r--r--test/Modules/Inputs/private/common.h6
-rw-r--r--test/Modules/Inputs/private/module.map9
-rw-r--r--test/Modules/Inputs/private/private1.h9
-rw-r--r--test/Modules/Inputs/private/private2.h9
-rw-r--r--test/Modules/Inputs/private/public1.h9
-rw-r--r--test/Modules/Inputs/private/public2.h9
-rw-r--r--test/Modules/Inputs/private0/common.h6
-rw-r--r--test/Modules/Inputs/private1/module.map4
-rw-r--r--test/Modules/Inputs/private1/private1.h9
-rw-r--r--test/Modules/Inputs/private1/public1.h9
-rw-r--r--test/Modules/Inputs/private2/module.map4
-rw-r--r--test/Modules/Inputs/private2/private2.h9
-rw-r--r--test/Modules/Inputs/private2/public2.h9
-rw-r--r--test/Modules/Inputs/recursive_visibility_a1_inner.h4
-rw-r--r--test/Modules/Inputs/recursive_visibility_a2_more_inner.h4
-rw-r--r--test/Modules/Inputs/recursive_visibility_b.h2
-rw-r--r--test/Modules/Inputs/recursive_visibility_c.h5
-rw-r--r--test/Modules/Inputs/separate_map_tree/maps/modulea.map12
-rw-r--r--test/Modules/Inputs/separate_map_tree/maps/moduleb.map4
-rw-r--r--test/Modules/Inputs/separate_map_tree/maps/modulec.map5
-rw-r--r--test/Modules/Inputs/separate_map_tree/src/common.h4
-rw-r--r--test/Modules/Inputs/separate_map_tree/src/private-in-c.h4
-rw-r--r--test/Modules/Inputs/separate_map_tree/src/public-in-b.h4
-rw-r--r--test/Modules/Inputs/separate_map_tree/src/public-in-c.h4
-rw-r--r--test/Modules/Inputs/submodules/import-self-a.h1
-rw-r--r--test/Modules/Inputs/submodules/import-self-b.h10
-rw-r--r--test/Modules/Inputs/submodules/import-self-c.h1
-rw-r--r--test/Modules/Inputs/submodules/import-self-d.h1
-rw-r--r--test/Modules/Inputs/submodules/module.map7
-rw-r--r--test/Modules/Inputs/templates-left.h6
-rw-r--r--test/Modules/Inputs/templates-right.h6
-rw-r--r--test/Modules/Inputs/templates-top.h8
-rw-r--r--test/Modules/Inputs/using-decl-a.h10
-rw-r--r--test/Modules/Inputs/using-decl-b.h11
-rw-r--r--test/Modules/Inputs/warning.h1
-rw-r--r--test/Modules/auto-module-import.m27
-rw-r--r--test/Modules/autolink.m2
-rw-r--r--test/Modules/build-fail-notes.m6
-rw-r--r--test/Modules/compiler_builtins_arm.m6
-rw-r--r--test/Modules/cxx-decls.cpp21
-rw-r--r--test/Modules/cxx-templates.cpp125
-rw-r--r--test/Modules/cycles.c2
-rw-r--r--test/Modules/declare-use1.cpp7
-rw-r--r--test/Modules/declare-use2.cpp7
-rw-r--r--test/Modules/decldef.m12
-rw-r--r--test/Modules/decldef.mm24
-rw-r--r--test/Modules/driver.c4
-rw-r--r--test/Modules/epic-fail.m2
-rw-r--r--test/Modules/fatal-module-loader-error.m26
-rw-r--r--test/Modules/import-decl.cpp9
-rw-r--r--test/Modules/incomplete-module.m5
-rw-r--r--test/Modules/initializer_list.cpp7
-rw-r--r--test/Modules/load_failure.c2
-rw-r--r--test/Modules/macros.c2
-rw-r--r--test/Modules/method_pool.m4
-rw-r--r--test/Modules/modular_maps.cpp8
-rw-r--r--test/Modules/namespaces.cpp7
-rw-r--r--test/Modules/normal-module-map.cpp4
-rw-r--r--test/Modules/objc-categories.m1
-rw-r--r--test/Modules/odr.cpp20
-rw-r--r--test/Modules/pch-used.m8
-rw-r--r--test/Modules/private.cpp13
-rw-r--r--test/Modules/private1.cpp13
-rw-r--r--test/Modules/recursive_visibility.mm9
-rw-r--r--test/Modules/requires.m3
-rw-r--r--test/Modules/requires.mm6
-rw-r--r--test/Modules/self-import-header/af.framework/Headers/a1.h4
-rw-r--r--test/Modules/self-import-header/af.framework/Headers/a2.h1
-rw-r--r--test/Modules/self-import-header/af.framework/module.map4
-rw-r--r--test/Modules/self-import-header/depend_builtin/h1.h1
-rw-r--r--test/Modules/self-import-header/depend_builtin/module.map5
-rw-r--r--test/Modules/self-import-header/test.m8
-rw-r--r--test/Modules/separate_map_tree.cpp8
-rw-r--r--test/Modules/subframeworks.m3
-rw-r--r--test/Modules/submodules.cpp15
-rw-r--r--test/Modules/system_headers.m8
-rw-r--r--test/Modules/templates.mm37
-rw-r--r--test/Modules/using-decl.cpp8
-rw-r--r--test/OpenMP/openmp_common.c2
-rw-r--r--test/OpenMP/parallel_ast_print.cpp60
-rw-r--r--test/OpenMP/parallel_default_messages.cpp21
-rw-r--r--test/OpenMP/parallel_firstprivate_messages.cpp82
-rw-r--r--test/OpenMP/parallel_messages.cpp53
-rw-r--r--test/OpenMP/parallel_private_messages.cpp81
-rw-r--r--test/OpenMP/parallel_shared_messages.cpp83
-rw-r--r--test/OpenMP/predefined_macro.c1
-rw-r--r--test/OpenMP/threadprivate_ast_print.cpp20
-rw-r--r--test/OpenMP/threadprivate_messages.cpp46
-rw-r--r--test/PCH/Inputs/chain-selectors2.h2
-rw-r--r--test/PCH/arc.m4
-rw-r--r--test/PCH/badpch.c4
-rw-r--r--test/PCH/chain-categories2.m1
-rw-r--r--test/PCH/chain-cxx.cpp3
-rw-r--r--test/PCH/chain-friend-instantiation.cpp1
-rw-r--r--test/PCH/chain-selectors.m6
-rw-r--r--test/PCH/check-deserializations.cpp28
-rw-r--r--test/PCH/cxx-friends.cpp8
-rw-r--r--test/PCH/cxx-friends.h25
-rw-r--r--test/PCH/cxx-member-init.cpp14
-rw-r--r--test/PCH/cxx-namespaces.cpp15
-rw-r--r--test/PCH/cxx-namespaces.h3
-rw-r--r--test/PCH/cxx-templates.cpp29
-rw-r--r--test/PCH/cxx-templates.h42
-rw-r--r--test/PCH/cxx-traits.cpp4
-rw-r--r--test/PCH/cxx-traits.h4
-rw-r--r--test/PCH/cxx-typeid.cpp6
-rw-r--r--test/PCH/cxx11-lambdas.mm13
-rw-r--r--test/PCH/cxx1y-deduced-return-type.cpp34
-rw-r--r--test/PCH/cxx1y-init-captures.cpp28
-rw-r--r--test/PCH/cxx1y-lambdas.mm58
-rw-r--r--test/PCH/cxx1y-variable-templates.cpp171
-rw-r--r--test/PCH/debug-info-limited-struct.c4
-rw-r--r--test/PCH/debug-info-limited-struct.h8
-rw-r--r--test/PCH/exprs.h4
-rw-r--r--test/PCH/external-defs.c2
-rw-r--r--test/PCH/floating-literal.c4
-rw-r--r--test/PCH/irgen-rdar13114142.mm2
-rw-r--r--test/PCH/line-directive.c4
-rw-r--r--test/PCH/modified-header-error.c2
-rw-r--r--test/PCH/objc_container.m4
-rw-r--r--test/PCH/objc_import.h11
-rw-r--r--test/PCH/objc_import.m15
-rw-r--r--test/PCH/objc_literals.m10
-rw-r--r--test/PCH/objc_literals.mm4
-rw-r--r--test/PCH/objcxx-ivar-class.mm4
-rw-r--r--test/PCH/pch-dir.c8
-rw-r--r--test/PCH/pragma-diag-section.cpp16
-rw-r--r--test/PCH/pragma-weak.c4
-rw-r--r--test/PCH/preamble.c2
-rw-r--r--test/PCH/pth.c4
-rw-r--r--test/PCH/rdar10830559.cpp2
-rw-r--r--test/PCH/remap-file-from-pch.cpp2
-rw-r--r--test/Parser/DelayedTemplateParsing.cpp24
-rw-r--r--test/Parser/MicrosoftExtensions.c25
-rw-r--r--test/Parser/MicrosoftExtensions.cpp83
-rw-r--r--test/Parser/PR11000.cpp2
-rw-r--r--test/Parser/altivec-csk-bool.c14
-rw-r--r--test/Parser/attr-availability.c2
-rw-r--r--test/Parser/attributes.c2
-rw-r--r--test/Parser/crash-report.c2
-rw-r--r--test/Parser/cxx-altivec.cpp6
-rw-r--r--test/Parser/cxx-ambig-init-templ.cpp171
-rw-r--r--test/Parser/cxx-attributes.cpp14
-rw-r--r--test/Parser/cxx-class-template-specialization.cpp8
-rw-r--r--test/Parser/cxx-decl.cpp49
-rw-r--r--test/Parser/cxx-default-args.cpp17
-rw-r--r--test/Parser/cxx-friend.cpp4
-rw-r--r--test/Parser/cxx-member-crash.cpp4
-rw-r--r--test/Parser/cxx-member-initializers.cpp72
-rw-r--r--test/Parser/cxx-template-argument.cpp65
-rw-r--r--test/Parser/cxx-template-decl.cpp14
-rw-r--r--test/Parser/cxx-using-directive.cpp9
-rw-r--r--test/Parser/cxx0x-attributes.cpp38
-rw-r--r--test/Parser/cxx0x-decl.cpp31
-rw-r--r--test/Parser/cxx0x-in-cxx98.cpp7
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp16
-rw-r--r--test/Parser/cxx0x-member-initializers.cpp10
-rw-r--r--test/Parser/cxx11-stmt-attributes.cpp5
-rw-r--r--test/Parser/declarators.c3
-rw-r--r--test/Parser/expressions.c10
-rw-r--r--test/Parser/objc-diag-width.mm2
-rw-r--r--test/Parser/objc-error-qualified-implementation.m8
-rw-r--r--test/Parser/objcxx0x-lambda-expressions.mm24
-rw-r--r--test/Parser/parser_overflow.c8
-rw-r--r--test/Parser/pragma-fp-contract.c2
-rw-r--r--test/Parser/pragma-weak.c27
-rw-r--r--test/Parser/recovery.cpp73
-rw-r--r--test/Parser/switch-recovery.cpp6
-rw-r--r--test/Preprocessor/_Pragma.c3
-rw-r--r--test/Preprocessor/aarch64-target-features.c32
-rw-r--r--test/Preprocessor/arm-target-features.c157
-rw-r--r--test/Preprocessor/assembler-with-cpp.c7
-rw-r--r--test/Preprocessor/feature_tests.c1
-rw-r--r--test/Preprocessor/has_attribute.c4
-rw-r--r--test/Preprocessor/hash_line.c13
-rw-r--r--test/Preprocessor/ifdef-recover.c2
-rw-r--r--test/Preprocessor/init.c568
-rw-r--r--test/Preprocessor/iwithprefix.c7
-rw-r--r--test/Preprocessor/line-directive-output.c3
-rw-r--r--test/Preprocessor/line-directive.c4
-rw-r--r--test/Preprocessor/macro_backslash.c3
-rw-r--r--test/Preprocessor/macro_expand_empty.c14
-rw-r--r--test/Preprocessor/macro_fn.c5
-rw-r--r--test/Preprocessor/macro_paste_bad.c2
-rw-r--r--test/Preprocessor/macro_paste_bcpl_comment.c2
-rw-r--r--test/Preprocessor/macro_paste_empty.c10
-rw-r--r--test/Preprocessor/macro_paste_msextensions.c2
-rw-r--r--test/Preprocessor/macro_with_initializer_list.cpp182
-rw-r--r--test/Preprocessor/microsoft-ext.c12
-rw-r--r--test/Preprocessor/optimize.c2
-rw-r--r--test/Preprocessor/pragma_microsoft.c33
-rw-r--r--test/Preprocessor/pragma_microsoft.cpp3
-rw-r--r--test/Preprocessor/predefined-arch-macros.c246
-rw-r--r--test/Preprocessor/predefined-macros.c18
-rw-r--r--test/Preprocessor/stdint.c332
-rw-r--r--test/Preprocessor/traditional-cpp.c23
-rw-r--r--test/Preprocessor/ucn-pp-identifier.c2
-rw-r--r--test/Preprocessor/warn-macro-unused.c4
-rw-r--r--test/Preprocessor/x86_target_features.c264
-rw-r--r--test/Rewriter/blockcast3.mm4
-rw-r--r--test/Rewriter/dllimport-typedef.c4
-rw-r--r--test/Rewriter/inner-block-helper-funcs.mm2
-rw-r--r--test/Rewriter/line-generation-test.m4
-rw-r--r--test/Rewriter/lit.local.cfg2
-rw-r--r--test/Rewriter/missing-dllimport.c4
-rw-r--r--test/Rewriter/objc-modern-StretAPI-3.mm58
-rw-r--r--test/Rewriter/objc-modern-boxing.mm4
-rw-r--r--test/Rewriter/objc-modern-fast-enumeration.mm25
-rw-r--r--test/Rewriter/objc-modern-numeric-literal.mm4
-rw-r--r--test/Rewriter/objc-modern-property-attributes.mm12
-rw-r--r--test/Rewriter/rewrite-cast-ivar-access.mm2
-rw-r--r--test/Rewriter/rewrite-category-property.mm2
-rw-r--r--test/Rewriter/rewrite-foreach-5.m2
-rw-r--r--test/Rewriter/rewrite-foreach-6.m2
-rw-r--r--test/Rewriter/rewrite-foreach-in-block.mm4
-rw-r--r--test/Rewriter/rewrite-foreach-protocol-id.m2
-rw-r--r--test/Rewriter/rewrite-forward-class.mm13
-rw-r--r--test/Rewriter/rewrite-interface-locals.mm20
-rw-r--r--test/Rewriter/rewrite-line-directive.m4
-rw-r--r--test/Rewriter/rewrite-message-expr.mm2
-rw-r--r--test/Rewriter/rewrite-modern-default-property-synthesis.mm2
-rw-r--r--test/Rewriter/rewrite-modern-synchronized.m15
-rw-r--r--test/Rewriter/rewrite-modern-typeof.mm2
-rw-r--r--test/Rewriter/rewrite-typeof.mm2
-rw-r--r--test/Sema/128bitfloat.cc24
-rw-r--r--test/Sema/128bitint.c4
-rw-r--r--test/Sema/Inputs/ms-keyword-system-header.h9
-rw-r--r--test/Sema/MicrosoftCompatibility.cpp6
-rw-r--r--test/Sema/MicrosoftExtensions.c34
-rw-r--r--test/Sema/aarch64-neon-vector-types.c33
-rw-r--r--test/Sema/address_spaces.c2
-rw-r--r--test/Sema/alias-redefinition.c44
-rw-r--r--test/Sema/align-x86-64.c10
-rw-r--r--test/Sema/alloc_size.c6
-rw-r--r--test/Sema/annotate.c6
-rw-r--r--test/Sema/arm-asm.c5
-rw-r--r--test/Sema/arm-darwin-aapcs.cpp12
-rw-r--r--test/Sema/arm-interrupt-attr.c16
-rw-r--r--test/Sema/array-init.c3
-rw-r--r--test/Sema/array-size-64.c9
-rw-r--r--test/Sema/atomic-expr.c13
-rw-r--r--test/Sema/atomic-ops.c16
-rw-r--r--test/Sema/atomic-requires-library-error.c31
-rw-r--r--test/Sema/attr-alias-elf.c54
-rw-r--r--test/Sema/attr-args.c50
-rw-r--r--test/Sema/attr-bounded.c15
-rw-r--r--test/Sema/attr-cleanup.c22
-rw-r--r--test/Sema/attr-deprecated.c4
-rw-r--r--test/Sema/attr-endian.c3
-rw-r--r--test/Sema/attr-format.c2
-rw-r--r--test/Sema/attr-mode.c18
-rw-r--r--test/Sema/attr-naked.c4
-rw-r--r--test/Sema/attr-nodebug.c4
-rw-r--r--test/Sema/attr-noinline.c2
-rw-r--r--test/Sema/attr-noreturn.c6
-rw-r--r--test/Sema/attr-ownership.c19
-rw-r--r--test/Sema/attr-print.c19
-rw-r--r--test/Sema/attr-regparm.c4
-rw-r--r--test/Sema/attr-returns-twice.c2
-rw-r--r--test/Sema/attr-section.c2
-rw-r--r--test/Sema/attr-tls_model.c4
-rw-r--r--test/Sema/attr-unavailable-message.c9
-rw-r--r--test/Sema/attr-unused.c2
-rw-r--r--test/Sema/attr-visibility.c2
-rw-r--r--test/Sema/block-args.c11
-rw-r--r--test/Sema/builtin-clear_cache.c5
-rw-r--r--test/Sema/builtins-aarch64.c5
-rw-r--r--test/Sema/builtins-arm-exclusive.c61
-rw-r--r--test/Sema/builtins-arm-strex-rettype.c8
-rw-r--r--test/Sema/builtins-arm.c16
-rw-r--r--test/Sema/builtins-gnu-mode.c27
-rw-r--r--test/Sema/builtins.c8
-rw-r--r--test/Sema/c89.c11
-rw-r--r--test/Sema/callingconv-ms_abi.c9
-rw-r--r--test/Sema/callingconv-sysv_abi.c9
-rw-r--r--test/Sema/callingconv.c28
-rw-r--r--test/Sema/captured-statements.c12
-rw-r--r--test/Sema/carbon.c3
-rw-r--r--test/Sema/cast.c8
-rw-r--r--test/Sema/constant-builtins-2.c118
-rw-r--r--test/Sema/convertvector.c17
-rw-r--r--test/Sema/declspec.c13
-rw-r--r--test/Sema/designated-initializers.c66
-rw-r--r--test/Sema/dllimport-dllexport.c5
-rw-r--r--test/Sema/empty1.c85
-rw-r--r--test/Sema/empty2.c43
-rw-r--r--test/Sema/enum-increment.c13
-rw-r--r--test/Sema/ext_vector_casts.c26
-rw-r--r--test/Sema/extern-redecl.c24
-rw-r--r--test/Sema/format-strings-ms.c25
-rw-r--r--test/Sema/format-strings.c10
-rw-r--r--test/Sema/freemain.c2
-rw-r--r--test/Sema/function.c10
-rw-r--r--test/Sema/gnu-flags.c171
-rw-r--r--test/Sema/init.c3
-rw-r--r--test/Sema/inline.c13
-rw-r--r--test/Sema/member-reference.c5
-rw-r--r--test/Sema/mips16_attr_allowed.c20
-rw-r--r--test/Sema/mrtd.c38
-rw-r--r--test/Sema/ms-inline-asm.c12
-rw-r--r--test/Sema/ms-keyword-system-header.c17
-rw-r--r--test/Sema/ms-wchar.c18
-rw-r--r--test/Sema/ms_abi-sysv_abi.c14
-rw-r--r--test/Sema/ms_bitfield_layout.c243
-rw-r--r--test/Sema/ms_class_layout.cpp88
-rw-r--r--test/Sema/neon-vector-types-support.c4
-rw-r--r--test/Sema/neon-vector-types.c7
-rw-r--r--test/Sema/nonnull.c3
-rw-r--r--test/Sema/offsetof-64.c22
-rw-r--r--test/Sema/offsetof.c1
-rw-r--r--test/Sema/overloadable.c18
-rw-r--r--test/Sema/parentheses.c2
-rw-r--r--test/Sema/pragma-weak.c11
-rw-r--r--test/Sema/string-init.c51
-rw-r--r--test/Sema/string-plus-char.c15
-rw-r--r--test/Sema/struct-decl.c9
-rw-r--r--test/Sema/thread-specifier.c4
-rw-r--r--test/Sema/types.c8
-rw-r--r--test/Sema/varargs.c7
-rw-r--r--test/Sema/varargs.cpp7
-rw-r--r--test/Sema/vfprintf-valid-redecl.c11
-rw-r--r--test/Sema/warn-documentation-fixits.cpp26
-rw-r--r--test/Sema/warn-documentation.cpp91
-rw-r--r--test/Sema/warn-documentation.m57
-rw-r--r--test/Sema/warn-main-return-type.c4
-rw-r--r--test/Sema/warn-main.c12
-rw-r--r--test/Sema/warn-null.c11
-rw-r--r--test/Sema/warn-outof-range-assign-enum.c12
-rw-r--r--test/Sema/warn-shadow-intrinsics.c11
-rw-r--r--test/Sema/warn-thread-safety-analysis.c123
-rw-r--r--test/Sema/warn-type-safety.c4
-rw-r--r--test/Sema/warn-unsequenced.c88
-rw-r--r--test/Sema/warn-unused-function.c6
-rw-r--r--test/Sema/warn-unused-label.c4
-rw-r--r--test/Sema/warn-unused-parameters.c2
-rw-r--r--test/Sema/warn-variable-not-needed.c9
-rw-r--r--test/Sema/wchar.c4
-rw-r--r--test/SemaCXX/Inputs/lit.local.cfg1
-rw-r--r--test/SemaCXX/Inputs/register.h5
-rw-r--r--test/SemaCXX/Inputs/warn-unused-variables.h2
-rw-r--r--test/SemaCXX/MicrosoftCompatibility.cpp16
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp79
-rw-r--r--test/SemaCXX/PR10447.cpp4
-rw-r--r--test/SemaCXX/PR12778.cpp7
-rw-r--r--test/SemaCXX/PR9572.cpp2
-rw-r--r--test/SemaCXX/__try.cpp20
-rw-r--r--test/SemaCXX/abstract.cpp36
-rw-r--r--test/SemaCXX/access.cpp34
-rw-r--r--test/SemaCXX/addr-of-overloaded-function-casting.cpp8
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp37
-rw-r--r--test/SemaCXX/alignment-of-derived-class.cpp41
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp4
-rw-r--r--test/SemaCXX/alignof.cpp14
-rw-r--r--test/SemaCXX/ambiguous-conversion-show-overload.cpp2
-rw-r--r--test/SemaCXX/anonymous-union.cpp9
-rw-r--r--test/SemaCXX/ast-print.cpp16
-rw-r--r--test/SemaCXX/attr-aligned.cpp16
-rw-r--r--test/SemaCXX/attr-cleanup-gcc.cpp16
-rw-r--r--test/SemaCXX/attr-cleanup.cpp29
-rw-r--r--test/SemaCXX/attr-common.cpp3
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp4
-rw-r--r--test/SemaCXX/attr-deprecated.cpp6
-rw-r--r--test/SemaCXX/attr-no-sanitize-address.cpp2
-rw-r--r--test/SemaCXX/attr-no-sanitize-memory.cpp2
-rw-r--r--test/SemaCXX/attr-no-sanitize-thread.cpp2
-rw-r--r--test/SemaCXX/attr-print.cpp6
-rw-r--r--test/SemaCXX/attr-selectany.cpp33
-rw-r--r--test/SemaCXX/attr-used.cpp5
-rw-r--r--test/SemaCXX/attr-weakref.cpp2
-rw-r--r--test/SemaCXX/blocks-1.cpp18
-rw-r--r--test/SemaCXX/bool.cpp2
-rw-r--r--test/SemaCXX/builtins.cpp22
-rw-r--r--test/SemaCXX/c99.cpp2
-rw-r--r--test/SemaCXX/calling-conv-compat.cpp387
-rw-r--r--test/SemaCXX/captured-statements.cpp7
-rw-r--r--test/SemaCXX/cast-conversion.cpp18
-rw-r--r--test/SemaCXX/class-base-member-init.cpp10
-rw-r--r--test/SemaCXX/class-layout.cpp469
-rw-r--r--test/SemaCXX/class.cpp6
-rw-r--r--test/SemaCXX/compare.cpp67
-rw-r--r--test/SemaCXX/complex-overload.cpp12
-rw-r--r--test/SemaCXX/compound-literal.cpp10
-rw-r--r--test/SemaCXX/conditional-expr.cpp2
-rw-r--r--test/SemaCXX/const-cast.cpp2
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp388
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp468
-rw-r--r--test/SemaCXX/constexpr-backtrace-limit.cpp8
-rw-r--r--test/SemaCXX/constexpr-duffs-device.cpp32
-rw-r--r--test/SemaCXX/constexpr-steps.cpp17
-rw-r--r--test/SemaCXX/constexpr-turing.cpp16
-rw-r--r--test/SemaCXX/constexpr-value-init.cpp2
-rw-r--r--test/SemaCXX/conversion-delete-expr.cpp24
-rw-r--r--test/SemaCXX/conversion-function.cpp4
-rw-r--r--test/SemaCXX/conversion-incomplete-type.cpp23
-rw-r--r--test/SemaCXX/crashes.cpp47
-rw-r--r--test/SemaCXX/cxx0x-class.cpp2
-rw-r--r--test/SemaCXX/cxx0x-compat.cpp9
-rw-r--r--test/SemaCXX/cxx0x-initializer-aggregates.cpp27
-rw-r--r--test/SemaCXX/cxx0x-initializer-references.cpp25
-rw-r--r--test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp24
-rw-r--r--test/SemaCXX/cxx0x-nontrivial-union.cpp22
-rw-r--r--test/SemaCXX/cxx11-attr-print.cpp5
-rw-r--r--test/SemaCXX/cxx11-crashes.cpp4
-rw-r--r--test/SemaCXX/cxx11-gnu-attrs.cpp5
-rw-r--r--test/SemaCXX/cxx11-thread-local-print.cpp6
-rw-r--r--test/SemaCXX/cxx1y-array-runtime-bound.cpp68
-rw-r--r--test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp177
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp152
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp1363
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas.cpp908
-rw-r--r--test/SemaCXX/cxx1y-init-captures.cpp169
-rw-r--r--test/SemaCXX/cxx1y-sized-deallocation.cpp17
-rw-r--r--test/SemaCXX/cxx1y-user-defined-literals.cpp44
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_in_class.cpp299
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_top_level.cpp434
-rw-r--r--test/SemaCXX/cxx98-compat-pedantic.cpp18
-rw-r--r--test/SemaCXX/cxx98-compat.cpp86
-rw-r--r--test/SemaCXX/dcl_ambig_res.cpp4
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp1
-rw-r--r--test/SemaCXX/decl-init-ref.cpp11
-rw-r--r--test/SemaCXX/decl-microsoft-call-conv.cpp143
-rw-r--r--test/SemaCXX/decltype.cpp8
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp8
-rw-r--r--test/SemaCXX/default1.cpp11
-rw-r--r--test/SemaCXX/deprecated.cpp67
-rw-r--r--test/SemaCXX/destructor.cpp4
-rw-r--r--test/SemaCXX/dynamic-cast.cpp2
-rw-r--r--test/SemaCXX/enum-increment.cpp16
-rw-r--r--test/SemaCXX/enum-scoped.cpp30
-rw-r--r--test/SemaCXX/enum-unscoped-nonexistent.cpp4
-rw-r--r--test/SemaCXX/err_init_conversion_failed.cpp45
-rw-r--r--test/SemaCXX/explicit.cpp91
-rw-r--r--test/SemaCXX/expression-traits.cpp4
-rw-r--r--test/SemaCXX/extern-c.cpp174
-rw-r--r--test/SemaCXX/flexible-array-test.cpp4
-rw-r--r--test/SemaCXX/for-range-examples.cpp31
-rw-r--r--test/SemaCXX/format-strings-0x.cpp4
-rw-r--r--test/SemaCXX/friend.cpp138
-rw-r--r--test/SemaCXX/function-pointer-arguments.cpp52
-rw-r--r--test/SemaCXX/function-redecl.cpp18
-rw-r--r--test/SemaCXX/function-type-qual.cpp8
-rw-r--r--test/SemaCXX/gnu-flags.cpp76
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp2
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp6
-rw-r--r--test/SemaCXX/inherit.cpp3
-rw-r--r--test/SemaCXX/init-priority-attr.cpp4
-rw-r--r--test/SemaCXX/lambda-expressions.cpp65
-rw-r--r--test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp34
-rw-r--r--test/SemaCXX/linkage-spec.cpp61
-rw-r--r--test/SemaCXX/linkage2.cpp55
-rw-r--r--test/SemaCXX/member-expr.cpp54
-rw-r--r--test/SemaCXX/member-init.cpp11
-rw-r--r--test/SemaCXX/member-pointer-ms.cpp5
-rw-r--r--test/SemaCXX/microsoft-dtor-lookup.cpp87
-rw-r--r--test/SemaCXX/microsoft-new-delete.cpp12
-rw-r--r--test/SemaCXX/missing-members.cpp10
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp8
-rw-r--r--test/SemaCXX/ms-overload-entry-point.cpp21
-rw-r--r--test/SemaCXX/ms-wchar.cpp12
-rw-r--r--test/SemaCXX/ms_struct.cpp18
-rw-r--r--test/SemaCXX/ms_wide_bitfield.cpp9
-rw-r--r--test/SemaCXX/neon-vector-types.cpp2
-rw-r--r--test/SemaCXX/nested-name-spec.cpp22
-rw-r--r--test/SemaCXX/new-delete-0x.cpp4
-rw-r--r--test/SemaCXX/new-delete.cpp15
-rw-r--r--test/SemaCXX/no-rtti.cpp19
-rw-r--r--test/SemaCXX/no-warn-unused-const-variables.cpp6
-rw-r--r--test/SemaCXX/nullptr.cpp3
-rw-r--r--test/SemaCXX/offsetof.cpp10
-rw-r--r--test/SemaCXX/operator-arrow-depth.cpp26
-rw-r--r--test/SemaCXX/overload-decl.cpp8
-rw-r--r--test/SemaCXX/overloaded-operator.cpp20
-rw-r--r--test/SemaCXX/parentheses.cpp8
-rw-r--r--test/SemaCXX/pr13394-crash-on-invalid.cpp17
-rw-r--r--test/SemaCXX/predefined-expr.cpp103
-rw-r--r--test/SemaCXX/qualified-id-lookup.cpp6
-rw-r--r--test/SemaCXX/references.cpp7
-rw-r--r--test/SemaCXX/scope-check.cpp21
-rw-r--r--test/SemaCXX/self-comparison.cpp23
-rw-r--r--test/SemaCXX/static-data-member.cpp17
-rw-r--r--test/SemaCXX/storage-class.cpp2
-rw-r--r--test/SemaCXX/string-init.cpp40
-rw-r--r--test/SemaCXX/string-plus-char.cpp32
-rw-r--r--test/SemaCXX/struct-class-redecl.cpp2
-rw-r--r--test/SemaCXX/switch.cpp15
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp8
-rw-r--r--test/SemaCXX/type-traits.cpp65
-rw-r--r--test/SemaCXX/typo-correction-pt2.cpp201
-rw-r--r--test/SemaCXX/typo-correction.cpp96
-rw-r--r--test/SemaCXX/uninitialized.cpp211
-rw-r--r--test/SemaCXX/unknown-type-name.cpp4
-rw-r--r--test/SemaCXX/using-decl-1.cpp42
-rw-r--r--test/SemaCXX/using-decl-templates.cpp14
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp50
-rw-r--r--test/SemaCXX/vector.cpp19
-rw-r--r--test/SemaCXX/virtual-base-used.cpp8
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp4
-rw-r--r--test/SemaCXX/virtual-override-x86.cpp4
-rw-r--r--test/SemaCXX/virtuals.cpp6
-rw-r--r--test/SemaCXX/warn-consumed-analysis.cpp795
-rw-r--r--test/SemaCXX/warn-consumed-parsing.cpp55
-rw-r--r--test/SemaCXX/warn-dangling-field.cpp16
-rw-r--r--test/SemaCXX/warn-div-or-rem-by-zero.cpp21
-rw-r--r--test/SemaCXX/warn-empty-body.cpp5
-rw-r--r--test/SemaCXX/warn-func-not-needed.cpp9
-rw-r--r--test/SemaCXX/warn-global-constructors.cpp6
-rw-r--r--test/SemaCXX/warn-logical-not-compare.cpp194
-rw-r--r--test/SemaCXX/warn-loop-analysis.cpp108
-rw-r--r--test/SemaCXX/warn-member-not-needed.cpp11
-rw-r--r--test/SemaCXX/warn-missing-variable-declarations.cpp6
-rw-r--r--test/SemaCXX/warn-reinterpret-base-class.cpp2
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp413
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp60
-rw-r--r--test/SemaCXX/warn-unreachable.cpp4
-rw-r--r--test/SemaCXX/warn-unsequenced.cpp14
-rw-r--r--test/SemaCXX/warn-unused-attribute.cpp20
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp81
-rw-r--r--test/SemaCXX/warn-unused-private-field.cpp2
-rw-r--r--test/SemaCXX/warn-unused-result.cpp16
-rw-r--r--test/SemaCXX/warn-unused-value.cpp20
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp25
-rw-r--r--test/SemaCXX/warn-using-namespace-in-header.cpp9
-rw-r--r--test/SemaCXX/writable-strings-deprecated.cpp4
-rw-r--r--test/SemaObjC/arc-bridged-cast.m2
-rw-r--r--test/SemaObjC/arc-cf.m12
-rw-r--r--test/SemaObjC/arc-decls.m24
-rw-r--r--test/SemaObjC/arc-dict-bridged-cast.m2
-rw-r--r--test/SemaObjC/arc-property-lifetime.m32
-rw-r--r--test/SemaObjC/arc-readonly-property-ivar-1.m4
-rw-r--r--test/SemaObjC/arc-repeated-weak.mm15
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m4
-rw-r--r--test/SemaObjC/arc.m19
-rw-r--r--test/SemaObjC/attr-objc-exception.m4
-rw-r--r--test/SemaObjC/attr-objc-gc.m6
-rw-r--r--test/SemaObjC/attr-print.m9
-rw-r--r--test/SemaObjC/attr-root-class.m6
-rw-r--r--test/SemaObjC/bad-property-synthesis-crash.m2
-rw-r--r--test/SemaObjC/blocks.m15
-rw-r--r--test/SemaObjC/call-super-2.m6
-rw-r--r--test/SemaObjC/class-def-test-1.m5
-rw-r--r--test/SemaObjC/compare-qualified-id.m2
-rw-r--r--test/SemaObjC/conditional-expr.m3
-rw-r--r--test/SemaObjC/conversion.m17
-rw-r--r--test/SemaObjC/dealloc.m2
-rw-r--r--test/SemaObjC/default-synthesize-1.m2
-rw-r--r--test/SemaObjC/default-synthesize-2.m4
-rw-r--r--test/SemaObjC/default-synthesize-3.m74
-rw-r--r--test/SemaObjC/default-synthesize.m2
-rw-r--r--test/SemaObjC/deprecated-objc-introspection.m7
-rw-r--r--test/SemaObjC/direct-synthesized-ivar-access.m2
-rw-r--r--test/SemaObjC/error-outof-scope-property-use.m8
-rw-r--r--test/SemaObjC/foreach.m6
-rw-r--r--test/SemaObjC/format-arg-attribute.m34
-rw-r--r--test/SemaObjC/format-strings-objc.m7
-rw-r--r--test/SemaObjC/forward-protocol-incomplete-impl-warn.m2
-rw-r--r--test/SemaObjC/iboutlet.m4
-rw-r--r--test/SemaObjC/iboutletcollection-attr.m17
-rw-r--r--test/SemaObjC/idiomatic-parentheses.m7
-rw-r--r--test/SemaObjC/instancetype.m2
-rw-r--r--test/SemaObjC/ivar-lookup.m74
-rw-r--r--test/SemaObjC/ivar-ref-misuse.m5
-rw-r--r--test/SemaObjC/message.m2
-rw-r--r--test/SemaObjC/method-bad-param.m14
-rw-r--r--test/SemaObjC/method-conflict-2.m49
-rw-r--r--test/SemaObjC/method-not-defined.m2
-rw-r--r--test/SemaObjC/method-sentinel-attr.m2
-rw-r--r--test/SemaObjC/missing-atend-metadata.m2
-rw-r--r--test/SemaObjC/nsobject-attribute.m2
-rw-r--r--test/SemaObjC/objc-array-literal.m16
-rw-r--r--test/SemaObjC/objc-dictionary-literal.m2
-rw-r--r--test/SemaObjC/objcbridge-attribute.m66
-rw-r--r--test/SemaObjC/overriding-property-in-class-extension.m3
-rw-r--r--test/SemaObjC/property-5.m2
-rw-r--r--test/SemaObjC/property-ambiguous-synthesis.m48
-rw-r--r--test/SemaObjC/property-category-1.m2
-rw-r--r--test/SemaObjC/property-choose-expr.m14
-rw-r--r--test/SemaObjC/property-in-class-extension-1.m9
-rw-r--r--test/SemaObjC/property-ownership-attr.m19
-rw-r--r--test/SemaObjC/protocol-id-test-1.m4
-rw-r--r--test/SemaObjC/protocol-id-test-2.m2
-rw-r--r--test/SemaObjC/provisional-ivar-lookup.m2
-rw-r--r--test/SemaObjC/related-result-type-inference.m18
-rw-r--r--test/SemaObjC/selector-3.m35
-rw-r--r--test/SemaObjC/self-comparison.m12
-rw-r--r--test/SemaObjC/sign-conversion.m39
-rw-r--r--test/SemaObjC/super-class-protocol-conformance.m2
-rw-r--r--test/SemaObjC/super-dealloc-attribute.m49
-rw-r--r--test/SemaObjC/super-property-notation.m2
-rw-r--r--test/SemaObjC/synth-provisional-ivars-1.m2
-rw-r--r--test/SemaObjC/synth-provisional-ivars.m2
-rw-r--r--test/SemaObjC/synthesized-ivar.m2
-rw-r--r--test/SemaObjC/tentative-property-decl.m4
-rw-r--r--test/SemaObjC/unimplemented-protocol-prop.m2
-rw-r--r--test/SemaObjC/unsued-backing-ivar-warning.m76
-rw-r--r--test/SemaObjC/warn-direct-ivar-access.m2
-rw-r--r--test/SemaObjC/warn-implicit-atomic-property.m2
-rw-r--r--test/SemaObjC/warn-missing-super.m2
-rw-r--r--test/SemaObjC/warn-retain-block-property.m4
-rw-r--r--test/SemaObjCXX/abstract-class-type-ivar.mm4
-rw-r--r--test/SemaObjCXX/arc-nsconsumed-errors.mm5
-rw-r--r--test/SemaObjCXX/arc-templates.mm10
-rw-r--r--test/SemaObjCXX/contextual-convert-to-id.mm33
-rw-r--r--test/SemaObjCXX/exceptions.mm11
-rw-r--r--test/SemaObjCXX/instancetype.mm2
-rw-r--r--test/SemaObjCXX/ivar-construct.mm2
-rw-r--r--test/SemaObjCXX/microsoft-abi-byval.mm14
-rw-r--r--test/SemaObjCXX/missing-lhs-gun-extension.mm23
-rw-r--r--test/SemaObjCXX/overload-1.mm25
-rw-r--r--test/SemaObjCXX/overload.mm17
-rw-r--r--test/SemaObjCXX/properties.mm39
-rw-r--r--test/SemaObjCXX/property-synthesis-error.mm2
-rw-r--r--test/SemaOpenCL/endian-attr.cl8
-rw-r--r--test/SemaOpenCL/event_t.cl3
-rw-r--r--test/SemaOpenCL/invalid-kernel-attrs.cl4
-rw-r--r--test/SemaOpenCL/invalid-kernel-parameters.cl132
-rw-r--r--test/SemaOpenCL/invalid-kernel.cl10
-rw-r--r--test/SemaOpenCL/str_literals.cl13
-rw-r--r--test/SemaOpenCL/vector_inc_dec_ops.cl19
-rw-r--r--test/SemaTemplate/alias-nested-nontag.cpp3
-rw-r--r--test/SemaTemplate/alias-templates.cpp35
-rw-r--r--test/SemaTemplate/array-to-pointer-decay.cpp12
-rw-r--r--test/SemaTemplate/canonical-expr-type.cpp6
-rw-r--r--test/SemaTemplate/class-template-decl.cpp4
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp4
-rw-r--r--test/SemaTemplate/deduction-crash.cpp36
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp31
-rw-r--r--test/SemaTemplate/default-arguments.cpp39
-rw-r--r--test/SemaTemplate/dependent-expr.cpp21
-rw-r--r--test/SemaTemplate/dependent-names.cpp13
-rw-r--r--test/SemaTemplate/derived.cpp24
-rw-r--r--test/SemaTemplate/destructor-template.cpp8
-rw-r--r--test/SemaTemplate/exception-spec-crash.cpp30
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp58
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp28
-rw-r--r--test/SemaTemplate/extension-sfinae.cpp12
-rw-r--r--test/SemaTemplate/friend-template.cpp17
-rw-r--r--test/SemaTemplate/function-template-specialization-noreturn.cpp8
-rw-r--r--test/SemaTemplate/function-template-specialization.cpp12
-rw-r--r--test/SemaTemplate/instantiate-exception-spec-cxx11.cpp13
-rw-r--r--test/SemaTemplate/instantiate-expr-5.cpp10
-rw-r--r--test/SemaTemplate/instantiate-function-params.cpp17
-rw-r--r--test/SemaTemplate/instantiate-init.cpp15
-rw-r--r--test/SemaTemplate/instantiate-local-class.cpp117
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-pointers.cpp9
-rw-r--r--test/SemaTemplate/instantiate-overload-candidates.cpp2
-rw-r--r--test/SemaTemplate/instantiate-partial-spec.cpp23
-rw-r--r--test/SemaTemplate/instantiate-using-decl.cpp24
-rw-r--r--test/SemaTemplate/local-member-templates.cpp76
-rw-r--r--test/SemaTemplate/lookup-dependent-bases.cpp2
-rw-r--r--test/SemaTemplate/ms-class-specialization-class-scope.cpp49
-rw-r--r--test/SemaTemplate/ms-lookup-template-base-classes.cpp40
-rw-r--r--test/SemaTemplate/nested-template.cpp1
-rw-r--r--test/SemaTemplate/overload-candidates.cpp45
-rw-r--r--test/SemaTemplate/recovery-crash.cpp19
-rw-r--r--test/SemaTemplate/resolve-single-template-id.cpp4
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp34
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp11
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp14
-rw-r--r--test/Tooling/Inputs/lit.local.cfg1
-rw-r--r--test/Tooling/auto-detect-from-source-parent-of-cwd.cpp6
-rw-r--r--test/Tooling/auto-detect-from-source-parent.cpp2
-rw-r--r--test/Tooling/auto-detect-from-source.cpp2
-rw-r--r--test/Tooling/clang-check-analyzer.cpp4
-rw-r--r--test/Tooling/clang-check-args.cpp2
-rw-r--r--test/Tooling/clang-check-autodetect-dir.cpp2
-rw-r--r--test/Tooling/clang-check-builtin-headers.cpp2
-rw-r--r--test/Tooling/clang-check-chdir.cpp2
-rw-r--r--test/Tooling/clang-check-extra-arg.cpp5
-rw-r--r--test/Tooling/clang-check-pwd.cpp6
-rw-r--r--test/Tooling/clang-check-rel-path.cpp10
-rw-r--r--test/Tooling/clang-check-strip-o.cpp11
-rw-r--r--test/Tooling/clang-check.cpp2
-rw-r--r--test/Tooling/ms-asm-no-target.cpp13
-rw-r--r--test/Tooling/multi-jobs.cpp5
-rw-r--r--test/Unit/lit.cfg17
-rw-r--r--test/Unit/lit.site.cfg.in15
-rw-r--r--test/lit.cfg119
-rw-r--r--test/lit.site.cfg.in17
-rw-r--r--tools/CMakeLists.txt19
-rw-r--r--tools/Makefile24
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp4
-rw-r--r--tools/c-arcmt-test/Makefile4
-rw-r--r--tools/c-index-test/CMakeLists.txt2
-rw-r--r--tools/c-index-test/Makefile12
-rw-r--r--tools/c-index-test/c-index-test.c12
-rw-r--r--tools/clang-check/CMakeLists.txt1
-rw-r--r--tools/clang-check/ClangCheck.cpp79
-rw-r--r--tools/clang-check/Makefile9
-rw-r--r--tools/clang-format-vs/ClangFormat.sln20
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.csproj227
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.vsct119
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs220
-rw-r--r--tools/clang-format-vs/ClangFormat/GlobalSuppressions.cs11
-rw-r--r--tools/clang-format-vs/ClangFormat/Guids.cs12
-rw-r--r--tools/clang-format-vs/ClangFormat/PkgCmdID.cs7
-rw-r--r--tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs33
-rw-r--r--tools/clang-format-vs/ClangFormat/Resources.Designer.cs64
-rw-r--r--tools/clang-format-vs/ClangFormat/Resources.resx129
-rw-r--r--tools/clang-format-vs/ClangFormat/Resources/Images_32bit.bmpbin0 -> 5176 bytes
-rw-r--r--tools/clang-format-vs/ClangFormat/Resources/Package.icobin0 -> 1078 bytes
-rw-r--r--tools/clang-format-vs/ClangFormat/VSPackage.resx140
-rw-r--r--tools/clang-format-vs/ClangFormat/source.extension.vsixmanifest31
-rw-r--r--tools/clang-format-vs/README.txt6
-rw-r--r--tools/clang-format/CMakeLists.txt10
-rw-r--r--tools/clang-format/ClangFormat.cpp202
-rw-r--r--tools/clang-format/Makefile2
-rwxr-xr-xtools/clang-format/clang-format-diff.py118
-rw-r--r--tools/clang-format/clang-format-sublime.py58
-rw-r--r--tools/clang-format/clang-format.el57
-rw-r--r--tools/clang-format/clang-format.py50
-rwxr-xr-xtools/clang-format/git-clang-format481
-rw-r--r--tools/diagtool/DiagnosticNames.cpp23
-rw-r--r--tools/diagtool/DiagnosticNames.h36
-rw-r--r--tools/diagtool/Makefile2
-rw-r--r--tools/diagtool/TreeView.cpp8
-rw-r--r--tools/driver/CMakeLists.txt73
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1_main.cpp7
-rw-r--r--tools/driver/cc1as_main.cpp46
-rw-r--r--tools/driver/clang_symlink.cmake16
-rw-r--r--tools/driver/driver.cpp202
-rw-r--r--tools/libclang/CIndex.cpp318
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp22
-rw-r--r--tools/libclang/CIndexHigh.cpp2
-rw-r--r--tools/libclang/CIndexUSRs.cpp848
-rw-r--r--tools/libclang/CIndexer.cpp87
-rw-r--r--tools/libclang/CIndexer.h15
-rw-r--r--tools/libclang/CMakeLists.txt22
-rw-r--r--tools/libclang/CXComment.cpp1094
-rw-r--r--tools/libclang/CXComment.h12
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp37
-rw-r--r--tools/libclang/CXCursor.cpp14
-rw-r--r--tools/libclang/CXSourceLocation.cpp41
-rw-r--r--tools/libclang/CXTranslationUnit.h7
-rw-r--r--tools/libclang/CXType.cpp70
-rw-r--r--tools/libclang/IndexBody.cpp4
-rw-r--r--tools/libclang/IndexDecl.cpp15
-rw-r--r--tools/libclang/Indexing.cpp44
-rw-r--r--tools/libclang/IndexingContext.cpp25
-rw-r--r--tools/libclang/IndexingContext.h35
-rw-r--r--tools/libclang/Makefile10
-rw-r--r--tools/libclang/RecursiveASTVisitor.h170
-rw-r--r--tools/libclang/libclang.exports5
-rwxr-xr-xtools/scan-build/ccc-analyzer45
-rwxr-xr-xtools/scan-build/scan-build73
-rw-r--r--unittests/AST/ASTTypeTraitsTest.cpp114
-rw-r--r--unittests/AST/ASTVectorTest.cpp24
-rw-r--r--unittests/AST/CMakeLists.txt3
-rw-r--r--unittests/AST/CommentParser.cpp35
-rw-r--r--unittests/AST/DeclTest.cpp59
-rw-r--r--unittests/AST/Makefile2
-rw-r--r--unittests/AST/MatchVerifier.h93
-rw-r--r--unittests/AST/SourceLocationTest.cpp111
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp360
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h33
-rw-r--r--unittests/ASTMatchers/CMakeLists.txt2
-rw-r--r--unittests/ASTMatchers/Dynamic/CMakeLists.txt7
-rw-r--r--unittests/ASTMatchers/Dynamic/Makefile20
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp238
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp347
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp144
-rw-r--r--unittests/ASTMatchers/Makefile4
-rw-r--r--unittests/Basic/FileManagerTest.cpp40
-rw-r--r--unittests/Basic/SourceManagerTest.cpp6
-rw-r--r--unittests/CMakeLists.txt15
-rw-r--r--unittests/Format/FormatTest.cpp3984
-rw-r--r--unittests/Format/Makefile2
-rw-r--r--unittests/Frontend/Makefile2
-rw-r--r--unittests/Lex/CMakeLists.txt2
-rw-r--r--unittests/Lex/LexerTest.cpp280
-rw-r--r--unittests/Lex/Makefile5
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp105
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp2
-rw-r--r--unittests/Makefile8
-rw-r--r--unittests/Sema/CMakeLists.txt7
-rw-r--r--unittests/Sema/ExternalSemaSourceTest.cpp266
-rw-r--r--unittests/Sema/Makefile19
-rw-r--r--unittests/Tooling/CMakeLists.txt1
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp50
-rw-r--r--unittests/Tooling/Makefile2
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp120
-rw-r--r--unittests/Tooling/RefactoringTest.cpp193
-rw-r--r--unittests/Tooling/ReplacementsYamlTest.cpp106
-rw-r--r--unittests/Tooling/RewriterTestContext.h42
-rw-r--r--unittests/Tooling/TestVisitor.h11
-rw-r--r--unittests/Tooling/ToolingTest.cpp165
-rwxr-xr-xutils/ABITest/ABITestGen.py2
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp395
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp1
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp172
-rw-r--r--utils/TableGen/NeonEmitter.cpp1508
-rw-r--r--utils/TableGen/OptParserEmitter.cpp275
-rw-r--r--utils/TableGen/TableGen.cpp191
-rw-r--r--utils/TableGen/TableGenBackends.h6
-rw-r--r--utils/analyzer/SATestBuild.py10
-rw-r--r--utils/find-unused-diagnostics.sh2
-rw-r--r--www/analyzer/checker_dev_manual.html336
-rw-r--r--www/analyzer/content.css5
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/open_projects.html17
-rw-r--r--www/analyzer/potential_checkers.html66
-rw-r--r--www/analyzer/release_notes.html43
-rw-r--r--www/analyzer/scan-build.html18
-rw-r--r--www/cxx_dr_status.html10593
-rw-r--r--www/cxx_status.html111
-rw-r--r--www/diagnostics.html6
-rwxr-xr-xwww/make_cxx_dr_status172
-rw-r--r--www/menu.html.incl14
-rw-r--r--www/related.html41
3456 files changed, 236663 insertions, 48379 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000000..9b3aa8b7213b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: LLVM
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d05a4cdb552..8d02bf05f827 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,12 +19,14 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
endif()
endif()
- if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
- # Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
+ if (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
+ set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
+ elseif (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
+ # Looking for bin/Debug/llvm-config is a complete hack. How can we get
# around this?
- if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
- message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
- endif()
+ set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
+ else()
+ message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
endif()
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
@@ -32,6 +34,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
ABSOLUTE)
+ option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF)
+
include(AddLLVM)
include(TableGen)
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
@@ -46,12 +50,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
link_directories("${PATH_TO_LLVM_BUILD}/lib")
- if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
- set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
- else()
- # FIXME: This is an utter hack.
- set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
- endif()
+ exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
+ set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
# Define the default arguments to use with 'lit', and an option for the user
# to override.
@@ -90,6 +90,16 @@ if( CLANG_VENDOR )
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
endif()
+set(CLANG_REPOSITORY_STRING "" CACHE STRING
+ "Vendor-specific text for showing the repository the source is taken from.")
+
+if(CLANG_REPOSITORY_STRING)
+ add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
+endif()
+
+set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
+ "Vendor-specific uti.")
+
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
@@ -151,7 +161,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
endif ()
if (APPLE)
- set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
endif ()
configure_file(
@@ -189,6 +199,41 @@ function(clang_tablegen)
endif()
endfunction(clang_tablegen)
+# FIXME: Generalize and move to llvm.
+function(add_clang_symbol_exports target_name export_file)
+ # Makefile.rules contains special cases for different platforms.
+ # We restrict ourselves to Darwin for the time being.
+ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ add_custom_command(OUTPUT symbol.exports
+ COMMAND sed -e "s/^/_/" < ${export_file} > symbol.exports
+ DEPENDS ${export_file}
+ VERBATIM
+ COMMENT "Creating export file for ${target_name}")
+ add_custom_target(${target_name}_exports DEPENDS symbol.exports)
+ set_property(DIRECTORY APPEND
+ PROPERTY ADDITIONAL_MAKE_CLEAN_FILES symbol.exports)
+
+ get_property(srcs TARGET ${target_name} PROPERTY SOURCES)
+ foreach(src ${srcs})
+ get_filename_component(extension ${src} EXT)
+ if(extension STREQUAL ".cpp")
+ set(first_source_file ${src})
+ break()
+ endif()
+ endforeach()
+
+ # Force re-linking when the exports file changes. Actually, it
+ # forces recompilation of the source file. The LINK_DEPENDS target
+ # property only works for makefile-based generators.
+ set_property(SOURCE ${first_source_file} APPEND PROPERTY
+ OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/symbol.exports)
+
+ set_property(TARGET ${target_name} APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
+ add_dependencies(${target_name} ${target_name}_exports)
+ endif()
+endfunction(add_clang_symbol_exports)
+
macro(add_clang_library name)
llvm_process_sources(srcs ${ARGN})
if(MSVC_IDE OR XCODE)
@@ -228,11 +273,18 @@ macro(add_clang_library name)
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
link_system_libs( ${name} )
+
+ if (SHARED_LIBRARY AND EXPORTED_SYMBOL_FILE)
+ add_clang_symbol_exports( ${name} ${EXPORTED_SYMBOL_FILE} )
+ endif()
+
+ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libclang")
+ install(TARGETS ${name}
+ LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ RUNTIME DESTINATION bin)
+ endif()
- install(TARGETS ${name}
- LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
- ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
- RUNTIME DESTINATION bin)
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
endmacro(add_clang_library)
@@ -246,26 +298,58 @@ include_directories(BEFORE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
-install(DIRECTORY include/
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(DIRECTORY include/
+ DESTINATION include
+ FILES_MATCHING
+ PATTERN "*.def"
+ PATTERN "*.h"
+ PATTERN "config.h" EXCLUDE
+ PATTERN ".svn" EXCLUDE
+ )
+
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
+ DESTINATION include
+ FILES_MATCHING
+ PATTERN "CMakeFiles" EXCLUDE
+ PATTERN "*.inc"
+ )
+endif()
+
+install(DIRECTORY include/clang-c
DESTINATION include
FILES_MATCHING
- PATTERN "*.def"
PATTERN "*.h"
- PATTERN "config.h" EXCLUDE
PATTERN ".svn" EXCLUDE
)
-install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
- DESTINATION include
- FILES_MATCHING
- PATTERN "CMakeFiles" EXCLUDE
- PATTERN "*.inc"
- )
-
add_definitions( -D_GNU_SOURCE )
-# FIXME: They should be options.
-add_definitions(-DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_REWRITER -DCLANG_ENABLE_STATIC_ANALYZER)
+option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
+option(CLANG_ENABLE_REWRITER "Build rewriter." ON)
+option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
+
+if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_ARCMT)
+ message(FATAL_ERROR "Cannot disable rewriter while enabling ARCMT")
+endif()
+
+if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_STATIC_ANALYZER)
+ message(FATAL_ERROR "Cannot disable rewriter while enabling static analyzer")
+endif()
+
+if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
+ message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
+endif()
+
+if(CLANG_ENABLE_ARCMT)
+ add_definitions(-DCLANG_ENABLE_ARCMT)
+endif()
+if(CLANG_ENABLE_REWRITER)
+ add_definitions(-DCLANG_ENABLE_REWRITER)
+endif()
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
+endif()
# Clang version information
set(CLANG_EXECUTABLE_VERSION
@@ -290,13 +374,17 @@ option(CLANG_INCLUDE_TESTS
"Generate build targets for the Clang unit tests."
${LLVM_INCLUDE_TESTS})
-# TODO: docs.
-add_subdirectory(test)
-
if( CLANG_INCLUDE_TESTS )
+ add_subdirectory(test)
add_subdirectory(unittests)
endif()
+option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
+ ${LLVM_INCLUDE_DOCS})
+if( CLANG_INCLUDE_DOCS )
+ add_subdirectory(docs)
+endif()
+
# Workaround for MSVS10 to avoid the Dialog Hell
# FIXME: This could be removed with future version of CMake.
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
@@ -309,3 +397,5 @@ endif()
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
"Default URL where bug reports are to be submitted.")
+set(CLANG_ORDER_FILE "" CACHE FILEPATH
+ "Order file to use when compiling clang in order to improve startup time.")
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index 13c0a9bde665..af5083184711 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -32,7 +32,7 @@ E: rjmccall@apple.com
D: Clang LLVM IR generation
N: Chad Rosier
-E: mcrosier@apple.com
+E: mcrosier@codeaurora.org
D: MS-inline asm, and the compiler driver
N: Richard Smith
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 880a1502a4ba..c103c7078003 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -266,6 +266,29 @@ class SourceRange(Structure):
def __ne__(self, other):
return not self.__eq__(other)
+ def __contains__(self, other):
+ """Useful to detect the Token/Lexer bug"""
+ if not isinstance(other, SourceLocation):
+ return False
+ if other.file is None and self.start.file is None:
+ pass
+ elif ( self.start.file.name != other.file.name or
+ other.file.name != self.end.file.name):
+ # same file name
+ return False
+ # same file, in between lines
+ if self.start.line < other.line < self.end.line:
+ return True
+ elif self.start.line == other.line:
+ # same file first line
+ if self.start.column <= other.column:
+ return True
+ elif other.line == self.end.line:
+ # same file last line
+ if other.column <= self.end.column:
+ return True
+ return False
+
def __repr__(self):
return "<SourceRange start %r, end %r>" % (self.start, self.end)
@@ -508,7 +531,7 @@ class CursorKind(object):
@staticmethod
def from_id(id):
if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
- raise ValueError,'Unknown cursor kind'
+ raise ValueError,'Unknown cursor kind %d' % id
return CursorKind._kinds[id]
@staticmethod
@@ -721,10 +744,14 @@ CursorKind.MEMBER_REF = CursorKind(47)
# A reference to a labeled statement.
CursorKind.LABEL_REF = CursorKind(48)
-# A reference toa a set of overloaded functions or function templates
+# A reference to a set of overloaded functions or function templates
# that has not yet been resolved to a specific function or function template.
CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
+# A reference to a variable that occurs in some non-expression
+# context, e.g., a C++ lambda capture list.
+CursorKind.VARIABLE_REF = CursorKind(50)
+
###
# Invalid/Error Kinds
@@ -908,6 +935,26 @@ CursorKind.PACK_EXPANSION_EXPR = CursorKind(142)
# pack.
CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
+# Represents a C++ lambda expression that produces a local function
+# object.
+#
+# \code
+# void abssort(float *x, unsigned N) {
+# std::sort(x, x + N,
+# [](float a, float b) {
+# return std::abs(a) < std::abs(b);
+# });
+# }
+# \endcode
+CursorKind.LAMBDA_EXPR = CursorKind(144)
+
+# Objective-c Boolean Literal.
+CursorKind.OBJ_BOOL_LITERAL_EXPR = CursorKind(145)
+
+# Represents the "self" expression in a ObjC method.
+CursorKind.OBJ_SELF_EXPR = CursorKind(146)
+
+
# A statement whose specific kind is not exposed via this interface.
#
# Unexposed statements have the same operations as any other kind of statement;
@@ -999,6 +1046,9 @@ CursorKind.SEH_EXCEPT_STMT = CursorKind(227)
# Windows Structured Exception Handling's finally statement.
CursorKind.SEH_FINALLY_STMT = CursorKind(228)
+# A MS inline assembly statement extension.
+CursorKind.MS_ASM_STMT = CursorKind(229)
+
# The null statement.
CursorKind.NULL_STMT = CursorKind(230)
@@ -1028,6 +1078,7 @@ CursorKind.CXX_FINAL_ATTR = CursorKind(404)
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
CursorKind.ANNOTATE_ATTR = CursorKind(406)
CursorKind.ASM_LABEL_ATTR = CursorKind(407)
+CursorKind.PACKED_ATTR = CursorKind(408)
###
# Preprocessing
@@ -1036,6 +1087,12 @@ CursorKind.MACRO_DEFINITION = CursorKind(501)
CursorKind.MACRO_INSTANTIATION = CursorKind(502)
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
+###
+# Extra declaration
+
+# A module import declaration.
+CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
+
### Cursors ###
class Cursor(Structure):
@@ -1282,6 +1339,16 @@ class Cursor(Structure):
return self._referenced
+ @property
+ def brief_comment(self):
+ """Returns the brief comment text associated with that Cursor"""
+ return conf.lib.clang_Cursor_getBriefCommentText(self)
+
+ @property
+ def raw_comment(self):
+ """Returns the raw comment text associated with that Cursor"""
+ return conf.lib.clang_Cursor_getRawCommentText(self)
+
def get_arguments(self):
"""Return an iterator for accessing the arguments of this cursor."""
num_args = conf.lib.clang_Cursor_getNumArguments(self)
@@ -1450,6 +1517,54 @@ TypeKind.FUNCTIONNOPROTO = TypeKind(110)
TypeKind.FUNCTIONPROTO = TypeKind(111)
TypeKind.CONSTANTARRAY = TypeKind(112)
TypeKind.VECTOR = TypeKind(113)
+TypeKind.INCOMPLETEARRAY = TypeKind(114)
+TypeKind.VARIABLEARRAY = TypeKind(115)
+TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
+TypeKind.MEMBERPOINTER = TypeKind(117)
+
+class RefQualifierKind(object):
+ """Describes a specific ref-qualifier of a type."""
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def __init__(self, value):
+ if value >= len(RefQualifierKind._kinds):
+ num_kinds = value - len(RefQualifierKind._kinds) + 1
+ RefQualifierKind._kinds += [None] * num_kinds
+ if RefQualifierKind._kinds[value] is not None:
+ raise ValueError, 'RefQualifierKind already loaded'
+ self.value = value
+ RefQualifierKind._kinds[value] = self
+ RefQualifierKind._name_map = None
+
+ def from_param(self):
+ return self.value
+
+ @property
+ def name(self):
+ """Get the enumeration name of this kind."""
+ if self._name_map is None:
+ self._name_map = {}
+ for key, value in RefQualifierKind.__dict__.items():
+ if isinstance(value, RefQualifierKind):
+ self._name_map[value] = key
+ return self._name_map[self]
+
+ @staticmethod
+ def from_id(id):
+ if (id >= len(RefQualifierKind._kinds) or
+ RefQualifierKind._kinds[id] is None):
+ raise ValueError, 'Unknown type kind %d' % id
+ return RefQualifierKind._kinds[id]
+
+ def __repr__(self):
+ return 'RefQualifierKind.%s' % (self.name,)
+
+RefQualifierKind.NONE = RefQualifierKind(0)
+RefQualifierKind.LVALUE = RefQualifierKind(1)
+RefQualifierKind.RVALUE = RefQualifierKind(2)
class Type(Structure):
"""
@@ -1625,6 +1740,12 @@ class Type(Structure):
"""
return conf.lib.clang_getArraySize(self)
+ def get_class_type(self):
+ """
+ Retrieve the class type of the member pointer type.
+ """
+ return conf.lib.clang_Type_getClassType(self)
+
def get_align(self):
"""
Retrieve the alignment of the record.
@@ -1643,6 +1764,18 @@ class Type(Structure):
"""
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
+ def get_ref_qualifier(self):
+ """
+ Retrieve the ref-qualifier of the type.
+ """
+ return RefQualifierKind.from_id(
+ conf.lib.clang_Type_getCXXRefQualifier(self))
+
+ @property
+ def spelling(self):
+ """Retrieve the spelling of this Type."""
+ return conf.lib.clang_getTypeSpelling(self)
+
def __eq__(self, other):
if type(other) != type(self):
return False
@@ -1918,7 +2051,7 @@ class Index(ClangObject):
def read(self, path):
"""Load a TranslationUnit from the given AST file."""
- return TranslationUnit.from_ast(path, self)
+ return TranslationUnit.from_ast_file(path, self)
def parse(self, path, args=None, unsaved_files=None, options = 0):
"""Load the translation unit from the given source code file by running
@@ -2590,6 +2723,10 @@ functionList = [
[Index, c_char_p],
c_object_p),
+ ("clang_CXXMethod_isPureVirtual",
+ [Cursor],
+ bool),
+
("clang_CXXMethod_isStatic",
[Cursor],
bool),
@@ -2973,6 +3110,11 @@ functionList = [
_CXString,
_CXString.from_result),
+ ("clang_getTypeSpelling",
+ [Type],
+ _CXString,
+ _CXString.from_result),
+
("clang_hashCursor",
[Cursor],
c_uint),
@@ -3077,17 +3219,36 @@ functionList = [
[Cursor],
bool),
+ ("clang_Cursor_getBriefCommentText",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_Cursor_getRawCommentText",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
("clang_Type_getAlignOf",
[Type],
c_longlong),
+ ("clang_Type_getClassType",
+ [Type],
+ Type,
+ Type.from_result),
+
("clang_Type_getOffsetOf",
[Type, c_char_p],
c_longlong),
("clang_Type_getSizeOf",
[Type],
- c_ulonglong),
+ c_longlong),
+
+ ("clang_Type_getCXXRefQualifier",
+ [Type],
+ c_uint),
]
class LibclangError(Exception):
diff --git a/bindings/python/tests/cindex/test_comment.py b/bindings/python/tests/cindex/test_comment.py
new file mode 100644
index 000000000000..d8f3129ac51e
--- /dev/null
+++ b/bindings/python/tests/cindex/test_comment.py
@@ -0,0 +1,40 @@
+from clang.cindex import TranslationUnit
+from tests.cindex.util import get_cursor
+
+def test_comment():
+ files = [('fake.c', """
+/// Aaa.
+int test1;
+
+/// Bbb.
+/// x
+void test2(void);
+
+void f() {
+
+}
+""")]
+ # make a comment-aware TU
+ tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
+ options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
+ test1 = get_cursor(tu, 'test1')
+ assert test1 is not None, "Could not find test1."
+ assert test1.type.is_pod()
+ raw = test1.raw_comment
+ brief = test1.brief_comment
+ assert raw == """/// Aaa."""
+ assert brief == """Aaa."""
+
+ test2 = get_cursor(tu, 'test2')
+ raw = test2.raw_comment
+ brief = test2.brief_comment
+ assert raw == """/// Bbb.\n/// x"""
+ assert brief == """Bbb. x"""
+
+ f = get_cursor(tu, 'f')
+ raw = f.raw_comment
+ brief = f.brief_comment
+ assert raw is None
+ assert brief is None
+
+
diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py
index f8466e5e0d1d..8cabc512d4c5 100644
--- a/bindings/python/tests/cindex/test_cursor_kind.py
+++ b/bindings/python/tests/cindex/test_cursor_kind.py
@@ -4,8 +4,15 @@ def test_name():
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
def test_get_all_kinds():
- assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
- assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
+ kinds = CursorKind.get_all_kinds()
+ assert CursorKind.UNEXPOSED_DECL in kinds
+ assert CursorKind.TRANSLATION_UNIT in kinds
+ assert CursorKind.VARIABLE_REF in kinds
+ assert CursorKind.LAMBDA_EXPR in kinds
+ assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
+ assert CursorKind.OBJ_SELF_EXPR in kinds
+ assert CursorKind.MS_ASM_STMT in kinds
+ assert CursorKind.MODULE_IMPORT_DECL in kinds
def test_kind_groups():
"""Check that every kind classifies to exactly one group."""
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index 9bbed5aa940e..a02c06fe5a13 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -132,6 +132,22 @@ def test_equal():
assert a.type != None
assert a.type != 'foo'
+def test_type_spelling():
+ """Ensure Type.spelling works."""
+ tu = get_tu('int c[5]; int i[]; int x; int v[x];')
+ c = get_cursor(tu, 'c')
+ i = get_cursor(tu, 'i')
+ x = get_cursor(tu, 'x')
+ v = get_cursor(tu, 'v')
+ assert c is not None
+ assert i is not None
+ assert x is not None
+ assert v is not None
+ assert c.type.spelling == "int [5]"
+ assert i.type.spelling == "int []"
+ assert x.type.spelling == "int"
+ assert v.type.spelling == "int [x]"
+
def test_typekind_spelling():
"""Ensure TypeKind.spelling works."""
tu = get_tu('int a;')
@@ -237,12 +253,20 @@ void bar(int a, int b);
def test_element_type():
"""Ensure Type.element_type works."""
- tu = get_tu('int i[5];')
+ tu = get_tu('int c[5]; int i[]; int x; int v[x];')
+ c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
+ v = get_cursor(tu, 'v')
+ assert c is not None
assert i is not None
+ assert v is not None
- assert i.type.kind == TypeKind.CONSTANTARRAY
+ assert c.type.kind == TypeKind.CONSTANTARRAY
+ assert c.type.element_type.kind == TypeKind.INT
+ assert i.type.kind == TypeKind.INCOMPLETEARRAY
assert i.type.element_type.kind == TypeKind.INT
+ assert v.type.kind == TypeKind.VARIABLEARRAY
+ assert v.type.element_type.kind == TypeKind.INT
@raises(Exception)
def test_invalid_element_type():
@@ -361,3 +385,13 @@ struct Test {
assert teststruct.type.get_offset("bar") == bar
+def test_decay():
+ """Ensure decayed types are handled as the original type"""
+
+ tu = get_tu("void foo(int a[]);")
+ foo = get_cursor(tu, 'foo')
+ a = foo.type.argument_types()[0]
+
+ assert a.kind == TypeKind.INCOMPLETEARRAY
+ assert a.element_type.kind == TypeKind.INT
+ assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng
index 22371dfed1e4..a8913a360b79 100644
--- a/bindings/xml/comment-xml-schema.rng
+++ b/bindings/xml/comment-xml-schema.rng
@@ -75,7 +75,6 @@
<optional>
<ref name="USR" />
</optional>
- <!-- TODO: Add exception specification. -->
<optional>
<ref name="Headerfile" />
</optional>
@@ -91,6 +90,9 @@
<optional>
<ref name="Parameters" />
</optional>
+ <optional>
+ <ref name="Exceptions" />
+ </optional>
<zeroOrMore>
<ref name="Availability" />
</zeroOrMore>
@@ -410,9 +412,14 @@
</data>
</element>
<optional>
- <element name="Index">
- <data type="nonNegativeInteger" />
- </element>
+ <choice>
+ <element name="Index">
+ <data type="nonNegativeInteger" />
+ </element>
+ <element name="IsVarArg">
+ <empty />
+ </element>
+ </choice>
</optional>
<element name="Direction">
<attribute name="isExplicit">
@@ -435,6 +442,14 @@
</element>
</define>
+ <define name="Exceptions">
+ <element name="Exceptions">
+ <oneOrMore>
+ <ref name="TextBlockContent" />
+ </oneOrMore>
+ </element>
+ </define>
+
<define name="Availability">
<element name="Availability">
<attribute name="distribution">
diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst
index 89e864450009..5bc6d0b88b43 100644
--- a/docs/AddressSanitizer.rst
+++ b/docs/AddressSanitizer.rst
@@ -16,6 +16,7 @@ following types of bugs:
* Use-after-free
* Use-after-return (to some extent)
* Double-free, invalid free
+* Memory leaks (experimental)
Typical slowdown introduced by AddressSanitizer is **2x**.
@@ -114,8 +115,7 @@ function attribute
(or a deprecated synonym `no_address_safety_analysis`)
to disable instrumentation of a particular function. This attribute may not be
supported by other compilers, so we suggest to use it together with
-``__has_feature(address_sanitizer)``. Note: currently, this attribute will be
-lost if the function is inlined.
+``__has_feature(address_sanitizer)``.
Initialization order checking
-----------------------------
@@ -126,6 +126,42 @@ globals defined in another translation unit. To enable this check at runtime,
you should set environment variable
``ASAN_OPTIONS=check_initialization_order=1``.
+Blacklist
+---------
+
+AddressSanitizer supports ``src`` and ``fun`` entity types in
+:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
+in the specified source files or functions. Additionally, AddressSanitizer
+introduces ``global`` and ``type`` entity types that can be used to
+suppress error reports for out-of-bound access to globals with certain
+names and types (you may only specify class or struct types).
+
+You may use an ``init`` category to suppress reports about initialization-order
+problems happening in certain source files or with certain global variables.
+
+.. code-block:: bash
+
+ # Suppress error reports for code in a file or in a function:
+ src:bad_file.cpp
+ # Ignore all functions with names containing MyFooBar:
+ fun:*MyFooBar*
+ # Disable out-of-bound checks for global:
+ global:bad_array
+ # Disable out-of-bound checks for global instances of a given class ...
+ type:class.Namespace::BadClassName
+ # ... or a given struct. Use wildcard to deal with anonymous namespace.
+ type:struct.Namespace2::*::BadStructName
+ # Disable initialization-order checks for globals:
+ global:bad_init_global=init
+ type:*BadInitClassSubstring*=init
+ src:bad/init/files/*=init
+
+Memory leak detection
+---------------------
+
+For the experimental memory leak detector in AddressSanitizer, see
+:doc:`LeakSanitizer`.
+
Supported Platforms
===================
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644
index 000000000000..8528c7af5840
--- /dev/null
+++ b/docs/CMakeLists.txt
@@ -0,0 +1,51 @@
+
+if (DOXYGEN_FOUND)
+if (LLVM_ENABLE_DOXYGEN)
+ set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
+ set(abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
+
+ if (HAVE_DOT)
+ set(DOT ${LLVM_PATH_DOT})
+ endif()
+
+ if (LLVM_DOXYGEN_EXTERNAL_SEARCH)
+ set(enable_searchengine "YES")
+ set(searchengine_url "${LLVM_DOXYGEN_SEARCHENGINE_URL}")
+ set(enable_server_based_search "YES")
+ set(enable_external_search "YES")
+ set(extra_search_mappings "${LLVM_DOXYGEN_SEARCH_MAPPINGS}")
+ else()
+ set(enable_searchengine "NO")
+ set(searchengine_url "")
+ set(enable_server_based_search "NO")
+ set(enable_external_search "NO")
+ set(extra_search_mappings "")
+ endif()
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
+
+ set(abs_top_srcdir)
+ set(abs_top_builddir)
+ set(DOT)
+ set(enable_searchengine)
+ set(searchengine_url)
+ set(enable_server_based_search)
+ set(enable_external_search)
+ set(extra_search_mappings)
+
+ add_custom_target(doxygen-clang
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating clang doxygen documentation." VERBATIM)
+
+ if (LLVM_BUILD_DOCS)
+ add_dependencies(doxygen doxygen-clang)
+ endif()
+
+ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/html
+ DESTINATION docs/html)
+ endif()
+endif()
+endif()
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index 964fc84d7bca..bc6b8a2c41fa 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -15,26 +15,73 @@ to format C/C++/Obj-C code.
.. code-block:: console
- $ clang-format --help
+ $ clang-format -help
OVERVIEW: A tool to format C/C++/Obj-C code.
If no arguments are specified, it formats the code from standard input
and writes the result to the standard output.
- If <file> is given, it reformats the file. If -i is specified together
- with <file>, the file is edited in-place. Otherwise, the result is
- written to the standard output.
+ If <file>s are given, it reformats the files. If -i is specified
+ together with <file>s, the files are edited in-place. Otherwise, the
+ result is written to the standard output.
- USAGE: clang-format [options] [<file>]
+ USAGE: clang-format [options] [<file> ...]
OPTIONS:
- -fatal-assembler-warnings - Consider warnings as error
- -help - Display available options (-help-hidden for more)
- -i - Inplace edit <file>, if specified.
- -length=<int> - Format a range of this length, -1 for end of file.
- -offset=<int> - Format a range starting at this file offset.
- -stats - Enable statistics output from program
- -style=<string> - Coding style, currently supports: LLVM, Google, Chromium.
- -version - Display the version of this program
+
+ Clang-format options:
+
+ -cursor=<uint> - The position of the cursor when invoking
+ clang-format from an editor integration
+ -dump-config - Dump configuration options to stdout and exit.
+ Can be used with -style option.
+ -i - Inplace edit <file>s, if specified.
+ -length=<uint> - Format a range of this length (in bytes).
+ Multiple ranges can be formatted by specifying
+ several -offset and -length pairs.
+ When only a single -offset is specified without
+ -length, clang-format will format up to the end
+ of the file.
+ Can only be used with one input file.
+ -lines=<string> - <start line>:<end line> - format a range of
+ lines (both 1-based).
+ Multiple ranges can be formatted by specifying
+ several -lines arguments.
+ Can't be used with -offset and -length.
+ Can only be used with one input file.
+ -offset=<uint> - Format a range starting at this byte offset.
+ Multiple ranges can be formatted by specifying
+ several -offset and -length pairs.
+ Can only be used with one input file.
+ -output-replacements-xml - Output replacements as XML.
+ -style=<string> - Coding style, currently supports:
+ LLVM, Google, Chromium, Mozilla, WebKit.
+ Use -style=file to load style configuration from
+ .clang-format file located in one of the parent
+ directories of the source file (or current
+ directory for stdin).
+ Use -style="{key: value, ...}" to set specific
+ parameters, e.g.:
+ -style="{BasedOnStyle: llvm, IndentWidth: 8}"
+
+ General options:
+
+ -help - Display available options (-help-hidden for more)
+ -help-list - Display list of available options (-help-list-hidden for more)
+ -version - Display the version of this program
+
+
+When the desired code formatting style is different from the available options,
+the style can be customized using the ``-style="{key: value, ...}"`` option or
+by putting your style configuration in the ``.clang-format`` or ``_clang-format``
+file in your project's directory and using ``clang-format -style=file``.
+
+An easy way to create the ``.clang-format`` file is:
+
+.. code-block:: console
+
+ clang-format -style=llvm -dump-config > .clang-format
+
+Available style options are described in :doc:`ClangFormatStyleOptions`.
Vim Integration
@@ -96,6 +143,13 @@ menu item by renaming the script, and can assign the menu item a keyboard
shortcut in the BBEdit preferences, under Menus & Shortcuts.
+Visual Studio Integration
+=========================
+
+Download the latest Visual Studio plugin from the `alpha build site
+<http://llvm.org/builds/>`_. The default key-binding is Ctrl-R,Ctrl-F.
+
+
Script for patch reformatting
=============================
@@ -106,18 +160,19 @@ a unified diff and reformats all contained lines with :program:`clang-format`.
usage: clang-format-diff.py [-h] [-p P] [-style STYLE]
- Reformat changed lines in diff
+ Reformat changed lines in diff.
optional arguments:
-h, --help show this help message and exit
-p P strip the smallest prefix containing P slashes
- -style STYLE formatting style to apply (LLVM, Google, Chromium)
+ -style STYLE formatting style to apply (LLVM, Google, Chromium, Mozilla,
+ WebKit)
So to reformat all the lines in the latest :program:`git` commit, just do:
.. code-block:: console
- git diff -U0 HEAD^ | clang-format-diff.py
+ git diff -U0 HEAD^ | clang-format-diff.py -p1
The :option:`-U0` will create a diff without context lines (the script would format
those as well).
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
new file mode 100644
index 000000000000..d73801c7e73d
--- /dev/null
+++ b/docs/ClangFormatStyleOptions.rst
@@ -0,0 +1,391 @@
+==========================
+Clang-Format Style Options
+==========================
+
+:doc:`ClangFormatStyleOptions` describes configurable formatting style options
+supported by :doc:`LibFormat` and :doc:`ClangFormat`.
+
+When using :program:`clang-format` command line utility or
+``clang::format::reformat(...)`` functions from code, one can either use one of
+the predefined styles (LLVM, Google, Chromium, Mozilla, WebKit) or create a
+custom style by configuring specific style options.
+
+
+Configuring Style with clang-format
+===================================
+
+:program:`clang-format` supports two ways to provide custom style options:
+directly specify style configuration in the ``-style=`` command line option or
+use ``-style=file`` and put style configuration in the ``.clang-format`` or
+``_clang-format`` file in the project directory.
+
+When using ``-style=file``, :program:`clang-format` for each input file will
+try to find the ``.clang-format`` file located in the closest parent directory
+of the input file. When the standard input is used, the search is started from
+the current directory.
+
+The ``.clang-format`` file uses YAML format:
+
+.. code-block:: yaml
+
+ key1: value1
+ key2: value2
+ # A comment.
+ ...
+
+An easy way to get a valid ``.clang-format`` file containing all configuration
+options of a certain predefined style is:
+
+.. code-block:: console
+
+ clang-format -style=llvm -dump-config > .clang-format
+
+When specifying configuration in the ``-style=`` option, the same configuration
+is applied for all input files. The format of the configuration is:
+
+.. code-block:: console
+
+ -style='{key1: value1, key2: value2, ...}'
+
+
+Configuring Style in Code
+=========================
+
+When using ``clang::format::reformat(...)`` functions, the format is specified
+by supplying the `clang::format::FormatStyle
+<http://clang.llvm.org/doxygen/structclang_1_1format_1_1FormatStyle.html>`_
+structure.
+
+
+Configurable Format Style Options
+=================================
+
+This section lists the supported style options. Value type is specified for
+each option. For enumeration types possible values are specified both as a C++
+enumeration member (with a prefix, e.g. ``LS_Auto``), and as a value usable in
+the configuration (without a prefix: ``Auto``).
+
+
+**BasedOnStyle** (``string``)
+ The style used for all options not specifically set in the configuration.
+
+ This option is supported only in the :program:`clang-format` configuration
+ (both within ``-style='{...}'`` and the ``.clang-format`` file).
+
+ Possible values:
+
+ * ``LLVM``
+ A style complying with the `LLVM coding standards
+ <http://llvm.org/docs/CodingStandards.html>`_
+ * ``Google``
+ A style complying with `Google's C++ style guide
+ <http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml>`_
+ * ``Chromium``
+ A style complying with `Chromium's style guide
+ <http://www.chromium.org/developers/coding-style>`_
+ * ``Mozilla``
+ A style complying with `Mozilla's style guide
+ <https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style>`_
+ * ``WebKit``
+ A style complying with `WebKit's style guide
+ <http://www.webkit.org/coding/coding-style.html>`_
+
+.. START_FORMAT_STYLE_OPTIONS
+
+**AccessModifierOffset** (``int``)
+ The extra indent or outdent of access modifiers, e.g. ``public:``.
+
+**AlignEscapedNewlinesLeft** (``bool``)
+ If ``true``, aligns escaped newlines as far left as possible.
+ Otherwise puts them into the right-most column.
+
+**AlignTrailingComments** (``bool``)
+ If ``true``, aligns trailing comments.
+
+**AllowAllParametersOfDeclarationOnNextLine** (``bool``)
+ Allow putting all parameters of a function declaration onto
+ the next line even if ``BinPackParameters`` is ``false``.
+
+**AllowShortIfStatementsOnASingleLine** (``bool``)
+ If ``true``, ``if (a) return;`` can be put on a single
+ line.
+
+**AllowShortLoopsOnASingleLine** (``bool``)
+ If ``true``, ``while (true) continue;`` can be put on a
+ single line.
+
+**AlwaysBreakBeforeMultilineStrings** (``bool``)
+ If ``true``, always break before multiline string literals.
+
+**AlwaysBreakTemplateDeclarations** (``bool``)
+ If ``true``, always break after the ``template<...>`` of a
+ template declaration.
+
+**BinPackParameters** (``bool``)
+ If ``false``, a function call's or function definition's parameters
+ will either all be on the same line or will have one line each.
+
+**BreakBeforeBinaryOperators** (``bool``)
+ If ``true``, binary operators will be placed after line breaks.
+
+**BreakBeforeBraces** (``BraceBreakingStyle``)
+ The brace breaking style to use.
+
+ Possible values:
+
+ * ``BS_Attach`` (in configuration: ``Attach``)
+ Always attach braces to surrounding context.
+ * ``BS_Linux`` (in configuration: ``Linux``)
+ Like ``Attach``, but break before braces on function, namespace and
+ class definitions.
+ * ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
+ Like ``Attach``, but break before function definitions.
+ * ``BS_Allman`` (in configuration: ``Allman``)
+ Always break before braces.
+
+
+**BreakConstructorInitializersBeforeComma** (``bool``)
+ Always break constructor initializers before commas and align
+ the commas with the colon.
+
+**ColumnLimit** (``unsigned``)
+ The column limit.
+
+ A column limit of ``0`` means that there is no column limit. In this case,
+ clang-format will respect the input's line breaking decisions within
+ statements.
+
+**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
+ If the constructor initializers don't fit on a line, put each
+ initializer on its own line.
+
+**ConstructorInitializerIndentWidth** (``unsigned``)
+ The number of characters to use for indentation of constructor
+ initializer lists.
+
+**Cpp11BracedListStyle** (``bool``)
+ If ``true``, format braced lists as best suited for C++11 braced
+ lists.
+
+ Important differences:
+ - No spaces inside the braced list.
+ - No line break before the closing brace.
+ - Indentation with the continuation indent, not with the block indent.
+
+ Fundamentally, C++11 braced lists are formatted exactly like function
+ calls would be formatted in their place. If the braced list follows a name
+ (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.
+
+**DerivePointerBinding** (``bool``)
+ If ``true``, analyze the formatted file for the most common binding.
+
+**ExperimentalAutoDetectBinPacking** (``bool``)
+ If ``true``, clang-format detects whether function calls and
+ definitions are formatted with one parameter per line.
+
+ Each call can be bin-packed, one-per-line or inconclusive. If it is
+ inconclusive, e.g. completely on one line, but a decision needs to be
+ made, clang-format analyzes whether there are other bin-packed cases in
+ the input file and act accordingly.
+
+ NOTE: This is an experimental flag, that might go away or be renamed. Do
+ not use this in config files, etc. Use at your own risk.
+
+**IndentCaseLabels** (``bool``)
+ Indent case labels one level from the switch statement.
+
+ When ``false``, use the same indentation level as for the switch statement.
+ Switch statement body is always indented one level more than case labels.
+
+**IndentFunctionDeclarationAfterType** (``bool``)
+ If ``true``, indent when breaking function declarations which
+ are not also definitions after the type.
+
+**IndentWidth** (``unsigned``)
+ The number of columns to use for indentation.
+
+**MaxEmptyLinesToKeep** (``unsigned``)
+ The maximum number of consecutive empty lines to keep.
+
+**NamespaceIndentation** (``NamespaceIndentationKind``)
+ The indentation used for namespaces.
+
+ Possible values:
+
+ * ``NI_None`` (in configuration: ``None``)
+ Don't indent in namespaces.
+ * ``NI_Inner`` (in configuration: ``Inner``)
+ Indent only in inner namespaces (nested in other namespaces).
+ * ``NI_All`` (in configuration: ``All``)
+ Indent in all namespaces.
+
+
+**ObjCSpaceBeforeProtocolList** (``bool``)
+ Add a space in front of an Objective-C protocol list, i.e. use
+ ``Foo <Protocol>`` instead of ``Foo<Protocol>``.
+
+**PenaltyBreakComment** (``unsigned``)
+ The penalty for each line break introduced inside a comment.
+
+**PenaltyBreakFirstLessLess** (``unsigned``)
+ The penalty for breaking before the first ``<<``.
+
+**PenaltyBreakString** (``unsigned``)
+ The penalty for each line break introduced inside a string literal.
+
+**PenaltyExcessCharacter** (``unsigned``)
+ The penalty for each character outside of the column limit.
+
+**PenaltyReturnTypeOnItsOwnLine** (``unsigned``)
+ Penalty for putting the return type of a function onto its own
+ line.
+
+**PointerBindsToType** (``bool``)
+ Set whether & and * bind to the type as opposed to the variable.
+
+**SpaceAfterControlStatementKeyword** (``bool``)
+ If ``true``, spaces will be inserted between 'for'/'if'/'while'/...
+ and '('.
+
+**SpaceBeforeAssignmentOperators** (``bool``)
+ If ``false``, spaces will be removed before assignment operators.
+
+**SpaceInEmptyParentheses** (``bool``)
+ If ``false``, spaces may be inserted into '()'.
+
+**SpacesBeforeTrailingComments** (``unsigned``)
+ The number of spaces to before trailing line comments.
+
+**SpacesInCStyleCastParentheses** (``bool``)
+ If ``false``, spaces may be inserted into C style casts.
+
+**SpacesInParentheses** (``bool``)
+ If ``true``, spaces will be inserted after every '(' and before
+ every ')'.
+
+**Standard** (``LanguageStandard``)
+ Format compatible with this standard, e.g. use
+ ``A<A<int> >`` instead of ``A<A<int>>`` for LS_Cpp03.
+
+ Possible values:
+
+ * ``LS_Cpp03`` (in configuration: ``Cpp03``)
+ 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> >``).
+ * ``LS_Auto`` (in configuration: ``Auto``)
+ Automatic detection based on the input.
+
+
+**TabWidth** (``unsigned``)
+ The number of columns used for tab stops.
+
+**UseTab** (``UseTabStyle``)
+ The way to use tab characters in the resulting file.
+
+ Possible values:
+
+ * ``UT_Never`` (in configuration: ``Never``)
+ Never use tab.
+ * ``UT_ForIndentation`` (in configuration: ``ForIndentation``)
+ Use tabs only for indentation.
+ * ``UT_Always`` (in configuration: ``Always``)
+ Use tabs whenever we need to fill whitespace that spans at least from
+ one tab stop to the next one.
+
+
+.. END_FORMAT_STYLE_OPTIONS
+
+Examples
+========
+
+A style similar to the `Linux Kernel style
+<https://www.kernel.org/doc/Documentation/CodingStyle>`_:
+
+.. code-block:: yaml
+
+ BasedOnStyle: LLVM
+ IndentWidth: 8
+ UseTab: Always
+ BreakBeforeBraces: Linux
+ AllowShortIfStatementsOnASingleLine: false
+ IndentCaseLabels: false
+
+The result is (imagine that tabs are used for indentation here):
+
+.. code-block:: c++
+
+ void test()
+ {
+ switch (x) {
+ case 0:
+ case 1:
+ do_something();
+ break;
+ case 2:
+ do_something_else();
+ break;
+ default:
+ break;
+ }
+ if (condition)
+ do_something_completely_different();
+
+ if (x == y) {
+ q();
+ } else if (x > y) {
+ w();
+ } else {
+ r();
+ }
+ }
+
+A style similar to the default Visual Studio formatting style:
+
+.. code-block:: yaml
+
+ UseTab: Never
+ IndentWidth: 4
+ BreakBeforeBraces: Allman
+ AllowShortIfStatementsOnASingleLine: false
+ IndentCaseLabels: false
+ ColumnLimit: 0
+
+The result is:
+
+.. code-block:: c++
+
+ void test()
+ {
+ switch (suffix)
+ {
+ case 0:
+ case 1:
+ do_something();
+ break;
+ case 2:
+ do_something_else();
+ break;
+ default:
+ break;
+ }
+ if (condition)
+ do_somthing_completely_different();
+
+ if (x == y)
+ {
+ q();
+ }
+ else if (x > y)
+ {
+ w();
+ }
+ else
+ {
+ r();
+ }
+ }
+
diff --git a/docs/ClangTools.rst b/docs/ClangTools.rst
index 9312e6baf09a..f8a7c366dbaf 100644
--- a/docs/ClangTools.rst
+++ b/docs/ClangTools.rst
@@ -88,8 +88,8 @@ Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
<ClangFormat>` with the goal of automatically reformatting C++ sources files
according to configurable style guides. To do so, clang-format uses Clang's
``Lexer`` to transform an input file into a token stream and then changes all
-the whitespace around those tokens. The goal is for clang-format to both serve
-both as a user tool (ideally with powerful IDE integrations) and part of other
+the whitespace around those tokens. The goal is for clang-format to serve both
+as a user tool (ideally with powerful IDE integrations) and as part of other
refactoring tools, e.g. to do a reformatting of all the lines changed during a
renaming.
@@ -125,7 +125,7 @@ Ideas for new Tools
``foo`` is a standard container. We could also detect similar patterns for
arrays.
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation
-can be incorporated into the ``auto`` transformation. Will convert
+ can be incorporated into the ``auto`` transformation. Will convert
.. code-block:: c++
diff --git a/docs/CrossCompilation.rst b/docs/CrossCompilation.rst
new file mode 100644
index 000000000000..89f8777ac074
--- /dev/null
+++ b/docs/CrossCompilation.rst
@@ -0,0 +1,204 @@
+===================================================================
+Cross-compilation using Clang
+===================================================================
+
+Introduction
+============
+
+This document will guide you in choosing the right Clang options
+for cross-compiling your code to a different architecture. It assumes you
+already know how to compile the code in question for the host architecture,
+and that you know how to choose additional include and library paths.
+
+However, this document is *not* a "how to" and won't help you setting your
+build system or Makefiles, nor choosing the right CMake options, etc.
+Also, it does not cover all the possible options, nor does it contain
+specific examples for specific architectures. For a concrete example, the
+`instructions for cross-compiling LLVM itself
+<http://llvm.org/docs/HowToCrossCompileLLVM.html>`_ may be of interest.
+
+After reading this document, you should be familiar with the main issues
+related to cross-compilation, and what main compiler options Clang provides
+for performing cross-compilation.
+
+Cross compilation issues
+========================
+
+In GCC world, every host/target combination has its own set of binaries,
+headers, libraries, etc. So, it's usually simple to download a package
+with all files in, unzip to a directory and point the build system to
+that compiler, that will know about its location and find all it needs to
+when compiling your code.
+
+On the other hand, Clang/LLVM is natively a cross-compiler, meaning that
+one set of programs can compile to all targets by setting the ``-target``
+option. That makes it a lot easier for programers wishing to compile to
+different platforms and architectures, and for compiler developers that
+only have to maintain one build system, and for OS distributions, that
+need only one set of main packages.
+
+But, as is true to any cross-compiler, and given the complexity of
+different architectures, OS's and options, it's not always easy finding
+the headers, libraries or binutils to generate target specific code.
+So you'll need special options to help Clang understand what target
+you're compiling to, where your tools are, etc.
+
+Another problem is that compilers come with standard libraries only (like
+``compiler-rt``, ``libcxx``, ``libgcc``, ``libm``, etc), so you'll have to
+find and make available to the build system, every other library required
+to build your software, that is specific to your target. It's not enough to
+have your host's libraries installed.
+
+Finally, not all toolchains are the same, and consequently, not every Clang
+option will work magically. Some options, like ``--sysroot`` (which
+effectively changes the logical root for headers and libraries), assume
+all your binaries and libraries are in the same directory, which may not
+true when your cross-compiler was installed by the distribution's package
+management. So, for each specific case, you may use more than one
+option, and in most cases, you'll end up setting include paths (``-I``) and
+library paths (``-L``) manually.
+
+To sum up, different toolchains can:
+ * be host/target specific or more flexible
+ * be in a single directory, or spread out across your system
+ * have different sets of libraries and headers by default
+ * need special options, which your build system won't be able to figure
+ out by itself
+
+General Cross-Compilation Options in Clang
+==========================================
+
+Target Triple
+-------------
+
+The basic option is to define the target architecture. For that, use
+``-target <triple>``. If you don't specify the target, CPU names won't
+match (since Clang assumes the host triple), and the compilation will
+go ahead, creating code for the host platform, which will break later
+on when assembling or linking.
+
+The triple has the general format ``<arch><sub>-<vendor>-<sys>-<abi>``, where:
+ * ``arch`` = ``x86``, ``arm``, ``thumb``, ``mips``, etc.
+ * ``sub`` = for ex. on ARM: ``v5``, ``v6m``, ``v7a``, ``v7m``, etc.
+ * ``vendor`` = ``pc``, ``apple``, ``nvidia``, ``ibm``, etc.
+ * ``sys`` = ``none``, ``linux``, ``win32``, ``darwin``, ``cuda``, etc.
+ * ``abi`` = ``eabi``, ``gnu``, ``android``, ``macho``, ``elf``, etc.
+
+The sub-architecture options are available for their own architectures,
+of course, so "x86v7a" doesn't make sense. The vendor needs to be
+specified only if there's a relevant change, for instance between PC
+and Apple. Most of the time it can be omitted (and Unknown)
+will be assumed, which sets the defaults for the specified architecture.
+The system name is generally the OS (linux, darwin), but could be special
+like the bare-metal "none".
+
+When a parameter is not important, they can be omitted, or you can
+choose ``unknown`` and the defaults will be used. If you choose a parameter
+that Clang doesn't know, like ``blerg``, it'll ignore and assume
+``unknown``, which is not always desired, so be careful.
+
+Finally, the ABI option is something that will pick default CPU/FPU,
+define the specific behaviour of your code (PCS, extensions),
+and also choose the correct library calls, etc.
+
+CPU, FPU, ABI
+-------------
+
+Once your target is specified, it's time to pick the hardware you'll
+be compiling to. For every architecture, a default set of CPU/FPU/ABI
+will be chosen, so you'll almost always have to change it via flags.
+
+Typical flags include:
+ * ``-mcpu=<cpu-name>``, like x86-64, swift, cortex-a15
+ * ``-fpu=<fpu-name>``, like SSE3, NEON, controlling the FP unit available
+ * ``-mfloat-abi=<fabi>``, like soft, hard, controlling which registers
+ to use for floating-point
+
+The default is normally the common denominator, so that Clang doesn't
+generate code that breaks. But that also means you won't get the best
+code for your specific hardware, which may mean orders of magnitude
+slower than you expect.
+
+For example, if your target is ``arm-none-eabi``, the default CPU will
+be ``arm7tdmi`` using soft float, which is extremely slow on modern cores,
+whereas if your triple is ``armv7a-none-eabi``, it'll be Cortex-A8 with
+NEON, but still using soft-float, which is much better, but still not
+great.
+
+Toolchain Options
+-----------------
+
+There are three main options to control access to your cross-compiler:
+``--sysroot``, ``-I``, and ``-L``. The two last ones are well known,
+but they're particularly important for additional libraries
+and headers that are specific to your target.
+
+There are two main ways to have a cross-compiler:
+
+#. When you have extracted your cross-compiler from a zip file into
+ a directory, you have to use ``--sysroot=<path>``. The path is the
+ root directory where you have unpacked your file, and Clang will
+ look for the directories ``bin``, ``lib``, ``include`` in there.
+
+ In this case, your setup should be pretty much done (if no
+ additional headers or libraries are needed), as Clang will find
+ all binaries it needs (assembler, linker, etc) in there.
+
+#. When you have installed via a package manager (modern Linux
+ distributions have cross-compiler packages available), make
+ sure the target triple you set is *also* the prefix of your
+ cross-compiler toolchain.
+
+ In this case, Clang will find the other binaries (assembler,
+ linker), but not always where the target headers and libraries
+ are. People add system-specific clues to Clang often, but as
+ things change, it's more likely that it won't find than the
+ other way around.
+
+ So, here, you'll be a lot safer if you specify the include/library
+ directories manually (via ``-I`` and ``-L``).
+
+Target-Specific Libraries
+=========================
+
+All libraries that you compile as part of your build will be
+cross-compiled to your target, and your build system will probably
+find them in the right place. But all dependencies that are
+normally checked against (like ``libxml`` or ``libz`` etc) will match
+against the host platform, not the target.
+
+So, if the build system is not aware that you want to cross-compile
+your code, it will get every dependency wrong, and your compilation
+will fail during build time, not configure time.
+
+Also, finding the libraries for your target are not as easy
+as for your host machine. There aren't many cross-libraries available
+as packages to most OS's, so you'll have to either cross-compile them
+from source, or download the package for your target platform,
+extract the libraries and headers, put them in specific directories
+and add ``-I`` and ``-L`` pointing to them.
+
+Also, some libraries have different dependencies on different targets,
+so configuration tools to find dependencies in the host can get the
+list wrong for the target platform. This means that the configuration
+of your build can get things wrong when setting their own library
+paths, and you'll have to augment it via additional flags (configure,
+Make, CMake, etc).
+
+Multilibs
+---------
+
+When you want to cross-compile to more than one configuration, for
+example hard-float-ARM and soft-float-ARM, you'll have to have multiple
+copies of your libraries and (possibly) headers.
+
+Some Linux distributions have support for Multilib, which handle that
+for you in an easier way, but if you're not careful and, for instance,
+forget to specify ``-ccc-gcc-name armv7l-linux-gnueabihf-gcc`` (which
+uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld``
+(which uses soft-float) and linker errors will happen.
+
+The same is true if you're compiling for different ABIs, like ``gnueabi``
+and ``androideabi``, and might even link and run, but produce run-time
+errors, which are much harder to track down and fix.
+
diff --git a/docs/DataFlowSanitizer.rst b/docs/DataFlowSanitizer.rst
new file mode 100644
index 000000000000..e0e9d74efde9
--- /dev/null
+++ b/docs/DataFlowSanitizer.rst
@@ -0,0 +1,158 @@
+=================
+DataFlowSanitizer
+=================
+
+.. toctree::
+ :hidden:
+
+ DataFlowSanitizerDesign
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+DataFlowSanitizer is a generalised dynamic data flow analysis.
+
+Unlike other Sanitizer tools, this tool is not designed to detect a
+specific class of bugs on its own. Instead, it provides a generic
+dynamic data flow analysis framework to be used by clients to help
+detect application-specific issues within their own code.
+
+Usage
+=====
+
+With no program changes, applying DataFlowSanitizer to a program
+will not alter its behavior. To use DataFlowSanitizer, the program
+uses API functions to apply tags to data to cause it to be tracked, and to
+check the tag of a specific data item. DataFlowSanitizer manages
+the propagation of tags through the program according to its data flow.
+
+The APIs are defined in the header file ``sanitizer/dfsan_interface.h``.
+For further information about each function, please refer to the header
+file.
+
+ABI List
+--------
+
+DataFlowSanitizer uses a list of functions known as an ABI list to decide
+whether a call to a specific function should use the operating system's native
+ABI or whether it should use a variant of this ABI that also propagates labels
+through function parameters and return values. The ABI list file also controls
+how labels are propagated in the former case. DataFlowSanitizer comes with a
+default ABI list which is intended to eventually cover the glibc library on
+Linux but it may become necessary for users to extend the ABI list in cases
+where a particular library or function cannot be instrumented (e.g. because
+it is implemented in assembly or another language which DataFlowSanitizer does
+not support) or a function is called from a library or function which cannot
+be instrumented.
+
+DataFlowSanitizer's ABI list file is a :doc:`SanitizerSpecialCaseList`.
+The pass treats every function in the ``uninstrumented`` category in the
+ABI list file as conforming to the native ABI. Unless the ABI list contains
+additional categories for those functions, a call to one of those functions
+will produce a warning message, as the labelling behavior of the function
+is unknown. The other supported categories are ``discard``, ``functional``
+and ``custom``.
+
+* ``discard`` -- To the extent that this function writes to (user-accessible)
+ memory, it also updates labels in shadow memory (this condition is trivially
+ satisfied for functions which do not write to user-accessible memory). Its
+ return value is unlabelled.
+* ``functional`` -- Like ``discard``, except that the label of its return value
+ is the union of the label of its arguments.
+* ``custom`` -- Instead of calling the function, a custom wrapper ``__dfsw_F``
+ is called, where ``F`` is the name of the function. This function may wrap
+ the original function or provide its own implementation. This category is
+ generally used for uninstrumentable functions which write to user-accessible
+ memory or which have more complex label propagation behavior. The signature
+ of ``__dfsw_F`` is based on that of ``F`` with each argument having a
+ label of type ``dfsan_label`` appended to the argument list. If ``F``
+ is of non-void return type a final argument of type ``dfsan_label *``
+ is appended to which the custom function can store the label for the
+ return value. For example:
+
+.. code-block:: c++
+
+ void f(int x);
+ void __dfsw_f(int x, dfsan_label x_label);
+
+ void *memcpy(void *dest, const void *src, size_t n);
+ void *__dfsw_memcpy(void *dest, const void *src, size_t n,
+ dfsan_label dest_label, dfsan_label src_label,
+ dfsan_label n_label, dfsan_label *ret_label);
+
+If a function defined in the translation unit being compiled belongs to the
+``uninstrumented`` category, it will be compiled so as to conform to the
+native ABI. Its arguments will be assumed to be unlabelled, but it will
+propagate labels in shadow memory.
+
+For example:
+
+.. code-block:: none
+
+ # main is called by the C runtime using the native ABI.
+ fun:main=uninstrumented
+ fun:main=discard
+
+ # malloc only writes to its internal data structures, not user-accessible memory.
+ fun:malloc=uninstrumented
+ fun:malloc=discard
+
+ # tolower is a pure function.
+ fun:tolower=uninstrumented
+ fun:tolower=functional
+
+ # memcpy needs to copy the shadow from the source to the destination region.
+ # This is done in a custom function.
+ fun:memcpy=uninstrumented
+ fun:memcpy=custom
+
+Example
+=======
+
+The following program demonstrates label propagation by checking that
+the correct labels are propagated.
+
+.. code-block:: c++
+
+ #include <sanitizer/dfsan_interface.h>
+ #include <assert.h>
+
+ int main(void) {
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ int j = 2;
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_set_label(j_label, &j, sizeof(j));
+
+ int k = 3;
+ dfsan_label k_label = dfsan_create_label("k", 0);
+ dfsan_set_label(k_label, &k, sizeof(k));
+
+ dfsan_label ij_label = dfsan_get_label(i + j);
+ assert(dfsan_has_label(ij_label, i_label));
+ assert(dfsan_has_label(ij_label, j_label));
+ assert(!dfsan_has_label(ij_label, k_label));
+
+ dfsan_label ijk_label = dfsan_get_label(i + j + k);
+ assert(dfsan_has_label(ijk_label, i_label));
+ assert(dfsan_has_label(ijk_label, j_label));
+ assert(dfsan_has_label(ijk_label, k_label));
+
+ return 0;
+ }
+
+Current status
+==============
+
+DataFlowSanitizer is a work in progress, currently under development for
+x86\_64 Linux.
+
+Design
+======
+
+Please refer to the :doc:`design document<DataFlowSanitizerDesign>`.
diff --git a/docs/DataFlowSanitizerDesign.rst b/docs/DataFlowSanitizerDesign.rst
new file mode 100644
index 000000000000..32db88bda269
--- /dev/null
+++ b/docs/DataFlowSanitizerDesign.rst
@@ -0,0 +1,220 @@
+DataFlowSanitizer Design Document
+=================================
+
+This document sets out the design for DataFlowSanitizer, a general
+dynamic data flow analysis. Unlike other Sanitizer tools, this tool is
+not designed to detect a specific class of bugs on its own. Instead,
+it provides a generic dynamic data flow analysis framework to be used
+by clients to help detect application-specific issues within their
+own code.
+
+DataFlowSanitizer is a program instrumentation which can associate
+a number of taint labels with any data stored in any memory region
+accessible by the program. The analysis is dynamic, which means that
+it operates on a running program, and tracks how the labels propagate
+through that program. The tool shall support a large (>100) number
+of labels, such that programs which operate on large numbers of data
+items may be analysed with each data item being tracked separately.
+
+Use Cases
+---------
+
+This instrumentation can be used as a tool to help monitor how data
+flows from a program's inputs (sources) to its outputs (sinks).
+This has applications from a privacy/security perspective in that
+one can audit how a sensitive data item is used within a program and
+ensure it isn't exiting the program anywhere it shouldn't be.
+
+Interface
+---------
+
+A number of functions are provided which will create taint labels,
+attach labels to memory regions and extract the set of labels
+associated with a specific memory region. These functions are declared
+in the header file ``sanitizer/dfsan_interface.h``.
+
+.. code-block:: c
+
+ /// Creates and returns a base label with the given description and user data.
+ dfsan_label dfsan_create_label(const char *desc, void *userdata);
+
+ /// Sets the label for each address in [addr,addr+size) to \c label.
+ void dfsan_set_label(dfsan_label label, void *addr, size_t size);
+
+ /// Sets the label for each address in [addr,addr+size) to the union of the
+ /// current label for that address and \c label.
+ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
+
+ /// Retrieves the label associated with the given data.
+ ///
+ /// The type of 'data' is arbitrary. The function accepts a value of any type,
+ /// which can be truncated or extended (implicitly or explicitly) as necessary.
+ /// The truncation/extension operations will preserve the label of the original
+ /// value.
+ dfsan_label dfsan_get_label(long data);
+
+ /// Retrieves a pointer to the dfsan_label_info struct for the given label.
+ const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
+
+ /// Returns whether the given label label contains the label elem.
+ int dfsan_has_label(dfsan_label label, dfsan_label elem);
+
+ /// If the given label label contains a label with the description desc, returns
+ /// that label, else returns 0.
+ dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
+
+Taint label representation
+--------------------------
+
+As stated above, the tool must track a large number of taint
+labels. This poses an implementation challenge, as most multiple-label
+tainting systems assign one label per bit to shadow storage, and
+union taint labels using a bitwise or operation. This will not scale
+to clients which use hundreds or thousands of taint labels, as the
+label union operation becomes O(n) in the number of supported labels,
+and data associated with it will quickly dominate the live variable
+set, causing register spills and hampering performance.
+
+Instead, a low overhead approach is proposed which is best-case O(log\
+:sub:`2` n) during execution. The underlying assumption is that
+the required space of label unions is sparse, which is a reasonable
+assumption to make given that we are optimizing for the case where
+applications mostly copy data from one place to another, without often
+invoking the need for an actual union operation. The representation
+of a taint label is a 16-bit integer, and new labels are allocated
+sequentially from a pool. The label identifier 0 is special, and means
+that the data item is unlabelled.
+
+When a label union operation is requested at a join point (any
+arithmetic or logical operation with two or more operands, such as
+addition), the code checks whether a union is required, whether the
+same union has been requested before, and whether one union label
+subsumes the other. If so, it returns the previously allocated union
+label. If not, it allocates a new union label from the same pool used
+for new labels.
+
+Specifically, the instrumentation pass will insert code like this
+to decide the union label ``lu`` for a pair of labels ``l1``
+and ``l2``:
+
+.. code-block:: c
+
+ if (l1 == l2)
+ lu = l1;
+ else
+ lu = __dfsan_union(l1, l2);
+
+The equality comparison is outlined, to provide an early exit in
+the common cases where the program is processing unlabelled data, or
+where the two data items have the same label. ``__dfsan_union`` is
+a runtime library function which performs all other union computation.
+
+Further optimizations are possible, for example if ``l1`` is known
+at compile time to be zero (e.g. it is derived from a constant),
+``l2`` can be used for ``lu``, and vice versa.
+
+Memory layout and label management
+----------------------------------
+
+The following is the current memory layout for Linux/x86\_64:
+
++---------------+---------------+--------------------+
+| Start | End | Use |
++===============+===============+====================+
+| 0x700000008000|0x800000000000 | application memory |
++---------------+---------------+--------------------+
+| 0x200200000000|0x700000008000 | unused |
++---------------+---------------+--------------------+
+| 0x200000000000|0x200200000000 | union table |
++---------------+---------------+--------------------+
+| 0x000000010000|0x200000000000 | shadow memory |
++---------------+---------------+--------------------+
+| 0x000000000000|0x000000010000 | reserved by kernel |
++---------------+---------------+--------------------+
+
+Each byte of application memory corresponds to two bytes of shadow
+memory, which are used to store its taint label. As for LLVM SSA
+registers, we have not found it necessary to associate a label with
+each byte or bit of data, as some other tools do. Instead, labels are
+associated directly with registers. Loads will result in a union of
+all shadow labels corresponding to bytes loaded (which most of the
+time will be short circuited by the initial comparison) and stores will
+result in a copy of the label to the shadow of all bytes stored to.
+
+Propagating labels through arguments
+------------------------------------
+
+In order to propagate labels through function arguments and return values,
+DataFlowSanitizer changes the ABI of each function in the translation unit.
+There are currently two supported ABIs:
+
+* Args -- Argument and return value labels are passed through additional
+ arguments and by modifying the return type.
+
+* TLS -- Argument and return value labels are passed through TLS variables
+ ``__dfsan_arg_tls`` and ``__dfsan_retval_tls``.
+
+The main advantage of the TLS ABI is that it is more tolerant of ABI mismatches
+(TLS storage is not shared with any other form of storage, whereas extra
+arguments may be stored in registers which under the native ABI are not used
+for parameter passing and thus could contain arbitrary values). On the other
+hand the args ABI is more efficient and allows ABI mismatches to be more easily
+identified by checking for nonzero labels in nominally unlabelled programs.
+
+Implementing the ABI list
+-------------------------
+
+The `ABI list <DataFlowSanitizer.html#abi-list>`_ provides a list of functions
+which conform to the native ABI, each of which is callable from an instrumented
+program. This is implemented by replacing each reference to a native ABI
+function with a reference to a function which uses the instrumented ABI.
+Such functions are automatically-generated wrappers for the native functions.
+For example, given the ABI list example provided in the user manual, the
+following wrappers will be generated under the args ABI:
+
+.. code-block:: llvm
+
+ define linkonce_odr { i8*, i16 } @"dfsw$malloc"(i64 %0, i16 %1) {
+ entry:
+ %2 = call i8* @malloc(i64 %0)
+ %3 = insertvalue { i8*, i16 } undef, i8* %2, 0
+ %4 = insertvalue { i8*, i16 } %3, i16 0, 1
+ ret { i8*, i16 } %4
+ }
+
+ define linkonce_odr { i32, i16 } @"dfsw$tolower"(i32 %0, i16 %1) {
+ entry:
+ %2 = call i32 @tolower(i32 %0)
+ %3 = insertvalue { i32, i16 } undef, i32 %2, 0
+ %4 = insertvalue { i32, i16 } %3, i16 %1, 1
+ ret { i32, i16 } %4
+ }
+
+ define linkonce_odr { i8*, i16 } @"dfsw$memcpy"(i8* %0, i8* %1, i64 %2, i16 %3, i16 %4, i16 %5) {
+ entry:
+ %labelreturn = alloca i16
+ %6 = call i8* @__dfsw_memcpy(i8* %0, i8* %1, i64 %2, i16 %3, i16 %4, i16 %5, i16* %labelreturn)
+ %7 = load i16* %labelreturn
+ %8 = insertvalue { i8*, i16 } undef, i8* %6, 0
+ %9 = insertvalue { i8*, i16 } %8, i16 %7, 1
+ ret { i8*, i16 } %9
+ }
+
+As an optimization, direct calls to native ABI functions will call the
+native ABI function directly and the pass will compute the appropriate label
+internally. This has the advantage of reducing the number of union operations
+required when the return value label is known to be zero (i.e. ``discard``
+functions, or ``functional`` functions with known unlabelled arguments).
+
+Checking ABI Consistency
+------------------------
+
+DFSan changes the ABI of each function in the module. This makes it possible
+for a function with the native ABI to be called with the instrumented ABI,
+or vice versa, thus possibly invoking undefined behavior. A simple way
+of statically detecting instances of this problem is to prepend the prefix
+"dfs$" to the name of each instrumented-ABI function.
+
+This will not catch every such problem; in particular function pointers passed
+across the instrumented-native barrier cannot be used on the other side.
+These problems could potentially be caught dynamically.
diff --git a/docs/InternalsManual.rst b/docs/InternalsManual.rst
index 59dd2f98d6d6..6f5570263fc5 100644
--- a/docs/InternalsManual.rst
+++ b/docs/InternalsManual.rst
@@ -950,17 +950,13 @@ functions, Objective-C methods, C++ constructors, destructors, and operators
``DeclarationName`` is designed to efficiently represent any kind of name.
Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value
-that describes what kind of name ``N`` stores. There are 8 options (all of the
-names are inside the ``DeclarationName`` class).
+that describes what kind of name ``N`` stores. There are 10 options (all of
+the names are inside the ``DeclarationName`` class).
``Identifier``
The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
the corresponding ``IdentifierInfo*`` pointing to the actual identifier.
- Note that C++ overloaded operators (e.g., "``operator+``") are represented as
- special kinds of identifiers. Use ``IdentifierInfo``'s
- ``getOverloadedOperatorID`` function to determine whether an identifier is an
- overloaded operator name.
``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector``
@@ -999,6 +995,21 @@ names are inside the ``DeclarationName`` class).
Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
value of type ``OverloadedOperatorKind``).
+``CXXLiteralOperatorName``
+
+ The name is a C++11 user defined literal operator. User defined
+ Literal operators are named according to the suffix they define,
+ e.g., "``_foo``" for "``operator "" _foo``". Use
+ ``N.getCXXLiteralIdentifier()`` to retrieve the corresponding
+ ``IdentifierInfo*`` pointing to the identifier.
+
+``CXXUsingDirective``
+
+ The name is a C++ using directive. Using directives are not really
+ NamedDecls, in that they all have the same name, but they are
+ implemented as such in order to store them in DeclContext
+ effectively.
+
``DeclarationName``\ s are cheap to create, copy, and compare. They require
only a single pointer's worth of storage in the common cases (identifiers,
zero- and one-argument Objective-C selectors) and use dense, uniqued storage
diff --git a/docs/IntroductionToTheClangAST.rst b/docs/IntroductionToTheClangAST.rst
index 81eb7ed0b9ef..600a6c884cb9 100644
--- a/docs/IntroductionToTheClangAST.rst
+++ b/docs/IntroductionToTheClangAST.rst
@@ -7,6 +7,12 @@ AST. It is targeted at developers who either want to contribute to
Clang, or use tools that work based on Clang's AST, like the AST
matchers.
+.. raw:: html
+
+ <center><iframe width="560" height="315" src="http://www.youtube.com/embed/VqCkCDFLSsc?vq=hd720" frameborder="0" allowfullscreen></iframe></center>
+
+`Slides <http://llvm.org/devmtg/2013-04/klimek-slides.pdf>`_
+
Introduction
============
@@ -27,9 +33,8 @@ Examining the AST
=================
A good way to familarize yourself with the Clang AST is to actually look
-at it on some simple example code. Clang has a builtin AST-dump modes,
-which can be enabled with the flags ``-ast-dump`` and ``-ast-dump-xml``. Note
-that ``-ast-dump-xml`` currently only works with debug builds of clang.
+at it on some simple example code. Clang has a builtin AST-dump mode,
+which can be enabled with the flag ``-ast-dump``.
Let's look at a simple example AST:
@@ -41,40 +46,26 @@ Let's look at a simple example AST:
return result;
}
- # Clang by default is a frontend for many tools; -cc1 tells it to directly
- # use the C++ compiler mode. -undef leaves out some internal declarations.
- $ clang -cc1 -undef -ast-dump-xml test.cc
+ # Clang by default is a frontend for many tools; -Xclang is used to pass
+ # options directly to the C++ frontend.
+ $ clang -Xclang -ast-dump -fsyntax-only test.cc
+ TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
... cutting out internal declarations of clang ...
- <TranslationUnit ptr="0x4871160">
- <Function ptr="0x48a5800" name="f" prototype="true">
- <FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
- <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- <parameters>
- <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- </parameters>
- </FunctionProtoType>
- <ParmVar ptr="0x4871d80" name="x" initstyle="c">
- <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- </ParmVar>
- <Stmt>
- (CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1>
- (DeclStmt 0x48a59c0 <line:2:3, col:24>
- 0x48a58c0 "int result =
- (ParenExpr 0x48a59a0 <col:16, col:23> 'int'
- (BinaryOperator 0x48a5978 <col:17, col:21> 'int' '/'
- (ImplicitCastExpr 0x48a5960 <col:17> 'int' <LValueToRValue>
- (DeclRefExpr 0x48a5918 <col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
- (IntegerLiteral 0x48a5940 <col:21> 'int' 42)))")
- (ReturnStmt 0x48a5a18 <line:3:3, col:10>
- (ImplicitCastExpr 0x48a5a00 <col:10> 'int' <LValueToRValue>
- (DeclRefExpr 0x48a59d8 <col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
-
- </Stmt>
- </Function>
- </TranslationUnit>
-
-In general, ``-ast-dump-xml`` dumps declarations in an XML-style format and
-statements in an S-expression-style format. The toplevel declaration in
+ `-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
+ |-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
+ `-CompoundStmt 0x5aead88 <col:14, line:4:1>
+ |-DeclStmt 0x5aead10 <line:2:3, col:24>
+ | `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
+ | `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
+ | `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
+ | |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
+ | | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
+ | `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
+ `-ReturnStmt 0x5aead68 <line:3:3, col:10>
+ `-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
+ `-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
+
+The toplevel declaration in
a translation unit is always the `translation unit
declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
In this example, our first user written declaration is the `function
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 324feafa98f0..7a4b31e7acc0 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -159,12 +159,16 @@ include paths, or 0 otherwise:
# include "myinclude.h"
#endif
+To test for this feature, use ``#if defined(__has_include)``:
+
+.. code-block:: c++
+
// To avoid problem with non-clang compilers not having this macro.
- #if defined(__has_include) && __has_include("myinclude.h")
+ #if defined(__has_include)
+ #if __has_include("myinclude.h")
# include "myinclude.h"
#endif
-
-To test for this feature, use ``#if defined(__has_include)``.
+ #endif
.. _langext-__has_include_next:
@@ -185,9 +189,11 @@ or 0 otherwise:
#endif
// To avoid problem with non-clang compilers not having this macro.
- #if defined(__has_include_next) && __has_include_next("myinclude.h")
+ #if defined(__has_include_next)
+ #if __has_include_next("myinclude.h")
# include_next "myinclude.h"
#endif
+ #endif
Note that ``__has_include_next``, like the GNU extension ``#include_next``
directive, is intended for use in headers only, and will issue a warning if
@@ -801,8 +807,7 @@ Use ``__has_feature(cxx_contextual_conversions)`` or
``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y 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. Clang does not yet
-support this feature.
+expression, or a condition in a ``switch`` statement.
C++1y decltype(auto)
^^^^^^^^^^^^^^^^^^^^
@@ -821,9 +826,9 @@ for default initializers in aggregate members is enabled.
C++1y generalized lambda capture
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Use ``__has_feature(cxx_generalized_capture)`` or
-``__has_extension(cxx_generalized_capture`` to determine if support for
-generalized lambda captures is enabled
+Use ``__has_feature(cxx_init_capture)`` or
+``__has_extension(cxx_init_capture)`` to determine if support for
+lambda captures with explicit initializers is enabled
(for instance, ``[n(0)] { return ++n; }``).
Clang does not yet support this feature.
@@ -843,7 +848,6 @@ Use ``__has_feature(cxx_relaxed_constexpr)`` or
``__has_extension(cxx_relaxed_constexpr)`` to determine if variable
declarations, local variable modification, and control flow constructs
are permitted in ``constexpr`` functions.
-Clang's implementation of this feature is incomplete.
C++1y return type deduction
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -852,7 +856,6 @@ Use ``__has_feature(cxx_return_type_deduction)`` or
``__has_extension(cxx_return_type_deduction)`` to determine if support
for return type deduction for functions (using ``auto`` as a return type)
is enabled.
-Clang's implementation of this feature is incomplete.
C++1y runtime-sized arrays
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -918,8 +921,8 @@ enabled.
C11 ``_Thread_local``
^^^^^^^^^^^^^^^^^^^^^
-Use ``__has_feature(c_thread_local)`` to determine if support for
-``_Thread_local`` variables is enabled.
+Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
+to determine if support for ``_Thread_local`` variables is enabled.
Checks for Type Traits
======================
@@ -1173,8 +1176,52 @@ of this feature in version of clang being used.
.. _langext-objc_method_family:
-The ``objc_method_family`` attribute
-------------------------------------
+
+Objective-C requiring a call to ``super`` in an override
+--------------------------------------------------------
+
+Some Objective-C classes allow a subclass to override a particular method in a
+parent class but expect that the overriding method also calls the overridden
+method in the parent class. For these cases, we provide an attribute to
+designate that a method requires a "call to ``super``" in the overriding
+method in the subclass.
+
+**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
+be placed at the end of a method declaration:
+
+.. code-block:: objc
+
+ - (void)foo __attribute__((objc_requires_super));
+
+This attribute can only be applied the method declarations within a class, and
+not a protocol. Currently this attribute does not enforce any placement of
+where the call occurs in the overriding method (such as in the case of
+``-dealloc`` where the call must appear at the end). It checks only that it
+exists.
+
+Note that on both OS X and iOS that the Foundation framework provides a
+convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this
+attribute:
+
+.. code-block:: objc
+
+ - (void)foo NS_REQUIRES_SUPER;
+
+This macro is conditionally defined depending on the compiler's support for
+this attribute. If the compiler does not support the attribute the macro
+expands to nothing.
+
+Operationally, when a method has this annotation the compiler will warn if the
+implementation of an override in a subclass does not call super. For example:
+
+.. code-block:: objc
+
+ warning: method possibly missing a [super AnnotMeth] call
+ - (void) AnnotMeth{};
+ ^
+
+Objective-C Method Families
+---------------------------
Many methods in Objective-C have conventional meanings determined by their
selectors. It is sometimes useful to be able to mark a method as having a
@@ -1253,6 +1300,21 @@ Query for these features with ``__has_attribute(ns_consumed)``,
``__has_attribute(ns_returns_retained)``, etc.
+Objective-C++ ABI: protocol-qualifier mangling of parameters
+------------------------------------------------------------
+
+Starting with LLVM 3.4, Clang produces a new mangling for parameters whose
+type is a qualified-``id`` (e.g., ``id<Foo>``). This mangling allows such
+parameters to be differentiated from those with the regular unqualified ``id``
+type.
+
+This was a non-backward compatible mangling change to the ABI. This change
+allows proper overloading, and also prevents mangling conflicts with template
+parameters of protocol-qualified type.
+
+Query the presence of this new mangling with
+``__has_feature(objc_protocol_qualifier_mangling)``.
+
Function Overloading in C
=========================
@@ -1411,7 +1473,9 @@ should only be used for timing small intervals. When not supported by the
target, the return value is always zero. This builtin takes no arguments and
produces an unsigned long long result.
-Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``.
+Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Note
+that even if present, its use may depend on run-time privilege or other OS
+controlled state.
.. _langext-__builtin_shufflevector:
@@ -1433,8 +1497,8 @@ for the implementation of various target-specific header files like
.. code-block:: c++
- // Identity operation - return 4-element vector V1.
- __builtin_shufflevector(V1, V1, 0, 1, 2, 3)
+ // identity operation - return 4-element vector v1.
+ __builtin_shufflevector(v1, v1, 0, 1, 2, 3)
// "Splat" element 0 of V1 into a 4-element result.
__builtin_shufflevector(V1, V1, 0, 0, 0, 0)
@@ -1448,6 +1512,9 @@ for the implementation of various target-specific header files like
// Concatenate every other element of 8-element vectors V1 and V2.
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
+ // Shuffle v1 with some elements being undefined
+ __builtin_shufflevector(v1, v1, 3, -1, 1, -1)
+
**Description**:
The first two arguments to ``__builtin_shufflevector`` are vectors that have
@@ -1456,7 +1523,8 @@ specify the elements indices of the first two vectors that should be extracted
and returned in a new vector. These element indices are numbered sequentially
starting with the first vector, continuing into the second vector. Thus, if
``vec1`` is a 4-element vector, index 5 would refer to the second element of
-``vec2``.
+``vec2``. An index of -1 can be used to indicate that the corresponding element
+in the returned vector is a don't care and can be optimized by the backend.
The result of ``__builtin_shufflevector`` is a vector with the same element
type as ``vec1``/``vec2`` but that has an element count equal to the number of
@@ -1464,6 +1532,50 @@ indices specified.
Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
+``__builtin_convertvector``
+---------------------------
+
+``__builtin_convertvector`` is used to express generic vector
+type-conversion operations. The input vector and the output vector
+type must have the same number of elements.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_convertvector(src_vec, dst_vec_type)
+
+**Examples**:
+
+.. code-block:: c++
+
+ typedef double vector4double __attribute__((__vector_size__(32)));
+ typedef float vector4float __attribute__((__vector_size__(16)));
+ typedef short vector4short __attribute__((__vector_size__(8)));
+ vector4float vf; vector4short vs;
+
+ // convert from a vector of 4 floats to a vector of 4 doubles.
+ __builtin_convertvector(vf, vector4double)
+ // equivalent to:
+ (vector4double) { (double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3] }
+
+ // convert from a vector of 4 shorts to a vector of 4 floats.
+ __builtin_convertvector(vs, vector4float)
+ // equivalent to:
+ (vector4float) { (float) vf[0], (float) vf[1], (float) vf[2], (float) vf[3] }
+
+**Description**:
+
+The first argument to ``__builtin_convertvector`` is a vector, and the second
+argument is a vector type with the same number of elements as the first
+argument.
+
+The result of ``__builtin_convertvector`` is a vector with the same element
+type as the second argument, with a value defined in terms of the action of a
+C-style cast applied to each element of the first argument.
+
+Query for this feature with ``__has_builtin(__builtin_convertvector)``.
+
``__builtin_unreachable``
-------------------------
@@ -1526,6 +1638,22 @@ correct code by avoiding expensive loops around
implementation details of ``__sync_lock_test_and_set()``. The
``__sync_swap()`` builtin is a full barrier.
+``__builtin_addressof``
+-----------------------
+
+``__builtin_addressof`` performs the functionality of the built-in ``&``
+operator, ignoring any ``operator&`` overload. This is useful in constant
+expressions in C++11, where there is no other way to take the address of an
+object that overloads ``operator&``.
+
+**Example of use**:
+
+.. code-block:: c++
+
+ template<typename T> constexpr T *addressof(T &value) {
+ return __builtin_addressof(value);
+ }
+
Multiprecision Arithmetic Builtins
----------------------------------
@@ -1554,15 +1682,60 @@ The complete list of builtins are:
.. code-block:: c
+ unsigned char __builtin_addcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
+ unsigned char __builtin_subcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
+Checked Arithmetic Builtins
+---------------------------
+
+Clang provides a set of builtins that implement checked arithmetic for security
+critical applications in a manner that is fast and easily expressable in C. As
+an example of their usage:
+
+.. code-block:: c
+
+ errorcode_t security_critical_application(...) {
+ unsigned x, y, result;
+ ...
+ if (__builtin_umul_overflow(x, y, &result))
+ return kErrorCodeHackers;
+ ...
+ use_multiply(result);
+ ...
+ }
+
+A complete enumeration of the builtins are:
+
+.. code-block:: c
+
+ bool __builtin_uadd_overflow (unsigned x, unsigned y, unsigned *sum);
+ bool __builtin_uaddl_overflow (unsigned long x, unsigned long y, unsigned long *sum);
+ bool __builtin_uaddll_overflow(unsigned long long x, unsigned long long y, unsigned long long *sum);
+ bool __builtin_usub_overflow (unsigned x, unsigned y, unsigned *diff);
+ bool __builtin_usubl_overflow (unsigned long x, unsigned long y, unsigned long *diff);
+ bool __builtin_usubll_overflow(unsigned long long x, unsigned long long y, unsigned long long *diff);
+ bool __builtin_umul_overflow (unsigned x, unsigned y, unsigned *prod);
+ bool __builtin_umull_overflow (unsigned long x, unsigned long y, unsigned long *prod);
+ bool __builtin_umulll_overflow(unsigned long long x, unsigned long long y, unsigned long long *prod);
+ bool __builtin_sadd_overflow (int x, int y, int *sum);
+ bool __builtin_saddl_overflow (long x, long y, long *sum);
+ bool __builtin_saddll_overflow(long long x, long long y, long long *sum);
+ bool __builtin_ssub_overflow (int x, int y, int *diff);
+ bool __builtin_ssubl_overflow (long x, long y, long *diff);
+ bool __builtin_ssubll_overflow(long long x, long long y, long long *diff);
+ bool __builtin_smul_overflow (int x, int y, int *prod);
+ bool __builtin_smull_overflow (long x, long y, long *prod);
+ bool __builtin_smulll_overflow(long long x, long long y, long long *prod);
+
+
.. _langext-__c11_atomic:
__c11_atomic builtins
@@ -1588,6 +1761,37 @@ C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
* ``__c11_atomic_fetch_or``
* ``__c11_atomic_fetch_xor``
+Low-level ARM exclusive memory builtins
+---------------------------------------
+
+Clang provides overloaded builtins giving direct access to the three key ARM
+instructions for implementing atomic operations.
+
+.. code-block:: c
+
+ T __builtin_arm_ldrex(const volatile T *addr);
+ int __builtin_arm_strex(T val, volatile T *addr);
+ void __builtin_arm_clrex(void);
+
+The types ``T`` currently supported are:
+* Integer types with width at most 64 bits.
+* Floating-point types
+* Pointer types.
+
+Note that the compiler does not guarantee it will not insert stores which clear
+the exclusive monitor in between an ``ldrex`` and its paired ``strex``. In
+practice this is only usually a risk when the extra store is on the same cache
+line as the variable being modified and Clang will only insert stack stores on
+its own, so it is best not to use these operations on variables with automatic
+storage duration.
+
+Also, loads and stores may be implicit in code written between the ``ldrex`` and
+``strex``. Clang will not necessarily mitigate the effects of these either, so
+care should be exercised.
+
+For these reasons the higher level atomic primitives should be preferred where
+possible.
+
Non-standard C++11 Attributes
=============================
@@ -1649,7 +1853,7 @@ are accepted with the ``__attribute__((foo))`` syntax are also accepted as
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable
attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
`GCC type attributes
-<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_. As with the GCC
+<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_). As with the GCC
implementation, these attributes must appertain to the *declarator-id* in a
declaration, which means they must go either at the start of the declaration or
immediately after the name being declared.
@@ -1698,6 +1902,48 @@ Which compiles to (on X86-32):
movl %gs:(%eax), %eax
ret
+ARM Language Extensions
+-----------------------
+
+Interrupt attribute
+^^^^^^^^^^^^^^^^^^^
+
+Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
+ARM targets. This attribute may be attached to a function definition and
+instructs the backend to generate appropriate function entry/exit code so that
+it can be used directly as an interrupt service routine.
+
+ The parameter passed to the interrupt attribute is optional, but if
+provided it must be a string literal with one of the following values: "IRQ",
+"FIQ", "SWI", "ABORT", "UNDEF".
+
+The semantics are as follows:
+
+- If the function is AAPCS, Clang instructs the backend to realign the stack to
+ 8 bytes on entry. This is a general requirement of the AAPCS at public
+ interfaces, but may not hold when an exception is taken. Doing this allows
+ other AAPCS functions to be called.
+- If the CPU is M-class this is all that needs to be done since the architecture
+ itself is designed in such a way that functions obeying the normal AAPCS ABI
+ constraints are valid exception handlers.
+- If the CPU is not M-class, the prologue and epilogue are modified to save all
+ non-banked registers that are used, so that upon return the user-mode state
+ will not be corrupted. Note that to avoid unnecessary overhead, only
+ general-purpose (integer) registers are saved in this way. If VFP operations
+ are needed, that state must be saved manually.
+
+ Specifically, interrupt kinds other than "FIQ" will save all core registers
+ except "lr" and "sp". "FIQ" interrupts will save r0-r7.
+- If the CPU is not M-class, the return instruction is changed to one of the
+ canonical sequences permitted by the architecture for exception return. Where
+ possible the function itself will make the necessary "lr" adjustments so that
+ the "preferred return address" is selected.
+
+ Unfortunately the compiler is unable to make this guarantee for an "UNDEF"
+ handler, where the offset from "lr" to the preferred return address depends on
+ the execution state of the code which generated the exception. In this case
+ a sequence equivalent to "movs pc, lr" will be used.
+
Extensions for Static Analysis
==============================
@@ -1735,8 +1981,8 @@ with :doc:`ThreadSanitizer`.
Use ``__attribute__((no_sanitize_thread))`` on a function declaration
to specify that checks for data races on plain (non-atomic) memory accesses
should not be inserted by ThreadSanitizer.
-The function may still be instrumented by the tool
-to avoid false positives in other places.
+The function is still instrumented by the tool to avoid false positives and
+provide meaningful stack traces.
.. _langext-memory_sanitizer:
@@ -1905,15 +2151,72 @@ to specify that the function must be called while holding the listed shared
locks. Arguments must be lockable type, and there must be at least one
argument.
+Consumed Annotation Checking
+============================
+
+Clang supports additional attributes for checking basic resource management
+properties, specifically for unique objects that have a single owning reference.
+The following attributes are currently supported, although **the implementation
+for these annotations is currently in development and are subject to change.**
+
+``consumable``
+--------------
+
+Each class that uses any of the following annotations must first be marked
+using the consumable attribute. Failure to do so will result in a warning.
+
+``set_typestate(new_state)``
+----------------------------
+
+Annotate methods that transition an object into a new state with
+``__attribute__((set_typestate(new_state)))``. The new new state must be
+unconsumed, consumed, or unknown.
+
+``callable_when(...)``
+----------------------
+
+Use ``__attribute__((callable_when(...)))`` to indicate what states a method
+may be called in. Valid states are unconsumed, consumed, or unknown. Each
+argument to this attribute must be a quoted string. E.g.:
+
+``__attribute__((callable_when("unconsumed", "unknown")))``
+
+``tests_typestate(tested_state)``
+---------------------------------
+
+Use ``__attribute__((tests_typestate(tested_state)))`` to indicate that a method
+returns true if the object is in the specified state..
+
+``param_typestate(expected_state)``
+-----------------------------------
+
+This attribute specifies expectations about function parameters. Calls to an
+function with annotated parameters will issue a warning if the corresponding
+argument isn't in the expected state. The attribute is also used to set the
+initial state of the parameter when analyzing the function's body.
+
+``return_typestate(ret_state)``
+-------------------------------
+
+The ``return_typestate`` attribute can be applied to functions or parameters.
+When applied to a function the attribute specifies the state of the returned
+value. The function's body is checked to ensure that it always returns a value
+in the specified state. On the caller side, values returned by the annotated
+function are initialized to the given state.
+
+If the attribute is applied to a function parameter it modifies the state of
+an argument after a call to the function returns. The function's body is
+checked to ensure that the parameter is in the expected state before returning.
+
Type Safety Checking
====================
Clang supports additional attributes to enable checking type safety properties
-that can't be enforced by C type system. Usecases include:
+that can't be enforced by the C type system. Use cases include:
* MPI library implementations, where these attributes enable checking that
- buffer type matches the passed ``MPI_Datatype``;
-* for HDF5 library there is a similar usecase as MPI;
+ the buffer type matches the passed ``MPI_Datatype``;
+* for HDF5 library there is a similar use case to MPI;
* checking types of variadic functions' arguments for functions like
``fcntl()`` and ``ioctl()``.
@@ -1948,7 +2251,7 @@ accepts a type tag that determines the type of some other argument.
applicable type tags.
This attribute is primarily useful for checking arguments of variadic functions
-(``pointer_with_type_tag`` can be used in most of non-variadic cases).
+(``pointer_with_type_tag`` can be used in most non-variadic cases).
For example:
diff --git a/docs/LeakSanitizer.rst b/docs/LeakSanitizer.rst
new file mode 100644
index 000000000000..b1071efd1aa2
--- /dev/null
+++ b/docs/LeakSanitizer.rst
@@ -0,0 +1,32 @@
+================
+LeakSanitizer
+================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+LeakSanitizer is a run-time memory leak detector. It can be combined with
+:doc:`AddressSanitizer` to get both memory error and leak detection.
+LeakSanitizer does not introduce any additional slowdown when used in this mode.
+The LeakSanitizer runtime can also be linked in separately to get leak detection
+only, at a minimal performance cost.
+
+Current status
+==============
+
+LeakSanitizer is experimental and supported only on x86\_64 Linux.
+
+The combined mode has been tested on fairly large software projects. The
+stand-alone mode has received much less testing.
+
+There are plans to support LeakSanitizer in :doc:`MemorySanitizer` builds.
+
+More Information
+================
+
+`https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer
+<https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer>`_
+
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index e80e4426f4b6..2c9b3aae0a89 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -57,6 +57,18 @@ find all matchers that can be used to match on Stmt nodes.</p>
<p>The exception to that rule are matchers that can match on any node. Those
are marked with a * and are listed in the beginning of each category.</p>
+<p>Note that the categorization of matchers is a great help when you combine
+them into matcher expressions. You will usually want to form matcher expressions
+that read like english sentences by alternating between node matchers and
+narrowing or traversal matchers, like this:
+<pre>
+recordDecl(hasDescendant(
+ ifStmt(hasTrueExpression(
+ expr(hasDescendant(
+ ifStmt()))))))
+</pre>
+</p>
+
<!-- ======================================================================= -->
<h2 id="decl-matchers">Node Matchers</h2>
<!-- ======================================================================= -->
@@ -73,10 +85,32 @@ and implicitly act as allOf matchers.</p>
bind the matched node to the given string, to be later retrieved from the
match callback.</p>
+<p>It is important to remember that the arguments to node matchers are
+predicates on the same node, just with additional information about the type.
+This is often useful to make matcher expression more readable by inlining bind
+calls into redundant node matchers inside another node matcher:
+<pre>
+// This binds the CXXRecordDecl to "id", as the decl() matcher will stay on
+// the same node.
+recordDecl(decl().bind("id"), hasName("::MyClass"))
+</pre>
+</p>
+
<table>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_DECL_MATCHERS -->
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt;</td><td class="name" onclick="toggle('ctorInitializer0')"><a name="ctorInitializer0Anchor">ctorInitializer</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="ctorInitializer0"><pre>Matches constructor initializers.
+
+Examples matches i(42).
+ class C {
+ C() : i(42) {}
+ int i;
+ };
+</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('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html">AccessSpecDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="accessSpecDecl0"><pre>Matches C++ access specifier declarations.
@@ -134,6 +168,17 @@ Examples matches X, C, and the friend declaration inside C;
</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('declaratorDecl0')"><a name="declaratorDecl0Anchor">declaratorDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="declaratorDecl0"><pre>Matches declarator declarations (field, variable, function
+and non-type template parameter declarations).
+
+Given
+ class X { int y; };
+declaratorDecl()
+ matches int y.
+</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('destructorDecl0')"><a name="destructorDecl0Anchor">destructorDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDestructorDecl.html">CXXDestructorDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="destructorDecl0"><pre>Matches explicit C++ destructor declarations.
@@ -175,6 +220,16 @@ fieldDecl()
</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('friendDecl0')"><a name="friendDecl0Anchor">friendDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="friendDecl0"><pre>Matches friend declarations.
+
+Given
+ class X { friend void foo(); };
+friendDecl()
+ matches 'friend void 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('functionDecl0')"><a name="functionDecl0Anchor">functionDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="functionDecl0"><pre>Matches function declarations.
@@ -212,6 +267,27 @@ Example matches X, S, the anonymous union type, i, and U;
</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('namespaceDecl0')"><a name="namespaceDecl0Anchor">namespaceDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="namespaceDecl0"><pre>Matches a declaration of a namespace.
+
+Given
+ namespace {}
+ namespace test {}
+namespaceDecl()
+ matches "namespace {}" and "namespace test {}"
+</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.
+
+Given
+ void f(int x);
+parmVarDecl()
+ matches int x.
+</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('recordDecl0')"><a name="recordDecl0Anchor">recordDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="recordDecl0"><pre>Matches C++ class declarations.
@@ -221,6 +297,18 @@ Example matches X, Z
</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('unresolvedUsingValueDecl0')"><a name="unresolvedUsingValueDecl0Anchor">unresolvedUsingValueDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingValueDecl.html">UnresolvedUsingValueDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="unresolvedUsingValueDecl0"><pre>Matches unresolved using value declarations.
+
+Given
+ template&lt;typename X&gt;
+ class C : private X {
+ using X::x;
+ };
+unresolvedUsingValueDecl()
+ matches using X::x </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('usingDecl0')"><a name="usingDecl0Anchor">usingDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="usingDecl0"><pre>Matches using declarations.
@@ -341,6 +429,16 @@ Example matches x.y() and y()
</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('caseStmt0')"><a name="caseStmt0Anchor">caseStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="caseStmt0"><pre>Matches case statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+caseStmt()
+ matches 'case 42: break;'.
+</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('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
@@ -460,6 +558,16 @@ Example matches the CXXDefaultArgExpr placeholder inserted for the
</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('defaultStmt0')"><a name="defaultStmt0Anchor">defaultStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DefaultStmt.html">DefaultStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="defaultStmt0"><pre>Matches default statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+defaultStmt()
+ matches 'default: break;'.
+</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('deleteExpr0')"><a name="deleteExpr0Anchor">deleteExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDeleteExpr.html">CXXDeleteExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="deleteExpr0"><pre>Matches delete expressions.
@@ -523,6 +631,15 @@ Example matches x()
</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('floatLiteral0')"><a name="floatLiteral0Anchor">floatLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes encodings, e.g.
+1.0, 1.0f, 1.0L and 1e10.
+
+Does not match implicit conversions such as
+ float a = 10;
+</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('forRangeStmt0')"><a name="forRangeStmt0Anchor">forRangeStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="forRangeStmt0"><pre>Matches range-based for statements.
@@ -591,11 +708,10 @@ initList()
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('integerLiteral0')"><a name="integerLiteral0Anchor">integerLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings.
+<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings, e.g.
+1, 1L, 0x1 and 1U.
-Not matching character-encoded integers such as L'a'.
-
-Example matches 1, 1L, 0x1, 1U
+Does not match character-encoded integers such as L'a'.
</pre></td></tr>
@@ -771,6 +887,14 @@ switchStmt()
</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('temporaryObjectExpr0')"><a name="temporaryObjectExpr0Anchor">temporaryObjectExpr</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="temporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
+
+Example: Matches Foo(bar, bar)
+ Foo h = Foo(bar, bar);
+</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('thisExpr0')"><a name="thisExpr0Anchor">thisExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="thisExpr0"><pre>Matches implicit and explicit this expressions.
@@ -820,6 +944,16 @@ Example matches !a
</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('unresolvedConstructExpr0')"><a name="unresolvedConstructExpr0Anchor">unresolvedConstructExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="unresolvedConstructExpr0"><pre>Matches unresolved constructor call expressions.
+
+Example matches T(t) in return statement of f
+ (matcher = unresolvedConstructExpr())
+ template &lt;typename T&gt;
+ void f(const T&amp; t) { return T(t); }
+</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('userDefinedLiteral0')"><a name="userDefinedLiteral0Anchor">userDefinedLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UserDefinedLiteral.html">UserDefinedLiteral</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="userDefinedLiteral0"><pre>Matches user defined literal operator call.
@@ -837,285 +971,11 @@ whileStmt()
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('arrayTypeLoc0')"><a name="arrayTypeLoc0Anchor">arrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="arrayTypeLoc0"><pre>Matches all kinds of arrays.
-
-Given
- int a[] = { 2, 3 };
- int b[4];
- void f() { int c[a[0]]; }
-arrayType()
- matches "int a[]", "int b[4]" and "int c[a[0]]";
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('atomicTypeLoc0')"><a name="atomicTypeLoc0Anchor">atomicTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicTypeLoc.html">AtomicTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="atomicTypeLoc0"><pre>Matches atomic types.
-
-Given
- _Atomic(int) i;
-atomicType()
- matches "_Atomic(int) i"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('autoTypeLoc0')"><a name="autoTypeLoc0Anchor">autoTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoTypeLoc.html">AutoTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="autoTypeLoc0"><pre>Matches types nodes representing C++11 auto types.
-
-Given:
- auto n = 4;
- int v[] = { 2, 3 }
- for (auto i : v) { }
-autoType()
- matches "auto n" and "auto i"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('blockPointerTypeLoc0')"><a name="blockPointerTypeLoc0Anchor">blockPointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="blockPointerTypeLoc0"><pre>Matches block pointer types, i.e. types syntactically represented as
-"void (^)(int)".
-
-The pointee is always required to be a FunctionType.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('builtinTypeLoc0')"><a name="builtinTypeLoc0Anchor">builtinTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BuiltinTypeLoc.html">BuiltinTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="builtinTypeLoc0"><pre>Matches builtin Types.
-
-Given
- struct A {};
- A a;
- int b;
- float c;
- bool d;
-builtinType()
- matches "int b", "float c" and "bool d"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('complexTypeLoc0')"><a name="complexTypeLoc0Anchor">complexTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="complexTypeLoc0"><pre>Matches C99 complex types.
-
-Given
- _Complex float f;
-complexType()
- matches "_Complex float f"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('constantArrayTypeLoc0')"><a name="constantArrayTypeLoc0Anchor">constantArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayTypeLoc.html">ConstantArrayTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="constantArrayTypeLoc0"><pre>Matches C arrays with a specified constant size.
-
-Given
- void() {
- int a[2];
- int b[] = { 2, 3 };
- int c[b[0]];
- }
-constantArrayType()
- matches "int a[2]"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('dependentSizedArrayTypeLoc0')"><a name="dependentSizedArrayTypeLoc0Anchor">dependentSizedArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DependentSizedArrayTypeLoc.html">DependentSizedArrayTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="dependentSizedArrayTypeLoc0"><pre>Matches C++ arrays whose size is a value-dependent expression.
-
-Given
- template&lt;typename T, int Size&gt;
- class array {
- T data[Size];
- };
-dependentSizedArrayType
- matches "T data[Size]"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('elaboratedTypeLoc0')"><a name="elaboratedTypeLoc0Anchor">elaboratedTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedTypeLoc.html">ElaboratedTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="elaboratedTypeLoc0"><pre>Matches types specified with an elaborated type keyword or with a
-qualified name.
-
-Given
- namespace N {
- namespace M {
- class D {};
- }
- }
- class C {};
-
- class C c;
- N::M::D d;
-
-elaboratedType() matches the type of the variable declarations of both
-c and d.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('functionTypeLoc0')"><a name="functionTypeLoc0Anchor">functionTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTypeLoc.html">FunctionTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="functionTypeLoc0"><pre>Matches FunctionType nodes.
-
-Given
- int (*f)(int);
- void g();
-functionType()
- matches "int (*f)(int)" and the type of "g".
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('incompleteArrayTypeLoc0')"><a name="incompleteArrayTypeLoc0Anchor">incompleteArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IncompleteArrayTypeLoc.html">IncompleteArrayTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="incompleteArrayTypeLoc0"><pre>Matches C arrays with unspecified size.
-
-Given
- int a[] = { 2, 3 };
- int b[42];
- void f(int c[]) { int d[a[0]]; };
-incompleteArrayType()
- matches "int a[]" and "int c[]"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('lValueReferenceTypeLoc0')"><a name="lValueReferenceTypeLoc0Anchor">lValueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceTypeLoc.html">LValueReferenceTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="lValueReferenceTypeLoc0"><pre>Matches lvalue reference types.
-
-Given:
- int *a;
- int &amp;b = *a;
- int &amp;&amp;c = 1;
- auto &amp;d = b;
- auto &amp;&amp;e = c;
- auto &amp;&amp;f = 2;
- int g = 5;
-
-lValueReferenceType() matches the types of b, d, and e. e is
-matched since the type is deduced as int&amp; by reference collapsing rules.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('memberPointerTypeLoc0')"><a name="memberPointerTypeLoc0Anchor">memberPointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="memberPointerTypeLoc0"><pre>Matches member pointer types.
-Given
- struct A { int i; }
- A::* ptr = A::i;
-memberPointerType()
- matches "A::* ptr"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('parenTypeLoc0')"><a name="parenTypeLoc0Anchor">parenTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenTypeLoc.html">ParenTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="parenTypeLoc0"><pre>Matches ParenType nodes.
-
-Given
- int (*ptr_to_array)[4];
- int *array_of_ptrs[4];
-
-varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
-array_of_ptrs.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointerTypeLoc0')"><a name="pointerTypeLoc0Anchor">pointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="pointerTypeLoc0"><pre>Matches pointer types.
-
-Given
- int *a;
- int &amp;b = *a;
- int c = 5;
-pointerType()
- matches "int *a"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('rValueReferenceTypeLoc0')"><a name="rValueReferenceTypeLoc0Anchor">rValueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceTypeLoc.html">RValueReferenceTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="rValueReferenceTypeLoc0"><pre>Matches rvalue reference types.
-
-Given:
- int *a;
- int &amp;b = *a;
- int &amp;&amp;c = 1;
- auto &amp;d = b;
- auto &amp;&amp;e = c;
- auto &amp;&amp;f = 2;
- int g = 5;
-
-rValueReferenceType() matches the types of c and f. e is not
-matched as it is deduced to int&amp; by reference collapsing rules.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('recordTypeLoc0')"><a name="recordTypeLoc0Anchor">recordTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordTypeLoc.html">RecordTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="recordTypeLoc0"><pre>Matches record types (e.g. structs, classes).
-
-Given
- class C {};
- struct S {};
-
- C c;
- S s;
-
-recordType() matches the type of the variable declarations of both c
-and s.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('referenceTypeLoc0')"><a name="referenceTypeLoc0Anchor">referenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches both lvalue and rvalue reference types.
-
-Given
- int *a;
- int &amp;b = *a;
- int &amp;&amp;c = 1;
- auto &amp;d = b;
- auto &amp;&amp;e = c;
- auto &amp;&amp;f = 2;
- int g = 5;
-
-referenceType() matches the types of b, c, d, e, and f.
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('templateSpecializationTypeLoc0')"><a name="templateSpecializationTypeLoc0Anchor">templateSpecializationTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationTypeLoc.html">TemplateSpecializationTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="templateSpecializationTypeLoc0"><pre>Matches template specialization types.
-
-Given
- template &lt;typename T&gt;
- class C { };
-
- template class C&lt;int&gt;; A
- C&lt;char&gt; var; B
-
-templateSpecializationType() matches the type of the explicit
-instantiation in A and the type of the variable declaration in B.
-</pre></td></tr>
-
-
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('typedefTypeLoc0')"><a name="typedefTypeLoc0Anchor">typedefTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefTypeLoc.html">TypedefTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="typedefTypeLoc0"><pre>Matches typedef types.
-
-Given
- typedef int X;
-typedefType()
- matches "typedef int X"
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('variableArrayTypeLoc0')"><a name="variableArrayTypeLoc0Anchor">variableArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayTypeLoc.html">VariableArrayTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="variableArrayTypeLoc0"><pre>Matches C arrays with a specified size that is not an
-integer-constant-expression.
-
-Given
- void f() {
- int a[] = { 2, 3 }
- int b[42];
- int c[a[0]];
-variableArrayType()
- matches "int c[a[0]]"
-</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('arrayType0')"><a name="arrayType0Anchor">arrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="arrayType0"><pre>Matches all kinds of arrays.
@@ -1381,6 +1241,16 @@ typedefType()
</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('unaryTransformType0')"><a name="unaryTransformType0Anchor">unaryTransformType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryTransformType.html">UnaryTransformType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryTransformType0"><pre>Matches types nodes representing unary type transformations.
+
+Given:
+ typedef __underlying_type(T) type;
+unaryTransformType()
+ matches "__underlying_type(T)"
+</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('variableArrayType0')"><a name="variableArrayType0Anchor">variableArrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="variableArrayType0"><pre>Matches C arrays with a specified size that is not an
integer-constant-expression.
@@ -1411,14 +1281,14 @@ which allow users to create more powerful match expressions.</p>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_NARROWING_MATCHERS -->
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('allOf0')"><a name="allOf0Anchor">allOf</a></td><td>Matcher&lt;*&gt; P1, Matcher&lt;*&gt; P2</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('allOf0')"><a name="allOf0Anchor">allOf</a></td><td>Matcher&lt;*&gt;, ..., Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="allOf0"><pre>Matches if all given matchers match.
Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('anyOf0')"><a name="anyOf0Anchor">anyOf</a></td><td>Matcher&lt;*&gt; P1, Matcher&lt;*&gt; P2</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('anyOf0')"><a name="anyOf0Anchor">anyOf</a></td><td>Matcher&lt;*&gt;, ..., Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="anyOf0"><pre>Matches if any of the given matchers matches.
Usable as: Any Matcher
@@ -1472,6 +1342,16 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('argumentCountIs1')"><a name="argumentCountIs1Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>&gt;</td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches a constructor declaration that has been implicitly added
by the compiler (eg. implicit defaultcopy constructors).
@@ -1479,7 +1359,7 @@ by the compiler (eg. implicit defaultcopy constructors).
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt;</td><td class="name" onclick="toggle('isWritten0')"><a name="isWritten0Anchor">isWritten</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isWritten0"><pre>Matches a contructor initializer if it is explicitly written in
+<tr><td colspan="4" class="doc" id="isWritten0"><pre>Matches a constructor initializer if it is explicitly written in
code (as opposed to implicitly added by the compiler).
Given
@@ -1513,6 +1393,19 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOpe
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
+
+Given
+struct A {
+ void foo() const;
+ void bar();
+};
+
+methodDecl(isConst()) matches A::foo() but not A::bar()
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isOverride0')"><a name="isOverride0Anchor">isOverride</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isOverride0"><pre>Matches if the given method declaration overrides another method.
@@ -1665,6 +1558,29 @@ declCountIs(2)
</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('equalsBoundNode1')"><a name="equalsBoundNode1Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode1"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</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('equalsNode0')"><a name="equalsNode0Anchor">equalsNode</a></td><td>Decl* Other</td></tr>
<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node.
@@ -1868,6 +1784,29 @@ callExpr(on(hasType(asString("class Y *"))))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('equalsBoundNode3')"><a name="equalsBoundNode3Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode3"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasLocalQualifiers0')"><a name="hasLocalQualifiers0Anchor">hasLocalQualifiers</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasLocalQualifiers0"><pre>Matches QualType nodes that have local CV-qualifiers attached to
the node, not hidden within a typedef.
@@ -1912,6 +1851,29 @@ matches "a(int)", "b(long)", but not "c(double)".
</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('equalsBoundNode0')"><a name="equalsBoundNode0Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode0"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</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('equalsNode1')"><a name="equalsNode1Anchor">equalsNode</a></td><td>Stmt* Other</td></tr>
<tr><td colspan="4" class="doc" id="equalsNode1"><pre>Matches if a node equals another node.
@@ -1935,6 +1897,29 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDec
</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('equalsBoundNode2')"><a name="equalsBoundNode2Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode2"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt;</td><td class="name" onclick="toggle('ofKind0')"><a name="ofKind0Anchor">ofKind</a></td><td>UnaryExprOrTypeTrait Kind</td></tr>
<tr><td colspan="4" class="doc" id="ofKind0"><pre>Matches unary expressions of a certain kind.
@@ -2022,7 +2007,7 @@ match expressions.</p>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_TRAVERSAL_MATCHERS -->
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('eachOf0')"><a name="eachOf0Anchor">eachOf</a></td><td>Matcher&lt;*&gt; P1, Matcher&lt;*&gt; P2</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('eachOf0')"><a name="eachOf0Anchor">eachOf</a></td><td>Matcher&lt;*&gt;, ..., Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="eachOf0"><pre>Matches if any of the given matchers matches.
Unlike anyOf, eachOf will generate a match result for each
@@ -2041,22 +2026,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('findAll0')"><a name="findAll0Anchor">findAll</a></td><td>Matcher&lt;T&gt; Matcher</td></tr>
-<tr><td colspan="4" class="doc" id="findAll0"><pre>Matches if the node or any descendant matches.
-
-Generates results for each match.
-
-For example, in:
- class A { class B {}; class C {}; };
-The matcher:
- recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
-will generate results for A, B and C.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher&lt;ChildT&gt; ChildMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
provided matcher.
@@ -2074,7 +2044,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('forEachDescendant0')"><a name="forEachDescendant0Anchor">forEachDescendant</a></td><td>Matcher&lt;DescendantT&gt; DescendantMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('forEachDescendant0')"><a name="forEachDescendant0Anchor">forEachDescendant</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="forEachDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
provided matcher.
@@ -2098,7 +2068,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('has0')"><a name="has0Anchor">has</a></td><td>Matcher&lt;ChildT&gt; ChildMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('has0')"><a name="has0Anchor">has</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="has0"><pre>Matches AST nodes that have child AST nodes that match the
provided matcher.
@@ -2113,7 +2083,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasAncestor0')"><a name="hasAncestor0Anchor">hasAncestor</a></td><td>Matcher&lt;AncestorT&gt; AncestorMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasAncestor0')"><a name="hasAncestor0Anchor">hasAncestor</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="hasAncestor0"><pre>Matches AST nodes that have an ancestor that matches the provided
matcher.
@@ -2126,7 +2096,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasDescendant0')"><a name="hasDescendant0Anchor">hasDescendant</a></td><td>Matcher&lt;DescendantT&gt; DescendantMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasDescendant0')"><a name="hasDescendant0Anchor">hasDescendant</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="hasDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
provided matcher.
@@ -2142,7 +2112,7 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasParent0')"><a name="hasParent0Anchor">hasParent</a></td><td>Matcher&lt;ParentT&gt; ParentMatcher</td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasParent0')"><a name="hasParent0Anchor">hasParent</a></td><td>Matcher&lt;*&gt;</td></tr>
<tr><td colspan="4" class="doc" id="hasParent0"><pre>Matches AST nodes that have a parent that matches the provided
matcher.
@@ -2177,8 +2147,8 @@ arraySubscriptExpression(hasIndex(integerLiteral()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element
type.
Given
@@ -2192,8 +2162,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayT
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;</td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;</td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element
type.
Given
@@ -2271,8 +2241,8 @@ Example matches b (matcher = binaryOperator(hasRHS()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -2287,8 +2257,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -2303,17 +2273,65 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasAnyArgument1')"><a name="hasAnyArgument1Anchor">hasAnyArgument</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyArgument1"><pre>Matches any argument of a call expression or a constructor call
+expression.
+
+Given
+ void x(int, int, int) { int y; x(1, y, 42); }
+callExpr(hasAnyArgument(declRefExpr()))
+ matches x(1, y, 42)
+with hasAnyArgument(...)
+ matching y
+
+FIXME: Currently this will ignore parentheses and implicit casts on
+the argument before applying the inner matcher. We'll want to remove
+this to allow for greater control by the user once ignoreImplicit()
+has been implemented.
+</pre></td></tr>
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasArgument1')"><a name="hasArgument1Anchor">hasArgument</a></td><td>unsigned N, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument1"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration12')"><a name="hasDeclaration12Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration12"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>&gt;</td><td class="name" onclick="toggle('forEachConstructorInitializer0')"><a name="forEachConstructorInitializer0Anchor">forEachConstructorInitializer</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachConstructorInitializer0"><pre>Matches each constructor initializer in a constructor definition.
+
+Given
+ class A { A() : i(42), j(42) {} int i; int j; };
+constructorDecl(forEachConstructorInitializer(forField(decl().bind("x"))))
+ will trigger two matches, binding for 'i' and 'j' respectively.
</pre></td></tr>
@@ -2375,7 +2393,7 @@ FIXME: Overload to allow directly matching types?
<tr><td colspan="4" class="doc" id="onImplicitObjectArgument0"><pre></pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;</td><td class="name" onclick="toggle('thisPointerType1')"><a name="thisPointerType1Anchor">thisPointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;</td><td class="name" onclick="toggle('thisPointerType1')"><a name="thisPointerType1Anchor">thisPointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="thisPointerType1"><pre>Overloaded to match the type's declaration.
</pre></td></tr>
@@ -2438,7 +2456,7 @@ match Base.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
given matcher.
@@ -2458,6 +2476,11 @@ callExpr(hasAnyArgument(declRefExpr()))
matches x(1, y, 42)
with hasAnyArgument(...)
matching y
+
+FIXME: Currently this will ignore parentheses and implicit casts on
+the argument before applying the inner matcher. We'll want to remove
+this to allow for greater control by the user once ignoreImplicit()
+has been implemented.
</pre></td></tr>
@@ -2471,17 +2494,38 @@ Example matches y in x(y)
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration4"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration13')"><a name="hasDeclaration13Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration13"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>&gt;</td><td class="name" onclick="toggle('hasCaseConstant0')"><a name="hasCaseConstant0Anchor">hasCaseConstant</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCaseConstant0"><pre>If the given case statement does not use the GNU case range
+extension, matches the constant given in the statement.
+
+Given
+ switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+caseStmt(hasCaseConstant(integerLiteral()))
+ matches "case 1:"
</pre></td></tr>
@@ -2523,8 +2567,8 @@ classTemplateSpecializationDecl(hasTemplateArgument(
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element
type.
Given
@@ -2538,8 +2582,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayT
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;</td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;</td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element
type.
Given
@@ -2591,6 +2635,30 @@ Example matches a
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration11')"><a name="hasDeclaration11Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration11"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;</td><td class="name" onclick="toggle('throughUsingDecl0')"><a name="throughUsingDecl0Anchor">throughUsingDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="throughUsingDecl0"><pre>Matches a DeclRefExpr that refers to a declaration through a
specific using shadow declaration.
@@ -2650,6 +2718,17 @@ declStmt(hasSingleDecl(anything()))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>&gt;</td><td class="name" onclick="toggle('hasTypeLoc0')"><a name="hasTypeLoc0Anchor">hasTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt; Inner</td></tr>
+<tr><td colspan="4" class="doc" id="hasTypeLoc0"><pre>Matches if the type location of the declarator decl's type matches
+the inner matcher.
+
+Given
+ int x;
+declaratorDecl(hasTypeLoc(loc(asString("int"))))
+ matches int x
+</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('hasDeclContext0')"><a name="hasDeclContext0Anchor">hasDeclContext</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclContext0"><pre>Matches declarations whose declaration context, interpreted as a
Decl, matches InnerMatcher.
@@ -2722,6 +2801,30 @@ declaration of d.
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration10')"><a name="hasDeclaration10Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration10"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>&gt;</td><td class="name" onclick="toggle('hasDestinationType0')"><a name="hasDestinationType0Anchor">hasDestinationType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDestinationType0"><pre>Matches casts whose destination type matches a given matcher.
@@ -2730,8 +2833,8 @@ actual casts "explicit" casts.)
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType2"><pre>Overloaded to match the declaration of the expression's or value
declaration's type.
In case of a value declaration (for example a variable declaration),
@@ -2906,7 +3009,7 @@ Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
Given
if (A* a = GetAPointer()) {}
-hasConditionVariableStatment(...)
+hasConditionVariableStatement(...)
matches 'A* a = GetAPointer()'.
</pre></td></tr>
@@ -2919,17 +3022,75 @@ FIXME: Unit test this matcher
</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('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration9')"><a name="hasDeclaration9Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration9"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration8')"><a name="hasDeclaration8Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration8"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</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('hasDeclaration7')"><a name="hasDeclaration7Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration7"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
</pre></td></tr>
@@ -2961,8 +3122,8 @@ memberExpr(member(hasName("first")))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -2977,8 +3138,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -3072,8 +3233,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenT
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -3088,8 +3249,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;</td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;</td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -3117,32 +3278,66 @@ declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration6')"><a name="hasDeclaration6Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration6"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('pointsTo1')"><a name="pointsTo1Anchor">pointsTo</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('pointsTo1')"><a name="pointsTo1Anchor">pointsTo</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="pointsTo1"><pre>Overloaded to match the pointee type's declaration.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('references1')"><a name="references1Anchor">references</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('references1')"><a name="references1Anchor">references</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="references1"><pre>Overloaded to match the referenced type's declaration.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -3157,8 +3352,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;</td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
-<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;</td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
Given
@@ -3185,6 +3380,43 @@ sizeof.
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>&gt;</td><td class="name" onclick="toggle('forEachSwitchCase0')"><a name="forEachSwitchCase0Anchor">forEachSwitchCase</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachSwitchCase0"><pre>Matches each case or default statement belonging to the given switch
+statement. This matcher may produce multiple matches.
+
+Given
+ switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
+ matches four times, with "c" binding each of "case 1:", "case 2:",
+"case 3:" and "case 4:", and "s" respectively binding "switch (1)",
+"switch (1)", "switch (2)" and "switch (2)".
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration4"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('refersToDeclaration0')"><a name="refersToDeclaration0Anchor">refersToDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="refersToDeclaration0"><pre>Matches a TemplateArgument that refers to a certain declaration.
@@ -3212,17 +3444,66 @@ classTemplateSpecializationDecl(hasAnyTemplateArgument(
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;T&gt;</td><td class="name" onclick="toggle('findAll0')"><a name="findAll0Anchor">findAll</a></td><td>Matcher&lt;T&gt; Matcher</td></tr>
+<tr><td colspan="4" class="doc" id="findAll0"><pre>Matches if the node or any descendant matches.
+
+Generates results for each match.
+
+For example, in:
+ class A { class B {}; class C {}; };
+The matcher:
+ recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
+will generate results for A, B and C.
+
+Usable as: Any Matcher
</pre></td></tr>
@@ -3233,16 +3514,26 @@ QualType-matcher matches.
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a type if the declaration of the type matches the given
-matcher.
+<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
-In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
-Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
-subtypes of clang::Type.
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
- Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
</pre></td></tr>
@@ -3264,6 +3555,30 @@ Example matches true (matcher = hasUnaryOperand(boolLiteral(equals(true))))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher&lt;T&gt; for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+FIXME: Add all node types for which this is matcher is usable due to
+getDecl().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyUsingShadowDecl0')"><a name="hasAnyUsingShadowDecl0Anchor">hasAnyUsingShadowDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyUsingShadowDecl0"><pre>Matches any using shadow declaration.
@@ -3286,8 +3601,8 @@ usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
matches using X::b but not using X::a </pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt;</td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType2"><pre>Overloaded to match the declaration of the expression's or value
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt;</td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value
declaration's type.
In case of a value declaration (for example a variable declaration),
diff --git a/docs/LibTooling.rst b/docs/LibTooling.rst
index a9c24c304545..505865606433 100644
--- a/docs/LibTooling.rst
+++ b/docs/LibTooling.rst
@@ -176,7 +176,7 @@ Builtin includes
Clang tools need their builtin headers and search for them the same way Clang
does. Thus, the default location to look for builtin headers is in a path
-``$(dirname /path/to/tool)/../lib/clang/3.3/include`` relative to the tool
+``$(dirname /path/to/tool)/../lib/clang/3.4/include`` relative to the tool
binary. This works out-of-the-box for tools running from llvm's toplevel
binary directory after building clang-headers, or if the tool is running from
the binary directory of a clang install next to the clang binary.
diff --git a/docs/Makefile b/docs/Makefile
index 2608046f1f85..a76ce024e73c 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -19,7 +19,12 @@ $(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
-e 's/@abs_srcdir@/./g' \
-e 's/@DOT@/dot/g' \
-e 's/@PACKAGE_VERSION@/mainline/' \
- -e 's/@abs_builddir@/./g' > $@
+ -e 's/@abs_builddir@/./g' \
+ -e 's/@enable_searchengine@/NO/g' \
+ -e 's/@searchengine_url@//g' \
+ -e 's/@enable_server_based_search@/NO/g' \
+ -e 's/@enable_external_search@/NO/g' \
+ -e 's/@extra_search_mappings@//g' > $@
endif
include $(CLANG_LEVEL)/Makefile
@@ -73,10 +78,10 @@ doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
regendoc:
$(Echo) Building doxygen documentation
- $(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
- $(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
- fi
+ $(Verb) $(RM) -rf $(PROJ_OBJ_DIR)/doxygen
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
+ $(Verb) sed -i "s/[$$]LatestRev[$$]/`svnversion $(PROJ_SRC_DIR)`/g" \
+ $(PROJ_OBJ_DIR)/doxygen/html/*.html
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
$(Echo) Packaging doxygen documentation
diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst
index 439acc47fa26..5fc7e745d19f 100644
--- a/docs/MemorySanitizer.rst
+++ b/docs/MemorySanitizer.rst
@@ -90,8 +90,16 @@ to disable uninitialized checks in a particular function.
MemorySanitizer may still instrument such functions to avoid false positives.
This attribute may not be
supported by other compilers, so we suggest to use it together with
-``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be
-lost if the function is inlined.
+``__has_feature(memory_sanitizer)``.
+
+Blacklist
+---------
+
+MemorySanitizer supports ``src`` and ``fun`` entity types in
+:doc:`SanitizerSpecialCaseList`, that can be used to relax MemorySanitizer
+checks for certain source files and functions. All "Use of uninitialized value"
+warnings will be suppressed and all values loaded from memory will be
+considered fully initialized.
Origin Tracking
===============
diff --git a/docs/Modules.rst b/docs/Modules.rst
index fdf597a5a926..9fb4c774874c 100644
--- a/docs/Modules.rst
+++ b/docs/Modules.rst
@@ -2,13 +2,13 @@
Modules
=======
+.. warning::
+ The functionality described on this page is supported for C and
+ Objective-C. C++ support is experimental.
+
.. contents::
:local:
-.. warning::
- The functionality described on this page is still experimental! Please
- try it out and send us bug reports!
-
Introduction
============
Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s):
@@ -106,24 +106,25 @@ Using Modules
=============
To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
-Import declaration
-------------------
-The most direct way to import a module is with an *import declaration*, which imports the named module:
+Objective-C Import declaration
+------------------------------
+Objective-C provides syntax for importing a module via an *@import declaration*, which imports the named module:
.. parsed-literal::
- import std;
+ @import std;
-The import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
+The @import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
.. parsed-literal::
- import std.io;
+ @import std.io;
Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope.
-.. warning::
- The import declaration syntax described here does not actually exist. Rather, it is a straw man proposal that may very well change when modules are discussed in the C and C++ committees. See the section `Includes as imports`_ to see how modules get imported today.
+At present, there is no C or C++ syntax for import declarations. Clang
+will track the modules proposal in the C++ committee. See the section
+`Includes as imports`_ to see how modules get imported today.
Includes as imports
-------------------
@@ -148,6 +149,8 @@ Module maps are specified as separate files (each named ``module.map``) alongsid
.. note::
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
+
+One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fmodule-maps`` option instead of the ``-fmodules`` option.
Compilation model
-----------------
@@ -165,6 +168,9 @@ Command-line parameters
``-fcxx-modules``
Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
+``-fmodule-maps``
+ Enable interpretation of module maps (EXPERIMENTAL). This option is implied by ``-fmodules``.
+
``-fmodules-cache-path=<directory>``
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
@@ -183,6 +189,15 @@ Command-line parameters
``-module-file-info <module file name>``
Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
+``-fmodules-decluse``
+ Enable checking of module ``use`` declarations.
+
+``-fmodule-name=module-id``
+ Consider a source file as a part of the given module.
+
+``-fmodule-map-file=<file>``
+ Load the given module map file if a header from its directory or one of its subdirectories is loaded.
+
Module Map Language
===================
@@ -231,8 +246,9 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
``config_macros`` ``export`` ``module``
``conflict`` ``framework`` ``requires``
- ``exclude`` ``header`` ``umbrella``
- ``explicit`` ``link``
+ ``exclude`` ``header`` ``private``
+ ``explicit`` ``link`` ``umbrella``
+ ``extern`` ``use``
Module map file
---------------
@@ -258,6 +274,7 @@ A module declaration describes a module, including the headers that contribute t
*module-declaration*:
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
+ ``extern`` ``module`` *module-id* *string-literal*
The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
@@ -286,10 +303,13 @@ Modules can have a number of different kinds of members, each of which is descri
*umbrella-dir-declaration*
*submodule-declaration*
*export-declaration*
+ *use-declaration*
*link-declaration*
*config-macros-declaration*
*conflict-declaration*
+An extern module references a module defined by the *module-id* in a file given by the *string-literal*. The file can be referenced either by an absolute path or by a path relative to the current map file.
+
Requires declaration
~~~~~~~~~~~~~~~~~~~~
A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module.
@@ -300,9 +320,12 @@ A *requires-declaration* specifies the requirements that an importing translatio
``requires`` *feature-list*
*feature-list*:
- *identifier* (',' *identifier*)*
+ *feature* (',' *feature*)*
+
+ *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 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 following features are defined:
@@ -360,6 +383,7 @@ A header declaration specifies that a particular header is associated with the e
*header-declaration*:
``umbrella``:sub:`opt` ``header`` *string-literal*
+ ``private`` ``header`` *string-literal*
``exclude`` ``header`` *string-literal*
A header declaration that does not contain ``exclude`` 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.
@@ -372,6 +396,8 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
``-Wincomplete-umbrella`` warning option to ask Clang to complain
about headers not covered by the umbrella header or the module map.
+A header with the ``private`` specifier may not be included from outside the module itself.
+
A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
@@ -521,6 +547,36 @@ 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).
+Use declaration
+~~~~~~~~~~~~~~~
+A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
+
+.. parsed-literal::
+
+ *use-declaration*:
+ ``use`` *module-id*
+
+**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
+
+.. parsed-literal::
+
+ module A {
+ header "a.h"
+ }
+
+ module B {
+ header "b.h"
+ }
+
+ module C {
+ header "c.h"
+ use B
+ }
+
+When compiling a source file that implements a module, use the option ``-fmodule-name=``module-id to indicate that the source file is logically part of that module.
+
+The compiler at present only applies restrictions to the module directly being built.
+
Link declaration
~~~~~~~~~~~~~~~~
A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
diff --git a/docs/ObjectiveCLiterals.rst b/docs/ObjectiveCLiterals.rst
index 92e4fb65cd29..8066d8f6bead 100644
--- a/docs/ObjectiveCLiterals.rst
+++ b/docs/ObjectiveCLiterals.rst
@@ -218,12 +218,6 @@ character data is valid. Passing ``NULL`` as the character pointer will
raise an exception at runtime. When possible, the compiler will reject
``NULL`` character pointers used in boxed expressions.
-Availability
-------------
-
-Boxed expressions will be available in clang 3.2. It is not currently
-available in any Apple compiler.
-
Container Literals
==================
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index e764a09d5363..ec0dbffed079 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,40 +1,56 @@
=======================
-Clang 3.3 Release Notes
+Clang 3.4 Release Notes
=======================
.. contents::
:local:
:depth: 2
-Written by the `LLVM Team <http://llvm.org/>`_
-
Introduction
============
This document contains the release notes for the Clang C/C++/Objective-C
-frontend, part of the LLVM Compiler Infrastructure, release 3.3. 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 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>`_.
-
-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 3.3?
+frontend, part of the LLVM Compiler Infrastructure, release 3.4. 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
+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 `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 3.4?
========================
Some of the major new features and improvements to Clang are listed
here. Generic improvements to Clang as a whole or to its underlying
-infrastructure are described first, followed by language-specific sections with
-improvements to Clang's support for those languages.
+infrastructure are described first, followed by language-specific
+sections with improvements to Clang's support for those languages.
+
+Last release which will build as C++98
+--------------------------------------
+
+This is expected to be the last release of Clang which compiles using a C++98
+toolchain. We expect to start using some C++11 features in Clang starting after
+this release. That said, we are committed to supporting a reasonable set of
+modern C++ toolchains as the host compiler on all of the platforms. This will
+at least include Visual Studio 2012 on Windows, and Clang 3.1 or GCC 4.7.x on
+Mac and Linux. The final set of compilers (and the C++11 features they support)
+is not set in stone, but we wanted users of Clang to have a heads up that the
+next release will involve a substantial change in the host toolchain
+requirements.
+
+Note that this change is part of a change for the entire LLVM project, not just
+Clang.
Major New Features
------------------
@@ -44,90 +60,210 @@ Improvements to Clang's diagnostics
Clang's diagnostics are constantly being improved to catch more issues,
explain them more clearly, and provide more accurate source information
-about them. The improvements since the 3.2 release include:
+about them. The improvements since the 3.3 release include:
+
+- -Wheader-guard warns on mismatches between the #ifndef and #define lines
+ in a header guard.
+
+ .. code-block:: c
+
+ #ifndef multiple
+ #define multi
+ #endif
+
+ returns
+ `warning: 'multiple' is used as a header guard here, followed by #define of a different macro [-Wheader-guard]`
+
+- -Wlogical-not-parentheses warns when a logical not ('!') only applies to the
+ left-hand side of a comparison. This warning is part of -Wparentheses.
+
+ .. code-block:: c++
+
+ int i1 = 0, i2 = 1;
+ bool ret;
+ ret = !i1 == i2;
+
+ returns
+ `warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses]`
+
+
+- Boolean increment, a deprecated feature, has own warning flag
+ -Wdeprecated-increment-bool, and is still part of -Wdeprecated.
+- Clang errors on builtin enum increments and decrements.
+
+ .. code-block:: c++
+
+ enum A { A1, A2 };
+ void test() {
+ A a;
+ a++;
+ }
+
+ returns
+ `error: must use 'enum' tag to refer to type 'A'`
+
+
+- -Wloop-analysis now warns on for-loops which have the same increment or
+ decrement in the loop header as the last statement in the loop.
+
+ .. code-block:: c
+
+ void foo(char *a, char *b, unsigned c) {
+ for (unsigned i = 0; i < c; ++i) {
+ a[i] = b[i];
+ ++i;
+ }
+ }
+
+ returns
+ `warning: variable 'i' is incremented both in the loop header and in the loop body [-Wloop-analysis]`
+
+- -Wuninitialized now performs checking across field initializers to detect
+ when one field in used uninitialized in another field initialization.
-Extended Identifiers: Unicode Support and Universal Character Names
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ .. code-block:: c++
-Clang 3.3 includes support for *extended identifiers* in C99 and C++.
-This feature allows identifiers to contain certain Unicode characters, as
-specified by the active language standard; these characters can be written
-directly in the source file using the UTF-8 encoding, or referred to using
-*universal character names* (``\u00E0``, ``\U000000E0``).
+ class A {
+ int x;
+ int y;
+ A() : x(y) {}
+ };
+
+ returns
+ `warning: field 'y' is uninitialized when used here [-Wuninitialized]`
+
+- Clang can detect initializer list use inside a macro and suggest parentheses
+ if possible to fix.
+- Many improvements to Clang's typo correction facilities, such as:
+
+ + Adding global namespace qualifiers so that corrections can refer to shadowed
+ or otherwise ambiguous or unreachable namespaces.
+ + Including accessible class members in the set of typo correction candidates,
+ so that corrections requiring a class name in the name specifier are now
+ possible.
+ + Allowing typo corrections that involve removing a name specifier.
+ + In some situations, correcting function names when a function was given the
+ wrong number of arguments, including situations where the original function
+ name was correct but was shadowed by a lexically closer function with the
+ same name yet took a different number of arguments.
+ + Offering typo suggestions for 'using' declarations.
+ + Providing better diagnostics and fixit suggestions in more situations when
+ a '->' was used instead of '.' or vice versa.
+ + Providing more relevant suggestions for typos followed by '.' or '='.
+ + Various performance improvements when searching for typo correction
+ candidates.
+
+- `LeakSanitizer <LeakSanitizer.html>`_ is an experimental memory leak detector
+ which can be combined with AddressSanitizer.
+
+New Compiler Flags
+------------------
+
+- Clang no longer special cases -O4 to enable lto. Explicitly pass -flto to
+ enable it.
+- Clang no longer fails on >= -O5. These flags are mapped to -O3 instead.
+- Command line "clang -O3 -flto a.c -c" and "clang -emit-llvm a.c -c"
+ are no longer equivalent.
+- Clang now errors on unknown -m flags (``-munknown-to-clang``),
+ unknown -f flags (``-funknown-to-clang``) and unknown
+ options (``-what-is-this``).
C Language Changes in Clang
---------------------------
+- Added new checked arithmetic builtins for security critical applications.
+
C++ Language Changes in Clang
-----------------------------
-- Clang now correctly implements language linkage for functions and variables.
- This means that, for example, it is now possible to overload static functions
- declared in an ``extern "C"`` context. For backwards compatibility, an alias
- with the unmangled name is still emitted if it is the only one and has the
- ``used`` attribute.
+- Fixed an ABI regression, introduced in Clang 3.2, which affected
+ member offsets for classes inheriting from certain classes with tail padding.
+ See PR16537.
+
+- Clang 3.4 supports the 2013-08-28 draft of the ISO WG21 SG10 feature test
+ macro recommendations. These aim to provide a portable method to determine
+ whether a compiler supports a language feature, much like Clang's
+ |has_feature macro|_.
+
+.. |has_feature macro| replace:: ``__has_feature`` macro
+.. _has_feature macro: LanguageExtensions.html#has-feature-and-has-extension
+
+C++1y Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+Clang 3.4 supports all the features in the current working draft of the
+upcoming C++ standard, provisionally named C++1y. Support for the following
+major new features has been added since Clang 3.3:
+
+- Generic lambdas and initialized lambda captures.
+- Deduced function return types (``auto f() { return 0; }``).
+- Generalized ``constexpr`` support (variable mutation and loops).
+- Variable templates and static data member templates.
+- Use of ``'`` as a digit separator in numeric literals.
+- Support for sized ``::operator delete`` functions.
+
+In addition, ``[[deprecated]]`` is now accepted as a synonym for Clang's
+existing ``deprecated`` attribute.
+
+Use ``-std=c++1y`` to enable C++1y mode.
+
+OpenCL C Language Changes in Clang
+----------------------------------
+
+- OpenCL C "long" now always has a size of 64 bit, and all OpenCL C
+ types are aligned as specified in the OpenCL C standard. Also,
+ "char" is now always signed.
Internal API Changes
--------------------
-These are major API changes that have happened since the 3.2 release of
+These are major API changes that have happened since the 3.3 release of
Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading.
-Value Casting
-^^^^^^^^^^^^^
-
-Certain type hierarchies (TypeLoc, CFGElement, ProgramPoint, and SVal) were
-misusing the llvm::cast machinery to perform undefined operations. Their APIs
-have been changed to use two member function templates that return values
-instead of pointers or references - "T castAs" and "Optional<T> getAs" (in the
-case of the TypeLoc hierarchy the latter is "T getAs" and you can use the
-boolean testability of a TypeLoc (or its 'validity') to verify that the cast
-succeeded). Essentially all previous 'cast' usage should be replaced with
-'castAs' and 'dyn_cast' should be replaced with 'getAs'. See r175462 for the
-first example of such a change along with many examples of how code was
-migrated to the new API.
-
-Storage Class
-^^^^^^^^^^^^^
-
-For each variable and function Clang used to keep the storage class as written
-in the source, the linkage and a semantic storage class. This was a bit
-redundant and the semantic storage class has been removed. The method
-getStorageClass now returns what is written in the source code for that decl.
-
-libclang
---------
-
-The clang_CXCursorSet_contains() function previously incorrectly returned 0
-if it contained a CXCursor, contrary to what the documentation stated. This
-has been fixed so that the function returns a non-zero value if the set
-contains a cursor. This is API breaking change, but matches the intended
-original behavior. Moreover, this also fixes the issue of an invalid CXCursorSet
-appearing to contain any CXCursor.
+Wide Character Types
+^^^^^^^^^^^^^^^^^^^^
+
+The ASTContext class now keeps track of two different types for wide character
+types: WCharTy and WideCharTy. WCharTy represents the built-in wchar_t type
+available in C++. WideCharTy is the type used for wide character literals; in
+C++ it is the same as WCharTy, but in C99, where wchar_t is a typedef, it is an
+integer type.
Static Analyzer
---------------
-The static analyzer (which contains additional code checking beyond compiler
-warnings) has improved significantly in both in the core analysis engine and
-also in the kinds of issues it can find.
+The static analyzer has been greatly improved. This impacts the overall analyzer quality and reduces a number of false positives.
+In particular, this release provides enhanced C++ support, reasoning about initializer lists, zeroing constructors, noreturn destructors and modeling of destructor calls on calls to delete.
-Core Analysis Improvements
-==========================
+Clang Format
+------------
+
+Clang now includes a new tool ``clang-format`` which can be used to
+automatically format C, C++ and Objective-C source code. ``clang-format``
+automatically chooses linebreaks and indentation and can be easily integrated
+into editors, IDEs and version control systems. It supports several pre-defined
+styles as well as precise style control using a multitude of formatting
+options. ``clang-format`` itself is just a thin wrapper around a library which
+can also be used directly from code refactoring and code translation tools.
+More information can be found on `Clang Format's
+site <http://clang.llvm.org/docs/ClangFormat.html>`_.
+
+Windows Support
+---------------
-- Support for interprocedural reasoning about constructors and destructors.
-- New false positive suppression mechanisms that reduced the number of false
- null pointer dereference warnings due to interprocedural analysis.
-- Major performance enhancements to speed up interprocedural analysis
+- `clang-cl <UsersManual.html#clang-cl>`_ provides a new driver mode that is
+ designed for compatibility with Visual Studio's compiler, cl.exe. This driver
+ mode makes Clang accept the same kind of command-line options as cl.exe. The
+ installer will attempt to expose clang-cl in any Visual Studio installations
+ on the system as a Platform Toolset, e.g. "LLVM-vs2012". clang-cl targets the
+ Microsoft ABI by default. Please note that this driver mode and compatibility
+ with the MS ABI is highly experimental.
-New Issues Found
-================
+Python Binding Changes
+----------------------
-- New memory error checks such as use-after-free with C++ 'delete'.
-- Detection of mismatched allocators and deallocators (e.g., using 'new' with
- 'free()', 'malloc()' with 'delete').
-- Additional checks for misuses of Apple Foundation framework collection APIs.
+The following methods have been added:
Significant Known Problems
==========================
@@ -135,11 +271,13 @@ Significant Known Problems
Additional Information
======================
-A wide variety of additional information is available on the `Clang web page
-<http://clang.llvm.org/>`_. The web page contains versions of the API
-documentation which are up-to-date with the Subversion version of the source
-code. You can access versions of these documents specific to this release by
-going into the "``clang/docs/``" directory in the Clang tree.
+A wide variety of additional information is available on the `Clang web
+page <http://clang.llvm.org/>`_. The web page contains versions of the
+API documentation which are up-to-date with the Subversion revision of
+the source code. You can access versions of these documents specific to
+this release by going into the "``clang/docs/``" directory in the Clang
+tree.
-If you have any questions or comments about Clang, please feel free to contact
-us via the `mailing list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
+If you have any questions or comments about Clang, please feel free to
+contact us via the `mailing
+list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
diff --git a/docs/SanitizerSpecialCaseList.rst b/docs/SanitizerSpecialCaseList.rst
new file mode 100644
index 000000000000..8f4727c2fbc3
--- /dev/null
+++ b/docs/SanitizerSpecialCaseList.rst
@@ -0,0 +1,79 @@
+===========================
+Sanitizer special case list
+===========================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+This document describes the way to disable or alter the behavior of
+sanitizer tools for certain source-level entities by providing a special
+file at compile-time.
+
+Goal and usage
+==============
+
+User of sanitizer tools, such as :doc:`AddressSanitizer`, :doc:`ThreadSanitizer`
+or :doc:`MemorySanitizer` may want to disable or alter some checks for
+certain source-level entities to:
+
+* speedup hot function, which is known to be correct;
+* ignore a function that does some low-level magic (e.g. walks through the
+ thread stack, bypassing the frame boundaries);
+* ignore a known problem.
+
+To achieve this, user may create a file listing the entities he wants to
+ignore, and pass it to clang at compile-time using
+``-fsanitize-blacklist`` flag. See :doc:`UsersManual` for details.
+
+Example
+=======
+
+.. code-block:: bash
+
+ $ cat foo.c
+ #include <stdlib.h>
+ void bad_foo() {
+ int *a = (int*)malloc(40);
+ a[10] = 1;
+ }
+ int main() { bad_foo(); }
+ $ cat blacklist.txt
+ # Ignore reports from bad_foo function.
+ fun:bad_foo
+ $ clang -fsanitize=address foo.c ; ./a.out
+ # AddressSanitizer prints an error report.
+ $ clang -fsanitize=address -fsanitize-blacklist=blacklist.txt foo.c ; ./a.out
+ # No error report here.
+
+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.
+
+.. code-block:: bash
+
+ # Lines starting with # are ignored.
+ # Turn off checks for the source file (use absolute path or path relative
+ # to the current working directory):
+ src:/path/to/source/file.c
+ # Turn off checks for a particular functions (use mangled names):
+ fun:MyFooBar
+ fun:_Z8MyFooBarv
+ # Extended regular expressions are supported:
+ fun:bad_(foo|bar)
+ src:bad_source[1-9].c
+ # Shell like usage of * is supported (* is treated as .*):
+ src:bad/sources/*
+ fun:*BadFunction*
+ # Specific sanitizer tools may introduce categories.
+ src:/special/path/*=special_sources
diff --git a/docs/ThreadSanitizer.rst b/docs/ThreadSanitizer.rst
index 5e5ee48f7f44..194ad4a8efb0 100644
--- a/docs/ThreadSanitizer.rst
+++ b/docs/ThreadSanitizer.rst
@@ -91,11 +91,21 @@ Some code should not be instrumented by ThreadSanitizer.
One may use the function attribute
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
-ThreadSanitizer may still instrument such functions to avoid false positives.
+ThreadSanitizer still instruments such functions to avoid false positives and
+provide meaningful stack traces.
This attribute may not be
supported by other compilers, so we suggest to use it together with
-``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be
-lost if the function is inlined.
+``__has_feature(thread_sanitizer)``.
+
+Blacklist
+---------
+
+ThreadSanitizer supports ``src`` and ``fun`` entity types in
+:doc:`SanitizerSpecialCaseList`, that can be used to suppress data race reports in
+the specified source files or functions. Unlike functions marked with
+:ref:`no_sanitize_thread <langext-thread_sanitizer>` attribute,
+blacklisted functions are not instrumented at all. This can lead to false positives
+due to missed synchronization via atomic operations and missed stack frames in reports.
Limitations
-----------
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 3dc07aba9013..96d65a47d1b8 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -44,6 +44,8 @@ as to improve functionality through Clang-specific features. The Clang
driver and language features are intentionally designed to be as
compatible with the GNU GCC compiler as reasonably possible, easing
migration from GCC to Clang. In most cases, code "just works".
+Clang also provides an alternative driver, :ref:`clang-cl`, that is designed
+to be compatible with the Visual C++ compiler, cl.exe.
In addition to language specific features, Clang has a variety of
features that depend on what CPU architecture or operating system is
@@ -235,6 +237,11 @@ output format of the diagnostics that it generates.
^
//
+**-fansi-escape-codes**
+ Controls whether ANSI escape codes are used instead of the Windows Console
+ API to output colored diagnostics. This option is only used on Windows and
+ defaults to off.
+
.. option:: -fdiagnostics-format=clang/msvc/vi
Changes diagnostic output format to better match IDEs and command line tools.
@@ -422,7 +429,7 @@ output format of the diagnostics that it generates.
map<
[...],
map<
- [float != float],
+ [float != double],
[...]>>>
.. _cl_diag_warning_groups:
@@ -853,7 +860,7 @@ Controlling Code Generation
Clang provides a number of ways to control code generation. The options
are listed below.
-**-fsanitize=check1,check2,...**
+**-f[no-]sanitize=check1,check2,...**
Turn on runtime checks for various forms of undefined or suspicious
behavior.
@@ -889,13 +896,14 @@ are listed below.
includes all of the checks listed below other than
``unsigned-integer-overflow``.
- ``-fsanitize=undefined-trap``: This includes all sanitizers
+ - ``-fsanitize=undefined-trap``: This includes all sanitizers
included by ``-fsanitize=undefined``, except those that require
- runtime support. This group of sanitizers are generally used
- in conjunction with the ``-fsanitize-undefined-trap-on-error``
- flag, which causes traps to be emitted, rather than calls to
- runtime libraries. This includes all of the checks listed below
- other than ``unsigned-integer-overflow`` and ``vptr``.
+ runtime support. This group of sanitizers is intended to be
+ used in conjunction with the ``-fsanitize-undefined-trap-on-error``
+ flag. This includes all of the checks listed below other than
+ ``unsigned-integer-overflow`` and ``vptr``.
+ - ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
+ flow analysis.
The following more fine-grained checks are also available:
@@ -913,6 +921,8 @@ are listed below.
destination.
- ``-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).
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
- ``-fsanitize=null``: Use of a null pointer or creation of a null
reference.
@@ -941,6 +951,15 @@ are listed below.
it is of the wrong dynamic type, or that its lifetime has not
begun or has ended. Incompatible with ``-fno-rtti``.
+ You can turn off or modify checks for certain source files, functions
+ or even variables by providing a special file:
+
+ - ``-fsanitize-blacklist=/path/to/blacklist/file``: disable or modify
+ sanitizer checks for objects listed in the file. See
+ :doc:`SanitizerSpecialCaseList` for file format description.
+ - ``-fno-sanitize-blacklist``: don't use blacklist file, if it was
+ specified earlier in the command line.
+
Experimental features of AddressSanitizer (not ready for widespread
use, require explicit ``-fsanitize=address``):
@@ -958,10 +977,31 @@ are listed below.
uninitialized bits came from. Slows down execution by additional
1.5x-2x.
+ Extra features of UndefinedBehaviorSanitizer:
+
+ - ``-fno-sanitize-recover``: By default, after a sanitizer diagnoses
+ an issue, it will attempt to continue executing the program if there
+ is a reasonable behavior it can give to the faulting operation. This
+ option causes the program to abort instead.
+ - ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted
+ rather than calls to runtime libraries when a problem is detected.
+ This option is intended for use in cases where the sanitizer runtime
+ cannot be used (for instance, when building libc or a kernel module).
+ This is only compatible with the sanitizers in the ``undefined-trap``
+ group.
+
The ``-fsanitize=`` argument must also be provided when linking, in
- order to link to the appropriate runtime library. It is not possible
- to combine the ``-fsanitize=address`` and ``-fsanitize=thread``
- checkers in the same program.
+ order to link to the appropriate runtime library. When using
+ ``-fsanitize=vptr`` (or a group that includes it, such as
+ ``-fsanitize=undefined``) with a C++ program, the link must be
+ performed by ``clang++``, not ``clang``, in order to link against the
+ C++-specific parts of the runtime library.
+
+ It is not possible to combine more than one of the ``-fsanitize=address``,
+ ``-fsanitize=thread``, and ``-fsanitize=memory`` checkers in the same
+ program. The ``-fsanitize=undefined`` checks can be combined with other
+ sanitizers.
+
**-f[no-]address-sanitizer**
Deprecated synonym for :ref:`-f[no-]sanitize=address
<opt_fsanitize_address>`.
@@ -1007,6 +1047,26 @@ are listed below.
efficient model can be used. The TLS model can be overridden per
variable using the ``tls_model`` attribute.
+.. option:: -mhwdiv=[values]
+
+ Select the ARM modes (arm or thumb) that support hardware division
+ instructions.
+
+ Valid values are: ``arm``, ``thumb`` and ``arm,thumb``.
+ This option is used to indicate which mode (arm or thumb) supports
+ hardware division instructions. This only applies to the ARM
+ architecture.
+
+.. option:: -m[no-]crc
+
+ Enable or disable CRC instructions.
+
+ This option is used to indicate whether CRC instructions are to
+ be generated. This only applies to the ARM architecture.
+
+ CRC instructions are enabled by default on ARMv8.
+
+
Controlling Size of Debug Information
-------------------------------------
@@ -1178,30 +1238,40 @@ Microsoft extensions
--------------------
clang has some experimental support for extensions from Microsoft Visual
-C++; to enable it, use the -fms-extensions command-line option. This is
-the default for Windows targets. Note that the support is incomplete;
-enabling Microsoft extensions will silently drop certain constructs
-(including ``__declspec`` and Microsoft-style asm statements).
-
-clang has a -fms-compatibility flag that makes clang accept enough
-invalid C++ to be able to parse most Microsoft headers. This flag is
-enabled by default for Windows targets.
-
--fdelayed-template-parsing lets clang delay all template instantiation
-until the end of a translation unit. This flag is enabled by default for
-Windows targets.
+C++; to enable it, use the ``-fms-extensions`` command-line option. This is
+the default for Windows targets. Note that the support is incomplete.
+Some constructs such as ``dllexport`` on classes are ignored with a warning,
+and others such as `Microsoft IDL annotations
+<http://msdn.microsoft.com/en-us/library/8tesw2eh.aspx>`_ are silently
+ignored.
+
+clang has a ``-fms-compatibility`` flag that makes clang accept enough
+invalid C++ to be able to parse most Microsoft headers. For example, it
+allows `unqualified lookup of dependent base class members
+<http://clang.llvm.org/compatibility.html#dep_lookup_bases>`_, which is
+a common compatibility issue with clang. This flag is enabled by default
+for Windows targets.
+
+``-fdelayed-template-parsing`` lets clang delay parsing of function template
+definitions until the end of a translation unit. This flag is enabled by
+default for Windows targets.
- clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to
- 1300 which is the same as Visual C/C++ 2003. Any number is supported
+ 1700 which is the same as Visual C/C++ 2012. Any number is supported
and can greatly affect what Windows SDK and c++stdlib headers clang
- can compile. This option will be removed when clang supports the full
- set of MS extensions required for these headers.
+ can compile.
- clang does not support the Microsoft extension where anonymous record
members can be declared using user defined typedefs.
-- clang supports the Microsoft "#pragma pack" feature for controlling
+- clang supports the Microsoft ``#pragma pack`` feature for controlling
record layout. GCC also contains support for this feature, however
where MSVC and GCC are incompatible clang follows the MSVC
definition.
+- clang supports the Microsoft ``#pragma comment(lib, "foo.lib")`` feature for
+ automatically linking against the specified library. Currently this feature
+ only works with the Visual C++ linker.
+- clang supports the Microsoft ``#pragma comment(linker, "/flag:foo")`` feature
+ for adding linker flags to COFF object files. The user is responsible for
+ ensuring that the linker understands the flags.
- clang defaults to C++11 for Windows targets.
.. _cxx:
@@ -1210,8 +1280,8 @@ C++ Language Features
=====================
clang fully implements all of standard C++98 except for exported
-templates (which were removed in C++11), and `many C++11
-features <http://clang.llvm.org/cxx_status.html>`_ are also implemented.
+templates (which were removed in C++11), and all of standard C++11
+and the current draft standard for C++1y.
Controlling implementation limits
---------------------------------
@@ -1229,7 +1299,12 @@ Controlling implementation limits
.. option:: -ftemplate-depth=N
Sets the limit for recursively nested template instantiations to N. The
- default is 1024.
+ default is 256.
+
+.. option:: -foperator-arrow-depth=N
+
+ Sets the limit for iterative calls to 'operator->' functions to N. The
+ default is 256.
.. _objc:
@@ -1258,8 +1333,8 @@ Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested
to correctly compile many large C, C++, Objective-C, and Objective-C++
codebases.
-On ``x86_64-mingw32``, passing i128(by value) is incompatible to Microsoft
-x64 calling conversion. You might need to tweak
+On ``x86_64-mingw32``, passing i128(by value) is incompatible with the
+Microsoft x64 calling conversion. You might need to tweak
``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
ARM
@@ -1271,11 +1346,19 @@ C++, Objective-C, and Objective-C++ codebases. Clang only supports a
limited number of ARM architectures. It does not yet fully support
ARMv5, for example.
+PowerPC
+^^^^^^^
+
+The support for PowerPC (especially PowerPC64) is considered stable
+on Linux and FreeBSD: it has been tested to correctly compile many
+large C and C++ codebases. PowerPC (32bit) is still missing certain
+features (e.g. PIC code on ELF platforms).
+
Other platforms
^^^^^^^^^^^^^^^
-clang currently contains some support for PPC and Sparc; however,
-significant pieces of code generation are still missing, and they
+clang currently contains some support for other architectures (e.g. Sparc);
+however, significant pieces of code generation are still missing, and they
haven't undergone significant testing.
clang contains limited support for the MSP430 embedded processor, but
@@ -1302,9 +1385,10 @@ None
Windows
^^^^^^^
-Experimental supports are on Cygming.
+Clang has experimental support for targeting "Cygming" (Cygwin / MinGW)
+platforms.
-See also `Microsoft Extensions <c_ms>`.
+See also :ref:`Microsoft Extensions <c_ms>`.
Cygwin
""""""
@@ -1349,3 +1433,111 @@ Clang expects the GCC executable "gcc.exe" compiled for
`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
``x86_64-w64-mingw32``.
+
+.. _clang-cl:
+
+clang-cl
+========
+
+clang-cl is an alternative command-line interface to Clang driver, designed for
+compatibility with the Visual C++ compiler, cl.exe.
+
+To enable clang-cl to find system headers, libraries, and the linker when run
+from the command-line, it should be executed inside a Visual Studio Native Tools
+Command Prompt or a regular Command Prompt where the environment has been set
+up using e.g. `vcvars32.bat <http://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx>`_.
+
+clang-cl can also be used from inside Visual Studio by using an LLVM Platform
+Toolset.
+
+Command-Line Options
+--------------------
+
+To be compatible with cl.exe, clang-cl supports most of the same command-line
+options. Those options can start with either ``/`` or ``-``. It also supports
+some of Clang's core options, such as the ``-W`` options.
+
+Options that are known to clang-cl, but not currently supported, are ignored
+with a warning. For example:
+
+ ::
+
+ clang-cl.exe: warning: argument unused during compilation: '/Zi'
+
+To suppress warnings about unused arguments, use the ``-Qunused-arguments`` option.
+
+Options that are not known to clang-cl will cause errors. If they are spelled with a
+leading ``/``, they will be mistaken for a filename:
+
+ ::
+
+ clang-cl.exe: error: no such file or directory: '/foobar'
+
+Please `file a bug <http://llvm.org/bugs/enter_bug.cgi?product=clang&component=Driver>`_
+for any valid cl.exe flags that clang-cl does not understand.
+
+Execute ``clang-cl /?`` to see a list of supported options:
+
+ ::
+
+ /? Display available options
+ /c Compile only
+ /D <macro[=value]> Define macro
+ /fallback Fall back to cl.exe if clang-cl fails to compile
+ /FA Output assembly code file during compilation
+ /Fa<file or directory> Output assembly code to this file during compilation
+ /Fe<file or directory> Set output executable file or directory (ends in / or \)
+ /FI<value> Include file before parsing
+ /Fo<file or directory> Set output object file, or directory (ends in / or \)
+ /GF- Disable string pooling
+ /GR- Disable RTTI
+ /GR Enable RTTI
+ /help Display available options
+ /I <dir> Add directory to include search path
+ /J Make char type unsigned
+ /LDd Create debug DLL
+ /LD Create DLL
+ /link <options> Forward options to the linker
+ /MDd Use DLL debug run-time
+ /MD Use DLL run-time
+ /MTd Use static debug run-time
+ /MT Use static run-time
+ /Ob0 Disable inlining
+ /Od Disable optimization
+ /Oi- Disable use of builtin functions
+ /Oi Enable use of builtin functions
+ /Os Optimize for size
+ /Ot Optimize for speed
+ /Ox Maximum optimization
+ /Oy- Disable frame pointer omission
+ /Oy Enable frame pointer omission
+ /O<n> Optimization level
+ /P Only run the preprocessor
+ /showIncludes Print info about included files to stderr
+ /TC Treat all source files as C
+ /Tc <filename> Specify a C source file
+ /TP Treat all source files as C++
+ /Tp <filename> Specify a C++ source file
+ /U <macro> Undefine macro
+ /W0 Disable all warnings
+ /W1 Enable -Wall
+ /W2 Enable -Wall
+ /W3 Enable -Wall
+ /W4 Enable -Wall
+ /Wall Enable -Wall
+ /WX- Do not treat warnings as errors
+ /WX Treat warnings as errors
+ /w Disable all warnings
+ /Zs Syntax-check only
+
+The /fallback Option
+^^^^^^^^^^^^^^^^^^^^
+
+When clang-cl is run with the ``/fallback`` option, it will first try to
+compile files itself. For any file that it fails to compile, it will fall back
+and try to compile the file by invoking cl.exe.
+
+This option is intended to be used as a temporary means to build projects where
+clang-cl cannot successfully compile all the files. clang-cl may fail to compile
+a file either because it cannot generate code for some C++ feature, or because
+it cannot parse some Microsoft language extension.
diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst
index f8e6f827c1be..14d6ae4c4c91 100644
--- a/docs/analyzer/DebugChecks.rst
+++ b/docs/analyzer/DebugChecks.rst
@@ -30,6 +30,10 @@ using a 'dot' format viewer (such as Graphviz on OS X) instead.
- debug.DumpLiveVars: Show the results of live variable analysis for each
top-level function being analyzed.
+- debug.ViewExplodedGraph: Show the Exploded Graphs generated for the
+ analysis of different functions in the input translation unit. When there
+ are several functions analyzed, display one graph per function. Beware
+ that these graphs may grow very large, even for small functions.
Path Tracking
=============
@@ -121,6 +125,19 @@ ExprInspection checks
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
}
+- void clang_analyzer_warnIfReached();
+
+ Generate a warning if this line of code gets reached by the analyzer.
+
+ Example usage::
+
+ if (true) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+ else {
+ clang_analyzer_warnIfReached(); // no-warning
+ }
+
Statistics
==========
diff --git a/docs/analyzer/IPA.txt b/docs/analyzer/IPA.txt
index 01e73cec7ff0..14da71e09030 100644
--- a/docs/analyzer/IPA.txt
+++ b/docs/analyzer/IPA.txt
@@ -74,7 +74,7 @@ This option controls whether functions from the C++ standard library, including
methods of the container classes in the Standard Template Library, should be
considered for inlining.
- -analyzer-config c++-template-inlining=[true | false]
+ -analyzer-config c++-stdlib-inlining=[true | false]
Currently, C++ standard library functions are considered for inlining by
default.
diff --git a/docs/analyzer/conf.py b/docs/analyzer/conf.py
index dff9610ac650..3690f936d336 100644
--- a/docs/analyzer/conf.py
+++ b/docs/analyzer/conf.py
@@ -48,9 +48,9 @@ copyright = u'2013, Analyzer Team'
# built documents.
#
# The short X.Y version.
-version = '3.3'
+version = '3.4'
# The full version, including alpha/beta/rc tags.
-release = '3.3'
+release = '3.4'
# 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 92741d25917c..183a285de249 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,9 +48,9 @@ copyright = u'2007-2013, The Clang Team'
# built documents.
#
# The short X.Y version.
-version = '3.3'
+version = '3.4'
# The full version, including alpha/beta/rc tags.
-release = '3.3'
+release = '3.4'
# 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 ed9ffcb85a53..61c0bd847f8a 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -1224,7 +1224,30 @@ DOT_CLEANUP = YES
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-SEARCHENGINE = NO
+SEARCHENGINE = @enable_searchengine@
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = @enable_server_based_search@
+
+SEARCHENGINE_URL = @searchengine_url@
+
+EXTERNAL_SEARCH = @enable_external_search@
+
+EXTERNAL_SEARCH_ID = clang
+
+EXTRA_SEARCH_MAPPINGS = @extra_search_mappings@
diff --git a/docs/doxygen.footer b/docs/doxygen.footer
index 524e9a2bb8b9..02db39fa559e 100644
--- a/docs/doxygen.footer
+++ b/docs/doxygen.footer
@@ -1,6 +1,6 @@
<hr>
<p class="footer">
-Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
+Generated on $datetime for r$LatestRev$ by <a href="http://www.doxygen.org">Doxygen
$doxygenversion</a>.</p>
<p class="footer">
diff --git a/docs/index.rst b/docs/index.rst
index 5cdfb6bb5b10..b18deb9b063d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,9 +18,13 @@ Using Clang as a Compiler
UsersManual
LanguageExtensions
+ CrossCompilation
AddressSanitizer
ThreadSanitizer
MemorySanitizer
+ DataFlowSanitizer
+ LeakSanitizer
+ SanitizerSpecialCaseList
Modules
FAQ
@@ -51,6 +55,7 @@ Using Clang Tools
ClangTools
ClangCheck
ClangFormat
+ ClangFormatStyleOptions
Design Documents
================
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index d2394a84a576..a58986c3a6b9 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler
=head1 SYNOPSIS
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
- [B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-Ofast>|B<-O4>]
+ [B<-O0>|B<-O1>|B<-O2>|B<-O3>|B<-Ofast>|B<-Os>|B<-Oz>|B<-O>|B<-O4>]
B<-W>I<warnings...> B<-pedantic>
B<-I>I<dir...> B<-L>I<dir...>
B<-D>I<macro[=defn]>
@@ -81,7 +81,8 @@ B<Clang Static Analyzer>
The Clang Static Analyzer is a tool that scans source code to try to find bugs
through code analysis. This tool uses many parts of Clang and is built into the
-same driver.
+same driver. Please see L<http://clang-analyzer.llvm.org> for more details
+on how to use the static analyzer.
=head1 OPTIONS
@@ -112,10 +113,6 @@ Run all of the above, plus the assembler, generating a target ".o" object file.
If no stage selection option is specified, all stages above are run, and the
linker is run to combine the results into an executable or shared library.
-=item B<--analyze>
-
-Run the Clang Static Analyzer.
-
=back
@@ -263,20 +260,52 @@ may not exist on earlier ones.
=over
-=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-Ofast> B<-O4>
-
-Specify which optimization level to use. B<-O0> means "no optimization": this
-level compiles the fastest and generates the most debuggable code. B<-O2> is a
-moderate level of optimization which enables most optimizations. B<-Os> is like
-B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
-(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>,
-except that it enables optimizations that take longer to perform or that may
-generate larger code (in an attempt to make the program run faster).
-B<-Ofast> enables all the optimizations from B<-O3> along with other aggressive
-optimizations that may violate strict compliance with language standards. On
-supported platforms, B<-O4> enables link-time optimization; object files are
-stored in the LLVM bitcode file format and whole program optimization is done at
-link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
+=item B<-O0> B<-O1> B<-O2> B<-O3> B<-Ofast> B<-Os> B<-Oz> B<-O> B<-O4>
+
+Specify which optimization level to use:
+
+=over
+
+=item B<-O0>
+
+Means "no optimization": this level compiles the fastest and
+generates the most debuggable code.
+
+=item B<-O1>
+
+Somewhere between B<-O0> and B<-O2>.
+
+=item B<-O2>
+
+Moderate level of optimization which enables most optimizations.
+
+=item B<-O3>
+
+Like B<-O2>, except that it enables optimizations that take longer to perform
+or that may generate larger code (in an attempt to make the program run faster).
+
+=item B<-Ofast>
+
+Enables all the optimizations from B<-O3> along with other aggressive
+optimizations that may violate strict compliance with language standards.
+
+=item B<-Os>
+
+Like B<-O2> with extra optimizations to reduce code size.
+
+=item B<-Oz>
+
+Like B<-Os> (and thus B<-O2>), but reduces code size further.
+
+=item B<-O>
+
+Equivalent to B<-O2>.
+
+=item B<-O4> and higher
+
+Currently equivalent to B<-O3>
+
+=back
=item B<-g>
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index 4ed6822be133..564dc380d648 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -154,20 +154,25 @@ def act_on_decl(declaration, comment, allowed_types):
inner, name = m.groups()
add_matcher('Type', name, 'Matcher<%s>...' % inner,
comment, is_dyncast=True)
- add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
- comment, is_dyncast=True)
+ # FIXME: re-enable once we have implemented casting on the TypeLoc
+ # hierarchy.
+ # add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
+ # comment, is_dyncast=True)
return
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
\s*([^\s,]+\s*),
- \s*(?:[^\s,]+\s*)
+ \s*(?:[^\s,]+\s*),
+ \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
\)\s*;\s*$""", declaration, flags=re.X)
if m:
- loc = m.group(1)
- name = m.group(2)
- result_types = extract_result_types(comment)
- if not result_types:
- raise Exception('Did not find allowed result types for: %s' % name)
+ loc, name, n_results, results = m.groups()[0:4]
+ result_types = [r.strip() for r in results.split(',')]
+
+ comment_result_types = extract_result_types(comment)
+ if (comment_result_types and
+ sorted(result_types) != sorted(comment_result_types)):
+ raise Exception('Inconsistent documentation for: %s' % name)
for result_type in result_types:
add_matcher(result_type, name, 'Matcher<Type>', comment)
if loc:
@@ -175,7 +180,31 @@ def act_on_decl(declaration, comment, allowed_types):
comment)
return
- m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
+ m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
+ \s*([^\s,]+)\s*,
+ \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*\d+\s*)?
+ \)\s*{\s*$""", declaration, flags=re.X)
+
+ if m:
+ p, n, name, n_results, results = m.groups()[0:5]
+ args = m.groups()[5:]
+ result_types = [r.strip() for r in results.split(',')]
+ if allowed_types and allowed_types != result_types:
+ raise Exception('Inconsistent documentation for: %s' % name)
+ if n not in ['', '2']:
+ raise Exception('Cannot parse "%s"' % declaration)
+ args = ', '.join('%s %s' % (args[i], args[i+1])
+ for i in range(0, len(args), 2) if args[i])
+ for result_type in result_types:
+ add_matcher(result_type, name, args, comment)
+ return
+
+ m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
(?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s*
(?:,\s*([^\s,]+)\s*
@@ -185,8 +214,8 @@ def act_on_decl(declaration, comment, allowed_types):
(?:,\s*\d+\s*)?
\)\s*{\s*$""", declaration, flags=re.X)
if m:
- p, n, result, name = m.groups()[1:5]
- args = m.groups()[5:]
+ p, n, result, name = m.groups()[0:4]
+ args = m.groups()[4:]
if not result:
if not allowed_types:
raise Exception('Did not find allowed result types for: %s' % name)
@@ -201,6 +230,26 @@ def act_on_decl(declaration, comment, allowed_types):
add_matcher(result_type, name, args, comment)
return
+ # Parse ArgumentAdapting matchers.
+ m = re.match(
+ r"""^.*ArgumentAdaptingMatcherFunc<.*>\s*(?:LLVM_ATTRIBUTE_UNUSED\s*)
+ ([a-zA-Z]*)\s*=\s*{};$""",
+ declaration, flags=re.X)
+ if m:
+ name = m.groups()[0]
+ add_matcher('*', name, 'Matcher<*>', comment)
+ return
+
+ # Parse Variadic operator matchers.
+ m = re.match(
+ r"""^.*VariadicOperatorMatcherFunc\s*([a-zA-Z]*)\s*=\s*{.*};$""",
+ declaration, flags=re.X)
+ if m:
+ name = m.groups()[0]
+ add_matcher('*', name, 'Matcher<*>, ..., Matcher<*>', comment)
+ return
+
+
# Parse free standing matcher functions, like:
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
m = re.match(r"""^\s*(.*)\s+
@@ -270,7 +319,7 @@ for line in open(MATCHERS_FILE).read().splitlines():
declaration += ' ' + line
if ((not line.strip()) or
line.rstrip()[-1] == ';' or
- line.rstrip()[-1] == '{'):
+ (line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')):
if line.strip() and line.rstrip()[-1] == '{':
body = True
else:
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
new file mode 100644
index 000000000000..0c8ca6d610f1
--- /dev/null
+++ b/docs/tools/dump_format_style.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# A tool to parse the FormatStyle struct from Format.h and update the
+# documentation in ../ClangFormatStyleOptions.rst automatically.
+# Run from the directory in which this file is located to update the docs.
+
+import collections
+import re
+import urllib2
+
+FORMAT_STYLE_FILE = '../../include/clang/Format/Format.h'
+DOC_FILE = '../ClangFormatStyleOptions.rst'
+
+
+def substitute(text, tag, contents):
+ replacement = '\n.. START_%s\n\n%s\n\n.. END_%s\n' % (tag, contents, tag)
+ pattern = r'\n\.\. START_%s\n.*\n\.\. END_%s\n' % (tag, tag)
+ return re.sub(pattern, '%s', text, flags=re.S) % replacement
+
+def doxygen2rst(text):
+ text = re.sub(r'<tt>\s*(.*?)\s*<\/tt>', r'``\1``', text)
+ text = re.sub(r'\\c ([^ ,;\.]+)', r'``\1``', text)
+ text = re.sub(r'\\\w+ ', '', text)
+ return text
+
+def indent(text, columns):
+ indent = ' ' * columns
+ s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S)
+ if s.startswith('\n'):
+ return s
+ return indent + s
+
+class Option:
+ def __init__(self, name, type, comment):
+ self.name = name
+ self.type = type
+ self.comment = comment.strip()
+ self.enum = None
+
+ def __str__(self):
+ s = '**%s** (``%s``)\n%s' % (self.name, self.type,
+ doxygen2rst(indent(self.comment, 2)))
+ if self.enum:
+ s += indent('\n\nPossible values:\n\n%s\n' % self.enum, 2)
+ return s
+
+class Enum:
+ def __init__(self, name, comment):
+ self.name = name
+ self.comment = comment.strip()
+ self.values = []
+
+ def __str__(self):
+ return '\n'.join(map(str, self.values))
+
+class EnumValue:
+ def __init__(self, name, comment):
+ self.name = name
+ self.comment = comment.strip()
+
+ def __str__(self):
+ return '* ``%s`` (in configuration: ``%s``)\n%s' % (
+ self.name,
+ re.sub('.*_', '', self.name),
+ doxygen2rst(indent(self.comment, 2)))
+
+def clean_comment_line(line):
+ return line[3:].strip() + '\n'
+
+def read_options(header):
+ class State:
+ BeforeStruct, Finished, InStruct, InFieldComment, InEnum, \
+ InEnumMemberComment = range(6)
+ state = State.BeforeStruct
+
+ options = []
+ enums = {}
+ comment = ''
+ enum = None
+
+ for line in header:
+ line = line.strip()
+ if state == State.BeforeStruct:
+ if line == 'struct FormatStyle {':
+ state = State.InStruct
+ elif state == State.InStruct:
+ if line.startswith('///'):
+ state = State.InFieldComment
+ comment = clean_comment_line(line)
+ elif line == '};':
+ state = State.Finished
+ break
+ elif state == State.InFieldComment:
+ if line.startswith('///'):
+ comment += clean_comment_line(line)
+ elif line.startswith('enum'):
+ state = State.InEnum
+ name = re.sub(r'enum\s+(\w+)\s*\{', '\\1', line)
+ enum = Enum(name, comment)
+ elif line.endswith(';'):
+ state = State.InStruct
+ field_type, field_name = re.match(r'(\w+)\s+(\w+);', line).groups()
+ option = Option(str(field_name), str(field_type), comment)
+ options.append(option)
+ else:
+ raise Exception('Invalid format, expected comment, field or enum')
+ elif state == State.InEnum:
+ if line.startswith('///'):
+ state = State.InEnumMemberComment
+ comment = clean_comment_line(line)
+ elif line == '};':
+ state = State.InStruct
+ enums[enum.name] = enum
+ else:
+ raise Exception('Invalid format, expected enum field comment or };')
+ elif state == State.InEnumMemberComment:
+ if line.startswith('///'):
+ comment += clean_comment_line(line)
+ else:
+ state = State.InEnum
+ enum.values.append(EnumValue(line.replace(',', ''), comment))
+ if state != State.Finished:
+ raise Exception('Not finished by the end of file')
+
+ for option in options:
+ if not option.type in ['bool', 'unsigned', 'int']:
+ if enums.has_key(option.type):
+ option.enum = enums[option.type]
+ else:
+ raise Exception('Unknown type: %s' % option.type)
+ return options
+
+options = read_options(open(FORMAT_STYLE_FILE))
+
+options = sorted(options, key=lambda x: x.name)
+options_text = '\n\n'.join(map(str, options))
+
+contents = open(DOC_FILE).read()
+
+contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
+
+with open(DOC_FILE, 'w') as output:
+ output.write(contents)
+
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index 0c4d35c8ebd2..55a8e6fb0f48 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -15,8 +15,8 @@ NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
- linker selectiondag asmparser instrumentation
+LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter irreader \
+ ipo linker selectiondag asmparser instrumentation option
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index 3d0d6409d90e..e00583d1a1ab 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -21,6 +21,7 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
@@ -34,11 +35,11 @@ using namespace clang::driver;
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
-llvm::sys::Path GetExecutablePath(const char *Argv0) {
+std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
- return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+ return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
static int Execute(llvm::Module *Mod, char * const *envp) {
@@ -67,14 +68,14 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
int main(int argc, const char **argv, char * const *envp) {
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
- llvm::sys::Path Path = GetExecutablePath(argv[0]);
+ std::string Path = GetExecutablePath(argv[0]);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- Driver TheDriver(Path.str(), llvm::sys::getProcessTriple(), "a.out", Diags);
+ Driver TheDriver(Path, llvm::sys::getProcessTriple(), "a.out", Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
@@ -94,7 +95,7 @@ int main(int argc, const char **argv, char * const *envp) {
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
- C->PrintJob(OS, C->getJobs(), "; ", true);
+ Jobs.Print(OS, "; ", true);
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
return 1;
}
@@ -117,7 +118,7 @@ int main(int argc, const char **argv, char * const *envp) {
// Show the invocation, with -v.
if (CI->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang invocation:\n";
- C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
+ Jobs.Print(llvm::errs(), "\n", true);
llvm::errs() << "\n";
}
diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h
index ff1ec63db057..fd65418f607c 100644
--- a/include/clang-c/CXCompilationDatabase.h
+++ b/include/clang-c/CXCompilationDatabase.h
@@ -58,7 +58,7 @@ typedef void * CXCompileCommand;
*/
typedef enum {
/*
- * \brief No error occured
+ * \brief No error occurred
*/
CXCompilationDatabase_NoError = 0,
@@ -142,6 +142,24 @@ CINDEX_LINKAGE CXString
clang_CompileCommand_getArg(CXCompileCommand, unsigned I);
/**
+ * \brief Get the number of source mappings for the compiler invocation.
+ */
+CINDEX_LINKAGE unsigned
+clang_CompileCommand_getNumMappedSources(CXCompileCommand);
+
+/**
+ * \brief Get the I'th mapped source path for the compiler invocation.
+ */
+CINDEX_LINKAGE CXString
+clang_CompileCommand_getMappedSourcePath(CXCompileCommand, unsigned I);
+
+/**
+ * \brief Get the I'th mapped source content for the compiler invocation.
+ */
+CINDEX_LINKAGE CXString
+clang_CompileCommand_getMappedSourceContent(CXCompileCommand, unsigned I);
+
+/**
* @}
*/
diff --git a/include/clang-c/CXString.h b/include/clang-c/CXString.h
index 34cab5e7bd8c..592c4dc44e30 100644
--- a/include/clang-c/CXString.h
+++ b/include/clang-c/CXString.h
@@ -46,7 +46,7 @@ typedef struct {
CINDEX_LINKAGE const char *clang_getCString(CXString string);
/**
- * \brief Free the given string,
+ * \brief Free the given string.
*/
CINDEX_LINKAGE void clang_disposeString(CXString string);
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index d8c37ebd70f9..95d54c279f03 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -16,9 +16,7 @@
#ifndef CLANG_C_INDEX_H
#define CLANG_C_INDEX_H
-#include <sys/stat.h>
#include <time.h>
-#include <stdio.h>
#include "clang-c/Platform.h"
#include "clang-c/CXString.h"
@@ -32,7 +30,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 19
+#define CINDEX_VERSION_MINOR 20
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -414,6 +412,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location);
/**
+ * \brief Returns non-zero if the given source location is in the main file of
+ * the corresponding translation unit.
+ */
+CINDEX_LINKAGE int clang_Location_isFromMainFile(CXSourceLocation location);
+
+/**
* \brief Retrieve a NULL (invalid) source range.
*/
CINDEX_LINKAGE CXSourceRange clang_getNullRange(void);
@@ -723,7 +727,7 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
* \brief Retrieve the child diagnostics of a CXDiagnostic.
*
* This CXDiagnosticSet does not need to be released by
- * clang_diposeDiagnosticSet.
+ * clang_disposeDiagnosticSet.
*/
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
@@ -763,7 +767,7 @@ CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic);
* \brief Options to control the display of diagnostics.
*
* The values in this enum are meant to be combined to customize the
- * behavior of \c clang_displayDiagnostic().
+ * behavior of \c clang_formatDiagnostic().
*/
enum CXDiagnosticDisplayOptions {
/**
@@ -850,7 +854,7 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
* default behavior of the clang compiler.
*
* \returns A set of display options suitable for use with \c
- * clang_displayDiagnostic().
+ * clang_formatDiagnostic().
*/
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
@@ -1942,7 +1946,7 @@ enum CXCursorKind {
*/
CXCursor_CompoundStmt = 202,
- /** \brief A case statment.
+ /** \brief A case statement.
*/
CXCursor_CaseStmt = 203,
@@ -2062,7 +2066,11 @@ enum CXCursorKind {
*/
CXCursor_DeclStmt = 231,
- CXCursor_LastStmt = CXCursor_DeclStmt,
+ /** \brief OpenMP parallel directive.
+ */
+ CXCursor_OMPParallelDirective = 232,
+
+ CXCursor_LastStmt = CXCursor_OMPParallelDirective,
/**
* \brief Cursor that represents the translation unit itself.
@@ -2087,7 +2095,8 @@ enum CXCursorKind {
CXCursor_CXXOverrideAttr = 405,
CXCursor_AnnotateAttr = 406,
CXCursor_AsmLabelAttr = 407,
- CXCursor_LastAttr = CXCursor_AsmLabelAttr,
+ CXCursor_PackedAttr = 408,
+ CXCursor_LastAttr = CXCursor_PackedAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -2666,7 +2675,11 @@ enum CXTypeKind {
CXType_FunctionNoProto = 110,
CXType_FunctionProto = 111,
CXType_ConstantArray = 112,
- CXType_Vector = 113
+ CXType_Vector = 113,
+ CXType_IncompleteArray = 114,
+ CXType_VariableArray = 115,
+ CXType_DependentSizedArray = 116,
+ CXType_MemberPointer = 117
};
/**
@@ -2683,6 +2696,8 @@ enum CXCallingConv {
CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_PnaclCall = 8,
CXCallingConv_IntelOclBicc = 9,
+ CXCallingConv_X86_64Win64 = 10,
+ CXCallingConv_X86_64SysV = 11,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@@ -2955,6 +2970,13 @@ enum CXTypeLayoutError {
CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T);
/**
+ * \brief Return the class type of an member pointer type.
+ *
+ * If a non-member-pointer type is passed in, an invalid type is returned.
+ */
+CINDEX_LINKAGE CXType clang_Type_getClassType(CXType T);
+
+/**
* \brief Return the size of a type in bytes as per C++[expr.sizeof] standard.
*
* If the type declaration is invalid, CXTypeLayoutError_Invalid is returned.
@@ -2980,6 +3002,23 @@ CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T);
*/
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
+enum CXRefQualifierKind {
+ /** \brief No ref-qualifier was provided. */
+ CXRefQualifier_None = 0,
+ /** \brief An lvalue ref-qualifier was provided (\c &). */
+ CXRefQualifier_LValue,
+ /** \brief An rvalue ref-qualifier was provided (\c &&). */
+ CXRefQualifier_RValue
+};
+
+/**
+ * \brief Retrieve the ref-qualifier kind of a function or method.
+ *
+ * The ref-qualifier is returned for C++ functions or methods. For other types
+ * or non-C++ declarations, CXRefQualifier_None is returned.
+ */
+CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T);
+
/**
* \brief Returns non-zero if the cursor specifies a Record member that is a
* bitfield.
@@ -3414,6 +3453,13 @@ typedef enum {
CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
/**
+ * \brief Given a cursor that represents an ObjC 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".
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
+
+/**
* \brief Returns non-zero if the given cursor is a variadic function or method.
*/
CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C);
@@ -4035,6 +4081,12 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
*/
/**
+ * \brief Determine if a C++ member function or member function template is
+ * pure virtual.
+ */
+CINDEX_LINKAGE unsigned clang_CXXMethod_isPureVirtual(CXCursor C);
+
+/**
* \brief Determine if a C++ member function or member function template is
* declared 'static'.
*/
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index c167d3c3192b..196f6c0b731f 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -97,6 +97,8 @@ class MigrationProcess {
FileRemapper Remapper;
public:
+ bool HadARCErrors;
+
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
StringRef outputDir = StringRef());
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index 2daaf73065c2..45c8b4ed1a39 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -57,14 +57,12 @@ public:
/// \brief Migrates to modern ObjC syntax.
class ObjCMigrateAction : public WrapperFrontendAction {
std::string MigrateDir;
- bool MigrateLiterals;
- bool MigrateSubscripting;
+ unsigned ObjCMigAction;
FileRemapper Remapper;
CompilerInstance *CompInst;
public:
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
- bool migrateLiterals,
- bool migrateSubscripting);
+ unsigned migrateAction);
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index 94c9e8f31acb..f7677cc8620a 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -53,7 +53,6 @@ public:
StringRef outputDir = StringRef());
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
- void remap(StringRef filePath, StringRef newPath);
void applyMappings(PreprocessorOptions &PPOpts) const;
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index ec8faa4e3524..b4fd2affa653 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -168,6 +168,13 @@ public:
MakeUninit();
}
+ /// \brief Returns whether the object performed allocations.
+ ///
+ /// If APValues are constructed via placement new, \c needsCleanup()
+ /// indicates whether the destructor must be called in order to correctly
+ /// free all allocated memory.
+ bool needsCleanup() const;
+
/// \brief Swaps the contents of this and the given APValue.
void swap(APValue &RHS);
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index ae779436a9da..7b6fa94b2043 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
#define LLVM_CLANG_AST_ASTCONSUMER_H
+#include "llvm/ADT/StringRef.h"
+
namespace clang {
class ASTContext;
class CXXRecordDecl;
@@ -70,6 +72,10 @@ public:
/// can be defined in declspecs).
virtual void HandleTagDeclDefinition(TagDecl *D) {}
+ /// \brief This callback is invoked the first time each TagDecl is required to
+ /// be complete.
+ virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {}
+
/// \brief Invoked when a function is implicitly instantiated.
/// Note that at this point point it does not have a body, its body is
/// instantiated at the end of the translation unit and passed to
@@ -86,6 +92,21 @@ public:
/// The default implementation passes it to HandleTopLevelDecl.
virtual void HandleImplicitImportDecl(ImportDecl *D);
+ /// \brief Handle a pragma that appends to Linker Options. Currently this
+ /// only exists to support Microsoft's #pragma comment(linker, "/foo").
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
+
+ /// \brief Handle a pragma that emits a mismatch identifier and value to the
+ /// object file for the linker to work with. Currently, this only exists to
+ /// support Microsoft's #pragma detect_mismatch.
+ virtual void HandleDetectMismatch(llvm::StringRef Name,
+ llvm::StringRef Value) {}
+
+ /// \brief Handle a dependent library created by a pragma in the source.
+ /// Currently this only exists to support Microsoft's
+ /// #pragma comment(lib, "/foo").
+ virtual void HandleDependentLibrary(llvm::StringRef Lib) {}
+
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be
/// completed.
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c5d3337fd22d..f420e85ee146 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -19,11 +19,9 @@
#include "clang/AST/CanonicalType.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/LambdaMangleContext.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RawCommentList.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
@@ -47,6 +45,7 @@ namespace llvm {
namespace clang {
class FileManager;
+ class AtomicExpr;
class ASTRecordLayout;
class BlockExpr;
class CharUnits;
@@ -55,9 +54,11 @@ namespace clang {
class ExternalASTSource;
class ASTMutationListener;
class IdentifierTable;
+ class MaterializeTemporaryExpr;
class SelectorTable;
class TargetInfo;
class CXXABI;
+ class MangleNumberingContext;
// Decls
class MangleContext;
class ObjCIvarDecl;
@@ -81,6 +82,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
mutable llvm::FoldingSet<PointerType> PointerTypes;
+ mutable llvm::FoldingSet<DecayedType> DecayedTypes;
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
@@ -146,7 +148,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable TypeInfoMap MemoizedTypeInfo;
/// \brief A cache mapping from CXXRecordDecls to key functions.
- llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
+ llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
@@ -163,6 +165,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
ClassScopeSpecializationPattern;
+ /// \brief Mapping from materialized temporaries with static storage duration
+ /// that appear in constant initializers to their evaluated values.
+ llvm::DenseMap<const MaterializeTemporaryExpr*, APValue>
+ MaterializedTemporaryValues;
+
/// \brief Representation of a "canonical" template template parameter that
/// is used in canonical template names.
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
@@ -190,6 +197,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the __uint128_t type.
mutable TypedefDecl *UInt128Decl;
+
+ /// \brief The typedef for the __float128 stub type.
+ mutable TypeDecl *Float128StubDecl;
/// \brief The typedef for the target specific predefined
/// __builtin_va_list type.
@@ -261,13 +271,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// wasting space in the Decl class.
llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs;
- /// \brief Keeps track of the static data member templates from which
- /// static data members of class template specializations were instantiated.
+ /// \brief A mapping from non-redeclarable declarations in modules that were
+ /// merged with other declarations to the canonical declaration that they were
+ /// merged into.
+ llvm::DenseMap<Decl*, Decl*> MergedDecls;
+
+public:
+ /// \brief A type synonym for the TemplateOrInstantiation mapping.
+ typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>
+ TemplateOrSpecializationInfo;
+
+private:
+
+ /// \brief A mapping to contain the template or declaration that
+ /// a variable declaration describes or was instantiated from,
+ /// respectively.
///
- /// This data structure stores the mapping from instantiations of static
- /// data members to the static data member representations within the
- /// class template from which they were instantiated along with the kind
- /// of instantiation or specialization (a TemplateSpecializationKind - 1).
+ /// For non-templates, this value will be NULL. For variable
+ /// declarations that describe a variable template, this will be a
+ /// pointer to a VarTemplateDecl. For static data members
+ /// of class template specializations, this will be the
+ /// MemberSpecializationInfo referring to the member variable that was
+ /// instantiated or specialized. Thus, the mapping will keep track of
+ /// the static data member templates from which static data members of
+ /// class template specializations were instantiated.
///
/// Given the following example:
///
@@ -286,8 +313,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// This mapping will contain an entry that maps from the VarDecl for
/// X<int>::value to the corresponding VarDecl for X<T>::value (within the
/// class template X) and will be marked TSK_ImplicitInstantiation.
- llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>
- InstantiatedFromStaticDataMember;
+ llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>
+ TemplateOrInstantiation;
/// \brief Keeps track of the declaration from which a UsingDecl was
/// created during instantiation.
@@ -328,12 +355,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
- /// \brief Mapping from each declaration context to its corresponding lambda
- /// mangling context.
- llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
+ /// \brief Mapping from each declaration context to its corresponding
+ /// mangling numbering context (used for constructs like lambdas which
+ /// need to be consistently numbered for the mangler).
+ llvm::DenseMap<const DeclContext *, MangleNumberingContext *>
+ MangleNumberingContexts;
- llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
- llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
+ /// \brief Side-table of mangling numbers for declarations which rarely
+ /// need them (like static local vars).
+ llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers;
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
@@ -368,6 +398,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap;
+ /// \brief Address space map mangling must be used with language specific
+ /// address spaces (e.g. OpenCL/CUDA)
+ bool AddrSpaceMapMangling;
+
friend class ASTDeclReader;
friend class ASTReader;
friend class ASTWriter;
@@ -419,22 +453,7 @@ public:
return getParents(ast_type_traits::DynTypedNode::create(Node));
}
- ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {
- assert(Node.getMemoizationData() &&
- "Invariant broken: only nodes that support memoization may be "
- "used in the parent map.");
- if (!AllParents) {
- // We always need to run over the whole translation unit, as
- // hasAncestor can escape any subtree.
- AllParents.reset(
- ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
- }
- ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
- if (I == AllParents->end()) {
- return ParentVector();
- }
- return I->second;
- }
+ ParentVector getParents(const ast_type_traits::DynTypedNode &Node);
const clang::PrintingPolicy &getPrintingPolicy() const {
return PrintingPolicy;
@@ -451,7 +470,7 @@ public:
return BumpAlloc;
}
- void *Allocate(unsigned Size, unsigned Align = 8) const {
+ void *Allocate(size_t Size, unsigned Align = 8) const {
return BumpAlloc.Allocate(Size, Align);
}
void Deallocate(void *Ptr) const { }
@@ -470,6 +489,19 @@ public:
const TargetInfo &getTargetInfo() const { return *Target; }
+ /// getIntTypeForBitwidth -
+ /// sets integer QualTy according to specified details:
+ /// bitwidth, signed/unsigned.
+ /// Returns empty type if there is no appropriate target types.
+ QualType getIntTypeForBitwidth(unsigned DestWidth,
+ unsigned Signed) const;
+ /// getRealTypeForBitwidth -
+ /// sets floating point QualTy according to specified bitwidth.
+ /// Returns empty type if there is no appropriate target types.
+ QualType getRealTypeForBitwidth(unsigned DestWidth) const;
+
+ bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
+
const LangOptions& getLangOpts() const { return LangOpts; }
DiagnosticsEngine &getDiagnostics() const;
@@ -580,7 +612,12 @@ public:
/// preprocessor is not available.
comments::FullComment *getCommentForDecl(const Decl *D,
const Preprocessor *PP) const;
-
+
+ /// Return parsed documentation comment attached to a given declaration.
+ /// Returns NULL if no comment is attached. Does not look at any
+ /// redeclarations of the declaration.
+ comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const;
+
comments::FullComment *cloneFullComment(comments::FullComment *FC,
const Decl *D) const;
@@ -601,9 +638,13 @@ public:
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
+ // FIXME: Remove ?
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
const VarDecl *Var);
+ TemplateOrSpecializationInfo
+ getTemplateOrSpecializationInfo(const VarDecl *Var);
+
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
void setClassScopeSpecializationPattern(FunctionDecl *FD,
@@ -615,6 +656,9 @@ public:
TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation());
+ void setTemplateOrSpecializationInfo(VarDecl *Inst,
+ TemplateOrSpecializationInfo TSI);
+
/// \brief If the given using decl \p Inst is an instantiation of a
/// (possibly unresolved) using decl from a template instantiation,
/// return it.
@@ -632,31 +676,6 @@ public:
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
- /// \brief Return \c true if \p FD is a zero-length bitfield which follows
- /// the non-bitfield \p LastFD.
- bool ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
-
- /// \brief Return \c true if \p FD is a zero-length bitfield which follows
- /// the bitfield \p LastFD.
- bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
-
- /// \brief Return \c true if \p FD is a bitfield which follows the bitfield
- /// \p LastFD.
- bool BitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
-
- /// \brief Return \c true if \p FD is not a bitfield which follows the
- /// bitfield \p LastFD.
- bool NonBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
-
- /// \brief Return \c true if \p FD is a bitfield which follows the
- /// non-bitfield \p LastFD.
- bool BitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
-
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator
@@ -732,7 +751,15 @@ public:
return import_iterator(FirstLocalImport);
}
import_iterator local_import_end() const { return import_iterator(); }
-
+
+ Decl *getPrimaryMergedDecl(Decl *D) {
+ Decl *Result = MergedDecls.lookup(D);
+ return Result ? Result : D;
+ }
+ void setPrimaryMergedDecl(Decl *D, Decl *Primary) {
+ MergedDecls[D] = Primary;
+ }
+
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
@@ -740,7 +767,8 @@ public:
CanQualType VoidTy;
CanQualType BoolTy;
CanQualType CharTy;
- CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
+ CanQualType WCharTy; // [C++ 3.9.1p5].
+ CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99.
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
@@ -809,6 +837,9 @@ public:
/// \brief Retrieve the declaration for the 128-bit unsigned integer type.
TypedefDecl *getUInt128Decl() const;
+
+ /// \brief Retrieve the declaration for a 128-bit float stub type.
+ TypeDecl *getFloat128StubType() const;
//===--------------------------------------------------------------------===//
// Type Constructors
@@ -884,6 +915,14 @@ public:
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
}
+ /// \brief Return the uniqued reference to the decayed version of the given
+ /// type. Can only be called on array and function types which decay to
+ /// pointer types.
+ QualType getDecayedType(QualType T) const;
+ CanQualType getDecayedType(CanQualType T) const {
+ return CanQualType::CreateUnsafe(getDecayedType((QualType) T));
+ }
+
/// \brief Return the uniqued reference to the atomic type for the specified
/// type.
QualType getAtomicType(QualType T) const;
@@ -1104,7 +1143,7 @@ public:
/// \brief C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
- bool IsDependent = false) const;
+ bool IsDependent) const;
/// \brief C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
@@ -1130,11 +1169,15 @@ public:
/// <stdint.h>.
CanQualType getUIntMaxType() const;
- /// \brief In C++, this returns the unique wchar_t type. In C99, this
- /// returns a type compatible with the type defined in <stddef.h> as defined
- /// by the target.
+ /// \brief Return the unique wchar_t type available in C++ (and available as
+ /// __wchar_t as a Microsoft extension).
QualType getWCharType() const { return WCharTy; }
+ /// \brief Return the type of wide characters. In C++, this returns the
+ /// unique wchar_t type. In C99, this returns a type compatible with the type
+ /// defined in <stddef.h> as defined by the target.
+ QualType getWideCharType() const { return WideCharTy; }
+
/// \brief Return the type of "signed wchar_t".
///
/// Used when in C++, as a GCC extension.
@@ -1607,14 +1650,17 @@ public:
/// \pre \p D must not be a bitfield type, as bitfields do not have a valid
/// alignment.
///
- /// If \p RefAsPointee, references are treated like their underlying type
- /// (for alignof), else they're treated like pointers (for CodeGen).
- CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const;
+ /// If \p ForAlignof, references are treated like their underlying type
+ /// and large arrays don't get any special treatment. If not \p ForAlignof
+ /// it computes the value expected by CodeGen: references are treated like
+ /// pointers and large arrays get extra alignment.
+ CharUnits getDeclAlign(const Decl *D, bool ForAlignof = false) const;
/// \brief Get or compute information about the layout of the specified
/// record (struct/union/class) \p D, which indicates its size and field
/// position information.
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
+ const ASTRecordLayout *BuildMicrosoftASTRecordLayout(const RecordDecl *D) const;
/// \brief Get or compute information about the layout of the specified
/// Objective-C interface.
@@ -1721,6 +1767,9 @@ public:
getCanonicalType(T2).getTypePtr();
}
+ bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
+ const ObjCMethodDecl *MethodImp);
+
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
/// \brief Retrieves the "canonical" nested name specifier for a
@@ -1749,19 +1798,9 @@ public:
NestedNameSpecifier *
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
- /// \brief Retrieves the default calling convention to use for
- /// C++ instance methods.
- CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
-
- /// \brief Retrieves the canonical representation of the given
- /// calling convention.
- CallingConv getCanonicalCallConv(CallingConv CC) const;
-
- /// \brief Determines whether two calling conventions name the same
- /// calling convention.
- bool isSameCallConv(CallingConv lcc, CallingConv rcc) {
- return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc));
- }
+ /// \brief Retrieves the default calling convention for the current target.
+ CallingConv getDefaultCallingConvention(bool isVariadic,
+ bool IsCXXMethod) const;
/// \brief Retrieves the "canonical" template name that refers to a
/// given template.
@@ -1899,6 +1938,12 @@ public:
return (*AddrSpaceMap)[AS - LangAS::Offset];
}
+ bool addressSpaceMapManglingFor(unsigned AS) const {
+ return AddrSpaceMapMangling ||
+ AS < LangAS::Offset ||
+ AS >= LangAS::Offset + LangAS::Count;
+ }
+
private:
// Helper for integer ordering
unsigned getIntegerRank(const Type *T) const;
@@ -1925,7 +1970,6 @@ public:
bool isObjCSelType(QualType T) const {
return T == getObjCSelType();
}
- bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
bool ForCompare);
@@ -2092,12 +2136,15 @@ public:
/// it is not used.
bool DeclMustBeEmitted(const Decl *D);
- void addUnnamedTag(const TagDecl *Tag);
- int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
+ void setManglingNumber(const NamedDecl *ND, unsigned Number);
+ unsigned getManglingNumber(const NamedDecl *ND) const;
+
+ /// \brief Retrieve the context for computing mangling numbers in the given
+ /// DeclContext.
+ MangleNumberingContext &getManglingNumberContext(const DeclContext *DC);
+
+ MangleNumberingContext *createMangleNumberingContext() const;
- /// \brief Retrieve the lambda mangling number for a lambda expression.
- unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
-
/// \brief Used by ParmVarDecl to store on the side the
/// index of the parameter when it exceeds the size of the normal bitfield.
void setParameterIndex(const ParmVarDecl *D, unsigned index);
@@ -2105,7 +2152,12 @@ public:
/// \brief Used by ParmVarDecl to retrieve on the side the
/// index of the parameter when it exceeds the size of the normal bitfield.
unsigned getParameterIndex(const ParmVarDecl *D) const;
-
+
+ /// \brief Get the storage for the constant value of a materialized temporary
+ /// of static storage duration.
+ APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
+ bool MayCreate);
+
//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
@@ -2197,93 +2249,21 @@ private:
const ObjCImplementationDecl *Impl) const;
private:
- /// \brief A set of deallocations that should be performed when the
+ /// \brief A set of deallocations that should be performed when the
/// ASTContext is destroyed.
- SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
-
+ typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
+ DeallocationMap;
+ DeallocationMap Deallocations;
+
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
// but we include it here so that ASTContext can quickly deallocate them.
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
- /// \brief A counter used to uniquely identify "blocks".
- mutable unsigned int UniqueBlockByRefTypeID;
-
friend class DeclContext;
friend class DeclarationNameTable;
void ReleaseDeclContextMaps();
- /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
- /// parents as defined by the \c RecursiveASTVisitor.
- ///
- /// Note that the relationship described here is purely in terms of AST
- /// traversal - there are other relationships (for example declaration context)
- /// in the AST that are better modeled by special matchers.
- ///
- /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
- class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
- public:
- /// \brief Builds and returns the translation unit's parent map.
- ///
- /// The caller takes ownership of the returned \c ParentMap.
- static ParentMap *buildMap(TranslationUnitDecl &TU) {
- ParentMapASTVisitor Visitor(new ParentMap);
- Visitor.TraverseDecl(&TU);
- return Visitor.Parents;
- }
-
- private:
- typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
-
- ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {
- }
-
- bool shouldVisitTemplateInstantiations() const {
- return true;
- }
- bool shouldVisitImplicitCode() const {
- return true;
- }
- // Disables data recursion. We intercept Traverse* methods in the RAV, which
- // are not triggered during data recursion.
- bool shouldUseDataRecursionFor(clang::Stmt *S) const {
- return false;
- }
-
- template <typename T>
- bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
- if (Node == NULL)
- return true;
- if (ParentStack.size() > 0)
- // FIXME: Currently we add the same parent multiple times, for example
- // when we visit all subexpressions of template instantiations; this is
- // suboptimal, bug benign: the only way to visit those is with
- // hasAncestor / hasParent, and those do not create new matches.
- // The plan is to enable DynTypedNode to be storable in a map or hash
- // map. The main problem there is to implement hash functions /
- // comparison operators for all types that DynTypedNode supports that
- // do not have pointer identity.
- (*Parents)[Node].push_back(ParentStack.back());
- ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
- bool Result = (this ->* traverse) (Node);
- ParentStack.pop_back();
- return Result;
- }
-
- bool TraverseDecl(Decl *DeclNode) {
- return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
- }
-
- bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
- }
-
- ParentMap *Parents;
- llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
-
- friend class RecursiveASTVisitor<ParentMapASTVisitor>;
- };
-
llvm::OwningPtr<ParentMap> AllParents;
};
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 64e955ea1472..1635511984dc 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define ASTSTART
#include "clang/Basic/DiagnosticASTKinds.inc"
#undef DIAG
diff --git a/include/clang/AST/ASTFwd.h b/include/clang/AST/ASTFwd.h
new file mode 100644
index 000000000000..4f3279874b16
--- /dev/null
+++ b/include/clang/AST/ASTFwd.h
@@ -0,0 +1,28 @@
+//===--- ASTFwd.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 Forward declaration of all AST node types.
+///
+//===-------------------------------------------------------------===//
+
+namespace clang {
+
+class Decl;
+#define DECL(DERIVED, BASE) class DERIVED##Decl;
+#include "clang/AST/DeclNodes.inc"
+class Stmt;
+#define STMT(DERIVED, BASE) class DERIVED;
+#include "clang/AST/StmtNodes.inc"
+class Type;
+#define TYPE(DERIVED, BASE) class DERIVED##Type;
+#include "clang/AST/TypeNodes.def"
+class CXXCtorInitializer;
+
+} // end namespace clang
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index 1672ab22a3de..b74c8ee1bf47 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -271,6 +271,14 @@ namespace clang {
/// Subclasses can override this function to observe all of the \c From ->
/// \c To declaration mappings as they are imported.
virtual Decl *Imported(Decl *From, Decl *To);
+
+ /// \brief Called by StructuralEquivalenceContext. If a RecordDecl is
+ /// being compared to another RecordDecl as part of import, completing the
+ /// other RecordDecl may trigger importation of the first RecordDecl. This
+ /// happens especially for anonymous structs. If the original of the second
+ /// RecordDecl can be found, we can complete it without the need for
+ /// importation, eliminating this loop.
+ virtual Decl *GetOriginalDecl(Decl *To) { return NULL; }
/// \brief Determine whether the given types are structurally
/// equivalent.
diff --git a/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h
new file mode 100644
index 000000000000..358ac7131e40
--- /dev/null
+++ b/include/clang/AST/ASTLambda.h
@@ -0,0 +1,80 @@
+//===--- ASTLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides some common utility functions for processing
+/// Lambda related AST Constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_LAMBDA_H
+#define LLVM_CLANG_AST_LAMBDA_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+namespace clang {
+inline StringRef getLambdaStaticInvokerName() {
+ return "__invoke";
+}
+// This function returns true if M is a specialization, a template,
+// or a non-generic lambda call operator.
+inline bool isLambdaCallOperator(const CXXMethodDecl *MD) {
+ const CXXRecordDecl *LambdaClass = MD->getParent();
+ if (!LambdaClass || !LambdaClass->isLambda()) return false;
+ return MD->getOverloadedOperator() == OO_Call;
+}
+
+inline bool isLambdaCallOperator(const DeclContext *DC) {
+ if (!DC || !isa<CXXMethodDecl>(DC)) return false;
+ return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
+ if (!MD) return false;
+ CXXRecordDecl *LambdaClass = MD->getParent();
+ if (LambdaClass && LambdaClass->isGenericLambda())
+ return isLambdaCallOperator(MD) &&
+ MD->isFunctionTemplateSpecialization();
+ return false;
+}
+
+inline bool isLambdaConversionOperator(CXXConversionDecl *C) {
+ return C ? C->getParent()->isLambda() : false;
+}
+
+inline bool isLambdaConversionOperator(Decl *D) {
+ if (!D) return false;
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))
+ return isLambdaConversionOperator(Conv);
+ if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))
+ if (CXXConversionDecl *Conv =
+ dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))
+ return isLambdaConversionOperator(Conv);
+ return false;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
+ return isGenericLambdaCallOperatorSpecialization(
+ dyn_cast<CXXMethodDecl>(DC));
+}
+
+
+// This returns the parent DeclContext ensuring that the correct
+// parent DeclContext is returned for Lambdas
+inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) {
+ if (isLambdaCallOperator(DC))
+ return DC->getParent()->getParent();
+ else
+ return DC->getParent();
+}
+
+} // clang
+
+#endif // LLVM_CLANG_AST_LAMBDA_H
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 6b70285e3ad8..6d12a92c61bf 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -27,8 +27,11 @@ namespace clang {
class ObjCContainerDecl;
class ObjCInterfaceDecl;
class ObjCPropertyDecl;
+ class QualType;
class TagDecl;
class VarDecl;
+ class VarTemplateDecl;
+ class VarTemplateSpecializationDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
@@ -53,9 +56,18 @@ public:
/// \brief A template specialization (or partial one) was added to the
/// template declaration.
+ virtual void
+ AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
+ const VarTemplateSpecializationDecl *D) {}
+
+ /// \brief A template specialization (or partial one) was added to the
+ /// template declaration.
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {}
+ /// \brief A function's return type has been deduced.
+ virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
+
/// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
@@ -78,6 +90,11 @@ public:
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) {}
+ /// \brief A declaration is marked used which was not previously marked used.
+ ///
+ /// \param D the declaration marked used
+ virtual void DeclarationMarkedUsed(const Decl *D) {}
+
// NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener.
};
diff --git a/include/clang/AST/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h
index 4688b12de701..087ad5609001 100644
--- a/include/clang/AST/ASTTypeTraits.h
+++ b/include/clang/AST/ASTTypeTraits.h
@@ -7,22 +7,132 @@
//
//===----------------------------------------------------------------------===//
//
-// Provides a dynamically typed node container that can be used to store
-// an AST base node at runtime in the same storage in a type safe way.
+// Provides a dynamic type identifier and a dynamically typed node container
+// that can be used to store an AST base node at runtime in the same storage in
+// a type safe way.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
+#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/Support/AlignOf.h"
+namespace llvm {
+
+class raw_ostream;
+
+}
+
namespace clang {
+
+struct PrintingPolicy;
+
namespace ast_type_traits {
+/// \brief Kind identifier.
+///
+/// It can be constructed from any node kind and allows for runtime type
+/// hierarchy checks.
+/// Use getFromNodeKind<T>() to construct them.
+class ASTNodeKind {
+public:
+ /// \brief Empty identifier. It matches nothing.
+ ASTNodeKind() : KindId(NKI_None) {}
+
+ /// \brief Construct an identifier for T.
+ template <class T>
+ static ASTNodeKind getFromNodeKind() {
+ return ASTNodeKind(KindToKindId<T>::Id);
+ }
+
+ /// \brief Returns \c true if \c this and \c Other represent the same kind.
+ bool isSame(ASTNodeKind Other) const;
+
+ /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
+ bool isBaseOf(ASTNodeKind Other) const;
+
+ /// \brief String representation of the kind.
+ StringRef asStringRef() const;
+
+private:
+ /// \brief Kind ids.
+ ///
+ /// Includes all possible base and derived kinds.
+ enum NodeKindId {
+ NKI_None,
+ NKI_CXXCtorInitializer,
+ NKI_TemplateArgument,
+ NKI_NestedNameSpecifier,
+ NKI_NestedNameSpecifierLoc,
+ NKI_QualType,
+ NKI_TypeLoc,
+ NKI_Decl,
+#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
+#include "clang/AST/DeclNodes.inc"
+ NKI_Stmt,
+#define STMT(DERIVED, BASE) NKI_##DERIVED,
+#include "clang/AST/StmtNodes.inc"
+ NKI_Type,
+#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
+#include "clang/AST/TypeNodes.def"
+ NKI_NumberOfKinds
+ };
+
+ /// \brief Use getFromNodeKind<T>() to construct the kind.
+ ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
+
+ /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
+ /// Derived.
+ static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
+
+ /// \brief Helper meta-function to convert a kind T to its enum value.
+ ///
+ /// This struct is specialized below for all known kinds.
+ template <class T> struct KindToKindId {
+ static const NodeKindId Id = NKI_None;
+ };
+
+ /// \brief Per kind info.
+ struct KindInfo {
+ /// \brief The id of the parent kind, or None if it has no parent.
+ NodeKindId ParentId;
+ /// \brief Name of the kind.
+ const char *Name;
+ };
+ static const KindInfo AllKindInfo[NKI_NumberOfKinds];
+
+ NodeKindId KindId;
+};
+
+#define KIND_TO_KIND_ID(Class) \
+ template <> struct ASTNodeKind::KindToKindId<Class> { \
+ static const NodeKindId Id = NKI_##Class; \
+ };
+KIND_TO_KIND_ID(CXXCtorInitializer)
+KIND_TO_KIND_ID(TemplateArgument)
+KIND_TO_KIND_ID(NestedNameSpecifier)
+KIND_TO_KIND_ID(NestedNameSpecifierLoc)
+KIND_TO_KIND_ID(QualType)
+KIND_TO_KIND_ID(TypeLoc)
+KIND_TO_KIND_ID(Decl)
+KIND_TO_KIND_ID(Stmt)
+KIND_TO_KIND_ID(Type)
+#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
+#include "clang/AST/DeclNodes.inc"
+#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
+#include "clang/AST/StmtNodes.inc"
+#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
+#include "clang/AST/TypeNodes.def"
+#undef KIND_TO_KIND_ID
+
/// \brief A dynamically typed AST node container.
///
/// Stores an AST node in a type safe way. This allows writing code that
@@ -32,7 +142,7 @@ namespace ast_type_traits {
/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
/// and \c get<T>() to retrieve the node as type T if the types match.
///
-/// See \c NodeTypeTag for which node base types are currently supported;
+/// See \c ASTNodeKind for which node base types are currently supported;
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
/// the supported base types.
class DynTypedNode {
@@ -49,15 +159,15 @@ public:
/// convertible to \c T.
///
/// For types that have identity via their pointer in the AST
- /// (like \c Stmt and \c Decl) the returned pointer points to the
- /// referenced AST node.
+ /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
+ /// pointer points to the referenced AST node.
/// For other types (like \c QualType) the value is stored directly
/// in the \c DynTypedNode, and the returned pointer points at
/// the storage inside DynTypedNode. For those nodes, do not
/// use the pointer outside the scope of the DynTypedNode.
template <typename T>
const T *get() const {
- return BaseConverter<T>::get(Tag, Storage.buffer);
+ return BaseConverter<T>::get(NodeKind, Storage.buffer);
}
/// \brief Returns a pointer that identifies the stored AST node.
@@ -67,142 +177,171 @@ public:
/// method returns NULL.
const void *getMemoizationData() const;
+ /// \brief Prints the node to the given output stream.
+ void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
+
+ /// \brief Dumps the node to the given output stream.
+ void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
+
+ /// \brief For nodes which represent textual entities in the source code,
+ /// return their SourceRange. For all other nodes, return SourceRange().
+ SourceRange getSourceRange() const;
+
+ /// @{
+ /// \brief Imposes an order on \c DynTypedNode.
+ ///
+ /// Supports comparison of nodes that support memoization.
+ /// FIXME: Implement comparsion for other node types (currently
+ /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
+ bool operator<(const DynTypedNode &Other) const {
+ assert(getMemoizationData() && Other.getMemoizationData());
+ return getMemoizationData() < Other.getMemoizationData();
+ }
+ bool operator==(const DynTypedNode &Other) const {
+ // Nodes with different types cannot be equal.
+ if (!NodeKind.isSame(Other.NodeKind))
+ return false;
+
+ // FIXME: Implement for other types.
+ if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
+ return *get<QualType>() == *Other.get<QualType>();
+ }
+ assert(getMemoizationData() && Other.getMemoizationData());
+ return getMemoizationData() == Other.getMemoizationData();
+ }
+ bool operator!=(const DynTypedNode &Other) const {
+ return !operator==(Other);
+ }
+ /// @}
+
private:
/// \brief Takes care of converting from and to \c T.
template <typename T, typename EnablerT = void> struct BaseConverter;
- /// \brief Supported base node types.
- enum NodeTypeTag {
- NT_Decl,
- NT_Stmt,
- NT_NestedNameSpecifier,
- NT_NestedNameSpecifierLoc,
- NT_QualType,
- NT_Type,
- NT_TypeLoc
- } Tag;
+ /// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
+ template <typename T, typename BaseT> struct DynCastPtrConverter {
+ static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+ if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
+ return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
+ return NULL;
+ }
+ static DynTypedNode create(const BaseT &Node) {
+ DynTypedNode Result;
+ Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ new (Result.Storage.buffer) const BaseT * (&Node);
+ return Result;
+ }
+ };
+
+ /// \brief Converter that stores T* (by pointer).
+ template <typename T> struct PtrConverter {
+ static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+ if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
+ return *reinterpret_cast<T *const *>(Storage);
+ return NULL;
+ }
+ static DynTypedNode create(const T &Node) {
+ DynTypedNode Result;
+ Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ new (Result.Storage.buffer) const T * (&Node);
+ return Result;
+ }
+ };
+
+ /// \brief Converter that stores T (by value).
+ template <typename T> struct ValueConverter {
+ static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+ if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
+ return reinterpret_cast<const T *>(Storage);
+ return NULL;
+ }
+ static DynTypedNode create(const T &Node) {
+ DynTypedNode Result;
+ Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ new (Result.Storage.buffer) T(Node);
+ return Result;
+ }
+ };
+
+ ASTNodeKind NodeKind;
/// \brief Stores the data of the node.
///
- /// Note that we can store \c Decls and \c Stmts by pointer as they are
- /// guaranteed to be unique pointers pointing to dedicated storage in the
- /// AST. \c QualTypes on the other hand do not have storage or unique
+ /// Note that we can store \c Decls, \c Stmts, \c Types,
+ /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
+ /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
+ /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
+ /// \c TemplateArguments on the other hand do not have storage or unique
/// pointers and thus need to be stored by value.
- llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
- NestedNameSpecifierLoc, QualType, Type,
- TypeLoc> Storage;
+ typedef llvm::AlignedCharArrayUnion<
+ Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
+ KindsByPointer;
+ llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
+ NestedNameSpecifierLoc, QualType, TypeLoc>
+ Storage;
};
-// FIXME: Pull out abstraction for the following.
-template<typename T> struct DynTypedNode::BaseConverter<T,
- typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
- static const T *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_Decl)
- return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
- return NULL;
- }
- static DynTypedNode create(const Decl &Node) {
- DynTypedNode Result;
- Result.Tag = NT_Decl;
- new (Result.Storage.buffer) const Decl*(&Node);
- return Result;
- }
-};
-template<typename T> struct DynTypedNode::BaseConverter<T,
- typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
- static const T *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_Stmt)
- return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
- return NULL;
- }
- static DynTypedNode create(const Stmt &Node) {
- DynTypedNode Result;
- Result.Tag = NT_Stmt;
- new (Result.Storage.buffer) const Stmt*(&Node);
- return Result;
- }
-};
-template<typename T> struct DynTypedNode::BaseConverter<T,
- typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
- static const T *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_Type)
- return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
- return NULL;
- }
- static DynTypedNode create(const Type &Node) {
- DynTypedNode Result;
- Result.Tag = NT_Type;
- new (Result.Storage.buffer) const Type*(&Node);
- return Result;
- }
-};
-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
- static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_NestedNameSpecifier)
- return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
- return NULL;
- }
- static DynTypedNode create(const NestedNameSpecifier &Node) {
- DynTypedNode Result;
- Result.Tag = NT_NestedNameSpecifier;
- new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
- return Result;
- }
-};
-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
- static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
- const char Storage[]) {
- if (Tag == NT_NestedNameSpecifierLoc)
- return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
- return NULL;
- }
- static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
- DynTypedNode Result;
- Result.Tag = NT_NestedNameSpecifierLoc;
- new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
- return Result;
- }
-};
-template<> struct DynTypedNode::BaseConverter<QualType, void> {
- static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_QualType)
- return reinterpret_cast<const QualType*>(Storage);
- return NULL;
- }
- static DynTypedNode create(const QualType &Node) {
- DynTypedNode Result;
- Result.Tag = NT_QualType;
- new (Result.Storage.buffer) QualType(Node);
- return Result;
- }
-};
-template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
- static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
- if (Tag == NT_TypeLoc)
- return reinterpret_cast<const TypeLoc*>(Storage);
- return NULL;
- }
- static DynTypedNode create(const TypeLoc &Node) {
- DynTypedNode Result;
- Result.Tag = NT_TypeLoc;
- new (Result.Storage.buffer) TypeLoc(Node);
- return Result;
- }
-};
+template <typename T>
+struct DynTypedNode::BaseConverter<
+ T, typename llvm::enable_if<llvm::is_base_of<
+ Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
+
+template <typename T>
+struct DynTypedNode::BaseConverter<
+ T, typename llvm::enable_if<llvm::is_base_of<
+ Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
+
+template <typename T>
+struct DynTypedNode::BaseConverter<
+ T, typename llvm::enable_if<llvm::is_base_of<
+ Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
+
+template <>
+struct DynTypedNode::BaseConverter<
+ NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
+
+template <>
+struct DynTypedNode::BaseConverter<
+ CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
+
+template <>
+struct DynTypedNode::BaseConverter<
+ TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
+
+template <>
+struct DynTypedNode::BaseConverter<
+ NestedNameSpecifierLoc,
+ void> : public ValueConverter<NestedNameSpecifierLoc> {};
+
+template <>
+struct DynTypedNode::BaseConverter<QualType,
+ void> : public ValueConverter<QualType> {};
+
+template <>
+struct DynTypedNode::BaseConverter<
+ TypeLoc, void> : public ValueConverter<TypeLoc> {};
+
// The only operation we allow on unsupported types is \c get.
// This allows to conveniently use \c DynTypedNode when having an arbitrary
// AST node that is not supported, but prevents misuse - a user cannot create
// a DynTypedNode from arbitrary types.
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
- static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
+ static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+ return NULL;
+ }
};
inline const void *DynTypedNode::getMemoizationData() const {
- switch (Tag) {
- case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
- case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
- default: return NULL;
- };
+ if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
+ return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
+ } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
+ return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
+ } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
+ return BaseConverter<Type>::get(NodeKind, Storage.buffer);
+ } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
+ return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
+ }
+ return NULL;
}
} // end namespace ast_type_traits
diff --git a/include/clang/AST/ASTUnresolvedSet.h b/include/clang/AST/ASTUnresolvedSet.h
index 5a56b4d2b46d..e8be67006c5b 100644
--- a/include/clang/AST/ASTUnresolvedSet.h
+++ b/include/clang/AST/ASTUnresolvedSet.h
@@ -22,12 +22,21 @@ namespace clang {
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
class ASTUnresolvedSet {
- typedef ASTVector<DeclAccessPair> DeclsTy;
+ struct DeclsTy : ASTVector<DeclAccessPair> {
+ DeclsTy() {}
+ DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {}
+
+ bool isLazy() const { return getTag(); }
+ void setLazy(bool Lazy) { setTag(Lazy); }
+ };
+
DeclsTy Decls;
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
+ friend class LazyASTUnresolvedSet;
+
public:
ASTUnresolvedSet() {}
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
@@ -48,7 +57,7 @@ public:
/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
- bool replace(const NamedDecl* Old, NamedDecl *New, AccessSpecifier AS) {
+ bool replace(const NamedDecl *Old, NamedDecl *New, AccessSpecifier AS) {
for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
if (I->getDecl() == Old) {
I->set(New, AS);
@@ -58,10 +67,7 @@ public:
return false;
}
- void erase(unsigned I) {
- Decls[I] = Decls.back();
- Decls.pop_back();
- }
+ void erase(unsigned I) { Decls[I] = Decls.pop_back_val(); }
void clear() { Decls.clear(); }
@@ -79,7 +85,29 @@ public:
DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
};
-
+
+/// \brief An UnresolvedSet-like class that might not have been loaded from the
+/// external AST source yet.
+class LazyASTUnresolvedSet {
+ mutable ASTUnresolvedSet Impl;
+
+ void getFromExternalSource(ASTContext &C) const;
+
+public:
+ ASTUnresolvedSet &get(ASTContext &C) const {
+ if (Impl.Decls.isLazy())
+ getFromExternalSource(C);
+ return Impl;
+ }
+
+ void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
+ void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
+ assert(Impl.empty() || Impl.Decls.isLazy());
+ Impl.Decls.setLazy(true);
+ Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS);
+ }
+};
+
} // namespace clang
#endif
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
index 669e50dbeb87..6db918eaa631 100644
--- a/include/clang/AST/ASTVector.h
+++ b/include/clang/AST/ASTVector.h
@@ -55,16 +55,24 @@ namespace clang {
template<typename T>
class ASTVector {
- T *Begin, *End, *Capacity;
+private:
+ T *Begin, *End;
+ llvm::PointerIntPair<T*, 1, bool> Capacity;
void setEnd(T *P) { this->End = P; }
+protected:
+ // Make a tag bit available to users of this class.
+ // FIXME: This is a horrible hack.
+ bool getTag() const { return Capacity.getInt(); }
+ void setTag(bool B) { Capacity.setInt(B); }
+
public:
// Default ctor - Initialize to empty.
- ASTVector() : Begin(NULL), End(NULL), Capacity(NULL) { }
+ ASTVector() : Begin(0), End(0), Capacity(0, false) {}
- ASTVector(ASTContext &C, unsigned N)
- : Begin(NULL), End(NULL), Capacity(NULL) {
+ ASTVector(const ASTContext &C, unsigned N)
+ : Begin(0), End(0), Capacity(0, false) {
reserve(C, N);
}
@@ -155,8 +163,8 @@ public:
return const_pointer(Begin);
}
- void push_back(const_reference Elt, ASTContext &C) {
- if (End < Capacity) {
+ void push_back(const_reference Elt, const ASTContext &C) {
+ if (End < this->capacity_ptr()) {
Retry:
new (End) T(Elt);
++End;
@@ -166,19 +174,19 @@ public:
goto Retry;
}
- void reserve(ASTContext &C, unsigned N) {
- if (unsigned(Capacity-Begin) < N)
+ void reserve(const ASTContext &C, unsigned N) {
+ if (unsigned(this->capacity_ptr()-Begin) < N)
grow(C, N);
}
/// capacity - Return the total number of elements in the currently allocated
/// buffer.
- size_t capacity() const { return Capacity - Begin; }
+ size_t capacity() const { return this->capacity_ptr() - Begin; }
/// append - Add the specified range to the end of the SmallVector.
///
template<typename in_iter>
- void append(ASTContext &C, in_iter in_start, in_iter in_end) {
+ void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
size_type NumInputs = std::distance(in_start, in_end);
if (NumInputs == 0)
@@ -197,7 +205,7 @@ public:
/// append - Add the specified range to the end of the SmallVector.
///
- void append(ASTContext &C, size_type NumInputs, const T &Elt) {
+ void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
// Grow allocated space if needed.
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
this->grow(C, this->size()+NumInputs);
@@ -214,13 +222,13 @@ public:
std::uninitialized_copy(I, E, Dest);
}
- iterator insert(ASTContext &C, iterator I, const T &Elt) {
+ iterator insert(const ASTContext &C, iterator I, const T &Elt) {
if (I == this->end()) { // Important special case for empty vector.
- push_back(Elt);
+ push_back(Elt, C);
return this->end()-1;
}
- if (this->EndX < this->CapacityX) {
+ if (this->End < this->capacity_ptr()) {
Retry:
new (this->end()) T(this->back());
this->setEnd(this->end()+1);
@@ -235,7 +243,7 @@ public:
goto Retry;
}
- iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
+ iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
const T &Elt) {
if (I == this->end()) { // Important special case for empty vector.
append(C, NumToInsert, Elt);
@@ -284,7 +292,7 @@ public:
}
template<typename ItTy>
- iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) {
+ iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
if (I == this->end()) { // Important special case for empty vector.
append(C, From, To);
return this->end()-1;
@@ -335,7 +343,7 @@ public:
return I;
}
- void resize(ASTContext &C, unsigned N, const T &NV) {
+ void resize(const ASTContext &C, unsigned N, const T &NV) {
if (N < this->size()) {
this->destroy_range(this->begin()+N, this->end());
this->setEnd(this->begin()+N);
@@ -350,7 +358,7 @@ public:
private:
/// grow - double the size of the allocated memory, guaranteeing space for at
/// least one more element or MinSize if specified.
- void grow(ASTContext &C, size_type MinSize = 1);
+ void grow(const ASTContext &C, size_type MinSize = 1);
void construct_range(T *S, T *E, const T &Elt) {
for (; S != E; ++S)
@@ -365,13 +373,16 @@ private:
}
protected:
- iterator capacity_ptr() { return (iterator)this->Capacity; }
+ const_iterator capacity_ptr() const {
+ return (iterator) Capacity.getPointer();
+ }
+ iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
};
// Define this out-of-line to dissuade the C++ compiler from inlining it.
template <typename T>
-void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
- size_t CurCapacity = Capacity-Begin;
+void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
+ size_t CurCapacity = this->capacity();
size_t CurSize = size();
size_t NewCapacity = 2*CurCapacity;
if (NewCapacity < MinSize)
@@ -394,7 +405,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
// ASTContext never frees any memory.
Begin = NewElts;
End = NewElts+CurSize;
- Capacity = Begin+NewCapacity;
+ Capacity.setPointer(Begin+NewCapacity);
}
} // end: clang namespace
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 27dcef2a1e98..7dbf41350a0f 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_ATTR_H
#include "clang/AST/AttrIterator.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
@@ -145,7 +146,7 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
// Relies on relative order of enum emission with respect to param attrs.
- return (A->getKind() <= attr::LAST_MS_INHERITABLE &&
+ return (A->getKind() <= attr::LAST_MS_INHERITANCE &&
A->getKind() > attr::LAST_INHERITABLE_PARAM);
}
};
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index 2983e04cda34..dbe4ad0f5a1d 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -287,9 +287,9 @@ public:
// Iterate over the set of overriding virtual methods in a given
// subobject.
- typedef SmallVector<UniqueVirtualMethod, 4>::iterator
+ typedef SmallVectorImpl<UniqueVirtualMethod>::iterator
overriding_iterator;
- typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
+ typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator
overriding_const_iterator;
// Add a new overriding method for a particular subobject.
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 946075739d06..9c699b7e0ae2 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -81,7 +81,7 @@ public:
operator QualType() const { return Stored; }
/// \brief Implicit conversion to bool.
- operator bool() const { return !isNull(); }
+ LLVM_EXPLICIT operator bool() const { return !isNull(); }
bool isNull() const {
return Stored.isNull();
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 082c672c2191..09ff6828ef5c 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -19,21 +19,20 @@
#include "llvm/Support/MathExtras.h"
namespace clang {
-
+
/// CharUnits - This is an opaque type for sizes expressed in character units.
- /// Instances of this type represent a quantity as a multiple of the size
+ /// Instances of this type represent a quantity as a multiple of the size
/// of the standard C type, char, on the target architecture. As an opaque
/// type, CharUnits protects you from accidentally combining operations on
- /// quantities in bit units and character units.
+ /// quantities in bit units and character units.
+ ///
+ /// In both C and C++, an object of type 'char', 'signed char', or 'unsigned
+ /// char' occupies exactly one byte, so 'character unit' and 'byte' refer to
+ /// the same quantity of storage. However, we use the term 'character unit'
+ /// rather than 'byte' to avoid an implication that a character unit is
+ /// exactly 8 bits.
///
- /// It should be noted that characters and bytes are distinct concepts. Bytes
- /// refer to addressable units of data storage on the target machine, and
- /// characters are members of a set of elements used for the organization,
- /// control, or representation of data. According to C99, bytes are allowed
- /// to exceed characters in size, although currently, clang only supports
- /// architectures where the two are the same size.
- ///
- /// For portability, never assume that a target character is 8 bits wide. Use
+ /// For portability, never assume that a target character is 8 bits wide. Use
/// CharUnit values wherever you calculate sizes, offsets, or alignments
/// in character units.
class CharUnits {
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index c02a82f0fa55..28849f58a8ec 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -699,7 +699,10 @@ private:
unsigned ParamIndex;
public:
- enum { InvalidParamIndex = ~0U };
+ enum LLVM_ENUM_INT_TYPE(unsigned) {
+ InvalidParamIndex = ~0U,
+ VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
+ };
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
@@ -755,14 +758,25 @@ public:
return ParamIndex != InvalidParamIndex;
}
+ bool isVarArgParam() const LLVM_READONLY {
+ return ParamIndex == VarArgParamIndex;
+ }
+
+ void setIsVarArgParam() {
+ ParamIndex = VarArgParamIndex;
+ assert(isParamIndexValid());
+ }
+
unsigned getParamIndex() const LLVM_READONLY {
assert(isParamIndexValid());
+ assert(!isVarArgParam());
return ParamIndex;
}
void setParamIndex(unsigned Index) {
ParamIndex = Index;
assert(isParamIndexValid());
+ assert(!isVarArgParam());
}
};
@@ -1097,10 +1111,6 @@ public:
return ThisDeclInfo;
}
- DeclInfo *getThisDeclInfo() const LLVM_READONLY {
- return ThisDeclInfo;
- }
-
ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
};
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index d1f5209d1eef..dde7a1442fe1 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -67,6 +67,9 @@ struct CommandInfo {
/// a template parameter (\\tparam or an alias).
unsigned IsTParamCommand : 1;
+ /// True if this command is \\throws or an alias.
+ unsigned IsThrowsCommand : 1;
+
/// True if this command is \\deprecated or an alias.
unsigned IsDeprecatedCommand : 1;
@@ -142,6 +145,8 @@ public:
llvm_unreachable("the command should be known");
}
+ const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const;
+
const CommandInfo *getCommandInfo(unsigned CommandID) const;
const CommandInfo *registerUnknownCommand(StringRef CommandName);
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
index 8c88494e9ae4..ed323daa9f8b 100644
--- a/include/clang/AST/CommentCommands.td
+++ b/include/clang/AST/CommentCommands.td
@@ -15,6 +15,7 @@ class Command<string name> {
bit IsReturnsCommand = 0;
bit IsParamCommand = 0;
bit IsTParamCommand = 0;
+ bit IsThrowsCommand = 0;
bit IsDeprecatedCommand = 0;
bit IsHeaderfileCommand = 0;
@@ -109,6 +110,10 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
// HeaderDoc command for template parameter documentation.
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
+def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
+def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
+def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
+
def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1;
let IsDeprecatedCommand = 1;
@@ -200,11 +205,17 @@ def Mainpage : VerbatimLineCommand<"mainpage">;
def Subpage : VerbatimLineCommand<"subpage">;
def Ref : VerbatimLineCommand<"ref">;
+def Relates : VerbatimLineCommand<"relates">;
+def Related : VerbatimLineCommand<"related">;
+def RelatesAlso : VerbatimLineCommand<"relatesalso">;
+def RelatedAlso : VerbatimLineCommand<"relatedalso">;
+
//===----------------------------------------------------------------------===//
// DeclarationVerbatimLineCommand
//===----------------------------------------------------------------------===//
// Doxygen commands.
+def Def : DeclarationVerbatimLineCommand<"def">;
def Fn : DeclarationVerbatimLineCommand<"fn">;
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
def Overload : DeclarationVerbatimLineCommand<"overload">;
diff --git a/include/clang/AST/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h
index 6e8941057994..312da065ff59 100644
--- a/include/clang/AST/CommentDiagnostic.h
+++ b/include/clang/AST/CommentDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define COMMENTSTART
#include "clang/Basic/DiagnosticCommentKinds.inc"
#undef DIAG
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index d6a1072786ed..7e008131d205 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -61,10 +61,8 @@ class Parser {
void consumeToken() {
if (MoreLATokens.empty())
L.lex(Tok);
- else {
- Tok = MoreLATokens.back();
- MoreLATokens.pop_back();
- }
+ else
+ Tok = MoreLATokens.pop_back_val();
}
void putBack(const Token &OldTok) {
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 15e454dcc389..39109602b148 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -58,9 +58,6 @@ class Sema {
/// AST node for the \\brief command and its aliases.
const BlockCommandComment *BriefCommand;
- /// AST node for the \\returns command and its aliases.
- const BlockCommandComment *ReturnsCommand;
-
/// AST node for the \\headerfile command.
const BlockCommandComment *HeaderfileCommand;
@@ -211,7 +208,11 @@ public:
bool isFunctionDecl();
bool isAnyFunctionDecl();
+
+ /// \returns \c true if declaration that this comment is attached to declares
+ /// a function pointer.
bool isFunctionPointerVarDecl();
+ bool isFunctionOrMethodVariadic();
bool isObjCMethodDecl();
bool isObjCPropertyDecl();
bool isTemplateOrSpecialization();
@@ -220,6 +221,8 @@ public:
bool isUnionDecl();
bool isObjCInterfaceDecl();
bool isObjCProtocolDecl();
+ bool isClassTemplateDecl();
+ bool isFunctionTemplateDecl();
ArrayRef<const ParmVarDecl *> getParamVars();
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index a0c76c069b86..244a7b8d400c 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
struct ASTTemplateArgumentListInfo;
@@ -43,6 +44,7 @@ class TemplateArgumentList;
class TemplateParameterList;
class TypeLoc;
class UnresolvedSetImpl;
+class VarTemplateDecl;
/// \brief A container of type source information.
///
@@ -109,7 +111,6 @@ class NamedDecl : public Decl {
private:
NamedDecl *getUnderlyingDeclImpl();
- void verifyLinkage() const;
protected:
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
@@ -142,7 +143,7 @@ public:
// FIXME: Deprecated, move clients to getName().
std::string getNameAsString() const { return Name.getAsString(); }
- void printName(raw_ostream &os) const { return Name.printName(os); }
+ void printName(raw_ostream &os) const { os << Name; }
/// getDeclName - Get the actual, stored name of the declaration,
/// which may be a special name.
@@ -189,10 +190,13 @@ 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) { Hidden = Hide; }
+
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
@@ -212,11 +216,24 @@ public:
bool isCXXInstanceMember() const;
/// \brief Determine what kind of linkage this entity has.
- Linkage getLinkage() const;
+ /// This is not the linkage as defined by the standard or the codegen notion
+ /// of linkage. It is just an implementation detail that is used to compute
+ /// those.
+ Linkage getLinkageInternal() const;
+
+ /// \brief Get the linkage from a semantic point of view. Entities in
+ /// anonymous namespaces are external (in c++98).
+ Linkage getFormalLinkage() const {
+ return clang::getFormalLinkage(getLinkageInternal());
+ }
/// \brief True if this decl has external linkage.
- bool hasExternalLinkage() const {
- return getLinkage() == ExternalLinkage;
+ bool hasExternalFormalLinkage() const {
+ return isExternalFormalLinkage(getLinkageInternal());
+ }
+
+ bool isExternallyVisible() const {
+ return clang::isExternallyVisible(getLinkageInternal());
}
/// \brief Determines the visibility of this entity.
@@ -256,6 +273,13 @@ public:
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
}
+ NamedDecl *getMostRecentDecl() {
+ return cast<NamedDecl>(static_cast<Decl *>(this)->getMostRecentDecl());
+ }
+ const NamedDecl *getMostRecentDecl() const {
+ return const_cast<NamedDecl*>(this)->getMostRecentDecl();
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
@@ -351,6 +375,7 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
/// \brief Returns true if this is an anonymous namespace declaration.
///
@@ -377,7 +402,7 @@ public:
/// \brief Get the original (first) namespace declaration.
NamespaceDecl *getOriginalNamespace() {
- if (isFirstDeclaration())
+ if (isFirstDecl())
return this;
return AnonOrFirstNamespaceAndInline.getPointer();
@@ -385,7 +410,7 @@ public:
/// \brief Get the original (first) namespace declaration.
const NamespaceDecl *getOriginalNamespace() const {
- if (isFirstDeclaration())
+ if (isFirstDecl())
return this;
return AnonOrFirstNamespaceAndInline.getPointer();
@@ -394,9 +419,7 @@ public:
/// \brief Return true if this declaration is an original (first) declaration
/// of the namespace. This is false for non-original (subsequent) namespace
/// declarations and anonymous namespaces.
- bool isOriginalNamespace() const {
- return isFirstDeclaration();
- }
+ bool isOriginalNamespace() const { return isFirstDecl(); }
/// \brief Retrieve the anonymous namespace nested inside this namespace,
/// if any.
@@ -689,11 +712,21 @@ private:
/// \brief Whether this variable is (C++0x) constexpr.
unsigned IsConstexpr : 1;
+
+ /// \brief Whether this variable is the implicit variable for a lambda
+ /// init-capture.
+ unsigned IsInitCapture : 1;
+
+ /// \brief Whether this local extern variable's previous declaration was
+ /// declared in the same block scope. This controls whether we should merge
+ /// the type of this declaration with its previous declaration.
+ unsigned PreviousDeclInSameBlockScope : 1;
};
- enum { NumVarDeclBits = 12 };
+ enum { NumVarDeclBits = 14 };
friend class ASTDeclReader;
friend class StmtIteratorBase;
+ friend class ASTNodeImporter;
protected:
enum { NumParameterIndexBits = 8 };
@@ -732,15 +765,8 @@ protected:
};
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, StorageClass SC)
- : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
- assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
- assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
- AllBits = 0;
- VarDeclBits.SClass = SC;
- // Everything else is implicitly initialized to false.
- }
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC);
typedef Redeclarable<VarDecl> redeclarable_base;
virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
@@ -757,6 +783,7 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
@@ -797,7 +824,8 @@ public:
/// is a non-static local variable.
bool hasLocalStorage() const {
if (getStorageClass() == SC_None)
- return !isFileVarDecl();
+ // Second check is for C++11 [dcl.stc]p4.
+ return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
// Return true for: Auto, Register.
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
@@ -808,7 +836,10 @@ public:
/// isStaticLocal - Returns true if a variable with function scope is a
/// static local variable.
bool isStaticLocal() const {
- return getStorageClass() == SC_Static && !isFileVarDecl();
+ return (getStorageClass() == SC_Static ||
+ // C++11 [dcl.stc]p4
+ (getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local))
+ && !isFileVarDecl();
}
/// \brief Returns true if a variable has extern or __private_extern__
@@ -818,12 +849,19 @@ public:
getStorageClass() == SC_PrivateExtern;
}
- /// hasGlobalStorage - Returns true for all variables that do not
- /// have local storage. This includs all global variables as well
- /// as static variables declared within a function.
+ /// \brief Returns true for all variables that do not have local storage.
+ ///
+ /// This includes all global variables as well as static variables declared
+ /// within a function.
bool hasGlobalStorage() const { return !hasLocalStorage(); }
- /// Compute the language linkage.
+ /// \brief Get the storage duration of this variable, per C++ [basic.stc].
+ StorageDuration getStorageDuration() const {
+ return hasLocalStorage() ? SD_Automatic :
+ getTSCSpec() ? SD_Thread : SD_Static;
+ }
+
+ /// \brief Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
/// \brief Determines whether this variable is a variable with
@@ -847,7 +885,7 @@ public:
bool isLocalVarDecl() const {
if (getKind() != Decl::Var)
return false;
- if (const DeclContext *DC = getDeclContext())
+ if (const DeclContext *DC = getLexicalDeclContext())
return DC->getRedeclContext()->isFunctionOrMethod();
return false;
}
@@ -857,7 +895,7 @@ public:
bool isFunctionOrMethodVarDecl() const {
if (getKind() != Decl::Var)
return false;
- const DeclContext *DC = getDeclContext()->getRedeclContext();
+ const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
}
@@ -908,10 +946,6 @@ public:
return const_cast<VarDecl*>(this)->getActingDefinition();
}
- /// \brief Determine whether this is a tentative definition of a
- /// variable in C.
- bool isTentativeDefinitionNow() const;
-
/// \brief Get the real (not just tentative) definition for this declaration.
VarDecl *getDefinition(ASTContext &);
const VarDecl *getDefinition(ASTContext &C) const {
@@ -933,10 +967,11 @@ public:
/// isFileVarDecl - Returns true for file scoped variable declaration.
bool isFileVarDecl() const {
- if (getKind() != Decl::Var)
+ Kind K = getKind();
+ if (K == ParmVar || K == ImplicitParam)
return false;
- if (getDeclContext()->getRedeclContext()->isFileContext())
+ if (getLexicalDeclContext()->getRedeclContext()->isFileContext())
return true;
if (isStaticDataMember())
@@ -1000,20 +1035,6 @@ public:
void setInit(Expr *I);
- /// \brief Determine whether this variable is a reference that
- /// extends the lifetime of its temporary initializer.
- ///
- /// A reference extends the lifetime of its temporary initializer if
- /// it's initializer is an rvalue that would normally go out of scope
- /// at the end of the initializer (a full expression). In such cases,
- /// the reference itself takes ownership of the temporary, which will
- /// be destroyed when the reference goes out of scope. For example:
- ///
- /// \code
- /// const int &r = 1.0; // creates a temporary of type 'int'
- /// \endcode
- bool extendsLifetimeOfTemporary() const;
-
/// \brief Determine whether this variable's value can be used in a
/// constant expression, according to the relevant language standard.
/// This only checks properties of the declaration, and does not check
@@ -1123,15 +1144,34 @@ public:
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
+ /// Whether this variable is the implicit variable for a lambda init-capture.
+ bool isInitCapture() const { return VarDeclBits.IsInitCapture; }
+ void setInitCapture(bool IC) { VarDeclBits.IsInitCapture = IC; }
+
+ /// Whether this local extern variable declaration's previous declaration
+ /// was declared in the same block scope. Only correct in C++.
+ bool isPreviousDeclInSameBlockScope() const {
+ return VarDeclBits.PreviousDeclInSameBlockScope;
+ }
+ void setPreviousDeclInSameBlockScope(bool Same) {
+ VarDeclBits.PreviousDeclInSameBlockScope = Same;
+ }
+
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
VarDecl *getInstantiatedFromStaticDataMember() const;
- /// \brief If this variable is a static data member, determine what kind of
+ /// \brief If this variable is an instantiation of a variable template or a
+ /// static data member of a class template, determine what kind of
/// template specialization or instantiation this is.
TemplateSpecializationKind getTemplateSpecializationKind() const;
+ /// \brief If this variable is an instantiation of a variable template or a
+ /// static data member of a class template, determine its point of
+ /// instantiation.
+ SourceLocation getPointOfInstantiation() const;
+
/// \brief If this variable is an instantiation of a static data member of a
/// class template specialization, retrieves the member specialization
/// information.
@@ -1142,6 +1182,26 @@ public:
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation());
+ /// \brief Specify that this variable is an instantiation of the
+ /// static data member VD.
+ void setInstantiationOfStaticDataMember(VarDecl *VD,
+ TemplateSpecializationKind TSK);
+
+ /// \brief Retrieves the variable template that is described by this
+ /// variable declaration.
+ ///
+ /// Every variable template is represented as a VarTemplateDecl and a
+ /// VarDecl. The former contains template properties (such as
+ /// the template parameter lists) while the latter contains the
+ /// actual description of the template's
+ /// contents. VarTemplateDecl::getTemplatedDecl() retrieves the
+ /// VarDecl that from a VarTemplateDecl, while
+ /// getDescribedVarTemplate() retrieves the VarTemplateDecl from
+ /// a VarDecl.
+ VarTemplateDecl *getDescribedVarTemplate() const;
+
+ void setDescribedVarTemplate(VarTemplateDecl *Template);
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
@@ -1314,11 +1374,7 @@ public:
ParmVarDeclBits.HasInheritedDefaultArg = I;
}
- QualType getOriginalType() const {
- if (getTypeSourceInfo())
- return getTypeSourceInfo()->getType();
- return getType();
- }
+ QualType getOriginalType() const;
/// \brief Determine whether this parameter is actually a function
/// parameter pack.
@@ -1517,6 +1573,7 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation NLoc,
@@ -1701,6 +1758,10 @@ public:
/// entry point into an executable program.
bool isMain() const;
+ /// \brief Determines whether this function is a MSVCRT user defined entry
+ /// point.
+ bool isMSVCRTEntryPoint() const;
+
/// \brief Determines whether this operator new or delete is one
/// of the reserved global placement operators:
/// void *operator new(size_t, void *);
@@ -1716,6 +1777,28 @@ public:
/// This function must be an allocation or deallocation function.
bool isReservedGlobalPlacementOperator() const;
+ /// \brief Determines whether this function is one of the replaceable
+ /// global allocation functions:
+ /// void *operator new(size_t);
+ /// void *operator new(size_t, const std::nothrow_t &) noexcept;
+ /// void *operator new[](size_t);
+ /// void *operator new[](size_t, const std::nothrow_t &) noexcept;
+ /// void operator delete(void *) noexcept;
+ /// void operator delete(void *, std::size_t) noexcept; [C++1y]
+ /// void operator delete(void *, const std::nothrow_t &) noexcept;
+ /// void operator delete[](void *) noexcept;
+ /// void operator delete[](void *, std::size_t) noexcept; [C++1y]
+ /// void operator delete[](void *, const std::nothrow_t &) noexcept;
+ /// 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;
+
+ /// \brief Determine whether this function is a sized global deallocation
+ /// function in C++1y. If so, find and return the corresponding unsized
+ /// deallocation function.
+ FunctionDecl *getCorrespondingUnsizedGlobalDeallocationFunction() const;
+
/// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
@@ -2039,7 +2122,7 @@ 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 {
+class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
// FIXME: This can be packed into the bitfields in Decl.
bool Mutable : 1;
mutable unsigned CachedFieldIndex : 31;
@@ -2153,6 +2236,10 @@ public:
SourceRange getSourceRange() const LLVM_READONLY;
+ /// Retrieves the canonical declaration of this field.
+ FieldDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
@@ -2165,7 +2252,7 @@ public:
/// that is defined. For example, in "enum X {a,b}", each of a/b are
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
/// TagType for the X EnumDecl.
-class EnumConstantDecl : public ValueDecl {
+class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
Stmt *Init; // an integer constant expression
llvm::APSInt Val; // The value.
protected:
@@ -2191,6 +2278,10 @@ public:
SourceRange getSourceRange() const LLVM_READONLY;
+ /// Retrieves the canonical declaration of this enumerator.
+ EnumConstantDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const EnumConstantDecl *getCanonicalDecl() const { return getFirstDecl(); }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == EnumConstant; }
@@ -2289,14 +2380,14 @@ public:
/// Base class for declarations which introduce a typedef-name.
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
virtual void anchor();
- /// UnderlyingType - This is the type the typedef is set to.
- TypeSourceInfo *TInfo;
+ typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
+ llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
protected:
TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
TypeSourceInfo *TInfo)
- : TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {}
+ : TypeDecl(DK, DC, IdLoc, Id, StartLoc), MaybeModedTInfo(TInfo) {}
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
virtual TypedefNameDecl *getNextRedeclaration() {
@@ -2315,26 +2406,31 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
- TypeSourceInfo *getTypeSourceInfo() const {
- return TInfo;
- }
+ bool isModed() const { return MaybeModedTInfo.is<ModedTInfo*>(); }
- /// Retrieves the canonical declaration of this typedef-name.
- TypedefNameDecl *getCanonicalDecl() {
- return getFirstDeclaration();
- }
- const TypedefNameDecl *getCanonicalDecl() const {
- return getFirstDeclaration();
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return isModed()
+ ? MaybeModedTInfo.get<ModedTInfo*>()->first
+ : MaybeModedTInfo.get<TypeSourceInfo*>();
}
-
QualType getUnderlyingType() const {
- return TInfo->getType();
+ return isModed()
+ ? MaybeModedTInfo.get<ModedTInfo*>()->second
+ : MaybeModedTInfo.get<TypeSourceInfo*>()->getType();
}
void setTypeSourceInfo(TypeSourceInfo *newType) {
- TInfo = newType;
+ MaybeModedTInfo = newType;
+ }
+ void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) {
+ MaybeModedTInfo = new (getASTContext()) ModedTInfo(unmodedTSI, modedTy);
}
+ /// Retrieves the canonical declaration of this typedef-name.
+ TypedefNameDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
@@ -2436,6 +2532,9 @@ protected:
/// This option is only enabled when modules are enabled.
bool MayHaveOutOfDateDef : 1;
+ /// Has the full definition of this type been required by a use somewhere in
+ /// the TU.
+ bool IsCompleteDefinitionRequired : 1;
private:
SourceLocation RBraceLoc;
@@ -2443,33 +2542,33 @@ private:
// to be used for the (uncommon) case of out-of-line declarations.
typedef QualifierInfo ExtInfo;
- /// TypedefNameDeclOrQualifier - If the (out-of-line) tag declaration name
+ /// \brief If the (out-of-line) tag declaration name
/// is qualified, it points to the qualifier info (nns and range);
/// otherwise, if the tag declaration is anonymous and it is part of
/// a typedef or alias, it points to the TypedefNameDecl (used for mangling);
+ /// otherwise, if the tag declaration is anonymous and it is used as a
+ /// declaration specifier for variables, it points to the first VarDecl (used
+ /// for mangling);
/// otherwise, it is a null (TypedefNameDecl) pointer.
- llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier;
+ llvm::PointerUnion<NamedDecl *, ExtInfo *> NamedDeclOrQualifier;
- bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); }
- ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); }
+ bool hasExtInfo() const { return NamedDeclOrQualifier.is<ExtInfo *>(); }
+ ExtInfo *getExtInfo() { return NamedDeclOrQualifier.get<ExtInfo *>(); }
const ExtInfo *getExtInfo() const {
- return TypedefNameDeclOrQualifier.get<ExtInfo*>();
+ return NamedDeclOrQualifier.get<ExtInfo *>();
}
protected:
- TagDecl(Kind DK, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TagDecl *PrevDecl, SourceLocation StartL)
- : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK),
- TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) {
+ TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL)
+ : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), TagDeclKind(TK),
+ IsCompleteDefinition(false), IsBeingDefined(false),
+ IsEmbeddedInDeclarator(false), IsFreeStanding(false),
+ IsCompleteDefinitionRequired(false),
+ NamedDeclOrQualifier((NamedDecl *)0) {
assert((DK != Enum || TK == TTK_Enum) &&
"EnumDecl not matched with TTK_Enum");
- TagDeclKind = TK;
- IsCompleteDefinition = false;
- IsBeingDefined = false;
- IsEmbeddedInDeclarator = false;
- IsFreeStanding = false;
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
}
typedef Redeclarable<TagDecl> redeclarable_base;
@@ -2492,6 +2591,7 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
@@ -2522,6 +2622,12 @@ public:
return IsCompleteDefinition;
}
+ /// \brief Return true if this complete decl is
+ /// required to be complete for some existing use.
+ bool isCompleteDefinitionRequired() const {
+ return IsCompleteDefinitionRequired;
+ }
+
/// isBeingDefined - Return true if this decl is currently being defined.
bool isBeingDefined() const {
return IsBeingDefined;
@@ -2563,6 +2669,10 @@ public:
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
+ void setCompleteDefinitionRequired(bool V = true) {
+ IsCompleteDefinitionRequired = V;
+ }
+
// FIXME: Return StringRef;
const char *getKindName() const {
return TypeWithKeyword::getTagTypeKindName(getTagKind());
@@ -2599,11 +2709,22 @@ public:
return (getDeclName() || getTypedefNameForAnonDecl());
}
+ bool hasDeclaratorForAnonDecl() const {
+ return dyn_cast_or_null<DeclaratorDecl>(
+ NamedDeclOrQualifier.get<NamedDecl *>());
+ }
+ DeclaratorDecl *getDeclaratorForAnonDecl() const {
+ return hasExtInfo() ? 0 : dyn_cast_or_null<DeclaratorDecl>(
+ NamedDeclOrQualifier.get<NamedDecl *>());
+ }
+
TypedefNameDecl *getTypedefNameForAnonDecl() const {
- return hasExtInfo() ? 0 :
- TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
+ return hasExtInfo() ? 0 : dyn_cast_or_null<TypedefNameDecl>(
+ NamedDeclOrQualifier.get<NamedDecl *>());
}
+ void setDeclaratorForAnonDecl(DeclaratorDecl *DD) { NamedDeclOrQualifier = DD; }
+
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
/// \brief Retrieve the nested-name-specifier that qualifies the name of this
@@ -2702,21 +2823,22 @@ public:
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
}
const EnumDecl *getCanonicalDecl() const {
- return cast<EnumDecl>(TagDecl::getCanonicalDecl());
+ return const_cast<EnumDecl*>(this)->getCanonicalDecl();
}
- const EnumDecl *getPreviousDecl() const {
- return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
- }
EnumDecl *getPreviousDecl() {
- return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
+ return cast_or_null<EnumDecl>(
+ static_cast<TagDecl *>(this)->getPreviousDecl());
}
-
- const EnumDecl *getMostRecentDecl() const {
- return cast<EnumDecl>(TagDecl::getMostRecentDecl());
+ const EnumDecl *getPreviousDecl() const {
+ return const_cast<EnumDecl*>(this)->getPreviousDecl();
}
+
EnumDecl *getMostRecentDecl() {
- return cast<EnumDecl>(TagDecl::getMostRecentDecl());
+ return cast<EnumDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
+ }
+ const EnumDecl *getMostRecentDecl() const {
+ return const_cast<EnumDecl*>(this)->getMostRecentDecl();
}
EnumDecl *getDefinition() const {
@@ -2912,18 +3034,19 @@ public:
IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
- const RecordDecl *getPreviousDecl() const {
- return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
- }
RecordDecl *getPreviousDecl() {
- return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
+ return cast_or_null<RecordDecl>(
+ static_cast<TagDecl *>(this)->getPreviousDecl());
}
-
- const RecordDecl *getMostRecentDecl() const {
- return cast<RecordDecl>(TagDecl::getMostRecentDecl());
+ const RecordDecl *getPreviousDecl() const {
+ return const_cast<RecordDecl*>(this)->getPreviousDecl();
}
+
RecordDecl *getMostRecentDecl() {
- return cast<RecordDecl>(TagDecl::getMostRecentDecl());
+ return cast<RecordDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
+ }
+ const RecordDecl *getMostRecentDecl() const {
+ return const_cast<RecordDecl*>(this)->getMostRecentDecl();
}
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
@@ -3106,13 +3229,17 @@ private:
Capture *Captures;
unsigned NumCaptures;
+ unsigned ManglingNumber;
+ Decl *ManglingContextDecl;
+
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false),
BlockMissingReturnType(true), IsConversionFromLambda(false),
ParamInfo(0), NumParams(0), Body(0),
- SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
+ SignatureAsWritten(0), Captures(0), NumCaptures(0),
+ ManglingNumber(0), ManglingContextDecl(0) {}
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
@@ -3182,6 +3309,18 @@ public:
const Capture *end,
bool capturesCXXThis);
+ unsigned getBlockManglingNumber() const {
+ return ManglingNumber;
+ }
+ Decl *getBlockManglingContextDecl() const {
+ return ManglingContextDecl;
+ }
+
+ void setBlockMangling(unsigned Number, Decl *Ctx) {
+ ManglingNumber = Number;
+ ManglingContextDecl = Ctx;
+ }
+
virtual SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
@@ -3354,7 +3493,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
}
template<typename decl_type>
-void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
+void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
// Note: This routine is implemented here because we need both NamedDecl
// and Redeclarable to be defined.
@@ -3364,10 +3503,16 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
- First = PrevDecl->getFirstDeclaration();
+ First = PrevDecl->getFirstDecl();
assert(First->RedeclLink.NextIsLatest() && "Expected first");
decl_type *MostRecent = First->RedeclLink.getNext();
RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
+
+ // If the declaration was previously visible, a redeclaration of it remains
+ // visible even if it wouldn't be visible by itself.
+ static_cast<decl_type*>(this)->IdentifierNamespace |=
+ MostRecent->getIdentifierNamespace() &
+ (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
} else {
// Make this first.
First = static_cast<decl_type*>(this);
diff --git a/include/clang/AST/DeclAccessPair.h b/include/clang/AST/DeclAccessPair.h
index 5731308f55e6..3c5056c6e55b 100644
--- a/include/clang/AST/DeclAccessPair.h
+++ b/include/clang/AST/DeclAccessPair.h
@@ -28,7 +28,7 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions.
class DeclAccessPair {
- NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
+ uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
enum { Mask = 0x3 };
@@ -40,10 +40,10 @@ public:
}
NamedDecl *getDecl() const {
- return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
+ return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
}
AccessSpecifier getAccess() const {
- return AccessSpecifier(Mask & (uintptr_t) Ptr);
+ return AccessSpecifier(Mask & Ptr);
}
void setDecl(NamedDecl *D) {
@@ -53,8 +53,7 @@ public:
set(getDecl(), AS);
}
void set(NamedDecl *D, AccessSpecifier AS) {
- Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
- reinterpret_cast<uintptr_t>(D));
+ Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
}
operator NamedDecl*() const { return getDecl(); }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 754facfb591d..26eea64f9d34 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -16,6 +16,7 @@
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclarationName.h"
+#include "clang/Basic/Linkage.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Compiler.h"
@@ -31,6 +32,7 @@ class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class FunctionDecl;
+class LinkageComputer;
class LinkageSpecDecl;
class Module;
class NamedDecl;
@@ -157,7 +159,12 @@ public:
/// This declaration is a C++ operator declared in a non-class
/// context. All such operators are also in IDNS_Ordinary.
/// C++ lexical operator lookup looks for these.
- IDNS_NonMemberOperator = 0x0400
+ IDNS_NonMemberOperator = 0x0400,
+
+ /// This declaration is a function-local extern declaration of a
+ /// variable or function. This may also be IDNS_Ordinary if it
+ /// has been declared outside any function.
+ IDNS_LocalExtern = 0x0800
};
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
@@ -284,19 +291,16 @@ protected:
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 12;
- /// \brief Whether the \c CachedLinkage field is active.
- ///
- /// This field is only valid for NamedDecls subclasses.
- mutable unsigned HasCachedLinkage : 1;
-
- /// \brief If \c HasCachedLinkage, the linkage of this declaration.
- ///
- /// This field is only valid for NamedDecls subclasses.
- mutable unsigned CachedLinkage : 2;
+ /// \brief If 0, we have not computed the linkage of this declaration.
+ /// Otherwise, it is the linkage + 1.
+ mutable unsigned CacheValidAndLinkage : 3;
friend class ASTDeclWriter;
friend class ASTDeclReader;
friend class ASTReader;
+ friend class LinkageComputer;
+
+ template<typename decl_type> friend class Redeclarable;
private:
void CheckAccessDeclContext() const;
@@ -309,7 +313,7 @@ protected:
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- HasCachedLinkage(0)
+ CacheValidAndLinkage(0)
{
if (StatisticsEnabled) add(DK);
}
@@ -319,7 +323,7 @@ protected:
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- HasCachedLinkage(0)
+ CacheValidAndLinkage(0)
{
if (StatisticsEnabled) add(DK);
}
@@ -341,6 +345,18 @@ protected:
/// \brief Update a potentially out-of-date declaration.
void updateOutOfDate(IdentifierInfo &II) const;
+ Linkage getCachedLinkage() const {
+ return Linkage(CacheValidAndLinkage - 1);
+ }
+
+ void setCachedLinkage(Linkage L) const {
+ CacheValidAndLinkage = L + 1;
+ }
+
+ bool hasCachedLinkage() const {
+ return CacheValidAndLinkage;
+ }
+
public:
/// \brief Source range that this declaration covers.
@@ -419,7 +435,6 @@ public:
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
}
const AttrVec &getAttrs() const;
- void swapAttrs(Decl *D);
void dropAttrs();
void addAttr(Attr *A) {
@@ -490,7 +505,16 @@ public:
/// whether the function is used.
bool isUsed(bool CheckUsedAttr = true) const;
- void setUsed(bool U = true) { Used = U; }
+ /// \brief Set whether the declaration is used, in the sense of odr-use.
+ ///
+ /// This should only be used immediately after creating a declaration.
+ void setIsUsed() { Used = true; }
+
+ /// \brief Mark the declaration used, in the sense of odr-use.
+ ///
+ /// This notifies any mutation listeners in addition to setting a bit
+ /// indicating the declaration is used.
+ void markUsed(ASTContext &C);
/// \brief Whether this declaration was referenced.
bool isReferenced() const;
@@ -513,13 +537,13 @@ public:
NextInContextAndBits.setInt(Bits);
}
-protected:
/// \brief Whether this declaration was marked as being private to the
/// module in which it was defined.
- bool isModulePrivate() const {
+ bool isModulePrivate() const {
return NextInContextAndBits.getInt() & ModulePrivateFlag;
}
-
+
+protected:
/// \brief Specify whether this declaration was marked as being private
/// to the module in which it was defined.
void setModulePrivate(bool MP = true) {
@@ -761,7 +785,12 @@ public:
const Decl *getPreviousDecl() const {
return const_cast<Decl *>(this)->getPreviousDeclImpl();
}
-
+
+ /// \brief True if this is the first declaration in its redeclaration chain.
+ bool isFirstDecl() const {
+ return getPreviousDecl() == 0;
+ }
+
/// \brief Retrieve the most recent declaration that declares the same entity
/// as this declaration (which may be this declaration).
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
@@ -777,8 +806,10 @@ public:
/// top-level Stmt* of that body. Otherwise this method returns null.
virtual Stmt* getBody() const { return 0; }
- /// \brief Returns true if this Decl represents a declaration for a body of
+ /// \brief Returns true if this \c Decl represents a declaration for a body of
/// code, such as a function or method definition.
+ /// Note that \c hasBody can also return true if any redeclaration of this
+ /// \c Decl represents a declaration for a body of code.
virtual bool hasBody() const { return getBody() != 0; }
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
@@ -808,37 +839,71 @@ public:
bool isFunctionOrFunctionTemplate() const;
/// \brief Changes the namespace of this declaration to reflect that it's
+ /// a function-local extern declaration.
+ ///
+ /// These declarations appear in the lexical context of the extern
+ /// 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;
+
+ IdentifierNamespace |= IDNS_LocalExtern;
+ if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
+ IdentifierNamespace |= IDNS_Ordinary;
+ }
+
+ /// \brief Determine whether this is a block-scope declaration with linkage.
+ /// This will either be a local variable declaration declared 'extern', or a
+ /// local function declaration.
+ bool isLocalExternDecl() {
+ return IdentifierNamespace & IDNS_LocalExtern;
+ }
+
+ /// \brief Changes the namespace of this declaration to reflect that it's
/// the object of a friend declaration.
///
/// These declarations appear in the lexical context of the friending
/// class, but in the semantic context of the actual entity. This property
/// applies only to a specific decl object; other redeclarations of the
/// same entity may not (and probably don't) share this property.
- void setObjectOfFriendDecl(bool PreviouslyDeclared) {
+ void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
unsigned OldNS = IdentifierNamespace;
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
- IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ IDNS_TagFriend | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern)) &&
"namespace includes neither ordinary nor tag");
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
- IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ IDNS_TagFriend | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern)) &&
"namespace includes other than ordinary or tag");
- IdentifierNamespace = 0;
+ Decl *Prev = getPreviousDecl();
+ IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type);
+
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
+ if (PerformFriendInjection ||
+ (Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
+ IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
- if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+ if (PerformFriendInjection ||
+ (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
+ IdentifierNamespace |= IDNS_Ordinary;
}
}
enum FriendObjectKind {
- FOK_None, // not a friend object
- FOK_Declared, // a friend of a previously-declared entity
- FOK_Undeclared // a friend of a previously-undeclared entity
+ FOK_None, ///< Not a friend object.
+ FOK_Declared, ///< A friend of a previously-declared entity.
+ FOK_Undeclared ///< A friend of a previously-undeclared entity.
};
/// \brief Determines whether this declaration is the object of a
@@ -846,11 +911,11 @@ public:
///
/// There is currently no direct way to find the associated FriendDecl.
FriendObjectKind getFriendObjectKind() const {
- unsigned mask
- = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
+ unsigned mask =
+ (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
if (!mask) return FOK_None;
- return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
- FOK_Declared : FOK_Undeclared);
+ return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared
+ : FOK_Undeclared);
}
/// Specifies that this declaration is a C++ overloaded non-member.
@@ -877,9 +942,6 @@ public:
// Same as dump(), but forces color printing.
LLVM_ATTRIBUTE_USED void dumpColor() const;
void dump(raw_ostream &Out) const;
- // Debuggers don't usually respect default arguments.
- LLVM_ATTRIBUTE_USED void dumpXML() const;
- void dumpXML(raw_ostream &OS) const;
private:
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
@@ -974,6 +1036,7 @@ protected:
mutable Decl *LastDecl;
friend class ExternalASTSource;
+ friend class ASTDeclReader;
friend class ASTWriter;
/// \brief Build up a chain of declarations.
@@ -1096,6 +1159,14 @@ public:
/// C++0x scoped enums), and C++ linkage specifications.
bool isTransparentContext() const;
+ /// \brief Determines whether this context or some of its ancestors is a
+ /// linkage specification context that specifies C linkage.
+ bool isExternCContext() const;
+
+ /// \brief Determines whether this context or some of its ancestors is a
+ /// linkage specification context that specifies C++ linkage.
+ bool isExternCXXContext() const;
+
/// \brief Determine whether this declaration context is equivalent
/// to the declaration context DC.
bool Equals(const DeclContext *DC) const {
@@ -1429,12 +1500,20 @@ public:
return const_cast<DeclContext*>(this)->lookup(Name);
}
+ /// \brief Find the declarations with the given name that are visible
+ /// within this context; don't attempt to retrieve anything from an
+ /// external source.
+ lookup_result noload_lookup(DeclarationName Name);
+
/// \brief A simplistic name lookup mechanism that performs name lookup
/// into this declaration context without consulting the external source.
///
/// This function should almost never be used, because it subverts the
/// usual relationship between a DeclContext and the external source.
/// See the ASTImporter for the (few, but important) use cases.
+ ///
+ /// FIXME: This is very inefficient; replace uses of it with uses of
+ /// noload_lookup.
void localUncachedLookup(DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Results);
@@ -1458,10 +1537,16 @@ public:
/// of looking up every possible name.
class all_lookups_iterator;
+ /// \brief Iterators over all possible lookups within this context.
all_lookups_iterator lookups_begin() const;
-
all_lookups_iterator lookups_end() const;
+ /// \brief Iterators over all possible lookups within this context that are
+ /// currently loaded; don't attempt to retrieve anything from an external
+ /// source.
+ all_lookups_iterator noload_lookups_begin() const;
+ all_lookups_iterator noload_lookups_end() const;
+
/// udir_iterator - Iterates through the using-directives stored
/// within this context.
typedef UsingDirectiveDecl * const * udir_iterator;
@@ -1532,6 +1617,8 @@ public:
static bool classof(const DeclContext *D) { return true; }
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
+ LLVM_ATTRIBUTE_USED void dumpLookups() const;
+ LLVM_ATTRIBUTE_USED void dumpLookups(llvm::raw_ostream &OS) const;
private:
void reconcileExternalVisibleStorage();
@@ -1548,6 +1635,8 @@ private:
friend class DependentDiagnostic;
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
+ template<decl_iterator (DeclContext::*Begin)() const,
+ decl_iterator (DeclContext::*End)() const>
void buildLookupImpl(DeclContext *DCtx);
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
bool Rediscoverable);
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index c483dde1f518..dbc41320bd72 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -6,10 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the C++ Decl subclasses, other than those for
-// templates (in DeclTemplate.h) and friends (in DeclFriend.h).
-//
+///
+/// \file
+/// \brief Defines the C++ Decl subclasses, other than those for templates
+/// (found in DeclTemplate.h) and friends (in DeclFriend.h).
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLCXX_H
@@ -88,7 +89,7 @@ namespace llvm {
namespace clang {
-/// @brief Represents an access specifier followed by colon ':'.
+/// \brief Represents an access specifier followed by colon ':'.
///
/// An objects of this class represents sugar for the syntactic occurrence
/// of an access specifier followed by a colon in the list of member
@@ -146,16 +147,16 @@ public:
/// level of access (public, protected, private) is used for the
/// derivation. For example:
///
-/// @code
+/// \code
/// class A { };
/// class B { };
/// class C : public virtual A, protected B { };
-/// @endcode
+/// \endcode
///
/// In this code, C will have two CXXBaseSpecifiers, one for "public
/// virtual A" and the other for "protected B".
class CXXBaseSpecifier {
- /// Range - The source code range that covers the full base
+ /// \brief The source code range that covers the full base
/// specifier, including the "virtual" (if present) and access
/// specifier (if present).
SourceRange Range;
@@ -167,25 +168,26 @@ class CXXBaseSpecifier {
/// \brief Whether this is a virtual base class or not.
bool Virtual : 1;
- /// BaseOfClass - Whether this is the base of a class (true) or of a
- /// struct (false). This determines the mapping from the access
- /// specifier as written in the source code to the access specifier
- /// used for semantic analysis.
+ /// \brief Whether this is the base of a class (true) or of a struct (false).
+ ///
+ /// This determines the mapping from the access specifier as written in the
+ /// source code to the access specifier used for semantic analysis.
bool BaseOfClass : 1;
- /// Access - Access specifier as written in the source code (which
- /// may be AS_none). The actual type of data stored here is an
- /// AccessSpecifier, but we use "unsigned" here to work around a
- /// VC++ bug.
+ /// \brief Access specifier as written in the source code (may be AS_none).
+ ///
+ /// The actual type of data stored here is an AccessSpecifier, but we use
+ /// "unsigned" here to work around a VC++ bug.
unsigned Access : 2;
- /// InheritConstructors - Whether the class contains a using declaration
+ /// \brief Whether the class contains a using declaration
/// to inherit the named class's constructors.
bool InheritConstructors : 1;
- /// BaseTypeInfo - The type of the base class. This will be a class or struct
- /// (or a typedef of such). The source code range does not include the
- /// "virtual" or access specifier.
+ /// \brief The type of the base class.
+ ///
+ /// This will be a class or struct (or a typedef of such). The source code
+ /// range does not include the \c virtual or the access specifier.
TypeSourceInfo *BaseTypeInfo;
public:
@@ -196,14 +198,12 @@ public:
: Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC),
Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { }
- /// getSourceRange - Retrieves the source range that contains the
- /// entire base specifier.
+ /// \brief Retrieves the source range that contains the entire base specifier.
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
- /// isVirtual - Determines whether the base class is a virtual base
- /// class (or not).
+ /// \brief Determines whether the base class is a virtual base class (or not).
bool isVirtual() const { return Virtual; }
/// \brief Determine whether this base class is a base of a class declared
@@ -226,11 +226,11 @@ public:
return EllipsisLoc;
}
- /// getAccessSpecifier - Returns the access specifier for this base
- /// specifier. This is the actual base specifier as used for
- /// semantic analysis, so the result can never be AS_none. To
- /// retrieve the access specifier as written in the source code, use
- /// getAccessSpecifierAsWritten().
+ /// \brief Returns the access specifier for this base specifier.
+ ///
+ /// This is the actual base specifier as used for semantic analysis, so
+ /// the result can never be AS_none. To retrieve the access specifier as
+ /// written in the source code, use getAccessSpecifierAsWritten().
AccessSpecifier getAccessSpecifier() const {
if ((AccessSpecifier)Access == AS_none)
return BaseOfClass? AS_private : AS_public;
@@ -238,19 +238,23 @@ public:
return (AccessSpecifier)Access;
}
- /// getAccessSpecifierAsWritten - Retrieves the access specifier as
- /// written in the source code (which may mean that no access
- /// specifier was explicitly written). Use getAccessSpecifier() to
- /// retrieve the access specifier for use in semantic analysis.
+ /// \brief Retrieves the access specifier as written in the source code
+ /// (which may mean that no access specifier was explicitly written).
+ ///
+ /// Use getAccessSpecifier() to retrieve the access specifier for use in
+ /// semantic analysis.
AccessSpecifier getAccessSpecifierAsWritten() const {
return (AccessSpecifier)Access;
}
- /// getType - Retrieves the type of the base class. This type will
- /// always be an unqualified class type.
- QualType getType() const { return BaseTypeInfo->getType(); }
+ /// \brief Retrieves the type of the base class.
+ ///
+ /// This type will always be an unqualified class type.
+ QualType getType() const {
+ return BaseTypeInfo->getType().getUnqualifiedType();
+ }
- /// getTypeLoc - Retrieves the type and source location of the base class.
+ /// \brief Retrieves the type and source location of the base class.
TypeSourceInfo *getTypeSourceInfo() const { return BaseTypeInfo; }
};
@@ -264,7 +268,8 @@ enum MSInheritanceModel {
MSIM_Unspecified
};
-/// CXXRecordDecl - Represents a C++ struct/union/class.
+/// \brief Represents a C++ struct/union/class.
+///
/// FIXME: This class will disappear once we've properly taught RecordDecl
/// to deal with C++-specific things.
class CXXRecordDecl : public RecordDecl {
@@ -288,32 +293,32 @@ class CXXRecordDecl : public RecordDecl {
/// \brief True if this class has any user-declared constructors.
bool UserDeclaredConstructor : 1;
- /// The user-declared special members which this class has.
+ /// \brief The user-declared special members which this class has.
unsigned UserDeclaredSpecialMembers : 6;
- /// Aggregate - True when this class is an aggregate.
+ /// \brief True when this class is an aggregate.
bool Aggregate : 1;
- /// PlainOldData - True when this class is a POD-type.
+ /// \brief True when this class is a POD-type.
bool PlainOldData : 1;
- /// Empty - true when this class is empty for traits purposes,
+ /// true when this class is empty for traits purposes,
/// i.e. has no data members other than 0-width bit-fields, has no
/// virtual function/base, and doesn't inherit from a non-empty
/// class. Doesn't take union-ness into account.
bool Empty : 1;
- /// Polymorphic - True when this class is polymorphic, i.e. has at
+ /// \brief True when this class is polymorphic, i.e., has at
/// least one virtual member or derives from a polymorphic class.
bool Polymorphic : 1;
- /// Abstract - True when this class is abstract, i.e. has at least
+ /// \brief True when this class is abstract, i.e., has at least
/// one pure virtual function, (that can come from a base class).
bool Abstract : 1;
- /// IsStandardLayout - True when this class has standard layout.
+ /// \brief True when this class has standard layout.
///
- /// C++0x [class]p7. A standard-layout class is a class that:
+ /// C++11 [class]p7. A standard-layout class is a class that:
/// * has no non-static data members of type non-standard-layout class (or
/// array of such types) or reference,
/// * has no virtual functions (10.3) and no virtual base classes (10.1),
@@ -327,20 +332,19 @@ class CXXRecordDecl : public RecordDecl {
/// member.
bool IsStandardLayout : 1;
- /// HasNoNonEmptyBases - True when there are no non-empty base classes.
+ /// \brief True when there are no non-empty base classes.
///
/// This is a helper bit of state used to implement IsStandardLayout more
/// efficiently.
bool HasNoNonEmptyBases : 1;
- /// HasPrivateFields - True when there are private non-static data members.
+ /// \brief True when there are private non-static data members.
bool HasPrivateFields : 1;
- /// HasProtectedFields - True when there are protected non-static data
- /// members.
+ /// \brief True when there are protected non-static data members.
bool HasProtectedFields : 1;
- /// HasPublicFields - True when there are private non-static data members.
+ /// \brief True when there are private non-static data members.
bool HasPublicFields : 1;
/// \brief True if this class (or any subobject) has mutable fields.
@@ -353,8 +357,10 @@ class CXXRecordDecl : public RecordDecl {
bool HasInClassInitializer : 1;
/// \brief True if any field is of reference type, and does not have an
- /// in-class initializer. In this case, value-initialization of this class
- /// is illegal in C++98 even if the class has a trivial default constructor.
+ /// in-class initializer.
+ ///
+ /// In this case, value-initialization of this class is illegal in C++98
+ /// even if the class has a trivial default constructor.
bool HasUninitializedReferenceMember : 1;
/// \brief These flags are \c true if a defaulted corresponding special
@@ -389,30 +395,29 @@ class CXXRecordDecl : public RecordDecl {
/// members which have not yet been declared.
unsigned DeclaredNonTrivialSpecialMembers : 6;
- /// HasIrrelevantDestructor - True when this class has a destructor with no
- /// semantic effect.
+ /// \brief True when this class has a destructor with no semantic effect.
bool HasIrrelevantDestructor : 1;
- /// HasConstexprNonCopyMoveConstructor - True when this class has at least
- /// one user-declared constexpr constructor which is neither the copy nor
- /// move constructor.
+ /// \brief True when this class has at least one user-declared constexpr
+ /// constructor which is neither the copy nor move constructor.
bool HasConstexprNonCopyMoveConstructor : 1;
- /// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default
- /// constructor for this class would be constexpr.
+ /// \brief True if a defaulted default constructor for this class would
+ /// be constexpr.
bool DefaultedDefaultConstructorIsConstexpr : 1;
- /// HasConstexprDefaultConstructor - True if this class has a constexpr
- /// default constructor (either user-declared or implicitly declared).
+ /// \brief True if this class has a constexpr default constructor.
+ ///
+ /// This is true for either a user-declared constexpr default constructor
+ /// or an implicitly declared constexpr default constructor..
bool HasConstexprDefaultConstructor : 1;
- /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
- /// one non-static data member or base class of non-literal or volatile
- /// type.
+ /// \brief True when this class contains at least one non-static data
+ /// member or base class of non-literal or volatile type.
bool HasNonLiteralTypeFieldsOrBases : 1;
- /// ComputedVisibleConversions - True when visible conversion functions are
- /// already computed and are available.
+ /// \brief True when visible conversion functions are already computed
+ /// and are available.
bool ComputedVisibleConversions : 1;
/// \brief Whether we have a C++11 user-provided default constructor (not
@@ -439,50 +444,44 @@ class CXXRecordDecl : public RecordDecl {
/// const-qualified reference parameter or a non-reference parameter.
bool HasDeclaredCopyAssignmentWithConstParam : 1;
- /// \brief Whether an implicit move constructor was attempted to be declared
- /// but would have been deleted.
- bool FailedImplicitMoveConstructor : 1;
-
- /// \brief Whether an implicit move assignment operator was attempted to be
- /// declared but would have been deleted.
- bool FailedImplicitMoveAssignment : 1;
-
/// \brief Whether this class describes a C++ lambda.
bool IsLambda : 1;
- /// NumBases - The number of base class specifiers in Bases.
+ /// \brief The number of base class specifiers in Bases.
unsigned NumBases;
- /// NumVBases - The number of virtual base class specifiers in VBases.
+ /// \brief The number of virtual base class specifiers in VBases.
unsigned NumVBases;
- /// Bases - Base classes of this class.
+ /// \brief Base classes of this class.
+ ///
/// FIXME: This is wasted space for a union.
LazyCXXBaseSpecifiersPtr Bases;
- /// VBases - direct and indirect virtual base classes of this class.
+ /// \brief direct and indirect virtual base classes of this class.
LazyCXXBaseSpecifiersPtr VBases;
- /// Conversions - Overload set containing the conversion functions
- /// of this C++ class (but not its inherited conversion
- /// functions). Each of the entries in this overload set is a
- /// CXXConversionDecl.
- ASTUnresolvedSet Conversions;
+ /// \brief The conversion functions of this C++ class (but not its
+ /// inherited conversion functions).
+ ///
+ /// Each of the entries in this overload set is a CXXConversionDecl.
+ LazyASTUnresolvedSet Conversions;
- /// VisibleConversions - Overload set containing the conversion
- /// functions of this C++ class and all those inherited conversion
- /// functions that are visible in this class. Each of the entries
- /// in this overload set is a CXXConversionDecl or a
+ /// \brief The conversion functions of this C++ class and all those
+ /// inherited conversion functions that are visible in this class.
+ ///
+ /// Each of the entries in this overload set is a CXXConversionDecl or a
/// FunctionTemplateDecl.
- ASTUnresolvedSet VisibleConversions;
+ LazyASTUnresolvedSet VisibleConversions;
- /// Definition - The declaration which defines this record.
+ /// \brief The declaration which defines this record.
CXXRecordDecl *Definition;
- /// FirstFriend - The first friend declaration in this class, or
- /// null if there aren't any. This is actually currently stored
- /// in reverse order.
- FriendDecl *FirstFriend;
+ /// \brief The first friend declaration in this class, or null if there
+ /// aren't any.
+ ///
+ /// This is actually currently stored in reverse order.
+ LazyDeclPtr FirstFriend;
/// \brief Retrieve the set of direct base classes.
CXXBaseSpecifier *getBases() const {
@@ -507,10 +506,12 @@ class CXXRecordDecl : public RecordDecl {
struct LambdaDefinitionData : public DefinitionData {
typedef LambdaExpr::Capture Capture;
- LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
- : DefinitionData(D), Dependent(Dependent), NumCaptures(0),
- NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
- MethodTyInfo(Info)
+ LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info,
+ bool Dependent, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault)
+ : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric),
+ CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0),
+ ManglingNumber(0), ContextDecl(0), Captures(0), MethodTyInfo(Info)
{
IsLambda = true;
}
@@ -522,14 +523,20 @@ class CXXRecordDecl : public RecordDecl {
/// within the default argument of a function template, because the
/// lambda will have been created with the enclosing context as its
/// declaration context, rather than function. This is an unfortunate
- /// artifact of having to parse the default arguments before
+ /// artifact of having to parse the default arguments before.
unsigned Dependent : 1;
- /// \brief The number of captures in this lambda.
- unsigned NumCaptures : 16;
+ /// \brief Whether this lambda is a generic lambda.
+ unsigned IsGenericLambda : 1;
+
+ /// \brief The Default Capture.
+ unsigned CaptureDefault : 2;
+
+ /// \brief The number of captures in this lambda is limited 2^NumCaptures.
+ unsigned NumCaptures : 15;
/// \brief The number of explicit captures in this lambda.
- unsigned NumExplicitCaptures : 15;
+ unsigned NumExplicitCaptures : 13;
/// \brief The number used to indicate this lambda expression for name
/// mangling in the Itanium C++ ABI.
@@ -547,6 +554,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The type of the call method.
TypeSourceInfo *MethodTyInfo;
+
};
struct DefinitionData &data() {
@@ -569,7 +577,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The template or declaration that this declaration
/// describes or was instantiated from, respectively.
///
- /// For non-templates, this value will be NULL. For record
+ /// For non-templates, this value will be null. For record
/// declarations that describe a class template, this will be a
/// pointer to a ClassTemplateDecl. For member
/// classes of class template specializations, this will be the
@@ -597,27 +605,29 @@ class CXXRecordDecl : public RecordDecl {
friend class ASTNodeImporter;
+ /// \brief Get the head of our list of friend declarations, possibly
+ /// deserializing the friends from an external AST source.
+ FriendDecl *getFirstFriend() const;
+
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, CXXRecordDecl *PrevDecl);
public:
- /// base_class_iterator - Iterator that traverses the base classes
- /// of a class.
+ /// \brief Iterator that traverses the base classes of a class.
typedef CXXBaseSpecifier* base_class_iterator;
- /// base_class_const_iterator - Iterator that traverses the base
- /// classes of a class.
+ /// \brief Iterator that traverses the base classes of a class.
typedef const CXXBaseSpecifier* base_class_const_iterator;
- /// reverse_base_class_iterator = Iterator that traverses the base classes
- /// of a class in reverse order.
+ /// \brief Iterator that traverses the base classes of a class in reverse
+ /// order.
typedef std::reverse_iterator<base_class_iterator>
reverse_base_class_iterator;
- /// reverse_base_class_iterator = Iterator that traverses the base classes
- /// of a class in reverse order.
+ /// \brief Iterator that traverses the base classes of a class in reverse
+ /// order.
typedef std::reverse_iterator<base_class_const_iterator>
reverse_base_class_const_iterator;
@@ -628,18 +638,21 @@ public:
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
}
+ CXXRecordDecl *getPreviousDecl() {
+ return cast_or_null<CXXRecordDecl>(
+ static_cast<RecordDecl *>(this)->getPreviousDecl());
+ }
const CXXRecordDecl *getPreviousDecl() const {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl());
+ return const_cast<CXXRecordDecl*>(this)->getPreviousDecl();
}
- CXXRecordDecl *getPreviousDecl() {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl());
+
+ CXXRecordDecl *getMostRecentDecl() {
+ return cast<CXXRecordDecl>(
+ static_cast<RecordDecl *>(this)->getMostRecentDecl());
}
const CXXRecordDecl *getMostRecentDecl() const {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl());
- }
- CXXRecordDecl *getMostRecentDecl() {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl());
+ return const_cast<CXXRecordDecl*>(this)->getMostRecentDecl();
}
CXXRecordDecl *getDefinition() const {
@@ -655,18 +668,18 @@ public:
bool DelayTypeCreation = false);
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool DependentLambda);
+ bool DependentLambda, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
bool isDynamicClass() const {
return data().Polymorphic || data().NumVBases != 0;
}
- /// setBases - Sets the base classes of this struct or class.
+ /// \brief Sets the base classes of this struct or class.
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
- /// getNumBases - Retrieves the number of base classes of this
- /// class.
+ /// \brief Retrieves the number of base classes of this class.
unsigned getNumBases() const { return data().NumBases; }
base_class_iterator bases_begin() { return data().getBases(); }
@@ -688,8 +701,7 @@ public:
return reverse_base_class_const_iterator(bases_begin());
}
- /// getNumVBases - Retrieves the number of virtual base classes of this
- /// class.
+ /// \brief Retrieves the number of virtual base classes of this class.
unsigned getNumVBases() const { return data().NumVBases; }
base_class_iterator vbases_begin() { return data().getVBases(); }
@@ -720,12 +732,12 @@ public:
/// special methods, etc.
typedef specific_decl_iterator<CXXMethodDecl> method_iterator;
- /// method_begin - Method begin iterator. Iterates in the order the methods
+ /// \brief Method begin iterator. Iterates in the order the methods
/// were declared.
method_iterator method_begin() const {
return method_iterator(decls_begin());
}
- /// method_end - Method end iterator.
+ /// \brief Method past-the-end iterator.
method_iterator method_end() const {
return method_iterator(decls_end());
}
@@ -749,18 +761,20 @@ public:
/// Determines whether this record has any friends.
bool hasFriends() const {
- return data().FirstFriend != 0;
+ return data().FirstFriend.isValid();
}
/// \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();
+ 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();
+ return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
+ !data().DefaultedMoveAssignmentIsDeleted;
}
/// \brief \c true if we know for sure that this class has an accessible
/// destructor that is not deleted.
@@ -784,22 +798,22 @@ public:
!(data().DeclaredSpecialMembers & SMF_DefaultConstructor);
}
- /// hasUserDeclaredConstructor - Whether this class has any
- /// user-declared constructors. When true, a default constructor
- /// will not be implicitly declared.
+ /// \brief Determine whether this class has any user-declared constructors.
+ ///
+ /// When true, a default constructor will not be implicitly declared.
bool hasUserDeclaredConstructor() const {
return data().UserDeclaredConstructor;
}
- /// hasUserProvidedDefaultconstructor - Whether this class has a
- /// user-provided default constructor per C++0x.
+ /// \brief Whether this class has a user-provided default constructor
+ /// per C++11.
bool hasUserProvidedDefaultConstructor() const {
return data().UserProvidedDefaultConstructor;
}
- /// hasUserDeclaredCopyConstructor - Whether this class has a
- /// user-declared copy constructor. When false, a copy constructor
- /// will be implicitly declared.
+ /// \brief Determine whether this class has a user-declared copy constructor.
+ ///
+ /// When false, a copy constructor will be implicitly declared.
bool hasUserDeclaredCopyConstructor() const {
return data().UserDeclaredSpecialMembers & SMF_CopyConstructor;
}
@@ -830,9 +844,11 @@ public:
implicitCopyConstructorHasConstParam());
}
- /// hasUserDeclaredMoveOperation - Whether this class has a user-
- /// declared move constructor or assignment operator. When false, a
- /// move constructor and assignment operator may be implicitly declared.
+ /// \brief Whether this class has a user-declared move constructor or
+ /// assignment operator.
+ ///
+ /// When false, a move constructor and assignment operator may be
+ /// implicitly declared.
bool hasUserDeclaredMoveOperation() const {
return data().UserDeclaredSpecialMembers &
(SMF_MoveConstructor | SMF_MoveAssignment);
@@ -850,28 +866,23 @@ public:
needsImplicitMoveConstructor();
}
- /// \brief Determine whether implicit move constructor generation for this
- /// class has failed before.
- bool hasFailedImplicitMoveConstructor() const {
- return data().FailedImplicitMoveConstructor;
- }
-
- /// \brief Set whether implicit move constructor generation for this class
- /// has failed before.
- void setFailedImplicitMoveConstructor(bool Failed = true) {
- data().FailedImplicitMoveConstructor = Failed;
+ /// \brief Set that we attempted to declare an implicitly move
+ /// constructor, but overload resolution failed so we deleted it.
+ void setImplicitMoveConstructorIsDeleted() {
+ assert((data().DefaultedMoveConstructorIsDeleted ||
+ needsOverloadResolutionForMoveConstructor()) &&
+ "move constructor should not be deleted");
+ data().DefaultedMoveConstructorIsDeleted = true;
}
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
bool needsImplicitMoveConstructor() const {
- return !hasFailedImplicitMoveConstructor() &&
- !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
+ return !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveAssignment() &&
- !hasUserDeclaredDestructor() &&
- !data().DefaultedMoveConstructorIsDeleted;
+ !hasUserDeclaredDestructor();
}
/// \brief Determine whether we need to eagerly declare a defaulted move
@@ -880,9 +891,10 @@ public:
return data().NeedOverloadResolutionForMoveConstructor;
}
- /// hasUserDeclaredCopyAssignment - Whether this class has a
- /// user-declared copy assignment operator. When false, a copy
- /// assigment operator will be implicitly declared.
+ /// \brief Determine whether this class has a user-declared copy assignment
+ /// operator.
+ ///
+ /// When false, a copy assigment operator will be implicitly declared.
bool hasUserDeclaredCopyAssignment() const {
return data().UserDeclaredSpecialMembers & SMF_CopyAssignment;
}
@@ -907,7 +919,7 @@ public:
/// \brief Determine whether this class has a copy assignment operator with
/// a parameter type which is a reference to a const-qualified type or is not
- /// a reference..
+ /// a reference.
bool hasCopyAssignmentWithConstParam() const {
return data().HasDeclaredCopyAssignmentWithConstParam ||
(needsImplicitCopyAssignment() &&
@@ -926,29 +938,24 @@ public:
needsImplicitMoveAssignment();
}
- /// \brief Determine whether implicit move assignment generation for this
- /// class has failed before.
- bool hasFailedImplicitMoveAssignment() const {
- return data().FailedImplicitMoveAssignment;
- }
-
- /// \brief Set whether implicit move assignment generation for this class
- /// has failed before.
- void setFailedImplicitMoveAssignment(bool Failed = true) {
- data().FailedImplicitMoveAssignment = Failed;
+ /// \brief Set that we attempted to declare an implicit move assignment
+ /// operator, but overload resolution failed so we deleted it.
+ void setImplicitMoveAssignmentIsDeleted() {
+ assert((data().DefaultedMoveAssignmentIsDeleted ||
+ needsOverloadResolutionForMoveAssignment()) &&
+ "move assignment should not be deleted");
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
/// \brief Determine whether this class should get an implicit move
/// assignment operator or if any existing special member function inhibits
/// this.
bool needsImplicitMoveAssignment() const {
- return !hasFailedImplicitMoveAssignment() &&
- !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
+ return !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveConstructor() &&
- !hasUserDeclaredDestructor() &&
- !data().DefaultedMoveAssignmentIsDeleted;
+ !hasUserDeclaredDestructor();
}
/// \brief Determine whether we need to eagerly declare a move assignment
@@ -957,9 +964,9 @@ public:
return data().NeedOverloadResolutionForMoveAssignment;
}
- /// hasUserDeclaredDestructor - Whether this class has a
- /// user-declared destructor. When false, a destructor will be
- /// implicitly declared.
+ /// \brief Determine whether this class has a user-declared destructor.
+ ///
+ /// When false, a destructor will be implicitly declared.
bool hasUserDeclaredDestructor() const {
return data().UserDeclaredSpecialMembers & SMF_Destructor;
}
@@ -979,15 +986,42 @@ public:
/// \brief Determine whether this class describes a lambda function object.
bool isLambda() const { return hasDefinition() && data().IsLambda; }
+ /// \brief Determine whether this class describes a generic
+ /// lambda function object (i.e. function call operator is
+ /// a template).
+ bool isGenericLambda() const;
+
+ /// \brief Retrieve the lambda call operator of the closure type
+ /// if this is a closure type.
+ CXXMethodDecl *getLambdaCallOperator() const;
+
+ /// \brief Retrieve the lambda static invoker, the address of which
+ /// is returned by the conversion operator, and the body of which
+ /// is forwarded to the lambda call operator.
+ CXXMethodDecl *getLambdaStaticInvoker() const;
+
+ /// \brief Retrieve the generic lambda's template parameter list.
+ /// Returns null if the class does not represent a lambda or a generic
+ /// lambda.
+ TemplateParameterList *getGenericLambdaTemplateParameterList() const;
+
+ LambdaCaptureDefault getLambdaCaptureDefault() const {
+ assert(isLambda());
+ return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
+ }
+
/// \brief For a closure type, retrieve the mapping from captured
- /// variables and this to the non-static data members that store the
+ /// variables and \c this to the non-static data members that store the
/// values or references of the captures.
///
/// \param Captures Will be populated with the mapping from captured
/// variables to the corresponding fields.
///
/// \param ThisCapture Will be set to the field declaration for the
- /// 'this' capture.
+ /// \c this capture.
+ ///
+ /// \note No entries will be added for init-captures, as they do not capture
+ /// variables.
void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
FieldDecl *&ThisCapture) const;
@@ -1001,10 +1035,10 @@ public:
typedef UnresolvedSetIterator conversion_iterator;
conversion_iterator conversion_begin() const {
- return data().Conversions.begin();
+ return data().Conversions.get(getASTContext()).begin();
}
conversion_iterator conversion_end() const {
- return data().Conversions.end();
+ return data().Conversions.get(getASTContext()).end();
}
/// Removes a conversion function from this class. The conversion
@@ -1012,38 +1046,39 @@ public:
/// this class must currently be in the process of being defined.
void removeConversion(const NamedDecl *Old);
- /// getVisibleConversionFunctions - get all conversion functions visible
- /// in current class; including conversion function templates.
+ /// \brief Get all conversion functions visible in current class,
+ /// including conversion function templates.
std::pair<conversion_iterator, conversion_iterator>
getVisibleConversionFunctions();
- /// isAggregate - Whether this class is an aggregate (C++
- /// [dcl.init.aggr]), which is a class with no user-declared
- /// constructors, no private or protected non-static data members,
- /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
+ /// Determine whether this class is an aggregate (C++ [dcl.init.aggr]),
+ /// which is a class with no user-declared constructors, no private
+ /// or protected non-static data members, no base classes, and no virtual
+ /// functions (C++ [dcl.init.aggr]p1).
bool isAggregate() const { return data().Aggregate; }
- /// hasInClassInitializer - Whether this class has any in-class initializers
+ /// \brief Whether this class has any in-class initializers
/// for non-static data members.
bool hasInClassInitializer() const { return data().HasInClassInitializer; }
/// \brief Whether this class or any of its subobjects has any members of
- /// reference type which would make value-initialization ill-formed, per
- /// C++03 [dcl.init]p5:
- /// -- if T is a non-union class type without a user-declared constructor,
- /// then every non-static data member and base-class component of T is
- /// value-initialized
- /// [...]
- /// A program that calls for [...] value-initialization of an entity of
- /// reference type is ill-formed.
+ /// reference type which would make value-initialization ill-formed.
+ ///
+ /// Per C++03 [dcl.init]p5:
+ /// - if T is a non-union class type without a user-declared constructor,
+ /// then every non-static data member and base-class component of T is
+ /// value-initialized [...] A program that calls for [...]
+ /// value-initialization of an entity of reference type is ill-formed.
bool hasUninitializedReferenceMember() const {
return !isUnion() && !hasUserDeclaredConstructor() &&
data().HasUninitializedReferenceMember;
}
- /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
- /// that is an aggregate that has no non-static non-POD data members, no
- /// reference data members, no user-defined copy assignment operator and no
+ /// \brief Whether this class is a POD-type (C++ [class]p4)
+ ///
+ /// For purposes of this function a class is POD if it is an aggregate
+ /// that has no non-static non-POD data members, no reference data
+ /// members, no user-defined copy assignment operator and no
/// user-defined destructor.
///
/// Note that this is the C++ TR1 definition of POD.
@@ -1053,26 +1088,33 @@ public:
/// it contains only public fields, no bases, tag kind is not 'class', etc.
bool isCLike() const;
- /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
- /// means it has a virtual function, virtual base, data member (other than
- /// 0-width bit-field) or inherits from a non-empty class. Does NOT include
- /// a check for union-ness.
+ /// \brief Determine whether this is an empty class in the sense of
+ /// (C++11 [meta.unary.prop]).
+ ///
+ /// A non-union class is empty iff it has a virtual function, virtual base,
+ /// data member (other than 0-width bit-field) or inherits from a non-empty
+ /// class.
+ ///
+ /// \note This does NOT include a check for union-ness.
bool isEmpty() const { return data().Empty; }
- /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
+ /// Whether this class is polymorphic (C++ [class.virtual]),
/// which means that the class contains or inherits a virtual function.
bool isPolymorphic() const { return data().Polymorphic; }
- /// isAbstract - Whether this class is abstract (C++ [class.abstract]),
- /// which means that the class contains or inherits a pure virtual function.
+ /// \brief Determine whether this class has a pure virtual function.
+ ///
+ /// The class is is abstract per (C++ [class.abstract]p2) if it declares
+ /// a pure virtual function or inherits a pure virtual function that is
+ /// not overridden.
bool isAbstract() const { return data().Abstract; }
- /// isStandardLayout - Whether this class has standard layout
+ /// \brief Determine whether this class has standard layout per
/// (C++ [class]p7)
bool isStandardLayout() const { return data().IsStandardLayout; }
- /// \brief Whether this class, or any of its class subobjects, contains a
- /// mutable field.
+ /// \brief Determine whether this class, or any of its class subobjects,
+ /// contains a mutable field.
bool hasMutableFields() const { return data().HasMutableFields; }
/// \brief Determine whether this class has a trivial default constructor
@@ -1180,47 +1222,49 @@ public:
return !(data().HasTrivialSpecialMembers & SMF_Destructor);
}
- // hasIrrelevantDestructor - Whether this class has a destructor which has no
- // semantic effect. Any such destructor will be trivial, public, defaulted
- // and not deleted, and will call only irrelevant destructors.
+ /// \brief Determine whether this class has a destructor which has no
+ /// semantic effect.
+ ///
+ /// Any such destructor will be trivial, public, defaulted and not deleted,
+ /// and will call only irrelevant destructors.
bool hasIrrelevantDestructor() const {
return data().HasIrrelevantDestructor;
}
- // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or
- // volatile type non-static data member or base class.
+ /// \brief Determine whether this class has a non-literal or/ volatile type
+ /// non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
return data().HasNonLiteralTypeFieldsOrBases;
}
- // isTriviallyCopyable - Whether this class is considered trivially copyable
- // (C++0x [class]p6).
+ /// \brief Determine whether this class is considered trivially copyable per
+ /// (C++11 [class]p6).
bool isTriviallyCopyable() const;
- // isTrivial - Whether this class is considered trivial
- //
- // C++0x [class]p6
- // A trivial class is a class that has a trivial default constructor and
- // is trivially copiable.
+ /// \brief Determine whether this class is considered trivial.
+ ///
+ /// C++11 [class]p6:
+ /// "A trivial class is a class that has a trivial default constructor and
+ /// is trivially copiable."
bool isTrivial() const {
return isTriviallyCopyable() && hasTrivialDefaultConstructor();
}
- // isLiteral - Whether this class is a literal type.
- //
- // C++11 [basic.types]p10
- // A class type that has all the following properties:
- // -- it has a trivial destructor
- // -- every constructor call and full-expression in the
- // brace-or-equal-intializers for non-static data members (if any) is
- // a constant expression.
- // -- it is an aggregate type or has at least one constexpr constructor or
- // constructor template that is not a copy or move constructor, and
- // -- all of its non-static data members and base classes are of literal
- // types
- //
- // We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
- // treating types with trivial default constructors as literal types.
+ /// \brief Determine whether this class is a literal type.
+ ///
+ /// C++11 [basic.types]p10:
+ /// A class type that has all the following properties:
+ /// - it has a trivial destructor
+ /// - every constructor call and full-expression in the
+ /// brace-or-equal-intializers for non-static data members (if any) is
+ /// a constant expression.
+ /// - it is an aggregate type or has at least one constexpr constructor
+ /// or constructor template that is not a copy or move constructor, and
+ /// - all of its non-static data members and base classes are of literal
+ /// types
+ ///
+ /// We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
+ /// treating types with trivial default constructors as literal types.
bool isLiteral() const {
return hasTrivialDestructor() &&
(isAggregate() || hasConstexprNonCopyMoveConstructor() ||
@@ -1231,15 +1275,15 @@ public:
/// \brief If this record is an instantiation of a member class,
/// retrieves the member class from which it was instantiated.
///
- /// This routine will return non-NULL for (non-templated) member
+ /// This routine will return non-null for (non-templated) member
/// classes of class templates. For example, given:
///
- /// @code
+ /// \code
/// template<typename T>
/// struct X {
/// struct A { };
/// };
- /// @endcode
+ /// \endcode
///
/// The declaration for X<int>::A is a (non-templated) CXXRecordDecl
/// whose parent is the class template specialization X<int>. For
@@ -1257,7 +1301,7 @@ public:
}
/// \brief Specify that this record is an instantiation of the
- /// member class RD.
+ /// member class \p RD.
void setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK);
@@ -1288,10 +1332,10 @@ public:
/// \brief Set the kind of specialization or template instantiation this is.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
- /// getDestructor - Returns the destructor decl for this class.
+ /// \brief Returns the destructor decl for this class.
CXXDestructorDecl *getDestructor() const;
- /// isLocalClass - If the class is a local class [class.local], returns
+ /// \brief If the class is a local class [class.local], returns
/// the enclosing function declaration.
const FunctionDecl *isLocalClass() const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getDeclContext()))
@@ -1300,6 +1344,11 @@ public:
return dyn_cast<FunctionDecl>(getDeclContext());
}
+ FunctionDecl *isLocalClass() {
+ return const_cast<FunctionDecl*>(
+ const_cast<const CXXRecordDecl*>(this)->isLocalClass());
+ }
+
/// \brief Determine whether this dependent class is a current instantiation,
/// when viewed from within the given context.
bool isCurrentInstantiation(const DeclContext *CurContext) const;
@@ -1328,7 +1377,7 @@ public:
/// \param Paths will contain the paths taken from the current class to the
/// given \p Base class.
///
- /// \returns true if this class is derived from Base, false otherwise.
+ /// \returns true if this class is derived from \p Base, false otherwise.
///
/// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
/// tangling input and output in \p Paths
@@ -1367,6 +1416,13 @@ public:
/// The class itself does not count as a base class. This routine
/// returns false if the class has non-computable base classes.
///
+ /// \param BaseMatches Callback invoked for each (direct or indirect) base
+ /// class of this type, or if \p AllowShortCircuit is true then until a call
+ /// returns false.
+ ///
+ /// \param UserData Passed as the second argument of every call to
+ /// \p BaseMatches.
+ ///
/// \param AllowShortCircuit if false, forces the callback to be called
/// for every base class, even if a dependent or non-matching base was
/// found.
@@ -1471,12 +1527,12 @@ public:
/// \brief Get the indirect primary bases for this class.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
- /// viewInheritance - Renders and displays an inheritance diagram
+ /// Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
void viewInheritance(ASTContext& Context) const;
- /// MergeAccess - Calculates the access of a decl that is reached
+ /// \brief Calculates the access of a decl that is reached
/// along a path.
static AccessSpecifier MergeAccess(AccessSpecifier PathAccess,
AccessSpecifier DeclAccess) {
@@ -1575,8 +1631,10 @@ public:
friend class ASTWriter;
};
-/// CXXMethodDecl - Represents a static or instance method of a
-/// struct/union/class.
+/// \brief Represents a static or instance method of a struct/union/class.
+///
+/// In the terminology of the C++ Standard, these are the (static and
+/// non-static) member functions, whether virtual or not.
class CXXMethodDecl : public FunctionDecl {
virtual void anchor();
protected:
@@ -1606,6 +1664,18 @@ public:
bool isStatic() const;
bool isInstance() const { return !isStatic(); }
+ /// Returns true if the given operator is implicitly static in a record
+ /// context.
+ static bool isStaticOverloadedOperator(OverloadedOperatorKind OOK) {
+ // [class.free]p1:
+ // Any allocation function for a class T is a static member
+ // (even if not explicitly declared static).
+ // [class.free]p6 Any deallocation function for a class X is a static member
+ // (even if not explicitly declared static).
+ return OOK == OO_New || OOK == OO_Array_New || OOK == OO_Delete ||
+ OOK == OO_Array_Delete;
+ }
+
bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); }
@@ -1633,14 +1703,22 @@ public:
/// \brief Determine whether this is a move assignment operator.
bool isMoveAssignmentOperator() const;
- const CXXMethodDecl *getCanonicalDecl() const {
- return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
- }
CXXMethodDecl *getCanonicalDecl() {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
}
+ const CXXMethodDecl *getCanonicalDecl() const {
+ return const_cast<CXXMethodDecl*>(this)->getCanonicalDecl();
+ }
+
+ CXXMethodDecl *getMostRecentDecl() {
+ return cast<CXXMethodDecl>(
+ static_cast<FunctionDecl *>(this)->getMostRecentDecl());
+ }
+ const CXXMethodDecl *getMostRecentDecl() const {
+ return const_cast<CXXMethodDecl*>(this)->getMostRecentDecl();
+ }
- /// isUserProvided - True if this method is user-declared and was not
+ /// True if this method is user-declared and was not
/// deleted or defaulted on its first declaration.
bool isUserProvided() const {
return !(isDeleted() || getCanonicalDecl()->isDefaulted());
@@ -1655,21 +1733,22 @@ public:
method_iterator end_overridden_methods() const;
unsigned size_overridden_methods() const;
- /// getParent - Returns the parent of this method declaration, which
+ /// Returns the parent of this method declaration, which
/// is the class in which this method is defined.
const CXXRecordDecl *getParent() const {
return cast<CXXRecordDecl>(FunctionDecl::getParent());
}
- /// getParent - Returns the parent of this method declaration, which
+ /// Returns the parent of this method declaration, which
/// is the class in which this method is defined.
CXXRecordDecl *getParent() {
return const_cast<CXXRecordDecl *>(
cast<CXXRecordDecl>(FunctionDecl::getParent()));
}
- /// getThisType - Returns the type of 'this' pointer.
- /// Should only be called for instance methods.
+ /// \brief Returns the type of the \c this pointer.
+ ///
+ /// Should only be called for instance (i.e., non-static) methods.
QualType getThisType(ASTContext &C) const;
unsigned getTypeQualifiers() const {
@@ -1702,11 +1781,11 @@ public:
/// or clone the function call operator.
bool isLambdaStaticInvoker() const;
- /// \brief Find the method in RD that corresponds to this one.
+ /// \brief Find the method in \p RD that corresponds to this one.
///
- /// Find if RD or one of the classes it inherits from override this method.
- /// If so, return it. RD is assumed to be a subclass of the class defining
- /// this method (or be the class itself), unless MayBeBase is set to true.
+ /// Find if \p RD or one of the classes it inherits from override this method.
+ /// If so, return it. \p RD is assumed to be a subclass of the class defining
+ /// this method (or be the class itself), unless \p MayBeBase is set to true.
CXXMethodDecl *
getCorrespondingMethodInClass(const CXXRecordDecl *RD,
bool MayBeBase = false);
@@ -1725,20 +1804,21 @@ public:
}
};
-/// CXXCtorInitializer - Represents a C++ base or member
-/// initializer, which is part of a constructor initializer that
+/// \brief Represents a C++ base or member initializer.
+///
+/// This is part of a constructor initializer that
/// initializes one non-static member variable or one base class. For
/// example, in the following, both 'A(a)' and 'f(3.14159)' are member
/// initializers:
///
-/// @code
+/// \code
/// class A { };
/// class B : public A {
/// float f;
/// public:
/// B(A& a) : A(a), f(3.14159) { }
/// };
-/// @endcode
+/// \endcode
class CXXCtorInitializer {
/// \brief Either the base class name/delegating constructor type (stored as
/// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
@@ -1747,7 +1827,9 @@ class CXXCtorInitializer {
Initializee;
/// \brief The source location for the field name or, for a base initializer
- /// pack expansion, the location of the ellipsis. In the case of a delegating
+ /// pack expansion, the location of the ellipsis.
+ ///
+ /// In the case of a delegating
/// constructor, it will still include the type's source location as the
/// Initializee points to the CXXConstructorDecl (to allow loop detection).
SourceLocation MemberOrEllipsisLocation;
@@ -1756,29 +1838,28 @@ class CXXCtorInitializer {
/// end up constructing an object (when multiple arguments are involved).
Stmt *Init;
- /// LParenLoc - Location of the left paren of the ctor-initializer.
+ /// \brief Location of the left paren of the ctor-initializer.
SourceLocation LParenLoc;
- /// RParenLoc - Location of the right paren of the ctor-initializer.
+ /// \brief Location of the right paren of the ctor-initializer.
SourceLocation RParenLoc;
/// \brief If the initializee is a type, whether that type makes this
/// a delegating initialization.
bool IsDelegating : 1;
- /// IsVirtual - If the initializer is a base initializer, this keeps track
+ /// \brief If the initializer is a base initializer, this keeps track
/// of whether the base is virtual or not.
bool IsVirtual : 1;
- /// IsWritten - Whether or not the initializer is explicitly written
+ /// \brief Whether or not the initializer is explicitly written
/// in the sources.
bool IsWritten : 1;
- /// SourceOrderOrNumArrayIndices - If IsWritten is true, then this
- /// number keeps track of the textual order of this initializer in the
- /// original sources, counting from 0; otherwise, if IsWritten is false,
- /// it stores the number of array index variables stored after this
- /// object in memory.
+ /// If IsWritten is true, then this number keeps track of the textual order
+ /// of this initializer in the original sources, counting from 0; otherwise,
+ /// it stores the number of array index variables stored after this object
+ /// in memory.
unsigned SourceOrderOrNumArrayIndices : 13;
CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
@@ -1786,25 +1867,25 @@ class CXXCtorInitializer {
SourceLocation R, VarDecl **Indices, unsigned NumIndices);
public:
- /// CXXCtorInitializer - Creates a new base-class initializer.
+ /// \brief Creates a new base-class initializer.
explicit
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init, SourceLocation R,
SourceLocation EllipsisLoc);
- /// CXXCtorInitializer - Creates a new member initializer.
+ /// \brief Creates a new member initializer.
explicit
CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
SourceLocation R);
- /// CXXCtorInitializer - Creates a new anonymous field initializer.
+ /// \brief Creates a new anonymous field initializer.
explicit
CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
SourceLocation R);
- /// CXXCtorInitializer - Creates a new delegating Initializer.
+ /// \brief Creates a new delegating initializer.
explicit
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo,
SourceLocation L, Expr *Init, SourceLocation R);
@@ -1816,14 +1897,13 @@ public:
Expr *Init, SourceLocation R,
VarDecl **Indices, unsigned NumIndices);
- /// isBaseInitializer - Returns true when this initializer is
- /// initializing a base class.
+ /// \brief Determine whether this initializer is initializing a base class.
bool isBaseInitializer() const {
return Initializee.is<TypeSourceInfo*>() && !IsDelegating;
}
- /// isMemberInitializer - Returns true when this initializer is
- /// initializing a non-static data member.
+ /// \brief Determine whether this initializer is initializing a non-static
+ /// data member.
bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); }
bool isAnyMemberInitializer() const {
@@ -1834,15 +1914,18 @@ public:
return Initializee.is<IndirectFieldDecl*>();
}
- /// isInClassMemberInitializer - Returns true when this initializer is an
- /// implicit ctor initializer generated for a field with an initializer
- /// defined on the member declaration.
+ /// \brief Determine whether this initializer is an implicit initializer
+ /// generated for a field with an initializer defined on the member
+ /// declaration.
+ ///
+ /// In-class member initializers (also known as "non-static data member
+ /// initializations", NSDMIs) were introduced in C++11.
bool isInClassMemberInitializer() const {
return isa<CXXDefaultInitExpr>(Init);
}
- /// isDelegatingInitializer - Returns true when this initializer is creating
- /// a delegating constructor.
+ /// \brief Determine whether this initializer is creating a delegating
+ /// constructor.
bool isDelegatingInitializer() const {
return Initializee.is<TypeSourceInfo*>() && IsDelegating;
}
@@ -1864,7 +1947,7 @@ public:
TypeLoc getBaseClassLoc() const;
/// If this is a base class initializer, returns the type of the base class.
- /// Otherwise, returns NULL.
+ /// Otherwise, returns null.
const Type *getBaseClass() const;
/// Returns whether the base is virtual or not.
@@ -1880,9 +1963,8 @@ public:
return Initializee.dyn_cast<TypeSourceInfo *>();
}
- /// getMember - If this is a member initializer, returns the
- /// declaration of the non-static data member being
- /// initialized. Otherwise, returns NULL.
+ /// \brief If this is a member initializer, returns the declaration of the
+ /// non-static data member being initialized. Otherwise, returns null.
FieldDecl *getMember() const {
if (isMemberInitializer())
return Initializee.get<FieldDecl*>();
@@ -1912,7 +1994,7 @@ public:
/// \brief Determine the source range covering the entire initializer.
SourceRange getSourceRange() const LLVM_READONLY;
- /// isWritten - Returns true if this initializer is explicitly written
+ /// \brief Determine whether this initializer is explicitly written
/// in the source code.
bool isWritten() const { return IsWritten; }
@@ -1922,9 +2004,13 @@ public:
return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1;
}
- /// \brief Set the source order of this initializer. This method can only
- /// be called once for each initializer; it cannot be called on an
- /// initializer having a positive number of (implicit) array indices.
+ /// \brief Set the source order of this initializer.
+ ///
+ /// This can only be called once for each initializer; it cannot be called
+ /// on an initializer having a positive number of (implicit) array indices.
+ ///
+ /// This assumes that the initialzier was written in the source code, and
+ /// ensures that isWritten() returns true.
void setSourceOrder(int pos) {
assert(!IsWritten &&
"calling twice setSourceOrder() on the same initializer");
@@ -1969,34 +2055,28 @@ public:
Expr *getInit() const { return static_cast<Expr*>(Init); }
};
-/// CXXConstructorDecl - Represents a C++ constructor within a
-/// class. For example:
+/// \brief Represents a C++ constructor within a class.
///
-/// @code
+/// For example:
+///
+/// \code
/// class X {
/// public:
/// explicit X(int); // represented by a CXXConstructorDecl.
/// };
-/// @endcode
+/// \endcode
class CXXConstructorDecl : public CXXMethodDecl {
virtual void anchor();
- /// IsExplicitSpecified - Whether this constructor declaration has the
- /// 'explicit' keyword specified.
+ /// \brief Whether this constructor declaration has the \c explicit keyword
+ /// specified.
bool IsExplicitSpecified : 1;
- /// ImplicitlyDefined - Whether this constructor was implicitly
- /// defined by the compiler. When false, the constructor was defined
- /// by the user. In C++03, this flag will have the same value as
- /// Implicit. In C++0x, however, a constructor that is
- /// explicitly defaulted (i.e., defined with " = default") will have
- /// @c !Implicit && ImplicitlyDefined.
- bool ImplicitlyDefined : 1;
-
- /// Support for base and member initializers.
- /// CtorInitializers - The arguments used to initialize the base
- /// or member.
+ /// \name Support for base and member initializers.
+ /// \{
+ /// \brief The arguments used to initialize the base or member.
CXXCtorInitializer **CtorInitializers;
unsigned NumCtorInitializers;
+ /// \}
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -2005,8 +2085,8 @@ class CXXConstructorDecl : public CXXMethodDecl {
bool isImplicitlyDeclared, bool isConstexpr)
: CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, SourceLocation()),
- IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
- CtorInitializers(0), NumCtorInitializers(0) {
+ IsExplicitSpecified(isExplicitSpecified), CtorInitializers(0),
+ NumCtorInitializers(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -2020,52 +2100,31 @@ public:
bool isInline, bool isImplicitlyDeclared,
bool isConstexpr);
- /// isExplicitSpecified - Whether this constructor declaration has the
- /// 'explicit' keyword specified.
+ /// \brief Determine whether this constructor declaration has the
+ /// \c explicit keyword specified.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
- /// isExplicit - Whether this constructor was marked "explicit" or not.
+ /// \brief Determine whether this constructor was marked "explicit" or not.
bool isExplicit() const {
- return cast<CXXConstructorDecl>(getFirstDeclaration())
- ->isExplicitSpecified();
- }
-
- /// isImplicitlyDefined - Whether this constructor was implicitly
- /// defined. If false, then this constructor was defined by the
- /// user. This operation can only be invoked if the constructor has
- /// already been defined.
- bool isImplicitlyDefined() const {
- assert(isThisDeclarationADefinition() &&
- "Can only get the implicit-definition flag once the "
- "constructor has been defined");
- return ImplicitlyDefined;
- }
-
- /// setImplicitlyDefined - Set whether this constructor was
- /// implicitly defined or not.
- void setImplicitlyDefined(bool ID) {
- assert(isThisDeclarationADefinition() &&
- "Can only set the implicit-definition flag once the constructor "
- "has been defined");
- ImplicitlyDefined = ID;
+ return cast<CXXConstructorDecl>(getFirstDecl())->isExplicitSpecified();
}
- /// init_iterator - Iterates through the member/base initializer list.
+ /// \brief Iterates through the member/base initializer list.
typedef CXXCtorInitializer **init_iterator;
- /// init_const_iterator - Iterates through the memberbase initializer list.
+ /// \brief Iterates through the member/base initializer list.
typedef CXXCtorInitializer * const * init_const_iterator;
- /// init_begin() - Retrieve an iterator to the first initializer.
+ /// \brief Retrieve an iterator to the first initializer.
init_iterator init_begin() { return CtorInitializers; }
- /// begin() - Retrieve an iterator to the first initializer.
+ /// \brief Retrieve an iterator to the first initializer.
init_const_iterator init_begin() const { return CtorInitializers; }
- /// init_end() - Retrieve an iterator past the last initializer.
+ /// \brief Retrieve an iterator past the last initializer.
init_iterator init_end() {
return CtorInitializers + NumCtorInitializers;
}
- /// end() - Retrieve an iterator past the last initializer.
+ /// \brief Retrieve an iterator past the last initializer.
init_const_iterator init_end() const {
return CtorInitializers + NumCtorInitializers;
}
@@ -2088,8 +2147,8 @@ public:
return init_const_reverse_iterator(init_begin());
}
- /// getNumArgs - Determine the number of arguments used to
- /// initialize the member or base.
+ /// \brief Determine the number of arguments used to initialize the member
+ /// or base.
unsigned getNumCtorInitializers() const {
return NumCtorInitializers;
}
@@ -2102,37 +2161,36 @@ public:
CtorInitializers = initializers;
}
- /// isDelegatingConstructor - Whether this constructor is a
- /// delegating constructor
+ /// \brief Determine whether this constructor is a delegating constructor.
bool isDelegatingConstructor() const {
return (getNumCtorInitializers() == 1) &&
CtorInitializers[0]->isDelegatingInitializer();
}
- /// getTargetConstructor - When this constructor delegates to
- /// another, retrieve the target
+ /// \brief When this constructor delegates to another, retrieve the target.
CXXConstructorDecl *getTargetConstructor() const;
- /// isDefaultConstructor - Whether this constructor is a default
+ /// Whether this constructor is a default
/// constructor (C++ [class.ctor]p5), which can be used to
/// default-initialize a class of this type.
bool isDefaultConstructor() const;
- /// isCopyConstructor - Whether this constructor is a copy
- /// constructor (C++ [class.copy]p2, which can be used to copy the
- /// class. @p TypeQuals will be set to the qualifiers on the
- /// argument type. For example, @p TypeQuals would be set to @c
+ /// \brief Whether this constructor is a copy constructor (C++ [class.copy]p2,
+ /// which can be used to copy the class.
+ ///
+ /// \p TypeQuals will be set to the qualifiers on the
+ /// argument type. For example, \p TypeQuals would be set to \c
/// Qualifiers::Const for the following copy constructor:
///
- /// @code
+ /// \code
/// class X {
/// public:
/// X(const X&);
/// };
- /// @endcode
+ /// \endcode
bool isCopyConstructor(unsigned &TypeQuals) const;
- /// isCopyConstructor - Whether this constructor is a copy
+ /// Whether this constructor is a copy
/// constructor (C++ [class.copy]p2, which can be used to copy the
/// class.
bool isCopyConstructor() const {
@@ -2166,7 +2224,7 @@ public:
return isCopyOrMoveConstructor(Quals);
}
- /// isConvertingConstructor - Whether this constructor is a
+ /// Whether this constructor is a
/// converting constructor (C++ [class.conv.ctor]), which can be
/// used for user-defined conversions.
bool isConvertingConstructor(bool AllowExplicit) const;
@@ -2197,24 +2255,18 @@ public:
friend class ASTDeclWriter;
};
-/// CXXDestructorDecl - Represents a C++ destructor within a
-/// class. For example:
+/// \brief Represents a C++ destructor within a class.
///
-/// @code
+/// For example:
+///
+/// \code
/// class X {
/// public:
/// ~X(); // represented by a CXXDestructorDecl.
/// };
-/// @endcode
+/// \endcode
class CXXDestructorDecl : public CXXMethodDecl {
virtual void anchor();
- /// ImplicitlyDefined - Whether this destructor was implicitly
- /// defined by the compiler. When false, the destructor was defined
- /// by the user. In C++03, this flag will have the same value as
- /// Implicit. In C++0x, however, a destructor that is
- /// explicitly defaulted (i.e., defined with " = default") will have
- /// @c !Implicit && ImplicitlyDefined.
- bool ImplicitlyDefined : 1;
FunctionDecl *OperatorDelete;
@@ -2224,7 +2276,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
bool isInline, bool isImplicitlyDeclared)
: CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
- ImplicitlyDefined(false), OperatorDelete(0) {
+ OperatorDelete(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -2237,26 +2289,6 @@ public:
bool isImplicitlyDeclared);
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
- /// isImplicitlyDefined - Whether this destructor was implicitly
- /// defined. If false, then this destructor was defined by the
- /// user. This operation can only be invoked if the destructor has
- /// already been defined.
- bool isImplicitlyDefined() const {
- assert(isThisDeclarationADefinition() &&
- "Can only get the implicit-definition flag once the destructor has "
- "been defined");
- return ImplicitlyDefined;
- }
-
- /// setImplicitlyDefined - Set whether this destructor was
- /// implicitly defined or not.
- void setImplicitlyDefined(bool ID) {
- assert(isThisDeclarationADefinition() &&
- "Can only set the implicit-definition flag once the destructor has "
- "been defined");
- ImplicitlyDefined = ID;
- }
-
void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; }
const FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
@@ -2268,19 +2300,20 @@ public:
friend class ASTDeclWriter;
};
-/// CXXConversionDecl - Represents a C++ conversion function within a
-/// class. For example:
+/// \brief Represents a C++ conversion function within a class.
+///
+/// For example:
///
-/// @code
+/// \code
/// class X {
/// public:
/// operator bool();
/// };
-/// @endcode
+/// \endcode
class CXXConversionDecl : public CXXMethodDecl {
virtual void anchor();
- /// IsExplicitSpecified - Whether this conversion function declaration is
- /// marked "explicit", meaning that it can only be applied when the user
+ /// Whether this conversion function declaration is marked
+ /// "explicit", meaning that it can only be applied when the user
/// explicitly wrote a cast. This is a C++0x feature.
bool IsExplicitSpecified : 1;
@@ -2303,21 +2336,20 @@ public:
SourceLocation EndLocation);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// IsExplicitSpecified - Whether this conversion function declaration is
- /// marked "explicit", meaning that it can only be applied when the user
- /// explicitly wrote a cast. This is a C++0x feature.
+ /// Whether this conversion function declaration is marked
+ /// "explicit", meaning that it can only be used for direct initialization
+ /// (including explitly written casts). This is a C++11 feature.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
- /// isExplicit - Whether this is an explicit conversion operator
- /// (C++0x only). Explicit conversion operators are only considered
- /// when the user has explicitly written a cast.
+ /// \brief Whether this is an explicit conversion operator (C++11 and later).
+ ///
+ /// Explicit conversion operators are only considered for direct
+ /// initialization, e.g., when the user has explicitly written a cast.
bool isExplicit() const {
- return cast<CXXConversionDecl>(getFirstDeclaration())
- ->isExplicitSpecified();
+ return cast<CXXConversionDecl>(getFirstDecl())->isExplicitSpecified();
}
- /// getConversionType - Returns the type that this conversion
- /// function is converting to.
+ /// \brief Returns the type that this conversion function is converting to.
QualType getConversionType() const {
return getType()->getAs<FunctionType>()->getResultType();
}
@@ -2334,32 +2366,37 @@ public:
friend class ASTDeclWriter;
};
-/// LinkageSpecDecl - This represents a linkage specification. For example:
-/// extern "C" void foo();
+/// \brief Represents a linkage specification.
///
+/// For example:
+/// \code
+/// extern "C" void foo();
+/// \endcode
class LinkageSpecDecl : public Decl, public DeclContext {
virtual void anchor();
public:
- /// LanguageIDs - Used to represent the language in a linkage
- /// specification. The values are part of the serialization abi for
- /// ASTs and cannot be changed without altering that abi. To help
- /// ensure a stable abi for this, we choose the DW_LANG_ encodings
+ /// \brief Represents the language in a linkage specification.
+ ///
+ /// The values are part of the serialization ABI for
+ /// ASTs and cannot be changed without altering that ABI. To help
+ /// ensure a stable ABI for this, we choose the DW_LANG_ encodings
/// from the dwarf standard.
enum LanguageIDs {
lang_c = /* DW_LANG_C */ 0x0002,
lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004
};
private:
- /// Language - The language for this linkage specification.
+ /// \brief The language for this linkage specification.
unsigned Language : 3;
- /// True if this linkage spec has brances. This is needed so that hasBraces()
- /// returns the correct result while the linkage spec body is being parsed.
- /// Once RBraceLoc has been set this is not used, so it doesn't need to be
- /// serialized.
+ /// \brief True if this linkage spec has braces.
+ ///
+ /// This is needed so that hasBraces() returns the correct result while the
+ /// linkage spec body is being parsed. Once RBraceLoc has been set this is
+ /// not used, so it doesn't need to be serialized.
unsigned HasBraces : 1;
- /// ExternLoc - The source location for the extern keyword.
+ /// \brief The source location for the extern keyword.
SourceLocation ExternLoc;
- /// RBraceLoc - The source location for the right brace (if valid).
+ /// \brief The source location for the right brace (if valid).
SourceLocation RBraceLoc;
LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc,
@@ -2417,34 +2454,38 @@ public:
}
};
-/// UsingDirectiveDecl - Represents C++ using-directive. For example:
+/// \brief Represents C++ using-directive.
///
+/// For example:
+/// \code
/// using namespace std;
+/// \endcode
///
-// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide
-// artificial names for all using-directives in order to store
-// them in DeclContext effectively.
+/// \note UsingDirectiveDecl should be Decl not NamedDecl, but we provide
+/// artificial names for all using-directives in order to store
+/// them in DeclContext effectively.
class UsingDirectiveDecl : public NamedDecl {
virtual void anchor();
- /// \brief The location of the "using" keyword.
+ /// \brief The location of the \c using keyword.
SourceLocation UsingLoc;
- /// SourceLocation - Location of 'namespace' token.
+ /// \brief The location of the \c namespace keyword.
SourceLocation NamespaceLoc;
/// \brief The nested-name-specifier that precedes the namespace.
NestedNameSpecifierLoc QualifierLoc;
- /// NominatedNamespace - Namespace nominated by using-directive.
+ /// \brief The namespace nominated by this using-directive.
NamedDecl *NominatedNamespace;
/// Enclosing context containing both using-directive and nominated
/// namespace.
DeclContext *CommonAncestor;
- /// getUsingDirectiveName - Returns special DeclarationName used by
- /// using-directives. This is only used by DeclContext for storing
- /// UsingDirectiveDecls in its lookup structure.
+ /// \brief Returns special DeclarationName used by using-directives.
+ ///
+ /// This is only used by DeclContext for storing UsingDirectiveDecls in
+ /// its lookup structure.
static DeclarationName getName() {
return DeclarationName::getUsingDirectiveName();
}
@@ -2475,7 +2516,7 @@ public:
return NominatedNamespace;
}
- /// getNominatedNamespace - Returns namespace nominated by using-directive.
+ /// \brief Returns the namespace nominated by this using-directive.
NamespaceDecl *getNominatedNamespace();
const NamespaceDecl *getNominatedNamespace() const {
@@ -2487,14 +2528,14 @@ public:
DeclContext *getCommonAncestor() { return CommonAncestor; }
const DeclContext *getCommonAncestor() const { return CommonAncestor; }
- /// \brief Return the location of the "using" keyword.
+ /// \brief Return the location of the \c using keyword.
SourceLocation getUsingLoc() const { return UsingLoc; }
// FIXME: Could omit 'Key' in name.
- /// getNamespaceKeyLocation - Returns location of namespace keyword.
+ /// \brief Returns the location of the \c namespace keyword.
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
- /// getIdentLocation - Returns location of identifier.
+ /// \brief Returns the location of this using declaration's identifier.
SourceLocation getIdentLocation() const { return getLocation(); }
static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
@@ -2523,23 +2564,25 @@ public:
///
/// For example:
///
-/// @code
+/// \code
/// namespace Foo = Bar;
-/// @endcode
+/// \endcode
class NamespaceAliasDecl : public NamedDecl {
virtual void anchor();
- /// \brief The location of the "namespace" keyword.
+ /// \brief The location of the \c namespace keyword.
SourceLocation NamespaceLoc;
- /// IdentLoc - Location of namespace identifier. Accessed by TargetNameLoc.
+ /// \brief The location of the namespace's identifier.
+ ///
+ /// This is accessed by TargetNameLoc.
SourceLocation IdentLoc;
/// \brief The nested-name-specifier that precedes the namespace.
NestedNameSpecifierLoc QualifierLoc;
- /// Namespace - The Decl that this alias points to. Can either be a
- /// NamespaceDecl or a NamespaceAliasDecl.
+ /// \brief The Decl that this alias points to, either a NamespaceDecl or
+ /// a NamespaceAliasDecl.
NamedDecl *Namespace;
NamespaceAliasDecl(DeclContext *DC, SourceLocation NamespaceLoc,
@@ -2579,7 +2622,7 @@ public:
/// "namespace foo = ns::bar;".
SourceLocation getAliasLoc() const { return getLocation(); }
- /// Returns the location of the 'namespace' keyword.
+ /// Returns the location of the \c namespace keyword.
SourceLocation getNamespaceLoc() const { return NamespaceLoc; }
/// Returns the location of the identifier in the named namespace.
@@ -2611,7 +2654,7 @@ public:
/// (resolved) using declaration.
///
/// For example,
-/// @code
+/// \code
/// namespace A {
/// void foo();
/// }
@@ -2619,8 +2662,8 @@ public:
/// using A::foo; // <- a UsingDecl
/// // Also creates a UsingShadowDecl for A::foo() in B
/// }
-/// @endcode
-class UsingShadowDecl : public NamedDecl {
+/// \endcode
+class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
virtual void anchor();
/// The referenced declaration.
@@ -2643,6 +2686,17 @@ class UsingShadowDecl : public NamedDecl {
setImplicit();
}
+ typedef Redeclarable<UsingShadowDecl> redeclarable_base;
+ virtual UsingShadowDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
+ }
+ virtual UsingShadowDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual UsingShadowDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
+
public:
static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation Loc, UsingDecl *Using,
@@ -2651,7 +2705,20 @@ public:
}
static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
+
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
+
+ virtual UsingShadowDecl *getCanonicalDecl() {
+ return getFirstDecl();
+ }
+ virtual const UsingShadowDecl *getCanonicalDecl() const {
+ return getFirstDecl();
+ }
+
/// \brief Gets the underlying declaration which has been brought into the
/// local scope.
NamedDecl *getTargetDecl() const { return Underlying; }
@@ -2683,20 +2750,20 @@ public:
/// \brief Represents a C++ using-declaration.
///
/// For example:
-/// @code
+/// \code
/// using someNameSpace::someIdentifier;
-/// @endcode
+/// \endcode
class UsingDecl : public NamedDecl {
virtual void anchor();
- /// \brief The source location of the "using" location itself.
+ /// \brief The source location of the 'using' keyword itself.
SourceLocation UsingLocation;
/// \brief The nested-name-specifier that precedes the name.
NestedNameSpecifierLoc QualifierLoc;
- /// DNLoc - Provides source/type location info for the
- /// declaration name embedded in the ValueDecl base class.
+ /// \brief Provides source/type location info for the declaration name
+ /// embedded in the ValueDecl base class.
DeclarationNameLoc DNLoc;
/// \brief The first shadow declaration of the shadow decl chain associated
@@ -2708,18 +2775,18 @@ class UsingDecl : public NamedDecl {
UsingDecl(DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
- const DeclarationNameInfo &NameInfo, bool IsTypeNameArg)
+ const DeclarationNameInfo &NameInfo, bool HasTypenameKeyword)
: NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()),
UsingLocation(UL), QualifierLoc(QualifierLoc),
- DNLoc(NameInfo.getInfo()), FirstUsingShadow(0, IsTypeNameArg) {
+ DNLoc(NameInfo.getInfo()), FirstUsingShadow(0, HasTypenameKeyword) {
}
public:
- /// \brief Returns the source location of the "using" keyword.
- SourceLocation getUsingLocation() const { return UsingLocation; }
+ /// \brief Return the source location of the 'using' keyword.
+ SourceLocation getUsingLoc() const { return UsingLocation; }
/// \brief Set the source location of the 'using' keyword.
- void setUsingLocation(SourceLocation L) { UsingLocation = L; }
+ void setUsingLoc(SourceLocation L) { UsingLocation = L; }
/// \brief Retrieve the nested-name-specifier that qualifies the name,
/// with source-location information.
@@ -2734,13 +2801,16 @@ public:
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
+ /// \brief Return true if it is a C++03 access declaration (no 'using').
+ bool isAccessDeclaration() const { return UsingLocation.isInvalid(); }
+
/// \brief Return true if the using declaration has 'typename'.
- bool isTypeName() const { return FirstUsingShadow.getInt(); }
+ bool hasTypename() const { return FirstUsingShadow.getInt(); }
/// \brief Sets whether the using declaration has 'typename'.
- void setTypeName(bool TN) { FirstUsingShadow.setInt(TN); }
+ void setTypename(bool TN) { FirstUsingShadow.setInt(TN); }
- /// \brief Iterates through the using shadow declarations assosiated with
+ /// \brief Iterates through the using shadow declarations associated with
/// this using declaration.
class shadow_iterator {
/// \brief The current using shadow declaration.
@@ -2796,13 +2866,11 @@ public:
SourceLocation UsingL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
- bool IsTypeNameArg);
+ bool HasTypenameKeyword);
static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(UsingLocation, getNameInfo().getEndLoc());
- }
+
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Using; }
@@ -2817,11 +2885,11 @@ public:
/// Unlike non-dependent using declarations, these *only* bring through
/// non-types; otherwise they would break two-phase lookup.
///
-/// @code
+/// \code
/// template \<class T> class A : public Base<T> {
/// using Base<T>::foo;
/// };
-/// @endcode
+/// \endcode
class UnresolvedUsingValueDecl : public ValueDecl {
virtual void anchor();
@@ -2831,8 +2899,8 @@ class UnresolvedUsingValueDecl : public ValueDecl {
/// \brief The nested-name-specifier that precedes the name.
NestedNameSpecifierLoc QualifierLoc;
- /// DNLoc - Provides source/type location info for the
- /// declaration name embedded in the ValueDecl base class.
+ /// \brief Provides source/type location info for the declaration name
+ /// embedded in the ValueDecl base class.
DeclarationNameLoc DNLoc;
UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty,
@@ -2852,6 +2920,9 @@ public:
/// \brief Set the source location of the 'using' keyword.
void setUsingLoc(SourceLocation L) { UsingLocation = L; }
+ /// \brief Return true if it is a C++03 access declaration (no 'using').
+ bool isAccessDeclaration() const { return UsingLocation.isInvalid(); }
+
/// \brief Retrieve the nested-name-specifier that qualifies the name,
/// with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
@@ -2873,9 +2944,7 @@ public:
static UnresolvedUsingValueDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(UsingLocation, getNameInfo().getEndLoc());
- }
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
@@ -2884,23 +2953,20 @@ public:
friend class ASTDeclWriter;
};
-/// @brief Represents a dependent using declaration which was marked with
+/// \brief Represents a dependent using declaration which was marked with
/// \c typename.
///
-/// @code
+/// \code
/// template \<class T> class A : public Base<T> {
/// using typename Base<T>::foo;
/// };
-/// @endcode
+/// \endcode
///
/// The type associated with an unresolved using typename decl is
/// currently always a typename type.
class UnresolvedUsingTypenameDecl : public TypeDecl {
virtual void anchor();
- /// \brief The source location of the 'using' keyword
- SourceLocation UsingLocation;
-
/// \brief The source location of the 'typename' keyword
SourceLocation TypenameLocation;
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 84f3698d6b58..9c626c80aaee 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
@@ -26,23 +27,29 @@ namespace clang {
class DependentDiagnostic;
-/// StoredDeclsList - This is an array of decls optimized a common case of only
-/// containing one entry.
+/// \brief An array of decls optimized for the common case of only containing
+/// one entry.
struct StoredDeclsList {
- /// DeclsTy - When in vector form, this is what the Data pointer points to.
+ /// \brief When in vector form, this is what the Data pointer points to.
typedef SmallVector<NamedDecl *, 4> DeclsTy;
+ /// \brief A collection of declarations, with a flag to indicate if we have
+ /// further external declarations.
+ typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy;
+
/// \brief The stored data, which will be either a pointer to a NamedDecl,
- /// or a pointer to a vector.
- llvm::PointerUnion<NamedDecl *, DeclsTy *> Data;
+ /// or a pointer to a vector with a flag to indicate if there are further
+ /// external declarations.
+ llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data;
public:
StoredDeclsList() {}
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
if (DeclsTy *RHSVec = RHS.getAsVector())
- Data = new DeclsTy(*RHSVec);
+ Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec),
+ RHS.hasExternalDecls());
}
~StoredDeclsList() {
@@ -56,7 +63,7 @@ public:
delete Vector;
Data = RHS.Data;
if (DeclsTy *RHSVec = RHS.getAsVector())
- Data = new DeclsTy(*RHSVec);
+ Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec), hasExternalDecls());
return *this;
}
@@ -66,8 +73,27 @@ public:
return Data.dyn_cast<NamedDecl *>();
}
+ DeclsAndHasExternalTy getAsVectorAndHasExternal() const {
+ return Data.dyn_cast<DeclsAndHasExternalTy>();
+ }
+
DeclsTy *getAsVector() const {
- return Data.dyn_cast<DeclsTy *>();
+ return getAsVectorAndHasExternal().getPointer();
+ }
+
+ bool hasExternalDecls() const {
+ return getAsVectorAndHasExternal().getInt();
+ }
+
+ void setHasExternalDecls() {
+ if (DeclsTy *Vec = getAsVector())
+ Data = DeclsAndHasExternalTy(Vec, true);
+ else {
+ DeclsTy *VT = new DeclsTy();
+ if (NamedDecl *OldD = getAsDecl())
+ VT->push_back(OldD);
+ Data = DeclsAndHasExternalTy(VT, true);
+ }
}
void setOnlyValue(NamedDecl *ND) {
@@ -110,6 +136,8 @@ public:
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
std::mem_fun(&Decl::isFromASTFile)),
Vec.end());
+ // Don't have any external decls any more.
+ Data = DeclsAndHasExternalTy(&Vec, false);
}
}
@@ -165,12 +193,14 @@ public:
/// not a redeclaration to merge it into the appropriate place in our list.
///
void AddSubsequentDecl(NamedDecl *D) {
+ assert(!isNull() && "don't AddSubsequentDecl when we have no decls");
+
// If this is the second decl added to the list, convert this to vector
// form.
if (NamedDecl *OldD = getAsDecl()) {
DeclsTy *VT = new DeclsTy();
VT->push_back(OldD);
- Data = VT;
+ Data = DeclsAndHasExternalTy(VT, false);
}
DeclsTy &Vec = *getAsVector();
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 3a12878e7414..be6f2eb3e3ad 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -220,7 +220,7 @@ public:
};
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
- return friend_iterator(data().FirstFriend);
+ return friend_iterator(getFirstFriend());
}
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
@@ -228,7 +228,7 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
}
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
- assert(FD->NextFriend == 0 && "friend already has next friend?");
+ assert(!FD->NextFriend && "friend already has next friend?");
FD->NextFriend = data().FirstFriend;
data().FirstFriend = FD;
}
diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h
index 4477c25a9135..c16975a3307f 100644
--- a/include/clang/AST/DeclLookups.h
+++ b/include/clang/AST/DeclLookups.h
@@ -37,6 +37,8 @@ public:
StoredDeclsMap::iterator End)
: It(It), End(End) {}
+ DeclarationName getLookupName() const { return It->first; }
+
reference operator*() const { return It->second.getLookupResult(); }
pointer operator->() const { return It->second.getLookupResult(); }
@@ -66,7 +68,7 @@ public:
}
};
-DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
+inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (Primary->hasExternalVisibleStorage())
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
@@ -75,7 +77,7 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
return all_lookups_iterator();
}
-DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
+inline DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (Primary->hasExternalVisibleStorage())
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
@@ -84,6 +86,22 @@ DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
return all_lookups_iterator();
}
+inline
+DeclContext::all_lookups_iterator DeclContext::noload_lookups_begin() const {
+ DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
+ if (StoredDeclsMap *Map = Primary->getLookupPtr())
+ return all_lookups_iterator(Map->begin(), Map->end());
+ return all_lookups_iterator();
+}
+
+inline
+DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const {
+ DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
+ if (StoredDeclsMap *Map = Primary->getLookupPtr())
+ return all_lookups_iterator(Map->end(), Map->end());
+ return all_lookups_iterator();
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 40de0135a74f..2e760d658e43 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -452,7 +452,7 @@ public:
}
/// \brief Determine whether this method has a body.
- virtual bool hasBody() const { return Body; }
+ virtual bool hasBody() const { return Body.isValid(); }
/// \brief Retrieve the body of this method, if it has one.
virtual Stmt *getBody() const;
@@ -463,7 +463,7 @@ public:
void setBody(Stmt *B) { Body = B; }
/// \brief Returns whether this specific method is a definition.
- bool isThisDeclarationADefinition() const { return Body; }
+ bool isThisDeclarationADefinition() const { return hasBody(); }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -553,6 +553,9 @@ public:
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
+ typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
+ ProtocolPropertyMap;
+
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
/// This routine collects list of properties to be implemented in the class.
@@ -1133,6 +1136,8 @@ public:
return lookupInstanceVariable(IVarName, ClassDeclared);
}
+ ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
+
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
@@ -1196,14 +1201,11 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C class.
- ObjCInterfaceDecl *getCanonicalDecl() {
- return getFirstDeclaration();
- }
- const ObjCInterfaceDecl *getCanonicalDecl() const {
- return getFirstDeclaration();
- }
+ ObjCInterfaceDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
// Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; }
@@ -1244,10 +1246,12 @@ private:
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
- bool synthesized)
+ bool synthesized,
+ bool backingIvarReferencedInAccessor)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
- NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
+ NextIvar(0), DeclAccess(ac), Synthesized(synthesized),
+ BackingIvarReferencedInAccessor(backingIvarReferencedInAccessor) {}
public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
@@ -1255,7 +1259,8 @@ public:
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW = NULL,
- bool synthesized=false);
+ bool synthesized=false,
+ bool backingIvarReferencedInAccessor=false);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1277,6 +1282,13 @@ public:
return DeclAccess == None ? Protected : AccessControl(DeclAccess);
}
+ void setBackingIvarReferencedInAccessor(bool val) {
+ BackingIvarReferencedInAccessor = val;
+ }
+ bool getBackingIvarReferencedInAccessor() const {
+ return BackingIvarReferencedInAccessor;
+ }
+
void setSynthesize(bool synth) { Synthesized = synth; }
bool getSynthesize() const { return Synthesized; }
@@ -1291,6 +1303,7 @@ private:
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
unsigned DeclAccess : 3;
unsigned Synthesized : 1;
+ unsigned BackingIvarReferencedInAccessor : 1;
};
@@ -1502,17 +1515,17 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C protocol.
- ObjCProtocolDecl *getCanonicalDecl() {
- return getFirstDeclaration();
- }
- const ObjCProtocolDecl *getCanonicalDecl() const {
- return getFirstDeclaration();
- }
+ ObjCProtocolDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); }
virtual void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const;
+
+void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
+ ProtocolPropertyMap &PM) 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 ca92040c3286..42fe907aa174 100644
--- a/include/clang/AST/DeclOpenMP.h
+++ b/include/clang/AST/DeclOpenMP.h
@@ -1,4 +1,4 @@
-//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
+//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file defines OpenMP nodes.
+/// \brief This file defines OpenMP nodes for declarative directives.
///
//===----------------------------------------------------------------------===//
@@ -20,8 +20,6 @@
namespace clang {
-class DeclRefExpr;
-
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
///
@@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl {
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
Decl(DK, DC, L), NumVars(0) { }
- ArrayRef<const DeclRefExpr *> getVars() const {
- return ArrayRef<const DeclRefExpr *>(
- reinterpret_cast<const DeclRefExpr * const *>(this + 1),
+ ArrayRef<const Expr *> getVars() const {
+ return ArrayRef<const Expr *>(
+ reinterpret_cast<const Expr * const *>(this + 1),
NumVars);
}
- llvm::MutableArrayRef<DeclRefExpr *> getVars() {
- return llvm::MutableArrayRef<DeclRefExpr *>(
- reinterpret_cast<DeclRefExpr **>(this + 1),
+ llvm::MutableArrayRef<Expr *> getVars() {
+ return llvm::MutableArrayRef<Expr *>(
+ reinterpret_cast<Expr **>(this + 1),
NumVars);
}
- void setVars(ArrayRef<DeclRefExpr *> VL);
+ void setVars(ArrayRef<Expr *> VL);
public:
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
- ArrayRef<DeclRefExpr *> VL);
+ ArrayRef<Expr *> VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N);
- typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator;
- typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator;
+ typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
+ typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
unsigned varlist_size() const { return NumVars; }
bool varlist_empty() const { return NumVars == 0; }
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 425a617738b0..24bd28a75aaa 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -34,6 +34,8 @@ class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
class TemplateTemplateParmDecl;
class TypeAliasTemplateDecl;
+class VarTemplateDecl;
+class VarTemplatePartialSpecializationDecl;
/// \brief Stores a template parameter of any kind.
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
@@ -629,9 +631,9 @@ public:
template <class decl_type> friend class RedeclarableTemplate;
/// \brief Retrieves the canonical declaration of this template.
- RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); }
- const RedeclarableTemplateDecl *getCanonicalDecl() const {
- return getFirstDeclaration();
+ RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDecl(); }
+ const RedeclarableTemplateDecl *getCanonicalDecl() const {
+ return getFirstDecl();
}
/// \brief Determines whether this template was a specialization of a
@@ -713,6 +715,7 @@ public:
using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
+ using redeclarable_base::isFirstDecl;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -743,7 +746,7 @@ protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
struct Common : CommonBase {
- Common() : InjectedArgs(0) { }
+ Common() : InjectedArgs(), LazySpecializations() { }
/// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations.
@@ -757,6 +760,13 @@ protected:
/// template, and is allocated lazily, since most function templates do not
/// require the use of this information.
TemplateArgument *InjectedArgs;
+
+ /// \brief If non-null, points to an array of specializations known only
+ /// by their external declaration IDs.
+ ///
+ /// The first value in the array is the number of of specializations
+ /// that follow.
+ uint32_t *LazySpecializations;
};
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
@@ -771,12 +781,13 @@ protected:
friend class FunctionDecl;
+ /// \brief Load any lazily-loaded specializations from the external source.
+ void LoadLazySpecializations() const;
+
/// \brief Retrieve the set of function template specializations of this
/// function template.
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
- getSpecializations() const {
- return getCommonPtr()->Specializations;
- }
+ getSpecializations() const;
/// \brief Add a specialization of this function template.
///
@@ -815,14 +826,14 @@ public:
/// NULL if no such declaration exists.
FunctionTemplateDecl *getPreviousDecl() {
return cast_or_null<FunctionTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
const FunctionTemplateDecl *getPreviousDecl() const {
return cast_or_null<FunctionTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
}
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
@@ -847,7 +858,7 @@ public:
/// arguments for a function template, the notion is convenient when
/// we need to perform substitutions inside the definition of a function
/// template.
- std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs();
+ ArrayRef<TemplateArgument> getInjectedTemplateArgs();
/// \brief Create a function template node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
@@ -1377,7 +1388,7 @@ class ClassTemplateSpecializationDecl
/// \brief The template argument list deduced for the class template
/// partial specialization itself.
- TemplateArgumentList *TemplateArgs;
+ const TemplateArgumentList *TemplateArgs;
};
/// \brief The template that this specialization specializes
@@ -1402,7 +1413,7 @@ class ClassTemplateSpecializationDecl
ExplicitSpecializationInfo *ExplicitInfo;
/// \brief The template arguments used to describe this specialization.
- TemplateArgumentList *TemplateArgs;
+ const TemplateArgumentList *TemplateArgs;
/// \brief The point where this template was instantiated (if any)
SourceLocation PointOfInstantiation;
@@ -1438,9 +1449,9 @@ public:
bool Qualified) const;
ClassTemplateSpecializationDecl *getMostRecentDecl() {
- CXXRecordDecl *Recent
- = cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl());
- if (!isa<ClassTemplateSpecializationDecl>(Recent)) {
+ CXXRecordDecl *Recent = static_cast<CXXRecordDecl *>(
+ this)->getMostRecentDecl();
+ while (!isa<ClassTemplateSpecializationDecl>(Recent)) {
// FIXME: Does injected class name need to be in the redeclarations chain?
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
Recent = Recent->getPreviousDecl();
@@ -1553,7 +1564,7 @@ public:
/// instantiation of the given class template partial specialization whose
/// template arguments have been deduced.
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
- TemplateArgumentList *TemplateArgs) {
+ const TemplateArgumentList *TemplateArgs) {
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Already set to a class template partial specialization!");
SpecializedPartialSpecialization *PS
@@ -1639,13 +1650,7 @@ class ClassTemplatePartialSpecializationDecl
/// \brief The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
- TemplateArgumentLoc *ArgsAsWritten;
- unsigned NumArgsAsWritten;
-
- /// \brief Sequence number indicating when this class template partial
- /// specialization was added to the set of partial specializations for
- /// its owning class template.
- unsigned SequenceNumber;
+ const ASTTemplateArgumentListInfo *ArgsAsWritten;
/// \brief The class template partial specialization from which this
/// class template partial specialization was instantiated.
@@ -1663,16 +1668,12 @@ class ClassTemplatePartialSpecializationDecl
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
- TemplateArgumentLoc *ArgInfos,
- unsigned NumArgInfos,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber);
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl()
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
- TemplateParams(0), ArgsAsWritten(0),
- NumArgsAsWritten(0), SequenceNumber(0),
- InstantiatedFromMember(0, false) { }
+ TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) { }
public:
static ClassTemplatePartialSpecializationDecl *
@@ -1684,15 +1685,15 @@ public:
unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber);
+ ClassTemplatePartialSpecializationDecl *PrevDecl);
static ClassTemplatePartialSpecializationDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<ClassTemplatePartialSpecializationDecl>(
- ClassTemplateSpecializationDecl::getMostRecentDecl());
+ static_cast<ClassTemplateSpecializationDecl *>(
+ this)->getMostRecentDecl());
}
/// Get the list of template parameters
@@ -1701,19 +1702,10 @@ public:
}
/// Get the template arguments as written.
- TemplateArgumentLoc *getTemplateArgsAsWritten() const {
+ const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}
- /// Get the number of template arguments as written.
- unsigned getNumTemplateArgsAsWritten() const {
- return NumArgsAsWritten;
- }
-
- /// \brief Get the sequence number for this class template partial
- /// specialization.
- unsigned getSequenceNumber() const { return SequenceNumber; }
-
/// \brief Retrieve the member class template partial specialization from
/// which this particular class template partial specialization was
/// instantiated.
@@ -1735,15 +1727,15 @@ public:
/// \c Outer<float>::Inner<U*>, this function would return
/// \c Outer<T>::Inner<U*>.
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
- ClassTemplatePartialSpecializationDecl *First
- = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ ClassTemplatePartialSpecializationDecl *First =
+ cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getPointer();
}
void setInstantiatedFromMember(
ClassTemplatePartialSpecializationDecl *PartialSpec) {
- ClassTemplatePartialSpecializationDecl *First
- = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ ClassTemplatePartialSpecializationDecl *First =
+ cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
First->InstantiatedFromMember.setPointer(PartialSpec);
}
@@ -1764,15 +1756,15 @@ public:
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() {
- ClassTemplatePartialSpecializationDecl *First
- = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ ClassTemplatePartialSpecializationDecl *First =
+ cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}
/// \brief Note that this member template is a specialization.
void setMemberSpecialization() {
- ClassTemplatePartialSpecializationDecl *First
- = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ ClassTemplatePartialSpecializationDecl *First =
+ cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
@@ -1821,7 +1813,7 @@ protected:
QualType InjectedClassNameType;
/// \brief If non-null, points to an array of specializations (including
- /// partial specializations) known ownly by their external declaration IDs.
+ /// partial specializations) known only by their external declaration IDs.
///
/// The first value in the array is the number of of specializations/
/// partial specializations that follow.
@@ -1900,14 +1892,23 @@ public:
/// NULL if no such declaration exists.
ClassTemplateDecl *getPreviousDecl() {
return cast_or_null<ClassTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this class template, or
/// NULL if no such declaration exists.
const ClassTemplateDecl *getPreviousDecl() const {
return cast_or_null<ClassTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<const RedeclarableTemplateDecl *>(
+ this)->getPreviousDecl());
+ }
+
+ ClassTemplateDecl *getMostRecentDecl() {
+ return cast<ClassTemplateDecl>(
+ static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
+ }
+ const ClassTemplateDecl *getMostRecentDecl() const {
+ return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl();
}
ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
@@ -1926,11 +1927,6 @@ public:
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
void *InsertPos);
- /// \brief Return the next partial specialization sequence number.
- unsigned getNextPartialSpecSequenceNumber() {
- return getPartialSpecializations().size();
- }
-
/// \brief Retrieve the partial specializations as an ordered list.
void getPartialSpecializations(
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
@@ -2139,14 +2135,15 @@ public:
/// NULL if no such declaration exists.
TypeAliasTemplateDecl *getPreviousDecl() {
return cast_or_null<TypeAliasTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
const TypeAliasTemplateDecl *getPreviousDecl() const {
return cast_or_null<TypeAliasTemplateDecl>(
- RedeclarableTemplateDecl::getPreviousDecl());
+ static_cast<const RedeclarableTemplateDecl *>(
+ this)->getPreviousDecl());
}
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
@@ -2239,6 +2236,578 @@ public:
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { }
+/// \brief Represents a variable template specialization, which refers to
+/// a variable template with a given set of template arguments.
+///
+/// Variable template specializations represent both explicit
+/// specializations of variable templates, as in the example below, and
+/// implicit instantiations of variable templates.
+///
+/// \code
+/// template<typename T> constexpr T pi = T(3.1415926535897932385);
+///
+/// template<>
+/// constexpr float pi<float>; // variable template specialization pi<float>
+/// \endcode
+class VarTemplateSpecializationDecl : public VarDecl,
+ public llvm::FoldingSetNode {
+
+ /// \brief Structure that stores information about a variable template
+ /// specialization that was instantiated from a variable template partial
+ /// specialization.
+ struct SpecializedPartialSpecialization {
+ /// \brief The variable template partial specialization from which this
+ /// variable template specialization was instantiated.
+ VarTemplatePartialSpecializationDecl *PartialSpecialization;
+
+ /// \brief The template argument list deduced for the variable template
+ /// partial specialization itself.
+ const TemplateArgumentList *TemplateArgs;
+ };
+
+ /// \brief The template that this specialization specializes.
+ llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
+ SpecializedTemplate;
+
+ /// \brief Further info for explicit template specialization/instantiation.
+ struct ExplicitSpecializationInfo {
+ /// \brief The type-as-written.
+ TypeSourceInfo *TypeAsWritten;
+ /// \brief The location of the extern keyword.
+ SourceLocation ExternLoc;
+ /// \brief The location of the template keyword.
+ SourceLocation TemplateKeywordLoc;
+
+ ExplicitSpecializationInfo()
+ : TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {}
+ };
+
+ /// \brief Further info for explicit template specialization/instantiation.
+ /// Does not apply to implicit specializations.
+ ExplicitSpecializationInfo *ExplicitInfo;
+
+ /// \brief The template arguments used to describe this specialization.
+ const TemplateArgumentList *TemplateArgs;
+ TemplateArgumentListInfo TemplateArgsInfo;
+
+ /// \brief The point where this template was instantiated (if any).
+ SourceLocation PointOfInstantiation;
+
+ /// \brief The kind of specialization this declaration refers to.
+ /// Really a value of type TemplateSpecializationKind.
+ unsigned SpecializationKind : 3;
+
+protected:
+ VarTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ VarTemplateDecl *SpecializedTemplate,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs);
+
+ explicit VarTemplateSpecializationDecl(Kind DK);
+
+public:
+ static VarTemplateSpecializationDecl *
+ Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs);
+ static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+
+ virtual void getNameForDiagnostic(raw_ostream &OS,
+ const PrintingPolicy &Policy,
+ bool Qualified) const;
+
+ VarTemplateSpecializationDecl *getMostRecentDecl() {
+ VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl();
+ return cast<VarTemplateSpecializationDecl>(Recent);
+ }
+
+ /// \brief Retrieve the template that this specialization specializes.
+ VarTemplateDecl *getSpecializedTemplate() const;
+
+ /// \brief Retrieve the template arguments of the variable template
+ /// specialization.
+ const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
+
+ // TODO: Always set this when creating the new specialization?
+ void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
+
+ const TemplateArgumentListInfo &getTemplateArgsInfo() const {
+ return TemplateArgsInfo;
+ }
+
+ /// \brief Determine the kind of specialization that this
+ /// declaration represents.
+ TemplateSpecializationKind getSpecializationKind() const {
+ return static_cast<TemplateSpecializationKind>(SpecializationKind);
+ }
+
+ bool isExplicitSpecialization() const {
+ return getSpecializationKind() == TSK_ExplicitSpecialization;
+ }
+
+ /// \brief True if this declaration is an explicit specialization,
+ /// explicit instantiation declaration, or explicit instantiation
+ /// definition.
+ bool isExplicitInstantiationOrSpecialization() const {
+ switch (getTemplateSpecializationKind()) {
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ return true;
+
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ return false;
+ }
+ llvm_unreachable("bad template specialization kind");
+ }
+
+ void setSpecializationKind(TemplateSpecializationKind TSK) {
+ SpecializationKind = TSK;
+ }
+
+ /// \brief Get the point of instantiation (if any), or null if none.
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
+ }
+
+ void setPointOfInstantiation(SourceLocation Loc) {
+ assert(Loc.isValid() && "point of instantiation must be valid!");
+ PointOfInstantiation = Loc;
+ }
+
+ /// \brief If this variable template specialization is an instantiation of
+ /// a template (rather than an explicit specialization), return the
+ /// variable template or variable template partial specialization from which
+ /// it was instantiated.
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ getInstantiatedFrom() const {
+ if (getSpecializationKind() != TSK_ImplicitInstantiation &&
+ getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
+ getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
+ return llvm::PointerUnion<VarTemplateDecl *,
+ VarTemplatePartialSpecializationDecl *>();
+
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization;
+
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+ }
+
+ /// \brief Retrieve the variable template or variable template partial
+ /// specialization which was specialized by this.
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ getSpecializedTemplateOrPartial() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization;
+
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+ }
+
+ /// \brief Retrieve the set of template arguments that should be used
+ /// to instantiate the initializer of the variable template or variable
+ /// template partial specialization from which this variable template
+ /// specialization was instantiated.
+ ///
+ /// \returns For a variable template specialization instantiated from the
+ /// primary template, this function will return the same template arguments
+ /// as getTemplateArgs(). For a variable template specialization instantiated
+ /// from a variable template partial specialization, this function will the
+ /// return deduced template arguments for the variable template partial
+ /// specialization itself.
+ const TemplateArgumentList &getTemplateInstantiationArgs() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return *PartialSpec->TemplateArgs;
+
+ return getTemplateArgs();
+ }
+
+ /// \brief Note that this variable template specialization is actually an
+ /// instantiation of the given variable template partial specialization whose
+ /// template arguments have been deduced.
+ void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
+ const TemplateArgumentList *TemplateArgs) {
+ assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
+ "Already set to a variable template partial specialization!");
+ SpecializedPartialSpecialization *PS =
+ new (getASTContext()) SpecializedPartialSpecialization();
+ PS->PartialSpecialization = PartialSpec;
+ PS->TemplateArgs = TemplateArgs;
+ SpecializedTemplate = PS;
+ }
+
+ /// \brief Note that this variable template specialization is an instantiation
+ /// of the given variable template.
+ void setInstantiationOf(VarTemplateDecl *TemplDecl) {
+ assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
+ "Previously set to a variable template partial specialization!");
+ SpecializedTemplate = TemplDecl;
+ }
+
+ /// \brief Sets the type of this specialization as it was written by
+ /// the user.
+ void setTypeAsWritten(TypeSourceInfo *T) {
+ if (!ExplicitInfo)
+ ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = T;
+ }
+ /// \brief Gets the type of this specialization as it was written by
+ /// the user, if it was so written.
+ TypeSourceInfo *getTypeAsWritten() const {
+ return ExplicitInfo ? ExplicitInfo->TypeAsWritten : 0;
+ }
+
+ /// \brief Gets the location of the extern keyword, if present.
+ SourceLocation getExternLoc() const {
+ return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
+ }
+ /// \brief Sets the location of the extern keyword.
+ void setExternLoc(SourceLocation Loc) {
+ if (!ExplicitInfo)
+ ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
+ ExplicitInfo->ExternLoc = Loc;
+ }
+
+ /// \brief Sets the location of the template keyword.
+ void setTemplateKeywordLoc(SourceLocation Loc) {
+ if (!ExplicitInfo)
+ ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
+ ExplicitInfo->TemplateKeywordLoc = Loc;
+ }
+ /// \brief Gets the location of the template keyword, if present.
+ SourceLocation getTemplateKeywordLoc() const {
+ return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs, ASTContext &Context) {
+ ID.AddInteger(NumTemplateArgs);
+ for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
+ TemplateArgs[Arg].Profile(ID, Context);
+ }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K >= firstVarTemplateSpecialization &&
+ K <= lastVarTemplateSpecialization;
+ }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
+class VarTemplatePartialSpecializationDecl
+ : public VarTemplateSpecializationDecl {
+ virtual void anchor();
+
+ /// \brief The list of template parameters
+ TemplateParameterList *TemplateParams;
+
+ /// \brief The source info for the template arguments as written.
+ /// FIXME: redundant with TypeAsWritten?
+ const ASTTemplateArgumentListInfo *ArgsAsWritten;
+
+ /// \brief The variable template partial specialization from which this
+ /// variable template partial specialization was instantiated.
+ ///
+ /// The boolean value will be true to indicate that this variable template
+ /// partial specialization was specialized at this level.
+ llvm::PointerIntPair<VarTemplatePartialSpecializationDecl *, 1, bool>
+ InstantiatedFromMember;
+
+ VarTemplatePartialSpecializationDecl(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const ASTTemplateArgumentListInfo *ArgInfos);
+
+ VarTemplatePartialSpecializationDecl()
+ : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization),
+ TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) {}
+
+public:
+ static VarTemplatePartialSpecializationDecl *
+ Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos);
+
+ static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+
+ VarTemplatePartialSpecializationDecl *getMostRecentDecl() {
+ return cast<VarTemplatePartialSpecializationDecl>(
+ static_cast<VarTemplateSpecializationDecl *>(
+ this)->getMostRecentDecl());
+ }
+
+ /// Get the list of template parameters
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ /// Get the template arguments as written.
+ const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+ return ArgsAsWritten;
+ }
+
+ /// \brief Retrieve the member variable template partial specialization from
+ /// which this particular variable template partial specialization was
+ /// instantiated.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct Outer {
+ /// template<typename U> U Inner;
+ /// template<typename U> U* Inner<U*> = (U*)(0); // #1
+ /// };
+ ///
+ /// template int* Outer<float>::Inner<int*>;
+ /// \endcode
+ ///
+ /// In this example, the instantiation of \c Outer<float>::Inner<int*> will
+ /// end up instantiating the partial specialization
+ /// \c Outer<float>::Inner<U*>, which itself was instantiated from the
+ /// variable template partial specialization \c Outer<T>::Inner<U*>. Given
+ /// \c Outer<float>::Inner<U*>, this function would return
+ /// \c Outer<T>::Inner<U*>.
+ VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
+ VarTemplatePartialSpecializationDecl *First =
+ cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ return First->InstantiatedFromMember.getPointer();
+ }
+
+ void
+ setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) {
+ VarTemplatePartialSpecializationDecl *First =
+ cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ First->InstantiatedFromMember.setPointer(PartialSpec);
+ }
+
+ /// \brief Determines whether this variable template partial specialization
+ /// was a specialization of a member partial specialization.
+ ///
+ /// In the following example, the member template partial specialization
+ /// \c X<int>::Inner<T*> is a member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> U Inner;
+ /// template<typename U> U* Inner<U*> = (U*)(0);
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// U* X<int>::Inner<T*> = (T*)(0) + 1;
+ /// \endcode
+ bool isMemberSpecialization() {
+ VarTemplatePartialSpecializationDecl *First =
+ cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ return First->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ VarTemplatePartialSpecializationDecl *First =
+ cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ assert(First->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ return First->InstantiatedFromMember.setInt(true);
+ }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K == VarTemplatePartialSpecialization;
+ }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
+/// Declaration of a variable template.
+class VarTemplateDecl : public RedeclarableTemplateDecl {
+ static void DeallocateCommon(void *Ptr);
+
+protected:
+ /// \brief Data that is common to all of the declarations of a given
+ /// variable template.
+ struct Common : CommonBase {
+ Common() : LazySpecializations() {}
+
+ /// \brief The variable template specializations for this variable
+ /// template, including explicit specializations and instantiations.
+ llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations;
+
+ /// \brief The variable template partial specializations for this variable
+ /// template.
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
+ PartialSpecializations;
+
+ /// \brief If non-null, points to an array of specializations (including
+ /// partial specializations) known ownly by their external declaration IDs.
+ ///
+ /// The first value in the array is the number of of specializations/
+ /// partial specializations that follow.
+ uint32_t *LazySpecializations;
+ };
+
+ /// \brief Load any lazily-loaded specializations from the external source.
+ void LoadLazySpecializations() const;
+
+ /// \brief Retrieve the set of specializations of this variable template.
+ llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
+ getSpecializations() const;
+
+ /// \brief Retrieve the set of partial specializations of this class
+ /// template.
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
+ getPartialSpecializations();
+
+ VarTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : RedeclarableTemplateDecl(VarTemplate, DC, L, Name, Params, Decl) {}
+
+ VarTemplateDecl(EmptyShell Empty)
+ : RedeclarableTemplateDecl(VarTemplate, 0, SourceLocation(),
+ DeclarationName(), 0, 0) {}
+
+ CommonBase *newCommon(ASTContext &C) const;
+
+ Common *getCommonPtr() const {
+ return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
+ }
+
+public:
+ /// \brief Get the underlying variable declarations of the template.
+ VarDecl *getTemplatedDecl() const {
+ return static_cast<VarDecl *>(TemplatedDecl);
+ }
+
+ /// \brief Returns whether this template declaration defines the primary
+ /// variable pattern.
+ bool isThisDeclarationADefinition() const {
+ return getTemplatedDecl()->isThisDeclarationADefinition();
+ }
+
+ VarTemplateDecl *getDefinition();
+
+ /// \brief Create a variable template node.
+ static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl,
+ VarTemplateDecl *PrevDecl);
+
+ /// \brief Create an empty variable template node.
+ static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ /// \brief Return the specialization with the provided arguments if it exists,
+ /// otherwise return the insertion point.
+ VarTemplateSpecializationDecl *
+ findSpecialization(const TemplateArgument *Args, unsigned NumArgs,
+ void *&InsertPos);
+
+ /// \brief Insert the specified specialization knowing that it is not already
+ /// in. InsertPos must be obtained from findSpecialization.
+ void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos);
+
+ VarTemplateDecl *getCanonicalDecl() {
+ return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
+ }
+ const VarTemplateDecl *getCanonicalDecl() const {
+ return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
+ }
+
+ /// \brief Retrieve the previous declaration of this variable template, or
+ /// NULL if no such declaration exists.
+ VarTemplateDecl *getPreviousDecl() {
+ return cast_or_null<VarTemplateDecl>(
+ static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
+ }
+
+ /// \brief Retrieve the previous declaration of this variable template, or
+ /// NULL if no such declaration exists.
+ const VarTemplateDecl *getPreviousDecl() const {
+ return cast_or_null<VarTemplateDecl>(
+ static_cast<const RedeclarableTemplateDecl *>(
+ this)->getPreviousDecl());
+ }
+
+ VarTemplateDecl *getInstantiatedFromMemberTemplate() {
+ return cast_or_null<VarTemplateDecl>(
+ RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
+ }
+
+ /// \brief Return the partial specialization with the provided arguments if it
+ /// exists, otherwise return the insertion point.
+ VarTemplatePartialSpecializationDecl *
+ findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs,
+ void *&InsertPos);
+
+ /// \brief Insert the specified partial specialization knowing that it is not
+ /// already in. InsertPos must be obtained from findPartialSpecialization.
+ void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D,
+ void *InsertPos);
+
+ /// \brief Retrieve the partial specializations as an ordered list.
+ void getPartialSpecializations(
+ SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS);
+
+ /// \brief Find a variable template partial specialization which was
+ /// instantiated
+ /// from the given member partial specialization.
+ ///
+ /// \param D a member variable template partial specialization.
+ ///
+ /// \returns the variable template partial specialization which was
+ /// instantiated
+ /// from the given member partial specialization, or NULL if no such partial
+ /// specialization exists.
+ VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember(
+ VarTemplatePartialSpecializationDecl *D);
+
+ typedef SpecIterator<VarTemplateSpecializationDecl> spec_iterator;
+
+ spec_iterator spec_begin() const {
+ return makeSpecIterator(getSpecializations(), false);
+ }
+
+ spec_iterator spec_end() const {
+ return makeSpecIterator(getSpecializations(), true);
+ }
+
+ typedef SpecIterator<VarTemplatePartialSpecializationDecl>
+ partial_spec_iterator;
+
+ partial_spec_iterator partial_spec_begin() {
+ return makeSpecIterator(getPartialSpecializations(), false);
+ }
+
+ partial_spec_iterator partial_spec_end() {
+ return makeSpecIterator(getPartialSpecializations(), true);
+ }
+
+ // Implement isa/cast/dyncast support
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == VarTemplate; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
} /* end of namespace clang */
#endif
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index f28882b3bf94..00766c27c136 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -182,11 +182,16 @@ public:
// operator bool() - Evaluates true when this declaration name is
// non-empty.
- operator bool() const {
+ LLVM_EXPLICIT operator bool() const {
return ((Ptr & PtrMask) != 0) ||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
}
+ /// \brief Evaluates true when this declaration name is empty.
+ bool isEmpty() const {
+ return !*this;
+ }
+
/// Predicate functions for querying what type of name this is.
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
bool isObjCZeroArgSelector() const {
@@ -210,9 +215,6 @@ public:
/// getNameAsString - Retrieve the human-readable string for this name.
std::string getAsString() const;
- /// printName - Print the human-readable name to a stream.
- void printName(raw_ostream &OS) const;
-
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
/// this declaration name, or NULL if this declaration name isn't a
/// simple identifier.
@@ -302,6 +304,8 @@ public:
void dump() const;
};
+raw_ostream &operator<<(raw_ostream &OS, DeclarationName N);
+
/// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering.
inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index 2e3cbfad919d..12c4fcc49b01 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -53,7 +53,7 @@ public:
if (E->getCond()->isValueDependent())
return;
// Only the selected subexpression matters; the other one is not evaluated.
- return this->Visit(E->getChosenSubExpr(Context));
+ return this->Visit(E->getChosenSubExpr());
}
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 4ff1257b7dc8..f2648b9a4a04 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -277,7 +277,6 @@ public:
MLV_IncompleteType,
MLV_ConstQualified,
MLV_ArrayType,
- MLV_ReadonlyProperty,
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
@@ -483,21 +482,22 @@ public:
///
/// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5.
- bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
+ bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx,
SourceLocation *Loc = 0,
bool isEvaluated = true) const;
- bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const;
+ bool isIntegerConstantExpr(const ASTContext &Ctx,
+ SourceLocation *Loc = 0) const;
/// isCXX98IntegralConstantExpr - Return true if this expression is an
/// integral constant expression in C++98. Can only be used in C++.
- bool isCXX98IntegralConstantExpr(ASTContext &Ctx) const;
+ bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const;
/// isCXX11ConstantExpr - Return true if this expression is a constant
/// expression in C++11. Can only be used in C++.
///
/// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5.
- bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
+ bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = 0,
SourceLocation *Loc = 0) const;
/// isPotentialConstantExpr - Return true if this function's definition
@@ -579,15 +579,14 @@ public:
/// \brief Determine whether this expression involves a call to any function
/// that is not trivial.
bool hasNonTrivialCall(ASTContext &Ctx);
-
+
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an
/// integer.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
-
- void EvaluateForOverflow(const ASTContext &Ctx,
- SmallVectorImpl<PartialDiagnosticAt> *Diag) const;
+
+ void EvaluateForOverflow(const ASTContext &Ctx) const;
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
/// lvalue with link time known address, with no side-effects.
@@ -760,10 +759,10 @@ public:
/// Walk outwards from an expression we want to bind a reference to and
/// find the expression whose lifetime needs to be extended. Record
- /// the adjustments needed along the path.
- const Expr *
- skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
+ /// the LHSs of comma expressions and adjustments needed along the path.
+ const Expr *skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHS,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
/// Skip irrelevant expressions to find what should be materialize for
/// binding with a reference.
@@ -893,7 +892,7 @@ class DeclRefExpr : public Expr {
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
/// \brief Helper to retrieve the optional NamedDecl through which this
- /// reference occured.
+ /// reference occurred.
NamedDecl *&getInternalFoundDecl() {
assert(hasFoundDecl());
if (hasQualifier())
@@ -902,12 +901,12 @@ class DeclRefExpr : public Expr {
}
/// \brief Helper to retrieve the optional NamedDecl through which this
- /// reference occured.
+ /// reference occurred.
NamedDecl *getInternalFoundDecl() const {
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
}
- DeclRefExpr(ASTContext &Ctx,
+ DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D, bool refersToEnclosingLocal,
@@ -922,7 +921,7 @@ class DeclRefExpr : public Expr {
/// \brief Computes the type- and value-dependence flags for this
/// declaration reference expression.
- void computeDependence(ASTContext &C);
+ void computeDependence(const ASTContext &C);
public:
DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
@@ -938,7 +937,7 @@ public:
computeDependence(D->getASTContext());
}
- static DeclRefExpr *Create(ASTContext &Context,
+ static DeclRefExpr *Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -948,7 +947,7 @@ public:
NamedDecl *FoundD = 0,
const TemplateArgumentListInfo *TemplateArgs = 0);
- static DeclRefExpr *Create(ASTContext &Context,
+ static DeclRefExpr *Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -959,7 +958,7 @@ public:
const TemplateArgumentListInfo *TemplateArgs = 0);
/// \brief Construct an empty declaration reference expression.
- static DeclRefExpr *CreateEmpty(ASTContext &Context,
+ static DeclRefExpr *CreateEmpty(const ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
@@ -1000,7 +999,7 @@ public:
return getInternalQualifierLoc();
}
- /// \brief Get the NamedDecl through which this reference occured.
+ /// \brief Get the NamedDecl through which this reference occurred.
///
/// This Decl may be different from the ValueDecl actually referred to in the
/// presence of using declarations, etc. It always returns non-NULL, and may
@@ -1151,6 +1150,7 @@ public:
Func,
Function,
LFunction, // Same as Function, but as wide string.
+ FuncDName,
PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.
@@ -1221,13 +1221,15 @@ protected:
else
return llvm::APInt(BitWidth, VAL);
}
- void setIntValue(ASTContext &C, const llvm::APInt &Val);
+ void setIntValue(const ASTContext &C, const llvm::APInt &Val);
};
class APIntStorage : private APNumericStorage {
public:
llvm::APInt getValue() const { return getIntValue(); }
- void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); }
+ void setValue(const ASTContext &C, const llvm::APInt &Val) {
+ setIntValue(C, Val);
+ }
};
class APFloatStorage : private APNumericStorage {
@@ -1235,7 +1237,7 @@ public:
llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
return llvm::APFloat(Semantics, getIntValue());
}
- void setValue(ASTContext &C, const llvm::APFloat &Val) {
+ void setValue(const ASTContext &C, const llvm::APFloat &Val) {
setIntValue(C, Val.bitcastToAPInt());
}
};
@@ -1250,17 +1252,17 @@ class IntegerLiteral : public Expr, public APIntStorage {
public:
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
// or UnsignedLongLongTy
- IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type,
+ IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
SourceLocation l);
/// \brief Returns a new integer literal with value 'V' and type 'type'.
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
/// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
/// \param V - the value that the returned integer literal contains.
- static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V,
+ static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l);
/// \brief Returns a new empty integer literal.
- static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
+ static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty);
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
@@ -1328,21 +1330,21 @@ public:
class FloatingLiteral : public Expr, private APFloatStorage {
SourceLocation Loc;
- FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact,
+ FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact,
QualType Type, SourceLocation L);
/// \brief Construct an empty floating-point literal.
- explicit FloatingLiteral(ASTContext &C, EmptyShell Empty);
+ explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty);
public:
- static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V,
+ static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L);
- static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
+ static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty);
llvm::APFloat getValue() const {
return APFloatStorage::getValue(getSemantics());
}
- void setValue(ASTContext &C, const llvm::APFloat &Val) {
+ void setValue(const ASTContext &C, const llvm::APFloat &Val) {
assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics");
APFloatStorage::setValue(C, Val);
}
@@ -1420,7 +1422,7 @@ public:
};
/// StringLiteral - This represents a string literal expression, e.g. "foo"
-/// or L"bar" (wide strings). The actual string is returned by getStrData()
+/// or L"bar" (wide strings). The actual string is returned by getBytes()
/// is NOT null-terminated, and the length of the string is determined by
/// calling getByteLength(). The C type for a string is always a
/// ConstantArrayType. In C++, the char type is const qualified, in C it is
@@ -1469,19 +1471,19 @@ private:
public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
- static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
- bool Pascal, QualType Ty,
+ static StringLiteral *Create(const ASTContext &C, StringRef Str,
+ StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc, unsigned NumStrs);
/// Simple constructor for string literals made from one token.
- static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
- bool Pascal, QualType Ty,
+ static StringLiteral *Create(const ASTContext &C, StringRef Str,
+ StringKind Kind, bool Pascal, QualType Ty,
SourceLocation Loc) {
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
}
/// \brief Construct an empty string literal.
- static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
+ static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs);
StringRef getString() const {
assert(CharByteWidth==1
@@ -1520,7 +1522,7 @@ public:
unsigned getCharByteWidth() const { return CharByteWidth; }
/// \brief Sets the string data to the given string data.
- void setString(ASTContext &C, StringRef Str,
+ void setString(const ASTContext &C, StringRef Str,
StringKind Kind, bool IsPascal);
StringKind getKind() const { return static_cast<StringKind>(Kind); }
@@ -1853,7 +1855,7 @@ private:
// Number of sub-expressions (i.e. array subscript expressions).
unsigned NumExprs;
- OffsetOfExpr(ASTContext &C, QualType type,
+ OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc);
@@ -1864,12 +1866,12 @@ private:
public:
- static OffsetOfExpr *Create(ASTContext &C, QualType type,
+ static OffsetOfExpr *Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps,
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
- static OffsetOfExpr *CreateEmpty(ASTContext &C,
+ static OffsetOfExpr *CreateEmpty(const ASTContext &C,
unsigned NumComps, unsigned NumExprs);
/// getOperatorLoc - Return the location of the operator.
@@ -2133,10 +2135,11 @@ class CallExpr : public Expr {
protected:
// These versions of the constructor are for derived classes.
- CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
+ CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc);
- CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty);
+ CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
+ EmptyShell Empty);
Stmt *getPreArg(unsigned i) {
assert(i < getNumPreArgs() && "Prearg access out of range!");
@@ -2154,11 +2157,11 @@ protected:
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
public:
- CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
+ CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc);
/// \brief Build an empty call expression.
- CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty);
+ CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty);
const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
@@ -2206,7 +2209,7 @@ public:
/// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set
/// to null.
- void setNumArgs(ASTContext& C, unsigned NumArgs);
+ void setNumArgs(const ASTContext& C, unsigned NumArgs);
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -2360,7 +2363,7 @@ public:
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
HadMultipleCandidates(false) {}
- static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
+ static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *memberdecl, DeclAccessPair founddecl,
@@ -2747,12 +2750,13 @@ public:
: CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) {
}
- static ImplicitCastExpr *Create(ASTContext &Context, QualType T,
+ static ImplicitCastExpr *Create(const ASTContext &Context, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
ExprValueKind Cat);
- static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
+ static ImplicitCastExpr *CreateEmpty(const ASTContext &Context,
+ unsigned PathSize);
SourceLocation getLocStart() const LLVM_READONLY {
return getSubExpr()->getLocStart();
@@ -2838,13 +2842,14 @@ class CStyleCastExpr : public ExplicitCastExpr {
: ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { }
public:
- static CStyleCastExpr *Create(ASTContext &Context, QualType T,
+ static CStyleCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, CastKind K,
Expr *Op, const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation R);
- static CStyleCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
+ static CStyleCastExpr *CreateEmpty(const ASTContext &Context,
+ unsigned PathSize);
SourceLocation getLParenLoc() const { return LPLoc; }
void setLParenLoc(SourceLocation L) { LPLoc = L; }
@@ -3412,7 +3417,7 @@ class ShuffleVectorExpr : public Expr {
unsigned NumExprs;
public:
- ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
+ ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type,
SourceLocation BLoc, SourceLocation RP);
/// \brief Build an empty vector-shuffle expression.
@@ -3450,11 +3455,11 @@ public:
return cast<Expr>(SubExprs[Index]);
}
- void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs);
+ void setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs);
- unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const {
+ llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const {
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
- return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
+ return getExpr(N+2)->EvaluateKnownConstInt(Ctx);
}
// Iterators
@@ -3463,6 +3468,60 @@ public:
}
};
+/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
+/// This AST node provides support for converting a vector type to another
+/// vector type of the same arity.
+class ConvertVectorExpr : public Expr {
+private:
+ Stmt *SrcExpr;
+ TypeSourceInfo *TInfo;
+ SourceLocation BuiltinLoc, RParenLoc;
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+ explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {}
+
+public:
+ ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType,
+ ExprValueKind VK, ExprObjectKind OK,
+ SourceLocation BuiltinLoc, SourceLocation RParenLoc)
+ : Expr(ConvertVectorExprClass, DstType, VK, OK,
+ DstType->isDependentType(),
+ DstType->isDependentType() || SrcExpr->isValueDependent(),
+ (DstType->isInstantiationDependentType() ||
+ SrcExpr->isInstantiationDependent()),
+ (DstType->containsUnexpandedParameterPack() ||
+ SrcExpr->containsUnexpandedParameterPack())),
+ SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
+
+ /// getSrcExpr - Return the Expr to be converted.
+ Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
+
+ /// getTypeSourceInfo - Return the destination type.
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return TInfo;
+ }
+ void setTypeSourceInfo(TypeSourceInfo *ti) {
+ TInfo = ti;
+ }
+
+ /// getBuiltinLoc - Return the location of the __builtin_convertvector token.
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+
+ /// getRParenLoc - Return the location of final right parenthesis.
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConvertVectorExprClass;
+ }
+
+ // Iterators
+ child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+};
+
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
/// This AST node is similar to the conditional operator (?:) in C, with
/// the following exceptions:
@@ -3476,10 +3535,12 @@ class ChooseExpr : public Expr {
enum { COND, LHS, RHS, END_EXPR };
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
SourceLocation BuiltinLoc, RParenLoc;
+ bool CondIsTrue;
public:
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
QualType t, ExprValueKind VK, ExprObjectKind OK,
- SourceLocation RP, bool TypeDependent, bool ValueDependent)
+ SourceLocation RP, bool condIsTrue,
+ bool TypeDependent, bool ValueDependent)
: Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent,
(cond->isInstantiationDependent() ||
lhs->isInstantiationDependent() ||
@@ -3487,7 +3548,7 @@ public:
(cond->containsUnexpandedParameterPack() ||
lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- BuiltinLoc(BLoc), RParenLoc(RP) {
+ BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) {
SubExprs[COND] = cond;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
@@ -3498,12 +3559,21 @@ public:
/// isConditionTrue - Return whether the condition is true (i.e. not
/// equal to zero).
- bool isConditionTrue(const ASTContext &C) const;
+ bool isConditionTrue() const {
+ assert(!isConditionDependent() &&
+ "Dependent condition isn't true or false");
+ return CondIsTrue;
+ }
+ void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; }
+
+ bool isConditionDependent() const {
+ return getCond()->isTypeDependent() || getCond()->isValueDependent();
+ }
/// getChosenSubExpr - Return the subexpression chosen according to the
/// condition.
- Expr *getChosenSubExpr(const ASTContext &C) const {
- return isConditionTrue(C) ? getLHS() : getRHS();
+ Expr *getChosenSubExpr() const {
+ return isConditionTrue() ? getLHS() : getRHS();
}
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
@@ -3663,7 +3733,7 @@ class InitListExpr : public Expr {
SourceLocation LBraceLoc, RBraceLoc;
/// The alternative form of the initializer list (if it exists).
- /// The int part of the pair stores whether this initalizer list is
+ /// The int part of the pair stores whether this initializer list is
/// in semantic form. If not null, the pointer points to:
/// - the syntactic form, if this is in semantic form;
/// - the semantic form, if this is in syntactic form.
@@ -3679,7 +3749,7 @@ class InitListExpr : public Expr {
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
public:
- InitListExpr(ASTContext &C, SourceLocation lbraceloc,
+ InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
/// \brief Build an empty initializer list.
@@ -3707,7 +3777,7 @@ public:
}
/// \brief Reserve space for some number of initializers.
- void reserveInits(ASTContext &C, unsigned NumInits);
+ void reserveInits(const ASTContext &C, unsigned NumInits);
/// @brief Specify the number of initializers
///
@@ -3715,7 +3785,7 @@ public:
/// initializers will be destroyed. If there are fewer than @p
/// NumInits initializers, NULL expressions will be added for the
/// unknown initializers.
- void resizeInits(ASTContext &Context, unsigned NumInits);
+ void resizeInits(const ASTContext &Context, unsigned NumInits);
/// @brief Updates the initializer at index @p Init with the new
/// expression @p expr, and returns the old expression at that
@@ -3724,7 +3794,7 @@ public:
/// When @p Init is out of range for this initializer list, the
/// initializer list will be extended with NULL expressions to
/// accommodate the new entry.
- Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
+ Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr);
/// \brief If this initializer list initializes an array with more elements
/// than there are initializers in the list, specifies an expression to be
@@ -3754,6 +3824,10 @@ public:
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
}
void setInitializedFieldInUnion(FieldDecl *FD) {
+ assert((FD == 0
+ || getInitializedFieldInUnion() == 0
+ || getInitializedFieldInUnion() == FD)
+ && "Only one field of a union may be initialized at a time!");
ArrayFillerOrUnionFieldInit = FD;
}
@@ -3794,13 +3868,6 @@ public:
InitListExprBits.HadArrayRangeDesignator = ARD;
}
- bool initializesStdInitializerList() const {
- return InitListExprBits.InitializesStdInitializerList != 0;
- }
- void setInitializesStdInitializerList(bool ISIL = true) {
- InitListExprBits.InitializesStdInitializerList = ISIL;
- }
-
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
@@ -3851,7 +3918,7 @@ public:
/// The InitListExpr contains three DesignatedInitExprs, the first of
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
/// designators, one array designator for @c [2] followed by one field
-/// designator for @c .y. The initalization expression will be 1.0.
+/// designator for @c .y. The initialization expression will be 1.0.
class DesignatedInitExpr : public Expr {
public:
/// \brief Forward declaration of the Designator class.
@@ -3879,7 +3946,7 @@ private:
Designator *Designators;
- DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
+ DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
ArrayRef<Expr*> IndexExprs, Expr *Init);
@@ -4041,13 +4108,15 @@ public:
}
};
- static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
+ static DesignatedInitExpr *Create(const ASTContext &C,
+ Designator *Designators,
unsigned NumDesignators,
ArrayRef<Expr*> IndexExprs,
SourceLocation EqualOrColonLoc,
bool GNUSyntax, Expr *Init);
- static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs);
+ static DesignatedInitExpr *CreateEmpty(const ASTContext &C,
+ unsigned NumIndexExprs);
/// @brief Returns the number of designators in this initializer.
unsigned size() const { return NumDesignators; }
@@ -4085,7 +4154,7 @@ public:
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
- void setDesignators(ASTContext &C, const Designator *Desigs,
+ void setDesignators(const ASTContext &C, const Designator *Desigs,
unsigned NumDesigs);
Expr *getArrayIndex(const Designator &D) const;
@@ -4133,8 +4202,8 @@ public:
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
- void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
- const Designator *Last);
+ void ExpandDesignator(const ASTContext &C, unsigned Idx,
+ const Designator *First, const Designator *Last);
SourceRange getDesignatorsSourceRange() const;
@@ -4188,8 +4257,8 @@ class ParenListExpr : public Expr {
SourceLocation LParenLoc, RParenLoc;
public:
- ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
- SourceLocation rparenloc);
+ ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
+ ArrayRef<Expr*> exprs, SourceLocation rparenloc);
/// \brief Build an empty paren list.
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
@@ -4262,7 +4331,7 @@ class GenericSelectionExpr : public Expr {
SourceLocation GenericLoc, DefaultLoc, RParenLoc;
public:
- GenericSelectionExpr(ASTContext &Context,
+ GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -4271,7 +4340,7 @@ public:
unsigned ResultIndex);
/// This constructor is used in the result-dependent case.
- GenericSelectionExpr(ASTContext &Context,
+ GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -4450,7 +4519,7 @@ public:
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
/// This AST node provides support for reinterpreting a type to another
/// type of the same size.
-class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
+class AsTypeExpr : public Expr {
private:
Stmt *SrcExpr;
SourceLocation BuiltinLoc, RParenLoc;
@@ -4552,13 +4621,13 @@ class PseudoObjectExpr : public Expr {
public:
/// NoResult - A value for the result index indicating that there is
/// no semantic result.
- enum { NoResult = ~0U };
+ enum LLVM_ENUM_INT_TYPE(unsigned) { NoResult = ~0U };
- static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,
+ static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic,
ArrayRef<Expr*> semantic,
unsigned resultIndex);
- static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
+ static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell,
unsigned numSemanticExprs);
/// Return the syntactic form of this expression, i.e. the
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 91e5b21eacff..6356ee7aee63 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the Expr interface and subclasses for C++ expressions.
-//
+///
+/// \file
+/// \brief Defines the clang::Expr interface and subclasses for C++ expressions.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_EXPRCXX_H
@@ -74,15 +75,15 @@ public:
CallExpr(C, CXXOperatorCallExprClass, Empty) { }
- /// getOperator - Returns the kind of overloaded operator that this
+ /// \brief Returns the kind of overloaded operator that this
/// expression refers to.
OverloadedOperatorKind getOperator() const { return Operator; }
- /// getOperatorLoc - Returns the location of the operator symbol in
- /// the expression. When @c getOperator()==OO_Call, this is the
- /// location of the right parentheses; when @c
- /// getOperator()==OO_Subscript, this is the location of the right
- /// bracket.
+ /// \brief Returns the location of the operator symbol in the expression.
+ ///
+ /// When \c getOperator()==OO_Call, this is the location of the right
+ /// parentheses; when \c getOperator()==OO_Subscript, this is the location
+ /// of the right bracket.
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
@@ -105,7 +106,7 @@ public:
friend class ASTStmtWriter;
};
-/// CXXMemberCallExpr - Represents a call to a member function that
+/// Represents a call to a member function that
/// may be written either with member call syntax (e.g., "obj.func()"
/// or "objptr->func()") or with normal function-call syntax
/// ("func()") within a member function that ends up calling a member
@@ -122,18 +123,19 @@ public:
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
- /// getImplicitObjectArgument - Retrieves the implicit object
- /// argument for the member call. For example, in "x.f(5)", this
- /// operation would return "x".
+ /// \brief Retrieves the implicit object argument for the member call.
+ ///
+ /// For example, in "x.f(5)", this returns the sub-expression "x".
Expr *getImplicitObjectArgument() const;
- /// Retrieves the declaration of the called method.
+ /// \brief Retrieves the declaration of the called method.
CXXMethodDecl *getMethodDecl() const;
- /// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of
- /// the implicit object argument. Note that this is may not be the same
- /// declaration as that of the class context of the CXXMethodDecl which this
- /// function is calling.
+ /// \brief Retrieves the CXXRecordDecl for the underlying type of
+ /// the implicit object argument.
+ ///
+ /// Note that this is may not be the same declaration as that of the class
+ /// context of the CXXMethodDecl which this function is calling.
/// FIXME: Returns 0 for member pointer call exprs.
CXXRecordDecl *getRecordDecl() const;
@@ -142,7 +144,7 @@ public:
}
};
-/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function.
+/// \brief Represents a call to a CUDA kernel function.
class CUDAKernelCallExpr : public CallExpr {
private:
enum { CONFIG, END_PREARG };
@@ -169,13 +171,12 @@ public:
}
};
-/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
-/// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c
-/// const_cast.
+/// \brief Abstract class common to all of the C++ "named"/"keyword" casts.
///
/// This abstract class is inherited by all of the classes
-/// representing "named" casts, e.g., CXXStaticCastExpr,
-/// CXXDynamicCastExpr, CXXReinterpretCastExpr, and CXXConstCastExpr.
+/// representing "named" casts: CXXStaticCastExpr for \c static_cast,
+/// CXXDynamicCastExpr for \c dynamic_cast, CXXReinterpretCastExpr for
+/// reinterpret_cast, and CXXConstCastExpr for \c const_cast.
class CXXNamedCastExpr : public ExplicitCastExpr {
private:
SourceLocation Loc; // the location of the casting op
@@ -200,7 +201,7 @@ public:
const char *getCastName() const;
/// \brief Retrieve the location of the cast operator keyword, e.g.,
- /// "static_cast".
+ /// \c static_cast.
SourceLocation getOperatorLoc() const { return Loc; }
/// \brief Retrieve the location of the closing parenthesis.
@@ -223,11 +224,10 @@ public:
}
};
-/// CXXStaticCastExpr - A C++ @c static_cast expression
-/// (C++ [expr.static.cast]).
+/// \brief A C++ \c static_cast expression (C++ [expr.static.cast]).
///
/// This expression node represents a C++ static cast, e.g.,
-/// @c static_cast<int>(1.0).
+/// \c static_cast<int>(1.0).
class CXXStaticCastExpr : public CXXNamedCastExpr {
CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op,
unsigned pathSize, TypeSourceInfo *writtenTy,
@@ -240,13 +240,13 @@ class CXXStaticCastExpr : public CXXNamedCastExpr {
: CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { }
public:
- static CXXStaticCastExpr *Create(ASTContext &Context, QualType T,
+ static CXXStaticCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *Path,
TypeSourceInfo *Written, SourceLocation L,
SourceLocation RParenLoc,
SourceRange AngleBrackets);
- static CXXStaticCastExpr *CreateEmpty(ASTContext &Context,
+ static CXXStaticCastExpr *CreateEmpty(const ASTContext &Context,
unsigned PathSize);
static bool classof(const Stmt *T) {
@@ -254,12 +254,11 @@ public:
}
};
-/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
-/// (C++ [expr.dynamic.cast]), which may perform a run-time check to
-/// determine how to perform the type cast.
+/// \brief A C++ @c dynamic_cast expression (C++ [expr.dynamic.cast]).
///
/// This expression node represents a dynamic cast, e.g.,
-/// @c dynamic_cast<Derived*>(BasePtr).
+/// \c dynamic_cast<Derived*>(BasePtr). Such a cast may perform a run-time
+/// check to determine how to perform the type conversion.
class CXXDynamicCastExpr : public CXXNamedCastExpr {
CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind,
Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy,
@@ -272,14 +271,14 @@ class CXXDynamicCastExpr : public CXXNamedCastExpr {
: CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { }
public:
- static CXXDynamicCastExpr *Create(ASTContext &Context, QualType T,
+ static CXXDynamicCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, CastKind Kind, Expr *Op,
const CXXCastPath *Path,
TypeSourceInfo *Written, SourceLocation L,
SourceLocation RParenLoc,
SourceRange AngleBrackets);
- static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context,
+ static CXXDynamicCastExpr *CreateEmpty(const ASTContext &Context,
unsigned pathSize);
bool isAlwaysNull() const;
@@ -289,12 +288,14 @@ public:
}
};
-/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
-/// [expr.reinterpret.cast]), which provides a differently-typed view
-/// of a value but performs no actual work at run time.
+/// \brief A C++ @c reinterpret_cast expression (C++ [expr.reinterpret.cast]).
///
/// This expression node represents a reinterpret cast, e.g.,
/// @c reinterpret_cast<int>(VoidPtr).
+///
+/// A reinterpret_cast provides a differently-typed view of a value but
+/// (in Clang, as in most C++ implementations) performs no actual work at
+/// run time.
class CXXReinterpretCastExpr : public CXXNamedCastExpr {
CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind,
Expr *op, unsigned pathSize,
@@ -308,13 +309,13 @@ class CXXReinterpretCastExpr : public CXXNamedCastExpr {
: CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { }
public:
- static CXXReinterpretCastExpr *Create(ASTContext &Context, QualType T,
+ static CXXReinterpretCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, CastKind Kind,
Expr *Op, const CXXCastPath *Path,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc,
SourceRange AngleBrackets);
- static CXXReinterpretCastExpr *CreateEmpty(ASTContext &Context,
+ static CXXReinterpretCastExpr *CreateEmpty(const ASTContext &Context,
unsigned pathSize);
static bool classof(const Stmt *T) {
@@ -322,11 +323,13 @@ public:
}
};
-/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
-/// which can remove type qualifiers but does not change the underlying value.
+/// \brief A C++ \c const_cast expression (C++ [expr.const.cast]).
///
/// This expression node represents a const cast, e.g.,
-/// @c const_cast<char*>(PtrToConstChar).
+/// \c const_cast<char*>(PtrToConstChar).
+///
+/// A const_cast can remove type qualifiers but does not change the underlying
+/// value.
class CXXConstCastExpr : public CXXNamedCastExpr {
CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op,
TypeSourceInfo *writtenTy, SourceLocation l,
@@ -338,19 +341,19 @@ class CXXConstCastExpr : public CXXNamedCastExpr {
: CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { }
public:
- static CXXConstCastExpr *Create(ASTContext &Context, QualType T,
+ static CXXConstCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc,
SourceRange AngleBrackets);
- static CXXConstCastExpr *CreateEmpty(ASTContext &Context);
+ static CXXConstCastExpr *CreateEmpty(const ASTContext &Context);
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXConstCastExprClass;
}
};
-/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
+/// \brief A call to a literal operator (C++11 [over.literal])
/// written as a user-defined literal (C++11 [lit.ext]).
///
/// Represents a user-defined literal, e.g. "foo"_bar or 1.23_xyz. While this
@@ -364,12 +367,12 @@ class UserDefinedLiteral : public CallExpr {
SourceLocation UDSuffixLoc;
public:
- UserDefinedLiteral(ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
+ UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
UDSuffixLoc(SuffixLoc) {}
- explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
+ explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty)
: CallExpr(C, UserDefinedLiteralClass, Empty) {}
/// The kind of literal operator which is invoked.
@@ -382,11 +385,11 @@ public:
LOK_Character ///< operator "" X (CharT)
};
- /// getLiteralOperatorKind - Returns the kind of literal operator invocation
+ /// \brief Returns the kind of literal operator invocation
/// which this expression represents.
LiteralOperatorKind getLiteralOperatorKind() const;
- /// getCookedLiteral - If this is not a raw user-defined literal, get the
+ /// \brief If this is not a raw user-defined literal, get the
/// underlying cooked literal (representing the literal with the suffix
/// removed).
Expr *getCookedLiteral();
@@ -402,12 +405,13 @@ public:
SourceLocation getLocEnd() const { return getRParenLoc(); }
- /// getUDSuffixLoc - Returns the location of a ud-suffix in the expression.
+ /// \brief Returns the location of a ud-suffix in the expression.
+ ///
/// For a string literal, there may be multiple identical suffixes. This
/// returns the first.
SourceLocation getUDSuffixLoc() const { return UDSuffixLoc; }
- /// getUDSuffix - Returns the ud-suffix specified for this literal.
+ /// \brief Returns the ud-suffix specified for this literal.
const IdentifierInfo *getUDSuffix() const;
static bool classof(const Stmt *S) {
@@ -418,7 +422,7 @@ public:
friend class ASTStmtWriter;
};
-/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
+/// \brief A boolean literal, per ([C++ lex.bool] Boolean literals).
///
class CXXBoolLiteralExpr : public Expr {
bool Value;
@@ -449,7 +453,9 @@ public:
child_range children() { return child_range(); }
};
-/// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal
+/// \brief The null pointer literal (C++11 [lex.nullptr])
+///
+/// Introduced in C++11, the only literal of type \c nullptr_t is \c nullptr.
class CXXNullPtrLiteralExpr : public Expr {
SourceLocation Loc;
public:
@@ -474,11 +480,50 @@ public:
child_range children() { return child_range(); }
};
-/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets
-/// the type_info that corresponds to the supplied type, or the (possibly
+/// \brief Implicit construction of a std::initializer_list<T> object from an
+/// array temporary within list-initialization (C++11 [dcl.init.list]p5).
+class CXXStdInitializerListExpr : public Expr {
+ Stmt *SubExpr;
+
+ CXXStdInitializerListExpr(EmptyShell Empty)
+ : Expr(CXXStdInitializerListExprClass, Empty), SubExpr(0) {}
+
+public:
+ CXXStdInitializerListExpr(QualType Ty, Expr *SubExpr)
+ : Expr(CXXStdInitializerListExprClass, Ty, VK_RValue, OK_Ordinary,
+ Ty->isDependentType(), SubExpr->isValueDependent(),
+ SubExpr->isInstantiationDependent(),
+ SubExpr->containsUnexpandedParameterPack()),
+ SubExpr(SubExpr) {}
+
+ Expr *getSubExpr() { return static_cast<Expr*>(SubExpr); }
+ const Expr *getSubExpr() const { return static_cast<const Expr*>(SubExpr); }
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SubExpr->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExpr->getLocEnd();
+ }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SubExpr->getSourceRange();
+ }
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == CXXStdInitializerListExprClass;
+ }
+
+ child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+};
+
+/// A C++ \c typeid expression (C++ [expr.typeid]), which gets
+/// the \c type_info that corresponds to the supplied type, or the (possibly
/// dynamic) type of the supplied expression.
///
-/// This represents code like @c typeid(int) or @c typeid(*objPtr)
+/// This represents code like \c typeid(int) or \c typeid(*objPtr)
class CXXTypeidExpr : public Expr {
private:
llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand;
@@ -521,7 +566,7 @@ public:
/// \brief Retrieves the type operand of this typeid() expression after
/// various required adjustments (removing reference types, cv-qualifiers).
- QualType getTypeOperand() const;
+ QualType getTypeOperand(ASTContext &Context) const;
/// \brief Retrieve source information for the type operand.
TypeSourceInfo *getTypeOperandSourceInfo() const {
@@ -561,10 +606,11 @@ public:
}
};
-/// A member reference to an MSPropertyDecl. This expression always
-/// has pseudo-object type, and therefore it is typically not
-/// encountered in a fully-typechecked expression except within the
-/// syntactic form of a PseudoObjectExpr.
+/// \brief A member reference to an MSPropertyDecl.
+///
+/// This expression always has pseudo-object type, and therefore it is
+/// typically not encountered in a fully-typechecked expression except
+/// within the syntactic form of a PseudoObjectExpr.
class MSPropertyRefExpr : public Expr {
Expr *BaseExpr;
MSPropertyDecl *TheDecl;
@@ -619,7 +665,7 @@ public:
friend class ASTStmtReader;
};
-/// CXXUuidofExpr - A microsoft C++ @c __uuidof expression, which gets
+/// A Microsoft C++ @c __uuidof expression, which gets
/// the _GUID that corresponds to the supplied type or expression.
///
/// This represents code like @c __uuidof(COMTYPE) or @c __uuidof(*comPtr)
@@ -655,7 +701,7 @@ public:
/// \brief Retrieves the type operand of this __uuidof() expression after
/// various required adjustments (removing reference types, cv-qualifiers).
- QualType getTypeOperand() const;
+ QualType getTypeOperand(ASTContext &Context) const;
/// \brief Retrieve source information for the type operand.
TypeSourceInfo *getTypeOperandSourceInfo() const {
@@ -678,6 +724,8 @@ public:
Operand = E;
}
+ StringRef getUuidAsStringRef(ASTContext &Context) const;
+
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
@@ -687,8 +735,10 @@ public:
return T->getStmtClass() == CXXUuidofExprClass;
}
- /// Grabs __declspec(uuid()) off a type, or returns 0 if there is none.
- static UuidAttr *GetUuidAttrOfType(QualType QT);
+ /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to
+ /// a single GUID.
+ static UuidAttr *GetUuidAttrOfType(QualType QT,
+ bool *HasMultipleGUIDsPtr = 0);
// Iterators
child_range children() {
@@ -698,17 +748,18 @@ public:
}
};
-/// CXXThisExpr - Represents the "this" expression in C++, which is a
-/// pointer to the object on which the current member function is
+/// \brief Represents the \c this expression in C++.
+///
+/// This is a pointer to the object on which the current member function is
/// executing (C++ [expr.prim]p3). Example:
///
-/// @code
+/// \code
/// class Foo {
/// public:
/// void bar();
/// void test() { this->bar(); }
/// };
-/// @endcode
+/// \endcode
class CXXThisExpr : public Expr {
SourceLocation Loc;
bool Implicit : 1;
@@ -742,10 +793,11 @@ public:
child_range children() { return child_range(); }
};
-/// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles
-/// 'throw' and 'throw' assignment-expression. When
-/// assignment-expression isn't present, Op will be null.
+/// \brief A C++ throw-expression (C++ [except.throw]).
///
+/// This handles 'throw' (for re-throwing the current exception) and
+/// 'throw' assignment-expression. When assignment-expression isn't
+/// present, Op will be null.
class CXXThrowExpr : public Expr {
Stmt *Op;
SourceLocation ThrowLoc;
@@ -755,8 +807,8 @@ class CXXThrowExpr : public Expr {
friend class ASTStmtReader;
public:
- // Ty is the void type which is used as the result type of the
- // exepression. The l is the location of the throw keyword. expr
+ // \p Ty is the void type which is used as the result type of the
+ // expression. The \p l is the location of the throw keyword. \p expr
// can by null, if the optional expression to throw isn't present.
CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l,
bool IsThrownVariableInScope) :
@@ -795,10 +847,11 @@ public:
}
};
-/// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a
-/// function call argument that was created from the corresponding
-/// parameter's default argument, when the call did not explicitly
-/// supply arguments for all of the parameters.
+/// \brief A default argument (C++ [dcl.fct.default]).
+///
+/// This wraps up a function call argument that was created from the
+/// corresponding parameter's default argument, when the call did not
+/// explicitly supply arguments for all of the parameters.
class CXXDefaultArgExpr : public Expr {
/// \brief The parameter whose default is being used.
///
@@ -831,20 +884,17 @@ class CXXDefaultArgExpr : public Expr {
public:
CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
-
- // Param is the parameter whose default argument is used by this
+ // \p Param is the parameter whose default argument is used by this
// expression.
- static CXXDefaultArgExpr *Create(ASTContext &C, SourceLocation Loc,
+ static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
ParmVarDecl *Param) {
return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param);
}
- // Param is the parameter whose default argument is used by this
- // expression, and SubExpr is the expression that will actually be used.
- static CXXDefaultArgExpr *Create(ASTContext &C,
- SourceLocation Loc,
- ParmVarDecl *Param,
- Expr *SubExpr);
+ // \p Param is the parameter whose default argument is used by this
+ // expression, and \p SubExpr is the expression that will actually be used.
+ static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
+ ParmVarDecl *Param, Expr *SubExpr);
// Retrieve the parameter that the argument was created from.
const ParmVarDecl *getParam() const { return Param.getPointer(); }
@@ -866,8 +916,8 @@ public:
/// used.
SourceLocation getUsedLocation() const { return Loc; }
- // Default argument expressions have no representation in the
- // source, so they have an empty source range.
+ /// Default argument expressions have no representation in the
+ /// source, so they have an empty source range.
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
@@ -884,7 +934,10 @@ public:
friend class ASTStmtWriter;
};
-/// \brief This wraps a use of a C++ default initializer (technically,
+/// \brief A use of a default initializer in a constructor or in aggregate
+/// initialization.
+///
+/// This wraps a use of a C++ default initializer (technically,
/// a brace-or-equal-initializer for a non-static data member) when it
/// is implicitly used in a mem-initializer-list in a constructor
/// (C++11 [class.base.init]p8) or in aggregate initialization
@@ -896,24 +949,24 @@ class CXXDefaultInitExpr : public Expr {
/// \brief The location where the default initializer expression was used.
SourceLocation Loc;
- CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, FieldDecl *Field,
+ CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field,
QualType T);
CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {}
public:
- // Field is the non-static data member whose default initializer is used
- // by this expression.
- static CXXDefaultInitExpr *Create(ASTContext &C, SourceLocation Loc,
+ /// \p Field is the non-static data member whose default initializer is used
+ /// by this expression.
+ static CXXDefaultInitExpr *Create(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field) {
return new (C) CXXDefaultInitExpr(C, Loc, Field, Field->getType());
}
- // Get the field whose initializer will be used.
+ /// \brief Get the field whose initializer will be used.
FieldDecl *getField() { return Field; }
const FieldDecl *getField() const { return Field; }
- // Get the initialization expression that will be used.
+ /// \brief Get the initialization expression that will be used.
const Expr *getExpr() const { return Field->getInClassInitializer(); }
Expr *getExpr() { return Field->getInClassInitializer(); }
@@ -931,16 +984,16 @@ public:
friend class ASTStmtReader;
};
-/// CXXTemporary - Represents a C++ temporary.
+/// \brief Represents a C++ temporary.
class CXXTemporary {
- /// Destructor - The destructor that needs to be called.
+ /// \brief The destructor that needs to be called.
const CXXDestructorDecl *Destructor;
- CXXTemporary(const CXXDestructorDecl *destructor)
+ explicit CXXTemporary(const CXXDestructorDecl *destructor)
: Destructor(destructor) { }
public:
- static CXXTemporary *Create(ASTContext &C,
+ static CXXTemporary *Create(const ASTContext &C,
const CXXDestructorDecl *Destructor);
const CXXDestructorDecl *getDestructor() const { return Destructor; }
@@ -980,7 +1033,7 @@ public:
CXXBindTemporaryExpr(EmptyShell Empty)
: Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {}
- static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
+ static CXXBindTemporaryExpr *Create(const ASTContext &C, CXXTemporary *Temp,
Expr* SubExpr);
CXXTemporary *getTemporary() { return Temp; }
@@ -1019,7 +1072,7 @@ private:
CXXConstructorDecl *Constructor;
SourceLocation Loc;
- SourceRange ParenRange;
+ SourceRange ParenOrBraceRange;
unsigned NumArgs : 16;
bool Elidable : 1;
bool HadMultipleCandidates : 1;
@@ -1029,7 +1082,7 @@ private:
Stmt **Args;
protected:
- CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+ CXXConstructExpr(const ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
ArrayRef<Expr *> Args,
@@ -1037,7 +1090,7 @@ protected:
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange);
+ SourceRange ParenOrBraceRange);
/// \brief Construct an empty C++ construction expression.
CXXConstructExpr(StmtClass SC, EmptyShell Empty)
@@ -1055,7 +1108,7 @@ public:
ConstructKind(0), Args(0)
{ }
- static CXXConstructExpr *Create(ASTContext &C, QualType T,
+ static CXXConstructExpr *Create(const ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
ArrayRef<Expr *> Args,
@@ -1063,7 +1116,7 @@ public:
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange);
+ SourceRange ParenOrBraceRange);
CXXConstructorDecl* getConstructor() const { return Constructor; }
void setConstructor(CXXConstructorDecl *C) { Constructor = C; }
@@ -1091,7 +1144,7 @@ public:
ZeroInitialization = ZeroInit;
}
- /// \brief Determines whether this constructor is actually constructing
+ /// \brief Determine whether this constructor is actually constructing
/// a base class (rather than a complete object).
ConstructionKind getConstructionKind() const {
return (ConstructionKind)ConstructKind;
@@ -1111,7 +1164,7 @@ public:
Expr **getArgs() const { return reinterpret_cast<Expr **>(Args); }
unsigned getNumArgs() const { return NumArgs; }
- /// getArg - Return the specified argument.
+ /// \brief Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
return cast<Expr>(Args[Arg]);
@@ -1121,7 +1174,7 @@ public:
return cast<Expr>(Args[Arg]);
}
- /// setArg - Set the specified argument.
+ /// \brief Set the specified argument.
void setArg(unsigned Arg, Expr *ArgExpr) {
assert(Arg < NumArgs && "Arg access out of range!");
Args[Arg] = ArgExpr;
@@ -1129,8 +1182,8 @@ public:
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
- SourceRange getParenRange() const { return ParenRange; }
- void setParenRange(SourceRange Range) { ParenRange = Range; }
+ SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; }
+ void setParenOrBraceRange(SourceRange Range) { ParenOrBraceRange = Range; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXConstructExprClass ||
@@ -1149,43 +1202,42 @@ public:
/// notation (C++ [expr.type.conv]).
///
/// Example:
-/// @code
+/// \code
/// x = int(0.5);
-/// @endcode
+/// \endcode
class CXXFunctionalCastExpr : public ExplicitCastExpr {
- SourceLocation TyBeginLoc;
+ SourceLocation LParenLoc;
SourceLocation RParenLoc;
CXXFunctionalCastExpr(QualType ty, ExprValueKind VK,
TypeSourceInfo *writtenTy,
- SourceLocation tyBeginLoc, CastKind kind,
- Expr *castExpr, unsigned pathSize,
- SourceLocation rParenLoc)
+ CastKind kind, Expr *castExpr, unsigned pathSize,
+ SourceLocation lParenLoc, SourceLocation rParenLoc)
: ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind,
castExpr, pathSize, writtenTy),
- TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
+ LParenLoc(lParenLoc), RParenLoc(rParenLoc) {}
explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize)
: ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) { }
public:
- static CXXFunctionalCastExpr *Create(ASTContext &Context, QualType T,
+ static CXXFunctionalCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
TypeSourceInfo *Written,
- SourceLocation TyBeginLoc,
CastKind Kind, Expr *Op,
const CXXCastPath *Path,
+ SourceLocation LPLoc,
SourceLocation RPLoc);
- static CXXFunctionalCastExpr *CreateEmpty(ASTContext &Context,
+ static CXXFunctionalCastExpr *CreateEmpty(const ASTContext &Context,
unsigned PathSize);
- SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
- void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; }
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceLocation getLocStart() const LLVM_READONLY { return TyBeginLoc; }
- SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXFunctionalCastExprClass;
@@ -1200,21 +1252,21 @@ public:
/// constructor to build a temporary object. With N == 1 arguments the
/// functional cast expression will be represented by CXXFunctionalCastExpr.
/// Example:
-/// @code
+/// \code
/// struct X { X(int, float); }
///
/// X create_X() {
/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr
/// };
-/// @endcode
+/// \endcode
class CXXTemporaryObjectExpr : public CXXConstructExpr {
TypeSourceInfo *Type;
public:
- CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
+ CXXTemporaryObjectExpr(const ASTContext &C, CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
ArrayRef<Expr *> Args,
- SourceRange parenRange,
+ SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization);
@@ -1244,26 +1296,35 @@ public:
/// }
/// \endcode
///
-/// Lambda expressions can capture local variables, either by copying
+/// C++11 lambda expressions can capture local variables, either by copying
/// the values of those local variables at the time the function
/// object is constructed (not when it is called!) or by holding a
/// reference to the local variable. These captures can occur either
/// implicitly or can be written explicitly between the square
/// brackets ([...]) that start the lambda expression.
+///
+/// C++1y introduces a new form of "capture" called an init-capture that
+/// includes an initializing expression (rather than capturing a variable),
+/// and which can never occur implicitly.
class LambdaExpr : public Expr {
enum {
/// \brief Flag used by the Capture class to indicate that the given
/// capture was implicit.
Capture_Implicit = 0x01,
- /// \brief Flag used by the Capture class to indciate that the
+ /// \brief Flag used by the Capture class to indicate that the
/// given capture was by-copy.
+ ///
+ /// This includes the case of a non-reference init-capture.
Capture_ByCopy = 0x02
};
/// \brief The source range that covers the lambda introducer ([...]).
SourceRange IntroducerRange;
+ /// \brief The source location of this lambda's capture-default ('=' or '&').
+ SourceLocation CaptureDefaultLoc;
+
/// \brief The number of captures.
unsigned NumCaptures : 16;
@@ -1297,9 +1358,10 @@ class LambdaExpr : public Expr {
// array captures.
public:
- /// \brief Describes the capture of either a variable or 'this'.
+ /// \brief Describes the capture of a variable or of \c this, or of a
+ /// C++1y init-capture.
class Capture {
- llvm::PointerIntPair<VarDecl *, 2> VarAndBits;
+ llvm::PointerIntPair<Decl *, 2> DeclAndBits;
SourceLocation Loc;
SourceLocation EllipsisLoc;
@@ -1307,15 +1369,17 @@ public:
friend class ASTStmtWriter;
public:
- /// \brief Create a new capture.
+ /// \brief Create a new capture of a variable or of \c this.
///
/// \param Loc The source location associated with this capture.
///
- /// \param Kind The kind of capture (this, byref, bycopy).
+ /// \param Kind The kind of capture (this, byref, bycopy), which must
+ /// not be init-capture.
///
/// \param Implicit Whether the capture was implicit or explicit.
///
- /// \param Var The local variable being captured, or null if capturing this.
+ /// \param Var The local variable being captured, or null if capturing
+ /// \c this.
///
/// \param EllipsisLoc The location of the ellipsis (...) for a
/// capture that is a pack expansion, or an invalid source
@@ -1327,36 +1391,43 @@ public:
/// \brief Determine the kind of capture.
LambdaCaptureKind getCaptureKind() const;
- /// \brief Determine whether this capture handles the C++ 'this'
+ /// \brief Determine whether this capture handles the C++ \c this
/// pointer.
- bool capturesThis() const { return VarAndBits.getPointer() == 0; }
+ bool capturesThis() const { return DeclAndBits.getPointer() == 0; }
/// \brief Determine whether this capture handles a variable.
- bool capturesVariable() const { return VarAndBits.getPointer() != 0; }
+ bool capturesVariable() const {
+ return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
+ }
+
+ /// \brief Determine whether this is an init-capture.
+ bool isInitCapture() const {
+ return capturesVariable() && getCapturedVar()->isInitCapture();
+ }
/// \brief Retrieve the declaration of the local variable being
/// captured.
///
- /// This operation is only valid if this capture does not capture
- /// 'this'.
- VarDecl *getCapturedVar() const {
- assert(!capturesThis() && "No variable available for 'this' capture");
- return VarAndBits.getPointer();
+ /// This operation is only valid if this capture is a variable capture
+ /// (other than a capture of \c this).
+ VarDecl *getCapturedVar() const {
+ assert(capturesVariable() && "No variable available for 'this' capture");
+ return cast<VarDecl>(DeclAndBits.getPointer());
}
/// \brief Determine whether this was an implicit capture (not
/// written between the square brackets introducing the lambda).
- bool isImplicit() const { return VarAndBits.getInt() & Capture_Implicit; }
+ bool isImplicit() const { return DeclAndBits.getInt() & Capture_Implicit; }
- /// \brief Determine whether this was an explicit capture, written
- /// between the square brackets introducing the lambda.
+ /// \brief Determine whether this was an explicit capture (written
+ /// between the square brackets introducing the lambda).
bool isExplicit() const { return !isImplicit(); }
/// \brief Retrieve the source location of the capture.
///
/// For an explicit capture, this returns the location of the
/// explicit capture in the source. For an implicit capture, this
- /// returns the location at which the variable or 'this' was first
+ /// returns the location at which the variable or \c this was first
/// used.
SourceLocation getLocation() const { return Loc; }
@@ -1376,6 +1447,7 @@ private:
/// \brief Construct a lambda expression.
LambdaExpr(QualType T, SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
@@ -1414,10 +1486,11 @@ private:
public:
/// \brief Construct a new lambda expression.
- static LambdaExpr *Create(ASTContext &C,
+ static LambdaExpr *Create(const ASTContext &C,
CXXRecordDecl *Class,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
@@ -1429,14 +1502,20 @@ public:
/// \brief Construct a new lambda expression that will be deserialized from
/// an external source.
- static LambdaExpr *CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+ static LambdaExpr *CreateDeserialized(const ASTContext &C,
+ unsigned NumCaptures,
unsigned NumArrayIndexVars);
-
+
/// \brief Determine the default capture kind for this lambda.
LambdaCaptureDefault getCaptureDefault() const {
return static_cast<LambdaCaptureDefault>(CaptureDefault);
}
+ /// \brief Retrieve the location of this lambda's capture-default, if any.
+ SourceLocation getCaptureDefaultLoc() const {
+ return CaptureDefaultLoc;
+ }
+
/// \brief An iterator that walks over the captures of the lambda,
/// both implicit and explicit.
typedef const Capture *capture_iterator;
@@ -1495,15 +1574,24 @@ public:
/// brackets ([...]).
SourceRange getIntroducerRange() const { return IntroducerRange; }
- /// \brief Retrieve the class that corresponds to the lambda, which
- /// stores the captures in its fields and provides the various
- /// operations permitted on a lambda (copying, calling).
+ /// \brief Retrieve the class that corresponds to the lambda.
+ ///
+ /// This is the "closure type" (C++1y [expr.prim.lambda]), and stores the
+ /// captures in its fields and provides the various operations permitted
+ /// on a lambda (copying, calling).
CXXRecordDecl *getLambdaClass() const;
/// \brief Retrieve the function call operator associated with this
/// lambda expression.
CXXMethodDecl *getCallOperator() const;
+ /// \brief If this is a generic lambda expression, retrieve the template
+ /// parameter list associated with it, or else return null.
+ TemplateParameterList *getTemplateParameterList() const;
+
+ /// \brief Whether this is a generic lambda.
+ bool isGenericLambda() const { return getTemplateParameterList(); }
+
/// \brief Retrieve the body of the lambda.
CompoundStmt *getBody() const;
@@ -1535,10 +1623,8 @@ public:
friend class ASTStmtWriter;
};
-/// CXXScalarValueInitExpr - [C++ 5.2.3p2]
-/// Expression "T()" which creates a value-initialized rvalue of type
-/// T, which is a non-class type.
-///
+/// An expression "T()" which creates a value-initialized rvalue of type
+/// T, which is a non-class type. See (C++98 [5.2.3p2]).
class CXXScalarValueInitExpr : public Expr {
SourceLocation RParenLoc;
TypeSourceInfo *TypeInfo;
@@ -1575,11 +1661,11 @@ public:
child_range children() { return child_range(); }
};
-/// @brief Represents a new-expression for memory allocation and constructor
-// calls, e.g: "new CXXNewExpr(foo)".
+/// \brief Represents a new-expression for memory allocation and constructor
+/// calls, e.g: "new CXXNewExpr(foo)".
class CXXNewExpr : public Expr {
- // Contains an optional array size expression, an optional initialization
- // expression, and any number of optional placement arguments, in that order.
+ /// Contains an optional array size expression, an optional initialization
+ /// expression, and any number of optional placement arguments, in that order.
Stmt **SubExprs;
/// \brief Points to the allocation function used.
FunctionDecl *OperatorNew;
@@ -1600,18 +1686,18 @@ class CXXNewExpr : public Expr {
/// \brief Source-range of a paren-delimited initializer.
SourceRange DirectInitRange;
- // Was the usage ::new, i.e. is the global new to be used?
+ /// Was the usage ::new, i.e. is the global new to be used?
bool GlobalNew : 1;
- // Do we allocate an array? If so, the first SubExpr is the size expression.
+ /// Do we allocate an array? If so, the first SubExpr is the size expression.
bool Array : 1;
- // If this is an array allocation, does the usual deallocation
- // function for the allocated type want to know the allocated size?
+ /// If this is an array allocation, does the usual deallocation
+ /// function for the allocated type want to know the allocated size?
bool UsualArrayDeleteWantsSize : 1;
- // The number of placement new arguments.
+ /// The number of placement new arguments.
unsigned NumPlacementArgs : 13;
- // What kind of initializer do we have? Could be none, parens, or braces.
- // In storage, we distinguish between "none, and no initializer expr", and
- // "none, but an implicit initializer expr".
+ /// What kind of initializer do we have? Could be none, parens, or braces.
+ /// In storage, we distinguish between "none, and no initializer expr", and
+ /// "none, but an implicit initializer expr".
unsigned StoredInitializationStyle : 2;
friend class ASTStmtReader;
@@ -1623,7 +1709,7 @@ public:
ListInit ///< New-expression has a C++11 list-initializer.
};
- CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
+ CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
@@ -1633,8 +1719,8 @@ public:
explicit CXXNewExpr(EmptyShell Shell)
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
- void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs,
- bool hasInitializer);
+ void AllocateArgsArray(const ASTContext &C, bool isArray,
+ unsigned numPlaceArgs, bool hasInitializer);
QualType getAllocatedType() const {
assert(getType()->isPointerType());
@@ -1646,15 +1732,17 @@ public:
}
/// \brief True if the allocation result needs to be null-checked.
- /// C++0x [expr.new]p13:
+ ///
+ /// C++11 [expr.new]p13:
/// If the allocation function returns null, initialization shall
/// not be done, the deallocation function shall not be called,
/// and the value of the new-expression shall be null.
+ ///
/// An allocation function is not allowed to return null unless it
/// has a non-throwing exception-specification. The '03 rule is
/// identical except that the definition of a non-throwing
/// exception specification is just "is it throw()?".
- bool shouldNullCheckAllocation(ASTContext &Ctx) const;
+ bool shouldNullCheckAllocation(const ASTContext &Ctx) const;
FunctionDecl *getOperatorNew() const { return OperatorNew; }
void setOperatorNew(FunctionDecl *D) { OperatorNew = D; }
@@ -1706,7 +1794,7 @@ public:
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
}
- /// \brief Returns the CXXConstructExpr from this new-expression, or NULL.
+ /// \brief Returns the CXXConstructExpr from this new-expression, or null.
const CXXConstructExpr* getConstructExpr() const {
return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
}
@@ -1768,22 +1856,22 @@ public:
/// \brief Represents a \c delete expression for memory deallocation and
/// destructor calls, e.g. "delete[] pArray".
class CXXDeleteExpr : public Expr {
- // Points to the operator delete overload that is used. Could be a member.
+ /// Points to the operator delete overload that is used. Could be a member.
FunctionDecl *OperatorDelete;
- // The pointer expression to be deleted.
+ /// The pointer expression to be deleted.
Stmt *Argument;
- // Location of the expression.
+ /// Location of the expression.
SourceLocation Loc;
- // Is this a forced global delete, i.e. "::delete"?
+ /// Is this a forced global delete, i.e. "::delete"?
bool GlobalDelete : 1;
- // Is this the array form of delete, i.e. "delete[]"?
+ /// Is this the array form of delete, i.e. "delete[]"?
bool ArrayForm : 1;
- // ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied
- // to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm
- // will be true).
+ /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied
+ /// to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm
+ /// will be true).
bool ArrayFormAsWritten : 1;
- // Does the usual deallocation function for the element type require
- // a size_t argument?
+ /// Does the usual deallocation function for the element type require
+ /// a size_t argument?
bool UsualArrayDeleteWantsSize : 1;
public:
CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
@@ -1816,9 +1904,10 @@ public:
Expr *getArgument() { return cast<Expr>(Argument); }
const Expr *getArgument() const { return cast<Expr>(Argument); }
- /// \brief Retrieve the type being destroyed. If the type being
- /// destroyed is a dependent type which may or may not be a pointer,
- /// return an invalid type.
+ /// \brief Retrieve the type being destroyed.
+ ///
+ /// If the type being destroyed is a dependent type which may or may not
+ /// be a pointer, return an invalid type.
QualType getDestroyedType() const;
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
@@ -1918,7 +2007,7 @@ class CXXPseudoDestructorExpr : public Expr {
friend class ASTStmtReader;
public:
- CXXPseudoDestructorExpr(ASTContext &Context,
+ CXXPseudoDestructorExpr(const ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
TypeSourceInfo *ScopeType,
@@ -1935,7 +2024,7 @@ public:
/// \brief Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo.
- bool hasQualifier() const { return QualifierLoc; }
+ bool hasQualifier() const { return QualifierLoc.hasQualifier(); }
/// \brief Retrieves the nested-name-specifier that qualifies the type name,
/// with source-location information.
@@ -1943,7 +2032,7 @@ public:
/// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
- /// NULL.
+ /// null.
NestedNameSpecifier *getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -1978,7 +2067,7 @@ public:
///
/// This type-source information is available for non-dependent
/// pseudo-destructor expressions and some dependent pseudo-destructor
- /// expressions. Returns NULL if we only have the identifier for a
+ /// expressions. Returns null if we only have the identifier for a
/// dependent pseudo-destructor expression.
TypeSourceInfo *getDestroyedTypeInfo() const {
return DestroyedType.getTypeSourceInfo();
@@ -2025,23 +2114,23 @@ public:
/// implementation of TR1/C++11 type trait templates.
///
/// Example:
-/// @code
+/// \code
/// __is_pod(int) == true
/// __is_enum(std::string) == false
-/// @endcode
+/// \endcode
class UnaryTypeTraitExpr : public Expr {
- /// UTT - The trait. A UnaryTypeTrait enum in MSVC compat unsigned.
+ /// \brief The trait. A UnaryTypeTrait enum in MSVC compatible unsigned.
unsigned UTT : 31;
/// The value of the type trait. Unspecified if dependent.
bool Value : 1;
- /// Loc - The location of the type trait keyword.
+ /// \brief The location of the type trait keyword.
SourceLocation Loc;
- /// RParen - The location of the closing paren.
+ /// \brief The location of the closing paren.
SourceLocation RParen;
- /// The type being queried.
+ /// \brief The type being queried.
TypeSourceInfo *QueriedType;
public:
@@ -2083,26 +2172,26 @@ public:
/// implementation of TR1/C++11 type trait templates.
///
/// Example:
-/// @code
+/// \code
/// __is_base_of(Base, Derived) == true
-/// @endcode
+/// \endcode
class BinaryTypeTraitExpr : public Expr {
- /// BTT - The trait. A BinaryTypeTrait enum in MSVC compat unsigned.
+ /// \brief The trait. A BinaryTypeTrait enum in MSVC compatible unsigned.
unsigned BTT : 8;
/// The value of the type trait. Unspecified if dependent.
bool Value : 1;
- /// Loc - The location of the type trait keyword.
+ /// \brief The location of the type trait keyword.
SourceLocation Loc;
- /// RParen - The location of the closing paren.
+ /// \brief The location of the closing paren.
SourceLocation RParen;
- /// The lhs type being queried.
+ /// \brief The lhs type being queried.
TypeSourceInfo *LhsType;
- /// The rhs type being queried.
+ /// \brief The rhs type being queried.
TypeSourceInfo *RhsType;
public:
@@ -2184,13 +2273,14 @@ class TypeTraitExpr : public Expr {
public:
/// \brief Create a new type trait expression.
- static TypeTraitExpr *Create(ASTContext &C, QualType T, SourceLocation Loc,
- TypeTrait Kind,
+ static TypeTraitExpr *Create(const ASTContext &C, QualType T,
+ SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc,
bool Value);
- static TypeTraitExpr *CreateDeserialized(ASTContext &C, unsigned NumArgs);
+ static TypeTraitExpr *CreateDeserialized(const ASTContext &C,
+ unsigned NumArgs);
/// \brief Determine which type trait this expression uses.
TypeTrait getTrait() const {
@@ -2249,10 +2339,10 @@ public:
/// __array_rank and __array_extent.
///
/// Example:
-/// @code
+/// \code
/// __array_rank(int[10][20]) == 2
/// __array_extent(int, 1) == 20
-/// @endcode
+/// \endcode
class ArrayTypeTraitExpr : public Expr {
virtual void anchor();
@@ -2319,12 +2409,12 @@ public:
/// \brief An expression trait intrinsic.
///
/// Example:
-/// @code
+/// \code
/// __is_lvalue_expr(std::cout) == true
/// __is_lvalue_expr(1) == false
-/// @endcode
+/// \endcode
class ExpressionTraitExpr : public Expr {
- /// \brief The trait. A ExpressionTrait enum in MSVC compat unsigned.
+ /// \brief The trait. A ExpressionTrait enum in MSVC compatible unsigned.
unsigned ET : 31;
/// \brief The value of the type trait. Unspecified if dependent.
bool Value : 1;
@@ -2403,7 +2493,7 @@ protected:
return const_cast<OverloadExpr*>(this)->getTemplateKWAndArgsInfo();
}
- OverloadExpr(StmtClass K, ASTContext &C,
+ OverloadExpr(StmtClass K, const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
@@ -2417,7 +2507,7 @@ protected:
: Expr(K, Empty), QualifierLoc(), Results(0), NumResults(0),
HasTemplateKWAndArgsInfo(false) { }
- void initializeResults(ASTContext &C,
+ void initializeResults(const ASTContext &C,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End);
@@ -2428,7 +2518,7 @@ public:
bool HasFormOfMemberPointer;
};
- /// Finds the overloaded expression in the given expression of
+ /// \brief Finds the overloaded expression in the given expression \p E of
/// OverloadTy.
///
/// \return the expression (which must be there) and true if it has
@@ -2561,10 +2651,11 @@ public:
/// parsing but could not resolve to a specific declaration.
///
/// This arises in several ways:
-/// * we might be waiting for argument-dependent lookup
-/// * the name might resolve to an overloaded function
+/// * we might be waiting for argument-dependent lookup;
+/// * the name might resolve to an overloaded function;
/// and eventually:
-/// * the lookup might have included a function template
+/// * the lookup might have included a function template.
+///
/// These never include UnresolvedUsingValueDecls, which are always class
/// members and therefore appear only in UnresolvedMemberLookupExprs.
class UnresolvedLookupExpr : public OverloadExpr {
@@ -2584,7 +2675,7 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// against the qualified-lookup bits.
CXXRecordDecl *NamingClass;
- UnresolvedLookupExpr(ASTContext &C,
+ UnresolvedLookupExpr(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -2606,7 +2697,7 @@ class UnresolvedLookupExpr : public OverloadExpr {
friend class ASTStmtReader;
public:
- static UnresolvedLookupExpr *Create(ASTContext &C,
+ static UnresolvedLookupExpr *Create(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
@@ -2618,7 +2709,7 @@ public:
ADL, Overloaded, 0, Begin, End);
}
- static UnresolvedLookupExpr *Create(ASTContext &C,
+ static UnresolvedLookupExpr *Create(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -2628,7 +2719,7 @@ public:
UnresolvedSetIterator Begin,
UnresolvedSetIterator End);
- static UnresolvedLookupExpr *CreateEmpty(ASTContext &C,
+ static UnresolvedLookupExpr *CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
@@ -2671,7 +2762,7 @@ public:
/// DependentScopeDeclRefExpr node is used only within C++ templates when
/// the qualification (e.g., X<T>::) refers to a dependent type. In
/// this case, X<T>::value cannot resolve to a declaration because the
-/// declaration will differ from on instantiation of X<T> to the
+/// declaration will differ from one instantiation of X<T> to the
/// next. Therefore, DependentScopeDeclRefExpr keeps track of the
/// qualifier (X<T>::) and the name of the entity being referenced
/// ("value"). Such expressions will instantiate to a DeclRefExpr once the
@@ -2681,7 +2772,7 @@ class DependentScopeDeclRefExpr : public Expr {
/// declaration name.
NestedNameSpecifierLoc QualifierLoc;
- /// The name of the entity we will be referencing.
+ /// \brief The name of the entity we will be referencing.
DeclarationNameInfo NameInfo;
/// \brief Whether the name includes info for explicit template
@@ -2706,13 +2797,13 @@ class DependentScopeDeclRefExpr : public Expr {
const TemplateArgumentListInfo *Args);
public:
- static DependentScopeDeclRefExpr *Create(ASTContext &C,
+ static DependentScopeDeclRefExpr *Create(const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
- static DependentScopeDeclRefExpr *CreateEmpty(ASTContext &C,
+ static DependentScopeDeclRefExpr *CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
@@ -2723,13 +2814,14 @@ public:
DeclarationName getDeclName() const { return NameInfo.getName(); }
/// \brief Retrieve the location of the name within the expression.
+ ///
+ /// For example, in "X<T>::value" this is the location of "value".
SourceLocation getLocation() const { return NameInfo.getLoc(); }
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name, with source location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
/// \brief Retrieve the nested-name-specifier that qualifies this
/// declaration.
NestedNameSpecifier *getQualifier() const {
@@ -2779,6 +2871,7 @@ public:
}
/// \brief Retrieves the optional explicit template arguments.
+ ///
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
@@ -2800,6 +2893,8 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
+ /// Note: getLocStart() is the start of the whole DependentScopeDeclRefExpr,
+ /// and differs from getLocation().getStart().
SourceLocation getLocStart() const LLVM_READONLY {
return QualifierLoc.getBeginLoc();
}
@@ -2819,7 +2914,7 @@ public:
friend class ASTStmtWriter;
};
-/// Represents an expression --- generally a full-expression --- which
+/// Represents an expression -- generally a full-expression -- that
/// introduces cleanups to be run at the end of the sub-expression's
/// evaluation. The most common source of expression-introduced
/// cleanups is temporary objects in C++, but several other kinds of
@@ -2852,10 +2947,10 @@ private:
friend class ASTStmtReader;
public:
- static ExprWithCleanups *Create(ASTContext &C, EmptyShell empty,
+ static ExprWithCleanups *Create(const ASTContext &C, EmptyShell empty,
unsigned numObjects);
- static ExprWithCleanups *Create(ASTContext &C, Expr *subexpr,
+ static ExprWithCleanups *Create(const ASTContext &C, Expr *subexpr,
ArrayRef<CleanupObject> objects);
ArrayRef<CleanupObject> getObjects() const {
@@ -2872,7 +2967,7 @@ public:
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
- /// setSubExpr - As with any mutator of the AST, be very careful
+ /// As with any mutator of the AST, be very careful
/// when modifying an existing AST to preserve its invariants.
void setSubExpr(Expr *E) { SubExpr = E; }
@@ -2935,13 +3030,13 @@ class CXXUnresolvedConstructExpr : public Expr {
friend class ASTStmtReader;
public:
- static CXXUnresolvedConstructExpr *Create(ASTContext &C,
+ static CXXUnresolvedConstructExpr *Create(const ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
ArrayRef<Expr*> Args,
SourceLocation RParenLoc);
- static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C,
+ static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &C,
unsigned NumArgs);
/// \brief Retrieve the type that is being constructed, as specified
@@ -2993,7 +3088,10 @@ public:
}
SourceLocation getLocStart() const LLVM_READONLY;
- SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ assert(RParenLoc.isValid() || NumArgs == 1);
+ return RParenLoc.isValid() ? RParenLoc : getArg(0)->getLocEnd();
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
@@ -3047,6 +3145,7 @@ class CXXDependentScopeMemberExpr : public Expr {
/// \brief The member to which this member expression refers, which
/// can be name, overloaded operator, or destructor.
+ ///
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
@@ -3061,36 +3160,32 @@ class CXXDependentScopeMemberExpr : public Expr {
->getTemplateKWAndArgsInfo();
}
- CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, QualType BaseType, bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- NamedDecl *FirstQualifierFoundInScope,
- DeclarationNameInfo MemberNameInfo,
- const TemplateArgumentListInfo *TemplateArgs);
+ CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base,
+ QualType BaseType, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationNameInfo MemberNameInfo,
+ const TemplateArgumentListInfo *TemplateArgs);
public:
- CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, QualType BaseType,
- bool IsArrow,
+ CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base,
+ QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo);
static CXXDependentScopeMemberExpr *
- Create(ASTContext &C,
- Expr *Base, QualType BaseType, bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- NamedDecl *FirstQualifierFoundInScope,
+ Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow,
+ SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
static CXXDependentScopeMemberExpr *
- CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
+ CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
/// \brief True if this is an implicit access, i.e. one in which the
@@ -3197,6 +3292,7 @@ public:
}
/// \brief Retrieves the optional explicit template arguments.
+ ///
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
@@ -3259,11 +3355,13 @@ public:
/// produced a set of overloaded functions.
///
/// The member access may be explicit or implicit:
+/// \code
/// struct A {
/// int a, b;
/// int explicitAccess() { return this->a + this->A::b; }
/// int implicitAccess() { return a + A::b; }
/// };
+/// \endcode
///
/// In the final AST, an explicit access always becomes a MemberExpr.
/// An implicit access may become either a MemberExpr or a
@@ -3278,17 +3376,18 @@ class UnresolvedMemberExpr : public OverloadExpr {
bool HasUnresolvedUsing : 1;
/// \brief The expression for the base pointer or class reference,
- /// e.g., the \c x in x.f. This can be null if this is an 'unbased'
- /// member expression
+ /// e.g., the \c x in x.f.
+ ///
+ /// This can be null if this is an 'unbased' member expression.
Stmt *Base;
- /// \brief The type of the base expression; never null.
+ /// \brief The type of the base expression; never null.
QualType BaseType;
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
- UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing,
+ UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -3305,7 +3404,7 @@ class UnresolvedMemberExpr : public OverloadExpr {
public:
static UnresolvedMemberExpr *
- Create(ASTContext &C, bool HasUnresolvedUsing,
+ Create(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -3315,12 +3414,13 @@ public:
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
static UnresolvedMemberExpr *
- CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
+ CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
- /// \brief True if this is an implicit access, i.e. one in which the
- /// member being accessed was not written in the source. The source
- /// location of the operator is invalid in this case.
+ /// \brief True if this is an implicit access, i.e., one in which the
+ /// member being accessed was not written in the source.
+ ///
+ /// The source location of the operator is invalid in this case.
bool isImplicitAccess() const;
/// \brief Retrieve the base object of this member expressions,
@@ -3347,7 +3447,7 @@ public:
/// \brief Retrieve the location of the '->' or '.' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
- /// \brief Retrieves the naming class of this lookup.
+ /// \brief Retrieve the naming class of this lookup.
CXXRecordDecl *getNamingClass() const;
/// \brief Retrieve the full name info for the member that this expression
@@ -3362,6 +3462,10 @@ public:
// expression refers to.
SourceLocation getMemberLoc() const { return getNameLoc(); }
+ // \brief Return the preferred location (the member name) for the arrow when
+ // diagnosing a problem with this expression.
+ SourceLocation getExprLoc() const LLVM_READONLY { return getMemberLoc(); }
+
SourceLocation getLocStart() const LLVM_READONLY {
if (!isImplicitAccess())
return Base->getLocStart();
@@ -3386,7 +3490,7 @@ public:
}
};
-/// \brief Represents a C++0x noexcept expression (C++ [expr.unary.noexcept]).
+/// \brief Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
///
/// The noexcept expression tests whether a given expression might throw. Its
/// result is a boolean constant.
@@ -3428,7 +3532,7 @@ public:
child_range children() { return child_range(&Operand, &Operand + 1); }
};
-/// \brief Represents a C++0x pack expansion that produces a sequence of
+/// \brief Represents a C++11 pack expansion that produces a sequence of
/// expressions.
///
/// A pack expansion expression contains a pattern (which itself is an
@@ -3527,7 +3631,7 @@ inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() {
/// };
/// \endcode
class SizeOfPackExpr : public Expr {
- /// \brief The location of the 'sizeof' keyword.
+ /// \brief The location of the \c sizeof keyword.
SourceLocation OperatorLoc;
/// \brief The location of the name of the parameter pack.
@@ -3550,7 +3654,7 @@ class SizeOfPackExpr : public Expr {
friend class ASTStmtWriter;
public:
- /// \brief Creates a value-dependent expression that computes the length of
+ /// \brief Create a value-dependent expression that computes the length of
/// the given parameter pack.
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc, SourceLocation RParenLoc)
@@ -3561,7 +3665,7 @@ public:
OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
Length(0), Pack(Pack) { }
- /// \brief Creates an expression that computes the length of
+ /// \brief Create an expression that computes the length of
/// the given parameter pack, which is already known.
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc, SourceLocation RParenLoc,
@@ -3744,11 +3848,11 @@ class FunctionParmPackExpr : public Expr {
friend class ASTStmtReader;
public:
- static FunctionParmPackExpr *Create(ASTContext &Context, QualType T,
+ static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T,
ParmVarDecl *ParamPack,
SourceLocation NameLoc,
ArrayRef<Decl *> Params);
- static FunctionParmPackExpr *CreateEmpty(ASTContext &Context,
+ static FunctionParmPackExpr *CreateEmpty(const ASTContext &Context,
unsigned NumParams);
/// \brief Get the parameter pack which this expression refers to.
@@ -3779,7 +3883,7 @@ public:
child_range children() { return child_range(); }
};
-/// \brief Represents a prvalue temporary that written into memory so that
+/// \brief Represents a prvalue temporary that is written into memory so that
/// a reference can bind to it.
///
/// Prvalue expressions are materialized when they need to have an address
@@ -3795,30 +3899,60 @@ public:
/// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues
/// (either an lvalue or an xvalue, depending on the kind of reference binding
/// to it), maintaining the invariant that references always bind to glvalues.
+///
+/// Reference binding and copy-elision can both extend the lifetime of a
+/// temporary. When either happens, the expression will also track the
+/// declaration which is responsible for the lifetime extension.
class MaterializeTemporaryExpr : public Expr {
+public:
/// \brief The temporary-generating expression whose value will be
/// materialized.
Stmt *Temporary;
+ /// \brief The declaration which lifetime-extended this reference, if any.
+ /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
+ const ValueDecl *ExtendingDecl;
+
friend class ASTStmtReader;
friend class ASTStmtWriter;
public:
MaterializeTemporaryExpr(QualType T, Expr *Temporary,
- bool BoundToLvalueReference)
+ bool BoundToLvalueReference,
+ const ValueDecl *ExtendedBy)
: Expr(MaterializeTemporaryExprClass, T,
BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
Temporary->isTypeDependent(), Temporary->isValueDependent(),
Temporary->isInstantiationDependent(),
Temporary->containsUnexpandedParameterPack()),
- Temporary(Temporary) { }
+ Temporary(Temporary), ExtendingDecl(ExtendedBy) {
+ }
MaterializeTemporaryExpr(EmptyShell Empty)
: Expr(MaterializeTemporaryExprClass, Empty) { }
/// \brief Retrieve the temporary-generating subexpression whose value will
/// be materialized into a glvalue.
- Expr *GetTemporaryExpr() const { return reinterpret_cast<Expr *>(Temporary); }
+ Expr *GetTemporaryExpr() const { return static_cast<Expr *>(Temporary); }
+
+ /// \brief Retrieve the storage duration for the materialized temporary.
+ StorageDuration getStorageDuration() const {
+ if (!ExtendingDecl)
+ return SD_FullExpression;
+ // FIXME: This is not necessarily correct for a temporary materialized
+ // within a default initializer.
+ if (isa<FieldDecl>(ExtendingDecl))
+ return SD_Automatic;
+ return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
+ }
+
+ /// \brief Get the declaration which triggered the lifetime-extension of this
+ /// temporary, if any.
+ const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }
+
+ void setExtendingDecl(const ValueDecl *ExtendedBy) {
+ ExtendingDecl = ExtendedBy;
+ }
/// \brief Determine whether this materialized temporary is bound to an
/// lvalue reference; otherwise, it's bound to an rvalue reference.
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index a94c69a115d6..aeb55da1fb91 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -143,12 +143,13 @@ class ObjCArrayLiteral : public Expr {
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
public:
- static ObjCArrayLiteral *Create(ASTContext &C,
+ static ObjCArrayLiteral *Create(const ASTContext &C,
ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR);
- static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements);
+ static ObjCArrayLiteral *CreateEmpty(const ASTContext &C,
+ unsigned NumElements);
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
@@ -289,13 +290,13 @@ class ObjCDictionaryLiteral : public Expr {
}
public:
- static ObjCDictionaryLiteral *Create(ASTContext &C,
+ static ObjCDictionaryLiteral *Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions,
QualType T, ObjCMethodDecl *method,
SourceRange SR);
- static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C,
+ static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C,
unsigned NumElements,
bool HasPackExpansions);
@@ -807,7 +808,7 @@ public:
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
: Expr(ObjCSubscriptRefExprClass, Empty) {}
- static ObjCSubscriptRefExpr *Create(ASTContext &C,
+ static ObjCSubscriptRefExpr *Create(const ASTContext &C,
Expr *base,
Expr *key, QualType T,
ObjCMethodDecl *getMethod,
@@ -1003,13 +1004,13 @@ class ObjCMessageExpr : public Expr {
return getNumSelectorLocs();
}
- static ObjCMessageExpr *alloc(ASTContext &C,
+ static ObjCMessageExpr *alloc(const ASTContext &C,
ArrayRef<Expr *> Args,
SourceLocation RBraceLoc,
ArrayRef<SourceLocation> SelLocs,
Selector Sel,
SelectorLocationsKind &SelLocsK);
- static ObjCMessageExpr *alloc(ASTContext &C,
+ static ObjCMessageExpr *alloc(const ASTContext &C,
unsigned NumArgs,
unsigned NumStoredSelLocs);
@@ -1051,7 +1052,7 @@ public:
/// \param Args The message send arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
- static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
@@ -1087,7 +1088,7 @@ public:
/// \param Args The message send arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
- static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
@@ -1121,7 +1122,7 @@ public:
/// \param Args The message send arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
- static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
@@ -1139,7 +1140,7 @@ public:
///
/// \param NumArgs The number of message arguments, not including
/// the receiver.
- static ObjCMessageExpr *CreateEmpty(ASTContext &Context,
+ static ObjCMessageExpr *CreateEmpty(const ASTContext &Context,
unsigned NumArgs,
unsigned NumStoredSelLocs);
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 81fcf242b65e..b077426e6a47 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -329,7 +329,12 @@ public:
/// \brief Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
- operator bool() const { return Ptr != 0; }
+ LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
+
+ /// \brief Whether this pointer is non-NULL.
+ ///
+ /// This operation does not require the AST node to be deserialized.
+ bool isValid() const { return Ptr != 0; }
/// \brief Whether this pointer is currently stored as an offset.
bool isOffset() const { return Ptr & 0x01; }
diff --git a/include/clang/AST/GlobalDecl.h b/include/clang/AST/GlobalDecl.h
index c43e44c26f31..54c9d88c9b2e 100644
--- a/include/clang/AST/GlobalDecl.h
+++ b/include/clang/AST/GlobalDecl.h
@@ -41,6 +41,7 @@ public:
GlobalDecl(const VarDecl *D) { Init(D);}
GlobalDecl(const FunctionDecl *D) { Init(D); }
GlobalDecl(const BlockDecl *D) { Init(D); }
+ GlobalDecl(const CapturedDecl *D) { Init(D); }
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
diff --git a/include/clang/AST/LambdaMangleContext.h b/include/clang/AST/LambdaMangleContext.h
deleted file mode 100644
index bbaee26494a9..000000000000
--- a/include/clang/AST/LambdaMangleContext.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- 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 LambdaMangleContext interface, which keeps track of
-// the Itanium C++ ABI mangling numbers for lambda expressions.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
-#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
-
-namespace clang {
-
-class CXXMethodDecl;
-class FunctionProtoType;
-
-/// \brief Keeps track of the mangled names of lambda expressions within a
-/// particular context.
-class LambdaMangleContext : public RefCountedBase<LambdaMangleContext> {
- llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
-
-public:
- /// \brief Retrieve the mangling number of a new lambda expression with the
- /// given call operator within this lambda context.
- unsigned getManglingNumber(CXXMethodDecl *CallOperator);
-};
-
-} // end namespace clang
-#endif
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index b6d22cfb5fd7..c4d0d22cdf0a 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
@@ -64,18 +65,29 @@ private:
/// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler.
class MangleContext {
+public:
+ enum ManglerKind {
+ MK_Itanium,
+ MK_Microsoft
+ };
+
+private:
virtual void anchor();
ASTContext &Context;
DiagnosticsEngine &Diags;
+ const ManglerKind Kind;
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
-
+
public:
+ ManglerKind getKind() const { return Kind; }
+
explicit MangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags)
- : Context(Context), Diags(Diags) { }
+ DiagnosticsEngine &Diags,
+ ManglerKind Kind)
+ : Context(Context), Diags(Diags), Kind(Kind) {}
virtual ~MangleContext() { }
@@ -96,8 +108,12 @@ public:
/// @name Mangler Entry Points
/// @{
- virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
- virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
+ bool shouldMangleDeclName(const NamedDecl *D);
+ virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
+
+ // FIXME: consider replacing raw_ostream & with something like SmallString &.
+ void mangleName(const NamedDecl *D, raw_ostream &);
+ virtual void mangleCXXName(const NamedDecl *D, raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &) = 0;
@@ -106,13 +122,6 @@ public:
raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D,
raw_ostream &) = 0;
- virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &) = 0;
- virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &) = 0;
- virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
@@ -129,36 +138,78 @@ public:
const BlockDecl *BD, raw_ostream &Out);
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
raw_ostream &Out);
- // Do the right thing.
- void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
- const NamedDecl *ID=0);
- void mangleObjCMethodName(const ObjCMethodDecl *MD,
- raw_ostream &);
+ void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &);
- // This is pretty lame.
- virtual void mangleItaniumGuardVariable(const VarDecl *D,
- raw_ostream &) {
- llvm_unreachable("Target does not support mangling guard variables");
- }
- // FIXME: Revisit this once we know what we need to do for MSVC compatibility.
+ virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0;
+
+ virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &) = 0;
+
+ virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &) = 0;
+
+ /// Generates a unique string for an externally visible type for use with TBAA
+ /// or type uniquing.
+ /// TODO: Extend this to internal types by generating names that are unique
+ /// across translation units so it can be used with LTO.
+ virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
+
+ /// @}
+};
+
+class ItaniumMangleContext : public MangleContext {
+public:
+ explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
+ : MangleContext(C, D, MK_Itanium) {}
+
+ virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
+ virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
+ virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &) = 0;
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
- raw_ostream &) {
- llvm_unreachable("Target does not support mangling thread_local variables");
- }
+ raw_ostream &) = 0;
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
- raw_ostream &) {
- llvm_unreachable("Target does not support mangling thread_local variables");
+ raw_ostream &) = 0;
+
+ static bool classof(const MangleContext *C) {
+ return C->getKind() == MK_Itanium;
}
- /// @}
+ static ItaniumMangleContext *create(ASTContext &Context,
+ DiagnosticsEngine &Diags);
};
-MangleContext *createItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags);
-MangleContext *createMicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags);
+class MicrosoftMangleContext : public MangleContext {
+public:
+ explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D)
+ : MangleContext(C, D, MK_Microsoft) {}
+
+ /// \brief Mangle vftable symbols. Only a subset of the bases along the path
+ /// to the vftable are included in the name. It's up to the caller to pick
+ /// them correctly.
+ virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) = 0;
+
+ /// \brief Mangle vbtable symbols. Only a subset of the bases along the path
+ /// to the vbtable are included in the name. It's up to the caller to pick
+ /// them correctly.
+ virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) = 0;
+
+ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ uint64_t OffsetInVFTable,
+ raw_ostream &) = 0;
+ static bool classof(const MangleContext *C) {
+ return C->getKind() == MK_Microsoft;
+ }
+
+ static MicrosoftMangleContext *create(ASTContext &Context,
+ DiagnosticsEngine &Diags);
+};
}
#endif
diff --git a/include/clang/AST/MangleNumberingContext.h b/include/clang/AST/MangleNumberingContext.h
new file mode 100644
index 000000000000..5a227f201fbb
--- /dev/null
+++ b/include/clang/AST/MangleNumberingContext.h
@@ -0,0 +1,59 @@
+//=== MangleNumberingContext.h - Context for mangling numbers ---*- 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 LambdaBlockMangleContext interface, which keeps track
+// of the Itanium C++ ABI mangling numbers for lambda expressions and block
+// literals.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
+#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+namespace clang {
+
+class BlockDecl;
+class CXXMethodDecl;
+class IdentifierInfo;
+class TagDecl;
+class Type;
+class VarDecl;
+
+/// \brief Keeps track of the mangled names of lambda expressions and block
+/// literals within a particular context.
+class MangleNumberingContext
+ : public RefCountedBase<MangleNumberingContext> {
+ llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
+ llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
+
+public:
+ virtual ~MangleNumberingContext() {}
+
+ /// \brief Retrieve the mangling number of a new lambda expression with the
+ /// given call operator within this context.
+ unsigned getManglingNumber(const CXXMethodDecl *CallOperator);
+
+ /// \brief Retrieve the mangling number of a new block literal within this
+ /// context.
+ unsigned getManglingNumber(const BlockDecl *BD);
+
+ /// \brief Retrieve the mangling number of a static local variable within
+ /// this context.
+ virtual unsigned getManglingNumber(const VarDecl *VD) = 0;
+
+ /// \brief Retrieve the mangling number of a static local variable within
+ /// this context.
+ unsigned getManglingNumber(const TagDecl *TD);
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 58f39862b102..b332b153fe8d 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -231,7 +231,11 @@ public:
/// \brief Evalutes true when this nested-name-specifier location is
/// non-empty.
- operator bool() const { return Qualifier; }
+ LLVM_EXPLICIT operator bool() const { return Qualifier; }
+
+ /// \brief Evalutes true when this nested-name-specifier location is
+ /// empty.
+ bool hasQualifier() const { return Qualifier; }
/// \brief Retrieve the nested-name-specifier to which this instance
/// refers.
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
index 62eae02c1525..bd2ebf5dbedb 100644
--- a/include/clang/AST/ParentMap.h
+++ b/include/clang/AST/ParentMap.h
@@ -29,6 +29,11 @@ public:
/// visited and updated or inserted but not the parents of S.
void addStmt(Stmt* S);
+ /// Manually sets the parent of \p S to \p Parent.
+ ///
+ /// If \p S is already in the map, this method will update the mapping.
+ void setParent(const Stmt *S, const Stmt *Parent);
+
Stmt *getParent(Stmt*) const;
Stmt *getParentIgnoreParens(Stmt *) const;
Stmt *getParentIgnoreParenCasts(Stmt *) const;
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index e3c09e7b418f..76426991cf47 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -39,8 +39,9 @@ struct PrintingPolicy {
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
- SuppressStrongLifetime(false), Bool(LO.Bool),
- TerseOutput(false), PolishForDeclaration(false) { }
+ SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
+ Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
+ MSWChar(LO.MicrosoftExt && !LO.WChar) { }
/// \brief What language we're printing.
LangOptions LangOpts;
@@ -131,6 +132,10 @@ struct PrintingPolicy {
/// ARC.
unsigned SuppressStrongLifetime : 1;
+ /// \brief When true, suppress printing of lifetime qualifier in
+ /// ARC.
+ unsigned SuppressLifetimeQualifiers : 1;
+
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
unsigned Bool : 1;
@@ -146,6 +151,10 @@ struct PrintingPolicy {
/// declaration tag; such as, do not print attributes attached to the declaration.
///
unsigned PolishForDeclaration : 1;
+
+ /// \brief When true, print the built-in wchar_t type as __wchar_t. For use in
+ /// Microsoft mode when wchar_t is not available.
+ unsigned MSWChar : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h
index 84a6e96fa01a..a4fcc108eb5d 100644
--- a/include/clang/AST/RawCommentList.h
+++ b/include/clang/AST/RawCommentList.h
@@ -107,12 +107,9 @@ public:
return RawText;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return Range;
- }
-
- unsigned getBeginLine(const SourceManager &SM) const;
- unsigned getEndLine(const SourceManager &SM) const;
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
const char *getBriefText(const ASTContext &Context) const {
if (BriefTextValid)
@@ -146,11 +143,6 @@ private:
/// considered as documentation comments.
bool ParseAllComments : 1;
- mutable bool BeginLineValid : 1; ///< True if BeginLine is valid
- mutable bool EndLineValid : 1; ///< True if EndLine is valid
- mutable unsigned BeginLine; ///< Cached line number
- mutable unsigned EndLine; ///< Cached line number
-
/// \brief Constructor for AST deserialization.
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
bool IsAlmostTrailingComment,
@@ -158,8 +150,7 @@ private:
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
IsAttached(false), IsTrailingComment(IsTrailingComment),
IsAlmostTrailingComment(IsAlmostTrailingComment),
- ParseAllComments(ParseAllComments),
- BeginLineValid(false), EndLineValid(false)
+ ParseAllComments(ParseAllComments)
{ }
StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
@@ -178,8 +169,7 @@ public:
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
bool operator()(const RawComment &LHS, const RawComment &RHS) {
- return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(),
- RHS.getSourceRange().getBegin());
+ return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart());
}
bool operator()(const RawComment *LHS, const RawComment *RHS) {
@@ -191,8 +181,7 @@ public:
/// sorted in order of appearance in the translation unit.
class RawCommentList {
public:
- RawCommentList(SourceManager &SourceMgr) :
- SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
+ RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
@@ -203,15 +192,9 @@ public:
private:
SourceManager &SourceMgr;
std::vector<RawComment *> Comments;
- SourceLocation PrevCommentEndLoc;
- bool OnlyWhitespaceSeen;
void addCommentsToFront(const std::vector<RawComment *> &C) {
- size_t OldSize = Comments.size();
- Comments.resize(C.size() + OldSize);
- std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
- Comments.end());
- std::copy(C.begin(), C.end(), Comments.begin());
+ Comments.insert(Comments.begin(), C.begin(), C.end());
}
friend class ASTReader;
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index 36556469eaf8..7268b3a8240c 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -93,10 +93,22 @@ private:
/// HasOwnVFPtr - Does this class provide a virtual function table
/// (vtable in Itanium, vftbl in Microsoft) that is independent from
/// its base classes?
- bool HasOwnVFPtr; // TODO: stash this somewhere more efficient
+ bool HasOwnVFPtr : 1;
+
+ /// HasVFPtr - Does this class have a vftable that could be extended by
+ /// a derived class. The class may have inherited this pointer from
+ /// a primary base class.
+ bool HasExtendableVFPtr : 1;
+
+ /// AlignAfterVBases - Force appropriate alignment after virtual bases are
+ /// laid out in MS-C++-ABI.
+ bool AlignAfterVBases : 1;
/// PrimaryBase - The primary base info for this record.
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
+
+ /// BaseSharingVBPtr - The base we share vbptr with.
+ const CXXRecordDecl *BaseSharingVBPtr;
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
@@ -122,13 +134,16 @@ private:
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- bool hasOwnVFPtr, CharUnits vbptroffset,
+ bool hasOwnVFPtr, bool hasExtendableVFPtr,
+ CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase,
bool IsPrimaryBaseVirtual,
+ const CXXRecordDecl *BaseSharingVBPtr,
+ bool ForceAlign,
const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets);
@@ -226,6 +241,37 @@ public:
return CXXInfo->HasOwnVFPtr;
}
+ /// hasVFPtr - Does this class have a virtual function table pointer
+ /// that can be extended by a derived class? This is synonymous with
+ /// this class having a VFPtr at offset zero.
+ bool hasExtendableVFPtr() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->HasExtendableVFPtr;
+ }
+
+ /// hasOwnVBPtr - Does this class provide its own virtual-base
+ /// table pointer, rather than inheriting one from a primary base
+ /// class?
+ ///
+ /// This implies that the ABI has no primary base class, meaning
+ /// that it has no base classes that are suitable under the conditions
+ /// of the ABI.
+ bool hasOwnVBPtr() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
+ }
+
+ /// hasVBPtr - Does this class have a virtual function table pointer.
+ bool hasVBPtr() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return !CXXInfo->VBPtrOffset.isNegative();
+ }
+
+ bool getAlignAfterVBases() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->AlignAfterVBases;
+ }
+
/// getVBPtrOffset - Get the offset for virtual base table pointer.
/// This is only meaningful with the Microsoft ABI.
CharUnits getVBPtrOffset() const {
@@ -233,6 +279,11 @@ public:
return CXXInfo->VBPtrOffset;
}
+ const CXXRecordDecl *getBaseSharingVBPtr() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->BaseSharingVBPtr;
+ }
+
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->VBaseOffsets;
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index b5a4b5e36d7d..d09550f0e2c2 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -27,6 +27,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -108,7 +109,7 @@ namespace clang {
/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
/// is Foo's super class) before calling VisitFoo(), the result is
/// that the Visit*() methods for a given node are called in the
-/// top-down order (e.g. for a node of type NamedDecl, the order will
+/// top-down order (e.g. for a node of type NamespaceDecl, the order will
/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
///
/// This scheme guarantees that all Visit*() calls for the same AST
@@ -243,8 +244,16 @@ public:
/// \brief Recursively visit a lambda capture.
///
/// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseLambdaCapture(LambdaExpr::Capture C);
-
+ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C);
+
+ /// \brief Recursively visit the body of a lambda expression.
+ ///
+ /// This provides a hook for visitors that need more context when visiting
+ /// \c LE->getBody().
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseLambdaBody(LambdaExpr *LE);
+
// ---- Methods on Stmts ----
// Declare Traverse*() for all concrete Stmt classes.
@@ -342,7 +351,7 @@ public:
// ---- Methods on TypeLocs ----
// FIXME: this currently just calls the matching Type methods
- // Declare Traverse*() for all concrete Type classes.
+ // Declare Traverse*() for all concrete TypeLoc classes.
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
@@ -398,8 +407,12 @@ public:
private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
- bool TraverseClassInstantiations(ClassTemplateDecl *D);
- bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
+#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
+ bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
+ DEF_TRAVERSE_TMPL_INST(Class)
+ DEF_TRAVERSE_TMPL_INST(Var)
+ DEF_TRAVERSE_TMPL_INST(Function)
+#undef DEF_TRAVERSE_TMPL_INST
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
@@ -409,6 +422,13 @@ private:
bool TraverseDeclContextHelper(DeclContext *DC);
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
+ bool TraverseOMPClause(OMPClause *C);
+#define OPENMP_CLAUSE(Name, Class) \
+ bool Visit##Class(Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
struct EnqueueJob {
Stmt *S;
@@ -802,10 +822,20 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
}
template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
+ LambdaExpr *LE, const LambdaExpr::Capture *C) {
+ if (C->isInitCapture())
+ TRY_TO(TraverseDecl(C->getCapturedVar()));
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
+ TRY_TO(TraverseStmt(LE->getBody()));
return true;
}
+
// ----------------- Type traversal -----------------
// This macro makes available a variable T, the passed-in type.
@@ -844,6 +874,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
TRY_TO(TraverseType(T->getPointeeType()));
})
+DEF_TRAVERSE_TYPE(DecayedType, {
+ TRY_TO(TraverseType(T->getOriginalType()));
+ })
+
DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseType(T->getElementType()));
})
@@ -1050,6 +1084,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
})
+DEF_TRAVERSE_TYPELOC(DecayedType, {
+ TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
+ })
+
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
@@ -1420,59 +1458,44 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
return true;
}
-// A helper method for traversing the implicit instantiations of a
-// class template.
-template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
- ClassTemplateDecl *D) {
- ClassTemplateDecl::spec_iterator end = D->spec_end();
- for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
- ClassTemplateSpecializationDecl* SD = *it;
-
- switch (SD->getSpecializationKind()) {
- // Visit the implicit instantiations with the requested pattern.
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- TRY_TO(TraverseDecl(SD));
- break;
-
- // We don't need to do anything on an explicit instantiation
- // or explicit specialization because there will be an explicit
- // node for it elsewhere.
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitSpecialization:
- break;
- }
- }
-
- return true;
+#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
+/* A helper method for traversing the implicit instantiations of a
+ class or variable template. */ \
+template<typename Derived> \
+bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( \
+ TMPLDECLKIND##TemplateDecl *D) { \
+ TMPLDECLKIND##TemplateDecl::spec_iterator end = D->spec_end(); \
+ for (TMPLDECLKIND##TemplateDecl::spec_iterator it = D->spec_begin(); \
+ it != end; ++it) { \
+ TMPLDECLKIND##TemplateSpecializationDecl* SD = *it; \
+ \
+ switch (SD->getSpecializationKind()) { \
+ /* Visit the implicit instantiations with the requested pattern. */ \
+ case TSK_Undeclared: \
+ case TSK_ImplicitInstantiation: \
+ TRY_TO(TraverseDecl(SD)); \
+ break; \
+ \
+ /* We don't need to do anything on an explicit instantiation
+ or explicit specialization because there will be an explicit
+ node for it elsewhere. */ \
+ case TSK_ExplicitInstantiationDeclaration: \
+ case TSK_ExplicitInstantiationDefinition: \
+ case TSK_ExplicitSpecialization: \
+ break; \
+ } \
+ } \
+ \
+ return true; \
}
-
-DEF_TRAVERSE_DECL(ClassTemplateDecl, {
- CXXRecordDecl* TempDecl = D->getTemplatedDecl();
- TRY_TO(TraverseDecl(TempDecl));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
- // By default, we do not traverse the instantiations of
- // class templates since they do not appear in the user code. The
- // following code optionally traverses them.
- //
- // We only traverse the class instantiations when we see the canonical
- // declaration of the template, to ensure we only visit them once.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D == D->getCanonicalDecl())
- TRY_TO(TraverseClassInstantiations(D));
-
- // Note that getInstantiatedFromMemberTemplate() is just a link
- // from a template instantiation back to the template from which
- // it was instantiated, and thus should not be traversed.
- })
+
+DEF_TRAVERSE_TMPL_INST(Class)
+DEF_TRAVERSE_TMPL_INST(Var)
// A helper method for traversing the instantiations of a
// function while skipping its specializations.
template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
+bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
FunctionTemplateDecl *D) {
FunctionTemplateDecl::spec_iterator end = D->spec_end();
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
@@ -1500,20 +1523,31 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
return true;
}
-DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
- TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
- // By default, we do not traverse the instantiations of
- // function templates since they do not appear in the user code. The
- // following code optionally traverses them.
- //
- // We only traverse the function instantiations when we see the canonical
- // declaration of the template, to ensure we only visit them once.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D == D->getCanonicalDecl())
- TRY_TO(TraverseFunctionInstantiations(D));
- })
+// This macro unifies the traversal of class, variable and function
+// template declarations.
+#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \
+ TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
+ \
+ /* By default, we do not traverse the instantiations of
+ class templates since they do not appear in the user code. The
+ following code optionally traverses them.
+
+ We only traverse the class instantiations when we see the canonical
+ declaration of the template, to ensure we only visit them once. */ \
+ if (getDerived().shouldVisitTemplateInstantiations() && \
+ D == D->getCanonicalDecl()) \
+ TRY_TO(TraverseTemplateInstantiations(D)); \
+ \
+ /* Note that getInstantiatedFromMemberTemplate() is just a link
+ from a template instantiation back to the template from which
+ it was instantiated, and thus should not be traversed. */ \
+ })
+
+DEF_TRAVERSE_TMPL_DECL(Class)
+DEF_TRAVERSE_TMPL_DECL(Var)
+DEF_TRAVERSE_TMPL_DECL(Function)
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like
@@ -1607,26 +1641,30 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, {
TRY_TO(TraverseCXXRecordHelper(D));
})
-DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
- // For implicit instantiations ("set<int> x;"), we don't want to
- // recurse at all, since the instatiated class isn't written in
- // the source code anywhere. (Note the instatiated *type* --
- // set<int> -- is written, and will still get a callback of
- // TemplateSpecializationType). For explicit instantiations
- // ("template set<int>;"), we do need a callback, since this
- // is the only callback that's made for this instantiation.
- // We use getTypeAsWritten() to distinguish.
- if (TypeSourceInfo *TSI = D->getTypeAsWritten())
- TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-
- if (!getDerived().shouldVisitTemplateInstantiations() &&
- D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
- // Returning from here skips traversing the
- // declaration context of the ClassTemplateSpecializationDecl
- // (embedded in the DEF_TRAVERSE_DECL() macro)
- // which contains the instantiated members of the class.
- return true;
- })
+#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
+ /* For implicit instantiations ("set<int> x;"), we don't want to
+ recurse at all, since the instatiated template isn't written in
+ the source code anywhere. (Note the instatiated *type* --
+ set<int> -- is written, and will still get a callback of
+ TemplateSpecializationType). For explicit instantiations
+ ("template set<int>;"), we do need a callback, since this
+ is the only callback that's made for this instantiation.
+ We use getTypeAsWritten() to distinguish. */ \
+ if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
+ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
+ \
+ if (!getDerived().shouldVisitTemplateInstantiations() && \
+ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
+ /* Returning from here skips traversing the
+ declaration context of the *TemplateSpecializationDecl
+ (embedded in the DEF_TRAVERSE_DECL() macro)
+ which contains the instantiated members of the template. */ \
+ return true; \
+ })
+
+DEF_TRAVERSE_TMPL_SPEC_DECL(Class)
+DEF_TRAVERSE_TMPL_SPEC_DECL(Var)
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
@@ -1637,25 +1675,30 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
return true;
}
-DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
- // The partial specialization.
- if (TemplateParameterList *TPL = D->getTemplateParameters()) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
- }
- }
- // The args that remains unspecialized.
- TRY_TO(TraverseTemplateArgumentLocsHelper(
- D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
-
- // Don't need the ClassTemplatePartialSpecializationHelper, even
- // though that's our parent class -- we already visit all the
- // template args here.
- TRY_TO(TraverseCXXRecordHelper(D));
-
- // Instantiations will have been visited with the primary template.
- })
+#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
+ /* The partial specialization. */ \
+ if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
+ I != E; ++I) { \
+ TRY_TO(TraverseDecl(*I)); \
+ } \
+ } \
+ /* The args that remains unspecialized. */ \
+ TRY_TO(TraverseTemplateArgumentLocsHelper( \
+ D->getTemplateArgsAsWritten()->getTemplateArgs(), \
+ D->getTemplateArgsAsWritten()->NumTemplateArgs)); \
+ \
+ /* Don't need the *TemplatePartialSpecializationHelper, even
+ though that's our parent class -- we already visit all the
+ template args here. */ \
+ TRY_TO(Traverse##DECLKIND##Helper(D)); \
+ \
+ /* Instantiations will have been visited with the primary template. */ \
+ })
+
+DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Class, CXXRecord)
+DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Var, Var)
DEF_TRAVERSE_DECL(EnumConstantDecl, {
TRY_TO(TraverseStmt(D->getInitExpr()));
@@ -1736,6 +1779,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// including exception specifications.
if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+ } else if (getDerived().shouldVisitImplicitCode()) {
+ // Visit parameter variable declarations of the implicit function
+ // if the traverser is visiting implicit code. Parameter variable
+ // declarations do not have valid TypeSourceInfo, so to visit them
+ // we need to traverse the declarations explicitly.
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end(); I != E; ++I)
+ TRY_TO(TraverseDecl(*I));
}
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
@@ -2117,10 +2168,12 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
// Walk only the visible parts of lambda expressions.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
+ TRY_TO(WalkUpFromLambdaExpr(S));
+
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
- TRY_TO(TraverseLambdaCapture(*C));
+ TRY_TO(TraverseLambdaCapture(S, C));
}
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
@@ -2140,7 +2193,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
}
}
- TRY_TO(TraverseStmt(S->getBody()));
+ TRY_TO(TraverseLambdaBody(S));
return true;
}
@@ -2174,6 +2227,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
@@ -2211,6 +2265,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
DEF_TRAVERSE_STMT(ParenListExpr, { })
DEF_TRAVERSE_STMT(PredefinedExpr, { })
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
DEF_TRAVERSE_STMT(StmtExpr, { })
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@@ -2269,6 +2324,61 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
// Traverse OpenCL: AsType, Convert.
DEF_TRAVERSE_STMT(AsTypeExpr, { })
+// OpenMP directives.
+DEF_TRAVERSE_STMT(OMPParallelDirective, {
+ ArrayRef<OMPClause *> Clauses = S->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (!TraverseOMPClause(*I)) return false;
+})
+
+// OpenMP clauses.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
+ if (!C) return true;
+ switch (C->getClauseKind()) {
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: \
+ return getDerived().Visit##Class(static_cast<Class*>(C));
+#include "clang/Basic/OpenMPKinds.def"
+ default: break;
+ }
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ return true;
+}
+
+template<typename Derived>
+template<typename T>
+void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ TraverseStmt(*I);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
+ OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
// FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
index e3b340a5a1fe..cfe5a90be0d5 100644
--- a/include/clang/AST/Redeclarable.h
+++ b/include/clang/AST/Redeclarable.h
@@ -75,7 +75,7 @@ public:
/// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration.
- decl_type *getFirstDeclaration() {
+ decl_type *getFirstDecl() {
decl_type *D = static_cast<decl_type*>(this);
while (D->getPreviousDecl())
D = D->getPreviousDecl();
@@ -84,31 +84,29 @@ public:
/// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration.
- const decl_type *getFirstDeclaration() const {
+ const decl_type *getFirstDecl() const {
const decl_type *D = static_cast<const decl_type*>(this);
while (D->getPreviousDecl())
D = D->getPreviousDecl();
return D;
}
- /// \brief Returns true if this is the first declaration.
- bool isFirstDeclaration() const {
- return RedeclLink.NextIsLatest();
- }
+ /// \brief True if this is the first declaration in its redeclaration chain.
+ bool isFirstDecl() const { return RedeclLink.NextIsLatest(); }
/// \brief Returns the most recent (re)declaration of this declaration.
decl_type *getMostRecentDecl() {
- return getFirstDeclaration()->RedeclLink.getNext();
+ return getFirstDecl()->RedeclLink.getNext();
}
/// \brief Returns the most recent (re)declaration of this declaration.
const decl_type *getMostRecentDecl() const {
- return getFirstDeclaration()->RedeclLink.getNext();
+ return getFirstDecl()->RedeclLink.getNext();
}
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
/// first and only declaration.
- void setPreviousDeclaration(decl_type *PrevDecl);
+ void setPreviousDecl(decl_type *PrevDecl);
/// \brief Iterates through all the redeclarations of the same decl.
class redecl_iterator {
@@ -134,7 +132,7 @@ public:
redecl_iterator& operator++() {
assert(Current && "Advancing while iterator has reached end");
// Sanity check to avoid infinite loop on invalid redecl chain.
- if (Current->isFirstDeclaration()) {
+ if (Current->isFirstDecl()) {
if (PassedFirst) {
assert(0 && "Passed first decl twice, invalid redecl chain!");
Current = 0;
@@ -175,6 +173,40 @@ public:
friend class ASTDeclWriter;
};
+/// \brief Get the primary declaration for a declaration from an AST file. That
+/// will be the first-loaded declaration.
+Decl *getPrimaryMergedDecl(Decl *D);
+
+/// \brief Provides common interface for the Decls that cannot be redeclared,
+/// but can be merged if the same declaration is brought in from multiple
+/// modules.
+template<typename decl_type>
+class Mergeable {
+public:
+ Mergeable() {}
+
+ /// \brief Return the first declaration of this declaration or itself if this
+ /// is the only declaration.
+ decl_type *getFirstDecl() {
+ decl_type *D = static_cast<decl_type*>(this);
+ if (!D->isFromASTFile())
+ return D;
+ return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
+ }
+
+ /// \brief Return the first declaration of this declaration or itself if this
+ /// is the only declaration.
+ const decl_type *getFirstDecl() const {
+ const decl_type *D = static_cast<const decl_type*>(this);
+ if (!D->isFromASTFile())
+ return D;
+ return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
+ }
+
+ /// \brief Returns true if this is the first declaration.
+ bool isFirstDecl() const { return getFirstDecl() == this; }
+};
+
}
#endif
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 74c9ec205363..ace53d83b3cf 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -266,10 +266,6 @@ protected:
/// Whether this initializer list originally had a GNU array-range
/// designator in it. This is a temporary marker used by CodeGen.
unsigned HadArrayRangeDesignator : 1;
-
- /// Whether this initializer list initializes a std::initializer_list
- /// object.
- unsigned InitializesStdInitializerList : 1;
};
class TypeTraitExprBitfields {
@@ -289,7 +285,7 @@ protected:
/// \brief The number of arguments to this type trait.
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
};
-
+
union {
// FIXME: this is wasteful on 64-bit platforms.
void *Aligner;
@@ -316,19 +312,21 @@ protected:
public:
// Only allow allocation of Stmts using the allocator in ASTContext
// or by doing a placement new.
- void* operator new(size_t bytes, ASTContext& C,
- unsigned alignment = 8) throw();
+ void* operator new(size_t bytes, const ASTContext& C,
+ unsigned alignment = 8);
- void* operator new(size_t bytes, ASTContext* C,
- unsigned alignment = 8) throw();
+ void* operator new(size_t bytes, const ASTContext* C,
+ unsigned alignment = 8) {
+ return operator new(bytes, *C, alignment);
+ }
void* operator new(size_t bytes, void* mem) throw() {
return mem;
}
- void operator delete(void*, ASTContext&, unsigned) throw() { }
- void operator delete(void*, ASTContext*, unsigned) throw() { }
- void operator delete(void*, std::size_t) throw() { }
+ void operator delete(void*, const ASTContext&, unsigned) throw() { }
+ void operator delete(void*, const ASTContext*, unsigned) throw() { }
+ void operator delete(void*, size_t) throw() { }
void operator delete(void*, void*) throw() { }
public:
@@ -382,7 +380,7 @@ public:
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax.
- void dumpPretty(ASTContext &Context) const;
+ void dumpPretty(const ASTContext &Context) const;
void printPretty(raw_ostream &OS, PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0) const;
@@ -401,13 +399,6 @@ public:
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
}
- /// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
- /// contain implicit control-flow in the order their subexpressions
- /// are evaluated. This predicate returns true if this statement has
- /// such implicit control-flow. Such statements are also specially handled
- /// within CFGs.
- bool hasImplicitControlFlow() const;
-
/// Child Iterators: All subclasses must implement 'children'
/// to permit easy iteration over the substatements/subexpessions of an
/// AST node. This permits easy iteration over all nodes in the AST.
@@ -553,10 +544,10 @@ class CompoundStmt : public Stmt {
Stmt** Body;
SourceLocation LBracLoc, RBracLoc;
public:
- CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
+ CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB);
- // \brief Build an empty compound statment with a location.
+ // \brief Build an empty compound statement with a location.
explicit CompoundStmt(SourceLocation Loc)
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
CompoundStmtBits.NumStmts = 0;
@@ -568,7 +559,7 @@ public:
CompoundStmtBits.NumStmts = 0;
}
- void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
+ void setStmts(const ASTContext &C, Stmt **Stmts, unsigned NumStmts);
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
unsigned size() const { return CompoundStmtBits.NumStmts; }
@@ -827,10 +818,10 @@ class AttributedStmt : public Stmt {
}
public:
- static AttributedStmt *Create(ASTContext &C, SourceLocation Loc,
+ static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
// \brief Build an empty attributed statement.
- static AttributedStmt *CreateEmpty(ASTContext &C, unsigned NumAttrs);
+ static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs);
SourceLocation getAttrLoc() const { return AttrLoc; }
ArrayRef<const Attr*> getAttrs() const {
@@ -860,7 +851,7 @@ class IfStmt : public Stmt {
SourceLocation ElseLoc;
public:
- IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
+ IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
/// \brief Build an empty if/then/else statement
@@ -875,7 +866,7 @@ public:
/// }
/// \endcode
VarDecl *getConditionVariable() const;
- void setConditionVariable(ASTContext &C, VarDecl *V);
+ void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this IfStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
@@ -933,7 +924,7 @@ class SwitchStmt : public Stmt {
unsigned AllEnumCasesCovered : 1;
public:
- SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond);
+ SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
/// \brief Build a empty switch statement.
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
@@ -948,7 +939,7 @@ public:
/// }
/// \endcode
VarDecl *getConditionVariable() const;
- void setConditionVariable(ASTContext &C, VarDecl *V);
+ void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
@@ -967,9 +958,6 @@ public:
SwitchCase *getSwitchCaseList() { return FirstCase; }
/// \brief Set the case list for this switch statement.
- ///
- /// The caller is responsible for incrementing the retain counts on
- /// all of the SwitchCase statements in this list.
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
SourceLocation getSwitchLoc() const { return SwitchLoc; }
@@ -1021,7 +1009,7 @@ class WhileStmt : public Stmt {
Stmt* SubExprs[END_EXPR];
SourceLocation WhileLoc;
public:
- WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
+ WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL);
/// \brief Build an empty while statement.
@@ -1036,7 +1024,7 @@ public:
/// }
/// \endcode
VarDecl *getConditionVariable() const;
- void setConditionVariable(ASTContext &C, VarDecl *V);
+ void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this WhileStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
@@ -1129,8 +1117,9 @@ class ForStmt : public Stmt {
SourceLocation LParenLoc, RParenLoc;
public:
- ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
- Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP);
+ ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
+ Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
+ SourceLocation RP);
/// \brief Build an empty for statement.
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
@@ -1146,7 +1135,7 @@ public:
/// }
/// \endcode
VarDecl *getConditionVariable() const;
- void setConditionVariable(ASTContext &C, VarDecl *V);
+ void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this ForStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
@@ -1417,7 +1406,7 @@ public:
//===--- Asm String Analysis ---===//
/// Assemble final IR asm string.
- std::string generateAsmString(ASTContext &C) const;
+ std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===//
@@ -1520,7 +1509,7 @@ class GCCAsmStmt : public AsmStmt {
friend class ASTStmtReader;
public:
- GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
+ GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
bool isvolatile, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers,
@@ -1586,10 +1575,10 @@ public:
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
- ASTContext &C, unsigned &DiagOffs) const;
+ const ASTContext &C, unsigned &DiagOffs) const;
/// Assemble final IR asm string.
- std::string generateAsmString(ASTContext &C) const;
+ std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===//
@@ -1649,7 +1638,7 @@ public:
}
private:
- void setOutputsAndInputsAndClobbers(ASTContext &C,
+ void setOutputsAndInputsAndClobbers(const ASTContext &C,
IdentifierInfo **Names,
StringLiteral **Constraints,
Stmt **Exprs,
@@ -1695,9 +1684,9 @@ class MSAsmStmt : public AsmStmt {
friend class ASTStmtReader;
public:
- MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
- bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
- unsigned numoutputs, unsigned numinputs,
+ MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
+ SourceLocation lbraceloc, bool issimple, bool isvolatile,
+ ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs,
ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs, StringRef asmstr,
ArrayRef<StringRef> clobbers, SourceLocation endloc);
@@ -1720,7 +1709,7 @@ public:
StringRef getAsmString() const { return AsmStr; }
/// Assemble final IR asm string.
- std::string generateAsmString(ASTContext &C) const;
+ std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===//
@@ -1765,12 +1754,9 @@ public:
StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
private:
- void initialize(ASTContext &C,
- StringRef AsmString,
- ArrayRef<Token> AsmToks,
- ArrayRef<StringRef> Constraints,
- ArrayRef<Expr*> Exprs,
- ArrayRef<StringRef> Clobbers);
+ void initialize(const ASTContext &C, StringRef AsmString,
+ ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints,
+ ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers);
public:
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
@@ -1800,7 +1786,7 @@ class SEHExceptStmt : public Stmt {
explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { }
public:
- static SEHExceptStmt* Create(ASTContext &C,
+ static SEHExceptStmt* Create(const ASTContext &C,
SourceLocation ExceptLoc,
Expr *FilterExpr,
Stmt *Block);
@@ -1841,7 +1827,7 @@ class SEHFinallyStmt : public Stmt {
explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { }
public:
- static SEHFinallyStmt* Create(ASTContext &C,
+ static SEHFinallyStmt* Create(const ASTContext &C,
SourceLocation FinallyLoc,
Stmt *Block);
@@ -1880,10 +1866,8 @@ class SEHTryStmt : public Stmt {
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
public:
- static SEHTryStmt* Create(ASTContext &C,
- bool isCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
+ static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
+ SourceLocation TryLoc, Stmt *TryBlock,
Stmt *Handler);
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
@@ -2006,13 +1990,13 @@ private:
void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; }
public:
- static CapturedStmt *Create(ASTContext &Context, Stmt *S,
+ static CapturedStmt *Create(const ASTContext &Context, Stmt *S,
CapturedRegionKind Kind,
ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
CapturedDecl *CD, RecordDecl *RD);
- static CapturedStmt *CreateDeserialized(ASTContext &Context,
+ static CapturedStmt *CreateDeserialized(const ASTContext &Context,
unsigned NumCaptures);
/// \brief Retrieve the statement being captured.
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 0112befb293f..df98d41ad5fb 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -79,10 +79,10 @@ class CXXTryStmt : public Stmt {
}
public:
- static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc,
+ static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc,
Stmt *tryBlock, ArrayRef<Stmt*> handlers);
- static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
+ static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty,
unsigned numHandlers);
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index b933ed076260..fbc8e5d4ea71 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_STMT_ITR_H
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Compiler.h"
#include <cassert>
#include <cstddef>
#include <iterator>
@@ -28,18 +29,14 @@ class VariableArrayType;
class StmtIteratorBase {
protected:
- enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
+ enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2,
Flags = 0x3 };
Stmt **stmt;
- union { Decl *decl; Decl **DGI; };
+ Decl **DGI;
uintptr_t RawVAPtr;
Decl **DGE;
- bool inDecl() const {
- return (RawVAPtr & Flags) == DeclMode;
- }
-
bool inDeclGroup() const {
return (RawVAPtr & Flags) == DeclGroupMode;
}
@@ -49,7 +46,7 @@ protected:
}
bool inStmt() const {
- return (RawVAPtr & Flags) == 0;
+ return (RawVAPtr & Flags) == StmtMode;
}
const VariableArrayType *getVAPtr() const {
@@ -57,7 +54,7 @@ protected:
}
void setVAPtr(const VariableArrayType *P) {
- assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
+ assert (inDeclGroup() || inSizeOfTypeVA());
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
}
@@ -67,11 +64,10 @@ protected:
Stmt*& GetDeclExpr() const;
- StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {}
- StmtIteratorBase(Decl *d, Stmt **s);
+ StmtIteratorBase(Stmt **s) : stmt(s), DGI(0), RawVAPtr(0) {}
StmtIteratorBase(const VariableArrayType *t);
StmtIteratorBase(Decl **dgi, Decl **dge);
- StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {}
+ StmtIteratorBase() : stmt(0), DGI(0), RawVAPtr(0) {}
};
@@ -86,7 +82,6 @@ public:
StmtIteratorImpl() {}
StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {}
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
- StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {}
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
DERIVED& operator++() {
@@ -107,15 +102,15 @@ public:
}
bool operator==(const DERIVED& RHS) const {
- return stmt == RHS.stmt && decl == RHS.decl && RawVAPtr == RHS.RawVAPtr;
+ return stmt == RHS.stmt && DGI == RHS.DGI && RawVAPtr == RHS.RawVAPtr;
}
bool operator!=(const DERIVED& RHS) const {
- return stmt != RHS.stmt || decl != RHS.decl || RawVAPtr != RHS.RawVAPtr;
+ return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr;
}
REFERENCE operator*() const {
- return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
+ return inStmt() ? *stmt : GetDeclExpr();
}
REFERENCE operator->() const { return operator*(); }
@@ -131,9 +126,6 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
StmtIterator(const VariableArrayType *t)
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
-
- StmtIterator(Decl* D, Stmt **s = 0)
- : StmtIteratorImpl<StmtIterator,Stmt*&>(D, s) {}
};
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
@@ -156,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
bool empty() const { return first == second; }
- operator bool() const { return !empty(); }
+ LLVM_EXPLICIT operator bool() const { return !empty(); }
Stmt *operator->() const { return first.operator->(); }
Stmt *&operator*() const { return first.operator*(); }
@@ -199,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
bool empty() const { return first == second; }
- operator bool() const { return !empty(); }
+ LLVM_EXPLICIT operator bool() const { return !empty(); }
const Stmt *operator->() const { return first.operator->(); }
const Stmt *operator*() const { return first.operator*(); }
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index e97c1a5a319f..bfb4a9b0bb7a 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -181,13 +181,12 @@ private:
HasFinally(HasFinally) { }
public:
- static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc,
- Stmt *atTryStmt,
+ static ObjCAtTryStmt *Create(const ASTContext &Context,
+ SourceLocation atTryLoc, Stmt *atTryStmt,
Stmt **CatchStmts, unsigned NumCatchStmts,
Stmt *atFinallyStmt);
- static ObjCAtTryStmt *CreateEmpty(ASTContext &Context,
- unsigned NumCatchStmts,
- bool HasFinally);
+ static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context,
+ unsigned NumCatchStmts, bool HasFinally);
/// \brief Retrieve the location of the @ in the \@try.
SourceLocation getAtTryLoc() const { return AtTryLoc; }
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
new file mode 100644
index 000000000000..8570d8850a2f
--- /dev/null
+++ b/include/clang/AST/StmtOpenMP.h
@@ -0,0 +1,528 @@
+//===- StmtOpenMP.h - Classes for OpenMP directives and clauses --*- 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 defines OpenMP AST classes for executable directives and
+/// clauses.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMTOPENMP_H
+#define LLVM_CLANG_AST_STMTOPENMP_H
+
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// AST classes for clauses.
+//===----------------------------------------------------------------------===//
+
+/// \brief This is a basic class for representing single OpenMP clause.
+///
+class OMPClause {
+ /// \brief Starting location of the clause (the clause keyword).
+ SourceLocation StartLoc;
+ /// \brief Ending location of the clause.
+ SourceLocation EndLoc;
+ /// \brief Kind of the clause.
+ OpenMPClauseKind Kind;
+protected:
+ OMPClause(OpenMPClauseKind K, SourceLocation StartLoc, SourceLocation EndLoc)
+ : StartLoc(StartLoc), EndLoc(EndLoc), Kind(K) {}
+
+public:
+
+ /// \brief Returns the starting location of the clause.
+ SourceLocation getLocStart() const { return StartLoc; }
+ /// \brief Returns the ending location of the clause.
+ SourceLocation getLocEnd() const { return EndLoc; }
+
+ /// \brief Sets the starting location of the clause.
+ void setLocStart(SourceLocation Loc) { StartLoc = Loc; }
+ /// \brief Sets the ending location of the clause.
+ void setLocEnd(SourceLocation Loc) { EndLoc = Loc; }
+
+ /// \brief Returns kind of OpenMP clause (private, shared, reduction, etc.).
+ OpenMPClauseKind getClauseKind() const { return Kind; }
+
+ bool isImplicit() const { return StartLoc.isInvalid();}
+
+ StmtRange children();
+ ConstStmtRange children() const {
+ return const_cast<OMPClause *>(this)->children();
+ }
+ static bool classof(const OMPClause *T) {
+ return true;
+ }
+};
+
+/// \brief This represents clauses with the list of variables like 'private',
+/// 'firstprivate', 'copyin', 'shared', or 'reduction' clauses in the
+/// '#pragma omp ...' directives.
+template <class T>
+class OMPVarList {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Number of variables in the list.
+ unsigned NumVars;
+protected:
+ /// \brief Fetches list of variables associated with this clause.
+ llvm::MutableArrayRef<Expr *> getVarRefs() {
+ return llvm::MutableArrayRef<Expr *>(
+ reinterpret_cast<Expr **>(static_cast<T *>(this) + 1),
+ NumVars);
+ }
+
+ /// \brief Sets the list of variables for this clause.
+ void setVarRefs(ArrayRef<Expr *> VL) {
+ assert(VL.size() == NumVars &&
+ "Number of variables is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(),
+ reinterpret_cast<Expr **>(static_cast<T *>(this) + 1));
+ }
+
+ /// \brief Build clause with number of variables \a N.
+ ///
+ /// \param N Number of the variables in the clause.
+ ///
+ OMPVarList(SourceLocation LParenLoc, unsigned N)
+ : LParenLoc(LParenLoc), NumVars(N) { }
+public:
+ typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
+ typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
+
+ unsigned varlist_size() const { return NumVars; }
+ bool varlist_empty() const { return NumVars == 0; }
+ varlist_iterator varlist_begin() { return getVarRefs().begin(); }
+ varlist_iterator varlist_end() { return getVarRefs().end(); }
+ varlist_const_iterator varlist_begin() const { return getVarRefs().begin(); }
+ varlist_const_iterator varlist_end() const { return getVarRefs().end(); }
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Fetches list of all variables in the clause.
+ ArrayRef<const Expr *> getVarRefs() const {
+ return ArrayRef<const Expr *>(
+ reinterpret_cast<const Expr *const *>(static_cast<const T *>(this) + 1),
+ NumVars);
+ }
+};
+
+/// \brief This represents 'default' clause in the '#pragma omp ...' directive.
+///
+/// \code
+/// #pragma omp parallel default(shared)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has simple 'default'
+/// clause with kind 'shared'.
+///
+class OMPDefaultClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief A kind of the 'default' clause.
+ OpenMPDefaultClauseKind Kind;
+ /// \brief Start location of the kind in source code.
+ SourceLocation KindKwLoc;
+
+ /// \brief Set kind of the clauses.
+ ///
+ /// \param K Argument of clause.
+ ///
+ void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; }
+
+ /// \brief Set argument location.
+ ///
+ /// \param KLoc Argument location.
+ ///
+ void setDefaultKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; }
+public:
+ /// \brief Build 'default' clause with argument \a A ('none' or 'shared').
+ ///
+ /// \param A Argument of the clause ('none' or 'shared').
+ /// \param ALoc Starting location of the argument.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_default, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Kind(A), KindKwLoc(ALoc) { }
+
+ /// \brief Build an empty clause.
+ ///
+ OMPDefaultClause()
+ : OMPClause(OMPC_default, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), Kind(OMPC_DEFAULT_unknown),
+ KindKwLoc(SourceLocation()) { }
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Returns kind of the clause.
+ OpenMPDefaultClauseKind getDefaultKind() const { return Kind; }
+
+ /// \brief Returns location of clause kind.
+ SourceLocation getDefaultKindKwLoc() const { return KindKwLoc; }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_default;
+ }
+
+ StmtRange children() {
+ return StmtRange();
+ }
+};
+
+/// \brief This represents clause 'private' in the '#pragma omp ...' directives.
+///
+/// \code
+/// #pragma omp parallel private(a,b)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clause 'private'
+/// with the variables 'a' and 'b'.
+///
+class OMPPrivateClause : public OMPClause, public OMPVarList<OMPPrivateClause> {
+ /// \brief 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 N Number of the variables in the clause.
+ ///
+ OMPPrivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPClause(OMPC_private, StartLoc, EndLoc),
+ OMPVarList<OMPPrivateClause>(LParenLoc, N) { }
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPPrivateClause(unsigned N)
+ : OMPClause(OMPC_private, SourceLocation(), SourceLocation()),
+ OMPVarList<OMPPrivateClause>(SourceLocation(), N) { }
+public:
+ /// \brief Creates clause with a list of variables \a VL.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ ///
+ static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL);
+ /// \brief Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ StmtRange children() {
+ return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_private;
+ }
+};
+
+/// \brief This represents clause 'firstprivate' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp parallel firstprivate(a,b)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clause 'firstprivate'
+/// with the variables 'a' and 'b'.
+///
+class OMPFirstprivateClause : public OMPClause,
+ public OMPVarList<OMPFirstprivateClause> {
+ /// \brief 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 N Number of the variables in the clause.
+ ///
+ OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPClause(OMPC_firstprivate, StartLoc, EndLoc),
+ OMPVarList<OMPFirstprivateClause>(LParenLoc, N) { }
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPFirstprivateClause(unsigned N)
+ : OMPClause(OMPC_firstprivate, SourceLocation(), SourceLocation()),
+ OMPVarList<OMPFirstprivateClause>(SourceLocation(), N) { }
+public:
+ /// \brief Creates clause with a list of variables \a VL.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ ///
+ static OMPFirstprivateClause *Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL);
+ /// \brief Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ StmtRange children() {
+ return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_firstprivate;
+ }
+};
+
+/// \brief This represents clause 'shared' in the '#pragma omp ...' directives.
+///
+/// \code
+/// #pragma omp parallel shared(a,b)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clause 'shared'
+/// with the variables 'a' and 'b'.
+///
+class OMPSharedClause : public OMPClause, public OMPVarList<OMPSharedClause> {
+ /// \brief 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 N Number of the variables in the clause.
+ ///
+ OMPSharedClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPClause(OMPC_shared, StartLoc, EndLoc),
+ OMPVarList<OMPSharedClause>(LParenLoc, N) { }
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPSharedClause(unsigned N)
+ : OMPClause(OMPC_shared, SourceLocation(), SourceLocation()),
+ OMPVarList<OMPSharedClause>(SourceLocation(), N) { }
+public:
+ /// \brief Creates clause with a list of variables \a VL.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ ///
+ static OMPSharedClause *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ /// \brief Creates an empty clause with \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPSharedClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ StmtRange children() {
+ return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_shared;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// AST classes for directives.
+//===----------------------------------------------------------------------===//
+
+/// \brief This is a basic class for representing single OpenMP executable
+/// directive.
+///
+class OMPExecutableDirective : public Stmt {
+ friend class ASTStmtReader;
+ /// \brief Kind of the directive.
+ OpenMPDirectiveKind Kind;
+ /// \brief Starting location of the directive (directive keyword).
+ SourceLocation StartLoc;
+ /// \brief Ending location of the directive.
+ SourceLocation EndLoc;
+ /// \brief Pointer to the list of clauses.
+ llvm::MutableArrayRef<OMPClause *> Clauses;
+ /// \brief Associated statement (if any) and expressions.
+ llvm::MutableArrayRef<Stmt *> StmtAndExpressions;
+protected:
+ /// \brief Build instance of directive of class \a K.
+ ///
+ /// \param SC Statement class.
+ /// \param K Kind of OpenMP directive.
+ /// \param StartLoc Starting location of the directive (directive keyword).
+ /// \param EndLoc Ending location of the directive.
+ ///
+ template <typename T>
+ OMPExecutableDirective(const T *, StmtClass SC, OpenMPDirectiveKind K,
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses, unsigned NumberOfExpressions)
+ : Stmt(SC), Kind(K), StartLoc(StartLoc), EndLoc(EndLoc),
+ Clauses(reinterpret_cast<OMPClause **>(static_cast<T *>(this) + 1),
+ NumClauses),
+ StmtAndExpressions(reinterpret_cast<Stmt **>(Clauses.end()),
+ NumberOfExpressions) { }
+
+ /// \brief Sets the list of variables for this clause.
+ ///
+ /// \param Clauses The list of clauses for the directive.
+ ///
+ void setClauses(ArrayRef<OMPClause *> Clauses);
+
+ /// \brief Set the associated statement for the directive.
+ ///
+ /// /param S Associated statement.
+ ///
+ void setAssociatedStmt(Stmt *S) {
+ StmtAndExpressions[0] = S;
+ }
+
+public:
+ /// \brief Returns starting location of directive kind.
+ SourceLocation getLocStart() const { return StartLoc; }
+ /// \brief Returns ending location of directive.
+ SourceLocation getLocEnd() const { return EndLoc; }
+
+ /// \brief Set starting location of directive kind.
+ ///
+ /// \param Loc New starting location of directive.
+ ///
+ void setLocStart(SourceLocation Loc) { StartLoc = Loc; }
+ /// \brief Set ending location of directive.
+ ///
+ /// \param Loc New ending location of directive.
+ ///
+ void setLocEnd(SourceLocation Loc) { EndLoc = Loc; }
+
+ /// \brief Get number of clauses.
+ unsigned getNumClauses() const { return Clauses.size(); }
+
+ /// \brief Returns specified clause.
+ ///
+ /// \param i Number of clause.
+ ///
+ OMPClause *getClause(unsigned i) const {
+ assert(i < Clauses.size() && "index out of bound!");
+ return Clauses[i];
+ }
+
+ /// \brief Returns statement associated with the directive.
+ Stmt *getAssociatedStmt() const {
+ return StmtAndExpressions[0];
+ }
+
+ OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() >= firstOMPExecutableDirectiveConstant &&
+ S->getStmtClass() <= lastOMPExecutableDirectiveConstant;
+ }
+
+ child_range children() {
+ return child_range(StmtAndExpressions.begin(), StmtAndExpressions.end());
+ }
+
+ ArrayRef<OMPClause *> clauses() { return Clauses; }
+
+ ArrayRef<OMPClause *> clauses() const { return Clauses; }
+};
+
+/// \brief This represents '#pragma omp parallel' directive.
+///
+/// \code
+/// #pragma omp parallel private(a,b) reduction(+: c,d)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clauses 'private'
+/// with the variables 'a' and 'b' and 'reduction' with operator '+' and
+/// variables 'c' and 'd'.
+///
+class OMPParallelDirective : public OMPExecutableDirective {
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive (directive keyword).
+ /// \param EndLoc Ending Location of the directive.
+ ///
+ OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned N)
+ : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel,
+ StartLoc, EndLoc, N, 1) { }
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param N Number of clauses.
+ ///
+ explicit OMPParallelDirective(unsigned N)
+ : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel,
+ SourceLocation(), SourceLocation(), N, 1) { }
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement associated with the directive.
+ ///
+ static OMPParallelDirective *Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt);
+
+ /// \brief Creates an empty directive with the place for \a N clauses.
+ ///
+ /// \param C AST context.
+ /// \param N The number of clauses.
+ ///
+ static OMPParallelDirective *CreateEmpty(const ASTContext &C, unsigned N,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPParallelDirectiveClass;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 38c4c0220e11..c71af38b61b6 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -18,6 +18,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
namespace clang {
@@ -184,6 +185,41 @@ template<typename ImplClass, typename RetTy=void>
class ConstStmtVisitor
: public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {};
+/// \brief This class implements a simple visitor for OMPClause
+/// subclasses.
+template<class ImplClass, template <typename> class Ptr, typename RetTy>
+class OMPClauseVisitorBase {
+public:
+#define PTR(CLASS) typename Ptr<CLASS>::type
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<PTR(CLASS)>(S))
+
+#define OPENMP_CLAUSE(Name, Class) \
+ RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); }
+#include "clang/Basic/OpenMPKinds.def"
+
+ RetTy Visit(PTR(OMPClause) S) {
+ // Top switch clause: visit each OMPClause.
+ switch (S->getClauseKind()) {
+ default: llvm_unreachable("Unknown clause kind!");
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_ ## Name : return Visit ## Class(static_cast<PTR(Class)>(S));
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ }
+ // Base case, ignore it. :)
+ RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); }
+#undef PTR
+#undef DISPATCH
+};
+
+template<class ImplClass, typename RetTy = void>
+class OMPClauseVisitor :
+ public OMPClauseVisitorBase <ImplClass, make_ptr, RetTy> {};
+template<class ImplClass, typename RetTy = void>
+class ConstOMPClauseVisitor :
+ public OMPClauseVisitorBase <ImplClass, make_const_ptr, RetTy> {};
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 70b934f36c2c..6c40eb1168ce 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -60,8 +60,8 @@ public:
/// The template argument is a pack expansion of a template name that was
/// provided for a template template parameter.
TemplateExpansion,
- /// The template argument is a value- or type-dependent expression
- /// stored in an Expr*.
+ /// The template argument is a value- or type-dependent expression or a
+ /// non-dependent __uuidof expression stored in an Expr*.
Expression,
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
@@ -70,57 +70,68 @@ public:
private:
/// \brief The kind of template argument we're storing.
- unsigned Kind;
struct DA {
- ValueDecl *D;
+ unsigned Kind;
bool ForRefParam;
+ ValueDecl *D;
};
struct I {
+ unsigned Kind;
// We store a decomposed APSInt with the data allocated by ASTContext if
// BitWidth > 64. The memory may be shared between multiple
// TemplateArgument instances.
+ unsigned BitWidth : 31;
+ unsigned IsUnsigned : 1;
union {
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
const uint64_t *pVal; ///< Used to store the >64 bits integer value.
};
- unsigned BitWidth : 31;
- unsigned IsUnsigned : 1;
void *Type;
};
struct A {
- const TemplateArgument *Args;
+ unsigned Kind;
unsigned NumArgs;
+ const TemplateArgument *Args;
};
struct TA {
- void *Name;
+ unsigned Kind;
unsigned NumExpansions;
+ void *Name;
+ };
+ struct TV {
+ unsigned Kind;
+ uintptr_t V;
};
union {
struct DA DeclArg;
struct I Integer;
struct A Args;
struct TA TemplateArg;
- uintptr_t TypeOrValue;
+ struct TV TypeOrValue;
};
TemplateArgument(TemplateName, bool) LLVM_DELETED_FUNCTION;
public:
/// \brief Construct an empty, invalid template argument.
- TemplateArgument() : Kind(Null), TypeOrValue(0) { }
+ TemplateArgument() {
+ TypeOrValue.Kind = Null;
+ TypeOrValue.V = 0;
+ }
/// \brief Construct a template type argument.
- TemplateArgument(QualType T, bool isNullPtr = false)
- : Kind(isNullPtr ? NullPtr : Type) {
- TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ TemplateArgument(QualType T, bool isNullPtr = false) {
+ TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
+ TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
}
/// \brief Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
- TemplateArgument(ValueDecl *D, bool ForRefParam) : Kind(Declaration) {
+ TemplateArgument(ValueDecl *D, bool ForRefParam) {
assert(D && "Expected decl");
+ DeclArg.Kind = Declaration;
DeclArg.D = D;
DeclArg.ForRefParam = ForRefParam;
}
@@ -131,8 +142,7 @@ public:
/// \brief Construct an integral constant template argument with the same
/// value as Other but a different type.
- TemplateArgument(const TemplateArgument &Other, QualType Type)
- : Kind(Integral) {
+ TemplateArgument(const TemplateArgument &Other, QualType Type) {
Integer = Other.Integer;
Integer.Type = Type.getAsOpaquePtr();
}
@@ -145,8 +155,8 @@ public:
/// is taken.
///
/// \param Name The template name.
- TemplateArgument(TemplateName Name) : Kind(Template)
- {
+ TemplateArgument(TemplateName Name) {
+ TemplateArg.Kind = Template;
TemplateArg.Name = Name.getAsVoidPointer();
TemplateArg.NumExpansions = 0;
}
@@ -162,9 +172,8 @@ public:
///
/// \param NumExpansions The number of expansions that will be generated by
/// instantiating
- TemplateArgument(TemplateName Name, Optional<unsigned> NumExpansions)
- : Kind(TemplateExpansion)
- {
+ TemplateArgument(TemplateName Name, Optional<unsigned> NumExpansions) {
+ TemplateArg.Kind = TemplateExpansion;
TemplateArg.Name = Name.getAsVoidPointer();
if (NumExpansions)
TemplateArg.NumExpansions = *NumExpansions + 1;
@@ -177,15 +186,17 @@ public:
/// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list.
- TemplateArgument(Expr *E) : Kind(Expression) {
- TypeOrValue = reinterpret_cast<uintptr_t>(E);
+ TemplateArgument(Expr *E) {
+ TypeOrValue.Kind = Expression;
+ TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
}
/// \brief Construct a template argument that is a template argument pack.
///
/// We assume that storage for the template arguments provided
/// outlives the TemplateArgument itself.
- TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){
+ TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) {
+ this->Args.Kind = Pack;
this->Args.Args = Args;
this->Args.NumArgs = NumArgs;
}
@@ -201,10 +212,10 @@ public:
unsigned NumArgs);
/// \brief Return the kind of stored template argument.
- ArgKind getKind() const { return (ArgKind)Kind; }
+ ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
/// \brief Determine whether this template argument has no value.
- bool isNull() const { return Kind == Null; }
+ bool isNull() const { return getKind() == Null; }
/// \brief Whether this template argument is dependent on a template
/// parameter such that its result can change from one instantiation to
@@ -224,40 +235,40 @@ public:
/// \brief Retrieve the type for a type template argument.
QualType getAsType() const {
- assert(Kind == Type && "Unexpected kind");
- return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
+ assert(getKind() == Type && "Unexpected kind");
+ return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
}
/// \brief Retrieve the declaration for a declaration non-type
/// template argument.
ValueDecl *getAsDecl() const {
- assert(Kind == Declaration && "Unexpected kind");
+ assert(getKind() == Declaration && "Unexpected kind");
return DeclArg.D;
}
/// \brief Retrieve whether a declaration is binding to a
/// reference parameter in a declaration non-type template argument.
bool isDeclForReferenceParam() const {
- assert(Kind == Declaration && "Unexpected kind");
+ assert(getKind() == Declaration && "Unexpected kind");
return DeclArg.ForRefParam;
}
/// \brief Retrieve the type for null non-type template argument.
QualType getNullPtrType() const {
- assert(Kind == NullPtr && "Unexpected kind");
- return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
+ assert(getKind() == NullPtr && "Unexpected kind");
+ return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
}
/// \brief Retrieve the template name for a template name argument.
TemplateName getAsTemplate() const {
- assert(Kind == Template && "Unexpected kind");
+ assert(getKind() == Template && "Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
/// \brief Retrieve the template argument as a template name; if the argument
/// is a pack expansion, return the pattern as a template name.
TemplateName getAsTemplateOrTemplatePattern() const {
- assert((Kind == Template || Kind == TemplateExpansion) &&
+ assert((getKind() == Template || getKind() == TemplateExpansion) &&
"Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name);
@@ -270,7 +281,7 @@ public:
/// \brief Retrieve the template argument as an integral value.
// FIXME: Provide a way to read the integral data without copying the value.
llvm::APSInt getAsIntegral() const {
- assert(Kind == Integral && "Unexpected kind");
+ assert(getKind() == Integral && "Unexpected kind");
using namespace llvm;
if (Integer.BitWidth <= 64)
return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
@@ -282,19 +293,19 @@ public:
/// \brief Retrieve the type of the integral value.
QualType getIntegralType() const {
- assert(Kind == Integral && "Unexpected kind");
+ assert(getKind() == Integral && "Unexpected kind");
return QualType::getFromOpaquePtr(Integer.Type);
}
void setIntegralType(QualType T) {
- assert(Kind == Integral && "Unexpected kind");
+ assert(getKind() == Integral && "Unexpected kind");
Integer.Type = T.getAsOpaquePtr();
}
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
- assert(Kind == Expression && "Unexpected kind");
- return reinterpret_cast<Expr *>(TypeOrValue);
+ assert(getKind() == Expression && "Unexpected kind");
+ return reinterpret_cast<Expr *>(TypeOrValue.V);
}
/// \brief Iterator that traverses the elements of a template argument pack.
@@ -303,27 +314,27 @@ public:
/// \brief Iterator referencing the first argument of a template argument
/// pack.
pack_iterator pack_begin() const {
- assert(Kind == Pack);
+ assert(getKind() == Pack);
return Args.Args;
}
/// \brief Iterator referencing one past the last argument of a template
/// argument pack.
pack_iterator pack_end() const {
- assert(Kind == Pack);
+ assert(getKind() == Pack);
return Args.Args + Args.NumArgs;
}
/// \brief The number of template arguments in the given template argument
/// pack.
unsigned pack_size() const {
- assert(Kind == Pack);
+ assert(getKind() == Pack);
return Args.NumArgs;
}
/// \brief Return the array of arguments in this template argument pack.
llvm::ArrayRef<TemplateArgument> getPackAsArray() const {
- assert(Kind == Pack);
+ assert(getKind() == Pack);
return llvm::ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs);
}
@@ -494,17 +505,6 @@ public:
assert(Argument.getKind() == TemplateArgument::TemplateExpansion);
return LocInfo.getTemplateEllipsisLoc();
}
-
- /// \brief When the template argument is a pack expansion, returns
- /// the pattern of the pack expansion.
- ///
- /// \param Ellipsis Will be set to the location of the ellipsis.
- ///
- /// \param NumExpansions Will be set to the number of expansions that will
- /// be generated from this pack expansion, if known a priori.
- TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis,
- Optional<unsigned> &NumExpansions,
- ASTContext &Context) const;
};
/// A convenient class for passing around template argument
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 39f10d3393ba..fb829e4d4103 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -441,7 +441,7 @@ public:
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
- operator bool() const { return hasQualifiers(); }
+ LLVM_EXPLICIT operator bool() const { return hasQualifiers(); }
Qualifiers &operator+=(Qualifiers R) {
addQualifiers(R);
@@ -818,7 +818,7 @@ public:
/// an lvalue. It removes a top-level reference (since there are no
/// expressions of reference type) and deletes top-level cvr-qualifiers
/// from non-class types (in C++) or all types (in C).
- QualType getNonLValueExprType(ASTContext &Context) const;
+ QualType getNonLValueExprType(const ASTContext &Context) const;
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
@@ -1194,7 +1194,7 @@ private:
mutable unsigned CacheValid : 1;
/// \brief Linkage of this type.
- mutable unsigned CachedLinkage : 2;
+ mutable unsigned CachedLinkage : 3;
/// \brief Whether this type involves and local or unnamed types.
mutable unsigned CachedLocalOrUnnamed : 1;
@@ -1214,7 +1214,7 @@ private:
return CachedLocalOrUnnamed;
}
};
- enum { NumTypeBits = 19 };
+ enum { NumTypeBits = 18 };
protected:
// These classes allow subclasses to somewhat cleanly pack bitfields
@@ -1315,6 +1315,8 @@ protected:
/// NumElements - The number of elements in the vector.
unsigned NumElements : 29 - NumTypeBits;
+
+ enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 };
};
class AttributedTypeBitfields {
@@ -1454,7 +1456,7 @@ public:
/// isLiteralType - Return true if this is a literal type
/// (C++11 [basic.types]p10)
- bool isLiteralType(ASTContext &Ctx) const;
+ bool isLiteralType(const ASTContext &Ctx) const;
/// \brief Test if this type is a standard-layout type.
/// (C++0x [basic.type]p9)
@@ -1512,7 +1514,6 @@ public:
bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
bool isVoidType() const; // C99 6.2.5p19
- bool isDerivedType() const; // C99 6.2.5p20
bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
bool isAggregateType() const;
bool isFundamentalType() const;
@@ -1811,6 +1812,10 @@ template <> const TypedefType *Type::getAs() const;
/// non-sugared type.
template <> const TemplateSpecializationType *Type::getAs() const;
+/// \brief This will check for an AttributedType by removing any existing sugar
+/// until it reaches an AttributedType or a non-sugared type.
+template <> const AttributedType *Type::getAs() const;
+
// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
#define TYPE(Class, Base)
@@ -1991,6 +1996,44 @@ public:
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
};
+/// \brief Represents a pointer type decayed from an array or function type.
+class DecayedType : public Type, public llvm::FoldingSetNode {
+ QualType OriginalType;
+ QualType DecayedPointer;
+
+ DecayedType(QualType OriginalType, QualType DecayedPointer,
+ QualType CanonicalPtr)
+ : Type(Decayed, CanonicalPtr, OriginalType->isDependentType(),
+ OriginalType->isInstantiationDependentType(),
+ OriginalType->isVariablyModifiedType(),
+ OriginalType->containsUnexpandedParameterPack()),
+ OriginalType(OriginalType), DecayedPointer(DecayedPointer) {
+ assert(isa<PointerType>(DecayedPointer));
+ }
+
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+ QualType getDecayedType() const { return DecayedPointer; }
+ QualType getOriginalType() const { return OriginalType; }
+
+ QualType getPointeeType() const {
+ return cast<PointerType>(DecayedPointer)->getPointeeType();
+ }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return DecayedPointer; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, OriginalType);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType OriginalType) {
+ ID.AddPointer(OriginalType.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Decayed; }
+};
+
/// BlockPointerType - pointer to a block type.
/// This type is to represent types syntactically represented as
/// "void (^)(int)", etc. Pointee is required to always be a function type.
@@ -2487,6 +2530,9 @@ public:
QualType getElementType() const { return ElementType; }
unsigned getNumElements() const { return VectorTypeBits.NumElements; }
+ static bool isVectorSizeTooLarge(unsigned NumElements) {
+ return NumElements > VectorTypeBitfields::MaxNumElements;
+ }
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -2641,7 +2687,11 @@ class FunctionType : public Type {
// Constructor with all defaults. Use when for example creating a
// function know to use defaults.
- ExtInfo() : Bits(0) {}
+ ExtInfo() : Bits(CC_C) { }
+
+ // Constructor with just the calling convention, which is an important part
+ // of the canonical type.
+ ExtInfo(CallingConv CC) : Bits(CC) { }
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
@@ -2784,6 +2834,12 @@ public:
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
ConsumedArguments(0) {}
+ ExtProtoInfo(CallingConv CC)
+ : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
+ ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
+ Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
+ ExceptionSpecTemplate(0), ConsumedArguments(0) {}
+
FunctionType::ExtInfo ExtInfo;
bool Variadic : 1;
bool HasTrailingReturn : 1;
@@ -2928,7 +2984,7 @@ public:
NR_Nothrow ///< The noexcept specifier evaluates to true.
};
/// \brief Get the meaning of the noexcept spec on this function, if any.
- NoexceptResult getNoexceptSpec(ASTContext &Ctx) const;
+ NoexceptResult getNoexceptSpec(const ASTContext &Ctx) const;
unsigned getNumExceptions() const { return NumExceptions; }
QualType getExceptionType(unsigned i) const {
assert(i < NumExceptions && "Invalid exception number!");
@@ -2959,7 +3015,7 @@ public:
return 0;
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];
}
- bool isNothrow(ASTContext &Ctx) const {
+ bool isNothrow(const ASTContext &Ctx) const {
ExceptionSpecificationType EST = getExceptionSpecType();
assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
@@ -3323,9 +3379,10 @@ public:
attr_objc_gc,
attr_objc_ownership,
attr_pcs,
+ attr_pcs_vfp,
FirstEnumOperandKind = attr_objc_gc,
- LastEnumOperandKind = attr_pcs,
+ LastEnumOperandKind = attr_pcs_vfp,
// No operand.
attr_noreturn,
@@ -3335,7 +3392,13 @@ public:
attr_thiscall,
attr_pascal,
attr_pnaclcall,
- attr_inteloclbicc
+ attr_inteloclbicc,
+ attr_ms_abi,
+ attr_sysv_abi,
+ attr_ptr32,
+ attr_ptr64,
+ attr_sptr,
+ attr_uptr
};
private:
@@ -3365,6 +3428,10 @@ public:
bool isSugared() const { return true; }
QualType desugar() const { return getEquivalentType(); }
+ bool isMSTypeSpec() const;
+
+ bool isCallingConv() const;
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
}
@@ -3563,10 +3630,13 @@ public:
/// is no deduced type and an auto type is canonical. In the latter case, it is
/// also a dependent type.
class AutoType : public Type, public llvm::FoldingSetNode {
- AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent)
+ AutoType(QualType DeducedType, bool IsDecltypeAuto,
+ bool IsDependent)
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
- /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
+ /*VariablyModified=*/false,
+ /*ContainsParameterPack=*/DeducedType.isNull()
+ ? false : DeducedType->containsUnexpandedParameterPack()) {
assert((DeducedType.isNull() || !IsDependent) &&
"auto deduced to dependent type");
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
@@ -3590,7 +3660,8 @@ public:
}
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDeducedType(), isDecltypeAuto(), isDependentType());
+ Profile(ID, getDeducedType(), isDecltypeAuto(),
+ isDependentType());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
@@ -3654,10 +3725,6 @@ class TemplateSpecializationType
public:
/// \brief Determine whether any of the given template arguments are
/// dependent.
- static bool anyDependentTemplateArguments(const TemplateArgument *Args,
- unsigned NumArgs,
- bool &InstantiationDependent);
-
static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args,
unsigned NumArgs,
bool &InstantiationDependent);
@@ -4154,8 +4221,8 @@ public:
return None;
}
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
+ bool isSugared() const { return !Pattern->isDependentType(); }
+ QualType desugar() const { return isSugared() ? Pattern : QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getPattern(), getNumExpansions());
@@ -4189,11 +4256,11 @@ public:
///
/// 'C<P>' is an ObjCObjectType with base C and protocol list [P].
///
-/// 'id' is a TypedefType which is sugar for an ObjCPointerType whose
+/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
/// and no protocols.
///
-/// 'id<P>' is an ObjCPointerType whose pointee is an ObjCObjecType
+/// 'id<P>' is an ObjCObjectPointerType whose pointee is an ObjCObjectType
/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually
/// this should get its own sugar class to better represent the source.
class ObjCObjectType : public Type {
@@ -4231,7 +4298,7 @@ public:
/// getBaseType - Gets the base type of this object type. This is
/// always (possibly sugar for) one of:
/// - the 'id' builtin type (as opposed to the 'id' type visible to the
- /// user, which is a typedef for an ObjCPointerType)
+ /// user, which is a typedef for an ObjCObjectPointerType)
/// - the 'Class' builtin type (same caveat)
/// - an ObjCObjectType (currently always an ObjCInterfaceType)
QualType getBaseType() const { return BaseType; }
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 11cad9bb9dd9..8ddfac7ad373 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the TypeLoc interface and subclasses.
-//
+///
+/// \file
+/// \brief Defines the clang::TypeLoc interface and its subclasses.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_TYPELOC_H
@@ -34,8 +35,8 @@ namespace clang {
/// \brief Base wrapper for a particular "section" of type source info.
///
-/// A client should use the TypeLoc subclasses through cast/dyn_cast in order to
-/// get at the actual information.
+/// A client should use the TypeLoc subclasses through castAs()/getAs()
+/// in order to get at the actual information.
class TypeLoc {
protected:
// The correctness of this relies on the property that, for Type *Ty,
@@ -46,6 +47,8 @@ protected:
public:
/// \brief Convert to the specified TypeLoc type, asserting that this TypeLoc
/// is of the desired type.
+ ///
+ /// \pre T::isKind(*this)
template<typename T>
T castAs() const {
assert(T::isKind(*this));
@@ -90,11 +93,15 @@ public:
}
bool isNull() const { return !Ty; }
- operator bool() const { return Ty; }
+ LLVM_EXPLICIT operator bool() const { return Ty; }
/// \brief Returns the size of type source info data block for the given type.
static unsigned getFullDataSizeForType(QualType Ty);
+ /// \brief Returns the alignment of type source info data block for
+ /// the given type.
+ static unsigned getLocalAlignmentForType(QualType Ty);
+
/// \brief Get the type for which this source info wrapper provides
/// information.
QualType getType() const {
@@ -229,7 +236,11 @@ public:
}
UnqualTypeLoc getUnqualifiedLoc() const {
- return UnqualTypeLoc(getTypePtr(), Data);
+ unsigned align =
+ TypeLoc::getLocalAlignmentForType(QualType(getTypePtr(), 0));
+ uintptr_t dataInt = reinterpret_cast<uintptr_t>(Data);
+ dataInt = llvm::RoundUpToAlignment(dataInt, align);
+ return UnqualTypeLoc(getTypePtr(), reinterpret_cast<void*>(dataInt));
}
/// Initializes the local data of this type source info block to
@@ -250,10 +261,11 @@ public:
return 0;
}
- /// \brief Returns the size of the type source info data block.
- unsigned getFullDataSize() const {
- return getLocalDataSize() +
- getFullDataSizeForType(getType().getLocalUnqualifiedType());
+ /// \brief Returns the alignment of the type source info data block that is
+ /// specific to this type.
+ unsigned getLocalDataAlignment() const {
+ // We don't preserve any location information.
+ return 1;
}
private:
@@ -280,9 +292,6 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
/// \tparam LocalData the structure type of local location data for
/// this type
///
-/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or
-/// else the world will end.
-///
/// TypeLocs with non-constant amounts of local data should override
/// getExtraLocalDataSize(); getExtraLocalData() will then point to
/// this extra memory.
@@ -309,7 +318,8 @@ class ConcreteTypeLoc : public Base {
friend class TypeLoc;
static bool isKind(const TypeLoc &TL) {
- return Derived::classofType(TL.getTypePtr());
+ return !TL.getType().hasLocalQualifiers() &&
+ Derived::classofType(TL.getTypePtr());
}
static bool classofType(const Type *Ty) {
@@ -317,12 +327,16 @@ class ConcreteTypeLoc : public Base {
}
public:
- unsigned getLocalDataSize() const {
- return sizeof(LocalData) + asDerived()->getExtraLocalDataSize();
+ unsigned getLocalDataAlignment() const {
+ return std::max(llvm::alignOf<LocalData>(),
+ asDerived()->getExtraLocalDataAlignment());
}
- // Give a default implementation that's useful for leaf types.
- unsigned getFullDataSize() const {
- return asDerived()->getLocalDataSize() + getInnerTypeSize();
+ unsigned getLocalDataSize() const {
+ unsigned size = sizeof(LocalData);
+ unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
+ size = llvm::RoundUpToAlignment(size, extraAlign);
+ size += asDerived()->getExtraLocalDataSize();
+ return size;
}
TypeLoc getNextTypeLoc() const {
@@ -338,6 +352,10 @@ protected:
return 0;
}
+ unsigned getExtraLocalDataAlignment() const {
+ return 1;
+ }
+
LocalData *getLocalData() const {
return static_cast<LocalData*>(Base::Data);
}
@@ -346,11 +364,17 @@ protected:
/// local data that can't be captured in the Info (e.g. because it's
/// of variable size).
void *getExtraLocalData() const {
- return getLocalData() + 1;
+ unsigned size = sizeof(LocalData);
+ unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
+ size = llvm::RoundUpToAlignment(size, extraAlign);
+ return reinterpret_cast<char*>(Base::Data) + size;
}
void *getNonLocalData() const {
- return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize();
+ uintptr_t data = reinterpret_cast<uintptr_t>(Base::Data);
+ data += asDerived()->getLocalDataSize();
+ data = llvm::RoundUpToAlignment(data, getNextTypeAlign());
+ return reinterpret_cast<void*>(data);
}
struct HasNoInnerType {};
@@ -373,6 +397,18 @@ private:
return getInnerTypeLoc().getFullDataSize();
}
+ unsigned getNextTypeAlign() const {
+ return getNextTypeAlign(asDerived()->getInnerType());
+ }
+
+ unsigned getNextTypeAlign(HasNoInnerType _) const {
+ return 1;
+ }
+
+ unsigned getNextTypeAlign(QualType T) const {
+ return TypeLoc::getLocalAlignmentForType(T);
+ }
+
TypeLoc getNextTypeLoc(HasNoInnerType _) const {
return TypeLoc();
}
@@ -393,7 +429,8 @@ class InheritingConcreteTypeLoc : public Base {
}
static bool isKind(const TypeLoc &TL) {
- return Derived::classofType(TL.getTypePtr());
+ return !TL.getType().hasLocalQualifiers() &&
+ Derived::classofType(TL.getTypePtr());
}
static bool isKind(const UnqualTypeLoc &TL) {
return Derived::classofType(TL.getTypePtr());
@@ -417,7 +454,8 @@ class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
Type,
TypeSpecLocInfo> {
public:
- enum { LocalDataSize = sizeof(TypeSpecLocInfo) };
+ enum { LocalDataSize = sizeof(TypeSpecLocInfo),
+ LocalDataAlignment = llvm::AlignOf<TypeSpecLocInfo>::Alignment };
SourceLocation getNameLoc() const {
return this->getLocalData()->NameLoc;
@@ -448,8 +486,6 @@ class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
BuiltinType,
BuiltinLocInfo> {
public:
- enum { LocalDataSize = sizeof(BuiltinLocInfo) };
-
SourceLocation getBuiltinLoc() const {
return getLocalData()->BuiltinLoc;
}
@@ -478,6 +514,10 @@ public:
return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0;
}
+ unsigned getExtraLocalDataAlignment() const {
+ return needsExtraLocalData() ? llvm::alignOf<WrittenBuiltinSpecs>() : 1;
+ }
+
SourceRange getLocalSourceRange() const {
return SourceRange(getBuiltinLoc(), getBuiltinLoc());
}
@@ -840,6 +880,10 @@ public:
return this->getNumProtocols() * sizeof(SourceLocation);
}
+ unsigned getExtraLocalDataAlignment() const {
+ return llvm::alignOf<SourceLocation>();
+ }
+
QualType getInnerType() const {
return getTypePtr()->getBaseType();
}
@@ -933,6 +977,40 @@ inline TypeLoc TypeLoc::IgnoreParens() const {
return *this;
}
+
+struct DecayedLocInfo { }; // Nothing.
+
+/// \brief Wrapper for source info for pointers decayed from arrays and
+/// functions.
+class DecayedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, DecayedTypeLoc,
+ DecayedType, DecayedLocInfo> {
+public:
+ TypeLoc getOriginalLoc() const {
+ return getInnerTypeLoc();
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ // do nothing
+ }
+
+ QualType getInnerType() const {
+ // The inner type is the undecayed type, since that's what we have source
+ // location information for.
+ return getTypePtr()->getOriginalType();
+ }
+
+ SourceRange getLocalSourceRange() const {
+ return SourceRange();
+ }
+
+ unsigned getLocalDataSize() const {
+ // sizeof(DecayedLocInfo) is 1, but we don't need its address to be unique
+ // anyway. TypeLocBuilder can't handle data sizes of 1.
+ return 0; // No data.
+ }
+};
+
+
struct PointerLikeLocInfo {
SourceLocation StarLoc;
};
@@ -1166,6 +1244,10 @@ public:
return getNumArgs() * sizeof(ParmVarDecl*);
}
+ unsigned getExtraLocalDataAlignment() const {
+ return llvm::alignOf<ParmVarDecl*>();
+ }
+
QualType getInnerType() const { return getTypePtr()->getResultType(); }
};
@@ -1357,6 +1439,10 @@ public:
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
}
+ unsigned getExtraLocalDataAlignment() const {
+ return llvm::alignOf<TemplateArgumentLocInfo>();
+ }
+
private:
TemplateArgumentLocInfo *getArgInfos() const {
return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
@@ -1761,6 +1847,10 @@ public:
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
}
+ unsigned getExtraLocalDataAlignment() const {
+ return llvm::alignOf<TemplateArgumentLocInfo>();
+ }
+
private:
TemplateArgumentLocInfo *getArgInfos() const {
return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 840e07d94a0d..3126f48c644a 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -81,6 +81,7 @@ TYPE(FunctionNoProto, FunctionType)
DEPENDENT_TYPE(UnresolvedUsing, Type)
NON_CANONICAL_TYPE(Paren, Type)
NON_CANONICAL_TYPE(Typedef, Type)
+NON_CANONICAL_TYPE(Decayed, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
@@ -98,7 +99,7 @@ TYPE(Auto, Type)
DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
-DEPENDENT_TYPE(PackExpansion, Type)
+NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type)
TYPE(ObjCObject, Type)
TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 59b59f517168..9c9f15e95323 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -6,11 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file provides a function objects and specializations that
-// allow QualType values to be sorted, used in std::maps, std::sets,
-// llvm::DenseMaps, and llvm::DenseSets.
-//
+///
+/// \file
+/// \brief Allows QualTypes to be sorted and hence used in maps and sets.
+///
+/// Defines clang::QualTypeOrdering, a total ordering on clang::QualType,
+/// and hence enables QualType values to be sorted and to be used in
+/// std::maps, std::sets, llvm::DenseMaps, and llvm::DenseSets.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TYPE_ORDERING_H
@@ -22,8 +25,7 @@
namespace clang {
-/// QualTypeOrdering - Function object that provides a total ordering
-/// on QualType values.
+/// \brief Function object that provides a total ordering on QualType values.
struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
bool operator()(QualType T1, QualType T2) const {
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index 242aa586d510..11e5a47f1f29 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -22,9 +22,50 @@ namespace clang {
return static_cast<ImplClass*>(this)-> \
Visit##CLASS(static_cast<const CLASS*>(T))
+/// \brief An operation on a type.
+///
+/// \tparam ImplClass Class implementing the operation. Must be inherited from
+/// TypeVisitor.
+/// \tparam RetTy %Type of result produced by the operation.
+///
+/// The class implements polymorphic operation on an object of type derived
+/// from Type. The operation is performed by calling method Visit. It then
+/// dispatches the call to function \c VisitFooType, if actual argument type
+/// is \c FooType.
+///
+/// The class implements static polymorphism using Curiously Recurring
+/// Template Pattern. It is designed to be a base class for some concrete
+/// class:
+///
+/// \code
+/// class SomeVisitor : public TypeVisitor<SomeVisitor,sometype> { ... };
+/// ...
+/// Type *atype = ...
+/// ...
+/// SomeVisitor avisitor;
+/// sometype result = avisitor.Visit(atype);
+/// \endcode
+///
+/// Actual treatment is made by methods of the derived class, TypeVisitor only
+/// dispatches call to the appropriate method. If the implementation class
+/// \c ImplClass provides specific action for some type, say
+/// \c ConstantArrayType, it should define method
+/// <tt>VisitConstantArrayType(const ConstantArrayType*)</tt>. Otherwise
+/// \c TypeVisitor dispatches call to the method that handles parent type. In
+/// this example handlers are tried in the sequence:
+///
+/// \li <tt>ImplClass::VisitConstantArrayType(const ConstantArrayType*)</tt>
+/// \li <tt>ImplClass::VisitArrayType(const ArrayType*)</tt>
+/// \li <tt>ImplClass::VisitType(const Type*)</tt>
+/// \li <tt>TypeVisitor::VisitType(const Type*)</tt>
+///
+/// The first function of this sequence that is defined will handle object of
+/// type \c ConstantArrayType.
template<typename ImplClass, typename RetTy=void>
class TypeVisitor {
public:
+
+ /// \brief Performs the operation associated with this visitor object.
RetTy Visit(const Type *T) {
// Top switch stmt: dispatch to VisitFooType for each FooType.
switch (T->getTypeClass()) {
@@ -42,7 +83,8 @@ public:
}
#include "clang/AST/TypeNodes.def"
- // Base case, ignore it. :)
+ /// \brief Method called if \c ImpClass doesn't provide specific handler
+ /// for some type class.
RetTy VisitType(const Type*) { return RetTy(); }
};
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index d26065e3745b..759af2537f75 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -51,6 +51,7 @@ public:
typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category;
NamedDecl *getDecl() const { return ir->getDecl(); }
+ void setDecl(NamedDecl *ND) const { return ir->setDecl(ND); }
AccessSpecifier getAccess() const { return ir->getAccess(); }
void setAccess(AccessSpecifier AS) { ir->setAccess(AS); }
DeclAccessPair getPair() const { return *ir; }
@@ -88,7 +89,7 @@ public:
bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; }
};
-/// UnresolvedSet - A set of unresolved declarations.
+/// \brief A set of unresolved declarations.
class UnresolvedSetImpl {
typedef SmallVectorImpl<DeclAccessPair> DeclsTy;
@@ -139,15 +140,9 @@ public:
I.ir->set(New, AS);
}
- void erase(unsigned I) {
- decls()[I] = decls().back();
- decls().pop_back();
- }
+ void erase(unsigned I) { decls()[I] = decls().pop_back_val(); }
- void erase(iterator I) {
- *I.ir = decls().back();
- decls().pop_back();
- }
+ void erase(iterator I) { *I.ir = decls().pop_back_val(); }
void setAccess(iterator I, AccessSpecifier AS) {
I.ir->setAccess(AS);
@@ -177,7 +172,7 @@ private:
}
};
-/// A set of unresolved declarations
+/// \brief A set of unresolved declarations.
template <unsigned InlineCapacity> class UnresolvedSet :
public UnresolvedSetImpl {
SmallVector<DeclAccessPair, InlineCapacity> Decls;
diff --git a/include/clang/AST/VTTBuilder.h b/include/clang/AST/VTTBuilder.h
index f24bb3f16b86..727bf5109ad4 100644
--- a/include/clang/AST/VTTBuilder.h
+++ b/include/clang/AST/VTTBuilder.h
@@ -63,54 +63,50 @@ struct VTTComponent {
: VTableIndex(VTableIndex), VTableBase(VTableBase) {}
};
-/// VTT builder - Class for building VTT layout information.
+/// \brief Class for building VTT layout information.
class VTTBuilder {
ASTContext &Ctx;
- /// MostDerivedClass - The most derived class for which we're building this
- /// vtable.
+ /// \brief The most derived class for which we're building this vtable.
const CXXRecordDecl *MostDerivedClass;
typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy;
- /// VTTVTables - The VTT vtables.
+ /// \brief The VTT vtables.
VTTVTablesVectorTy VTTVTables;
typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy;
- /// VTTComponents - The VTT components.
+ /// \brief The VTT components.
VTTComponentsVectorTy VTTComponents;
- /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ /// \brief The AST record layout of the most derived class.
const ASTRecordLayout &MostDerivedClassLayout;
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
- /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
- /// class.
+ /// \brief The sub-VTT indices for the bases of the most derived class.
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
- /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
- /// all subobjects of the most derived class.
+ /// \brief The secondary virtual pointer indices of all subobjects of
+ /// the most derived class.
llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
- /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
- /// the VTT.
+ /// \brief Whether the VTT builder should generate LLVM IR for the VTT.
bool GenerateDefinition;
- /// AddVTablePointer - Add a vtable pointer to the VTT currently being built.
+ /// \brief Add a vtable pointer to the VTT currently being built.
void AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
const CXXRecordDecl *VTableClass);
- /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
- /// subobject.
+ /// \brief Lay out the secondary VTTs of the given base subobject.
void LayoutSecondaryVTTs(BaseSubobject Base);
- /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
- /// for the given base subobject.
+ /// \brief Lay out the secondary virtual pointers for the given base
+ /// subobject.
///
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
/// or a direct or indirect base of a virtual base.
@@ -120,17 +116,17 @@ class VTTBuilder {
const CXXRecordDecl *VTableClass,
VisitedVirtualBasesSetTy &VBases);
- /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
- /// for the given base subobject.
+ /// \brief Lay out the secondary virtual pointers for the given base
+ /// subobject.
void LayoutSecondaryVirtualPointers(BaseSubobject Base,
uint64_t VTableIndex);
- /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
- /// given record decl.
+ /// \brief Lay out the VTTs for the virtual base classes of the given
+ /// record declaration.
void LayoutVirtualVTTs(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases);
- /// LayoutVTT - Will lay out the VTT for the given subobject, including any
+ /// \brief Lay out the VTT for the given subobject, including any
/// secondary VTTs, secondary virtual pointers and virtual VTTs.
void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
@@ -138,23 +134,22 @@ public:
VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass,
bool GenerateDefinition);
- // getVTTComponents - Returns a reference to the VTT components.
+ // \brief Returns a reference to the VTT components.
const VTTComponentsVectorTy &getVTTComponents() const {
return VTTComponents;
}
- // getVTTVTables - Returns a reference to the VTT vtables.
+ // \brief Returns a reference to the VTT vtables.
const VTTVTablesVectorTy &getVTTVTables() const {
return VTTVTables;
}
- /// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
+ /// \brief Returns a reference to the sub-VTT indices.
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
}
- /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
- /// virtual pointer indices.
+ /// \brief Returns a reference to the secondary virtual pointer indices.
const llvm::DenseMap<BaseSubobject, uint64_t> &
getSecondaryVirtualPointerIndices() const {
return SecondaryVirtualPointerIndices;
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index bcbe8754ea4a..4e451324d734 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -20,12 +20,13 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/ABI.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/DenseSet.h"
#include <utility>
namespace clang {
class CXXRecordDecl;
-/// VTableComponent - Represents a single component in a vtable.
+/// \brief Represents a single component in a vtable.
class VTableComponent {
public:
enum Kind {
@@ -35,15 +36,17 @@ public:
CK_RTTI,
CK_FunctionPointer,
- /// CK_CompleteDtorPointer - A pointer to the complete destructor.
+ /// \brief A pointer to the complete destructor.
CK_CompleteDtorPointer,
- /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
+ /// \brief A pointer to the deleting destructor.
CK_DeletingDtorPointer,
- /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
- /// will end up never being called. Such vtable function pointers are
- /// represented as a CK_UnusedFunctionPointer.
+ /// \brief An entry that is never used.
+ ///
+ /// In some cases, a vtable function pointer will end up never being
+ /// called. Such vtable function pointers are represented as a
+ /// CK_UnusedFunctionPointer.
CK_UnusedFunctionPointer
};
@@ -94,7 +97,7 @@ public:
return VTableComponent(I);
}
- /// getKind - Get the kind of this vtable component.
+ /// \brief Get the kind of this vtable component.
Kind getKind() const {
return (Kind)(Value & 0x7);
}
@@ -189,7 +192,7 @@ private:
/// The kind is stored in the lower 3 bits of the value. For offsets, we
/// make use of the facts that classes can't be larger than 2^55 bytes,
- /// so we store the offset in the lower part of the 61 bytes that remain.
+ /// so we store the offset in the lower part of the 61 bits that remain.
/// (The reason that we're not simply using a PointerIntPair here is that we
/// need the offsets to be 64-bit, even when on a 32-bit machine).
int64_t Value;
@@ -198,7 +201,6 @@ private:
class VTableLayout {
public:
typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
- typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
typedef const VTableComponent *vtable_component_iterator;
typedef const VTableThunkTy *vtable_thunk_iterator;
@@ -208,11 +210,11 @@ private:
uint64_t NumVTableComponents;
llvm::OwningArrayPtr<VTableComponent> VTableComponents;
- /// VTableThunks - Contains thunks needed by vtables.
+ /// \brief Contains thunks needed by vtables, sorted by indices.
uint64_t NumVTableThunks;
llvm::OwningArrayPtr<VTableThunkTy> VTableThunks;
- /// Address points - Address points for all vtables.
+ /// \brief Address points for all vtables.
AddressPointsMapTy AddressPoints;
bool IsMicrosoftABI;
@@ -231,23 +233,21 @@ public:
}
vtable_component_iterator vtable_component_begin() const {
- return VTableComponents.get();
+ return VTableComponents.get();
}
vtable_component_iterator vtable_component_end() const {
- return VTableComponents.get()+NumVTableComponents;
+ return VTableComponents.get() + NumVTableComponents;
}
- uint64_t getNumVTableThunks() const {
- return NumVTableThunks;
- }
+ uint64_t getNumVTableThunks() const { return NumVTableThunks; }
vtable_thunk_iterator vtable_thunk_begin() const {
- return VTableThunks.get();
+ return VTableThunks.get();
}
vtable_thunk_iterator vtable_thunk_end() const {
- return VTableThunks.get()+NumVTableThunks;
+ return VTableThunks.get() + NumVTableThunks;
}
uint64_t getAddressPoint(BaseSubobject Base) const {
@@ -266,19 +266,45 @@ public:
}
};
-class VTableContext {
- ASTContext &Context;
-
+class VTableContextBase {
public:
- typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
- VTableThunksTy;
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+protected:
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// \brief Contains all thunks that a given method decl will need.
+ ThunksMapTy Thunks;
+
+ /// Compute and store all vtable related information (vtable layout, vbase
+ /// offset offsets, thunks etc) for the given record decl.
+ virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0;
+
+ virtual ~VTableContextBase() {}
+
+public:
+ virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl());
+ computeVTableRelatedInformation(MD->getParent());
+
+ // This assumes that all the destructors present in the vtable
+ // use exactly the same set of thunks.
+ ThunksMapTy::const_iterator I = Thunks.find(MD);
+ if (I == Thunks.end()) {
+ // We did not find a thunk for this method.
+ return 0;
+ }
+
+ return &I->second;
+ }
+};
+
+class ItaniumVTableContext : public VTableContextBase {
private:
bool IsMicrosoftABI;
- /// MethodVTableIndices - Contains the index (relative to the vtable address
- /// point) where the function pointer for a virtual function is stored.
+ /// \brief Contains the index (relative to the vtable address point)
+ /// where the function pointer for a virtual function is stored.
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
MethodVTableIndicesTy MethodVTableIndices;
@@ -286,49 +312,25 @@ private:
VTableLayoutMapTy;
VTableLayoutMapTy VTableLayouts;
- /// NumVirtualFunctionPointers - Contains the number of virtual function
- /// pointers in the vtable for a given record decl.
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
-
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
- /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
- /// the address point) in chars where the offsets for virtual bases of a class
- /// are stored.
+ /// \brief vtable offsets for offsets of virtual bases of a class.
+ ///
+ /// Contains the vtable offset (relative to the address point) in chars
+ /// where the offsets for virtual bases of a class are stored.
typedef llvm::DenseMap<ClassPairTy, CharUnits>
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
- typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
-
- /// Thunks - Contains all thunks that a given method decl will need.
- ThunksMapTy Thunks;
-
- void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
-
- /// ComputeVTableRelatedInformation - Compute and store all vtable related
- /// information (vtable layout, vbase offset offsets, thunks etc) for the
- /// given record decl.
- void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
-
- /// ErrorUnsupported - Print out an error that the v-table layout code
- /// doesn't support the particular C++ feature yet.
- void ErrorUnsupported(StringRef Feature, SourceLocation Location);
+ void computeVTableRelatedInformation(const CXXRecordDecl *RD);
public:
- VTableContext(ASTContext &Context);
- ~VTableContext();
-
- bool isMicrosoftABI() const {
- // FIXME: Currently, this method is only used in the VTableContext and
- // VTableBuilder code which is ABI-specific. Probably we can remove it
- // when we add a layer of abstraction for vtable generation.
- return IsMicrosoftABI;
- }
+ ItaniumVTableContext(ASTContext &Context);
+ ~ItaniumVTableContext();
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
- ComputeVTableRelatedInformation(RD);
+ computeVTableRelatedInformation(RD);
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
return *VTableLayouts[RD];
@@ -340,36 +342,177 @@ public:
bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass);
- const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) {
- ComputeVTableRelatedInformation(MD->getParent());
+ /// \brief Locate a virtual function in the vtable.
+ ///
+ /// Return the index (relative to the vtable address point) where the
+ /// function pointer for the given virtual function is stored.
+ uint64_t getMethodVTableIndex(GlobalDecl GD);
- ThunksMapTy::const_iterator I = Thunks.find(MD);
- if (I == Thunks.end()) {
- // We did not find a thunk for this method.
- return 0;
- }
+ /// Return the offset in chars (relative to the vtable address point) where
+ /// the offset of the virtual base that contains the given base is stored,
+ /// otherwise, if no virtual base contains the given class, return 0.
+ ///
+ /// Base must be a virtual base class or an unambiguous base.
+ CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase);
+};
- return &I->second;
+struct VFPtrInfo {
+ typedef SmallVector<const CXXRecordDecl *, 1> BasePath;
+
+ // Don't pass the PathToMangle as it should be calculated later.
+ VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr)
+ : VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset),
+ PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) {
}
- /// getNumVirtualFunctionPointers - Return the number of virtual function
- /// pointers in the vtable for a given record decl.
- uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
+ // Don't pass the PathToMangle as it should be calculated later.
+ VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase,
+ CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr,
+ CharUnits VFPtrFullOffset)
+ : VBTableIndex(VBTableIndex), LastVBase(LastVBase),
+ VFPtrOffset(VFPtrOffset), PathToBaseWithVFPtr(PathToBaseWithVFPtr),
+ VFPtrFullOffset(VFPtrFullOffset) {
+ assert(VBTableIndex && "The full constructor should only be used "
+ "for vfptrs in virtual bases");
+ assert(LastVBase);
+ }
- /// getMethodVTableIndex - Return the index (relative to the vtable address
- /// point) where the function pointer for the given virtual function is
- /// stored.
- uint64_t getMethodVTableIndex(GlobalDecl GD);
+ /// If nonzero, holds the vbtable index of the virtual base with the vfptr.
+ uint64_t VBTableIndex;
- /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
- /// vtable address point) where the offset of the virtual base that contains
- /// the given base is stored, otherwise, if no virtual base contains the given
- /// class, return 0. Base must be a virtual base class or an unambigious
- /// base.
- CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase);
+ /// Stores the last vbase on the path from the complete type to the vfptr.
+ const CXXRecordDecl *LastVBase;
+
+ /// This is the offset of the vfptr from the start of the last vbase,
+ /// or the complete type if there are no virtual bases.
+ CharUnits VFPtrOffset;
+
+ /// This holds the base classes path from the complete type to the first base
+ /// with the given vfptr offset, in the base-to-derived order.
+ BasePath PathToBaseWithVFPtr;
+
+ /// This holds the subset of records that need to be mangled into the vftable
+ /// symbol name in order to get a unique name, in the derived-to-base order.
+ BasePath PathToMangle;
+
+ /// This is the full offset of the vfptr from the start of the complete type.
+ CharUnits VFPtrFullOffset;
};
+class MicrosoftVTableContext : public VTableContextBase {
+public:
+ struct MethodVFTableLocation {
+ /// If nonzero, holds the vbtable index of the virtual base with the vfptr.
+ uint64_t VBTableIndex;
+
+ /// If nonnull, holds the last vbase which contains the vfptr that the
+ /// method definition is adjusted to.
+ const CXXRecordDecl *VBase;
+
+ /// This is the offset of the vfptr from the start of the last vbase, or the
+ /// complete type if there are no virtual bases.
+ CharUnits VFPtrOffset;
+
+ /// Method's index in the vftable.
+ uint64_t Index;
+
+ MethodVFTableLocation()
+ : VBTableIndex(0), VBase(0), VFPtrOffset(CharUnits::Zero()),
+ Index(0) {}
+
+ MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
+ CharUnits VFPtrOffset, uint64_t Index)
+ : VBTableIndex(VBTableIndex), VBase(VBase),
+ VFPtrOffset(VFPtrOffset), Index(Index) {}
+
+ bool operator<(const MethodVFTableLocation &other) const {
+ if (VBTableIndex != other.VBTableIndex) {
+ assert(VBase != other.VBase);
+ return VBTableIndex < other.VBTableIndex;
+ }
+ if (VFPtrOffset != other.VFPtrOffset)
+ return VFPtrOffset < other.VFPtrOffset;
+ if (Index != other.Index)
+ return Index < other.Index;
+ return false;
+ }
+ };
+
+ typedef SmallVector<VFPtrInfo, 1> VFPtrListTy;
+
+private:
+ ASTContext &Context;
+
+ typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
+ MethodVFTableLocationsTy;
+ MethodVFTableLocationsTy MethodVFTableLocations;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, VFPtrListTy>
+ VFPtrLocationsMapTy;
+ VFPtrLocationsMapTy VFPtrLocations;
+
+ typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
+ typedef llvm::DenseMap<VFTableIdTy, const VTableLayout *> VFTableLayoutMapTy;
+ VFTableLayoutMapTy VFTableLayouts;
+
+ typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy;
+ void enumerateVFPtrs(const CXXRecordDecl *MostDerivedClass,
+ const ASTRecordLayout &MostDerivedClassLayout,
+ BaseSubobject Base, const CXXRecordDecl *LastVBase,
+ const VFPtrInfo::BasePath &PathFromCompleteClass,
+ BasesSetVectorTy &VisitedVBases,
+ MicrosoftVTableContext::VFPtrListTy &Result);
+
+ void enumerateVFPtrs(const CXXRecordDecl *ForClass,
+ MicrosoftVTableContext::VFPtrListTy &Result);
+
+ void computeVTableRelatedInformation(const CXXRecordDecl *RD);
+
+ void dumpMethodLocations(const CXXRecordDecl *RD,
+ const MethodVFTableLocationsTy &NewMethods,
+ raw_ostream &);
+
+ typedef std::pair<const CXXRecordDecl *, const CXXRecordDecl *> ClassPairTy;
+ typedef llvm::DenseMap<ClassPairTy, unsigned> VBTableIndicesTy;
+ VBTableIndicesTy VBTableIndices;
+ llvm::DenseSet<const CXXRecordDecl *> ComputedVBTableIndices;
+
+ void computeVBTableRelatedInformation(const CXXRecordDecl *RD);
+
+public:
+ MicrosoftVTableContext(ASTContext &Context) : Context(Context) {}
+
+ ~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); }
+
+ const VFPtrListTy &getVFPtrOffsets(const CXXRecordDecl *RD);
+
+ const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD,
+ CharUnits VFPtrOffset);
+
+ const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD);
+
+ const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
+ // Complete destructors don't have a slot in a vftable, so no thunks needed.
+ if (isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() == Dtor_Complete)
+ return 0;
+ return VTableContextBase::getThunkInfo(GD);
+ }
+
+ /// \brief Returns the index of VBase in the vbtable of Derived.
+ /// VBase must be a morally virtual base of Derived.
+ /// The vbtable is an array of i32 offsets. The first entry is a self entry,
+ /// and the rest are offsets from the vbptr to virtual bases.
+ unsigned getVBTableIndex(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *VBase) {
+ computeVBTableRelatedInformation(Derived);
+ ClassPairTy Pair(Derived, VBase);
+ assert(VBTableIndices.count(Pair) == 1 &&
+ "VBase must be a vbase of Derived");
+ return VBTableIndices[Pair];
+ }
+};
}
#endif
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index 870a39b39111..db0a83d72262 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -97,6 +97,11 @@ public:
///
/// Optionally override to do per translation unit tasks.
virtual void onStartOfTranslationUnit() {}
+
+ /// \brief Called at the end of each translation unit.
+ ///
+ /// Optionally override to do per translation unit tasks.
+ virtual void onEndOfTranslationUnit() {}
};
/// \brief Called when parsing is finished. Intended for testing only.
@@ -131,6 +136,17 @@ public:
MatchCallback *Action);
/// @}
+ /// \brief Adds a matcher to execute when running over the AST.
+ ///
+ /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
+ /// is more flexible, but the lost type information enables a caller to pass
+ /// a matcher that cannot match anything.
+ ///
+ /// \returns \c true if the matcher is a valid top-level matcher, \c false
+ /// otherwise.
+ bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+ MatchCallback *Action);
+
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
@@ -147,6 +163,9 @@ public:
ASTContext &Context);
/// @}
+ /// \brief Finds all matches in the given AST.
+ void matchAST(ASTContext &Context);
+
/// \brief Registers a callback to notify the end of parsing.
///
/// The provided closure is called after parsing is done, before the AST is
@@ -157,7 +176,7 @@ public:
private:
/// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
/// when it matches.
- std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
+ std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> >
MatcherCallbackPairs;
/// \brief Called when parsing is done.
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index ab62dd0c3e81..0a3157dde817 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -45,6 +45,7 @@
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
@@ -85,6 +86,16 @@ 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;
+
+ /// \brief Retrieve mapping from binding identifiers to bound nodes.
+ const IDToNodeMap &getMap() const {
+ return MyBoundNodes.getMap();
+ }
+
private:
/// \brief Create BoundNodes from a pre-filled map of bindings.
BoundNodes(internal::BoundNodesMap &MyBoundNodes)
@@ -92,7 +103,7 @@ private:
internal::BoundNodesMap MyBoundNodes;
- friend class internal::BoundNodesTree;
+ friend class internal::BoundNodesTreeBuilder;
};
/// \brief If the provided matcher matches a node, binds the node to \c ID.
@@ -204,6 +215,28 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ClassTemplateSpecializationDecl> classTemplateSpecializationDecl;
+/// \brief Matches declarator declarations (field, variable, function
+/// and non-type template parameter declarations).
+///
+/// Given
+/// \code
+/// class X { int y; };
+/// \endcode
+/// declaratorDecl()
+/// matches \c int y.
+const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl>
+ declaratorDecl;
+
+/// \brief Matches parameter variable declarations.
+///
+/// Given
+/// \code
+/// void f(int x);
+/// \endcode
+/// parmVarDecl()
+/// matches \c int x.
+const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl;
+
/// \brief Matches C++ access specifier declarations.
///
/// Given
@@ -219,6 +252,17 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
AccessSpecDecl> accessSpecDecl;
+/// \brief Matches constructor initializers.
+///
+/// Examples matches \c i(42).
+/// \code
+/// class C {
+/// C() : i(42) {}
+/// int i;
+/// };
+/// \endcode
+const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer;
+
/// \brief Matches public C++ declarations.
///
/// Given
@@ -281,12 +325,9 @@ AST_MATCHER(Decl, isPrivate) {
/// matches the specialization \c A<int>
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
internal::Matcher<TemplateArgument>, InnerMatcher) {
- const TemplateArgumentList &List = Node.getTemplateArgs();
- for (unsigned i = 0; i < List.size(); ++i) {
- if (InnerMatcher.matches(List.get(i), Finder, Builder))
- return true;
- }
- return false;
+ llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray();
+ return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder,
+ Builder);
}
/// \brief Matches expressions that match InnerMatcher after any implicit casts
@@ -520,6 +561,16 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
FunctionTemplateDecl> functionTemplateDecl;
+/// \brief Matches friend declarations.
+///
+/// Given
+/// \code
+/// class X { friend void foo(); };
+/// \endcode
+/// friendDecl()
+/// matches 'friend void foo()'.
+const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl;
+
/// \brief Matches statements.
///
/// Given
@@ -607,6 +658,21 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
/// matches \code using X::x \endcode
const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl;
+/// \brief Matches unresolved using value declarations.
+///
+/// Given
+/// \code
+/// template<typename X>
+/// class C : private X {
+/// using X::x;
+/// };
+/// \endcode
+/// unresolvedUsingValueDecl()
+/// matches \code using X::x \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ UnresolvedUsingValueDecl> unresolvedUsingValueDecl;
+
/// \brief Matches constructor call expressions (including implicit ones).
///
/// Example matches string(ptr, n) and ptr within arguments of f
@@ -621,6 +687,18 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CXXConstructExpr> constructExpr;
+/// \brief Matches unresolved constructor call expressions.
+///
+/// Example matches T(t) in return statement of f
+/// (matcher = unresolvedConstructExpr())
+/// \code
+/// template <typename T>
+/// void f(const T& t) { return T(t); }
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXUnresolvedConstructExpr> unresolvedConstructExpr;
+
/// \brief Matches implicit and explicit this expressions.
///
/// Example matches the implicit this expression in "return i".
@@ -894,6 +972,26 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt;
/// matches 'case 42: break;' and 'default: break;'.
const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase;
+/// \brief Matches case statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// caseStmt()
+/// matches 'case 42: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt;
+
+/// \brief Matches default statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// defaultStmt()
+/// matches 'default: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt;
+
/// \brief Matches compound statements.
///
/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
@@ -981,15 +1079,25 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CharacterLiteral> characterLiteral;
-/// \brief Matches integer literals of all sizes / encodings.
-///
-/// Not matching character-encoded integers such as L'a'.
+/// \brief Matches integer literals of all sizes / encodings, e.g.
+/// 1, 1L, 0x1 and 1U.
///
-/// Example matches 1, 1L, 0x1, 1U
+/// Does not match character-encoded integers such as L'a'.
const internal::VariadicDynCastAllOfMatcher<
Stmt,
IntegerLiteral> integerLiteral;
+/// \brief Matches float literals of all sizes / encodings, e.g.
+/// 1.0, 1.0f, 1.0L and 1e10.
+///
+/// Does not match implicit conversions such as
+/// \code
+/// float a = 10;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ FloatingLiteral> floatLiteral;
+
/// \brief Matches user defined literal operator call.
///
/// Example match: "foo"_suffix
@@ -1171,6 +1279,16 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CXXFunctionalCastExpr> functionalCastExpr;
+/// \brief Matches functional cast expressions having N != 1 arguments
+///
+/// Example: Matches Foo(bar, bar)
+/// \code
+/// Foo h = Foo(bar, bar);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXTemporaryObjectExpr> temporaryObjectExpr;
+
/// \brief Matches \c QualTypes in the clang AST.
const internal::VariadicAllOfMatcher<QualType> qualType;
@@ -1199,93 +1317,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
/// \c b.
///
/// Usable as: Any Matcher
-template <typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2>
-eachOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1,
- M2>(P1, P2);
-}
-
-/// \brief Various overloads for the anyOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc eachOf = {
+ internal::EachOfVariadicOperator
+};
/// \brief Matches if any of the given matchers matches.
///
/// Usable as: Any Matcher
-template<typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, M2>
-anyOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M1, M2 >(P1, P2);
-}
-template<typename M1, typename M2, typename M3>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2, M3> >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3) {
- return anyOf(P1, anyOf(P2, P3));
-}
-template<typename M1, typename M2, typename M3, typename M4>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M3, M4> > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
- return anyOf(P1, anyOf(P2, anyOf(P3, P4)));
-}
-template<typename M1, typename M2, typename M3, typename M4, typename M5>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M3,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M4, M5> > > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
- return anyOf(P1, anyOf(P2, anyOf(P3, anyOf(P4, P5))));
-}
-
-/// @}
-
-/// \brief Various overloads for the allOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc anyOf = {
+ internal::AnyOfVariadicOperator
+};
/// \brief Matches if all given matchers match.
///
/// Usable as: Any Matcher
-template <typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>
-allOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>(
- P1, P2);
-}
-template <typename M1, typename M2, typename M3>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M2, M3> >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3) {
- return allOf(P1, allOf(P2, P3));
-}
-template <typename M1, typename M2, typename M3, typename M4>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M2, internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M3, M4> > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
- return allOf(P1, allOf(P2, P3, P4));
-}
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M3,
- internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M4,
- M5> > > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
- return allOf(P1, allOf(P2, P3, P4, P5));
-}
-
-/// @}
+const internal::VariadicOperatorMatcherFunc allOf = {
+ internal::AllOfVariadicOperator
+};
/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
///
@@ -1412,10 +1460,13 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
///
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
inline internal::PolymorphicMatcherWithParam1<
- internal::HasOverloadedOperatorNameMatcher, StringRef>
+ internal::HasOverloadedOperatorNameMatcher, StringRef,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>
hasOverloadedOperatorName(const StringRef Name) {
return internal::PolymorphicMatcherWithParam1<
- internal::HasOverloadedOperatorNameMatcher, StringRef>(Name);
+ internal::HasOverloadedOperatorNameMatcher, StringRef,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>(
+ Name);
}
/// \brief Matches C++ classes that are directly or indirectly derived from
@@ -1445,24 +1496,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
}
/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) {
assert(!BaseName.empty());
- return isDerivedFrom(hasName(BaseName));
+ return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Similar to \c isDerivedFrom(), but also matches classes that directly
/// match \c Base.
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- internal::Matcher<NamedDecl> Base) {
- return anyOf(Base, isDerivedFrom(Base));
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
+ internal::Matcher<NamedDecl>, Base, 0) {
+ return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base)))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName,
+ 1) {
assert(!BaseName.empty());
- return isSameOrDerivedFrom(hasName(BaseName));
+ return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Matches the first method of a class or struct that satisfies \c
@@ -1478,12 +1530,8 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
/// but not \c B.
AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
InnerMatcher) {
- for (CXXRecordDecl::method_iterator I = Node.method_begin(),
- E = Node.method_end();
- I != E; ++I)
- if (InnerMatcher.matches(**I, Finder, Builder))
- return true;
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.method_begin(),
+ Node.method_end(), Finder, Builder);
}
/// \brief Matches AST nodes that have child AST nodes that match the
@@ -1499,12 +1547,8 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
/// ChildT must be an AST base type.
///
/// Usable as: Any Matcher
-template <typename ChildT>
-internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
- const internal::Matcher<ChildT> &ChildMatcher) {
- return internal::ArgumentAdaptingMatcher<internal::HasMatcher,
- ChildT>(ChildMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher>
+LLVM_ATTRIBUTE_UNUSED has = {};
/// \brief Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
@@ -1520,13 +1564,8 @@ internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
/// DescendantT must be an AST base type.
///
/// Usable as: Any Matcher
-template <typename DescendantT>
-internal::ArgumentAdaptingMatcher<internal::HasDescendantMatcher, DescendantT>
-hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasDescendantMatcher,
- DescendantT>(DescendantMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher>
+LLVM_ATTRIBUTE_UNUSED hasDescendant = {};
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
@@ -1544,13 +1583,8 @@ hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
/// matches instead of only on the first one.
///
/// Usable as: Any Matcher
-template <typename ChildT>
-internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
- const internal::Matcher<ChildT> &ChildMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::ForEachMatcher,
- ChildT>(ChildMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher>
+LLVM_ATTRIBUTE_UNUSED forEach = {};
/// \brief Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
@@ -1576,15 +1610,8 @@ internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
/// \endcode
///
/// Usable as: Any Matcher
-template <typename DescendantT>
-internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher,
- DescendantT>
-forEachDescendant(
- const internal::Matcher<DescendantT> &DescendantMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::ForEachDescendantMatcher,
- DescendantT>(DescendantMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher>
+LLVM_ATTRIBUTE_UNUSED forEachDescendant = {};
/// \brief Matches if the node or any descendant matches.
///
@@ -1602,10 +1629,7 @@ forEachDescendant(
///
/// Usable as: Any Matcher
template <typename T>
-internal::PolymorphicMatcherWithParam2<
- internal::EachOfMatcher, internal::Matcher<T>,
- internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, T> >
-findAll(const internal::Matcher<T> &Matcher) {
+internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) {
return eachOf(Matcher, forEachDescendant(Matcher));
}
@@ -1619,13 +1643,9 @@ findAll(const internal::Matcher<T> &Matcher) {
/// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
///
/// Usable as: Any Matcher
-template <typename ParentT>
-internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT>
-hasParent(const internal::Matcher<ParentT> &ParentMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasParentMatcher,
- ParentT>(ParentMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<
+ internal::HasParentMatcher, internal::TypeList<Decl, Stmt>,
+ internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasParent = {};
/// \brief Matches AST nodes that have an ancestor that matches the provided
/// matcher.
@@ -1638,13 +1658,9 @@ hasParent(const internal::Matcher<ParentT> &ParentMatcher) {
/// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43.
///
/// Usable as: Any Matcher
-template <typename AncestorT>
-internal::ArgumentAdaptingMatcher<internal::HasAncestorMatcher, AncestorT>
-hasAncestor(const internal::Matcher<AncestorT> &AncestorMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasAncestorMatcher,
- AncestorT>(AncestorMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<
+ internal::HasAncestorMatcher, internal::TypeList<Decl, Stmt>,
+ internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasAncestor = {};
/// \brief Matches if the provided matcher does not match.
///
@@ -1662,22 +1678,31 @@ unless(const M &InnerMatcher) {
internal::NotMatcher, M>(InnerMatcher);
}
-/// \brief Matches a type if the declaration of the type matches the given
-/// matcher.
+/// \brief Matches a node if the declaration associated with that node
+/// matches the given matcher.
+///
+/// The associated declaration is:
+/// - for type nodes, the declaration of the underlying type
+/// - for CallExpr, the declaration of the callee
+/// - for MemberExpr, the declaration of the referenced member
+/// - for CXXConstructExpr, the declaration of the constructor
///
-/// In addition to being usable as Matcher<TypedefType>, also usable as
-/// Matcher<T> for any T supporting the getDecl() member function. e.g. various
-/// subtypes of clang::Type.
+/// Also usable as Matcher<T> for any T supporting the getDecl() member
+/// function. e.g. various subtypes of clang::Type and various expressions.
///
-/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>,
-/// Matcher<MemberExpr>, Matcher<TypedefType>,
-/// Matcher<TemplateSpecializationType>
-inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
- internal::Matcher<Decl> >
- hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
+/// Usable as: Matcher<CallExpr>, Matcher<CXXConstructExpr>,
+/// Matcher<DeclRefExpr>, Matcher<EnumType>, Matcher<InjectedClassNameType>,
+/// Matcher<LabelStmt>, Matcher<MemberExpr>, Matcher<QualType>,
+/// Matcher<RecordType>, Matcher<TagType>,
+/// Matcher<TemplateSpecializationType>, Matcher<TemplateTypeParmType>,
+/// Matcher<TypedefType>, Matcher<UnresolvedUsingType>
+inline internal::PolymorphicMatcherWithParam1<
+ internal::HasDeclarationMatcher, internal::Matcher<Decl>,
+ void(internal::HasDeclarationSupportedTypes)>
+hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
return internal::PolymorphicMatcherWithParam1<
- internal::HasDeclarationMatcher,
- internal::Matcher<Decl> >(InnerMatcher);
+ internal::HasDeclarationMatcher, internal::Matcher<Decl>,
+ void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
}
/// \brief Matches on the implicit object argument of a member call expression.
@@ -1728,9 +1753,9 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
/// class Y { public: void x(); };
/// void z() { Y y; y.x();
/// \endcode
-inline internal::Matcher<CallExpr> callee(
- const internal::Matcher<Decl> &InnerMatcher) {
- return callExpr(hasDeclaration(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
+ 1) {
+ return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
}
/// \brief Matches if the expression's or declaration's type matches a type
@@ -1742,11 +1767,9 @@ inline internal::Matcher<CallExpr> callee(
/// class X {};
/// void y(X &x) { x; X z; }
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<Expr, NodeType>::value ||
- llvm::is_base_of<ValueDecl, NodeType>::value),
- instantiated_with_wrong_types);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return InnerMatcher.matches(Node.getType(), Finder, Builder);
}
@@ -1767,11 +1790,27 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
/// \endcode
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
-inline internal::PolymorphicMatcherWithParam1<
- internal::matcher_hasType0Matcher,
- internal::Matcher<QualType> >
-hasType(const internal::Matcher<Decl> &InnerMatcher) {
- return hasType(qualType(hasDeclaration(InnerMatcher)));
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<Decl>, InnerMatcher, 1) {
+ return qualType(hasDeclaration(InnerMatcher))
+ .matches(Node.getType(), Finder, Builder);
+}
+
+/// \brief Matches if the type location of the declarator decl's type matches
+/// the inner matcher.
+///
+/// Given
+/// \code
+/// int x;
+/// \endcode
+/// declaratorDecl(hasTypeLoc(loc(asString("int"))))
+/// matches int x
+AST_MATCHER_P(DeclaratorDecl, hasTypeLoc, internal::Matcher<TypeLoc>, Inner) {
+ if (!Node.getTypeSourceInfo())
+ // This happens for example for implicit destructors.
+ return false;
+ return Inner.matches(Node.getTypeSourceInfo()->getTypeLoc(), Finder, Builder);
}
/// \brief Matches if the matched type is represented by the given string.
@@ -1804,9 +1843,10 @@ AST_MATCHER_P(
}
/// \brief Overloaded to match the pointee type's declaration.
-inline internal::Matcher<QualType> pointsTo(
- const internal::Matcher<Decl> &InnerMatcher) {
- return pointsTo(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return pointsTo(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches if the matched type is a reference type and the referenced
@@ -1841,13 +1881,16 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
InnerMatcher) {
+ if (Node.isNull())
+ return false;
return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
}
/// \brief Overloaded to match the referenced type's declaration.
-inline internal::Matcher<QualType> references(
- const internal::Matcher<Decl> &InnerMatcher) {
- return references(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return references(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
@@ -1859,17 +1902,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
/// \brief Matches if the expression's type either matches the specified
/// matcher, or is a pointer to a type that matches the InnerMatcher.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<QualType> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded to match the type's declaration.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<Decl> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<Decl>, InnerMatcher, 1) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches a DeclRefExpr that refers to a declaration that matches the
@@ -1953,11 +1998,9 @@ AST_MATCHER_P(
/// void f(int x, int y);
/// f(0, 0);
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value ||
- llvm::is_base_of<CXXConstructExpr,
- NodeType>::value),
- instantiated_with_wrong_types);
+AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ CallExpr, CXXConstructExpr),
+ unsigned, N) {
return Node.getNumArgs() == N;
}
@@ -1970,11 +2013,9 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
/// void x(int) { int y; x(y); }
/// \endcode
AST_POLYMORPHIC_MATCHER_P2(
- hasArgument, unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value ||
- llvm::is_base_of<CXXConstructExpr,
- NodeType>::value),
- instantiated_with_wrong_types);
+ hasArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CallExpr, CXXConstructExpr),
+ unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
return (N < Node.getNumArgs() &&
InnerMatcher.matches(
*Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
@@ -2037,13 +2078,8 @@ AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
/// record matches Foo, hasAnyConstructorInitializer matches foo_(1)
AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
- for (CXXConstructorDecl::init_const_iterator I = Node.init_begin();
- I != Node.init_end(); ++I) {
- if (InnerMatcher.matches(**I, Finder, Builder)) {
- return true;
- }
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.init_begin(),
+ Node.init_end(), Finder, Builder);
}
/// \brief Matches the field declaration of a constructor initializer.
@@ -2086,7 +2122,7 @@ AST_MATCHER_P(CXXCtorInitializer, withInitializer,
InnerMatcher.matches(*NodeAsExpr, Finder, Builder));
}
-/// \brief Matches a contructor initializer if it is explicitly written in
+/// \brief Matches a constructor initializer if it is explicitly written in
/// code (as opposed to implicitly added by the compiler).
///
/// Given
@@ -2120,15 +2156,19 @@ AST_MATCHER(CXXConstructorDecl, isImplicit) {
/// matches x(1, y, 42)
/// with hasAnyArgument(...)
/// matching y
-AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher<Expr>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value ||
- llvm::is_base_of<CXXConstructExpr,
- NodeType>::value),
- instantiated_with_wrong_types);
+///
+/// FIXME: Currently this will ignore parentheses and implicit casts on
+/// the argument before applying the inner matcher. We'll want to remove
+/// this to allow for greater control by the user once \c ignoreImplicit()
+/// has been implemented.
+AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ CallExpr, CXXConstructExpr),
+ internal::Matcher<Expr>, InnerMatcher) {
for (unsigned I = 0; I < Node.getNumArgs(); ++I) {
- if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(),
- Finder, Builder)) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder,
+ &Result)) {
+ *Builder = Result;
return true;
}
}
@@ -2167,12 +2207,8 @@ AST_MATCHER_P2(FunctionDecl, hasParameter,
/// matching int y
AST_MATCHER_P(FunctionDecl, hasAnyParameter,
internal::Matcher<ParmVarDecl>, InnerMatcher) {
- for (unsigned I = 0; I < Node.getNumParams(); ++I) {
- if (InnerMatcher.matches(*Node.getParamDecl(I), Finder, Builder)) {
- return true;
- }
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.param_begin(),
+ Node.param_end(), Finder, Builder);
}
/// \brief Matches \c FunctionDecls that have a specific parameter count.
@@ -2222,27 +2258,68 @@ AST_MATCHER(FunctionDecl, isExternC) {
/// \code
/// if (true) {}
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher<Expr>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<IfStmt, NodeType>::value) ||
- (llvm::is_base_of<ForStmt, NodeType>::value) ||
- (llvm::is_base_of<WhileStmt, NodeType>::value) ||
- (llvm::is_base_of<DoStmt, NodeType>::value) ||
- (llvm::is_base_of<ConditionalOperator, NodeType>::value),
- has_condition_requires_if_statement_conditional_operator_or_loop);
+AST_POLYMORPHIC_MATCHER_P(
+ hasCondition, AST_POLYMORPHIC_SUPPORTED_TYPES_5(
+ IfStmt, ForStmt, WhileStmt, DoStmt, ConditionalOperator),
+ internal::Matcher<Expr>, InnerMatcher) {
const Expr *const Condition = Node.getCond();
return (Condition != NULL &&
InnerMatcher.matches(*Condition, Finder, Builder));
}
+namespace internal {
+struct NotEqualsBoundNodePredicate {
+ bool operator()(const internal::BoundNodesMap &Nodes) const {
+ return Nodes.getNode(ID) != Node;
+ }
+ std::string ID;
+ ast_type_traits::DynTypedNode Node;
+};
+} // namespace internal
+
+/// \brief Matches if a node equals a previously bound node.
+///
+/// Matches a node if it equals the node previously bound to \p ID.
+///
+/// Given
+/// \code
+/// class X { int a; int b; };
+/// \endcode
+/// recordDecl(
+/// has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+/// matches the class \c X, as \c a and \c b have the same type.
+///
+/// Note that when multiple matches are involved via \c forEach* matchers,
+/// \c equalsBoundNodes acts as a filter.
+/// For example:
+/// compoundStmt(
+/// forEachDescendant(varDecl().bind("d")),
+/// forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+/// will trigger a match for each combination of variable declaration
+/// and reference to that variable declaration within a compound statement.
+AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, AST_POLYMORPHIC_SUPPORTED_TYPES_4(
+ Stmt, Decl, Type, QualType),
+ std::string, ID) {
+ // FIXME: Figure out whether it makes sense to allow this
+ // on any other node types.
+ // For *Loc it probably does not make sense, as those seem
+ // unique. For NestedNameSepcifier it might make sense, as
+ // those also have pointer identity, but I'm not sure whether
+ // they're ever reused.
+ internal::NotEqualsBoundNodePredicate Predicate;
+ Predicate.ID = ID;
+ Predicate.Node = ast_type_traits::DynTypedNode::create(Node);
+ return Builder->removeBindings(Predicate);
+}
+
/// \brief Matches the condition variable statement in an if statement.
///
/// Given
/// \code
/// if (A* a = GetAPointer()) {}
/// \endcode
-/// hasConditionVariableStatment(...)
+/// hasConditionVariableStatement(...)
/// matches 'A* a = GetAPointer()'.
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
internal::Matcher<DeclStmt>, InnerMatcher) {
@@ -2296,13 +2373,9 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
/// matches 'for (;;) {}'
/// with compoundStmt()
/// matching '{}'
-AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<DoStmt, NodeType>::value) ||
- (llvm::is_base_of<ForStmt, NodeType>::value) ||
- (llvm::is_base_of<WhileStmt, NodeType>::value),
- has_body_requires_for_while_or_do_statement);
+AST_POLYMORPHIC_MATCHER_P(
+ hasBody, AST_POLYMORPHIC_SUPPORTED_TYPES_3(DoStmt, ForStmt, WhileStmt),
+ internal::Matcher<Stmt>, InnerMatcher) {
const Stmt *const Statement = Node.getBody();
return (Statement != NULL &&
InnerMatcher.matches(*Statement, Finder, Builder));
@@ -2321,12 +2394,8 @@ AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
/// matching '{}'
AST_MATCHER_P(CompoundStmt, hasAnySubstatement,
internal::Matcher<Stmt>, InnerMatcher) {
- for (CompoundStmt::const_body_iterator It = Node.body_begin();
- It != Node.body_end();
- ++It) {
- if (InnerMatcher.matches(**It, Finder, Builder)) return true;
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.body_begin(),
+ Node.body_end(), Finder, Builder);
}
/// \brief Checks that a compound statement contains a specific number of
@@ -2367,11 +2436,9 @@ equals(const ValueT &Value) {
/// \code
/// !(a || b)
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<BinaryOperator, NodeType>::value) ||
- (llvm::is_base_of<UnaryOperator, NodeType>::value),
- has_condition_requires_if_statement_or_conditional_operator);
+AST_POLYMORPHIC_MATCHER_P(hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ BinaryOperator, UnaryOperator),
+ std::string, Name) {
return Name == Node.getOpcodeStr(Node.getOpcode());
}
@@ -2493,12 +2560,8 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
/// \endcode
///
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
-AST_POLYMORPHIC_MATCHER(isDefinition) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<TagDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<FunctionDecl, NodeType>::value),
- is_definition_requires_isThisDeclarationADefinition_method);
+AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES_3(
+ TagDecl, VarDecl, FunctionDecl)) {
return Node.isThisDeclarationADefinition();
}
@@ -2540,6 +2603,21 @@ AST_MATCHER(CXXMethodDecl, isVirtual) {
return Node.isVirtual();
}
+/// \brief Matches if the given method declaration is const.
+///
+/// Given
+/// \code
+/// struct A {
+/// void foo() const;
+/// void bar();
+/// };
+/// \endcode
+///
+/// methodDecl(isConst()) matches A::foo() but not A::bar()
+AST_MATCHER(CXXMethodDecl, isConst) {
+ return Node.isConst();
+}
+
/// \brief Matches if the given method declaration overrides another method.
///
/// Given
@@ -2672,12 +2750,8 @@ AST_MATCHER_P(MemberExpr, hasObjectExpression,
/// matches \code using X::b \endcode
AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl,
internal::Matcher<UsingShadowDecl>, InnerMatcher) {
- for (UsingDecl::shadow_iterator II = Node.shadow_begin();
- II != Node.shadow_end(); ++II) {
- if (InnerMatcher.matches(**II, Finder, Builder))
- return true;
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(),
+ Node.shadow_end(), Finder, Builder);
}
/// \brief Matches a using shadow declaration where the target declaration is
@@ -2720,11 +2794,9 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
/// does not match, as X<A> is an explicit template specialization.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
- requires_getTemplateSpecializationKind_method);
+AST_POLYMORPHIC_MATCHER(
+ isTemplateInstantiation,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation ||
Node.getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition);
@@ -2742,11 +2814,9 @@ AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) {
/// matches the specialization A<int>().
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
- requires_getTemplateSpecializationKind_method);
+AST_POLYMORPHIC_MATCHER(
+ isExplicitTemplateSpecialization,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
}
@@ -2807,7 +2877,9 @@ AST_TYPE_MATCHER(ComplexType, complexType);
/// matches "int b[7]"
///
/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
-AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement);
+AST_TYPELOC_TRAVERSE_MATCHER(
+ hasElementType, getElement,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(ArrayType, ComplexType));
/// \brief Matches C arrays with a specified constant size.
///
@@ -2914,7 +2986,8 @@ AST_TYPE_MATCHER(AtomicType, atomicType);
/// matches "_Atomic(int) i"
///
/// Usable as: Matcher<AtomicType>
-AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue);
+AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(AtomicType));
/// \brief Matches types nodes representing C++11 auto types.
///
@@ -2942,7 +3015,8 @@ AST_TYPE_MATCHER(AutoType, autoType);
/// matches "auto a"
///
/// Usable as: Matcher<AutoType>
-AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
+AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(AutoType));
/// \brief Matches \c FunctionType nodes.
///
@@ -2979,7 +3053,8 @@ AST_TYPE_MATCHER(ParenType, parenType);
/// \c ptr_to_func but not \c ptr_to_array.
///
/// Usable as: Matcher<ParenType>
-AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType);
+AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(ParenType));
/// \brief Matches block pointer types, i.e. types syntactically represented as
/// "void (^)(int)".
@@ -3073,7 +3148,10 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
///
/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
/// Matcher<PointerType>, Matcher<ReferenceType>
-AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
+AST_TYPELOC_TRAVERSE_MATCHER(
+ pointee, getPointee,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_4(BlockPointerType, MemberPointerType,
+ PointerType, ReferenceType));
/// \brief Matches typedef types.
///
@@ -3100,6 +3178,16 @@ AST_TYPE_MATCHER(TypedefType, typedefType);
/// instantiation in \c A and the type of the variable declaration in \c B.
AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType);
+/// \brief Matches types nodes representing unary type transformations.
+///
+/// Given:
+/// \code
+/// typedef __underlying_type(T) type;
+/// \endcode
+/// unaryTransformType()
+/// matches "__underlying_type(T)"
+AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType);
+
/// \brief Matches record types (e.g. structs, classes).
///
/// Given
@@ -3331,6 +3419,80 @@ AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, Stmt*, Other, 1) {
/// @}
+/// \brief Matches each case or default statement belonging to the given switch
+/// statement. This matcher may produce multiple matches.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+/// \endcode
+/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
+/// matches four times, with "c" binding each of "case 1:", "case 2:",
+/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)",
+/// "switch (1)", "switch (2)" and "switch (2)".
+AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
+ InnerMatcher) {
+ BoundNodesTreeBuilder Result;
+ // FIXME: getSwitchCaseList() does not necessarily guarantee a stable
+ // iteration order. We should use the more general iterating matchers once
+ // they are capable of expressing this matcher (for example, it should ignore
+ // case statements belonging to nested switch statements).
+ bool Matched = false;
+ for (const SwitchCase *SC = Node.getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ BoundNodesTreeBuilder CaseBuilder(*Builder);
+ bool CaseMatched = InnerMatcher.matches(*SC, Finder, &CaseBuilder);
+ if (CaseMatched) {
+ Matched = true;
+ Result.addMatch(CaseBuilder);
+ }
+ }
+ *Builder = Result;
+ return Matched;
+}
+
+/// \brief Matches each constructor initializer in a constructor definition.
+///
+/// Given
+/// \code
+/// class A { A() : i(42), j(42) {} int i; int j; };
+/// \endcode
+/// constructorDecl(forEachConstructorInitializer(forField(decl().bind("x"))))
+/// will trigger two matches, binding for 'i' and 'j' respectively.
+AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
+ internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
+ BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(),
+ E = Node.init_end();
+ I != E; ++I) {
+ BoundNodesTreeBuilder InitBuilder(*Builder);
+ if (InnerMatcher.matches(**I, Finder, &InitBuilder)) {
+ Matched = true;
+ Result.addMatch(InitBuilder);
+ }
+ }
+ *Builder = Result;
+ return Matched;
+}
+
+/// \brief If the given case statement does not use the GNU case range
+/// extension, matches the constant given in the statement.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+/// \endcode
+/// caseStmt(hasCaseConstant(integerLiteral()))
+/// matches "case 1:"
+AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
+ InnerMatcher) {
+ if (Node.getRHS())
+ return false;
+
+ return InnerMatcher.matches(*Node.getLHS(), Finder, Builder);
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 30691ad8f912..69cee2eb5dfd 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -36,12 +36,13 @@
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
#include "clang/AST/ASTTypeTraits.h"
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtCXX.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/VariadicFunction.h"
#include "llvm/Support/type_traits.h"
#include <map>
@@ -60,7 +61,6 @@ class BoundNodes;
namespace internal {
-class BoundNodesTreeBuilder;
/// \brief Internal version of BoundNodes. Holds all the bound nodes.
class BoundNodesMap {
public:
@@ -71,9 +71,6 @@ public:
void addNode(StringRef ID, const T* Node) {
NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node);
}
- void addNode(StringRef ID, ast_type_traits::DynTypedNode Node) {
- NodeMap[ID] = Node;
- }
/// \brief Returns the AST node bound to \c ID.
///
@@ -88,29 +85,39 @@ public:
return It->second.get<T>();
}
- /// \brief Copies all ID/Node pairs to BoundNodesTreeBuilder \c Builder.
- void copyTo(BoundNodesTreeBuilder *Builder) const;
+ ast_type_traits::DynTypedNode getNode(StringRef ID) const {
+ IDToNodeMap::const_iterator It = NodeMap.find(ID);
+ if (It == NodeMap.end()) {
+ return ast_type_traits::DynTypedNode();
+ }
+ return It->second;
+ }
- /// \brief Copies all ID/Node pairs to BoundNodesMap \c Other.
- void copyTo(BoundNodesMap *Other) const;
+ /// \brief Imposes an order on BoundNodesMaps.
+ bool operator<(const BoundNodesMap &Other) const {
+ return NodeMap < Other.NodeMap;
+ }
-private:
/// \brief A map from IDs to the bound nodes.
+ ///
+ /// 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;
+ const IDToNodeMap &getMap() const {
+ return NodeMap;
+ }
+
+private:
IDToNodeMap NodeMap;
};
-/// \brief A tree of bound nodes in match results.
-///
-/// If a match can contain multiple matches on the same node with different
-/// matching subexpressions, BoundNodesTree contains a branch for each of
-/// those matching subexpressions.
+/// \brief Creates BoundNodesTree objects.
///
-/// BoundNodesTree's are created during the matching process; when a match
-/// is found, we iterate over the tree and create a BoundNodes object containing
-/// the union of all bound nodes on the path from the root to a each leaf.
-class BoundNodesTree {
+/// The tree builder is used during the matching process to insert the bound
+/// nodes from the Id matcher.
+class BoundNodesTreeBuilder {
public:
/// \brief A visitor interface to visit all BoundNodes results for a
/// BoundNodesTree.
@@ -124,63 +131,36 @@ public:
virtual void visitMatch(const BoundNodes& BoundNodesView) = 0;
};
- BoundNodesTree();
-
- /// \brief Create a BoundNodesTree from pre-filled maps of bindings.
- BoundNodesTree(const BoundNodesMap& Bindings,
- const std::vector<BoundNodesTree> RecursiveBindings);
+ /// \brief Add a binding from an id to a node.
+ template <typename T> void setBinding(const std::string &Id, const T *Node) {
+ if (Bindings.empty())
+ Bindings.push_back(BoundNodesMap());
+ for (unsigned i = 0, e = Bindings.size(); i != e; ++i)
+ Bindings[i].addNode(Id, Node);
+ }
- /// \brief Adds all bound nodes to \c Builder.
- void copyTo(BoundNodesTreeBuilder* Builder) const;
+ /// \brief Adds a branch in the tree.
+ void addMatch(const BoundNodesTreeBuilder &Bindings);
/// \brief Visits all matches that this BoundNodesTree represents.
///
/// The ownership of 'ResultVisitor' remains at the caller.
void visitMatches(Visitor* ResultVisitor);
-private:
- void visitMatchesRecursively(
- Visitor* ResultVistior,
- const BoundNodesMap& AggregatedBindings);
-
- // FIXME: Find out whether we want to use different data structures here -
- // first benchmarks indicate that it doesn't matter though.
-
- BoundNodesMap Bindings;
-
- std::vector<BoundNodesTree> RecursiveBindings;
-};
-
-/// \brief Creates BoundNodesTree objects.
-///
-/// The tree builder is used during the matching process to insert the bound
-/// nodes from the Id matcher.
-class BoundNodesTreeBuilder {
-public:
- BoundNodesTreeBuilder();
-
- /// \brief Add a binding from an id to a node.
- template <typename T>
- void setBinding(const std::string &Id, const T *Node) {
- Bindings.addNode(Id, Node);
- }
- void setBinding(const std::string &Id, ast_type_traits::DynTypedNode Node) {
- Bindings.addNode(Id, Node);
+ template <typename ExcludePredicate>
+ bool removeBindings(const ExcludePredicate &Predicate) {
+ Bindings.erase(std::remove_if(Bindings.begin(), Bindings.end(), Predicate),
+ Bindings.end());
+ return !Bindings.empty();
}
- /// \brief Adds a branch in the tree.
- void addMatch(const BoundNodesTree& Bindings);
-
- /// \brief Returns a BoundNodes object containing all current bindings.
- BoundNodesTree build() const;
+ /// \brief Imposes an order on BoundNodesTreeBuilders.
+ bool operator<(const BoundNodesTreeBuilder &Other) const {
+ return Bindings < Other.Bindings;
+ }
private:
- BoundNodesTreeBuilder(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
- void operator=(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
-
- BoundNodesMap Bindings;
-
- std::vector<BoundNodesTree> RecursiveBindings;
+ SmallVector<BoundNodesMap, 16> Bindings;
};
class ASTMatchFinder;
@@ -225,24 +205,6 @@ private:
}
};
-/// \brief Base class for all matchers that works on a \c DynTypedNode.
-///
-/// Matcher implementations will check whether the \c DynTypedNode is
-/// convertible into the respecitve types and then do the actual match
-/// on the actual node, or return false if it is not convertible.
-class DynTypedMatcher {
-public:
- virtual ~DynTypedMatcher() {}
-
- /// \brief Returns true if the matcher matches the given \c DynNode.
- virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const = 0;
-
- /// \brief Returns a unique ID for the matcher.
- virtual uint64_t getID() const = 0;
-};
-
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
///
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
@@ -252,7 +214,7 @@ public:
/// operator rather than a type hierarchy to be able to templatize the
/// type hierarchy instead of spelling it out.
template <typename T>
-class Matcher : public DynTypedMatcher {
+class Matcher {
public:
/// \brief Takes ownership of the provided implementation pointer.
explicit Matcher(MatcherInterface<T> *Implementation)
@@ -282,7 +244,13 @@ public:
bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- return Implementation->matches(Node, Finder, Builder);
+ if (Implementation->matches(Node, Finder, Builder))
+ return true;
+ // Delete all bindings when a matcher does not match.
+ // This prevents unexpected exposure of bound nodes in unmatches
+ // branches of the match tree.
+ *Builder = BoundNodesTreeBuilder();
+ return false;
}
/// \brief Returns an ID that uniquely identifies the matcher.
@@ -292,15 +260,6 @@ public:
return reinterpret_cast<uint64_t>(Implementation.getPtr());
}
- /// \brief Returns whether the matcher matches on the given \c DynNode.
- virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- const T *Node = DynNode.get<T>();
- if (!Node) return false;
- return matches(*Node, Finder, Builder);
- }
-
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
/// Matcher<QualType>.
///
@@ -353,6 +312,217 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
return Matcher<T>(Implementation);
}
+template <typename T> class BindableMatcher;
+
+/// \brief Matcher that works on a \c DynTypedNode.
+///
+/// It is constructed from a \c Matcher<T> object and redirects most calls to
+/// underlying matcher.
+/// It checks whether the \c DynTypedNode is convertible into the type of the
+/// underlying matcher and then do the actual match on the actual node, or
+/// return false if it is not convertible.
+class DynTypedMatcher {
+public:
+ /// \brief Construct from a \c Matcher<T>. Copies the matcher.
+ template <typename T> inline DynTypedMatcher(const Matcher<T> &M);
+
+ /// \brief Construct from a bindable \c Matcher<T>. Copies the matcher.
+ ///
+ /// This version enables \c tryBind() on the \c DynTypedMatcher.
+ template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M);
+
+ /// \brief Returns true if the matcher matches the given \c DynNode.
+ bool matches(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const {
+ return Storage->matches(DynNode, Finder, Builder);
+ }
+
+ /// \brief Bind the specified \p ID to the matcher.
+ /// \return A new matcher with the \p ID bound to it if this matcher supports
+ /// binding. Otherwise, returns an empty \c Optional<>.
+ llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const {
+ return Storage->tryBind(ID);
+ }
+
+ /// \brief Returns a unique \p ID for the matcher.
+ uint64_t getID() const { return Storage->getID(); }
+
+ /// \brief Returns the type this matcher works on.
+ ///
+ /// \c matches() will always return false unless the node passed is of this
+ /// or a derived type.
+ ast_type_traits::ASTNodeKind getSupportedKind() const {
+ return Storage->getSupportedKind();
+ }
+
+ /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted
+ /// to a \c Matcher<T>.
+ ///
+ /// This method verifies that the underlying matcher in \c Other can process
+ /// nodes of types T.
+ template <typename T> bool canConvertTo() const {
+ return getSupportedKind().isBaseOf(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
+
+ /// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
+ ///
+ /// This method asserts that \c canConvertTo() is \c true. Callers
+ /// should call \c canConvertTo() first to make sure that \c this is
+ /// compatible with T.
+ template <typename T> Matcher<T> convertTo() const {
+ assert(canConvertTo<T>());
+ return unconditionalConvertTo<T>();
+ }
+
+ /// \brief Same as \c convertTo(), but does not check that the underlying
+ /// matcher can handle a value of T.
+ ///
+ /// If it is not compatible, then this matcher will never match anything.
+ template <typename T> Matcher<T> unconditionalConvertTo() const {
+ return Matcher<T>(new WrappedMatcher<T>(*this));
+ }
+
+private:
+ class MatcherStorage : public RefCountedBaseVPTR {
+ public:
+ MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID)
+ : SupportedKind(SupportedKind), ID(ID) {}
+ virtual ~MatcherStorage();
+
+ virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const = 0;
+
+ virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0;
+
+ ast_type_traits::ASTNodeKind getSupportedKind() const {
+ return SupportedKind;
+ }
+
+ uint64_t getID() const { return ID; }
+
+ private:
+ const ast_type_traits::ASTNodeKind SupportedKind;
+ const uint64_t ID;
+ };
+
+ /// \brief Typed implementation of \c MatcherStorage.
+ template <typename T> class TypedMatcherStorage;
+
+ /// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
+ template <typename T> class WrappedMatcher;
+
+ IntrusiveRefCntPtr<const MatcherStorage> Storage;
+};
+
+template <typename T>
+class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage {
+public:
+ TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind)
+ : MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
+ Other.getID()),
+ InnerMatcher(Other), AllowBind(AllowBind) {}
+
+ bool matches(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const
+ LLVM_OVERRIDE {
+ if (const T *Node = DynNode.get<T>()) {
+ return InnerMatcher.matches(*Node, Finder, Builder);
+ }
+ return false;
+ }
+
+ llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const LLVM_OVERRIDE {
+ if (!AllowBind)
+ return llvm::Optional<DynTypedMatcher>();
+ return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID));
+ }
+
+private:
+ const Matcher<T> InnerMatcher;
+ const bool AllowBind;
+};
+
+template <typename T>
+inline DynTypedMatcher::DynTypedMatcher(const Matcher<T> &M)
+ : Storage(new TypedMatcherStorage<T>(M, false)) {}
+
+template <typename T>
+inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M)
+ : Storage(new TypedMatcherStorage<T>(M, true)) {}
+
+template <typename T>
+class DynTypedMatcher::WrappedMatcher : public MatcherInterface<T> {
+public:
+ explicit WrappedMatcher(const DynTypedMatcher &Matcher) : Inner(Matcher) {}
+ virtual ~WrappedMatcher() {}
+
+ bool matches(const T &Node, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Inner.matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+ Builder);
+ }
+
+private:
+ const DynTypedMatcher Inner;
+};
+
+/// \brief Specialization of the conversion functions for QualType.
+///
+/// These specializations provide the Matcher<Type>->Matcher<QualType>
+/// conversion that the static API does.
+template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const {
+ const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
+ return SourceKind.isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
+ SourceKind.isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
+}
+
+template <>
+inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const {
+ assert(canConvertTo<QualType>());
+ const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
+ if (SourceKind.isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) {
+ // We support implicit conversion from Matcher<Type> to Matcher<QualType>
+ return unconditionalConvertTo<Type>();
+ }
+ return unconditionalConvertTo<QualType>();
+}
+
+/// \brief Finds the first node in a range that matches the given matcher.
+template <typename MatcherT, typename IteratorT>
+bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start,
+ IteratorT End, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) {
+ for (IteratorT I = Start; I != End; ++I) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (Matcher.matches(*I, Finder, &Result)) {
+ *Builder = Result;
+ return true;
+ }
+ }
+ return false;
+}
+
+/// \brief Finds the first node in a pointer range that matches the given
+/// matcher.
+template <typename MatcherT, typename IteratorT>
+bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
+ IteratorT End, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) {
+ for (IteratorT I = Start; I != End; ++I) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (Matcher.matches(**I, Finder, &Result)) {
+ *Builder = Result;
+ return true;
+ }
+ }
+ return false;
+}
+
/// \brief Metafunction to determine if type T has a member called getDecl.
template <typename T> struct has_getDecl {
struct Default { int getDecl; };
@@ -632,6 +802,94 @@ protected:
AncestorMatchMode MatchMode) = 0;
};
+/// \brief A type-list implementation.
+///
+/// A list is declared as a tree of type list nodes, where the leafs are the
+/// types.
+/// However, it is used as a "linked list" of types, by using the ::head and
+/// ::tail typedefs.
+/// Each node supports up to 4 children (instead of just 2) to reduce the
+/// nesting required by large lists.
+template <typename T1 = void, typename T2 = void, typename T3 = void,
+ typename T4 = void>
+struct TypeList {
+ /// \brief Implementation detail. Combined with the specializations below,
+ /// this typedef allows for flattening of nested structures.
+ typedef TypeList<T1, T2, T3, T4> self;
+
+ /// \brief The first type on the list.
+ typedef T1 head;
+
+ /// \brief A sub list with the tail. ie everything but the head.
+ ///
+ /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the
+ /// end of the list.
+ typedef typename TypeList<T2, T3, T4>::self tail;
+};
+
+/// \brief Template specialization to allow nested lists.
+///
+/// First element is a typelist. Pop its first element.
+template <typename Sub1, typename Sub2, typename Sub3, typename Sub4,
+ typename T2, typename T3, typename T4>
+struct TypeList<TypeList<Sub1, Sub2, Sub3, Sub4>, T2, T3,
+ T4> : public TypeList<Sub1,
+ typename TypeList<Sub2, Sub3, Sub4>::self,
+ typename TypeList<T2, T3, T4>::self> {};
+
+/// \brief Template specialization to allow nested lists.
+///
+/// First element is an empty typelist. Skip it.
+template <typename T2, typename T3, typename T4>
+struct TypeList<TypeList<>, T2, T3, T4> : public TypeList<T2, T3, T4> {
+};
+
+/// \brief The empty type list.
+typedef TypeList<> EmptyTypeList;
+
+/// \brief Helper meta-function to determine if some type \c T is present or
+/// a parent type in the list.
+template <typename AnyTypeList, typename T>
+struct TypeListContainsSuperOf {
+ static const bool value =
+ llvm::is_base_of<typename AnyTypeList::head, T>::value ||
+ TypeListContainsSuperOf<typename AnyTypeList::tail, T>::value;
+};
+template <typename T>
+struct TypeListContainsSuperOf<EmptyTypeList, T> {
+ static const bool value = false;
+};
+
+/// \brief A "type list" that contains all types.
+///
+/// Useful for matchers like \c anything and \c unless.
+typedef TypeList<
+ TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc>,
+ TypeList<QualType, Type, TypeLoc, CXXCtorInitializer> > AllNodeBaseTypes;
+
+/// \brief Helper meta-function to extract the argument out of a function of
+/// type void(Arg).
+///
+/// See AST_POLYMORPHIC_SUPPORTED_TYPES_* for details.
+template <class T> struct ExtractFunctionArgMeta;
+template <class T> struct ExtractFunctionArgMeta<void(T)> {
+ typedef T type;
+};
+
+/// \brief Default type lists for ArgumentAdaptingMatcher matchers.
+typedef AllNodeBaseTypes AdaptativeDefaultFromTypes;
+typedef TypeList<TypeList<Decl, Stmt, NestedNameSpecifier>,
+ TypeList<NestedNameSpecifierLoc, TypeLoc, QualType> >
+AdaptativeDefaultToTypes;
+
+/// \brief All types that are supported by HasDeclarationMatcher above.
+typedef TypeList<TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType>,
+ TypeList<InjectedClassNameType, LabelStmt, MemberExpr>,
+ TypeList<QualType, RecordType, TagType>,
+ TypeList<TemplateSpecializationType, TemplateTypeParmType,
+ TypedefType, UnresolvedUsingType> >
+HasDeclarationSupportedTypes;
+
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
/// "adapting" a \c To into a \c T.
///
@@ -646,19 +904,33 @@ protected:
/// If a matcher does not need knowledge about the inner type, prefer to use
/// PolymorphicMatcherWithParam1.
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
- typename T>
-class ArgumentAdaptingMatcher {
-public:
- explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
+ typename FromTypes = AdaptativeDefaultFromTypes,
+ typename ToTypes = AdaptativeDefaultToTypes>
+struct ArgumentAdaptingMatcherFunc {
+ template <typename T> class Adaptor {
+ public:
+ explicit Adaptor(const Matcher<T> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
- template <typename To>
- operator Matcher<To>() const {
- return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
+ typedef ToTypes ReturnTypes;
+
+ template <typename To> operator Matcher<To>() const {
+ return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
+ }
+
+ private:
+ const Matcher<T> InnerMatcher;
+ };
+
+ template <typename T>
+ static Adaptor<T> create(const Matcher<T> &InnerMatcher) {
+ return Adaptor<T>(InnerMatcher);
}
-private:
- const Matcher<T> InnerMatcher;
+ template <typename T>
+ Adaptor<T> operator()(const Matcher<T> &InnerMatcher) const {
+ return create(InnerMatcher);
+ }
};
/// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
@@ -673,24 +945,33 @@ private:
/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42)
/// creates an object that can be used as a Matcher<T> for any type T
/// where a ValueEqualsMatcher<T, int>(42) can be constructed.
-template <template <typename T> class MatcherT>
+template <template <typename T> class MatcherT,
+ typename ReturnTypesF = void(AllNodeBaseTypes)>
class PolymorphicMatcherWithParam0 {
public:
+ typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
template <typename T>
operator Matcher<T>() const {
+ TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
+ right_polymorphic_conversion);
return Matcher<T>(new MatcherT<T>());
}
};
template <template <typename T, typename P1> class MatcherT,
- typename P1>
+ typename P1,
+ typename ReturnTypesF = void(AllNodeBaseTypes)>
class PolymorphicMatcherWithParam1 {
public:
explicit PolymorphicMatcherWithParam1(const P1 &Param1)
: Param1(Param1) {}
+ typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+
template <typename T>
operator Matcher<T>() const {
+ TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
+ right_polymorphic_conversion);
return Matcher<T>(new MatcherT<T, P1>(Param1));
}
@@ -699,14 +980,19 @@ private:
};
template <template <typename T, typename P1, typename P2> class MatcherT,
- typename P1, typename P2>
+ typename P1, typename P2,
+ typename ReturnTypesF = void(AllNodeBaseTypes)>
class PolymorphicMatcherWithParam2 {
public:
PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
: Param1(Param1), Param2(Param2) {}
+ typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+
template <typename T>
operator Matcher<T>() const {
+ TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value),
+ right_polymorphic_conversion);
return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
}
@@ -737,27 +1023,6 @@ public:
}
};
-/// \brief Provides a MatcherInterface<T> for a Matcher<To> that matches if T is
-/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed
-/// node.
-template <typename T, typename To>
-class DynCastMatcher : public MatcherInterface<T> {
-public:
- explicit DynCastMatcher(const Matcher<To> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
-
- virtual bool matches(const T &Node,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- const To *InnerMatchValue = dyn_cast<To>(&Node);
- return InnerMatchValue != NULL &&
- InnerMatcher.matches(*InnerMatchValue, Finder, Builder);
- }
-
-private:
- const Matcher<To> InnerMatcher;
-};
-
/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
/// to an ID if the inner matcher matches on the node.
template <typename T>
@@ -790,7 +1055,8 @@ private:
template <typename T>
class BindableMatcher : public Matcher<T> {
public:
- BindableMatcher(MatcherInterface<T> *Implementation)
+ explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {}
+ explicit BindableMatcher(MatcherInterface<T> *Implementation)
: Matcher<T>(Implementation) {}
/// \brief Returns a matcher that will bind the matched node on a match.
@@ -867,108 +1133,172 @@ public:
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- return !InnerMatcher.matches(Node, Finder, Builder);
+ // The 'unless' matcher will always discard the result:
+ // If the inner matcher doesn't match, unless returns true,
+ // but the inner matcher cannot have bound anything.
+ // If the inner matcher matches, the result is false, and
+ // any possible binding will be discarded.
+ // We still need to hand in all the bound nodes up to this
+ // point so the inner matcher can depend on bound nodes,
+ // and we need to actively discard the bound nodes, otherwise
+ // the inner matcher will reset the bound nodes if it doesn't
+ // match, but this would be inversed by 'unless'.
+ BoundNodesTreeBuilder Discard(*Builder);
+ return !InnerMatcher.matches(Node, Finder, &Discard);
}
private:
const Matcher<T> InnerMatcher;
};
-/// \brief Matches nodes of type T for which both provided matchers match.
-///
-/// Type arguments MatcherT1 and MatcherT2 are required by
-/// PolymorphicMatcherWithParam2 but not actually used. They will
-/// always be instantiated with types convertible to Matcher<T>.
-template <typename T, typename MatcherT1, typename MatcherT2>
-class AllOfMatcher : public MatcherInterface<T> {
+/// \brief VariadicOperatorMatcher related types.
+/// @{
+
+/// \brief Function signature for any variadic operator. It takes the inner
+/// matchers as an array of DynTypedMatcher.
+typedef bool (*VariadicOperatorFunction)(
+ const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
+
+/// \brief \c MatcherInterface<T> implementation for an variadic operator.
+template <typename T>
+class VariadicOperatorMatcherInterface : public MatcherInterface<T> {
public:
- AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
- : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+ VariadicOperatorMatcherInterface(VariadicOperatorFunction Func,
+ ArrayRef<const Matcher<T> *> InputMatchers)
+ : Func(Func) {
+ for (size_t i = 0, e = InputMatchers.size(); i != e; ++i) {
+ InnerMatchers.push_back(*InputMatchers[i]);
+ }
+ }
- virtual bool matches(const T &Node,
- ASTMatchFinder *Finder,
+ virtual bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- return InnerMatcher1.matches(Node, Finder, Builder) &&
- InnerMatcher2.matches(Node, Finder, Builder);
+ return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder,
+ InnerMatchers);
}
private:
- const Matcher<T> InnerMatcher1;
- const Matcher<T> InnerMatcher2;
+ const VariadicOperatorFunction Func;
+ std::vector<DynTypedMatcher> InnerMatchers;
};
-/// \brief Matches nodes of type T for which at least one of the two provided
-/// matchers matches.
+/// \brief "No argument" placeholder to use as template paratemers.
+struct VariadicOperatorNoArg {};
+
+/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction
+/// operator.
///
-/// Type arguments MatcherT1 and MatcherT2 are
-/// required by PolymorphicMatcherWithParam2 but not actually
-/// used. They will always be instantiated with types convertible to
-/// Matcher<T>.
-template <typename T, typename MatcherT1, typename MatcherT2>
-class EachOfMatcher : public MatcherInterface<T> {
+/// Input matchers can have any type (including other polymorphic matcher
+/// types), and the actual Matcher<T> is generated on demand with an implicit
+/// coversion operator.
+template <typename P1, typename P2,
+ typename P3 = VariadicOperatorNoArg,
+ typename P4 = VariadicOperatorNoArg,
+ typename P5 = VariadicOperatorNoArg>
+class VariadicOperatorMatcher {
public:
- EachOfMatcher(const Matcher<T> &InnerMatcher1,
- const Matcher<T> &InnerMatcher2)
- : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {
+ VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1,
+ const P2 &Param2,
+ const P3 &Param3 = VariadicOperatorNoArg(),
+ const P4 &Param4 = VariadicOperatorNoArg(),
+ const P5 &Param5 = VariadicOperatorNoArg())
+ : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3),
+ Param4(Param4), Param5(Param5) {}
+
+ template <typename T> operator Matcher<T>() const {
+ Matcher<T> *Array[5];
+ size_t Size = 0;
+
+ addMatcher<T>(Param1, Array, Size);
+ addMatcher<T>(Param2, Array, Size);
+ addMatcher<T>(Param3, Array, Size);
+ addMatcher<T>(Param4, Array, Size);
+ addMatcher<T>(Param5, Array, Size);
+ Matcher<T> Result(new VariadicOperatorMatcherInterface<T>(
+ Func, ArrayRef<const Matcher<T> *>(Array, Size)));
+ for (size_t i = 0, e = Size; i != e; ++i) delete Array[i];
+ return Result;
}
- virtual bool matches(const T &Node, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- BoundNodesTreeBuilder Builder1;
- bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1);
- if (Matched1)
- Builder->addMatch(Builder1.build());
-
- BoundNodesTreeBuilder Builder2;
- bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2);
- if (Matched2)
- Builder->addMatch(Builder2.build());
-
- return Matched1 || Matched2;
+private:
+ template <typename T>
+ static void addMatcher(const Matcher<T> &M, Matcher<T> **Array,
+ size_t &Size) {
+ Array[Size++] = new Matcher<T>(M);
}
-private:
- const Matcher<T> InnerMatcher1;
- const Matcher<T> InnerMatcher2;
+ /// \brief Overload to ignore \c VariadicOperatorNoArg arguments.
+ template <typename T>
+ static void addMatcher(VariadicOperatorNoArg, Matcher<T> **Array,
+ size_t &Size) {}
+
+ const VariadicOperatorFunction Func;
+ const P1 Param1;
+ const P2 Param2;
+ const P3 Param3;
+ const P4 Param4;
+ const P5 Param5;
};
-/// \brief Matches nodes of type T for which at least one of the two provided
-/// matchers matches.
+/// \brief Overloaded function object to generate VariadicOperatorMatcher
+/// objects from arbitrary matchers.
///
-/// Type arguments MatcherT1 and MatcherT2 are
-/// required by PolymorphicMatcherWithParam2 but not actually
-/// used. They will always be instantiated with types convertible to
-/// Matcher<T>.
-template <typename T, typename MatcherT1, typename MatcherT2>
-class AnyOfMatcher : public MatcherInterface<T> {
-public:
- AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
- : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+/// It supports 2-5 argument overloaded operator(). More can be added if needed.
+struct VariadicOperatorMatcherFunc {
+ VariadicOperatorFunction Func;
- virtual bool matches(const T &Node,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return InnerMatcher1.matches(Node, Finder, Builder) ||
- InnerMatcher2.matches(Node, Finder, Builder);
+ template <typename M1, typename M2>
+ VariadicOperatorMatcher<M1, M2> operator()(const M1 &P1, const M2 &P2) const {
+ return VariadicOperatorMatcher<M1, M2>(Func, P1, P2);
+ }
+ template <typename M1, typename M2, typename M3>
+ VariadicOperatorMatcher<M1, M2, M3> operator()(const M1 &P1, const M2 &P2,
+ const M3 &P3) const {
+ return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3);
+ }
+ template <typename M1, typename M2, typename M3, typename M4>
+ VariadicOperatorMatcher<M1, M2, M3, M4>
+ operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
+ return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4);
+ }
+ template <typename M1, typename M2, typename M3, typename M4, typename M5>
+ VariadicOperatorMatcher<M1, M2, M3, M4, M5>
+ operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
+ const M5 &P5) const {
+ return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4,
+ P5);
}
-
-private:
- const Matcher<T> InnerMatcher1;
- const Matcher<T> InnerMatcher2;
};
+/// @}
+
+/// \brief Matches nodes for which all provided matchers match.
+bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+/// \brief Matches nodes for which at least one of the provided matchers
+/// matches, but doesn't stop at the first match.
+bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+/// \brief Matches nodes for which at least one of the provided matchers
+/// matches.
+bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
template<typename T>
BindableMatcher<T> makeAllOfComposite(
ArrayRef<const Matcher<T> *> InnerMatchers) {
- if (InnerMatchers.empty())
- return BindableMatcher<T>(new TrueMatcher<T>);
- MatcherInterface<T> *InnerMatcher = new TrueMatcher<T>;
- for (int i = InnerMatchers.size() - 1; i >= 0; --i) {
- InnerMatcher = new AllOfMatcher<T, Matcher<T>, Matcher<T> >(
- *InnerMatchers[i], makeMatcher(InnerMatcher));
- }
- return BindableMatcher<T>(InnerMatcher);
+ return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>(
+ AllOfVariadicOperator, InnerMatchers));
}
/// \brief Creates a Matcher<T> that matches if
@@ -980,8 +1310,8 @@ BindableMatcher<T> makeAllOfComposite(
template<typename T, typename InnerT>
BindableMatcher<T> makeDynCastAllOfComposite(
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
- return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(
- makeAllOfComposite(InnerMatchers)));
+ return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers))
+ .unconditionalConvertTo<T>());
}
/// \brief Matches nodes of type T that have at least one descendant node of
@@ -1233,9 +1563,53 @@ private:
TypeLoc (T::*TraverseFunction)() const;
};
-template <typename T, typename InnerT>
-T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
- return T(makeAllOfComposite<InnerT>(InnerMatchers));
+/// \brief Converts a \c Matcher<InnerT> to a \c Matcher<OuterT>, where
+/// \c OuterT is any type that is supported by \c Getter.
+///
+/// \code Getter<OuterT>::value() \endcode returns a
+/// \code InnerTBase (OuterT::*)() \endcode, which is used to adapt a \c OuterT
+/// object into a \c InnerT
+template <typename InnerTBase,
+ template <typename OuterT> class Getter,
+ template <typename OuterT> class MatcherImpl,
+ typename ReturnTypesF>
+class TypeTraversePolymorphicMatcher {
+private:
+ typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl,
+ ReturnTypesF> Self;
+ static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers);
+
+public:
+ typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+
+ explicit TypeTraversePolymorphicMatcher(
+ ArrayRef<const Matcher<InnerTBase> *> InnerMatchers)
+ : InnerMatcher(makeAllOfComposite(InnerMatchers)) {}
+
+ template <typename OuterT> operator Matcher<OuterT>() const {
+ return Matcher<OuterT>(
+ new MatcherImpl<OuterT>(InnerMatcher, Getter<OuterT>::value()));
+ }
+
+ struct Func : public llvm::VariadicFunction<Self, Matcher<InnerTBase>,
+ &Self::create> {
+ Func() {}
+ };
+
+private:
+ const Matcher<InnerTBase> InnerMatcher;
+};
+
+// Define the create() method out of line to silence a GCC warning about
+// the struct "Func" having greater visibility than its base, which comes from
+// using the flag -fvisibility-inlines-hidden.
+template <typename InnerTBase, template <typename OuterT> class Getter,
+ template <typename OuterT> class MatcherImpl, typename ReturnTypesF>
+TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, ReturnTypesF>
+TypeTraversePolymorphicMatcher<
+ InnerTBase, Getter, MatcherImpl,
+ ReturnTypesF>::create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) {
+ return Self(InnerMatchers);
}
} // end namespace internal
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index f5ca26bca73c..b5d530312515 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -49,23 +49,19 @@
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER(Type, DefineMatcher) \
- AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0)
-
-#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId) \
namespace internal { \
- class matcher_##DefineMatcher##OverloadId##Matcher \
- : public MatcherInterface<Type> { \
+ class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> { \
public: \
- explicit matcher_##DefineMatcher##OverloadId##Matcher() {} \
+ explicit matcher_##DefineMatcher##Matcher() {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
}; \
} \
inline internal::Matcher<Type> DefineMatcher() { \
return internal::makeMatcher( \
- new internal::matcher_##DefineMatcher##OverloadId##Matcher()); \
+ new internal::matcher_##DefineMatcher##Matcher()); \
} \
- inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
+ inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -93,10 +89,10 @@
public: \
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
const ParamType &A##Param) \
- : Param(A##Param) { \
- } \
+ : Param(A##Param) {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType Param; \
}; \
@@ -105,6 +101,8 @@
return internal::makeMatcher( \
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \
} \
+ typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType &Param); \
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -136,53 +134,70 @@
public: \
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) { \
- } \
+ : Param1(A##Param1), Param2(A##Param2) {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
}; \
} \
- inline internal::Matcher<Type> \
- DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
+ inline internal::Matcher<Type> DefineMatcher(const ParamType1 &Param1, \
+ const ParamType2 &Param2) { \
return internal::makeMatcher( \
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \
Param2)); \
} \
+ typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType1 &Param1, const ParamType2 &Param2); \
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
+/// \brief Construct a type-list to be passed to the AST_POLYMORPHIC_MATCHER*
+/// macros.
+///
+/// You can't pass something like \c TypeList<Foo, Bar> to a macro, because it
+/// will look at that as two arguments. However, you can pass
+/// \c void(TypeList<Foo, Bar>), which works thanks to the parenthesis.
+/// The \c PolymorphicMatcherWithParam* classes will unpack the function type to
+/// extract the TypeList object.
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_1(t1) void(internal::TypeList<t1>)
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_2(t1, t2) \
+ void(internal::TypeList<t1, t2>)
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_3(t1, t2, t3) \
+ void(internal::TypeList<t1, t2, t3>)
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_4(t1, t2, t3, t4) \
+ void(internal::TypeList<t1, t2, t3, t4>)
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_5(t1, t2, t3, t4, t5) \
+ void(internal::TypeList<t1, t2, t3, internal::TypeList<t4, t5> >)
+
/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... }
/// defines a single-parameter function named DefineMatcher() that is
/// polymorphic in the return type.
///
/// The variables are the same as for AST_MATCHER, but NodeType will be deduced
/// from the calling context.
-#define AST_POLYMORPHIC_MATCHER(DefineMatcher) \
- AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, 0)
-
-#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, OverloadId) \
+#define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF) \
namespace internal { \
template <typename NodeType> \
- class matcher_##DefineMatcher##OverloadId##Matcher \
- : public MatcherInterface<NodeType> { \
+ class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \
public: \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
}; \
} \
inline internal::PolymorphicMatcherWithParam0< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher> DefineMatcher() {\
+ internal::matcher_##DefineMatcher##Matcher, ReturnTypesF> \
+ DefineMatcher() { \
return internal::PolymorphicMatcherWithParam0< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher>(); \
+ internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>(); \
} \
template <typename NodeType> \
- bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
- NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const
+ bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
/// defines a single-parameter function named DefineMatcher() that is
@@ -193,11 +208,13 @@
/// of the matcher Matcher<NodeType> returned by the function matcher().
///
/// FIXME: Pull out common code with above macro?
-#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \
- AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, 0)
+#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ReturnTypesF, ParamType, \
+ Param) \
+ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType, \
+ Param, 0)
-#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, \
- OverloadId) \
+#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, \
+ ParamType, Param, OverloadId) \
namespace internal { \
template <typename NodeType, typename ParamT> \
class matcher_##DefineMatcher##OverloadId##Matcher \
@@ -205,21 +222,25 @@
public: \
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
const ParamType &A##Param) \
- : Param(A##Param) { \
- } \
+ : Param(A##Param) {} \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType Param; \
}; \
} \
inline internal::PolymorphicMatcherWithParam1< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType> \
- DefineMatcher(const ParamType &Param) { \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
+ ReturnTypesF> DefineMatcher(const ParamType &Param) { \
return internal::PolymorphicMatcherWithParam1< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType>( \
- Param); \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
+ ReturnTypesF>(Param); \
} \
+ typedef internal::PolymorphicMatcherWithParam1< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
+ ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType &Param); \
template <typename NodeType, typename ParamT> \
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
@@ -233,13 +254,14 @@
/// The variables are the same as for AST_MATCHER_P2, with the
/// addition of NodeType, which specifies the node type of the matcher
/// Matcher<NodeType> returned by the function DefineMatcher().
-#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ParamType1, Param1, \
- ParamType2, Param2) \
- AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \
- ParamType2, Param2, 0)
+#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ReturnTypesF, ParamType1, \
+ Param1, ParamType2, Param2) \
+ AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType1, \
+ Param1, ParamType2, Param2, 0)
-#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \
- ParamType2, Param2, OverloadId) \
+#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, \
+ ParamType1, Param1, ParamType2, \
+ Param2, OverloadId) \
namespace internal { \
template <typename NodeType, typename ParamT1, typename ParamT2> \
class matcher_##DefineMatcher##OverloadId##Matcher \
@@ -247,10 +269,10 @@
public: \
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) { \
- } \
+ : Param1(A##Param1), Param2(A##Param2) {} \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
@@ -258,12 +280,16 @@
} \
inline internal::PolymorphicMatcherWithParam2< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
- ParamType2> \
- DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
+ ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 &Param1, \
+ const ParamType2 &Param2) { \
return internal::PolymorphicMatcherWithParam2< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
- ParamType2>(Param1, Param2); \
+ ParamType2, ReturnTypesF>(Param1, Param2); \
} \
+ typedef internal::PolymorphicMatcherWithParam2< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
+ ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType1 &Param1, const ParamType2 &Param2); \
template <typename NodeType, typename ParamT1, typename ParamT2> \
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
NodeType, ParamT1, ParamT2>::matches( \
@@ -282,64 +308,29 @@
/// to another.
///
/// For a specific \c SpecificType, the traversal is done using
-/// \c SpecificType::FunctionName. The existance of such a function determines
+/// \c SpecificType::FunctionName. The existence of such a function determines
/// whether a corresponding matcher can be used on \c SpecificType.
-#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \
- class Polymorphic##MatcherName##TypeMatcher { \
- public: \
- Polymorphic##MatcherName##TypeMatcher( \
- const internal::Matcher<QualType> &InnerMatcher) \
- : InnerMatcher(InnerMatcher) { \
- } \
- template <typename T> operator internal:: Matcher< T>() { \
- return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
- InnerMatcher, &T::FunctionName)); \
- } \
- private: \
- const internal::Matcher<QualType> InnerMatcher; \
- } \
- ; \
- class Variadic##MatcherName##TypeTraverseMatcher \
- : public llvm::VariadicFunction< \
- Polymorphic##MatcherName##TypeMatcher, internal::Matcher<QualType>, \
- internal::makeTypeAllOfComposite< \
- Polymorphic##MatcherName##TypeMatcher, QualType> > { \
- public: \
- Variadic##MatcherName##TypeTraverseMatcher() { \
- } \
+#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \
+ namespace internal { \
+ template <typename T> struct TypeMatcher##MatcherName##Getter { \
+ static QualType (T::*value())() const { return &T::FunctionName; } \
+ }; \
} \
- ; \
- const Variadic##MatcherName##TypeTraverseMatcher MatcherName
+ const internal::TypeTraversePolymorphicMatcher< \
+ QualType, internal::TypeMatcher##MatcherName##Getter, \
+ internal::TypeTraverseMatcher, ReturnTypesF>::Func MatcherName
/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
-#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \
- class Polymorphic##MatcherName##TypeLocMatcher { \
- public: \
- Polymorphic##MatcherName##TypeLocMatcher( \
- const internal::Matcher<TypeLoc> &InnerMatcher) \
- : InnerMatcher(InnerMatcher) { \
- } \
- template <typename T> operator internal:: Matcher< T>() { \
- return internal::Matcher<T>( \
- new internal::TypeLocTraverseMatcher<T>(InnerMatcher, \
- &T::FunctionName##Loc)); \
- } \
- private: \
- const internal::Matcher<TypeLoc> InnerMatcher; \
- } \
- ; \
- class Variadic##MatcherName##TypeLocTraverseMatcher \
- : public llvm::VariadicFunction< \
- Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher<TypeLoc>,\
- internal::makeTypeAllOfComposite< \
- Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
- public: \
- Variadic##MatcherName##TypeLocTraverseMatcher() { \
- } \
+#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \
+ namespace internal { \
+ template <typename T> struct TypeLocMatcher##MatcherName##Getter { \
+ static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \
+ }; \
} \
- ; \
- const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
- AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
+ const internal::TypeTraversePolymorphicMatcher< \
+ TypeLoc, internal::TypeLocMatcher##MatcherName##Getter, \
+ internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \
+ AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF)
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
new file mode 100644
index 000000000000..aec0c0e31ce2
--- /dev/null
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -0,0 +1,185 @@
+//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Diagnostics class to manage error messages.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+struct SourceLocation {
+ SourceLocation() : Line(), Column() {}
+ unsigned Line;
+ unsigned Column;
+};
+
+struct SourceRange {
+ SourceLocation Start;
+ SourceLocation End;
+};
+
+/// \brief A VariantValue instance annotated with its parser context.
+struct ParserValue {
+ ParserValue() : Text(), Range(), Value() {}
+ StringRef Text;
+ SourceRange Range;
+ VariantValue Value;
+};
+
+/// \brief Helper class to manage error messages.
+class Diagnostics {
+public:
+ /// \brief Parser context types.
+ enum ContextType {
+ CT_MatcherArg = 0,
+ CT_MatcherConstruct = 1
+ };
+
+ /// \brief All errors from the system.
+ enum ErrorType {
+ ET_None = 0,
+
+ ET_RegistryNotFound = 1,
+ ET_RegistryWrongArgCount = 2,
+ ET_RegistryWrongArgType = 3,
+ ET_RegistryNotBindable = 4,
+ ET_RegistryAmbiguousOverload = 5,
+
+ ET_ParserStringError = 100,
+ ET_ParserNoOpenParen = 101,
+ ET_ParserNoCloseParen = 102,
+ ET_ParserNoComma = 103,
+ ET_ParserNoCode = 104,
+ ET_ParserNotAMatcher = 105,
+ ET_ParserInvalidToken = 106,
+ ET_ParserMalformedBindExpr = 107,
+ ET_ParserTrailingCode = 108,
+ ET_ParserUnsignedError = 109,
+ ET_ParserOverloadedType = 110
+ };
+
+ /// \brief Helper stream class.
+ class ArgStream {
+ public:
+ ArgStream(std::vector<std::string> *Out) : Out(Out) {}
+ template <class T> ArgStream &operator<<(const T &Arg) {
+ return operator<<(Twine(Arg));
+ }
+ ArgStream &operator<<(const Twine &Arg);
+
+ private:
+ std::vector<std::string> *Out;
+ };
+
+ /// \brief Class defining a parser context.
+ ///
+ /// Used by the parser to specify (possibly recursive) contexts where the
+ /// parsing/construction can fail. Any error triggered within a context will
+ /// keep information about the context chain.
+ /// This class should be used as a RAII instance in the stack.
+ struct Context {
+ public:
+ /// \brief About to call the constructor for a matcher.
+ enum ConstructMatcherEnum { ConstructMatcher };
+ Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName,
+ const SourceRange &MatcherRange);
+ /// \brief About to recurse into parsing one argument for a matcher.
+ enum MatcherArgEnum { MatcherArg };
+ Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName,
+ const SourceRange &MatcherRange, unsigned ArgNumber);
+ ~Context();
+
+ private:
+ Diagnostics *const Error;
+ };
+
+ /// \brief Context for overloaded matcher construction.
+ ///
+ /// This context will take care of merging all errors that happen within it
+ /// as "candidate" overloads for the same matcher.
+ struct OverloadContext {
+ public:
+ OverloadContext(Diagnostics* Error);
+ ~OverloadContext();
+
+ /// \brief Revert all errors that happened within this context.
+ void revertErrors();
+
+ private:
+ Diagnostics *const Error;
+ unsigned BeginIndex;
+ };
+
+ /// \brief Add an error to the diagnostics.
+ ///
+ /// All the context information will be kept on the error message.
+ /// \return a helper class to allow the caller to pass the arguments for the
+ /// error message, using the << operator.
+ ArgStream addError(const SourceRange &Range, ErrorType Error);
+
+ /// \brief Information stored for one frame of the context.
+ struct ContextFrame {
+ ContextType Type;
+ SourceRange Range;
+ std::vector<std::string> Args;
+ };
+
+ /// \brief Information stored for each error found.
+ struct ErrorContent {
+ std::vector<ContextFrame> ContextStack;
+ struct Message {
+ SourceRange Range;
+ ErrorType Type;
+ std::vector<std::string> Args;
+ };
+ std::vector<Message> Messages;
+ };
+ ArrayRef<ErrorContent> errors() const { return Errors; }
+
+ /// \brief Returns a simple string representation of each error.
+ ///
+ /// Each error only shows the error message without any context.
+ void printToStream(llvm::raw_ostream &OS) const;
+ std::string toString() const;
+
+ /// \brief Returns the full string representation of each error.
+ ///
+ /// Each error message contains the full context.
+ void printToStreamFull(llvm::raw_ostream &OS) const;
+ std::string toStringFull() const;
+
+private:
+ /// \brief Helper function used by the constructors of ContextFrame.
+ ArgStream pushContextFrame(ContextType Type, SourceRange Range);
+
+ std::vector<ContextFrame> ContextStack;
+ std::vector<ErrorContent> Errors;
+};
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
new file mode 100644
index 000000000000..bb6ac76989d0
--- /dev/null
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -0,0 +1,151 @@
+//===--- Parser.h - Matcher expression parser -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Simple matcher expression parser.
+///
+/// The parser understands matcher expressions of the form:
+/// MatcherName(Arg0, Arg1, ..., ArgN)
+/// as well as simple types like strings.
+/// The parser does not know how to process the matchers. It delegates this task
+/// to a Sema object received as an argument.
+///
+/// \code
+/// Grammar for the expressions supported:
+/// <Expression> := <Literal> | <MatcherExpression>
+/// <Literal> := <StringLiteral> | <Unsigned>
+/// <StringLiteral> := "quoted string"
+/// <Unsigned> := [0-9]+
+/// <MatcherExpression> := <MatcherName>(<ArgumentList>) |
+/// <MatcherName>(<ArgumentList>).bind(<StringLiteral>)
+/// <MatcherName> := [a-zA-Z]+
+/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
+/// \endcode
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+
+#include "clang/ASTMatchers/Dynamic/Diagnostics.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/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+/// \brief Matcher expression parser.
+class Parser {
+public:
+ /// \brief Interface to connect the parser with the registry and more.
+ ///
+ /// The parser uses the Sema instance passed into
+ /// parseMatcherExpression() to handle all matcher tokens. The simplest
+ /// processor implementation would simply call into the registry to create
+ /// the matchers.
+ /// However, a more complex processor might decide to intercept the matcher
+ /// creation and do some extra work. For example, it could apply some
+ /// transformation to the matcher by adding some id() nodes, or could detect
+ /// specific matcher nodes for more efficient lookup.
+ class Sema {
+ public:
+ virtual ~Sema();
+
+ /// \brief Process a matcher expression.
+ ///
+ /// All the arguments passed here have already been processed.
+ ///
+ /// \param MatcherName The matcher name found by the parser.
+ ///
+ /// \param NameRange The location of the name in the matcher source.
+ /// Useful for error reporting.
+ ///
+ /// \param BindID The ID to use to bind the matcher, or a null \c StringRef
+ /// if no ID is specified.
+ ///
+ /// \param Args The argument list for the matcher.
+ ///
+ /// \return The matcher objects constructed by the processor, or a null
+ /// matcher if an error occurred. In that case, \c Error will contain a
+ /// description of the error.
+ virtual VariantMatcher actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) = 0;
+ };
+
+ /// \brief Parse a matcher expression, creating matchers from the registry.
+ ///
+ /// This overload creates matchers calling directly into the registry. If the
+ /// caller needs more control over how the matchers are created, then it can
+ /// use the overload below that takes a Sema.
+ ///
+ /// \param MatcherCode The matcher expression to parse.
+ ///
+ /// \return The matcher object constructed, or an empty Optional if an error
+ /// occurred.
+ /// In that case, \c Error will contain a description of the error.
+ /// The caller takes ownership of the DynTypedMatcher object returned.
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error);
+
+ /// \brief Parse a matcher expression.
+ ///
+ /// \param MatcherCode The matcher expression to parse.
+ ///
+ /// \param S The Sema instance that will help the parser
+ /// construct the matchers.
+ /// \return The matcher object constructed by the processor, or an empty
+ /// Optional if an error occurred. In that case, \c Error will contain a
+ /// description of the error.
+ /// The caller takes ownership of the DynTypedMatcher object returned.
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error);
+
+ /// \brief Parse an expression, creating matchers from the registry.
+ ///
+ /// Parses any expression supported by this parser. In general, the
+ /// \c parseMatcherExpression function is a better approach to get a matcher
+ /// object.
+ static bool parseExpression(StringRef Code, VariantValue *Value,
+ Diagnostics *Error);
+
+ /// \brief Parse an expression.
+ ///
+ /// Parses any expression supported by this parser. In general, the
+ /// \c parseMatcherExpression function is a better approach to get a matcher
+ /// object.
+ static bool parseExpression(StringRef Code, Sema *S,
+ VariantValue *Value, Diagnostics *Error);
+
+private:
+ class CodeTokenizer;
+ struct TokenInfo;
+
+ Parser(CodeTokenizer *Tokenizer, Sema *S,
+ Diagnostics *Error);
+
+ bool parseExpressionImpl(VariantValue *Value);
+ bool parseMatcherExpressionImpl(VariantValue *Value);
+
+ CodeTokenizer *const Tokenizer;
+ Sema *const S;
+ Diagnostics *const Error;
+};
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h
new file mode 100644
index 000000000000..c113c1404ef0
--- /dev/null
+++ b/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -0,0 +1,75 @@
+//===--- Registry.h - Matcher registry -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// 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_AST_MATCHERS_DYNAMIC_REGISTRY_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
+
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+class Registry {
+public:
+ /// \brief Construct a matcher from the registry by name.
+ ///
+ /// Consult the registry of known matchers and construct the appropriate
+ /// matcher by name.
+ ///
+ /// \param MatcherName The name of the matcher to instantiate.
+ ///
+ /// \param NameRange The location of the name in the matcher source.
+ /// Useful for error reporting.
+ ///
+ /// \param Args The argument list for the matcher. The number and types of the
+ /// values must be valid for the matcher requested. Otherwise, the function
+ /// will return an error.
+ ///
+ /// \return The matcher object constructed if no error was found.
+ /// A null matcher if the matcher is not found, or if the number of
+ /// arguments or argument types do not match the signature.
+ /// In that case \c Error will contain the description of the error.
+ static VariantMatcher constructMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
+
+ /// \brief Construct a matcher from the registry and bind it.
+ ///
+ /// Similar the \c constructMatcher() above, but it then tries to bind the
+ /// matcher to the specified \c BindID.
+ /// If the matcher is not bindable, it sets an error in \c Error and returns
+ /// a null matcher.
+ static VariantMatcher constructBoundMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
+
+private:
+ Registry() LLVM_DELETED_FUNCTION;
+};
+
+} // 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
new file mode 100644
index 000000000000..b9bc017a48c0
--- /dev/null
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -0,0 +1,261 @@
+//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Polymorphic value type.
+///
+/// Supports all the types required for dynamic Matcher construction.
+/// Used by the registry to construct matchers in a generic way.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
+
+#include <vector>
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+using ast_matchers::internal::DynTypedMatcher;
+
+/// \brief A variant matcher object.
+///
+/// The purpose of this object is to abstract simple and polymorphic matchers
+/// into a single object type.
+/// Polymorphic matchers might be implemented as a list of all the possible
+/// overloads of the matcher. \c VariantMatcher knows how to select the
+/// appropriate overload when needed.
+/// To get a real matcher object out of a \c VariantMatcher you can do:
+/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous
+/// to decide which matcher to return. Eg. it contains only a single
+/// matcher, or a polymorphic one with only one overload.
+/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
+/// the underlying matcher(s) can unambiguously return a Matcher<T>.
+class VariantMatcher {
+ /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher.
+ class MatcherOps {
+ public:
+ virtual ~MatcherOps();
+ virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0;
+ virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
+ virtual void constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> InnerMatchers) = 0;
+ };
+
+ /// \brief Payload interface to be specialized by each matcher type.
+ ///
+ /// It follows a similar interface as VariantMatcher itself.
+ class Payload : public RefCountedBaseVPTR {
+ public:
+ virtual ~Payload();
+ virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
+ virtual std::string getTypeAsString() const = 0;
+ virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
+ };
+
+public:
+ /// \brief A null matcher.
+ VariantMatcher();
+
+ /// \brief Clones the provided matcher.
+ static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher);
+
+ /// \brief Clones the provided matchers.
+ ///
+ /// They should be the result of a polymorphic matcher.
+ static VariantMatcher PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers);
+
+ /// \brief Creates a 'variadic' operator matcher.
+ ///
+ /// It will bind to the appropriate type on getTypedMatcher<T>().
+ static VariantMatcher VariadicOperatorMatcher(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args);
+
+ /// \brief Makes the matcher the "null" matcher.
+ void reset();
+
+ /// \brief Whether the matcher is null.
+ bool isNull() const { return !Value; }
+
+ /// \brief Return a single matcher, if there is no ambiguity.
+ ///
+ /// \returns the matcher, if there is only one matcher. An empty Optional, if
+ /// the underlying matcher is a polymorphic matcher with more than one
+ /// representation.
+ llvm::Optional<DynTypedMatcher> getSingleMatcher() const;
+
+ /// \brief Determines if the contained matcher can be converted to
+ /// \c Matcher<T>.
+ ///
+ /// For the Single case, it returns true if it can be converted to
+ /// \c Matcher<T>.
+ /// For the Polymorphic case, it returns true if one, and only one, of the
+ /// overloads can be converted to \c Matcher<T>. If there are more than one
+ /// that can, the result would be ambiguous and false is returned.
+ template <class T>
+ bool hasTypedMatcher() const {
+ TypedMatcherOps<T> Ops;
+ if (Value) Value->makeTypedMatcher(Ops);
+ return Ops.hasMatcher();
+ }
+
+ /// \brief Return this matcher as a \c Matcher<T>.
+ ///
+ /// Handles the different types (Single, Polymorphic) accordingly.
+ /// Asserts that \c hasTypedMatcher<T>() is true.
+ template <class T>
+ ast_matchers::internal::Matcher<T> getTypedMatcher() const {
+ TypedMatcherOps<T> Ops;
+ Value->makeTypedMatcher(Ops);
+ assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
+ return Ops.matcher();
+ }
+
+ /// \brief String representation of the type of the value.
+ ///
+ /// If the underlying matcher is a polymorphic one, the string will show all
+ /// the types.
+ std::string getTypeAsString() const;
+
+private:
+ explicit VariantMatcher(Payload *Value) : Value(Value) {}
+
+ class SinglePayload;
+ class PolymorphicPayload;
+ class VariadicOpPayload;
+
+ template <typename T>
+ class TypedMatcherOps : public MatcherOps {
+ public:
+ typedef ast_matchers::internal::Matcher<T> MatcherT;
+
+ virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
+ return Matcher.canConvertTo<T>();
+ }
+
+ virtual void constructFrom(const DynTypedMatcher& Matcher) {
+ Out.reset(new MatcherT(Matcher.convertTo<T>()));
+ }
+
+ virtual void constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> InnerMatchers) {
+ const size_t NumArgs = InnerMatchers.size();
+ MatcherT **InnerArgs = new MatcherT *[NumArgs]();
+ bool HasError = false;
+ for (size_t i = 0; i != NumArgs; ++i) {
+ // Abort if any of the inner matchers can't be converted to
+ // Matcher<T>.
+ if (!InnerMatchers[i].hasTypedMatcher<T>()) {
+ HasError = true;
+ break;
+ }
+ InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher<T>());
+ }
+ if (!HasError) {
+ Out.reset(new MatcherT(
+ new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
+ Func, ArrayRef<const MatcherT *>(InnerArgs, NumArgs))));
+ }
+ for (size_t i = 0; i != NumArgs; ++i) {
+ delete InnerArgs[i];
+ }
+ delete[] InnerArgs;
+ }
+
+ bool hasMatcher() const { return Out.get() != NULL; }
+ const MatcherT &matcher() const { return *Out; }
+
+ private:
+ OwningPtr<MatcherT> Out;
+ };
+
+ IntrusiveRefCntPtr<const Payload> Value;
+};
+
+/// \brief Variant value class.
+///
+/// Basically, a tagged union with value type semantics.
+/// It is used by the registry as the return value and argument type for the
+/// matcher factory methods.
+/// It can be constructed from any of the supported types. It supports
+/// copy/assignment.
+///
+/// Supported types:
+/// - \c unsigned
+/// - \c std::string
+/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
+class VariantValue {
+public:
+ VariantValue() : Type(VT_Nothing) {}
+
+ VariantValue(const VariantValue &Other);
+ ~VariantValue();
+ VariantValue &operator=(const VariantValue &Other);
+
+ /// \brief Specific constructors for each supported type.
+ VariantValue(unsigned Unsigned);
+ VariantValue(const std::string &String);
+ VariantValue(const VariantMatcher &Matchers);
+
+ /// \brief Unsigned value functions.
+ bool isUnsigned() const;
+ unsigned getUnsigned() const;
+ void setUnsigned(unsigned Unsigned);
+
+ /// \brief String value functions.
+ bool isString() const;
+ const std::string &getString() const;
+ void setString(const std::string &String);
+
+ /// \brief Matcher value functions.
+ bool isMatcher() const;
+ const VariantMatcher &getMatcher() const;
+ void setMatcher(const VariantMatcher &Matcher);
+
+ /// \brief String representation of the type of the value.
+ std::string getTypeAsString() const;
+
+private:
+ void reset();
+
+ /// \brief All supported value types.
+ enum ValueType {
+ VT_Nothing,
+ VT_Unsigned,
+ VT_String,
+ VT_Matcher
+ };
+
+ /// \brief All supported value types.
+ union AllValues {
+ unsigned Unsigned;
+ std::string *String;
+ VariantMatcher *Matcher;
+ };
+
+ ValueType Type;
+ AllValues Value;
+};
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h
new file mode 100644
index 000000000000..23a094a79643
--- /dev/null
+++ b/include/clang/Analysis/Analyses/Consumed.h
@@ -0,0 +1,264 @@
+//===- Consumed.h ----------------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A intra-procedural analysis for checking consumed properties. This is based,
+// in part, on research on linear types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CONSUMED_H
+#define LLVM_CLANG_CONSUMED_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+namespace consumed {
+
+ enum ConsumedState {
+ // No state information for the given variable.
+ CS_None,
+
+ CS_Unknown,
+ CS_Unconsumed,
+ CS_Consumed
+ };
+
+ class ConsumedStmtVisitor;
+
+ typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
+ typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
+ typedef std::list<DelayedDiag> DiagList;
+
+ class ConsumedWarningsHandlerBase {
+
+ public:
+
+ virtual ~ConsumedWarningsHandlerBase();
+
+ /// \brief Emit the warnings and notes left by the analysis.
+ virtual void emitDiagnostics() {}
+
+ /// \brief Warn that a variable's state doesn't match at the entry and exit
+ /// of a loop.
+ ///
+ /// \param Loc -- The location of the end of the loop.
+ ///
+ /// \param VariableName -- The name of the variable that has a mismatched
+ /// state.
+ virtual void warnLoopStateMismatch(SourceLocation Loc,
+ StringRef VariableName) {}
+
+ /// \brief Warn about parameter typestate mismatches upon return.
+ ///
+ /// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
+ virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {};
+
+ // FIXME: Add documentation.
+ virtual void warnParamTypestateMismatch(SourceLocation LOC,
+ StringRef ExpectedState,
+ StringRef ObservedState) {}
+
+ // FIXME: This can be removed when the attr propagation fix for templated
+ // classes lands.
+ /// \brief Warn about return typestates set for unconsumable types.
+ ///
+ /// \param Loc -- The location of the attributes.
+ ///
+ /// \param TypeName -- The name of the unconsumable type.
+ virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
+ StringRef TypeName) {}
+
+ /// \brief Warn about return typestate mismatches.
+ ///
+ /// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
+ virtual void warnReturnTypestateMismatch(SourceLocation Loc,
+ StringRef ExpectedState,
+ StringRef ObservedState) {}
+
+ /// \brief Warn about use-while-consumed errors.
+ /// \param MethodName -- The name of the method that was incorrectly
+ /// invoked.
+ ///
+ /// \param State -- The state the object was used in.
+ ///
+ /// \param Loc -- The SourceLocation of the method invocation.
+ virtual void warnUseOfTempInInvalidState(StringRef MethodName,
+ StringRef State,
+ SourceLocation Loc) {}
+
+ /// \brief Warn about use-while-consumed errors.
+ /// \param MethodName -- The name of the method that was incorrectly
+ /// invoked.
+ ///
+ /// \param State -- The state the object was used in.
+ ///
+ /// \param VariableName -- The name of the variable that holds the unique
+ /// value.
+ ///
+ /// \param Loc -- The SourceLocation of the method invocation.
+ virtual void warnUseInInvalidState(StringRef MethodName,
+ StringRef VariableName,
+ StringRef State,
+ SourceLocation Loc) {}
+ };
+
+ class ConsumedStateMap {
+
+ typedef llvm::DenseMap<const VarDecl *, ConsumedState> VarMapType;
+ typedef llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>
+ TmpMapType;
+
+ protected:
+
+ bool Reachable;
+ const Stmt *From;
+ VarMapType VarMap;
+ TmpMapType TmpMap;
+
+ public:
+ ConsumedStateMap() : Reachable(true), From(NULL) {}
+ ConsumedStateMap(const ConsumedStateMap &Other)
+ : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
+ TmpMap() {}
+
+ /// \brief Warn if any of the parameters being tracked are not in the state
+ /// they were declared to be in upon return from a function.
+ void checkParamsForReturnTypestate(SourceLocation BlameLoc,
+ ConsumedWarningsHandlerBase &WarningsHandler) const;
+
+ /// \brief Clear the TmpMap.
+ void clearTemporaries();
+
+ /// \brief Get the consumed state of a given variable.
+ ConsumedState getState(const VarDecl *Var) const;
+
+ /// \brief Get the consumed state of a given temporary value.
+ ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const;
+
+ /// \brief Merge this state map with another map.
+ void intersect(const ConsumedStateMap *Other);
+
+ void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack,
+ const ConsumedStateMap *LoopBackStates,
+ ConsumedWarningsHandlerBase &WarningsHandler);
+
+ /// \brief Return true if this block is reachable.
+ bool isReachable() const { return Reachable; }
+
+ /// \brief Mark the block as unreachable.
+ void markUnreachable();
+
+ /// \brief Set the source for a decision about the branching of states.
+ /// \param Source -- The statement that was the origin of a branching
+ /// decision.
+ void setSource(const Stmt *Source) { this->From = Source; }
+
+ /// \brief Set the consumed state of a given variable.
+ void setState(const VarDecl *Var, ConsumedState State);
+
+ /// \brief Set the consumed state of a given temporary value.
+ void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
+
+ /// \brief Remove the variable from our state map.
+ void remove(const VarDecl *Var);
+
+ /// \brief Tests to see if there is a mismatch in the states stored in two
+ /// maps.
+ ///
+ /// \param Other -- The second map to compare against.
+ bool operator!=(const ConsumedStateMap *Other) const;
+ };
+
+ class ConsumedBlockInfo {
+ std::vector<ConsumedStateMap*> StateMapsArray;
+ std::vector<unsigned int> VisitOrder;
+
+ public:
+ ConsumedBlockInfo() { }
+
+ ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
+ : StateMapsArray(NumBlocks, 0), VisitOrder(NumBlocks, 0) {
+ unsigned int VisitOrderCounter = 0;
+ for (PostOrderCFGView::iterator BI = SortedGraph->begin(),
+ BE = SortedGraph->end(); BI != BE; ++BI) {
+ VisitOrder[(*BI)->getBlockID()] = VisitOrderCounter++;
+ }
+ }
+
+ bool allBackEdgesVisited(const CFGBlock *CurrBlock,
+ const CFGBlock *TargetBlock);
+
+ void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
+ bool &AlreadyOwned);
+ void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap);
+
+ ConsumedStateMap* borrowInfo(const CFGBlock *Block);
+
+ void discardInfo(const CFGBlock *Block);
+
+ ConsumedStateMap* getInfo(const CFGBlock *Block);
+
+ bool isBackEdge(const CFGBlock *From, const CFGBlock *To);
+ bool isBackEdgeTarget(const CFGBlock *Block);
+ };
+
+ /// A class that handles the analysis of uniqueness violations.
+ class ConsumedAnalyzer {
+
+ ConsumedBlockInfo BlockInfo;
+ ConsumedStateMap *CurrStates;
+
+ ConsumedState ExpectedReturnState;
+
+ void determineExpectedReturnState(AnalysisDeclContext &AC,
+ const FunctionDecl *D);
+ bool hasConsumableAttributes(const CXXRecordDecl *RD);
+ bool splitState(const CFGBlock *CurrBlock,
+ const ConsumedStmtVisitor &Visitor);
+
+ public:
+
+ ConsumedWarningsHandlerBase &WarningsHandler;
+
+ ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler)
+ : WarningsHandler(WarningsHandler) {}
+
+ ConsumedState getExpectedReturnState() const { return ExpectedReturnState; }
+
+ /// \brief Check a function's CFG for consumed violations.
+ ///
+ /// We traverse the blocks in the CFG, keeping track of the state of each
+ /// value who's type has uniquness annotations. If methods are invoked in
+ /// the wrong state a warning is issued. Each block in the CFG is traversed
+ /// exactly once.
+ void run(AnalysisDeclContext &AC);
+ };
+}} // end namespace clang::consumed
+
+#endif
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 4bd989cf4ef3..c9516b50cae3 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -49,7 +49,7 @@ public:
const char *toString() const { return representation; }
// Overloaded operators for bool like qualities
- operator bool() const { return flag; }
+ LLVM_EXPLICIT operator bool() const { return flag; }
OptionalFlag& operator=(const bool &rhs) {
flag = rhs;
return *this; // Return a reference to myself.
@@ -73,6 +73,9 @@ public:
AsIntMax, // 'j'
AsSizeT, // 'z'
AsPtrDiff, // 't'
+ AsInt32, // 'I32' (MSVCRT, like __int32)
+ AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)
+ AsInt64, // 'I64' (MSVCRT, like __int64)
AsLongDouble, // 'L'
AsAllocate, // for '%as', GNU extension to C90 scanf
AsMAllocate, // for '%ms', GNU extension to scanf
@@ -95,6 +98,9 @@ public:
case AsLongLong:
case AsChar:
return 2;
+ case AsInt32:
+ case AsInt64:
+ return 3;
case None:
return 0;
}
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index 8a888e633322..5def3dd3dfd1 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -11,8 +11,8 @@
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
// conditions), based off of an annotation system.
//
-// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
-// information.
+// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// for more information.
//
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index e8810c32a140..188722d94b3a 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -38,6 +38,12 @@ private:
/// The expression which uses this variable.
const Expr *User;
+ /// Is this use uninitialized whenever the function is called?
+ bool UninitAfterCall;
+
+ /// Is this use uninitialized whenever the variable declaration is reached?
+ bool UninitAfterDecl;
+
/// Does this use always see an uninitialized value?
bool AlwaysUninit;
@@ -46,13 +52,17 @@ private:
SmallVector<Branch, 2> UninitBranches;
public:
- UninitUse(const Expr *User, bool AlwaysUninit) :
- User(User), AlwaysUninit(AlwaysUninit) {}
+ UninitUse(const Expr *User, bool AlwaysUninit)
+ : User(User), UninitAfterCall(false), UninitAfterDecl(false),
+ AlwaysUninit(AlwaysUninit) {}
void addUninitBranch(Branch B) {
UninitBranches.push_back(B);
}
+ void setUninitAfterCall() { UninitAfterCall = true; }
+ void setUninitAfterDecl() { UninitAfterDecl = true; }
+
/// Get the expression containing the uninitialized use.
const Expr *getUser() const { return User; }
@@ -62,6 +72,12 @@ public:
Maybe,
/// The use is uninitialized whenever a certain branch is taken.
Sometimes,
+ /// The use is uninitialized the first time it is reached after we reach
+ /// the variable's declaration.
+ AfterDecl,
+ /// The use is uninitialized the first time it is reached after the function
+ /// is called.
+ AfterCall,
/// The use is always uninitialized.
Always
};
@@ -69,6 +85,8 @@ public:
/// Get the kind of uninitialized use.
Kind getKind() const {
return AlwaysUninit ? Always :
+ UninitAfterCall ? AfterCall :
+ UninitAfterDecl ? AfterDecl :
!branch_empty() ? Sometimes : Maybe;
}
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 46d7d07e0907..b6f183d21b68 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -16,18 +16,14 @@
#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
#include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Allocator.h"
namespace clang {
-class Decl;
class Stmt;
class CFGReverseBlockReachabilityAnalysis;
class CFGStmtMap;
@@ -35,7 +31,6 @@ class LiveVariables;
class ManagedAnalysis;
class ParentMap;
class PseudoConstantAnalysis;
-class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
class BlockInvocationContext;
@@ -256,6 +251,7 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
+ void dumpStack(raw_ostream &OS, StringRef Indent = "") const;
LLVM_ATTRIBUTE_USED void dumpStack() const;
public:
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index d4e1f5fb6907..33c940e7bbf0 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define ANALYSISSTART
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index ee0be736dd5e..14b7ab842675 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -43,6 +43,8 @@ namespace clang {
class PrinterHelper;
class LangOptions;
class ASTContext;
+ class CXXRecordDecl;
+ class CXXDeleteExpr;
/// CFGElement - Represents a top-level expression in a basic block.
class CFGElement {
@@ -53,6 +55,7 @@ public:
Initializer,
// dtor kind
AutomaticObjectDtor,
+ DeleteDtor,
BaseDtor,
MemberDtor,
TemporaryDtor,
@@ -185,6 +188,31 @@ private:
}
};
+/// CFGDeleteDtor - Represents C++ object destructor generated
+/// from a call to delete.
+class CFGDeleteDtor : public CFGImplicitDtor {
+public:
+ CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE)
+ : CFGImplicitDtor(DeleteDtor, RD, DE) {}
+
+ const CXXRecordDecl *getCXXRecordDecl() const {
+ return static_cast<CXXRecordDecl*>(Data1.getPointer());
+ }
+
+ // Get Delete expression which triggered the destructor call.
+ const CXXDeleteExpr *getDeleteExpr() const {
+ return static_cast<CXXDeleteExpr *>(Data2.getPointer());
+ }
+
+
+private:
+ friend class CFGElement;
+ CFGDeleteDtor() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == DeleteDtor;
+ }
+};
+
/// CFGBaseDtor - Represents C++ object destructor implicitly generated for
/// base object in destructor.
class CFGBaseDtor : public CFGImplicitDtor {
@@ -269,7 +297,7 @@ public:
Stmt &operator*() { return *getStmt(); }
const Stmt &operator*() const { return *getStmt(); }
- operator bool() const { return getStmt(); }
+ LLVM_EXPLICIT operator bool() const { return getStmt(); }
};
/// CFGBlock - Represents a single basic block in a source-level CFG.
@@ -564,6 +592,10 @@ public:
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
+ Elements.push_back(CFGDeleteDtor(RD, DE), C);
+ }
+
// Destructors must be inserted 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.
@@ -745,6 +777,35 @@ public:
TryDispatchBlocks.push_back(block);
}
+ /// Records a synthetic DeclStmt and the DeclStmt it was constructed from.
+ ///
+ /// The CFG uses synthetic DeclStmts when a single AST DeclStmt contains
+ /// multiple decls.
+ void addSyntheticDeclStmt(const DeclStmt *Synthetic,
+ const DeclStmt *Source) {
+ assert(Synthetic->isSingleDecl() && "Can handle single declarations only");
+ assert(Synthetic != Source && "Don't include original DeclStmts in map");
+ assert(!SyntheticDeclStmts.count(Synthetic) && "Already in map");
+ SyntheticDeclStmts[Synthetic] = Source;
+ }
+
+ typedef llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator
+ synthetic_stmt_iterator;
+
+ /// Iterates over synthetic DeclStmts in the CFG.
+ ///
+ /// Each element is a (synthetic statement, source statement) pair.
+ ///
+ /// \sa addSyntheticDeclStmt
+ synthetic_stmt_iterator synthetic_stmt_begin() const {
+ return SyntheticDeclStmts.begin();
+ }
+
+ /// \sa synthetic_stmt_begin
+ synthetic_stmt_iterator synthetic_stmt_end() const {
+ return SyntheticDeclStmts.end();
+ }
+
//===--------------------------------------------------------------------===//
// Member templates useful for various batch operations over CFGs.
//===--------------------------------------------------------------------===//
@@ -763,21 +824,6 @@ public:
// CFG Introspection.
//===--------------------------------------------------------------------===//
- struct BlkExprNumTy {
- const signed Idx;
- explicit BlkExprNumTy(signed idx) : Idx(idx) {}
- explicit BlkExprNumTy() : Idx(-1) {}
- operator bool() const { return Idx >= 0; }
- operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
- };
-
- bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); }
- bool isBlkExpr(const Stmt *S) const {
- return const_cast<CFG*>(this)->isBlkExpr(S);
- }
- BlkExprNumTy getBlkExprNum(const Stmt *S);
- unsigned getNumBlkExprs();
-
/// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
/// start at 0).
unsigned getNumBlockIDs() const { return NumBlockIDs; }
@@ -800,9 +846,7 @@ public:
//===--------------------------------------------------------------------===//
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
- BlkExprMap(NULL), Blocks(BlkBVC, 10) {}
-
- ~CFG();
+ Blocks(BlkBVC, 10) {}
llvm::BumpPtrAllocator& getAllocator() {
return BlkBVC.getAllocator();
@@ -819,11 +863,6 @@ private:
// for indirect gotos
unsigned NumBlockIDs;
- // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
- // It represents a map from Expr* to integers to record the set of
- // block-level expressions and their "statement number" in the CFG.
- void * BlkExprMap;
-
BumpVectorContext BlkBVC;
CFGBlockListTy Blocks;
@@ -832,6 +871,9 @@ private:
/// This is the collection of such blocks present in the CFG.
std::vector<const CFGBlock *> TryDispatchBlocks;
+ /// Collects DeclStmts synthesized for this CFG and maps each one back to its
+ /// source DeclStmt.
+ llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts;
};
} // end namespace clang
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index 5015eb61497e..593ba575c78e 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -144,8 +144,8 @@ private:
public:
CallGraphNode(Decl *D) : FD(D) {}
- typedef SmallVector<CallRecord, 5>::iterator iterator;
- typedef SmallVector<CallRecord, 5>::const_iterator const_iterator;
+ typedef SmallVectorImpl<CallRecord>::iterator iterator;
+ typedef SmallVectorImpl<CallRecord>::const_iterator const_iterator;
/// Iterators through all the callees/children of the node.
inline iterator begin() { return CalledFunctions.begin(); }
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index 0f5e7bf246e8..c611ea2397ec 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -45,8 +45,7 @@ public:
/// dequeue - Remove a block from the worklist.
const CFGBlock *dequeue() {
assert(!BlockQueue.empty());
- const CFGBlock *B = BlockQueue.back();
- BlockQueue.pop_back();
+ const CFGBlock *B = BlockQueue.pop_back_val();
BlockSet[B] = 0;
return B;
}
diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
deleted file mode 100644
index 35cc799b13bc..000000000000
--- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h
+++ /dev/null
@@ -1,307 +0,0 @@
-// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- 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 definition of dataflow types used by analyses such
-// as LiveVariables and UninitializedValues. The underlying dataflow values
-// are implemented as bitvectors, but the definitions in this file include
-// the necessary boilerplate to use with our dataflow framework.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
-#define LLVM_CLANG_STMTDECLBVDVAL_H
-
-#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
-#include "clang/Analysis/CFG.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-
-namespace clang {
-
- class Stmt;
- class ASTContext;
-
-struct DeclBitVector_Types {
-
- class Idx {
- unsigned I;
- public:
- explicit Idx(unsigned i) : I(i) {}
- Idx() : I(~0U) {}
-
- bool isValid() const {
- return I != ~0U;
- }
- operator unsigned() const {
- assert (isValid());
- return I;
- }
- };
-
- //===--------------------------------------------------------------------===//
- // AnalysisDataTy - Whole-function meta data.
- //===--------------------------------------------------------------------===//
-
- class AnalysisDataTy {
- public:
- typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy;
- typedef DMapTy::const_iterator decl_iterator;
-
- protected:
- DMapTy DMap;
- unsigned NDecls;
-
- public:
-
- AnalysisDataTy() : NDecls(0) {}
- virtual ~AnalysisDataTy() {}
-
- bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); }
-
- Idx getIdx(const NamedDecl *SD) const {
- DMapTy::const_iterator I = DMap.find(SD);
- return I == DMap.end() ? Idx() : Idx(I->second);
- }
-
- unsigned getNumDecls() const { return NDecls; }
-
- void Register(const NamedDecl *SD) {
- if (!isTracked(SD)) DMap[SD] = NDecls++;
- }
-
- decl_iterator begin_decl() const { return DMap.begin(); }
- decl_iterator end_decl() const { return DMap.end(); }
- };
-
- //===--------------------------------------------------------------------===//
- // ValTy - Dataflow value.
- //===--------------------------------------------------------------------===//
-
- class ValTy {
- llvm::BitVector DeclBV;
- public:
-
- void resetDeclValues(AnalysisDataTy& AD) {
- DeclBV.resize(AD.getNumDecls());
- DeclBV.reset();
- }
-
- void setDeclValues(AnalysisDataTy& AD) {
- DeclBV.resize(AD.getNumDecls());
- DeclBV.set();
- }
-
- void resetValues(AnalysisDataTy& AD) {
- resetDeclValues(AD);
- }
-
- bool operator==(const ValTy& RHS) const {
- assert (sizesEqual(RHS));
- return DeclBV == RHS.DeclBV;
- }
-
- void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }
-
- llvm::BitVector::reference getBit(unsigned i) {
- return DeclBV[i];
- }
-
- bool getBit(unsigned i) const {
- return DeclBV[i];
- }
-
- llvm::BitVector::reference
- operator()(const NamedDecl *ND, const AnalysisDataTy& AD) {
- return getBit(AD.getIdx(ND));
- }
-
- bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const {
- return getBit(AD.getIdx(ND));
- }
-
- llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
- const llvm::BitVector::reference getDeclBit(unsigned i) const {
- return const_cast<llvm::BitVector&>(DeclBV)[i];
- }
-
- ValTy& operator|=(const ValTy& RHS) {
- assert (sizesEqual(RHS));
- DeclBV |= RHS.DeclBV;
- return *this;
- }
-
- ValTy& operator&=(const ValTy& RHS) {
- assert (sizesEqual(RHS));
- DeclBV &= RHS.DeclBV;
- return *this;
- }
-
- ValTy& OrDeclBits(const ValTy& RHS) {
- return operator|=(RHS);
- }
-
- ValTy& AndDeclBits(const ValTy& RHS) {
- return operator&=(RHS);
- }
-
- bool sizesEqual(const ValTy& RHS) const {
- return DeclBV.size() == RHS.DeclBV.size();
- }
- };
-
- //===--------------------------------------------------------------------===//
- // Some useful merge operations.
- //===--------------------------------------------------------------------===//
-
- struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
- struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
-};
-
-
-struct StmtDeclBitVector_Types {
-
- //===--------------------------------------------------------------------===//
- // AnalysisDataTy - Whole-function meta data.
- //===--------------------------------------------------------------------===//
-
- class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
- ASTContext *ctx;
- CFG* cfg;
- public:
- AnalysisDataTy() : ctx(0), cfg(0) {}
- virtual ~AnalysisDataTy() {}
-
- void setContext(ASTContext &c) { ctx = &c; }
- ASTContext &getContext() {
- assert(ctx && "ASTContext should not be NULL.");
- return *ctx;
- }
-
- void setCFG(CFG& c) { cfg = &c; }
- CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
-
- bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); }
- using DeclBitVector_Types::AnalysisDataTy::isTracked;
-
- unsigned getIdx(const Stmt *S) const {
- CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
- assert(I && "Stmtession not tracked for bitvector.");
- return I;
- }
- using DeclBitVector_Types::AnalysisDataTy::getIdx;
-
- unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
- };
-
- //===--------------------------------------------------------------------===//
- // ValTy - Dataflow value.
- //===--------------------------------------------------------------------===//
-
- class ValTy : public DeclBitVector_Types::ValTy {
- llvm::BitVector BlkExprBV;
- typedef DeclBitVector_Types::ValTy ParentTy;
-
- static inline ParentTy& ParentRef(ValTy& X) {
- return static_cast<ParentTy&>(X);
- }
-
- static inline const ParentTy& ParentRef(const ValTy& X) {
- return static_cast<const ParentTy&>(X);
- }
-
- public:
-
- void resetBlkExprValues(AnalysisDataTy& AD) {
- BlkExprBV.resize(AD.getNumBlkExprs());
- BlkExprBV.reset();
- }
-
- void setBlkExprValues(AnalysisDataTy& AD) {
- BlkExprBV.resize(AD.getNumBlkExprs());
- BlkExprBV.set();
- }
-
- void resetValues(AnalysisDataTy& AD) {
- resetDeclValues(AD);
- resetBlkExprValues(AD);
- }
-
- void setValues(AnalysisDataTy& AD) {
- setDeclValues(AD);
- setBlkExprValues(AD);
- }
-
- bool operator==(const ValTy& RHS) const {
- return ParentRef(*this) == ParentRef(RHS)
- && BlkExprBV == RHS.BlkExprBV;
- }
-
- void copyValues(const ValTy& RHS) {
- ParentRef(*this).copyValues(ParentRef(RHS));
- BlkExprBV = RHS.BlkExprBV;
- }
-
- llvm::BitVector::reference
- operator()(const Stmt *S, const AnalysisDataTy& AD) {
- return BlkExprBV[AD.getIdx(S)];
- }
- const llvm::BitVector::reference
- operator()(const Stmt *S, const AnalysisDataTy& AD) const {
- return const_cast<ValTy&>(*this)(S,AD);
- }
-
- using DeclBitVector_Types::ValTy::operator();
-
-
- llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
- const llvm::BitVector::reference getStmtBit(unsigned i) const {
- return const_cast<llvm::BitVector&>(BlkExprBV)[i];
- }
-
- ValTy& OrBlkExprBits(const ValTy& RHS) {
- BlkExprBV |= RHS.BlkExprBV;
- return *this;
- }
-
- ValTy& AndBlkExprBits(const ValTy& RHS) {
- BlkExprBV &= RHS.BlkExprBV;
- return *this;
- }
-
- ValTy& operator|=(const ValTy& RHS) {
- assert (sizesEqual(RHS));
- ParentRef(*this) |= ParentRef(RHS);
- BlkExprBV |= RHS.BlkExprBV;
- return *this;
- }
-
- ValTy& operator&=(const ValTy& RHS) {
- assert (sizesEqual(RHS));
- ParentRef(*this) &= ParentRef(RHS);
- BlkExprBV &= RHS.BlkExprBV;
- return *this;
- }
-
- bool sizesEqual(const ValTy& RHS) const {
- return ParentRef(*this).sizesEqual(ParentRef(RHS))
- && BlkExprBV.size() == RHS.BlkExprBV.size();
- }
- };
-
- //===--------------------------------------------------------------------===//
- // Some useful merge operations.
- //===--------------------------------------------------------------------===//
-
- struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
- struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
-
-};
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
deleted file mode 100644
index 2bf3eda070b9..000000000000
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- 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 template class CFGRecStmtDeclVisitor, which extends
-// CFGRecStmtVisitor by implementing (typed) visitation of decls.
-//
-// FIXME: This may not be fully complete. We currently explore only subtypes
-// of ScopedDecl.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
-#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
-
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-
-#define DISPATCH_CASE(CLASS) \
-case Decl::CLASS: \
-static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \
- static_cast<CLASS##Decl*>(D)); \
-break;
-
-#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {}
-#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\
- { static_cast<ImplClass*>(this)->VisitVarDecl(D); }
-
-
-namespace clang {
-template <typename ImplClass>
-class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
-public:
-
- void VisitDeclRefExpr(DeclRefExpr *DR) {
- static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
- }
-
- void VisitDeclStmt(DeclStmt *DS) {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
- Decl *D = *DI;
- static_cast<ImplClass*>(this)->VisitDecl(D);
- // Visit the initializer.
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- if (Expr *I = VD->getInit())
- static_cast<ImplClass*>(this)->Visit(I);
- }
- }
-
- void VisitDecl(Decl *D) {
- switch (D->getKind()) {
- DISPATCH_CASE(Function)
- DISPATCH_CASE(CXXMethod)
- DISPATCH_CASE(Var)
- DISPATCH_CASE(ParmVar) // FIXME: (same)
- DISPATCH_CASE(ImplicitParam)
- DISPATCH_CASE(EnumConstant)
- DISPATCH_CASE(Typedef)
- DISPATCH_CASE(TypeAlias)
- DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
- DISPATCH_CASE(CXXRecord)
- DISPATCH_CASE(Enum)
- DISPATCH_CASE(Field)
- DISPATCH_CASE(UsingDirective)
- DISPATCH_CASE(Using)
- DISPATCH_CASE(NamespaceAlias)
- default:
- llvm_unreachable("Subtype of ScopedDecl not handled.");
- }
- }
-
- DEFAULT_DISPATCH(Var)
- DEFAULT_DISPATCH(Function)
- DEFAULT_DISPATCH(CXXMethod)
- DEFAULT_DISPATCH_VARDECL(ParmVar)
- DEFAULT_DISPATCH(ImplicitParam)
- DEFAULT_DISPATCH(EnumConstant)
- DEFAULT_DISPATCH(Typedef)
- DEFAULT_DISPATCH(TypeAlias)
- DEFAULT_DISPATCH(Record)
- DEFAULT_DISPATCH(Enum)
- DEFAULT_DISPATCH(Field)
- DEFAULT_DISPATCH(ObjCInterface)
- DEFAULT_DISPATCH(ObjCMethod)
- DEFAULT_DISPATCH(ObjCProtocol)
- DEFAULT_DISPATCH(ObjCCategory)
- DEFAULT_DISPATCH(UsingDirective)
- DEFAULT_DISPATCH(Using)
- DEFAULT_DISPATCH(NamespaceAlias)
-
- void VisitCXXRecordDecl(CXXRecordDecl *D) {
- static_cast<ImplClass*>(this)->VisitRecordDecl(D);
- }
-};
-
-} // end namespace clang
-
-#undef DISPATCH_CASE
-#undef DEFAULT_DISPATCH
-#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
deleted file mode 100644
index 4d1cabfc5c0b..000000000000
--- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- 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 template class CFGRecStmtVisitor, which extends
-// CFGStmtVisitor by implementing a default recursive visit of all statements.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
-#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
-
-#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
-
-namespace clang {
-template <typename ImplClass>
-class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
-public:
-
- void VisitStmt(Stmt *S) {
- static_cast< ImplClass* >(this)->VisitChildren(S);
- }
-
- void VisitCompoundStmt(CompoundStmt *S) {
- // Do nothing. Everything in a CompoundStmt is inlined
- // into the CFG.
- }
-
- void VisitConditionVariableInit(Stmt *S) {
- assert(S == this->getCurrentBlkStmt());
- VarDecl *CondVar = 0;
- switch (S->getStmtClass()) {
-#define CONDVAR_CASE(CLASS) \
-case Stmt::CLASS ## Class:\
-CondVar = cast<CLASS>(S)->getConditionVariable();\
-break;
- CONDVAR_CASE(IfStmt)
- CONDVAR_CASE(ForStmt)
- CONDVAR_CASE(SwitchStmt)
- CONDVAR_CASE(WhileStmt)
-#undef CONDVAR_CASE
- default:
- llvm_unreachable("Infeasible");
- }
- static_cast<ImplClass*>(this)->Visit(CondVar->getInit());
- }
-
- // Defining operator() allows the visitor to be used as a C++ style functor.
- void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
-};
-
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
deleted file mode 100644
index b354ba7b1680..000000000000
--- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h
+++ /dev/null
@@ -1,175 +0,0 @@
-//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- 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 CFGStmtVisitor interface, which extends
-// StmtVisitor. This interface is useful for visiting statements in a CFG
-// where some statements have implicit control-flow and thus should
-// be treated specially.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
-#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
-
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/CFG.h"
-
-namespace clang {
-
-#define DISPATCH_CASE(CLASS) \
-case Stmt::CLASS ## Class: return \
-static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
-
-#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
-{ return\
- static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
- cast<Expr>(S)); }
-
-template <typename ImplClass, typename RetTy=void>
-class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
- Stmt *CurrentBlkStmt;
-
- struct NullifyStmt {
- Stmt*& S;
-
- NullifyStmt(Stmt*& s) : S(s) {}
- ~NullifyStmt() { S = NULL; }
- };
-
-public:
- CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
-
- Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; }
-
- RetTy Visit(Stmt *S) {
- if (S == CurrentBlkStmt ||
- !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
- return StmtVisitor<ImplClass,RetTy>::Visit(S);
- else
- return RetTy();
- }
-
- /// VisitConditionVariableInit - Handle the initialization of condition
- /// variables at branches. Valid statements include IfStmt, ForStmt,
- /// WhileStmt, and SwitchStmt.
- RetTy VisitConditionVariableInit(Stmt *S) {
- return RetTy();
- }
-
- /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
- /// CFGBlocks. Root statements are the statements that appear explicitly in
- /// the list of statements in a CFGBlock. For substatements, or when there
- /// is no implementation provided for a BlockStmt_XXX method, we default
- /// to using StmtVisitor's Visit method.
- RetTy BlockStmt_Visit(Stmt *S) {
- CurrentBlkStmt = S;
- NullifyStmt cleanup(CurrentBlkStmt);
-
- switch (S->getStmtClass()) {
- case Stmt::IfStmtClass:
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::SwitchStmtClass:
- return static_cast<ImplClass*>(this)->VisitConditionVariableInit(S);
-
- DISPATCH_CASE(StmtExpr)
- DISPATCH_CASE(ConditionalOperator)
- DISPATCH_CASE(BinaryConditionalOperator)
- DISPATCH_CASE(ObjCForCollectionStmt)
- DISPATCH_CASE(CXXForRangeStmt)
-
- case Stmt::BinaryOperatorClass: {
- BinaryOperator* B = cast<BinaryOperator>(S);
- if (B->isLogicalOp())
- return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
- else if (B->getOpcode() == BO_Comma)
- return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
- // Fall through.
- }
-
- default:
- if (isa<Expr>(S))
- return
- static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
- else
- return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
- }
- }
-
- DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
- DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
- DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
-
- RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
- return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
- }
-
- RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) {
- return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
- }
-
- RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) {
- return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
- }
-
- RetTy BlockStmt_VisitExpr(Expr *E) {
- return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
- }
-
- RetTy BlockStmt_VisitStmt(Stmt *S) {
- return static_cast<ImplClass*>(this)->Visit(S);
- }
-
- RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
- return
- static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
- }
-
- RetTy BlockStmt_VisitComma(BinaryOperator* B) {
- return
- static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
- }
-
- //===--------------------------------------------------------------------===//
- // Utility methods. Not called by default (but subclasses may use them).
- //===--------------------------------------------------------------------===//
-
- /// VisitChildren: Call "Visit" on each child of S.
- void VisitChildren(Stmt *S) {
-
- switch (S->getStmtClass()) {
- default:
- break;
-
- case Stmt::StmtExprClass: {
- CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt();
- if (CS->body_empty()) return;
- static_cast<ImplClass*>(this)->Visit(CS->body_back());
- return;
- }
-
- case Stmt::BinaryOperatorClass: {
- BinaryOperator* B = cast<BinaryOperator>(S);
- if (B->getOpcode() != BO_Comma) break;
- static_cast<ImplClass*>(this)->Visit(B->getRHS());
- return;
- }
- }
-
- for (Stmt::child_range I = S->children(); I; ++I)
- if (*I) static_cast<ImplClass*>(this)->Visit(*I);
- }
-};
-
-#undef DEFAULT_BLOCKSTMT_VISIT
-#undef DISPATCH_CASE
-
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Basic/ABI.h b/include/clang/Basic/ABI.h
index fecf613a0461..3b3d59efc015 100644
--- a/include/clang/Basic/ABI.h
+++ b/include/clang/Basic/ABI.h
@@ -39,28 +39,64 @@ struct ReturnAdjustment {
/// \brief The non-virtual adjustment from the derived object to its
/// nearest virtual base.
int64_t NonVirtual;
+
+ /// \brief Holds the ABI-specific information about the virtual return
+ /// adjustment, if needed.
+ union VirtualAdjustment {
+ // Itanium ABI
+ struct {
+ /// \brief The offset (in bytes), relative to the address point
+ /// of the virtual base class offset.
+ int64_t VBaseOffsetOffset;
+ } Itanium;
+
+ // Microsoft ABI
+ struct {
+ /// \brief The offset (in bytes) of the vbptr, relative to the beginning
+ /// of the derived class.
+ uint32_t VBPtrOffset;
+
+ /// \brief Index of the virtual base in the vbtable.
+ uint32_t VBIndex;
+ } Microsoft;
+
+ VirtualAdjustment() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ bool Equals(const VirtualAdjustment &Other) const {
+ return memcmp(this, &Other, sizeof(Other)) == 0;
+ }
+
+ bool isEmpty() const {
+ VirtualAdjustment Zero;
+ return Equals(Zero);
+ }
+
+ bool Less(const VirtualAdjustment &RHS) const {
+ return memcmp(this, &RHS, sizeof(RHS)) < 0;
+ }
+ } Virtual;
- /// \brief The offset (in bytes), relative to the address point
- /// of the virtual base class offset.
- int64_t VBaseOffsetOffset;
-
- ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+ ReturnAdjustment() : NonVirtual(0) {}
- bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+ bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
friend bool operator==(const ReturnAdjustment &LHS,
const ReturnAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
+ return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
+ }
+
+ friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) {
+ return !(LHS == RHS);
}
friend bool operator<(const ReturnAdjustment &LHS,
const ReturnAdjustment &RHS) {
if (LHS.NonVirtual < RHS.NonVirtual)
return true;
-
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
+
+ return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
}
};
@@ -70,18 +106,57 @@ struct ThisAdjustment {
/// nearest virtual base.
int64_t NonVirtual;
- /// \brief The offset (in bytes), relative to the address point,
- /// of the virtual call offset.
- int64_t VCallOffsetOffset;
+ /// \brief Holds the ABI-specific information about the virtual this
+ /// adjustment, if needed.
+ union VirtualAdjustment {
+ // Itanium ABI
+ struct {
+ /// \brief The offset (in bytes), relative to the address point,
+ /// of the virtual call offset.
+ int64_t VCallOffsetOffset;
+ } Itanium;
+
+ struct {
+ /// \brief The offset of the vtordisp (in bytes), relative to the ECX.
+ int32_t VtordispOffset;
+
+ /// \brief The offset of the vbptr of the derived class (in bytes),
+ /// relative to the ECX after vtordisp adjustment.
+ int32_t VBPtrOffset;
+
+ /// \brief The offset (in bytes) of the vbase offset in the vbtable.
+ int32_t VBOffsetOffset;
+ } Microsoft;
+
+ VirtualAdjustment() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ bool Equals(const VirtualAdjustment &Other) const {
+ return memcmp(this, &Other, sizeof(Other)) == 0;
+ }
+
+ bool isEmpty() const {
+ VirtualAdjustment Zero;
+ return Equals(Zero);
+ }
+
+ bool Less(const VirtualAdjustment &RHS) const {
+ return memcmp(this, &RHS, sizeof(RHS)) < 0;
+ }
+ } Virtual;
- ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
+ ThisAdjustment() : NonVirtual(0) { }
- bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
+ bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
friend bool operator==(const ThisAdjustment &LHS,
const ThisAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
+ return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
+ }
+
+ friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
+ return !(LHS == RHS);
}
friend bool operator<(const ThisAdjustment &LHS,
@@ -89,11 +164,12 @@ struct ThisAdjustment {
if (LHS.NonVirtual < RHS.NonVirtual)
return true;
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VCallOffsetOffset < RHS.VCallOffsetOffset;
+ return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
}
};
+class CXXMethodDecl;
+
/// \brief The \c this pointer adjustment as well as an optional return
/// adjustment for a thunk.
struct ThunkInfo {
@@ -103,23 +179,25 @@ struct ThunkInfo {
/// \brief The return adjustment.
ReturnAdjustment Return;
- ThunkInfo() { }
+ /// \brief Holds a pointer to the overridden method this thunk is for,
+ /// if needed by the ABI to distinguish different thunks with equal
+ /// adjustments. Otherwise, null.
+ /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
+ /// an ABI-specific comparator.
+ const CXXMethodDecl *Method;
- ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
- : This(This), Return(Return) { }
+ ThunkInfo() : Method(0) { }
- friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
- return LHS.This == RHS.This && LHS.Return == RHS.Return;
- }
+ ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
+ const CXXMethodDecl *Method = 0)
+ : This(This), Return(Return), Method(Method) {}
- friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) {
- if (LHS.This < RHS.This)
- return true;
-
- return LHS.This == RHS.This && LHS.Return < RHS.Return;
+ friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ return LHS.This == RHS.This && LHS.Return == RHS.Return &&
+ LHS.Method == RHS.Method;
}
- bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+ bool isEmpty() const { return This.isEmpty() && Return.isEmpty() && Method == 0; }
};
} // end namespace clang
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 441a79a23b26..8c3bdba89a8c 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -1,8 +1,11 @@
-////////////////////////////////////////////////////////////////////////////////
-// Note: This file is a work in progress. Please do not apply non-trivial
-// updates unless you have talked to Sean Hunt <rideau3@gmail.com> prior.
-// Merely adding a new attribute is a trivial update.
-////////////////////////////////////////////////////////////////////////////////
+//==--- Attr.td - attribute definitions -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
// An attribute's subject is whatever it appertains to. In this file, it is
// more accurately a list of things that an attribute can appertain to. All
@@ -36,45 +39,53 @@ def NormalVar : SubsetSubject<Var, "non-register, non-parameter variable",
S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::ParmVar &&
S->getKind() != Decl::NonTypeTemplateParm}]>;
-def CXXVirtualMethod : SubsetSubject<CXXRecord, "virtual member function",
- [{S->isVirtual()}]>;
def NonBitField : SubsetSubject<Field, "non-bit field",
[{!S->isBitField()}]>;
// A single argument to an attribute
-class Argument<string name> {
+class Argument<string name, bit optional> {
string Name = name;
+ bit Optional = optional;
}
-class BoolArgument<string name> : Argument<name>;
-class IdentifierArgument<string name> : Argument<name>;
-class IntArgument<string name> : Argument<name>;
-class StringArgument<string name> : Argument<name>;
-class ExprArgument<string name> : Argument<name>;
-class FunctionArgument<string name> : Argument<name>;
-class TypeArgument<string name> : Argument<name>;
-class UnsignedArgument<string name> : Argument<name>;
-class SourceLocArgument<string name> : Argument<name>;
-class VariadicUnsignedArgument<string name> : Argument<name>;
-class VariadicExprArgument<string name> : Argument<name>;
+class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IdentifierArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IntArgument<string name, bit opt = 0> : Argument<name, opt>;
+class StringArgument<string name, bit opt = 0> : Argument<name, opt>;
+class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
+class FunctionArgument<string name, bit opt = 0> : Argument<name, opt>;
+class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
+class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
+class SourceLocArgument<string name, bit opt = 0> : Argument<name, opt>;
+class VariadicUnsignedArgument<string name> : Argument<name, 1>;
+class VariadicExprArgument<string name> : Argument<name, 1>;
// A version of the form major.minor[.subminor].
-class VersionArgument<string name> : Argument<name>;
+class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
// This one's a doozy, so it gets its own special type
// It can be an unsigned integer, or a type. Either can
// be dependent.
-class AlignedArgument<string name> : Argument<name>;
+class AlignedArgument<string name, bit opt = 0> : Argument<name, opt>;
// An integer argument with a default value
-class DefaultIntArgument<string name, int default> : IntArgument<name> {
+class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
int Default = default;
}
// This argument is more complex, it includes the enumerator type name,
// a list of strings to accept, and a list of enumerators to map them to.
class EnumArgument<string name, string type, list<string> values,
- list<string> enums> : Argument<name> {
+ list<string> enums, bit opt = 0> : Argument<name, opt> {
+ string Type = type;
+ list<string> Values = values;
+ list<string> Enums = enums;
+}
+
+// FIXME: There should be a VariadicArgument type that takes any other type
+// of argument and generates the appropriate type.
+class VariadicEnumArgument<string name, string type, list<string> values,
+ list<string> enums> : Argument<name, 1> {
string Type = type;
list<string> Values = values;
list<string> Enums = enums;
@@ -122,13 +133,27 @@ class Attr {
bit Ignored = 0;
// Set to true if each of the spellings is a distinct attribute.
bit DistinctSpellings = 0;
+ // Set to true if the attribute's parsing does not match its semantic
+ // content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of
+ // common attribute error checking.
+ bit HasCustomParsing = 0;
// Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
+/// A type attribute is not processed on a declaration or a statement.
+class TypeAttr : Attr {
+ let ASTNode = 0;
+}
+
/// An inheritable attribute is inherited by later redeclarations.
class InheritableAttr : Attr;
+/// A target-specific attribute that is meant to be processed via
+/// TargetAttributesSema::ProcessDeclAttribute. This class is meant to be used
+/// as a mixin with InheritableAttr or Attr depending on the attribute's needs.
+class TargetSpecificAttr;
+
/// An inheritable parameter attribute is inherited by later
/// redeclarations, even when it's written on a parameter.
class InheritableParamAttr : InheritableAttr;
@@ -144,13 +169,12 @@ class IgnoredAttr : Attr {
// Attributes begin here
//
-def AddressSpace : Attr {
+def AddressSpace : TypeAttr {
let Spellings = [GNU<"address_space">];
let Args = [IntArgument<"AddressSpace">];
- let ASTNode = 0;
}
-def Alias : InheritableAttr {
+def Alias : Attr {
let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
let Args = [StringArgument<"Aliasee">];
}
@@ -159,7 +183,7 @@ def Aligned : InheritableAttr {
let Spellings = [GNU<"aligned">, Declspec<"align">, CXX11<"gnu", "aligned">,
Keyword<"alignas">, Keyword<"_Alignas">];
let Subjects = [NonBitField, NormalVar, Tag];
- let Args = [AlignedArgument<"Alignment">];
+ let Args = [AlignedArgument<"Alignment", 1>];
let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
Accessor<"isC11", [Keyword<"_Alignas">]>,
Accessor<"isAlignas", [Keyword<"alignas">,
@@ -172,7 +196,7 @@ def AlignMac68k : InheritableAttr {
let SemaHandler = 0;
}
-def AllocSize : Attr {
+def AllocSize : InheritableAttr {
let Spellings = [GNU<"alloc_size">, CXX11<"gnu", "alloc_size">];
let Args = [VariadicUnsignedArgument<"Args">];
}
@@ -196,6 +220,14 @@ def Annotate : InheritableParamAttr {
let Args = [StringArgument<"Annotation">];
}
+def ARMInterrupt : InheritableAttr, TargetSpecificAttr {
+ let Spellings = [GNU<"interrupt">];
+ let Args = [EnumArgument<"Interrupt", "InterruptType",
+ ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
+ ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"],
+ 1>];
+}
+
def AsmLabel : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Label">];
@@ -214,6 +246,7 @@ def Availability : InheritableAttr {
.Case("macosx", "OS X")
.Default(llvm::StringRef());
} }];
+ let HasCustomParsing = 1;
}
def Blocks : InheritableAttr {
@@ -282,12 +315,13 @@ def Common : InheritableAttr {
}
def Const : InheritableAttr {
- let Spellings = [GNU<"const">, GNU<"__const">, CXX11<"gnu", "const">];
+ let Spellings = [GNU<"const">, GNU<"__const">,
+ CXX11<"gnu", "const">, CXX11<"gnu", "__const">];
}
def Constructor : InheritableAttr {
let Spellings = [GNU<"constructor">, CXX11<"gnu", "constructor">];
- let Args = [IntArgument<"Priority">];
+ let Args = [IntArgument<"Priority", 1>];
}
def CUDAConstant : InheritableAttr {
@@ -326,7 +360,7 @@ def CXX11NoReturn : InheritableAttr {
let Subjects = [Function];
}
-def OpenCLKernel : Attr {
+def OpenCLKernel : InheritableAttr {
let Spellings = [Keyword<"__kernel">, Keyword<"kernel">];
}
@@ -336,13 +370,14 @@ def OpenCLImageAccess : Attr {
}
def Deprecated : InheritableAttr {
- let Spellings = [GNU<"deprecated">, CXX11<"gnu", "deprecated">];
- let Args = [StringArgument<"Message">];
+ let Spellings = [GNU<"deprecated">,
+ CXX11<"gnu", "deprecated">, CXX11<"","deprecated">];
+ let Args = [StringArgument<"Message", 1>];
}
def Destructor : InheritableAttr {
let Spellings = [GNU<"destructor">, CXX11<"gnu", "destructor">];
- let Args = [IntArgument<"Priority">];
+ let Args = [IntArgument<"Priority", 1>];
}
def ExtVectorType : Attr {
@@ -362,7 +397,8 @@ def FastCall : InheritableAttr {
}
def Final : InheritableAttr {
- let Spellings = [];
+ let Spellings = [Keyword<"final">, Keyword<"sealed">];
+ let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>];
let SemaHandler = 0;
}
@@ -373,7 +409,7 @@ def MinSize : InheritableAttr {
def Format : InheritableAttr {
let Spellings = [GNU<"format">, CXX11<"gnu", "format">];
- let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
+ let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
IntArgument<"FirstArg">];
}
@@ -400,7 +436,7 @@ def IBOutlet : InheritableAttr {
def IBOutletCollection : InheritableAttr {
let Spellings = [GNU<"iboutletcollection">];
- let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
+ let Args = [TypeArgument<"Interface", 1>];
}
def Malloc : InheritableAttr {
@@ -417,23 +453,17 @@ def MayAlias : InheritableAttr {
let Spellings = [GNU<"may_alias">, CXX11<"gnu", "may_alias">];
}
-def MSP430Interrupt : InheritableAttr {
- let Spellings = [];
- let Args = [UnsignedArgument<"Number">];
- let SemaHandler = 0;
-}
-
-def MBlazeInterruptHandler : InheritableAttr {
- let Spellings = [];
- let SemaHandler = 0;
+def MSABI : InheritableAttr {
+ let Spellings = [GNU<"ms_abi">, CXX11<"gnu", "ms_abi">];
}
-def MBlazeSaveVolatiles : InheritableAttr {
+def MSP430Interrupt : InheritableAttr, TargetSpecificAttr {
let Spellings = [];
+ let Args = [UnsignedArgument<"Number">];
let SemaHandler = 0;
}
-def Mips16 : InheritableAttr {
+def Mips16 : InheritableAttr, TargetSpecificAttr {
let Spellings = [GNU<"mips16">, CXX11<"gnu", "mips16">];
let Subjects = [Function];
}
@@ -441,23 +471,20 @@ def Mips16 : InheritableAttr {
def Mode : Attr {
let Spellings = [GNU<"mode">, CXX11<"gnu", "mode">];
let Args = [IdentifierArgument<"Mode">];
- let ASTNode = 0;
}
def Naked : InheritableAttr {
let Spellings = [GNU<"naked">, CXX11<"gnu", "naked">];
}
-def NeonPolyVectorType : Attr {
+def NeonPolyVectorType : TypeAttr {
let Spellings = [GNU<"neon_polyvector_type">];
let Args = [IntArgument<"NumElements">];
- let ASTNode = 0;
}
-def NeonVectorType : Attr {
+def NeonVectorType : TypeAttr {
let Spellings = [GNU<"neon_vector_type">];
let Args = [IntArgument<"NumElements">];
- let ASTNode = 0;
}
def ReturnsTwice : InheritableAttr {
@@ -476,7 +503,7 @@ def NoInline : InheritableAttr {
let Spellings = [GNU<"noinline">, CXX11<"gnu", "noinline">];
}
-def NoMips16 : InheritableAttr {
+def NoMips16 : InheritableAttr, TargetSpecificAttr {
let Spellings = [GNU<"nomips16">, CXX11<"gnu", "nomips16">];
let Subjects = [Function];
}
@@ -513,7 +540,13 @@ def NoThrow : InheritableAttr {
def NSBridged : InheritableAttr {
let Spellings = [GNU<"ns_bridged">];
let Subjects = [Record];
- let Args = [IdentifierArgument<"BridgedType">];
+ let Args = [IdentifierArgument<"BridgedType", 1>];
+}
+
+def ObjCBridge : InheritableAttr {
+ let Spellings = [GNU<"objc_bridge">];
+ let Subjects = [Record];
+ let Args = [IdentifierArgument<"BridgedType", 1>];
}
def NSReturnsRetained : InheritableAttr {
@@ -558,14 +591,14 @@ def ObjCNSObject : InheritableAttr {
let Spellings = [GNU<"NSObject">];
}
-def ObjCPreciseLifetime : Attr {
+def ObjCPreciseLifetime : InheritableAttr {
let Spellings = [GNU<"objc_precise_lifetime">];
let Subjects = [Var];
}
-def ObjCReturnsInnerPointer : Attr {
+def ObjCReturnsInnerPointer : InheritableAttr {
let Spellings = [GNU<"objc_returns_inner_pointer">];
- let Subjects = [ObjCMethod];
+ let Subjects = [ObjCMethod, ObjCProperty];
}
def ObjCRequiresSuper : InheritableAttr {
@@ -573,7 +606,7 @@ def ObjCRequiresSuper : InheritableAttr {
let Subjects = [ObjCMethod];
}
-def ObjCRootClass : Attr {
+def ObjCRootClass : InheritableAttr {
let Spellings = [GNU<"objc_root_class">];
let Subjects = [ObjCInterface];
}
@@ -595,6 +628,7 @@ def Ownership : InheritableAttr {
["ownership_holds", "ownership_returns", "ownership_takes"],
["Holds", "Returns", "Takes"]>,
StringArgument<"Module">, VariadicUnsignedArgument<"Args">];
+ let HasCustomParsing = 1;
}
def Packed : InheritableAttr {
@@ -631,11 +665,6 @@ def ReqdWorkGroupSize : InheritableAttr {
UnsignedArgument<"ZDim">];
}
-def Endian : InheritableAttr {
- let Spellings = [GNU<"endian">];
- let Args = [IdentifierArgument<"platform">];
-}
-
def WorkGroupSizeHint : InheritableAttr {
let Spellings = [GNU<"work_group_size_hint">];
let Args = [UnsignedArgument<"XDim">,
@@ -664,6 +693,10 @@ def StdCall : InheritableAttr {
Keyword<"__stdcall">, Keyword<"_stdcall">];
}
+def SysVABI : InheritableAttr {
+ let Spellings = [GNU<"sysv_abi">, CXX11<"gnu", "sysv_abi">];
+}
+
def ThisCall : InheritableAttr {
let Spellings = [GNU<"thiscall">, CXX11<"gnu", "thiscall">,
Keyword<"__thiscall">, Keyword<"_thiscall">];
@@ -679,7 +712,7 @@ def TransparentUnion : InheritableAttr {
def Unavailable : InheritableAttr {
let Spellings = [GNU<"unavailable">];
- let Args = [StringArgument<"Message">];
+ let Args = [StringArgument<"Message", 1>];
}
def ArcWeakrefUnavailable : InheritableAttr {
@@ -687,13 +720,12 @@ def ArcWeakrefUnavailable : InheritableAttr {
let Subjects = [ObjCInterface];
}
-def ObjCGC : Attr {
+def ObjCGC : TypeAttr {
let Spellings = [GNU<"objc_gc">];
let Args = [IdentifierArgument<"Kind">];
- let ASTNode = 0;
}
-def ObjCOwnership : Attr {
+def ObjCOwnership : InheritableAttr {
let Spellings = [GNU<"objc_ownership">];
let Args = [IdentifierArgument<"Kind">];
let ASTNode = 0;
@@ -718,15 +750,14 @@ def Uuid : InheritableAttr {
let Subjects = [CXXRecord];
}
-def VectorSize : Attr {
+def VectorSize : TypeAttr {
let Spellings = [GNU<"vector_size">, CXX11<"gnu", "vector_size">];
let Args = [ExprArgument<"NumBytes">];
- let ASTNode = 0;
}
def VecTypeHint : InheritableAttr {
let Spellings = [GNU<"vec_type_hint">];
- let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
+ let Args = [TypeArgument<"TypeHint">];
}
def Visibility : InheritableAttr {
@@ -750,6 +781,11 @@ def VecReturn : InheritableAttr {
let Subjects = [CXXRecord];
}
+def WarnUnused : InheritableAttr {
+ let Spellings = [GNU<"warn_unused">];
+ let Subjects = [Record];
+}
+
def WarnUnusedResult : InheritableAttr {
let Spellings = [GNU<"warn_unused_result">,
CXX11<"clang", "warn_unused_result">,
@@ -766,16 +802,20 @@ def WeakImport : InheritableAttr {
def WeakRef : InheritableAttr {
let Spellings = [GNU<"weakref">, CXX11<"gnu", "weakref">];
+ // A WeakRef that has an argument is treated as being an AliasAttr
+ let Args = [StringArgument<"Aliasee", 1>];
}
-def X86ForceAlignArgPointer : InheritableAttr {
+def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr {
let Spellings = [];
}
// Attribute to disable AddressSanitizer (or equivalent) checks.
def NoSanitizeAddress : InheritableAttr {
let Spellings = [GNU<"no_address_safety_analysis">,
- GNU<"no_sanitize_address">];
+ GNU<"no_sanitize_address">,
+ CXX11<"gnu", "no_address_safety_analysis">,
+ CXX11<"gnu", "no_sanitize_address">];
}
// Attribute to disable ThreadSanitizer checks.
@@ -852,6 +892,20 @@ def SharedLockFunction : InheritableAttr {
let TemplateDependent = 1;
}
+def AssertExclusiveLock : InheritableAttr {
+ let Spellings = [GNU<"assert_exclusive_lock">];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+ let TemplateDependent = 1;
+}
+
+def AssertSharedLock : InheritableAttr {
+ let Spellings = [GNU<"assert_shared_lock">];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+ let TemplateDependent = 1;
+}
+
// The first argument is an integer or boolean value specifying the return value
// of a successful lock acquisition.
def ExclusiveTrylockFunction : InheritableAttr {
@@ -905,6 +959,56 @@ def SharedLocksRequired : InheritableAttr {
let TemplateDependent = 1;
}
+// C/C++ consumed attributes.
+
+def Consumable : InheritableAttr {
+ let Spellings = [GNU<"consumable">];
+ let Subjects = [CXXRecord];
+ let Args = [EnumArgument<"DefaultState", "ConsumedState",
+ ["unknown", "consumed", "unconsumed"],
+ ["Unknown", "Consumed", "Unconsumed"]>];
+}
+
+def CallableWhen : InheritableAttr {
+ let Spellings = [GNU<"callable_when">];
+ let Subjects = [CXXMethod];
+ let Args = [VariadicEnumArgument<"CallableState", "ConsumedState",
+ ["unknown", "consumed", "unconsumed"],
+ ["Unknown", "Consumed", "Unconsumed"]>];
+}
+
+def ParamTypestate : InheritableAttr {
+ let Spellings = [GNU<"param_typestate">];
+ let Subjects = [ParmVar];
+ let Args = [EnumArgument<"ParamState", "ConsumedState",
+ ["unknown", "consumed", "unconsumed"],
+ ["Unknown", "Consumed", "Unconsumed"]>];
+}
+
+def ReturnTypestate : InheritableAttr {
+ let Spellings = [GNU<"return_typestate">];
+ let Subjects = [Function, ParmVar];
+ let Args = [EnumArgument<"State", "ConsumedState",
+ ["unknown", "consumed", "unconsumed"],
+ ["Unknown", "Consumed", "Unconsumed"]>];
+}
+
+def SetTypestate : InheritableAttr {
+ let Spellings = [GNU<"set_typestate">];
+ let Subjects = [CXXMethod];
+ let Args = [EnumArgument<"NewState", "ConsumedState",
+ ["unknown", "consumed", "unconsumed"],
+ ["Unknown", "Consumed", "Unconsumed"]>];
+}
+
+def TestTypestate : InheritableAttr {
+ let Spellings = [GNU<"test_typestate">];
+ let Subjects = [CXXMethod];
+ let Args = [EnumArgument<"TestState", "ConsumedState",
+ ["consumed", "unconsumed"],
+ ["Consumed", "Unconsumed"]>];
+}
+
// Type safety attributes for `void *' pointers and type tags.
def ArgumentWithTypeTag : InheritableAttr {
@@ -915,6 +1019,7 @@ def ArgumentWithTypeTag : InheritableAttr {
UnsignedArgument<"TypeTagIdx">,
BoolArgument<"IsPointer">];
let Subjects = [Function];
+ let HasCustomParsing = 1;
}
def TypeTagForDatatype : InheritableAttr {
@@ -924,11 +1029,12 @@ def TypeTagForDatatype : InheritableAttr {
BoolArgument<"LayoutCompatible">,
BoolArgument<"MustBeNull">];
let Subjects = [Var];
+ let HasCustomParsing = 1;
}
// Microsoft-related attributes
-def MsProperty : Attr {
+def MsProperty : IgnoredAttr {
let Spellings = [Declspec<"property">];
}
@@ -936,11 +1042,11 @@ def MsStruct : InheritableAttr {
let Spellings = [Declspec<"ms_struct">];
}
-def DLLExport : InheritableAttr {
+def DLLExport : InheritableAttr, TargetSpecificAttr {
let Spellings = [Declspec<"dllexport">];
}
-def DLLImport : InheritableAttr {
+def DLLImport : InheritableAttr, TargetSpecificAttr {
let Spellings = [Declspec<"dllimport">];
}
@@ -948,18 +1054,30 @@ def ForceInline : InheritableAttr {
let Spellings = [Keyword<"__forceinline">];
}
+def SelectAny : InheritableAttr {
+ let Spellings = [Declspec<"selectany">];
+}
+
def Win64 : InheritableAttr {
let Spellings = [Keyword<"__w64">];
}
-def Ptr32 : InheritableAttr {
+def Ptr32 : TypeAttr {
let Spellings = [Keyword<"__ptr32">];
}
-def Ptr64 : InheritableAttr {
+def Ptr64 : TypeAttr {
let Spellings = [Keyword<"__ptr64">];
}
+def SPtr : TypeAttr {
+ let Spellings = [Keyword<"__sptr">];
+}
+
+def UPtr : TypeAttr {
+ let Spellings = [Keyword<"__uptr">];
+}
+
class MSInheritanceAttr : InheritableAttr;
def SingleInheritance : MSInheritanceAttr {
diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h
index bd090ecc0d1b..7c4e2c75f04d 100644
--- a/include/clang/Basic/AttrKinds.h
+++ b/include/clang/Basic/AttrKinds.h
@@ -24,7 +24,7 @@ enum Kind {
#define ATTR(X) X,
#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,
#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X,
-#define LAST_MS_INHERITABLE_ATTR(X) X, LAST_MS_INHERITABLE = X,
+#define LAST_MS_INHERITANCE_ATTR(X) X, LAST_MS_INHERITANCE = X,
#include "clang/Basic/AttrList.inc"
NUM_ATTRS
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 0a513efdbc16..55c6ed7deead 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -25,6 +25,7 @@
// c -> char
// s -> short
// i -> int
+// h -> half
// f -> float
// d -> double
// z -> size_t
@@ -70,6 +71,8 @@
// f -> this is a libc/libm function without the '__builtin_' prefix. It can
// be followed by ':headername:' to state which header this function
// comes from.
+// i -> this is a runtime library implemented function without the
+// '__builtin_' prefix. It will be implemented in compiter-rt or libgcc.
// p:N: -> this is a printf-like function whose Nth argument is the format
// string.
// P:N: -> similar to the p:N: attribute, but the function is like vprintf
@@ -89,6 +92,10 @@
# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
#endif
+#if defined(BUILTIN) && !defined(LANGBUILTIN)
+# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
// Standard libc/libm functions:
BUILTIN(__builtin_atan2 , "ddd" , "Fnc")
BUILTIN(__builtin_atan2f, "fff" , "Fnc")
@@ -236,8 +243,8 @@ BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc")
BUILTIN(__builtin_nextafter , "ddd", "Fnc")
BUILTIN(__builtin_nextafterf, "fff", "Fnc")
BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc")
-BUILTIN(__builtin_nexttoward , "ddd", "Fnc")
-BUILTIN(__builtin_nexttowardf, "fff", "Fnc")
+BUILTIN(__builtin_nexttoward , "ddLd", "Fnc")
+BUILTIN(__builtin_nexttowardf, "ffLd", "Fnc")
BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc")
BUILTIN(__builtin_remainder , "ddd", "Fnc")
BUILTIN(__builtin_remainderf, "fff", "Fnc")
@@ -485,6 +492,7 @@ BUILTIN(__builtin_trap, "v", "nr")
BUILTIN(__builtin_debugtrap, "v", "n")
BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
+BUILTIN(__builtin_convertvector, "v." , "nct")
BUILTIN(__builtin_alloca, "v*z" , "n")
// "Overloaded" Atomic operator builtins. These are overloaded to support data
@@ -666,11 +674,11 @@ BUILTIN(__builtin_abort, "v", "Fnr")
BUILTIN(__builtin_index, "c*cC*i", "Fn")
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
-// Microsoft builtins.
-BUILTIN(__assume, "vb", "n")
-BUILTIN(__noop, "v.", "n")
-BUILTIN(__debugbreak, "v", "n")
-
+// Microsoft builtins. These are only active with -fms-extensions.
+LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__noop, "v.", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
// C99 library functions
// C99 stdlib.h
@@ -718,48 +726,47 @@ LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
// C99
+#undef setjmp
+LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
-// Non-C library functions
-// FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode!
-LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_LANGUAGES)
+// Non-C library functions, active in GNU mode only.
+LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_GNU_LANGUAGES)
// POSIX string.h
-LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
// POSIX strings.h
-LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
-LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
-LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
+LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_GNU_LANGUAGES)
// In some systems str[n]casejmp is a macro that expands to _str[n]icmp.
// We undefine then here to avoid wrong name.
#undef strcasecmp
#undef strncasecmp
-LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
-LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
+LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_GNU_LANGUAGES)
// POSIX unistd.h
-LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
-LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
+LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_GNU_LANGUAGES)
// POSIX setjmp.h
// In some systems setjmp is a macro that expands to _setjmp. We undefine
// it here to avoid having two identical LIBBUILTIN entries.
-#undef setjmp
-LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES)
-
-LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+
+LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES)
// non-standard but very common
-LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
// id objc_msgSend(id, SEL, ...)
LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
// long double objc_msgSend_fpret(id self, SEL op, ...)
@@ -814,109 +821,321 @@ LIBBUILTIN(NSLog, "vG.", "fp:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
LIBBUILTIN(NSLogv, "vGa", "fP:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
// Builtin math library functions
-LIBBUILTIN(acos, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(acosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(acosf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atan2, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atan2f, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atan2l, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(asin, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(asinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(asinf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(abs, "ii", "fnc", "stdlib.h", ALL_LANGUAGES)
+LIBBUILTIN(labs, "LiLi", "fnc", "stdlib.h", ALL_LANGUAGES)
+LIBBUILTIN(llabs, "LLiLLi", "fnc", "stdlib.h", ALL_LANGUAGES)
-LIBBUILTIN(atan, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(atanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(atanf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(copysign, "ddd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(copysignf, "fff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(copysignl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(atan2, "ddd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(atan2l, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(atan2f, "fff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fabs, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fabsf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fabsl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(ceil, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(ceill, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(ceilf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmod, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmodf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmodl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cimag, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
-LIBBUILTIN(cimagf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
-LIBBUILTIN(cimagl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(frexp, "ddi*", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(frexpf, "ffi*", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(frexpl, "LdLdi*", "fn", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(creal, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
-LIBBUILTIN(crealf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
-LIBBUILTIN(creall, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ldexp, "ddi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ldexpf, "ffi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ldexpl, "LdLdi", "fne", "math.h", ALL_LANGUAGES)
+
+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(pow, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(powf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(powl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(acos, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(acosf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(acosl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(acosh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(acoshf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(acoshl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(asin, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(asinf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(asinl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(asinh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(asinhf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(asinhl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(atan, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atanf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atanl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(atanh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atanhf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(atanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cbrt, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cbrtf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cbrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ceil, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ceilf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ceill, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cos, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cosf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cosl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cosh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(coshf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(coshl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(erf, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(erff, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(erfl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(erfc, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(erfcf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(erfcl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(exp, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(expf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(expl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(exp2, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(exp2f, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(exp2l, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(expm1, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(expm1f, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(expm1l, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(fdim, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fdimf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fdiml, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(floor, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(floorf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(floorl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(fma, "dddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmaf, "ffff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmal, "LdLdLdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(fmax, "ddd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmaxf, "fff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fmaxl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(fmin, "ddd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fminf, "fff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fminl, "LdLdLd", "fnc", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(hypot, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(hypotf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(hypotl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ilogb, "id", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ilogbf, "if", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(ilogbl, "iLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(copysign, "ddd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(copysignl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(copysignf, "fff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgamma, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammaf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llrint, "LLid", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llrintf, "LLif", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llrintl, "LLiLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(exp, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(expl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(expf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llround, "LLid", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llroundf, "LLif", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(llroundl, "LLiLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(exp2, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(exp2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(exp2f, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(logf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(logl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fabs, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fabsl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fabsf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log10, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log10f, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log10l, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floor, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floorl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floorf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log1p, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log1pf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log1pl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fma, "dddd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log2, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log2f, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(log2l, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmax, "ddd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmaxl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmaxf, "fff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(logb, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(logbf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(logbl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmin, "ddd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fminl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fminf, "fff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lrint, "Lid", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lrintf, "Lif", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lrintl, "LiLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(log, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(logl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(logf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lround, "Lid", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lroundf, "Lif", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lroundl, "LiLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(log2, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(log2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(log2f, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nearbyint, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nearbyintf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nearbyintl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nearbyint, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nearbyintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nearbyintf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nextafter, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nextafterf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nextafterl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nexttoward, "ddLd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nexttowardf, "ffLd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nexttowardl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(rint, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(rintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(rintf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(remainder, "ddd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(remainderf, "fff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(remainderl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(round, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(roundl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(roundf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(rint, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(rintf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(rintl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(round, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(roundf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(roundl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalbln, "ddLi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalblnf, "ffLi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalblnl, "LdLdLi", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(tan, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(tanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(tanf, "ff", "fe", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalbn, "ddi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalbnf, "ffi", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(scalbnl, "LdLdi", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(trunc, "dd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(truncl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(truncf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sin, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sinf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sinl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(sinh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sinhf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sinhl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(sqrt, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sqrtf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(sqrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(tan, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tanf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tanl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(tanh, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tanhf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(tgamma, "dd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tgammaf, "ff", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(tgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(trunc, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(truncf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(truncl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cabs, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cabsf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cabsl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cacos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cacosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cacosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cacosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cacoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cacoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(carg, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cargf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cargl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(casin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(casinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(casinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(casinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(casinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(casinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(catan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(catanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(catanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(catanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(catanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(catanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ccos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ccosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ccosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ccosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ccoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ccoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cexp, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cexpf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cexpl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cimag, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cimagf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cimagl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(conj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(conjf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(conjl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(clog, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(clogf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(clogl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cproj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cprojf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cprojl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(cpow, "XdXdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cpowf, "XfXfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cpowl, "XLdXLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(creal, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(crealf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(creall, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(csin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(csinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(csqrt, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csqrtf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(csqrtl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ctan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ctanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ctanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(ctanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ctanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(ctanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES)
// Blocks runtime Builtin math library functions
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
@@ -927,14 +1146,40 @@ LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
BUILTIN(__builtin_annotation, "v.", "tn")
// Multiprecision Arithmetic Builtins.
+BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n")
BUILTIN(__builtin_addc, "UiUiCUiCUiCUi*", "n")
BUILTIN(__builtin_addcl, "ULiULiCULiCULiCULi*", "n")
BUILTIN(__builtin_addcll, "ULLiULLiCULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_subcb, "UcUcCUcCUcCUc*", "n")
BUILTIN(__builtin_subcs, "UsUsCUsCUsCUs*", "n")
BUILTIN(__builtin_subc, "UiUiCUiCUiCUi*", "n")
BUILTIN(__builtin_subcl, "ULiULiCULiCULiCULi*", "n")
BUILTIN(__builtin_subcll, "ULLiULLiCULLiCULLiCULLi*", "n")
+// Checked Arithmetic Builtins for Security.
+BUILTIN(__builtin_uadd_overflow, "bUiCUiCUi*", "n")
+BUILTIN(__builtin_uaddl_overflow, "bULiCULiCULi*", "n")
+BUILTIN(__builtin_uaddll_overflow, "bULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_usub_overflow, "bUiCUiCUi*", "n")
+BUILTIN(__builtin_usubl_overflow, "bULiCULiCULi*", "n")
+BUILTIN(__builtin_usubll_overflow, "bULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_umul_overflow, "bUiCUiCUi*", "n")
+BUILTIN(__builtin_umull_overflow, "bULiCULiCULi*", "n")
+BUILTIN(__builtin_umulll_overflow, "bULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_sadd_overflow, "bSiCSiCSi*", "n")
+BUILTIN(__builtin_saddl_overflow, "bSLiCSLiCSLi*", "n")
+BUILTIN(__builtin_saddll_overflow, "bSLLiCSLLiCSLLi*", "n")
+BUILTIN(__builtin_ssub_overflow, "bSiCSiCSi*", "n")
+BUILTIN(__builtin_ssubl_overflow, "bSLiCSLiCSLi*", "n")
+BUILTIN(__builtin_ssubll_overflow, "bSLLiCSLLiCSLLi*", "n")
+BUILTIN(__builtin_smul_overflow, "bSiCSiCSi*", "n")
+BUILTIN(__builtin_smull_overflow, "bSLiCSLiCSLi*", "n")
+BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n")
+
+// Clang builtins (not available in GCC).
+BUILTIN(__builtin_addressof, "v*v&", "nct")
+
#undef BUILTIN
#undef LIBBUILTIN
+#undef LANGBUILTIN
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 3b88e1550cba..9756f21a1c48 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -31,10 +31,14 @@ namespace clang {
class LangOptions;
enum LanguageID {
- C_LANG = 0x1, // builtin for c only.
- CXX_LANG = 0x2, // builtin for cplusplus only.
- OBJC_LANG = 0x4, // builtin for objective-c and objective-c++
- ALL_LANGUAGES = (C_LANG|CXX_LANG|OBJC_LANG) //builtin is for all languages.
+ GNU_LANG = 0x1, // builtin requires GNU mode.
+ C_LANG = 0x2, // builtin for c only.
+ CXX_LANG = 0x4, // builtin for cplusplus only.
+ OBJC_LANG = 0x8, // builtin for objective-c and objective-c++
+ MS_LANG = 0x10, // builtin requires MS mode.
+ 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.
};
namespace Builtin {
@@ -73,9 +77,8 @@ public:
/// such.
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
- /// \brief Popular the vector with the names of all of the builtins.
- void GetBuiltinNames(SmallVectorImpl<const char *> &Names,
- bool NoBuiltins);
+ /// \brief Populate the vector with the names of all of the builtins.
+ void GetBuiltinNames(SmallVectorImpl<const char *> &Names);
/// \brief Return the identifier name for the specified builtin,
/// e.g. "__builtin_abs".
@@ -128,6 +131,13 @@ public:
return strchr(GetRecord(ID).Attributes, 'f') != 0;
}
+ /// \brief Determines whether this builtin is a predefined compiler-rt/libgcc
+ /// function, such as "__clear_cache", where we know the signature a
+ /// priori.
+ bool isPredefinedRuntimeFunction(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'i') != 0;
+ }
+
/// \brief Determines whether this builtin has custom typechecking.
bool hasCustomTypechecking(unsigned ID) const {
return strchr(GetRecord(ID).Attributes, 't') != 0;
@@ -163,6 +173,10 @@ public:
private:
const Info &GetRecord(unsigned ID) const;
+
+ /// \brief Is this builtin supported according to the given language options?
+ bool BuiltinIsSupported(const Builtin::Info &BuiltinInfo,
+ const LangOptions &LangOpts);
};
}
diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
index 9e9f6d0875db..aafd202aae11 100644
--- a/include/clang/Basic/BuiltinsAArch64.def
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -15,4 +15,11 @@
// The format of this database matches clang/Basic/Builtins.def.
// In libgcc
-BUILTIN(__clear_cache, "vv*v*", "")
+BUILTIN(__clear_cache, "vv*v*", "i")
+// NEON
+#define GET_NEON_AARCH64_BUILTINS
+#include "clang/Basic/arm_neon.inc"
+#undef GET_NEON_AARCH64_BUILTINS
+#undef GET_NEON_BUILTINS
+
+#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index 888e529111ab..21bb892a8b9b 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -15,7 +15,7 @@
// The format of this database matches clang/Basic/Builtins.def.
// In libgcc
-BUILTIN(__clear_cache, "v.", "")
+BUILTIN(__clear_cache, "vv*v*", "i")
BUILTIN(__builtin_thread_pointer, "v*", "")
// Saturating arithmetic
@@ -24,10 +24,14 @@ BUILTIN(__builtin_arm_qsub, "iii", "nc")
BUILTIN(__builtin_arm_ssat, "iiUi", "nc")
BUILTIN(__builtin_arm_usat, "UiUiUi", "nc")
-// Store and load exclusive doubleword
+// Store and load exclusive
BUILTIN(__builtin_arm_ldrexd, "LLUiv*", "")
BUILTIN(__builtin_arm_strexd, "iLLUiv*", "")
+BUILTIN(__builtin_arm_ldrex, "v.", "t")
+BUILTIN(__builtin_arm_strex, "i.", "t")
+BUILTIN(__builtin_arm_clrex, "v", "")
+
// VFP
BUILTIN(__builtin_arm_get_fpscr, "Ui", "nc")
BUILTIN(__builtin_arm_set_fpscr, "vUi", "nc")
@@ -44,6 +48,23 @@ BUILTIN(__builtin_arm_cdp2, "vUiUiUiUiUiUi", "")
BUILTIN(__builtin_arm_mcrr, "vUiUiUiUiUi", "")
BUILTIN(__builtin_arm_mcrr2, "vUiUiUiUiUi", "")
+// CRC32
+BUILTIN(__builtin_arm_crc32b, "UiUiUc", "nc")
+BUILTIN(__builtin_arm_crc32cb, "UiUiUc", "nc")
+BUILTIN(__builtin_arm_crc32h, "UiUiUs", "nc")
+BUILTIN(__builtin_arm_crc32ch, "UiUiUs", "nc")
+BUILTIN(__builtin_arm_crc32w, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_crc32d, "UiUiLLUi", "nc")
+BUILTIN(__builtin_arm_crc32cd, "UiUiLLUi", "nc")
+
+// HINT
+BUILTIN(__builtin_arm_sevl, "v", "")
+
+// Data barrier
+BUILTIN(__builtin_arm_dmb, "vUi", "nc")
+BUILTIN(__builtin_arm_dsb, "vUi", "nc")
+
// NEON
#define GET_NEON_BUILTINS
#include "clang/Basic/arm_neon.inc"
diff --git a/include/clang/Basic/BuiltinsMips.def b/include/clang/Basic/BuiltinsMips.def
index 43fb90756efb..e435d52ed4f9 100644
--- a/include/clang/Basic/BuiltinsMips.def
+++ b/include/clang/Basic/BuiltinsMips.def
@@ -185,4 +185,716 @@ BUILTIN(__builtin_mips_subu_s_ph, "V2sV2sV2s", "n")
BUILTIN(__builtin_mips_subuh_qb, "V4ScV4ScV4Sc", "nc")
BUILTIN(__builtin_mips_subuh_r_qb, "V4ScV4ScV4Sc", "nc")
+// MIPS MSA
+
+BUILTIN(__builtin_msa_add_a_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_add_a_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_add_a_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_add_a_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_adds_a_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_adds_a_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_adds_a_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_adds_a_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_adds_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_adds_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_adds_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_adds_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_adds_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_adds_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_adds_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_adds_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_addv_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_addv_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_addv_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_addv_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_addvi_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_addvi_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_addvi_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_addvi_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_and_v, "V16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_andi_b, "V16UcV16UcIUi", "nc")
+
+BUILTIN(__builtin_msa_asub_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_asub_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_asub_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_asub_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_asub_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_asub_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_asub_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_asub_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_ave_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_ave_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_ave_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_ave_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_ave_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_ave_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_ave_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_ave_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_aver_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_aver_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_aver_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_aver_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_aver_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_aver_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_aver_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_aver_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bclr_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_bclr_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_bclr_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_bclr_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bclri_b, "V16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_bclri_h, "V8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_bclri_w, "V4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_bclri_d, "V2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_binsl_b, "V16UcV16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_binsl_h, "V8UsV8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_binsl_w, "V4UiV4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_binsl_d, "V2ULLiV2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_binsli_b, "V16UcV16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_binsli_h, "V8UsV8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_binsli_w, "V4UiV4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_binsli_d, "V2ULLiV2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_binsr_b, "V16UcV16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_binsr_h, "V8UsV8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_binsr_w, "V4UiV4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_binsr_d, "V2ULLiV2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_binsri_b, "V16UcV16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_binsri_h, "V8UsV8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_binsri_w, "V4UiV4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_binsri_d, "V2ULLiV2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_bmnz_v, "V16UcV16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_bmnzi_b, "V16UcV16UcV16UcIUi", "nc")
+
+BUILTIN(__builtin_msa_bmz_v, "V16UcV16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_bmzi_b, "V16UcV16UcV16UcIUi", "nc")
+
+BUILTIN(__builtin_msa_bneg_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_bneg_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_bneg_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_bneg_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bnegi_b, "V16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_bnegi_h, "V8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_bnegi_w, "V4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_bnegi_d, "V2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_bnz_b, "iV16Uc", "nc")
+BUILTIN(__builtin_msa_bnz_h, "iV8Us", "nc")
+BUILTIN(__builtin_msa_bnz_w, "iV4Ui", "nc")
+BUILTIN(__builtin_msa_bnz_d, "iV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bnz_v, "iV16Uc", "nc")
+
+BUILTIN(__builtin_msa_bsel_v, "V16UcV16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_bseli_b, "V16UcV16UcV16UcIUi", "nc")
+
+BUILTIN(__builtin_msa_bset_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_bset_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_bset_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_bset_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bseti_b, "V16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_bseti_h, "V8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_bseti_w, "V4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_bseti_d, "V2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_bz_b, "iV16Uc", "nc")
+BUILTIN(__builtin_msa_bz_h, "iV8Us", "nc")
+BUILTIN(__builtin_msa_bz_w, "iV4Ui", "nc")
+BUILTIN(__builtin_msa_bz_d, "iV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_bz_v, "iV16Uc", "nc")
+
+BUILTIN(__builtin_msa_ceq_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_ceq_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_ceq_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_ceq_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_ceqi_b, "V16ScV16ScISi", "nc")
+BUILTIN(__builtin_msa_ceqi_h, "V8SsV8SsISi", "nc")
+BUILTIN(__builtin_msa_ceqi_w, "V4SiV4SiISi", "nc")
+BUILTIN(__builtin_msa_ceqi_d, "V2SLLiV2SLLiISi", "nc")
+
+BUILTIN(__builtin_msa_cfcmsa, "iIi", "n")
+
+BUILTIN(__builtin_msa_cle_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_cle_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_cle_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_cle_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_cle_u_b, "V16ScV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_cle_u_h, "V8SsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_cle_u_w, "V4SiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_cle_u_d, "V2SLLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_clei_s_b, "V16ScV16ScISi", "nc")
+BUILTIN(__builtin_msa_clei_s_h, "V8SsV8SsISi", "nc")
+BUILTIN(__builtin_msa_clei_s_w, "V4SiV4SiISi", "nc")
+BUILTIN(__builtin_msa_clei_s_d, "V2SLLiV2SLLiISi", "nc")
+
+BUILTIN(__builtin_msa_clei_u_b, "V16ScV16UcIUi", "nc")
+BUILTIN(__builtin_msa_clei_u_h, "V8SsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_clei_u_w, "V4SiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_clei_u_d, "V2SLLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_clt_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_clt_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_clt_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_clt_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_clt_u_b, "V16ScV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_clt_u_h, "V8SsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_clt_u_w, "V4SiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_clt_u_d, "V2SLLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_clti_s_b, "V16ScV16ScISi", "nc")
+BUILTIN(__builtin_msa_clti_s_h, "V8SsV8SsISi", "nc")
+BUILTIN(__builtin_msa_clti_s_w, "V4SiV4SiISi", "nc")
+BUILTIN(__builtin_msa_clti_s_d, "V2SLLiV2SLLiISi", "nc")
+
+BUILTIN(__builtin_msa_clti_u_b, "V16ScV16UcIUi", "nc")
+BUILTIN(__builtin_msa_clti_u_h, "V8SsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_clti_u_w, "V4SiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_clti_u_d, "V2SLLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_copy_s_b, "iV16ScIUi", "nc")
+BUILTIN(__builtin_msa_copy_s_h, "iV8SsIUi", "nc")
+BUILTIN(__builtin_msa_copy_s_w, "iV4SiIUi", "nc")
+BUILTIN(__builtin_msa_copy_s_d, "LLiV2SLLiIUi", "nc")
+
+BUILTIN(__builtin_msa_copy_u_b, "iV16UcIUi", "nc")
+BUILTIN(__builtin_msa_copy_u_h, "iV8UsIUi", "nc")
+BUILTIN(__builtin_msa_copy_u_w, "iV4UiIUi", "nc")
+BUILTIN(__builtin_msa_copy_u_d, "LLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_ctcmsa, "vIii", "n")
+
+BUILTIN(__builtin_msa_div_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_div_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_div_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_div_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_div_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_div_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_div_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_div_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_dotp_s_h, "V8SsV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_dotp_s_w, "V4SiV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_dotp_s_d, "V2SLLiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_dotp_u_h, "V8UsV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_dotp_u_w, "V4UiV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_dotp_u_d, "V2ULLiV4UiV4Ui", "nc")
+
+BUILTIN(__builtin_msa_dpadd_s_h, "V8SsV8SsV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_dpadd_s_w, "V4SiV4SiV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_dpadd_s_d, "V2SLLiV2SLLiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_dpadd_u_h, "V8UsV8UsV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_dpadd_u_w, "V4UiV4UiV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_dpadd_u_d, "V2ULLiV2ULLiV4UiV4Ui", "nc")
+
+BUILTIN(__builtin_msa_dpsub_s_h, "V8SsV8SsV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_dpsub_s_w, "V4SiV4SiV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_dpsub_s_d, "V2SLLiV2SLLiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_dpsub_u_h, "V8UsV8UsV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_dpsub_u_w, "V4UiV4UiV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_dpsub_u_d, "V2ULLiV2ULLiV4UiV4Ui", "nc")
+
+BUILTIN(__builtin_msa_fadd_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fadd_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcaf_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcaf_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fceq_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fceq_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fclass_w, "V4iV4f", "nc")
+BUILTIN(__builtin_msa_fclass_d, "V2LLiV2d", "nc")
+
+BUILTIN(__builtin_msa_fcle_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcle_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fclt_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fclt_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcne_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcne_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcor_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcor_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcueq_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcueq_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcule_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcule_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcult_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcult_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcun_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcun_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fcune_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fcune_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fdiv_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fdiv_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fexdo_h, "V8hV4fV4f", "nc")
+BUILTIN(__builtin_msa_fexdo_w, "V4fV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fexp2_w, "V4fV4fV4i", "nc")
+BUILTIN(__builtin_msa_fexp2_d, "V2dV2dV2LLi", "nc")
+
+BUILTIN(__builtin_msa_fexupl_w, "V4fV8h", "nc")
+BUILTIN(__builtin_msa_fexupl_d, "V2dV4f", "nc")
+
+BUILTIN(__builtin_msa_fexupr_w, "V4fV8h", "nc")
+BUILTIN(__builtin_msa_fexupr_d, "V2dV4f", "nc")
+
+BUILTIN(__builtin_msa_ffint_s_w, "V4fV4Si", "nc")
+BUILTIN(__builtin_msa_ffint_s_d, "V2dV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_ffint_u_w, "V4fV4Ui", "nc")
+BUILTIN(__builtin_msa_ffint_u_d, "V2dV2ULLi", "nc")
+
+// ffql uses integers since long _Fract is not implemented
+BUILTIN(__builtin_msa_ffql_w, "V4fV8Ss", "nc")
+BUILTIN(__builtin_msa_ffql_d, "V2dV4Si", "nc")
+
+// ffqr uses integers since long _Fract is not implemented
+BUILTIN(__builtin_msa_ffqr_w, "V4fV8Ss", "nc")
+BUILTIN(__builtin_msa_ffqr_d, "V2dV4Si", "nc")
+
+BUILTIN(__builtin_msa_fill_b, "V16Sci", "nc")
+BUILTIN(__builtin_msa_fill_h, "V8Ssi", "nc")
+BUILTIN(__builtin_msa_fill_w, "V4Sii", "nc")
+BUILTIN(__builtin_msa_fill_d, "V2SLLiLLi", "nc")
+
+BUILTIN(__builtin_msa_flog2_w, "V4fV4f", "nc")
+BUILTIN(__builtin_msa_flog2_d, "V2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmadd_w, "V4fV4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmadd_d, "V2dV2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmax_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmax_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmax_a_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmax_a_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmin_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmin_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmin_a_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmin_a_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmsub_w, "V4fV4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmsub_d, "V2dV2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fmul_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fmul_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_frint_w, "V4fV4f", "nc")
+BUILTIN(__builtin_msa_frint_d, "V2dV2d", "nc")
+
+BUILTIN(__builtin_msa_frcp_w, "V4fV4f", "nc")
+BUILTIN(__builtin_msa_frcp_d, "V2dV2d", "nc")
+
+BUILTIN(__builtin_msa_frsqrt_w, "V4fV4f", "nc")
+BUILTIN(__builtin_msa_frsqrt_d, "V2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsaf_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsaf_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fseq_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fseq_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsle_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsle_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fslt_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fslt_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsne_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsne_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsor_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsor_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsqrt_w, "V4fV4f", "nc")
+BUILTIN(__builtin_msa_fsqrt_d, "V2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsub_w, "V4fV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsub_d, "V2dV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsueq_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsueq_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsule_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsule_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsult_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsult_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsun_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsun_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_fsune_w, "V4iV4fV4f", "nc")
+BUILTIN(__builtin_msa_fsune_d, "V2LLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_ftint_s_w, "V4SiV4f", "nc")
+BUILTIN(__builtin_msa_ftint_s_d, "V2SLLiV2d", "nc")
+
+BUILTIN(__builtin_msa_ftint_u_w, "V4UiV4f", "nc")
+BUILTIN(__builtin_msa_ftint_u_d, "V2ULLiV2d", "nc")
+
+BUILTIN(__builtin_msa_ftq_h, "V4UiV4fV4f", "nc")
+BUILTIN(__builtin_msa_ftq_w, "V2ULLiV2dV2d", "nc")
+
+BUILTIN(__builtin_msa_ftrunc_s_w, "V4SiV4f", "nc")
+BUILTIN(__builtin_msa_ftrunc_s_d, "V2SLLiV2d", "nc")
+
+BUILTIN(__builtin_msa_ftrunc_u_w, "V4UiV4f", "nc")
+BUILTIN(__builtin_msa_ftrunc_u_d, "V2ULLiV2d", "nc")
+
+BUILTIN(__builtin_msa_hadd_s_h, "V8SsV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_hadd_s_w, "V4SiV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_hadd_s_d, "V2SLLiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_hadd_u_h, "V8UsV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_hadd_u_w, "V4UiV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_hadd_u_d, "V2ULLiV4UiV4Ui", "nc")
+
+BUILTIN(__builtin_msa_hsub_s_h, "V8SsV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_hsub_s_w, "V4SiV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_hsub_s_d, "V2SLLiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_hsub_u_h, "V8UsV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_hsub_u_w, "V4UiV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_hsub_u_d, "V2ULLiV4UiV4Ui", "nc")
+
+BUILTIN(__builtin_msa_ilvev_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_ilvev_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_ilvev_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_ilvev_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_ilvl_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_ilvl_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_ilvl_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_ilvl_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_ilvod_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_ilvod_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_ilvod_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_ilvod_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_ilvr_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_ilvr_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_ilvr_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_ilvr_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_insert_b, "V16ScV16ScIUii", "nc")
+BUILTIN(__builtin_msa_insert_h, "V8SsV8SsIUii", "nc")
+BUILTIN(__builtin_msa_insert_w, "V4SiV4SiIUii", "nc")
+BUILTIN(__builtin_msa_insert_d, "V2SLLiV2SLLiIUiLLi", "nc")
+
+BUILTIN(__builtin_msa_insve_b, "V16ScV16ScIUiV16Sc", "nc")
+BUILTIN(__builtin_msa_insve_h, "V8SsV8SsIUiV8Ss", "nc")
+BUILTIN(__builtin_msa_insve_w, "V4SiV4SiIUiV4Si", "nc")
+BUILTIN(__builtin_msa_insve_d, "V2SLLiV2SLLiIUiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_ld_b, "V16Scv*Ii", "nc")
+BUILTIN(__builtin_msa_ld_h, "V8Ssv*Ii", "nc")
+BUILTIN(__builtin_msa_ld_w, "V4Siv*Ii", "nc")
+BUILTIN(__builtin_msa_ld_d, "V2SLLiv*Ii", "nc")
+
+BUILTIN(__builtin_msa_ldi_b, "V16cIi", "nc")
+BUILTIN(__builtin_msa_ldi_h, "V8sIi", "nc")
+BUILTIN(__builtin_msa_ldi_w, "V4iIi", "nc")
+BUILTIN(__builtin_msa_ldi_d, "V2LLiIi", "nc")
+
+BUILTIN(__builtin_msa_madd_q_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_madd_q_w, "V4SiV4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_maddr_q_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_maddr_q_w, "V4SiV4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_maddv_b, "V16ScV16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_maddv_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_maddv_w, "V4SiV4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_maddv_d, "V2SLLiV2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_max_a_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_max_a_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_max_a_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_max_a_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_max_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_max_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_max_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_max_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_max_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_max_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_max_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_max_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_maxi_s_b, "V16ScV16ScIi", "nc")
+BUILTIN(__builtin_msa_maxi_s_h, "V8SsV8SsIi", "nc")
+BUILTIN(__builtin_msa_maxi_s_w, "V4SiV4SiIi", "nc")
+BUILTIN(__builtin_msa_maxi_s_d, "V2SLLiV2SLLiIi", "nc")
+
+BUILTIN(__builtin_msa_maxi_u_b, "V16UcV16UcIi", "nc")
+BUILTIN(__builtin_msa_maxi_u_h, "V8UsV8UsIi", "nc")
+BUILTIN(__builtin_msa_maxi_u_w, "V4UiV4UiIi", "nc")
+BUILTIN(__builtin_msa_maxi_u_d, "V2ULLiV2ULLiIi", "nc")
+
+BUILTIN(__builtin_msa_min_a_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_min_a_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_min_a_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_min_a_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_min_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_min_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_min_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_min_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_min_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_min_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_min_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_min_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_mini_s_b, "V16ScV16ScIi", "nc")
+BUILTIN(__builtin_msa_mini_s_h, "V8SsV8SsIi", "nc")
+BUILTIN(__builtin_msa_mini_s_w, "V4SiV4SiIi", "nc")
+BUILTIN(__builtin_msa_mini_s_d, "V2SLLiV2SLLiIi", "nc")
+
+BUILTIN(__builtin_msa_mini_u_b, "V16UcV16UcIi", "nc")
+BUILTIN(__builtin_msa_mini_u_h, "V8UsV8UsIi", "nc")
+BUILTIN(__builtin_msa_mini_u_w, "V4UiV4UiIi", "nc")
+BUILTIN(__builtin_msa_mini_u_d, "V2ULLiV2ULLiIi", "nc")
+
+BUILTIN(__builtin_msa_mod_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_mod_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_mod_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_mod_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_mod_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_mod_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_mod_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_mod_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_move_v, "V16ScV16Sc", "nc")
+
+BUILTIN(__builtin_msa_msub_q_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_msub_q_w, "V4SiV4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_msubr_q_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_msubr_q_w, "V4SiV4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_msubv_b, "V16ScV16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_msubv_h, "V8SsV8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_msubv_w, "V4SiV4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_msubv_d, "V2SLLiV2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_mul_q_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_mul_q_w, "V4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_mulr_q_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_mulr_q_w, "V4SiV4SiV4Si", "nc")
+
+BUILTIN(__builtin_msa_mulv_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_mulv_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_mulv_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_mulv_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_nloc_b, "V16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_nloc_h, "V8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_nloc_w, "V4SiV4Si", "nc")
+BUILTIN(__builtin_msa_nloc_d, "V2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_nlzc_b, "V16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_nlzc_h, "V8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_nlzc_w, "V4SiV4Si", "nc")
+BUILTIN(__builtin_msa_nlzc_d, "V2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_nor_v, "V16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_nori_b, "V16UcV16cIUi", "nc")
+
+BUILTIN(__builtin_msa_or_v, "V16UcV16UcV16Uc", "nc")
+
+BUILTIN(__builtin_msa_ori_b, "V16UcV16UcIUi", "nc")
+
+BUILTIN(__builtin_msa_pckev_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_pckev_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_pckev_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_pckev_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_pckod_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_pckod_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_pckod_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_pckod_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_pcnt_b, "V16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_pcnt_h, "V8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_pcnt_w, "V4SiV4Si", "nc")
+BUILTIN(__builtin_msa_pcnt_d, "V2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_sat_s_b, "V16ScV16ScIUi", "nc")
+BUILTIN(__builtin_msa_sat_s_h, "V8SsV8SsIUi", "nc")
+BUILTIN(__builtin_msa_sat_s_w, "V4SiV4SiIUi", "nc")
+BUILTIN(__builtin_msa_sat_s_d, "V2SLLiV2SLLiIUi", "nc")
+
+BUILTIN(__builtin_msa_sat_u_b, "V16UcV16UcIUi", "nc")
+BUILTIN(__builtin_msa_sat_u_h, "V8UsV8UsIUi", "nc")
+BUILTIN(__builtin_msa_sat_u_w, "V4UiV4UiIUi", "nc")
+BUILTIN(__builtin_msa_sat_u_d, "V2ULLiV2ULLiIUi", "nc")
+
+BUILTIN(__builtin_msa_shf_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_shf_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_shf_w, "V4iV4iIUi", "nc")
+
+BUILTIN(__builtin_msa_sld_b, "V16cV16cUi", "nc")
+BUILTIN(__builtin_msa_sld_h, "V8sV8sUi", "nc")
+BUILTIN(__builtin_msa_sld_w, "V4iV4iUi", "nc")
+BUILTIN(__builtin_msa_sld_d, "V2LLiV2LLiUi", "nc")
+
+BUILTIN(__builtin_msa_sldi_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_sldi_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_sldi_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_sldi_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_sll_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_sll_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_sll_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_sll_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_slli_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_slli_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_slli_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_slli_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_splat_b, "V16cV16cUi", "nc")
+BUILTIN(__builtin_msa_splat_h, "V8sV8sUi", "nc")
+BUILTIN(__builtin_msa_splat_w, "V4iV4iUi", "nc")
+BUILTIN(__builtin_msa_splat_d, "V2LLiV2LLiUi", "nc")
+
+BUILTIN(__builtin_msa_splati_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_splati_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_splati_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_splati_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_sra_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_sra_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_sra_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_sra_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_srai_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_srai_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_srai_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_srai_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_srar_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_srar_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_srar_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_srar_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_srari_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_srari_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_srari_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_srari_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_srl_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_srl_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_srl_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_srl_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_srli_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_srli_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_srli_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_srli_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_srlr_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_srlr_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_srlr_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_srlr_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_srlri_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_srlri_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_srlri_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_srlri_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_st_b, "vV16Scv*Ii", "nc")
+BUILTIN(__builtin_msa_st_h, "vV8Ssv*Ii", "nc")
+BUILTIN(__builtin_msa_st_w, "vV4Siv*Ii", "nc")
+BUILTIN(__builtin_msa_st_d, "vV2SLLiv*Ii", "nc")
+
+BUILTIN(__builtin_msa_subs_s_b, "V16ScV16ScV16Sc", "nc")
+BUILTIN(__builtin_msa_subs_s_h, "V8SsV8SsV8Ss", "nc")
+BUILTIN(__builtin_msa_subs_s_w, "V4SiV4SiV4Si", "nc")
+BUILTIN(__builtin_msa_subs_s_d, "V2SLLiV2SLLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_subs_u_b, "V16UcV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_subs_u_h, "V8UsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_subs_u_w, "V4UiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_subs_u_d, "V2ULLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_subsus_u_b, "V16UcV16UcV16Sc", "nc")
+BUILTIN(__builtin_msa_subsus_u_h, "V8UsV8UsV8Ss", "nc")
+BUILTIN(__builtin_msa_subsus_u_w, "V4UiV4UiV4Si", "nc")
+BUILTIN(__builtin_msa_subsus_u_d, "V2ULLiV2ULLiV2SLLi", "nc")
+
+BUILTIN(__builtin_msa_subsuu_s_b, "V16ScV16UcV16Uc", "nc")
+BUILTIN(__builtin_msa_subsuu_s_h, "V8SsV8UsV8Us", "nc")
+BUILTIN(__builtin_msa_subsuu_s_w, "V4SiV4UiV4Ui", "nc")
+BUILTIN(__builtin_msa_subsuu_s_d, "V2SLLiV2ULLiV2ULLi", "nc")
+
+BUILTIN(__builtin_msa_subv_b, "V16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_subv_h, "V8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_subv_w, "V4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_subv_d, "V2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_subvi_b, "V16cV16cIUi", "nc")
+BUILTIN(__builtin_msa_subvi_h, "V8sV8sIUi", "nc")
+BUILTIN(__builtin_msa_subvi_w, "V4iV4iIUi", "nc")
+BUILTIN(__builtin_msa_subvi_d, "V2LLiV2LLiIUi", "nc")
+
+BUILTIN(__builtin_msa_vshf_b, "V16cV16cV16cV16c", "nc")
+BUILTIN(__builtin_msa_vshf_h, "V8sV8sV8sV8s", "nc")
+BUILTIN(__builtin_msa_vshf_w, "V4iV4iV4iV4i", "nc")
+BUILTIN(__builtin_msa_vshf_d, "V2LLiV2LLiV2LLiV2LLi", "nc")
+
+BUILTIN(__builtin_msa_xor_v, "V16cV16cV16c", "nc")
+
+BUILTIN(__builtin_msa_xori_b, "V16cV16cIUi", "nc")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def
index 3c3f06c5ea3a..7e9b5eea8325 100644
--- a/include/clang/Basic/BuiltinsNVPTX.def
+++ b/include/clang/Basic/BuiltinsNVPTX.def
@@ -61,248 +61,506 @@ BUILTIN(__builtin_ptx_bar_sync, "vi", "n")
// Builtins exposed as part of NVVM
-BUILTIN(__syncthreads, "v", "n")
-BUILTIN(__nvvm_bar0, "v", "n")
-BUILTIN(__nvvm_bar0_popc, "ii", "n")
-BUILTIN(__nvvm_bar0_and, "ii", "n")
-BUILTIN(__nvvm_bar0_or, "ii", "n")
-BUILTIN(__nvvm_membar_cta, "v", "n")
-BUILTIN(__nvvm_membar_gl, "v", "n")
-BUILTIN(__nvvm_membar_sys, "v", "n")
-BUILTIN(__nvvm_popc_i, "ii", "nc")
-BUILTIN(__nvvm_popc_ll, "LiLi", "nc")
-BUILTIN(__nvvm_prmt, "UiUiUiUi", "nc")
-BUILTIN(__nvvm_min_i, "iii", "nc")
-BUILTIN(__nvvm_min_ui, "UiUiUi", "nc")
-BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "nc")
-BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "nc")
-BUILTIN(__nvvm_max_i, "iii", "nc")
-BUILTIN(__nvvm_max_ui, "UiUiUi", "nc")
-BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "nc")
-BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "nc")
-BUILTIN(__nvvm_mulhi_i, "iii", "nc")
-BUILTIN(__nvvm_mulhi_ui, "UiUiUi", "nc")
-BUILTIN(__nvvm_mulhi_ll, "LLiLLiLLi", "nc")
-BUILTIN(__nvvm_mulhi_ull, "ULLiULLiULLi", "nc")
-BUILTIN(__nvvm_mul24_i, "iii", "nc")
-BUILTIN(__nvvm_mul24_ui, "UiUiUi", "nc")
-BUILTIN(__nvvm_brev32, "UiUi", "nc")
-BUILTIN(__nvvm_brev64, "ULLiULLi", "nc")
-BUILTIN(__nvvm_sad_i, "iiii", "nc")
-BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "nc")
-BUILTIN(__nvvm_abs_i, "ii", "nc")
-BUILTIN(__nvvm_abs_ll, "LiLi", "nc")
-BUILTIN(__nvvm_floor_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_floor_f, "ff", "nc")
-BUILTIN(__nvvm_floor_d, "dd", "nc")
-BUILTIN(__nvvm_fabs_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_fabs_f, "ff", "nc")
-BUILTIN(__nvvm_fabs_d, "dd", "nc")
-BUILTIN(__nvvm_rcp_approx_ftz_d, "dd", "nc")
-BUILTIN(__nvvm_fmin_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_fmin_f, "fff", "nc")
-BUILTIN(__nvvm_fmax_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_fmax_f, "fff", "nc")
-BUILTIN(__nvvm_rsqrt_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_rsqrt_approx_f, "ff", "nc")
-BUILTIN(__nvvm_fmin_d, "ddd", "nc")
-BUILTIN(__nvvm_fmax_d, "ddd", "nc")
-BUILTIN(__nvvm_rsqrt_approx_d, "dd", "nc")
-BUILTIN(__nvvm_ceil_d, "dd", "nc")
-BUILTIN(__nvvm_trunc_d, "dd", "nc")
-BUILTIN(__nvvm_round_d, "dd", "nc")
-BUILTIN(__nvvm_ex2_approx_d, "dd", "nc")
-BUILTIN(__nvvm_lg2_approx_d, "dd", "nc")
-BUILTIN(__nvvm_round_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_round_f, "ff", "nc")
-BUILTIN(__nvvm_ex2_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_ex2_approx_f, "ff", "nc")
-BUILTIN(__nvvm_lg2_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_lg2_approx_f, "ff", "nc")
-BUILTIN(__nvvm_sin_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sin_approx_f, "ff", "nc")
-BUILTIN(__nvvm_cos_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_cos_approx_f, "ff", "nc")
-BUILTIN(__nvvm_trunc_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_trunc_f, "ff", "nc")
-BUILTIN(__nvvm_ceil_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_ceil_f, "ff", "nc")
-BUILTIN(__nvvm_saturate_d, "dd", "nc")
-BUILTIN(__nvvm_saturate_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_saturate_f, "ff", "nc")
-BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rn_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rz_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rm_ftz_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rm_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rp_ftz_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rp_f, "ffff", "nc")
-BUILTIN(__nvvm_fma_rn_d, "dddd", "nc")
-BUILTIN(__nvvm_fma_rz_d, "dddd", "nc")
-BUILTIN(__nvvm_fma_rm_d, "dddd", "nc")
-BUILTIN(__nvvm_fma_rp_d, "dddd", "nc")
-BUILTIN(__nvvm_div_approx_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_div_approx_f, "fff", "nc")
-BUILTIN(__nvvm_div_rn_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_div_rn_f, "fff", "nc")
-BUILTIN(__nvvm_div_rz_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_div_rz_f, "fff", "nc")
-BUILTIN(__nvvm_div_rm_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_div_rm_f, "fff", "nc")
-BUILTIN(__nvvm_div_rp_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_div_rp_f, "fff", "nc")
-BUILTIN(__nvvm_rcp_rn_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rn_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rz_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rz_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rm_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rm_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rp_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_rcp_rp_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rn_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rn_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rz_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rm_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rm_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rp_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_rp_f, "ff", "nc")
-BUILTIN(__nvvm_div_rn_d, "ddd", "nc")
-BUILTIN(__nvvm_div_rz_d, "ddd", "nc")
-BUILTIN(__nvvm_div_rm_d, "ddd", "nc")
-BUILTIN(__nvvm_div_rp_d, "ddd", "nc")
-BUILTIN(__nvvm_rcp_rn_d, "dd", "nc")
-BUILTIN(__nvvm_rcp_rz_d, "dd", "nc")
-BUILTIN(__nvvm_rcp_rm_d, "dd", "nc")
-BUILTIN(__nvvm_rcp_rp_d, "dd", "nc")
-BUILTIN(__nvvm_sqrt_rn_d, "dd", "nc")
-BUILTIN(__nvvm_sqrt_rz_d, "dd", "nc")
-BUILTIN(__nvvm_sqrt_rm_d, "dd", "nc")
-BUILTIN(__nvvm_sqrt_rp_d, "dd", "nc")
-BUILTIN(__nvvm_sqrt_approx_ftz_f, "ff", "nc")
-BUILTIN(__nvvm_sqrt_approx_f, "ff", "nc")
-BUILTIN(__nvvm_add_rn_d, "ddd", "nc")
-BUILTIN(__nvvm_add_rz_d, "ddd", "nc")
-BUILTIN(__nvvm_add_rm_d, "ddd", "nc")
-BUILTIN(__nvvm_add_rp_d, "ddd", "nc")
-BUILTIN(__nvvm_mul_rn_d, "ddd", "nc")
-BUILTIN(__nvvm_mul_rz_d, "ddd", "nc")
-BUILTIN(__nvvm_mul_rm_d, "ddd", "nc")
-BUILTIN(__nvvm_mul_rp_d, "ddd", "nc")
-BUILTIN(__nvvm_add_rm_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_add_rm_f, "fff", "nc")
-BUILTIN(__nvvm_add_rp_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_add_rp_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rm_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rm_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rp_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rp_f, "fff", "nc")
-BUILTIN(__nvvm_add_rn_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_add_rn_f, "fff", "nc")
-BUILTIN(__nvvm_add_rz_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_add_rz_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rn_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rn_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rz_ftz_f, "fff", "nc")
-BUILTIN(__nvvm_mul_rz_f, "fff", "nc")
-BUILTIN(__nvvm_d2f_rn_ftz, "fd", "nc")
-BUILTIN(__nvvm_d2f_rn, "fd", "nc")
-BUILTIN(__nvvm_d2f_rz_ftz, "fd", "nc")
-BUILTIN(__nvvm_d2f_rz, "fd", "nc")
-BUILTIN(__nvvm_d2f_rm_ftz, "fd", "nc")
-BUILTIN(__nvvm_d2f_rm, "fd", "nc")
-BUILTIN(__nvvm_d2f_rp_ftz, "fd", "nc")
-BUILTIN(__nvvm_d2f_rp, "fd", "nc")
-BUILTIN(__nvvm_d2i_rn, "id", "nc")
-BUILTIN(__nvvm_d2i_rz, "id", "nc")
-BUILTIN(__nvvm_d2i_rm, "id", "nc")
-BUILTIN(__nvvm_d2i_rp, "id", "nc")
-BUILTIN(__nvvm_d2ui_rn, "Uid", "nc")
-BUILTIN(__nvvm_d2ui_rz, "Uid", "nc")
-BUILTIN(__nvvm_d2ui_rm, "Uid", "nc")
-BUILTIN(__nvvm_d2ui_rp, "Uid", "nc")
-BUILTIN(__nvvm_i2d_rn, "di", "nc")
-BUILTIN(__nvvm_i2d_rz, "di", "nc")
-BUILTIN(__nvvm_i2d_rm, "di", "nc")
-BUILTIN(__nvvm_i2d_rp, "di", "nc")
-BUILTIN(__nvvm_ui2d_rn, "dUi", "nc")
-BUILTIN(__nvvm_ui2d_rz, "dUi", "nc")
-BUILTIN(__nvvm_ui2d_rm, "dUi", "nc")
-BUILTIN(__nvvm_ui2d_rp, "dUi", "nc")
-BUILTIN(__nvvm_f2i_rn_ftz, "if", "nc")
-BUILTIN(__nvvm_f2i_rn, "if", "nc")
-BUILTIN(__nvvm_f2i_rz_ftz, "if", "nc")
-BUILTIN(__nvvm_f2i_rz, "if", "nc")
-BUILTIN(__nvvm_f2i_rm_ftz, "if", "nc")
-BUILTIN(__nvvm_f2i_rm, "if", "nc")
-BUILTIN(__nvvm_f2i_rp_ftz, "if", "nc")
-BUILTIN(__nvvm_f2i_rp, "if", "nc")
-BUILTIN(__nvvm_f2ui_rn_ftz, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rn, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rz_ftz, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rz, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rm_ftz, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rm, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rp_ftz, "Uif", "nc")
-BUILTIN(__nvvm_f2ui_rp, "Uif", "nc")
-BUILTIN(__nvvm_i2f_rn, "fi", "nc")
-BUILTIN(__nvvm_i2f_rz, "fi", "nc")
-BUILTIN(__nvvm_i2f_rm, "fi", "nc")
-BUILTIN(__nvvm_i2f_rp, "fi", "nc")
-BUILTIN(__nvvm_ui2f_rn, "fUi", "nc")
-BUILTIN(__nvvm_ui2f_rz, "fUi", "nc")
-BUILTIN(__nvvm_ui2f_rm, "fUi", "nc")
-BUILTIN(__nvvm_ui2f_rp, "fUi", "nc")
-BUILTIN(__nvvm_lohi_i2d, "dii", "nc")
-BUILTIN(__nvvm_d2i_lo, "id", "nc")
-BUILTIN(__nvvm_d2i_hi, "id", "nc")
-BUILTIN(__nvvm_f2ll_rn_ftz, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rn, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rz_ftz, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rz, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rm_ftz, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rm, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rp_ftz, "LLif", "nc")
-BUILTIN(__nvvm_f2ll_rp, "LLif", "nc")
-BUILTIN(__nvvm_f2ull_rn_ftz, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rn, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rz_ftz, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rz, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rm_ftz, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rm, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rp_ftz, "ULLif", "nc")
-BUILTIN(__nvvm_f2ull_rp, "ULLif", "nc")
-BUILTIN(__nvvm_d2ll_rn, "LLid", "nc")
-BUILTIN(__nvvm_d2ll_rz, "LLid", "nc")
-BUILTIN(__nvvm_d2ll_rm, "LLid", "nc")
-BUILTIN(__nvvm_d2ll_rp, "LLid", "nc")
-BUILTIN(__nvvm_d2ull_rn, "ULLid", "nc")
-BUILTIN(__nvvm_d2ull_rz, "ULLid", "nc")
-BUILTIN(__nvvm_d2ull_rm, "ULLid", "nc")
-BUILTIN(__nvvm_d2ull_rp, "ULLid", "nc")
-BUILTIN(__nvvm_ll2f_rn, "fLLi", "nc")
-BUILTIN(__nvvm_ll2f_rz, "fLLi", "nc")
-BUILTIN(__nvvm_ll2f_rm, "fLLi", "nc")
-BUILTIN(__nvvm_ll2f_rp, "fLLi", "nc")
-BUILTIN(__nvvm_ull2f_rn, "fULLi", "nc")
-BUILTIN(__nvvm_ull2f_rz, "fULLi", "nc")
-BUILTIN(__nvvm_ull2f_rm, "fULLi", "nc")
-BUILTIN(__nvvm_ull2f_rp, "fULLi", "nc")
-BUILTIN(__nvvm_ll2d_rn, "dLLi", "nc")
-BUILTIN(__nvvm_ll2d_rz, "dLLi", "nc")
-BUILTIN(__nvvm_ll2d_rm, "dLLi", "nc")
-BUILTIN(__nvvm_ll2d_rp, "dLLi", "nc")
-BUILTIN(__nvvm_ull2d_rn, "dULLi", "nc")
-BUILTIN(__nvvm_ull2d_rz, "dULLi", "nc")
-BUILTIN(__nvvm_ull2d_rm, "dULLi", "nc")
-BUILTIN(__nvvm_ull2d_rp, "dULLi", "nc")
-BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "nc")
-BUILTIN(__nvvm_f2h_rn, "Usf", "nc")
-BUILTIN(__nvvm_h2f, "fUs", "nc")
-BUILTIN(__nvvm_bitcast_i2f, "fi", "nc")
-BUILTIN(__nvvm_bitcast_f2i, "if", "nc")
-BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "nc")
-BUILTIN(__nvvm_bitcast_d2ll, "LLid", "nc")
+// MISC
+
+BUILTIN(__nvvm_clz_i, "ii", "")
+BUILTIN(__nvvm_clz_ll, "iLLi", "")
+BUILTIN(__nvvm_popc_i, "ii", "")
+BUILTIN(__nvvm_popc_ll, "iLLi", "")
+BUILTIN(__nvvm_prmt, "UiUiUiUi", "")
+
+// Min Max
+
+BUILTIN(__nvvm_min_i, "iii", "")
+BUILTIN(__nvvm_min_ui, "UiUiUi", "")
+BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "")
+BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "")
+
+BUILTIN(__nvvm_max_i, "iii", "")
+BUILTIN(__nvvm_max_ui, "UiUiUi", "")
+BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "")
+BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "")
+
+BUILTIN(__nvvm_fmax_ftz_f, "fff", "")
+BUILTIN(__nvvm_fmax_f, "fff", "")
+BUILTIN(__nvvm_fmin_ftz_f, "fff", "")
+BUILTIN(__nvvm_fmin_f, "fff", "")
+
+BUILTIN(__nvvm_fmax_d, "ddd", "")
+BUILTIN(__nvvm_fmin_d, "ddd", "")
+
+// Multiplication
+
+BUILTIN(__nvvm_mulhi_i, "iii", "")
+BUILTIN(__nvvm_mulhi_ui, "UiUiUi", "")
+BUILTIN(__nvvm_mulhi_ll, "LLiLLiLLi", "")
+BUILTIN(__nvvm_mulhi_ull, "ULLiULLiULLi", "")
+
+BUILTIN(__nvvm_mul_rn_ftz_f, "fff", "")
+BUILTIN(__nvvm_mul_rn_f, "fff", "")
+BUILTIN(__nvvm_mul_rz_ftz_f, "fff", "")
+BUILTIN(__nvvm_mul_rz_f, "fff", "")
+BUILTIN(__nvvm_mul_rm_ftz_f, "fff", "")
+BUILTIN(__nvvm_mul_rm_f, "fff", "")
+BUILTIN(__nvvm_mul_rp_ftz_f, "fff", "")
+BUILTIN(__nvvm_mul_rp_f, "fff", "")
+
+BUILTIN(__nvvm_mul_rn_d, "ddd", "")
+BUILTIN(__nvvm_mul_rz_d, "ddd", "")
+BUILTIN(__nvvm_mul_rm_d, "ddd", "")
+BUILTIN(__nvvm_mul_rp_d, "ddd", "")
+
+BUILTIN(__nvvm_mul24_i, "iii", "")
+BUILTIN(__nvvm_mul24_ui, "UiUiUi", "")
+
+// Div
+
+BUILTIN(__nvvm_div_approx_ftz_f, "fff", "")
+BUILTIN(__nvvm_div_approx_f, "fff", "")
+
+BUILTIN(__nvvm_div_rn_ftz_f, "fff", "")
+BUILTIN(__nvvm_div_rn_f, "fff", "")
+BUILTIN(__nvvm_div_rz_ftz_f, "fff", "")
+BUILTIN(__nvvm_div_rz_f, "fff", "")
+BUILTIN(__nvvm_div_rm_ftz_f, "fff", "")
+BUILTIN(__nvvm_div_rm_f, "fff", "")
+BUILTIN(__nvvm_div_rp_ftz_f, "fff", "")
+BUILTIN(__nvvm_div_rp_f, "fff", "")
+
+BUILTIN(__nvvm_div_rn_d, "ddd", "")
+BUILTIN(__nvvm_div_rz_d, "ddd", "")
+BUILTIN(__nvvm_div_rm_d, "ddd", "")
+BUILTIN(__nvvm_div_rp_d, "ddd", "")
+
+// Brev
+
+BUILTIN(__nvvm_brev32, "UiUi", "")
+BUILTIN(__nvvm_brev64, "ULLiULLi", "")
+
+// Sad
+
+BUILTIN(__nvvm_sad_i, "iii", "")
+BUILTIN(__nvvm_sad_ui, "UiUiUi", "")
+
+// Floor, Ceil
+
+BUILTIN(__nvvm_floor_ftz_f, "ff", "")
+BUILTIN(__nvvm_floor_f, "ff", "")
+BUILTIN(__nvvm_floor_d, "dd", "")
+
+BUILTIN(__nvvm_ceil_ftz_f, "ff", "")
+BUILTIN(__nvvm_ceil_f, "ff", "")
+BUILTIN(__nvvm_ceil_d, "dd", "")
+
+// Abs
+
+BUILTIN(__nvvm_abs_i, "ii", "")
+BUILTIN(__nvvm_abs_ll, "LLiLLi", "")
+
+BUILTIN(__nvvm_fabs_ftz_f, "ff", "")
+BUILTIN(__nvvm_fabs_f, "ff", "")
+BUILTIN(__nvvm_fabs_d, "dd", "")
+
+// Round
+
+BUILTIN(__nvvm_round_ftz_f, "ff", "")
+BUILTIN(__nvvm_round_f, "ff", "")
+BUILTIN(__nvvm_round_d, "dd", "")
+
+// Trunc
+
+BUILTIN(__nvvm_trunc_ftz_f, "ff", "")
+BUILTIN(__nvvm_trunc_f, "ff", "")
+BUILTIN(__nvvm_trunc_d, "dd", "")
+
+// Saturate
+
+BUILTIN(__nvvm_saturate_ftz_f, "ff", "")
+BUILTIN(__nvvm_saturate_f, "ff", "")
+BUILTIN(__nvvm_saturate_d, "dd", "")
+
+// Exp2, Log2
+
+BUILTIN(__nvvm_ex2_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_ex2_approx_f, "ff", "")
+BUILTIN(__nvvm_ex2_approx_d, "dd", "")
+
+BUILTIN(__nvvm_lg2_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_lg2_approx_f, "ff", "")
+BUILTIN(__nvvm_lg2_approx_d, "dd", "")
+
+// Sin, Cos
+
+BUILTIN(__nvvm_sin_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_sin_approx_f, "ff", "")
+
+BUILTIN(__nvvm_cos_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_cos_approx_f, "ff", "")
+
+// Fma
+
+BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "")
+BUILTIN(__nvvm_fma_rn_f, "ffff", "")
+BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "")
+BUILTIN(__nvvm_fma_rz_f, "ffff", "")
+BUILTIN(__nvvm_fma_rm_ftz_f, "ffff", "")
+BUILTIN(__nvvm_fma_rm_f, "ffff", "")
+BUILTIN(__nvvm_fma_rp_ftz_f, "ffff", "")
+BUILTIN(__nvvm_fma_rp_f, "ffff", "")
+BUILTIN(__nvvm_fma_rn_d, "dddd", "")
+BUILTIN(__nvvm_fma_rz_d, "dddd", "")
+BUILTIN(__nvvm_fma_rm_d, "dddd", "")
+BUILTIN(__nvvm_fma_rp_d, "dddd", "")
+
+// Rcp
+
+BUILTIN(__nvvm_rcp_rn_ftz_f, "ff", "")
+BUILTIN(__nvvm_rcp_rn_f, "ff", "")
+BUILTIN(__nvvm_rcp_rz_ftz_f, "ff", "")
+BUILTIN(__nvvm_rcp_rz_f, "ff", "")
+BUILTIN(__nvvm_rcp_rm_ftz_f, "ff", "")
+BUILTIN(__nvvm_rcp_rm_f, "ff", "")
+BUILTIN(__nvvm_rcp_rp_ftz_f, "ff", "")
+BUILTIN(__nvvm_rcp_rp_f, "ff", "")
+
+BUILTIN(__nvvm_rcp_rn_d, "dd", "")
+BUILTIN(__nvvm_rcp_rz_d, "dd", "")
+BUILTIN(__nvvm_rcp_rm_d, "dd", "")
+BUILTIN(__nvvm_rcp_rp_d, "dd", "")
+BUILTIN(__nvvm_rcp_approx_ftz_d, "dd", "")
+
+// Sqrt
+
+BUILTIN(__nvvm_sqrt_rn_ftz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rn_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rz_ftz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rm_ftz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rm_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rp_ftz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_rp_f, "ff", "")
+BUILTIN(__nvvm_sqrt_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_sqrt_approx_f, "ff", "")
+
+BUILTIN(__nvvm_sqrt_rn_d, "dd", "")
+BUILTIN(__nvvm_sqrt_rz_d, "dd", "")
+BUILTIN(__nvvm_sqrt_rm_d, "dd", "")
+BUILTIN(__nvvm_sqrt_rp_d, "dd", "")
+
+// Rsqrt
+
+BUILTIN(__nvvm_rsqrt_approx_ftz_f, "ff", "")
+BUILTIN(__nvvm_rsqrt_approx_f, "ff", "")
+BUILTIN(__nvvm_rsqrt_approx_d, "dd", "")
+
+// Add
+
+BUILTIN(__nvvm_add_rn_ftz_f, "ff", "")
+BUILTIN(__nvvm_add_rn_f, "ff", "")
+BUILTIN(__nvvm_add_rz_ftz_f, "ff", "")
+BUILTIN(__nvvm_add_rz_f, "ff", "")
+BUILTIN(__nvvm_add_rm_ftz_f, "ff", "")
+BUILTIN(__nvvm_add_rm_f, "ff", "")
+BUILTIN(__nvvm_add_rp_ftz_f, "ff", "")
+BUILTIN(__nvvm_add_rp_f, "ff", "")
+
+BUILTIN(__nvvm_add_rn_d, "dd", "")
+BUILTIN(__nvvm_add_rz_d, "dd", "")
+BUILTIN(__nvvm_add_rm_d, "dd", "")
+BUILTIN(__nvvm_add_rp_d, "dd", "")
+
+// Convert
+
+BUILTIN(__nvvm_d2f_rn_ftz, "fd", "")
+BUILTIN(__nvvm_d2f_rn, "fd", "")
+BUILTIN(__nvvm_d2f_rz_ftz, "fd", "")
+BUILTIN(__nvvm_d2f_rz, "fd", "")
+BUILTIN(__nvvm_d2f_rm_ftz, "fd", "")
+BUILTIN(__nvvm_d2f_rm, "fd", "")
+BUILTIN(__nvvm_d2f_rp_ftz, "fd", "")
+BUILTIN(__nvvm_d2f_rp, "fd", "")
+
+BUILTIN(__nvvm_d2i_rn, "id", "")
+BUILTIN(__nvvm_d2i_rz, "id", "")
+BUILTIN(__nvvm_d2i_rm, "id", "")
+BUILTIN(__nvvm_d2i_rp, "id", "")
+
+BUILTIN(__nvvm_d2ui_rn, "Uid", "")
+BUILTIN(__nvvm_d2ui_rz, "Uid", "")
+BUILTIN(__nvvm_d2ui_rm, "Uid", "")
+BUILTIN(__nvvm_d2ui_rp, "Uid", "")
+
+BUILTIN(__nvvm_i2d_rn, "di", "")
+BUILTIN(__nvvm_i2d_rz, "di", "")
+BUILTIN(__nvvm_i2d_rm, "di", "")
+BUILTIN(__nvvm_i2d_rp, "di", "")
+
+BUILTIN(__nvvm_ui2d_rn, "dUi", "")
+BUILTIN(__nvvm_ui2d_rz, "dUi", "")
+BUILTIN(__nvvm_ui2d_rm, "dUi", "")
+BUILTIN(__nvvm_ui2d_rp, "dUi", "")
+
+BUILTIN(__nvvm_f2i_rn_ftz, "if", "")
+BUILTIN(__nvvm_f2i_rn, "if", "")
+BUILTIN(__nvvm_f2i_rz_ftz, "if", "")
+BUILTIN(__nvvm_f2i_rz, "if", "")
+BUILTIN(__nvvm_f2i_rm_ftz, "if", "")
+BUILTIN(__nvvm_f2i_rm, "if", "")
+BUILTIN(__nvvm_f2i_rp_ftz, "if", "")
+BUILTIN(__nvvm_f2i_rp, "if", "")
+
+BUILTIN(__nvvm_f2ui_rn_ftz, "Uif", "")
+BUILTIN(__nvvm_f2ui_rn, "Uif", "")
+BUILTIN(__nvvm_f2ui_rz_ftz, "Uif", "")
+BUILTIN(__nvvm_f2ui_rz, "Uif", "")
+BUILTIN(__nvvm_f2ui_rm_ftz, "Uif", "")
+BUILTIN(__nvvm_f2ui_rm, "Uif", "")
+BUILTIN(__nvvm_f2ui_rp_ftz, "Uif", "")
+BUILTIN(__nvvm_f2ui_rp, "Uif", "")
+
+BUILTIN(__nvvm_i2f_rn, "fi", "")
+BUILTIN(__nvvm_i2f_rz, "fi", "")
+BUILTIN(__nvvm_i2f_rm, "fi", "")
+BUILTIN(__nvvm_i2f_rp, "fi", "")
+
+BUILTIN(__nvvm_ui2f_rn, "fUi", "")
+BUILTIN(__nvvm_ui2f_rz, "fUi", "")
+BUILTIN(__nvvm_ui2f_rm, "fUi", "")
+BUILTIN(__nvvm_ui2f_rp, "fUi", "")
+
+BUILTIN(__nvvm_lohi_i2d, "dii", "")
+
+BUILTIN(__nvvm_d2i_lo, "id", "")
+BUILTIN(__nvvm_d2i_hi, "id", "")
+
+BUILTIN(__nvvm_f2ll_rn_ftz, "LLif", "")
+BUILTIN(__nvvm_f2ll_rn, "LLif", "")
+BUILTIN(__nvvm_f2ll_rz_ftz, "LLif", "")
+BUILTIN(__nvvm_f2ll_rz, "LLif", "")
+BUILTIN(__nvvm_f2ll_rm_ftz, "LLif", "")
+BUILTIN(__nvvm_f2ll_rm, "LLif", "")
+BUILTIN(__nvvm_f2ll_rp_ftz, "LLif", "")
+BUILTIN(__nvvm_f2ll_rp, "LLif", "")
+
+BUILTIN(__nvvm_f2ull_rn_ftz, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rn, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rz_ftz, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rz, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rm_ftz, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rm, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rp_ftz, "ULLif", "")
+BUILTIN(__nvvm_f2ull_rp, "ULLif", "")
+
+BUILTIN(__nvvm_d2ll_rn, "LLid", "")
+BUILTIN(__nvvm_d2ll_rz, "LLid", "")
+BUILTIN(__nvvm_d2ll_rm, "LLid", "")
+BUILTIN(__nvvm_d2ll_rp, "LLid", "")
+
+BUILTIN(__nvvm_d2ull_rn, "ULLid", "")
+BUILTIN(__nvvm_d2ull_rz, "ULLid", "")
+BUILTIN(__nvvm_d2ull_rm, "ULLid", "")
+BUILTIN(__nvvm_d2ull_rp, "ULLid", "")
+
+BUILTIN(__nvvm_ll2f_rn, "fLLi", "")
+BUILTIN(__nvvm_ll2f_rz, "fLLi", "")
+BUILTIN(__nvvm_ll2f_rm, "fLLi", "")
+BUILTIN(__nvvm_ll2f_rp, "fLLi", "")
+
+BUILTIN(__nvvm_ull2f_rn, "fULLi", "")
+BUILTIN(__nvvm_ull2f_rz, "fULLi", "")
+BUILTIN(__nvvm_ull2f_rm, "fULLi", "")
+BUILTIN(__nvvm_ull2f_rp, "fULLi", "")
+
+BUILTIN(__nvvm_ll2d_rn, "dLLi", "")
+BUILTIN(__nvvm_ll2d_rz, "dLLi", "")
+BUILTIN(__nvvm_ll2d_rm, "dLLi", "")
+BUILTIN(__nvvm_ll2d_rp, "dLLi", "")
+
+BUILTIN(__nvvm_ull2d_rn, "dULLi", "")
+BUILTIN(__nvvm_ull2d_rz, "dULLi", "")
+BUILTIN(__nvvm_ull2d_rm, "dULLi", "")
+BUILTIN(__nvvm_ull2d_rp, "dULLi", "")
+
+BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "")
+BUILTIN(__nvvm_f2h_rn, "Usf", "")
+
+BUILTIN(__nvvm_h2f, "fUs", "")
+
+// Bitcast
+
+BUILTIN(__nvvm_bitcast_f2i, "if", "")
+BUILTIN(__nvvm_bitcast_i2f, "fi", "")
+
+BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "")
+BUILTIN(__nvvm_bitcast_d2ll, "LLid", "")
+
+// Sync
+
+BUILTIN(__syncthreads, "v", "")
+BUILTIN(__nvvm_bar0, "v", "")
+BUILTIN(__nvvm_bar0_popc, "ii", "")
+BUILTIN(__nvvm_bar0_and, "ii", "")
+BUILTIN(__nvvm_bar0_or, "ii", "")
+
+// Membar
+
+BUILTIN(__nvvm_membar_cta, "v", "")
+BUILTIN(__nvvm_membar_gl, "v", "")
+BUILTIN(__nvvm_membar_sys, "v", "")
+
+// Memcpy, Memset
+
+BUILTIN(__nvvm_memcpy, "vUc*Uc*zi","")
+BUILTIN(__nvvm_memset, "vUc*Uczi","")
+
+// Image
+
+BUILTIN(__builtin_ptx_read_image2Dfi_, "V4fiiii", "")
+BUILTIN(__builtin_ptx_read_image2Dff_, "V4fiiff", "")
+BUILTIN(__builtin_ptx_read_image2Dii_, "V4iiiii", "")
+BUILTIN(__builtin_ptx_read_image2Dif_, "V4iiiff", "")
+
+BUILTIN(__builtin_ptx_read_image3Dfi_, "V4fiiiiii", "")
+BUILTIN(__builtin_ptx_read_image3Dff_, "V4fiiffff", "")
+BUILTIN(__builtin_ptx_read_image3Dii_, "V4iiiiiii", "")
+BUILTIN(__builtin_ptx_read_image3Dif_, "V4iiiffff", "")
+
+BUILTIN(__builtin_ptx_write_image2Df_, "viiiffff", "")
+BUILTIN(__builtin_ptx_write_image2Di_, "viiiiiii", "")
+BUILTIN(__builtin_ptx_write_image2Dui_, "viiiUiUiUiUi", "")
+BUILTIN(__builtin_ptx_get_image_depthi_, "ii", "")
+BUILTIN(__builtin_ptx_get_image_heighti_, "ii", "")
+BUILTIN(__builtin_ptx_get_image_widthi_, "ii", "")
+BUILTIN(__builtin_ptx_get_image_channel_data_typei_, "ii", "")
+BUILTIN(__builtin_ptx_get_image_channel_orderi_, "ii", "")
+
+// Atomic
+//
+// We need the atom intrinsics because
+// - they are used in converging analysis
+// - they are used in address space analysis and optimization
+// So it does not hurt to expose them as builtins.
+//
+BUILTIN(__nvvm_atom_add_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_add_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_add_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_add_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_add_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_add_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_add_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_add_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_add_gen_ll, "LLiLLiD*LLi", "n")
+BUILTIN(__nvvm_atom_add_g_f, "ffD*1f", "n")
+BUILTIN(__nvvm_atom_add_s_f, "ffD*3f", "n")
+BUILTIN(__nvvm_atom_add_gen_f, "ffD*f", "n")
+
+BUILTIN(__nvvm_atom_sub_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_sub_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_sub_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_sub_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_sub_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_sub_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_sub_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_sub_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_sub_gen_ll, "LLiLLiD*LLi", "n")
+
+BUILTIN(__nvvm_atom_xchg_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_xchg_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_xchg_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_xchg_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_xchg_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_xchg_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_xchg_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_xchg_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_xchg_gen_ll, "LLiLLiD*LLi", "n")
+
+BUILTIN(__nvvm_atom_max_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_max_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_max_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_max_g_ui, "UiUiD*1Ui", "n")
+BUILTIN(__nvvm_atom_max_s_ui, "UiUiD*3Ui", "n")
+BUILTIN(__nvvm_atom_max_gen_ui, "UiUiD*Ui", "n")
+BUILTIN(__nvvm_atom_max_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_max_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_max_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_max_g_ul, "ULiULiD*1ULi", "n")
+BUILTIN(__nvvm_atom_max_s_ul, "ULiULiD*3ULi", "n")
+BUILTIN(__nvvm_atom_max_gen_ul, "ULiULiD*ULi", "n")
+BUILTIN(__nvvm_atom_max_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_max_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_max_gen_ll, "LLiLLiD*LLi", "n")
+BUILTIN(__nvvm_atom_max_g_ull, "ULLiULLiD*1ULLi", "n")
+BUILTIN(__nvvm_atom_max_s_ull, "ULLiULLiD*3ULLi", "n")
+BUILTIN(__nvvm_atom_max_gen_ull, "ULLiULLiD*ULLi", "n")
+
+BUILTIN(__nvvm_atom_min_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_min_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_min_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_min_g_ui, "UiUiD*1Ui", "n")
+BUILTIN(__nvvm_atom_min_s_ui, "UiUiD*3Ui", "n")
+BUILTIN(__nvvm_atom_min_gen_ui, "UiUiD*Ui", "n")
+BUILTIN(__nvvm_atom_min_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_min_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_min_gen_l, "LiLi10D*Li", "n")
+BUILTIN(__nvvm_atom_min_g_ul, "ULiULiD*1ULi", "n")
+BUILTIN(__nvvm_atom_min_s_ul, "ULiULiD*3ULi", "n")
+BUILTIN(__nvvm_atom_min_gen_ul, "ULiULiD*ULi", "n")
+BUILTIN(__nvvm_atom_min_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_min_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_min_gen_ll, "LLiLLiD*LLi", "n")
+BUILTIN(__nvvm_atom_min_g_ull, "ULLiULLiD*1ULLi", "n")
+BUILTIN(__nvvm_atom_min_s_ull, "ULLiULLiD*3ULLi", "n")
+BUILTIN(__nvvm_atom_min_gen_ull, "ULLiULLiD*ULLi", "n")
+
+BUILTIN(__nvvm_atom_inc_g_ui, "UiUiD*1Ui", "n")
+BUILTIN(__nvvm_atom_inc_s_ui, "UiUiD*3Ui", "n")
+BUILTIN(__nvvm_atom_inc_gen_ui, "UiUiD*Ui", "n")
+BUILTIN(__nvvm_atom_dec_g_ui, "UiUiD*1Ui", "n")
+BUILTIN(__nvvm_atom_dec_s_ui, "UiUiD*3Ui", "n")
+BUILTIN(__nvvm_atom_dec_gen_ui, "UiUiD*Ui", "n")
+
+BUILTIN(__nvvm_atom_and_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_and_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_and_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_and_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_and_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_and_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_and_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_and_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_and_gen_ll, "LLiLLiD*LLi", "n")
+
+BUILTIN(__nvvm_atom_or_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_or_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_or_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_or_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_or_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_or_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_or_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_or_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_or_gen_ll, "LLiLLiD*LLi", "n")
+
+BUILTIN(__nvvm_atom_xor_g_i, "iiD*1i", "n")
+BUILTIN(__nvvm_atom_xor_s_i, "iiD*3i", "n")
+BUILTIN(__nvvm_atom_xor_gen_i, "iiD*i", "n")
+BUILTIN(__nvvm_atom_xor_g_l, "LiLiD*1Li", "n")
+BUILTIN(__nvvm_atom_xor_s_l, "LiLiD*3Li", "n")
+BUILTIN(__nvvm_atom_xor_gen_l, "LiLiD*Li", "n")
+BUILTIN(__nvvm_atom_xor_g_ll, "LLiLLiD*1LLi", "n")
+BUILTIN(__nvvm_atom_xor_s_ll, "LLiLLiD*3LLi", "n")
+BUILTIN(__nvvm_atom_xor_gen_ll, "LLiLLiD*LLi", "n")
+
+BUILTIN(__nvvm_atom_cas_g_i, "iiD*1ii", "n")
+BUILTIN(__nvvm_atom_cas_s_i, "iiD*3ii", "n")
+BUILTIN(__nvvm_atom_cas_gen_i, "iiD*ii", "n")
+BUILTIN(__nvvm_atom_cas_g_l, "LiLiD*1LiLi", "n")
+BUILTIN(__nvvm_atom_cas_s_l, "LiLiD*3LiLi", "n")
+BUILTIN(__nvvm_atom_cas_gen_l, "LiLiD*LiLi", "n")
+BUILTIN(__nvvm_atom_cas_g_ll, "LLiLLiD*1LLiLLi", "n")
+BUILTIN(__nvvm_atom_cas_s_ll, "LLiLLiD*3LLiLLi", "n")
+BUILTIN(__nvvm_atom_cas_gen_ll, "LLiLLiD*LLiLLi", "n")
+
+// Compiler Error Warn
+BUILTIN(__nvvm_compiler_error, "vcC*4", "n")
+BUILTIN(__nvvm_compiler_warn, "vcC*4", "n")
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index d536821d55d9..51397fa45df6 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -258,6 +258,7 @@ BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
BUILTIN(__builtin_ia32_movmskpd, "iV2d", "")
BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "")
BUILTIN(__builtin_ia32_movnti, "vi*i", "")
+BUILTIN(__builtin_ia32_movnti64, "vLLi*LLi", "")
BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "")
BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "")
BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "")
@@ -559,7 +560,7 @@ BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLi*", "")
BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "")
BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "")
BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "")
-BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLiC*", "")
+BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLi", "")
BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIi", "")
BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIi", "")
BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "")
@@ -641,6 +642,19 @@ BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "")
BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "")
BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "")
+// TBM
+BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "")
+BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "")
+
+// SHA
+BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "")
+BUILTIN(__builtin_ia32_sha1nexte, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_sha1msg1, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_sha1msg2, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_sha256rnds2, "V4iV4iV4iV4i", "")
+BUILTIN(__builtin_ia32_sha256msg1, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_sha256msg2, "V4iV4iV4i", "")
+
// FMA4
BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "")
BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "")
diff --git a/include/clang/Basic/BuiltinsXCore.def b/include/clang/Basic/BuiltinsXCore.def
new file mode 100644
index 000000000000..672d20578a63
--- /dev/null
+++ b/include/clang/Basic/BuiltinsXCore.def
@@ -0,0 +1,22 @@
+//===--- BuiltinsXCore.def - XCore 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 XCore-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.
+
+BUILTIN(__builtin_bitrev, "UiUi", "nc")
+BUILTIN(__builtin_getid, "Si", "nc")
+BUILTIN(__builtin_getps, "UiUi", "n")
+BUILTIN(__builtin_setps, "vUiUi", "n")
+
+#undef BUILTIN
diff --git a/include/clang/Basic/CapturedStmt.h b/include/clang/Basic/CapturedStmt.h
index 484bbb1feeef..c4a289b696dd 100644
--- a/include/clang/Basic/CapturedStmt.h
+++ b/include/clang/Basic/CapturedStmt.h
@@ -15,7 +15,8 @@ namespace clang {
/// \brief The different kinds of captured statement.
enum CapturedRegionKind {
- CR_Default
+ CR_Default,
+ CR_OpenMP
};
} // end namespace clang
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index ad2afa7a57cd..18bca5741962 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -44,6 +44,9 @@ def Named : Decl<1>;
def CXXDestructor : DDecl<CXXMethod>;
def CXXConversion : DDecl<CXXMethod>;
def Var : DDecl<Declarator>;
+ def VarTemplateSpecialization : DDecl<Var>;
+ def VarTemplatePartialSpecialization
+ : DDecl<VarTemplateSpecialization>;
def ImplicitParam : DDecl<Var>;
def ParmVar : DDecl<Var>;
def NonTypeTemplateParm : DDecl<Declarator>;
@@ -51,6 +54,7 @@ def Named : Decl<1>;
def RedeclarableTemplate : DDecl<Template, 1>;
def FunctionTemplate : DDecl<RedeclarableTemplate>;
def ClassTemplate : DDecl<RedeclarableTemplate>;
+ def VarTemplate : DDecl<RedeclarableTemplate>;
def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
def TemplateTemplateParm : DDecl<Template>;
def Using : DDecl<Named>;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3e125944a361..c057bdf63436 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -21,7 +21,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/type_traits.h"
#include <list>
#include <vector>
@@ -490,7 +489,14 @@ public:
FatalErrorOccurred = true;
LastDiagLevel = DiagnosticIDs::Ignored;
}
-
+
+ /// \brief Determine whether the previous diagnostic was ignored. This can
+ /// be used by clients that want to determine whether notes attached to a
+ /// diagnostic will be suppressed.
+ bool isLastDiagnosticIgnored() const {
+ return LastDiagLevel == DiagnosticIDs::Ignored;
+ }
+
/// \brief Controls whether otherwise-unmapped extension diagnostics are
/// mapped onto ignore/warning/error.
///
@@ -983,6 +989,10 @@ public:
bool hasMaxRanges() const {
return NumRanges == DiagnosticsEngine::MaxRanges;
}
+
+ bool hasMaxFixItHints() const {
+ return NumFixits == DiagnosticsEngine::MaxFixItHints;
+ }
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
@@ -1212,7 +1222,7 @@ public:
~StoredDiagnostic();
/// \brief Evaluates true when this object stores a diagnostic.
- operator bool() const { return Message.size() > 0; }
+ LLVM_EXPLICIT operator bool() const { return Message.size() > 0; }
unsigned getID() const { return ID; }
DiagnosticsEngine::Level getLevel() const { return Level; }
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index 6dfecdcb7972..2616548bc009 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -26,6 +26,13 @@ def CLASS_WARNING : DiagClass;
def CLASS_EXTENSION : DiagClass;
def CLASS_ERROR : DiagClass;
+// Responses to a diagnostic in a SFINAE context.
+class SFINAEResponse;
+def SFINAE_SubstitutionFailure : SFINAEResponse;
+def SFINAE_Suppress : SFINAEResponse;
+def SFINAE_Report : SFINAEResponse;
+def SFINAE_AccessControl : SFINAEResponse;
+
// Diagnostic Categories. These can be applied to groups or individual
// diagnostics to specify a category.
class DiagCategory<string Name> {
@@ -52,19 +59,30 @@ include "DiagnosticGroups.td"
// All diagnostics emitted by the compiler are an indirect subclass of this.
class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
/// Component is specified by the file with a big let directive.
- string Component = ?;
- string Text = text;
- DiagClass Class = DC;
- bit SFINAE = 1;
- bit AccessControl = 0;
- bit WarningNoWerror = 0;
- bit WarningShowInSystemHeader = 0;
- DiagMapping DefaultMapping = defaultmapping;
- DiagGroup Group;
- string CategoryName = "";
+ string Component = ?;
+ string Text = text;
+ DiagClass Class = DC;
+ SFINAEResponse SFINAE = SFINAE_Suppress;
+ bit AccessControl = 0;
+ bit WarningNoWerror = 0;
+ bit WarningShowInSystemHeader = 0;
+ DiagMapping DefaultMapping = defaultmapping;
+ DiagGroup Group;
+ string CategoryName = "";
+}
+
+class SFINAEFailure {
+ SFINAEResponse SFINAE = SFINAE_SubstitutionFailure;
+}
+class NoSFINAE {
+ SFINAEResponse SFINAE = SFINAE_Report;
+}
+class AccessControl {
+ SFINAEResponse SFINAE = SFINAE_AccessControl;
}
-class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
+// FIXME: ExtWarn and Extension should also be SFINAEFailure by default.
+class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>, SFINAEFailure;
class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
@@ -82,9 +100,6 @@ class DefaultWarnShowInSystemHeader {
bit WarningShowInSystemHeader = 1;
}
-class NoSFINAE { bit SFINAE = 0; }
-class AccessControl { bit AccessControl = 1; }
-
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"
include "DiagnosticAnalysisKinds.td"
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index c69f85f18d3d..113e56490520 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -38,12 +38,16 @@ def note_constexpr_nonliteral : Note<
def note_constexpr_non_global : Note<
"%select{pointer|reference}0 to %select{|subobject of }1"
"%select{temporary|%3}2 is not a constant expression">;
+def note_constexpr_uninitialized : Note<
+ "%select{|sub}0object of type %1 is not initialized">;
def note_constexpr_array_index : Note<"cannot refer to element %0 of "
"%select{array of %2 elements|non-array object}1 in a constant expression">;
def note_constexpr_float_arithmetic : Note<
"floating point arithmetic produces %select{an infinity|a NaN}0">;
def note_constexpr_pointer_subtraction_not_same_array : Note<
"subtracted pointers are not elements of the same array">;
+def note_constexpr_pointer_subtraction_zero_size : Note<
+ "subtraction of pointers to type %0 of zero size">;
def note_constexpr_pointer_comparison_base_classes : Note<
"comparison of addresses of subobjects of different base classes "
"has unspecified value">;
@@ -83,12 +87,17 @@ def note_constexpr_depth_limit_exceeded : Note<
"constexpr evaluation exceeded maximum depth of %0 calls">;
def note_constexpr_call_limit_exceeded : Note<
"constexpr evaluation hit maximum call limit">;
+def note_constexpr_step_limit_exceeded : Note<
+ "constexpr evaluation hit maximum step limit; possible infinite loop?">;
def note_constexpr_lifetime_ended : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"%select{temporary|variable}1 whose lifetime has ended">;
def note_constexpr_access_uninit : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"object outside its lifetime is not allowed in a constant expression">;
+def note_constexpr_use_uninit_reference : Note<
+ "use of reference outside its lifetime "
+ "is not allowed in a constant expression">;
def note_constexpr_modify_const_type : Note<
"modification of object of const-qualified type %0 is not allowed "
"in a constant expression">;
@@ -115,9 +124,16 @@ 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 "
"is not allowed in a constant expression">;
+def note_constexpr_access_static_temporary : Note<
+ "%select{read of|assignment to|increment of|decrement of}0 temporary "
+ "is not allowed in a constant expression outside the expression that "
+ "created the temporary">;
def note_constexpr_modify_global : Note<
"a constant expression cannot modify an object that is visible outside "
"that expression">;
+def note_constexpr_stmt_expr_unsupported : Note<
+ "this use of statement expressions is not supported in a "
+ "constant expression">;
def note_constexpr_calls_suppressed : Note<
"(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
"see all)">;
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index c913e31ebad1..49781fec9a9c 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -160,5 +160,9 @@ def warn_unknown_comment_command_name : Warning<
"unknown command tag name">,
InGroup<DocumentationUnknownCommand>, DefaultIgnore;
+def warn_correct_comment_command_name : Warning<
+ "unknown command tag name '%0'; did you mean '%1'?">,
+ InGroup<Documentation>, DefaultIgnore;
+
} // end of documentation issue category
} // end of AST component
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 7ff6ae13b4ef..c54bafc07fe8 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -37,6 +37,9 @@ def note_possibility : Note<"one possibility">;
def note_also_found : Note<"also found">;
// Parse && Lex
+
+let CategoryName = "Lexical or Preprocessor Issue" in {
+
def err_expected_colon : Error<"expected ':'">;
def err_expected_colon_after_setter_name : Error<
"method name referenced in property setter attribute "
@@ -51,7 +54,12 @@ def err_invalid_character_udl : Error<
def err_invalid_numeric_udl : Error<
"numeric literal with user-defined suffix cannot be used here">;
+}
+
// Parse && Sema
+
+let CategoryName = "Parse Issue" in {
+
def err_param_redefinition : Error<"redefinition of parameter %0">;
def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
@@ -79,6 +87,8 @@ def err_attribute_not_type_attr : Error<
"%0 attribute cannot be applied to types">;
def err_enum_template : Error<"enumeration cannot be a template">;
+}
+
// Sema && Lex
def ext_c99_longlong : Extension<
"'long long' is an extension when C99 mode is not enabled">,
@@ -89,10 +99,10 @@ def ext_cxx11_longlong : Extension<
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
-def warn_integer_too_large : Warning<
- "integer constant is too large for its type">;
+def err_integer_too_large : Error<
+ "integer constant is larger than the largest unsigned integer type">;
def warn_integer_too_large_for_signed : Warning<
- "integer constant is so large that it is unsigned">;
+ "integer constant is larger than the largest signed integer type">;
// Sema && AST
def note_invalid_subexpr_in_const_expr : Note<
@@ -105,7 +115,9 @@ def err_target_unknown_triple : Error<
def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
def err_target_unknown_cxxabi : Error<"unknown C++ ABI '%0'">;
-def err_target_invalid_feature : Error<"invalid target feature '%0'">;
+def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">;
+def err_target_unsupported_fpmath : Error<
+ "the '%0' unit is not supported with this instruction set">;
// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index db457b15369d..b48980778c46 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -26,8 +26,6 @@ def err_drv_unsupported_rtlib_for_platform : Error<
"unsupported runtime library '%0' for platform '%1'">;
def err_drv_invalid_stdlib_name : Error<
"invalid library name in argument '%0'">;
-def err_drv_invalid_opt_with_multiple_archs : Error<
- "option '%0' cannot be used with multiple -arch options">;
def err_drv_invalid_output_with_multiple_archs : Error<
"cannot use '%0' output with multiple -arch options">;
def err_drv_no_input_files : Error<"no input files">;
@@ -35,8 +33,10 @@ def err_drv_use_of_Z_option : Error<
"unsupported use of internal gcc -Z option '%0'">;
def err_drv_output_argument_with_multiple_files : Error<
"cannot specify -o when generating multiple output files">;
-def err_no_external_windows_assembler : Error<
- "there is no external assembler we can use on windows">;
+def err_drv_out_file_argument_with_multiple_sources : Error<
+ "cannot specify '%0%1' when compiling multiple source files">;
+def err_no_external_assembler : Error<
+ "there is no external assembler that can be used on this platform">;
def err_drv_unable_to_remove_file : Error<
"unable to remove file: %0">;
def err_drv_command_failure : Error<
@@ -77,8 +77,8 @@ def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
"invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
-def err_drv_invalid_feature : Error<
- "invalid feature '%0' for CPU '%1'">;
+def err_drv_malformed_sanitizer_blacklist : Error<
+ "malformed sanitizer blacklist: '%0'">;
def err_drv_I_dash_not_supported : Error<
"'%0' not supported, please use -iquote instead">;
@@ -107,7 +107,14 @@ def err_drv_mg_requires_m_or_mm : Error<
"option '-MG' requires '-M' or '-MM'">;
def err_drv_unknown_objc_runtime : Error<
"unknown or ill-formed Objective-C runtime '%0'">;
+def err_drv_emit_llvm_link : Error<
+ "-emit-llvm cannot be used when linking">;
+def err_drv_unknown_toolchain : Error<
+ "cannot recognize the type of the toolchain">;
+def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
+def warn_drv_optimization_value : Warning<"optimization level '%0' is unsupported; using '%1%2' instead">,
+ InGroup<InvalidCommandLineArgument>;
def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for C++ and Objective-C++ only">;
def warn_drv_input_file_unused : Warning<
@@ -135,6 +142,9 @@ def warn_drv_assuming_mfloat_abi_is : Warning<
"unknown platform, assuming -mfloat-abi=%0">;
def warn_ignoring_ftabstop_value : Warning<
"ignoring invalid -ftabstop value '%0', using default value %1">;
+def warn_drv_overriding_flag_option : Warning<
+ "overriding '%0' option with '%1'">,
+ InGroup<DiagGroup<"overriding-t-option">>;
def warn_drv_treating_input_as_cxx : Warning<
"treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">,
InGroup<Deprecated>;
@@ -147,6 +157,8 @@ def warn_missing_sysroot : Warning<"no such sysroot directory: '%0'">,
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
+def note_drv_t_option_is_global :
+ Note<"The last /TC or /TP option takes precedence over earlier instances">;
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index f05fb9be82cc..bcf3c41cdb64 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -11,7 +11,7 @@ let Component = "Frontend" in {
def err_fe_error_opening : Error<"error opening '%0': %1">;
def err_fe_error_reading : Error<"error reading '%0'">;
-def err_fe_error_reading_stdin : Error<"error reading stdin">;
+def err_fe_error_reading_stdin : Error<"error reading stdin: %0">;
def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
// Error generated by the backend.
@@ -136,9 +136,8 @@ 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 err_module_map_temp_file : Error<
- "unable to write temporary module map file '%0'">, DefaultFatal;
-def err_module_unavailable : Error<"module '%0' requires feature '%1'">;
+def err_module_unavailable : Error<
+ "module '%0' %select{is incompatible with|requires}1 feature '%2'">;
def warn_module_config_macro_undef : Warning<
"%select{definition|#undef}0 of configuration macro '%1' has no effect on "
"the import of '%2'; pass '%select{-D%1=...|-U%1}0' on the command line "
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index d5f777d3d715..b0d02164ebc4 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -21,12 +21,16 @@ def : DiagGroup<"abi">;
def : DiagGroup<"address">;
def AddressOfTemporary : DiagGroup<"address-of-temporary">;
def : DiagGroup<"aggregate-return">;
+def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">;
def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
+def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
def ArrayBounds : DiagGroup<"array-bounds">;
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
def Availability : DiagGroup<"availability">;
def Section : DiagGroup<"section">;
def AutoImport : DiagGroup<"auto-import">;
+def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
+def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
def ConstantConversion :
DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
@@ -45,23 +49,39 @@ def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def C99Compat : DiagGroup<"c99-compat">;
def CXXCompat: DiagGroup<"c++-compat">;
+def ExternCCompat : DiagGroup<"extern-c-compat">;
+def KeywordCompat : DiagGroup<"keyword-compat">;
+def GNUCaseRange : DiagGroup<"gnu-case-range">;
def CastAlign : DiagGroup<"cast-align">;
def : DiagGroup<"cast-qual">;
def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
+def GNUComplexInteger : DiagGroup<"gnu-complex-integer">;
+def GNUConditionalOmittedOperand : DiagGroup<"gnu-conditional-omitted-operand">;
def ConfigMacros : DiagGroup<"config-macros">;
def : DiagGroup<"ctor-dtor-privacy">;
def GNUDesignator : DiagGroup<"gnu-designator">;
+def GNUStringLiteralOperatorTemplate :
+ DiagGroup<"gnu-string-literal-operator-template">;
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
def AbstractFinalClass : DiagGroup<"abstract-final-class">;
-def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
-def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
-def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >,
- DiagCategory<"Deprecations">;
+def CXX11CompatDeprecatedWritableStr :
+ DiagGroup<"c++11-compat-deprecated-writable-strings">;
+def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
+def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
+def DeprecatedRegister : DiagGroup<"deprecated-register">;
+def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
+ [CXX11CompatDeprecatedWritableStr]>;
+// FIXME: Why are DeprecatedImplementations and DeprecatedWritableStr
+// not in this group?
+def Deprecated : DiagGroup<"deprecated", [DeprecatedDeclarations,
+ DeprecatedIncrementBool,
+ DeprecatedRegister]>,
+ DiagCategory<"Deprecations">;
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
@@ -77,16 +97,21 @@ def Documentation : DiagGroup<"documentation",
DocumentationDeprecatedSync]>;
def EmptyBody : DiagGroup<"empty-body">;
+def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">;
+def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">;
def ExtraTokens : DiagGroup<"extra-tokens">;
def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
def ExtraSemi : DiagGroup<"extra-semi", [CXX11ExtraSemi]>;
+def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">;
+def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">;
+def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
// Warnings for C++1y code which is not compatible with prior C++ standards.
-def CXXPre1yCompat : DiagGroup<"cxx98-cxx11-compat">;
-def CXXPre1yCompatPedantic : DiagGroup<"cxx98-cxx11-compat-pedantic",
+def CXXPre1yCompat : DiagGroup<"c++98-c++11-compat">;
+def CXXPre1yCompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
[CXXPre1yCompat]>;
def CXX98CompatBindToTemporaryCopy :
@@ -123,6 +148,7 @@ def ReservedUserDefinedLiteral :
def CXX11Compat : DiagGroup<"c++11-compat",
[CXX11Narrowing,
CXX11CompatReservedUserDefinedLiteral,
+ CXX11CompatDeprecatedWritableStr,
CXXPre1yCompat]>;
def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic",
@@ -136,11 +162,13 @@ def FourByteMultiChar : DiagGroup<"four-char-constants">;
def GlobalConstructors : DiagGroup<"global-constructors">;
def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
+def LogicalNotParentheses: DiagGroup<"logical-not-parentheses">;
def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">;
def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
def DanglingField : DiagGroup<"dangling-field">;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
+def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
def IncompatiblePointerTypesDiscardsQualifiers
@@ -149,15 +177,18 @@ def IncompatiblePointerTypes
: DiagGroup<"incompatible-pointer-types",
[IncompatiblePointerTypesDiscardsQualifiers]>;
def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
+def IncompleteModule : DiagGroup<"incomplete-module", [IncompleteUmbrella]>;
def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
def : DiagGroup<"invalid-pch">;
+def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">;
def LiteralRange : DiagGroup<"literal-range">;
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args",
[CXX98CompatLocalTypeTemplateArgs]>;
+def LoopAnalysis : DiagGroup<"loop-analysis">;
def MalformedWarningCheck : DiagGroup<"malformed-warning-check">;
def Main : DiagGroup<"main">;
def MainReturnType : DiagGroup<"main-return-type">;
@@ -176,6 +207,7 @@ def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def ModuleConflict : DiagGroup<"module-conflict">;
+def NewlineEOF : DiagGroup<"newline-eof">;
def NullArithmetic : DiagGroup<"null-arithmetic">;
def NullCharacter : DiagGroup<"null-character">;
def NullDereference : DiagGroup<"null-dereference">;
@@ -202,7 +234,10 @@ def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">;
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">;
+def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">;
def ObjCRootClass : DiagGroup<"objc-root-class">;
+def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">;
+def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>;
def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">;
def Packed : DiagGroup<"packed">;
def Padded : DiagGroup<"padded">;
@@ -213,6 +248,8 @@ def PoundPragmaMessage : DiagGroup<"#pragma-messages">,
DiagCategory<"#pragma message Directive">;
def : DiagGroup<"pointer-to-int-cast">;
def : DiagGroup<"redundant-decls">;
+def RedeclaredClassMember : DiagGroup<"redeclared-class-member">;
+def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">;
def ReturnStackAddress : DiagGroup<"return-stack-address">;
def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
@@ -237,7 +274,9 @@ def StaticInInline : DiagGroup<"static-in-inline">;
def StaticLocalInInline : DiagGroup<"static-local-in-inline">;
def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">;
def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatInit]>;
+def GNUStatementExpression : DiagGroup<"gnu-statement-expression">;
def StringPlusInt : DiagGroup<"string-plus-int">;
+def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
@@ -245,6 +284,9 @@ def TautologicalCompare : DiagGroup<"tautological-compare",
def HeaderHygiene : DiagGroup<"header-hygiene">;
def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
+def GNUUnionCast : DiagGroup<"gnu-union-cast">;
+def GNUVariableSizedTypeNotAtEnd : DiagGroup<"gnu-variable-sized-type-not-at-end">;
+def Varargs : DiagGroup<"varargs">;
def Unsequenced : DiagGroup<"unsequenced">;
// GCC name for -Wunsequenced
@@ -298,10 +340,12 @@ def UnknownAttributes : DiagGroup<"attributes">;
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
[CXX98CompatUnnamedTypeTemplateArgs]>;
+def UnsupportedFriend : DiagGroup<"unsupported-friend">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedSanitizeArgument : DiagGroup<"unused-sanitize-argument">;
def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument",
[UnusedSanitizeArgument]>;
+def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument">;
def UnusedComparison : DiagGroup<"unused-comparison">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
@@ -314,7 +358,10 @@ def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedResult : DiagGroup<"unused-result">;
def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>;
-def UnusedVariable : DiagGroup<"unused-variable">;
+def UnusedConstVariable : DiagGroup<"unused-const-variable">;
+def UnusedVariable : DiagGroup<"unused-variable",
+ [UnusedConstVariable]>;
+def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
@@ -336,7 +383,10 @@ def AutomaticReferenceCounting : DiagGroup<"arc",
def ARCRepeatedUseOfWeakMaybe : DiagGroup<"arc-maybe-repeated-use-of-weak">;
def ARCRepeatedUseOfWeak : DiagGroup<"arc-repeated-use-of-weak",
[ARCRepeatedUseOfWeakMaybe]>;
-def Selector : DiagGroup<"selector">;
+def ObjCBridge : DiagGroup<"bridge-cast">;
+
+def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">;
+def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>;
def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
@@ -348,6 +398,8 @@ def VLAExtension : DiagGroup<"vla-extension">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def Visibility : DiagGroup<"visibility">;
def ZeroLengthArray : DiagGroup<"zero-length-array">;
+def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
+def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
// GCC calls -Wdeprecated-writable-strings -Wwrite-strings.
def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>;
@@ -365,6 +417,7 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
def Parentheses : DiagGroup<"parentheses",
[LogicalOpParentheses,
+ LogicalNotParentheses,
BitwiseOpParentheses,
ShiftOpParentheses,
OverloadedShiftOpParentheses,
@@ -396,7 +449,7 @@ def Unused : DiagGroup<"unused",
// UnusedParameter, (matches GCC's behavior)
// UnusedMemberFunction, (clean-up llvm before enabling)
UnusedPrivateField,
- UnusedValue, UnusedVariable]>,
+ UnusedValue, UnusedVariable, UnusedPropertyIvar]>,
DiagCategory<"Unused Entity Issue">;
// Format settings.
@@ -414,7 +467,9 @@ def Format2 : DiagGroup<"format=2",
def TypeSafety : DiagGroup<"type-safety">;
-def IntToPointerCast : DiagGroup<"int-to-pointer-cast">;
+def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">;
+def IntToPointerCast : DiagGroup<"int-to-pointer-cast",
+ [IntToVoidPointerCast]>;
def Extra : DiagGroup<"extra", [
MissingFieldInitializers,
@@ -449,7 +504,8 @@ def Most : DiagGroup<"most", [
ObjCMissingSuperCalls,
OverloadedVirtual,
PrivateExtern,
- SelTypeCast
+ SelTypeCast,
+ ExternCCompat
]>;
// Thread Safety warnings
@@ -462,6 +518,9 @@ def ThreadSafety : DiagGroup<"thread-safety",
ThreadSafetyPrecise]>;
def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">;
+// Uniqueness Analysis warnings
+def Consumed : DiagGroup<"consumed">;
+
// Note that putting warnings in -Wall will not disable them by default. If a
// warning should be active _only_ when -Wall is passed in, mark it as
// DefaultIgnore in addition to putting it here.
@@ -472,7 +531,7 @@ def Pedantic : DiagGroup<"pedantic">;
// Aliases.
def : DiagGroup<"", [Extra]>; // -W = -Wextra
-def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wendif-tokens
+def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens
def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
def : DiagGroup<"conversion-null",
[NullConversion]>; // -Wconversion-null = -Wnull-conversion
@@ -507,8 +566,20 @@ def C11 : DiagGroup<"c11-extensions">;
def C99 : DiagGroup<"c99-extensions">;
// A warning group for warnings about GCC extensions.
-def GNU : DiagGroup<"gnu", [GNUDesignator, VLAExtension,
- ZeroLengthArray, GNUStaticFloatInit]>;
+def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
+ GNUBinaryLiteral, GNUCaseRange,
+ GNUComplexInteger, GNUCompoundLiteralInitializer,
+ GNUConditionalOmittedOperand, GNUDesignator,
+ GNUEmptyInitializer, GNUEmptyStruct,
+ VLAExtension, GNUFlexibleArrayInitializer,
+ GNUFlexibleArrayUnionMember, GNUFoldingConstant,
+ GNUImaginaryConstant, GNULabelsAsValue,
+ RedeclaredClassMember, GNURedeclaredEnum,
+ GNUStatementExpression, GNUStaticFloatInit,
+ GNUStringLiteralOperatorTemplate,
+ GNUUnionCast, GNUVariableSizedTypeNotAtEnd,
+ ZeroLengthArray, GNUZeroLineDirective,
+ GNUZeroVariadicMacroArguments]>;
// A warning group for warnings about code that clang accepts but gcc doesn't.
def GccCompat : DiagGroup<"gcc-compat">;
@@ -532,10 +603,13 @@ def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [
]>;
def ObjCStringComparison : DiagGroup<"objc-string-compare">;
+def ObjCStringConcatenation : DiagGroup<"objc-string-concatenation">;
def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [
ObjCStringComparison
]>;
+def ObjCLiteralMissingAtSign : DiagGroup<"objc-literal-missing-atsign">;
+
// Inline ASM warnings.
def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
def ASM : DiagGroup<"asm", [
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index d35b90742496..56e30fbda7b0 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -22,13 +22,13 @@
namespace clang {
class DiagnosticsEngine;
class SourceLocation;
- struct WarningOption;
// Import the diagnostic enums themselves.
namespace diag {
// Start position for diagnostics.
enum {
- DIAG_START_DRIVER = 300,
+ DIAG_START_COMMON = 0,
+ DIAG_START_DRIVER = DIAG_START_COMMON + 300,
DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
@@ -48,7 +48,8 @@ namespace clang {
// Get typedefs for common diagnostics.
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER) ENUM,
+ SFINAE,CATEGORY,NOWERROR,SHOWINSYSHEADER) ENUM,
+#define COMMONSTART
#include "clang/Basic/DiagnosticCommonKinds.inc"
NUM_BUILTIN_COMMON_DIAGNOSTICS
#undef DIAG
@@ -105,11 +106,12 @@ public:
void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
};
-/// \brief Used for handling and querying diagnostic IDs. Can be used and shared
-/// by multiple Diagnostics for multiple translation units.
+/// \brief Used for handling and querying diagnostic IDs.
+///
+/// Can be used and shared by multiple Diagnostics for multiple translation units.
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
- /// Level The level of the diagnostic, after it has been through mapping.
+ /// \brief The level of the diagnostic, after it has been through mapping.
enum Level {
Ignored, Note, Warning, Error, Fatal
};
@@ -224,8 +226,8 @@ public:
/// \brief Get the set of all diagnostic IDs in the group with the given name.
///
- /// \param Diags [out] - On return, the diagnostics in the group.
- /// \returns True if the given group is unknown, false otherwise.
+ /// \param[out] Diags - On return, the diagnostics in the group.
+ /// \returns \c true if the given group is unknown, \c false otherwise.
bool getDiagnosticsInGroup(StringRef Group,
SmallVectorImpl<diag::kind> &Diags) const;
@@ -237,18 +239,14 @@ public:
static StringRef getNearestWarningOption(StringRef Group);
private:
- /// \brief Get the set of all diagnostic IDs in the given group.
- ///
- /// \param Diags [out] - On return, the diagnostics in the group.
- void getDiagnosticsInGroup(const WarningOption *Group,
- SmallVectorImpl<diag::kind> &Diags) const;
-
- /// \brief Based on the way the client configured the DiagnosticsEngine
- /// object, classify the specified diagnostic ID into a Level, consumable by
+ /// \brief Classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
+ ///
+ /// The classification is based on the way the client configured the
+ /// DiagnosticsEngine object.
///
- /// \param Loc The source location we are interested in finding out the
- /// diagnostic state. Can be null in order to query the latest state.
+ /// \param Loc The source location for which we are interested in finding out
+ /// the diagnostic state. Can be null in order to query the latest state.
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
const DiagnosticsEngine &Diag) const;
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 2c16000d339d..871f5f65447d 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -47,7 +47,9 @@ def ext_line_comment : Extension<
"// comments are not allowed in this language">,
InGroup<Comment>;
def ext_no_newline_eof : Extension<"no newline at end of file">,
- InGroup<DiagGroup<"newline-eof">>;
+ InGroup<NewlineEOF>;
+def warn_no_newline_eof : Warning<"no newline at end of file">,
+ InGroup<NewlineEOF>, DefaultIgnore;
def warn_cxx98_compat_no_newline_eof : Warning<
"C++98 requires newline at end of file">,
@@ -157,6 +159,11 @@ def err_invalid_suffix_integer_constant : Error<
"invalid suffix '%0' on integer constant">;
def err_invalid_suffix_float_constant : Error<
"invalid suffix '%0' on floating constant">;
+def warn_cxx11_compat_digit_separator : Warning<
+ "digit separators are incompatible with C++ standards before C++1y">,
+ InGroup<CXXPre1yCompat>, DefaultIgnore;
+def err_digit_separator_not_between_digits : Error<
+ "digit separator cannot appear at %select{start|end}0 of digit sequence">;
def warn_extraneous_char_constant : Warning<
"extraneous characters in character constant ignored">;
def warn_char_constant_too_large : Warning<
@@ -165,7 +172,7 @@ 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<GNU>;
+ "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
def err_hexconstant_requires_digits : Error<
@@ -173,15 +180,15 @@ def err_hexconstant_requires_digits : Error<
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_binary_literal : Extension<
- "binary integer literals are a GNU extension">, InGroup<GNU>;
+ "binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>;
def ext_binary_literal_cxx1y : Extension<
"binary integer literals are a C++1y extension">, InGroup<CXX1y>;
def warn_cxx11_compat_binary_literal : Warning<
"binary integer literals are incompatible with C++ standards before C++1y">,
InGroup<CXXPre1yCompatPedantic>, DefaultIgnore;
def err_pascal_string_too_long : Error<"Pascal string is too long">;
-def warn_octal_escape_too_large : ExtWarn<"octal escape sequence out of range">;
-def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">;
+def err_octal_escape_too_large : Error<"octal escape sequence out of range">;
+def err_hex_escape_too_large : Error<"hex escape sequence out of range">;
def ext_string_too_long : Extension<"string literal of length %0 exceeds "
"maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to "
"support">, InGroup<OverlengthStrings>;
@@ -320,7 +327,7 @@ def ext_embedded_directive : Extension<
InGroup<DiagGroup<"embedded-directive">>;
def ext_missing_varargs_arg : Extension<
"must specify at least one argument for '...' parameter of variadic macro">,
- InGroup<GNU>;
+ InGroup<GNUZeroVariadicMacroArguments>;
def ext_empty_fnmacro_arg : Extension<
"empty macro arguments are a C99 feature">, InGroup<C99>;
def warn_cxx98_compat_empty_fnmacro_arg : Warning<
@@ -406,6 +413,21 @@ def warn_pragma_include_alias_expected_filename :
ExtWarn<"pragma include_alias expected include filename">,
InGroup<UnknownPragmas>;
+// - #pragma warning(...)
+def warn_pragma_warning_expected :
+ ExtWarn<"#pragma warning expected '%0'">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_warning_spec_invalid :
+ ExtWarn<"#pragma warning expected 'push', 'pop', 'default', 'disable',"
+ " 'error', 'once', 'suppress', 1, 2, 3, or 4">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_warning_push_level :
+ ExtWarn<"#pragma warning(push, level) requires a level between 0 and 4">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_warning_expected_number :
+ ExtWarn<"#pragma warning expected a warning number">,
+ InGroup<UnknownPragmas>;
+
def err__Pragma_malformed : Error<
"_Pragma takes a parenthesized string literal">;
def err_pragma_message_malformed : Error<
@@ -455,11 +477,16 @@ def err_paste_at_start : Error<
"'##' cannot appear at start of macro expansion">;
def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
def ext_paste_comma : Extension<
- "token pasting of ',' and __VA_ARGS__ is a GNU extension">, InGroup<GNU>;
+ "token pasting of ',' and __VA_ARGS__ is a GNU extension">, InGroup<GNUZeroVariadicMacroArguments>;
def err_unterm_macro_invoc : Error<
"unterminated function-like macro invocation">;
def err_too_many_args_in_macro_invoc : Error<
"too many arguments provided to function-like macro invocation">;
+def note_suggest_parens_for_macro : Note<
+ "parentheses are required around macro argument containing braced "
+ "initializer list">;
+def note_init_list_at_beginning_of_macro_argument : Note<
+ "cannot use initializer list at the beginning of a macro argument">;
def err_too_few_args_in_macro_invoc : Error<
"too few arguments provided to function-like macro invocation">;
def err_pp_bad_paste : Error<
@@ -475,7 +502,7 @@ def err_pp_line_requires_integer : Error<
"#line directive requires a positive integer argument">;
def ext_pp_line_zero : Extension<
"#line directive with zero argument is a GNU extension">,
- InGroup<GNU>;
+ InGroup<GNUZeroLineDirective>;
def err_pp_line_invalid_filename : Error<
"invalid filename for #line directive">;
def warn_pp_line_decimal : Warning<
@@ -520,19 +547,18 @@ def note_mmap_lsquare_match : Note<"to match this ']'">;
def err_mmap_expected_member : Error<
"expected umbrella, header, submodule, or module export">;
def err_mmap_expected_header : Error<"expected a header name after '%0'">;
+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_header_conflict : Error<
- "header '%0' is already part of module '%1'">;
def err_mmap_header_not_found : Error<
"%select{|umbrella }0header '%1' not found">;
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_export_module_id : Error<
- "expected an exported module name or '*'">;
+def err_mmap_module_id : Error<
+ "expected a module name or '*'">;
def err_mmap_expected_library_name : Error<
"expected %select{library|framework}0 name as a string">;
def err_mmap_config_macro_submodule : Error<
@@ -579,8 +605,20 @@ def warn_auto_module_import : Warning<
"import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
def warn_uncovered_module_header : Warning<
"umbrella header for module '%0' does not include header '%1'">,
- InGroup<IncompleteUmbrella>;
+ InGroup<IncompleteUmbrella>, DefaultIgnore;
+def warn_forgotten_module_header : Warning<
+ "header '%0' is included in module '%1' but not listed in module map">,
+ InGroup<IncompleteModule>, DefaultIgnore;
def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">;
-
+def error_use_of_private_header_outside_module : Error<
+ "use of private header from outside its module: '%0'">;
+def error_undeclared_use_of_module : Error<
+ "use of a module not declared used: '%0'">;
+
+def warn_header_guard : Warning<
+ "%0 is used as a header guard here, followed by #define of a different macro">,
+ InGroup<DiagGroup<"header-guard">>;
+def note_header_guard : Note<
+ "%0 is defined here; did you mean %1?">;
}
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
index 41bbff2edec2..a360a5a84e98 100644
--- a/include/clang/Basic/DiagnosticOptions.def
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -72,6 +72,7 @@ DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected
DIAGOPT(ElideType, 1, 0) /// Elide identical types in template diffing
DIAGOPT(ShowTemplateTree, 1, 0) /// Print a template tree when diffing
+DIAGOPT(CLFallbackMode, 1, 0) /// Format for clang-cl fallback mode
VALUE_DIAGOPT(ErrorLimit, 32, 0) /// Limit # errors emitted.
/// Limit depth of macro expansion backtrace.
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e001bd46a230..2feab52ef4d1 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -23,6 +23,8 @@ def err_asm_empty : Error<"__asm used with no assembly instructions">;
def err_inline_ms_asm_parsing : Error<"%0">;
def err_msasm_unsupported_arch : Error<
"Unsupported architecture '%0' for MS-style inline assembly">;
+def err_msasm_unable_to_create_target : Error<
+ "MS-style inline assembly is not available: %0">;
}
let CategoryName = "Parse Issue" in {
@@ -54,13 +56,12 @@ def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">,
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
def ext_integer_complex : Extension<
- "complex integer types are a GNU extension">, InGroup<GNU>;
+ "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
def ext_thread_before : Extension<"'__thread' before '%0'">;
+def ext_keyword_as_ident : ExtWarn<
+ "keyword '%0' will be treated as an identifier %select{here|for the remainder of the translation unit}1">,
+ InGroup<KeywordCompat>;
-def ext_empty_struct_union : Extension<
- "empty %select{struct|union}0 is a GNU extension">, InGroup<GNU>;
-def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 "
- "has size 0 in C, size 1 in C++">, InGroup<CXXCompat>, DefaultIgnore;
def error_empty_enum : Error<"use of empty enum">;
def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
def err_invalid_short_spec : Error<"'short %0' is invalid">;
@@ -75,8 +76,6 @@ def ext_c99_variable_decl_in_for_loop : Extension<
"variable declaration in for loop is a C99-specific feature">, InGroup<C99>;
def ext_c99_compound_literal : Extension<
"compound literals are a C99-specific feature">, InGroup<C99>;
-def ext_c99_flexible_array_member : Extension<
- "Flexible array members are a C99-specific feature">, InGroup<C99>;
def ext_enumerator_list_comma_c : Extension<
"commas at the end of enumerator lists are a C99-specific "
"feature">, InGroup<C99>;
@@ -103,7 +102,7 @@ def warn_cxx98_compat_alignof : Warning<
"alignof expressions are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_alignof_expr : ExtWarn<
- "%0 applied to an expression is a GNU extension">, InGroup<GNU>;
+ "%0 applied to an expression is a GNU extension">, InGroup<GNUAlignofExpression>;
def warn_microsoft_dependent_exists : Warning<
"dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">,
@@ -123,17 +122,15 @@ def ext_c11_noreturn : Extension<
"_Noreturn functions are a C11-specific feature">, InGroup<C11>;
def ext_gnu_indirect_goto : Extension<
- "use of GNU indirect-goto extension">, InGroup<GNU>;
+ "use of GNU indirect-goto extension">, InGroup<GNULabelsAsValue>;
def ext_gnu_address_of_label : Extension<
- "use of GNU address-of-label extension">, InGroup<GNU>;
-def ext_gnu_local_label : Extension<
- "use of GNU locally declared label extension">, InGroup<GNU>;
+ "use of GNU address-of-label extension">, InGroup<GNULabelsAsValue>;
def ext_gnu_statement_expr : Extension<
- "use of GNU statement expression extension">, InGroup<GNU>;
+ "use of GNU statement expression extension">, InGroup<GNUStatementExpression>;
def ext_gnu_conditional_expr : Extension<
- "use of GNU ?: expression extension, eliding middle term">, InGroup<GNU>;
+ "use of GNU ?: conditional expression extension, omitting middle operand">, InGroup<GNUConditionalOmittedOperand>;
def ext_gnu_empty_initializer : Extension<
- "use of GNU empty initializer extension">, InGroup<GNU>;
+ "use of GNU empty initializer extension">, InGroup<GNUEmptyInitializer>;
def ext_gnu_array_range : Extension<"use of GNU array range extension">,
InGroup<GNUDesignator>;
def ext_gnu_missing_equal_designator : ExtWarn<
@@ -144,7 +141,7 @@ def ext_gnu_old_style_field_designator : ExtWarn<
"use of GNU old-style field designator extension">,
InGroup<GNUDesignator>;
def ext_gnu_case_range : Extension<"use of GNU case range extension">,
- InGroup<GNU>;
+ InGroup<GNUCaseRange>;
// Generic errors.
def err_expected_expression : Error<"expected expression">;
@@ -156,7 +153,7 @@ def err_expected_ident_lparen : Error<"expected identifier or '('">;
def err_expected_ident_lbrace : Error<"expected identifier or '{'">;
def err_expected_lbrace : Error<"expected '{'">;
def err_expected_lparen : Error<"expected '('">;
-def err_expected_lparen_or_lbrace : Error<"expected '('or '{'">;
+def err_expected_lparen_or_lbrace : Error<"expected '(' or '{'">;
def err_expected_rparen : Error<"expected ')'">;
def err_expected_lsquare : Error<"expected '['">;
def err_expected_rsquare : Error<"expected ']'">;
@@ -173,10 +170,6 @@ def err_expected_member_name_or_semi : Error<
"expected member name or ';' after declaration specifiers">;
def err_function_declared_typedef : Error<
"function definition declared 'typedef'">;
-def err_iboutletcollection_builtintype : Error<
- "type argument of iboutletcollection attribute cannot be a builtin type">;
-def err_iboutletcollection_with_protocol : Error<
- "invalid argument of iboutletcollection attribute">;
def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">;
def err_at_in_class : Error<"unexpected '@' in member specification">;
@@ -313,6 +306,11 @@ def err_expected_class_name_not_template :
Error<"'typename' is redundant; base classes are implicitly types">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
+def warn_deprecated_register : Warning<
+ "'register' storage class specifier is deprecated">,
+ InGroup<DeprecatedRegister>;
+def err_expected_parentheses_around_typename : Error<
+ "expected parentheses around type name in %0 expression">;
def err_expected_case_before_expression: Error<
"expected 'case' keyword before expression">;
@@ -451,6 +449,7 @@ def err_invalid_operator_on_type : Error<
"cannot use %select{dot|arrow}0 operator on a type">;
def err_expected_unqualified_id : Error<
"expected %select{identifier|unqualified-id}0">;
+def err_unexpected_unqualified_id : Error<"type-id cannot have a name">;
def err_func_def_no_params : Error<
"function definition does not declare parameters">;
def err_expected_lparen_after_type : Error<
@@ -468,6 +467,10 @@ def err_expected_member_or_base_name : Error<
"expected class member or base class name">;
def err_expected_lbrace_after_base_specifiers : Error<
"expected '{' after base class list">;
+def err_missing_end_of_definition : Error<
+ "missing '}' at end of definition of %q0">;
+def note_missing_end_of_definition_before : Note<
+ "still within definition of %q0 here">;
def ext_ellipsis_exception_spec : Extension<
"exception specification of '...' is a Microsoft extension">,
InGroup<Microsoft>;
@@ -482,6 +485,8 @@ def err_expected_rbrace_or_comma : Error<"expected '}' or ','">;
def err_expected_rsquare_or_comma : Error<"expected ']' or ','">;
def err_using_namespace_in_class : Error<
"'using namespace' is not allowed in classes">;
+def err_constructor_bad_name : Error<
+ "missing return type for function %0; did you mean the constructor name %1?">;
def err_destructor_tilde_identifier : Error<
"expected a class name after '~' to name a destructor">;
def err_destructor_template_id : Error<
@@ -498,6 +503,9 @@ def err_misplaced_ellipsis_in_declaration : Error<
def ext_abstract_pack_declarator_parens : ExtWarn<
"ISO C++11 requires a parenthesized pack declaration to have a name">,
InGroup<DiagGroup<"anonymous-pack-parens">>;
+def err_function_is_not_record : Error<
+ "unexpected '%select{.|->}0' in function call; perhaps remove the "
+ "'%select{.|->}0'?">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -579,7 +587,7 @@ def err_two_right_angle_brackets_need_space : Error<
def err_right_angle_bracket_equal_needs_space : Error<
"a space is required between a right angle bracket and an equals sign "
"(use '> =')">;
-def warn_cxx0x_right_shift_in_template_arg : Warning<
+def warn_cxx11_right_shift_in_template_arg : Warning<
"use of right-shift operator ('>>') in template argument will require "
"parentheses in C++11">, InGroup<CXX11Compat>;
def warn_cxx98_compat_two_right_angle_brackets : Warning<
@@ -593,6 +601,12 @@ def err_explicit_instantiation_with_definition : Error<
"explicit template instantiation cannot have a definition; if this "
"definition is meant to be an explicit specialization, add '<>' after the "
"'template' keyword">;
+def err_template_defn_explicit_instantiation : Error<
+ "%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this "
+ "declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">;
+def err_friend_explicit_instantiation : Error<
+ "friend cannot be declared in an explicit instantiation; if this "
+ "declaration is meant to be a friend declaration, remove the 'template' keyword">;
def err_explicit_instantiation_enum : Error<
"enumerations cannot be explicitly instantiated">;
def err_expected_template_parameter : Error<"expected template parameter">;
@@ -609,7 +623,7 @@ def warn_cxx98_compat_extern_template : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def warn_static_inline_explicit_inst_ignored : Warning<
"ignoring '%select{static|inline}0' keyword on explicit template "
- "instantiation">;
+ "instantiation">, InGroup<DiagGroup<"static-inline-explicit-instantiation">>;
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<
@@ -693,6 +707,9 @@ def warn_cxx98_compat_override_control_keyword : Warning<
InGroup<CXX98Compat>, DefaultIgnore;
def err_override_control_interface : Error<
"'%0' keyword not permitted with interface types">;
+def ext_ms_sealed_keyword : ExtWarn<
+ "'sealed' keyword is a Microsoft extension">,
+ InGroup<Microsoft>;
def err_access_specifier_interface : Error<
"interface types cannot specify '%select{private|protected}0' access">;
@@ -783,13 +800,16 @@ def warn_pragma_unused_expected_punc : Warning<
"expected ')' or ',' in '#pragma unused'">;
// - #pragma fp_contract
def err_pragma_fp_contract_scope : Error<
- "'#pragma fp_contract' should only appear at file scope or at the start of a "
- "compound expression">;
+ "'#pragma fp_contract' can only appear at file scope or at the start of a "
+ "compound statement">;
// - #pragma comment
def err_pragma_comment_malformed : Error<
"pragma comment requires parenthesized identifier and optional string">;
def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
-
+// - #pragma detect_mismatch
+def err_pragma_detect_mismatch_malformed : Error<
+ "pragma detect_mismatch is malformed; it requires two comma-separated "
+ "string literals">;
// OpenCL Section 6.8.g
def err_not_opencl_storage_class_specifier : Error<
@@ -819,13 +839,18 @@ def err_seh___finally_block : Error<
def warn_pragma_omp_ignored : Warning <
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
def warn_omp_extra_tokens_at_eol : Warning <
- "extra tokens at end of '#pragma omp %0' are ignored">,
+ "extra tokens at the end of '#pragma omp %0' are ignored">,
InGroup<ExtraTokens>;
def err_omp_unknown_directive : Error <
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error <
"unexpected OpenMP directive '#pragma omp %0'">;
-
+def err_omp_expected_punc : Error <
+ "expected ',' or ')' in %select{'#pragma omp %1'|'%1' clause}0">;
+def err_omp_unexpected_clause : Error <
+ "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">;
+def err_omp_more_one_clause : Error <
+ "directive '#pragma omp %0' cannot contain more than one '%1' clause">;
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index f5345eb8c359..6c7cb001808a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -18,7 +18,12 @@ let CategoryName = "Semantic Issue" in {
def warn_variables_not_in_loop_body : Warning<
"variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 "
"used in loop condition not modified in loop body">,
- InGroup<DiagGroup<"loop-analysis">>, DefaultIgnore;
+ InGroup<LoopAnalysis>, DefaultIgnore;
+def warn_redundant_loop_iteration : Warning<
+ "variable %0 is %select{decremented|incremented}1 both in the loop header "
+ "and in the loop body">,
+ InGroup<LoopAnalysis>, DefaultIgnore;
+def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
def warn_duplicate_enum_values : Warning<
"element %0 has been implicitly assigned %1 which another element has "
@@ -30,23 +35,19 @@ def err_expr_not_ice : Error<
"expression is not an %select{integer|integral}0 constant expression">;
def ext_expr_not_ice : Extension<
"expression is not an %select{integer|integral}0 constant expression; "
- "folding it to a constant is a GNU extension">, InGroup<GNU>;
+ "folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>;
def err_typecheck_converted_constant_expression : Error<
"value of type %0 is not implicitly convertible to %1">;
def err_typecheck_converted_constant_expression_disallowed : Error<
"conversion from %0 to %1 is not allowed in a converted constant expression">;
def err_expr_not_cce : Error<
- "%select{case value|enumerator value|non-type template argument}0 "
+ "%select{case value|enumerator value|non-type template argument|array size}0 "
"is not a constant expression">;
-def err_cce_narrowing : ExtWarn<
- "%select{case value|enumerator value|non-type template argument}0 "
+def ext_cce_narrowing : ExtWarn<
+ "%select{case value|enumerator value|non-type template argument|array size}0 "
"%select{cannot be narrowed from type %2 to %3|"
"evaluates to %2, which cannot be narrowed to type %3}1">,
- InGroup<CXX11Narrowing>, DefaultError;
-def err_cce_narrowing_sfinae : Error<
- "%select{case value|enumerator value|non-type template argument}0 "
- "%select{cannot be narrowed from type %2 to %3|"
- "evaluates to %2, which cannot be narrowed to type %3}1">;
+ InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def err_ice_not_integral : Error<
"integral constant expression must have integral or unscoped enumeration "
"type, not %0">;
@@ -78,9 +79,6 @@ def ext_vla : Extension<"variable length arrays are a C99 feature">,
InGroup<VLAExtension>;
def warn_vla_used : Warning<"variable length array used">,
InGroup<VLA>, DefaultIgnore;
-def warn_cxx11_compat_array_of_runtime_bound : Warning<
- "arrays of runtime bound are incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompatPedantic>, DefaultIgnore;
def err_vla_non_pod : Error<"variable length array of non-POD element type %0">;
def err_vla_in_sfinae : Error<
"variable length array cannot be formed during template argument deduction">;
@@ -93,7 +91,7 @@ def err_vla_decl_has_static_storage : Error<
def err_vla_decl_has_extern_linkage : Error<
"variable length array declaration can not have 'extern' linkage">;
def ext_vla_folded_to_constant : Extension<
- "variable length array folded to constant array as an extension">;
+ "variable length array folded to constant array as an extension">, InGroup<GNUFoldingConstant>;
// C99 variably modified types
def err_variably_modified_template_arg : Error<
@@ -138,7 +136,7 @@ def err_designator_into_flexible_array_member : Error<
def note_flexible_array_member : Note<
"initialized flexible array member %0 is here">;
def ext_flexible_array_init : Extension<
- "flexible array initialization is a GNU extension">, InGroup<GNU>;
+ "flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
// Declarations.
def err_bad_variable_name : Error<
@@ -150,6 +148,12 @@ def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
+def warn_unused_property_backing_ivar :
+ Warning<"ivar %0 which backs the property is not "
+ "referenced in this property's accessor">,
+ InGroup<UnusedPropertyIvar>, DefaultIgnore;
+def warn_unused_const_variable : Warning<"unused variable %0">,
+ InGroup<UnusedConstVariable>, DefaultIgnore;
def warn_unused_exception_param : Warning<"unused exception parameter %0">,
InGroup<UnusedExceptionParameter>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
@@ -287,6 +291,18 @@ def note_using_decl : Note<"%select{|previous }0using declaration">;
def warn_access_decl_deprecated : Warning<
"access declarations are deprecated; use using declarations instead">,
InGroup<Deprecated>;
+def err_access_decl : Error<
+ "ISO C++11 does not allow access declarations; "
+ "use using declarations instead">;
+def warn_exception_spec_deprecated : Warning<
+ "dynamic exception specifications are deprecated">,
+ InGroup<Deprecated>, DefaultIgnore;
+def note_exception_spec_deprecated : Note<"use '%0' instead">;
+def warn_deprecated_copy_operation : Warning<
+ "definition of implicit copy %select{constructor|assignment operator}1 "
+ "for %0 is deprecated because it has a user-declared "
+ "%select{copy %select{assignment operator|constructor}1|destructor}2">,
+ InGroup<Deprecated>, DefaultIgnore;
def warn_global_constructor : Warning<
"declaration requires a global constructor">,
@@ -400,7 +416,7 @@ def ext_noreturn_main : ExtWarn<
def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
def err_constexpr_main : Error<
"'main' is not allowed to be declared constexpr">;
-def err_main_template_decl : Error<"'main' cannot be a template">;
+def err_mainlike_template_decl : Error<"'%0' cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
InGroup<MainReturnType>;
@@ -447,6 +463,7 @@ def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
def warn_pragma_pack_pop_identifer_and_alignment : Warning<
"specifying both a name and alignment to 'pop' is undefined">;
def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">;
+def warn_pragma_ms_struct_failed : Warning<"#pramga ms_struct can not be used with dynamic classes or structures">, InGroup<IgnoredAttributes>;
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">;
@@ -472,7 +489,6 @@ def err_no_nsconstant_string_class : Error<
"cannot find interface declaration for %0">;
def err_recursive_superclass : Error<
"trying to recursively use %0 as superclass of %1">;
-def warn_previous_alias_decl : Warning<"previously declared alias is ignored">;
def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">;
def warn_undef_interface : Warning<"cannot find interface declaration for %0">;
def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">;
@@ -488,6 +504,9 @@ def warn_property_attribute : Warning<
"'%1' attribute on property %0 does not match the property inherited from %2">;
def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">;
+def warn_protocol_property_mismatch : Warning<
+ "property of type %0 was selected for synthesis">,
+ InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
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">;
@@ -499,6 +518,8 @@ def note_while_in_implementation : Note<
"detected while default synthesizing properties in class implementation">;
def note_class_declared : Note<
"class is declared here">;
+def note_receiver_class_declared : Note<
+ "receiver is instance of class declared here">;
def note_receiver_is_id : Note<
"receiver is treated with 'id' type for purpose of method lookup">;
def note_suppressed_class_declare : Note<
@@ -506,7 +527,7 @@ def note_suppressed_class_declare : Note<
def err_objc_root_class_subclass : Error<
"objc_root_class attribute may only be specified on a root class declaration">;
def warn_objc_root_class_missing : Warning<
- "class %0 defined without specifying a base class">,
+ "class %0 defined without specifying a base class">,
InGroup<ObjCRootClass>;
def note_objc_needs_superclass : Note<
"add a super class to fix this problem">;
@@ -645,12 +666,18 @@ def warn_objc_isa_assign : Warning<
def warn_objc_pointer_masking : Warning<
"bitmasking for introspection of Objective-C object pointers is strongly "
"discouraged">,
- InGroup<DiagGroup<"deprecated-objc-pointer-introspection">>;
+ InGroup<ObjCPointerIntrospect>;
+def warn_objc_pointer_masking_performSelector : Warning<warn_objc_pointer_masking.Text>,
+ InGroup<ObjCPointerIntrospectPerformSelector>;
def warn_objc_property_default_assign_on_object : Warning<
"default property attribute 'assign' not appropriate for non-GC object">,
InGroup<ObjCPropertyNoAttribute>;
def warn_property_attr_mismatch : Warning<
"property attribute in class extension does not match the primary class">;
+def warn_property_implicitly_mismatched : Warning <
+ "primary property declaration is implicitly strong while redeclaration "
+ "in class extension is weak">,
+ InGroup<DiagGroup<"objc-property-implicit-mismatch">>;
def warn_objc_property_copy_missing_on_block : Warning<
"'copy' attribute must be specified for the block property "
"when -fobjc-gc-only is specified">;
@@ -727,6 +754,8 @@ def error_category_property : Error<
"class implementation">;
def note_property_declare : Note<
"property declared here">;
+def note_protocol_property_declare : Note<
+ "it could also be property of type %0 declared here">;
def note_property_synthesize : Note<
"property synthesized here">;
def error_synthesize_category_decl : Error<
@@ -804,6 +833,9 @@ def error_dealloc_bad_result_type : Error<
"instead of %0">;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
+def warn_undeclared_selector_with_typo : Warning<
+ "undeclared selector %0; did you mean %1?">,
+ InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_implicit_atomic_property : Warning<
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
def note_auto_readonly_iboutlet_fixup_suggest : Note<
@@ -813,10 +845,12 @@ def warn_auto_readonly_iboutlet_property : Warning<
"not work correctly with 'nib' loader">,
InGroup<DiagGroup<"readonly-iboutlet-property">>;
def warn_auto_implicit_atomic_property : Warning<
- "property is assumed atomic when auto-synthesizing the property">,
+ "property is assumed atomic when auto-synthesizing the property">,
InGroup<ImplicitAtomic>, DefaultIgnore;
def warn_unimplemented_selector: Warning<
- "unimplemented selector %0">, InGroup<Selector>, DefaultIgnore;
+ "creating selector for nonexistent method %0">, InGroup<Selector>, DefaultIgnore;
+def warning_multiple_selectors: Warning<
+ "multiple selectors named %0 found">, InGroup<SelectorTypeMismatch>, DefaultIgnore;
def warn_unimplemented_protocol_method : Warning<
"method %0 in protocol not implemented">, InGroup<Protocol>;
@@ -834,7 +868,7 @@ def err_inline_namespace_mismatch : Error<
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def ext_enum_friend : ExtWarn<
- "enumeration type %0 cannot be a friend">;
+ "befriending enumeration type %0 is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_enum_friend : Warning<
"befriending enumeration type %0 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -865,7 +899,7 @@ def err_tagless_friend_type_template : Error<
def err_no_matching_local_friend : Error<
"no matching function found in local scope">;
def err_no_matching_local_friend_suggest : Error<
- "no matching function %0 found in local scope; did you mean %2?">;
+ "no matching function %0 found in local scope; did you mean %3?">;
def err_partial_specialization_friend : Error<
"partial specialization cannot be declared as a friend">;
def err_qualified_friend_def : Error<
@@ -876,6 +910,14 @@ def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
def err_using_decl_friend : Error<
"cannot befriend target of using declaration">;
+def warn_template_qualified_friend_unsupported : Warning<
+ "dependent nested name specifier '%0' for friend class declaration is "
+ "not supported; turning off access control for %1">,
+ InGroup<UnsupportedFriend>;
+def warn_template_qualified_friend_ignored : Warning<
+ "dependent nested name specifier '%0' for friend template declaration is "
+ "not supported; ignoring this friend declaration">,
+ InGroup<UnsupportedFriend>;
def err_invalid_member_in_interface : Error<
"%select{data member |non-public member function |static member function |"
@@ -886,12 +928,15 @@ def err_invalid_base_in_interface : Error<
"%select{'struct|non-public 'interface|'class}0 %1'">;
def err_abstract_type_in_decl : Error<
- "%select{return|parameter|variable|field|instance variable}0 type %1 is an abstract class">;
+ "%select{return|parameter|variable|field|instance variable|"
+ "synthesized instance variable}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
"allocating an object of abstract class type %0">;
def err_throw_abstract_type : Error<
"cannot throw an object of abstract type %0">;
def err_array_of_abstract_type : Error<"array of abstract class type %0">;
+def err_capture_of_abstract_type : Error<
+ "by-copy capture of value of abstract type %0">;
def err_multiple_final_overriders : Error<
"virtual function %q0 has more than one final overrider in %1">;
@@ -999,8 +1044,8 @@ def err_access_dtor_base :
Error<"base class %0 has %select{private|protected}1 destructor">,
AccessControl;
def err_access_dtor_vbase :
- Error<"inherited virtual base class %0 has "
- "%select{private|protected}1 destructor">,
+ Error<"inherited virtual base class %1 has "
+ "%select{private|protected}2 destructor">,
AccessControl;
def err_access_dtor_temp :
Error<"temporary of type %0 has %select{private|protected}1 destructor">,
@@ -1086,6 +1131,8 @@ def err_explicit_non_ctor_or_conv_function : Error<
def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">;
def err_static_out_of_line : Error<
"'static' can only be specified inside the class definition">;
+def err_storage_class_for_static_member : Error<
+ "static data member definition cannot specify a storage class">;
def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">;
def err_not_integral_type_bitfield : Error<
"bit-field %0 has non-integral type %1">;
@@ -1114,7 +1161,7 @@ def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
def note_member_synthesized_at : Note<
- "implicit default %select{constructor|copy constructor|move constructor|copy "
+ "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<
@@ -1172,6 +1219,9 @@ def ext_static_data_member_in_union : ExtWarn<
def warn_cxx98_compat_static_data_member_in_union : Warning<
"static data member %0 in union is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def ext_union_member_of_reference_type : ExtWarn<
+ "union member %0 has reference type %1, which is a Microsoft extension">,
+ InGroup<Microsoft>;
def err_union_member_of_reference_type : Error<
"union member %0 has reference type %1">;
def ext_anonymous_struct_union_qualified : Extension<
@@ -1261,7 +1311,9 @@ def err_destructor_template : Error<
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}0 "
+ "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 "
"%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"
@@ -1330,6 +1382,9 @@ def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
def warn_reference_field_is_uninit : Warning<
"reference %0 is not yet bound to a value when used here">,
InGroup<Uninitialized>;
+def note_uninit_in_this_constructor : Note<
+ "during field initialization in %select{this|the implicit default}0 "
+ "constructor">;
def warn_static_self_reference_in_init : Warning<
"static variable %0 is suspiciously used within its own initialization">,
InGroup<UninitializedStaticSelfInit>;
@@ -1348,7 +1403,10 @@ def warn_sometimes_uninit_var : Warning<
"%select{'%3' condition is %select{true|false}4|"
"'%3' loop %select{is entered|exits because its condition is false}4|"
"'%3' loop %select{condition is true|exits because its condition is false}4|"
- "switch %3 is taken}2">, InGroup<UninitializedSometimes>, DefaultIgnore;
+ "switch %3 is taken|"
+ "its declaration is reached|"
+ "%3 is called}2">,
+ InGroup<UninitializedSometimes>, DefaultIgnore;
def warn_maybe_uninit_var : Warning<
"variable %0 may be uninitialized when "
"%select{used here|captured by block}1">,
@@ -1425,11 +1483,14 @@ def err_illegal_decl_array_of_auto : Error<
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "'auto' not allowed %select{in function prototype|in non-static struct member"
+ "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype"
+ "|in non-static struct member"
"|in non-static union member|in non-static class member|in interface member"
"|in exception declaration|in template parameter|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
- "|in conversion function type|here}0">;
+ "|in conversion function type|here|in lambda parameter}1">;
+def err_auto_not_allowed_var_inst : Error<
+ "'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
"declaration of variable %0 with type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
@@ -1498,19 +1559,22 @@ def err_auto_fn_virtual : Error<
// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<
"only virtual member functions can be marked '%0'">;
+def override_keyword_hides_virtual_member_function : Error<
+ "non-virtual member function marked '%0' hides virtual member "
+ "%select{function|functions}1">;
def err_function_marked_override_not_overriding : Error<
"%0 marked 'override' but does not override any member functions">;
def err_class_marked_final_used_as_base : Error<
- "base %0 is marked 'final'">;
+ "base %0 is marked '%select{final|sealed}1'">;
def warn_abstract_final_class : Warning<
- "abstract class is marked 'final'">, InGroup<AbstractFinalClass>;
+ "abstract class is marked '%select{final|sealed}0'">, InGroup<AbstractFinalClass>;
// C++11 attributes
def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">;
// C++11 final
def err_final_function_overridden : Error<
- "declaration of %0 overrides a 'final' function">;
+ "declaration of %0 overrides a '%select{final|sealed}1' function">;
// C++11 scoped enumerations
def err_enum_invalid_underlying : Error<
@@ -1572,6 +1636,9 @@ def note_in_for_range: Note<
def err_for_range_invalid: Error<
"invalid range expression of type %0; no viable '%select{begin|end}1' "
"function available">;
+def err_range_on_array_parameter : Error<
+ "cannot build range expression with array function parameter %0 since "
+ "parameter with array type %1 is treated as pointer type %2">;
def err_for_range_dereference : Error<
"invalid range expression of type %0; did you mean to dereference it "
"with '*'?">;
@@ -1725,8 +1792,8 @@ def err_attribute_can_be_applied_only_to_symbol_declaration : Error<
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
def err_attribute_wrong_number_arguments : Error<
- "attribute %plural{0:takes no arguments|1:takes one argument|"
- ":requires exactly %0 arguments}0">;
+ "%0 attribute %plural{0:takes no arguments|1:takes one argument|"
+ ":requires exactly %1 arguments}1">;
def err_attribute_too_many_arguments : Error<
"attribute takes no more than %0 argument%s0">;
def err_suppress_autosynthesis : Error<
@@ -1734,13 +1801,11 @@ def err_suppress_autosynthesis : Error<
"to a class declaration">;
def err_attribute_too_few_arguments : Error<
"attribute takes at least %0 argument%s0">;
-def err_attribute_missing_parameter_name : Error<
- "attribute requires unquoted parameter">;
def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
def err_attribute_bad_neon_vector_size : Error<
"Neon vector size must be 64 or 128 bits">;
-def err_attribute_argument_not_int : Error<
- "'%0' attribute requires integer constant">;
+def err_attribute_unsupported : Error<
+ "%0 attribute is not supported for this target">;
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
def err_alignas_attribute_wrong_decl_type : Error<
@@ -1756,8 +1821,12 @@ def err_alignas_mismatch : Error<
"redeclaration has different alignment requirement (%1 vs %0)">;
def err_alignas_underaligned : Error<
"requested alignment is less than minimum alignment of %1 for type %0">;
-def err_attribute_first_argument_not_int_or_bool : Error<
- "%0 attribute first argument must be of int or bool type">;
+def err_attribute_argument_n_type : Error<
+ "%0 attribute requires parameter %1 to be %select{int or bool|an integer "
+ "constant|a string|an identifier}2">;
+def err_attribute_argument_type : Error<
+ "%0 attribute requires %select{int or bool|an integer "
+ "constant|a string|an identifier}1">;
def err_attribute_argument_outof_range : Error<
"init_priority attribute requires integer constant between "
"101 and 65535 inclusive">;
@@ -1766,26 +1835,20 @@ def err_init_priority_object_attr : Error<
"of objects of class type">;
def err_attribute_argument_vec_type_hint : Error<
"invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
-def err_attribute_argument_n_not_int : Error<
- "'%0' attribute requires parameter %1 to be an integer constant">;
-def err_attribute_argument_n_not_string : Error<
- "'%0' attribute requires parameter %1 to be a string">;
-def err_attribute_argument_n_not_identifier : Error<
- "'%0' attribute requires parameter %1 to be an identifier">;
def err_attribute_argument_out_of_bounds : Error<
"'%0' attribute parameter %1 is out of bounds">;
-def err_attribute_requires_objc_interface : Error<
- "attribute may only be applied to an Objective-C interface">;
def err_attribute_uuid_malformed_guid : Error<
"uuid attribute contains a malformed GUID">;
def warn_nonnull_pointers_only : Warning<
"nonnull attribute only applies to pointer arguments">;
def err_attribute_pointers_only : Error<
- "'%0' attribute only applies to pointer arguments">;
+ "%0 attribute only applies to pointer arguments">;
+def err_attribute_no_member_pointers : Error<
+ "%0 attribute cannot be used with pointers to members">;
def err_attribute_invalid_implicit_this_argument : Error<
"'%0' attribute is invalid for the implicit this argument">;
def err_ownership_type : Error<
- "%0 attribute only applies to %1 arguments">;
+ "%0 attribute only applies to %select{pointer|integer}1 arguments">;
def err_format_strftime_third_parameter : Error<
"strftime format attribute requires 3rd parameter to be 0">;
def err_format_attribute_requires_variadic : Error<
@@ -1795,12 +1858,14 @@ def err_format_attribute_result_not : Error<"function does not return %0">;
def err_format_attribute_implicit_this_format_string : Error<
"format attribute cannot specify the implicit this argument as the format "
"string">;
-def warn_unknown_method_family : Warning<"unrecognized method family">;
+def err_common_not_supported_cplusplus : Error<
+ "common attribute is not supported in C++">;
def err_init_method_bad_return_type : Error<
"init methods must return an object pointer type, not %0">;
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 : Error<
"can't convert between vector values of different size (%0 and %1)">;
def err_typecheck_ext_vector_not_typedef : Error<
@@ -1809,8 +1874,6 @@ def err_ext_vector_component_exceeds_length : Error<
"vector component access exceeds type %0">;
def err_ext_vector_component_name_illegal : Error<
"illegal vector component name '%0'">;
-def err_attribute_address_space_not_int : Error<
- "address space attribute requires an integer constant">;
def err_attribute_address_space_negative : Error<
"address space is negative">;
def err_attribute_address_space_too_high : Error<
@@ -1827,8 +1890,6 @@ def err_field_with_address_space : Error<
"field may not be qualified with an address space">;
def err_attr_objc_ownership_redundant : Error<
"the type %0 is already explicitly ownership-qualified">;
-def err_attribute_not_string : Error<
- "argument to %0 attribute was not a string literal">;
def err_undeclared_nsnumber : Error<
"NSNumber must be available to use Objective-C literals">;
def err_invalid_nsnumber_type : Error<
@@ -1862,9 +1923,15 @@ def warn_objc_literal_comparison : Warning<
"direct comparison of %select{an array literal|a dictionary literal|"
"a numeric literal|a boxed expression|}0 has undefined behavior">,
InGroup<ObjCLiteralComparison>;
+def warn_missing_atsign_prefix : Warning<
+ "string literal must be prefixed by '@' ">, InGroup<ObjCLiteralMissingAtSign>;
def warn_objc_string_literal_comparison : Warning<
"direct comparison of a string literal has undefined behavior">,
InGroup<ObjCStringComparison>;
+def warn_concatenated_nsarray_literal : Warning<
+ "concatenated NSString literal for an NSArray expression - "
+ "possibly missing a comma">,
+ InGroup<ObjCStringConcatenation>;
def note_objc_literal_comparison_isequal : Note<
"use 'isEqual:' instead">;
@@ -1948,8 +2015,10 @@ def warn_weak_identifier_undeclared : Warning<
"weak identifier %0 never declared">;
def err_attribute_weak_static : Error<
"weak declaration cannot have internal linkage">;
-def warn_attribute_weak_import_invalid_on_definition : Warning<
- "'weak_import' attribute cannot be specified on a definition">,
+def err_attribute_selectany_non_extern_data : Error<
+ "'selectany' can only be applied to data items with external linkage">;
+def warn_attribute_invalid_on_definition : Warning<
+ "'%0' attribute cannot be specified on a definition">,
InGroup<IgnoredAttributes>;
def err_attribute_weakref_not_static : Error<
"weakref declaration must have internal linkage">;
@@ -1959,6 +2028,12 @@ def err_attribute_weakref_without_alias : Error<
"weakref declaration of '%0' must also have an alias attribute">;
def err_alias_not_supported_on_darwin : Error <
"only weak aliases are supported on darwin">;
+def err_alias_to_undefined : Error<
+ "alias must point to a defined variable or function">;
+def err_duplicate_mangled_name : Error<
+ "definition with same mangled name as another definition">;
+def err_cyclic_alias : Error<
+ "alias definition is part of a cycle">;
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
@@ -1967,7 +2042,7 @@ def warn_attribute_wrong_decl_type : Warning<
"variables, functions and labels|fields and global variables|structs|"
"variables, functions and tag types|thread-local variables|"
"variables and fields|variables, data members and tag types|"
- "types and namespaces}1">,
+ "types and namespaces|Objective-C interfaces}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
@@ -1977,15 +2052,11 @@ def err_attribute_wrong_decl_type : Error<
"variables, functions and labels|fields and global variables|structs|"
"variables, functions and tag types|thread-local variables|"
"variables and fields|variables, data members and tag types|"
- "types and namespaces}1">;
-def warn_function_attribute_wrong_type : Warning<
- "'%0' only applies to function types; type here is %1">,
- InGroup<IgnoredAttributes>;
-def warn_pointer_attribute_wrong_type : Warning<
- "'%0' only applies to pointer types; type here is %1">,
- InGroup<IgnoredAttributes>;
-def warn_objc_object_attribute_wrong_type : Warning<
- "'%0' only applies to Objective-C object or block pointer types; type here is %1">,
+ "types and namespaces|Objective-C interfaces|"
+ "methods and properties|struct or union|struct, union or class}1">;
+def warn_type_attribute_wrong_type : Warning<
+ "'%0' only applies to %select{function|pointer|"
+ "Objective-C object or block pointer}1 types; type here is %2">,
InGroup<IgnoredAttributes>;
def warn_attribute_requires_functions_or_static_globals : Warning<
"%0 only applies to variables with static storage duration and functions">,
@@ -2007,6 +2078,9 @@ def err_cconv_knr : Error<
"function with no prototype cannot use %0 calling convention">;
def err_cconv_varargs : Error<
"variadic function cannot use %0 calling convention">;
+def warn_cconv_varargs : Warning<
+ "%0 calling convention ignored on variadic function">,
+ InGroup<IgnoredAttributes>;
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">;
@@ -2148,6 +2222,32 @@ def note_found_mutex_near_match : Note<"found near match '%0'">;
def warn_thread_safety_beta : Warning<
"Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore;
+// Consumed warnings
+def warn_use_in_invalid_state : Warning<
+ "invalid invocation of method '%0' on object '%1' while it is in the '%2' "
+ "state">, InGroup<Consumed>, DefaultIgnore;
+def warn_use_of_temp_in_invalid_state : Warning<
+ "invalid invocation of method '%0' on a temporary object while it is in the "
+ "'%1' state">, InGroup<Consumed>, DefaultIgnore;
+def warn_attr_on_unconsumable_class : Warning<
+ "consumed analysis attribute is attached to member of class '%0' which isn't "
+ "marked as consumable">, InGroup<Consumed>, DefaultIgnore;
+def warn_return_typestate_for_unconsumable_type : Warning<
+ "return state set for an unconsumable type '%0'">, InGroup<Consumed>,
+ DefaultIgnore;
+def warn_return_typestate_mismatch : Warning<
+ "return value not in expected state; expected '%0', observed '%1'">,
+ InGroup<Consumed>, DefaultIgnore;
+def warn_loop_state_mismatch : Warning<
+ "state of variable '%0' must match at the entry and exit of loop">,
+ InGroup<Consumed>, DefaultIgnore;
+def warn_param_return_typestate_mismatch : Warning<
+ "parameter '%0' not in expected state when the function returns: expected "
+ "'%1', observed '%2'">, InGroup<Consumed>, DefaultIgnore;
+def warn_param_typestate_mismatch : Warning<
+ "argument not in expected state; expected '%0', observed '%1'">,
+ InGroup<Consumed>, DefaultIgnore;
+
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
InGroup<Conversion>, DefaultIgnore;
@@ -2211,9 +2311,17 @@ def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
InGroup<CastAlign>, DefaultIgnore;
+// Separate between casts to void* and non-void* pointers.
+// Some APIs use (abuse) void* for something like a user context,
+// and often that value is an integer even if it isn't a pointer itself.
+// Having a separate warning flag allows users to control the warning
+// for their workflow.
def warn_int_to_pointer_cast : Warning<
"cast to %1 from smaller integer type %0">,
InGroup<IntToPointerCast>;
+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">,
@@ -2238,16 +2346,14 @@ def warn_transparent_union_attribute_zero_fields : Warning<
"transparent_union attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_attribute_type_not_supported : Warning<
- "'%0' attribute argument not supported: %1">,
+ "%0 attribute argument not supported: %1">,
InGroup<IgnoredAttributes>;
-def warn_attribute_unknown_visibility : Warning<"unknown visibility '%0'">,
+def warn_attribute_unknown_visibility : Warning<"unknown visibility %0">,
InGroup<IgnoredAttributes>;
def warn_attribute_protected_visibility :
Warning<"target does not support 'protected' visibility; using 'default'">,
InGroup<DiagGroup<"unsupported-visibility">>;
def err_mismatched_visibility: Error<"visibility does not match previous declaration">;
-def warn_attribute_unknown_endian : Warning<"unknown endian '%0'">,
- InGroup<IgnoredAttributes>;
def note_previous_attribute : Note<"previous attribute is here">;
def err_unknown_machine_mode : Error<"unknown machine mode %0">;
def err_unsupported_machine_mode : Error<"unsupported machine mode %0">;
@@ -2273,10 +2379,12 @@ def err_attribute_sentinel_less_than_zero : Error<
"'sentinel' parameter 1 less than zero">;
def err_attribute_sentinel_not_zero_or_one : Error<
"'sentinel' parameter 2 not 0 or 1">;
-def err_attribute_cleanup_arg_not_found : Error<
- "'cleanup' argument %0 not found">;
+def warn_cleanup_ext : Warning<
+ "GCC does not allow the 'cleanup' attribute argument to be anything other "
+ "than a simple identifier">,
+ InGroup<GccCompat>;
def err_attribute_cleanup_arg_not_function : Error<
- "'cleanup' argument %0 is not a function">;
+ "'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">;
def err_attribute_cleanup_func_must_take_one_arg : Error<
"'cleanup' function %0 must take 1 parameter">;
def err_attribute_cleanup_func_arg_incompatible_type : Error<
@@ -2297,10 +2405,15 @@ def warn_attribute_ibaction: Warning<
InGroup<IgnoredAttributes>;
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
+def err_iboutletcollection_builtintype : Error<
+ "type argument of iboutletcollection attribute cannot be a builtin type">;
def warn_iboutlet_object_type : Warning<
"%select{instance variable|property}2 with %0 attribute must "
- "be an object type (invalid %1)">,
- InGroup<DiagGroup<"invalid-iboutlet">>;
+ "be an object type (invalid %1)">, InGroup<ObjCInvalidIBOutletProperty>;
+def warn_iboutletcollection_property_assign : Warning<
+ "IBOutletCollection properties should be copy/strong and not assign">,
+ InGroup<ObjCInvalidIBOutletProperty>;
+
def err_attribute_overloadable_not_function : Error<
"'overloadable' attribute can only be applied to a function">;
def err_attribute_overloadable_missing : Error<
@@ -2311,7 +2424,7 @@ def note_attribute_overloadable_prev_overload : Note<
def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
def warn_ns_attribute_wrong_return_type : Warning<
- "%0 attribute only applies to %select{functions|methods}1 that "
+ "%0 attribute only applies to %select{functions|methods|properties}1 that "
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
InGroup<IgnoredAttributes>;
def warn_ns_attribute_wrong_parameter_type : Warning<
@@ -2326,6 +2439,18 @@ def note_protocol_decl : Note<
def err_ns_bridged_not_interface : Error<
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;
+
+// objc_bridge attribute diagnostics.
+def err_objc_bridge_not_id : Error<
+ "parameter of 'objc_bridge' attribute must be a single name of an Objective-C class">;
+def err_objc_cf_bridged_not_interface : Error<
+ "CF object of type %0 is bridged to '%1', which is not an Objective-C class">;
+def err_objc_ns_bridged_invalid_cfobject : Error<
+ "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">;
+def warn_objc_invalid_bridge : Warning<
+ "%0 bridges to %1, not %2">, InGroup<ObjCBridge>;
+def warn_objc_invalid_bridge_to_cf : Warning<
+ "%0 cannot bridge to %1">, InGroup<ObjCBridge>;
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
@@ -2366,8 +2491,8 @@ def err_param_default_argument_member_template_redecl : Error<
"of a %select{class template|class template partial specialization|nested "
"class in a template}0">;
def err_uninitialized_member_for_assign : Error<
- "cannot define the implicit default assignment operator for %0, because "
- "non-static %select{reference|const}1 member %2 can't use default "
+ "cannot define the implicit copy assignment operator for %0, because "
+ "non-static %select{reference|const}1 member %2 can't use copy "
"assignment operator">;
def err_uninitialized_member_in_ctor : Error<
"%select{|implicit default |inheriting }0constructor for %1 must explicitly "
@@ -2688,6 +2813,7 @@ def err_ovl_ambiguous_oper_unary : Error<
def err_ovl_ambiguous_oper_binary : Error<
"use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">;
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
+def note_assign_lhs_incomplete : Note<"type %0 is incomplete">;
def err_ovl_deleted_oper : Error<
"overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
def err_ovl_deleted_special_oper : Error<
@@ -2731,7 +2857,8 @@ def err_addr_ovl_no_qualifier : Error<
def err_ovl_no_viable_literal_operator : Error<
"no matching literal operator for call to %0"
"%select{| with argument of type %2| with arguments of types %2 and %3}1"
- "%select{| or 'const char *', and no matching literal operator template}4">;
+ "%select{| or 'const char *'}4"
+ "%select{|, and no matching literal operator template}5">;
// C++ Template Declarations
def err_template_param_shadow : Error<
@@ -2741,6 +2868,8 @@ def warn_template_export_unsupported : Warning<
"exported templates are unsupported">;
def err_template_outside_namespace_or_class_scope : Error<
"templates can only be declared in namespace or class scope">;
+def err_template_inside_local_class : Error<
+ "templates cannot be declared inside of a local class">;
def err_template_linkage : Error<"templates must have C++ linkage">;
def err_template_typedef : Error<"a typedef cannot be a template">;
def err_template_unnamed_class : Error<
@@ -2789,7 +2918,11 @@ def err_template_parameter_default_friend_template : Error<
def err_template_template_parm_no_parms : Error<
"template template parameter must have its own template parameters">;
-def err_template_variable : Error<"variable %0 declared as a template">;
+def ext_variable_template : ExtWarn<"variable templates are a C++1y extension">,
+ InGroup<CXX1y>;
+def warn_cxx11_compat_variable_template : Warning<
+ "variable templates are incompatible with C++ standards before C++1y">,
+ InGroup<CXXPre1yCompat>, DefaultIgnore;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
def err_template_member : Error<"member %0 declared as a template">;
@@ -2798,7 +2931,7 @@ def err_template_member_noparams : Error<
def err_template_tag_noparams : Error<
"extraneous 'template<>' in declaration of %0 %1">;
def err_template_decl_ref : Error<
- "cannot refer to class template %0 without a template argument list">;
+ "cannot refer to %select{class|variable}0 template %1 without a template argument list">;
// C++ Template Argument Lists
def err_template_missing_args : Error<
@@ -2879,9 +3012,6 @@ def err_template_arg_ref_bind_ignores_quals : Error<
"ignores qualifiers">;
def err_template_arg_not_decl_ref : Error<
"non-type template argument does not refer to any declaration">;
-def err_template_arg_not_object_or_func_form : Error<
- "non-type template argument does not directly refer to an object or "
- "function">;
def err_template_arg_not_address_of : Error<
"non-type template argument for template parameter of pointer type %0 must "
"have its address taken">;
@@ -2926,11 +3056,14 @@ 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_ms_deref_template_argument: ExtWarn<
+ "non-type template argument containing a dereference operation is a "
+ "Microsoft extension">, InGroup<Microsoft>;
// C++ template specialization
def err_template_spec_unknown_kind : Error<
"can only provide an explicit specialization for a class template, function "
- "template, or a member function, static data member, "
+ "template, variable template, or a member function, static data member, "
"%select{or member class|member class, or member enumeration}0 of a "
"class template">;
def note_specialized_entity : Note<
@@ -2942,29 +3075,35 @@ def err_template_spec_decl_class_scope : Error<
def err_template_spec_decl_friend : Error<
"cannot declare an explicit specialization in a friend">;
def err_template_spec_decl_out_of_scope_global : Error<
- "%select{class template|class template partial|function template|member "
- "function|static data member|member class|member enumeration}0 "
+ "%select{class template|class template partial|variable template|"
+ "variable template partial|function template|member function|"
+ "static data member|member class|member enumeration}0 "
"specialization of %1 must originally be declared in the global scope">;
def err_template_spec_decl_out_of_scope : Error<
- "%select{class template|class template partial|function template|member "
+ "%select{class template|class template partial|variable template|"
+ "variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 must originally be declared in namespace %2">;
def ext_template_spec_decl_out_of_scope : ExtWarn<
"first declaration of %select{class template|class template partial|"
+ "variable template|variable template partial|"
"function template|member function|static data member|member class|"
"member enumeration}0 specialization of %1 outside namespace %2 is a "
"C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning<
- "%select{class template|class template partial|function template|member "
+ "%select{class template|class template partial|variable template|"
+ "variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 outside namespace %2 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_template_spec_redecl_out_of_scope : Error<
- "%select{class template|class template partial|function template|member "
+ "%select{class template|class template partial|variable template|"
+ "variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 not in a namespace enclosing %2">;
def err_template_spec_redecl_global_scope : Error<
- "%select{class template|class template partial|function template|member "
+ "%select{class template|class template partial|variable template|"
+ "variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 must occur at global scope">;
def err_spec_member_not_instantiated : Error<
@@ -3029,12 +3168,12 @@ def err_dependent_typed_non_type_arg_in_partial_spec : Error<
"non-type template argument specializes a template parameter with "
"dependent type %0">;
def err_partial_spec_args_match_primary_template : Error<
- "class template partial specialization does not specialize any template "
- "argument; to %select{declare|define}0 the primary template, remove the "
- "template argument list">;
+ "%select{class|variable}0 template partial specialization does not "
+ "specialize any template argument; to %select{declare|define}1 the "
+ "primary template, remove the template argument list">;
def warn_partial_specs_not_deducible : Warning<
- "class template partial specialization contains "
- "%select{a template parameter|template parameters}0 that can not be "
+ "%select{class|variable}0 template partial specialization contains "
+ "%select{a template parameter|template parameters}1 that can not be "
"deduced; this partial specialization will never be used">;
def note_partial_spec_unused_parameter : Note<
"non-deducible template parameter %0">;
@@ -3047,6 +3186,14 @@ def note_prev_partial_spec_here : Note<
"previous declaration of class template partial specialization %0 is here">;
def err_partial_spec_fully_specialized : Error<
"partial specialization of %0 does not use any of its template parameters">;
+
+// C++ Variable Template Partial Specialization
+def err_var_partial_spec_redeclared : Error<
+ "variable template partial specialization %0 cannot be redefined">;
+def note_var_prev_partial_spec_here : Note<
+ "previous declaration of variable template partial specialization is here">;
+def err_var_spec_no_template : Error<
+ "no variable template matches%select{| partial}0 specialization">;
// C++ Function template specializations
def err_function_template_spec_no_match : Error<
@@ -3084,6 +3231,8 @@ def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">;
+def note_template_variable_def_here : Note<
+ "in instantiation of variable template specialization %q0 requested here">;
def note_template_enum_def_here : Note<
"in instantiation of enumeration %q0 requested here">;
def note_template_type_alias_instantiation_here : Note<
@@ -3160,8 +3309,8 @@ def err_explicit_instantiation_of_typedef : Error<
def err_explicit_instantiation_storage_class : Error<
"explicit instantiation cannot have a storage class">;
def err_explicit_instantiation_not_known : Error<
- "explicit instantiation of %0 does not refer to a function template, member "
- "function, member class, or static data member">;
+ "explicit instantiation of %0 does not refer to a function template, "
+ "variable template, member function, member class, or static data member">;
def note_explicit_instantiation_here : Note<
"explicit instantiation refers here">;
def err_explicit_instantiation_data_member_not_instantiated : Error<
@@ -3184,6 +3333,8 @@ def err_explicit_instantiation_constexpr : Error<
def ext_explicit_instantiation_without_qualified_id : Extension<
"qualifier in explicit instantiation of %q0 requires a template-id "
"(a typedef is not permitted)">;
+def err_explicit_instantiation_without_template_id : Error<
+ "explicit instantiation of %q0 must specify a template argument list">;
def err_explicit_instantiation_unqualified_wrong_namespace : Error<
"explicit instantiation of %q0 must occur in namespace %1">;
def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
@@ -3194,11 +3345,17 @@ def err_explicit_instantiation_undefined_member : Error<
"static data member}0 %1 of class template %2">;
def err_explicit_instantiation_undefined_func_template : Error<
"explicit instantiation of undefined function template %0">;
+def err_explicit_instantiation_undefined_var_template : Error<
+ "explicit instantiation of undefined variable template %q0">;
def err_explicit_instantiation_declaration_after_definition : Error<
"explicit instantiation declaration (with 'extern') follows explicit "
"instantiation definition (without 'extern')">;
def note_explicit_instantiation_definition_here : Note<
"explicit instantiation definition is here">;
+def err_invalid_var_template_spec_type : Error<"type %2 "
+ "of %select{explicit instantiation|explicit specialization|"
+ "partial specialization|redeclaration}0 of %1 does not match"
+ " expected type %3">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
@@ -3244,7 +3401,8 @@ def err_non_type_template_in_nested_name_specifier : Error<
def err_template_id_not_a_type : Error<
"template name refers to non-type template %0">;
def note_template_declared_here : Note<
- "%select{function template|class template|type alias template|template template parameter}0 "
+ "%select{function template|class template|variable template"
+ "|type alias template|template template parameter}0 "
"%1 declared here">;
def note_parameter_type : Note<
"parameter of type %0 is declared here">;
@@ -3350,6 +3508,10 @@ def note_unavailable_here : Note<
"%select{unavailable|deleted|deprecated}1 here">;
def note_implicitly_deleted : Note<
"explicitly defaulted function was implicitly deleted here">;
+def note_inherited_deleted_here : Note<
+ "deleted constructor was inherited here">;
+def note_cannot_inherit : Note<
+ "constructor cannot be inherited">;
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">,
InGroup<Sentinel>;
@@ -3367,10 +3529,14 @@ def warn_missing_variable_declarations : Warning<
"no previous extern declaration for non-static variable %0">,
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
def err_redefinition : Error<"redefinition of %0">;
+def err_alias_after_tentative :
+ Error<"alias definition of %0 after tentative definition">;
+def err_tentative_after_alias :
+ Error<"tentative definition of %0 after alias definition">;
def err_definition_of_implicitly_declared_member : Error<
"definition of implicitly declared %select{default constructor|copy "
"constructor|move constructor|copy assignment operator|move assignment "
- "operator|destructor}1">;
+ "operator|destructor|function}1">;
def err_definition_of_explicitly_defaulted_member : Error<
"definition of explicitly defaulted %select{default constructor|copy "
"constructor|move constructor|copy assignment operator|move assignment "
@@ -3444,6 +3610,14 @@ def err_static_non_static : Error<
"static declaration of %0 follows non-static declaration">;
def err_different_language_linkage : Error<
"declaration of %0 has a different language linkage">;
+def ext_retained_language_linkage : Extension<
+ "friend function %0 retaining previous language linkage is an extension">,
+ InGroup<DiagGroup<"retained-language-linkage">>;
+def err_extern_c_global_conflict : Error<
+ "declaration of %1 %select{with C language linkage|in global scope}0 "
+ "conflicts with declaration %select{in global scope|with C language linkage}0">;
+def note_extern_c_global_conflict : Note<
+ "declared %select{in global scope|with C language linkage}0 here">;
def warn_weak_import : Warning <
"an already-declared variable is made a weak_import declaration %0">;
def warn_static_non_static : ExtWarn<
@@ -3503,7 +3677,7 @@ def err_forward_ref_enum : Error<
def ext_ms_forward_ref_enum : Extension<
"forward references to 'enum' types are a Microsoft extension">, InGroup<Microsoft>;
def ext_forward_ref_enum_def : Extension<
- "redeclaration of already-defined enum %0 is a GNU extension">, InGroup<GNU>;
+ "redeclaration of already-defined enum %0 is a GNU extension">, InGroup<GNURedeclaredEnum>;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
@@ -3574,6 +3748,8 @@ def warn_typecheck_zero_static_array_size : Warning<
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
+def ext_aggregate_init_not_constant : Extension<
+ "initializer for aggregate is not a compile-time constant">, InGroup<C99>;
def err_local_cant_init : Error<
"'__local' variable cannot have an initializer">;
def err_block_extern_cant_init : Error<
@@ -3620,22 +3796,15 @@ def warn_cxx98_compat_ctor_list_init : Warning<
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
-def err_init_list_type_narrowing_sfinae : Error<
- "type %0 cannot be narrowed to %1 in initializer list">;
-def err_init_list_type_narrowing : ExtWarn<
+def ext_init_list_type_narrowing : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
- InGroup<CXX11Narrowing>, DefaultError;
-def err_init_list_variable_narrowing_sfinae : Error<
- "non-constant-expression cannot be narrowed from type %0 to %1 in "
- "initializer list">;
-def err_init_list_variable_narrowing : ExtWarn<
+ InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
+def ext_init_list_variable_narrowing : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
- "initializer list">, InGroup<CXX11Narrowing>, DefaultError;
-def err_init_list_constant_narrowing_sfinae : Error<
- "constant expression evaluates to %0 which cannot be narrowed to type %1">;
-def err_init_list_constant_narrowing : ExtWarn<
+ "initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
+def ext_init_list_constant_narrowing : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
- InGroup<CXX11Narrowing>, DefaultError;
+ InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def warn_init_list_type_narrowing : Warning<
"type %0 cannot be narrowed to %1 in initializer list in C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
@@ -3676,9 +3845,6 @@ def warn_anon_bitfield_width_exceeds_type_size : Warning<
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
InGroup<MissingBraces>, DefaultIgnore;
-def err_missing_braces : Error<
- "cannot omit braces around initialization of subobject when using direct "
- "list-initialization">;
def err_redefinition_of_label : Error<"redefinition of label %0">;
def err_undeclared_label_use : Error<"use of undeclared label %0">;
@@ -3778,10 +3944,16 @@ def err_field_declared_as_function : Error<"field %0 declared as a function">;
def err_field_incomplete : Error<"field has incomplete type %0">;
def ext_variable_sized_type_in_struct : ExtWarn<
"field %0 with variable sized type %1 not at the end of a struct or class is"
- " a GNU extension">, InGroup<GNU>;
-
-def err_flexible_array_empty_struct : Error<
- "flexible array %0 not allowed in otherwise empty struct">;
+ " a GNU extension">, InGroup<GNUVariableSizedTypeNotAtEnd>;
+
+def ext_c99_flexible_array_member : Extension<
+ "flexible array members are a C99 feature">, InGroup<C99>;
+def err_flexible_array_virtual_base : Error<
+ "flexible array member %0 not allowed in "
+ "%select{struct|interface|union|class|enum}1 which has a virtual base class">;
+def err_flexible_array_empty_aggregate : Error<
+ "flexible array member %0 not allowed in otherwise empty "
+ "%select{struct|interface|union|class|enum}1">;
def err_flexible_array_has_nonpod_type : Error<
"flexible array member %0 of non-POD element type %1">;
def ext_flexible_array_in_struct : Extension<
@@ -3796,15 +3968,17 @@ def ext_flexible_array_empty_aggregate_ms : Extension<
"flexible array member %0 in otherwise empty "
"%select{struct|interface|union|class|enum}1 is a Microsoft extension">,
InGroup<Microsoft>;
+def err_flexible_array_union : Error<
+ "flexible array member %0 in a union is not allowed">;
def ext_flexible_array_union_ms : Extension<
"flexible array member %0 in a union is a Microsoft extension">,
InGroup<Microsoft>;
def ext_flexible_array_empty_aggregate_gnu : Extension<
"flexible array member %0 in otherwise empty "
"%select{struct|interface|union|class|enum}1 is a GNU extension">,
- InGroup<GNU>;
+ InGroup<GNUEmptyStruct>;
def ext_flexible_array_union_gnu : Extension<
- "flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
+ "flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>;
let CategoryName = "ARC Semantic Issue" in {
@@ -3852,7 +4026,7 @@ def err_arc_objc_property_default_assign_on_object : Error<
def err_arc_illegal_selector : Error<
"ARC forbids use of %0 in a @selector">;
def err_arc_illegal_method_def : Error<
- "ARC forbids implementation of %0">;
+ "ARC forbids %select{implementation|synthesis}0 of %1">;
def warn_arc_strong_pointer_objc_pointer : Warning<
"method parameter of type %0 with no explicit ownership">,
InGroup<DiagGroup<"explicit-ownership-type">>, DefaultIgnore;
@@ -4053,6 +4227,9 @@ def ext_sizeof_alignof_void_type : Extension<
def err_sizeof_alignof_incomplete_type : Error<
"invalid application of '%select{sizeof|alignof|vec_step}0' to an "
"incomplete type %1">;
+def err_sizeof_alignof_function_type : Error<
+ "invalid application of '%select{sizeof|alignof|vec_step}0' to a "
+ "function type">;
def err_sizeof_alignof_bitfield : Error<
"invalid application of '%select{sizeof|alignof}0' to bit-field">;
def err_alignof_member_of_incomplete_type : Error<
@@ -4072,6 +4249,11 @@ def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">,
def warn_offsetof_non_standardlayout_type : ExtWarn<
"offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>;
def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
+def err_offsetof_field_of_virtual_base : Error<
+ "invalid application of 'offsetof' to a field of a virtual base">;
+def warn_sub_ptr_zero_size_types : Warning<
+ "subtraction of pointers to type %0 of zero size has undefined behavior">,
+ InGroup<PointerArith>;
def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
@@ -4139,7 +4321,10 @@ def warn_self_assignment : Warning<
def warn_string_plus_int : Warning<
"adding %0 to a string does not append to the string">,
InGroup<StringPlusInt>;
-def note_string_plus_int_silence : Note<
+def warn_string_plus_char : Warning<
+ "adding %0 to a string pointer does not append to the string">,
+ InGroup<StringPlusChar>;
+def note_string_plus_scalar_silence : Note<
"use array indexing to silence this warning">;
def warn_sizeof_array_param : Warning<
@@ -4189,6 +4374,10 @@ def err_typecheck_member_reference_arrow : Error<
"member reference type %0 is not a pointer">;
def err_typecheck_member_reference_suggestion : Error<
"member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">;
+def note_typecheck_member_reference_suggestion : Note<
+ "did you mean to use '.' instead?">;
+def note_member_reference_arrow_from_operator_arrow : Note<
+ "'->' applied to return value of the operator->() declared here">;
def err_typecheck_member_reference_type : Error<
"cannot refer to type member %0 in %1 with '%select{.|->}2'">;
def err_typecheck_member_reference_unknown : Error<
@@ -4215,20 +4404,28 @@ def note_enum_specialized_here : Note<
"enum %0 was explicitly specialized here">;
def err_member_redeclared : Error<"class member cannot be redeclared">;
+def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">,
+ InGroup<RedeclaredClassMember>;
def err_member_redeclared_in_instantiation : Error<
"multiple overloads of %0 instantiate to the same signature %1">;
def err_member_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error<
"out-of-line definition of %0 from class %1 without definition">;
-def err_member_def_does_not_match : Error<
- "out-of-line definition of %0 does not match any declaration in %1">;
+def err_member_decl_does_not_match : Error<
+ "out-of-line %select{declaration|definition}2 of %0 "
+ "does not match any declaration in %1">;
+def err_friend_decl_with_def_arg_must_be_def : Error<
+ "friend declaration specifying a default argument must be a definition">;
+def err_friend_decl_with_def_arg_redeclared : Error<
+ "friend declaration specifying a default argument must be the only declaration">;
def err_friend_decl_does_not_match : Error<
"friend declaration of %0 does not match any declaration in %1">;
-def err_member_def_does_not_match_suggest : Error<
- "out-of-line definition of %0 does not match any declaration in %1; "
- "did you mean %2?">;
+def err_member_decl_does_not_match_suggest : Error<
+ "out-of-line %select{declaration|definition}2 of %0 "
+ "does not match any declaration in %1; did you mean %3?">;
def err_member_def_does_not_match_ret_type : Error<
- "out-of-line definition of %q0 differs from the declaration in the return type">;
+ "return type of out-of-line definition of %q0 differs from "
+ "that in the declaration">;
def err_nonstatic_member_out_of_line : Error<
"non-static data member defined out-of-line">;
def err_qualified_typedef_declarator : Error<
@@ -4251,6 +4448,10 @@ def note_member_def_close_const_match : Note<
def note_member_def_close_param_match : Note<
"type of %ordinal0 parameter of member declaration does not match definition"
"%diff{ ($ vs $)|}1,2">;
+def note_local_decl_close_match : Note<"local declaration nearly matches">;
+def note_local_decl_close_param_match : Note<
+ "type of %ordinal0 parameter of local declaration does not match definition"
+ "%diff{ ($ vs $)|}1,2">;
def err_typecheck_ivar_variable_size : Error<
"instance variables must have a constant size">;
def err_ivar_reference_type : Error<
@@ -4266,13 +4467,13 @@ def err_typecheck_pointer_arith_void_type : Error<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to void">;
def err_typecheck_decl_incomplete_type : Error<
"variable has incomplete type %0">;
+def err_typecheck_decl_incomplete_type___float128 : Error<
+ "support for type '__float128' is not yet implemented">;
def ext_typecheck_decl_incomplete_type : ExtWarn<
"tentative definition of variable with internal linkage has incomplete non-array type %0">,
InGroup<DiagGroup<"tentative-definition-incomplete-type">>;
def err_tentative_def_incomplete_type : Error<
"tentative definition has type %0 that is never completed">;
-def err_tentative_def_incomplete_type_arr : Error<
- "tentative definition has array of type %0 that is never completed">;
def warn_tentative_incomplete_array : Warning<
"tentative array definition assumed to have one element">;
def err_typecheck_incomplete_array_needs_initializer : Error<
@@ -4280,7 +4481,13 @@ def err_typecheck_incomplete_array_needs_initializer : Error<
"or an initializer">;
def err_array_init_not_init_list : Error<
"array initializer must be an initializer "
- "list%select{| or string literal}0">;
+ "list%select{| or string literal| or wide string literal}0">;
+def err_array_init_narrow_string_into_wchar : Error<
+ "initializing wide char array with non-wide string literal">;
+def err_array_init_wide_string_into_char : Error<
+ "initializing char array with wide string literal">;
+def err_array_init_incompat_wide_string_into_wchar : Error<
+ "initializing wide char array with incompatible wide string literal">;
def err_array_init_different_type : Error<
"cannot initialize array %diff{of type $ with array of type $|"
"with different type of array}0,1">;
@@ -4290,13 +4497,16 @@ def err_array_init_non_constant_array : Error<
def ext_array_init_copy : Extension<
"initialization of an array "
"%diff{of type $ from a compound literal of type $|"
- "from a compound literal}0,1 is a GNU extension">, InGroup<GNU>;
+ "from a compound literal}0,1 is a GNU extension">, InGroup<GNUCompoundLiteralInitializer>;
// This is intentionally not disabled by -Wno-gnu.
def ext_array_init_parens : ExtWarn<
"parenthesized initialization of a member array is a GNU extension">,
InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError;
def warn_deprecated_string_literal_conversion : Warning<
- "conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>;
+ "conversion from string literal to %0 is deprecated">,
+ InGroup<CXX11CompatDeprecatedWritableStr>;
+def warn_deprecated_string_literal_conversion_c : Warning<
+ "dummy warning to enable -fconst-strings">, InGroup<DeprecatedWritableStr>, DefaultIgnore;
def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
@@ -4331,6 +4541,8 @@ def ext_typecheck_addrof_temporary : ExtWarn<
InGroup<DiagGroup<"address-of-temporary">>, DefaultError;
def err_typecheck_addrof_temporary : Error<
"taking the address of a temporary object of type %0">;
+def err_typecheck_addrof_dtor : Error<
+ "taking the address of a destructor">;
def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
def err_typecheck_indirection_requires_pointer : Error<
@@ -4405,6 +4617,14 @@ def warn_null_in_comparison_operation : Warning<
"%select{(%1 and NULL)|(NULL and %1)}0">,
InGroup<NullArithmetic>;
+def warn_logical_not_on_lhs_of_comparison : Warning<
+ "logical not is only applied to the left hand side of this comparison">,
+ InGroup<LogicalNotParentheses>;
+def note_logical_not_fix : Note<
+ "add parentheses after the '!' to evaluate the comparison first">;
+def note_logical_not_silence_with_parens : Note<
+ "add parentheses around left hand side expression to silence this warning">;
+
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a non-static member function">;
def err_this_static_member_func : Error<
@@ -4547,6 +4767,15 @@ def warn_instance_method_on_class_found : Warning<
def warn_inst_method_not_found : Warning<
"instance method %objcinstance0 not found (return type defaults to 'id')">,
InGroup<MethodAccess>;
+def warn_instance_method_not_found_with_typo : Warning<
+ "instance method %objcinstance0 not found (return type defaults to 'id')"
+ "; did you mean %objcinstance2?">, InGroup<MethodAccess>;
+def warn_class_method_not_found_with_typo : Warning<
+ "class method %objcclass0 not found (return type defaults to 'id')"
+ "; did you mean %objcclass2?">, InGroup<MethodAccess>;
+def error_method_not_found_with_typo : Error<
+ "%select{instance|class}1 method %0 not found "
+ "; did you mean %2?">;
def error_no_super_class_message : Error<
"no @interface declaration found in class messaging of %0">;
def error_root_class_cannot_use_super : Error<
@@ -4561,6 +4790,7 @@ def warn_bad_receiver_type : Warning<
"receiver type %0 is not 'id' or interface pointer, consider "
"casting it to 'id'">,InGroup<ObjCReceiver>;
def err_bad_receiver_type : Error<"bad receiver type %0">;
+def err_incomplete_receiver_type : Error<"incomplete receiver type %0">;
def err_unknown_receiver_suggest : Error<
"unknown receiver %0; did you mean %1?">;
def error_objc_throw_expects_object : Error<
@@ -4602,6 +4832,8 @@ def note_parameter_named_here : Note<
"passing argument to parameter %0 here">;
def note_parameter_here : Note<
"passing argument to parameter here">;
+def note_method_return_type_change : Note<
+ "compiler has implicitly changed method %0 return type">;
// C++ casts
// These messages adhere to the TryCast pattern: %0 is an int specifying the
@@ -4695,6 +4927,8 @@ def err_need_header_before_ms_uuidof : Error<
"you need to include <guiddef.h> before using the '__uuidof' operator">;
def err_uuidof_without_guid : Error<
"cannot call operator __uuidof on a type with no GUID">;
+def err_uuidof_with_multiple_guids : Error<
+ "cannot call operator __uuidof on a type with multiple GUIDs">;
def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">;
def err_static_illegal_in_new : Error<
"the 'static' modifier for the array size is not legal in new expressions">;
@@ -4744,13 +4978,17 @@ def err_default_init_const : Error<
def err_delete_operand : Error<"cannot delete expression of type %0">;
def ext_delete_void_ptr_operand : ExtWarn<
"cannot delete expression with pointer-to-'void' type %0">;
-def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
- "expression of type %0 to a pointer">;
+def err_ambiguous_delete_operand : Error<
+ "ambiguous conversion of delete expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behavior">,
InGroup<DiagGroup<"delete-incomplete">>;
def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
+def err_delete_explicit_conversion : Error<
+ "converting delete expression from type %0 to type %1 invokes an explicit "
+ "conversion function">;
+def note_delete_conversion : Note<"conversion to pointer type %0">;
def warn_delete_array_type : Warning<
"'delete' applied to a pointer-to-array type %0 treated as delete[]">;
def err_no_suitable_delete_member_function_found : Error<
@@ -4761,7 +4999,10 @@ def note_member_declared_here : Note<
"member %0 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">, InGroup<Deprecated>;
+ "incrementing expression of type bool is deprecated">,
+ InGroup<DeprecatedIncrementBool>;
+def err_increment_decrement_enum : Error<
+ "cannot %select{decrement|increment}0 expression of enum type %1">;
def err_catch_incomplete_ptr : Error<
"cannot catch pointer to incomplete type %0">;
def err_catch_incomplete_ref : Error<
@@ -4848,8 +5089,6 @@ let CategoryName = "Lambda Issue" in {
"duration">;
def err_this_capture : Error<
"'this' cannot be %select{implicitly |}0captured in this context">;
- def err_lambda_capture_block : Error<
- "__block variable %0 cannot be captured in a lambda expression">;
def err_lambda_capture_anonymous_var : Error<
"unnamed variable cannot be implicitly captured in a lambda expression">;
def err_lambda_capture_vm_type : Error<
@@ -4864,14 +5103,14 @@ let CategoryName = "Lambda Issue" in {
def note_lambda_decl : Note<"lambda expression begins here">;
def err_lambda_unevaluated_operand : Error<
"lambda expression in an unevaluated operand">;
+ def err_lambda_in_constant_expression : Error<
+ "a lambda expression may not appear inside of a constant expression">;
def err_lambda_return_init_list : Error<
"cannot deduce lambda return type from initializer list">;
def err_lambda_capture_default_arg : Error<
"lambda expression in default argument cannot capture any entity">;
def err_lambda_incomplete_result : Error<
"incomplete result type %0 in lambda expression">;
- def err_lambda_objc_object_result : Error<
- "non-pointer Objective-C class type %0 in lambda expression result">;
def err_noreturn_lambda_has_return_expr : Error<
"lambda declared 'noreturn' should not return">;
def warn_maybe_falloff_nonvoid_lambda : Warning<
@@ -4889,13 +5128,41 @@ let CategoryName = "Lambda Issue" in {
def note_lambda_to_block_conv : Note<
"implicit capture of lambda object due to conversion to block pointer "
"here">;
+
+ // C++1y lambda init-captures.
+ def warn_cxx11_compat_init_capture : Warning<
+ "initialized lambda captures are incompatible with C++ standards "
+ "before C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
+ def ext_init_capture : ExtWarn<
+ "initialized lambda captures are a C++1y extension">, InGroup<CXX1y>;
+ def err_init_capture_no_expression : Error<
+ "initializer missing for lambda capture %0">;
+ def err_init_capture_multiple_expressions : Error<
+ "initializer for lambda capture %0 contains multiple expressions">;
+ def err_init_capture_deduction_failure : Error<
+ "cannot deduce type for lambda capture %0 from initializer of type %2">;
+ def err_init_capture_deduction_failure_from_init_list : Error<
+ "cannot deduce type for lambda capture %0 from initializer list">;
}
def err_return_in_captured_stmt : Error<
"cannot return from %0">;
+def err_capture_block_variable : Error<
+ "__block variable %0 cannot be captured in a "
+ "%select{lambda expression|captured statement}1">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
+def err_operator_arrow_depth_exceeded : Error<
+ "use of 'operator->' on type %0 would invoke a sequence of more than %1 "
+ "'operator->' calls">;
+def note_operator_arrow_here : Note<
+ "'operator->' declared here produces an object of type %0">;
+def note_operator_arrows_suppressed : Note<
+ "(skipping %0 'operator->'%s0 in backtrace)">;
+def note_operator_arrow_depth : Note<
+ "use -foperator-arrow-depth=N to increase 'operator->' limit">;
+
def err_pseudo_dtor_base_not_scalar : Error<
"object expression of non-scalar type %0 cannot be used in a "
"pseudo-destructor expression">;
@@ -4926,6 +5193,8 @@ def err_typecheck_ambiguous_condition : Error<
"conversion %diff{from $ to $|between types}0,1 is ambiguous">;
def err_typecheck_nonviable_condition : Error<
"no viable conversion%diff{ from $ to $|}0,1">;
+def err_typecheck_nonviable_condition_incomplete : Error<
+ "no viable conversion%diff{ from $ to incomplete type $|}0,1">;
def err_typecheck_deleted_function : Error<
"conversion function %diff{from $ to $|between types}0,1 "
"invokes a deleted function">;
@@ -4939,11 +5208,15 @@ def err_invalid_declarator_global_scope : Error<
"definition or redeclaration of %0 cannot name the global scope">;
def err_invalid_declarator_in_function : Error<
"definition or redeclaration of %0 not allowed inside a function">;
+def err_invalid_declarator_in_block : Error<
+ "definition or redeclaration of %0 not allowed inside a block">;
def err_not_tag_in_scope : Error<
"no %select{struct|interface|union|class|enum}0 named %1 in %2">;
def err_no_typeid_with_fno_rtti : Error<
"cannot use typeid with -fno-rtti">;
+def err_no_dynamic_cast_with_fno_rtti : Error<
+ "cannot use dynamic_cast with -fno-rtti">;
def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
@@ -5243,6 +5516,14 @@ def err_typecheck_call_too_few_args_at_least_one : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"at least argument %1 must be specified">;
+def err_typecheck_call_too_few_args_suggest : Error<
+ "too few %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
+ "expected %1, have %2; did you mean %3?">;
+def err_typecheck_call_too_few_args_at_least_suggest : Error<
+ "too few %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
+ "expected at least %1, have %2; did you mean %3?">;
def err_typecheck_call_too_many_args : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
@@ -5259,6 +5540,19 @@ def err_typecheck_call_too_many_args_at_most_one : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at most single argument %1, have %2 arguments">;
+def err_typecheck_call_too_many_args_suggest : Error<
+ "too many %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
+ "expected %1, have %2; did you mean %3?">;
+def err_typecheck_call_too_many_args_at_most_suggest : Error<
+ "too many %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
+ "expected at most %1, have %2; did you mean %3?">;
+
+def err_arc_typecheck_convert_incompatible_pointer : Error<
+ "incompatible pointer types passing retainable parameter of type %0"
+ "to a CF function expecting %1 type">;
+
def note_callee_decl : Note<
"%0 declared here">;
def note_defined_here : Note<"%0 defined here">;
@@ -5268,28 +5562,38 @@ def err_builtin_fn_use : Error<"builtin functions must be directly called">;
def warn_call_wrong_number_of_arguments : Warning<
"too %select{few|many}0 arguments in call to %1">;
def err_atomic_builtin_must_be_pointer : Error<
- "first argument to atomic builtin must be a pointer (%0 invalid)">;
+ "address argument to atomic builtin must be a pointer (%0 invalid)">;
def err_atomic_builtin_must_be_pointer_intptr : Error<
- "first argument to atomic builtin must be a pointer to integer or pointer"
+ "address argument to atomic builtin must be a pointer to integer or pointer"
" (%0 invalid)">;
+def err_atomic_builtin_must_be_pointer_intfltptr : Error<
+ "address argument to atomic builtin must be a pointer to integer,"
+ " floating-point or pointer (%0 invalid)">;
def err_atomic_builtin_pointer_size : Error<
- "first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
+ "address argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
"type (%0 invalid)">;
+def err_atomic_exclusive_builtin_pointer_size : Error<
+ "address argument to load or store exclusive builtin must be a pointer to"
+ " 1,2,4 or 8 byte type (%0 invalid)">;
def err_atomic_op_needs_atomic : Error<
- "first argument to atomic operation must be a pointer to _Atomic "
+ "address argument to atomic operation must be a pointer to _Atomic "
"type (%0 invalid)">;
def err_atomic_op_needs_non_const_atomic : Error<
- "first argument to atomic operation must be a pointer to non-const _Atomic "
+ "address argument to atomic operation must be a pointer to non-const _Atomic "
"type (%0 invalid)">;
def err_atomic_op_needs_trivial_copy : Error<
- "first argument to atomic operation must be a pointer to a trivially-copyable"
- " type (%0 invalid)">;
+ "address argument to atomic operation must be a pointer to a "
+ "trivially-copyable type (%0 invalid)">;
def err_atomic_op_needs_atomic_int_or_ptr : Error<
- "first argument to atomic operation must be a pointer to %select{|atomic }0"
+ "address argument to atomic operation must be a pointer to %select{|atomic }0"
"integer or pointer (%1 invalid)">;
def err_atomic_op_bitwise_needs_atomic_int : Error<
- "first argument to bitwise atomic operation must be a pointer to "
+ "address argument to bitwise atomic operation must be a pointer to "
"%select{|atomic }0integer (%1 invalid)">;
+
+def err_atomic_load_store_uses_lib : Error<
+ "atomic %select{load|store}0 requires runtime support that is not "
+ "available for this target">;
def err_deleted_function_use : Error<"attempt to use a deleted function">;
@@ -5326,6 +5630,13 @@ def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning<
"passing object of trivial but non-POD type %0 through variadic"
" %select{function|block|method|constructor}1 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def err_cannot_pass_to_vararg : Error<
+ "cannot pass %select{expression of type %1|initializer list}0 to variadic "
+ "%select{function|block|method|constructor}2">;
+def err_cannot_pass_to_vararg_format : Error<
+ "cannot pass %select{expression of type %1|initializer list}0 to variadic "
+ "%select{function|block|method|constructor}2; expected type from format "
+ "string was %3">;
def err_typecheck_call_invalid_ordered_compare : Error<
"ordered compare requires two args of floating point type"
@@ -5345,7 +5656,7 @@ def ext_typecheck_cast_nonscalar : Extension<
"C99 forbids casting nonscalar type %0 to the same type">;
def ext_typecheck_cast_to_union : Extension<
"cast to union type is a GNU extension">,
- InGroup<GNU>;
+ InGroup<GNUUnionCast>;
def err_typecheck_cast_to_union_no_type : Error<
"cast to union type from type %0 not present in union">;
def err_cast_pointer_from_non_pointer_int : Error<
@@ -5415,6 +5726,16 @@ def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
def err_typecheck_cond_incompatible_operands_null : Error<
"non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">;
+def ext_empty_struct_union : Extension<
+ "empty %select{struct|union}0 is a GNU extension">, InGroup<GNUEmptyStruct>;
+def ext_no_named_members_in_struct_union : Extension<
+ "%select{struct|union}0 without named members is a GNU extension">, InGroup<GNUEmptyStruct>;
+def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0"
+ "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
+ InGroup<CXXCompat>, DefaultIgnore;
+def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0"
+ "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
+ InGroup<ExternCCompat>;
} // End of general sema category.
// inline asm.
@@ -5447,8 +5768,8 @@ let CategoryName = "Inline Assembly Issue" in {
"accepted due to -fheinous-gnu-extensions, but clang may remove support "
"for this in the future">;
def warn_asm_mismatched_size_modifier : Warning<
- "the value is truncated when put into register, "
- "use a modifier to specify the size">,
+ "value size does not match register size specified by the constraint "
+ "and modifier">,
InGroup<ASMOperandWidths>;
}
@@ -5483,6 +5804,10 @@ def warn_initializer_out_of_order : Warning<
"%select{field|base class}0 %1 will be initialized after "
"%select{field|base}2 %3">,
InGroup<Reorder>, DefaultIgnore;
+def warn_abstract_vbase_init_ignored : Warning<
+ "initializer for virtual base class %0 of abstract class %1 "
+ "will never be used">,
+ InGroup<DiagGroup<"abstract-vbase-init">>, DefaultIgnore;
def err_base_init_does_not_name_class : Error<
"constructor initializer %0 does not name a class">;
@@ -5516,7 +5841,7 @@ def err_in_class_initializer_references_def_ctor : Error<
def ext_in_class_initializer_non_constant : Extension<
"in-class initializer for static data member is not a constant expression; "
- "folding it to a constant is a GNU extension">, InGroup<GNU>;
+ "folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>;
def err_thread_dynamic_init : Error<
"initializer for thread-local variable must be a constant expression">;
@@ -5529,7 +5854,7 @@ def note_use_thread_local : Note<
def ext_anonymous_union : Extension<
"anonymous unions are a C11 extension">, InGroup<C11>;
def ext_gnu_anonymous_struct : Extension<
- "anonymous structs are a GNU extension">, InGroup<GNU>;
+ "anonymous structs are a GNU extension">, InGroup<GNUAnonymousStruct>;
def ext_c11_anonymous_struct : Extension<
"anonymous structs are a C11 extension">, InGroup<C11>;
def err_anonymous_union_not_static : Error<
@@ -5584,6 +5909,8 @@ def err_base_must_be_class : Error<"base specifier must name a class">;
def err_union_as_base_class : Error<"unions cannot be base classes">;
def err_circular_inheritance : Error<
"circular inheritance between %0 and %1">;
+def err_base_class_has_flexible_array_member : Error<
+ "base class %0 has a flexible array member">;
def err_incomplete_base_class : Error<"base class has incomplete type">;
def err_duplicate_base_class : Error<
"base class %0 specified more than once as a direct base class">;
@@ -5636,6 +5963,9 @@ def err_operator_new_delete_declared_in_namespace : Error<
"%0 cannot be declared inside a namespace">;
def err_operator_new_delete_declared_static : Error<
"%0 cannot be declared static in global scope">;
+def ext_operator_new_delete_declared_inline : ExtWarn<
+ "replacement function %0 cannot be declared 'inline'">,
+ InGroup<DiagGroup<"inline-new-delete">>;
def err_operator_new_delete_invalid_result_type : Error<
"%0 must return type %1">;
def err_operator_new_delete_dependent_result_type : Error<
@@ -5667,9 +5997,12 @@ def err_literal_operator_params : Error<
"parameter declaration for literal operator %0 is not valid">;
def err_literal_operator_extern_c : Error<
"literal operator must have C++ linkage">;
+def ext_string_literal_operator_template : ExtWarn<
+ "string literal operator templates are a GNU extension">,
+ InGroup<GNUStringLiteralOperatorTemplate>;
def warn_user_literal_reserved : Warning<
- "user-defined literal suffixes not starting with '_' are reserved; "
- "no literal will invoke this operator">,
+ "user-defined literal suffixes not starting with '_' are reserved"
+ "%select{; no literal will invoke this operator|}0">,
InGroup<UserDefinedLiterals>;
// C++ conversion functions
@@ -5718,7 +6051,7 @@ def err_defaulted_special_member_return_type : Error<
"return %1">;
def err_defaulted_special_member_quals : Error<
"an explicitly-defaulted %select{copy|move}0 assignment operator may not "
- "have 'const', 'constexpr' or 'volatile' qualifiers">;
+ "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">;
def err_defaulted_special_member_volatile_param : Error<
"the parameter for an explicitly-defaulted %select{<<ERROR>>|"
"copy constructor|move constructor|copy assignment operator|"
@@ -5740,11 +6073,19 @@ def err_incorrect_defaulted_exception_spec : Error<
"calculated one">;
def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %select{default constructor|copy constructor|"
- "move constructor}0 is not constexpr">;
+ "move constructor|copy assignment operator|move assignment operator}0 "
+ "is not constexpr">;
def err_out_of_line_default_deletes : Error<
"defaulting this %select{default constructor|copy constructor|move "
"constructor|copy assignment operator|move assignment operator|destructor}0 "
"would delete it after its first declaration">;
+def warn_vbase_moved_multiple_times : Warning<
+ "defaulted move assignment operator of %0 will move assign virtual base "
+ "class %1 multiple times">, InGroup<DiagGroup<"multiple-move-vbase">>;
+def note_vbase_moved_here : Note<
+ "%select{%1 is a virtual base class of base class %2 declared here|"
+ "virtual base class %1 declared here}0">;
+
def ext_implicit_exception_spec_mismatch : ExtWarn<
"function previously declared with an %select{explicit|implicit}0 exception "
"specification redeclared with an %select{implicit|explicit}0 exception "
@@ -5876,10 +6217,12 @@ def warn_init_ptr_member_to_parameter_addr : Warning<
"initializing pointer member %0 with the stack address of parameter %1">,
InGroup<DanglingField>;
def warn_bind_ref_member_to_temporary : Warning<
- "binding reference member %0 to a temporary value">,
+ "binding reference %select{|subobject of }1member %0 to a temporary value">,
InGroup<DanglingField>;
def note_ref_or_ptr_member_declared_here : Note<
"%select{reference|pointer}0 member declared here">;
+def note_ref_subobject_of_member_declared_here : Note<
+ "member with reference subobject declared here">;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
@@ -6023,7 +6366,7 @@ def warn_unreachable_default : Warning<
InGroup<CoveredSwitchDefault>, DefaultIgnore;
def warn_not_in_enum : Warning<"case value not in enumerated type %0">,
InGroup<Switch>;
-def warn_not_in_enum_assignement : Warning<"integer constant not in range "
+def warn_not_in_enum_assignment : Warning<"integer constant not in range "
"of enumerated type %0">, InGroup<DiagGroup<"assign-enum">>, DefaultIgnore;
def err_typecheck_statement_requires_scalar : Error<
"statement requires expression of scalar type (%0 invalid)">;
@@ -6057,7 +6400,9 @@ def note_empty_body_on_separate_line : Note<
def err_va_start_used_in_non_variadic_function : Error<
"'va_start' used in function with fixed args">;
def warn_second_parameter_of_va_start_not_last_named_argument : Warning<
- "second parameter of 'va_start' not last named argument">;
+ "second parameter of 'va_start' not last named argument">, InGroup<Varargs>;
+def warn_va_start_of_reference_type_is_undefined : Warning<
+ "'va_start' has undefined behavior with reference types">, InGroup<Varargs>;
def err_first_argument_to_va_arg_not_of_type_va_list : Error<
"first argument to 'va_arg' is of type %0 and not 'va_list'">;
def err_second_parameter_to_va_arg_incomplete: Error<
@@ -6072,7 +6417,7 @@ def warn_second_parameter_to_va_arg_ownership_qualified : Warning<
InGroup<NonPODVarargs>, DefaultError;
def warn_second_parameter_to_va_arg_never_compatible : Warning<
"second argument to 'va_arg' is of promotable type %0; this va_arg has "
- "undefined behavior because arguments will be promoted to %1">;
+ "undefined behavior because arguments will be promoted to %1">, InGroup<Varargs>;
def warn_return_missing_expr : Warning<
"non-void %select{function|method}1 %0 should return a value">, DefaultError,
@@ -6124,6 +6469,13 @@ def err_shufflevector_argument_too_large : Error<
"index for __builtin_shufflevector must be less than the total number "
"of vector elements">;
+def err_convertvector_non_vector : Error<
+ "first argument to __builtin_convertvector must be a vector">;
+def err_convertvector_non_vector_type : Error<
+ "second argument to __builtin_convertvector must be a vector type">;
+def err_convertvector_incompatible_vector : Error<
+ "first two arguments to __builtin_convertvector must have the same number of elements">;
+
def err_vector_incorrect_num_initializers : Error<
"%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
def err_altivec_empty_initializer : Error<"expected initializer">;
@@ -6153,6 +6505,8 @@ def err_selector_element_not_lvalue : Error<
"selector element is not a valid lvalue">;
def err_selector_element_type : Error<
"selector element type %0 is not a valid object">;
+def err_selector_element_const_type : Error<
+ "selector element of type %0 cannot be a constant l-value expression">;
def err_collection_expr_type : Error<
"the type %0 is not a pointer to a fast-enumerable object">;
def warn_collection_expr_type : Warning<
@@ -6161,6 +6515,9 @@ def warn_collection_expr_type : Warning<
def err_invalid_conversion_between_ext_vectors : Error<
"invalid conversion between ext-vector type %0 and %1">;
+def warn_duplicate_attribute_exact : Warning<
+ "attribute %0 is already applied">, InGroup<IgnoredAttributes>;
+
def warn_duplicate_attribute : Warning<
"attribute %0 is already applied with different parameters">,
InGroup<IgnoredAttributes>;
@@ -6231,19 +6588,19 @@ def warn_direct_ivar_access : Warning<"instance variable %0 is being "
// Spell-checking diagnostics
def err_unknown_type_or_class_name_suggest : Error<
- "unknown %select{type|class}2 name %0; did you mean %1?">;
+ "unknown %select{type|class}1 name %0; did you mean %2?">;
def err_unknown_typename_suggest : Error<
"unknown type name %0; did you mean %1?">;
def err_unknown_nested_typename_suggest : Error<
- "no type named %0 in %1; did you mean %2?">;
-def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %2?">;
+ "no type named %0 in %1; did you mean %select{|simply }2%3?">;
+def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">;
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_suggest : Error<"no template named %0; did you mean %1?">;
def err_no_member_template_suggest : Error<
- "no template named %0 in %1; did you mean %2?">;
+ "no template named %0 in %1; did you mean %select{|simply }2%3?">;
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?">;
@@ -6273,7 +6630,7 @@ def note_base_class_specified_here : Note<
def err_using_directive_suggest : Error<
"no namespace named %0; did you mean %1?">;
def err_using_directive_member_suggest : Error<
- "no namespace named %0 in %1; did you mean %2?">;
+ "no namespace named %0 in %1; did you mean %select{|simply }2%3?">;
def note_namespace_defined_here : Note<"namespace %0 defined here">;
def err_sizeof_pack_no_pack_name_suggest : Error<
"%0 does not refer to the name of a parameter pack; did you mean %1?">;
@@ -6308,16 +6665,22 @@ def err_invalid_astype_of_different_size : Error<
"invalid reinterpretation: sizes of %0 and %1 must match">;
def err_static_kernel : Error<
"kernel functions cannot be declared static">;
-def err_opencl_ptrptr_kernel_arg : Error<
- "kernel argument cannot be declared as a pointer to a pointer">;
+def err_opencl_ptrptr_kernel_param : Error<
+ "kernel parameter cannot be declared as a pointer to a pointer">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
def err_opencl_bitfields : Error<
"bitfields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
-def err_event_t_kernel_arg : Error<
- "the event_t type cannot be used to declare a kernel function argument">;
+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<
+ "%select{struct|union}0 kernel parameters may not contain pointers">;
+def note_within_field_of_type : Note<
+ "within field of type %0 declared here">;
+def note_illegal_field_declared_here : Note<
+ "field of illegal %select{type|pointer type}0 %1 declared here">;
def err_event_t_global_var : Error<
"the event_t type cannot be used to declare a program scope variable">;
def err_event_t_struct_field : Error<
@@ -6332,24 +6695,49 @@ def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_global_invalid_addr_space : Error<
"global variables must have a constant address space qualifier">;
-
+def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
+} // end of sema category
+
+let CategoryName = "OpenMP Issue" in {
// OpenMP support.
+def err_omp_expected_var_arg : Error<
+ "%0 is not a global variable, static local variable or static data member">;
def err_omp_expected_var_arg_suggest : Error<
- "%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">;
+ "%0 is not a global variable, static local variable or static data member; "
+ "did you mean %1">;
def err_omp_global_var_arg : Error<
"arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
def err_omp_ref_type_arg : Error<
"arguments of '#pragma omp %0' cannot be of reference type %1">;
def err_omp_var_scope : Error<
- "'#pragma omp %0' must appear in the scope of the %1 variable declaration">;
+ "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
def err_omp_var_used : Error<
- "'#pragma omp %0' must precede all references to variable %1">;
+ "'#pragma omp %0' must precede all references to variable %q1">;
def err_omp_var_thread_local : Error<
"variable %0 cannot be threadprivate because it is thread-local">;
-def err_omp_incomplete_type : Error<
- "a threadprivate variable must not have incomplete type %0">;
-
-} // end of sema category
+def err_omp_private_incomplete_type : Error<
+ "a private variable with incomplete type %0">;
+def err_omp_firstprivate_incomplete_type : Error<
+ "a firstprivate variable with incomplete type %0">;
+def err_omp_unexpected_clause_value : Error <
+ "expected %0 in OpenMP clause '%1'">;
+def err_omp_expected_var_name : Error <
+ "expected variable name">;
+def err_omp_required_method : Error <
+ "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">;
+def err_omp_clause_ref_type_arg : Error<
+ "arguments of OpenMP clause '%0' cannot be of reference type %1">;
+def err_omp_threadprivate_incomplete_type : Error<
+ "threadprivate variable with incomplete type %0">;
+def err_omp_no_dsa_for_variable : Error <
+ "variable %0 must have explicitly specified data sharing attributes">;
+def err_omp_wrong_dsa : Error<
+ "%0 variable cannot be %1">;
+def note_omp_explicit_dsa : Note <
+ "defined as %0">;
+def note_omp_predetermined_dsa : Note <
+ "predetermined as %0">;
+} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
// Objective-C related result type compatibility
@@ -6386,6 +6774,8 @@ def err_module_private_local : Error<
def err_module_private_local_class : Error<
"local %select{struct|interface|union|class|enum}0 cannot be declared "
"__module_private__">;
+def err_module_private_declaration : Error<
+ "declaration of %0 must be imported from module '%1' before it is required">;
def err_module_private_definition : Error<
"definition of %0 must be imported from module '%1' before it is required">;
}
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 1b45b10c1221..81509cc18821 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -14,7 +14,7 @@ def err_fe_unable_to_read_pch_file : Error<
def err_fe_not_a_pch_file : Error<
"input is not a PCH file: '%0'">;
def err_fe_pch_malformed : Error<
- "malformed or corrupted PCH file: '%0'">, DefaultFatal;
+ "malformed or corrupted AST file: '%0'">, DefaultFatal;
def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_file_modified : Error<
@@ -22,6 +22,8 @@ def err_fe_pch_file_modified : Error<
DefaultFatal;
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
+def note_module_cache_path : Note<
+ "after modifying system headers, please delete the module cache at '%0'">;
def err_pch_targetopt_mismatch : Error<
"PCH file was compiled for the %0 '%1' but the current translation "
@@ -65,4 +67,13 @@ def err_pch_pp_detailed_record : Error<
def err_not_a_pch_file : Error<
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
+
+def err_module_odr_violation_missing_decl : Error<
+ "%q0 from module '%1' is not present in definition of %q2"
+ "%select{ in module '%4'| provided earlier}3">, NoSFINAE;
+def note_module_odr_violation_no_possible_decls : Note<
+ "definition has no member %0">;
+def note_module_odr_violation_possible_decl : Note<
+ "declaration of %0 does not match">;
+
}
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 6d9e53b7eb0d..255eee3084b5 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/FileSystem.h"
// FIXME: Enhance libsystem to support inode and other fields in stat.
#include <sys/types.h>
@@ -35,7 +36,6 @@ struct stat;
namespace llvm {
class MemoryBuffer;
-namespace sys { class Path; }
}
namespace clang {
@@ -63,9 +63,9 @@ class FileEntry {
time_t ModTime; // Modification time of file.
const DirectoryEntry *Dir; // Directory file lives in.
unsigned UID; // A unique (small) ID for the file.
- dev_t Device; // ID for the device containing the file.
- ino_t Inode; // Inode number for the file.
- mode_t FileMode; // The file mode as returned by 'stat'.
+ llvm::sys::fs::UniqueID UniqueID;
+ bool IsNamedPipe;
+ bool InPCH;
/// FD - The file descriptor for the file entry if it is opened and owned
/// by the FileEntry. If not, this is set to -1.
@@ -73,10 +73,12 @@ class FileEntry {
friend class FileManager;
public:
- FileEntry(dev_t device, ino_t inode, mode_t m)
- : Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {}
+ FileEntry(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe, bool InPCH)
+ : Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH),
+ FD(-1) {}
// Add a default constructor for use with llvm::StringMap
- FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {}
+ FileEntry()
+ : Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false), FD(-1) {}
FileEntry(const FileEntry &FE) {
memcpy(this, &FE, sizeof(FE));
@@ -93,23 +95,22 @@ public:
const char *getName() const { return Name; }
off_t getSize() const { return Size; }
unsigned getUID() const { return UID; }
- ino_t getInode() const { return Inode; }
- dev_t getDevice() const { return Device; }
+ const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
+ bool isInPCH() const { return InPCH; }
time_t getModificationTime() const { return ModTime; }
- mode_t getFileMode() const { return FileMode; }
/// \brief Return the directory the file lives in.
const DirectoryEntry *getDir() const { return Dir; }
- bool operator<(const FileEntry &RHS) const {
- return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
- }
+ bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; }
/// \brief Check whether the file is a named pipe (and thus can't be opened by
/// the native FileManager methods).
- bool isNamedPipe() const;
+ bool isNamedPipe() const { return IsNamedPipe; }
};
+struct FileData;
+
/// \brief Implements support for file system lookup, file system caching,
/// and directory search management.
///
@@ -170,8 +171,8 @@ class FileManager : public RefCountedBase<FileManager> {
// Caching.
OwningPtr<FileSystemStatCache> StatCache;
- bool getStatValue(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor);
+ bool getStatValue(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor);
/// Add all ancestors of the given path (pointing to either a file
/// or a directory) as virtual directories.
@@ -244,7 +245,8 @@ public:
///
/// If the path is relative, it will be resolved against the WorkingDir of the
/// FileManager's FileSystemOptions.
- bool getNoncachedStatValue(StringRef Path, struct stat &StatBuf);
+ bool getNoncachedStatValue(StringRef Path,
+ llvm::sys::fs::file_status &Result);
/// \brief Remove the real file \p Entry from the cache.
void invalidateCache(const FileEntry *Entry);
diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h
index ff70373ffb06..23d82569437f 100644
--- a/include/clang/Basic/FileSystemStatCache.h
+++ b/include/clang/Basic/FileSystemStatCache.h
@@ -18,11 +18,21 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FileSystem.h"
#include <sys/stat.h>
#include <sys/types.h>
namespace clang {
+struct FileData {
+ uint64_t Size;
+ time_t ModTime;
+ llvm::sys::fs::UniqueID UniqueID;
+ bool IsDirectory;
+ bool IsNamedPipe;
+ bool InPCH;
+};
+
/// \brief Abstract interface for introducing a FileManager cache for 'stat'
/// system calls, which is used by precompiled and pretokenized headers to
/// improve performance.
@@ -49,10 +59,9 @@ public:
/// success for directories (not files). On a successful file lookup, the
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
- static bool get(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor, FileSystemStatCache *Cache);
-
-
+ static bool get(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor, FileSystemStatCache *Cache);
+
/// \brief Sets the next stat call cache in the chain of stat caches.
/// Takes ownership of the given stat cache.
void setNextStatCache(FileSystemStatCache *Cache) {
@@ -68,18 +77,18 @@ public:
FileSystemStatCache *takeNextStatCache() { return NextStatCache.take(); }
protected:
- virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) = 0;
+ virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) = 0;
- LookupResult statChained(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
+ LookupResult statChained(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
if (FileSystemStatCache *Next = getNextStatCache())
- return Next->getStat(Path, StatBuf, isFile, FileDescriptor);
-
+ return Next->getStat(Path, Data, isFile, FileDescriptor);
+
// If we hit the end of the list of stat caches to try, just compute and
// return it without a cache.
- return get(Path, StatBuf,
- isFile, FileDescriptor, 0) ? CacheMissing : CacheExists;
+ return get(Path, Data, isFile, FileDescriptor, 0) ? CacheMissing
+ : CacheExists;
}
};
@@ -89,16 +98,16 @@ protected:
class MemorizeStatCalls : public FileSystemStatCache {
public:
/// \brief The set of stat() calls that have been seen.
- llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
-
- typedef llvm::StringMap<struct stat, llvm::BumpPtrAllocator>::const_iterator
+ llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
+
+ typedef llvm::StringMap<FileData, llvm::BumpPtrAllocator>::const_iterator
iterator;
-
+
iterator begin() const { return StatCalls.begin(); }
iterator end() const { return StatCalls.end(); }
-
- virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor);
+
+ virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor);
};
} // end namespace clang
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index d4d53390bdb3..304ff364bfc9 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -19,6 +19,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
@@ -147,7 +148,7 @@ public:
return HadMacro;
}
- /// getTokenID - If this is a source-language token (e.g. 'for'), this API
+ /// If this is a source-language token (e.g. 'for'), this API
/// can be used to cause the lexer to map identifiers to source-language
/// tokens.
tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; }
@@ -183,8 +184,9 @@ public:
}
void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; }
- /// getBuiltinID - Return a value indicating whether this is a builtin
- /// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target.
+ /// \brief Return a value indicating whether this is a builtin function.
+ ///
+ /// 0 is not-built-in. 1 is builtin-for-some-nonprimary-target.
/// 2+ are specific builtin functions.
unsigned getBuiltinID() const {
if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS)
@@ -236,7 +238,7 @@ public:
RecomputeNeedsHandleIdentifier();
}
- /// isPoisoned - Return true if this token has been poisoned.
+ /// \brief Return true if this token has been poisoned.
bool isPoisoned() const { return IsPoisoned; }
/// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether
@@ -256,12 +258,14 @@ public:
T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }
void setFETokenInfo(void *T) { FETokenInfo = T; }
- /// isHandleIdentifierCase - Return true if the Preprocessor::HandleIdentifier
- /// must be called on a token of this identifier. If this returns false, we
- /// know that HandleIdentifier will not affect the token.
+ /// \brief Return true if the Preprocessor::HandleIdentifier must be called
+ /// on a token of this identifier.
+ ///
+ /// If this returns false, we know that HandleIdentifier will not affect
+ /// the token.
bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; }
- /// isFromAST - Return true if the identifier in its current state was loaded
+ /// \brief Return true if the identifier in its current state was loaded
/// from an AST file.
bool isFromAST() const { return IsFromAST; }
@@ -293,12 +297,10 @@ public:
RecomputeNeedsHandleIdentifier();
}
- /// \brief Determine whether this is the contextual keyword
- /// 'import'.
+ /// \brief Determine whether this is the contextual keyword \c import.
bool isModulesImport() const { return IsModulesImport; }
- /// \brief Set whether this identifier is the contextual keyword
- /// 'import'.
+ /// \brief Set whether this identifier is the contextual keyword \c import.
void setModulesImport(bool I) {
IsModulesImport = I;
if (I)
@@ -308,10 +310,9 @@ public:
}
private:
- /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does
- /// several special (but rare) things to identifiers of various sorts. For
- /// example, it changes the "for" keyword token from tok::identifier to
- /// tok::for.
+ /// The Preprocessor::HandleIdentifier does several special (but rare)
+ /// things to identifiers of various sorts. For example, it changes the
+ /// \c for keyword token from tok::identifier to tok::for.
///
/// This method is very tied to the definition of HandleIdentifier. Any
/// change to it should be reflected here.
@@ -323,9 +324,10 @@ private:
}
};
-/// \brief an RAII object for [un]poisoning an identifier
-/// within a certain scope. II is allowed to be null, in
-/// which case, objects of this type have no effect.
+/// \brief An RAII object for [un]poisoning an identifier within a scope.
+///
+/// \p II is allowed to be null, in which case objects of this type have
+/// no effect.
class PoisonIdentifierRAIIObject {
IdentifierInfo *const II;
const bool OldValue;
@@ -371,17 +373,16 @@ public:
virtual StringRef Next() = 0;
};
-/// IdentifierInfoLookup - An abstract class used by IdentifierTable that
-/// provides an interface for performing lookups from strings
-/// (const char *) to IdentiferInfo objects.
+/// \brief Provides lookups to, and iteration over, IdentiferInfo objects.
class IdentifierInfoLookup {
public:
virtual ~IdentifierInfoLookup();
- /// get - Return the identifier token info for the specified named identifier.
- /// Unlike the version in IdentifierTable, this returns a pointer instead
- /// of a reference. If the pointer is NULL then the IdentifierInfo cannot
- /// be found.
+ /// \brief Return the IdentifierInfo for the specified named identifier.
+ ///
+ /// Unlike the version in IdentifierTable, this returns a pointer instead
+ /// of a reference. If the pointer is null then the IdentifierInfo cannot
+ /// be found.
virtual IdentifierInfo* get(StringRef Name) = 0;
/// \brief Retrieve an iterator into the set of all identifiers
@@ -577,6 +578,19 @@ enum { ObjCMethodFamilyBitWidth = 4 };
/// \brief An invalid value of ObjCMethodFamily.
enum { InvalidObjCMethodFamily = (1 << ObjCMethodFamilyBitWidth) - 1 };
+/// \brief A family of Objective-C methods.
+///
+/// These are family of methods whose result type is initially 'id', but
+/// but are candidate for the result type to be changed to 'instancetype'.
+enum ObjCInstanceTypeFamily {
+ OIT_None,
+ OIT_Array,
+ OIT_Dictionary,
+ OIT_Singleton,
+ OIT_Init,
+ OIT_ReturnsSelf
+};
+
/// \brief Smart pointer class that efficiently represents Objective-C method
/// names.
///
@@ -697,6 +711,8 @@ public:
static Selector getTombstoneMarker() {
return Selector(uintptr_t(-2));
}
+
+ static ObjCInstanceTypeFamily getInstTypeMethodFamily(Selector sel);
};
/// \brief This table allows us to fully hide how we implement
@@ -725,13 +741,19 @@ public:
/// \brief Return the total amount of memory allocated for managing selectors.
size_t getTotalMemory() const;
- /// \brief Return the setter name for the given identifier.
+ /// \brief Return the default setter name for the given identifier.
+ ///
+ /// This is "set" + \p Name where the initial character of \p Name
+ /// has been capitalized.
+ static SmallString<64> constructSetterName(StringRef Name);
+
+ /// \brief Return the default setter selector for the given identifier.
///
/// This is "set" + \p Name where the initial character of \p Name
/// has been capitalized.
- static Selector constructSetterName(IdentifierTable &Idents,
- SelectorTable &SelTable,
- const IdentifierInfo *Name);
+ static Selector constructSetterSelector(IdentifierTable &Idents,
+ SelectorTable &SelTable,
+ const IdentifierInfo *Name);
};
/// DeclarationNameExtra - Common base of the MultiKeywordSelector,
diff --git a/include/clang/Basic/Lambda.h b/include/clang/Basic/Lambda.h
index b1ad6acda3b4..280ae94fedc5 100644
--- a/include/clang/Basic/Lambda.h
+++ b/include/clang/Basic/Lambda.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Defines several types used to describe C++ lambda expressions
+/// \brief Defines several types used to describe C++ lambda expressions
/// that are shared between the parser and AST.
///
//===----------------------------------------------------------------------===//
@@ -26,12 +26,15 @@ enum LambdaCaptureDefault {
LCD_ByRef
};
-/// \brief The different capture forms in a lambda introducer: 'this' or a
-/// copied or referenced variable.
+/// \brief The different capture forms in a lambda introducer
+///
+/// C++11 allows capture of \c this, or of local variables by copy or
+/// by reference. C++1y also allows "init-capture", where the initializer
+/// is an expression.
enum LambdaCaptureKind {
- LCK_This,
- LCK_ByCopy,
- LCK_ByRef
+ LCK_This, ///< Capturing the \c this pointer
+ LCK_ByCopy, ///< Capturing by copy (a.k.a., by value)
+ LCK_ByRef ///< Capturing by reference
};
} // end namespace clang
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index b17dfbc9b520..5a1025cba7ec 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -1,4 +1,4 @@
-//===--- LangOptions.def - Language option database --------------- C++ -*-===//
+//===--- LangOptions.def - Language option database -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines the language options. Users of this file must
-// define the LANGOPT macro to make use of this information.
+// define the LANGOPT macro to make use of this information.
// Optionally, the user may also define BENIGN_LANGOPT
// (for options that don't affect the construction of the AST in an
// incompatible way), ENUM_LANGOPT (for options that have enumeration,
@@ -52,11 +52,11 @@ LANGOPT(CPlusPlus11 , 1, 0, "C++0x")
LANGOPT(CPlusPlus1y , 1, 0, "C++1y")
LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
-BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
+BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
"Objective-C auto-synthesized properties")
-BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0,
+BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0,
"Encoding extended block type signature")
-BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1,
+BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1,
"Objective-C related result type inference")
LANGOPT(Trigraphs , 1, 0,"trigraphs")
LANGOPT(LineComment , 1, 0, "'//' comments")
@@ -85,6 +85,7 @@ LANGOPT(RTTI , 1, 1, "run-time type information")
LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout")
LANGOPT(Freestanding, 1, 0, "freestanding implementation")
LANGOPT(NoBuiltin , 1, 0, "disable builtin functions")
+LANGOPT(NoMathBuiltin , 1, 0, "disable math builtin functions")
BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers")
LANGOPT(POSIXThreads , 1, 0, "POSIX thread support")
@@ -93,10 +94,11 @@ BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations"
LANGOPT(MathErrno , 1, 1, "errno support for math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
LANGOPT(Modules , 1, 0, "modules extension to C")
+LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
-VALUE_LANGOPT(PackStruct , 32, 0,
+VALUE_LANGOPT(PackStruct , 32, 0,
"default struct packing maximum alignment")
VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level")
@@ -121,6 +123,7 @@ LANGOPT(CUDA , 1, 0, "CUDA")
LANGOPT(OpenMP , 1, 0, "OpenMP support")
LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
+LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions")
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")
@@ -140,31 +143,37 @@ 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")
LANGOPT(ObjCARCWeak , 1, 0, "__weak support in the ARC runtime")
+LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in legacy ObjectiveC runtime")
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
+ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
LANGOPT(MRTD , 1, 0, "-mrtd calling convention")
BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing")
LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime")
ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode")
-ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility,
+ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility,
"value symbol visibility")
-ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
+ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
"type symbol visibility")
-ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
+ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
"stack protector mode")
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
"signed integer overflow handling")
-BENIGN_LANGOPT(InstantiationDepth, 32, 256,
+BENIGN_LANGOPT(ArrowDepth, 32, 256,
+ "maximum number of operator->s to follow")
+BENIGN_LANGOPT(InstantiationDepth, 32, 256,
"maximum template instantiation depth")
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
"maximum constexpr call depth")
+BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576,
+ "maximum constexpr evaluation steps")
BENIGN_LANGOPT(BracketDepth, 32, 256,
"maximum bracket nesting depth")
-BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
+BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
"if non-zero, warn about parameter or return Warn if parameter/return value is larger in bytes than this setting. 0 is no check.")
-VALUE_LANGOPT(MSCVersion, 32, 0,
+VALUE_LANGOPT(MSCVersion, 32, 0,
"version of Microsoft Visual C/C++")
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 21ca7eb201c9..d4e8b4eb5bad 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -66,6 +66,8 @@ public:
SOB_Trapping // -ftrapv
};
+ enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off };
+
public:
clang::ObjCRuntime ObjCRuntime;
@@ -95,6 +97,11 @@ public:
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
+
+ bool isSubscriptPointerArithmetic() const {
+ return ObjCRuntime.isSubscriptPointerArithmetic() &&
+ !ObjCSubscriptingLegacyRuntime;
+ }
/// \brief Reset all of the options that are not considered when building a
/// module.
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
index 01b8db15f511..699620784ecd 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -37,6 +37,10 @@ enum Linkage {
/// point of view.
UniqueExternalLinkage,
+ /// \brief No linkage according to the standard, but is visible from other
+ /// translation units because of types defined in a inline function.
+ VisibleNoLinkage,
+
/// \brief External linkage, which indicates that the entity can
/// be referred to from other translation units.
ExternalLinkage
@@ -62,14 +66,40 @@ enum GVALinkage {
GVA_ExplicitTemplateInstantiation
};
-/// \brief Determine whether the given linkage is semantically external.
-inline bool isExternalLinkage(Linkage L) {
- return L == UniqueExternalLinkage || L == ExternalLinkage;
+inline bool isExternallyVisible(Linkage L) {
+ return L == ExternalLinkage || L == VisibleNoLinkage;
+}
+
+inline Linkage getFormalLinkage(Linkage L) {
+ if (L == UniqueExternalLinkage)
+ return ExternalLinkage;
+ if (L == VisibleNoLinkage)
+ return NoLinkage;
+ return L;
}
-/// \brief Compute the minimum linkage given two linages.
+inline bool isExternalFormalLinkage(Linkage L) {
+ return getFormalLinkage(L) == ExternalLinkage;
+}
+
+/// \brief Compute the minimum linkage given two linkages.
+///
+/// The linkage can be interpreted as a pair formed by the formal linkage and
+/// a boolean for external visibility. This is just what getFormalLinkage and
+/// isExternallyVisible return. We want the minimum of both components. The
+/// Linkage enum is defined in an order that makes this simple, we just need
+/// special cases for when VisibleNoLinkage would lose the visible bit and
+/// become NoLinkage.
inline Linkage minLinkage(Linkage L1, Linkage L2) {
- return L1 < L2? L1 : L2;
+ if (L2 == VisibleNoLinkage)
+ std::swap(L1, L2);
+ if (L1 == VisibleNoLinkage) {
+ if (L2 == InternalLinkage)
+ return NoLinkage;
+ if (L2 == UniqueExternalLinkage)
+ return NoLinkage;
+ }
+ return L1 < L2 ? L1 : L2;
}
} // end namespace clang
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index d2a43f0219e6..e8d774e1eb54 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_BASIC_MODULE_H
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SetVector.h"
@@ -37,6 +38,7 @@ class FileEntry;
class FileManager;
class LangOptions;
class TargetInfo;
+class IdentifierInfo;
/// \brief Describes the name of a module.
typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
@@ -75,19 +77,28 @@ private:
/// \brief top-level header filenames that aren't resolved to FileEntries yet.
std::vector<std::string> TopHeaderNames;
+ /// \brief Cache of modules visible to lookup in this module.
+ mutable llvm::DenseSet<const Module*> VisibleModulesCache;
+
public:
/// \brief The headers that are part of this module.
- SmallVector<const FileEntry *, 2> Headers;
+ SmallVector<const FileEntry *, 2> NormalHeaders;
/// \brief The headers that are explicitly excluded from this module.
SmallVector<const FileEntry *, 2> ExcludedHeaders;
+ /// \brief The headers that are private to this module.
+ llvm::SmallVector<const FileEntry *, 2> PrivateHeaders;
+
+ /// \brief An individual requirement: a feature name and a flag indicating
+ /// the required state of that feature.
+ typedef std::pair<std::string, bool> Requirement;
+
/// \brief The set of language features required to use this module.
///
- /// If any of these features is not present, the \c IsAvailable bit
- /// will be false to indicate that this (sub)module is not
- /// available.
- SmallVector<std::string, 2> Requires;
+ /// If any of these requirements are not available, the \c IsAvailable bit
+ /// will be false to indicate that this (sub)module is not available.
+ SmallVector<Requirement, 2> Requirements;
/// \brief Whether this module is available in the current
/// translation unit.
@@ -176,6 +187,12 @@ public:
/// \brief The set of export declarations that have yet to be resolved.
SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+ /// \brief The directly used modules.
+ SmallVector<Module *, 2> DirectUses;
+
+ /// \brief The set of use declarations that have yet to be resolved.
+ SmallVector<ModuleId, 2> UnresolvedDirectUses;
+
/// \brief A library or framework to link against when an entity from this
/// module is used.
struct LinkLibrary {
@@ -254,12 +271,12 @@ public:
///
/// \param Target The target options used for the current translation unit.
///
- /// \param Feature If this module is unavailable, this parameter
- /// will be set to one of the features that is required for use of
- /// this module (but is not available).
+ /// \param Req If this module is unavailable, this parameter
+ /// will be set to one of the requirements that is not met for use of
+ /// this module.
bool isAvailable(const LangOptions &LangOpts,
const TargetInfo &Target,
- StringRef &Feature) const;
+ Requirement &Req) const;
/// \brief Determine whether this module is a submodule.
bool isSubModule() const { return Parent != 0; }
@@ -353,12 +370,16 @@ public:
/// \param Feature The feature that is required by this module (and
/// its submodules).
///
+ /// \param RequiredState The required state of this feature: \c true
+ /// if it must be present, \c false if it must be absent.
+ ///
/// \param LangOpts The set of language options that will be used to
/// evaluate the availability of this feature.
///
/// \param Target The target options that will be used to evaluate the
/// availability of this feature.
- void addRequirement(StringRef Feature, const LangOptions &LangOpts,
+ void addRequirement(StringRef Feature, bool RequiredState,
+ const LangOptions &LangOpts,
const TargetInfo &Target);
/// \brief Find the submodule with the given name.
@@ -366,6 +387,14 @@ public:
/// \returns The submodule if found, or NULL otherwise.
Module *findSubmodule(StringRef Name) const;
+ /// \brief Determine whether the specified module would be visible to
+ /// a lookup at the end of this module.
+ bool isModuleVisible(const Module *M) const {
+ if (VisibleModulesCache.empty())
+ buildVisibleModulesCache();
+ return VisibleModulesCache.count(M);
+ }
+
typedef std::vector<Module *>::iterator submodule_iterator;
typedef std::vector<Module *>::const_iterator submodule_const_iterator;
@@ -374,7 +403,10 @@ public:
submodule_iterator submodule_end() { return SubModules.end(); }
submodule_const_iterator submodule_end() const { return SubModules.end(); }
- /// \brief Returns the exported modules based on the wildcard restrictions.
+ /// \brief Appends this module's list of exported modules to \p Exported.
+ ///
+ /// This provides a subset of immediately imported modules (the ones that are
+ /// directly exported), not the complete set of exported modules.
void getExportedModules(SmallVectorImpl<Module *> &Exported) const;
static StringRef getModuleInputBufferName() {
@@ -387,6 +419,9 @@ public:
/// \brief Dump the contents of this module to the given output stream.
void dump() const;
+
+private:
+ void buildVisibleModulesCache() const;
};
} // end namespace clang
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index 18ef64a31527..4c6449750373 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -79,7 +79,7 @@ public:
case GCC: return false;
case MacOSX: return true;
case GNUstep: return true;
- case ObjFW: return false;
+ case ObjFW: return true;
case iOS: return true;
}
llvm_unreachable("bad kind");
@@ -98,9 +98,8 @@ public:
Arch == llvm::Triple::x86 ||
Arch == llvm::Triple::x86_64)
return false;
- // Mac runtimes use legacy dispatch everywhere except x86-64
- } else if (isNeXTFamily() && isNonFragile())
- return Arch != llvm::Triple::x86_64;
+ }
+ // Mac runtimes use legacy dispatch everywhere now.
return true;
}
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index f968977f64bc..6d1a7b27b749 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
/// \file
-/// \brief This file defines the list of supported OpenMP directives and
+/// \brief This file defines the list of supported OpenMP directives and
/// clauses.
///
//===----------------------------------------------------------------------===//
@@ -15,9 +15,38 @@
#ifndef OPENMP_DIRECTIVE
# define OPENMP_DIRECTIVE(Name)
#endif
+#ifndef OPENMP_CLAUSE
+# define OPENMP_CLAUSE(Name, Class)
+#endif
+#ifndef OPENMP_PARALLEL_CLAUSE
+# define OPENMP_PARALLEL_CLAUSE(Name)
+#endif
+#ifndef OPENMP_DEFAULT_KIND
+# define OPENMP_DEFAULT_KIND(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
OPENMP_DIRECTIVE(parallel)
+OPENMP_DIRECTIVE(task)
+
+// OpenMP clauses.
+OPENMP_CLAUSE(default, OMPDefaultClause)
+OPENMP_CLAUSE(private, OMPPrivateClause)
+OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
+OPENMP_CLAUSE(shared, OMPSharedClause)
+
+// Clauses allowed for OpenMP directives.
+OPENMP_PARALLEL_CLAUSE(default)
+OPENMP_PARALLEL_CLAUSE(private)
+OPENMP_PARALLEL_CLAUSE(firstprivate)
+OPENMP_PARALLEL_CLAUSE(shared)
+
+// Static attributes for 'default' clause.
+OPENMP_DEFAULT_KIND(none)
+OPENMP_DEFAULT_KIND(shared)
+#undef OPENMP_DEFAULT_KIND
#undef OPENMP_DIRECTIVE
+#undef OPENMP_CLAUSE
+#undef OPENMP_PARALLEL_CLAUSE
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index c90e9a0a76d5..5b4573124f21 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -28,9 +28,37 @@ enum OpenMPDirectiveKind {
NUM_OPENMP_DIRECTIVES
};
+/// \brief OpenMP clauses.
+enum OpenMPClauseKind {
+ OMPC_unknown = 0,
+#define OPENMP_CLAUSE(Name, Class) \
+ OMPC_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_threadprivate,
+ NUM_OPENMP_CLAUSES
+};
+
+/// \brief OpenMP attributes for 'default' clause.
+enum OpenMPDefaultClauseKind {
+ OMPC_DEFAULT_unknown = 0,
+#define OPENMP_DEFAULT_KIND(Name) \
+ OMPC_DEFAULT_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ NUM_OPENMP_DEFAULT_KINDS
+};
+
OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str);
const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind);
+OpenMPClauseKind getOpenMPClauseKind(llvm::StringRef Str);
+const char *getOpenMPClauseName(OpenMPClauseKind Kind);
+
+unsigned getOpenMPSimpleClauseType(OpenMPClauseKind Kind, llvm::StringRef Str);
+const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type);
+
+bool isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind CKind);
+
}
#endif
diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h
index 108014faabe1..2ceab9cbab9d 100644
--- a/include/clang/Basic/OperatorKinds.h
+++ b/include/clang/Basic/OperatorKinds.h
@@ -30,7 +30,7 @@ enum OverloadedOperatorKind {
/// \brief Retrieve the spelling of the given overloaded operator, without
/// the preceding "operator" keyword.
const char *getOperatorSpelling(OverloadedOperatorKind Operator);
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 3f68160f69a6..dd29926fce73 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -368,6 +368,27 @@ public:
}
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const IdentifierInfo *II) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(II),
+ DiagnosticsEngine::ak_identifierinfo);
+ return PD;
+ }
+
+ // Adds a DeclContext to the diagnostic. The enable_if template magic is here
+ // so that we only match those arguments that are (statically) DeclContexts;
+ // other arguments that derive from DeclContext (e.g., RecordDecls) will not
+ // match.
+ template<typename T>
+ friend inline
+ typename llvm::enable_if<llvm::is_same<T, DeclContext>,
+ const PartialDiagnostic &>::type
+ operator<<(const PartialDiagnostic &PD, T *DC) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
+ DiagnosticsEngine::ak_declcontext);
+ return PD;
+ }
+
+ friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const SourceRange &R) {
PD.AddSourceRange(CharSourceRange::getTokenRange(R));
return PD;
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index 709ec8d0376f..c9b31a39aa55 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -54,13 +54,17 @@ SANITIZER("memory", Memory)
// ThreadSanitizer
SANITIZER("thread", Thread)
+// LeakSanitizer
+SANITIZER("leak", Leak)
+
// UndefinedBehaviorSanitizer
SANITIZER("alignment", Alignment)
+SANITIZER("array-bounds", ArrayBounds)
SANITIZER("bool", Bool)
-SANITIZER("bounds", Bounds)
SANITIZER("enum", Enum)
SANITIZER("float-cast-overflow", FloatCastOverflow)
SANITIZER("float-divide-by-zero", FloatDivideByZero)
+SANITIZER("function", Function)
SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
SANITIZER("null", Null)
SANITIZER("object-size", ObjectSize)
@@ -74,20 +78,23 @@ SANITIZER("vptr", Vptr)
// IntegerSanitizer
SANITIZER("unsigned-integer-overflow", UnsignedIntegerOverflow)
+// DataFlowSanitizer
+SANITIZER("dataflow", DataFlow)
+
// -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 | Bounds | Enum | FloatCastOverflow |
- FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
- Return | Shift | SignedIntegerOverflow | Unreachable |
- VLABound | Vptr)
+ Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
+ FloatDivideByZero | Function | IntegerDivideByZero | Null |
+ ObjectSize | Return | Shift | SignedIntegerOverflow |
+ Unreachable | VLABound | Vptr)
// -fsanitize=undefined-trap (and its alias -fcatch-undefined-behavior) includes
// all sanitizers included by -fsanitize=undefined, except those that require
// runtime support. This group is generally used in conjunction with the
// -fsanitize-undefined-trap-on-error flag.
SANITIZER_GROUP("undefined-trap", UndefinedTrap,
- Alignment | Bool | Bounds | Enum | FloatCastOverflow |
+ Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
Return | Shift | SignedIntegerOverflow | Unreachable |
VLABound)
@@ -96,5 +103,9 @@ SANITIZER_GROUP("integer", Integer,
SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
IntegerDivideByZero)
+// -fbounds-checking
+SANITIZER("local-bounds", LocalBounds)
+SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds)
+
#undef SANITIZER
#undef SANITIZER_GROUP
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 143beb67e0b7..10ae07b82498 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -89,7 +89,7 @@ class SourceLocation {
friend class SourceManager;
friend class ASTReader;
friend class ASTWriter;
- enum {
+ enum LLVM_ENUM_INT_TYPE(unsigned) {
MacroIDBit = 1U << 31
};
public:
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index f82b196929a3..6aab998bd898 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -1005,7 +1005,7 @@ public:
return SourceLocation();
unsigned FileOffset = Entry.getOffset();
- return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID) - 1);
+ return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID));
}
/// \brief Returns the include location if \p FID is a \#include'd file
@@ -1161,6 +1161,22 @@ public:
/// expansion but not the expansion of an argument to a function-like macro.
bool isMacroBodyExpansion(SourceLocation Loc) const;
+ /// \brief Returns true if the given MacroID location points at the beginning
+ /// of the immediate macro expansion.
+ ///
+ /// \param MacroBegin If non-null and function returns true, it is set to the
+ /// begin location of the immediate macro expansion.
+ bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc,
+ SourceLocation *MacroBegin = 0) const;
+
+ /// \brief Returns true if the given MacroID location points at the character
+ /// end of the immediate macro expansion.
+ ///
+ /// \param MacroEnd If non-null and function returns true, it is set to the
+ /// character end location of the immediate macro expansion.
+ bool isAtEndOfImmediateMacroExpansion(SourceLocation Loc,
+ SourceLocation *MacroEnd = 0) const;
+
/// \brief Returns true if \p Loc is inside the [\p Start, +\p Length)
/// chunk of the source location address space.
///
@@ -1276,14 +1292,28 @@ public:
PresumedLoc getPresumedLoc(SourceLocation Loc,
bool UseLineDirectives = true) const;
- /// \brief Returns true if both SourceLocations correspond to the same file.
- bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
+ /// \brief Returns whether the PresumedLoc for a given SourceLocation is
+ /// in the main file.
+ ///
+ /// This computes the "presumed" location for a SourceLocation, then checks
+ /// whether it came from a file other than the main file. This is different
+ /// from isWrittenInMainFile() because it takes line marker directives into
+ /// account.
+ bool isInMainFile(SourceLocation Loc) const;
+
+ /// \brief Returns true if the spelling locations for both SourceLocations
+ /// are part of the same file buffer.
+ ///
+ /// This check ignores line marker directives.
+ bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
return getFileID(Loc1) == getFileID(Loc2);
}
- /// \brief Returns true if the file of provided SourceLocation is the main
- /// file.
- bool isFromMainFile(SourceLocation Loc) const {
+ /// \brief Returns true if the spelling location for the given location
+ /// is in the main file buffer.
+ ///
+ /// This check ignores line marker directives.
+ bool isWrittenInMainFile(SourceLocation Loc) const {
return getFileID(Loc) == getMainFileID();
}
@@ -1467,7 +1497,7 @@ public:
if (Invalid) *Invalid = true;
return LocalSLocEntryTable[0];
}
- return getSLocEntryByID(FID.ID);
+ return getSLocEntryByID(FID.ID, Invalid);
}
unsigned getNextLocalOffset() const { return NextLocalOffset; }
@@ -1531,11 +1561,11 @@ private:
const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const;
/// \brief Get the entry with the given unwrapped FileID.
- const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
+ const SrcMgr::SLocEntry &getSLocEntryByID(int ID, bool *Invalid = 0) const {
assert(ID != -1 && "Using FileID sentinel value");
if (ID < 0)
- return getLoadedSLocEntryByID(ID);
- return getLocalSLocEntry(static_cast<unsigned>(ID));
+ return getLoadedSLocEntryByID(ID, Invalid);
+ return getLocalSLocEntry(static_cast<unsigned>(ID), Invalid);
}
const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID,
@@ -1570,6 +1600,14 @@ private:
return SLocOffset < getSLocEntryByID(FID.ID+1).getOffset();
}
+ /// \brief Returns the previous in-order FileID or an invalid FileID if there
+ /// is no previous one.
+ FileID getPreviousFileID(FileID FID) const;
+
+ /// \brief Returns the next in-order FileID or an invalid FileID if there is
+ /// no next one.
+ FileID getNextFileID(FileID FID) const;
+
/// \brief Create a new fileID for the specified ContentCache and
/// include position.
///
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index eb3fc659a874..0b8093969ae3 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -131,8 +131,8 @@ namespace clang {
OK_ObjCSubscript
};
- // \brief Describes the kind of template specialization that a
- // particular template specialization declaration represents.
+ /// \brief Describes the kind of template specialization that a
+ /// particular template specialization declaration represents.
enum TemplateSpecializationKind {
/// This template specialization was formed from a template-id but
/// has not yet been declared, defined, or instantiated.
@@ -154,6 +154,13 @@ namespace clang {
TSK_ExplicitInstantiationDefinition
};
+ /// \brief Determine whether this template specialization kind refers
+ /// to an instantiation of an entity (as opposed to a non-template or
+ /// an explicit specialization).
+ inline bool isTemplateInstantiation(TemplateSpecializationKind Kind) {
+ return Kind != TSK_Undeclared && Kind != TSK_ExplicitSpecialization;
+ }
+
/// \brief Thread storage-class-specifier.
enum ThreadStorageClassSpecifier {
TSCS_unspecified,
@@ -200,18 +207,40 @@ namespace clang {
/// \brief CallingConv - Specifies the calling convention that a function uses.
enum CallingConv {
- CC_Default,
CC_C, // __attribute__((cdecl))
CC_X86StdCall, // __attribute__((stdcall))
CC_X86FastCall, // __attribute__((fastcall))
CC_X86ThisCall, // __attribute__((thiscall))
CC_X86Pascal, // __attribute__((pascal))
+ CC_X86_64Win64, // __attribute__((ms_abi))
+ CC_X86_64SysV, // __attribute__((sysv_abi))
CC_AAPCS, // __attribute__((pcs("aapcs")))
CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp")))
CC_PnaclCall, // __attribute__((pnaclcall))
CC_IntelOclBicc // __attribute__((intel_ocl_bicc))
};
+ /// \brief Checks whether the given calling convention is callee-cleanup.
+ inline bool isCalleeCleanup(CallingConv CC) {
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86FastCall:
+ case CC_X86ThisCall:
+ case CC_X86Pascal:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// \brief The storage duration for an object (per C++ [basic.stc]).
+ enum StorageDuration {
+ SD_FullExpression, ///< Full-expression storage duration (for temporaries).
+ SD_Automatic, ///< Automatic storage duration (most local variables).
+ SD_Thread, ///< Thread storage duration.
+ SD_Static, ///< Static storage duration.
+ SD_Dynamic ///< Dynamic storage duration.
+ };
} // end namespace clang
#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index cbfce83c4b57..69851a9d5283 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -110,6 +110,7 @@ def CXXThrowExpr : DStmt<Expr>;
def CXXDefaultArgExpr : DStmt<Expr>;
def CXXDefaultInitExpr : DStmt<Expr>;
def CXXScalarValueInitExpr : DStmt<Expr>;
+def CXXStdInitializerListExpr : DStmt<Expr>;
def CXXNewExpr : DStmt<Expr>;
def CXXDeleteExpr : DStmt<Expr>;
def CXXPseudoDestructorExpr : DStmt<Expr>;
@@ -161,6 +162,7 @@ def CUDAKernelCallExpr : DStmt<CallExpr>;
// Clang Extensions.
def ShuffleVectorExpr : DStmt<Expr>;
+def ConvertVectorExpr : DStmt<Expr>;
def BlockExpr : DStmt<Expr>;
def OpaqueValueExpr : DStmt<Expr>;
@@ -174,3 +176,7 @@ def MSDependentExistsStmt : Stmt;
// OpenCL Extensions.
def AsTypeExpr : DStmt<Expr>;
+
+// OpenMP Directives.
+def OMPExecutableDirective : Stmt<1>;
+def OMPParallelDirective : DStmt<OMPExecutableDirective>;
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index 66e378fa9b45..ed3cc49fedb9 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -90,8 +90,10 @@ namespace clang {
Int64,
Poly8,
Poly16,
+ Poly64,
Float16,
- Float32
+ Float32,
+ Float64
};
NeonTypeFlags(unsigned F) : Flags(F) {}
@@ -130,6 +132,16 @@ namespace clang {
LastTSBuiltin
};
}
+
+ /// \brief XCore builtins
+ namespace XCore {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsXCore.def"
+ LastTSBuiltin
+ };
+ }
} // end namespace clang.
#endif
diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
index c9d28f8774b6..1590cca62337 100644
--- a/include/clang/Basic/TargetCXXABI.h
+++ b/include/clang/Basic/TargetCXXABI.h
@@ -131,24 +131,36 @@ public:
/// \brief Is the default C++ member function calling convention
/// the same as the default calling convention?
bool isMemberFunctionCCDefault() const {
- // Right now, this is always true for Microsoft.
+ // Right now, this is always false for Microsoft.
return !isMicrosoft();
}
+ /// Are temporary objects passed by value to a call destroyed by the callee?
+ /// This is a fundamental language change, since it implies that objects
+ /// passed by value do *not* live to the end of the full expression.
+ /// Temporaries passed to a function taking a const reference live to the end
+ /// of the full expression as usual. Both the caller and the callee must
+ /// have access to the destructor, while only the caller needs the
+ /// destructor if this is false.
+ bool isArgumentDestroyedByCallee() const {
+ return isMicrosoft();
+ }
+
/// \brief Does this ABI have different entrypoints for complete-object
/// and base-subobject constructors?
bool hasConstructorVariants() const {
return isItaniumFamily();
}
- /// \brief Does this ABI have different entrypoints for complete-object
- /// and base-subobject destructors?
- bool hasDestructorVariants() const {
+ /// \brief Does this ABI allow virtual bases to be primary base classes?
+ bool hasPrimaryVBases() const {
return isItaniumFamily();
}
- /// \brief Does this ABI allow virtual bases to be primary base classes?
- bool hasPrimaryVBases() const {
+ /// \brief Does this ABI use key functions? If so, class data such as the
+ /// vtable is emitted with strong linkage by the TU containing the key
+ /// function.
+ bool hasKeyFunctions() const {
return isItaniumFamily();
}
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 49b26ac8e372..047872dd4017 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -86,7 +86,7 @@ protected:
unsigned ComplexLongDoubleUsesFP2Ret : 1;
// TargetInfo Constructor. Default initializes all fields.
- TargetInfo(const std::string &T);
+ TargetInfo(const llvm::Triple &T);
public:
/// \brief Construct a target for the given options.
@@ -112,6 +112,8 @@ public:
///===---- Target Data Type Query Methods -------------------------------===//
enum IntType {
NoInt = 0,
+ SignedChar,
+ UnsignedChar,
SignedShort,
UnsignedShort,
SignedInt,
@@ -123,6 +125,7 @@ public:
};
enum RealType {
+ NoFloat = 255,
Float = 0,
Double,
LongDouble
@@ -199,6 +202,10 @@ protected:
/// zero length bitfield, regardless of the zero length bitfield type.
unsigned ZeroLengthBitfieldBoundary;
+ /// \brief Specify if mangling based on address space map should be used or
+ /// not for language specific address spaces
+ bool UseAddrSpaceMapMangling;
+
public:
IntType getSizeType() const { return SizeType; }
IntType getIntMaxType() const { return IntMaxType; }
@@ -220,6 +227,12 @@ public:
/// For example, SignedInt -> getIntWidth().
unsigned getTypeWidth(IntType T) const;
+ /// \brief Return integer type with specified width.
+ IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const;
+
+ /// \brief Return floating point type with specified width.
+ RealType getRealTypeByWidth(unsigned BitWidth) const;
+
/// \brief Return the alignment (in bits) of the specified integer type enum.
///
/// For example, SignedInt -> getIntAlign().
@@ -345,11 +358,11 @@ public:
unsigned getUnwindWordWidth() const { return getPointerWidth(0); }
/// \brief Return the "preferred" register width on this target.
- uint64_t getRegisterWidth() const {
+ unsigned getRegisterWidth() const {
// Currently we assume the register width on the target matches the pointer
// width, we can introduce a new variable for this if/when some target wants
// it.
- return LongWidth;
+ return PointerWidth;
}
/// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro,
@@ -422,6 +435,12 @@ public:
return ComplexLongDoubleUsesFP2Ret;
}
+ /// \brief Specify if mangling based on address space map should be used or
+ /// not for language specific address spaces
+ bool useAddressSpaceMapMangling() const {
+ return UseAddrSpaceMapMangling;
+ }
+
///===---- Other target property query methods --------------------------===//
/// \brief Appends the target-specific \#define values for this
@@ -653,6 +672,13 @@ public:
return false;
}
+ /// \brief Use the specified unit for FP math.
+ ///
+ /// \return False on error (invalid unit name).
+ virtual bool setFPMath(StringRef Name) {
+ return false;
+ }
+
/// \brief Use this specified C++ ABI.
///
/// \return False on error (invalid C++ ABI name).
@@ -672,12 +698,10 @@ public:
/// \brief Enable or disable a specific target feature;
/// the feature name must be valid.
- ///
- /// \return False on error (invalid feature name).
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ virtual void setFeatureEnabled(llvm::StringMap<bool> &Features,
StringRef Name,
bool Enabled) const {
- return false;
+ Features[Name] = Enabled;
}
/// \brief Perform initialization based on the user configured
@@ -687,7 +711,11 @@ public:
///
/// The target may modify the features list, to change which options are
/// passed onwards to the backend.
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ ///
+ /// \return False on error.
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ return true;
}
/// \brief Determine whether the given target has the given feature.
@@ -770,7 +798,6 @@ public:
default:
return CCCR_Warning;
case CC_C:
- case CC_Default:
return CCCR_OK;
}
}
@@ -790,7 +817,7 @@ protected:
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const = 0;
virtual void getGCCAddlRegNames(const AddlRegName *&Addl,
- unsigned &NumAddl) const {
+ unsigned &NumAddl) const {
Addl = 0;
NumAddl = 0;
}
diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h
index c2183fd29d56..9909182ab6dd 100644
--- a/include/clang/Basic/TargetOptions.h
+++ b/include/clang/Basic/TargetOptions.h
@@ -32,6 +32,9 @@ public:
/// If given, the name of the target CPU to generate code for.
std::string CPU;
+ /// If given, the unit to use for floating point math.
+ std::string FPMath;
+
/// If given, the name of the target ABI to use.
std::string ABI;
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
index dda011a54e18..c5218933a226 100644
--- a/include/clang/Basic/TemplateKinds.h
+++ b/include/clang/Basic/TemplateKinds.h
@@ -27,6 +27,9 @@ enum TemplateNameKind {
/// type. The template itself could be a class template, template
/// template parameter, or C++0x 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
/// function template depends on the context in which the template
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index bcf0f31dcbf6..6812cce2dbea 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -270,7 +270,7 @@ KEYWORD(__objc_no , KEYALL)
// C++ 2.11p1: Keywords.
KEYWORD(asm , KEYCXX|KEYGNU)
-KEYWORD(bool , BOOLSUPPORT|KEYALTIVEC)
+KEYWORD(bool , BOOLSUPPORT)
KEYWORD(catch , KEYCXX)
KEYWORD(class , KEYCXX)
KEYWORD(const_cast , KEYCXX)
@@ -278,7 +278,7 @@ KEYWORD(delete , KEYCXX)
KEYWORD(dynamic_cast , KEYCXX)
KEYWORD(explicit , KEYCXX)
KEYWORD(export , KEYCXX)
-KEYWORD(false , BOOLSUPPORT|KEYALTIVEC)
+KEYWORD(false , BOOLSUPPORT)
KEYWORD(friend , KEYCXX)
KEYWORD(mutable , KEYCXX)
KEYWORD(namespace , KEYCXX)
@@ -292,7 +292,7 @@ KEYWORD(static_cast , KEYCXX)
KEYWORD(template , KEYCXX)
KEYWORD(this , KEYCXX)
KEYWORD(throw , KEYCXX)
-KEYWORD(true , BOOLSUPPORT|KEYALTIVEC)
+KEYWORD(true , BOOLSUPPORT)
KEYWORD(try , KEYCXX)
KEYWORD(typename , KEYCXX)
KEYWORD(typeid , KEYCXX)
@@ -349,7 +349,10 @@ KEYWORD(__PRETTY_FUNCTION__ , KEYALL)
KEYWORD(typeof , KEYGNU)
// MS Extensions
+KEYWORD(__FUNCDNAME__ , KEYMS)
KEYWORD(L__FUNCTION__ , KEYMS)
+KEYWORD(__is_interface_class , KEYMS)
+KEYWORD(__is_sealed , KEYMS)
// GNU and MS Type Traits
KEYWORD(__has_nothrow_assign , KEYCXX)
@@ -370,7 +373,6 @@ KEYWORD(__is_convertible_to , KEYCXX)
KEYWORD(__is_empty , KEYCXX)
KEYWORD(__is_enum , KEYCXX)
KEYWORD(__is_final , KEYCXX)
-KEYWORD(__is_interface_class , KEYCXX)
// Tentative name - there's no implementation of std::is_literal_type yet.
KEYWORD(__is_literal , KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using
@@ -509,6 +511,8 @@ ALIAS("__volatile__" , volatile , KEYALL)
// Microsoft extensions which should be disabled in strict conformance mode
KEYWORD(__ptr64 , KEYMS)
KEYWORD(__ptr32 , KEYMS)
+KEYWORD(__sptr , KEYMS)
+KEYWORD(__uptr , KEYMS)
KEYWORD(__w64 , KEYMS)
KEYWORD(__uuidof , KEYMS | KEYBORLAND)
KEYWORD(__try , KEYMS | KEYBORLAND)
@@ -524,6 +528,7 @@ KEYWORD(__interface , KEYMS)
ALIAS("__int8" , char , KEYMS)
ALIAS("__int16" , short , KEYMS)
ALIAS("__int32" , int , KEYMS)
+ALIAS("__wchar_t" , wchar_t , KEYMS)
ALIAS("_asm" , asm , KEYMS)
ALIAS("_alignof" , __alignof , KEYMS)
ALIAS("__builtin_alignof", __alignof , KEYMS)
@@ -539,6 +544,7 @@ ALIAS("_declspec" , __declspec , KEYMS)
ALIAS("_pascal" , __pascal , KEYBORLAND)
// Clang Extensions.
+KEYWORD(__builtin_convertvector , KEYALL)
ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)
@@ -661,6 +667,9 @@ ANNOTATION(pragma_opencl_extension)
ANNOTATION(pragma_openmp)
ANNOTATION(pragma_openmp_end)
+// Annotation for module import translated from #include etc.
+ANNOTATION(module_include)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 16457969862a..fc53527188bb 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -57,6 +57,7 @@ namespace clang {
UTT_IsReference,
UTT_IsRvalueReference,
UTT_IsScalar,
+ UTT_IsSealed,
UTT_IsSigned,
UTT_IsStandardLayout,
UTT_IsTrivial,
diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h
index b623b94a6787..6ac52ed6b5e1 100644
--- a/include/clang/Basic/Visibility.h
+++ b/include/clang/Basic/Visibility.h
@@ -49,7 +49,7 @@ inline Visibility minVisibility(Visibility L, Visibility R) {
}
class LinkageInfo {
- uint8_t linkage_ : 2;
+ uint8_t linkage_ : 3;
uint8_t visibility_ : 2;
uint8_t explicit_ : 1;
@@ -89,6 +89,20 @@ public:
mergeLinkage(other.getLinkage());
}
+ void mergeExternalVisibility(Linkage L) {
+ Linkage ThisL = getLinkage();
+ if (!isExternallyVisible(L)) {
+ if (ThisL == VisibleNoLinkage)
+ ThisL = NoLinkage;
+ else if (ThisL == ExternalLinkage)
+ ThisL = UniqueExternalLinkage;
+ }
+ setLinkage(ThisL);
+ }
+ void mergeExternalVisibility(LinkageInfo Other) {
+ mergeExternalVisibility(Other.getLinkage());
+ }
+
/// Merge in the visibility 'newVis'.
void mergeVisibility(Visibility newVis, bool newExplicit) {
Visibility oldVis = getVisibility();
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 77bc797c5056..b918459f4e4a 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -18,31 +18,58 @@ def OP_NONE : Op;
def OP_UNAVAILABLE : Op;
def OP_ADD : Op;
def OP_ADDL : Op;
+def OP_ADDLHi : Op;
def OP_ADDW : Op;
+def OP_ADDWHi : Op;
def OP_SUB : Op;
def OP_SUBL : Op;
+def OP_SUBLHi : Op;
def OP_SUBW : Op;
+def OP_SUBWHi : Op;
def OP_MUL : Op;
def OP_MLA : Op;
def OP_MLAL : Op;
+def OP_MULLHi : Op;
+def OP_MULLHi_N : Op;
+def OP_MLALHi : Op;
+def OP_MLALHi_N : Op;
def OP_MLS : Op;
def OP_MLSL : Op;
+def OP_MLSLHi : Op;
+def OP_MLSLHi_N : Op;
def OP_MUL_N : Op;
def OP_MLA_N : Op;
def OP_MLS_N : Op;
+def OP_FMLA_N : Op;
+def OP_FMLS_N : Op;
def OP_MLAL_N : Op;
def OP_MLSL_N : Op;
def OP_MUL_LN: Op;
+def OP_MULX_LN: Op;
def OP_MULL_LN : Op;
+def OP_MULLHi_LN : Op;
def OP_MLA_LN: Op;
def OP_MLS_LN: Op;
def OP_MLAL_LN : Op;
+def OP_MLALHi_LN : Op;
def OP_MLSL_LN : Op;
+def OP_MLSLHi_LN : Op;
def OP_QDMULL_LN : Op;
+def OP_QDMULLHi_LN : Op;
def OP_QDMLAL_LN : Op;
+def OP_QDMLALHi_LN : Op;
def OP_QDMLSL_LN : Op;
+def OP_QDMLSLHi_LN : Op;
def OP_QDMULH_LN : Op;
def OP_QRDMULH_LN : Op;
+def OP_FMS_LN : Op;
+def OP_FMS_LNQ : Op;
+def OP_TRN1 : Op;
+def OP_ZIP1 : Op;
+def OP_UZP1 : Op;
+def OP_TRN2 : Op;
+def OP_ZIP2 : Op;
+def OP_UZP2 : Op;
def OP_EQ : Op;
def OP_GE : Op;
def OP_LE : Op;
@@ -65,10 +92,49 @@ def OP_SEL : Op;
def OP_REV64 : Op;
def OP_REV32 : Op;
def OP_REV16 : Op;
+def OP_XTN : Op;
+def OP_SQXTUN : Op;
+def OP_QXTN : Op;
+def OP_VCVT_NA_HI : Op;
+def OP_VCVT_EX_HI : Op;
+def OP_VCVTX_HI : Op;
def OP_REINT : Op;
+def OP_ADDHNHi : Op;
+def OP_RADDHNHi : Op;
+def OP_SUBHNHi : Op;
+def OP_RSUBHNHi : Op;
def OP_ABDL : Op;
+def OP_ABDLHi : Op;
def OP_ABA : Op;
def OP_ABAL : Op;
+def OP_ABALHi : Op;
+def OP_QDMULLHi : Op;
+def OP_QDMULLHi_N : Op;
+def OP_QDMLALHi : Op;
+def OP_QDMLALHi_N : Op;
+def OP_QDMLSLHi : Op;
+def OP_QDMLSLHi_N : Op;
+def OP_DIV : Op;
+def OP_LONG_HI : Op;
+def OP_NARROW_HI : Op;
+def OP_MOVL_HI : Op;
+def OP_COPY_LN : Op;
+def OP_COPYQ_LN : Op;
+def OP_COPY_LNQ : Op;
+def OP_SCALAR_MUL_LN : Op;
+def OP_SCALAR_MUL_LNQ : Op;
+def OP_SCALAR_MULX_LN : Op;
+def OP_SCALAR_MULX_LNQ : Op;
+def OP_SCALAR_VMULX_LN : Op;
+def OP_SCALAR_VMULX_LNQ : Op;
+def OP_SCALAR_QDMULL_LN : Op;
+def OP_SCALAR_QDMULL_LNQ : Op;
+def OP_SCALAR_QDMULH_LN : Op;
+def OP_SCALAR_QDMULH_LNQ : Op;
+def OP_SCALAR_QRDMULH_LN : Op;
+def OP_SCALAR_QRDMULH_LNQ : Op;
+def OP_SCALAR_GET_LN : Op;
+def OP_SCALAR_SET_LN : Op;
class Inst <string n, string p, string t, Op o> {
string Name = n;
@@ -76,7 +142,11 @@ class Inst <string n, string p, string t, Op o> {
string Types = t;
Op Operand = o;
bit isShift = 0;
+ bit isScalarShift = 0;
+ bit isScalarNarrowShift = 0;
bit isVCVT_N = 0;
+ bit isA64 = 0;
+ bit isCrypto = 0;
// Certain intrinsics have different names than their representative
// instructions. This field allows us to handle this correctly when we
@@ -123,18 +193,29 @@ class NoTestOpInst<string n, string p, string t, Op o> : Inst<n, p, t, o> {}
// x: signed integer (int/float args)
// u: unsigned integer (int/float args)
// f: float (int args)
+// F: double (int args)
// d: default
// g: default, ignore 'Q' size modifier.
+// j: default, force 'Q' size modifier.
// w: double width elements, same num elts
// n: double width elements, half num elts
// h: half width elements, double num elts
+// q: half width elements, quad num elts
// e: half width elements, double num elts, unsigned
+// m: half width elements, same num elts
// i: constant int
// l: constant uint64
// s: scalar of element type
+// z: scalar of half width element type, signed
+// r: scalar of double width element type, signed
// a: scalar of element type (splat to vector type)
+// b: scalar of unsigned integer/long type (int/float args)
+// $: scalar of signed integer/long type (int/float args)
+// y: scalar of float
+// o: scalar of double
// k: default elt width, double num elts
-// #: array of default vectors
+// 2,3,4: array of default vectors
+// B,C,D: array of default elts, force 'Q' size modifier.
// p: pointer type
// c: const pointer type
@@ -145,10 +226,13 @@ class NoTestOpInst<string n, string p, string t, Op o> : Inst<n, p, t, o> {}
// l: long
// f: float
// h: half-float
+// d: double
// size modifiers:
+// S: scalar, only used for function mangling.
// U: unsigned
// Q: 128b
+// H: 128b without mangling 'q'
// P: polynomial
////////////////////////////////////////////////////////////////////////////////
@@ -206,7 +290,7 @@ let InstName = "vacgt" in {
def VCAGT : IInst<"vcagt", "udd", "fQf">;
def VCALT : IInst<"vcalt", "udd", "fQf">;
}
-def VTST : WInst<"vtst", "udd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc">;
+def VTST : WInst<"vtst", "udd", "csiUcUsUiPcPsQcQsQiQUcQUsQUiQPcQPs">;
////////////////////////////////////////////////////////////////////////////////
// E.3.5 Absolute Difference
@@ -452,3 +536,803 @@ def VREINTERPRET
// Vector fused multiply-add operations
def VFMA : SInst<"vfma", "dddd", "fQf">;
+
+////////////////////////////////////////////////////////////////////////////////
+// AArch64 Intrinsics
+
+let isA64 = 1 in {
+
+////////////////////////////////////////////////////////////////////////////////
+// Load/Store
+// With additional QUl, Ql, d, Qd, Pl, QPl type.
+def LD1 : WInst<"vld1", "dc",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def LD2 : WInst<"vld2", "2c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def LD3 : WInst<"vld3", "3c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def LD4 : WInst<"vld4", "4c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def ST1 : WInst<"vst1", "vpd",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def ST2 : WInst<"vst2", "vp2",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def ST3 : WInst<"vst3", "vp3",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+def ST4 : WInst<"vst4", "vp4",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsUcUsUiUlcsilhfdPcPsPlQPl">;
+
+def LD1_X2 : WInst<"vld1_x2", "2c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD3_x3 : WInst<"vld1_x3", "3c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD4_x4 : WInst<"vld1_x4", "4c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+
+def ST1_X2 : WInst<"vst1_x2", "vp2",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST1_X3 : WInst<"vst1_x3", "vp3",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST1_X4 : WInst<"vst1_x4", "vp4",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+
+// With additional QUl, Ql, d, Qd, Pl, QPl type.
+def LD1_LANE : WInst<"vld1_lane", "dcdi",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD2_LANE : WInst<"vld2_lane", "2c2i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD3_LANE : WInst<"vld3_lane", "3c3i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD4_LANE : WInst<"vld4_lane", "4c4i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST1_LANE : WInst<"vst1_lane", "vpdi",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST2_LANE : WInst<"vst2_lane", "vp2i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST3_LANE : WInst<"vst3_lane", "vp3i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def ST4_LANE : WInst<"vst4_lane", "vp4i",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+
+def LD1_DUP : WInst<"vld1_dup", "dc",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD2_DUP : WInst<"vld2_dup", "2c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD3_DUP : WInst<"vld3_dup", "3c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+def LD4_DUP : WInst<"vld4_dup", "4c",
+ "QUcQUsQUiQUlQcQsQiQlQhQfQdQPcQPsQPlUcUsUiUlcsilhfdPcPsPl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Addition
+// With additional d, Qd type.
+def ADD : IOpInst<"vadd", "ddd", "csilfdUcUsUiUlQcQsQiQlQfQUcQUsQUiQUlQd",
+ OP_ADD>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Subtraction
+// With additional Qd type.
+def SUB : IOpInst<"vsub", "ddd", "csildfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUlQd",
+ OP_SUB>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Multiplication
+// With additional Qd type.
+def MUL : IOpInst<"vmul", "ddd", "csifdUcUsUiQcQsQiQfQUcQUsQUiQd", OP_MUL>;
+def MLA : IOpInst<"vmla", "dddd", "csifdUcUsUiQcQsQiQfQUcQUsQUiQd", OP_MLA>;
+def MLS : IOpInst<"vmls", "dddd", "csifdUcUsUiQcQsQiQfQUcQUsQUiQd", OP_MLS>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Multiplication Extended
+def MULX : SInst<"vmulx", "ddd", "fdQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Division
+def FDIV : IOpInst<"vdiv", "ddd", "fdQfQd", OP_DIV>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Vector fused multiply-add operations
+// With additional d, Qd type.
+def FMLA : SInst<"vfma", "dddd", "fdQfQd">;
+def FMLS : SInst<"vfms", "dddd", "fdQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// MUL, FMA, FMS definitions with scalar argument
+def VMUL_N_A64 : IOpInst<"vmul_n", "dds", "Qd", OP_MUL_N>;
+def FMLA_N : SOpInst<"vfma_n", "ddds", "fQf", OP_FMLA_N>;
+def FMLS_N : SOpInst<"vfms_n", "ddds", "fQf", OP_FMLS_N>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Logical operations
+// With additional Qd, Ql, QPl type.
+def BSL : SInst<"vbsl", "dudd",
+ "csilUcUsUiUlfdPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPsQdPlQPl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Absolute Difference
+// With additional Qd type.
+def ABD : SInst<"vabd", "ddd", "csiUcUsUifdQcQsQiQUcQUsQUiQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// saturating absolute/negate
+// With additional Qd/Ql type.
+def ABS : SInst<"vabs", "dd", "csilfdQcQsQiQfQlQd">;
+def QABS : SInst<"vqabs", "dd", "csilQcQsQiQl">;
+def NEG : SOpInst<"vneg", "dd", "csilfdQcQsQiQfQdQl", OP_NEG>;
+def QNEG : SInst<"vqneg", "dd", "csilQcQsQiQl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Accumulated of Unsigned Value
+def SUQADD : SInst<"vuqadd", "ddd", "csilQcQsQiQl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Unsigned Saturating Accumulated of Signed Value
+def USQADD : SInst<"vsqadd", "ddd", "UcUsUiUlQUcQUsQUiQUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Reciprocal/Sqrt
+// With additional d, Qd type.
+def FRECPS : IInst<"vrecps", "ddd", "fdQfQd">;
+def FRSQRTS : IInst<"vrsqrts", "ddd", "fdQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// bitwise reverse
+def RBIT : IInst<"vrbit", "dd", "cUcPcQcQUcQPc">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Integer extract and narrow to high
+def XTN2 : SOpInst<"vmovn_high", "qhk", "silUsUiUl", OP_XTN>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed integer saturating extract and unsigned narrow to high
+def SQXTUN2 : SOpInst<"vqmovun_high", "qhk", "sil", OP_SQXTUN>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Integer saturating extract and narrow to high
+def QXTN2 : SOpInst<"vqmovn_high", "qhk", "silUsUiUl", OP_QXTN>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Converting vectors
+def VCVT_HIGH_F16 : SOpInst<"vcvt_high_f16", "qhj", "f", OP_VCVT_NA_HI>;
+def VCVT_HIGH_F32_F16 : SOpInst<"vcvt_high_f32", "wk", "h", OP_VCVT_EX_HI>;
+def VCVT_F32_F64 : SInst<"vcvt_f32_f64", "fj", "d">;
+def VCVT_HIGH_F32_F64 : SOpInst<"vcvt_high_f32", "qfj", "d", OP_VCVT_NA_HI>;
+def VCVT_F64_F32 : SInst<"vcvt_f64_f32", "wd", "f">;
+def VCVT_F64 : SInst<"vcvt_f64", "Fd", "lUlQlQUl">;
+def VCVT_HIGH_F64_F32 : SOpInst<"vcvt_high_f64", "wj", "f", OP_VCVT_EX_HI>;
+def VCVTX_F32_F64 : SInst<"vcvtx_f32", "fj", "d">;
+def VCVTX_HIGH_F32_F64 : SOpInst<"vcvtx_high_f32", "qfj", "d", OP_VCVTX_HI>;
+def FRINTN : SInst<"vrndn", "dd", "fdQfQd">;
+def FRINTA : SInst<"vrnda", "dd", "fdQfQd">;
+def FRINTP : SInst<"vrndp", "dd", "fdQfQd">;
+def FRINTM : SInst<"vrndm", "dd", "fdQfQd">;
+def FRINTX : SInst<"vrndx", "dd", "fdQfQd">;
+def FRINTZ : SInst<"vrnd", "dd", "fdQfQd">;
+def FRINTI : SInst<"vrndi", "dd", "fdQfQd">;
+def VCVT_S64 : SInst<"vcvt_s64", "xd", "dQd">;
+def VCVT_U64 : SInst<"vcvt_u64", "ud", "dQd">;
+def FCVTNS_S32 : SInst<"vcvtn_s32", "xd", "fQf">;
+def FCVTNS_S64 : SInst<"vcvtn_s64", "xd", "dQd">;
+def FCVTNU_S32 : SInst<"vcvtn_u32", "ud", "fQf">;
+def FCVTNU_S64 : SInst<"vcvtn_u64", "ud", "dQd">;
+def FCVTPS_S32 : SInst<"vcvtp_s32", "xd", "fQf">;
+def FCVTPS_S64 : SInst<"vcvtp_s64", "xd", "dQd">;
+def FCVTPU_S32 : SInst<"vcvtp_u32", "ud", "fQf">;
+def FCVTPU_S64 : SInst<"vcvtp_u64", "ud", "dQd">;
+def FCVTMS_S32 : SInst<"vcvtm_s32", "xd", "fQf">;
+def FCVTMS_S64 : SInst<"vcvtm_s64", "xd", "dQd">;
+def FCVTMU_S32 : SInst<"vcvtm_u32", "ud", "fQf">;
+def FCVTMU_S64 : SInst<"vcvtm_u64", "ud", "dQd">;
+def FCVTAS_S32 : SInst<"vcvta_s32", "xd", "fQf">;
+def FCVTAS_S64 : SInst<"vcvta_s64", "xd", "dQd">;
+def FCVTAU_S32 : SInst<"vcvta_u32", "ud", "fQf">;
+def FCVTAU_S64 : SInst<"vcvta_u64", "ud", "dQd">;
+def FRECPE : SInst<"vrecpe", "dd", "fdUiQfQUiQd">;
+def FRSQRTE : SInst<"vrsqrte", "dd", "fdUiQfQUiQd">;
+def FSQRT : SInst<"vsqrt", "dd", "fdQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Comparison
+// With additional Qd, Ql, QPl type.
+def FCAGE : IInst<"vcage", "udd", "fdQfQd">;
+def FCAGT : IInst<"vcagt", "udd", "fdQfQd">;
+def FCALE : IInst<"vcale", "udd", "fdQfQd">;
+def FCALT : IInst<"vcalt", "udd", "fdQfQd">;
+// With additional Ql, QUl, Qd types.
+def CMTST : WInst<"vtst", "udd",
+ "csiUcUsUiPcPsQcQsQiQUcQUsQUiQPcQPslUlQlQUlPlQPl">;
+// With additional l, Ul,d, Qd, Ql, QUl, Qd types.
+def CFMEQ : SOpInst<"vceq", "udd",
+ "csilfUcUsUiUlPcQcdQdQsQiQfQUcQUsQUiQUlQlQPcPlQPl", OP_EQ>;
+def CFMGE : SOpInst<"vcge", "udd",
+ "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUldQd", OP_GE>;
+def CFMLE : SOpInst<"vcle", "udd",
+ "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUldQd", OP_LE>;
+def CFMGT : SOpInst<"vcgt", "udd",
+ "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUldQd", OP_GT>;
+def CFMLT : SOpInst<"vclt", "udd",
+ "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUldQd", OP_LT>;
+
+def CMEQ : SInst<"vceqz", "ud",
+ "csilfUcUsUiUlPcPsPlQcQsQiQlQfQUcQUsQUiQUlQPcQPsdQdQPl">;
+def CMGE : SInst<"vcgez", "ud", "csilfdQcQsQiQlQfQd">;
+def CMLE : SInst<"vclez", "ud", "csilfdQcQsQiQlQfQd">;
+def CMGT : SInst<"vcgtz", "ud", "csilfdQcQsQiQlQfQd">;
+def CMLT : SInst<"vcltz", "ud", "csilfdQcQsQiQlQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Max/Min Integer
+// With additional Qd type.
+def MAX : SInst<"vmax", "ddd", "csiUcUsUifdQcQsQiQUcQUsQUiQfQd">;
+def MIN : SInst<"vmin", "ddd", "csiUcUsUifdQcQsQiQUcQUsQUiQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// MaxNum/MinNum Floating Point
+def FMAXNM : SInst<"vmaxnm", "ddd", "fdQfQd">;
+def FMINNM : SInst<"vminnm", "ddd", "fdQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Pairwise Max/Min
+// With additional Qc Qs Qi QUc QUs QUi Qf Qd types.
+def MAXP : SInst<"vpmax", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQfQd">;
+def MINP : SInst<"vpmin", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Pairwise MaxNum/MinNum Floating Point
+def FMAXNMP : SInst<"vpmaxnm", "ddd", "fQfQd">;
+def FMINNMP : SInst<"vpminnm", "ddd", "fQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Pairwise Addition
+// With additional Qc Qs Qi QUc QUs QUi Qf Qd types.
+def ADDP : IInst<"vpadd", "ddd", "csiUcUsUifQcQsQiQlQUcQUsQUiQUlQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Shifts by constant
+let isShift = 1 in {
+// Left shift long high
+def SHLL_HIGH_N : SOpInst<"vshll_high_n", "ndi", "HcHsHiHUcHUsHUi",
+ OP_LONG_HI>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Shifts with insert, with additional Ql, QPl type.
+def SRI_N : WInst<"vsri_n", "dddi",
+ "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPsPlQPl">;
+def SLI_N : WInst<"vsli_n", "dddi",
+ "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPsPlQPl">;
+
+// Right shift narrow high
+def SHRN_HIGH_N : IOpInst<"vshrn_high_n", "hmdi",
+ "HsHiHlHUsHUiHUl", OP_NARROW_HI>;
+def QSHRUN_HIGH_N : SOpInst<"vqshrun_high_n", "hmdi",
+ "HsHiHl", OP_NARROW_HI>;
+def RSHRN_HIGH_N : IOpInst<"vrshrn_high_n", "hmdi",
+ "HsHiHlHUsHUiHUl", OP_NARROW_HI>;
+def QRSHRUN_HIGH_N : SOpInst<"vqrshrun_high_n", "hmdi",
+ "HsHiHl", OP_NARROW_HI>;
+def QSHRN_HIGH_N : SOpInst<"vqshrn_high_n", "hmdi",
+ "HsHiHlHUsHUiHUl", OP_NARROW_HI>;
+def QRSHRN_HIGH_N : SOpInst<"vqrshrn_high_n", "hmdi",
+ "HsHiHlHUsHUiHUl", OP_NARROW_HI>;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Converting vectors
+def VMOVL_HIGH : SOpInst<"vmovl_high", "nd", "HcHsHiHUcHUsHUi", OP_MOVL_HI>;
+
+let isVCVT_N = 1 in {
+def CVTF_N_F64 : SInst<"vcvt_n_f64", "Fdi", "lUlQlQUl">;
+def FCVTZS_N_S64 : SInst<"vcvt_n_s64", "xdi", "dQd">;
+def FCVTZS_N_U64 : SInst<"vcvt_n_u64", "udi", "dQd">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 3VDiff class using high 64-bit in operands
+def VADDL_HIGH : SOpInst<"vaddl_high", "wkk", "csiUcUsUi", OP_ADDLHi>;
+def VADDW_HIGH : SOpInst<"vaddw_high", "wwk", "csiUcUsUi", OP_ADDWHi>;
+def VSUBL_HIGH : SOpInst<"vsubl_high", "wkk", "csiUcUsUi", OP_SUBLHi>;
+def VSUBW_HIGH : SOpInst<"vsubw_high", "wwk", "csiUcUsUi", OP_SUBWHi>;
+
+def VABDL_HIGH : SOpInst<"vabdl_high", "wkk", "csiUcUsUi", OP_ABDLHi>;
+def VABAL_HIGH : SOpInst<"vabal_high", "wwkk", "csiUcUsUi", OP_ABALHi>;
+
+def VMULL_HIGH : SOpInst<"vmull_high", "wkk", "csiUcUsUiPc", OP_MULLHi>;
+def VMULL_HIGH_N : SOpInst<"vmull_high_n", "wks", "siUsUi", OP_MULLHi_N>;
+def VMLAL_HIGH : SOpInst<"vmlal_high", "wwkk", "csiUcUsUi", OP_MLALHi>;
+def VMLAL_HIGH_N : SOpInst<"vmlal_high_n", "wwks", "siUsUi", OP_MLALHi_N>;
+def VMLSL_HIGH : SOpInst<"vmlsl_high", "wwkk", "csiUcUsUi", OP_MLSLHi>;
+def VMLSL_HIGH_N : SOpInst<"vmlsl_high_n", "wwks", "siUsUi", OP_MLSLHi_N>;
+
+def VADDHN_HIGH : SOpInst<"vaddhn_high", "qhkk", "silUsUiUl", OP_ADDHNHi>;
+def VRADDHN_HIGH : SOpInst<"vraddhn_high", "qhkk", "silUsUiUl", OP_RADDHNHi>;
+def VSUBHN_HIGH : SOpInst<"vsubhn_high", "qhkk", "silUsUiUl", OP_SUBHNHi>;
+def VRSUBHN_HIGH : SOpInst<"vrsubhn_high", "qhkk", "silUsUiUl", OP_RSUBHNHi>;
+
+def VQDMULL_HIGH : SOpInst<"vqdmull_high", "wkk", "si", OP_QDMULLHi>;
+def VQDMULL_HIGH_N : SOpInst<"vqdmull_high_n", "wks", "si", OP_QDMULLHi_N>;
+def VQDMLAL_HIGH : SOpInst<"vqdmlal_high", "wwkk", "si", OP_QDMLALHi>;
+def VQDMLAL_HIGH_N : SOpInst<"vqdmlal_high_n", "wwks", "si", OP_QDMLALHi_N>;
+def VQDMLSL_HIGH : SOpInst<"vqdmlsl_high", "wwkk", "si", OP_QDMLSLHi>;
+def VQDMLSL_HIGH_N : SOpInst<"vqdmlsl_high_n", "wwks", "si", OP_QDMLSLHi_N>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Extract or insert element from vector
+def GET_LANE : IInst<"vget_lane", "sdi",
+ "csilPcPsUcUsUiUlQcQsQiQlQUcQUsQUiQUlPcPsQPcQPsfdQfQdPlQPl">;
+def SET_LANE : IInst<"vset_lane", "dsdi",
+ "csilPcPsUcUsUiUlQcQsQiQlQUcQUsQUiQUlPcPsQPcQPsfdQfQdPlQPl">;
+def COPY_LANE : IOpInst<"vcopy_lane", "ddidi",
+ "csilPcPsUcUsUiUlPcPsPlfd", OP_COPY_LN>;
+def COPYQ_LANE : IOpInst<"vcopy_lane", "ddigi",
+ "QcQsQiQlQUcQUsQUiQUlQPcQPsQfQdQPl", OP_COPYQ_LN>;
+def COPY_LANEQ : IOpInst<"vcopy_laneq", "ddiki",
+ "csilPcPsPlUcUsUiUlfd", OP_COPY_LNQ>;
+def COPYQ_LANEQ : IOpInst<"vcopy_laneq", "ddidi",
+ "QcQsQiQlQUcQUsQUiQUlQPcQPsQfQdQPl", OP_COPY_LN>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Set all lanes to same value
+def VDUP_LANE1: WOpInst<"vdup_lane", "dgi",
+ "csilPcPsUcUsUiUlhfdQcQsQiQlQPcQPsQUcQUsQUiQUlQhQfQdPlQPl",
+ OP_DUP_LN>;
+def VDUP_LANE2: WOpInst<"vdup_laneq", "dki",
+ "csilPcPsUcUsUiUlhfdQcQsQiQlQPcQPsQUcQUsQUiQUlQhQfQdPlQPl",
+ OP_DUP_LN>;
+def DUP_N : WOpInst<"vdup_n", "ds",
+ "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUldQdPlQPl",
+ OP_DUP>;
+def MOV_N : WOpInst<"vmov_n", "ds",
+ "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUldQd",
+ OP_DUP>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Combining vectors, with additional Pl
+def COMBINE : NoTestOpInst<"vcombine", "kdd", "csilhfdUcUsUiUlPcPsPl", OP_CONC>;
+
+////////////////////////////////////////////////////////////////////////////////
+//Initialize a vector from bit pattern, with additional Pl
+def CREATE : NoTestOpInst<"vcreate", "dl", "csihfdUcUsUiUlPcPslPl", OP_CAST>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+def VMLA_LANEQ : IOpInst<"vmla_laneq", "dddji",
+ "siUsUifQsQiQUsQUiQf", OP_MLA_LN>;
+def VMLS_LANEQ : IOpInst<"vmls_laneq", "dddji",
+ "siUsUifQsQiQUsQUiQf", OP_MLS_LN>;
+
+def VFMA_LANE : IInst<"vfma_lane", "dddgi", "fdQfQd">;
+def VFMA_LANEQ : IInst<"vfma_laneq", "dddji", "fdQfQd">;
+def VFMS_LANE : IOpInst<"vfms_lane", "dddgi", "fdQfQd", OP_FMS_LN>;
+def VFMS_LANEQ : IOpInst<"vfms_laneq", "dddji", "fdQfQd", OP_FMS_LNQ>;
+
+def VMLAL_LANEQ : SOpInst<"vmlal_laneq", "wwdki", "siUsUi", OP_MLAL_LN>;
+def VMLAL_HIGH_LANE : SOpInst<"vmlal_high_lane", "wwkdi", "siUsUi",
+ OP_MLALHi_LN>;
+def VMLAL_HIGH_LANEQ : SOpInst<"vmlal_high_laneq", "wwkki", "siUsUi",
+ OP_MLALHi_LN>;
+def VMLSL_LANEQ : SOpInst<"vmlsl_laneq", "wwdki", "siUsUi", OP_MLSL_LN>;
+def VMLSL_HIGH_LANE : SOpInst<"vmlsl_high_lane", "wwkdi", "siUsUi",
+ OP_MLSLHi_LN>;
+def VMLSL_HIGH_LANEQ : SOpInst<"vmlsl_high_laneq", "wwkki", "siUsUi",
+ OP_MLSLHi_LN>;
+
+def VQDMLAL_LANEQ : SOpInst<"vqdmlal_laneq", "wwdki", "si", OP_QDMLAL_LN>;
+def VQDMLAL_HIGH_LANE : SOpInst<"vqdmlal_high_lane", "wwkdi", "si",
+ OP_QDMLALHi_LN>;
+def VQDMLAL_HIGH_LANEQ : SOpInst<"vqdmlal_high_laneq", "wwkki", "si",
+ OP_QDMLALHi_LN>;
+def VQDMLSL_LANEQ : SOpInst<"vqdmlsl_laneq", "wwdki", "si", OP_QDMLSL_LN>;
+def VQDMLSL_HIGH_LANE : SOpInst<"vqdmlsl_high_lane", "wwkdi", "si",
+ OP_QDMLSLHi_LN>;
+def VQDMLSL_HIGH_LANEQ : SOpInst<"vqdmlsl_high_laneq", "wwkki", "si",
+ OP_QDMLSLHi_LN>;
+
+// Newly add double parameter for vmul_lane in aarch64
+// Note: d type is handled by SCALAR_VMUL_LANE
+def VMUL_LANE_A64 : IOpInst<"vmul_lane", "ddgi", "Qd", OP_MUL_LN>;
+
+// Note: d type is handled by SCALAR_VMUL_LANEQ
+def VMUL_LANEQ : IOpInst<"vmul_laneq", "ddji",
+ "sifUsUiQsQiQfQUsQUiQfQd", OP_MUL_LN>;
+def VMULL_LANEQ : SOpInst<"vmull_laneq", "wdki", "siUsUi", OP_MULL_LN>;
+def VMULL_HIGH_LANE : SOpInst<"vmull_high_lane", "wkdi", "siUsUi",
+ OP_MULLHi_LN>;
+def VMULL_HIGH_LANEQ : SOpInst<"vmull_high_laneq", "wkki", "siUsUi",
+ OP_MULLHi_LN>;
+
+def VQDMULL_LANEQ : SOpInst<"vqdmull_laneq", "wdki", "si", OP_QDMULL_LN>;
+def VQDMULL_HIGH_LANE : SOpInst<"vqdmull_high_lane", "wkdi", "si",
+ OP_QDMULLHi_LN>;
+def VQDMULL_HIGH_LANEQ : SOpInst<"vqdmull_high_laneq", "wkki", "si",
+ OP_QDMULLHi_LN>;
+
+def VQDMULH_LANEQ : SOpInst<"vqdmulh_laneq", "ddji", "siQsQi", OP_QDMULH_LN>;
+def VQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ddji", "siQsQi", OP_QRDMULH_LN>;
+
+// Note: d type implemented by SCALAR_VMULX_LANE
+def VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "fQfQd", OP_MULX_LN>;
+// Note: d type is implemented by SCALAR_VMULX_LANEQ
+def VMULX_LANEQ : IOpInst<"vmulx_laneq", "ddji", "fQfQd", OP_MULX_LN>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Across vectors class
+def VADDLV : SInst<"vaddlv", "rd", "csiUcUsUiQcQsQiQUcQUsQUi">;
+def VMAXV : SInst<"vmaxv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQd">;
+def VMINV : SInst<"vminv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQd">;
+def VADDV : SInst<"vaddv", "sd", "csifUcUsUiQcQsQiQUcQUsQUiQfQdQlQUl">;
+def FMAXNMV : SInst<"vmaxnmv", "sd", "fQfQd">;
+def FMINNMV : SInst<"vminnmv", "sd", "fQfQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Newly added Vector Extract for f64
+def VEXT_A64 : WInst<"vext", "dddi",
+ "cUcPcsUsPsiUilUlfdQcQUcQPcQsQUsQPsQiQUiQlQUlQfQdPlQPl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Crypto
+let isCrypto = 1 in {
+def AESE : SInst<"vaese", "ddd", "QUc">;
+def AESD : SInst<"vaesd", "ddd", "QUc">;
+def AESMC : SInst<"vaesmc", "dd", "QUc">;
+def AESIMC : SInst<"vaesimc", "dd", "QUc">;
+
+def SHA1H : SInst<"vsha1h", "ss", "Ui">;
+def SHA1SU1 : SInst<"vsha1su1", "ddd", "QUi">;
+def SHA256SU0 : SInst<"vsha256su0", "ddd", "QUi">;
+
+def SHA1C : SInst<"vsha1c", "ddsd", "QUi">;
+def SHA1P : SInst<"vsha1p", "ddsd", "QUi">;
+def SHA1M : SInst<"vsha1m", "ddsd", "QUi">;
+def SHA1SU0 : SInst<"vsha1su0", "dddd", "QUi">;
+def SHA256H : SInst<"vsha256h", "dddd", "QUi">;
+def SHA256H2 : SInst<"vsha256h2", "dddd", "QUi">;
+def SHA256SU1 : SInst<"vsha256su1", "dddd", "QUi">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Permutation
+def VTRN1 : SOpInst<"vtrn1", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_TRN1>;
+def VZIP1 : SOpInst<"vzip1", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_ZIP1>;
+def VUZP1 : SOpInst<"vuzp1", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_UZP1>;
+def VTRN2 : SOpInst<"vtrn2", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_TRN2>;
+def VZIP2 : SOpInst<"vzip2", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_ZIP2>;
+def VUZP2 : SOpInst<"vuzp2", "ddd",
+ "csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_UZP2>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Table lookup
+let InstName = "vtbl" in {
+def VQTBL1_A64 : WInst<"vqtbl1", "djt", "UccPcQUcQcQPc">;
+def VQTBL2_A64 : WInst<"vqtbl2", "dBt", "UccPcQUcQcQPc">;
+def VQTBL3_A64 : WInst<"vqtbl3", "dCt", "UccPcQUcQcQPc">;
+def VQTBL4_A64 : WInst<"vqtbl4", "dDt", "UccPcQUcQcQPc">;
+}
+let InstName = "vtbx" in {
+def VQTBX1_A64 : WInst<"vqtbx1", "ddjt", "UccPcQUcQcQPc">;
+def VQTBX2_A64 : WInst<"vqtbx2", "ddBt", "UccPcQUcQcQPc">;
+def VQTBX3_A64 : WInst<"vqtbx3", "ddCt", "UccPcQUcQcQPc">;
+def VQTBX4_A64 : WInst<"vqtbx4", "ddDt", "UccPcQUcQcQPc">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Vector reinterpret cast operations
+// With additional d, Qd, pl, Qpl types
+def REINTERPRET
+ : NoTestOpInst<"vreinterpret", "dd",
+ "csilUcUsUiUlhfdPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQdQPcQPsQPl", OP_REINT>;
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Intrinsics
+// Scalar Arithmetic
+
+// Scalar Addition
+def SCALAR_ADD : SInst<"vadd", "sss", "SlSUl">;
+// Scalar Saturating Add
+def SCALAR_QADD : SInst<"vqadd", "sss", "ScSsSiSlSUcSUsSUiSUl">;
+
+// Scalar Subtraction
+def SCALAR_SUB : SInst<"vsub", "sss", "SlSUl">;
+// Scalar Saturating Sub
+def SCALAR_QSUB : SInst<"vqsub", "sss", "ScSsSiSlSUcSUsSUiSUl">;
+
+let InstName = "vmov" in {
+def VGET_HIGH_A64 : NoTestOpInst<"vget_high", "dk", "csilhfdUcUsUiUlPcPsPl",
+ OP_HI>;
+def VGET_LOW_A64 : NoTestOpInst<"vget_low", "dk", "csilhfdUcUsUiUlPcPsPl",
+ OP_LO>;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Shift
+// Scalar Shift Left
+def SCALAR_SHL: SInst<"vshl", "sss", "SlSUl">;
+// Scalar Saturating Shift Left
+def SCALAR_QSHL: SInst<"vqshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
+// Scalar Saturating Rounding Shift Left
+def SCALAR_QRSHL: SInst<"vqrshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
+// Scalar Shift Rouding Left
+def SCALAR_RSHL: SInst<"vrshl", "sss", "SlSUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Shift (Immediate)
+let isScalarShift = 1 in {
+// Signed/Unsigned Shift Right (Immediate)
+def SCALAR_SSHR_N: SInst<"vshr_n", "ssi", "SlSUl">;
+// Signed/Unsigned Rounding Shift Right (Immediate)
+def SCALAR_SRSHR_N: SInst<"vrshr_n", "ssi", "SlSUl">;
+
+// Signed/Unsigned Shift Right and Accumulate (Immediate)
+def SCALAR_SSRA_N: SInst<"vsra_n", "sssi", "SlSUl">;
+// Signed/Unsigned Rounding Shift Right and Accumulate (Immediate)
+def SCALAR_SRSRA_N: SInst<"vrsra_n", "sssi", "SlSUl">;
+
+// Shift Left (Immediate)
+def SCALAR_SHL_N: SInst<"vshl_n", "ssi", "SlSUl">;
+// Signed/Unsigned Saturating Shift Left (Immediate)
+def SCALAR_SQSHL_N: SInst<"vqshl_n", "ssi", "ScSsSiSlSUcSUsSUiSUl">;
+// Signed Saturating Shift Left Unsigned (Immediate)
+def SCALAR_SQSHLU_N: SInst<"vqshlu_n", "ssi", "ScSsSiSl">;
+
+// Shift Right And Insert (Immediate)
+def SCALAR_SRI_N: SInst<"vsri_n", "sssi", "SlSUl">;
+// Shift Left And Insert (Immediate)
+def SCALAR_SLI_N: SInst<"vsli_n", "sssi", "SlSUl">;
+
+let isScalarNarrowShift = 1 in {
+ // Signed/Unsigned Saturating Shift Right Narrow (Immediate)
+ def SCALAR_SQSHRN_N: SInst<"vqshrn_n", "zsi", "SsSiSlSUsSUiSUl">;
+ // Signed/Unsigned Saturating Rounded Shift Right Narrow (Immediate)
+ def SCALAR_SQRSHRN_N: SInst<"vqrshrn_n", "zsi", "SsSiSlSUsSUiSUl">;
+ // Signed Saturating Shift Right Unsigned Narrow (Immediate)
+ def SCALAR_SQSHRUN_N: SInst<"vqshrun_n", "zsi", "SsSiSl">;
+ // Signed Saturating Rounded Shift Right Unsigned Narrow (Immediate)
+ def SCALAR_SQRSHRUN_N: SInst<"vqrshrun_n", "zsi", "SsSiSl">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed/Unsigned Fixed-point Convert To Floating-Point (Immediate)
+def SCALAR_SCVTF_N_F32: SInst<"vcvt_n_f32", "ysi", "SiSUi">;
+def SCALAR_SCVTF_N_F64: SInst<"vcvt_n_f64", "osi", "SlSUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Convert To Signed/Unsigned Fixed-point (Immediate)
+def SCALAR_FCVTZS_N_S32 : SInst<"vcvt_n_s32", "$si", "Sf">;
+def SCALAR_FCVTZU_N_U32 : SInst<"vcvt_n_u32", "bsi", "Sf">;
+def SCALAR_FCVTZS_N_S64 : SInst<"vcvt_n_s64", "$si", "Sd">;
+def SCALAR_FCVTZU_N_U64 : SInst<"vcvt_n_u64", "bsi", "Sd">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Reduce Pairwise Addition (Scalar and Floating Point)
+def SCALAR_ADDP : SInst<"vpadd", "sd", "SfSHlSHdSHUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Reduce Floating Point Pairwise Max/Min
+def SCALAR_FMAXP : SInst<"vpmax", "sd", "SfSQd">;
+
+def SCALAR_FMINP : SInst<"vpmin", "sd", "SfSQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Reduce Floating Point Pairwise maxNum/minNum
+def SCALAR_FMAXNMP : SInst<"vpmaxnm", "sd", "SfSQd">;
+def SCALAR_FMINNMP : SInst<"vpminnm", "sd", "SfSQd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Integer Saturating Doubling Multiply Half High
+def SCALAR_SQDMULH : SInst<"vqdmulh", "sss", "SsSi">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Integer Saturating Rounding Doubling Multiply Half High
+def SCALAR_SQRDMULH : SInst<"vqrdmulh", "sss", "SsSi">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Multiply Extended
+def SCALAR_FMULX : IInst<"vmulx", "sss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Reciprocal Step
+def SCALAR_FRECPS : IInst<"vrecps", "sss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Reciprocal Square Root Step
+def SCALAR_FRSQRTS : IInst<"vrsqrts", "sss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Integer Convert To Floating-point
+def SCALAR_SCVTFS : SInst<"vcvt_f32", "ys", "Si">;
+def SCALAR_SCVTFD : SInst<"vcvt_f64", "os", "Sl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Unsigned Integer Convert To Floating-point
+def SCALAR_UCVTFS : SInst<"vcvt_f32", "ys", "SUi">;
+def SCALAR_UCVTFD : SInst<"vcvt_f64", "os", "SUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Converts
+def SCALAR_FCVTXN : IInst<"vcvtx_f32", "ys", "Sd">;
+def SCALAR_FCVTNSS : SInst<"vcvtn_s32", "$s", "Sf">;
+def SCALAR_FCVTNUS : SInst<"vcvtn_u32", "bs", "Sf">;
+def SCALAR_FCVTNSD : SInst<"vcvtn_s64", "$s", "Sd">;
+def SCALAR_FCVTNUD : SInst<"vcvtn_u64", "bs", "Sd">;
+def SCALAR_FCVTMSS : SInst<"vcvtm_s32", "$s", "Sf">;
+def SCALAR_FCVTMUS : SInst<"vcvtm_u32", "bs", "Sf">;
+def SCALAR_FCVTMSD : SInst<"vcvtm_s64", "$s", "Sd">;
+def SCALAR_FCVTMUD : SInst<"vcvtm_u64", "bs", "Sd">;
+def SCALAR_FCVTASS : SInst<"vcvta_s32", "$s", "Sf">;
+def SCALAR_FCVTAUS : SInst<"vcvta_u32", "bs", "Sf">;
+def SCALAR_FCVTASD : SInst<"vcvta_s64", "$s", "Sd">;
+def SCALAR_FCVTAUD : SInst<"vcvta_u64", "bs", "Sd">;
+def SCALAR_FCVTPSS : SInst<"vcvtp_s32", "$s", "Sf">;
+def SCALAR_FCVTPUS : SInst<"vcvtp_u32", "bs", "Sf">;
+def SCALAR_FCVTPSD : SInst<"vcvtp_s64", "$s", "Sd">;
+def SCALAR_FCVTPUD : SInst<"vcvtp_u64", "bs", "Sd">;
+def SCALAR_FCVTZSS : SInst<"vcvt_s32", "$s", "Sf">;
+def SCALAR_FCVTZUS : SInst<"vcvt_u32", "bs", "Sf">;
+def SCALAR_FCVTZSD : SInst<"vcvt_s64", "$s", "Sd">;
+def SCALAR_FCVTZUD : SInst<"vcvt_u64", "bs", "Sd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Reciprocal Estimate
+def SCALAR_FRECPE : IInst<"vrecpe", "ss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Reciprocal Exponent
+def SCALAR_FRECPX : IInst<"vrecpx", "ss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Reciprocal Square Root Estimate
+def SCALAR_FRSQRTE : IInst<"vrsqrte", "ss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Integer Comparison
+def SCALAR_CMEQ : SInst<"vceq", "sss", "SlSUl">;
+def SCALAR_CMEQZ : SInst<"vceqz", "ss", "SlSUl">;
+def SCALAR_CMGE : SInst<"vcge", "sss", "Sl">;
+def SCALAR_CMGEZ : SInst<"vcgez", "ss", "Sl">;
+def SCALAR_CMHS : SInst<"vcge", "sss", "SUl">;
+def SCALAR_CMLE : SInst<"vcle", "sss", "SlSUl">;
+def SCALAR_CMLEZ : SInst<"vclez", "ss", "Sl">;
+def SCALAR_CMLT : SInst<"vclt", "sss", "SlSUl">;
+def SCALAR_CMLTZ : SInst<"vcltz", "ss", "Sl">;
+def SCALAR_CMGT : SInst<"vcgt", "sss", "Sl">;
+def SCALAR_CMGTZ : SInst<"vcgtz", "ss", "Sl">;
+def SCALAR_CMHI : SInst<"vcgt", "sss", "SUl">;
+def SCALAR_CMTST : SInst<"vtst", "sss", "SlSUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Comparison
+def SCALAR_FCMEQ : IInst<"vceq", "bss", "SfSd">;
+def SCALAR_FCMEQZ : IInst<"vceqz", "bs", "SfSd">;
+def SCALAR_FCMGE : IInst<"vcge", "bss", "SfSd">;
+def SCALAR_FCMGEZ : IInst<"vcgez", "bs", "SfSd">;
+def SCALAR_FCMGT : IInst<"vcgt", "bss", "SfSd">;
+def SCALAR_FCMGTZ : IInst<"vcgtz", "bs", "SfSd">;
+def SCALAR_FCMLE : IInst<"vcle", "bss", "SfSd">;
+def SCALAR_FCMLEZ : IInst<"vclez", "bs", "SfSd">;
+def SCALAR_FCMLT : IInst<"vclt", "bss", "SfSd">;
+def SCALAR_FCMLTZ : IInst<"vcltz", "bs", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Absolute Compare Mask Greater Than Or Equal
+def SCALAR_FACGE : IInst<"vcage", "bss", "SfSd">;
+def SCALAR_FACLE : IInst<"vcale", "bss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Floating-point Absolute Compare Mask Greater Than
+def SCALAR_FACGT : IInst<"vcagt", "bss", "SfSd">;
+def SCALAR_FACLT : IInst<"vcalt", "bss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Absolute Value
+def SCALAR_ABS : SInst<"vabs", "ss", "Sl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Absolute Difference
+def SCALAR_ABD : IInst<"vabd", "sss", "SfSd">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Saturating Absolute Value
+def SCALAR_SQABS : SInst<"vqabs", "ss", "ScSsSiSl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Negate
+def SCALAR_NEG : SInst<"vneg", "ss", "Sl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Saturating Negate
+def SCALAR_SQNEG : SInst<"vqneg", "ss", "ScSsSiSl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Saturating Accumulated of Unsigned Value
+def SCALAR_SUQADD : SInst<"vuqadd", "sss", "ScSsSiSl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Unsigned Saturating Accumulated of Signed Value
+def SCALAR_USQADD : SInst<"vsqadd", "sss", "SUcSUsSUiSUl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Doubling Multiply-Add Long
+def SCALAR_SQDMLAL : SInst<"vqdmlal", "rrss", "SsSi">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Doubling Multiply-Subtract Long
+def SCALAR_SQDMLSL : SInst<"vqdmlsl", "rrss", "SsSi">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Doubling Multiply Long
+def SCALAR_SQDMULL : SInst<"vqdmull", "rss", "SsSi">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Saturating Extract Unsigned Narrow
+def SCALAR_SQXTUN : SInst<"vqmovun", "zs", "SsSiSl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Signed Saturating Extract Narrow
+def SCALAR_SQXTN : SInst<"vqmovn", "zs", "SsSiSl">;
+
+////////////////////////////////////////////////////////////////////////////////
+// Scalar Unsigned Saturating Extract Narrow
+def SCALAR_UQXTN : SInst<"vqmovn", "zs", "SUsSUiSUl">;
+
+// Scalar Floating Point multiply (scalar, by element)
+def SCALAR_FMUL_LANE : IOpInst<"vmul_lane", "ssdi", "SfSd", OP_SCALAR_MUL_LN>;
+def SCALAR_FMUL_LANEQ : IOpInst<"vmul_laneq", "ssji", "SfSd", OP_SCALAR_MUL_LNQ>;
+
+// Scalar Floating Point multiply extended (scalar, by element)
+def SCALAR_FMULX_LANE : IOpInst<"vmulx_lane", "ssdi", "SfSd", OP_SCALAR_MULX_LN>;
+def SCALAR_FMULX_LANEQ : IOpInst<"vmulx_laneq", "ssji", "SfSd", OP_SCALAR_MULX_LNQ>;
+
+def SCALAR_VMUL_N : IInst<"vmul_n", "dds", "d">;
+
+// VMUL_LANE_A64 d type implemented using scalar mul lane
+def SCALAR_VMUL_LANE : IInst<"vmul_lane", "ddgi", "d">;
+
+// VMUL_LANEQ d type implemented using scalar mul lane
+def SCALAR_VMUL_LANEQ : IInst<"vmul_laneq", "ddji", "d">;
+
+// VMULX_LANE d type implemented using scalar vmulx_lane
+def SCALAR_VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "d", OP_SCALAR_VMULX_LN>;
+
+// VMULX_LANEQ d type implemented using scalar vmulx_laneq
+def SCALAR_VMULX_LANEQ : IOpInst<"vmulx_laneq", "ddji", "d", OP_SCALAR_VMULX_LNQ>;
+
+// Scalar Floating Point fused multiply-add (scalar, by element)
+def SCALAR_FMLA_LANE : IInst<"vfma_lane", "sssdi", "SfSd">;
+def SCALAR_FMLA_LANEQ : IInst<"vfma_laneq", "sssji", "SfSd">;
+
+// Scalar Floating Point fused multiply-subtract (scalar, by element)
+def SCALAR_FMLS_LANE : IOpInst<"vfms_lane", "sssdi", "SfSd", OP_FMS_LN>;
+def SCALAR_FMLS_LANEQ : IOpInst<"vfms_laneq", "sssji", "SfSd", OP_FMS_LNQ>;
+
+// Signed Saturating Doubling Multiply Long (scalar by element)
+def SCALAR_SQDMULL_LANE : SOpInst<"vqdmull_lane", "rsdi", "SsSi", OP_SCALAR_QDMULL_LN>;
+def SCALAR_SQDMULL_LANEQ : SOpInst<"vqdmull_laneq", "rsji", "SsSi", OP_SCALAR_QDMULL_LNQ>;
+
+// Signed Saturating Doubling Multiply-Add Long (scalar by element)
+def SCALAR_SQDMLAL_LANE : SInst<"vqdmlal_lane", "rrsdi", "SsSi">;
+def SCALAR_SQDMLAL_LANEQ : SInst<"vqdmlal_laneq", "rrsji", "SsSi">;
+
+// Signed Saturating Doubling Multiply-Subtract Long (scalar by element)
+def SCALAR_SQDMLS_LANE : SInst<"vqdmlsl_lane", "rrsdi", "SsSi">;
+def SCALAR_SQDMLS_LANEQ : SInst<"vqdmlsl_laneq", "rrsji", "SsSi">;
+
+// Scalar Integer Saturating Doubling Multiply Half High (scalar by element)
+def SCALAR_SQDMULH_LANE : SOpInst<"vqdmulh_lane", "ssdi", "SsSi", OP_SCALAR_QDMULH_LN>;
+def SCALAR_SQDMULH_LANEQ : SOpInst<"vqdmulh_laneq", "ssji", "SsSi", OP_SCALAR_QDMULH_LNQ>;
+
+// Scalar Integer Saturating Rounding Doubling Multiply Half High
+def SCALAR_SQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "ssdi", "SsSi", OP_SCALAR_QRDMULH_LN>;
+def SCALAR_SQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ssji", "SsSi", OP_SCALAR_QRDMULH_LNQ>;
+
+def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
+def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
+
+def SCALAR_GET_LANE : IOpInst<"vget_lane", "sdi", "hQh", OP_SCALAR_GET_LN>;
+def SCALAR_SET_LANE : IOpInst<"vset_lane", "dsdi", "hQh", OP_SCALAR_SET_LN>;
+}
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
new file mode 100644
index 000000000000..96da0e9de1ad
--- /dev/null
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -0,0 +1,361 @@
+//==-- CGFunctionInfo.h - Representation of function argument/return types -==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines CGFunctionInfo and associated types used in representing the
+// LLVM source types and ABI-coerced types for function arguments and
+// return values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
+#define LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
+
+#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/FoldingSet.h"
+
+#include <cassert>
+
+namespace llvm {
+ class Type;
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// ABIArgInfo - Helper class to encapsulate information about how a
+/// specific C type should be passed to or returned from a function.
+class ABIArgInfo {
+public:
+ enum Kind {
+ /// Direct - Pass the argument directly using the normal converted LLVM
+ /// type, or by coercing to another specified type stored in
+ /// 'CoerceToType'). If an offset is specified (in UIntData), then the
+ /// argument passed is offset by some number of bytes in the memory
+ /// representation. A dummy argument is emitted before the real argument
+ /// if the specified type stored in "PaddingType" is not zero.
+ Direct,
+
+ /// Extend - Valid only for integer argument types. Same as 'direct'
+ /// but also emit a zero/sign extension attribute.
+ Extend,
+
+ /// Indirect - Pass the argument indirectly via a hidden pointer
+ /// with the specified alignment (0 indicates default alignment).
+ Indirect,
+
+ /// Ignore - Ignore the argument (treat as void). Useful for void and
+ /// empty structs.
+ Ignore,
+
+ /// Expand - Only valid for aggregate argument types. The structure should
+ /// be expanded into consecutive arguments for its constituent fields.
+ /// Currently expand is only allowed on structures whose fields
+ /// are all scalar types or are themselves expandable types.
+ Expand,
+
+ KindFirst=Direct, KindLast=Expand
+ };
+
+private:
+ Kind TheKind;
+ llvm::Type *TypeData;
+ llvm::Type *PaddingType;
+ unsigned UIntData;
+ bool BoolData0;
+ bool BoolData1;
+ bool InReg;
+ bool PaddingInReg;
+
+ ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
+ bool PIR, llvm::Type* P)
+ : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
+ BoolData1(B1), InReg(IR), PaddingInReg(PIR) {}
+
+public:
+ ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
+
+ static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
+ llvm::Type *Padding = 0) {
+ return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding);
+ }
+ static ABIArgInfo getDirectInReg(llvm::Type *T = 0) {
+ return ABIArgInfo(Direct, T, 0, false, false, true, false, 0);
+ }
+ static ABIArgInfo getExtend(llvm::Type *T = 0) {
+ return ABIArgInfo(Extend, T, 0, false, false, false, false, 0);
+ }
+ static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
+ return ABIArgInfo(Extend, T, 0, false, false, true, false, 0);
+ }
+ static ABIArgInfo getIgnore() {
+ return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
+ }
+ static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
+ , bool Realign = false
+ , llvm::Type *Padding = 0) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
+ Padding);
+ }
+ static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
+ , bool Realign = false) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
+ }
+ static ABIArgInfo getExpand() {
+ return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0);
+ }
+ static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
+ llvm::Type *Padding) {
+ return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg,
+ Padding);
+ }
+
+ Kind getKind() const { return TheKind; }
+ bool isDirect() const { return TheKind == Direct; }
+ bool isExtend() const { return TheKind == Extend; }
+ bool isIgnore() const { return TheKind == Ignore; }
+ bool isIndirect() const { return TheKind == Indirect; }
+ bool isExpand() const { return TheKind == Expand; }
+
+ bool canHaveCoerceToType() const {
+ return TheKind == Direct || TheKind == Extend;
+ }
+
+ // Direct/Extend accessors
+ unsigned getDirectOffset() const {
+ assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ return UIntData;
+ }
+
+ llvm::Type *getPaddingType() const {
+ return PaddingType;
+ }
+
+ bool getPaddingInReg() const {
+ return PaddingInReg;
+ }
+
+ llvm::Type *getCoerceToType() const {
+ assert(canHaveCoerceToType() && "Invalid kind!");
+ return TypeData;
+ }
+
+ void setCoerceToType(llvm::Type *T) {
+ assert(canHaveCoerceToType() && "Invalid kind!");
+ TypeData = T;
+ }
+
+ bool getInReg() const {
+ assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
+ return InReg;
+ }
+
+ // Indirect accessors
+ unsigned getIndirectAlign() const {
+ assert(TheKind == Indirect && "Invalid kind!");
+ return UIntData;
+ }
+
+ bool getIndirectByVal() const {
+ assert(TheKind == Indirect && "Invalid kind!");
+ return BoolData0;
+ }
+
+ bool getIndirectRealign() const {
+ assert(TheKind == Indirect && "Invalid kind!");
+ return BoolData1;
+ }
+
+ void dump() const;
+};
+
+/// A class for recording the number of arguments that a function
+/// signature requires.
+class RequiredArgs {
+ /// The number of required arguments, or ~0 if the signature does
+ /// not permit optional arguments.
+ unsigned NumRequired;
+public:
+ enum All_t { All };
+
+ RequiredArgs(All_t _) : NumRequired(~0U) {}
+ explicit RequiredArgs(unsigned n) : NumRequired(n) {
+ assert(n != ~0U);
+ }
+
+ /// Compute the arguments required by the given formal prototype,
+ /// given that there may be some additional, non-formal arguments
+ /// in play.
+ static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype,
+ unsigned additional) {
+ if (!prototype->isVariadic()) return All;
+ return RequiredArgs(prototype->getNumArgs() + additional);
+ }
+
+ static RequiredArgs forPrototype(const FunctionProtoType *prototype) {
+ return forPrototypePlus(prototype, 0);
+ }
+
+ static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) {
+ return forPrototype(prototype.getTypePtr());
+ }
+
+ static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype,
+ unsigned additional) {
+ return forPrototypePlus(prototype.getTypePtr(), additional);
+ }
+
+ bool allowsOptionalArgs() const { return NumRequired != ~0U; }
+ unsigned getNumRequiredArgs() const {
+ assert(allowsOptionalArgs());
+ return NumRequired;
+ }
+
+ unsigned getOpaqueData() const { return NumRequired; }
+ static RequiredArgs getFromOpaqueData(unsigned value) {
+ if (value == ~0U) return All;
+ return RequiredArgs(value);
+ }
+};
+
+/// CGFunctionInfo - Class to encapsulate the information about a
+/// function definition.
+class CGFunctionInfo : public llvm::FoldingSetNode {
+ struct ArgInfo {
+ CanQualType type;
+ ABIArgInfo info;
+ };
+
+ /// The LLVM::CallingConv to use for this function (as specified by the
+ /// user).
+ unsigned CallingConvention : 8;
+
+ /// The LLVM::CallingConv to actually use for this function, which may
+ /// depend on the ABI.
+ unsigned EffectiveCallingConvention : 8;
+
+ /// The clang::CallingConv that this was originally created with.
+ unsigned ASTCallingConvention : 8;
+
+ /// Whether this function is noreturn.
+ unsigned NoReturn : 1;
+
+ /// Whether this function is returns-retained.
+ unsigned ReturnsRetained : 1;
+
+ /// How many arguments to pass inreg.
+ unsigned HasRegParm : 1;
+ unsigned RegParm : 4;
+
+ RequiredArgs Required;
+
+ unsigned NumArgs;
+ ArgInfo *getArgsBuffer() {
+ return reinterpret_cast<ArgInfo*>(this+1);
+ }
+ const ArgInfo *getArgsBuffer() const {
+ return reinterpret_cast<const ArgInfo*>(this + 1);
+ }
+
+ CGFunctionInfo() : Required(RequiredArgs::All) {}
+
+public:
+ static CGFunctionInfo *create(unsigned llvmCC,
+ const FunctionType::ExtInfo &extInfo,
+ CanQualType resultType,
+ ArrayRef<CanQualType> argTypes,
+ RequiredArgs required);
+
+ typedef const ArgInfo *const_arg_iterator;
+ typedef ArgInfo *arg_iterator;
+
+ const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
+ const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
+ arg_iterator arg_begin() { return getArgsBuffer() + 1; }
+ arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
+
+ unsigned arg_size() const { return NumArgs; }
+
+ bool isVariadic() const { return Required.allowsOptionalArgs(); }
+ RequiredArgs getRequiredArgs() const { return Required; }
+
+ bool isNoReturn() const { return NoReturn; }
+
+ /// In ARC, whether this function retains its return value. This
+ /// is not always reliable for call sites.
+ bool isReturnsRetained() const { return ReturnsRetained; }
+
+ /// getASTCallingConvention() - Return the AST-specified calling
+ /// convention.
+ CallingConv getASTCallingConvention() const {
+ return CallingConv(ASTCallingConvention);
+ }
+
+ /// getCallingConvention - Return the user specified calling
+ /// convention, which has been translated into an LLVM CC.
+ unsigned getCallingConvention() const { return CallingConvention; }
+
+ /// getEffectiveCallingConvention - Return the actual calling convention to
+ /// use, which may depend on the ABI.
+ unsigned getEffectiveCallingConvention() const {
+ return EffectiveCallingConvention;
+ }
+ void setEffectiveCallingConvention(unsigned Value) {
+ EffectiveCallingConvention = Value;
+ }
+
+ bool getHasRegParm() const { return HasRegParm; }
+ unsigned getRegParm() const { return RegParm; }
+
+ FunctionType::ExtInfo getExtInfo() const {
+ return FunctionType::ExtInfo(isNoReturn(),
+ getHasRegParm(), getRegParm(),
+ getASTCallingConvention(),
+ isReturnsRetained());
+ }
+
+ CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+
+ ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
+ const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ ID.AddInteger(getASTCallingConvention());
+ ID.AddBoolean(NoReturn);
+ ID.AddBoolean(ReturnsRetained);
+ ID.AddBoolean(HasRegParm);
+ ID.AddInteger(RegParm);
+ ID.AddInteger(Required.getOpaqueData());
+ getReturnType().Profile(ID);
+ for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
+ it->type.Profile(ID);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const FunctionType::ExtInfo &info,
+ RequiredArgs required,
+ CanQualType resultType,
+ ArrayRef<CanQualType> argTypes) {
+ ID.AddInteger(info.getCC());
+ ID.AddBoolean(info.getNoReturn());
+ ID.AddBoolean(info.getProducesResult());
+ ID.AddBoolean(info.getHasRegParm());
+ ID.AddInteger(info.getRegParm());
+ ID.AddInteger(required.getOpaqueData());
+ resultType.Profile(ID);
+ for (ArrayRef<CanQualType>::iterator
+ i = argTypes.begin(), e = argTypes.end(); i != e; ++i) {
+ i->Profile(ID);
+ }
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h
new file mode 100644
index 000000000000..81e2cdc1901b
--- /dev/null
+++ b/include/clang/CodeGen/CodeGenABITypes.h
@@ -0,0 +1,80 @@
+//==---- CodeGenABITypes.h - Convert Clang types to LLVM types for ABI -----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CodeGenABITypes is a simple interface for getting LLVM types for
+// the parameters and the return value of a function given the Clang
+// types.
+//
+// The class is implemented as a public wrapper around the private
+// CodeGenTypes class in lib/CodeGen.
+//
+// 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
+// these parameters are stored in.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_ABITYPES_H
+#define LLVM_CLANG_CODEGEN_ABITYPES_H
+
+#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
+
+namespace llvm {
+ class DataLayout;
+ class Module;
+}
+
+namespace clang {
+class ASTContext;
+class CXXRecordDecl;
+class CodeGenOptions;
+class DiagnosticsEngine;
+class ObjCMethodDecl;
+
+namespace CodeGen {
+class CGFunctionInfo;
+class CodeGenModule;
+
+class CodeGenABITypes
+{
+public:
+ CodeGenABITypes(ASTContext &C, const CodeGenOptions &CodeGenOpts,
+ llvm::Module &M, const llvm::DataLayout &TD,
+ DiagnosticsEngine &Diags);
+
+ ~CodeGenABITypes();
+
+ /// These methods all forward to methods in the private implementation class
+ /// CodeGenTypes.
+
+ const CGFunctionInfo &arrangeObjCMessageSendSignature(
+ const ObjCMethodDecl *MD,
+ QualType receiverType);
+ const CGFunctionInfo &arrangeFreeFunctionType(
+ CanQual<FunctionProtoType> Ty);
+ const CGFunctionInfo &arrangeFreeFunctionType(
+ CanQual<FunctionNoProtoType> Ty);
+ const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP);
+ const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
+ llvm::ArrayRef<CanQualType> argTypes,
+ FunctionType::ExtInfo info,
+ RequiredArgs args);
+
+private:
+ CodeGen::CodeGenModule *CGM;
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 4057e48f69a4..289dbe3ee4f8 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -14,9 +14,14 @@
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
+namespace llvm {
+namespace opt {
+ class Arg;
+}
+}
+
namespace clang {
namespace driver {
- class Arg;
/// Action - Represent an abstract compilation step to perform.
///
@@ -94,11 +99,12 @@ public:
class InputAction : public Action {
virtual void anchor();
- const Arg &Input;
+ const llvm::opt::Arg &Input;
+
public:
- InputAction(const Arg &_Input, types::ID _Type);
+ InputAction(const llvm::opt::Arg &_Input, types::ID _Type);
- const Arg &getInputArg() const { return Input; }
+ const llvm::opt::Arg &getInputArg() const { return Input; }
static bool classof(const Action *A) {
return A->getKind() == InputClass;
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
deleted file mode 100644
index 662a2e2c618b..000000000000
--- a/include/clang/Driver/Arg.h
+++ /dev/null
@@ -1,133 +0,0 @@
-//===--- Arg.h - Parsed Argument Classes ------------------------*- 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 the clang::driver::Arg class for parsed arguments.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_ARG_H_
-#define CLANG_DRIVER_ARG_H_
-
-#include "Util.h"
-#include "clang/Driver/Option.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include <string>
-
-namespace clang {
-namespace driver {
- class ArgList;
-
- /// \brief A concrete instance of a particular driver option.
- ///
- /// The Arg class encodes just enough information to be able to
- /// derive the argument values efficiently. In addition, Arg
- /// instances have an intrusive double linked list which is used by
- /// ArgList to provide efficient iteration over all instances of a
- /// particular option.
- class Arg {
- Arg(const Arg &) LLVM_DELETED_FUNCTION;
- void operator=(const Arg &) LLVM_DELETED_FUNCTION;
-
- private:
- /// \brief The option this argument is an instance of.
- const Option Opt;
-
- /// \brief The argument this argument was derived from (during tool chain
- /// argument translation), if any.
- const Arg *BaseArg;
-
- /// \brief How this instance of the option was spelled.
- StringRef Spelling;
-
- /// \brief The index at which this argument appears in the containing
- /// ArgList.
- unsigned Index;
-
- /// \brief Was this argument used to affect compilation?
- ///
- /// This is used for generating "argument unused" diagnostics.
- mutable unsigned Claimed : 1;
-
- /// \brief Does this argument own its values?
- mutable unsigned OwnsValues : 1;
-
- /// \brief The argument values, as C strings.
- SmallVector<const char *, 2> Values;
-
- public:
- Arg(const Option Opt, StringRef Spelling, unsigned Index,
- const Arg *BaseArg = 0);
- Arg(const Option Opt, StringRef Spelling, unsigned Index,
- const char *Value0, const Arg *BaseArg = 0);
- Arg(const Option Opt, StringRef Spelling, unsigned Index,
- const char *Value0, const char *Value1, const Arg *BaseArg = 0);
- ~Arg();
-
- Option getOption() const { return Opt; }
- StringRef getSpelling() const { return Spelling; }
- unsigned getIndex() const { return Index; }
-
- /// \brief Return the base argument which generated this arg.
- ///
- /// This is either the argument itself or the argument it was
- /// derived from during tool chain specific argument translation.
- const Arg &getBaseArg() const {
- return BaseArg ? *BaseArg : *this;
- }
- void setBaseArg(const Arg *_BaseArg) {
- BaseArg = _BaseArg;
- }
-
- bool getOwnsValues() const { return OwnsValues; }
- void setOwnsValues(bool Value) const { OwnsValues = Value; }
-
- bool isClaimed() const { return getBaseArg().Claimed; }
-
- /// \brief Set the Arg claimed bit.
- void claim() const { getBaseArg().Claimed = true; }
-
- unsigned getNumValues() const { return Values.size(); }
- const char *getValue(unsigned N = 0) const {
- return Values[N];
- }
-
- SmallVectorImpl<const char*> &getValues() {
- return Values;
- }
-
- bool containsValue(StringRef Value) const {
- for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- if (Values[i] == Value)
- return true;
- return false;
- }
-
- /// \brief Append the argument onto the given array as strings.
- void render(const ArgList &Args, ArgStringList &Output) const;
-
- /// \brief Append the argument, render as an input, onto the given
- /// array as strings.
- ///
- /// The distinction is that some options only render their values
- /// when rendered as a input (e.g., Xlinker).
- void renderAsInput(const ArgList &Args, ArgStringList &Output) const;
-
- void dump() const;
-
- /// \brief Return a formatted version of the argument and
- /// its values, for debugging and diagnostics.
- std::string getAsString(const ArgList &Args) const;
- };
-
-} // end namespace driver
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
deleted file mode 100644
index 9db170c4a254..000000000000
--- a/include/clang/Driver/ArgList.h
+++ /dev/null
@@ -1,442 +0,0 @@
-//===--- ArgList.h - Argument List Management ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_ARGLIST_H_
-#define CLANG_DRIVER_ARGLIST_H_
-
-#include "clang/Basic/LLVM.h"
-#include "clang/Driver/OptSpecifier.h"
-#include "clang/Driver/Option.h"
-#include "clang/Driver/Util.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include <list>
-#include <string>
-#include <vector>
-
-namespace clang {
- class DiagnosticsEngine;
-
-namespace driver {
- class Arg;
- class ArgList;
- class Option;
-
- /// arg_iterator - Iterates through arguments stored inside an ArgList.
- class arg_iterator {
- /// The current argument.
- SmallVectorImpl<Arg*>::const_iterator Current;
-
- /// The argument list we are iterating over.
- const ArgList &Args;
-
- /// Optional filters on the arguments which will be match. Most clients
- /// should never want to iterate over arguments without filters, so we won't
- /// bother to factor this into two separate iterator implementations.
- //
- // FIXME: Make efficient; the idea is to provide efficient iteration over
- // all arguments which match a particular id and then just provide an
- // iterator combinator which takes multiple iterators which can be
- // efficiently compared and returns them in order.
- OptSpecifier Id0, Id1, Id2;
-
- void SkipToNextArg();
-
- public:
- typedef Arg * const * value_type;
- typedef Arg * const & reference;
- typedef Arg * const * pointer;
- typedef std::forward_iterator_tag iterator_category;
- typedef std::ptrdiff_t difference_type;
-
- arg_iterator(SmallVectorImpl<Arg*>::const_iterator it,
- const ArgList &_Args, OptSpecifier _Id0 = 0U,
- OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U)
- : Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) {
- SkipToNextArg();
- }
-
- operator const Arg*() { return *Current; }
- reference operator*() const { return *Current; }
- pointer operator->() const { return Current; }
-
- arg_iterator &operator++() {
- ++Current;
- SkipToNextArg();
- return *this;
- }
-
- arg_iterator operator++(int) {
- arg_iterator tmp(*this);
- ++(*this);
- return tmp;
- }
-
- friend bool operator==(arg_iterator LHS, arg_iterator RHS) {
- return LHS.Current == RHS.Current;
- }
- friend bool operator!=(arg_iterator LHS, arg_iterator RHS) {
- return !(LHS == RHS);
- }
- };
-
- /// ArgList - Ordered collection of driver arguments.
- ///
- /// The ArgList class manages a list of Arg instances as well as
- /// auxiliary data and convenience methods to allow Tools to quickly
- /// check for the presence of Arg instances for a particular Option
- /// and to iterate over groups of arguments.
- class ArgList {
- private:
- ArgList(const ArgList &) LLVM_DELETED_FUNCTION;
- void operator=(const ArgList &) LLVM_DELETED_FUNCTION;
-
- public:
- typedef SmallVector<Arg*, 16> arglist_type;
- typedef arglist_type::iterator iterator;
- typedef arglist_type::const_iterator const_iterator;
- typedef arglist_type::reverse_iterator reverse_iterator;
- typedef arglist_type::const_reverse_iterator const_reverse_iterator;
-
- private:
- /// The internal list of arguments.
- arglist_type Args;
-
- protected:
- ArgList();
-
- public:
- virtual ~ArgList();
-
- /// @name Arg Access
- /// @{
-
- /// append - Append \p A to the arg list.
- void append(Arg *A);
-
- arglist_type &getArgs() { return Args; }
- const arglist_type &getArgs() const { return Args; }
-
- unsigned size() const { return Args.size(); }
-
- /// @}
- /// @name Arg Iteration
- /// @{
-
- iterator begin() { return Args.begin(); }
- iterator end() { return Args.end(); }
-
- reverse_iterator rbegin() { return Args.rbegin(); }
- reverse_iterator rend() { return Args.rend(); }
-
- const_iterator begin() const { return Args.begin(); }
- const_iterator end() const { return Args.end(); }
-
- const_reverse_iterator rbegin() const { return Args.rbegin(); }
- const_reverse_iterator rend() const { return Args.rend(); }
-
- arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U,
- OptSpecifier Id2 = 0U) const {
- return arg_iterator(Args.begin(), *this, Id0, Id1, Id2);
- }
- arg_iterator filtered_end() const {
- return arg_iterator(Args.end(), *this);
- }
-
- /// @}
- /// @name Arg Removal
- /// @{
-
- /// eraseArg - Remove any option matching \p Id.
- void eraseArg(OptSpecifier Id);
-
- /// @}
- /// @name Arg Access
- /// @{
-
- /// hasArg - Does the arg list contain any option matching \p Id.
- ///
- /// \p Claim Whether the argument should be claimed, if it exists.
- bool hasArgNoClaim(OptSpecifier Id) const {
- return getLastArgNoClaim(Id) != 0;
- }
- bool hasArg(OptSpecifier Id) const {
- return getLastArg(Id) != 0;
- }
- bool hasArg(OptSpecifier Id0, OptSpecifier Id1) const {
- return getLastArg(Id0, Id1) != 0;
- }
- bool hasArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const {
- return getLastArg(Id0, Id1, Id2) != 0;
- }
-
- /// getLastArg - Return the last argument matching \p Id, or null.
- ///
- /// \p Claim Whether the argument should be claimed, if it exists.
- Arg *getLastArgNoClaim(OptSpecifier Id) const;
- Arg *getLastArg(OptSpecifier Id) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
- OptSpecifier Id3) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
- OptSpecifier Id3, OptSpecifier Id4) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
- OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
- OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5,
- OptSpecifier Id6) const;
- Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
- OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5,
- OptSpecifier Id6, OptSpecifier Id7) const;
-
- /// getArgString - Return the input argument string at \p Index.
- virtual const char *getArgString(unsigned Index) const = 0;
-
- /// getNumInputArgStrings - Return the number of original argument strings,
- /// which are guaranteed to be the first strings in the argument string
- /// list.
- virtual unsigned getNumInputArgStrings() const = 0;
-
- /// @}
- /// @name Argument Lookup Utilities
- /// @{
-
- /// getLastArgValue - Return the value of the last argument, or a default.
- StringRef getLastArgValue(OptSpecifier Id,
- StringRef Default = "") const;
-
- /// getLastArgValue - 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.
- int getLastArgIntValue(OptSpecifier Id, int Default,
- DiagnosticsEngine *Diags = 0) const;
-
- /// getLastArgValue - Return the value of the last argument as an integer,
- /// or a default. Emits an error if the argument is given, but non-integral.
- int getLastArgIntValue(OptSpecifier Id, int Default,
- DiagnosticsEngine &Diags) const {
- return getLastArgIntValue(Id, Default, &Diags);
- }
-
- /// getAllArgValues - Get the values of all instances of the given argument
- /// as strings.
- std::vector<std::string> getAllArgValues(OptSpecifier Id) const;
-
- /// @}
- /// @name Translation Utilities
- /// @{
-
- /// hasFlag - Given an option \p Pos and its negative form \p Neg, return
- /// true if the option is present, false if the negation is present, and
- /// \p Default if neither option is given. If both the option and its
- /// negation are present, the last one wins.
- bool hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default = true) const;
-
- /// hasFlag - Given an option \p Pos, an alias \p PosAlias and its negative
- /// form \p Neg, return true if the option or its alias is present, false if
- /// the negation is present, and \p Default if none of the options are
- /// given. If multiple options are present, the last one wins.
- bool hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg,
- bool Default = true) const;
-
- /// AddLastArg - Render only the last argument match \p Id0, if present.
- void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const;
- void AddLastArg(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const;
-
- /// AddAllArgs - Render all arguments matching the given ids.
- void AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const;
-
- /// AddAllArgValues - Render the argument values of all arguments
- /// matching the given ids.
- void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const;
-
- /// AddAllArgsTranslated - Render all the arguments matching the
- /// given ids, but forced to separate args and using the provided
- /// name instead of the first option value.
- ///
- /// \param Joined - If true, render the argument as joined with
- /// the option specifier.
- void AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
- const char *Translation,
- bool Joined = false) const;
-
- /// ClaimAllArgs - Claim all arguments which match the given
- /// option id.
- void ClaimAllArgs(OptSpecifier Id0) const;
-
- /// ClaimAllArgs - Claim all arguments.
- ///
- void ClaimAllArgs() const;
-
- /// @}
- /// @name Arg Synthesis
- /// @{
-
- /// MakeArgString - Construct a constant string pointer whose
- /// lifetime will match that of the ArgList.
- virtual const char *MakeArgString(StringRef Str) const = 0;
- const char *MakeArgString(const char *Str) const {
- return MakeArgString(StringRef(Str));
- }
- const char *MakeArgString(std::string Str) const {
- return MakeArgString(StringRef(Str));
- }
- const char *MakeArgString(const Twine &Str) const;
-
- /// \brief Create an arg string for (\p LHS + \p RHS), reusing the
- /// string at \p Index if possible.
- const char *GetOrMakeJoinedArgString(unsigned Index, StringRef LHS,
- StringRef RHS) const;
-
- /// @}
-
- void dump();
- };
-
- class InputArgList : public ArgList {
- private:
- /// List of argument strings used by the contained Args.
- ///
- /// This is mutable since we treat the ArgList as being the list
- /// of Args, and allow routines to add new strings (to have a
- /// convenient place to store the memory) via MakeIndex.
- mutable ArgStringList ArgStrings;
-
- /// Strings for synthesized arguments.
- ///
- /// This is mutable since we treat the ArgList as being the list
- /// of Args, and allow routines to add new strings (to have a
- /// convenient place to store the memory) via MakeIndex.
- mutable std::list<std::string> SynthesizedStrings;
-
- /// The number of original input argument strings.
- unsigned NumInputArgStrings;
-
- public:
- InputArgList(const char* const *ArgBegin, const char* const *ArgEnd);
- ~InputArgList();
-
- virtual const char *getArgString(unsigned Index) const {
- return ArgStrings[Index];
- }
-
- virtual unsigned getNumInputArgStrings() const {
- return NumInputArgStrings;
- }
-
- /// @name Arg Synthesis
- /// @{
-
- public:
- /// MakeIndex - Get an index for the given string(s).
- unsigned MakeIndex(StringRef String0) const;
- unsigned MakeIndex(StringRef String0, StringRef String1) const;
-
- virtual const char *MakeArgString(StringRef Str) const;
-
- /// @}
- };
-
- /// DerivedArgList - An ordered collection of driver arguments,
- /// whose storage may be in another argument list.
- class DerivedArgList : public ArgList {
- const InputArgList &BaseArgs;
-
- /// The list of arguments we synthesized.
- mutable arglist_type SynthesizedArgs;
-
- public:
- /// Construct a new derived arg list from \p BaseArgs.
- DerivedArgList(const InputArgList &BaseArgs);
- ~DerivedArgList();
-
- virtual const char *getArgString(unsigned Index) const {
- return BaseArgs.getArgString(Index);
- }
-
- virtual unsigned getNumInputArgStrings() const {
- return BaseArgs.getNumInputArgStrings();
- }
-
- const InputArgList &getBaseArgs() const {
- return BaseArgs;
- }
-
- /// @name Arg Synthesis
- /// @{
-
- /// AddSynthesizedArg - Add a argument to the list of synthesized arguments
- /// (to be freed).
- void AddSynthesizedArg(Arg *A) {
- SynthesizedArgs.push_back(A);
- }
-
- virtual const char *MakeArgString(StringRef Str) const;
-
- /// AddFlagArg - Construct a new FlagArg for the given option \p Id and
- /// append it to the argument list.
- void AddFlagArg(const Arg *BaseArg, const Option Opt) {
- append(MakeFlagArg(BaseArg, Opt));
- }
-
- /// AddPositionalArg - Construct a new Positional arg for the given option
- /// \p Id, with the provided \p Value and append it to the argument
- /// list.
- void AddPositionalArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) {
- append(MakePositionalArg(BaseArg, Opt, Value));
- }
-
-
- /// AddSeparateArg - Construct a new Positional arg for the given option
- /// \p Id, with the provided \p Value and append it to the argument
- /// list.
- void AddSeparateArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) {
- append(MakeSeparateArg(BaseArg, Opt, Value));
- }
-
-
- /// AddJoinedArg - Construct a new Positional arg for the given option
- /// \p Id, with the provided \p Value and append it to the argument list.
- void AddJoinedArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) {
- append(MakeJoinedArg(BaseArg, Opt, Value));
- }
-
-
- /// MakeFlagArg - Construct a new FlagArg for the given option \p Id.
- Arg *MakeFlagArg(const Arg *BaseArg, const Option Opt) const;
-
- /// MakePositionalArg - Construct a new Positional arg for the
- /// given option \p Id, with the provided \p Value.
- Arg *MakePositionalArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const;
-
- /// MakeSeparateArg - Construct a new Positional arg for the
- /// given option \p Id, with the provided \p Value.
- Arg *MakeSeparateArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const;
-
- /// MakeJoinedArg - Construct a new Positional arg for the
- /// given option \p Id, with the provided \p Value.
- Arg *MakeJoinedArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const;
-
- /// @}
- };
-
-} // end namespace driver
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Driver/CC1AsOptions.h b/include/clang/Driver/CC1AsOptions.h
index 420a10138cba..345f50a57d5f 100644
--- a/include/clang/Driver/CC1AsOptions.h
+++ b/include/clang/Driver/CC1AsOptions.h
@@ -10,24 +10,27 @@
#ifndef CLANG_DRIVER_CC1ASOPTIONS_H
#define CLANG_DRIVER_CC1ASOPTIONS_H
+namespace llvm {
+namespace opt {
+ class OptTable;
+}
+}
+
namespace clang {
namespace driver {
- class OptTable;
namespace cc1asoptions {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define PREFIX(NAME, VALUE)
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) OPT_##ID,
#include "clang/Driver/CC1AsOptions.inc"
LastOption
#undef OPTION
-#undef PREFIX
};
}
- OptTable *createCC1AsOptTable();
+llvm::opt::OptTable *createCC1AsOptTable();
}
}
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index 2749bcd7779c..b536724f2425 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
// Include the common option parsing interfaces.
-include "OptParser.td"
+include "llvm/Option/OptParser.td"
//===----------------------------------------------------------------------===//
// Target Options
@@ -33,7 +33,7 @@ def I : JoinedOrSeparate<["-"], "I">, MetaVarName<"<directory>">,
HelpText<"Add directory to include search path">;
def n : Flag<["-"], "n">,
HelpText<"Don't automatically start assembly file with a text section">;
-def L : Flag<["-"], "L">,
+def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
HelpText<"Save temporary labels in the symbol table. "
"Note this may change .s semantics, it should almost never be used "
"on compiler generated code!">;
@@ -77,15 +77,12 @@ def show_inst : Flag<["-"], "show-inst">,
// Assemble Options
//===----------------------------------------------------------------------===//
-def relax_all : Flag<["-"], "relax-all">,
+def mrelax_all : Flag<["-"], "mrelax-all">,
HelpText<"Relax all fixups (for performance testing)">;
-def no_exec_stack : Flag<["--"], "noexecstack">,
+def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
-def fatal_warnings : Flag<["--"], "fatal-warnings">,
- HelpText<"Consider warnings as errors">;
-
def g : Flag<["-"], "g">, HelpText<"Generate source level debug information">;
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 96a50fc5c66a..85cfdcf3946b 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -23,6 +23,8 @@ def target_abi : Separate<["-"], "target-abi">,
HelpText<"Target a particular ABI type">;
def target_cpu : Separate<["-"], "target-cpu">,
HelpText<"Target a specific cpu type">;
+def mfpmath : Separate<["-"], "mfpmath">,
+ HelpText<"Which unit to use for fp math">;
def target_feature : Separate<["-"], "target-feature">,
HelpText<"Target specific attributes">;
def target_linker_version : Separate<["-"], "target-linker-version">,
@@ -136,6 +138,8 @@ def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
HelpText<"Turn on column location information.">;
def split_dwarf : Flag<["-"], "split-dwarf">,
HelpText<"Split out the dwarf .dwo sections">;
+def gnu_pubnames : Flag<["-"], "gnu-pubnames">,
+ HelpText<"Emit newer GNU style pubnames">;
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">,
@@ -161,8 +165,8 @@ def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfie
HelpText<"Use register sized accesses to bit-fields, when possible.">;
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
-def struct_path_tbaa : Flag<["-"], "struct-path-tbaa">,
- HelpText<"Turn on struct-path aware Type Based Alias Analysis">;
+def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
+ HelpText<"Turn off struct-path aware Type Based Alias Analysis">;
def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<["-"], "mcode-model">,
@@ -204,6 +208,14 @@ def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">,
HelpText<"Emit complete constructors and destructors as aliases when possible">;
def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">,
HelpText<"Link the given bitcode file before performing optimizations.">;
+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">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
@@ -213,6 +225,8 @@ def sys_header_deps : Flag<["-"], "sys-header-deps">,
HelpText<"Include system headers in dependency output">;
def header_include_file : Separate<["-"], "header-include-file">,
HelpText<"Filename (or -) to write header include output to">;
+def show_includes : Flag<["--"], "show-includes">,
+ HelpText<"Print cl.exe style /showIncludes to stderr">;
//===----------------------------------------------------------------------===//
// Diagnostic Options
@@ -290,6 +304,8 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
" nodes having a certain substring in a qualified name. Use"
" -ast-list to list all filterable declaration node names.">;
+def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">,
+ HelpText<"Include name lookup table dumps in AST dumps">;
def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">,
HelpText<"Do not automatically generate or update the global module index">;
@@ -320,8 +336,6 @@ def ast_list : Flag<["-"], "ast-list">,
HelpText<"Build ASTs and print the list of declaration node qualified names">;
def ast_dump : Flag<["-"], "ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
-def ast_dump_xml : Flag<["-"], "ast-dump-xml">,
- HelpText<"Build ASTs and then debug dump them in a verbose XML format">;
def ast_view : Flag<["-"], "ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
def print_decl_contexts : Flag<["-"], "print-decl-contexts">,
@@ -357,8 +371,6 @@ def arcmt_modify : Flag<["-"], "arcmt-modify">,
def arcmt_migrate : Flag<["-"], "arcmt-migrate">,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def relocatable_pch : Flag<["-", "--"], "relocatable-pch">,
- HelpText<"Whether to build a relocatable precompiled header">;
def print_stats : Flag<["-"], "print-stats">,
HelpText<"Print performance metrics and statistics">;
def fdump_record_layouts : Flag<["-"], "fdump-record-layouts">,
@@ -391,8 +403,6 @@ def main_file_name : Separate<["-"], "main-file-name">,
HelpText<"Main file name to use for debug info">;
def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
HelpText<"File name to use for split dwarf debug info output">;
-def fno_signed_char : Flag<["-"], "fno-signed-char">,
- HelpText<"Char is unsigned">;
def fno_wchar : Flag<["-"], "fno-wchar">,
HelpText<"Disable C++ builtin type wchar_t">;
def fconstant_string_class : Separate<["-"], "fconstant-string-class">,
@@ -404,8 +414,8 @@ 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">;
-def fobjc_default_synthesize_properties : Flag<["-"], "fobjc-default-synthesize-properties">,
- HelpText<"enable the default synthesis of Objective-C properties">;
+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">,
HelpText<"enable extended encoding of block type signature">;
def pic_level : Separate<["-"], "pic-level">,
@@ -432,8 +442,12 @@ def ftype_visibility : Separate<["-"], "ftype-visibility">,
HelpText<"Default type visibility">;
def ftemplate_depth : Separate<["-"], "ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
+def foperator_arrow_depth : Separate<["-"], "foperator-arrow-depth">,
+ HelpText<"Maximum number of 'operator->'s to call for a member access">;
def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">,
HelpText<"Maximum depth of recursive constexpr function calls">;
+def fconstexpr_steps : Separate<["-"], "fconstexpr-steps">,
+ HelpText<"Maximum number of steps in constexpr function evaluation">;
def fbracket_depth : Separate<["-"], "fbracket-depth">,
HelpText<"Maximum nesting level for parentheses, brackets, and braces">;
def fconst_strings : Flag<["-"], "fconst-strings">,
@@ -444,6 +458,8 @@ def fno_bitfield_type_align : Flag<["-"], "fno-bitfield-type-align">,
HelpText<"Ignore bit-field types when aligning structures">;
def ffake_address_space_map : Flag<["-"], "ffake-address-space-map">,
HelpText<"Use a fake address space map; OpenCL testing purposes only">;
+def faddress_space_map_mangling_EQ : Joined<["-"], "faddress-space-map-mangling=">, MetaVarName<"<yes|no|target>">,
+ HelpText<"Set the mode for address space map based mangling; OpenCL testing purposes only">;
def funknown_anytype : Flag<["-"], "funknown-anytype">,
HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">;
def fdebugger_support : Flag<["-"], "fdebugger-support">,
@@ -456,6 +472,10 @@ def fdeprecated_macro : Flag<["-"], "fdeprecated-macro">,
HelpText<"Defines the __DEPRECATED macro">;
def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">,
HelpText<"Undefines the __DEPRECATED macro">;
+def fsized_deallocation : Flag<["-"], "fsized-deallocation">,
+ HelpText<"Enable C++1y sized global deallocation functions">;
+def fobjc_subscripting_legacy_runtime : Flag<["-"], "fobjc-subscripting-legacy-runtime">,
+ HelpText<"Allow Objective-C array and dictionary subscripting in legacy runtime">;
//===----------------------------------------------------------------------===//
// Header Search Options
@@ -463,9 +483,6 @@ def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">,
def nostdsysteminc : Flag<["-"], "nostdsysteminc">,
HelpText<"Disable standard system #include directories">;
-def fmodule_name : Joined<["-"], "fmodule-name=">,
- MetaVarName<"<name>">,
- HelpText<"Specify the name of the module to build">;
def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">,
HelpText<"Disable the module hash">;
def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">,
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
new file mode 100644
index 000000000000..d17a63c62c92
--- /dev/null
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -0,0 +1,255 @@
+//===--- CLCompatOptions.td - Options for clang-cl ------------------------===//
+//
+// 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 options accepted by clang-cl.
+//
+//===----------------------------------------------------------------------===//
+
+def cl_Group : OptionGroup<"<clang-cl options>">,
+ HelpText<"CL.EXE COMPATIBILITY OPTIONS">;
+
+def cl_compile_Group : OptionGroup<"<clang-cl compile-only options>">,
+ Group<cl_Group>;
+
+def cl_ignored_Group : OptionGroup<"<clang-cl ignored options>">,
+ Group<cl_Group>;
+
+class CLFlag<string name> : Option<["/", "-"], name, KIND_FLAG>,
+ Group<cl_Group>, Flags<[CLOption, DriverOption]>;
+
+class CLCompileFlag<string name> : Option<["/", "-"], name, KIND_FLAG>,
+ Group<cl_compile_Group>, Flags<[CLOption, DriverOption]>;
+
+class CLIgnoredFlag<string name> : Option<["/", "-"], name, KIND_FLAG>,
+ Group<cl_ignored_Group>, Flags<[CLOption, DriverOption, HelpHidden]>;
+
+class CLJoined<string name> : Option<["/", "-"], name, KIND_JOINED>,
+ Group<cl_Group>, Flags<[CLOption, DriverOption]>;
+
+class CLCompileJoined<string name> : Option<["/", "-"], name, KIND_JOINED>,
+ Group<cl_compile_Group>, Flags<[CLOption, DriverOption]>;
+
+class CLIgnoredJoined<string name> : Option<["/", "-"], name, KIND_JOINED>,
+ Group<cl_ignored_Group>, Flags<[CLOption, DriverOption, HelpHidden]>;
+
+class CLJoinedOrSeparate<string name> : Option<["/", "-"], name,
+ KIND_JOINED_OR_SEPARATE>, Group<cl_Group>, Flags<[CLOption, DriverOption]>;
+
+class CLCompileJoinedOrSeparate<string name> : Option<["/", "-"], name,
+ KIND_JOINED_OR_SEPARATE>, Group<cl_compile_Group>,
+ Flags<[CLOption, DriverOption]>;
+
+class CLRemainingArgs<string name> : Option<["/", "-"], name,
+ KIND_REMAINING_ARGS>, Group<cl_Group>, Flags<[CLOption, DriverOption]>;
+
+// Aliases:
+// (We don't put any of these in cl_compile_Group as the options they alias are
+// already in the right group.)
+
+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_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">,
+ MetaVarName<"<macro[=value]>">, Alias<D>;
+def _SLASH_GR : CLFlag<"GR">, HelpText<"Enable RTTI">, Alias<frtti>;
+def _SLASH_GR_ : CLFlag<"GR-">, HelpText<"Disable RTTI">, Alias<fno_rtti>;
+def _SLASH_GF_ : CLFlag<"GF-">, HelpText<"Disable string pooling">,
+ Alias<fwritable_strings>;
+def _SLASH_help : CLFlag<"help">, Alias<help>,
+ HelpText<"Display available options">;
+def _SLASH_HELP : CLFlag<"HELP">, Alias<help>;
+def _SLASH_I : CLJoinedOrSeparate<"I">,
+ HelpText<"Add directory to include search path">, MetaVarName<"<dir>">,
+ Alias<I>;
+def _SLASH_J : CLFlag<"J">, HelpText<"Make char type unsigned">,
+ Alias<funsigned_char>;
+def _SLASH_O : CLJoined<"O">, HelpText<"Optimization level">,
+ MetaVarName<"<n>">, Alias<O>;
+def _SLASH_Ob0 : CLFlag<"Ob0">, HelpText<"Disable inlining">,
+ Alias<fno_inline>;
+def _SLASH_Od : CLFlag<"Od">, HelpText<"Disable optimization">, Alias<O0>;
+def _SLASH_Oi : CLFlag<"Oi">, HelpText<"Enable use of builtin functions">,
+ Alias<fbuiltin>;
+def _SLASH_Oi_ : CLFlag<"Oi-">, HelpText<"Disable use of builtin functions">,
+ Alias<fno_builtin>;
+def _SLASH_Os : CLFlag<"Os">, HelpText<"Optimize for size">, Alias<O>,
+ AliasArgs<["s"]>;
+def _SLASH_Ot : CLFlag<"Ot">, HelpText<"Optimize for speed">, Alias<O>,
+ AliasArgs<["2"]>;
+def _SLASH_Ox : CLFlag<"Ox">, HelpText<"Maximum optimization">, Alias<O>,
+ AliasArgs<["3"]>;
+def _SLASH_Oy : CLFlag<"Oy">, HelpText<"Enable frame pointer omission">,
+ Alias<fomit_frame_pointer>;
+def _SLASH_Oy_ : CLFlag<"Oy-">, HelpText<"Disable frame pointer omission">,
+ Alias<fno_omit_frame_pointer>;
+def _SLASH_P : CLFlag<"P">, HelpText<"Only run the preprocessor">, Alias<E>;
+def _SLASH_QUESTION : CLFlag<"?">, Alias<help>,
+ HelpText<"Display available options">;
+def _SLASH_showIncludes : CLFlag<"showIncludes">,
+ HelpText<"Print info about included files to stderr">,
+ Alias<show_includes>;
+def _SLASH_U : CLJoinedOrSeparate<"U">, HelpText<"Undefine macro">,
+ MetaVarName<"<macro>">, Alias<U>;
+def _SLASH_W0 : CLFlag<"W0">, HelpText<"Disable all warnings">, Alias<w>;
+def _SLASH_W1 : CLFlag<"W1">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_W2 : CLFlag<"W2">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_W3 : CLFlag<"W3">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_W4 : CLFlag<"W4">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_WX : CLFlag<"WX">, HelpText<"Treat warnings as errors">,
+ Alias<W_Joined>, AliasArgs<["error"]>;
+def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">,
+ Alias<W_Joined>, AliasArgs<["no-error"]>;
+def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias<w>;
+def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">,
+ Alias<fsyntax_only>;
+
+
+// Non-aliases:
+
+def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>;
+
+def _SLASH_FA : CLFlag<"FA">,
+ HelpText<"Output assembly code file during compilation">;
+def _SLASH_Fa : CLJoined<"Fa">,
+ HelpText<"Output assembly code to this file during compilation">,
+ MetaVarName<"<file or directory>">;
+def _SLASH_fallback : CLCompileFlag<"fallback">,
+ HelpText<"Fall back to cl.exe if clang-cl fails to compile">;
+def _SLASH_FI : CLJoinedOrSeparate<"FI">,
+ HelpText<"Include file before parsing">, Alias<include_>;
+def _SLASH_Fe : CLJoined<"Fe">,
+ HelpText<"Set output executable file or directory (ends in / or \\)">,
+ MetaVarName<"<file or directory>">;
+def _SLASH_Fo : CLCompileJoined<"Fo">,
+ HelpText<"Set output object file, or directory (ends in / or \\)">,
+ MetaVarName<"<file or directory>">;
+def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
+def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
+def _SLASH_link : CLRemainingArgs<"link">,
+ HelpText<"Forward options to the linker">, MetaVarName<"<options>">;
+def _SLASH_MD : Option<["/", "-"], "MD", KIND_FLAG>, Group<_SLASH_M_Group>,
+ Flags<[CLOption, DriverOption]>, HelpText<"Use DLL run-time">;
+def _SLASH_MDd : Option<["/", "-"], "MDd", KIND_FLAG>, Group<_SLASH_M_Group>,
+ Flags<[CLOption, DriverOption]>, HelpText<"Use DLL debug run-time">;
+def _SLASH_MT : Option<["/", "-"], "MT", KIND_FLAG>, Group<_SLASH_M_Group>,
+ Flags<[CLOption, DriverOption]>, HelpText<"Use static run-time">;
+def _SLASH_MTd : Option<["/", "-"], "MTd", KIND_FLAG>, Group<_SLASH_M_Group>,
+ Flags<[CLOption, DriverOption]>, HelpText<"Use static debug run-time">;
+def _SLASH_Tc : CLCompileJoinedOrSeparate<"Tc">,
+ HelpText<"Specify a C source file">, MetaVarName<"<filename>">;
+def _SLASH_TC : CLCompileFlag<"TC">, HelpText<"Treat all source files as C">;
+def _SLASH_Tp : CLCompileJoinedOrSeparate<"Tp">,
+ HelpText<"Specify a C++ source file">, MetaVarName<"<filename>">;
+def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">;
+
+
+// Ignored:
+
+def _SLASH_analyze_ : CLIgnoredFlag<"analyze-">;
+def _SLASH_errorReport : CLIgnoredJoined<"errorReport">;
+def _SLASH_FS : CLIgnoredFlag<"FS">, HelpText<"Force synchronous PDB writes">;
+def _SLASH_GF : CLIgnoredFlag<"GF">;
+def _SLASH_GS_ : CLIgnoredFlag<"GS-">;
+def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
+def _SLASH_nologo : CLIgnoredFlag<"nologo">;
+def _SLASH_Ob1 : CLIgnoredFlag<"Ob1">;
+def _SLASH_Ob2 : CLIgnoredFlag<"Ob2">;
+def _SLASH_RTC : CLIgnoredJoined<"RTC">;
+def _SLASH_sdl : CLIgnoredFlag<"sdl">;
+def _SLASH_sdl_ : CLIgnoredFlag<"sdl-">;
+def _SLASH_vmg : CLIgnoredFlag<"vmg">;
+def _SLASH_w : CLIgnoredJoined<"w">;
+def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">;
+def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">;
+def _SLASH_Zm : CLIgnoredJoined<"Zm">;
+
+
+// Unsupported:
+
+def _SLASH_AI : CLJoined<"AI">;
+def _SLASH_arch : CLJoined<"arch:">;
+def _SLASH_bigobj : CLFlag<"bigobj">;
+def _SLASH_clr : CLJoined<"clr">;
+def _SLASH_doc : CLJoined<"doc">;
+def _SLASH_E : CLFlag<"E">;
+def _SLASH_EH : CLJoined<"EH">;
+def _SLASH_EP : CLFlag<"EP">;
+def _SLASH_FA_joined : CLJoined<"FA">;
+def _SLASH_favor : CLJoined<"favor">;
+def _SLASH_FC : CLFlag<"FC">;
+def _SLASH_F : CLFlag<"F">;
+def _SLASH_Fd : CLJoined<"Fd">;
+def _SLASH_Fi : CLJoined<"Fi">;
+def _SLASH_Fm : CLJoined<"Fm">;
+def _SLASH_fp : CLJoined<"fp">;
+def _SLASH_Fp : CLJoined<"Fp">;
+def _SLASH_Fr : CLJoined<"Fr">;
+def _SLASH_FR : CLJoined<"FR">;
+def _SLASH_FU : CLJoinedOrSeparate<"FU">;
+def _SLASH_Fx : CLFlag<"Fx">;
+def _SLASH_G1 : CLFlag<"G1">;
+def _SLASH_G2 : CLFlag<"G2">;
+def _SLASH_GA : CLFlag<"GA">;
+def _SLASH_Gd : CLFlag<"Gd">;
+def _SLASH_Ge : CLFlag<"Ge">;
+def _SLASH_Gh : CLFlag<"Gh">;
+def _SLASH_GH : CLFlag<"GH">;
+def _SLASH_GL : CLFlag<"GL">;
+def _SLASH_GL_ : CLFlag<"GL-">;
+def _SLASH_Gm : CLFlag<"Gm">;
+def _SLASH_Gm_ : CLFlag<"Gm-">;
+def _SLASH_Gr : CLFlag<"Gr">;
+def _SLASH_GS : CLFlag<"GS">;
+def _SLASH_Gs : CLJoined<"Gs">;
+def _SLASH_GT : CLFlag<"GT">;
+def _SLASH_GX : CLFlag<"GX">;
+def _SLASH_Gy : CLFlag<"Gy">;
+def _SLASH_Gy_ : CLFlag<"Gy-">;
+def _SLASH_Gz : CLFlag<"Gz">;
+def _SLASH_GZ : CLFlag<"GZ">;
+def _SLASH_H : CLFlag<"H">;
+def _SLASH_homeparams : CLFlag<"homeparams">;
+def _SLASH_hotpatch : CLFlag<"hotpatch">;
+def _SLASH_kernel : CLFlag<"kernel">;
+def _SLASH_LN : CLFlag<"LN">;
+def _SLASH_MP : CLJoined<"MP">;
+def _SLASH_o : CLJoinedOrSeparate<"o">;
+def _SLASH_openmp : CLFlag<"openmp">;
+def _SLASH_Qfast_transcendentals : CLFlag<"Qfast_transcendentals">;
+def _SLASH_QIfist : CLFlag<"QIfist">;
+def _SLASH_Qimprecise_fwaits : CLFlag<"Qimprecise_fwaits">;
+def _SLASH_Qpar : CLFlag<"Qpar">;
+def _SLASH_Qvec_report : CLJoined<"Qvec-report">;
+def _SLASH_u : CLFlag<"u">;
+def _SLASH_V : CLFlag<"V">;
+def _SLASH_vd : CLJoined<"vd">;
+def _SLASH_vmb : CLFlag<"vmb">;
+def _SLASH_vmm : CLFlag<"vmm">;
+def _SLASH_vms : CLFlag<"vms">;
+def _SLASH_vmv : CLFlag<"vmv">;
+def _SLASH_volatile : CLFlag<"volatile">;
+def _SLASH_WL : CLFlag<"WL">;
+def _SLASH_Wp64 : CLFlag<"Wp64">;
+def _SLASH_X : CLFlag<"X">;
+def _SLASH_Yc : CLJoined<"Yc">;
+def _SLASH_Y_ : CLFlag<"Y-">;
+def _SLASH_Yd : CLFlag<"Yd">;
+def _SLASH_Yl : CLJoined<"Yl">;
+def _SLASH_Yu : CLJoined<"Yu">;
+def _SLASH_Z7 : CLFlag<"Z7">;
+def _SLASH_Za : CLFlag<"Za">;
+def _SLASH_Zc : CLJoined<"Zc:">;
+def _SLASH_Ze : CLFlag<"Ze">;
+def _SLASH_Zg : CLFlag<"Zg">;
+def _SLASH_Zi : CLFlag<"Zi">;
+def _SLASH_ZI : CLFlag<"ZI">;
+def _SLASH_Zl : CLFlag<"Zl">;
+def _SLASH_Zp : CLFlag<"Zp">;
+def _SLASH_ZW : CLJoined<"ZW">;
diff --git a/include/clang/Driver/CMakeLists.txt b/include/clang/Driver/CMakeLists.txt
index 1277d51edb82..5961cac20ccf 100644
--- a/include/clang/Driver/CMakeLists.txt
+++ b/include/clang/Driver/CMakeLists.txt
@@ -1,7 +1,7 @@
-clang_tablegen(Options.inc -gen-opt-parser-defs
- SOURCE Options.td
- TARGET ClangDriverOptions)
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ClangDriverOptions)
-clang_tablegen(CC1AsOptions.inc -gen-opt-parser-defs
- SOURCE CC1AsOptions.td
- TARGET ClangCC1AsOptions)
+set(LLVM_TARGET_DEFINITIONS CC1AsOptions.td)
+tablegen(LLVM CC1AsOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ClangCC1AsOptions)
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 15c5e40e495a..3493e4f1509b 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -15,11 +15,16 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Path.h"
+namespace llvm {
+namespace opt {
+ class DerivedArgList;
+ class InputArgList;
+}
+}
+
namespace clang {
namespace driver {
- class DerivedArgList;
class Driver;
- class InputArgList;
class JobAction;
class JobList;
class ToolChain;
@@ -34,11 +39,11 @@ class Compilation {
const ToolChain &DefaultToolChain;
/// The original (untranslated) input argument list.
- InputArgList *Args;
+ llvm::opt::InputArgList *Args;
/// The driver translated arguments. Note that toolchains may perform their
/// own argument translation.
- DerivedArgList *TranslatedArgs;
+ llvm::opt::DerivedArgList *TranslatedArgs;
/// The list of actions.
ActionList Actions;
@@ -48,11 +53,11 @@ class Compilation {
/// Cache of translated arguments for a particular tool chain and bound
/// architecture.
- llvm::DenseMap<std::pair<const ToolChain*, const char*>,
- DerivedArgList*> TCArgs;
+ llvm::DenseMap<std::pair<const ToolChain *, const char *>,
+ llvm::opt::DerivedArgList *> TCArgs;
/// Temporary files which should be removed on exit.
- ArgStringList TempFiles;
+ llvm::opt::ArgStringList TempFiles;
/// Result files which should be removed on failure.
ArgStringMap ResultFiles;
@@ -62,22 +67,23 @@ class Compilation {
ArgStringMap FailureResultFiles;
/// Redirection for stdout, stderr, etc.
- const llvm::sys::Path **Redirects;
+ const StringRef **Redirects;
public:
Compilation(const Driver &D, const ToolChain &DefaultToolChain,
- InputArgList *Args, DerivedArgList *TranslatedArgs);
+ llvm::opt::InputArgList *Args,
+ llvm::opt::DerivedArgList *TranslatedArgs);
~Compilation();
const Driver &getDriver() const { return TheDriver; }
const ToolChain &getDefaultToolChain() const { return DefaultToolChain; }
- const InputArgList &getInputArgs() const { return *Args; }
+ const llvm::opt::InputArgList &getInputArgs() const { return *Args; }
- const DerivedArgList &getArgs() const { return *TranslatedArgs; }
+ const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; }
- DerivedArgList &getArgs() { return *TranslatedArgs; }
+ llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; }
ActionList &getActions() { return Actions; }
const ActionList &getActions() const { return Actions; }
@@ -87,7 +93,7 @@ public:
void addCommand(Command *C) { Jobs.addJob(C); }
- const ArgStringList &getTempFiles() const { return TempFiles; }
+ const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
const ArgStringMap &getResultFiles() const { return ResultFiles; }
@@ -102,8 +108,8 @@ public:
/// tool chain \p TC (or the default tool chain, if TC is not specified).
///
/// \param BoundArch - The bound architecture name, or 0.
- const DerivedArgList &getArgsForToolChain(const ToolChain *TC,
- const char *BoundArch);
+ const llvm::opt::DerivedArgList &getArgsForToolChain(const ToolChain *TC,
+ const char *BoundArch);
/// addTempFile - Add a file to remove on exit, and returns its
/// argument.
@@ -136,7 +142,7 @@ public:
///
/// \param IssueErrors - Report failures as errors.
/// \return Whether all files were removed successfully.
- bool CleanupFileList(const ArgStringList &Files,
+ bool CleanupFileList(const llvm::opt::ArgStringList &Files,
bool IssueErrors = false) const;
/// CleanupFileMap - Remove the files in the given map.
@@ -149,23 +155,6 @@ public:
const JobAction *JA,
bool IssueErrors = false) const;
- /// PrintJob - Print one job in -### format.
- ///
- /// \param OS - The stream to print on.
- /// \param J - The job to print.
- /// \param Terminator - A string to print at the end of the line.
- /// \param Quote - Should separate arguments be quoted.
- void PrintJob(raw_ostream &OS, const Job &J,
- const char *Terminator, bool Quote) const;
-
- /// PrintDiagnosticJob - Print one job in -### format, but with the
- /// superfluous options removed, which are not necessary for
- /// reproducing the crash.
- ///
- /// \param OS - The stream to print on.
- /// \param J - The job to print.
- void PrintDiagnosticJob(raw_ostream &OS, const Job &J) const;
-
/// ExecuteCommand - Execute an actual command.
///
/// \param FailingCommand - For non-zero results, this will be set to the
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index d9053d1972aa..867444ea4e13 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -15,6 +15,7 @@
#include "clang/Driver/Phases.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
@@ -24,27 +25,41 @@
#include <set>
#include <string>
+namespace llvm {
+namespace opt {
+ class Arg;
+ class ArgList;
+ class DerivedArgList;
+ class InputArgList;
+ class OptTable;
+}
+}
+
namespace clang {
namespace driver {
+
class Action;
- class Arg;
- class ArgList;
class Command;
class Compilation;
- class DerivedArgList;
- class InputArgList;
class InputInfo;
class JobAction;
- class OptTable;
+ class SanitizerArgs;
class ToolChain;
/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
- OptTable *Opts;
+ llvm::opt::OptTable *Opts;
DiagnosticsEngine &Diags;
+ enum DriverMode {
+ GCCMode,
+ GXXMode,
+ CPPMode,
+ CLMode
+ } Mode;
+
public:
// Diag - Forwarding function for diagnostics.
DiagnosticBuilder Diag(unsigned DiagID) const {
@@ -79,6 +94,9 @@ public:
/// sysroot, if present
std::string SysRoot;
+ /// Dynamic loader prefix, if present
+ std::string DyldPrefix;
+
/// If the standard library is used
bool UseStdLib;
@@ -104,16 +122,17 @@ public:
const char *CCLogDiagnosticsFilename;
/// A list of inputs and their types for the given arguments.
- typedef SmallVector<std::pair<types::ID, const Arg*>, 16> InputList;
+ typedef SmallVector<std::pair<types::ID, const llvm::opt::Arg *>, 16>
+ InputList;
/// Whether the driver should follow g++ like behavior.
- unsigned CCCIsCXX : 1;
+ bool CCCIsCXX() const { return Mode == GXXMode; }
/// Whether the driver is just the preprocessor.
- unsigned CCCIsCPP : 1;
+ bool CCCIsCPP() const { return Mode == CPPMode; }
- /// Echo commands while executing (in -v style).
- unsigned CCCEcho : 1;
+ /// Whether the driver should follow cl.exe like behavior.
+ bool IsCLMode() const { return Mode == CLMode; }
/// Only print tool bindings, don't build any jobs.
unsigned CCCPrintBindings : 1;
@@ -163,12 +182,13 @@ private:
private:
/// TranslateInputArgs - Create a new derived argument list from the input
/// arguments, after applying the standard argument translations.
- DerivedArgList *TranslateInputArgs(const InputArgList &Args) const;
+ llvm::opt::DerivedArgList *
+ TranslateInputArgs(const llvm::opt::InputArgList &Args) const;
// getFinalPhase - Determine which compilation mode we are in and record
// which option we used to determine the final phase.
- phases::ID getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg = 0)
- const;
+ phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL,
+ llvm::opt::Arg **FinalPhaseArg = 0) const;
public:
Driver(StringRef _ClangExecutable,
@@ -183,8 +203,7 @@ public:
/// Name to use when invoking gcc/g++.
const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; }
-
- const OptTable &getOpts() const { return *Opts; }
+ const llvm::opt::OptTable &getOpts() const { return *Opts; }
const DiagnosticsEngine &getDiags() const { return Diags; }
@@ -226,9 +245,12 @@ public:
/// @name Driver Steps
/// @{
+ /// ParseDriverMode - Look for and handle the driver mode option in Args.
+ void ParseDriverMode(ArrayRef<const char *> Args);
+
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
- InputArgList *ParseArgStrings(ArrayRef<const char *> Args);
+ llvm::opt::InputArgList *ParseArgStrings(ArrayRef<const char *> Args);
/// BuildInputs - Construct the list of inputs and their types from
/// the given arguments.
@@ -237,7 +259,7 @@ public:
/// \param Args - The input arguments.
/// \param Inputs - The list to store the resulting compilation
/// inputs onto.
- void BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
+ void BuildInputs(const ToolChain &TC, const llvm::opt::DerivedArgList &Args,
InputList &Inputs) const;
/// BuildActions - Construct the list of actions to perform for the
@@ -246,7 +268,7 @@ public:
/// \param TC - The default host tool chain.
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
- void BuildActions(const ToolChain &TC, const DerivedArgList &Args,
+ void BuildActions(const ToolChain &TC, llvm::opt::DerivedArgList &Args,
const InputList &Inputs, ActionList &Actions) const;
/// BuildUniversalActions - Construct the list of actions to perform
@@ -255,7 +277,8 @@ public:
/// \param TC - The default host tool chain.
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
- void BuildUniversalActions(const ToolChain &TC, const DerivedArgList &Args,
+ void BuildUniversalActions(const ToolChain &TC,
+ llvm::opt::DerivedArgList &Args,
const InputList &BAInputs,
ActionList &Actions) const;
@@ -292,9 +315,6 @@ public:
/// \param ShowHidden - Show hidden options.
void PrintHelp(bool ShowHidden) const;
- /// PrintOptions - Print the list of arguments.
- void PrintOptions(const ArgList &Args) const;
-
/// PrintVersion - Print the driver version.
void PrintVersion(const Compilation &C, raw_ostream &OS) const;
@@ -324,10 +344,9 @@ public:
/// ConstructAction - Construct the appropriate action to do for
/// \p Phase on the \p Input, taking in to account arguments
/// like -fsyntax-only or --analyze.
- Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
+ Action *ConstructPhaseAction(const llvm::opt::ArgList &Args, phases::ID Phase,
Action *Input) const;
-
/// BuildJobsForAction - Construct the jobs to perform for the
/// action \p A.
void BuildJobsForAction(Compilation &C,
@@ -367,18 +386,22 @@ public:
/// handle this action.
bool ShouldUseClangCompiler(const JobAction &JA) const;
- bool IsUsingLTO(const ArgList &Args) const;
+ bool IsUsingLTO(const llvm::opt::ArgList &Args) const;
private:
/// \brief Retrieves a ToolChain for a particular target triple.
///
/// Will cache ToolChains for the life of the driver object, and create them
/// on-demand.
- const ToolChain &getToolChain(const ArgList &Args,
+ const ToolChain &getToolChain(const llvm::opt::ArgList &Args,
StringRef DarwinArchName = "") const;
/// @}
+ /// \brief Get bitmasks for which option flags to include and exclude based on
+ /// the driver mode.
+ std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const;
+
public:
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
/// return the grouped values as integers. Numbers which are not
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index ea7b52f9cb72..f3c33aeccb42 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define DRIVERSTART
#include "clang/Basic/DiagnosticDriverKinds.inc"
#undef DIAG
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 045b5d89ded3..1dd49a792356 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -11,18 +11,28 @@
#define CLANG_DRIVER_JOB_H_
#include "clang/Basic/LLVM.h"
-#include "clang/Driver/Util.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Option/Option.h"
+
+namespace llvm {
+ class raw_ostream;
+}
namespace clang {
namespace driver {
+class Action;
class Command;
class Tool;
+// Re-export this as clang::driver::ArgStringList.
+using llvm::opt::ArgStringList;
+
class Job {
public:
enum JobClass {
CommandClass,
+ FallbackCommandClass,
JobListClass
};
@@ -36,16 +46,19 @@ public:
JobClass getKind() const { return Kind; }
- /// addCommand - Append a command to the current job, which must be
- /// either a piped job or a job list.
- void addCommand(Command *C);
+ /// Print - Print this Job in -### format.
+ ///
+ /// \param OS - The stream to print on.
+ /// \param Terminator - A string to print at the end of the line.
+ /// \param Quote - Should separate arguments be quoted.
+ /// \param CrashReport - Whether to print for inclusion in a crash report.
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
+ bool Quote, bool CrashReport = false) const = 0;
};
- /// Command - An executable path/name and argument vector to
- /// execute.
+/// Command - An executable path/name and argument vector to
+/// execute.
class Command : public Job {
- virtual void anchor();
-
/// Source - The action which caused the creation of this job.
const Action &Source;
@@ -57,11 +70,17 @@ class Command : public Job {
/// The list of program arguments (not including the implicit first
/// argument, which will be the executable).
- ArgStringList Arguments;
+ llvm::opt::ArgStringList Arguments;
public:
Command(const Action &_Source, const Tool &_Creator, const char *_Executable,
- const ArgStringList &_Arguments);
+ const llvm::opt::ArgStringList &_Arguments);
+
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
+ bool Quote, bool CrashReport = false) const;
+
+ virtual int Execute(const 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; }
@@ -69,16 +88,37 @@ public:
/// getCreator - Return the Tool which caused the creation of this job.
const Tool &getCreator() const { return Creator; }
- const char *getExecutable() const { return Executable; }
+ const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
- const ArgStringList &getArguments() const { return Arguments; }
+ static bool classof(const Job *J) {
+ return J->getKind() == CommandClass ||
+ J->getKind() == FallbackCommandClass;
+ }
+};
+
+/// Like Command, but with a fallback which is executed in case
+/// the primary command crashes.
+class FallbackCommand : public Command {
+public:
+ FallbackCommand(const Action &Source_, const Tool &Creator_,
+ const char *Executable_, const ArgStringList &Arguments_,
+ Command *Fallback_);
+
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
+ bool Quote, bool CrashReport = false) const;
+
+ virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
+ bool *ExecutionFailed) const;
static bool classof(const Job *J) {
- return J->getKind() == CommandClass;
+ return J->getKind() == FallbackCommandClass;
}
+
+private:
+ OwningPtr<Command> Fallback;
};
- /// JobList - A sequence of jobs to perform.
+/// JobList - A sequence of jobs to perform.
class JobList : public Job {
public:
typedef SmallVector<Job*, 4> list_type;
@@ -93,6 +133,9 @@ public:
JobList();
virtual ~JobList();
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
+ bool Quote, bool CrashReport = false) const;
+
/// Add a job to the list (taking ownership).
void addJob(Job *J) { Jobs.push_back(J); }
diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile
index 7d066c77b377..77cf6ff8d938 100644
--- a/include/clang/Driver/Makefile
+++ b/include/clang/Driver/Makefile
@@ -5,10 +5,10 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/Options.inc.tmp : Options.td CC1Options.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Options.inc.tmp : Options.td CC1Options.td CLCompatOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang Driver Option tables with tblgen"
- $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang CC1 Assembler Option tables with tblgen"
- $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td
deleted file mode 100644
index d16a2a779324..000000000000
--- a/include/clang/Driver/OptParser.td
+++ /dev/null
@@ -1,152 +0,0 @@
-//===--- OptParser.td - Common Option Parsing Interfaces ------------------===//
-//
-// 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 common interfaces used by the option parsing TableGen
-// backend.
-//
-//===----------------------------------------------------------------------===//
-
-// Define the kinds of options.
-
-class OptionKind<string name, int predecence = 0, bit sentinel = 0> {
- string Name = name;
- // The kind precedence, kinds with lower precedence are matched first.
- int Precedence = predecence;
- // Indicate a sentinel option.
- bit Sentinel = sentinel;
-}
-
-// An option group.
-def KIND_GROUP : OptionKind<"Group">;
-// The input option kind.
-def KIND_INPUT : OptionKind<"Input", 1, 1>;
-// The unknown option kind.
-def KIND_UNKNOWN : OptionKind<"Unknown", 2, 1>;
-// A flag with no values.
-def KIND_FLAG : OptionKind<"Flag">;
-// An option which prefixes its (single) value.
-def KIND_JOINED : OptionKind<"Joined", 1>;
-// An option which is followed by its value.
-def KIND_SEPARATE : OptionKind<"Separate">;
-// An option followed by its values, which are separated by commas.
-def KIND_COMMAJOINED : OptionKind<"CommaJoined">;
-// An option which is which takes multiple (separate) arguments.
-def KIND_MULTIARG : OptionKind<"MultiArg">;
-// An option which is either joined to its (non-empty) value, or followed by its
-// value.
-def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">;
-// An option which is both joined to its (first) value, and followed by its
-// (second) value.
-def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">;
-
-// Define the option flags.
-
-class OptionFlag {}
-
-// DriverOption - The option is a "driver" option, and should not be forwarded
-// to gcc.
-def DriverOption : OptionFlag;
-
-// LinkerInput - The option is a linker input.
-def LinkerInput : OptionFlag;
-
-// NoArgumentUnused - Don't report argument unused warnings for this option; this
-// is useful for options like -static or -dynamic which a user may always end up
-// passing, even if the platform defaults to (or only supports) that option.
-def NoArgumentUnused : OptionFlag;
-
-// RenderAsInput - The option should not render the name when rendered as an
-// input (i.e., the option is rendered as values).
-def RenderAsInput : OptionFlag;
-
-// RenderJoined - The option should be rendered joined, even if separate (only
-// sensible on single value separate options).
-def RenderJoined : OptionFlag;
-
-// RenderSeparate - The option should be rendered separately, even if joined
-// (only sensible on joined options).
-def RenderSeparate : OptionFlag;
-
-// Unsupported - The option is unsupported, and the driver will reject command
-// lines that use it.
-def Unsupported : OptionFlag;
-
-// HelpHidden - The option should not be displayed in --help, even if it has
-// help text. Clients *can* use this in conjunction with the OptTable::PrintHelp
-// arguments to implement hidden help groups.
-def HelpHidden : OptionFlag;
-
-// NoForward - The option should not be implicitly forwarded to other tools.
-def NoForward : OptionFlag;
-
-// CC1Option - This option should be accepted by clang -cc1.
-def CC1Option : OptionFlag;
-
-// NoDriverOption - This option should not be accepted by the driver.
-def NoDriverOption : OptionFlag;
-
-// Define the option group class.
-
-class OptionGroup<string name> {
- string EnumName = ?; // Uses the def name if undefined.
- string Name = name;
- string HelpText = ?;
- OptionGroup Group = ?;
-}
-
-// Define the option class.
-
-class Option<list<string> prefixes, string name, OptionKind kind> {
- string EnumName = ?; // Uses the def name if undefined.
- list<string> Prefixes = prefixes;
- string Name = name;
- OptionKind Kind = kind;
- // Used by MultiArg option kind.
- int NumArgs = 0;
- string HelpText = ?;
- string MetaVarName = ?;
- list<OptionFlag> Flags = [];
- OptionGroup Group = ?;
- Option Alias = ?;
-}
-
-// Helpers for defining options.
-
-class Flag<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_FLAG>;
-class Joined<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_JOINED>;
-class Separate<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_SEPARATE>;
-class CommaJoined<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_COMMAJOINED>;
-class MultiArg<list<string> prefixes, string name, int numargs>
- : Option<prefixes, name, KIND_MULTIARG> {
- int NumArgs = numargs;
-}
-class JoinedOrSeparate<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_JOINED_OR_SEPARATE>;
-class JoinedAndSeparate<list<string> prefixes, string name>
- : Option<prefixes, name, KIND_JOINED_AND_SEPARATE>;
-
-// Mix-ins for adding optional attributes.
-
-class Alias<Option alias> { Option Alias = alias; }
-class EnumName<string name> { string EnumName = name; }
-class Flags<list<OptionFlag> flags> { list<OptionFlag> Flags = flags; }
-class Group<OptionGroup group> { OptionGroup Group = group; }
-class HelpText<string text> { string HelpText = text; }
-class MetaVarName<string name> { string MetaVarName = name; }
-
-// Predefined options.
-
-// FIXME: Have generator validate that these appear in correct position (and
-// aren't duplicated).
-def INPUT : Option<[], "<input>", KIND_INPUT>, Flags<[DriverOption,CC1Option]>;
-def UNKNOWN : Option<[], "<unknown>", KIND_UNKNOWN>;
diff --git a/include/clang/Driver/OptSpecifier.h b/include/clang/Driver/OptSpecifier.h
deleted file mode 100644
index e683ef325b8e..000000000000
--- a/include/clang/Driver/OptSpecifier.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===--- OptSpecifier.h - Option Specifiers ---------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_OPTSPECIFIER_H
-#define CLANG_DRIVER_OPTSPECIFIER_H
-
-#include "llvm/Support/Compiler.h"
-
-namespace clang {
-namespace driver {
- class Option;
-
- /// OptSpecifier - Wrapper class for abstracting references to option IDs.
- class OptSpecifier {
- unsigned ID;
-
- private:
- explicit OptSpecifier(bool) LLVM_DELETED_FUNCTION;
-
- public:
- OptSpecifier() : ID(0) {}
- /*implicit*/ OptSpecifier(unsigned _ID) : ID(_ID) {}
- /*implicit*/ OptSpecifier(const Option *Opt);
-
- bool isValid() const { return ID != 0; }
-
- unsigned getID() const { return ID; }
-
- bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); }
- bool operator!=(OptSpecifier Opt) const { return !(*this == Opt); }
- };
-}
-}
-
-#endif
diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h
deleted file mode 100644
index 53d83a0f38aa..000000000000
--- a/include/clang/Driver/OptTable.h
+++ /dev/null
@@ -1,161 +0,0 @@
-//===--- OptTable.h - Option Table ------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_OPTTABLE_H
-#define CLANG_DRIVER_OPTTABLE_H
-
-#include "clang/Basic/LLVM.h"
-#include "clang/Driver/OptSpecifier.h"
-#include "llvm/ADT/StringSet.h"
-
-namespace clang {
-namespace driver {
- class Arg;
- class ArgList;
- class InputArgList;
- class Option;
-
- /// \brief Provide access to the Option info table.
- ///
- /// The OptTable class provides a layer of indirection which allows Option
- /// instance to be created lazily. In the common case, only a few options will
- /// be needed at runtime; the OptTable class maintains enough information to
- /// parse command lines without instantiating Options, while letting other
- /// parts of the driver still use Option instances where convenient.
- class OptTable {
- public:
- /// \brief Entry for a single option instance in the option data table.
- struct Info {
- /// A null terminated array of prefix strings to apply to name while
- /// matching.
- const char *const *Prefixes;
- const char *Name;
- const char *HelpText;
- const char *MetaVar;
- unsigned ID;
- unsigned char Kind;
- unsigned char Param;
- unsigned short Flags;
- unsigned short GroupID;
- unsigned short AliasID;
- };
-
- private:
- /// \brief The static option information table.
- const Info *OptionInfos;
- unsigned NumOptionInfos;
-
- unsigned TheInputOptionID;
- unsigned TheUnknownOptionID;
-
- /// The index of the first option which can be parsed (i.e., is not a
- /// special option like 'input' or 'unknown', and is not an option group).
- unsigned FirstSearchableIndex;
-
- /// The union of all option prefixes. If an argument does not begin with
- /// one of these, it is an input.
- llvm::StringSet<> PrefixesUnion;
- std::string PrefixChars;
-
- private:
- const Info &getInfo(OptSpecifier Opt) const {
- unsigned id = Opt.getID();
- assert(id > 0 && id - 1 < getNumOptions() && "Invalid Option ID.");
- return OptionInfos[id - 1];
- }
-
- protected:
- OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos);
- public:
- ~OptTable();
-
- /// \brief Return the total number of option classes.
- unsigned getNumOptions() const { return NumOptionInfos; }
-
- /// \brief Get the given Opt's Option instance, lazily creating it
- /// if necessary.
- ///
- /// \return The option, or null for the INVALID option id.
- const Option getOption(OptSpecifier Opt) const;
-
- /// \brief Lookup the name of the given option.
- const char *getOptionName(OptSpecifier id) const {
- return getInfo(id).Name;
- }
-
- /// \brief Get the kind of the given option.
- unsigned getOptionKind(OptSpecifier id) const {
- return getInfo(id).Kind;
- }
-
- /// \brief Get the group id for the given option.
- unsigned getOptionGroupID(OptSpecifier id) const {
- return getInfo(id).GroupID;
- }
-
- /// \brief Get the help text to use to describe this option.
- const char *getOptionHelpText(OptSpecifier id) const {
- return getInfo(id).HelpText;
- }
-
- /// \brief Get the meta-variable name to use when describing
- /// this options values in the help text.
- const char *getOptionMetaVar(OptSpecifier id) const {
- return getInfo(id).MetaVar;
- }
-
- /// \brief Parse a single argument; returning the new argument and
- /// updating Index.
- ///
- /// \param [in,out] Index - The current parsing position in the argument
- /// string list; on return this will be the index of the next argument
- /// string to parse.
- ///
- /// \return The parsed argument, or 0 if the argument is missing values
- /// (in which case Index still points at the conceptual next argument string
- /// to parse).
- Arg *ParseOneArg(const ArgList &Args, unsigned &Index) const;
-
- /// \brief Parse an list of arguments into an InputArgList.
- ///
- /// The resulting InputArgList will reference the strings in [\p ArgBegin,
- /// \p ArgEnd), and their lifetime should extend past that of the returned
- /// InputArgList.
- ///
- /// The only error that can occur in this routine is if an argument is
- /// missing values; in this case \p MissingArgCount will be non-zero.
- ///
- /// \param ArgBegin - The beginning of the argument vector.
- /// \param ArgEnd - The end of the argument vector.
- /// \param MissingArgIndex - On error, the index of the option which could
- /// not be parsed.
- /// \param MissingArgCount - On error, the number of missing options.
- /// \return An InputArgList; on error this will contain all the options
- /// which could be parsed.
- InputArgList *ParseArgs(const char* const *ArgBegin,
- const char* const *ArgEnd,
- unsigned &MissingArgIndex,
- unsigned &MissingArgCount) const;
-
- /// \brief Render the help text for an option table.
- ///
- /// \param OS - The stream to write the help text to.
- /// \param Name - The name to use in the usage line.
- /// \param Title - The title to use in the usage line.
- /// \param FlagsToInclude - If non-zero, only include options with any
- /// of these flags set.
- /// \param FlagsToExclude - Exclude options with any of these flags set.
- void PrintHelp(raw_ostream &OS, const char *Name,
- const char *Title, unsigned short FlagsToInclude = 0,
- unsigned short FlagsToExclude = 0) const;
- };
-}
-}
-
-#endif
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
deleted file mode 100644
index 764934fdf810..000000000000
--- a/include/clang/Driver/Option.h
+++ /dev/null
@@ -1,204 +0,0 @@
-//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_OPTION_H_
-#define CLANG_DRIVER_OPTION_H_
-
-#include "clang/Basic/LLVM.h"
-#include "clang/Driver/OptTable.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ErrorHandling.h"
-
-namespace clang {
-namespace driver {
- class Arg;
- class ArgList;
-
-namespace options {
- /// Base flags for all options. Custom flags may be added after.
- enum DriverFlag {
- HelpHidden = (1 << 0),
- RenderAsInput = (1 << 1),
- RenderJoined = (1 << 2),
- RenderSeparate = (1 << 3)
- };
-
- /// Flags specifically for clang options.
- enum ClangFlags {
- DriverOption = (1 << 4),
- LinkerInput = (1 << 5),
- NoArgumentUnused = (1 << 6),
- NoForward = (1 << 7),
- Unsupported = (1 << 8),
- CC1Option = (1 << 9),
- NoDriverOption = (1 << 10)
- };
-}
-
- /// Option - Abstract representation for a single form of driver
- /// argument.
- ///
- /// An Option class represents a form of option that the driver
- /// takes, for example how many arguments the option has and how
- /// they can be provided. Individual option instances store
- /// additional information about what group the option is a member
- /// of (if any), if the option is an alias, and a number of
- /// flags. At runtime the driver parses the command line into
- /// concrete Arg instances, each of which corresponds to a
- /// particular Option instance.
- class Option {
- public:
- enum OptionClass {
- GroupClass = 0,
- InputClass,
- UnknownClass,
- FlagClass,
- JoinedClass,
- SeparateClass,
- CommaJoinedClass,
- MultiArgClass,
- JoinedOrSeparateClass,
- JoinedAndSeparateClass
- };
-
- enum RenderStyleKind {
- RenderCommaJoinedStyle,
- RenderJoinedStyle,
- RenderSeparateStyle,
- RenderValuesStyle
- };
-
- protected:
- const OptTable::Info *Info;
- const OptTable *Owner;
-
- public:
- Option(const OptTable::Info *Info, const OptTable *Owner);
- ~Option();
-
- bool isValid() const {
- return Info != 0;
- }
-
- unsigned getID() const {
- assert(Info && "Must have a valid info!");
- return Info->ID;
- }
-
- OptionClass getKind() const {
- assert(Info && "Must have a valid info!");
- return OptionClass(Info->Kind);
- }
-
- /// \brief Get the name of this option without any prefix.
- StringRef getName() const {
- assert(Info && "Must have a valid info!");
- return Info->Name;
- }
-
- const Option getGroup() const {
- assert(Info && "Must have a valid info!");
- assert(Owner && "Must have a valid owner!");
- return Owner->getOption(Info->GroupID);
- }
-
- const Option getAlias() const {
- assert(Info && "Must have a valid info!");
- assert(Owner && "Must have a valid owner!");
- return Owner->getOption(Info->AliasID);
- }
-
- /// \brief Get the default prefix for this option.
- StringRef getPrefix() const {
- const char *Prefix = *Info->Prefixes;
- return Prefix ? Prefix : StringRef();
- }
-
- /// \brief Get the name of this option with the default prefix.
- std::string getPrefixedName() const {
- std::string Ret = getPrefix();
- Ret += getName();
- return Ret;
- }
-
- unsigned getNumArgs() const { return Info->Param; }
-
- bool hasNoOptAsInput() const { return Info->Flags & options::RenderAsInput;}
-
- RenderStyleKind getRenderStyle() const {
- if (Info->Flags & options::RenderJoined)
- return RenderJoinedStyle;
- if (Info->Flags & options::RenderSeparate)
- return RenderSeparateStyle;
- switch (getKind()) {
- case GroupClass:
- case InputClass:
- case UnknownClass:
- return RenderValuesStyle;
- case JoinedClass:
- case JoinedAndSeparateClass:
- return RenderJoinedStyle;
- case CommaJoinedClass:
- return RenderCommaJoinedStyle;
- case FlagClass:
- case SeparateClass:
- case MultiArgClass:
- case JoinedOrSeparateClass:
- return RenderSeparateStyle;
- }
- llvm_unreachable("Unexpected kind!");
- }
-
- /// Test if this option has the flag \a Val.
- bool hasFlag(unsigned Val) const {
- return Info->Flags & Val;
- }
-
- /// getUnaliasedOption - Return the final option this option
- /// aliases (itself, if the option has no alias).
- const Option getUnaliasedOption() const {
- const Option Alias = getAlias();
- if (Alias.isValid()) return Alias.getUnaliasedOption();
- return *this;
- }
-
- /// getRenderName - Return the name to use when rendering this
- /// option.
- StringRef getRenderName() const {
- return getUnaliasedOption().getName();
- }
-
- /// matches - Predicate for whether this option is part of the
- /// given option (which may be a group).
- ///
- /// Note that matches against options which are an alias should never be
- /// done -- aliases do not participate in matching and so such a query will
- /// always be false.
- bool matches(OptSpecifier ID) const;
-
- /// accept - Potentially accept the current argument, returning a
- /// new Arg instance, or 0 if the option does not accept this
- /// argument (or the argument is missing values).
- ///
- /// If the option accepts the current argument, accept() sets
- /// Index to the position where argument parsing should resume
- /// (even if the argument is missing values).
- ///
- /// \parm ArgSize The number of bytes taken up by the matched Option prefix
- /// and name. This is used to determine where joined values
- /// start.
- Arg *accept(const ArgList &Args, unsigned &Index, unsigned ArgSize) const;
-
- void dump() const;
- };
-
-} // end namespace driver
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 6c114e252d3c..28948be96dec 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -10,24 +10,40 @@
#ifndef CLANG_DRIVER_OPTIONS_H
#define CLANG_DRIVER_OPTIONS_H
+namespace llvm {
+namespace opt {
+class OptTable;
+}
+}
+
namespace clang {
namespace driver {
- class OptTable;
namespace options {
- enum ID {
+/// Flags specifically for clang options. Must not overlap with
+/// llvm::opt::DriverFlag.
+enum ClangFlags {
+ DriverOption = (1 << 4),
+ LinkerInput = (1 << 5),
+ NoArgumentUnused = (1 << 6),
+ Unsupported = (1 << 7),
+ CoreOption = (1 << 8),
+ CLOption = (1 << 9),
+ CC1Option = (1 << 10),
+ NoDriverOption = (1 << 11)
+};
+
+enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define PREFIX(NAME, VALUE)
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) OPT_##ID,
#include "clang/Driver/Options.inc"
LastOption
#undef OPTION
-#undef PREFIX
};
}
- OptTable *createDriverOptTable();
+llvm::opt::OptTable *createDriverOptTable();
}
}
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 3a5358a7e355..9e7dc78d63cf 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -12,23 +12,55 @@
//===----------------------------------------------------------------------===//
// Include the common option parsing interfaces.
-include "OptParser.td"
+include "llvm/Option/OptParser.td"
+
+/////////
+// Flags
+
+// DriverOption - The option is a "driver" option, and should not be forwarded
+// to other tools.
+def DriverOption : OptionFlag;
+
+// LinkerInput - The option is a linker input.
+def LinkerInput : OptionFlag;
+
+// NoArgumentUnused - Don't report argument unused warnings for this option; this
+// is useful for options like -static or -dynamic which a user may always end up
+// passing, even if the platform defaults to (or only supports) that option.
+def NoArgumentUnused : OptionFlag;
+
+// Unsupported - The option is unsupported, and the driver will reject command
+// lines that use it.
+def Unsupported : OptionFlag;
+
+// CoreOption - This is considered a "core" Clang option, available in both
+// clang and clang-cl modes.
+def CoreOption : OptionFlag;
+
+// CLOption - This is a cl.exe compatibility option. Options with this flag
+// are made available when the driver is running in CL compatibility mode.
+def CLOption : OptionFlag;
+
+// CC1Option - This option should be accepted by clang -cc1.
+def CC1Option : OptionFlag;
+
+// NoDriverOption - This option should not be accepted by the driver.
+def NoDriverOption : OptionFlag;
/////////
// Groups
-// Meta-group which defines
+// Meta-group for options which are only used for compilation,
+// and not linking etc.
def CompileOnly_Group : OptionGroup<"<CompileOnly group>">;
+
def Action_Group : OptionGroup<"<action group>">;
def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
-def L_Group : OptionGroup<"<L group>">, Group<CompileOnly_Group>;
def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
def T_Group : OptionGroup<"<T group>">;
def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>;
-def X_Group : OptionGroup<"<X group>">;
-def a_Group : OptionGroup<"<a group>">;
def d_Group : OptionGroup<"<d group>">;
def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>;
@@ -39,10 +71,10 @@ def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>;
def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>;
def m_x86_Features_Group : OptionGroup<"<m x86 features group>">, Group<m_Group>;
def m_hexagon_Features_Group : OptionGroup<"<m hexagon features group>">, Group<m_Group>;
+def m_arm_Features_Group : OptionGroup<"<m arm features group>">, Group<m_Group>;
+def m_ppc_Features_Group : OptionGroup<"<m ppc features group>">, Group<m_Group>;
def opencl_Group : OptionGroup<"<opencl group>">;
def u_Group : OptionGroup<"<u group>">;
-def mips_CPUs_Group : OptionGroup<"<MIPS CPU aliases group>">,
- Group<CompileOnly_Group>;
def pedantic_Group : OptionGroup<"<pedantic group>">,
Group<CompileOnly_Group>;
@@ -69,7 +101,9 @@ def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">,
// substitutions:
// _ => __
// - => _
+// / => _SLASH
// # => _HASH
+// ? => _QUESTION
// , => _COMMA
// = => _EQ
// C++ => CXX
@@ -77,45 +111,40 @@ def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">,
// Developer Driver Options
-def ccc_Group : OptionGroup<"<clang internal options>">;
-def ccc_driver_Group : OptionGroup<"<clang driver internal options>">,
- Group<ccc_Group>, HelpText<"DRIVER OPTIONS">;
-def ccc_debug_Group : OptionGroup<"<clang debug/development internal options>">,
- Group<ccc_Group>, HelpText<"DEBUG/DEVELOPMENT OPTIONS">;
-
-class CCCDriverOpt : Group<ccc_driver_Group>, Flags<[DriverOption, HelpHidden]>;
-def ccc_cxx : Flag<["-"], "ccc-cxx">, CCCDriverOpt,
- HelpText<"Act as a C++ driver">;
-def ccc_echo : Flag<["-"], "ccc-echo">, CCCDriverOpt,
- HelpText<"Echo commands before running them">;
-def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, CCCDriverOpt,
+def internal_Group : OptionGroup<"<clang internal options>">;
+def internal_driver_Group : OptionGroup<"<clang driver internal options>">,
+ Group<internal_Group>, HelpText<"DRIVER OPTIONS">;
+def internal_debug_Group :
+ OptionGroup<"<clang debug/development internal options>">,
+ Group<internal_Group>, HelpText<"DEBUG/DEVELOPMENT OPTIONS">;
+
+class InternalDriverOpt : Group<internal_driver_Group>,
+ Flags<[DriverOption, HelpHidden]>;
+def driver_mode : Joined<["--"], "driver-mode=">, Group<internal_driver_Group>,
+ Flags<[CoreOption, DriverOption, HelpHidden]>,
+ HelpText<"Set the driver mode to either 'gcc', 'g++', 'cpp', or 'cl'">;
+def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, InternalDriverOpt,
HelpText<"Name for native GCC compiler">,
MetaVarName<"<gcc-path>">;
-def ccc_clang_archs : Separate<["-"], "ccc-clang-archs">, CCCDriverOpt,
- HelpText<"Comma separate list of architectures to use the clang compiler for">,
- MetaVarName<"<arch-list>">;
-def ccc_pch_is_pch : Flag<["-"], "ccc-pch-is-pch">, CCCDriverOpt,
+def ccc_pch_is_pch : Flag<["-"], "ccc-pch-is-pch">, InternalDriverOpt,
HelpText<"Use lazy PCH for precompiled headers">;
-def ccc_pch_is_pth : Flag<["-"], "ccc-pch-is-pth">, CCCDriverOpt,
+def ccc_pch_is_pth : Flag<["-"], "ccc-pch-is-pth">, InternalDriverOpt,
HelpText<"Use pretokenized headers for precompiled headers">;
-class CCCDebugOpt : Group<ccc_debug_Group>, Flags<[DriverOption, HelpHidden]>;
-def ccc_install_dir : Separate<["-"], "ccc-install-dir">, CCCDebugOpt,
+class InternalDebugOpt : Group<internal_debug_Group>,
+ Flags<[DriverOption, HelpHidden]>;
+def ccc_install_dir : Separate<["-"], "ccc-install-dir">, InternalDebugOpt,
HelpText<"Simulate installation in the given directory">;
-def ccc_print_options : Flag<["-"], "ccc-print-options">, CCCDebugOpt,
- HelpText<"Dump parsed command line arguments">;
-def ccc_print_phases : Flag<["-"], "ccc-print-phases">, CCCDebugOpt,
+def ccc_print_phases : Flag<["-"], "ccc-print-phases">, InternalDebugOpt,
HelpText<"Dump list of actions to perform">;
-def ccc_print_bindings : Flag<["-"], "ccc-print-bindings">, CCCDebugOpt,
+def ccc_print_bindings : Flag<["-"], "ccc-print-bindings">, InternalDebugOpt,
HelpText<"Show bindings of tools to actions">;
-def ccc_arcmt_check : Flag<["-"], "ccc-arcmt-check">, CCCDriverOpt,
+def ccc_arcmt_check : Flag<["-"], "ccc-arcmt-check">, InternalDriverOpt,
HelpText<"Check for ARC migration issues that need manual handling">;
-def ccc_arcmt_modify : Flag<["-"], "ccc-arcmt-modify">, CCCDriverOpt,
+def ccc_arcmt_modify : Flag<["-"], "ccc-arcmt-modify">, InternalDriverOpt,
HelpText<"Apply modifications to files to conform to ARC">;
-def ccc_arrmt_check : Flag<["-"], "ccc-arrmt-check">, Alias<ccc_arcmt_check>;
-def ccc_arrmt_modify : Flag<["-"], "ccc-arrmt-modify">, Alias<ccc_arcmt_modify>;
-def ccc_arcmt_migrate : Separate<["-"], "ccc-arcmt-migrate">, CCCDriverOpt,
+def ccc_arcmt_migrate : Separate<["-"], "ccc-arcmt-migrate">, InternalDriverOpt,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output">,
HelpText<"Output path for the plist report">, Flags<[CC1Option]>;
@@ -125,25 +154,49 @@ def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
-def ccc_objcmt_migrate : Separate<["-"], "ccc-objcmt-migrate">, CCCDriverOpt,
+def ccc_objcmt_migrate : Separate<["-"], "ccc-objcmt-migrate">,
+ InternalDriverOpt,
HelpText<"Apply modifications and produces temporary files to migrate to "
"modern ObjC syntax">;
def objcmt_migrate_literals : Flag<["-"], "objcmt-migrate-literals">, Flags<[CC1Option]>,
HelpText<"Enable migration to modern ObjC literals">;
def objcmt_migrate_subscripting : Flag<["-"], "objcmt-migrate-subscripting">, Flags<[CC1Option]>,
HelpText<"Enable migration to modern ObjC subscripting">;
+def objcmt_migrate_property : Flag<["-"], "objcmt-migrate-property">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to modern ObjC property">;
+def objcmt_migrate_all : Flag<["-"], "objcmt-migrate-all">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to modern ObjC">;
+def objcmt_migrate_readonly_property : Flag<["-"], "objcmt-migrate-readonly-property">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to modern ObjC readonly property">;
+def objcmt_migrate_readwrite_property : Flag<["-"], "objcmt-migrate-readwrite-property">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to modern ObjC readwrite property">;
+def objcmt_migrate_annotation : Flag<["-"], "objcmt-migrate-annotation">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to property and method annotations">;
+def objcmt_migrate_instancetype : Flag<["-"], "objcmt-migrate-instancetype">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to infer instancetype for method result type">;
+def objcmt_migrate_nsmacros : Flag<["-"], "objcmt-migrate-ns-macros">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to NS_ENUM/NS_OPTIONS macros">;
+def objcmt_migrate_protocol_conformance : Flag<["-"], "objcmt-migrate-protocol-conformance">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to add protocol conformance on classes">;
+def objcmt_atomic_property : Flag<["-"], "objcmt-atomic-property">, Flags<[CC1Option]>,
+ HelpText<"Make migration to 'atomic' properties">;
+def objcmt_returns_innerpointer_property : Flag<["-"], "objcmt-returns-innerpointer-property">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to annotate property with NS_RETURNS_INNER_POINTER">;
+def objcmt_ns_nonatomic_iosonly: Flag<["-"], "objcmt-ns-nonatomic-iosonly">, Flags<[CC1Option]>,
+ HelpText<"Enable migration to use NS_NONATOMIC_IOSONLY macro for setting property's 'atomic' attribute">;
+def objcmt_white_list_dir_path: Joined<["-"], "objcmt-white-list-dir-path=">, Flags<[CC1Option]>,
+ HelpText<"Only modify files with a filename contained in the provided directory path">;
// Make sure all other -ccc- options are rejected.
-def ccc_ : Joined<["-"], "ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
+def ccc_ : Joined<["-"], "ccc-">, Group<internal_Group>, Flags<[Unsupported]>;
// Standard Options
-def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption]>,
+def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption, CoreOption]>,
HelpText<"Print the commands to run for this compilation">;
-// The '--' option is here for the sake of compatibility with gcc, but is
-// being ignored by the driver.
-def _DASH_DASH : Flag<["--"], "">, Flags<[DriverOption]>;
-def A : JoinedOrSeparate<["-"], "A">;
+def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>,
+ Flags<[DriverOption, CoreOption]>;
+def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>;
def B : JoinedOrSeparate<["-"], "B">;
def CC : Flag<["-"], "CC">, Flags<[CC1Option]>;
def C : Flag<["-"], "C">, Flags<[CC1Option]>;
@@ -174,18 +227,19 @@ def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Specify target for dependency">;
def Mach : Flag<["-"], "Mach">;
def M : Flag<["-"], "M">, Group<M_Group>;
-def O0 : Joined<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>;
-def O4 : Joined<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>;
+def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>;
+def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>;
def ObjCXX : Flag<["-"], "ObjC++">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C++ inputs">;
def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C inputs">;
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[CC1Option]>;
+def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["2"]>;
def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>;
def P : Flag<["-"], "P">, Flags<[CC1Option]>,
HelpText<"Disable linemarker output in -E mode">;
def Qn : Flag<["-"], "Qn">;
-def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption]>,
+def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>,
HelpText<"Don't emit warning for unused driver arguments">;
def Q : Flag<["-"], "Q">;
def R : Flag<["-"], "R">;
@@ -214,9 +268,7 @@ def Wnonportable_cfstrings : Joined<["-"], "Wnonportable-cfstrings">, Group<W_Gr
def Wp_COMMA : CommaJoined<["-"], "Wp,">,
HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">,
MetaVarName<"<arg>">;
-def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option]>;
-def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option]>;
-def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option]>,
+def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CoreOption]>,
MetaVarName<"<warning>">, HelpText<"Enable the specified warning">;
def Xanalyzer : Separate<["-"], "Xanalyzer">,
HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
@@ -225,7 +277,7 @@ def Xassembler : Separate<["-"], "Xassembler">,
HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">;
def Xclang : Separate<["-"], "Xclang">,
HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">,
- Flags<[NoForward]>;
+ Flags<[DriverOption, CoreOption]>;
def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">;
def Xpreprocessor : Separate<["-"], "Xpreprocessor">,
@@ -236,11 +288,11 @@ def Z_Flag : Flag<["-"], "Z">;
def Z_Joined : Joined<["-"], "Z">;
def all__load : Flag<["-"], "all_load">;
def allowable__client : Separate<["-"], "allowable_client">;
-def ansi : Flag<["-", "--"], "ansi">, Group<a_Group>;
+def ansi : Flag<["-", "--"], "ansi">;
def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">;
def arch : Separate<["-"], "arch">, Flags<[DriverOption]>;
def arch__only : Separate<["-"], "arch_only">;
-def a : Joined<["-"], "a">, Group<a_Group>;
+def a : Joined<["-"], "a">;
def bind__at__load : Flag<["-"], "bind_at_load">;
def bundle__loader : Separate<["-"], "bundle_loader">;
def bundle : Flag<["-"], "bundle">;
@@ -290,9 +342,6 @@ def fPIE : Flag<["-"], "fPIE">, Group<f_Group>;
def fno_PIE : Flag<["-"], "fno-PIE">, Group<f_Group>;
def faccess_control : Flag<["-"], "faccess-control">, Group<f_Group>;
def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_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 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]>,
@@ -313,9 +362,14 @@ def fast : Flag<["-"], "fast">, Group<f_Group>;
def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>;
def fautolink : Flag <["-"], "fautolink">, Group<f_Group>;
-def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>, Flags<[NoForward, CC1Option]>,
+def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>,
+ Flags<[DriverOption, CC1Option]>,
HelpText<"Disable generation of linker directives for automatic library linking">;
+def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Enable sample-based profile guided optimizations">;
+
def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the 'blocks' language feature">;
def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group<f_Group>;
@@ -325,8 +379,6 @@ def fbounds_checking : Flag<["-"], "fbounds-checking">, Group<f_Group>,
HelpText<"Enable run-time bounds checks">;
def fbounds_checking_EQ : Joined<["-"], "fbounds-checking=">, Flags<[CC1Option]>,
Group<f_Group>;
-def fbuiltin_strcat : Flag<["-"], "fbuiltin-strcat">, Group<f_Group>;
-def fbuiltin_strcpy : Flag<["-"], "fbuiltin-strcpy">, Group<f_Group>;
def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>;
def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>;
def fcatch_undefined_behavior : Flag<["-"], "fcatch-undefined-behavior">, Group<f_Group>;
@@ -335,6 +387,8 @@ def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, Flag
HelpText<"Use colors in diagnostics">;
def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group<f_Group>;
def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_Group>;
+def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Use ANSI escape codes for diagnostics">;
def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Treat each comma separated argument in <arg> as a documentation comment block command">,
MetaVarName<"<arg>">;
@@ -344,13 +398,15 @@ def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>;
def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group<f_Group>;
def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>;
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 fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
-def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>, Flags<[NoForward]>;
+def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>,
+ Flags<[DriverOption]>;
def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group<f_Group>;
def fdebug_pass_structure : Flag<["-"], "fdebug-pass-structure">, Group<f_Group>;
def fdiagnostics_fixit_info : Flag<["-"], "fdiagnostics-fixit-info">, Group<f_clang_Group>;
@@ -387,6 +443,10 @@ def fencoding_EQ : Joined<["-"], "fencoding=">, Group<f_Group>;
def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>;
def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable support for exception handling">;
+def fexpensive_optimizations : Flag<["-"], "fexpensive-optimizations">,
+ Group<clang_ignored_f_Group>;
+def fno_expensive_optimizations : Flag<["-"], "fno-expensive-optimizations">,
+ Group<clang_ignored_f_Group>;
def fextdirs_EQ : Joined<["-"], "fextdirs=">, Group<f_Group>;
def fextended_identifiers : Flag<["-"], "fextended-identifiers">,
Group<clang_ignored_f_Group>;
@@ -405,7 +465,7 @@ def fbracket_depth_EQ : Joined<["-"], "fbracket-depth=">, Group<f_Group>;
def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>;
def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
- Flags<[CC1Option]>, MetaVarName<"<check>">,
+ Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
HelpText<"Enable runtime instrumentation for bug detection: "
"address (memory errors) | thread (race detection) | "
"undefined (miscellaneous undefined behavior)">;
@@ -500,13 +560,13 @@ def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Op
HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">;
def fms_compatibility : Flag<["-"], "fms-compatibility">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Microsoft compatibility mode">;
-def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>, Flags<[CC1Option]>,
+def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>, Flags<[CC1Option, CoreOption]>,
HelpText<"Version of the Microsoft C/C++ compiler to report in _MSC_VER (0 = don't define it (default))">;
def fdelayed_template_parsing : Flag<["-"], "fdelayed-template-parsing">, Group<f_Group>,
HelpText<"Parse templated function definitions at the end of the "
"translation unit ">, Flags<[CC1Option]>;
def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
- Flags<[NoForward,CC1Option]>, MetaVarName<"<directory>">,
+ Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">,
HelpText<"Specify the module cache path">;
def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
Flags<[CC1Option]>, MetaVarName<"<seconds>">,
@@ -514,10 +574,23 @@ def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i
def fmodules_prune_after : Joined<["-"], "fmodules-prune-after=">, Group<i_Group>,
Flags<[CC1Option]>, MetaVarName<"<seconds>">,
HelpText<"Specify the interval (in seconds) after which a module file will be considered unused">;
-def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, Flags<[NoForward,CC1Option]>,
+def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
+ Flags<[DriverOption, CC1Option]>,
HelpText<"Enable the 'modules' language feature">;
+def fmodule_maps : Flag <["-"], "fmodule-maps">, Group<f_Group>,
+ Flags<[DriverOption,CC1Option]>,
+ HelpText<"Read module maps to understand the structure of library headers">;
+def fmodule_name : JoinedOrSeparate<["-"], "fmodule-name=">, Group<f_Group>,
+ Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">,
+ HelpText<"Specify the name of the module to build">;
+def fmodule_map_file : JoinedOrSeparate<["-"], "fmodule-map-file=">,
+ Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">,
+ HelpText<"Load this module map file">;
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>,
+ Flags<[DriverOption,CC1Option]>,
+ HelpText<"Require declaration of modules used within a module">;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -534,10 +607,12 @@ def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">,
Flags<[CC1Option]>;
def fno_blocks : Flag<["-"], "fno-blocks">, Group<f_Group>;
def fno_borland_extensions : Flag<["-"], "fno-borland-extensions">, Group<f_Group>;
-def fno_builtin_strcat : Flag<["-"], "fno-builtin-strcat">, Group<f_Group>;
-def fno_builtin_strcpy : Flag<["-"], "fno-builtin-strcpy">, Group<f_Group>;
def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable implicit builtin knowledge of functions">;
+def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<clang_ignored_f_Group>,
+ HelpText<"Disable implicit builtin knowledge of a specific function">;
+def fno_math_builtin : Flag<["-"], "fno-math-builtin">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Disable implicit builtin knowledge of math functions">;
def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<f_Group>,
Flags<[CC1Option]>;
def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>;
@@ -548,13 +623,14 @@ def fno_constant_cfstrings : Flag<["-"], "fno-constant-cfstrings">, Group<f_Grou
Flags<[CC1Option]>,
HelpText<"Disable creation of CodeFoundation-type constant strings">;
def fno_cxx_exceptions: Flag<["-"], "fno-cxx-exceptions">, Group<f_Group>;
-def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>, Flags<[NoForward]>;
+def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>,
+ Flags<[DriverOption]>;
def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Do not include fixit information in diagnostics">;
def fno_diagnostics_show_name : Flag<["-"], "fno-diagnostics-show-name">, Group<f_Group>;
def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group<f_Group>;
def fno_diagnostics_show_note_include_stack : Flag<["-"], "fno-diagnostics-show-note-include-stack">,
- Flags<[CC1Option]>, Group<f_Group>, HelpText<"Display include stacks for diagnostic notes">;
+ Flags<[CC1Option]>, Group<f_Group>;
def fno_dollars_in_identifiers : Flag<["-"], "fno-dollars-in-identifiers">, Group<f_Group>,
HelpText<"Disallow '$' in identifiers">, Flags<[CC1Option]>;
def fno_elide_constructors : Flag<["-"], "fno-elide-constructors">, Group<f_Group>,
@@ -571,7 +647,12 @@ def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Group<f_Group>,
HelpText<"Do not limit debug information produced to reduce size of debug binary">;
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Disallow merging of constants">;
-def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>, Flags<[NoForward]>;
+def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>,
+ Flags<[DriverOption]>;
+def fno_module_maps : Flag <["-"], "fno-module-maps">, Group<f_Group>,
+ Flags<[DriverOption]>;
+def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
+ Flags<[DriverOption]>;
def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>;
def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>;
@@ -594,6 +675,7 @@ def fno_spell_checking : Flag<["-"], "fno-spell-checking">, Group<f_Group>,
def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>;
def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
+def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>;
def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Group>,
@@ -643,7 +725,6 @@ def fobjc_nonfragile_abi : Flag<["-"], "fobjc-nonfragile-abi">, Group<f_Group>;
def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Group>;
def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
-def fobjc : Flag<["-"], "fobjc">, Group<f_Group>;
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option]>;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
@@ -658,6 +739,8 @@ def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group<f_Group>, Flags<[CC1
HelpText<"Specify the default maximum struct packing alignment">;
def fpascal_strings : Flag<["-"], "fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Recognize and construct Pascal-style string literals">;
+def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Override the default ABI to return all structs on the stack">;
def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group<f_Group>;
def fpic : Flag<["-"], "fpic">, Group<f_Group>;
def fno_pic : Flag<["-"], "fno-pic">, Group<f_Group>;
@@ -667,6 +750,8 @@ def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>;
def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>;
def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>;
def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>;
+def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Override the default ABI to return small structs in registers">;
def frtti : Flag<["-"], "frtti">, Group<f_Group>;
def fsched_interblock : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>;
def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>,
@@ -682,6 +767,8 @@ def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
+def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>,
+ Group<clang_ignored_f_Group>, HelpText<"Char is unsigned">;
def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>;
def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>;
@@ -696,6 +783,8 @@ def ftemplate_depth_EQ : Joined<["-"], "ftemplate-depth=">, Group<f_Group>;
def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<["-"], "ftemplate-backtrace-limit=">,
Group<f_Group>;
+def foperator_arrow_depth_EQ : Joined<["-"], "foperator-arrow-depth=">,
+ Group<f_Group>;
def ftest_coverage : Flag<["-"], "ftest-coverage">, Group<f_Group>;
def fvectorize : Flag<["-"], "fvectorize">, Group<f_Group>,
HelpText<"Enable the loop vectorization passes">;
@@ -737,12 +826,21 @@ def ftrap_function_EQ : Joined<["-"], "ftrap-function=">, Group<f_Group>, Flags<
def funit_at_a_time : Flag<["-"], "funit-at-a-time">, Group<f_Group>;
def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>,
HelpText<"Turn on loop unroller">, Flags<[CC1Option]>;
+def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
+ HelpText<"Turn off loop unroller">, Flags<[CC1Option]>;
+def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>,
+ HelpText<"Turn on loop reroller">, Flags<[CC1Option]>;
+def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>,
+ HelpText<"Turn off loop reroller">;
def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
+def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">, Group<clang_ignored_f_Group>;
def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use .init_array instead of .ctors">;
+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">;
@@ -757,11 +855,17 @@ def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Store string literals as writable data">;
def fzero_initialized_in_bss : Flag<["-"], "fzero-initialized-in-bss">, Group<f_Group>;
-def ffunction_sections: Flag <["-"], "ffunction-sections">, Group<f_Group>,
- Flags<[CC1Option]>, HelpText<"Place each function in its own section (ELF Only)">;
-def fdata_sections : Flag <["-"], "fdata-sections">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Place each data in its own section (ELF Only)">;
-def f : Joined<["-"], "f">, Group<f_Group>;
+def ffunction_sections : Flag<["-"], "ffunction-sections">, Group<f_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Place each function in its own section (ELF Only)">;
+def fno_function_sections : Flag<["-"], "fno-function-sections">,
+ Group<f_Group>, Flags<[CC1Option]>;
+def fdata_sections : Flag <["-"], "fdata-sections">, Group<f_Group>,
+ Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">;
+def fno_data_sections : Flag <["-"], "fno-data-sections">, Group<f_Group>,
+ Flags<[CC1Option]>;
+def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
+ Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
HelpText<"Generate source level debug information">, Flags<[CC1Option]>;
def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<g_Group>,
@@ -775,9 +879,12 @@ def ggdb0 : Flag<["-"], "ggdb0">, Group<g_Group>;
def ggdb1 : Flag<["-"], "ggdb1">, Group<g_Group>;
def ggdb2 : Flag<["-"], "ggdb2">, Group<g_Group>;
def ggdb3 : Flag<["-"], "ggdb3">, Group<g_Group>;
-def gdwarf_2 : Flag<["-"], "gdwarf-2">, Group<g_Group>;
-def gdwarf_3 : Flag<["-"], "gdwarf-3">, Group<g_Group>;
-def gdwarf_4 : Flag<["-"], "gdwarf-4">, Group<g_Group>;
+def gdwarf_2 : Flag<["-"], "gdwarf-2">, Group<g_Group>,
+ HelpText<"Generate source level debug information with dwarf version 2">, Flags<[CC1Option]>;
+def gdwarf_3 : Flag<["-"], "gdwarf-3">, Group<g_Group>,
+ HelpText<"Generate source level debug information with dwarf version 3">, Flags<[CC1Option]>;
+def gdwarf_4 : Flag<["-"], "gdwarf-4">, Group<g_Group>,
+ HelpText<"Generate source level debug information with dwarf version 4">, Flags<[CC1Option]>;
def gfull : Flag<["-"], "gfull">, Group<g_Group>;
def gused : Flag<["-"], "gused">, Group<g_Group>;
def gstabs : Joined<["-"], "gstabs">, Group<g_Group>, Flags<[Unsupported]>;
@@ -792,6 +899,7 @@ def gstrict_dwarf : Flag<["-"], "gstrict-dwarf">, Group<g_flags_Group>;
def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>;
def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>;
def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>;
+def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>;
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
def help : Flag<["-", "--"], "help">, Flags<[CC1Option]>,
HelpText<"Display available options">;
@@ -808,6 +916,8 @@ def include_ : JoinedOrSeparate<["-", "--"], "include">, Group<clang_i_Group>, E
MetaVarName<"<file>">, HelpText<"Include file before parsing">, Flags<[CC1Option]>;
def include_pch : Separate<["-"], "include-pch">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Include precompiled header file">, MetaVarName<"<file>">;
+def relocatable_pch : Flag<["-", "--"], "relocatable-pch">, Flags<[CC1Option]>,
+ HelpText<"Whether to build a relocatable precompiled header">;
def init : Separate<["-"], "init">;
def install__name : Separate<["-"], "install_name">;
def integrated_as : Flag<["-"], "integrated-as">, Flags<[DriverOption]>;
@@ -835,39 +945,34 @@ def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
def EL : Flag<["-"], "EL">, Flags<[DriverOption]>;
def EB : Flag<["-"], "EB">, Flags<[DriverOption]>;
-def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption]>;
+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]>;
+def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
-def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
-def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>;
-def mfprnd : Flag<["-"], "mfprnd">, Group<m_Group>;
-def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_Group>;
-def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_Group>;
-def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_Group>;
-def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_Group>;
-def mno_popcntd : Flag<["-"], "mno-popcntd">, Group<m_Group>;
-def mqpx : Flag<["-"], "mqpx">, Group<m_Group>;
-def mno_qpx : Flag<["-"], "mno-qpx">, Group<m_Group>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
def mcpu_EQ : Joined<["-"], "mcpu=">, 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>;
+def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ignored_m_Group>;
+def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>;
def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>;
def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>;
def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>;
+def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>;
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>;
def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Group<m_Group>;
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
-def mlinker_version_EQ : Joined<["-"], "mlinker-version=">, Flags<[NoForward]>;
+def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
+ Flags<[DriverOption]>;
def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option]>,
HelpText<"Additional arguments to forward to LLVM's option processing">;
def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">, Group<m_Group>;
@@ -877,8 +982,6 @@ def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Opti
HelpText<"Force realign the stack at entry to every function">;
def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the stack alignment">;
-def mstrict_align : Flag<["-"], "mstrict-align">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"Force all memory accesses to be aligned (ARM only)">;
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>;
@@ -886,7 +989,8 @@ def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Grou
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">, Group<m_Group>;
+def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">,
+ Alias<fno_pascal_strings>;
def mno_red_zone : Flag<["-"], "mno-red-zone">, Group<m_Group>;
def mno_relax_all : Flag<["-"], "mno-relax-all">, Group<m_Group>;
def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>;
@@ -903,12 +1007,17 @@ 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_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_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>;
@@ -916,16 +1025,50 @@ 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_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>;
-def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_Group>;
+def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
+ HelpText<"Allow memory accesses to be unaligned (ARM only)">;
+def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_arm_Features_Group>,
+ HelpText<"Force all memory accesses to be aligned (ARM only)">;
+def mstrict_align : Flag<["-"], "mstrict-align">, Alias<mno_unaligned_access>, Flags<[CC1Option,HelpHidden]>,
+ HelpText<"Force all memory accesses to be aligned (ARM only, same as mno-unaligned-access)">;
+def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_arm_Features_Group>;
+def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>,
+ HelpText<"Disallow generation of deprecated IT blocks for ARMv8. It is on by default for ARMv8 Thumb mode.">;
+def mno_restrict_it: Flag<["-"], "mno-restrict-it">, Group<m_arm_Features_Group>,
+ HelpText<"Allow generation of deprecated IT blocks for ARMv8. It is off by default for ARMv8 Thumb mode">;
def marm : Flag<["-"], "marm">, Alias<mno_thumb>;
+def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_arm_Features_Group>,
+ HelpText<"Reserve the r9 register (ARM only)">;
+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 mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
+def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
+def mfprnd : Flag<["-"], "mfprnd">, Group<m_ppc_Features_Group>;
+def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_ppc_Features_Group>;
+def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_ppc_Features_Group>;
+def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_ppc_Features_Group>;
+def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_ppc_Features_Group>;
+def mno_popcntd : Flag<["-"], "mno-popcntd">, Group<m_ppc_Features_Group>;
+def mqpx : Flag<["-"], "mqpx">, Group<m_ppc_Features_Group>;
+def mno_qpx : Flag<["-"], "mno-qpx">, 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 mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings">, Group<m_Group>;
def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>;
def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>,
HelpText<"Omit frame pointer setup for leaf functions">, Flags<[CC1Option]>;
def moslib_EQ : Joined<["-"], "moslib=">, Group<m_Group>;
-def mpascal_strings : Flag<["-"], "mpascal-strings">, Group<m_Group>;
+def mpascal_strings : Flag<["-"], "mpascal-strings">, Alias<fpascal_strings>;
def mred_zone : Flag<["-"], "mred-zone">, Group<m_Group>;
def mregparm_EQ : Joined<["-"], "mregparm=">, Group<m_Group>;
def mrelax_all : Flag<["-"], "mrelax-all">, Group<m_Group>, Flags<[CC1Option]>,
@@ -949,12 +1092,17 @@ 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 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 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>;
@@ -962,25 +1110,45 @@ 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 msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>;
+def mcx16 : Flag<["-"], "mcx16">, 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>;
def mno_micromips : Flag<["-"], "mno-micromips">, Group<m_Group>;
def mxgot : Flag<["-"], "mxgot">, Group<m_Group>;
def mno_xgot : Flag<["-"], "mno-xgot">, Group<m_Group>;
+def mldc1_sdc1 : Flag<["-"], "mldc1-sdc1">, Group<m_Group>;
+def mno_ldc1_sdc1 : Flag<["-"], "mno-ldc1-sdc1">, Group<m_Group>;
+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 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 mips32 : Flag<["-"], "mips32">, Group<mips_CPUs_Group>,
+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 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 mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>;
+def mips32 : Flag<["-"], "mips32">,
+ Alias<march_EQ>, AliasArgs<["mips32"]>,
HelpText<"Equivalent to -march=mips32">, Flags<[HelpHidden]>;
-def mips32r2 : Flag<["-"], "mips32r2">, Group<mips_CPUs_Group>,
+def mips32r2 : Flag<["-"], "mips32r2">,
+ Alias<march_EQ>, AliasArgs<["mips32r2"]>,
HelpText<"Equivalent to -march=mips32r2">, Flags<[HelpHidden]>;
-def mips64 : Flag<["-"], "mips64">, Group<mips_CPUs_Group>,
+def mips64 : Flag<["-"], "mips64">,
+ Alias<march_EQ>, AliasArgs<["mips64"]>,
HelpText<"Equivalent to -march=mips64">, Flags<[HelpHidden]>;
-def mips64r2 : Flag<["-"], "mips64r2">, Group<mips_CPUs_Group>,
+def mips64r2 : Flag<["-"], "mips64r2">,
+ Alias<march_EQ>, AliasArgs<["mips64r2"]>,
HelpText<"Equivalent to -march=mips64r2">, Flags<[HelpHidden]>;
def module_file_info : Flag<["-"], "module-file-info">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
@@ -989,8 +1157,6 @@ def multi__module : Flag<["-"], "multi_module">;
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
def multiply__defined : Separate<["-"], "multiply_defined">;
def mwarn_nonportable_cfstrings : Flag<["-"], "mwarn-nonportable-cfstrings">, Group<m_Group>;
-def m_Separate : Separate<["-"], "m">, Group<m_Group>;
-def m_Joined : Joined<["-"], "m">, Group<m_Group>;
def no_canonical_prefixes : Flag<["-"], "no-canonical-prefixes">, Flags<[HelpHidden]>,
HelpText<"Use relative instead of canonical paths">;
def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>;
@@ -1004,6 +1170,7 @@ def nodefaultlibs : Flag<["-"], "nodefaultlibs">;
def nofixprebinding : Flag<["-"], "nofixprebinding">;
def nolibc : Flag<["-"], "nolibc">;
def nomultidefs : Flag<["-"], "nomultidefs">;
+def nopie : Flag<["-"], "nopie">;
def noprebind : Flag<["-"], "noprebind">;
def noseglinkedit : Flag<["-"], "noseglinkedit">;
def nostartfiles : Flag<["-"], "nostartfiles">;
@@ -1084,16 +1251,16 @@ def static_libgcc : Flag<["-"], "static-libgcc">;
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<L_Group>,
- HelpText<"Language standard to compile for">;
+def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>,
+ Group<CompileOnly_Group>, HelpText<"Language standard to compile for">;
def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>,
HelpText<"C++ standard library to use">;
def sub__library : JoinedOrSeparate<["-"], "sub_library">;
def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">;
def s : Flag<["-"], "s">;
-def target : Separate<["-"], "target">, Flags<[DriverOption]>,
+def target : Joined<["--"], "target=">, Flags<[DriverOption]>,
HelpText<"Generate code for the given target">;
-def gcc_toolchain : Separate<["-"], "gcc-toolchain">, Flags<[DriverOption]>,
+def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[DriverOption]>,
HelpText<"Use the gcc toolchain at the given directory">;
def time : Flag<["-"], "time">,
HelpText<"Time individual commands">;
@@ -1111,7 +1278,6 @@ def undef : Flag<["-"], "undef">, Group<u_Group>, Flags<[CC1Option]>,
HelpText<"undef all system defines">;
def unexported__symbols__list : Separate<["-"], "unexported_symbols_list">;
def u : JoinedOrSeparate<["-"], "u">, Group<u_Group>;
-def use_gold_plugin : Flag<["-"], "use-gold-plugin">;
def v : Flag<["-"], "v">, Flags<[CC1Option]>,
HelpText<"Show commands to run and use verbose output">;
def verify : Flag<["-"], "verify">, Flags<[DriverOption,CC1Option]>,
@@ -1136,6 +1302,7 @@ def working_directory_EQ : Joined<["-"], "working-directory=">, Flags<[CC1Option
// Double dash options, which are usually an alias for one of the previous
// options.
+def _mhwdiv_EQ : Separate<["--"], "mhwdiv">, Alias<mhwdiv_EQ>;
def _CLASSPATH_EQ : Joined<["--"], "CLASSPATH=">, Alias<fclasspath_EQ>;
def _CLASSPATH : Separate<["--"], "CLASSPATH">, Alias<fclasspath_EQ>;
def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>;
@@ -1160,6 +1327,8 @@ def _debug : Flag<["--"], "debug">, Alias<g_Flag>;
def _define_macro_EQ : Joined<["--"], "define-macro=">, Alias<D>;
def _define_macro : Separate<["--"], "define-macro">, Alias<D>;
def _dependencies : Flag<["--"], "dependencies">, Alias<M>;
+def _dyld_prefix_EQ : Joined<["--"], "dyld-prefix=">;
+def _dyld_prefix : Separate<["--"], "dyld-prefix">, Alias<_dyld_prefix_EQ>;
def _encoding_EQ : Joined<["--"], "encoding=">, Alias<fencoding_EQ>;
def _encoding : Separate<["--"], "encoding">, Alias<fencoding_EQ>;
def _entry : Flag<["--"], "entry">, Alias<e>;
@@ -1190,10 +1359,6 @@ def _language_EQ : Joined<["--"], "language=">, Alias<x>;
def _language : Separate<["--"], "language">, Alias<x>;
def _library_directory_EQ : Joined<["--"], "library-directory=">, Alias<L>;
def _library_directory : Separate<["--"], "library-directory">, Alias<L>;
-def _machine__EQ : Joined<["--"], "machine-=">, Alias<m_Joined>;
-def _machine_ : Joined<["--"], "machine-">, Alias<m_Joined>;
-def _machine_EQ : Joined<["--"], "machine=">, Alias<m_Joined>;
-def _machine : Separate<["--"], "machine">, Alias<m_Joined>;
def _no_line_commands : Flag<["--"], "no-line-commands">, Alias<P>;
def _no_standard_includes : Flag<["--"], "no-standard-includes">, Alias<nostdinc>;
def _no_standard_libraries : Flag<["--"], "no-standard-libraries">, Alias<nostdlib>;
@@ -1241,6 +1406,22 @@ def _write_dependencies : Flag<["--"], "write-dependencies">, Alias<MD>;
def _write_user_dependencies : Flag<["--"], "write-user-dependencies">, Alias<MMD>;
def _ : Joined<["--"], "">, Flags<[Unsupported]>;
def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group<m_hexagon_Features_Group>;
+def mv1 : Flag<["-"], "mv1">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
+ AliasArgs<["v1"]>;
+def mv2 : Flag<["-"], "mv2">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
+ AliasArgs<["v2"]>;
+def mv3 : Flag<["-"], "mv3">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
+ AliasArgs<["v3"]>;
+def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
+ AliasArgs<["v4"]>;
+def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
+ AliasArgs<["v5"]>;
+
+// 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
+// style of double-dash and equals-joined flags.
+def gcc_toolchain_legacy_spelling : Separate<["-"], "gcc-toolchain">, Alias<gcc_toolchain>;
+def target_legacy_spelling : Separate<["-"], "target">, Alias<target>;
// Special internal option to handle -Xlinker --no-demangle.
def Z_Xlinker__no_demangle : Flag<["-"], "Z-Xlinker-no-demangle">,
@@ -1256,4 +1437,140 @@ def Z_reserved_lib_stdcxx : Flag<["-"], "Z-reserved-lib-stdc++">,
def Z_reserved_lib_cckext : Flag<["-"], "Z-reserved-lib-cckext">,
Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>;
+// Ignored options
+// FIXME: multiclasess produce suffixes, not prefixes. This is fine for now
+// since it is only used in ignored options.
+multiclass BooleanFFlag<string name> {
+ def _f : Flag<["-"], "f"#name>;
+ def _fno : Flag<["-"], "fno-"#name>;
+}
+
+def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_f_Group>;
+
+defm profile_use : BooleanFFlag<"profile-use">, Group<clang_ignored_f_Group>;
+def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group<clang_ignored_f_Group>;
+def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<clang_ignored_f_Group>;
+
+defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_f_Group>;
+def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<clang_ignored_f_Group>;
+
+// FIXME: This option should be supported and wired up to our diognostics, but
+// ignore it for now to avoid breaking builds that use it.
+def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">, Group<clang_ignored_f_Group>;
+
+defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>;
+defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_f_Group>;
+defm function_attribute_list : BooleanFFlag<"function-attribute-list">, Group<clang_ignored_f_Group>;
+defm gcse : BooleanFFlag<"gcse">, Group<clang_ignored_f_Group>;
+defm gnu : BooleanFFlag<"gnu">, Group<clang_ignored_f_Group>;
+defm ident : BooleanFFlag<"ident">, Group<clang_ignored_f_Group>;
+defm implicit_templates : BooleanFFlag<"implicit-templates">, Group<clang_ignored_f_Group>;
+defm inline_limit : BooleanFFlag<"inline-limit">, Group<clang_ignored_f_Group>;
+defm ivopts : BooleanFFlag<"ivopts">, Group<clang_ignored_f_Group>;
+defm non_call_exceptions : BooleanFFlag<"non-call-exceptions">, Group<clang_ignored_f_Group>;
+defm permissive : BooleanFFlag<"permissive">, Group<clang_ignored_f_Group>;
+defm prefetch_loop_arrays : BooleanFFlag<"prefetch-loop-arrays">, Group<clang_ignored_f_Group>;
+defm printf : BooleanFFlag<"printf">, Group<clang_ignored_f_Group>;
+defm profile : BooleanFFlag<"profile">, Group<clang_ignored_f_Group>;
+defm profile_correction : BooleanFFlag<"profile-correction">, Group<clang_ignored_f_Group>;
+defm profile_generate_sampling : BooleanFFlag<"profile-generate-sampling">, Group<clang_ignored_f_Group>;
+defm profile_reusedist : BooleanFFlag<"profile-reusedist">, Group<clang_ignored_f_Group>;
+defm profile_values : BooleanFFlag<"profile-values">, Group<clang_ignored_f_Group>;
+defm regs_graph : BooleanFFlag<"regs-graph">, Group<clang_ignored_f_Group>;
+defm ripa : BooleanFFlag<"ripa">, Group<clang_ignored_f_Group>;
+defm rounding_math : BooleanFFlag<"rounding-math">, Group<clang_ignored_f_Group>;
+defm schedule_insns : BooleanFFlag<"schedule-insns">, Group<clang_ignored_f_Group>;
+defm see : BooleanFFlag<"see">, Group<clang_ignored_f_Group>;
+defm signaling_nans : BooleanFFlag<"signaling-nans">, Group<clang_ignored_f_Group>;
+defm spec_constr_count : BooleanFFlag<"spec-constr-count">, Group<clang_ignored_f_Group>;
+defm strength_reduce :
+ BooleanFFlag<"strength-reduce">, Group<clang_ignored_f_Group>;
+defm tls_model : BooleanFFlag<"tls-model">, Group<clang_ignored_f_Group>;
+defm tracer : BooleanFFlag<"tracer">, Group<clang_ignored_f_Group>;
+defm tree_salias : BooleanFFlag<"tree-salias">, Group<clang_ignored_f_Group>;
+defm tree_vectorizer_verbose : BooleanFFlag<"tree-vectorizer-verbose">, Group<clang_ignored_f_Group>;
+defm unroll_all_loops : BooleanFFlag<"unroll-all-loops">, Group<clang_ignored_f_Group>;
+defm unswitch_loops : BooleanFFlag<"unswitch-loops">, Group<clang_ignored_f_Group>;
+
+
+// gfortran options that we recognize in the driver and pass along when
+// invoking GCC to compile Fortran code.
+def gfortran_Group : OptionGroup<"gfortran Group">;
+
+// Generic gfortran options.
+def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;
+def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group<gfortran_Group>;
+def cpp : Flag<["-"], "cpp">, Group<gfortran_Group>;
+def nocpp : Flag<["-"], "nocpp">, Group<gfortran_Group>;
+def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group>;
+
+// "f" options with values for gfortran.
+def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>;
+def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
+def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
+def fconvert_EQ : Joined<["-"], "fconvert=">, Group<gfortran_Group>;
+def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<gfortran_Group>;
+def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
+def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
+def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
+def finit_integer_EQ : Joined<["-"], "finit-integer=">, Group<gfortran_Group>;
+def finit_logical_EQ : Joined<["-"], "finit-logical=">, Group<gfortran_Group>;
+def finit_real_EQ : Joined<["-"], "finit-real=">, Group<gfortran_Group>;
+def fmax_array_constructor_EQ : Joined<["-"], "fmax-array-constructor=">, Group<gfortran_Group>;
+def fmax_errors_EQ : Joined<["-"], "fmax-errors=">, Group<gfortran_Group>;
+def fmax_stack_var_size_EQ : Joined<["-"], "fmax-stack-var-size=">, Group<gfortran_Group>;
+def fmax_subrecord_length_EQ : Joined<["-"], "fmax-subrecord-length=">, Group<gfortran_Group>;
+def frecord_marker_EQ : Joined<["-"], "frecord-marker=">, Group<gfortran_Group>;
+
+// "f" flags for gfortran.
+defm aggressive_function_elimination : BooleanFFlag<"aggressive-function-elimination">, Group<gfortran_Group>;
+defm align_commons : BooleanFFlag<"align-commons">, Group<gfortran_Group>;
+defm all_intrinsics : BooleanFFlag<"all-intrinsics">, Group<gfortran_Group>;
+defm automatic : BooleanFFlag<"automatic">, Group<gfortran_Group>;
+defm backslash : BooleanFFlag<"backslash">, Group<gfortran_Group>;
+defm backtrace : BooleanFFlag<"backtrace">, Group<gfortran_Group>;
+defm bounds_check : BooleanFFlag<"bounds-check">, Group<gfortran_Group>;
+defm check_array_temporaries : BooleanFFlag<"check-array-temporaries">, Group<gfortran_Group>;
+defm cray_pointer : BooleanFFlag<"cray-pointer">, Group<gfortran_Group>;
+defm d_lines_as_code : BooleanFFlag<"d-lines-as-code">, Group<gfortran_Group>;
+defm d_lines_as_comments : BooleanFFlag<"d-lines-as-comments">, Group<gfortran_Group>;
+defm default_double_8 : BooleanFFlag<"default-double-8">, Group<gfortran_Group>;
+defm default_integer_8 : BooleanFFlag<"default-integer-8">, Group<gfortran_Group>;
+defm default_real_8 : BooleanFFlag<"default-real-8">, Group<gfortran_Group>;
+defm dollar_ok : BooleanFFlag<"dollar-ok">, Group<gfortran_Group>;
+defm dump_fortran_optimized : BooleanFFlag<"dump-fortran-optimized">, Group<gfortran_Group>;
+defm dump_fortran_original : BooleanFFlag<"dump-fortran-original">, Group<gfortran_Group>;
+defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group<gfortran_Group>;
+defm external_blas : BooleanFFlag<"external-blas">, Group<gfortran_Group>;
+defm f2c : BooleanFFlag<"f2c">, Group<gfortran_Group>;
+defm fixed_form : BooleanFFlag<"fixed-form">, Group<gfortran_Group>;
+defm free_form : BooleanFFlag<"free-form">, Group<gfortran_Group>;
+defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group<gfortran_Group>;
+defm implicit_none : BooleanFFlag<"implicit-none">, Group<gfortran_Group>;
+defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>;
+defm integer_4_integer_8 : BooleanFFlag<"integer-4-integer-8">, Group<gfortran_Group>;
+defm intrinsic_modules_path : BooleanFFlag<"intrinsic-modules-path">, Group<gfortran_Group>;
+defm max_identifier_length : BooleanFFlag<"max-identifier-length">, Group<gfortran_Group>;
+defm module_private : BooleanFFlag<"module-private">, Group<gfortran_Group>;
+defm pack_derived : BooleanFFlag<"pack-derived">, Group<gfortran_Group>;
+defm protect_parens : BooleanFFlag<"protect-parens">, Group<gfortran_Group>;
+defm range_check : BooleanFFlag<"range-check">, Group<gfortran_Group>;
+defm real_4_real_10 : BooleanFFlag<"real-4-real-10">, Group<gfortran_Group>;
+defm real_4_real_16 : BooleanFFlag<"real-4-real-16">, Group<gfortran_Group>;
+defm real_4_real_8 : BooleanFFlag<"real-4-real-8">, Group<gfortran_Group>;
+defm real_8_real_10 : BooleanFFlag<"real-8-real-10">, Group<gfortran_Group>;
+defm real_8_real_16 : BooleanFFlag<"real-8-real-16">, Group<gfortran_Group>;
+defm real_8_real_4 : BooleanFFlag<"real-8-real-4">, Group<gfortran_Group>;
+defm realloc_lhs : BooleanFFlag<"realloc-lhs">, Group<gfortran_Group>;
+defm recursive : BooleanFFlag<"recursive">, Group<gfortran_Group>;
+defm repack_arrays : BooleanFFlag<"repack-arrays">, Group<gfortran_Group>;
+defm second_underscore : BooleanFFlag<"second-underscore">, Group<gfortran_Group>;
+defm sign_zero : BooleanFFlag<"sign-zero">, Group<gfortran_Group>;
+defm stack_arrays : BooleanFFlag<"stack-arrays">, Group<gfortran_Group>;
+defm underscoring : BooleanFFlag<"underscoring">, Group<gfortran_Group>;
+defm whole_file : BooleanFFlag<"whole-file">, Group<gfortran_Group>;
+
+
include "CC1Options.td"
+
+include "CLCompatOptions.td"
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
new file mode 100644
index 000000000000..35b8f89a88a7
--- /dev/null
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -0,0 +1,147 @@
+//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
+
+#include <string>
+
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+
+namespace clang {
+namespace driver {
+
+class Driver;
+class ToolChain;
+
+class SanitizerArgs {
+ /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
+ /// bit positions within \c Kind.
+ enum SanitizeOrdinal {
+#define SANITIZER(NAME, ID) SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+ SO_Count
+ };
+
+ /// Bugs to catch at runtime.
+ enum SanitizeKind {
+#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) \
+ ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+ NeedsAsanRt = Address,
+ NeedsTsanRt = Thread,
+ NeedsMsanRt = Memory,
+ NeedsDfsanRt = DataFlow,
+ NeedsLeakDetection = Leak,
+ NeedsUbsanRt = Undefined | Integer,
+ NotAllowedWithTrap = Vptr,
+ HasZeroBaseShadow = Thread | Memory | DataFlow
+ };
+ unsigned Kind;
+
+ std::string BlacklistFile;
+ bool MsanTrackOrigins;
+ bool AsanZeroBaseShadow;
+ bool UbsanTrapOnError;
+
+ public:
+ SanitizerArgs();
+ /// Parses the sanitizer arguments from an argument list.
+ SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
+
+ bool needsAsanRt() const { return Kind & NeedsAsanRt; }
+ bool needsTsanRt() const { return Kind & NeedsTsanRt; }
+ bool needsMsanRt() const { return Kind & NeedsMsanRt; }
+ bool needsLeakDetection() const { return Kind & NeedsLeakDetection; }
+ bool needsLsanRt() const {
+ return needsLeakDetection() && !needsAsanRt();
+ }
+ bool needsUbsanRt() const {
+ return !UbsanTrapOnError && (Kind & NeedsUbsanRt);
+ }
+ bool needsDfsanRt() const { return Kind & NeedsDfsanRt; }
+
+ bool sanitizesVptr() const { return Kind & Vptr; }
+ bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
+ bool hasZeroBaseShadow() const {
+ return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow;
+ }
+ void addArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ private:
+ void clear();
+
+ /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
+ /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
+ /// if \p Value is not known.
+ static unsigned parse(const char *Value);
+
+ /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+ /// invalid components.
+ static unsigned parse(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
+
+ /// Parse a single flag of the form -f[no]sanitize=, or
+ /// -f*-sanitizer. Sets the masks defining required change of Kind value.
+ /// Returns true if the flag was parsed successfully.
+ static bool parse(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A, unsigned &Add, unsigned &Remove,
+ bool DiagnoseErrors);
+
+ /// Produce an argument string from ArgList \p Args, which shows how it
+ /// provides a sanitizer kind in \p Mask. For example, the argument list
+ /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
+ /// would produce "-fsanitize=vptr".
+ static std::string lastArgumentForKind(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ unsigned Kind);
+
+ /// Produce an argument string from argument \p A, which shows how it provides
+ /// a value in \p Mask. For instance, the argument
+ /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
+ /// "-fsanitize=alignment".
+ static std::string describeSanitizeArg(const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ unsigned Mask);
+
+ static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
+ std::string &BLPath);
+
+ /// Return the smallest superset of sanitizer set \p Kinds such that each
+ /// member of each group whose flag is set in \p Kinds has its flag set in the
+ /// result.
+ static unsigned expandGroups(unsigned Kinds);
+
+ /// Return the subset of \p Kinds supported by toolchain \p TC. If
+ /// \p DiagnoseErrors is true, produce an error diagnostic for each sanitizer
+ /// removed from \p Kinds.
+ static unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds);
+
+ /// The flags in \p Mask are unsupported by \p TC. If present in \p Kinds,
+ /// remove them and produce an error diagnostic referring to \p A if
+ /// \p DiagnoseErrors is true.
+ static void filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
+ unsigned Mask,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds);
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 4c05d0a743bc..015dcf513e0a 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -12,9 +12,15 @@
#include "clang/Basic/LLVM.h"
+namespace llvm {
+namespace opt {
+ class ArgList;
+}
+}
+
namespace clang {
namespace driver {
- class ArgList;
+
class Compilation;
class InputInfo;
class Job;
@@ -57,7 +63,8 @@ public:
virtual bool hasGoodDiagnostics() const { return false; }
/// ConstructJob - Construct jobs to perform the action \p JA,
- /// writing to \p Output and with \p Inputs.
+ /// writing to \p Output and with \p Inputs, and add the jobs to
+ /// \p C.
///
/// \param TCArgs - The argument list for this toolchain, with any
/// tool chain specific translations applied.
@@ -66,7 +73,7 @@ public:
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const = 0;
};
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index aae3d79936b6..84e0b55ba5af 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -19,16 +19,22 @@
#include "llvm/Support/Path.h"
#include <string>
+namespace llvm {
+namespace opt {
+ class ArgList;
+ class DerivedArgList;
+ class InputArgList;
+}
+}
+
namespace clang {
class ObjCRuntime;
namespace driver {
- class ArgList;
class Compilation;
- class DerivedArgList;
class Driver;
- class InputArgList;
class JobAction;
+ class SanitizerArgs;
class Tool;
/// ToolChain - Access to tools for a single platform.
@@ -49,7 +55,7 @@ public:
private:
const Driver &D;
const llvm::Triple Triple;
- const ArgList &Args;
+ const llvm::opt::ArgList &Args;
/// The list of toolchain specific path prefixes to search for
/// files.
@@ -67,8 +73,11 @@ private:
Tool *getLink() const;
Tool *getClangAs() const;
+ mutable OwningPtr<SanitizerArgs> SanitizerArguments;
+
protected:
- ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &Args);
+ ToolChain(const Driver &D, const llvm::Triple &T,
+ const llvm::opt::ArgList &Args);
virtual Tool *buildAssembler() const;
virtual Tool *buildLinker() const;
@@ -76,17 +85,18 @@ protected:
/// \name Utilities for implementing subclasses.
///@{
- static void addSystemInclude(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
+ static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
- static void addExternCSystemInclude(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
+ static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const Twine &Path);
+ static void
+ addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
- static void addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
- const Twine &Path);
- static void addSystemIncludes(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
+ static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
ArrayRef<StringRef> Paths);
///@}
@@ -117,6 +127,8 @@ public:
path_list &getProgramPaths() { return ProgramPaths; }
const path_list &getProgramPaths() const { return ProgramPaths; }
+ const SanitizerArgs& getSanitizerArgs() const;
+
// Tool access.
/// TranslateArgs - Create a new derived argument list for any argument
@@ -124,8 +136,9 @@ public:
/// specific translations are needed.
///
/// \param BoundArch - The bound architecture name, or 0.
- virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
- const char *BoundArch) const {
+ virtual llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ const char *BoundArch) const {
return 0;
}
@@ -137,6 +150,13 @@ public:
std::string GetFilePath(const char *Name) const;
std::string GetProgramPath(const char *Name) const;
+ /// \brief Dispatch to the specific toolchain for verbose printing.
+ ///
+ /// This is used when handling the verbose option to print detailed,
+ /// toolchain-specific information useful for understanding the behavior of
+ /// the driver on a specific platform.
+ virtual void printVerboseInfo(raw_ostream &OS) const {};
+
// Platform defaults information
/// HasNativeLTOLinker - Check whether the linker and related tools have
@@ -157,17 +177,9 @@ public:
/// \brief Check if the toolchain should use the integrated assembler.
bool useIntegratedAs() const;
- /// IsStrictAliasingDefault - Does this tool chain use -fstrict-aliasing by
- /// default.
- virtual bool IsStrictAliasingDefault() const { return true; }
-
/// IsMathErrnoDefault - Does this tool chain use -fmath-errno by default.
virtual bool IsMathErrnoDefault() const { return true; }
- /// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable
- /// -fobjc-default-synthesize-properties by default.
- virtual bool IsObjCDefaultSynthPropertiesDefault() const { return true; }
-
/// IsEncodeExtendedBlockSignatureDefault - Does this tool chain enable
/// -fencode-extended-block-signature by default.
virtual bool IsEncodeExtendedBlockSignatureDefault() const { return false; }
@@ -225,16 +237,18 @@ public:
/// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
/// command line arguments into account.
- virtual std::string ComputeLLVMTriple(const ArgList &Args,
- types::ID InputType = types::TY_INVALID) const;
+ virtual std::string
+ ComputeLLVMTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType = types::TY_INVALID) const;
/// ComputeEffectiveClangTriple - Return the Clang triple to use for this
/// target, which may take into account the command line arguments. For
/// example, on Darwin the -mmacosx-version-min= command line argument (which
/// sets the deployment target) determines the version in the triple passed to
/// Clang.
- virtual std::string ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType = types::TY_INVALID) const;
+ virtual std::string ComputeEffectiveClangTriple(
+ const llvm::opt::ArgList &Args,
+ types::ID InputType = types::TY_INVALID) const;
/// getDefaultObjCRuntime - Return the default Objective-C runtime
/// for this platform.
@@ -253,42 +267,46 @@ public:
///
/// This routine is responsible for adding the necessary cc1 arguments to
/// include headers from standard system header directories.
- virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
/// \brief Add options that need to be passed to cc1 for this target.
- virtual void addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
// GetRuntimeLibType - Determine the runtime library type to use with the
// given compilation arguments.
- virtual RuntimeLibType GetRuntimeLibType(const ArgList &Args) const;
+ virtual RuntimeLibType
+ GetRuntimeLibType(const llvm::opt::ArgList &Args) const;
// GetCXXStdlibType - Determine the C++ standard library type to use with the
// given compilation arguments.
- virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
+ virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
/// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set
/// the include paths to use for the given C++ standard library type.
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
/// AddCXXStdlibLibArgs - Add the system specific linker arguments to use
/// for the given C++ standard library type.
- virtual void AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
/// AddCCKextLibArgs - Add the system specific linker arguments to use
/// for kernel extensions (Darwin-specific).
- virtual void AddCCKextLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
/// AddFastMathRuntimeIfAvailable - If a runtime library exists that sets
/// global flags for unsafe floating point math, add it and return true.
///
/// This checks for presence of the -ffast-math or -funsafe-math flags.
- virtual bool AddFastMathRuntimeIfAvailable(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual bool
+ AddFastMathRuntimeIfAvailable(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
};
} // end namespace driver
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 42f0709cf17a..d4f52d3220c8 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -66,7 +66,7 @@ TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, 0, "pu")
// Other languages.
TYPE("ada", Ada, INVALID, 0, "u")
TYPE("assembler", PP_Asm, INVALID, "s", "au")
-TYPE("assembler-with-cpp", Asm, PP_Asm, 0, "au")
+TYPE("assembler-with-cpp", Asm, PP_Asm, "S", "au")
TYPE("f95", PP_Fortran, INVALID, 0, "u")
TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u")
TYPE("java", Java, INVALID, 0, "u")
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index 18cd2d5102cf..cca576a054aa 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -34,7 +34,7 @@ namespace types {
/// getTypeTempSuffix - Return the suffix to use when creating a
/// temp file of this type, or null if unspecified.
- const char *getTypeTempSuffix(ID Id);
+ const char *getTypeTempSuffix(ID Id, bool CLMode = false);
/// onlyAssembleType - Should this type only be assembled.
bool onlyAssembleType(ID Id);
@@ -78,7 +78,7 @@ namespace types {
/// done for type 'Id'.
void getCompilationPhases(
ID Id,
- llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &Phases);
+ llvm::SmallVectorImpl<phases::ID> &Phases);
/// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given
/// C type (used for clang++ emulation of g++ behaviour)
diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h
index 06b82b977fe0..b24b9904f2b5 100644
--- a/include/clang/Driver/Util.h
+++ b/include/clang/Driver/Util.h
@@ -14,13 +14,12 @@
#include "llvm/ADT/DenseMap.h"
namespace clang {
+class DiagnosticsEngine;
+
namespace driver {
class Action;
class JobAction;
- /// ArgStringList - Type used for constructing argv lists for subprocesses.
- typedef SmallVector<const char*, 16> ArgStringList;
-
/// ArgStringMap - Type used to map a JobAction to its result file.
typedef llvm::DenseMap<const JobAction*, const char*> ArgStringMap;
diff --git a/include/clang/Edit/Commit.h b/include/clang/Edit/Commit.h
index 48e3d593aa54..626b1dd6305e 100644
--- a/include/clang/Edit/Commit.h
+++ b/include/clang/Edit/Commit.h
@@ -13,6 +13,7 @@
#include "clang/Edit/FileOffset.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
namespace clang {
class LangOptions;
@@ -48,16 +49,19 @@ private:
const LangOptions &LangOpts;
const PPConditionalDirectiveRecord *PPRec;
EditedSource *Editor;
-
+
+ const bool ForceCommitInSystemHeader;
bool IsCommitable;
SmallVector<Edit, 8> CachedEdits;
+
+ llvm::BumpPtrAllocator StrAlloc;
public:
explicit Commit(EditedSource &Editor);
Commit(const SourceManager &SM, const LangOptions &LangOpts,
const PPConditionalDirectiveRecord *PPRec = 0)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0),
- IsCommitable(true) { }
+ ForceCommitInSystemHeader(true), IsCommitable(true) { }
bool isCommitable() const { return IsCommitable; }
@@ -103,7 +107,7 @@ public:
CharSourceRange::getTokenRange(TokenInnerRange));
}
- typedef SmallVector<Edit, 8>::const_iterator edit_iterator;
+ typedef SmallVectorImpl<Edit>::const_iterator edit_iterator;
edit_iterator edit_begin() const { return CachedEdits.begin(); }
edit_iterator edit_end() const { return CachedEdits.end(); }
@@ -131,6 +135,12 @@ private:
SourceLocation *MacroBegin = 0) const;
bool isAtEndOfMacroExpansion(SourceLocation loc,
SourceLocation *MacroEnd = 0) const;
+
+ StringRef copyString(StringRef str) {
+ char *buf = StrAlloc.Allocate<char>(str.size());
+ std::memcpy(buf, str.data(), str.size());
+ return StringRef(buf, str.size());
+ }
};
}
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
index 733ad400c934..3ad5a6be1464 100644
--- a/include/clang/Edit/EditedSource.h
+++ b/include/clang/Edit/EditedSource.h
@@ -28,6 +28,7 @@ class EditedSource {
const SourceManager &SourceMgr;
const LangOptions &LangOpts;
const PPConditionalDirectiveRecord *PPRec;
+ const bool ForceCommitInSystemHeader;
struct FileEdit {
StringRef Text;
@@ -45,8 +46,10 @@ class EditedSource {
public:
EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
- const PPConditionalDirectiveRecord *PPRec = 0)
+ const PPConditionalDirectiveRecord *PPRec = 0,
+ const bool FCommitInSystemHeader = true)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec),
+ ForceCommitInSystemHeader(FCommitInSystemHeader),
StrAlloc(/*size=*/512) { }
const SourceManager &getSourceManager() const { return SourceMgr; }
@@ -54,6 +57,10 @@ public:
const PPConditionalDirectiveRecord *getPPCondDirectiveRecord() const {
return PPRec;
}
+
+ bool getForceCommitInSystemHeader() const {
+ return ForceCommitInSystemHeader;
+ }
bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
diff --git a/include/clang/Edit/Rewriters.h b/include/clang/Edit/Rewriters.h
index 292878e75695..5e3425f56f73 100644
--- a/include/clang/Edit/Rewriters.h
+++ b/include/clang/Edit/Rewriters.h
@@ -9,10 +9,16 @@
#ifndef LLVM_CLANG_EDIT_REWRITERS_H
#define LLVM_CLANG_EDIT_REWRITERS_H
+#include "llvm/ADT/SmallVector.h"
namespace clang {
class ObjCMessageExpr;
+ class ObjCMethodDecl;
+ class ObjCInterfaceDecl;
+ class ObjCProtocolDecl;
class NSAPI;
+ class EnumDecl;
+ class TypedefDecl;
class ParentMap;
namespace edit {
@@ -24,7 +30,7 @@ bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit,
const ParentMap *PMap);
-
+
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 5304dc7ba228..0f2746712a69 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -17,6 +17,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Refactoring.h"
+#include "llvm/Support/system_error.h"
namespace clang {
@@ -30,13 +31,29 @@ namespace format {
/// specific guidelines.
struct FormatStyle {
/// \brief The column limit.
+ ///
+ /// A column limit of \c 0 means that there is no column limit. In this case,
+ /// clang-format will respect the input's line breaking decisions within
+ /// statements.
unsigned ColumnLimit;
+ /// \brief The maximum number of consecutive empty lines to keep.
+ unsigned MaxEmptyLinesToKeep;
+
+ /// \brief The penalty for each line break introduced inside a comment.
+ unsigned PenaltyBreakComment;
+
+ /// \brief The penalty for each line break introduced inside a string literal.
+ unsigned PenaltyBreakString;
+
/// \brief The penalty for each character outside of the column limit.
unsigned PenaltyExcessCharacter;
- /// \brief The maximum number of consecutive empty lines to keep.
- unsigned MaxEmptyLinesToKeep;
+ /// \brief The penalty for breaking before the first \c <<.
+ unsigned PenaltyBreakFirstLessLess;
+
+ /// \brief The penalty for breaking a function call after "call(".
+ unsigned PenaltyBreakBeforeFirstCallParameter;
/// \brief Set whether & and * bind to the type as opposed to the variable.
bool PointerBindsToType;
@@ -44,32 +61,62 @@ struct FormatStyle {
/// \brief If \c true, analyze the formatted file for the most common binding.
bool DerivePointerBinding;
- /// \brief The extra indent or outdent of access modifiers (e.g.: public:).
+ /// \brief The extra indent or outdent of access modifiers, e.g. \c public:.
int AccessModifierOffset;
+ /// \brief Supported language standards.
enum LanguageStandard {
+ /// Use C++03-compatible syntax.
LS_Cpp03,
+ /// Use features of C++11 (e.g. \c A<A<int>> instead of
+ /// <tt>A<A<int> ></tt>).
LS_Cpp11,
+ /// Automatic detection based on the input.
LS_Auto
};
- /// \brief Format compatible with this standard, e.g. use \c A<A<int> >
- /// instead of \c A<A<int>> for LS_Cpp03.
+ /// \brief Format compatible with this standard, e.g. use
+ /// <tt>A<A<int> ></tt> instead of \c A<A<int>> for LS_Cpp03.
LanguageStandard Standard;
/// \brief Indent case labels one level from the switch statement.
///
- /// When false, use the same indentation level as for the switch statement.
+ /// When \c false, use the same indentation level as for the switch statement.
/// Switch statement body is always indented one level more than case labels.
bool IndentCaseLabels;
+ /// \brief Different ways to indent namespace contents.
+ enum NamespaceIndentationKind {
+ /// Don't indent in namespaces.
+ NI_None,
+ /// Indent only in inner namespaces (nested in other namespaces).
+ NI_Inner,
+ /// Indent in all namespaces.
+ NI_All
+ };
+
+ /// \brief The indentation used for namespaces.
+ NamespaceIndentationKind NamespaceIndentation;
+
/// \brief The number of spaces to before trailing line comments.
unsigned SpacesBeforeTrailingComments;
- /// \brief If false, a function call's or function definition's parameters
+ /// \brief If \c false, a function call's or function definition's parameters
/// will either all be on the same line or will have one line each.
bool BinPackParameters;
+ /// \brief If \c true, clang-format detects whether function calls and
+ /// definitions are formatted with one parameter per line.
+ ///
+ /// Each call can be bin-packed, one-per-line or inconclusive. If it is
+ /// inconclusive, e.g. completely on one line, but a decision needs to be
+ /// made, clang-format analyzes whether there are other bin-packed cases in
+ /// the input file and act accordingly.
+ ///
+ /// NOTE: This is an experimental flag, that might go away or be renamed. Do
+ /// not use this in config files, etc. Use at your own risk.
+ bool ExperimentalAutoDetectBinPacking;
+
/// \brief Allow putting all parameters of a function declaration onto
/// the next line even if \c BinPackParameters is \c false.
bool AllowAllParametersOfDeclarationOnNextLine;
@@ -82,16 +129,176 @@ struct FormatStyle {
/// initializer on its own line.
bool ConstructorInitializerAllOnOneLineOrOnePerLine;
- /// \brief If true, "if (a) return;" can be put on a single line.
+ /// \brief Always break constructor initializers before commas and align
+ /// the commas with the colon.
+ bool BreakConstructorInitializersBeforeComma;
+
+ /// \brief If \c true, <tt>if (a) return;</tt> can be put on a single
+ /// line.
bool AllowShortIfStatementsOnASingleLine;
+ /// \brief If \c true, <tt>while (true) continue;</tt> can be put on a
+ /// single line.
+ bool AllowShortLoopsOnASingleLine;
+
/// \brief Add a space in front of an Objective-C protocol list, i.e. use
- /// Foo <Protocol> instead of Foo<Protocol>.
+ /// <tt>Foo <Protocol></tt> instead of \c Foo<Protocol>.
bool ObjCSpaceBeforeProtocolList;
+ /// \brief If \c true, aligns trailing comments.
+ bool AlignTrailingComments;
+
/// \brief If \c true, aligns escaped newlines as far left as possible.
/// Otherwise puts them into the right-most column.
bool AlignEscapedNewlinesLeft;
+
+ /// \brief The number of columns to use for indentation.
+ unsigned IndentWidth;
+
+ /// \brief The number of columns used for tab stops.
+ unsigned TabWidth;
+
+ /// \brief The number of characters to use for indentation of constructor
+ /// initializer lists.
+ unsigned ConstructorInitializerIndentWidth;
+
+ /// \brief If \c true, always break after the <tt>template<...></tt> of a
+ /// template declaration.
+ bool AlwaysBreakTemplateDeclarations;
+
+ /// \brief If \c true, always break before multiline string literals.
+ bool AlwaysBreakBeforeMultilineStrings;
+
+ /// \brief Different ways to use tab in formatting.
+ enum UseTabStyle {
+ /// Never use tab.
+ UT_Never,
+ /// Use tabs only for indentation.
+ UT_ForIndentation,
+ /// Use tabs whenever we need to fill whitespace that spans at least from
+ /// one tab stop to the next one.
+ UT_Always
+ };
+
+ /// \brief The way to use tab characters in the resulting file.
+ UseTabStyle UseTab;
+
+ /// \brief If \c true, binary operators will be placed after line breaks.
+ bool BreakBeforeBinaryOperators;
+
+ /// \brief If \c true, ternary operators will be placed after line breaks.
+ bool BreakBeforeTernaryOperators;
+
+ /// \brief Different ways to attach braces to their surrounding context.
+ enum BraceBreakingStyle {
+ /// Always attach braces to surrounding context.
+ BS_Attach,
+ /// Like \c Attach, but break before braces on function, namespace and
+ /// class definitions.
+ BS_Linux,
+ /// Like \c Attach, but break before function definitions.
+ BS_Stroustrup,
+ /// Always break before braces.
+ BS_Allman
+ };
+
+ /// \brief The brace breaking style to use.
+ BraceBreakingStyle BreakBeforeBraces;
+
+ /// \brief If \c true, format braced lists as best suited for C++11 braced
+ /// lists.
+ ///
+ /// Important differences:
+ /// - No spaces inside the braced list.
+ /// - No line break before the closing brace.
+ /// - Indentation with the continuation indent, not with the block indent.
+ ///
+ /// Fundamentally, C++11 braced lists are formatted exactly like function
+ /// calls would be formatted in their place. If the braced list follows a name
+ /// (e.g. a type or variable name), clang-format formats as if the \c {} were
+ /// the parentheses of a function call with that name. If there is no name,
+ /// a zero-length name is assumed.
+ bool Cpp11BracedListStyle;
+
+ /// \brief If \c true, indent when breaking function declarations which
+ /// are not also definitions after the type.
+ bool IndentFunctionDeclarationAfterType;
+
+ /// \brief If \c true, spaces will be inserted after '(' and before ')'.
+ bool SpacesInParentheses;
+
+ /// \brief If \c true, spaces will be inserted after '<' and before '>' in
+ /// template argument lists
+ bool SpacesInAngles;
+
+ /// \brief If \c false, spaces may be inserted into '()'.
+ bool SpaceInEmptyParentheses;
+
+ /// \brief If \c false, spaces may be inserted into C style casts.
+ bool SpacesInCStyleCastParentheses;
+
+ /// \brief If \c true, spaces will be inserted between 'for'/'if'/'while'/...
+ /// and '('.
+ bool SpaceAfterControlStatementKeyword;
+
+ /// \brief If \c false, spaces will be removed before assignment operators.
+ bool SpaceBeforeAssignmentOperators;
+
+ /// \brief Indent width for line continuations.
+ unsigned ContinuationIndentWidth;
+
+ bool operator==(const FormatStyle &R) const {
+ return AccessModifierOffset == R.AccessModifierOffset &&
+ ConstructorInitializerIndentWidth ==
+ R.ConstructorInitializerIndentWidth &&
+ AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
+ AlignTrailingComments == R.AlignTrailingComments &&
+ AllowAllParametersOfDeclarationOnNextLine ==
+ R.AllowAllParametersOfDeclarationOnNextLine &&
+ AllowShortIfStatementsOnASingleLine ==
+ R.AllowShortIfStatementsOnASingleLine &&
+ AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
+ AlwaysBreakTemplateDeclarations ==
+ R.AlwaysBreakTemplateDeclarations &&
+ AlwaysBreakBeforeMultilineStrings ==
+ R.AlwaysBreakBeforeMultilineStrings &&
+ BinPackParameters == R.BinPackParameters &&
+ BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
+ BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
+ BreakBeforeBraces == R.BreakBeforeBraces &&
+ BreakConstructorInitializersBeforeComma ==
+ R.BreakConstructorInitializersBeforeComma &&
+ ColumnLimit == R.ColumnLimit &&
+ ConstructorInitializerAllOnOneLineOrOnePerLine ==
+ R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
+ DerivePointerBinding == R.DerivePointerBinding &&
+ ExperimentalAutoDetectBinPacking ==
+ R.ExperimentalAutoDetectBinPacking &&
+ IndentCaseLabels == R.IndentCaseLabels &&
+ IndentFunctionDeclarationAfterType ==
+ R.IndentFunctionDeclarationAfterType &&
+ IndentWidth == R.IndentWidth &&
+ MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
+ NamespaceIndentation == R.NamespaceIndentation &&
+ ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
+ PenaltyBreakComment == R.PenaltyBreakComment &&
+ PenaltyBreakFirstLessLess == R.PenaltyBreakFirstLessLess &&
+ PenaltyBreakString == R.PenaltyBreakString &&
+ PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
+ PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
+ PointerBindsToType == R.PointerBindsToType &&
+ SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
+ Cpp11BracedListStyle == R.Cpp11BracedListStyle &&
+ Standard == R.Standard && TabWidth == R.TabWidth &&
+ UseTab == R.UseTab && SpacesInParentheses == R.SpacesInParentheses &&
+ SpacesInAngles == R.SpacesInAngles &&
+ SpaceInEmptyParentheses == R.SpaceInEmptyParentheses &&
+ SpacesInCStyleCastParentheses == R.SpacesInCStyleCastParentheses &&
+ SpaceAfterControlStatementKeyword ==
+ R.SpaceAfterControlStatementKeyword &&
+ SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
+ ContinuationIndentWidth == R.ContinuationIndentWidth;
+ }
};
/// \brief Returns a format style complying with the LLVM coding standards:
@@ -110,6 +317,24 @@ FormatStyle getChromiumStyle();
/// https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style.
FormatStyle getMozillaStyle();
+/// \brief Returns a format style complying with Webkit's style guide:
+/// http://www.webkit.org/coding/coding-style.html
+FormatStyle getWebKitStyle();
+
+/// \brief Gets a predefined style by name.
+///
+/// Currently supported names: LLVM, Google, Chromium, Mozilla. Names are
+/// compared case-insensitively.
+///
+/// Returns \c true if the Style has been set.
+bool getPredefinedStyle(StringRef Name, FormatStyle *Style);
+
+/// \brief Parse configuration from YAML-formatted text.
+llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style);
+
+/// \brief Gets configuration in a YAML string.
+std::string configurationAsText(const FormatStyle &Style);
+
/// \brief Reformats the given \p Ranges in the token stream coming out of
/// \c Lex.
///
@@ -117,18 +342,49 @@ FormatStyle getMozillaStyle();
/// everything that might influence its formatting or might be influenced by its
/// formatting.
///
-/// \param DiagClient A custom DiagnosticConsumer. Can be 0, in this case
-/// diagnostic is output to llvm::errs().
-///
/// Returns the \c Replacements necessary to make all \p Ranges comply with
/// \p Style.
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
SourceManager &SourceMgr,
- std::vector<CharSourceRange> Ranges,
- DiagnosticConsumer *DiagClient = 0);
+ std::vector<CharSourceRange> Ranges);
+
+/// \brief Reformats the given \p Ranges in \p Code.
+///
+/// Otherwise identical to the reformat() function consuming a \c Lexer.
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ std::vector<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
/// \brief Returns the \c LangOpts that the formatter expects you to set.
-LangOptions getFormattingLangOpts();
+///
+/// \param Standard determines lexing mode: LC_Cpp11 and LS_Auto turn on C++11
+/// lexing mode, LS_Cpp03 - C++03 mode.
+LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard =
+ FormatStyle::LS_Cpp11);
+
+/// \brief Description to be used for help text for a llvm::cl option for
+/// specifying format style. The description is closely related to the operation
+/// of getStyle().
+extern const char *StyleOptionHelpDescription;
+
+/// \brief Construct a FormatStyle based on \c StyleName.
+///
+/// \c StyleName can take several forms:
+/// \li "{<key>: <value>, ...}" - Set specic style parameters.
+/// \li "<style name>" - One of the style names supported by
+/// getPredefinedStyle().
+/// \li "file" - Load style configuration from a file called '.clang-format'
+/// located in one of the parent directories of \c FileName or the current
+/// directory if \c FileName is empty.
+///
+/// \param[in] StyleName Style name to interpret according to the description
+/// above.
+/// \param[in] FileName Path to start search for .clang-format if \c StyleName
+/// == "file".
+///
+/// \returns FormatStyle as specified by \c StyleName. If no style could be
+/// determined, the default is LLVM Style (see getLLVMStyle()).
+FormatStyle getStyle(StringRef StyleName, StringRef FileName);
} // end namespace format
} // end namespace clang
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index 3731478403ef..366c499b67f5 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -16,9 +16,6 @@
#include "clang/Basic/LLVM.h"
-namespace llvm {
- namespace sys { class Path; }
-}
namespace clang {
class ASTConsumer;
@@ -37,16 +34,12 @@ ASTConsumer *CreateASTPrinter(raw_ostream *OS, StringRef FilterString);
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
-ASTConsumer *CreateASTDumper(StringRef FilterString);
+ASTConsumer *CreateASTDumper(StringRef FilterString, bool DumpLookups = false);
// AST Decl node lister: prints qualified names of all filterable AST Decl
// nodes.
ASTConsumer *CreateASTDeclNodeLister();
-// AST XML-dumper: dumps out the AST to stderr in a very detailed XML
-// format; this is intended for particularly intense debugging.
-ASTConsumer *CreateASTDumperXML(raw_ostream &OS);
-
// Graphical AST viewer: for each function definition, creates a graph of
// the AST and displays it with the graph viewer "dotty". Also outputs
// function declarations to stderr.
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 02c57d7472a5..43d77f0171e9 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -25,7 +25,6 @@
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
@@ -44,6 +43,7 @@ namespace llvm {
}
namespace clang {
+class Sema;
class ASTContext;
class ASTReader;
class CodeCompleteConsumer;
@@ -75,6 +75,7 @@ private:
IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
ASTReader *Reader;
+ bool HadModuleLoaderFatalFailure;
struct ASTWriterData;
OwningPtr<ASTWriterData> WriterData;
@@ -456,7 +457,7 @@ public:
void setASTContext(ASTContext *ctx) { Ctx = ctx; }
void setPreprocessor(Preprocessor *pp);
- bool hasSema() const { return TheSema; }
+ bool hasSema() const { return TheSema.isValid(); }
Sema &getSema() const {
assert(TheSema && "ASTUnit does not have a Sema object!");
return *TheSema;
@@ -471,13 +472,14 @@ public:
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(const llvm::sys::Path &TempFile);
-
+ void addTemporaryFile(StringRef TempFile);
+
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
@@ -697,10 +699,10 @@ public:
/// lifetime is expected to extend past that of the returned ASTUnit.
///
/// \param Action - The ASTFrontendAction to invoke. Its ownership is not
- /// transfered.
+ /// transferred.
///
/// \param Unit - optionally an already created ASTUnit. Its ownership is not
- /// transfered.
+ /// transferred.
///
/// \param Persistent - if true the returned ASTUnit will be complete.
/// false means the caller is only interested in getting info through the
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index f6e2472cb9b7..78b825dc14ff 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -39,11 +39,12 @@ CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker
///< aliases to base ctors when possible.
CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled.
CODEGENOPT(DisableFPElim , 1, 0) ///< Set when -fomit-frame-pointer is enabled.
+CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.
+CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing.
CODEGENOPT(DisableLLVMOpts , 1, 0) ///< Don't run any optimizations, for use in
///< getting .bc files that correspond to the
///< internal state before optimizations are
///< done.
-CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing.
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
@@ -85,6 +86,10 @@ CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer
///< enabled.
VALUE_CODEGENOPT(OptimizationLevel, 3, 0) ///< The -O[0-4] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
+
+ /// If -fpcc-struct-return or -freg-struct-return is specified.
+ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
+
CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA.
@@ -102,8 +107,12 @@ CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled.
CODEGENOPT(UnitAtATime , 1, 1) ///< Unused. For mirroring GCC optimization
///< selection.
CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled.
+CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
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.
/// Attempt to use register sized accesses to bit-fields in structures, when
/// possible.
@@ -131,6 +140,9 @@ VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
/// The kind of generated debug info.
ENUM_CODEGENOPT(DebugInfo, DebugInfoKind, 2, NoDebugInfo)
+/// Dwarf version.
+VALUE_CODEGENOPT(DwarfVersion, 3, 0)
+
/// The kind of inlining to perform.
ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining)
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index db6b4186731c..86aabf7b95ec 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -71,6 +71,12 @@ public:
FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
};
+ enum StructReturnConventionKind {
+ SRCK_Default, // No special option was passed.
+ SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return).
+ SRCK_InRegs // Small structs in registers (-freg-struct-return).
+ };
+
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -122,6 +128,12 @@ public:
/// A list of command-line options to forward to the LLVM backend.
std::vector<std::string> BackendOptions;
+ /// A list of dependent libraries.
+ std::vector<std::string> DependentLibraries;
+
+ /// Name of the profile file to use with -fprofile-sample-use.
+ std::string SampleProfileFile;
+
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index dbd76066b94e..5673c5908d78 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -395,7 +395,7 @@ public:
/// @name ASTConsumer
/// {
- bool hasASTConsumer() const { return Consumer != 0; }
+ bool hasASTConsumer() const { return Consumer.isValid(); }
ASTConsumer &getASTConsumer() const {
assert(Consumer && "Compiler instance has no AST consumer!");
@@ -413,7 +413,7 @@ public:
/// }
/// @name Semantic analysis
/// {
- bool hasSema() const { return TheSema != 0; }
+ bool hasSema() const { return TheSema.isValid(); }
Sema &getSema() const {
assert(TheSema && "Compiler instance has no Sema object!");
@@ -433,7 +433,9 @@ public:
/// @name Code Completion
/// {
- bool hasCodeCompletionConsumer() const { return CompletionConsumer != 0; }
+ bool hasCodeCompletionConsumer() const {
+ return CompletionConsumer.isValid();
+ }
CodeCompleteConsumer &getCodeCompletionConsumer() const {
assert(CompletionConsumer &&
@@ -455,7 +457,7 @@ public:
/// @name Frontend timer
/// {
- bool hasFrontendTimer() const { return FrontendTimer != 0; }
+ bool hasFrontendTimer() const { return FrontendTimer.isValid(); }
llvm::Timer &getFrontendTimer() const {
assert(FrontendTimer && "Compiler instance has no frontend timer!");
@@ -589,10 +591,10 @@ public:
/// \return - Null on error.
llvm::raw_fd_ostream *
createOutputFile(StringRef OutputPath,
- bool Binary = true, bool RemoveFileOnSignal = true,
- StringRef BaseInput = "",
- StringRef Extension = "",
- bool UseTemporary = false,
+ bool Binary, bool RemoveFileOnSignal,
+ StringRef BaseInput,
+ StringRef Extension,
+ bool UseTemporary,
bool CreateMissingDirectories = false);
/// Create a new output file, optionally deriving the output path name.
@@ -622,13 +624,13 @@ public:
/// will be stored here on success.
static llvm::raw_fd_ostream *
createOutputFile(StringRef OutputPath, std::string &Error,
- bool Binary = true, bool RemoveFileOnSignal = true,
- StringRef BaseInput = "",
- StringRef Extension = "",
- bool UseTemporary = false,
- bool CreateMissingDirectories = false,
- std::string *ResultPathName = 0,
- std::string *TempPathName = 0);
+ bool Binary, bool RemoveFileOnSignal,
+ StringRef BaseInput,
+ StringRef Extension,
+ bool UseTemporary,
+ bool CreateMissingDirectories,
+ std::string *ResultPathName,
+ std::string *TempPathName);
/// }
/// @name Initialization Utility Methods
@@ -662,6 +664,10 @@ public:
SourceLocation ImportLoc,
bool Complain);
+ bool hadModuleLoaderFatalFailure() const {
+ return ModuleLoader::HadFatalFailure;
+ }
+
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index fac05c55fbb1..f64773c2c4bd 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -29,15 +29,16 @@
#include <string>
#include <vector>
-namespace clang {
+namespace llvm {
+namespace opt {
+class ArgList;
+}
+}
+namespace clang {
class CompilerInvocation;
class DiagnosticsEngine;
-namespace driver {
-class ArgList;
-}
-
/// \brief Fill out Opts based on the options given in Args.
///
/// Args must have been created from the OptTable returned by
@@ -45,9 +46,9 @@ class ArgList;
///
/// When errors are encountered, return false and, if Diags is non-null,
/// report the error(s).
-bool ParseDiagnosticArgs(DiagnosticOptions &Opts, driver::ArgList &Args,
+bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
DiagnosticsEngine *Diags = 0);
-
+
class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> {
protected:
/// Options controlling the language variant.
diff --git a/include/clang/Frontend/DependencyOutputOptions.h b/include/clang/Frontend/DependencyOutputOptions.h
index 83976c36048f..fefb6f3eda84 100644
--- a/include/clang/Frontend/DependencyOutputOptions.h
+++ b/include/clang/Frontend/DependencyOutputOptions.h
@@ -25,6 +25,7 @@ public:
/// dependency, which can avoid some 'make'
/// problems.
unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list
+ unsigned PrintShowIncludes : 1; ///< Print cl.exe style /showIncludes info.
/// The file to write dependency output to.
std::string OutputFile;
@@ -48,6 +49,7 @@ public:
ShowHeaderIncludes = 0;
UsePhonyTargets = 0;
AddMissingHeaderDeps = 0;
+ PrintShowIncludes = 0;
}
};
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index c67be924720c..a568ba02d2a0 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -94,6 +94,14 @@ protected:
/// BeginSourceFileAction (and BeginSourceFile).
virtual void EndSourceFileAction() {}
+ /// \brief Callback at the end of processing a single input, to determine
+ /// if the output files should be erased or not.
+ ///
+ /// By default it returns true if a compiler error occurred.
+ /// This is guaranteed to only be called following a successful call to
+ /// BeginSourceFileAction (and BeginSourceFile).
+ virtual bool shouldEraseOutputFiles();
+
/// @}
public:
@@ -116,7 +124,7 @@ public:
bool isCurrentFileAST() const {
assert(!CurrentInput.isEmpty() && "No current file!");
- return CurrentASTUnit != 0;
+ return CurrentASTUnit.isValid();
}
const FrontendInputFile &getCurrentInput() const {
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 178619047a38..f3d12769f143 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -56,12 +56,6 @@ protected:
StringRef InFile);
};
-class ASTDumpXMLAction : public ASTFrontendAction {
-protected:
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile);
-};
-
class ASTViewAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
@@ -99,6 +93,7 @@ public:
class GenerateModuleAction : public ASTFrontendAction {
clang::Module *Module;
+ bool IsSystem;
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
@@ -111,6 +106,9 @@ protected:
virtual bool hasASTFileSupport() const { return false; }
public:
+ explicit GenerateModuleAction(bool IsSystem = false)
+ : ASTFrontendAction(), IsSystem(IsSystem) { }
+
virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename);
/// \brief Compute the AST consumer arguments that will be used to
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 0b05b74b9cce..312dbf14115b 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define FRONTENDSTART
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#undef DIAG
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 234e3446c809..4b321e86d29c 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -26,7 +26,6 @@ namespace frontend {
enum ActionKind {
ASTDeclList, ///< Parse ASTs and list Decl nodes.
ASTDump, ///< Parse ASTs and dump them.
- ASTDumpXML, ///< Parse ASTs and dump them in XML.
ASTPrint, ///< Parse ASTs and print them.
ASTView, ///< Parse ASTs and view them in Graphviz.
DumpRawTokens, ///< Dump out raw tokens.
@@ -142,6 +141,8 @@ public:
///< global module index if available.
unsigned GenerateGlobalModuleIndex : 1; ///< Whether we can generate the
///< global module index if needed.
+ unsigned ASTDumpLookups : 1; ///< Whether we include lookup table
+ ///< dumps in AST dumps.
CodeCompleteOptions CodeCompleteOpts;
@@ -157,9 +158,35 @@ public:
/// \brief Enable migration to modern ObjC literals.
ObjCMT_Literals = 0x1,
/// \brief Enable migration to modern ObjC subscripting.
- ObjCMT_Subscripting = 0x2
+ ObjCMT_Subscripting = 0x2,
+ /// \brief Enable migration to modern ObjC readonly property.
+ ObjCMT_ReadonlyProperty = 0x4,
+ /// \brief Enable migration to modern ObjC readwrite property.
+ ObjCMT_ReadwriteProperty = 0x8,
+ /// \brief Enable migration to modern ObjC property.
+ ObjCMT_Property = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty),
+ /// \brief Enable annotation of ObjCMethods of all kinds.
+ ObjCMT_Annotation = 0x10,
+ /// \brief Enable migration of ObjC methods to 'instancetype'.
+ ObjCMT_Instancetype = 0x20,
+ /// \brief Enable migration to NS_ENUM/NS_OPTIONS macros.
+ ObjCMT_NsMacros = 0x40,
+ /// \brief Enable migration to add conforming protocols.
+ ObjCMT_ProtocolConformance = 0x80,
+ /// \brief prefer 'atomic' property over 'nonatomic'.
+ ObjCMT_AtomicProperty = 0x100,
+ /// \brief annotate property with NS_RETURNS_INNER_POINTER
+ ObjCMT_ReturnsInnerPointerProperty = 0x200,
+ /// \brief use NS_NONATOMIC_IOSONLY for property 'atomic' attribute
+ ObjCMT_NsAtomicIOSOnlyProperty = 0x400,
+ ObjCMT_MigrateDecls = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty |
+ ObjCMT_Annotation | ObjCMT_Instancetype |
+ ObjCMT_NsMacros | ObjCMT_ProtocolConformance |
+ ObjCMT_NsAtomicIOSOnlyProperty),
+ ObjCMT_MigrateAll = (ObjCMT_Literals | ObjCMT_Subscripting | ObjCMT_MigrateDecls)
};
unsigned ObjCMTAction;
+ std::string ObjCMTWhiteListPath;
std::string MTMigrateDir;
std::string ARCMTMigrateReportOut;
@@ -215,7 +242,7 @@ public:
FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
SkipFunctionBodies(false), UseGlobalModuleIndex(true),
- GenerateGlobalModuleIndex(true),
+ GenerateGlobalModuleIndex(true), ASTDumpLookups(false),
ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None),
ProgramAction(frontend::ParseSyntaxOnly)
{}
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index 656aa57e6e5a..c8d01b0b15eb 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -51,7 +51,8 @@ public:
/// TextDiagnostic logic requires.
static void printDiagnosticLevel(raw_ostream &OS,
DiagnosticsEngine::Level Level,
- bool ShowColors);
+ bool ShowColors,
+ bool CLFallbackMode = false);
/// \brief Pretty-print a diagnostic message to a raw_ostream.
///
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 8830dced3cc2..dff56c3a8a4e 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -17,10 +17,15 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/OptSpecifier.h"
namespace llvm {
class raw_fd_ostream;
class Triple;
+
+namespace opt {
+class ArgList;
+}
}
namespace clang {
@@ -86,9 +91,11 @@ void AttachDependencyFileGen(Preprocessor &PP,
/// the default behavior used by -H.
/// \param OutputPath - If non-empty, a path to write the header include
/// information to, instead of writing to stderr.
+/// \param ShowDepth - Whether to indent to show the nesting of the includes.
+/// \param MSStyle - Whether to print in cl.exe /showIncludes style.
void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false,
StringRef OutputPath = "",
- bool ShowDepth = true);
+ bool ShowDepth = true, bool MSStyle = false);
/// CacheTokens - Cache tokens for use with PCH. Note that this requires
/// a seekable stream.
@@ -104,6 +111,18 @@ createInvocationFromCommandLine(ArrayRef<const char *> Args,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
IntrusiveRefCntPtr<DiagnosticsEngine>());
-} // end namespace clang
+/// 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.
+int getLastArgIntValue(const llvm::opt::ArgList &Args,
+ llvm::opt::OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags = 0);
+
+inline int getLastArgIntValue(const llvm::opt::ArgList &Args,
+ llvm::opt::OptSpecifier Id, int Default,
+ DiagnosticsEngine &Diags) {
+ return getLastArgIntValue(Args, Id, Default, &Diags);
+}
+
+} // end namespace clang
#endif
diff --git a/include/clang/Index/CommentToXML.h b/include/clang/Index/CommentToXML.h
new file mode 100644
index 000000000000..8444b145343f
--- /dev/null
+++ b/include/clang/Index/CommentToXML.h
@@ -0,0 +1,50 @@
+//===--- CommentToXML.h - Convert comments to XML representation ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_COMMENTTOXML_H
+#define LLVM_CLANG_INDEX_COMMENTTOXML_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+class ASTContext;
+
+namespace comments {
+class FullComment;
+class HTMLTagComment;
+}
+
+namespace index {
+class SimpleFormatContext;
+
+class CommentToXMLConverter {
+ SimpleFormatContext *FormatContext;
+ unsigned FormatInMemoryUniqueId;
+
+public:
+ CommentToXMLConverter() : FormatContext(0), FormatInMemoryUniqueId(0) {}
+
+ void convertCommentToHTML(const comments::FullComment *FC,
+ SmallVectorImpl<char> &HTML,
+ const ASTContext &Context);
+
+ void convertHTMLTagNodeToText(const comments::HTMLTagComment *HTC,
+ SmallVectorImpl<char> &Text,
+ const ASTContext &Context);
+
+ void convertCommentToXML(const comments::FullComment *FC,
+ SmallVectorImpl<char> &XML,
+ const ASTContext &Context);
+};
+
+} // namespace index
+} // namespace clang
+
+#endif // LLVM_CLANG_INDEX_COMMENTTOXML_H
+
diff --git a/include/clang/Index/USRGeneration.h b/include/clang/Index/USRGeneration.h
new file mode 100644
index 000000000000..7b0fd5063ac6
--- /dev/null
+++ b/include/clang/Index/USRGeneration.h
@@ -0,0 +1,54 @@
+//===- USRGeneration.h - Routines for USR generation ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_USRGENERATION_H
+#define LLVM_CLANG_INDEX_USRGENERATION_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+ class Decl;
+
+namespace index {
+
+static inline StringRef getUSRSpacePrefix() {
+ return "c:";
+}
+
+/// \brief Generate a USR for a Decl, including the prefix.
+/// \returns true if the results should be ignored, false otherwise.
+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);
+
+/// \brief Generate a USR fragment for an Objective-C class category.
+void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS);
+
+/// \brief Generate a USR fragment for an Objective-C instance variable. The
+/// complete USR can be created by concatenating the USR for the
+/// encompassing class with this USR fragment.
+void generateUSRForObjCIvar(StringRef Ivar, raw_ostream &OS);
+
+/// \brief Generate a USR fragment for an Objective-C method.
+void generateUSRForObjCMethod(StringRef Sel, bool IsInstanceMethod,
+ raw_ostream &OS);
+
+/// \brief Generate a USR fragment for an Objective-C property.
+void generateUSRForObjCProperty(StringRef Prop, raw_ostream &OS);
+
+/// \brief Generate a USR fragment for an Objective-C protocol.
+void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS);
+
+} // namespace index
+} // namespace clang
+
+#endif // LLVM_CLANG_IDE_USRGENERATION_H
+
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index 261dfabc0fd2..dff3e8c3608d 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/ModuleMap.h"
namespace clang {
class HeaderMap;
@@ -129,6 +130,11 @@ public:
return (SrcMgr::CharacteristicKind)DirCharacteristic;
}
+ /// \brief Whether this describes a system header directory.
+ bool isSystemHeaderDirectory() const {
+ return getDirCharacteristic() != SrcMgr::C_User;
+ }
+
/// \brief Whether this header map is building a framework or not.
bool isIndexHeaderMap() const {
return isHeaderMap() && IsIndexHeaderMap;
@@ -158,7 +164,7 @@ public:
const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const;
private:
@@ -166,7 +172,7 @@ private:
StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemHeader) const;
};
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 8a5a798560de..fb1a86206354 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -53,6 +53,13 @@ struct HeaderFileInfo {
/// \brief Whether this header is part of a module.
unsigned isModuleHeader : 1;
+
+ /// \brief Whether this header is part of the module that we are building.
+ unsigned isCompilingModuleHeader : 1;
+
+ /// \brief Whether this header is part of the module that we are building.
+ /// This is an instance of ModuleMap::ModuleHeaderRole.
+ unsigned HeaderRole : 2;
/// \brief Whether this structure is considered to already have been
/// "resolved", meaning that it was loaded from the external source.
@@ -93,8 +100,9 @@ struct HeaderFileInfo {
HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
- External(false), isModuleHeader(false), Resolved(false),
- IndexHeaderMapHeader(false),
+ External(false), isModuleHeader(false), isCompilingModuleHeader(false),
+ HeaderRole(ModuleMap::NormalHeader),
+ Resolved(false), IndexHeaderMapHeader(false),
NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {}
/// \brief Retrieve the controlling macro for this header file, if
@@ -107,6 +115,16 @@ struct HeaderFileInfo {
return isImport || isPragmaOnce || NumIncludes || ControllingMacro ||
ControllingMacroID;
}
+
+ /// \brief Get the HeaderRole properly typed.
+ ModuleMap::ModuleHeaderRole getHeaderRole() const {
+ return static_cast<ModuleMap::ModuleHeaderRole>(HeaderRole);
+ }
+
+ /// \brief Set the HeaderRole properly typed.
+ void setHeaderRole(ModuleMap::ModuleHeaderRole Role) {
+ HeaderRole = Role;
+ }
};
/// \brief An external source of header file information, which may supply
@@ -222,7 +240,7 @@ class HeaderSearch {
public:
HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
- FileManager &FM, DiagnosticsEngine &Diags,
+ SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target);
~HeaderSearch();
@@ -261,7 +279,7 @@ public:
/// \brief Checks whether the map exists or not.
bool HasIncludeAliasMap() const {
- return IncludeAliases;
+ return IncludeAliases.isValid();
}
/// \brief Map the source include name to the dest include name.
@@ -354,7 +372,7 @@ public:
const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache = false);
/// \brief Look up a subframework for the specified \#include file.
@@ -368,7 +386,7 @@ public:
const FileEntry *RelativeFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule);
+ ModuleMap::KnownHeader *SuggestedModule);
/// \brief Look up the specified framework name in our framework cache.
/// \returns The DirectoryEntry it is in if we know, null otherwise.
@@ -405,7 +423,9 @@ public:
}
/// \brief Mark the specified file as part of a module.
- void MarkFileModuleHeader(const FileEntry *File);
+ void MarkFileModuleHeader(const FileEntry *File,
+ ModuleMap::ModuleHeaderRole Role,
+ bool IsCompiledModuleHeader);
/// \brief Increment the count for the number of times the specified
/// FileEntry has been entered.
@@ -422,6 +442,11 @@ public:
getFileInfo(File).ControllingMacro = ControllingMacro;
}
+ /// \brief Return true if this is the first time encountering this header.
+ bool FirstTimeLexingFile(const FileEntry *File) {
+ return getFileInfo(File).NumIncludes == 1;
+ }
+
/// \brief Determine whether this file is intended to be safe from
/// multiple inclusions, e.g., it has \#pragma once or a controlling
/// macro.
@@ -471,25 +496,33 @@ public:
///
/// \param Root The "root" directory, at which we should stop looking for
/// module maps.
- bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root);
+ ///
+ /// \param IsSystem Whether the directories we're looking at are system
+ /// header directories.
+ bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root,
+ bool IsSystem);
/// \brief Retrieve the module that corresponds to the given file, if any.
///
/// \param File The header that we wish to map to a module.
- Module *findModuleForHeader(const FileEntry *File) const;
+ ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File) const;
/// \brief Read the contents of the given module map file.
///
/// \param File The module map file.
+ /// \param IsSystem Whether this file is in a system header directory.
///
/// \returns true if an error occurred, false otherwise.
- bool loadModuleMapFile(const FileEntry *File);
+ bool loadModuleMapFile(const FileEntry *File, bool IsSystem);
/// \brief Collect the set of all known, top-level modules.
///
/// \param Modules Will be filled with the set of known, top-level modules.
void collectAllModules(SmallVectorImpl<Module *> &Modules);
-
+
+ /// \brief Load all known, top-level system modules.
+ void loadTopLevelSystemModules();
+
private:
/// \brief Retrieve a module with the given name, which may be part of the
/// given framework.
@@ -516,9 +549,6 @@ public:
unsigned header_file_size() const { return FileInfo.size(); }
- // Used by ASTReader.
- void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
-
/// \brief Return the HeaderFileInfo structure for the specified FileEntry.
const HeaderFileInfo &getFileInfo(const FileEntry *FE) const {
return const_cast<HeaderSearch*>(this)->getFileInfo(FE);
@@ -577,18 +607,21 @@ private:
///
/// \param DirName The name of the directory where we will look for a module
/// map file.
+ /// \param IsSystem Whether this is a system header directory.
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
- LoadModuleMapResult loadModuleMapFile(StringRef DirName);
+ LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem);
/// \brief Try to load the module map file in the given directory.
///
/// \param Dir The directory where we will look for a module map file.
+ /// \param IsSystem Whether this is a system header directory.
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
- LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir);
+ LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir,
+ bool IsSystem);
/// \brief Return the HeaderFileInfo structure for the specified FileEntry.
HeaderFileInfo &getFileInfo(const FileEntry *FE);
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index afce5ba18b3b..0b21c0dd3492 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -95,6 +95,9 @@ public:
/// Note: Only used for testing!
unsigned DisableModuleHash : 1;
+ /// \brief Interpret module maps. This option is implied by full modules.
+ unsigned ModuleMaps : 1;
+
/// \brief The interval (in seconds) between pruning operations.
///
/// This operation is expensive, because it requires Clang to walk through
@@ -117,6 +120,9 @@ public:
/// of computing the module hash.
llvm::SetVector<std::string> ModulesIgnoreMacros;
+ /// \brief The set of user-provided module-map-files.
+ llvm::SetVector<std::string> ModuleMapFiles;
+
/// Include the compiler builtin includes.
unsigned UseBuiltinIncludes : 1;
@@ -134,7 +140,7 @@ public:
public:
HeaderSearchOptions(StringRef _Sysroot = "/")
- : Sysroot(_Sysroot), DisableModuleHash(0),
+ : Sysroot(_Sysroot), DisableModuleHash(0), ModuleMaps(0),
ModuleCachePruneInterval(7*24*60*60),
ModuleCachePruneAfter(31*24*60*60),
UseBuiltinIncludes(true),
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 41b93963a7ee..85424aa8a10f 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define LEXSTART
#include "clang/Basic/DiagnosticLexKinds.inc"
#undef DIAG
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index cb4f57fb9cf4..f456fa9cd51c 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -80,6 +80,12 @@ class Lexer : public PreprocessorLexer {
// line" flag set on it.
bool IsAtStartOfLine;
+ bool IsAtPhysicalStartOfLine;
+
+ bool HasLeadingSpace;
+
+ bool HasLeadingEmptyMacro;
+
// CurrentConflictMarkerState - The kind of conflict marker we are handling.
ConflictMarkerKind CurrentConflictMarkerState;
@@ -127,31 +133,21 @@ public:
/// from. Currently this is only used by _Pragma handling.
SourceLocation getFileLoc() const { return FileLoc; }
+private:
/// Lex - Return the next token in the file. If this is the end of file, it
/// return the tok::eof token. This implicitly involves the preprocessor.
- void Lex(Token &Result) {
- // Start a new token.
- Result.startToken();
-
- // NOTE, any changes here should also change code after calls to
- // Preprocessor::HandleDirective
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- IsAtStartOfLine = false;
- }
-
- // Get a token. Note that this may delete the current lexer if the end of
- // file is reached.
- LexTokenInternal(Result);
- }
+ bool Lex(Token &Result);
+public:
/// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma.
bool isPragmaLexer() const { return Is_PragmaLexer; }
+private:
/// IndirectLex - An indirect call to 'Lex' that can be invoked via
/// the PreprocessorLexer interface.
void IndirectLex(Token &Result) { Lex(Result); }
+public:
/// LexFromRawLexer - Lex a token from a designated raw lexer (one with no
/// associated preprocessor object. Return true if the 'next character to
/// read' pointer points at the end of the lexer buffer, false otherwise.
@@ -202,7 +198,10 @@ public:
/// lexer has nothing to reset to.
void resetExtendedTokenMode();
- const char *getBufferStart() const { return BufferStart; }
+ /// Gets source code buffer.
+ StringRef getBuffer() const {
+ return StringRef(BufferStart, BufferEnd - BufferStart);
+ }
/// ReadToEndOfLine - Read the rest of the current preprocessor line as an
/// uninterpreted string. This switches the lexer out of directive mode.
@@ -285,7 +284,8 @@ public:
/// \returns true if there was a failure, false on success.
static bool getRawToken(SourceLocation Loc, Token &Result,
const SourceManager &SM,
- const LangOptions &LangOpts);
+ const LangOptions &LangOpts,
+ bool IgnoreWhiteSpace = false);
/// \brief Given a location any where in a source buffer, find the location
/// that corresponds to the beginning of the token in which the original
@@ -443,12 +443,14 @@ private:
/// LexTokenInternal - Internal interface to lex a preprocessing token. Called
/// by Lex.
///
- void LexTokenInternal(Token &Result);
+ bool LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine);
+
+ bool CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr);
/// Given that a token begins with the Unicode character \p C, figure out
/// what kind of token it is and dispatch to the appropriate lexing helper
/// function.
- void LexUnicode(Token &Result, uint32_t C, const char *CurPtr);
+ bool LexUnicode(Token &Result, uint32_t C, const char *CurPtr);
/// FormTokenWithChars - When we lex a token, we have identified a span
/// starting at BufferPtr, going to TokEnd that forms the token. This method
@@ -566,23 +568,28 @@ private:
void SkipBytes(unsigned Bytes, bool StartOfLine);
- const char *LexUDSuffix(Token &Result, const char *CurPtr);
-
+ void PropagateLineStartLeadingSpaceInfo(Token &Result);
+
+ const char *LexUDSuffix(Token &Result, const char *CurPtr,
+ bool IsStringLiteral);
+
// Helper functions to lex the remainder of a token of the specific type.
- void LexIdentifier (Token &Result, const char *CurPtr);
- void LexNumericConstant (Token &Result, const char *CurPtr);
- void LexStringLiteral (Token &Result, const char *CurPtr,
+ bool LexIdentifier (Token &Result, const char *CurPtr);
+ bool LexNumericConstant (Token &Result, const char *CurPtr);
+ bool LexStringLiteral (Token &Result, const char *CurPtr,
tok::TokenKind Kind);
- void LexRawStringLiteral (Token &Result, const char *CurPtr,
+ bool LexRawStringLiteral (Token &Result, const char *CurPtr,
tok::TokenKind Kind);
- void LexAngledStringLiteral(Token &Result, const char *CurPtr);
- void LexCharConstant (Token &Result, const char *CurPtr,
+ bool LexAngledStringLiteral(Token &Result, const char *CurPtr);
+ bool LexCharConstant (Token &Result, const char *CurPtr,
tok::TokenKind Kind);
bool LexEndOfFile (Token &Result, const char *CurPtr);
-
- bool SkipWhitespace (Token &Result, const char *CurPtr);
- bool SkipLineComment (Token &Result, const char *CurPtr);
- bool SkipBlockComment (Token &Result, const char *CurPtr);
+ bool SkipWhitespace (Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine);
+ bool SkipLineComment (Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine);
+ bool SkipBlockComment (Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine);
bool SaveLineComment (Token &Result, const char *CurPtr);
bool IsStartOfConflictMarker(const char *CurPtr);
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index b1430cc80519..64d5aa2d5928 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -79,6 +79,8 @@ public:
return SuffixBegin - ThisTokBegin;
}
+ static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix);
+
unsigned getRadix() const { return radix; }
/// GetIntegerValue - Convert this numeric literal value to an APInt that
@@ -98,10 +100,18 @@ private:
void ParseNumberStartingWithZero(SourceLocation TokLoc);
+ static bool isDigitSeparator(char C) { return C == '\''; }
+
+ enum CheckSeparatorKind { CSK_BeforeDigits, CSK_AfterDigits };
+
+ /// \brief Ensure that we don't have a digit separator here.
+ void checkSeparator(SourceLocation TokLoc, const char *Pos,
+ CheckSeparatorKind IsAfterDigits);
+
/// SkipHexDigits - Read and skip over any hex digits, up to End.
/// Return a pointer to the first non-hex digit or End.
const char *SkipHexDigits(const char *ptr) {
- while (ptr != ThisTokEnd && isHexDigit(*ptr))
+ while (ptr != ThisTokEnd && (isHexDigit(*ptr) || isDigitSeparator(*ptr)))
ptr++;
return ptr;
}
@@ -109,7 +119,8 @@ private:
/// SkipOctalDigits - Read and skip over any octal digits, up to End.
/// Return a pointer to the first non-hex digit or End.
const char *SkipOctalDigits(const char *ptr) {
- while (ptr != ThisTokEnd && ((*ptr >= '0') && (*ptr <= '7')))
+ while (ptr != ThisTokEnd &&
+ ((*ptr >= '0' && *ptr <= '7') || isDigitSeparator(*ptr)))
ptr++;
return ptr;
}
@@ -117,7 +128,7 @@ private:
/// SkipDigits - Read and skip over any digits, up to End.
/// Return a pointer to the first non-hex digit or End.
const char *SkipDigits(const char *ptr) {
- while (ptr != ThisTokEnd && isDigit(*ptr))
+ while (ptr != ThisTokEnd && (isDigit(*ptr) || isDigitSeparator(*ptr)))
ptr++;
return ptr;
}
@@ -125,7 +136,8 @@ private:
/// SkipBinaryDigits - Read and skip over any binary digits, up to End.
/// Return a pointer to the first non-binary digit or End.
const char *SkipBinaryDigits(const char *ptr) {
- while (ptr != ThisTokEnd && (*ptr == '0' || *ptr == '1'))
+ while (ptr != ThisTokEnd &&
+ (*ptr == '0' || *ptr == '1' || isDigitSeparator(*ptr)))
ptr++;
return ptr;
}
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 64323b7c765f..8cb370e6f833 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -251,7 +251,7 @@ public:
return ReplacementTokens[Tok];
}
- typedef SmallVector<Token, 8>::const_iterator tokens_iterator;
+ typedef SmallVectorImpl<Token>::const_iterator tokens_iterator;
tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); }
tokens_iterator tokens_end() const { return ReplacementTokens.end(); }
bool tokens_empty() const { return ReplacementTokens.empty(); }
@@ -421,7 +421,7 @@ public:
bool isValid() const { return DefDirective != 0; }
bool isInvalid() const { return !isValid(); }
- operator bool() const { return isValid(); }
+ LLVM_EXPLICIT operator bool() const { return isValid(); }
inline DefInfo getPreviousDefinition(bool AllowHidden = false);
const DefInfo getPreviousDefinition(bool AllowHidden = false) const {
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 3acf9151bc52..254ab36fe960 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -54,6 +54,8 @@ public:
/// then loading that module.
class ModuleLoader {
public:
+ ModuleLoader() : HadFatalFailure(false) {}
+
virtual ~ModuleLoader();
/// \brief Attempt to load the given module.
@@ -85,6 +87,8 @@ public:
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) = 0;
+
+ bool HadFatalFailure;
};
}
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index dc75f1803cb7..3a17157f94d5 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -37,7 +37,7 @@ class HeaderSearch;
class ModuleMapParser;
class ModuleMap {
- SourceManager *SourceMgr;
+ SourceManager &SourceMgr;
IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
const LangOptions &LangOpts;
const TargetInfo *Target;
@@ -52,37 +52,64 @@ class ModuleMap {
/// These are always simple C language options.
LangOptions MMapLangOpts;
+ // The module that we are building; related to \c LangOptions::CurrentModule.
+ Module *CompilingModule;
+
+public:
+ // The module that the .cc source file is associated with.
+ Module *SourceModule;
+ std::string SourceModuleName;
+
+private:
/// \brief The top-level modules that are known.
llvm::StringMap<Module *> Modules;
+public:
+ /// \brief Describes the role of a module header.
+ enum ModuleHeaderRole {
+ /// \brief This header is normally included in the module.
+ NormalHeader,
+ /// \brief This header is included but private.
+ PrivateHeader,
+ /// \brief This header is explicitly excluded from the module.
+ ExcludedHeader
+ // Caution: Adding an enumerator needs other changes.
+ // Adjust the number of bits for KnownHeader::Storage.
+ // Adjust the bitfield HeaderFileInfo::HeaderRole size.
+ // Adjust the HeaderFileInfoTrait::ReadData streaming.
+ // Adjust the HeaderFileInfoTrait::EmitData streaming.
+ };
+
/// \brief A header that is known to reside within a given module,
/// whether it was included or excluded.
class KnownHeader {
- llvm::PointerIntPair<Module *, 1, bool> Storage;
+ llvm::PointerIntPair<Module *, 2, ModuleHeaderRole> Storage;
public:
- KnownHeader() : Storage(0, false) { }
- KnownHeader(Module *M, bool Excluded) : Storage(M, Excluded) { }
+ KnownHeader() : Storage(0, NormalHeader) { }
+ KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) { }
/// \brief Retrieve the module the header is stored in.
Module *getModule() const { return Storage.getPointer(); }
- /// \brief Whether this header is explicitly excluded from the module.
- bool isExcluded() const { return Storage.getInt(); }
+ /// \brief The role of this header within the module.
+ ModuleHeaderRole getRole() const { return Storage.getInt(); }
/// \brief Whether this header is available in the module.
bool isAvailable() const {
- return !isExcluded() && getModule()->isAvailable();
+ return getRole() != ExcludedHeader && getModule()->isAvailable();
}
// \brief Whether this known header is valid (i.e., it has an
// associated module).
- operator bool() const { return Storage.getPointer() != 0; }
+ LLVM_EXPLICIT operator bool() const { return Storage.getPointer() != 0; }
};
- typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap;
+private:
+ typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1> >
+ HeadersMap;
- /// \brief Mapping from each header to the module that owns the contents of the
+ /// \brief Mapping from each header to the module that owns the contents of
/// that header.
HeadersMap Headers;
@@ -151,9 +178,9 @@ class ModuleMap {
public:
/// \brief Construct a new module map.
///
- /// \param FileMgr The file manager used to find module files and headers.
- /// This file manager should be shared with the header-search mechanism, since
- /// they will refer to the same headers.
+ /// \param SourceMgr The source manager used to find module files and headers.
+ /// This source manager should be shared with the header-search mechanism,
+ /// since they will refer to the same headers.
///
/// \param DC A diagnostic consumer that will be cloned for use in generating
/// diagnostics.
@@ -161,7 +188,7 @@ public:
/// \param LangOpts Language options for this translation unit.
///
/// \param Target The target for this translation unit.
- ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC,
+ ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo);
@@ -182,9 +209,15 @@ public:
///
/// \param File The header file that is likely to be included.
///
- /// \returns The module that owns the given header file, or null to indicate
+ /// \param RequestingModule Specifies the module the header is intended to be
+ /// used from. Used to disambiguate if a header is present in multiple
+ /// modules.
+ ///
+ /// \returns The module KnownHeader, which provides the module that owns the
+ /// given header file. The KnownHeader is default constructed to indicate
/// that no module owns this header file.
- Module *findModuleForHeader(const FileEntry *File);
+ KnownHeader findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule = NULL);
/// \brief Determine whether the given header is part of a module
/// marked 'unavailable'.
@@ -278,6 +311,16 @@ public:
/// false otherwise.
bool resolveExports(Module *Mod, bool Complain);
+ /// \brief Resolve all of the unresolved uses in the given module.
+ ///
+ /// \param Mod The module whose uses should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving uses,
+ /// false otherwise.
+ bool resolveUses(Module *Mod, bool Complain);
+
/// \brief Resolve all of the unresolved conflicts in the given module.
///
/// \param Mod The module whose conflicts should be resolved.
@@ -307,17 +350,20 @@ public:
void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
/// \brief Adds this header to the given module.
- /// \param Excluded Whether this header is explicitly excluded from the
- /// module; otherwise, it's included in the module.
- void addHeader(Module *Mod, const FileEntry *Header, bool Excluded);
+ /// \param Role The role of the header wrt the module.
+ void addHeader(Module *Mod, const FileEntry *Header,
+ ModuleHeaderRole Role);
/// \brief Parse the given module map file, and record any modules we
/// encounter.
///
/// \param File The file to be parsed.
///
+ /// \param IsSystem Whether this module map file is in a system header
+ /// directory, and therefore should be considered a system module.
+ ///
/// \returns true if an error occurred, false otherwise.
- bool parseModuleMapFile(const FileEntry *File);
+ bool parseModuleMapFile(const FileEntry *File, bool IsSystem);
/// \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 a2a5a77c73d7..b532bf82f049 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -15,6 +15,8 @@
#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+#include "clang/Basic/SourceLocation.h"
+
namespace clang {
class IdentifierInfo;
@@ -32,6 +34,11 @@ class MultipleIncludeOpt {
/// \#endif can be easily detected.
bool ReadAnyTokens;
+ /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens
+ /// processed in the file so far is an #ifndef and an identifier. Used in
+ /// the detection of header guards in a file.
+ bool ImmediatelyAfterTopLevelIfndef;
+
/// ReadAnyTokens - This is set to false when a file is first opened and true
/// any time a token is returned to the client or a (non-multiple-include)
/// directive is parsed. When the final #endif is parsed this is reset back
@@ -42,11 +49,36 @@ class MultipleIncludeOpt {
/// TheMacro - The controlling macro for a file, if valid.
///
const IdentifierInfo *TheMacro;
+
+ /// DefinedMacro - The macro defined right after TheMacro, if any.
+ const IdentifierInfo *DefinedMacro;
+
+ SourceLocation MacroLoc;
+ SourceLocation DefinedLoc;
public:
MultipleIncludeOpt() {
ReadAnyTokens = false;
+ ImmediatelyAfterTopLevelIfndef = false;
DidMacroExpansion = false;
TheMacro = 0;
+ DefinedMacro = 0;
+ }
+
+ SourceLocation GetMacroLocation() const {
+ return MacroLoc;
+ }
+
+ SourceLocation GetDefinedLocation() const {
+ return DefinedLoc;
+ }
+
+ void resetImmediatelyAfterTopLevelIfndef() {
+ ImmediatelyAfterTopLevelIfndef = false;
+ }
+
+ void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) {
+ DefinedMacro = M;
+ DefinedLoc = Loc;
}
/// Invalidate - Permanently mark this file as not being suitable for the
@@ -55,6 +87,8 @@ public:
// If we have read tokens but have no controlling macro, the state-machine
// below can never "accept".
ReadAnyTokens = true;
+ ImmediatelyAfterTopLevelIfndef = false;
+ DefinedMacro = 0;
TheMacro = 0;
}
@@ -63,8 +97,17 @@ public:
/// the "ifndef x" would count as reading tokens.
bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
+ /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive
+ /// was an #ifndef at the beginning of the file.
+ bool getImmediatelyAfterTopLevelIfndef() const {
+ return ImmediatelyAfterTopLevelIfndef;
+ }
+
// If a token is read, remember that we have seen a side-effect in this file.
- void ReadToken() { ReadAnyTokens = true; }
+ void ReadToken() {
+ ReadAnyTokens = true;
+ ImmediatelyAfterTopLevelIfndef = false;
+ }
/// ExpandedMacro - When a macro is expanded with this lexer as the current
/// buffer, this method is called to disable the MIOpt if needed.
@@ -77,7 +120,7 @@ public:
/// ensures that this is only called if there are no tokens read before the
/// \#ifndef. The caller is required to do this, because reading the \#if
/// line obviously reads in in tokens.
- void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
+ void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) {
// If the macro is already set, this is after the top-level #endif.
if (TheMacro)
return Invalidate();
@@ -91,7 +134,9 @@ public:
// Remember that we're in the #if and that we have the macro.
ReadAnyTokens = true;
+ ImmediatelyAfterTopLevelIfndef = true;
TheMacro = M;
+ MacroLoc = Loc;
}
/// \brief Invoked when a top level conditional (except \#ifndef) is found.
@@ -111,6 +156,7 @@ public:
// At this point, we haven't "read any tokens" but we do have a controlling
// macro.
ReadAnyTokens = false;
+ ImmediatelyAfterTopLevelIfndef = false;
}
/// \brief Once the entire file has been lexed, if there is a controlling
@@ -122,6 +168,12 @@ public:
return TheMacro;
return 0;
}
+
+ /// \brief If the ControllingMacro is followed by a macro definition, return
+ /// the macro that was defined.
+ const IdentifierInfo *GetDefinedMacro() const {
+ return DefinedMacro;
+ }
};
} // end namespace clang
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index db2ecd247f40..0e112182794d 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Pragma.h"
#include "llvm/ADT/StringRef.h"
#include <string>
@@ -155,11 +156,23 @@ public:
virtual void Ident(SourceLocation Loc, const std::string &str) {
}
+ /// \brief Callback invoked when start reading any pragma directive.
+ virtual void PragmaDirective(SourceLocation Loc,
+ PragmaIntroducerKind Introducer) {
+ }
+
/// \brief Callback invoked when a \#pragma comment directive is read.
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str) {
}
+ /// \brief Callback invoked when a \#pragma detect_mismatch directive is
+ /// read.
+ virtual void PragmaDetectMismatch(SourceLocation Loc,
+ const std::string &Name,
+ const std::string &Value) {
+ }
+
/// \brief Callback invoked when a \#pragma clang __debug directive is read.
/// \param Loc The location of the debug directive.
/// \param DebugType The identifier following __debug.
@@ -204,6 +217,26 @@ public:
diag::Mapping mapping, StringRef Str) {
}
+ /// \brief Called when an OpenCL extension is either disabled or
+ /// enabled with a pragma.
+ virtual void PragmaOpenCLExtension(SourceLocation NameLoc,
+ const IdentifierInfo *Name,
+ SourceLocation StateLoc, unsigned State) {
+ }
+
+ /// \brief Callback invoked when a \#pragma warning directive is read.
+ virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
+ ArrayRef<int> Ids) {
+ }
+
+ /// \brief Callback invoked when a \#pragma warning(push) directive is read.
+ virtual void PragmaWarningPush(SourceLocation Loc, int Level) {
+ }
+
+ /// \brief Callback invoked when a \#pragma warning(pop) directive is read.
+ virtual void PragmaWarningPop(SourceLocation Loc) {
+ }
+
/// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a
/// macro invocation is found.
virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
@@ -224,7 +257,8 @@ public:
/// \brief Hook called whenever the 'defined' operator is seen.
/// \param MD The MacroDirective if the name was a macro, null otherwise.
- virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD,
+ SourceRange Range) {
}
/// \brief Hook called when a source range is skipped.
@@ -236,18 +270,21 @@ public:
/// \brief Hook called whenever an \#if is seen.
/// \param Loc the source location of the directive.
/// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param ConditionValue The evaluated value of the condition.
///
// FIXME: better to pass in a list (or tree!) of Tokens.
- virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange,
+ bool ConditionValue) {
}
/// \brief Hook called whenever an \#elif is seen.
/// \param Loc the source location of the directive.
/// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param ConditionValue The evaluated value of the condition.
/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
// FIXME: better to pass in a list (or tree!) of Tokens.
virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc) {
+ bool ConditionValue, SourceLocation IfLoc) {
}
/// \brief Hook called whenever an \#ifdef is seen.
@@ -352,6 +389,13 @@ public:
Second->PragmaComment(Loc, Kind, Str);
}
+ virtual void PragmaDetectMismatch(SourceLocation Loc,
+ const std::string &Name,
+ const std::string &Value) {
+ First->PragmaDetectMismatch(Loc, Name, Value);
+ Second->PragmaDetectMismatch(Loc, Name, Value);
+ }
+
virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
PragmaMessageKind Kind, StringRef Str) {
First->PragmaMessage(Loc, Namespace, Kind, Str);
@@ -376,6 +420,29 @@ public:
Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
}
+ virtual void PragmaOpenCLExtension(SourceLocation NameLoc,
+ const IdentifierInfo *Name,
+ SourceLocation StateLoc, unsigned State) {
+ First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State);
+ Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State);
+ }
+
+ virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
+ ArrayRef<int> Ids) {
+ First->PragmaWarning(Loc, WarningSpec, Ids);
+ Second->PragmaWarning(Loc, WarningSpec, Ids);
+ }
+
+ virtual void PragmaWarningPush(SourceLocation Loc, int Level) {
+ First->PragmaWarningPush(Loc, Level);
+ Second->PragmaWarningPush(Loc, Level);
+ }
+
+ virtual void PragmaWarningPop(SourceLocation Loc) {
+ First->PragmaWarningPop(Loc);
+ Second->PragmaWarningPop(Loc);
+ }
+
virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range, const MacroArgs *Args) {
First->MacroExpands(MacroNameTok, MD, Range, Args);
@@ -393,9 +460,10 @@ public:
Second->MacroUndefined(MacroNameTok, MD);
}
- virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
- First->Defined(MacroNameTok, MD);
- Second->Defined(MacroNameTok, MD);
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD,
+ SourceRange Range) {
+ First->Defined(MacroNameTok, MD, Range);
+ Second->Defined(MacroNameTok, MD, Range);
}
virtual void SourceRangeSkipped(SourceRange Range) {
@@ -404,16 +472,17 @@ public:
}
/// \brief Hook called whenever an \#if is seen.
- virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
- First->If(Loc, ConditionRange);
- Second->If(Loc, ConditionRange);
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange,
+ bool ConditionValue) {
+ First->If(Loc, ConditionRange, ConditionValue);
+ Second->If(Loc, ConditionRange, ConditionValue);
}
- /// \brief Hook called whenever an \#if is seen.
+ /// \brief Hook called whenever an \#elif is seen.
virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc) {
- First->Elif(Loc, ConditionRange, IfLoc);
- Second->Elif(Loc, ConditionRange, IfLoc);
+ bool ConditionValue, SourceLocation IfLoc) {
+ First->Elif(Loc, ConditionRange, ConditionValue, IfLoc);
+ Second->Elif(Loc, ConditionRange, ConditionValue, IfLoc);
}
/// \brief Hook called whenever an \#ifdef is seen.
diff --git a/include/clang/Lex/PPConditionalDirectiveRecord.h b/include/clang/Lex/PPConditionalDirectiveRecord.h
index b9a22529e205..54a132d586d1 100644
--- a/include/clang/Lex/PPConditionalDirectiveRecord.h
+++ b/include/clang/Lex/PPConditionalDirectiveRecord.h
@@ -86,9 +86,10 @@ public:
SourceLocation findConditionalDirectiveRegionLoc(SourceLocation Loc) const;
private:
- virtual void If(SourceLocation Loc, SourceRange ConditionRange);
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange,
+ bool ConditionValue);
virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc);
+ bool ConditionValue, SourceLocation IfLoc);
virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
const MacroDirective *MD);
virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index a9276e86b726..d748bc1f7dff 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -68,7 +68,7 @@ public:
~PTHLexer() {}
/// Lex - Return the next token.
- void Lex(Token &Tok);
+ bool Lex(Token &Tok);
void getEOF(Token &Tok);
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index db74352aa81e..2584340f6ec7 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -576,7 +576,8 @@ namespace clang {
virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
const MacroDirective *MD);
/// \brief Hook called whenever the 'defined' operator is seen.
- virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD);
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD,
+ SourceRange Range);
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 c5981777cd29..223fd470eca1 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -20,6 +20,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/PTHManager.h"
@@ -221,7 +222,10 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief The module import path that we're currently processing.
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> ModuleImportPath;
-
+
+ /// \brief Whether the last token we lexed was an '@'.
+ bool LastTokenWasAt;
+
/// \brief Whether the module import expectes an identifier next. Otherwise,
/// it expects a '.' or ';'.
bool ModuleImportExpectsIdentifier;
@@ -457,6 +461,10 @@ public:
/// \brief Retrieve the module loader associated with this preprocessor.
ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
+ bool hadModuleLoaderFatalFailure() const {
+ return TheModuleLoader.HadFatalFailure;
+ }
+
/// \brief True if we are currently preprocessing a #if or #elif directive
bool isParsingIfOrElifDirective() const {
return ParsingIfOrElifDirective;
@@ -711,17 +719,8 @@ public:
/// caching of tokens is on.
bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); }
- /// Lex - To lex a token from the preprocessor, just pull a token from the
- /// current lexer or macro object.
- void Lex(Token &Result) {
- switch (CurLexerKind) {
- case CLK_Lexer: CurLexer->Lex(Result); break;
- case CLK_PTHLexer: CurPTHLexer->Lex(Result); break;
- case CLK_TokenLexer: CurTokenLexer->Lex(Result); break;
- case CLK_CachingLexer: CachingLex(Result); break;
- case CLK_LexAfterModuleImport: LexAfterModuleImport(Result); break;
- }
- }
+ /// Lex - Lex the next token for this preprocessor.
+ void Lex(Token &Result);
void LexAfterModuleImport(Token &Result);
@@ -828,6 +827,13 @@ public:
AnnotatePreviousCachedTokens(Tok);
}
+ /// Get the location of the last cached token, suitable for setting the end
+ /// location of an annotation token.
+ SourceLocation getLastCachedTokenLocation() const {
+ assert(CachedLexPos != 0);
+ return CachedTokens[CachedLexPos-1].getLocation();
+ }
+
/// \brief Replace the last token with an annotation token.
///
/// Like AnnotateCachedTokens(), this routine replaces an
@@ -989,8 +995,9 @@ public:
/// \brief Relex the token at the specified location.
/// \returns true if there was a failure, false on success.
- bool getRawToken(SourceLocation Loc, Token &Result) {
- return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts);
+ bool getRawToken(SourceLocation Loc, Token &Result,
+ bool IgnoreWhiteSpace = false) {
+ return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts, IgnoreWhiteSpace);
}
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
@@ -1155,7 +1162,10 @@ public:
/// identifier and has filled in the tokens IdentifierInfo member. This
/// callback potentially macro expands it or turns it into a named token (like
/// 'for').
- void HandleIdentifier(Token &Identifier);
+ ///
+ /// \returns true if we actually computed a token, false if we need to
+ /// lex again.
+ bool HandleIdentifier(Token &Identifier);
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
@@ -1216,12 +1226,12 @@ public:
///
/// Returns null on failure. \p isAngled indicates whether the file
/// reference is for system \#include's or not (i.e. using <> instead of "").
- const FileEntry *LookupFile(StringRef Filename,
+ const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename,
bool isAngled, const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache = false);
/// GetCurLookup - The DirectoryLookup structure used to find the current
@@ -1273,6 +1283,8 @@ private:
IncludeMacroStack.pop_back();
}
+ void PropagateLineStartLeadingSpaceInfo(Token &Result);
+
/// \brief Allocate a new MacroInfo object.
MacroInfo *AllocateMacroInfo();
@@ -1329,7 +1341,7 @@ private:
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to
/// be expanded as a macro, handle it and return the next token as 'Tok'. If
- /// the macro should not be expanded return true, otherwise return false.
+ /// we lexed a token, return true; otherwise the caller should lex again.
bool HandleMacroExpandedIdentifier(Token &Tok, MacroDirective *MD);
/// \brief Cache macro expanded tokens for TokenLexers.
@@ -1400,7 +1412,7 @@ private:
bool InCachingLexMode() const {
// If the Lexer pointers are 0 and IncludeMacroStack is empty, it means
// that we are past EOF, not that we are in CachingLex mode.
- return CurPPLexer == 0 && CurTokenLexer == 0 && CurPTHLexer == 0 &&
+ return !CurPPLexer && !CurTokenLexer && !CurPTHLexer &&
!IncludeMacroStack.empty();
}
void EnterCachingLexMode();
@@ -1432,8 +1444,32 @@ private:
void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
void HandleMicrosoftImportDirective(Token &Tok);
+ // Module inclusion testing.
+ /// \brief Find the module for the source or header file that \p FilenameLoc
+ /// points to.
+ Module *getModuleForLocation(SourceLocation FilenameLoc);
+
+ /// \brief Verify that a private header is included only from within its
+ /// module.
+ bool violatesPrivateInclude(Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule);
+
+ /// \brief Verify that a module includes headers only from modules that it
+ /// has declared that it uses.
+ bool violatesUseDeclarations(Module *RequestingModule,
+ Module *RequestedModule);
+
+ /// \brief Verify that it is legal for the source file that \p FilenameLoc
+ /// points to to include the file \p Filename.
+ ///
+ /// Tries to reuse \p IncFileEnt.
+ void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename,
+ const FileEntry *IncFileEnt);
+
// Macro handling.
- void HandleDefineDirective(Token &Tok);
+ void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
void HandleUndefDirective(Token &Tok);
// Conditional Inclusion.
@@ -1445,7 +1481,8 @@ private:
void HandleElifDirective(Token &Tok);
// Pragmas.
- void HandlePragmaDirective(unsigned Introducer);
+ void HandlePragmaDirective(SourceLocation IntroducerLoc,
+ PragmaIntroducerKind Introducer);
public:
void HandlePragmaOnce(Token &OnceTok);
void HandlePragmaMark();
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 20fb8a0c4804..27a8df43a274 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -111,9 +111,9 @@ protected:
/// stack, returning information about it. If the conditional stack is empty,
/// this returns true and does not fill in the arguments.
bool popConditionalLevel(PPConditionalInfo &CI) {
- if (ConditionalStack.empty()) return true;
- CI = ConditionalStack.back();
- ConditionalStack.pop_back();
+ if (ConditionalStack.empty())
+ return true;
+ CI = ConditionalStack.pop_back_val();
return false;
}
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index bcbe9c913be1..4f6391d6502d 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -71,13 +71,16 @@ public:
// Various flags set per token:
enum TokenFlags {
- StartOfLine = 0x01, // At start of line or only after whitespace.
- LeadingSpace = 0x02, // Whitespace exists before this token.
+ StartOfLine = 0x01, // At start of line or only after whitespace
+ // (considering the line after macro expansion).
+ LeadingSpace = 0x02, // Whitespace exists before this token (considering
+ // whitespace after macro expansion).
DisableExpand = 0x04, // This identifier may never be macro expanded.
NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
HasUDSuffix = 0x20, // This string or character literal has a ud-suffix.
- HasUCN = 0x40 // This identifier contains a UCN.
+ HasUCN = 0x40, // This identifier contains a UCN.
+ IgnoredComma = 0x80 // This comma is not a macro argument separator (MS).
};
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index 090402a811e2..7c8cfd028a28 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -136,7 +136,7 @@ public:
unsigned isNextTokenLParen() const;
/// Lex - Lex and return a token from this macro stream.
- void Lex(Token &Tok);
+ bool Lex(Token &Tok);
/// isParsingPreprocessorDirective - Return true if we are in the middle of a
/// preprocessor directive.
@@ -181,6 +181,8 @@ private:
/// macro definition.
void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
Token *begin_tokens, Token *end_tokens);
+
+ void PropagateLineStartLeadingSpaceInfo(Token &Result);
};
} // end namespace clang
diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt
index d20708e58c55..ed80c1889c7d 100644
--- a/include/clang/Parse/CMakeLists.txt
+++ b/include/clang/Parse/CMakeLists.txt
@@ -1,7 +1,12 @@
-clang_tablegen(AttrExprArgs.inc -gen-clang-attr-expr-args-list
+clang_tablegen(AttrIdentifierArg.inc -gen-clang-attr-identifier-arg-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
- TARGET ClangAttrExprArgs)
+ TARGET ClangAttrIdentifierArg)
+
+clang_tablegen(AttrTypeArg.inc -gen-clang-attr-type-arg-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrTypeArg)
clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
diff --git a/include/clang/Parse/Makefile b/include/clang/Parse/Makefile
index fb63175ba9b3..00d41fafddeb 100644
--- a/include/clang/Parse/Makefile
+++ b/include/clang/Parse/Makefile
@@ -1,19 +1,25 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = AttrExprArgs.inc AttrLateParsed.inc
+BUILT_SOURCES = AttrIdentifierArg.inc AttrLateParsed.inc AttrTypeArg.inc
TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/AttrExprArgs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+$(ObjDir)/AttrIdentifierArg.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
- $(Echo) "Building Clang attribute expression arguments table with tblgen"
- $(Verb) $(ClangTableGen) -gen-clang-attr-expr-args-list -o $(call SYSPATH, $@) \
+ $(Echo) "Building Clang attribute identifier argument table with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-identifier-arg-list -o $(call SYSPATH, $@) \
+ -I $(PROJ_SRC_DIR)/../../ $<
+
+$(ObjDir)/AttrTypeArg.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+ $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute type argument table with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-type-arg-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
$(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute late-parsed table with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \
- -I $(PROJ_SRC_DIR)/../../ $< \ No newline at end of file
+ -I $(PROJ_SRC_DIR)/../../ $<
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index 0d4729297057..b593806ff391 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define PARSESTART
#include "clang/Basic/DiagnosticParseKinds.inc"
#undef DIAG
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 1029a90c55c8..bd49988c5b00 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -45,6 +45,7 @@ namespace clang {
class InMessageExpressionRAIIObject;
class PoisonSEHIdentifiersRAIIObject;
class VersionTuple;
+ class OMPClause;
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
@@ -101,15 +102,17 @@ class Parser : public CodeCompletionHandler {
/// Contextual keywords for Microsoft extensions.
IdentifierInfo *Ident__except;
+ mutable IdentifierInfo *Ident_sealed;
/// Ident_super - IdentifierInfo for "super", to support fast
/// comparison.
IdentifierInfo *Ident_super;
- /// Ident_vector and Ident_pixel - cached IdentifierInfo's for
- /// "vector" and "pixel" fast comparison. Only present if
- /// AltiVec enabled.
+ /// Ident_vector, Ident_pixel, Ident_bool - cached IdentifierInfo's
+ /// for "vector", "pixel", and "bool" fast comparison. Only present
+ /// if AltiVec enabled.
IdentifierInfo *Ident_vector;
IdentifierInfo *Ident_pixel;
+ IdentifierInfo *Ident_bool;
/// Objective-C contextual keywords.
mutable IdentifierInfo *Ident_instancetype;
@@ -150,6 +153,7 @@ class Parser : public CodeCompletionHandler {
OwningPtr<CommentHandler> CommentSemaHandler;
OwningPtr<PragmaHandler> OpenMPHandler;
OwningPtr<PragmaHandler> MSCommentHandler;
+ OwningPtr<PragmaHandler> MSDetectMismatchHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
@@ -398,7 +402,8 @@ private:
/// \brief Abruptly cut off parsing; mainly used when we have reached the
/// code-completion point.
void cutOffParsing() {
- PP.setCodeCompletionReached();
+ if (PP.isCodeCompletionEnabled())
+ PP.setCodeCompletionReached();
// Cut off parsing by acting as if we reached the end-of-file.
Tok.setKind(tok::eof);
}
@@ -419,6 +424,10 @@ private:
void HandlePragmaMSStruct();
/// \brief Handle the annotation token produced for
+ /// #pragma comment...
+ void HandlePragmaMSComment();
+
+ /// \brief Handle the annotation token produced for
/// #pragma align...
void HandlePragmaAlign();
@@ -525,7 +534,8 @@ private:
bool &isInvalid) {
if (!getLangOpts().AltiVec ||
(Tok.getIdentifierInfo() != Ident_vector &&
- Tok.getIdentifierInfo() != Ident_pixel))
+ Tok.getIdentifierInfo() != Ident_pixel &&
+ Tok.getIdentifierInfo() != Ident_bool))
return false;
return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid);
@@ -545,6 +555,13 @@ private:
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid);
+ /// TryKeywordIdentFallback - For compatibility with system headers using
+ /// keywords as identifiers, attempt to convert the current token to an
+ /// identifier and optionally disable the keyword for the remainder of the
+ /// translation unit. This returns false if the token was not replaced,
+ /// otherwise emits a diagnostic and returns true.
+ bool TryKeywordIdentFallback(bool DisableKeyword);
+
/// \brief Get the TemplateIdAnnotation from the token.
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
@@ -599,6 +616,7 @@ private:
assert(!isActive && "Forgot to call Commit or Revert!");
}
};
+ class UnannotatedTentativeParsingAction;
/// ObjCDeclContextSwitch - An object used to switch context from
/// an objective-c decl context to its enclosing decl context and
@@ -725,32 +743,45 @@ private:
void CheckNestedObjCContexts(SourceLocation AtLoc);
public:
+
+ /// \brief Control flags for SkipUntil functions.
+ enum SkipUntilFlags {
+ StopAtSemi = 1 << 0, ///< Stop skipping at semicolon
+ /// \brief Stop skipping at specified token, but don't skip the token itself
+ StopBeforeMatch = 1 << 1,
+ StopAtCodeCompletion = 1 << 2 ///< Stop at code completion
+ };
+
+ friend LLVM_CONSTEXPR SkipUntilFlags operator|(SkipUntilFlags L,
+ SkipUntilFlags R) {
+ return static_cast<SkipUntilFlags>(static_cast<unsigned>(L) |
+ static_cast<unsigned>(R));
+ }
+
/// SkipUntil - Read tokens until we get to the specified token, then consume
- /// it (unless DontConsume is true). Because we cannot guarantee that the
- /// token will ever occur, this skips to the next token, or to some likely
- /// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
- /// character.
+ /// it (unless StopBeforeMatch is specified). Because we cannot guarantee
+ /// that the token will ever occur, this skips to the next token, or to some
+ /// likely good stopping point. If Flags has StopAtSemi flag, skipping will
+ /// stop at a ';' character.
///
/// If SkipUntil finds the specified token, it returns true, otherwise it
/// returns false.
- bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
- bool DontConsume = false, bool StopAtCodeCompletion = false) {
- return SkipUntil(llvm::makeArrayRef(T), StopAtSemi, DontConsume,
- StopAtCodeCompletion);
+ bool SkipUntil(tok::TokenKind T,
+ SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) {
+ return SkipUntil(llvm::makeArrayRef(T), Flags);
}
- bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true,
- bool DontConsume = false, bool StopAtCodeCompletion = false) {
+ bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2,
+ SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) {
tok::TokenKind TokArray[] = {T1, T2};
- return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion);
+ return SkipUntil(TokArray, Flags);
}
bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3,
- bool StopAtSemi = true, bool DontConsume = false,
- bool StopAtCodeCompletion = false) {
+ SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0)) {
tok::TokenKind TokArray[] = {T1, T2, T3};
- return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion);
+ return SkipUntil(TokArray, Flags);
}
- bool SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi = true,
- bool DontConsume = false, bool StopAtCodeCompletion = false);
+ bool SkipUntil(ArrayRef<tok::TokenKind> Toks,
+ SkipUntilFlags Flags = static_cast<SkipUntilFlags>(0));
/// SkipMalformedDecl - Read tokens until we get to some likely good stopping
/// point for skipping past a simple-declaration.
@@ -1042,32 +1073,21 @@ private:
SourceRange getSourceRange() const LLVM_READONLY;
};
- /// \brief Contains a late templated function.
- /// Will be parsed at the end of the translation unit.
- struct LateParsedTemplatedFunction {
- explicit LateParsedTemplatedFunction(Decl *MD)
- : D(MD) {}
-
- CachedTokens Toks;
-
- /// \brief The template function declaration to be late parsed.
- Decl *D;
- };
-
void LexTemplateFunctionForLateParsing(CachedTokens &Toks);
- void ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT);
- typedef llvm::DenseMap<const FunctionDecl*, LateParsedTemplatedFunction*>
- LateParsedTemplateMapT;
- LateParsedTemplateMapT LateParsedTemplateMap;
+ void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT);
- static void LateTemplateParserCallback(void *P, const FunctionDecl *FD);
- void LateTemplateParser(const FunctionDecl *FD);
+ static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT);
Sema::ParsingClassState
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
void DeallocateParsedClasses(ParsingClass *Class);
void PopParsingClass(Sema::ParsingClassState);
+ enum CachedInitKind {
+ CIK_DefaultArgument,
+ CIK_DefaultInitializer
+ };
+
NamedDecl *ParseCXXInlineMethodDef(AccessSpecifier AS,
AttributeList *AccessAttrs,
ParsingDeclarator &D,
@@ -1089,6 +1109,8 @@ private:
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
+ bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK);
+ bool ConsumeAndStoreConditional(CachedTokens &Toks);
bool ConsumeAndStoreUntil(tok::TokenKind T1,
CachedTokens &Toks,
bool StopAtSemi = true,
@@ -1274,6 +1296,12 @@ private:
ArrayRef<Expr *> Args) = 0,
Expr *Data = 0);
+ /// ParseSimpleExpressionList - A simple comma-separated list of expressions,
+ /// used for misc language extensions.
+ bool ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
+ SmallVectorImpl<SourceLocation> &CommaLocs);
+
+
/// ParenParseOption - Control what ParseParenExpression will parse.
enum ParenParseOption {
SimpleExpr, // Only parse '(' expression ')'
@@ -1325,7 +1353,8 @@ private:
// [...] () -> type {...}
ExprResult ParseLambdaExpression();
ExprResult TryParseLambdaExpression();
- Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro);
+ Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro,
+ bool *SkippedInits = 0);
bool TryParseLambdaIntroducer(LambdaIntroducer &Intro);
ExprResult ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro);
@@ -1461,10 +1490,7 @@ private:
/// A SmallVector of types.
typedef SmallVector<ParsedType, 12> TypeVector;
- StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) {
- StmtVector Stmts;
- return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
- }
+ StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0);
StmtResult ParseStatementOrDeclaration(StmtVector &Stmts,
bool OnlyStatement,
SourceLocation *TrailingElseLoc = 0);
@@ -1628,6 +1654,9 @@ private:
AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal,
LateParsedAttrList *LateAttrs = 0);
+ bool DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+ DeclSpecContext DSContext,
+ LateParsedAttrList *LateAttrs = 0);
void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
DeclSpecContext DSC = DSC_normal);
@@ -1800,6 +1829,11 @@ private:
isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False(),
bool *HasMissingTypename = 0);
+ /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or
+ /// \c TPResult::Ambiguous, determine whether the decl-specifier would be
+ /// a type-specifier other than a cv-qualifier.
+ bool isCXXDeclarationSpecifierAType();
+
/// \brief Determine whether an identifier has been tentatively declared as a
/// non-type. Such tentative declarations should not be found to name a type
/// during a tentative parse, but also should not be annotated as a non-type.
@@ -1812,15 +1846,18 @@ private:
// that more tentative parsing is necessary for disambiguation.
// They all consume tokens, so backtracking should be used after calling them.
- TPResult TryParseDeclarationSpecifier(bool *HasMissingTypename = 0);
TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl);
TPResult TryParseTypeofSpecifier();
TPResult TryParseProtocolQualifiers();
+ TPResult TryParsePtrOperatorSeq();
+ TPResult TryParseOperatorId();
TPResult TryParseInitDeclaratorList();
TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true);
- TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = 0);
+ TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = 0,
+ bool VersusTemplateArg = false);
TPResult TryParseFunctionDeclarator();
TPResult TryParseBracketDeclarator();
+ TPResult TryConsumeDeclarationSpecifier();
public:
TypeResult ParseTypeName(SourceRange *Range = 0,
@@ -1866,6 +1903,10 @@ private:
// for example, attributes appertain to decl specifiers.
void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs);
+ /// \brief Diagnose and skip C++11 attributes that appear in syntactic
+ /// locations where attributes are not allowed.
+ void DiagnoseAndSkipCXX11Attributes();
+
void MaybeParseGNUAttributes(Declarator &D,
LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute)) {
@@ -1891,6 +1932,7 @@ private:
IdentifierInfo *ScopeName,
SourceLocation ScopeLoc,
AttributeList::Syntax Syntax);
+ IdentifierLoc *ParseIdentifierLoc();
void MaybeParseCXX11Attributes(Declarator &D) {
if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
@@ -1961,6 +2003,11 @@ private:
ParsedAttributes &Attrs,
SourceLocation *EndLoc);
+ void ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc);
+
void ParseTypeofSpecifier(DeclSpec &DS);
SourceLocation ParseDecltypeSpecifier(DeclSpec &DS);
void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
@@ -2024,7 +2071,8 @@ private:
void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true,
bool CXX11AttributesAllowed = true,
- bool AtomicAllowed = true);
+ bool AtomicAllowed = true,
+ bool IdentifierRequired = false);
void ParseDirectDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
void ParseFunctionDeclarator(Declarator &D,
@@ -2035,11 +2083,11 @@ private:
bool isFunctionDeclaratorIdentifierList();
void ParseFunctionDeclaratorIdentifierList(
Declarator &D,
- SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo);
+ SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo);
void ParseParameterDeclarationClause(
Declarator &D,
ParsedAttributes &attrs,
- SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc);
void ParseBracketDeclarator(Declarator &D);
@@ -2060,6 +2108,8 @@ private:
isCXX11AttributeSpecifier(bool Disambiguate = false,
bool OuterMightBeMessageSend = false);
+ void DiagnoseUnexpectedNamespace(NamedDecl *Context);
+
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
SourceLocation InlineLoc = SourceLocation());
void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
@@ -2134,9 +2184,44 @@ private:
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
+ /// \brief Parses declarative OpenMP directives.
DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+ /// \brief Parses simple list of variables.
+ ///
+ /// \param Kind Kind of the directive.
+ /// \param [out] VarList List of referenced variables.
+ /// \param AllowScopeSpecifier true, if the variables can have fully
+ /// qualified names.
+ ///
bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
- SmallVectorImpl<DeclarationNameInfo> &IdList);
+ SmallVectorImpl<Expr *> &VarList,
+ bool AllowScopeSpecifier);
+ /// \brief Parses declarative or executable directive.
+ StmtResult ParseOpenMPDeclarativeOrExecutableDirective();
+ /// \brief Parses clause of kind \a CKind for directive of a kind \a Kind.
+ ///
+ /// \param DKind Kind of current directive.
+ /// \param CKind Kind of current clause.
+ /// \param FirstClause true, if this is the first clause of a kind \a CKind
+ /// in current directive.
+ ///
+ OMPClause *ParseOpenMPClause(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind CKind, bool FirstClause);
+ /// \brief Parses clause with a single expression of a kind \a Kind.
+ ///
+ /// \param Kind Kind of current clause.
+ ///
+ OMPClause *ParseOpenMPSingleExprClause(OpenMPClauseKind Kind);
+ /// \brief Parses simple clause of a kind \a Kind.
+ ///
+ /// \param Kind Kind of current clause.
+ ///
+ OMPClause *ParseOpenMPSimpleClause(OpenMPClauseKind Kind);
+ /// \brief Parses clause with the list of variables of a kind \a Kind.
+ ///
+ /// \param Kind Kind of current clause.
+ ///
+ OMPClause *ParseOpenMPVarListClause(OpenMPClauseKind Kind);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
diff --git a/include/clang/Rewrite/Core/HTMLRewrite.h b/include/clang/Rewrite/Core/HTMLRewrite.h
index 88caf85e6010..3cd04615d826 100644
--- a/include/clang/Rewrite/Core/HTMLRewrite.h
+++ b/include/clang/Rewrite/Core/HTMLRewrite.h
@@ -57,7 +57,7 @@ namespace html {
/// in 's' are not interpreted as HTML tags. Unlike the version of
/// EscapeText that rewrites a file, this version by default replaces tabs
/// with spaces.
- std::string EscapeText(const std::string& s,
+ std::string EscapeText(StringRef s,
bool EscapeSpaces = false, bool ReplaceTabs = false);
void AddLineNumbers(Rewriter& R, FileID FID);
diff --git a/include/clang/Rewrite/Core/Rewriter.h b/include/clang/Rewrite/Core/Rewriter.h
index cb044aef23fe..2d2917b910b9 100644
--- a/include/clang/Rewrite/Core/Rewriter.h
+++ b/include/clang/Rewrite/Core/Rewriter.h
@@ -40,20 +40,18 @@ class RewriteBuffer {
/// Deltas - Keep track of all the deltas in the source code due to insertions
/// and deletions.
DeltaTree Deltas;
-
- /// Buffer - This is the actual buffer itself. Note that using a vector or
- /// string is a horribly inefficient way to do this, we should use a rope
- /// instead.
- typedef RewriteRope BufferTy;
- BufferTy Buffer;
+ RewriteRope Buffer;
public:
- typedef BufferTy::const_iterator iterator;
+ typedef RewriteRope::const_iterator iterator;
iterator begin() const { return Buffer.begin(); }
iterator end() const { return Buffer.end(); }
unsigned size() const { return Buffer.size(); }
/// \brief Write to \p Stream the result of applying all changes to the
/// original buffer.
+ /// Note that it isn't safe to use this function to overwrite memory mapped
+ /// files in-place (PR17960). Consider using a higher-level utility such as
+ /// Rewriter::overwriteChangedFiles() instead.
///
/// The original buffer is not actually changed.
raw_ostream &write(raw_ostream &Stream) const;
@@ -149,6 +147,7 @@ public:
};
typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
+ typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator;
explicit Rewriter(SourceManager &SM, const LangOptions &LO)
: SourceMgr(&SM), LangOpts(&LO) {}
@@ -282,10 +281,12 @@ public:
// Iterators over rewrite buffers.
buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
buffer_iterator buffer_end() { return RewriteBuffers.end(); }
+ const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); }
+ const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); }
/// overwriteChangedFiles - Save all changed files to disk.
///
- /// Returns whether not all changes were saved successfully.
+ /// Returns true if any files were not saved successfully.
/// Outputs diagnostics via the source manager's diagnostic engine
/// in case of an error.
bool overwriteChangedFiles();
diff --git a/include/clang/Sema/AnalysisBasedWarnings.h b/include/clang/Sema/AnalysisBasedWarnings.h
index eeac97332dfb..432c4e23a993 100644
--- a/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/include/clang/Sema/AnalysisBasedWarnings.h
@@ -38,6 +38,7 @@ public:
unsigned enableCheckFallThrough : 1;
unsigned enableCheckUnreachable : 1;
unsigned enableThreadSafetyAnalysis : 1;
+ unsigned enableConsumedAnalysis : 1;
public:
Policy();
void disableCheckFallThrough() { enableCheckFallThrough = 0; }
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index d5f31779a635..508064def2ca 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -19,6 +19,7 @@
#include "clang/Basic/VersionTuple.h"
#include "clang/Sema/Ownership.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
@@ -44,6 +45,20 @@ struct AvailabilityChange {
bool isValid() const { return !Version.empty(); }
};
+/// \brief Wraps an identifier and optional source location for the identifier.
+struct IdentifierLoc {
+ SourceLocation Loc;
+ IdentifierInfo *Ident;
+
+ static IdentifierLoc *create(ASTContext &Ctx, SourceLocation Loc,
+ IdentifierInfo *Ident);
+};
+
+/// \brief A union of the various pointer types that can be passed to an
+/// AttributeList as an argument.
+typedef llvm::PointerUnion<Expr*, IdentifierLoc*> ArgsUnion;
+typedef llvm::SmallVector<ArgsUnion, 12U> ArgsVector;
+
/// AttributeList - Represents a syntactic attribute.
///
/// For a GNU attribute, there are four forms of this construct:
@@ -66,13 +81,12 @@ public:
/// __ptr16, alignas(...), etc.
AS_Keyword
};
+
private:
IdentifierInfo *AttrName;
IdentifierInfo *ScopeName;
- IdentifierInfo *ParmName;
SourceRange AttrRange;
SourceLocation ScopeLoc;
- SourceLocation ParmLoc;
SourceLocation EllipsisLoc;
/// The number of expression arguments this attribute has.
@@ -100,6 +114,9 @@ private:
/// Microsoft __delcspec(property) attribute.
unsigned IsProperty : 1;
+ /// True if this has a ParsedType
+ unsigned HasParsedType : 1;
+
unsigned AttrKind : 8;
/// \brief The location of the 'unavailable' keyword in an
@@ -114,22 +131,27 @@ private:
/// The next attribute allocated in the current Pool.
AttributeList *NextInPool;
- Expr **getArgsBuffer() {
- return reinterpret_cast<Expr**>(this+1);
+ /// Arguments, if any, are stored immediately following the object.
+ ArgsUnion *getArgsBuffer() {
+ return reinterpret_cast<ArgsUnion*>(this+1);
}
- Expr * const *getArgsBuffer() const {
- return reinterpret_cast<Expr* const *>(this+1);
+ ArgsUnion const *getArgsBuffer() const {
+ return reinterpret_cast<ArgsUnion const *>(this+1);
}
enum AvailabilitySlot {
IntroducedSlot, DeprecatedSlot, ObsoletedSlot
};
- AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) {
- return reinterpret_cast<AvailabilityChange*>(this+1)[index];
+ /// Availability information is stored immediately following the arguments,
+ /// if any, at the end of the object.
+ AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) {
+ return reinterpret_cast<AvailabilityChange*>(getArgsBuffer()
+ + NumArgs)[index];
}
const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const {
- return reinterpret_cast<const AvailabilityChange*>(this+1)[index];
+ return reinterpret_cast<const AvailabilityChange*>(getArgsBuffer()
+ + NumArgs)[index];
}
public:
@@ -145,14 +167,20 @@ public:
};
private:
+ /// Type tag information is stored immediately following the arguments, if
+ /// any, at the end of the object. They are mutually exlusive with
+ /// availability slots.
TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() {
- return *reinterpret_cast<TypeTagForDatatypeData *>(this + 1);
+ return *reinterpret_cast<TypeTagForDatatypeData*>(getArgsBuffer()+NumArgs);
}
const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const {
- return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1);
+ return *reinterpret_cast<const TypeTagForDatatypeData*>(getArgsBuffer()
+ + NumArgs);
}
+ /// The type buffer immediately follows the object and are mutually exclusive
+ /// with arguments.
ParsedType &getTypeBuffer() {
return *reinterpret_cast<ParsedType *>(this + 1);
}
@@ -161,6 +189,8 @@ private:
return *reinterpret_cast<const ParsedType *>(this + 1);
}
+ /// The property data immediately follows the object is is mutually exclusive
+ /// with arguments.
PropertyData &getPropertyDataBuffer() {
assert(IsProperty);
return *reinterpret_cast<PropertyData*>(this + 1);
@@ -181,36 +211,34 @@ private:
/// Constructor for attributes with expression arguments.
AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
- Expr **args, unsigned numArgs,
+ ArgsUnion *args, unsigned numArgs,
Syntax syntaxUsed, SourceLocation ellipsisLoc)
- : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
- EllipsisLoc(ellipsisLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed),
- Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(false), NextInPosition(0),
- NextInPool(0) {
- if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
+ : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
+ ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs),
+ SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false),
+ IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
+ HasParsedType(false), NextInPosition(0), NextInPool(0) {
+ if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Constructor for availability attributes.
AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
- const AvailabilityChange &introduced,
+ IdentifierLoc *Parm, const AvailabilityChange &introduced,
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
SourceLocation unavailable,
const Expr *messageExpr,
Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(),
- NumArgs(0), SyntaxUsed(syntaxUsed),
+ : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
+ ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
- IsTypeTagForDatatype(false), IsProperty(false),
+ IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
UnavailableLoc(unavailable), MessageExpr(messageExpr),
NextInPosition(0), NextInPool(0) {
+ ArgsUnion PVal(Parm);
+ memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
@@ -220,16 +248,15 @@ private:
/// Constructor for type_tag_for_datatype attribute.
AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *argumentKindName,
- SourceLocation argumentKindLoc,
- ParsedType matchingCType, bool layoutCompatible,
- bool mustBeNull, Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc),
- EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
+ IdentifierLoc *ArgKind, ParsedType matchingCType,
+ bool layoutCompatible, bool mustBeNull, Syntax syntaxUsed)
+ : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
+ ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(true), IsProperty(false), NextInPosition(NULL),
- NextInPool(NULL) {
+ IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false),
+ NextInPosition(NULL), NextInPool(NULL) {
+ ArgsUnion PVal(ArgKind);
+ memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
new (&ExtraData.MatchingCType) ParsedType(matchingCType);
ExtraData.LayoutCompatible = layoutCompatible;
@@ -240,14 +267,12 @@ private:
/// Constructor for attributes with a single type argument.
AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
ParsedType typeArg, Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
- EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(false), NextInPosition(0),
- NextInPool(0) {
+ : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
+ ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
+ Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
+ IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true),
+ NextInPosition(0), NextInPool(0) {
new (&getTypeBuffer()) ParsedType(typeArg);
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
@@ -255,15 +280,13 @@ private:
/// Constructor for microsoft __declspec(property) attribute.
AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
IdentifierInfo *getterId, IdentifierInfo *setterId,
Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
- SyntaxUsed(syntaxUsed),
+ : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
+ ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(true), NextInPosition(0),
- NextInPool(0) {
+ IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false),
+ NextInPosition(0), NextInPool(0) {
new (&getPropertyDataBuffer()) PropertyData(getterId, setterId);
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
@@ -288,8 +311,7 @@ public:
IdentifierInfo *getScopeName() const { return ScopeName; }
SourceLocation getScopeLoc() const { return ScopeLoc; }
- IdentifierInfo *getParameterName() const { return ParmName; }
- SourceLocation getParameterLoc() const { return ParmLoc; }
+ bool hasParsedType() const { return HasParsedType; }
/// Is this the Microsoft __declspec(property) attribute?
bool isDeclspecPropertyAttribute() const {
@@ -326,21 +348,31 @@ public:
/// getNumArgs - Return the number of actual arguments to this attribute.
unsigned getNumArgs() const { return NumArgs; }
- /// hasParameterOrArguments - Return true if this attribute has a parameter,
- /// or has a non empty argument expression list.
- bool hasParameterOrArguments() const { return ParmName || NumArgs; }
-
/// getArg - Return the specified argument.
- Expr *getArg(unsigned Arg) const {
+ ArgsUnion getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
return getArgsBuffer()[Arg];
}
+ bool isArgExpr(unsigned Arg) const {
+ return Arg < NumArgs && getArg(Arg).is<Expr*>();
+ }
+ Expr *getArgAsExpr(unsigned Arg) const {
+ return getArg(Arg).get<Expr*>();
+ }
+
+ bool isArgIdent(unsigned Arg) const {
+ return Arg < NumArgs && getArg(Arg).is<IdentifierLoc*>();
+ }
+ IdentifierLoc *getArgAsIdent(unsigned Arg) const {
+ return getArg(Arg).get<IdentifierLoc*>();
+ }
+
class arg_iterator {
- Expr * const *X;
+ ArgsUnion const *X;
unsigned Idx;
public:
- arg_iterator(Expr * const *x, unsigned idx) : X(x), Idx(idx) {}
+ arg_iterator(ArgsUnion const *x, unsigned idx) : X(x), Idx(idx) {}
arg_iterator& operator++() {
++Idx;
@@ -357,7 +389,7 @@ public:
return !operator==(I);
}
- Expr* operator*() const {
+ ArgsUnion operator*() const {
return X[Idx];
}
@@ -418,7 +450,7 @@ public:
}
const ParsedType &getTypeArg() const {
- assert(getKind() == AT_VecTypeHint && "Not a type attribute");
+ assert(HasParsedType && "Not a type attribute");
return getTypeBuffer();
}
@@ -431,6 +463,10 @@ public:
/// defined in Attr.td. This index is used by an attribute
/// to pretty print itself.
unsigned getAttributeSpellingListIndex() const;
+
+ bool hasCustomParsing() const;
+ unsigned getMinArgs() const;
+ unsigned getMaxArgs() const;
};
/// A factory, from which one makes pools, from which one creates
@@ -445,11 +481,13 @@ public:
/// which we want to ensure is a multiple of sizeof(void*).
AvailabilityAllocSize =
sizeof(AttributeList)
- + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1)
+ + ((3 * sizeof(AvailabilityChange) + sizeof(void*) +
+ sizeof(ArgsUnion) - 1)
/ sizeof(void*) * sizeof(void*)),
TypeTagForDatatypeAllocSize =
sizeof(AttributeList)
- + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1)
+ + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) +
+ sizeof(ArgsUnion) - 1)
/ sizeof(void*) * sizeof(void*),
PropertyAllocSize =
sizeof(AttributeList)
@@ -541,22 +579,20 @@ public:
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
- Expr **args, unsigned numArgs,
+ ArgsUnion *args, unsigned numArgs,
AttributeList::Syntax syntax,
SourceLocation ellipsisLoc = SourceLocation()) {
void *memory = allocate(sizeof(AttributeList)
- + numArgs * sizeof(Expr*));
+ + numArgs * sizeof(ArgsUnion));
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
- parmName, parmLoc,
args, numArgs, syntax,
ellipsisLoc));
}
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
+ IdentifierLoc *Param,
const AvailabilityChange &introduced,
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
@@ -566,9 +602,9 @@ public:
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
- parmName, parmLoc,
- introduced, deprecated, obsoleted,
- unavailable, MessageExpr, syntax));
+ Param, introduced, deprecated,
+ obsoleted, unavailable, MessageExpr,
+ syntax));
}
AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
@@ -577,40 +613,35 @@ public:
AttributeList *createTypeTagForDatatype(
IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *argumentKindName,
- SourceLocation argumentKindLoc,
- ParsedType matchingCType, bool layoutCompatible,
- bool mustBeNull, AttributeList::Syntax syntax) {
+ IdentifierLoc *argumentKind, ParsedType matchingCType,
+ bool layoutCompatible, bool mustBeNull,
+ AttributeList::Syntax syntax) {
void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize);
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
- argumentKindName, argumentKindLoc,
- matchingCType, layoutCompatible,
- mustBeNull, syntax));
+ argumentKind, matchingCType,
+ layoutCompatible, mustBeNull,
+ syntax));
}
AttributeList *createTypeAttribute(
IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
void *memory = allocate(sizeof(AttributeList) + sizeof(void *));
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
- parmName, parmLoc,
typeArg, syntaxUsed));
}
AttributeList *createPropertyAttribute(
IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
IdentifierInfo *getterId, IdentifierInfo *setterId,
AttributeList::Syntax syntaxUsed) {
void *memory = allocate(AttributeFactory::PropertyAllocSize);
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
- parmName, parmLoc,
getterId, setterId,
syntaxUsed));
}
@@ -709,13 +740,12 @@ public:
/// Add attribute with expression arguments.
AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
- Expr **args, unsigned numArgs,
+ ArgsUnion *args, unsigned numArgs,
AttributeList::Syntax syntax,
SourceLocation ellipsisLoc = SourceLocation()) {
AttributeList *attr =
- pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
- args, numArgs, syntax, ellipsisLoc);
+ pool.create(attrName, attrRange, scopeName, scopeLoc, args, numArgs,
+ syntax, ellipsisLoc);
add(attr);
return attr;
}
@@ -723,7 +753,7 @@ public:
/// Add availability attribute.
AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
+ IdentifierLoc *Param,
const AvailabilityChange &introduced,
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
@@ -731,9 +761,8 @@ public:
const Expr *MessageExpr,
AttributeList::Syntax syntax) {
AttributeList *attr =
- pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
- introduced, deprecated, obsoleted, unavailable,
- MessageExpr, syntax);
+ pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced,
+ deprecated, obsoleted, unavailable, MessageExpr, syntax);
add(attr);
return attr;
}
@@ -742,16 +771,14 @@ public:
AttributeList *addNewTypeTagForDatatype(
IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *argumentKindName,
- SourceLocation argumentKindLoc,
- ParsedType matchingCType, bool layoutCompatible,
- bool mustBeNull, AttributeList::Syntax syntax) {
+ IdentifierLoc *argumentKind, ParsedType matchingCType,
+ bool layoutCompatible, bool mustBeNull,
+ AttributeList::Syntax syntax) {
AttributeList *attr =
pool.createTypeTagForDatatype(attrName, attrRange,
scopeName, scopeLoc,
- argumentKindName, argumentKindLoc,
- matchingCType, layoutCompatible,
- mustBeNull, syntax);
+ argumentKind, matchingCType,
+ layoutCompatible, mustBeNull, syntax);
add(attr);
return attr;
}
@@ -760,11 +787,10 @@ public:
AttributeList *
addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
AttributeList *attr =
pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc,
- parmName, parmLoc, typeArg, syntaxUsed);
+ typeArg, syntaxUsed);
add(attr);
return attr;
}
@@ -773,13 +799,11 @@ public:
AttributeList *
addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
- IdentifierInfo *parmName, SourceLocation parmLoc,
IdentifierInfo *getterId, IdentifierInfo *setterId,
AttributeList::Syntax syntaxUsed) {
AttributeList *attr =
pool.createPropertyAttribute(attrName, attrRange, scopeName, scopeLoc,
- parmName, parmLoc, getterId, setterId,
- syntaxUsed);
+ getterId, setterId, syntaxUsed);
add(attr);
return attr;
}
@@ -798,6 +822,15 @@ private:
AttributeList *list;
};
+/// These constants match the enumerated choices of
+/// err_attribute_argument_n_type and err_attribute_argument_type.
+enum AttributeArgumentNType {
+ AANT_ArgumentIntOrBool,
+ AANT_ArgumentIntegerConstant,
+ AANT_ArgumentString,
+ AANT_ArgumentIdentifier
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/Sema/CMakeLists.txt b/include/clang/Sema/CMakeLists.txt
index 6b5d222b5d56..5a48b901d2bf 100644
--- a/include/clang/Sema/CMakeLists.txt
+++ b/include/clang/Sema/CMakeLists.txt
@@ -17,3 +17,8 @@ clang_tablegen(AttrSpellingListIndex.inc -gen-clang-attr-spelling-index
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrSpellingListIndex)
+
+clang_tablegen(AttrParsedAttrImpl.inc -gen-clang-attr-parsed-attr-impl
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrParsedAttrImpl)
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index a1ddec7520ad..64de82c6b05f 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -271,22 +271,17 @@ private:
QualType BaseType;
/// \brief The identifiers for Objective-C selector parts.
- IdentifierInfo **SelIdents;
-
- /// \brief The number of Objective-C selector parts.
- unsigned NumSelIdents;
+ ArrayRef<IdentifierInfo *> SelIdents;
public:
/// \brief Construct a new code-completion context of the given kind.
- CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL),
- NumSelIdents(0) { }
+ CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(None) { }
/// \brief Construct a new code-completion context of the given kind.
CodeCompletionContext(enum Kind Kind, QualType T,
- IdentifierInfo **SelIdents = NULL,
- unsigned NumSelIdents = 0) : Kind(Kind),
- SelIdents(SelIdents),
- NumSelIdents(NumSelIdents) {
+ ArrayRef<IdentifierInfo *> SelIdents = None)
+ : Kind(Kind),
+ SelIdents(SelIdents) {
if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess ||
Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage ||
Kind == CCC_ObjCInstanceMessage)
@@ -308,10 +303,7 @@ public:
QualType getBaseType() const { return BaseType; }
/// \brief Retrieve the Objective-C selector identifiers.
- IdentifierInfo **getSelIdents() const { return SelIdents; }
-
- /// \brief Retrieve the number of Objective-C selector identifiers.
- unsigned getNumSelIdents() const { return NumSelIdents; }
+ ArrayRef<IdentifierInfo *> getSelIdents() const { return SelIdents; }
/// \brief Determines whether we want C++ constructors as results within this
/// context.
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 059919a35bb0..8f6bd186a7dc 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -337,6 +337,7 @@ private:
// function-specifier
unsigned FS_inline_specified : 1;
+ unsigned FS_forceinline_specified: 1;
unsigned FS_virtual_specified : 1;
unsigned FS_explicit_specified : 1;
unsigned FS_noreturn_specified : 1;
@@ -381,6 +382,7 @@ private:
SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
+ SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
WrittenBuiltinSpecs writtenBS;
@@ -419,6 +421,7 @@ public:
TypeSpecOwned(false),
TypeQualifiers(TQ_unspecified),
FS_inline_specified(false),
+ FS_forceinline_specified(false),
FS_virtual_specified(false),
FS_explicit_specified(false),
FS_noreturn_specified(false),
@@ -458,6 +461,12 @@ public:
ThreadStorageClassSpecLoc = SourceLocation();
}
+ void ClearTypeSpecType() {
+ TypeSpecType = DeclSpec::TST_unspecified;
+ TypeSpecOwned = false;
+ TSTLoc = SourceLocation();
+ }
+
// type-specifier
TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; }
TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; }
@@ -504,6 +513,8 @@ public:
return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto;
}
+ bool hasTagDefinition() const;
+
/// \brief Turn a type-specifier-type into a string like "_Bool" or "union".
static const char *getSpecifierName(DeclSpec::TST T);
static const char *getSpecifierName(DeclSpec::TQ Q);
@@ -532,8 +543,12 @@ public:
}
// function-specifier
- bool isInlineSpecified() const { return FS_inline_specified; }
- SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; }
+ bool isInlineSpecified() const {
+ return FS_inline_specified | FS_forceinline_specified;
+ }
+ SourceLocation getInlineSpecLoc() const {
+ return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
+ }
bool isVirtualSpecified() const { return FS_virtual_specified; }
SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; }
@@ -547,6 +562,8 @@ public:
void ClearFunctionSpecs() {
FS_inline_specified = false;
FS_inlineLoc = SourceLocation();
+ FS_forceinline_specified = false;
+ FS_forceinlineLoc = SourceLocation();
FS_virtual_specified = false;
FS_virtualLoc = SourceLocation();
FS_explicit_specified = false;
@@ -615,6 +632,8 @@ public:
const char *&PrevSpec, unsigned &DiagID);
bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID);
+ bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID);
bool SetTypeSpecError();
void UpdateDeclRep(Decl *Rep) {
assert(isDeclRep((TST) TypeSpecType));
@@ -632,10 +651,16 @@ public:
bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, const LangOptions &Lang);
- bool setFunctionSpecInline(SourceLocation Loc);
- bool setFunctionSpecVirtual(SourceLocation Loc);
- bool setFunctionSpecExplicit(SourceLocation Loc);
- bool setFunctionSpecNoreturn(SourceLocation Loc);
+ bool setFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
+ bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
@@ -1500,6 +1525,7 @@ public:
ObjCCatchContext, // Objective-C catch exception-declaration
BlockLiteralContext, // Block literal declarator.
LambdaExprContext, // Lambda-expression declarator.
+ LambdaExprParameterContext, // Lambda-expression parameter declarator.
ConversionIdContext, // C++ conversion-type-id.
TrailingReturnContext, // C++11 trailing-type-specifier.
TemplateTypeArgContext, // Template type argument.
@@ -1575,7 +1601,6 @@ public:
~Declarator() {
clear();
}
-
/// getDeclSpec - Return the declaration-specifier that this declarator was
/// declared with.
const DeclSpec &getDeclSpec() const { return DS; }
@@ -1604,7 +1629,8 @@ public:
bool isPrototypeContext() const {
return (Context == PrototypeContext ||
Context == ObjCParameterContext ||
- Context == ObjCResultContext);
+ Context == ObjCResultContext ||
+ Context == LambdaExprParameterContext);
}
/// \brief Get the source range that spans this declarator.
@@ -1668,6 +1694,7 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
@@ -1696,6 +1723,7 @@ public:
case ForContext:
case ConditionContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case TemplateParamContext:
case CXXCatchContext:
case ObjCCatchContext:
@@ -1717,6 +1745,39 @@ 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 ConditionContext:
+ case PrototypeContext:
+ case LambdaExprParameterContext:
+ case TemplateParamContext:
+ case CXXCatchContext:
+ case ObjCCatchContext:
+ case TypeNameContext:
+ case ConversionIdContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
+ case BlockLiteralContext:
+ case CXXNewContext:
+ case LambdaExprContext:
+ return false;
+
+ case AliasDeclContext:
+ case AliasTemplateContext:
+ case TemplateTypeArgContext:
+ case TrailingReturnContext:
+ return true;
+ }
+ llvm_unreachable("unknown context kind!");
+ }
+
/// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
/// followed by a C++ direct initializer, e.g. "int x(1);".
bool mayBeFollowedByCXXDirectInit() const {
@@ -1748,6 +1809,7 @@ public:
case KNRTypeListContext:
case MemberContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
@@ -1934,6 +1996,7 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
@@ -1995,7 +2058,7 @@ public:
/// \brief Return a source range list of C++11 attributes associated
/// with the declarator.
- void getCXX11AttributeRanges(SmallVector<SourceRange, 4> &Ranges) {
+ void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &Ranges) {
AttributeList *AttrList = Attrs.getList();
while (AttrList) {
if (AttrList->isCXX11Attribute())
@@ -2038,6 +2101,16 @@ public:
return (FunctionDefinitionKind)FunctionDefinition;
}
+ /// Returns true if this declares a real member and not a friend.
+ bool isFirstDeclarationOfMember() {
+ return getContext() == MemberContext && !getDeclSpec().isFriendSpecified();
+ }
+
+ /// Returns true if this declares a static member. This cannot be called on a
+ /// declarator outside of a MemberContext because we won't know until
+ /// redeclaration time if the decl is static.
+ bool isStaticMember();
+
void setRedeclaration(bool Val) { Redeclaration = Val; }
bool isRedeclaration() const { return Redeclaration; }
};
@@ -2057,7 +2130,8 @@ public:
enum Specifier {
VS_None = 0,
VS_Override = 1,
- VS_Final = 2
+ VS_Final = 2,
+ VS_Sealed = 4
};
VirtSpecifiers() : Specifiers(0) { }
@@ -2068,7 +2142,8 @@ public:
bool isOverrideSpecified() const { return Specifiers & VS_Override; }
SourceLocation getOverrideLoc() const { return VS_overrideLoc; }
- bool isFinalSpecified() const { return Specifiers & VS_Final; }
+ bool isFinalSpecified() const { return Specifiers & (VS_Final | VS_Sealed); }
+ bool isFinalSpelledSealed() const { return Specifiers & VS_Sealed; }
SourceLocation getFinalLoc() const { return VS_finalLoc; }
void clear() { Specifiers = 0; }
@@ -2088,13 +2163,16 @@ private:
struct LambdaCapture {
LambdaCaptureKind Kind;
SourceLocation Loc;
- IdentifierInfo* Id;
+ IdentifierInfo *Id;
SourceLocation EllipsisLoc;
-
+ ExprResult Init;
+ ParsedType InitCaptureType;
LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
- IdentifierInfo* Id = 0,
- SourceLocation EllipsisLoc = SourceLocation())
- : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc)
+ IdentifierInfo* Id,
+ SourceLocation EllipsisLoc,
+ ExprResult Init, ParsedType InitCaptureType)
+ : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init),
+ InitCaptureType(InitCaptureType)
{}
};
@@ -2111,11 +2189,13 @@ struct LambdaIntroducer {
/// \brief Append a capture in a lambda introducer.
void addCapture(LambdaCaptureKind Kind,
SourceLocation Loc,
- IdentifierInfo* Id = 0,
- SourceLocation EllipsisLoc = SourceLocation()) {
- Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc));
+ IdentifierInfo* Id,
+ SourceLocation EllipsisLoc,
+ ExprResult Init,
+ ParsedType InitCaptureType) {
+ Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init,
+ InitCaptureType));
}
-
};
} // end namespace clang
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index 3704e095c74f..4f4a87fe11f2 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -6,16 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the DelayedDiagnostic class, which is used to
-// record diagnostics that are being conditionally produced during
-// declarator parsing. Certain kinds of diagnostics --- notably
-// deprecation and access control --- are suppressed based on
-// semantic properties of the parsed declaration that aren't known
-// until it is fully parsed.
-//
-// This file also defines AccessedEntity.
-//
+///
+/// \file
+/// \brief Defines the classes clang::DelayedDiagnostic and
+/// clang::AccessedEntity.
+///
+/// DelayedDiangostic is used to record diagnostics that are being
+/// conditionally produced during declarator parsing. Certain kinds of
+/// diagnostics -- notably deprecation and access control -- are suppressed
+/// based on semantic properties of the parsed declaration that aren't known
+/// until it is fully parsed.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
@@ -224,8 +225,7 @@ private:
};
};
-/// DelayedDiagnosticPool - A collection of diagnostics which were
-/// delayed.
+/// \brief A collection of diagnostics which were delayed.
class DelayedDiagnosticPool {
const DelayedDiagnosticPool *Parent;
SmallVector<DelayedDiagnostic, 4> Diagnostics;
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index cbce757ea7d0..325abdf8e517 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -14,6 +14,8 @@
#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Type.h"
+#include "clang/Sema/TypoCorrection.h"
#include "clang/Sema/Weak.h"
#include "llvm/ADT/MapVector.h"
#include <utility>
@@ -30,7 +32,8 @@ class Sema;
class TypedefNameDecl;
class ValueDecl;
class VarDecl;
-
+struct LateParsedTemplate;
+
/// \brief A simple structure that captures a vtable use for the purposes of
/// the \c ExternalSemaSource.
struct ExternalVTableUse {
@@ -177,6 +180,45 @@ public:
SmallVectorImpl<std::pair<ValueDecl *,
SourceLocation> > &Pending) {}
+ /// \brief Read the set of late parsed template functions for this source.
+ ///
+ /// The external source should insert its own late parsed template functions
+ /// into the map. Note that this routine may be invoked multiple times; the
+ /// external source should take care not to introduce the same map entries
+ /// repeatedly.
+ virtual void ReadLateParsedTemplates(
+ llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {}
+
+ /// \copydoc Sema::CorrectTypo
+ /// \note LookupKind must correspond to a valid Sema::LookupNameKind
+ ///
+ /// ExternalSemaSource::CorrectTypo is always given the first chance to
+ /// correct a typo (really, to offer suggestions to repair a failed lookup).
+ /// It will even be called when SpellChecking is turned off or after a
+ /// fatal error has already been detected.
+ virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+ return TypoCorrection();
+ }
+
+ /// \brief Produces a diagnostic note if the external source contains a
+ /// complete definition for \p T.
+ ///
+ /// \param Loc the location at which a complete type was required but not
+ /// provided
+ ///
+ /// \param T the \c QualType that should have been complete at \p Loc
+ ///
+ /// \return true if a diagnostic was produced, false otherwise.
+ virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc,
+ QualType T) {
+ return false;
+ }
+
// isa/cast/dyn_cast support
static bool classof(const ExternalASTSource *Source) {
return Source->SemaSource;
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 0b1b74a0d8cc..99d94a1fed85 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -51,11 +51,6 @@ class IdentifierResolver {
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
- /// Replaces the Old declaration with the New declaration. If the
- /// replacement is successful, returns true. If the old
- /// declaration was not found, returns false.
- bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
-
/// \brief Insert the given declaration at the given position in the list.
void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) {
Decls.insert(Pos, D);
@@ -168,11 +163,6 @@ public:
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
- /// Replace the decl Old with the new declaration New on its
- /// identifier chain. Returns true if the old declaration was found
- /// (and, therefore, replaced).
- bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
-
/// \brief Insert the given declaration after the given iterator
/// position.
void InsertDeclAfter(iterator Pos, NamedDecl *D);
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 58781ac628c4..83fb2be5f15f 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -35,6 +35,7 @@ class ParmVarDecl;
class Sema;
class TypeLoc;
class VarDecl;
+class ObjCMethodDecl;
/// \brief Describes an entity that is being initialized.
class InitializedEntity {
@@ -78,7 +79,17 @@ public:
EK_LambdaCapture,
/// \brief The entity being initialized is the initializer for a compound
/// literal.
- EK_CompoundLiteralInit
+ EK_CompoundLiteralInit,
+ /// \brief The entity being implicitly initialized back to the formal
+ /// result type.
+ EK_RelatedResult,
+ /// \brief The entity being initialized is a function parameter; function
+ /// is member of group of audited CF APIs.
+ EK_Parameter_CF_Audited
+
+ // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this
+ // enum as an index for its first %select. When modifying this list,
+ // that diagnostic text needs to be updated as well.
};
private:
@@ -105,8 +116,8 @@ private:
};
struct C {
- /// \brief The variable being captured by an EK_LambdaCapture.
- VarDecl *Var;
+ /// \brief The name of the variable being captured by an EK_LambdaCapture.
+ IdentifierInfo *VarID;
/// \brief The source location at which the capture occurs.
unsigned Location;
@@ -116,6 +127,10 @@ private:
/// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
/// FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
+
+ /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where
+ /// result type was implicitly changed to accommodate ARC semantics.
+ ObjCMethodDecl *MethodDecl;
/// \brief When Kind == EK_Parameter, the ParmVarDecl, with the
/// low bit indicating whether the parameter is "consumed".
@@ -168,10 +183,10 @@ private:
const InitializedEntity &Parent);
/// \brief Create the initialization entity for a lambda capture.
- InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc)
- : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType())
+ InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc)
+ : Kind(EK_LambdaCapture), Parent(0), Type(FieldType)
{
- Capture.Var = Var;
+ Capture.VarID = VarID;
Capture.Location = Loc.getRawEncoding();
}
@@ -254,10 +269,19 @@ public:
Result.TypeInfo = TypeInfo;
return Result;
}
+
+ /// \brief Create the initialization entity for a related result.
+ static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD,
+ QualType Type) {
+ InitializedEntity Result(EK_RelatedResult, SourceLocation(), Type);
+ Result.MethodDecl = MD;
+ return Result;
+ }
+
/// \brief Create the initialization entity for a base class subobject.
static InitializedEntity InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base,
+ const CXXBaseSpecifier *Base,
bool IsInheritedVirtualBase);
/// \brief Create the initialization entity for a delegated constructor.
@@ -285,10 +309,10 @@ public:
}
/// \brief Create the initialization entity for a lambda capture.
- static InitializedEntity InitializeLambdaCapture(VarDecl *Var,
- FieldDecl *Field,
+ static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
+ QualType FieldType,
SourceLocation Loc) {
- return InitializedEntity(Var, Field, Loc);
+ return InitializedEntity(VarID, FieldType, Loc);
}
/// \brief Create the entity for a compound literal initializer.
@@ -326,22 +350,29 @@ public:
/// \brief Retrieve the variable, parameter, or field being
/// initialized.
DeclaratorDecl *getDecl() const;
+
+ /// \brief Retrieve the ObjectiveC method being initialized.
+ ObjCMethodDecl *getMethodDecl() const { return MethodDecl; }
/// \brief Determine whether this initialization allows the named return
/// value optimization, which also applies to thrown objects.
bool allowsNRVO() const;
+ bool isParameterKind() const {
+ return (getKind() == EK_Parameter ||
+ getKind() == EK_Parameter_CF_Audited);
+ }
/// \brief Determine whether this initialization consumes the
/// parameter.
bool isParameterConsumed() const {
- assert(getKind() == EK_Parameter && "Not a parameter");
+ assert(isParameterKind() && "Not a parameter");
return (Parameter & 1);
}
/// \brief Retrieve the base specifier.
- CXXBaseSpecifier *getBaseSpecifier() const {
+ const CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
- return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1);
+ return reinterpret_cast<const CXXBaseSpecifier *>(Base & ~0x1);
}
/// \brief Return whether the base is an inherited virtual base.
@@ -371,19 +402,28 @@ public:
getKind() == EK_ComplexElement);
this->Index = Index;
}
-
- /// \brief Retrieve the variable for a captured variable in a lambda.
- VarDecl *getCapturedVar() const {
+ /// \brief For a lambda capture, return the capture's name.
+ StringRef getCapturedVarName() const {
assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
- return Capture.Var;
+ return Capture.VarID->getName();
}
-
/// \brief Determine the location of the capture when initializing
/// field from a captured variable in a lambda.
SourceLocation getCaptureLoc() const {
assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
return SourceLocation::getFromRawEncoding(Capture.Location);
}
+
+ void setParameterCFAudited() {
+ Kind = EK_Parameter_CF_Audited;
+ }
+
+ /// Dump a representation of the initialized entity to standard error,
+ /// for debugging purposes.
+ void dump() const;
+
+private:
+ unsigned dumpImpl(raw_ostream &OS) const;
};
/// \brief Describes the kind of initialization being performed, along with
@@ -544,8 +584,10 @@ public:
bool AllowExplicit() const { return !isCopyInit(); }
/// \brief Retrieve whether this initialization allows the use of explicit
- /// conversion functions.
- bool allowExplicitConversionFunctions() const {
+ /// conversion functions when binding a reference. If the reference is the
+ /// first parameter in a copy or move constructor, such conversions are
+ /// permitted even though we are performing copy-initialization.
+ bool allowExplicitConversionFunctionsInRefBinding() const {
return !isCopyInit() || Context == IC_ExplicitConvs;
}
@@ -610,6 +652,8 @@ public:
SK_LValueToRValue,
/// \brief Perform an implicit conversion sequence.
SK_ConversionSequence,
+ /// \brief Perform an implicit conversion sequence without narrowing.
+ SK_ConversionSequenceNoNarrowing,
/// \brief Perform list-initialization without a constructor
SK_ListInitialization,
/// \brief Perform list-initialization with a constructor.
@@ -706,6 +750,16 @@ public:
/// \brief Array must be initialized with an initializer list or a
/// string literal.
FK_ArrayNeedsInitListOrStringLiteral,
+ /// \brief Array must be initialized with an initializer list or a
+ /// wide string literal.
+ FK_ArrayNeedsInitListOrWideStringLiteral,
+ /// \brief Initializing a wide char array with narrow string literal.
+ FK_NarrowStringIntoWideCharArray,
+ /// \brief Initializing char array with wide string literal.
+ FK_WideStringIntoCharArray,
+ /// \brief Initializing wide char array with incompatible wide string
+ /// literal.
+ FK_IncompatWideStringIntoWideChar,
/// \brief Array type mismatch.
FK_ArrayTypeMismatch,
/// \brief Non-constant array initializer
@@ -753,9 +807,6 @@ public:
/// \brief Initializer has a placeholder type which cannot be
/// resolved by initialization.
FK_PlaceholderType,
- /// \brief Failed to initialize a std::initializer_list because copy
- /// construction of some element failed.
- FK_InitListElementCopyFailure,
/// \brief List-copy-initialization chose an explicit constructor.
FK_ExplicitConstructor
};
@@ -791,11 +842,19 @@ public:
/// \param Kind the kind of initialization being performed.
///
/// \param Args the argument(s) provided for initialization.
+ ///
+ /// \param InInitList true if we are initializing from an expression within
+ /// an initializer list. This disallows narrowing conversions in C++11
+ /// onwards.
InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
- MultiExprArg Args);
-
+ MultiExprArg Args,
+ bool InInitList = false);
+ void InitializeFrom(Sema &S, const InitializedEntity &Entity,
+ const InitializationKind &Kind, MultiExprArg Args,
+ bool InInitList);
+
~InitializationSequence();
/// \brief Perform the actual initialization of the given entity based on
@@ -841,12 +900,12 @@ public:
void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; }
/// \brief Determine whether the initialization sequence is valid.
- operator bool() const { return !Failed(); }
+ LLVM_EXPLICIT operator bool() const { return !Failed(); }
/// \brief Determine whether the initialization sequence is invalid.
bool Failed() const { return SequenceKind == FailedSequence; }
-
- typedef SmallVector<Step, 4>::const_iterator step_iterator;
+
+ typedef SmallVectorImpl<Step>::const_iterator step_iterator;
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
@@ -930,7 +989,7 @@ public:
/// \brief Add a new step that applies an implicit conversion sequence.
void AddConversionSequenceStep(const ImplicitConversionSequence &ICS,
- QualType T);
+ QualType T, bool TopLevelOfInitList = false);
/// \brief Add a list-initialization step.
void AddListInitializationStep(QualType T);
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 3e7e3a16ebc8..105c8791e222 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -139,7 +139,8 @@ public:
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
- AllowHidden(Redecl == Sema::ForRedeclaration)
+ AllowHidden(Redecl == Sema::ForRedeclaration),
+ Shadowed(false)
{
configure();
}
@@ -160,7 +161,8 @@ public:
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
- AllowHidden(Redecl == Sema::ForRedeclaration)
+ AllowHidden(Redecl == Sema::ForRedeclaration),
+ Shadowed(false)
{
configure();
}
@@ -179,7 +181,8 @@ public:
Redecl(Other.Redecl),
HideTags(Other.HideTags),
Diagnose(false),
- AllowHidden(Other.AllowHidden)
+ AllowHidden(Other.AllowHidden),
+ Shadowed(false)
{}
~LookupResult() {
@@ -283,33 +286,36 @@ public:
/// \brief Determine whether the given declaration is visible to the
/// program.
- static bool isVisible(NamedDecl *D) {
+ static bool isVisible(Sema &SemaRef, NamedDecl *D) {
// If this declaration is not hidden, it's visible.
if (!D->isHidden())
return true;
-
- // FIXME: We should be allowed to refer to a module-private name from
- // within the same module, e.g., during template instantiation.
- // This requires us know which module a particular declaration came from.
- return false;
+
+ if (SemaRef.ActiveTemplateInstantiations.empty())
+ return false;
+
+ // During template instantiation, we can refer to hidden declarations, if
+ // they were visible in any module along the path of instantiation.
+ return isVisibleSlow(SemaRef, D);
}
-
+
/// \brief Retrieve the accepted (re)declaration of the given declaration,
/// if there is one.
NamedDecl *getAcceptableDecl(NamedDecl *D) const {
if (!D->isInIdentifierNamespace(IDNS))
return 0;
-
- if (isHiddenDeclarationVisible() || isVisible(D))
+
+ if (isHiddenDeclarationVisible() || isVisible(SemaRef, D))
return D;
-
+
return getAcceptableDeclSlow(D);
}
-
+
private:
+ static bool isVisibleSlow(Sema &SemaRef, NamedDecl *D);
NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
+
public:
-
/// \brief Returns the identifier namespace mask for this lookup.
unsigned getIdentifierNamespace() const {
return IDNS;
@@ -390,7 +396,15 @@ public:
assert(ResultKind == NotFound && Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}
-
+
+ /// \brief Determine whether the lookup result was shadowed by some other
+ /// declaration that lookup ignored.
+ bool isShadowed() const { return Shadowed; }
+
+ /// \brief Note that we found and ignored a declaration while performing
+ /// lookup.
+ void setShadowed() { Shadowed = true; }
+
/// \brief Resolves the result kind of the lookup, possibly hiding
/// decls.
///
@@ -479,6 +493,7 @@ public:
if (Paths) deletePaths(Paths);
Paths = NULL;
NamingClass = 0;
+ Shadowed = false;
}
/// \brief Clears out any current state and re-initializes for a
@@ -598,6 +613,13 @@ public:
return Filter(*this);
}
+ void setFindLocalExtern(bool FindLocalExtern) {
+ if (FindLocalExtern)
+ IDNS |= Decl::IDNS_LocalExtern;
+ else
+ IDNS &= ~Decl::IDNS_LocalExtern;
+ }
+
private:
void diagnose() {
if (isAmbiguous())
@@ -657,34 +679,44 @@ private:
/// \brief True if we should allow hidden declarations to be 'visible'.
bool AllowHidden;
+
+ /// \brief True if the found declarations were shadowed by some other
+ /// declaration that we skipped. This only happens when \c LookupKind
+ /// is \c LookupRedeclarationWithLinkage.
+ bool Shadowed;
};
- /// \brief Consumes visible declarations found when searching for
- /// all visible names within a given scope or context.
+/// \brief Consumes visible declarations found when searching for
+/// all visible names within a given scope or context.
+///
+/// This abstract class is meant to be subclassed by clients of \c
+/// Sema::LookupVisibleDecls(), each of which should override the \c
+/// FoundDecl() function to process declarations as they are found.
+class VisibleDeclConsumer {
+public:
+ /// \brief Destroys the visible declaration consumer.
+ virtual ~VisibleDeclConsumer();
+
+ /// \brief Determine whether hidden declarations (from unimported
+ /// modules) should be given to this consumer. By default, they
+ /// are not included.
+ virtual bool includeHiddenDecls() const;
+
+ /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a
+ /// declaration visible from the current scope or context.
///
- /// This abstract class is meant to be subclassed by clients of \c
- /// Sema::LookupVisibleDecls(), each of which should override the \c
- /// FoundDecl() function to process declarations as they are found.
- class VisibleDeclConsumer {
- public:
- /// \brief Destroys the visible declaration consumer.
- virtual ~VisibleDeclConsumer();
-
- /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a
- /// declaration visible from the current scope or context.
- ///
- /// \param ND the declaration found.
- ///
- /// \param Hiding a declaration that hides the declaration \p ND,
- /// or NULL if no such declaration exists.
- ///
- /// \param Ctx the original context from which the lookup started.
- ///
- /// \param InBaseClass whether this declaration was found in base
- /// class of the context we searched.
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
- bool InBaseClass) = 0;
- };
+ /// \param ND the declaration found.
+ ///
+ /// \param Hiding a declaration that hides the declaration \p ND,
+ /// or NULL if no such declaration exists.
+ ///
+ /// \param Ctx the original context from which the lookup started.
+ ///
+ /// \param InBaseClass whether this declaration was found in base
+ /// class of the context we searched.
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass) = 0;
+};
/// \brief A class for storing results from argument-dependent lookup.
class ADLResult {
@@ -701,7 +733,8 @@ public:
Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
}
- class iterator {
+ class iterator
+ : public std::iterator<std::forward_iterator_tag, NamedDecl *> {
typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
inner_iterator iter;
@@ -713,7 +746,7 @@ public:
iterator &operator++() { ++iter; return *this; }
iterator operator++(int) { return iterator(iter++); }
- NamedDecl *operator*() const { return iter->second; }
+ value_type operator*() const { return iter->second; }
bool operator==(const iterator &other) const { return iter == other.iter; }
bool operator!=(const iterator &other) const { return iter != other.iter; }
diff --git a/include/clang/Sema/Makefile b/include/clang/Sema/Makefile
index 7d658a7c11ef..799f789e0ead 100644
--- a/include/clang/Sema/Makefile
+++ b/include/clang/Sema/Makefile
@@ -1,7 +1,7 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
BUILT_SOURCES = AttrTemplateInstantiate.inc AttrParsedAttrList.inc AttrParsedAttrKinds.inc \
- AttrSpellingListIndex.inc
+ AttrSpellingListIndex.inc AttrParsedAttrImpl.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -31,4 +31,9 @@ $(ObjDir)/AttrSpellingListIndex.inc.tmp : $(TD_SRC_DIR)/Attr.td \
$(Verb) $(ClangTableGen) -gen-clang-attr-spelling-index -o \
$(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+$(ObjDir)/AttrParsedAttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang parsed attribute list impl with tablegen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-impl -o \
+ $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index ff87d05c0404..e9ba479d1255 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -322,6 +322,36 @@ public:
virtual void ReadPendingInstantiations(
SmallVectorImpl<std::pair<ValueDecl*, SourceLocation> >& Pending);
+ /// \brief Read the set of late parsed template functions for this source.
+ ///
+ /// The external source should insert its own late parsed template functions
+ /// into the map. Note that this routine may be invoked multiple times; the
+ /// external source should take care not to introduce the same map entries
+ /// repeatedly.
+ virtual void ReadLateParsedTemplates(
+ llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap);
+
+ /// \copydoc ExternalSemaSource::CorrectTypo
+ /// \note Returns the first nonempty correction.
+ virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT);
+
+ /// \brief Produces a diagnostic note if one of the attached sources
+ /// contains a complete definition for \p T. Queries the sources in list
+ /// order until the first one claims that a diagnostic was produced.
+ ///
+ /// \param Loc the location at which a complete type was required but not
+ /// provided
+ ///
+ /// \param T the \c QualType that should have been complete at \p Loc
+ ///
+ /// \return true if a diagnostic was produced, false otherwise.
+ virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, QualType T);
+
// isa/cast/dyn_cast support
static bool classof(const MultiplexExternalSemaSource*) { return true; }
//static bool classof(const ExternalSemaSource*) { return true; }
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index c685843f18cd..b8bd14aa1cd5 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -22,6 +22,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Sema/SemaFixItUtils.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
@@ -241,7 +242,7 @@ namespace clang {
QualType &ConstantType) const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
- void DebugPrint() const;
+ void dump() const;
};
/// UserDefinedConversionSequence - Represents a user-defined
@@ -287,7 +288,7 @@ namespace clang {
/// that refers to \c ConversionFunction.
DeclAccessPair FoundConversionFunction;
- void DebugPrint() const;
+ void dump() const;
};
/// Represents an ambiguous user-defined conversion sequence.
@@ -405,9 +406,6 @@ namespace clang {
/// ConversionKind - The kind of implicit conversion sequence.
unsigned ConversionKind : 30;
- /// \brief Whether the argument is an initializer list.
- bool ListInitializationSequence : 1;
-
/// \brief Whether the target is really a std::initializer_list, and the
/// sequence only represents the worst element conversion.
bool StdInitializerListElement : 1;
@@ -440,16 +438,14 @@ namespace clang {
BadConversionSequence Bad;
};
- ImplicitConversionSequence()
- : ConversionKind(Uninitialized), ListInitializationSequence(false),
- StdInitializerListElement(false)
+ ImplicitConversionSequence()
+ : ConversionKind(Uninitialized), StdInitializerListElement(false)
{}
~ImplicitConversionSequence() {
destruct();
}
ImplicitConversionSequence(const ImplicitConversionSequence &Other)
- : ConversionKind(Other.ConversionKind),
- ListInitializationSequence(Other.ListInitializationSequence),
+ : ConversionKind(Other.ConversionKind),
StdInitializerListElement(Other.StdInitializerListElement)
{
switch (ConversionKind) {
@@ -535,16 +531,6 @@ namespace clang {
Ambiguous.construct();
}
- /// \brief Whether this sequence was created by the rules of
- /// list-initialization sequences.
- bool isListInitializationSequence() const {
- return ListInitializationSequence;
- }
-
- void setListInitializationSequence() {
- ListInitializationSequence = true;
- }
-
/// \brief Whether the target is really a std::initializer_list, and the
/// sequence only represents the worst element conversion.
bool isStdInitializerListElement() const {
@@ -568,7 +554,7 @@ namespace clang {
SourceLocation CaretLoc,
const PartialDiagnostic &PDiag) const;
- void DebugPrint() const;
+ void dump() const;
};
enum OverloadFailureKind {
@@ -656,53 +642,6 @@ namespace clang {
/// \brief The number of call arguments that were explicitly provided,
/// to be used while performing partial ordering of function templates.
unsigned ExplicitCallArguments;
-
- /// A structure used to record information about a failed
- /// template argument deduction.
- struct DeductionFailureInfo {
- /// A Sema::TemplateDeductionResult.
- unsigned Result : 8;
-
- /// \brief Indicates whether a diagnostic is stored in Diagnostic.
- unsigned HasDiagnostic : 1;
-
- /// \brief Opaque pointer containing additional data about
- /// this deduction failure.
- void *Data;
-
- /// \brief A diagnostic indicating why deduction failed.
- union {
- void *Align;
- char Diagnostic[sizeof(PartialDiagnosticAt)];
- };
-
- /// \brief Retrieve the diagnostic which caused this deduction failure,
- /// if any.
- PartialDiagnosticAt *getSFINAEDiagnostic();
-
- /// \brief Retrieve the template parameter this deduction failure
- /// refers to, if any.
- TemplateParameter getTemplateParameter();
-
- /// \brief Retrieve the template argument list associated with this
- /// deduction failure, if any.
- TemplateArgumentList *getTemplateArgumentList();
-
- /// \brief Return the first template argument this deduction failure
- /// refers to, if any.
- const TemplateArgument *getFirstArg();
-
- /// \brief Return the second template argument this deduction failure
- /// refers to, if any.
- const TemplateArgument *getSecondArg();
-
- /// \brief Return the expression this deduction failure refers to,
- /// if any.
- Expr *getExpr();
-
- /// \brief Free any memory associated with this deduction failure.
- void Destroy();
- };
union {
DeductionFailureInfo DeductionFailure;
@@ -773,7 +712,7 @@ namespace clang {
/// \brief Clear out all of the candidates.
void clear();
- typedef SmallVector<OverloadCandidate, 16>::iterator iterator;
+ typedef SmallVectorImpl<OverloadCandidate>::iterator iterator;
iterator begin() { return Candidates.begin(); }
iterator end() { return Candidates.end(); }
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index c3d1f4e0b7db..b7d7710eb121 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -33,8 +33,12 @@ namespace clang {
class TemplateName;
class TemplateParameterList;
- /// OpaquePtr - This is a very simple POD type that wraps a pointer that the
- /// Parser doesn't know about but that Sema or another client does. The UID
+ /// \brief Wrapper for void* pointer.
+ /// \tparam PtrTy Either a pointer type like 'T*' or a type that behaves like
+ /// a pointer.
+ ///
+ /// This is a very simple POD type that wraps a pointer that the Parser
+ /// doesn't know about but that Sema or another client does. The PtrTy
/// template argument is used to make sure that "Decl" pointers are not
/// compatible with "Type" pointers for example.
template <class PtrTy>
@@ -49,11 +53,21 @@ namespace clang {
static OpaquePtr make(PtrTy P) { OpaquePtr OP; OP.set(P); return OP; }
- template <typename T> T* getAs() const {
+ /// \brief Returns plain pointer to the entity pointed by this wrapper.
+ /// \tparam PointeeT Type of pointed entity.
+ ///
+ /// It is identical to getPtrAs<PointeeT*>.
+ template <typename PointeeT> PointeeT* getPtrTo() const {
return get();
}
- template <typename T> T getAsVal() const {
+ /// \brief Returns pointer converted to the specified type.
+ /// \tparam PtrT Result pointer type. There must be implicit conversion
+ /// from PtrTy to PtrT.
+ ///
+ /// In contrast to getPtrTo, this method allows the return type to be
+ /// a smart pointer.
+ template <typename PtrT> PtrT getPtrAs() const {
return get();
}
@@ -65,7 +79,7 @@ namespace clang {
Ptr = Traits::getAsVoidPointer(P);
}
- operator bool() const { return Ptr != 0; }
+ LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
void *getAsOpaquePtr() const { return Ptr; }
static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); }
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index d016b9b887c5..249a4c74311b 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -91,7 +91,10 @@ public:
TryScope = 0x2000,
/// \brief This is the scope for a function-level C++ try or catch scope.
- FnTryCatchScope = 0x4000
+ FnTryCatchScope = 0x4000,
+
+ /// \brief This is the scope of OpenMP executable directive
+ OpenMPDirectiveScope = 0x8000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -143,11 +146,10 @@ private:
typedef llvm::SmallPtrSet<Decl *, 32> DeclSetTy;
DeclSetTy DeclsInScope;
- /// Entity - The entity with which this scope is associated. For
+ /// The DeclContext with which this scope is associated. For
/// example, the entity of a class scope is the class itself, the
- /// entity of a function scope is a function, etc. This field is
- /// maintained by the Action implementation.
- void *Entity;
+ /// entity of a function scope is a function, etc.
+ DeclContext *Entity;
typedef SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy;
UsingDirectivesTy UsingDirectives;
@@ -236,8 +238,8 @@ public:
return DeclsInScope.count(D) != 0;
}
- void* getEntity() const { return Entity; }
- void setEntity(void *E) { Entity = E; }
+ DeclContext *getEntity() const { return Entity; }
+ void setEntity(DeclContext *E) { Entity = E; }
bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); }
@@ -301,7 +303,12 @@ public:
}
return false;
}
-
+
+ /// \brief Determines whether this scope is the OpenMP directive scope
+ bool isOpenMPDirectiveScope() const {
+ return (getFlags() & Scope::OpenMPDirectiveScope);
+ }
+
/// \brief Determine whether this scope is a C++ 'try' block.
bool isTryScope() const { return getFlags() & Scope::TryScope; }
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index b232b59d3c17..06afe1a8ae9d 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -18,8 +18,11 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CapturedStmt.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/Ownership.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
namespace clang {
@@ -27,6 +30,7 @@ class Decl;
class BlockDecl;
class CapturedDecl;
class CXXMethodDecl;
+class FieldDecl;
class ObjCPropertyDecl;
class IdentifierInfo;
class ImplicitParamDecl;
@@ -34,8 +38,11 @@ class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
+class TemplateTypeParmDecl;
+class TemplateParameterList;
class VarDecl;
class DeclRefExpr;
+class MemberExpr;
class ObjCIvarRefExpr;
class ObjCPropertyRefExpr;
class ObjCMessageExpr;
@@ -330,60 +337,78 @@ public:
ImplicitCaptureStyle ImpCaptureStyle;
class Capture {
- // There are two categories of capture: capturing 'this', and capturing
- // local variables. There are three ways to capture a local variable:
- // capture by copy in the C++11 sense, capture by reference
- // in the C++11 sense, and __block capture. Lambdas explicitly specify
- // capture by copy or capture by reference. For blocks, __block capture
- // applies to variables with that annotation, variables of reference type
- // are captured by reference, and other variables are captured by copy.
+ // There are three categories of capture: capturing 'this', capturing
+ // local variables, and C++1y initialized captures (which can have an
+ // arbitrary initializer, and don't really capture in the traditional
+ // sense at all).
+ //
+ // There are three ways to capture a local variable:
+ // - capture by copy in the C++11 sense,
+ // - capture by reference in the C++11 sense, and
+ // - __block capture.
+ // Lambdas explicitly specify capture by copy or capture by reference.
+ // For blocks, __block capture applies to variables with that annotation,
+ // variables of reference type are captured by reference, and other
+ // variables are captured by copy.
enum CaptureKind {
- Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block
+ Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_This
};
- // The variable being captured (if we are not capturing 'this'),
- // and misc bits descibing the capture.
- llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind;
+ /// The variable being captured (if we are not capturing 'this') and whether
+ /// this is a nested capture.
+ llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested;
- // Expression to initialize a field of the given type, and whether this
- // is a nested capture; the expression is only required if we are
- // capturing ByVal and the variable's type has a non-trivial
- // copy constructor.
- llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested;
+ /// Expression to initialize a field of the given type, and the kind of
+ /// capture (if this is a capture and not an init-capture). The expression
+ /// is only required if we are capturing ByVal and the variable's type has
+ /// a non-trivial copy constructor.
+ llvm::PointerIntPair<Expr*, 2, CaptureKind> InitExprAndCaptureKind;
- /// \brief The source location at which the first capture occurred..
+ /// \brief The source location at which the first capture occurred.
SourceLocation Loc;
-
+
/// \brief The location of the ellipsis that expands a parameter pack.
SourceLocation EllipsisLoc;
-
+
/// \brief The type as it was captured, which is in effect the type of the
/// non-static data member that would hold the capture.
QualType CaptureType;
-
+
public:
- Capture(VarDecl *Var, bool block, bool byRef, bool isNested,
- SourceLocation Loc, SourceLocation EllipsisLoc,
+ Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
+ SourceLocation Loc, SourceLocation EllipsisLoc,
QualType CaptureType, Expr *Cpy)
- : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
- CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc),
- CaptureType(CaptureType){}
+ : VarAndNested(Var, IsNested),
+ InitExprAndCaptureKind(Cpy, Block ? Cap_Block :
+ ByRef ? Cap_ByRef : Cap_ByCopy),
+ Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
enum IsThisCapture { ThisCapture };
- Capture(IsThisCapture, bool isNested, SourceLocation Loc,
+ Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
QualType CaptureType, Expr *Cpy)
- : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
- EllipsisLoc(), CaptureType(CaptureType) { }
+ : VarAndNested(0, IsNested),
+ InitExprAndCaptureKind(Cpy, Cap_This),
+ Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
- bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
- bool isVariableCapture() const { return !isThisCapture(); }
- bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; }
- bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; }
- bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; }
- bool isNested() { return CopyExprAndNested.getInt(); }
+ bool isThisCapture() const {
+ return InitExprAndCaptureKind.getInt() == Cap_This;
+ }
+ bool isVariableCapture() const {
+ return InitExprAndCaptureKind.getInt() != Cap_This;
+ }
+ bool isCopyCapture() const {
+ return InitExprAndCaptureKind.getInt() == Cap_ByCopy;
+ }
+ bool isReferenceCapture() const {
+ return InitExprAndCaptureKind.getInt() == Cap_ByRef;
+ }
+ bool isBlockCapture() const {
+ return InitExprAndCaptureKind.getInt() == Cap_Block;
+ }
+ bool isNested() { return VarAndNested.getInt(); }
VarDecl *getVariable() const {
- return VarAndKind.getPointer();
+ return VarAndNested.getPointer();
}
/// \brief Retrieve the location at which this variable was captured.
@@ -398,8 +423,8 @@ public:
/// that would store this capture.
QualType getCaptureType() const { return CaptureType; }
- Expr *getCopyExpr() const {
- return CopyExprAndNested.getPointer();
+ Expr *getInitExpr() const {
+ return InitExprAndCaptureKind.getPointer();
}
};
@@ -529,6 +554,8 @@ public:
switch (CapRegionKind) {
case CR_Default:
return "default captured statement";
+ case CR_OpenMP:
+ return "OpenMP region";
}
llvm_unreachable("Invalid captured region kind!");
}
@@ -543,19 +570,23 @@ public:
/// \brief The class that describes the lambda.
CXXRecordDecl *Lambda;
- /// \brief The class that describes the lambda.
+ /// \brief The lambda's compiler-generated \c operator().
CXXMethodDecl *CallOperator;
/// \brief Source range covering the lambda introducer [...].
SourceRange IntroducerRange;
- /// \brief The number of captures in the \c Captures list that are
+ /// \brief Source location of the '&' or '=' specifying the default capture
+ /// type, if any.
+ SourceLocation CaptureDefaultLoc;
+
+ /// \brief The number of captures in the \c Captures list that are
/// explicit captures.
unsigned NumExplicitCaptures;
/// \brief Whether this is a mutable lambda.
bool Mutable;
-
+
/// \brief Whether the (empty) parameter list is explicit.
bool ExplicitParams;
@@ -572,25 +603,169 @@ public:
/// its list of array index variables.
SmallVector<unsigned, 4> ArrayIndexStarts;
- LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
- CXXMethodDecl *CallOperator)
- : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
- CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
- ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
+ /// \brief If this is a generic lambda, use this as the depth of
+ /// each 'auto' parameter, during initial AST construction.
+ unsigned AutoTemplateParameterDepth;
+
+ /// \brief Store the list of the auto parameters for a generic lambda.
+ /// If this is a generic lambda, store the list of the auto
+ /// parameters converted into TemplateTypeParmDecls into a vector
+ /// that can be used to construct the generic lambda's template
+ /// parameter list, during initial AST construction.
+ SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+
+ /// If this is a generic lambda, and the template parameter
+ /// list has been created (from the AutoTemplateParams) then
+ /// store a reference to it (cache it to avoid reconstructing it).
+ TemplateParameterList *GLTemplateParameterList;
+
+ /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs
+ /// or MemberExprs) that refer to local variables in a generic lambda
+ /// or a lambda in a potentially-evaluated-if-used context.
+ ///
+ /// Potentially capturable variables of a nested lambda that might need
+ /// to be captured by the lambda are housed here.
+ /// This is specifically useful for generic lambdas or
+ /// lambdas within a a potentially evaluated-if-used context.
+ /// If an enclosing variable is named in an expression of a lambda nested
+ /// within a generic lambda, we don't always know know whether the variable
+ /// will truly be odr-used (i.e. need to be captured) by that nested lambda,
+ /// until its instantiation. But we still need to capture it in the
+ /// enclosing lambda if all intervening lambdas can capture the variable.
+
+ llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs;
+
+ /// \brief Contains all variable-referring-expressions that refer
+ /// to local variables that are usable as constant expressions and
+ /// do not involve an odr-use (they may still need to be captured
+ /// if the enclosing full-expression is instantiation dependent).
+ llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs;
+
+ SourceLocation PotentialThisCaptureLocation;
+
+ LambdaScopeInfo(DiagnosticsEngine &Diag)
+ : CapturingScopeInfo(Diag, ImpCap_None), Lambda(0),
+ CallOperator(0), NumExplicitCaptures(0), Mutable(false),
+ ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
+ AutoTemplateParameterDepth(0), GLTemplateParameterList(0)
{
Kind = SK_Lambda;
}
virtual ~LambdaScopeInfo();
- /// \brief Note when
+ /// \brief Note when all explicit captures have been added.
void finishedExplicitCaptures() {
NumExplicitCaptures = Captures.size();
}
static bool classof(const FunctionScopeInfo *FSI) {
- return FSI->Kind == SK_Lambda;
+ return FSI->Kind == SK_Lambda;
}
+
+ ///
+ /// \brief Add a variable that might potentially be captured by the
+ /// lambda and therefore the enclosing lambdas.
+ ///
+ /// This is also used by enclosing lambda's to speculatively capture
+ /// variables that nested lambda's - depending on their enclosing
+ /// specialization - might need to capture.
+ /// Consider:
+ /// void f(int, int); <-- don't capture
+ /// void f(const int&, double); <-- capture
+ /// void foo() {
+ /// const int x = 10;
+ /// auto L = [=](auto a) { // capture 'x'
+ /// return [=](auto b) {
+ /// f(x, a); // we may or may not need to capture 'x'
+ /// };
+ /// };
+ /// }
+ void addPotentialCapture(Expr *VarExpr) {
+ assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr));
+ PotentiallyCapturingExprs.push_back(VarExpr);
+ }
+
+ void addPotentialThisCapture(SourceLocation Loc) {
+ PotentialThisCaptureLocation = Loc;
+ }
+ bool hasPotentialThisCapture() const {
+ return PotentialThisCaptureLocation.isValid();
+ }
+
+ /// \brief Mark a variable's reference in a lambda as non-odr using.
+ ///
+ /// For generic lambdas, if a variable is named in a potentially evaluated
+ /// expression, where the enclosing full expression is dependent then we
+ /// must capture the variable (given a default capture).
+ /// This is accomplished by recording all references to variables
+ /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of
+ /// PotentialCaptures. All such variables have to be captured by that lambda,
+ /// except for as described below.
+ /// If that variable is usable as a constant expression and is named in a
+ /// manner that does not involve its odr-use (e.g. undergoes
+ /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the
+ /// act of analyzing the enclosing full expression (ActOnFinishFullExpr)
+ /// if we can determine that the full expression is not instantiation-
+ /// dependent, then we can entirely avoid its capture.
+ ///
+ /// const int n = 0;
+ /// [&] (auto x) {
+ /// (void)+n + x;
+ /// };
+ /// Interestingly, this strategy would involve a capture of n, even though
+ /// it's obviously not odr-used here, because the full-expression is
+ /// instantiation-dependent. It could be useful to avoid capturing such
+ /// variables, even when they are referred to in an instantiation-dependent
+ /// expression, if we can unambiguously determine that they shall never be
+ /// odr-used. This would involve removal of the variable-referring-expression
+ /// from the array of PotentialCaptures during the lvalue-to-rvalue
+ /// conversions. But per the working draft N3797, (post-chicago 2013) we must
+ /// capture such variables.
+ /// Before anyone is tempted to implement a strategy for not-capturing 'n',
+ /// consider the insightful warning in:
+ /// /cfe-commits/Week-of-Mon-20131104/092596.html
+ /// "The problem is that the set of captures for a lambda is part of the ABI
+ /// (since lambda layout can be made visible through inline functions and the
+ /// like), and there are no guarantees as to which cases we'll manage to build
+ /// an lvalue-to-rvalue conversion in, when parsing a template -- some
+ /// seemingly harmless change elsewhere in Sema could cause us to start or stop
+ /// building such a node. So we need a rule that anyone can implement and get
+ /// exactly the same result".
+ ///
+ void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
+ assert(isa<DeclRefExpr>(CapturingVarExpr)
+ || isa<MemberExpr>(CapturingVarExpr));
+ NonODRUsedCapturingExprs.insert(CapturingVarExpr);
+ }
+ bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) {
+ assert(isa<DeclRefExpr>(CapturingVarExpr)
+ || isa<MemberExpr>(CapturingVarExpr));
+ return NonODRUsedCapturingExprs.count(CapturingVarExpr);
+ }
+ void removePotentialCapture(Expr *E) {
+ PotentiallyCapturingExprs.erase(
+ std::remove(PotentiallyCapturingExprs.begin(),
+ PotentiallyCapturingExprs.end(), E),
+ PotentiallyCapturingExprs.end());
+ }
+ void clearPotentialCaptures() {
+ PotentiallyCapturingExprs.clear();
+ PotentialThisCaptureLocation = SourceLocation();
+ }
+ unsigned getNumPotentialVariableCaptures() const {
+ return PotentiallyCapturingExprs.size();
+ }
+
+ bool hasPotentialCaptures() const {
+ return getNumPotentialVariableCaptures() ||
+ PotentialThisCaptureLocation.isValid();
+ }
+
+ // When passed the index, returns the VarDecl and Expr associated
+ // with the index.
+ void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E);
+
};
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index d7c80f2e4f91..48794d6f02fd 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -20,12 +20,13 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
@@ -49,6 +50,7 @@
#include "llvm/MC/MCParser/MCAsmParser.h"
#include <deque>
#include <string>
+#include <vector>
namespace llvm {
class APSInt;
@@ -85,6 +87,7 @@ namespace clang {
class ClassTemplateDecl;
class ClassTemplatePartialSpecializationDecl;
class ClassTemplateSpecializationDecl;
+ class VarTemplatePartialSpecializationDecl;
class CodeCompleteConsumer;
class CodeCompletionAllocator;
class CodeCompletionTUInfo;
@@ -136,6 +139,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OMPThreadPrivateDecl;
+ class OMPClause;
class OverloadCandidateSet;
class OverloadExpr;
class ParenListExpr;
@@ -170,9 +174,12 @@ namespace clang {
class UsingShadowDecl;
class ValueDecl;
class VarDecl;
+ class VarTemplateSpecializationDecl;
class VisibilityAttr;
class VisibleDeclConsumer;
class IndirectFieldDecl;
+ struct DeductionFailureInfo;
+ class TemplateSpecCandidateSet;
namespace sema {
class AccessedEntity;
@@ -215,7 +222,7 @@ class Sema {
// 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 !Old->isHidden() || New->hasExternalLinkage();
+ return !Old->isHidden() || New->isExternallyVisible();
}
public:
@@ -274,6 +281,12 @@ public:
/// element type here is ExprWithCleanups::Object.
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
+ /// \brief Store a list of either DeclRefExprs or MemberExprs
+ /// that contain a reference to a variable (constant) that may or may not
+ /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue
+ /// and discarded value conversions have been applied to all subexpressions
+ /// of the enclosing full expression. This is cleared at the end of each
+ /// full expression.
llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
/// \brief Stack containing information about each of the nested
@@ -340,8 +353,7 @@ public:
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternCDecls;
/// \brief Look for a locally scoped extern "C" declaration by the given name.
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- findLocallyScopedExternCDecl(DeclarationName Name);
+ NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);
typedef LazyVector<VarDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
@@ -366,11 +378,6 @@ public:
/// cycle detection at the end of the TU.
DelegatingCtorDeclsType DelegatingCtorDecls;
- /// \brief All the destructors seen during a class definition that had their
- /// exception spec computation delayed because it depended on an unparsed
- /// exception spec.
- SmallVector<CXXDestructorDecl*, 2> DelayedDestructorExceptionSpecs;
-
/// \brief All the overriding destructors seen during a class definition
/// (there could be multiple due to nested classes) that had their exception
/// spec checks delayed, plus the overridden destructor.
@@ -388,8 +395,12 @@ public:
SmallVector<std::pair<CXXMethodDecl*, const FunctionProtoType*>, 2>
DelayedDefaultedMemberExceptionSpecs;
+ typedef llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *>
+ LateParsedTemplateMapT;
+ LateParsedTemplateMapT LateParsedTemplateMap;
+
/// \brief Callback to the parser to parse templated functions when needed.
- typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
+ typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT);
LateTemplateParserCB *LateTemplateParser;
void *OpaqueParser;
@@ -621,7 +632,7 @@ public:
/// \brief The current context is "potentially evaluated" in C++11 terms,
/// but the expression is evaluated at compile-time (like the values of
- /// cases in a switch statment).
+ /// cases in a switch statement).
ConstantEvaluated,
/// \brief The current expression is potentially evaluated at run time,
@@ -662,17 +673,17 @@ public:
/// is indeed an unevaluated context.
SmallVector<LambdaExpr *, 2> Lambdas;
- /// \brief The declaration that provides context for the lambda expression
- /// if the normal declaration context does not suffice, e.g., in a
- /// default function argument.
- Decl *LambdaContextDecl;
+ /// \brief The declaration that provides context for lambda expressions
+ /// and block literals if the normal declaration context does not
+ /// suffice, e.g., in a default function argument.
+ Decl *ManglingContextDecl;
/// \brief The context information used to mangle lambda expressions
- /// within this context.
+ /// and block literals within this context.
///
/// This mangling information is allocated lazily, since most contexts
- /// do not have lambda expressions.
- IntrusiveRefCntPtr<LambdaMangleContext> LambdaMangle;
+ /// do not have lambda expressions or block literals.
+ IntrusiveRefCntPtr<MangleNumberingContext> MangleNumbering;
/// \brief If we are processing a decltype type, a set of call expressions
/// for which we have deferred checking the completeness of the return type.
@@ -685,19 +696,15 @@ public:
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
bool ParentNeedsCleanups,
- Decl *LambdaContextDecl,
+ Decl *ManglingContextDecl,
bool IsDecltype)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
- LambdaContextDecl(LambdaContextDecl), LambdaMangle() { }
-
- /// \brief Retrieve the mangling context for lambdas.
- LambdaMangleContext &getLambdaMangleContext() {
- assert(LambdaContextDecl && "Need to have a lambda context declaration");
- if (!LambdaMangle)
- LambdaMangle = new LambdaMangleContext;
- return *LambdaMangle;
- }
+ ManglingContextDecl(ManglingContextDecl), MangleNumbering() { }
+
+ /// \brief Retrieve the mangling numbering context, used to consistently
+ /// number constructs like lambdas for mangling.
+ MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
bool isUnevaluated() const {
return Context == Unevaluated || Context == UnevaluatedAbstract;
@@ -707,6 +714,18 @@ public:
/// A stack of expression evaluation contexts.
SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
+ /// \brief Compute the mangling number context for a lambda expression or
+ /// block literal.
+ ///
+ /// \param DC - The DeclContext containing the lambda expression or
+ /// block literal.
+ /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl
+ /// associated with the context, if relevant.
+ MangleNumberingContext *getCurrentMangleNumberContext(
+ const DeclContext *DC,
+ Decl *&ManglingContextDecl);
+
+
/// SpecialMemberOverloadResult - The overloading result for a special member
/// function.
///
@@ -775,7 +794,7 @@ public:
/// Obtain a sorted list of functions that are undefined but ODR-used.
void getUndefinedButUsed(
- llvm::SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined);
+ SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined);
typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods;
typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool;
@@ -905,6 +924,15 @@ public:
// Dispatch to Sema to emit the diagnostic.
SemaRef.EmitCurrentDiagnostic(DiagID);
}
+
+ /// Teach operator<< to produce an object of the correct type.
+ template<typename T>
+ friend const SemaDiagnosticBuilder &operator<<(
+ const SemaDiagnosticBuilder &Diag, const T &Value) {
+ const DiagnosticBuilder &BaseDiag = Diag;
+ BaseDiag << Value;
+ return Diag;
+ }
};
/// \brief Emit a diagnostic.
@@ -922,8 +950,9 @@ public:
bool findMacroSpelling(SourceLocation &loc, StringRef name);
/// \brief Get a string to suggest for zero-initialization of a type.
- std::string getFixItZeroInitializerForType(QualType T) const;
- std::string getFixItZeroLiteralForType(QualType T) const;
+ std::string
+ getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const;
+ std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const;
ExprResult Owned(Expr* E) { return E; }
ExprResult Owned(ExprResult R) { return R; }
@@ -937,7 +966,13 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
- void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+ sema::LambdaScopeInfo *PushLambdaScope();
+
+ /// \brief This is used to inform Sema what the current TemplateParameterDepth
+ /// is during Parsing. Currently it is used to pass on the depth
+ /// when parsing generic lambda 'auto' parameters.
+ void RecordParsingTemplateParameterDepth(unsigned Depth);
+
void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
RecordDecl *RD,
CapturedRegionKind K);
@@ -947,7 +982,13 @@ public:
sema::FunctionScopeInfo *getCurFunction() const {
return FunctionScopes.back();
}
-
+
+ template <typename ExprT>
+ void recordUseOfEvaluatedWeak(const ExprT *E, bool IsRead=true) {
+ if (!isUnevaluatedContext())
+ getCurFunction()->recordUseOfWeak(E, IsRead);
+ }
+
void PushCompoundScope();
void PopCompoundScope();
@@ -958,14 +999,17 @@ public:
/// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
- /// \brief Retrieve the current lambda expression, if any.
+ /// \brief Retrieve the current lambda scope info, if any.
sema::LambdaScopeInfo *getCurLambda();
+ /// \brief Retrieve the current generic lambda info, if any.
+ sema::LambdaScopeInfo *getCurGenericLambda();
+
/// \brief Retrieve the current captured region, if any.
sema::CapturedRegionScopeInfo *getCurCapturedRegion();
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
- SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+ SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
void ActOnComment(SourceRange Comment);
@@ -987,6 +1031,8 @@ public:
QualType BuildExtVectorType(QualType T, Expr *ArraySize,
SourceLocation AttrLoc);
+ bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
+
/// \brief Build a function type.
///
/// This routine checks the function type according to C++ rules and
@@ -1152,6 +1198,10 @@ public:
virtual ~BoundTypeDiagnoser3() { }
};
+private:
+ bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+ TypeDiagnoser &Diagnoser);
+public:
bool RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
bool RequireCompleteType(SourceLocation Loc, QualType T,
@@ -1287,6 +1337,7 @@ public:
NC_Expression,
NC_NestedNameSpecifier,
NC_TypeTemplate,
+ NC_VarTemplate,
NC_FunctionTemplate
};
@@ -1325,6 +1376,12 @@ public:
return Result;
}
+ static NameClassification VarTemplate(TemplateName Name) {
+ NameClassification Result(NC_VarTemplate);
+ Result.Template = Name;
+ return Result;
+ }
+
static NameClassification FunctionTemplate(TemplateName Name) {
NameClassification Result(NC_FunctionTemplate);
Result.Template = Name;
@@ -1344,13 +1401,22 @@ public:
}
TemplateName getTemplateName() const {
- assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
+ assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate ||
+ Kind == NC_VarTemplate);
return Template;
}
TemplateNameKind getTemplateNameKind() const {
- assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
- return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template;
+ switch (Kind) {
+ case NC_TypeTemplate:
+ return TNK_Type_template;
+ case NC_FunctionTemplate:
+ return TNK_Function_template;
+ case NC_VarTemplate:
+ return TNK_Var_template;
+ default:
+ llvm_unreachable("unsupported name classification.");
+ }
}
};
@@ -1390,13 +1456,12 @@ public:
NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists);
- void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
- const LookupResult &Previous,
- Scope *S);
+ void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S);
bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
DeclarationName Name,
SourceLocation Loc);
+ static bool adjustContextForLocalExternDecl(DeclContext *&DC);
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
@@ -1407,10 +1472,11 @@ public:
LookupResult &Previous);
NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D,
LookupResult &Previous, bool &Redeclaration);
- NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo,
LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists);
+ MultiTemplateParamsArg TemplateParamLists,
+ bool &AddToScope);
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
@@ -1418,6 +1484,7 @@ public:
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
void ActOnStartFunctionDeclarator();
void ActOnEndFunctionDeclarator();
+
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypeSourceInfo *TInfo,
LookupResult &Previous,
@@ -1429,12 +1496,17 @@ public:
bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
- void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
+ void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD);
+ void FindHiddenVirtualMethods(CXXMethodDecl *MD,
+ SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods);
+ void NoteHiddenVirtualMethods(CXXMethodDecl *MD,
+ SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods);
// Returns true if the function declaration is a redeclaration
bool CheckFunctionDeclaration(Scope *S,
FunctionDecl *NewFD, LookupResult &Previous,
bool IsExplicitSpecialization);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
+ void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
@@ -1462,19 +1534,20 @@ public:
void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
- Decl **Group,
- unsigned NumDecls);
- DeclGroupPtrTy BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
+ ArrayRef<Decl *> Group);
+ DeclGroupPtrTy BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *> Group,
bool TypeMayContainAuto = true);
/// Should be called on all declarations that might have attached
/// documentation comments.
void ActOnDocumentableDecl(Decl *D);
- void ActOnDocumentableDecls(Decl **Group, unsigned NumDecls);
+ void ActOnDocumentableDecls(ArrayRef<Decl *> Group);
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
- void CheckForFunctionRedefinition(FunctionDecl *FD);
+ void CheckForFunctionRedefinition(FunctionDecl *FD,
+ const FunctionDecl *EffectiveDefinition =
+ 0);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
@@ -1533,6 +1606,10 @@ public:
DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
ModuleIdPath Path);
+ /// \brief The parser has processed a module import translated from a
+ /// #include or similar preprocessing directive.
+ void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod);
+
/// \brief Create an implicit import of the given module at the given
/// source location.
///
@@ -1660,6 +1737,7 @@ public:
/// member declarations.
void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl,
SourceLocation FinalLoc,
+ bool IsFinalSpelledSealed,
SourceLocation LBraceLoc);
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
@@ -1748,7 +1826,7 @@ public:
/// \param ExplicitInstantiationOrSpecialization When true, we are checking
/// whether the declaration is in scope for the purposes of explicit template
/// instantiation or specialization. The default is false.
- bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0,
+ bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = 0,
bool ExplicitInstantiationOrSpecialization = false);
/// Finds the scope corresponding to the given decl context, if it
@@ -1780,9 +1858,9 @@ public:
unsigned AttrSpellingListIndex);
DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex);
- FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
- int FormatIdx, int FirstArg,
- unsigned AttrSpellingListIndex);
+ FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Format, int FormatIdx,
+ int FirstArg, unsigned AttrSpellingListIndex);
SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
@@ -1802,13 +1880,13 @@ public:
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
- bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S);
+ bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S,
+ bool MergeTypeWithOld);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
- Scope *S);
+ Scope *S, bool MergeTypeWithOld);
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
- void MergeVarDecl(VarDecl *New, LookupResult &OldDecls,
- bool OldDeclsWereHidden);
- void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldIsHidden);
+ void MergeVarDecl(VarDecl *New, LookupResult &Previous);
+ void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
@@ -1821,7 +1899,8 @@ public:
AA_Converting,
AA_Initializing,
AA_Sending,
- AA_Casting
+ AA_Casting,
+ AA_Passing_CFAudited
};
/// C++ Overloading.
@@ -1920,65 +1999,91 @@ public:
/// Contexts in which a converted constant expression is required.
enum CCEKind {
- CCEK_CaseValue, ///< Expression in a case label.
- CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
- CCEK_TemplateArg ///< Value of a non-type template parameter.
+ CCEK_CaseValue, ///< Expression in a case label.
+ CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
+ CCEK_TemplateArg, ///< Value of a non-type template parameter.
+ CCEK_NewExpr ///< Constant expression in a noptr-new-declarator.
};
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value, CCEKind CCE);
- /// \brief Abstract base class used to diagnose problems that occur while
- /// trying to convert an expression to integral or enumeration type.
- class ICEConvertDiagnoser {
+ /// \brief Abstract base class used to perform a contextual implicit
+ /// conversion from an expression to any type passing a filter.
+ class ContextualImplicitConverter {
public:
bool Suppress;
bool SuppressConversion;
- ICEConvertDiagnoser(bool Suppress = false,
- bool SuppressConversion = false)
- : Suppress(Suppress), SuppressConversion(SuppressConversion) { }
+ ContextualImplicitConverter(bool Suppress = false,
+ bool SuppressConversion = false)
+ : Suppress(Suppress), SuppressConversion(SuppressConversion) {}
+
+ /// \brief Determine whether the specified type is a valid destination type
+ /// for this conversion.
+ virtual bool match(QualType T) = 0;
/// \brief Emits a diagnostic complaining that the expression does not have
/// integral or enumeration type.
- virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) = 0;
+ virtual SemaDiagnosticBuilder
+ diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a diagnostic when the expression has incomplete class type.
- virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
- QualType T) = 0;
+ virtual SemaDiagnosticBuilder
+ diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a diagnostic when the only matching conversion function
/// is explicit.
- virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
- QualType T,
- QualType ConvTy) = 0;
+ virtual SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0;
/// \brief Emits a note for the explicit conversion function.
- virtual DiagnosticBuilder
+ virtual SemaDiagnosticBuilder
noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0;
/// \brief Emits a diagnostic when there are multiple possible conversion
/// functions.
- virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) = 0;
+ virtual SemaDiagnosticBuilder
+ diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a note for one of the candidate conversions.
- virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) = 0;
+ virtual SemaDiagnosticBuilder
+ noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0;
/// \brief Emits a diagnostic when we picked a conversion function
/// (for cases when we are not allowed to pick a conversion function).
- virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
- QualType T,
- QualType ConvTy) = 0;
+ virtual SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0;
- virtual ~ICEConvertDiagnoser() {}
+ virtual ~ContextualImplicitConverter() {}
};
- ExprResult
- ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE,
- ICEConvertDiagnoser &Diagnoser,
- bool AllowScopedEnumerations);
+ class ICEConvertDiagnoser : public ContextualImplicitConverter {
+ bool AllowScopedEnumerations;
+
+ public:
+ ICEConvertDiagnoser(bool AllowScopedEnumerations,
+ bool Suppress, bool SuppressConversion)
+ : ContextualImplicitConverter(Suppress, SuppressConversion),
+ AllowScopedEnumerations(AllowScopedEnumerations) {}
+
+ /// Match an integral or (possibly scoped) enumeration type.
+ bool match(QualType T);
+
+ SemaDiagnosticBuilder
+ diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) {
+ return diagnoseNotInt(S, Loc, T);
+ }
+
+ /// \brief Emits a diagnostic complaining that the expression does not have
+ /// integral or enumeration type.
+ virtual SemaDiagnosticBuilder
+ diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0;
+ };
+
+ /// Perform a contextual implicit conversion.
+ ExprResult PerformContextualImplicitConversion(
+ SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter);
+
enum ObjCSubscriptKind {
OS_Array,
@@ -2054,12 +2159,14 @@ public:
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
- OverloadCandidateSet& CandidateSet);
+ OverloadCandidateSet& CandidateSet,
+ bool AllowObjCConversionOnExplicit = false);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
- OverloadCandidateSet &CandidateSet);
+ OverloadCandidateSet &CandidateSet,
+ bool AllowObjCConversionOnExplicit = false);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -2159,14 +2266,13 @@ public:
ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection=true);
bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
- Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc,
+ MultiExprArg Args, SourceLocation RParenLoc,
OverloadCandidateSet *CandidateSet,
ExprResult *Result);
@@ -2186,15 +2292,17 @@ public:
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
- SourceLocation LParenLoc, Expr **Args,
- unsigned NumArgs, SourceLocation RParenLoc);
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc);
ExprResult
BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc);
ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc);
+ SourceLocation OpLoc,
+ bool *NoArrowOperatorFound = 0);
/// CheckCallReturnType - Checks that a call expression's return type is
/// complete. Returns true on failure. The location passed in is the location
@@ -2203,7 +2311,8 @@ public:
CallExpr *CE, FunctionDecl *FD);
/// Helpers for dealing with blocks and functions.
- bool CheckParmsForFunctionDef(ParmVarDecl **Param, ParmVarDecl **ParamEnd,
+ bool CheckParmsForFunctionDef(ParmVarDecl *const *Param,
+ ParmVarDecl *const *ParamEnd,
bool CheckParameterNames);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
@@ -2271,6 +2380,9 @@ public:
/// are outside of the current scope unless they have linkage. See
/// C99 6.2.2p4-5 and C++ [basic.link]p6.
LookupRedeclarationWithLinkage,
+ /// Look up a friend of a local class. This lookup does not look
+ /// outside the innermost non-class scope. See C++11 [class.friend]p11.
+ LookupLocalFriendName,
/// Look up the name of an Objective-C protocol.
LookupObjCProtocolName,
/// Look up implicit 'self' parameter of an objective-c method.
@@ -2303,7 +2415,11 @@ public:
/// \brief The lookup found an overload set of literal operator templates,
/// which expect the characters of the spelling of the literal token to be
/// passed as a non-type template argument pack.
- LOLR_Template
+ LOLR_Template,
+ /// \brief The lookup found an overload set of literal operator templates,
+ /// which expect the character type and characters of the spelling of the
+ /// string literal token to be passed as template arguments.
+ LOLR_StringTemplate
};
SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
@@ -2370,7 +2486,9 @@ public:
LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
- bool AllowRawAndTemplate);
+ bool AllowRaw,
+ bool AllowTemplate,
+ bool AllowStringTemplate);
bool isKnownName(StringRef name);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
@@ -2391,7 +2509,17 @@ public:
CorrectionCandidateCallback &CCC,
DeclContext *MemberContext = 0,
bool EnteringContext = false,
- const ObjCObjectPointerType *OPT = 0);
+ const ObjCObjectPointerType *OPT = 0,
+ bool RecordFailure = true);
+
+ void diagnoseTypo(const TypoCorrection &Correction,
+ const PartialDiagnostic &TypoDiag,
+ bool ErrorRecovery = true);
+
+ void diagnoseTypo(const TypoCorrection &Correction,
+ const PartialDiagnostic &TypoDiag,
+ const PartialDiagnostic &PrevNote,
+ bool ErrorRecovery = true);
void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
ArrayRef<Expr *> Args,
@@ -2402,7 +2530,7 @@ public:
bool ConsiderLinkage,
bool ExplicitInstantiationOrSpecialization);
- bool DiagnoseAmbiguousLookup(LookupResult &Result);
+ void DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
@@ -2419,12 +2547,8 @@ public:
void ProcessPragmaWeak(Scope *S, Decl *D);
// Decl attributes - this routine is the top level dispatcher.
- void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable = true,
- bool Inheritable = true);
+ void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
- bool NonInheritable = true,
- bool Inheritable = true,
bool IncludeCXX11Attributes = true);
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList);
@@ -2435,8 +2559,21 @@ public:
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD = 0);
bool CheckNoReturnAttr(const AttributeList &attr);
+ bool checkStringLiteralArgumentAttr(const AttributeList &Attr,
+ unsigned ArgNum, StringRef &Str,
+ SourceLocation *ArgLocation = 0);
+
void CheckAlignasUnderalignment(Decl *D);
+ /// Adjust the calling convention of a method to be the ABI default if it
+ /// wasn't specified explicitly. This handles method types formed from
+ /// function type typedefs and typename template arguments.
+ void adjustMemberFunctionCC(QualType &T, bool IsStatic);
+
+ /// Get the outermost AttributedType node that sets a calling convention.
+ /// Valid types should not have multiple attributes with different CCs.
+ const AttributedType *getCallingConvAttributedType(QualType T) const;
+
/// \brief Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
SourceRange Range);
@@ -2457,9 +2594,6 @@ public:
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl);
- bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
- ObjCInterfaceDecl *IDecl);
-
typedef llvm::SmallPtrSet<Selector, 8> SelectorSet;
typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
@@ -2507,6 +2641,16 @@ public:
bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
ObjCMethodDecl *Method, ObjCIvarDecl *IV);
+ /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which
+ /// backs the property is not used in the property's accessor.
+ void DiagnoseUnusedBackingIvarInAccessor(Scope *S);
+
+ /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and
+ /// it property has a backing ivar, returns this ivar; otherwise, returns NULL.
+ /// It also returns ivar's property on success.
+ ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method,
+ const ObjCPropertyDecl *&PDecl) const;
+
/// Called by ActOnProperty to handle \@property declarations in
/// class extensions.
ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S,
@@ -2592,6 +2736,17 @@ private:
bool receiverIdOrClass,
bool warn, bool instance);
+ /// \brief Record the typo correction failure and return an empty correction.
+ TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc,
+ bool RecordFailure = true,
+ bool IsUnqualifiedLookup = false) {
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
+ if (RecordFailure)
+ TypoCorrectionFailures[Typo].insert(TypoLoc);
+ return TypoCorrection();
+ }
+
public:
/// AddInstanceMethodToGlobalPool - All instance methods in a translation
/// unit are added to a global pool. This allows us to efficiently associate
@@ -2628,6 +2783,14 @@ public:
warn, /*instance*/false);
}
+ const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel,
+ QualType ObjectType=QualType());
+
+ /// DiagnoseMismatchedMethodsInGlobalPool - This routine goes through list of
+ /// methods in global pool and issues diagnostic on identical selectors which
+ /// have mismathched types.
+ void DiagnoseMismatchedMethodsInGlobalPool();
+
/// LookupImplementedMethodInGlobalPool - Returns the method which has an
/// implementation.
ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel);
@@ -2691,8 +2854,7 @@ public:
void ActOnStartOfCompoundStmt();
void ActOnFinishOfCompoundStmt();
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
- MultiStmtArg Elts,
- bool isStmtExpr);
+ ArrayRef<Stmt *> Elts, bool isStmtExpr);
/// \brief A RAII object to enter scope of a compound statement.
class CompoundScopeRAII {
@@ -2865,11 +3027,10 @@ public:
StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
Decl *ExDecl, Stmt *HandlerBlock);
StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
- MultiStmtArg Handlers);
+ ArrayRef<Stmt *> Handlers);
StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ?
- SourceLocation TryLoc,
- Stmt *TryBlock,
+ SourceLocation TryLoc, Stmt *TryBlock,
Stmt *Handler);
StmtResult ActOnSEHExceptBlock(SourceLocation Loc,
@@ -2944,7 +3105,7 @@ public:
ObjCMethodDecl *Getter,
SourceLocation Loc);
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
- Expr **Args, unsigned NumArgs);
+ ArrayRef<Expr *> Args);
void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl = 0,
@@ -3006,12 +3167,19 @@ public:
/// from within the current scope. Only valid when the variable can be
/// captured.
///
+ /// \param FunctionScopeIndexToStopAt If non-null, it points to the index
+ /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.
+ /// This is useful when enclosing lambdas must speculatively capture
+ /// variables that may or may not be used in certain specializations of
+ /// a nested generic lambda.
+ ///
/// \returns true if an error occurred (i.e., the variable cannot be
/// captured) and false if the capture succeeded.
bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
SourceLocation EllipsisLoc, bool BuildAndDiagnose,
QualType &CaptureType,
- QualType &DeclRefType);
+ QualType &DeclRefType,
+ const unsigned *const FunctionScopeIndexToStopAt);
/// \brief Try to capture the given variable.
bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
@@ -3034,8 +3202,8 @@ public:
bool (*IsPlausibleResult)(QualType) = 0);
/// \brief Figure out if an expression could be turned into a call.
- bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
- UnresolvedSetImpl &NonTemplateOverloads);
+ bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
+ UnresolvedSetImpl &NonTemplateOverloads);
/// \brief Conditionally issue a diagnostic based on the current
/// evaluation context.
@@ -3054,7 +3222,8 @@ public:
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
bool HasTrailingLParen, bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC = 0);
+ CorrectionCandidateCallback *CCC = 0,
+ bool IsInlineAsmIdentifier = false);
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
@@ -3080,17 +3249,19 @@ public:
ExprValueKind VK,
SourceLocation Loc,
const CXXScopeSpec *SS = 0);
- ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty,
- ExprValueKind VK,
+ ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS = 0,
- NamedDecl *FoundD = 0);
+ const CXXScopeSpec *SS = 0, NamedDecl *FoundD = 0,
+ const TemplateArgumentListInfo *TemplateArgs = 0);
ExprResult
- BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
- SourceLocation nameLoc,
- IndirectFieldDecl *indirectField,
- Expr *baseObjectExpr = 0,
- SourceLocation opLoc = SourceLocation());
+ BuildAnonymousStructUnionMemberReference(
+ const CXXScopeSpec &SS,
+ SourceLocation nameLoc,
+ IndirectFieldDecl *indirectField,
+ DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_none),
+ Expr *baseObjectExpr = 0,
+ SourceLocation opLoc = SourceLocation());
+
ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -3115,9 +3286,9 @@ public:
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R,
bool NeedsADL);
- ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- NamedDecl *D, NamedDecl *FoundD = 0);
+ ExprResult BuildDeclarationNameExpr(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
+ NamedDecl *FoundD = 0, const TemplateArgumentListInfo *TemplateArgs = 0);
ExprResult BuildLiteralOperatorCall(LookupResult &R,
DeclarationNameInfo &SuffixInfo,
@@ -3125,6 +3296,8 @@ public:
SourceLocation LitEndLoc,
TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
+ ExprResult BuildPredefinedExpr(SourceLocation Loc,
+ PredefinedExpr::IdentType IT);
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0);
@@ -3143,15 +3316,14 @@ public:
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- MultiTypeArg ArgTypes,
- MultiExprArg ArgExprs);
+ ArrayRef<ParsedType> ArgTypes,
+ ArrayRef<Expr *> ArgExprs);
ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- TypeSourceInfo **Types,
- Expr **Exprs,
- unsigned NumAssocs);
+ ArrayRef<TypeSourceInfo *> Types,
+ ArrayRef<Expr *> Exprs);
// Binary/Unary Operators. 'Tok' is the token for the operator.
ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
@@ -3161,6 +3333,8 @@ public:
ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, Expr *Input);
+ QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc);
+
ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind,
@@ -3255,7 +3429,7 @@ public:
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool ExecConfig = false);
void CheckStaticArrayArgument(SourceLocation CallLoc,
@@ -3270,7 +3444,7 @@ public:
Expr *ExecConfig = 0, bool IsExecConfig = false);
ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Arg,
SourceLocation RParenLoc,
Expr *Config = 0,
bool IsExecConfig = false);
@@ -3431,6 +3605,13 @@ public:
ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body,
Scope *CurScope);
+ //===---------------------------- Clang Extensions ----------------------===//
+
+ /// __builtin_convertvector(...)
+ ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc);
+
//===---------------------------- OpenCL Features -----------------------===//
/// __builtin_astype(...)
@@ -3488,12 +3669,14 @@ public:
void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow);
bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target,
- const LookupResult &PreviousDecls);
+ const LookupResult &PreviousDecls,
+ UsingShadowDecl *&PrevShadow);
UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD,
- NamedDecl *Target);
+ NamedDecl *Target,
+ UsingShadowDecl *PrevDecl);
bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
- bool isTypeName,
+ bool HasTypenameKeyword,
const CXXScopeSpec &SS,
SourceLocation NameLoc,
const LookupResult &Previous);
@@ -3507,7 +3690,7 @@ public:
const DeclarationNameInfo &NameInfo,
AttributeList *AttrList,
bool IsInstantiation,
- bool IsTypeName,
+ bool HasTypenameKeyword,
SourceLocation TypenameLoc);
bool CheckInheritingConstructorUsingDecl(UsingDecl *UD);
@@ -3519,7 +3702,7 @@ public:
CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName,
+ bool HasTypenameKeyword,
SourceLocation TypenameLoc);
Decl *ActOnAliasDeclaration(Scope *CurScope,
AccessSpecifier AS,
@@ -3918,7 +4101,17 @@ public:
///
/// \param Explicit Whether 'this' is explicitly captured in a lambda
/// capture list.
- void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
+ ///
+ /// \param FunctionScopeIndexToStopAt If non-null, it points to the index
+ /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.
+ /// This is useful when enclosing lambdas must speculatively capture
+ /// 'this' that may or may not be used in certain specializations of
+ /// a nested generic lambda (depending on whether the name resolves to
+ /// a non-static member function or a static function).
+ /// \return returns 'true' if failed, 'false' if success.
+ bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false,
+ bool BuildAndDiagnose = true,
+ const unsigned *const FunctionScopeIndexToStopAt = 0);
/// \brief Determine whether the given type is the type of *this that is used
/// outside of the body of a member function for a type that is currently
@@ -3979,22 +4172,26 @@ public:
SourceRange R);
bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool UseGlobal, QualType AllocType, bool IsArray,
- Expr **PlaceArgs, unsigned NumPlaceArgs,
+ MultiExprArg PlaceArgs,
FunctionDecl *&OperatorNew,
FunctionDecl *&OperatorDelete);
bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
- DeclarationName Name, Expr** Args,
- unsigned NumArgs, DeclContext *Ctx,
+ DeclarationName Name, MultiExprArg Args,
+ DeclContext *Ctx,
bool AllowMissing, FunctionDecl *&Operator,
bool Diagnose = true);
void DeclareGlobalNewDelete();
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
- QualType Argument,
+ QualType Param1,
+ QualType Param2 = QualType(),
bool addMallocAttr = false);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator,
bool Diagnose = true);
+ FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc,
+ bool CanProvideSize,
+ DeclarationName Name);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
ExprResult ActOnCXXDelete(SourceLocation StartLoc,
@@ -4120,7 +4317,8 @@ public:
}
ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
bool DiscardedValue = false,
- bool IsConstexpr = false);
+ bool IsConstexpr = false,
+ bool IsLambdaInitCaptureInitializer = false);
StmtResult ActOnFinishFullStmt(Stmt *Stmt);
// Marks SS invalid if it represents an incomplete type.
@@ -4131,7 +4329,6 @@ public:
bool EnteringContext = false);
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
- bool isUnknownSpecialization(const CXXScopeSpec &SS);
/// \brief The parser has parsed a global nested-name-specifier '::'.
///
@@ -4296,7 +4493,8 @@ public:
/// \brief Create a new lambda closure type.
CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
TypeSourceInfo *Info,
- bool KnownDependent);
+ bool KnownDependent,
+ LambdaCaptureDefault CaptureDefault);
/// \brief Start the definition of a lambda expression.
CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
@@ -4305,13 +4503,31 @@ public:
SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params);
- /// \brief Introduce the scope for a lambda expression.
- sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
- SourceRange IntroducerRange,
- LambdaCaptureDefault CaptureDefault,
- bool ExplicitParams,
- bool ExplicitResultType,
- bool Mutable);
+ /// \brief Endow the lambda scope info with the relevant properties.
+ void buildLambdaScope(sema::LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ bool Mutable);
+
+ /// \brief Perform initialization analysis of the init-capture and perform
+ /// any implicit conversions such as an lvalue-to-rvalue conversion if
+ /// not being used to initialize a reference.
+ QualType performLambdaInitCaptureInitialization(SourceLocation Loc,
+ bool ByRef, IdentifierInfo *Id, Expr *&Init);
+ /// \brief Create a dummy variable within the declcontext of the lambda's
+ /// call operator, for name lookup purposes for a lambda init capture.
+ ///
+ /// CodeGen handles emission of lambda captures, ignoring these dummy
+ /// variables appropriately.
+ VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
+ QualType InitCaptureType, IdentifierInfo *Id, Expr *Init);
+
+ /// \brief Build the implicit field for an init-capture.
+ FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
/// \brief Note that we have finished the explicit captures for the
/// given lambda.
@@ -4444,6 +4660,7 @@ public:
//
bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = 0);
+ bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS);
bool ActOnAccessSpecifier(AccessSpecifier Access,
SourceLocation ASLoc,
@@ -4466,7 +4683,7 @@ public:
const DeclSpec &DS,
SourceLocation IdLoc,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc);
@@ -4590,7 +4807,9 @@ public:
void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnFinishDelayedMemberInitializers(Decl *Record);
- void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
+ void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
+ CachedTokens &Toks);
+ void UnmarkAsLateParsedTemplate(FunctionDecl *FD);
bool IsInsideALocalClassWithinATemplateFunction();
Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
@@ -4624,7 +4843,7 @@ public:
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
const FunctionProtoType *T);
- void CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
+ void CheckDelayedMemberExceptionSpecs();
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -4687,7 +4906,7 @@ public:
bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange);
/// CheckOverrideControl - Check C++11 override control semantics.
- void CheckOverrideControl(Decl *D);
+ void CheckOverrideControl(NamedDecl *D);
/// CheckForFunctionMarkedFinal - Checks whether a virtual member function
/// overrides a virtual member function marked 'final', according to
@@ -4735,6 +4954,9 @@ public:
const PartialDiagnostic &PDiag,
QualType objectType = QualType());
AccessResult CheckFriendAccess(NamedDecl *D);
+ AccessResult CheckMemberAccess(SourceLocation UseLoc,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair Found);
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
Expr *ArgExpr,
@@ -4771,6 +4993,7 @@ public:
AbstractVariableType,
AbstractFieldType,
AbstractIvarType,
+ AbstractSynthesizedIvarType,
AbstractArrayType
};
@@ -4878,12 +5101,13 @@ public:
Decl **Params, unsigned NumParams,
SourceLocation RAngleLoc);
- /// \brief The context in which we are checking a template parameter
- /// list.
+ /// \brief The context in which we are checking a template parameter list.
enum TemplateParamListContext {
TPC_ClassTemplate,
+ TPC_VarTemplate,
TPC_FunctionTemplate,
TPC_ClassTemplateMember,
+ TPC_FriendClassTemplate,
TPC_FriendFunctionTemplate,
TPC_FriendFunctionTemplateDefinition,
TPC_TypeAliasTemplate
@@ -4892,15 +5116,10 @@ public:
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
TemplateParameterList *OldParams,
TemplateParamListContext TPC);
- TemplateParameterList *
- MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
- SourceLocation DeclLoc,
- const CXXScopeSpec &SS,
- TemplateParameterList **ParamLists,
- unsigned NumParamLists,
- bool IsFriend,
- bool &IsExplicitSpecialization,
- bool &Invalid);
+ TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
+ SourceLocation DeclStartLoc, SourceLocation DeclLoc,
+ const CXXScopeSpec &SS, ArrayRef<TemplateParameterList *> ParamLists,
+ bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
@@ -4942,6 +5161,21 @@ public:
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc);
+ DeclResult ActOnVarTemplateSpecialization(
+ Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
+ SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
+ StorageClass SC, bool IsPartialSpecialization);
+
+ DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation TemplateNameLoc,
+ const TemplateArgumentListInfo &TemplateArgs);
+
+ ExprResult CheckVarTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ VarTemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
@@ -5035,7 +5269,9 @@ public:
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
- SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument>
+ &Converted,
+ bool &HasDefaultArg);
/// \brief Specifies the context in which a particular template
/// argument is being checked.
@@ -5289,7 +5525,7 @@ public:
/// \brief Block expression,
UPPC_Block
-};
+ };
/// \brief Diagnose unexpanded parameter packs.
///
@@ -5538,10 +5774,25 @@ public:
/// false otherwise.
bool containsUnexpandedParameterPacks(Declarator &D);
+ /// \brief Returns the pattern of the pack expansion for a template argument.
+ ///
+ /// \param OrigLoc The template argument to expand.
+ ///
+ /// \param Ellipsis Will be set to the location of the ellipsis.
+ ///
+ /// \param NumExpansions Will be set to the number of expansions that will
+ /// be generated from this pack expansion, if known a priori.
+ TemplateArgumentLoc getTemplateArgumentPackExpansionPattern(
+ TemplateArgumentLoc OrigLoc,
+ SourceLocation &Ellipsis,
+ Optional<unsigned> &NumExpansions) const;
+
//===--------------------------------------------------------------------===//
// C++ Template Argument Deduction (C++ [temp.deduct])
//===--------------------------------------------------------------------===//
+ QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType);
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -5598,12 +5849,16 @@ public:
sema::TemplateDeductionInfo &Info);
TemplateDeductionResult
- SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo &ExplicitTemplateArgs,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- SmallVectorImpl<QualType> &ParamTypes,
- QualType *FunctionType,
- sema::TemplateDeductionInfo &Info);
+ DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ sema::TemplateDeductionInfo &Info);
+
+ TemplateDeductionResult SubstituteExplicitTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo &ExplicitTemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType,
+ sema::TemplateDeductionInfo &Info);
/// brief A function argument from which we performed template argument
// deduction for a call.
@@ -5655,6 +5910,12 @@ public:
sema::TemplateDeductionInfo &Info,
bool InOverloadResolution = false);
+ /// \brief Substitute Replacement for \p auto in \p TypeWithAuto
+ QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
+ /// \brief Substitute Replacement for auto in TypeWithAuto
+ TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+ QualType Replacement);
+
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {
DAR_Succeeded,
@@ -5666,7 +5927,6 @@ public:
QualType &Result);
DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
QualType &Result);
- QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
@@ -5679,17 +5939,16 @@ public:
FunctionTemplateDecl *FT2,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments);
- UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin,
- UnresolvedSetIterator SEnd,
- TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- bool Complain = true,
- QualType TargetType = QualType());
+ unsigned NumCallArguments1,
+ unsigned NumCallArguments2);
+ UnresolvedSetIterator
+ getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd,
+ TemplateSpecCandidateSet &FailedCandidates,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ bool Complain = true, QualType TargetType = QualType());
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
@@ -5697,6 +5956,10 @@ public:
ClassTemplatePartialSpecializationDecl *PS2,
SourceLocation Loc);
+ VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *PS1,
+ VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc);
+
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
unsigned Depth,
@@ -5814,10 +6077,7 @@ public:
case PriorTemplateArgumentSubstitution:
case DefaultTemplateArgumentChecking:
- if (X.Template != Y.Template)
- return false;
-
- // Fall through
+ return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs;
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
@@ -5845,6 +6105,20 @@ public:
SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
+ /// \brief Extra modules inspected when performing a lookup during a template
+ /// instantiation. Computed lazily.
+ SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules;
+
+ /// \brief Cache of additional modules that should be used for name lookup
+ /// within the current template instantiation. Computed lazily; use
+ /// getLookupModules() to get a complete set.
+ llvm::DenseSet<Module*> LookupModulesCache;
+
+ /// \brief Get the set of additional modules that should be checked during
+ /// name lookup. A module and its imports become visible when instanting a
+ /// template defined within it.
+ llvm::DenseSet<Module*> &getLookupModules();
+
/// \brief Whether we are in a SFINAE context that is not associated with
/// template instantiation.
///
@@ -5906,8 +6180,9 @@ public:
/// deduction.
///
/// FIXME: Serialize this structure to the AST file.
- llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >
- SuppressedDiagnostics;
+ typedef llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >
+ SuppressedDiagnosticsMap;
+ SuppressedDiagnosticsMap SuppressedDiagnostics;
/// \brief A stack object to be created when performing template
/// instantiation.
@@ -5959,6 +6234,15 @@ public:
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are instantiating as part of template
+ /// argument deduction for a variable template partial
+ /// specialization.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ VarTemplatePartialSpecializationDecl *PartialSpec,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange = SourceRange());
+
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs,
@@ -5994,7 +6278,7 @@ public:
/// \brief Determines whether we have exceeded the maximum
/// recursive template instantiations.
- operator bool() const { return Invalid; }
+ bool isInvalid() const { return Invalid; }
private:
Sema &SemaRef;
@@ -6031,7 +6315,7 @@ public:
/// \brief RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument
- /// deduction.`
+ /// deduction.
class SFINAETrap {
Sema &SemaRef;
unsigned PrevSFINAEErrors;
@@ -6063,10 +6347,34 @@ public:
}
};
+ /// \brief RAII class used to indicate that we are performing provisional
+ /// semantic analysis to determine the validity of a construct, so
+ /// typo-correction and diagnostics in the immediate context (not within
+ /// implicitly-instantiated templates) should be suppressed.
+ class TentativeAnalysisScope {
+ Sema &SemaRef;
+ // FIXME: Using a SFINAETrap for this is a hack.
+ SFINAETrap Trap;
+ bool PrevDisableTypoCorrection;
+ public:
+ explicit TentativeAnalysisScope(Sema &SemaRef)
+ : SemaRef(SemaRef), Trap(SemaRef, true),
+ PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) {
+ SemaRef.DisableTypoCorrection = true;
+ }
+ ~TentativeAnalysisScope() {
+ SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection;
+ }
+ };
+
/// \brief The current instantiation scope used to store local
/// variables.
LocalInstantiationScope *CurrentInstantiationScope;
+ /// \brief Tracks whether we are in a context where typo correction is
+ /// disabled.
+ bool DisableTypoCorrection;
+
/// \brief The number of typos corrected by CorrectTypo.
unsigned TyposCorrected;
@@ -6081,6 +6389,14 @@ public:
/// string represents a keyword.
UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected;
+ typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet;
+ typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations;
+
+ /// \brief A cache containing identifiers for which typo correction failed and
+ /// their locations, so that repeated attempts to correct an identifier in a
+ /// given location are ignored if typo correction already failed for it.
+ IdentifierSourceLocations TypoCorrectionFailures;
+
/// \brief Worker object for performing CFG-based warnings.
sema::AnalysisBasedWarnings AnalysisWarnings;
@@ -6107,6 +6423,26 @@ public:
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
+ class SavePendingLocalImplicitInstantiationsRAII {
+ public:
+ SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) {
+ SavedPendingLocalImplicitInstantiations.swap(
+ S.PendingLocalImplicitInstantiations);
+ }
+
+ ~SavePendingLocalImplicitInstantiationsRAII() {
+ assert(S.PendingLocalImplicitInstantiations.empty() &&
+ "there shouldn't be any pending local implicit instantiations");
+ SavedPendingLocalImplicitInstantiations.swap(
+ S.PendingLocalImplicitInstantiations);
+ }
+
+ private:
+ Sema &S;
+ std::deque<PendingImplicitInstantiation>
+ SavedPendingLocalImplicitInstantiations;
+ };
+
void PerformPendingInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
@@ -6240,6 +6576,30 @@ public:
FunctionDecl *Function,
bool Recursive = false,
bool DefinitionRequired = false);
+ VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(
+ VarTemplateDecl *VarTemplate, VarDecl *FromVar,
+ const TemplateArgumentList &TemplateArgList,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ SmallVectorImpl<TemplateArgument> &Converted,
+ SourceLocation PointOfInstantiation, void *InsertPos,
+ LateInstantiatedAttrVec *LateAttrs = 0,
+ LocalInstantiationScope *StartingScope = 0);
+ VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ void
+ BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ LateInstantiatedAttrVec *LateAttrs,
+ DeclContext *Owner,
+ LocalInstantiationScope *StartingScope,
+ bool InstantiatingVarTemplate = false);
+ void InstantiateVariableInitializer(
+ VarDecl *Var, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ void InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
+ VarDecl *Var, bool Recursive = false,
+ bool DefinitionRequired = false);
void InstantiateStaticDataMemberDefinition(
SourceLocation PointOfInstantiation,
VarDecl *Var,
@@ -6277,6 +6637,10 @@ public:
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
+
+ void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc);
Decl *ActOnCompatibilityAlias(
SourceLocation AtCompatibilityAliasLoc,
@@ -6359,18 +6723,15 @@ public:
void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
- const IdentifierInfo *Name);
+ const IdentifierInfo *Name,
+ bool OverridingProtocolProperty);
void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID);
- void MatchOneProtocolPropertiesInClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl);
-
Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd,
- Decl **allMethods = 0, unsigned allNum = 0,
- Decl **allProperties = 0, unsigned pNum = 0,
- DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+ ArrayRef<Decl *> allMethods = None,
+ ArrayRef<DeclGroupPtrTy> allTUVars = None);
Decl *ActOnProperty(Scope *S, SourceLocation AtLoc,
SourceLocation LParenLoc,
@@ -6584,6 +6945,15 @@ public:
PMSST_ON // #pragms ms_struct on
};
+ enum PragmaMSCommentKind {
+ PCK_Unknown,
+ PCK_Linker, // #pragma comment(linker, ...)
+ PCK_Lib, // #pragma comment(lib, ...)
+ PCK_Compiler, // #pragma comment(compiler, ...)
+ PCK_ExeStr, // #pragma comment(exestr, ...)
+ PCK_User // #pragma comment(user, ...)
+ };
+
/// ActOnPragmaPack - Called on well formed \#pragma pack(...).
void ActOnPragmaPack(PragmaPackKind Kind,
IdentifierInfo *Name,
@@ -6595,6 +6965,13 @@ public:
/// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off].
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
+ /// ActOnPragmaMSComment - Called on well formed
+ /// \#pragma comment(kind, "arg").
+ void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg);
+
+ /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
+ void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
+
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
void ActOnPragmaUnused(const Token &Identifier,
Scope *curScope,
@@ -6670,16 +7047,79 @@ public:
unsigned SpellingListIndex, bool IsPackExpansion);
// OpenMP directives and clauses.
+private:
+ void *VarDataSharingAttributesStack;
+ /// \brief Initialization of data-sharing attributes stack.
+ void InitDataSharingAttributesStack();
+ void DestroyDataSharingAttributesStack();
+public:
+ /// \brief Called on start of new data sharing attribute block.
+ void StartOpenMPDSABlock(OpenMPDirectiveKind K,
+ const DeclarationNameInfo &DirName,
+ Scope *CurScope);
+ /// \brief Called on end of data sharing attribute block.
+ void EndOpenMPDSABlock(Stmt *CurDirective);
+ // OpenMP directives and clauses.
+ /// \brief Called on correct id-expression from the '#pragma omp
+ /// threadprivate'.
+ ExprResult ActOnOpenMPIdExpression(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id);
/// \brief Called on well-formed '#pragma omp threadprivate'.
DeclGroupPtrTy ActOnOpenMPThreadprivateDirective(
- SourceLocation Loc,
- Scope *CurScope,
- ArrayRef<DeclarationNameInfo> IdList);
- /// \brief Build a new OpenMPThreadPrivateDecl and check its correctness.
+ SourceLocation Loc,
+ ArrayRef<Expr *> VarList);
+ // \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness.
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
- SourceLocation Loc,
- ArrayRef<DeclRefExpr *> VarList);
+ SourceLocation Loc,
+ ArrayRef<Expr *> VarList);
+
+ StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed '\#pragma omp parallel' after parsing
+ /// of the associated statement.
+ StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
+
+ OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
+ unsigned Argument,
+ SourceLocation ArgumentLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'default' clause.
+ OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
+ SourceLocation KindLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+
+ OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
+ ArrayRef<Expr *> Vars,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'private' clause.
+ OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'firstprivate' clause.
+ OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'shared' clause.
+ OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
@@ -6753,20 +7193,25 @@ public:
enum VarArgKind {
VAK_Valid,
VAK_ValidInCXX11,
+ VAK_Undefined,
VAK_Invalid
};
// Determines which VarArgKind fits an expression.
VarArgKind isValidVarArgType(const QualType &Ty);
+ /// Check to see if the given expression is a valid argument to a variadic
+ /// function, issuing a diagnostic if not.
+ void checkVariadicArgument(const Expr *E, VariadicCallType CT);
+
/// GatherArgumentsForCall - Collector argument expressions for various
/// form of call prototypes.
bool GatherArgumentsForCall(SourceLocation CallLoc,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
unsigned FirstProtoArg,
- Expr **Args, unsigned NumArgs,
- SmallVector<Expr *, 8> &AllArgs,
+ ArrayRef<Expr *> Args,
+ SmallVectorImpl<Expr *> &AllArgs,
VariadicCallType CallType = VariadicDoesNotApply,
bool AllowExplicit = false,
bool IsListInitialization = false);
@@ -6776,10 +7221,6 @@ public:
ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
FunctionDecl *FDecl);
- /// Checks to see if the given expression is a valid argument to a variadic
- /// function, issuing a diagnostic and returning NULL if not.
- bool variadicArgumentPODCheck(const Expr *E, VariadicCallType CT);
-
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
// operands and then handles various conversions that are common to binary
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
@@ -6892,7 +7333,8 @@ public:
// this routine performs the default function/array converions.
AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType,
ExprResult &RHS,
- bool Diagnose = true);
+ bool Diagnose = true,
+ bool DiagnoseCFAudited = false);
// \brief If the lhs type is a transparent union, check whether we
// can initialize the transparent union with the given expression.
@@ -7071,7 +7513,8 @@ public:
/// retainable pointers and other pointer kinds.
ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
QualType castType, Expr *&op,
- CheckedConversionKind CCK);
+ CheckedConversionKind CCK,
+ bool DiagnoseCFAudited = false);
Expr *stripARCUnbridgedCast(Expr *e);
void diagnoseARCUnbridgedCast(Expr *e);
@@ -7098,7 +7541,7 @@ public:
/// \param [out] ReturnType - The return type of the send.
/// \return true iff there were any incompatible types.
bool CheckMessageArgumentTypes(QualType ReceiverType,
- Expr **Args, unsigned NumArgs, Selector Sel,
+ MultiExprArg Args, Selector Sel,
ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method, bool isClassMessage,
bool isSuperMessage,
@@ -7186,8 +7629,8 @@ public:
/// Returns false on success.
/// Can optionally return whether the bit-field is of width 0
ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, Expr *BitWidth,
- bool *ZeroWidth = 0);
+ QualType FieldTy, bool IsMsStruct,
+ Expr *BitWidth, bool *ZeroWidth = 0);
enum CUDAFunctionTarget {
CFT_Device,
@@ -7284,9 +7727,10 @@ public:
void CodeCompleteNamespaceDecl(Scope *S);
void CodeCompleteNamespaceAliasDecl(Scope *S);
void CodeCompleteOperatorName(Scope *S);
- void CodeCompleteConstructorInitializer(Decl *Constructor,
- CXXCtorInitializer** Initializers,
- unsigned NumInitializers);
+ void CodeCompleteConstructorInitializer(
+ Decl *Constructor,
+ ArrayRef<CXXCtorInitializer *> Initializers);
+
void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
bool AfterAmpersand);
@@ -7301,24 +7745,20 @@ public:
bool IsParameter);
void CodeCompleteObjCMessageReceiver(Scope *S);
void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression);
void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
bool IsSuper = false);
void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
ObjCInterfaceDecl *Super = 0);
void CodeCompleteObjCForCollection(Scope *S,
DeclGroupPtrTy IterationVar);
void CodeCompleteObjCSelector(Scope *S,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents);
+ ArrayRef<IdentifierInfo *> SelIdents);
void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
unsigned NumProtocols);
void CodeCompleteObjCProtocolDecl(Scope *S);
@@ -7343,8 +7783,7 @@ public:
bool IsInstanceMethod,
bool AtParameterName,
ParsedType ReturnType,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents);
+ ArrayRef<IdentifierInfo *> SelIdents);
void CodeCompletePreprocessorDirective(bool InConditional);
void CodeCompleteInPreprocessorConditionalExclusion(Scope *S);
void CodeCompletePreprocessorMacroName(bool IsDefinition);
@@ -7385,8 +7824,9 @@ private:
const FunctionProtoType *Proto);
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
ArrayRef<const Expr *> Args);
- bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
- const FunctionProtoType *Proto);
+ bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto);
+ bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto);
void CheckConstructorCall(FunctionDecl *FDecl,
ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto,
@@ -7401,7 +7841,10 @@ private:
bool CheckObjCString(Expr *Arg);
ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+ bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
@@ -7411,6 +7854,9 @@ private:
public:
// Used by C++ template instantiation.
ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
+ ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc);
private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
@@ -7422,6 +7868,7 @@ private:
bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result);
+public:
enum FormatStringType {
FST_Scanf,
FST_Printf,
@@ -7433,37 +7880,26 @@ private:
};
static FormatStringType GetFormatStringType(const FormatAttr *Format);
- enum StringLiteralCheckType {
- SLCT_NotALiteral,
- SLCT_UncheckedLiteral,
- SLCT_CheckedLiteral
- };
-
- StringLiteralCheckType checkFormatStringExpr(const Expr *E,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg,
- unsigned format_idx,
- unsigned firstDataArg,
- FormatStringType Type,
- VariadicCallType CallType,
- bool inFunctionCall = true);
-
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
ArrayRef<const Expr *> Args, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, bool inFunctionCall,
- VariadicCallType CallType);
+ VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs);
+private:
bool CheckFormatArguments(const FormatAttr *Format,
ArrayRef<const Expr *> Args,
bool IsCXXMember,
VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range);
+ SourceLocation Loc, SourceRange Range,
+ llvm::SmallBitVector &CheckedVarArgs);
bool CheckFormatArguments(ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
- SourceLocation Loc, SourceRange range);
+ SourceLocation Loc, SourceRange range,
+ llvm::SmallBitVector &CheckedVarArgs);
void CheckNonNullArguments(const NonNullAttr *NonNull,
const Expr * const *ExprArgs,
@@ -7536,6 +7972,7 @@ private:
Scope *CurScope;
mutable IdentifierInfo *Ident_super;
+ mutable IdentifierInfo *Ident___float128;
protected:
friend class Parser;
@@ -7555,6 +7992,7 @@ public:
Scope *getCurScope() const { return CurScope; }
IdentifierInfo *getSuperIdentifier() const;
+ IdentifierInfo *getFloat128Identifier() const;
Decl *getObjCDeclContext() const;
@@ -7601,6 +8039,18 @@ public:
}
};
-} // end namespace clang
+DeductionFailureInfo
+MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK,
+ sema::TemplateDeductionInfo &Info);
+
+/// \brief Contains a late templated function.
+/// Will be parsed at the end of the translation unit, used by Sema & Parser.
+struct LateParsedTemplate {
+ CachedTokens Toks;
+ /// \brief The template function declaration to be late parsed.
+ Decl *D;
+};
+
+} // end namespace clang
#endif
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index 9605bf889a31..fdf959305151 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define SEMASTART
#include "clang/Basic/DiagnosticSemaKinds.inc"
#undef DIAG
diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index bbf42721ba6d..01d4cc9679ef 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/include/clang/Sema/SemaInternal.h
@@ -24,7 +24,44 @@ namespace clang {
inline PartialDiagnostic Sema::PDiag(unsigned DiagID) {
return PartialDiagnostic(DiagID, Context.getDiagAllocator());
}
-
+
+
+// This requires the variable to be non-dependent and the initializer
+// to not be value dependent.
+inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) {
+ const VarDecl *DefVD = 0;
+ return !isa<ParmVarDecl>(Var) &&
+ Var->isUsableInConstantExpressions(Context) &&
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE();
+}
+
+// Directly mark a variable odr-used. Given a choice, prefer to use
+// MarkVariableReferenced since it does additional checks and then
+// calls MarkVarDeclODRUsed.
+// If the variable must be captured:
+// - if FunctionScopeIndexToStopAt is null, capture it in the CurContext
+// - else capture it in the DeclContext that maps to the
+// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
+inline void MarkVarDeclODRUsed(VarDecl *Var,
+ SourceLocation Loc, Sema &SemaRef,
+ const unsigned *const FunctionScopeIndexToStopAt) {
+ // 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->isStaticDataMember() && Var->hasInit())) {
+ SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
+ if (old.isInvalid()) old = Loc;
+ }
+ QualType CaptureType, DeclRefType;
+ SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true,
+ CaptureType, DeclRefType,
+ FunctionScopeIndexToStopAt);
+
+ Var->markUsed(SemaRef.Context);
+}
}
#endif
diff --git a/include/clang/Sema/SemaLambda.h b/include/clang/Sema/SemaLambda.h
new file mode 100644
index 000000000000..cf9fff1f1a2a
--- /dev/null
+++ b/include/clang/Sema/SemaLambda.h
@@ -0,0 +1,39 @@
+//===--- SemaLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides some common utility functions for processing
+/// Lambdas.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_LAMBDA_H
+#define LLVM_CLANG_SEMA_LAMBDA_H
+#include "clang/AST/ASTLambda.h"
+#include "clang/Sema/ScopeInfo.h"
+namespace clang {
+
+// Given a lambda's call operator and a variable (or null for 'this'),
+// compute the nearest enclosing lambda that is capture-ready (i.e
+// the enclosing context is not dependent, and all intervening lambdas can
+// either implicitly or explicitly capture Var)
+//
+// Return the CallOperator of the capturable lambda and set function scope
+// index to the correct index within the function scope stack to correspond
+// to the capturable lambda.
+// If VarDecl *VD is null, we check for 'this' capture.
+CXXMethodDecl*
+GetInnermostEnclosingCapturableLambda(
+ ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
+ unsigned &FunctionScopeIndex,
+ DeclContext *const CurContext, VarDecl *VD, Sema &S);
+
+} // clang
+
+#endif // LLVM_CLANG_SEMA_LAMBDA_H
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index f9481c6c0c20..1af61d5abd61 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -97,13 +97,6 @@ namespace clang {
addOuterTemplateArguments(ArgList(TemplateArgs->data(),
TemplateArgs->size()));
}
-
- /// \brief Add a new outmost level to the multi-level template argument
- /// list.
- void addOuterTemplateArguments(const TemplateArgument *Args,
- unsigned NumArgs) {
- addOuterTemplateArguments(ArgList(Args, NumArgs));
- }
/// \brief Add a new outmost level to the multi-level template argument
/// list.
@@ -385,6 +378,14 @@ namespace clang {
ClassTemplatePartialSpecializationDecl *>, 4>
OutOfLinePartialSpecs;
+ /// \brief A list of out-of-line variable template partial
+ /// specializations that will need to be instantiated after the
+ /// enclosing variable's instantiation is complete.
+ /// FIXME: Verify that this is needed.
+ SmallVector<
+ std::pair<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>, 4>
+ OutOfLineVarPartialSpecs;
+
public:
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
@@ -393,62 +394,39 @@ namespace clang {
Owner(Owner), TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0)
{ }
- // FIXME: Once we get closer to completion, replace these manually-written
- // declarations with automatically-generated ones from
- // clang/AST/DeclNodes.inc.
- Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
- Decl *VisitLabelDecl(LabelDecl *D);
- Decl *VisitNamespaceDecl(NamespaceDecl *D);
- Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
- Decl *VisitTypedefDecl(TypedefDecl *D);
- Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
- Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
- Decl *VisitVarDecl(VarDecl *D);
- Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
- Decl *VisitFieldDecl(FieldDecl *D);
- Decl *VisitMSPropertyDecl(MSPropertyDecl *D);
- Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D);
- Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
- Decl *VisitEnumDecl(EnumDecl *D);
- Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFriendDecl(FriendDecl *D);
- Decl *VisitFunctionDecl(FunctionDecl *D,
- TemplateParameterList *TemplateParams = 0);
- Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
+// Define all the decl visitors using DeclNodes.inc
+#define DECL(DERIVED, BASE) \
+ Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D);
+#define ABSTRACT_DECL(DECL)
+
+// Decls which never appear inside a class or function.
+#define OBJCCONTAINER(DERIVED, BASE)
+#define FILESCOPEASM(DERIVED, BASE)
+#define IMPORT(DERIVED, BASE)
+#define LINKAGESPEC(DERIVED, BASE)
+#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
+#define OBJCMETHOD(DERIVED, BASE)
+#define OBJCIVAR(DERIVED, BASE)
+#define OBJCPROPERTY(DERIVED, BASE)
+#define OBJCPROPERTYIMPL(DERIVED, BASE)
+#define EMPTY(DERIVED, BASE)
+
+// Decls which use special-case instantiation code.
+#define BLOCK(DERIVED, BASE)
+#define CAPTURED(DERIVED, BASE)
+#define IMPLICITPARAM(DERIVED, BASE)
+
+#include "clang/AST/DeclNodes.inc"
+
+ // A few supplemental visitor functions.
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams = 0,
+ TemplateParameterList *TemplateParams,
bool IsClassScopeSpecialization = false);
- Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
- Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
- Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
- ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
- Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
- Decl *VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D);
- Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
- Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
- Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
- Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
- Decl *VisitUsingDecl(UsingDecl *D);
- Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
- Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
- Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
- Decl *VisitClassScopeFunctionSpecializationDecl(
- ClassScopeFunctionSpecializationDecl *D);
- Decl *VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
-
- // Base case. FIXME: Remove once we can instantiate everything.
- Decl *VisitDecl(Decl *D) {
- unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
- DiagnosticsEngine::Error,
- "cannot instantiate %0 yet");
- SemaRef.Diag(D->getLocation(), DiagID)
- << D->getDeclKindName();
-
- return 0;
- }
-
+ Decl *VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams);
+ Decl *VisitDecl(Decl *D);
+ Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate);
+
// Enable late instantiation of attributes. Late instantiated attributes
// will be stored in LA.
void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) {
@@ -470,6 +448,10 @@ namespace clang {
::iterator
delayed_partial_spec_iterator;
+ typedef SmallVectorImpl<std::pair<
+ VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> >::iterator
+ delayed_var_partial_spec_iterator;
+
/// \brief Return an iterator to the beginning of the set of
/// "delayed" partial specializations, which must be passed to
/// InstantiateClassTemplatePartialSpecialization once the class
@@ -478,6 +460,10 @@ namespace clang {
return OutOfLinePartialSpecs.begin();
}
+ delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() {
+ return OutOfLineVarPartialSpecs.begin();
+ }
+
/// \brief Return an iterator to the end of the set of
/// "delayed" partial specializations, which must be passed to
/// InstantiateClassTemplatePartialSpecialization once the class
@@ -486,6 +472,10 @@ namespace clang {
return OutOfLinePartialSpecs.end();
}
+ delayed_var_partial_spec_iterator delayed_var_partial_spec_end() {
+ return OutOfLineVarPartialSpecs.end();
+ }
+
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
SmallVectorImpl<ParmVarDecl *> &Params);
@@ -499,12 +489,21 @@ namespace clang {
DeclaratorDecl *NewDecl);
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);
-
+
+ Decl *VisitVarTemplateSpecializationDecl(
+ VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ llvm::ArrayRef<TemplateArgument> Converted);
+
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
ClassTemplatePartialSpecializationDecl *
InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec);
+ VarTemplatePartialSpecializationDecl *
+ InstantiateVarTemplatePartialSpecialization(
+ VarTemplateDecl *VarTemplate,
+ VarTemplatePartialSpecializationDecl *PartialSpec);
void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
};
}
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 8292045fdb91..1daa6891ed12 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -20,6 +20,7 @@
namespace clang {
class TemplateArgumentList;
+class Sema;
namespace sema {
@@ -162,7 +163,124 @@ public:
Expr *Expression;
};
-}
-}
+} // end namespace sema
+
+/// A structure used to record information about a failed
+/// template argument deduction, for diagnosis.
+struct DeductionFailureInfo {
+ /// A Sema::TemplateDeductionResult.
+ unsigned Result : 8;
+
+ /// \brief Indicates whether a diagnostic is stored in Diagnostic.
+ unsigned HasDiagnostic : 1;
+
+ /// \brief Opaque pointer containing additional data about
+ /// this deduction failure.
+ void *Data;
+
+ /// \brief A diagnostic indicating why deduction failed.
+ union {
+ void *Align;
+ char Diagnostic[sizeof(PartialDiagnosticAt)];
+ };
+
+ /// \brief Retrieve the diagnostic which caused this deduction failure,
+ /// if any.
+ PartialDiagnosticAt *getSFINAEDiagnostic();
+
+ /// \brief Retrieve the template parameter this deduction failure
+ /// refers to, if any.
+ TemplateParameter getTemplateParameter();
+
+ /// \brief Retrieve the template argument list associated with this
+ /// deduction failure, if any.
+ TemplateArgumentList *getTemplateArgumentList();
+
+ /// \brief Return the first template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getFirstArg();
+
+ /// \brief Return the second template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getSecondArg();
+
+ /// \brief Return the expression this deduction failure refers to,
+ /// if any.
+ Expr *getExpr();
+
+ /// \brief Free any memory associated with this deduction failure.
+ void Destroy();
+};
+
+/// TemplateSpecCandidate - This is a generalization of OverloadCandidate
+/// which keeps track of template argument deduction failure info, when
+/// handling explicit specializations (and instantiations) of templates
+/// beyond function overloading.
+/// For now, assume that the candidates are non-matching specializations.
+/// TODO: In the future, we may need to unify/generalize this with
+/// OverloadCandidate.
+struct TemplateSpecCandidate {
+ /// Specialization - The actual specialization that this candidate
+ /// represents. When NULL, this may be a built-in candidate.
+ Decl *Specialization;
+
+ /// Template argument deduction info
+ DeductionFailureInfo DeductionFailure;
+
+ void set(Decl *Spec, DeductionFailureInfo Info) {
+ Specialization = Spec;
+ DeductionFailure = Info;
+ }
+
+ /// Diagnose a template argument deduction failure.
+ void NoteDeductionFailure(Sema &S);
+};
+
+/// TemplateSpecCandidateSet - A set of generalized overload candidates,
+/// used in template specializations.
+/// TODO: In the future, we may need to unify/generalize this with
+/// OverloadCandidateSet.
+class TemplateSpecCandidateSet {
+ SmallVector<TemplateSpecCandidate, 16> Candidates;
+ SourceLocation Loc;
+
+ TemplateSpecCandidateSet(
+ const TemplateSpecCandidateSet &) LLVM_DELETED_FUNCTION;
+ void operator=(const TemplateSpecCandidateSet &) LLVM_DELETED_FUNCTION;
+
+ void destroyCandidates();
+
+public:
+ TemplateSpecCandidateSet(SourceLocation Loc) : Loc(Loc) {}
+ ~TemplateSpecCandidateSet() { destroyCandidates(); }
+
+ SourceLocation getLocation() const { return Loc; }
+
+ /// \brief Clear out all of the candidates.
+ /// TODO: This may be unnecessary.
+ void clear();
+
+ typedef SmallVector<TemplateSpecCandidate, 16>::iterator iterator;
+ iterator begin() { return Candidates.begin(); }
+ iterator end() { return Candidates.end(); }
+
+ size_t size() const { return Candidates.size(); }
+ bool empty() const { return Candidates.empty(); }
+
+ /// \brief Add a new candidate with NumConversions conversion sequence slots
+ /// to the overload set.
+ TemplateSpecCandidate &addCandidate() {
+ Candidates.push_back(TemplateSpecCandidate());
+ return Candidates.back();
+ }
+
+ void NoteCandidates(Sema &S, SourceLocation Loc);
+
+ void NoteCandidates(Sema &S, SourceLocation Loc) const {
+ const_cast<TemplateSpecCandidateSet *>(this)->NoteCandidates(S, Loc);
+ }
+};
+
+} // end namespace clang
#endif
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index cdd71c8fa9aa..f0b772649847 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -39,31 +39,35 @@ public:
static const unsigned CallbackDistanceWeight = 150U;
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
- NestedNameSpecifier *NNS=0, unsigned CharDistance=0,
- unsigned QualifierDistance=0)
+ NestedNameSpecifier *NNS = 0, unsigned CharDistance = 0,
+ unsigned QualifierDistance = 0)
: CorrectionName(Name), CorrectionNameSpec(NNS),
- CharDistance(CharDistance), QualifierDistance(QualifierDistance),
- CallbackDistance(0) {
+ CharDistance(CharDistance), QualifierDistance(QualifierDistance),
+ CallbackDistance(0), ForceSpecifierReplacement(false),
+ RequiresImport(false) {
if (NameDecl)
CorrectionDecls.push_back(NameDecl);
}
- TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
- unsigned CharDistance=0)
+ TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = 0,
+ unsigned CharDistance = 0)
: CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
- CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {
+ CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
+ ForceSpecifierReplacement(false), RequiresImport(false) {
if (Name)
CorrectionDecls.push_back(Name);
}
- TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
- unsigned CharDistance=0)
+ TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = 0,
+ unsigned CharDistance = 0)
: CorrectionName(Name), CorrectionNameSpec(NNS),
- CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {}
+ CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
+ ForceSpecifierReplacement(false), RequiresImport(false) {}
TypoCorrection()
: CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0),
- CallbackDistance(0) {}
+ CallbackDistance(0), ForceSpecifierReplacement(false),
+ RequiresImport(false) {}
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
@@ -77,6 +81,15 @@ public:
}
void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
CorrectionNameSpec = NNS;
+ ForceSpecifierReplacement = (NNS != 0);
+ }
+
+ void WillReplaceSpecifier(bool ForceReplacement) {
+ ForceSpecifierReplacement = ForceReplacement;
+ }
+
+ bool WillReplaceSpecifier() const {
+ return ForceSpecifierReplacement;
}
void setQualifierDistance(unsigned ED) {
@@ -116,20 +129,31 @@ public:
}
/// \brief Gets the pointer to the declaration of the typo correction
- NamedDecl* getCorrectionDecl() const {
+ NamedDecl *getCorrectionDecl() const {
return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0;
}
template <class DeclClass>
DeclClass *getCorrectionDeclAs() const {
return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
}
-
+
+ /// \brief Clears the list of NamedDecls.
+ void ClearCorrectionDecls() {
+ CorrectionDecls.clear();
+ }
+
/// \brief Clears the list of NamedDecls before adding the new one.
void setCorrectionDecl(NamedDecl *CDecl) {
CorrectionDecls.clear();
addCorrectionDecl(CDecl);
}
+ /// \brief Clears the list of NamedDecls and adds the given set.
+ void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) {
+ CorrectionDecls.clear();
+ CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
+ }
+
/// \brief Add the given NamedDecl to the list of NamedDecls that are the
/// declarations associated with the DeclarationName of this TypoCorrection
void addCorrectionDecl(NamedDecl *CDecl);
@@ -140,7 +164,7 @@ public:
}
/// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
- operator bool() const { return bool(CorrectionName); }
+ LLVM_EXPLICIT operator bool() const { return bool(CorrectionName); }
/// \brief Mark this TypoCorrection as being a keyword.
/// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
@@ -149,6 +173,7 @@ public:
void makeKeyword() {
CorrectionDecls.clear();
CorrectionDecls.push_back(0);
+ ForceSpecifierReplacement = true;
}
// Check if this TypoCorrection is a keyword by checking if the first
@@ -171,10 +196,11 @@ public:
return CorrectionDecls.size() > 1;
}
- void setCorrectionRange(CXXScopeSpec* SS,
+ void setCorrectionRange(CXXScopeSpec *SS,
const DeclarationNameInfo &TypoName) {
- CorrectionRange.setBegin(CorrectionNameSpec && SS ? SS->getBeginLoc()
- : TypoName.getLoc());
+ CorrectionRange.setBegin(ForceSpecifierReplacement && SS && !SS->isEmpty()
+ ? SS->getBeginLoc()
+ : TypoName.getLoc());
CorrectionRange.setEnd(TypoName.getLoc());
}
@@ -182,17 +208,22 @@ public:
return CorrectionRange;
}
- typedef SmallVector<NamedDecl *, 1>::iterator decl_iterator;
+ typedef SmallVectorImpl<NamedDecl *>::iterator decl_iterator;
decl_iterator begin() {
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
}
decl_iterator end() { return CorrectionDecls.end(); }
- typedef SmallVector<NamedDecl *, 1>::const_iterator const_decl_iterator;
+ typedef SmallVectorImpl<NamedDecl *>::const_iterator const_decl_iterator;
const_decl_iterator begin() const {
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
}
const_decl_iterator end() const { return CorrectionDecls.end(); }
+ /// \brief Returns whether this typo correction is correcting to a
+ /// declaration that was declared in a module that has not been imported.
+ bool requiresImport() const { return RequiresImport; }
+ void setRequiresImport(bool Req) { RequiresImport = Req; }
+
private:
bool hasCorrectionDecl() const {
return (!isKeyword() && !CorrectionDecls.empty());
@@ -206,12 +237,14 @@ private:
unsigned QualifierDistance;
unsigned CallbackDistance;
SourceRange CorrectionRange;
+ bool ForceSpecifierReplacement;
+ bool RequiresImport;
};
/// @brief Base class for callback objects used by Sema::CorrectTypo to check
/// the validity of a potential typo correction.
class CorrectionCandidateCallback {
- public:
+public:
static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
CorrectionCandidateCallback()
@@ -260,12 +293,42 @@ class CorrectionCandidateCallback {
/// to ones having a single Decl* of the given type.
template <class C>
class DeclFilterCCC : public CorrectionCandidateCallback {
- public:
+public:
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
return candidate.getCorrectionDeclAs<C>();
}
};
+// @brief Callback class to limit the allowed keywords and to only accept typo
+// corrections that are keywords or whose decls refer to functions (or template
+// functions) that accept the given number of arguments.
+class FunctionCallFilterCCC : public CorrectionCandidateCallback {
+public:
+ FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
+ bool HasExplicitTemplateArgs);
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate);
+
+ private:
+ unsigned NumArgs;
+ bool HasExplicitTemplateArgs;
+};
+
+// @brief Callback class that effectively disabled typo correction
+class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
+public:
+ NoTypoCorrectionCCC() {
+ WantTypeSpecifiers = false;
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return false;
+ }
+};
+
}
#endif
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 81f898042581..03d905054aea 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -535,7 +535,10 @@ namespace clang {
/// \brief Record code for undefined but used functions and variables that
/// need a definition in this TU.
- UNDEFINED_BUT_USED = 49
+ UNDEFINED_BUT_USED = 49,
+
+ /// \brief Record code for late parsed template functions.
+ LATE_PARSED_TEMPLATE = 50
};
/// \brief Record types used within a source manager block.
@@ -623,7 +626,9 @@ namespace clang {
/// \brief Specifies a configuration macro for this module.
SUBMODULE_CONFIG_MACRO = 11,
/// \brief Specifies a conflict with another module.
- SUBMODULE_CONFLICT = 12
+ SUBMODULE_CONFLICT = 12,
+ /// \brief Specifies a header that is private to this submodule.
+ SUBMODULE_PRIVATE_HEADER = 13
};
/// \brief Record types used within a comments block.
@@ -834,7 +839,9 @@ namespace clang {
/// \brief A UnaryTransformType record.
TYPE_UNARY_TRANSFORM = 39,
/// \brief An AtomicType record.
- TYPE_ATOMIC = 40
+ TYPE_ATOMIC = 40,
+ /// \brief A DecayedType record.
+ TYPE_DECAYED = 41
};
/// \brief The type IDs for special types constructed by semantic
@@ -1023,6 +1030,12 @@ namespace clang {
DECL_CLASS_TEMPLATE_SPECIALIZATION,
/// \brief A ClassTemplatePartialSpecializationDecl record.
DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION,
+ /// \brief A VarTemplateDecl record.
+ DECL_VAR_TEMPLATE,
+ /// \brief A VarTemplateSpecializationDecl record.
+ DECL_VAR_TEMPLATE_SPECIALIZATION,
+ /// \brief A VarTemplatePartialSpecializationDecl record.
+ DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION,
/// \brief A FunctionTemplateDecl record.
DECL_FUNCTION_TEMPLATE,
/// \brief A TemplateTypeParmDecl record.
@@ -1050,7 +1063,7 @@ namespace clang {
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
/// \brief An ImportDecl recording a module import.
DECL_IMPORT,
- /// \brief A OMPThreadPrivateDecl record.
+ /// \brief An OMPThreadPrivateDecl record.
DECL_OMP_THREADPRIVATE,
/// \brief An EmptyDecl record.
DECL_EMPTY
@@ -1173,6 +1186,8 @@ namespace clang {
EXPR_GNU_NULL,
/// \brief A ShuffleVectorExpr record.
EXPR_SHUFFLE_VECTOR,
+ /// \brief A ConvertVectorExpr record.
+ EXPR_CONVERT_VECTOR,
/// \brief BlockExpr
EXPR_BLOCK,
/// \brief A GenericSelectionExpr record.
@@ -1259,6 +1274,8 @@ namespace clang {
EXPR_CXX_FUNCTIONAL_CAST,
/// \brief A UserDefinedLiteral record.
EXPR_USER_DEFINED_LITERAL,
+ /// \brief A CXXStdInitializerListExpr record.
+ EXPR_CXX_STD_INITIALIZER_LIST,
/// \brief A CXXBoolLiteralExpr record.
EXPR_CXX_BOOL_LITERAL,
EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
@@ -1313,7 +1330,10 @@ namespace clang {
STMT_SEH_EXCEPT, // SEHExceptStmt
STMT_SEH_FINALLY, // SEHFinallyStmt
STMT_SEH_TRY, // SEHTryStmt
-
+
+ // OpenMP drectives
+ STMT_OMP_PARALLEL_DIRECTIVE,
+
// ARC
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 2c0102e3410f..d3cca1a84948 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -88,7 +88,7 @@ class TypeLocReader;
struct HeaderFileInfo;
class VersionTuple;
class TargetOptions;
-class ASTUnresolvedSet;
+class LazyASTUnresolvedSet;
/// \brief Abstract interface for callback invocations by the ASTReader.
///
@@ -166,9 +166,6 @@ public:
return false;
}
- /// \brief Receives a HeaderFileInfo entry.
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {}
-
/// \brief Receives __COUNTER__ value.
virtual void ReadCounter(const serialization::ModuleFile &M,
unsigned Value) {}
@@ -190,11 +187,9 @@ class PCHValidator : public ASTReaderListener {
Preprocessor &PP;
ASTReader &Reader;
- unsigned NumHeaderInfos;
-
public:
PCHValidator(Preprocessor &PP, ASTReader &Reader)
- : PP(PP), Reader(Reader), NumHeaderInfos(0) {}
+ : PP(PP), Reader(Reader) {}
virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain);
@@ -203,7 +198,6 @@ public:
virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool Complain,
std::string &SuggestedPredefines);
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value);
private:
@@ -246,6 +240,7 @@ class ASTReader
{
public:
typedef SmallVector<uint64_t, 64> RecordData;
+ typedef SmallVectorImpl<uint64_t> RecordDataImpl;
/// \brief The result of reading the control block of an AST file, which
/// can fail for various reasons.
@@ -315,6 +310,10 @@ private:
/// \brief The module manager which manages modules and their dependencies
ModuleManager ModuleMgr;
+ /// \brief The location where the module file will be considered as
+ /// imported from. For non-module AST types it should be invalid.
+ SourceLocation CurrentImportLoc;
+
/// \brief The global module index, if loaded.
llvm::OwningPtr<GlobalModuleIndex> GlobalIndex;
@@ -712,6 +711,9 @@ private:
/// SourceLocation of a matching ODR-use.
SmallVector<uint64_t, 8> UndefinedButUsed;
+ // \brief A list of late parsed template function data.
+ SmallVector<uint64_t, 1> LateParsedTemplates;
+
/// \brief A list of modules that were imported by precompiled headers or
/// any other non-module AST file.
SmallVector<serialization::SubmoduleID, 2> ImportedModules;
@@ -873,6 +875,14 @@ private:
/// been completed.
std::deque<PendingDeclContextInfo> PendingDeclContextInfos;
+ /// \brief The set of NamedDecls that have been loaded, but are members of a
+ /// context that has been merged into another context where the corresponding
+ /// declaration is either missing or has not yet been loaded.
+ ///
+ /// We will check whether the corresponding declaration is in fact missing
+ /// once recursing loading has been completed.
+ llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks;
+
/// \brief The set of Objective-C categories that have been deserialized
/// since the last time the declaration chains were linked.
llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized;
@@ -909,16 +919,22 @@ private:
/// the given canonical declaration.
MergedDeclsMap::iterator
combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID);
-
- /// \brief Ready to load the previous declaration of the given Decl.
- void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID);
+
+ /// \brief A mapping from DeclContexts to the semantic DeclContext that we
+ /// are treating as the definition of the entity. This is used, for instance,
+ /// when merging implicit instantiations of class templates across modules.
+ llvm::DenseMap<DeclContext *, DeclContext *> MergedDeclContexts;
+
+ /// \brief A mapping from canonical declarations of enums to their canonical
+ /// definitions. Only populated when using modules in C++.
+ llvm::DenseMap<EnumDecl *, EnumDecl *> EnumDefinitions;
/// \brief When reading a Stmt tree, Stmt operands are placed in this stack.
SmallVector<Stmt *, 16> StmtStack;
/// \brief What kind of records we are reading.
enum ReadingKind {
- Read_Decl, Read_Type, Read_Stmt
+ Read_None, Read_Decl, Read_Type, Read_Stmt
};
/// \brief What kind of records we are reading.
@@ -1238,7 +1254,7 @@ public:
void setDeserializationListener(ASTDeserializationListener *Listener);
/// \brief Determine whether this AST reader has a global index.
- bool hasGlobalIndex() const { return GlobalIndex; }
+ bool hasGlobalIndex() const { return GlobalIndex.isValid(); }
/// \brief Attempts to load the global index.
///
@@ -1252,6 +1268,9 @@ public:
/// \brief Initializes the ASTContext
void InitializeContext();
+ /// \brief Update the state of Sema after loading some additional modules.
+ void UpdateSema();
+
/// \brief Add in-memory (virtual file) buffer.
void addInMemoryBuffer(StringRef &FileName, llvm::MemoryBuffer *Buffer) {
ModuleMgr.addInMemoryBuffer(FileName, Buffer);
@@ -1386,6 +1405,10 @@ public:
ReadTemplateArgumentLoc(ModuleFile &F,
const RecordData &Record, unsigned &Idx);
+ const ASTTemplateArgumentListInfo*
+ ReadASTTemplateArgumentListInfo(ModuleFile &F,
+ const RecordData &Record, unsigned &Index);
+
/// \brief Reads a declarator info from the given record.
TypeSourceInfo *GetTypeSourceInfo(ModuleFile &F,
const RecordData &Record, unsigned &Idx);
@@ -1612,6 +1635,9 @@ public:
SmallVectorImpl<std::pair<ValueDecl *,
SourceLocation> > &Pending);
+ virtual void ReadLateParsedTemplates(
+ llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap);
+
/// \brief Load a selector from disk, registering its ID if it exists.
void LoadSelector(Selector Sel);
@@ -1734,12 +1760,12 @@ public:
/// \brief Read a template argument array.
void
- ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
+ ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a UnresolvedSet structure.
- void ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
+ void ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx);
/// \brief Read a C++ base specifier.
@@ -1762,7 +1788,8 @@ public:
/// \brief Read a source location.
SourceLocation ReadSourceLocation(ModuleFile &ModuleFile,
- const RecordData &Record, unsigned &Idx) {
+ const RecordDataImpl &Record,
+ unsigned &Idx) {
return ReadSourceLocation(ModuleFile, Record[Idx++]);
}
@@ -1813,7 +1840,7 @@ public:
Expr *ReadSubExpr();
/// \brief Reads a token out of a record.
- Token ReadToken(ModuleFile &M, const RecordData &Record, unsigned &Idx);
+ Token ReadToken(ModuleFile &M, const RecordDataImpl &Record, unsigned &Idx);
/// \brief Reads the macro record located at the given offset.
MacroInfo *ReadMacroRecord(ModuleFile &F, uint64_t Offset);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 8ac8fde88470..07fdd062ace7 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -424,7 +424,8 @@ private:
StringRef isysroot, const std::string &OutputFile);
void WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
- StringRef isysroot);
+ StringRef isysroot,
+ bool Modules);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
StringRef isysroot);
@@ -456,7 +457,8 @@ private:
void WriteObjCCategories();
void WriteRedeclarations();
void WriteMergedDecls();
-
+ void WriteLateParsedTemplates(Sema &SemaRef);
+
unsigned DeclParmVarAbbrev;
unsigned DeclContextLexicalAbbrev;
unsigned DeclContextVisibleLookupAbbrev;
@@ -575,6 +577,11 @@ public:
void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
RecordDataImpl &Record);
+ /// \brief Emits an AST template argument list info.
+ void AddASTTemplateArgumentListInfo(
+ const ASTTemplateArgumentListInfo *ASTTemplArgList,
+ RecordDataImpl &Record);
+
/// \brief Emit a reference to a declaration.
void AddDeclRef(const Decl *D, RecordDataImpl &Record);
@@ -723,8 +730,12 @@ public:
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D);
+ virtual void
+ AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
+ const VarTemplateSpecializationDecl *D);
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D);
+ virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
virtual void StaticDataMemberInstantiated(const VarDecl *D);
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
@@ -732,6 +743,7 @@ public:
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt);
+ void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE;
};
/// \brief AST and semantic-analysis consumer that generates a
@@ -746,6 +758,8 @@ class PCHGenerator : public SemaConsumer {
SmallVector<char, 128> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
+ bool AllowASTWithErrors;
+ bool HasEmittedPCH;
protected:
ASTWriter &getWriter() { return Writer; }
@@ -754,12 +768,15 @@ protected:
public:
PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
clang::Module *Module,
- StringRef isysroot, raw_ostream *Out);
+ StringRef isysroot, raw_ostream *Out,
+ bool AllowASTWithErrors = false);
~PCHGenerator();
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
virtual ASTMutationListener *GetASTMutationListener();
virtual ASTDeserializationListener *GetASTDeserializationListener();
+
+ bool hasEmittedPCH() const { return HasEmittedPCH; }
};
} // end namespace clang
diff --git a/include/clang/Serialization/GlobalModuleIndex.h b/include/clang/Serialization/GlobalModuleIndex.h
index ab91f4009c0b..76414ba634cc 100644
--- a/include/clang/Serialization/GlobalModuleIndex.h
+++ b/include/clang/Serialization/GlobalModuleIndex.h
@@ -34,6 +34,7 @@ namespace clang {
class DirectoryEntry;
class FileEntry;
class FileManager;
+class IdentifierIterator;
namespace serialization {
class ModuleFile;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index b2c406346a5f..ca643ba45f2e 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -96,9 +96,9 @@ class ModuleManager {
void returnVisitState(VisitState *State);
public:
- typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator;
- typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator;
- typedef SmallVector<ModuleFile*, 2>::reverse_iterator ModuleReverseIterator;
+ typedef SmallVectorImpl<ModuleFile*>::iterator ModuleIterator;
+ typedef SmallVectorImpl<ModuleFile*>::const_iterator ModuleConstIterator;
+ typedef SmallVectorImpl<ModuleFile*>::reverse_iterator ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
explicit ModuleManager(FileManager &FileMgr);
diff --git a/include/clang/Serialization/SerializationDiagnostic.h b/include/clang/Serialization/SerializationDiagnostic.h
index e63f814ee6a0..c28cfea25c87 100644
--- a/include/clang/Serialization/SerializationDiagnostic.h
+++ b/include/clang/Serialization/SerializationDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define SERIALIZATIONSTART
#include "clang/Basic/DiagnosticSerializationKinds.inc"
#undef DIAG
diff --git a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
new file mode 100644
index 000000000000..5978299701cf
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
@@ -0,0 +1,223 @@
+//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- 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 core data structures for retain count "summaries"
+// for Objective-C and Core Foundation APIs. These summaries are used
+// by the static analyzer to summarize the retain/release effects of
+// function and method calls. This drives a path-sensitive typestate
+// analysis in the static analyzer, but can also potentially be used by
+// other clients.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_OBJCRETAINCOUNT_H
+#define LLVM_CLANG_OBJCRETAINCOUNT_H
+
+namespace clang { namespace ento { namespace objc_retain {
+
+/// An ArgEffect summarizes the retain count behavior on an argument or receiver
+/// to a function or method.
+enum ArgEffect {
+ /// There is no effect.
+ DoNothing,
+
+ /// The argument is treated as if an -autorelease message had been sent to
+ /// the referenced object.
+ Autorelease,
+
+ /// The argument is treated as if an -dealloc message had been sent to
+ /// the referenced object.
+ Dealloc,
+
+ /// The argument has its reference count decreased by 1. This is as
+ /// if CFRelease has been called on the argument.
+ DecRef,
+
+ /// The argument has its reference count decreased by 1. This is as
+ /// if a -release message has been sent to the argument. This differs
+ /// in behavior from DecRef when GC is enabled.
+ DecRefMsg,
+
+ /// The argument has its reference count decreased by 1 to model
+ /// a transferred bridge cast under ARC.
+ DecRefBridgedTransferred,
+
+ /// The argument has its reference count increased by 1. This is as
+ /// if a -retain message has been sent to the argument. This differs
+ /// in behavior from IncRef when GC is enabled.
+ IncRefMsg,
+
+ /// The argument has its reference count increased by 1. This is as
+ /// if CFRetain has been called on the argument.
+ IncRef,
+
+ /// The argument acts as if has been passed to CFMakeCollectable, which
+ /// transfers the object to the Garbage Collector under GC.
+ MakeCollectable,
+
+ /// The argument is treated as potentially escaping, meaning that
+ /// even when its reference count hits 0 it should be treated as still
+ /// possibly being alive as someone else *may* be holding onto the object.
+ MayEscape,
+
+ /// All typestate tracking of the object ceases. This is usually employed
+ /// when the effect of the call is completely unknown.
+ StopTracking,
+
+ /// All typestate tracking of the object ceases. Unlike StopTracking,
+ /// this is also enforced when the method body is inlined.
+ ///
+ /// In some cases, we obtain a better summary for this checker
+ /// by looking at the call site than by inlining the function.
+ /// Signifies that we should stop tracking the symbol even if
+ /// the function is inlined.
+ StopTrackingHard,
+
+ /// Performs the combined functionality of DecRef and StopTrackingHard.
+ ///
+ /// The models the effect that the called function decrements the reference
+ /// count of the argument and all typestate tracking on that argument
+ /// should cease.
+ DecRefAndStopTrackingHard,
+
+ /// Performs the combined functionality of DecRefMsg and StopTrackingHard.
+ ///
+ /// The models the effect that the called function decrements the reference
+ /// count of the argument and all typestate tracking on that argument
+ /// should cease.
+ DecRefMsgAndStopTrackingHard
+};
+
+/// RetEffect summarizes a call's retain/release behavior with respect
+/// to its return value.
+class RetEffect {
+public:
+ enum Kind {
+ /// Indicates that no retain count information is tracked for
+ /// the return value.
+ NoRet,
+ /// Indicates that the returned value is an owned (+1) symbol.
+ OwnedSymbol,
+ /// Indicates that the returned value is an owned (+1) symbol and
+ /// that it should be treated as freshly allocated.
+ OwnedAllocatedSymbol,
+ /// Indicates that the returned value is an object with retain count
+ /// semantics but that it is not owned (+0). This is the default
+ /// for getters, etc.
+ NotOwnedSymbol,
+ /// Indicates that the object is not owned and controlled by the
+ /// Garbage collector.
+ GCNotOwnedSymbol,
+ /// Indicates that the object is not owned and controlled by ARC.
+ ARCNotOwnedSymbol,
+ /// Indicates that the return value is an owned object when the
+ /// receiver is also a tracked object.
+ OwnedWhenTrackedReceiver,
+ // Treat this function as returning a non-tracked symbol even if
+ // the function has been inlined. This is used where the call
+ // site summary is more presise than the summary indirectly produced
+ // by inlining the function
+ NoRetHard
+ };
+
+ /// Determines the object kind of a tracked object.
+ enum ObjKind {
+ /// Indicates that the tracked object is a CF object. This is
+ /// important between GC and non-GC code.
+ CF,
+ /// 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
+ };
+
+private:
+ Kind K;
+ ObjKind O;
+
+ RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
+
+public:
+ Kind getKind() const { return K; }
+
+ ObjKind getObjKind() const { return O; }
+
+ bool isOwned() const {
+ return K == OwnedSymbol || K == OwnedAllocatedSymbol ||
+ K == OwnedWhenTrackedReceiver;
+ }
+
+ bool notOwned() const {
+ return K == NotOwnedSymbol || K == ARCNotOwnedSymbol;
+ }
+
+ bool operator==(const RetEffect &Other) const {
+ return K == Other.K && O == Other.O;
+ }
+
+ static RetEffect MakeOwnedWhenTrackedReceiver() {
+ return RetEffect(OwnedWhenTrackedReceiver, ObjC);
+ }
+
+ static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) {
+ return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o);
+ }
+ static RetEffect MakeNotOwned(ObjKind o) {
+ return RetEffect(NotOwnedSymbol, o);
+ }
+ static RetEffect MakeGCNotOwned() {
+ return RetEffect(GCNotOwnedSymbol, ObjC);
+ }
+ static RetEffect MakeARCNotOwned() {
+ return RetEffect(ARCNotOwnedSymbol, ObjC);
+ }
+ static RetEffect MakeNoRet() {
+ return RetEffect(NoRet);
+ }
+ static RetEffect MakeNoRetHard() {
+ return RetEffect(NoRetHard);
+ }
+};
+
+/// Encapsulates the retain count semantics on the arguments, return value,
+/// and receiver (if any) of a function/method call.
+///
+/// Note that construction of these objects is not highly efficient. That
+/// is okay for clients where creating these objects isn't really a bottleneck.
+/// The purpose of the API is to provide something simple. The actual
+/// static analyzer checker that implements retain/release typestate
+/// tracking uses something more efficient.
+class CallEffects {
+ llvm::SmallVector<ArgEffect, 10> Args;
+ RetEffect Ret;
+ ArgEffect Receiver;
+
+ CallEffects(const RetEffect &R) : Ret(R) {}
+
+public:
+ /// Returns the argument effects for a call.
+ llvm::ArrayRef<ArgEffect> getArgs() const { return Args; }
+
+ /// Returns the effects on the receiver.
+ ArgEffect getReceiver() const { return Receiver; }
+
+ /// Returns the effect on the return value.
+ RetEffect getReturnValue() const { return Ret; }
+
+ /// Return the CallEfect for a given Objective-C method.
+ static CallEffects getEffect(const ObjCMethodDecl *MD);
+
+ /// Return the CallEfect for a given C/C++ function.
+ static CallEffects getEffect(const FunctionDecl *FD);
+};
+
+}}}
+
+#endif
+
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index dc7945016b1a..3355f4b6949c 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -24,14 +24,14 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR
ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
#ifndef ANALYSIS_DIAGNOSTICS
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)
#endif
-ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false)
-ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true)
-ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true)
-ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true)
-ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer)
+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_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer)
+ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer)
#ifndef ANALYSIS_PURGE
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC)
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index fb35f518ef02..618782e5d78c 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -52,7 +52,7 @@ NumConstraints
/// AnalysisDiagClients - Set of available diagnostic clients for rendering
/// analysis results.
enum AnalysisDiagClients {
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NUM_ANALYSIS_DIAG_CLIENTS
};
@@ -201,6 +201,9 @@ private:
/// \sa mayInlineCXXContainerCtorsAndDtors
Optional<bool> InlineCXXContainerCtorsAndDtors;
+ /// \sa mayInlineCXXSharedPtrDtor
+ Optional<bool> InlineCXXSharedPtrDtor;
+
/// \sa mayInlineObjCMethod
Optional<bool> ObjCInliningMode;
@@ -223,6 +226,9 @@ private:
/// \sa shouldSuppressFromCXXStandardLibrary
Optional<bool> SuppressFromCXXStandardLibrary;
+ /// \sa reportIssuesInMainSourceFile
+ Optional<bool> ReportIssuesInMainSourceFile;
+
/// \sa getGraphTrimInterval
Optional<unsigned> GraphTrimInterval;
@@ -291,6 +297,16 @@ public:
/// accepts the values "true" and "false".
bool mayInlineCXXContainerCtorsAndDtors();
+ /// Returns whether or not the destructor of C++ 'shared_ptr' may be
+ /// considered for inlining.
+ ///
+ /// This covers std::shared_ptr, std::tr1::shared_ptr, and boost::shared_ptr,
+ /// and indeed any destructor named "~shared_ptr".
+ ///
+ /// This is controlled by the 'c++-shared_ptr-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineCXXSharedPtrDtor();
+
/// Returns whether or not paths that go through null returns should be
/// suppressed.
///
@@ -326,6 +342,13 @@ public:
/// which accepts the values "true" and "false".
bool shouldSuppressFromCXXStandardLibrary();
+ /// Returns whether or not the diagnostic report should be always reported
+ /// in the main source file and not the headers.
+ ///
+ /// This is controlled by the 'report-in-main-source-file' config option,
+ /// which accepts the values "true" and "false".
+ bool shouldReportIssuesInMainSourceFile();
+
/// Returns whether irrelevant parts of a bug report path should be pruned
/// out of the final output.
///
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 5c560b2f0ec9..9584b8baf4f1 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_GR_BUGREPORTER
#include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
@@ -375,6 +376,7 @@ public:
virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
virtual ASTContext &getASTContext() = 0;
virtual SourceManager& getSourceManager() = 0;
+ virtual AnalyzerOptions& getAnalyzerOptions() = 0;
};
/// BugReporter is a utility class for generating PathDiagnostics for analysis.
@@ -442,6 +444,8 @@ public:
SourceManager& getSourceManager() { return D.getSourceManager(); }
+ AnalyzerOptions& getAnalyzerOptions() { return D.getAnalyzerOptions(); }
+
virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic,
PathDiagnosticConsumer &PC,
ArrayRef<BugReport *> &bugReports) {
@@ -462,20 +466,7 @@ public:
void EmitBasicReport(const Decl *DeclWithIssue,
StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
- SourceRange* RangeBeg, unsigned NumRanges);
-
- void EmitBasicReport(const Decl *DeclWithIssue,
- StringRef BugName, StringRef BugCategory,
- StringRef BugStr, PathDiagnosticLocation Loc) {
- EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0);
- }
-
- void EmitBasicReport(const Decl *DeclWithIssue,
- StringRef BugName, StringRef Category,
- StringRef BugStr, PathDiagnosticLocation Loc,
- SourceRange R) {
- EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
- }
+ ArrayRef<SourceRange> Ranges = None);
private:
llvm::StringMap<BugType *> StrBugTypes;
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 644aa3159301..49f9c83ba950 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
@@ -31,10 +32,12 @@ private:
const std::string Name;
const std::string Category;
bool SuppressonSink;
+
+ virtual void anchor();
public:
BugType(StringRef name, StringRef cat)
: Name(name), Category(cat), SuppressonSink(false) {}
- virtual ~BugType();
+ virtual ~BugType() {}
// FIXME: Should these be made strings as well?
StringRef getName() const { return Name; }
@@ -50,14 +53,14 @@ public:
};
class BuiltinBug : public BugType {
- virtual void anchor();
const std::string desc;
+ virtual void anchor();
public:
BuiltinBug(const char *name, const char *description)
- : BugType(name, "Logic error"), desc(description) {}
+ : BugType(name, categories::LogicError), desc(description) {}
BuiltinBug(const char *name)
- : BugType(name, "Logic error"), desc(name) {}
+ : BugType(name, categories::LogicError), desc(name) {}
StringRef getDescription() const { return desc; }
};
diff --git a/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 9d4251b1a757..3f0fe968cc11 100644
--- a/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -7,16 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H
-#define LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H
+#ifndef LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H
+#define LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H
// Common strings used for the "category" of many static analyzer issues.
namespace clang {
namespace ento {
namespace categories {
- extern const char *CoreFoundationObjectiveC;
- extern const char *MemoryCoreFoundationObjectiveC;
- extern const char *UnixAPI;
+ extern const char * const CoreFoundationObjectiveC;
+ extern const char * const LogicError;
+ extern const char * const MemoryCoreFoundationObjectiveC;
+ extern const char * const UnixAPI;
}
}
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index a80b5a7a248c..b0670dad240d 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -38,6 +38,7 @@ class ParentMap;
class ProgramPoint;
class SourceManager;
class Stmt;
+class CallExpr;
namespace ento {
@@ -97,7 +98,6 @@ public:
enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
- virtual bool supportsAllBlockEdges() const { return false; }
/// Return true if the PathDiagnosticConsumer supports individual
/// PathDiagnostics that span multiple files.
@@ -285,11 +285,13 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const;
+ void dump() const;
+
/// \brief Given an exploded node, retrieve the statement that should be used
/// for the diagnostic location.
static const Stmt *getStmt(const ExplodedNode *N);
- /// \brief Retrieve the statement corresponding to the sucessor node.
+ /// \brief Retrieve the statement corresponding to the successor node.
static const Stmt *getNextStmt(const ExplodedNode *N);
};
@@ -331,6 +333,10 @@ private:
const std::string str;
const Kind kind;
const DisplayHint Hint;
+
+ /// \brief In the containing bug report, this piece is the last piece from
+ /// the main source file.
+ bool LastInMainSourceFile;
/// A constant string that can be used to tag the PathDiagnosticPiece,
/// typically with the identification of the creator. The actual pointer
@@ -389,6 +395,16 @@ public:
ArrayRef<SourceRange> getRanges() const { return ranges; }
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ void setAsLastInMainSourceFile() {
+ LastInMainSourceFile = true;
+ }
+
+ bool isLastInMainSourceFile() const {
+ return LastInMainSourceFile;
+ }
+
+ virtual void dump() const = 0;
};
@@ -403,6 +419,8 @@ public:
flattenTo(Result, Result, ShouldFlattenMacros);
return Result;
}
+
+ LLVM_ATTRIBUTE_USED void dump() const;
};
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
@@ -421,7 +439,7 @@ public:
PathDiagnosticLocation getLocation() const { return Pos; }
virtual void flattenLocations() { Pos.flatten(); }
-
+
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
static bool classof(const PathDiagnosticPiece *P) {
@@ -504,7 +522,7 @@ public:
}
bool hasCallStackHint() {
- return (CallStackHint != 0);
+ return CallStackHint.isValid();
}
/// Produce the hint for the given node. The node contains
@@ -515,6 +533,8 @@ public:
return "";
}
+ virtual void dump() const;
+
static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Event;
}
@@ -582,6 +602,8 @@ public:
static PathDiagnosticCallPiece *construct(PathPieces &pieces,
const Decl *caller);
+ virtual void dump() const;
+
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
static inline bool classof(const PathDiagnosticPiece *P) {
@@ -649,7 +671,9 @@ public:
static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == ControlFlow;
}
-
+
+ virtual void dump() const;
+
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
@@ -673,7 +697,9 @@ public:
static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Macro;
}
-
+
+ virtual void dump() const;
+
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
@@ -687,7 +713,10 @@ class PathDiagnostic : public llvm::FoldingSetNode {
std::string ShortDesc;
std::string Category;
std::deque<std::string> OtherDesc;
+
+ /// \brief Loc The location of the path diagnostic report.
PathDiagnosticLocation Loc;
+
PathPieces pathImpl;
SmallVector<PathPieces *, 3> pathStack;
@@ -735,12 +764,23 @@ public:
getActivePath().push_back(EndPiece);
}
+ void appendToDesc(StringRef S) {
+ if (!ShortDesc.empty())
+ ShortDesc.append(S);
+ VerboseDesc.append(S);
+ }
+
void resetPath() {
pathStack.clear();
pathImpl.clear();
Loc = PathDiagnosticLocation();
}
-
+
+ /// \brief If the last piece of the report point to the header file, resets
+ /// the location of the report to be the last location in the main source
+ /// file.
+ void resetDiagnosticLocationToMainFile();
+
StringRef getVerboseDescription() const { return VerboseDesc; }
StringRef getShortDescription() const {
return ShortDesc.empty() ? VerboseDesc : ShortDesc;
@@ -759,7 +799,7 @@ public:
void addMeta(StringRef s) { OtherDesc.push_back(s); }
PathDiagnosticLocation getLocation() const {
- assert(Loc.isValid() && "No end-of-path location set yet!");
+ assert(Loc.isValid() && "No report location set yet!");
return Loc;
}
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 0dbaab033d2d..cf7cf051d225 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -320,18 +320,35 @@ public:
class PointerEscape {
template <typename CHECKER>
static ProgramStateRef
- _checkPointerEscape(void *checker,
+ _checkPointerEscape(void *Checker,
ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind,
- bool IsConst) {
- if (!IsConst)
- return ((const CHECKER *)checker)->checkPointerEscape(State,
+ RegionAndSymbolInvalidationTraits *ETraits) {
+
+ if (!ETraits)
+ return ((const CHECKER *)Checker)->checkPointerEscape(State,
Escaped,
Call,
Kind);
- return State;
+
+ InvalidatedSymbols RegularEscape;
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end(); I != E; ++I)
+ if (!ETraits->hasTrait(*I,
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
+ !ETraits->hasTrait(*I,
+ RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
+ RegularEscape.insert(*I);
+
+ if (RegularEscape.empty())
+ return State;
+
+ return ((const CHECKER *)Checker)->checkPointerEscape(State,
+ RegularEscape,
+ Call,
+ Kind);
}
public:
@@ -346,18 +363,32 @@ public:
class ConstPointerEscape {
template <typename CHECKER>
static ProgramStateRef
- _checkConstPointerEscape(void *checker,
+ _checkConstPointerEscape(void *Checker,
ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind,
- bool IsConst) {
- if (IsConst)
- return ((const CHECKER *)checker)->checkConstPointerEscape(State,
- Escaped,
- Call,
- Kind);
- return State;
+ RegionAndSymbolInvalidationTraits *ETraits) {
+
+ if (!ETraits)
+ return State;
+
+ InvalidatedSymbols ConstEscape;
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end(); I != E; ++I)
+ if (ETraits->hasTrait(*I,
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
+ !ETraits->hasTrait(*I,
+ RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
+ ConstEscape.insert(*I);
+
+ if (ConstEscape.empty())
+ return State;
+
+ return ((const CHECKER *)Checker)->checkConstPointerEscape(State,
+ ConstEscape,
+ Call,
+ Kind);
}
public:
@@ -502,10 +533,14 @@ struct ImplicitNullDerefEvent {
};
/// \brief A helper class which wraps a boolean value set to false by default.
+///
+/// This class should behave exactly like 'bool' except that it doesn't need to
+/// be explicitly initialized.
struct DefaultBool {
bool val;
DefaultBool() : val(false) {}
- operator bool() const { return val; }
+ /*implicit*/ operator bool&() { return val; }
+ /*implicit*/ operator const bool&() const { return val; }
DefaultBool &operator=(bool b) { val = b; return *this; }
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index b2411e6e6544..8ad67c118f01 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -19,7 +19,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallVector.h"
#include <vector>
@@ -366,14 +365,16 @@ public:
/// \param Escaped The list of escaped symbols.
/// \param Call The corresponding CallEvent, if the symbols escape as
/// parameters to the given call.
- /// \param IsConst Specifies if the pointer is const.
+ /// \param Kind The reason of pointer escape.
+ /// \param ITraits Information about invalidation for a particular
+ /// region/symbol.
/// \returns Checkers can modify the state by returning a new one.
ProgramStateRef
runCheckersForPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind,
- bool IsConst = false);
+ RegionAndSymbolInvalidationTraits *ITraits);
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
@@ -465,7 +466,7 @@ public:
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind,
- bool IsConst)>
+ RegionAndSymbolInvalidationTraits *ITraits)>
CheckPointerEscapeFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
@@ -581,35 +582,12 @@ private:
};
std::vector<StmtCheckerInfo> StmtCheckers;
- struct CachedStmtCheckersKey {
- unsigned StmtKind;
- bool IsPreVisit;
-
- CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { }
- CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit)
- : StmtKind(stmtKind), IsPreVisit(isPreVisit) { }
-
- static CachedStmtCheckersKey getSentinel() {
- return CachedStmtCheckersKey(~0U, 0);
- }
- unsigned getHashValue() const {
- llvm::FoldingSetNodeID ID;
- ID.AddInteger(StmtKind);
- ID.AddBoolean(IsPreVisit);
- return ID.ComputeHash();
- }
- bool operator==(const CachedStmtCheckersKey &RHS) const {
- return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit;
- }
- };
- friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>;
-
typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
- typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers>
- CachedStmtCheckersMapTy;
+ typedef llvm::DenseMap<unsigned, CachedStmtCheckers> CachedStmtCheckersMapTy;
CachedStmtCheckersMapTy CachedStmtCheckersMap;
- CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit);
+ const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S,
+ bool isPreVisit);
std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
@@ -659,30 +637,4 @@ private:
} // end clang namespace
-namespace llvm {
- /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key
- /// in DenseMap and DenseSets.
- template <>
- struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> {
- static inline clang::ento::CheckerManager::CachedStmtCheckersKey
- getEmptyKey() {
- return clang::ento::CheckerManager::CachedStmtCheckersKey();
- }
- static inline clang::ento::CheckerManager::CachedStmtCheckersKey
- getTombstoneKey() {
- return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel();
- }
-
- static unsigned
- getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) {
- return S.getHashValue();
- }
-
- static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS,
- clang::ento::CheckerManager::CachedStmtCheckersKey RHS) {
- return LHS == RHS;
- }
- };
-} // end namespace llvm
-
#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index 4557aa40ea80..ca68a74fef96 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -54,10 +54,6 @@
//
// For a complete working example, see examples/analyzer-plugin.
-
-namespace clang {
-namespace ento {
-
#ifndef CLANG_ANALYZER_API_VERSION_STRING
// FIXME: The Clang version string is not particularly granular;
// the analyzer infrastructure can change a lot between releases.
@@ -67,6 +63,9 @@ namespace ento {
#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING
#endif
+namespace clang {
+namespace ento {
+
class CheckerOptInfo;
/// Manages a set of available checkers for running a static analysis.
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index b856de7dc612..43e9166b3cdc 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -27,18 +27,12 @@ namespace ento {
class PathDiagnosticConsumer;
typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
-#define CREATE_CONSUMER(NAME)\
-void create ## NAME ## DiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,\
- PathDiagnosticConsumers &C,\
- const std::string& prefix,\
- const Preprocessor &PP);
-
-CREATE_CONSUMER(HTML)
-CREATE_CONSUMER(Plist)
-CREATE_CONSUMER(PlistMultiFile)
-CREATE_CONSUMER(TextPath)
-
-#undef CREATE_CONSUMER
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)\
+void CREATEFN(AnalyzerOptions &AnalyzerOpts,\
+ PathDiagnosticConsumers &C,\
+ const std::string &Prefix,\
+ const Preprocessor &PP);
+#include "clang/StaticAnalyzer/Core/Analyses.def"
} // end 'ento' namespace
} // end 'clang' namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 458c8966e79e..d7d83ce8b17d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -65,6 +65,10 @@ public:
StoreManagerCreator getStoreManagerCreator() {
return CreateStoreMgr;
}
+
+ AnalyzerOptions& getAnalyzerOptions() {
+ return options;
+ }
ConstraintManagerCreator getConstraintManagerCreator() {
return CreateConstraintMgr;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index f990b8dcd0ec..cfaf085b5f34 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -228,11 +228,6 @@ public:
return false;
}
- /// \brief Returns true if this is a call to a variadic function or method.
- virtual bool isVariadic() const {
- return false;
- }
-
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
@@ -341,6 +336,11 @@ public:
/// This will return a null QualType if the result type cannot be determined.
static QualType getDeclaredResultType(const Decl *D);
+ /// \brief Returns true if the given decl is known to be variadic.
+ ///
+ /// \p D must not be null.
+ static bool isVariadic(const Decl *D);
+
// Iterator access to formal parameters and their types.
private:
typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun;
@@ -350,19 +350,13 @@ public:
/// Returns an iterator over the call's formal parameters.
///
- /// If UseDefinitionParams is set, this will return the parameter decls
- /// used in the callee's definition (suitable for inlining). Most of the
- /// time it is better to use the decl found by name lookup, which likely
- /// carries more annotations.
- ///
/// Remember that the number of formal parameters may not match the number
/// of arguments for all calls. However, the first parameter will always
/// correspond with the argument value returned by \c getArgSVal(0).
///
- /// If the call has no accessible declaration (or definition, if
- /// \p UseDefinitionParams is set), \c param_begin() will be equal to
- /// \c param_end().
- virtual param_iterator param_begin() const =0;
+ /// If the call has no accessible declaration, \c param_begin() will be equal
+ /// to \c param_end().
+ virtual param_iterator param_begin() const = 0;
/// \sa param_begin()
virtual param_iterator param_end() const = 0;
@@ -423,10 +417,6 @@ public:
return RuntimeDefinition();
}
- virtual bool isVariadic() const {
- return getDecl()->isVariadic();
- }
-
virtual bool argumentsMayEscape() const;
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -527,10 +517,6 @@ public:
return RuntimeDefinition(getBlockDecl());
}
- virtual bool isVariadic() const {
- return getBlockDecl()->isVariadic();
- }
-
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const;
@@ -849,9 +835,6 @@ public:
virtual const Expr *getArgExpr(unsigned Index) const {
return getOriginExpr()->getArg(Index);
}
- virtual bool isVariadic() const {
- return getDecl()->isVariadic();
- }
bool isInstanceMessage() const {
return getOriginExpr()->isInstanceMessage();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index edcfc8a6c097..bf17cd807d65 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -184,7 +184,7 @@ public:
bool isSink() const { return Succs.getFlag(); }
- bool hasSinglePred() const {
+ bool hasSinglePred() const {
return (pred_size() == 1);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 33e4431eb4be..d89dffe63b0a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -203,6 +203,8 @@ public:
void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessDeleteDtor(const CFGDeleteDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
void ProcessBaseDtor(const CFGBaseDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void ProcessMemberDtor(const CFGMemberDtor D,
@@ -476,14 +478,14 @@ protected:
SVal Loc, SVal Val);
/// Call PointerEscape callback when a value escapes as a result of
/// region invalidation.
- /// \param[in] IsConst Specifies that the pointer is const.
+ /// \param[in] ITraits Specifies invalidation traits for regions/symbols.
ProgramStateRef notifyCheckersOfPointerEscape(
ProgramStateRef State,
const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call,
- bool IsConst);
+ RegionAndSymbolInvalidationTraits &ITraits);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 9b4f77dd679f..cc790c1b6b39 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -635,12 +635,14 @@ class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
const BlockTextRegion *BC;
const LocationContext *LC; // Can be null */
+ unsigned BlockCount;
void *ReferencedVars;
void *OriginalVars;
BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
- const MemRegion *sreg)
+ unsigned count, const MemRegion *sreg)
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ BlockCount(count),
ReferencedVars(0), OriginalVars(0) {}
public:
@@ -692,7 +694,8 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *,
- const LocationContext *, const MemRegion *);
+ const LocationContext *, unsigned,
+ const MemRegion *);
static bool classof(const MemRegion* R) {
return R->getKind() == BlockDataRegionKind;
@@ -1270,7 +1273,13 @@ public:
/// argument is allowed to be NULL for cases where we have no known
/// context.
const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
- const LocationContext *lc = NULL);
+ const LocationContext *lc,
+ unsigned blockCount);
+
+ /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended
+ /// by static references. This differs from getCXXTempObjectRegion in the
+ /// super-region used.
+ const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
private:
template <typename RegionTy, typename A1>
@@ -1304,6 +1313,39 @@ private:
inline ASTContext &MemRegion::getContext() const {
return getMemRegionManager()->getContext();
}
+
+//===----------------------------------------------------------------------===//
+// Means for storing region/symbol handling traits.
+//===----------------------------------------------------------------------===//
+
+/// Information about invalidation for a particular region/symbol.
+class RegionAndSymbolInvalidationTraits {
+ typedef unsigned char StorageTypeForKinds;
+ llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap;
+ llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap;
+
+ typedef llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator
+ const_region_iterator;
+ typedef llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator
+ const_symbol_iterator;
+
+public:
+ /// \brief Describes different invalidation traits.
+ enum InvalidationKinds {
+ /// Tells that a region's contents is not changed.
+ TK_PreserveContents = 0x1,
+ /// Suppress pointer-escaping of a region.
+ TK_SuppressEscape = 0x2
+
+ // Do not forget to extend StorageTypeForKinds if number of traits exceed
+ // the number of bits StorageTypeForKinds can store.
+ };
+
+ void setTrait(SymbolRef Sym, InvalidationKinds IK);
+ void setTrait(const MemRegion *MR, InvalidationKinds IK);
+ bool hasTrait(SymbolRef Sym, InvalidationKinds IK);
+ bool hasTrait(const MemRegion *MR, InvalidationKinds IK);
+};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 42ef1db45591..03739ed9284d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -232,22 +232,21 @@ public:
/// \param IS the set of invalidated symbols.
/// \param Call if non-null, the invalidated regions represent parameters to
/// the call and should be considered directly invalidated.
- /// \param ConstRegions the set of regions whose contents are accessible,
- /// even though the regions themselves should not be invalidated.
+ /// \param ITraits information about special handling for a particular
+ /// region/symbol.
ProgramStateRef
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
const CallEvent *Call = 0,
- ArrayRef<const MemRegion *> ConstRegions =
- ArrayRef<const MemRegion *>()) const;
+ RegionAndSymbolInvalidationTraits *ITraits = 0) const;
ProgramStateRef
invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
const CallEvent *Call = 0,
- ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const;
+ RegionAndSymbolInvalidationTraits *ITraits = 0) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
@@ -425,9 +424,9 @@ private:
const Expr *E, unsigned BlockCount,
const LocationContext *LCtx,
bool ResultsInSymbolEscape,
- InvalidatedSymbols &IS,
- const CallEvent *Call,
- ArrayRef<SVal> ConstValues) const;
+ InvalidatedSymbols *IS,
+ RegionAndSymbolInvalidationTraits *HTraits,
+ const CallEvent *Call) const;
};
//===----------------------------------------------------------------------===//
@@ -516,8 +515,8 @@ public:
public:
- SVal ArrayToPointer(Loc Array) {
- return StoreMgr->ArrayToPointer(Array);
+ SVal ArrayToPointer(Loc Array, QualType ElementTy) {
+ return StoreMgr->ArrayToPointer(Array, ElementTy);
}
// Methods that manipulate the GDM.
@@ -798,7 +797,7 @@ CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
/// A Utility class that allows to visit the reachable symbols using a custom
/// SymbolVisitor.
class ScanReachableSymbols {
- typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
+ typedef llvm::DenseSet<const void*> VisitedItems;
VisitedItems visited;
ProgramStateRef state;
@@ -808,6 +807,7 @@ public:
ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v)
: state(st), visitor(v) {}
+ bool scan(nonloc::LazyCompoundVal val);
bool scan(nonloc::CompoundVal val);
bool scan(SVal val);
bool scan(const MemRegion *R);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index bbb56885af04..c5d0a92cabdd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -200,7 +200,8 @@ public:
DefinedSVal getFunctionPointer(const FunctionDecl *func);
DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
- const LocationContext *locContext);
+ const LocationContext *locContext,
+ unsigned blockCount);
/// Returns the value of \p E, if it can be determined in a non-path-sensitive
/// manner.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 326e784e83d4..5a426ef00197 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -290,7 +290,7 @@ public:
static inline bool isLocType(QualType T) {
return T->isAnyPointerType() || T->isBlockPointerType() ||
- T->isReferenceType();
+ T->isReferenceType() || T->isNullPtrType();
}
private:
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index b219495d5f06..530dae59892a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -111,7 +111,7 @@ public:
/// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
- virtual SVal ArrayToPointer(Loc Array) = 0;
+ virtual SVal ArrayToPointer(Loc Array, QualType ElementTy) = 0;
/// Evaluates a chain of derived-to-base casts through the path specified in
/// \p Cast.
@@ -164,8 +164,6 @@ public:
/// the given regions. Optionally, invalidates non-static globals as well.
/// \param[in] store The initial store
/// \param[in] Values The values to invalidate.
- /// \param[in] ConstValues The values to invalidate; these are known to be
- /// const, so only regions accesible from them should be invalidated.
/// \param[in] E The current statement being evaluated. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Count The current block count. Used to conjure
@@ -174,13 +172,10 @@ public:
/// globals should get invalidated.
/// \param[in,out] IS A set to fill with any symbols that are no longer
/// accessible. Pass \c NULL if this information will not be used.
- /// \param[in,out] ConstIS A set to fill with any symbols corresponding to
- /// the ConstValues.
+ /// \param[in] ITraits Information about invalidation for a particular
+ /// region/symbol.
/// \param[in,out] InvalidatedTopLevel A vector to fill with regions
- //// explicitely being invalidated. Pass \c NULL if this
- /// information will not be used.
- /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const
- //// regions explicitely being invalidated. Pass \c NULL if this
+ //// explicitly being invalidated. Pass \c NULL if this
/// information will not be used.
/// \param[in,out] Invalidated A vector to fill with any regions being
/// invalidated. This should include any regions explicitly invalidated
@@ -188,14 +183,12 @@ public:
/// information will not be used.
virtual StoreRef invalidateRegions(Store store,
ArrayRef<SVal> Values,
- ArrayRef<SVal> ConstValues,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
const CallEvent *Call,
InvalidatedSymbols &IS,
- InvalidatedSymbols &ConstIS,
+ RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *InvalidatedTopLevel,
- InvalidatedRegions *InvalidatedTopLevelConst,
InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
@@ -231,7 +224,7 @@ public:
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
SVal val);
- operator bool() { return First && Binding; }
+ LLVM_EXPLICIT operator bool() { return First && Binding; }
const MemRegion *getRegion() { return Binding; }
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index d4100634a785..f653c70a30f3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -134,7 +134,7 @@ public:
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call,
- bool IsConst = false) = 0;
+ RegionAndSymbolInvalidationTraits &HTraits) = 0;
/// printState - Called by ProgramStateManager to print checker-specific data.
virtual void printState(raw_ostream &Out, ProgramStateRef State,
diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h
index 492ddd2b0078..71acef8650fe 100644
--- a/include/clang/Tooling/ArgumentsAdjusters.h
+++ b/include/clang/Tooling/ArgumentsAdjusters.h
@@ -52,6 +52,12 @@ class ClangSyntaxOnlyAdjuster : public ArgumentsAdjuster {
virtual CommandLineArguments Adjust(const CommandLineArguments &Args);
};
+/// \brief An argument adjuster which removes output-related command line
+/// arguments.
+class ClangStripOutputAdjuster : public ArgumentsAdjuster {
+ virtual CommandLineArguments Adjust(const CommandLineArguments &Args);
+};
+
} // end namespace tooling
} // end namespace clang
diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h
index 677593413948..eaffe4363515 100644
--- a/include/clang/Tooling/CommonOptionsParser.h
+++ b/include/clang/Tooling/CommonOptionsParser.h
@@ -64,7 +64,7 @@ public:
/// This constructor can change argc and argv contents, e.g. consume
/// command-line options used for creating FixedCompilationDatabase.
/// This constructor exits program in case of error.
- CommonOptionsParser(int &argc, const char **argv);
+ CommonOptionsParser(int &argc, const char **argv, const char *Overview = 0);
/// Returns a reference to the loaded compilations database.
CompilationDatabase &getCompilations() {
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index 7a8054ffc3a4..8cca3296f94d 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -50,6 +50,16 @@ struct CompileCommand {
/// \brief The command line that was executed.
std::vector<std::string> CommandLine;
+
+ /// \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.
@@ -108,6 +118,10 @@ public:
/// \brief Returns all compile commands for all the files in the compilation
/// database.
+ ///
+ /// FIXME: Add a layer in Tooling that provides an interface to run a tool
+ /// over all files in a compilation database. Not all build systems have the
+ /// ability to provide a feasible implementation for \c getAllCompileCommands.
virtual std::vector<CompileCommand> getAllCompileCommands() const = 0;
};
diff --git a/include/clang/Tooling/Refactoring.h b/include/clang/Tooling/Refactoring.h
index 079ce7420db9..43ec9acdb3bf 100644
--- a/include/clang/Tooling/Refactoring.h
+++ b/include/clang/Tooling/Refactoring.h
@@ -32,6 +32,37 @@ class SourceLocation;
namespace tooling {
+/// \brief A source range independent of the \c SourceManager.
+class Range {
+public:
+ Range() : Offset(0), Length(0) {}
+ Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
+
+ /// \brief Accessors.
+ /// @{
+ unsigned getOffset() const { return Offset; }
+ unsigned getLength() const { return Length; }
+ /// @}
+
+ /// \name Range Predicates
+ /// @{
+ /// \brief Whether this range overlaps with \p RHS or not.
+ bool overlapsWith(Range RHS) const {
+ return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
+ }
+
+ /// \brief Whether this range contains \p RHS or not.
+ bool contains(Range RHS) const {
+ return RHS.Offset >= Offset &&
+ (RHS.Offset + RHS.Length) <= (Offset + Length);
+ }
+ /// @}
+
+private:
+ unsigned Offset;
+ unsigned Length;
+};
+
/// \brief A text replacement.
///
/// Represents a SourceManager independent replacement of a range of text in a
@@ -72,8 +103,8 @@ public:
/// \brief Accessors.
/// @{
StringRef getFilePath() const { return FilePath; }
- unsigned getOffset() const { return Offset; }
- unsigned getLength() const { return Length; }
+ unsigned getOffset() const { return ReplacementRange.getOffset(); }
+ unsigned getLength() const { return ReplacementRange.getLength(); }
StringRef getReplacementText() const { return ReplacementText; }
/// @}
@@ -83,12 +114,6 @@ public:
/// \brief Returns a human readable string representation.
std::string toString() const;
- /// \brief Comparator to be able to use Replacement in std::set for uniquing.
- class Less {
- public:
- bool operator()(const Replacement &R1, const Replacement &R2) const;
- };
-
private:
void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
unsigned Length, StringRef ReplacementText);
@@ -96,14 +121,27 @@ public:
StringRef ReplacementText);
std::string FilePath;
- unsigned Offset;
- unsigned Length;
+ Range ReplacementRange;
std::string ReplacementText;
};
+/// \brief Less-than operator between two Replacements.
+bool operator<(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief Equal-to operator between two Replacements.
+bool operator==(const Replacement &LHS, const Replacement &RHS);
+
/// \brief A set of Replacements.
/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
-typedef std::set<Replacement, Replacement::Less> Replacements;
+typedef std::set<Replacement> Replacements;
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
///
@@ -111,7 +149,48 @@ typedef std::set<Replacement, Replacement::Less> Replacements;
/// other applications.
///
/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite);
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+ Rewriter &Rewrite);
+
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+///
+/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+ unsigned Position);
+
+/// \brief Removes duplicate Replacements and reports if Replacements conflict
+/// with one another.
+///
+/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+///
+/// This function sorts \p Replaces so that conflicts can be reported simply by
+/// offset into \p Replaces and number of elements in the conflict.
+void deduplicate(std::vector<Replacement> &Replaces,
+ std::vector<Range> &Conflicts);
+
+/// \brief Collection of Replacements generated from a single translation unit.
+struct TranslationUnitReplacements {
+ /// Name of the main source for the translation unit.
+ std::string MainSourceFile;
+
+ /// A freeform chunk of text to describe the context of the replacements.
+ /// Will be printed, for example, when detecting conflicts during replacement
+ /// deduplication.
+ std::string Context;
+
+ std::vector<Replacement> Replacements;
+};
/// \brief A tool to run refactorings.
///
diff --git a/include/clang/Tooling/ReplacementsYaml.h b/include/clang/Tooling/ReplacementsYaml.h
new file mode 100644
index 000000000000..18d3259d7058
--- /dev/null
+++ b/include/clang/Tooling/ReplacementsYaml.h
@@ -0,0 +1,88 @@
+//===-- ReplacementsYaml.h -- Serialiazation for Replacements ---*- 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 defines the structure of a YAML document for serializing
+/// replacements.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
+#define LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
+
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <vector>
+#include <string>
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::Replacement)
+
+namespace llvm {
+namespace yaml {
+
+/// \brief ScalarTraits to read/write std::string objects.
+template <> struct ScalarTraits<std::string> {
+ static void output(const std::string &Val, void *, llvm::raw_ostream &Out) {
+ Out << Val;
+ }
+
+ static StringRef input(StringRef Scalar, void *, std::string &Val) {
+ Val = Scalar;
+ return StringRef();
+ }
+};
+
+/// \brief Specialized MappingTraits to describe how a Replacement is
+/// (de)serialized.
+template <> struct MappingTraits<clang::tooling::Replacement> {
+ /// \brief Helper to (de)serialize a Replacement since we don't have direct
+ /// access to its data members.
+ struct NormalizedReplacement {
+ NormalizedReplacement(const IO &)
+ : FilePath(""), Offset(0), Length(0), ReplacementText("") {}
+
+ NormalizedReplacement(const IO &, const clang::tooling::Replacement &R)
+ : FilePath(R.getFilePath()), Offset(R.getOffset()),
+ Length(R.getLength()), ReplacementText(R.getReplacementText()) {}
+
+ clang::tooling::Replacement denormalize(const IO &) {
+ return clang::tooling::Replacement(FilePath, Offset, Length,
+ ReplacementText);
+ }
+
+ std::string FilePath;
+ unsigned int Offset;
+ unsigned int Length;
+ std::string ReplacementText;
+ };
+
+ static void mapping(IO &Io, clang::tooling::Replacement &R) {
+ MappingNormalization<NormalizedReplacement, clang::tooling::Replacement>
+ Keys(Io, R);
+ Io.mapRequired("FilePath", Keys->FilePath);
+ Io.mapRequired("Offset", Keys->Offset);
+ Io.mapRequired("Length", Keys->Length);
+ Io.mapRequired("ReplacementText", Keys->ReplacementText);
+ }
+};
+
+/// \brief Specialized MappingTraits to describe how a
+/// TranslationUnitReplacements is (de)serialized.
+template <> struct MappingTraits<clang::tooling::TranslationUnitReplacements> {
+ static void mapping(IO &Io,
+ clang::tooling::TranslationUnitReplacements &Doc) {
+ Io.mapRequired("MainSourceFile", Doc.MainSourceFile);
+ Io.mapOptional("Context", Doc.Context, std::string());
+ Io.mapRequired("Replacements", Doc.Replacements);
+ }
+};
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 27e5a0af2573..de507a7a8b25 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -30,6 +30,7 @@
#ifndef LLVM_CLANG_TOOLING_TOOLING_H
#define LLVM_CLANG_TOOLING_TOOLING_H
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Util.h"
@@ -53,11 +54,34 @@ class FrontendAction;
namespace tooling {
+/// \brief Interface to process a clang::CompilerInvocation.
+///
+/// If your tool is based on FrontendAction, you should be deriving from
+/// FrontendActionFactory instead.
+class ToolAction {
+public:
+ virtual ~ToolAction();
+
+ /// \brief Perform an action for an invocation.
+ virtual bool runInvocation(clang::CompilerInvocation *Invocation,
+ FileManager *Files,
+ DiagnosticConsumer *DiagConsumer) = 0;
+};
+
/// \brief Interface to generate clang::FrontendActions.
-class FrontendActionFactory {
+///
+/// Having a factory interface allows, for example, a new FrontendAction to be
+/// created for each translation unit processed by ClangTool. This class is
+/// also a ToolAction which uses the FrontendActions created by create() to
+/// process each translation unit.
+class FrontendActionFactory : public ToolAction {
public:
virtual ~FrontendActionFactory();
+ /// \brief Invokes the compiler with a FrontendAction created by create().
+ bool runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files,
+ DiagnosticConsumer *DiagConsumer);
+
/// \brief Returns a new clang::FrontendAction.
///
/// The caller takes ownership of the returned action.
@@ -66,7 +90,7 @@ public:
/// \brief Returns a new FrontendActionFactory for a given type.
///
-/// T must extend clang::FrontendAction.
+/// T must derive from clang::FrontendAction.
///
/// Example:
/// FrontendActionFactory *Factory =
@@ -74,12 +98,22 @@ public:
template <typename T>
FrontendActionFactory *newFrontendActionFactory();
-/// \brief Called at the end of each source file when used with
-/// \c newFrontendActionFactory.
-class EndOfSourceFileCallback {
+/// \brief Callbacks called before and after each source file processed by a
+/// FrontendAction created by the FrontedActionFactory returned by \c
+/// newFrontendActionFactory.
+class SourceFileCallbacks {
public:
- virtual ~EndOfSourceFileCallback() {}
- virtual void run() = 0;
+ virtual ~SourceFileCallbacks() {}
+
+ /// \brief Called before a source file is processed by a FrontEndAction.
+ /// \see clang::FrontendAction::BeginSourceFileAction
+ virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) {
+ return true;
+ }
+
+ /// \brief Called after a source file is processed by a FrontendAction.
+ /// \see clang::FrontendAction::EndSourceFileAction
+ virtual void handleEndSource() {}
};
/// \brief Returns a new FrontendActionFactory for any type that provides an
@@ -95,7 +129,7 @@ public:
/// newFrontendActionFactory(&Factory);
template <typename FactoryT>
inline FrontendActionFactory *newFrontendActionFactory(
- FactoryT *ConsumerFactory, EndOfSourceFileCallback *EndCallback = NULL);
+ FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks = NULL);
/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag.
///
@@ -120,6 +154,26 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
const std::vector<std::string> &Args,
const Twine &FileName = "input.cc");
+/// \brief Builds an AST for 'Code'.
+///
+/// \param Code C++ code.
+/// \param FileName The file name which 'Code' will be mapped as.
+///
+/// \return The resulting AST or null if an error occurred.
+ASTUnit *buildASTFromCode(const Twine &Code,
+ const Twine &FileName = "input.cc");
+
+/// \brief Builds an AST for 'Code' with additional flags.
+///
+/// \param Code C++ code.
+/// \param Args Additional flags to pass on.
+/// \param FileName The file name which 'Code' will be mapped as.
+///
+/// \return The resulting AST or null if an error occurred.
+ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName = "input.cc");
+
/// \brief Utility to run a FrontendAction in a single clang invocation.
class ToolInvocation {
public:
@@ -129,12 +183,25 @@ class ToolInvocation {
/// uses its binary name (CommandLine[0]) to locate its builtin headers.
/// Callers have to ensure that they are installed in a compatible location
/// (see clang driver implementation) or mapped in via mapVirtualFile.
- /// \param ToolAction The action to be executed. Class takes ownership.
+ /// \param FAction The action to be executed. Class takes ownership.
/// \param Files The FileManager used for the execution. Class does not take
/// ownership.
- ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,
+ ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *FAction,
+ FileManager *Files);
+
+ /// \brief Create a tool invocation.
+ ///
+ /// \param CommandLine The command line arguments to clang.
+ /// \param Action The action to be executed.
+ /// \param Files The FileManager used for the execution.
+ ToolInvocation(ArrayRef<std::string> CommandLine, ToolAction *Action,
FileManager *Files);
+ ~ToolInvocation();
+
+ /// \brief Set a \c DiagnosticConsumer to use during parsing.
+ void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer);
+
/// \brief Map a virtual file to be used while running the tool.
///
/// \param FilePath The path at which the content will be mapped.
@@ -154,10 +221,12 @@ class ToolInvocation {
clang::CompilerInvocation *Invocation);
std::vector<std::string> CommandLine;
- OwningPtr<FrontendAction> ToolAction;
+ ToolAction *Action;
+ bool OwnsAction;
FileManager *Files;
// Maps <file name> -> <file content>.
llvm::StringMap<StringRef> MappedFileContents;
+ DiagnosticConsumer *DiagConsumer;
};
/// \brief Utility to run a FrontendAction over a set of files.
@@ -165,8 +234,8 @@ class ToolInvocation {
/// This class is written to be usable for command line utilities.
/// By default the class uses ClangSyntaxOnlyAdjuster to modify
/// command line arguments before the arguments are used to run
-/// a frontend action. One could install another command line
-/// arguments adjuster by call setArgumentsAdjuster() method.
+/// a frontend action. One could install an additional command line
+/// arguments adjuster by calling the appendArgumentsAdjuster() method.
class ClangTool {
public:
/// \brief Constructs a clang tool to run over a list of files.
@@ -178,7 +247,10 @@ class ClangTool {
ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths);
- virtual ~ClangTool() {}
+ virtual ~ClangTool() { clearArgumentsAdjusters(); }
+
+ /// \brief Set a \c DiagnosticConsumer to use during parsing.
+ void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer);
/// \brief Map a virtual file to be used while running the tool.
///
@@ -189,29 +261,45 @@ class ClangTool {
/// \brief Install command line arguments adjuster.
///
/// \param Adjuster Command line arguments adjuster.
+ //
+ /// FIXME: Function is deprecated. Use (clear/append)ArgumentsAdjuster instead.
+ /// Remove it once all callers are gone.
void setArgumentsAdjuster(ArgumentsAdjuster *Adjuster);
- /// Runs a frontend action over all files specified in the command line.
+ /// \brief Append a command line arguments adjuster to the adjuster chain.
+ ///
+ /// \param Adjuster An argument adjuster, which will be run on the output of
+ /// previous argument adjusters.
+ void appendArgumentsAdjuster(ArgumentsAdjuster *Adjuster);
+
+ /// \brief Clear the command line arguments adjuster chain.
+ void clearArgumentsAdjusters();
+
+ /// Runs an action over all files specified in the command line.
///
- /// \param ActionFactory Factory generating the frontend actions. The function
- /// takes ownership of this parameter. A new action is generated for every
- /// processed translation unit.
- virtual int run(FrontendActionFactory *ActionFactory);
+ /// \param Action Tool action.
+ int run(ToolAction *Action);
+
+ /// \brief Create an AST for each file specified in the command line and
+ /// append them to ASTs.
+ int buildASTs(std::vector<ASTUnit *> &ASTs);
/// \brief Returns the file manager used in the tool.
///
/// The file manager is shared between all translation units.
- FileManager &getFiles() { return Files; }
+ FileManager &getFiles() { return *Files; }
private:
// We store compile commands as pair (file name, compile command).
std::vector< std::pair<std::string, CompileCommand> > CompileCommands;
- FileManager Files;
+ llvm::IntrusiveRefCntPtr<FileManager> Files;
// Contains a list of pairs (<file name>, <file content>).
std::vector< std::pair<StringRef, StringRef> > MappedFileContents;
- OwningPtr<ArgumentsAdjuster> ArgsAdjuster;
+ SmallVector<ArgumentsAdjuster *, 2> ArgsAdjusters;
+
+ DiagnosticConsumer *DiagConsumer;
};
template <typename T>
@@ -226,23 +314,23 @@ FrontendActionFactory *newFrontendActionFactory() {
template <typename FactoryT>
inline FrontendActionFactory *newFrontendActionFactory(
- FactoryT *ConsumerFactory, EndOfSourceFileCallback *EndCallback) {
+ FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks) {
class FrontendActionFactoryAdapter : public FrontendActionFactory {
public:
explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory,
- EndOfSourceFileCallback *EndCallback)
- : ConsumerFactory(ConsumerFactory), EndCallback(EndCallback) {}
+ SourceFileCallbacks *Callbacks)
+ : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
virtual clang::FrontendAction *create() {
- return new ConsumerFactoryAdaptor(ConsumerFactory, EndCallback);
+ return new ConsumerFactoryAdaptor(ConsumerFactory, Callbacks);
}
private:
class ConsumerFactoryAdaptor : public clang::ASTFrontendAction {
public:
ConsumerFactoryAdaptor(FactoryT *ConsumerFactory,
- EndOfSourceFileCallback *EndCallback)
- : ConsumerFactory(ConsumerFactory), EndCallback(EndCallback) {}
+ SourceFileCallbacks *Callbacks)
+ : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &,
StringRef) {
@@ -250,21 +338,29 @@ inline FrontendActionFactory *newFrontendActionFactory(
}
protected:
- virtual void EndSourceFileAction() {
- if (EndCallback != NULL)
- EndCallback->run();
+ virtual bool BeginSourceFileAction(CompilerInstance &CI,
+ StringRef Filename) LLVM_OVERRIDE {
+ if (!clang::ASTFrontendAction::BeginSourceFileAction(CI, Filename))
+ return false;
+ if (Callbacks != NULL)
+ return Callbacks->handleBeginSource(CI, Filename);
+ return true;
+ }
+ virtual void EndSourceFileAction() LLVM_OVERRIDE {
+ if (Callbacks != NULL)
+ Callbacks->handleEndSource();
clang::ASTFrontendAction::EndSourceFileAction();
}
private:
FactoryT *ConsumerFactory;
- EndOfSourceFileCallback *EndCallback;
+ SourceFileCallbacks *Callbacks;
};
FactoryT *ConsumerFactory;
- EndOfSourceFileCallback *EndCallback;
+ SourceFileCallbacks *Callbacks;
};
- return new FrontendActionFactoryAdapter(ConsumerFactory, EndCallback);
+ return new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks);
}
/// \brief Returns the absolute path of \c File, by prepending it with
@@ -275,10 +371,8 @@ inline FrontendActionFactory *newFrontendActionFactory(
/// Otherwise, the returned path will contain the literal path-concatenation of
/// the current directory and \c File.
///
-/// The difference to llvm::sys::fs::make_absolute is that we prefer
-/// ::getenv("PWD") if available.
-/// FIXME: Make this functionality available from llvm::sys::fs and delete
-/// this function.
+/// The difference to llvm::sys::fs::make_absolute is the canonicalization this
+/// does by removing "./" and computing native paths.
///
/// \param File Either an absolute or relative path.
std::string getAbsolutePath(StringRef File);
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index a6d48762fe55..3e429beded5d 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -150,7 +150,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
// and avoid unrelated complications.
llvm::Triple triple(origCI.getTargetOpts().Triple);
- if (triple.getOS() == llvm::Triple::IOS)
+ if (triple.isiOS())
return triple.getOSMajorVersion() >= 5;
if (triple.getOS() == llvm::Triple::Darwin)
@@ -321,10 +321,6 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
DiagClient->EndSourceFile();
errRec.FinishCapture();
- // If we are migrating code that gets the '-fobjc-arc' flag, make sure
- // to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts()->ObjCAutoRefCount = false;
-
return capturedDiags.hasErrors() || testAct.hasReportedErrors();
}
@@ -374,9 +370,6 @@ static bool applyTransforms(CompilerInvocation &origCI,
origCI.getLangOpts()->ObjCAutoRefCount = true;
return migration.getRemapper().overwriteOriginal(*Diags);
} else {
- // If we are migrating code that gets the '-fobjc-arc' flag, make sure
- // to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts()->ObjCAutoRefCount = false;
return migration.getRemapper().flushToDisk(outputDir, *Diags);
}
}
@@ -545,7 +538,7 @@ MigrationProcess::RewriteListener::~RewriteListener() { }
MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
DiagnosticConsumer *diagClient,
StringRef outputDir)
- : OrigCI(CI), DiagClient(diagClient) {
+ : OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) {
if (!outputDir.empty()) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
@@ -588,6 +581,8 @@ bool MigrationProcess::applyTransform(TransformFn trans,
}
Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
+ HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
+
// Don't filter diagnostics anymore.
Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index da51d6db83b8..c55261277dd1 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -40,4 +40,5 @@ target_link_libraries(clangARCMigrate
clangFrontend
clangRewriteCore
clangRewriteFrontend
+ clangStaticAnalyzerCheckers
)
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 6a8686c4ff0f..a14226e43fe0 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -43,10 +43,9 @@ void FileRemapper::clear(StringRef outputDir) {
std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
assert(!outputDir.empty());
- llvm::sys::Path dir(outputDir);
- llvm::sys::Path infoFile = dir;
- infoFile.appendComponent("remap");
- return infoFile.str();
+ SmallString<128> InfoFile = outputDir;
+ llvm::sys::path::append(InfoFile, "remap");
+ return InfoFile.str();
}
bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
@@ -127,7 +126,7 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
std::string errMsg;
std::string infoFile = outputPath;
llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
- llvm::raw_fd_ostream::F_Binary);
+ llvm::sys::fs::F_Binary);
if (!errMsg.empty())
return report(errMsg, Diag);
@@ -147,11 +146,10 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
} else {
SmallString<64> tempPath;
- tempPath = path::filename(origFE->getName());
- tempPath += "-%%%%%%%%";
- tempPath += path::extension(origFE->getName());
int fd;
- if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success)
+ if (fs::createTemporaryFile(path::filename(origFE->getName()),
+ path::extension(origFE->getName()), fd,
+ tempPath))
return report("Could not create file: " + tempPath.str(), Diag);
llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true);
@@ -176,29 +174,22 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
for (MappingsTy::iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
- if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) {
- if (fs::copy_file(newFE->getName(), origFE->getName(),
- fs::copy_option::overwrite_if_exists) != llvm::errc::success)
- return report(StringRef("Could not copy file '") + newFE->getName() +
- "' to file '" + origFE->getName() + "'", Diag);
- } else {
-
- bool fileExists = false;
- fs::exists(origFE->getName(), fileExists);
- if (!fileExists)
- return report(StringRef("File does not exist: ") + origFE->getName(),
- Diag);
+ assert(I->second.is<llvm::MemoryBuffer *>());
+ bool fileExists = false;
+ fs::exists(origFE->getName(), fileExists);
+ if (!fileExists)
+ return report(StringRef("File does not exist: ") + origFE->getName(),
+ Diag);
- std::string errMsg;
- llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
- llvm::raw_fd_ostream::F_Binary);
- if (!errMsg.empty())
- return report(errMsg, Diag);
+ std::string errMsg;
+ llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
+ llvm::sys::fs::F_Binary);
+ if (!errMsg.empty())
+ return report(errMsg, Diag);
- llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
- Out.write(mem->getBufferStart(), mem->getBufferSize());
- Out.close();
- }
+ llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+ Out.write(mem->getBufferStart(), mem->getBufferSize());
+ Out.close();
}
clear(outputDir);
@@ -239,12 +230,6 @@ void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) {
remap(getOriginalFile(filePath), memBuf);
}
-void FileRemapper::remap(StringRef filePath, StringRef newPath) {
- const FileEntry *file = getOriginalFile(filePath);
- const FileEntry *newfile = FileMgr->getFile(newPath);
- remap(file, newfile);
-}
-
void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) {
assert(file);
Target &targ = FromToMappings[file];
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 57fac0389fc3..cac0fb0aed1b 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "Transforms.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,46 +24,101 @@
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
+#include "clang/AST/Attr.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
using namespace clang;
using namespace arcmt;
+using namespace ento::objc_retain;
namespace {
class ObjCMigrateASTConsumer : public ASTConsumer {
+ enum CF_BRIDGING_KIND {
+ CF_BRIDGING_NONE,
+ CF_BRIDGING_ENABLE,
+ CF_BRIDGING_MAY_INCLUDE
+ };
+
void migrateDecl(Decl *D);
-
+ void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
+ void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl);
+ void migrateProtocolConformance(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl);
+ void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
+ bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl);
+ void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
+ void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM);
+ bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
+ void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
+ void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
+ void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM,
+ ObjCInstanceTypeFamily OIT_Family = OIT_None);
+
+ void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
+ void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
+ const FunctionDecl *FuncDecl, bool ResultAnnotated);
+ void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
+ const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
+
+ void AnnotateImplicitBridging(ASTContext &Ctx);
+
+ CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
+ const FunctionDecl *FuncDecl);
+
+ void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
+
+ void migrateAddMethodAnnotation(ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl);
public:
std::string MigrateDir;
- bool MigrateLiterals;
- bool MigrateSubscripting;
+ unsigned ASTMigrateActions;
+ FileID FileId;
+ const TypedefDecl *NSIntegerTypedefed;
+ const TypedefDecl *NSUIntegerTypedefed;
OwningPtr<NSAPI> NSAPIObj;
OwningPtr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
const PPConditionalDirectiveRecord *PPRec;
+ Preprocessor &PP;
bool IsOutputFile;
-
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
+ llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
+ llvm::StringMap<char> WhiteListFilenames;
+
ObjCMigrateASTConsumer(StringRef migrateDir,
- bool migrateLiterals,
- bool migrateSubscripting,
+ unsigned astMigrateActions,
FileRemapper &remapper,
FileManager &fileMgr,
const PPConditionalDirectiveRecord *PPRec,
- bool isOutputFile = false)
+ Preprocessor &PP,
+ bool isOutputFile,
+ ArrayRef<std::string> WhiteList)
: MigrateDir(migrateDir),
- MigrateLiterals(migrateLiterals),
- MigrateSubscripting(migrateSubscripting),
- Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec),
- IsOutputFile(isOutputFile) { }
+ ASTMigrateActions(astMigrateActions),
+ NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
+ Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
+ IsOutputFile(isOutputFile) {
+
+ for (ArrayRef<std::string>::iterator
+ I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) {
+ WhiteListFilenames.GetOrCreateValue(*I);
+ }
+ }
protected:
virtual void Initialize(ASTContext &Context) {
NSAPIObj.reset(new NSAPI(Context));
Editor.reset(new edit::EditedSource(Context.getSourceManager(),
Context.getLangOpts(),
- PPRec));
+ PPRec, false));
}
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -78,16 +134,22 @@ protected:
}
virtual void HandleTranslationUnit(ASTContext &Ctx);
+
+ bool canModifyFile(StringRef Path) {
+ if (WhiteListFilenames.empty())
+ return true;
+ return WhiteListFilenames.find(llvm::sys::path::filename(Path))
+ != WhiteListFilenames.end();
+ }
};
}
ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
- StringRef migrateDir,
- bool migrateLiterals,
- bool migrateSubscripting)
+ StringRef migrateDir,
+ unsigned migrateAction)
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
- MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
+ ObjCMigAction(migrateAction),
CompInst(0) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
@@ -101,11 +163,13 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *
WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
- MigrateLiterals,
- MigrateSubscripting,
+ ObjCMigAction,
Remapper,
CompInst->getFileManager(),
- PPRec);
+ PPRec,
+ CompInst->getPreprocessor(),
+ false,
+ ArrayRef<std::string>());
ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
return new MultiplexConsumer(Consumers);
}
@@ -131,13 +195,13 @@ public:
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (Consumer.MigrateLiterals) {
+ if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
edit::Commit commit(*Consumer.Editor);
edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Consumer.Editor->commit(commit);
}
- if (Consumer.MigrateSubscripting) {
+ if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
edit::Commit commit(*Consumer.Editor);
edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
Consumer.Editor->commit(commit);
@@ -184,6 +248,1322 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
BodyMigrator(*this).TraverseDecl(D);
}
+static void append_attr(std::string &PropertyString, const char *attr,
+ bool &LParenAdded) {
+ if (!LParenAdded) {
+ PropertyString += "(";
+ LParenAdded = true;
+ }
+ else
+ PropertyString += ", ";
+ PropertyString += attr;
+}
+
+static
+void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
+ const std::string& TypeString,
+ const char *name) {
+ const char *argPtr = TypeString.c_str();
+ int paren = 0;
+ while (*argPtr) {
+ switch (*argPtr) {
+ case '(':
+ PropertyString += *argPtr;
+ paren++;
+ break;
+ case ')':
+ PropertyString += *argPtr;
+ paren--;
+ break;
+ case '^':
+ case '*':
+ PropertyString += (*argPtr);
+ if (paren == 1) {
+ PropertyString += name;
+ name = "";
+ }
+ break;
+ default:
+ PropertyString += *argPtr;
+ break;
+ }
+ argPtr++;
+ }
+}
+
+static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
+ Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
+ bool RetainableObject = ArgType->isObjCRetainableType();
+ if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
+ if (const ObjCObjectPointerType *ObjPtrTy =
+ ArgType->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
+ if (IDecl &&
+ IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
+ return "copy";
+ else
+ return "retain";
+ }
+ else if (ArgType->isBlockPointerType())
+ return "copy";
+ } else if (propertyLifetime == Qualifiers::OCL_Weak)
+ // TODO. More precise determination of 'weak' attribute requires
+ // looking into setter's implementation for backing weak ivar.
+ return "weak";
+ else if (RetainableObject)
+ return ArgType->isBlockPointerType() ? "copy" : "retain";
+ return 0;
+}
+
+static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
+ const ObjCMethodDecl *Setter,
+ const NSAPI &NS, edit::Commit &commit,
+ unsigned LengthOfPrefix,
+ bool Atomic, bool UseNsIosOnlyMacro,
+ bool AvailabilityArgsMatch) {
+ ASTContext &Context = NS.getASTContext();
+ bool LParenAdded = false;
+ std::string PropertyString = "@property ";
+ if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) {
+ PropertyString += "(NS_NONATOMIC_IOSONLY";
+ LParenAdded = true;
+ } else if (!Atomic) {
+ PropertyString += "(nonatomic";
+ LParenAdded = true;
+ }
+
+ std::string PropertyNameString = Getter->getNameAsString();
+ StringRef PropertyName(PropertyNameString);
+ if (LengthOfPrefix > 0) {
+ if (!LParenAdded) {
+ PropertyString += "(getter=";
+ LParenAdded = true;
+ }
+ else
+ PropertyString += ", getter=";
+ PropertyString += PropertyNameString;
+ }
+ // Property with no setter may be suggested as a 'readonly' property.
+ if (!Setter) {
+ append_attr(PropertyString, "readonly", LParenAdded);
+ QualType ResType = Context.getCanonicalType(Getter->getResultType());
+ if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
+ append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
+ }
+
+ // Short circuit 'delegate' properties that contain the name "delegate" or
+ // "dataSource", or have exact name "target" to have 'assign' attribute.
+ if (PropertyName.equals("target") ||
+ (PropertyName.find("delegate") != StringRef::npos) ||
+ (PropertyName.find("dataSource") != StringRef::npos)) {
+ QualType QT = Getter->getResultType();
+ if (!QT->isRealType())
+ append_attr(PropertyString, "assign", LParenAdded);
+ }
+ else if (Setter) {
+ const ParmVarDecl *argDecl = *Setter->param_begin();
+ QualType ArgType = Context.getCanonicalType(argDecl->getType());
+ if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
+ append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
+ }
+ if (LParenAdded)
+ PropertyString += ')';
+ QualType RT = Getter->getResultType();
+ if (!isa<TypedefType>(RT)) {
+ // strip off any ARC lifetime qualifier.
+ QualType CanResultTy = Context.getCanonicalType(RT);
+ if (CanResultTy.getQualifiers().hasObjCLifetime()) {
+ Qualifiers Qs = CanResultTy.getQualifiers();
+ Qs.removeObjCLifetime();
+ RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+ }
+ }
+ PropertyString += " ";
+ PrintingPolicy SubPolicy(Context.getPrintingPolicy());
+ SubPolicy.SuppressStrongLifetime = true;
+ SubPolicy.SuppressLifetimeQualifiers = true;
+ std::string TypeString = RT.getAsString(SubPolicy);
+ if (LengthOfPrefix > 0) {
+ // property name must strip off "is" and lower case the first character
+ // after that; e.g. isContinuous will become continuous.
+ StringRef PropertyNameStringRef(PropertyNameString);
+ PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
+ PropertyNameString = PropertyNameStringRef;
+ bool NoLowering = (isUppercase(PropertyNameString[0]) &&
+ PropertyNameString.size() > 1 &&
+ isUppercase(PropertyNameString[1]));
+ if (!NoLowering)
+ PropertyNameString[0] = toLowercase(PropertyNameString[0]);
+ }
+ if (RT->isBlockPointerType() || RT->isFunctionPointerType())
+ MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
+ TypeString,
+ PropertyNameString.c_str());
+ else {
+ char LastChar = TypeString[TypeString.size()-1];
+ PropertyString += TypeString;
+ if (LastChar != '*')
+ PropertyString += ' ';
+ PropertyString += PropertyNameString;
+ }
+ SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
+ Selector GetterSelector = Getter->getSelector();
+
+ SourceLocation EndGetterSelectorLoc =
+ StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
+ commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
+ EndGetterSelectorLoc),
+ PropertyString);
+ if (Setter && AvailabilityArgsMatch) {
+ SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
+ // Get location past ';'
+ EndLoc = EndLoc.getLocWithOffset(1);
+ SourceLocation BeginOfSetterDclLoc = Setter->getLocStart();
+ // FIXME. This assumes that setter decl; is immediately preceeded by eoln.
+ // It is trying to remove the setter method decl. line entirely.
+ BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
+ commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
+ ObjCContainerDecl *D) {
+ if (D->isDeprecated())
+ return;
+
+ for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated())
+ continue;
+ bool PropertyInferred = migrateProperty(Ctx, D, Method);
+ // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
+ // the getter method as it ends up on the property itself which we don't want
+ // to do unless -objcmt-returns-innerpointer-property option is on.
+ if (!PropertyInferred ||
+ (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateNsReturnsInnerPointer(Ctx, Method);
+ }
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
+ return;
+
+ for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
+ E = D->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
+ !Prop->isDeprecated())
+ migratePropertyNsReturnsInnerPointer(Ctx, Prop);
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx,
+ ObjCCategoryDecl *CatDecl) {
+ StringRef Name = CatDecl->getName();
+ if (!Name.endswith("Deprecated"))
+ return;
+
+ if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition())
+ return;
+
+ ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl);
+
+ for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated() || Method->isImplicit())
+ continue;
+ // Annotate with DEPRECATED
+ edit::Commit commit(*Editor);
+ commit.insertBefore(Method->getLocEnd(), " DEPRECATED");
+ Editor->commit(commit);
+ }
+ for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
+ E = D->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if (Prop->isDeprecated())
+ continue;
+ // Annotate with DEPRECATED
+ edit::Commit commit(*Editor);
+ commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED");
+ Editor->commit(commit);
+ }
+}
+
+static bool
+ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl,
+ const ObjCInterfaceDecl *IDecl,
+ ObjCProtocolDecl *Protocol) {
+ // In auto-synthesis, protocol properties are not synthesized. So,
+ // a conforming protocol must have its required properties declared
+ // in class interface.
+ bool HasAtleastOneRequiredProperty = false;
+ if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Property = *P;
+ if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ continue;
+ HasAtleastOneRequiredProperty = true;
+ DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
+ if (R.size() == 0) {
+ // Relax the rule and look into class's implementation for a synthesize
+ // or dynamic declaration. Class is implementing a property coming from
+ // another protocol. This still makes the target protocol as conforming.
+ if (!ImpDecl->FindPropertyImplDecl(
+ Property->getDeclName().getAsIdentifierInfo()))
+ return false;
+ }
+ else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
+ if ((ClassProperty->getPropertyAttributes()
+ != Property->getPropertyAttributes()) ||
+ !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
+ return false;
+ }
+ else
+ return false;
+ }
+
+ // At this point, all required properties in this protocol conform to those
+ // declared in the class.
+ // Check that class implements the required methods of the protocol too.
+ bool HasAtleastOneRequiredMethod = false;
+ if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
+ if (PDecl->meth_begin() == PDecl->meth_end())
+ return HasAtleastOneRequiredProperty;
+ for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
+ MEnd = PDecl->meth_end(); M != MEnd; ++M) {
+ ObjCMethodDecl *MD = (*M);
+ if (MD->isImplicit())
+ continue;
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
+ continue;
+ DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
+ if (R.size() == 0)
+ return false;
+ bool match = false;
+ HasAtleastOneRequiredMethod = true;
+ for (unsigned I = 0, N = R.size(); I != N; ++I)
+ if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
+ if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
+ match = true;
+ break;
+ }
+ if (!match)
+ return false;
+ }
+ }
+ if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
+ return true;
+ return false;
+}
+
+static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
+ llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
+ const NSAPI &NS, edit::Commit &commit) {
+ const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
+ std::string ClassString;
+ SourceLocation EndLoc =
+ IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
+
+ if (Protocols.empty()) {
+ ClassString = '<';
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ ClassString += ConformingProtocols[i]->getNameAsString();
+ if (i != (e-1))
+ ClassString += ", ";
+ }
+ ClassString += "> ";
+ }
+ else {
+ ClassString = ", ";
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ ClassString += ConformingProtocols[i]->getNameAsString();
+ if (i != (e-1))
+ ClassString += ", ";
+ }
+ ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
+ EndLoc = *PL;
+ }
+
+ commit.insertAfterToken(EndLoc, ClassString);
+ return true;
+}
+
+static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl,
+ const NSAPI &NS, edit::Commit &commit,
+ bool IsNSIntegerType,
+ bool NSOptions) {
+ std::string ClassString;
+ if (NSOptions)
+ ClassString = "typedef NS_OPTIONS(NSUInteger, ";
+ else
+ ClassString =
+ IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
+ : "typedef NS_ENUM(NSUInteger, ";
+
+ ClassString += TypedefDcl->getIdentifier()->getName();
+ ClassString += ')';
+ SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
+ commit.replace(R, ClassString);
+ SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd();
+ EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
+ NS.getASTContext(), /*IsDecl*/true);
+ if (!EndOfEnumDclLoc.isInvalid()) {
+ SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc);
+ commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange);
+ }
+ else
+ return false;
+
+ SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd();
+ EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
+ NS.getASTContext(), /*IsDecl*/true);
+ if (!EndTypedefDclLoc.isInvalid()) {
+ SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc);
+ commit.remove(TDRange);
+ }
+ else
+ return false;
+
+ EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(),
+ /*IsDecl*/true);
+ if (!EndOfEnumDclLoc.isInvalid()) {
+ SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
+ // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
+ // It is trying to remove the enum decl. lines entirely.
+ BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
+ commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
+ return true;
+ }
+ return false;
+}
+
+static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl,
+ const NSAPI &NS, edit::Commit &commit,
+ bool IsNSIntegerType) {
+ std::string ClassString =
+ IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
+ ClassString += TypedefDcl->getIdentifier()->getName();
+ ClassString += ')';
+ SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
+ commit.replace(R, ClassString);
+ SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
+ commit.remove(SourceRange(TypedefLoc, TypedefLoc));
+}
+
+static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
+ const EnumDecl *EnumDcl) {
+ bool PowerOfTwo = true;
+ bool AllHexdecimalEnumerator = true;
+ uint64_t MaxPowerOfTwoVal = 0;
+ for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
+ EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
+ EnumConstantDecl *Enumerator = (*EI);
+ const Expr *InitExpr = Enumerator->getInitExpr();
+ if (!InitExpr) {
+ PowerOfTwo = false;
+ AllHexdecimalEnumerator = false;
+ continue;
+ }
+ InitExpr = InitExpr->IgnoreParenCasts();
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
+ if (BO->isShiftOp() || BO->isBitwiseOp())
+ return true;
+
+ uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
+ if (PowerOfTwo && EnumVal) {
+ if (!llvm::isPowerOf2_64(EnumVal))
+ PowerOfTwo = false;
+ else if (EnumVal > MaxPowerOfTwoVal)
+ MaxPowerOfTwoVal = EnumVal;
+ }
+ if (AllHexdecimalEnumerator && EnumVal) {
+ bool FoundHexdecimalEnumerator = false;
+ SourceLocation EndLoc = Enumerator->getLocEnd();
+ Token Tok;
+ if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
+ if (Tok.isLiteral() && Tok.getLength() > 2) {
+ if (const char *StringLit = Tok.getLiteralData())
+ FoundHexdecimalEnumerator =
+ (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
+ }
+ if (!FoundHexdecimalEnumerator)
+ AllHexdecimalEnumerator = false;
+ }
+ }
+ return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
+}
+
+void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl) {
+ const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
+ if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
+ return;
+ // Find all implicit conforming protocols for this class
+ // and make them explicit.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
+ Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
+ llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
+
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
+ ObjCProtocolDecls.begin(),
+ E = ObjCProtocolDecls.end(); I != E; ++I)
+ if (!ExplicitProtocols.count(*I))
+ PotentialImplicitProtocols.push_back(*I);
+
+ if (PotentialImplicitProtocols.empty())
+ return;
+
+ // go through list of non-optional methods and properties in each protocol
+ // in the PotentialImplicitProtocols list. If class implements every one of the
+ // methods and properties, then this class conforms to this protocol.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
+ for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
+ if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
+ PotentialImplicitProtocols[i]))
+ ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
+
+ if (ConformingProtocols.empty())
+ return;
+
+ // Further reduce number of conforming protocols. If protocol P1 is in the list
+ // protocol P2 (P2<P1>), No need to include P1.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ bool DropIt = false;
+ ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
+ for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
+ ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
+ if (PDecl == TargetPDecl)
+ continue;
+ if (PDecl->lookupProtocolNamed(
+ TargetPDecl->getDeclName().getAsIdentifierInfo())) {
+ DropIt = true;
+ break;
+ }
+ }
+ if (!DropIt)
+ MinimalConformingProtocols.push_back(TargetPDecl);
+ }
+ edit::Commit commit(*Editor);
+ rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
+ *NSAPIObj, commit);
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
+ const TypedefDecl *TypedefDcl) {
+
+ QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
+ if (NSAPIObj->isObjCNSIntegerType(qt))
+ NSIntegerTypedefed = TypedefDcl;
+ else if (NSAPIObj->isObjCNSUIntegerType(qt))
+ NSUIntegerTypedefed = TypedefDcl;
+}
+
+bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
+ const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl) {
+ if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
+ EnumDcl->isDeprecated())
+ return false;
+ if (!TypedefDcl) {
+ if (NSIntegerTypedefed) {
+ TypedefDcl = NSIntegerTypedefed;
+ NSIntegerTypedefed = 0;
+ }
+ else if (NSUIntegerTypedefed) {
+ TypedefDcl = NSUIntegerTypedefed;
+ NSUIntegerTypedefed = 0;
+ }
+ else
+ return false;
+ FileID FileIdOfTypedefDcl =
+ PP.getSourceManager().getFileID(TypedefDcl->getLocation());
+ FileID FileIdOfEnumDcl =
+ PP.getSourceManager().getFileID(EnumDcl->getLocation());
+ if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
+ return false;
+ }
+ if (TypedefDcl->isDeprecated())
+ return false;
+
+ QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
+ bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
+ bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
+
+ if (!IsNSIntegerType && !IsNSUIntegerType) {
+ // Also check for typedef enum {...} TD;
+ if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
+ if (EnumTy->getDecl() == EnumDcl) {
+ bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
+ if (NSOptions) {
+ if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
+ return false;
+ }
+ else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
+ return false;
+ edit::Commit commit(*Editor);
+ rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
+ Editor->commit(commit);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // We may still use NS_OPTIONS based on what we find in the enumertor list.
+ bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
+ // NS_ENUM must be available.
+ if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
+ return false;
+ // NS_OPTIONS must be available.
+ if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
+ return false;
+ edit::Commit commit(*Editor);
+ bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
+ commit, IsNSIntegerType, NSOptions);
+ Editor->commit(commit);
+ return Res;
+}
+
+static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
+ ObjCMethodDecl *OM) {
+ SourceRange R;
+ std::string ClassString;
+ if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
+ ClassString = "instancetype";
+ }
+ else {
+ R = SourceRange(OM->getLocStart(), OM->getLocStart());
+ ClassString = OM->isInstanceMethod() ? '-' : '+';
+ ClassString += " (instancetype)";
+ }
+ edit::Commit commit(*ASTC.Editor);
+ commit.replace(R, ClassString);
+ ASTC.Editor->commit(commit);
+}
+
+static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
+ ObjCMethodDecl *OM) {
+ ObjCInterfaceDecl *IDecl = OM->getClassInterface();
+ SourceRange R;
+ std::string ClassString;
+ if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
+ ClassString = IDecl->getName();
+ ClassString += "*";
+ }
+ }
+ else {
+ R = SourceRange(OM->getLocStart(), OM->getLocStart());
+ ClassString = "+ (";
+ ClassString += IDecl->getName(); ClassString += "*)";
+ }
+ edit::Commit commit(*ASTC.Editor);
+ commit.replace(R, ClassString);
+ ASTC.Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM) {
+ ObjCInstanceTypeFamily OIT_Family =
+ Selector::getInstTypeMethodFamily(OM->getSelector());
+
+ std::string ClassName;
+ switch (OIT_Family) {
+ case OIT_None:
+ migrateFactoryMethod(Ctx, CDecl, OM);
+ return;
+ case OIT_Array:
+ ClassName = "NSArray";
+ break;
+ case OIT_Dictionary:
+ ClassName = "NSDictionary";
+ break;
+ case OIT_Singleton:
+ migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
+ return;
+ case OIT_Init:
+ if (OM->getResultType()->isObjCIdType())
+ ReplaceWithInstancetype(*this, OM);
+ return;
+ case OIT_ReturnsSelf:
+ migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
+ return;
+ }
+ if (!OM->getResultType()->isObjCIdType())
+ return;
+
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = CatDecl->getClassInterface();
+ else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
+ IDecl = ImpDecl->getClassInterface();
+ }
+ if (!IDecl ||
+ !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
+ migrateFactoryMethod(Ctx, CDecl, OM);
+ return;
+ }
+ ReplaceWithInstancetype(*this, OM);
+}
+
+static bool TypeIsInnerPointer(QualType T) {
+ if (!T->isAnyPointerType())
+ return false;
+ if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
+ T->isBlockPointerType() || T->isFunctionPointerType() ||
+ ento::coreFoundation::isCFObjectRef(T))
+ return false;
+ // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
+ // is not an innter pointer type.
+ QualType OrigT = T;
+ while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
+ T = TD->getDecl()->getUnderlyingType();
+ if (OrigT == T || !T->isPointerType())
+ return true;
+ const PointerType* PT = T->getAs<PointerType>();
+ QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
+ if (UPointeeT->isRecordType()) {
+ const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
+ if (!RecordTy->getDecl()->isCompleteDefinition())
+ return false;
+ }
+ return true;
+}
+
+/// \brief Check whether the two versions match.
+static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
+ return (X == Y);
+}
+
+/// AvailabilityAttrsMatch - This routine checks that if comparing two
+/// availability attributes, all their components match. It returns
+/// true, if not dealing with availability or when all components of
+/// availability attributes match. This routine is only called when
+/// the attributes are of the same kind.
+static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
+ const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
+ if (!AA1)
+ return true;
+ const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2);
+
+ VersionTuple Introduced1 = AA1->getIntroduced();
+ VersionTuple Deprecated1 = AA1->getDeprecated();
+ VersionTuple Obsoleted1 = AA1->getObsoleted();
+ bool IsUnavailable1 = AA1->getUnavailable();
+ VersionTuple Introduced2 = AA2->getIntroduced();
+ VersionTuple Deprecated2 = AA2->getDeprecated();
+ VersionTuple Obsoleted2 = AA2->getObsoleted();
+ bool IsUnavailable2 = AA2->getUnavailable();
+ return (versionsMatch(Introduced1, Introduced2) &&
+ versionsMatch(Deprecated1, Deprecated2) &&
+ versionsMatch(Obsoleted1, Obsoleted2) &&
+ IsUnavailable1 == IsUnavailable2);
+
+}
+
+static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
+ bool &AvailabilityArgsMatch) {
+ // This list is very small, so this need not be optimized.
+ for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
+ bool match = false;
+ for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
+ // Matching attribute kind only. Except for Availabilty attributes,
+ // we are not getting into details of the attributes. For all practical purposes
+ // this is sufficient.
+ if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
+ if (AvailabilityArgsMatch)
+ AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ return true;
+}
+
+/// AttributesMatch - This routine checks list of attributes for two
+/// decls. It returns false, if there is a mismatch in kind of
+/// attributes seen in the decls. It returns true if the two decls
+/// have list of same kind of attributes. Furthermore, when there
+/// are availability attributes in the two decls, it sets the
+/// AvailabilityArgsMatch to false if availability attributes have
+/// different versions, etc.
+static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
+ bool &AvailabilityArgsMatch) {
+ if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
+ AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
+ return true;
+ }
+ AvailabilityArgsMatch = true;
+ const AttrVec &Attrs1 = Decl1->getAttrs();
+ const AttrVec &Attrs2 = Decl2->getAttrs();
+ bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
+ if (match && (Attrs2.size() > Attrs1.size()))
+ return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
+ return match;
+}
+
+static bool IsValidIdentifier(ASTContext &Ctx,
+ const char *Name) {
+ if (!isIdentifierHead(Name[0]))
+ return false;
+ std::string NameString = Name;
+ NameString[0] = toLowercase(NameString[0]);
+ IdentifierInfo *II = &Ctx.Idents.get(NameString);
+ return II->getTokenID() == tok::identifier;
+}
+
+bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
+ ObjCContainerDecl *D,
+ ObjCMethodDecl *Method) {
+ if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
+ Method->param_size() != 0)
+ return false;
+ // Is this method candidate to be a getter?
+ QualType GRT = Method->getResultType();
+ if (GRT->isVoidType())
+ return false;
+
+ Selector GetterSelector = Method->getSelector();
+ ObjCInstanceTypeFamily OIT_Family =
+ Selector::getInstTypeMethodFamily(GetterSelector);
+
+ if (OIT_Family != OIT_None)
+ return false;
+
+ IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
+ Selector SetterSelector =
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ getterName);
+ ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
+ unsigned LengthOfPrefix = 0;
+ if (!SetterMethod) {
+ // try a different naming convention for getter: isXxxxx
+ StringRef getterNameString = getterName->getName();
+ bool IsPrefix = getterNameString.startswith("is");
+ // Note that we don't want to change an isXXX method of retainable object
+ // type to property (readonly or otherwise).
+ if (IsPrefix && GRT->isObjCRetainableType())
+ return false;
+ if (IsPrefix || getterNameString.startswith("get")) {
+ LengthOfPrefix = (IsPrefix ? 2 : 3);
+ const char *CGetterName = getterNameString.data() + LengthOfPrefix;
+ // Make sure that first character after "is" or "get" prefix can
+ // start an identifier.
+ if (!IsValidIdentifier(Ctx, CGetterName))
+ return false;
+ if (CGetterName[0] && isUppercase(CGetterName[0])) {
+ getterName = &Ctx.Idents.get(CGetterName);
+ SetterSelector =
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ getterName);
+ SetterMethod = D->getInstanceMethod(SetterSelector);
+ }
+ }
+ }
+
+ if (SetterMethod) {
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
+ return false;
+ bool AvailabilityArgsMatch;
+ if (SetterMethod->isDeprecated() ||
+ !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
+ return false;
+
+ // Is this a valid setter, matching the target getter?
+ QualType SRT = SetterMethod->getResultType();
+ if (!SRT->isVoidType())
+ return false;
+ const ParmVarDecl *argDecl = *SetterMethod->param_begin();
+ QualType ArgType = argDecl->getType();
+ if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
+ return false;
+ edit::Commit commit(*Editor);
+ rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
+ LengthOfPrefix,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_AtomicProperty) != 0,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
+ AvailabilityArgsMatch);
+ Editor->commit(commit);
+ return true;
+ }
+ else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
+ // Try a non-void method with no argument (and no setter or property of same name
+ // as a 'readonly' property.
+ edit::Commit commit(*Editor);
+ rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
+ LengthOfPrefix,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_AtomicProperty) != 0,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
+ /*AvailabilityArgsMatch*/false);
+ Editor->commit(commit);
+ return true;
+ }
+ return false;
+}
+
+void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
+ ObjCMethodDecl *OM) {
+ if (OM->isImplicit() ||
+ !OM->isInstanceMethod() ||
+ OM->hasAttr<ObjCReturnsInnerPointerAttr>())
+ return;
+
+ QualType RT = OM->getResultType();
+ if (!TypeIsInnerPointer(RT) ||
+ !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
+ return;
+
+ edit::Commit commit(*Editor);
+ commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER");
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
+ ObjCPropertyDecl *P) {
+ QualType T = P->getType();
+
+ if (!TypeIsInnerPointer(T) ||
+ !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
+ return;
+ edit::Commit commit(*Editor);
+ commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER ");
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl) {
+ if (CDecl->isDeprecated())
+ return;
+
+ // migrate methods which can have instancetype as their result type.
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
+ MEnd = CDecl->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated())
+ continue;
+ migrateMethodInstanceType(Ctx, CDecl, Method);
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM,
+ ObjCInstanceTypeFamily OIT_Family) {
+ if (OM->isInstanceMethod() ||
+ OM->getResultType() == Ctx.getObjCInstanceType() ||
+ !OM->getResultType()->isObjCIdType())
+ return;
+
+ // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
+ // NSYYYNamE with matching names be at least 3 characters long.
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = CatDecl->getClassInterface();
+ else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
+ IDecl = ImpDecl->getClassInterface();
+ }
+ if (!IDecl)
+ return;
+
+ std::string StringClassName = IDecl->getName();
+ StringRef LoweredClassName(StringClassName);
+ std::string StringLoweredClassName = LoweredClassName.lower();
+ LoweredClassName = StringLoweredClassName;
+
+ IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
+ // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
+ if (!MethodIdName)
+ return;
+
+ std::string MethodName = MethodIdName->getName();
+ if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
+ StringRef STRefMethodName(MethodName);
+ size_t len = 0;
+ if (STRefMethodName.startswith("standard"))
+ len = strlen("standard");
+ else if (STRefMethodName.startswith("shared"))
+ len = strlen("shared");
+ else if (STRefMethodName.startswith("default"))
+ len = strlen("default");
+ else
+ return;
+ MethodName = STRefMethodName.substr(len);
+ }
+ std::string MethodNameSubStr = MethodName.substr(0, 3);
+ StringRef MethodNamePrefix(MethodNameSubStr);
+ std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
+ MethodNamePrefix = StringLoweredMethodNamePrefix;
+ size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
+ if (Ix == StringRef::npos)
+ return;
+ std::string ClassNamePostfix = LoweredClassName.substr(Ix);
+ StringRef LoweredMethodName(MethodName);
+ std::string StringLoweredMethodName = LoweredMethodName.lower();
+ LoweredMethodName = StringLoweredMethodName;
+ if (!LoweredMethodName.startswith(ClassNamePostfix))
+ return;
+ if (OIT_Family == OIT_ReturnsSelf)
+ ReplaceWithClasstype(*this, OM);
+ else
+ ReplaceWithInstancetype(*this, OM);
+}
+
+static bool IsVoidStarType(QualType Ty) {
+ if (!Ty->isPointerType())
+ return false;
+
+ while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
+ Ty = TD->getDecl()->getUnderlyingType();
+
+ // Is the type void*?
+ const PointerType* PT = Ty->getAs<PointerType>();
+ if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
+ return true;
+ return IsVoidStarType(PT->getPointeeType());
+}
+
+/// AuditedType - This routine audits the type AT and returns false if it is one of known
+/// CF object types or of the "void *" variety. It returns true if we don't care about the type
+/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
+static bool AuditedType (QualType AT) {
+ if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
+ return true;
+ // FIXME. There isn't much we can say about CF pointer type; or is there?
+ if (ento::coreFoundation::isCFObjectRef(AT) ||
+ IsVoidStarType(AT) ||
+ // If an ObjC object is type, assuming that it is not a CF function and
+ // that it is an un-audited function.
+ AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
+ return false;
+ // All other pointers are assumed audited as harmless.
+ return true;
+}
+
+void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
+ if (CFFunctionIBCandidates.empty())
+ return;
+ if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
+ CFFunctionIBCandidates.clear();
+ FileId = FileID();
+ return;
+ }
+ // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
+ const Decl *FirstFD = CFFunctionIBCandidates[0];
+ const Decl *LastFD =
+ CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
+ const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
+ edit::Commit commit(*Editor);
+ commit.insertBefore(FirstFD->getLocStart(), PragmaString);
+ PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
+ SourceLocation EndLoc = LastFD->getLocEnd();
+ // get location just past end of function location.
+ EndLoc = PP.getLocForEndOfToken(EndLoc);
+ if (isa<FunctionDecl>(LastFD)) {
+ // For Methods, EndLoc points to the ending semcolon. So,
+ // not of these extra work is needed.
+ Token Tok;
+ // get locaiton of token that comes after end of function.
+ bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
+ if (!Failed)
+ EndLoc = Tok.getLocation();
+ }
+ commit.insertAfterToken(EndLoc, PragmaString);
+ Editor->commit(commit);
+ FileId = FileID();
+ CFFunctionIBCandidates.clear();
+}
+
+void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
+ if (Decl->isDeprecated())
+ return;
+
+ if (Decl->hasAttr<CFAuditedTransferAttr>()) {
+ assert(CFFunctionIBCandidates.empty() &&
+ "Cannot have audited functions/methods inside user "
+ "provided CF_IMPLICIT_BRIDGING_ENABLE");
+ return;
+ }
+
+ // Finction must be annotated first.
+ if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
+ CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
+ if (AuditKind == CF_BRIDGING_ENABLE) {
+ CFFunctionIBCandidates.push_back(Decl);
+ if (FileId.isInvalid())
+ FileId = PP.getSourceManager().getFileID(Decl->getLocation());
+ }
+ else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
+ if (!CFFunctionIBCandidates.empty()) {
+ CFFunctionIBCandidates.push_back(Decl);
+ if (FileId.isInvalid())
+ FileId = PP.getSourceManager().getFileID(Decl->getLocation());
+ }
+ }
+ else
+ AnnotateImplicitBridging(Ctx);
+ }
+ else {
+ migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
+ AnnotateImplicitBridging(Ctx);
+ }
+}
+
+void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
+ const CallEffects &CE,
+ const FunctionDecl *FuncDecl,
+ bool ResultAnnotated) {
+ // Annotate function.
+ if (!ResultAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ const char *AnnotationString = 0;
+ if (Ret.getObjKind() == RetEffect::CF) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_RETAINED";
+ else if (Ret.notOwned() &&
+ Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_NOT_RETAINED";
+ }
+ else if (Ret.getObjKind() == RetEffect::ObjC) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " NS_RETURNS_RETAINED";
+ }
+
+ if (AnnotationString) {
+ edit::Commit commit(*Editor);
+ commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
+ Editor->commit(commit);
+ }
+ }
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
+ pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
+ }
+ else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
+ Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
+ Editor->commit(commit);
+ }
+ }
+}
+
+
+ObjCMigrateASTConsumer::CF_BRIDGING_KIND
+ ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
+ ASTContext &Ctx,
+ const FunctionDecl *FuncDecl) {
+ if (FuncDecl->hasBody())
+ return CF_BRIDGING_NONE;
+
+ CallEffects CE = CallEffects::getEffect(FuncDecl);
+ bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
+ FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
+
+ // Trivial case of when funciton is annotated and has no argument.
+ if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
+ return CF_BRIDGING_NONE;
+
+ bool ReturnCFAudited = false;
+ if (!FuncIsReturnAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ if (Ret.getObjKind() == RetEffect::CF &&
+ (Ret.isOwned() || Ret.notOwned()))
+ ReturnCFAudited = true;
+ else if (!AuditedType(FuncDecl->getResultType()))
+ return CF_BRIDGING_NONE;
+ }
+
+ // At this point result type is audited for potential inclusion.
+ // Now, how about argument types.
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ bool ArgCFAudited = false;
+ for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
+ pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
+ ArgCFAudited = true;
+ else if (AE == IncRef)
+ ArgCFAudited = true;
+ }
+ else {
+ QualType AT = pd->getType();
+ if (!AuditedType(AT)) {
+ AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
+ return CF_BRIDGING_NONE;
+ }
+ }
+ }
+ if (ReturnCFAudited || ArgCFAudited)
+ return CF_BRIDGING_ENABLE;
+
+ return CF_BRIDGING_MAY_INCLUDE;
+}
+
+void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl) {
+ if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
+ return;
+
+ // migrate methods which can have instancetype as their result type.
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
+ MEnd = CDecl->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ migrateCFAnnotation(Ctx, Method);
+ }
+}
+
+void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
+ const CallEffects &CE,
+ const ObjCMethodDecl *MethodDecl,
+ bool ResultAnnotated) {
+ // Annotate function.
+ if (!ResultAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ const char *AnnotationString = 0;
+ if (Ret.getObjKind() == RetEffect::CF) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_RETAINED";
+ else if (Ret.notOwned() &&
+ Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_NOT_RETAINED";
+ }
+ else if (Ret.getObjKind() == RetEffect::ObjC) {
+ ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
+ switch (OMF) {
+ case clang::OMF_alloc:
+ case clang::OMF_new:
+ case clang::OMF_copy:
+ case clang::OMF_init:
+ case clang::OMF_mutableCopy:
+ break;
+
+ default:
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " NS_RETURNS_RETAINED";
+ break;
+ }
+ }
+
+ if (AnnotationString) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
+ Editor->commit(commit);
+ }
+ }
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
+ pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
+ }
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
+ ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl) {
+ if (MethodDecl->hasBody() || MethodDecl->isImplicit())
+ return;
+
+ CallEffects CE = CallEffects::getEffect(MethodDecl);
+ bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
+ MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
+
+ if (CE.getReceiver() == DecRefMsg &&
+ !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
+ MethodDecl->getMethodFamily() != OMF_init &&
+ MethodDecl->getMethodFamily() != OMF_release &&
+ Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF");
+ Editor->commit(commit);
+ }
+
+ // Trivial case of when funciton is annotated and has no argument.
+ if (MethodIsReturnAnnotated &&
+ (MethodDecl->param_begin() == MethodDecl->param_end()))
+ return;
+
+ if (!MethodIsReturnAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ if ((Ret.getObjKind() == RetEffect::CF ||
+ Ret.getObjKind() == RetEffect::ObjC) &&
+ (Ret.isOwned() || Ret.notOwned())) {
+ AddCFAnnotations(Ctx, CE, MethodDecl, false);
+ return;
+ }
+ else if (!AuditedType(MethodDecl->getResultType()))
+ return;
+ }
+
+ // At this point result type is either annotated or audited.
+ // Now, how about argument types.
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
+ pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
+ !AuditedType(pd->getType())) {
+ AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
+ return;
+ }
+ }
+ return;
+}
+
namespace {
class RewritesReceiver : public edit::EditsReceiver {
@@ -202,7 +1582,114 @@ public:
}
+static bool
+IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SEntry =
+ Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
+ if (!Invalid && SEntry.isFile()) {
+ const SrcMgr::FileInfo &FI = SEntry.getFile();
+ if (!FI.hasLineDirectives()) {
+ if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
+ return true;
+ if (FI.getFileCharacteristic() == SrcMgr::C_System) {
+ // This file is in a system header directory. Continue with commiting change
+ // only if it is a user specified system directory because user put a
+ // .system_framework file in the framework directory.
+ StringRef Directory(file->getDir()->getName());
+ size_t Ix = Directory.rfind(".framework");
+ if (Ix == StringRef::npos)
+ return true;
+ std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
+ PatchToSystemFramework += ".system_framework";
+ if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+
+ TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
+ for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
+ D != DEnd; ++D) {
+ FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
+ if (!FID.isInvalid())
+ if (!FileId.isInvalid() && FileId != FID) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ AnnotateImplicitBridging(Ctx);
+ }
+
+ if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
+ migrateObjCInterfaceDecl(Ctx, CDecl);
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
+ migrateObjCInterfaceDecl(Ctx, CatDecl);
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateDeprecatedAnnotation(Ctx, CatDecl);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
+ ObjCProtocolDecls.insert(PDecl);
+ else if (const ObjCImplementationDecl *ImpDecl =
+ dyn_cast<ObjCImplementationDecl>(*D)) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
+ migrateProtocolConformance(Ctx, ImpDecl);
+ }
+ else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
+ continue;
+ DeclContext::decl_iterator N = D;
+ if (++N != DEnd) {
+ const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
+ if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
+ D++;
+ }
+ else
+ migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
+ }
+ else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
+ continue;
+ DeclContext::decl_iterator N = D;
+ if (++N == DEnd)
+ continue;
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
+ if (++N != DEnd)
+ if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
+ // prefer typedef-follows-enum to enum-follows-typedef pattern.
+ if (migrateNSEnumDecl(Ctx, ED, TDF)) {
+ ++D; ++D;
+ CacheObjCNSIntegerTypedefed(TD);
+ continue;
+ }
+ }
+ if (migrateNSEnumDecl(Ctx, ED, TD)) {
+ ++D;
+ continue;
+ }
+ }
+ CacheObjCNSIntegerTypedefed(TD);
+ }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateCFAnnotation(Ctx, FD);
+ }
+
+ if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
+ // migrate methods which can have instancetype as their result type.
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype)
+ migrateAllMethodInstaceType(Ctx, CDecl);
+ // annotate methods with CF annotations.
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateARCSafeAnnotation(Ctx, CDecl);
+ }
+ }
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ AnnotateImplicitBridging(Ctx);
+ }
+
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
RewritesReceiver Rec(rewriter);
Editor->applyRewrites(Rec);
@@ -213,6 +1700,10 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
+ if (IsReallyASystemHeader(Ctx, file, FID))
+ continue;
+ if (!canModifyFile(file->getName()))
+ continue;
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
@@ -236,16 +1727,49 @@ bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
return true;
}
+static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
+ using namespace llvm::sys::fs;
+ using namespace llvm::sys::path;
+
+ std::vector<std::string> Filenames;
+ if (DirPath.empty() || !is_directory(DirPath))
+ return Filenames;
+
+ llvm::error_code EC;
+ directory_iterator DI = directory_iterator(DirPath, EC);
+ directory_iterator DE;
+ for (; !EC && DI != DE; DI = DI.increment(EC)) {
+ if (is_regular_file(DI->path()))
+ Filenames.push_back(filename(DI->path()));
+ }
+
+ return Filenames;
+}
+
ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
+ unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
+ unsigned ObjCMTOpts = ObjCMTAction;
+ // These are companion flags, they do not enable transformations.
+ ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty |
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty);
+ if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
+ // If no specific option was given, enable literals+subscripting transforms
+ // by default.
+ ObjCMTAction |= FrontendOptions::ObjCMT_Literals |
+ FrontendOptions::ObjCMT_Subscripting;
+ }
CI.getPreprocessor().addPPCallbacks(PPRec);
+ std::vector<std::string> WhiteList =
+ getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
- /*MigrateLiterals=*/true,
- /*MigrateSubscripting=*/true,
+ ObjCMTAction,
Remapper,
CI.getFileManager(),
PPRec,
- /*isOutputFile=*/true);
+ CI.getPreprocessor(),
+ /*isOutputFile=*/true,
+ WhiteList);
}
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index fc4a75fdb838..7b360c640cfd 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -77,6 +77,13 @@ public:
TraverseStmt(body);
}
+ bool TraverseBlockDecl(BlockDecl *D) {
+ // ParentMap does not enter into a BlockDecl to record its stmts, so use a
+ // new UnbridgedCastRewriter to handle the block.
+ UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
+ return true;
+ }
+
bool VisitCastExpr(CastExpr *E) {
if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
E->getCastKind() != CK_BitCast &&
@@ -148,7 +155,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage()) {
+ FD->isExternallyVisible()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -413,7 +420,7 @@ private:
FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage())
+ FD->isExternallyVisible())
return true;
return false;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 087219535a18..679b924ba009 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -49,7 +49,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return false;
// iOS is always safe to use 'weak'.
- if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
+ if (Ctx.getTargetInfo().getTriple().isiOS())
AllowOnUnknownClass = true;
while (const PointerType *ptr = T->getAs<PointerType>())
@@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage() &&
+ FD->isExternallyVisible() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -122,8 +122,8 @@ bool trans::isPlusOne(const Expr *E) {
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
- ASTContext &Ctx) {
- SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
+ ASTContext &Ctx, bool IsDecl) {
+ SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
if (SemiLoc.isInvalid())
return SourceLocation();
return SemiLoc.getLocWithOffset(1);
@@ -134,7 +134,8 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
- ASTContext &Ctx) {
+ ASTContext &Ctx,
+ bool IsDecl) {
SourceManager &SM = Ctx.getSourceManager();
if (loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
@@ -159,8 +160,13 @@ SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
file.begin(), tokenBegin, file.end());
Token tok;
lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::semi))
- return SourceLocation();
+ if (tok.isNot(tok::semi)) {
+ if (!IsDecl)
+ return SourceLocation();
+ // Declaration may be followed with other tokens; such as an __attribute,
+ // before ending with a semicolon.
+ return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
+ }
return tok.getLocation();
}
@@ -198,7 +204,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->hasExternalLinkage();
+ DRE->getDecl()->isExternallyVisible();
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index e20fe5927f39..eab5e85d56b7 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -167,13 +167,15 @@ bool isPlusOne(const Expr *E);
/// immediately after the semicolon following the statement.
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
-SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx);
+SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx,
+ bool IsDecl = false);
/// \brief 'Loc' is the end of a statement range. This returns the location
/// of the semicolon following the statement.
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
-SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx);
+SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
+ bool IsDecl = false);
bool hasSideEffects(Expr *E, ASTContext &Ctx);
bool isGlobalVar(Expr *E);
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 98e825b3bafb..541836b21b70 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -212,6 +212,40 @@ void APValue::DestroyDataAndMakeUninit() {
Kind = Uninitialized;
}
+bool APValue::needsCleanup() const {
+ switch (getKind()) {
+ case Uninitialized:
+ case AddrLabelDiff:
+ return false;
+ case Struct:
+ case Union:
+ case Array:
+ case Vector:
+ return true;
+ case Int:
+ return getInt().needsCleanup();
+ case Float:
+ return getFloat().needsCleanup();
+ case ComplexFloat:
+ assert(getComplexFloatImag().needsCleanup() ==
+ getComplexFloatReal().needsCleanup() &&
+ "In _Complex float types, real and imaginary values always have the "
+ "same size.");
+ return getComplexFloatReal().needsCleanup();
+ case ComplexInt:
+ assert(getComplexIntImag().needsCleanup() ==
+ getComplexIntReal().needsCleanup() &&
+ "In _Complex int types, real and imaginary values must have the "
+ "same size.");
+ return getComplexIntReal().needsCleanup();
+ case LValue:
+ return reinterpret_cast<const LV *>(Data)->hasPathPtr();
+ case MemberPointer:
+ return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr();
+ }
+ llvm_unreachable("Unknown APValue kind!");
+}
+
void APValue::swap(APValue &RHS) {
std::swap(Kind, RHS.Kind);
char TmpData[MaxSize];
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 176aec53a252..a03cf9e7d47b 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -25,13 +25,16 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -132,8 +135,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
isa<RedeclarableTemplateDecl>(D) ||
isa<ClassTemplateSpecializationDecl>(D))
DeclLoc = D->getLocStart();
- else
+ else {
DeclLoc = D->getLocation();
+ // If location of the typedef name is in a macro, it is because being
+ // declared via a macro. Try using declaration's starting location
+ // as the "declaration location".
+ if (DeclLoc.isMacroID() && isa<TypedefDecl>(D))
+ DeclLoc = D->getLocStart();
+ }
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
@@ -175,7 +184,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// First check whether we have a trailing comment.
if (Comment != RawComments.end() &&
(*Comment)->isDocumentation() && (*Comment)->isTrailingComment() &&
- (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D))) {
+ (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
std::pair<FileID, unsigned> CommentBeginDecomp
= SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin());
// Check that Doxygen trailing comment comes after the declaration, starts
@@ -220,7 +230,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// There should be no other declarations or preprocessor directives between
// comment and declaration.
- if (Text.find_first_of(",;{}#@") != StringRef::npos)
+ if (Text.find_first_of(";{}#@") != StringRef::npos)
return NULL;
return *Comment;
@@ -406,9 +416,16 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
}
+comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const {
+ const RawComment *RC = getRawCommentForDeclNoCache(D);
+ return RC ? RC->parse(*this, 0, D) : 0;
+}
+
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
+ if (D->isInvalidDecl())
+ return NULL;
D = adjustDeclToTemplate(D);
const Decl *Canonical = D->getCanonicalDecl();
@@ -679,6 +696,19 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
}
}
+static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
+ const LangOptions &LangOpts) {
+ switch (LangOpts.getAddressSpaceMapMangling()) {
+ case LangOptions::ASMM_Target:
+ return TI.useAddressSpaceMapMangling();
+ case LangOptions::ASMM_On:
+ return true;
+ case LangOptions::ASMM_Off:
+ return false;
+ }
+ llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything.");
+}
+
ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
@@ -690,7 +720,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
GlobalNestedNameSpecifier(0),
- Int128Decl(0), UInt128Decl(0),
+ Int128Decl(0), UInt128Decl(0), Float128StubDecl(0),
BuiltinVaListDecl(0),
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
BOOLDecl(0),
@@ -709,8 +739,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
- LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ LastSDM(0, 0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -726,10 +755,12 @@ ASTContext::~ASTContext() {
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
- // Call all of the deallocation functions.
- for (unsigned I = 0, N = Deallocations.size(); I != N; ++I)
- Deallocations[I].first(Deallocations[I].second);
-
+ // Call all of the deallocation functions on all of their targets.
+ for (DeallocationMap::const_iterator I = Deallocations.begin(),
+ E = Deallocations.end(); I != E; ++I)
+ for (unsigned J = 0, N = I->second.size(); J != N; ++J)
+ (I->first)((I->second)[J]);
+
// ASTRecordLayout objects in ASTRecordLayouts must always be destroyed
// because they can contain DenseMaps.
for (llvm::DenseMap<const ObjCContainerDecl*,
@@ -750,10 +781,16 @@ ASTContext::~ASTContext() {
AEnd = DeclAttrs.end();
A != AEnd; ++A)
A->second->~AttrVec();
+
+ for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator
+ I = MangleNumberingContexts.begin(),
+ E = MangleNumberingContexts.end();
+ I != E; ++I)
+ delete I->second;
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
- Deallocations.push_back(std::make_pair(Callback, Data));
+ Deallocations[Callback].push_back(Data);
}
void
@@ -848,6 +885,20 @@ TypedefDecl *ASTContext::getUInt128Decl() const {
return UInt128Decl;
}
+TypeDecl *ASTContext::getFloat128StubType() const {
+ assert(LangOpts.CPlusPlus && "should only be called for c++");
+ if (!Float128StubDecl) {
+ Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this),
+ TTK_Struct,
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("__float128"));
+ }
+
+ return Float128StubDecl;
+}
+
void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
R = CanQualType::CreateUnsafe(QualType(Ty, 0));
@@ -863,6 +914,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
ABI.reset(createCXXABI(Target));
AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
+ AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts);
// C99 6.2.5p19.
InitBuiltinType(VoidTy, BuiltinType::Void);
@@ -897,13 +949,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
- if (TargetInfo::isTypeSigned(Target.getWCharType()))
- InitBuiltinType(WCharTy, BuiltinType::WChar_S);
- else // -fshort-wchar makes wchar_t be unsigned.
- InitBuiltinType(WCharTy, BuiltinType::WChar_U);
- } else // C99 (or C++ using -fno-wchar)
- WCharTy = getFromTargetType(Target.getWCharType());
+ // C++ 3.9.1p5
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
+ InitBuiltinType(WCharTy, BuiltinType::WChar_S);
+ else // -fshort-wchar makes wchar_t be unsigned.
+ InitBuiltinType(WCharTy, BuiltinType::WChar_U);
+ if (LangOpts.CPlusPlus && LangOpts.WChar)
+ WideCharTy = WCharTy;
+ else {
+ // C99 (or C++ using -fno-wchar).
+ WideCharTy = getFromTargetType(Target.getWCharType());
+ }
WIntTy = getFromTargetType(Target.getWIntType());
@@ -1008,13 +1064,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
+// FIXME: Remove ?
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
- llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos
- = InstantiatedFromStaticDataMember.find(Var);
- if (Pos == InstantiatedFromStaticDataMember.end())
- return 0;
+ return getTemplateOrSpecializationInfo(Var)
+ .dyn_cast<MemberSpecializationInfo *>();
+}
+
+ASTContext::TemplateOrSpecializationInfo
+ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) {
+ llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos =
+ TemplateOrInstantiation.find(Var);
+ if (Pos == TemplateOrInstantiation.end())
+ return TemplateOrSpecializationInfo();
return Pos->second;
}
@@ -1025,10 +1088,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
SourceLocation PointOfInstantiation) {
assert(Inst->isStaticDataMember() && "Not a static data member");
assert(Tmpl->isStaticDataMember() && "Not a static data member");
- assert(!InstantiatedFromStaticDataMember[Inst] &&
- "Already noted what static data member was instantiated from");
- InstantiatedFromStaticDataMember[Inst]
- = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
+ setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo(
+ Tmpl, TSK, PointOfInstantiation));
+}
+
+void
+ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
+ TemplateOrSpecializationInfo TSI) {
+ assert(!TemplateOrInstantiation[Inst] &&
+ "Already noted what the variable was instantiated from");
+ TemplateOrInstantiation[Inst] = TSI;
}
FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
@@ -1105,38 +1174,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
-bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0);
-}
-
-bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0 &&
- LastFD->getBitWidthValue(*this) != 0);
-}
-
-bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this));
-}
-
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -1224,12 +1261,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlign - Return a conservative estimate of the alignment of the
-/// specified decl. Note that bitfields do not have a valid alignment, so
-/// this method will assert on them.
-/// If @p RefAsPointee, references are treated like their underlying type
-/// (for alignof), else they're treated like pointers (for CodeGen).
-CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
unsigned Align = Target->getCharWidth();
bool UseAlignAttrOnly = false;
@@ -1262,7 +1294,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
} else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- if (RefAsPointee)
+ if (ForAlignof)
T = RT->getPointeeType();
else
T = getPointerType(RT->getPointeeType());
@@ -1270,14 +1302,15 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
if (!T->isIncompleteType() && !T->isFunctionType()) {
// Adjust alignments of declarations with array type by the
// large-array alignment on the target.
- unsigned MinWidth = Target->getLargeArrayMinWidth();
- const ArrayType *arrayType;
- if (MinWidth && (arrayType = getAsArrayType(T))) {
- if (isa<VariableArrayType>(arrayType))
- Align = std::max(Align, Target->getLargeArrayAlign());
- else if (isa<ConstantArrayType>(arrayType) &&
- MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
- Align = std::max(Align, Target->getLargeArrayAlign());
+ if (const ArrayType *arrayType = getAsArrayType(T)) {
+ unsigned MinWidth = Target->getLargeArrayMinWidth();
+ if (!ForAlignof && MinWidth) {
+ if (isa<VariableArrayType>(arrayType))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ else if (isa<ConstantArrayType>(arrayType) &&
+ MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ }
// Walk through any array types while we're at it.
T = getBaseElementType(arrayType);
@@ -1294,24 +1327,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
// a max-field-alignment constraint (#pragma pack). So calculate
// the actual alignment of the field within the struct, and then
// (as we're expected to) constrain that by the alignment of the type.
- if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) {
- // So calculate the alignment of the field.
- const ASTRecordLayout &layout = getASTRecordLayout(field->getParent());
-
- // Start with the record's overall alignment.
- unsigned fieldAlign = toBits(layout.getAlignment());
-
- // Use the GCD of that and the offset within the record.
- uint64_t offset = layout.getFieldOffset(field->getFieldIndex());
- if (offset > 0) {
- // Alignment is always a power of 2, so the GCD will be a power of 2,
- // which means we get to do this crazy thing instead of Euclid's.
- uint64_t lowBitOfOffset = offset & (~offset + 1);
- if (lowBitOfOffset < fieldAlign)
- fieldAlign = static_cast<unsigned>(lowBitOfOffset);
- }
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) {
+ const RecordDecl *Parent = Field->getParent();
+ // We can only produce a sensible answer if the record is valid.
+ if (!Parent->isInvalidDecl()) {
+ const ASTRecordLayout &Layout = getASTRecordLayout(Parent);
+
+ // Start with the record's overall alignment.
+ unsigned FieldAlign = toBits(Layout.getAlignment());
+
+ // Use the GCD of that and the offset within the record.
+ uint64_t Offset = Layout.getFieldOffset(Field->getFieldIndex());
+ if (Offset > 0) {
+ // Alignment is always a power of 2, so the GCD will be a power of 2,
+ // which means we get to do this crazy thing instead of Euclid's.
+ uint64_t LowBitOfOffset = Offset & (~Offset + 1);
+ if (LowBitOfOffset < FieldAlign)
+ FieldAlign = static_cast<unsigned>(LowBitOfOffset);
+ }
- Align = std::min(Align, fieldAlign);
+ Align = std::min(Align, FieldAlign);
+ }
}
}
@@ -1339,8 +1375,30 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
return sizeAndAlign;
}
+/// getConstantArrayInfoInChars - Performing the computation in CharUnits
+/// instead of in bits prevents overflowing the uint64_t for some large arrays.
+std::pair<CharUnits, CharUnits>
+static getConstantArrayInfoInChars(const ASTContext &Context,
+ const ConstantArrayType *CAT) {
+ std::pair<CharUnits, CharUnits> EltInfo =
+ Context.getTypeInfoInChars(CAT->getElementType());
+ uint64_t Size = CAT->getSize().getZExtValue();
+ assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <=
+ (uint64_t)(-1)/Size) &&
+ "Overflow in array type char size evaluation");
+ uint64_t Width = EltInfo.first.getQuantity() * Size;
+ unsigned Align = EltInfo.second.getQuantity();
+ if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ Context.getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
+ return std::make_pair(CharUnits::fromQuantity(Width),
+ CharUnits::fromQuantity(Align));
+}
+
std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
+ return getConstantArrayInfoInChars(*this, CAT);
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
return std::make_pair(toCharUnitsFromBits(Info.first),
toCharUnitsFromBits(Info.second));
@@ -1376,6 +1434,10 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \
+ case Type::Class: \
+ assert(!T->isDependentType() && "should not see dependent types here"); \
+ return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr());
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Should not see dependent types");
@@ -1401,7 +1463,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
"Overflow in array type bit size evaluation");
Width = EltInfo.first*Size;
Align = EltInfo.second;
- Width = llvm::RoundUpToAlignment(Width, Align);
+ if (!getTargetInfo().getCXXABI().isMicrosoft() ||
+ getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
break;
}
case Type::ExtVector:
@@ -1568,6 +1632,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::ObjCObject:
return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
+ case Type::Decayed:
+ return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr());
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -1624,20 +1690,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
break;
}
- case Type::TypeOfExpr:
- return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::TypeOf:
- return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
-
- case Type::Decltype:
- return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::UnaryTransform:
- return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
-
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
@@ -1645,18 +1697,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
- case Type::TemplateSpecialization: {
- assert(getCanonicalType(T) != T &&
- "Cannot request the size of a dependent type");
- const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
- // A type alias template specialization may refer to a typedef with the
- // aligned attribute on it.
- if (TST->isTypeAlias())
- return getTypeInfo(TST->getAliasedType().getTypePtr());
- else
- return getTypeInfo(getCanonicalType(T));
- }
-
case Type::Atomic: {
// Start with the base type information.
std::pair<uint64_t, unsigned> Info
@@ -1696,10 +1736,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const {
/// getTypeSizeInChars - Return the size of the specified type, in characters.
/// This method does not work on incomplete types.
CharUnits ASTContext::getTypeSizeInChars(QualType T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
CharUnits ASTContext::getTypeSizeInChars(const Type *T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
@@ -1718,6 +1758,9 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
unsigned ABIAlign = getTypeAlign(T);
+ if (Target->getTriple().getArch() == llvm::Triple::xcore)
+ return ABIAlign; // Never overalign on XCore.
+
// Double and long long should be naturally aligned if possible.
if (const ComplexType* CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
@@ -2042,10 +2085,7 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2053,12 +2093,18 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
QualType ResultType) {
- // FIXME: Need to inform serialization code about this!
- for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) {
+ FD = FD->getMostRecentDecl();
+ while (true) {
const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI));
+ if (FunctionDecl *Next = FD->getPreviousDecl())
+ FD = Next;
+ else
+ break;
}
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->DeducedReturnType(FD, ResultType);
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -2117,6 +2163,45 @@ QualType ASTContext::getPointerType(QualType T) const {
return QualType(New, 0);
}
+QualType ASTContext::getDecayedType(QualType T) const {
+ assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
+
+ llvm::FoldingSetNodeID ID;
+ DecayedType::Profile(ID, T);
+ void *InsertPos = 0;
+ if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(DT, 0);
+
+ QualType Decayed;
+
+ // C99 6.7.5.3p7:
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ if (T->isArrayType())
+ Decayed = getArrayDecayedType(T);
+
+ // C99 6.7.5.3p8:
+ // A declaration of a parameter as "function returning type"
+ // shall be adjusted to "pointer to function returning type", as
+ // in 6.3.2.1.
+ if (T->isFunctionType())
+ Decayed = getPointerType(T);
+
+ QualType Canonical = getCanonicalType(Decayed);
+
+ // Get the new insert position for the node we care about.
+ DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+
+ DecayedType *New =
+ new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
+ Types.push_back(New);
+ DecayedTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
/// getBlockPointerType - Return the uniqued reference to the type for
/// a pointer to the specified block.
QualType ASTContext::getBlockPointerType(QualType T) const {
@@ -2676,9 +2761,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv DefaultCC = Info.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
+ const CallingConv CallConv = Info.getCC();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -2690,11 +2774,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(FT, 0);
QualType Canonical;
- if (!ResultTy.isCanonical() ||
- getCanonicalCallConv(CallConv) != CallConv) {
- Canonical =
- getFunctionNoProtoType(getCanonicalType(ResultTy),
- Info.withCallingConv(getCanonicalCallConv(CallConv)));
+ if (!ResultTy.isCanonical()) {
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -2743,14 +2824,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
- const CallingConv DefaultCC = EPI.ExtInfo.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
-
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
+ if (!isCanonical) {
SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2760,8 +2837,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
CanonicalEPI.HasTrailingReturn = false;
CanonicalEPI.ExceptionSpecType = EST_None;
CanonicalEPI.NumExceptions = 0;
- CanonicalEPI.ExtInfo
- = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
// Result types do not have ARC lifetime qualifiers.
QualType CanResultTy = getCanonicalType(ResultTy);
@@ -2803,7 +2878,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
- newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
@@ -2856,13 +2930,11 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
"Template type parameter types are always available.");
if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
- assert(!Record->getPreviousDecl() &&
- "struct/union has previous declaration");
+ assert(Record->isFirstDecl() && "struct/union has previous declaration");
assert(!NeedsInjectedClassNameType(Record));
return getRecordType(Record);
} else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
- assert(!Enum->getPreviousDecl() &&
- "enum has previous declaration");
+ assert(Enum->isFirstDecl() && "enum has previous declaration");
return getEnumType(Enum);
} else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
@@ -4104,22 +4176,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
}
QualType ASTContext::getAdjustedParameterType(QualType T) const {
- // C99 6.7.5.3p7:
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- if (T->isArrayType())
- return getArrayDecayedType(T);
-
- // C99 6.7.5.3p8:
- // A declaration of a parameter as "function returning type"
- // shall be adjusted to "pointer to function returning type", as
- // in 6.3.2.1.
- if (T->isFunctionType())
- return getPointerType(T);
-
- return T;
+ if (T->isArrayType() || T->isFunctionType())
+ return getDecayedType(T);
+ return T;
}
QualType ASTContext::getSignatureParameterType(QualType T) const {
@@ -4364,12 +4423,27 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {
return Qualifiers::OCL_None;
}
+static const Type *getIntegerTypeForEnum(const EnumType *ET) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
+ return ET->getDecl()->getIntegerType().getTypePtr();
+ return NULL;
+}
+
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
const Type *LHSC = getCanonicalType(LHS).getTypePtr();
const Type *RHSC = getCanonicalType(RHS).getTypePtr();
+
+ // Unwrap enums to their underlying type.
+ if (const EnumType *ET = dyn_cast<EnumType>(LHSC))
+ LHSC = getIntegerTypeForEnum(ET);
+ if (const EnumType *ET = dyn_cast<EnumType>(RHSC))
+ RHSC = getIntegerTypeForEnum(ET);
+
if (LHSC == RHSC) return 0;
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
@@ -4484,7 +4558,7 @@ QualType ASTContext::getBlockDescriptorType() const {
UnsignedLongTy,
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size"
};
@@ -4525,7 +4599,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
getPointerType(VoidPtrTy)
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size",
"CopyFuncPtr",
@@ -4910,6 +4984,10 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
if (PD->isReadOnly()) {
S += ",R";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy)
+ S += ",C";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain)
+ S += ",&";
} else {
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
@@ -5200,12 +5278,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '[';
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
- if (getTypeSize(CAT->getElementType()) == 0)
- S += '0';
- else
- S += llvm::utostr(CAT->getSize().getZExtValue());
- } else {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ else {
//Variable length arrays are encoded as a regular array with 0 elements.
assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
"Unknown array type!");
@@ -5384,6 +5459,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// We encode the underlying type which comes out as
// {...};
S += '^';
+ if (FD && OPT->getInterfaceDecl()) {
+ // Prevent recursive encoding of fields in some rare cases.
+ ObjCInterfaceDecl *OI = OPT->getInterfaceDecl();
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
+ DeepCollectObjCIvars(OI, true, Ivars);
+ for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
+ if (cast<FieldDecl>(Ivars[i]) == FD) {
+ S += '{';
+ S += OI->getIdentifier()->getName();
+ S += '}';
+ return;
+ }
+ }
+ }
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
NULL,
@@ -5484,7 +5573,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (base->isEmpty())
continue;
uint64_t offs = toBits(layout.getVBaseClassOffset(base));
- if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
+ if (offs >= uint64_t(toBits(layout.getNonVirtualSize())) &&
+ FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(),
std::make_pair(offs, base));
}
@@ -6267,6 +6357,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
CanQualType ASTContext::getFromTargetType(unsigned Type) const {
switch (Type) {
case TargetInfo::NoInt: return CanQualType();
+ case TargetInfo::SignedChar: return SignedCharTy;
+ case TargetInfo::UnsignedChar: return UnsignedCharTy;
case TargetInfo::SignedShort: return ShortTy;
case TargetInfo::UnsignedShort: return UnsignedShortTy;
case TargetInfo::SignedInt: return IntTy;
@@ -6369,15 +6461,6 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
return false;
}
-/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
- if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
- return false;
-}
-
/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
/// Class<pr1, ...>.
bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
@@ -6890,7 +6973,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
// Compatible functions must have compatible calling conventions
- if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
+ if (lbaseInfo.getCC() != rbaseInfo.getCC())
return QualType();
// Regparm is part of the calling convention.
@@ -7000,10 +7083,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType,
- ArrayRef<QualType>(proto->arg_type_begin(),
- proto->getNumArgs()),
- EPI);
+ return getFunctionType(retType, proto->getArgTypes(), EPI);
}
if (allLTypes) return lhs;
@@ -7351,11 +7431,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
- QualType ResultType
- = getFunctionType(OldReturnType,
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ QualType ResultType =
+ getFunctionType(OldReturnType, FPT->getArgTypes(), EPI);
return ResultType;
}
}
@@ -7407,7 +7484,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) const {
- if (const EnumType *ET = dyn_cast<EnumType>(T))
+ if (const EnumType *ET = T->getAs<EnumType>())
T = ET->getDecl()->getIntegerType();
if (T->isBooleanType())
return 1;
@@ -7450,6 +7527,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
ASTMutationListener::~ASTMutationListener() { }
+void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
+ QualType ReturnType) {}
//===----------------------------------------------------------------------===//
// Builtin Type Computation
@@ -7507,6 +7586,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
"Bad modifiers used with 'v'!");
Type = Context.VoidTy;
break;
+ case 'h':
+ assert(HowLong == 0 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'f'!");
+ Type = Context.HalfTy;
+ break;
case 'f':
assert(HowLong == 0 && !Signed && !Unsigned &&
"Bad modifiers used with 'f'!");
@@ -7734,7 +7818,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
- FunctionType::ExtInfo EI;
+ FunctionType::ExtInfo EI(CC_C);
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
bool Variadic = (TypeStr[0] == '.');
@@ -7751,36 +7835,30 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
- GVALinkage External = GVA_StrongExternal;
-
- Linkage L = FD->getLinkage();
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!FD->isExternallyVisible())
return GVA_Internal;
-
- case ExternalLinkage:
- switch (FD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- External = GVA_StrongExternal;
- break;
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ GVALinkage External = GVA_StrongExternal;
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = GVA_StrongExternal;
+ break;
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ImplicitInstantiation:
- External = GVA_TemplateInstantiation;
- break;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
+ External = GVA_TemplateInstantiation;
+ break;
}
if (!FD->isInlined())
return External;
-
- if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+
+ if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) ||
+ FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
@@ -7804,37 +7882,23 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
}
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
- // If this is a static data member, compute the kind of template
- // specialization. Otherwise, this variable is not part of a
- // template.
- TemplateSpecializationKind TSK = TSK_Undeclared;
- if (VD->isStaticDataMember())
- TSK = VD->getTemplateSpecializationKind();
-
- Linkage L = VD->getLinkage();
-
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!VD->isExternallyVisible())
return GVA_Internal;
- case ExternalLinkage:
- switch (TSK) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return GVA_StrongExternal;
+ switch (VD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ return GVA_StrongExternal;
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Variable should not be instantiated");
- // Fall through to treat this like any other instantiation.
-
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Variable should not be instantiated");
+ // Fall through to treat this like any other instantiation.
- case TSK_ImplicitInstantiation:
- return GVA_TemplateInstantiation;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ImplicitInstantiation:
+ return GVA_TemplateInstantiation;
}
llvm_unreachable("Invalid Linkage!");
@@ -7918,16 +7982,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
}
-CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
+CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
+ bool IsCXXMethod) const {
// Pass through to the C++ ABI object
- return ABI->getDefaultMethodCallConv(isVariadic);
-}
+ if (IsCXXMethod)
+ return ABI->getDefaultMethodCallConv(IsVariadic);
-CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD &&
- getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
- return CC_Default;
- return CC;
+ return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C;
}
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -7941,9 +8002,9 @@ MangleContext *ASTContext::createMangleContext() {
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
- return createItaniumMangleContext(*this, getDiagnostics());
+ return ItaniumMangleContext::create(*this, getDiagnostics());
case TargetCXXABI::Microsoft:
- return createMicrosoftMangleContext(*this, getDiagnostics());
+ return MicrosoftMangleContext::create(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
}
@@ -7951,45 +8012,77 @@ MangleContext *ASTContext::createMangleContext() {
CXXABI::~CXXABI() {}
size_t ASTContext::getSideTableAllocatedMemory() const {
- return ASTRecordLayouts.getMemorySize()
- + llvm::capacity_in_bytes(ObjCLayouts)
- + llvm::capacity_in_bytes(KeyFunctions)
- + llvm::capacity_in_bytes(ObjCImpls)
- + llvm::capacity_in_bytes(BlockVarCopyInits)
- + llvm::capacity_in_bytes(DeclAttrs)
- + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember)
- + llvm::capacity_in_bytes(InstantiatedFromUsingDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
- + llvm::capacity_in_bytes(OverriddenMethods)
- + llvm::capacity_in_bytes(Types)
- + llvm::capacity_in_bytes(VariableArrayTypes)
- + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
-}
-
-void ASTContext::addUnnamedTag(const TagDecl *Tag) {
- // FIXME: This mangling should be applied to function local classes too
- if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
- !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
- return;
+ return ASTRecordLayouts.getMemorySize() +
+ llvm::capacity_in_bytes(ObjCLayouts) +
+ llvm::capacity_in_bytes(KeyFunctions) +
+ llvm::capacity_in_bytes(ObjCImpls) +
+ llvm::capacity_in_bytes(BlockVarCopyInits) +
+ llvm::capacity_in_bytes(DeclAttrs) +
+ llvm::capacity_in_bytes(TemplateOrInstantiation) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
+ llvm::capacity_in_bytes(OverriddenMethods) +
+ llvm::capacity_in_bytes(Types) +
+ llvm::capacity_in_bytes(VariableArrayTypes) +
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+}
+
+/// getIntTypeForBitwidth -
+/// sets integer QualTy according to specified details:
+/// bitwidth, signed/unsigned.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth,
+ unsigned Signed) const {
+ TargetInfo::IntType Ty = getTargetInfo().getIntTypeByWidth(DestWidth, Signed);
+ CanQualType QualTy = getFromTargetType(Ty);
+ if (!QualTy && DestWidth == 128)
+ return Signed ? Int128Ty : UnsignedInt128Ty;
+ return QualTy;
+}
+
+/// getRealTypeForBitwidth -
+/// sets floating point QualTy according to specified bitwidth.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const {
+ TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth);
+ switch (Ty) {
+ case TargetInfo::Float:
+ return FloatTy;
+ case TargetInfo::Double:
+ return DoubleTy;
+ case TargetInfo::LongDouble:
+ return LongDoubleTy;
+ case TargetInfo::NoFloat:
+ return QualType();
+ }
- std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
- UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
- UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+ llvm_unreachable("Unhandled TargetInfo::RealType value");
}
-int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
- llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
- UnnamedMangleNumbers.find(Tag);
- return I != UnnamedMangleNumbers.end() ? I->second : -1;
+void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
+ if (Number > 1)
+ MangleNumbers[ND] = Number;
}
-unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
- CXXRecordDecl *Lambda = CallOperator->getParent();
- return LambdaMangleContexts[Lambda->getDeclContext()]
- .getManglingNumber(CallOperator);
+unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
+ llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I =
+ MangleNumbers.find(ND);
+ return I != MangleNumbers.end() ? I->second : 1;
}
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(const DeclContext *DC) {
+ assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
+ MangleNumberingContext *&MCtx = MangleNumberingContexts[DC];
+ if (!MCtx)
+ MCtx = createMangleNumberingContext();
+ return *MCtx;
+}
+
+MangleNumberingContext *ASTContext::createMangleNumberingContext() const {
+ return ABI->createMangleNumberingContext();
+}
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
ParamIndices[D] = index;
@@ -8001,3 +8094,160 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
"ParmIndices lacks entry set by ParmVarDecl");
return I->second;
}
+
+APValue *
+ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
+ bool MayCreate) {
+ assert(E && E->getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate)
+ return &MaterializedTemporaryValues[E];
+
+ llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =
+ MaterializedTemporaryValues.find(E);
+ return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
+}
+
+bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
+ const llvm::Triple &T = getTargetInfo().getTriple();
+ if (!T.isOSDarwin())
+ return false;
+
+ if (!(T.isiOS() && T.isOSVersionLT(7)) &&
+ !(T.isMacOSX() && T.isOSVersionLT(10, 9)))
+ return false;
+
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ CharUnits sizeChars = getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth();
+ return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits);
+}
+
+namespace {
+
+ /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
+ /// parents as defined by the \c RecursiveASTVisitor.
+ ///
+ /// Note that the relationship described here is purely in terms of AST
+ /// traversal - there are other relationships (for example declaration context)
+ /// in the AST that are better modeled by special matchers.
+ ///
+ /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
+ class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
+
+ public:
+ /// \brief Builds and returns the translation unit's parent map.
+ ///
+ /// The caller takes ownership of the returned \c ParentMap.
+ static ASTContext::ParentMap *buildMap(TranslationUnitDecl &TU) {
+ ParentMapASTVisitor Visitor(new ASTContext::ParentMap);
+ Visitor.TraverseDecl(&TU);
+ return Visitor.Parents;
+ }
+
+ private:
+ typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
+
+ ParentMapASTVisitor(ASTContext::ParentMap *Parents) : Parents(Parents) {
+ }
+
+ bool shouldVisitTemplateInstantiations() const {
+ return true;
+ }
+ bool shouldVisitImplicitCode() const {
+ return true;
+ }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const {
+ return false;
+ }
+
+ template <typename T>
+ bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
+ if (Node == NULL)
+ return true;
+ if (ParentStack.size() > 0)
+ // FIXME: Currently we add the same parent multiple times, for example
+ // when we visit all subexpressions of template instantiations; this is
+ // suboptimal, bug benign: the only way to visit those is with
+ // hasAncestor / hasParent, and those do not create new matches.
+ // The plan is to enable DynTypedNode to be storable in a map or hash
+ // map. The main problem there is to implement hash functions /
+ // comparison operators for all types that DynTypedNode supports that
+ // do not have pointer identity.
+ (*Parents)[Node].push_back(ParentStack.back());
+ ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
+ bool Result = (this ->* traverse) (Node);
+ ParentStack.pop_back();
+ return Result;
+ }
+
+ bool TraverseDecl(Decl *DeclNode) {
+ return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
+ }
+
+ bool TraverseStmt(Stmt *StmtNode) {
+ return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
+ }
+
+ ASTContext::ParentMap *Parents;
+ llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
+
+ friend class RecursiveASTVisitor<ParentMapASTVisitor>;
+ };
+
+} // end namespace
+
+ASTContext::ParentVector
+ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ if (!AllParents) {
+ // We always need to run over the whole translation unit, as
+ // hasAncestor can escape any subtree.
+ AllParents.reset(
+ ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
+ }
+ ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
+ if (I == AllParents->end()) {
+ return ParentVector();
+ }
+ return I->second;
+}
+
+bool
+ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
+ const ObjCMethodDecl *MethodImpl) {
+ // No point trying to match an unavailable/deprecated mothod.
+ if (MethodDecl->hasAttr<UnavailableAttr>()
+ || MethodDecl->hasAttr<DeprecatedAttr>())
+ return false;
+ if (MethodDecl->getObjCDeclQualifier() !=
+ MethodImpl->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(MethodDecl->getResultType(),
+ MethodImpl->getResultType()))
+ return false;
+
+ if (MethodDecl->param_size() != MethodImpl->param_size())
+ return false;
+
+ for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(),
+ IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(),
+ EF = MethodDecl->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
+ const ParmVarDecl *DeclVar = (*IF);
+ const ParmVarDecl *ImplVar = (*IM);
+ if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(DeclVar->getType(), ImplVar->getType()))
+ return false;
+ }
+ return (MethodDecl->isVariadic() == MethodImpl->isVariadic());
+
+}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 1ed65e476ce3..fce8f64b3328 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument(
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- N.printName(OS);
+ OS << DeclarationName::getFromOpaqueInteger(Val);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -459,6 +458,10 @@ class TemplateDiff {
/// FromValueDecl, ToValueDecl - Whether the argument is a decl.
ValueDecl *FromValueDecl, *ToValueDecl;
+ /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of
+ /// operator before it.
+ bool FromAddressOf, ToAddressOf;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -469,7 +472,8 @@ class TemplateDiff {
: Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
- ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
+ ToValueDecl(0), FromAddressOf(false), ToAddressOf(false),
+ FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -526,9 +530,12 @@ class TemplateDiff {
}
/// SetNode - Set FromValueDecl and ToValueDecl of the current node.
- void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromAddressOf, bool ToAddressOf) {
FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ FlatTree[CurrentNode].FromAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].ToAddressOf = ToAddressOf;
}
/// SetSame - Sets the same flag of the current node.
@@ -620,9 +627,12 @@ class TemplateDiff {
}
/// GetNode - Gets the FromValueDecl and ToValueDecl.
- void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
+ bool &FromAddressOf, bool &ToAddressOf) {
FromValueDecl = FlatTree[ReadNode].FromValueDecl;
ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ FromAddressOf = FlatTree[ReadNode].FromAddressOf;
+ ToAddressOf = FlatTree[ReadNode].ToAddressOf;
}
/// NodeIsSame - Returns true the arguments are the same.
@@ -821,8 +831,10 @@ class TemplateDiff {
void DiffTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
// Begin descent into diffing template tree.
- TemplateParameterList *Params =
+ TemplateParameterList *ParamsFrom =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
+ TemplateParameterList *ParamsTo =
+ ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
@@ -831,15 +843,18 @@ class TemplateDiff {
// Get the parameter at index TotalArgs. If index is larger
// than the total number of parameters, then there is an
// argument pack, so re-use the last parameter.
- NamedDecl *ParamND = Params->getParam(
- (TotalArgs < Params->size()) ? TotalArgs
- : Params->size() - 1);
+ unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
+ NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex);
+
// Handle Types
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
FromType = GetType(FromIter, DefaultTTPD);
- ToType = GetType(ToIter, DefaultTTPD);
+ // A forward declaration can have no default arg but the actual class
+ // can, don't mix up iterators and get the original parameter.
+ ToType = GetType(
+ ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex)));
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
@@ -942,7 +957,14 @@ class TemplateDiff {
FromValueDecl = GetValueDecl(FromIter, FromExpr);
if (!HasToValueDecl && ToExpr)
ToValueDecl = GetValueDecl(ToIter, ToExpr);
- Tree.SetNode(FromValueDecl, ToValueDecl);
+ QualType ArgumentType = DefaultNTTPD->getType();
+ bool FromAddressOf = FromValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !FromValueDecl->getType()->isArrayType();
+ bool ToAddressOf = ToValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !ToValueDecl->getType()->isArrayType();
+ Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
Tree.SetSame(FromValueDecl && ToValueDecl &&
FromValueDecl->getCanonicalDecl() ==
ToValueDecl->getCanonicalDecl());
@@ -973,7 +995,7 @@ class TemplateDiff {
/// makeTemplateList - Dump every template alias into the vector.
static void makeTemplateList(
- SmallVector<const TemplateSpecializationType*, 1> &TemplateList,
+ SmallVectorImpl<const TemplateSpecializationType *> &TemplateList,
const TemplateSpecializationType *TST) {
while (TST) {
TemplateList.push_back(TST);
@@ -1008,7 +1030,7 @@ class TemplateDiff {
makeTemplateList(FromTemplateList, FromTST);
makeTemplateList(ToTemplateList, ToTST);
- SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
+ SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
@@ -1037,10 +1059,14 @@ class TemplateDiff {
if (!Iter.isEnd())
return Iter->getAsType();
- if (!isVariadic)
- return DefaultTTPD->getDefaultArgument();
+ if (isVariadic)
+ return QualType();
+
+ QualType ArgType = DefaultTTPD->getDefaultArgument();
+ if (ArgType->isDependentType())
+ return Iter.getDesugar().getAsType();
- return QualType();
+ return ArgType;
}
/// GetExpr - Retrieves the template expression argument, including default
@@ -1080,7 +1106,7 @@ class TemplateDiff {
return ArgExpr->EvaluateKnownConstInt(Context);
}
- /// GetValueDecl - Retrieves the template integer argument, including
+ /// GetValueDecl - Retrieves the template Decl argument, including
/// default expression argument.
ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
// Default, value-depenedent expressions require fetching
@@ -1095,7 +1121,12 @@ class TemplateDiff {
default:
assert(0 && "Unexpected template argument kind");
}
- return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
+ if (!DRE) {
+ DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr());
+ }
+
+ return DRE->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
@@ -1228,9 +1259,10 @@ class TemplateDiff {
}
case DiffTree::Declaration: {
ValueDecl *FromValueDecl, *ToValueDecl;
- Tree.GetNode(FromValueDecl, ToValueDecl);
- PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
- Tree.ToDefault(), Tree.NodeIsSame());
+ bool FromAddressOf, ToAddressOf;
+ Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Template: {
@@ -1478,7 +1510,8 @@ class TemplateDiff {
/// PrintDecl - Handles printing of Decl arguments, highlighting
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromDefault, bool ToDefault, bool Same) {
+ bool FromAddressOf, bool ToAddressOf, bool FromDefault,
+ bool ToDefault, bool Same) {
assert((FromValueDecl || ToValueDecl) &&
"Only one Decl argument may be NULL");
@@ -1487,15 +1520,21 @@ class TemplateDiff {
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
+ if (ToAddressOf)
+ OS << "&";
OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 340cc41f7e81..2f402559f4da 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
@@ -62,6 +63,9 @@ namespace {
// Null statements
static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+ // Undeserialized entities
+ static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true };
+
// CastKind from CastExpr's
static const TerminalColor CastColor = { raw_ostream::RED, false };
@@ -173,6 +177,7 @@ namespace {
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
+ void dumpLookups(const DeclContext *DC);
void dumpAttr(const Attr *A);
// C++ Utilities
@@ -214,6 +219,11 @@ namespace {
const ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D);
+ void VisitVarTemplateDecl(const VarTemplateDecl *D);
+ void VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
@@ -244,6 +254,7 @@ namespace {
void VisitAttributedStmt(const AttributedStmt *Node);
void VisitLabelStmt(const LabelStmt *Node);
void VisitGotoStmt(const GotoStmt *Node);
+ void VisitCXXCatchStmt(const CXXCatchStmt *Node);
// Exprs
void VisitExpr(const Expr *Node);
@@ -271,9 +282,14 @@ namespace {
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
+ void VisitLambdaExpr(const LambdaExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getLambdaClass());
+ }
// ObjC
void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
@@ -329,8 +345,8 @@ void ASTDumper::indent() {
OS << "\n";
ColorScope Color(*this, IndentColor);
- for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
- E = Indents.end();
+ for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(),
+ E = Indents.end();
I != E; ++I) {
switch (*I) {
case IT_Child:
@@ -449,9 +465,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
ColorScope Color(*this, DeclNameColor);
- OS << " '";
- ND->getDeclName().printName(OS);
- OS << "'";
+ OS << " '" << ND->getDeclName() << '\'';
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
@@ -479,20 +493,76 @@ bool ASTDumper::hasNodes(const DeclContext *DC) {
if (!DC)
return false;
- return DC->decls_begin() != DC->decls_end();
+ return DC->hasExternalLexicalStorage() ||
+ DC->noload_decls_begin() != DC->noload_decls_end();
}
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ bool HasUndeserializedDecls = DC->hasExternalLexicalStorage();
+ for (DeclContext::decl_iterator I = DC->noload_decls_begin(),
+ E = DC->noload_decls_end();
I != E; ++I) {
DeclContext::decl_iterator Next = I;
++Next;
- if (Next == E)
+ if (Next == E && !HasUndeserializedDecls)
lastChild();
dumpDecl(*I);
}
+ if (HasUndeserializedDecls) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized declarations>";
+ }
+}
+
+void ASTDumper::dumpLookups(const DeclContext *DC) {
+ IndentScope Indent(*this);
+
+ OS << "StoredDeclsMap ";
+ dumpBareDeclRef(cast<Decl>(DC));
+
+ const DeclContext *Primary = DC->getPrimaryContext();
+ if (Primary != DC) {
+ OS << " primary";
+ dumpPointer(cast<Decl>(Primary));
+ }
+
+ bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
+
+ DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
+ E = Primary->noload_lookups_end();
+ while (I != E) {
+ DeclarationName Name = I.getLookupName();
+ DeclContextLookupResult R = *I++;
+ if (I == E && !HasUndeserializedLookups)
+ lastChild();
+
+ IndentScope Indent(*this);
+ OS << "DeclarationName ";
+ {
+ ColorScope Color(*this, DeclNameColor);
+ OS << '\'' << Name << '\'';
+ }
+
+ for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
+ RI != RE; ++RI) {
+ if (RI + 1 == RE)
+ lastChild();
+ dumpDeclRef(*RI);
+ if ((*RI)->isHidden())
+ OS << " hidden";
+ }
+ }
+
+ if (HasUndeserializedLookups) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized lookups>";
+ }
}
void ASTDumper::dumpAttr(const Attr *A) {
@@ -511,21 +581,29 @@ void ASTDumper::dumpAttr(const Attr *A) {
#include "clang/AST/AttrDump.inc"
}
-static Decl *getPreviousDeclImpl(...) {
- return 0;
+static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
+
+template<typename T>
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) {
+ const T *First = D->getFirstDecl();
+ if (First != D)
+ OS << " first " << First;
}
template<typename T>
-static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
- return D->getPreviousDecl();
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) {
+ const T *Prev = D->getPreviousDecl();
+ if (Prev)
+ OS << " prev " << Prev;
}
-/// Get the previous declaration in the redeclaration chain for a declaration.
-static const Decl *getPreviousDecl(const Decl *D) {
+/// Dump the previous declaration in the redeclaration chain for a declaration,
+/// if any.
+static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) {
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
- return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+ return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D));
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
}
@@ -662,20 +740,25 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpPointer(D);
if (D->getLexicalDeclContext() != D->getDeclContext())
OS << " parent " << cast<Decl>(D->getDeclContext());
- if (const Decl *Prev = getPreviousDecl(D))
- OS << " prev " << Prev;
+ dumpPreviousDecl(OS, D);
dumpSourceRange(D->getSourceRange());
+ if (Module *M = D->getOwningModule())
+ OS << " in " << M->getFullModuleName();
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->isHidden())
+ OS << " hidden";
bool HasAttrs = D->attr_begin() != D->attr_end();
- bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ const FullComment *Comment =
+ D->getASTContext().getLocalCommentForDeclUncached(D);
// Decls within functions are visited by the body
bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
hasNodes(dyn_cast<DeclContext>(D));
- setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ setMoreChildren(HasAttrs || Comment || HasDeclContext);
ConstDeclVisitor<ASTDumper>::Visit(D);
- setMoreChildren(HasComment || HasDeclContext);
+ setMoreChildren(Comment || HasDeclContext);
for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
I != E; ++I) {
if (I + 1 == E)
@@ -685,7 +768,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
setMoreChildren(HasDeclContext);
lastChild();
- dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+ dumpFullComment(Comment);
+
+ if (D->isInvalidDecl())
+ OS << " invalid";
setMoreChildren(false);
if (HasDeclContext)
@@ -722,6 +808,8 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
dumpName(D);
if (D->isModulePrivate())
OS << " __module_private__";
+ if (D->isCompleteDefinition())
+ OS << " definition";
}
void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
@@ -764,6 +852,19 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
else if (D->isDeletedAsWritten())
OS << " delete";
+ if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ switch (EPI.ExceptionSpecType) {
+ default: break;
+ case EST_Unevaluated:
+ OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl;
+ break;
+ case EST_Uninstantiated:
+ OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate;
+ break;
+ }
+ }
+
bool OldMoreChildren = hasMoreChildren();
const FunctionTemplateSpecializationInfo *FTSI =
D->getTemplateSpecializationInfo();
@@ -1012,6 +1113,49 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
dumpTemplateArgumentListInfo(D->templateArgs());
}
+void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+
+ VarTemplateDecl::spec_iterator I = D->spec_begin();
+ VarTemplateDecl::spec_iterator E = D->spec_end();
+ if (I == E)
+ lastChild();
+ dumpDecl(D->getTemplatedDecl());
+ for (; I != E; ++I) {
+ VarTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D) {
+ dumpTemplateArgumentList(D->getTemplateArgs());
+ VisitVarDecl(D);
+}
+
+void ASTDumper::VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D) {
+ dumpTemplateParameters(D->getTemplateParameters());
+ VisitVarTemplateSpecializationDecl(D);
+}
+
void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->wasDeclaredWithTypename())
OS << " typename";
@@ -1097,6 +1241,8 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpType(D->getType());
if (D->getSynthesize())
OS << " synthesize";
+ if (D->getBackingIvarReferencedInAccessor())
+ OS << " BackingIvarReferencedInAccessor";
switch (D->getAccessControl()) {
case ObjCIvarDecl::None:
@@ -1331,7 +1477,7 @@ void ASTDumper::dumpStmt(const Stmt *S) {
return;
}
- setMoreChildren(S->children());
+ setMoreChildren(!S->children().empty());
ConstStmtVisitor<ASTDumper>::Visit(S);
setMoreChildren(false);
for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
@@ -1385,6 +1531,11 @@ void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
dumpPointer(Node->getLabel());
}
+void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
+ VisitStmt(Node);
+ dumpDecl(Node->getExceptionDecl());
+}
+
//===----------------------------------------------------------------------===//
// Expr dumping methods.
//===----------------------------------------------------------------------===//
@@ -1510,6 +1661,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
@@ -1659,6 +1811,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
dumpCXXTemporary(Node->getTemporary());
}
+void
+ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
+ VisitExpr(Node);
+ if (const ValueDecl *VD = Node->getExtendingDecl()) {
+ OS << " extended by ";
+ dumpBareDeclRef(VD);
+ }
+}
+
void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
VisitExpr(Node);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
@@ -1949,6 +2110,20 @@ void Decl::dumpColor() const {
&getASTContext().getSourceManager(), /*ShowColors*/true);
P.dumpDecl(this);
}
+
+void DeclContext::dumpLookups() const {
+ dumpLookups(llvm::errs());
+}
+
+void DeclContext::dumpLookups(raw_ostream &OS) const {
+ const DeclContext *DC = this;
+ while (!DC->isTranslationUnit())
+ DC = DC->getParent();
+ ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
+ ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
+ P.dumpLookups(this);
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 915eb6feb85e..e16015b7c4ed 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -106,6 +106,8 @@ namespace clang {
bool ImportDefinition(RecordDecl *From, RecordDecl *To,
ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
@@ -120,9 +122,12 @@ namespace clang {
SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
+ bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
+ bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
@@ -157,7 +162,9 @@ namespace clang {
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D);
-
+ Decl *VisitVarTemplateDecl(VarTemplateDecl *D);
+ Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+
// Importing statements
Stmt *VisitStmt(Stmt *S);
@@ -400,6 +407,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Decayed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecayedType>(T1)->getPointeeType(),
+ cast<DecayedType>(T2)->getPointeeType()))
+ return false;
+ break;
+
case Type::Pointer:
if (!IsStructurallyEquivalent(Context,
cast<PointerType>(T1)->getPointeeType(),
@@ -1695,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
+ return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ /*IsDependent*/false);
}
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
@@ -1968,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
= FromData.HasDeclaredCopyConstructorWithConstParam;
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
- ToData.FailedImplicitMoveConstructor
- = FromData.FailedImplicitMoveConstructor;
- ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
@@ -2010,6 +2022,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
return false;
}
+bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition())
+ return false;
+
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return false;
+}
+
bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind) {
if (To->getDefinition() || To->isBeingDefined()) {
@@ -2148,13 +2175,30 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
RecordDecl *ToRecord, bool Complain) {
+ // Eliminate a potential failure point where we attempt to re-import
+ // something we're trying to import while completing ToRecord.
+ Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord);
+ if (ToOrigin) {
+ RecordDecl *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin);
+ if (ToOriginRecord)
+ ToRecord = ToOriginRecord;
+ }
+
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
- Importer.getToContext(),
+ ToRecord->getASTContext(),
Importer.getNonEquivalentDecls(),
false, Complain);
return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord);
}
+bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain) {
+ StructuralEquivalenceContext Ctx(
+ Importer.getFromContext(), Importer.getToContext(),
+ Importer.getNonEquivalentDecls(), false, Complain);
+ return Ctx.IsStructurallyEquivalent(FromVar, ToVar);
+}
+
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2181,6 +2225,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
return Ctx.IsStructurallyEquivalent(From, To);
}
+bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
+ VarTemplateDecl *To) {
+ StructuralEquivalenceContext Ctx(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getNonEquivalentDecls());
+ return Ctx.IsStructurallyEquivalent(From, To);
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -2610,8 +2662,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
continue;
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
- if (isExternalLinkage(FoundFunction->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundFunction->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
@@ -2664,10 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FromEPI.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getResultType(),
- ArrayRef<QualType>(FromFPT->arg_type_begin(),
- FromFPT->getNumArgs()),
- DefaultEPI);
+ FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI);
usedDifferentExceptionSpec = true;
}
}
@@ -2878,7 +2927,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
- Name)) {
+ !Name.isEmpty())) {
Importer.Imported(D, FoundField);
return FoundField;
}
@@ -2965,7 +3014,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
- BitWidth, D->getSynthesize());
+ BitWidth, D->getSynthesize(),
+ D->getBackingIvarReferencedInAccessor());
ToIvar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIvar);
LexicalDC->addDeclInternal(ToIvar);
@@ -2995,8 +3045,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
- if (isExternalLinkage(FoundVar->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundVar->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
@@ -3088,13 +3138,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
LexicalDC->addDeclInternal(ToVar);
// Merge the initializer.
- // FIXME: Can we really import any initializer? Alternatively, we could force
- // ourselves to import every declaration of a variable and then only use
- // getInit() here.
- ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+ if (ImportDefinition(D, ToVar))
+ return 0;
- // FIXME: Other bits to merge?
-
return ToVar;
}
@@ -4108,6 +4154,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return D2;
}
+Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ // If this variable has a definition in the translation unit we're coming
+ // from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition =
+ cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition());
+ if (Definition && Definition != D->getTemplatedDecl()) {
+ Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate());
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this variable template.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // We may already have a template of the same name; try to find and match it.
+ assert(!DC->isFunctionOrMethod() &&
+ "Variable templates cannot be declared at function scope");
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ Decl *Found = FoundDecls[I];
+ if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ // The variable templates structurally match; call it the same template.
+ Importer.Imported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.Imported(D, FoundTemplate);
+ }
+ }
+
+ ConflictingDecls.push_back(FoundDecls[I]);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+
+ if (!Name)
+ return 0;
+
+ VarDecl *DTemplated = D->getTemplatedDecl();
+
+ // Import the type.
+ QualType T = Importer.Import(DTemplated->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
+ TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo());
+ VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc,
+ IdLoc, Name.getAsIdentifierInfo(), T,
+ TInfo, DTemplated->getStorageClass());
+ D2Templated->setAccess(DTemplated->getAccess());
+ D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
+ D2Templated->setLexicalDeclContext(LexicalDC);
+
+ // Importer.Imported(DTemplated, D2Templated);
+ // LexicalDC->addDeclInternal(D2Templated);
+
+ // Merge the initializer.
+ if (ImportDefinition(DTemplated, D2Templated))
+ return 0;
+
+ // Create the variable template declaration itself.
+ TemplateParameterList *TemplateParams =
+ ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ VarTemplateDecl *D2 = VarTemplateDecl::Create(
+ Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated,
+ /*PrevDecl=*/0);
+ D2Templated->setDescribedVarTemplate(D2);
+
+ D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+
+ // Note the relationship between the variable templates.
+ Importer.Imported(D, D2);
+ Importer.Imported(DTemplated, D2Templated);
+
+ if (DTemplated->isThisDeclarationADefinition() &&
+ !D2Templated->isThisDeclarationADefinition()) {
+ // FIXME: Import definition!
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>(
+ Importer.Import(D->getSpecializedTemplate()));
+ if (!VarTemplate)
+ return 0;
+
+ // Import the context of this declaration.
+ DeclContext *DC = VarTemplate->getDeclContext();
+ if (!DC)
+ return 0;
+
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ }
+
+ // Import the location of this declaration.
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
+
+ // Import template arguments.
+ SmallVector<TemplateArgument, 2> TemplateArgs;
+ if (ImportTemplateArguments(D->getTemplateArgs().data(),
+ D->getTemplateArgs().size(), TemplateArgs))
+ return 0;
+
+ // Try to find an existing specialization with these template arguments.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
+ TemplateArgs.data(), TemplateArgs.size(), InsertPos);
+ if (D2) {
+ // We already have a variable template specialization with these template
+ // arguments.
+
+ // FIXME: Check for specialization vs. instantiation errors.
+
+ if (VarDecl *FoundDef = D2->getDefinition()) {
+ if (!D->isThisDeclarationADefinition() ||
+ IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // variable.
+ return Importer.Imported(D, FoundDef);
+ }
+ }
+ } else {
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+
+ // Create a new specialization.
+ D2 = VarTemplateSpecializationDecl::Create(
+ Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo,
+ D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size());
+ D2->setSpecializationKind(D->getSpecializationKind());
+ D2->setTemplateArgsInfo(D->getTemplateArgsInfo());
+
+ // Add this specialization to the class template.
+ VarTemplate->AddSpecialization(D2, InsertPos);
+
+ // Import the qualifier, if any.
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
+
+ // Add the specialization to this context.
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+ }
+ Importer.Imported(D, D2);
+
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2))
+ return 0;
+
+ return D2;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
@@ -4406,7 +4651,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
} else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) {
// When we've finished transforming a typedef, see whether it was the
// typedef for an anonymous tag.
- for (SmallVector<TagDecl *, 4>::iterator
+ for (SmallVectorImpl<TagDecl *>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
new file mode 100644
index 000000000000..ae47ea98882b
--- /dev/null
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -0,0 +1,105 @@
+//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a dynamic type identifier and a dynamically typed node container
+// that can be used to store an AST base node at runtime in the same storage in
+// a type safe way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
+ { NKI_None, "<None>" },
+ { NKI_None, "CXXCtorInitializer" },
+ { NKI_None, "TemplateArgument" },
+ { NKI_None, "NestedNameSpecifier" },
+ { NKI_None, "NestedNameSpecifierLoc" },
+ { NKI_None, "QualType" },
+ { NKI_None, "TypeLoc" },
+ { NKI_None, "Decl" },
+#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
+#include "clang/AST/DeclNodes.inc"
+ { NKI_None, "Stmt" },
+#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
+#include "clang/AST/StmtNodes.inc"
+ { NKI_None, "Type" },
+#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
+#include "clang/AST/TypeNodes.def"
+};
+
+bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
+ return isBaseOf(KindId, Other.KindId);
+}
+
+bool ASTNodeKind::isSame(ASTNodeKind Other) const {
+ return KindId != NKI_None && KindId == Other.KindId;
+}
+
+bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
+ if (Base == NKI_None || Derived == NKI_None) return false;
+ while (Derived != Base && Derived != NKI_None)
+ Derived = AllKindInfo[Derived].ParentId;
+ return Derived == Base;
+}
+
+StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+
+void DynTypedNode::print(llvm::raw_ostream &OS,
+ const PrintingPolicy &PP) const {
+ if (const TemplateArgument *TA = get<TemplateArgument>())
+ TA->print(PP, OS);
+ else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
+ NNS->print(OS, PP);
+ else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ NNSL->getNestedNameSpecifier()->print(OS, PP);
+ else if (const QualType *QT = get<QualType>())
+ QT->print(OS, PP);
+ else if (const TypeLoc *TL = get<TypeLoc>())
+ TL->getType().print(OS, PP);
+ else if (const Decl *D = get<Decl>())
+ D->print(OS, PP);
+ else if (const Stmt *S = get<Stmt>())
+ S->printPretty(OS, 0, PP);
+ else if (const Type *T = get<Type>())
+ QualType(T, 0).print(OS, PP);
+ else
+ OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
+}
+
+void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const {
+ if (const Decl *D = get<Decl>())
+ D->dump(OS);
+ else if (const Stmt *S = get<Stmt>())
+ S->dump(OS, SM);
+ else
+ OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
+}
+
+SourceRange DynTypedNode::getSourceRange() const {
+ if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
+ return CCI->getSourceRange();
+ if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ return NNSL->getSourceRange();
+ if (const TypeLoc *TL = get<TypeLoc>())
+ return TL->getSourceRange();
+ if (const Decl *D = get<Decl>())
+ return D->getSourceRange();
+ if (const Stmt *S = get<Stmt>())
+ return S->getSourceRange();
+ return SourceRange();
+}
+
+} // end namespace ast_type_traits
+} // end namespace clang
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index daf65e56bdc6..7af3c8b16263 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
Attr::~Attr() { }
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e804fe720558..461e8b3ac18e 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangAST
ASTDiagnostic.cpp
ASTDumper.cpp
ASTImporter.cpp
+ ASTTypeTraits.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
@@ -25,7 +26,6 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- DumpXML.cpp
Expr.cpp
ExprClassification.cpp
ExprConstant.cpp
@@ -34,8 +34,8 @@ add_clang_library(clangAST
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
- LambdaMangleContext.cpp
Mangle.cpp
+ MangleNumberingContext.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 6d67d9a12b55..89203f18ca77 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -21,6 +21,7 @@ namespace clang {
class ASTContext;
class MemberPointerType;
+class MangleNumberingContext;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
@@ -34,9 +35,12 @@ public:
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
- // Returns whether the given class is nearly empty, with just virtual pointers
- // and no data except possibly virtual bases.
+ /// Returns whether the given class is nearly empty, with just virtual
+ /// pointers and no data except possibly virtual bases.
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0;
+
+ /// Returns a new mangling number context for this C++ ABI.
+ virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
};
/// Creates an instance of a C++ ABI class.
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 0e0b35d92adf..b51014b7428f 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -168,9 +168,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
}
}
- if (Queue.empty()) break;
- Record = Queue.back(); // not actually a queue.
- Queue.pop_back();
+ if (Queue.empty())
+ break;
+ Record = Queue.pop_back_val(); // not actually a queue.
}
return AllMatches;
@@ -447,7 +447,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
- SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
= Overrides[OverriddenSubobject];
if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
Overriding) == SubobjectOverrides.end())
@@ -650,11 +650,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
SOEnd = OM->second.end();
SO != SOEnd;
++SO) {
- SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second;
if (Overriding.size() < 2)
continue;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
Pos = Overriding.begin(), PosEnd = Overriding.end();
Pos != PosEnd;
/* increment in loop */) {
@@ -669,7 +669,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
// in a base class subobject that hides the virtual base class
// subobject.
bool Hidden = false;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
OP = Overriding.begin(), OPEnd = Overriding.end();
OP != OPEnd && !Hidden;
++OP) {
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 68c73fd48e3c..f24a23d34c57 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -41,14 +42,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
return good();
}
+LLVM_ATTRIBUTE_UNUSED
static inline bad implements_child_begin_end(
Comment::child_iterator (Comment::*)() const) {
return bad();
}
#define ASSERT_IMPLEMENTS_child_begin(function) \
- (void) sizeof(good(implements_child_begin_end(function)))
+ (void) good(implements_child_begin_end(function))
+LLVM_ATTRIBUTE_UNUSED
static inline void CheckCommentASTNodes() {
#define ABSTRACT_COMMENT(COMMENT)
#define COMMENT(CLASS, PARENT) \
@@ -94,9 +97,7 @@ Comment::child_iterator Comment::child_end() const {
bool TextComment::isWhitespaceNoCache() const {
for (StringRef::const_iterator I = Text.begin(), E = Text.end();
I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\f' && C != '\v')
+ if (!clang::isWhitespace(*I))
return false;
}
return true;
@@ -293,12 +294,14 @@ void DeclInfo::fill() {
StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
assert(isParamIndexValid());
- return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
+ if (isVarArgParam())
+ return "...";
+ return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
}
StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
assert(isPositionValid());
- const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
+ const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
for (unsigned i = 0, e = getDepth(); i != e; ++i) {
if (i == e-1)
return TPL->getParam(getIndex(i))->getName();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e24d542c9623..01bd12e5fefa 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -43,6 +43,49 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
+static void
+HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
+ StringRef Typo, const CommandInfo *Command) {
+ const unsigned MaxEditDistance = 1;
+ unsigned BestEditDistance = MaxEditDistance + 1;
+ StringRef Name = Command->Name;
+
+ unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 1)
+ return;
+ unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
+ if (EditDistance > MaxEditDistance)
+ return;
+ if (EditDistance == BestEditDistance)
+ BestCommand.push_back(Command);
+ else if (EditDistance < BestEditDistance) {
+ BestCommand.clear();
+ BestCommand.push_back(Command);
+ BestEditDistance = EditDistance;
+ }
+}
+
+const CommandInfo *
+CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
+ // single character command impostures, such as \t or \n must not go
+ // through the fixit logic.
+ if (Typo.size() <= 1)
+ return NULL;
+
+ SmallVector<const CommandInfo *, 2> BestCommand;
+
+ const int NumOfCommands = llvm::array_lengthof(Commands);
+ for (int i = 0; i < NumOfCommands; i++)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
+
+ for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
+ if (!RegisteredCommands[i]->IsUnknownCommand)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
+
+ return (BestCommand.size() != 1) ? NULL : BestCommand[0];
+}
+
CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 70410d61085d..01ed3ce80a66 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -157,7 +157,7 @@ const char *skipDecimalCharacterReference(const char *BufferPtr,
}
const char *skipHexCharacterReference(const char *BufferPtr,
- const char *BufferEnd) {
+ const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr))
return BufferPtr;
@@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
}
llvm_unreachable("buffer end hit before '*/' was seen");
}
+
} // unnamed namespace
void Lexer::lexCommentText(Token &T) {
@@ -352,10 +353,20 @@ void Lexer::lexCommentText(Token &T) {
const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
if (!Info) {
- formTokenWithChars(T, TokenPtr, tok::unknown_command);
- T.setUnknownCommandName(CommandName);
- Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
- return;
+ if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) {
+ StringRef CorrectedName = Info->Name;
+ SourceLocation Loc = getSourceLocation(BufferPtr);
+ SourceRange CommandRange(Loc.getLocWithOffset(1),
+ getSourceLocation(TokenPtr));
+ Diag(Loc, diag::warn_correct_comment_command_name)
+ << CommandName << CorrectedName
+ << FixItHint::CreateReplacement(CommandRange, CorrectedName);
+ } else {
+ formTokenWithChars(T, TokenPtr, tok::unknown_command);
+ T.setUnknownCommandName(CommandName);
+ Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
+ return;
+ }
}
if (Info->IsVerbatimBlockCommand) {
setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d89c79b3d93d..03e01015b954 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -16,6 +16,15 @@
#include "llvm/Support/ErrorHandling.h"
namespace clang {
+
+static inline bool isWhitespace(llvm::StringRef S) {
+ for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ if (!isWhitespace(*I))
+ return false;
+ }
+ return true;
+}
+
namespace comments {
/// Re-lexes a sequence of tok::text tokens.
@@ -594,6 +603,18 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
break; // Two newlines -- end of paragraph.
}
+ // Also allow [tok::newline, tok::text, tok::newline] if the middle
+ // tok::text is just whitespace.
+ if (Tok.is(tok::text) && isWhitespace(Tok.getText())) {
+ Token WhitespaceTok = Tok;
+ consumeToken();
+ if (Tok.is(tok::newline) || Tok.is(tok::eof)) {
+ consumeToken();
+ break;
+ }
+ // We have [tok::newline, tok::text, non-newline]. Put back tok::text.
+ putBack(WhitespaceTok);
+ }
if (Content.size() > 0)
Content.back()->addTrailingNewline();
continue;
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index e0138d5f3f27..1c6222f9ec02 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -29,8 +29,7 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
- HeaderfileCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_function:
- DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
break;
case CommandTraits::KCI_functiongroup:
- DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
break;
case CommandTraits::KCI_method:
DiagSelect = !isObjCMethodDecl() ? 3 : 0;
@@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_class:
- DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
+ // Allow @class command on @interface declarations.
+ // FIXME. Currently, \class and @class are indistinguishable. So,
+ // \class is also allowed on an @interface declaration
+ if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
+ DiagSelect = 0;
break;
case CommandTraits::KCI_interface:
DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
@@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
<< Comment->getSourceRange();
}
+/// \brief Turn a string into the corresponding PassDirection or -1 if it's not
+/// valid.
+static int getParamPassDirection(StringRef Arg) {
+ return llvm::StringSwitch<int>(Arg)
+ .Case("[in]", ParamCommandComment::In)
+ .Case("[out]", ParamCommandComment::Out)
+ .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
+ .Default(-1);
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
- ParamCommandComment::PassDirection Direction;
std::string ArgLower = Arg.lower();
- // TODO: optimize: lower Name first (need an API in SmallString for that),
- // after that StringSwitch.
- if (ArgLower == "[in]")
- Direction = ParamCommandComment::In;
- else if (ArgLower == "[out]")
- Direction = ParamCommandComment::Out;
- else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
- Direction = ParamCommandComment::InOut;
- else {
- // Remove spaces.
- std::string::iterator O = ArgLower.begin();
- for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
- I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\v' && C != '\f')
- *O++ = C;
- }
- ArgLower.resize(O - ArgLower.begin());
-
- bool RemovingWhitespaceHelped = false;
- if (ArgLower == "[in]") {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[out]") {
- Direction = ParamCommandComment::Out;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
- Direction = ParamCommandComment::InOut;
- RemovingWhitespaceHelped = true;
- } else {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = false;
- }
+ int Direction = getParamPassDirection(ArgLower);
+
+ if (Direction == -1) {
+ // Try again with whitespace removed.
+ ArgLower.erase(
+ std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
+ ArgLower.end());
+ Direction = getParamPassDirection(ArgLower);
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- if (RemovingWhitespaceHelped)
+ if (Direction != -1) {
+ const char *FixedName = ParamCommandComment::getDirectionAsString(
+ (ParamCommandComment::PassDirection)Direction);
Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
- << ArgRange
- << FixItHint::CreateReplacement(
- ArgRange,
- ParamCommandComment::getDirectionAsString(Direction));
- else
- Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
- << ArgRange;
+ << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
+ } else {
+ Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
+ Direction = ParamCommandComment::In; // Sane fall back.
+ }
}
- Command->setDirection(Direction, /* Explicit = */ true);
+ Command->setDirection((ParamCommandComment::PassDirection)Direction,
+ /*Explicit=*/true);
}
void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
@@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SmallVector<unsigned, 2> Position;
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
- llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
- TemplateParameterDocs.find(Arg);
- if (PrevCommandIt != TemplateParameterDocs.end()) {
+ TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
+ if (PrevCommand) {
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
<< Arg << ArgRange;
- TParamCommandComment *PrevCommand = PrevCommandIt->second;
Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
<< PrevCommand->getParamNameRange();
}
- TemplateParameterDocs[Arg] = Command;
+ PrevCommand = Command;
return;
}
@@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
}
while (!HTMLOpenTags.empty()) {
- const HTMLStartTagComment *HST = HTMLOpenTags.back();
- HTMLOpenTags.pop_back();
+ const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
StringRef LastNotClosedTagName = HST->getTagName();
if (LastNotClosedTagName == TagName)
break;
@@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = BriefCommand;
- } else if (Info->IsReturnsCommand) {
- if (!ReturnsCommand) {
- ReturnsCommand = Command;
- return;
- }
- PrevCommand = ReturnsCommand;
} else if (Info->IsHeaderfileCommand) {
if (!HeaderfileCommand) {
HeaderfileCommand = Command;
@@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
// Check that referenced parameter name is in the function decl.
const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
ParamVars);
+ if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
+ PCC->setIsVarArgParam();
+ continue;
+ }
if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
UnresolvedParamCommands.push_back(PCC);
continue;
@@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
}
-
+
+bool Sema::isFunctionOrMethodVariadic() {
+ if (!isAnyFunctionDecl() && !isObjCMethodDecl())
+ return false;
+ if (const FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
+ return FD->isVariadic();
+ if (const ObjCMethodDecl *MD =
+ dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
+ return MD->isVariadic();
+ return false;
+}
+
bool Sema::isObjCMethodDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
}
-
-/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
-/// function decl.
+
bool Sema::isFunctionPointerVarDecl() {
if (!ThisDeclInfo)
return false;
@@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() {
isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
!isUnionDecl();
}
+
+bool Sema::isClassTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
+
+bool Sema::isFunctionTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
bool Sema::isObjCInterfaceDecl() {
if (!ThisDeclInfo)
@@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
if (II && II->getName() == Name)
return i;
}
+ if (Name == "..." && isFunctionOrMethodVariadic())
+ return ParamCommandComment::VarArgParamIndex;
return ParamCommandComment::InvalidParamIndex;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ab9d73b9178e..6bd985851a39 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -34,6 +34,10 @@
using namespace clang;
+Decl *clang::getPrimaryMergedDecl(Decl *D) {
+ return D->getASTContext().getPrimaryMergedDecl(D);
+}
+
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -85,6 +89,7 @@ using namespace clang;
// 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
@@ -108,7 +113,11 @@ enum LVComputationKind {
/// 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)
+ 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
@@ -211,11 +220,19 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return None;
}
+static LinkageInfo
+getLVForType(const Type &T, LVComputationKind computation) {
+ if (computation == LVForLinkageOnly)
+ return LinkageInfo(T.getLinkage(), DefaultVisibility, true);
+ return T.getLinkageAndVisibility();
+}
+
/// \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) {
+getLVForTemplateParameterList(const TemplateParameterList *params,
+ LVComputationKind computation) {
LinkageInfo LV;
for (TemplateParameterList::const_iterator P = params->begin(),
PEnd = params->end();
@@ -234,7 +251,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!NTTP->isExpandedParameterPack()) {
if (!NTTP->getType()->isDependentType()) {
- LV.merge(NTTP->getType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*NTTP->getType(), computation));
}
continue;
}
@@ -254,7 +271,8 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!TTP->isExpandedParameterPack()) {
- LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(),
+ computation));
continue;
}
@@ -262,7 +280,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
i != n; ++i) {
LV.merge(getLVForTemplateParameterList(
- TTP->getExpansionTemplateParameters(i)));
+ TTP->getExpansionTemplateParameters(i), computation));
}
}
@@ -273,13 +291,25 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation);
+static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
+ const Decl *Ret = NULL;
+ const DeclContext *DC = D->getDeclContext();
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC))
+ Ret = cast<Decl>(DC);
+ DC = DC->getParent();
+ }
+ return Ret;
+}
+
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
///
/// 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) {
+getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args,
+ LVComputationKind computation) {
LinkageInfo LV;
for (unsigned i = 0, e = args.size(); i != e; ++i) {
@@ -291,13 +321,13 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
continue;
case TemplateArgument::Type:
- LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*arg.getAsType(), computation));
continue;
case TemplateArgument::Declaration:
if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
assert(!usesTypeVisibility(ND));
- LV.merge(getLVForDecl(ND, LVForValue));
+ LV.merge(getLVForDecl(ND, computation));
}
continue;
@@ -309,11 +339,11 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
= arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.merge(getLVForDecl(Template, LVForValue));
+ LV.merge(getLVForDecl(Template, computation));
continue;
case TemplateArgument::Pack:
- LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation));
continue;
}
llvm_unreachable("bad template argument kind");
@@ -323,8 +353,9 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
- return getLVForTemplateArgumentList(TArgs.asArray());
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVComputationKind computation) {
+ return getLVForTemplateArgumentList(TArgs.asArray(), computation);
}
static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
@@ -348,19 +379,20 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
/// \param[out] LV the computation to use for the parent
static void
mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *specInfo) {
+ const FunctionTemplateSpecializationInfo *specInfo,
+ LVComputationKind computation) {
bool considerVisibility =
shouldConsiderTemplateVisibility(fn, specInfo);
// Merge information from the template parameters.
FunctionTemplateDecl *temp = specInfo->getTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// Merge information from the template arguments.
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
@@ -379,6 +411,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D,
if (D->hasAttr<VisibilityAttr>())
return true;
return false;
+ case LVForLinkageOnly:
+ return false;
}
llvm_unreachable("bad visibility computation kind");
}
@@ -431,7 +465,7 @@ static void mergeTemplateLV(LinkageInfo &LV,
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV,
considerVisibility && !hasExplicitVisibilityAlready(computation));
@@ -439,8 +473,10 @@ static void mergeTemplateLV(LinkageInfo &LV,
// template-argument visibility if we've got an explicit
// instantiation with a visibility attribute.
const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
- LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
+ if (considerVisibility)
+ LV.mergeVisibility(argsLV);
+ LV.mergeExternalVisibility(argsLV);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -472,7 +508,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
}
template <typename T> static bool isFirstInExternCContext(T *D) {
- const T *First = D->getFirstDeclaration();
+ const T *First = D->getFirstDecl();
return First->isInExternCContext();
}
@@ -508,7 +544,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
!Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
- return PrevVar->getLinkageAndVisibility();
+ return getLVForDecl(PrevVar, computation);
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
@@ -539,11 +575,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
- } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
- // - a data member of an anonymous union.
- if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return LinkageInfo::internal();
}
+ // - a data member of an anonymous union.
+ assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!");
+ assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
@@ -627,7 +662,7 @@ 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)) {
- LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
if (!LV.isVisibilityExplicit())
@@ -660,16 +695,27 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
if (Context.getLangOpts().CPlusPlus &&
- !Function->isInExternCContext() &&
- Function->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
+ !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.
+ QualType TypeAsWritten = Function->getType();
+ if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// Consider LV from the template and the template arguments.
// We're at file scope, so we do not need to worry about nested
// specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, Function, specInfo);
+ mergeTemplateLV(LV, Function, specInfo, computation);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -695,7 +741,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
computation);
- if (!isExternalLinkage(EnumLV.getLinkage()))
+ if (!isExternalFormalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
@@ -704,7 +750,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
bool considerVisibility = !hasExplicitVisibilityAlready(computation);
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// - a namespace (7.3), unless it is declared within an unnamed
@@ -739,6 +785,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
+ isa<IndirectFieldDecl>(D) ||
isa<TagDecl>(D)))
return LinkageInfo::none();
@@ -766,13 +813,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
LinkageInfo classLV =
getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
- if (!isExternalLinkage(classLV.getLinkage()))
- return LinkageInfo::none();
-
// If the class already has unique-external linkage, we can't improve.
if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
+ if (!isExternallyVisible(classLV.getLinkage()))
+ return LinkageInfo::none();
+
+
// Otherwise, don't merge in classLV yet, because in certain cases
// we need to completely ignore the visibility from it.
@@ -782,14 +830,25 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (const CXXMethodDecl *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.
- if (MD->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
-
+ // 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();
+ }
// If this is a method template specialization, use the linkage for
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, MD, spec);
+ mergeTemplateLV(LV, MD, spec, computation);
if (spec->isExplicitSpecialization()) {
explicitSpecSuppressor = MD;
} else if (isExplicitMemberSpecialization(spec->getTemplate())) {
@@ -819,9 +878,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
- LV.mergeMaybeWithVisibility(typeLV,
- !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
+ LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
+ if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit())
+ LV.mergeVisibility(typeLV);
+ LV.mergeExternalVisibility(typeLV);
if (isExplicitMemberSpecialization(VD)) {
explicitSpecSuppressor = VD;
@@ -834,7 +894,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
!classLV.isVisibilityExplicit() &&
!hasExplicitVisibilityAlready(computation));
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
if (const RedeclarableTemplateDecl *redeclTemp =
@@ -866,81 +926,42 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
void NamedDecl::anchor() { }
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
+
bool NamedDecl::isLinkageValid() const {
- if (!HasCachedLinkage)
+ if (!hasCachedLinkage())
return true;
- return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
- Linkage(CachedLinkage);
+ return computeLVForDecl(this, LVForLinkageOnly).getLinkage() ==
+ getCachedLinkage();
}
-Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage)
- return Linkage(CachedLinkage);
-
+Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
- CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
- HasCachedLinkage = 1;
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return Linkage(CachedLinkage);
+ return getLVForDecl(this, LVForLinkageOnly).getLinkage();
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
LVComputationKind computation =
(usesTypeVisibility(this) ? LVForType : LVForValue);
- LinkageInfo LI = getLVForDecl(this, computation);
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) == LI.getLinkage());
- return LI;
- }
- HasCachedLinkage = 1;
- CachedLinkage = LI.getLinkage();
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return LI;
+ return getLVForDecl(this, computation);
}
-void NamedDecl::verifyLinkage() const {
- // 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 = getASTContext().getLangOpts();
- if (!Opts.CPlusPlus || Opts.MicrosoftExt)
- return;
-
- // 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 *D = NULL;
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- NamedDecl *T = cast<NamedDecl>(*I);
- if (T == this)
- continue;
- if (T->HasCachedLinkage != 0) {
- D = T;
- break;
- }
- }
- assert(!D || D->CachedLinkage == CachedLinkage);
-}
+static Optional<Visibility>
+getExplicitVisibilityAux(const NamedDecl *ND,
+ NamedDecl::ExplicitVisibilityKind kind,
+ bool IsMostRecent) {
+ assert(!IsMostRecent || ND == ND->getMostRecentDecl());
-Optional<Visibility>
-NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// Check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ if (Optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
// If this is a member class of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) {
CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
if (InstantiatedFrom)
return getVisibilityOf(InstantiatedFrom, kind);
@@ -950,16 +971,18 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// specialization of a class template, check for visibility
// on the pattern.
if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ = dyn_cast<ClassTemplateSpecializationDecl>(ND))
return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
kind);
// Use the most recent declaration.
- const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
- if (MostRecent != this)
- return MostRecent->getExplicitVisibility(kind);
+ if (!IsMostRecent && !isa<NamespaceDecl>(ND)) {
+ const NamedDecl *MostRecent = ND->getMostRecentDecl();
+ if (MostRecent != ND)
+ return getExplicitVisibilityAux(MostRecent, kind, true);
+ }
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
+ if (const VarDecl *Var = dyn_cast<VarDecl>(ND)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
@@ -969,7 +992,7 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return None;
}
// Also handle function template specializations.
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) {
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
@@ -987,12 +1010,33 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
}
// The visibility of a template is stored in the templated decl.
- if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
+ if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
return None;
}
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ return getExplicitVisibilityAux(this, kind, false);
+}
+
+static LinkageInfo 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);
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+ return getLVForDecl(ND, computation);
+
+ return LinkageInfo::external();
+}
+
static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
LVComputationKind computation) {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -1040,13 +1084,55 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
return LV;
}
+
+ if (!Var->isStaticLocal())
+ return LinkageInfo::none();
}
- return LinkageInfo::none();
+ ASTContext &Context = D->getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return LinkageInfo::none();
+
+ const Decl *OuterD = getOutermostFuncOrBlockContext(D);
+ if (!OuterD)
+ return LinkageInfo::none();
+
+ LinkageInfo LV;
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) {
+ if (!BD->getBlockManglingNumber())
+ return LinkageInfo::none();
+
+ LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(),
+ BD->getBlockManglingContextDecl(), computation);
+ } else {
+ const FunctionDecl *FD = cast<FunctionDecl>(OuterD);
+ if (!FD->isInlined() &&
+ FD->getTemplateSpecializationKind() == TSK_Undeclared)
+ return LinkageInfo::none();
+
+ LV = getLVForDecl(FD, computation);
+ }
+ if (!isExternallyVisible(LV.getLinkage()))
+ return LinkageInfo::none();
+ return LinkageInfo(VisibleNoLinkage, LV.getVisibility(),
+ LV.isVisibilityExplicit());
}
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
+static inline const CXXRecordDecl*
+getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
+ const CXXRecordDecl *Ret = Record;
+ while (Record && Record->isLambda()) {
+ Ret = Record;
+ if (!Record->getParent()) break;
+ // Get the Containing Class of this Lambda Class
+ Record = dyn_cast_or_null<CXXRecordDecl>(
+ Record->getParent()->getParent());
+ }
+ return Ret;
+}
+
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -1074,20 +1160,25 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
// This lambda has no mangling number, so it's internal.
return LinkageInfo::internal();
}
-
- // This lambda has its linkage/visibility determined by its owner.
- const DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (Decl *ContextDecl = Record->getLambdaContextDecl()) {
- if (isa<ParmVarDecl>(ContextDecl))
- DC = ContextDecl->getDeclContext()->getRedeclContext();
- else
- return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
- }
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, computation);
+ // This lambda has its linkage/visibility determined:
+ // - either by the outermost lambda if that lambda has no mangling
+ // number.
+ // - or by the parent of the outer most lambda
+ // This prevents infinite recursion in settings such as nested lambdas
+ // used in NSDMI's, for e.g.
+ // struct L {
+ // int t{};
+ // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
+ // };
+ const CXXRecordDecl *OuterMostLambda =
+ getOutermostEnclosingLambda(Record);
+ if (!OuterMostLambda->getLambdaManglingNumber())
+ return LinkageInfo::internal();
- return LinkageInfo::external();
+ return getLVForClosure(
+ OuterMostLambda->getDeclContext()->getRedeclContext(),
+ OuterMostLambda->getLambdaContextDecl(), computation);
}
break;
@@ -1127,6 +1218,57 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
return LinkageInfo::none();
}
+namespace clang {
+class LinkageComputer {
+public:
+ static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (computation == LVForLinkageOnly && D->hasCachedLinkage())
+ return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
+
+ LinkageInfo LV = computeLVForDecl(D, computation);
+ if (D->hasCachedLinkage())
+ assert(D->getCachedLinkage() == LV.getLinkage());
+
+ D->setCachedLinkage(LV.getLinkage());
+
+#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;
+
+ // 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 = NULL;
+ for (NamedDecl::redecl_iterator I = D->redecls_begin(),
+ E = D->redecls_end();
+ I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == D)
+ continue;
+ if (T->hasCachedLinkage()) {
+ Old = T;
+ break;
+ }
+ }
+ assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
+#endif
+
+ return LV;
+ }
+};
+}
+
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ return clang::LinkageComputer::getLVForDecl(D, computation);
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
}
@@ -1265,6 +1407,15 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
cast<UsingDecl>(OldD)->getQualifier());
}
+ if (isa<UnresolvedUsingValueDecl>(this) &&
+ isa<UnresolvedUsingValueDecl>(OldD)) {
+ ASTContext &Context = getASTContext();
+ return Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(this)->getQualifier()) ==
+ Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
+ }
+
// A typedef of an Objective-C class type can replace an Objective-C class
// declaration or definition, and vice versa.
if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) ||
@@ -1278,7 +1429,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- return getLinkage() != NoLinkage;
+ return getFormalLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
@@ -1469,6 +1620,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
llvm_unreachable("Invalid storage class");
}
+VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
+ assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
+ assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+ AllBits = 0;
+ VarDeclBits.SClass = SC;
+ // Everything else is implicitly initialized to false.
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
@@ -1502,7 +1664,7 @@ template<typename T>
static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
// C++ [dcl.link]p1: All function types, function names with external linkage,
// and variable names with external linkage have a language linkage.
- if (!isExternalLinkage(D.getLinkage()))
+ if (!D.hasExternalFormalLinkage())
return NoLanguageLinkage;
// Language linkage is a C++ concept, but saying that everything else in C has
@@ -1547,32 +1709,15 @@ bool VarDecl::isExternC() const {
return isExternCTemplate(*this);
}
-static bool isLinkageSpecContext(const DeclContext *DC,
- LinkageSpecDecl::LanguageIDs ID) {
- while (DC->getDeclKind() != Decl::TranslationUnit) {
- if (DC->getDeclKind() == Decl::LinkageSpec)
- return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
- DC = DC->getParent();
- }
- return false;
-}
-
-template <typename T>
-static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) {
- return isLinkageSpecContext(D->getLexicalDeclContext(), ID);
-}
-
bool VarDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool VarDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
-VarDecl *VarDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); }
VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
ASTContext &C) const
@@ -1581,13 +1726,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// A declaration is a definition unless [...] it contains the 'extern'
// specifier or a linkage-specification and neither an initializer [...],
// it declares a static data member in a class declaration [...].
- // C++ [temp.expl.spec]p15:
- // An explicit specialization of a static data member of a template is a
- // definition if the declaration includes an initializer; otherwise, it is
- // a declaration.
+ // C++1y [temp.expl.spec]p15:
+ // An explicit specialization of a static data member or an explicit
+ // specialization of a static data member template is a definition if the
+ // declaration includes an initializer; otherwise, it is a declaration.
+ //
+ // FIXME: How do you declare (but not define) a partial specialization of
+ // a static data member template outside the containing class?
if (isStaticDataMember()) {
- if (isOutOfLine() && (hasInit() ||
- getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ if (isOutOfLine() &&
+ (hasInit() ||
+ // If the first declaration is out-of-line, this may be an
+ // instantiation of an out-of-line partial specialization of a variable
+ // template for which we have not yet instantiated the initializer.
+ (getFirstDecl()->isOutOfLine()
+ ? getTemplateSpecializationKind() == TSK_Undeclared
+ : getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization) ||
+ isa<VarTemplatePartialSpecializationDecl>(this)))
return Definition;
else
return DeclarationOnly;
@@ -1602,6 +1758,16 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
if (hasInit())
return Definition;
+ if (hasAttr<AliasAttr>())
+ return Definition;
+
+ // A variable template specialization (other than a static data member
+ // template or an explicit specialization) is a declaration until we
+ // instantiate its initializer.
+ if (isa<VarTemplateSpecializationDecl>(this) &&
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ return DeclarationOnly;
+
if (hasExternalStorage())
return DeclarationOnly;
@@ -1631,7 +1797,7 @@ VarDecl *VarDecl::getActingDefinition() {
return 0;
VarDecl *LastTentative = 0;
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = (*I)->isThisDeclarationADefinition();
@@ -1643,20 +1809,8 @@ VarDecl *VarDecl::getActingDefinition() {
return LastTentative;
}
-bool VarDecl::isTentativeDefinitionNow() const {
- DefinitionKind Kind = isThisDeclarationADefinition();
- if (Kind != TentativeDefinition)
- return false;
-
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((*I)->isThisDeclarationADefinition() == Definition)
- return false;
- }
- return true;
-}
-
VarDecl *VarDecl::getDefinition(ASTContext &C) {
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
if ((*I)->isThisDeclarationADefinition(C) == Definition)
@@ -1668,7 +1822,7 @@ VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
- const VarDecl *First = getFirstDeclaration();
+ const VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C));
@@ -1763,6 +1917,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
Stmt *S = Init.get<Stmt *>();
+ // Note: EvaluatedStmt contains an APValue, which usually holds
+ // resources not allocated from the ASTContext. We need to do some
+ // work to avoid leaking those, but we do so in VarDecl::evaluateValue
+ // where we can detect whether there's anything to clean up or not.
Eval = new (getASTContext()) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
@@ -1775,6 +1933,13 @@ APValue *VarDecl::evaluateValue() const {
return evaluateValue(Notes);
}
+namespace {
+// Destroy an APValue that was allocated in an ASTContext.
+void DestroyAPValue(void* UntypedValue) {
+ static_cast<APValue*>(UntypedValue)->~APValue();
+}
+} // namespace
+
APValue *VarDecl::evaluateValue(
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
@@ -1800,9 +1965,13 @@ APValue *VarDecl::evaluateValue(
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
this, Notes);
- // Ensure the result is an uninitialized APValue if evaluation fails.
+ // Ensure the computed APValue is cleaned up later if evaluation succeeded,
+ // or that it's empty (so that there's nothing to clean up) if evaluation
+ // failed.
if (!Result)
Eval->Evaluated = APValue();
+ else if (Eval->Evaluated.needsCleanup())
+ getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
@@ -1853,19 +2022,6 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
-bool VarDecl::extendsLifetimeOfTemporary() const {
- assert(getType()->isReferenceType() &&"Non-references never extend lifetime");
-
- const Expr *E = getInit();
- if (!E)
- return false;
-
- if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(E))
- E = Cleanups->getSubExpr();
-
- return isa<MaterializeTemporaryExpr>(E);
-}
-
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -1874,25 +2030,73 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
-
+
return TSK_Undeclared;
}
+SourceLocation VarDecl::getPointOfInstantiation() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getPointOfInstantiation();
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getPointOfInstantiation();
+
+ return SourceLocation();
+}
+
+VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<VarTemplateDecl *>();
+}
+
+void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) {
+ getASTContext().setTemplateOrSpecializationInfo(this, Template);
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
- return getASTContext().getInstantiatedFromStaticDataMember(this);
+ if (isStaticDataMember())
+ // FIXME: Remove ?
+ // return getASTContext().getInstantiatedFromStaticDataMember(this);
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<MemberSpecializationInfo *>();
+ return 0;
}
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation) {
- MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
- assert(MSI && "Not an instantiated static data member?");
- MSI->setTemplateSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization &&
- PointOfInstantiation.isValid() &&
- MSI->getPointOfInstantiation().isInvalid())
- MSI->setPointOfInstantiation(PointOfInstantiation);
+ assert((isa<VarTemplateSpecializationDecl>(this) ||
+ getMemberSpecializationInfo()) &&
+ "not a variable or static data member template specialization");
+
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ Spec->getPointOfInstantiation().isInvalid())
+ Spec->setPointOfInstantiation(PointOfInstantiation);
+ }
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ MSI->setTemplateSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ MSI->getPointOfInstantiation().isInvalid())
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ }
+}
+
+void
+VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD,
+ TemplateSpecializationKind TSK) {
+ assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() &&
+ "Previous template or instantiation?");
+ getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK);
}
//===----------------------------------------------------------------------===//
@@ -1908,6 +2112,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
S, DefArg);
}
+QualType ParmVarDecl::getOriginalType() const {
+ TypeSourceInfo *TSI = getTypeSourceInfo();
+ QualType T = TSI ? TSI->getType() : getType();
+ if (const DecayedType *DT = dyn_cast<DecayedType>(T))
+ return DT->getOriginalType();
+ return T;
+}
+
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
@@ -2010,7 +2222,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
+ I->hasAttr<AliasAttr>()) {
Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
return true;
}
@@ -2020,15 +2233,11 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
}
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->Body) {
- Definition = *I;
- return I->Body.get(getASTContext().getExternalSource());
- } else if (I->IsLateTemplateParsed) {
- Definition = *I;
- return 0;
- }
- }
+ if (!hasBody(Definition))
+ return 0;
+
+ if (Definition->Body)
+ return Definition->Body.get(getASTContext().getExternalSource());
return 0;
}
@@ -2046,13 +2255,45 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
+template<std::size_t Len>
+static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) {
+ IdentifierInfo *II = ND->getIdentifier();
+ return II && II->isStr(Str);
+}
+
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
return tunit &&
!tunit->getASTContext().getLangOpts().Freestanding &&
- getIdentifier() &&
- getIdentifier()->isStr("main");
+ isNamed(this, "main");
+}
+
+bool FunctionDecl::isMSVCRTEntryPoint() const {
+ const TranslationUnitDecl *TUnit =
+ dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+ if (!TUnit)
+ return false;
+
+ // Even though we aren't really targeting MSVCRT if we are freestanding,
+ // semantic analysis for these functions remains the same.
+
+ // MSVCRT entry points only exist on MSVCRT targets.
+ if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT())
+ return false;
+
+ // Nameless functions like constructors cannot be entry points.
+ if (!getIdentifier())
+ return false;
+
+ return llvm::StringSwitch<bool>(getName())
+ .Cases("main", // an ANSI console app
+ "wmain", // a Unicode console App
+ "WinMain", // an ANSI GUI app
+ "wWinMain", // a Unicode GUI app
+ "DllMain", // a DLL
+ true)
+ .Default(false);
}
bool FunctionDecl::isReservedGlobalPlacementOperator() const {
@@ -2077,13 +2318,83 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-LanguageLinkage FunctionDecl::getLanguageLinkage() const {
- // Users expect to be able to write
- // extern "C" void *__builtin_alloca (size_t);
- // so consider builtins as having C language linkage.
- if (getBuiltinID())
- return CLanguageLinkage;
+static bool isNamespaceStd(const DeclContext *DC) {
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext());
+ return ND && isNamed(ND, "std") &&
+ ND->getParent()->getRedeclContext()->isTranslationUnit();
+}
+bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return false;
+ if (getDeclName().getCXXOverloadedOperator() != OO_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ if (isa<CXXRecordDecl>(getDeclContext()))
+ return false;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
+ if (FPT->getNumArgs() > 2 || FPT->isVariadic())
+ return false;
+
+ // If this is a single-parameter function, it must be a replaceable global
+ // allocation or deallocation function.
+ if (FPT->getNumArgs() == 1)
+ return true;
+
+ // Otherwise, we're looking for a second parameter whose type is
+ // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
+ QualType Ty = FPT->getArgType(1);
+ ASTContext &Ctx = getASTContext();
+ if (Ctx.getLangOpts().SizedDeallocation &&
+ Ctx.hasSameType(Ty, Ctx.getSizeType()))
+ return true;
+ if (!Ty->isReferenceType())
+ return false;
+ Ty = Ty->getPointeeType();
+ if (Ty.getCVRQualifiers() != Qualifiers::Const)
+ return false;
+ // FIXME: Recognise nothrow_t in an inline namespace inside std?
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
+}
+
+FunctionDecl *
+FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
+ ASTContext &Ctx = getASTContext();
+ if (!Ctx.getLangOpts().SizedDeallocation)
+ return 0;
+
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return 0;
+ if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return 0;
+ if (isa<CXXRecordDecl>(getDeclContext()))
+ return 0;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ if (getNumParams() != 2 || isVariadic() ||
+ !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1),
+ Ctx.getSizeType()))
+ return 0;
+
+ // This is a sized deallocation function. Find the corresponding unsized
+ // deallocation function.
+ lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE;
+ ++RI)
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
+ if (FD->getNumParams() == 1 && !FD->isVariadic())
+ return FD;
+ return 0;
+}
+
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getLanguageLinkageTemplate(*this);
}
@@ -2092,11 +2403,11 @@ bool FunctionDecl::isExternC() const {
}
bool FunctionDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool FunctionDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
bool FunctionDecl::isGlobal() const {
@@ -2127,13 +2438,13 @@ bool FunctionDecl::isNoReturn() const {
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
+ redeclarable_base::setPreviousDecl(PrevDecl);
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
FunctionTemplateDecl *PrevFunTmpl
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
- FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+ FunTmpl->setPreviousDecl(PrevFunTmpl);
}
if (PrevDecl && PrevDecl->IsInline)
@@ -2141,12 +2452,10 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
}
const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
- return getFirstDeclaration();
+ return getFirstDecl();
}
-FunctionDecl *FunctionDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
@@ -2166,6 +2475,22 @@ unsigned FunctionDecl::getBuiltinID() const {
return 0;
ASTContext &Context = getASTContext();
+ if (Context.getLangOpts().CPlusPlus) {
+ const LinkageSpecDecl *LinkageDecl = dyn_cast<LinkageSpecDecl>(
+ getFirstDecl()->getDeclContext());
+ // In C++, the first declaration of a builtin is always inside an implicit
+ // extern "C".
+ // FIXME: A recognised library function may not be directly in an extern "C"
+ // declaration, for instance "extern "C" { namespace std { decl } }".
+ if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
+ return 0;
+ }
+
+ // If the function is marked "overloadable", it has a different mangled name
+ // and is not the C library function.
+ if (getAttr<OverloadableAttr>())
+ return 0;
+
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
@@ -2177,22 +2502,7 @@ unsigned FunctionDecl::getBuiltinID() const {
if (getStorageClass() == SC_Static)
return 0;
- // If this function is at translation-unit scope and we're not in
- // C++, it refers to the C library function.
- if (!Context.getLangOpts().CPlusPlus &&
- getDeclContext()->isTranslationUnit())
- return BuiltinID;
-
- // If the function is in an extern "C" linkage specification and is
- // not marked "overloadable", it's the real function.
- if (isa<LinkageSpecDecl>(getDeclContext()) &&
- cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
- == LinkageSpecDecl::lang_c &&
- !getAttr<OverloadableAttr>())
- return BuiltinID;
-
- // Not a builtin
- return 0;
+ return BuiltinID;
}
@@ -2304,7 +2614,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (Prev->Body) {
// If it's not the case that both 'inline' and 'extern' are
@@ -2332,7 +2642,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (RedeclForcesDefC99(Prev))
return false;
}
@@ -2818,26 +3128,18 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
}
unsigned FieldDecl::getFieldIndex() const {
+ const FieldDecl *Canonical = getCanonicalDecl();
+ if (Canonical != this)
+ return Canonical->getFieldIndex();
+
if (CachedFieldIndex) return CachedFieldIndex - 1;
unsigned Index = 0;
const RecordDecl *RD = getParent();
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(getASTContext());
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I, ++Index) {
- I->CachedFieldIndex = Index + 1;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield(*I, LastFD)) {
- --Index;
- continue;
- }
- LastFD = *I;
- }
- }
+ I != E; ++I, ++Index)
+ I->getCanonicalDecl()->CachedFieldIndex = Index + 1;
assert(CachedFieldIndex && "failed to find field in parent");
return CachedFieldIndex - 1;
@@ -2874,12 +3176,10 @@ SourceRange TagDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), E);
}
-TagDecl* TagDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+ NamedDeclOrQualifier = TDD;
if (TypeForDecl)
assert(TypeForDecl->isLinkageValid());
assert(isLinkageValid());
@@ -2936,7 +3236,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
} else {
@@ -2944,7 +3244,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
getASTContext().Deallocate(getExtInfo());
- TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0;
+ NamedDeclOrQualifier = (TypedefNameDecl*) 0;
}
else
getExtInfo()->QualifierLoc = QualifierLoc;
@@ -2959,7 +3259,7 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
// Make sure the extended decl info is allocated.
if (!hasExtInfo())
// Allocate external info struct.
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set the template parameter lists info.
getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 084a4321d8f1..121c5a671a29 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false;
}
+void Decl::markUsed(ASTContext &C) {
+ if (Used)
+ return;
+
+ if (C.getASTMutationListener())
+ C.getASTMutationListener()->DeclarationMarkedUsed(this);
+
+ Used = true;
+}
+
bool Decl::isReferenced() const {
if (Referenced)
return true;
@@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
+ case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
@@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:
+ case VarTemplateSpecialization:
+ case VarTemplatePartialSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
@@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const {
return getASTContext().getDeclAttrs(this);
}
-void Decl::swapAttrs(Decl *RHS) {
- bool HasLHSAttr = this->HasAttrs;
- bool HasRHSAttr = RHS->HasAttrs;
-
- // Usually, neither decl has attrs, nothing to do.
- if (!HasLHSAttr && !HasRHSAttr) return;
-
- // If 'this' has no attrs, swap the other way.
- if (!HasLHSAttr)
- return RHS->swapAttrs(this);
-
- ASTContext &Context = getASTContext();
-
- // Handle the case when both decls have attrs.
- if (HasRHSAttr) {
- std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS));
- return;
- }
-
- // Otherwise, LHS has an attr and RHS doesn't.
- Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this);
- Context.eraseDeclAttrs(this);
- this->HasAttrs = false;
- RHS->HasAttrs = true;
-}
-
Decl *Decl::castFromDeclContext (const DeclContext *D) {
Decl::Kind DK = D->getDeclKind();
switch(DK) {
@@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const {
return false;
}
+static bool isLinkageSpecContext(const DeclContext *DC,
+ LinkageSpecDecl::LanguageIDs ID) {
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (DC->getDeclKind() == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
+bool DeclContext::isExternCContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c);
+}
+
+bool DeclContext::isExternCXXContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx);
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() {
NeedToReconcileExternalVisibleStorage = false;
StoredDeclsMap &Map = *LookupPtr.getPointer();
- ExternalASTSource *Source = getParentASTContext().getExternalSource();
- for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
- I->second.removeExternalDecls();
- Source->FindExternalVisibleDeclsByName(this, I->first);
- }
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I)
+ I->second.setHasExternalDecls();
}
/// \brief Load the declarations within this lexical storage from an
@@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- // Add an entry to the map for this name, if it's not already present.
- (*Map)[Name];
+ (*Map)[Name].removeExternalDecls();
return DeclContext::lookup_result();
}
@@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
- for (ArrayRef<NamedDecl*>::iterator
- I = Decls.begin(), E = Decls.end(); I != E; ++I) {
- if (List.isNull())
- List.setOnlyValue(*I);
- else
- // FIXME: Need declarationReplaces handling for redeclarations in modules.
- List.AddSubsequentDecl(*I);
+
+ // Clear out any old external visible declarations, to avoid quadratic
+ // performance in the redeclaration checks below.
+ List.removeExternalDecls();
+
+ if (!List.isNull()) {
+ // We have both existing declarations and new declarations for this name.
+ // Some of the declarations may simply replace existing ones. Handle those
+ // first.
+ llvm::SmallVector<unsigned, 8> Skip;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I)
+ if (List.HandleRedeclaration(Decls[I]))
+ Skip.push_back(I);
+ Skip.push_back(Decls.size());
+
+ // Add in any new declarations.
+ unsigned SkipPos = 0;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ if (I == Skip[SkipPos])
+ ++SkipPos;
+ else
+ List.AddSubsequentDecl(Decls[I]);
+ }
+ } else {
+ // Convert the array to a StoredDeclsList.
+ for (ArrayRef<NamedDecl*>::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ if (List.isNull())
+ List.setOnlyValue(*I);
+ else
+ List.AddSubsequentDecl(*I);
+ }
}
return List.getLookupResult();
@@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() {
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl(Contexts[I]);
+ buildLookupImpl<&DeclContext::decls_begin,
+ &DeclContext::decls_end>(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
@@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() {
/// declarations contained within DCtx, which will either be this
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
+template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
+ DeclContext::decl_iterator (DeclContext::*End)() const>
void DeclContext::buildLookupImpl(DeclContext *DCtx) {
- for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end();
+ for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
I != E; ++I) {
Decl *D = *I;
// Insert this declaration into the lookup structure, but only if
// it's semantically within its decl context. Any other decls which
// should be found in this context are added eagerly.
+ //
+ // If it's from an AST file, don't add it now. It'll get handled by
+ // FindExternalVisibleDeclsByName if needed. Exception: if we're not
+ // in C++, we do not track external visible decls for the TU, so in
+ // that case we need to collect them all here.
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND))
+ if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) &&
+ (!ND->isFromASTFile() ||
+ (isTranslationUnit() &&
+ !getParentASTContext().getLangOpts().CPlusPlus)))
makeDeclVisibleInContextImpl(ND, false);
// If this declaration is itself a transparent declaration context
@@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) {
// context (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookupImpl(InnerCtx);
+ buildLookupImpl<Begin, End>(InnerCtx);
}
}
@@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) {
if (!Map)
Map = CreateStoredDeclsMap(getParentASTContext());
- // If a PCH/module has a result for this name, and we have a local
- // declaration, we will have imported the PCH/module result when adding the
- // local declaration or when reconciling the module.
+ // If we have a lookup result with no external decls, we are done.
std::pair<StoredDeclsMap::iterator, bool> R =
Map->insert(std::make_pair(Name, StoredDeclsList()));
- if (!R.second)
+ if (!R.second && !R.first->second.hasExternalDecls())
return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
@@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
+DeclContext::lookup_result
+DeclContext::noload_lookup(DeclarationName Name) {
+ assert(DeclKind != Decl::LinkageSpec &&
+ "Should not perform lookups into linkage specs!");
+ if (!hasExternalVisibleStorage())
+ return lookup(Name);
+
+ DeclContext *PrimaryContext = getPrimaryContext();
+ if (PrimaryContext != this)
+ return PrimaryContext->noload_lookup(Name);
+
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt()) {
+ // Carefully build the lookup map, without deserializing anything.
+ SmallVector<DeclContext *, 2> Contexts;
+ collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
+ buildLookupImpl<&DeclContext::noload_decls_begin,
+ &DeclContext::noload_decls_end>(Contexts[I]);
+
+ // We no longer have any lazy decls.
+ LookupPtr.setInt(false);
+
+ // There may now be names for which we have local decls but are
+ // missing the external decls. FIXME: Just set the hasExternalDecls
+ // flag on those names that have external decls.
+ NeedToReconcileExternalVisibleStorage = true;
+
+ Map = LookupPtr.getPointer();
+ }
+
+ if (!Map)
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
+
+ StoredDeclsMap::iterator I = Map->find(Name);
+ return I != Map->end()
+ ? I->second.getLookupResult()
+ : lookup_result(lookup_iterator(0), lookup_iterator(0));
+}
+
void DeclContext::localUncachedLookup(DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
@@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
assert(this == getPrimaryContext() && "expected a primary DC");
// Skip declarations within functions.
- // FIXME: We shouldn't need to build lookup tables for function declarations
- // ever, and we can't do so correctly because we can't model the nesting of
- // scopes which occurs within functions. We use "qualified" lookup into
- // function declarations when handling friend declarations inside nested
- // classes, and consequently accept the following invalid code:
- //
- // void f() { void g(); { int g; struct S { friend void g(); }; } }
- if (isFunctionOrMethod() && !isa<FunctionDecl>(D))
+ if (isFunctionOrMethod())
return;
// Skip declarations which should be invisible to name lookup.
@@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
// Insert this declaration into the map.
StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()];
- if (DeclNameEntries.isNull()) {
+
+ if (Internal) {
+ // If this is being added as part of loading an external declaration,
+ // this may not be the only external declaration with this name.
+ // In this case, we never try to replace an existing declaration; we'll
+ // handle that when we finalize the list of declarations for this name.
+ DeclNameEntries.setHasExternalDecls();
+ DeclNameEntries.AddSubsequentDecl(D);
+ return;
+ }
+
+ else if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 064649904d30..a17abdd0ae2a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -10,9 +10,9 @@
// This file implements the C++ related Decl classes.
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
@@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (Mem) AccessSpecDecl(EmptyShell());
}
+void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
+ ExternalASTSource *Source = C.getExternalSource();
+ assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set");
+ assert(Source && "getFromExternalSource with no external source");
+
+ for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
+ I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
+ reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)));
+ Impl.Decls.setLazy(false);
+}
+
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
@@ -60,9 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ Definition(D), FirstFriend() {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -97,12 +107,17 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool Dependent) {
+ bool Dependent, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
0, 0);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info,
+ Dependent,
+ IsGeneric,
+ CaptureDefault);
R->MayHaveOutOfDateDef = false;
+ R->setImplicit(true);
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -552,18 +567,16 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (Conversion->getPrimaryTemplate()) {
// We don't record specializations.
- } else if (FunTmpl) {
- if (FunTmpl->getPreviousDecl())
- data().Conversions.replace(FunTmpl->getPreviousDecl(),
- FunTmpl, AS);
- else
- data().Conversions.addDecl(getASTContext(), FunTmpl, AS);
} else {
- if (Conversion->getPreviousDecl())
- data().Conversions.replace(Conversion->getPreviousDecl(),
- Conversion, AS);
+ ASTContext &Ctx = getASTContext();
+ ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx);
+ NamedDecl *Primary =
+ FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion);
+ if (Primary->getPreviousDecl())
+ Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()),
+ Primary, AS);
else
- data().Conversions.addDecl(getASTContext(), Conversion, AS);
+ Conversions.addDecl(Ctx, Primary, AS);
}
}
@@ -662,7 +675,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!Context.getLangOpts().ObjCAutoRefCount ||
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
setHasObjectMember(true);
- } else if (!T.isPODType(Context))
+ } else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
if (T->isReferenceType()) {
@@ -712,6 +725,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (FieldRec->getDefinition()) {
addedClassSubobject(FieldRec);
+ // 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)) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForMoveAssignment = true;
+ }
+
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
// A defaulted [special member] for a class X is defined as
// deleted if:
@@ -880,10 +900,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// Handle using declarations of conversion functions.
- if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) {
if (Shadow->getDeclName().getNameKind()
- == DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+ == DeclarationName::CXXConversionFunctionName) {
+ ASTContext &Ctx = getASTContext();
+ data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
+ }
+ }
}
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
@@ -929,6 +952,43 @@ bool CXXRecordDecl::isCLike() const {
return isPOD() && data().HasOnlyCMembers;
}
+
+bool CXXRecordDecl::isGenericLambda() const {
+ if (!isLambda()) return false;
+ return getLambdaData().IsGenericLambda;
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = lookup(Name);
+
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+
+ NamedDecl *CallOp = Calls.front();
+ if (FunctionTemplateDecl *CallOpTmpl =
+ dyn_cast<FunctionTemplateDecl>(CallOp))
+ return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(CallOp);
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ &getASTContext().Idents.get(getLambdaStaticInvokerName());
+ DeclContext::lookup_const_result Invoker = lookup(Name);
+ if (Invoker.empty()) return 0;
+ assert(Invoker.size() == 1 && "More than one static invoker operator!");
+ NamedDecl *InvokerFun = Invoker.front();
+ if (FunctionTemplateDecl *InvokerTemplate =
+ dyn_cast<FunctionTemplateDecl>(InvokerFun))
+ return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(InvokerFun);
+}
void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
@@ -940,15 +1000,22 @@ void CXXRecordDecl::getCaptureFields(
RecordDecl::field_iterator Field = field_begin();
for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
C != CEnd; ++C, ++Field) {
- if (C->capturesThis()) {
+ if (C->capturesThis())
ThisCapture = *Field;
- continue;
- }
-
- Captures[C->getCapturedVar()] = *Field;
+ else if (C->capturesVariable())
+ Captures[C->getCapturedVar()] = *Field;
}
+ assert(Field == field_end());
}
+TemplateParameterList *
+CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
+ if (!isLambda()) return 0;
+ CXXMethodDecl *CallOp = getLambdaCallOperator();
+ if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
+ return Tmpl->getTemplateParameters();
+ return 0;
+}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
@@ -1085,16 +1152,21 @@ static void CollectVisibleConversions(ASTContext &Context,
/// in current class; including conversion function templates.
std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
CXXRecordDecl::getVisibleConversionFunctions() {
- // If root class, all conversions are visible.
- if (bases_begin() == bases_end())
- return std::make_pair(data().Conversions.begin(), data().Conversions.end());
- // If visible conversion list is already evaluated, return it.
- if (!data().ComputedVisibleConversions) {
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
+ ASTContext &Ctx = getASTContext();
+
+ ASTUnresolvedSet *Set;
+ if (bases_begin() == bases_end()) {
+ // If root class, all conversions are visible.
+ Set = &data().Conversions.get(Ctx);
+ } else {
+ Set = &data().VisibleConversions.get(Ctx);
+ // If visible conversion list is not evaluated, evaluate it.
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(Ctx, this, *Set);
+ data().ComputedVisibleConversions = true;
+ }
}
- return std::make_pair(data().VisibleConversions.begin(),
- data().VisibleConversions.end());
+ return std::make_pair(Set->begin(), Set->end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1109,7 +1181,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- ASTUnresolvedSet &Convs = data().Conversions;
+ ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext());
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1134,7 +1206,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
assert(TemplateOrInstantiation.isNull() &&
"Previous template or instantiation?");
- assert(!isa<ClassTemplateSpecializationDecl>(this));
+ assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
TemplateOrInstantiation
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
@@ -1235,8 +1307,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
}
// Set access bits correctly on the directly-declared conversions.
- for (UnresolvedSetIterator I = data().Conversions.begin(),
- E = data().Conversions.end();
+ for (conversion_iterator I = conversion_begin(), E = conversion_end();
I != E; ++I)
I.setAccess((*I)->getAccess());
}
@@ -1266,21 +1337,8 @@ bool CXXMethodDecl::isStatic() const {
if (MD->getStorageClass() == SC_Static)
return true;
- DeclarationName Name = getDeclName();
- // [class.free]p1:
- // Any allocation function for a class T is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_New ||
- Name.getCXXOverloadedOperator() == OO_Array_New)
- return true;
-
- // [class.free]p6 Any deallocation function for a class X is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_Delete ||
- Name.getCXXOverloadedOperator() == OO_Array_Delete)
- return true;
-
- return false;
+ OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator();
+ return isStaticOverloadedOperator(OOK);
}
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
@@ -1408,7 +1466,8 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
- /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1427,7 +1486,8 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
// non-template member function of class X with exactly one parameter of type
// X&&, const X&&, volatile X&&, or const volatile X&&.
if (getOverloadedOperator() != OO_Equal || isStatic() ||
- getPrimaryTemplate() || getDescribedFunctionTemplate())
+ getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1492,11 +1552,17 @@ bool CXXMethodDecl::hasInlineBody() const {
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
- return getParent()->isLambda() &&
- getIdentifier() && getIdentifier()->getName() == "__invoke";
+ const CXXRecordDecl *P = getParent();
+ if (P->isLambda()) {
+ if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
+ if (StaticInvoker == this) return true;
+ if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
+ return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
+ }
+ }
+ return false;
}
-
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
@@ -1865,7 +1931,7 @@ NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
@@ -1959,8 +2025,8 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
- bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg);
+ bool HasTypename) {
+ return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
}
UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -1969,6 +2035,12 @@ UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo(), false);
}
+SourceRange UsingDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingValueDecl::anchor() { }
UnresolvedUsingValueDecl *
@@ -1988,6 +2060,12 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo());
}
+SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingTypenameDecl::anchor() { }
UnresolvedUsingTypenameDecl *
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 37a812e71aae..1c639d676dc9 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
+FriendDecl *CXXRecordDecl::getFirstFriend() const {
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ Decl *First = data().FirstFriend.get(Source);
+ return First ? cast<FriendDecl>(First) : 0;
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 4ddbb22199b2..b2b5b70197b7 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -441,6 +441,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
return NULL;
}
+ObjCProtocolDecl *
+ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
+ for (ObjCInterfaceDecl::all_protocol_iterator P =
+ all_referenced_protocol_begin(), PE = all_referenced_protocol_end();
+ P != PE; ++P)
+ if ((*P)->lookupProtocolNamed(Name))
+ return (*P);
+ ObjCInterfaceDecl *SuperClass = getSuperClass();
+ return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL;
+}
+
/// lookupMethod - This method returns an instance/class method by looking in
/// the class, its categories, and its super classes (using a linear search).
/// When argument category "C" is specified, any implicit method found
@@ -627,23 +638,29 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
Decl *CtxD = cast<Decl>(getDeclContext());
- if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
- if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
- if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCImplementationDecl *ImplD =
- dyn_cast<ObjCImplementationDecl>(CtxD)) {
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
- Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryImplDecl *CImplD =
- dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
- if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
- Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ if (!CtxD->isInvalidDecl()) {
+ if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
+ if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
+ if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCImplementationDecl *ImplD =
+ dyn_cast<ObjCImplementationDecl>(CtxD)) {
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ if (!IFD->isInvalidDecl())
+ Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryImplDecl *CImplD =
+ dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
+ if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
+ if (!CatD->isInvalidDecl())
+ Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ }
}
if (!Redecl && isRedeclaration()) {
@@ -1062,7 +1079,7 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
if (PrevDecl)
@@ -1308,7 +1325,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
- bool synthesized) {
+ bool synthesized,
+ bool backingIvarReferencedInAccessor) {
if (DC) {
// Ivar's can only appear in interfaces, implementations (via synthesized
// properties), and class extensions (via direct declaration, or synthesized
@@ -1336,13 +1354,13 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
}
return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
- ac, BW, synthesized);
+ ac, BW, synthesized, backingIvarReferencedInAccessor);
}
ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl));
return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, ObjCIvarDecl::None, 0, false);
+ QualType(), 0, ObjCIvarDecl::None, 0, false, false);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -1401,7 +1419,7 @@ ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCProtocolDecl *PrevDecl)
: ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
Data = PrevDecl->Data;
}
@@ -1493,6 +1511,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
}
}
+
+void ObjCProtocolDecl::collectInheritedProtocolProperties(
+ const ObjCPropertyDecl *Property,
+ ProtocolPropertyMap &PM) const {
+ if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+ bool MatchFound = false;
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if (Prop == Property)
+ continue;
+ if (Prop->getIdentifier() == Property->getIdentifier()) {
+ PM[PDecl] = Prop;
+ MatchFound = true;
+ break;
+ }
+ }
+ // Scan through protocol's protocols which did not have a matching property.
+ if (!MatchFound)
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ (*PI)->collectInheritedProtocolProperties(Property, PM);
+ }
+}
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index c0d10a0f418c..0d195f74623d 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
- ArrayRef<DeclRefExpr *> VL) {
+ ArrayRef<Expr *> VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
- (VL.size() * sizeof(DeclRefExpr *));
+ (VL.size() * sizeof(Expr *));
void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -52,9 +52,10 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
return D;
}
-void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ Expr **Vars = reinterpret_cast<Expr **>(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}
+
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d47972bc6130..767f6620a295 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -260,6 +260,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
QualType CurDeclType = getDeclType(*D);
if (!Decls.empty() && !CurDeclType.isNull()) {
QualType BaseType = GetBaseType(CurDeclType);
+ if (!BaseType.isNull() && isa<ElaboratedType>(BaseType))
+ BaseType = cast<ElaboratedType>(BaseType)->getNamedType();
if (!BaseType.isNull() && isa<TagType>(BaseType) &&
cast<TagType>(BaseType)->getDecl() == Decls[0]) {
Decls.push_back(*D);
@@ -337,12 +339,14 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
if (D->isModulePrivate())
Out << "__module_private__ ";
}
- D->getUnderlyingType().print(Out, Policy, D->getName());
+ D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName());
prettyPrintAttributes(D);
}
void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy);
+ Out << "using " << *D;
+ prettyPrintAttributes(D);
+ Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
@@ -665,9 +669,9 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Out << "__module_private__ ";
}
- QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
- if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
- T = Parm->getOriginalType();
+ QualType T = D->getTypeSourceInfo()
+ ? D->getTypeSourceInfo()->getType()
+ : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
T.print(Out, Policy, D->getName());
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
@@ -1153,7 +1157,10 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
+ if (D->hasTypename())
+ Out << "typename ";
D->getQualifier()->print(Out, Policy);
Out << *D;
}
@@ -1166,7 +1173,8 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
D->getQualifier()->print(Out, Policy);
Out << D->getName();
}
@@ -1180,9 +1188,10 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
- I != E; ++I) {
- Out << (I == D->varlist_begin() ? '(' : ',')
- << *cast<NamedDecl>((*I)->getDecl());
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',');
+ NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+ ND->printQualifiedName(Out);
}
Out << ")";
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0b94f7d2c49b..7172fb7b487f 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -129,33 +129,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
//===----------------------------------------------------------------------===//
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
- if (!Common) {
- // Walk the previous-declaration chain until we either find a declaration
- // with a common pointer or we run out of previous declarations.
- SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
- for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
- Prev = Prev->getPreviousDecl()) {
- if (Prev->Common) {
- Common = Prev->Common;
- break;
- }
-
- PrevDecls.push_back(Prev);
+ if (Common)
+ return Common;
+
+ // Walk the previous-declaration chain until we either find a declaration
+ // with a common pointer or we run out of previous declarations.
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ if (Prev->Common) {
+ Common = Prev->Common;
+ break;
}
- // If we never found a common pointer, allocate one now.
- if (!Common) {
- // FIXME: If any of the declarations is from an AST file, we probably
- // need an update record to add the common data.
-
- Common = newCommon(getASTContext());
- }
-
- // Update any previous declarations we saw with the common pointer.
- for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
- PrevDecls[I]->Common = Common;
+ PrevDecls.push_back(Prev);
+ }
+
+ // If we never found a common pointer, allocate one now.
+ if (!Common) {
+ // FIXME: If any of the declarations is from an AST file, we probably
+ // need an update record to add the common data.
+
+ Common = newCommon(getASTContext());
}
+ // Update any previous declarations we saw with the common pointer.
+ for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
+ PrevDecls[I]->Common = Common;
+
return Common;
}
@@ -245,6 +246,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const {
return CommonPtr;
}
+void FunctionTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
+FunctionTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
FunctionDecl *
FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
unsigned NumArgs, void *&InsertPos) {
@@ -261,18 +279,17 @@ void FunctionTemplateDecl::addSpecialization(
L->AddedCXXTemplateSpecialization(this, Info->Function);
}
-std::pair<const TemplateArgument *, unsigned>
-FunctionTemplateDecl::getInjectedTemplateArgs() {
+ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
Common *CommonPtr = getCommonPtr();
if (!CommonPtr->InjectedArgs) {
CommonPtr->InjectedArgs
- = new (getASTContext()) TemplateArgument [Params->size()];
- GenerateInjectedTemplateArgs(getASTContext(), Params,
+ = new (getASTContext()) TemplateArgument[Params->size()];
+ GenerateInjectedTemplateArgs(getASTContext(), Params,
CommonPtr->InjectedArgs);
}
-
- return std::make_pair(CommonPtr->InjectedArgs, Params->size());
+
+ return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
}
//===----------------------------------------------------------------------===//
@@ -292,7 +309,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
ClassTemplateDecl *PrevDecl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
- New->setPreviousDeclaration(PrevDecl);
+ New->setPreviousDecl(PrevDecl);
return New;
}
@@ -381,13 +398,11 @@ void ClassTemplateDecl::getPartialSpecializations(
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &PartialSpecs
= getPartialSpecializations();
PS.clear();
- PS.resize(PartialSpecs.size());
+ PS.reserve(PartialSpecs.size());
for (llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>::iterator
P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
- P != PEnd; ++P) {
- assert(!PS[P->getSequenceNumber()]);
- PS[P->getSequenceNumber()] = P->getMostRecentDecl();
- }
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
}
ClassTemplatePartialSpecializationDecl *
@@ -813,19 +828,16 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
- TemplateArgumentLoc *ArgInfos,
- unsigned NumArgInfos,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber)
+ const ASTTemplateArgumentListInfo *ArgInfos,
+ ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
TK, DC, StartLoc, IdLoc,
SpecializedTemplate,
Args, NumArgs, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
InstantiatedFromMember(0, false)
-{
+{
AdoptTemplateParameterList(Params, this);
}
@@ -839,12 +851,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber) {
- unsigned N = ArgInfos.size();
- TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
- for (unsigned I = 0; I != N; ++I)
- ClonedArgs[I] = ArgInfos[I];
+ ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos =
+ ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
ClassTemplatePartialSpecializationDecl *Result
= new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
@@ -852,9 +861,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
Params,
SpecializedTemplate,
Args, NumArgs,
- ClonedArgs, N,
- PrevDecl,
- SequenceNumber);
+ ASTArgInfos,
+ PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->MayHaveOutOfDateDef = false;
@@ -942,3 +950,252 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0,
false, TemplateArgumentListInfo());
}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void VarTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
+VarTemplateDecl *VarTemplateDecl::getDefinition() {
+ VarTemplateDecl *CurD = this;
+ while (CurD) {
+ if (CurD->isThisDeclarationADefinition())
+ return CurD;
+ CurD = CurD->getPreviousDecl();
+ }
+ return 0;
+}
+
+VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ VarTemplateDecl *PrevDecl) {
+ VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl);
+ New->setPreviousDecl(PrevDecl);
+ return New;
+}
+
+VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl));
+ return new (Mem) VarTemplateDecl(EmptyShell());
+}
+
+// TODO: Unify accross class, function and variable templates?
+// May require moving this and Common to RedeclarableTemplateDecl.
+void VarTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
+VarTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
+llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
+VarTemplateDecl::getPartialSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->PartialSpecializations;
+}
+
+RedeclarableTemplateDecl::CommonBase *
+VarTemplateDecl::newCommon(ASTContext &C) const {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateDecl::findSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+}
+
+void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
+ void *InsertPos) {
+ if (InsertPos)
+ getSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplateSpecializationDecl *Existing =
+ getSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
+ InsertPos);
+}
+
+void VarTemplateDecl::AddPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *D, void *InsertPos) {
+ if (InsertPos)
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplatePartialSpecializationDecl *Existing =
+ getPartialSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+void VarTemplateDecl::getPartialSpecializations(
+ SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs =
+ getPartialSpecializations();
+ PS.clear();
+ PS.reserve(PartialSpecs.size());
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(),
+ PEnd = PartialSpecs.end();
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecInstantiatedFromMember(
+ VarTemplatePartialSpecializationDecl *D) {
+ Decl *DCanon = D->getCanonicalDecl();
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+ return P->getMostRecentDecl();
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
+ ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs)
+ : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T,
+ TInfo, S),
+ SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0),
+ TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
+ SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK)
+ : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0,
+ SC_None),
+ ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs) {
+ VarTemplateSpecializationDecl *Result = new (Context)
+ VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC,
+ StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs);
+ return Result;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem =
+ AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl));
+ VarTemplateSpecializationDecl *Result =
+ new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization);
+ return Result;
+}
+
+void VarTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
+
+ const TemplateArgumentList &TemplateArgs = getTemplateArgs();
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
+}
+
+VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+}
+
+void VarTemplateSpecializationDecl::setTemplateArgsInfo(
+ const TemplateArgumentListInfo &ArgsInfo) {
+ unsigned N = ArgsInfo.size();
+ TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc());
+ TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc());
+ for (unsigned I = 0; I != N; ++I)
+ TemplateArgsInfo.addArgument(ArgsInfo[I]);
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+void VarTemplatePartialSpecializationDecl::anchor() {}
+
+VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const ASTTemplateArgumentListInfo *ArgInfos)
+ : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization,
+ DC, StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs),
+ TemplateParams(Params), ArgsAsWritten(ArgInfos),
+ InstantiatedFromMember(0, false) {
+ // TODO: The template parameters should be in DC by now. Verify.
+ // AdoptTemplateParameterList(Params, DC);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const TemplateArgumentListInfo &ArgInfos) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos
+ = ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
+
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Context) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
+ S, Args, NumArgs, ASTArgInfos);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(
+ C, ID, sizeof(VarTemplatePartialSpecializationDecl));
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Mem) VarTemplatePartialSpecializationDecl();
+ return Result;
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index e4a41b6ffb50..e064e23a0ae9 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
llvm_unreachable("Invalid DeclarationName Kind!");
}
+raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
+ switch (N.getNameKind()) {
+ case DeclarationName::Identifier:
+ if (const IdentifierInfo *II = N.getAsIdentifierInfo())
+ OS << II->getName();
+ return OS;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return OS << N.getObjCSelector().getAsString();
+
+ case DeclarationName::CXXConstructorName: {
+ QualType ClassType = N.getCXXNameType();
+ if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
+ return OS << *ClassRec->getDecl();
+ return OS << ClassType.getAsString();
+ }
+
+ case DeclarationName::CXXDestructorName: {
+ OS << '~';
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+
+ case DeclarationName::CXXOperatorName: {
+ static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
+ 0,
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ Spelling,
+#include "clang/Basic/OperatorKinds.def"
+ };
+ const char *OpName = OperatorNames[N.getCXXOverloadedOperator()];
+ assert(OpName && "not an overloaded operator");
+
+ OS << "operator";
+ if (OpName[0] >= 'a' && OpName[0] <= 'z')
+ OS << ' ';
+ return OS << OpName;
+ }
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName();
+
+ case DeclarationName::CXXConversionFunctionName: {
+ OS << "operator ";
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+ case DeclarationName::CXXUsingDirective:
+ return OS << "<using-directive>";
+ }
+
+ llvm_unreachable("Unexpected declaration name kind");
+}
+
} // end namespace clang
DeclarationName::NameKind DeclarationName::getNameKind() const {
@@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const {
std::string DeclarationName::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
- printName(OS);
+ OS << *this;
return OS.str();
}
-void DeclarationName::printName(raw_ostream &OS) const {
- switch (getNameKind()) {
- case Identifier:
- if (const IdentifierInfo *II = getAsIdentifierInfo())
- OS << II->getName();
- return;
-
- case ObjCZeroArgSelector:
- case ObjCOneArgSelector:
- case ObjCMultiArgSelector:
- OS << getObjCSelector().getAsString();
- return;
-
- case CXXConstructorName: {
- QualType ClassType = getCXXNameType();
- if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- OS << *ClassRec->getDecl();
- else
- OS << ClassType.getAsString();
- return;
- }
-
- case CXXDestructorName: {
- OS << '~';
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
-
- case CXXOperatorName: {
- static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- 0,
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
- const char *OpName = OperatorNames[getCXXOverloadedOperator()];
- assert(OpName && "not an overloaded operator");
-
- OS << "operator";
- if (OpName[0] >= 'a' && OpName[0] <= 'z')
- OS << ' ';
- OS << OpName;
- return;
- }
-
- case CXXLiteralOperatorName:
- OS << "operator \"\" " << getCXXLiteralIdentifier()->getName();
- return;
-
- case CXXConversionFunctionName: {
- OS << "operator ";
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
- case CXXUsingDirective:
- OS << "<using-directive>";
- return;
- }
-
- llvm_unreachable("Unexpected declaration name kind");
-}
-
QualType DeclarationName::getCXXNameType() const {
if (CXXSpecialName *CXXName = getAsCXXSpecialName())
return CXXName->Type;
@@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
}
void DeclarationName::dump() const {
- printName(llvm::errs());
- llvm::errs() << '\n';
+ llvm::errs() << *this << '\n';
}
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
@@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
- Name.printName(OS);
+ OS << Name;
return;
case DeclarationName::CXXConstructorName:
@@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
OS << TInfo->getType().getAsString();
- }
- else
- Name.printName(OS);
+ } else
+ OS << Name;
return;
}
llvm_unreachable("Unexpected declaration name kind");
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
deleted file mode 100644
index be22ae450b62..000000000000
--- a/lib/AST/DumpXML.cpp
+++ /dev/null
@@ -1,1053 +0,0 @@
-//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===//
-//
-// 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 Decl::dumpXML() method, a debugging tool to
-// print a detailed graph of an AST in an unspecified XML format.
-//
-// There is no guarantee of stability for this format.
-//
-//===----------------------------------------------------------------------===//
-
-// Only pay for this in code size in assertions-enabled builds.
-
-#include "clang/AST/ASTContext.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/DeclVisitor.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/StmtVisitor.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/TypeLocVisitor.h"
-#include "clang/AST/TypeVisitor.h"
-#include "llvm/ADT/SmallString.h"
-
-using namespace clang;
-
-#ifndef NDEBUG
-
-namespace {
-
-enum NodeState {
- NS_Attrs, NS_LazyChildren, NS_Children
-};
-
-struct Node {
- StringRef Name;
- NodeState State;
- Node(StringRef name) : Name(name), State(NS_Attrs) {}
-
- bool isDoneWithAttrs() const { return State != NS_Attrs; }
-};
-
-template <class Impl> struct XMLDeclVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D))
-
- void dispatch(Decl *D) {
- if (D->isUsed())
- static_cast<Impl*>(this)->set("used", "1");
- switch (D->getKind()) {
-#define DECL(DERIVED, BASE) \
- case Decl::DERIVED: \
- DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \
- DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \
- break;
-#define ABSTRACT_DECL(DECL)
-#include "clang/AST/DeclNodes.inc"
- }
- }
-
-#define DECL(DERIVED, BASE) \
- void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##AsContext, BASE); \
- DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {}
-#include "clang/AST/DeclNodes.inc"
-
- void dispatchDeclAttrs(Decl *D) {
- DISPATCH(visitDeclAttrs, Decl);
- }
- void visitDeclAttrs(Decl *D) {}
-
- void dispatchDeclChildren(Decl *D) {
- DISPATCH(visitDeclChildren, Decl);
- }
- void visitDeclChildren(Decl *D) {}
-
- void dispatchDeclAsContext(Decl *D) {
- DISPATCH(visitDeclAsContext, Decl);
- }
- void visitDeclAsContext(Decl *D) {}
-
-#undef DISPATCH
-};
-
-template <class Impl> struct XMLTypeVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T))
-
- void dispatch(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) \
- case Type::DERIVED: \
- DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \
- break;
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
- }
-
-#define TYPE(DERIVED, BASE) \
- void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \
- void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeChildren(DERIVED##Type *T) {}
-#include "clang/AST/TypeNodes.def"
-
- void dispatchTypeAttrs(Type *T) {
- DISPATCH(visitTypeAttrs, Type);
- }
- void visitTypeAttrs(Type *T) {}
-
- void dispatchTypeChildren(Type *T) {
- DISPATCH(visitTypeChildren, Type);
- }
- void visitTypeChildren(Type *T) {}
-
-#undef DISPATCH
-};
-
-static StringRef getTypeKindName(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type";
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
-
- llvm_unreachable("unknown type kind!");
-}
-
-struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
- public XMLTypeVisitor<XMLDumper> {
- raw_ostream &out;
- ASTContext &Context;
- SmallVector<Node, 16> Stack;
- unsigned Indent;
- explicit XMLDumper(raw_ostream &OS, ASTContext &context)
- : out(OS), Context(context), Indent(0) {}
-
- void indent() {
- for (unsigned I = Indent; I; --I)
- out << ' ';
- }
-
- /// Push a new node on the stack.
- void push(StringRef name) {
- if (!Stack.empty()) {
- assert(Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- Stack.back().State = NS_Children;
- out << ">\n";
- }
- Indent++;
- indent();
- }
- Stack.push_back(Node(name));
- out << '<' << name;
- }
-
- /// Set the given attribute to the given value.
- void set(StringRef attr, StringRef value) {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation
- }
-
- /// Finish attributes.
- void completeAttrs() {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- Stack.back().State = NS_LazyChildren;
- }
-
- /// Pop a node.
- void pop() {
- assert(!Stack.empty() && Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- out << "/>\n";
- } else {
- indent();
- out << "</" << Stack.back().Name << ">\n";
- }
- if (Stack.size() > 1) Indent--;
- Stack.pop_back();
- }
-
- //---- General utilities -------------------------------------------//
-
- void setPointer(StringRef prop, const void *p) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << p;
- os.flush();
- set(prop, buffer);
- }
-
- void setPointer(void *p) {
- setPointer("ptr", p);
- }
-
- void setInteger(StringRef prop, const llvm::APSInt &v) {
- set(prop, v.toString(10));
- }
-
- void setInteger(StringRef prop, unsigned n) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << n;
- os.flush();
- set(prop, buffer);
- }
-
- void setFlag(StringRef prop, bool flag) {
- if (flag) set(prop, "true");
- }
-
- void setName(DeclarationName Name) {
- if (!Name)
- return set("name", "");
-
- // Common case.
- if (Name.isIdentifier())
- return set("name", Name.getAsIdentifierInfo()->getName());
-
- set("name", Name.getAsString());
- }
-
- class TemporaryContainer {
- XMLDumper &Dumper;
- public:
- TemporaryContainer(XMLDumper &dumper, StringRef name)
- : Dumper(dumper) {
- Dumper.push(name);
- Dumper.completeAttrs();
- }
-
- ~TemporaryContainer() {
- Dumper.pop();
- }
- };
-
- void visitTemplateParameters(TemplateParameterList *L) {
- push("template_parameters");
- completeAttrs();
- for (TemplateParameterList::iterator
- I = L->begin(), E = L->end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
-
- void visitTemplateArguments(const TemplateArgumentList &L) {
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = L.size(); I != E; ++I)
- dispatch(L[I]);
- pop();
- }
-
- /// Visits a reference to the given declaration.
- void visitDeclRef(Decl *D) {
- push(D->getDeclKindName());
- setPointer("ref", D);
- completeAttrs();
- pop();
- }
- void visitDeclRef(StringRef Name, Decl *D) {
- TemporaryContainer C(*this, Name);
- if (D) visitDeclRef(D);
- }
-
- void dispatch(const TemplateArgument &A) {
- switch (A.getKind()) {
- case TemplateArgument::Null: {
- TemporaryContainer C(*this, "null");
- break;
- }
- case TemplateArgument::Type: {
- dispatch(A.getAsType());
- break;
- }
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::NullPtr:
- // FIXME: Implement!
- break;
-
- case TemplateArgument::Declaration: {
- visitDeclRef(A.getAsDecl());
- break;
- }
- case TemplateArgument::Integral: {
- push("integer");
- setInteger("value", A.getAsIntegral());
- completeAttrs();
- pop();
- break;
- }
- case TemplateArgument::Expression: {
- dispatch(A.getAsExpr());
- break;
- }
- case TemplateArgument::Pack: {
- for (TemplateArgument::pack_iterator P = A.pack_begin(),
- PEnd = A.pack_end();
- P != PEnd; ++P)
- dispatch(*P);
- break;
- }
- }
- }
-
- void dispatch(const TemplateArgumentLoc &A) {
- dispatch(A.getArgument());
- }
-
- //---- Declarations ------------------------------------------------//
- // Calls are made in this order:
- // # Enter a new node.
- // push("FieldDecl")
- //
- // # In this phase, attributes are set on the node.
- // visitDeclAttrs(D)
- // visitNamedDeclAttrs(D)
- // ...
- // visitFieldDeclAttrs(D)
- //
- // # No more attributes after this point.
- // completeAttrs()
- //
- // # Create "header" child nodes, i.e. those which logically
- // # belong to the declaration itself.
- // visitDeclChildren(D)
- // visitNamedDeclChildren(D)
- // ...
- // visitFieldDeclChildren(D)
- //
- // # Create nodes for the lexical children.
- // visitDeclAsContext(D)
- // visitNamedDeclAsContext(D)
- // ...
- // visitFieldDeclAsContext(D)
- //
- // # Finish the node.
- // pop();
- void dispatch(Decl *D) {
- push(D->getDeclKindName());
- XMLDeclVisitor<XMLDumper>::dispatch(D);
- pop();
- }
- void visitDeclAttrs(Decl *D) {
- setPointer(D);
- }
-
- /// Visit all the lexical decls in the given context.
- void visitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
- dispatch(*I);
-
- // FIXME: point out visible declarations not in lexical context?
- }
-
- /// Set the "access" attribute on the current node according to the
- /// given specifier.
- void setAccess(AccessSpecifier AS) {
- switch (AS) {
- case AS_public: return set("access", "public");
- case AS_protected: return set("access", "protected");
- case AS_private: return set("access", "private");
- case AS_none: llvm_unreachable("explicit forbidden access");
- }
- }
-
- template <class T> void visitRedeclarableAttrs(T *D) {
- if (T *Prev = D->getPreviousDecl())
- setPointer("previous", Prev);
- }
-
-
- // TranslationUnitDecl
- void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) {
- visitDeclContext(D);
- }
-
- // LinkageSpecDecl
- void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
- StringRef lang = "";
- switch (D->getLanguage()) {
- case LinkageSpecDecl::lang_c: lang = "C"; break;
- case LinkageSpecDecl::lang_cxx: lang = "C++"; break;
- }
- set("lang", lang);
- }
- void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) {
- visitDeclContext(D);
- }
-
- // NamespaceDecl
- void visitNamespaceDeclAttrs(NamespaceDecl *D) {
- setFlag("inline", D->isInline());
- if (!D->isOriginalNamespace())
- setPointer("original", D->getOriginalNamespace());
- }
- void visitNamespaceDeclAsContext(NamespaceDecl *D) {
- visitDeclContext(D);
- }
-
- // NamedDecl
- void visitNamedDeclAttrs(NamedDecl *D) {
- setName(D->getDeclName());
- }
-
- // ValueDecl
- void visitValueDeclChildren(ValueDecl *D) {
- dispatch(D->getType());
- }
-
- // DeclaratorDecl
- void visitDeclaratorDeclChildren(DeclaratorDecl *D) {
- //dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // VarDecl
- void visitVarDeclAttrs(VarDecl *D) {
- visitRedeclarableAttrs(D);
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- StringRef initStyle = "";
- switch (D->getInitStyle()) {
- case VarDecl::CInit: initStyle = "c"; break;
- case VarDecl::CallInit: initStyle = "call"; break;
- case VarDecl::ListInit: initStyle = "list"; break;
- }
- set("initstyle", initStyle);
- setFlag("nrvo", D->isNRVOVariable());
- // TODO: instantiation, etc.
- }
- void visitVarDeclChildren(VarDecl *D) {
- if (D->hasInit()) dispatch(D->getInit());
- }
-
- // ParmVarDecl?
-
- // FunctionDecl
- void visitFunctionDeclAttrs(FunctionDecl *D) {
- visitRedeclarableAttrs(D);
- setFlag("pure", D->isPure());
- setFlag("trivial", D->isTrivial());
- setFlag("returnzero", D->hasImplicitReturnZero());
- setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeletedAsWritten());
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- setFlag("inline", D->isInlineSpecified());
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
- set("asmlabel", ALA->getLabel());
- // TODO: instantiation, etc.
- }
- void visitFunctionDeclChildren(FunctionDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
- E = D->getDeclsInPrototypeScope().end();
- I != E; ++I)
- dispatch(*I);
- if (D->doesThisDeclarationHaveABody())
- dispatch(D->getBody());
- }
-
- // CXXMethodDecl ?
- // CXXConstructorDecl ?
- // CXXDestructorDecl ?
- // CXXConversionDecl ?
-
- void dispatch(CXXCtorInitializer *Init) {
- // TODO
- }
-
- // FieldDecl
- void visitFieldDeclAttrs(FieldDecl *D) {
- setFlag("mutable", D->isMutable());
- }
- void visitFieldDeclChildren(FieldDecl *D) {
- if (D->isBitField()) {
- TemporaryContainer C(*this, "bitwidth");
- dispatch(D->getBitWidth());
- }
- // TODO: C++0x member initializer
- }
-
- // EnumConstantDecl
- void visitEnumConstantDeclChildren(EnumConstantDecl *D) {
- // value in any case?
- if (D->getInitExpr()) dispatch(D->getInitExpr());
- }
-
- // IndirectFieldDecl
- void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) {
- for (IndirectFieldDecl::chain_iterator
- I = D->chain_begin(), E = D->chain_end(); I != E; ++I) {
- NamedDecl *VD = const_cast<NamedDecl*>(*I);
- push(isa<VarDecl>(VD) ? "variable" : "field");
- setPointer("ptr", VD);
- completeAttrs();
- pop();
- }
- }
-
- // TypeDecl
- void visitTypeDeclAttrs(TypeDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- }
-
- // TypedefDecl
- void visitTypedefDeclAttrs(TypedefDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypedefDeclChildren(TypedefDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TypeAliasDecl
- void visitTypeAliasDeclAttrs(TypeAliasDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypeAliasDeclChildren(TypeAliasDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TagDecl
- void visitTagDeclAttrs(TagDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitTagDeclAsContext(TagDecl *D) {
- visitDeclContext(D);
- }
-
- // EnumDecl
- void visitEnumDeclAttrs(EnumDecl *D) {
- setFlag("scoped", D->isScoped());
- setFlag("fixed", D->isFixed());
- }
- void visitEnumDeclChildren(EnumDecl *D) {
- {
- TemporaryContainer C(*this, "promotion_type");
- dispatch(D->getPromotionType());
- }
- {
- TemporaryContainer C(*this, "integer_type");
- dispatch(D->getIntegerType());
- }
- }
-
- // RecordDecl ?
-
- void visitCXXRecordDeclChildren(CXXRecordDecl *D) {
- if (!D->isThisDeclarationADefinition()) return;
-
- for (CXXRecordDecl::base_class_iterator
- I = D->bases_begin(), E = D->bases_end(); I != E; ++I) {
- push("base");
- setAccess(I->getAccessSpecifier());
- completeAttrs();
- dispatch(I->getTypeSourceInfo()->getTypeLoc());
- pop();
- }
- }
-
- // ClassTemplateSpecializationDecl ?
-
- // FileScopeAsmDecl ?
-
- // BlockDecl
- void visitBlockDeclAttrs(BlockDecl *D) {
- setFlag("variadic", D->isVariadic());
- }
- void visitBlockDeclChildren(BlockDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- dispatch(D->getBody());
- }
-
- // AccessSpecDecl
- void visitAccessSpecDeclAttrs(AccessSpecDecl *D) {
- setAccess(D->getAccess());
- }
-
- // TemplateDecl
- void visitTemplateDeclChildren(TemplateDecl *D) {
- visitTemplateParameters(D->getTemplateParameters());
- if (D->getTemplatedDecl())
- dispatch(D->getTemplatedDecl());
- }
-
- // FunctionTemplateDecl
- void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (FunctionTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
- FunctionTemplateSpecializationInfo *Info
- = I->getTemplateSpecializationInfo();
-
- bool Unknown = false;
- switch (Info->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(*Info->TemplateArguments);
- dispatch(Info->Function);
- }
- }
-
- // ClasTemplateDecl
- void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitClassTemplateDeclChildren(ClassTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (ClassTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
-
- bool Unknown = false;
- switch (I->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(I->getTemplateArgs());
- dispatch(*I);
- }
- }
-
- // TemplateTypeParmDecl
- void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgumentInfo()->getTypeLoc());
- // parameter pack?
- }
-
- // NonTypeTemplateParmDecl
- void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // TemplateTemplateParmDecl
- void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // FriendDecl
- void visitFriendDeclChildren(FriendDecl *D) {
- if (TypeSourceInfo *T = D->getFriendType())
- dispatch(T->getTypeLoc());
- else
- dispatch(D->getFriendDecl());
- }
-
- // UsingDirectiveDecl ?
- // UsingDecl ?
- // UsingShadowDecl ?
- // NamespaceAliasDecl ?
- // UnresolvedUsingValueDecl ?
- // UnresolvedUsingTypenameDecl ?
- // StaticAssertDecl ?
-
- // ObjCImplDecl
- void visitObjCImplDeclChildren(ObjCImplDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
- void visitObjCImplDeclAsContext(ObjCImplDecl *D) {
- visitDeclContext(D);
- }
-
- void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- setFlag("forward_decl", !D->isThisDeclarationADefinition());
- setFlag("implicit_interface", D->isImplicitInterfaceDecl());
- }
- void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
-
- if (!D->visible_categories_empty()) {
- TemporaryContainer C(*this, "categories");
-
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = D->visible_categories_begin(),
- CatEnd = D->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- visitDeclRef(*Cat);
- }
- }
- }
- void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryDecl
- void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) {
- setFlag("extension", D->IsClassExtension());
- }
- void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) {
- visitDeclRef("interface", D->getClassInterface());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCCategoryDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryImplDecl
- void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) {
- visitDeclRef(D->getCategoryDecl());
- }
-
- // ObjCImplementationDecl
- void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- if (D->init_begin() != D->init_end()) {
- TemporaryContainer C(*this, "initializers");
- for (ObjCImplementationDecl::init_iterator
- I = D->init_begin(), E = D->init_end(); I != E; ++I)
- dispatch(*I);
- }
- }
-
- // ObjCProtocolDecl
- void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- visitDeclContext(D);
- }
-
- // ObjCMethodDecl
- void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) {
- // decl qualifier?
- // implementation control?
-
- setFlag("instance", D->isInstanceMethod());
- setFlag("variadic", D->isVariadic());
- setFlag("property_accessor", D->isPropertyAccessor());
- setFlag("defined", D->isDefined());
- setFlag("related_result_type", D->hasRelatedResultType());
- }
- void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
- dispatch(D->getResultType());
- for (ObjCMethodDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- if (D->isThisDeclarationADefinition())
- dispatch(D->getBody());
- }
-
- // ObjCIvarDecl
- void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) {
- switch (AC) {
- case ObjCIvarDecl::None: return set(prop, "none");
- case ObjCIvarDecl::Private: return set(prop, "private");
- case ObjCIvarDecl::Protected: return set(prop, "protected");
- case ObjCIvarDecl::Public: return set(prop, "public");
- case ObjCIvarDecl::Package: return set(prop, "package");
- }
- }
- void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) {
- setFlag("synthesize", D->getSynthesize());
- setAccessControl("access", D->getAccessControl());
- }
-
- // ObjCCompatibleAliasDecl
- void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
-
- // FIXME: ObjCPropertyDecl
- // FIXME: ObjCPropertyImplDecl
-
- //---- Types -----------------------------------------------------//
- void dispatch(TypeLoc TL) {
- dispatch(TL.getType()); // for now
- }
-
- void dispatch(QualType T) {
- if (T.hasLocalQualifiers()) {
- push("QualType");
- Qualifiers Qs = T.getLocalQualifiers();
- setFlag("const", Qs.hasConst());
- setFlag("volatile", Qs.hasVolatile());
- setFlag("restrict", Qs.hasRestrict());
- if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace());
- if (Qs.hasObjCGCAttr()) {
- switch (Qs.getObjCGCAttr()) {
- case Qualifiers::Weak: set("gc", "weak"); break;
- case Qualifiers::Strong: set("gc", "strong"); break;
- case Qualifiers::GCNone: llvm_unreachable("explicit none");
- }
- }
-
- completeAttrs();
- dispatch(QualType(T.getTypePtr(), 0));
- pop();
- return;
- }
-
- Type *Ty = const_cast<Type*>(T.getTypePtr());
- push(getTypeKindName(Ty));
- XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr()));
- pop();
- }
-
- void setCallingConv(CallingConv CC) {
- switch (CC) {
- case CC_Default: return;
- case CC_C: return set("cc", "cdecl");
- case CC_X86FastCall: return set("cc", "x86_fastcall");
- case CC_X86StdCall: return set("cc", "x86_stdcall");
- case CC_X86ThisCall: return set("cc", "x86_thiscall");
- case CC_X86Pascal: return set("cc", "x86_pascal");
- case CC_AAPCS: return set("cc", "aapcs");
- case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
- case CC_PnaclCall: return set("cc", "pnaclcall");
- case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
- }
- }
-
- void visitTypeAttrs(Type *D) {
- setPointer(D);
- setFlag("dependent", D->isDependentType());
- setFlag("variably_modified", D->isVariablyModifiedType());
-
- setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr());
- }
-
- void visitPointerTypeChildren(PointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitReferenceTypeChildren(ReferenceType *T) {
- dispatch(T->getPointeeType());
- }
- void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitBlockPointerTypeChildren(BlockPointerType *T) {
- dispatch(T->getPointeeType());
- }
-
- // Types that just wrap declarations.
- void visitTagTypeChildren(TagType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitTypedefTypeChildren(TypedefType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) {
- visitDeclRef(T->getDecl());
- }
-
- void visitFunctionTypeAttrs(FunctionType *T) {
- setFlag("noreturn", T->getNoReturnAttr());
- setCallingConv(T->getCallConv());
- if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType());
- }
- void visitFunctionTypeChildren(FunctionType *T) {
- dispatch(T->getResultType());
- }
-
- void visitFunctionProtoTypeAttrs(FunctionProtoType *T) {
- setFlag("const", T->isConst());
- setFlag("volatile", T->isVolatile());
- setFlag("restrict", T->isRestrict());
- switch (T->getExceptionSpecType()) {
- case EST_None: break;
- case EST_DynamicNone: set("exception_spec", "throw()"); break;
- case EST_Dynamic: set("exception_spec", "throw(T)"); break;
- case EST_MSAny: set("exception_spec", "throw(...)"); break;
- case EST_BasicNoexcept: set("exception_spec", "noexcept"); break;
- case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break;
- case EST_Unevaluated: set("exception_spec", "unevaluated"); break;
- case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break;
- }
- }
- void visitFunctionProtoTypeChildren(FunctionProtoType *T) {
- push("parameters");
- setFlag("variadic", T->isVariadic());
- completeAttrs();
- for (FunctionProtoType::arg_type_iterator
- I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I)
- dispatch(*I);
- pop();
-
- if (T->hasDynamicExceptionSpec()) {
- push("exception_specifiers");
- setFlag("any", T->getExceptionSpecType() == EST_MSAny);
- completeAttrs();
- for (FunctionProtoType::exception_iterator
- I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
- // FIXME: noexcept specifier
- }
-
- void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) {
- if (const RecordType *RT = T->getAs<RecordType>())
- visitDeclRef(RT->getDecl());
-
- // TODO: TemplateName
-
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I)
- dispatch(T->getArg(I));
- pop();
- }
-
- //---- Statements ------------------------------------------------//
- void dispatch(Stmt *S) {
- // FIXME: this is not really XML at all
- push("Stmt");
- out << ">\n";
- Stack.back().State = NS_Children; // explicitly become non-lazy
- S->dump(out, Context.getSourceManager());
- out << '\n';
- pop();
- }
-};
-}
-
-void Decl::dumpXML() const {
- dumpXML(llvm::errs());
-}
-
-void Decl::dumpXML(raw_ostream &out) const {
- XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
-}
-
-#else /* ifndef NDEBUG */
-
-void Decl::dumpXML() const {}
-void Decl::dumpXML(raw_ostream &out) const {}
-
-#endif
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9538ddf9416c..9055ddac35e3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
@@ -50,9 +51,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
return cast<CXXRecordDecl>(D);
}
-const Expr *
-Expr::skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+const Expr *Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHSs,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
const Expr *E = this;
while (true) {
E = E->IgnoreParens();
@@ -73,12 +74,14 @@ Expr::skipRValueSubobjectAdjustments(
continue;
}
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ if (!ME->isArrow()) {
assert(ME->getBase()->getType()->isRecordType());
if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- E = ME->getBase();
- Adjustments.push_back(SubobjectAdjustment(Field));
- continue;
+ if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field));
+ continue;
+ }
}
}
} else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -88,6 +91,11 @@ Expr::skipRValueSubobjectAdjustments(
const MemberPointerType *MPT =
BO->getRHS()->getType()->getAs<MemberPointerType>();
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ continue;
+ } else if (BO->getOpcode() == BO_Comma) {
+ CommaLHSs.push_back(BO->getLHS());
+ E = BO->getRHS();
+ continue;
}
}
@@ -231,8 +239,8 @@ SourceLocation Expr::getExprLoc() const {
/// \brief Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
-static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
- bool &TypeDependent,
+static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D,
+ QualType T, bool &TypeDependent,
bool &ValueDependent,
bool &InstantiationDependent) {
TypeDependent = false;
@@ -307,6 +315,9 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
Var->getDeclContext()->isDependentContext()) {
ValueDependent = true;
InstantiationDependent = true;
+ TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo();
+ if (TInfo->getType()->isIncompleteArrayType())
+ TypeDependent = true;
}
return;
@@ -321,7 +332,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
}
}
-void DeclRefExpr::computeDependence(ASTContext &Ctx) {
+void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
bool TypeDependent = false;
bool ValueDependent = false;
bool InstantiationDependent = false;
@@ -355,7 +366,7 @@ void DeclRefExpr::computeDependence(ASTContext &Ctx) {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
+DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D, bool RefersToEnclosingLocal,
@@ -392,7 +403,7 @@ DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
computeDependence(Ctx);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -408,7 +419,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
T, VK, FoundD, TemplateArgs);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -423,7 +434,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
FoundD = 0;
std::size_t Size = sizeof(DeclRefExpr);
- if (QualifierLoc != 0)
+ if (QualifierLoc)
Size += sizeof(NestedNameSpecifierLoc);
if (FoundD)
Size += sizeof(NamedDecl *);
@@ -438,7 +449,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NameInfo, FoundD, TemplateArgs, T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
@@ -471,6 +482,30 @@ SourceLocation DeclRefExpr::getLocEnd() const {
std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
ASTContext &Context = CurrentDecl->getASTContext();
+ if (IT == PredefinedExpr::FuncDName) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
+ OwningPtr<MangleContext> MC;
+ MC.reset(Context.createMangleContext());
+
+ if (MC->shouldMangleDeclName(ND)) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
+ MC->mangleCXXCtor(CD, Ctor_Base, Out);
+ else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
+ MC->mangleCXXDtor(DD, Dtor_Base, Out);
+ else
+ MC->mangleName(ND, Out);
+
+ Out.flush();
+ if (!Buffer.empty() && Buffer.front() == '\01')
+ return Buffer.substr(1);
+ return Buffer.str();
+ } else
+ return ND->getIdentifier()->getName();
+ }
+ return "";
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
@@ -578,7 +613,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut.flush();
- if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
+ // Print "auto" for all deduced return types. This includes C++1y return
+ // type deduction and lambdas. For trailing return types resolve the
+ // decltype expression. Otherwise print the real type when this is
+ // not a constructor or destructor.
+ if ((isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
+ (FT && FT->getResultType()->getAs<AutoType>()))
+ Proto = "auto " + Proto;
+ else if (FT && FT->getResultType()->getAs<DecltypeType>())
+ FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType()
+ .getAsStringInternal(Proto, Policy);
+ else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
AFT->getResultType().getAsStringInternal(Proto, Policy);
Out << Proto;
@@ -586,6 +632,16 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
Out.flush();
return Name.str().str();
}
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) {
+ for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent())
+ // Skip to its enclosing function or method, but not its enclosing
+ // CapturedDecl.
+ if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) {
+ const Decl *D = Decl::castFromDeclContext(DC);
+ return ComputeName(IT, D);
+ }
+ llvm_unreachable("CapturedDecl not inside a function or method");
+ }
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
@@ -615,7 +671,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
-void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
+void APNumericStorage::setIntValue(const ASTContext &C,
+ const llvm::APInt &Val) {
if (hasAllocation())
C.Deallocate(pVal);
@@ -631,7 +688,7 @@ void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
VAL = 0;
}
-IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l)
: Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -643,17 +700,17 @@ IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l) {
return new (C) IntegerLiteral(C, V, type, l);
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) {
+IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) IntegerLiteral(Empty);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
@@ -662,20 +719,20 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
setValue(C, V);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
+FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L) {
return new (C) FloatingLiteral(C, V, isexact, Type, L);
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
+FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
@@ -749,7 +806,7 @@ int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) {
return CharByteWidth;
}
-StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
+StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
@@ -771,7 +828,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
return SL;
}
-StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
+StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C,
+ unsigned NumStrs) {
void *Mem = C.Allocate(sizeof(StringLiteral)+
sizeof(SourceLocation)*(NumStrs-1),
llvm::alignOf<StringLiteral>());
@@ -875,7 +933,7 @@ void StringLiteral::outputString(raw_ostream &OS) const {
OS << '"';
}
-void StringLiteral::setString(ASTContext &C, StringRef Str,
+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.
@@ -1028,9 +1086,9 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
-CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation rparenloc)
+CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
+ unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t,
+ ExprValueKind VK, SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
@@ -1057,7 +1115,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
+CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: Expr(CallExprClass, t, VK, OK_Ordinary,
fn->isTypeDependent(),
@@ -1085,14 +1143,14 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty)
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START];
CallExprBits.NumPreArgs = 0;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs,
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
@@ -1131,7 +1189,7 @@ FunctionDecl *CallExpr::getDirectCallee() {
/// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set
/// to null.
-void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
+void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) {
// No change, just return.
if (NumArgs == getNumArgs()) return;
@@ -1220,7 +1278,7 @@ SourceLocation CallExpr::getLocEnd() const {
return end;
}
-OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
+OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps,
@@ -1234,7 +1292,7 @@ OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
RParenLoc);
}
-OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C,
unsigned numComps, unsigned numExprs) {
void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
sizeof(OffsetOfNode) * numComps +
@@ -1242,7 +1300,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
return new (Mem) OffsetOfExpr(numComps, numExprs);
}
-OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
+OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc)
@@ -1276,7 +1334,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
}
-MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
+MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *memberdecl,
@@ -1630,7 +1688,7 @@ void CastExpr::setCastPath(const CXXCastPath &Path) {
memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*));
}
-ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
+ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
ExprValueKind VK) {
@@ -1643,7 +1701,7 @@ ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
+ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -1651,7 +1709,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
}
-CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
+CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
@@ -1665,7 +1723,8 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C,
+ unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize);
@@ -1774,7 +1833,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
+InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -1782,7 +1841,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
- setInitializesStdInitializerList(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -1797,16 +1855,16 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
}
-void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) {
if (NumInits > InitExprs.size())
InitExprs.reserve(C, NumInits);
}
-void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) {
InitExprs.resize(C, NumInits, 0);
}
-Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
+Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
@@ -1923,6 +1981,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()->
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ case ChooseExprClass:
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->
+ isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -2066,17 +2127,24 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
case CXXTemporaryObjectExprClass:
- case CXXConstructExprClass:
+ case CXXConstructExprClass: {
+ if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
+ if (Type->hasAttr<WarnUnusedAttr>()) {
+ WarnE = this;
+ Loc = getLocStart();
+ R1 = getSourceRange();
+ return true;
+ }
+ }
return false;
+ }
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
if (Ctx.getLangOpts().ObjCAutoRefCount &&
ME->isInstanceMessage() &&
!ME->getType()->isVoidType() &&
- ME->getSelector().getIdentifierInfoForSlot(0) &&
- ME->getSelector().getIdentifierInfoForSlot(0)
- ->getName().startswith("init")) {
+ ME->getMethodFamily() == OMF_init) {
WarnE = this;
Loc = getExprLoc();
R1 = ME->getSourceRange();
@@ -2161,7 +2229,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
WarnE = this;
if (const CXXFunctionalCastExpr *CXXCE =
dyn_cast<CXXFunctionalCastExpr>(this)) {
- Loc = CXXCE->getTypeBeginLoc();
+ Loc = CXXCE->getLocStart();
R1 = CXXCE->getSubExpr()->getSourceRange();
} else {
const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this);
@@ -2291,6 +2359,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
+ if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) {
+ if (!P->isConditionDependent()) {
+ E = P->getChosenSubExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -2300,26 +2374,11 @@ Expr* Expr::IgnoreParens() {
Expr *Expr::IgnoreParenCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2341,24 +2400,12 @@ Expr *Expr::IgnoreParenCasts() {
Expr *Expr::IgnoreParenLValueCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- } else if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ E = E->IgnoreParens();
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
if (P->getCastKind() == CK_LValueToRValue) {
E = P->getSubExpr();
continue;
}
- } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
} else if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2376,10 +2423,7 @@ Expr *Expr::IgnoreParenLValueCasts() {
Expr *Expr::ignoreParenBaseCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
if (CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
@@ -2396,26 +2440,11 @@ Expr *Expr::ignoreParenBaseCasts() {
Expr *Expr::IgnoreParenImpCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2444,10 +2473,7 @@ Expr *Expr::IgnoreConversionOperator() {
Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
// We ignore integer <-> casts that are of the same width, ptr<->ptr and
@@ -2469,20 +2495,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
-
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
-
if (SubstNonTypeTemplateParmExpr *NTTP
= dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
E = NTTP->getReplacement();
@@ -2628,11 +2640,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// This function is attempting whether an expression is an initializer
- // which can be evaluated at compile-time. isEvaluatable handles most
- // of the cases, but it can't deal with some initializer-specific
- // expressions, and it can't deal with aggregates; we deal with those here,
- // and fall back to isEvaluatable for the other cases.
-
+ // which can be evaluated at compile-time. It very closely parallels
+ // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
+ // will lead to unexpected results. Like ConstExprEmitter, it falls back
+ // to isEvaluatable most of the time.
+ //
// If we ever capture reference-binding directly in the AST, we can
// kill the second parameter.
@@ -2643,30 +2655,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
switch (getStmtClass()) {
default: break;
- case IntegerLiteralClass:
- case FloatingLiteralClass:
case StringLiteralClass:
- case ObjCStringLiteralClass:
case ObjCEncodeExprClass:
return true;
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
- // Only if it's
- if (CE->getConstructor()->isTrivial()) {
- // 1) an application of the trivial default constructor or
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->getParent()->hasTrivialDestructor()) {
+ // Trivial default constructor
if (!CE->getNumArgs()) return true;
- // 2) an elidable trivial copy construction of an operand which is
- // itself a constant initializer. Note that we consider the
- // operand on its own, *not* as a reference binding.
- if (CE->isElidable() &&
- CE->getArg(0)->isConstantInitializer(Ctx, false))
- return true;
+ // Trivial copy constructor
+ assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
+ return CE->getArg(0)->isConstantInitializer(Ctx, false);
}
- // 3) a foldable constexpr constructor.
break;
}
case CompoundLiteralExprClass: {
@@ -2677,16 +2682,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return Exp->isConstantInitializer(Ctx, false);
}
case InitListExprClass: {
- // FIXME: This doesn't deal with fields with reference types correctly.
- // FIXME: This incorrectly allows pointers cast to integers to be assigned
- // to bitfields.
- const InitListExpr *Exp = cast<InitListExpr>(this);
- unsigned numInits = Exp->getNumInits();
- for (unsigned i = 0; i < numInits; i++) {
- if (!Exp->getInit(i)->isConstantInitializer(Ctx, false))
- return false;
+ const InitListExpr *ILE = cast<InitListExpr>(this);
+ if (ILE->getType()->isArrayType()) {
+ unsigned numInits = ILE->getNumInits();
+ for (unsigned i = 0; i < numInits; i++) {
+ if (!ILE->getInit(i)->isConstantInitializer(Ctx, false))
+ return false;
+ }
+ return true;
}
- return true;
+
+ if (ILE->getType()->isRecordType()) {
+ unsigned ElementNo = 0;
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (ElementNo < ILE->getNumInits()) {
+ const Expr *Elt = ILE->getInit(ElementNo++);
+ if (Field->isBitField()) {
+ // Bitfields have to evaluate to an integer.
+ llvm::APSInt ResultTmp;
+ if (!Elt->EvaluateAsInt(ResultTmp, Ctx))
+ return false;
+ } else {
+ bool RefType = Field->getType()->isReferenceType();
+ if (!Elt->isConstantInitializer(Ctx, RefType))
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ break;
}
case ImplicitValueInitExprClass:
return true;
@@ -2694,12 +2730,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case GenericSelectionExprClass:
- if (cast<GenericSelectionExpr>(this)->isResultDependent())
- return false;
return cast<GenericSelectionExpr>(this)->getResultExpr()
->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
+ if (cast<ChooseExpr>(this)->isConditionDependent())
+ return false;
+ return cast<ChooseExpr>(this)->getChosenSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
@@ -2710,31 +2746,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
- case CStyleCastExprClass: {
+ case CStyleCastExprClass:
+ case ObjCBridgedCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass: {
const CastExpr *CE = cast<CastExpr>(this);
- // If we're promoting an integer to an _Atomic type then this is constant
- // if the integer is constant. We also need to check the converse in case
- // someone does something like:
- //
- // int a = (_Atomic(int))42;
- //
- // I doubt anyone would write code like this directly, but it's quite
- // possible as the result of macro expansions.
- if (CE->getCastKind() == CK_NonAtomicToAtomic ||
- CE->getCastKind() == CK_AtomicToNonAtomic)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
- // Handle bitcasts of vector constants.
- if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
// Handle misc casts we want to ignore.
- // FIXME: Is it really safe to ignore all these?
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_LValueToRValue ||
CE->getCastKind() == CK_ToUnion ||
- CE->getCastKind() == CK_ConstructorConversion)
+ CE->getCastKind() == CK_ConstructorConversion ||
+ CE->getCastKind() == CK_NonAtomicToAtomic ||
+ CE->getCastKind() == CK_AtomicToNonAtomic)
return CE->getSubExpr()->isConstantInitializer(Ctx, false);
break;
@@ -2742,6 +2767,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
->isConstantInitializer(Ctx, false);
+
+ case SubstNonTypeTemplateParmExprClass:
+ return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultInitExprClass:
+ return cast<CXXDefaultInitExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
}
return isEvaluatable(Ctx);
}
@@ -2829,9 +2864,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case DesignatedInitExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
case ShuffleVectorExprClass:
+ case ConvertVectorExprClass:
case AsTypeExprClass:
// These have a side-effect if any subexpression does.
break;
@@ -2858,7 +2895,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
HasSideEffects(Ctx);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx);
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx);
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
@@ -3017,7 +3054,8 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
Expr::NullPointerConstantKind
Expr::isNullPointerConstant(ASTContext &Ctx,
NullPointerConstantValueDependence NPC) const {
- if (isValueDependent()) {
+ if (isValueDependent() &&
+ (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) {
switch (NPC) {
case NPC_NeverValueDependent:
llvm_unreachable("Unexpected value dependent expression!");
@@ -3053,7 +3091,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const GenericSelectionExpr *GE =
dyn_cast<GenericSelectionExpr>(this)) {
+ if (GE->isResultDependent())
+ return NPCK_NotNull;
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) {
+ if (CE->isConditionDependent())
+ return NPCK_NotNull;
+ return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions.
@@ -3078,7 +3122,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (!Ctx.getLangOpts().CPlusPlus11 &&
+ UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){
const Expr *InitExpr = CLE->getInitializer();
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr))
@@ -3089,14 +3134,19 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
(Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType()))
return NPCK_NotNull;
- // If we have an integer constant expression, we need to *evaluate* it and
- // test for the value 0. Don't use the C++11 constant expression semantics
- // for this, for now; once the dust settles on core issue 903, we might only
- // allow a literal 0 here in C++11 mode.
if (Ctx.getLangOpts().CPlusPlus11) {
- if (!isCXX98IntegralConstantExpr(Ctx))
+ // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with
+ // value zero or a prvalue of type std::nullptr_t.
+ // Microsoft mode permits C++98 rules reflecting MSVC behavior.
+ const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this);
+ if (Lit && !Lit->getValue())
+ return NPCK_ZeroLiteral;
+ else if (!Ctx.getLangOpts().MicrosoftMode ||
+ !isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
+ // If we have an integer constant expression, we need to *evaluate* it and
+ // test for the value 0.
if (!isIntegerConstantExpr(Ctx))
return NPCK_NotNull;
}
@@ -3370,7 +3420,7 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args,
}
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
@@ -3395,7 +3445,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
Method, Args, RBracLoc, isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
@@ -3418,7 +3468,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
@@ -3441,14 +3491,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
+ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
ArrayRef<Expr *> Args,
SourceLocation RBraceLoc,
ArrayRef<SourceLocation> SelLocs,
@@ -3460,7 +3510,7 @@ ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
return alloc(C, Args.size(), NumStoredSelLocs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
@@ -3537,11 +3587,7 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
llvm_unreachable("Invalid BridgeKind!");
}
-bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
- return getCond()->EvaluateKnownConstInt(C) != 0;
-}
-
-ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
+ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args,
QualType Type, SourceLocation BLoc,
SourceLocation RP)
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
@@ -3565,16 +3611,15 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
}
}
-void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
- unsigned NumExprs) {
+void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) {
if (SubExprs) C.Deallocate(SubExprs);
- SubExprs = new (C) Stmt* [NumExprs];
- this->NumExprs = NumExprs;
- memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
+ this->NumExprs = Exprs.size();
+ SubExprs = new (C) Stmt*[NumExprs];
+ memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size());
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3600,7 +3645,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3637,7 +3682,7 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
+DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
@@ -3704,7 +3749,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
}
DesignatedInitExpr *
-DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators,
unsigned NumDesignators,
ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
@@ -3716,14 +3761,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
IndexExprs, Init);
}
-DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
+DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C,
unsigned NumIndexExprs) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
-void DesignatedInitExpr::setDesignators(ASTContext &C,
+void DesignatedInitExpr::setDesignators(const ASTContext &C,
const Designator *Desigs,
unsigned NumDesigs) {
Designators = new (C) Designator[NumDesigs];
@@ -3790,7 +3835,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
+void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
@@ -3815,7 +3860,7 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
-ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
+ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
@@ -3847,7 +3892,8 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
return cast<OpaqueValueExpr>(e);
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context,
+ EmptyShell sh,
unsigned numSemanticExprs) {
void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
(1 + numSemanticExprs) * sizeof(Expr*),
@@ -3860,7 +3906,7 @@ PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax,
ArrayRef<Expr*> semantics,
unsigned resultIndex) {
assert(syntax && "no syntactic expression!");
@@ -3975,7 +4021,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
}
}
-ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C,
ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
@@ -3984,7 +4030,7 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR);
}
-ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C,
unsigned NumElements) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
@@ -4029,7 +4075,7 @@ ObjCDictionaryLiteral::ObjCDictionaryLiteral(
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::Create(ASTContext &C,
+ObjCDictionaryLiteral::Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions,
QualType T, ObjCMethodDecl *method,
@@ -4044,7 +4090,7 @@ ObjCDictionaryLiteral::Create(ASTContext &C,
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
+ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements,
bool HasPackExpansions) {
unsigned ExpansionsSize = 0;
if (HasPackExpansions)
@@ -4055,7 +4101,7 @@ ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
HasPackExpansions);
}
-ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
+ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C,
Expr *base,
Expr *key, QualType T,
ObjCMethodDecl *getMethod,
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 402d7b532b21..3738c0e4f2c9 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -40,46 +40,106 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const {
return false;
}
-QualType CXXTypeidExpr::getTypeOperand() const {
+QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
-QualType CXXUuidofExpr::getTypeOperand() const {
+QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
// static
-UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
+ bool *RDHasMultipleGUIDsPtr) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
if (QT->isPointerType() || QT->isReferenceType())
Ty = QT->getPointeeType().getTypePtr();
else if (QT->isArrayType())
- Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
+ Ty = Ty->getBaseElementTypeUnsafe();
// Loop all record redeclaration looking for an uuid attribute.
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return 0;
+
+ // __uuidof can grab UUIDs from template arguments.
+ if (ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ UuidAttr *UuidForRD = 0;
+
+ for (unsigned I = 0, N = TAL.size(); I != N; ++I) {
+ const TemplateArgument &TA = TAL[I];
+ bool SeenMultipleGUIDs = false;
+
+ UuidAttr *UuidForTA = 0;
+ if (TA.getKind() == TemplateArgument::Type)
+ UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs);
+ else if (TA.getKind() == TemplateArgument::Declaration)
+ UuidForTA =
+ GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs);
+
+ // If the template argument has a UUID, there are three cases:
+ // - This is the first UUID seen for this RecordDecl.
+ // - This is a different UUID than previously seen for this RecordDecl.
+ // - This is the same UUID than previously seen for this RecordDecl.
+ if (UuidForTA) {
+ if (!UuidForRD)
+ UuidForRD = UuidForTA;
+ else if (UuidForRD != UuidForTA)
+ SeenMultipleGUIDs = true;
+ }
+
+ // Seeing multiple UUIDs means that we couldn't find a UUID
+ if (SeenMultipleGUIDs) {
+ if (RDHasMultipleGUIDsPtr)
+ *RDHasMultipleGUIDsPtr = true;
+ return 0;
+ }
+ }
+
+ return UuidForRD;
+ }
+
for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
+ E = RD->redecls_end();
+ I != E; ++I)
if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
return Uuid;
- }
return 0;
}
+StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const {
+ StringRef Uuid;
+ if (isTypeOperand())
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(getTypeOperand(Context))->getGuid();
+ else {
+ // Special case: __uuidof(0) means an all-zero GUID.
+ Expr *Op = getExprOperand();
+ if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid();
+ else
+ Uuid = "00000000-0000-0000-0000-000000000000";
+ }
+ return Uuid;
+}
+
// CXXScalarValueInitExpr
SourceLocation CXXScalarValueInitExpr::getLocStart() const {
return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
-CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- FunctionDecl *operatorDelete,
+CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
+ FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
@@ -134,11 +194,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
this->Range.setEnd(DirectInitRange.getEnd()); break;
case ListInit:
this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break;
- default: break;
+ default:
+ if (TypeIdParens.isValid())
+ this->Range.setEnd(TypeIdParens.getEnd());
+ break;
}
}
-void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
+void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray,
unsigned numPlaceArgs, bool hasInitializer){
assert(SubExprs == 0 && "SubExprs already allocated");
Array = isArray;
@@ -148,7 +211,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
SubExprs = new (C) Stmt*[TotalSize];
}
-bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
+bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const {
return getOperatorNew()->getType()->
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
@@ -172,14 +235,16 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
}
-CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
+CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, None,
- FunctionProtoType::ExtProtoInfo())),
+ Context.getPointerType(Context.getFunctionType(
+ Context.VoidTy, None,
+ FunctionProtoType::ExtProtoInfo(
+ Context.getDefaultCallingConvention(false, true)))),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
@@ -224,7 +289,7 @@ SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
-UnresolvedLookupExpr::Create(ASTContext &C,
+UnresolvedLookupExpr::Create(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -245,7 +310,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
}
UnresolvedLookupExpr *
-UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
+UnresolvedLookupExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
@@ -258,7 +323,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
return E;
}
-OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
+OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
@@ -330,7 +395,7 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
setType(C.DependentTy);
}
-void OverloadExpr::initializeResults(ASTContext &C,
+void OverloadExpr::initializeResults(const ASTContext &C,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
assert(Results == 0 && "Results already initialized!");
@@ -386,11 +451,12 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::Create(ASTContext &C,
+DependentScopeDeclRefExpr::Create(const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
+ assert(QualifierLoc && "should be created for dependent qualifiers");
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size());
@@ -402,7 +468,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
+DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
@@ -427,8 +493,8 @@ SourceLocation CXXConstructExpr::getLocEnd() const {
if (isa<CXXTemporaryObjectExpr>(this))
return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
- if (ParenRange.isValid())
- return ParenRange.getEnd();
+ if (ParenOrBraceRange.isValid())
+ return ParenOrBraceRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -520,7 +586,7 @@ const char *CXXNamedCastExpr::getCastName() const {
}
}
-CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
+CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -538,14 +604,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C,
+CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize);
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
+CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -563,7 +629,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
+CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -604,8 +670,8 @@ bool CXXDynamicCastExpr::isAlwaysNull() const
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- CastKind K, Expr *Op,
+CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T,
+ ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc,
@@ -621,13 +687,13 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize);
}
-CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
+CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
@@ -636,31 +702,39 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
-CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
+CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) {
return new (C) CXXConstCastExpr(EmptyShell());
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- TypeSourceInfo *Written, SourceLocation L,
- CastKind K, Expr *Op, const CXXCastPath *BasePath,
- SourceLocation R) {
+CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK,
+ TypeSourceInfo *Written, CastKind K, Expr *Op,
+ const CXXCastPath *BasePath,
+ SourceLocation L, SourceLocation R) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXFunctionalCastExpr *E =
- new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R);
+ new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
+SourceLocation CXXFunctionalCastExpr::getLocStart() const {
+ return getTypeInfoAsWritten()->getTypeLoc().getLocStart();
+}
+
+SourceLocation CXXFunctionalCastExpr::getLocEnd() const {
+ return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getLocEnd();
+}
+
UserDefinedLiteral::LiteralOperatorKind
UserDefinedLiteral::getLiteralOperatorKind() const {
if (getNumArgs() == 0)
@@ -696,14 +770,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
}
CXXDefaultArgExpr *
-CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
+CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc,
ParmVarDecl *Param, Expr *SubExpr) {
void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *));
return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
SubExpr);
}
-CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
+CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field, QualType T)
: Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType()
@@ -714,12 +788,12 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
assert(Field->hasInClassInitializer());
}
-CXXTemporary *CXXTemporary::Create(ASTContext &C,
+CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
}
-CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
+CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
CXXTemporary *Temp,
Expr* SubExpr) {
assert((SubExpr->getType()->isRecordType() ||
@@ -729,11 +803,11 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
}
-CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
+CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
ArrayRef<Expr*> Args,
- SourceRange parenRange,
+ SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization)
@@ -743,7 +817,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Cons, false, Args,
HadMultipleCandidates,
ListInitialization, ZeroInitialization,
- CXXConstructExpr::CK_Complete, parenRange),
+ CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
}
@@ -752,10 +826,13 @@ SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
}
SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
- return getParenRange().getEnd();
+ SourceLocation Loc = getParenOrBraceRange().getEnd();
+ if (Loc.isInvalid() && getNumArgs())
+ Loc = getArg(getNumArgs()-1)->getLocEnd();
+ return Loc;
}
-CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
ArrayRef<Expr*> Args,
@@ -763,28 +840,29 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange) {
+ SourceRange ParenOrBraceRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args,
HadMultipleCandidates, ListInitialization,
ZeroInitialization, ConstructKind,
- ParenRange);
+ ParenOrBraceRange);
}
-CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
- SourceLocation Loc,
+CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
+ QualType T, SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange)
+ SourceRange ParenOrBraceRange)
: Expr(SC, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()),
+ Constructor(D), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange),
+ NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
@@ -811,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
LambdaCaptureKind Kind, VarDecl *Var,
SourceLocation EllipsisLoc)
- : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
+ : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
{
unsigned Bits = 0;
if (Implicit)
@@ -829,20 +907,22 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
assert(Var && "capture must have a variable!");
break;
}
- VarAndBits.setInt(Bits);
+ DeclAndBits.setInt(Bits);
}
LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
- if (capturesThis())
+ Decl *D = DeclAndBits.getPointer();
+ if (!D)
return LCK_This;
- return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef;
+ return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
}
-LambdaExpr::LambdaExpr(QualType T,
+LambdaExpr::LambdaExpr(QualType T,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -854,6 +934,7 @@ LambdaExpr::LambdaExpr(QualType T,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
ContainsUnexpandedParameterPack),
IntroducerRange(IntroducerRange),
+ CaptureDefaultLoc(CaptureDefaultLoc),
NumCaptures(Captures.size()),
CaptureDefault(CaptureDefault),
ExplicitParams(ExplicitParams),
@@ -867,7 +948,7 @@ LambdaExpr::LambdaExpr(QualType T,
// FIXME: Propagate "has unexpanded parameter pack" bit.
// Copy captures.
- ASTContext &Context = Class->getASTContext();
+ const ASTContext &Context = Class->getASTContext();
Data.NumCaptures = NumCaptures;
Data.NumExplicitCaptures = 0;
Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
@@ -899,11 +980,12 @@ LambdaExpr::LambdaExpr(QualType T,
}
}
-LambdaExpr *LambdaExpr::Create(ASTContext &Context,
+LambdaExpr *LambdaExpr::Create(const ASTContext &Context,
CXXRecordDecl *Class,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -923,13 +1005,15 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
Size += sizeof(VarDecl *) * ArrayIndexVars.size();
}
void *Mem = Context.Allocate(Size);
- return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
- Captures, ExplicitParams, ExplicitResultType,
+ return new (Mem) LambdaExpr(T, IntroducerRange,
+ CaptureDefault, CaptureDefaultLoc, Captures,
+ ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
ClosingBrace, ContainsUnexpandedParameterPack);
}
-LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C,
+ unsigned NumCaptures,
unsigned NumArrayIndexVars) {
unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumArrayIndexVars)
@@ -984,13 +1068,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
CXXMethodDecl *LambdaExpr::getCallOperator() const {
CXXRecordDecl *Record = getLambdaClass();
- DeclarationName Name
- = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(!Calls.empty() && "Missing lambda call operator!");
- assert(Calls.size() == 1 && "More than one lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
- return Result;
+ return Record->getLambdaCallOperator();
+}
+
+TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getGenericLambdaTemplateParameterList();
+
}
CompoundStmt *LambdaExpr::getBody() const {
@@ -1017,7 +1101,7 @@ ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
getObjectsBuffer()[i] = objects[i];
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
ArrayRef<CleanupObject> objects) {
size_t size = sizeof(ExprWithCleanups)
+ objects.size() * sizeof(CleanupObject);
@@ -1030,7 +1114,8 @@ ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
ExprWithCleanupsBits.NumObjects = numObjects;
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C,
+ EmptyShell empty,
unsigned numObjects) {
size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
@@ -1063,7 +1148,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::Create(ASTContext &C,
+CXXUnresolvedConstructExpr::Create(const ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
ArrayRef<Expr*> Args,
@@ -1074,7 +1159,7 @@ CXXUnresolvedConstructExpr::Create(ASTContext &C,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
+CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) {
Stmt::EmptyShell Empty;
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
sizeof(Expr *) * NumArgs);
@@ -1085,7 +1170,7 @@ SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
return Type->getTypeLoc().getBeginLoc();
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1121,7 +1206,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
}
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1142,7 +1227,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
MemberNameInfo(MemberNameInfo) { }
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::Create(ASTContext &C,
+CXXDependentScopeMemberExpr::Create(const ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1171,7 +1256,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
}
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
+CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
if (!HasTemplateKWAndArgsInfo)
@@ -1222,7 +1307,7 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
return true;
}
-UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
+UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
@@ -1260,8 +1345,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const {
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::Create(ASTContext &C,
- bool HasUnresolvedUsing,
+UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1284,7 +1368,8 @@ UnresolvedMemberExpr::Create(ASTContext &C,
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
+UnresolvedMemberExpr::CreateEmpty(const ASTContext &C,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (HasTemplateKWAndArgsInfo)
@@ -1352,7 +1437,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
@@ -1361,7 +1446,8 @@ FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) {
+FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
+ unsigned NumParams) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * NumParams))
FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
@@ -1396,7 +1482,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
}
}
-TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
+TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
@@ -1407,7 +1493,7 @@ TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
}
-TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C,
+TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
unsigned NumArgs) {
unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs;
void *Mem = C.Allocate(Size);
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index bcb6d4e809bf..54f77efef0f9 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::OffsetOfExprClass:
case Expr::CXXThrowExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
@@ -286,13 +287,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
- return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx));
+ return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
// Extended vector element access is an lvalue unless there are duplicates
// in the shuffle expression.
case Expr::ExtVectorElementExprClass:
- return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ?
- Cl::CL_DuplicateVectorComponents : Cl::CL_LValue;
+ if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements())
+ return Cl::CL_DuplicateVectorComponents;
+ if (cast<ExtVectorElementExpr>(E)->isArrow())
+ return Cl::CL_LValue;
+ return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase());
// Simply look at the actual default argument.
case Expr::CXXDefaultArgExprClass:
@@ -353,6 +357,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXStdInitializerListExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
@@ -587,6 +592,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)
+ return Cl::CM_ConstQualified;
// Arrays are not modifiable, only their elements are.
if (CT->isArrayType())
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8c650290b579..390cfe9cd235 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -23,8 +23,8 @@
// where it is possible to determine the evaluated result regardless.
//
// * A set of notes indicating why the evaluation was not a constant expression
-// (under the C++11 rules only, at the moment), or, if folding failed too,
-// why the expression could not be folded.
+// (under the C++11 / C++1y rules only, at the moment), or, if folding failed
+// too, why the expression could not be folded.
//
// If we are checking for a potential constant expression, failure to constant
// fold a potential constant sub-expression will be indicated by a 'false'
@@ -63,7 +63,25 @@ namespace {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
return D->getType();
- return B.get<const Expr*>()->getType();
+
+ const Expr *Base = B.get<const Expr*>();
+
+ // For a materialized temporary, the type of the temporary we materialized
+ // may not be the type of the expression.
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Temp = MTE->GetTemporaryExpr();
+ const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
+ Adjustments);
+ // Keep any cv-qualifiers from the reference if we generated a temporary
+ // for it.
+ if (Inner != Temp)
+ return Inner->getType();
+ }
+
+ return Base->getType();
}
/// Get an LValue path entry, which is known to not be an array index, as a
@@ -284,7 +302,7 @@ namespace {
/// This - The binding for the this pointer in this call, if any.
const LValue *This;
- /// ParmBindings - Parameter bindings for this function call, indexed by
+ /// Arguments - Parameter bindings for this function call, indexed by
/// parameters' function scope indices.
APValue *Arguments;
@@ -299,6 +317,12 @@ namespace {
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
~CallStackFrame();
+
+ APValue *getTemporary(const void *Key) {
+ MapTy::iterator I = Temporaries.find(Key);
+ return I == Temporaries.end() ? 0 : &I->second;
+ }
+ APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
};
/// Temporarily override 'this'.
@@ -343,14 +367,37 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
+ // FIXME: Force the precision of the source value down so we don't
+ // print digits which are usually useless (we don't really care here if
+ // we truncate a digit by accident in edge cases). Ideally,
+ // APFloat::toString would automatically print the shortest
+ // representation which rounds to the correct value, but it's a bit
+ // tricky to implement.
+ unsigned precision =
+ llvm::APFloat::semanticsPrecision(F.getSemantics());
+ precision = (precision * 59 + 195) / 196;
SmallVector<char, 32> Buffer;
- F.toString(Buffer);
+ F.toString(Buffer, precision);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
return *this;
}
};
+ /// A cleanup, and a flag indicating whether it is lifetime-extended.
+ class Cleanup {
+ llvm::PointerIntPair<APValue*, 1, bool> Value;
+
+ public:
+ Cleanup(APValue *Val, bool IsLifetimeExtended)
+ : Value(Val, IsLifetimeExtended) {}
+
+ bool isLifetimeExtended() const { return Value.getInt(); }
+ void endLifetime() {
+ *Value.getPointer() = APValue();
+ }
+ };
+
/// EvalInfo - This is a private struct used by the evaluator to capture
/// information about a subexpression as it is folded. It retains information
/// about the AST context, but also maintains information about the folded
@@ -380,13 +427,22 @@ namespace {
/// NextCallIndex - The next call index to assign.
unsigned NextCallIndex;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
+
/// BottomFrame - The frame in which evaluation started. This must be
/// initialized after CurrentCall and CallStackDepth.
CallStackFrame BottomFrame;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
+
/// EvaluatingDecl - This is the declaration whose initializer is being
/// evaluated, if any.
- const VarDecl *EvaluatingDecl;
+ APValue::LValueBase EvaluatingDecl;
/// EvaluatingDeclValue - This is the value being constructed for the
/// declaration whose initializer is being evaluated, if any.
@@ -396,24 +452,52 @@ namespace {
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
- /// CheckingPotentialConstantExpression - Are we checking whether the
- /// expression is a potential constant expression? If so, some diagnostics
- /// are suppressed.
- bool CheckingPotentialConstantExpression;
-
- bool IntOverflowCheckMode;
+ enum EvaluationMode {
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression.
+ EM_ConstantExpression,
+
+ /// Evaluate as a potential constant expression. Keep going if we hit a
+ /// construct that we can't evaluate yet (because we don't yet know the
+ /// value of something) but stop if we hit something that could never be
+ /// a constant expression.
+ EM_PotentialConstantExpression,
+
+ /// Fold the expression to a constant. Stop if we hit a side-effect that
+ /// we can't model.
+ EM_ConstantFold,
+
+ /// Evaluate the expression looking for integer overflow and similar
+ /// issues. Don't worry about side-effects, and try to visit all
+ /// subexpressions.
+ EM_EvaluateForOverflow,
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
- bool OverflowCheckMode=false)
+ /// Evaluate in any way we know how. Don't worry about side-effects that
+ /// can't be modeled.
+ EM_IgnoreSideEffects
+ } EvalMode;
+
+ /// Are we checking whether the expression is a potential constant
+ /// expression?
+ bool checkingPotentialConstantExpression() const {
+ return EvalMode == EM_PotentialConstantExpression;
+ }
+
+ /// Are we checking an expression for overflow?
+ // FIXME: We should check for any kind of undefined or suspicious behavior
+ // in such constructs, not just overflow.
+ bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; }
+
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(getLangOpts().ConstexprStepLimit),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
- EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false),
- IntOverflowCheckMode(OverflowCheckMode) {}
+ EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0),
+ HasActiveDiagnostic(false), EvalMode(Mode) {}
- void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
- EvaluatingDecl = VD;
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
+ EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
}
@@ -422,7 +506,7 @@ namespace {
bool CheckCallLimit(SourceLocation Loc) {
// Don't perform any constexpr calls (other than the call we're checking)
// when checking a potential constant expression.
- if (CheckingPotentialConstantExpression && CallStackDepth > 1)
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
return false;
if (NextCallIndex == 0) {
// NextCallIndex has wrapped around.
@@ -446,6 +530,15 @@ namespace {
return (Frame->Index == CallIndex) ? Frame : 0;
}
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
+ return false;
+ }
+ --StepsLeft;
+ return true;
+ }
+
private:
/// Add a diagnostic to the diagnostics list.
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
@@ -462,22 +555,41 @@ namespace {
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important.
- // FIXME: We might want to show both diagnostics to the user.
if (EvalStatus.Diag) {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ case EM_EvaluateForOverflow:
+ if (!EvalStatus.HasSideEffects)
+ break;
+ // We've had side-effects; we want the diagnostic from them, not
+ // some later problem.
+ case EM_ConstantExpression:
+ case EM_PotentialConstantExpression:
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+ }
+
unsigned CallStackNotes = CallStackDepth - 1;
unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
if (Limit)
CallStackNotes = std::min(CallStackNotes, Limit + 1);
- if (CheckingPotentialConstantExpression)
+ if (checkingPotentialConstantExpression())
CallStackNotes = 0;
HasActiveDiagnostic = true;
EvalStatus.Diag->clear();
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
addDiag(Loc, DiagId);
- if (!CheckingPotentialConstantExpression)
+ if (!checkingPotentialConstantExpression())
addCallStack(Limit);
return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
}
@@ -494,15 +606,17 @@ namespace {
return OptionalDiagnostic();
}
- bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
-
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
+ ///
+ /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
+ /// EM_PotentialConstantExpression mode and we produce one of these.
template<typename LocArg>
OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // Don't override a previous diagnostic.
+ // Don't override a previous diagnostic. Don't bother collecting
+ // diagnostics if we're evaluating for overflow.
if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
HasActiveDiagnostic = false;
return OptionalDiagnostic();
@@ -525,30 +639,72 @@ namespace {
}
}
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() {
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ case EM_IgnoreSideEffects:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
+ }
+
/// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be folded?
+ /// construct which can't be reduced to a value?
bool keepEvaluatingAfterFailure() {
- // Should return true in IntOverflowCheckMode, so that we check for
- // overflow even if some subexpressions can't be evaluated as constants.
- return IntOverflowCheckMode ||
- (CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty());
+ if (!StepsLeft)
+ return false;
+
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
}
};
/// Object used to treat all foldable expressions as constant expressions.
struct FoldConstant {
+ EvalInfo &Info;
bool Enabled;
-
- explicit FoldConstant(EvalInfo &Info)
- : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects) {
- }
- // Treat the value we've computed since this object was created as constant.
- void Fold(EvalInfo &Info) {
- if (Enabled && !Info.EvalStatus.Diag->empty() &&
+ bool HadNoPriorDiags;
+ EvalInfo::EvaluationMode OldMode;
+
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info),
+ Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag &&
+ Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects),
+ OldMode(Info.EvalMode) {
+ if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression)
+ Info.EvalMode = EvalInfo::EM_ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects)
Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
}
};
@@ -563,11 +719,50 @@ namespace {
SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
+ // If we're speculatively evaluating, we may have skipped over some
+ // evaluations and missed out a side effect.
+ Info.EvalStatus.HasSideEffects = true;
}
~SpeculativeEvaluationRAII() {
Info.EvalStatus = Old;
}
};
+
+ /// RAII object wrapping a full-expression or block scope, and handling
+ /// the ending of the lifetime of temporaries created within it.
+ template<bool IsFullExpression>
+ class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
+ public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {}
+ ~ScopeRAII() {
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ cleanup(Info, OldStackSize);
+ }
+ private:
+ static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
+ unsigned NewEnd = OldStackSize;
+ for (unsigned I = OldStackSize, N = Info.CleanupStack.size();
+ I != N; ++I) {
+ if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) {
+ // Full-expression cleanup of a lifetime-extended temporary: nothing
+ // to do, just move this cleanup to the right place in the stack.
+ std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]);
+ ++NewEnd;
+ } else {
+ // End the lifetime of the object.
+ Info.CleanupStack[I].endLifetime();
+ }
+ }
+ Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd,
+ Info.CleanupStack.end());
+ }
+ };
+ typedef ScopeRAII<false> BlockScopeRAII;
+ typedef ScopeRAII<true> FullExpressionRAII;
}
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
@@ -610,32 +805,16 @@ CallStackFrame::~CallStackFrame() {
Info.CurrentCall = Caller;
}
-/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
- unsigned ArgIndex = 0;
- bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
- !isa<CXXConstructorDecl>(Frame->Callee) &&
- cast<CXXMethodDecl>(Frame->Callee)->isInstance();
-
- if (!IsMemberCall)
- Out << *Frame->Callee << '(';
-
- for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
- E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
- if (ArgIndex > (unsigned)IsMemberCall)
- Out << ", ";
-
- const ParmVarDecl *Param = *I;
- const APValue &Arg = Frame->Arguments[ArgIndex];
- Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
-
- if (ArgIndex == 0 && IsMemberCall)
- Out << "->" << *Frame->Callee << '(';
- }
-
- Out << ')';
+APValue &CallStackFrame::createTemporary(const void *Key,
+ bool IsLifetimeExtended) {
+ APValue &Result = Temporaries[Key];
+ assert(Result.isUninit() && "temporary created multiple times");
+ Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
+ return Result;
}
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out);
+
void EvalInfo::addCallStack(unsigned Limit) {
// Determine which calls to skip, if any.
unsigned ActiveCalls = CallStackDepth - 1;
@@ -884,19 +1063,11 @@ namespace {
return false;
return LHS.Path == RHS.Path;
}
-
- /// Kinds of constant expression checking, for diagnostics.
- enum CheckConstantExpressionKind {
- CCEK_Constant, ///< A normal constant.
- CCEK_ReturnValue, ///< A constexpr function return value.
- CCEK_MemberInit ///< A constexpr constructor mem-initializer.
- };
}
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E,
- CheckConstantExpressionKind CCEK = CCEK_Constant,
bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
@@ -908,23 +1079,66 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//
+/// Produce a string describing the given constexpr call.
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
+ unsigned ArgIndex = 0;
+ bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
+ !isa<CXXConstructorDecl>(Frame->Callee) &&
+ cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+
+ if (!IsMemberCall)
+ Out << *Frame->Callee << '(';
+
+ if (Frame->This && IsMemberCall) {
+ APValue Val;
+ Frame->This->moveInto(Val);
+ Val.printPretty(Out, Frame->Info.Ctx,
+ Frame->This->Designator.MostDerivedType);
+ // FIXME: Add parens around Val if needed.
+ Out << "->" << *Frame->Callee << '(';
+ IsMemberCall = false;
+ }
+
+ for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
+ E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ if (ArgIndex > (unsigned)IsMemberCall)
+ Out << ", ";
+
+ const ParmVarDecl *Param = *I;
+ const APValue &Arg = Frame->Arguments[ArgIndex];
+ Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
+
+ if (ArgIndex == 0 && IsMemberCall)
+ Out << "->" << *Frame->Callee << '(';
+ }
+
+ Out << ')';
+}
+
/// Evaluate an expression to see if it had side-effects, and discard its
/// result.
/// \return \c true if the caller should keep evaluating.
static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
APValue Scratch;
- if (!Evaluate(Scratch, Info, E)) {
- Info.EvalStatus.HasSideEffects = true;
- return Info.keepEvaluatingAfterFailure();
- }
+ if (!Evaluate(Scratch, Info, E))
+ // We don't need the value, but we might have skipped a side effect here.
+ return Info.noteSideEffect();
return true;
}
+/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
+/// return its existing value.
+static int64_t getExtValue(const APSInt &Value) {
+ return Value.isSigned() ? Value.getSExtValue()
+ : static_cast<int64_t>(Value.getZExtValue());
+}
+
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
unsigned Builtin = E->isBuiltinCall();
@@ -956,6 +1170,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
return CLE->isFileScope() && CLE->isLValue();
}
+ case Expr::MaterializeTemporaryExprClass:
+ // A materialized temporary might have been lifetime-extended to static
+ // storage duration.
+ return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static;
// A string literal has static storage duration.
case Expr::StringLiteralClass:
case Expr::PredefinedExprClass:
@@ -1020,7 +1238,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Don't allow references to temporaries to escape.
return false;
}
- assert((Info.CheckingPotentialConstantExpression ||
+ assert((Info.checkingPotentialConstantExpression() ||
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
@@ -1057,10 +1275,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
/// 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) {
+static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
+ const LValue *This = 0) {
if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
+ // C++1y: A constant initializer for an object o [...] may also invoke
+ // constexpr constructors for o and its subobjects even if those objects
+ // are of non-literal class types.
+ if (Info.getLangOpts().CPlusPlus1y && This &&
+ Info.EvaluatingDecl == This->getLValueBase())
+ return true;
+
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
@@ -1075,6 +1301,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
+ if (Value.isUninit()) {
+ Info.Diag(DiagLoc, diag::note_constexpr_uninitialized)
+ << true << Type;
+ return false;
+ }
+
// Core issue 1454: For a literal constant expression of array or class type,
// each subobject of its value shall have been initialized by a constant
// expression.
@@ -1129,7 +1361,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
+ if (Value.CallIndex)
+ return false;
+ const Expr *E = Value.Base.dyn_cast<const Expr*>();
+ return E && !isa<MaterializeTemporaryExpr>(E);
}
static bool IsWeakLValue(const LValue &Value) {
@@ -1252,6 +1487,27 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
return true;
}
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
+ APValue &Value, const FieldDecl *FD) {
+ assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
+
+ if (!Value.isInt()) {
+ // Trying to store a pointer-cast-to-integer into a bitfield.
+ // FIXME: In this case, we should provide the diagnostic for casting
+ // a pointer to an integer.
+ assert(Value.isLValue() && "integral value neither int nor lvalue?");
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt &Int = Value.getInt();
+ unsigned OldBitWidth = Int.getBitWidth();
+ unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx);
+ if (NewBitWidth < OldBitWidth)
+ Int = Int.trunc(NewBitWidth).extend(OldBitWidth);
+ return true;
+}
+
static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
llvm::APInt &Res) {
APValue SVal;
@@ -1299,6 +1555,155 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
return false;
}
+/// Perform the given integer operation, which is known to need at most BitWidth
+/// bits, and check for overflow in the original type (if that type was not an
+/// unsigned type).
+template<typename Operation>
+static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op) {
+ if (LHS.isUnsigned())
+ return Op(LHS, RHS);
+
+ APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
+ APSInt Result = Value.trunc(LHS.getBitWidth());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.checkingForOverflow())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
+ return Result;
+}
+
+/// Perform the given binary integer operation.
+static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
+ BinaryOperatorKind Opcode, APSInt RHS,
+ APSInt &Result) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>());
+ return true;
+ case BO_Add:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::plus<APSInt>());
+ return true;
+ case BO_Sub:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::minus<APSInt>());
+ return true;
+ case BO_And: Result = LHS & RHS; return true;
+ case BO_Xor: Result = LHS ^ RHS; return true;
+ case BO_Or: Result = LHS | RHS; return true;
+ case BO_Div:
+ case BO_Rem:
+ if (RHS == 0) {
+ Info.Diag(E, diag::note_expr_divide_by_zero);
+ return false;
+ }
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1.
+ if (RHS.isNegative() && RHS.isAllOnesValue() &&
+ LHS.isSigned() && LHS.isMinSignedValue())
+ HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return true;
+ case BO_Shl: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_right;
+ }
+ shift_left:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS) {
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ } else if (LHS.isSigned()) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ if (LHS.isNegative())
+ Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
+ else if (LHS.countLeadingZeros() < SA)
+ Info.CCEDiag(E, diag::note_constexpr_lshift_discards);
+ }
+ Result = LHS << SA;
+ return true;
+ }
+ case BO_Shr: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_left;
+ }
+ shift_right:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS)
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ Result = LHS >> SA;
+ return true;
+ }
+
+ case BO_LT: Result = LHS < RHS; return true;
+ case BO_GT: Result = LHS > RHS; return true;
+ case BO_LE: Result = LHS <= RHS; return true;
+ case BO_GE: Result = LHS >= RHS; return true;
+ case BO_EQ: Result = LHS == RHS; return true;
+ case BO_NE: Result = LHS != RHS; return true;
+ }
+}
+
+/// Perform the given binary floating-point operation, in-place, on LHS.
+static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
+ APFloat &LHS, BinaryOperatorKind Opcode,
+ const APFloat &RHS) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Add:
+ LHS.add(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Sub:
+ LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Div:
+ LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ }
+
+ if (LHS.isInfinity() || LHS.isNaN())
+ Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+ return true;
+}
+
/// Cast an lvalue referring to a base subobject to a derived class, by
/// truncating the lvalue's path to the given length.
static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -1369,6 +1774,19 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return true;
}
+static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
+ QualType Type, LValue &Result) {
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
+ return false;
+ Type = (*PathI)->getType();
+ }
+ return true;
+}
+
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
@@ -1470,7 +1888,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
// Assume arguments of a potential constant expression are unknown
// constant expressions.
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
return false;
if (!Frame || !Frame->Arguments) {
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
@@ -1482,11 +1900,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// If this is a local variable, dig out its value.
if (Frame) {
- Result = &Frame->Temporaries[VD];
- // If we've carried on past an unevaluatable local variable initializer,
- // we can't go any further. This can happen during potential constant
- // expression checking.
- return !Result->isUninit();
+ Result = Frame->getTemporary(VD);
+ assert(Result && "missing value for local variable");
+ return true;
}
// Dig out the initializer, and use the declaration which it's attached to.
@@ -1494,16 +1910,16 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (!Init || Init->isValueDependent()) {
// If we're checking a potential constant expression, the variable could be
// initialized later.
- if (!Info.CheckingPotentialConstantExpression)
+ if (!Info.checkingPotentialConstantExpression())
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
// If we're currently evaluating the initializer of this declaration, use that
// in-flight value.
- if (Info.EvaluatingDecl == VD) {
+ if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) {
Result = Info.EvaluatingDeclValue;
- return !Result->isUninit();
+ return true;
}
// Never evaluate the initializer of a weak variable. We can't be sure that
@@ -1615,7 +2031,7 @@ static void expandArray(APValue &Array, unsigned Index) {
Array.swap(NewValue);
}
-/// Kinds of access we can perform on an object.
+/// Kinds of access we can perform on an object, for diagnostics.
enum AccessKinds {
AK_Read,
AK_Assign,
@@ -1637,7 +2053,7 @@ struct CompleteObject {
assert(Value && "missing value for complete object");
}
- operator bool() const { return Value; }
+ LLVM_EXPLICIT operator bool() const { return Value; }
};
/// Find the designated sub-object of an rvalue.
@@ -1656,16 +2072,33 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
Info.Diag(E);
return handler.failed();
}
- if (Sub.Entries.empty())
- return handler.found(*Obj.Value, Obj.Type);
- if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit())
- // This object might be initialized later.
- return handler.failed();
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
+ const FieldDecl *LastField = 0;
+
// Walk the designator's path to find the subobject.
- for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
+ if (O->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
+ return handler.failed();
+ }
+
+ if (I == N) {
+ if (!handler.found(*O, ObjType))
+ return false;
+
+ // If we modified a bit-field, truncate it to the right width.
+ if (handler.AccessKind != AK_Read &&
+ LastField && LastField->isBitField() &&
+ !truncateBitfieldValue(Info, E, *O, LastField))
+ return false;
+
+ return true;
+ }
+
+ LastField = 0;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
@@ -1767,6 +2200,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
return handler.failed();
}
+
+ LastField = Field;
} else {
// Next subobject is a base class.
const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
@@ -1778,15 +2213,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (WasConstQualified)
ObjType.addConst();
}
-
- if (O->isUninit()) {
- if (!Info.CheckingPotentialConstantExpression)
- Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
- return handler.failed();
- }
}
-
- return handler.found(*O, ObjType);
}
namespace {
@@ -1963,9 +2390,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
- } else if (AK != AK_Read) {
- Info.Diag(E, diag::note_constexpr_modify_global);
- return CompleteObject();
}
// C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
@@ -1983,7 +2407,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Compute value storage location and type of base object.
APValue *BaseVal = 0;
- QualType BaseType;
+ QualType BaseType = getType(LVal.Base);
if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
@@ -2004,7 +2428,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
// Accesses of volatile-qualified objects are not allowed.
- BaseType = VD->getType();
if (BaseType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
@@ -2019,8 +2442,16 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
- assert(AK == AK_Read && "can't modify non-local");
- if (VD->isConstexpr()) {
+ if (Info.getLangOpts().CPlusPlus1y &&
+ VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
+ // OK, we can read and modify an object if we're in the process of
+ // evaluating its initializer, because its lifetime began in this
+ // evaluation.
+ } else if (AK != AK_Read) {
+ // All the remaining cases only permit reading.
+ Info.Diag(E, diag::note_constexpr_modify_global);
+ return CompleteObject();
+ } else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (BaseType->isIntegralOrEnumerationType()) {
if (!BaseType.isConstQualified()) {
@@ -2060,12 +2491,45 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
- Info.Diag(E);
- return CompleteObject();
- }
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ assert(MTE->getStorageDuration() == SD_Static &&
+ "should have a frame for a non-global materialized temporary");
+
+ // Per C++1y [expr.const]p2:
+ // an lvalue-to-rvalue conversion [is not allowed unless it applies to]
+ // - a [...] glvalue of integral or enumeration type that refers to
+ // a non-volatile const object [...]
+ // [...]
+ // - a [...] glvalue of literal type that refers to a non-volatile
+ // object whose lifetime began within the evaluation of e.
+ //
+ // C++11 misses the 'began within the evaluation of e' check and
+ // instead allows all temporaries, including things like:
+ // int &&r = 1;
+ // int x = ++r;
+ // constexpr int k = r;
+ // Therefore we use the C++1y rules in C++11 too.
+ const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
+ const ValueDecl *ED = MTE->getExtendingDecl();
+ if (!(BaseType.isConstQualified() &&
+ BaseType->isIntegralOrEnumerationType()) &&
+ !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
+ return CompleteObject();
+ }
- BaseType = Base->getType();
- BaseVal = &Frame->Temporaries[Base];
+ BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(BaseVal && "got reference to unevaluated temporary");
+ } else {
+ Info.Diag(E);
+ return CompleteObject();
+ }
+ } else {
+ BaseVal = Frame->getTemporary(Base);
+ assert(BaseVal && "missing value for temporary");
+ }
// Volatile temporary objects cannot be accessed in constant expressions.
if (BaseType.isVolatileQualified()) {
@@ -2080,10 +2544,22 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
}
- // In C++1y, we can't safely access any mutable state when checking a
- // potential constant expression.
+ // 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
+ // object under construction.
+ if (LVal.getLValueBase() == Info.EvaluatingDecl) {
+ BaseType = Info.Ctx.getCanonicalType(BaseType);
+ BaseType.removeLocalConst();
+ }
+
+ // In C++1y, we can't safely access any mutable state when we might be
+ // evaluating after an unmodeled side effect or an evaluation failure.
+ //
+ // FIXME: Not all local state is mutable. Allow local constant subobjects
+ // to be read here (but take care with 'mutable' fields).
if (Frame && Info.getLangOpts().CPlusPlus1y &&
- Info.CheckingPotentialConstantExpression)
+ (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
return CompleteObject();
return CompleteObject(BaseVal, BaseType);
@@ -2159,6 +2635,124 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
}
namespace {
+struct CompoundAssignSubobjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ QualType PromotedLHSType;
+ BinaryOperatorKind Opcode;
+ const APValue &RHS;
+
+ static const AccessKinds AccessKind = AK_Assign;
+
+ typedef bool result_type;
+
+ bool checkConst(QualType QT) {
+ // Assigning to a const object has undefined behavior.
+ if (QT.isConstQualified()) {
+ Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ return false;
+ }
+ return true;
+ }
+
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ switch (Subobj.getKind()) {
+ case APValue::Int:
+ return found(Subobj.getInt(), SubobjType);
+ case APValue::Float:
+ return found(Subobj.getFloat(), SubobjType);
+ case APValue::ComplexInt:
+ case APValue::ComplexFloat:
+ // FIXME: Implement complex compound assignment.
+ Info.Diag(E);
+ return false;
+ case APValue::LValue:
+ return foundPointer(Subobj, SubobjType);
+ default:
+ // FIXME: can this happen?
+ Info.Diag(E);
+ return false;
+ }
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ if (!SubobjType->isIntegerType() || !RHS.isInt()) {
+ // We don't support compound assignment on integer-cast-to-pointer
+ // values.
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt LHS = HandleIntToIntCast(Info, E, PromotedLHSType,
+ SubobjType, Value);
+ if (!handleIntIntBinOp(Info, E, LHS, Opcode, RHS.getInt(), LHS))
+ return false;
+ Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
+ return true;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ return checkConst(SubobjType) &&
+ HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType,
+ Value) &&
+ handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) &&
+ HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value);
+ }
+ bool foundPointer(APValue &Subobj, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ QualType PointeeType;
+ if (const PointerType *PT = SubobjType->getAs<PointerType>())
+ PointeeType = PT->getPointeeType();
+
+ if (PointeeType.isNull() || !RHS.isInt() ||
+ (Opcode != BO_Add && Opcode != BO_Sub)) {
+ Info.Diag(E);
+ return false;
+ }
+
+ int64_t Offset = getExtValue(RHS.getInt());
+ if (Opcode == BO_Sub)
+ Offset = -Offset;
+
+ LValue LVal;
+ LVal.setFrom(Info.Ctx, Subobj);
+ if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset))
+ return false;
+ LVal.moveInto(Subobj);
+ return true;
+ }
+ bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
+ llvm_unreachable("shouldn't encounter string elements here");
+ }
+};
+} // end anonymous namespace
+
+const AccessKinds CompoundAssignSubobjectHandler::AccessKind;
+
+/// Perform a compound assignment of LVal <op>= RVal.
+static bool handleCompoundAssignment(
+ EvalInfo &Info, const Expr *E,
+ const LValue &LVal, QualType LValType, QualType PromotedLValType,
+ BinaryOperatorKind Opcode, const APValue &RVal) {
+ if (LVal.Designator.Invalid)
+ return false;
+
+ if (!Info.getLangOpts().CPlusPlus1y) {
+ Info.Diag(E);
+ return false;
+ }
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
+ CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
+ RVal };
+ return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
+}
+
+namespace {
struct IncDecSubobjectHandler {
EvalInfo &Info;
const Expr *E;
@@ -2326,54 +2920,53 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// lvalue referring to the result.
///
/// \param Info - Information about the ongoing evaluation.
-/// \param BO - The member pointer access operation.
-/// \param LV - Filled in with a reference to the resulting object.
+/// \param LV - An lvalue referring to the base of the member pointer.
+/// \param RHS - The member pointer expression.
/// \param IncludeMember - Specifies whether the member itself is included in
/// the resulting LValue subobject designator. This is not possible when
/// creating a bound member function.
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- const BinaryOperator *BO,
+ QualType LVType,
LValue &LV,
+ const Expr *RHS,
bool IncludeMember = true) {
- assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
-
- bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV);
- if (!EvalObjOK && !Info.keepEvaluatingAfterFailure())
- return 0;
-
MemberPtr MemPtr;
- if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info))
+ if (!EvaluateMemberPointer(RHS, MemPtr, Info))
return 0;
// C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
// member value, the behavior is undefined.
- if (!MemPtr.getDecl())
- return 0;
-
- if (!EvalObjOK)
+ if (!MemPtr.getDecl()) {
+ // FIXME: Specific diagnostic.
+ Info.Diag(RHS);
return 0;
+ }
if (MemPtr.isDerivedMember()) {
// This is a member of some derived class. Truncate LV appropriately.
// The end of the derived-to-base path for the base object must match the
// derived-to-base path for the member pointer.
if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
- LV.Designator.Entries.size())
+ LV.Designator.Entries.size()) {
+ Info.Diag(RHS);
return 0;
+ }
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *LVDecl = getAsBaseClass(
LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
- if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl())
+ if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
+ Info.Diag(RHS);
return 0;
+ }
}
// Truncate the lvalue to the appropriate derived class.
- if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+ if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(),
PathLengthToMember))
return 0;
} else if (!MemPtr.Path.empty()) {
@@ -2382,7 +2975,6 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
MemPtr.Path.size() + IncludeMember);
// Walk down to the appropriate base class.
- QualType LVType = BO->getLHS()->getType();
if (const PointerType *PT = LVType->getAs<PointerType>())
LVType = PT->getPointeeType();
const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl();
@@ -2390,23 +2982,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// The first class in the path is that of the lvalue.
for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
- if (!HandleLValueDirectBase(Info, BO, LV, RD, Base))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base))
return 0;
RD = Base;
}
// Finally cast to the class containing the member.
- if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord()))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD,
+ MemPtr.getContainingRecord()))
return 0;
}
// Add the member. Note that we cannot build bound member functions here.
if (IncludeMember) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueMember(Info, BO, LV, FD))
+ if (!HandleLValueMember(Info, RHS, LV, FD))
return 0;
} else if (const IndirectFieldDecl *IFD =
dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueIndirectMember(Info, BO, LV, IFD))
+ if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return 0;
} else {
llvm_unreachable("can't construct reference to bound member function");
@@ -2416,6 +3009,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
return MemPtr.getDecl();
}
+static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
+ const BinaryOperator *BO,
+ LValue &LV,
+ bool IncludeMember = true) {
+ assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
+
+ if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) {
+ if (Info.keepEvaluatingAfterFailure()) {
+ MemberPtr MemPtr;
+ EvaluateMemberPointer(BO->getRHS(), MemPtr, Info);
+ }
+ return 0;
+ }
+
+ return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV,
+ BO->getRHS(), IncludeMember);
+}
+
/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
/// the provided lvalue, which currently refers to the base object.
static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
@@ -2465,7 +3076,9 @@ enum EvalStmtResult {
/// Hit a 'continue' statement.
ESR_Continue,
/// Hit a 'break' statement.
- ESR_Break
+ ESR_Break,
+ /// Still scanning for 'case' or 'default' statement.
+ ESR_CaseNotFound
};
}
@@ -2477,7 +3090,14 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
LValue Result;
Result.set(VD, Info.CurrentCall->Index);
- APValue &Val = Info.CurrentCall->Temporaries[VD];
+ APValue &Val = Info.CurrentCall->createTemporary(VD, true);
+
+ if (!VD->getInit()) {
+ Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
+ << false << VD->getType();
+ Val = APValue();
+ return false;
+ }
if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
// Wipe out any partially-computed value, to allow tracking that this
@@ -2493,18 +3113,21 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
/// Evaluate a condition (either a variable declaration or an expression).
static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
const Expr *Cond, bool &Result) {
+ FullExpressionRAII Scope(Info);
if (CondDecl && !EvaluateDecl(Info, CondDecl))
return false;
return EvaluateAsBooleanCondition(Cond, Result, Info);
}
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S);
+ const Stmt *S, const SwitchCase *SC = 0);
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
- const Stmt *Body) {
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {
+ const Stmt *Body,
+ const SwitchCase *Case = 0) {
+ BlockScopeRAII Scope(Info);
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -2512,21 +3135,149 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
return ESR_Continue;
case ESR_Failed:
case ESR_Returned:
+ case ESR_CaseNotFound:
+ return ESR;
+ }
+ llvm_unreachable("Invalid EvalStmtResult!");
+}
+
+/// Evaluate a switch statement.
+static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
+ const SwitchStmt *SS) {
+ BlockScopeRAII Scope(Info);
+
+ // Evaluate the switch condition.
+ APSInt Value;
+ {
+ FullExpressionRAII Scope(Info);
+ if (SS->getConditionVariable() &&
+ !EvaluateDecl(Info, SS->getConditionVariable()))
+ return ESR_Failed;
+ if (!EvaluateInteger(SS->getCond(), Value, Info))
+ return ESR_Failed;
+ }
+
+ // Find the switch case corresponding to the value of the condition.
+ // FIXME: Cache this lookup.
+ const SwitchCase *Found = 0;
+ for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ if (isa<DefaultStmt>(SC)) {
+ Found = SC;
+ continue;
+ }
+
+ const CaseStmt *CS = cast<CaseStmt>(SC);
+ APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
+ APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
+ : LHS;
+ if (LHS <= Value && Value <= RHS) {
+ Found = SC;
+ break;
+ }
+ }
+
+ if (!Found)
+ return ESR_Succeeded;
+
+ // Search the switch body for the switch case and evaluate it from there.
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ case ESR_Break:
+ return ESR_Succeeded;
+ case ESR_Succeeded:
+ case ESR_Continue:
+ case ESR_Failed:
+ case ESR_Returned:
return ESR;
+ case ESR_CaseNotFound:
+ // This can only happen if the switch case is nested within a statement
+ // expression. We have no intention of supporting that.
+ Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
+ return ESR_Failed;
}
llvm_unreachable("Invalid EvalStmtResult!");
}
// Evaluate a statement.
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S) {
- // FIXME: Mark all temporaries in the current frame as destroyed at
- // the end of each full-expression.
+ const Stmt *S, const SwitchCase *Case) {
+ if (!Info.nextStep(S))
+ return ESR_Failed;
+
+ // If we're hunting down a 'case' or 'default' label, recurse through
+ // substatements until we hit the label.
+ if (Case) {
+ // FIXME: We don't start the lifetime of objects whose initialization we
+ // jump over. However, such objects must be of class type with a trivial
+ // default constructor that initialize all subobjects, so must be empty,
+ // so this almost never matters.
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ // FIXME: Precompute which substatement of a compound statement we
+ // would jump to, and go straight there rather than performing a
+ // linear scan each time.
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::DoStmtClass:
+ break;
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ if (Case == S)
+ Case = 0;
+ break;
+
+ case Stmt::IfStmtClass: {
+ // FIXME: Precompute which side of an 'if' we would jump to, and go
+ // straight there rather than scanning both sides.
+ const IfStmt *IS = cast<IfStmt>(S);
+
+ // Wrap the evaluation in a block scope, in case it's a DeclStmt
+ // preceded by our switch label.
+ BlockScopeRAII Scope(Info);
+
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
+ if (ESR != ESR_CaseNotFound || !IS->getElse())
+ return ESR;
+ return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ }
+
+ case Stmt::WhileStmtClass: {
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ break;
+ }
+
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(S);
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
+ break;
+ }
+
+ case Stmt::DeclStmtClass:
+ // FIXME: If the variable has initialization that can't be jumped over,
+ // bail out of any immediately-surrounding compound-statement too.
+ default:
+ return ESR_CaseNotFound;
+ }
+ }
+
switch (S->getStmtClass()) {
default:
if (const Expr *E = dyn_cast<Expr>(S)) {
// Don't bother evaluating beyond an expression-statement which couldn't
// be evaluated.
+ FullExpressionRAII Scope(Info);
if (!EvaluateIgnoredValue(Info, E))
return ESR_Failed;
return ESR_Succeeded;
@@ -2541,34 +3292,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
- DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt)
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ // Each declaration initialization is its own full-expression.
+ // FIXME: This isn't quite right; if we're performing aggregate
+ // initialization, each braced subexpression is its own full-expression.
+ FullExpressionRAII Scope(Info);
if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
return ESR_Failed;
+ }
return ESR_Succeeded;
}
case Stmt::ReturnStmtClass: {
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+ FullExpressionRAII Scope(Info);
if (RetExpr && !Evaluate(Result, Info, RetExpr))
return ESR_Failed;
return ESR_Returned;
}
case Stmt::CompoundStmtClass: {
+ BlockScopeRAII Scope(Info);
+
const CompoundStmt *CS = cast<CompoundStmt>(S);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end(); BI != BE; ++BI) {
- EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
- if (ESR != ESR_Succeeded)
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
+ if (ESR == ESR_Succeeded)
+ Case = 0;
+ else if (ESR != ESR_CaseNotFound)
return ESR;
}
- return ESR_Succeeded;
+ return Case ? ESR_CaseNotFound : ESR_Succeeded;
}
case Stmt::IfStmtClass: {
const IfStmt *IS = cast<IfStmt>(S);
// Evaluate the condition, as either a var decl or as an expression.
+ BlockScopeRAII Scope(Info);
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
return ESR_Failed;
@@ -2584,6 +3346,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::WhileStmtClass: {
const WhileStmt *WS = cast<WhileStmt>(S);
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue;
if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(),
Continue))
@@ -2602,10 +3365,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const DoStmt *DS = cast<DoStmt>(S);
bool Continue;
do {
- EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
+ Case = 0;
+ FullExpressionRAII CondScope(Info);
if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
return ESR_Failed;
} while (Continue);
@@ -2614,12 +3379,14 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
if (ESR != ESR_Succeeded)
return ESR;
}
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue = true;
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
@@ -2631,14 +3398,18 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
if (ESR != ESR_Continue)
return ESR;
- if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))
- return ESR_Failed;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
}
return ESR_Succeeded;
}
case Stmt::CXXForRangeStmtClass: {
const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S);
+ BlockScopeRAII Scope(Info);
// Initialize the __range variable.
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
@@ -2652,13 +3423,17 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
while (true) {
// Condition: __begin != __end.
- bool Continue = true;
- if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
- return ESR_Failed;
- if (!Continue)
- break;
+ {
+ bool Continue = true;
+ FullExpressionRAII CondExpr(Info);
+ if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
+ return ESR_Failed;
+ if (!Continue)
+ break;
+ }
// User's variable declaration, initialized by *__begin.
+ BlockScopeRAII InnerScope(Info);
ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
if (ESR != ESR_Succeeded)
return ESR;
@@ -2676,11 +3451,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
return ESR_Succeeded;
}
+ case Stmt::SwitchStmtClass:
+ return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
+
case Stmt::ContinueStmtClass:
return ESR_Continue;
case Stmt::BreakStmtClass:
return ESR_Break;
+
+ case Stmt::LabelStmtClass:
+ return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case);
+
+ case Stmt::AttributedStmtClass:
+ // As a general principle, C++11 attributes can be ignored without
+ // any semantic impact.
+ return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(),
+ Case);
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);
}
}
@@ -2718,10 +3509,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Definition) {
// Potential constant expressions can contain calls to declared, but not yet
// defined, constexpr functions.
- if (Info.CheckingPotentialConstantExpression && !Definition &&
+ if (Info.checkingPotentialConstantExpression() && !Definition &&
Declaration->isConstexpr())
return false;
+ // Bail out with no diagnostic if the function declaration itself is invalid.
+ // We will have produced a relevant diagnostic while parsing it.
+ if (Declaration->isInvalidDecl())
+ return false;
+
// Can we evaluate this function call?
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
@@ -2774,6 +3570,27 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
return false;
CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
+
+ // For a trivial copy or move assignment, perform an APValue copy. This is
+ // essential for unions, where the operations performed by the assignment
+ // operator cannot be represented as statements.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
+ if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ assert(This &&
+ (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
+ LValue RHS;
+ RHS.setFrom(Info.Ctx, ArgValues[0]);
+ APValue RHSValue;
+ if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
+ RHS, RHSValue))
+ return false;
+ if (!handleAssignment(Info, Args[0], *This, MD->getThisType(Info.Ctx),
+ RHSValue))
+ return false;
+ This->moveInto(Result);
+ return true;
+ }
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
if (ESR == ESR_Succeeded) {
if (Callee->getResultType()->isVoidType())
@@ -2806,8 +3623,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
// If it's a delegating constructor, just delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
- if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
- return false;
+ {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ return false;
+ }
return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
}
@@ -2831,6 +3651,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+ // A scope for temporaries lifetime-extended by reference members.
+ BlockScopeRAII LifetimeExtendedScope(Info);
+
bool Success = true;
unsigned BasesSeen = 0;
#ifndef NDEBUG
@@ -2842,6 +3665,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
APValue *Value = &Result;
// Determine the subobject to initialize.
+ FieldDecl *FD = 0;
if ((*I)->isBaseInitializer()) {
QualType BaseType((*I)->getBaseClass(), 0);
#ifndef NDEBUG
@@ -2856,7 +3680,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
- } else if (FieldDecl *FD = (*I)->getMember()) {
+ } else if ((FD = (*I)->getMember())) {
if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout))
return false;
if (RD->isUnion()) {
@@ -2871,7 +3695,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
CE = IFD->chain_end();
C != CE; ++C) {
- FieldDecl *FD = cast<FieldDecl>(*C);
+ FD = cast<FieldDecl>(*C);
CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
// Switch the union field if it differs. This happens if we had
// preceding zero-initialization, and we're now initializing a union
@@ -2897,9 +3721,10 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
llvm_unreachable("unknown base initializer kind");
}
- if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(),
- (*I)->isBaseInitializer()
- ? CCEK_Constant : CCEK_MemberInit)) {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) ||
+ (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(),
+ *Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.keepEvaluatingAfterFailure())
@@ -2934,7 +3759,7 @@ private:
// expression, then the conditional operator is not either.
template<typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
- assert(Info.CheckingPotentialConstantExpression);
+ assert(Info.checkingPotentialConstantExpression());
// Speculatively evaluate both arms.
{
@@ -2959,7 +3784,7 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
CheckPotentialConstantConditional(E);
return false;
}
@@ -3008,15 +3833,19 @@ public:
RetTy VisitUnaryPlus(const UnaryOperator *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
RetTy VisitChooseExpr(const ChooseExpr *E)
- { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
- RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E)
- { return StmtVisitorTy::Visit(E->getExpr()); }
+ RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+ // The initializer may not have been parsed yet, or might be erroneous.
+ if (!E->getExpr())
+ return Error(E);
+ return StmtVisitorTy::Visit(E->getExpr());
+ }
// We cannot create any objects for which cleanups are required, so there is
// nothing to do here; all cleanups must come from unevaluated subexpressions.
RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
@@ -3056,7 +3885,7 @@ public:
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
- if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()],
+ if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
Info, E->getCommon()))
return false;
@@ -3076,33 +3905,30 @@ public:
// Always assume __builtin_constant_p(...) ? ... : ... is a potential
// constant expression; we can't check whether it's potentially foldable.
- if (Info.CheckingPotentialConstantExpression && IsBcpCall)
+ if (Info.checkingPotentialConstantExpression() && IsBcpCall)
return false;
- FoldConstant Fold(Info);
-
- if (!HandleConditionalOperator(E))
+ FoldConstant Fold(Info, IsBcpCall);
+ if (!HandleConditionalOperator(E)) {
+ Fold.keepDiagnostics();
return false;
-
- if (IsBcpCall)
- Fold.Fold(Info);
+ }
return true;
}
RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- APValue &Value = Info.CurrentCall->Temporaries[E];
- if (Value.isUninit()) {
- const Expr *Source = E->getSourceExpr();
- if (!Source)
- return Error(E);
- if (Source == E) { // sanity checking.
- assert(0 && "OpaqueValueExpr recursively refers to itself");
- return Error(E);
- }
- return StmtVisitorTy::Visit(Source);
+ if (APValue *Value = Info.CurrentCall->getTemporary(E))
+ return DerivedSuccess(*Value, E);
+
+ const Expr *Source = E->getSourceExpr();
+ if (!Source)
+ return Error(E);
+ if (Source == E) { // sanity checking.
+ assert(0 && "OpaqueValueExpr recursively refers to itself");
+ return Error(E);
}
- return DerivedSuccess(Value, E);
+ return StmtVisitorTy::Visit(Source);
}
RetTy VisitCallExpr(const CallExpr *E) {
@@ -3240,8 +4066,13 @@ public:
default:
break;
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ APValue AtomicVal;
+ if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info))
+ return false;
+ return DerivedSuccess(AtomicVal, E);
+ }
+
case CK_NoOp:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -3282,6 +4113,41 @@ public:
return DerivedSuccess(RVal, UO);
}
+ RetTy VisitStmtExpr(const StmtExpr *E) {
+ // We will have checked the full-expressions inside the statement expression
+ // when they were completed, and don't need to check them again now.
+ if (Info.checkingForOverflow())
+ return Error(E);
+
+ BlockScopeRAII Scope(Info);
+ const CompoundStmt *CS = E->getSubStmt();
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end();
+ /**/; ++BI) {
+ if (BI + 1 == BE) {
+ const Expr *FinalExpr = dyn_cast<Expr>(*BI);
+ if (!FinalExpr) {
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ return this->Visit(FinalExpr);
+ }
+
+ APValue ReturnValue;
+ EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI);
+ if (ESR != ESR_Succeeded) {
+ // FIXME: If the statement-expression terminated due to 'return',
+ // 'break', or 'continue', it would be nice to propagate that to
+ // the outer statement evaluation rather than bailing out.
+ if (ESR != ESR_Failed)
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ }
+ }
+
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
@@ -3374,24 +4240,14 @@ public:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!this->Visit(E->getSubExpr()))
return false;
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type = E->getSubExpr()->getType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(this->Info, E, E->getSubExpr()->getType(),
+ Result);
}
}
};
@@ -3420,8 +4276,12 @@ public:
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
// - Locals and temporaries
+// * MaterializeTemporaryExpr
// * Any Expr, with a CallIndex indicating the function in which the temporary
-// was evaluated.
+// was evaluated, for cases where the MaterializeTemporaryExpr is missing
+// from the AST (FIXME).
+// * A MaterializeTemporaryExpr that has static storage duration, with no
+// CallIndex, for a lifetime-extended temporary.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
@@ -3511,17 +4371,78 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
APValue *V;
if (!evaluateVarDeclInit(Info, E, VD, Frame, V))
return false;
+ if (V->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_use_uninit_reference);
+ return false;
+ }
return Success(*V, E);
}
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- if (E->getType()->isRecordType())
- return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
+ // Walk through the expression to find the materialized temporary itself.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Inner = E->GetTemporaryExpr()->
+ skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+
+ // If we passed any comma operators, evaluate their LHSs.
+ for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
+ if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
+ return false;
+
+ // A materialized temporary with static storage duration can appear within the
+ // result of a constant expression evaluation, so we need to preserve its
+ // value for use outside this evaluation.
+ APValue *Value;
+ if (E->getStorageDuration() == SD_Static) {
+ Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ *Value = APValue();
+ Result.set(E);
+ } else {
+ Value = &Info.CurrentCall->
+ createTemporary(E, E->getStorageDuration() == SD_Automatic);
+ Result.set(E, Info.CurrentCall->Index);
+ }
- Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info,
- Result, E->GetTemporaryExpr());
+ QualType Type = Inner->getType();
+
+ // Materialize the temporary itself.
+ if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
+ (E->getStorageDuration() == SD_Static &&
+ !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ *Value = APValue();
+ return false;
+ }
+
+ // Adjust our lvalue to refer to the desired subobject.
+ for (unsigned I = Adjustments.size(); I != 0; /**/) {
+ --I;
+ switch (Adjustments[I].Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ if (!HandleLValueBasePath(Info, Adjustments[I].DerivedToBase.BasePath,
+ Type, Result))
+ return false;
+ Type = Adjustments[I].DerivedToBase.BasePath->getType();
+ break;
+
+ case SubobjectAdjustment::FieldAdjustment:
+ if (!HandleLValueMember(Info, E, Result, Adjustments[I].Field))
+ return false;
+ Type = Adjustments[I].Field->getType();
+ break;
+
+ case SubobjectAdjustment::MemberPointerAdjustment:
+ if (!HandleMemberPointerAccess(this->Info, Type, Result,
+ Adjustments[I].Ptr.RHS))
+ return false;
+ Type = Adjustments[I].Ptr.MPT->getPointeeType();
+ break;
+ }
+ }
+
+ return true;
}
bool
@@ -3576,11 +4497,9 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- int64_t IndexValue
- = Index.isSigned() ? Index.getSExtValue()
- : static_cast<int64_t>(Index.getZExtValue());
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
+ getExtValue(Index));
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -3634,14 +4553,10 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
if (!Evaluate(RHS, this->Info, CAO->getRHS()))
return false;
- // FIXME:
- //return handleCompoundAssignment(
- // this->Info, CAO,
- // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
- // RHS, CAO->getRHS()->getType(),
- // CAO->getOpForCompoundAssignment(CAO->getOpcode()),
- // CAO->getComputationResultType());
- return Error(CAO);
+ return handleCompoundAssignment(
+ this->Info, CAO,
+ Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
+ CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
@@ -3705,6 +4620,9 @@ public:
return Error(E);
}
bool VisitCXXThisExpr(const CXXThisExpr *E) {
+ // Can't look at 'this' when checking a potential constant expression.
+ if (Info.checkingPotentialConstantExpression())
+ return false;
if (!Info.CurrentCall->This)
return Error(E);
Result = *Info.CurrentCall->This;
@@ -3737,9 +4655,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
llvm::APSInt Offset;
if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
- int64_t AdditionalOffset
- = Offset.isSigned() ? Offset.getSExtValue()
- : static_cast<int64_t>(Offset.getZExtValue());
+
+ int64_t AdditionalOffset = getExtValue(Offset);
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
@@ -3779,7 +4696,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return false;
if (!Result.Base && Result.Offset.isZero())
@@ -3787,19 +4704,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type =
- E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
+ castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -3839,7 +4746,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
} else {
Result.set(SubExpr, Info.CurrentCall->Index);
- if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr],
+ if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false),
Info, Result, SubExpr))
return false;
}
@@ -3862,7 +4769,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ switch (E->isBuiltinCall()) {
+ case Builtin::BI__builtin_addressof:
+ return EvaluateLValue(E->getArg(0), Result, Info);
+
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ }
}
//===----------------------------------------------------------------------===//
@@ -3976,6 +4889,7 @@ namespace {
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
}
@@ -4091,10 +5005,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- // Cannot constant-evaluate std::initializer_list inits.
- if (E->initializesStdInitializerList())
- return false;
-
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -4156,8 +5066,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
isa<CXXDefaultInitExpr>(Init));
- if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info,
- Subobject, Init)) {
+ APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
+ if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
+ (Field->isBitField() && !truncateBitfieldValue(Info, Init,
+ FieldVal, *Field))) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@@ -4210,6 +5122,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
Result);
}
+bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *E) {
+ const ConstantArrayType *ArrayType =
+ Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+
+ LValue Array;
+ if (!EvaluateLValue(E->getSubExpr(), Array, Info))
+ return false;
+
+ // Get a pointer to the first element of the array.
+ Array.addArray(Info, E, ArrayType);
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end())
+ return Error(E);
+
+ // Start pointer.
+ if (!Field->getType()->isPointerType() ||
+ !Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType()))
+ return Error(E);
+
+ // FIXME: What if the initializer_list type has base classes, etc?
+ Result = APValue(APValue::UninitStruct(), 0, 2);
+ Array.moveInto(Result.getStructField(0));
+
+ if (++Field == Record->field_end())
+ return Error(E);
+
+ if (Field->getType()->isPointerType() &&
+ Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ // End pointer.
+ if (!HandleLValueArrayAdjustment(Info, E, Array,
+ ArrayType->getElementType(),
+ ArrayType->getSize().getZExtValue()))
+ return false;
+ Array.moveInto(Result.getStructField(1));
+ } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
+ // Length.
+ Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
+ else
+ return Error(E);
+
+ if (++Field != Record->field_end())
+ return Error(E);
+
+ return true;
+}
+
static bool EvaluateRecord(const Expr *E, const LValue &This,
APValue &Result, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isRecordType() &&
@@ -4234,7 +5198,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E);
+ return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false),
+ Info, Result, E);
}
bool VisitCastExpr(const CastExpr *E) {
@@ -4393,7 +5358,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
while (CountElts < NumElements) {
// Handle nested vector initialization.
if (CountInits < NumInits
- && E->getInit(CountInits)->getType()->isExtVectorType()) {
+ && E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -4951,7 +5916,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
} else if (ArgType->isPointerType() || Arg->isGLValue()) {
LValue LV;
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status);
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
: EvaluatePointer(Arg, LV, Info)) &&
!Status.HasSideEffects)
@@ -5045,9 +6010,37 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
+ // FIXME: BI__builtin_clrsb
+ // FIXME: BI__builtin_clrsbl
+ // FIXME: BI__builtin_clrsbll
+
+ case Builtin::BI__builtin_clz:
+ case Builtin::BI__builtin_clzl:
+ case Builtin::BI__builtin_clzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countLeadingZeros(), E);
+ }
+
case Builtin::BI__builtin_constant_p:
return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E);
+ case Builtin::BI__builtin_ctz:
+ case Builtin::BI__builtin_ctzl:
+ case Builtin::BI__builtin_ctzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countTrailingZeros(), E);
+ }
+
case Builtin::BI__builtin_eh_return_data_regno: {
int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);
@@ -5057,6 +6050,81 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_expect:
return Visit(E->getArg(0));
+ case Builtin::BI__builtin_ffs:
+ case Builtin::BI__builtin_ffsl:
+ case Builtin::BI__builtin_ffsll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ unsigned N = Val.countTrailingZeros();
+ return Success(N == Val.getBitWidth() ? 0 : N + 1, E);
+ }
+
+ case Builtin::BI__builtin_fpclassify: {
+ APFloat Val(0.0);
+ if (!EvaluateFloat(E->getArg(5), Val, Info))
+ return false;
+ unsigned Arg;
+ switch (Val.getCategory()) {
+ case APFloat::fcNaN: Arg = 0; break;
+ case APFloat::fcInfinity: Arg = 1; break;
+ case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
+ case APFloat::fcZero: Arg = 4; break;
+ }
+ return Visit(E->getArg(Arg));
+ }
+
+ case Builtin::BI__builtin_isinf_sign: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? (Val.isNegative() ? -1 : 1) : 0, E);
+ }
+
+ case Builtin::BI__builtin_isinf: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isfinite: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isFinite() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isnan: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isNaN() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isnormal: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isNormal() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_parity:
+ case Builtin::BI__builtin_parityl:
+ case Builtin::BI__builtin_parityll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.countPopulation() % 2, E);
+ }
+
+ case Builtin::BI__builtin_popcount:
+ case Builtin::BI__builtin_popcountl:
+ case Builtin::BI__builtin_popcountll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.countPopulation(), E);
+ }
+
case Builtin::BIstrlen:
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
@@ -5065,22 +6133,47 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
// Fall through.
- case Builtin::BI__builtin_strlen:
- // As an extension, we support strlen() and __builtin_strlen() as constant
- // expressions when the argument is a string literal.
- if (const StringLiteral *S
- = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
+ case Builtin::BI__builtin_strlen: {
+ // As an extension, we support __builtin_strlen() as a constant expression,
+ // and support folding strlen() to a constant.
+ LValue String;
+ if (!EvaluatePointer(E->getArg(0), String, Info))
+ return false;
+
+ // Fast path: if it's a string literal, search the string value.
+ if (const StringLiteral *S = dyn_cast_or_null<StringLiteral>(
+ String.getLValueBase().dyn_cast<const Expr *>())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
- StringRef Str = S->getString();
- StringRef::size_type Pos = Str.find(0);
- if (Pos != StringRef::npos)
- Str = Str.substr(0, Pos);
-
- return Success(Str.size(), E);
+ StringRef Str = S->getBytes();
+ int64_t Off = String.Offset.getQuantity();
+ if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() &&
+ S->getCharByteWidth() == 1) {
+ Str = Str.substr(Off);
+
+ StringRef::size_type Pos = Str.find(0);
+ if (Pos != StringRef::npos)
+ Str = Str.substr(0, Pos);
+
+ return Success(Str.size(), E);
+ }
+
+ // Fall through to slow path to issue appropriate diagnostic.
}
-
- return Error(E);
+
+ // Slow path: scan the bytes of the string looking for the terminating 0.
+ QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+ for (uint64_t Strlen = 0; /**/; ++Strlen) {
+ APValue Char;
+ if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) ||
+ !Char.isInt())
+ return false;
+ if (!Char.getInt())
+ return Success(Strlen, E);
+ if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1))
+ return false;
+ }
+ }
case Builtin::BI__atomic_always_lock_free:
case Builtin::BI__atomic_is_lock_free:
@@ -5149,29 +6242,6 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
A.getLValueCallIndex() == B.getLValueCallIndex();
}
-/// Perform the given integer operation, which is known to need at most BitWidth
-/// bits, and check for overflow in the original type (if that type was not an
-/// unsigned type).
-template<typename Operation>
-static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &LHS, const APSInt &RHS,
- unsigned BitWidth, Operation Op) {
- if (LHS.isUnsigned())
- return Op(LHS, RHS);
-
- APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
- APSInt Result = Value.trunc(LHS.getBitWidth());
- if (Result.extend(BitWidth) != Value) {
- if (Info.getIntOverflowCheckMode())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_integer_constant_overflow)
- << Result.toString(10) << E->getType();
- else
- HandleOverflow(Info, E, Value, E->getType());
- }
- return Result;
-}
-
namespace {
/// \brief Data recursive integer evaluator of certain binary operators.
@@ -5296,36 +6366,39 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Comma) {
// Ignore LHS but note if we could not evaluate it.
if (LHSResult.Failed)
- Info.EvalStatus.HasSideEffects = true;
+ return Info.noteSideEffect();
return true;
}
-
+
if (E->isLogicalOp()) {
- bool lhsResult;
- if (HandleConversionToBool(LHSResult.Val, lhsResult)) {
+ bool LHSAsBool;
+ if (!LHSResult.Failed && HandleConversionToBool(LHSResult.Val, LHSAsBool)) {
// We were able to evaluate the LHS, see if we can get away with not
// evaluating the RHS: 0 && X -> 0, 1 || X -> 1
- if (lhsResult == (E->getOpcode() == BO_LOr)) {
- Success(lhsResult, E, LHSResult.Val);
+ if (LHSAsBool == (E->getOpcode() == BO_LOr)) {
+ Success(LHSAsBool, E, LHSResult.Val);
return false; // Ignore RHS
}
} else {
+ LHSResult.Failed = true;
+
// Since we weren't able to evaluate the left hand side, it
// must have had side effects.
- Info.EvalStatus.HasSideEffects = true;
-
+ if (!Info.noteSideEffect())
+ return false;
+
// We can't evaluate the LHS; however, sometimes the result
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
// Don't ignore RHS and suppress diagnostics from this arm.
SuppressRHSDiags = true;
}
-
+
return true;
}
-
+
assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
E->getRHS()->getType()->isIntegralOrEnumerationType());
-
+
if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure())
return false; // Ignore RHS;
@@ -5378,8 +6451,8 @@ bool DataRecursiveIntBinOpEvaluator::
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
Result = LHSVal;
- CharUnits AdditionalOffset = CharUnits::fromQuantity(
- RHSVal.getInt().getZExtValue());
+ CharUnits AdditionalOffset =
+ CharUnits::fromQuantity(RHSVal.getInt().getZExtValue());
if (E->getOpcode() == BO_Add)
Result.getLValueOffset() += AdditionalOffset;
else
@@ -5391,8 +6464,8 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Add &&
RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- Result.getLValueOffset() += CharUnits::fromQuantity(
- LHSVal.getInt().getZExtValue());
+ Result.getLValueOffset() +=
+ CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
return true;
}
@@ -5416,108 +6489,20 @@ bool DataRecursiveIntBinOpEvaluator::
Result = APValue(LHSAddrExpr, RHSAddrExpr);
return true;
}
-
- // All the following cases expect both operands to be an integer
+
+ // All the remaining cases expect both operands to be an integer
if (!LHSVal.isInt() || !RHSVal.isInt())
return Error(E);
-
- const APSInt &LHS = LHSVal.getInt();
- APSInt RHS = RHSVal.getInt();
-
- switch (E->getOpcode()) {
- default:
- return Error(E);
- case BO_Mul:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() * 2,
- std::multiplies<APSInt>()), E,
- Result);
- case BO_Add:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() + 1,
- std::plus<APSInt>()), E, Result);
- case BO_Sub:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() + 1,
- std::minus<APSInt>()), E, Result);
- case BO_And: return Success(LHS & RHS, E, Result);
- case BO_Xor: return Success(LHS ^ RHS, E, Result);
- case BO_Or: return Success(LHS | RHS, E, Result);
- case BO_Div:
- case BO_Rem:
- if (RHS == 0)
- return Error(E, diag::note_expr_divide_by_zero);
- // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. The latter is
- // not actually undefined behavior in C++11 due to a language defect.
- if (RHS.isNegative() && RHS.isAllOnesValue() &&
- LHS.isSigned() && LHS.isMinSignedValue())
- HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
- return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
- Result);
- case BO_Shl: {
- if (Info.getLangOpts().OpenCL)
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
- RHS.isUnsigned());
- else if (RHS.isSigned() && RHS.isNegative()) {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
- RHS = -RHS;
- goto shift_right;
- }
-
- shift_left:
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of
- // the shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
- if (SA != RHS) {
- CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
- } else if (LHS.isSigned()) {
- // C++11 [expr.shift]p2: A signed left shift must have a non-negative
- // operand, and must not overflow the corresponding unsigned type.
- if (LHS.isNegative())
- CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
- else if (LHS.countLeadingZeros() < SA)
- CCEDiag(E, diag::note_constexpr_lshift_discards);
- }
-
- return Success(LHS << SA, E, Result);
- }
- case BO_Shr: {
- if (Info.getLangOpts().OpenCL)
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
- RHS.isUnsigned());
- else if (RHS.isSigned() && RHS.isNegative()) {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
- RHS = -RHS;
- goto shift_left;
- }
-
- shift_right:
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
- // shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
- if (SA != RHS)
- CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
-
- return Success(LHS >> SA, E, Result);
- }
-
- case BO_LT: return Success(LHS < RHS, E, Result);
- case BO_GT: return Success(LHS > RHS, E, Result);
- case BO_LE: return Success(LHS <= RHS, E, Result);
- case BO_GE: return Success(LHS >= RHS, E, Result);
- case BO_EQ: return Success(LHS == RHS, E, Result);
- case BO_NE: return Success(LHS != RHS, E, Result);
- }
+
+ // Set up the width and signedness manually, in case it can't be deduced
+ // from the operation we're performing.
+ // FIXME: Don't do this in the cases where we can deduce it.
+ APSInt Value(Info.Ctx.getIntWidth(E->getType()),
+ E->getType()->isUnsignedIntegerOrEnumerationType());
+ if (!handleIntIntBinOp(Info, E, LHSVal.getInt(), E->getOpcode(),
+ RHSVal.getInt(), Value))
+ return false;
+ return Success(Value, E, Result);
}
void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
@@ -5737,6 +6722,15 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
return false;
+ // As an extension, a type may have zero size (empty struct or union in
+ // C, array of zero length). Pointer subtraction in such cases has
+ // undefined behavior, so is not constant.
+ if (ElementSize.isZero()) {
+ Info.Diag(E, diag::note_constexpr_pointer_subtraction_zero_size)
+ << ElementType;
+ return false;
+ }
+
// FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,
// and produce incorrect results when it overflows. Such behavior
// appears to be non-conforming, but is common, so perhaps we should
@@ -5999,7 +6993,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CurrentType = AT->getElementType();
CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
Result += IdxResult.getSExtValue() * ElementSize;
- break;
+ break;
}
case OffsetOfExpr::OffsetOfNode::Field: {
@@ -6125,6 +7119,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -6140,7 +7135,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_UserDefinedConversion:
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -6369,6 +7363,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.changeSign();
return true;
+ // FIXME: Builtin::BI__builtin_powi
+ // FIXME: Builtin::BI__builtin_powif
+ // FIXME: Builtin::BI__builtin_powil
+
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
case Builtin::BI__builtin_copysignl: {
@@ -6430,28 +7428,8 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK)
- return false;
-
- switch (E->getOpcode()) {
- default: return Error(E);
- case BO_Mul:
- Result.multiply(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Add:
- Result.add(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Sub:
- Result.subtract(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Div:
- Result.divide(RHS, APFloat::rmNearestTiesToEven);
- break;
- }
-
- if (Result.isInfinity() || Result.isNaN())
- CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN();
- return true;
+ return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK &&
+ handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS);
}
bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
@@ -6613,11 +7591,11 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -6874,6 +7852,46 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
//===----------------------------------------------------------------------===//
+// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic
+// implicit conversion.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class AtomicExprEvaluator :
+ public ExprEvaluatorBase<AtomicExprEvaluator, bool> {
+ APValue &Result;
+public:
+ AtomicExprEvaluator(EvalInfo &Info, APValue &Result)
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+
+ bool ZeroInitialization(const Expr *E) {
+ ImplicitValueInitExpr VIE(
+ E->getType()->castAs<AtomicType>()->getValueType());
+ return Evaluate(Result, Info, &VIE);
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ case CK_NonAtomicToAtomic:
+ return Evaluate(Result, Info, E->getSubExpr());
+ }
+ }
+};
+} // end anonymous namespace
+
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isAtomicType());
+ return AtomicExprEvaluator(Info, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
// Void expression evaluation, primarily for a cast to void on the LHS of a
// comma operator
//===----------------------------------------------------------------------===//
@@ -6910,56 +7928,62 @@ static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
// In C, function designators are not lvalues, but we evaluate them as if they
// are.
- if (E->isGLValue() || E->getType()->isFunctionType()) {
+ QualType T = E->getType();
+ if (E->isGLValue() || T->isFunctionType()) {
LValue LV;
if (!EvaluateLValue(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isVectorType()) {
+ } else if (T->isVectorType()) {
if (!EvaluateVector(E, Result, Info))
return false;
- } else if (E->getType()->isIntegralOrEnumerationType()) {
+ } else if (T->isIntegralOrEnumerationType()) {
if (!IntExprEvaluator(Info, Result).Visit(E))
return false;
- } else if (E->getType()->hasPointerRepresentation()) {
+ } else if (T->hasPointerRepresentation()) {
LValue LV;
if (!EvaluatePointer(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isRealFloatingType()) {
+ } else if (T->isRealFloatingType()) {
llvm::APFloat F(0.0);
if (!EvaluateFloat(E, F, Info))
return false;
Result = APValue(F);
- } else if (E->getType()->isAnyComplexType()) {
+ } else if (T->isAnyComplexType()) {
ComplexValue C;
if (!EvaluateComplex(E, C, Info))
return false;
C.moveInto(Result);
- } else if (E->getType()->isMemberPointerType()) {
+ } else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
return false;
P.moveInto(Result);
return true;
- } else if (E->getType()->isArrayType()) {
+ } else if (T->isArrayType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
- if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ if (!EvaluateArray(E, LV, Value, Info))
return false;
- Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isRecordType()) {
+ Result = Value;
+ } else if (T->isRecordType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
- if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ if (!EvaluateRecord(E, LV, Value, Info))
return false;
- Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isVoidType()) {
+ Result = Value;
+ } else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
+ } else if (T->isAtomicType()) {
+ if (!EvaluateAtomic(E, Result, Info))
+ return false;
} else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
@@ -6975,9 +7999,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
/// cases, the in-place evaluation is essential, since later initializers for
/// an object can indirectly refer to subobjects which were initialized earlier.
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
- const Expr *E, CheckConstantExpressionKind CCEK,
- bool AllowNonLiteralTypes) {
- if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E))
+ const Expr *E, bool AllowNonLiteralTypes) {
+ if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E, &This))
return false;
if (E->isRValue()) {
@@ -7046,7 +8069,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
return IsConst;
- EvalInfo Info(Ctx, Result);
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
return ::EvaluateAsRValue(Info, this, Result.Val);
}
@@ -7072,7 +8095,7 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
}
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result);
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
LValue LV;
if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
@@ -7096,7 +8119,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus);
+ EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold);
InitInfo.setEvaluatingDecl(VD, Value);
LValue LVal;
@@ -7109,13 +8132,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
!VD->getType()->isReferenceType()) {
ImplicitValueInitExpr VIE(VD->getType());
- if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE, CCEK_Constant,
+ if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE,
/*AllowNonLiteralTypes=*/true))
return false;
}
- if (!EvaluateInPlace(Value, InitInfo, LVal, this, CCEK_Constant,
- /*AllowNonLiteralTypes=*/true) ||
+ if (!EvaluateInPlace(Value, InitInfo, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
EStatus.HasSideEffects)
return false;
@@ -7142,21 +8165,19 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
return EvalResult.Val.getInt();
}
-void Expr::EvaluateForOverflow(const ASTContext &Ctx,
- SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
bool IsConst;
EvalResult EvalResult;
- EvalResult.Diag = Diags;
if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
- EvalInfo Info(Ctx, EvalResult, true);
+ EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow);
(void)::EvaluateAsRValue(Info, this, EvalResult.Val);
}
}
- bool Expr::EvalResult::isGlobalLValue() const {
- assert(Val.isLValue());
- return IsGlobalLValue(Val.getLValueBase());
- }
+bool Expr::EvalResult::isGlobalLValue() const {
+ assert(Val.isLValue());
+ return IsGlobalLValue(Val.getLValueBase());
+}
/// isIntegerConstantExpr - this recursive routine will test if an expression is
@@ -7200,7 +8221,7 @@ static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
-static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
+static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
!EVResult.Val.isInt())
@@ -7209,7 +8230,7 @@ static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
-static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
+static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
if (!E->getType()->isIntegralOrEnumerationType())
return ICEDiag(IK_NotICE, E->getLocStart());
@@ -7250,6 +8271,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::UnresolvedLookupExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
+ case Expr::CXXStdInitializerListExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::CXXTemporaryObjectExprClass:
@@ -7269,6 +8291,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::BlockExprClass:
case Expr::NoStmtClass:
case Expr::OpaqueValueExprClass:
@@ -7561,7 +8584,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXDefaultInitExprClass:
return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx);
case Expr::ChooseExprClass: {
- return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
+ return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx);
}
}
@@ -7569,7 +8592,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
/// Evaluate an expression as a C++11 integral constant expression.
-static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
+static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
const Expr *E,
llvm::APSInt *Value,
SourceLocation *Loc) {
@@ -7587,7 +8610,8 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
return true;
}
-bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
+bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
+ SourceLocation *Loc) const {
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
@@ -7599,7 +8623,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
return true;
}
-bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
@@ -7611,11 +8635,11 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
return true;
}
-bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
+bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
return CheckICE(this, Ctx).Kind == IK_ICE;
}
-bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
+bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
SourceLocation *Loc) const {
// We support this checking in C++98 mode in order to diagnose compatibility
// issues.
@@ -7625,7 +8649,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
Expr::EvalStatus Status;
SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
- EvalInfo Info(Ctx, Status);
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
@@ -7653,13 +8677,13 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
Expr::EvalStatus Status;
Status.Diag = &Diags;
- EvalInfo Info(FD->getASTContext(), Status);
- Info.CheckingPotentialConstantExpression = true;
+ EvalInfo Info(FD->getASTContext(), Status,
+ EvalInfo::EM_PotentialConstantExpression);
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0;
- // FIXME: Fabricate an arbitrary expression on the stack and pretend that it
+ // Fabricate an arbitrary expression on the stack and pretend that it
// is a temporary being used as the 'this' pointer.
LValue This;
ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
@@ -7670,9 +8694,12 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
SourceLocation Loc = FD->getLocation();
APValue Scratch;
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ // Evaluate the call as a constant initializer, to allow the construction
+ // of objects of non-literal types.
+ Info.setEvaluatingDecl(This.getLValueBase(), Scratch);
HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
- else
+ } else
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0,
Args, FD->getBody(), Info, Scratch);
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index e03632a71e0e..3d64310dc56b 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -17,9 +17,11 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/TypeOrdering.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
+#include <set>
using namespace llvm;
@@ -135,34 +137,28 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
QualType Self = Context.getTypeDeclType(this);
- std::string ErrMsg;
- sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
- if (Filename.isEmpty()) {
- llvm::errs() << "Error: " << ErrMsg << "\n";
- return;
- }
- Filename.appendComponent(Self.getAsString() + ".dot");
- if (Filename.makeUnique(true,&ErrMsg)) {
- llvm::errs() << "Error: " << ErrMsg << "\n";
+
+ int FD;
+ SmallString<128> Filename;
+ error_code EC =
+ sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename);
+ if (EC) {
+ llvm::errs() << "Error: " << EC.message() << "\n";
return;
}
- llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
+ llvm::errs() << "Writing '" << Filename << "'... ";
- llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
+ llvm::raw_fd_ostream O(FD, true);
- if (ErrMsg.empty()) {
- InheritanceHierarchyWriter Writer(Context, O);
- Writer.WriteGraph(Self);
- llvm::errs() << " done. \n";
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
+ llvm::errs() << " done. \n";
- O.close();
+ O.close();
- // Display the graph
- DisplayGraph(Filename);
- } else {
- llvm::errs() << "error opening file for writing!\n";
- }
+ // Display the graph
+ DisplayGraph(Filename);
}
}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 894eb3bff5fd..578466028ce8 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -20,6 +20,7 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -27,6 +28,19 @@
using namespace clang;
namespace {
+
+/// \brief Keeps track of the mangled names of lambda expressions and block
+/// literals within a particular context.
+class ItaniumNumberingContext : public MangleNumberingContext {
+ llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
+
+public:
+ /// Variable decls are numbered by identifier.
+ virtual unsigned getManglingNumber(const VarDecl *VD) {
+ return ++VarManglingNumbers[VD->getIdentifier()];
+ }
+};
+
class ItaniumCXXABI : public CXXABI {
protected:
ASTContext &Context;
@@ -61,6 +75,10 @@ public:
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize;
}
+
+ virtual MangleNumberingContext *createMangleNumberingContext() const {
+ return new ItaniumNumberingContext();
+ }
};
class ARMCXXABI : public ItaniumCXXABI {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 5ad8021fac92..0621d7b1ad86 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -56,23 +56,36 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
= dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
return ContextParam->getDeclContext();
}
+
+ // Perform the same check for block literals.
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (ParmVarDecl *ContextParam
+ = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
+ return ContextParam->getDeclContext();
+ }
- return D->getDeclContext();
+ const DeclContext *DC = D->getDeclContext();
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
+ return getEffectiveDeclContext(CD);
+
+ return DC;
}
static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
-
-static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
- const DeclContext *DC = dyn_cast<DeclContext>(ND);
- if (!DC)
- DC = getEffectiveDeclContext(ND);
+
+static bool isLocalContainerContext(const DeclContext *DC) {
+ return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
+}
+
+static const RecordDecl *GetLocalClassDecl(const Decl *D) {
+ const DeclContext *DC = getEffectiveDeclContext(D);
while (!DC->isNamespace() && !DC->isTranslationUnit()) {
- const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
- if (isa<FunctionDecl>(Parent))
- return dyn_cast<CXXRecordDecl>(DC);
- DC = Parent;
+ if (isLocalContainerContext(DC))
+ return dyn_cast<RecordDecl>(D);
+ D = cast<Decl>(DC);
+ DC = getEffectiveDeclContext(D);
}
return 0;
}
@@ -91,15 +104,16 @@ static const NamedDecl *getStructor(const NamedDecl *decl) {
static const unsigned UnknownArity = ~0U;
-class ItaniumMangleContext : public MangleContext {
+class ItaniumMangleContextImpl : public ItaniumMangleContext {
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
- unsigned Discriminator;
+ typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
+ llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
public:
- explicit ItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags)
- : MangleContext(Context, Diags) { }
+ explicit ItaniumMangleContextImpl(ASTContext &Context,
+ DiagnosticsEngine &Diags)
+ : ItaniumMangleContext(Context, Diags) {}
uint64_t getAnonymousStructId(const TagDecl *TD) {
std::pair<llvm::DenseMap<const TagDecl *,
@@ -108,16 +122,11 @@ public:
return Result.first->second;
}
- void startNewFunction() {
- MangleContext::startNewFunction();
- mangleInitDiscriminator();
- }
-
/// @name Mangler Entry Points
/// @{
- bool shouldMangleDeclName(const NamedDecl *D);
- void mangleName(const NamedDecl *D, raw_ostream &);
+ bool shouldMangleCXXName(const NamedDecl *D);
+ void mangleCXXName(const NamedDecl *D, raw_ostream &);
void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &);
@@ -135,30 +144,45 @@ public:
raw_ostream &);
void mangleCXXRTTI(QualType T, raw_ostream &);
void mangleCXXRTTIName(QualType T, raw_ostream &);
+ void mangleTypeName(QualType T, raw_ostream &);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
raw_ostream &);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &);
- void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
+ void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &);
+ void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
+ void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out);
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &);
void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &);
- void mangleInitDiscriminator() {
- Discriminator = 0;
- }
-
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
- // Lambda closure types with external linkage (indicated by a
- // non-zero lambda mangling number) have their own numbering scheme, so
- // they do not need a discriminator.
+ // Lambda closure types are already numbered.
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
- if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
+ if (RD->isLambda())
return false;
-
+
+ // Anonymous tags are already numbered.
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
+ if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl())
+ return false;
+ }
+
+ // Use the canonical number for externally visible decls.
+ if (ND->isExternallyVisible()) {
+ unsigned discriminator = getASTContext().getManglingNumber(ND);
+ if (discriminator == 1)
+ return false;
+ disc = discriminator - 2;
+ return true;
+ }
+
+ // Make up a reasonable number for internal decls.
unsigned &discriminator = Uniquifier[ND];
- if (!discriminator)
- discriminator = ++Discriminator;
+ if (!discriminator) {
+ const DeclContext *DC = getEffectiveDeclContext(ND);
+ discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
+ }
if (discriminator == 1)
return false;
disc = discriminator-2;
@@ -169,7 +193,7 @@ public:
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
- ItaniumMangleContext &Context;
+ ItaniumMangleContextImpl &Context;
raw_ostream &Out;
/// The "structor" is the top-level declaration being mangled, if
@@ -225,7 +249,7 @@ class CXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const NamedDecl *D = 0)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
SeqID(0) {
@@ -233,11 +257,11 @@ public:
assert(!D || (!isa<CXXDestructorDecl>(D) &&
!isa<CXXConstructorDecl>(D)));
}
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
@@ -305,7 +329,9 @@ private:
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const NamedDecl *ND);
+ void mangleLocalName(const Decl *D);
+ void mangleBlockForPrefix(const BlockDecl *Block);
+ void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
bool NoFunction=false);
@@ -315,7 +341,7 @@ private:
void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void manglePrefix(QualType type);
- void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false);
void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
@@ -334,6 +360,7 @@ private:
void mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType);
void mangleNeonVectorType(const VectorType *T);
+ void mangleAArch64NeonVectorType(const VectorType *T);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
void mangleMemberExpr(const Expr *base, bool isArrow,
@@ -358,16 +385,7 @@ private:
}
-bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
-
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
-
+bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
if (FD) {
LanguageLinkage L = FD->getLanguageLinkage();
@@ -405,7 +423,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
- if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
+ if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
+ !isa<VarTemplateSpecializationDecl>(D))
return false;
}
@@ -413,26 +432,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
}
void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
-
- // Adding the prefix can cause problems when one file has a "foo" and
- // another has a "\01foo". That is known to happen on ELF with the
- // tricks normally used for producing aliases (PR9177). Fortunately the
- // llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker. We also avoid adding the marker if this is an alias for an
- // LLVM intrinsic.
- StringRef UserLabelPrefix =
- getASTContext().getTargetInfo().getUserLabelPrefix();
- if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
- Out << '\01'; // LLVM IR Marker for __asm("foo")
-
- Out << ALA->getLabel();
- return;
- }
-
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
@@ -441,6 +440,8 @@ void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
mangleFunctionEncoding(FD);
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleName(VD);
+ else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D))
+ mangleName(IFD->getAnonField());
else
mangleName(cast<FieldDecl>(D));
}
@@ -527,6 +528,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return Spec->getSpecializedTemplate();
}
+ // Check if we have a variable template.
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
return 0;
}
@@ -550,7 +558,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
- if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
+ if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
@@ -573,7 +581,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
return;
}
- if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
+ if (isLocalContainerContext(DC)) {
mangleLocalName(ND);
return;
}
@@ -825,6 +833,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
switch (type->getTypeClass()) {
case Type::Builtin:
case Type::Complex:
+ case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
case Type::LValueReference:
@@ -1053,7 +1062,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// static void foo();
// This naming convention is the same as that followed by GCC,
// though it shouldn't actually matter.
- if (ND && ND->getLinkage() == InternalLinkage &&
+ if (ND && ND->getFormalLinkage() == InternalLinkage &&
getEffectiveDeclContext(ND)->isFileContext())
Out << 'L';
@@ -1129,11 +1138,11 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
}
- int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
- if (UnnamedMangle != -1) {
+ if (TD->isExternallyVisible()) {
+ unsigned UnnamedMangle = getASTContext().getManglingNumber(TD);
Out << "Ut";
- if (UnnamedMangle != 0)
- Out << llvm::utostr(UnnamedMangle - 1);
+ if (UnnamedMangle > 1)
+ Out << llvm::utostr(UnnamedMangle - 2);
Out << '_';
break;
}
@@ -1231,14 +1240,19 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
- mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
+ Qualifiers MethodQuals =
+ Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+ // We do not consider restrict a distinguishing attribute for overloading
+ // purposes so we must not mangle it.
+ MethodQuals.removeRestrict();
+ mangleQualifiers(MethodQuals);
mangleRefQualifier(Method->getRefQualifier());
}
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD);
+ mangleTemplatePrefix(TD, NoFunction);
mangleTemplateArgs(*TemplateArgs);
}
else {
@@ -1261,36 +1275,37 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'E';
}
-void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
+void CXXNameMangler::mangleLocalName(const Decl *D) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <local-name> := Z <function encoding> E d [ <parameter number> ]
// _ <entity name>
// <discriminator> := _ <non-negative number>
- const DeclContext *DC = getEffectiveDeclContext(ND);
- if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
- // Don't add objc method name mangling to locally declared function
- mangleUnqualifiedName(ND);
- return;
- }
+ assert(isa<NamedDecl>(D) || isa<BlockDecl>(D));
+ const RecordDecl *RD = GetLocalClassDecl(D);
+ const DeclContext *DC = getEffectiveDeclContext(RD ? RD : D);
Out << 'Z';
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
- mangleObjCMethodName(MD);
- } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
- mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
- Out << 'E';
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(MD);
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
+ mangleBlockForPrefix(BD);
+ else
+ mangleFunctionEncoding(cast<FunctionDecl>(DC));
+
+ Out << 'E';
+ if (RD) {
// The parameter number is omitted for the last parameter, 0 for the
// second-to-last parameter, 1 for the third-to-last parameter, etc. The
// <entity name> will of course contain a <closure-type-name>: Its
// numbering will be local to the particular argument in which it appears
// -- other default arguments do not affect its encoding.
- bool SkipDiscriminator = false;
- if (RD->isLambda()) {
+ const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXRD->isLambda()) {
if (const ParmVarDecl *Parm
- = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
+ = dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) {
if (const FunctionDecl *Func
= dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
Out << 'd';
@@ -1298,34 +1313,88 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
if (Num > 1)
mangleNumber(Num - 2);
Out << '_';
- SkipDiscriminator = true;
}
}
}
// Mangle the name relative to the closest enclosing function.
- if (ND == RD) // equality ok because RD derived from ND above
- mangleUnqualifiedName(ND);
- else
- mangleNestedName(ND, DC, true /*NoFunction*/);
-
- if (!SkipDiscriminator) {
- unsigned disc;
- if (Context.getNextDiscriminator(RD, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
+ // equality ok because RD derived from ND above
+ if (D == RD) {
+ mangleUnqualifiedName(RD);
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
+ mangleUnqualifiedBlock(BD);
+ } else {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/);
+ }
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ // Mangle a block in a default parameter; see above explanation for
+ // lambdas.
+ if (const ParmVarDecl *Parm
+ = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) {
+ if (const FunctionDecl *Func
+ = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+ Out << 'd';
+ unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
+ if (Num > 1)
+ mangleNumber(Num - 2);
+ Out << '_';
}
}
-
+
+ mangleUnqualifiedBlock(BD);
+ } else {
+ mangleUnqualifiedName(cast<NamedDecl>(D));
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(ND, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
+ }
+}
+
+void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
+ if (GetLocalClassDecl(Block)) {
+ mangleLocalName(Block);
return;
}
- else
- mangleFunctionEncoding(cast<FunctionDecl>(DC));
+ const DeclContext *DC = getEffectiveDeclContext(Block);
+ if (isLocalContainerContext(DC)) {
+ mangleLocalName(Block);
+ return;
+ }
+ manglePrefix(getEffectiveDeclContext(Block));
+ mangleUnqualifiedBlock(Block);
+}
- Out << 'E';
- mangleUnqualifiedName(ND);
+void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
+ if (Decl *Context = Block->getBlockManglingContextDecl()) {
+ if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
+ Context->getDeclContext()->isRecord()) {
+ if (const IdentifierInfo *Name
+ = cast<NamedDecl>(Context)->getIdentifier()) {
+ mangleSourceName(Name);
+ Out << 'M';
+ }
+ }
+ }
+
+ // If we have a block mangling number, use it.
+ unsigned Number = Block->getBlockManglingNumber();
+ // Otherwise, just make up a number. It doesn't matter what it is because
+ // the symbol in question isn't externally visible.
+ if (!Number)
+ Number = Context.getBlockId(Block, false);
+ Out << "Ub";
+ if (Number > 1)
+ Out << Number - 2;
+ Out << '_';
}
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
@@ -1411,16 +1480,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (DC->isTranslationUnit())
return;
- if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
- manglePrefix(getEffectiveParentContext(DC), NoFunction);
- SmallString<64> Name;
- llvm::raw_svector_ostream NameStream(Name);
- Context.mangleBlock(Block, NameStream);
- NameStream.flush();
- Out << Name.size() << Name;
+ if (NoFunction && isLocalContainerContext(DC))
return;
- }
-
+
+ assert(!isLocalContainerContext(DC));
+
const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
@@ -1430,12 +1494,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgs(*TemplateArgs);
- }
- else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
- return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
- mangleObjCMethodName(Method);
- else {
+ } else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND);
}
@@ -1466,7 +1525,8 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
mangleUnscopedTemplateName(Template);
}
-void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
+void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
+ bool NoFunction) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
@@ -1483,7 +1543,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
return;
}
- manglePrefix(getEffectiveDeclContext(ND));
+ manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -1671,15 +1731,32 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
Out << 'K';
if (Quals.hasAddressSpace()) {
- // Extension:
+ // Address space extension:
//
- // <type> ::= U <address-space-number>
- //
- // where <address-space-number> is a source name consisting of 'AS'
- // followed by the address space <number>.
+ // <type> ::= U <target-addrspace>
+ // <type> ::= U <OpenCL-addrspace>
+ // <type> ::= U <CUDA-addrspace>
+
SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(
- Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace()));
+ unsigned AS = Quals.getAddressSpace();
+
+ if (Context.getASTContext().addressSpaceMapManglingFor(AS)) {
+ // <target-addrspace> ::= "AS" <address-space-number>
+ unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS);
+ ASString = "AS" + llvm::utostr_32(TargetAS);
+ } else {
+ switch (AS) {
+ default: llvm_unreachable("Not a language specific address space");
+ // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" ]
+ case LangAS::opencl_global: ASString = "CLglobal"; break;
+ case LangAS::opencl_local: ASString = "CLlocal"; break;
+ case LangAS::opencl_constant: ASString = "CLconstant"; break;
+ // <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ]
+ case LangAS::cuda_device: ASString = "CUdevice"; break;
+ case LangAS::cuda_constant: ASString = "CUconstant"; break;
+ case LangAS::cuda_shared: ASString = "CUshared"; break;
+ }
+ }
Out << 'U' << ASString.size() << ASString;
}
@@ -1722,7 +1799,6 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
// <ref-qualifier> ::= R # lvalue reference
// ::= O # rvalue-reference
- // Proposal to Itanium C++ ABI list on 1/26/11
switch (RefQualifier) {
case RQ_None:
break;
@@ -1905,7 +1981,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// <type> ::= <function-type>
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
-// (Proposal to cxx-abi-dev, 2012-05-11)
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
// e.g. "const" in "int (A::*)() const".
@@ -2101,7 +2176,9 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
case BuiltinType::LongLong: EltName = "int64_t"; break;
case BuiltinType::ULongLong: EltName = "uint64_t"; break;
case BuiltinType::Float: EltName = "float32_t"; break;
- default: llvm_unreachable("unexpected Neon vector element type");
+ case BuiltinType::Half: EltName = "float16_t";break;
+ default:
+ llvm_unreachable("unexpected Neon vector element type");
}
}
const char *BaseName = 0;
@@ -2117,6 +2194,71 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
Out << BaseName << EltName;
}
+static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
+ switch (EltType->getKind()) {
+ case BuiltinType::SChar:
+ return "Int8";
+ case BuiltinType::Short:
+ return "Int16";
+ case BuiltinType::Int:
+ return "Int32";
+ case BuiltinType::LongLong:
+ return "Int64";
+ case BuiltinType::UChar:
+ return "Uint8";
+ case BuiltinType::UShort:
+ return "Uint16";
+ case BuiltinType::UInt:
+ return "Uint32";
+ case BuiltinType::ULongLong:
+ return "Uint64";
+ case BuiltinType::Half:
+ return "Float16";
+ case BuiltinType::Float:
+ return "Float32";
+ case BuiltinType::Double:
+ return "Float64";
+ default:
+ llvm_unreachable("Unexpected vector element base type");
+ }
+}
+
+// AArch64's ABI for Neon vector types specifies that they should be mangled as
+// the equivalent internal name. The vector type must be one of the special
+// types predefined by ARM.
+void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) {
+ QualType EltType = T->getElementType();
+ assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
+ unsigned BitSize =
+ (T->getNumElements() * getASTContext().getTypeSize(EltType));
+ (void)BitSize; // Silence warning.
+
+ assert((BitSize == 64 || BitSize == 128) &&
+ "Neon vector type not 64 or 128 bits");
+
+ StringRef EltName;
+ if (T->getVectorKind() == VectorType::NeonPolyVector) {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::UChar:
+ EltName = "Poly8";
+ break;
+ case BuiltinType::UShort:
+ EltName = "Poly16";
+ break;
+ case BuiltinType::ULongLong:
+ EltName = "Poly64";
+ break;
+ default:
+ llvm_unreachable("unexpected Neon polynomial vector element type");
+ }
+ } else
+ EltName = mangleAArch64VectorBase(cast<BuiltinType>(EltType));
+
+ std::string TypeName =
+ ("__" + EltName + "x" + llvm::utostr(T->getNumElements()) + "_t").str();
+ Out << TypeName.length() << TypeName;
+}
+
// GNU extension: vector types
// <type> ::= <vector-type>
// <vector-type> ::= Dv <positive dimension number> _
@@ -2128,7 +2270,11 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
void CXXNameMangler::mangleType(const VectorType *T) {
if ((T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
- mangleNeonVectorType(T);
+ if (getASTContext().getTargetInfo().getTriple().getArch() ==
+ llvm::Triple::aarch64)
+ mangleAArch64NeonVectorType(T);
+ else
+ mangleNeonVectorType(T);
return;
}
Out << "Dv" << T->getNumElements() << '_';
@@ -2160,8 +2306,19 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
}
void CXXNameMangler::mangleType(const ObjCObjectType *T) {
- // We don't allow overloading by different protocol qualification,
- // so mangling them isn't necessary.
+ if (!T->qual_empty()) {
+ // Mangle protocol qualifiers.
+ SmallString<64> QualStr;
+ llvm::raw_svector_ostream QualOS(QualStr);
+ QualOS << "objcproto";
+ ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end();
+ for ( ; i != e; ++i) {
+ StringRef name = (*i)->getName();
+ QualOS << name.size() << name;
+ }
+ QualOS.flush();
+ Out << 'U' << QualStr.size() << QualStr;
+ }
mangleType(T->getBaseType());
}
@@ -2422,6 +2579,7 @@ recurse:
case Expr::OffsetOfExprClass:
case Expr::PredefinedExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
@@ -2477,6 +2635,10 @@ recurse:
mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity);
break;
+ case Expr::CXXStdInitializerListExprClass:
+ mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
+ break;
+
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
@@ -2676,8 +2838,8 @@ recurse:
case Expr::CXXThrowExprClass: {
const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= tw <expression> # throw expression
+ // ::= tr # rethrow
if (TE->getSubExpr()) {
Out << "tw";
mangleExpression(TE->getSubExpr());
@@ -2689,11 +2851,11 @@ recurse:
case Expr::CXXTypeidExprClass: {
const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= ti <type> # typeid (type)
+ // ::= te <expression> # typeid (expression)
if (TIE->isTypeOperand()) {
Out << "ti";
- mangleType(TIE->getTypeOperand());
+ mangleType(TIE->getTypeOperand(Context.getASTContext()));
} else {
Out << "te";
mangleExpression(TIE->getExprOperand());
@@ -2703,8 +2865,8 @@ recurse:
case Expr::CXXDeleteExprClass: {
const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= [gs] dl <expression> # [::] delete expr
+ // ::= [gs] da <expression> # [::] delete [] expr
if (DE->isGlobalDelete()) Out << "gs";
Out << (DE->isArrayForm() ? "da" : "dl");
mangleExpression(DE->getArgument());
@@ -2935,8 +3097,6 @@ recurse:
// fallthrough
case Expr::CXXNullPtrLiteralExprClass: {
- // Proposal from David Vandervoorde, 2010.06.30, as
- // modified by ABI list discussion.
Out << "LDnE";
break;
}
@@ -3101,7 +3261,6 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
- // ::= sp <expression> # pack expansion of (C++0x)
if (!A.isInstantiationDependent() || A.isDependent())
A = Context.getASTContext().getCanonicalTemplateArgument(A);
@@ -3181,9 +3340,9 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
break;
}
case TemplateArgument::Pack: {
- // Note: proposal by Mike Herrick on 12/20/10
+ // <template-arg> ::= J <template-arg>* E
Out << 'J';
- for (TemplateArgument::pack_iterator PA = A.pack_begin(),
+ for (TemplateArgument::pack_iterator PA = A.pack_begin(),
PAEnd = A.pack_end();
PA != PAEnd; ++PA)
mangleTemplateArg(*PA);
@@ -3452,8 +3611,8 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
/// and this routine will return false. In this case, the caller should just
/// emit the identifier of the declaration (\c D->getIdentifier()) as its
/// name.
-void ItaniumMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D,
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -3467,23 +3626,23 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
return Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
@@ -3499,21 +3658,20 @@ void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
Mangler.getStream() << 'c';
// Mangle the 'this' pointer adjustment.
- Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
-
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual,
+ Thunk.This.Virtual.Itanium.VCallOffsetOffset);
+
// Mangle the return pointer adjustment if there is one.
if (!Thunk.Return.isEmpty())
Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
-
+ Thunk.Return.Virtual.Itanium.VBaseOffsetOffset);
+
Mangler.mangleFunctionEncoding(MD);
}
-void
-ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXDtorThunk(
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment, raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
CXXNameMangler Mangler(*this, Out, DD, Type);
@@ -3521,15 +3679,15 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
// Mangle the 'this' pointer adjustment.
Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
- ThisAdjustment.VCallOffsetOffset);
+ ThisAdjustment.Virtual.Itanium.VCallOffsetOffset);
Mangler.mangleFunctionEncoding(DD);
}
/// mangleGuardVariable - Returns the mangled name for a guard variable
/// for the passed in VarDecl.
-void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleStaticGuardVariable(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
CXXNameMangler Mangler(*this, Out);
@@ -3537,24 +3695,44 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D,
+void ItaniumMangleContextImpl::mangleDynamicInitializer(const VarDecl *MD,
raw_ostream &Out) {
+ // These symbols are internal in the Itanium ABI, so the names don't matter.
+ // Clang has traditionally used this symbol and allowed LLVM to adjust it to
+ // avoid duplicate symbols.
+ Out << "__cxx_global_var_init";
+}
+
+void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) {
+ // Prefix the mangling of D with __dtor_.
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "__dtor_";
+ if (shouldMangleDeclName(D))
+ Mangler.mangle(D);
+ else
+ Mangler.getStream() << D->getName();
+}
+
+void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= TH <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTH";
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D,
- raw_ostream &Out) {
+void
+ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= TW <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTW";
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleReferenceTemporary(const VarDecl *D,
+ raw_ostream &Out) {
// We match the GCC mangling here.
// <special-name> ::= GR <object name>
CXXNameMangler Mangler(*this, Out);
@@ -3562,26 +3740,26 @@ void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTV";
Mangler.mangleNameOrStandardSubstitution(RD);
}
-void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
// <special-name> ::= TT <type> # VTT structure
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTT";
Mangler.mangleNameOrStandardSubstitution(RD);
}
-void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXCtorVTable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &Out) {
// <special-name> ::= TC <type> <offset number> _ <base type>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTC";
@@ -3591,8 +3769,7 @@ void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
Mangler.mangleNameOrStandardSubstitution(Type);
}
-void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
// <special-name> ::= TI <type> # typeinfo structure
assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
CXXNameMangler Mangler(*this, Out);
@@ -3600,15 +3777,19 @@ void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
Mangler.mangleType(Ty);
}
-void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty,
+ raw_ostream &Out) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTS";
Mangler.mangleType(Ty);
}
-MangleContext *clang::createItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new ItaniumMangleContext(Context, Diags);
+void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
+ mangleCXXRTTIName(Ty, Out);
+}
+
+ItaniumMangleContext *
+ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
+ return new ItaniumMangleContextImpl(Context, Diags);
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index eb794124490a..231ef036d829 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -10,6 +10,7 @@
// Implements generic name mangling support for blocks and Objective-C.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -19,6 +20,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,8 +36,6 @@ using namespace clang;
// FIXME: For blocks we currently mimic GCC's mangling scheme, which leaves
// much to be desired. Come up with a better mangling scheme.
-namespace {
-
static void mangleFunctionBlock(MangleContext &Context,
StringRef Outer,
const BlockDecl *BD,
@@ -47,23 +47,131 @@ static void mangleFunctionBlock(MangleContext &Context,
Out << "__" << Outer << "_block_invoke_" << discriminator+1;
}
-static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
-#ifndef NDEBUG
- const DeclContext *ExpectedDC = BD->getDeclContext();
- while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
- ExpectedDC = ExpectedDC->getParent();
- // In-class initializers for non-static data members are lexically defined
- // within the class, but are mangled as if they were specified as constructor
- // member initializers.
- if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
- DC = DC->getParent();
- assert(DC == ExpectedDC && "Given decl context did not match expected!");
-#endif
+void MangleContext::anchor() { }
+
+enum StdOrFastCC {
+ SOF_OTHER,
+ SOF_FAST,
+ SOF_STD
+};
+
+static bool isExternC(const NamedDecl *ND) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return FD->isExternC();
+ return cast<VarDecl>(ND)->isExternC();
}
+static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
+ const NamedDecl *ND) {
+ const TargetInfo &TI = Context.getTargetInfo();
+ llvm::Triple Triple = TI.getTriple();
+ if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
+ return SOF_OTHER;
+
+ if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
+ TI.getCXXABI() == TargetCXXABI::Microsoft)
+ return SOF_OTHER;
+
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ if (!FD)
+ return SOF_OTHER;
+ QualType T = FD->getType();
+
+ const FunctionType *FT = T->castAs<FunctionType>();
+
+ CallingConv CC = FT->getCallConv();
+ switch (CC) {
+ default:
+ return SOF_OTHER;
+ case CC_X86FastCall:
+ return SOF_FAST;
+ case CC_X86StdCall:
+ return SOF_STD;
+ }
}
-void MangleContext::anchor() { }
+bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ const ASTContext &ASTContext = getASTContext();
+
+ StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+ if (CC != SOF_OTHER)
+ return true;
+
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
+ return shouldMangleCXXName(D);
+}
+
+void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+ // If we have an asm name, then we use it as the mangling.
+
+ // Adding the prefix can cause problems when one file has a "foo" and
+ // another has a "\01foo". That is known to happen on ELF with the
+ // tricks normally used for producing aliases (PR9177). Fortunately the
+ // llvm mangler on ELF is a nop, so we can just avoid adding the \01
+ // marker. We also avoid adding the marker if this is an alias for an
+ // LLVM intrinsic.
+ StringRef UserLabelPrefix =
+ getASTContext().getTargetInfo().getUserLabelPrefix();
+ if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+ Out << ALA->getLabel();
+ return;
+ }
+
+ const ASTContext &ASTContext = getASTContext();
+ StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+ bool MCXX = shouldMangleCXXName(D);
+ const TargetInfo &TI = Context.getTargetInfo();
+ if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
+ mangleCXXName(D, Out);
+ return;
+ }
+
+ Out << '\01';
+ if (CC == SOF_STD)
+ Out << '_';
+ else
+ Out << '@';
+
+ if (!MCXX)
+ Out << D->getIdentifier()->getName();
+ else
+ mangleCXXName(D, Out);
+
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ const FunctionType *FT = FD->getType()->castAs<FunctionType>();
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT);
+ Out << '@';
+ if (!Proto) {
+ Out << '0';
+ return;
+ }
+ assert(!Proto->isVariadic());
+ unsigned ArgWords = 0;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (!MD->isStatic())
+ ++ArgWords;
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg) {
+ QualType AT = *Arg;
+ // Size should be aligned to DWORD boundary
+ ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
+ }
+ Out << 4 * ArgWords;
+}
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
const NamedDecl *ID,
@@ -85,7 +193,6 @@ void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
CXXCtorType CT, const BlockDecl *BD,
raw_ostream &ResStream) {
- checkMangleDC(CD, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXCtor(CD, CT, Out);
@@ -96,7 +203,6 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
CXXDtorType DT, const BlockDecl *BD,
raw_ostream &ResStream) {
- checkMangleDC(DD, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXDtor(DD, DT, Out);
@@ -107,7 +213,6 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
raw_ostream &Out) {
assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC));
- checkMangleDC(DC, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Stream(Buffer);
@@ -145,15 +250,3 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
Out << OS.str().size() << OS.str();
}
-
-void MangleContext::mangleBlock(const BlockDecl *BD,
- raw_ostream &Out,
- const NamedDecl *ID) {
- const DeclContext *DC = BD->getDeclContext();
- while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
- DC = DC->getParent();
- if (DC->isFunctionOrMethod())
- mangleBlock(DC, BD, Out);
- else
- mangleGlobalBlock(BD, ID, Out);
-}
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/MangleNumberingContext.cpp
index 54f445df4b64..91ef0e2240d8 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/MangleNumberingContext.cpp
@@ -1,4 +1,4 @@
-//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===//
+//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,22 +12,32 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;
-unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
+unsigned
+MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
-
- QualType Key =
- Context.getFunctionType(Context.VoidTy,
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- FunctionProtoType::ExtProtoInfo());
+
+ QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
+
+unsigned
+MangleNumberingContext::getManglingNumber(const BlockDecl *BD) {
+ // FIXME: Compute a BlockPointerType? Not obvious how.
+ const Type *Ty = 0;
+ return ++ManglingNumbers[Ty];
+}
+
+unsigned
+MangleNumberingContext::getManglingNumber(const TagDecl *TD) {
+ return ++TagManglingNumbers[TD->getIdentifier()];
+}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index fd932f7330a5..4a93ea1f417f 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -23,6 +24,22 @@
using namespace clang;
namespace {
+
+/// \brief Numbers things which need to correspond across multiple TUs.
+/// Typically these are things like static locals, lambdas, or blocks.
+class MicrosoftNumberingContext : public MangleNumberingContext {
+ unsigned NumStaticLocals;
+
+public:
+ MicrosoftNumberingContext() : NumStaticLocals(0) { }
+
+ /// Static locals are numbered by source order.
+ virtual unsigned getManglingNumber(const VarDecl *VD) {
+ assert(VD->isStaticLocal());
+ return ++NumStaticLocals;
+ }
+};
+
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
public:
@@ -51,6 +68,10 @@ public:
return Layout.getNonVirtualSize() == PointerSize ||
Layout.getNonVirtualSize() == PointerSize * 2;
}
+
+ MangleNumberingContext *createMangleNumberingContext() const {
+ return new MicrosoftNumberingContext();
+ }
};
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 1785063d7b1a..52565019d41d 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -22,12 +23,47 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include <map>
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringMap.h"
using namespace clang;
namespace {
+/// \brief Retrieve the declaration context that should be used when mangling
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+ // The ABI assumes that lambda closure types that occur within
+ // default arguments live in the context of the function. However, due to
+ // the way in which Clang parses and creates function declarations, this is
+ // not the case: the lambda closure type ends up living in the context
+ // where the function itself resides, because the function declaration itself
+ // had not yet been created. Fix the context here.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->isLambda())
+ if (ParmVarDecl *ContextParam =
+ dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ // Perform the same check for block literals.
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (ParmVarDecl *ContextParam =
+ dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ const DeclContext *DC = D->getDeclContext();
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
+ return getEffectiveDeclContext(CD);
+
+ return DC;
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+ return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
static const FunctionDecl *getStructor(const FunctionDecl *fn) {
if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
return ftd->getTemplatedDecl();
@@ -47,9 +83,7 @@ class MicrosoftCXXNameMangler {
const NamedDecl *Structor;
unsigned StructorType;
- // FIXME: audit the performance of BackRefMap as it might do way too many
- // copying of strings.
- typedef std::map<std::string, unsigned> BackRefMap;
+ typedef llvm::StringMap<unsigned> BackRefMap;
BackRefMap NameBackReferences;
bool UseNameBackReferences;
@@ -58,30 +92,41 @@ class MicrosoftCXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
+ // FIXME: If we add support for __ptr32/64 qualifiers, then we should push
+ // this check into mangleQualifiers().
+ const bool PointersAre64Bit;
+
public:
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
: Context(C), Out(Out_),
Structor(0), StructorType(-1),
- UseNameBackReferences(true) { }
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) { }
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_),
Structor(getStructor(D)), StructorType(Type),
- UseNameBackReferences(true) { }
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) { }
raw_ostream &getStream() const { return Out; }
void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
void mangleName(const NamedDecl *ND);
+ void mangleDeclaration(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleVariableEncoding(const VarDecl *VD);
void mangleNumber(int64_t Number);
- void mangleNumber(const llvm::APSInt &Value);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
+ void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = 0,
+ bool ForceInstMethod = false);
+ void manglePostfix(const DeclContext *DC, bool NoFunction = false);
private:
void disableBackReferences() { UseNameBackReferences = false; }
@@ -89,8 +134,7 @@ private:
mangleUnqualifiedName(ND, ND->getDeclName());
}
void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
- void mangleSourceName(const IdentifierInfo *II);
- void manglePostfix(const DeclContext *DC, bool NoFunction=false);
+ void mangleSourceName(StringRef Name);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
@@ -114,98 +158,111 @@ private:
#undef NON_CANONICAL_TYPE
#undef TYPE
- void mangleType(const TagType*);
- void mangleFunctionType(const FunctionType *T, const FunctionDecl *D,
- bool IsStructor, bool IsInstMethod);
- void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal);
- void mangleArrayType(const ArrayType *T, Qualifiers Quals);
+ void mangleType(const TagDecl *TD);
+ void mangleDecayedArrayType(const ArrayType *T);
+ void mangleArrayType(const ArrayType *T);
void mangleFunctionClass(const FunctionDecl *FD);
- void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
+ void mangleCallingConvention(const FunctionType *T);
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
void mangleTemplateArgs(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs);
-
+ void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA);
};
-/// MicrosoftMangleContext - Overrides the default MangleContext for the
+/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
/// Microsoft Visual C++ ABI.
-class MicrosoftMangleContext : public MangleContext {
+class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
public:
- MicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
- virtual bool shouldMangleDeclName(const NamedDecl *D);
- virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
+ MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
+ : MicrosoftMangleContext(Context, Diags) {}
+ virtual bool shouldMangleCXXName(const NamedDecl *D);
+ virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
+ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ uint64_t OffsetInVFTable,
+ raw_ostream &);
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &);
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &);
- virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &);
+ virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out);
+ virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out);
virtual void mangleCXXRTTI(QualType T, raw_ostream &);
virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
+ virtual void mangleTypeName(QualType T, raw_ostream &);
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
raw_ostream &);
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &);
- virtual void mangleReferenceTemporary(const clang::VarDecl *,
- raw_ostream &);
-};
-
-}
+ virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &);
+ virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out);
+ virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
+ virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out);
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = D->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
+private:
+ void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode);
+};
- return false;
}
-bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
+bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ LanguageLinkage L = FD->getLanguageLinkage();
+ // Overloadable functions need mangling.
+ if (FD->hasAttr<OverloadableAttr>())
+ return true;
+
+ // The ABI expects that we would never mangle "typical" user-defined entry
+ // points regardless of visibility or freestanding-ness.
+ //
+ // N.B. This is distinct from asking about "main". "main" has a lot of
+ // special rules associated with it in the standard while these
+ // user-defined entry points are outside of the purview of the standard.
+ // For example, there can be only one definition for "main" in a standards
+ // compliant program; however nothing forbids the existence of wmain and
+ // WinMain in the same translation unit.
+ if (FD->isMSVCRTEntryPoint())
+ return false;
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
+ // C++ functions and those whose names are not a simple identifier need
+ // mangling.
+ if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+ return true;
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
+ // C functions are not mangled.
+ if (L == CLanguageLinkage)
+ return false;
+ }
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- // Variables at global scope with internal linkage are not mangled.
- if (!FD) {
- const DeclContext *DC = D->getDeclContext();
- if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage)
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // C variables are not mangled.
+ if (VD->isExternC())
return false;
- }
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
+ // Variables at global scope with non-internal linkage are not mangled.
+ const DeclContext *DC = getEffectiveDeclContext(D);
+ // Check for extern variable declared locally.
+ if (DC->isFunctionOrMethod() && D->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = getEffectiveParentContext(DC);
+
+ if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage &&
+ !isa<VarTemplateSpecializationDecl>(D))
+ return false;
+ }
return true;
}
@@ -218,14 +275,6 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
// default, we emit an asm marker at the start so we get the name right.
// Callers can override this with a custom prefix.
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
- Out << '\01' << ALA->getLabel();
- return;
- }
-
// <mangled-name> ::= ? <name> <type-encoding>
Out << Prefix;
mangleName(D);
@@ -247,27 +296,25 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <type-encoding> ::= <function-class> <function-type>
- // Don't mangle in the type if this isn't a decl we should typically mangle.
- if (!Context.shouldMangleDeclName(FD))
- return;
-
+ // Since MSVC operates on the type as written and not the canonical type, it
+ // actually matters which decl we have here. MSVC appears to choose the
+ // first, since it is most likely to be the declaration in a header file.
+ FD = FD->getFirstDecl();
+
// We should never ever see a FunctionNoProtoType at this point.
// We don't even know how to mangle their types anyway :).
const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
- bool InStructor = false, InInstMethod = false;
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- if (MD) {
- if (MD->isInstance())
- InInstMethod = true;
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- InStructor = true;
- }
-
- // First, the function class.
- mangleFunctionClass(FD);
+ // extern "C" functions can hold entities that must be mangled.
+ // As it stands, these functions still need to get expressed in the full
+ // external name. They have their class and type omitted, replaced with '9'.
+ if (Context.shouldMangleDeclName(FD)) {
+ // First, the function class.
+ mangleFunctionClass(FD);
- mangleFunctionType(FT, FD, InStructor, InInstMethod);
+ mangleFunctionType(FT, FD);
+ } else
+ Out << '9';
}
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
@@ -299,12 +346,21 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
// mangled as 'QAHA' instead of 'PAHB', for example.
TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
QualType Ty = TL.getType();
- if (Ty->isPointerType() || Ty->isReferenceType()) {
+ if (Ty->isPointerType() || Ty->isReferenceType() ||
+ Ty->isMemberPointerType()) {
mangleType(Ty, TL.getSourceRange(), QMM_Drop);
- mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
+ if (PointersAre64Bit)
+ Out << 'E';
+ if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) {
+ mangleQualifiers(MPT->getPointeeType().getQualifiers(), true);
+ // Member pointers are suffixed with a back reference to the member
+ // pointer's class name.
+ mangleName(MPT->getClass()->getAsCXXRecordDecl());
+ } else
+ mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
} else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
// Global arrays are funny, too.
- mangleDecayedArrayType(AT, true);
+ mangleDecayedArrayType(AT);
if (AT->getElementType()->isArrayType())
Out << 'A';
else
@@ -335,39 +391,32 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
}
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
- APSNumber = Number;
- mangleNumber(APSNumber);
-}
-
-void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
- // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
- // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
- // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
- if (Value.isSigned() && Value.isNegative()) {
+ // <non-negative integer> ::= A@ # when Number == 0
+ // ::= <decimal digit> # when 1 <= Number <= 10
+ // ::= <hex digit>+ @ # when Number >= 10
+ //
+ // <number> ::= [?] <non-negative integer>
+
+ uint64_t Value = static_cast<uint64_t>(Number);
+ if (Number < 0) {
+ Value = -Value;
Out << '?';
- mangleNumber(llvm::APSInt(Value.abs()));
- return;
}
- llvm::APSInt Temp(Value);
- // There's a special shorter mangling for 0, but Microsoft
- // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
- if (Value.uge(1) && Value.ule(10)) {
- --Temp;
- Temp.print(Out, false);
- } else {
- // We have to build up the encoding in reverse order, so it will come
- // out right when we write it out.
- char Encoding[64];
- char *EndPtr = Encoding+sizeof(Encoding);
- char *CurPtr = EndPtr;
- llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
- NibbleMask = 0xf;
- do {
- *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
- Temp = Temp.lshr(4);
- } while (Temp != 0);
- Out.write(CurPtr, EndPtr-CurPtr);
+
+ if (Value == 0)
+ Out << "A@";
+ else if (Value >= 1 && Value <= 10)
+ Out << (Value - 1);
+ else {
+ // Numbers that are not encoded as decimal digits are represented as nibbles
+ // in the range of ASCII characters 'A' to 'P'.
+ // The number 0x123450 would be encoded as 'BCDEFA'
+ char EncodedNumberBuffer[sizeof(uint64_t) * 2];
+ llvm::MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
+ llvm::MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
+ for (; Value != 0; Value >>= 4)
+ *I++ = 'A' + (Value & 0xf);
+ Out.write(I.base(), I - BufferRef.rbegin());
Out << '@';
}
}
@@ -403,7 +452,16 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- // We have a template.
+ // Function templates aren't considered for name back referencing. This
+ // makes sense since function templates aren't likely to occur multiple
+ // times in a symbol.
+ // FIXME: Test alias template mangling with MSVC 2013.
+ if (!isa<ClassTemplateDecl>(TD)) {
+ mangleTemplateInstantiationName(TD, *TemplateArgs);
+ return;
+ }
+
+ // We have a class template.
// Here comes the tricky thing: if we need to mangle something like
// void foo(A::X<Y>, B::X<Y>),
// the X<Y> part is aliased. However, if you need to mangle
@@ -445,7 +503,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- mangleSourceName(II);
+ mangleSourceName(II->getName());
break;
}
@@ -466,13 +524,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
- mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo()->getName());
break;
}
- // When VC encounters an anonymous type with no tag and no typedef,
- // it literally emits '<unnamed-tag>'.
- Out << "<unnamed-tag>";
+ if (TD->hasDeclaratorForAnonDecl()) {
+ // Anonymous types with no tag or typedef get the name of their
+ // declarator mangled in.
+ llvm::SmallString<64> Name("<unnamed-type-");
+ Name += TD->getDeclaratorForAnonDecl()->getName();
+ Name += ">";
+ mangleSourceName(Name.str());
+ } else {
+ // Anonymous types with no tag, no typedef, or declarator get
+ // '<unnamed-tag>'.
+ mangleSourceName("<unnamed-tag>");
+ }
break;
}
@@ -495,9 +562,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// use the type we were given.
mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
else
- // Otherwise, use the complete destructor name. This is relevant if a
+ // Otherwise, use the base destructor name. This is relevant if a
// class with a destructor is declared within a destructor.
- mangleCXXDtorType(Dtor_Complete);
+ mangleCXXDtorType(Dtor_Base);
break;
case DeclarationName::CXXConversionFunctionName:
@@ -538,9 +605,20 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
return;
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- Context.mangleBlock(BD, Out);
+ 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 << '@';
return manglePostfix(DC->getParent(), NoFunction);
+ } else if (isa<CapturedDecl>(DC)) {
+ // Skip CapturedDecl context.
+ manglePostfix(DC->getParent(), NoFunction);
+ return;
}
if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
@@ -556,18 +634,19 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
}
void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ // Microsoft uses the names on the case labels for these dtor variants. Clang
+ // uses the Itanium terminology internally. Everything in this ABI delegates
+ // towards the base dtor.
switch (T) {
- case Dtor_Deleting:
- Out << "?_G";
- return;
- case Dtor_Base:
- // FIXME: We should be asked to mangle base dtors.
- // However, fixing this would require larger changes to the CodeGenModule.
- // Please put llvm_unreachable here when CGM is changed.
- // For now, just mangle a base dtor the same way as a complete dtor...
- case Dtor_Complete:
- Out << "?1";
- return;
+ // <operator-name> ::= ?1 # destructor
+ case Dtor_Base: Out << "?1"; return;
+ // <operator-name> ::= ?_D # vbase destructor
+ case Dtor_Complete: Out << "?_D"; return;
+ // <operator-name> ::= ?_G # scalar deleting destructor
+ case Dtor_Deleting: Out << "?_G"; return;
+ // <operator-name> ::= ?_E # vector deleting destructor
+ // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
+ // it.
}
llvm_unreachable("Unsupported dtor type?");
}
@@ -704,17 +783,16 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
}
}
-void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
- std::string key = II->getNameStart();
BackRefMap::iterator Found;
if (UseNameBackReferences)
- Found = NameBackReferences.find(key);
+ Found = NameBackReferences.find(Name);
if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- Out << II->getName() << '@';
+ Out << Name << '@';
if (UseNameBackReferences && NameBackReferences.size() < 10) {
size_t Size = NameBackReferences.size();
- NameBackReferences[key] = Size;
+ NameBackReferences[Name] = Size;
}
} else {
Out << Found->second;
@@ -756,7 +834,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
// functions. You could have a method baz of class C inside a function bar
// inside a function foo, like so:
// ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
- int NestLevel = getLocalNestingLevel(FD);
+ unsigned NestLevel = getLocalNestingLevel(FD);
Out << '?';
mangleNumber(NestLevel);
Out << '?';
@@ -800,7 +878,7 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
if (IsBoolean && Value.getBoolValue())
mangleNumber(1);
else
- mangleNumber(Value);
+ mangleNumber(Value.getSExtValue());
}
void
@@ -812,6 +890,33 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
return;
}
+ const CXXUuidofExpr *UE = 0;
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_AddrOf)
+ UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr());
+ } else
+ UE = dyn_cast<CXXUuidofExpr>(E);
+
+ if (UE) {
+ // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from
+ // const __s_GUID _GUID_{lower case UUID with underscores}
+ StringRef Uuid = UE->getUuidAsStringRef(Context.getASTContext());
+ std::string Name = "_GUID_" + Uuid.lower();
+ std::replace(Name.begin(), Name.end(), '-', '_');
+
+ // If we had to peek through an address-of operator, treat this like we are
+ // dealing with a pointer type. Otherwise, treat it like a const reference.
+ //
+ // N.B. This matches up with the handling of TemplateArgument::Declaration
+ // in mangleTemplateArg
+ if (UE == E)
+ Out << "$E?";
+ else
+ Out << "$1?";
+ Out << Name << "@@3U__s_GUID@@B";
+ return;
+ }
+
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
@@ -827,44 +932,51 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
unsigned NumTemplateArgs = TemplateArgs.size();
for (unsigned i = 0; i < NumTemplateArgs; ++i) {
const TemplateArgument &TA = TemplateArgs[i];
- switch (TA.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("Can't mangle null template arguments!");
- case TemplateArgument::Type: {
- QualType T = TA.getAsType();
- mangleType(T, SourceRange(), QMM_Escape);
- break;
- }
- case TemplateArgument::Declaration:
- mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?");
- break;
- case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getAsIntegral(),
- TA.getIntegralType()->isBooleanType());
- break;
- case TemplateArgument::Expression:
- mangleExpression(TA.getAsExpr());
- break;
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Pack: {
- // Issue a diagnostic.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle template argument %0 of kind %select{ERROR|ERROR|"
- "pointer/reference|nullptr|integral|template|template pack expansion|"
- "ERROR|parameter pack}1 yet");
- Diags.Report(TD->getLocation(), DiagID)
- << i + 1
- << TA.getKind()
- << TD->getSourceRange();
- }
- }
+ mangleTemplateArg(TD, TA);
}
Out << '@';
}
+void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
+ const TemplateArgument &TA) {
+ switch (TA.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't mangle null template arguments!");
+ case TemplateArgument::TemplateExpansion:
+ llvm_unreachable("Can't mangle template expansion arguments!");
+ case TemplateArgument::Type: {
+ QualType T = TA.getAsType();
+ mangleType(T, SourceRange(), QMM_Escape);
+ break;
+ }
+ case TemplateArgument::Declaration: {
+ const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
+ mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ break;
+ }
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
+ break;
+ case TemplateArgument::NullPtr:
+ Out << "$0A@";
+ break;
+ case TemplateArgument::Expression:
+ mangleExpression(TA.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ // Unlike Itanium, there is no character code to indicate an argument pack.
+ for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end();
+ I != E; ++I)
+ mangleTemplateArg(TD, *I);
+ break;
+ case TemplateArgument::Template:
+ mangleType(cast<TagDecl>(
+ TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl()));
+ break;
+ }
+}
+
void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
bool IsMember) {
// <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
@@ -921,6 +1033,7 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
// ::= 5 # not really based
bool HasConst = Quals.hasConst(),
HasVolatile = Quals.hasVolatile();
+
if (!IsMember) {
if (HasConst && HasVolatile) {
Out << 'D';
@@ -966,20 +1079,32 @@ void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
SourceRange Range) {
- void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
+ // MSVC will backreference two canonically equivalent types that have slightly
+ // different manglings when mangled alone.
+
+ // Decayed types do not match up with non-decayed versions of the same type.
+ //
+ // e.g.
+ // void (*x)(void) will not form a backreference with void x(void)
+ void *TypePtr;
+ if (const DecayedType *DT = T->getAs<DecayedType>()) {
+ TypePtr = DT->getOriginalType().getCanonicalType().getAsOpaquePtr();
+ // If the original parameter was textually written as an array,
+ // instead treat the decayed parameter like it's const.
+ //
+ // e.g.
+ // int [] -> int * const
+ if (DT->getOriginalType()->isArrayType())
+ T = T.withConst();
+ } else
+ TypePtr = T.getCanonicalType().getAsOpaquePtr();
+
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
size_t OutSizeBefore = Out.GetNumBytesInBuffer();
- if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
- mangleDecayedArrayType(AT, false);
- } else if (const FunctionType *FT = T->getAs<FunctionType>()) {
- Out << "P6";
- mangleFunctionType(FT, 0, false, false);
- } else {
- mangleType(T, Range, QMM_Drop);
- }
+ mangleType(T, Range, QMM_Drop);
// See if it's worth creating a back reference.
// Only types longer than 1 character are considered
@@ -996,16 +1121,18 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM) {
- // Only operate on the canonical type!
- T = getASTContext().getCanonicalType(T);
+ // Don't use the canonical types. MSVC includes things like 'const' on
+ // pointer arguments to function pointers that canonicalization strips away.
+ T = T.getDesugaredType(getASTContext());
Qualifiers Quals = T.getLocalQualifiers();
-
- if (const ArrayType *AT = dyn_cast<ArrayType>(T)) {
+ if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
+ // If there were any Quals, getAsArrayType() pushed them onto the array
+ // element type.
if (QMM == QMM_Mangle)
Out << 'A';
else if (QMM == QMM_Escape || QMM == QMM_Result)
Out << "$$B";
- mangleArrayType(AT, Quals);
+ mangleArrayType(AT);
return;
}
@@ -1018,7 +1145,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
case QMM_Mangle:
if (const FunctionType *FT = dyn_cast<FunctionType>(T)) {
Out << '6';
- mangleFunctionType(FT, 0, false, false);
+ mangleFunctionType(FT);
return;
}
mangleQualifiers(Quals, false);
@@ -1151,7 +1278,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
// structor type.
// FIXME: This may not be lambda-friendly.
Out << "$$A6";
- mangleFunctionType(T, NULL, false, false);
+ mangleFunctionType(T);
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
SourceRange) {
@@ -1160,18 +1287,31 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
const FunctionDecl *D,
- bool IsStructor,
- bool IsInstMethod) {
+ bool ForceInstMethod) {
// <function-type> ::= <this-cvr-qualifiers> <calling-convention>
// <return-type> <argument-list> <throw-spec>
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+ SourceRange Range;
+ if (D) Range = D->getSourceRange();
+
+ bool IsStructor = false, IsInstMethod = ForceInstMethod;
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
+ if (MD->isInstance())
+ IsInstMethod = true;
+ if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
+ IsStructor = true;
+ }
+
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
- if (IsInstMethod)
+ if (IsInstMethod) {
+ if (PointersAre64Bit)
+ Out << 'E';
mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
+ }
- mangleCallingConvention(T, IsInstMethod);
+ mangleCallingConvention(T);
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
@@ -1182,12 +1322,15 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// However, the FunctionType generated has 0 arguments.
// FIXME: This is a temporary hack.
// Maybe should fix the FunctionType creation instead?
- Out << "PAXI@Z";
+ Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return;
}
Out << '@';
} else {
- mangleType(Proto->getResultType(), SourceRange(), QMM_Result);
+ QualType ResultType = Proto->getResultType();
+ if (ResultType->isVoidType())
+ ResultType = ResultType.getUnqualifiedType();
+ mangleType(ResultType, Range, QMM_Result);
}
// <argument-list> ::= X # void
@@ -1196,23 +1339,11 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
Out << 'X';
} else {
- if (D) {
- // If we got a decl, use the type-as-written to make sure arrays
- // get mangled right. Note that we can't rely on the TSI
- // existing if (for example) the parameter was synthesized.
- for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
- ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
- TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
- QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
- mangleArgumentType(Type, (*Parm)->getSourceRange());
- }
- } else {
- // Happens for function pointer type arguments for example.
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleArgumentType(*Arg, SourceRange());
- }
+ // Happens for function pointer type arguments for example.
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleArgumentType(*Arg, Range);
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
@@ -1224,35 +1355,34 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
}
void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
- // <function-class> ::= A # private: near
- // ::= B # private: far
- // ::= C # private: static near
- // ::= D # private: static far
- // ::= E # private: virtual near
- // ::= F # private: virtual far
- // ::= G # private: thunk near
- // ::= H # private: thunk far
- // ::= I # protected: near
- // ::= J # protected: far
- // ::= K # protected: static near
- // ::= L # protected: static far
- // ::= M # protected: virtual near
- // ::= N # protected: virtual far
- // ::= O # protected: thunk near
- // ::= P # protected: thunk far
- // ::= Q # public: near
- // ::= R # public: far
- // ::= S # public: static near
- // ::= T # public: static far
- // ::= U # public: virtual near
- // ::= V # public: virtual far
- // ::= W # public: thunk near
- // ::= X # public: thunk far
- // ::= Y # global near
- // ::= Z # global far
+ // <function-class> ::= <member-function> E? # E designates a 64-bit 'this'
+ // # pointer. in 64-bit mode *all*
+ // # 'this' pointers are 64-bit.
+ // ::= <global-function>
+ // <member-function> ::= A # private: near
+ // ::= B # private: far
+ // ::= C # private: static near
+ // ::= D # private: static far
+ // ::= E # private: virtual near
+ // ::= F # private: virtual far
+ // ::= I # protected: near
+ // ::= J # protected: far
+ // ::= K # protected: static near
+ // ::= L # protected: static far
+ // ::= M # protected: virtual near
+ // ::= N # protected: virtual far
+ // ::= Q # public: near
+ // ::= R # public: far
+ // ::= S # public: static near
+ // ::= T # public: static far
+ // ::= U # public: virtual near
+ // ::= V # public: virtual far
+ // <global-function> ::= Y # global near
+ // ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
switch (MD->getAccess()) {
- default:
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
Out << 'C';
@@ -1280,8 +1410,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
} else
Out << 'Y';
}
-void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
- bool IsInstMethod) {
+void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
// <calling-convention> ::= A # __cdecl
// ::= B # __export __cdecl
// ::= C # __pascal
@@ -1298,20 +1427,11 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
// that they could be in a DLL and somebody from another module could call
// them.)
CallingConv CC = T->getCallConv();
- if (CC == CC_Default) {
- if (IsInstMethod) {
- const FunctionProtoType *FPT =
- T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
- bool isVariadic = FPT->isVariadic();
- CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
- } else {
- CC = CC_C;
- }
- }
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
- case CC_Default:
+ case CC_X86_64Win64:
+ case CC_X86_64SysV:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
case CC_X86ThisCall: Out << 'E'; break;
@@ -1347,13 +1467,13 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
// <class-type> ::= V <name>
// <enum-type> ::= W <size> <name>
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
- mangleType(cast<TagType>(T));
+ mangleType(cast<TagType>(T)->getDecl());
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
- mangleType(cast<TagType>(T));
+ mangleType(cast<TagType>(T)->getDecl());
}
-void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
- switch (T->getDecl()->getTagKind()) {
+void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
+ switch (TD->getTagKind()) {
case TTK_Union:
Out << 'T';
break;
@@ -1367,30 +1487,23 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
case TTK_Enum:
Out << 'W';
Out << getASTContext().getTypeSizeInChars(
- cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity();
+ cast<EnumDecl>(TD)->getIntegerType()).getQuantity();
break;
}
- mangleName(T->getDecl());
+ mangleName(TD);
}
// <type> ::= <array-type>
// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
// [Y <dimension-count> <dimension>+]
-// <element-type> # as global
-// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as param
+// <element-type> # as global, E is never required
// It's supposed to be the other way around, but for some strange reason, it
// isn't. Today this behavior is retained for the sole purpose of backwards
// compatibility.
-void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T,
- bool IsGlobal) {
+void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
- if (IsGlobal) {
- manglePointerQualifiers(T->getElementType().getQualifiers());
- } else {
- Out << 'Q';
- }
+ manglePointerQualifiers(T->getElementType().getQualifiers());
mangleType(T->getElementType(), SourceRange());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
@@ -1409,8 +1522,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
SourceRange) {
llvm_unreachable("Should have been special cased");
}
-void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
- Qualifiers Quals) {
+void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
QualType ElementTy(T, 0);
SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
@@ -1449,8 +1561,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
mangleNumber(Dimensions.size());
for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
mangleNumber(Dimensions[Dim].getLimitedValue());
- mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals),
- SourceRange(), QMM_Escape);
+ mangleType(ElementTy, SourceRange(), QMM_Escape);
}
// <type> ::= <pointer-to-member-type>
@@ -1462,8 +1573,10 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '8';
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
- mangleFunctionType(FPT, NULL, false, true);
+ mangleFunctionType(FPT, 0, true);
} else {
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleQualifiers(PointeeType.getQualifiers(), true);
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleType(PointeeType, Range, QMM_Drop);
@@ -1490,32 +1603,43 @@ void MicrosoftCXXNameMangler::mangleType(
}
// <type> ::= <pointer-type>
-// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static pointers
void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
SourceRange Range) {
QualType PointeeTy = T->getPointeeType();
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(PointeeTy, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
SourceRange Range) {
// Object pointers never have qualifiers.
Out << 'A';
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <reference-type>
-// <reference-type> ::= A <cvr-qualifiers> <type>
+// <reference-type> ::= A E? <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static lvalue references
void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
SourceRange Range) {
Out << 'A';
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <r-value-reference-type>
-// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type>
+// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static rvalue references
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
SourceRange Range) {
Out << "$$Q";
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
@@ -1598,16 +1722,12 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
Out << "_E";
QualType pointee = T->getPointeeType();
- mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
+ mangleFunctionType(pointee->castAs<FunctionProtoType>());
}
-void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this injected class name type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *,
+ SourceRange) {
+ llvm_unreachable("Cannot mangle injected class name type.");
}
void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T,
@@ -1700,8 +1820,8 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T,
<< Range;
}
-void MicrosoftMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -1714,85 +1834,265 @@ void MicrosoftMangleContext::mangleName(const NamedDecl *D,
MicrosoftCXXNameMangler Mangler(*this, Out);
return Mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this method yet");
- getDiags().Report(MD->getLocation(), DiagID);
+
+// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
+// <virtual-adjustment>
+// <no-adjustment> ::= A # private near
+// ::= B # private far
+// ::= I # protected near
+// ::= J # protected far
+// ::= Q # public near
+// ::= R # public far
+// <static-adjustment> ::= G <static-offset> # private near
+// ::= H <static-offset> # private far
+// ::= O <static-offset> # protected near
+// ::= P <static-offset> # protected far
+// ::= W <static-offset> # public near
+// ::= X <static-offset> # public far
+// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near
+// ::= $1 <virtual-shift> <static-offset> # private far
+// ::= $2 <virtual-shift> <static-offset> # protected near
+// ::= $3 <virtual-shift> <static-offset> # protected far
+// ::= $4 <virtual-shift> <static-offset> # public near
+// ::= $5 <virtual-shift> <static-offset> # public far
+// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift>
+// <vtordisp-shift> ::= <offset-to-vtordisp>
+// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset>
+// <offset-to-vtordisp>
+static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
+ const ThisAdjustment &Adjustment,
+ MicrosoftCXXNameMangler &Mangler,
+ raw_ostream &Out) {
+ if (!Adjustment.Virtual.isEmpty()) {
+ Out << '$';
+ char AccessSpec;
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ AccessSpec = '0';
+ break;
+ case AS_protected:
+ AccessSpec = '2';
+ break;
+ case AS_public:
+ AccessSpec = '4';
+ }
+ if (Adjustment.Virtual.Microsoft.VBPtrOffset) {
+ Out << 'R' << AccessSpec;
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBPtrOffset));
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBOffsetOffset));
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
+ Mangler.mangleNumber(static_cast<uint32_t>(Adjustment.NonVirtual));
+ } else {
+ Out << AccessSpec;
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
+ Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
+ }
+ } else if (Adjustment.NonVirtual != 0) {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'G';
+ break;
+ case AS_protected:
+ Out << 'O';
+ break;
+ case AS_public:
+ Out << 'W';
+ }
+ Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
+ } else {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'A';
+ break;
+ case AS_protected:
+ Out << 'I';
+ break;
+ case AS_public:
+ Out << 'Q';
+ }
+ }
}
-void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this destructor yet");
- getDiags().Report(DD->getLocation(), DiagID);
+
+void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
+ const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) {
+ bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
+
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_9";
+ Mangler.mangleName(MD->getParent());
+ Mangler.getStream() << "$B";
+ Mangler.mangleNumber(OffsetInVFTable);
+ Mangler.getStream() << "A";
+ Mangler.getStream() << (Is64Bit ? "A" : "E");
}
-void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+
+void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
raw_ostream &Out) {
- // <mangled-name> ::= ? <operator-name> <class-name> <storage-class>
- // <cvr-qualifiers> [<name>] @
- // <operator-name> ::= _7 # vftable
- // ::= _8 # vbtable
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Out << "\01?";
+ Mangler.mangleName(MD);
+ mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out);
+ if (!Thunk.Return.isEmpty())
+ assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl");
+
+ const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
+ Mangler.mangleFunctionType(
+ DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &Adjustment, raw_ostream &Out) {
+ // FIXME: Actually, the dtor thunk should be emitted for vector deleting
+ // dtors rather than scalar deleting dtors. Just use the vector deleting dtor
+ // mangling manually until we support both deleting dtor types.
+ assert(Type == Dtor_Deleting);
+ MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type);
+ Out << "\01??_E";
+ Mangler.mangleName(DD->getParent());
+ mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out);
+ Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXVFTable(
+ const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ?_7 <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
- // is always '6' for vftables and '7' for vbtables. (The difference is
- // beyond me.)
- // TODO: vbtables.
+ // is always '6' for vftables.
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??_7";
- Mangler.mangleName(RD);
- Mangler.getStream() << "6B";
- // TODO: If the class has more than one vtable, mangle in the class it came
- // from.
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
+ for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
+ E = BasePath.end();
+ I != E; ++I) {
+ Mangler.mangleName(*I);
+ }
Mangler.getStream() << '@';
}
-void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have virtual table tables!");
-}
-void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
+
+void MicrosoftMangleContextImpl::mangleCXXVBTable(
+ const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ?_8 <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
+ // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
+ // is always '7' for vbtables.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_8";
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const.
+ for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
+ E = BasePath.end();
+ I != E; ++I) {
+ Mangler.mangleName(*I);
+ }
+ Mangler.getStream() << '@';
}
-void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &) {
// FIXME: Give a location...
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle RTTI descriptors for type %0 yet");
getDiags().Report(DiagID)
<< T.getBaseTypeIdentifier();
}
-void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, raw_ostream &) {
// FIXME: Give a location...
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle the name of type %0 into RTTI descriptors yet");
getDiags().Report(DiagID)
<< T.getBaseTypeIdentifier();
}
-void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream & Out) {
+
+void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
+ // This is just a made up unique string for the purposes of tbaa. undname
+ // does *not* know how to demangle it.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << '?';
+ Mangler.mangleType(T, SourceRange());
+}
+
+void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream &Out) {
MicrosoftCXXNameMangler mangler(*this, Out);
mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream & Out) {
+
+void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream &Out) {
MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
+ raw_ostream &) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this reference temporary yet");
getDiags().Report(VD->getLocation(), DiagID);
}
-MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new MicrosoftMangleContext(Context, Diags);
+void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
+ raw_ostream &Out) {
+ // <guard-name> ::= ?_B <postfix> @51
+ // ::= ?$S <guard-num> @ <postfix> @4IA
+
+ // The first mangling is what MSVC uses to guard static locals in inline
+ // functions. It uses a different mangling in external functions to support
+ // guarding more than 32 variables. MSVC rejects inline functions with more
+ // than 32 static locals. We don't fully implement the second mangling
+ // because those guards are not externally visible, and instead use LLVM's
+ // default renaming when creating a new guard variable.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+
+ bool Visible = VD->isExternallyVisible();
+ // <operator-name> ::= ?_B # local static guard
+ Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@");
+ Mangler.manglePostfix(VD->getDeclContext());
+ Mangler.getStream() << (Visible ? "@51" : "@4IA");
+}
+
+void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D,
+ raw_ostream &Out,
+ char CharCode) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??__" << CharCode;
+ Mangler.mangleName(D);
+ // This is the function class mangling. These stubs are global, non-variadic,
+ // cdecl functions that return void and take no args.
+ Mangler.getStream() << "YAXXZ";
+}
+
+void MicrosoftMangleContextImpl::mangleDynamicInitializer(const VarDecl *D,
+ raw_ostream &Out) {
+ // <initializer-name> ::= ?__E <name> YAXXZ
+ mangleInitFiniStub(D, Out, 'E');
+}
+
+void
+MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) {
+ // <destructor-name> ::= ?__F <name> YAXXZ
+ mangleInitFiniStub(D, Out, 'F');
+}
+
+MicrosoftMangleContext *
+MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
+ return new MicrosoftMangleContextImpl(Context, Diags);
}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 79cc21a062c8..b03c4e09fa46 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -566,8 +566,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
Stack.push_back(NNS);
while (!Stack.empty()) {
- NestedNameSpecifier *NNS = Stack.back();
- Stack.pop_back();
+ NestedNameSpecifier *NNS = Stack.pop_back_val();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 113592860b77..ff44d938d3ae 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/DenseMap.h"
using namespace clang;
@@ -33,6 +34,11 @@ static void BuildParentMap(MapTy& M, Stmt* S,
assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+ // If we are rebuilding the map, clear out any existing state.
+ if (M[POE->getSyntacticForm()])
+ for (Stmt::child_range I = S->children(); I; ++I)
+ M[*I] = 0;
+
M[POE->getSyntacticForm()] = S;
BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
@@ -62,13 +68,19 @@ static void BuildParentMap(MapTy& M, Stmt* S,
break;
}
- case Stmt::OpaqueValueExprClass:
- if (OVMode == OV_Transparent) {
- OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ case Stmt::OpaqueValueExprClass: {
+ // FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs
+ // share a single source expression, but in the AST a single
+ // OpaqueValueExpr is shared among multiple parent expressions.
+ // The right thing to do is to give the OpaqueValueExpr its syntactic
+ // parent, then not reassign that when traversing the semantic expressions.
+ OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) {
M[OVE->getSourceExpr()] = S;
BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
}
break;
+ }
default:
for (Stmt::child_range I = S->children(); I; ++I) {
if (*I) {
@@ -98,6 +110,13 @@ void ParentMap::addStmt(Stmt* S) {
}
}
+void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {
+ assert(S);
+ assert(Parent);
+ MapTy *M = reinterpret_cast<MapTy *>(Impl);
+ M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent)));
+}
+
Stmt* ParentMap::getParent(Stmt* S) const {
MapTy* M = (MapTy*) Impl;
MapTy::iterator I = M->find(S);
@@ -139,8 +158,9 @@ bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;
- // Ignore parents that are parentheses or casts.
- while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) {
+ // Ignore parents that don't guarantee consumption.
+ while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||
+ isa<ExprWithCleanups>(P))) {
DirectChild = P;
P = getParent(P);
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 92b96dc8e5a1..1fa7cea1d498 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -68,8 +68,7 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
bool Merged, bool ParseAllComments) :
Range(SR), RawTextValid(false), BriefTextValid(false),
IsAttached(false), IsAlmostTrailingComment(false),
- ParseAllComments(ParseAllComments),
- BeginLineValid(false), EndLineValid(false) {
+ ParseAllComments(ParseAllComments) {
// Extract raw comment text, if possible.
if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) {
Kind = RCK_Invalid;
@@ -90,26 +89,6 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
}
}
-unsigned RawComment::getBeginLine(const SourceManager &SM) const {
- if (BeginLineValid)
- return BeginLine;
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin());
- BeginLine = SM.getLineNumber(LocInfo.first, LocInfo.second);
- BeginLineValid = true;
- return BeginLine;
-}
-
-unsigned RawComment::getEndLine(const SourceManager &SM) const {
- if (EndLineValid)
- return EndLine;
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getEnd());
- EndLine = SM.getLineNumber(LocInfo.first, LocInfo.second);
- EndLineValid = true;
- return EndLine;
-}
-
StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const {
FileID BeginFileID;
FileID EndFileID;
@@ -184,13 +163,9 @@ comments::FullComment *RawComment::parse(const ASTContext &Context,
return P.parseFullComment();
}
-namespace {
-bool containsOnlyWhitespace(StringRef Str) {
- return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos;
-}
-
-bool onlyWhitespaceBetween(SourceManager &SM,
- SourceLocation Loc1, SourceLocation Loc2) {
+static bool onlyWhitespaceBetween(SourceManager &SM,
+ SourceLocation Loc1, SourceLocation Loc2,
+ unsigned MaxNewlinesAllowed) {
std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1);
std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2);
@@ -203,10 +178,38 @@ bool onlyWhitespaceBetween(SourceManager &SM,
if (Invalid)
return false;
- StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second);
- return containsOnlyWhitespace(Text);
+ unsigned NumNewlines = 0;
+ assert(Loc1Info.second <= Loc2Info.second && "Loc1 after Loc2!");
+ // Look for non-whitespace characters and remember any newlines seen.
+ for (unsigned I = Loc1Info.second; I != Loc2Info.second; ++I) {
+ switch (Buffer[I]) {
+ default:
+ return false;
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ break;
+ case '\r':
+ case '\n':
+ ++NumNewlines;
+
+ // Check if we have found more than the maximum allowed number of
+ // newlines.
+ if (NumNewlines > MaxNewlinesAllowed)
+ return false;
+
+ // Collapse \r\n and \n\r into a single newline.
+ if (I + 1 != Loc2Info.second &&
+ (Buffer[I + 1] == '\n' || Buffer[I + 1] == '\r') &&
+ Buffer[I] != Buffer[I + 1])
+ ++I;
+ break;
+ }
+ }
+
+ return true;
}
-} // unnamed namespace
void RawCommentList::addComment(const RawComment &RC,
llvm::BumpPtrAllocator &Allocator) {
@@ -215,23 +218,13 @@ void RawCommentList::addComment(const RawComment &RC,
// Check if the comments are not in source order.
while (!Comments.empty() &&
- !SourceMgr.isBeforeInTranslationUnit(
- Comments.back()->getSourceRange().getBegin(),
- RC.getSourceRange().getBegin())) {
+ !SourceMgr.isBeforeInTranslationUnit(Comments.back()->getLocStart(),
+ RC.getLocStart())) {
// If they are, just pop a few last comments that don't fit.
// This happens if an \#include directive contains comments.
Comments.pop_back();
}
- if (OnlyWhitespaceSeen) {
- if (!onlyWhitespaceBetween(SourceMgr,
- PrevCommentEndLoc,
- RC.getSourceRange().getBegin()))
- OnlyWhitespaceSeen = false;
- }
-
- PrevCommentEndLoc = RC.getSourceRange().getEnd();
-
// Ordinary comments are not interesting for us.
if (RC.isOrdinary())
return;
@@ -240,7 +233,6 @@ void RawCommentList::addComment(const RawComment &RC,
// anything to merge it with).
if (Comments.empty()) {
Comments.push_back(new (Allocator) RawComment(RC));
- OnlyWhitespaceSeen = true;
return;
}
@@ -250,21 +242,13 @@ void RawCommentList::addComment(const RawComment &RC,
// Merge comments only if there is only whitespace between them.
// Can't merge trailing and non-trailing comments.
// Merge comments if they are on same or consecutive lines.
- bool Merged = false;
- if (OnlyWhitespaceSeen &&
- (C1.isTrailingComment() == C2.isTrailingComment())) {
- unsigned C1EndLine = C1.getEndLine(SourceMgr);
- unsigned C2BeginLine = C2.getBeginLine(SourceMgr);
- if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) {
- SourceRange MergedRange(C1.getSourceRange().getBegin(),
- C2.getSourceRange().getEnd());
- *Comments.back() = RawComment(SourceMgr, MergedRange, true,
- RC.isParseAllComments());
- Merged = true;
- }
- }
- if (!Merged)
+ if (C1.isTrailingComment() == C2.isTrailingComment() &&
+ onlyWhitespaceBetween(SourceMgr, C1.getLocEnd(), C2.getLocStart(),
+ /*MaxNewlinesAllowed=*/1)) {
+ SourceRange MergedRange(C1.getLocStart(), C2.getLocEnd());
+ *Comments.back() = RawComment(SourceMgr, MergedRange, true,
+ RC.isParseAllComments());
+ } else {
Comments.push_back(new (Allocator) RawComment(RC));
-
- OnlyWhitespaceSeen = true;
+ }
}
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index f6cfe63cd34e..71e44ecf9219 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -43,7 +43,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- bool hasOwnVFPtr, CharUnits vbptroffset,
+ bool hasOwnVFPtr, bool hasExtendableVFPtr,
+ CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
@@ -52,6 +53,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase,
bool IsPrimaryBaseVirtual,
+ const CXXRecordDecl *BaseSharingVBPtr,
+ bool AlignAfterVBases,
const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0),
@@ -71,6 +74,10 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->VBaseOffsets = VBaseOffsets;
CXXInfo->HasOwnVFPtr = hasOwnVFPtr;
CXXInfo->VBPtrOffset = vbptroffset;
+ CXXInfo->HasExtendableVFPtr = hasExtendableVFPtr;
+ CXXInfo->BaseSharingVBPtr = BaseSharingVBPtr;
+ CXXInfo->AlignAfterVBases = AlignAfterVBases;
+
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 42c3ba31bc76..4390e66c8b1c 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -211,7 +211,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
if (!RD->isEmpty())
return;
- // If we have empty structures inside an union, we can assign both
+ // If we have empty structures inside a union, we can assign both
// the same offset. Just avoid pushing them twice in the list.
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
@@ -573,10 +573,14 @@ protected:
unsigned IsMsStruct : 1;
- /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
- /// this contains the number of bits in the last byte that can be used for
- /// an adjacent bitfield if necessary.
- unsigned char UnfilledBitsInLastByte;
+ /// UnfilledBitsInLastUnit - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last unit that can be used for
+ /// an adjacent bitfield if necessary. The unit in question is usually
+ /// a byte, but larger units are used if IsMsStruct.
+ unsigned char UnfilledBitsInLastUnit;
+ /// LastBitfieldTypeSize - If IsMsStruct, represents the size of the type
+ /// of the previous field if it was a bitfield.
+ unsigned char LastBitfieldTypeSize;
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
@@ -588,8 +592,6 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
- FieldDecl *ZeroLengthBitfield;
-
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -602,9 +604,6 @@ protected:
/// pointer, as opposed to inheriting one from a primary base class.
bool HasOwnVFPtr;
- /// VBPtrOffset - Virtual base table offset. Only for MS layout.
- CharUnits VBPtrOffset;
-
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@@ -646,13 +645,12 @@ protected:
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
ExternalLayout(false), InferAlignment(false),
Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
+ UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
+ MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
- ZeroLengthBitfield(0), PrimaryBase(0),
- PrimaryBaseIsVirtual(false),
+ PrimaryBase(0), PrimaryBaseIsVirtual(false),
HasOwnVFPtr(false),
- VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
/// Reset this RecordLayoutBuilder to a fresh state, using the given
@@ -680,12 +678,6 @@ protected:
return Context.getTargetInfo().getCXXABI();
}
- bool isMicrosoftCXXABI() const {
- return getCXXABI().isMicrosoft();
- }
-
- void MSLayoutVirtualBases(const CXXRecordDecl *RD);
-
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@@ -727,21 +719,12 @@ protected:
void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset);
- bool needsVFTable(const CXXRecordDecl *RD) const;
- bool hasNewVirtualFunction(const CXXRecordDecl *RD,
- bool IgnoreDestructor = false) const;
- bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const;
-
- void computeVtordisps(const CXXRecordDecl *RD,
- ClassSetTy &VtordispVBases);
-
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
- void LayoutVirtualBase(const BaseSubobjectInfo *Base,
- bool IsVtordispNeed = false);
+ void LayoutVirtualBase(const BaseSubobjectInfo *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in chars.
@@ -851,7 +834,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (isPossiblePrimaryBase(Base)) {
+ if (Base->isDynamicClass()) {
// We found it.
PrimaryBase = Base;
PrimaryBaseIsVirtual = false;
@@ -859,12 +842,6 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
}
- // The Microsoft ABI doesn't have primary virtual bases.
- if (isMicrosoftCXXABI()) {
- assert(!PrimaryBase && "Should not get here with a primary base!");
- return;
- }
-
// Under the Itanium ABI, if there is no non-virtual primary base class,
// try to compute the primary virtual base. The primary virtual base is
// the first nearly empty virtual base that is not an indirect primary
@@ -1043,7 +1020,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// If this class needs a vtable/vf-table and didn't get one from a
// primary base, add it in now.
- } else if (needsVFTable(RD)) {
+ } else if (RD->isDynamicClass()) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
@@ -1055,26 +1032,17 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
setDataSize(getSize());
}
- bool HasDirectVirtualBases = false;
- bool HasNonVirtualBaseWithVBTable = false;
-
// Now lay out the non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual bases, but remember that we saw one.
- if (I->isVirtual()) {
- HasDirectVirtualBases = true;
+ // Ignore virtual bases.
+ if (I->isVirtual())
continue;
- }
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
- // Remember if this base has virtual bases itself.
- if (BaseDecl->getNumVBases())
- HasNonVirtualBaseWithVBTable = true;
-
// Skip the primary base, because we've already laid it out. The
// !PrimaryBaseIsVirtual check is required because we might have a
// non-virtual base of the same type as a primary virtual base.
@@ -1087,37 +1055,6 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
LayoutNonVirtualBase(BaseInfo);
}
-
- // In the MS ABI, add the vb-table pointer if we need one, which is
- // whenever we have a virtual base and we can't re-use a vb-table
- // pointer from a non-virtual base.
- if (isMicrosoftCXXABI() &&
- HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) {
- CharUnits PtrWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- CharUnits PtrAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
-
- // MSVC potentially over-aligns the vb-table pointer by giving it
- // the max alignment of all the non-virtual objects in the class.
- // This is completely unnecessary, but we're not here to pass
- // judgment.
- //
- // Note that we've only laid out the non-virtual bases, so on the
- // first pass Alignment won't be set correctly here, but if the
- // vb-table doesn't end up aligned correctly we'll come through
- // and redo the layout from scratch with the right alignment.
- //
- // TODO: Instead of doing this, just lay out the fields as if the
- // vb-table were at offset zero, then retroactively bump the field
- // offsets up.
- PtrAlign = std::max(PtrAlign, Alignment);
-
- EnsureVTablePointerAlignment(PtrAlign);
- VBPtrOffset = getSize();
- setSize(getSize() + PtrWidth);
- setDataSize(getSize());
- }
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
@@ -1166,249 +1103,6 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
}
}
-/// needsVFTable - Return true if this class needs a vtable or vf-table
-/// when laid out as a base class. These are treated the same because
-/// they're both always laid out at offset zero.
-///
-/// This function assumes that the class has no primary base.
-bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const {
- assert(!PrimaryBase);
-
- // In the Itanium ABI, every dynamic class needs a vtable: even if
- // this class has no virtual functions as a base class (i.e. it's
- // non-polymorphic or only has virtual functions from virtual
- // bases),x it still needs a vtable to locate its virtual bases.
- if (!isMicrosoftCXXABI())
- return RD->isDynamicClass();
-
- // In the MS ABI, we need a vfptr if the class has virtual functions
- // other than those declared by its virtual bases. The AST doesn't
- // tell us that directly, and checking manually for virtual
- // functions that aren't overrides is expensive, but there are
- // some important shortcuts:
-
- // - Non-polymorphic classes have no virtual functions at all.
- if (!RD->isPolymorphic()) return false;
-
- // - Polymorphic classes with no virtual bases must either declare
- // virtual functions directly or inherit them, but in the latter
- // case we would have a primary base.
- if (RD->getNumVBases() == 0) return true;
-
- return hasNewVirtualFunction(RD);
-}
-
-/// Does the given class inherit non-virtually from any of the classes
-/// in the given set?
-static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD,
- const ClassSetTy &set) {
- for (CXXRecordDecl::base_class_const_iterator
- I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual links.
- if (I->isVirtual()) continue;
-
- // Check whether the set contains the base.
- const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
- if (set.count(base))
- return true;
-
- // Otherwise, recurse and propagate.
- if (hasNonVirtualBaseInSet(base, set))
- return true;
- }
-
- return false;
-}
-
-/// Does the given method (B::foo()) already override a method (A::foo())
-/// such that A requires a vtordisp in B? If so, we don't need to add a
-/// new vtordisp for B in a yet-more-derived class C providing C::foo().
-static bool overridesMethodRequiringVtorDisp(const ASTContext &Context,
- const CXXMethodDecl *M) {
- CXXMethodDecl::method_iterator
- I = M->begin_overridden_methods(), E = M->end_overridden_methods();
- if (I == E) return false;
-
- const ASTRecordLayout::VBaseOffsetsMapTy &offsets =
- Context.getASTRecordLayout(M->getParent()).getVBaseOffsetsMap();
- do {
- const CXXMethodDecl *overridden = *I;
-
- // If the overridden method's class isn't recognized as a virtual
- // base in the derived class, ignore it.
- ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- it = offsets.find(overridden->getParent());
- if (it == offsets.end()) continue;
-
- // Otherwise, check if the overridden method's class needs a vtordisp.
- if (it->second.hasVtorDisp()) return true;
-
- } while (++I != E);
- return false;
-}
-
-/// In the Microsoft ABI, decide which of the virtual bases require a
-/// vtordisp field.
-void RecordLayoutBuilder::computeVtordisps(const CXXRecordDecl *RD,
- ClassSetTy &vtordispVBases) {
- // Bail out if we have no virtual bases.
- assert(RD->getNumVBases());
-
- // Build up the set of virtual bases that we haven't decided yet.
- ClassSetTy undecidedVBases;
- for (CXXRecordDecl::base_class_const_iterator
- I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *vbase = I->getType()->getAsCXXRecordDecl();
- undecidedVBases.insert(vbase);
- }
- assert(!undecidedVBases.empty());
-
- // A virtual base requires a vtordisp field in a derived class if it
- // requires a vtordisp field in a base class. Walk all the direct
- // bases and collect this information.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
- const ASTRecordLayout &baseLayout = Context.getASTRecordLayout(base);
-
- // Iterate over the set of virtual bases provided by this class.
- for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- VI = baseLayout.getVBaseOffsetsMap().begin(),
- VE = baseLayout.getVBaseOffsetsMap().end(); VI != VE; ++VI) {
- // If it doesn't need a vtordisp in this base, ignore it.
- if (!VI->second.hasVtorDisp()) continue;
-
- // If we've already seen it and decided it needs a vtordisp, ignore it.
- if (!undecidedVBases.erase(VI->first))
- continue;
-
- // Add it.
- vtordispVBases.insert(VI->first);
-
- // Quit as soon as we've decided everything.
- if (undecidedVBases.empty())
- return;
- }
- }
-
- // Okay, we have virtual bases that we haven't yet decided about. A
- // virtual base requires a vtordisp if any the non-destructor
- // virtual methods declared in this class directly override a method
- // provided by that virtual base. (If so, we need to emit a thunk
- // for that method, to be used in the construction vftable, which
- // applies an additional 'vtordisp' this-adjustment.)
-
- // Collect the set of bases directly overridden by any method in this class.
- // It's possible that some of these classes won't be virtual bases, or won't be
- // provided by virtual bases, or won't be virtual bases in the overridden
- // instance but are virtual bases elsewhere. Only the last matters for what
- // we're doing, and we can ignore those: if we don't directly override
- // a method provided by a virtual copy of a base class, but we do directly
- // override a method provided by a non-virtual copy of that base class,
- // then we must indirectly override the method provided by the virtual base,
- // and so we should already have collected it in the loop above.
- ClassSetTy overriddenBases;
- for (CXXRecordDecl::method_iterator
- M = RD->method_begin(), E = RD->method_end(); M != E; ++M) {
- // Ignore non-virtual methods and destructors.
- if (isa<CXXDestructorDecl>(*M) || !M->isVirtual())
- continue;
-
- for (CXXMethodDecl::method_iterator I = M->begin_overridden_methods(),
- E = M->end_overridden_methods(); I != E; ++I) {
- const CXXMethodDecl *overriddenMethod = (*I);
-
- // Ignore methods that override methods from vbases that require
- // require vtordisps.
- if (overridesMethodRequiringVtorDisp(Context, overriddenMethod))
- continue;
-
- // As an optimization, check immediately whether we're overriding
- // something from the undecided set.
- const CXXRecordDecl *overriddenBase = overriddenMethod->getParent();
- if (undecidedVBases.erase(overriddenBase)) {
- vtordispVBases.insert(overriddenBase);
- if (undecidedVBases.empty()) return;
-
- // We can't 'continue;' here because one of our undecided
- // vbases might non-virtually inherit from this base.
- // Consider:
- // struct A { virtual void foo(); };
- // struct B : A {};
- // struct C : virtual A, virtual B { virtual void foo(); };
- // We need a vtordisp for B here.
- }
-
- // Otherwise, just collect it.
- overriddenBases.insert(overriddenBase);
- }
- }
-
- // Walk the undecided v-bases and check whether they (non-virtually)
- // provide any of the overridden bases. We don't need to consider
- // virtual links because the vtordisp inheres to the layout
- // subobject containing the base.
- for (ClassSetTy::const_iterator
- I = undecidedVBases.begin(), E = undecidedVBases.end(); I != E; ++I) {
- if (hasNonVirtualBaseInSet(*I, overriddenBases))
- vtordispVBases.insert(*I);
- }
-}
-
-/// hasNewVirtualFunction - Does the given polymorphic class declare a
-/// virtual function that does not override a method from any of its
-/// base classes?
-bool
-RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD,
- bool IgnoreDestructor) const {
- if (!RD->getNumBases())
- return true;
-
- for (CXXRecordDecl::method_iterator method = RD->method_begin();
- method != RD->method_end();
- ++method) {
- if (method->isVirtual() && !method->size_overridden_methods() &&
- !(IgnoreDestructor && method->getKind() == Decl::CXXDestructor)) {
- return true;
- }
- }
- return false;
-}
-
-/// isPossiblePrimaryBase - Is the given base class an acceptable
-/// primary base class?
-bool
-RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *base) const {
- // In the Itanium ABI, a class can be a primary base class if it has
- // a vtable for any reason.
- if (!isMicrosoftCXXABI())
- return base->isDynamicClass();
-
- // In the MS ABI, a class can only be a primary base class if it
- // provides a vf-table at a static offset. That means it has to be
- // non-virtual base. The existence of a separate vb-table means
- // that it's possible to get virtual functions only from a virtual
- // base, which we have to guard against.
-
- // First off, it has to have virtual functions.
- if (!base->isPolymorphic()) return false;
-
- // If it has no virtual bases, then the vfptr must be at a static offset.
- if (!base->getNumVBases()) return true;
-
- // Otherwise, the necessary information is cached in the layout.
- const ASTRecordLayout &layout = Context.getASTRecordLayout(base);
-
- // If the base has its own vfptr, it can be a primary base.
- if (layout.hasOwnVFPtr()) return true;
-
- // If the base has a primary base class, then it can be a primary base.
- if (layout.getPrimaryBase()) return true;
-
- // Otherwise it can't.
- return false;
-}
-
void
RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
@@ -1458,39 +1152,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
-void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
- if (!RD->getNumVBases())
- return;
-
- ClassSetTy VtordispVBases;
- computeVtordisps(RD, VtordispVBases);
-
- // This is substantially simplified because there are no virtual
- // primary bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
- const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
- assert(BaseInfo && "Did not find virtual base info!");
-
- // If this base requires a vtordisp, add enough space for an int field.
- // This is apparently always 32-bits, even on x64.
- bool vtordispNeeded = false;
- if (VtordispVBases.count(BaseDecl)) {
- CharUnits IntSize =
- CharUnits::fromQuantity(Context.getTargetInfo().getIntWidth() / 8);
-
- setSize(getSize() + IntSize);
- setDataSize(getSize());
- vtordispNeeded = true;
- }
-
- LayoutVirtualBase(BaseInfo, vtordispNeeded);
- }
-}
-
-void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
- bool IsVtordispNeed) {
+void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
// Layout the base.
@@ -1499,10 +1161,9 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
// Add its base class offset.
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
VBases.insert(std::make_pair(Base->Class,
- ASTRecordLayout::VBaseInfo(Offset, IsVtordispNeed)));
+ ASTRecordLayout::VBaseInfo(Offset, false)));
- if (!isMicrosoftCXXABI())
- AddPrimaryVirtualBaseOffsets(Base, Offset);
+ AddPrimaryVirtualBaseOffsets(Base, Offset);
}
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
@@ -1530,18 +1191,19 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
}
+ CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
(!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
return CharUnits::Zero();
}
- CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
- CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
-
// The maximum field alignment overrides base align.
if (!MaxFieldAlignment.isZero()) {
BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
@@ -1655,24 +1317,8 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
- if (isMicrosoftCXXABI()) {
- if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
- CharUnits AlignMember =
- NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
-
- setSize(getSize() + AlignMember);
- setDataSize(getSize());
-
- NonVirtualSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.getTargetInfo().getCharAlign()));
- }
-
- MSLayoutVirtualBases(RD);
- } else {
- // Lay out the virtual bases and add the primary virtual base offsets.
- LayoutVirtualBases(RD, RD);
- }
+ // Lay out the virtual bases and add the primary virtual base offsets.
+ LayoutVirtualBases(RD, RD);
// Finally, round the size of the total struct up to the alignment
// of the struct itself.
@@ -1728,123 +1374,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
- const FieldDecl *LastFD = 0;
- ZeroLengthBitfield = 0;
- unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
- if (IsMsStruct) {
- FieldDecl *FD = *Field;
- if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
- ZeroLengthBitfield = FD;
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
- continue;
- // FIXME. streamline these conditions into a simple one.
- else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
- Context.BitfieldFollowsNonBitfield(FD, LastFD) ||
- Context.NonBitfieldFollowsBitfield(FD, LastFD)) {
- // 1) Adjacent bit fields are packed into the same 1-, 2-, or
- // 4-byte allocation unit if the integral types are the same
- // size and if the next bit field fits into the current
- // allocation unit without crossing the boundary imposed by the
- // common alignment requirements of the bit fields.
- // 2) Establish a new alignment for a bitfield following
- // a non-bitfield if size of their types differ.
- // 3) Establish a new alignment for a non-bitfield following
- // a bitfield if size of their types differ.
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- unsigned FieldAlign = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSize > FieldAlign &&
- (Context.hasSameType(FD->getType(),
- Context.UnsignedLongLongTy)
- ||Context.hasSameType(FD->getType(),
- Context.LongLongTy)))
- FieldAlign = TypeSize;
- FieldInfo = Context.getTypeInfo(LastFD->getType());
- uint64_t TypeSizeLastFD = FieldInfo.first;
- unsigned FieldAlignLastFD = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSizeLastFD > FieldAlignLastFD &&
- (Context.hasSameType(LastFD->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(LastFD->getType(),
- Context.LongLongTy)))
- FieldAlignLastFD = TypeSizeLastFD;
-
- if (TypeSizeLastFD != TypeSize) {
- if (RemainingInAlignment &&
- LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(Context)) {
- // If previous field was a bitfield with some remaining unfilled
- // bits, pad the field so current field starts on its type boundary.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- RemainingInAlignment = 0;
- }
-
- uint64_t UnpaddedFieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
-
- // The maximum field alignment overrides the aligned attribute.
- if (!MaxFieldAlignment.isZero()) {
- unsigned MaxFieldAlignmentInBits =
- Context.toBits(MaxFieldAlignment);
- FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
- }
-
- uint64_t NewSizeInBits =
- llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
- if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
- if (RemainingInAlignment < FieldSize)
- RemainingInAlignment = TypeSize - FieldSize;
- else
- RemainingInAlignment -= FieldSize;
- }
- }
- else if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- RemainingInAlignment = TypeSize - FieldSize;
- }
- LastFD = FD;
- }
- else if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
- Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
- if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
- ZeroLengthBitfield = *Field;
- }
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
LayoutField(*Field);
- }
- if (IsMsStruct && RemainingInAlignment &&
- LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {
- // If we ended a bitfield before the full length of the type then
- // pad the struct out to the full length of the last type.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1878,10 +1410,11 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
uint64_t FieldOffset;
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
if (IsUnion) {
setDataSize(std::max(getDataSizeInBits(), FieldSize));
@@ -1896,7 +1429,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
}
// Place this field at the current location.
@@ -1914,49 +1447,43 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidthValue(Context);
-
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
-
- // This check is needed for 'long long' in -m32 mode.
- if (IsMsStruct && (TypeSize > FieldAlign) &&
- (Context.hasSameType(D->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(D->getType(), Context.LongLongTy)))
- FieldAlign = TypeSize;
- if (ZeroLengthBitfield) {
- std::pair<uint64_t, unsigned> FieldInfo;
- unsigned ZeroLengthBitfieldAlignment;
- if (IsMsStruct) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and 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.
- if (ZeroLengthBitfield != D) {
- FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType());
- ZeroLengthBitfieldAlignment = FieldInfo.second;
- // Ignore alignment of subsequent zero-length bitfields.
- if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
- FieldAlign = ZeroLengthBitfieldAlignment;
- if (FieldSize)
- ZeroLengthBitfield = 0;
- }
- } else {
- // The alignment of a zero-length bitfield affects the alignment
- // of the next member. The alignment is the max of the zero
- // length bitfield's alignment and a target specific fixed value.
- unsigned ZeroLengthBitfieldBoundary =
- Context.getTargetInfo().getZeroLengthBitfieldBoundary();
- if (ZeroLengthBitfieldBoundary > FieldAlign)
- FieldAlign = ZeroLengthBitfieldBoundary;
+ if (IsMsStruct) {
+ // The field alignment for integer types in ms_struct structs is
+ // always the size.
+ FieldAlign = TypeSize;
+ // Ignore zero-length bitfields after non-bitfields in ms_struct structs.
+ if (!FieldSize && !LastBitfieldTypeSize)
+ FieldAlign = 1;
+ // If a bitfield is followed by a bitfield of a different size, don't
+ // pack the bits together in ms_struct structs.
+ if (LastBitfieldTypeSize != TypeSize) {
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
}
}
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
+ uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
+
+ bool ZeroLengthBitfield = false;
+ if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
+ Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ FieldSize == 0) {
+ // The alignment of a zero-length bitfield affects the alignment
+ // of the next member. The alignment is the max of the zero
+ // length bitfield's alignment and a target specific fixed value.
+ ZeroLengthBitfield = true;
+ unsigned ZeroLengthBitfieldBoundary =
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary();
+ if (ZeroLengthBitfieldBoundary > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldBoundary;
+ }
+
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
@@ -1982,6 +1509,13 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
+ // ms_struct bitfields always have to start at a round alignment.
+ if (IsMsStruct && !LastBitfieldTypeSize) {
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ }
+
// Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() &&
@@ -1996,12 +1530,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// Padding members don't affect overall alignment, unless zero length bitfield
// alignment is enabled.
- if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment())
+ if (!D->getIdentifier() &&
+ !Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ !IsMsStruct)
FieldAlign = UnpackedFieldAlign = 1;
- if (!IsMsStruct)
- ZeroLengthBitfield = 0;
-
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
@@ -2017,11 +1550,29 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// FIXME: I think FieldSize should be TypeSize here.
setDataSize(std::max(getDataSizeInBits(), FieldSize));
} else {
- uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ if (IsMsStruct && FieldSize) {
+ // Under ms_struct, a bitfield always takes up space equal to the size
+ // of the type. We can't just change the alignment computation on the
+ // other codepath because of the way this interacts with #pragma pack:
+ // in a packed struct, we need to allocate misaligned space in the
+ // struct to hold the bitfield.
+ if (!UnfilledBitsInLastUnit) {
+ setDataSize(FieldOffset + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else if (UnfilledBitsInLastUnit < FieldSize) {
+ setDataSize(getDataSizeInBits() + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else {
+ UnfilledBitsInLastUnit -= FieldSize;
+ }
+ LastBitfieldTypeSize = TypeSize;
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+ uint64_t BitfieldAlignment = Context.getTargetInfo().getCharAlign();
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, BitfieldAlignment));
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
+ LastBitfieldTypeSize = 0;
+ }
}
// Update the size.
@@ -2038,10 +1589,11 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
return;
}
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
// Reset the unfilled bits.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
CharUnits FieldOffset =
@@ -2069,30 +1621,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
- if (ZeroLengthBitfield) {
- CharUnits ZeroLengthBitfieldBoundary =
- Context.toCharUnitsFromBits(
- Context.getTargetInfo().getZeroLengthBitfieldBoundary());
- if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and 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.
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
- CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
- if (ZeroLengthBitfieldAlignment > FieldAlign)
- FieldAlign = ZeroLengthBitfieldAlignment;
- } else if (ZeroLengthBitfieldBoundary > FieldAlign) {
- // Align 'bar' based on a fixed alignment specified by the target.
- assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
- "ZeroLengthBitfieldBoundary should only be used in conjunction"
- " with useZeroLengthBitfieldAlignment.");
- FieldAlign = ZeroLengthBitfieldBoundary;
- }
- ZeroLengthBitfield = 0;
- }
-
if (IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -2189,7 +1717,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Finally, round the size of the record up to the alignment of the
// record itself.
- uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
@@ -2209,13 +1737,6 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
return;
}
-
- // MSVC doesn't round up to the alignment of the record with virtual bases.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (isMicrosoftCXXABI() && RD->getNumVBases())
- return;
- }
-
// Set the size to the final size.
setSize(RoundedSize);
@@ -2354,7 +1875,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
// A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
- if (RD->getLinkage() != ExternalLinkage)
+ if (!RD->isExternallyVisible())
return 0;
// Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
@@ -2453,6 +1974,732 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
llvm_unreachable("bad tail-padding use kind");
}
+static bool isMsLayout(const RecordDecl* D) {
+ return D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft();
+}
+
+// This section contains an implementation of struct layout that is, up to the
+// included tests, compatible with cl.exe (2012). The layout produced is
+// significantly different than those produced by the Itanium ABI. Here we note
+// the most important differences.
+//
+// * The alignment of bitfields in unions is ignored when computing the
+// alignment of the union.
+// * The existance of zero-width bitfield that occurs after anything other than
+// a non-zero length bitfield is ignored.
+// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
+// function pointer) and a vbptr (virtual base pointer). They can each be
+// shared with a, non-virtual bases. These bases need not be the same. vfptrs
+// always occur at offset 0. vbptrs can occur at an
+// arbitrary offset and are placed after non-virtual bases but before fields.
+// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
+// the virtual base and is used in conjunction with virtual overrides during
+// construction and destruction.
+// * vfptrs are allocated in a block of memory equal to the alignment of the
+// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer
+// sized block of memory in 64 bit mode.
+// * vbptrs are allocated in a block of memory equal to the alignment of the
+// fields and non-virtual bases. This block is at a potentially unaligned
+// offset. If the allocation slot is unaligned and the alignment is less than
+// or equal to the pointer size, additional space is allocated so that the
+// pointer can be aligned properly. This causes very strange effects on the
+// placement of objects after the allocated block. (see the code).
+// * vtordisps are allocated in a block of memory with size and alignment equal
+// to the alignment of the completed structure (before applying __declspec(
+// align())). The vtordisp always occur at the end of the allocation block,
+// immediately prior to the virtual base.
+// * The last zero sized non-virtual base is allocated after the placement of
+// vbptr if one exists and can be placed at the end of the struct, potentially
+// aliasing either the first member or another struct allocated after this
+// one.
+// * The last zero size virtual base may be placed at the end of the struct.
+// and can potentially alias a zero sized type in the next struct.
+// * If the last field is a non-zero length bitfield and we have any virtual
+// bases then some extra padding is added before the virtual bases for no
+// obvious reason.
+// * When laying out empty non-virtual bases, an extra byte of padding is added
+// if the non-virtual base before the empty non-virtual base has a vbptr.
+
+
+namespace {
+struct MicrosoftRecordLayoutBuilder {
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
+ MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
+private:
+ MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &)
+ LLVM_DELETED_FUNCTION;
+ void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+public:
+
+ void layout(const RecordDecl *RD);
+ void cxxLayout(const CXXRecordDecl *RD);
+ /// \brief Initializes size and alignment and honors some flags.
+ void initializeLayout(const RecordDecl *RD);
+ /// \brief Initialized C++ layout, compute alignment and virtual alignment and
+ /// existance of vfptrs and vbptrs. Alignment is needed before the vfptr is
+ /// laid out.
+ void initializeCXXLayout(const CXXRecordDecl *RD);
+ void layoutVFPtr(const CXXRecordDecl *RD);
+ void layoutNonVirtualBases(const CXXRecordDecl *RD);
+ void layoutNonVirtualBase(const CXXRecordDecl *RD);
+ void layoutVBPtr(const CXXRecordDecl *RD);
+ /// \brief Lays out the fields of the record. Also rounds size up to
+ /// alignment.
+ void layoutFields(const RecordDecl *RD);
+ void layoutField(const FieldDecl *FD);
+ void layoutBitField(const FieldDecl *FD);
+ /// \brief Lays out a single zero-width bit-field in the record and handles
+ /// special cases associated with zero-width bit-fields.
+ void layoutZeroWidthBitField(const FieldDecl *FD);
+ void layoutVirtualBases(const CXXRecordDecl *RD);
+ void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp);
+ /// \brief Flushes the lazy virtual base and conditionally rounds up to
+ /// alignment.
+ void finalizeCXXLayout(const CXXRecordDecl *RD);
+ void honorDeclspecAlign(const RecordDecl *RD);
+
+ /// \brief Updates the alignment of the type. This function doesn't take any
+ /// properties (such as packedness) into account. getAdjustedFieldInfo()
+ /// adjustes for packedness.
+ void updateAlignment(CharUnits NewAlignment) {
+ Alignment = std::max(Alignment, NewAlignment);
+ }
+ /// \brief Gets the size and alignment taking attributes into account.
+ std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
+ /// \brief Places a field at offset 0.
+ void placeFieldAtZero() { FieldOffsets.push_back(0); }
+ /// \brief Places a field at an offset in CharUnits.
+ void placeFieldAtOffset(CharUnits FieldOffset) {
+ FieldOffsets.push_back(Context.toBits(FieldOffset));
+ }
+ /// \brief Places a bitfield at a bit offset.
+ void placeFieldAtBitOffset(uint64_t FieldOffset) {
+ FieldOffsets.push_back(FieldOffset);
+ }
+ /// \brief Compute the set of virtual bases for which vtordisps are required.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2>
+ computeVtorDispSet(const CXXRecordDecl *RD);
+
+ const ASTContext &Context;
+ /// \brief The size of the record being laid out.
+ CharUnits Size;
+ /// \brief The current alignment of the record layout.
+ CharUnits Alignment;
+ /// \brief The collection of field offsets.
+ SmallVector<uint64_t, 16> FieldOffsets;
+ /// \brief The maximum allowed field alignment. This is set by #pragma pack.
+ CharUnits MaxFieldAlignment;
+ /// \brief Alignment does not occur for virtual bases unless something
+ /// forces it to by explicitly using __declspec(align())
+ bool AlignAfterVBases : 1;
+ bool IsUnion : 1;
+ /// \brief True if the last field laid out was a bitfield and was not 0
+ /// width.
+ bool LastFieldIsNonZeroWidthBitfield : 1;
+ /// \brief The size of the allocation of the currently active bitfield.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield
+ /// is true.
+ CharUnits CurrentBitfieldSize;
+ /// \brief The number of remaining bits in our last bitfield allocation.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
+ /// true.
+ unsigned RemainingBitsInField;
+
+ /// \brief The data alignment of the record layout.
+ CharUnits DataSize;
+ /// \brief The alignment of the non-virtual portion of the record layout
+ /// without the impact of the virtual pointers.
+ /// Only used for C++ layouts.
+ CharUnits BasesAndFieldsAlignment;
+ /// \brief The alignment of the non-virtual portion of the record layout
+ /// Only used for C++ layouts.
+ CharUnits NonVirtualAlignment;
+ /// \brief The additional alignment imposed by the virtual bases.
+ CharUnits VirtualAlignment;
+ /// \brief The primary base class (if one exists).
+ const CXXRecordDecl *PrimaryBase;
+ /// \brief The class we share our vb-pointer with.
+ const CXXRecordDecl *SharedVBPtrBase;
+ /// \brief True if the class has a vftable pointer that can be extended
+ /// by this class or classes derived from it. Such a vfptr will always occur
+ /// at offset 0.
+ bool HasExtendableVFPtr : 1;
+ /// \brief True if the class has a (not necessarily its own) vbtable pointer.
+ bool HasVBPtr : 1;
+ /// \brief Offset to the virtual base table pointer (if one exists).
+ CharUnits VBPtrOffset;
+ /// \brief Base classes and their offsets in the record.
+ BaseOffsetsMapTy Bases;
+ /// \brief virtual base classes and their offsets in the record.
+ ASTRecordLayout::VBaseOffsetsMapTy VBases;
+ /// \brief The size of a pointer.
+ CharUnits PointerSize;
+ /// \brief The alignment of a pointer.
+ CharUnits PointerAlignment;
+ /// \brief Holds an empty base we haven't yet laid out.
+ const CXXRecordDecl *LazyEmptyBase;
+ /// \brief Lets us know if the last base we laid out was empty. Only used
+ /// when adjusting the placement of a last zero-sized base in 64 bit mode.
+ bool LastBaseWasEmpty;
+ /// \brief Lets us know if we're in 64-bit mode
+ bool Is64BitMode;
+ /// \brief True if the last non-virtual base has a vbptr.
+ bool LastNonVirtualBaseHasVBPtr;
+};
+} // namespace
+
+std::pair<CharUnits, CharUnits>
+MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+
+ // If we're not on win32 and using ms_struct the field alignment will be wrong
+ // for 64 bit types, so we fix that here.
+ if (FD->getASTContext().getTargetInfo().getTriple().getOS() !=
+ llvm::Triple::Win32) {
+ QualType T = Context.getBaseElementType(FD->getType());
+ if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
+ CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
+ if (TypeSize > FieldInfo.second)
+ FieldInfo.second = TypeSize;
+ }
+ }
+
+ // Respect packed attribute.
+ if (FD->hasAttr<PackedAttr>())
+ FieldInfo.second = CharUnits::One();
+ // Respect pack pragma.
+ else if (!MaxFieldAlignment.isZero())
+ FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment);
+ // Respect alignment attributes.
+ if (unsigned fieldAlign = FD->getMaxAlignment()) {
+ CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign);
+ AlignAfterVBases = true;
+ FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
+ }
+ return FieldInfo;
+}
+
+void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
+ IsUnion = RD->isUnion();
+ Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
+
+ Size = CharUnits::Zero();
+ Alignment = CharUnits::One();
+ AlignAfterVBases = false;
+
+ // Compute the maximum field alignment.
+ MaxFieldAlignment = CharUnits::Zero();
+ // Honor the default struct packing maximum alignment flag.
+ if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
+ MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
+ // Honor the packing attribute.
+ if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>())
+ MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
+ // Packed attribute forces max field alignment to be 1.
+ if (RD->hasAttr<PackedAttr>())
+ MaxFieldAlignment = CharUnits::One();
+}
+
+void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
+ initializeLayout(RD);
+ layoutFields(RD);
+ honorDeclspecAlign(RD);
+}
+
+void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
+ initializeLayout(RD);
+ initializeCXXLayout(RD);
+ layoutVFPtr(RD);
+ layoutNonVirtualBases(RD);
+ layoutVBPtr(RD);
+ layoutFields(RD);
+ DataSize = Size;
+ NonVirtualAlignment = Alignment;
+ layoutVirtualBases(RD);
+ finalizeCXXLayout(RD);
+ honorDeclspecAlign(RD);
+}
+
+void
+MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
+ // Calculate pointer size and alignment.
+ PointerSize =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ PointerAlignment = PointerSize;
+ if (!MaxFieldAlignment.isZero())
+ PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment);
+
+ // Initialize information about the bases.
+ HasVBPtr = false;
+ HasExtendableVFPtr = false;
+ SharedVBPtrBase = 0;
+ PrimaryBase = 0;
+ VirtualAlignment = CharUnits::One();
+ AlignAfterVBases = Is64BitMode;
+
+ // If the record has a dynamic base class, attempt to choose a primary base
+ // class. It is the first (in direct base class order) non-virtual dynamic
+ // base class, if one exists.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ // Handle forced alignment.
+ if (Layout.getAlignAfterVBases())
+ AlignAfterVBases = true;
+ // Handle virtual bases.
+ if (i->isVirtual()) {
+ VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment());
+ HasVBPtr = true;
+ continue;
+ }
+ // We located a primary base class!
+ if (!PrimaryBase && Layout.hasExtendableVFPtr()) {
+ PrimaryBase = BaseDecl;
+ HasExtendableVFPtr = true;
+ }
+ // We located a base to share a VBPtr with!
+ if (!SharedVBPtrBase && Layout.hasVBPtr()) {
+ SharedVBPtrBase = BaseDecl;
+ HasVBPtr = true;
+ }
+ updateAlignment(Layout.getAlignment());
+ }
+
+ // Use LayoutFields to compute the alignment of the fields. The layout
+ // is discarded. This is the simplest way to get all of the bit-field
+ // behavior correct and is not actually very expensive.
+ layoutFields(RD);
+ Size = CharUnits::Zero();
+ BasesAndFieldsAlignment = Alignment;
+ FieldOffsets.clear();
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) {
+ // If we have a primary base then our VFPtr was already laid out
+ if (PrimaryBase)
+ return;
+
+ // Look at all of our methods to determine if we need a VFPtr. We need a
+ // vfptr if we define a new virtual function.
+ if (!HasExtendableVFPtr && RD->isDynamicClass())
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end();
+ !HasExtendableVFPtr && i != e; ++i)
+ HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
+ if (!HasExtendableVFPtr)
+ return;
+
+ // MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving
+ // it the max alignment of all the non-virtual data in the class. The
+ // resulting layout is essentially { vftbl, { nvdata } }. This is completely
+ // unnecessary, but we're not here to pass judgment.
+ updateAlignment(PointerAlignment);
+ if (Is64BitMode)
+ Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize;
+ else
+ Size = Size.RoundUpToAlignment(PointerAlignment) + Alignment;
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
+ LazyEmptyBase = 0;
+ LastBaseWasEmpty = false;
+ LastNonVirtualBaseHasVBPtr = false;
+
+ // Lay out the primary base first.
+ if (PrimaryBase)
+ layoutNonVirtualBase(PrimaryBase);
+
+ // Iterate through the bases and lay out the non-virtual ones.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ if (i->isVirtual())
+ continue;
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
+ if (BaseDecl != PrimaryBase)
+ layoutNonVirtualBase(BaseDecl);
+ }
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
+ const ASTRecordLayout *Layout = RD ? &Context.getASTRecordLayout(RD) : 0;
+
+ // If we have a lazy empty base we haven't laid out yet, do that now.
+ if (LazyEmptyBase) {
+ const ASTRecordLayout &LazyLayout =
+ Context.getASTRecordLayout(LazyEmptyBase);
+ Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ // If the last non-virtual base has a vbptr we add a byte of padding for no
+ // obvious reason.
+ if (LastNonVirtualBaseHasVBPtr)
+ Size++;
+ Bases.insert(std::make_pair(LazyEmptyBase, Size));
+ // Empty bases only consume space when followed by another empty base.
+ if (RD && Layout->getNonVirtualSize().isZero()) {
+ LastBaseWasEmpty = true;
+ Size++;
+ }
+ LazyEmptyBase = 0;
+ LastNonVirtualBaseHasVBPtr = false;
+ }
+
+ // RD is null when flushing the final lazy base.
+ if (!RD)
+ return;
+
+ if (Layout->getNonVirtualSize().isZero()) {
+ LazyEmptyBase = RD;
+ return;
+ }
+
+ // Insert the base here.
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment());
+ Bases.insert(std::make_pair(RD, BaseOffset));
+ Size = BaseOffset + Layout->getDataSize();
+ // Note: we don't update alignment here because it was accounted
+ // for during initalization.
+ LastBaseWasEmpty = false;
+ LastNonVirtualBaseHasVBPtr = Layout->hasVBPtr();
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ VBPtrOffset = CharUnits::fromQuantity(-1);
+ else if (SharedVBPtrBase) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
+ VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
+ } else {
+ VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
+ CharUnits OldSize = Size;
+ Size = VBPtrOffset + PointerSize;
+ if (BasesAndFieldsAlignment <= PointerAlignment) {
+ // Handle strange padding rules for the lazily placed base. I have no
+ // explanation for why the last virtual base is padded in such an odd way.
+ // Two things to note about this padding are that the rules are different
+ // if the alignment of the bases+fields is <= to the alignemnt of a
+ // pointer and that the rule in 64-bit mode behaves differently depending
+ // on if the second to last base was also zero sized.
+ Size += OldSize % BasesAndFieldsAlignment.getQuantity();
+ } else {
+ if (Is64BitMode)
+ Size += LastBaseWasEmpty ? CharUnits::One() : CharUnits::Zero();
+ else
+ Size = OldSize + BasesAndFieldsAlignment;
+ }
+ updateAlignment(PointerAlignment);
+ }
+
+ // Flush the lazy empty base.
+ layoutNonVirtualBase(0);
+}
+
+void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
+ LastFieldIsNonZeroWidthBitfield = false;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field)
+ layoutField(*Field);
+ Size = Size.RoundUpToAlignment(Alignment);
+}
+
+void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
+ if (FD->isBitField()) {
+ layoutBitField(FD);
+ return;
+ }
+ LastFieldIsNonZeroWidthBitfield = false;
+
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ updateAlignment(FieldAlign);
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ } else {
+ // Round up the current record size to the field's alignment boundary.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset + FieldSize;
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
+ unsigned Width = FD->getBitWidthValue(Context);
+ if (Width == 0) {
+ layoutZeroWidthBitField(FD);
+ return;
+ }
+
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ // Clamp the bitfield to a containable size for the sake of being able
+ // to lay them out. Sema will throw an error.
+ if (Width > Context.toBits(FieldSize))
+ Width = Context.toBits(FieldSize);
+
+ // Check to see if this bitfield fits into an existing allocation. Note:
+ // MSVC refuses to pack bitfields of formal types with different sizes
+ // into the same allocation.
+ if (!IsUnion && LastFieldIsNonZeroWidthBitfield &&
+ CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) {
+ placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
+ RemainingBitsInField -= Width;
+ return;
+ }
+
+ LastFieldIsNonZeroWidthBitfield = true;
+ CurrentBitfieldSize = FieldSize;
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
+ } else {
+ // Allocate a new block of memory and place the bitfield in it.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset + FieldSize;
+ updateAlignment(FieldAlign);
+ RemainingBitsInField = Context.toBits(FieldSize) - Width;
+ }
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
+ // Zero-width bitfields are ignored unless they follow a non-zero-width
+ // bitfield.
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ if (!LastFieldIsNonZeroWidthBitfield) {
+ placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size);
+ // TODO: Add a Sema warning that MS ignores alignment for zero
+ // sized bitfields that occur after zero-size bitfields or non bitfields.
+ return;
+ }
+
+ LastFieldIsNonZeroWidthBitfield = false;
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ } else {
+ // Round up the current record size to the field's alignment boundary.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset;
+ updateAlignment(FieldAlign);
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ return;
+
+ updateAlignment(VirtualAlignment);
+
+ // Zero-sized v-bases obey the alignment attribute so apply it here. The
+ // alignment attribute is normally accounted for in FinalizeLayout.
+ if (unsigned MaxAlign = RD->getMaxAlignment())
+ updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
+
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp =
+ computeVtorDispSet(RD);
+
+ // If the last field we laid out was a non-zero length bitfield then add some
+ // extra padding for no obvious reason.
+ if (LastFieldIsNonZeroWidthBitfield)
+ Size += CurrentBitfieldSize;
+
+ // Iterate through the virtual bases and lay them out.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
+ e = RD->vbases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
+ layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl));
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
+ bool HasVtordisp) {
+ if (LazyEmptyBase) {
+ const ASTRecordLayout &LazyLayout =
+ Context.getASTRecordLayout(LazyEmptyBase);
+ Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ VBases.insert(
+ std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false)));
+ // Empty bases only consume space when followed by another empty base.
+ // The space consumed is in an Alignment sized/aligned block and the v-base
+ // is placed at its alignment offset into the chunk, unless its alignment
+ // is less than 4 bytes, at which it is placed at 4 byte offset in the
+ // chunk. We have no idea why.
+ if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero())
+ Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
+ LazyEmptyBase = 0;
+ }
+
+ // RD is null when flushing the final lazy virtual base.
+ if (!RD)
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ if (Layout.getNonVirtualSize().isZero() && !HasVtordisp) {
+ LazyEmptyBase = RD;
+ return;
+ }
+
+ CharUnits BaseNVSize = Layout.getNonVirtualSize();
+ CharUnits BaseAlign = Layout.getAlignment();
+
+ // vtordisps are always 4 bytes (even in 64-bit mode)
+ if (HasVtordisp)
+ Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
+ Size = Size.RoundUpToAlignment(BaseAlign);
+
+ // Insert the base here.
+ CharUnits BaseOffset = Size.RoundUpToAlignment(BaseAlign);
+ VBases.insert(
+ std::make_pair(RD, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
+ Size = BaseOffset + BaseNVSize;
+ // Note: we don't update alignment here because it was accounted for in
+ // InitializeLayout.
+}
+
+void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
+ // Flush the lazy virtual base.
+ layoutVirtualBase(0, false);
+
+ if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases)
+ Size = Size.RoundUpToAlignment(Alignment);
+
+ if (Size.isZero())
+ Size = Alignment;
+}
+
+void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) {
+ if (unsigned MaxAlign = RD->getMaxAlignment()) {
+ AlignAfterVBases = true;
+ updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
+ Size = Size.RoundUpToAlignment(Alignment);
+ }
+}
+
+static bool
+RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
+ const CXXRecordDecl *RD) {
+ if (HasVtordisp.count(RD))
+ return true;
+ // If any of a virtual bases non-virtual bases (recursively) requires a
+ // vtordisp than so does this virtual base.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i)
+ if (!i->isVirtual() &&
+ RequiresVtordisp(
+ HasVtordisp,
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl())))
+ return true;
+ return false;
+}
+
+llvm::SmallPtrSet<const CXXRecordDecl *, 2>
+MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp;
+
+ // If any of our bases need a vtordisp for this type, so do we. Check our
+ // direct bases for vtordisp requirements.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
+ bi = Layout.getVBaseOffsetsMap().begin(),
+ be = Layout.getVBaseOffsetsMap().end();
+ bi != be; ++bi)
+ if (bi->second.hasVtorDisp())
+ HasVtordisp.insert(bi->first);
+ }
+
+ // If we define a constructor or destructor and override a function that is
+ // defined in a virtual base's vtable, that virtual bases need a vtordisp.
+ // Here we collect a list of classes with vtables for which our virtual bases
+ // actually live. The virtual bases with this property will require
+ // vtordisps. In addition, virtual bases that contain non-virtual bases that
+ // define functions we override also require vtordisps, this case is checked
+ // explicitly below.
+ if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) {
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
+ // Seed the working set with our non-destructor virtual methods.
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end();
+ i != e; ++i)
+ if ((*i)->isVirtual() && !isa<CXXDestructorDecl>(*i))
+ Work.insert(*i);
+ while (!Work.empty()) {
+ const CXXMethodDecl *MD = *Work.begin();
+ CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods();
+ if (i == e)
+ // If a virtual method has no-overrides it lives in its parent's vtable.
+ HasVtordisp.insert(MD->getParent());
+ else
+ Work.insert(i, e);
+ // We've finished processing this element, remove it from the working set.
+ Work.erase(MD);
+ }
+ }
+
+ // Re-check all of our vbases for vtordisp requirements (in case their
+ // non-virtual bases have vtordisp requirements).
+ for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
+ e = RD->vbases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
+ if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl))
+ HasVtordisp.insert(BaseDecl);
+ }
+
+ return HasVtordisp;
+}
+
+/// \brief Get or compute information about the layout of the specified record
+/// (struct/union/class), which indicates its size and field position
+/// information.
+const ASTRecordLayout *
+ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
+ MicrosoftRecordLayoutBuilder Builder(*this);
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ Builder.cxxLayout(RD);
+ return new (*this) ASTRecordLayout(
+ *this, Builder.Size, Builder.Alignment,
+ Builder.HasExtendableVFPtr && !Builder.PrimaryBase,
+ Builder.HasExtendableVFPtr,
+ Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(), Builder.DataSize,
+ Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
+ false, Builder.SharedVBPtrBase, Builder.AlignAfterVBases, Builder.Bases,
+ Builder.VBases);
+ } else {
+ Builder.layout(D);
+ return new (*this) ASTRecordLayout(
+ *this, Builder.Size, Builder.Alignment, Builder.Size,
+ Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
+ }
+}
+
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@@ -2468,6 +2715,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
+ assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!");
assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
// Look up this layout, if already laid out, return what we have.
@@ -2476,27 +2724,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
const ASTRecordLayout *Entry = ASTRecordLayouts[D];
if (Entry) return *Entry;
- const ASTRecordLayout *NewEntry;
+ const ASTRecordLayout *NewEntry = 0;
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (isMsLayout(D) && !D->getASTContext().getExternalSource()) {
+ NewEntry = BuildMicrosoftASTRecordLayout(D);
+ } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
RecordLayoutBuilder Builder(*this, &EmptySubobjects);
Builder.Layout(RD);
- // MSVC gives the vb-table pointer an alignment equal to that of
- // the non-virtual part of the structure. That's an inherently
- // multi-pass operation. If our first pass doesn't give us
- // adequate alignment, try again with the specified minimum
- // alignment. This is *much* more maintainable than computing the
- // alignment in advance in a separately-coded pass; it's also
- // significantly more efficient in the common case where the
- // vb-table doesn't need extra padding.
- if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) &&
- (Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) {
- Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment);
- Builder.Layout(RD);
- }
-
// In certain situations, we are allowed to lay out objects in the
// tail-padding of base classes. This is ABI-dependent.
// FIXME: this should be stored in the record layout.
@@ -2508,12 +2744,12 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
skipTailPadding ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
skipTailPadding ? DataSize : Builder.NonVirtualSize;
-
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
Builder.HasOwnVFPtr,
- Builder.VBPtrOffset,
+ RD->isDynamicClass(),
+ CharUnits::fromQuantity(-1),
DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
@@ -2522,6 +2758,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
+ 0, true,
Builder.Bases, Builder.VBases);
} else {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
@@ -2538,43 +2775,45 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
ASTRecordLayouts[D] = NewEntry;
if (getLangOpts().DumpRecordLayouts) {
- llvm::errs() << "\n*** Dumping AST Record Layout\n";
- DumpRecordLayout(D, llvm::errs(), getLangOpts().DumpRecordLayoutsSimple);
+ llvm::outs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::outs(), getLangOpts().DumpRecordLayoutsSimple);
}
return *NewEntry;
}
const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+ if (!getTargetInfo().getCXXABI().hasKeyFunctions())
+ return 0;
+
assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- const CXXMethodDecl *&entry = KeyFunctions[RD];
- if (!entry) {
- entry = computeKeyFunction(*this, RD);
- }
+ LazyDeclPtr &Entry = KeyFunctions[RD];
+ if (!Entry)
+ Entry = const_cast<CXXMethodDecl*>(computeKeyFunction(*this, RD));
- return entry;
+ return cast_or_null<CXXMethodDecl>(Entry.get(getExternalSource()));
}
-void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
- assert(method == method->getFirstDeclaration() &&
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
+ assert(Method == Method->getFirstDecl() &&
"not working with method declaration from class definition");
// Look up the cache entry. Since we're working with the first
// declaration, its parent must be the class definition, which is
// the correct key for the KeyFunctions hash.
- llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
- i = KeyFunctions.find(method->getParent());
+ llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator
+ I = KeyFunctions.find(Method->getParent());
// If it's not cached, there's nothing to do.
- if (i == KeyFunctions.end()) return;
+ if (I == KeyFunctions.end()) return;
// If it is cached, check whether it's the target method, and if so,
// remove it from the cache.
- if (i->second == method) {
+ if (I->second.get(getExternalSource()) == Method) {
// FIXME: remember that we did this for module / chained PCH state?
- KeyFunctions.erase(i);
+ KeyFunctions.erase(I);
}
}
@@ -2676,16 +2915,19 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- bool HasVfptr = Layout.hasOwnVFPtr();
- bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
+ bool HasOwnVFPtr = Layout.hasOwnVFPtr();
+ bool HasOwnVBPtr = Layout.hasOwnVBPtr();
// Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase &&
- !C.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (RD->isDynamicClass() && !PrimaryBase && !isMsLayout(RD)) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
+ } else if (HasOwnVFPtr) {
+ PrintOffset(OS, Offset, IndentLevel);
+ // vfptr (for Microsoft C++ ABI)
+ OS << '(' << *RD << " vftable pointer)\n";
}
-
+
// Dump (non-virtual) bases
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
@@ -2704,12 +2946,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
/*IncludeVirtualBases=*/false);
}
- // vfptr and vbptr (for Microsoft C++ ABI)
- if (HasVfptr) {
- PrintOffset(OS, Offset, IndentLevel);
- OS << '(' << *RD << " vftable pointer)\n";
- }
- if (HasVbptr) {
+ // vbptr (for Microsoft C++ ABI)
+ if (HasOwnVBPtr) {
PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
OS << '(' << *RD << " vbtable pointer)\n";
}
@@ -2762,7 +3000,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << "[sizeof=" << Layout.getSize().getQuantity();
- OS << ", dsize=" << Layout.getDataSize().getQuantity();
+ if (!isMsLayout(RD))
+ OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
PrintIndentNoOffset(OS, IndentLevel - 1);
@@ -2789,7 +3028,8 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
- OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
+ if (!isMsLayout(RD))
+ OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 5b29c073f928..de851615cb7a 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
@@ -48,16 +49,11 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
return StmtClassInfo[E];
}
-void *Stmt::operator new(size_t bytes, ASTContext& C,
- unsigned alignment) throw() {
+void *Stmt::operator new(size_t bytes, const ASTContext& C,
+ unsigned alignment) {
return ::operator new(bytes, C, alignment);
}
-void *Stmt::operator new(size_t bytes, ASTContext* C,
- unsigned alignment) throw() {
- return ::operator new(bytes, *C, alignment);
-}
-
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
@@ -139,6 +135,7 @@ namespace {
template <class T> good implements_children(children_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_children(children_t Stmt::*) {
return bad();
}
@@ -147,6 +144,7 @@ namespace {
template <class T> good implements_getLocStart(getLocStart_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_getLocStart(getLocStart_t Stmt::*) {
return bad();
}
@@ -155,20 +153,22 @@ namespace {
template <class T> good implements_getLocEnd(getLocEnd_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) {
return bad();
}
#define ASSERT_IMPLEMENTS_children(type) \
- (void) sizeof(is_good(implements_children(&type::children)))
+ (void) is_good(implements_children(&type::children))
#define ASSERT_IMPLEMENTS_getLocStart(type) \
- (void) sizeof(is_good(implements_getLocStart(&type::getLocStart)))
+ (void) is_good(implements_getLocStart(&type::getLocStart))
#define ASSERT_IMPLEMENTS_getLocEnd(type) \
- (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd)))
+ (void) is_good(implements_getLocEnd(&type::getLocEnd))
}
/// Check whether the various Stmt classes implement their member
/// functions.
+LLVM_ATTRIBUTE_UNUSED
static inline void check_implementations() {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
@@ -252,7 +252,7 @@ SourceLocation Stmt::getLocEnd() const {
llvm_unreachable("unknown statement kind");
}
-CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
+CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
CompoundStmtBits.NumStmts = Stmts.size();
@@ -268,7 +268,8 @@ CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
std::copy(Stmts.begin(), Stmts.end(), Body);
}
-void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
+void CompoundStmt::setStmts(const ASTContext &C, Stmt **Stmts,
+ unsigned NumStmts) {
if (this->Body)
C.Deallocate(Body);
this->CompoundStmtBits.NumStmts = NumStmts;
@@ -281,7 +282,7 @@ const char *LabelStmt::getName() const {
return getDecl()->getIdentifier()->getNameStart();
}
-AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc,
+AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
ArrayRef<const Attr*> Attrs,
Stmt *SubStmt) {
void *Mem = C.Allocate(sizeof(AttributedStmt) +
@@ -290,7 +291,8 @@ AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc,
return new (Mem) AttributedStmt(Loc, Attrs, SubStmt);
}
-AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
+AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C,
+ unsigned NumAttrs) {
assert(NumAttrs > 0 && "NumAttrs should be greater than zero");
void *Mem = C.Allocate(sizeof(AttributedStmt) +
sizeof(Attr*) * (NumAttrs - 1),
@@ -298,29 +300,7 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
-bool Stmt::hasImplicitControlFlow() const {
- switch (StmtBits.sClass) {
- default:
- return false;
-
- case CallExprClass:
- case ConditionalOperatorClass:
- case ChooseExprClass:
- case StmtExprClass:
- case DeclStmtClass:
- return true;
-
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator* B = cast<BinaryOperator>(this);
- if (B->isLogicalOp() || B->getOpcode() == BO_Comma)
- return true;
- else
- return false;
- }
- }
-}
-
-std::string AsmStmt::generateAsmString(ASTContext &C) const {
+std::string AsmStmt::generateAsmString(const ASTContext &C) const {
if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
return gccAsmStmt->generateAsmString(C);
if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
@@ -406,14 +386,14 @@ StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
return getInputConstraintLiteral(i)->getString();
}
-void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
- IdentifierInfo **Names,
- StringLiteral **Constraints,
- Stmt **Exprs,
- unsigned NumOutputs,
- unsigned NumInputs,
- StringLiteral **Clobbers,
- unsigned NumClobbers) {
+void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
+ IdentifierInfo **Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ StringLiteral **Clobbers,
+ unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
this->NumClobbers = NumClobbers;
@@ -461,7 +441,7 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
- ASTContext &C, unsigned &DiagOffs) const {
+ const ASTContext &C, unsigned &DiagOffs) const {
StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
const char *StrEnd = Str.end();
@@ -599,7 +579,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
}
/// Assemble final IR asm string (GCC-style).
-std::string GCCAsmStmt::generateAsmString(ASTContext &C) const {
+std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const {
// Analyze the asm string to decompose it into its pieces. We know that Sema
// has already done this, so it is guaranteed to be successful.
SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces;
@@ -620,7 +600,7 @@ std::string GCCAsmStmt::generateAsmString(ASTContext &C) const {
}
/// Assemble final IR asm string (MS-style).
-std::string MSAsmStmt::generateAsmString(ASTContext &C) const {
+std::string MSAsmStmt::generateAsmString(const ASTContext &C) const {
// FIXME: This needs to be translated into the IR string representation.
return AsmStr;
}
@@ -646,12 +626,12 @@ QualType CXXCatchStmt::getCaughtType() const {
// Constructors
//===----------------------------------------------------------------------===//
-GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
- bool isvolatile, unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints,
- Expr **exprs, StringLiteral *asmstr,
- unsigned numclobbers, StringLiteral **clobbers,
- SourceLocation rparenloc)
+GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
+ bool issimple, bool isvolatile, unsigned numoutputs,
+ unsigned numinputs, IdentifierInfo **names,
+ StringLiteral **constraints, Expr **exprs,
+ StringLiteral *asmstr, unsigned numclobbers,
+ StringLiteral **clobbers, SourceLocation rparenloc)
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
@@ -670,7 +650,7 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
}
-MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
+MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
SourceLocation lbraceloc, bool issimple, bool isvolatile,
ArrayRef<Token> asmtoks, unsigned numoutputs,
unsigned numinputs,
@@ -684,15 +664,14 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
}
-static StringRef copyIntoContext(ASTContext &C, StringRef str) {
+static StringRef copyIntoContext(const ASTContext &C, StringRef str) {
size_t size = str.size();
char *buffer = new (C) char[size];
memcpy(buffer, str.data(), size);
return StringRef(buffer, size);
}
-void MSAsmStmt::initialize(ASTContext &C,
- StringRef asmstr,
+void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr,
ArrayRef<Token> asmtoks,
ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs,
@@ -731,7 +710,7 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
SourceLocation RPL)
: Stmt(ObjCForCollectionStmtClass) {
SubExprs[ELEM] = Elem;
- SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
+ SubExprs[COLLECTION] = Collect;
SubExprs[BODY] = Body;
ForLoc = FCL;
RParenLoc = RPL;
@@ -752,7 +731,7 @@ ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
Stmts[NumCatchStmts + 1] = atFinallyStmt;
}
-ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
+ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context,
SourceLocation atTryLoc,
Stmt *atTryStmt,
Stmt **CatchStmts,
@@ -765,9 +744,9 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
atFinallyStmt);
}
-ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
- unsigned NumCatchStmts,
- bool HasFinally) {
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(const ASTContext &Context,
+ unsigned NumCatchStmts,
+ bool HasFinally) {
unsigned Size = sizeof(ObjCAtTryStmt) +
(1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
@@ -782,7 +761,7 @@ SourceLocation ObjCAtTryStmt::getLocEnd() const {
return getTryBody()->getLocEnd();
}
-CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
+CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc,
Stmt *tryBlock, ArrayRef<Stmt*> handlers) {
std::size_t Size = sizeof(CXXTryStmt);
Size += ((handlers.size() + 1) * sizeof(Stmt));
@@ -791,7 +770,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
}
-CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
+CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty,
unsigned numHandlers) {
std::size_t Size = sizeof(CXXTryStmt);
Size += ((numHandlers + 1) * sizeof(Stmt));
@@ -815,8 +794,8 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
: Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
SubExprs[RANGE] = Range;
SubExprs[BEGINEND] = BeginEndStmt;
- SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
- SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[COND] = Cond;
+ SubExprs[INC] = Inc;
SubExprs[LOOPVAR] = LoopVar;
SubExprs[BODY] = Body;
}
@@ -842,12 +821,12 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const {
return const_cast<CXXForRangeStmt*>(this)->getLoopVariable();
}
-IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
+IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL, Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
{
setConditionVariable(C, var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[THEN] = then;
SubExprs[ELSE] = elsev;
}
@@ -860,7 +839,7 @@ VarDecl *IfStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -871,15 +850,15 @@ void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
VarRange.getEnd());
}
-ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
+ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP)
: Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP)
{
SubExprs[INIT] = Init;
setConditionVariable(C, condVar);
- SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
- SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[COND] = Cond;
+ SubExprs[INC] = Inc;
SubExprs[BODY] = Body;
}
@@ -891,7 +870,7 @@ VarDecl *ForStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[CONDVAR] = 0;
return;
@@ -902,11 +881,11 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
VarRange.getEnd());
}
-SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond)
+SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
: Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0)
{
setConditionVariable(C, Var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[BODY] = NULL;
}
@@ -918,7 +897,7 @@ VarDecl *SwitchStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void SwitchStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -935,11 +914,11 @@ Stmt *SwitchCase::getSubStmt() {
return cast<DefaultStmt>(this)->getSubStmt();
}
-WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
+WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
: Stmt(WhileStmtClass) {
setConditionVariable(C, Var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[BODY] = body;
WhileLoc = WL;
}
@@ -952,7 +931,7 @@ VarDecl *WhileStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -991,10 +970,8 @@ SEHTryStmt::SEHTryStmt(bool IsCXXTry,
Children[HANDLER] = Handler;
}
-SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
- bool IsCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
+SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
+ SourceLocation TryLoc, Stmt *TryBlock,
Stmt *Handler) {
return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
}
@@ -1013,14 +990,12 @@ SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
: Stmt(SEHExceptStmtClass),
Loc(Loc)
{
- Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+ Children[FILTER_EXPR] = FilterExpr;
Children[BLOCK] = Block;
}
-SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
- SourceLocation Loc,
- Expr *FilterExpr,
- Stmt *Block) {
+SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc,
+ Expr *FilterExpr, Stmt *Block) {
return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
}
@@ -1031,8 +1006,7 @@ SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
Block(Block)
{}
-SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
- SourceLocation Loc,
+SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc,
Stmt *Block) {
return new(C)SEHFinallyStmt(Loc,Block);
}
@@ -1079,7 +1053,7 @@ CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
getStoredStmts()[NumCaptures] = 0;
}
-CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
+CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S,
CapturedRegionKind Kind,
ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
@@ -1107,7 +1081,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
}
-CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
+CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context,
unsigned NumCaptures) {
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumCaptures > 0) {
@@ -1128,7 +1102,7 @@ Stmt::child_range CapturedStmt::children() {
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
for (const_capture_iterator I = capture_begin(),
E = capture_end(); I != E; ++I) {
- if (I->capturesThis())
+ if (!I->capturesVariable())
continue;
// This does not handle variable redeclarations. This should be
@@ -1140,3 +1114,107 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
return false;
}
+
+StmtRange OMPClause::children() {
+ switch(getClauseKind()) {
+ default : break;
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_ ## Name : return static_cast<Class *>(this)->children();
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("unknown OMPClause");
+}
+
+OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPPrivateClause>());
+ OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc,
+ EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPPrivateClause>());
+ return new (Mem) OMPPrivateClause(N);
+}
+
+OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) +
+ sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPFirstprivateClause>());
+ OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
+ LParenLoc,
+ EndLoc,
+ VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPFirstprivateClause>());
+ return new (Mem) OMPFirstprivateClause(N);
+}
+
+OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPSharedClause>());
+ OMPSharedClause *Clause = new (Mem) OMPSharedClause(StartLoc, LParenLoc,
+ EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPSharedClause>());
+ return new (Mem) OMPSharedClause(N);
+}
+
+void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
+ assert(Clauses.size() == this->Clauses.size() &&
+ "Number of clauses is not the same as the preallocated buffer");
+ std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin());
+}
+
+OMPParallelDirective *OMPParallelDirective::Create(
+ const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
+ sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *),
+ llvm::alignOf<OMPParallelDirective>());
+ OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc,
+ Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
+ unsigned N,
+ EmptyShell) {
+ void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
+ sizeof(OMPClause *) * N + sizeof(Stmt *),
+ llvm::alignOf<OMPParallelDirective>());
+ return new (Mem) OMPParallelDirective(N);
+}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 9bf4aeaae83e..6e85375ed22f 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -40,14 +40,7 @@ void StmtIteratorBase::NextVA() {
if (p)
return;
- if (inDecl()) {
- if (VarDecl* VD = dyn_cast<VarDecl>(decl))
- if (VD->Init)
- return;
-
- NextDecl();
- }
- else if (inDeclGroup()) {
+ if (inDeclGroup()) {
if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
if (VD->Init)
return;
@@ -55,40 +48,26 @@ void StmtIteratorBase::NextVA() {
NextDecl();
}
else {
- assert (inSizeOfTypeVA());
- assert(!decl);
+ assert(inSizeOfTypeVA());
RawVAPtr = 0;
}
}
void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
assert (getVAPtr() == NULL);
+ assert(inDeclGroup());
- if (inDecl()) {
- assert(decl);
+ if (ImmediateAdvance)
+ ++DGI;
- // FIXME: SIMPLIFY AWAY.
- if (ImmediateAdvance)
- decl = 0;
- else if (HandleDecl(decl))
+ for ( ; DGI != DGE; ++DGI)
+ if (HandleDecl(*DGI))
return;
- }
- else {
- assert(inDeclGroup());
-
- if (ImmediateAdvance)
- ++DGI;
-
- for ( ; DGI != DGE; ++DGI)
- if (HandleDecl(*DGI))
- return;
- }
RawVAPtr = 0;
}
bool StmtIteratorBase::HandleDecl(Decl* D) {
-
if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
if (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
setVAPtr(VAPtr);
@@ -113,43 +92,23 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
return false;
}
-StmtIteratorBase::StmtIteratorBase(Decl *d, Stmt **s)
- : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) {
- if (decl)
- NextDecl(false);
-}
-
StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
: stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
NextDecl(false);
}
StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t)
- : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) {
+ : stmt(0), DGI(0), RawVAPtr(SizeOfTypeVAMode) {
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
}
Stmt*& StmtIteratorBase::GetDeclExpr() const {
-
if (const VariableArrayType* VAPtr = getVAPtr()) {
assert (VAPtr->SizeExpr);
return const_cast<Stmt*&>(VAPtr->SizeExpr);
}
- assert (inDecl() || inDeclGroup());
-
- if (inDeclGroup()) {
- VarDecl* VD = cast<VarDecl>(*DGI);
- return *VD->getInitAddress();
- }
-
- assert (inDecl());
-
- if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
- assert (VD->Init);
- return *VD->getInitAddress();
- }
-
- EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl);
- return ECD->Init;
+ assert (inDeclGroup());
+ VarDecl* VD = cast<VarDecl>(*DGI);
+ return *VD->getInitAddress();
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 9203dc1584bb..0ecb5b52c24f 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -580,6 +580,87 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
}
//===----------------------------------------------------------------------===//
+// OpenMP clauses printing methods
+//===----------------------------------------------------------------------===//
+
+namespace {
+class OMPClausePrinter : public OMPClauseVisitor<OMPClausePrinter> {
+ raw_ostream &OS;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node, char StartSym);
+public:
+ OMPClausePrinter(raw_ostream &OS) : OS(OS) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
+ OS << "default("
+ << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind())
+ << ")";
+}
+
+template<typename T>
+void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
+ for (typename T::varlist_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ OS << (I == Node->varlist_begin() ? StartSym : ',')
+ << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+}
+
+void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "private";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "firstprivate";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "shared";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP directives printing methods
+//===----------------------------------------------------------------------===//
+
+void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
+ Indent() << "#pragma omp parallel ";
+
+ OMPClausePrinter Printer(OS);
+ ArrayRef<OMPClause *> Clauses = Node->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (*I && !(*I)->isImplicit()) {
+ Printer.Visit(*I);
+ OS << ' ';
+ }
+ OS << "\n";
+ if (Node->getAssociatedStmt()) {
+ assert(isa<CapturedStmt>(Node->getAssociatedStmt()) &&
+ "Expected captured statement!");
+ Stmt *CS = cast<CapturedStmt>(Node->getAssociatedStmt())->getCapturedStmt();
+ PrintStmt(CS);
+ }
+}
+//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -657,6 +738,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::Function:
OS << "__FUNCTION__";
break;
+ case PredefinedExpr::FuncDName:
+ OS << "__FUNCDNAME__";
+ break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
@@ -1019,6 +1103,14 @@ void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) {
+ OS << "__builtin_convertvector(";
+ PrintExpr(Node->getSrcExpr());
+ OS << ", ";
+ Node->getType().print(OS, Policy);
+ OS << ")";
+}
+
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
if (Node->getSyntacticForm()) {
Visit(Node->getSyntacticForm());
@@ -1226,7 +1318,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
- Node->getTypeOperand().print(OS, Policy);
+ Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1236,7 +1328,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
- Node->getTypeOperand().print(OS, Policy);
+ Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1339,6 +1431,8 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
Arg != ArgEnd; ++Arg) {
+ if (Arg->isDefaultArgument())
+ break;
if (Arg != Node->arg_begin())
OS << ", ";
PrintExpr(*Arg);
@@ -1377,17 +1471,18 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
break;
case LCK_ByRef:
- if (Node->getCaptureDefault() != LCD_ByRef)
+ if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture())
OS << '&';
OS << C->getCapturedVar()->getName();
break;
case LCK_ByCopy:
- if (Node->getCaptureDefault() != LCD_ByCopy)
- OS << '=';
OS << C->getCapturedVar()->getName();
break;
}
+
+ if (C->isInitCapture())
+ PrintExpr(C->getCapturedVar()->getInit());
}
OS << ']';
@@ -1525,6 +1620,10 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
OS << " }";
}
+void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ PrintExpr(E->getSubExpr());
+}
+
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
// Just forward to the sub expression.
PrintExpr(E->getSubExpr());
@@ -1616,6 +1715,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsReference: return "__is_reference";
case UTT_IsRvalueReference: return "__is_rvalue_reference";
case UTT_IsScalar: return "__is_scalar";
+ case UTT_IsSealed: return "__is_sealed";
case UTT_IsSigned: return "__is_signed";
case UTT_IsStandardLayout: return "__is_standard_layout";
case UTT_IsTrivial: return "__is_trivial";
@@ -1886,7 +1986,7 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
// Stmt method implementations
//===----------------------------------------------------------------------===//
-void Stmt::dumpPretty(ASTContext &Context) const {
+void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), 0, PrintingPolicy(Context.getLangOpts()));
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 8ade242d56d9..6805e62befb0 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -252,6 +252,52 @@ StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) {
VisitStmt(S);
}
+namespace {
+class OMPClauseProfiler : public ConstOMPClauseVisitor<OMPClauseProfiler> {
+ StmtProfiler *Profiler;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
+public:
+ OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(const Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
+
+template<typename T>
+void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_const_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ Profiler->VisitStmt(*I);
+}
+
+void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPFirstprivateClause(
+ const OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+}
+}
+
+void
+StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
+ VisitStmt(S);
+ OMPClauseProfiler P(this);
+ ArrayRef<OMPClause *> Clauses = S->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (*I)
+ P.Visit(*I);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
@@ -417,6 +463,10 @@ void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) {
VisitExpr(S);
}
@@ -758,16 +808,21 @@ void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
- VisitType(S->getTypeOperand());
+ VisitType(S->getTypeOperandSourceInfo()->getType());
}
void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
- VisitType(S->getTypeOperand());
+ VisitType(S->getTypeOperandSourceInfo()->getType());
}
void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) {
@@ -822,9 +877,14 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
ID.AddInteger(C->getCaptureKind());
- if (C->capturesVariable()) {
+ switch (C->getCaptureKind()) {
+ case LCK_This:
+ break;
+ case LCK_ByRef:
+ case LCK_ByCopy:
VisitDecl(C->getCapturedVar());
ID.AddBoolean(C->isPackExpansion());
+ break;
}
}
// Note: If we actually needed to be able to match lambda
@@ -863,7 +923,14 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
- VisitType(S->getDestroyedType());
+ ID.AddBoolean(S->getScopeTypeInfo() != 0);
+ if (S->getScopeTypeInfo())
+ VisitType(S->getScopeTypeInfo()->getType());
+ ID.AddBoolean(S->getDestroyedTypeInfo() != 0);
+ if (S->getDestroyedTypeInfo())
+ VisitType(S->getDestroyedType());
+ else
+ ID.AddPointer(S->getDestroyedTypeIdentifier());
}
void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index d68b95edb730..16efb790b68e 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -55,8 +55,8 @@ static void printIntegral(const TemplateArgument &TemplArg,
//===----------------------------------------------------------------------===//
TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
- QualType Type)
- : Kind(Integral) {
+ QualType Type) {
+ Integer.Kind = Integral;
// Copy the APSInt value into our decomposed form.
Integer.BitWidth = Value.getBitWidth();
Integer.IsUnsigned = Value.isUnsigned();
@@ -225,7 +225,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
}
Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
- assert(Kind == TemplateExpansion);
+ assert(getKind() == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
@@ -234,8 +234,8 @@ Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context) const {
- ID.AddInteger(Kind);
- switch (Kind) {
+ ID.AddInteger(getKind());
+ switch (getKind()) {
case Null:
break;
@@ -243,6 +243,10 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
getAsType().Profile(ID);
break;
+ case NullPtr:
+ getNullPtrType().Profile(ID);
+ break;
+
case Declaration:
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
@@ -291,7 +295,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
case Template:
case TemplateExpansion:
case NullPtr:
- return TypeOrValue == Other.TypeOrValue;
+ return TypeOrValue.V == Other.TypeOrValue.V;
case Declaration:
return getAsDecl() == Other.getAsDecl() &&
@@ -353,9 +357,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Declaration: {
NamedDecl *ND = cast<NamedDecl>(getAsDecl());
+ Out << '&';
if (ND->getDeclName()) {
// FIXME: distinguish between pointer and reference args?
- Out << *ND;
+ ND->printQualifiedName(Out);
} else {
Out << "<anonymous>";
}
@@ -449,68 +454,6 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern(
- SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions,
- ASTContext &Context) const {
- assert(Argument.isPackExpansion());
-
- switch (Argument.getKind()) {
- case TemplateArgument::Type: {
- // FIXME: We shouldn't ever have to worry about missing
- // type-source info!
- TypeSourceInfo *ExpansionTSInfo = getTypeSourceInfo();
- if (!ExpansionTSInfo)
- ExpansionTSInfo = Context.getTrivialTypeSourceInfo(
- getArgument().getAsType(),
- Ellipsis);
- PackExpansionTypeLoc Expansion =
- ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
- Ellipsis = Expansion.getEllipsisLoc();
-
- TypeLoc Pattern = Expansion.getPatternLoc();
- NumExpansions = Expansion.getTypePtr()->getNumExpansions();
-
- // FIXME: This is horrible. We know where the source location data is for
- // the pattern, and we have the pattern's type, but we are forced to copy
- // them into an ASTContext because TypeSourceInfo bundles them together
- // and TemplateArgumentLoc traffics in TypeSourceInfo pointers.
- TypeSourceInfo *PatternTSInfo
- = Context.CreateTypeSourceInfo(Pattern.getType(),
- Pattern.getFullDataSize());
- memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(),
- Pattern.getOpaqueData(), Pattern.getFullDataSize());
- return TemplateArgumentLoc(TemplateArgument(Pattern.getType()),
- PatternTSInfo);
- }
-
- case TemplateArgument::Expression: {
- PackExpansionExpr *Expansion
- = cast<PackExpansionExpr>(Argument.getAsExpr());
- Expr *Pattern = Expansion->getPattern();
- Ellipsis = Expansion->getEllipsisLoc();
- NumExpansions = Expansion->getNumExpansions();
- return TemplateArgumentLoc(Pattern, Pattern);
- }
-
- case TemplateArgument::TemplateExpansion:
- Ellipsis = getTemplateEllipsisLoc();
- NumExpansions = Argument.getNumTemplateExpansions();
- return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
- getTemplateQualifierLoc(),
- getTemplateNameLoc());
-
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Template:
- case TemplateArgument::Integral:
- case TemplateArgument::Pack:
- case TemplateArgument::Null:
- return TemplateArgumentLoc();
- }
-
- llvm_unreachable("Invalid TemplateArgument Kind!");
-}
-
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const TemplateArgument &Arg) {
switch (Arg.getKind()) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index fa16facb634f..7421bae7bf54 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -93,7 +93,7 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 &&
(NumElements.getZExtValue() >> 32) == 0) {
uint64_t TotalSize = NumElements.getZExtValue() * ElementSize;
- return 64 - llvm::CountLeadingZeros_64(TotalSize);
+ return 64 - llvm::countLeadingZeros(TotalSize);
}
// Otherwise, use APSInt to handle arbitrary sized values.
@@ -111,11 +111,12 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) {
unsigned Bits = Context.getTypeSize(Context.getSizeType());
- // GCC appears to only allow 63 bits worth of address space when compiling
- // for 64-bit, so we do the same.
- if (Bits == 64)
- --Bits;
-
+ // Limit the number of bits in size_t so that maximal bit size fits 64 bit
+ // integer (see PR8256). We can do this as currently there is no hardware
+ // that supports full 64-bit virtual space.
+ if (Bits > 61)
+ Bits = 61;
+
return Bits;
}
@@ -337,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const {
return getAsSugar<TemplateSpecializationType>(this);
}
+template <> const AttributedType *Type::getAs() const {
+ return getAsSugar<AttributedType>(this);
+}
+
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
/// sugar off the given type. This should produce an object of the
/// same dynamic type as the canonical type.
@@ -357,23 +362,6 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
}
}
-
-bool Type::isDerivedType() const {
- switch (CanonicalType->getTypeClass()) {
- case Pointer:
- case VariableArray:
- case ConstantArray:
- case IncompleteArray:
- case FunctionProto:
- case FunctionNoProto:
- case LValueReference:
- case RValueReference:
- case Record:
- return true;
- default:
- return false;
- }
-}
bool Type::isClassType() const {
if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isClass();
@@ -750,9 +738,9 @@ bool Type::isSignedIntegerOrEnumerationType() const {
bool Type::hasSignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
- return VT->getElementType()->isSignedIntegerType();
+ return VT->getElementType()->isSignedIntegerOrEnumerationType();
else
- return isSignedIntegerType();
+ return isSignedIntegerOrEnumerationType();
}
/// isUnsignedIntegerType - Return true if this is an integer type that is
@@ -790,9 +778,9 @@ bool Type::isUnsignedIntegerOrEnumerationType() const {
bool Type::hasUnsignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
- return VT->getElementType()->isUnsignedIntegerType();
+ return VT->getElementType()->isUnsignedIntegerOrEnumerationType();
else
- return isUnsignedIntegerType();
+ return isUnsignedIntegerOrEnumerationType();
}
bool Type::isFloatingType() const {
@@ -1109,15 +1097,18 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
}
}
- // C++0x [basic.types]p9
+ // C++11 [basic.types]p9
// Scalar types, trivially copyable class types, arrays of such types, and
- // cv-qualified versions of these types are collectively called trivial
- // types.
+ // non-volatile const-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())
@@ -1142,7 +1133,7 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
-bool Type::isLiteralType(ASTContext &Ctx) const {
+bool Type::isLiteralType(const ASTContext &Ctx) const {
if (isDependentType())
return false;
@@ -1196,6 +1187,15 @@ bool Type::isLiteralType(ASTContext &Ctx) const {
return true;
}
+ // We treat _Atomic T as a literal type if T is a literal type.
+ if (const AtomicType *AT = BaseTy->getAs<AtomicType>())
+ return AT->getValueType()->isLiteralType(Ctx);
+
+ // If this type hasn't been deduced yet, then conservatively assume that
+ // it'll work out to be a literal type.
+ if (isa<AutoType>(BaseTy->getCanonicalTypeInternal()))
+ return true;
+
return false;
}
@@ -1521,7 +1521,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Double: return "double";
case LongDouble: return "long double";
case WChar_S:
- case WChar_U: return "wchar_t";
+ case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t";
case Char16: return "char16_t";
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
@@ -1548,7 +1548,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
llvm_unreachable("Invalid builtin type.");
}
-QualType QualType::getNonLValueExprType(ASTContext &Context) const {
+QualType QualType::getNonLValueExprType(const ASTContext &Context) const {
if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
return RefType->getPointeeType();
@@ -1566,14 +1566,13 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const {
StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
- case CC_Default:
- llvm_unreachable("no name for default cc");
-
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
case CC_X86FastCall: return "fastcall";
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
+ case CC_X86_64Win64: return "ms_abi";
+ case CC_X86_64SysV: return "sysv_abi";
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
case CC_PnaclCall: return "pnaclcall";
@@ -1664,7 +1663,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
}
FunctionProtoType::NoexceptResult
-FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const {
+FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
ExceptionSpecificationType est = getExceptionSpecType();
if (est == EST_BasicNoexcept)
return NR_Nothrow;
@@ -1849,6 +1848,49 @@ bool TagType::isBeingDefined() const {
return getDecl()->isBeingDefined();
}
+bool AttributedType::isMSTypeSpec() const {
+ switch (getAttrKind()) {
+ default: return false;
+ case attr_ptr32:
+ case attr_ptr64:
+ case attr_sptr:
+ case attr_uptr:
+ return true;
+ }
+ llvm_unreachable("invalid attr kind");
+}
+
+bool AttributedType::isCallingConv() const {
+ switch (getAttrKind()) {
+ case attr_ptr32:
+ case attr_ptr64:
+ case attr_sptr:
+ case attr_uptr:
+ case attr_address_space:
+ case attr_regparm:
+ case attr_vector_size:
+ case attr_neon_vector_type:
+ case attr_neon_polyvector_type:
+ case attr_objc_gc:
+ case attr_objc_ownership:
+ case attr_noreturn:
+ return false;
+ case attr_pcs:
+ case attr_pcs_vfp:
+ case attr_cdecl:
+ case attr_fastcall:
+ case attr_stdcall:
+ case attr_thiscall:
+ case attr_pascal:
+ case attr_ms_abi:
+ case attr_sysv_abi:
+ case attr_pnaclcall:
+ case attr_inteloclbicc:
+ return true;
+ }
+ llvm_unreachable("invalid attr kind");
+}
+
CXXRecordDecl *InjectedClassNameType::getDecl() const {
return cast<CXXRecordDecl>(getInterestingTagDecl(Decl));
}
@@ -1908,7 +1950,8 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N,
return false;
}
-bool TemplateSpecializationType::
+#ifndef NDEBUG
+static bool
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
bool &InstantiationDependent) {
for (unsigned i = 0; i != N; ++i) {
@@ -1922,6 +1965,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
}
return false;
}
+#endif
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
@@ -1945,8 +1989,8 @@ TemplateSpecializationType(TemplateName T,
(void)InstantiationDependent;
assert((!Canon.isNull() ||
T.isDependent() ||
- anyDependentTemplateArguments(Args, NumArgs,
- InstantiationDependent)) &&
+ ::anyDependentTemplateArguments(Args, NumArgs,
+ InstantiationDependent)) &&
"No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
@@ -2124,7 +2168,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- Linkage L = Tag->getLinkage();
+ Linkage L = Tag->getLinkageInternal();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
!Tag->hasNameForLinkage();
@@ -2166,7 +2210,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage();
+ Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkageInternal();
return CachedProperties(L, false);
}
case Type::ObjCObject:
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 03d40309f53a..22a51bc345ac 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -41,12 +41,30 @@ SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
}
namespace {
+ class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> {
+ public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return TyLoc.getLocalDataAlignment(); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+/// \brief Returns the alignment of the type source info data block.
+unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) {
+ if (Ty.isNull()) return 1;
+ return TypeAligner().Visit(TypeLoc(Ty, 0));
+}
+
+namespace {
class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
public:
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getFullDataSize(); \
+ return TyLoc.getLocalDataSize(); \
}
#include "clang/AST/TypeLocNodes.def"
};
@@ -54,8 +72,18 @@ namespace {
/// \brief Returns the size of the type source info data block.
unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
- if (Ty.isNull()) return 0;
- return TypeSizer().Visit(TypeLoc(Ty, 0));
+ unsigned Total = 0;
+ TypeLoc TyLoc(Ty, 0);
+ unsigned MaxAlign = 1;
+ while (!TyLoc.isNull()) {
+ unsigned Align = getLocalAlignmentForType(TyLoc.getType());
+ MaxAlign = std::max(Align, MaxAlign);
+ Total = llvm::RoundUpToAlignment(Total, Align);
+ Total += TypeSizer().Visit(TyLoc);
+ TyLoc = TyLoc.getNextTypeLoc();
+ }
+ Total = llvm::RoundUpToAlignment(Total, MaxAlign);
+ return Total;
}
namespace {
@@ -329,10 +357,13 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
for (unsigned i = 0, e = NumArgs; i != e; ++i) {
switch (Args[i].getKind()) {
case TemplateArgument::Null:
- case TemplateArgument::Declaration:
+ llvm_unreachable("Impossible TemplateArgument");
+
case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
- llvm_unreachable("Impossible TemplateArgument");
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
case TemplateArgument::Expression:
ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
@@ -347,18 +378,16 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Args[i].getAsTemplate();
+ TemplateName Template = Args[i].getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
-
+
ArgInfos[i] = TemplateArgumentLocInfo(
- Builder.getWithLocInContext(Context),
- Loc,
- Args[i].getKind() == TemplateArgument::Template
- ? SourceLocation()
- : Loc);
+ Builder.getWithLocInContext(Context), Loc,
+ Args[i].getKind() == TemplateArgument::Template ? SourceLocation()
+ : Loc);
break;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 043707622bd5..571e3db0289f 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -36,7 +36,8 @@ namespace {
public:
explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
: Policy(Policy), Old(Policy.SuppressStrongLifetime) {
- Policy.SuppressStrongLifetime = false;
+ if (!Policy.SuppressLifetimeQualifiers)
+ Policy.SuppressStrongLifetime = false;
}
~IncludeStrongLifetimeRAII() {
@@ -81,10 +82,11 @@ namespace {
class TypePrinter {
PrintingPolicy Policy;
bool HasEmptyPlaceHolder;
+ bool InsideCCAttribute;
public:
explicit TypePrinter(const PrintingPolicy &Policy)
- : Policy(Policy), HasEmptyPlaceHolder(false) { }
+ : Policy(Policy), HasEmptyPlaceHolder(false), InsideCCAttribute(false) { }
void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
StringRef PlaceHolder);
@@ -166,6 +168,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
TC = Subst->getReplacementType()->getTypeClass();
switch (TC) {
+ case Type::Auto:
case Type::Builtin:
case Type::Complex:
case Type::UnresolvedUsing:
@@ -201,6 +204,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
NeedARCStrongQualifier = true;
// Fall through
+ case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
case Type::LValueReference:
@@ -215,7 +219,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::Attributed:
case Type::PackExpansion:
case Type::SubstTemplateTypeParm:
- case Type::Auto:
CanPrefixQualifiers = false;
break;
}
@@ -468,6 +471,14 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T,
printAfter(T->getElementType(), OS);
}
+void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) {
+ // Print as though it's a pointer.
+ printBefore(T->getDecayedType(), OS);
+}
+void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) {
+ printAfter(T->getDecayedType(), OS);
+}
+
void TypePrinter::printDependentSizedArrayBefore(
const DependentSizedArrayType *T,
raw_ostream &OS) {
@@ -621,36 +632,51 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
OS << ')';
FunctionType::ExtInfo Info = T->getExtInfo();
- switch(Info.getCC()) {
- case CC_Default: break;
- case CC_C:
- OS << " __attribute__((cdecl))";
- break;
- case CC_X86StdCall:
- OS << " __attribute__((stdcall))";
- break;
- case CC_X86FastCall:
- OS << " __attribute__((fastcall))";
- break;
- case CC_X86ThisCall:
- OS << " __attribute__((thiscall))";
- break;
- case CC_X86Pascal:
- OS << " __attribute__((pascal))";
- break;
- case CC_AAPCS:
- OS << " __attribute__((pcs(\"aapcs\")))";
- break;
- case CC_AAPCS_VFP:
- OS << " __attribute__((pcs(\"aapcs-vfp\")))";
- break;
- case CC_PnaclCall:
- OS << " __attribute__((pnaclcall))";
- break;
- case CC_IntelOclBicc:
- OS << " __attribute__((intel_ocl_bicc))";
- break;
+
+ if (!InsideCCAttribute) {
+ switch (Info.getCC()) {
+ case CC_C:
+ // The C calling convention is the default on the vast majority of platforms
+ // we support. If the user wrote it explicitly, it will usually be printed
+ // while traversing the AttributedType. If the type has been desugared, let
+ // the canonical spelling be the implicit calling convention.
+ // FIXME: It would be better to be explicit in certain contexts, such as a
+ // cdecl function typedef used to declare a member function with the
+ // Microsoft C++ ABI.
+ break;
+ case CC_X86StdCall:
+ OS << " __attribute__((stdcall))";
+ break;
+ case CC_X86FastCall:
+ OS << " __attribute__((fastcall))";
+ break;
+ case CC_X86ThisCall:
+ OS << " __attribute__((thiscall))";
+ break;
+ case CC_X86Pascal:
+ OS << " __attribute__((pascal))";
+ break;
+ case CC_AAPCS:
+ OS << " __attribute__((pcs(\"aapcs\")))";
+ break;
+ case CC_AAPCS_VFP:
+ OS << " __attribute__((pcs(\"aapcs-vfp\")))";
+ break;
+ case CC_PnaclCall:
+ OS << " __attribute__((pnaclcall))";
+ break;
+ case CC_IntelOclBicc:
+ OS << " __attribute__((intel_ocl_bicc))";
+ break;
+ case CC_X86_64Win64:
+ OS << " __attribute__((ms_abi))";
+ break;
+ case CC_X86_64SysV:
+ OS << " __attribute__((sysv_abi))";
+ break;
+ }
}
+
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
if (Info.getRegParm())
@@ -989,6 +1015,8 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
raw_ostream &OS) {
+ if (Policy.SuppressTag && isa<TagType>(T->getNamedType()))
+ return;
OS << TypeWithKeyword::getKeywordName(T->getKeyword());
if (T->getKeyword() != ETK_None)
OS << " ";
@@ -1072,6 +1100,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
return printBefore(T->getEquivalentType(), OS);
printBefore(T->getModifiedType(), OS);
+
+ if (T->isMSTypeSpec()) {
+ switch (T->getAttrKind()) {
+ default: return;
+ case AttributedType::attr_ptr32: OS << " __ptr32"; break;
+ case AttributedType::attr_ptr64: OS << " __ptr64"; break;
+ case AttributedType::attr_sptr: OS << " __sptr"; break;
+ case AttributedType::attr_uptr: OS << " __uptr"; break;
+ }
+ spaceBeforePlaceHolder(OS);
+ }
}
void TypePrinter::printAttributedAfter(const AttributedType *T,
@@ -1082,8 +1121,18 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
return printAfter(T->getEquivalentType(), OS);
// TODO: not all attributes are GCC-style attributes.
+ if (T->isMSTypeSpec())
+ return;
+
+ // If this is a calling convention attribute, don't print the implicit CC from
+ // the modified type.
+ SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
+
+ printAfter(T->getModifiedType(), OS);
+
OS << " __attribute__((";
switch (T->getAttrKind()) {
+ default: llvm_unreachable("This attribute should have been handled already");
case AttributedType::attr_address_space:
OS << "address_space(";
OS << T->getEquivalentType().getAddressSpace();
@@ -1115,6 +1164,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
}
case AttributedType::attr_regparm: {
+ // FIXME: When Sema learns to form this AttributedType, avoid printing the
+ // attribute again in printFunctionProtoAfter.
OS << "regparm(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@@ -1154,13 +1205,19 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
+ // FIXME: When Sema learns to form this AttributedType, avoid printing the
+ // attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
+
case AttributedType::attr_cdecl: OS << "cdecl"; break;
case AttributedType::attr_fastcall: OS << "fastcall"; break;
case AttributedType::attr_stdcall: OS << "stdcall"; break;
case AttributedType::attr_thiscall: OS << "thiscall"; break;
case AttributedType::attr_pascal: OS << "pascal"; break;
- case AttributedType::attr_pcs: {
+ case AttributedType::attr_ms_abi: OS << "ms_abi"; break;
+ case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break;
+ case AttributedType::attr_pcs:
+ case AttributedType::attr_pcs_vfp: {
OS << "pcs(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@@ -1266,18 +1323,19 @@ TemplateSpecializationType::PrintTemplateArgumentList(
bool needSpace = false;
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg > 0)
- OS << ", ";
-
// Print the argument into a string.
SmallString<128> Buf;
llvm::raw_svector_ostream ArgOS(Buf);
if (Args[Arg].getKind() == TemplateArgument::Pack) {
+ if (Args[Arg].pack_size() && Arg > 0)
+ OS << ", ";
PrintTemplateArgumentList(ArgOS,
Args[Arg].pack_begin(),
Args[Arg].pack_size(),
Policy, true);
} else {
+ if (Arg > 0)
+ OS << ", ";
Args[Arg].print(Policy, ArgOS);
}
StringRef ArgString = ArgOS.str();
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index f80232f44c98..5f7ae0f3ff4a 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -34,7 +34,8 @@ struct BaseOffset {
const CXXRecordDecl *DerivedClass;
/// VirtualBase - If the path from the derived class to the base class
- /// involves a virtual base class, this holds its declaration.
+ /// involves virtual base classes, this holds the declaration of the last
+ /// virtual base in this path (i.e. closest to the base class).
const CXXRecordDecl *VirtualBase;
/// NonVirtualOffset - The offset from the derived class to the base class.
@@ -62,7 +63,7 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
- /// Offset - the base offset of the overrider in the layout class.
+ /// Offset - the base offset of the overrider's parent in the layout class.
CharUnits Offset;
OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
@@ -146,8 +147,6 @@ public:
};
-#define DUMP_OVERRIDERS 0
-
FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset,
const CXXRecordDecl *LayoutClass)
@@ -219,16 +218,14 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *VirtualBase = 0;
// First, look for the virtual base class.
- for (unsigned I = 0, E = Path.size(); I != E; ++I) {
- const CXXBasePathElement &Element = Path[I];
-
+ for (int I = Path.size(), E = 0; I != E; --I) {
+ const CXXBasePathElement &Element = Path[I - 1];
+
if (Element.Base->isVirtual()) {
- // FIXME: Can we break when we find the first virtual base?
- // (If we can't, can't we just iterate over the path in reverse order?)
- NonVirtualStart = I + 1;
+ NonVirtualStart = I;
QualType VBaseType = Element.Base->getType();
- VirtualBase =
- cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ VirtualBase = VBaseType->getAsCXXRecordDecl();
+ break;
}
}
@@ -239,8 +236,7 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
// Check the base class offset.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
- const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
- const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+ const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl();
NonVirtualOffset += Layout.getBaseClassOffset(Base);
}
@@ -343,8 +339,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
// Traverse our bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
CharUnits BaseOffset;
CharUnits BaseOffsetInLayoutClass;
@@ -381,8 +376,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Ignore bases that don't have any virtual member functions.
if (!BaseDecl->isPolymorphic())
@@ -418,7 +412,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
Out << " " << MD->getQualifiedNameAsString() << " - (";
Out << Overrider.Method->getQualifiedNameAsString();
- Out << ", " << ", " << Overrider.Offset.getQuantity() << ')';
+ Out << ", " << Overrider.Offset.getQuantity() << ')';
BaseOffset Offset;
if (!Overrider.Method->isPure())
@@ -727,8 +721,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
if (I->isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
if (BaseDecl == PrimaryBase)
continue;
@@ -750,8 +743,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
// Add vbase offsets.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Check if this is a virtual base that we haven't visited before.
if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
@@ -775,8 +767,8 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
}
}
-/// VTableBuilder - Class for building vtable layout information.
-class VTableBuilder {
+/// ItaniumVTableBuilder - Class for building vtable layout information.
+class ItaniumVTableBuilder {
public:
/// PrimaryBasesSetVectorTy - A set vector of direct and indirect
/// primary bases.
@@ -789,9 +781,11 @@ public:
typedef llvm::DenseMap<BaseSubobject, uint64_t>
AddressPointsMapTy;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
+
private:
/// VTables - Global vtable information.
- VTableContext &VTables;
+ ItaniumVTableContext &VTables;
/// MostDerivedClass - The most derived class for which we're building this
/// vtable.
@@ -861,7 +855,11 @@ private:
/// MethodInfoMap - The information for all methods in the vtable we're
/// currently building.
MethodInfoMapTy MethodInfoMap;
-
+
+ /// MethodVTableIndices - Contains the index (relative to the vtable address
+ /// point) where the function pointer for a virtual function is stored.
+ MethodVTableIndicesTy MethodVTableIndices;
+
typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
/// VTableThunks - The thunks by vtable index in the vtable currently being
@@ -984,24 +982,22 @@ private:
}
public:
- VTableBuilder(VTableContext &VTables, const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- bool MostDerivedClassIsVirtual, const
- CXXRecordDecl *LayoutClass)
- : VTables(VTables), MostDerivedClass(MostDerivedClass),
- MostDerivedClassOffset(MostDerivedClassOffset),
- MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
- LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
- Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+ ItaniumVTableBuilder(ItaniumVTableContext &VTables,
+ const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual,
+ const CXXRecordDecl *LayoutClass)
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassOffset(MostDerivedClassOffset),
+ MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
+ LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
+ Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+ assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
LayoutVTable();
if (Context.getLangOpts().DumpVTableLayouts)
- dumpLayout(llvm::errs());
- }
-
- bool isMicrosoftABI() const {
- return VTables.isMicrosoftABI();
+ dumpLayout(llvm::outs());
}
uint64_t getNumThunks() const {
@@ -1024,6 +1020,14 @@ public:
return AddressPoints;
}
+ MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
+ return MethodVTableIndices.begin();
+ }
+
+ MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
+ return MethodVTableIndices.end();
+ }
+
/// getNumVTableComponents - Return the number of components in the vtable
/// currently built.
uint64_t getNumVTableComponents() const {
@@ -1058,12 +1062,13 @@ public:
void dumpLayout(raw_ostream&);
};
-void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk) {
assert(!isBuildingConstructorVTable() &&
"Can't add thunks for construction vtable");
- SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
-
+ SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD];
+
// Check if we have this thunk already.
if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
ThunksVector.end())
@@ -1074,24 +1079,45 @@ void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
-/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
-/// the overridden methods that the function decl overrides.
-static void
-ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
- OverriddenMethodsSetTy& OverriddenMethods) {
+/// Visit all the methods overridden by the given method recursively,
+/// in a depth-first pre-order. The Visitor's visitor method returns a bool
+/// indicating whether to continue the recursion for the given overridden
+/// method (i.e. returning false stops the iteration).
+template <class VisitorTy>
+static void
+visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
assert(MD->isVirtual() && "Method is not virtual!");
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
E = MD->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
-
- OverriddenMethods.insert(OverriddenMD);
-
- ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
+ if (!Visitor.visit(OverriddenMD))
+ continue;
+ visitAllOverriddenMethods(OverriddenMD, Visitor);
}
}
-void VTableBuilder::ComputeThisAdjustments() {
+namespace {
+ struct OverriddenMethodsCollector {
+ OverriddenMethodsSetTy *Methods;
+
+ bool visit(const CXXMethodDecl *MD) {
+ // Don't recurse on this method if we've already collected it.
+ return Methods->insert(MD);
+ }
+ };
+}
+
+/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
+/// the overridden methods that the function decl overrides.
+static void
+ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
+ OverriddenMethodsSetTy& OverriddenMethods) {
+ OverriddenMethodsCollector Collector = { &OverriddenMethods };
+ visitAllOverriddenMethods(MD, Collector);
+}
+
+void ItaniumVTableBuilder::ComputeThisAdjustments() {
// Now go through the method info map and see if any of the methods need
// 'this' pointer adjustments.
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -1160,8 +1186,6 @@ void VTableBuilder::ComputeThisAdjustments() {
break;
case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
- // FIXME: check how this works in the Microsoft ABI
- // while working on the multiple inheritance patch.
continue;
}
@@ -1170,7 +1194,8 @@ void VTableBuilder::ComputeThisAdjustments() {
}
}
-ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment
+ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1178,10 +1203,10 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
// Get the virtual base offset offset.
if (Offset.DerivedClass == MostDerivedClass) {
// We can get the offset offset directly from our map.
- Adjustment.VBaseOffsetOffset =
+ Adjustment.Virtual.Itanium.VBaseOffsetOffset =
VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
} else {
- Adjustment.VBaseOffsetOffset =
+ Adjustment.Virtual.Itanium.VBaseOffsetOffset =
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
Offset.VirtualBase).getQuantity();
}
@@ -1193,9 +1218,8 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
return Adjustment;
}
-BaseOffset
-VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
- BaseSubobject Derived) const {
+BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
+ BaseSubobject Base, BaseSubobject Derived) const {
const CXXRecordDecl *BaseRD = Base.getBase();
const CXXRecordDecl *DerivedRD = Derived.getBase();
@@ -1240,11 +1264,10 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
return BaseOffset();
}
-
-ThisAdjustment
-VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
- CharUnits BaseOffsetInLayoutClass,
- FinalOverriders::OverriderInfo Overrider) {
+
+ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
+ const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider) {
// Ignore adjustments for pure virtual member functions.
if (Overrider.Method->isPure())
return ThisAdjustment();
@@ -1281,7 +1304,7 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
VCallOffsets = Builder.getVCallOffsets();
}
- Adjustment.VCallOffsetOffset =
+ Adjustment.Virtual.Itanium.VCallOffsetOffset =
VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
}
@@ -1290,23 +1313,16 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
return Adjustment;
}
-
-void
-VTableBuilder::AddMethod(const CXXMethodDecl *MD,
- ReturnAdjustment ReturnAdjustment) {
+
+void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
- // FIXME: Should probably add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VTableComponent::MakeCompleteDtor(DD));
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
- } else {
- // Add the scalar deleting destructor.
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
- }
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
@@ -1328,9 +1344,9 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
///
/// OverridesIndirectMethodInBase will return true if given C::f as the method
/// and { A } as the set of bases.
-static bool
-OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+static bool OverridesIndirectMethodInBases(
+ const CXXMethodDecl *MD,
+ ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) {
if (Bases.count(MD->getParent()))
return true;
@@ -1346,11 +1362,10 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
return false;
}
-bool
-VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
- CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass) const {
+bool ItaniumVTableBuilder::IsOverriderUsed(
+ const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass) const {
// If the base and the first base in the primary base chain have the same
// offsets, then this overrider will be used.
if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
@@ -1364,8 +1379,8 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
// that the overrider will be used.
if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
return true;
-
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+
+ ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
PrimaryBases.insert(RD);
@@ -1409,18 +1424,21 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
}
+typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy;
+
/// FindNearestOverriddenMethod - Given a method, returns the overridden method
/// from the nearest base. Returns null if no method was found.
-static const CXXMethodDecl *
+/// The Bases are expected to be sorted in a base-to-derived order.
+static const CXXMethodDecl *
FindNearestOverriddenMethod(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ BasesSetVectorTy &Bases) {
OverriddenMethodsSetTy OverriddenMethods;
ComputeAllOverriddenMethods(MD, OverriddenMethods);
for (int I = Bases.size(), E = 0; I != E; --I) {
const CXXRecordDecl *PrimaryBase = Bases[I - 1];
- // Now check the overriden methods.
+ // Now check the overridden methods.
for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
E = OverriddenMethods.end(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
@@ -1432,13 +1450,22 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
}
return 0;
-}
+}
+
+void ItaniumVTableBuilder::AddMethods(
+ BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass,
+ PrimaryBasesSetVectorTy &PrimaryBases) {
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
-void
-VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass,
- PrimaryBasesSetVectorTy &PrimaryBases) {
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -1476,6 +1503,11 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
llvm_unreachable("Found a duplicate primary base!");
}
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
+ NewVirtualFunctionsTy NewVirtualFunctions;
+
// Now go through all virtual member functions and add them.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
@@ -1520,7 +1552,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
Overrider);
- if (ThisAdjustment.VCallOffsetOffset &&
+ if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset &&
Overrider.Method->getParent() == MostDerivedClass) {
// There's no return adjustment from OverriddenMD and MD,
@@ -1541,6 +1573,33 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
}
}
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+ }
+
+ NewVirtualFunctions.push_back(MD);
+ }
+
+ if (ImplicitVirtualDtor)
+ NewVirtualFunctions.push_back(ImplicitVirtualDtor);
+
+ for (NewVirtualFunctionsTy::const_iterator I = NewVirtualFunctions.begin(),
+ E = NewVirtualFunctions.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, Base.getBaseOffset());
+
// Insert the method info for this method.
MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
Components.size());
@@ -1557,7 +1616,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
continue;
}
-
+
// Check if this overrider needs a return adjustment.
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
@@ -1573,7 +1632,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
}
}
-void VTableBuilder::LayoutVTable() {
+void ItaniumVTableBuilder::LayoutVTable() {
LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
CharUnits::Zero()),
/*BaseIsMorallyVirtual=*/false,
@@ -1594,12 +1653,10 @@ void VTableBuilder::LayoutVTable() {
if (IsAppleKext)
Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero()));
}
-
-void
-VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- bool BaseIsVirtualInLayoutClass,
- CharUnits OffsetInLayoutClass) {
+
+void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject Base, bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) {
assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
// Add vcall and vbase offsets for this vtable.
@@ -1621,18 +1678,12 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
- // FIXME: Should probably add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- // Add the offset to top.
- CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
- Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+ // Add the offset to top.
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
- // Next, add the RTTI.
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
- } else {
- // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
- // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
- }
+ // Next, add the RTTI.
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
uint64_t AddressPoint = Components.size();
@@ -1642,11 +1693,28 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
Base.getBase(), OffsetInLayoutClass,
PrimaryBases);
+ const CXXRecordDecl *RD = Base.getBase();
+ if (RD == MostDerivedClass) {
+ assert(MethodVTableIndices.empty());
+ for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
+ E = MethodInfoMap.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const MethodInfo &MI = I->second;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
+ = MI.VTableIndex - AddressPoint;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
+ = MI.VTableIndex + 1 - AddressPoint;
+ } else {
+ MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
+ }
+ }
+ }
+
// Compute 'this' pointer adjustments.
ComputeThisAdjustments();
// Add all address points.
- const CXXRecordDecl *RD = Base.getBase();
while (true) {
AddressPoints.insert(std::make_pair(
BaseSubobject(RD, OffsetInLayoutClass),
@@ -1678,9 +1746,10 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
}
-void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- CharUnits OffsetInLayoutClass) {
+void
+ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ CharUnits OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
// Following the primary virtual table of a derived class are secondary
// virtual tables for each of its proper base classes, except any primary
@@ -1696,8 +1765,7 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
if (I->isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Ignore bases that don't have a vtable.
if (!BaseDecl->isDynamicClass())
@@ -1737,10 +1805,9 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
}
}
-void
-VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- CharUnits OffsetInLayoutClass,
- VisitedVirtualBasesSetTy &VBases) {
+void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
+ const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass,
+ VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Check if this base has a primary base.
@@ -1773,8 +1840,7 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
// Traverse bases, looking for more primary virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
CharUnits BaseOffsetInLayoutClass;
@@ -1796,17 +1862,15 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
}
}
-void
-VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases) {
+void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
+ const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
// Itanium C++ ABI 2.5.2:
// Then come the virtual base virtual tables, also in inheritance graph
// order, and again excluding primary bases (which share virtual tables with
// the classes for which they are primary).
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
@@ -1836,8 +1900,25 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
}
}
+struct ItaniumThunkInfoComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ assert(LHS.Method == 0);
+ assert(RHS.Method == 0);
+
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ return false;
+ }
+};
+
/// dumpLayout - Dump the vtable layout.
-void VTableBuilder::dumpLayout(raw_ostream& Out) {
+void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
+ // FIXME: write more tests that actually use the dumpLayout output to prevent
+ // ItaniumVTableBuilder regressions.
if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
@@ -1915,8 +1996,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [return adjustment: ";
Out << Thunk.Return.NonVirtual << " non-virtual";
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
Out << " vbase offset offset";
}
@@ -1928,8 +2009,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -1950,8 +2031,6 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << DD->getQualifiedNameAsString();
if (IsComplete)
Out << "() [complete]";
- else if (isMicrosoftABI())
- Out << "() [scalar deleting]";
else
Out << "() [deleting]";
@@ -1965,8 +2044,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -2078,7 +2157,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
const CXXMethodDecl *MD = I->second;
ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::sort(ThunksVector.begin(), ThunksVector.end());
+ std::sort(ThunksVector.begin(), ThunksVector.end(),
+ ItaniumThunkInfoComparator());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2090,10 +2170,10 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
// If this function pointer has a return pointer adjustment, dump it.
if (!Thunk.Return.isEmpty()) {
- Out << "return adjustment: " << Thunk.This.NonVirtual;
+ Out << "return adjustment: " << Thunk.Return.NonVirtual;
Out << " non-virtual";
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
Out << " vbase offset offset";
}
@@ -2106,8 +2186,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
}
@@ -2136,18 +2216,14 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // FIXME: Should add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
- = MethodName + " [complete]";
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
- = MethodName + " [deleting]";
- } else {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
- = MethodName + " [scalar deleting]";
- }
+ GlobalDecl GD(DD, Dtor_Complete);
+ assert(MethodVTableIndices.count(GD));
+ uint64_t VTableIndex = MethodVTableIndices[GD];
+ IndicesMap[VTableIndex] = MethodName + " [complete]";
+ IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
} else {
- IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
+ assert(MethodVTableIndices.count(MD));
+ IndicesMap[MethodVTableIndices[MD]] = MethodName;
}
}
@@ -2162,14 +2238,24 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
uint64_t VTableIndex = I->first;
const std::string &MethodName = I->second;
- Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName
+ Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
<< '\n';
}
}
Out << '\n';
}
-
+
+struct VTableThunksComparator {
+ bool operator()(const VTableLayout::VTableThunkTy &LHS,
+ const VTableLayout::VTableThunkTy &RHS) {
+ if (LHS.first == RHS.first) {
+ assert(LHS.second == RHS.second &&
+ "Different thunks should have unique indices!");
+ }
+ return LHS.first < RHS.first;
+ }
+};
}
VTableLayout::VTableLayout(uint64_t NumVTableComponents,
@@ -2188,183 +2274,38 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
this->VTableThunks.get());
+ std::sort(this->VTableThunks.get(),
+ this->VTableThunks.get() + NumVTableThunks,
+ VTableThunksComparator());
}
VTableLayout::~VTableLayout() { }
-VTableContext::VTableContext(ASTContext &Context)
- : Context(Context),
- IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context)
+ : IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
}
-VTableContext::~VTableContext() {
+ItaniumVTableContext::~ItaniumVTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
}
-static void
-CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
- VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (!PrimaryBase)
- return;
-
- CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
-
- if (!PrimaryBases.insert(PrimaryBase))
- llvm_unreachable("Found a duplicate primary base!");
-}
-
-void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
-
- // Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
- //
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
-
- int64_t CurrentIndex = 0;
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (PrimaryBase) {
- assert(PrimaryBase->isCompleteDefinition() &&
- "Should have the definition decl of the primary base!");
-
- // Since the record decl shares its vtable pointer with the primary base
- // we need to start counting at the end of the primary base's vtable.
- CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
- }
-
- // Collect all the primary bases, so we can check whether methods override
- // a method from the base.
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
- CollectPrimaryBases(RD, Context, PrimaryBases);
-
- const CXXDestructorDecl *ImplicitVirtualDtor = 0;
-
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
-
- // We only want virtual methods.
- if (!MD->isVirtual())
- continue;
-
- // Check if this method overrides a method in the primary base.
- if (const CXXMethodDecl *OverriddenMD =
- FindNearestOverriddenMethod(MD, PrimaryBases)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- if (ComputeReturnAdjustmentBaseOffset(Context, MD,
- OverriddenMD).isEmpty()) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- if (!isMicrosoftABI()) {
- // Add both the complete and deleting entries.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- } else {
- // Add the scalar deleting destructor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- }
- } else {
- MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
- }
-
- // We don't need to add an entry for this method.
- continue;
- }
- }
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- if (MD->isImplicit()) {
- assert(!ImplicitVirtualDtor &&
- "Did already see an implicit virtual dtor!");
- ImplicitVirtualDtor = DD;
- continue;
- }
-
- if (!isMicrosoftABI()) {
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
- } else {
- // Add the scalar deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
- }
- } else {
- // Add the entry.
- MethodVTableIndices[MD] = CurrentIndex++;
- }
- }
-
- if (ImplicitVirtualDtor) {
- // Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
-
- if (isMicrosoftABI()) {
- ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
- ImplicitVirtualDtor->getLocation());
- }
-
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
- CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
- CurrentIndex++;
- }
-
- NumVirtualFunctionPointers[RD] = CurrentIndex;
-}
-
-uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
- llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
- NumVirtualFunctionPointers.find(RD);
- if (I != NumVirtualFunctionPointers.end())
- return I->second;
-
- ComputeMethodVTableIndices(RD);
-
- I = NumVirtualFunctionPointers.find(RD);
- assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
- return I->second;
-}
-
-uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) {
+uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) {
MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
if (I != MethodVTableIndices.end())
return I->second;
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
- ComputeMethodVTableIndices(RD);
+ computeVTableRelatedInformation(RD);
I = MethodVTableIndices.find(GD);
assert(I != MethodVTableIndices.end() && "Did not find index!");
return I->second;
}
-CharUnits
-VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+CharUnits
+ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
VirtualBaseClassOffsetOffsetsMapTy::iterator I =
@@ -2393,30 +2334,35 @@ VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
return I->second;
}
-static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
+static VTableLayout *CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
SmallVector<VTableLayout::VTableThunkTy, 1>
VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- std::sort(VTableThunks.begin(), VTableThunks.end());
return new VTableLayout(Builder.getNumVTableComponents(),
Builder.vtable_component_begin(),
VTableThunks.size(),
VTableThunks.data(),
Builder.getAddressPoints(),
- Builder.isMicrosoftABI());
+ /*IsMicrosoftABI=*/false);
}
-void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+void
+ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
+ assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!");
+
const VTableLayout *&Entry = VTableLayouts[RD];
// Check if we've computed this information before.
if (Entry)
return;
- VTableBuilder Builder(*this, RD, CharUnits::Zero(),
- /*MostDerivedClassIsVirtual=*/0, RD);
+ ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
+ /*MostDerivedClassIsVirtual=*/0, RD);
Entry = CreateVTableLayout(Builder);
+ MethodVTableIndices.insert(Builder.vtable_indices_begin(),
+ Builder.vtable_indices_end());
+
// Add the known thunks.
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
@@ -2426,16 +2372,16 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (!RD->getNumVBases())
return;
- const RecordType *VBaseRT =
- RD->vbases_begin()->getType()->getAs<RecordType>();
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+ const CXXRecordDecl *VBase =
+ RD->vbases_begin()->getType()->getAsCXXRecordDecl();
if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
return;
-
- for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
- Builder.getVBaseOffsetOffsets().begin(),
- E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+
+ for (ItaniumVTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator
+ I = Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end();
+ I != E; ++I) {
// Insert all types.
ClassPairTy ClassPair(RD, I->first);
@@ -2443,20 +2389,1040 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
}
}
-void VTableContext::ErrorUnsupported(StringRef Feature,
- SourceLocation Location) {
- clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "v-table layout for %0 is not supported yet");
- Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+VTableLayout *ItaniumVTableContext::createConstructionVTableLayout(
+ const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) {
+ ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
+ MostDerivedClassIsVirtual, LayoutClass);
+ return CreateVTableLayout(Builder);
}
-VTableLayout *VTableContext::createConstructionVTableLayout(
- const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- bool MostDerivedClassIsVirtual,
- const CXXRecordDecl *LayoutClass) {
- VTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
- MostDerivedClassIsVirtual, LayoutClass);
- return CreateVTableLayout(Builder);
+namespace {
+
+// Vtables in the Microsoft ABI are different from the Itanium ABI.
+//
+// The main differences are:
+// 1. Separate vftable and vbtable.
+//
+// 2. Each subobject with a vfptr gets its own vftable rather than an address
+// point in a single vtable shared between all the subobjects.
+// Each vftable is represented by a separate section and virtual calls
+// must be done using the vftable which has a slot for the function to be
+// called.
+//
+// 3. Virtual method definitions expect their 'this' parameter to point to the
+// first vfptr whose table provides a compatible overridden method. In many
+// cases, this permits the original vf-table entry to directly call
+// the method instead of passing through a thunk.
+//
+// A compatible overridden method is one which does not have a non-trivial
+// covariant-return adjustment.
+//
+// The first vfptr is the one with the lowest offset in the complete-object
+// layout of the defining class, and the method definition will subtract
+// that constant offset from the parameter value to get the real 'this'
+// value. Therefore, if the offset isn't really constant (e.g. if a virtual
+// function defined in a virtual base is overridden in a more derived
+// virtual base and these bases have a reverse order in the complete
+// object), the vf-table may require a this-adjustment thunk.
+//
+// 4. vftables do not contain new entries for overrides that merely require
+// this-adjustment. Together with #3, this keeps vf-tables smaller and
+// eliminates the need for this-adjustment thunks in many cases, at the cost
+// of often requiring redundant work to adjust the "this" pointer.
+//
+// 5. Instead of VTT and constructor vtables, vbtables and vtordisps are used.
+// Vtordisps are emitted into the class layout if a class has
+// a) a user-defined ctor/dtor
+// and
+// b) a method overriding a method in a virtual base.
+
+class VFTableBuilder {
+public:
+ typedef MicrosoftVTableContext::MethodVFTableLocation MethodVFTableLocation;
+
+ typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
+ MethodVFTableLocationsTy;
+
+private:
+ /// VTables - Global vtable information.
+ MicrosoftVTableContext &VTables;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ VFPtrInfo WhichVFPtr;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ const FinalOverriders Overriders;
+
+ /// Components - The components of the vftable being built.
+ SmallVector<VTableComponent, 64> Components;
+
+ MethodVFTableLocationsTy MethodVFTableLocations;
+
+ /// MethodInfo - Contains information about a method in a vtable.
+ /// (Used for computing 'this' pointer adjustment thunks.
+ struct MethodInfo {
+ /// VBTableIndex - The nonzero index in the vbtable that
+ /// this method's base has, or zero.
+ const uint64_t VBTableIndex;
+
+ /// VFTableIndex - The index in the vftable that this method has.
+ const uint64_t VFTableIndex;
+
+ /// Shadowed - Indicates if this vftable slot is shadowed by
+ /// a slot for a covariant-return override. If so, it shouldn't be printed
+ /// or used for vcalls in the most derived class.
+ bool Shadowed;
+
+ MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex)
+ : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
+ Shadowed(false) {}
+
+ MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {}
+ };
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
+
+ /// MethodInfoMap - The information for all methods in the vftable we're
+ /// currently building.
+ MethodInfoMapTy MethodInfoMap;
+
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
+
+ /// VTableThunks - The thunks by vftable index in the vftable currently being
+ /// built.
+ VTableThunksMapTy VTableThunks;
+
+ typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - A map that contains all the thunks needed for all methods in the
+ /// most derived class for which the vftable is currently being built.
+ ThunksMapTy Thunks;
+
+ /// AddThunk - Add a thunk for the given method.
+ void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
+
+ // Check if we have this thunk already.
+ if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
+ ThunksVector.end())
+ return;
+
+ ThunksVector.push_back(Thunk);
+ }
+
+ /// ComputeThisOffset - Returns the 'this' argument offset for the given
+ /// method in the given subobject, relative to the beginning of the
+ /// MostDerivedClass.
+ CharUnits ComputeThisOffset(const CXXMethodDecl *MD,
+ BaseSubobject Base,
+ FinalOverriders::OverriderInfo Overrider);
+
+ void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
+ CharUnits ThisOffset, ThisAdjustment &TA);
+
+ /// AddMethod - Add a single virtual member function to the vftable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(TI.Return.isEmpty() &&
+ "Destructor can't have return adjustment!");
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ } else {
+ if (!TI.isEmpty())
+ VTableThunks[Components.size()] = TI;
+ Components.push_back(VTableComponent::MakeFunction(MD));
+ }
+ }
+
+ /// AddMethods - Add the methods of this base subobject and the relevant
+ /// subbases to the vftable we're currently laying out.
+ void AddMethods(BaseSubobject Base, unsigned BaseDepth,
+ const CXXRecordDecl *LastVBase,
+ BasesSetVectorTy &VisitedBases);
+
+ void LayoutVFTable() {
+ // FIXME: add support for RTTI when we have proper LLVM support for symbols
+ // pointing to the middle of a section.
+
+ BasesSetVectorTy VisitedBases;
+ AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, 0,
+ VisitedBases);
+
+ assert(MethodVFTableLocations.empty());
+ for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
+ E = MethodInfoMap.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const MethodInfo &MI = I->second;
+ // Skip the methods that the MostDerivedClass didn't override
+ // and the entries shadowed by return adjusting thunks.
+ if (MD->getParent() != MostDerivedClass || MI.Shadowed)
+ continue;
+ MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.LastVBase,
+ WhichVFPtr.VFPtrOffset, MI.VFTableIndex);
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
+ } else {
+ MethodVFTableLocations[MD] = Loc;
+ }
+ }
+ }
+
+ void ErrorUnsupported(StringRef Feature, SourceLocation Location) {
+ clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet");
+ Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+ }
+
+public:
+ VFTableBuilder(MicrosoftVTableContext &VTables,
+ const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which)
+ : VTables(VTables),
+ Context(MostDerivedClass->getASTContext()),
+ MostDerivedClass(MostDerivedClass),
+ MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
+ WhichVFPtr(Which),
+ Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
+ LayoutVFTable();
+
+ if (Context.getLangOpts().DumpVTableLayouts)
+ dumpLayout(llvm::outs());
+ }
+
+ uint64_t getNumThunks() const { return Thunks.size(); }
+
+ ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); }
+
+ ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
+
+ MethodVFTableLocationsTy::const_iterator vtable_indices_begin() const {
+ return MethodVFTableLocations.begin();
+ }
+
+ MethodVFTableLocationsTy::const_iterator vtable_indices_end() const {
+ return MethodVFTableLocations.end();
+ }
+
+ uint64_t getNumVTableComponents() const { return Components.size(); }
+
+ const VTableComponent *vtable_component_begin() const {
+ return Components.begin();
+ }
+
+ const VTableComponent *vtable_component_end() const {
+ return Components.end();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ return VTableThunks.begin();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_end() const {
+ return VTableThunks.end();
+ }
+
+ void dumpLayout(raw_ostream &);
+};
+
+/// InitialOverriddenDefinitionCollector - Finds the set of least derived bases
+/// that define the given method.
+struct InitialOverriddenDefinitionCollector {
+ BasesSetVectorTy Bases;
+ OverriddenMethodsSetTy VisitedOverriddenMethods;
+
+ bool visit(const CXXMethodDecl *OverriddenMD) {
+ if (OverriddenMD->size_overridden_methods() == 0)
+ Bases.insert(OverriddenMD->getParent());
+ // Don't recurse on this method if we've already collected it.
+ return VisitedOverriddenMethods.insert(OverriddenMD);
+ }
+};
+
+static bool BaseInSet(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, void *BasesSet) {
+ BasesSetVectorTy *Bases = (BasesSetVectorTy *)BasesSet;
+ return Bases->count(Specifier->getType()->getAsCXXRecordDecl());
+}
+
+CharUnits
+VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
+ BaseSubobject Base,
+ FinalOverriders::OverriderInfo Overrider) {
+ InitialOverriddenDefinitionCollector Collector;
+ visitAllOverriddenMethods(MD, Collector);
+
+ CXXBasePaths Paths;
+ Base.getBase()->lookupInBases(BaseInSet, &Collector.Bases, Paths);
+
+ // This will hold the smallest this offset among overridees of MD.
+ // This implies that an offset of a non-virtual base will dominate an offset
+ // of a virtual base to potentially reduce the number of thunks required
+ // in the derived classes that inherit this method.
+ CharUnits Ret;
+ bool First = true;
+
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ const CXXBasePath &Path = (*I);
+ CharUnits ThisOffset = Base.getBaseOffset();
+ CharUnits LastVBaseOffset;
+
+ // For each path from the overrider to the parents of the overridden methods,
+ // traverse the path, calculating the this offset in the most derived class.
+ for (int J = 0, F = Path.size(); J != F; ++J) {
+ const CXXBasePathElement &Element = Path[J];
+ QualType CurTy = Element.Base->getType();
+ const CXXRecordDecl *PrevRD = Element.Class,
+ *CurRD = CurTy->getAsCXXRecordDecl();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
+
+ if (Element.Base->isVirtual()) {
+ LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
+ if (Overrider.Method->getParent() == PrevRD) {
+ // This one's interesting. If the final overrider is in a vbase B of the
+ // most derived class and it overrides a method of the B's own vbase A,
+ // it uses A* as "this". In its prologue, it can cast A* to B* with
+ // a static offset. This offset is used regardless of the actual
+ // offset of A from B in the most derived class, requiring an
+ // this-adjusting thunk in the vftable if A and B are laid out
+ // differently in the most derived class.
+ ThisOffset += Layout.getVBaseClassOffset(CurRD);
+ } else {
+ ThisOffset = LastVBaseOffset;
+ }
+ } else {
+ ThisOffset += Layout.getBaseClassOffset(CurRD);
+ }
+ }
+
+ if (isa<CXXDestructorDecl>(MD)) {
+ if (LastVBaseOffset.isZero()) {
+ // If a "Base" class has at least one non-virtual base with a virtual
+ // destructor, the "Base" virtual destructor will take the address
+ // of the "Base" subobject as the "this" argument.
+ return Base.getBaseOffset();
+ } else {
+ // A virtual destructor of a virtual base takes the address of the
+ // virtual base subobject as the "this" argument.
+ return LastVBaseOffset;
+ }
+ }
+
+ if (Ret > ThisOffset || First) {
+ First = false;
+ Ret = ThisOffset;
+ }
+ }
+
+ assert(!First && "Method not found in the given subobject?");
+ return Ret;
+}
+
+void VFTableBuilder::CalculateVtordispAdjustment(
+ FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
+ ThisAdjustment &TA) {
+ const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap =
+ MostDerivedClassLayout.getVBaseOffsetsMap();
+ const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
+ VBaseMap.find(WhichVFPtr.LastVBase);
+ assert(VBaseMapEntry != VBaseMap.end());
+
+ // Check if we need a vtordisp adjustment at all.
+ if (!VBaseMapEntry->second.hasVtorDisp())
+ return;
+
+ CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ // The implicit vtordisp field is located right before the vbase.
+ TA.Virtual.Microsoft.VtordispOffset =
+ (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4;
+
+ // If the final overrider is defined in either:
+ // - the most derived class or its non-virtual base or
+ // - the same vbase as the initial declaration,
+ // a simple vtordisp thunk will suffice.
+ const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
+ if (OverriderRD == MostDerivedClass)
+ return;
+
+ const CXXRecordDecl *OverriderVBase =
+ ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
+ if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase)
+ return;
+
+ // Otherwise, we need to do use the dynamic offset of the final overrider
+ // in order to get "this" adjustment right.
+ TA.Virtual.Microsoft.VBPtrOffset =
+ (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset -
+ MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
+ TA.Virtual.Microsoft.VBOffsetOffset =
+ Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
+ VTables.getVBTableIndex(MostDerivedClass, OverriderVBase);
+
+ TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
+}
+
+static void GroupNewVirtualOverloads(
+ const CXXRecordDecl *RD,
+ SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) {
+ // Put the virtual methods into VirtualMethods in the proper order:
+ // 1) Group overloads by declaration name. New groups are added to the
+ // vftable in the order of their first declarations in this class
+ // (including overrides).
+ // 2) In each group, new overloads appear in the reverse order of declaration.
+ typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
+ SmallVector<MethodGroup, 10> Groups;
+ typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
+ VisitedGroupIndicesTy VisitedGroupIndices;
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+ if (!MD->isVirtual())
+ continue;
+
+ VisitedGroupIndicesTy::iterator J;
+ bool Inserted;
+ llvm::tie(J, Inserted) = VisitedGroupIndices.insert(
+ std::make_pair(MD->getDeclName(), Groups.size()));
+ if (Inserted)
+ Groups.push_back(MethodGroup(1, MD));
+ else
+ Groups[J->second].push_back(MD);
+ }
+
+ for (unsigned I = 0, E = Groups.size(); I != E; ++I)
+ VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend());
+}
+
+void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
+ const CXXRecordDecl *LastVBase,
+ BasesSetVectorTy &VisitedBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+ if (!RD->isPolymorphic())
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // See if this class expands a vftable of the base we look at, which is either
+ // the one defined by the vfptr base path or the primary base of the current class.
+ const CXXRecordDecl *NextBase = 0, *NextLastVBase = LastVBase;
+ CharUnits NextBaseOffset;
+ if (BaseDepth < WhichVFPtr.PathToBaseWithVFPtr.size()) {
+ NextBase = WhichVFPtr.PathToBaseWithVFPtr[BaseDepth];
+ if (Layout.getVBaseOffsetsMap().count(NextBase)) {
+ NextLastVBase = NextBase;
+ NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase);
+ } else {
+ NextBaseOffset =
+ Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase);
+ }
+ } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ assert(!Layout.isPrimaryBaseVirtual() &&
+ "No primary virtual bases in this ABI");
+ NextBase = PrimaryBase;
+ NextBaseOffset = Base.getBaseOffset();
+ }
+
+ if (NextBase) {
+ AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
+ NextLastVBase, VisitedBases);
+ if (!VisitedBases.insert(NextBase))
+ llvm_unreachable("Found a duplicate primary base!");
+ }
+
+ SmallVector<const CXXMethodDecl*, 10> VirtualMethods;
+ // Put virtual methods in the proper order.
+ GroupNewVirtualOverloads(RD, VirtualMethods);
+
+ // Now go through all virtual member functions and add them to the current
+ // vftable. This is done by
+ // - replacing overridden methods in their existing slots, as long as they
+ // don't require return adjustment; calculating This adjustment if needed.
+ // - adding new slots for methods of the current base not present in any
+ // sub-bases;
+ // - adding new slots for methods that require Return adjustment.
+ // We keep track of the methods visited in the sub-bases in MethodInfoMap.
+ for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) {
+ const CXXMethodDecl *MD = VirtualMethods[I];
+
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, Base.getBaseOffset());
+ ThisAdjustment ThisAdjustmentOffset;
+ bool ForceThunk = false;
+
+ // Check if this virtual member function overrides
+ // a method in one of the visited bases.
+ if (const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, VisitedBases)) {
+ MethodInfoMapTy::iterator OverriddenMDIterator =
+ MethodInfoMap.find(OverriddenMD);
+
+ // If the overridden method went to a different vftable, skip it.
+ if (OverriddenMDIterator == MethodInfoMap.end())
+ continue;
+
+ MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
+
+ // Create a this-adjusting thunk if needed.
+ CharUnits TI = ComputeThisOffset(MD, Base, Overrider);
+ if (TI != WhichVFPtr.VFPtrFullOffset) {
+ ThisAdjustmentOffset.NonVirtual =
+ (TI - WhichVFPtr.VFPtrFullOffset).getQuantity();
+ }
+
+ if (WhichVFPtr.LastVBase)
+ CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset);
+
+ if (!ThisAdjustmentOffset.isEmpty()) {
+ VTableThunks[OverriddenMethodInfo.VFTableIndex].This =
+ ThisAdjustmentOffset;
+ AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
+ }
+
+ if (MD->getResultType() == OverriddenMD->getResultType()) {
+ // No return adjustment needed - just replace the overridden method info
+ // with the current info.
+ MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
+ OverriddenMethodInfo.VFTableIndex);
+ MethodInfoMap.erase(OverriddenMDIterator);
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+ MethodInfoMap.insert(std::make_pair(MD, MI));
+ continue;
+ } else {
+ // In case we need a return adjustment, we'll add a new slot for
+ // the overrider and put a return-adjusting thunk where the overridden
+ // method was in the vftable.
+ // For now, just mark the overriden method as shadowed by a new slot.
+ OverriddenMethodInfo.Shadowed = true;
+ ForceThunk = true;
+
+ // Also apply this adjustment to the shadowed slots.
+ if (!ThisAdjustmentOffset.isEmpty()) {
+ // FIXME: this is O(N^2), can be O(N).
+ const CXXMethodDecl *SubOverride = OverriddenMD;
+ while ((SubOverride =
+ FindNearestOverriddenMethod(SubOverride, VisitedBases))) {
+ MethodInfoMapTy::iterator SubOverrideIterator =
+ MethodInfoMap.find(SubOverride);
+ if (SubOverrideIterator == MethodInfoMap.end())
+ break;
+ MethodInfo &SubOverrideMI = SubOverrideIterator->second;
+ assert(SubOverrideMI.Shadowed);
+ VTableThunks[SubOverrideMI.VFTableIndex].This =
+ ThisAdjustmentOffset;
+ AddThunk(MD, VTableThunks[SubOverrideMI.VFTableIndex]);
+ }
+ }
+ }
+ } else if (Base.getBaseOffset() != WhichVFPtr.VFPtrFullOffset ||
+ MD->size_overridden_methods()) {
+ // Skip methods that don't belong to the vftable of the current class,
+ // e.g. each method that wasn't seen in any of the visited sub-bases
+ // but overrides multiple methods of other sub-bases.
+ continue;
+ }
+
+ // 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, Components.size());
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+ MethodInfoMap.insert(std::make_pair(MD, MI));
+
+ const CXXMethodDecl *OverriderMD = Overrider.Method;
+
+ // Check if this overrider needs a return adjustment.
+ // We don't want to do this for pure virtual member functions.
+ BaseOffset ReturnAdjustmentOffset;
+ ReturnAdjustment ReturnAdjustment;
+ if (!OverriderMD->isPure()) {
+ ReturnAdjustmentOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
+ }
+ if (!ReturnAdjustmentOffset.isEmpty()) {
+ ForceThunk = true;
+ ReturnAdjustment.NonVirtual =
+ ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
+ if (ReturnAdjustmentOffset.VirtualBase) {
+ const ASTRecordLayout &DerivedLayout =
+ Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass);
+ ReturnAdjustment.Virtual.Microsoft.VBPtrOffset =
+ DerivedLayout.getVBPtrOffset().getQuantity();
+ ReturnAdjustment.Virtual.Microsoft.VBIndex =
+ VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
+ ReturnAdjustmentOffset.VirtualBase);
+ }
+ }
+
+ AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+ ForceThunk ? MD : 0));
+ }
+}
+
+void PrintBasePath(const VFPtrInfo::BasePath &Path, raw_ostream &Out) {
+ for (VFPtrInfo::BasePath::const_reverse_iterator I = Path.rbegin(),
+ E = Path.rend(); I != E; ++I) {
+ Out << "'" << (*I)->getQualifiedNameAsString() << "' in ";
+ }
+}
+
+struct MicrosoftThunkInfoStableSortComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ // Keep different thunks with the same adjustments in the order they
+ // were put into the vector.
+ return false;
+ }
+};
+
+static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
+ bool ContinueFirstLine) {
+ const ReturnAdjustment &R = TI.Return;
+ bool Multiline = false;
+ const char *LinePrefix = "\n ";
+ if (!R.isEmpty()) {
+ if (!ContinueFirstLine)
+ Out << LinePrefix;
+ Out << "[return adjustment: ";
+ if (R.Virtual.Microsoft.VBPtrOffset)
+ Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
+ if (R.Virtual.Microsoft.VBIndex)
+ Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", ";
+ Out << R.NonVirtual << " non-virtual]";
+ Multiline = true;
+ }
+
+ const ThisAdjustment &T = TI.This;
+ if (!T.isEmpty()) {
+ if (Multiline || !ContinueFirstLine)
+ Out << LinePrefix;
+ Out << "[this adjustment: ";
+ if (!TI.This.Virtual.isEmpty()) {
+ assert(T.Virtual.Microsoft.VtordispOffset < 0);
+ Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
+ if (T.Virtual.Microsoft.VBPtrOffset) {
+ Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
+ << " to the left, ";
+ assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
+ Out << LinePrefix << " vboffset at "
+ << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
+ }
+ }
+ Out << T.NonVirtual << " non-virtual]";
+ }
+}
+
+void VFTableBuilder::dumpLayout(raw_ostream &Out) {
+ Out << "VFTable for ";
+ PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
+ Out << "'" << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << Components.size() << " entries).\n";
+
+ for (unsigned I = 0, E = Components.size(); I != E; ++I) {
+ Out << llvm::format("%4d | ", I);
+
+ const VTableComponent &Component = Components[I];
+
+ // Dump the component.
+ switch (Component.getKind()) {
+ case VTableComponent::CK_RTTI:
+ Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ break;
+
+ case VTableComponent::CK_FunctionPointer: {
+ const CXXMethodDecl *MD = Component.getFunctionDecl();
+
+ std::string Str = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+ Out << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+
+ if (MD->isDeleted()) {
+ ErrorUnsupported("deleted methods", MD->getLocation());
+ Out << " [deleted]";
+ }
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty())
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
+
+ break;
+ }
+
+ case VTableComponent::CK_DeletingDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString();
+ Out << "() [scalar deleting]";
+
+ if (DD->isPure())
+ Out << " [pure]";
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ assert(Thunk.Return.isEmpty() &&
+ "No return adjustment needed for destructors!");
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
+ }
+
+ break;
+ }
+
+ default:
+ DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "Unexpected vftable component type %0 for component number %1");
+ Diags.Report(MostDerivedClass->getLocation(), DiagID)
+ << I << Component.getKind();
+ }
+
+ Out << '\n';
+ }
+
+ Out << '\n';
+
+ if (!Thunks.empty()) {
+ // We store the method names in a map to get a stable order.
+ std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
+
+ for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
+ I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ std::string MethodName = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+
+ MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
+ }
+
+ for (std::map<std::string, const CXXMethodDecl *>::const_iterator
+ I = MethodNamesAndDecls.begin(),
+ E = MethodNamesAndDecls.end();
+ I != E; ++I) {
+ const std::string &MethodName = I->first;
+ const CXXMethodDecl *MD = I->second;
+
+ ThunkInfoVectorTy ThunksVector = Thunks[MD];
+ std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
+ MicrosoftThunkInfoStableSortComparator());
+
+ Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
+ Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
+
+ for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
+ const ThunkInfo &Thunk = ThunksVector[I];
+
+ Out << llvm::format("%4d | ", I);
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true);
+ Out << '\n';
+ }
+
+ Out << '\n';
+ }
+ }
+}
+}
+
+void MicrosoftVTableContext::enumerateVFPtrs(
+ const CXXRecordDecl *MostDerivedClass,
+ const ASTRecordLayout &MostDerivedClassLayout, BaseSubobject Base,
+ const CXXRecordDecl *LastVBase,
+ const VFPtrInfo::BasePath &PathFromCompleteClass,
+ BasesSetVectorTy &VisitedVBases,
+ VFPtrListTy &Result) {
+ const CXXRecordDecl *CurrentClass = Base.getBase();
+ CharUnits OffsetInCompleteClass = Base.getBaseOffset();
+ const ASTRecordLayout &CurrentClassLayout =
+ Context.getASTRecordLayout(CurrentClass);
+
+ if (CurrentClassLayout.hasOwnVFPtr()) {
+ if (LastVBase) {
+ uint64_t VBIndex = getVBTableIndex(MostDerivedClass, LastVBase);
+ assert(VBIndex > 0 && "vbases must have vbindex!");
+ CharUnits VFPtrOffset =
+ OffsetInCompleteClass -
+ MostDerivedClassLayout.getVBaseClassOffset(LastVBase);
+ Result.push_back(VFPtrInfo(VBIndex, LastVBase, VFPtrOffset,
+ PathFromCompleteClass, OffsetInCompleteClass));
+ } else {
+ Result.push_back(VFPtrInfo(OffsetInCompleteClass, PathFromCompleteClass));
+ }
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = CurrentClass->bases_begin(),
+ E = CurrentClass->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+
+ CharUnits NextBaseOffset;
+ const CXXRecordDecl *NextLastVBase;
+ if (I->isVirtual()) {
+ if (!VisitedVBases.insert(BaseDecl))
+ continue;
+ NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ NextLastVBase = BaseDecl;
+ } else {
+ NextBaseOffset = OffsetInCompleteClass +
+ CurrentClassLayout.getBaseClassOffset(BaseDecl);
+ NextLastVBase = LastVBase;
+ }
+
+ VFPtrInfo::BasePath NewPath = PathFromCompleteClass;
+ NewPath.push_back(BaseDecl);
+ BaseSubobject NextBase(BaseDecl, NextBaseOffset);
+
+ enumerateVFPtrs(MostDerivedClass, MostDerivedClassLayout, NextBase,
+ NextLastVBase, NewPath, VisitedVBases, Result);
+ }
+}
+
+/// CalculatePathToMangle - Calculate the subset of records that should be used
+/// to mangle the vftable for the given vfptr.
+/// Should only be called if a class has multiple vftables.
+static void
+CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) {
+ // FIXME: In some rare cases this code produces a slightly incorrect mangling.
+ // It's very likely that the vbtable mangling code can be adjusted to mangle
+ // both vftables and vbtables correctly.
+
+ VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr;
+ if (FullPath.empty()) {
+ // Mangle the class's own vftable.
+ assert(RD->getNumVBases() &&
+ "Something's wrong: if the most derived "
+ "class has more than one vftable, it can only have its own "
+ "vftable if it has vbases");
+ VFPtr.PathToMangle.push_back(RD);
+ return;
+ }
+
+ unsigned Begin = 0;
+
+ // First, skip all the bases before the vbase.
+ if (VFPtr.LastVBase) {
+ while (FullPath[Begin] != VFPtr.LastVBase) {
+ Begin++;
+ assert(Begin < FullPath.size());
+ }
+ }
+
+ // Then, put the rest of the base path in the reverse order.
+ for (unsigned I = FullPath.size(); I != Begin; --I) {
+ const CXXRecordDecl *CurBase = FullPath[I - 1],
+ *ItsBase = (I == 1) ? RD : FullPath[I - 2];
+ bool BaseIsVirtual = false;
+ for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(),
+ F = ItsBase->bases_end(); J != F; ++J) {
+ if (J->getType()->getAsCXXRecordDecl() == CurBase) {
+ BaseIsVirtual = J->isVirtual();
+ break;
+ }
+ }
+
+ // Should skip the current base if it is a non-virtual base with no siblings.
+ if (BaseIsVirtual || ItsBase->getNumBases() != 1)
+ VFPtr.PathToMangle.push_back(CurBase);
+ }
+}
+
+void MicrosoftVTableContext::enumerateVFPtrs(
+ const CXXRecordDecl *ForClass,
+ MicrosoftVTableContext::VFPtrListTy &Result) {
+ Result.clear();
+ const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(ForClass);
+ BasesSetVectorTy VisitedVBases;
+ enumerateVFPtrs(ForClass, ClassLayout,
+ BaseSubobject(ForClass, CharUnits::Zero()), 0,
+ VFPtrInfo::BasePath(), VisitedVBases, Result);
+ if (Result.size() > 1) {
+ for (unsigned I = 0, E = Result.size(); I != E; ++I)
+ CalculatePathToMangle(ForClass, Result[I]);
+ }
+}
+
+void MicrosoftVTableContext::computeVTableRelatedInformation(
+ const CXXRecordDecl *RD) {
+ assert(RD->isDynamicClass());
+
+ // Check if we've computed this information before.
+ if (VFPtrLocations.count(RD))
+ return;
+
+ const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
+
+ VFPtrListTy &VFPtrs = VFPtrLocations[RD];
+ enumerateVFPtrs(RD, VFPtrs);
+
+ MethodVFTableLocationsTy NewMethodLocations;
+ for (VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end();
+ I != E; ++I) {
+ VFTableBuilder Builder(*this, RD, *I);
+
+ VFTableIdTy id(RD, I->VFPtrFullOffset);
+ assert(VFTableLayouts.count(id) == 0);
+ SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
+ Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
+ VFTableLayouts[id] = new VTableLayout(
+ Builder.getNumVTableComponents(), Builder.vtable_component_begin(),
+ VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true);
+ NewMethodLocations.insert(Builder.vtable_indices_begin(),
+ Builder.vtable_indices_end());
+ Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+ }
+
+ MethodVFTableLocations.insert(NewMethodLocations.begin(),
+ NewMethodLocations.end());
+ if (Context.getLangOpts().DumpVTableLayouts)
+ dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
+}
+
+void MicrosoftVTableContext::dumpMethodLocations(
+ const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods,
+ raw_ostream &Out) {
+ // Compute the vtable indices for all the member functions.
+ // Store them in a map keyed by the location so we'll get a sorted table.
+ std::map<MethodVFTableLocation, std::string> IndicesMap;
+ bool HasNonzeroOffset = false;
+
+ for (MethodVFTableLocationsTy::const_iterator I = NewMethods.begin(),
+ E = NewMethods.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I->first.getDecl());
+ assert(MD->isVirtual());
+
+ std::string MethodName = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+
+ if (isa<CXXDestructorDecl>(MD)) {
+ IndicesMap[I->second] = MethodName + " [scalar deleting]";
+ } else {
+ IndicesMap[I->second] = MethodName;
+ }
+
+ if (!I->second.VFPtrOffset.isZero() || I->second.VBTableIndex != 0)
+ HasNonzeroOffset = true;
+ }
+
+ // Print the vtable indices for all the member functions.
+ if (!IndicesMap.empty()) {
+ Out << "VFTable indices for ";
+ Out << "'" << RD->getQualifiedNameAsString();
+ Out << "' (" << IndicesMap.size() << " entries).\n";
+
+ CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1);
+ uint64_t LastVBIndex = 0;
+ for (std::map<MethodVFTableLocation, std::string>::const_iterator
+ I = IndicesMap.begin(),
+ E = IndicesMap.end();
+ I != E; ++I) {
+ CharUnits VFPtrOffset = I->first.VFPtrOffset;
+ uint64_t VBIndex = I->first.VBTableIndex;
+ if (HasNonzeroOffset &&
+ (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
+ assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
+ Out << " -- accessible via ";
+ if (VBIndex)
+ Out << "vbtable index " << VBIndex << ", ";
+ Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n";
+ LastVFPtrOffset = VFPtrOffset;
+ LastVBIndex = VBIndex;
+ }
+
+ uint64_t VTableIndex = I->first.Index;
+ const std::string &MethodName = I->second;
+ Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n';
+ }
+ Out << '\n';
+ }
+}
+
+void MicrosoftVTableContext::computeVBTableRelatedInformation(
+ const CXXRecordDecl *RD) {
+ if (ComputedVBTableIndices.count(RD))
+ return;
+ ComputedVBTableIndices.insert(RD);
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ BasesSetVectorTy VisitedBases;
+
+ // First, see if the Derived class shared the vbptr with a non-virtual base.
+ if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) {
+ // If the Derived class shares the vbptr with a non-virtual base,
+ // it inherits its vbase indices.
+ computeVBTableRelatedInformation(VBPtrBase);
+ for (CXXRecordDecl::base_class_const_iterator I = VBPtrBase->vbases_begin(),
+ E = VBPtrBase->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *SubVBase = I->getType()->getAsCXXRecordDecl();
+ assert(VBTableIndices.count(ClassPairTy(VBPtrBase, SubVBase)));
+ VBTableIndices[ClassPairTy(RD, SubVBase)] =
+ VBTableIndices[ClassPairTy(VBPtrBase, SubVBase)];
+ VisitedBases.insert(SubVBase);
+ }
+ }
+
+ // New vbases are added to the end of the vbtable.
+ // Skip the self entry and vbases visited in the non-virtual base, if any.
+ unsigned VBTableIndex = 1 + VisitedBases.size();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *CurVBase = I->getType()->getAsCXXRecordDecl();
+ if (VisitedBases.insert(CurVBase))
+ VBTableIndices[ClassPairTy(RD, CurVBase)] = VBTableIndex++;
+ }
+}
+
+const MicrosoftVTableContext::VFPtrListTy &
+MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) {
+ computeVTableRelatedInformation(RD);
+
+ assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
+ return VFPtrLocations[RD];
+}
+
+const VTableLayout &
+MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD,
+ CharUnits VFPtrOffset) {
+ computeVTableRelatedInformation(RD);
+
+ VFTableIdTy id(RD, VFPtrOffset);
+ assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset");
+ return *VFTableLayouts[id];
+}
+
+const MicrosoftVTableContext::MethodVFTableLocation &
+MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) {
+ assert(cast<CXXMethodDecl>(GD.getDecl())->isVirtual() &&
+ "Only use this method for virtual methods or dtors");
+ if (isa<CXXDestructorDecl>(GD.getDecl()))
+ assert(GD.getDtorType() == Dtor_Deleting);
+
+ MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
+ if (I != MethodVFTableLocations.end())
+ return I->second;
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ computeVTableRelatedInformation(RD);
+
+ I = MethodVFTableLocations.find(GD);
+ assert(I != MethodVFTableLocations.end() && "Did not find index!");
+ return I->second;
}
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 6ebd736e3ce4..f6dcb9779aba 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -30,10 +30,21 @@ namespace {
typedef MatchFinder::MatchCallback MatchCallback;
+// The maximum number of memoization entries to store.
+// 10k has been experimentally found to give a good trade-off
+// of performance vs. memory consumption by running matcher
+// that match on every statement over a very large codebase.
+//
+// FIXME: Do some performance optimization in general and
+// revisit this number; also, put up micro-benchmarks that we can
+// optimize this on.
+static const unsigned MaxMemoizationEntries = 10000;
+
// We use memoization to avoid running the same matcher on the same
-// AST node twice. This pair is the key for looking up match
+// AST node twice. This struct is the key for looking up match
// result. It consists of an ID of the MatcherInterface (for
-// identifying the matcher) and a pointer to the AST node.
+// identifying the matcher), a pointer to the AST node and the
+// bound nodes before the matcher was executed.
//
// We currently only memoize on nodes whose pointers identify the
// nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
@@ -41,12 +52,24 @@ typedef MatchFinder::MatchCallback MatchCallback;
// generation of keys for each type.
// FIXME: Benchmark whether memoization of non-pointer typed nodes
// provides enough benefit for the additional amount of code.
-typedef std::pair<uint64_t, const void*> UntypedMatchInput;
+struct MatchKey {
+ uint64_t MatcherID;
+ ast_type_traits::DynTypedNode Node;
+ BoundNodesTreeBuilder BoundNodes;
+
+ bool operator<(const MatchKey &Other) const {
+ if (MatcherID != Other.MatcherID)
+ return MatcherID < Other.MatcherID;
+ if (Node != Other.Node)
+ return Node < Other.Node;
+ return BoundNodes < Other.BoundNodes;
+ }
+};
// Used to store the result of a match and possibly bound nodes.
struct MemoizedMatchResult {
bool ResultOfMatch;
- BoundNodesTree Nodes;
+ BoundNodesTreeBuilder Nodes;
};
// A RecursiveASTVisitor that traverses all children or all descendants of
@@ -103,6 +126,12 @@ public:
else if (const TypeLoc *T = DynNode.get<TypeLoc>())
traverse(*T);
// FIXME: Add other base types after adding tests.
+
+ // It's OK to always overwrite the bound nodes, as if there was
+ // no match in this recursive branch, the result set is empty
+ // anyway.
+ *Builder = ResultBindings;
+
return Matches;
}
@@ -220,18 +249,20 @@ private:
return true;
}
if (Bind != ASTMatchFinder::BK_All) {
- if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
- Finder, Builder)) {
+ BoundNodesTreeBuilder RecursiveBuilder(*Builder);
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+ &RecursiveBuilder)) {
Matches = true;
- return false; // Abort as soon as a match is found.
+ ResultBindings.addMatch(RecursiveBuilder);
+ return false; // Abort as soon as a match is found.
}
} else {
- BoundNodesTreeBuilder RecursiveBuilder;
- if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
- Finder, &RecursiveBuilder)) {
+ BoundNodesTreeBuilder RecursiveBuilder(*Builder);
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+ &RecursiveBuilder)) {
// After the first match the matcher succeeds.
Matches = true;
- Builder->addMatch(RecursiveBuilder.build());
+ ResultBindings.addMatch(RecursiveBuilder);
}
}
return true;
@@ -251,6 +282,7 @@ private:
const DynTypedMatcher *const Matcher;
ASTMatchFinder *const Finder;
BoundNodesTreeBuilder *const Builder;
+ BoundNodesTreeBuilder ResultBindings;
int CurrentDepth;
const int MaxDepth;
const ASTMatchFinder::TraversalKind Traversal;
@@ -263,21 +295,31 @@ private:
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
- MatchASTVisitor(std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> > *MatcherCallbackPairs)
- : MatcherCallbackPairs(MatcherCallbackPairs),
- ActiveASTContext(NULL) {
- }
+ MatchASTVisitor(
+ std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *
+ MatcherCallbackPairs)
+ : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(NULL) {}
void onStartOfTranslationUnit() {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ for (std::vector<std::pair<internal::DynTypedMatcher,
+ MatchCallback *> >::const_iterator
+ I = MatcherCallbackPairs->begin(),
+ E = MatcherCallbackPairs->end();
I != E; ++I) {
I->second->onStartOfTranslationUnit();
}
}
+ void onEndOfTranslationUnit() {
+ for (std::vector<std::pair<internal::DynTypedMatcher,
+ MatchCallback *> >::const_iterator
+ I = MatcherCallbackPairs->begin(),
+ E = MatcherCallbackPairs->end();
+ I != E; ++I) {
+ I->second->onEndOfTranslationUnit();
+ }
+ }
+
void set_active_ast_context(ASTContext *NewActiveASTContext) {
ActiveASTContext = NewActiveASTContext;
}
@@ -285,7 +327,7 @@ public:
// The following Visit*() and Traverse*() functions "override"
// methods in RecursiveASTVisitor.
- bool VisitTypedefDecl(TypedefDecl *DeclNode) {
+ bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
// When we see 'typedef A B', we add name 'B' to the set of names
// A's canonical type maps to. This is necessary for implementing
// isDerivedFrom(x) properly, where x can be the name of the base
@@ -332,25 +374,30 @@ public:
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
- const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
-
// For AST-nodes that don't have an identity, we can't memoize.
- if (!input.second)
+ if (!Node.getMemoizationData())
return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
Bind);
- std::pair<MemoizationMap::iterator, bool> InsertResult
- = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()));
- if (InsertResult.second) {
- BoundNodesTreeBuilder DescendantBoundNodesBuilder;
- InsertResult.first->second.ResultOfMatch =
- matchesRecursively(Node, Matcher, &DescendantBoundNodesBuilder,
- MaxDepth, Traversal, Bind);
- InsertResult.first->second.Nodes =
- DescendantBoundNodesBuilder.build();
+ MatchKey Key;
+ Key.MatcherID = Matcher.getID();
+ Key.Node = Node;
+ // Note that we key on the bindings *before* the match.
+ Key.BoundNodes = *Builder;
+
+ MemoizationMap::iterator I = ResultCache.find(Key);
+ if (I != ResultCache.end()) {
+ *Builder = I->second.Nodes;
+ return I->second.ResultOfMatch;
}
- InsertResult.first->second.Nodes.copyTo(Builder);
- return InsertResult.first->second.ResultOfMatch;
+
+ MemoizedMatchResult Result;
+ Result.Nodes = *Builder;
+ Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
+ MaxDepth, Traversal, Bind);
+ ResultCache[Key] = Result;
+ *Builder = Result.Nodes;
+ return Result.ResultOfMatch;
}
// Matches children or descendants of 'Node' with 'BaseMatcher'.
@@ -373,14 +420,18 @@ public:
BoundNodesTreeBuilder *Builder,
TraversalKind Traversal,
BindKind Bind) {
- return matchesRecursively(Node, Matcher, Builder, 1, Traversal,
- Bind);
+ if (ResultCache.size() > MaxMemoizationEntries)
+ ResultCache.clear();
+ return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal,
+ Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) {
+ if (ResultCache.size() > MaxMemoizationEntries)
+ ResultCache.clear();
return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
TK_AsIs, Bind);
}
@@ -389,6 +440,10 @@ public:
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
+ // Reset the cache outside of the recursive call to make sure we
+ // don't invalidate any iterators.
+ if (ResultCache.size() > MaxMemoizationEntries)
+ ResultCache.clear();
return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
MatchMode);
}
@@ -396,15 +451,15 @@ public:
// Matches all registered matchers on the given node and calls the
// result callback for every node that matches.
void match(const ast_type_traits::DynTypedNode& Node) {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ for (std::vector<std::pair<internal::DynTypedMatcher,
+ MatchCallback *> >::const_iterator
+ I = MatcherCallbackPairs->begin(),
+ E = MatcherCallbackPairs->end();
I != E; ++I) {
BoundNodesTreeBuilder Builder;
- if (I->first->matches(Node, this, &Builder)) {
- BoundNodesTree BoundNodes = Builder.build();
+ if (I->first.matches(Node, this, &Builder)) {
MatchVisitor Visitor(ActiveASTContext, I->second);
- BoundNodes.visitMatches(&Visitor);
+ Builder.visitMatches(&Visitor);
}
}
}
@@ -450,60 +505,71 @@ private:
assert(false && "Found node that is not in the parent map.");
return false;
}
- const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
- MemoizationMap::iterator I = ResultCache.find(input);
- if (I == ResultCache.end()) {
- BoundNodesTreeBuilder AncestorBoundNodesBuilder;
- bool Matches = false;
- if (Parents.size() == 1) {
- // Only one parent - do recursive memoization.
- const ast_type_traits::DynTypedNode Parent = Parents[0];
- if (Matcher.matches(Parent, this, &AncestorBoundNodesBuilder)) {
- Matches = true;
- } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- Matches = memoizedMatchesAncestorOfRecursively(
- Parent, Matcher, &AncestorBoundNodesBuilder, MatchMode);
+ MatchKey Key;
+ Key.MatcherID = Matcher.getID();
+ Key.Node = Node;
+ Key.BoundNodes = *Builder;
+
+ // Note that we cannot use insert and reuse the iterator, as recursive
+ // calls to match might invalidate the result cache iterators.
+ MemoizationMap::iterator I = ResultCache.find(Key);
+ if (I != ResultCache.end()) {
+ *Builder = I->second.Nodes;
+ return I->second.ResultOfMatch;
+ }
+ MemoizedMatchResult Result;
+ Result.ResultOfMatch = false;
+ Result.Nodes = *Builder;
+ if (Parents.size() == 1) {
+ // Only one parent - do recursive memoization.
+ const ast_type_traits::DynTypedNode Parent = Parents[0];
+ if (Matcher.matches(Parent, this, &Result.Nodes)) {
+ Result.ResultOfMatch = true;
+ } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ // Reset the results to not include the bound nodes from the failed
+ // match above.
+ Result.Nodes = *Builder;
+ Result.ResultOfMatch = memoizedMatchesAncestorOfRecursively(
+ Parent, Matcher, &Result.Nodes, MatchMode);
+ // Once we get back from the recursive call, the result will be the
+ // same as the parent's result.
+ }
+ } else {
+ // Multiple parents - BFS over the rest of the nodes.
+ llvm::DenseSet<const void *> Visited;
+ std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
+ Parents.end());
+ while (!Queue.empty()) {
+ Result.Nodes = *Builder;
+ if (Matcher.matches(Queue.front(), this, &Result.Nodes)) {
+ Result.ResultOfMatch = true;
+ break;
}
- } else {
- // Multiple parents - BFS over the rest of the nodes.
- llvm::DenseSet<const void *> Visited;
- std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
- Parents.end());
- while (!Queue.empty()) {
- if (Matcher.matches(Queue.front(), this,
- &AncestorBoundNodesBuilder)) {
- Matches = true;
- break;
- }
- if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- ASTContext::ParentVector Ancestors =
- ActiveASTContext->getParents(Queue.front());
- for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
- E = Ancestors.end();
- I != E; ++I) {
- // Make sure we do not visit the same node twice.
- // Otherwise, we'll visit the common ancestors as often as there
- // are splits on the way down.
- if (Visited.insert(I->getMemoizationData()).second)
- Queue.push_back(*I);
- }
+ if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ ASTContext::ParentVector Ancestors =
+ ActiveASTContext->getParents(Queue.front());
+ for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
+ E = Ancestors.end();
+ I != E; ++I) {
+ // Make sure we do not visit the same node twice.
+ // Otherwise, we'll visit the common ancestors as often as there
+ // are splits on the way down.
+ if (Visited.insert(I->getMemoizationData()).second)
+ Queue.push_back(*I);
}
- Queue.pop_front();
}
+ Queue.pop_front();
}
-
- I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()))
- .first;
- I->second.Nodes = AncestorBoundNodesBuilder.build();
- I->second.ResultOfMatch = Matches;
}
- I->second.Nodes.copyTo(Builder);
- return I->second.ResultOfMatch;
+ ResultCache[Key] = Result;
+
+ *Builder = Result.Nodes;
+ return Result.ResultOfMatch;
}
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
// the aggregated bound nodes for each match.
- class MatchVisitor : public BoundNodesTree::Visitor {
+ class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
public:
MatchVisitor(ASTContext* Context,
MatchFinder::MatchCallback* Callback)
@@ -525,28 +591,74 @@ private:
BoundNodesTreeBuilder *Builder) {
const Type *const CanonicalType =
ActiveASTContext->getCanonicalType(TypeNode);
- const std::set<const TypedefDecl*> &Aliases = TypeAliases[CanonicalType];
- for (std::set<const TypedefDecl*>::const_iterator
+ const std::set<const TypedefNameDecl *> &Aliases =
+ TypeAliases[CanonicalType];
+ for (std::set<const TypedefNameDecl*>::const_iterator
It = Aliases.begin(), End = Aliases.end();
It != End; ++It) {
- if (Matcher.matches(**It, this, Builder))
+ BoundNodesTreeBuilder Result(*Builder);
+ if (Matcher.matches(**It, this, &Result)) {
+ *Builder = Result;
return true;
+ }
}
return false;
}
- std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> > *const MatcherCallbackPairs;
+ std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const
+ MatcherCallbackPairs;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
- llvm::DenseMap<const Type*, std::set<const TypedefDecl*> > TypeAliases;
+ llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
// Maps (matcher, node) -> the match result for memoization.
- typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
+ typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
MemoizationMap ResultCache;
};
+static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) {
+ // Type::getAs<...>() drills through typedefs.
+ if (TypeNode->getAs<DependentNameType>() != NULL ||
+ TypeNode->getAs<DependentTemplateSpecializationType>() != NULL ||
+ TypeNode->getAs<TemplateTypeParmType>() != NULL)
+ // Dependent names and template TypeNode parameters will be matched when
+ // the template is instantiated.
+ return NULL;
+ TemplateSpecializationType const *TemplateType =
+ TypeNode->getAs<TemplateSpecializationType>();
+ if (TemplateType == NULL) {
+ return TypeNode->getAsCXXRecordDecl();
+ }
+ if (TemplateType->getTemplateName().isDependent())
+ // Dependent template specializations will be matched when the
+ // template is instantiated.
+ return NULL;
+
+ // For template specialization types which are specializing a template
+ // declaration which is an explicit or partial specialization of another
+ // template declaration, getAsCXXRecordDecl() returns the corresponding
+ // ClassTemplateSpecializationDecl.
+ //
+ // For template specialization types which are specializing a template
+ // declaration which is neither an explicit nor partial specialization of
+ // another template declaration, getAsCXXRecordDecl() returns NULL and
+ // we get the CXXRecordDecl of the templated declaration.
+ CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl();
+ if (SpecializationDecl != NULL) {
+ return SpecializationDecl;
+ }
+ NamedDecl *Templated =
+ TemplateType->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
+ if (CXXRecordDecl *TemplatedRecord = dyn_cast<CXXRecordDecl>(Templated)) {
+ return TemplatedRecord;
+ }
+ // Now it can still be that we have an alias template.
+ TypeAliasDecl *AliasDecl = dyn_cast<TypeAliasDecl>(Templated);
+ assert(AliasDecl);
+ return getAsCXXRecordDecl(AliasDecl->getUnderlyingType().getTypePtr());
+}
+
// Returns true if the given class is directly or indirectly derived
// from a base type with the given name. A class is not considered to be
// derived from itself.
@@ -557,58 +669,26 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
return false;
typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
for (BaseIterator It = Declaration->bases_begin(),
- End = Declaration->bases_end(); It != End; ++It) {
+ End = Declaration->bases_end();
+ It != End; ++It) {
const Type *TypeNode = It->getType().getTypePtr();
if (typeHasMatchingAlias(TypeNode, Base, Builder))
return true;
- // Type::getAs<...>() drills through typedefs.
- if (TypeNode->getAs<DependentNameType>() != NULL ||
- TypeNode->getAs<DependentTemplateSpecializationType>() != NULL ||
- TypeNode->getAs<TemplateTypeParmType>() != NULL)
- // Dependent names and template TypeNode parameters will be matched when
- // the template is instantiated.
+ CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode);
+ if (ClassDecl == NULL)
continue;
- CXXRecordDecl *ClassDecl = NULL;
- TemplateSpecializationType const *TemplateType =
- TypeNode->getAs<TemplateSpecializationType>();
- if (TemplateType != NULL) {
- if (TemplateType->getTemplateName().isDependent())
- // Dependent template specializations will be matched when the
- // template is instantiated.
- continue;
-
- // For template specialization types which are specializing a template
- // declaration which is an explicit or partial specialization of another
- // template declaration, getAsCXXRecordDecl() returns the corresponding
- // ClassTemplateSpecializationDecl.
- //
- // For template specialization types which are specializing a template
- // declaration which is neither an explicit nor partial specialization of
- // another template declaration, getAsCXXRecordDecl() returns NULL and
- // we get the CXXRecordDecl of the templated declaration.
- CXXRecordDecl *SpecializationDecl =
- TemplateType->getAsCXXRecordDecl();
- if (SpecializationDecl != NULL) {
- ClassDecl = SpecializationDecl;
- } else {
- ClassDecl = dyn_cast<CXXRecordDecl>(
- TemplateType->getTemplateName()
- .getAsTemplateDecl()->getTemplatedDecl());
- }
- } else {
- ClassDecl = TypeNode->getAsCXXRecordDecl();
- }
- assert(ClassDecl != NULL);
if (ClassDecl == Declaration) {
// This can happen for recursive template definitions; if the
// current declaration did not match, we can safely return false.
- assert(TemplateType);
return false;
}
- if (Base.matches(*ClassDecl, this, Builder))
+ BoundNodesTreeBuilder Result(*Builder);
+ if (Base.matches(*ClassDecl, this, &Result)) {
+ *Builder = Result;
return true;
+ }
if (classIsDerivedFrom(ClassDecl, Base, Builder))
return true;
}
@@ -664,25 +744,19 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
class MatchASTConsumer : public ASTConsumer {
public:
- MatchASTConsumer(
- std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> > *MatcherCallbackPairs,
- MatchFinder::ParsingDoneTestCallback *ParsingDone)
- : Visitor(MatcherCallbackPairs),
- ParsingDone(ParsingDone) {}
+ MatchASTConsumer(MatchFinder *Finder,
+ MatchFinder::ParsingDoneTestCallback *ParsingDone)
+ : Finder(Finder), ParsingDone(ParsingDone) {}
private:
virtual void HandleTranslationUnit(ASTContext &Context) {
if (ParsingDone != NULL) {
ParsingDone->run();
}
- Visitor.set_active_ast_context(&Context);
- Visitor.onStartOfTranslationUnit();
- Visitor.TraverseDecl(Context.getTranslationUnitDecl());
- Visitor.set_active_ast_context(NULL);
+ Finder->matchAST(Context);
}
- MatchASTVisitor Visitor;
+ MatchFinder *Finder;
MatchFinder::ParsingDoneTestCallback *ParsingDone;
};
@@ -699,53 +773,64 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
MatchFinder::MatchFinder() : ParsingDone(NULL) {}
-MatchFinder::~MatchFinder() {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end();
- It != End; ++It) {
- delete It->first;
- }
-}
+MatchFinder::~MatchFinder() {}
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new internal::Matcher<Decl>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new internal::Matcher<QualType>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new internal::Matcher<Stmt>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new NestedNameSpecifierMatcher(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new NestedNameSpecifierLocMatcher(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(
- new TypeLocMatcher(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+}
+
+bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+ MatchCallback *Action) {
+ if (NodeMatch.canConvertTo<Decl>()) {
+ addMatcher(NodeMatch.convertTo<Decl>(), Action);
+ return true;
+ } else if (NodeMatch.canConvertTo<QualType>()) {
+ addMatcher(NodeMatch.convertTo<QualType>(), Action);
+ return true;
+ } else if (NodeMatch.canConvertTo<Stmt>()) {
+ addMatcher(NodeMatch.convertTo<Stmt>(), Action);
+ return true;
+ } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
+ addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
+ return true;
+ } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
+ addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
+ return true;
+ } else if (NodeMatch.canConvertTo<TypeLoc>()) {
+ addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
+ return true;
+ }
+ return false;
}
ASTConsumer *MatchFinder::newASTConsumer() {
- return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
+ return new internal::MatchASTConsumer(this, ParsingDone);
}
void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
@@ -755,6 +840,14 @@ void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
Visitor.match(Node);
}
+void MatchFinder::matchAST(ASTContext &Context) {
+ internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ Visitor.set_active_ast_context(&Context);
+ Visitor.onStartOfTranslationUnit();
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ Visitor.onEndOfTranslationUnit();
+}
+
void MatchFinder::registerTestCallbackAfterParsing(
MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
ParsingDone = NewParsingDone;
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index f1a9ff2e09cb..d15eb54002fe 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -18,68 +18,65 @@ namespace clang {
namespace ast_matchers {
namespace internal {
-void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const {
- for (IDToNodeMap::const_iterator It = NodeMap.begin();
- It != NodeMap.end();
- ++It) {
- Builder->setBinding(It->first, It->second);
+void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
+ if (Bindings.empty())
+ Bindings.push_back(BoundNodesMap());
+ for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
+ ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
}
}
-void BoundNodesMap::copyTo(BoundNodesMap *Other) const {
- for (IDToNodeMap::const_iterator I = NodeMap.begin(),
- E = NodeMap.end();
- I != E; ++I) {
- Other->NodeMap[I->first] = I->second;
- }
-}
-
-BoundNodesTree::BoundNodesTree() {}
+DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
-BoundNodesTree::BoundNodesTree(
- const BoundNodesMap& Bindings,
- const std::vector<BoundNodesTree> RecursiveBindings)
- : Bindings(Bindings),
- RecursiveBindings(RecursiveBindings) {}
-
-void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
- Bindings.copyTo(Builder);
- for (std::vector<BoundNodesTree>::const_iterator
- I = RecursiveBindings.begin(),
- E = RecursiveBindings.end();
- I != E; ++I) {
- Builder->addMatch(*I);
+void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
+ for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
+ Bindings.push_back(Other.Bindings[i]);
}
}
-void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
- BoundNodesMap AggregatedBindings;
- visitMatchesRecursively(ResultVisitor, AggregatedBindings);
+bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ // allOf leads to one matcher for each alternative in the first
+ // matcher combined with each alternative in the second matcher.
+ // Thus, we can reuse the same Builder.
+ for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+ if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
+ return false;
+ }
+ return true;
}
-void BoundNodesTree::
-visitMatchesRecursively(Visitor* ResultVisitor,
- const BoundNodesMap& AggregatedBindings) {
- BoundNodesMap CombinedBindings(AggregatedBindings);
- Bindings.copyTo(&CombinedBindings);
- if (RecursiveBindings.empty()) {
- ResultVisitor->visitMatch(BoundNodes(CombinedBindings));
- } else {
- for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
- RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
- CombinedBindings);
+bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+ BoundNodesTreeBuilder BuilderInner(*Builder);
+ if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
+ Matched = true;
+ Result.addMatch(BuilderInner);
}
}
+ *Builder = Result;
+ return Matched;
}
-BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
-
-void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
- RecursiveBindings.push_back(Bindings);
-}
-
-BoundNodesTree BoundNodesTreeBuilder::build() const {
- return BoundNodesTree(Bindings, RecursiveBindings);
+bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+ BoundNodesTreeBuilder Result = *Builder;
+ if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
+ *Builder = Result;
+ return true;
+ }
+ }
+ return false;
}
} // end namespace internal
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
index 86560d61c9d3..4a390a8fc3de 100644
--- a/lib/ASTMatchers/CMakeLists.txt
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -1,3 +1,5 @@
+add_subdirectory(Dynamic)
+
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangASTMatchers
diff --git a/lib/ASTMatchers/Dynamic/CMakeLists.txt b/lib/ASTMatchers/Dynamic/CMakeLists.txt
new file mode 100644
index 000000000000..843341b29728
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangDynamicASTMatchers
+ Diagnostics.cpp
+ VariantValue.cpp
+ Parser.cpp
+ Registry.cpp
+ )
+
+add_dependencies(clangDynamicASTMatchers
+ clangASTMatchers
+ )
+
+target_link_libraries(clangDynamicASTMatchers
+ clangASTMatchers
+ )
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
new file mode 100644
index 000000000000..da2ed9a1d270
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -0,0 +1,220 @@
+//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
+ SourceRange Range) {
+ ContextStack.push_back(ContextFrame());
+ ContextFrame& data = ContextStack.back();
+ data.Type = Type;
+ data.Range = Range;
+ return ArgStream(&data.Args);
+}
+
+Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,
+ StringRef MatcherName,
+ const SourceRange &MatcherRange)
+ : Error(Error) {
+ Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;
+}
+
+Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,
+ StringRef MatcherName,
+ const SourceRange &MatcherRange,
+ unsigned ArgNumber)
+ : Error(Error) {
+ Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber
+ << MatcherName;
+}
+
+Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
+
+Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
+ : Error(Error), BeginIndex(Error->Errors.size()) {}
+
+Diagnostics::OverloadContext::~OverloadContext() {
+ // Merge all errors that happened while in this context.
+ if (BeginIndex < Error->Errors.size()) {
+ Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
+ for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
+ Dest.Messages.push_back(Error->Errors[i].Messages[0]);
+ }
+ Error->Errors.resize(BeginIndex + 1);
+ }
+}
+
+void Diagnostics::OverloadContext::revertErrors() {
+ // Revert the errors.
+ Error->Errors.resize(BeginIndex);
+}
+
+Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
+ Out->push_back(Arg.str());
+ return *this;
+}
+
+Diagnostics::ArgStream Diagnostics::addError(const SourceRange &Range,
+ ErrorType Error) {
+ Errors.push_back(ErrorContent());
+ ErrorContent &Last = Errors.back();
+ Last.ContextStack = ContextStack;
+ Last.Messages.push_back(ErrorContent::Message());
+ Last.Messages.back().Range = Range;
+ Last.Messages.back().Type = Error;
+ return ArgStream(&Last.Messages.back().Args);
+}
+
+StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
+ switch (Type) {
+ case Diagnostics::CT_MatcherConstruct:
+ return "Error building matcher $0.";
+ case Diagnostics::CT_MatcherArg:
+ return "Error parsing argument $0 for matcher $1.";
+ }
+ llvm_unreachable("Unknown ContextType value.");
+}
+
+StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
+ switch (Type) {
+ case Diagnostics::ET_RegistryNotFound:
+ return "Matcher not found: $0";
+ case Diagnostics::ET_RegistryWrongArgCount:
+ return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
+ case Diagnostics::ET_RegistryWrongArgType:
+ return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
+ case Diagnostics::ET_RegistryNotBindable:
+ return "Matcher does not support binding.";
+ case Diagnostics::ET_RegistryAmbiguousOverload:
+ // TODO: Add type info about the overload error.
+ return "Ambiguous matcher overload.";
+
+ case Diagnostics::ET_ParserStringError:
+ return "Error parsing string token: <$0>";
+ case Diagnostics::ET_ParserNoOpenParen:
+ return "Error parsing matcher. Found token <$0> while looking for '('.";
+ case Diagnostics::ET_ParserNoCloseParen:
+ return "Error parsing matcher. Found end-of-code while looking for ')'.";
+ case Diagnostics::ET_ParserNoComma:
+ return "Error parsing matcher. Found token <$0> while looking for ','.";
+ case Diagnostics::ET_ParserNoCode:
+ return "End of code found while looking for token.";
+ case Diagnostics::ET_ParserNotAMatcher:
+ return "Input value is not a matcher expression.";
+ case Diagnostics::ET_ParserInvalidToken:
+ return "Invalid token <$0> found when looking for a value.";
+ case Diagnostics::ET_ParserMalformedBindExpr:
+ 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_ParserOverloadedType:
+ return "Input value has unresolved overloaded type: $0";
+
+ case Diagnostics::ET_None:
+ return "<N/A>";
+ }
+ llvm_unreachable("Unknown ErrorType value.");
+}
+
+void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args,
+ llvm::raw_ostream &OS) {
+ while (!FormatString.empty()) {
+ std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
+ OS << Pieces.first.str();
+ if (Pieces.second.empty()) break;
+
+ const char Next = Pieces.second.front();
+ FormatString = Pieces.second.drop_front();
+ if (Next >= '0' && Next <= '9') {
+ const unsigned Index = Next - '0';
+ if (Index < Args.size()) {
+ OS << Args[Index];
+ } else {
+ OS << "<Argument_Not_Provided>";
+ }
+ }
+ }
+}
+
+static void maybeAddLineAndColumn(const SourceRange &Range,
+ llvm::raw_ostream &OS) {
+ if (Range.Start.Line > 0 && Range.Start.Column > 0) {
+ OS << Range.Start.Line << ":" << Range.Start.Column << ": ";
+ }
+}
+
+static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,
+ llvm::raw_ostream &OS) {
+ maybeAddLineAndColumn(Frame.Range, OS);
+ formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
+}
+
+static void
+printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
+ const Twine Prefix, llvm::raw_ostream &OS) {
+ maybeAddLineAndColumn(Message.Range, OS);
+ OS << Prefix;
+ formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
+}
+
+static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
+ llvm::raw_ostream &OS) {
+ if (Content.Messages.size() == 1) {
+ printMessageToStream(Content.Messages[0], "", OS);
+ } else {
+ for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
+ if (i != 0) OS << "\n";
+ printMessageToStream(Content.Messages[i],
+ "Candidate " + Twine(i + 1) + ": ", OS);
+ }
+ }
+}
+
+void Diagnostics::printToStream(llvm::raw_ostream &OS) const {
+ for (size_t i = 0, e = Errors.size(); i != e; ++i) {
+ if (i != 0) OS << "\n";
+ printErrorContentToStream(Errors[i], OS);
+ }
+}
+
+std::string Diagnostics::toString() const {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ printToStream(OS);
+ return OS.str();
+}
+
+void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {
+ for (size_t i = 0, e = Errors.size(); i != e; ++i) {
+ if (i != 0) OS << "\n";
+ const ErrorContent &Error = Errors[i];
+ for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {
+ printContextFrameToStream(Error.ContextStack[i], OS);
+ OS << "\n";
+ }
+ printErrorContentToStream(Error, OS);
+ }
+}
+
+std::string Diagnostics::toStringFull() const {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ printToStreamFull(OS);
+ return OS.str();
+}
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
diff --git a/lib/ASTMatchers/Dynamic/Makefile b/lib/ASTMatchers/Dynamic/Makefile
new file mode 100644
index 000000000000..a57d75222952
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangDynamicASTMatchers
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
new file mode 100644
index 000000000000..ae0c300d094a
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -0,0 +1,453 @@
+//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Functions templates and classes to wrap matcher construct functions.
+///
+/// A collection of template function and classes that provide a generic
+/// 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_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+
+#include <string>
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+namespace internal {
+
+/// \brief Helper template class to just from argument type to the right is/get
+/// functions in VariantValue.
+/// Used to verify and extract the matcher arguments below.
+template <class T> struct ArgTypeTraits;
+template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {
+};
+
+template <> struct ArgTypeTraits<std::string> {
+ static StringRef asString() { return "String"; }
+ static bool is(const VariantValue &Value) { return Value.isString(); }
+ static const std::string &get(const VariantValue &Value) {
+ return Value.getString();
+ }
+};
+
+template <>
+struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> {
+};
+
+template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
+ static std::string asString() {
+ return (Twine("Matcher<") +
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() +
+ ">").str();
+ }
+ 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>();
+ }
+};
+
+template <> struct ArgTypeTraits<unsigned> {
+ static std::string asString() { return "Unsigned"; }
+ static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
+ static unsigned get(const VariantValue &Value) {
+ return Value.getUnsigned();
+ }
+};
+
+/// \brief Generic MatcherCreate interface.
+///
+/// Provides a \c run() method that constructs the matcher from the provided
+/// arguments.
+class MatcherCreateCallback {
+public:
+ virtual ~MatcherCreateCallback() {}
+ virtual VariantMatcher run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const = 0;
+};
+
+/// \brief Simple callback implementation. Marshaller and function are provided.
+///
+/// This class wraps a function of arbitrary signature and a marshaller
+/// function into a MatcherCreateCallback.
+/// The marshaller is in charge of taking the VariantValue arguments, checking
+/// their types, unpacking them and calling the underlying function.
+class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback {
+public:
+ typedef VariantMatcher (*MarshallerType)(void (*Func)(),
+ StringRef MatcherName,
+ const 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
+ /// compile-time matcher expressions would use to create the matcher.
+ FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, void (*Func)(),
+ StringRef MatcherName)
+ : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName) {}
+
+ VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ return Marshaller(Func, MatcherName, NameRange, Args, Error);
+ }
+
+private:
+ const MarshallerType Marshaller;
+ void (* const Func)();
+ const std::string MatcherName;
+};
+
+/// \brief Simple callback implementation. Free function is wrapped.
+///
+/// This class simply wraps a free function with the right signature to export
+/// it as a MatcherCreateCallback.
+/// This allows us to have one implementation of the interface for as many free
+/// functions as we want, reducing the number of symbols and size of the
+/// object file.
+class FreeFuncMatcherCreateCallback : public MatcherCreateCallback {
+public:
+ typedef VariantMatcher (*RunFunc)(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
+
+ FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName)
+ : Func(Func), MatcherName(MatcherName.str()) {}
+
+ VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ return Func(MatcherName, NameRange, Args, Error);
+ }
+
+private:
+ const RunFunc Func;
+ const std::string MatcherName;
+};
+
+/// \brief Helper macros to check the arguments on all marshaller functions.
+#define CHECK_ARG_COUNT(count) \
+ if (Args.size() != count) { \
+ Error->addError(NameRange, Error->ET_RegistryWrongArgCount) \
+ << count << Args.size(); \
+ return VariantMatcher(); \
+ }
+
+#define CHECK_ARG_TYPE(index, type) \
+ if (!ArgTypeTraits<type>::is(Args[index].Value)) { \
+ Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \
+ << (index + 1) << ArgTypeTraits<type>::asString() \
+ << Args[index].Value.getTypeAsString(); \
+ return VariantMatcher(); \
+ }
+
+/// \brief Helper methods to extract and merge all possible typed matchers
+/// out of the polymorphic object.
+template <class PolyMatcher>
+static void mergePolyMatchers(const PolyMatcher &Poly,
+ std::vector<DynTypedMatcher> &Out,
+ ast_matchers::internal::EmptyTypeList) {}
+
+template <class PolyMatcher, class TypeList>
+static void mergePolyMatchers(const PolyMatcher &Poly,
+ std::vector<DynTypedMatcher> &Out, TypeList) {
+ Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
+ mergePolyMatchers(Poly, Out, typename TypeList::tail());
+}
+
+/// \brief Convert the return values of the functions into a VariantMatcher.
+///
+/// There are 2 cases right now: The return value is a Matcher<T> or is a
+/// polymorphic matcher. For the former, we just construct the VariantMatcher.
+/// For the latter, we instantiate all the possible Matcher<T> of the poly
+/// matcher.
+static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) {
+ return VariantMatcher::SingleMatcher(Matcher);
+}
+
+template <typename T>
+static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher,
+ typename T::ReturnTypes * =
+ NULL) {
+ std::vector<DynTypedMatcher> Matchers;
+ mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes());
+ VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers);
+ return Out;
+}
+
+/// \brief 0-arg marshaller function.
+template <typename ReturnType>
+static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ typedef ReturnType (*FuncType)();
+ CHECK_ARG_COUNT(0);
+ return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)());
+}
+
+/// \brief 1-arg marshaller function.
+template <typename ReturnType, typename ArgType1>
+static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ typedef ReturnType (*FuncType)(ArgType1);
+ CHECK_ARG_COUNT(1);
+ CHECK_ARG_TYPE(0, ArgType1);
+ return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)(
+ ArgTypeTraits<ArgType1>::get(Args[0].Value)));
+}
+
+/// \brief 2-arg marshaller function.
+template <typename ReturnType, typename ArgType1, typename ArgType2>
+static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ typedef ReturnType (*FuncType)(ArgType1, ArgType2);
+ CHECK_ARG_COUNT(2);
+ CHECK_ARG_TYPE(0, ArgType1);
+ CHECK_ARG_TYPE(1, ArgType2);
+ return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)(
+ ArgTypeTraits<ArgType1>::get(Args[0].Value),
+ ArgTypeTraits<ArgType2>::get(Args[1].Value)));
+}
+
+#undef CHECK_ARG_COUNT
+#undef CHECK_ARG_TYPE
+
+/// \brief Variadic marshaller function.
+template <typename ResultT, typename ArgT,
+ ResultT (*Func)(ArrayRef<const ArgT *>)>
+VariantMatcher
+variadicMatcherCreateCallback(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) {
+ ArgT **InnerArgs = new ArgT *[Args.size()]();
+
+ bool HasError = false;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ typedef ArgTypeTraits<ArgT> ArgTraits;
+ const ParserValue &Arg = Args[i];
+ const VariantValue &Value = Arg.Value;
+ if (!ArgTraits::is(Value)) {
+ Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
+ << (i + 1) << ArgTraits::asString() << Value.getTypeAsString();
+ HasError = true;
+ break;
+ }
+ InnerArgs[i] = new ArgT(ArgTraits::get(Value));
+ }
+
+ VariantMatcher Out;
+ if (!HasError) {
+ Out = outvalueToVariantMatcher(
+ Func(ArrayRef<const ArgT *>(InnerArgs, Args.size())));
+ }
+
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ delete InnerArgs[i];
+ }
+ delete[] InnerArgs;
+ return Out;
+}
+
+/// \brief Helper class used to collect all the possible overloads of an
+/// argument adaptative matcher function.
+template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
+ typename FromTypes, typename ToTypes>
+class AdaptativeOverloadCollector {
+public:
+ AdaptativeOverloadCollector(StringRef Name,
+ std::vector<MatcherCreateCallback *> &Out)
+ : Name(Name), Out(Out) {
+ collect(FromTypes());
+ }
+
+private:
+ typedef ast_matchers::internal::ArgumentAdaptingMatcherFunc<
+ ArgumentAdapterT, FromTypes, ToTypes> AdaptativeFunc;
+
+ /// \brief End case for the recursion
+ static void collect(ast_matchers::internal::EmptyTypeList) {}
+
+ /// \brief Recursive case. Get the overload for the head of the list, and
+ /// recurse to the tail.
+ template <typename FromTypeList> inline void collect(FromTypeList);
+
+ const StringRef Name;
+ std::vector<MatcherCreateCallback *> &Out;
+};
+
+/// \brief MatcherCreateCallback that wraps multiple "overloads" of the same
+/// matcher.
+///
+/// It will try every overload and generate appropriate errors for when none or
+/// more than one overloads match the arguments.
+class OverloadedMatcherCreateCallback : public MatcherCreateCallback {
+public:
+ OverloadedMatcherCreateCallback(ArrayRef<MatcherCreateCallback *> Callbacks)
+ : Overloads(Callbacks) {}
+
+ virtual ~OverloadedMatcherCreateCallback() {
+ llvm::DeleteContainerPointers(Overloads);
+ }
+
+ virtual VariantMatcher run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ std::vector<VariantMatcher> Constructed;
+ Diagnostics::OverloadContext Ctx(Error);
+ for (size_t i = 0, e = Overloads.size(); i != e; ++i) {
+ VariantMatcher SubMatcher = Overloads[i]->run(NameRange, Args, Error);
+ if (!SubMatcher.isNull()) {
+ Constructed.push_back(SubMatcher);
+ }
+ }
+
+ if (Constructed.empty()) return VariantMatcher(); // No overload matched.
+ // We ignore the errors if any matcher succeeded.
+ Ctx.revertErrors();
+ if (Constructed.size() > 1) {
+ // More than one constructed. It is ambiguous.
+ Error->addError(NameRange, Error->ET_RegistryAmbiguousOverload);
+ return VariantMatcher();
+ }
+ return Constructed[0];
+ }
+
+private:
+ std::vector<MatcherCreateCallback *> Overloads;
+};
+
+/// \brief Variadic operator marshaller function.
+class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback {
+public:
+ typedef ast_matchers::internal::VariadicOperatorFunction VarFunc;
+ VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName)
+ : Func(Func), MatcherName(MatcherName) {}
+
+ virtual VariantMatcher run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ std::vector<VariantMatcher> InnerArgs;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ const ParserValue &Arg = Args[i];
+ const VariantValue &Value = Arg.Value;
+ if (!Value.isMatcher()) {
+ Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
+ << (i + 1) << "Matcher<>" << Value.getTypeAsString();
+ return VariantMatcher();
+ }
+ InnerArgs.push_back(Value.getMatcher());
+ }
+ return VariantMatcher::VariadicOperatorMatcher(Func, InnerArgs);
+ }
+
+private:
+ const VarFunc Func;
+ const StringRef MatcherName;
+};
+
+
+/// Helper functions to select the appropriate marshaller functions.
+/// They detect the number of arguments, arguments types and return type.
+
+/// \brief 0-arg overload
+template <typename ReturnType>
+MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(),
+ StringRef MatcherName) {
+ return new FixedArgCountMatcherCreateCallback(
+ matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
+ MatcherName);
+}
+
+/// \brief 1-arg overload
+template <typename ReturnType, typename ArgType1>
+MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1),
+ StringRef MatcherName) {
+ return new FixedArgCountMatcherCreateCallback(
+ matcherMarshall1<ReturnType, ArgType1>,
+ reinterpret_cast<void (*)()>(Func), MatcherName);
+}
+
+/// \brief 2-arg overload
+template <typename ReturnType, typename ArgType1, typename ArgType2>
+MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1,
+ ArgType2),
+ StringRef MatcherName) {
+ return new FixedArgCountMatcherCreateCallback(
+ matcherMarshall2<ReturnType, ArgType1, ArgType2>,
+ reinterpret_cast<void (*)()>(Func), MatcherName);
+}
+
+/// \brief Variadic overload.
+template <typename ResultT, typename ArgT,
+ ResultT (*Func)(ArrayRef<const ArgT *>)>
+MatcherCreateCallback *
+makeMatcherAutoMarshall(llvm::VariadicFunction<ResultT, ArgT, Func> VarFunc,
+ StringRef MatcherName) {
+ return new FreeFuncMatcherCreateCallback(
+ &variadicMatcherCreateCallback<ResultT, ArgT, Func>, MatcherName);
+}
+
+/// \brief Argument adaptative overload.
+template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
+ typename FromTypes, typename ToTypes>
+MatcherCreateCallback *
+makeMatcherAutoMarshall(ast_matchers::internal::ArgumentAdaptingMatcherFunc<
+ ArgumentAdapterT, FromTypes, ToTypes>,
+ StringRef MatcherName) {
+ std::vector<MatcherCreateCallback *> Overloads;
+ AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>(MatcherName,
+ Overloads);
+ return new OverloadedMatcherCreateCallback(Overloads);
+}
+
+template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
+ typename FromTypes, typename ToTypes>
+template <typename FromTypeList>
+inline void
+AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>::collect(
+ FromTypeList) {
+ Out.push_back(makeMatcherAutoMarshall(
+ &AdaptativeFunc::template create<typename FromTypeList::head>, Name));
+ collect(typename FromTypeList::tail());
+}
+
+/// \brief Variadic operator overload.
+MatcherCreateCallback *makeMatcherAutoMarshall(
+ ast_matchers::internal::VariadicOperatorMatcherFunc Func,
+ StringRef MatcherName) {
+ return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName);
+}
+
+} // namespace internal
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
new file mode 100644
index 000000000000..df9596e9b935
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -0,0 +1,420 @@
+//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Recursive parser implementation for the matcher expression grammar.
+///
+//===----------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+/// \brief Simple structure to hold information for one token from the parser.
+struct Parser::TokenInfo {
+ /// \brief Different possible tokens.
+ enum TokenKind {
+ TK_Eof = 0,
+ TK_OpenParen = 1,
+ TK_CloseParen = 2,
+ TK_Comma = 3,
+ TK_Period = 4,
+ TK_Literal = 5,
+ TK_Ident = 6,
+ TK_InvalidChar = 7,
+ TK_Error = 8
+ };
+
+ /// \brief Some known identifiers.
+ static const char* const ID_Bind;
+
+ TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {}
+
+ StringRef Text;
+ TokenKind Kind;
+ SourceRange Range;
+ VariantValue Value;
+};
+
+const char* const Parser::TokenInfo::ID_Bind = "bind";
+
+/// \brief Simple tokenizer for the parser.
+class Parser::CodeTokenizer {
+public:
+ explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
+ : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) {
+ NextToken = getNextToken();
+ }
+
+ /// \brief Returns but doesn't consume the next token.
+ const TokenInfo &peekNextToken() const { return NextToken; }
+
+ /// \brief Consumes and returns the next token.
+ TokenInfo consumeNextToken() {
+ TokenInfo ThisToken = NextToken;
+ NextToken = getNextToken();
+ return ThisToken;
+ }
+
+ TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }
+
+private:
+ TokenInfo getNextToken() {
+ consumeWhitespace();
+ TokenInfo Result;
+ Result.Range.Start = currentLocation();
+
+ if (Code.empty()) {
+ Result.Kind = TokenInfo::TK_Eof;
+ Result.Text = "";
+ return Result;
+ }
+
+ switch (Code[0]) {
+ case ',':
+ Result.Kind = TokenInfo::TK_Comma;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
+ case '.':
+ Result.Kind = TokenInfo::TK_Period;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
+ case '(':
+ Result.Kind = TokenInfo::TK_OpenParen;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
+ case ')':
+ Result.Kind = TokenInfo::TK_CloseParen;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
+
+ case '"':
+ case '\'':
+ // Parse a string literal.
+ consumeStringLiteral(&Result);
+ break;
+
+ 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);
+ break;
+
+ default:
+ if (isAlphanumeric(Code[0])) {
+ // Parse an identifier
+ size_t TokenLength = 1;
+ while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength]))
+ ++TokenLength;
+ Result.Kind = TokenInfo::TK_Ident;
+ Result.Text = Code.substr(0, TokenLength);
+ Code = Code.drop_front(TokenLength);
+ } else {
+ Result.Kind = TokenInfo::TK_InvalidChar;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front(1);
+ }
+ break;
+ }
+
+ Result.Range.End = currentLocation();
+ return Result;
+ }
+
+ /// \brief Consume an unsigned literal.
+ void consumeUnsignedLiteral(TokenInfo *Result) {
+ unsigned Length = 1;
+ if (Code.size() > 1) {
+ // Consume the 'x' or 'b' radix modifier, if present.
+ switch (toLowercase(Code[1])) {
+ case 'x': case 'b': Length = 2;
+ }
+ }
+ while (Length < Code.size() && isHexDigit(Code[Length]))
+ ++Length;
+
+ 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;
+ } else {
+ SourceRange Range;
+ Range.Start = Result->Range.Start;
+ Range.End = currentLocation();
+ Error->addError(Range, Error->ET_ParserUnsignedError) << Result->Text;
+ Result->Kind = TokenInfo::TK_Error;
+ }
+ }
+
+ /// \brief Consume a string literal.
+ ///
+ /// \c Code must be positioned at the start of the literal (the opening
+ /// quote). Consumed until it finds the same closing quote character.
+ void consumeStringLiteral(TokenInfo *Result) {
+ bool InEscape = false;
+ const char Marker = Code[0];
+ for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
+ if (InEscape) {
+ InEscape = false;
+ continue;
+ }
+ if (Code[Length] == '\\') {
+ InEscape = true;
+ continue;
+ }
+ if (Code[Length] == Marker) {
+ Result->Kind = TokenInfo::TK_Literal;
+ Result->Text = Code.substr(0, Length + 1);
+ Result->Value = Code.substr(1, Length - 1).str();
+ Code = Code.drop_front(Length + 1);
+ return;
+ }
+ }
+
+ StringRef ErrorText = Code;
+ Code = Code.drop_front(Code.size());
+ SourceRange Range;
+ Range.Start = Result->Range.Start;
+ Range.End = currentLocation();
+ Error->addError(Range, Error->ET_ParserStringError) << ErrorText;
+ Result->Kind = TokenInfo::TK_Error;
+ }
+
+ /// \brief Consume all leading whitespace from \c Code.
+ void consumeWhitespace() {
+ while (!Code.empty() && isWhitespace(Code[0])) {
+ if (Code[0] == '\n') {
+ ++Line;
+ StartOfLine = Code.drop_front();
+ }
+ Code = Code.drop_front();
+ }
+ }
+
+ SourceLocation currentLocation() {
+ SourceLocation Location;
+ Location.Line = Line;
+ Location.Column = Code.data() - StartOfLine.data() + 1;
+ return Location;
+ }
+
+ StringRef Code;
+ StringRef StartOfLine;
+ unsigned Line;
+ Diagnostics *Error;
+ TokenInfo NextToken;
+};
+
+Parser::Sema::~Sema() {}
+
+/// \brief Parse and validate a matcher expression.
+/// \return \c true on success, in which case \c Value has the matcher parsed.
+/// If the input is malformed, or some argument has an error, it
+/// returns \c false.
+bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
+ const TokenInfo NameToken = Tokenizer->consumeNextToken();
+ assert(NameToken.Kind == TokenInfo::TK_Ident);
+ const TokenInfo OpenToken = Tokenizer->consumeNextToken();
+ if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
+ Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen)
+ << OpenToken.Text;
+ return false;
+ }
+
+ std::vector<ParserValue> Args;
+ TokenInfo EndToken;
+ while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {
+ if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {
+ // End of args.
+ EndToken = Tokenizer->consumeNextToken();
+ break;
+ }
+ if (Args.size() > 0) {
+ // We must find a , token to continue.
+ const TokenInfo CommaToken = Tokenizer->consumeNextToken();
+ if (CommaToken.Kind != TokenInfo::TK_Comma) {
+ Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
+ << CommaToken.Text;
+ return false;
+ }
+ }
+
+ Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,
+ NameToken.Text, NameToken.Range, Args.size() + 1);
+ ParserValue ArgValue;
+ ArgValue.Text = Tokenizer->peekNextToken().Text;
+ ArgValue.Range = Tokenizer->peekNextToken().Range;
+ if (!parseExpressionImpl(&ArgValue.Value)) return false;
+
+ Args.push_back(ArgValue);
+ }
+
+ if (EndToken.Kind == TokenInfo::TK_Eof) {
+ Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);
+ return false;
+ }
+
+ std::string BindID;
+ if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {
+ // Parse .bind("foo")
+ Tokenizer->consumeNextToken(); // consume the period.
+ const TokenInfo BindToken = Tokenizer->consumeNextToken();
+ const TokenInfo OpenToken = Tokenizer->consumeNextToken();
+ const TokenInfo IDToken = Tokenizer->consumeNextToken();
+ const TokenInfo CloseToken = Tokenizer->consumeNextToken();
+
+ // TODO: We could use different error codes for each/some to be more
+ // explicit about the syntax error.
+ if (BindToken.Kind != TokenInfo::TK_Ident ||
+ BindToken.Text != TokenInfo::ID_Bind) {
+ Error->addError(BindToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
+ Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) {
+ Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (CloseToken.Kind != TokenInfo::TK_CloseParen) {
+ Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ BindID = IDToken.Value.getString();
+ }
+
+ // Merge the start and end infos.
+ Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,
+ NameToken.Text, NameToken.Range);
+ SourceRange MatcherRange = NameToken.Range;
+ MatcherRange.End = EndToken.Range.End;
+ VariantMatcher Result = S->actOnMatcherExpression(
+ NameToken.Text, MatcherRange, BindID, Args, Error);
+ if (Result.isNull()) return false;
+
+ *Value = Result;
+ return true;
+}
+
+/// \brief Parse an <Expresssion>
+bool Parser::parseExpressionImpl(VariantValue *Value) {
+ switch (Tokenizer->nextTokenKind()) {
+ case TokenInfo::TK_Literal:
+ *Value = Tokenizer->consumeNextToken().Value;
+ return true;
+
+ case TokenInfo::TK_Ident:
+ return parseMatcherExpressionImpl(Value);
+
+ case TokenInfo::TK_Eof:
+ Error->addError(Tokenizer->consumeNextToken().Range,
+ Error->ET_ParserNoCode);
+ return false;
+
+ case TokenInfo::TK_Error:
+ // This error was already reported by the tokenizer.
+ return false;
+
+ case TokenInfo::TK_OpenParen:
+ case TokenInfo::TK_CloseParen:
+ case TokenInfo::TK_Comma:
+ case TokenInfo::TK_Period:
+ case TokenInfo::TK_InvalidChar:
+ const TokenInfo Token = Tokenizer->consumeNextToken();
+ Error->addError(Token.Range, Error->ET_ParserInvalidToken) << Token.Text;
+ return false;
+ }
+
+ llvm_unreachable("Unknown token kind.");
+}
+
+Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
+ Diagnostics *Error)
+ : Tokenizer(Tokenizer), S(S), Error(Error) {}
+
+class RegistrySema : public Parser::Sema {
+public:
+ virtual ~RegistrySema() {}
+ VariantMatcher actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ if (BindID.empty()) {
+ return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
+ } else {
+ return Registry::constructBoundMatcher(MatcherName, NameRange, BindID,
+ Args, Error);
+ }
+ }
+};
+
+bool Parser::parseExpression(StringRef Code, VariantValue *Value,
+ Diagnostics *Error) {
+ RegistrySema S;
+ return parseExpression(Code, &S, Value, Error);
+}
+
+bool Parser::parseExpression(StringRef Code, Sema *S,
+ VariantValue *Value, Diagnostics *Error) {
+ CodeTokenizer Tokenizer(Code, Error);
+ if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false;
+ if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) {
+ Error->addError(Tokenizer.peekNextToken().Range,
+ Error->ET_ParserTrailingCode);
+ return false;
+ }
+ return true;
+}
+
+llvm::Optional<DynTypedMatcher>
+Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) {
+ RegistrySema S;
+ return parseMatcherExpression(Code, &S, Error);
+}
+
+llvm::Optional<DynTypedMatcher>
+Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S,
+ Diagnostics *Error) {
+ VariantValue Value;
+ if (!parseExpression(Code, S, &Value, Error))
+ return llvm::Optional<DynTypedMatcher>();
+ if (!Value.isMatcher()) {
+ Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);
+ return llvm::Optional<DynTypedMatcher>();
+ }
+ llvm::Optional<DynTypedMatcher> Result =
+ Value.getMatcher().getSingleMatcher();
+ if (!Result.hasValue()) {
+ Error->addError(SourceRange(), Error->ET_ParserOverloadedType)
+ << Value.getTypeAsString();
+ }
+ return Result;
+}
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
new file mode 100644
index 000000000000..70e956e65465
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -0,0 +1,345 @@
+//===--- 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 <utility>
+
+#include "Marshallers.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ManagedStatic.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using internal::MatcherCreateCallback;
+
+typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap;
+class RegistryMaps {
+public:
+ RegistryMaps();
+ ~RegistryMaps();
+
+ const ConstructorMap &constructors() const { return Constructors; }
+
+private:
+ void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback);
+ ConstructorMap Constructors;
+};
+
+void RegistryMaps::registerMatcher(StringRef MatcherName,
+ MatcherCreateCallback *Callback) {
+ assert(Constructors.find(MatcherName) == Constructors.end());
+ Constructors[MatcherName] = Callback;
+}
+
+#define REGISTER_MATCHER(name) \
+ registerMatcher(#name, internal::makeMatcherAutoMarshall( \
+ ::clang::ast_matchers::name, #name));
+
+#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \
+ static_cast< ::clang::ast_matchers::name##_Type##Id>( \
+ ::clang::ast_matchers::name)
+
+#define REGISTER_OVERLOADED_2(name) \
+ do { \
+ MatcherCreateCallback *Callbacks[] = { \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \
+ #name), \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \
+ #name) \
+ }; \
+ registerMatcher(#name, \
+ new internal::OverloadedMatcherCreateCallback(Callbacks)); \
+ } while (0)
+
+/// \brief Generate a registry map with all the known matchers.
+RegistryMaps::RegistryMaps() {
+ // TODO: Here is the list of the missing matchers, grouped by reason.
+ //
+ // Need Variant/Parser fixes:
+ // ofKind
+ //
+ // Polymorphic + argument overload:
+ // unless
+ // findAll
+ //
+ // Other:
+ // loc
+ // equals
+ // equalsNode
+
+ REGISTER_OVERLOADED_2(callee);
+ REGISTER_OVERLOADED_2(hasPrefix);
+ REGISTER_OVERLOADED_2(hasType);
+ REGISTER_OVERLOADED_2(isDerivedFrom);
+ REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
+ REGISTER_OVERLOADED_2(pointsTo);
+ REGISTER_OVERLOADED_2(references);
+ REGISTER_OVERLOADED_2(thisPointerType);
+
+ REGISTER_MATCHER(accessSpecDecl);
+ REGISTER_MATCHER(alignOfExpr);
+ REGISTER_MATCHER(allOf);
+ REGISTER_MATCHER(anyOf);
+ REGISTER_MATCHER(anything);
+ REGISTER_MATCHER(argumentCountIs);
+ REGISTER_MATCHER(arraySubscriptExpr);
+ REGISTER_MATCHER(arrayType);
+ REGISTER_MATCHER(asString);
+ REGISTER_MATCHER(asmStmt);
+ REGISTER_MATCHER(atomicType);
+ REGISTER_MATCHER(autoType);
+ REGISTER_MATCHER(binaryOperator);
+ REGISTER_MATCHER(bindTemporaryExpr);
+ REGISTER_MATCHER(blockPointerType);
+ REGISTER_MATCHER(boolLiteral);
+ REGISTER_MATCHER(breakStmt);
+ REGISTER_MATCHER(builtinType);
+ REGISTER_MATCHER(cStyleCastExpr);
+ REGISTER_MATCHER(callExpr);
+ REGISTER_MATCHER(castExpr);
+ REGISTER_MATCHER(catchStmt);
+ REGISTER_MATCHER(characterLiteral);
+ REGISTER_MATCHER(classTemplateDecl);
+ REGISTER_MATCHER(classTemplateSpecializationDecl);
+ REGISTER_MATCHER(complexType);
+ REGISTER_MATCHER(compoundLiteralExpr);
+ REGISTER_MATCHER(compoundStmt);
+ REGISTER_MATCHER(conditionalOperator);
+ REGISTER_MATCHER(constCastExpr);
+ REGISTER_MATCHER(constantArrayType);
+ REGISTER_MATCHER(constructExpr);
+ REGISTER_MATCHER(constructorDecl);
+ REGISTER_MATCHER(containsDeclaration);
+ REGISTER_MATCHER(continueStmt);
+ REGISTER_MATCHER(ctorInitializer);
+ REGISTER_MATCHER(decl);
+ REGISTER_MATCHER(declCountIs);
+ REGISTER_MATCHER(declRefExpr);
+ REGISTER_MATCHER(declStmt);
+ REGISTER_MATCHER(defaultArgExpr);
+ REGISTER_MATCHER(deleteExpr);
+ REGISTER_MATCHER(dependentSizedArrayType);
+ REGISTER_MATCHER(destructorDecl);
+ REGISTER_MATCHER(doStmt);
+ REGISTER_MATCHER(dynamicCastExpr);
+ REGISTER_MATCHER(eachOf);
+ REGISTER_MATCHER(elaboratedType);
+ REGISTER_MATCHER(enumConstantDecl);
+ REGISTER_MATCHER(enumDecl);
+ REGISTER_MATCHER(explicitCastExpr);
+ REGISTER_MATCHER(expr);
+ REGISTER_MATCHER(fieldDecl);
+ REGISTER_MATCHER(floatLiteral);
+ REGISTER_MATCHER(forEach);
+ REGISTER_MATCHER(forEachDescendant);
+ REGISTER_MATCHER(forField);
+ REGISTER_MATCHER(forRangeStmt);
+ REGISTER_MATCHER(forStmt);
+ REGISTER_MATCHER(functionDecl);
+ REGISTER_MATCHER(functionTemplateDecl);
+ REGISTER_MATCHER(functionType);
+ REGISTER_MATCHER(functionalCastExpr);
+ REGISTER_MATCHER(gotoStmt);
+ REGISTER_MATCHER(has);
+ REGISTER_MATCHER(hasAncestor);
+ REGISTER_MATCHER(hasAnyArgument);
+ REGISTER_MATCHER(hasAnyConstructorInitializer);
+ REGISTER_MATCHER(hasAnyParameter);
+ REGISTER_MATCHER(hasAnySubstatement);
+ REGISTER_MATCHER(hasAnyTemplateArgument);
+ REGISTER_MATCHER(hasAnyUsingShadowDecl);
+ REGISTER_MATCHER(hasArgument);
+ REGISTER_MATCHER(hasArgumentOfType);
+ REGISTER_MATCHER(hasBase);
+ REGISTER_MATCHER(hasBody);
+ REGISTER_MATCHER(hasCanonicalType);
+ REGISTER_MATCHER(hasCondition);
+ REGISTER_MATCHER(hasConditionVariableStatement);
+ REGISTER_MATCHER(hasDeclContext);
+ REGISTER_MATCHER(hasDeclaration);
+ REGISTER_MATCHER(hasDeducedType);
+ REGISTER_MATCHER(hasDescendant);
+ REGISTER_MATCHER(hasDestinationType);
+ REGISTER_MATCHER(hasEitherOperand);
+ REGISTER_MATCHER(hasElementType);
+ REGISTER_MATCHER(hasFalseExpression);
+ REGISTER_MATCHER(hasImplicitDestinationType);
+ REGISTER_MATCHER(hasIncrement);
+ REGISTER_MATCHER(hasIndex);
+ REGISTER_MATCHER(hasInitializer);
+ REGISTER_MATCHER(hasLHS);
+ REGISTER_MATCHER(hasLocalQualifiers);
+ REGISTER_MATCHER(hasLoopInit);
+ REGISTER_MATCHER(hasMethod);
+ REGISTER_MATCHER(hasName);
+ REGISTER_MATCHER(hasObjectExpression);
+ REGISTER_MATCHER(hasOperatorName);
+ REGISTER_MATCHER(hasOverloadedOperatorName);
+ REGISTER_MATCHER(hasParameter);
+ REGISTER_MATCHER(hasParent);
+ REGISTER_MATCHER(hasQualifier);
+ REGISTER_MATCHER(hasRHS);
+ REGISTER_MATCHER(hasSingleDecl);
+ REGISTER_MATCHER(hasSize);
+ REGISTER_MATCHER(hasSizeExpr);
+ REGISTER_MATCHER(hasSourceExpression);
+ REGISTER_MATCHER(hasTargetDecl);
+ REGISTER_MATCHER(hasTemplateArgument);
+ REGISTER_MATCHER(hasTrueExpression);
+ REGISTER_MATCHER(hasUnaryOperand);
+ REGISTER_MATCHER(hasValueType);
+ REGISTER_MATCHER(ifStmt);
+ REGISTER_MATCHER(ignoringImpCasts);
+ REGISTER_MATCHER(ignoringParenCasts);
+ REGISTER_MATCHER(ignoringParenImpCasts);
+ REGISTER_MATCHER(implicitCastExpr);
+ REGISTER_MATCHER(incompleteArrayType);
+ REGISTER_MATCHER(initListExpr);
+ REGISTER_MATCHER(innerType);
+ REGISTER_MATCHER(integerLiteral);
+ REGISTER_MATCHER(isArrow);
+ REGISTER_MATCHER(isConstQualified);
+ REGISTER_MATCHER(isDefinition);
+ REGISTER_MATCHER(isExplicitTemplateSpecialization);
+ REGISTER_MATCHER(isExternC);
+ REGISTER_MATCHER(isImplicit);
+ REGISTER_MATCHER(isInteger);
+ REGISTER_MATCHER(isOverride);
+ REGISTER_MATCHER(isPrivate);
+ REGISTER_MATCHER(isProtected);
+ REGISTER_MATCHER(isPublic);
+ REGISTER_MATCHER(isTemplateInstantiation);
+ REGISTER_MATCHER(isVirtual);
+ REGISTER_MATCHER(isWritten);
+ REGISTER_MATCHER(lValueReferenceType);
+ REGISTER_MATCHER(labelStmt);
+ REGISTER_MATCHER(lambdaExpr);
+ REGISTER_MATCHER(matchesName);
+ REGISTER_MATCHER(materializeTemporaryExpr);
+ REGISTER_MATCHER(member);
+ REGISTER_MATCHER(memberCallExpr);
+ REGISTER_MATCHER(memberExpr);
+ REGISTER_MATCHER(memberPointerType);
+ REGISTER_MATCHER(methodDecl);
+ REGISTER_MATCHER(namedDecl);
+ REGISTER_MATCHER(namesType);
+ REGISTER_MATCHER(namespaceDecl);
+ REGISTER_MATCHER(nestedNameSpecifier);
+ REGISTER_MATCHER(nestedNameSpecifierLoc);
+ REGISTER_MATCHER(newExpr);
+ REGISTER_MATCHER(nullPtrLiteralExpr);
+ REGISTER_MATCHER(nullStmt);
+ REGISTER_MATCHER(ofClass);
+ REGISTER_MATCHER(on);
+ REGISTER_MATCHER(onImplicitObjectArgument);
+ REGISTER_MATCHER(operatorCallExpr);
+ REGISTER_MATCHER(parameterCountIs);
+ REGISTER_MATCHER(parenType);
+ REGISTER_MATCHER(pointee);
+ REGISTER_MATCHER(pointerType);
+ REGISTER_MATCHER(qualType);
+ REGISTER_MATCHER(rValueReferenceType);
+ REGISTER_MATCHER(recordDecl);
+ REGISTER_MATCHER(recordType);
+ REGISTER_MATCHER(referenceType);
+ REGISTER_MATCHER(refersToDeclaration);
+ REGISTER_MATCHER(refersToType);
+ REGISTER_MATCHER(reinterpretCastExpr);
+ REGISTER_MATCHER(returnStmt);
+ REGISTER_MATCHER(returns);
+ REGISTER_MATCHER(sizeOfExpr);
+ REGISTER_MATCHER(specifiesNamespace);
+ REGISTER_MATCHER(specifiesType);
+ REGISTER_MATCHER(specifiesTypeLoc);
+ REGISTER_MATCHER(statementCountIs);
+ REGISTER_MATCHER(staticCastExpr);
+ REGISTER_MATCHER(stmt);
+ REGISTER_MATCHER(stringLiteral);
+ REGISTER_MATCHER(switchCase);
+ REGISTER_MATCHER(switchStmt);
+ REGISTER_MATCHER(templateSpecializationType);
+ REGISTER_MATCHER(thisExpr);
+ REGISTER_MATCHER(throughUsingDecl);
+ REGISTER_MATCHER(throwExpr);
+ REGISTER_MATCHER(to);
+ REGISTER_MATCHER(tryStmt);
+ REGISTER_MATCHER(type);
+ REGISTER_MATCHER(typeLoc);
+ REGISTER_MATCHER(typedefType);
+ REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
+ REGISTER_MATCHER(unaryOperator);
+ REGISTER_MATCHER(userDefinedLiteral);
+ REGISTER_MATCHER(usingDecl);
+ REGISTER_MATCHER(varDecl);
+ REGISTER_MATCHER(variableArrayType);
+ REGISTER_MATCHER(whileStmt);
+ REGISTER_MATCHER(withInitializer);
+}
+
+RegistryMaps::~RegistryMaps() {
+ for (ConstructorMap::iterator it = Constructors.begin(),
+ end = Constructors.end();
+ it != end; ++it) {
+ delete it->second;
+ }
+}
+
+static llvm::ManagedStatic<RegistryMaps> RegistryData;
+
+} // anonymous namespace
+
+// static
+VariantMatcher Registry::constructMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ ConstructorMap::const_iterator it =
+ RegistryData->constructors().find(MatcherName);
+ if (it == RegistryData->constructors().end()) {
+ Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName;
+ return VariantMatcher();
+ }
+
+ return it->second->run(NameRange, Args, Error);
+}
+
+// static
+VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error);
+ if (Out.isNull()) return Out;
+
+ llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher();
+ if (Result.hasValue()) {
+ llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
+ if (Bound.hasValue()) {
+ return VariantMatcher::SingleMatcher(*Bound);
+ }
+ }
+ Error->addError(NameRange, Error->ET_RegistryNotBindable);
+ return VariantMatcher();
+}
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
new file mode 100644
index 000000000000..3e49e1b8ef03
--- /dev/null
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -0,0 +1,256 @@
+//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Polymorphic value type.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+VariantMatcher::MatcherOps::~MatcherOps() {}
+VariantMatcher::Payload::~Payload() {}
+
+class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
+public:
+ SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
+
+ virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ return Matcher;
+ }
+
+ virtual std::string getTypeAsString() const {
+ return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
+ .str();
+ }
+
+ virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ if (Ops.canConstructFrom(Matcher))
+ Ops.constructFrom(Matcher);
+ }
+
+private:
+ const DynTypedMatcher Matcher;
+};
+
+class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
+public:
+ PolymorphicPayload(ArrayRef<DynTypedMatcher> MatchersIn)
+ : Matchers(MatchersIn) {}
+
+ virtual ~PolymorphicPayload() {}
+
+ virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ if (Matchers.size() != 1)
+ return llvm::Optional<DynTypedMatcher>();
+ return Matchers[0];
+ }
+
+ virtual std::string getTypeAsString() const {
+ std::string Inner;
+ for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
+ if (i != 0)
+ Inner += "|";
+ Inner += Matchers[i].getSupportedKind().asStringRef();
+ }
+ return (Twine("Matcher<") + Inner + ">").str();
+ }
+
+ virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ const DynTypedMatcher *Found = NULL;
+ for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
+ if (Ops.canConstructFrom(Matchers[i])) {
+ if (Found)
+ return;
+ Found = &Matchers[i];
+ }
+ }
+ if (Found)
+ Ops.constructFrom(*Found);
+ }
+
+ const std::vector<DynTypedMatcher> Matchers;
+};
+
+class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
+public:
+ VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args)
+ : Func(Func), Args(Args) {}
+
+ virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ return llvm::Optional<DynTypedMatcher>();
+ }
+
+ virtual std::string getTypeAsString() const {
+ std::string Inner;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ if (i != 0)
+ Inner += "&";
+ Inner += Args[i].getTypeAsString();
+ }
+ return Inner;
+ }
+
+ virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ Ops.constructVariadicOperator(Func, Args);
+ }
+
+private:
+ const ast_matchers::internal::VariadicOperatorFunction Func;
+ const std::vector<VariantMatcher> Args;
+};
+
+VariantMatcher::VariantMatcher() {}
+
+VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
+ return VariantMatcher(new SinglePayload(Matcher));
+}
+
+VariantMatcher
+VariantMatcher::PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers) {
+ return VariantMatcher(new PolymorphicPayload(Matchers));
+}
+
+VariantMatcher VariantMatcher::VariadicOperatorMatcher(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args) {
+ return VariantMatcher(new VariadicOpPayload(Func, Args));
+}
+
+llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
+ return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
+}
+
+void VariantMatcher::reset() { Value.reset(); }
+
+std::string VariantMatcher::getTypeAsString() const {
+ if (Value) return Value->getTypeAsString();
+ return "<Nothing>";
+}
+
+VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
+ *this = Other;
+}
+
+VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
+ setUnsigned(Unsigned);
+}
+
+VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) {
+ setString(String);
+}
+
+VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {
+ setMatcher(Matcher);
+}
+
+VariantValue::~VariantValue() { reset(); }
+
+VariantValue &VariantValue::operator=(const VariantValue &Other) {
+ if (this == &Other) return *this;
+ reset();
+ switch (Other.Type) {
+ case VT_Unsigned:
+ setUnsigned(Other.getUnsigned());
+ break;
+ case VT_String:
+ setString(Other.getString());
+ break;
+ case VT_Matcher:
+ setMatcher(Other.getMatcher());
+ break;
+ case VT_Nothing:
+ Type = VT_Nothing;
+ break;
+ }
+ return *this;
+}
+
+void VariantValue::reset() {
+ switch (Type) {
+ case VT_String:
+ delete Value.String;
+ break;
+ case VT_Matcher:
+ delete Value.Matcher;
+ break;
+ // Cases that do nothing.
+ case VT_Unsigned:
+ case VT_Nothing:
+ break;
+ }
+ Type = VT_Nothing;
+}
+
+bool VariantValue::isUnsigned() const {
+ return Type == VT_Unsigned;
+}
+
+unsigned VariantValue::getUnsigned() const {
+ assert(isUnsigned());
+ return Value.Unsigned;
+}
+
+void VariantValue::setUnsigned(unsigned NewValue) {
+ reset();
+ Type = VT_Unsigned;
+ Value.Unsigned = NewValue;
+}
+
+bool VariantValue::isString() const {
+ return Type == VT_String;
+}
+
+const std::string &VariantValue::getString() const {
+ assert(isString());
+ return *Value.String;
+}
+
+void VariantValue::setString(const std::string &NewValue) {
+ reset();
+ Type = VT_String;
+ Value.String = new std::string(NewValue);
+}
+
+bool VariantValue::isMatcher() const {
+ return Type == VT_Matcher;
+}
+
+const VariantMatcher &VariantValue::getMatcher() const {
+ assert(isMatcher());
+ return *Value.Matcher;
+}
+
+void VariantValue::setMatcher(const VariantMatcher &NewValue) {
+ reset();
+ Type = VT_Matcher;
+ Value.Matcher = new VariantMatcher(NewValue);
+}
+
+std::string VariantValue::getTypeAsString() const {
+ switch (Type) {
+ case VT_String: return "String";
+ case VT_Matcher: return getMatcher().getTypeAsString();
+ case VT_Unsigned: return "Unsigned";
+ case VT_Nothing: return "Nothing";
+ }
+ llvm_unreachable("Invalid Type");
+}
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/lib/ASTMatchers/Makefile b/lib/ASTMatchers/Makefile
index 76d82719a103..3ee9ccb580b7 100644
--- a/lib/ASTMatchers/Makefile
+++ b/lib/ASTMatchers/Makefile
@@ -10,4 +10,6 @@
CLANG_LEVEL := ../..
LIBRARYNAME := clangASTMatchers
+PARALLEL_DIRS = Dynamic
+
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 5ff7842407a9..465f0c383486 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -157,6 +157,19 @@ AnalysisDeclContext::getBlockForRegisteredExpression(const Stmt *stmt) {
return itr->second;
}
+/// Add each synthetic statement in the CFG to the parent map, using the
+/// source statement's parent.
+static void addParentsForSyntheticStmts(const CFG *TheCFG, ParentMap &PM) {
+ if (!TheCFG)
+ return;
+
+ for (CFG::synthetic_stmt_iterator I = TheCFG->synthetic_stmt_begin(),
+ E = TheCFG->synthetic_stmt_end();
+ I != E; ++I) {
+ PM.setParent(I->first, PM.getParent(I->second));
+ }
+}
+
CFG *AnalysisDeclContext::getCFG() {
if (!cfgBuildOptions.PruneTriviallyFalseEdges)
return getUnoptimizedCFG();
@@ -167,6 +180,9 @@ CFG *AnalysisDeclContext::getCFG() {
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCFG = true;
+
+ if (PM)
+ addParentsForSyntheticStmts(cfg.get(), *PM);
}
return cfg.get();
}
@@ -180,6 +196,9 @@ CFG *AnalysisDeclContext::getUnoptimizedCFG() {
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCompleteCFG = true;
+
+ if (PM)
+ addParentsForSyntheticStmts(completeCFG.get(), *PM);
}
return completeCFG.get();
}
@@ -222,6 +241,10 @@ ParentMap &AnalysisDeclContext::getParentMap() {
PM->addStmt((*I)->getInit());
}
}
+ if (builtCFG)
+ addParentsForSyntheticStmts(getCFG(), *PM);
+ if (builtCompleteCFG)
+ addParentsForSyntheticStmts(getUnoptimizedCFG(), *PM);
}
return *PM;
}
@@ -387,7 +410,7 @@ bool LocationContext::isParentOf(const LocationContext *LC) const {
return false;
}
-void LocationContext::dumpStack() const {
+void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const {
ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
PrintingPolicy PP(Ctx.getLangOpts());
PP.TerseOutput = 1;
@@ -396,15 +419,15 @@ void LocationContext::dumpStack() const {
for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
switch (LCtx->getKind()) {
case StackFrame:
- llvm::errs() << '#' << Frame++ << ' ';
- cast<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP);
- llvm::errs() << '\n';
+ OS << Indent << '#' << Frame++ << ' ';
+ cast<StackFrameContext>(LCtx)->getDecl()->print(OS, PP);
+ OS << '\n';
break;
case Scope:
- llvm::errs() << " (scope)\n";
+ OS << Indent << " (scope)\n";
break;
case Block:
- llvm::errs() << " (block context: "
+ OS << Indent << " (block context: "
<< cast<BlockInvocationContext>(LCtx)->getContextData()
<< ")\n";
break;
@@ -412,6 +435,10 @@ void LocationContext::dumpStack() const {
}
}
+void LocationContext::dumpStack() const {
+ dumpStack(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Lazily generated map to query the external variables referenced by a Block.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 096c7a080bf6..8b8c573feade 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Builtins.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -155,7 +156,7 @@ public:
return !(*this == rhs);
}
- operator bool() const {
+ LLVM_EXPLICIT operator bool() const {
return *this != const_iterator();
}
@@ -362,6 +363,7 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
+ CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
AddStmtChoice asc);
@@ -470,6 +472,10 @@ private:
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
}
+ void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
+ B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
+ }
+
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E);
@@ -974,10 +980,23 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
// Check for const references bound to temporary. Set type to pointee.
QualType QT = VD->getType();
if (QT.getTypePtr()->isReferenceType()) {
- if (!VD->extendsLifetimeOfTemporary())
+ // Attempt to determine whether this declaration lifetime-extends a
+ // temporary.
+ //
+ // FIXME: This is incorrect. Non-reference declarations can lifetime-extend
+ // 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;
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr();
+ if (!isa<MaterializeTemporaryExpr>(Init))
return Scope;
- QT = getReferenceInitTemporaryType(*Context, VD->getInit());
+ // Lifetime-extending a temporary.
+ QT = getReferenceInitTemporaryType(*Context, Init);
}
// Check for constant size array. Set type to array element type.
@@ -1103,6 +1122,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::CXXConstructExprClass:
return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
+ case Stmt::CXXDeleteExprClass:
+ return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
+
case Stmt::CXXFunctionalCastExprClass:
return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
@@ -1449,18 +1471,33 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
AddEHEdge = true;
}
+ // If this is a call to a builtin function, it might not actually evaluate
+ // its arguments. Don't add them to the CFG if this is the case.
+ bool OmitArguments = false;
+
if (FunctionDecl *FD = C->getDirectCallee()) {
if (FD->isNoReturn())
NoReturn = true;
if (FD->hasAttr<NoThrowAttr>())
AddEHEdge = false;
+ if (FD->getBuiltinID() == Builtin::BI__builtin_object_size)
+ OmitArguments = true;
}
if (!CanThrow(C->getCallee(), *Context))
AddEHEdge = false;
- if (!NoReturn && !AddEHEdge)
+ if (OmitArguments) {
+ assert(!NoReturn && "noreturn calls with unevaluated args not implemented");
+ assert(!AddEHEdge && "EH calls with unevaluated args not implemented");
+ autoCreateBlock();
+ appendStmt(Block, C);
+ return Visit(C->getCallee());
+ }
+
+ if (!NoReturn && !AddEHEdge) {
return VisitStmt(C, asc.withAlwaysAdd(true));
+ }
if (Block) {
Succ = Block;
@@ -1627,6 +1664,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
Decl *D = *I;
void *Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
DeclStmt *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
+ cfg->addSyntheticDeclStmt(DSNew, DS);
// Append the fake DeclStmt to block.
B = VisitDeclSubExpr(DSNew);
@@ -1639,19 +1677,11 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
- Decl *D = DS->getSingleDecl();
-
- if (isa<StaticAssertDecl>(D)) {
- // static_asserts aren't added to the CFG because they do not impact
- // runtime semantics.
- return Block;
- }
-
VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD) {
- autoCreateBlock();
- appendStmt(Block, DS);
+ // Of everything that can be declared in a DeclStmt, only VarDecls impact
+ // runtime semantics.
return Block;
}
@@ -1869,9 +1899,12 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// Create the new block.
Block = createBlock(false);
- // The Exit block is the only successor.
addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
- addSuccessor(Block, &cfg->getExit());
+
+ // If the one of the destructors does not return, we already have the Exit
+ // block as a successor.
+ if (!Block->hasNoReturnElement())
+ addSuccessor(Block, &cfg->getExit());
// Add the return statement to the block. This may create new blocks if R
// contains control-flow (short-circuit operations).
@@ -2190,17 +2223,24 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// Now create the true branch.
{
// Save the current values for Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Succ(Succ);
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
- save_break(BreakJumpTarget);
+ save_break(BreakJumpTarget);
+ // Add an intermediate block between the BodyBlock and the
+ // EntryConditionBlock to represent the "loop back" transition, for looping
+ // back to the head of the loop.
+ CFGBlock *LoopBackBlock = 0;
+ Succ = LoopBackBlock = createBlock();
+ LoopBackBlock->setLoopTarget(S);
+
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
- ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
+ ContinueJumpTarget = JumpTarget(Succ, ScopePos);
CFGBlock *BodyBlock = addStmt(S->getBody());
if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
+ BodyBlock = ContinueJumpTarget.block; // can happen for "for (X in Y) ;"
else if (Block) {
if (badCFG)
return 0;
@@ -2679,9 +2719,15 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// If we have no "default:" case, the default transition is to the code
// following the switch body. Moreover, take into account if all the
// cases of a switch are covered (e.g., switching on an enum value).
+ //
+ // Note: We add a successor to a switch that is considered covered yet has no
+ // case statements if the enumeration has no enumerators.
+ bool SwitchAlwaysHasSuccessor = false;
+ SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
+ SwitchAlwaysHasSuccessor |= Terminator->isAllEnumCasesCovered() &&
+ Terminator->getSwitchCaseList();
addSuccessor(SwitchTerminatedBlock,
- switchExclusivelyCovered || Terminator->isAllEnumCasesCovered()
- ? 0 : DefaultCaseBlock);
+ SwitchAlwaysHasSuccessor ? 0 : DefaultCaseBlock);
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
@@ -3078,6 +3124,22 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
return VisitChildren(C);
}
+
+CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
+ AddStmtChoice asc) {
+ autoCreateBlock();
+ appendStmt(Block, DE);
+ QualType DTy = DE->getDestroyedType();
+ DTy = DTy.getNonReferenceType();
+ CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
+ if (RD) {
+ if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor())
+ appendDeleteDtor(Block, RD, DE);
+ }
+
+ return VisitChildren(DE);
+}
+
CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
AddStmtChoice asc) {
if (asc.alwaysAdd(*this, E)) {
@@ -3378,6 +3440,14 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
cast<CXXRecordDecl>(recordType->getDecl());
return classDecl->getDestructor();
}
+ case CFGElement::DeleteDtor: {
+ const CXXDeleteExpr *DE = castAs<CFGDeleteDtor>().getDeleteExpr();
+ QualType DTy = DE->getDestroyedType();
+ DTy = DTy.getNonReferenceType();
+ const CXXRecordDecl *classDecl =
+ astContext.getBaseElementType(DTy)->getAsCXXRecordDecl();
+ return classDecl->getDestructor();
+ }
case CFGElement::TemporaryDtor: {
const CXXBindTemporaryExpr *bindExpr =
castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
@@ -3400,113 +3470,6 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
}
//===----------------------------------------------------------------------===//
-// CFG: Queries for BlkExprs.
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
-}
-
-static void FindSubExprAssignments(const Stmt *S,
- llvm::SmallPtrSet<const Expr*,50>& Set) {
- if (!S)
- return;
-
- for (Stmt::const_child_range I = S->children(); I; ++I) {
- const Stmt *child = *I;
- if (!child)
- continue;
-
- if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child))
- if (B->isAssignmentOp()) Set.insert(B);
-
- FindSubExprAssignments(child, Set);
- }
-}
-
-static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
- BlkExprMapTy* M = new BlkExprMapTy();
-
- // Look for assignments that are used as subexpressions. These are the only
- // assignments that we want to *possibly* register as a block-level
- // expression. Basically, if an assignment occurs both in a subexpression and
- // at the block-level, it is a block-level expression.
- llvm::SmallPtrSet<const Expr*,50> SubExprAssignments;
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
- for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
- if (Optional<CFGStmt> S = BI->getAs<CFGStmt>())
- FindSubExprAssignments(S->getStmt(), SubExprAssignments);
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
-
- // Iterate over the statements again on identify the Expr* and Stmt* at the
- // block-level that are block-level expressions.
-
- for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
- Optional<CFGStmt> CS = BI->getAs<CFGStmt>();
- if (!CS)
- continue;
- if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
- assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
-
- if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
- // Assignment expressions that are not nested within another
- // expression are really "statements" whose value is never used by
- // another expression.
- if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
- continue;
- } else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) {
- // Special handling for statement expressions. The last statement in
- // the statement expression is also a block-level expr.
- const CompoundStmt *C = SE->getSubStmt();
- if (!C->body_empty()) {
- const Stmt *Last = C->body_back();
- if (const Expr *LastEx = dyn_cast<Expr>(Last))
- Last = LastEx->IgnoreParens();
- unsigned x = M->size();
- (*M)[Last] = x;
- }
- }
-
- unsigned x = M->size();
- (*M)[Exp] = x;
- }
- }
-
- // Look at terminators. The condition is a block-level expression.
-
- Stmt *S = (*I)->getTerminatorCondition();
-
- if (S && M->find(S) == M->end()) {
- unsigned x = M->size();
- (*M)[S] = x;
- }
- }
-
- return M;
-}
-
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) {
- assert(S != NULL);
- if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
-
- BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
- BlkExprMapTy::iterator I = M->find(S);
- return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second);
-}
-
-unsigned CFG::getNumBlkExprs() {
- if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
- return M->size();
-
- // We assume callers interested in the number of BlkExprs will want
- // the map constructed if it doesn't already exist.
- BlkExprMap = (void*) PopulateBlkExprMap(*this);
- return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
-}
-
-//===----------------------------------------------------------------------===//
// Filtered walking of the CFG.
//===----------------------------------------------------------------------===//
@@ -3530,14 +3493,6 @@ bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
}
//===----------------------------------------------------------------------===//
-// Cleanup: CFG dstor.
-//===----------------------------------------------------------------------===//
-
-CFG::~CFG() {
- delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
-}
-
-//===----------------------------------------------------------------------===//
// CFG pretty printing
//===----------------------------------------------------------------------===//
@@ -3753,35 +3708,32 @@ public:
};
} // end anonymous namespace
-static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
+static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
const CFGElement &E) {
if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
- if (Helper) {
-
- // special printing for statement-expressions.
- if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
- const CompoundStmt *Sub = SE->getSubStmt();
-
- if (Sub->children()) {
- OS << "({ ... ; ";
- Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
- OS << " })\n";
- return;
- }
+ // special printing for statement-expressions.
+ if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
+ const CompoundStmt *Sub = SE->getSubStmt();
+
+ if (Sub->children()) {
+ OS << "({ ... ; ";
+ Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
+ OS << " })\n";
+ return;
}
- // special printing for comma expressions.
- if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
- if (B->getOpcode() == BO_Comma) {
- OS << "... , ";
- Helper->handledStmt(B->getRHS(),OS);
- OS << '\n';
- return;
- }
+ }
+ // special printing for comma expressions.
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+ if (B->getOpcode() == BO_Comma) {
+ OS << "... , ";
+ Helper.handledStmt(B->getRHS(),OS);
+ OS << '\n';
+ return;
}
}
- S->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
+ S->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts()));
if (isa<CXXOperatorCallExpr>(S)) {
OS << " (OperatorCall)";
@@ -3807,21 +3759,25 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
const CXXCtorInitializer *I = IE->getInitializer();
if (I->isBaseInitializer())
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
+ else if (I->isDelegatingInitializer())
+ OS << I->getTypeSourceInfo()->getType()->getAsCXXRecordDecl()->getName();
else OS << I->getAnyMember()->getName();
OS << "(";
if (Expr *IE = I->getInit())
- IE->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
+ IE->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts()));
OS << ")";
if (I->isBaseInitializer())
OS << " (Base initializer)\n";
+ else if (I->isDelegatingInitializer())
+ OS << " (Delegating initializer)\n";
else OS << " (Member initializer)\n";
} else if (Optional<CFGAutomaticObjDtor> DE =
E.getAs<CFGAutomaticObjDtor>()) {
const VarDecl *VD = DE->getVarDecl();
- Helper->handleDecl(VD, OS);
+ Helper.handleDecl(VD, OS);
const Type* T = VD->getType().getTypePtr();
if (const ReferenceType* RT = T->getAs<ReferenceType>())
@@ -3831,6 +3787,15 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
+ } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
+ const CXXRecordDecl *RD = DE->getCXXRecordDecl();
+ if (!RD)
+ return;
+ CXXDeleteExpr *DelExpr =
+ const_cast<CXXDeleteExpr*>(DE->getDeleteExpr());
+ Helper.handledStmt(cast<Stmt>(DelExpr->getArgument()), OS);
+ OS << "->~" << RD->getName().str() << "()";
+ OS << " (Implicit destructor)\n";
} else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
@@ -3845,18 +3810,18 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
} else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
- OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
- OS << " (Temporary object destructor)\n";
+ OS << "~";
+ BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
+ OS << "() (Temporary object destructor)\n";
}
}
static void print_block(raw_ostream &OS, const CFG* cfg,
const CFGBlock &B,
- StmtPrinterHelper* Helper, bool print_edges,
+ StmtPrinterHelper &Helper, bool print_edges,
bool ShowColors) {
- if (Helper)
- Helper->setBlockID(B.getBlockID());
+ Helper.setBlockID(B.getBlockID());
// Print the header.
if (ShowColors)
@@ -3886,19 +3851,19 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
OS << L->getName();
else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
OS << "case ";
- C->getLHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
+ C->getLHS()->printPretty(OS, &Helper,
+ PrintingPolicy(Helper.getLangOpts()));
if (C->getRHS()) {
OS << " ... ";
- C->getRHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
+ C->getRHS()->printPretty(OS, &Helper,
+ PrintingPolicy(Helper.getLangOpts()));
}
} else if (isa<DefaultStmt>(Label))
OS << "default";
else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) {
OS << "catch (";
if (CS->getExceptionDecl())
- CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()),
+ CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper.getLangOpts()),
0);
else
OS << "...";
@@ -3922,8 +3887,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
OS << llvm::format("%3d", j) << ": ";
- if (Helper)
- Helper->setStmtID(j);
+ Helper.setStmtID(j);
print_elem(OS, Helper, *I);
}
@@ -3935,10 +3899,10 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
OS << " T: ";
- if (Helper) Helper->setBlockID(-1);
+ Helper.setBlockID(-1);
- PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions());
- CFGBlockTerminatorPrint TPrinter(OS, Helper, PP);
+ PrintingPolicy PP(Helper.getLangOpts());
+ CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
OS << '\n';
@@ -4020,7 +3984,7 @@ void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const {
StmtPrinterHelper Helper(this, LO);
// Print the entry block.
- print_block(OS, this, getEntry(), &Helper, true, ShowColors);
+ print_block(OS, this, getEntry(), Helper, true, ShowColors);
// Iterate through the CFGBlocks and print them one by one.
for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
@@ -4028,11 +3992,11 @@ void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const {
if (&(**I) == &getEntry() || &(**I) == &getExit())
continue;
- print_block(OS, this, **I, &Helper, true, ShowColors);
+ print_block(OS, this, **I, Helper, true, ShowColors);
}
// Print the exit block.
- print_block(OS, this, getExit(), &Helper, true, ShowColors);
+ print_block(OS, this, getExit(), Helper, true, ShowColors);
OS << '\n';
OS.flush();
}
@@ -4048,7 +4012,7 @@ void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
const LangOptions &LO, bool ShowColors) const {
StmtPrinterHelper Helper(cfg, LO);
- print_block(OS, cfg, *this, &Helper, true, ShowColors);
+ print_block(OS, cfg, *this, Helper, true, ShowColors);
OS << '\n';
}
@@ -4070,6 +4034,10 @@ Stmt *CFGBlock::getTerminatorCondition() {
default:
break;
+ case Stmt::CXXForRangeStmtClass:
+ E = cast<CXXForRangeStmt>(Terminator)->getCond();
+ break;
+
case Stmt::ForStmtClass:
E = cast<ForStmt>(Terminator)->getCond();
break;
@@ -4146,7 +4114,7 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
#ifndef NDEBUG
std::string OutSStr;
llvm::raw_string_ostream Out(OutSStr);
- print_block(Out,Graph, *Node, GraphHelper, false, false);
+ print_block(Out,Graph, *Node, *GraphHelper, false, false);
std::string& OutStr = Out.str();
if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
index e77e72fa9fb1..492e66fe8172 100644
--- a/lib/Analysis/CFGReachabilityAnalysis.cpp
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -50,11 +50,10 @@ void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
// multiple queries relating to a destination node.
worklist.push_back(Dst);
bool firstRun = true;
-
- while (!worklist.empty()) {
- const CFGBlock *block = worklist.back();
- worklist.pop_back();
-
+
+ while (!worklist.empty()) {
+ const CFGBlock *block = worklist.pop_back_val();
+
if (visited[block->getBlockID()])
continue;
visited[block->getBlockID()] = true;
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index ca166669fc89..deab8f1f22fd 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_library(clangAnalysis
CFGStmtMap.cpp
CallGraph.cpp
CocoaConventions.cpp
+ Consumed.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
new file mode 100644
index 000000000000..b33c8d8930f8
--- /dev/null
+++ b/lib/Analysis/Consumed.cpp
@@ -0,0 +1,1521 @@
+//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A intra-procedural analysis for checking consumed properties. This is based,
+// in part, on research on linear types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/Analyses/Consumed.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+// TODO: Adjust states of args to constructors in the same way that arguments to
+// function calls are handled.
+// TODO: Use information from tests in for- and while-loop conditional.
+// TODO: Add notes about the actual and expected state for
+// TODO: Correctly identify unreachable blocks when chaining boolean operators.
+// TODO: Adjust the parser and AttributesList class to support lists of
+// identifiers.
+// TODO: Warn about unreachable code.
+// TODO: Switch to using a bitmap to track unreachable blocks.
+// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
+// if (valid) ...; (Deferred)
+// TODO: Take notes on state transitions to provide better warning messages.
+// (Deferred)
+// TODO: Test nested conditionals: A) Checking the same value multiple times,
+// and 2) Checking different values. (Deferred)
+
+using namespace clang;
+using namespace consumed;
+
+// Key method definition
+ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
+
+static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
+ // Find the source location of the first statement in the block, if the block
+ // is not empty.
+ for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
+ BI != BE; ++BI) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ return CS->getStmt()->getLocStart();
+ }
+
+ // Block is empty.
+ // If we have one successor, return the first statement in that block
+ if (Block->succ_size() == 1 && *Block->succ_begin())
+ return getFirstStmtLoc(*Block->succ_begin());
+
+ return SourceLocation();
+}
+
+static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
+ // Find the source location of the last statement in the block, if the block
+ // is not empty.
+ if (const Stmt *StmtNode = Block->getTerminator()) {
+ return StmtNode->getLocStart();
+ } else {
+ for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
+ BE = Block->rend(); BI != BE; ++BI) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ return CS->getStmt()->getLocStart();
+ }
+ }
+
+ // If we have one successor, return the first statement in that block
+ SourceLocation Loc;
+ if (Block->succ_size() == 1 && *Block->succ_begin())
+ Loc = getFirstStmtLoc(*Block->succ_begin());
+ if (Loc.isValid())
+ return Loc;
+
+ // If we have one predecessor, return the last statement in that block
+ if (Block->pred_size() == 1 && *Block->pred_begin())
+ return getLastStmtLoc(*Block->pred_begin());
+
+ return Loc;
+}
+
+static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
+ switch (State) {
+ case CS_Unconsumed:
+ return CS_Consumed;
+ case CS_Consumed:
+ return CS_Unconsumed;
+ case CS_None:
+ return CS_None;
+ case CS_Unknown:
+ return CS_Unknown;
+ }
+ llvm_unreachable("invalid enum");
+}
+
+static bool isCallableInState(const CallableWhenAttr *CWAttr,
+ ConsumedState State) {
+
+ CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
+ E = CWAttr->callableState_end();
+
+ for (; I != E; ++I) {
+
+ ConsumedState MappedAttrState = CS_None;
+
+ switch (*I) {
+ case CallableWhenAttr::Unknown:
+ MappedAttrState = CS_Unknown;
+ break;
+
+ case CallableWhenAttr::Unconsumed:
+ MappedAttrState = CS_Unconsumed;
+ break;
+
+ case CallableWhenAttr::Consumed:
+ MappedAttrState = CS_Consumed;
+ break;
+ }
+
+ if (MappedAttrState == State)
+ return true;
+ }
+
+ return false;
+}
+
+static bool isConsumableType(const QualType &QT) {
+ if (QT->isPointerType() || QT->isReferenceType())
+ return false;
+
+ if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
+ return RD->hasAttr<ConsumableAttr>();
+
+ return false;
+}
+
+static bool isKnownState(ConsumedState State) {
+ switch (State) {
+ case CS_Unconsumed:
+ case CS_Consumed:
+ return true;
+ case CS_None:
+ case CS_Unknown:
+ return false;
+ }
+ llvm_unreachable("invalid enum");
+}
+
+static bool isRValueRefish(QualType ParamType) {
+ return ParamType->isRValueReferenceType() ||
+ (ParamType->isLValueReferenceType() &&
+ !cast<LValueReferenceType>(
+ ParamType.getCanonicalType())->isSpelledAsLValue());
+}
+
+static bool isTestingFunction(const FunctionDecl *FunDecl) {
+ return FunDecl->hasAttr<TestTypestateAttr>();
+}
+
+static bool isValueType(QualType ParamType) {
+ return !(ParamType->isPointerType() || ParamType->isReferenceType());
+}
+
+static ConsumedState mapConsumableAttrState(const QualType QT) {
+ assert(isConsumableType(QT));
+
+ const ConsumableAttr *CAttr =
+ QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
+
+ switch (CAttr->getDefaultState()) {
+ case ConsumableAttr::Unknown:
+ return CS_Unknown;
+ case ConsumableAttr::Unconsumed:
+ return CS_Unconsumed;
+ case ConsumableAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid enum");
+}
+
+static ConsumedState
+mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
+ switch (PTAttr->getParamState()) {
+ case ParamTypestateAttr::Unknown:
+ return CS_Unknown;
+ case ParamTypestateAttr::Unconsumed:
+ return CS_Unconsumed;
+ case ParamTypestateAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid_enum");
+}
+
+static ConsumedState
+mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
+ switch (RTSAttr->getState()) {
+ case ReturnTypestateAttr::Unknown:
+ return CS_Unknown;
+ case ReturnTypestateAttr::Unconsumed:
+ return CS_Unconsumed;
+ case ReturnTypestateAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid enum");
+}
+
+static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
+ switch (STAttr->getNewState()) {
+ case SetTypestateAttr::Unknown:
+ return CS_Unknown;
+ case SetTypestateAttr::Unconsumed:
+ return CS_Unconsumed;
+ case SetTypestateAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid_enum");
+}
+
+static StringRef stateToString(ConsumedState State) {
+ switch (State) {
+ case consumed::CS_None:
+ return "none";
+
+ case consumed::CS_Unknown:
+ return "unknown";
+
+ case consumed::CS_Unconsumed:
+ return "unconsumed";
+
+ case consumed::CS_Consumed:
+ return "consumed";
+ }
+ llvm_unreachable("invalid enum");
+}
+
+static ConsumedState testsFor(const FunctionDecl *FunDecl) {
+ assert(isTestingFunction(FunDecl));
+ switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
+ case TestTypestateAttr::Unconsumed:
+ return CS_Unconsumed;
+ case TestTypestateAttr::Consumed:
+ return CS_Consumed;
+ }
+ llvm_unreachable("invalid enum");
+}
+
+namespace {
+struct VarTestResult {
+ const VarDecl *Var;
+ ConsumedState TestsFor;
+};
+} // end anonymous::VarTestResult
+
+namespace clang {
+namespace consumed {
+
+enum EffectiveOp {
+ EO_And,
+ EO_Or
+};
+
+class PropagationInfo {
+ enum {
+ IT_None,
+ IT_State,
+ IT_VarTest,
+ IT_BinTest,
+ IT_Var,
+ IT_Tmp
+ } InfoType;
+
+ struct BinTestTy {
+ const BinaryOperator *Source;
+ EffectiveOp EOp;
+ VarTestResult LTest;
+ VarTestResult RTest;
+ };
+
+ union {
+ ConsumedState State;
+ VarTestResult VarTest;
+ const VarDecl *Var;
+ const CXXBindTemporaryExpr *Tmp;
+ BinTestTy BinTest;
+ };
+
+public:
+ PropagationInfo() : InfoType(IT_None) {}
+
+ PropagationInfo(const VarTestResult &VarTest)
+ : InfoType(IT_VarTest), VarTest(VarTest) {}
+
+ PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
+ : InfoType(IT_VarTest) {
+
+ VarTest.Var = Var;
+ VarTest.TestsFor = TestsFor;
+ }
+
+ PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
+ const VarTestResult &LTest, const VarTestResult &RTest)
+ : InfoType(IT_BinTest) {
+
+ BinTest.Source = Source;
+ BinTest.EOp = EOp;
+ BinTest.LTest = LTest;
+ BinTest.RTest = RTest;
+ }
+
+ PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
+ const VarDecl *LVar, ConsumedState LTestsFor,
+ const VarDecl *RVar, ConsumedState RTestsFor)
+ : InfoType(IT_BinTest) {
+
+ BinTest.Source = Source;
+ BinTest.EOp = EOp;
+ BinTest.LTest.Var = LVar;
+ BinTest.LTest.TestsFor = LTestsFor;
+ BinTest.RTest.Var = RVar;
+ BinTest.RTest.TestsFor = RTestsFor;
+ }
+
+ PropagationInfo(ConsumedState State)
+ : InfoType(IT_State), State(State) {}
+
+ PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
+ PropagationInfo(const CXXBindTemporaryExpr *Tmp)
+ : InfoType(IT_Tmp), Tmp(Tmp) {}
+
+ const ConsumedState & getState() const {
+ assert(InfoType == IT_State);
+ return State;
+ }
+
+ const VarTestResult & getVarTest() const {
+ assert(InfoType == IT_VarTest);
+ return VarTest;
+ }
+
+ const VarTestResult & getLTest() const {
+ assert(InfoType == IT_BinTest);
+ return BinTest.LTest;
+ }
+
+ const VarTestResult & getRTest() const {
+ assert(InfoType == IT_BinTest);
+ return BinTest.RTest;
+ }
+
+ const VarDecl * getVar() const {
+ assert(InfoType == IT_Var);
+ return Var;
+ }
+
+ const CXXBindTemporaryExpr * getTmp() const {
+ assert(InfoType == IT_Tmp);
+ return Tmp;
+ }
+
+ ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
+ assert(isVar() || isTmp() || isState());
+
+ if (isVar())
+ return StateMap->getState(Var);
+ else if (isTmp())
+ return StateMap->getState(Tmp);
+ else if (isState())
+ return State;
+ else
+ return CS_None;
+ }
+
+ EffectiveOp testEffectiveOp() const {
+ assert(InfoType == IT_BinTest);
+ return BinTest.EOp;
+ }
+
+ const BinaryOperator * testSourceNode() const {
+ assert(InfoType == IT_BinTest);
+ return BinTest.Source;
+ }
+
+ inline bool isValid() const { return InfoType != IT_None; }
+ inline bool isState() const { return InfoType == IT_State; }
+ inline bool isVarTest() const { return InfoType == IT_VarTest; }
+ inline bool isBinTest() const { return InfoType == IT_BinTest; }
+ inline bool isVar() const { return InfoType == IT_Var; }
+ inline bool isTmp() const { return InfoType == IT_Tmp; }
+
+ bool isTest() const {
+ return InfoType == IT_VarTest || InfoType == IT_BinTest;
+ }
+
+ bool isPointerToValue() const {
+ return InfoType == IT_Var || InfoType == IT_Tmp;
+ }
+
+ PropagationInfo invertTest() const {
+ assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
+
+ if (InfoType == IT_VarTest) {
+ return PropagationInfo(VarTest.Var,
+ invertConsumedUnconsumed(VarTest.TestsFor));
+
+ } else if (InfoType == IT_BinTest) {
+ return PropagationInfo(BinTest.Source,
+ BinTest.EOp == EO_And ? EO_Or : EO_And,
+ BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
+ BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
+ } else {
+ return PropagationInfo();
+ }
+ }
+};
+
+static inline void
+setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
+ ConsumedState State) {
+
+ assert(PInfo.isVar() || PInfo.isTmp());
+
+ if (PInfo.isVar())
+ StateMap->setState(PInfo.getVar(), State);
+ else
+ StateMap->setState(PInfo.getTmp(), State);
+}
+
+class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
+
+ typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
+ typedef std::pair<const Stmt *, PropagationInfo> PairType;
+ typedef MapType::iterator InfoEntry;
+ typedef MapType::const_iterator ConstInfoEntry;
+
+ AnalysisDeclContext &AC;
+ ConsumedAnalyzer &Analyzer;
+ ConsumedStateMap *StateMap;
+ MapType PropagationMap;
+ void forwardInfo(const Stmt *From, const Stmt *To);
+ bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
+ void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
+ QualType ReturnType);
+
+public:
+ void checkCallability(const PropagationInfo &PInfo,
+ const FunctionDecl *FunDecl,
+ SourceLocation BlameLoc);
+
+ void VisitBinaryOperator(const BinaryOperator *BinOp);
+ void VisitCallExpr(const CallExpr *Call);
+ void VisitCastExpr(const CastExpr *Cast);
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
+ void VisitCXXConstructExpr(const CXXConstructExpr *Call);
+ void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
+ void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
+ void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
+ void VisitDeclStmt(const DeclStmt *DelcS);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
+ void VisitMemberExpr(const MemberExpr *MExpr);
+ void VisitParmVarDecl(const ParmVarDecl *Param);
+ void VisitReturnStmt(const ReturnStmt *Ret);
+ void VisitUnaryOperator(const UnaryOperator *UOp);
+ void VisitVarDecl(const VarDecl *Var);
+
+ ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
+ ConsumedStateMap *StateMap)
+ : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
+
+ PropagationInfo getInfo(const Stmt *StmtNode) const {
+ ConstInfoEntry Entry = PropagationMap.find(StmtNode);
+
+ if (Entry != PropagationMap.end())
+ return Entry->second;
+ else
+ return PropagationInfo();
+ }
+
+ void reset(ConsumedStateMap *NewStateMap) {
+ StateMap = NewStateMap;
+ }
+};
+
+void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
+ const FunctionDecl *FunDecl,
+ SourceLocation BlameLoc) {
+ assert(!PInfo.isTest());
+
+ if (!FunDecl->hasAttr<CallableWhenAttr>())
+ return;
+
+ const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
+
+ if (PInfo.isVar()) {
+ ConsumedState VarState = StateMap->getState(PInfo.getVar());
+
+ if (VarState == CS_None || isCallableInState(CWAttr, VarState))
+ return;
+
+ Analyzer.WarningsHandler.warnUseInInvalidState(
+ FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
+ stateToString(VarState), BlameLoc);
+
+ } else {
+ ConsumedState TmpState = PInfo.getAsState(StateMap);
+
+ if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
+ return;
+
+ Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
+ FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
+ }
+}
+
+void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
+ InfoEntry Entry = PropagationMap.find(From);
+
+ if (Entry != PropagationMap.end())
+ PropagationMap.insert(PairType(To, Entry->second));
+}
+
+bool ConsumedStmtVisitor::isLikeMoveAssignment(
+ const CXXMethodDecl *MethodDecl) {
+
+ return MethodDecl->isMoveAssignmentOperator() ||
+ (MethodDecl->getOverloadedOperator() == OO_Equal &&
+ MethodDecl->getNumParams() == 1 &&
+ MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
+}
+
+void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
+ const FunctionDecl *Fun,
+ QualType ReturnType) {
+ if (isConsumableType(ReturnType)) {
+
+ ConsumedState ReturnState;
+
+ if (Fun->hasAttr<ReturnTypestateAttr>())
+ ReturnState = mapReturnTypestateAttrState(
+ Fun->getAttr<ReturnTypestateAttr>());
+ else
+ ReturnState = mapConsumableAttrState(ReturnType);
+
+ PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
+ }
+}
+
+void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
+ switch (BinOp->getOpcode()) {
+ case BO_LAnd:
+ case BO_LOr : {
+ InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
+ REntry = PropagationMap.find(BinOp->getRHS());
+
+ VarTestResult LTest, RTest;
+
+ if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
+ LTest = LEntry->second.getVarTest();
+
+ } else {
+ LTest.Var = NULL;
+ LTest.TestsFor = CS_None;
+ }
+
+ if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
+ RTest = REntry->second.getVarTest();
+
+ } else {
+ RTest.Var = NULL;
+ RTest.TestsFor = CS_None;
+ }
+
+ if (!(LTest.Var == NULL && RTest.Var == NULL))
+ PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
+ static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
+
+ break;
+ }
+
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ forwardInfo(BinOp->getLHS(), BinOp);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
+ if (const FunctionDecl *FunDecl =
+ dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
+
+ // Special case for the std::move function.
+ // TODO: Make this more specific. (Deferred)
+ if (FunDecl->getNameAsString() == "move") {
+ forwardInfo(Call->getArg(0), Call);
+ return;
+ }
+
+ unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
+
+ for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
+ const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
+ QualType ParamType = Param->getType();
+
+ InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
+
+ if (Entry == PropagationMap.end() || Entry->second.isTest())
+ continue;
+
+ PropagationInfo PInfo = Entry->second;
+
+ // Check that the parameter is in the correct state.
+
+ if (Param->hasAttr<ParamTypestateAttr>()) {
+ ConsumedState ParamState = PInfo.getAsState(StateMap);
+
+ ConsumedState ExpectedState =
+ mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
+
+ if (ParamState != ExpectedState)
+ Analyzer.WarningsHandler.warnParamTypestateMismatch(
+ Call->getArg(Index - Offset)->getExprLoc(),
+ stateToString(ExpectedState), stateToString(ParamState));
+ }
+
+ if (!(Entry->second.isVar() || Entry->second.isTmp()))
+ continue;
+
+ // Adjust state on the caller side.
+
+ if (isRValueRefish(ParamType)) {
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
+
+ } else if (Param->hasAttr<ReturnTypestateAttr>()) {
+ setStateForVarOrTmp(StateMap, PInfo,
+ mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
+
+ } else if (!isValueType(ParamType) &&
+ !ParamType->getPointeeType().isConstQualified()) {
+
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
+ }
+ }
+
+ QualType RetType = FunDecl->getCallResultType();
+ if (RetType->isReferenceType())
+ RetType = RetType->getPointeeType();
+
+ propagateReturnType(Call, FunDecl, RetType);
+ }
+}
+
+void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
+ forwardInfo(Cast->getSubExpr(), Cast);
+}
+
+void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
+ const CXXBindTemporaryExpr *Temp) {
+
+ InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
+
+ if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
+ StateMap->setState(Temp, Entry->second.getAsState(StateMap));
+ PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
+ }
+}
+
+void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
+ CXXConstructorDecl *Constructor = Call->getConstructor();
+
+ ASTContext &CurrContext = AC.getASTContext();
+ QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
+
+ if (!isConsumableType(ThisType))
+ return;
+
+ // FIXME: What should happen if someone annotates the move constructor?
+ if (Constructor->hasAttr<ReturnTypestateAttr>()) {
+ // TODO: Adjust state of args appropriately.
+
+ ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
+ ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
+ PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
+
+ } else if (Constructor->isDefaultConstructor()) {
+
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(consumed::CS_Consumed)));
+
+ } else if (Constructor->isMoveConstructor()) {
+
+ InfoEntry Entry = PropagationMap.find(Call->getArg(0));
+
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo PInfo = Entry->second;
+
+ if (PInfo.isVar()) {
+ const VarDecl* Var = PInfo.getVar();
+
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(StateMap->getState(Var))));
+
+ StateMap->setState(Var, consumed::CS_Consumed);
+
+ } else if (PInfo.isTmp()) {
+ const CXXBindTemporaryExpr *Tmp = PInfo.getTmp();
+
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(StateMap->getState(Tmp))));
+
+ StateMap->setState(Tmp, consumed::CS_Consumed);
+
+ } else {
+ PropagationMap.insert(PairType(Call, PInfo));
+ }
+ }
+ } else if (Constructor->isCopyConstructor()) {
+ forwardInfo(Call->getArg(0), Call);
+
+ } else {
+ // TODO: Adjust state of args appropriately.
+
+ ConsumedState RetState = mapConsumableAttrState(ThisType);
+ PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
+ }
+}
+
+void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
+ const CXXMemberCallExpr *Call) {
+
+ VisitCallExpr(Call);
+
+ InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
+
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo PInfo = Entry->second;
+ const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
+
+ checkCallability(PInfo, MethodDecl, Call->getExprLoc());
+
+ if (PInfo.isVar()) {
+ if (isTestingFunction(MethodDecl))
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
+ else if (MethodDecl->hasAttr<SetTypestateAttr>())
+ StateMap->setState(PInfo.getVar(),
+ mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
+ } else if (PInfo.isTmp() && MethodDecl->hasAttr<SetTypestateAttr>()) {
+ StateMap->setState(PInfo.getTmp(),
+ mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
+ }
+ }
+}
+
+void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
+ const CXXOperatorCallExpr *Call) {
+
+ const FunctionDecl *FunDecl =
+ dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
+
+ if (!FunDecl) return;
+
+ if (isa<CXXMethodDecl>(FunDecl) &&
+ isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
+
+ InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
+ InfoEntry REntry = PropagationMap.find(Call->getArg(1));
+
+ PropagationInfo LPInfo, RPInfo;
+
+ if (LEntry != PropagationMap.end() &&
+ REntry != PropagationMap.end()) {
+
+ LPInfo = LEntry->second;
+ RPInfo = REntry->second;
+
+ if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) {
+ setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap));
+ PropagationMap.insert(PairType(Call, LPInfo));
+ setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
+
+ } else if (RPInfo.isState()) {
+ setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState());
+ PropagationMap.insert(PairType(Call, LPInfo));
+
+ } else {
+ setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
+ }
+
+ } else if (LEntry != PropagationMap.end() &&
+ REntry == PropagationMap.end()) {
+
+ LPInfo = LEntry->second;
+
+ assert(!LPInfo.isTest());
+
+ if (LPInfo.isPointerToValue()) {
+ setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown);
+ PropagationMap.insert(PairType(Call, LPInfo));
+
+ } else {
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(consumed::CS_Unknown)));
+ }
+
+ } else if (LEntry == PropagationMap.end() &&
+ REntry != PropagationMap.end()) {
+
+ RPInfo = REntry->second;
+
+ if (RPInfo.isPointerToValue())
+ setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
+ }
+
+ } else {
+
+ VisitCallExpr(Call);
+
+ InfoEntry Entry = PropagationMap.find(Call->getArg(0));
+
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo PInfo = Entry->second;
+
+ checkCallability(PInfo, FunDecl, Call->getExprLoc());
+
+ if (PInfo.isVar()) {
+ if (isTestingFunction(FunDecl))
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
+ else if (FunDecl->hasAttr<SetTypestateAttr>())
+ StateMap->setState(PInfo.getVar(),
+ mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
+
+ } else if (PInfo.isTmp() && FunDecl->hasAttr<SetTypestateAttr>()) {
+ StateMap->setState(PInfo.getTmp(),
+ mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
+ }
+ }
+ }
+}
+
+void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
+ if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
+ if (StateMap->getState(Var) != consumed::CS_None)
+ PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
+}
+
+void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
+ for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
+ DE = DeclS->decl_end(); DI != DE; ++DI) {
+
+ if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
+ }
+
+ if (DeclS->isSingleDecl())
+ if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
+ PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
+}
+
+void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *Temp) {
+
+ forwardInfo(Temp->GetTemporaryExpr(), Temp);
+}
+
+void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
+ forwardInfo(MExpr->getBase(), MExpr);
+}
+
+
+void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
+ QualType ParamType = Param->getType();
+ ConsumedState ParamState = consumed::CS_None;
+
+ if (Param->hasAttr<ParamTypestateAttr>()) {
+ const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
+ ParamState = mapParamTypestateAttrState(PTAttr);
+
+ } else if (isConsumableType(ParamType)) {
+ ParamState = mapConsumableAttrState(ParamType);
+
+ } else if (isRValueRefish(ParamType) &&
+ isConsumableType(ParamType->getPointeeType())) {
+
+ ParamState = mapConsumableAttrState(ParamType->getPointeeType());
+
+ } else if (ParamType->isReferenceType() &&
+ isConsumableType(ParamType->getPointeeType())) {
+ ParamState = consumed::CS_Unknown;
+ }
+
+ if (ParamState != CS_None)
+ StateMap->setState(Param, ParamState);
+}
+
+void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
+ ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
+
+ if (ExpectedState != CS_None) {
+ InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
+
+ if (Entry != PropagationMap.end()) {
+ ConsumedState RetState = Entry->second.getAsState(StateMap);
+
+ if (RetState != ExpectedState)
+ Analyzer.WarningsHandler.warnReturnTypestateMismatch(
+ Ret->getReturnLoc(), stateToString(ExpectedState),
+ stateToString(RetState));
+ }
+ }
+
+ StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
+ Analyzer.WarningsHandler);
+}
+
+void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
+ InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
+ if (Entry == PropagationMap.end()) return;
+
+ switch (UOp->getOpcode()) {
+ case UO_AddrOf:
+ PropagationMap.insert(PairType(UOp, Entry->second));
+ break;
+
+ case UO_LNot:
+ if (Entry->second.isTest())
+ PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
+ break;
+
+ default:
+ break;
+ }
+}
+
+// TODO: See if I need to check for reference types here.
+void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
+ if (isConsumableType(Var->getType())) {
+ if (Var->hasInit()) {
+ MapType::iterator VIT = PropagationMap.find(
+ Var->getInit()->IgnoreImplicit());
+ if (VIT != PropagationMap.end()) {
+ PropagationInfo PInfo = VIT->second;
+ ConsumedState St = PInfo.getAsState(StateMap);
+
+ if (St != consumed::CS_None) {
+ StateMap->setState(Var, St);
+ return;
+ }
+ }
+ }
+ // Otherwise
+ StateMap->setState(Var, consumed::CS_Unknown);
+ }
+}
+}} // end clang::consumed::ConsumedStmtVisitor
+
+namespace clang {
+namespace consumed {
+
+void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
+ ConsumedStateMap *ThenStates,
+ ConsumedStateMap *ElseStates) {
+
+ ConsumedState VarState = ThenStates->getState(Test.Var);
+
+ if (VarState == CS_Unknown) {
+ ThenStates->setState(Test.Var, Test.TestsFor);
+ ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
+
+ } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
+ ThenStates->markUnreachable();
+
+ } else if (VarState == Test.TestsFor) {
+ ElseStates->markUnreachable();
+ }
+}
+
+void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
+ ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
+
+ const VarTestResult &LTest = PInfo.getLTest(),
+ &RTest = PInfo.getRTest();
+
+ ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
+ RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
+
+ if (LTest.Var) {
+ if (PInfo.testEffectiveOp() == EO_And) {
+ if (LState == CS_Unknown) {
+ ThenStates->setState(LTest.Var, LTest.TestsFor);
+
+ } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
+ ThenStates->markUnreachable();
+
+ } else if (LState == LTest.TestsFor && isKnownState(RState)) {
+ if (RState == RTest.TestsFor)
+ ElseStates->markUnreachable();
+ else
+ ThenStates->markUnreachable();
+ }
+
+ } else {
+ if (LState == CS_Unknown) {
+ ElseStates->setState(LTest.Var,
+ invertConsumedUnconsumed(LTest.TestsFor));
+
+ } else if (LState == LTest.TestsFor) {
+ ElseStates->markUnreachable();
+
+ } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
+ isKnownState(RState)) {
+
+ if (RState == RTest.TestsFor)
+ ElseStates->markUnreachable();
+ else
+ ThenStates->markUnreachable();
+ }
+ }
+ }
+
+ if (RTest.Var) {
+ if (PInfo.testEffectiveOp() == EO_And) {
+ if (RState == CS_Unknown)
+ ThenStates->setState(RTest.Var, RTest.TestsFor);
+ else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
+ ThenStates->markUnreachable();
+
+ } else {
+ if (RState == CS_Unknown)
+ ElseStates->setState(RTest.Var,
+ invertConsumedUnconsumed(RTest.TestsFor));
+ else if (RState == RTest.TestsFor)
+ ElseStates->markUnreachable();
+ }
+ }
+}
+
+bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
+ const CFGBlock *TargetBlock) {
+
+ assert(CurrBlock && "Block pointer must not be NULL");
+ assert(TargetBlock && "TargetBlock pointer must not be NULL");
+
+ unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
+ for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
+ PE = TargetBlock->pred_end(); PI != PE; ++PI) {
+ if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
+ return false;
+ }
+ return true;
+}
+
+void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
+ ConsumedStateMap *StateMap,
+ bool &AlreadyOwned) {
+
+ assert(Block && "Block pointer must not be NULL");
+
+ ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
+
+ if (Entry) {
+ Entry->intersect(StateMap);
+
+ } else if (AlreadyOwned) {
+ StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
+
+ } else {
+ StateMapsArray[Block->getBlockID()] = StateMap;
+ AlreadyOwned = true;
+ }
+}
+
+void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
+ ConsumedStateMap *StateMap) {
+
+ assert(Block != NULL && "Block pointer must not be NULL");
+
+ ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
+
+ if (Entry) {
+ Entry->intersect(StateMap);
+ delete StateMap;
+
+ } else {
+ StateMapsArray[Block->getBlockID()] = StateMap;
+ }
+}
+
+ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
+ assert(Block && "Block pointer must not be NULL");
+ assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
+
+ return StateMapsArray[Block->getBlockID()];
+}
+
+void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
+ unsigned int BlockID = Block->getBlockID();
+ delete StateMapsArray[BlockID];
+ StateMapsArray[BlockID] = NULL;
+}
+
+ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
+ assert(Block && "Block pointer must not be NULL");
+
+ ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
+ if (isBackEdgeTarget(Block)) {
+ return new ConsumedStateMap(*StateMap);
+ } else {
+ StateMapsArray[Block->getBlockID()] = NULL;
+ return StateMap;
+ }
+}
+
+bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
+ assert(From && "From block must not be NULL");
+ assert(To && "From block must not be NULL");
+
+ return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
+}
+
+bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
+ assert(Block != NULL && "Block pointer must not be NULL");
+
+ // Anything with less than two predecessors can't be the target of a back
+ // edge.
+ if (Block->pred_size() < 2)
+ return false;
+
+ unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
+ for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
+ PE = Block->pred_end(); PI != PE; ++PI) {
+ if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
+ return true;
+ }
+ return false;
+}
+
+void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
+ ConsumedWarningsHandlerBase &WarningsHandler) const {
+
+ ConsumedState ExpectedState;
+
+ for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
+ DMI != DME; ++DMI) {
+
+ if (isa<ParmVarDecl>(DMI->first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+
+ if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
+
+ ExpectedState =
+ mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
+
+ if (DMI->second != ExpectedState) {
+ WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
+ Param->getNameAsString(), stateToString(ExpectedState),
+ stateToString(DMI->second));
+ }
+ }
+ }
+}
+
+void ConsumedStateMap::clearTemporaries() {
+ TmpMap.clear();
+}
+
+ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
+ VarMapType::const_iterator Entry = VarMap.find(Var);
+
+ if (Entry != VarMap.end())
+ return Entry->second;
+
+ return CS_None;
+}
+
+ConsumedState
+ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
+ TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
+
+ if (Entry != TmpMap.end())
+ return Entry->second;
+
+ return CS_None;
+}
+
+void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
+ ConsumedState LocalState;
+
+ if (this->From && this->From == Other->From && !Other->Reachable) {
+ this->markUnreachable();
+ return;
+ }
+
+ for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
+ DME = Other->VarMap.end(); DMI != DME; ++DMI) {
+
+ LocalState = this->getState(DMI->first);
+
+ if (LocalState == CS_None)
+ continue;
+
+ if (LocalState != DMI->second)
+ VarMap[DMI->first] = CS_Unknown;
+ }
+}
+
+void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
+ const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
+ ConsumedWarningsHandlerBase &WarningsHandler) {
+
+ ConsumedState LocalState;
+ SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
+
+ for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
+ DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
+
+ LocalState = this->getState(DMI->first);
+
+ if (LocalState == CS_None)
+ continue;
+
+ if (LocalState != DMI->second) {
+ VarMap[DMI->first] = CS_Unknown;
+ WarningsHandler.warnLoopStateMismatch(
+ BlameLoc, DMI->first->getNameAsString());
+ }
+ }
+}
+
+void ConsumedStateMap::markUnreachable() {
+ this->Reachable = false;
+ VarMap.clear();
+ TmpMap.clear();
+}
+
+void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
+ VarMap[Var] = State;
+}
+
+void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
+ ConsumedState State) {
+ TmpMap[Tmp] = State;
+}
+
+void ConsumedStateMap::remove(const VarDecl *Var) {
+ VarMap.erase(Var);
+}
+
+bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
+ for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
+ DME = Other->VarMap.end(); DMI != DME; ++DMI) {
+
+ if (this->getState(DMI->first) != DMI->second)
+ return true;
+ }
+
+ return false;
+}
+
+void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
+ const FunctionDecl *D) {
+ QualType ReturnType;
+ if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ ASTContext &CurrContext = AC.getASTContext();
+ ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
+ } else
+ ReturnType = D->getCallResultType();
+
+ if (D->hasAttr<ReturnTypestateAttr>()) {
+ const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
+
+ const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
+ if (!RD || !RD->hasAttr<ConsumableAttr>()) {
+ // FIXME: This should be removed when template instantiation propagates
+ // attributes at template specialization definition, not
+ // declaration. When it is removed the test needs to be enabled
+ // in SemaDeclAttr.cpp.
+ WarningsHandler.warnReturnTypestateForUnconsumableType(
+ RTSAttr->getLocation(), ReturnType.getAsString());
+ ExpectedReturnState = CS_None;
+ } else
+ ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
+ } else if (isConsumableType(ReturnType))
+ ExpectedReturnState = mapConsumableAttrState(ReturnType);
+ else
+ ExpectedReturnState = CS_None;
+}
+
+bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
+ const ConsumedStmtVisitor &Visitor) {
+
+ OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
+ PropagationInfo PInfo;
+
+ if (const IfStmt *IfNode =
+ dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
+
+ const Stmt *Cond = IfNode->getCond();
+
+ PInfo = Visitor.getInfo(Cond);
+ if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
+ PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
+
+ if (PInfo.isVarTest()) {
+ CurrStates->setSource(Cond);
+ FalseStates->setSource(Cond);
+ splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
+ FalseStates.get());
+
+ } else if (PInfo.isBinTest()) {
+ CurrStates->setSource(PInfo.testSourceNode());
+ FalseStates->setSource(PInfo.testSourceNode());
+ splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
+
+ } else {
+ return false;
+ }
+
+ } else if (const BinaryOperator *BinOp =
+ dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
+
+ PInfo = Visitor.getInfo(BinOp->getLHS());
+ if (!PInfo.isVarTest()) {
+ if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
+ PInfo = Visitor.getInfo(BinOp->getRHS());
+
+ if (!PInfo.isVarTest())
+ return false;
+
+ } else {
+ return false;
+ }
+ }
+
+ CurrStates->setSource(BinOp);
+ FalseStates->setSource(BinOp);
+
+ const VarTestResult &Test = PInfo.getVarTest();
+ ConsumedState VarState = CurrStates->getState(Test.Var);
+
+ if (BinOp->getOpcode() == BO_LAnd) {
+ if (VarState == CS_Unknown)
+ CurrStates->setState(Test.Var, Test.TestsFor);
+ else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
+ CurrStates->markUnreachable();
+
+ } else if (BinOp->getOpcode() == BO_LOr) {
+ if (VarState == CS_Unknown)
+ FalseStates->setState(Test.Var,
+ invertConsumedUnconsumed(Test.TestsFor));
+ else if (VarState == Test.TestsFor)
+ FalseStates->markUnreachable();
+ }
+
+ } else {
+ return false;
+ }
+
+ CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
+
+ if (*SI)
+ BlockInfo.addInfo(*SI, CurrStates);
+ else
+ delete CurrStates;
+
+ if (*++SI)
+ BlockInfo.addInfo(*SI, FalseStates.take());
+
+ CurrStates = NULL;
+ return true;
+}
+
+void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
+ const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
+ if (!D)
+ return;
+
+ CFG *CFGraph = AC.getCFG();
+ if (!CFGraph)
+ return;
+
+ determineExpectedReturnState(AC, D);
+
+ PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ // AC.getCFG()->viewCFG(LangOptions());
+
+ BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
+
+ CurrStates = new ConsumedStateMap();
+ ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
+
+ // Add all trackable parameters to the state map.
+ for (FunctionDecl::param_const_iterator PI = D->param_begin(),
+ PE = D->param_end(); PI != PE; ++PI) {
+ Visitor.VisitParmVarDecl(*PI);
+ }
+
+ // Visit all of the function's basic blocks.
+ for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+ E = SortedGraph->end(); I != E; ++I) {
+
+ const CFGBlock *CurrBlock = *I;
+
+ if (CurrStates == NULL)
+ CurrStates = BlockInfo.getInfo(CurrBlock);
+
+ if (!CurrStates) {
+ continue;
+
+ } else if (!CurrStates->isReachable()) {
+ delete CurrStates;
+ CurrStates = NULL;
+ continue;
+ }
+
+ Visitor.reset(CurrStates);
+
+ // Visit all of the basic block's statements.
+ for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+ BE = CurrBlock->end(); BI != BE; ++BI) {
+
+ switch (BI->getKind()) {
+ case CFGElement::Statement:
+ Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
+ break;
+
+ case CFGElement::TemporaryDtor: {
+ const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
+
+ Visitor.checkCallability(PropagationInfo(BTE),
+ DTor.getDestructorDecl(AC.getASTContext()),
+ BTE->getExprLoc());
+ break;
+ }
+
+ case CFGElement::AutomaticObjectDtor: {
+ const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
+ SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
+ const VarDecl *Var = DTor.getVarDecl();
+
+ Visitor.checkCallability(PropagationInfo(Var),
+ DTor.getDestructorDecl(AC.getASTContext()),
+ Loc);
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ CurrStates->clearTemporaries();
+
+ // TODO: Handle other forms of branching with precision, including while-
+ // and for-loops. (Deferred)
+ if (!splitState(CurrBlock, Visitor)) {
+ CurrStates->setSource(NULL);
+
+ if (CurrBlock->succ_size() > 1 ||
+ (CurrBlock->succ_size() == 1 &&
+ (*CurrBlock->succ_begin())->pred_size() > 1)) {
+
+ bool OwnershipTaken = false;
+
+ for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+ SE = CurrBlock->succ_end(); SI != SE; ++SI) {
+
+ if (*SI == NULL) continue;
+
+ if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
+ BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
+ CurrStates,
+ WarningsHandler);
+
+ if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
+ BlockInfo.discardInfo(*SI);
+ } else {
+ BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
+ }
+ }
+
+ if (!OwnershipTaken)
+ delete CurrStates;
+
+ CurrStates = NULL;
+ }
+ }
+
+ if (CurrBlock == &AC.getCFG()->getExit() &&
+ D->getCallResultType()->isVoidType())
+ CurrStates->checkParamsForReturnTypestate(D->getLocation(),
+ WarningsHandler);
+ } // End of block iterator.
+
+ // Delete the last existing state map.
+ delete CurrStates;
+
+ WarningsHandler.emitDiagnostics();
+}
+}} // end namespace clang::consumed
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index ad0dce4444b6..43ecc6682e3f 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -223,6 +223,27 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
break;
}
return false;
+ // printf: AsInt64, AsInt32, AsInt3264
+ // scanf: AsInt64
+ case 'I':
+ if (I + 1 != E && I + 2 != E) {
+ if (I[1] == '6' && I[2] == '4') {
+ I += 3;
+ lmKind = LengthModifier::AsInt64;
+ break;
+ }
+ if (IsScanf)
+ return false;
+
+ if (I[1] == '3' && I[2] == '2') {
+ I += 3;
+ lmKind = LengthModifier::AsInt32;
+ break;
+ }
+ }
+ ++I;
+ lmKind = LengthModifier::AsInt3264;
+ break;
}
LengthModifier lm(lmPosition, lmKind);
FS.setLengthModifier(lm);
@@ -334,7 +355,7 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const {
return false;
QualType pointeeTy =
C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
- return pointeeTy == C.getWCharType();
+ return pointeeTy == C.getWideCharType();
}
case WIntTy: {
@@ -398,7 +419,7 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const {
Res = C.getPointerType(C.CharTy);
break;
case WCStrTy:
- Res = C.getPointerType(C.getWCharType());
+ Res = C.getPointerType(C.getWideCharType());
break;
case ObjCPointerTy:
Res = C.ObjCBuiltinIdTy;
@@ -471,6 +492,12 @@ analyze_format_string::LengthModifier::toString() const {
return "z";
case AsPtrDiff:
return "t";
+ case AsInt32:
+ return "I32";
+ case AsInt3264:
+ return "I";
+ case AsInt64:
+ return "I64";
case AsLongDouble:
return "L";
case AsAllocate:
@@ -514,7 +541,7 @@ const char *ConversionSpecifier::toString() const {
case ScanListArg: return "[";
case InvalidSpecifier: return NULL;
- // MacOS X unicode extensions.
+ // POSIX unicode extensions.
case CArg: return "C";
case SArg: return "S";
@@ -678,6 +705,20 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
default:
return false;
}
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
+ case LengthModifier::AsInt64:
+ switch (CS.getKind()) {
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ case ConversionSpecifier::oArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::xArg:
+ case ConversionSpecifier::XArg:
+ return Target.getTriple().isOSMSVCRT();
+ default:
+ return false;
+ }
}
llvm_unreachable("Invalid LengthModifier Kind!");
}
@@ -697,6 +738,9 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
case LengthModifier::AsQuad:
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
+ case LengthModifier::AsInt64:
return false;
}
llvm_unreachable("Invalid LengthModifier Kind!");
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index b43892a30938..9e5ec557bca2 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -87,8 +87,7 @@ void DataflowWorklist::sortWorklist() {
const CFGBlock *DataflowWorklist::dequeue() {
if (worklist.empty())
return 0;
- const CFGBlock *b = worklist.back();
- worklist.pop_back();
+ const CFGBlock *b = worklist.pop_back_val();
enqueuedBlocks[b->getBlockID()] = false;
return b;
}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 8f151b9358e6..f21b407bcb51 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -187,8 +187,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case 'i': k = ConversionSpecifier::iArg; break;
case 'n': k = ConversionSpecifier::nArg; break;
case 'o': k = ConversionSpecifier::oArg; break;
- case 'p': k = ConversionSpecifier::pArg; break;
- case 's': k = ConversionSpecifier::sArg; break;
+ case 'p': k = ConversionSpecifier::pArg; break;
+ case 's': k = ConversionSpecifier::sArg; break;
case 'u': k = ConversionSpecifier::uArg; break;
case 'x': k = ConversionSpecifier::xArg; break;
// POSIX specific.
@@ -278,18 +278,27 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsLongDouble:
// GNU extension.
return Ctx.LongLongTy;
- case LengthModifier::None: return Ctx.IntTy;
+ case LengthModifier::None:
+ return Ctx.IntTy;
+ case LengthModifier::AsInt32:
+ return ArgType(Ctx.IntTy, "__int32");
case LengthModifier::AsChar: return ArgType::AnyCharTy;
case LengthModifier::AsShort: return Ctx.ShortTy;
case LengthModifier::AsLong: return Ctx.LongTy;
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
return Ctx.LongLongTy;
+ case LengthModifier::AsInt64:
+ return ArgType(Ctx.LongLongTy, "__int64");
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();
+ case LengthModifier::AsInt3264:
+ return Ctx.getTargetInfo().getTriple().isArch64Bit()
+ ? ArgType(Ctx.LongLongTy, "__int64")
+ : ArgType(Ctx.IntTy, "__int32");
case LengthModifier::AsPtrDiff:
return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
case LengthModifier::AsAllocate:
@@ -302,17 +311,26 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsLongDouble:
// GNU extension.
return Ctx.UnsignedLongLongTy;
- case LengthModifier::None: return Ctx.UnsignedIntTy;
+ case LengthModifier::None:
+ return Ctx.UnsignedIntTy;
+ case LengthModifier::AsInt32:
+ return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
return Ctx.UnsignedLongLongTy;
+ case LengthModifier::AsInt64:
+ return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
case LengthModifier::AsIntMax:
return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
case LengthModifier::AsSizeT:
return ArgType(Ctx.getSizeType(), "size_t");
+ case LengthModifier::AsInt3264:
+ return Ctx.getTargetInfo().getTriple().isArch64Bit()
+ ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
+ : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
case LengthModifier::AsPtrDiff:
// FIXME: How to get the corresponding unsigned
// version of ptrdiff_t?
@@ -351,6 +369,9 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
return ArgType(); // FIXME: Is this a known extension?
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
+ case LengthModifier::AsInt64:
return ArgType::Invalid();
}
}
@@ -372,7 +393,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case ConversionSpecifier::CArg:
if (IsObjCLiteral)
return ArgType(Ctx.UnsignedShortTy, "unichar");
- return ArgType(Ctx.WCharTy, "wchar_t");
+ return ArgType(Ctx.WideCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgType::CPointerTy;
case ConversionSpecifier::ObjCObjArg:
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index a90aebbe28ed..a2d19c050829 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -110,10 +110,13 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
return 0;
}
-static int SrcCmp(const void *p1, const void *p2) {
- return
- ((const std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
- ((const std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
+static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
+ const std::pair<const CFGBlock *, const Stmt *> *p2) {
+ if (p1->second->getLocStart() < p2->second->getLocStart())
+ return -1;
+ if (p2->second->getLocStart() < p1->second->getLocStart())
+ return 1;
+ return 0;
}
unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
@@ -227,7 +230,7 @@ static SourceLocation GetUnreachableLoc(const Stmt *S,
case Expr::CXXFunctionalCastExprClass: {
const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
R1 = CE->getSubExpr()->getSourceRange();
- return CE->getTypeBeginLoc();
+ return CE->getLocStart();
}
case Stmt::CXXTryStmtClass: {
return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 2dbc9e494881..f5ce84fe3615 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -232,6 +232,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
return ArgType::PtrTo(Ctx.LongLongTy);
+ case LengthModifier::AsInt64:
+ return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
@@ -243,8 +245,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// GNU extension.
return ArgType::PtrTo(Ctx.LongLongTy);
case LengthModifier::AsAllocate:
- return ArgType::Invalid();
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
return ArgType::Invalid();
}
@@ -267,6 +270,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
+ case LengthModifier::AsInt64:
+ return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
case LengthModifier::AsSizeT:
@@ -278,8 +283,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// GNU extension.
return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
case LengthModifier::AsAllocate:
- return ArgType::Invalid();
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
return ArgType::Invalid();
}
@@ -311,7 +317,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::None:
return ArgType::PtrTo(ArgType::AnyCharTy);
case LengthModifier::AsLong:
- return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType::CStrTy);
@@ -323,7 +329,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// FIXME: Mac OS X specific?
switch (LM.getKind()) {
case LengthModifier::None:
- return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
@@ -349,6 +355,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
return ArgType::PtrTo(Ctx.LongLongTy);
+ case LengthModifier::AsInt64:
+ return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
@@ -359,6 +367,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
return ArgType(); // FIXME: Is this a known extension?
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsInt32:
+ case LengthModifier::AsInt3264:
return ArgType::Invalid();
}
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 479d9a301f4b..6e0e1732bae9 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -10,8 +10,8 @@
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
// conditions), based off of an annotation system.
//
-// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
-// information.
+// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// for more information.
//
//===----------------------------------------------------------------------===//
@@ -266,6 +266,11 @@ private:
return NodeVec.size()-1;
}
+ inline bool isCalleeArrow(const Expr *E) {
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
+ return ME ? ME->isArrow() : false;
+ }
+
/// Build an SExpr from the given C++ expression.
/// Recursive function that terminates on DeclRefExpr.
/// Note: this function merely creates a SExpr; it does not check to
@@ -323,13 +328,11 @@ private:
} else if (const CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
// When calling a function with a lock_returned attribute, replace
// the function call with the expression in lock_returned.
- const CXXMethodDecl* MD =
- cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
+ const CXXMethodDecl *MD = CMCE->getMethodDecl()->getMostRecentDecl();
if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
- LRCallCtx.SelfArrow =
- dyn_cast<MemberExpr>(CMCE->getCallee())->isArrow();
+ LRCallCtx.SelfArrow = isCalleeArrow(CMCE->getCallee());
LRCallCtx.NumArgs = CMCE->getNumArgs();
LRCallCtx.FunArgs = CMCE->getArgs();
LRCallCtx.PrevCtx = CallCtx;
@@ -339,7 +342,7 @@ private:
// ignore any method named get().
if (CMCE->getMethodDecl()->getNameAsString() == "get" &&
CMCE->getNumArgs() == 0) {
- if (NDeref && dyn_cast<MemberExpr>(CMCE->getCallee())->isArrow())
+ if (NDeref && isCalleeArrow(CMCE->getCallee()))
++(*NDeref);
return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref);
}
@@ -353,8 +356,7 @@ private:
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
} else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- const FunctionDecl* FD =
- cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
+ const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl();
if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
LRCallCtx.NumArgs = CE->getNumArgs();
@@ -498,11 +500,10 @@ private:
} else if (const CXXMemberCallExpr *CE =
dyn_cast<CXXMemberCallExpr>(DeclExp)) {
CallCtx.SelfArg = CE->getImplicitObjectArgument();
- CallCtx.SelfArrow = dyn_cast<MemberExpr>(CE->getCallee())->isArrow();
+ CallCtx.SelfArrow = isCalleeArrow(CE->getCallee());
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
- } else if (const CallExpr *CE =
- dyn_cast<CallExpr>(DeclExp)) {
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (const CXXConstructExpr *CE =
@@ -750,16 +751,18 @@ struct LockData {
///
/// FIXME: add support for re-entrant locking and lock up/downgrading
LockKind LKind;
+ bool Asserted; // for asserted locks
bool Managed; // for ScopedLockable objects
SExpr UnderlyingMutex; // for ScopedLockable objects
- LockData(SourceLocation AcquireLoc, LockKind LKind, bool M = false)
- : AcquireLoc(AcquireLoc), LKind(LKind), Managed(M),
+ LockData(SourceLocation AcquireLoc, LockKind LKind, bool M=false,
+ bool Asrt=false)
+ : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(Asrt), Managed(M),
UnderlyingMutex(Decl::EmptyShell())
{}
LockData(SourceLocation AcquireLoc, LockKind LKind, const SExpr &Mu)
- : AcquireLoc(AcquireLoc), LKind(LKind), Managed(false),
+ : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(false), Managed(false),
UnderlyingMutex(Mu)
{}
@@ -864,6 +867,16 @@ public:
return false;
}
+ // Returns an iterator
+ iterator findLockIter(FactManager &FM, const SExpr &M) {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M))
+ return I;
+ }
+ return end();
+ }
+
LockData* findLock(FactManager &FM, const SExpr &M) const {
for (const_iterator I = begin(), E = end(); I != E; ++I) {
const SExpr &Exp = FM[*I].MutID;
@@ -1484,7 +1497,8 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
return;
if (FSet.findLock(FactMan, Mutex)) {
- Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
+ if (!LDat.Asserted)
+ Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
} else {
FSet.addLock(FactMan, Mutex, LDat);
}
@@ -1647,15 +1661,22 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
if (!TCond) Negate = !Negate;
return getTrylockCallExpr(BOP->getLHS(), C, Negate);
}
- else if (getStaticBooleanValue(BOP->getLHS(), TCond)) {
+ TCond = false;
+ if (getStaticBooleanValue(BOP->getLHS(), TCond)) {
if (!TCond) Negate = !Negate;
return getTrylockCallExpr(BOP->getRHS(), C, Negate);
}
return 0;
}
+ if (BOP->getOpcode() == BO_LAnd) {
+ // LHS must have been evaluated in a different block.
+ return getTrylockCallExpr(BOP->getRHS(), C, Negate);
+ }
+ if (BOP->getOpcode() == BO_LOr) {
+ return getTrylockCallExpr(BOP->getRHS(), C, Negate);
+ }
return 0;
}
- // FIXME -- handle && and || as well.
return 0;
}
@@ -1669,11 +1690,11 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
const CFGBlock *CurrBlock) {
Result = ExitSet;
- if (!PredBlock->getTerminatorCondition())
+ const Stmt *Cond = PredBlock->getTerminatorCondition();
+ if (!Cond)
return;
bool Negate = false;
- const Stmt *Cond = PredBlock->getTerminatorCondition();
const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->getBlockID()];
const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
@@ -1686,7 +1707,6 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
if(!FunDecl || !FunDecl->hasAttrs())
return;
-
MutexIDList ExclusiveLocksToAdd;
MutexIDList SharedLocksToAdd;
@@ -1858,6 +1878,13 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
return;
}
+ if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(Exp)) {
+ if (Analyzer->Handler.issueBetaWarnings()) {
+ checkPtAccess(AE->getLHS(), AK);
+ return;
+ }
+ }
+
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
if (ME->isArrow())
checkPtAccess(ME->getBase(), AK);
@@ -1881,7 +1908,27 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
- Exp = Exp->IgnoreParenCasts();
+ if (Analyzer->Handler.issueBetaWarnings()) {
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ Exp = PE->getSubExpr();
+ continue;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ if (CE->getCastKind() == CK_ArrayToPointerDecay) {
+ // If it's an actual array, and not a pointer, then it's elements
+ // are protected by GUARDED_BY, not PT_GUARDED_BY;
+ checkAccess(CE->getSubExpr(), AK);
+ return;
+ }
+ Exp = CE->getSubExpr();
+ continue;
+ }
+ break;
+ }
+ }
+ else
+ Exp = Exp->IgnoreParenCasts();
const ValueDecl *D = getValueDecl(Exp);
if (!D || !D->hasAttrs())
@@ -1909,6 +1956,7 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
/// the same signature as const method calls can be also treated as reads.
///
void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
+ SourceLocation Loc = Exp->getExprLoc();
const AttrVec &ArgAttrs = D->getAttrs();
MutexIDList ExclusiveLocksToAdd;
MutexIDList SharedLocksToAdd;
@@ -1933,6 +1981,32 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
break;
}
+ // An assert will add a lock to the lockset, but will not generate
+ // a warning if it is already there, and will not generate a warning
+ // if it is not removed.
+ case attr::AssertExclusiveLock: {
+ AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
+
+ MutexIDList AssertLocks;
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
+ Analyzer->addLock(FSet, AssertLocks[i],
+ LockData(Loc, LK_Exclusive, false, true));
+ }
+ break;
+ }
+ case attr::AssertSharedLock: {
+ AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
+
+ MutexIDList AssertLocks;
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
+ Analyzer->addLock(FSet, AssertLocks[i],
+ LockData(Loc, LK_Shared, false, true));
+ }
+ break;
+ }
+
// When we encounter an unlock function, we need to remove unlocked
// mutexes from the lockset, and flag a warning if they are not there.
case attr::UnlockFunction: {
@@ -1986,7 +2060,6 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
}
// Add locks.
- SourceLocation Loc = Exp->getExprLoc();
for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
Analyzer->addLock(FSet, ExclusiveLocksToAdd[i],
LockData(Loc, LK_Exclusive, isScopedVar));
@@ -2052,6 +2125,7 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
checkAccess(BO->getLHS(), AK_Written);
}
+
/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
/// need to ensure we hold any required mutexes.
/// FIXME: Deal with non-primitive types.
@@ -2091,9 +2165,19 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
checkAccess(Source, AK_Read);
break;
}
+ case OO_Star:
+ case OO_Arrow:
+ case OO_Subscript: {
+ if (Analyzer->Handler.issueBetaWarnings()) {
+ const Expr *Obj = OE->getArg(0);
+ checkAccess(Obj, AK_Read);
+ checkPtAccess(Obj, AK_Read);
+ }
+ break;
+ }
default: {
- const Expr *Source = OE->getArg(0);
- checkAccess(Source, AK_Read);
+ const Expr *Obj = OE->getArg(0);
+ checkAccess(Obj, AK_Read);
break;
}
}
@@ -2160,21 +2244,28 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
bool Modify) {
FactSet FSet1Orig = FSet1;
+ // Find locks in FSet2 that conflict or are not in FSet1, and warn.
for (FactSet::const_iterator I = FSet2.begin(), E = FSet2.end();
I != E; ++I) {
const SExpr &FSet2Mutex = FactMan[*I].MutID;
const LockData &LDat2 = FactMan[*I].LDat;
+ FactSet::iterator I1 = FSet1.findLockIter(FactMan, FSet2Mutex);
- if (const LockData *LDat1 = FSet1.findLock(FactMan, FSet2Mutex)) {
+ if (I1 != FSet1.end()) {
+ const LockData* LDat1 = &FactMan[*I1].LDat;
if (LDat1->LKind != LDat2.LKind) {
Handler.handleExclusiveAndShared(FSet2Mutex.toString(),
LDat2.AcquireLoc,
LDat1->AcquireLoc);
if (Modify && LDat1->LKind != LK_Exclusive) {
- FSet1.removeLock(FactMan, FSet2Mutex);
- FSet1.addLock(FactMan, FSet2Mutex, LDat2);
+ // Take the exclusive lock, which is the one in FSet2.
+ *I1 = *I;
}
}
+ else if (LDat1->Asserted && !LDat2.Asserted) {
+ // The non-asserted lock in FSet2 is the one we want to track.
+ *I1 = *I;
+ }
} else {
if (LDat2.UnderlyingMutex.isValid()) {
if (FSet2.findLock(FactMan, LDat2.UnderlyingMutex)) {
@@ -2186,14 +2277,15 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
+ else if (!LDat2.Managed && !FSet2Mutex.isUniversal() && !LDat2.Asserted)
Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
LDat2.AcquireLoc,
JoinLoc, LEK1);
}
}
- for (FactSet::const_iterator I = FSet1.begin(), E = FSet1.end();
+ // Find locks in FSet1 that are not in FSet2, and remove them.
+ for (FactSet::const_iterator I = FSet1Orig.begin(), E = FSet1Orig.end();
I != E; ++I) {
const SExpr &FSet1Mutex = FactMan[*I].MutID;
const LockData &LDat1 = FactMan[*I].LDat;
@@ -2209,7 +2301,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
+ else if (!LDat1.Managed && !FSet1Mutex.isUniversal() && !LDat1.Asserted)
Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
LDat1.AcquireLoc,
JoinLoc, LEK2);
@@ -2305,8 +2397,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
= dyn_cast<SharedLocksRequiredAttr>(Attr)) {
getMutexIDs(SharedLocksToAdd, A, (Expr*) 0, D);
} else if (UnlockFunctionAttr *A = dyn_cast<UnlockFunctionAttr>(Attr)) {
- if (!Handler.issueBetaWarnings())
- return;
// UNLOCK_FUNCTION() is used to hide the underlying lock implementation.
// We must ignore such methods.
if (A->args_size() == 0)
@@ -2316,15 +2406,11 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
getMutexIDs(LocksReleased, A, (Expr*) 0, D);
} else if (ExclusiveLockFunctionAttr *A
= dyn_cast<ExclusiveLockFunctionAttr>(Attr)) {
- if (!Handler.issueBetaWarnings())
- return;
if (A->args_size() == 0)
return;
getMutexIDs(ExclusiveLocksAcquired, A, (Expr*) 0, D);
} else if (SharedLockFunctionAttr *A
= dyn_cast<SharedLockFunctionAttr>(Attr)) {
- if (!Handler.issueBetaWarnings())
- return;
if (A->args_size() == 0)
return;
getMutexIDs(SharedLocksAcquired, A, (Expr*) 0, D);
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 730aa6ba212c..332c02cf1852 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -14,12 +14,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
+#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/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PackedVector.h"
@@ -240,10 +240,9 @@ const CFGBlock *DataflowWorklist::dequeue() {
// First dequeue from the worklist. This can represent
// updates along backedges that we want propagated as quickly as possible.
- if (!worklist.empty()) {
- B = worklist.back();
- worklist.pop_back();
- }
+ if (!worklist.empty())
+ B = worklist.pop_back_val();
+
// Next dequeue from the initial reverse post order. This is the
// theoretical ideal in the presence of no back edges.
else if (PO_I != PO_E) {
@@ -527,14 +526,29 @@ public:
// of marking it as not being a candidate element of the frontier.
SuccsVisited[block->getBlockID()] = block->succ_size();
while (!Queue.empty()) {
- const CFGBlock *B = Queue.back();
- Queue.pop_back();
+ const CFGBlock *B = Queue.pop_back_val();
+
+ // If the use is always reached from the entry block, make a note of that.
+ if (B == &cfg.getEntry())
+ Use.setUninitAfterCall();
+
for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
I != E; ++I) {
const CFGBlock *Pred = *I;
- if (vals.getValue(Pred, B, vd) == Initialized)
+ Value AtPredExit = vals.getValue(Pred, B, vd);
+ if (AtPredExit == Initialized)
// This block initializes the variable.
continue;
+ if (AtPredExit == MayUninitialized &&
+ vals.getValue(B, 0, vd) == Uninitialized) {
+ // This block declares the variable (uninitialized), and is reachable
+ // from a block that initializes the variable. We can't guarantee to
+ // give an earlier location for the diagnostic (and it appears that
+ // this code is intended to be reachable) so give a diagnostic here
+ // and go no further down this path.
+ Use.setUninitAfterDecl();
+ continue;
+ }
unsigned &SV = SuccsVisited[Pred->getBlockID()];
if (!SV) {
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 242c204d6d80..c84dd6dc38ff 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -16,11 +16,13 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
using namespace clang;
static const Builtin::Info BuiltinInfo[] = {
{ "not a builtin function", 0, 0, 0, ALL_LANGUAGES },
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) { #ID, TYPE, ATTRS, 0, BUILTIN_LANG },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\
BUILTIN_LANG },
#include "clang/Basic/Builtins.def"
@@ -44,6 +46,23 @@ void Builtin::Context::InitializeTarget(const TargetInfo &Target) {
Target.getTargetBuiltins(TSRecords, NumTSRecords);
}
+bool Builtin::Context::BuiltinIsSupported(const Builtin::Info &BuiltinInfo,
+ const LangOptions &LangOpts) {
+ bool BuiltinsUnsupported = LangOpts.NoBuiltin &&
+ strchr(BuiltinInfo.Attributes, 'f');
+ bool MathBuiltinsUnsupported =
+ LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
+ llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
+ bool GnuModeUnsupported = !LangOpts.GNUMode &&
+ (BuiltinInfo.builtin_lang & GNU_LANG);
+ bool MSModeUnsupported = !LangOpts.MicrosoftExt &&
+ (BuiltinInfo.builtin_lang & MS_LANG);
+ bool ObjCUnsupported = !LangOpts.ObjC1 &&
+ BuiltinInfo.builtin_lang == OBJC_LANG;
+ return !BuiltinsUnsupported && !MathBuiltinsUnsupported &&
+ !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported;
+}
+
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
/// such.
@@ -51,10 +70,8 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
const LangOptions& LangOpts) {
// Step #1: mark all target-independent builtins with their ID's.
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
- if (!LangOpts.NoBuiltin || !strchr(BuiltinInfo[i].Attributes, 'f')) {
- if (LangOpts.ObjC1 ||
- BuiltinInfo[i].builtin_lang != clang::OBJC_LANG)
- Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
+ if (BuiltinIsSupported(BuiltinInfo[i], LangOpts)) {
+ Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
}
// Step #2: Register target-specific builtins.
@@ -64,16 +81,15 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
}
void
-Builtin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names,
- bool NoBuiltins) {
+Builtin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names) {
// Final all target-independent names
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
- if (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))
+ if (!strchr(BuiltinInfo[i].Attributes, 'f'))
Names.push_back(BuiltinInfo[i].Name);
// Find target-specific names.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
- if (!NoBuiltins || !strchr(TSRecords[i].Attributes, 'f'))
+ if (!strchr(TSRecords[i].Attributes, 'f'))
Names.push_back(TSRecords[i].Name);
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 353af4bd6df1..9d99fbedd83c 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include <map>
using namespace clang;
@@ -35,11 +36,10 @@ enum {
};
struct StaticDiagInfoRec {
- unsigned short DiagID;
+ uint16_t DiagID;
unsigned Mapping : 3;
unsigned Class : 3;
- unsigned SFINAE : 1;
- unsigned AccessControl : 1;
+ unsigned SFINAE : 2;
unsigned WarnNoWerror : 1;
unsigned WarnShowInSystemHeader : 1;
unsigned Category : 5;
@@ -66,9 +66,9 @@ struct StaticDiagInfoRec {
static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \
- CATEGORY) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, \
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, \
+ DiagnosticIDs::SFINAE, \
NOWERROR, SHOWINSYSHEADER, CATEGORY, GROUP, \
STR_SIZE(DESC, uint16_t), DESC },
#include "clang/Basic/DiagnosticCommonKinds.inc"
@@ -82,18 +82,16 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
-static const unsigned StaticDiagInfoSize =
- sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
+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;
+ static bool IsFirst = true; // So the check is only performed on first call.
if (IsFirst) {
for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
@@ -109,7 +107,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
// Out of bounds diag. Can't be in the table.
using namespace diag;
- if (DiagID >= DIAG_UPPER_LIMIT)
+ if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
return 0;
// Compute the index of the requested diagnostic in the static table.
@@ -121,8 +119,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
// This is cheaper than a binary search on the table as it doesn't touch
// memory at all.
unsigned Offset = 0;
- unsigned ID = DiagID;
-#define DIAG_START_COMMON 0 // Sentinel value.
+ unsigned ID = DiagID - DIAG_START_COMMON - 1;
#define CATEGORY(NAME, PREV) \
if (DiagID > DIAG_START_##NAME) { \
Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
@@ -138,7 +135,6 @@ CATEGORY(COMMENT, AST)
CATEGORY(SEMA, COMMENT)
CATEGORY(ANALYSIS, SEMA)
#undef CATEGORY
-#undef DIAG_START_COMMON
// Avoid out of bounds reads.
if (ID + Offset >= StaticDiagInfoSize)
@@ -224,7 +220,7 @@ static const StaticDiagCategoryRec CategoryNameTable[] = {
/// getNumberOfCategories - Return the number of categories
unsigned DiagnosticIDs::getNumberOfCategories() {
- return sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
+ return llvm::array_lengthof(CategoryNameTable) - 1;
}
/// getCategoryNameFromID - Given a category ID, return the name of the
@@ -238,22 +234,10 @@ StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
-DiagnosticIDs::SFINAEResponse
+DiagnosticIDs::SFINAEResponse
DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
- if (Info->AccessControl)
- return SFINAE_AccessControl;
-
- if (!Info->SFINAE)
- return SFINAE_Report;
-
- if (Info->Class == CLASS_ERROR)
- return SFINAE_SubstitutionFailure;
-
- // Suppress notes, warnings, and extensions;
- return SFINAE_Suppress;
- }
-
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
return SFINAE_Report;
}
@@ -504,36 +488,34 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
return Result;
}
-struct clang::WarningOption {
- // Be safe with the size of 'NameLen' because we don't statically check if
- // the size will fit in the field; the struct size won't decrease with a
- // shorter type anyway.
- size_t NameLen;
- const char *NameStr;
- const short *Members;
- const short *SubGroups;
-
- StringRef getName() const {
- return StringRef(NameStr, NameLen);
- }
-};
-
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_ARRAYS
+namespace {
+ struct WarningOption {
+ uint16_t NameOffset;
+ uint16_t Members;
+ uint16_t SubGroups;
+
+ // String is stored with a pascal-style length byte.
+ StringRef getName() const {
+ return StringRef(DiagGroupNames + NameOffset + 1,
+ DiagGroupNames[NameOffset]);
+ }
+ };
+}
+
// Second the table of options, sorted by name for fast binary lookup.
static const WarningOption OptionTable[] = {
#define GET_DIAG_TABLE
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_TABLE
};
-static const size_t OptionTableSize =
-sizeof(OptionTable) / sizeof(OptionTable[0]);
+static const size_t OptionTableSize = llvm::array_lengthof(OptionTable);
-static bool WarningOptionCompare(const WarningOption &LHS,
- const WarningOption &RHS) {
- return LHS.getName() < RHS.getName();
+static bool WarningOptionCompare(const WarningOption &LHS, StringRef RHS) {
+ return LHS.getName() < RHS;
}
/// getWarningOptionForDiag - Return the lowest-level warning option that
@@ -545,34 +527,30 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return StringRef();
}
-void DiagnosticIDs::getDiagnosticsInGroup(
- const WarningOption *Group,
- SmallVectorImpl<diag::kind> &Diags) const {
+static void getDiagnosticsInGroup(const WarningOption *Group,
+ SmallVectorImpl<diag::kind> &Diags) {
// Add the members of the option diagnostic set.
- if (const short *Member = Group->Members) {
- for (; *Member != -1; ++Member)
- Diags.push_back(*Member);
- }
+ const int16_t *Member = DiagArrays + Group->Members;
+ for (; *Member != -1; ++Member)
+ Diags.push_back(*Member);
// Add the members of the subgroups.
- if (const short *SubGroups = Group->SubGroups) {
- for (; *SubGroups != (short)-1; ++SubGroups)
- getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags);
- }
+ const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
+ for (; *SubGroups != (int16_t)-1; ++SubGroups)
+ getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags);
}
bool DiagnosticIDs::getDiagnosticsInGroup(
StringRef Group,
SmallVectorImpl<diag::kind> &Diags) const {
- WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
- std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
+ std::lower_bound(OptionTable, OptionTable + OptionTableSize, Group,
WarningOptionCompare);
if (Found == OptionTable + OptionTableSize ||
Found->getName() != Group)
return true; // Option not found.
- getDiagnosticsInGroup(Found, Diags);
+ ::getDiagnosticsInGroup(Found, Diags);
return false;
}
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 9cc59027ab6e..af9b2663cbfa 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -63,91 +63,16 @@ FileEntry::~FileEntry() {
if (FD != -1) ::close(FD);
}
-bool FileEntry::isNamedPipe() const {
- return S_ISFIFO(FileMode);
-}
-
-//===----------------------------------------------------------------------===//
-// Windows.
-//===----------------------------------------------------------------------===//
-
-#ifdef LLVM_ON_WIN32
-
-namespace {
- static std::string GetFullPath(const char *relPath) {
- char *absPathStrPtr = _fullpath(NULL, relPath, 0);
- assert(absPathStrPtr && "_fullpath() returned NULL!");
-
- std::string absPath(absPathStrPtr);
-
- free(absPathStrPtr);
- return absPath;
- }
-}
-
-class FileManager::UniqueDirContainer {
- /// UniqueDirs - Cache from full path to existing directories/files.
- ///
- llvm::StringMap<DirectoryEntry> UniqueDirs;
-
-public:
- /// getDirectory - Return an existing DirectoryEntry with the given
- /// name if there is already one; otherwise create and return a
- /// default-constructed DirectoryEntry.
- DirectoryEntry &getDirectory(const char *Name,
- const struct stat & /*StatBuf*/) {
- std::string FullPath(GetFullPath(Name));
- return UniqueDirs.GetOrCreateValue(FullPath).getValue();
- }
-
- size_t size() const { return UniqueDirs.size(); }
-};
-
-class FileManager::UniqueFileContainer {
- /// UniqueFiles - Cache from full path to existing directories/files.
- ///
- llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
-
-public:
- /// getFile - Return an existing FileEntry with the given name if
- /// there is already one; otherwise create and return a
- /// default-constructed FileEntry.
- FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) {
- std::string FullPath(GetFullPath(Name));
-
- // Lowercase string because Windows filesystem is case insensitive.
- FullPath = StringRef(FullPath).lower();
- return UniqueFiles.GetOrCreateValue(FullPath).getValue();
- }
-
- size_t size() const { return UniqueFiles.size(); }
-
- void erase(const FileEntry *Entry) {
- std::string FullPath(GetFullPath(Entry->getName()));
-
- // Lowercase string because Windows filesystem is case insensitive.
- FullPath = StringRef(FullPath).lower();
- UniqueFiles.erase(FullPath);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// Unix-like Systems.
-//===----------------------------------------------------------------------===//
-
-#else
-
class FileManager::UniqueDirContainer {
/// UniqueDirs - Cache from ID's to existing directories/files.
- std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
+ std::map<llvm::sys::fs::UniqueID, DirectoryEntry> UniqueDirs;
public:
/// getDirectory - Return an existing DirectoryEntry with the given
/// ID's if there is already one; otherwise create and return a
/// default-constructed DirectoryEntry.
- DirectoryEntry &getDirectory(const char * /*Name*/,
- const struct stat &StatBuf) {
- return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
+ DirectoryEntry &getDirectory(const llvm::sys::fs::UniqueID &UniqueID) {
+ return UniqueDirs[UniqueID];
}
size_t size() const { return UniqueDirs.size(); }
@@ -161,12 +86,10 @@ public:
/// getFile - Return an existing FileEntry with the given ID's if
/// there is already one; otherwise create and return a
/// default-constructed FileEntry.
- FileEntry &getFile(const char * /*Name*/, const struct stat &StatBuf) {
- return
- const_cast<FileEntry&>(
- *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
- StatBuf.st_ino,
- StatBuf.st_mode)).first);
+ FileEntry &getFile(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe,
+ bool InPCH) {
+ return const_cast<FileEntry &>(
+ *UniqueFiles.insert(FileEntry(UniqueID, IsNamedPipe, InPCH)).first);
}
size_t size() const { return UniqueFiles.size(); }
@@ -174,8 +97,6 @@ public:
void erase(const FileEntry *Entry) { UniqueFiles.erase(*Entry); }
};
-#endif
-
//===----------------------------------------------------------------------===//
// Common logic.
//===----------------------------------------------------------------------===//
@@ -292,6 +213,16 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
DirName != llvm::sys::path::root_path(DirName) &&
llvm::sys::path::is_separator(DirName.back()))
DirName = DirName.substr(0, DirName.size()-1);
+#ifdef LLVM_ON_WIN32
+ // Fixing a problem with "clang C:test.c" on Windows.
+ // Stat("C:") does not recognize "C:" as a valid directory
+ std::string DirNameStr;
+ if (DirName.size() > 1 && DirName.back() == ':' &&
+ DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
+ DirNameStr = DirName.str() + '.';
+ DirName = DirNameStr;
+ }
+#endif
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
@@ -313,8 +244,8 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
const char *InterndDirName = NamedDirEnt.getKeyData();
// Check to see if the directory exists.
- struct stat StatBuf;
- if (getStatValue(InterndDirName, StatBuf, false, 0/*directory lookup*/)) {
+ FileData Data;
+ if (getStatValue(InterndDirName, Data, false, 0 /*directory lookup*/)) {
// There's no real directory at the given path.
if (!CacheFailure)
SeenDirEntries.erase(DirName);
@@ -325,7 +256,8 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// same inode (this occurs on Unix-like systems when one dir is
// symlinked to another, for example) or the same path (on
// Windows).
- DirectoryEntry &UDE = UniqueRealDirs.getDirectory(InterndDirName, StatBuf);
+ DirectoryEntry &UDE =
+ UniqueRealDirs.getDirectory(Data.UniqueID);
NamedDirEnt.setValue(&UDE);
if (!UDE.getName()) {
@@ -378,8 +310,8 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// Nope, there isn't. Check to see if the file exists.
int FileDescriptor = -1;
- struct stat StatBuf;
- if (getStatValue(InterndFileName, StatBuf, true,
+ FileData Data;
+ if (getStatValue(InterndFileName, Data, true,
openFile ? &FileDescriptor : 0)) {
// There's no real file at the given path.
if (!CacheFailure)
@@ -395,7 +327,8 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// It exists. See if we have already opened a file with the same inode.
// This occurs when one dir is symlinked to another, for example.
- FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
+ FileEntry &UFE =
+ UniqueRealFiles.getFile(Data.UniqueID, Data.IsNamedPipe, Data.InPCH);
NamedFileEnt.setValue(&UFE);
if (UFE.getName()) { // Already have an entry with this inode, return it.
@@ -410,8 +343,8 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// FIXME: Change the name to be a char* that points back to the
// 'SeenFileEntries' key.
UFE.Name = InterndFileName;
- UFE.Size = StatBuf.st_size;
- UFE.ModTime = StatBuf.st_mtime;
+ UFE.Size = Data.Size;
+ UFE.ModTime = Data.ModTime;
UFE.Dir = DirInfo;
UFE.UID = NextFileUID++;
UFE.FD = FileDescriptor;
@@ -448,12 +381,12 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
"The directory of a virtual file should already be in the cache.");
// Check to see if the file exists. If so, drop the virtual file
- struct stat StatBuf;
+ FileData Data;
const char *InterndFileName = NamedFileEnt.getKeyData();
- if (getStatValue(InterndFileName, StatBuf, true, 0) == 0) {
- StatBuf.st_size = Size;
- StatBuf.st_mtime = ModificationTime;
- UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
+ if (getStatValue(InterndFileName, Data, true, 0) == 0) {
+ Data.Size = Size;
+ Data.ModTime = ModificationTime;
+ UFE = &UniqueRealFiles.getFile(Data.UniqueID, Data.IsNamedPipe, Data.InPCH);
NamedFileEnt.setValue(UFE);
@@ -562,27 +495,27 @@ getBufferForFile(StringRef Filename, std::string *ErrorStr) {
/// if the path points to a virtual file or does not exist, or returns
/// false if it's an existent real file. If FileDescriptor is NULL,
/// do directory look-up instead of file look-up.
-bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
+bool FileManager::getStatValue(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
// FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
// absolute!
if (FileSystemOpts.WorkingDir.empty())
- return FileSystemStatCache::get(Path, StatBuf, isFile, FileDescriptor,
+ return FileSystemStatCache::get(Path, Data, isFile, FileDescriptor,
StatCache.get());
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return FileSystemStatCache::get(FilePath.c_str(), StatBuf,
- isFile, FileDescriptor, StatCache.get());
+ return FileSystemStatCache::get(FilePath.c_str(), Data, isFile,
+ FileDescriptor, StatCache.get());
}
-bool FileManager::getNoncachedStatValue(StringRef Path,
- struct stat &StatBuf) {
+bool FileManager::getNoncachedStatValue(StringRef Path,
+ llvm::sys::fs::file_status &Result) {
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return ::stat(FilePath.c_str(), &StatBuf) != 0;
+ return llvm::sys::fs::status(FilePath.c_str(), Result);
}
void FileManager::invalidateCache(const FileEntry *Entry) {
@@ -610,7 +543,7 @@ void FileManager::GetUniqueIDMapping(
UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
// Map virtual file entries
- for (SmallVector<FileEntry*, 4>::const_iterator
+ for (SmallVectorImpl<FileEntry *>::const_iterator
VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
VFE != VFEEnd; ++VFE)
if (*VFE && *VFE != NON_EXISTENT_FILE)
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index 38c46299018c..7a01bffcd95f 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileSystemStatCache.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-#include <fcntl.h>
// FIXME: This is terrible, we need this for ::close.
#if !defined(_MSC_VER) && !defined(__MINGW32__)
@@ -30,6 +30,16 @@ using namespace clang;
void FileSystemStatCache::anchor() { }
+static void copyStatusToFileData(const llvm::sys::fs::file_status &Status,
+ FileData &Data) {
+ Data.Size = Status.getSize();
+ Data.ModTime = Status.getLastModificationTime().toEpochTime();
+ Data.UniqueID = Status.getUniqueID();
+ Data.IsDirectory = is_directory(Status);
+ Data.IsNamedPipe = Status.type() == llvm::sys::fs::file_type::fifo_file;
+ Data.InPCH = false;
+}
+
/// FileSystemStatCache::get - Get the 'stat' information for the specified
/// path, using the cache to accelerate it if possible. This returns true if
/// the path does not exist or false if it exists.
@@ -39,19 +49,24 @@ void FileSystemStatCache::anchor() { }
/// success for directories (not files). On a successful file lookup, the
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
-bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor,
- FileSystemStatCache *Cache) {
+bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor, FileSystemStatCache *Cache) {
LookupResult R;
bool isForDir = !isFile;
// If we have a cache, use it to resolve the stat query.
if (Cache)
- R = Cache->getStat(Path, StatBuf, isFile, FileDescriptor);
+ R = Cache->getStat(Path, Data, isFile, FileDescriptor);
else if (isForDir || !FileDescriptor) {
// If this is a directory or a file descriptor is not needed and we have
// no cache, just go to the file system.
- R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
+ llvm::sys::fs::file_status Status;
+ if (llvm::sys::fs::status(Path, Status)) {
+ R = CacheMissing;
+ } else {
+ R = CacheExists;
+ copyStatusToFileData(Status, Data);
+ }
} else {
// Otherwise, we have to go to the filesystem. We can always just use
// 'stat' here, but (for files) the client is asking whether the file exists
@@ -60,22 +75,20 @@ bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
//
// Because of this, check to see if the file exists with 'open'. If the
// open succeeds, use fstat to get the stat info.
- int OpenFlags = O_RDONLY;
-#ifdef O_BINARY
- OpenFlags |= O_BINARY; // Open input file in binary mode on win32.
-#endif
- *FileDescriptor = ::open(Path, OpenFlags);
-
- if (*FileDescriptor == -1) {
+ llvm::error_code EC = llvm::sys::fs::openFileForRead(Path, *FileDescriptor);
+
+ if (EC) {
// If the open fails, our "stat" fails.
R = CacheMissing;
} else {
// Otherwise, the open succeeded. Do an fstat to get the information
// about the file. We'll end up returning the open file descriptor to the
// client to do what they please with it.
- if (::fstat(*FileDescriptor, &StatBuf) == 0)
+ llvm::sys::fs::file_status Status;
+ if (!llvm::sys::fs::status(*FileDescriptor, Status)) {
R = CacheExists;
- else {
+ copyStatusToFileData(Status, Data);
+ } else {
// fstat rarely fails. If it does, claim the initial open didn't
// succeed.
R = CacheMissing;
@@ -90,7 +103,7 @@ bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
// If the path exists, make sure that its "directoryness" matches the clients
// demands.
- if (S_ISDIR(StatBuf.st_mode) != isForDir) {
+ if (Data.IsDirectory != isForDir) {
// If not, close the file if opened.
if (FileDescriptor && *FileDescriptor != -1) {
::close(*FileDescriptor);
@@ -103,12 +116,11 @@ bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
return false;
}
-
MemorizeStatCalls::LookupResult
-MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
-
+MemorizeStatCalls::getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
+ LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
+
// Do not cache failed stats, it is easy to construct common inconsistent
// situations if we do, and they are not important for PCH performance (which
// currently only needs the stats to construct the initial FileManager
@@ -117,8 +129,8 @@ MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
return Result;
// Cache file 'stat' results and directories with absolutely paths.
- if (!S_ISDIR(StatBuf.st_mode) || llvm::sys::path::is_absolute(Path))
- StatCalls[Path] = StatBuf;
-
+ if (!Data.IsDirectory || llvm::sys::path::is_absolute(Path))
+ StatCalls[Path] = Data;
+
return Result;
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 951c718d183a..500e732eef34 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -13,11 +13,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -453,6 +452,32 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
return OMF_None;
}
+ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
+ IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
+ if (!first) return OIT_None;
+
+ StringRef name = first->getName();
+
+ if (name.empty()) return OIT_None;
+ switch (name.front()) {
+ case 'a':
+ if (startsWithWord(name, "array")) return OIT_Array;
+ break;
+ case 'd':
+ if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
+ if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
+ break;
+ case 's':
+ if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
+ if (startsWithWord(name, "standard")) return OIT_Singleton;
+ case 'i':
+ if (startsWithWord(name, "init")) return OIT_Init;
+ default:
+ break;
+ }
+ return OIT_None;
+}
+
namespace {
struct SelectorTableImpl {
llvm::FoldingSet<MultiKeywordSelector> Table;
@@ -464,15 +489,20 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) {
return *static_cast<SelectorTableImpl*>(P);
}
-/*static*/ Selector
-SelectorTable::constructSetterName(IdentifierTable &Idents,
- SelectorTable &SelTable,
- const IdentifierInfo *Name) {
- SmallString<100> SelectorName;
- SelectorName = "set";
- SelectorName += Name->getName();
- SelectorName[3] = toUppercase(SelectorName[3]);
- IdentifierInfo *SetterName = &Idents.get(SelectorName);
+SmallString<64>
+SelectorTable::constructSetterName(StringRef Name) {
+ SmallString<64> SetterName("set");
+ SetterName += Name;
+ SetterName[3] = toUppercase(SetterName[3]);
+ return SetterName;
+}
+
+Selector
+SelectorTable::constructSetterSelector(IdentifierTable &Idents,
+ SelectorTable &SelTable,
+ const IdentifierInfo *Name) {
+ IdentifierInfo *SetterName =
+ &Idents.get(constructSetterName(Name->getName()));
return SelTable.getUnarySelector(SetterName);
}
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 13518cde6642..d08cef1a1563 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -11,6 +11,7 @@
// code.
//
//===----------------------------------------------------------------------===//
+
#include "clang/Basic/Module.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
@@ -20,6 +21,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+
using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
@@ -65,16 +67,17 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Default(Target.hasFeature(Feature));
}
-bool
+bool
Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
- StringRef &Feature) const {
+ Requirement &Req) const {
if (IsAvailable)
return true;
for (const Module *Current = this; Current; Current = Current->Parent) {
- for (unsigned I = 0, N = Current->Requires.size(); I != N; ++I) {
- if (!hasFeature(Current->Requires[I], LangOpts, Target)) {
- Feature = Current->Requires[I];
+ for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
+ if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
+ Current->Requirements[I].second) {
+ Req = Current->Requirements[I];
return false;
}
}
@@ -111,8 +114,8 @@ std::string Module::getFullModuleName() const {
Names.push_back(M->Name);
std::string Result;
- for (SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
- IEnd = Names.rend();
+ for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
+ IEnd = Names.rend();
I != IEnd; ++I) {
if (!Result.empty())
Result += '.';
@@ -143,12 +146,13 @@ ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
}
-void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
+void Module::addRequirement(StringRef Feature, bool RequiredState,
+ const LangOptions &LangOpts,
const TargetInfo &Target) {
- Requires.push_back(Feature);
+ Requirements.push_back(Requirement(Feature, RequiredState));
// If this feature is currently available, we're done.
- if (hasFeature(Feature, LangOpts, Target))
+ if (hasFeature(Feature, LangOpts, Target) == RequiredState)
return;
if (!IsAvailable)
@@ -190,6 +194,16 @@ static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
}
void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
+ // All non-explicit submodules are exported.
+ for (std::vector<Module *>::const_iterator I = SubModules.begin(),
+ E = SubModules.end();
+ I != E; ++I) {
+ Module *Mod = *I;
+ if (!Mod->IsExplicit)
+ Exported.push_back(Mod);
+ }
+
+ // Find re-exported modules by filtering the list of imported modules.
bool AnyWildcard = false;
bool UnrestrictedWildcard = false;
SmallVector<Module *, 4> WildcardRestrictions;
@@ -242,6 +256,23 @@ void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
}
}
+void Module::buildVisibleModulesCache() const {
+ assert(VisibleModulesCache.empty() && "cache does not need building");
+
+ // This module is visible to itself.
+ VisibleModulesCache.insert(this);
+
+ // Every imported module is visible.
+ SmallVector<Module *, 16> Stack(Imports.begin(), Imports.end());
+ while (!Stack.empty()) {
+ Module *CurrModule = Stack.pop_back_val();
+
+ // Every module transitively exported by an imported module is visible.
+ if (VisibleModulesCache.insert(CurrModule).second)
+ CurrModule->getExportedModules(Stack);
+ }
+}
+
void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent);
if (IsFramework)
@@ -257,13 +288,15 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << " {\n";
- if (!Requires.empty()) {
+ if (!Requirements.empty()) {
OS.indent(Indent + 2);
OS << "requires ";
- for (unsigned I = 0, N = Requires.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Requirements.size(); I != N; ++I) {
if (I)
OS << ", ";
- OS << Requires[I];
+ if (!Requirements[I].second)
+ OS << "!";
+ OS << Requirements[I].first;
}
OS << "\n";
}
@@ -293,10 +326,10 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
- for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
+ for (unsigned I = 0, N = NormalHeaders.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "header \"";
- OS.write_escaped(Headers[I]->getName());
+ OS.write_escaped(NormalHeaders[I]->getName());
OS << "\"\n";
}
@@ -306,6 +339,13 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(ExcludedHeaders[I]->getName());
OS << "\"\n";
}
+
+ for (unsigned I = 0, N = PrivateHeaders.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "private header \"";
+ OS.write_escaped(PrivateHeaders[I]->getName());
+ OS << "\"\n";
+ }
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
@@ -337,6 +377,20 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
+ for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "use ";
+ OS << DirectUses[I]->getFullModuleName();
+ OS << "\n";
+ }
+
+ for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "use ";
+ printModuleId(OS, UnresolvedDirectUses[I]);
+ OS << "\n";
+ }
+
for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "link ";
diff --git a/lib/Basic/ObjCRuntime.cpp b/lib/Basic/ObjCRuntime.cpp
index 9bd433a0649b..be50fc4fe24f 100644
--- a/lib/Basic/ObjCRuntime.cpp
+++ b/lib/Basic/ObjCRuntime.cpp
@@ -71,16 +71,20 @@ bool ObjCRuntime::tryParse(StringRef input) {
kind = ObjCRuntime::GCC;
} else if (runtimeName == "objfw") {
kind = ObjCRuntime::ObjFW;
+ Version = VersionTuple(0, 8);
} else {
return true;
}
TheKind = kind;
-
+
if (dash != StringRef::npos) {
StringRef verString = input.substr(dash + 1);
- if (Version.tryParse(verString))
+ if (Version.tryParse(verString))
return true;
}
+ if (kind == ObjCRuntime::ObjFW && Version > VersionTuple(0, 8))
+ Version = VersionTuple(0, 8);
+
return false;
}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 835908d2a1b5..1350934d0e65 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -32,12 +32,102 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
assert(Kind < NUM_OPENMP_DIRECTIVES);
switch (Kind) {
case OMPD_unknown:
- return ("unknown");
+ return "unknown";
#define OPENMP_DIRECTIVE(Name) \
case OMPD_##Name : return #Name;
#include "clang/Basic/OpenMPKinds.def"
- default:
+ case NUM_OPENMP_DIRECTIVES:
break;
}
llvm_unreachable("Invalid OpenMP directive kind");
}
+
+OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
+ return llvm::StringSwitch<OpenMPClauseKind>(Str)
+#define OPENMP_CLAUSE(Name, Class) \
+ .Case(#Name, OMPC_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_unknown);
+}
+
+const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) {
+ assert(Kind < NUM_OPENMP_CLAUSES);
+ switch (Kind) {
+ case OMPC_unknown:
+ return "unknown";
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name : return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ case OMPC_threadprivate:
+ return "threadprivate or thread local";
+ case NUM_OPENMP_CLAUSES:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP clause kind");
+}
+
+unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
+ StringRef Str) {
+ switch (Kind) {
+ case OMPC_default:
+ return llvm::StringSwitch<OpenMPDefaultClauseKind>(Str)
+#define OPENMP_DEFAULT_KIND(Name) \
+ .Case(#Name, OMPC_DEFAULT_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_DEFAULT_unknown);
+ case OMPC_unknown:
+ case OMPC_threadprivate:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_shared:
+ case NUM_OPENMP_CLAUSES:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP simple clause kind");
+}
+
+const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
+ unsigned Type) {
+ switch (Kind) {
+ case OMPC_default:
+ switch (Type) {
+ case OMPC_DEFAULT_unknown:
+ return "unknown";
+#define OPENMP_DEFAULT_KIND(Name) \
+ case OMPC_DEFAULT_##Name : return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'default' clause type");
+ case OMPC_unknown:
+ case OMPC_threadprivate:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_shared:
+ case NUM_OPENMP_CLAUSES:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP simple clause kind");
+}
+
+bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind CKind) {
+ assert(DKind < NUM_OPENMP_DIRECTIVES);
+ assert(CKind < NUM_OPENMP_CLAUSES);
+ switch (DKind) {
+ case OMPD_parallel:
+ switch (CKind) {
+#define OPENMP_PARALLEL_CLAUSE(Name) \
+ case OMPC_##Name: return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_unknown:
+ case OMPD_threadprivate:
+ case OMPD_task:
+ case NUM_OPENMP_DIRECTIVES:
+ break;
+ }
+ return false;
+}
diff --git a/lib/Basic/OperatorPrecedence.cpp b/lib/Basic/OperatorPrecedence.cpp
index f9de231c5e77..ade8d6d841df 100644
--- a/lib/Basic/OperatorPrecedence.cpp
+++ b/lib/Basic/OperatorPrecedence.cpp
@@ -28,7 +28,7 @@ prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
return prec::Unknown;
case tok::greatergreater:
- // C++0x [temp.names]p3:
+ // C++11 [temp.names]p3:
//
// [...] Similarly, the first non-nested >> is treated as two
// consecutive but distinct > tokens, the first of which is
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index d6dc6d6328af..9d79551f9118 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -536,6 +536,43 @@ SourceManager::getFakeContentCacheForRecovery() const {
return FakeContentCacheForRecovery;
}
+/// \brief Returns the previous in-order FileID or an invalid FileID if there
+/// is no previous one.
+FileID SourceManager::getPreviousFileID(FileID FID) const {
+ if (FID.isInvalid())
+ return FileID();
+
+ int ID = FID.ID;
+ if (ID == -1)
+ return FileID();
+
+ if (ID > 0) {
+ if (ID-1 == 0)
+ return FileID();
+ } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) {
+ return FileID();
+ }
+
+ return FileID::get(ID-1);
+}
+
+/// \brief Returns the next in-order FileID or an invalid FileID if there is
+/// no next one.
+FileID SourceManager::getNextFileID(FileID FID) const {
+ if (FID.isInvalid())
+ return FileID();
+
+ int ID = FID.ID;
+ if (ID > 0) {
+ if (unsigned(ID+1) >= local_sloc_entry_size())
+ return FileID();
+ } else if (ID+1 >= -1) {
+ return FileID();
+ }
+
+ return FileID::get(ID+1);
+}
+
//===----------------------------------------------------------------------===//
// Methods to create new FileID's and macro expansions.
//===----------------------------------------------------------------------===//
@@ -998,6 +1035,77 @@ bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const {
return Expansion.isMacroBodyExpansion();
}
+bool SourceManager::isAtStartOfImmediateMacroExpansion(SourceLocation Loc,
+ SourceLocation *MacroBegin) const {
+ assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc");
+
+ std::pair<FileID, unsigned> DecompLoc = getDecomposedLoc(Loc);
+ if (DecompLoc.second > 0)
+ return false; // Does not point at the start of expansion range.
+
+ bool Invalid = false;
+ const SrcMgr::ExpansionInfo &ExpInfo =
+ getSLocEntry(DecompLoc.first, &Invalid).getExpansion();
+ if (Invalid)
+ return false;
+ SourceLocation ExpLoc = ExpInfo.getExpansionLocStart();
+
+ if (ExpInfo.isMacroArgExpansion()) {
+ // For macro argument expansions, check if the previous FileID is part of
+ // the same argument expansion, in which case this Loc is not at the
+ // beginning of the expansion.
+ FileID PrevFID = getPreviousFileID(DecompLoc.first);
+ if (!PrevFID.isInvalid()) {
+ const SrcMgr::SLocEntry &PrevEntry = getSLocEntry(PrevFID, &Invalid);
+ if (Invalid)
+ return false;
+ if (PrevEntry.isExpansion() &&
+ PrevEntry.getExpansion().getExpansionLocStart() == ExpLoc)
+ return false;
+ }
+ }
+
+ if (MacroBegin)
+ *MacroBegin = ExpLoc;
+ return true;
+}
+
+bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc,
+ SourceLocation *MacroEnd) const {
+ assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc");
+
+ FileID FID = getFileID(Loc);
+ SourceLocation NextLoc = Loc.getLocWithOffset(1);
+ if (isInFileID(NextLoc, FID))
+ return false; // Does not point at the end of expansion range.
+
+ bool Invalid = false;
+ const SrcMgr::ExpansionInfo &ExpInfo =
+ getSLocEntry(FID, &Invalid).getExpansion();
+ if (Invalid)
+ return false;
+
+ if (ExpInfo.isMacroArgExpansion()) {
+ // For macro argument expansions, check if the next FileID is part of the
+ // same argument expansion, in which case this Loc is not at the end of the
+ // expansion.
+ FileID NextFID = getNextFileID(FID);
+ if (!NextFID.isInvalid()) {
+ const SrcMgr::SLocEntry &NextEntry = getSLocEntry(NextFID, &Invalid);
+ if (Invalid)
+ return false;
+ if (NextEntry.isExpansion() &&
+ NextEntry.getExpansion().getExpansionLocStart() ==
+ ExpInfo.getExpansionLocStart())
+ return false;
+ }
+ }
+
+ if (MacroEnd)
+ *MacroEnd = ExpInfo.getExpansionLocEnd();
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Queries about the code at a SourceLocation.
@@ -1150,7 +1258,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
// If we found a newline, adjust the pointer and jump to the handling code.
if (Mask != 0) {
- NextBuf += llvm::CountTrailingZeros_32(Mask);
+ NextBuf += llvm::countTrailingZeros(Mask);
goto FoundSpecialChar;
}
NextBuf += 16;
@@ -1445,6 +1553,36 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc,
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
+/// \brief Returns whether the PresumedLoc for a given SourceLocation is
+/// in the main file.
+///
+/// This computes the "presumed" location for a SourceLocation, then checks
+/// whether it came from a file other than the main file. This is different
+/// from isWrittenInMainFile() because it takes line marker directives into
+/// account.
+bool SourceManager::isInMainFile(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return false;
+
+ // Presumed locations are always for expansion points.
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
+
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return false;
+
+ const SrcMgr::FileInfo &FI = Entry.getFile();
+
+ // Check if there is a line directive for this location.
+ if (FI.hasLineDirectives())
+ if (const LineEntry *Entry =
+ LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second))
+ if (Entry->IncludeOffset)
+ return false;
+
+ return FI.getIncludeLoc().isInvalid();
+}
+
/// \brief The size of the SLocEnty that \arg FID represents.
unsigned SourceManager::getFileIDSize(FileID FID) const {
bool Invalid = false;
@@ -1472,15 +1610,16 @@ unsigned SourceManager::getFileIDSize(FileID FID) const {
///
/// This routine involves a system call, and therefore should only be used
/// in non-performance-critical code.
-static Optional<ino_t> getActualFileInode(const FileEntry *File) {
+static Optional<llvm::sys::fs::UniqueID>
+getActualFileUID(const FileEntry *File) {
if (!File)
return None;
-
- struct stat StatBuf;
- if (::stat(File->getName(), &StatBuf))
+
+ llvm::sys::fs::UniqueID ID;
+ if (llvm::sys::fs::getUniqueID(File->getName(), ID))
return None;
-
- return StatBuf.st_ino;
+
+ return ID;
}
/// \brief Get the source location for the given file:line:col triplet.
@@ -1509,7 +1648,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
// First, check the main file ID, since it is common to look for a
// location in the main file.
- Optional<ino_t> SourceFileInode;
+ Optional<llvm::sys::fs::UniqueID> SourceFileUID;
Optional<StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
bool Invalid = false;
@@ -1530,10 +1669,11 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
const FileEntry *MainFile = MainContentCache->OrigEntry;
SourceFileName = llvm::sys::path::filename(SourceFile->getName());
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
- SourceFileInode = getActualFileInode(SourceFile);
- if (SourceFileInode) {
- if (Optional<ino_t> MainFileInode = getActualFileInode(MainFile)) {
- if (*SourceFileInode == *MainFileInode) {
+ SourceFileUID = getActualFileUID(SourceFile);
+ if (SourceFileUID) {
+ if (Optional<llvm::sys::fs::UniqueID> MainFileUID =
+ getActualFileUID(MainFile)) {
+ if (*SourceFileUID == *MainFileUID) {
FirstFID = MainFileID;
SourceFile = MainFile;
}
@@ -1576,12 +1716,11 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
// If we haven't found what we want yet, try again, but this time stat()
// each of the files in case the files have changed since we originally
- // parsed the file.
+ // parsed the file.
if (FirstFID.isInvalid() &&
- (SourceFileName ||
+ (SourceFileName ||
(SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
- (SourceFileInode ||
- (SourceFileInode = getActualFileInode(SourceFile)))) {
+ (SourceFileUID || (SourceFileUID = getActualFileUID(SourceFile)))) {
bool Invalid = false;
for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
FileID IFileID;
@@ -1596,8 +1735,9 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
- if (Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
- if (*SourceFileInode == *EntryInode) {
+ if (Optional<llvm::sys::fs::UniqueID> EntryUID =
+ getActualFileUID(Entry)) {
+ if (*SourceFileUID == *EntryUID) {
FirstFID = FileID::get(I);
SourceFile = Entry;
break;
@@ -1617,6 +1757,10 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
SourceLocation SourceManager::translateLineCol(FileID FID,
unsigned Line,
unsigned Col) const {
+ // Lines are used as a one-based index into a zero-based array. This assert
+ // checks for possible buffer underruns.
+ assert(Line != 0 && "Passed a zero-based line");
+
if (FID.isInvalid())
return SourceLocation();
@@ -1624,7 +1768,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
const SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid)
return SourceLocation();
-
+
if (!Entry.isFile())
return SourceLocation();
@@ -1637,7 +1781,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
= const_cast<ContentCache *>(Entry.getFile().getContentCache());
if (!Content)
return SourceLocation();
-
+
// If this is the first use of line information for this buffer, compute the
// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
@@ -1666,10 +1810,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
// Check that the given column is valid.
while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
++i;
- if (i < Col-1)
- return FileLoc.getLocWithOffset(FilePos + i);
-
- return FileLoc.getLocWithOffset(FilePos + Col - 1);
+ return FileLoc.getLocWithOffset(FilePos + i);
}
/// \brief Compute a map of macro argument chunks to their expanded source
@@ -1700,7 +1841,10 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
return;
}
- const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID, &Invalid);
+ if (Invalid)
+ return;
if (Entry.isFile()) {
SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc();
if (IncludeLoc.isInvalid())
@@ -1850,6 +1994,9 @@ SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
std::pair<FileID, unsigned>
SourceManager::getDecomposedIncludedLoc(FileID FID) const {
+ if (FID.isInvalid())
+ return std::make_pair(FileID(), 0);
+
// Uses IncludedLocMap to retrieve/cache the decomposed loc.
typedef std::pair<FileID, unsigned> DecompTy;
@@ -1861,11 +2008,14 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const {
return DecompLoc; // already in map.
SourceLocation UpperLoc;
- const SrcMgr::SLocEntry &Entry = getSLocEntry(FID);
- if (Entry.isExpansion())
- UpperLoc = Entry.getExpansion().getExpansionLocStart();
- else
- UpperLoc = Entry.getFile().getIncludeLoc();
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (!Invalid) {
+ if (Entry.isExpansion())
+ UpperLoc = Entry.getExpansion().getExpansionLocStart();
+ else
+ UpperLoc = Entry.getFile().getIncludeLoc();
+ }
if (UpperLoc.isValid())
DecompLoc = getDecomposedLoc(UpperLoc);
@@ -1925,6 +2075,12 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
+ // getDecomposedLoc may have failed to return a valid FileID because, e.g. it
+ // is a serialized one referring to a file that was removed after we loaded
+ // the PCH.
+ if (LOffs.first.isInvalid() || ROffs.first.isInvalid())
+ return LOffs.first.isInvalid() && !ROffs.first.isInvalid();
+
// If the source locations are in the same file, just compare offsets.
if (LOffs.first == ROffs.first)
return LOffs.second < ROffs.second;
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 0d44dc010e1a..e993055cc881 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -24,8 +24,7 @@ using namespace clang;
static const LangAS::Map DefaultAddrSpaceMap = { 0 };
// TargetInfo Constructor.
-TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
-{
+TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
// SPARC. These should be overridden by concrete targets as needed.
BigEndian = true;
@@ -89,6 +88,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
// Default to an empty address space map.
AddrSpaceMap = &DefaultAddrSpaceMap;
+ UseAddrSpaceMapMangling = false;
// Default to an unknown platform name.
PlatformName = "unknown";
@@ -103,6 +103,8 @@ TargetInfo::~TargetInfo() {}
const char *TargetInfo::getTypeName(IntType T) {
switch (T) {
default: llvm_unreachable("not an integer!");
+ case SignedChar: return "char";
+ case UnsignedChar: return "unsigned char";
case SignedShort: return "short";
case UnsignedShort: return "unsigned short";
case SignedInt: return "int";
@@ -119,10 +121,12 @@ const char *TargetInfo::getTypeName(IntType T) {
const char *TargetInfo::getTypeConstantSuffix(IntType T) {
switch (T) {
default: llvm_unreachable("not an integer!");
+ case SignedChar:
case SignedShort:
case SignedInt: return "";
case SignedLong: return "L";
case SignedLongLong: return "LL";
+ case UnsignedChar:
case UnsignedShort:
case UnsignedInt: return "U";
case UnsignedLong: return "UL";
@@ -135,6 +139,8 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
unsigned TargetInfo::getTypeWidth(IntType T) const {
switch (T) {
default: llvm_unreachable("not an integer!");
+ case SignedChar:
+ case UnsignedChar: return getCharWidth();
case SignedShort:
case UnsignedShort: return getShortWidth();
case SignedInt:
@@ -146,11 +152,49 @@ unsigned TargetInfo::getTypeWidth(IntType T) const {
};
}
+TargetInfo::IntType TargetInfo::getIntTypeByWidth(
+ unsigned BitWidth, bool IsSigned) const {
+ if (getCharWidth() == BitWidth)
+ return IsSigned ? SignedChar : UnsignedChar;
+ if (getShortWidth() == BitWidth)
+ return IsSigned ? SignedShort : UnsignedShort;
+ if (getIntWidth() == BitWidth)
+ return IsSigned ? SignedInt : UnsignedInt;
+ if (getLongWidth() == BitWidth)
+ return IsSigned ? SignedLong : UnsignedLong;
+ if (getLongLongWidth() == BitWidth)
+ return IsSigned ? SignedLongLong : UnsignedLongLong;
+ return NoInt;
+}
+
+TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth) const {
+ if (getFloatWidth() == BitWidth)
+ return Float;
+ if (getDoubleWidth() == BitWidth)
+ return Double;
+
+ switch (BitWidth) {
+ case 96:
+ if (&getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended)
+ return LongDouble;
+ break;
+ case 128:
+ if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble ||
+ &getLongDoubleFormat() == &llvm::APFloat::IEEEquad)
+ return LongDouble;
+ break;
+ }
+
+ return NoFloat;
+}
+
/// getTypeAlign - Return the alignment (in bits) of the specified integer type
/// enum. For example, SignedInt -> getIntAlign().
unsigned TargetInfo::getTypeAlign(IntType T) const {
switch (T) {
default: llvm_unreachable("not an integer!");
+ case SignedChar:
+ case UnsignedChar: return getCharAlign();
case SignedShort:
case UnsignedShort: return getShortAlign();
case SignedInt:
@@ -167,11 +211,13 @@ unsigned TargetInfo::getTypeAlign(IntType T) const {
bool TargetInfo::isTypeSigned(IntType T) {
switch (T) {
default: llvm_unreachable("not an integer!");
+ case SignedChar:
case SignedShort:
case SignedInt:
case SignedLong:
case SignedLongLong:
return true;
+ case UnsignedChar:
case UnsignedShort:
case UnsignedInt:
case UnsignedLong:
@@ -188,6 +234,35 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
UseBitFieldTypeAlignment = false;
if (Opts.ShortWChar)
WCharType = UnsignedShort;
+
+ if (Opts.OpenCL) {
+ // OpenCL C requires specific widths for types, irrespective of
+ // what these normally are for the target.
+ // We also define long long and long double here, although the
+ // OpenCL standard only mentions these as "reserved".
+ IntWidth = IntAlign = 32;
+ LongWidth = LongAlign = 64;
+ LongLongWidth = LongLongAlign = 128;
+ HalfWidth = HalfAlign = 16;
+ FloatWidth = FloatAlign = 32;
+ DoubleWidth = DoubleAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 128;
+
+ assert(PointerWidth == 32 || PointerWidth == 64);
+ bool Is32BitArch = PointerWidth == 32;
+ SizeType = Is32BitArch ? UnsignedInt : UnsignedLong;
+ PtrDiffType = Is32BitArch ? SignedInt : SignedLong;
+ IntPtrType = Is32BitArch ? SignedInt : SignedLong;
+
+ IntMaxType = SignedLongLong;
+ UIntMaxType = UnsignedLongLong;
+ Int64Type = SignedLong;
+
+ HalfFormat = &llvm::APFloat::IEEEhalf;
+ FloatFormat = &llvm::APFloat::IEEEsingle;
+ DoubleFormat = &llvm::APFloat::IEEEdouble;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a622a11aa5a2..bccd0d72d8f5 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -73,7 +73,7 @@ protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const=0;
public:
- OSTargetInfo(const std::string& triple) : TgtInfo(triple) {}
+ OSTargetInfo(const llvm::Triple &Triple) : TgtInfo(Triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
TgtInfo::getTargetDefines(Opts, Builder);
@@ -88,7 +88,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
const llvm::Triple &Triple,
StringRef &PlatformName,
VersionTuple &PlatformMinVersion) {
- Builder.defineMacro("__APPLE_CC__", "5621");
+ Builder.defineMacro("__APPLE_CC__", "6000");
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
@@ -138,31 +138,37 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
return;
}
- // Set the appropriate OS version define.
- if (Triple.getOS() == llvm::Triple::IOS) {
- 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_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
- } else {
- // 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(Triple.getEnvironmentName().empty() && "Invalid environment!");
- assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[5];
- 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';
- Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
+ // If there's an environment specified in the triple, that means we're dealing
+ // with an embedded variant of some sort and don't want the platform
+ // version-min defines, so only add them if there's not one.
+ if (Triple.getEnvironmentName().empty()) {
+ // Set the appropriate OS version define.
+ if (Triple.isiOS()) {
+ 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_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ Str);
+ } else {
+ // 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(Triple.getEnvironmentName().empty() && "Invalid environment!");
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[5];
+ 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';
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
+ }
}
PlatformMinVersion = VersionTuple(Maj, Min, Rev);
@@ -179,12 +185,10 @@ protected:
}
public:
- DarwinTargetInfo(const std::string& triple) :
- OSTargetInfo<Target>(triple) {
- llvm::Triple T = llvm::Triple(triple);
- this->TLSSupported = T.isMacOSX() && !T.isMacOSXVersionLT(10,7);
- this->MCountName = "\01mcount";
- }
+ DarwinTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->TLSSupported = Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 7);
+ this->MCountName = "\01mcount";
+ }
virtual std::string isValidSectionSpecifier(StringRef SR) const {
// Let MCSectionMachO validate this.
@@ -224,18 +228,17 @@ protected:
DefineStd(Builder, "unix", Opts);
}
public:
- DragonFlyBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
+ DragonFlyBSDTargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
- llvm::Triple Triple(triple);
- switch (Triple.getArch()) {
- default:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- this->MCountName = ".mcount";
- break;
- }
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ }
}
};
@@ -256,31 +259,57 @@ protected:
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.
+ Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1");
}
public:
- FreeBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
-
- llvm::Triple Triple(triple);
- 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:
- this->MCountName = "_mcount";
- break;
- case llvm::Triple::arm:
- this->MCountName = "__mcount";
- break;
- }
+ FreeBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ 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:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ // 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) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ }
};
// Minix Target
@@ -302,10 +331,9 @@ protected:
DefineStd(Builder, "unix", Opts);
}
public:
- MinixTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
- }
+ MinixTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ }
};
// Linux target
@@ -327,8 +355,7 @@ protected:
Builder.defineMacro("_GNU_SOURCE");
}
public:
- LinuxTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ LinuxTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
this->WIntType = TargetInfo::UnsignedInt;
}
@@ -352,10 +379,9 @@ protected:
Builder.defineMacro("_POSIX_THREADS");
}
public:
- NetBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
- }
+ NetBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ }
};
// OpenBSD Target
@@ -373,12 +399,10 @@ protected:
Builder.defineMacro("_REENTRANT");
}
public:
- OpenBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
- this->TLSSupported = false;
+ OpenBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ this->TLSSupported = false;
- llvm::Triple Triple(triple);
switch (Triple.getArch()) {
default:
case llvm::Triple::x86:
@@ -412,11 +436,10 @@ protected:
Builder.defineMacro("_REENTRANT");
}
public:
- BitrigTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
- this->TLSSupported = false;
- this->MCountName = "__mcount";
+ BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ this->TLSSupported = false;
+ this->MCountName = "__mcount";
}
};
@@ -433,8 +456,7 @@ protected:
Builder.defineMacro("__ELF__");
}
public:
- PSPTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
}
};
@@ -455,8 +477,7 @@ protected:
Builder.defineMacro("__powerpc64__");
}
public:
- PS3PPUTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ PS3PPUTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
this->LongWidth = this->LongAlign = 32;
this->PointerWidth = this->PointerAlign = 32;
@@ -481,8 +502,7 @@ protected:
Builder.defineMacro("__ELF__");
}
public:
- PS3SPUTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ PS3SPUTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
}
};
@@ -500,8 +520,8 @@ protected:
Builder.defineMacro("__SVR4");
}
public:
- AuroraUXTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ AuroraUXTargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
this->WCharType = this->SignedLong;
// FIXME: WIntType should be SignedLong
@@ -535,8 +555,7 @@ protected:
Builder.defineMacro("_REENTRANT");
}
public:
- SolarisTargetInfo(const std::string& triple)
- : OSTargetInfo<Target>(triple) {
+ SolarisTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
this->WCharType = this->SignedInt;
// FIXME: WIntType should be SignedLong
@@ -586,13 +605,13 @@ protected:
}
public:
- WindowsTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {}
+ WindowsTargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {}
};
template <typename Target>
class NaClTargetInfo : public OSTargetInfo<Target> {
- protected:
+protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
if (Opts.POSIXThreads)
@@ -604,9 +623,9 @@ class NaClTargetInfo : public OSTargetInfo<Target> {
Builder.defineMacro("__ELF__");
Builder.defineMacro("__native_client__");
}
- public:
- NaClTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
+
+public:
+ NaClTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
this->LongAlign = 32;
this->LongWidth = 32;
@@ -645,8 +664,14 @@ class PPCTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
std::string CPU;
+
+ // Target cpu features.
+ bool HasVSX;
+
public:
- PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ PPCTargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), HasVSX(false) {
+ BigEndian = (Triple.getArch() != llvm::Triple::ppc64le);
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
}
@@ -718,6 +743,8 @@ public:
.Case("ppc", true)
.Case("powerpc64", true)
.Case("ppc64", true)
+ .Case("powerpc64le", true)
+ .Case("ppc64le", true)
.Default(false);
if (CPUKnown)
@@ -739,10 +766,8 @@ public:
virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const;
-
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags);
virtual bool hasFeature(StringRef Feature) const;
virtual void getGCCRegNames(const char * const *&Names,
@@ -864,6 +889,29 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
#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) {
+ // Remember the maximum enabled sselevel.
+ for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
+ // Ignore disabled features.
+ if (Features[i][0] == '-')
+ continue;
+
+ StringRef Feature = StringRef(Features[i]).substr(1);
+
+ if (Feature == "vsx") {
+ HasVSX = true;
+ continue;
+ }
+
+ // 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.
@@ -871,6 +919,7 @@ 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__");
@@ -878,22 +927,27 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_PPC64");
Builder.defineMacro("__powerpc64__");
Builder.defineMacro("__ppc64__");
- } else {
- Builder.defineMacro("__ppc__");
+ Builder.defineMacro("__PPC64__");
}
// Target properties.
- if (getTriple().getOS() != llvm::Triple::NetBSD &&
- getTriple().getOS() != llvm::Triple::OpenBSD)
- Builder.defineMacro("_BIG_ENDIAN");
- Builder.defineMacro("__BIG_ENDIAN__");
+ if (getTriple().getArch() == llvm::Triple::ppc64le) {
+ Builder.defineMacro("_LITTLE_ENDIAN");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ } else {
+ if (getTriple().getOS() != llvm::Triple::NetBSD &&
+ getTriple().getOS() != llvm::Triple::OpenBSD)
+ Builder.defineMacro("_BIG_ENDIAN");
+ Builder.defineMacro("__BIG_ENDIAN__");
+ }
// Subtarget options.
Builder.defineMacro("__NATURAL_ALIGNMENT__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
// FIXME: Should be controlled by command line option.
- Builder.defineMacro("__LONG_DOUBLE_128__");
+ if (LongDoubleWidth == 128)
+ Builder.defineMacro("__LONG_DOUBLE_128__");
if (Opts.AltiVec) {
Builder.defineMacro("__VEC__", "10206");
@@ -988,13 +1042,15 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__TOS_BGQ__");
}
+ if (HasVSX)
+ Builder.defineMacro("__VSX__");
+
// FIXME: The following are not yet generated here by Clang, but are
// generated by GCC:
//
// _SOFT_FLOAT_
// __RECIP_PRECISION__
// __APPLE_ALTIVEC__
- // __VSX__
// __RECIP__
// __RECIPF__
// __RSQRTE__
@@ -1021,23 +1077,12 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
.Case("pwr6", true)
.Case("pwr7", true)
.Case("ppc64", true)
+ .Case("ppc64le", true)
.Default(false);
Features["qpx"] = (CPU == "a2q");
}
-bool PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- if (Name == "altivec" || Name == "fprnd" || Name == "mfocrf" ||
- Name == "popcntd" || Name == "qpx") {
- Features[Name] = Enabled;
- return true;
- }
-
- return false;
-}
-
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
return Feature == "powerpc";
}
@@ -1150,7 +1195,7 @@ void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
namespace {
class PPC32TargetInfo : public PPCTargetInfo {
public:
- PPC32TargetInfo(const std::string &triple) : PPCTargetInfo(triple) {
+ PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
@@ -1182,10 +1227,12 @@ public:
};
} // end anonymous namespace.
+// Note: ABI differences may eventually require us to have a separate
+// TargetInfo for little endian.
namespace {
class PPC64TargetInfo : public PPCTargetInfo {
public:
- PPC64TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
+ PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
@@ -1195,7 +1242,7 @@ public:
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:64:64-"
+ "i64:64:64-f32:32:32-f64:64:64-"
"v128:128:128-n32:64";
} else
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
@@ -1216,10 +1263,11 @@ namespace {
class DarwinPPC32TargetInfo :
public DarwinTargetInfo<PPC32TargetInfo> {
public:
- DarwinPPC32TargetInfo(const std::string& triple)
- : DarwinTargetInfo<PPC32TargetInfo>(triple) {
+ DarwinPPC32TargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<PPC32TargetInfo>(Triple) {
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;
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
@@ -1233,8 +1281,8 @@ public:
class DarwinPPC64TargetInfo :
public DarwinTargetInfo<PPC64TargetInfo> {
public:
- DarwinPPC64TargetInfo(const std::string& triple)
- : DarwinTargetInfo<PPC64TargetInfo>(triple) {
+ DarwinPPC64TargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<PPC64TargetInfo>(Triple) {
HasAlignMac68kSupport = true;
SuitableAlign = 128;
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
@@ -1255,13 +1303,13 @@ namespace {
class NVPTXTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const Builtin::Info BuiltinInfo[];
- std::vector<StringRef> AvailableFeatures;
public:
- NVPTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ NVPTXTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
TLSSupported = false;
LongWidth = LongAlign = 64;
AddrSpaceMap = &NVPTXAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
// Define available target features
// These must be defined in sorted order!
NoAsmVariants = true;
@@ -1289,9 +1337,18 @@ namespace {
NumAliases = 0;
}
virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
- // FIXME: implement
- return true;
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default: return false;
+ case 'c':
+ case 'h':
+ case 'r':
+ case 'l':
+ case 'f':
+ case 'd':
+ Info.setAllowsRegister();
+ return true;
+ }
}
virtual const char *getClobbers() const {
// FIXME: Is this really right?
@@ -1311,9 +1368,6 @@ namespace {
return Valid;
}
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const;
};
const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = {
@@ -1333,21 +1387,9 @@ namespace {
NumNames = llvm::array_lengthof(GCCRegNames);
}
- bool NVPTXTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- if(std::binary_search(AvailableFeatures.begin(), AvailableFeatures.end(),
- Name)) {
- Features[Name] = Enabled;
- return true;
- } else {
- return false;
- }
- }
-
class NVPTX32TargetInfo : public NVPTXTargetInfo {
public:
- NVPTX32TargetInfo(const std::string& triple) : NVPTXTargetInfo(triple) {
+ NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 32;
SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt;
DescriptionString
@@ -1359,7 +1401,7 @@ namespace {
class NVPTX64TargetInfo : public NVPTXTargetInfo {
public:
- NVPTX64TargetInfo(const std::string& triple) : NVPTXTargetInfo(triple) {
+ NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 64;
SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong;
DescriptionString
@@ -1400,6 +1442,7 @@ static const char *DescriptionStringR600DoubleOps =
static const char *DescriptionStringSI =
"e"
"-p:64:64:64"
+ "-p3:32:32:32"
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
"-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
"-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
@@ -1417,15 +1460,16 @@ class R600TargetInfo : public TargetInfo {
GK_EVERGREEN_DOUBLE_OPS,
GK_NORTHERN_ISLANDS,
GK_CAYMAN,
- GK_SOUTHERN_ISLANDS
+ GK_SOUTHERN_ISLANDS,
+ GK_SEA_ISLANDS
} GPU;
public:
- R600TargetInfo(const std::string& triple)
- : TargetInfo(triple),
- GPU(GK_R600) {
+ R600TargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), GPU(GK_R600) {
DescriptionString = DescriptionStringR600;
AddrSpaceMap = &R600AddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
}
virtual const char * getClobbers() const {
@@ -1496,6 +1540,10 @@ public:
.Case("pitcairn", GK_SOUTHERN_ISLANDS)
.Case("verde", GK_SOUTHERN_ISLANDS)
.Case("oland", GK_SOUTHERN_ISLANDS)
+ .Case("bonaire", GK_SEA_ISLANDS)
+ .Case("kabini", GK_SEA_ISLANDS)
+ .Case("kaveri", GK_SEA_ISLANDS)
+ .Case("hawaii", GK_SEA_ISLANDS)
.Default(GK_NONE);
if (GPU == GK_NONE) {
@@ -1518,6 +1566,7 @@ public:
DescriptionString = DescriptionStringR600DoubleOps;
break;
case GK_SOUTHERN_ISLANDS:
+ case GK_SEA_ISLANDS:
DescriptionString = DescriptionStringSI;
break;
}
@@ -1529,137 +1578,6 @@ public:
} // end anonymous namespace
namespace {
-// MBlaze abstract base class
-class MBlazeTargetInfo : public TargetInfo {
- static const char * const GCCRegNames[];
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
-
-public:
- MBlazeTargetInfo(const std::string& triple) : TargetInfo(triple) {
- DescriptionString = "E-p:32:32:32-i8:8:8-i16:16:16";
- }
-
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- // FIXME: Implement.
- Records = 0;
- NumRecords = 0;
- }
-
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const;
-
- virtual bool hasFeature(StringRef Feature) const {
- return Feature == "mblaze";
- }
-
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
- return TargetInfo::CharPtrBuiltinVaList;
- }
- virtual const char *getTargetPrefix() const {
- return "mblaze";
- }
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default: return false;
- case 'O': // Zero
- return true;
- case 'b': // Base register
- case 'f': // Floating point register
- Info.setAllowsRegister();
- return true;
- }
- }
- virtual const char *getClobbers() const {
- return "";
- }
-};
-
-/// MBlazeTargetInfo::getTargetDefines - Return a set of the MBlaze-specific
-/// #defines that are not tied to a specific subtarget.
-void MBlazeTargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- // Target identification.
- Builder.defineMacro("__microblaze__");
- Builder.defineMacro("_ARCH_MICROBLAZE");
- Builder.defineMacro("__MICROBLAZE__");
-
- // Target properties.
- Builder.defineMacro("_BIG_ENDIAN");
- Builder.defineMacro("__BIG_ENDIAN__");
-
- // Subtarget options.
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-}
-
-
-const char * const MBlazeTargetInfo::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",
- "hi", "lo", "accum","rmsr", "$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7","$ap", "$rap", "$frp"
-};
-
-void MBlazeTargetInfo::getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias MBlazeTargetInfo::GCCRegAliases[] = {
- { {"f0"}, "r0" },
- { {"f1"}, "r1" },
- { {"f2"}, "r2" },
- { {"f3"}, "r3" },
- { {"f4"}, "r4" },
- { {"f5"}, "r5" },
- { {"f6"}, "r6" },
- { {"f7"}, "r7" },
- { {"f8"}, "r8" },
- { {"f9"}, "r9" },
- { {"f10"}, "r10" },
- { {"f11"}, "r11" },
- { {"f12"}, "r12" },
- { {"f13"}, "r13" },
- { {"f14"}, "r14" },
- { {"f15"}, "r15" },
- { {"f16"}, "r16" },
- { {"f17"}, "r17" },
- { {"f18"}, "r18" },
- { {"f19"}, "r19" },
- { {"f20"}, "r20" },
- { {"f21"}, "r21" },
- { {"f22"}, "r22" },
- { {"f23"}, "r23" },
- { {"f24"}, "r24" },
- { {"f25"}, "r25" },
- { {"f26"}, "r26" },
- { {"f27"}, "r27" },
- { {"f28"}, "r28" },
- { {"f29"}, "r29" },
- { {"f30"}, "r30" },
- { {"f31"}, "r31" },
-};
-
-void MBlazeTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = GCCRegAliases;
- NumAliases = llvm::array_lengthof(GCCRegAliases);
-}
-} // end anonymous namespace.
-
-namespace {
// Namespace for x86 abstract base class
const Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
@@ -1695,11 +1613,17 @@ const TargetInfo::AddlRegName AddlRegNames[] = {
// most of the implementation can be shared.
class X86TargetInfo : public TargetInfo {
enum X86SSEEnum {
- NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2
+ NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F
} SSELevel;
enum MMX3DNowEnum {
NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon
} MMX3DNowLevel;
+ enum XOPEnum {
+ NoXOP,
+ SSE4A,
+ FMA4,
+ XOP
+ } XOPLevel;
bool HasAES;
bool HasPCLMUL;
@@ -1711,11 +1635,12 @@ class X86TargetInfo : public TargetInfo {
bool HasRTM;
bool HasPRFCHW;
bool HasRDSEED;
- bool HasSSE4a;
- bool HasFMA4;
+ bool HasTBM;
bool HasFMA;
- bool HasXOP;
bool HasF16C;
+ bool HasAVX512CD, HasAVX512ER, HasAVX512PF;
+ bool HasSHA;
+ bool HasCX16;
/// \brief Enumeration of all of the X86 CPUs supported by Clang.
///
@@ -1789,6 +1714,7 @@ class X86TargetInfo : public TargetInfo {
/// Atom processors
//@{
CK_Atom,
+ CK_Silvermont,
//@}
/// \name Nehalem
@@ -1800,6 +1726,10 @@ class X86TargetInfo : public TargetInfo {
CK_CoreAVX2,
//@}
+ /// \name Knights Landing
+ /// Knights Landing processor.
+ CK_KNL,
+
/// \name K6
/// K6 architecture processors.
//@{
@@ -1843,6 +1773,7 @@ class X86TargetInfo : public TargetInfo {
//@{
CK_BDVER1,
CK_BDVER2,
+ CK_BDVER3,
//@}
/// This specification is deprecated and will be removed in the future.
@@ -1858,13 +1789,21 @@ class X86TargetInfo : public TargetInfo {
//@}
} CPU;
+ enum FPMathKind {
+ FP_Default,
+ FP_SSE,
+ FP_387
+ } FPMath;
+
public:
- X86TargetInfo(const std::string& triple)
- : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
- HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false),
- HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false),
- HasPRFCHW(false), HasRDSEED(false), HasSSE4a(false), HasFMA4(false),
- HasFMA(false), HasXOP(false), HasF16C(false), CPU(CK_Generic) {
+ X86TargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
+ XOPLevel(NoXOP), HasAES(false), HasPCLMUL(false), HasLZCNT(false),
+ HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false),
+ HasRTM(false), HasPRFCHW(false), HasRDSEED(false), HasTBM(false),
+ HasFMA(false), HasF16C(false), HasAVX512CD(false), HasAVX512ER(false),
+ HasAVX512PF(false), HasSHA(false), HasCX16(false), CPU(CK_Generic),
+ FPMath(FP_Default) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1900,12 +1839,24 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const;
+ 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);
+ virtual void setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled) const {
+ setFeatureEnabledImpl(Features, Name, Enabled);
+ }
+ // This exists purely to cut down on the number of virtual calls in
+ // getDefaultFeatures which calls this repeatedly.
+ static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled);
virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
virtual bool hasFeature(StringRef Feature) const;
- virtual void HandleTargetFeatures(std::vector<std::string> &Features);
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags);
virtual const char* getABI() const {
if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
@@ -1939,10 +1890,12 @@ public:
.Case("core2", CK_Core2)
.Case("penryn", CK_Penryn)
.Case("atom", CK_Atom)
+ .Case("slm", CK_Silvermont)
.Case("corei7", CK_Corei7)
.Case("corei7-avx", CK_Corei7AVX)
.Case("core-avx-i", CK_CoreAVXi)
.Case("core-avx2", CK_CoreAVX2)
+ .Case("knl", CK_KNL)
.Case("k6", CK_K6)
.Case("k6-2", CK_K6_2)
.Case("k6-3", CK_K6_3)
@@ -1963,6 +1916,7 @@ public:
.Case("btver2", CK_BTVER2)
.Case("bdver1", CK_BDVER1)
.Case("bdver2", CK_BDVER2)
+ .Case("bdver3", CK_BDVER3)
.Case("x86-64", CK_x86_64)
.Case("geode", CK_Geode)
.Default(CK_Generic);
@@ -2013,10 +1967,12 @@ public:
case CK_Core2:
case CK_Penryn:
case CK_Atom:
+ case CK_Silvermont:
case CK_Corei7:
case CK_Corei7AVX:
case CK_CoreAVXi:
case CK_CoreAVX2:
+ case CK_KNL:
case CK_Athlon64:
case CK_Athlon64SSE3:
case CK_AthlonFX:
@@ -2029,12 +1985,15 @@ public:
case CK_BTVER2:
case CK_BDVER1:
case CK_BDVER2:
+ case CK_BDVER3:
case CK_x86_64:
return true;
}
llvm_unreachable("Unhandled CPU kind");
}
+ virtual bool setFPMath(StringRef Name);
+
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
// We accept all non-ARM calling conventions
return (CC == CC_X86ThisCall ||
@@ -2050,40 +2009,24 @@ public:
}
};
-void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
- // FIXME: This should not be here.
- Features["3dnow"] = false;
- Features["3dnowa"] = false;
- Features["mmx"] = false;
- Features["sse"] = false;
- Features["sse2"] = false;
- Features["sse3"] = false;
- Features["ssse3"] = false;
- Features["sse41"] = false;
- Features["sse42"] = false;
- Features["sse4a"] = false;
- Features["aes"] = false;
- Features["pclmul"] = false;
- Features["avx"] = false;
- Features["avx2"] = false;
- Features["lzcnt"] = false;
- Features["rdrand"] = false;
- Features["bmi"] = false;
- Features["bmi2"] = false;
- Features["popcnt"] = false;
- Features["rtm"] = false;
- Features["prfchw"] = false;
- Features["rdseed"] = false;
- Features["fma4"] = false;
- Features["fma"] = false;
- Features["xop"] = false;
- Features["f16c"] = false;
+bool X86TargetInfo::setFPMath(StringRef Name) {
+ if (Name == "387") {
+ FPMath = FP_387;
+ return true;
+ }
+ if (Name == "sse") {
+ FPMath = FP_SSE;
+ return true;
+ }
+ return false;
+}
+void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
// FIXME: This *really* should not be here.
// X86_64 always has SSE2.
if (getTriple().getArch() == llvm::Triple::x86_64)
- setFeatureEnabled(Features, "sse2", true);
+ setFeatureEnabledImpl(Features, "sse2", true);
switch (CPU) {
case CK_Generic:
@@ -2096,295 +2039,349 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
break;
case CK_PentiumMMX:
case CK_Pentium2:
- setFeatureEnabled(Features, "mmx", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_Pentium3:
case CK_Pentium3M:
- setFeatureEnabled(Features, "sse", true);
+ setFeatureEnabledImpl(Features, "sse", true);
break;
case CK_PentiumM:
case CK_Pentium4:
case CK_Pentium4M:
case CK_x86_64:
- setFeatureEnabled(Features, "sse2", true);
+ setFeatureEnabledImpl(Features, "sse2", true);
break;
case CK_Yonah:
case CK_Prescott:
case CK_Nocona:
- setFeatureEnabled(Features, "sse3", true);
+ setFeatureEnabledImpl(Features, "sse3", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Core2:
- setFeatureEnabled(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Penryn:
- setFeatureEnabled(Features, "sse4.1", true);
+ setFeatureEnabledImpl(Features, "sse4.1", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Atom:
- setFeatureEnabled(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ break;
+ case CK_Silvermont:
+ setFeatureEnabledImpl(Features, "sse4.2", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
break;
case CK_Corei7:
- setFeatureEnabled(Features, "sse4", true);
+ setFeatureEnabledImpl(Features, "sse4.2", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Corei7AVX:
- setFeatureEnabled(Features, "avx", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "avx", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
break;
case CK_CoreAVXi:
- setFeatureEnabled(Features, "avx", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
- setFeatureEnabled(Features, "rdrnd", true);
- setFeatureEnabled(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "avx", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
break;
case CK_CoreAVX2:
- setFeatureEnabled(Features, "avx2", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "rdrnd", true);
- setFeatureEnabled(Features, "f16c", true);
- setFeatureEnabled(Features, "bmi", true);
- setFeatureEnabled(Features, "bmi2", true);
- setFeatureEnabled(Features, "rtm", true);
- setFeatureEnabled(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "avx2", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ setFeatureEnabledImpl(Features, "rtm", true);
+ setFeatureEnabledImpl(Features, "fma", 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, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ setFeatureEnabledImpl(Features, "rtm", true);
+ setFeatureEnabledImpl(Features, "fma", true);
break;
case CK_K6:
case CK_WinChipC6:
- setFeatureEnabled(Features, "mmx", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_K6_2:
case CK_K6_3:
case CK_WinChip2:
case CK_C3:
- setFeatureEnabled(Features, "3dnow", true);
+ setFeatureEnabledImpl(Features, "3dnow", true);
break;
case CK_Athlon:
case CK_AthlonThunderbird:
case CK_Geode:
- setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabledImpl(Features, "3dnowa", true);
break;
case CK_Athlon4:
case CK_AthlonXP:
case CK_AthlonMP:
- setFeatureEnabled(Features, "sse", true);
- setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabledImpl(Features, "sse", true);
+ setFeatureEnabledImpl(Features, "3dnowa", true);
break;
case CK_K8:
case CK_Opteron:
case CK_Athlon64:
case CK_AthlonFX:
- setFeatureEnabled(Features, "sse2", true);
- setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabledImpl(Features, "sse2", true);
+ setFeatureEnabledImpl(Features, "3dnowa", true);
break;
case CK_K8SSE3:
case CK_OpteronSSE3:
case CK_Athlon64SSE3:
- setFeatureEnabled(Features, "sse3", true);
- setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabledImpl(Features, "sse3", true);
+ setFeatureEnabledImpl(Features, "3dnowa", true);
break;
case CK_AMDFAM10:
- setFeatureEnabled(Features, "sse3", true);
- setFeatureEnabled(Features, "sse4a", true);
- setFeatureEnabled(Features, "3dnowa", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "popcnt", true);
+ setFeatureEnabledImpl(Features, "sse3", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "3dnowa", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
break;
case CK_BTVER1:
- setFeatureEnabled(Features, "ssse3", true);
- setFeatureEnabled(Features, "sse4a", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "popcnt", true);
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
break;
case CK_BTVER2:
- setFeatureEnabled(Features, "avx", true);
- setFeatureEnabled(Features, "sse4a", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
- setFeatureEnabled(Features, "bmi", true);
- setFeatureEnabled(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "avx", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_BDVER1:
- setFeatureEnabled(Features, "xop", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "xop", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_BDVER2:
- setFeatureEnabled(Features, "xop", true);
- setFeatureEnabled(Features, "lzcnt", true);
- setFeatureEnabled(Features, "aes", true);
- setFeatureEnabled(Features, "pclmul", true);
- setFeatureEnabled(Features, "bmi", true);
- setFeatureEnabled(Features, "fma", true);
- setFeatureEnabled(Features, "f16c", true);
+ case CK_BDVER3:
+ setFeatureEnabledImpl(Features, "xop", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "tbm", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_C3_2:
- setFeatureEnabled(Features, "sse", true);
+ setFeatureEnabledImpl(Features, "sse", true);
break;
}
}
-bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- // FIXME: This *really* should not be here. We need some way of translating
- // options into llvm subtarget features.
- if (!Features.count(Name) &&
- (Name != "sse4" && Name != "sse4.2" && Name != "sse4.1" &&
- Name != "rdrnd"))
- return false;
+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;
+ 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;
+ }
- // FIXME: this should probably use a switch with fall through.
+ 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"] = false;
+ setXOPLevel(Features, FMA4, false);
+ case AVX2:
+ Features["avx2"] = false;
+ case AVX512F:
+ Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
+ Features["avx512pf"] = false;
+ }
+}
+void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
+ MMX3DNowEnum Level, bool Enabled) {
if (Enabled) {
- if (Name == "mmx")
+ switch (Level) {
+ case AMD3DNowAthlon:
+ Features["3dnowa"] = true;
+ case AMD3DNow:
+ Features["3dnow"] = true;
+ case MMX:
Features["mmx"] = true;
- else if (Name == "sse")
- Features["mmx"] = Features["sse"] = true;
- else if (Name == "sse2")
- Features["mmx"] = Features["sse"] = Features["sse2"] = true;
- else if (Name == "sse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- true;
- else if (Name == "ssse3")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = true;
- else if (Name == "sse4" || Name == "sse4.2")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = true;
- else if (Name == "sse4.1")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = true;
- else if (Name == "3dnow")
- Features["mmx"] = Features["3dnow"] = true;
- else if (Name == "3dnowa")
- Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = true;
- else if (Name == "aes")
- Features["sse"] = Features["sse2"] = Features["aes"] = true;
- else if (Name == "pclmul")
- Features["sse"] = Features["sse2"] = Features["pclmul"] = true;
- else if (Name == "avx")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = Features["avx"] = true;
- else if (Name == "avx2")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = Features["avx"] = Features["avx2"] = true;
- else if (Name == "fma")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = Features["avx"] = Features["fma"] = true;
- else if (Name == "fma4")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = Features["avx"] = Features["sse4a"] =
- Features["fma4"] = true;
- else if (Name == "xop")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["popcnt"] = Features["avx"] = Features["sse4a"] =
- Features["fma4"] = Features["xop"] = true;
- else if (Name == "sse4a")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["sse4a"] = true;
- else if (Name == "lzcnt")
- Features["lzcnt"] = true;
- else if (Name == "rdrnd")
- Features["rdrand"] = true;
- else if (Name == "bmi")
- Features["bmi"] = true;
- else if (Name == "bmi2")
- Features["bmi2"] = true;
- else if (Name == "popcnt")
- Features["popcnt"] = true;
- else if (Name == "f16c")
- Features["f16c"] = true;
- else if (Name == "rtm")
- Features["rtm"] = true;
- else if (Name == "prfchw")
- Features["prfchw"] = true;
- else if (Name == "rdseed")
- Features["rdseed"] = true;
- } else {
- if (Name == "mmx")
- Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
- else if (Name == "sse")
- Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["sse4a"] = Features["avx"] = Features["avx2"] =
- Features["fma"] = Features["fma4"] = Features["aes"] =
- Features["pclmul"] = Features["xop"] = false;
- else if (Name == "sse2")
- Features["sse2"] = Features["sse3"] = Features["ssse3"] =
- Features["sse41"] = Features["sse42"] = Features["sse4a"] =
- Features["avx"] = Features["avx2"] = Features["fma"] =
- Features["fma4"] = Features["aes"] = Features["pclmul"] =
- Features["xop"] = false;
- else if (Name == "sse3")
- Features["sse3"] = Features["ssse3"] = Features["sse41"] =
- Features["sse42"] = Features["sse4a"] = Features["avx"] =
- Features["avx2"] = Features["fma"] = Features["fma4"] =
- Features["xop"] = false;
- else if (Name == "ssse3")
- Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["avx"] = Features["avx2"] = Features["fma"] = false;
- else if (Name == "sse4" || Name == "sse4.1")
- Features["sse41"] = Features["sse42"] = Features["avx"] =
- Features["avx2"] = Features["fma"] = false;
- else if (Name == "sse4.2")
- Features["sse42"] = Features["avx"] = Features["avx2"] =
- Features["fma"] = false;
- else if (Name == "3dnow")
- Features["3dnow"] = Features["3dnowa"] = false;
- else if (Name == "3dnowa")
- Features["3dnowa"] = false;
- else if (Name == "aes")
- Features["aes"] = false;
- else if (Name == "pclmul")
- Features["pclmul"] = false;
- else if (Name == "avx")
- Features["avx"] = Features["avx2"] = Features["fma"] =
- Features["fma4"] = Features["xop"] = false;
- else if (Name == "avx2")
- Features["avx2"] = false;
- else if (Name == "fma")
- Features["fma"] = false;
- else if (Name == "sse4a")
- Features["sse4a"] = Features["fma4"] = Features["xop"] = false;
- else if (Name == "lzcnt")
- Features["lzcnt"] = false;
- else if (Name == "rdrnd")
- Features["rdrand"] = false;
- else if (Name == "bmi")
- Features["bmi"] = false;
- else if (Name == "bmi2")
- Features["bmi2"] = false;
- else if (Name == "popcnt")
- Features["popcnt"] = false;
- else if (Name == "fma4")
- Features["fma4"] = Features["xop"] = false;
- else if (Name == "xop")
- Features["xop"] = false;
- else if (Name == "f16c")
- Features["f16c"] = false;
- else if (Name == "rtm")
- Features["rtm"] = false;
- else if (Name == "prfchw")
- Features["prfchw"] = false;
- else if (Name == "rdseed")
- Features["rdseed"] = false;
+ case NoMMX3DNow:
+ break;
+ }
+ return;
}
- return true;
+ 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;
+ }
}
-/// HandleTargetOptions - Perform initialization based on the user
+void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled) {
+ // FIXME: This *really* should not be here. We need some way of translating
+ // options into llvm subtarget features.
+ if (Name == "sse4")
+ Name = "sse4.2";
+
+ 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") {
+ if (Enabled)
+ setSSELevel(Features, AVX512F, Enabled);
+ } 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);
+ }
+}
+
+/// handleTargetFeatures - Perform initialization based on the user
/// configured set of features.
-void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
+bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
// Remember the maximum enabled sselevel.
for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
// Ignore disabled features.
@@ -2408,7 +2405,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
- if (Feature == "rdrand") {
+ if (Feature == "rdrnd") {
HasRDRND = true;
continue;
}
@@ -2443,37 +2440,53 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
- if (Feature == "sse4a") {
- HasSSE4a = true;
+ if (Feature == "tbm") {
+ HasTBM = true;
continue;
}
- if (Feature == "fma4") {
- HasFMA4 = true;
+ if (Feature == "fma") {
+ HasFMA = true;
continue;
}
- if (Feature == "fma") {
- HasFMA = true;
+ if (Feature == "f16c") {
+ HasF16C = true;
continue;
}
- if (Feature == "xop") {
- HasXOP = true;
+ if (Feature == "avx512cd") {
+ HasAVX512CD = true;
continue;
}
- if (Feature == "f16c") {
- HasF16C = true;
+ if (Feature == "avx512er") {
+ HasAVX512ER = true;
+ continue;
+ }
+
+ if (Feature == "avx512pf") {
+ HasAVX512PF = true;
+ continue;
+ }
+
+ if (Feature == "sha") {
+ HasSHA = true;
+ continue;
+ }
+
+ if (Feature == "cx16") {
+ HasCX16 = true;
continue;
}
assert(Features[i][0] == '+' && "Invalid target feature!");
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
+ .Case("avx512f", AVX512F)
.Case("avx2", AVX2)
.Case("avx", AVX)
- .Case("sse42", SSE42)
- .Case("sse41", SSE41)
+ .Case("sse4.2", SSE42)
+ .Case("sse4.1", SSE41)
.Case("ssse3", SSSE3)
.Case("sse3", SSE3)
.Case("sse2", SSE2)
@@ -2487,16 +2500,53 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.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);
+ }
+
+ // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled.
+ // Can't do this earlier because we need to be able to explicitly enable
+ // popcnt and still disable sse4.2.
+ if (!HasPOPCNT && SSELevel >= SSE42 &&
+ std::find(Features.begin(), Features.end(), "-popcnt") == Features.end()){
+ HasPOPCNT = true;
+ Features.push_back("+popcnt");
+ }
+
+ // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled.
+ if (!HasPRFCHW && MMX3DNowLevel >= AMD3DNow &&
+ std::find(Features.begin(), Features.end(), "-prfchw") == Features.end()){
+ HasPRFCHW = true;
+ Features.push_back("+prfchw");
+ }
+
+ // 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) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "sse";
+ return false;
+ } else if (FPMath == FP_387 && SSELevel >= SSE1) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "387";
+ return false;
}
// Don't tell the backend if we're turning off mmx; it will end up disabling
// SSE, which we don't want.
+ // Additionally, if SSE is enabled and mmx is not explicitly disabled,
+ // then enable MMX.
std::vector<std::string>::iterator it;
it = std::find(Features.begin(), Features.end(), "-mmx");
if (it != Features.end())
Features.erase(it);
+ else if (SSELevel > NoSSE)
+ MMX3DNowLevel = std::max(MMX3DNowLevel, MMX);
+ return true;
}
/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
@@ -2574,12 +2624,18 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Atom:
defineCPUMacros(Builder, "atom");
break;
+ case CK_Silvermont:
+ defineCPUMacros(Builder, "slm");
+ break;
case CK_Corei7:
case CK_Corei7AVX:
case CK_CoreAVXi:
case CK_CoreAVX2:
defineCPUMacros(Builder, "corei7");
break;
+ case CK_KNL:
+ defineCPUMacros(Builder, "knl");
+ break;
case CK_K6_2:
Builder.defineMacro("__k6_2__");
Builder.defineMacro("__tune_k6_2__");
@@ -2632,6 +2688,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_BDVER2:
defineCPUMacros(Builder, "bdver2");
break;
+ case CK_BDVER3:
+ defineCPUMacros(Builder, "bdver3");
+ break;
case CK_Geode:
defineCPUMacros(Builder, "geode");
break;
@@ -2676,23 +2735,43 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasRDSEED)
Builder.defineMacro("__RDSEED__");
- if (HasSSE4a)
- Builder.defineMacro("__SSE4A__");
+ if (HasTBM)
+ Builder.defineMacro("__TBM__");
- if (HasFMA4)
+ 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 (HasXOP)
- Builder.defineMacro("__XOP__");
-
if (HasF16C)
Builder.defineMacro("__F16C__");
+ if (HasAVX512CD)
+ Builder.defineMacro("__AVX512CD__");
+ if (HasAVX512ER)
+ Builder.defineMacro("__AVX512ER__");
+ if (HasAVX512PF)
+ Builder.defineMacro("__AVX512PF__");
+
+ if (HasSHA)
+ Builder.defineMacro("__SHA__");
+
+ if (HasCX16)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
+
// Each case falls through to the previous one here.
switch (SSELevel) {
+ case AVX512F:
+ Builder.defineMacro("__AVX512F__");
case AVX2:
Builder.defineMacro("__AVX2__");
case AVX:
@@ -2717,6 +2796,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) {
switch (SSELevel) {
+ case AVX512F:
case AVX2:
case AVX:
case SSE42:
@@ -2760,10 +2840,17 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.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("bmi", HasBMI)
.Case("bmi2", HasBMI2)
+ .Case("cx16", HasCX16)
+ .Case("f16c", HasF16C)
.Case("fma", HasFMA)
- .Case("fma4", HasFMA4)
+ .Case("fma4", XOPLevel >= FMA4)
+ .Case("tbm", HasTBM)
.Case("lzcnt", HasLZCNT)
.Case("rdrnd", HasRDRND)
.Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
@@ -2774,18 +2861,18 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("rtm", HasRTM)
.Case("prfchw", HasPRFCHW)
.Case("rdseed", HasRDSEED)
+ .Case("sha", HasSHA)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
.Case("sse3", SSELevel >= SSE3)
.Case("ssse3", SSELevel >= SSSE3)
- .Case("sse41", SSELevel >= SSE41)
- .Case("sse42", SSELevel >= SSE42)
- .Case("sse4a", HasSSE4a)
+ .Case("sse4.1", SSELevel >= SSE41)
+ .Case("sse4.2", SSELevel >= SSE42)
+ .Case("sse4a", XOPLevel >= SSE4A)
.Case("x86", true)
.Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
.Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
- .Case("xop", HasXOP)
- .Case("f16c", HasF16C)
+ .Case("xop", XOPLevel >= XOP)
.Default(false);
}
@@ -2858,7 +2945,7 @@ namespace {
// X86-32 generic target
class X86_32TargetInfo : public X86TargetInfo {
public:
- X86_32TargetInfo(const std::string& triple) : X86TargetInfo(triple) {
+ X86_32TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) {
DoubleAlign = LongLongAlign = 32;
LongDoubleWidth = 96;
LongDoubleAlign = 32;
@@ -2909,12 +2996,16 @@ public:
namespace {
class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> {
public:
- NetBSDI386TargetInfo(const std::string &triple) :
- NetBSDTargetInfo<X86_32TargetInfo>(triple) {
- }
+ NetBSDI386TargetInfo(const llvm::Triple &Triple)
+ : NetBSDTargetInfo<X86_32TargetInfo>(Triple) {}
virtual unsigned getFloatEvalMethod() const {
- // NetBSD defaults to "double" rounding
+ 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;
}
};
@@ -2923,8 +3014,8 @@ public:
namespace {
class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> {
public:
- OpenBSDI386TargetInfo(const std::string& triple) :
- OpenBSDTargetInfo<X86_32TargetInfo>(triple) {
+ OpenBSDI386TargetInfo(const llvm::Triple &Triple)
+ : OpenBSDTargetInfo<X86_32TargetInfo>(Triple) {
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
@@ -2935,8 +3026,8 @@ public:
namespace {
class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> {
public:
- BitrigI386TargetInfo(const std::string& triple) :
- BitrigTargetInfo<X86_32TargetInfo>(triple) {
+ BitrigI386TargetInfo(const llvm::Triple &Triple)
+ : BitrigTargetInfo<X86_32TargetInfo>(Triple) {
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
@@ -2947,8 +3038,8 @@ public:
namespace {
class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> {
public:
- DarwinI386TargetInfo(const std::string& triple) :
- DarwinTargetInfo<X86_32TargetInfo>(triple) {
+ DarwinI386TargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<X86_32TargetInfo>(Triple) {
LongDoubleWidth = 128;
LongDoubleAlign = 128;
SuitableAlign = 128;
@@ -2968,8 +3059,8 @@ namespace {
// x86-32 Windows target
class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
public:
- WindowsX86_32TargetInfo(const std::string& triple)
- : WindowsTargetInfo<X86_32TargetInfo>(triple) {
+ WindowsX86_32TargetInfo(const llvm::Triple &Triple)
+ : WindowsTargetInfo<X86_32TargetInfo>(Triple) {
TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
@@ -2989,8 +3080,8 @@ namespace {
// x86-32 Windows Visual Studio target
class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
- VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
- : WindowsX86_32TargetInfo(triple) {
+ VisualStudioWindowsX86_32TargetInfo(const llvm::Triple &Triple)
+ : WindowsX86_32TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
@@ -3010,9 +3101,8 @@ namespace {
// x86-32 MinGW target
class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
- MinGWX86_32TargetInfo(const std::string& triple)
- : WindowsX86_32TargetInfo(triple) {
- }
+ MinGWX86_32TargetInfo(const llvm::Triple &Triple)
+ : WindowsX86_32TargetInfo(Triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
@@ -3038,8 +3128,8 @@ namespace {
// x86-32 Cygwin target
class CygwinX86_32TargetInfo : public X86_32TargetInfo {
public:
- CygwinX86_32TargetInfo(const std::string& triple)
- : X86_32TargetInfo(triple) {
+ CygwinX86_32TargetInfo(const llvm::Triple &Triple)
+ : X86_32TargetInfo(Triple) {
TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
@@ -3064,8 +3154,7 @@ namespace {
// x86-32 Haiku target
class HaikuX86_32TargetInfo : public X86_32TargetInfo {
public:
- HaikuX86_32TargetInfo(const std::string& triple)
- : X86_32TargetInfo(triple) {
+ HaikuX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) {
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
@@ -3093,37 +3182,35 @@ protected:
Builder.defineMacro("__rtems__");
Builder.defineMacro("__ELF__");
}
-public:
- RTEMSTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {
- this->UserLabelPrefix = "";
- llvm::Triple Triple(triple);
- 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:
- // this->MCountName = "_mcount";
- break;
- case llvm::Triple::arm:
- // this->MCountName = "__mcount";
- break;
- }
+public:
+ RTEMSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ 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;
}
+ }
};
namespace {
// x86-32 RTEMS target
class RTEMSX86_32TargetInfo : public X86_32TargetInfo {
public:
- RTEMSX86_32TargetInfo(const std::string& triple)
- : X86_32TargetInfo(triple) {
+ RTEMSX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) {
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
@@ -3142,7 +3229,7 @@ namespace {
// x86-64 generic target
class X86_64TargetInfo : public X86TargetInfo {
public:
- X86_64TargetInfo(const std::string &triple) : X86TargetInfo(triple) {
+ X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
@@ -3181,9 +3268,9 @@ public:
}
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
- return (CC == CC_Default ||
- CC == CC_C ||
- CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
+ return (CC == CC_C ||
+ CC == CC_IntelOclBicc ||
+ CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning;
}
virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
@@ -3197,8 +3284,8 @@ namespace {
// x86-64 Windows target
class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
public:
- WindowsX86_64TargetInfo(const std::string& triple)
- : WindowsTargetInfo<X86_64TargetInfo>(triple) {
+ WindowsX86_64TargetInfo(const llvm::Triple &Triple)
+ : WindowsTargetInfo<X86_64TargetInfo>(Triple) {
TLSSupported = false;
WCharType = UnsignedShort;
LongWidth = LongAlign = 32;
@@ -3219,6 +3306,11 @@ public:
virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::CharPtrBuiltinVaList;
}
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ return (CC == CC_C ||
+ CC == CC_IntelOclBicc ||
+ CC == CC_X86_64SysV) ? CCCR_OK : CCCR_Warning;
+ }
};
} // end anonymous namespace
@@ -3226,8 +3318,8 @@ namespace {
// x86-64 Windows Visual Studio target
class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
- VisualStudioWindowsX86_64TargetInfo(const std::string& triple)
- : WindowsX86_64TargetInfo(triple) {
+ VisualStudioWindowsX86_64TargetInfo(const llvm::Triple &Triple)
+ : WindowsX86_64TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
@@ -3245,9 +3337,8 @@ namespace {
// x86-64 MinGW target
class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
- MinGWX86_64TargetInfo(const std::string& triple)
- : WindowsX86_64TargetInfo(triple) {
- }
+ MinGWX86_64TargetInfo(const llvm::Triple &Triple)
+ : WindowsX86_64TargetInfo(Triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
@@ -3271,8 +3362,8 @@ public:
namespace {
class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> {
public:
- DarwinX86_64TargetInfo(const std::string& triple)
- : DarwinTargetInfo<X86_64TargetInfo>(triple) {
+ DarwinX86_64TargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<X86_64TargetInfo>(Triple) {
Int64Type = SignedLongLong;
MaxVectorAlign = 256;
}
@@ -3282,8 +3373,8 @@ public:
namespace {
class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> {
public:
- OpenBSDX86_64TargetInfo(const std::string& triple)
- : OpenBSDTargetInfo<X86_64TargetInfo>(triple) {
+ OpenBSDX86_64TargetInfo(const llvm::Triple &Triple)
+ : OpenBSDTargetInfo<X86_64TargetInfo>(Triple) {
IntMaxType = SignedLongLong;
UIntMaxType = UnsignedLongLong;
Int64Type = SignedLongLong;
@@ -3294,11 +3385,11 @@ public:
namespace {
class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> {
public:
- BitrigX86_64TargetInfo(const std::string& triple)
- : BitrigTargetInfo<X86_64TargetInfo>(triple) {
- IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
- Int64Type = SignedLongLong;
+ BitrigX86_64TargetInfo(const llvm::Triple &Triple)
+ : BitrigTargetInfo<X86_64TargetInfo>(Triple) {
+ IntMaxType = SignedLongLong;
+ UIntMaxType = UnsignedLongLong;
+ Int64Type = SignedLongLong;
}
};
}
@@ -3308,9 +3399,17 @@ class AArch64TargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ enum FPUModeEnum {
+ FPUMode,
+ NeonMode
+ };
+
+ unsigned FPU;
+ unsigned Crypto;
static const Builtin::Info BuiltinInfo[];
+
public:
- AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ AArch64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
LongWidth = LongAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
@@ -3336,22 +3435,20 @@ public:
Builder.defineMacro("__AARCH64EL__");
// ACLE predefines. Many can only have one possible value on v8 AArch64.
-
- // FIXME: these were written based on an unreleased version of a 32-bit ACLE
- // which was intended to be compatible with a 64-bit implementation. They
- // will need updating when a real 64-bit ACLE exists. Particularly pressing
- // instances are: __ARM_ARCH_ISA_ARM, __ARM_ARCH_ISA_THUMB, __ARM_PCS.
- Builder.defineMacro("__ARM_ACLE", "101");
+ Builder.defineMacro("__ARM_ACLE", "200");
Builder.defineMacro("__ARM_ARCH", "8");
Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
+ Builder.defineMacro("__ARM_64BIT_STATE");
+ Builder.defineMacro("__ARM_PCS_AAPCS64");
+ Builder.defineMacro("__ARM_ARCH_ISA_A64");
+
Builder.defineMacro("__ARM_FEATURE_UNALIGNED");
Builder.defineMacro("__ARM_FEATURE_CLZ");
Builder.defineMacro("__ARM_FEATURE_FMA");
+ Builder.defineMacro("__ARM_FEATURE_DIV");
- // FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean
- // 128-bit LDXP present, at which point this becomes 0x1f.
- Builder.defineMacro("__ARM_FEATURE_LDREX", "0xf");
+ Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
// 0xe implies support for half, single and double precision operations.
Builder.defineMacro("__ARM_FP", "0xe");
@@ -3373,7 +3470,17 @@ public:
Opts.ShortEnums ? "1" : "4");
if (BigEndian)
- Builder.defineMacro("__ARM_BIG_ENDIAN");
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+
+ if (FPU == NeonMode) {
+ Builder.defineMacro("__ARM_NEON");
+ // 64-bit NEON supports half, single and double precision operations.
+ Builder.defineMacro("__ARM_NEON_FP", "7");
+ }
+
+ if (Crypto) {
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO");
+ }
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -3381,9 +3488,30 @@ public:
NumRecords = clang::AArch64::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
virtual bool hasFeature(StringRef Feature) const {
- return Feature == "aarch64";
+ return Feature == "aarch64" || (Feature == "neon" && FPU == NeonMode);
}
- virtual void getGCCRegNames(const char * const *&Names,
+
+ virtual bool setCPU(const std::string &Name) {
+ return llvm::StringSwitch<bool>(Name)
+ .Case("generic", true)
+ .Cases("cortex-a53", "cortex-a57", true)
+ .Default(false);
+ }
+
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ FPU = FPUMode;
+ Crypto = 0;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+ if (Features[i] == "+neon")
+ FPU = NeonMode;
+ if (Features[i] == "+crypto")
+ Crypto = 1;
+ }
+ return true;
+ }
+
+ virtual void getGCCRegNames(const char *const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const;
@@ -3504,11 +3632,18 @@ class ARMTargetInfo : public TargetInfo {
VFP2FPU = (1 << 0),
VFP3FPU = (1 << 1),
VFP4FPU = (1 << 2),
- NeonFPU = (1 << 3)
+ 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);
+ return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8);
}
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -3516,15 +3651,24 @@ class ARMTargetInfo : public TargetInfo {
std::string ABI, CPU;
- unsigned FPU : 4;
+ enum {
+ FP_Default,
+ FP_VFP,
+ FP_Neon
+ } FPMath;
+
+ unsigned FPU : 5;
unsigned IsAAPCS : 1;
unsigned IsThumb : 1;
+ unsigned HWDiv : 2;
// Initialized via features.
unsigned SoftFloat : 1;
unsigned SoftFloatABI : 1;
+ unsigned CRC : 1;
+
static const Builtin::Info BuiltinInfo[];
static bool shouldUseInlineAtomic(const llvm::Triple &T) {
@@ -3533,8 +3677,11 @@ class ARMTargetInfo : public TargetInfo {
// the kernel which on armv6 and newer uses ldrex and strex. The net result
// is that if we assume the kernel is at least as recent as the hardware,
// it is safe to use atomic instructions on armv6 and newer.
- if (T.getOS() != llvm::Triple::Linux)
- return false;
+ if (!T.isOSLinux() &&
+ T.getOS() != llvm::Triple::FreeBSD &&
+ T.getOS() != llvm::Triple::NetBSD &&
+ T.getOS() != llvm::Triple::Bitrig)
+ return false;
StringRef ArchName = T.getArchName();
if (T.getArch() == llvm::Triple::arm) {
if (!ArchName.startswith("armv"))
@@ -3556,14 +3703,23 @@ class ARMTargetInfo : public TargetInfo {
}
public:
- ARMTargetInfo(const std::string &TripleStr)
- : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true)
- {
+ ARMTargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), ABI("aapcs-linux"), CPU("arm1136j-s"),
+ FPMath(FP_Default), IsAAPCS(true) {
BigEndian = false;
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
- WCharType = UnsignedInt;
+ switch (getTriple().getOS()) {
+ case llvm::Triple::NetBSD:
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ WCharType = SignedInt;
+ break;
+ default:
+ // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
+ WCharType = UnsignedInt;
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ break;
+ }
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
@@ -3639,6 +3795,9 @@ public:
// FIXME: Override "preferred align" for double and long long.
} else if (Name == "aapcs" || Name == "aapcs-vfp") {
+ // size_t is unsigned long on Darwin.
+ if (getTriple().isOSDarwin())
+ SizeType = UnsignedLong;
IsAAPCS = true;
// FIXME: Enumerated types are variable width in straight AAPCS.
} else if (Name == "aapcs-linux") {
@@ -3650,33 +3809,45 @@ public:
}
void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ StringRef ArchName = getTriple().getArchName();
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
- else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
- CPU == "cortex-a9" || CPU == "cortex-a9-mp")
+ else if (CPU == "cortex-a8" || CPU == "cortex-a9" ||
+ CPU == "cortex-a9-mp") {
+ Features["vfp3"] = true;
+ Features["neon"] = true;
+ }
+ else if (CPU == "cortex-a5") {
+ Features["vfp4"] = true;
Features["neon"] = true;
- else if (CPU == "swift" || CPU == "cortex-a7") {
+ } else if (CPU == "swift" || CPU == "cortex-a7" || CPU == "cortex-a15") {
Features["vfp4"] = true;
Features["neon"] = true;
+ Features["hwdiv"] = true;
+ Features["hwdiv-arm"] = true;
+ } else if (CPU == "cortex-a53" || CPU == "cortex-a57") {
+ Features["fp-armv8"] = true;
+ Features["neon"] = true;
+ Features["hwdiv"] = true;
+ Features["hwdiv-arm"] = true;
+ Features["crc"] = true;
+ } else if (CPU == "cortex-r5" || CPU == "cortex-m3" ||
+ CPU == "cortex-m4" ||
+ // Enable the hwdiv extension for all v8a AArch32 cores by
+ // default.
+ ArchName == "armv8a" || ArchName == "armv8" ||
+ ArchName == "thumbv8a" || ArchName == "thumbv8") {
+ Features["hwdiv"] = true;
+ Features["hwdiv-arm"] = true;
}
}
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- if (Name == "soft-float" || Name == "soft-float-abi" ||
- Name == "vfp2" || Name == "vfp3" || Name == "vfp4" || Name == "neon" ||
- Name == "d16" || Name == "neonfp") {
- Features[Name] = Enabled;
- } else
- return false;
-
- return true;
- }
-
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
FPU = 0;
+ CRC = 0;
SoftFloat = SoftFloatABI = false;
+ HWDiv = 0;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
if (Features[i] == "+soft-float")
SoftFloat = true;
@@ -3688,10 +3859,28 @@ public:
FPU |= VFP3FPU;
else if (Features[i] == "+vfp4")
FPU |= VFP4FPU;
+ else if (Features[i] == "+fp-armv8")
+ FPU |= FPARMV8;
else if (Features[i] == "+neon")
FPU |= NeonFPU;
+ else if (Features[i] == "+hwdiv")
+ HWDiv |= HWDivThumb;
+ else if (Features[i] == "+hwdiv-arm")
+ HWDiv |= HWDivARM;
+ else if (Features[i] == "+crc")
+ CRC = 1;
+ }
+
+ 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.
std::vector<std::string>::iterator it;
it = std::find(Features.begin(), Features.end(), "+soft-float");
@@ -3700,6 +3889,7 @@ public:
it = std::find(Features.begin(), Features.end(), "+soft-float-abi");
if (it != Features.end())
Features.erase(it);
+ return true;
}
virtual bool hasFeature(StringRef Feature) const {
@@ -3707,8 +3897,9 @@ public:
.Case("arm", true)
.Case("softfloat", SoftFloat)
.Case("thumb", IsThumb)
- .Case("neon", FPU == NeonFPU && !SoftFloat &&
- StringRef(getCPUDefineSuffix(CPU)).startswith("7"))
+ .Case("neon", (FPU & NeonFPU) && !SoftFloat)
+ .Case("hwdiv", HWDiv & HWDivThumb)
+ .Case("hwdiv-arm", HWDiv & HWDivARM)
.Default(false);
}
// FIXME: Should we actually have some table instead of these switches?
@@ -3729,19 +3920,22 @@ public:
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
- .Cases("cortex-a9", "cortex-a15", "7A")
- .Case("cortex-r5", "7R")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "7A")
+ .Cases("cortex-r4", "cortex-r5", "7R")
.Case("cortex-a9-mp", "7F")
.Case("swift", "7S")
.Cases("cortex-m3", "cortex-m4", "7M")
.Case("cortex-m0", "6M")
+ .Cases("cortex-a53", "cortex-a57", "8A")
.Default(0);
}
static const char *getCPUProfile(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
- .Cases("cortex-a8", "cortex-a9", "A")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "A")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "A")
+ .Cases("cortex-a53", "cortex-a57", "A")
.Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
- .Case("cortex-r5", "R")
+ .Cases("cortex-r4", "cortex-r5", "R")
.Default("");
}
virtual bool setCPU(const std::string &Name) {
@@ -3751,6 +3945,7 @@ public:
CPU = Name;
return true;
}
+ virtual bool setFPMath(StringRef Name);
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
@@ -3763,6 +3958,10 @@ public:
Builder.defineMacro("__REGISTER_PREFIX__", "");
StringRef CPUArch = getCPUDefineSuffix(CPU);
+ unsigned int CPUArchVer;
+ if(CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer)) {
+ llvm_unreachable("Invalid char for architecture version number");
+ }
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
StringRef CPUProfile = getCPUProfile(CPU);
@@ -3773,12 +3972,12 @@ public:
// FIXME: It's more complicated than this and we don't really support
// interworking.
- if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
+ if (5 <= CPUArchVer && CPUArchVer <= 7)
Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
- // M-class CPUs on Darwin follow AAPCS, but not EABI.
- if (!(getTriple().isOSDarwin() && CPUProfile == "M"))
+ // Embedded targets on Darwin follow AAPCS, but not EABI.
+ if (!getTriple().isOSDarwin())
Builder.defineMacro("__ARM_EABI__");
Builder.defineMacro("__ARM_PCS", "1");
@@ -3792,13 +3991,14 @@ public:
if (CPU == "xscale")
Builder.defineMacro("__XSCALE__");
- bool IsARMv7 = CPUArch.startswith("7");
if (IsThumb) {
Builder.defineMacro("__THUMBEL__");
Builder.defineMacro("__thumb__");
- if (CPUArch == "6T2" || IsARMv7)
+ if (CPUArch == "6T2" || CPUArchVer == 7)
Builder.defineMacro("__thumb2__");
}
+ if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb))
+ 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__");
@@ -3817,8 +4017,18 @@ public:
// 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 && IsARMv7)
+ if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7)
Builder.defineMacro("__ARM_NEON__");
+
+ if (CRC)
+ Builder.defineMacro("__ARM_FEATURE_CRC32");
+
+ if (CPUArchVer >= 6 && CPUArch != "6M") {
+ 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");
+ }
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -3896,8 +4106,7 @@ public:
case 'r': {
switch (Modifier) {
default:
- return isInOut || (isOutput && Size >= 32) ||
- (!isOutput && !isInOut && Size <= 32);
+ return (isInOut || isOutput || Size <= 64);
case 'q':
// A register of size 32 cannot fit a vector type.
return false;
@@ -3923,6 +4132,18 @@ public:
}
};
+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",
@@ -3996,8 +4217,8 @@ protected:
}
public:
- DarwinARMTargetInfo(const std::string& triple)
- : DarwinTargetInfo<ARMTargetInfo>(triple) {
+ DarwinARMTargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<ARMTargetInfo>(Triple) {
HasAlignMac68kSupport = true;
// iOS always has 64-bit atomic instructions.
// FIXME: This should be based off of the target features in ARMTargetInfo.
@@ -4018,7 +4239,7 @@ class HexagonTargetInfo : public TargetInfo {
static const TargetInfo::GCCRegAlias GCCRegAliases[];
std::string CPU;
public:
- HexagonTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
DescriptionString = ("e-p:32:32:32-"
"i64:64:64-i32:32:32-i16:16:16-i1:32:32-"
@@ -4171,23 +4392,15 @@ class SparcTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
bool SoftFloat;
public:
- SparcTargetInfo(const std::string &triple) : TargetInfo(triple) {}
+ SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {}
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- if (Name == "soft-float")
- Features[Name] = Enabled;
- else
- return false;
-
- return true;
- }
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
SoftFloat = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i)
if (Features[i] == "+soft-float")
SoftFloat = true;
+ return true;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4284,7 +4497,7 @@ void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
// SPARC v8 is the 32-bit mode selected by Triple::sparc.
class SparcV8TargetInfo : public SparcTargetInfo {
public:
- SparcV8TargetInfo(const std::string& triple) : SparcTargetInfo(triple) {
+ SparcV8TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) {
// FIXME: Support Sparc quad-precision long double?
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
@@ -4300,10 +4513,22 @@ public:
// SPARC v9 is the 64-bit mode selected by Triple::sparcv9.
class SparcV9TargetInfo : public SparcTargetInfo {
public:
- SparcV9TargetInfo(const std::string& triple) : SparcTargetInfo(triple) {
+ SparcV9TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) {
// FIXME: Support Sparc quad-precision long double?
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64: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;
+ UIntMaxType = UnsignedLongLong;
+ } else {
+ IntMaxType = SignedLong;
+ UIntMaxType = UnsignedLong;
+ }
+ Int64Type = IntMaxType;
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -4327,16 +4552,16 @@ public:
namespace {
class AuroraUXSparcV8TargetInfo : public AuroraUXTargetInfo<SparcV8TargetInfo> {
public:
- AuroraUXSparcV8TargetInfo(const std::string& triple) :
- AuroraUXTargetInfo<SparcV8TargetInfo>(triple) {
+ AuroraUXSparcV8TargetInfo(const llvm::Triple &Triple)
+ : AuroraUXTargetInfo<SparcV8TargetInfo>(Triple) {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
}
};
class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> {
public:
- SolarisSparcV8TargetInfo(const std::string& triple) :
- SolarisTargetInfo<SparcV8TargetInfo>(triple) {
+ SolarisSparcV8TargetInfo(const llvm::Triple &Triple)
+ : SolarisTargetInfo<SparcV8TargetInfo>(Triple) {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
}
@@ -4348,7 +4573,7 @@ namespace {
static const char *const GCCRegNames[];
public:
- SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
TLSSupported = true;
IntWidth = IntAlign = 32;
LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
@@ -4392,6 +4617,17 @@ namespace {
virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::SystemZBuiltinVaList;
}
+ virtual bool setCPU(const std::string &Name) {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("z10", true)
+ .Case("z196", true)
+ .Case("zEC12", true)
+ .Default(false);
+
+ // No need to store the CPU yet. There aren't any CPU-specific
+ // macros to define.
+ return CPUKnown;
+ }
};
const char *const SystemZTargetInfo::GCCRegNames[] = {
@@ -4441,7 +4677,7 @@ namespace {
class MSP430TargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
public:
- MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ MSP430TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
TLSSupported = false;
IntWidth = 16; IntAlign = 16;
@@ -4450,9 +4686,9 @@ namespace {
PointerWidth = 16; PointerAlign = 16;
SuitableAlign = 16;
SizeType = UnsignedInt;
- IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
- IntPtrType = SignedShort;
+ IntMaxType = SignedLongLong;
+ UIntMaxType = UnsignedLongLong;
+ IntPtrType = SignedInt;
PtrDiffType = SignedInt;
SigAtomicType = SignedLong;
DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16";
@@ -4528,7 +4764,7 @@ namespace {
class TCETargetInfo : public TargetInfo{
public:
- TCETargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TCETargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
TLSSupported = false;
IntWidth = 32;
LongWidth = LongLongWidth = 32;
@@ -4556,6 +4792,7 @@ namespace {
"f32:32:32-f64:32:32-v64:32:32-"
"v128:32:32-a0:0:32-n32";
AddrSpaceMap = &TCEOpenCLAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -4589,10 +4826,13 @@ namespace {
namespace {
class MipsTargetInfoBase : public TargetInfo {
+ virtual void setDescriptionString() = 0;
+
static const Builtin::Info BuiltinInfo[];
std::string CPU;
bool IsMips16;
bool IsMicromips;
+ bool IsNan2008;
bool IsSingleFloat;
enum MipsFloatABI {
HardFloat, SoftFloat
@@ -4600,23 +4840,18 @@ class MipsTargetInfoBase : public TargetInfo {
enum DspRevEnum {
NoDSP, DSP1, DSP2
} DspRev;
+ bool HasMSA;
protected:
+ bool HasFP64;
std::string ABI;
public:
- MipsTargetInfoBase(const std::string& triple,
- const std::string& ABIStr,
- const std::string& CPUStr)
- : TargetInfo(triple),
- CPU(CPUStr),
- IsMips16(false),
- IsMicromips(false),
- IsSingleFloat(false),
- FloatABI(HardFloat),
- DspRev(NoDSP),
- ABI(ABIStr)
- {}
+ MipsTargetInfoBase(const llvm::Triple &Triple, const std::string &ABIStr,
+ const std::string &CPUStr)
+ : TargetInfo(Triple), CPU(CPUStr), IsMips16(false), IsMicromips(false),
+ IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat),
+ DspRev(NoDSP), HasMSA(false), HasFP64(false), ABI(ABIStr) {}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) = 0;
@@ -4647,12 +4882,19 @@ public:
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;
@@ -4667,6 +4909,9 @@ public:
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()));
@@ -4681,14 +4926,17 @@ public:
NumRecords = clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin;
}
virtual bool hasFeature(StringRef Feature) const {
- return Feature == "mips";
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("mips", true)
+ .Case("fp64", HasFP64)
+ .Default(false);
}
virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::VoidPtrBuiltinVaList;
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const {
- static const char * const GCCRegNames[] = {
+ static const char *const GCCRegNames[] = {
// CPU register names
// Must match second column of GCCRegAliases
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
@@ -4702,7 +4950,15 @@ public:
"$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
// Hi/lo and condition register names
"hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7"
+ "$fcc5","$fcc6","$fcc7",
+ // 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"
};
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
@@ -4735,33 +4991,15 @@ public:
return "";
}
- virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name,
- bool Enabled) const {
- if (Name == "soft-float" || Name == "single-float" ||
- Name == "o32" || Name == "n32" || Name == "n64" || Name == "eabi" ||
- Name == "mips32" || Name == "mips32r2" ||
- Name == "mips64" || Name == "mips64r2" ||
- Name == "mips16" || Name == "micromips" ||
- Name == "dsp" || Name == "dspr2") {
- Features[Name] = Enabled;
- return true;
- } else if (Name == "32") {
- Features["o32"] = Enabled;
- return true;
- } else if (Name == "64") {
- Features["n64"] = Enabled;
- return true;
- }
- return false;
- }
-
- virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ virtual bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
IsMips16 = false;
IsMicromips = false;
+ IsNan2008 = false;
IsSingleFloat = false;
FloatABI = HardFloat;
DspRev = NoDSP;
+ HasFP64 = ABI == "n32" || ABI == "n64" || ABI == "64";
for (std::vector<std::string>::iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it) {
@@ -4777,13 +5015,28 @@ public:
DspRev = std::max(DspRev, DSP1);
else if (*it == "+dspr2")
DspRev = std::max(DspRev, DSP2);
+ else if (*it == "+msa")
+ HasMSA = true;
+ else if (*it == "+fp64")
+ HasFP64 = true;
+ else if (*it == "-fp64")
+ HasFP64 = false;
+ else if (*it == "+nan2008")
+ IsNan2008 = true;
}
- // Remove front-end specific option.
+ // Remove front-end specific options.
std::vector<std::string>::iterator it =
std::find(Features.begin(), Features.end(), "+soft-float");
if (it != Features.end())
Features.erase(it);
+ it = std::find(Features.begin(), Features.end(), "+nan2008");
+ if (it != Features.end())
+ Features.erase(it);
+
+ setDescriptionString();
+
+ return true;
}
virtual int getEHDataRegisterNumber(unsigned RegNo) const {
@@ -4802,8 +5055,8 @@ const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = {
class Mips32TargetInfoBase : public MipsTargetInfoBase {
public:
- Mips32TargetInfoBase(const std::string& triple) :
- MipsTargetInfoBase(triple, "o32", "mips32") {
+ Mips32TargetInfoBase(const llvm::Triple &Triple)
+ : MipsTargetInfoBase(Triple, "o32", "mips32") {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
@@ -4873,11 +5126,15 @@ public:
};
class Mips32EBTargetInfo : public Mips32TargetInfoBase {
-public:
- Mips32EBTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
+ virtual void setDescriptionString() {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
+
+public:
+ Mips32EBTargetInfo(const llvm::Triple &Triple)
+ : Mips32TargetInfoBase(Triple) {
+ }
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "MIPSEB", Opts);
@@ -4887,12 +5144,16 @@ public:
};
class Mips32ELTargetInfo : public Mips32TargetInfoBase {
-public:
- Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
- BigEndian = false;
+ virtual void setDescriptionString() {
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
+
+public:
+ Mips32ELTargetInfo(const llvm::Triple &Triple)
+ : Mips32TargetInfoBase(Triple) {
+ BigEndian = false;
+ }
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "MIPSEL", Opts);
@@ -4902,10 +5163,9 @@ public:
};
class Mips64TargetInfoBase : public MipsTargetInfoBase {
- virtual void SetDescriptionString(const std::string &Name) = 0;
public:
- Mips64TargetInfoBase(const std::string& triple) :
- MipsTargetInfoBase(triple, "n64", "mips64") {
+ Mips64TargetInfoBase(const llvm::Triple &Triple)
+ : MipsTargetInfoBase(Triple, "n64", "mips64") {
LongWidth = LongAlign = 64;
PointerWidth = PointerAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
@@ -4918,7 +5178,6 @@ public:
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual bool setABI(const std::string &Name) {
- SetDescriptionString(Name);
if (Name == "n32") {
LongWidth = LongAlign = 32;
PointerWidth = PointerAlign = 32;
@@ -4994,20 +5253,21 @@ public:
};
class Mips64EBTargetInfo : public Mips64TargetInfoBase {
- virtual void SetDescriptionString(const std::string &Name) {
- // Change DescriptionString only if ABI is n32.
- if (Name == "n32")
+ virtual void setDescriptionString() {
+ if (ABI == "n32")
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
"v64:64:64-n32:64-S128";
+ else
+ DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v64:64:64-n32:64-S128";
+
}
+
public:
- Mips64EBTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
- // Default ABI is n64.
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32:64-S128";
- }
+ Mips64EBTargetInfo(const llvm::Triple &Triple)
+ : Mips64TargetInfoBase(Triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "MIPSEB", Opts);
@@ -5017,20 +5277,21 @@ public:
};
class Mips64ELTargetInfo : public Mips64TargetInfoBase {
- virtual void SetDescriptionString(const std::string &Name) {
- // Change DescriptionString only if ABI is n32.
- if (Name == "n32")
+ virtual void setDescriptionString() {
+ if (ABI == "n32")
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128"
"-v64:64:64-n32:64-S128";
+ else
+ DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v64:64:64-n32:64-S128";
}
public:
- Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
+ Mips64ELTargetInfo(const llvm::Triple &Triple)
+ : Mips64TargetInfoBase(Triple) {
// Default ABI is n64.
BigEndian = false;
- DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32:64-S128";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -5044,7 +5305,7 @@ public:
namespace {
class PNaClTargetInfo : public TargetInfo {
public:
- PNaClTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
this->UserLabelPrefix = "";
this->LongAlign = 32;
@@ -5123,11 +5384,8 @@ namespace {
0 // cuda_shared
};
class SPIRTargetInfo : public TargetInfo {
- static const char * const GCCRegNames[];
- static const Builtin::Info BuiltinInfo[];
- std::vector<StringRef> AvailableFeatures;
public:
- SPIRTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ SPIRTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
"SPIR target must use unknown OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
@@ -5136,6 +5394,7 @@ namespace {
TLSSupported = false;
LongWidth = LongAlign = 64;
AddrSpaceMap = &SPIRAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
// Define available target features
// These must be defined in sorted order!
NoAsmVariants = true;
@@ -5169,7 +5428,7 @@ namespace {
class SPIR32TargetInfo : public SPIRTargetInfo {
public:
- SPIR32TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ SPIR32TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) {
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
@@ -5187,7 +5446,7 @@ namespace {
class SPIR64TargetInfo : public SPIRTargetInfo {
public:
- SPIR64TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ SPIR64TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) {
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
@@ -5204,300 +5463,374 @@ namespace {
};
}
+namespace {
+class XCoreTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+public:
+ XCoreTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
+ BigEndian = false;
+ NoAsmVariants = true;
+ LongLongAlign = 32;
+ SuitableAlign = 32;
+ DoubleAlign = LongDoubleAlign = 32;
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ WCharType = UnsignedChar;
+ WIntType = UnsignedInt;
+ UseZeroLengthBitfieldAlignment = true;
+ DescriptionString = "e-p:32:32:32-a0:0:32-n32"
+ "-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32"
+ "-f16:16:32-f32:32:32-f64:32:32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__XS1B__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+ virtual const char *getClobbers() const {
+ return "";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ static const char * const GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr"
+ };
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = NULL;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ return false;
+ }
+};
+
+const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsXCore.def"
+};
+} // end anonymous namespace.
+
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
-static TargetInfo *AllocateTarget(const std::string &T) {
- llvm::Triple Triple(T);
+static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
llvm::Triple::OSType os = Triple.getOS();
switch (Triple.getArch()) {
default:
return NULL;
+ case llvm::Triple::xcore:
+ return new XCoreTargetInfo(Triple);
+
case llvm::Triple::hexagon:
- return new HexagonTargetInfo(T);
+ return new HexagonTargetInfo(Triple);
case llvm::Triple::aarch64:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<AArch64TargetInfo>(T);
+ return new LinuxTargetInfo<AArch64TargetInfo>(Triple);
default:
- return new AArch64TargetInfo(T);
+ return new AArch64TargetInfo(Triple);
}
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Triple.isOSDarwin())
- return new DarwinARMTargetInfo(T);
+ return new DarwinARMTargetInfo(Triple);
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<ARMTargetInfo>(T);
+ return new LinuxTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<ARMTargetInfo>(T);
+ return new FreeBSDTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<ARMTargetInfo>(T);
+ return new NetBSDTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<ARMTargetInfo>(T);
+ return new OpenBSDTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::Bitrig:
- return new BitrigTargetInfo<ARMTargetInfo>(T);
+ return new BitrigTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<ARMTargetInfo>(T);
+ return new RTEMSTargetInfo<ARMTargetInfo>(Triple);
case llvm::Triple::NaCl:
- return new NaClTargetInfo<ARMTargetInfo>(T);
+ return new NaClTargetInfo<ARMTargetInfo>(Triple);
default:
- return new ARMTargetInfo(T);
+ return new ARMTargetInfo(Triple);
}
case llvm::Triple::msp430:
- return new MSP430TargetInfo(T);
+ return new MSP430TargetInfo(Triple);
case llvm::Triple::mips:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<Mips32EBTargetInfo>(T);
+ return new LinuxTargetInfo<Mips32EBTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<Mips32EBTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips32EBTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<Mips32EBTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips32EBTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<Mips32EBTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips32EBTargetInfo>(Triple);
default:
- return new Mips32EBTargetInfo(T);
+ return new Mips32EBTargetInfo(Triple);
}
case llvm::Triple::mipsel:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<Mips32ELTargetInfo>(T);
+ return new LinuxTargetInfo<Mips32ELTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<Mips32ELTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips32ELTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<Mips32ELTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips32ELTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<Mips32ELTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips32ELTargetInfo>(Triple);
+ case llvm::Triple::NaCl:
+ return new NaClTargetInfo<Mips32ELTargetInfo>(Triple);
default:
- return new Mips32ELTargetInfo(T);
+ return new Mips32ELTargetInfo(Triple);
}
case llvm::Triple::mips64:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<Mips64EBTargetInfo>(T);
+ return new LinuxTargetInfo<Mips64EBTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<Mips64EBTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips64EBTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<Mips64EBTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips64EBTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<Mips64EBTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips64EBTargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<Mips64EBTargetInfo>(T);
+ return new OpenBSDTargetInfo<Mips64EBTargetInfo>(Triple);
default:
- return new Mips64EBTargetInfo(T);
+ return new Mips64EBTargetInfo(Triple);
}
case llvm::Triple::mips64el:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<Mips64ELTargetInfo>(T);
+ return new LinuxTargetInfo<Mips64ELTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<Mips64ELTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips64ELTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<Mips64ELTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips64ELTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<Mips64ELTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips64ELTargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<Mips64ELTargetInfo>(T);
+ return new OpenBSDTargetInfo<Mips64ELTargetInfo>(Triple);
default:
- return new Mips64ELTargetInfo(T);
+ return new Mips64ELTargetInfo(Triple);
}
case llvm::Triple::le32:
switch (os) {
case llvm::Triple::NaCl:
- return new NaClTargetInfo<PNaClTargetInfo>(T);
+ return new NaClTargetInfo<PNaClTargetInfo>(Triple);
default:
return NULL;
}
case llvm::Triple::ppc:
if (Triple.isOSDarwin())
- return new DarwinPPC32TargetInfo(T);
+ return new DarwinPPC32TargetInfo(Triple);
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<PPC32TargetInfo>(T);
+ return new LinuxTargetInfo<PPC32TargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
+ return new FreeBSDTargetInfo<PPC32TargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<PPC32TargetInfo>(T);
+ return new NetBSDTargetInfo<PPC32TargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<PPC32TargetInfo>(T);
+ return new OpenBSDTargetInfo<PPC32TargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<PPC32TargetInfo>(T);
+ return new RTEMSTargetInfo<PPC32TargetInfo>(Triple);
default:
- return new PPC32TargetInfo(T);
+ return new PPC32TargetInfo(Triple);
}
case llvm::Triple::ppc64:
if (Triple.isOSDarwin())
- return new DarwinPPC64TargetInfo(T);
+ return new DarwinPPC64TargetInfo(Triple);
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<PPC64TargetInfo>(T);
+ return new LinuxTargetInfo<PPC64TargetInfo>(Triple);
case llvm::Triple::Lv2:
- return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
+ return new PS3PPUTargetInfo<PPC64TargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<PPC64TargetInfo>(T);
+ return new FreeBSDTargetInfo<PPC64TargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<PPC64TargetInfo>(T);
+ return new NetBSDTargetInfo<PPC64TargetInfo>(Triple);
+ default:
+ return new PPC64TargetInfo(Triple);
+ }
+
+ case llvm::Triple::ppc64le:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<PPC64TargetInfo>(Triple);
default:
- return new PPC64TargetInfo(T);
+ return new PPC64TargetInfo(Triple);
}
case llvm::Triple::nvptx:
- return new NVPTX32TargetInfo(T);
+ return new NVPTX32TargetInfo(Triple);
case llvm::Triple::nvptx64:
- return new NVPTX64TargetInfo(T);
-
- case llvm::Triple::mblaze:
- return new MBlazeTargetInfo(T);
+ return new NVPTX64TargetInfo(Triple);
case llvm::Triple::r600:
- return new R600TargetInfo(T);
+ return new R600TargetInfo(Triple);
case llvm::Triple::sparc:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<SparcV8TargetInfo>(T);
+ return new LinuxTargetInfo<SparcV8TargetInfo>(Triple);
case llvm::Triple::AuroraUX:
- return new AuroraUXSparcV8TargetInfo(T);
+ return new AuroraUXSparcV8TargetInfo(Triple);
case llvm::Triple::Solaris:
- return new SolarisSparcV8TargetInfo(T);
+ return new SolarisSparcV8TargetInfo(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<SparcV8TargetInfo>(T);
+ return new NetBSDTargetInfo<SparcV8TargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<SparcV8TargetInfo>(T);
+ return new OpenBSDTargetInfo<SparcV8TargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<SparcV8TargetInfo>(T);
+ return new RTEMSTargetInfo<SparcV8TargetInfo>(Triple);
default:
- return new SparcV8TargetInfo(T);
+ return new SparcV8TargetInfo(Triple);
}
case llvm::Triple::sparcv9:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<SparcV9TargetInfo>(T);
+ return new LinuxTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<SparcV9TargetInfo>(T);
+ return new AuroraUXTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::Solaris:
- return new SolarisTargetInfo<SparcV9TargetInfo>(T);
+ return new SolarisTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<SparcV9TargetInfo>(T);
+ return new NetBSDTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<SparcV9TargetInfo>(T);
+ return new OpenBSDTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<SparcV9TargetInfo>(T);
+ return new FreeBSDTargetInfo<SparcV9TargetInfo>(Triple);
default:
- return new SparcV9TargetInfo(T);
+ return new SparcV9TargetInfo(Triple);
}
case llvm::Triple::systemz:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<SystemZTargetInfo>(T);
+ return new LinuxTargetInfo<SystemZTargetInfo>(Triple);
default:
- return new SystemZTargetInfo(T);
+ return new SystemZTargetInfo(Triple);
}
case llvm::Triple::tce:
- return new TCETargetInfo(T);
+ return new TCETargetInfo(Triple);
case llvm::Triple::x86:
if (Triple.isOSDarwin())
- return new DarwinI386TargetInfo(T);
+ return new DarwinI386TargetInfo(Triple);
switch (os) {
case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<X86_32TargetInfo>(T);
+ return new AuroraUXTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Linux:
- return new LinuxTargetInfo<X86_32TargetInfo>(T);
+ return new LinuxTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::DragonFly:
- return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(T);
+ return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDI386TargetInfo(T);
+ return new NetBSDI386TargetInfo(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDI386TargetInfo(T);
+ return new OpenBSDI386TargetInfo(Triple);
case llvm::Triple::Bitrig:
- return new BitrigI386TargetInfo(T);
+ return new BitrigI386TargetInfo(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<X86_32TargetInfo>(T);
+ return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple);
+ case llvm::Triple::KFreeBSD:
+ return new KFreeBSDTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Minix:
- return new MinixTargetInfo<X86_32TargetInfo>(T);
+ return new MinixTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Solaris:
- return new SolarisTargetInfo<X86_32TargetInfo>(T);
+ return new SolarisTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Cygwin:
- return new CygwinX86_32TargetInfo(T);
+ return new CygwinX86_32TargetInfo(Triple);
case llvm::Triple::MinGW32:
- return new MinGWX86_32TargetInfo(T);
+ return new MinGWX86_32TargetInfo(Triple);
case llvm::Triple::Win32:
- return new VisualStudioWindowsX86_32TargetInfo(T);
+ return new VisualStudioWindowsX86_32TargetInfo(Triple);
case llvm::Triple::Haiku:
- return new HaikuX86_32TargetInfo(T);
+ return new HaikuX86_32TargetInfo(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSX86_32TargetInfo(T);
+ return new RTEMSX86_32TargetInfo(Triple);
case llvm::Triple::NaCl:
- return new NaClTargetInfo<X86_32TargetInfo>(T);
+ return new NaClTargetInfo<X86_32TargetInfo>(Triple);
default:
- return new X86_32TargetInfo(T);
+ return new X86_32TargetInfo(Triple);
}
case llvm::Triple::x86_64:
if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO)
- return new DarwinX86_64TargetInfo(T);
+ return new DarwinX86_64TargetInfo(Triple);
switch (os) {
case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<X86_64TargetInfo>(T);
+ return new AuroraUXTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::Linux:
- return new LinuxTargetInfo<X86_64TargetInfo>(T);
+ return new LinuxTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::DragonFly:
- return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T);
+ return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<X86_64TargetInfo>(T);
+ return new NetBSDTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDX86_64TargetInfo(T);
+ return new OpenBSDX86_64TargetInfo(Triple);
case llvm::Triple::Bitrig:
- return new BitrigX86_64TargetInfo(T);
+ return new BitrigX86_64TargetInfo(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<X86_64TargetInfo>(T);
+ return new FreeBSDTargetInfo<X86_64TargetInfo>(Triple);
+ case llvm::Triple::KFreeBSD:
+ return new KFreeBSDTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::Solaris:
- return new SolarisTargetInfo<X86_64TargetInfo>(T);
+ return new SolarisTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::MinGW32:
- return new MinGWX86_64TargetInfo(T);
+ return new MinGWX86_64TargetInfo(Triple);
case llvm::Triple::Win32: // This is what Triple.h supports now.
- return new VisualStudioWindowsX86_64TargetInfo(T);
+ return new VisualStudioWindowsX86_64TargetInfo(Triple);
case llvm::Triple::NaCl:
- return new NaClTargetInfo<X86_64TargetInfo>(T);
+ return new NaClTargetInfo<X86_64TargetInfo>(Triple);
default:
- return new X86_64TargetInfo(T);
+ return new X86_64TargetInfo(Triple);
}
case llvm::Triple::spir: {
- llvm::Triple Triple(T);
if (Triple.getOS() != llvm::Triple::UnknownOS ||
- Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
return NULL;
- return new SPIR32TargetInfo(T);
+ return new SPIR32TargetInfo(Triple);
}
case llvm::Triple::spir64: {
- llvm::Triple Triple(T);
if (Triple.getOS() != llvm::Triple::UnknownOS ||
- Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
return NULL;
- return new SPIR64TargetInfo(T);
+ return new SPIR64TargetInfo(Triple);
}
}
}
@@ -5509,7 +5842,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
llvm::Triple Triple(Opts->Triple);
// Construct the target
- OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
+ OwningPtr<TargetInfo> Target(AllocateTarget(Triple));
if (!Target) {
Diags.Report(diag::err_target_unknown_triple) << Triple.str();
return 0;
@@ -5534,45 +5867,24 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
return 0;
}
+ // Set the fp math unit.
+ if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) {
+ Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath;
+ return 0;
+ }
+
// Compute the default target features, we need the target to handle this
// because features may have dependencies on one another.
llvm::StringMap<bool> Features;
Target->getDefaultFeatures(Features);
// Apply the user specified deltas.
- // First the enables.
- for (std::vector<std::string>::const_iterator
- it = Opts->FeaturesAsWritten.begin(),
- ie = Opts->FeaturesAsWritten.end();
- it != ie; ++it) {
- const char *Name = it->c_str();
-
- if (Name[0] != '+')
- continue;
-
+ for (unsigned I = 0, N = Opts->FeaturesAsWritten.size();
+ I < N; ++I) {
+ const char *Name = Opts->FeaturesAsWritten[I].c_str();
// Apply the feature via the target.
- if (!Target->setFeatureEnabled(Features, Name + 1, true)) {
- Diags.Report(diag::err_target_invalid_feature) << Name;
- return 0;
- }
- }
-
- // Then the disables.
- for (std::vector<std::string>::const_iterator
- it = Opts->FeaturesAsWritten.begin(),
- ie = Opts->FeaturesAsWritten.end();
- it != ie; ++it) {
- const char *Name = it->c_str();
-
- if (Name[0] == '+')
- continue;
-
- // Apply the feature via the target.
- if (Name[0] != '-' ||
- !Target->setFeatureEnabled(Features, Name + 1, false)) {
- Diags.Report(diag::err_target_invalid_feature) << Name;
- return 0;
- }
+ bool Enabled = Name[0] == '+';
+ Target->setFeatureEnabled(Features, Name + 1, Enabled);
}
// Add the features to the compile options.
@@ -5583,7 +5895,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
- Target->HandleTargetFeatures(Opts->Features);
+ if (!Target->handleTargetFeatures(Opts->Features, Diags))
+ return 0;
return Target.take();
}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 743143d643ae..4a2b1fccb24e 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -36,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/branches/release_34/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 053320ced1d0..7bb65e923e2c 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -3,17 +3,24 @@ add_subdirectory(Basic)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(AST)
-add_subdirectory(ASTMatchers)
+if(CLANG_ENABLE_REWRITER)
+ add_subdirectory(ASTMatchers)
+endif()
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
add_subdirectory(Edit)
add_subdirectory(Rewrite)
-add_subdirectory(ARCMigrate)
+if(CLANG_ENABLE_ARCMT)
+ add_subdirectory(ARCMigrate)
+endif()
add_subdirectory(Driver)
add_subdirectory(Serialization)
add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Tooling)
-add_subdirectory(StaticAnalyzer)
+add_subdirectory(Index)
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ add_subdirectory(StaticAnalyzer)
+endif()
add_subdirectory(Format)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index df6dc7216a47..468fe0439967 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -25,6 +25,7 @@ namespace clang {
class TargetInfo;
namespace CodeGen {
+ class CGCXXABI;
class CGFunctionInfo;
class CodeGenFunction;
class CodeGenTypes;
@@ -35,151 +36,6 @@ namespace clang {
// the targets to support this, since the Targets currently live in a
// layer below types n'stuff.
- /// ABIArgInfo - Helper class to encapsulate information about how a
- /// specific C type should be passed to or returned from a function.
- class ABIArgInfo {
- public:
- enum Kind {
- /// Direct - Pass the argument directly using the normal converted LLVM
- /// type, or by coercing to another specified type stored in
- /// 'CoerceToType'). If an offset is specified (in UIntData), then the
- /// argument passed is offset by some number of bytes in the memory
- /// representation. A dummy argument is emitted before the real argument
- /// if the specified type stored in "PaddingType" is not zero.
- Direct,
-
- /// Extend - Valid only for integer argument types. Same as 'direct'
- /// but also emit a zero/sign extension attribute.
- Extend,
-
- /// Indirect - Pass the argument indirectly via a hidden pointer
- /// with the specified alignment (0 indicates default alignment).
- Indirect,
-
- /// Ignore - Ignore the argument (treat as void). Useful for void and
- /// empty structs.
- Ignore,
-
- /// Expand - Only valid for aggregate argument types. The structure should
- /// be expanded into consecutive arguments for its constituent fields.
- /// Currently expand is only allowed on structures whose fields
- /// are all scalar types or are themselves expandable types.
- Expand,
-
- KindFirst=Direct, KindLast=Expand
- };
-
- private:
- Kind TheKind;
- llvm::Type *TypeData;
- llvm::Type *PaddingType;
- unsigned UIntData;
- bool BoolData0;
- bool BoolData1;
- bool InReg;
- bool PaddingInReg;
-
- ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
- bool PIR, llvm::Type* P)
- : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
- BoolData1(B1), InReg(IR), PaddingInReg(PIR) {}
-
- public:
- ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
-
- static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
- llvm::Type *Padding = 0) {
- return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding);
- }
- static ABIArgInfo getDirectInReg(llvm::Type *T = 0) {
- return ABIArgInfo(Direct, T, 0, false, false, true, false, 0);
- }
- static ABIArgInfo getExtend(llvm::Type *T = 0) {
- return ABIArgInfo(Extend, T, 0, false, false, false, false, 0);
- }
- static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
- return ABIArgInfo(Extend, T, 0, false, false, true, false, 0);
- }
- static ABIArgInfo getIgnore() {
- return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
- }
- static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
- , bool Realign = false
- , llvm::Type *Padding = 0) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
- Padding);
- }
- static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
- , bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
- }
- static ABIArgInfo getExpand() {
- return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0);
- }
- static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
- llvm::Type *Padding) {
- return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg,
- Padding);
- }
-
- Kind getKind() const { return TheKind; }
- bool isDirect() const { return TheKind == Direct; }
- bool isExtend() const { return TheKind == Extend; }
- bool isIgnore() const { return TheKind == Ignore; }
- bool isIndirect() const { return TheKind == Indirect; }
- bool isExpand() const { return TheKind == Expand; }
-
- bool canHaveCoerceToType() const {
- return TheKind == Direct || TheKind == Extend;
- }
-
- // Direct/Extend accessors
- unsigned getDirectOffset() const {
- assert((isDirect() || isExtend()) && "Not a direct or extend kind");
- return UIntData;
- }
-
- llvm::Type *getPaddingType() const {
- return PaddingType;
- }
-
- bool getPaddingInReg() const {
- return PaddingInReg;
- }
-
- llvm::Type *getCoerceToType() const {
- assert(canHaveCoerceToType() && "Invalid kind!");
- return TypeData;
- }
-
- void setCoerceToType(llvm::Type *T) {
- assert(canHaveCoerceToType() && "Invalid kind!");
- TypeData = T;
- }
-
- bool getInReg() const {
- assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
- return InReg;
- }
-
- // Indirect accessors
- unsigned getIndirectAlign() const {
- assert(TheKind == Indirect && "Invalid kind!");
- return UIntData;
- }
-
- bool getIndirectByVal() const {
- assert(TheKind == Indirect && "Invalid kind!");
- return BoolData0;
- }
-
- bool getIndirectRealign() const {
- assert(TheKind == Indirect && "Invalid kind!");
- return BoolData1;
- }
-
- void dump() const;
- };
/// ABIInfo - Target specific hooks for defining how a type should be
/// passed or returned from functions.
@@ -194,6 +50,7 @@ namespace clang {
virtual ~ABIInfo();
+ CodeGen::CGCXXABI &getCXXABI() const;
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 45079c098984..90b0f68bd693 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -154,6 +154,14 @@ static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase
PM.add(createObjCARCOptPass());
}
+static void addSampleProfileLoaderPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper &>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createSampleProfileLoaderPass(CGOpts.SampleProfileFile));
+}
+
static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
PM.add(createBoundsCheckingPass());
@@ -206,6 +214,14 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PM.add(createThreadSanitizerPass(CGOpts.SanitizerBlacklistFile));
}
+static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createDataFlowSanitizerPass(CGOpts.SanitizerBlacklistFile));
+}
+
void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining();
@@ -220,10 +236,17 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
PMBuilder.OptLevel = OptLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
+ PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB;
+ PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
+ PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
- PMBuilder.DisableSimplifyLibCalls = !CodeGenOpts.SimplifyLibCalls;
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
+ PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
+
+ if (!CodeGenOpts.SampleProfileFile.empty())
+ PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
+ addSampleProfileLoaderPass);
// In ObjC ARC mode, add the main ARC optimization passes.
if (LangOpts.ObjCAutoRefCount) {
@@ -235,7 +258,7 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
addObjCARCOptPass);
}
- if (LangOpts.Sanitize.Bounds) {
+ if (LangOpts.Sanitize.LocalBounds) {
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
addBoundsCheckingPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -263,6 +286,13 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
addThreadSanitizerPass);
}
+ if (LangOpts.Sanitize.DataFlow) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addDataFlowSanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addDataFlowSanitizerPass);
+ }
+
// Figure out TargetLibraryInfo.
Triple TargetTriple(TheModule->getTargetTriple());
PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
@@ -410,13 +440,10 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
// Set frame pointer elimination mode.
if (!CodeGenOpts.DisableFPElim) {
Options.NoFramePointerElim = false;
- Options.NoFramePointerElimNonLeaf = false;
} else if (CodeGenOpts.OmitLeafFramePointer) {
Options.NoFramePointerElim = false;
- Options.NoFramePointerElimNonLeaf = true;
} else {
Options.NoFramePointerElim = true;
- Options.NoFramePointerElimNonLeaf = true;
}
if (CodeGenOpts.UseInitArray)
@@ -452,11 +479,9 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
Options.UseSoftFloat = CodeGenOpts.SoftFloat;
Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
- Options.RealignStack = CodeGenOpts.StackRealignment;
Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
- Options.SSPBufferSize = CodeGenOpts.SSPBufferSize;
Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
@@ -529,6 +554,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
Action != Backend_EmitLL);
TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
if (UsesCodeGen && !TM) return;
+ llvm::OwningPtr<TargetMachine> TMOwner(CodeGenOpts.DisableFree ? 0 : TM);
CreatePasses(TM);
switch (Action) {
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 0b48a5c66435..0df2a4000e28 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -15,6 +15,8 @@
#include "CGCall.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
@@ -92,7 +94,7 @@ namespace {
return (ValueSizeInBits != AtomicSizeInBits);
}
- void emitMemSetZeroIfNecessary(LValue dest) const;
+ bool emitMemSetZeroIfNecessary(LValue dest) const;
llvm::Value *getAtomicSizeValue() const {
CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
@@ -105,7 +107,8 @@ namespace {
/// Turn an atomic-layout object into an r-value.
RValue convertTempToRValue(llvm::Value *addr,
- AggValueSlot resultSlot) const;
+ AggValueSlot resultSlot,
+ SourceLocation loc) const;
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
@@ -163,21 +166,22 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
AtomicSizeInBits / 2);
- // Just be pessimistic about aggregates.
+ // Padding in structs has an undefined bit pattern. User beware.
case TEK_Aggregate:
- return true;
+ return false;
}
llvm_unreachable("bad evaluation kind");
}
-void AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
+bool AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
llvm::Value *addr = dest.getAddress();
if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
- return;
+ return false;
CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
AtomicSizeInBits / 8,
dest.getAlignment().getQuantity());
+ return true;
}
static void
@@ -317,6 +321,22 @@ EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
return DeclPtr;
}
+static void
+AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
+ bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
+ SourceLocation Loc) {
+ if (UseOptimizedLibcall) {
+ // Load value and pass it to the function directly.
+ unsigned Align = CGF.getContext().getTypeAlignInChars(ValTy).getQuantity();
+ Val = CGF.EmitLoadOfScalar(Val, false, Align, ValTy, Loc);
+ Args.add(RValue::get(Val), ValTy);
+ } else {
+ // Non-optimized functions always take a reference.
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(Val)),
+ CGF.getContext().VoidPtrTy);
+ }
+}
+
RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
QualType MemTy = AtomicTy;
@@ -424,67 +444,142 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
if (UseLibcall) {
+ bool UseOptimizedLibcall = false;
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ // For these, only library calls for certain sizes exist.
+ UseOptimizedLibcall = true;
+ break;
+ default:
+ // Only use optimized library calls for sizes for which they exist.
+ if (Size == 1 || Size == 2 || Size == 4 || Size == 8)
+ UseOptimizedLibcall = true;
+ break;
+ }
- SmallVector<QualType, 5> Params;
CallArgList Args;
- // Size is always the first parameter
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
- // Atomic address is always the second parameter
- Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
- getContext().VoidPtrTy);
+ if (!UseOptimizedLibcall) {
+ // For non-optimized library calls, the size is the first parameter
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ }
+ // Atomic address is the first or second parameter
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)), getContext().VoidPtrTy);
- const char* LibCallName;
- QualType RetTy = getContext().VoidTy;
+ std::string LibCallName;
+ QualType RetTy;
+ bool HaveRetTy = false;
switch (E->getOp()) {
// There is only one libcall for compare an exchange, because there is no
// optimisation benefit possible from a libcall version of a weak compare
// and exchange.
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
// void *desired, int success, int failure)
+ // bool __atomic_compare_exchange_N(T *mem, T *expected, T desired,
+ // int success, int failure)
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
case AtomicExpr::AO__atomic_compare_exchange:
case AtomicExpr::AO__atomic_compare_exchange_n:
LibCallName = "__atomic_compare_exchange";
RetTy = getContext().BoolTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(Order),
- getContext().IntTy);
+ HaveRetTy = true;
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)), getContext().VoidPtrTy);
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2, MemTy,
+ E->getExprLoc());
+ Args.add(RValue::get(Order), getContext().IntTy);
Order = OrderFail;
break;
// void __atomic_exchange(size_t size, void *mem, void *val, void *return,
// int order)
+ // T __atomic_exchange_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
case AtomicExpr::AO__atomic_exchange:
LibCallName = "__atomic_exchange";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
break;
// 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__atomic_store:
case AtomicExpr::AO__atomic_store_n:
LibCallName = "__atomic_store";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
+ RetTy = getContext().VoidTy;
+ HaveRetTy = true;
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
break;
// 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__atomic_load:
case AtomicExpr::AO__atomic_load_n:
LibCallName = "__atomic_load";
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
+ break;
+ // T __atomic_fetch_add_N(T *mem, T val, int order)
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ LibCallName = "__atomic_fetch_add";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
+ break;
+ // T __atomic_fetch_and_N(T *mem, T val, int order)
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ LibCallName = "__atomic_fetch_and";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
+ break;
+ // T __atomic_fetch_or_N(T *mem, T val, int order)
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ LibCallName = "__atomic_fetch_or";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
+ break;
+ // T __atomic_fetch_sub_N(T *mem, T val, int order)
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ LibCallName = "__atomic_fetch_sub";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
+ break;
+ // T __atomic_fetch_xor_N(T *mem, T val, int order)
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ LibCallName = "__atomic_fetch_xor";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ E->getExprLoc());
break;
default: return EmitUnsupportedRValue(E, "atomic library call");
}
+
+ // Optimized functions have the size in their name.
+ if (UseOptimizedLibcall)
+ LibCallName += "_" + llvm::utostr(Size);
+ // By default, assume we return a value of the atomic type.
+ if (!HaveRetTy) {
+ if (UseOptimizedLibcall) {
+ // Value is returned directly.
+ RetTy = MemTy;
+ } else {
+ // Value is returned through parameter before the order.
+ RetTy = getContext().VoidTy;
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ }
+ }
// order is always the last parameter
Args.add(RValue::get(Order),
getContext().IntTy);
@@ -495,11 +590,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (E->isCmpXChg())
+ if (!RetTy->isVoidType())
return Res;
if (E->getType()->isVoidType())
return RValue::get(0);
- return convertTempToRValue(Dest, E->getType());
+ return convertTempToRValue(Dest, E->getType(), E->getExprLoc());
}
bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
@@ -554,7 +649,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
}
if (E->getType()->isVoidType())
return RValue::get(0);
- return convertTempToRValue(OrigDest, E->getType());
+ return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
}
// Long case, when Order isn't obviously constant.
@@ -616,7 +711,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
Builder.SetInsertPoint(ContBB);
if (E->getType()->isVoidType())
return RValue::get(0);
- return convertTempToRValue(OrigDest, E->getType());
+ return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
}
llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
@@ -628,48 +723,30 @@ llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
}
RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
- AggValueSlot resultSlot) const {
- if (EvaluationKind == TEK_Aggregate) {
- // Nothing to do if the result is ignored.
- if (resultSlot.isIgnored()) return resultSlot.asRValue();
-
- assert(resultSlot.getAddr() == addr || hasPadding());
-
- // In these cases, we should have emitted directly into the result slot.
- if (!hasPadding() || resultSlot.isValueOfAtomic())
- return resultSlot.asRValue();
-
- // Otherwise, fall into the common path.
- }
+ AggValueSlot resultSlot,
+ SourceLocation loc) const {
+ if (EvaluationKind == TEK_Aggregate)
+ return resultSlot.asRValue();
// Drill into the padding structure if we have one.
if (hasPadding())
addr = CGF.Builder.CreateStructGEP(addr, 0);
- // If we're emitting to an aggregate, copy into the result slot.
- if (EvaluationKind == TEK_Aggregate) {
- CGF.EmitAggregateCopy(resultSlot.getAddr(), addr, getValueType(),
- resultSlot.isVolatile());
- return resultSlot.asRValue();
- }
-
// Otherwise, just convert the temporary to an r-value using the
// normal conversion routine.
- return CGF.convertTempToRValue(addr, getValueType());
+ return CGF.convertTempToRValue(addr, getValueType(), loc);
}
/// Emit a load from an l-value of atomic type. Note that the r-value
/// we produce is an r-value of the atomic *value* type.
-RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
+RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
+ AggValueSlot resultSlot) {
AtomicInfo atomics(*this, src);
// Check whether we should use a library call.
if (atomics.shouldUseLibcall()) {
llvm::Value *tempAddr;
- if (resultSlot.isValueOfAtomic()) {
- assert(atomics.getEvaluationKind() == TEK_Aggregate);
- tempAddr = resultSlot.getPaddedAtomicAddr();
- } else if (!resultSlot.isIgnored() && !atomics.hasPadding()) {
+ if (!resultSlot.isIgnored()) {
assert(atomics.getEvaluationKind() == TEK_Aggregate);
tempAddr = resultSlot.getAddr();
} else {
@@ -690,7 +767,7 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
// Produce the r-value.
- return atomics.convertTempToRValue(tempAddr, resultSlot);
+ return atomics.convertTempToRValue(tempAddr, resultSlot, loc);
}
// Okay, we're doing this natively.
@@ -733,16 +810,10 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
llvm::Value *temp;
bool tempIsVolatile = false;
CharUnits tempAlignment;
- if (atomics.getEvaluationKind() == TEK_Aggregate &&
- (!atomics.hasPadding() || resultSlot.isValueOfAtomic())) {
+ if (atomics.getEvaluationKind() == TEK_Aggregate) {
assert(!resultSlot.isIgnored());
- if (resultSlot.isValueOfAtomic()) {
- temp = resultSlot.getPaddedAtomicAddr();
- tempAlignment = atomics.getAtomicAlignment();
- } else {
- temp = resultSlot.getAddr();
- tempAlignment = atomics.getValueAlignment();
- }
+ temp = resultSlot.getAddr();
+ tempAlignment = atomics.getValueAlignment();
tempIsVolatile = resultSlot.isVolatile();
} else {
temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
@@ -754,7 +825,7 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
->setVolatile(tempIsVolatile);
- return atomics.convertTempToRValue(temp, resultSlot);
+ return atomics.convertTempToRValue(temp, resultSlot, loc);
}
@@ -812,8 +883,7 @@ llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
/// Note that the r-value is expected to be an r-value *of the atomic
/// type*; this means that for aggregate r-values, it should include
/// storage for any padding that was necessary.
-void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
- bool isInit) {
+void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
// If this is an aggregate r-value, it should agree in type except
// maybe for address-space qualification.
assert(!rvalue.isAggregate() ||
@@ -910,13 +980,11 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
}
case TEK_Aggregate: {
- // Memset the buffer first if there's any possibility of
- // uninitialized internal bits.
- atomics.emitMemSetZeroIfNecessary(dest);
-
- // HACK: whether the initializer actually has an atomic type
- // doesn't really seem reliable right now.
+ // Fix up the destination if the initializer isn't an expression
+ // of atomic type.
+ bool Zeroed = false;
if (!init->getType()->isAtomicType()) {
+ Zeroed = atomics.emitMemSetZeroIfNecessary(dest);
dest = atomics.projectValue(dest);
}
@@ -924,7 +992,10 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
AggValueSlot slot = AggValueSlot::forLValue(dest,
AggValueSlot::IsNotDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
+ AggValueSlot::IsNotAliased,
+ Zeroed ? AggValueSlot::IsZeroed :
+ AggValueSlot::IsNotZeroed);
+
EmitAggExpr(init, slot);
return;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index ded019e64ae8..692f9a0dd63f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -63,14 +63,16 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
/// buildBlockDescriptor is accessed from 5th field of the Block_literal
/// meta-data and contains stationary information about the block literal.
/// Its definition will have 4 (or optinally 6) words.
+/// \code
/// struct Block_descriptor {
/// unsigned long reserved;
/// unsigned long size; // size of Block_literal metadata in bytes.
/// void *copy_func_helper_decl; // optional copy helper.
/// void *destroy_func_decl; // optioanl destructor helper.
-/// void *block_method_encoding_address;//@encode for block literal signature.
+/// void *block_method_encoding_address; // @encode for block literal signature.
/// void *block_layout_info; // encoding of captured block variables.
/// };
+/// \endcode
static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
ASTContext &C = CGM.getContext();
@@ -353,14 +355,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// First, 'this'.
if (block->capturesCXXThis()) {
- const DeclContext *DC = block->getDeclContext();
- for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext())
- ;
- QualType thisType;
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
- thisType = C.getPointerType(C.getRecordType(RD));
- else
- thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
+ assert(CGF && CGF->CurFuncDecl && isa<CXXMethodDecl>(CGF->CurFuncDecl) &&
+ "Can't capture 'this' outside a method");
+ QualType thisType = cast<CXXMethodDecl>(CGF->CurFuncDecl)->getThisType(C);
llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
std::pair<CharUnits,CharUnits> tinfo
@@ -837,7 +834,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
type->isBlockPointerType()) {
// Load the block and do a simple retain.
LValue srcLV = MakeAddrLValue(src, type, align);
- llvm::Value *value = EmitLoadOfScalar(srcLV);
+ llvm::Value *value = EmitLoadOfScalar(srcLV, SourceLocation());
value = EmitARCRetainNonBlock(value);
// Do a primitive store to the block field.
@@ -934,7 +931,7 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
}
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
const BlockPointerType *BPT =
E->getCallee()->getType()->getAs<BlockPointerType>();
@@ -1092,8 +1089,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
bool IsLambdaConversionToBlock) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
- // Check if we should generate debug info for this block function.
- maybeInitializeDebugInfo();
CurGD = GD;
BlockInfo = &blockInfo;
@@ -1167,9 +1162,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
Alloca->setAlignment(Align);
// Set the DebugLocation to empty, so the store is recognized as a
// frame setup instruction by llvm::DwarfDebug::beginFunction().
- Builder.DisableDebugLocations();
+ NoLocation NL(*this, Builder);
Builder.CreateAlignedStore(BlockPointer, Alloca, Align);
- Builder.EnableDebugLocations();
BlockPointerDbgLoc = Alloca;
}
@@ -1307,9 +1301,6 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
IdentifierInfo *II
= &CGM.getContext().Idents.get("__copy_helper_block_");
- // Check if we should generate debug info for this block helper function.
- maybeInitializeDebugInfo();
-
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
@@ -1317,7 +1308,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
SC_Static,
false,
false);
+ // Create a scope with an artificial location for the body of this function.
+ ArtificialLocation AL(*this, Builder);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1479,9 +1473,6 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__destroy_helper_block_", &CGM.getModule());
- // Check if we should generate debug info for this block destroy function.
- maybeInitializeDebugInfo();
-
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1490,7 +1481,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
false, false);
+ // Create a scope with an artificial location for the body of this function.
+ ArtificialLocation AL(*this, Builder);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1781,8 +1775,6 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_Static,
false, false);
- // Initialize debug info if necessary.
- CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@@ -1854,8 +1846,6 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SourceLocation(), II, R, 0,
SC_Static,
false, false);
- // Initialize debug info if necessary.
- CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsDispose()) {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index d18767897f39..7726ad309d8a 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
@@ -165,7 +166,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
const CallExpr *E, llvm::Value *calleeValue) {
- return CGF.EmitCall(E->getCallee()->getType(), calleeValue,
+ return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E->getLocStart(),
ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn);
}
@@ -408,8 +409,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
assert(CI);
uint64_t val = CI->getZExtValue();
CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
-
- Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType);
+ // FIXME: Get right address space.
+ llvm::Type *Tys[] = { ResType, Builder.getInt8PtrTy(0) };
+ Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)),CI));
}
case Builtin::BI__builtin_prefetch: {
@@ -602,6 +604,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BIalloca:
+ case Builtin::BI_alloca:
case Builtin::BI__builtin_alloca: {
Value *Size = EmitScalarExpr(E->getArg(0));
return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size));
@@ -1282,18 +1285,25 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
case Builtin::BIsqrtl: {
- // TODO: there is currently no set of optimizer flags
- // sufficient for us to rewrite sqrt to @llvm.sqrt.
- // -fmath-errno=0 is not good enough; we need finiteness.
- // We could probably precondition the call with an ult
- // against 0, but is that worth the complexity?
- break;
+ // 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::BIpow:
case Builtin::BIpowf:
case Builtin::BIpowl: {
- // Rewrite sqrt to intrinsic if allowed.
+ // Transform a call to pow* into a @llvm.pow.* intrinsic call.
if (!FD->hasAttr<ConstAttr>())
break;
Value *Base = EmitScalarExpr(E->getArg(0));
@@ -1301,6 +1311,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = Base->getType();
Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType);
return RValue::get(Builder.CreateCall2(F, Base, Exponent));
+ break;
}
case Builtin::BIfma:
@@ -1345,10 +1356,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
+ case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
@@ -1382,12 +1395,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Intrinsic::ID IntrinsicId;
switch (BuiltinID) {
default: llvm_unreachable("Unknown multiprecision builtin id.");
+ case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
break;
+ case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
@@ -1410,6 +1425,79 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
CarryOutStore->setAlignment(CarryOutPtr.second);
return RValue::get(Sum2);
}
+ case Builtin::BI__builtin_uadd_overflow:
+ case Builtin::BI__builtin_uaddl_overflow:
+ case Builtin::BI__builtin_uaddll_overflow:
+ case Builtin::BI__builtin_usub_overflow:
+ case Builtin::BI__builtin_usubl_overflow:
+ case Builtin::BI__builtin_usubll_overflow:
+ case Builtin::BI__builtin_umul_overflow:
+ case Builtin::BI__builtin_umull_overflow:
+ case Builtin::BI__builtin_umulll_overflow:
+ case Builtin::BI__builtin_sadd_overflow:
+ case Builtin::BI__builtin_saddl_overflow:
+ case Builtin::BI__builtin_saddll_overflow:
+ case Builtin::BI__builtin_ssub_overflow:
+ case Builtin::BI__builtin_ssubl_overflow:
+ case Builtin::BI__builtin_ssubll_overflow:
+ case Builtin::BI__builtin_smul_overflow:
+ case Builtin::BI__builtin_smull_overflow:
+ case Builtin::BI__builtin_smulll_overflow: {
+
+ // We translate all of these builtins directly to the relevant llvm IR node.
+
+ // Scalarize our inputs.
+ llvm::Value *X = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Y = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value *, unsigned> SumOutPtr =
+ EmitPointerWithAlignment(E->getArg(2));
+
+ // Decide which of the overflow intrinsics we are lowering to:
+ llvm::Intrinsic::ID IntrinsicId;
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unknown security overflow builtin id.");
+ case Builtin::BI__builtin_uadd_overflow:
+ case Builtin::BI__builtin_uaddl_overflow:
+ case Builtin::BI__builtin_uaddll_overflow:
+ IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
+ break;
+ case Builtin::BI__builtin_usub_overflow:
+ case Builtin::BI__builtin_usubl_overflow:
+ case Builtin::BI__builtin_usubll_overflow:
+ IntrinsicId = llvm::Intrinsic::usub_with_overflow;
+ break;
+ case Builtin::BI__builtin_umul_overflow:
+ case Builtin::BI__builtin_umull_overflow:
+ case Builtin::BI__builtin_umulll_overflow:
+ IntrinsicId = llvm::Intrinsic::umul_with_overflow;
+ break;
+ case Builtin::BI__builtin_sadd_overflow:
+ case Builtin::BI__builtin_saddl_overflow:
+ case Builtin::BI__builtin_saddll_overflow:
+ IntrinsicId = llvm::Intrinsic::sadd_with_overflow;
+ break;
+ case Builtin::BI__builtin_ssub_overflow:
+ case Builtin::BI__builtin_ssubl_overflow:
+ case Builtin::BI__builtin_ssubll_overflow:
+ IntrinsicId = llvm::Intrinsic::ssub_with_overflow;
+ break;
+ case Builtin::BI__builtin_smul_overflow:
+ case Builtin::BI__builtin_smull_overflow:
+ case Builtin::BI__builtin_smulll_overflow:
+ IntrinsicId = llvm::Intrinsic::smul_with_overflow;
+ break;
+ }
+
+
+ llvm::Value *Carry;
+ llvm::Value *Sum = EmitOverflowIntrinsic(*this, IntrinsicId, X, Y, Carry);
+ llvm::StoreInst *SumOutStore = Builder.CreateStore(Sum, SumOutPtr.first);
+ SumOutStore->setAlignment(SumOutPtr.second);
+
+ return RValue::get(Carry);
+ }
+ case Builtin::BI__builtin_addressof:
+ return RValue::get(EmitLValue(E->getArg(0)).getAddress());
case Builtin::BI__noop:
return RValue::get(0);
}
@@ -1512,6 +1600,7 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
return EmitX86BuiltinExpr(BuiltinID, E);
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
return EmitPPCBuiltinExpr(BuiltinID, E);
default:
return 0;
@@ -1519,24 +1608,28 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
}
static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
- NeonTypeFlags TypeFlags) {
+ NeonTypeFlags TypeFlags,
+ bool V1Ty=false) {
int IsQuad = TypeFlags.isQuad();
switch (TypeFlags.getEltType()) {
case NeonTypeFlags::Int8:
case NeonTypeFlags::Poly8:
- return llvm::VectorType::get(CGF->Int8Ty, 8 << IsQuad);
+ return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad));
case NeonTypeFlags::Int16:
case NeonTypeFlags::Poly16:
case NeonTypeFlags::Float16:
- return llvm::VectorType::get(CGF->Int16Ty, 4 << IsQuad);
+ return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
case NeonTypeFlags::Int32:
- return llvm::VectorType::get(CGF->Int32Ty, 2 << IsQuad);
+ return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad));
case NeonTypeFlags::Int64:
- return llvm::VectorType::get(CGF->Int64Ty, 1 << IsQuad);
+ case NeonTypeFlags::Poly64:
+ return llvm::VectorType::get(CGF->Int64Ty, V1Ty ? 1 : (1 << IsQuad));
case NeonTypeFlags::Float32:
- return llvm::VectorType::get(CGF->FloatTy, 2 << IsQuad);
+ return llvm::VectorType::get(CGF->FloatTy, V1Ty ? 1 : (2 << IsQuad));
+ case NeonTypeFlags::Float64:
+ return llvm::VectorType::get(CGF->DoubleTy, V1Ty ? 1 : (1 << IsQuad));
}
- llvm_unreachable("Invalid NeonTypeFlags element type!");
+ llvm_unreachable("Unknown vector element type!");
}
Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C) {
@@ -1568,6 +1661,39 @@ Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
return llvm::ConstantVector::getSplat(VTy->getNumElements(), C);
}
+// \brief Right-shift a vector by a constant.
+Value *CodeGenFunction::EmitNeonRShiftImm(Value *Vec, Value *Shift,
+ llvm::Type *Ty, bool usgn,
+ const char *name) {
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+
+ int ShiftAmt = cast<ConstantInt>(Shift)->getSExtValue();
+ int EltSize = VTy->getScalarSizeInBits();
+
+ Vec = Builder.CreateBitCast(Vec, Ty);
+
+ // lshr/ashr are undefined when the shift amount is equal to the vector
+ // element size.
+ if (ShiftAmt == EltSize) {
+ if (usgn) {
+ // Right-shifting an unsigned value by its size yields 0.
+ llvm::Constant *Zero = ConstantInt::get(VTy->getElementType(), 0);
+ return llvm::ConstantVector::getSplat(VTy->getNumElements(), Zero);
+ } else {
+ // Right-shifting a signed value by its size is equivalent
+ // to a shift of size-1.
+ --ShiftAmt;
+ Shift = ConstantInt::get(VTy->getElementType(), ShiftAmt);
+ }
+ }
+
+ Shift = EmitNeonShiftVector(Shift, Ty, false);
+ if (usgn)
+ return Builder.CreateLShr(Vec, Shift, name);
+ else
+ return Builder.CreateAShr(Vec, Shift, name);
+}
+
/// GetPointeeAlignment - Given an expression with a pointer type, find the
/// alignment of the type referenced by the pointer. Skip over implicit
/// casts.
@@ -1623,8 +1749,1140 @@ CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) {
return std::make_pair(EmitScalarExpr(Addr), Align);
}
+static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF,
+ unsigned BuiltinID,
+ const CallExpr *E) {
+ unsigned int Int = 0;
+ // Scalar result generated across vectors
+ bool AcrossVec = false;
+ // Extend element of one-element vector
+ bool ExtendEle = false;
+ bool OverloadInt = false;
+ bool OverloadCmpInt = false;
+ bool IsFpCmpZInt = false;
+ bool OverloadCvtInt = false;
+ bool OverloadWideInt = false;
+ bool OverloadNarrowInt = false;
+ const char *s = NULL;
+
+ SmallVector<Value *, 4> Ops;
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
+ Ops.push_back(CGF.EmitScalarExpr(E->getArg(i)));
+ }
+
+ // AArch64 scalar builtins are not overloaded, they do not have an extra
+ // argument that specifies the vector type, need to handle each case.
+ switch (BuiltinID) {
+ default: break;
+ case AArch64::BI__builtin_neon_vdups_lane_f32:
+ case AArch64::BI__builtin_neon_vdupd_lane_f64:
+ case AArch64::BI__builtin_neon_vdups_laneq_f32:
+ case AArch64::BI__builtin_neon_vdupd_laneq_f64: {
+ return CGF.Builder.CreateExtractElement(Ops[0], Ops[1], "vdup_lane");
+ }
+ case AArch64::BI__builtin_neon_vdupb_lane_i8:
+ case AArch64::BI__builtin_neon_vduph_lane_i16:
+ case AArch64::BI__builtin_neon_vdups_lane_i32:
+ case AArch64::BI__builtin_neon_vdupd_lane_i64:
+ case AArch64::BI__builtin_neon_vdupb_laneq_i8:
+ case AArch64::BI__builtin_neon_vduph_laneq_i16:
+ case AArch64::BI__builtin_neon_vdups_laneq_i32:
+ case AArch64::BI__builtin_neon_vdupd_laneq_i64: {
+ // The backend treats Neon scalar types as v1ix types
+ // So we want to dup lane from any vector to v1ix vector
+ // with shufflevector
+ s = "vdup_lane";
+ Value* SV = llvm::ConstantVector::getSplat(1, cast<ConstantInt>(Ops[1]));
+ Value *Result = CGF.Builder.CreateShuffleVector(Ops[0], Ops[0], SV, s);
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ // AArch64 intrinsic one-element vector type cast to
+ // scalar type expected by the builtin
+ return CGF.Builder.CreateBitCast(Result, Ty, s);
+ }
+ case AArch64::BI__builtin_neon_vqdmlalh_lane_s16 :
+ case AArch64::BI__builtin_neon_vqdmlalh_laneq_s16 :
+ case AArch64::BI__builtin_neon_vqdmlals_lane_s32 :
+ case AArch64::BI__builtin_neon_vqdmlals_laneq_s32 :
+ case AArch64::BI__builtin_neon_vqdmlslh_lane_s16 :
+ case AArch64::BI__builtin_neon_vqdmlslh_laneq_s16 :
+ case AArch64::BI__builtin_neon_vqdmlsls_lane_s32 :
+ case AArch64::BI__builtin_neon_vqdmlsls_laneq_s32 : {
+ Int = Intrinsic::arm_neon_vqadds;
+ if (BuiltinID == AArch64::BI__builtin_neon_vqdmlslh_lane_s16 ||
+ BuiltinID == AArch64::BI__builtin_neon_vqdmlslh_laneq_s16 ||
+ BuiltinID == AArch64::BI__builtin_neon_vqdmlsls_lane_s32 ||
+ BuiltinID == AArch64::BI__builtin_neon_vqdmlsls_laneq_s32) {
+ Int = Intrinsic::arm_neon_vqsubs;
+ }
+ // create vqdmull call with b * c[i]
+ llvm::Type *Ty = CGF.ConvertType(E->getArg(1)->getType());
+ llvm::VectorType *OpVTy = llvm::VectorType::get(Ty, 1);
+ Ty = CGF.ConvertType(E->getArg(0)->getType());
+ llvm::VectorType *ResVTy = llvm::VectorType::get(Ty, 1);
+ Value *F = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, ResVTy);
+ Value *V = UndefValue::get(OpVTy);
+ llvm::Constant *CI = ConstantInt::get(CGF.Int32Ty, 0);
+ SmallVector<Value *, 2> MulOps;
+ MulOps.push_back(Ops[1]);
+ MulOps.push_back(Ops[2]);
+ MulOps[0] = CGF.Builder.CreateInsertElement(V, MulOps[0], CI);
+ MulOps[1] = CGF.Builder.CreateExtractElement(MulOps[1], Ops[3], "extract");
+ MulOps[1] = CGF.Builder.CreateInsertElement(V, MulOps[1], CI);
+ Value *MulRes = CGF.Builder.CreateCall2(F, MulOps[0], MulOps[1]);
+ // create vqadds call with a +/- vqdmull result
+ F = CGF.CGM.getIntrinsic(Int, ResVTy);
+ SmallVector<Value *, 2> AddOps;
+ AddOps.push_back(Ops[0]);
+ AddOps.push_back(MulRes);
+ V = UndefValue::get(ResVTy);
+ AddOps[0] = CGF.Builder.CreateInsertElement(V, AddOps[0], CI);
+ Value *AddRes = CGF.Builder.CreateCall2(F, AddOps[0], AddOps[1]);
+ return CGF.Builder.CreateBitCast(AddRes, Ty);
+ }
+ case AArch64::BI__builtin_neon_vfmas_lane_f32:
+ case AArch64::BI__builtin_neon_vfmas_laneq_f32:
+ case AArch64::BI__builtin_neon_vfmad_lane_f64:
+ case AArch64::BI__builtin_neon_vfmad_laneq_f64: {
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ Value *F = CGF.CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[2] = CGF.Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
+ return CGF.Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ }
+ // Scalar Floating-point Multiply Extended
+ case AArch64::BI__builtin_neon_vmulxs_f32:
+ case AArch64::BI__builtin_neon_vmulxd_f64: {
+ Int = Intrinsic::aarch64_neon_vmulx;
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ return CGF.EmitNeonCall(CGF.CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
+ }
+ case AArch64::BI__builtin_neon_vmul_n_f64: {
+ // v1f64 vmul_n_f64 should be mapped to Neon scalar mul lane
+ llvm::Type *VTy = GetNeonType(&CGF,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, false));
+ Ops[0] = CGF.Builder.CreateBitCast(Ops[0], VTy);
+ llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0);
+ Ops[0] = CGF.Builder.CreateExtractElement(Ops[0], Idx, "extract");
+ Value *Result = CGF.Builder.CreateFMul(Ops[0], Ops[1]);
+ return CGF.Builder.CreateBitCast(Result, VTy);
+ }
+ case AArch64::BI__builtin_neon_vget_lane_i8:
+ case AArch64::BI__builtin_neon_vget_lane_i16:
+ case AArch64::BI__builtin_neon_vget_lane_i32:
+ case AArch64::BI__builtin_neon_vget_lane_i64:
+ case AArch64::BI__builtin_neon_vget_lane_f32:
+ case AArch64::BI__builtin_neon_vget_lane_f64:
+ case AArch64::BI__builtin_neon_vgetq_lane_i8:
+ case AArch64::BI__builtin_neon_vgetq_lane_i16:
+ case AArch64::BI__builtin_neon_vgetq_lane_i32:
+ case AArch64::BI__builtin_neon_vgetq_lane_i64:
+ case AArch64::BI__builtin_neon_vgetq_lane_f32:
+ case AArch64::BI__builtin_neon_vgetq_lane_f64:
+ return CGF.EmitARMBuiltinExpr(ARM::BI__builtin_neon_vget_lane_i8, E);
+ case AArch64::BI__builtin_neon_vset_lane_i8:
+ case AArch64::BI__builtin_neon_vset_lane_i16:
+ case AArch64::BI__builtin_neon_vset_lane_i32:
+ case AArch64::BI__builtin_neon_vset_lane_i64:
+ case AArch64::BI__builtin_neon_vset_lane_f32:
+ case AArch64::BI__builtin_neon_vset_lane_f64:
+ case AArch64::BI__builtin_neon_vsetq_lane_i8:
+ case AArch64::BI__builtin_neon_vsetq_lane_i16:
+ case AArch64::BI__builtin_neon_vsetq_lane_i32:
+ case AArch64::BI__builtin_neon_vsetq_lane_i64:
+ case AArch64::BI__builtin_neon_vsetq_lane_f32:
+ case AArch64::BI__builtin_neon_vsetq_lane_f64:
+ return CGF.EmitARMBuiltinExpr(ARM::BI__builtin_neon_vset_lane_i8, E);
+ // Crypto
+ case AArch64::BI__builtin_neon_vsha1h_u32:
+ Int = Intrinsic::arm_neon_sha1h;
+ s = "sha1h"; OverloadInt = true; break;
+ case AArch64::BI__builtin_neon_vsha1cq_u32:
+ Int = Intrinsic::aarch64_neon_sha1c;
+ s = "sha1c"; break;
+ case AArch64::BI__builtin_neon_vsha1pq_u32:
+ Int = Intrinsic::aarch64_neon_sha1p;
+ s = "sha1p"; break;
+ case AArch64::BI__builtin_neon_vsha1mq_u32:
+ Int = Intrinsic::aarch64_neon_sha1m;
+ s = "sha1m"; break;
+ // Scalar Add
+ case AArch64::BI__builtin_neon_vaddd_s64:
+ Int = Intrinsic::aarch64_neon_vaddds;
+ s = "vaddds"; break;
+ case AArch64::BI__builtin_neon_vaddd_u64:
+ Int = Intrinsic::aarch64_neon_vadddu;
+ s = "vadddu"; break;
+ // Scalar Sub
+ case AArch64::BI__builtin_neon_vsubd_s64:
+ Int = Intrinsic::aarch64_neon_vsubds;
+ s = "vsubds"; break;
+ case AArch64::BI__builtin_neon_vsubd_u64:
+ Int = Intrinsic::aarch64_neon_vsubdu;
+ s = "vsubdu"; break;
+ // Scalar Saturating Add
+ case AArch64::BI__builtin_neon_vqaddb_s8:
+ case AArch64::BI__builtin_neon_vqaddh_s16:
+ case AArch64::BI__builtin_neon_vqadds_s32:
+ case AArch64::BI__builtin_neon_vqaddd_s64:
+ Int = Intrinsic::arm_neon_vqadds;
+ s = "vqadds"; OverloadInt = true; break;
+ case AArch64::BI__builtin_neon_vqaddb_u8:
+ case AArch64::BI__builtin_neon_vqaddh_u16:
+ case AArch64::BI__builtin_neon_vqadds_u32:
+ case AArch64::BI__builtin_neon_vqaddd_u64:
+ Int = Intrinsic::arm_neon_vqaddu;
+ s = "vqaddu"; OverloadInt = true; break;
+ // Scalar Saturating Sub
+ case AArch64::BI__builtin_neon_vqsubb_s8:
+ case AArch64::BI__builtin_neon_vqsubh_s16:
+ case AArch64::BI__builtin_neon_vqsubs_s32:
+ case AArch64::BI__builtin_neon_vqsubd_s64:
+ Int = Intrinsic::arm_neon_vqsubs;
+ s = "vqsubs"; OverloadInt = true; break;
+ case AArch64::BI__builtin_neon_vqsubb_u8:
+ case AArch64::BI__builtin_neon_vqsubh_u16:
+ case AArch64::BI__builtin_neon_vqsubs_u32:
+ case AArch64::BI__builtin_neon_vqsubd_u64:
+ Int = Intrinsic::arm_neon_vqsubu;
+ s = "vqsubu"; OverloadInt = true; break;
+ // Scalar Shift Left
+ case AArch64::BI__builtin_neon_vshld_s64:
+ Int = Intrinsic::aarch64_neon_vshlds;
+ s = "vshlds"; break;
+ case AArch64::BI__builtin_neon_vshld_u64:
+ Int = Intrinsic::aarch64_neon_vshldu;
+ s = "vshldu"; break;
+ // Scalar Saturating Shift Left
+ case AArch64::BI__builtin_neon_vqshlb_s8:
+ case AArch64::BI__builtin_neon_vqshlh_s16:
+ case AArch64::BI__builtin_neon_vqshls_s32:
+ case AArch64::BI__builtin_neon_vqshld_s64:
+ Int = Intrinsic::aarch64_neon_vqshls;
+ s = "vqshls"; OverloadInt = true; break;
+ case AArch64::BI__builtin_neon_vqshlb_u8:
+ case AArch64::BI__builtin_neon_vqshlh_u16:
+ case AArch64::BI__builtin_neon_vqshls_u32:
+ case AArch64::BI__builtin_neon_vqshld_u64:
+ Int = Intrinsic::aarch64_neon_vqshlu;
+ s = "vqshlu"; OverloadInt = true; break;
+ // Scalar Rouding Shift Left
+ case AArch64::BI__builtin_neon_vrshld_s64:
+ Int = Intrinsic::aarch64_neon_vrshlds;
+ s = "vrshlds"; break;
+ case AArch64::BI__builtin_neon_vrshld_u64:
+ Int = Intrinsic::aarch64_neon_vrshldu;
+ s = "vrshldu"; break;
+ // Scalar Saturating Rouding Shift Left
+ case AArch64::BI__builtin_neon_vqrshlb_s8:
+ case AArch64::BI__builtin_neon_vqrshlh_s16:
+ case AArch64::BI__builtin_neon_vqrshls_s32:
+ case AArch64::BI__builtin_neon_vqrshld_s64:
+ Int = Intrinsic::aarch64_neon_vqrshls;
+ s = "vqrshls"; OverloadInt = true; break;
+ case AArch64::BI__builtin_neon_vqrshlb_u8:
+ case AArch64::BI__builtin_neon_vqrshlh_u16:
+ case AArch64::BI__builtin_neon_vqrshls_u32:
+ case AArch64::BI__builtin_neon_vqrshld_u64:
+ Int = Intrinsic::aarch64_neon_vqrshlu;
+ s = "vqrshlu"; OverloadInt = true; break;
+ // Scalar Reduce Pairwise Add
+ case AArch64::BI__builtin_neon_vpaddd_s64:
+ case AArch64::BI__builtin_neon_vpaddd_u64:
+ Int = Intrinsic::aarch64_neon_vpadd; s = "vpadd";
+ break;
+ case AArch64::BI__builtin_neon_vpadds_f32:
+ Int = Intrinsic::aarch64_neon_vpfadd; s = "vpfadd";
+ break;
+ case AArch64::BI__builtin_neon_vpaddd_f64:
+ Int = Intrinsic::aarch64_neon_vpfaddq; s = "vpfaddq";
+ break;
+ // Scalar Reduce Pairwise Floating Point Max
+ case AArch64::BI__builtin_neon_vpmaxs_f32:
+ Int = Intrinsic::aarch64_neon_vpmax; s = "vpmax";
+ break;
+ case AArch64::BI__builtin_neon_vpmaxqd_f64:
+ Int = Intrinsic::aarch64_neon_vpmaxq; s = "vpmaxq";
+ break;
+ // Scalar Reduce Pairwise Floating Point Min
+ case AArch64::BI__builtin_neon_vpmins_f32:
+ Int = Intrinsic::aarch64_neon_vpmin; s = "vpmin";
+ break;
+ case AArch64::BI__builtin_neon_vpminqd_f64:
+ Int = Intrinsic::aarch64_neon_vpminq; s = "vpminq";
+ break;
+ // Scalar Reduce Pairwise Floating Point Maxnm
+ case AArch64::BI__builtin_neon_vpmaxnms_f32:
+ Int = Intrinsic::aarch64_neon_vpfmaxnm; s = "vpfmaxnm";
+ break;
+ case AArch64::BI__builtin_neon_vpmaxnmqd_f64:
+ Int = Intrinsic::aarch64_neon_vpfmaxnmq; s = "vpfmaxnmq";
+ break;
+ // Scalar Reduce Pairwise Floating Point Minnm
+ case AArch64::BI__builtin_neon_vpminnms_f32:
+ Int = Intrinsic::aarch64_neon_vpfminnm; s = "vpfminnm";
+ break;
+ case AArch64::BI__builtin_neon_vpminnmqd_f64:
+ Int = Intrinsic::aarch64_neon_vpfminnmq; s = "vpfminnmq";
+ break;
+ // The followings are intrinsics with scalar results generated AcrossVec vectors
+ case AArch64::BI__builtin_neon_vaddlv_s8:
+ case AArch64::BI__builtin_neon_vaddlv_s16:
+ case AArch64::BI__builtin_neon_vaddlvq_s8:
+ case AArch64::BI__builtin_neon_vaddlvq_s16:
+ case AArch64::BI__builtin_neon_vaddlvq_s32:
+ Int = Intrinsic::aarch64_neon_saddlv;
+ AcrossVec = true; ExtendEle = true; s = "saddlv"; break;
+ case AArch64::BI__builtin_neon_vaddlv_u8:
+ case AArch64::BI__builtin_neon_vaddlv_u16:
+ case AArch64::BI__builtin_neon_vaddlvq_u8:
+ case AArch64::BI__builtin_neon_vaddlvq_u16:
+ case AArch64::BI__builtin_neon_vaddlvq_u32:
+ Int = Intrinsic::aarch64_neon_uaddlv;
+ AcrossVec = true; ExtendEle = true; s = "uaddlv"; break;
+ case AArch64::BI__builtin_neon_vmaxv_s8:
+ case AArch64::BI__builtin_neon_vmaxv_s16:
+ case AArch64::BI__builtin_neon_vmaxvq_s8:
+ case AArch64::BI__builtin_neon_vmaxvq_s16:
+ case AArch64::BI__builtin_neon_vmaxvq_s32:
+ Int = Intrinsic::aarch64_neon_smaxv;
+ AcrossVec = true; ExtendEle = false; s = "smaxv"; break;
+ case AArch64::BI__builtin_neon_vmaxv_u8:
+ case AArch64::BI__builtin_neon_vmaxv_u16:
+ case AArch64::BI__builtin_neon_vmaxvq_u8:
+ case AArch64::BI__builtin_neon_vmaxvq_u16:
+ case AArch64::BI__builtin_neon_vmaxvq_u32:
+ Int = Intrinsic::aarch64_neon_umaxv;
+ AcrossVec = true; ExtendEle = false; s = "umaxv"; break;
+ case AArch64::BI__builtin_neon_vminv_s8:
+ case AArch64::BI__builtin_neon_vminv_s16:
+ case AArch64::BI__builtin_neon_vminvq_s8:
+ case AArch64::BI__builtin_neon_vminvq_s16:
+ case AArch64::BI__builtin_neon_vminvq_s32:
+ Int = Intrinsic::aarch64_neon_sminv;
+ AcrossVec = true; ExtendEle = false; s = "sminv"; break;
+ case AArch64::BI__builtin_neon_vminv_u8:
+ case AArch64::BI__builtin_neon_vminv_u16:
+ case AArch64::BI__builtin_neon_vminvq_u8:
+ case AArch64::BI__builtin_neon_vminvq_u16:
+ case AArch64::BI__builtin_neon_vminvq_u32:
+ Int = Intrinsic::aarch64_neon_uminv;
+ AcrossVec = true; ExtendEle = false; s = "uminv"; break;
+ case AArch64::BI__builtin_neon_vaddv_s8:
+ case AArch64::BI__builtin_neon_vaddv_s16:
+ case AArch64::BI__builtin_neon_vaddvq_s8:
+ case AArch64::BI__builtin_neon_vaddvq_s16:
+ case AArch64::BI__builtin_neon_vaddvq_s32:
+ case AArch64::BI__builtin_neon_vaddvq_s64:
+ case AArch64::BI__builtin_neon_vaddv_u8:
+ case AArch64::BI__builtin_neon_vaddv_u16:
+ case AArch64::BI__builtin_neon_vaddvq_u8:
+ case AArch64::BI__builtin_neon_vaddvq_u16:
+ case AArch64::BI__builtin_neon_vaddvq_u32:
+ case AArch64::BI__builtin_neon_vaddvq_u64:
+ case AArch64::BI__builtin_neon_vaddv_f32:
+ case AArch64::BI__builtin_neon_vaddvq_f32:
+ case AArch64::BI__builtin_neon_vaddvq_f64:
+ Int = Intrinsic::aarch64_neon_vaddv;
+ AcrossVec = true; ExtendEle = false; s = "vaddv"; break;
+ case AArch64::BI__builtin_neon_vmaxv_f32:
+ case AArch64::BI__builtin_neon_vmaxvq_f32:
+ case AArch64::BI__builtin_neon_vmaxvq_f64:
+ Int = Intrinsic::aarch64_neon_vmaxv;
+ AcrossVec = true; ExtendEle = false; s = "vmaxv"; break;
+ case AArch64::BI__builtin_neon_vminv_f32:
+ case AArch64::BI__builtin_neon_vminvq_f32:
+ case AArch64::BI__builtin_neon_vminvq_f64:
+ Int = Intrinsic::aarch64_neon_vminv;
+ AcrossVec = true; ExtendEle = false; s = "vminv"; break;
+ case AArch64::BI__builtin_neon_vmaxnmv_f32:
+ case AArch64::BI__builtin_neon_vmaxnmvq_f32:
+ case AArch64::BI__builtin_neon_vmaxnmvq_f64:
+ Int = Intrinsic::aarch64_neon_vmaxnmv;
+ AcrossVec = true; ExtendEle = false; s = "vmaxnmv"; break;
+ case AArch64::BI__builtin_neon_vminnmv_f32:
+ case AArch64::BI__builtin_neon_vminnmvq_f32:
+ case AArch64::BI__builtin_neon_vminnmvq_f64:
+ Int = Intrinsic::aarch64_neon_vminnmv;
+ AcrossVec = true; ExtendEle = false; s = "vminnmv"; break;
+ // Scalar Integer Saturating Doubling Multiply Half High
+ case AArch64::BI__builtin_neon_vqdmulhh_s16:
+ case AArch64::BI__builtin_neon_vqdmulhs_s32:
+ Int = Intrinsic::arm_neon_vqdmulh;
+ s = "vqdmulh"; OverloadInt = true; break;
+ // Scalar Integer Saturating Rounding Doubling Multiply Half High
+ case AArch64::BI__builtin_neon_vqrdmulhh_s16:
+ case AArch64::BI__builtin_neon_vqrdmulhs_s32:
+ Int = Intrinsic::arm_neon_vqrdmulh;
+ s = "vqrdmulh"; OverloadInt = true; break;
+ // Scalar Floating-point Reciprocal Step and
+ case AArch64::BI__builtin_neon_vrecpss_f32:
+ case AArch64::BI__builtin_neon_vrecpsd_f64:
+ Int = Intrinsic::arm_neon_vrecps;
+ s = "vrecps"; OverloadInt = true; break;
+ // Scalar Floating-point Reciprocal Square Root Step
+ case AArch64::BI__builtin_neon_vrsqrtss_f32:
+ case AArch64::BI__builtin_neon_vrsqrtsd_f64:
+ Int = Intrinsic::arm_neon_vrsqrts;
+ s = "vrsqrts"; OverloadInt = true; break;
+ // Scalar Signed Integer Convert To Floating-point
+ case AArch64::BI__builtin_neon_vcvts_f32_s32:
+ Int = Intrinsic::aarch64_neon_vcvtf32_s32,
+ s = "vcvtf"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_f64_s64:
+ Int = Intrinsic::aarch64_neon_vcvtf64_s64,
+ s = "vcvtf"; OverloadInt = false; break;
+ // Scalar Unsigned Integer Convert To Floating-point
+ case AArch64::BI__builtin_neon_vcvts_f32_u32:
+ Int = Intrinsic::aarch64_neon_vcvtf32_u32,
+ s = "vcvtf"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_f64_u64:
+ Int = Intrinsic::aarch64_neon_vcvtf64_u64,
+ s = "vcvtf"; OverloadInt = false; break;
+ // Scalar Floating-point Converts
+ case AArch64::BI__builtin_neon_vcvtxd_f32_f64:
+ Int = Intrinsic::aarch64_neon_fcvtxn;
+ s = "vcvtxn"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtas_s32_f32:
+ case AArch64::BI__builtin_neon_vcvtad_s64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtas;
+ s = "vcvtas"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtas_u32_f32:
+ case AArch64::BI__builtin_neon_vcvtad_u64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtau;
+ s = "vcvtau"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtms_s32_f32:
+ case AArch64::BI__builtin_neon_vcvtmd_s64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtms;
+ s = "vcvtms"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtms_u32_f32:
+ case AArch64::BI__builtin_neon_vcvtmd_u64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtmu;
+ s = "vcvtmu"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtns_s32_f32:
+ case AArch64::BI__builtin_neon_vcvtnd_s64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtns;
+ s = "vcvtns"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtns_u32_f32:
+ case AArch64::BI__builtin_neon_vcvtnd_u64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtnu;
+ s = "vcvtnu"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtps_s32_f32:
+ case AArch64::BI__builtin_neon_vcvtpd_s64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtps;
+ s = "vcvtps"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvtps_u32_f32:
+ case AArch64::BI__builtin_neon_vcvtpd_u64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtpu;
+ s = "vcvtpu"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvts_s32_f32:
+ case AArch64::BI__builtin_neon_vcvtd_s64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtzs;
+ s = "vcvtzs"; OverloadCvtInt = true; break;
+ case AArch64::BI__builtin_neon_vcvts_u32_f32:
+ case AArch64::BI__builtin_neon_vcvtd_u64_f64:
+ Int = Intrinsic::aarch64_neon_fcvtzu;
+ s = "vcvtzu"; OverloadCvtInt = true; break;
+ // Scalar Floating-point Reciprocal Estimate
+ case AArch64::BI__builtin_neon_vrecpes_f32:
+ case AArch64::BI__builtin_neon_vrecped_f64:
+ Int = Intrinsic::arm_neon_vrecpe;
+ s = "vrecpe"; OverloadInt = true; break;
+ // Scalar Floating-point Reciprocal Exponent
+ case AArch64::BI__builtin_neon_vrecpxs_f32:
+ case AArch64::BI__builtin_neon_vrecpxd_f64:
+ Int = Intrinsic::aarch64_neon_vrecpx;
+ s = "vrecpx"; OverloadInt = true; break;
+ // Scalar Floating-point Reciprocal Square Root Estimate
+ case AArch64::BI__builtin_neon_vrsqrtes_f32:
+ case AArch64::BI__builtin_neon_vrsqrted_f64:
+ Int = Intrinsic::arm_neon_vrsqrte;
+ s = "vrsqrte"; OverloadInt = true; break;
+ // Scalar Compare Equal
+ case AArch64::BI__builtin_neon_vceqd_s64:
+ case AArch64::BI__builtin_neon_vceqd_u64:
+ Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
+ OverloadCmpInt = true; break;
+ // Scalar Compare Equal To Zero
+ case AArch64::BI__builtin_neon_vceqzd_s64:
+ case AArch64::BI__builtin_neon_vceqzd_u64:
+ Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
+ OverloadCmpInt = true; break;
+ // Scalar Compare Greater Than or Equal
+ case AArch64::BI__builtin_neon_vcged_s64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ OverloadCmpInt = true; break;
+ case AArch64::BI__builtin_neon_vcged_u64:
+ Int = Intrinsic::aarch64_neon_vchs; s = "vcge";
+ OverloadCmpInt = true; break;
+ // Scalar Compare Greater Than or Equal To Zero
+ case AArch64::BI__builtin_neon_vcgezd_s64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
+ OverloadCmpInt = true; break;
+ // Scalar Compare Greater Than
+ case AArch64::BI__builtin_neon_vcgtd_s64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ OverloadCmpInt = true; break;
+ case AArch64::BI__builtin_neon_vcgtd_u64:
+ Int = Intrinsic::aarch64_neon_vchi; s = "vcgt";
+ OverloadCmpInt = true; break;
+ // Scalar Compare Greater Than Zero
+ case AArch64::BI__builtin_neon_vcgtzd_s64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
+ OverloadCmpInt = true; break;
+ // Scalar Compare Less Than or Equal
+ case AArch64::BI__builtin_neon_vcled_s64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ case AArch64::BI__builtin_neon_vcled_u64:
+ Int = Intrinsic::aarch64_neon_vchs; s = "vchs";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ // Scalar Compare Less Than or Equal To Zero
+ case AArch64::BI__builtin_neon_vclezd_s64:
+ Int = Intrinsic::aarch64_neon_vclez; s = "vcle";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
+ OverloadCmpInt = true; break;
+ // Scalar Compare Less Than
+ case AArch64::BI__builtin_neon_vcltd_s64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ case AArch64::BI__builtin_neon_vcltd_u64:
+ Int = Intrinsic::aarch64_neon_vchi; s = "vchi";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ // Scalar Compare Less Than Zero
+ case AArch64::BI__builtin_neon_vcltzd_s64:
+ Int = Intrinsic::aarch64_neon_vcltz; s = "vclt";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Equal
+ case AArch64::BI__builtin_neon_vceqs_f32:
+ case AArch64::BI__builtin_neon_vceqd_f64:
+ Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Equal To Zero
+ case AArch64::BI__builtin_neon_vceqzs_f32:
+ case AArch64::BI__builtin_neon_vceqzd_f64:
+ Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
+ IsFpCmpZInt = true;
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Greater Than Or Equal
+ case AArch64::BI__builtin_neon_vcges_f32:
+ case AArch64::BI__builtin_neon_vcged_f64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Greater Than Or Equal To Zero
+ case AArch64::BI__builtin_neon_vcgezs_f32:
+ case AArch64::BI__builtin_neon_vcgezd_f64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
+ IsFpCmpZInt = true;
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Greather Than
+ case AArch64::BI__builtin_neon_vcgts_f32:
+ case AArch64::BI__builtin_neon_vcgtd_f64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Greather Than Zero
+ case AArch64::BI__builtin_neon_vcgtzs_f32:
+ case AArch64::BI__builtin_neon_vcgtzd_f64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
+ IsFpCmpZInt = true;
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Less Than or Equal
+ case AArch64::BI__builtin_neon_vcles_f32:
+ case AArch64::BI__builtin_neon_vcled_f64:
+ Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Less Than Or Equal To Zero
+ case AArch64::BI__builtin_neon_vclezs_f32:
+ case AArch64::BI__builtin_neon_vclezd_f64:
+ Int = Intrinsic::aarch64_neon_vclez; s = "vcle";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
+ IsFpCmpZInt = true;
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Compare Less Than Zero
+ case AArch64::BI__builtin_neon_vclts_f32:
+ case AArch64::BI__builtin_neon_vcltd_f64:
+ Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ // Scalar Floating-point Compare Less Than Zero
+ case AArch64::BI__builtin_neon_vcltzs_f32:
+ case AArch64::BI__builtin_neon_vcltzd_f64:
+ Int = Intrinsic::aarch64_neon_vcltz; s = "vclt";
+ // Add implicit zero operand.
+ Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
+ IsFpCmpZInt = true;
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Absolute Compare Greater Than Or Equal
+ case AArch64::BI__builtin_neon_vcages_f32:
+ case AArch64::BI__builtin_neon_vcaged_f64:
+ Int = Intrinsic::aarch64_neon_vcage; s = "vcage";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Absolute Compare Greater Than
+ case AArch64::BI__builtin_neon_vcagts_f32:
+ case AArch64::BI__builtin_neon_vcagtd_f64:
+ Int = Intrinsic::aarch64_neon_vcagt; s = "vcagt";
+ OverloadCmpInt = true; break;
+ // Scalar Floating-point Absolute Compare Less Than Or Equal
+ case AArch64::BI__builtin_neon_vcales_f32:
+ case AArch64::BI__builtin_neon_vcaled_f64:
+ Int = Intrinsic::aarch64_neon_vcage; s = "vcage";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ // Scalar Floating-point Absolute Compare Less Than
+ case AArch64::BI__builtin_neon_vcalts_f32:
+ case AArch64::BI__builtin_neon_vcaltd_f64:
+ Int = Intrinsic::aarch64_neon_vcagt; s = "vcalt";
+ OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
+ // Scalar Compare Bitwise Test Bits
+ case AArch64::BI__builtin_neon_vtstd_s64:
+ case AArch64::BI__builtin_neon_vtstd_u64:
+ Int = Intrinsic::aarch64_neon_vtstd; s = "vtst";
+ OverloadCmpInt = true; break;
+ // Scalar Absolute Value
+ case AArch64::BI__builtin_neon_vabsd_s64:
+ Int = Intrinsic::aarch64_neon_vabs;
+ s = "vabs"; OverloadInt = false; break;
+ // Scalar Absolute Difference
+ case AArch64::BI__builtin_neon_vabds_f32:
+ case AArch64::BI__builtin_neon_vabdd_f64:
+ Int = Intrinsic::aarch64_neon_vabd;
+ s = "vabd"; OverloadInt = true; break;
+ // Scalar Signed Saturating Absolute Value
+ case AArch64::BI__builtin_neon_vqabsb_s8:
+ case AArch64::BI__builtin_neon_vqabsh_s16:
+ case AArch64::BI__builtin_neon_vqabss_s32:
+ case AArch64::BI__builtin_neon_vqabsd_s64:
+ Int = Intrinsic::arm_neon_vqabs;
+ s = "vqabs"; OverloadInt = true; break;
+ // Scalar Negate
+ case AArch64::BI__builtin_neon_vnegd_s64:
+ Int = Intrinsic::aarch64_neon_vneg;
+ s = "vneg"; OverloadInt = false; break;
+ // Scalar Signed Saturating Negate
+ case AArch64::BI__builtin_neon_vqnegb_s8:
+ case AArch64::BI__builtin_neon_vqnegh_s16:
+ case AArch64::BI__builtin_neon_vqnegs_s32:
+ case AArch64::BI__builtin_neon_vqnegd_s64:
+ Int = Intrinsic::arm_neon_vqneg;
+ s = "vqneg"; OverloadInt = true; break;
+ // Scalar Signed Saturating Accumulated of Unsigned Value
+ case AArch64::BI__builtin_neon_vuqaddb_s8:
+ case AArch64::BI__builtin_neon_vuqaddh_s16:
+ case AArch64::BI__builtin_neon_vuqadds_s32:
+ case AArch64::BI__builtin_neon_vuqaddd_s64:
+ Int = Intrinsic::aarch64_neon_vuqadd;
+ s = "vuqadd"; OverloadInt = true; break;
+ // Scalar Unsigned Saturating Accumulated of Signed Value
+ case AArch64::BI__builtin_neon_vsqaddb_u8:
+ case AArch64::BI__builtin_neon_vsqaddh_u16:
+ case AArch64::BI__builtin_neon_vsqadds_u32:
+ case AArch64::BI__builtin_neon_vsqaddd_u64:
+ Int = Intrinsic::aarch64_neon_vsqadd;
+ s = "vsqadd"; OverloadInt = true; break;
+ // Signed Saturating Doubling Multiply-Add Long
+ case AArch64::BI__builtin_neon_vqdmlalh_s16:
+ case AArch64::BI__builtin_neon_vqdmlals_s32:
+ Int = Intrinsic::aarch64_neon_vqdmlal;
+ s = "vqdmlal"; OverloadWideInt = true; break;
+ // Signed Saturating Doubling Multiply-Subtract Long
+ case AArch64::BI__builtin_neon_vqdmlslh_s16:
+ case AArch64::BI__builtin_neon_vqdmlsls_s32:
+ Int = Intrinsic::aarch64_neon_vqdmlsl;
+ s = "vqdmlsl"; OverloadWideInt = true; break;
+ // Signed Saturating Doubling Multiply Long
+ case AArch64::BI__builtin_neon_vqdmullh_s16:
+ case AArch64::BI__builtin_neon_vqdmulls_s32:
+ Int = Intrinsic::arm_neon_vqdmull;
+ s = "vqdmull"; OverloadWideInt = true; break;
+ // Scalar Signed Saturating Extract Unsigned Narrow
+ case AArch64::BI__builtin_neon_vqmovunh_s16:
+ case AArch64::BI__builtin_neon_vqmovuns_s32:
+ case AArch64::BI__builtin_neon_vqmovund_s64:
+ Int = Intrinsic::arm_neon_vqmovnsu;
+ s = "vqmovun"; OverloadNarrowInt = true; break;
+ // Scalar Signed Saturating Extract Narrow
+ case AArch64::BI__builtin_neon_vqmovnh_s16:
+ case AArch64::BI__builtin_neon_vqmovns_s32:
+ case AArch64::BI__builtin_neon_vqmovnd_s64:
+ Int = Intrinsic::arm_neon_vqmovns;
+ s = "vqmovn"; OverloadNarrowInt = true; break;
+ // Scalar Unsigned Saturating Extract Narrow
+ case AArch64::BI__builtin_neon_vqmovnh_u16:
+ case AArch64::BI__builtin_neon_vqmovns_u32:
+ case AArch64::BI__builtin_neon_vqmovnd_u64:
+ Int = Intrinsic::arm_neon_vqmovnu;
+ s = "vqmovn"; OverloadNarrowInt = true; break;
+ // Scalar Signed Shift Right (Immediate)
+ case AArch64::BI__builtin_neon_vshrd_n_s64:
+ Int = Intrinsic::aarch64_neon_vshrds_n;
+ s = "vsshr"; OverloadInt = false; break;
+ // Scalar Unsigned Shift Right (Immediate)
+ case AArch64::BI__builtin_neon_vshrd_n_u64:
+ Int = Intrinsic::aarch64_neon_vshrdu_n;
+ s = "vushr"; OverloadInt = false; break;
+ // Scalar Signed Rounding Shift Right (Immediate)
+ case AArch64::BI__builtin_neon_vrshrd_n_s64:
+ Int = Intrinsic::aarch64_neon_vsrshr;
+ s = "vsrshr"; OverloadInt = true; break;
+ // Scalar Unsigned Rounding Shift Right (Immediate)
+ case AArch64::BI__builtin_neon_vrshrd_n_u64:
+ Int = Intrinsic::aarch64_neon_vurshr;
+ s = "vurshr"; OverloadInt = true; break;
+ // Scalar Signed Shift Right and Accumulate (Immediate)
+ case AArch64::BI__builtin_neon_vsrad_n_s64:
+ Int = Intrinsic::aarch64_neon_vsrads_n;
+ s = "vssra"; OverloadInt = false; break;
+ // Scalar Unsigned Shift Right and Accumulate (Immediate)
+ case AArch64::BI__builtin_neon_vsrad_n_u64:
+ Int = Intrinsic::aarch64_neon_vsradu_n;
+ s = "vusra"; OverloadInt = false; break;
+ // Scalar Signed Rounding Shift Right and Accumulate (Immediate)
+ case AArch64::BI__builtin_neon_vrsrad_n_s64:
+ Int = Intrinsic::aarch64_neon_vrsrads_n;
+ s = "vsrsra"; OverloadInt = false; break;
+ // Scalar Unsigned Rounding Shift Right and Accumulate (Immediate)
+ case AArch64::BI__builtin_neon_vrsrad_n_u64:
+ Int = Intrinsic::aarch64_neon_vrsradu_n;
+ s = "vursra"; OverloadInt = false; break;
+ // Scalar Signed/Unsigned Shift Left (Immediate)
+ case AArch64::BI__builtin_neon_vshld_n_s64:
+ case AArch64::BI__builtin_neon_vshld_n_u64:
+ Int = Intrinsic::aarch64_neon_vshld_n;
+ s = "vshl"; OverloadInt = false; break;
+ // Signed Saturating Shift Left (Immediate)
+ case AArch64::BI__builtin_neon_vqshlb_n_s8:
+ case AArch64::BI__builtin_neon_vqshlh_n_s16:
+ case AArch64::BI__builtin_neon_vqshls_n_s32:
+ case AArch64::BI__builtin_neon_vqshld_n_s64:
+ Int = Intrinsic::aarch64_neon_vqshls_n;
+ s = "vsqshl"; OverloadInt = true; break;
+ // Unsigned Saturating Shift Left (Immediate)
+ case AArch64::BI__builtin_neon_vqshlb_n_u8:
+ case AArch64::BI__builtin_neon_vqshlh_n_u16:
+ case AArch64::BI__builtin_neon_vqshls_n_u32:
+ case AArch64::BI__builtin_neon_vqshld_n_u64:
+ Int = Intrinsic::aarch64_neon_vqshlu_n;
+ s = "vuqshl"; OverloadInt = true; break;
+ // Signed Saturating Shift Left Unsigned (Immediate)
+ case AArch64::BI__builtin_neon_vqshlub_n_s8:
+ case AArch64::BI__builtin_neon_vqshluh_n_s16:
+ case AArch64::BI__builtin_neon_vqshlus_n_s32:
+ case AArch64::BI__builtin_neon_vqshlud_n_s64:
+ Int = Intrinsic::aarch64_neon_vsqshlu;
+ s = "vsqshlu"; OverloadInt = true; break;
+ // Shift Right And Insert (Immediate)
+ case AArch64::BI__builtin_neon_vsrid_n_s64:
+ case AArch64::BI__builtin_neon_vsrid_n_u64:
+ Int = Intrinsic::aarch64_neon_vsri;
+ s = "vsri"; OverloadInt = true; break;
+ // Shift Left And Insert (Immediate)
+ case AArch64::BI__builtin_neon_vslid_n_s64:
+ case AArch64::BI__builtin_neon_vslid_n_u64:
+ Int = Intrinsic::aarch64_neon_vsli;
+ s = "vsli"; OverloadInt = true; break;
+ // Signed Saturating Shift Right Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqshrnh_n_s16:
+ case AArch64::BI__builtin_neon_vqshrns_n_s32:
+ case AArch64::BI__builtin_neon_vqshrnd_n_s64:
+ Int = Intrinsic::aarch64_neon_vsqshrn;
+ s = "vsqshrn"; OverloadInt = true; break;
+ // Unsigned Saturating Shift Right Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqshrnh_n_u16:
+ case AArch64::BI__builtin_neon_vqshrns_n_u32:
+ case AArch64::BI__builtin_neon_vqshrnd_n_u64:
+ Int = Intrinsic::aarch64_neon_vuqshrn;
+ s = "vuqshrn"; OverloadInt = true; break;
+ // Signed Saturating Rounded Shift Right Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqrshrnh_n_s16:
+ case AArch64::BI__builtin_neon_vqrshrns_n_s32:
+ case AArch64::BI__builtin_neon_vqrshrnd_n_s64:
+ Int = Intrinsic::aarch64_neon_vsqrshrn;
+ s = "vsqrshrn"; OverloadInt = true; break;
+ // Unsigned Saturating Rounded Shift Right Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqrshrnh_n_u16:
+ case AArch64::BI__builtin_neon_vqrshrns_n_u32:
+ case AArch64::BI__builtin_neon_vqrshrnd_n_u64:
+ Int = Intrinsic::aarch64_neon_vuqrshrn;
+ s = "vuqrshrn"; OverloadInt = true; break;
+ // Signed Saturating Shift Right Unsigned Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqshrunh_n_s16:
+ case AArch64::BI__builtin_neon_vqshruns_n_s32:
+ case AArch64::BI__builtin_neon_vqshrund_n_s64:
+ Int = Intrinsic::aarch64_neon_vsqshrun;
+ s = "vsqshrun"; OverloadInt = true; break;
+ // Signed Saturating Rounded Shift Right Unsigned Narrow (Immediate)
+ case AArch64::BI__builtin_neon_vqrshrunh_n_s16:
+ case AArch64::BI__builtin_neon_vqrshruns_n_s32:
+ case AArch64::BI__builtin_neon_vqrshrund_n_s64:
+ Int = Intrinsic::aarch64_neon_vsqrshrun;
+ s = "vsqrshrun"; OverloadInt = true; break;
+ // Scalar Signed Fixed-point Convert To Floating-Point (Immediate)
+ case AArch64::BI__builtin_neon_vcvts_n_f32_s32:
+ Int = Intrinsic::aarch64_neon_vcvtf32_n_s32;
+ s = "vcvtf"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_n_f64_s64:
+ Int = Intrinsic::aarch64_neon_vcvtf64_n_s64;
+ s = "vcvtf"; OverloadInt = false; break;
+ // Scalar Unsigned Fixed-point Convert To Floating-Point (Immediate)
+ case AArch64::BI__builtin_neon_vcvts_n_f32_u32:
+ Int = Intrinsic::aarch64_neon_vcvtf32_n_u32;
+ s = "vcvtf"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_n_f64_u64:
+ Int = Intrinsic::aarch64_neon_vcvtf64_n_u64;
+ s = "vcvtf"; OverloadInt = false; break;
+ // Scalar Floating-point Convert To Signed Fixed-point (Immediate)
+ case AArch64::BI__builtin_neon_vcvts_n_s32_f32:
+ Int = Intrinsic::aarch64_neon_vcvts_n_s32_f32;
+ s = "fcvtzs"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_n_s64_f64:
+ Int = Intrinsic::aarch64_neon_vcvtd_n_s64_f64;
+ s = "fcvtzs"; OverloadInt = false; break;
+ // Scalar Floating-point Convert To Unsigned Fixed-point (Immediate)
+ case AArch64::BI__builtin_neon_vcvts_n_u32_f32:
+ Int = Intrinsic::aarch64_neon_vcvts_n_u32_f32;
+ s = "fcvtzu"; OverloadInt = false; break;
+ case AArch64::BI__builtin_neon_vcvtd_n_u64_f64:
+ Int = Intrinsic::aarch64_neon_vcvtd_n_u64_f64;
+ s = "fcvtzu"; OverloadInt = false; break;
+ }
+
+ if (!Int)
+ return 0;
+
+ // AArch64 scalar builtin that returns scalar type
+ // and should be mapped to AArch64 intrinsic that returns
+ // one-element vector type.
+ Function *F = 0;
+ if (AcrossVec) {
+ // Gen arg type
+ const Expr *Arg = E->getArg(E->getNumArgs()-1);
+ llvm::Type *Ty = CGF.ConvertType(Arg->getType());
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ llvm::Type *ETy = VTy->getElementType();
+ llvm::VectorType *RTy = llvm::VectorType::get(ETy, 1);
+
+ if (ExtendEle) {
+ assert(!ETy->isFloatingPointTy());
+ RTy = llvm::VectorType::getExtendedElementVectorType(RTy);
+ }
+
+ llvm::Type *Tys[2] = {RTy, VTy};
+ F = CGF.CGM.getIntrinsic(Int, Tys);
+ assert(E->getNumArgs() == 1);
+ } else if (OverloadInt) {
+ // Determine the type of this overloaded AArch64 intrinsic
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
+ assert(VTy);
+
+ F = CGF.CGM.getIntrinsic(Int, VTy);
+ } else if (OverloadWideInt || OverloadNarrowInt) {
+ // Determine the type of this overloaded AArch64 intrinsic
+ const Expr *Arg = E->getArg(E->getNumArgs()-1);
+ llvm::Type *Ty = CGF.ConvertType(Arg->getType());
+ llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
+ llvm::VectorType *RTy = OverloadWideInt ?
+ llvm::VectorType::getExtendedElementVectorType(VTy) :
+ llvm::VectorType::getTruncatedElementVectorType(VTy);
+ F = CGF.CGM.getIntrinsic(Int, RTy);
+ } else if (OverloadCmpInt) {
+ // Determine the types of this overloaded AArch64 intrinsic
+ SmallVector<llvm::Type *, 3> Tys;
+ const Expr *Arg = E->getArg(E->getNumArgs()-1);
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
+ Tys.push_back(VTy);
+ Ty = CGF.ConvertType(Arg->getType());
+ VTy = llvm::VectorType::get(Ty, 1);
+ Tys.push_back(VTy);
+ if(IsFpCmpZInt)
+ VTy = llvm::VectorType::get(CGF.FloatTy, 1);
+ Tys.push_back(VTy);
+
+ F = CGF.CGM.getIntrinsic(Int, Tys);
+ } else if (OverloadCvtInt) {
+ // Determine the types of this overloaded AArch64 intrinsic
+ SmallVector<llvm::Type *, 2> Tys;
+ const Expr *Arg = E->getArg(E->getNumArgs()-1);
+ llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
+ llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
+ Tys.push_back(VTy);
+ Ty = CGF.ConvertType(Arg->getType());
+ VTy = llvm::VectorType::get(Ty, 1);
+ Tys.push_back(VTy);
+
+ F = CGF.CGM.getIntrinsic(Int, Tys);
+ } else
+ F = CGF.CGM.getIntrinsic(Int);
+
+ Value *Result = CGF.EmitNeonCall(F, Ops, s);
+ llvm::Type *ResultType = CGF.ConvertType(E->getType());
+ // AArch64 intrinsic one-element vector type cast to
+ // scalar type expected by the builtin
+ return CGF.Builder.CreateBitCast(Result, ResultType, s);
+}
+
+Value *CodeGenFunction::EmitAArch64CompareBuiltinExpr(
+ Value *Op, llvm::Type *Ty, const CmpInst::Predicate Fp,
+ const CmpInst::Predicate Ip, const Twine &Name) {
+ llvm::Type *OTy = ((llvm::User *)Op)->getOperand(0)->getType();
+ if (OTy->isPointerTy())
+ OTy = Ty;
+ Op = Builder.CreateBitCast(Op, OTy);
+ if (((llvm::VectorType *)OTy)->getElementType()->isFloatingPointTy()) {
+ Op = Builder.CreateFCmp(Fp, Op, ConstantAggregateZero::get(OTy));
+ } else {
+ Op = Builder.CreateICmp(Ip, Op, ConstantAggregateZero::get(OTy));
+ }
+ return Builder.CreateZExt(Op, Ty, Name);
+}
+
+static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
+ Value *ExtOp, Value *IndexOp,
+ llvm::Type *ResTy, unsigned IntID,
+ const char *Name) {
+ SmallVector<Value *, 2> TblOps;
+ if (ExtOp)
+ TblOps.push_back(ExtOp);
+
+ // Build a vector containing sequential number like (0, 1, 2, ..., 15)
+ SmallVector<Constant*, 16> Indices;
+ llvm::VectorType *TblTy = cast<llvm::VectorType>(Ops[0]->getType());
+ for (unsigned i = 0, e = TblTy->getNumElements(); i != e; ++i) {
+ Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i));
+ Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i+1));
+ }
+ Value *SV = llvm::ConstantVector::get(Indices);
+
+ int PairPos = 0, End = Ops.size() - 1;
+ while (PairPos < End) {
+ TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
+ Ops[PairPos+1], SV, Name));
+ PairPos += 2;
+ }
+
+ // If there's an odd number of 64-bit lookup table, fill the high 64-bit
+ // of the 128-bit lookup table with zero.
+ if (PairPos == End) {
+ Value *ZeroTbl = ConstantAggregateZero::get(TblTy);
+ TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
+ ZeroTbl, SV, Name));
+ }
+
+ TblTy = llvm::VectorType::get(TblTy->getElementType(),
+ 2*TblTy->getNumElements());
+ llvm::Type *Tys[2] = { ResTy, TblTy };
+
+ Function *TblF;
+ TblOps.push_back(IndexOp);
+ TblF = CGF.CGM.getIntrinsic(IntID, Tys);
+
+ return CGF.EmitNeonCall(TblF, TblOps, Name);
+}
+
+static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF,
+ unsigned BuiltinID,
+ const CallExpr *E) {
+ unsigned int Int = 0;
+ const char *s = NULL;
+
+ unsigned TblPos;
+ switch (BuiltinID) {
+ default:
+ return 0;
+ case AArch64::BI__builtin_neon_vtbl1_v:
+ case AArch64::BI__builtin_neon_vqtbl1_v:
+ case AArch64::BI__builtin_neon_vqtbl1q_v:
+ case AArch64::BI__builtin_neon_vtbl2_v:
+ case AArch64::BI__builtin_neon_vqtbl2_v:
+ case AArch64::BI__builtin_neon_vqtbl2q_v:
+ case AArch64::BI__builtin_neon_vtbl3_v:
+ case AArch64::BI__builtin_neon_vqtbl3_v:
+ case AArch64::BI__builtin_neon_vqtbl3q_v:
+ case AArch64::BI__builtin_neon_vtbl4_v:
+ case AArch64::BI__builtin_neon_vqtbl4_v:
+ case AArch64::BI__builtin_neon_vqtbl4q_v:
+ TblPos = 0;
+ break;
+ case AArch64::BI__builtin_neon_vtbx1_v:
+ case AArch64::BI__builtin_neon_vqtbx1_v:
+ case AArch64::BI__builtin_neon_vqtbx1q_v:
+ case AArch64::BI__builtin_neon_vtbx2_v:
+ case AArch64::BI__builtin_neon_vqtbx2_v:
+ case AArch64::BI__builtin_neon_vqtbx2q_v:
+ case AArch64::BI__builtin_neon_vtbx3_v:
+ case AArch64::BI__builtin_neon_vqtbx3_v:
+ case AArch64::BI__builtin_neon_vqtbx3q_v:
+ case AArch64::BI__builtin_neon_vtbx4_v:
+ case AArch64::BI__builtin_neon_vqtbx4_v:
+ case AArch64::BI__builtin_neon_vqtbx4q_v:
+ TblPos = 1;
+ break;
+ }
+
+ assert(E->getNumArgs() >= 3);
+
+ // Get the last argument, which specifies the vector type.
+ llvm::APSInt Result;
+ const Expr *Arg = E->getArg(E->getNumArgs() - 1);
+ if (!Arg->isIntegerConstantExpr(Result, CGF.getContext()))
+ return 0;
+
+ // Determine the type of this overloaded NEON intrinsic.
+ NeonTypeFlags Type(Result.getZExtValue());
+ llvm::VectorType *VTy = GetNeonType(&CGF, Type);
+ llvm::Type *Ty = VTy;
+ if (!Ty)
+ return 0;
+
+ SmallVector<Value *, 4> Ops;
+ for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
+ Ops.push_back(CGF.EmitScalarExpr(E->getArg(i)));
+ }
+
+ Arg = E->getArg(TblPos);
+ llvm::Type *TblTy = CGF.ConvertType(Arg->getType());
+ llvm::VectorType *VTblTy = cast<llvm::VectorType>(TblTy);
+ llvm::Type *Tys[2] = { Ty, VTblTy };
+ unsigned nElts = VTy->getNumElements();
+
+ // AArch64 scalar builtins are not overloaded, they do not have an extra
+ // argument that specifies the vector type, need to handle each case.
+ SmallVector<Value *, 2> TblOps;
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vtbl1_v: {
+ TblOps.push_back(Ops[0]);
+ return packTBLDVectorList(CGF, TblOps, 0, Ops[1], Ty,
+ Intrinsic::aarch64_neon_vtbl1, "vtbl1");
+ }
+ case AArch64::BI__builtin_neon_vtbl2_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ return packTBLDVectorList(CGF, TblOps, 0, Ops[2], Ty,
+ Intrinsic::aarch64_neon_vtbl1, "vtbl1");
+ }
+ case AArch64::BI__builtin_neon_vtbl3_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ return packTBLDVectorList(CGF, TblOps, 0, Ops[3], Ty,
+ Intrinsic::aarch64_neon_vtbl2, "vtbl2");
+ }
+ case AArch64::BI__builtin_neon_vtbl4_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ return packTBLDVectorList(CGF, TblOps, 0, Ops[4], Ty,
+ Intrinsic::aarch64_neon_vtbl2, "vtbl2");
+ }
+ case AArch64::BI__builtin_neon_vtbx1_v: {
+ TblOps.push_back(Ops[1]);
+ Value *TblRes = packTBLDVectorList(CGF, TblOps, 0, Ops[2], Ty,
+ Intrinsic::aarch64_neon_vtbl1, "vtbl1");
+
+ llvm::Constant *Eight = ConstantInt::get(VTy->getElementType(), 8);
+ Value* EightV = llvm::ConstantVector::getSplat(nElts, Eight);
+ Value *CmpRes = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[2], EightV);
+ CmpRes = CGF.Builder.CreateSExt(CmpRes, Ty);
+
+ SmallVector<Value *, 4> BslOps;
+ BslOps.push_back(CmpRes);
+ BslOps.push_back(Ops[0]);
+ BslOps.push_back(TblRes);
+ Function *BslF = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty);
+ return CGF.EmitNeonCall(BslF, BslOps, "vbsl");
+ }
+ case AArch64::BI__builtin_neon_vtbx2_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[3], Ty,
+ Intrinsic::aarch64_neon_vtbx1, "vtbx1");
+ }
+ case AArch64::BI__builtin_neon_vtbx3_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ Value *TblRes = packTBLDVectorList(CGF, TblOps, 0, Ops[4], Ty,
+ Intrinsic::aarch64_neon_vtbl2, "vtbl2");
+
+ llvm::Constant *TwentyFour = ConstantInt::get(VTy->getElementType(), 24);
+ Value* TwentyFourV = llvm::ConstantVector::getSplat(nElts, TwentyFour);
+ Value *CmpRes = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[4],
+ TwentyFourV);
+ CmpRes = CGF.Builder.CreateSExt(CmpRes, Ty);
+
+ SmallVector<Value *, 4> BslOps;
+ BslOps.push_back(CmpRes);
+ BslOps.push_back(Ops[0]);
+ BslOps.push_back(TblRes);
+ Function *BslF = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty);
+ return CGF.EmitNeonCall(BslF, BslOps, "vbsl");
+ }
+ case AArch64::BI__builtin_neon_vtbx4_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ TblOps.push_back(Ops[4]);
+ return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[5], Ty,
+ Intrinsic::aarch64_neon_vtbx2, "vtbx2");
+ }
+ case AArch64::BI__builtin_neon_vqtbl1_v:
+ case AArch64::BI__builtin_neon_vqtbl1q_v:
+ Int = Intrinsic::aarch64_neon_vtbl1; s = "vtbl1"; break;
+ case AArch64::BI__builtin_neon_vqtbl2_v:
+ case AArch64::BI__builtin_neon_vqtbl2q_v: {
+ Int = Intrinsic::aarch64_neon_vtbl2; s = "vtbl2"; break;
+ case AArch64::BI__builtin_neon_vqtbl3_v:
+ case AArch64::BI__builtin_neon_vqtbl3q_v:
+ Int = Intrinsic::aarch64_neon_vtbl3; s = "vtbl3"; break;
+ case AArch64::BI__builtin_neon_vqtbl4_v:
+ case AArch64::BI__builtin_neon_vqtbl4q_v:
+ Int = Intrinsic::aarch64_neon_vtbl4; s = "vtbl4"; break;
+ case AArch64::BI__builtin_neon_vqtbx1_v:
+ case AArch64::BI__builtin_neon_vqtbx1q_v:
+ Int = Intrinsic::aarch64_neon_vtbx1; s = "vtbx1"; break;
+ case AArch64::BI__builtin_neon_vqtbx2_v:
+ case AArch64::BI__builtin_neon_vqtbx2q_v:
+ Int = Intrinsic::aarch64_neon_vtbx2; s = "vtbx2"; break;
+ case AArch64::BI__builtin_neon_vqtbx3_v:
+ case AArch64::BI__builtin_neon_vqtbx3q_v:
+ Int = Intrinsic::aarch64_neon_vtbx3; s = "vtbx3"; break;
+ case AArch64::BI__builtin_neon_vqtbx4_v:
+ case AArch64::BI__builtin_neon_vqtbx4q_v:
+ Int = Intrinsic::aarch64_neon_vtbx4; s = "vtbx4"; break;
+ }
+ }
+
+ if (!Int)
+ return 0;
+
+ Function *F = CGF.CGM.getIntrinsic(Int, Tys);
+ return CGF.EmitNeonCall(F, Ops, s);
+}
+
Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
+ // Process AArch64 scalar builtins
+ if (Value *Result = EmitAArch64ScalarBuiltinExpr(*this, BuiltinID, E))
+ return Result;
+
+ // Process AArch64 table lookup builtins
+ if (Value *Result = EmitAArch64TblBuiltinExpr(*this, BuiltinID, E))
+ return Result;
+
if (BuiltinID == AArch64::BI__clear_cache) {
assert(E->getNumArgs() == 2 &&
"Variadic __clear_cache slipped through on AArch64");
@@ -1639,17 +2897,1039 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
- return 0;
+ SmallVector<Value *, 4> Ops;
+ llvm::Value *Align = 0; // Alignment for load/store
+ for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
+ if (i == 0) {
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vst1_x2_v:
+ case AArch64::BI__builtin_neon_vst1q_x2_v:
+ case AArch64::BI__builtin_neon_vst1_x3_v:
+ case AArch64::BI__builtin_neon_vst1q_x3_v:
+ case AArch64::BI__builtin_neon_vst1_x4_v:
+ case AArch64::BI__builtin_neon_vst1q_x4_v:
+ // Handle ld1/st1 lane in this function a little different from ARM.
+ case AArch64::BI__builtin_neon_vld1_lane_v:
+ case AArch64::BI__builtin_neon_vld1q_lane_v:
+ case AArch64::BI__builtin_neon_vst1_lane_v:
+ case AArch64::BI__builtin_neon_vst1q_lane_v:
+ // Get the alignment for the argument in addition to the value;
+ // we'll use it later.
+ std::pair<llvm::Value *, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(0));
+ Ops.push_back(Src.first);
+ Align = Builder.getInt32(Src.second);
+ continue;
+ }
+ }
+ if (i == 1) {
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vld1_x2_v:
+ case AArch64::BI__builtin_neon_vld1q_x2_v:
+ case AArch64::BI__builtin_neon_vld1_x3_v:
+ case AArch64::BI__builtin_neon_vld1q_x3_v:
+ case AArch64::BI__builtin_neon_vld1_x4_v:
+ case AArch64::BI__builtin_neon_vld1q_x4_v:
+ // Handle ld1/st1 dup lane in this function a little different from ARM.
+ case AArch64::BI__builtin_neon_vld2_dup_v:
+ case AArch64::BI__builtin_neon_vld2q_dup_v:
+ case AArch64::BI__builtin_neon_vld3_dup_v:
+ case AArch64::BI__builtin_neon_vld3q_dup_v:
+ case AArch64::BI__builtin_neon_vld4_dup_v:
+ case AArch64::BI__builtin_neon_vld4q_dup_v:
+ case AArch64::BI__builtin_neon_vld2_lane_v:
+ case AArch64::BI__builtin_neon_vld2q_lane_v:
+ // Get the alignment for the argument in addition to the value;
+ // we'll use it later.
+ std::pair<llvm::Value *, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
+ Ops.push_back(Src.first);
+ Align = Builder.getInt32(Src.second);
+ continue;
+ }
+ }
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+ }
+
+ // Get the last argument, which specifies the vector type.
+ llvm::APSInt Result;
+ const Expr *Arg = E->getArg(E->getNumArgs() - 1);
+ if (!Arg->isIntegerConstantExpr(Result, getContext()))
+ return 0;
+
+ // Determine the type of this overloaded NEON intrinsic.
+ NeonTypeFlags Type(Result.getZExtValue());
+ bool usgn = Type.isUnsigned();
+ bool quad = Type.isQuad();
+
+ llvm::VectorType *VTy = GetNeonType(this, Type);
+ llvm::Type *Ty = VTy;
+ if (!Ty)
+ return 0;
+
+ unsigned Int;
+ switch (BuiltinID) {
+ default:
+ return 0;
+
+ // AArch64 builtins mapping to legacy ARM v7 builtins.
+ // FIXME: the mapped builtins listed correspond to what has been tested
+ // in aarch64-neon-intrinsics.c so far.
+ case AArch64::BI__builtin_neon_vuzp_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vuzp_v, E);
+ case AArch64::BI__builtin_neon_vuzpq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vuzpq_v, E);
+ case AArch64::BI__builtin_neon_vzip_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vzip_v, E);
+ case AArch64::BI__builtin_neon_vzipq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vzipq_v, E);
+ case AArch64::BI__builtin_neon_vtrn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtrn_v, E);
+ case AArch64::BI__builtin_neon_vtrnq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtrnq_v, E);
+ case AArch64::BI__builtin_neon_vext_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vext_v, E);
+ case AArch64::BI__builtin_neon_vextq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vextq_v, E);
+ case AArch64::BI__builtin_neon_vmul_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmul_v, E);
+ case AArch64::BI__builtin_neon_vmulq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmulq_v, E);
+ case AArch64::BI__builtin_neon_vabd_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabd_v, E);
+ case AArch64::BI__builtin_neon_vabdq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabdq_v, E);
+ case AArch64::BI__builtin_neon_vfma_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vfma_v, E);
+ case AArch64::BI__builtin_neon_vfmaq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vfmaq_v, E);
+ case AArch64::BI__builtin_neon_vbsl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vbsl_v, E);
+ case AArch64::BI__builtin_neon_vbslq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vbslq_v, E);
+ case AArch64::BI__builtin_neon_vrsqrts_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrts_v, E);
+ case AArch64::BI__builtin_neon_vrsqrtsq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrtsq_v, E);
+ case AArch64::BI__builtin_neon_vrecps_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecps_v, E);
+ case AArch64::BI__builtin_neon_vrecpsq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecpsq_v, E);
+ case AArch64::BI__builtin_neon_vcale_v:
+ if (VTy->getVectorNumElements() == 1) {
+ std::swap(Ops[0], Ops[1]);
+ } else {
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcale_v, E);
+ }
+ case AArch64::BI__builtin_neon_vcage_v:
+ if (VTy->getVectorNumElements() == 1) {
+ // Determine the types of this overloaded AArch64 intrinsic
+ SmallVector<llvm::Type *, 3> Tys;
+ Tys.push_back(VTy);
+ VTy = llvm::VectorType::get(DoubleTy, 1);
+ Tys.push_back(VTy);
+ Tys.push_back(VTy);
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vcage, Tys);
+ return EmitNeonCall(F, Ops, "vcage");
+ }
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcage_v, E);
+ case AArch64::BI__builtin_neon_vcaleq_v:
+ std::swap(Ops[0], Ops[1]);
+ case AArch64::BI__builtin_neon_vcageq_v: {
+ Function *F;
+ if (VTy->getElementType()->isIntegerTy(64))
+ F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vacgeq);
+ else
+ F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgeq);
+ return EmitNeonCall(F, Ops, "vcage");
+ }
+ case AArch64::BI__builtin_neon_vcalt_v:
+ if (VTy->getVectorNumElements() == 1) {
+ std::swap(Ops[0], Ops[1]);
+ } else {
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcalt_v, E);
+ }
+ case AArch64::BI__builtin_neon_vcagt_v:
+ if (VTy->getVectorNumElements() == 1) {
+ // Determine the types of this overloaded AArch64 intrinsic
+ SmallVector<llvm::Type *, 3> Tys;
+ Tys.push_back(VTy);
+ VTy = llvm::VectorType::get(DoubleTy, 1);
+ Tys.push_back(VTy);
+ Tys.push_back(VTy);
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vcagt, Tys);
+ return EmitNeonCall(F, Ops, "vcagt");
+ }
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcagt_v, E);
+ case AArch64::BI__builtin_neon_vcaltq_v:
+ std::swap(Ops[0], Ops[1]);
+ case AArch64::BI__builtin_neon_vcagtq_v: {
+ Function *F;
+ if (VTy->getElementType()->isIntegerTy(64))
+ F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vacgtq);
+ else
+ F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgtq);
+ return EmitNeonCall(F, Ops, "vcagt");
+ }
+ case AArch64::BI__builtin_neon_vtst_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtst_v, E);
+ case AArch64::BI__builtin_neon_vtstq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtstq_v, E);
+ case AArch64::BI__builtin_neon_vhadd_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhadd_v, E);
+ case AArch64::BI__builtin_neon_vhaddq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhaddq_v, E);
+ case AArch64::BI__builtin_neon_vhsub_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhsub_v, E);
+ case AArch64::BI__builtin_neon_vhsubq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhsubq_v, E);
+ case AArch64::BI__builtin_neon_vrhadd_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrhadd_v, E);
+ case AArch64::BI__builtin_neon_vrhaddq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrhaddq_v, E);
+ case AArch64::BI__builtin_neon_vqadd_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqadd_v, E);
+ case AArch64::BI__builtin_neon_vqaddq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqaddq_v, E);
+ case AArch64::BI__builtin_neon_vqsub_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqsub_v, E);
+ case AArch64::BI__builtin_neon_vqsubq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqsubq_v, E);
+ case AArch64::BI__builtin_neon_vshl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshl_v, E);
+ case AArch64::BI__builtin_neon_vshlq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshlq_v, E);
+ case AArch64::BI__builtin_neon_vqshl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshl_v, E);
+ case AArch64::BI__builtin_neon_vqshlq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshlq_v, E);
+ case AArch64::BI__builtin_neon_vrshl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrshl_v, E);
+ case AArch64::BI__builtin_neon_vrshlq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrshlq_v, E);
+ case AArch64::BI__builtin_neon_vqrshl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrshl_v, E);
+ case AArch64::BI__builtin_neon_vqrshlq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrshlq_v, E);
+ case AArch64::BI__builtin_neon_vaddhn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vaddhn_v, E);
+ case AArch64::BI__builtin_neon_vraddhn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vraddhn_v, E);
+ case AArch64::BI__builtin_neon_vsubhn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsubhn_v, E);
+ case AArch64::BI__builtin_neon_vrsubhn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsubhn_v, E);
+ case AArch64::BI__builtin_neon_vmull_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmull_v, E);
+ case AArch64::BI__builtin_neon_vqdmull_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmull_v, E);
+ case AArch64::BI__builtin_neon_vqdmlal_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmlal_v, E);
+ case AArch64::BI__builtin_neon_vqdmlsl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmlsl_v, E);
+ case AArch64::BI__builtin_neon_vmax_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmax_v, E);
+ case AArch64::BI__builtin_neon_vmaxq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmaxq_v, E);
+ case AArch64::BI__builtin_neon_vmin_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmin_v, E);
+ case AArch64::BI__builtin_neon_vminq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vminq_v, E);
+ case AArch64::BI__builtin_neon_vpmax_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpmax_v, E);
+ case AArch64::BI__builtin_neon_vpmin_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpmin_v, E);
+ case AArch64::BI__builtin_neon_vpadd_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpadd_v, E);
+ case AArch64::BI__builtin_neon_vqdmulh_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmulh_v, E);
+ case AArch64::BI__builtin_neon_vqdmulhq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmulhq_v, E);
+ case AArch64::BI__builtin_neon_vqrdmulh_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrdmulh_v, E);
+ case AArch64::BI__builtin_neon_vqrdmulhq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrdmulhq_v, E);
+
+ // Shift by immediate
+ case AArch64::BI__builtin_neon_vshr_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshr_n_v, E);
+ case AArch64::BI__builtin_neon_vshrq_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshrq_n_v, E);
+ case AArch64::BI__builtin_neon_vrshr_n_v:
+ case AArch64::BI__builtin_neon_vrshrq_n_v:
+ Int = usgn ? Intrinsic::aarch64_neon_vurshr
+ : Intrinsic::aarch64_neon_vsrshr;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n");
+ case AArch64::BI__builtin_neon_vsra_n_v:
+ if (VTy->getElementType()->isIntegerTy(64)) {
+ Int = usgn ? Intrinsic::aarch64_neon_vsradu_n
+ : Intrinsic::aarch64_neon_vsrads_n;
+ return EmitNeonCall(CGM.getIntrinsic(Int), Ops, "vsra_n");
+ }
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsra_n_v, E);
+ case AArch64::BI__builtin_neon_vsraq_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsraq_n_v, E);
+ case AArch64::BI__builtin_neon_vrsra_n_v:
+ if (VTy->getElementType()->isIntegerTy(64)) {
+ Int = usgn ? Intrinsic::aarch64_neon_vrsradu_n
+ : Intrinsic::aarch64_neon_vrsrads_n;
+ return EmitNeonCall(CGM.getIntrinsic(Int), Ops, "vrsra_n");
+ }
+ // fall through
+ case AArch64::BI__builtin_neon_vrsraq_n_v: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Int = usgn ? Intrinsic::aarch64_neon_vurshr
+ : Intrinsic::aarch64_neon_vsrshr;
+ Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
+ return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
+ }
+ case AArch64::BI__builtin_neon_vshl_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshl_n_v, E);
+ case AArch64::BI__builtin_neon_vshlq_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshlq_n_v, E);
+ case AArch64::BI__builtin_neon_vqshl_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshl_n_v, E);
+ case AArch64::BI__builtin_neon_vqshlq_n_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshlq_n_v, E);
+ case AArch64::BI__builtin_neon_vqshlu_n_v:
+ case AArch64::BI__builtin_neon_vqshluq_n_v:
+ Int = Intrinsic::aarch64_neon_vsqshlu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n");
+ case AArch64::BI__builtin_neon_vsri_n_v:
+ case AArch64::BI__builtin_neon_vsriq_n_v:
+ Int = Intrinsic::aarch64_neon_vsri;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsri_n");
+ case AArch64::BI__builtin_neon_vsli_n_v:
+ case AArch64::BI__builtin_neon_vsliq_n_v:
+ Int = Intrinsic::aarch64_neon_vsli;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsli_n");
+ case AArch64::BI__builtin_neon_vshll_n_v: {
+ llvm::Type *SrcTy = llvm::VectorType::getTruncatedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ if (usgn)
+ Ops[0] = Builder.CreateZExt(Ops[0], VTy);
+ else
+ Ops[0] = Builder.CreateSExt(Ops[0], VTy);
+ Ops[1] = EmitNeonShiftVector(Ops[1], VTy, false);
+ return Builder.CreateShl(Ops[0], Ops[1], "vshll_n");
+ }
+ case AArch64::BI__builtin_neon_vshrn_n_v: {
+ llvm::Type *SrcTy = llvm::VectorType::getExtendedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = EmitNeonShiftVector(Ops[1], SrcTy, false);
+ if (usgn)
+ Ops[0] = Builder.CreateLShr(Ops[0], Ops[1]);
+ else
+ Ops[0] = Builder.CreateAShr(Ops[0], Ops[1]);
+ return Builder.CreateTrunc(Ops[0], Ty, "vshrn_n");
+ }
+ case AArch64::BI__builtin_neon_vqshrun_n_v:
+ Int = Intrinsic::aarch64_neon_vsqshrun;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrun_n");
+ case AArch64::BI__builtin_neon_vrshrn_n_v:
+ Int = Intrinsic::aarch64_neon_vrshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshrn_n");
+ case AArch64::BI__builtin_neon_vqrshrun_n_v:
+ Int = Intrinsic::aarch64_neon_vsqrshrun;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrun_n");
+ case AArch64::BI__builtin_neon_vqshrn_n_v:
+ Int = usgn ? Intrinsic::aarch64_neon_vuqshrn
+ : Intrinsic::aarch64_neon_vsqshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n");
+ case AArch64::BI__builtin_neon_vqrshrn_n_v:
+ Int = usgn ? Intrinsic::aarch64_neon_vuqrshrn
+ : Intrinsic::aarch64_neon_vsqrshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n");
+
+ // Convert
+ case AArch64::BI__builtin_neon_vmovl_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmovl_v, E);
+ case AArch64::BI__builtin_neon_vcvt_n_f32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_f32_v, E);
+ case AArch64::BI__builtin_neon_vcvtq_n_f32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_f32_v, E);
+ case AArch64::BI__builtin_neon_vcvt_n_f64_v:
+ case AArch64::BI__builtin_neon_vcvtq_n_f64_v: {
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ llvm::Type *Tys[2] = { FloatTy, Ty };
+ Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp
+ : Intrinsic::arm_neon_vcvtfxs2fp;
+ Function *F = CGM.getIntrinsic(Int, Tys);
+ return EmitNeonCall(F, Ops, "vcvt_n");
+ }
+ case AArch64::BI__builtin_neon_vcvt_n_s32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_s32_v, E);
+ case AArch64::BI__builtin_neon_vcvtq_n_s32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_s32_v, E);
+ case AArch64::BI__builtin_neon_vcvt_n_u32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_u32_v, E);
+ case AArch64::BI__builtin_neon_vcvtq_n_u32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_u32_v, E);
+ case AArch64::BI__builtin_neon_vcvt_n_s64_v:
+ case AArch64::BI__builtin_neon_vcvt_n_u64_v:
+ case AArch64::BI__builtin_neon_vcvtq_n_s64_v:
+ case AArch64::BI__builtin_neon_vcvtq_n_u64_v: {
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ llvm::Type *Tys[2] = { Ty, FloatTy };
+ Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu
+ : Intrinsic::arm_neon_vcvtfp2fxs;
+ Function *F = CGM.getIntrinsic(Int, Tys);
+ return EmitNeonCall(F, Ops, "vcvt_n");
+ }
+
+ // Load/Store
+ case AArch64::BI__builtin_neon_vld1_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1_v, E);
+ case AArch64::BI__builtin_neon_vld1q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1q_v, E);
+ case AArch64::BI__builtin_neon_vld2_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2_v, E);
+ case AArch64::BI__builtin_neon_vld2q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_v, E);
+ case AArch64::BI__builtin_neon_vld3_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3_v, E);
+ case AArch64::BI__builtin_neon_vld3q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3q_v, E);
+ case AArch64::BI__builtin_neon_vld4_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4_v, E);
+ case AArch64::BI__builtin_neon_vld4q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4q_v, E);
+ case AArch64::BI__builtin_neon_vst1_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst1_v, E);
+ case AArch64::BI__builtin_neon_vst1q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst1q_v, E);
+ case AArch64::BI__builtin_neon_vst2_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2_v, E);
+ case AArch64::BI__builtin_neon_vst2q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2q_v, E);
+ case AArch64::BI__builtin_neon_vst3_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3_v, E);
+ case AArch64::BI__builtin_neon_vst3q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3q_v, E);
+ case AArch64::BI__builtin_neon_vst4_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4_v, E);
+ case AArch64::BI__builtin_neon_vst4q_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4q_v, E);
+ case AArch64::BI__builtin_neon_vld1_x2_v:
+ case AArch64::BI__builtin_neon_vld1q_x2_v:
+ case AArch64::BI__builtin_neon_vld1_x3_v:
+ case AArch64::BI__builtin_neon_vld1q_x3_v:
+ case AArch64::BI__builtin_neon_vld1_x4_v:
+ case AArch64::BI__builtin_neon_vld1q_x4_v: {
+ unsigned Int;
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vld1_x2_v:
+ case AArch64::BI__builtin_neon_vld1q_x2_v:
+ Int = Intrinsic::aarch64_neon_vld1x2;
+ break;
+ case AArch64::BI__builtin_neon_vld1_x3_v:
+ case AArch64::BI__builtin_neon_vld1q_x3_v:
+ Int = Intrinsic::aarch64_neon_vld1x3;
+ break;
+ case AArch64::BI__builtin_neon_vld1_x4_v:
+ case AArch64::BI__builtin_neon_vld1q_x4_v:
+ Int = Intrinsic::aarch64_neon_vld1x4;
+ break;
+ }
+ Function *F = CGM.getIntrinsic(Int, Ty);
+ Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld1xN");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vst1_x2_v:
+ case AArch64::BI__builtin_neon_vst1q_x2_v:
+ case AArch64::BI__builtin_neon_vst1_x3_v:
+ case AArch64::BI__builtin_neon_vst1q_x3_v:
+ case AArch64::BI__builtin_neon_vst1_x4_v:
+ case AArch64::BI__builtin_neon_vst1q_x4_v: {
+ Ops.push_back(Align);
+ unsigned Int;
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vst1_x2_v:
+ case AArch64::BI__builtin_neon_vst1q_x2_v:
+ Int = Intrinsic::aarch64_neon_vst1x2;
+ break;
+ case AArch64::BI__builtin_neon_vst1_x3_v:
+ case AArch64::BI__builtin_neon_vst1q_x3_v:
+ Int = Intrinsic::aarch64_neon_vst1x3;
+ break;
+ case AArch64::BI__builtin_neon_vst1_x4_v:
+ case AArch64::BI__builtin_neon_vst1q_x4_v:
+ Int = Intrinsic::aarch64_neon_vst1x4;
+ break;
+ }
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "");
+ }
+ case AArch64::BI__builtin_neon_vld1_lane_v:
+ case AArch64::BI__builtin_neon_vld1q_lane_v: {
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ty = llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ LoadInst *Ld = Builder.CreateLoad(Ops[0]);
+ Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
+ return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
+ }
+ case AArch64::BI__builtin_neon_vld2_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_lane_v, E);
+ case AArch64::BI__builtin_neon_vld2q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_lane_v, E);
+ case AArch64::BI__builtin_neon_vld3_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3_lane_v, E);
+ case AArch64::BI__builtin_neon_vld3q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3q_lane_v, E);
+ case AArch64::BI__builtin_neon_vld4_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4_lane_v, E);
+ case AArch64::BI__builtin_neon_vld4q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4q_lane_v, E);
+ case AArch64::BI__builtin_neon_vst1_lane_v:
+ case AArch64::BI__builtin_neon_vst1q_lane_v: {
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ StoreInst *St =
+ Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty));
+ St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
+ return St;
+ }
+ case AArch64::BI__builtin_neon_vst2_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2_lane_v, E);
+ case AArch64::BI__builtin_neon_vst2q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2q_lane_v, E);
+ case AArch64::BI__builtin_neon_vst3_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3_lane_v, E);
+ case AArch64::BI__builtin_neon_vst3q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3q_lane_v, E);
+ case AArch64::BI__builtin_neon_vst4_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4_lane_v, E);
+ case AArch64::BI__builtin_neon_vst4q_lane_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4q_lane_v, E);
+ case AArch64::BI__builtin_neon_vld1_dup_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1_dup_v, E);
+ case AArch64::BI__builtin_neon_vld1q_dup_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1q_dup_v, E);
+ case AArch64::BI__builtin_neon_vld2_dup_v:
+ case AArch64::BI__builtin_neon_vld2q_dup_v:
+ case AArch64::BI__builtin_neon_vld3_dup_v:
+ case AArch64::BI__builtin_neon_vld3q_dup_v:
+ case AArch64::BI__builtin_neon_vld4_dup_v:
+ case AArch64::BI__builtin_neon_vld4q_dup_v: {
+ // Handle 64-bit x 1 elements as a special-case. There is no "dup" needed.
+ if (VTy->getElementType()->getPrimitiveSizeInBits() == 64 &&
+ VTy->getNumElements() == 1) {
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vld2_dup_v:
+ Int = Intrinsic::arm_neon_vld2;
+ break;
+ case AArch64::BI__builtin_neon_vld3_dup_v:
+ Int = Intrinsic::arm_neon_vld3;
+ break;
+ case AArch64::BI__builtin_neon_vld4_dup_v:
+ Int = Intrinsic::arm_neon_vld4;
+ break;
+ default:
+ llvm_unreachable("unknown vld_dup intrinsic?");
+ }
+ Function *F = CGM.getIntrinsic(Int, Ty);
+ Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_neon_vld2_dup_v:
+ case AArch64::BI__builtin_neon_vld2q_dup_v:
+ Int = Intrinsic::arm_neon_vld2lane;
+ break;
+ case AArch64::BI__builtin_neon_vld3_dup_v:
+ case AArch64::BI__builtin_neon_vld3q_dup_v:
+ Int = Intrinsic::arm_neon_vld3lane;
+ break;
+ case AArch64::BI__builtin_neon_vld4_dup_v:
+ case AArch64::BI__builtin_neon_vld4q_dup_v:
+ Int = Intrinsic::arm_neon_vld4lane;
+ break;
+ }
+ Function *F = CGM.getIntrinsic(Int, Ty);
+ llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
+
+ SmallVector<Value *, 6> Args;
+ Args.push_back(Ops[1]);
+ Args.append(STy->getNumElements(), UndefValue::get(Ty));
+
+ llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
+ Args.push_back(CI);
+ Args.push_back(Align);
+
+ Ops[1] = Builder.CreateCall(F, Args, "vld_dup");
+ // splat lane 0 to all elts in each vector of the result.
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ Value *Val = Builder.CreateExtractValue(Ops[1], i);
+ Value *Elt = Builder.CreateBitCast(Val, Ty);
+ Elt = EmitNeonSplat(Elt, CI);
+ Elt = Builder.CreateBitCast(Elt, Val->getType());
+ Ops[1] = Builder.CreateInsertValue(Ops[1], Elt, i);
+ }
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+
+ // Crypto
+ case AArch64::BI__builtin_neon_vaeseq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aese, Ty),
+ Ops, "aese");
+ case AArch64::BI__builtin_neon_vaesdq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesd, Ty),
+ Ops, "aesd");
+ case AArch64::BI__builtin_neon_vaesmcq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesmc, Ty),
+ Ops, "aesmc");
+ case AArch64::BI__builtin_neon_vaesimcq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesimc, Ty),
+ Ops, "aesimc");
+ case AArch64::BI__builtin_neon_vsha1su1q_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1su1, Ty),
+ Ops, "sha1su1");
+ case AArch64::BI__builtin_neon_vsha256su0q_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256su0, Ty),
+ Ops, "sha256su0");
+ case AArch64::BI__builtin_neon_vsha1su0q_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1su0, Ty),
+ Ops, "sha1su0");
+ case AArch64::BI__builtin_neon_vsha256hq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256h, Ty),
+ Ops, "sha256h");
+ case AArch64::BI__builtin_neon_vsha256h2q_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256h2, Ty),
+ Ops, "sha256h2");
+ case AArch64::BI__builtin_neon_vsha256su1q_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256su1, Ty),
+ Ops, "sha256su1");
+ case AArch64::BI__builtin_neon_vmul_lane_v:
+ case AArch64::BI__builtin_neon_vmul_laneq_v: {
+ // v1f64 vmul_lane should be mapped to Neon scalar mul lane
+ bool Quad = false;
+ if (BuiltinID == AArch64::BI__builtin_neon_vmul_laneq_v)
+ Quad = true;
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ llvm::Type *VTy = GetNeonType(this,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, Quad));
+ Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2], "extract");
+ Value *Result = Builder.CreateFMul(Ops[0], Ops[1]);
+ return Builder.CreateBitCast(Result, Ty);
+ }
+
+ // AArch64-only builtins
+ case AArch64::BI__builtin_neon_vfmaq_laneq_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vfmaq_lane_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
+ VTy->getNumElements() / 2);
+ Ops[2] = Builder.CreateBitCast(Ops[2], STy);
+ Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
+ cast<ConstantInt>(Ops[3]));
+ Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
+
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vfma_lane_v: {
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ // v1f64 fma should be mapped to Neon scalar f64 fma
+ if (VTy && VTy->getElementType() == DoubleTy) {
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
+ llvm::Type *VTy = GetNeonType(this,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, false));
+ Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
+ Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
+ Value *Result = Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ return Builder.CreateBitCast(Result, Ty);
+ }
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vfma_laneq_v: {
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ // v1f64 fma should be mapped to Neon scalar f64 fma
+ if (VTy && VTy->getElementType() == DoubleTy) {
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
+ llvm::Type *VTy = GetNeonType(this,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, true));
+ Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
+ Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
+ Value *Result = Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ return Builder.CreateBitCast(Result, Ty);
+ }
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
+ VTy->getNumElements() * 2);
+ Ops[2] = Builder.CreateBitCast(Ops[2], STy);
+ Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
+ cast<ConstantInt>(Ops[3]));
+ Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
+
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vfms_v:
+ case AArch64::BI__builtin_neon_vfmsq_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[1] = Builder.CreateFNeg(Ops[1]);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+
+ // LLVM's fma intrinsic puts the accumulator in the last position, but the
+ // AArch64 intrinsic has it first.
+ return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ }
+ case AArch64::BI__builtin_neon_vmaxnm_v:
+ case AArch64::BI__builtin_neon_vmaxnmq_v: {
+ Int = Intrinsic::aarch64_neon_vmaxnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmaxnm");
+ }
+ case AArch64::BI__builtin_neon_vminnm_v:
+ case AArch64::BI__builtin_neon_vminnmq_v: {
+ Int = Intrinsic::aarch64_neon_vminnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vminnm");
+ }
+ case AArch64::BI__builtin_neon_vpmaxnm_v:
+ case AArch64::BI__builtin_neon_vpmaxnmq_v: {
+ Int = Intrinsic::aarch64_neon_vpmaxnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmaxnm");
+ }
+ case AArch64::BI__builtin_neon_vpminnm_v:
+ case AArch64::BI__builtin_neon_vpminnmq_v: {
+ Int = Intrinsic::aarch64_neon_vpminnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpminnm");
+ }
+ case AArch64::BI__builtin_neon_vpmaxq_v: {
+ Int = usgn ? Intrinsic::arm_neon_vpmaxu : Intrinsic::arm_neon_vpmaxs;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmax");
+ }
+ case AArch64::BI__builtin_neon_vpminq_v: {
+ Int = usgn ? Intrinsic::arm_neon_vpminu : Intrinsic::arm_neon_vpmins;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmin");
+ }
+ case AArch64::BI__builtin_neon_vpaddq_v: {
+ Int = Intrinsic::arm_neon_vpadd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpadd");
+ }
+ case AArch64::BI__builtin_neon_vmulx_v:
+ case AArch64::BI__builtin_neon_vmulxq_v: {
+ Int = Intrinsic::aarch64_neon_vmulx;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
+ }
+ case AArch64::BI__builtin_neon_vpaddl_v:
+ case AArch64::BI__builtin_neon_vpaddlq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpaddl_v, E);
+ case AArch64::BI__builtin_neon_vpadal_v:
+ case AArch64::BI__builtin_neon_vpadalq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpadal_v, E);
+ case AArch64::BI__builtin_neon_vqabs_v:
+ case AArch64::BI__builtin_neon_vqabsq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqabs_v, E);
+ case AArch64::BI__builtin_neon_vqneg_v:
+ case AArch64::BI__builtin_neon_vqnegq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqneg_v, E);
+ case AArch64::BI__builtin_neon_vabs_v:
+ case AArch64::BI__builtin_neon_vabsq_v: {
+ if (VTy->getElementType()->isFloatingPointTy()) {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::fabs, Ty), Ops, "vabs");
+ }
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabs_v, E);
+ }
+ case AArch64::BI__builtin_neon_vsqadd_v:
+ case AArch64::BI__builtin_neon_vsqaddq_v: {
+ Int = Intrinsic::aarch64_neon_usqadd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqadd");
+ }
+ case AArch64::BI__builtin_neon_vuqadd_v:
+ case AArch64::BI__builtin_neon_vuqaddq_v: {
+ Int = Intrinsic::aarch64_neon_suqadd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
+ }
+ case AArch64::BI__builtin_neon_vcls_v:
+ case AArch64::BI__builtin_neon_vclsq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcls_v, E);
+ case AArch64::BI__builtin_neon_vclz_v:
+ case AArch64::BI__builtin_neon_vclzq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vclz_v, E);
+ case AArch64::BI__builtin_neon_vcnt_v:
+ case AArch64::BI__builtin_neon_vcntq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcnt_v, E);
+ case AArch64::BI__builtin_neon_vrbit_v:
+ case AArch64::BI__builtin_neon_vrbitq_v:
+ Int = Intrinsic::aarch64_neon_rbit;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrbit");
+ case AArch64::BI__builtin_neon_vmovn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmovn_v, E);
+ case AArch64::BI__builtin_neon_vqmovun_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqmovun_v, E);
+ case AArch64::BI__builtin_neon_vqmovn_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqmovn_v, E);
+ case AArch64::BI__builtin_neon_vcvt_f16_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f16_v, E);
+ case AArch64::BI__builtin_neon_vcvt_f32_f16:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f32_f16, E);
+ case AArch64::BI__builtin_neon_vcvt_f32_f64: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, false));
+ return Builder.CreateFPTrunc(Ops[0], Ty, "vcvt");
+ }
+ case AArch64::BI__builtin_neon_vcvtx_f32_v: {
+ llvm::Type *EltTy = FloatTy;
+ llvm::Type *ResTy = llvm::VectorType::get(EltTy, 2);
+ llvm::Type *Tys[2] = { ResTy, Ty };
+ Int = Intrinsic::aarch64_neon_fcvtxn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtx_f32_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvt_f64_f32: {
+ llvm::Type *OpTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, false));
+ Ops[0] = Builder.CreateBitCast(Ops[0], OpTy);
+ return Builder.CreateFPExt(Ops[0], Ty, "vcvt");
+ }
+ case AArch64::BI__builtin_neon_vcvt_f64_v:
+ case AArch64::BI__builtin_neon_vcvtq_f64_v: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
+ : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
+ }
+ case AArch64::BI__builtin_neon_vrndn_v:
+ case AArch64::BI__builtin_neon_vrndnq_v: {
+ Int = Intrinsic::aarch64_neon_frintn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndn");
+ }
+ case AArch64::BI__builtin_neon_vrnda_v:
+ case AArch64::BI__builtin_neon_vrndaq_v: {
+ Int = Intrinsic::round;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnda");
+ }
+ case AArch64::BI__builtin_neon_vrndp_v:
+ case AArch64::BI__builtin_neon_vrndpq_v: {
+ Int = Intrinsic::ceil;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndp");
+ }
+ case AArch64::BI__builtin_neon_vrndm_v:
+ case AArch64::BI__builtin_neon_vrndmq_v: {
+ Int = Intrinsic::floor;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndm");
+ }
+ case AArch64::BI__builtin_neon_vrndx_v:
+ case AArch64::BI__builtin_neon_vrndxq_v: {
+ Int = Intrinsic::rint;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndx");
+ }
+ case AArch64::BI__builtin_neon_vrnd_v:
+ case AArch64::BI__builtin_neon_vrndq_v: {
+ Int = Intrinsic::trunc;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd");
+ }
+ case AArch64::BI__builtin_neon_vrndi_v:
+ case AArch64::BI__builtin_neon_vrndiq_v: {
+ Int = Intrinsic::nearbyint;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndi");
+ }
+ case AArch64::BI__builtin_neon_vcvt_s32_v:
+ case AArch64::BI__builtin_neon_vcvt_u32_v:
+ case AArch64::BI__builtin_neon_vcvtq_s32_v:
+ case AArch64::BI__builtin_neon_vcvtq_u32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_u32_v, E);
+ case AArch64::BI__builtin_neon_vcvt_s64_v:
+ case AArch64::BI__builtin_neon_vcvt_u64_v:
+ case AArch64::BI__builtin_neon_vcvtq_s64_v:
+ case AArch64::BI__builtin_neon_vcvtq_u64_v: {
+ llvm::Type *DoubleTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
+ : Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
+ }
+ case AArch64::BI__builtin_neon_vcvtn_s32_v:
+ case AArch64::BI__builtin_neon_vcvtnq_s32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtns;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtns_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtn_s64_v:
+ case AArch64::BI__builtin_neon_vcvtnq_s64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtns;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtns_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvtn_u32_v:
+ case AArch64::BI__builtin_neon_vcvtnq_u32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtnu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtnu_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtn_u64_v:
+ case AArch64::BI__builtin_neon_vcvtnq_u64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtnu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtnu_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvtp_s32_v:
+ case AArch64::BI__builtin_neon_vcvtpq_s32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtps;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtps_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtp_s64_v:
+ case AArch64::BI__builtin_neon_vcvtpq_s64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtps;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtps_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvtp_u32_v:
+ case AArch64::BI__builtin_neon_vcvtpq_u32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtpu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtpu_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtp_u64_v:
+ case AArch64::BI__builtin_neon_vcvtpq_u64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtpu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtpu_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvtm_s32_v:
+ case AArch64::BI__builtin_neon_vcvtmq_s32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtms;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtms_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtm_s64_v:
+ case AArch64::BI__builtin_neon_vcvtmq_s64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtms;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtms_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvtm_u32_v:
+ case AArch64::BI__builtin_neon_vcvtmq_u32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtmu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtmu_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvtm_u64_v:
+ case AArch64::BI__builtin_neon_vcvtmq_u64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtmu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtmu_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvta_s32_v:
+ case AArch64::BI__builtin_neon_vcvtaq_s32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtas;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtas_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvta_s64_v:
+ case AArch64::BI__builtin_neon_vcvtaq_s64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtas;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtas_f64");
+ }
+ case AArch64::BI__builtin_neon_vcvta_u32_v:
+ case AArch64::BI__builtin_neon_vcvtaq_u32_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtau;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtau_f32");
+ }
+ case AArch64::BI__builtin_neon_vcvta_u64_v:
+ case AArch64::BI__builtin_neon_vcvtaq_u64_v: {
+ llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
+ llvm::Type *Tys[2] = { Ty, OpTy };
+ Int = Intrinsic::aarch64_neon_fcvtau;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtau_f64");
+ }
+ case AArch64::BI__builtin_neon_vrecpe_v:
+ case AArch64::BI__builtin_neon_vrecpeq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecpe_v, E);
+ case AArch64::BI__builtin_neon_vrsqrte_v:
+ case AArch64::BI__builtin_neon_vrsqrteq_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrte_v, E);
+ case AArch64::BI__builtin_neon_vsqrt_v:
+ case AArch64::BI__builtin_neon_vsqrtq_v: {
+ Int = Intrinsic::sqrt;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqrt");
+ }
+ case AArch64::BI__builtin_neon_vcvt_f32_v:
+ case AArch64::BI__builtin_neon_vcvtq_f32_v:
+ return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f32_v, E);
+ case AArch64::BI__builtin_neon_vceqz_v:
+ case AArch64::BI__builtin_neon_vceqzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OEQ,
+ ICmpInst::ICMP_EQ, "vceqz");
+ case AArch64::BI__builtin_neon_vcgez_v:
+ case AArch64::BI__builtin_neon_vcgezq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGE,
+ ICmpInst::ICMP_SGE, "vcgez");
+ case AArch64::BI__builtin_neon_vclez_v:
+ case AArch64::BI__builtin_neon_vclezq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLE,
+ ICmpInst::ICMP_SLE, "vclez");
+ case AArch64::BI__builtin_neon_vcgtz_v:
+ case AArch64::BI__builtin_neon_vcgtzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGT,
+ ICmpInst::ICMP_SGT, "vcgtz");
+ case AArch64::BI__builtin_neon_vcltz_v:
+ case AArch64::BI__builtin_neon_vcltzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLT,
+ ICmpInst::ICMP_SLT, "vcltz");
+ }
}
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == ARM::BI__clear_cache) {
+ assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
const FunctionDecl *FD = E->getDirectCallee();
- // Oddly people write this call without args on occasion and gcc accepts
- // it - it's also marked as varargs in the description file.
SmallVector<Value*, 2> Ops;
- for (unsigned i = 0; i < E->getNumArgs(); i++)
+ for (unsigned i = 0; i < 2; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
@@ -1657,11 +3937,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
- if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
+ if (BuiltinID == ARM::BI__builtin_arm_ldrexd ||
+ (BuiltinID == ARM::BI__builtin_arm_ldrex &&
+ getContext().getTypeSize(E->getType()) == 64)) {
Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
Value *LdPtr = EmitScalarExpr(E->getArg(0));
- Value *Val = Builder.CreateCall(F, LdPtr, "ldrexd");
+ Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
+ "ldrexd");
Value *Val0 = Builder.CreateExtractValue(Val, 1);
Value *Val1 = Builder.CreateExtractValue(Val, 0);
@@ -1670,15 +3953,37 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Value *ShiftCst = llvm::ConstantInt::get(Int64Ty, 32);
Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
- return Builder.CreateOr(Val, Val1);
+ Val = Builder.CreateOr(Val, Val1);
+ return Builder.CreateBitCast(Val, ConvertType(E->getType()));
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_ldrex) {
+ Value *LoadAddr = EmitScalarExpr(E->getArg(0));
+
+ QualType Ty = E->getType();
+ llvm::Type *RealResTy = ConvertType(Ty);
+ llvm::Type *IntResTy = llvm::IntegerType::get(getLLVMContext(),
+ getContext().getTypeSize(Ty));
+ LoadAddr = Builder.CreateBitCast(LoadAddr, IntResTy->getPointerTo());
+
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrex, LoadAddr->getType());
+ Value *Val = Builder.CreateCall(F, LoadAddr, "ldrex");
+
+ if (RealResTy->isPointerTy())
+ return Builder.CreateIntToPtr(Val, RealResTy);
+ else {
+ Val = Builder.CreateTruncOrBitCast(Val, IntResTy);
+ return Builder.CreateBitCast(Val, RealResTy);
+ }
}
- if (BuiltinID == ARM::BI__builtin_arm_strexd) {
+ if (BuiltinID == ARM::BI__builtin_arm_strexd ||
+ (BuiltinID == ARM::BI__builtin_arm_strex &&
+ getContext().getTypeSize(E->getArg(0)->getType()) == 64)) {
Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
- Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int64Ty, One);
+ Value *Tmp = CreateMemTemp(E->getArg(0)->getType());
Value *Val = EmitScalarExpr(E->getArg(0));
Builder.CreateStore(Val, Tmp);
@@ -1687,10 +3992,83 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Value *Arg0 = Builder.CreateExtractValue(Val, 0);
Value *Arg1 = Builder.CreateExtractValue(Val, 1);
- Value *StPtr = EmitScalarExpr(E->getArg(1));
+ Value *StPtr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), Int8PtrTy);
return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
}
+ if (BuiltinID == ARM::BI__builtin_arm_strex) {
+ Value *StoreVal = EmitScalarExpr(E->getArg(0));
+ Value *StoreAddr = EmitScalarExpr(E->getArg(1));
+
+ QualType Ty = E->getArg(0)->getType();
+ llvm::Type *StoreTy = llvm::IntegerType::get(getLLVMContext(),
+ getContext().getTypeSize(Ty));
+ StoreAddr = Builder.CreateBitCast(StoreAddr, StoreTy->getPointerTo());
+
+ if (StoreVal->getType()->isPointerTy())
+ StoreVal = Builder.CreatePtrToInt(StoreVal, Int32Ty);
+ else {
+ StoreVal = Builder.CreateBitCast(StoreVal, StoreTy);
+ StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int32Ty);
+ }
+
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_strex, StoreAddr->getType());
+ return Builder.CreateCall2(F, StoreVal, StoreAddr, "strex");
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_clrex) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex);
+ return Builder.CreateCall(F);
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_sevl) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_sevl);
+ return Builder.CreateCall(F);
+ }
+
+ // CRC32
+ Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
+ switch (BuiltinID) {
+ case ARM::BI__builtin_arm_crc32b:
+ CRCIntrinsicID = Intrinsic::arm_crc32b; break;
+ case ARM::BI__builtin_arm_crc32cb:
+ CRCIntrinsicID = Intrinsic::arm_crc32cb; break;
+ case ARM::BI__builtin_arm_crc32h:
+ CRCIntrinsicID = Intrinsic::arm_crc32h; break;
+ case ARM::BI__builtin_arm_crc32ch:
+ CRCIntrinsicID = Intrinsic::arm_crc32ch; break;
+ case ARM::BI__builtin_arm_crc32w:
+ case ARM::BI__builtin_arm_crc32d:
+ CRCIntrinsicID = Intrinsic::arm_crc32w; break;
+ case ARM::BI__builtin_arm_crc32cw:
+ case ARM::BI__builtin_arm_crc32cd:
+ CRCIntrinsicID = Intrinsic::arm_crc32cw; break;
+ }
+
+ if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
+ Value *Arg0 = EmitScalarExpr(E->getArg(0));
+ Value *Arg1 = EmitScalarExpr(E->getArg(1));
+
+ // crc32{c,}d intrinsics are implemnted as two calls to crc32{c,}w
+ // intrinsics, hence we need different codegen for these cases.
+ if (BuiltinID == ARM::BI__builtin_arm_crc32d ||
+ BuiltinID == ARM::BI__builtin_arm_crc32cd) {
+ Value *C1 = llvm::ConstantInt::get(Int64Ty, 32);
+ Value *Arg1a = Builder.CreateTruncOrBitCast(Arg1, Int32Ty);
+ Value *Arg1b = Builder.CreateLShr(Arg1, C1);
+ Arg1b = Builder.CreateTruncOrBitCast(Arg1b, Int32Ty);
+
+ Function *F = CGM.getIntrinsic(CRCIntrinsicID);
+ Value *Res = Builder.CreateCall2(F, Arg0, Arg1a);
+ return Builder.CreateCall2(F, Res, Arg1b);
+ } else {
+ Arg1 = Builder.CreateZExtOrBitCast(Arg1, Int32Ty);
+
+ Function *F = CGM.getIntrinsic(CRCIntrinsicID);
+ return Builder.CreateCall2(F, Arg0, Arg1);
+ }
+ }
+
SmallVector<Value*, 4> Ops;
llvm::Value *Align = 0;
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
@@ -1836,9 +4214,24 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vabsq_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vabs, Ty),
Ops, "vabs");
- case ARM::BI__builtin_neon_vaddhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vaddhn, Ty),
- Ops, "vaddhn");
+ case ARM::BI__builtin_neon_vaddhn_v: {
+ llvm::VectorType *SrcTy =
+ llvm::VectorType::getExtendedElementVectorType(VTy);
+
+ // %sum = add <4 x i32> %lhs, %rhs
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
+ Ops[0] = Builder.CreateAdd(Ops[0], Ops[1], "vaddhn");
+
+ // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
+ Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
+ SrcTy->getScalarSizeInBits() / 2);
+ ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
+ Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vaddhn");
+
+ // %res = trunc <4 x i32> %high to <4 x i16>
+ return Builder.CreateTrunc(Ops[0], VTy, "vaddhn");
+ }
case ARM::BI__builtin_neon_vcale_v:
std::swap(Ops[0], Ops[1]);
case ARM::BI__builtin_neon_vcage_v: {
@@ -2142,6 +4535,11 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, Ty),
Ops, "vmul");
case ARM::BI__builtin_neon_vmull_v:
+ // FIXME: the integer vmull operations could be emitted in terms of pure
+ // LLVM IR (2 exts followed by a mul). Unfortunately LLVM has a habit of
+ // hoisting the exts outside loops. Until global ISel comes along that can
+ // see through such movement this leads to bad CodeGen. So we need an
+ // intrinsic for now.
Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
@@ -2195,12 +4593,28 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vqaddq_v:
Int = usgn ? Intrinsic::arm_neon_vqaddu : Intrinsic::arm_neon_vqadds;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqadd");
- case ARM::BI__builtin_neon_vqdmlal_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlal, Ty),
- Ops, "vqdmlal");
- case ARM::BI__builtin_neon_vqdmlsl_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmlsl, Ty),
- Ops, "vqdmlsl");
+ case ARM::BI__builtin_neon_vqdmlal_v: {
+ SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
+ Value *Mul = EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, Ty),
+ MulOps, "vqdmlal");
+
+ SmallVector<Value *, 2> AddOps;
+ AddOps.push_back(Ops[0]);
+ AddOps.push_back(Mul);
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqadds, Ty),
+ AddOps, "vqdmlal");
+ }
+ case ARM::BI__builtin_neon_vqdmlsl_v: {
+ SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
+ Value *Mul = EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, Ty),
+ MulOps, "vqdmlsl");
+
+ SmallVector<Value *, 2> SubOps;
+ SubOps.push_back(Ops[0]);
+ SubOps.push_back(Mul);
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqsubs, Ty),
+ SubOps, "vqdmlsl");
+ }
case ARM::BI__builtin_neon_vqdmulh_v:
case ARM::BI__builtin_neon_vqdmulhq_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmulh, Ty),
@@ -2320,12 +4734,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops, "vshrn_n", 1, true);
case ARM::BI__builtin_neon_vshr_n_v:
case ARM::BI__builtin_neon_vshrq_n_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
- if (usgn)
- return Builder.CreateLShr(Ops[0], Ops[1], "vshr_n");
- else
- return Builder.CreateAShr(Ops[0], Ops[1], "vshr_n");
+ return EmitNeonRShiftImm(Ops[0], Ops[1], Ty, usgn, "vshr_n");
case ARM::BI__builtin_neon_vsri_n_v:
case ARM::BI__builtin_neon_vsriq_n_v:
rightShift = true;
@@ -2337,12 +4746,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vsra_n_v:
case ARM::BI__builtin_neon_vsraq_n_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = EmitNeonShiftVector(Ops[2], Ty, false);
- if (usgn)
- Ops[1] = Builder.CreateLShr(Ops[1], Ops[2], "vsra_n");
- else
- Ops[1] = Builder.CreateAShr(Ops[1], Ops[2], "vsra_n");
+ Ops[1] = EmitNeonRShiftImm(Ops[1], Ops[2], Ty, usgn, "vsra_n");
return Builder.CreateAdd(Ops[0], Ops[1]);
case ARM::BI__builtin_neon_vst1_v:
case ARM::BI__builtin_neon_vst1q_v:
@@ -2400,9 +4804,24 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
Ops, "");
- case ARM::BI__builtin_neon_vsubhn_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vsubhn, Ty),
- Ops, "vsubhn");
+ case ARM::BI__builtin_neon_vsubhn_v: {
+ llvm::VectorType *SrcTy =
+ llvm::VectorType::getExtendedElementVectorType(VTy);
+
+ // %sum = add <4 x i32> %lhs, %rhs
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
+ Ops[0] = Builder.CreateSub(Ops[0], Ops[1], "vsubhn");
+
+ // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
+ Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
+ SrcTy->getScalarSizeInBits() / 2);
+ ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
+ Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vsubhn");
+
+ // %res = trunc <4 x i32> %high to <4 x i16>
+ return Builder.CreateTrunc(Ops[0], VTy, "vsubhn");
+ }
case ARM::BI__builtin_neon_vtbl1_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl1),
Ops, "vtbl1");
@@ -2560,19 +4979,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateExtractElement(Ops[0],
llvm::ConstantInt::get(Ops[1]->getType(), 0));
case X86::BI__builtin_ia32_ldmxcsr: {
- llvm::Type *PtrTy = Int8PtrTy;
- Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int32Ty, One);
+ Value *Tmp = CreateMemTemp(E->getArg(0)->getType());
Builder.CreateStore(Ops[0], Tmp);
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr),
- Builder.CreateBitCast(Tmp, PtrTy));
+ Builder.CreateBitCast(Tmp, Int8PtrTy));
}
case X86::BI__builtin_ia32_stmxcsr: {
- llvm::Type *PtrTy = Int8PtrTy;
- Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int32Ty, One);
+ Value *Tmp = CreateMemTemp(E->getType());
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
- Builder.CreateBitCast(Tmp, PtrTy));
+ Builder.CreateBitCast(Tmp, Int8PtrTy));
return Builder.CreateLoad(Tmp, "stmxcsr");
}
case X86::BI__builtin_ia32_storehps:
@@ -2697,7 +5112,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_movntpd256:
case X86::BI__builtin_ia32_movntdq:
case X86::BI__builtin_ia32_movntdq256:
- case X86::BI__builtin_ia32_movnti: {
+ case X86::BI__builtin_ia32_movnti:
+ case X86::BI__builtin_ia32_movnti64: {
llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(),
Builder.getInt32(1));
@@ -2707,7 +5123,16 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
"cast");
StoreInst *SI = Builder.CreateStore(Ops[1], BC);
SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
- SI->setAlignment(16);
+
+ // If the operand is an integer, we can't assume alignment. Otherwise,
+ // assume natural alignment.
+ QualType ArgTy = E->getArg(1)->getType();
+ unsigned Align;
+ if (ArgTy->isIntegerType())
+ Align = 1;
+ else
+ Align = getContext().getTypeSizeInChars(ArgTy).getQuantity();
+ SI->setAlignment(Align);
return SI;
}
// 3DNow!
@@ -2761,6 +5186,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Builder.CreateStore(Builder.CreateExtractValue(Call, 0), Ops[0]);
return Builder.CreateExtractValue(Call, 1);
}
+ // AVX2 broadcast
+ case X86::BI__builtin_ia32_vbroadcastsi256: {
+ Value *VecTmp = CreateMemTemp(E->getArg(0)->getType());
+ Builder.CreateStore(Ops[0], VecTmp);
+ Value *F = CGM.getIntrinsic(Intrinsic::x86_avx2_vbroadcasti128);
+ return Builder.CreateCall(F, Builder.CreateBitCast(VecTmp, Int8PtrTy));
+ }
}
}
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
index fc72008af886..eaf31bb6f67f 100644
--- a/lib/CodeGen/CGCUDARuntime.cpp
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -44,8 +44,8 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
}
llvm::Value *Callee = CGF.EmitScalarExpr(E->getCallee());
- CGF.EmitCall(E->getCallee()->getType(), Callee, ReturnValue,
- E->arg_begin(), E->arg_end(), TargetDecl);
+ CGF.EmitCall(E->getCallee()->getType(), Callee, E->getLocStart(),
+ ReturnValue, E->arg_begin(), E->arg_end(), TargetDecl);
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 983cb9224ade..cfb2d6291b8a 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -34,6 +34,11 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
+ // Producing an alias to a base class ctor/dtor can degrade debug quality
+ // as the debugger cannot tell them appart.
+ if (getCodeGenOpts().OptimizationLevel == 0)
+ return true;
+
// If the destructor doesn't have a trivial body, we have to emit it
// separately.
if (!D->hasTrivialBody())
@@ -82,60 +87,44 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!UniqueBase)
return true;
- /// 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.
- const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
- if (!BaseD->isImplicit() && !BaseD->hasBody())
- return true;
-
// If the base is at a non-zero offset, give up.
const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
return true;
+ const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
- GlobalDecl(BaseD, Dtor_Base));
+ GlobalDecl(BaseD, Dtor_Base),
+ false);
}
/// 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) {
+ GlobalDecl TargetDecl,
+ bool InEveryTU) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
// The alias will use the linkage of the referrent. If we can't
// support aliases with that linkage, fail.
- llvm::GlobalValue::LinkageTypes Linkage
- = getFunctionLinkage(cast<FunctionDecl>(AliasDecl.getDecl()));
-
- switch (Linkage) {
- // We can definitely emit aliases to definitions with external linkage.
- case llvm::GlobalValue::ExternalLinkage:
- case llvm::GlobalValue::ExternalWeakLinkage:
- break;
-
- // Same with local linkage.
- case llvm::GlobalValue::InternalLinkage:
- case llvm::GlobalValue::PrivateLinkage:
- case llvm::GlobalValue::LinkerPrivateLinkage:
- break;
-
- // We should try to support linkonce linkages.
- case llvm::GlobalValue::LinkOnceAnyLinkage:
- case llvm::GlobalValue::LinkOnceODRLinkage:
- return true;
+ llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
- // Other linkages will probably never be supported.
- default:
+ // We can't use an alias if the linkage is not valid for one.
+ if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
- }
- llvm::GlobalValue::LinkageTypes TargetLinkage
- = getFunctionLinkage(cast<FunctionDecl>(TargetDecl.getDecl()));
+ llvm::GlobalValue::LinkageTypes TargetLinkage =
+ getFunctionLinkage(TargetDecl);
- if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
- return true;
+ // Check if we have it already.
+ StringRef MangledName = getMangledName(AliasDecl);
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+ if (Entry && !Entry->isDeclaration())
+ return false;
+ if (Replacements.count(MangledName))
+ return false;
// Derive the type for the alias.
llvm::PointerType *AliasType
@@ -149,15 +138,41 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
if (Ref->getType() != AliasType)
Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
+ // Instead of creating as alias to a linkonce_odr, replace all of the uses
+ // of the aliassee.
+ if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
+ (TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
+ !TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
+ // FIXME: An extern template instanciation 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.
+ Replacements[MangledName] = Aliasee;
+ return false;
+ }
+
+ 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;
+ }
+
+ // Don't create an alias to a linker weak symbol. This avoids producing
+ // different COMDATs in different TUs. Another option would be to
+ // output the alias both for weak_odr and linkonce_odr, but that
+ // requires explicit comdat support in the IL.
+ if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
+ return true;
+
// Create the alias with no name.
llvm::GlobalAlias *Alias =
new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
// Switch any previous uses to the alias.
- StringRef MangledName = getMangledName(AliasDecl);
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- assert(Entry->isDeclaration() && "definition already exists for alias");
assert(Entry->getType() == AliasType &&
"declaration exists with different type");
Alias->takeName(Entry);
@@ -173,37 +188,26 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return false;
}
-void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
- // The constructor used for constructing this as a complete class;
- // constucts the virtual bases, then calls the base constructor.
- if (!D->getParent()->isAbstract()) {
- // We don't need to emit the complete ctor if the class is abstract.
- EmitGlobal(GlobalDecl(D, Ctor_Complete));
- }
-
- // The constructor used for constructing this as a base class;
- // ignores virtual bases.
- if (getTarget().getCXXABI().hasConstructorVariants())
- EmitGlobal(GlobalDecl(D, Ctor_Base));
-}
-
void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
CXXCtorType ctorType) {
// The complete constructor is equivalent to the base constructor
// for classes with no virtual bases. Try to emit it as an alias.
if (getTarget().getCXXABI().hasConstructorVariants() &&
- ctorType == Ctor_Complete &&
!ctor->getParent()->getNumVBases() &&
- !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
- GlobalDecl(ctor, Ctor_Base)))
- return;
+ (ctorType == Ctor_Complete || ctorType == Ctor_Base)) {
+ bool ProducedAlias =
+ !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
+ GlobalDecl(ctor, Ctor_Base), true);
+ if (ctorType == Ctor_Complete && ProducedAlias)
+ return;
+ }
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo));
- setFunctionLinkage(ctor, fn);
+ setFunctionLinkage(GlobalDecl(ctor, ctorType), fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo);
@@ -229,31 +233,22 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
/*ForVTable=*/false));
}
-void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
- // The destructor in a virtual table is always a 'deleting'
- // destructor, which calls the complete destructor and then uses the
- // appropriate operator delete.
- if (D->isVirtual())
- EmitGlobal(GlobalDecl(D, Dtor_Deleting));
-
- // The destructor used for destructing this as a most-derived class;
- // call the base destructor and then destructs any virtual bases.
- EmitGlobal(GlobalDecl(D, Dtor_Complete));
-
- // The destructor used for destructing this as a base class; ignores
- // virtual bases.
- EmitGlobal(GlobalDecl(D, Dtor_Base));
-}
-
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
CXXDtorType dtorType) {
// The complete destructor is equivalent to the base destructor for
// classes with no virtual bases, so try to emit it as an alias.
- if (dtorType == Dtor_Complete &&
- !dtor->getParent()->getNumVBases() &&
- !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete),
- GlobalDecl(dtor, Dtor_Base)))
- return;
+ if (!dtor->getParent()->getNumVBases() &&
+ (dtorType == Dtor_Complete || dtorType == Dtor_Base)) {
+ bool ProducedAlias =
+ !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete),
+ GlobalDecl(dtor, Dtor_Base), true);
+ if (ProducedAlias) {
+ if (dtorType == Dtor_Complete)
+ return;
+ if (dtor->isVirtual())
+ getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete));
+ }
+ }
// The base destructor is equivalent to the base destructor of its
// base class if there is exactly one non-virtual base class with a
@@ -267,7 +262,7 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo));
- setFunctionLinkage(dtor, fn);
+ setFunctionLinkage(GlobalDecl(dtor, dtorType), fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo);
@@ -278,47 +273,51 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
CXXDtorType dtorType,
- const CGFunctionInfo *fnInfo) {
+ const CGFunctionInfo *fnInfo,
+ llvm::FunctionType *fnType) {
GlobalDecl GD(dtor, dtorType);
StringRef name = getMangledName(GD);
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
- if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
-
- llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
+ if (!fnType) {
+ if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
+ fnType = getTypes().GetFunctionType(*fnInfo);
+ }
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
-static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
- llvm::Value *This, llvm::Type *Ty) {
+static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Type *Ty,
+ const CXXRecordDecl *RD) {
+ assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
+ "No kext in Microsoft ABI");
+ GD = GD.getCanonicalDecl();
+ CodeGenModule &CGM = CGF.CGM;
+ llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
Ty = Ty->getPointerTo()->getPointerTo();
-
- llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+ VTable = CGF.Builder.CreateBitCast(VTable, Ty);
+ assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
+ uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
+ uint64_t AddressPoint =
+ CGM.getItaniumVTableContext().getVTableLayout(RD)
+ .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
+ VTableIndex += AddressPoint;
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
return CGF.Builder.CreateLoad(VFuncPtr);
}
-llvm::Value *
-CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
- llvm::Type *Ty) {
- MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD);
-
- return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
-}
-
-/// BuildVirtualCall - This routine is to support gcc's kext ABI making
+/// BuildAppleKextVirtualCall - This routine is to support gcc's kext ABI making
/// indirect call to virtual functions. It makes the call through indexing
/// into the vtable.
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
llvm::Type *Ty) {
- llvm::Value *VTable = 0;
assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
"BuildAppleKextVirtualCall - bad Qual kind");
@@ -330,20 +329,8 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD))
return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);
-
- VTable = CGM.getVTables().GetAddrOfVTable(RD);
- Ty = Ty->getPointerTo()->getPointerTo();
- VTable = Builder.CreateBitCast(VTable, Ty);
- assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
- MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD);
- uint64_t AddressPoint =
- CGM.getVTableContext().getVTableLayout(RD)
- .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
- VTableIndex += AddressPoint;
- llvm::Value *VFuncPtr =
- Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
- return Builder.CreateLoad(VFuncPtr);
+
+ return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
}
/// BuildVirtualCall - This routine makes indirect vtable call for
@@ -353,42 +340,16 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
const CXXDestructorDecl *DD,
CXXDtorType Type,
const CXXRecordDecl *RD) {
- llvm::Value * Callee = 0;
const CXXMethodDecl *MD = cast<CXXMethodDecl>(DD);
// FIXME. Dtor_Base dtor is always direct!!
// It need be somehow inline expanded into the caller.
// -O does that. But need to support -O0 as well.
if (MD->isVirtual() && Type != Dtor_Base) {
// Compute the function type we're calling.
- const CGFunctionInfo &FInfo =
- CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
- Dtor_Complete);
+ const CGFunctionInfo &FInfo =
+ CGM.getTypes().arrangeCXXDestructor(DD, Dtor_Complete);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
-
- llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
- Ty = Ty->getPointerTo()->getPointerTo();
- VTable = Builder.CreateBitCast(VTable, Ty);
- DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- uint64_t VTableIndex =
- CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type));
- uint64_t AddressPoint =
- CGM.getVTableContext().getVTableLayout(RD)
- .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
- VTableIndex += AddressPoint;
- llvm::Value *VFuncPtr =
- Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
- Callee = Builder.CreateLoad(VFuncPtr);
+ return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
}
- return Callee;
+ return 0;
}
-
-llvm::Value *
-CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
- llvm::Value *This, llvm::Type *Ty) {
- DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- uint64_t VTableIndex =
- CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type));
-
- return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
-}
-
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 68fecb2d0cb8..412b27814ac8 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -1,4 +1,4 @@
-//===----- CGCXXABI.cpp - Interface to C++ ABIs -----------------*- C++ -*-===//
+//===----- CGCXXABI.cpp - Interface to C++ ABIs ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -212,13 +212,6 @@ llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
return llvm::ConstantInt::get(CGF.SizeTy, 0);
}
-void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
- const VarDecl &D,
- llvm::GlobalVariable *GV,
- bool PerformInit) {
- ErrorUnsupportedABI(CGF, "static local variable initialization");
-}
-
void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
const VarDecl &D,
llvm::Constant *dtor,
@@ -227,7 +220,7 @@ void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
// The default behavior is to use atexit.
- CGF.registerGlobalDtorWithAtExit(dtor, addr);
+ CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
}
/// Returns the adjustment, in bytes, required for the given
@@ -251,8 +244,31 @@ llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
E->path_end());
}
-llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler(
- CodeGenFunction &CGF) {
+CharUnits CGCXXABI::getMemberPointerPathAdjustment(const APValue &MP) {
+ // TODO: Store base specifiers in APValue member pointer paths so we can
+ // easily reuse CGM.GetNonVirtualBaseClassOffset().
+ const ValueDecl *MPD = MP.getMemberPointerDecl();
+ CharUnits ThisAdjustment = CharUnits::Zero();
+ ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
+ bool DerivedMember = MP.isMemberPointerToDerivedMember();
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ const CXXRecordDecl *Base = RD;
+ const CXXRecordDecl *Derived = Path[I];
+ if (DerivedMember)
+ std::swap(Base, Derived);
+ ThisAdjustment +=
+ getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
+ RD = Path[I];
+ }
+ if (DerivedMember)
+ ThisAdjustment = -ThisAdjustment;
+ return ThisAdjustment;
+}
+
+llvm::BasicBlock *
+CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {
if (CGM.getTarget().getCXXABI().hasConstructorVariants())
llvm_unreachable("shouldn't be called in this ABI");
@@ -270,3 +286,7 @@ LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
ErrorUnsupportedABI(CGF, "odr-use of thread_local global");
return LValue();
}
+
+bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
+ return false;
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 1e4da631d6f6..9e9a2a7aaf9b 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -97,8 +97,12 @@ public:
return *MangleCtx;
}
- /// Returns true if the given instance method is one of the
- /// kinds that the ABI says returns 'this'.
+ /// Returns true if the given constructor or destructor is one of the
+ /// kinds that the ABI says returns 'this' (only applies when called
+ /// non-virtually for destructors).
+ ///
+ /// There currently is no way to indicate if a destructor returns 'this'
+ /// when called virtually, and code generation does not support the case.
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
/// Returns true if the given record type should be returned indirectly.
@@ -192,6 +196,12 @@ protected:
/// is required.
llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
+ /// \brief Computes the non-virtual adjustment needed for a member pointer
+ /// conversion along an inheritance path stored in an APValue. Unlike
+ /// getMemberPointerAdjustment(), the adjustment can be negative if the path
+ /// is from a derived type to a base type.
+ CharUnits getMemberPointerPathAdjustment(const APValue &MP);
+
public:
/// Adjust the given non-null pointer to an object of polymorphic
/// type to point to the complete object.
@@ -202,11 +212,16 @@ public:
llvm::Value *ptr,
QualType type) = 0;
+ virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) = 0;
+
/// Build the signature of the given constructor variant by adding
- /// any required parameters. For convenience, ResTy has been
- /// initialized to 'void', and ArgTys has been initialized with the
- /// type of 'this' (although this may be changed by the ABI) and
- /// will have the formal parameters added to it afterwards.
+ /// any required parameters. For convenience, ArgTys has been initialized
+ /// with the type of 'this' and ResTy has been initialized with the type of
+ /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise
+ /// (although both may be changed by the ABI).
///
/// If there are ever any ABIs where the implicit parameters are
/// intermixed with the formal parameters, we can address those
@@ -216,46 +231,138 @@ public:
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) = 0;
- virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+ virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD);
+
+ /// Emit the code to initialize hidden members required
+ /// to handle virtual inheritance, if needed by the ABI.
+ virtual void
+ initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {}
+
+ /// Emit constructor variants required by this ABI.
+ virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
/// Build the signature of the given destructor variant by adding
- /// any required parameters. For convenience, ResTy has been
- /// initialized to 'void' and ArgTys has been initialized with the
- /// type of 'this' (although this may be changed by the ABI).
+ /// any required parameters. For convenience, ArgTys has been initialized
+ /// with the type of 'this' and ResTy has been initialized with the type of
+ /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise
+ /// (although both may be changed by the ABI).
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ /// Returns true if the given destructor type should be emitted as a linkonce
+ /// delegating thunk, regardless of whether the dtor is defined in this TU or
+ /// not.
+ virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
+ CXXDtorType DT) const = 0;
+
+ /// Emit destructor variants required by this ABI.
+ virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0;
+
+ /// Get the type of the implicit "this" parameter used by a method. May return
+ /// zero if no specific type is applicable, e.g. if the ABI expects the "this"
+ /// parameter to point to some artificial offset in a complete object due to
+ /// vbases being reordered.
+ virtual const CXXRecordDecl *
+ getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
+ return MD->getParent();
+ }
+
+ /// Perform ABI-specific "this" argument adjustment required prior to
+ /// a virtual function call.
+ virtual llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This) {
+ return This;
+ }
+
/// Build the ABI-specific portion of the parameter list for a
/// function. This generally involves a 'this' parameter and
/// possibly some extra data for constructors and destructors.
///
/// ABIs may also choose to override the return type, which has been
- /// initialized with the formal return type of the function.
+ /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
+ /// the formal return type of the function otherwise.
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) = 0;
+ /// Perform ABI-specific "this" parameter adjustment in a virtual function
+ /// prologue.
+ virtual llvm::Value *adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ return This;
+ }
+
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
/// Emit the constructor call. Return the function that is called.
- virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ virtual void EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) = 0;
+ /// Emits the VTable definitions required for the given record type.
+ virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
+ const CXXRecordDecl *RD) = 0;
+
+ /// Get the address point of the vtable for the given base subobject while
+ /// building a constructor or a destructor. On return, NeedsVirtualOffset
+ /// tells if a virtual base adjustment is needed in order to get the offset
+ /// of the base subobject.
+ virtual llvm::Value *getVTableAddressPointInStructor(
+ CodeGenFunction &CGF, const CXXRecordDecl *RD, BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) = 0;
+
+ /// Get the address point of the vtable for the given base subobject while
+ /// building a constexpr.
+ virtual llvm::Constant *
+ getVTableAddressPointForConstExpr(BaseSubobject Base,
+ const CXXRecordDecl *VTableClass) = 0;
+
+ /// Get the address of the vtable for the given record decl which should be
+ /// used for the vptr at the given offset in RD.
+ virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
+ CharUnits VPtrOffset) = 0;
+
+ /// Build a virtual function pointer in the ABI-specific way.
+ virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) = 0;
+
/// Emit the ABI-specific virtual destructor call.
- virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- llvm::Value *This) = 0;
+ virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ llvm::Value *This) = 0;
+
+ virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ CallArgList &CallArgs) {}
+
+ /// Emit any tables needed to implement virtual inheritance. For Itanium,
+ /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
+ /// base tables.
+ virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
+
+ virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
+
+ virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const ThisAdjustment &TA) = 0;
+
+ virtual llvm::Value *performReturnAdjustment(CodeGenFunction &CGF,
+ llvm::Value *Ret,
+ const ReturnAdjustment &RA) = 0;
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType);
@@ -266,6 +373,10 @@ public:
/// Gets the deleted virtual member call name.
virtual StringRef GetDeletedVirtualCallName() = 0;
+ /// \brief Returns true iff static data members that are initialized in the
+ /// class definition should have linkonce linkage.
+ virtual bool isInlineInitializedStaticDataMemberLinkOnce() { return false; }
+
/**************************** Array cookies ******************************/
/// Returns the extra size required in order to store the array
@@ -312,6 +423,9 @@ public:
QualType ElementType, llvm::Value *&NumElements,
llvm::Value *&AllocPtr, CharUnits &CookieSize);
+ /// Return whether the given global decl needs a VTT parameter.
+ virtual bool NeedsVTTParameter(GlobalDecl GD);
+
protected:
/// Returns the extra size required in order to store the array
/// cookie for the given type. Assumes that an array cookie is
@@ -344,7 +458,8 @@ public:
/// - a static local variable
/// - a static data member of a class template instantiation
virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr, bool PerformInit);
+ llvm::GlobalVariable *DeclPtr,
+ bool PerformInit) = 0;
/// Emit code to force the execution of a destructor during global
/// teardown. The default implementation of this uses atexit.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index b0f460ec0e7b..22f2467021e1 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1,4 +1,4 @@
-//===--- CGCall.cpp - Encapsulate calling convention details ----*- C++ -*-===//
+//===--- CGCall.cpp - Encapsulate calling convention details --------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -22,6 +22,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Attributes.h"
@@ -41,6 +42,8 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
+ case CC_X86_64Win64: return llvm::CallingConv::X86_64_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;
case CC_IntelOclBicc: return llvm::CallingConv::Intel_OCL_BI;
@@ -103,24 +106,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo());
}
-/// Given the formal ext-info of a C++ instance method, adjust it
-/// according to the C++ ABI in effect.
-static void adjustCXXMethodInfo(CodeGenTypes &CGT,
- FunctionType::ExtInfo &extInfo,
- bool isVariadic) {
- if (extInfo.getCC() == CC_Default) {
- CallingConv CC = CGT.getContext().getDefaultCXXMethodCallConv(isVariadic);
- extInfo = extInfo.withCallingConv(CC);
- }
-}
-
/// Arrange the argument and result information for a free function (i.e.
/// not a C++ or ObjC instance method) of the given type.
static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
}
@@ -160,6 +151,8 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
/// Arrange the argument and result information for a call to an
/// unknown C++ non-static member function of the given abstract type.
+/// (Zero value of RD means we don't have any meaningful "this" argument type,
+/// so fall back to a generic pointer type).
/// The member function must be an ordinary function, i.e. not a
/// constructor or destructor.
const CGFunctionInfo &
@@ -168,7 +161,10 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
SmallVector<CanQualType, 16> argTypes;
// Add the 'this' pointer.
- argTypes.push_back(GetThisType(Context, RD));
+ if (RD)
+ argTypes.push_back(GetThisType(Context, RD));
+ else
+ argTypes.push_back(Context.VoidPtrTy);
return ::arrangeCXXMethodType(*this, argTypes,
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
@@ -180,14 +176,15 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
/// constructor or destructor.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
- assert(!isa<CXXConstructorDecl>(MD) && "wrong method for contructors!");
+ assert(!isa<CXXConstructorDecl>(MD) && "wrong method for constructors!");
assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
CanQual<FunctionProtoType> prototype = GetFormalType(MD);
if (MD->isInstance()) {
// The abstract case is perfectly fine.
- return arrangeCXXMethodType(MD->getParent(), prototype.getTypePtr());
+ const CXXRecordDecl *ThisType = TheCXXABI.getThisArgumentTypeForMethod(MD);
+ return arrangeCXXMethodType(ThisType, prototype.getTypePtr());
}
return arrangeFreeFunctionType(prototype);
@@ -200,7 +197,10 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
CXXCtorType ctorKind) {
SmallVector<CanQualType, 16> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent()));
- CanQualType resultType = Context.VoidTy;
+
+ GlobalDecl GD(D, ctorKind);
+ CanQualType resultType =
+ TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
@@ -213,7 +213,6 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
argTypes.push_back(FTP->getArgType(i));
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
}
@@ -225,7 +224,10 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType dtorKind) {
SmallVector<CanQualType, 2> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent()));
- CanQualType resultType = Context.VoidTy;
+
+ GlobalDecl GD(D, dtorKind);
+ CanQualType resultType =
+ TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
@@ -234,7 +236,6 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- adjustCXXMethodInfo(*this, extInfo, false);
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
RequiredArgs::All);
}
@@ -322,6 +323,7 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
/// additional number of formal parameters considered required.
static const CGFunctionInfo &
arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
+ CodeGenModule &CGM,
const CallArgList &args,
const FunctionType *fnType,
unsigned numExtraRequiredArgs) {
@@ -340,8 +342,9 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
// explicitly use the variadic convention for unprototyped calls,
// treat all of the arguments as required but preserve the nominal
// possibility of variadics.
- } else if (CGT.CGM.getTargetCodeGenInfo()
- .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
+ } else if (CGM.getTargetCodeGenInfo()
+ .isNoProtoCallVariadic(args,
+ cast<FunctionNoProtoType>(fnType))) {
required = RequiredArgs(args.size());
}
@@ -356,7 +359,7 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
- return arrangeFreeFunctionLikeCall(*this, args, fnType, 0);
+ return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 0);
}
/// A block function call is essentially a free-function call with an
@@ -364,7 +367,7 @@ CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
const CGFunctionInfo &
CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
- return arrangeFreeFunctionLikeCall(*this, args, fnType, 1);
+ return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1);
}
const CGFunctionInfo &
@@ -393,7 +396,6 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
FunctionType::ExtInfo info = FPT->getExtInfo();
- adjustCXXMethodInfo(*this, info, FPT->isVariadic());
return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
argTypes, info, required);
}
@@ -642,6 +644,10 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
/// CoerceIntOrPtrToIntOrPtr - Convert a value Val to the specific Ty where both
/// are either integers or pointers. This does a truncation of the value if it
/// is too large or a zero extension if it is too small.
+///
+/// This behaves as if the value were coerced through memory, so on big-endian
+/// targets the high bits are preserved in a truncation, while little-endian
+/// targets preserve the low bits.
static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
llvm::Type *Ty,
CodeGenFunction &CGF) {
@@ -661,8 +667,25 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
if (isa<llvm::PointerType>(DestIntTy))
DestIntTy = CGF.IntPtrTy;
- if (Val->getType() != DestIntTy)
- Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii");
+ if (Val->getType() != DestIntTy) {
+ const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
+ if (DL.isBigEndian()) {
+ // Preserve the high bits on big-endian targets.
+ // That is what memory coercion does.
+ uint64_t SrcSize = DL.getTypeAllocSizeInBits(Val->getType());
+ uint64_t DstSize = DL.getTypeAllocSizeInBits(DestIntTy);
+ if (SrcSize > DstSize) {
+ Val = CGF.Builder.CreateLShr(Val, SrcSize - DstSize, "coerce.highbits");
+ Val = CGF.Builder.CreateTrunc(Val, DestIntTy, "coerce.val.ii");
+ } else {
+ Val = CGF.Builder.CreateZExt(Val, DestIntTy, "coerce.val.ii");
+ Val = CGF.Builder.CreateShl(Val, DstSize - SrcSize, "coerce.highbits");
+ }
+ } else {
+ // Little-endian targets preserve the low bits. No shifts required.
+ Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii");
+ }
+ }
if (isa<llvm::PointerType>(Ty))
Val = CGF.Builder.CreateIntToPtr(Val, Ty, "coerce.val.ip");
@@ -1024,25 +1047,29 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// Attributes that should go on the function, but not the call site.
if (!CodeGenOpts.DisableFPElim) {
FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "false");
} else if (CodeGenOpts.OmitLeafFramePointer) {
FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
} else {
FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
}
FuncAttrs.addAttribute("less-precise-fpmad",
- CodeGenOpts.LessPreciseFPMAD ? "true" : "false");
+ llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
FuncAttrs.addAttribute("no-infs-fp-math",
- CodeGenOpts.NoInfsFPMath ? "true" : "false");
+ llvm::toStringRef(CodeGenOpts.NoInfsFPMath));
FuncAttrs.addAttribute("no-nans-fp-math",
- CodeGenOpts.NoNaNsFPMath ? "true" : "false");
+ llvm::toStringRef(CodeGenOpts.NoNaNsFPMath));
FuncAttrs.addAttribute("unsafe-fp-math",
- CodeGenOpts.UnsafeFPMath ? "true" : "false");
+ llvm::toStringRef(CodeGenOpts.UnsafeFPMath));
FuncAttrs.addAttribute("use-soft-float",
- CodeGenOpts.SoftFloat ? "true" : "false");
+ llvm::toStringRef(CodeGenOpts.SoftFloat));
+ FuncAttrs.addAttribute("stack-protector-buffer-size",
+ llvm::utostr(CodeGenOpts.SSPBufferSize));
+
+ if (!CodeGenOpts.StackRealignment)
+ FuncAttrs.addAttribute("no-realign-stack");
}
QualType RetTy = FI.getReturnType();
@@ -1050,12 +1077,15 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
- if (RetTy->hasSignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attribute::SExt);
- else if (RetTy->hasUnsignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attribute::ZExt);
- break;
+ if (RetTy->hasSignedIntegerRepresentation())
+ RetAttrs.addAttribute(llvm::Attribute::SExt);
+ else if (RetTy->hasUnsignedIntegerRepresentation())
+ RetAttrs.addAttribute(llvm::Attribute::ZExt);
+ // FALL THROUGH
case ABIArgInfo::Direct:
+ if (RetAI.getInReg())
+ RetAttrs.addAttribute(llvm::Attribute::InReg);
+ break;
case ABIArgInfo::Ignore:
break;
@@ -1263,7 +1293,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
} else {
// Load scalar value from indirect argument.
CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
- V = EmitLoadOfScalar(V, false, Alignment.getQuantity(), Ty);
+ V = EmitLoadOfScalar(V, false, Alignment.getQuantity(), Ty,
+ Arg->getLocStart());
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
@@ -1294,6 +1325,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ if (const CXXMethodDecl *MD =
+ dyn_cast_or_null<CXXMethodDecl>(CurCodeDecl)) {
+ if (MD->isVirtual() && Arg == CXXABIThisDecl)
+ V = CGM.getCXXABI().
+ adjustThisParameterInVirtualFunctionPrologue(*this, CurGD, V);
+ }
+
// Because of merging of function types from multiple decls it is
// possible for the type of an argument to not match the corresponding
// type in the function type. Since we are codegening the callee
@@ -1371,7 +1409,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Match to what EmitParmDecl is expecting for this type.
if (CodeGenFunction::hasScalarEvaluationKind(Ty)) {
- V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty);
+ V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty, Arg->getLocStart());
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
}
@@ -1609,20 +1647,9 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
return store;
}
-/// Check whether 'this' argument of a callsite matches 'this' of the caller.
-static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
- if (ThisArg == This)
- return true;
- // Check whether ThisArg is a bitcast of This.
- llvm::BitCastInst *Bitcast;
- if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
- Bitcast->getOperand(0) == This)
- return true;
- return false;
-}
-
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
- bool EmitRetDbgLoc) {
+ bool EmitRetDbgLoc,
+ SourceLocation EndLoc) {
// Functions with no result always return void.
if (ReturnValue == 0) {
Builder.CreateRetVoid();
@@ -1639,7 +1666,8 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
ComplexPairTy RT =
- EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy));
+ EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy),
+ EndLoc);
EmitStoreOfComplex(RT,
MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
/*isInit*/ true);
@@ -1667,8 +1695,10 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
// If there is a dominating store to ReturnValue, we can elide
// the load, zap the store, and usually zap the alloca.
if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) {
- // Reuse the debug location from the store unless we're told not to.
- if (EmitRetDbgLoc)
+ // Reuse the debug location from the store unless there is
+ // cleanup code to be emitted between the store and return
+ // instruction.
+ if (EmitRetDbgLoc && !AutoreleaseResult)
RetDbgLoc = SI->getDebugLoc();
// Get the stored value and nuke the now-dead store.
RV = SI->getValueOperand();
@@ -1715,26 +1745,14 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument");
}
- // If this function returns 'this', the last instruction is a CallInst
- // that returns 'this', and 'this' argument of the CallInst points to
- // the same object as CXXThisValue, use the return value from the CallInst.
- // We will not need to keep 'this' alive through the callsite. It also enables
- // optimizations in the backend, such as tail call optimization.
- if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
- llvm::BasicBlock *IP = Builder.GetInsertBlock();
- llvm::CallInst *Callsite;
- if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
- Callsite->getCalledFunction() == CalleeWithThisReturn &&
- checkThisPointer(Callsite->getOperand(0), CXXThisValue))
- RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
- }
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
}
void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
- const VarDecl *param) {
+ const VarDecl *param,
+ SourceLocation loc) {
// StartFunction converted the ABI-lowered parameter(s) into a
// local alloca. We need to turn that into an r-value suitable
// for EmitCall.
@@ -1755,7 +1773,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- args.add(convertTempToRValue(local, type), type);
+ args.add(convertTempToRValue(local, type, loc), type);
}
static bool isProvablyNull(llvm::Value *addr) {
@@ -1814,7 +1832,7 @@ static void emitWriteback(CodeGenFunction &CGF,
CGF.EmitARCIntrinsicUse(writeback.ToUse);
// Load the old value (primitively).
- llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV);
+ llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV, SourceLocation());
// Put the new value in place (primitively).
CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false);
@@ -1839,6 +1857,19 @@ static void emitWritebacks(CodeGenFunction &CGF,
emitWriteback(CGF, *i);
}
+static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF,
+ const CallArgList &CallArgs) {
+ assert(CGF.getTarget().getCXXABI().isArgumentDestroyedByCallee());
+ ArrayRef<CallArgList::CallArgCleanup> Cleanups =
+ CallArgs.getCleanupsToDeactivate();
+ // Iterate in reverse to increase the likelihood of popping the cleanup.
+ for (ArrayRef<CallArgList::CallArgCleanup>::reverse_iterator
+ I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) {
+ CGF.DeactivateCleanupBlock(I->Cleanup, I->IsActiveIP);
+ I->IsActiveIP->eraseFromParent();
+ }
+}
+
static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
if (uop->getOpcode() == UO_AddrOf)
@@ -1930,7 +1961,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// Perform a copy if necessary.
if (shouldCopy) {
- RValue srcRV = CGF.EmitLoadOfLValue(srcLV);
+ RValue srcRV = CGF.EmitLoadOfLValue(srcLV, SourceLocation());
assert(srcRV.isScalar());
llvm::Value *src = srcRV.getScalarVal();
@@ -1987,16 +2018,47 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
if (E->isGLValue()) {
assert(E->getObjectKind() == OK_Ordinary);
- return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
- type);
+ return args.add(EmitReferenceBindingToExpr(E), type);
+ }
+
+ bool HasAggregateEvalKind = hasAggregateEvaluationKind(type);
+
+ // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
+ // However, we still have to push an EH-only cleanup in case we unwind before
+ // we make it to the call.
+ if (HasAggregateEvalKind &&
+ CGM.getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+ if (RD && RD->hasNonTrivialDestructor()) {
+ AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp");
+ Slot.setExternallyDestructed();
+ EmitAggExpr(E, Slot);
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+
+ pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject,
+ /*useEHCleanupForArray*/ true);
+ // This unreachable is a temporary marker which will be removed later.
+ llvm::Instruction *IsActive = Builder.CreateUnreachable();
+ args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive);
+ return;
+ }
}
- if (hasAggregateEvaluationKind(type) &&
- isa<ImplicitCastExpr>(E) &&
+ if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
assert(L.isSimple());
- args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true);
+ if (L.getAlignment() >= getContext().getTypeAlignInChars(type)) {
+ args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true);
+ } else {
+ // We can't represent a misaligned lvalue in the CallArgList, so copy
+ // to an aligned temporary now.
+ llvm::Value *tmp = CreateMemTemp(type);
+ EmitAggregateCopy(tmp, L.getAddress(), type, L.isVolatile(),
+ L.getAlignment());
+ args.add(RValue::getAggregate(tmp), type);
+ }
return;
}
@@ -2127,7 +2189,7 @@ static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
}
void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
- SmallVector<llvm::Value*,16> &Args,
+ SmallVectorImpl<llvm::Value *> &Args,
llvm::FunctionType *IRFuncTy) {
if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
unsigned NumElts = AT->getSize().getZExtValue();
@@ -2135,7 +2197,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *Addr = RV.getAggregateAddr();
for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
- RValue EltRV = convertTempToRValue(EltAddr, EltTy);
+ RValue EltRV = convertTempToRValue(EltAddr, EltTy, SourceLocation());
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
}
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -2159,7 +2221,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
}
}
if (LargestFD) {
- RValue FldRV = EmitRValueForField(LV, LargestFD);
+ RValue FldRV = EmitRValueForField(LV, LargestFD, SourceLocation());
ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy);
}
} else {
@@ -2167,7 +2229,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
i != e; ++i) {
FieldDecl *FD = *i;
- RValue FldRV = EmitRValueForField(LV, FD);
+ RValue FldRV = EmitRValueForField(LV, FD, SourceLocation());
ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy);
}
}
@@ -2394,6 +2456,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
+ if (!CallArgs.getCleanupsToDeactivate().empty())
+ deactivateArgCleanupsBeforeCall(*this, CallArgs);
+
// If the callee is a bitcast of a function to a varargs pointer to function
// type, check to see if we can remove the bitcast. This handles some cases
// with unprototyped functions.
@@ -2482,7 +2547,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect:
- return convertTempToRValue(Args[0], RetTy);
+ return convertTempToRValue(Args[0], RetTy, SourceLocation());
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
@@ -2540,7 +2605,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- return convertTempToRValue(DestPtr, RetTy);
+ return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}
case ABIArgInfo::Expand:
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 85c3320ec0ee..532cb59c62e5 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -16,6 +16,7 @@
#define CLANG_CODEGEN_CGCALL_H
#include "CGValue.h"
+#include "EHScopeStack.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/FoldingSet.h"
@@ -67,6 +68,14 @@ namespace CodeGen {
llvm::Value *ToUse;
};
+ struct CallArgCleanup {
+ EHScopeStack::stable_iterator Cleanup;
+
+ /// The "is active" insertion point. This instruction is temporary and
+ /// will be removed after insertion.
+ llvm::Instruction *IsActiveIP;
+ };
+
void add(RValue rvalue, QualType type, bool needscopy = false) {
push_back(CallArg(rvalue, type, needscopy));
}
@@ -92,57 +101,25 @@ namespace CodeGen {
writeback_iterator writeback_begin() const { return Writebacks.begin(); }
writeback_iterator writeback_end() const { return Writebacks.end(); }
- private:
- SmallVector<Writeback, 1> Writebacks;
- };
-
- /// A class for recording the number of arguments that a function
- /// signature requires.
- class RequiredArgs {
- /// The number of required arguments, or ~0 if the signature does
- /// not permit optional arguments.
- unsigned NumRequired;
- public:
- enum All_t { All };
-
- RequiredArgs(All_t _) : NumRequired(~0U) {}
- explicit RequiredArgs(unsigned n) : NumRequired(n) {
- assert(n != ~0U);
- }
-
- /// Compute the arguments required by the given formal prototype,
- /// given that there may be some additional, non-formal arguments
- /// in play.
- static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype,
- unsigned additional) {
- if (!prototype->isVariadic()) return All;
- return RequiredArgs(prototype->getNumArgs() + additional);
- }
-
- static RequiredArgs forPrototype(const FunctionProtoType *prototype) {
- return forPrototypePlus(prototype, 0);
- }
-
- static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) {
- return forPrototype(prototype.getTypePtr());
+ void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
+ llvm::Instruction *IsActiveIP) {
+ CallArgCleanup ArgCleanup;
+ ArgCleanup.Cleanup = Cleanup;
+ ArgCleanup.IsActiveIP = IsActiveIP;
+ CleanupsToDeactivate.push_back(ArgCleanup);
}
- static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype,
- unsigned additional) {
- return forPrototypePlus(prototype.getTypePtr(), additional);
+ ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const {
+ return CleanupsToDeactivate;
}
- bool allowsOptionalArgs() const { return NumRequired != ~0U; }
- unsigned getNumRequiredArgs() const {
- assert(allowsOptionalArgs());
- return NumRequired;
- }
+ private:
+ SmallVector<Writeback, 1> Writebacks;
- unsigned getOpaqueData() const { return NumRequired; }
- static RequiredArgs getFromOpaqueData(unsigned value) {
- if (value == ~0U) return All;
- return RequiredArgs(value);
- }
+ /// Deactivate these cleanups immediately before making the call. This
+ /// is used to cleanup objects that are owned by the callee once the call
+ /// occurs.
+ SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
};
/// FunctionArgList - Type for representing both the decl and type
@@ -151,137 +128,6 @@ namespace CodeGen {
class FunctionArgList : public SmallVector<const VarDecl*, 16> {
};
- /// CGFunctionInfo - Class to encapsulate the information about a
- /// function definition.
- class CGFunctionInfo : public llvm::FoldingSetNode {
- struct ArgInfo {
- CanQualType type;
- ABIArgInfo info;
- };
-
- /// The LLVM::CallingConv to use for this function (as specified by the
- /// user).
- unsigned CallingConvention : 8;
-
- /// The LLVM::CallingConv to actually use for this function, which may
- /// depend on the ABI.
- unsigned EffectiveCallingConvention : 8;
-
- /// The clang::CallingConv that this was originally created with.
- unsigned ASTCallingConvention : 8;
-
- /// Whether this function is noreturn.
- unsigned NoReturn : 1;
-
- /// Whether this function is returns-retained.
- unsigned ReturnsRetained : 1;
-
- /// How many arguments to pass inreg.
- unsigned HasRegParm : 1;
- unsigned RegParm : 4;
-
- RequiredArgs Required;
-
- unsigned NumArgs;
- ArgInfo *getArgsBuffer() {
- return reinterpret_cast<ArgInfo*>(this+1);
- }
- const ArgInfo *getArgsBuffer() const {
- return reinterpret_cast<const ArgInfo*>(this + 1);
- }
-
- CGFunctionInfo() : Required(RequiredArgs::All) {}
-
- public:
- static CGFunctionInfo *create(unsigned llvmCC,
- const FunctionType::ExtInfo &extInfo,
- CanQualType resultType,
- ArrayRef<CanQualType> argTypes,
- RequiredArgs required);
-
- typedef const ArgInfo *const_arg_iterator;
- typedef ArgInfo *arg_iterator;
-
- const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
- const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
- arg_iterator arg_begin() { return getArgsBuffer() + 1; }
- arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
-
- unsigned arg_size() const { return NumArgs; }
-
- bool isVariadic() const { return Required.allowsOptionalArgs(); }
- RequiredArgs getRequiredArgs() const { return Required; }
-
- bool isNoReturn() const { return NoReturn; }
-
- /// In ARC, whether this function retains its return value. This
- /// is not always reliable for call sites.
- bool isReturnsRetained() const { return ReturnsRetained; }
-
- /// getASTCallingConvention() - Return the AST-specified calling
- /// convention.
- CallingConv getASTCallingConvention() const {
- return CallingConv(ASTCallingConvention);
- }
-
- /// getCallingConvention - Return the user specified calling
- /// convention, which has been translated into an LLVM CC.
- unsigned getCallingConvention() const { return CallingConvention; }
-
- /// getEffectiveCallingConvention - Return the actual calling convention to
- /// use, which may depend on the ABI.
- unsigned getEffectiveCallingConvention() const {
- return EffectiveCallingConvention;
- }
- void setEffectiveCallingConvention(unsigned Value) {
- EffectiveCallingConvention = Value;
- }
-
- bool getHasRegParm() const { return HasRegParm; }
- unsigned getRegParm() const { return RegParm; }
-
- FunctionType::ExtInfo getExtInfo() const {
- return FunctionType::ExtInfo(isNoReturn(),
- getHasRegParm(), getRegParm(),
- getASTCallingConvention(),
- isReturnsRetained());
- }
-
- CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
-
- ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
- const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- ID.AddInteger(getASTCallingConvention());
- ID.AddBoolean(NoReturn);
- ID.AddBoolean(ReturnsRetained);
- ID.AddBoolean(HasRegParm);
- ID.AddInteger(RegParm);
- ID.AddInteger(Required.getOpaqueData());
- getReturnType().Profile(ID);
- for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
- it->type.Profile(ID);
- }
- static void Profile(llvm::FoldingSetNodeID &ID,
- const FunctionType::ExtInfo &info,
- RequiredArgs required,
- CanQualType resultType,
- ArrayRef<CanQualType> argTypes) {
- ID.AddInteger(info.getCC());
- ID.AddBoolean(info.getNoReturn());
- ID.AddBoolean(info.getProducesResult());
- ID.AddBoolean(info.getHasRegParm());
- ID.AddInteger(info.getRegParm());
- ID.AddInteger(required.getOpaqueData());
- resultType.Profile(ID);
- for (ArrayRef<CanQualType>::iterator
- i = argTypes.begin(), e = argTypes.end(); i != e; ++i) {
- i->Profile(ID);
- }
- }
- };
-
/// ReturnValueSlot - Contains the address where the return value of a
/// function can be stored, and whether the address is volatile or not.
class ReturnValueSlot {
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 3fd075701d03..4848d7565d40 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -17,10 +17,12 @@
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
using namespace clang;
@@ -198,7 +200,8 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
// Compute the virtual offset.
llvm::Value *VirtualOffset = 0;
if (VBase) {
- VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
+ VirtualOffset =
+ CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase);
}
// Apply both offsets.
@@ -285,7 +288,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
bool ForVirtualBase,
bool Delegating) {
- if (!CodeGenVTables::needsVTTParameter(GD)) {
+ if (!CGM.getCXXABI().NeedsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
}
@@ -303,7 +306,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
} else if (RD == Base) {
// If the record matches the base, this is the complete ctor/dtor
// variant calling the base variant in a class with virtual bases.
- assert(!CodeGenVTables::needsVTTParameter(CurGD) &&
+ assert(!CGM.getCXXABI().NeedsVTTParameter(CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
assert(!ForVirtualBase && "Can't have same class as virtual base!");
SubVTTIndex = 0;
@@ -318,7 +321,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
- if (CodeGenVTables::needsVTTParameter(CurGD)) {
+ if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
// A VTT parameter was passed to the constructor, use it.
VTT = LoadCXXVTT();
VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
@@ -432,52 +435,45 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
unsigned Index) {
if (Index == ArrayIndexes.size()) {
LValue LV = LHS;
- { // Scope for Cleanups.
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- if (ArrayIndexVar) {
- // If we have an array index variable, load it and use it as an offset.
- // Then, increment the value.
- llvm::Value *Dest = LHS.getAddress();
- llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
- Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
- llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
- Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
- CGF.Builder.CreateStore(Next, ArrayIndexVar);
-
- // Update the LValue.
- LV.setAddress(Dest);
- CharUnits Align = CGF.getContext().getTypeAlignInChars(T);
- LV.setAlignment(std::min(Align, LV.getAlignment()));
- }
- switch (CGF.getEvaluationKind(T)) {
- case TEK_Scalar:
- CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
- break;
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
- break;
- case TEK_Aggregate: {
- AggValueSlot Slot =
- AggValueSlot::forLValue(LV,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
-
- CGF.EmitAggExpr(Init, Slot);
- break;
- }
- }
+ if (ArrayIndexVar) {
+ // If we have an array index variable, load it and use it as an offset.
+ // Then, increment the value.
+ llvm::Value *Dest = LHS.getAddress();
+ llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
+ Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
+ llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
+ Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
+ CGF.Builder.CreateStore(Next, ArrayIndexVar);
+
+ // Update the LValue.
+ LV.setAddress(Dest);
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(T);
+ LV.setAlignment(std::min(Align, LV.getAlignment()));
}
- // Now, outside of the initializer cleanup scope, destroy the backing array
- // for a std::initializer_list member.
- CGF.MaybeEmitStdInitializerListCleanup(LV.getAddress(), Init);
+ switch (CGF.getEvaluationKind(T)) {
+ case TEK_Scalar:
+ CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
+ break;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
+ AggValueSlot Slot =
+ AggValueSlot::forLValue(LV,
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+
+ CGF.EmitAggExpr(Init, Slot);
+ break;
+ }
+ }
return;
}
-
+
const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
assert(Array && "Array initialization without the array type?");
llvm::Value *IndexVar
@@ -511,16 +507,12 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.EmitBlock(ForBody);
llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
-
- {
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- // Inside the loop body recurse to emit the inner loop or, eventually, the
- // constructor call.
- EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
- Array->getElementType(), ArrayIndexes, Index + 1);
- }
-
+
+ // Inside the loop body recurse to emit the inner loop or, eventually, the
+ // constructor call.
+ EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
+ Array->getElementType(), ArrayIndexes, Index + 1);
+
CGF.EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -573,7 +565,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// in the AST, we could generalize it more easily.
const ConstantArrayType *Array
= CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array && Constructor->isImplicitlyDefined() &&
+ if (Array && Constructor->isDefaulted() &&
Constructor->isCopyOrMoveConstructor()) {
QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
@@ -713,7 +705,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
CGM.getTarget().getCXXABI().hasConstructorVariants()) {
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, Ctor->getLocEnd());
- EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
+ EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd());
return;
}
@@ -725,7 +717,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
if (IsTryBody)
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
- EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
+ RunCleanupsScope RunCleanups(*this);
// TODO: in restricted cases, we can emit the vbase initializers of
// a complete ctor and then delegate to the base ctor.
@@ -744,13 +736,36 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// initializers, which includes (along the exceptional path) the
// destructors for those members and bases that were fully
// constructed.
- PopCleanupBlocks(CleanupDepth);
+ RunCleanups.ForceCleanup();
if (IsTryBody)
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
namespace {
+ /// RAII object to indicate that codegen is copying the value representation
+ /// instead of the object representation. Useful when copying a struct or
+ /// class which has uninitialized members and we're only performing
+ /// lvalue-to-rvalue conversion on the object but not its members.
+ class CopyingValueRepresentation {
+ public:
+ explicit CopyingValueRepresentation(CodeGenFunction &CGF)
+ : CGF(CGF), SO(*CGF.SanOpts), OldSanOpts(CGF.SanOpts) {
+ SO.Bool = false;
+ SO.Enum = false;
+ CGF.SanOpts = &SO;
+ }
+ ~CopyingValueRepresentation() {
+ CGF.SanOpts = OldSanOpts;
+ }
+ private:
+ CodeGenFunction &CGF;
+ SanitizerOptions SO;
+ const SanitizerOptions *OldSanOpts;
+ };
+}
+
+namespace {
class FieldMemcpyizer {
public:
FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl,
@@ -859,8 +874,12 @@ namespace {
}
void addNextField(FieldDecl *F) {
- assert(F->getFieldIndex() == LastAddedFieldIndex + 1 &&
- "Cannot aggregate non-contiguous fields.");
+ // For the most part, the following invariant will hold:
+ // F->getFieldIndex() == LastAddedFieldIndex + 1
+ // The one exception is that Sema won't add a copy-initializer for an
+ // unnamed bitfield, which will show up here as a gap in the sequence.
+ assert(F->getFieldIndex() >= LastAddedFieldIndex + 1 &&
+ "Cannot aggregate fields out of order.");
LastAddedFieldIndex = F->getFieldIndex();
// The 'first' and 'last' fields are chosen by offset, rather than field
@@ -891,7 +910,7 @@ namespace {
/// constructor.
static const VarDecl* getTrivialCopySource(const CXXConstructorDecl *CD,
FunctionArgList &Args) {
- if (CD->isCopyOrMoveConstructor() && CD->isImplicitlyDefined())
+ if (CD->isCopyOrMoveConstructor() && CD->isDefaulted())
return Args[Args.size() - 1];
return 0;
}
@@ -925,7 +944,7 @@ namespace {
FunctionArgList &Args)
: FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CD, Args)),
ConstructorDecl(CD),
- MemcpyableCtor(CD->isImplicitlyDefined() &&
+ MemcpyableCtor(CD->isDefaulted() &&
CD->isCopyOrMoveConstructor() &&
CGF.getLangOpts().getGC() == LangOptions::NonGC),
Args(Args) { }
@@ -945,9 +964,10 @@ namespace {
if (AggregatedInits.size() <= 1) {
// This memcpy is too small to be worthwhile. Fall back on default
// codegen.
- for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
+ if (!AggregatedInits.empty()) {
+ CopyingValueRepresentation CVR(CGF);
EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
- AggregatedInits[i], ConstructorDecl, Args);
+ AggregatedInits[0], ConstructorDecl, Args);
}
reset();
return;
@@ -986,8 +1006,8 @@ namespace {
private:
// Returns the memcpyable field copied by the given statement, if one
- // exists. Otherwise r
- FieldDecl* getMemcpyableField(Stmt *S) {
+ // exists. Otherwise returns null.
+ FieldDecl *getMemcpyableField(Stmt *S) {
if (!AssignmentsMemcpyable)
return 0;
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
@@ -1081,8 +1101,10 @@ namespace {
void emitAggregatedStmts() {
if (AggregatedStmts.size() <= 1) {
- for (unsigned i = 0; i < AggregatedStmts.size(); ++i)
- CGF.EmitStmt(AggregatedStmts[i]);
+ if (!AggregatedStmts.empty()) {
+ CopyingValueRepresentation CVR(CGF);
+ CGF.EmitStmt(AggregatedStmts[0]);
+ }
reset();
}
@@ -1115,7 +1137,8 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
!CGM.getTarget().getCXXABI().hasConstructorVariants()) {
// The ABIs that don't have constructor variants need to put a branch
// before the virtual base initialization code.
- BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this);
+ BaseCtorContinueBB =
+ CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this, ClassDecl);
assert(BaseCtorContinueBB);
}
@@ -1270,16 +1293,19 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// If this is the complete variant, just invoke the base variant;
// the epilogue will destruct the virtual bases. But we can't do
// this optimization if the body is a function-try-block, because
- // we'd introduce *two* handler blocks.
+ // we'd introduce *two* handler blocks. In the Microsoft ABI, we
+ // always delegate because we might not have a definition in this TU.
switch (DtorType) {
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
case Dtor_Complete:
+ assert((Body || getTarget().getCXXABI().isMicrosoft()) &&
+ "can't emit a dtor without a body for non-Microsoft ABIs");
+
// Enter the cleanup scopes for virtual bases.
EnterDtorCleanups(Dtor, Dtor_Complete);
- if (!isTryBody &&
- CGM.getTarget().getCXXABI().hasDestructorVariants()) {
+ if (!isTryBody) {
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThis());
break;
@@ -1287,6 +1313,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// Fallthrough: act like we're in the base variant.
case Dtor_Base:
+ assert(Body);
+
// Enter the cleanup scopes for fields and non-virtual bases.
EnterDtorCleanups(Dtor, Dtor_Base);
@@ -1635,17 +1663,6 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI &&
- CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) {
- // If debug info for this class has not been emitted then this is the
- // right time to do so.
- const CXXRecordDecl *Parent = D->getParent();
- DI->getOrCreateRecordType(CGM.getContext().getTypeDeclType(Parent),
- Parent->getLocation());
- }
-
// If this is a trivial constructor, just emit what's needed.
if (D->isTrivial()) {
if (ArgBeg == ArgEnd) {
@@ -1667,11 +1684,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
// Non-trivial constructors are handled in an ABI-specific manner.
- llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
- ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
- CalleeWithThisReturn = Callee;
+ CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
+ Delegating, This, ArgBeg, ArgEnd);
}
void
@@ -1686,8 +1700,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
EmitAggregateCopy(This, Src, (*ArgBeg)->getType());
return;
}
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D,
- clang::Ctor_Complete);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, clang::Ctor_Complete);
assert(D->isInstance() &&
"Trying to emit a member call expr on a static method!");
@@ -1730,7 +1743,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
void
CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
- const FunctionArgList &Args) {
+ const FunctionArgList &Args,
+ SourceLocation Loc) {
CallArgList DelegateArgs;
FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
@@ -1747,7 +1761,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.add(RValue::get(VTT), VoidPP);
- if (CodeGenVTables::needsVTTParameter(CurGD)) {
+ if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
assert(I != E && "cannot skip vtt parameter, already done with args");
assert((*I)->getType() == VoidPP && "skipping parameter not of vtt type");
++I;
@@ -1757,15 +1771,13 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
// Explicit arguments.
for (; I != E; ++I) {
const VarDecl *param = *I;
- EmitDelegateCallArg(DelegateArgs, param);
+ // FIXME: per-argument source location
+ EmitDelegateCallArg(DelegateArgs, param, Loc);
}
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
- CalleeWithThisReturn = Callee;
}
namespace {
@@ -1818,8 +1830,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
bool ForVirtualBase,
bool Delegating,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type),
- ForVirtualBase, Delegating);
+ GlobalDecl GD(DD, Type);
+ llvm::Value *VTT = GetVTTParameter(GD, ForVirtualBase, Delegating);
llvm::Value *Callee = 0;
if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
@@ -1827,14 +1839,14 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
if (!Callee)
Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
-
+
+ if (DD->isVirtual())
+ This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, GD, This);
+
// FIXME: Provide a source location here.
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
- CalleeWithThisReturn = Callee;
}
namespace {
@@ -1868,69 +1880,30 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) {
PushDestructorCleanup(D, Addr);
}
-llvm::Value *
-CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy);
- CharUnits VBaseOffsetOffset =
- CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
-
- llvm::Value *VBaseOffsetPtr =
- Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
- "vbase.offset.ptr");
- llvm::Type *PtrDiffTy =
- ConvertType(getContext().getPointerDiffType());
-
- VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
- PtrDiffTy->getPointerTo());
-
- llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
-
- return VBaseOffset;
-}
-
void
CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
CharUnits OffsetFromNearestVBase,
- llvm::Constant *VTable,
const CXXRecordDecl *VTableClass) {
- const CXXRecordDecl *RD = Base.getBase();
-
// Compute the address point.
- llvm::Value *VTableAddressPoint;
-
- // Check if we need to use a vtable from the VTT.
- if (CodeGenVTables::needsVTTParameter(CurGD) &&
- (RD->getNumVBases() || NearestVBase)) {
- // Get the secondary vpointer index.
- uint64_t VirtualPointerIndex =
- CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
-
- /// Load the VTT.
- llvm::Value *VTT = LoadCXXVTT();
- if (VirtualPointerIndex)
- VTT = Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
-
- // And load the address point from the VTT.
- VTableAddressPoint = Builder.CreateLoad(VTT);
- } else {
- uint64_t AddressPoint =
- CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
- VTableAddressPoint =
- Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
- }
+ bool NeedsVirtualOffset;
+ llvm::Value *VTableAddressPoint =
+ CGM.getCXXABI().getVTableAddressPointInStructor(
+ *this, VTableClass, Base, NearestVBase, NeedsVirtualOffset);
+ if (!VTableAddressPoint)
+ return;
// Compute where to store the address point.
llvm::Value *VirtualOffset = 0;
CharUnits NonVirtualOffset = CharUnits::Zero();
- if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) {
+ if (NeedsVirtualOffset) {
// We need to use the virtual base offset offset because the virtual base
// might have a different offset in the most derived class.
- VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass,
- NearestVBase);
+ VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(*this,
+ LoadCXXThis(),
+ VTableClass,
+ NearestVBase);
NonVirtualOffset = OffsetFromNearestVBase;
} else {
// We can just use the base offset in the complete class.
@@ -1958,7 +1931,6 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
CharUnits OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
- llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
VisitedVirtualBasesSetTy& VBases) {
// If this base is a non-virtual primary base the address point has already
@@ -1966,7 +1938,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
if (!BaseIsNonVirtualPrimaryBase) {
// Initialize the vtable pointer for this base.
InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase,
- VTable, VTableClass);
+ VTableClass);
}
const CXXRecordDecl *RD = Base.getBase();
@@ -2009,7 +1981,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
I->isVirtual() ? BaseDecl : NearestVBase,
BaseOffsetFromNearestVBase,
BaseDeclIsNonVirtualPrimaryBase,
- VTable, VTableClass, VBases);
+ VTableClass, VBases);
}
}
@@ -2018,16 +1990,15 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
if (!RD->isDynamicClass())
return;
- // Get the VTable.
- llvm::Constant *VTable = CGM.getVTables().GetAddrOfVTable(RD);
-
// Initialize the vtable pointers for this class and all of its bases.
VisitedVirtualBasesSetTy VBases;
InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()),
/*NearestVBase=*/0,
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
- /*BaseIsNonVirtualPrimaryBase=*/false,
- VTable, RD, VBases);
+ /*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
+
+ if (RD->getNumVBases())
+ CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
}
llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
@@ -2038,29 +2009,6 @@ llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
return VTable;
}
-static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
- const Expr *E = Base;
-
- while (true) {
- E = E->IgnoreParens();
- if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if (CE->getCastKind() == CK_DerivedToBase ||
- CE->getCastKind() == CK_UncheckedDerivedToBase ||
- CE->getCastKind() == CK_NoOp) {
- E = CE->getSubExpr();
- continue;
- }
- }
-
- break;
- }
-
- QualType DerivedType = E->getType();
- if (const PointerType *PTy = DerivedType->getAs<PointerType>())
- DerivedType = PTy->getPointeeType();
-
- return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
-}
// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
// quite what we want.
@@ -2087,10 +2035,14 @@ static const Expr *skipNoOpCastsAndParens(const Expr *E) {
}
}
-/// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member
-/// function call on the given expr can be devirtualized.
-static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
- const CXXMethodDecl *MD) {
+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 most derived class is marked final, we know that no subclass can
// override this member function and so we can devirtualize it. For example:
//
@@ -2101,7 +2053,7 @@ static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
// b->f();
// }
//
- const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base);
+ const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
if (MostDerivedClassDecl->hasAttr<FinalAttr>())
return true;
@@ -2124,7 +2076,14 @@ static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
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();
+
// We can always devirtualize calls on temporary object expressions.
if (isa<CXXConstructExpr>(Base))
return true;
@@ -2141,20 +2100,6 @@ static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
return false;
}
-static bool UseVirtualCall(ASTContext &Context,
- const CXXOperatorCallExpr *CE,
- const CXXMethodDecl *MD) {
- if (!MD->isVirtual())
- return false;
-
- // When building with -fapple-kext, all calls must go through the vtable since
- // the kernel linker can do runtime patching of vtables.
- if (Context.getLangOpts().AppleKext)
- return true;
-
- return !canDevirtualizeMemberFunctionCall(CE->getArg(0), MD);
-}
-
llvm::Value *
CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
@@ -2163,20 +2108,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodDeclaration(MD));
- if (UseVirtualCall(getContext(), E, MD))
- return BuildVirtualCall(MD, This, fnType);
+ if (MD->isVirtual() && !CanDevirtualizeMemberFunctionCall(E->getArg(0), MD))
+ return CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, fnType);
return CGM.GetAddrOfFunction(MD, fnType);
}
-void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
- CallArgList &callArgs) {
- // Lookup the call operator
- DeclarationName operatorName
- = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
- CXXMethodDecl *callOperator =
- cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
-
+void CodeGenFunction::EmitForwardingCallToLambda(
+ const CXXMethodDecl *callOperator,
+ CallArgList &callArgs) {
// Get the address of the call operator.
const CGFunctionInfo &calleeFnInfo =
CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);
@@ -2225,10 +2165,11 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
for (BlockDecl::param_const_iterator I = BD->param_begin(),
E = BD->param_end(); I != E; ++I) {
ParmVarDecl *param = *I;
- EmitDelegateCallArg(CallArgs, param);
+ EmitDelegateCallArg(CallArgs, param, param->getLocStart());
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ assert(!Lambda->isGenericLambda() &&
+ "generic lambda interconversion to block not implemented");
+ EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
}
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
@@ -2239,7 +2180,7 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
return;
}
- EmitFunctionBody(Args);
+ EmitFunctionBody(Args, cast<FunctionDecl>(CurGD.getDecl())->getBody());
}
void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
@@ -2256,10 +2197,22 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
E = MD->param_end(); I != E; ++I) {
ParmVarDecl *param = *I;
- EmitDelegateCallArg(CallArgs, param);
+ EmitDelegateCallArg(CallArgs, param, param->getLocStart());
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
+ // For a generic lambda, find the corresponding call operator specialization
+ // to which the call to the static-invoker shall be forwarded.
+ if (Lambda->isGenericLambda()) {
+ assert(MD->isFunctionTemplateSpecialization());
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos);
+ assert(CorrespondingCallOpSpecialization);
+ CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ }
+ EmitForwardingCallToLambda(CallOp, CallArgs);
}
void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index ba6b56c2676f..65de4d498d1a 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -17,8 +17,8 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGCleanup.h"
+#include "CodeGenFunction.h"
using namespace clang;
using namespace CodeGen;
@@ -371,8 +371,7 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
}
/// Pops cleanup blocks until the given savepoint is reached.
-void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
- SourceLocation EHLoc) {
+void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
assert(Old.isValid());
while (EHStack.stable_begin() != Old) {
@@ -384,8 +383,35 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
bool FallThroughIsBranchThrough =
Old.strictlyEncloses(Scope.getEnclosingNormalCleanup());
- PopCleanupBlock(FallThroughIsBranchThrough, EHLoc);
+ PopCleanupBlock(FallThroughIsBranchThrough);
+ }
+}
+
+/// Pops cleanup blocks until the given savepoint is reached, then add the
+/// cleanups from the given savepoint in the lifetime-extended cleanups stack.
+void
+CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
+ size_t OldLifetimeExtendedSize) {
+ PopCleanupBlocks(Old);
+
+ // Move our deferred cleanups onto the EH stack.
+ for (size_t I = OldLifetimeExtendedSize,
+ E = LifetimeExtendedCleanupStack.size(); I != E; /**/) {
+ // Alignment should be guaranteed by the vptrs in the individual cleanups.
+ assert((I % llvm::alignOf<LifetimeExtendedCleanupHeader>() == 0) &&
+ "misaligned cleanup stack entry");
+
+ LifetimeExtendedCleanupHeader &Header =
+ reinterpret_cast<LifetimeExtendedCleanupHeader&>(
+ LifetimeExtendedCleanupStack[I]);
+ I += sizeof(Header);
+
+ EHStack.pushCopyOfCleanup(Header.getKind(),
+ &LifetimeExtendedCleanupStack[I],
+ Header.getSize());
+ I += Header.getSize();
}
+ LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);
}
static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
@@ -533,8 +559,7 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
/// Pops a cleanup block. If the block includes a normal cleanup, the
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
-void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
- SourceLocation EHLoc) {
+void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
assert(!EHStack.empty() && "cleanup stack is empty!");
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
@@ -836,7 +861,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
// Emit the EH cleanup if required.
if (RequiresEHCleanup) {
if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, EHLoc);
+ DI->EmitLocation(Builder, CurEHLocation);
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index d8dbe41bf0f3..1bd6bba523fb 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -14,13 +14,15 @@
#ifndef CLANG_CODEGEN_CGCLEANUP_H
#define CLANG_CODEGEN_CGCLEANUP_H
-/// EHScopeStack is defined in CodeGenFunction.h, but its
-/// implementation is in this file and in CGCleanup.cpp.
-#include "CodeGenFunction.h"
+#include "EHScopeStack.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
namespace llvm {
- class Value;
- class BasicBlock;
+class BasicBlock;
+class Value;
+class ConstantInt;
+class AllocaInst;
}
namespace clang {
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index ddcb931e46c5..fcb26f0da615 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -13,6 +13,7 @@
#include "CGDebugInfo.h"
#include "CGBlocks.h"
+#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
@@ -36,12 +37,13 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
using namespace clang;
using namespace clang::CodeGen;
CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
- : CGM(CGM), DBuilder(CGM.getModule()),
- BlockLiteralGenericSet(false) {
+ : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
+ DBuilder(CGM.getModule()) {
CreateCompileUnit();
}
@@ -50,9 +52,54 @@ CGDebugInfo::~CGDebugInfo() {
"Region stack mismatch, stack not empty!");
}
+
+NoLocation::NoLocation(CodeGenFunction &CGF, CGBuilderTy &B)
+ : DI(CGF.getDebugInfo()), Builder(B) {
+ if (DI) {
+ SavedLoc = DI->getLocation();
+ DI->CurLoc = SourceLocation();
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+ }
+}
+
+NoLocation::~NoLocation() {
+ if (DI) {
+ assert(Builder.getCurrentDebugLocation().isUnknown());
+ DI->CurLoc = SavedLoc;
+ }
+}
+
+ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B)
+ : DI(CGF.getDebugInfo()), Builder(B) {
+ if (DI) {
+ SavedLoc = DI->getLocation();
+ DI->CurLoc = SourceLocation();
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+ }
+}
+
+void ArtificialLocation::Emit() {
+ if (DI) {
+ // Sync the Builder.
+ DI->EmitLocation(Builder, SavedLoc);
+ DI->CurLoc = SourceLocation();
+ // Construct a location that has a valid scope, but no line info.
+ assert(!DI->LexicalBlockStack.empty());
+ llvm::DIDescriptor Scope(DI->LexicalBlockStack.back());
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, Scope));
+ }
+}
+
+ArtificialLocation::~ArtificialLocation() {
+ if (DI) {
+ assert(Builder.getCurrentDebugLocation().getLine() == 0);
+ DI->CurLoc = SavedLoc;
+ }
+}
+
void CGDebugInfo::setLocation(SourceLocation Loc) {
// If the new location isn't valid return.
- if (!Loc.isValid()) return;
+ if (Loc.isInvalid()) return;
CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
@@ -112,7 +159,7 @@ llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) {
}
/// getFunctionName - Get function name for the given FunctionDecl. If the
-/// name is constructred on demand (e.g. C++ destructor) then the name
+/// name is constructed on demand (e.g. C++ destructor) then the name
/// is stored on the side.
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
assert (FD && "Invalid FunctionDecl!");
@@ -138,10 +185,7 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
}
// Copy this name on the side and use its reference.
- OS.flush();
- char *StrPtr = DebugInfoNames.Allocate<char>(NS.size());
- memcpy(StrPtr, NS.data(), NS.size());
- return StringRef(StrPtr, NS.size());
+ return internString(OS.str());
}
StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
@@ -149,35 +193,37 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
llvm::raw_svector_ostream OS(MethodName);
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
const DeclContext *DC = OMD->getDeclContext();
- if (const ObjCImplementationDecl *OID =
+ if (const ObjCImplementationDecl *OID =
dyn_cast<const ObjCImplementationDecl>(DC)) {
OS << OID->getName();
- } else if (const ObjCInterfaceDecl *OID =
+ } else if (const ObjCInterfaceDecl *OID =
dyn_cast<const ObjCInterfaceDecl>(DC)) {
OS << OID->getName();
- } else if (const ObjCCategoryImplDecl *OCD =
+ } else if (const ObjCCategoryImplDecl *OCD =
dyn_cast<const ObjCCategoryImplDecl>(DC)){
OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
OCD->getIdentifier()->getNameStart() << ')';
+ } else if (isa<ObjCProtocolDecl>(DC)) {
+ // We can extract the type of the class from the self pointer.
+ if (ImplicitParamDecl* SelfDecl = OMD->getSelfDecl()) {
+ QualType ClassTy =
+ cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
+ ClassTy.print(OS, PrintingPolicy(LangOptions()));
+ }
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
- char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
- memcpy(StrPtr, MethodName.begin(), OS.tell());
- return StringRef(StrPtr, OS.tell());
+ return internString(OS.str());
}
/// getSelectorName - Return selector name. This is used for debugging
/// info.
StringRef CGDebugInfo::getSelectorName(Selector S) {
- const std::string &SName = S.getAsString();
- char *StrPtr = DebugInfoNames.Allocate<char>(SName.size());
- memcpy(StrPtr, SName.data(), SName.size());
- return StringRef(StrPtr, SName.size());
+ return internString(S.getAsString());
}
/// getClassName - Get class name including template argument list.
-StringRef
+StringRef
CGDebugInfo::getClassName(const RecordDecl *RD) {
const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RD);
@@ -206,11 +252,7 @@ CGDebugInfo::getClassName(const RecordDecl *RD) {
}
// Copy this name on the side and use its reference.
- size_t Length = Name.size() + TemplateArgList.size();
- char *StrPtr = DebugInfoNames.Allocate<char>(Length);
- memcpy(StrPtr, Name.data(), Name.size());
- memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size());
- return StringRef(StrPtr, Length);
+ return internString(Name, TemplateArgList);
}
/// getOrCreateFile - Get the file debug info descriptor for the input location.
@@ -280,9 +322,7 @@ StringRef CGDebugInfo::getCurrentDirname() {
return CWDName;
SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
- char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
- memcpy(CompDirnamePtr, CWD.data(), CWD.size());
- return CWDName = StringRef(CompDirnamePtr, CWD.size());
+ return CWDName = internString(CWD);
}
/// CreateCompileUnit - Create new compile unit.
@@ -301,21 +341,20 @@ void CGDebugInfo::CreateCompileUnit() {
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
MainFileDir = MainFile->getDir()->getName();
- if (MainFileDir != ".")
- MainFileName = MainFileDir + "/" + MainFileName;
+ if (MainFileDir != ".") {
+ llvm::SmallString<1024> MainFileDirSS(MainFileDir);
+ llvm::sys::path::append(MainFileDirSS, MainFileName);
+ MainFileName = MainFileDirSS.str();
+ }
}
// Save filename string.
- char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
- memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
- StringRef Filename(FilenamePtr, MainFileName.length());
+ StringRef Filename = internString(MainFileName);
// Save split dwarf file string.
std::string SplitDwarfFile = CGM.getCodeGenOpts().SplitDwarfFile;
- char *SplitDwarfPtr = DebugInfoNames.Allocate<char>(SplitDwarfFile.length());
- memcpy(SplitDwarfPtr, SplitDwarfFile.c_str(), SplitDwarfFile.length());
- StringRef SplitDwarfFilename(SplitDwarfPtr, SplitDwarfFile.length());
-
+ StringRef SplitDwarfFilename = internString(SplitDwarfFile);
+
unsigned LangTag;
const LangOptions &LO = CGM.getLangOpts();
if (LO.CPlusPlus) {
@@ -339,12 +378,11 @@ void CGDebugInfo::CreateCompileUnit() {
RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
// Create new compile unit.
- DBuilder.createCompileUnit(LangTag, Filename, getCurrentDirname(),
- Producer, LO.Optimize,
- CGM.getCodeGenOpts().DwarfDebugFlags,
- RuntimeVers, SplitDwarfFilename);
// FIXME - Eliminate TheCU.
- TheCU = llvm::DICompileUnit(DBuilder.getCU());
+ TheCU = DBuilder.createCompileUnit(LangTag, Filename, getCurrentDirname(),
+ Producer, LO.Optimize,
+ CGM.getCodeGenOpts().DwarfDebugFlags,
+ RuntimeVers, SplitDwarfFilename);
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -360,12 +398,11 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Dependent:
llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
- return DBuilder.
- createNullPtrType(BT->getName(CGM.getLangOpts()));
+ return DBuilder.createNullPtrType();
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- if (ClassTy.Verify())
+ if (ClassTy)
return ClassTy;
ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_class", TheCU,
@@ -377,16 +414,16 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
// Class isa;
// } *id;
- if (ObjTy.Verify())
+ if (ObjTy)
return ObjTy;
- if (!ClassTy.Verify())
+ if (!ClassTy)
ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_class", TheCU,
getOrCreateMainFile(), 0);
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
-
+
llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
ObjTy =
@@ -398,7 +435,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
return ObjTy;
}
case BuiltinType::ObjCSel: {
- if (SelTy.Verify())
+ if (SelTy)
return SelTy;
SelTy =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
@@ -411,7 +448,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
return getOrCreateStructPtrType("opencl_image1d_t",
OCLImage1dDITy);
case BuiltinType::OCLImage1dArray:
- return getOrCreateStructPtrType("opencl_image1d_array_t",
+ return getOrCreateStructPtrType("opencl_image1d_array_t",
OCLImage1dArrayDITy);
case BuiltinType::OCLImage1dBuffer:
return getOrCreateStructPtrType("opencl_image1d_buffer_t",
@@ -471,7 +508,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(BT);
uint64_t Align = CGM.getContext().getTypeAlign(BT);
- llvm::DIType DbgTy =
+ llvm::DIType DbgTy =
DBuilder.createBasicType(BTName, Size, Align, Encoding);
return DbgTy;
}
@@ -484,7 +521,7 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- llvm::DIType DbgTy =
+ llvm::DIType DbgTy =
DBuilder.createBasicType("complex", Size, Align, Encoding);
return DbgTy;
@@ -523,7 +560,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// No need to fill in the Name, Line, Size, Alignment, Offset in case of
// CVR derived types.
llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy);
-
+
return DbgTy;
}
@@ -537,20 +574,48 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
llvm::DIType DbgTy =
- CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
}
+/// In C++ mode, types have linkage, so we can rely on the ODR and
+/// on their mangled names, if they're external.
+static SmallString<256>
+getUniqueTagTypeName(const TagType *Ty, CodeGenModule &CGM,
+ llvm::DICompileUnit TheCU) {
+ SmallString<256> FullName;
+ // FIXME: ODR should apply to ObjC++ exactly the same wasy it does to C++.
+ // For now, only apply ODR with C++.
+ const TagDecl *TD = Ty->getDecl();
+ if (TheCU.getLanguage() != llvm::dwarf::DW_LANG_C_plus_plus ||
+ !TD->isExternallyVisible())
+ return FullName;
+ // Microsoft Mangler does not have support for mangleCXXRTTIName yet.
+ if (CGM.getTarget().getCXXABI().isMicrosoft())
+ return FullName;
+
+ // TODO: This is using the RTTI name. Is there a better way to get
+ // a unique string for a type?
+ llvm::raw_svector_ostream Out(FullName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out);
+ Out.flush();
+ return FullName;
+}
+
// Creates a forward declaration for a RecordDecl in the given context.
-llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
- llvm::DIDescriptor Ctx) {
+llvm::DICompositeType
+CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
+ llvm::DIDescriptor Ctx) {
+ const RecordDecl *RD = Ty->getDecl();
+ if (llvm::DIType T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
+ return llvm::DICompositeType(T);
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
@@ -566,74 +631,18 @@ llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
}
// Create the type.
- return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line);
-}
-
-// Walk up the context chain and create forward decls for record decls,
-// and normal descriptors for namespaces.
-llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
- if (!Context)
- return TheCU;
-
- // See if we already have the parent.
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
- I = RegionMap.find(Context);
- if (I != RegionMap.end()) {
- llvm::Value *V = I->second;
- return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
- }
-
- // Check namespace.
- if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
-
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
- if (!RD->isDependentType()) {
- llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
- getOrCreateMainFile());
- return llvm::DIDescriptor(Ty);
- }
- }
- return TheCU;
-}
-
-/// CreatePointeeType - Create Pointee type. If Pointee is a record
-/// then emit record's fwd if debug info size reduction is enabled.
-llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
- llvm::DIFile Unit) {
- if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo)
- return getOrCreateType(PointeeTy, Unit);
-
- // Limit debug info for the pointee type.
-
- // If we have an existing type, use that, it's still smaller than creating
- // a new type.
- llvm::DIType Ty = getTypeOrNull(PointeeTy);
- if (Ty.Verify()) return Ty;
-
- // Handle qualifiers.
- if (PointeeTy.hasLocalQualifiers())
- return CreateQualifiedType(PointeeTy, Unit);
-
- if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) {
- RecordDecl *RD = RTy->getDecl();
- llvm::DIDescriptor FDContext =
- getContextDescriptor(cast<Decl>(RD->getDeclContext()));
- llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
- TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy;
- return RetTy;
- }
- return getOrCreateType(PointeeTy, Unit);
+ SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
+ return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line, 0, 0, 0,
+ FullName);
}
llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
- const Type *Ty,
+ const Type *Ty,
QualType PointeeTy,
llvm::DIFile Unit) {
if (Tag == llvm::dwarf::DW_TAG_reference_type ||
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
- return DBuilder.createReferenceType(Tag,
- CreatePointeeType(PointeeTy, Unit));
+ return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit));
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
@@ -642,25 +651,24 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
uint64_t Size = CGM.getTarget().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit),
- Size, Align);
+ return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
+ Align);
}
-llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache) {
- if (Cache.Verify())
- return Cache;
- Cache =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- Name, TheCU, getOrCreateMainFile(),
- 0);
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- Cache = DBuilder.createPointerType(Cache, Size);
+llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
+ llvm::DIType &Cache) {
+ if (Cache)
return Cache;
+ Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name,
+ TheCU, getOrCreateMainFile(), 0);
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ Cache = DBuilder.createPointerType(Cache, Size);
+ return Cache;
}
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIFile Unit) {
- if (BlockLiteralGenericSet)
+ if (BlockLiteralGeneric)
return BlockLiteralGeneric;
SmallVector<llvm::Value *, 8> EltTys;
@@ -716,7 +724,6 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
Unit, LineNo, FieldOffset, 0,
Flags, llvm::DIType(), Elements);
- BlockLiteralGenericSet = true;
BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
return BlockLiteralGeneric;
}
@@ -725,16 +732,16 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
// Typedefs are derived from some other type. If we have a typedef of a
// typedef, make sure to emit the whole chain.
llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
- if (!Src.Verify())
+ if (!Src)
return llvm::DIType();
// We don't set size information, but do specify where the typedef was
// declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
const TypedefNameDecl *TyDecl = Ty->getDecl();
-
+
llvm::DIDescriptor TypedefContext =
getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
-
+
return
DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
}
@@ -767,7 +774,7 @@ llvm::DIType CGDebugInfo::createFieldType(StringRef name,
AccessSpecifier AS,
uint64_t offsetInBits,
llvm::DIFile tunit,
- llvm::DIDescriptor scope) {
+ llvm::DIScope scope) {
llvm::DIType debugType = getOrCreateType(type, tunit);
// Get the location for the field.
@@ -839,20 +846,15 @@ CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
}
}
-/// CollectRecordStaticField - Helper for CollectRecordFields.
-void CGDebugInfo::
-CollectRecordStaticField(const VarDecl *Var,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DIType RecordTy) {
+/// Helper for CollectRecordFields.
+llvm::DIDerivedType
+CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,
+ llvm::DIType RecordTy) {
// Create the descriptor for the static variable, with or without
// constant initializers.
llvm::DIFile VUnit = getOrCreateFile(Var->getLocation());
llvm::DIType VTy = getOrCreateType(Var->getType(), VUnit);
- // Do not describe enums as static members.
- if (VTy.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
- return;
-
unsigned LineNumber = getLineNumber(Var->getLocation());
StringRef VName = Var->getName();
llvm::Constant *C = NULL;
@@ -873,10 +875,10 @@ CollectRecordStaticField(const VarDecl *Var,
else if (Access == clang::AS_protected)
Flags |= llvm::DIDescriptor::FlagProtected;
- llvm::DIType GV = DBuilder.createStaticMemberType(RecordTy, VName, VUnit,
- LineNumber, VTy, Flags, C);
- elements.push_back(GV);
+ llvm::DIDerivedType GV = DBuilder.createStaticMemberType(
+ RecordTy, VName, VUnit, LineNumber, VTy, Flags, C);
StaticDataMemberCache[Var->getCanonicalDecl()] = llvm::WeakVH(GV);
+ return GV;
}
/// CollectRecordNormalField - Helper for CollectRecordFields.
@@ -908,10 +910,10 @@ CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
-void CGDebugInfo::
-CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DIType RecordTy) {
+void CGDebugInfo::CollectRecordFields(const RecordDecl *record,
+ llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DICompositeType RecordTy) {
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
if (CXXDecl && CXXDecl->isLambda())
@@ -922,24 +924,22 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
// Field number for non-static fields.
unsigned fieldNo = 0;
- // Bookkeeping for an ms struct, which ignores certain fields.
- bool IsMsStruct = record->isMsStruct(CGM.getContext());
- const FieldDecl *LastFD = 0;
-
// Static and non-static members should appear in the same order as
// the corresponding declarations in the source program.
for (RecordDecl::decl_iterator I = record->decls_begin(),
E = record->decls_end(); I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I))
- CollectRecordStaticField(V, elements, RecordTy);
- else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are
- // completely ignored; we don't even count them.
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD))
- continue;
- LastFD = field;
- }
+ if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
+ // Reuse the existing static member declaration if one exists
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =
+ StaticDataMemberCache.find(V->getCanonicalDecl());
+ if (MI != StaticDataMemberCache.end()) {
+ assert(MI->second &&
+ "Static data member declaration should still exist");
+ elements.push_back(
+ llvm::DIDerivedType(cast<llvm::MDNode>(MI->second)));
+ } else
+ elements.push_back(CreateRecordStaticField(V, RecordTy));
+ } else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
tunit, elements, RecordTy);
@@ -952,17 +952,17 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
/// function type is not updated to include implicit "this" pointer. Use this
/// routine to get a method type which includes "this" pointer.
-llvm::DIType
+llvm::DICompositeType
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
- return getOrCreateType(QualType(Func, 0), Unit);
+ return llvm::DICompositeType(getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(CGM.getContext()),
Func, Unit);
}
-llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
+llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit) {
// Add "this" pointer.
llvm::DIArray Args = llvm::DICompositeType(
@@ -984,7 +984,8 @@ llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
uint64_t Size = CGM.getTarget().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
- llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
+ llvm::DIType ThisPtrType =
+ DBuilder.createPointerType(PointeeType, Size, Align);
TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
// TODO: This and the artificial type below are misleading, the
// types aren't artificial the argument is, but the current
@@ -1007,7 +1008,7 @@ llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
return DBuilder.createSubroutineType(Unit, EltTypeArray);
}
-/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
+/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
/// inside a function.
static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
@@ -1023,11 +1024,11 @@ llvm::DISubprogram
CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
llvm::DIFile Unit,
llvm::DIType RecordTy) {
- bool IsCtorOrDtor =
+ bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
-
+
StringRef MethodName = getFunctionName(Method);
- llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
+ llvm::DICompositeType MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
@@ -1036,24 +1037,32 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
MethodLinkageName = CGM.getMangledName(Method);
// Get the location for the method.
- llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation());
- unsigned MethodLine = getLineNumber(Method->getLocation());
+ llvm::DIFile MethodDefUnit;
+ unsigned MethodLine = 0;
+ if (!Method->isImplicit()) {
+ MethodDefUnit = getOrCreateFile(Method->getLocation());
+ MethodLine = getLineNumber(Method->getLocation());
+ }
// Collect virtual method info.
llvm::DIType ContainingType;
- unsigned Virtuality = 0;
+ unsigned Virtuality = 0;
unsigned VIndex = 0;
-
+
if (Method->isVirtual()) {
if (Method->isPure())
Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual;
else
Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual;
-
+
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
- if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getVTableContext().getMethodVTableIndex(Method);
+ // FIXME: Add proper support for debug info for virtual calls in
+ // the Microsoft ABI, where we may use multiple vptrs to make a vftable
+ // lookup if we have multiple or virtual inheritance.
+ if (!isa<CXXDestructorDecl>(Method) &&
+ !CGM.getTarget().getCXXABI().isMicrosoft())
+ VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
ContainingType = RecordTy;
}
@@ -1068,7 +1077,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DIDescriptor::FlagExplicit;
- } else if (const CXXConversionDecl *CXXC =
+ } else if (const CXXConversionDecl *CXXC =
dyn_cast<CXXConversionDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DIDescriptor::FlagExplicit;
@@ -1078,21 +1087,21 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram SP =
- DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
+ DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
MethodDefUnit, MethodLine,
- MethodTy, /*isLocalToUnit=*/false,
+ MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/ false,
Virtuality, VIndex, ContainingType,
Flags, CGM.getLangOpts().Optimize, NULL,
TParamsArray);
-
+
SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
return SP;
}
/// CollectCXXMemberFunctions - A helper function to collect debug info for
-/// C++ member functions. This is used while creating debug info entry for
+/// C++ member functions. This is used while creating debug info entry for
/// a Record.
void CGDebugInfo::
CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
@@ -1104,40 +1113,42 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
// the functions.
for(DeclContext::decl_iterator I = RD->decls_begin(),
E = RD->decls_end(); I != E; ++I) {
- Decl *D = *I;
- if (D->isImplicit() && !D->isUsed())
- continue;
-
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
- else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I)) {
+ // Reuse the existing member function declaration if it exists.
+ // It may be associated with the declaration of the type & should be
+ // reused as we're building the definition.
+ //
+ // This situation can arise in the vtable-based debug info reduction where
+ // implicit members are emitted in a non-vtable TU.
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =
+ SPCache.find(Method->getCanonicalDecl());
+ if (MI == SPCache.end()) {
+ // If the member is implicit, lazily create it when we see the
+ // definition, not before. (an ODR-used implicit default ctor that's
+ // never actually code generated should not produce debug info)
+ if (!Method->isImplicit())
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
+ } else
+ EltTys.push_back(MI->second);
+ } else if (const FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(*I)) {
+ // Add any template specializations that have already been seen. Like
+ // implicit member functions, these may have been added to a declaration
+ // in the case of vtable-based debug info reduction.
for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
- SE = FTD->spec_end(); SI != SE; ++SI)
- EltTys.push_back(CreateCXXMemberFunction(cast<CXXMethodDecl>(*SI), Unit,
- RecordTy));
- }
-}
-
-/// CollectCXXFriends - A helper function to collect debug info for
-/// C++ base classes. This is used while creating debug info entry for
-/// a Record.
-void CGDebugInfo::
-CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
- for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
- BE = RD->friend_end(); BI != BE; ++BI) {
- if ((*BI)->isUnsupportedFriend())
- continue;
- if (TypeSourceInfo *TInfo = (*BI)->getFriendType())
- EltTys.push_back(DBuilder.createFriend(RecordTy,
- getOrCreateType(TInfo->getType(),
- Unit)));
+ SE = FTD->spec_end();
+ SI != SE; ++SI) {
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =
+ SPCache.find(cast<CXXMethodDecl>(*SI)->getCanonicalDecl());
+ if (MI != SPCache.end())
+ EltTys.push_back(MI->second);
+ }
+ }
}
}
/// CollectCXXBases - A helper function to collect debug info for
-/// C++ base classes. This is used while creating debug info entry for
+/// C++ base classes. This is used while creating debug info entry for
/// a Record.
void CGDebugInfo::
CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
@@ -1149,30 +1160,30 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
BE = RD->bases_end(); BI != BE; ++BI) {
unsigned BFlags = 0;
uint64_t BaseOffset;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
-
+
if (BI->isVirtual()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
- BaseOffset =
- 0 - CGM.getVTableContext()
+ BaseOffset =
+ 0 - CGM.getItaniumVTableContext()
.getVirtualBaseOffsetOffset(RD, Base).getQuantity();
BFlags = llvm::DIDescriptor::FlagVirtual;
} else
BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
// FIXME: Inconsistent units for BaseOffset. It is in bytes when
// BI->isVirtual() and bits when not.
-
+
AccessSpecifier Access = BI->getAccessSpecifier();
if (Access == clang::AS_private)
BFlags |= llvm::DIDescriptor::FlagPrivate;
else if (Access == clang::AS_protected)
BFlags |= llvm::DIDescriptor::FlagProtected;
-
- llvm::DIType DTy =
- DBuilder.createInheritance(RecordTy,
+
+ llvm::DIType DTy =
+ DBuilder.createInheritance(RecordTy,
getOrCreateType(BI->getType(), Unit),
BaseOffset, BFlags);
EltTys.push_back(DTy);
@@ -1182,23 +1193,119 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// CollectTemplateParams - A helper function to collect template parameters.
llvm::DIArray CGDebugInfo::
CollectTemplateParams(const TemplateParameterList *TPList,
- const TemplateArgumentList &TAList,
+ ArrayRef<TemplateArgument> TAList,
llvm::DIFile Unit) {
- SmallVector<llvm::Value *, 16> TemplateParams;
+ SmallVector<llvm::Value *, 16> TemplateParams;
for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
const TemplateArgument &TA = TAList[i];
- const NamedDecl *ND = TPList->getParam(i);
- if (TA.getKind() == TemplateArgument::Type) {
+ StringRef Name;
+ if (TPList)
+ Name = TPList->getParam(i)->getName();
+ switch (TA.getKind()) {
+ case TemplateArgument::Type: {
llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
llvm::DITemplateTypeParameter TTP =
- DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy);
+ DBuilder.createTemplateTypeParameter(TheCU, Name, TTy);
TemplateParams.push_back(TTP);
- } else if (TA.getKind() == TemplateArgument::Integral) {
+ } break;
+ case TemplateArgument::Integral: {
llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
- TA.getAsIntegral().getZExtValue());
- TemplateParams.push_back(TVP);
+ DBuilder.createTemplateValueParameter(
+ TheCU, Name, TTy,
+ llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()));
+ TemplateParams.push_back(TVP);
+ } break;
+ case TemplateArgument::Declaration: {
+ const ValueDecl *D = TA.getAsDecl();
+ bool InstanceMember = D->isCXXInstanceMember();
+ QualType T = InstanceMember
+ ? CGM.getContext().getMemberPointerType(
+ D->getType(), cast<RecordDecl>(D->getDeclContext())
+ ->getTypeForDecl())
+ : CGM.getContext().getPointerType(D->getType());
+ llvm::DIType TTy = getOrCreateType(T, Unit);
+ llvm::Value *V = 0;
+ // Variable pointer template parameters have a value that is the address
+ // of the variable.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ V = CGM.GetAddrOfGlobalVar(VD);
+ // Member function pointers have special support for building them, though
+ // this is currently unsupported in LLVM CodeGen.
+ if (InstanceMember) {
+ if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(D))
+ V = CGM.getCXXABI().EmitMemberPointer(method);
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ V = CGM.GetAddrOfFunction(FD);
+ // Member data pointers have special handling too to compute the fixed
+ // offset within the object.
+ if (isa<FieldDecl>(D)) {
+ // These five lines (& possibly the above member function pointer
+ // handling) might be able to be refactored to use similar code in
+ // CodeGenModule::getMemberPointerConstant
+ uint64_t fieldOffset = CGM.getContext().getFieldOffset(D);
+ CharUnits chars =
+ CGM.getContext().toCharUnitsFromBits((int64_t) fieldOffset);
+ V = CGM.getCXXABI().EmitMemberDataPointer(
+ cast<MemberPointerType>(T.getTypePtr()), chars);
+ }
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateValueParameter(TheCU, Name, TTy,
+ V->stripPointerCasts());
+ TemplateParams.push_back(TVP);
+ } break;
+ case TemplateArgument::NullPtr: {
+ QualType T = TA.getNullPtrType();
+ llvm::DIType TTy = getOrCreateType(T, Unit);
+ llvm::Value *V = 0;
+ // Special case member data pointer null values since they're actually -1
+ // instead of zero.
+ if (const MemberPointerType *MPT =
+ dyn_cast<MemberPointerType>(T.getTypePtr()))
+ // But treat member function pointers as simple zero integers because
+ // it's easier than having a special case in LLVM's CodeGen. If LLVM
+ // CodeGen grows handling for values of non-null member function
+ // pointers then perhaps we could remove this special case and rely on
+ // EmitNullMemberPointer for member function pointers.
+ if (MPT->isMemberDataPointer())
+ V = CGM.getCXXABI().EmitNullMemberPointer(MPT);
+ if (!V)
+ V = llvm::ConstantInt::get(CGM.Int8Ty, 0);
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V);
+ TemplateParams.push_back(TVP);
+ } break;
+ case TemplateArgument::Template: {
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateTemplateParameter(
+ TheCU, Name, llvm::DIType(),
+ TA.getAsTemplate().getAsTemplateDecl()
+ ->getQualifiedNameAsString());
+ TemplateParams.push_back(TVP);
+ } break;
+ case TemplateArgument::Pack: {
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateParameterPack(
+ TheCU, Name, llvm::DIType(),
+ CollectTemplateParams(NULL, TA.getPackAsArray(), Unit));
+ TemplateParams.push_back(TVP);
+ } break;
+ case TemplateArgument::Expression: {
+ const Expr *E = TA.getAsExpr();
+ QualType T = E->getType();
+ llvm::Value *V = CGM.EmitConstantExpr(E, T);
+ assert(V && "Expression in template argument isn't constant");
+ llvm::DIType TTy = getOrCreateType(T, Unit);
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateValueParameter(TheCU, Name, TTy,
+ V->stripPointerCasts());
+ TemplateParams.push_back(TVP);
+ } break;
+ // And the following should never occur:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Null:
+ llvm_unreachable(
+ "These argument types shouldn't exist in concrete types");
}
}
return DBuilder.getOrCreateArray(TemplateParams);
@@ -1213,8 +1320,8 @@ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
const TemplateParameterList *TList =
FD->getTemplateSpecializationInfo()->getTemplate()
->getTemplateParameters();
- return
- CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit);
+ return CollectTemplateParams(
+ TList, FD->getTemplateSpecializationArgs()->asArray(), Unit);
}
return llvm::DIArray();
}
@@ -1227,12 +1334,12 @@ CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
PU = TSpecial->getSpecializedTemplateOrPartial();
-
+
TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
- return CollectTemplateParams(TPList, TAList, Unit);
+ return CollectTemplateParams(TPList, TAList.asArray(), Unit);
}
/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
@@ -1255,13 +1362,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
/// getVTableName - Get vtable name for the given Class.
StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
- // Construct gdb compatible name name.
- std::string Name = "_vptr$" + RD->getNameAsString();
-
- // Copy this name on the side and use its reference.
- char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
- memcpy(StrPtr, Name.data(), Name.length());
- return StringRef(StrPtr, Name.length());
+ // Copy the gdb compatible name on the side and use its reference.
+ return internString("_vptr$", RD->getNameAsString());
}
@@ -1283,15 +1385,16 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
= DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
- 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial,
+ 0, Size, 0, 0,
+ llvm::DIDescriptor::FlagArtificial,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
}
-/// getOrCreateRecordType - Emit record type's standalone debug info.
-llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
+/// getOrCreateRecordType - Emit record type's standalone debug info.
+llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
return T;
}
@@ -1300,15 +1403,76 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// debug info.
llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
RetainedTypes.push_back(D.getAsOpaquePtr());
return T;
}
+void CGDebugInfo::completeType(const RecordDecl *RD) {
+ if (DebugKind > CodeGenOptions::LimitedDebugInfo ||
+ !CGM.getLangOpts().CPlusPlus)
+ completeRequiredType(RD);
+}
+
+void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {
+ if (const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
+ if (CXXDecl->isDynamicClass())
+ return;
+
+ QualType Ty = CGM.getContext().getRecordType(RD);
+ llvm::DIType T = getTypeOrNull(Ty);
+ if (T && T.isForwardDecl())
+ completeClassData(RD);
+}
+
+void CGDebugInfo::completeClassData(const RecordDecl *RD) {
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
+ QualType Ty = CGM.getContext().getRecordType(RD);
+ void* TyPtr = Ty.getAsOpaquePtr();
+ if (CompletedTypeCache.count(TyPtr))
+ return;
+ llvm::DIType Res = CreateTypeDefinition(Ty->castAs<RecordType>());
+ assert(!Res.isForwardDecl());
+ CompletedTypeCache[TyPtr] = Res;
+ TypeCache[TyPtr] = Res;
+}
+
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ // Always emit declarations for types that aren't required to be complete when
+ // in limit-debug-info mode. If the type is later found to be required to be
+ // complete this declaration will be upgraded to a definition by
+ // `completeRequiredType`.
+ // If the type is dynamic, only emit the definition in TUs that require class
+ // data. This is handled by `completeClassData`.
+ llvm::DICompositeType T(getTypeOrNull(QualType(Ty, 0)));
+ // If we've already emitted the type, just use that, even if it's only a
+ // declaration. The completeType, completeRequiredType, and completeClassData
+ // callbacks will handle promoting the declaration to a definition.
+ if (T ||
+ (DebugKind <= CodeGenOptions::LimitedDebugInfo &&
+ // Under -flimit-debug-info, emit only a declaration unless the type is
+ // required to be complete.
+ !RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||
+ // If the class is dynamic, only emit a declaration. A definition will be
+ // emitted whenever the vtable is emitted.
+ (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass()) || T) {
+ llvm::DIDescriptor FDContext =
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+ if (!T)
+ T = getOrCreateRecordFwdDecl(Ty, FDContext);
+ return T;
+ }
+
+ return CreateTypeDefinition(Ty);
+}
+
+llvm::DIType CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
+ RecordDecl *RD = Ty->getDecl();
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
@@ -1320,14 +1484,16 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DICompositeType FwdDecl(
- getOrCreateLimitedType(QualType(Ty, 0), DefUnit));
- assert(FwdDecl.Verify() &&
- "The debug type of a RecordType should be a DICompositeType");
+ llvm::DICompositeType FwdDecl(getOrCreateLimitedType(Ty, DefUnit));
+ assert(FwdDecl.isCompositeType() &&
+ "The debug type of a RecordType should be a llvm::DICompositeType");
if (FwdDecl.isForwardDecl())
return FwdDecl;
+ if (const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
+ CollectContainingType(CXXDecl, FwdDecl);
+
// Push the struct on region stack.
LexicalBlockStack.push_back(&*FwdDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
@@ -1337,6 +1503,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// Convert all the elements.
SmallVector<llvm::Value *, 16> EltTys;
+ // what about nested types?
// Note: The split of CXXDecl information here is intentional, the
// gdb tests will depend on a certain ordering at printout. The debug
@@ -1350,20 +1517,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// Collect data fields (including static variables and any initializers).
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
- llvm::DIArray TParamsArray;
- if (CXXDecl) {
+ if (CXXDecl)
CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
- CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl);
- if (const ClassTemplateSpecializationDecl *TSpecial
- = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit);
- }
LexicalBlockStack.pop_back();
RegionMap.erase(Ty->getDecl());
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- FwdDecl.setTypeArray(Elements, TParamsArray);
+ FwdDecl.setTypeArray(Elements);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
return FwdDecl;
@@ -1376,6 +1537,31 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty,
return getOrCreateType(Ty->getBaseType(), Unit);
}
+
+/// \return true if Getter has the default name for the property PD.
+static bool hasDefaultGetterName(const ObjCPropertyDecl *PD,
+ const ObjCMethodDecl *Getter) {
+ assert(PD);
+ if (!Getter)
+ return true;
+
+ assert(Getter->getDeclName().isObjCZeroArgSelector());
+ return PD->getName() ==
+ Getter->getDeclName().getObjCSelector().getNameForSlot(0);
+}
+
+/// \return true if Setter has the default name for the property PD.
+static bool hasDefaultSetterName(const ObjCPropertyDecl *PD,
+ const ObjCMethodDecl *Setter) {
+ assert(PD);
+ if (!Setter)
+ return true;
+
+ assert(Setter->getDeclName().isObjCOneArgSelector());
+ return SelectorTable::constructSetterName(PD->getName()) ==
+ Setter->getDeclName().getObjCSelector().getNameForSlot(0);
+}
+
/// CreateType - get objective-c interface type.
llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIFile Unit) {
@@ -1418,8 +1604,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// will find it and we're emitting the complete type.
QualType QualTy = QualType(Ty, 0);
CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
- // Push the struct on region stack.
+ // Push the struct on region stack.
LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
@@ -1432,12 +1618,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
if (!SClassTy.isValid())
return llvm::DIType();
-
+
llvm::DIType InhTag =
DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
EltTys.push_back(InhTag);
}
+ // Create entries for all of the properties.
for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(),
E = ID->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
@@ -1449,9 +1636,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::MDNode *PropertyNode =
DBuilder.createObjCProperty(PD->getName(),
PUnit, PLine,
- (Getter && Getter->isImplicit()) ? "" :
+ hasDefaultGetterName(PD, Getter) ? "" :
getSelectorName(PD->getGetterName()),
- (Setter && Setter->isImplicit()) ? "" :
+ hasDefaultSetterName(PD, Setter) ? "" :
getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(),
getOrCreateType(PD->getType(), PUnit));
@@ -1465,7 +1652,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
if (!FieldTy.isValid())
return llvm::DIType();
-
+
StringRef FieldName = Field->getName();
// Ignore unnamed fields.
@@ -1483,8 +1670,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Bit size, align and offset of the type.
FieldSize = Field->isBitField()
- ? Field->getBitWidthValue(CGM.getContext())
- : CGM.getContext().getTypeSize(FType);
+ ? Field->getBitWidthValue(CGM.getContext())
+ : CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
}
@@ -1512,7 +1699,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::MDNode *PropertyNode = NULL;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
- if (ObjCPropertyImplDecl *PImpD =
+ if (ObjCPropertyImplDecl *PImpD =
ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
SourceLocation Loc = PD->getLocation();
@@ -1523,9 +1710,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
PropertyNode =
DBuilder.createObjCProperty(PD->getName(),
PUnit, PLine,
- (Getter && Getter->isImplicit()) ? "" :
+ hasDefaultGetterName(PD, Getter) ? "" :
getSelectorName(PD->getGetterName()),
- (Setter && Setter->isImplicit()) ? "" :
+ hasDefaultSetterName(PD, Setter) ? "" :
getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(),
getOrCreateType(PD->getType(), PUnit));
@@ -1547,7 +1734,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// private ivars that we would miss otherwise.
if (ID->getImplementation() == 0)
CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
-
+
LexicalBlockStack.pop_back();
return RealDecl;
}
@@ -1585,7 +1772,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
Align = 0;
else
Align = CGM.getContext().getTypeAlign(Ty->getElementType());
- } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) {
+ } else if (Ty->isIncompleteType()) {
Size = 0;
Align = 0;
} else {
@@ -1610,7 +1797,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
int64_t Count = -1; // Count == -1 is an unbounded array.
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
Count = CAT->getSize().getZExtValue();
-
+
// FIXME: Verify this is right for VLAs.
Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
EltTy = Ty->getElementType();
@@ -1618,30 +1805,30 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
- llvm::DIType DbgTy =
+ llvm::DIType DbgTy =
DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
SubscriptArray);
return DbgTy;
}
-llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
+llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
Ty, Ty->getPointeeType(), Unit);
}
-llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
+llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type,
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type,
Ty, Ty->getPointeeType(), Unit);
}
-llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
+llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIFile U) {
llvm::DIType ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
if (!Ty->getPointeeType()->isFunctionType())
return DBuilder.createMemberPointerType(
- CreatePointeeType(Ty->getPointeeType(), U), ClassType);
+ getOrCreateType(Ty->getPointeeType(), U), ClassType);
return DBuilder.createMemberPointerType(getOrCreateInstanceMethodType(
CGM.getContext().getPointerType(
QualType(Ty->getClass(), Ty->getPointeeType().getCVRQualifiers())),
@@ -1649,7 +1836,7 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
ClassType);
}
-llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
+llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
llvm::DIFile U) {
// Ignore the atomic wrapping
// FIXME: What is the correct representation?
@@ -1657,7 +1844,8 @@ llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
}
/// CreateEnumType - get enumeration type.
-llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
+llvm::DIType CGDebugInfo::CreateEnumType(const EnumType *Ty) {
+ const EnumDecl *ED = Ty->getDecl();
uint64_t Size = 0;
uint64_t Align = 0;
if (!ED->getTypeForDecl()->isIncompleteType()) {
@@ -1665,6 +1853,8 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
}
+ SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
+
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!ED->getDefinition()) {
@@ -1675,7 +1865,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
StringRef EDName = ED->getName();
return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
EDName, EDContext, DefUnit, Line, 0,
- Size, Align);
+ Size, Align, FullName);
}
// Create DIEnumerator elements for each enumerator.
@@ -1686,7 +1876,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
Enum != EnumEnd; ++Enum) {
Enumerators.push_back(
DBuilder.createEnumerator(Enum->getName(),
- Enum->getInitVal().getZExtValue()));
+ Enum->getInitVal().getSExtValue()));
}
// Return a CompositeType for the enum itself.
@@ -1694,21 +1884,25 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
- llvm::DIDescriptor EnumContext =
+ llvm::DIDescriptor EnumContext =
getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIType ClassTy = ED->isFixed() ?
getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
- llvm::DIType DbgTy =
+ llvm::DIType DbgTy =
DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
Size, Align, EltArray,
- ClassTy);
+ ClassTy, FullName);
return DbgTy;
}
static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
Qualifiers Quals;
do {
- Quals += T.getLocalQualifiers();
+ Qualifiers InnerQuals = T.getLocalQualifiers();
+ // Qualifiers::operator+() doesn't like it if you add a Qualifier
+ // that is already there.
+ Quals += Qualifiers::removeCommonQualifiers(Quals, InnerQuals);
+ Quals += InnerQuals;
QualType LastT = T;
switch (T->getTypeClass()) {
default:
@@ -1741,21 +1935,25 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
case Type::Auto:
- T = cast<AutoType>(T)->getDeducedType();
+ QualType DT = cast<AutoType>(T)->getDeducedType();
+ if (DT.isNull())
+ return T;
+ T = DT;
break;
}
-
+
assert(T != LastT && "Type unwrapping failed to unwrap!");
(void)LastT;
} while (true);
}
-/// getType - Get the type from the cache or return null type if it doesn't exist.
+/// getType - Get the type from the cache or return null type if it doesn't
+/// exist.
llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
-
+
// Check for existing entry.
if (Ty->getTypeClass() == Type::ObjCInterface) {
llvm::Value *V = getCachedInterfaceTypeOrNull(Ty);
@@ -1793,10 +1991,7 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
}
// Verify that any cached debug info still exists.
- if (V != 0)
- return llvm::DIType(cast<llvm::MDNode>(V));
-
- return llvm::DIType();
+ return llvm::DIType(cast_or_null<llvm::MDNode>(V));
}
/// getCachedInterfaceTypeOrNull - Get the type from the interface
@@ -1824,9 +2019,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
- llvm::DIType T = getCompletedTypeOrNull(Ty);
-
- if (T.Verify())
+ if (llvm::DIType T = getCompletedTypeOrNull(Ty))
return T;
// Otherwise create the type.
@@ -1836,29 +2029,33 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// And update the type cache.
TypeCache[TyPtr] = Res;
+ // FIXME: this getTypeOrNull call seems silly when we just inserted the type
+ // into the cache - but getTypeOrNull has a special case for cached interface
+ // types. We should probably just pull that out as a special case for the
+ // "else" block below & skip the otherwise needless lookup.
llvm::DIType TC = getTypeOrNull(Ty);
- if (TC.Verify() && TC.isForwardDecl())
+ if (TC && TC.isForwardDecl())
ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
else if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) {
// Interface types may have elements added to them by a
// subsequent implementation or extension, so we keep them in
// the ObjCInterfaceCache together with a checksum. Instead of
- // the (possibly) incomplete interace type, we return a forward
+ // the (possibly) incomplete interface type, we return a forward
// declaration that gets RAUW'd in CGDebugInfo::finalize().
- llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
- ::iterator it = ObjCInterfaceCache.find(TyPtr);
- if (it != ObjCInterfaceCache.end())
- TC = llvm::DIType(cast<llvm::MDNode>(it->second.first));
- else
- TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- Decl->getName(), TheCU, Unit,
- getLineNumber(Decl->getLocation()),
- TheCU.getLanguage());
+ std::pair<llvm::WeakVH, unsigned> &V = ObjCInterfaceCache[TyPtr];
+ if (V.first)
+ return llvm::DIType(cast<llvm::MDNode>(V.first));
+ TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Decl->getName(), TheCU, Unit,
+ getLineNumber(Decl->getLocation()),
+ TheCU.getLanguage());
// Store the forward declaration in the cache.
- ObjCInterfaceCache[TyPtr] = std::make_pair(TC, Checksum(Decl));
+ V.first = TC;
+ V.second = Checksum(Decl);
// Register the type for replacement in finalize().
ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
+
return TC;
}
@@ -1868,19 +2065,25 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
return Res;
}
-/// Currently the checksum merely consists of the number of ivars.
-unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl
- *InterfaceDecl) {
- unsigned IvarNo = 0;
- for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin();
- Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo;
- return IvarNo;
+/// Currently the checksum of an interface includes the number of
+/// ivars and property accessors.
+unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) {
+ // The assumption is that the number of ivars can only increase
+ // monotonically, so it is safe to just use their current number as
+ // a checksum.
+ unsigned Sum = 0;
+ for (const ObjCIvarDecl *Ivar = ID->all_declared_ivar_begin();
+ Ivar != 0; Ivar = Ivar->getNextIvar())
+ ++Sum;
+
+ return Sum;
}
ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
switch (Ty->getTypeClass()) {
case Type::ObjCObjectPointer:
- return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)
+ ->getPointeeType());
case Type::ObjCInterface:
return cast<ObjCInterfaceType>(Ty)->getDecl();
default:
@@ -1895,7 +2098,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
return CreateQualifiedType(Ty, Unit);
const char *Diag = 0;
-
+
// Work out details of type.
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
@@ -1920,6 +2123,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
return CreateType(cast<ComplexType>(Ty));
case Type::Pointer:
return CreateType(cast<PointerType>(Ty), Unit);
+ case Type::Decayed:
+ // Decayed types are just pointers in LLVM and DWARF.
+ return CreateType(
+ cast<PointerType>(cast<DecayedType>(Ty)->getDecayedType()), Unit);
case Type::BlockPointer:
return CreateType(cast<BlockPointerType>(Ty), Unit);
case Type::Typedef:
@@ -1927,7 +2134,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::Record:
return CreateType(cast<RecordType>(Ty));
case Type::Enum:
- return CreateEnumType(cast<EnumType>(Ty)->getDecl());
+ return CreateEnumType(cast<EnumType>(Ty));
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
@@ -1956,10 +2163,13 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::TypeOf:
case Type::Decltype:
case Type::UnaryTransform:
- case Type::Auto:
+ case Type::PackExpansion:
llvm_unreachable("type should have been unwrapped!");
+ case Type::Auto:
+ Diag = "auto";
+ break;
}
-
+
assert(Diag && "Fall through without a diagnostic?");
unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"debug information for %0 is not yet supported");
@@ -1970,117 +2180,119 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// limited type if necessary.
-llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
+llvm::DIType CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
llvm::DIFile Unit) {
- if (Ty.isNull())
- return llvm::DIType();
+ QualType QTy(Ty, 0);
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
-
- llvm::DIType T = getTypeOrNull(Ty);
+ llvm::DICompositeType T(getTypeOrNull(QTy));
// We may have cached a forward decl when we could have created
// a non-forward decl. Go ahead and create a non-forward decl
// now.
- if (T.Verify() && !T.isForwardDecl()) return T;
+ if (T && !T.isForwardDecl()) return T;
// Otherwise create the type.
- llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
+ llvm::DICompositeType Res = CreateLimitedType(Ty);
- if (T.Verify() && T.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(T)));
+ // Propagate members from the declaration to the definition
+ // CreateType(const RecordType*) will overwrite this with the members in the
+ // correct order if the full type is needed.
+ Res.setTypeArray(T.getTypeArray());
+
+ if (T && T.isForwardDecl())
+ ReplaceMap.push_back(
+ std::make_pair(QTy.getAsOpaquePtr(), static_cast<llvm::Value *>(T)));
// And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
+ TypeCache[QTy.getAsOpaquePtr()] = Res;
return Res;
}
// TODO: Currently used for context chains when limiting debug info.
-llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
+llvm::DICompositeType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
-
+
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
- llvm::DIDescriptor RDContext;
- if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo)
- RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
- else
- RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+ llvm::DIDescriptor RDContext =
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+
+ // If we ended up creating the type during the context chain construction,
+ // just return that.
+ // FIXME: this could be dealt with better if the type was recorded as
+ // completed before we started this (see the CompletedTypeCache usage in
+ // CGDebugInfo::CreateTypeDefinition(const RecordType*) - that would need to
+ // be pushed to before context creation, but after it was known to be
+ // destined for completion (might still have an issue if this caller only
+ // required a declaration but the context construction ended up creating a
+ // definition)
+ llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));
+ if (T && (!T.isForwardDecl() || !RD->getDefinition()))
+ return T;
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!RD->getDefinition())
- return createRecordFwdDecl(RD, RDContext);
+ return getOrCreateRecordFwdDecl(Ty, RDContext);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
llvm::DICompositeType RealDecl;
-
+
+ SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
+
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
+ Size, Align, 0, llvm::DIArray(), 0,
+ FullName);
else if (RD->isClass()) {
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, 0, llvm::DIType(),
llvm::DIArray(), llvm::DIType(),
- llvm::DIArray());
+ llvm::DIArray(), FullName);
} else
RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIType(), llvm::DIArray());
+ Size, Align, 0, llvm::DIType(),
+ llvm::DIArray(), 0, llvm::DIType(),
+ FullName);
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
- if (CXXDecl) {
- // A class's primary base or the class itself contains the vtable.
- llvm::DICompositeType ContainingType;
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
- // Seek non virtual primary base root.
- while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
- }
- ContainingType = llvm::DICompositeType(
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit));
- } else if (CXXDecl->isDynamicClass())
- ContainingType = RealDecl;
-
- RealDecl.setContainingType(ContainingType);
- }
- return llvm::DIType(RealDecl);
+ if (const ClassTemplateSpecializationDecl *TSpecial =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RealDecl.setTypeArray(llvm::DIArray(),
+ CollectCXXTemplateParams(TSpecial, DefUnit));
+ return RealDecl;
}
-/// CreateLimitedTypeNode - Create a new debug type node, but only forward
-/// declare composite types that haven't been processed yet.
-llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
-
- // Work out details of type.
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
- #include "clang/AST/TypeNodes.def"
- llvm_unreachable("Dependent types cannot show up in debug information");
+void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
+ llvm::DICompositeType RealDecl) {
+ // A class's primary base or the class itself contains the vtable.
+ llvm::DICompositeType ContainingType;
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
+ // Seek non virtual primary base root.
+ while (1) {
+ const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+ const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+ if (PBT && !BRL.isPrimaryBaseVirtual())
+ PBase = PBT;
+ else
+ break;
+ }
+ ContainingType = llvm::DICompositeType(
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
+ getOrCreateFile(RD->getLocation())));
+ } else if (RD->isDynamicClass())
+ ContainingType = RealDecl;
- case Type::Record:
- return CreateLimitedType(cast<RecordType>(Ty));
- default:
- return CreateTypeNode(Ty, Unit);
- }
+ RealDecl.setContainingType(ContainingType);
}
/// CreateMemberType - Create new member and increase Offset by FType's size.
@@ -2097,21 +2309,57 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
return Ty;
}
+llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
+ // We only need a declaration (not a definition) of the type - so use whatever
+ // we would otherwise do to get a type for a pointee. (forward declarations in
+ // limited debug info, full definitions (if the type definition is available)
+ // in unlimited debug info)
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ return getOrCreateType(CGM.getContext().getTypeDeclType(TD),
+ getOrCreateFile(TD->getLocation()));
+ // Otherwise fall back to a fairly rudimentary cache of existing declarations.
+ // This doesn't handle providing declarations (for functions or variables) for
+ // entities without definitions in this TU, nor when the definition proceeds
+ // the call to this function.
+ // FIXME: This should be split out into more specific maps with support for
+ // emitting forward declarations and merging definitions with declarations,
+ // the same way as we do for types.
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I =
+ DeclCache.find(D->getCanonicalDecl());
+ if (I == DeclCache.end())
+ return llvm::DIDescriptor();
+ llvm::Value *V = I->second;
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
+}
+
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
+ if (!D || DebugKind == CodeGenOptions::DebugLineTablesOnly)
+ return llvm::DISubprogram();
+
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
if (!FD) return llvm::DISubprogram();
// Setup context.
- getContextDescriptor(cast<Decl>(D->getDeclContext()));
+ llvm::DIScope S = getContextDescriptor(cast<Decl>(D->getDeclContext()));
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
MI = SPCache.find(FD->getCanonicalDecl());
+ if (MI == SPCache.end()) {
+ if (const CXXMethodDecl *MD =
+ dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {
+ llvm::DICompositeType T(S);
+ llvm::DISubprogram SP =
+ CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), T);
+ T.addMember(SP);
+ return SP;
+ }
+ }
if (MI != SPCache.end()) {
llvm::Value *V = MI->second;
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
- if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ if (SP.isSubprogram() && !SP.isDefinition())
return SP;
}
@@ -2123,7 +2371,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
if (MI != SPCache.end()) {
llvm::Value *V = MI->second;
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
- if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ if (SP.isSubprogram() && !SP.isDefinition())
return SP;
}
}
@@ -2132,9 +2380,15 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
// implicit parameter "this".
-llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
- QualType FnType,
- llvm::DIFile F) {
+llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
+ QualType FnType,
+ llvm::DIFile F) {
+ if (!D || DebugKind == CodeGenOptions::DebugLineTablesOnly)
+ // Create fake but valid subroutine type. Otherwise
+ // llvm::DISubprogram::Verify() would return false, and
+ // subprogram DIE will miss DW_AT_decl_file and
+ // DW_AT_decl_line fields.
+ return DBuilder.createSubroutineType(F, DBuilder.getOrCreateArray(None));
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
return getOrCreateMethodType(Method, F);
@@ -2143,7 +2397,14 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
SmallVector<llvm::Value *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
- Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
+ QualType ResultTy = OMethod->getResultType();
+
+ // Replace the instancetype keyword with the actual type.
+ if (ResultTy == CGM.getContext().getObjCInstanceType())
+ ResultTy = CGM.getContext().getPointerType(
+ QualType(OMethod->getClassInterface()->getTypeForDecl(), 0));
+
+ Elts.push_back(getOrCreateType(ResultTy, F));
// "self" pointer is always first argument.
QualType SelfDeclTy = OMethod->getSelfDecl()->getType();
llvm::DIType SelfTy = getOrCreateType(SelfDeclTy, F);
@@ -2152,14 +2413,14 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
Elts.push_back(DBuilder.createArtificialType(CmdTy));
// Get rest of the arguments.
- for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
PE = OMethod->param_end(); PI != PE; ++PI)
Elts.push_back(getOrCreateType((*PI)->getType(), F));
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
return DBuilder.createSubroutineType(F, EltTypeArray);
}
- return getOrCreateType(FnType, F);
+ return llvm::DICompositeType(getOrCreateType(FnType, F));
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
@@ -2187,7 +2448,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::DIArray TParamsArray;
if (!HasDecl) {
// Use llvm function name.
- Name = Fn->getName();
+ LinkageName = Fn->getName();
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// If there is a DISubprogram for this function available then use it.
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
@@ -2214,16 +2475,16 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (LinkageName == Name ||
(!CGM.getCodeGenOpts().EmitGcovArcs &&
!CGM.getCodeGenOpts().EmitGcovNotes &&
- CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly))
+ DebugKind <= CodeGenOptions::DebugLineTablesOnly))
LinkageName = StringRef();
- if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
+ if (DebugKind >= CodeGenOptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
- dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
+ dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
else if (const RecordDecl *RDecl =
- dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
- FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext()));
+ dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
+ FDContext = getContextDescriptor(cast<Decl>(RDecl));
// Collect template parameters.
TParamsArray = CollectFunctionTemplateParams(FD, Unit);
@@ -2243,28 +2504,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!HasDecl || D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
- llvm::DIType DIFnType;
- llvm::DISubprogram SPDecl;
- if (HasDecl &&
- CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
- DIFnType = getOrCreateFunctionType(D, FnType, Unit);
- SPDecl = getFunctionDeclaration(D);
- } else {
- // Create fake but valid subroutine type. Otherwise
- // llvm::DISubprogram::Verify() would return false, and
- // subprogram DIE will miss DW_AT_decl_file and
- // DW_AT_decl_line fields.
- SmallVector<llvm::Value*, 16> Elts;
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
- DIFnType = DBuilder.createSubroutineType(Unit, EltTypeArray);
- }
- llvm::DISubprogram SP;
- SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
- LineNo, DIFnType,
- Fn->hasInternalLinkage(), true/*definition*/,
- getLineNumber(CurLoc), Flags,
- CGM.getLangOpts().Optimize,
- Fn, TParamsArray, SPDecl);
+ llvm::DISubprogram SP =
+ DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo,
+ getOrCreateFunctionType(D, FnType, Unit),
+ Fn->hasInternalLinkage(), true /*definition*/,
+ getLineNumber(CurLoc), Flags,
+ CGM.getLangOpts().Optimize, Fn, TParamsArray,
+ getFunctionDeclaration(D));
+ if (HasDecl)
+ DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(SP)));
// Push function on region stack.
llvm::MDNode *SPN = SP;
@@ -2274,10 +2522,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
/// EmitLocation - Emit metadata to indicate a change in line/column
-/// information in the source file.
+/// information in the source file. If the location is invalid, the
+/// previous location will be reused.
void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
bool ForceColumnInfo) {
-
// Update our current location
setLocation(Loc);
@@ -2292,7 +2540,7 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
Builder.getCurrentDebugLocation().getScope(CGM.getLLVMContext()) ==
LexicalBlockStack.back())
return;
-
+
// Update last state.
PrevLoc = CurLoc;
@@ -2319,7 +2567,8 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
/// region - beginning of a DW_TAG_lexical_block.
-void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) {
+void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
+ SourceLocation Loc) {
// Set our current location.
setLocation(Loc);
@@ -2334,7 +2583,8 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc
/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
/// region - end of a DW_TAG_lexical_block.
-void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) {
+void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
+ SourceLocation Loc) {
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
// Provide an entry in the line table for the end of the block.
@@ -2355,7 +2605,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
FnBeginRegionCount.pop_back();
}
-// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *XOffset) {
@@ -2364,9 +2614,9 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
QualType FType;
uint64_t FieldSize, FieldOffset;
unsigned FieldAlign;
-
+
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- QualType Type = VD->getType();
+ QualType Type = VD->getType();
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
@@ -2388,21 +2638,23 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
Qualifiers::ObjCLifetime Lifetime;
if (CGM.getContext().getByrefLifetime(Type,
Lifetime, HasByrefExtendedLayout)
- && HasByrefExtendedLayout)
+ && HasByrefExtendedLayout) {
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(CreateMemberType(Unit, FType,
"__byref_variable_layout",
&FieldOffset));
-
+ }
+
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
CGM.getTarget().getPointerAlign(0))) {
- CharUnits FieldOffsetInBytes
+ CharUnits FieldOffsetInBytes
= CGM.getContext().toCharUnitsFromBits(FieldOffset);
CharUnits AlignedOffsetInBytes
= FieldOffsetInBytes.RoundUpToAlignment(Align);
CharUnits NumPaddingBytes
= AlignedOffsetInBytes - FieldOffsetInBytes;
-
+
if (NumPaddingBytes.isPositive()) {
llvm::APInt pad(32, NumPaddingBytes.getQuantity());
FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
@@ -2410,40 +2662,45 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
}
}
-
+
FType = Type;
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().toBits(Align);
- *XOffset = FieldOffset;
+ *XOffset = FieldOffset;
FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
-
+
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
+
unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
-
+
return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
llvm::DIType(), Elements);
}
/// EmitDeclare - Emit local variable declaration debug info.
void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
- llvm::Value *Storage,
+ llvm::Value *Storage,
unsigned ArgNo, CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
+ bool Unwritten =
+ VD->isImplicit() || (isa<Decl>(VD->getDeclContext()) &&
+ cast<Decl>(VD->getDeclContext())->isImplicit());
+ llvm::DIFile Unit;
+ if (!Unwritten)
+ Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
uint64_t XOffset = 0;
if (VD->hasAttr<BlocksAttr>())
Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
- else
+ else
Ty = getOrCreateType(VD->getType(), Unit);
// If there is no debug info for this type then do not emit debug info
@@ -2451,24 +2708,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
if (!Ty)
return;
- if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage)) {
- // If Storage is an aggregate returned as 'sret' then let debugger know
- // about this.
- if (Arg->hasStructRetAttr())
- Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
- else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) {
- // If an aggregate variable has non trivial destructor or non trivial copy
- // constructor than it is pass indirectly. Let debug info know about this
- // by using reference of the aggregate type as a argument type.
- if (Record->hasNonTrivialCopyConstructor() ||
- !Record->hasTrivialDestructor())
- Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
- }
- }
-
// Get location information.
- unsigned Line = getLineNumber(VD->getLocation());
- unsigned Column = getColumnNumber(VD->getLocation());
+ unsigned Line = 0;
+ unsigned Column = 0;
+ if (!Unwritten) {
+ Line = getLineNumber(VD->getLocation());
+ Column = getColumnNumber(VD->getLocation());
+ }
unsigned Flags = 0;
if (VD->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
@@ -2479,6 +2725,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// otherwise it is 'self' or 'this'.
if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
Flags |= llvm::DIDescriptor::FlagObjectPointer;
+ if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage))
+ if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() &&
+ !VD->getType()->isPointerType())
+ Flags |= llvm::DIDescriptor::FlagIndirectVariable;
llvm::MDNode *Scope = LexicalBlockStack.back();
@@ -2501,33 +2751,18 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag,
+ DBuilder.createComplexVariable(Tag,
llvm::DIDescriptor(Scope),
VD->getName(), Unit, Line, Ty,
addr, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- } else if (isa<VariableArrayType>(VD->getType())) {
- // These are "complex" variables in that they need an op_deref.
- // Create the descriptor for the variable.
- llvm::Value *Addr = llvm::ConstantInt::get(CGM.Int64Ty,
- llvm::DIBuilder::OpDeref);
- llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag,
- llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- Addr, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
- }
+ } else if (isa<VariableArrayType>(VD->getType()))
+ Flags |= llvm::DIDescriptor::FlagIndirectVariable;
} else if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
// If VD is an anonymous union then Storage represents value for
// all union fields.
@@ -2539,18 +2774,18 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
StringRef FieldName = Field->getName();
-
+
// Ignore unnamed fields. Do not ignore unnamed records.
if (FieldName.empty() && !isa<RecordType>(Field->getType()))
continue;
-
+
// Use VarDecl's Tag, Scope and Line number.
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- FieldName, Unit, Line, FieldTy,
+ FieldName, Unit, Line, FieldTy,
CGM.getLangOpts().Optimize, Flags,
ArgNo);
-
+
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
@@ -2575,7 +2810,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
}
@@ -2585,9 +2820,10 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
/// never happen though, since creating a type for the implicit self
/// argument implies that we already parsed the interface definition
/// and the ivar declarations in the implementation.
-llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType Ty) {
+llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy,
+ llvm::DIType Ty) {
llvm::DIType CachedTy = getTypeOrNull(QualTy);
- if (CachedTy.Verify()) Ty = CachedTy;
+ if (CachedTy) Ty = CachedTy;
else DEBUG(llvm::dbgs() << "No cached type for self.");
return DBuilder.createObjectPointerType(Ty);
}
@@ -2596,20 +2832,20 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder,
const CGBlockInfo &blockInfo) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
+
if (Builder.GetInsertBlock() == 0)
return;
-
+
bool isByRef = VD->hasAttr<BlocksAttr>();
-
+
uint64_t XOffset = 0;
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
if (isByRef)
Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
- else
+ else
Ty = getOrCreateType(VD->getType(), Unit);
// Self is passed along as an implicit non-arg variable in a
@@ -2649,7 +2885,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
+ DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
llvm::DIDescriptor(LexicalBlockStack.back()),
VD->getName(), Unit, Line, Ty, addr);
@@ -2665,7 +2901,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
unsigned ArgNo,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
}
@@ -2683,7 +2919,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::Value *Arg,
llvm::Value *LocalAddr,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
const BlockDecl *blockDecl = block.getBlockDecl();
@@ -2692,7 +2928,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::DIFile tunit = getOrCreateFile(loc);
unsigned line = getLineNumber(loc);
unsigned column = getColumnNumber(loc);
-
+
// Build the debug-info type for the block literal.
getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
@@ -2812,7 +3048,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Create the descriptor for the parameter.
llvm::DIVariable debugVar =
DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
- llvm::DIDescriptor(scope),
+ llvm::DIDescriptor(scope),
Arg->getName(), tunit, line, type,
CGM.getLangOpts().Optimize, flags,
cast<llvm::Argument>(Arg)->getArgNo() + 1);
@@ -2831,25 +3067,32 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
}
-/// getStaticDataMemberDeclaration - If D is an out-of-class definition of
-/// a static data member of a class, find its corresponding in-class
-/// declaration.
-llvm::DIDerivedType CGDebugInfo::getStaticDataMemberDeclaration(const Decl *D) {
- if (cast<VarDecl>(D)->isStaticDataMember()) {
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
- MI = StaticDataMemberCache.find(D->getCanonicalDecl());
- if (MI != StaticDataMemberCache.end())
- // Verify the info still exists.
- if (llvm::Value *V = MI->second)
- return llvm::DIDerivedType(cast<llvm::MDNode>(V));
- }
- return llvm::DIDerivedType();
+/// If D is an out-of-class definition of a static data member of a class, find
+/// its corresponding in-class declaration.
+llvm::DIDerivedType
+CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
+ if (!D->isStaticDataMember())
+ return llvm::DIDerivedType();
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =
+ StaticDataMemberCache.find(D->getCanonicalDecl());
+ if (MI != StaticDataMemberCache.end()) {
+ assert(MI->second && "Static data member declaration should still exist");
+ return llvm::DIDerivedType(cast<llvm::MDNode>(MI->second));
+ }
+
+ // If the member wasn't found in the cache, lazily construct and add it to the
+ // type (used when a limited form of the type is emitted).
+ llvm::DICompositeType Ctxt(
+ getContextDescriptor(cast<Decl>(D->getDeclContext())));
+ llvm::DIDerivedType T = CreateRecordStaticField(D, Ctxt);
+ Ctxt.addMember(T);
+ return T;
}
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
unsigned LineNo = getLineNumber(D->getLocation());
@@ -2873,18 +3116,19 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
LinkageName = Var->getName();
if (LinkageName == DeclName)
LinkageName = StringRef();
- llvm::DIDescriptor DContext =
+ llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
- DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
- Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var,
- getStaticDataMemberDeclaration(D));
+ llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
+ DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(), Var,
+ getOrCreateStaticDataMemberDeclarationOrNull(D));
+ DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));
}
/// EmitGlobalVariable - Emit information about an objective-c interface.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *ID) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
unsigned LineNo = getLineNumber(ID->getLocation());
@@ -2908,9 +3152,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
}
/// EmitGlobalVariable - Emit global variable's debug info.
-void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
+void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
llvm::Constant *Init) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
// Create the descriptor for the variable.
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
StringRef Name = VD->getName();
@@ -2923,34 +3167,79 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
// Do not use DIGlobalVariable for enums.
if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
- DBuilder.createStaticVariable(Unit, Name, Name, Unit,
- getLineNumber(VD->getLocation()),
- Ty, true, Init,
- getStaticDataMemberDeclaration(VD));
+ llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
+ Unit, Name, Name, Unit, getLineNumber(VD->getLocation()), Ty, true, Init,
+ getOrCreateStaticDataMemberDeclarationOrNull(cast<VarDecl>(VD)));
+ DeclCache.insert(std::make_pair(VD->getCanonicalDecl(), llvm::WeakVH(GV)));
+}
+
+llvm::DIScope CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
+ if (!LexicalBlockStack.empty())
+ return llvm::DIScope(LexicalBlockStack.back());
+ return getContextDescriptor(D);
}
void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
- llvm::DIScope Scope =
- LexicalBlockStack.empty()
- ? getContextDescriptor(cast<Decl>(UD.getDeclContext()))
- : llvm::DIScope(LexicalBlockStack.back());
+ if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
+ return;
DBuilder.createImportedModule(
- Scope, getOrCreateNameSpace(UD.getNominatedNamespace()),
+ getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
+ getOrCreateNameSpace(UD.getNominatedNamespace()),
getLineNumber(UD.getLocation()));
}
+void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
+ if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
+ return;
+ assert(UD.shadow_size() &&
+ "We shouldn't be codegening an invalid UsingDecl containing no decls");
+ // Emitting one decl is sufficient - debuggers can detect that this is an
+ // overloaded name & provide lookup for all the overloads.
+ const UsingShadowDecl &USD = **UD.shadow_begin();
+ if (llvm::DIDescriptor Target =
+ getDeclarationOrDefinition(USD.getUnderlyingDecl()))
+ DBuilder.createImportedDeclaration(
+ getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
+ getLineNumber(USD.getLocation()));
+}
+
+llvm::DIImportedEntity
+CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
+ if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
+ return llvm::DIImportedEntity(0);
+ llvm::WeakVH &VH = NamespaceAliasCache[&NA];
+ if (VH)
+ return llvm::DIImportedEntity(cast<llvm::MDNode>(VH));
+ llvm::DIImportedEntity R(0);
+ if (const NamespaceAliasDecl *Underlying =
+ dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
+ // This could cache & dedup here rather than relying on metadata deduping.
+ R = DBuilder.createImportedModule(
+ getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
+ EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()),
+ NA.getName());
+ else
+ R = DBuilder.createImportedModule(
+ getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
+ getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
+ getLineNumber(NA.getLocation()), NA.getName());
+ VH = R;
+ return R;
+}
+
/// getOrCreateNamesSpace - Return namespace descriptor for the given
/// namespace decl.
-llvm::DINameSpace
+llvm::DINameSpace
CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
- llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
+ NSDecl = NSDecl->getCanonicalDecl();
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
NameSpaceCache.find(NSDecl);
if (I != NameSpaceCache.end())
return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
-
+
unsigned LineNo = getLineNumber(NSDecl->getLocation());
llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation());
- llvm::DIDescriptor Context =
+ llvm::DIDescriptor Context =
getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
llvm::DINameSpace NS =
DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
@@ -2965,7 +3254,7 @@ void CGDebugInfo::finalize() {
// Verify that the debug info still exists.
if (llvm::Value *V = VI->second)
Ty = llvm::DIType(cast<llvm::MDNode>(V));
-
+
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(VI->first);
if (it != TypeCache.end()) {
@@ -2974,7 +3263,7 @@ void CGDebugInfo::finalize() {
RepTy = llvm::DIType(cast<llvm::MDNode>(V));
}
- if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify())
+ if (Ty && Ty.isForwardDecl() && RepTy)
Ty.replaceAllUsesWith(RepTy);
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 4080492a1c68..0ca274f56881 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -18,6 +18,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/DIBuilder.h"
#include "llvm/DebugInfo.h"
@@ -35,6 +36,7 @@ namespace clang {
class ObjCIvarDecl;
class ClassTemplateSpecializationDecl;
class GlobalDecl;
+ class UsingDecl;
namespace CodeGen {
class CodeGenModule;
@@ -45,7 +47,10 @@ namespace CodeGen {
/// and is responsible for emitting to llvm globals or pass directly to
/// the backend.
class CGDebugInfo {
+ friend class NoLocation;
+ friend class ArtificialLocation;
CodeGenModule &CGM;
+ const CodeGenOptions::DebugInfoKind DebugKind;
llvm::DIBuilder DBuilder;
llvm::DICompileUnit TheCU;
SourceLocation CurLoc, PrevLoc;
@@ -57,14 +62,14 @@ class CGDebugInfo {
llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
llvm::DIType OCLImage3dDITy;
llvm::DIType OCLEventDITy;
-
+ llvm::DIType BlockLiteralGeneric;
+
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
/// ObjCInterfaceCache - Cache of previously constructed interfaces
/// which may change. Storing a pair of DIType and checksum.
- llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
- ObjCInterfaceCache;
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned> > ObjCInterfaceCache;
/// RetainedTypes - list of interfaces we want to keep even if orphaned.
std::vector<void *> RetainedTypes;
@@ -76,9 +81,6 @@ class CGDebugInfo {
/// compilation.
std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
- bool BlockLiteralGenericSet;
- llvm::DIType BlockLiteralGeneric;
-
// LexicalBlockStack - Keep track of our current nested lexical block.
std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
@@ -94,22 +96,28 @@ class CGDebugInfo {
llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+ /// \brief 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::WeakVH> DeclCache;
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
+ llvm::DenseMap<const NamespaceAliasDecl *, llvm::WeakVH> NamespaceAliasCache;
llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
/// Helper functions for getOrCreateType.
unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
llvm::DIType CreateType(const BuiltinType *Ty);
llvm::DIType CreateType(const ComplexType *Ty);
- llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
- llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile F);
+ llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile Fg);
+ llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile Fg);
llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile F);
llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const RecordType *Ty);
- llvm::DIType CreateLimitedType(const RecordType *Ty);
+ llvm::DIType CreateType(const RecordType *Tyg);
+ llvm::DIType CreateTypeDefinition(const RecordType *Ty);
+ llvm::DICompositeType CreateLimitedType(const RecordType *Ty);
+ void CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType CT);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
@@ -118,19 +126,19 @@ class CGDebugInfo {
llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit);
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
- llvm::DIType CreateEnumType(const EnumDecl *ED);
+ llvm::DIType CreateEnumType(const EnumType *Ty);
llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
llvm::DIType getTypeOrNull(const QualType);
llvm::DIType getCompletedTypeOrNull(const QualType);
- llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile F);
- llvm::DIType getOrCreateInstanceMethodType(
+ llvm::DICompositeType getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DIFile F);
+ llvm::DICompositeType getOrCreateInstanceMethodType(
QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit);
- llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
- llvm::DIFile F);
+ llvm::DICompositeType getOrCreateFunctionType(const Decl *D, QualType FnType,
+ llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
- llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F);
+ llvm::DIType getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile F);
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DIFile F);
@@ -141,29 +149,24 @@ class CGDebugInfo {
llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
llvm::DIFile F,
llvm::DIType RecordTy);
-
+
void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType T);
- void CollectCXXFriends(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy);
-
void CollectCXXBases(const CXXRecordDecl *Decl,
llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy);
-
+
llvm::DIArray
CollectTemplateParams(const TemplateParameterList *TPList,
- const TemplateArgumentList &TAList,
+ ArrayRef<TemplateArgument> TAList,
llvm::DIFile Unit);
llvm::DIArray
CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit);
- llvm::DIArray
+ llvm::DIArray
CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
llvm::DIFile F);
@@ -171,22 +174,21 @@ class CGDebugInfo {
uint64_t sizeInBitsOverride, SourceLocation loc,
AccessSpecifier AS, uint64_t offsetInBits,
llvm::DIFile tunit,
- llvm::DIDescriptor scope);
+ llvm::DIScope scope);
// Helpers for collecting fields of a record.
void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
- void CollectRecordStaticField(const VarDecl *Var,
- SmallVectorImpl<llvm::Value *> &E,
- llvm::DIType RecordTy);
+ llvm::DIDerivedType CreateRecordStaticField(const VarDecl *Var,
+ llvm::DIType RecordTy);
void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
- llvm::DIType RecordTy);
+ llvm::DICompositeType RecordTy);
void CollectVTableInfo(const CXXRecordDecl *Decl,
llvm::DIFile F,
@@ -195,7 +197,7 @@ class CGDebugInfo {
// CreateLexicalBlock - Create a new lexical block node and push it on
// the stack.
void CreateLexicalBlock(SourceLocation Loc);
-
+
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
@@ -206,6 +208,9 @@ public:
/// invalid it is ignored.
void setLocation(SourceLocation Loc);
+ /// getLocation - Return the current source location.
+ SourceLocation getLocation() const { return CurLoc; }
+
/// EmitLocation - Emit metadata to indicate a change in line/column
/// information in the source file.
/// \param ForceColumnInfo Assume DebugColumnInfo option is true.
@@ -265,20 +270,30 @@ public:
/// \brief - Emit C++ using directive.
void EmitUsingDirective(const UsingDirectiveDecl &UD);
- /// getOrCreateRecordType - Emit record type's standalone debug info.
+ /// \brief - Emit C++ using declaration.
+ void EmitUsingDecl(const UsingDecl &UD);
+
+ /// \brief - Emit C++ namespace alias.
+ llvm::DIImportedEntity EmitNamespaceAlias(const NamespaceAliasDecl &NA);
+
+ /// getOrCreateRecordType - Emit record type's standalone debug info.
llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L);
/// getOrCreateInterfaceType - Emit an objective c interface type standalone
/// debug info.
llvm::DIType getOrCreateInterfaceType(QualType Ty,
- SourceLocation Loc);
+ SourceLocation Loc);
+
+ void completeType(const RecordDecl *RD);
+ void completeRequiredType(const RecordDecl *RD);
+ void completeClassData(const RecordDecl *RD);
private:
/// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
unsigned ArgNo, CGBuilderTy &Builder);
- // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+ // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *OffSet);
@@ -286,10 +301,12 @@ private:
/// getContextDescriptor - Get context info for the decl.
llvm::DIScope getContextDescriptor(const Decl *Decl);
- /// createRecordFwdDecl - Create a forward decl for a RecordType in a given
- /// context.
- llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor);
-
+ llvm::DIScope getCurrentContextDescriptor(const Decl *Decl);
+
+ /// \brief Create a forward decl for a RecordType in a given context.
+ llvm::DICompositeType getOrCreateRecordFwdDecl(const RecordType *,
+ llvm::DIDescriptor);
+
/// createContextChain - Create a set of decls for the context chain.
llvm::DIDescriptor createContextChain(const Decl *Decl);
@@ -299,7 +316,7 @@ private:
/// CreateCompileUnit - Create new compile unit.
void CreateCompileUnit();
- /// getOrCreateFile - Get the file debug info descriptor for the input
+ /// getOrCreateFile - Get the file debug info descriptor for the input
/// location.
llvm::DIFile getOrCreateFile(SourceLocation Loc);
@@ -308,43 +325,43 @@ private:
/// getOrCreateType - Get the type from the cache or create a new type if
/// necessary.
- llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
+ llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile Fg);
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// partial type if necessary.
- llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
+ llvm::DIType getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile F);
/// CreateTypeNode - Create type metadata for a source language type.
- llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile Fg);
/// getObjCInterfaceDecl - return the underlying ObjCInterfaceDecl
/// if Ty is an ObjCInterface or a pointer to one.
ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty);
- /// CreateLimitedTypeNode - Create type metadata for a source language
- /// type, but only partial types for records.
- llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
-
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, uint64_t *Offset);
+ /// \brief Retrieve the DIDescriptor, if any, for the canonical form of this
+ /// declaration.
+ llvm::DIDescriptor getDeclarationOrDefinition(const Decl *D);
+
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
llvm::DISubprogram getFunctionDeclaration(const Decl *D);
- /// getStaticDataMemberDeclaration - Return debug info descriptor to
- /// describe in-class static data member declaration for the given
- /// out-of-class definition.
- llvm::DIDerivedType getStaticDataMemberDeclaration(const Decl *D);
+ /// Return debug info descriptor to describe in-class static data member
+ /// declaration for the given out-of-class definition.
+ llvm::DIDerivedType
+ getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
/// getFunctionName - Get function name for the given FunctionDecl. If the
- /// name is constructred on demand (e.g. C++ destructor) then the name
+ /// name is constructed on demand (e.g. C++ destructor) then the name
/// is stored on the side.
StringRef getFunctionName(const FunctionDecl *FD);
/// getObjCMethodName - Returns the unmangled name of an Objective-C method.
- /// This is the display name for the debugging info.
+ /// This is the display name for the debugging info.
StringRef getObjCMethodName(const ObjCMethodDecl *FD);
/// getSelectorName - Return selector name. This is used for debugging
@@ -361,11 +378,62 @@ private:
/// then use current location.
unsigned getLineNumber(SourceLocation Loc);
- /// getColumnNumber - Get column number for the location. If location is
+ /// getColumnNumber - Get column number for the location. If location is
/// invalid then use current location.
/// \param Force Assume DebugColumnInfo option is true.
unsigned getColumnNumber(SourceLocation Loc, bool Force=false);
+
+ /// internString - Allocate a copy of \p A using the DebugInfoNames allocator
+ /// and return a reference to it. If multiple arguments are given the strings
+ /// are concatenated.
+ StringRef internString(StringRef A, StringRef B = StringRef()) {
+ char *Data = DebugInfoNames.Allocate<char>(A.size() + B.size());
+ std::memcpy(Data, A.data(), A.size());
+ std::memcpy(Data + A.size(), B.data(), B.size());
+ return StringRef(Data, A.size() + B.size());
+ }
};
+
+/// NoLocation - An RAII object that temporarily disables debug
+/// locations. This is useful for emitting instructions that should be
+/// counted towards the function prologue.
+class NoLocation {
+ SourceLocation SavedLoc;
+ CGDebugInfo *DI;
+ CGBuilderTy &Builder;
+public:
+ NoLocation(CodeGenFunction &CGF, CGBuilderTy &B);
+ /// ~NoLocation - Autorestore everything back to normal.
+ ~NoLocation();
+};
+
+/// ArtificialLocation - An RAII object that temporarily switches to
+/// an artificial debug location that has a valid scope, but no line
+/// information. This is useful when emitting compiler-generated
+/// helper functions that have no source location associated with
+/// them. The DWARF specification allows the compiler to use the
+/// special line number 0 to indicate code that can not be attributed
+/// to any source location.
+///
+/// This is necessary because passing an empty SourceLocation to
+/// CGDebugInfo::setLocation() will result in the last valid location
+/// being reused.
+class ArtificialLocation {
+ SourceLocation SavedLoc;
+ CGDebugInfo *DI;
+ CGBuilderTy &Builder;
+public:
+ ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B);
+
+ /// Set the current location to line 0, but within the current scope
+ /// (= the top of the LexicalBlockStack).
+ void Emit();
+
+ /// ~ArtificialLocation - Autorestore everything back to normal.
+ ~ArtificialLocation();
+};
+
+
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 3ce6dec6a53c..66d6b33eb6f0 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalVariable.h"
@@ -37,6 +38,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::UnresolvedUsingTypename:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingValue:
case Decl::NonTypeTemplateParm:
@@ -52,6 +55,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ParmVar:
case Decl::ImplicitParam:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
@@ -72,15 +76,13 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Block:
case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
+ case Decl::UsingShadow:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
case Decl::EnumConstant: // enum ? { X = ? }
case Decl::CXXRecord: // struct/union/class X; [C++]
- case Decl::Using: // using X; [C++]
- case Decl::UsingShadow:
- case Decl::NamespaceAlias:
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
case Decl::Import:
@@ -89,6 +91,14 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
// None of these decls require codegen support.
return;
+ case Decl::NamespaceAlias:
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(D));
+ return;
+ case Decl::Using: // using X; [C++]
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitUsingDecl(cast<UsingDecl>(D));
+ return;
case Decl::UsingDirective: // using namespace X; [C++]
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D));
@@ -114,35 +124,32 @@ 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) {
- switch (D.getStorageClass()) {
- case SC_None:
- case SC_Auto:
- case SC_Register:
- return EmitAutoVarDecl(D);
- case SC_Static: {
+ if (D.isStaticLocal()) {
llvm::GlobalValue::LinkageTypes Linkage =
llvm::GlobalValue::InternalLinkage;
- // If the function definition has some sort of weak linkage, its
- // static variables should also be weak so that they get properly
- // uniqued. We can't do this in C, though, because there's no
- // standard way to agree on which variables are the same (i.e.
- // there's no mangling).
- if (getLangOpts().CPlusPlus)
- if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
- Linkage = CurFn->getLinkage();
+ // If the variable is externally visible, it must have weak linkage so it
+ // can be uniqued.
+ if (D.isExternallyVisible()) {
+ Linkage = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ // FIXME: We need to force the emission/use of a guard variable for
+ // some variables even if we can constant-evaluate them because
+ // we can't guarantee every translation unit will constant-evaluate them.
+ }
return EmitStaticVarDecl(D, Linkage);
}
- case SC_Extern:
- case SC_PrivateExtern:
+
+ if (D.hasExternalStorage())
// Don't emit it now, allow it to be emitted lazily on its first use.
return;
- case SC_OpenCLWorkGroupLocal:
+
+ if (D.getStorageClass() == SC_OpenCLWorkGroupLocal)
return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
- }
- llvm_unreachable("Unknown storage class");
+ assert(D.hasLocalStorage());
+ return EmitAutoVarDecl(D);
}
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
@@ -200,8 +207,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable::NotThreadLocal,
AddrSpace);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
- if (Linkage != llvm::GlobalValue::InternalLinkage)
- GV->setVisibility(CurFn->getVisibility());
+ CGM.setGlobalVisibility(GV, &D);
if (D.getTLSKind())
CGM.setTLSMode(GV, D);
@@ -420,7 +426,8 @@ namespace {
// byref or something.
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), false,
Var.getType(), VK_LValue, SourceLocation());
- llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
+ llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE),
+ SourceLocation());
CGF.EmitExtendGCLifetime(value);
}
};
@@ -647,7 +654,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
// might have to initialize with a barrier. We have to do this for
// both __weak and __strong, but __weak got filtered out above.
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
- llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
+ llvm::Value *oldValue = EmitLoadOfScalar(lvalue, init->getExprLoc());
EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
EmitARCRelease(oldValue, ARCImpreciseLifetime);
return;
@@ -838,19 +845,19 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
bool NRVO = getLangOpts().ElideConstructors &&
D.isNRVOVariable();
- // If this value is a POD array or struct with a statically
- // determinable constant initializer, there are optimizations we can do.
+ // If this value is an array or struct with a statically determinable
+ // constant initializer, there are optimizations we can do.
//
// TODO: We should constant-evaluate the initializer of any variable,
// as long as it is initialized by a constant expression. Currently,
// isConstantInitializer produces wrong answers for structs with
// reference or bitfield members, and a few other cases, and checking
// for POD-ness protects us from some of these.
- if (D.getInit() &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
- (Ty.isPODType(getContext()) ||
- getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
- D.getInit()->isConstantInitializer(getContext(), false)) {
+ if (D.getInit() && (Ty->isArrayType() || Ty->isRecordType()) &&
+ (D.isConstexpr() ||
+ ((Ty.isPODType(getContext()) ||
+ getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
+ D.getInit()->isConstantInitializer(getContext(), false)))) {
// If the variable's a const type, and it's neither an NRVO
// candidate nor a __block variable and has no mutable members,
@@ -1078,7 +1085,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
llvm::Constant *constant = 0;
- if (emission.IsConstantAggregate) {
+ if (emission.IsConstantAggregate || D.isConstexpr()) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = CGM.EmitConstantInit(D, this);
}
@@ -1089,6 +1096,13 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
return EmitExprAsInit(Init, &D, lv, capturedByInit);
}
+ if (!emission.IsConstantAggregate) {
+ // For simple scalar/complex initialization, store the value directly.
+ LValue lv = MakeAddrLValue(Loc, type, alignment);
+ lv.setNonGC(true);
+ return EmitStoreThroughLValue(RValue::get(constant), lv, true);
+ }
+
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
bool isVolatile = type.isVolatileQualified();
@@ -1151,7 +1165,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
QualType type = D->getType();
if (type->isReferenceType()) {
- RValue rvalue = EmitReferenceBindingToExpr(init, D);
+ RValue rvalue = EmitReferenceBindingToExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true);
@@ -1178,7 +1192,6 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
}
- MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
return;
}
llvm_unreachable("bad evaluation kind");
@@ -1331,6 +1344,26 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
destroyer, useEHCleanupForArray);
}
+void CodeGenFunction::pushLifetimeExtendedDestroy(
+ CleanupKind cleanupKind, llvm::Value *addr, QualType type,
+ Destroyer *destroyer, bool useEHCleanupForArray) {
+ assert(!isInConditionalBranch() &&
+ "performing lifetime extension from within conditional");
+
+ // Push an EH-only cleanup for the object now.
+ // FIXME: When popping normal cleanups, we need to keep this EH cleanup
+ // around in case a temporary's destructor throws an exception.
+ if (cleanupKind & EHCleanup)
+ EHStack.pushCleanup<DestroyObject>(
+ static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
+ destroyer, useEHCleanupForArray);
+
+ // Remember that we need to push a full cleanup for the object at the
+ // end of the full-expression.
+ pushCleanupAfterFullExpr<DestroyObject>(
+ cleanupKind, addr, type, destroyer, useEHCleanupForArray);
+}
+
/// emitDestroy - Immediately perform the destruction of the given
/// object.
///
@@ -1608,10 +1641,18 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
llvm::Value *DeclPtr;
+ bool HasNonScalarEvalKind = !CodeGenFunction::hasScalarEvaluationKind(Ty);
// If this is an aggregate or variable sized value, reuse the input pointer.
- if (!Ty->isConstantSizeType() ||
- !CodeGenFunction::hasScalarEvaluationKind(Ty)) {
+ if (HasNonScalarEvalKind || !Ty->isConstantSizeType()) {
DeclPtr = Arg;
+ // Push a destructor cleanup for this parameter if the ABI requires it.
+ if (HasNonScalarEvalKind &&
+ getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ if (const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
+ if (RD->hasNonTrivialDestructor())
+ pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
+ }
+ }
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
@@ -1649,7 +1690,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// use objc_storeStrong(&dest, value) for retaining the
// object. But first, store a null into 'dest' because
// objc_storeStrong attempts to release its old value.
- llvm::Value * Null = CGM.EmitNullConstant(D.getType());
+ llvm::Value *Null = CGM.EmitNullConstant(D.getType());
EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
EmitARCStoreStrongCall(lv.getAddress(), Arg, true);
doStore = false;
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 9ffcff276623..7bdb9eb0a4a6 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -96,13 +96,14 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
CXXDestructorDecl *dtor = record->getDestructor();
function = CGM.GetAddrOfCXXDestructor(dtor, Dtor_Complete);
- argument = addr;
+ argument = llvm::ConstantExpr::getBitCast(
+ addr, CGF.getTypes().ConvertType(type)->getPointerTo());
// Otherwise, the standard logic requires a helper function.
} else {
- function = CodeGenFunction(CGM).generateDestroyHelper(addr, type,
- CGF.getDestroyer(dtorKind),
- CGF.needsEHCleanup(dtorKind));
+ function = CodeGenFunction(CGM)
+ .generateDestroyHelper(addr, type, CGF.getDestroyer(dtorKind),
+ CGF.needsEHCleanup(dtorKind), &D);
argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
}
@@ -149,7 +150,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
assert(PerformInit && "cannot have constant initializer which needs "
"destruction for reference");
unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
- RValue RV = EmitReferenceBindingToExpr(Init, &D);
+ RValue RV = EmitReferenceBindingToExpr(Init);
EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
}
@@ -161,23 +162,24 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
/// Create a stub function, suitable for being passed to atexit,
/// which passes the given address to the given destructor function.
-static llvm::Constant *createAtExitStub(CodeGenModule &CGM,
+static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD,
llvm::Constant *dtor,
llvm::Constant *addr) {
// Get the destructor function type, void(*)(void).
llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false);
+ SmallString<256> FnName;
+ {
+ llvm::raw_svector_ostream Out(FnName);
+ CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out);
+ }
llvm::Function *fn =
- CreateGlobalInitOrDestructFunction(CGM, ty,
- Twine("__dtor_", addr->getName()));
+ CreateGlobalInitOrDestructFunction(CGM, ty, FnName.str());
CodeGenFunction CGF(CGM);
- // Initialize debug info if needed.
- CGF.maybeInitializeDebugInfo();
-
- CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn,
- CGM.getTypes().arrangeNullaryFunction(),
- FunctionArgList(), SourceLocation());
+ CGF.StartFunction(&VD, CGM.getContext().VoidTy, fn,
+ CGM.getTypes().arrangeNullaryFunction(), FunctionArgList(),
+ SourceLocation());
llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
@@ -192,10 +194,11 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM,
}
/// Register a global destructor using the C atexit runtime function.
-void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtor,
+void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
+ llvm::Constant *dtor,
llvm::Constant *addr) {
// Create a function which calls the destructor.
- llvm::Constant *dtorStub = createAtExitStub(CGM, dtor, addr);
+ llvm::Constant *dtorStub = createAtExitStub(CGM, VD, dtor, addr);
// extern "C" int atexit(void (*f)(void));
llvm::FunctionType *atexitTy =
@@ -257,10 +260,15 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+ SmallString<256> FnName;
+ {
+ llvm::raw_svector_ostream Out(FnName);
+ getCXXABI().getMangleContext().mangleDynamicInitializer(D, Out);
+ }
// Create a variable initialization function.
llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init");
+ CreateGlobalInitOrDestructFunction(*this, FTy, FnName.str());
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
PerformInit);
@@ -278,6 +286,20 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
+ } else if (D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
+ D->getTemplateSpecializationKind() != TSK_Undeclared) {
+ // C++ [basic.start.init]p2:
+ // Definitions of explicitly specialized class template static data
+ // members have ordered initialization. Other class template static data
+ // members (i.e., implicitly or explicitly instantiated specializations)
+ // have unordered initialization.
+ //
+ // As a consequence, we can put them into their own llvm.global_ctors entry.
+ // This should allow GlobalOpt to fire more often, and allow us to implement
+ // the Microsoft C++ ABI, which uses COMDAT elimination to avoid double
+ // initializaiton.
+ AddGlobalCtor(Fn);
+ DelayedCXXInitPosition.erase(D);
} else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
DelayedCXXInitPosition.find(D);
@@ -386,8 +408,8 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
llvm::GlobalVariable *Addr,
bool PerformInit) {
// Check if we need to emit debug info for variable initializer.
- if (!D->hasAttr<NoDebugAttr>())
- maybeInitializeDebugInfo();
+ if (D->hasAttr<NoDebugAttr>())
+ DebugInfo = NULL; // disable debug info indefinitely for this function
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
@@ -410,9 +432,6 @@ void
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Constant *> Decls,
llvm::GlobalVariable *Guard) {
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
-
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -459,9 +478,6 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
-
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -481,11 +497,9 @@ void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
/// generateDestroyHelper - Generates a helper function which, when
/// invoked, destroys the given object.
-llvm::Function *
-CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
- QualType type,
- Destroyer *destroyer,
- bool useEHCleanupForArray) {
+llvm::Function *CodeGenFunction::generateDestroyHelper(
+ llvm::Constant *addr, QualType type, Destroyer *destroyer,
+ bool useEHCleanupForArray, const VarDecl *VD) {
FunctionArgList args;
ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
args.push_back(&dst);
@@ -498,11 +512,7 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
-
- StartFunction(GlobalDecl(), getContext().VoidTy, fn, FI, args,
- SourceLocation());
+ StartFunction(VD, getContext().VoidTy, fn, FI, args, SourceLocation());
emitDestroy(addr, type, destroyer, useEHCleanupForArray);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index a088d78641fa..39a992aab17d 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -89,7 +89,7 @@ static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
}
static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
- // void __cxa_call_unexepcted(void *thrown_exception);
+ // void __cxa_call_unexpected(void *thrown_exception);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
@@ -766,6 +766,11 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Save the current IR generation state.
CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
+ SourceLocation SavedLocation;
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ SavedLocation = DI->getLocation();
+ DI->EmitLocation(Builder, CurEHLocation);
+ }
const EHPersonality &personality = EHPersonality::get(getLangOpts());
@@ -887,6 +892,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Restore the old IR generation state.
Builder.restoreIP(savedIP);
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitLocation(Builder, SavedLocation);
return lpad;
}
@@ -938,7 +945,8 @@ static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
/// parameter during catch initialization.
static void InitCatchParam(CodeGenFunction &CGF,
const VarDecl &CatchParam,
- llvm::Value *ParamAddr) {
+ llvm::Value *ParamAddr,
+ SourceLocation Loc) {
// Load the exception from where the landing pad saved it.
llvm::Value *Exn = CGF.getExceptionFromSlot();
@@ -1045,11 +1053,11 @@ static void InitCatchParam(CodeGenFunction &CGF,
CGF.getContext().getDeclAlign(&CatchParam));
switch (TEK) {
case TEK_Complex:
- CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV), destLV,
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
/*init*/ true);
return;
case TEK_Scalar: {
- llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV);
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
return;
}
@@ -1143,7 +1151,7 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
// Emit the local.
CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
- InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF));
+ InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getLocStart());
CGF.EmitAutoVarCleanups(var);
}
@@ -1612,8 +1620,15 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
- llvm::CallInst *TerminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
- TerminateCall->setDoesNotReturn();
+ llvm::CallInst *terminateCall;
+ if (useClangCallTerminate(CGM)) {
+ // Load the exception pointer.
+ llvm::Value *exn = getExceptionFromSlot();
+ terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
+ } else {
+ terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
+ }
+ terminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1683,3 +1698,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
return EHResumeBlock;
}
+
+void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
+ CGM.ErrorUnsupported(&S, "SEH __try");
+}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 64670c5e81e4..cb990b243fba 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -171,244 +171,240 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
llvm_unreachable("bad evaluation kind");
}
-static llvm::Value *
-CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
- const NamedDecl *InitializedDecl) {
- if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
- if (VD->hasGlobalStorage()) {
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
- Out.flush();
-
- llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
-
- // Create the reference temporary.
- llvm::GlobalVariable *RefTemp =
- new llvm::GlobalVariable(CGF.CGM.getModule(),
- RefTempTy, /*isConstant=*/false,
- llvm::GlobalValue::InternalLinkage,
- llvm::Constant::getNullValue(RefTempTy),
- Name.str());
- // If we're binding to a thread_local variable, the temporary is also
- // thread local.
- if (VD->getTLSKind())
- CGF.CGM.setTLSMode(RefTemp, *VD);
- return RefTemp;
- }
- }
-
- return CGF.CreateMemTemp(Type, "ref.tmp");
-}
-
-static llvm::Value *
-EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
- llvm::Value *&ReferenceTemporary,
- const CXXDestructorDecl *&ReferenceTemporaryDtor,
- const InitListExpr *&ReferenceInitializerList,
- QualType &ObjCARCReferenceLifetimeType,
- const NamedDecl *InitializedDecl) {
- const MaterializeTemporaryExpr *M = NULL;
- E = E->findMaterializedTemporary(M);
+static void
+pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
+ const Expr *E, llvm::Value *ReferenceTemporary) {
// Objective-C++ ARC:
// If we are binding a reference to a temporary that has ownership, we
// need to perform retain/release operations on the temporary.
- if (M && CGF.getLangOpts().ObjCAutoRefCount &&
- M->getType()->isObjCLifetimeType() &&
- (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
- M->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
- M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
- ObjCARCReferenceLifetimeType = M->getType();
-
- if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
- CGF.enterFullExpression(EWC);
- CodeGenFunction::RunCleanupsScope Scope(CGF);
-
- return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(),
- ReferenceTemporary,
- ReferenceTemporaryDtor,
- ReferenceInitializerList,
- ObjCARCReferenceLifetimeType,
- InitializedDecl);
- }
-
- if (E->isGLValue()) {
- // Emit the expression as an lvalue.
- LValue LV = CGF.EmitLValue(E);
- assert(LV.isSimple());
- return LV.getAddress();
- }
-
- if (!ObjCARCReferenceLifetimeType.isNull()) {
- ReferenceTemporary = CreateReferenceTemporary(CGF,
- ObjCARCReferenceLifetimeType,
- InitializedDecl);
-
-
- LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary,
- ObjCARCReferenceLifetimeType);
-
- CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl),
- RefTempDst, false);
-
- bool ExtendsLifeOfTemporary = false;
- if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
- if (Var->extendsLifetimeOfTemporary())
- ExtendsLifeOfTemporary = true;
- } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) {
- ExtendsLifeOfTemporary = true;
- }
-
- if (!ExtendsLifeOfTemporary) {
- // Since the lifetime of this temporary isn't going to be extended,
- // we need to clean it up ourselves at the end of the full expression.
- switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- break;
-
- case Qualifiers::OCL_Strong: {
- assert(!ObjCARCReferenceLifetimeType->isArrayType());
- CleanupKind cleanupKind = CGF.getARCCleanupKind();
- CGF.pushDestroy(cleanupKind,
- ReferenceTemporary,
- ObjCARCReferenceLifetimeType,
- CodeGenFunction::destroyARCStrongImprecise,
- cleanupKind & EHCleanup);
- break;
- }
-
- case Qualifiers::OCL_Weak:
+ //
+ // FIXME: This should be looking at E, not M.
+ if (CGF.getLangOpts().ObjCAutoRefCount &&
+ M->getType()->isObjCLifetimeType()) {
+ QualType ObjCARCReferenceLifetimeType = M->getType();
+ switch (Qualifiers::ObjCLifetime Lifetime =
+ ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // Carry on to normal cleanup handling.
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ // Nothing to do; cleaned up by an autorelease pool.
+ return;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ switch (StorageDuration Duration = M->getStorageDuration()) {
+ case SD_Static:
+ // Note: we intentionally do not register a cleanup to release
+ // the object on program termination.
+ return;
+
+ case SD_Thread:
+ // FIXME: We should probably register a cleanup in this case.
+ return;
+
+ case SD_Automatic:
+ case SD_FullExpression:
assert(!ObjCARCReferenceLifetimeType->isArrayType());
- CGF.pushDestroy(NormalAndEHCleanup,
- ReferenceTemporary,
- ObjCARCReferenceLifetimeType,
- CodeGenFunction::destroyARCWeak,
- /*useEHCleanupForArray*/ true);
- break;
+ CodeGenFunction::Destroyer *Destroy;
+ CleanupKind CleanupKind;
+ if (Lifetime == Qualifiers::OCL_Strong) {
+ const ValueDecl *VD = M->getExtendingDecl();
+ bool Precise =
+ VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();
+ CleanupKind = CGF.getARCCleanupKind();
+ Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise
+ : &CodeGenFunction::destroyARCStrongImprecise;
+ } else {
+ // __weak objects always get EH cleanups; otherwise, exceptions
+ // could cause really nasty crashes instead of mere leaks.
+ CleanupKind = NormalAndEHCleanup;
+ Destroy = &CodeGenFunction::destroyARCWeak;
+ }
+ if (Duration == SD_FullExpression)
+ CGF.pushDestroy(CleanupKind, ReferenceTemporary,
+ ObjCARCReferenceLifetimeType, *Destroy,
+ CleanupKind & EHCleanup);
+ else
+ CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
+ ObjCARCReferenceLifetimeType,
+ *Destroy, CleanupKind & EHCleanup);
+ return;
+
+ case SD_Dynamic:
+ llvm_unreachable("temporary cannot have dynamic storage duration");
}
-
- ObjCARCReferenceLifetimeType = QualType();
+ llvm_unreachable("unknown storage duration");
}
-
- return ReferenceTemporary;
}
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- E = E->skipRValueSubobjectAdjustments(Adjustments);
- if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
- if (opaque->getType()->isRecordType())
- return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+ CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+ if (const RecordType *RT =
+ E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ // Get the destructor for the reference temporary.
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (!ClassDecl->hasTrivialDestructor())
+ ReferenceTemporaryDtor = ClassDecl->getDestructor();
+ }
- // Create a reference temporary if necessary.
- AggValueSlot AggSlot = AggValueSlot::ignored();
- if (CGF.hasAggregateEvaluationKind(E->getType())) {
- ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
- InitializedDecl);
- CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
- AggValueSlot::IsDestructed_t isDestructed
- = AggValueSlot::IsDestructed_t(InitializedDecl != 0);
- AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment,
- Qualifiers(), isDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
- }
-
- if (InitializedDecl) {
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->initializesStdInitializerList()) {
- ReferenceInitializerList = ILE;
- }
- }
- else if (const RecordType *RT =
- E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){
- // Get the destructor for the reference temporary.
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (!ClassDecl->hasTrivialDestructor())
- ReferenceTemporaryDtor = ClassDecl->getDestructor();
+ if (!ReferenceTemporaryDtor)
+ return;
+
+ // Call the destructor for the temporary.
+ switch (M->getStorageDuration()) {
+ case SD_Static:
+ case SD_Thread: {
+ llvm::Constant *CleanupFn;
+ llvm::Constant *CleanupArg;
+ if (E->getType()->isArrayType()) {
+ CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(
+ cast<llvm::Constant>(ReferenceTemporary), E->getType(),
+ CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions,
+ dyn_cast_or_null<VarDecl>(M->getExtendingDecl()));
+ CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
+ } else {
+ CleanupFn =
+ CGF.CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+ CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
}
+ CGF.CGM.getCXXABI().registerGlobalDtor(
+ CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
+ break;
}
- RValue RV = CGF.EmitAnyExpr(E, AggSlot);
-
- // Check if need to perform derived-to-base casts and/or field accesses, to
- // get from the temporary object we created (and, potentially, for which we
- // extended the lifetime) to the subobject we're binding the reference to.
- if (!Adjustments.empty()) {
- llvm::Value *Object = RV.getAggregateAddr();
- for (unsigned I = Adjustments.size(); I != 0; --I) {
- SubobjectAdjustment &Adjustment = Adjustments[I-1];
- switch (Adjustment.Kind) {
- case SubobjectAdjustment::DerivedToBaseAdjustment:
- Object =
- CGF.GetAddressOfBaseClass(Object,
- Adjustment.DerivedToBase.DerivedClass,
- Adjustment.DerivedToBase.BasePath->path_begin(),
- Adjustment.DerivedToBase.BasePath->path_end(),
- /*NullCheckValue=*/false);
- break;
-
- case SubobjectAdjustment::FieldAdjustment: {
- LValue LV = CGF.MakeAddrLValue(Object, E->getType());
- LV = CGF.EmitLValueForField(LV, Adjustment.Field);
- if (LV.isSimple()) {
- Object = LV.getAddress();
- break;
- }
-
- // For non-simple lvalues, we actually have to create a copy of
- // the object we're binding to.
- QualType T = Adjustment.Field->getType().getNonReferenceType()
- .getUnqualifiedType();
- Object = CreateReferenceTemporary(CGF, T, InitializedDecl);
- LValue TempLV = CGF.MakeAddrLValue(Object,
- Adjustment.Field->getType());
- CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV);
- break;
- }
+ case SD_FullExpression:
+ CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+ CodeGenFunction::destroyCXXObject,
+ CGF.getLangOpts().Exceptions);
+ break;
- case SubobjectAdjustment::MemberPointerAdjustment: {
- llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
- Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
- CGF, Object, Ptr, Adjustment.Ptr.MPT);
- break;
- }
- }
+ case SD_Automatic:
+ CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,
+ ReferenceTemporary, E->getType(),
+ CodeGenFunction::destroyCXXObject,
+ CGF.getLangOpts().Exceptions);
+ break;
+
+ case SD_Dynamic:
+ llvm_unreachable("temporary cannot have dynamic storage duration");
+ }
+}
+
+static llvm::Value *
+createReferenceTemporary(CodeGenFunction &CGF,
+ const MaterializeTemporaryExpr *M, const Expr *Inner) {
+ switch (M->getStorageDuration()) {
+ case SD_FullExpression:
+ case SD_Automatic:
+ return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
+
+ case SD_Thread:
+ case SD_Static:
+ return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);
+
+ case SD_Dynamic:
+ llvm_unreachable("temporary can't have dynamic storage duration");
+ }
+ llvm_unreachable("unknown storage duration");
+}
+
+LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *M) {
+ const Expr *E = M->GetTemporaryExpr();
+
+ if (getLangOpts().ObjCAutoRefCount &&
+ M->getType()->isObjCLifetimeType() &&
+ M->getType().getObjCLifetime() != Qualifiers::OCL_None &&
+ M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ // FIXME: Fold this into the general case below.
+ llvm::Value *Object = createReferenceTemporary(*this, M, E);
+ LValue RefTempDst = MakeAddrLValue(Object, M->getType());
+
+ if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
+ // We should not have emitted the initializer for this temporary as a
+ // constant.
+ assert(!Var->hasInitializer());
+ Var->setInitializer(CGM.EmitNullConstant(E->getType()));
}
- return Object;
+ EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false);
+
+ pushTemporaryCleanup(*this, M, E, Object);
+ return RefTempDst;
}
- if (RV.isAggregate())
- return RV.getAggregateAddr();
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ E = E->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+
+ for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
+ EmitIgnoredExpr(CommaLHSs[I]);
- // Create a temporary variable that we can bind the reference to.
- ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
- InitializedDecl);
+ if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) {
+ if (opaque->getType()->isRecordType()) {
+ assert(Adjustments.empty());
+ return EmitOpaqueValueLValue(opaque);
+ }
+ }
+ // Create and initialize the reference temporary.
+ llvm::Value *Object = createReferenceTemporary(*this, M, E);
+ if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
+ // If the temporary is a global and has a constant initializer, we may
+ // have already initialized it.
+ if (!Var->hasInitializer()) {
+ Var->setInitializer(CGM.EmitNullConstant(E->getType()));
+ EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
+ }
+ } else {
+ EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
+ }
+ pushTemporaryCleanup(*this, M, E, Object);
+
+ // Perform derived-to-base casts and/or field accesses, to get from the
+ // temporary object we created (and, potentially, for which we extended
+ // the lifetime) to the subobject we're binding the reference to.
+ for (unsigned I = Adjustments.size(); I != 0; --I) {
+ SubobjectAdjustment &Adjustment = Adjustments[I-1];
+ switch (Adjustment.Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ Object =
+ GetAddressOfBaseClass(Object, Adjustment.DerivedToBase.DerivedClass,
+ Adjustment.DerivedToBase.BasePath->path_begin(),
+ Adjustment.DerivedToBase.BasePath->path_end(),
+ /*NullCheckValue=*/ false);
+ break;
- LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
- E->getType());
- if (RV.isScalar())
- CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
- else
- CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
- return ReferenceTemporary;
+ case SubobjectAdjustment::FieldAdjustment: {
+ LValue LV = MakeAddrLValue(Object, E->getType());
+ LV = EmitLValueForField(LV, Adjustment.Field);
+ assert(LV.isSimple() &&
+ "materialized temporary field is not a simple lvalue");
+ Object = LV.getAddress();
+ break;
+ }
+
+ case SubobjectAdjustment::MemberPointerAdjustment: {
+ llvm::Value *Ptr = EmitScalarExpr(Adjustment.Ptr.RHS);
+ Object = CGM.getCXXABI().EmitMemberDataPointerAddress(
+ *this, Object, Ptr, Adjustment.Ptr.MPT);
+ break;
+ }
+ }
+ }
+
+ return MakeAddrLValue(Object, M->getType());
}
RValue
-CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
- const NamedDecl *InitializedDecl) {
- llvm::Value *ReferenceTemporary = 0;
- const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
- const InitListExpr *ReferenceInitializerList = 0;
- QualType ObjCARCReferenceLifetimeType;
- llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
- ReferenceTemporaryDtor,
- ReferenceInitializerList,
- ObjCARCReferenceLifetimeType,
- InitializedDecl);
+CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E) {
+ // Emit the expression as an lvalue.
+ LValue LV = EmitLValue(E);
+ assert(LV.isSimple());
+ llvm::Value *Value = LV.getAddress();
+
if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {
// C++11 [dcl.ref]p5 (as amended by core issue 453):
// If a glvalue to which a reference is directly bound designates neither
@@ -418,80 +414,7 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
QualType Ty = E->getType();
EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
}
- if (!ReferenceTemporaryDtor && !ReferenceInitializerList &&
- ObjCARCReferenceLifetimeType.isNull())
- return RValue::get(Value);
-
- // Make sure to call the destructor for the reference temporary.
- const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
- if (VD && VD->hasGlobalStorage()) {
- if (ReferenceTemporaryDtor) {
- llvm::Constant *CleanupFn;
- llvm::Constant *CleanupArg;
- if (E->getType()->isArrayType()) {
- CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
- cast<llvm::Constant>(ReferenceTemporary), E->getType(),
- destroyCXXObject, getLangOpts().Exceptions);
- CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
- } else {
- CleanupFn =
- CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
- CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
- }
- CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg);
- } else if (ReferenceInitializerList) {
- // FIXME: This is wrong. We need to register a global destructor to clean
- // up the initializer_list object, rather than adding it as a local
- // cleanup.
- EmitStdInitializerListCleanup(ReferenceTemporary,
- ReferenceInitializerList);
- } else {
- assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind());
- // Note: We intentionally do not register a global "destructor" to
- // release the object.
- }
-
- return RValue::get(Value);
- }
- if (ReferenceTemporaryDtor) {
- if (E->getType()->isArrayType())
- pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
- destroyCXXObject, getLangOpts().Exceptions);
- else
- PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
- } else if (ReferenceInitializerList) {
- EmitStdInitializerListCleanup(ReferenceTemporary,
- ReferenceInitializerList);
- } else {
- switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- llvm_unreachable(
- "Not a reference temporary that needs to be deallocated");
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- // Nothing to do.
- break;
-
- case Qualifiers::OCL_Strong: {
- bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
- CleanupKind cleanupKind = getARCCleanupKind();
- pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
- precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
- cleanupKind & EHCleanup);
- break;
- }
-
- case Qualifiers::OCL_Weak: {
- // __weak objects always get EH cleanups; otherwise, exceptions
- // could cause really nasty crashes instead of mere leaks.
- pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
- ObjCARCReferenceLifetimeType, destroyARCWeak, true);
- break;
- }
- }
- }
-
return RValue::get(Value);
}
@@ -553,7 +476,9 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// The glvalue must refer to a large enough storage region.
// FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation
// to check this.
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy);
+ // FIXME: Get object address space
+ llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy };
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
llvm::Value *Min = Builder.getFalse();
llvm::Value *CastAddr = Builder.CreateBitCast(Address, Int8PtrTy);
llvm::Value *LargeEnough =
@@ -716,7 +641,8 @@ static llvm::Value *getArrayIndexingBound(
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
llvm::Value *Index, QualType IndexType,
bool Accessed) {
- assert(SanOpts->Bounds && "should not be called unless adding bounds checks");
+ assert(SanOpts->ArrayBounds &&
+ "should not be called unless adding bounds checks");
QualType IndexedType;
llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
@@ -741,13 +667,13 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
CodeGenFunction::ComplexPairTy CodeGenFunction::
EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
- ComplexPairTy InVal = EmitLoadOfComplex(LV);
-
+ ComplexPairTy InVal = EmitLoadOfComplex(LV, E->getExprLoc());
+
llvm::Value *NextVal;
if (isa<llvm::IntegerType>(InVal.first->getType())) {
uint64_t AmountVal = isInc ? 1 : -1;
NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
-
+
// Add the inc/dec to the real part.
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
} else {
@@ -756,16 +682,16 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
if (!isInc)
FVal.changeSign();
NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal);
-
+
// Add the inc/dec to the real part.
NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
}
-
+
ComplexPairTy IncVal(NextVal, InVal.second);
-
+
// Store the updated result through the lvalue.
EmitStoreOfComplex(IncVal, LV, /*init*/ false);
-
+
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
return isPre ? IncVal : InVal;
@@ -787,7 +713,7 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
}
-
+
// If this is a use of an undefined aggregate type, the aggregate must have an
// identifiable address. Just because the contents of the value are undefined
// doesn't mean that the address can't be taken and compared.
@@ -817,7 +743,7 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV;
- if (SanOpts->Bounds && isa<ArraySubscriptExpr>(E))
+ if (SanOpts->ArrayBounds && isa<ArraySubscriptExpr>(E))
LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
else
LV = EmitLValue(E);
@@ -899,8 +825,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitLValue(cleanups->getSubExpr());
}
- case Expr::CXXScalarValueInitExprClass:
- return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E));
case Expr::CXXDefaultArgExprClass:
return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr());
case Expr::CXXDefaultInitExprClass: {
@@ -931,7 +855,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::BinaryConditionalOperatorClass:
return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
case Expr::ChooseExprClass:
- return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
+ return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
case Expr::OpaqueValueExprClass:
return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
case Expr::SubstNonTypeTemplateParmExprClass:
@@ -1047,7 +971,7 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
llvm::Constant *C = CGM.EmitConstantValue(result.Val, resultType, this);
// Make sure we emit a debug reference to the global variable.
- // This should probably fire even for
+ // This should probably fire even for
if (isa<VarDecl>(value)) {
if (!getContext().DeclMustBeEmitted(cast<VarDecl>(value)))
EmitDeclRefExprDbgValue(refExpr, C);
@@ -1063,10 +987,11 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
return ConstantEmission::forValue(C);
}
-llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
+llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
+ SourceLocation Loc) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(),
- lvalue.getType(), lvalue.getTBAAInfo(),
+ lvalue.getType(), Loc, lvalue.getTBAAInfo(),
lvalue.getTBAABaseType(), lvalue.getTBAAOffset());
}
@@ -1128,21 +1053,22 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
}
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
- unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo,
- QualType TBAABaseType,
- uint64_t TBAAOffset) {
+ unsigned Alignment, QualType Ty,
+ SourceLocation Loc,
+ llvm::MDNode *TBAAInfo,
+ QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// For better performance, handle vector loads differently.
if (Ty->isVectorType()) {
llvm::Value *V;
const llvm::Type *EltTy =
cast<llvm::PointerType>(Addr->getType())->getElementType();
-
+
const llvm::VectorType *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);
@@ -1175,9 +1101,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
LValue lvalue = LValue::MakeAddr(Addr, Ty,
CharUnits::fromQuantity(Alignment),
getContext(), TBAAInfo);
- return EmitAtomicLoad(lvalue).getScalarVal();
+ return EmitAtomicLoad(lvalue, Loc).getScalarVal();
}
-
+
llvm::LoadInst *Load = Builder.CreateLoad(Addr);
if (Volatile)
Load->setVolatile(true);
@@ -1186,7 +1112,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
if (TBAAInfo) {
llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
TBAAOffset);
- CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/);
+ if (TBAAPath)
+ CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/);
}
if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
@@ -1205,9 +1132,12 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
Load, llvm::ConstantInt::get(getLLVMContext(), Min));
Check = Builder.CreateAnd(Upper, Lower);
}
- // FIXME: Provide a SourceLocation.
- EmitCheck(Check, "load_invalid_value", EmitCheckTypeDescriptor(Ty),
- EmitCheckValue(Load), CRK_Recoverable);
+ llvm::Constant *StaticArgs[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty)
+ };
+ EmitCheck(Check, "load_invalid_value", StaticArgs, EmitCheckValue(Load),
+ CRK_Recoverable);
}
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
@@ -1243,11 +1173,10 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment,
- QualType Ty,
- llvm::MDNode *TBAAInfo,
+ QualType Ty, llvm::MDNode *TBAAInfo,
bool isInit, QualType TBAABaseType,
uint64_t TBAAOffset) {
-
+
// Handle vectors differently to get better performance.
if (Ty->isVectorType()) {
llvm::Type *SrcTy = Value->getType();
@@ -1255,20 +1184,17 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
// Handle vec3 special.
if (VecTy->getNumElements() == 3) {
llvm::LLVMContext &VMContext = getLLVMContext();
-
+
// Our source is a vec3, do a shuffle vector to make it a vec4.
SmallVector<llvm::Constant*, 4> Mask;
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext),
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext),
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
1));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext),
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
2));
Mask.push_back(llvm::UndefValue::get(llvm::Type::getInt32Ty(VMContext)));
-
+
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Value = Builder.CreateShuffleVector(Value,
llvm::UndefValue::get(VecTy),
@@ -1282,7 +1208,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
}
}
-
+
Value = EmitToMemory(Value, Ty);
if (Ty->isAtomicType()) {
@@ -1300,7 +1226,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
if (TBAAInfo) {
llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
TBAAOffset);
- CGM.DecorateInstruction(Store, TBAAPath, false/*ConvertTypeToTag*/);
+ if (TBAAPath)
+ CGM.DecorateInstruction(Store, TBAAPath, false/*ConvertTypeToTag*/);
}
}
@@ -1315,7 +1242,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
/// method emits the address of the lvalue, then loads the result as an rvalue,
/// returning the rvalue.
-RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
+RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
if (LV.isObjCWeak()) {
// load of a __weak object.
llvm::Value *AddrWeakObj = LV.getAddress();
@@ -1332,7 +1259,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
assert(!LV.getType()->isFunctionType());
// Everything needs a load.
- return RValue::get(EmitLoadOfScalar(LV));
+ return RValue::get(EmitLoadOfScalar(LV, Loc));
}
if (LV.isVectorElt()) {
@@ -1420,7 +1347,8 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
-void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit) {
+void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
+ bool isInit) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element.
@@ -1489,7 +1417,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit
llvm::Value *RHS = EmitScalarExpr(Dst.getBaseIvarExp());
llvm::Value *dst = RHS;
RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
- llvm::Value *LHS =
+ llvm::Value *LHS =
Builder.CreatePtrToInt(LvalueDst, ResultType, "sub.ptr.lhs.cast");
llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset");
CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst,
@@ -1625,6 +1553,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
for (unsigned i = 0; i != NumDstElts; ++i)
Mask.push_back(Builder.getInt32(i));
+ // When the vector size is odd and .odd or .hi is used, the last element
+ // of the Elts constant array will be one past the size of the vector.
+ // Ignore the last element here, if it is greater than the mask size.
+ if (getAccessedFieldNo(NumSrcElts - 1, Elts) == Mask.size())
+ NumSrcElts--;
+
// modify when what gets shuffled in
for (unsigned i = 0; i != NumSrcElts; ++i)
Mask[getAccessedFieldNo(i, Elts)] = Builder.getInt32(i+NumDstElts);
@@ -1654,12 +1588,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
bool IsMemberAccess=false) {
if (Ctx.getLangOpts().getGC() == LangOptions::NonGC)
return;
-
+
if (isa<ObjCIvarRefExpr>(E)) {
QualType ExpTy = E->getType();
if (IsMemberAccess && ExpTy->isPointerType()) {
// If ivar is a structure pointer, assigning to field of
- // this struct follows gcc's behavior and makes it a non-ivar
+ // this struct follows gcc's behavior and makes it a non-ivar
// writer-barrier conservatively.
ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
if (ExpTy->isRecordType()) {
@@ -1673,7 +1607,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
LV.setObjCArray(E->getType()->isArrayType());
return;
}
-
+
if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
if (VD->hasGlobalStorage()) {
@@ -1684,12 +1618,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
LV.setObjCArray(E->getType()->isArrayType());
return;
}
-
+
if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
-
+
if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
if (LV.isObjCIvar()) {
@@ -1699,7 +1633,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
if (ExpTy->isPointerType())
ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
if (ExpTy->isRecordType())
- LV.setObjCIvar(false);
+ LV.setObjCIvar(false);
}
return;
}
@@ -1713,7 +1647,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
-
+
if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
@@ -1726,12 +1660,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
- if (LV.isObjCIvar() && !LV.isObjCArray())
- // Using array syntax to assigning to what an ivar points to is not
+ if (LV.isObjCIvar() && !LV.isObjCArray())
+ // Using array syntax to assigning to what an ivar points to is not
// same as assigning to the ivar itself. {id *Names;} Names[i] = 0;
- LV.setObjCIvar(false);
+ LV.setObjCIvar(false);
else if (LV.isGlobalObjCRef() && !LV.isObjCArray())
- // Using array syntax to assigning to what global points to is not
+ // Using array syntax to assigning to what global points to is not
// same as assigning to the global itself. {id *G;} G[i] = 0;
LV.setGlobalObjCRef(false);
return;
@@ -1793,6 +1727,13 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
return CGF.MakeAddrLValue(V, E->getType(), Alignment);
}
+static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
+ llvm::Value *ThisValue) {
+ QualType TagType = CGF.getContext().getTagDeclType(FD->getParent());
+ LValue LV = CGF.MakeNaturalAlignAddrLValue(ThisValue, TagType);
+ return CGF.EmitLValueForField(LV, FD);
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
CharUnits Alignment = getContext().getDeclAlign(ND);
@@ -1838,16 +1779,17 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
bool isBlockVariable = VD->hasAttr<BlocksAttr>();
llvm::Value *V = LocalDeclMap.lookup(VD);
- if (!V && VD->isStaticLocal())
+ if (!V && VD->isStaticLocal())
V = CGM.getStaticLocalDeclAddress(VD);
// Use special handling for lambdas.
if (!V) {
if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) {
- QualType LambdaTagType = getContext().getTagDeclType(FD->getParent());
- LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
- LambdaTagType);
- return EmitLValueForField(LambdaLV, FD);
+ return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+ } else if (CapturedStmtInfo) {
+ if (const FieldDecl *FD = CapturedStmtInfo->lookup(VD))
+ return EmitCapturedFieldLValue(*this, FD,
+ CapturedStmtInfo->getContextValue());
}
assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
@@ -1888,8 +1830,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LV;
}
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND))
- return EmitFunctionDeclLValue(*this, E, fn);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return EmitFunctionDeclLValue(*this, E, FD);
llvm_unreachable("Unhandled DeclRefExpr");
}
@@ -1945,7 +1887,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
case UO_PreDec: {
LValue LV = EmitLValue(E->getSubExpr());
bool isInc = E->getOpcode() == UO_PreInc;
-
+
if (E->getType()->isAnyComplexType())
EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/);
else
@@ -2008,8 +1950,9 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Func:
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
+ case PredefinedExpr::FuncDName:
case PredefinedExpr::PrettyFunction: {
- unsigned IdentType = E->getIdentType();
+ PredefinedExpr::IdentType IdentType = E->getIdentType();
std::string GlobalVarName;
switch (IdentType) {
@@ -2020,6 +1963,9 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Function:
GlobalVarName = "__FUNCTION__.";
break;
+ case PredefinedExpr::FuncDName:
+ GlobalVarName = "__FUNCDNAME__.";
+ break;
case PredefinedExpr::LFunction:
GlobalVarName = "L__FUNCTION__.";
break;
@@ -2033,17 +1979,28 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
FnName = FnName.substr(1);
GlobalVarName += FnName;
+ // If this is outside of a function use the top level decl.
const Decl *CurDecl = CurCodeDecl;
- if (CurDecl == 0)
+ if (CurDecl == 0 || isa<VarDecl>(CurDecl))
CurDecl = getContext().getTranslationUnitDecl();
- std::string FunctionName =
- (isa<BlockDecl>(CurDecl)
- ? FnName.str()
- : PredefinedExpr::ComputeName((PredefinedExpr::IdentType)IdentType,
- CurDecl));
+ const Type *ElemType = E->getType()->getArrayElementTypeNoTypeQual();
+ std::string FunctionName;
+ if (isa<BlockDecl>(CurDecl)) {
+ // Blocks use the mangled function name.
+ // FIXME: ComputeName should handle blocks.
+ FunctionName = FnName.str();
+ } else if (isa<CapturedDecl>(CurDecl)) {
+ // For a captured statement, the function name is its enclosing
+ // function name not the one compiler generated.
+ FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
+ } else {
+ FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
+ assert(cast<ConstantArrayType>(E->getType())->getSize() - 1 ==
+ FunctionName.size() &&
+ "Computed __func__ length differs from type!");
+ }
- const Type* ElemType = E->getType()->getArrayElementTypeNoTypeQual();
llvm::Constant *C;
if (ElemType->isWideCharType()) {
SmallString<32> RawChars;
@@ -2076,7 +2033,10 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
/// followed by an array of i8 containing the type name. TypeKind is 0 for an
/// integer, 1 for a floating point value, and -1 for anything else.
llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
- // FIXME: Only emit each type's descriptor once.
+ // Only emit each type's descriptor once.
+ if (llvm::Constant *C = CGM.getTypeDescriptor(T))
+ return C;
+
uint16_t TypeKind = -1;
uint16_t TypeInfo = 0;
@@ -2109,6 +2069,10 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
llvm::GlobalVariable::PrivateLinkage,
Descriptor);
GV->setUnnamedAddr(true);
+
+ // Remember the descriptor for this type.
+ CGM.setTypeDescriptor(T, GV);
+
return GV;
}
@@ -2151,12 +2115,10 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
llvm::Constant *Data[] = {
- // FIXME: Only emit each file name once.
- PLoc.isValid() ? cast<llvm::Constant>(
- Builder.CreateGlobalStringPtr(PLoc.getFilename()))
+ PLoc.isValid() ? CGM.GetAddrOfConstantCString(PLoc.getFilename(), ".src")
: llvm::Constant::getNullValue(Int8PtrTy),
- Builder.getInt32(PLoc.getLine()),
- Builder.getInt32(PLoc.getColumn())
+ Builder.getInt32(PLoc.isValid() ? PLoc.getLine() : 0),
+ Builder.getInt32(PLoc.isValid() ? PLoc.getColumn() : 0)
};
return llvm::ConstantStruct::getAnon(Data);
@@ -2271,12 +2233,12 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
const CastExpr *CE = dyn_cast<CastExpr>(E);
if (CE == 0 || CE->getCastKind() != CK_ArrayToPointerDecay)
return 0;
-
+
// If this is a decay from variable width array, bail out.
const Expr *SubExpr = CE->getSubExpr();
if (SubExpr->getType()->isVariableArrayType())
return 0;
-
+
return SubExpr;
}
@@ -2287,7 +2249,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
- if (SanOpts->Bounds)
+ if (SanOpts->ArrayBounds)
EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
// If the base is a vector type, then we are forming a vector element lvalue
@@ -2360,7 +2322,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
llvm::Value *ArrayPtr = ArrayLV.getAddress();
llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *Args[] = { Zero, Idx };
-
+
// Propagate the alignment from the array itself to the result.
ArrayAlignment = ArrayLV.getAlignment();
@@ -2381,7 +2343,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
assert(!T.isNull() &&
"CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
-
+
// Limit the alignment to that of the result type.
LValue LV;
if (!ArrayAlignment.isZero()) {
@@ -2404,7 +2366,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
static
llvm::Constant *GenerateConstantVector(CGBuilderTy &Builder,
- SmallVector<unsigned, 4> &Elts) {
+ SmallVectorImpl<unsigned> &Elts) {
SmallVector<llvm::Constant*, 4> CElts;
for (unsigned i = 0, e = Elts.size(); i != e; ++i)
CElts.push_back(Builder.getInt32(Elts[i]));
@@ -2435,7 +2397,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
assert(E->getBase()->getType()->isVectorType() &&
"Result must be a vector");
llvm::Value *Vec = EmitScalarExpr(E->getBase());
-
+
// Store the vector to memory (because LValue wants an address).
llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMem);
@@ -2444,7 +2406,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
QualType type =
E->getType().withCVRQualifiers(Base.getQuals().getCVRQualifiers());
-
+
// Encode the element access list into a vector of unsigned indices.
SmallVector<unsigned, 4> Indices;
E->getEncodedElementAccess(Indices);
@@ -2485,7 +2447,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
-
+
if (VarDecl *VD = dyn_cast<VarDecl>(ND))
return EmitGlobalVarDeclLValue(*this, E, VD);
@@ -2567,7 +2529,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
tbaa = CGM.getTBAAInfo(getContext().CharTy);
else
tbaa = CGM.getTBAAInfo(type);
- CGM.DecorateInstruction(load, tbaa);
+ if (tbaa)
+ CGM.DecorateInstruction(load, tbaa);
}
addr = load;
@@ -2580,7 +2543,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
cvr = 0; // qualifiers don't recursively apply to referencee
}
}
-
+
// Make sure that the address is pointing to the right type. This is critical
// 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
@@ -2618,11 +2581,11 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
return LV;
}
-LValue
-CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
+LValue
+CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
const FieldDecl *Field) {
QualType FieldType = Field->getType();
-
+
if (!FieldType->isReferenceType())
return EmitLValueForField(Base, Field);
@@ -2657,7 +2620,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
if (E->getType()->isVariablyModifiedType())
// make sure to emit the VLA size.
EmitVariablyModifiedType(E->getType());
-
+
llvm::Value *DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral");
const Expr *InitExpr = E->getInitializer();
LValue Result = MakeAddrLValue(DeclPtr, E->getType());
@@ -2705,19 +2668,19 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
ConditionalEvaluation eval(*this);
EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock);
-
+
// Any temporaries created here are conditional.
EmitBlock(lhsBlock);
eval.begin(*this);
LValue lhs = EmitLValue(expr->getTrueExpr());
eval.end(*this);
-
+
if (!lhs.isSimple())
return EmitUnsupportedLValue(expr, "conditional operator");
lhsBlock = Builder.GetInsertBlock();
Builder.CreateBr(contBlock);
-
+
// Any temporaries created here are conditional.
EmitBlock(rhsBlock);
eval.begin(*this);
@@ -2746,26 +2709,6 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
switch (E->getCastKind()) {
case CK_ToVoid:
- return EmitUnsupportedLValue(E, "unexpected cast lvalue");
-
- case CK_Dependent:
- llvm_unreachable("dependent cast kind in IR gen!");
-
- case CK_BuiltinFnToFnPtr:
- llvm_unreachable("builtin functions are handled elsewhere");
-
- // These two casts are currently treated as no-ops, although they could
- // potentially be real operations depending on the target's ABI.
- case CK_NonAtomicToAtomic:
- case CK_AtomicToNonAtomic:
-
- case CK_NoOp:
- case CK_LValueToRValue:
- if (!E->getSubExpr()->Classify(getContext()).isPRValue()
- || E->getType()->isRecordType())
- return EmitLValue(E->getSubExpr());
- // Fall through to synthesize a temporary.
-
case CK_BitCast:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
@@ -2799,16 +2742,20 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_CopyAndAutoreleaseBlockObject: {
- // These casts only produce lvalues when we're binding a reference to a
- // temporary realized from a (converted) pure rvalue. Emit the expression
- // as a value, copy it into a temporary, and return an lvalue referring to
- // that temporary.
- llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp");
- EmitAnyExprToMem(E, V, E->getType().getQualifiers(), false);
- return MakeAddrLValue(V, E->getType());
- }
+ case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
+ return EmitUnsupportedLValue(E, "unexpected cast lvalue");
+
+ case CK_Dependent:
+ llvm_unreachable("dependent cast kind in IR gen!");
+
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
+ // These are never l-values; just use the aggregate emission code.
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic:
+ return EmitAggExprToLValue(E);
case CK_Dynamic: {
LValue LV = EmitLValue(E->getSubExpr());
@@ -2821,53 +2768,55 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_UserDefinedConversion:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
+ case CK_NoOp:
+ case CK_LValueToRValue:
return EmitLValue(E->getSubExpr());
-
+
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- const RecordType *DerivedClassTy =
+ const RecordType *DerivedClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
+ CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
+
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *This = LV.getAddress();
-
+
// Perform the derived-to-base conversion
- llvm::Value *Base =
- GetAddressOfBaseClass(This, DerivedClassDecl,
+ llvm::Value *Base =
+ GetAddressOfBaseClass(This, DerivedClassDecl,
E->path_begin(), E->path_end(),
/*NullCheckValue=*/false);
-
+
return MakeAddrLValue(Base, E->getType());
}
case CK_ToUnion:
return EmitAggExprToLValue(E);
case CK_BaseToDerived: {
const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
+ CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
+
LValue LV = EmitLValue(E->getSubExpr());
+ // Perform the base-to-derived conversion
+ llvm::Value *Derived =
+ GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
+ E->path_begin(), E->path_end(),
+ /*NullCheckValue=*/false);
+
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
if (SanitizePerformTypeCheck)
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
- LV.getAddress(), E->getType());
+ Derived, E->getType());
- // Perform the base-to-derived conversion
- llvm::Value *Derived =
- GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
- E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false);
-
return MakeAddrLValue(Derived, E->getType());
}
case CK_LValueBitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E);
-
+
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
ConvertType(CE->getTypeAsWritten()));
@@ -2876,23 +2825,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ObjCObjectLValueCast: {
LValue LV = EmitLValue(E->getSubExpr());
QualType ToType = getContext().getLValueReferenceType(E->getType());
- llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
+ llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
ConvertType(ToType));
return MakeAddrLValue(V, E->getType());
}
case CK_ZeroToOCLEvent:
llvm_unreachable("NULL to OpenCL event lvalue cast is not valid");
}
-
- llvm_unreachable("Unhandled lvalue cast kind?");
-}
-LValue CodeGenFunction::EmitNullInitializationLValue(
- const CXXScalarValueInitExpr *E) {
- QualType Ty = E->getType();
- LValue LV = MakeAddrLValue(CreateMemTemp(Ty), Ty);
- EmitNullInitialization(LV.getAddress(), Ty);
- return LV;
+ llvm_unreachable("Unhandled lvalue cast kind?");
}
LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
@@ -2900,23 +2841,18 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
return getOpaqueLValueMapping(e);
}
-LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
- const MaterializeTemporaryExpr *E) {
- RValue RV = EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
- return MakeAddrLValue(RV.getScalarVal(), E->getType());
-}
-
RValue CodeGenFunction::EmitRValueForField(LValue LV,
- const FieldDecl *FD) {
+ const FieldDecl *FD,
+ SourceLocation Loc) {
QualType FT = FD->getType();
LValue FieldLV = EmitLValueForField(LV, FD);
switch (getEvaluationKind(FT)) {
case TEK_Complex:
- return RValue::getComplex(EmitLoadOfComplex(FieldLV));
+ return RValue::getComplex(EmitLoadOfComplex(FieldLV, Loc));
case TEK_Aggregate:
return FieldLV.asAggregateRValue();
case TEK_Scalar:
- return EmitLoadOfLValue(FieldLV);
+ return EmitLoadOfLValue(FieldLV, Loc);
}
llvm_unreachable("bad evaluation kind");
}
@@ -2925,7 +2861,7 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
// Expression Emission
//===--------------------------------------------------------------------===//
-RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
+RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
if (CGDebugInfo *DI = getDebugInfo()) {
SourceLocation Loc = E->getLocStart();
@@ -2956,7 +2892,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
- if (const CXXPseudoDestructorExpr *PseudoDtor
+ if (const CXXPseudoDestructorExpr *PseudoDtor
= dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
if (getLangOpts().ObjCAutoRefCount &&
@@ -2969,7 +2905,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
Expr *BaseExpr = PseudoDtor->getBase();
llvm::Value *BaseValue = NULL;
Qualifiers BaseQuals;
-
+
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
if (PseudoDtor->isArrow()) {
BaseValue = EmitScalarExpr(BaseExpr);
@@ -2981,15 +2917,15 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
QualType BaseTy = BaseExpr->getType();
BaseQuals = BaseTy.getQualifiers();
}
-
+
switch (PseudoDtor->getDestroyedType().getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
-
+
case Qualifiers::OCL_Strong:
- EmitARCRelease(Builder.CreateLoad(BaseValue,
+ EmitARCRelease(Builder.CreateLoad(BaseValue,
PseudoDtor->getDestroyedType().isVolatileQualified()),
ARCPreciseLifetime);
break;
@@ -3003,16 +2939,16 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
// The result shall only be used as the operand for the function call
// operator (), and the result of such a call has type void. The only
// effect is the evaluation of the postfix-expression before the dot or
- // arrow.
+ // arrow.
EmitScalarExpr(E->getCallee());
}
-
+
return RValue::get(0);
}
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
- return EmitCall(E->getCallee()->getType(), Callee, ReturnValue,
- E->arg_begin(), E->arg_end(), TargetDecl);
+ return EmitCall(E->getCallee()->getType(), Callee, E->getLocStart(),
+ ReturnValue, E->arg_begin(), E->arg_end(), TargetDecl);
}
LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
@@ -3068,7 +3004,7 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddr(), E->getType());
-
+
assert(E->getCallReturnType()->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
"reference type!");
@@ -3095,7 +3031,8 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
}
llvm::Value *CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return CGM.GetAddrOfUuidDescriptor(E);
+ return Builder.CreateBitCast(CGM.GetAddrOfUuidDescriptor(E),
+ ConvertType(E->getType())->getPointerTo());
}
LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {
@@ -3120,19 +3057,19 @@ CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) {
LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
RValue RV = EmitObjCMessageExpr(E);
-
+
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddr(), E->getType());
-
+
assert(E->getMethodDecl()->getResultType()->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
"reference type!");
-
+
return MakeAddrLValue(RV.getScalarVal(), E->getType());
}
LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
- llvm::Value *V =
+ llvm::Value *V =
CGM.getObjCRuntime().GetSelector(*this, E->getSelector(), true);
return MakeAddrLValue(V, E->getType());
}
@@ -3168,7 +3105,7 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
BaseQuals = ObjectTy.getQualifiers();
}
- LValue LV =
+ LValue LV =
EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(),
BaseQuals.getCVRQualifiers());
setObjCGCLValueClass(getContext(), E, LV);
@@ -3182,6 +3119,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
}
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
+ SourceLocation CallLoc,
ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
@@ -3196,8 +3134,60 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
const FunctionType *FnType
= cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
+ // Force column info to differentiate multiple inlined call sites on
+ // the same line, analoguous to EmitCallExpr.
+ bool ForceColumnInfo = false;
+ if (const FunctionDecl* FD = dyn_cast_or_null<const FunctionDecl>(TargetDecl))
+ ForceColumnInfo = FD->isInlineSpecified();
+
+ if (getLangOpts().CPlusPlus && SanOpts->Function &&
+ (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
+ if (llvm::Constant *PrefixSig =
+ CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
+ llvm::Constant *FTRTTIConst =
+ CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true);
+ llvm::Type *PrefixStructTyElems[] = {
+ PrefixSig->getType(),
+ FTRTTIConst->getType()
+ };
+ llvm::StructType *PrefixStructTy = llvm::StructType::get(
+ CGM.getLLVMContext(), PrefixStructTyElems, /*isPacked=*/true);
+
+ llvm::Value *CalleePrefixStruct = Builder.CreateBitCast(
+ Callee, llvm::PointerType::getUnqual(PrefixStructTy));
+ llvm::Value *CalleeSigPtr =
+ Builder.CreateConstGEP2_32(CalleePrefixStruct, 0, 0);
+ llvm::Value *CalleeSig = Builder.CreateLoad(CalleeSigPtr);
+ llvm::Value *CalleeSigMatch = Builder.CreateICmpEQ(CalleeSig, PrefixSig);
+
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+ llvm::BasicBlock *TypeCheck = createBasicBlock("typecheck");
+ Builder.CreateCondBr(CalleeSigMatch, TypeCheck, Cont);
+
+ EmitBlock(TypeCheck);
+ llvm::Value *CalleeRTTIPtr =
+ Builder.CreateConstGEP2_32(CalleePrefixStruct, 0, 1);
+ llvm::Value *CalleeRTTI = Builder.CreateLoad(CalleeRTTIPtr);
+ llvm::Value *CalleeRTTIMatch =
+ Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst);
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(CallLoc),
+ EmitCheckTypeDescriptor(CalleeType)
+ };
+ EmitCheck(CalleeRTTIMatch,
+ "function_type_mismatch",
+ StaticData,
+ Callee,
+ CRK_Recoverable);
+
+ Builder.CreateBr(Cont);
+ EmitBlock(Cont);
+ }
+ }
+
CallArgList Args;
- EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
+ EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd,
+ ForceColumnInfo);
const CGFunctionInfo &FnInfo =
CGM.getTypes().arrangeFreeFunctionCall(Args, FnType);
@@ -3250,15 +3240,16 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
/// Given the address of a temporary variable, produce an r-value of
/// its type.
RValue CodeGenFunction::convertTempToRValue(llvm::Value *addr,
- QualType type) {
+ QualType type,
+ SourceLocation loc) {
LValue lvalue = MakeNaturalAlignAddrLValue(addr, type);
switch (getEvaluationKind(type)) {
case TEK_Complex:
- return RValue::getComplex(EmitLoadOfComplex(lvalue));
+ return RValue::getComplex(EmitLoadOfComplex(lvalue, loc));
case TEK_Aggregate:
return lvalue.asAggregateRValue();
case TEK_Scalar:
- return RValue::get(EmitLoadOfScalar(lvalue));
+ return RValue::get(EmitLoadOfScalar(lvalue, loc));
}
llvm_unreachable("bad evaluation kind");
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index b974e1dcc682..9d0f3a9661a6 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -29,14 +29,6 @@ using namespace CodeGen;
// Aggregate Expression Emitter
//===----------------------------------------------------------------------===//
-llvm::Value *AggValueSlot::getPaddedAtomicAddr() const {
- assert(isValueOfAtomic());
- llvm::GEPOperator *op = cast<llvm::GEPOperator>(getAddr());
- assert(op->getNumIndices() == 2);
- assert(op->hasAllZeroIndices());
- return op->getPointerOperand();
-}
-
namespace {
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
@@ -91,7 +83,6 @@ public:
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
- void EmitStdInitializerList(llvm::Value *DestPtr, InitListExpr *InitList);
void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
QualType elementType, InitListExpr *E);
@@ -177,6 +168,7 @@ public:
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
+ void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E);
void VisitExprWithCleanups(ExprWithCleanups *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
@@ -202,38 +194,6 @@ public:
CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
}
};
-
-/// A helper class for emitting expressions into the value sub-object
-/// of a padded atomic type.
-class ValueDestForAtomic {
- AggValueSlot Dest;
-public:
- ValueDestForAtomic(CodeGenFunction &CGF, AggValueSlot dest, QualType type)
- : Dest(dest) {
- assert(!Dest.isValueOfAtomic());
- if (!Dest.isIgnored() && CGF.CGM.isPaddedAtomicType(type)) {
- llvm::Value *valueAddr = CGF.Builder.CreateStructGEP(Dest.getAddr(), 0);
- Dest = AggValueSlot::forAddr(valueAddr,
- Dest.getAlignment(),
- Dest.getQualifiers(),
- Dest.isExternallyDestructed(),
- Dest.requiresGCollection(),
- Dest.isPotentiallyAliased(),
- Dest.isZeroed(),
- AggValueSlot::IsValueOfAtomic);
- }
- }
-
- const AggValueSlot &getDest() const { return Dest; }
-
- ~ValueDestForAtomic() {
- // Kill the GEP if we made one and it didn't end up used.
- if (Dest.isValueOfAtomic()) {
- llvm::Instruction *addr = cast<llvm::GetElementPtrInst>(Dest.getAddr());
- if (addr->use_empty()) addr->eraseFromParent();
- }
- }
-};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -248,8 +208,7 @@ void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
// If the type of the l-value is atomic, then do an atomic load.
if (LV.getType()->isAtomicType()) {
- ValueDestForAtomic valueDest(CGF, Dest, LV.getType());
- CGF.EmitAtomicLoad(LV, valueDest.getDest());
+ CGF.EmitAtomicLoad(LV, E->getExprLoc(), Dest);
return;
}
@@ -345,89 +304,70 @@ void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
std::min(dest.getAlignment(), src.getAlignment()));
}
-static QualType GetStdInitializerListElementType(QualType T) {
- // Just assume that this is really std::initializer_list.
- ClassTemplateSpecializationDecl *specialization =
- cast<ClassTemplateSpecializationDecl>(T->castAs<RecordType>()->getDecl());
- return specialization->getTemplateArgs()[0].getAsType();
-}
-
-/// \brief Prepare cleanup for the temporary array.
-static void EmitStdInitializerListCleanup(CodeGenFunction &CGF,
- QualType arrayType,
- llvm::Value *addr,
- const InitListExpr *initList) {
- QualType::DestructionKind dtorKind = arrayType.isDestructedType();
- if (!dtorKind)
- return; // Type doesn't need destroying.
- if (dtorKind != QualType::DK_cxx_destructor) {
- CGF.ErrorUnsupported(initList, "ObjC ARC type in initializer_list");
- return;
- }
-
- CodeGenFunction::Destroyer *destroyer = CGF.getDestroyer(dtorKind);
- CGF.pushDestroy(NormalAndEHCleanup, addr, arrayType, destroyer,
- /*EHCleanup=*/true);
-}
-
/// \brief Emit the initializer for a std::initializer_list initialized with a
/// real initializer list.
-void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr,
- InitListExpr *initList) {
- // We emit an array containing the elements, then have the init list point
- // at the array.
- ASTContext &ctx = CGF.getContext();
- unsigned numInits = initList->getNumInits();
- QualType element = GetStdInitializerListElementType(initList->getType());
- llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType array = ctx.getConstantArrayType(element, size, ArrayType::Normal,0);
- llvm::Type *LTy = CGF.ConvertTypeForMem(array);
- llvm::AllocaInst *alloc = CGF.CreateTempAlloca(LTy);
- alloc->setAlignment(ctx.getTypeAlignInChars(array).getQuantity());
- alloc->setName(".initlist.");
-
- EmitArrayInit(alloc, cast<llvm::ArrayType>(LTy), element, initList);
-
- // FIXME: The diagnostics are somewhat out of place here.
- RecordDecl *record = initList->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator field = record->field_begin();
- if (field == record->field_end()) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+void
+AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ // Emit an array containing the elements. The array is externally destructed
+ // if the std::initializer_list object is.
+ ASTContext &Ctx = CGF.getContext();
+ LValue Array = CGF.EmitLValue(E->getSubExpr());
+ assert(Array.isSimple() && "initializer_list array not a simple lvalue");
+ llvm::Value *ArrayPtr = Array.getAddress();
+
+ const ConstantArrayType *ArrayType =
+ Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+ assert(ArrayType && "std::initializer_list constructed from non-array");
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end()) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- QualType elementPtr = ctx.getPointerType(element.withConst());
-
// Start pointer.
- if (!ctx.hasSameType(field->getType(), elementPtr)) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ if (!Field->getType()->isPointerType() ||
+ !Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- LValue DestLV = CGF.MakeNaturalAlignAddrLValue(destPtr, initList->getType());
- LValue start = CGF.EmitLValueForFieldInitialization(DestLV, *field);
- llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart");
- CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start);
- ++field;
-
- if (field == record->field_end()) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+
+ AggValueSlot Dest = EnsureSlot(E->getType());
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
+ Dest.getAlignment());
+ LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
+ llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
+ llvm::Value *IdxStart[] = { Zero, Zero };
+ llvm::Value *ArrayStart =
+ Builder.CreateInBoundsGEP(ArrayPtr, IdxStart, "arraystart");
+ CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
+ ++Field;
+
+ if (Field == Record->field_end()) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- LValue endOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *field);
- if (ctx.hasSameType(field->getType(), elementPtr)) {
+
+ llvm::Value *Size = Builder.getInt(ArrayType->getSize());
+ LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
+ if (Field->getType()->isPointerType() &&
+ Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
// End pointer.
- llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend");
- CGF.EmitStoreThroughLValue(RValue::get(arrayEnd), endOrLength);
- } else if(ctx.hasSameType(field->getType(), ctx.getSizeType())) {
+ llvm::Value *IdxEnd[] = { Zero, Size };
+ llvm::Value *ArrayEnd =
+ Builder.CreateInBoundsGEP(ArrayPtr, IdxEnd, "arrayend");
+ CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
+ } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
// Length.
- CGF.EmitStoreThroughLValue(RValue::get(Builder.getInt(size)), endOrLength);
+ CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
} else {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
-
- if (!Dest.isExternallyDestructed())
- EmitStdInitializerListCleanup(CGF, array, alloc, initList);
}
/// \brief Emit initialization of an array from an initializer list.
@@ -490,15 +430,8 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
if (endOfInit) Builder.CreateStore(element, endOfInit);
}
- // If these are nested std::initializer_list inits, do them directly,
- // because they are conceptually the same "location".
- InitListExpr *initList = dyn_cast<InitListExpr>(E->getInit(i));
- if (initList && initList->initializesStdInitializerList()) {
- EmitStdInitializerList(element, initList);
- } else {
- LValue elementLV = CGF.MakeAddrLValue(element, elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
- }
+ LValue elementLV = CGF.MakeAddrLValue(element, elementType);
+ EmitInitializationToLValue(E->getInit(i), elementLV);
}
// Check whether there's a non-trivial array-fill expression.
@@ -679,34 +612,33 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
}
// If we're converting an r-value of non-atomic type to an r-value
- // of atomic type, just make an atomic temporary, emit into that,
- // and then copy the value out. (FIXME: do we need to
- // zero-initialize it first?)
+ // of atomic type, just emit directly into the relevant sub-object.
if (isToAtomic) {
- ValueDestForAtomic valueDest(CGF, Dest, atomicType);
- CGF.EmitAggExpr(E->getSubExpr(), valueDest.getDest());
+ AggValueSlot valueDest = Dest;
+ if (!valueDest.isIgnored() && CGF.CGM.isPaddedAtomicType(atomicType)) {
+ // Zero-initialize. (Strictly speaking, we only need to intialize
+ // the padding at the end, but this is simpler.)
+ if (!Dest.isZeroed())
+ CGF.EmitNullInitialization(Dest.getAddr(), atomicType);
+
+ // Build a GEP to refer to the subobject.
+ llvm::Value *valueAddr =
+ CGF.Builder.CreateStructGEP(valueDest.getAddr(), 0);
+ valueDest = AggValueSlot::forAddr(valueAddr,
+ valueDest.getAlignment(),
+ valueDest.getQualifiers(),
+ valueDest.isExternallyDestructed(),
+ valueDest.requiresGCollection(),
+ valueDest.isPotentiallyAliased(),
+ AggValueSlot::IsZeroed);
+ }
+
+ CGF.EmitAggExpr(E->getSubExpr(), valueDest);
return;
}
// Otherwise, we're converting an atomic type to a non-atomic type.
-
- // If the dest is a value-of-atomic subobject, drill back out.
- if (Dest.isValueOfAtomic()) {
- AggValueSlot atomicSlot =
- AggValueSlot::forAddr(Dest.getPaddedAtomicAddr(),
- Dest.getAlignment(),
- Dest.getQualifiers(),
- Dest.isExternallyDestructed(),
- Dest.requiresGCollection(),
- Dest.isPotentiallyAliased(),
- Dest.isZeroed(),
- AggValueSlot::IsNotValueOfAtomic);
- CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
- return;
- }
-
- // Otherwise, make an atomic temporary, emit into that, and then
- // copy the value out.
+ // Make an atomic temporary, emit into that, and then copy the value out.
AggValueSlot atomicSlot =
CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
@@ -988,7 +920,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
}
void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
- Visit(CE->getChosenSubExpr(CGF.getContext()));
+ Visit(CE->getChosenSubExpr());
}
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
@@ -1078,7 +1010,7 @@ static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
void
-AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
QualType type = LV.getType();
// FIXME: Ignore result?
// FIXME: Are initializers affected by volatile?
@@ -1088,7 +1020,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
} else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
return EmitNullInitializationToLValue(LV);
} else if (type->isReferenceType()) {
- RValue RV = CGF.EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
+ RValue RV = CGF.EmitReferenceBindingToExpr(E);
return CGF.EmitStoreThroughLValue(RV, LV);
}
@@ -1159,12 +1091,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
- if (E->initializesStdInitializerList()) {
- EmitStdInitializerList(Dest.getAddr(), E);
- return;
- }
-
AggValueSlot Dest = EnsureSlot(E->getType());
+
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
Dest.getAlignment());
@@ -1545,58 +1473,3 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
alignment.getQuantity(), isVolatile,
/*TBAATag=*/0, TBAAStructTag);
}
-
-void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
- const Expr *init) {
- const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(init);
- if (cleanups)
- init = cleanups->getSubExpr();
-
- if (isa<InitListExpr>(init) &&
- cast<InitListExpr>(init)->initializesStdInitializerList()) {
- // We initialized this std::initializer_list with an initializer list.
- // A backing array was created. Push a cleanup for it.
- EmitStdInitializerListCleanup(loc, cast<InitListExpr>(init));
- }
-}
-
-static void EmitRecursiveStdInitializerListCleanup(CodeGenFunction &CGF,
- llvm::Value *arrayStart,
- const InitListExpr *init) {
- // Check if there are any recursive cleanups to do, i.e. if we have
- // std::initializer_list<std::initializer_list<obj>> list = {{obj()}};
- // then we need to destroy the inner array as well.
- for (unsigned i = 0, e = init->getNumInits(); i != e; ++i) {
- const InitListExpr *subInit = dyn_cast<InitListExpr>(init->getInit(i));
- if (!subInit || !subInit->initializesStdInitializerList())
- continue;
-
- // This one needs to be destroyed. Get the address of the std::init_list.
- llvm::Value *offset = llvm::ConstantInt::get(CGF.SizeTy, i);
- llvm::Value *loc = CGF.Builder.CreateInBoundsGEP(arrayStart, offset,
- "std.initlist");
- CGF.EmitStdInitializerListCleanup(loc, subInit);
- }
-}
-
-void CodeGenFunction::EmitStdInitializerListCleanup(llvm::Value *loc,
- const InitListExpr *init) {
- ASTContext &ctx = getContext();
- QualType element = GetStdInitializerListElementType(init->getType());
- unsigned numInits = init->getNumInits();
- llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType array =ctx.getConstantArrayType(element, size, ArrayType::Normal, 0);
- QualType arrayPtr = ctx.getPointerType(array);
- llvm::Type *arrayPtrType = ConvertType(arrayPtr);
-
- // lvalue is the location of a std::initializer_list, which as its first
- // element has a pointer to the array we want to destroy.
- llvm::Value *startPointer = Builder.CreateStructGEP(loc, 0, "startPointer");
- llvm::Value *startAddress = Builder.CreateLoad(startPointer, "startAddress");
-
- ::EmitRecursiveStdInitializerListCleanup(*this, startAddress, init);
-
- llvm::Value *arrayAddress =
- Builder.CreateBitCast(startAddress, arrayPtrType, "arrayAddress");
- ::EmitStdInitializerListCleanup(*this, array, arrayAddress, init);
-}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 83c8ace98cd4..cc7b24d5e83e 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 "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
@@ -62,99 +63,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
Callee, ReturnValue, Args, MD);
}
-// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
-// quite what we want.
-static const Expr *skipNoOpCastsAndParens(const Expr *E) {
- while (true) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- E = PE->getSubExpr();
- continue;
- }
-
- if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if (CE->getCastKind() == CK_NoOp) {
- E = CE->getSubExpr();
- continue;
- }
- }
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
- if (UO->getOpcode() == UO_Extension) {
- E = UO->getSubExpr();
- continue;
- }
- }
- return E;
- }
-}
-
-/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
-/// expr can be devirtualized.
-static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
- 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 (Context.getLangOpts().AppleKext)
- return false;
-
- // If the most derived class is marked final, we know that no subclass can
- // override this member function and so we can devirtualize it. For example:
- //
- // struct A { virtual void f(); }
- // struct B final : A { };
- //
- // void f(B *b) {
- // b->f();
- // }
- //
- const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
- if (MostDerivedClassDecl->hasAttr<FinalAttr>())
- return true;
-
- // If the member function is marked 'final', we know that it can't be
- // overridden and can therefore devirtualize it.
- if (MD->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 (MD->getParent()->hasAttr<FinalAttr>())
- return true;
-
- Base = skipNoOpCastsAndParens(Base);
- 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();
-
- // We can always devirtualize calls on temporary object expressions.
- if (isa<CXXConstructExpr>(Base))
- return true;
-
- // And calls on bound temporaries.
- if (isa<CXXBindTemporaryExpr>(Base))
- return true;
-
- // Check if this is a call expr that returns a record type.
- if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
- return CE->getCallReturnType()->isRecordType();
-
- // We can't devirtualize the call.
- return false;
-}
-
static CXXRecordDecl *getCXXRecord(const Expr *E) {
QualType T = E->getType();
if (const PointerType *PTy = T->getAs<PointerType>())
@@ -175,22 +83,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
const MemberExpr *ME = cast<MemberExpr>(callee);
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- CGDebugInfo *DI = getDebugInfo();
- if (DI &&
- CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo &&
- !isa<CallExpr>(ME->getBase())) {
- QualType PQTy = ME->getBase()->IgnoreParenImpCasts()->getType();
- if (const PointerType * PTy = dyn_cast<PointerType>(PQTy)) {
- DI->getOrCreateRecordType(PTy->getPointeeType(),
- MD->getParent()->getLocation());
- }
- }
-
if (MD->isStatic()) {
// The method is static, emit it as we would a regular call.
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
return EmitCall(getContext().getPointerType(MD->getType()), Callee,
- ReturnValue, CE->arg_begin(), CE->arg_end());
+ CE->getLocStart(), ReturnValue, CE->arg_begin(),
+ CE->arg_end());
}
// Compute the object pointer.
@@ -198,8 +96,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier();
const CXXMethodDecl *DevirtualizedMethod = NULL;
- if (CanUseVirtualCall &&
- canDevirtualizeMemberFunctionCalls(getContext(), Base, MD)) {
+ if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) {
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
assert(DevirtualizedMethod);
@@ -271,7 +168,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
else
FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
- llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo);
+ llvm::FunctionType *Ty = CGM.getTypes().GetFunctionType(*FInfo);
// C++ [class.virtual]p12:
// Explicit qualification with the scope operator (5.1) suppresses the
@@ -280,34 +177,37 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// We also don't emit a virtual call if the base expression has a record type
// because then we know what the type is.
bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
-
llvm::Value *Callee;
+
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(CE->arg_begin() == CE->arg_end() &&
+ "Destructor shouldn't have explicit parameters");
+ assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
if (UseVirtualCall) {
- assert(CE->arg_begin() == CE->arg_end() &&
- "Virtual destructor shouldn't have explicit parameters");
- return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
- Dtor_Complete,
- CE->getExprLoc(),
- ReturnValue, This);
+ CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete,
+ CE->getExprLoc(), This);
} else {
if (getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
else if (!DevirtualizedMethod)
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
+ Callee = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete, FInfo, Ty);
else {
const CXXDestructorDecl *DDtor =
cast<CXXDestructorDecl>(DevirtualizedMethod);
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
}
+ EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
+ /*ImplicitParam=*/0, QualType(), 0, 0);
}
- } else if (const CXXConstructorDecl *Ctor =
- dyn_cast<CXXConstructorDecl>(MD)) {
+ return RValue::get(0);
+ }
+
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
} else if (UseVirtualCall) {
- Callee = BuildVirtualCall(MD, This, Ty);
+ Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty);
} else {
if (getLangOpts().AppleKext &&
MD->isVirtual() &&
@@ -320,6 +220,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
}
+ if (MD->isVirtual())
+ This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, MD, This);
+
return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
/*ImplicitParam=*/0, QualType(),
CE->arg_begin(), CE->arg_end());
@@ -371,8 +274,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required), Callee,
- ReturnValue, Args);
+ return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
+ Callee, ReturnValue, Args);
}
RValue
@@ -540,8 +443,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest,
assert(!getContext().getAsConstantArrayType(E->getType())
&& "EmitSynthesizedCXXCopyCtor - Copied-in Array");
- EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src,
- E->arg_begin(), E->arg_end());
+ EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, E->arg_begin(), E->arg_end());
}
static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
@@ -818,7 +720,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
QualType AllocType, llvm::Value *NewPtr) {
-
+ // FIXME: Refactor with EmitExprAsInit.
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
switch (CGF.getEvaluationKind(AllocType)) {
case TEK_Scalar:
@@ -838,8 +740,6 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
-
- CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
return;
}
}
@@ -866,10 +766,22 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
QualType::DestructionKind dtorKind = elementType.isDestructedType();
EHScopeStack::stable_iterator cleanup;
llvm::Instruction *cleanupDominator = 0;
+
// If the initializer is an initializer list, first do the explicit elements.
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
initializerElements = ILE->getNumInits();
+ // If this is a multi-dimensional array new, we will initialize multiple
+ // elements with each init list element.
+ QualType AllocType = E->getAllocatedType();
+ if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>(
+ AllocType->getAsArrayTypeUnsafe())) {
+ unsigned AS = explicitPtr->getType()->getPointerAddressSpace();
+ llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo(AS);
+ explicitPtr = Builder.CreateBitCast(explicitPtr, AllocPtrTy);
+ initializerElements *= getContext().getConstantArrayElementCount(CAT);
+ }
+
// Enter a partial-destruction cleanup if necessary.
if (needsEHCleanup(dtorKind)) {
// In principle we could tell the cleanup where we are more
@@ -888,12 +800,16 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
// element. TODO: some of these stores can be trivially
// observed to be unnecessary.
if (endOfInit) Builder.CreateStore(explicitPtr, endOfInit);
- StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), elementType, explicitPtr);
- explicitPtr =Builder.CreateConstGEP1_32(explicitPtr, 1, "array.exp.next");
+ StoreAnyExprIntoOneUnit(*this, ILE->getInit(i),
+ ILE->getInit(i)->getType(), explicitPtr);
+ explicitPtr = Builder.CreateConstGEP1_32(explicitPtr, 1,
+ "array.exp.next");
}
// The remaining elements are filled with the array filler expression.
Init = ILE->getArrayFiller();
+
+ explicitPtr = Builder.CreateBitCast(explicitPtr, beginPtr->getType());
}
// Create the continuation block.
@@ -1012,6 +928,41 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
}
+/// Emit a call to an operator new or operator delete function, as implicitly
+/// created by new-expressions and delete-expressions.
+static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
+ const FunctionDecl *Callee,
+ const FunctionProtoType *CalleeType,
+ const CallArgList &Args) {
+ llvm::Instruction *CallOrInvoke;
+ llvm::Value *CalleeAddr = CGF.CGM.GetAddrOfFunction(Callee);
+ RValue RV =
+ CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, CalleeType),
+ CalleeAddr, ReturnValueSlot(), Args,
+ Callee, &CallOrInvoke);
+
+ /// C++1y [expr.new]p10:
+ /// [In a new-expression,] an implementation is allowed to omit a call
+ /// to a replaceable global allocation function.
+ ///
+ /// We model such elidable calls with the 'builtin' attribute.
+ llvm::Function *Fn = dyn_cast<llvm::Function>(CalleeAddr);
+ if (Callee->isReplaceableGlobalAllocationFunction() &&
+ 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,
+ llvm::Attribute::Builtin);
+ else if (llvm::InvokeInst *II = dyn_cast<llvm::InvokeInst>(CallOrInvoke))
+ II->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::Builtin);
+ else
+ llvm_unreachable("unexpected kind of call instruction");
+ }
+
+ return RV;
+}
+
namespace {
/// A cleanup to call the given 'operator delete' function upon
/// abnormal exit from a new expression.
@@ -1061,9 +1012,7 @@ namespace {
DeleteArgs.add(getPlacementArgs()[I], *AI++);
// Call 'operator delete'.
- CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, FPT),
- CGF.CGM.GetAddrOfFunction(OperatorDelete),
- ReturnValueSlot(), DeleteArgs, OperatorDelete);
+ EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
}
};
@@ -1122,9 +1071,7 @@ namespace {
}
// Call 'operator delete'.
- CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, FPT),
- CGF.CGM.GetAddrOfFunction(OperatorDelete),
- ReturnValueSlot(), DeleteArgs, OperatorDelete);
+ EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
}
};
}
@@ -1237,10 +1184,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// TODO: kill any unnecessary computations done for the size
// argument.
} else {
- RV = EmitCall(CGM.getTypes().arrangeFreeFunctionCall(allocatorArgs,
- allocatorType),
- CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
- allocatorArgs, allocator);
+ RV = EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
}
// Emit a null check on the allocation result if the allocation
@@ -1360,9 +1304,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
DeleteArgs.add(RValue::get(Size), SizeTy);
// Emit the call to delete.
- EmitCall(CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, DeleteFTy),
- CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
- DeleteArgs, DeleteFD);
+ EmitNewDeleteCall(*this, DeleteFD, DeleteFTy, DeleteArgs);
}
namespace {
@@ -1415,8 +1357,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
// FIXME: Provide a source location here.
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
- SourceLocation(),
- ReturnValueSlot(), Ptr);
+ SourceLocation(), Ptr);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
@@ -1519,9 +1460,7 @@ namespace {
}
// Emit the call to delete.
- CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(Args, DeleteFTy),
- CGF.CGM.GetAddrOfFunction(OperatorDelete),
- ReturnValueSlot(), Args, OperatorDelete);
+ EmitNewDeleteCall(CGF, OperatorDelete, DeleteFTy, Args);
}
};
}
@@ -1667,8 +1606,8 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
ConvertType(E->getType())->getPointerTo();
if (E->isTypeOperand()) {
- llvm::Constant *TypeInfo =
- CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand());
+ llvm::Constant *TypeInfo =
+ CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand(getContext()));
return Builder.CreateBitCast(TypeInfo, StdTypeInfoPtrTy);
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 36f974a31329..73d5bcb13a95 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
+#include <algorithm>
using namespace clang;
using namespace CodeGen;
@@ -69,10 +70,10 @@ public:
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
ComplexPairTy EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(CGF.EmitLValue(E));
+ return EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc());
}
- ComplexPairTy EmitLoadOfLValue(LValue LV);
+ ComplexPairTy EmitLoadOfLValue(LValue LV, SourceLocation Loc);
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
@@ -81,6 +82,9 @@ public:
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
QualType DestType);
+ /// EmitComplexToComplexCast - Emit a cast from scalar value Val to DestType.
+ ComplexPairTy EmitScalarToComplexCast(llvm::Value *Val, QualType SrcType,
+ QualType DestType);
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -109,11 +113,12 @@ public:
ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E));
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
+ E->getExprLoc());
- llvm::ConstantStruct *pair =
- cast<llvm::ConstantStruct>(result.getValue());
- return ComplexPairTy(pair->getOperand(0), pair->getOperand(1));
+ llvm::Constant *pair = result.getValue();
+ return ComplexPairTy(pair->getAggregateElement(0U),
+ pair->getAggregateElement(1U));
}
return EmitLoadOfLValue(E);
}
@@ -127,7 +132,7 @@ public:
ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
- return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
+ return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc());
return CGF.getOpaqueRValueMapping(E).getComplexVal();
}
@@ -215,7 +220,7 @@ public:
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)
(const BinOpInfo &),
- ComplexPairTy &Val);
+ RValue &Val);
ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)
(const BinOpInfo &));
@@ -287,26 +292,34 @@ public:
/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
/// load the real and imaginary pieces, returning them as Real/Imag.
-ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue) {
+ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
+ SourceLocation loc) {
assert(lvalue.isSimple() && "non-simple complex l-value?");
if (lvalue.getType()->isAtomicType())
- return CGF.EmitAtomicLoad(lvalue).getComplexVal();
+ return CGF.EmitAtomicLoad(lvalue, loc).getComplexVal();
llvm::Value *SrcPtr = lvalue.getAddress();
bool isVolatile = lvalue.isVolatileQualified();
+ unsigned AlignR = lvalue.getAlignment().getQuantity();
+ ASTContext &C = CGF.getContext();
+ QualType ComplexTy = lvalue.getType();
+ unsigned ComplexAlign = C.getTypeAlignInChars(ComplexTy).getQuantity();
+ unsigned AlignI = std::min(AlignR, ComplexAlign);
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal || isVolatile) {
llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0,
SrcPtr->getName() + ".realp");
- Real = Builder.CreateLoad(RealP, isVolatile, SrcPtr->getName() + ".real");
+ Real = Builder.CreateAlignedLoad(RealP, AlignR, isVolatile,
+ SrcPtr->getName() + ".real");
}
if (!IgnoreImag || isVolatile) {
llvm::Value *ImagP = Builder.CreateStructGEP(SrcPtr, 1,
SrcPtr->getName() + ".imagp");
- Imag = Builder.CreateLoad(ImagP, isVolatile, SrcPtr->getName() + ".imag");
+ Imag = Builder.CreateAlignedLoad(ImagP, AlignI, isVolatile,
+ SrcPtr->getName() + ".imag");
}
return ComplexPairTy(Real, Imag);
}
@@ -322,10 +335,16 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val,
llvm::Value *Ptr = lvalue.getAddress();
llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
-
- // TODO: alignment
- Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
- Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
+ unsigned AlignR = lvalue.getAlignment().getQuantity();
+ ASTContext &C = CGF.getContext();
+ QualType ComplexTy = lvalue.getType();
+ unsigned ComplexAlign = C.getTypeAlignInChars(ComplexTy).getQuantity();
+ unsigned AlignI = std::min(AlignR, ComplexAlign);
+
+ Builder.CreateAlignedStore(Val.first, RealPtr, AlignR,
+ lvalue.isVolatileQualified());
+ Builder.CreateAlignedStore(Val.second, ImagPtr, AlignI,
+ lvalue.isVolatileQualified());
}
@@ -358,7 +377,10 @@ ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
CodeGenFunction::StmtExprEvaluation eval(CGF);
- return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal();
+ llvm::Value *RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(), true);
+ assert(RetAlloca && "Expected complex return value");
+ return EmitLoadOfLValue(CGF.MakeAddrLValue(RetAlloca, E->getType()),
+ E->getExprLoc());
}
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
@@ -377,6 +399,17 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
return Val;
}
+ComplexPairTy ComplexExprEmitter::EmitScalarToComplexCast(llvm::Value *Val,
+ QualType SrcType,
+ QualType DestType) {
+ // Convert the input element to the element type of the complex.
+ DestType = DestType->castAs<ComplexType>()->getElementType();
+ Val = CGF.EmitScalarConversion(Val, SrcType, DestType);
+
+ // Return (realval, 0).
+ return ComplexPairTy(Val, llvm::Constant::getNullValue(Val->getType()));
+}
+
ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
QualType DestTy) {
switch (CK) {
@@ -397,7 +430,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
V = Builder.CreateBitCast(V,
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy,
- origLV.getAlignment()));
+ origLV.getAlignment()),
+ Op->getExprLoc());
}
case CK_BitCast:
@@ -444,16 +478,9 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
- case CK_IntegralRealToComplex: {
- llvm::Value *Elt = CGF.EmitScalarExpr(Op);
-
- // Convert the input element to the element type of the complex.
- DestTy = DestTy->castAs<ComplexType>()->getElementType();
- Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
-
- // Return (realval, 0).
- return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
- }
+ case CK_IntegralRealToComplex:
+ return EmitScalarToComplexCast(CGF.EmitScalarExpr(Op),
+ Op->getType(), DestTy);
case CK_FloatingComplexCast:
case CK_FloatingComplexToIntegralComplex:
@@ -608,7 +635,7 @@ ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
LValue ComplexExprEmitter::
EmitCompoundAssignLValue(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
- ComplexPairTy &Val) {
+ RValue &Val) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
QualType LHSTy = E->getLHS()->getType();
@@ -628,20 +655,29 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
LValue LHS = CGF.EmitLValue(E->getLHS());
- // Load from the l-value.
- ComplexPairTy LHSComplexPair = EmitLoadOfLValue(LHS);
-
- OpInfo.LHS = EmitComplexToComplexCast(LHSComplexPair, LHSTy, OpInfo.Ty);
+ // Load from the l-value and convert it.
+ if (LHSTy->isAnyComplexType()) {
+ ComplexPairTy LHSVal = EmitLoadOfLValue(LHS, E->getExprLoc());
+ OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty);
+ } else {
+ llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, E->getExprLoc());
+ OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty);
+ }
// Expand the binary operator.
ComplexPairTy Result = (this->*Func)(OpInfo);
- // Truncate the result back to the LHS type.
- Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
- Val = Result;
-
- // Store the result value into the LHS lvalue.
- EmitStoreOfComplex(Result, LHS, /*isInit*/ false);
+ // Truncate the result and store it into the LHS lvalue.
+ if (LHSTy->isAnyComplexType()) {
+ ComplexPairTy ResVal = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
+ EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false);
+ Val = RValue::getComplex(ResVal);
+ } else {
+ llvm::Value *ResVal =
+ CGF.EmitComplexToScalarConversion(Result, OpInfo.Ty, LHSTy);
+ CGF.EmitStoreOfScalar(ResVal, LHS, /*isInit*/ false);
+ Val = RValue::get(ResVal);
+ }
return LHS;
}
@@ -650,18 +686,18 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
ComplexPairTy ComplexExprEmitter::
EmitCompoundAssign(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
- ComplexPairTy Val;
+ RValue Val;
LValue LV = EmitCompoundAssignLValue(E, Func, Val);
// The result of an assignment in C is the assigned r-value.
if (!CGF.getLangOpts().CPlusPlus)
- return Val;
+ return Val.getComplexVal();
// If the lvalue is non-volatile, return the computed value of the assignment.
if (!LV.isVolatileQualified())
- return Val;
+ return Val.getComplexVal();
- return EmitLoadOfLValue(LV);
+ return EmitLoadOfLValue(LV, E->getExprLoc());
}
LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
@@ -696,7 +732,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfLValue(LV);
+ return EmitLoadOfLValue(LV, E->getExprLoc());
}
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -746,7 +782,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
}
ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
- return Visit(E->getChosenSubExpr(CGF.getContext()));
+ return Visit(E->getChosenSubExpr());
}
ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
@@ -785,8 +821,8 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
return ComplexPairTy(U, U);
}
- return EmitLoadOfLValue(
- CGF.MakeNaturalAlignAddrLValue(ArgPtr, E->getType()));
+ return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(ArgPtr, E->getType()),
+ E->getExprLoc());
}
//===----------------------------------------------------------------------===//
@@ -820,8 +856,9 @@ void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
}
/// EmitLoadOfComplex - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src) {
- return ComplexExprEmitter(*this).EmitLoadOfLValue(src);
+ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src,
+ SourceLocation loc) {
+ return ComplexExprEmitter(*this).EmitLoadOfLValue(src, loc);
}
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
@@ -830,19 +867,33 @@ LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
}
-LValue CodeGenFunction::
-EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
- ComplexPairTy(ComplexExprEmitter::*Op)(const ComplexExprEmitter::BinOpInfo &);
- switch (E->getOpcode()) {
- case BO_MulAssign: Op = &ComplexExprEmitter::EmitBinMul; break;
- case BO_DivAssign: Op = &ComplexExprEmitter::EmitBinDiv; break;
- case BO_SubAssign: Op = &ComplexExprEmitter::EmitBinSub; break;
- case BO_AddAssign: Op = &ComplexExprEmitter::EmitBinAdd; break;
+typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)(
+ const ComplexExprEmitter::BinOpInfo &);
+static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
+ switch (Op) {
+ case BO_MulAssign: return &ComplexExprEmitter::EmitBinMul;
+ case BO_DivAssign: return &ComplexExprEmitter::EmitBinDiv;
+ case BO_SubAssign: return &ComplexExprEmitter::EmitBinSub;
+ case BO_AddAssign: return &ComplexExprEmitter::EmitBinAdd;
default:
llvm_unreachable("unexpected complex compound assignment");
}
+}
- ComplexPairTy Val; // ignored
+LValue CodeGenFunction::
+EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
+ CompoundFunc Op = getComplexOp(E->getOpcode());
+ RValue Val;
return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
}
+
+LValue CodeGenFunction::
+EmitScalarCompooundAssignWithComplex(const CompoundAssignOperator *E,
+ llvm::Value *&Result) {
+ CompoundFunc Op = getComplexOp(E->getOpcode());
+ RValue Val;
+ LValue Ret = ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
+ Result = Val.getScalarVal();
+ return Ret;
+}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index f5c8187c26f4..f4d6861c8b8b 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -53,9 +53,6 @@ private:
NextFieldOffsetInChars(CharUnits::Zero()),
LLVMStructAlignment(CharUnits::One()) { }
- void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass);
-
void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitExpr);
@@ -72,8 +69,7 @@ private:
bool Build(InitListExpr *ILE);
void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
- llvm::Constant *VTable, const CXXRecordDecl *VTableClass,
- CharUnits BaseOffset);
+ const CXXRecordDecl *VTableClass, CharUnits BaseOffset);
llvm::Constant *Finalize(QualType Ty);
CharUnits getAlignment(const llvm::Constant *C) const {
@@ -88,23 +84,6 @@ private:
}
};
-void ConstStructBuilder::AppendVTablePointer(BaseSubobject Base,
- llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass) {
- // Find the appropriate vtable within the vtable group.
- uint64_t AddressPoint =
- CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
- llvm::Value *Indices[] = {
- llvm::ConstantInt::get(CGM.Int64Ty, 0),
- llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
- };
- llvm::Constant *VTableAddressPoint =
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
-
- // Add the vtable at the start of the object.
- AppendBytes(Base.getBaseOffset(), VTableAddressPoint);
-}
-
void ConstStructBuilder::
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitCst) {
@@ -368,40 +347,21 @@ void ConstStructBuilder::ConvertStructToPacked() {
}
bool ConstStructBuilder::Build(InitListExpr *ILE) {
- if (ILE->initializesStdInitializerList()) {
- //CGM.ErrorUnsupported(ILE, "global std::initializer_list");
- return false;
- }
-
RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
unsigned FieldNo = 0;
unsigned ElementNo = 0;
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(CGM.getContext());
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield(*Field, LastFD)) {
- --FieldNo;
- continue;
- }
- LastFD = *Field;
- }
-
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
continue;
// Don't emit anonymous bitfields, they just affect layout.
- if (Field->isUnnamedBitfield()) {
- LastFD = *Field;
+ if (Field->isUnnamedBitfield())
continue;
- }
// Get the initializer. A struct can include fields without initializers,
// we just use explicit null values for them.
@@ -443,15 +403,19 @@ struct BaseInfo {
}
void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
- bool IsPrimaryBase, llvm::Constant *VTable,
+ bool IsPrimaryBase,
const CXXRecordDecl *VTableClass,
CharUnits Offset) {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
// Add a vtable pointer, if we need one and it hasn't already been added.
- if (CD->isDynamicClass() && !IsPrimaryBase)
- AppendVTablePointer(BaseSubobject(CD, Offset), VTable, VTableClass);
+ if (CD->isDynamicClass() && !IsPrimaryBase) {
+ llvm::Constant *VTableAddressPoint =
+ CGM.getCXXABI().getVTableAddressPointForConstExpr(
+ BaseSubobject(CD, Offset), VTableClass);
+ AppendBytes(Offset, VTableAddressPoint);
+ }
// Accumulate and sort bases, in order to visit them in address order, which
// may not be the same as declaration order.
@@ -472,36 +436,22 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
- VTable, VTableClass, Offset + Base.Offset);
+ VTableClass, Offset + Base.Offset);
}
}
unsigned FieldNo = 0;
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(CGM.getContext());
uint64_t OffsetBits = CGM.getContext().toBits(Offset);
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield(*Field, LastFD)) {
- --FieldNo;
- continue;
- }
- LastFD = *Field;
- }
-
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && Val.getUnionField() != *Field)
continue;
// Don't emit anonymous bitfields, they just affect layout.
- if (Field->isUnnamedBitfield()) {
- LastFD = *Field;
+ if (Field->isUnnamedBitfield())
continue;
- }
// Emit the value of the initializer.
const APValue &FieldValue =
@@ -593,11 +543,7 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
- llvm::Constant *VTable = 0;
- if (CD && CD->isDynamicClass())
- VTable = CGM.getVTables().GetAddrOfVTable(CD);
-
- Builder.Build(Val, RD, false, VTable, CD, CharUnits::Zero());
+ Builder.Build(Val, RD, false, CD, CharUnits::Zero());
return Builder.Finalize(ValTy);
}
@@ -642,6 +588,10 @@ public:
return Visit(GE->getResultExpr());
}
+ llvm::Constant *VisitChooseExpr(ChooseExpr *CE) {
+ return Visit(CE->getChosenSubExpr());
+ }
+
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return Visit(E->getInitializer());
}
@@ -687,6 +637,7 @@ public:
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_NoOp:
+ case CK_ConstructorConversion:
return C;
case CK_Dependent: llvm_unreachable("saw dependent cast!");
@@ -716,7 +667,6 @@ public:
case CK_LValueBitCast:
case CK_NullToMemberPointer:
case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
@@ -995,7 +945,7 @@ public:
CXXTypeidExpr *Typeid = cast<CXXTypeidExpr>(E);
QualType T;
if (Typeid->isTypeOperand())
- T = Typeid->getTypeOperand();
+ T = Typeid->getTypeOperand(CGM.getContext());
else
T = Typeid->getExprOperand()->getType();
return CGM.GetAddrOfRTTIDescriptor(T);
@@ -1003,6 +953,15 @@ public:
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 0;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index c1c252d12b76..f3a5387c58d3 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -87,15 +87,16 @@ public:
void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
- Value *EmitLoadOfLValue(LValue LV) {
- return CGF.EmitLoadOfLValue(LV).getScalarVal();
+ Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
+ return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal();
}
/// EmitLoadOfLValue - Given an expression with complex type that represents a
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load));
+ return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load),
+ E->getExprLoc());
}
/// EmitConversionToBool - Convert the specified expression value to a
@@ -161,18 +162,18 @@ public:
Value *Visit(Expr *E) {
return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
}
-
+
Value *VisitStmt(Stmt *S) {
S->dump(CGF.getContext().getSourceManager());
llvm_unreachable("Stmt can't have complex result type!");
}
Value *VisitExpr(Expr *S);
-
+
Value *VisitParenExpr(ParenExpr *PE) {
- return Visit(PE->getSubExpr());
+ return Visit(PE->getSubExpr());
}
Value *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
- return Visit(E->getReplacement());
+ return Visit(E->getReplacement());
}
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
@@ -217,7 +218,7 @@ public:
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
- return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
+ return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc());
// Otherwise, assume the mapping is the scalar directly.
return CGF.getOpaqueRValueMapping(E).getScalarVal();
@@ -227,7 +228,8 @@ public:
Value *VisitDeclRefExpr(DeclRefExpr *E) {
if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E));
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
+ E->getExprLoc());
return result.getValue();
}
return EmitLoadOfLValue(E);
@@ -243,7 +245,7 @@ public:
return EmitLoadOfLValue(E);
}
Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (E->getMethodDecl() &&
+ if (E->getMethodDecl() &&
E->getMethodDecl()->getResultType()->isReferenceType())
return EmitLoadOfLValue(E);
return CGF.EmitObjCMessageExpr(E).getScalarVal();
@@ -251,12 +253,13 @@ public:
Value *VisitObjCIsaExpr(ObjCIsaExpr *E) {
LValue LV = CGF.EmitObjCIsaExpr(E);
- Value *V = CGF.EmitLoadOfLValue(LV).getScalarVal();
+ Value *V = CGF.EmitLoadOfLValue(LV, E->getExprLoc()).getScalarVal();
return V;
}
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
Value *VisitMemberExpr(MemberExpr *E);
Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
@@ -310,7 +313,7 @@ public:
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
-
+
Value *VisitUnaryAddrOf(const UnaryOperator *E) {
if (isa<MemberPointerType>(E->getType())) // never sugared
return CGF.CGM.getMemberPointerConstant(E);
@@ -335,12 +338,12 @@ public:
Value *VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
-
+
// C++
Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) {
return EmitLoadOfLValue(E);
}
-
+
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
}
@@ -430,7 +433,7 @@ public:
Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops);
// Check for undefined division and modulus behaviors.
- void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
+ void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
// Common helper for getting how wide LHS of shift is.
static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
@@ -893,51 +896,43 @@ Value *ScalarExprEmitter::VisitExpr(Expr *E) {
Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// Vector Mask Case
- if (E->getNumSubExprs() == 2 ||
+ if (E->getNumSubExprs() == 2 ||
(E->getNumSubExprs() == 3 && E->getExpr(2)->getType()->isVectorType())) {
Value *LHS = CGF.EmitScalarExpr(E->getExpr(0));
Value *RHS = CGF.EmitScalarExpr(E->getExpr(1));
Value *Mask;
-
+
llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType());
unsigned LHSElts = LTy->getNumElements();
if (E->getNumSubExprs() == 3) {
Mask = CGF.EmitScalarExpr(E->getExpr(2));
-
+
// Shuffle LHS & RHS into one input vector.
SmallVector<llvm::Constant*, 32> concat;
for (unsigned i = 0; i != LHSElts; ++i) {
concat.push_back(Builder.getInt32(2*i));
concat.push_back(Builder.getInt32(2*i+1));
}
-
+
Value* CV = llvm::ConstantVector::get(concat);
LHS = Builder.CreateShuffleVector(LHS, RHS, CV, "concat");
LHSElts *= 2;
} else {
Mask = RHS;
}
-
+
llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType());
llvm::Constant* EltMask;
-
- // Treat vec3 like vec4.
- if ((LHSElts == 6) && (E->getNumSubExprs() == 3))
- EltMask = llvm::ConstantInt::get(MTy->getElementType(),
- (1 << llvm::Log2_32(LHSElts+2))-1);
- else if ((LHSElts == 3) && (E->getNumSubExprs() == 2))
- EltMask = llvm::ConstantInt::get(MTy->getElementType(),
- (1 << llvm::Log2_32(LHSElts+1))-1);
- else
- EltMask = llvm::ConstantInt::get(MTy->getElementType(),
- (1 << llvm::Log2_32(LHSElts))-1);
-
+
+ EltMask = llvm::ConstantInt::get(MTy->getElementType(),
+ llvm::NextPowerOf2(LHSElts-1)-1);
+
// Mask off the high bits of each shuffle index.
Value *MaskBits = llvm::ConstantVector::getSplat(MTy->getNumElements(),
EltMask);
Mask = Builder.CreateAnd(Mask, MaskBits, "mask");
-
+
// newv = undef
// mask = mask & maskbits
// for each elt
@@ -945,43 +940,110 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// x = extract val n
// newv = insert newv, x, i
llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(),
- MTy->getNumElements());
+ MTy->getNumElements());
Value* NewV = llvm::UndefValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
Value *IIndx = Builder.getInt32(i);
Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx");
Indx = Builder.CreateZExt(Indx, CGF.Int32Ty, "idx_zext");
-
- // Handle vec3 special since the index will be off by one for the RHS.
- if ((LHSElts == 6) && (E->getNumSubExprs() == 3)) {
- Value *cmpIndx, *newIndx;
- cmpIndx = Builder.CreateICmpUGT(Indx, Builder.getInt32(3),
- "cmp_shuf_idx");
- newIndx = Builder.CreateSub(Indx, Builder.getInt32(1), "shuf_idx_adj");
- Indx = Builder.CreateSelect(cmpIndx, newIndx, Indx, "sel_shuf_idx");
- }
+
Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt");
NewV = Builder.CreateInsertElement(NewV, VExt, IIndx, "shuf_ins");
}
return NewV;
}
-
+
Value* V1 = CGF.EmitScalarExpr(E->getExpr(0));
Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
-
- // Handle vec3 special since the index will be off by one for the RHS.
- llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
+
SmallVector<llvm::Constant*, 32> indices;
- for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
- unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
- if (VTy->getNumElements() == 3 && Idx > 3)
- Idx -= 1;
- indices.push_back(Builder.getInt32(Idx));
+ for (unsigned i = 2; i < E->getNumSubExprs(); ++i) {
+ llvm::APSInt Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
+ // Check for -1 and output it as undef in the IR.
+ if (Idx.isSigned() && Idx.isAllOnesValue())
+ indices.push_back(llvm::UndefValue::get(CGF.Int32Ty));
+ else
+ indices.push_back(Builder.getInt32(Idx.getZExtValue()));
}
Value *SV = llvm::ConstantVector::get(indices);
return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
}
+
+Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+ QualType SrcType = E->getSrcExpr()->getType(),
+ DstType = E->getType();
+
+ Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+
+ SrcType = CGF.getContext().getCanonicalType(SrcType);
+ DstType = CGF.getContext().getCanonicalType(DstType);
+ if (SrcType == DstType) return Src;
+
+ assert(SrcType->isVectorType() &&
+ "ConvertVector source type must be a vector");
+ assert(DstType->isVectorType() &&
+ "ConvertVector destination type must be a vector");
+
+ llvm::Type *SrcTy = Src->getType();
+ llvm::Type *DstTy = ConvertType(DstType);
+
+ // Ignore conversions like int -> uint.
+ if (SrcTy == DstTy)
+ return Src;
+
+ QualType SrcEltType = SrcType->getAs<VectorType>()->getElementType(),
+ DstEltType = DstType->getAs<VectorType>()->getElementType();
+
+ assert(SrcTy->isVectorTy() &&
+ "ConvertVector source IR type must be a vector");
+ assert(DstTy->isVectorTy() &&
+ "ConvertVector destination IR type must be a vector");
+
+ llvm::Type *SrcEltTy = SrcTy->getVectorElementType(),
+ *DstEltTy = DstTy->getVectorElementType();
+
+ if (DstEltType->isBooleanType()) {
+ assert((SrcEltTy->isFloatingPointTy() ||
+ isa<llvm::IntegerType>(SrcEltTy)) && "Unknown boolean conversion");
+
+ llvm::Value *Zero = llvm::Constant::getNullValue(SrcTy);
+ if (SrcEltTy->isFloatingPointTy()) {
+ return Builder.CreateFCmpUNE(Src, Zero, "tobool");
+ } else {
+ return Builder.CreateICmpNE(Src, Zero, "tobool");
+ }
+ }
+
+ // We have the arithmetic types: real int/float.
+ Value *Res = NULL;
+
+ if (isa<llvm::IntegerType>(SrcEltTy)) {
+ bool InputSigned = SrcEltType->isSignedIntegerOrEnumerationType();
+ if (isa<llvm::IntegerType>(DstEltTy))
+ Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
+ else if (InputSigned)
+ Res = Builder.CreateSIToFP(Src, DstTy, "conv");
+ else
+ Res = Builder.CreateUIToFP(Src, DstTy, "conv");
+ } else if (isa<llvm::IntegerType>(DstEltTy)) {
+ assert(SrcEltTy->isFloatingPointTy() && "Unknown real conversion");
+ if (DstEltType->isSignedIntegerOrEnumerationType())
+ Res = Builder.CreateFPToSI(Src, DstTy, "conv");
+ else
+ Res = Builder.CreateFPToUI(Src, DstTy, "conv");
+ } else {
+ assert(SrcEltTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() &&
+ "Unknown real conversion");
+ if (DstEltTy->getTypeID() < SrcEltTy->getTypeID())
+ Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
+ else
+ Res = Builder.CreateFPExt(Src, DstTy, "conv");
+ }
+
+ return Res;
+}
+
Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
llvm::APSInt Value;
if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
@@ -992,18 +1054,6 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
return Builder.getInt(Value);
}
- // Emit debug info for aggregate now, if it was delayed to reduce
- // debug info size.
- CGDebugInfo *DI = CGF.getDebugInfo();
- if (DI &&
- CGF.CGM.getCodeGenOpts().getDebugInfo()
- == CodeGenOptions::LimitedDebugInfo) {
- QualType PQTy = E->getBase()->IgnoreParenImpCasts()->getType();
- if (const PointerType * PTy = dyn_cast<PointerType>(PQTy))
- if (FieldDecl *M = dyn_cast<FieldDecl>(E->getMemberDecl()))
- DI->getOrCreateRecordType(PTy->getPointeeType(),
- M->getParent()->getLocation());
- }
return EmitLoadOfLValue(E);
}
@@ -1023,7 +1073,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
Value *Idx = Visit(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
- if (CGF.SanOpts->Bounds)
+ if (CGF.SanOpts->ArrayBounds)
CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true);
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
@@ -1034,7 +1084,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx,
unsigned Off, llvm::Type *I32Ty) {
int MV = SVI->getMaskValue(Idx);
- if (MV == -1)
+ if (MV == -1)
return llvm::UndefValue::get(I32Ty);
return llvm::ConstantInt::get(I32Ty, Off+MV);
}
@@ -1044,13 +1094,13 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
(void)Ignore;
assert (Ignore == false && "init list ignored");
unsigned NumInitElements = E->getNumInits();
-
+
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
-
+
llvm::VectorType *VType =
dyn_cast<llvm::VectorType>(ConvertType(E->getType()));
-
+
if (!VType) {
if (NumInitElements == 0) {
// C++11 value-initialization for the scalar.
@@ -1059,10 +1109,10 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
// We have a scalar in braces. Just use the first element.
return Visit(E->getInit(0));
}
-
+
unsigned ResElts = VType->getNumElements();
-
- // Loop over initializers collecting the Value for each, and remembering
+
+ // Loop over initializers collecting the Value for each, and remembering
// whether the source was swizzle (ExtVectorElementExpr). This will allow
// us to fold the shuffle for the swizzle into the shuffle for the vector
// initializer, since LLVM optimizers generally do not want to touch
@@ -1074,11 +1124,11 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Expr *IE = E->getInit(i);
Value *Init = Visit(IE);
SmallVector<llvm::Constant*, 16> Args;
-
+
llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType());
-
+
// Handle scalar elements. If the scalar initializer is actually one
- // element of a different vector of the same width, use shuffle instead of
+ // element of a different vector of the same width, use shuffle instead of
// extract+insert.
if (!VVT) {
if (isa<ExtVectorElementExpr>(IE)) {
@@ -1121,10 +1171,10 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
++CurIdx;
continue;
}
-
+
unsigned InitElts = VVT->getNumElements();
- // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's
+ // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's
// input is the same width as the vector being constructed, generate an
// optimized shuffle of the swizzle input into the result.
unsigned Offset = (CurIdx == 0) ? 0 : ResElts;
@@ -1132,7 +1182,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init);
Value *SVOp = SVI->getOperand(0);
llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType());
-
+
if (OpTy->getNumElements() == ResElts) {
for (unsigned j = 0; j != CurIdx; ++j) {
// If the current vector initializer is a shuffle with undef, merge
@@ -1182,11 +1232,11 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
VIsUndefShuffle = isa<llvm::UndefValue>(Init);
CurIdx += InitElts;
}
-
+
// FIXME: evaluate codegen vs. shuffling against constant null vector.
// Emit remaining default initializers.
llvm::Type *EltTy = VType->getElementType();
-
+
// Emit remaining default initializers
for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) {
Value *Idx = Builder.getInt32(CurIdx);
@@ -1201,12 +1251,12 @@ static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
if (CE->getCastKind() == CK_UncheckedDerivedToBase)
return false;
-
+
if (isa<CXXThisExpr>(E)) {
// We always assume that 'this' is never null.
return false;
}
-
+
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
// And that glvalue casts are never null.
if (ICE->getValueKind() != VK_RValue)
@@ -1223,7 +1273,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Expr *E = CE->getSubExpr();
QualType DestTy = CE->getType();
CastKind Kind = CE->getCastKind();
-
+
if (!DestTy->isVoidType())
TestAndClearIgnoreResultAssign();
@@ -1235,12 +1285,13 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_BuiltinFnToFnPtr:
llvm_unreachable("builtin functions are handled elsewhere");
- case CK_LValueBitCast:
+ case CK_LValueBitCast:
case CK_ObjCObjectLValueCast: {
Value *V = EmitLValue(E).getAddress();
- V = Builder.CreateBitCast(V,
+ V = Builder.CreateBitCast(V,
ConvertType(CGF.getContext().getPointerType(DestTy)));
- return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(V, DestTy));
+ return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(V, DestTy),
+ CE->getExprLoc());
}
case CK_CPointerToObjCPointerCast:
@@ -1262,15 +1313,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
llvm::Value *V = Visit(E);
+ llvm::Value *Derived =
+ CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
+ CE->path_begin(), CE->path_end(),
+ ShouldNullCheckClassCastValue(CE));
+
// C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
if (CGF.SanitizePerformTypeCheck)
CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
- V, DestTy->getPointeeType());
+ Derived, DestTy->getPointeeType());
- return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
- CE->path_begin(), CE->path_end(),
- ShouldNullCheckClassCastValue(CE));
+ return Derived;
}
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
@@ -1278,7 +1332,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
E->getType()->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!");
- return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
+ return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
@@ -1330,7 +1384,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer: {
Value *Src = Visit(E);
-
+
// Note that the AST doesn't distinguish between checked and
// unchecked member pointer conversions, so we always have to
// implement checked conversions here. This is inefficient when
@@ -1354,7 +1408,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_CopyAndAutoreleaseBlockObject:
return CGF.EmitBlockCopyAndAutorelease(Visit(E), E->getType());
-
+
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
case CK_IntegralRealToComplex:
@@ -1442,8 +1496,12 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
CodeGenFunction::StmtExprEvaluation eval(CGF);
- return CGF.EmitCompoundStmt(*E->getSubStmt(), !E->getType()->isVoidType())
- .getScalarVal();
+ llvm::Value *RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(),
+ !E->getType()->isVoidType());
+ if (!RetAlloca)
+ return 0;
+ return CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(RetAlloca, E->getType()),
+ E->getExprLoc());
}
//===----------------------------------------------------------------------===//
@@ -1477,7 +1535,7 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
llvm::Value *
ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
-
+
QualType type = E->getSubExpr()->getType();
llvm::PHINode *atomicPHI = 0;
llvm::Value *value;
@@ -1503,7 +1561,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
// Special case for atomic increment / decrement on integers, emit
// atomicrmw instructions. We skip this if we want to be doing overflow
- // checking, and fall into the slow path with the atomic cmpxchg loop.
+ // checking, and fall into the slow path with the atomic cmpxchg loop.
if (!type->isBooleanType() && type->isIntegerType() &&
!(type->isUnsignedIntegerType() &&
CGF.SanOpts->UnsignedIntegerOverflow) &&
@@ -1519,7 +1577,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
LV.getAddress(), amt, llvm::SequentiallyConsistent);
return isPre ? Builder.CreateBinOp(op, old, amt) : old;
}
- value = EmitLoadOfLValue(LV);
+ value = EmitLoadOfLValue(LV, E->getExprLoc());
input = value;
// For every other atomic operation, we need to emit a load-op-cmpxchg loop
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
@@ -1531,7 +1589,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
atomicPHI->addIncoming(value, startBB);
value = atomicPHI;
} else {
- value = EmitLoadOfLValue(LV);
+ value = EmitLoadOfLValue(LV, E->getExprLoc());
input = value;
}
@@ -1569,7 +1627,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = EmitOverflowCheckedBinOp(BinOp);
} else
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
-
+
// Next most common: pointer increment.
} else if (const PointerType *ptr = type->getAs<PointerType>()) {
QualType type = ptr->getPointeeType();
@@ -1583,7 +1641,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
-
+
// Arithmetic on function pointers (!) is just +-1.
} else if (type->isFunctionType()) {
llvm::Value *amt = Builder.getInt32(amount);
@@ -1665,7 +1723,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
-
+
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
@@ -1696,10 +1754,10 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
// Emit unary minus with EmitSub so we handle overflow cases etc.
BinOpInfo BinOp;
BinOp.RHS = Visit(E->getSubExpr());
-
+
if (BinOp.RHS->getType()->isFPOrFPVectorTy())
BinOp.LHS = llvm::ConstantFP::getZeroValueForNegation(BinOp.RHS->getType());
- else
+ else
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub;
@@ -1726,7 +1784,7 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
}
-
+
// Compare operand to zero.
Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr());
@@ -1814,7 +1872,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Save the element type.
CurrentType = ON.getBase()->getType();
-
+
// Compute the offset to the base.
const RecordType *BaseRT = CurrentType->getAs<RecordType>();
CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
@@ -1873,7 +1931,8 @@ Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
if (E->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E)).getScalarVal();
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
+ E->getExprLoc()).getScalarVal();
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, false, true).first;
@@ -1889,7 +1948,8 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
if (Op->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E)).getScalarVal();
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
+ E->getExprLoc()).getScalarVal();
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, true, false).second;
@@ -1926,17 +1986,10 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
Value *&Result) {
QualType LHSTy = E->getLHS()->getType();
BinOpInfo OpInfo;
-
- if (E->getComputationResultType()->isAnyComplexType()) {
- // This needs to go through the complex expression emitter, but it's a tad
- // complicated to do that... I'm leaving it out for now. (Note that we do
- // actually need the imaginary part of the RHS for multiplication and
- // division.)
- CGF.ErrorUnsupported(E, "complex compound assignment");
- Result = llvm::UndefValue::get(CGF.ConvertType(E->getType()));
- return LValue();
- }
-
+
+ if (E->getComputationResultType()->isAnyComplexType())
+ return CGF.EmitScalarCompooundAssignWithComplex(E, Result);
+
// Emit the RHS first. __block variables need to have the rhs evaluated
// first, plus this should improve codegen a little.
OpInfo.RHS = Visit(E->getRHS());
@@ -1993,7 +2046,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
// floating point environment in the loop.
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
- OpInfo.LHS = EmitLoadOfLValue(LHSLV);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
@@ -2002,14 +2055,14 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.LHS = atomicPHI;
}
else
- OpInfo.LHS = EmitLoadOfLValue(LHSLV);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
// Expand the binary operator.
Result = (this->*Func)(OpInfo);
-
+
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
@@ -2024,7 +2077,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
Builder.SetInsertPoint(contBB);
return LHSLV;
}
-
+
// Store the result value into the LHS lvalue. Bit-fields are handled
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after the
@@ -2056,7 +2109,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
return RHS;
// Otherwise, reload the value.
- return EmitLoadOfLValue(LHS);
+ return EmitLoadOfLValue(LHS, E->getExprLoc());
}
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
@@ -2236,7 +2289,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// Must have binary (not unary) expr here. Unary pointer
// increment/decrement doesn't use this path.
const BinaryOperator *expr = cast<BinaryOperator>(op.E);
-
+
Value *pointer = op.LHS;
Expr *pointerOperand = expr->getLHS();
Value *index = op.RHS;
@@ -2261,7 +2314,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (isSubtraction)
index = CGF.Builder.CreateNeg(index, "idx.neg");
- if (CGF.SanOpts->Bounds)
+ if (CGF.SanOpts->ArrayBounds)
CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
/*Accessed*/ false);
@@ -2325,7 +2378,7 @@ static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend,
const CodeGenFunction &CGF, CGBuilderTy &Builder,
bool negMul, bool negAdd) {
assert(!(negMul && negAdd) && "Only one of negMul and negAdd should be set.");
-
+
Value *MulOp0 = MulOp->getOperand(0);
Value *MulOp1 = MulOp->getOperand(1);
if (negMul) {
@@ -2355,7 +2408,7 @@ static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend,
// Checks that (a) the operation is fusable, and (b) -ffp-contract=on.
// Does NOT check the type of the operation - it's assumed that this function
// will be called from contexts where it's known that the type is contractable.
-static Value* tryEmitFMulAdd(const BinOpInfo &op,
+static Value* tryEmitFMulAdd(const BinOpInfo &op,
const CodeGenFunction &CGF, CGBuilderTy &Builder,
bool isSub=false) {
@@ -2503,7 +2556,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
divisor = CGF.CGM.getSize(elementSize);
}
-
+
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
// pointer difference in C is only defined in the case where both operands
// are pointing to elements of an array.
@@ -2809,7 +2862,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return RHS;
// Otherwise, reload the value.
- return EmitLoadOfLValue(LHS);
+ return EmitLoadOfLValue(LHS, E->getExprLoc());
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
@@ -2828,9 +2881,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
Value *And = Builder.CreateAnd(LHS, RHS);
return Builder.CreateSExt(And, ConvertType(E->getType()), "sext");
}
-
+
llvm::Type *ResTy = ConvertType(E->getType());
-
+
// If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
// If we have 1 && X, just emit X without inserting the control flow.
bool LHSCondVal;
@@ -2899,9 +2952,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
Value *Or = Builder.CreateOr(LHS, RHS);
return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext");
}
-
+
llvm::Type *ResTy = ConvertType(E->getType());
-
+
// If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
// If we have 0 || X, just emit X without inserting the control flow.
bool LHSCondVal;
@@ -2970,22 +3023,15 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
/// flow into selects in some cases.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
CodeGenFunction &CGF) {
- E = E->IgnoreParens();
-
// Anything that is an integer or floating point constant is fine.
- if (E->isConstantInitializer(CGF.getContext(), false))
- return true;
-
- // Non-volatile automatic variables too, to get "cond ? X : Y" where
- // X and Y are local variables.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
- if (VD->hasLocalStorage() && !(CGF.getContext()
- .getCanonicalType(VD->getType())
- .isVolatileQualified()))
- return true;
-
- return false;
+ return E->IgnoreParens()->isEvaluatable(CGF.getContext());
+
+ // Even non-volatile automatic variables can't be evaluated unconditionally.
+ // Referencing a thread_local may cause non-trivial initialization work to
+ // occur. If we're inside a lambda and one of the variables is from the scope
+ // outside the lambda, that function may have returned already. Reading its
+ // locals is a bad idea. Also, these reads may introduce races there didn't
+ // exist in the source-level program.
}
@@ -3023,26 +3069,26 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// OpenCL: If the condition is a vector, we can treat this condition like
// the select function.
- if (CGF.getLangOpts().OpenCL
+ if (CGF.getLangOpts().OpenCL
&& condExpr->getType()->isVectorType()) {
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
-
+
llvm::Type *condType = ConvertType(condExpr->getType());
llvm::VectorType *vecTy = cast<llvm::VectorType>(condType);
-
- unsigned numElem = vecTy->getNumElements();
+
+ unsigned numElem = vecTy->getNumElements();
llvm::Type *elemType = vecTy->getElementType();
-
+
llvm::Value *zeroVec = llvm::Constant::getNullValue(vecTy);
llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec);
- llvm::Value *tmp = Builder.CreateSExt(TestMSB,
+ llvm::Value *tmp = Builder.CreateSExt(TestMSB,
llvm::VectorType::get(elemType,
- numElem),
+ numElem),
"sext");
llvm::Value *tmp2 = Builder.CreateNot(tmp);
-
+
// Cast float to int to perform ANDs if necessary.
llvm::Value *RHSTmp = RHS;
llvm::Value *LHSTmp = LHS;
@@ -3053,7 +3099,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
LHSTmp = Builder.CreateBitCast(LHS, tmp->getType());
wasCast = true;
}
-
+
llvm::Value *tmp3 = Builder.CreateAnd(RHSTmp, tmp2);
llvm::Value *tmp4 = Builder.CreateAnd(LHSTmp, tmp);
llvm::Value *tmp5 = Builder.CreateOr(tmp3, tmp4, "cond");
@@ -3062,7 +3108,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return tmp5;
}
-
+
// If this is a really simple expression (like x ? 4 : 5), emit this as a
// select instead of as control flow. We can only do this if it is cheap and
// safe to evaluate the LHS and RHS unconditionally.
@@ -3116,7 +3162,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
}
Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
- return Visit(E->getChosenSubExpr(CGF.getContext()));
+ return Visit(E->getChosenSubExpr());
}
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
@@ -3138,49 +3184,49 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
llvm::Type *DstTy = ConvertType(E->getType());
-
+
// Going from vec4->vec3 or vec3->vec4 is a special case and requires
// a shuffle vector instead of a bitcast.
llvm::Type *SrcTy = Src->getType();
if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) {
unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements();
unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements();
- if ((numElementsDst == 3 && numElementsSrc == 4)
+ if ((numElementsDst == 3 && numElementsSrc == 4)
|| (numElementsDst == 4 && numElementsSrc == 3)) {
-
-
+
+
// In the case of going from int4->float3, a bitcast is needed before
// doing a shuffle.
- llvm::Type *srcElemTy =
+ llvm::Type *srcElemTy =
cast<llvm::VectorType>(SrcTy)->getElementType();
- llvm::Type *dstElemTy =
+ llvm::Type *dstElemTy =
cast<llvm::VectorType>(DstTy)->getElementType();
-
+
if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy())
|| (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) {
// Create a float type of the same size as the source or destination.
llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy,
numElementsSrc);
-
+
Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast");
}
-
+
llvm::Value *UnV = llvm::UndefValue::get(Src->getType());
-
+
SmallVector<llvm::Constant*, 3> Args;
Args.push_back(Builder.getInt32(0));
Args.push_back(Builder.getInt32(1));
Args.push_back(Builder.getInt32(2));
-
+
if (numElementsDst == 4)
Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
-
+
llvm::Constant *Mask = llvm::ConstantVector::get(Args);
-
+
return Builder.CreateShuffleVector(Src, UnV, Mask, "astype");
}
}
-
+
return Builder.CreateBitCast(Src, DstTy, "astype");
}
@@ -3248,14 +3294,14 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *Src = EmitScalarExpr(BaseExpr);
Builder.CreateStore(Src, V);
V = ScalarExprEmitter(*this).EmitLoadOfLValue(
- MakeNaturalAlignAddrLValue(V, E->getType()));
+ MakeNaturalAlignAddrLValue(V, E->getType()), E->getExprLoc());
} else {
if (E->isArrow())
V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
else
V = EmitLValue(BaseExpr).getAddress();
}
-
+
// build Class* type
ClassPtrTy = ClassPtrTy->getPointerTo();
V = Builder.CreateBitCast(V, ClassPtrTy);
@@ -3283,7 +3329,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
COMPOUND_OP(Xor);
COMPOUND_OP(Or);
#undef COMPOUND_OP
-
+
case BO_PtrMemD:
case BO_PtrMemI:
case BO_Mul:
@@ -3308,6 +3354,6 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
case BO_Comma:
llvm_unreachable("Not valid compound assignment operators");
}
-
+
llvm_unreachable("Unhandled compound assignment operator");
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 713509bf6738..0bda053f35f7 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CallSite.h"
#include "llvm/IR/DataLayout.h"
@@ -468,8 +469,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
SourceLocation StartLoc) {
FunctionArgList args;
// Check if we should generate debug info for this method.
- if (!OMD->hasAttr<NoDebugAttr>())
- maybeInitializeDebugInfo();
+ if (OMD->hasAttr<NoDebugAttr>())
+ DebugInfo = NULL; // disable debug info indefinitely for this function
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
@@ -925,7 +926,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
QualType ivarType = ivar->getType();
switch (getEvaluationKind(ivarType)) {
case TEK_Complex: {
- ComplexPairTy pair = EmitLoadOfComplex(LV);
+ ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
EmitStoreOfComplex(pair,
MakeNaturalAlignAddrLValue(ReturnValue, ivarType),
/*init*/ true);
@@ -949,7 +950,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// Otherwise we want to do a simple load, suppressing the
// final autorelease.
} else {
- value = EmitLoadOfLValue(LV).getScalarVal();
+ value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
AutoreleaseResult = false;
}
@@ -1048,8 +1049,6 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
FunctionType::ExtInfo(),
RequiredArgs::All),
copyCppAtomicObjectFn, ReturnValueSlot(), args);
-
-
}
@@ -1404,7 +1403,7 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() {
VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
Self->getType(), VK_LValue, SourceLocation());
- return EmitLoadOfScalar(EmitDeclRefLValue(&DRE));
+ return EmitLoadOfScalar(EmitDeclRefLValue(&DRE), SourceLocation());
}
QualType CodeGenFunction::TypeOfSelfObject() {
@@ -2084,7 +2083,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
newValue = EmitARCRetain(type, newValue);
// Read the old value.
- llvm::Value *oldValue = EmitLoadOfScalar(dst);
+ llvm::Value *oldValue = EmitLoadOfScalar(dst, SourceLocation());
// Store. We do this before the release so that any deallocs won't
// see the old value.
@@ -2355,7 +2354,8 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
- return TryEmitResult(CGF.EmitLoadOfLValue(lvalue).getScalarVal(),
+ return TryEmitResult(CGF.EmitLoadOfLValue(lvalue,
+ SourceLocation()).getScalarVal(),
false);
case Qualifiers::OCL_Weak:
@@ -2381,7 +2381,8 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lv = CGF.EmitLValue(e);
// Load the object pointer.
- llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
+ llvm::Value *result = CGF.EmitLoadOfLValue(lv,
+ SourceLocation()).getScalarVal();
// Set the source pointer to NULL.
CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
@@ -2784,8 +2785,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
// If the RHS was emitted retained, expand this.
if (hasImmediateRetain) {
- llvm::Value *oldValue =
- EmitLoadOfScalar(lvalue);
+ llvm::Value *oldValue = EmitLoadOfScalar(lvalue, SourceLocation());
EmitStoreOfScalar(value, lvalue);
EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
} else {
@@ -2905,9 +2905,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
"__assign_helper_atomic_property_",
&CGM.getModule());
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
-
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
DeclRefExpr DstExpr(&dstDecl, false, DestTy,
@@ -2988,9 +2985,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__copy_helper_atomic_property_", &CGM.getModule());
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
-
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index fbf8a1abb013..a7ab8507014f 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -454,13 +454,15 @@ protected:
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
llvm::Value *cmd,
- llvm::MDNode *node) = 0;
+ llvm::MDNode *node,
+ MessageSendInfo &MSI) = 0;
/// Looks up the method for sending a message to a superclass. This
/// mechanism differs between the GCC and GNU runtimes, so this method must
/// be overridden in subclasses.
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
llvm::Value *ObjCSuper,
- llvm::Value *cmd) = 0;
+ llvm::Value *cmd,
+ MessageSendInfo &MSI) = 0;
/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
/// stored in a 64-bit value with the low bit set to 1 and the remaining 63
/// bits set to their values, LSB first, while larger ones are stored in a
@@ -596,7 +598,8 @@ protected:
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
llvm::Value *cmd,
- llvm::MDNode *node) {
+ llvm::MDNode *node,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
@@ -607,7 +610,8 @@ protected:
}
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
llvm::Value *ObjCSuper,
- llvm::Value *cmd) {
+ llvm::Value *cmd,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
@@ -655,7 +659,8 @@ class CGObjCGNUstep : public CGObjCGNU {
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
llvm::Value *cmd,
- llvm::MDNode *node) {
+ llvm::MDNode *node,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Function *LookupFn = SlotLookupFn;
@@ -693,7 +698,8 @@ class CGObjCGNUstep : public CGObjCGNU {
}
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
llvm::Value *ObjCSuper,
- llvm::Value *cmd) {
+ llvm::Value *cmd,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
@@ -790,38 +796,52 @@ class CGObjCGNUstep : public CGObjCGNU {
}
};
-/// Support for the ObjFW runtime. Support here is due to
-/// Jonathan Schleifer <js@webkeks.org>, the ObjFW maintainer.
+/// Support for the ObjFW runtime.
class CGObjCObjFW: public CGObjCGNU {
protected:
/// The GCC ABI message lookup function. Returns an IMP pointing to the
/// method implementation for this message.
LazyRuntimeFunction MsgLookupFn;
+ /// stret lookup function. While this does not seem to make sense at the
+ /// first look, this is required to call the correct forwarding function.
+ LazyRuntimeFunction MsgLookupFnSRet;
/// The GCC ABI superclass message lookup function. Takes a pointer to a
/// structure describing the receiver and the class, and a selector as
/// arguments. Returns the IMP for the corresponding method.
- LazyRuntimeFunction MsgLookupSuperFn;
+ LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet;
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
llvm::Value *cmd,
- llvm::MDNode *node) {
+ llvm::MDNode *node,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
+
+ llvm::CallSite imp;
+ if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+ imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFnSRet, args);
+ else
+ imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
+
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
llvm::Value *ObjCSuper,
- llvm::Value *cmd) {
+ llvm::Value *cmd,
+ MessageSendInfo &MSI) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
+
+ if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFnSRet, lookupArgs);
+ else
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
@@ -847,9 +867,13 @@ public:
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
// IMP objc_msg_lookup(id, SEL);
MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+ MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
+ SelectorTy, NULL);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
PtrToObjCSuperTy, SelectorTy, NULL);
+ MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
+ PtrToObjCSuperTy, SelectorTy, NULL);
}
};
} // end anonymous namespace
@@ -1041,7 +1065,7 @@ llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval) {
- SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
+ SmallVectorImpl<TypedSelector> &Types = SelectorTable[Sel];
llvm::GlobalAlias *SelValue = 0;
@@ -1291,7 +1315,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
// Get the IMP
- llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd);
+ llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI);
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Value *impMD[] = {
@@ -1390,7 +1414,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
// given platform), so we
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
case CodeGenOptions::Legacy:
- imp = LookupIMP(CGF, Receiver, cmd, node);
+ imp = LookupIMP(CGF, Receiver, cmd, node, MSI);
break;
case CodeGenOptions::Mixed:
case CodeGenOptions::NonLegacy:
@@ -1414,8 +1438,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
- 0, &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, 0, &call);
call->setMetadata(msgSendMDKind, node);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index e8498b06ad2f..2b2a5b837608 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
@@ -4348,7 +4349,7 @@ void CGObjCCommonMac::EmitImageInfo() {
// Indicate whether we're compiling this to run on a simulator.
const llvm::Triple &Triple = CGM.getTarget().getTriple();
- if (Triple.getOS() == llvm::Triple::IOS &&
+ if (Triple.isiOS() &&
(Triple.getArch() == llvm::Triple::x86 ||
Triple.getArch() == llvm::Triple::x86_64))
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
@@ -5757,6 +5758,9 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
};
if (!Values[1])
Values[1] = llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy);
+ if (!Values[3])
+ Values[3] = llvm::Constant::getNullValue(
+ llvm::PointerType::getUnqual(ObjCTypes.ImpnfABITy));
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
@@ -5800,14 +5804,21 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::GlobalValue::ExternalLinkage,
0,
"_objc_empty_cache");
-
- ObjCEmptyVtableVar = new llvm::GlobalVariable(
- CGM.getModule(),
- ObjCTypes.ImpnfABITy,
- false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- "_objc_empty_vtable");
+
+ // Make this entry NULL for any iOS device target, any iOS simulator target,
+ // OS X with deployment target 10.9 or later.
+ const llvm::Triple &Triple = CGM.getTarget().getTriple();
+ if (Triple.isiOS() || (Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 9)))
+ // This entry will be null.
+ ObjCEmptyVtableVar = 0;
+ else
+ ObjCEmptyVtableVar = new llvm::GlobalVariable(
+ CGM.getModule(),
+ ObjCTypes.ImpnfABITy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "_objc_empty_vtable");
}
assert(ID->getClassInterface() &&
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 9c0d5189f815..d097b6fad2c2 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -20,6 +20,7 @@
#include "CodeGenModule.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/Support/CallSite.h"
using namespace clang;
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 40dc6bfa3b0e..aa687b956098 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -332,6 +332,7 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
switch (Ty->getLinkage()) {
case NoLinkage:
+ case VisibleNoLinkage:
case InternalLinkage:
case UniqueExternalLinkage:
return llvm::GlobalValue::InternalLinkage;
@@ -507,60 +508,6 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
Fields.push_back(VTable);
}
-// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures
-// from available_externally to the correct linkage if necessary. An example of
-// this is:
-//
-// struct A {
-// virtual void f();
-// };
-//
-// const std::type_info &g() {
-// return typeid(A);
-// }
-//
-// void A::f() { }
-//
-// When we're generating the typeid(A) expression, we do not yet know that
-// A's key function is defined in this translation unit, so we will give the
-// typeinfo and typename structures available_externally linkage. When A::f
-// forces the vtable to be generated, we need to change the linkage of the
-// typeinfo and typename structs, otherwise we'll end up with undefined
-// externals when linking.
-static void
-maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
- QualType Ty) {
- // We're only interested in globals with available_externally linkage.
- if (!GV->hasAvailableExternallyLinkage())
- return;
-
- // Get the real linkage for the type.
- llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty);
-
- // If variable is supposed to have available_externally linkage, we don't
- // need to do anything.
- if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
- return;
-
- // Update the typeinfo linkage.
- GV->setLinkage(Linkage);
-
- // Get the typename global.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name);
-
- assert(TypeNameGV->hasAvailableExternallyLinkage() &&
- "Type name has different linkage from type info!");
-
- // And update its linkage.
- TypeNameGV->setLinkage(Linkage);
-}
-
llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -574,7 +521,8 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
if (OldGV && !OldGV->isDeclaration()) {
- maybeUpdateRTTILinkage(CGM, OldGV, Ty);
+ assert(!OldGV->hasAvailableExternallyLinkage() &&
+ "available_externally typeinfos not yet implemented");
return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
}
@@ -898,7 +846,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
CharUnits Offset;
if (Base->isVirtual())
Offset =
- CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
Offset = Layout.getBaseClassOffset(BaseDecl);
@@ -1024,6 +972,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptors() {
Context.UnsignedLongLongTy, Context.FloatTy,
Context.DoubleTy, Context.LongDoubleTy,
Context.Char16Ty, Context.Char32Ty };
- for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i)
+ for (unsigned i = 0; i < llvm::array_lengthof(FundamentalTypes); ++i)
EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 30ab528ffbe4..ab92563b21f3 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -78,9 +78,6 @@ public:
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
-
- /// IsMsStruct - Whether ms_struct is in effect or not
- bool IsMsStruct;
private:
CodeGenTypes &Types;
@@ -117,7 +114,7 @@ private:
RecordDecl::field_iterator &FI,
RecordDecl::field_iterator FE);
- /// LayoutField - try to layout all fields in the record decl.
+ /// LayoutFields - try to layout all fields in the record decl.
/// Returns false if the operation failed because the struct is not packed.
bool LayoutFields(const RecordDecl *D);
@@ -195,8 +192,7 @@ public:
CGRecordLayoutBuilder(CodeGenTypes &Types)
: BaseSubobjectType(0),
IsZeroInitializable(true), IsZeroInitializableAsBase(true),
- Packed(false), IsMsStruct(false),
- Types(Types) { }
+ Packed(false), Types(Types) { }
/// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D);
@@ -205,10 +201,9 @@ public:
}
void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
- Alignment = Types.getContext().getASTRecordLayout(D).getAlignment();
- Packed = D->hasAttr<PackedAttr>();
-
- IsMsStruct = D->isMsStruct(Types.getContext());
+ const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
+ Alignment = Layout.getAlignment();
+ Packed = D->hasAttr<PackedAttr>() || Layout.getSize() % Alignment != 0;
if (D->isUnion()) {
LayoutUnion(D);
@@ -702,7 +697,7 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
}
// Add a vb-table pointer if the layout insists.
- if (Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1)) {
+ if (Layout.hasOwnVBPtr()) {
CharUnits VBPtrOffset = Layout.getVBPtrOffset();
llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
@@ -764,20 +759,10 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
return false;
unsigned FieldNo = 0;
- const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator FI = D->field_begin(), FE = D->field_end();
FI != FE; ++FI, ++FieldNo) {
FieldDecl *FD = *FI;
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
- --FieldNo;
- continue;
- }
- LastFD = FD;
- }
// If this field is a bitfield, layout all of the consecutive
// non-zero-length bitfields and the last zero-length bitfield; these will
@@ -992,11 +977,11 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
// Dump the layout, if requested.
if (getContext().getLangOpts().DumpRecordLayouts) {
- llvm::errs() << "\n*** Dumping IRgen Record Layout\n";
- llvm::errs() << "Record: ";
- D->dump();
- llvm::errs() << "\nLayout: ";
- RL->dump();
+ llvm::outs() << "\n*** Dumping IRgen Record Layout\n";
+ llvm::outs() << "Record: ";
+ D->dump(llvm::outs());
+ llvm::outs() << "\nLayout: ";
+ RL->print(llvm::outs());
}
#ifndef NDEBUG
@@ -1028,8 +1013,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
RecordDecl::field_iterator it = D->field_begin();
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = D->isMsStruct(getContext());
for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
const FieldDecl *FD = *it;
@@ -1039,25 +1022,12 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
unsigned FieldNo = RL->getLLVMFieldNo(FD);
assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) &&
"Invalid field offset!");
- LastFD = FD;
continue;
}
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
- --i;
- continue;
- }
- LastFD = FD;
- }
// Ignore unnamed bit-fields.
- if (!FD->getDeclName()) {
- LastFD = FD;
+ if (!FD->getDeclName())
continue;
- }
// Don't inspect zero-length bitfields.
if (FD->getBitWidthValue(getContext()) == 0)
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 5e2ebe0d9cd4..0bc51ddb5178 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -16,12 +16,14 @@
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -32,14 +34,10 @@ using namespace CodeGen;
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
SourceLocation Loc;
- if (isa<DeclStmt>(S))
- Loc = S->getLocEnd();
- else
- Loc = S->getLocStart();
+ Loc = S->getLocStart();
DI->EmitLocation(Builder, Loc);
- //if (++NumStopPoints == 1)
- LastStopPoint = Loc;
+ LastStopPoint = Loc;
}
}
@@ -77,6 +75,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
case Stmt::MSDependentExistsStmtClass:
+ case Stmt::OMPParallelDirectiveClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
@@ -137,8 +136,10 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::GCCAsmStmtClass: // Intentional fall-through.
case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
- case Stmt::CapturedStmtClass:
- EmitCapturedStmt(cast<CapturedStmt>(*S));
+ case Stmt::CapturedStmtClass: {
+ const CapturedStmt *CS = cast<CapturedStmt>(S);
+ EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
+ }
break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
@@ -167,8 +168,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
break;
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
+ break;
case Stmt::SEHTryStmtClass:
- // FIXME Not yet implemented
+ EmitSEHTryStmt(cast<SEHTryStmt>(*S));
break;
}
}
@@ -195,8 +197,8 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
/// this captures the expression result of the last sub-statement and returns it
/// (for use by the statement expression extension).
-RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
- AggValueSlot AggSlot) {
+llvm::Value* CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
+ AggValueSlot AggSlot) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
"LLVM IR generation of compound statement ('{}')");
@@ -206,17 +208,17 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
}
-RValue CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast,
- AggValueSlot AggSlot) {
+llvm::Value*
+CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
+ bool GetLast,
+ AggValueSlot AggSlot) {
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
- RValue RV;
- if (!GetLast)
- RV = RValue::get(0);
- else {
+ llvm::Value *RetAlloca = 0;
+ if (GetLast) {
// We have to special case labels here. They are statements, but when put
// at the end of a statement expression, they yield the value of their
// subexpression. Handle this by walking through all labels we encounter,
@@ -229,10 +231,21 @@ RValue CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool
EnsureInsertPoint();
- RV = EmitAnyExpr(cast<Expr>(LastStmt), AggSlot);
+ QualType ExprTy = cast<Expr>(LastStmt)->getType();
+ if (hasAggregateEvaluationKind(ExprTy)) {
+ EmitAggExpr(cast<Expr>(LastStmt), AggSlot);
+ } else {
+ // We can't return an RValue here because there might be cleanups at
+ // the end of the StmtExpr. Because of that, we have to emit the result
+ // here into a temporary alloca.
+ RetAlloca = CreateMemTemp(ExprTy);
+ EmitAnyExprToMem(cast<Expr>(LastStmt), RetAlloca, Qualifiers(),
+ /*IsInit*/false);
+ }
+
}
- return RV;
+ return RetAlloca;
}
void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
@@ -416,7 +429,7 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
- RunCleanupsScope ConditionScope(*this);
+ LexicalScope ConditionScope(*this, S.getSourceRange());
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
@@ -626,15 +639,14 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Create a cleanup scope for the condition variable cleanups.
RunCleanupsScope ConditionScope(*this);
- llvm::Value *BoolCondVal = 0;
if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable
// declaration.
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (S.getConditionVariable()) {
EmitAutoVarDecl(*S.getConditionVariable());
}
+ llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
if (ForScope.requiresCleanups())
@@ -645,8 +657,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
- BoolCondVal = EvaluateExprAsBool(S.getCond());
- Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
+ EmitBranchOnBoolExpr(S.getCond(), ForBody, ExitBlock);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
@@ -726,8 +737,7 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
// The body is executed if the expression, contextually converted
// to bool, is true.
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
- Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
+ EmitBranchOnBoolExpr(S.getCond(), ForBody, ExitBlock);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
@@ -818,7 +828,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (FnRetTy->isReferenceType()) {
// If this function returns a reference, take the address of the expression
// rather than the value.
- RValue Result = EmitReferenceBindingToExpr(RV, /*InitializedDecl=*/0);
+ RValue Result = EmitReferenceBindingToExpr(RV);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else {
switch (getEvaluationKind(RV->getType())) {
@@ -842,9 +852,9 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
}
}
- NumReturnExprs += 1;
+ ++NumReturnExprs;
if (RV == 0 || RV->isEvaluatable(getContext()))
- NumSimpleReturnExprs += 1;
+ ++NumSimpleReturnExprs;
cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
@@ -1334,7 +1344,7 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
break;
case '#': // Ignore the rest of the constraint alternative.
while (Constraint[1] && Constraint[1] != ',')
- Constraint++;
+ Constraint++;
break;
case ',':
Result += "|";
@@ -1398,11 +1408,12 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
llvm::Value*
CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
- std::string &ConstraintStr) {
+ std::string &ConstraintStr,
+ SourceLocation Loc) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
- Arg = EmitLoadOfLValue(InputValue).getScalarVal();
+ Arg = EmitLoadOfLValue(InputValue, Loc).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
@@ -1435,7 +1446,8 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
- return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr);
+ return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
+ InputExpr->getExprLoc());
}
/// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline
@@ -1559,10 +1571,15 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
ResultRegTypes.back() = ConvertType(InputTy);
}
}
- if (llvm::Type* AdjTy =
+ if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
ResultRegTypes.back()))
ResultRegTypes.back() = AdjTy;
+ else {
+ CGM.getDiags().Report(S.getAsmLoc(),
+ diag::err_asm_invalid_type_in_input)
+ << OutExpr->getType() << OutputConstraint;
+ }
} else {
ArgTypes.push_back(Dest.getAddress()->getType());
Args.push_back(Dest.getAddress());
@@ -1575,11 +1592,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
const Expr *InputExpr = S.getOutputExpr(i);
llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
- InOutConstraints);
+ InOutConstraints,
+ InputExpr->getExprLoc());
if (llvm::Type* AdjTy =
- getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
- Arg->getType()))
+ getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
+ Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
if (Info.allowsRegister())
@@ -1644,6 +1662,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
getTargetHooks().adjustInlineAsmType(*this, InputConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
+ else
+ CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << InputConstraint;
ArgTypes.push_back(Arg->getType());
Args.push_back(Arg);
@@ -1751,6 +1772,91 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
-void CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S) {
- llvm_unreachable("not implemented yet");
+static LValue InitCapturedStruct(CodeGenFunction &CGF, const CapturedStmt &S) {
+ const RecordDecl *RD = S.getCapturedRecordDecl();
+ QualType RecordTy = CGF.getContext().getRecordType(RD);
+
+ // Initialize the captured struct.
+ LValue SlotLV = CGF.MakeNaturalAlignAddrLValue(
+ CGF.CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
+
+ RecordDecl::field_iterator CurField = RD->field_begin();
+ for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(),
+ E = S.capture_init_end();
+ I != E; ++I, ++CurField) {
+ LValue LV = CGF.EmitLValueForFieldInitialization(SlotLV, *CurField);
+ CGF.EmitInitializerForField(*CurField, LV, *I, ArrayRef<VarDecl *>());
+ }
+
+ return SlotLV;
+}
+
+/// Generate an outlined function for the body of a CapturedStmt, store any
+/// captured variables into the captured struct, and call the outlined function.
+llvm::Function *
+CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
+ const CapturedDecl *CD = S.getCapturedDecl();
+ const RecordDecl *RD = S.getCapturedRecordDecl();
+ assert(CD->hasBody() && "missing CapturedDecl body");
+
+ LValue CapStruct = InitCapturedStruct(*this, S);
+
+ // Emit the CapturedDecl
+ CodeGenFunction CGF(CGM, true);
+ CGF.CapturedStmtInfo = new CGCapturedStmtInfo(S, K);
+ llvm::Function *F = CGF.GenerateCapturedStmtFunction(CD, RD, S.getLocStart());
+ delete CGF.CapturedStmtInfo;
+
+ // Emit call to the helper function.
+ EmitCallOrInvoke(F, CapStruct.getAddress());
+
+ return F;
+}
+
+/// Creates the outlined function for a CapturedStmt.
+llvm::Function *
+CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
+ const RecordDecl *RD,
+ SourceLocation Loc) {
+ assert(CapturedStmtInfo &&
+ "CapturedStmtInfo should be set when generating the captured function");
+
+ // Build the argument list.
+ ASTContext &Ctx = CGM.getContext();
+ FunctionArgList Args;
+ Args.append(CD->param_begin(), CD->param_end());
+
+ // Create the function declaration.
+ FunctionType::ExtInfo ExtInfo;
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().arrangeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
+ /*IsVariadic=*/false);
+ llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
+
+ llvm::Function *F =
+ llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
+ CapturedStmtInfo->getHelperName(), &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
+
+ // Generate the function.
+ StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getBody()->getLocStart());
+
+ // Set the context parameter in CapturedStmtInfo.
+ llvm::Value *DeclPtr = LocalDeclMap[CD->getContextParam()];
+ assert(DeclPtr && "missing context parameter for CapturedStmt");
+ CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
+
+ // If 'this' is captured, load it into CXXThisValue.
+ if (CapturedStmtInfo->isCXXThisExprCaptured()) {
+ FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
+ LValue LV = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
+ Ctx.getTagDeclType(RD));
+ LValue ThisLValue = EmitLValueForField(LV, FD);
+ CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
+ }
+
+ CapturedStmtInfo->EmitBody(*this, CD->getBody());
+ FinishFunction(CD->getBodyRBrace());
+
+ return F;
}
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 98be872a5525..bfff47058897 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -19,7 +19,8 @@ using namespace clang;
using namespace CodeGen;
static llvm::Constant *
-GetAddrOfVTTVTable(CodeGenVTables &CGVT, const CXXRecordDecl *MostDerivedClass,
+GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM,
+ const CXXRecordDecl *MostDerivedClass,
const VTTVTable &VTable,
llvm::GlobalVariable::LinkageTypes Linkage,
llvm::DenseMap<BaseSubobject, uint64_t> &AddressPoints) {
@@ -27,7 +28,7 @@ GetAddrOfVTTVTable(CodeGenVTables &CGVT, const CXXRecordDecl *MostDerivedClass,
assert(VTable.getBaseOffset().isZero() &&
"Most derived class vtable must have a zero offset!");
// This is a regular vtable.
- return CGVT.GetAddrOfVTable(MostDerivedClass);
+ return CGM.getCXXABI().getAddrOfVTable(MostDerivedClass, CharUnits());
}
return CGVT.GenerateConstructionVTable(MostDerivedClass,
@@ -52,7 +53,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
for (const VTTVTable *i = Builder.getVTTVTables().begin(),
*e = Builder.getVTTVTables().end(); i != e; ++i) {
VTableAddressPoints.push_back(VTableAddressPointsMapTy());
- VTables.push_back(GetAddrOfVTTVTable(*this, RD, *i, Linkage,
+ VTables.push_back(GetAddrOfVTTVTable(*this, CGM, RD, *i, Linkage,
VTableAddressPoints.back()));
}
@@ -64,8 +65,8 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
uint64_t AddressPoint;
if (VTTVT.getBase() == RD) {
// Just get the address point for the regular vtable.
- AddressPoint = VTContext.getVTableLayout(RD)
- .getAddressPoint(i->VTableBase);
+ AddressPoint =
+ ItaniumVTContext.getVTableLayout(RD).getAddressPoint(i->VTableBase);
assert(AddressPoint != 0 && "Did not find vtable address point!");
} else {
AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
@@ -101,12 +102,13 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, Out);
+ cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
+ .mangleCXXVTT(RD, Out);
Out.flush();
StringRef Name = OutName.str();
// This will also defer the definition of the VTT.
- (void) GetAddrOfVTable(RD);
+ (void) CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
@@ -120,24 +122,6 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
return GV;
}
-bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // We don't have any virtual bases, just return early.
- if (!MD->getParent()->getNumVBases())
- return false;
-
- // Check if we have a base constructor.
- if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
- return true;
-
- // Check if we have a base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return true;
-
- return false;
-}
-
uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
BaseSubobject Base) {
BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 069cd5f9e738..f28d9b67a8f3 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -16,6 +16,7 @@
#include "CodeGenModule.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
@@ -29,7 +30,14 @@ using namespace clang;
using namespace CodeGen;
CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
- : CGM(CGM), VTContext(CGM.getContext()) { }
+ : CGM(CGM), ItaniumVTContext(CGM.getContext()) {
+ if (CGM.getTarget().getCXXABI().isMicrosoft()) {
+ // FIXME: Eventually, we should only have one of V*TContexts available.
+ // Today we use both in the Microsoft ABI as MicrosoftVFTableContext
+ // is not completely supported in CodeGen yet.
+ MicrosoftVTContext.reset(new MicrosoftVTableContext(CGM.getContext()));
+ }
+}
llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const ThunkInfo &Thunk) {
@@ -49,53 +57,6 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true);
}
-static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
- llvm::Value *Ptr,
- int64_t NonVirtualAdjustment,
- int64_t VirtualAdjustment,
- bool IsReturnAdjustment) {
- if (!NonVirtualAdjustment && !VirtualAdjustment)
- return Ptr;
-
- llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
- llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
-
- if (NonVirtualAdjustment && !IsReturnAdjustment) {
- // Perform the non-virtual adjustment for a base-to-derived cast.
- V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
- }
-
- if (VirtualAdjustment) {
- llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- // Perform the virtual adjustment.
- llvm::Value *VTablePtrPtr =
- CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
-
- llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
-
- llvm::Value *OffsetPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
-
- OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
-
- // Load the adjustment offset from the vtable.
- llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
-
- // Adjust our pointer.
- V = CGF.Builder.CreateInBoundsGEP(V, Offset);
- }
-
- if (NonVirtualAdjustment && IsReturnAdjustment) {
- // Perform the non-virtual adjustment for a derived-to-base cast.
- V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
- }
-
- // Cast back to the original type.
- return CGF.Builder.CreateBitCast(V, Ptr->getType());
-}
-
static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
const ThunkInfo &Thunk, llvm::Function *Fn) {
CGM.setGlobalVisibility(Fn, MD);
@@ -174,12 +135,10 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
CGF.EmitBlock(AdjustNotNull);
}
-
- ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
- Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset,
- /*IsReturnAdjustment*/true);
-
+
+ ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF, ReturnValue,
+ Thunk.Return);
+
if (NullCheckValue) {
CGF.Builder.CreateBr(AdjustEnd);
CGF.EmitBlock(AdjustNull);
@@ -259,11 +218,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
assert(ThisStore && "Store of this should be in entry block?");
// Adjust "this", if necessary.
Builder.SetInsertPoint(ThisStore);
- llvm::Value *AdjustedThisPtr =
- PerformTypeAdjustment(*this, ThisPtr,
- Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset,
- /*IsReturnAdjustment*/false);
+ llvm::Value *AdjustedThisPtr =
+ CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This);
ThisStore->setOperand(0, AdjustedThisPtr);
if (!Thunk.Return.isEmpty()) {
@@ -282,94 +238,99 @@ void CodeGenFunction::GenerateVarArgsThunk(
}
}
-void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- GlobalDecl GD, const ThunkInfo &Thunk) {
+void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
+ const CGFunctionInfo &FnInfo) {
+ assert(!CurGD.getDecl() && "CurGD was already set!");
+ CurGD = GD;
+
+ // Build FunctionArgs.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getResultType();
QualType ThisType = MD->getThisType(getContext());
-
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType =
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
FunctionArgList FunctionArgs;
- // FIXME: It would be nice if more of this code could be shared with
- // CodeGenFunction::GenerateCode.
-
// Create the implicit 'this' parameter declaration.
- CurGD = GD;
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs);
// Add the rest of the parameters.
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I) {
- ParmVarDecl *Param = *I;
-
- FunctionArgs.push_back(Param);
- }
-
- // Initialize debug info if needed.
- maybeInitializeDebugInfo();
+ E = MD->param_end();
+ I != E; ++I)
+ FunctionArgs.push_back(*I);
+ // Start defining the function.
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
SourceLocation());
+ // Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
CXXThisValue = CXXABIThisValue;
+}
- // Adjust the 'this' pointer if necessary.
- llvm::Value *AdjustedThisPtr =
- PerformTypeAdjustment(*this, LoadCXXThis(),
- Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset,
- /*IsReturnAdjustment*/false);
-
+void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
+ llvm::Value *Callee,
+ const ThunkInfo *Thunk) {
+ assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
+ "Please use a new CGF for this thunk");
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Adjust the 'this' pointer if necessary
+ llvm::Value *AdjustedThisPtr = Thunk ? CGM.getCXXABI().performThisAdjustment(
+ *this, LoadCXXThis(), Thunk->This)
+ : LoadCXXThis();
+
+ // Start building CallArgs.
CallArgList CallArgs;
-
- // Add our adjusted 'this' pointer.
+ QualType ThisType = MD->getThisType(getContext());
CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
- // Add the rest of the parameters.
+ if (isa<CXXDestructorDecl>(MD))
+ CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs);
+
+ // Add the rest of the arguments.
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I) {
- ParmVarDecl *param = *I;
- EmitDelegateCallArg(CallArgs, param);
- }
+ E = MD->param_end(); I != E; ++I)
+ EmitDelegateCallArg(CallArgs, *I, (*I)->getLocStart());
- // Get our callee.
- llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
- llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
#ifndef NDEBUG
const CGFunctionInfo &CallFnInfo =
CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT,
RequiredArgs::forPrototypePlus(FPT, 1));
- assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() &&
- CallFnInfo.isNoReturn() == FnInfo.isNoReturn() &&
- CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention());
+ assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
+ CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
+ CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
assert(isa<CXXDestructorDecl>(MD) || // ignore dtor return types
similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(),
- FnInfo.getReturnInfo(), FnInfo.getReturnType()));
- assert(CallFnInfo.arg_size() == FnInfo.arg_size());
- for (unsigned i = 0, e = FnInfo.arg_size(); i != e; ++i)
+ CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType()));
+ assert(CallFnInfo.arg_size() == CurFnInfo->arg_size());
+ for (unsigned i = 0, e = CurFnInfo->arg_size(); i != e; ++i)
assert(similar(CallFnInfo.arg_begin()[i].info,
CallFnInfo.arg_begin()[i].type,
- FnInfo.arg_begin()[i].info, FnInfo.arg_begin()[i].type));
+ CurFnInfo->arg_begin()[i].info,
+ CurFnInfo->arg_begin()[i].type));
#endif
-
+
// Determine whether we have a return value slot to use.
+ QualType ResultType =
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
- FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
!hasScalarEvaluationKind(CurFnInfo->getReturnType()))
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
- RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
+ RValue RV = EmitCall(*CurFnInfo, Callee, Slot, CallArgs, MD);
- if (!Thunk.Return.isEmpty())
- RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
+ // Consider return adjustment if we have ThunkInfo.
+ if (Thunk && !Thunk->Return.isEmpty())
+ RV = PerformReturnAdjustment(*this, ResultType, RV, *Thunk);
+ // Emit return.
if (!ResultType->isVoidType() && Slot.isNull())
CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
@@ -377,17 +338,31 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
AutoreleaseResult = false;
FinishFunction();
+}
+
+void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk) {
+ StartThunk(Fn, GD, FnInfo);
+
+ // Get our callee.
+ llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+
+ // Make the call and return the result.
+ EmitCallAndReturnForThunk(GD, Callee, &Thunk);
// Set the right linkage.
- CGM.setFunctionLinkage(MD, Fn);
+ CGM.setFunctionLinkage(GD, Fn);
// Set the right visibility.
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
setThunkVisibility(CGM, MD, Thunk, Fn);
}
-void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
- bool UseAvailableExternallyLinkage)
-{
+void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
+ bool ForVTable) {
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
// FIXME: re-use FnInfo in this computation.
@@ -425,19 +400,17 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
}
llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+ bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions();
+ bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions;
if (!ThunkFn->isDeclaration()) {
- if (UseAvailableExternallyLinkage) {
+ if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) {
// There is already a thunk emitted for this function, do nothing.
return;
}
- // If a function has a body, it should have available_externally linkage.
- assert(ThunkFn->hasAvailableExternallyLinkage() &&
- "Function should have available_externally linkage!");
-
// Change the linkage.
- CGM.setFunctionLinkage(cast<CXXMethodDecl>(GD.getDecl()), ThunkFn);
+ CGM.setFunctionLinkage(GD, ThunkFn);
return;
}
@@ -449,30 +422,34 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
// expensive/sucky at the moment, so don't generate the thunk unless
// we have to.
// FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
- if (!UseAvailableExternallyLinkage)
+ if (!UseAvailableExternallyLinkage) {
CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
+ CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
+ }
} else {
// Normal thunk body generation.
CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
+ CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
}
-
- if (UseAvailableExternallyLinkage)
- ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
}
-void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
- const ThunkInfo &Thunk) {
- // We only want to do this when building with optimizations.
- if (!CGM.getCodeGenOpts().OptimizationLevel)
+void CodeGenVTables::maybeEmitThunkForVTable(GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ // If the ABI has key functions, only the TU with the key function should emit
+ // the thunk. However, we can allow inlining of thunks if we emit them with
+ // available_externally linkage together with vtables when optimizations are
+ // enabled.
+ if (CGM.getTarget().getCXXABI().hasKeyFunctions() &&
+ !CGM.getCodeGenOpts().OptimizationLevel)
return;
// We can't emit thunks for member functions with incomplete types.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
if (!CGM.getTypes().isFuncTypeConvertible(
- cast<FunctionType>(MD->getType().getTypePtr())))
+ MD->getType()->castAs<FunctionType>()))
return;
- EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
+ emitThunk(GD, Thunk, /*ForVTable=*/true);
}
void CodeGenVTables::EmitThunks(GlobalDecl GD)
@@ -484,14 +461,18 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
return;
- const VTableContext::ThunkInfoVectorTy *ThunkInfoVector =
- VTContext.getThunkInfo(MD);
+ const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector;
+ if (MicrosoftVTContext.isValid()) {
+ ThunkInfoVector = MicrosoftVTContext->getThunkInfo(GD);
+ } else {
+ ThunkInfoVector = ItaniumVTContext.getThunkInfo(GD);
+ }
+
if (!ThunkInfoVector)
return;
for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I)
- EmitThunk(GD, (*ThunkInfoVector)[I],
- /*UseAvailableExternallyLinkage=*/false);
+ emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
}
llvm::Constant *
@@ -586,7 +567,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
VTableThunks[NextVTableThunkIndex].first == I) {
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
- MaybeEmitThunkAvailableExternally(GD, Thunk);
+ maybeEmitThunkForVTable(GD, Thunk);
Init = CGM.GetAddrOfThunk(GD, Thunk);
NextVTableThunkIndex++;
@@ -613,63 +594,18 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
return llvm::ConstantArray::get(ArrayType, Inits);
}
-llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&VTable = VTables[RD];
- if (VTable)
- return VTable;
-
- // Queue up this v-table for possible deferred emission.
- CGM.addDeferredVTable(RD);
-
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(CGM.Int8PtrTy,
- VTContext.getVTableLayout(RD).getNumVTableComponents());
-
- VTable =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType,
- llvm::GlobalValue::ExternalLinkage);
- VTable->setUnnamedAddr(true);
- return VTable;
-}
-
-void
-CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
- llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
- const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
-
- // Create and set the initializer.
- llvm::Constant *Init =
- CreateVTableInitializer(RD,
- VTLayout.vtable_component_begin(),
- VTLayout.getNumVTableComponents(),
- VTLayout.vtable_thunk_begin(),
- VTLayout.getNumVTableThunks());
- VTable->setInitializer(Init);
-
- // Set the correct linkage.
- VTable->setLinkage(Linkage);
-
- // Set the right visibility.
- CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable);
-}
-
llvm::GlobalVariable *
CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
const BaseSubobject &Base,
bool BaseIsVirtual,
llvm::GlobalVariable::LinkageTypes Linkage,
VTableAddressPointsMapTy& AddressPoints) {
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+ DI->completeClassData(Base.getBase());
+
OwningPtr<VTableLayout> VTLayout(
- VTContext.createConstructionVTableLayout(Base.getBase(),
- Base.getBaseOffset(),
- BaseIsVirtual, RD));
+ ItaniumVTContext.createConstructionVTableLayout(
+ Base.getBase(), Base.getBaseOffset(), BaseIsVirtual, RD));
// Add the address points.
AddressPoints = VTLayout->getAddressPoints();
@@ -677,9 +613,9 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// Get the mangled construction vtable name.
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().
- mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(),
- Out);
+ cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
+ .mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(),
+ Base.getBase(), Out);
Out.flush();
StringRef Name = OutName.str();
@@ -719,7 +655,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
/// Note that we only call this at the end of the translation unit.
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->getLinkage() != ExternalLinkage)
+ if (!RD->isExternallyVisible())
return llvm::GlobalVariable::InternalLinkage;
// We're at the end of the translation unit, so the current key
@@ -734,12 +670,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
switch (keyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- // When compiling with optimizations turned on, we emit all vtables,
- // even if the key function is not defined in the current translation
- // unit. If this is the case, use available_externally linkage.
- if (!def && CodeGenOpts.OptimizationLevel)
- return llvm::GlobalVariable::AvailableExternallyLinkage;
-
+ assert(def && "Should not have been asked to emit this");
if (keyFunction->isInlined())
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
@@ -758,9 +689,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
llvm::Function::InternalLinkage;
case TSK_ExplicitInstantiationDeclaration:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::AvailableExternallyLinkage :
- llvm::Function::InternalLinkage;
+ llvm_unreachable("Should not have been asked to emit this");
}
}
@@ -776,7 +705,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return llvm::GlobalVariable::LinkOnceODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
- return llvm::GlobalVariable::AvailableExternallyLinkage;
+ llvm_unreachable("Should not have been asked to emit this");
case TSK_ExplicitInstantiationDefinition:
return llvm::GlobalVariable::WeakODRLinkage;
@@ -803,35 +732,13 @@ void CodeGenModule::EmitVTable(CXXRecordDecl *theClass, bool isRequired) {
void
CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
- // First off, check whether we've already emitted the v-table and
- // associated stuff.
- llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);
- if (VTable->hasInitializer())
- return;
-
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
- EmitVTableDefinition(VTable, Linkage, RD);
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+ DI->completeClassData(RD);
- if (RD->getNumVBases()) {
- if (!CGM.getTarget().getCXXABI().isMicrosoft()) {
- llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
- EmitVTTDefinition(VTT, Linkage, RD);
- } else {
- // FIXME: Emit vbtables here.
- }
- }
+ if (RD->getNumVBases())
+ CGM.getCXXABI().emitVirtualInheritanceTables(RD);
- // If this is the magic class __cxxabiv1::__fundamental_type_info,
- // we will emit the typeinfo for the fundamental types. This is the
- // same behaviour as GCC.
- const DeclContext *DC = RD->getDeclContext();
- if (RD->getIdentifier() &&
- RD->getIdentifier()->isStr("__fundamental_type_info") &&
- isa<NamespaceDecl>(DC) &&
- cast<NamespaceDecl>(DC)->getIdentifier() &&
- cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
- DC->getParent()->isTranslationUnit())
- CGM.EmitFundamentalRTTIDescriptors();
+ CGM.getCXXABI().emitVTableDefinitions(*this, RD);
}
/// At this point in the translation unit, does it appear that can we
@@ -875,16 +782,6 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
/// we define that v-table?
static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
const CXXRecordDecl *RD) {
- // If we're building with optimization, we always emit v-tables
- // since that allows for virtual function calls to be devirtualized.
- // If the v-table is defined strongly elsewhere, this definition
- // will be emitted available_externally.
- //
- // However, we don't want to do this in -fapple-kext mode, because
- // kext mode does not permit devirtualization.
- if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
- return true;
-
return !CGM.getVTables().isVTableExternal(RD);
}
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index bd3bdb13583d..e8cd55eed80a 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -31,10 +31,10 @@ namespace CodeGen {
class CodeGenVTables {
CodeGenModule &CGM;
- VTableContext VTContext;
-
- /// VTables - All the vtables which have been defined.
- llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
+ // FIXME: Consider moving ItaniumVTContext and MicrosoftVTContext into
+ // respective CXXABI classes?
+ ItaniumVTableContext ItaniumVTContext;
+ OwningPtr<MicrosoftVTableContext> MicrosoftVTContext;
/// VTableAddressPointsMapTy - Address points for a single vtable.
typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
@@ -52,16 +52,14 @@ class CodeGenVTables {
/// indices.
SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
- /// EmitThunk - Emit a single thunk.
- void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
- bool UseAvailableExternallyLinkage);
+ /// emitThunk - Emit a single thunk.
+ void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable);
- /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
- /// available_externally linkage to allow for inlining of thunks.
- /// This will be done iff optimizations are enabled and the member function
- /// doesn't contain any incomplete types.
- void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
+ /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by
+ /// the ABI.
+ void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk);
+public:
/// CreateVTableInitializer - Create a vtable initializer for the given record
/// decl.
/// \param Components - The vtable components; this is really an array of
@@ -72,15 +70,13 @@ class CodeGenVTables {
const VTableLayout::VTableThunkTy *VTableThunks,
unsigned NumVTableThunks);
-public:
CodeGenVTables(CodeGenModule &CGM);
- VTableContext &getVTableContext() { return VTContext; }
+ ItaniumVTableContext &getItaniumVTableContext() { return ItaniumVTContext; }
- /// needsVTTParameter - Return whether the given global decl needs a VTT
- /// parameter, which it does if it's a base constructor or destructor with
- /// virtual bases.
- static bool needsVTTParameter(GlobalDecl GD);
+ MicrosoftVTableContext &getMicrosoftVTableContext() {
+ return *MicrosoftVTContext.get();
+ }
/// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
/// given record decl.
@@ -95,14 +91,6 @@ public:
/// class decl.
uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD);
- /// GetAddrOfVTable - Get the address of the vtable for the given record decl.
- llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD);
-
- /// EmitVTableDefinition - Emit the definition of the given vtable.
- void EmitVTableDefinition(llvm::GlobalVariable *VTable,
- llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD);
-
/// GenerateConstructionVTable - Generate a construction vtable for the given
/// base subobject.
llvm::GlobalVariable *
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index b625b866c072..da2a03437d3d 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -381,23 +381,11 @@ class AggValueSlot {
/// evaluating an expression which constructs such an object.
bool AliasedFlag : 1;
- /// ValueOfAtomicFlag - This is set to true if the slot is the value
- /// subobject of an object the size of an _Atomic(T). The specific
- /// guarantees this makes are:
- /// - the address is guaranteed to be a getelementptr into the
- /// padding struct and
- /// - it is okay to store something the width of an _Atomic(T)
- /// into the address.
- /// Tracking this allows us to avoid some obviously unnecessary
- /// memcpys.
- bool ValueOfAtomicFlag : 1;
-
public:
enum IsAliased_t { IsNotAliased, IsAliased };
enum IsDestructed_t { IsNotDestructed, IsDestructed };
enum IsZeroed_t { IsNotZeroed, IsZeroed };
enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
- enum IsValueOfAtomic_t { IsNotValueOfAtomic, IsValueOfAtomic };
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
@@ -421,9 +409,7 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed,
- IsValueOfAtomic_t isValueOfAtomic
- = IsNotValueOfAtomic) {
+ IsZeroed_t isZeroed = IsNotZeroed) {
AggValueSlot AV;
AV.Addr = addr;
AV.Alignment = align.getQuantity();
@@ -432,7 +418,6 @@ public:
AV.ObjCGCFlag = needsGC;
AV.ZeroedFlag = isZeroed;
AV.AliasedFlag = isAliased;
- AV.ValueOfAtomicFlag = isValueOfAtomic;
return AV;
}
@@ -440,12 +425,9 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed,
- IsValueOfAtomic_t isValueOfAtomic
- = IsNotValueOfAtomic) {
+ IsZeroed_t isZeroed = IsNotZeroed) {
return forAddr(LV.getAddress(), LV.getAlignment(),
- LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed,
- isValueOfAtomic);
+ LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
}
IsDestructed_t isExternallyDestructed() const {
@@ -477,12 +459,6 @@ public:
return Addr;
}
- IsValueOfAtomic_t isValueOfAtomic() const {
- return IsValueOfAtomic_t(ValueOfAtomicFlag);
- }
-
- llvm::Value *getPaddedAtomicAddr() const;
-
bool isIgnored() const {
return Addr == 0;
}
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 9ca2295a9229..83dbbf0d3460 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -41,6 +41,7 @@ add_clang_library(clangCodeGen
CGStmt.cpp
CGVTables.cpp
CGVTT.cpp
+ CodeGenABITypes.cpp
CodeGenAction.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
@@ -48,6 +49,7 @@ add_clang_library(clangCodeGen
CodeGenTypes.cpp
ItaniumCXXABI.cpp
MicrosoftCXXABI.cpp
+ MicrosoftVBTables.cpp
ModuleBuilder.cpp
TargetInfo.cpp
)
diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp
new file mode 100644
index 000000000000..18c836cf2f4c
--- /dev/null
+++ b/lib/CodeGen/CodeGenABITypes.cpp
@@ -0,0 +1,69 @@
+//==--- CodeGenABITypes.cpp - Convert Clang types to LLVM types for ABI ----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CodeGenABITypes is a simple interface for getting LLVM types for
+// the parameters and the return value of a function given the Clang
+// types.
+//
+// The class is implemented as a public wrapper around the private
+// CodeGenTypes class in lib/CodeGen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGen/CodeGenABITypes.h"
+
+#include "clang/CodeGen/CGFunctionInfo.h"
+#include "CodeGenModule.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+CodeGenABITypes::CodeGenABITypes(ASTContext &C,
+ const CodeGenOptions &CodeGenOpts,
+ llvm::Module &M,
+ const llvm::DataLayout &TD,
+ DiagnosticsEngine &Diags)
+ : CGM(new CodeGen::CodeGenModule(C, CodeGenOpts, M, TD, Diags)) {
+}
+
+CodeGenABITypes::~CodeGenABITypes()
+{
+ delete CGM;
+}
+
+const CGFunctionInfo &
+CodeGenABITypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
+ QualType receiverType) {
+ return CGM->getTypes().arrangeObjCMessageSendSignature(MD, receiverType);
+}
+
+const CGFunctionInfo &
+CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty) {
+ return CGM->getTypes().arrangeFreeFunctionType(Ty);
+}
+
+const CGFunctionInfo &
+CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty) {
+ return CGM->getTypes().arrangeFreeFunctionType(Ty);
+}
+
+const CGFunctionInfo &
+CodeGenABITypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP) {
+ return CGM->getTypes().arrangeCXXMethodType(RD, FTP);
+}
+
+const CGFunctionInfo &
+CodeGenABITypes::arrangeLLVMFunctionInfo(CanQualType returnType,
+ llvm::ArrayRef<CanQualType> argTypes,
+ FunctionType::ExtInfo info,
+ RequiredArgs args) {
+ return CGM->getTypes().arrangeLLVMFunctionInfo(returnType, argTypes,
+ info, args);
+}
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 679cfeb6ed3c..3072204c9b66 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -171,6 +171,10 @@ namespace clang {
Gen->HandleTagDeclDefinition(D);
}
+ virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {
+ Gen->HandleTagDeclRequiredDefinition(D);
+ }
+
virtual void CompleteTentativeDefinition(VarDecl *D) {
Gen->CompleteTentativeDefinition(D);
}
@@ -179,6 +183,19 @@ namespace clang {
Gen->HandleVTable(RD, DefinitionRequired);
}
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ Gen->HandleLinkerOptionPragma(Opts);
+ }
+
+ virtual void HandleDetectMismatch(llvm::StringRef Name,
+ llvm::StringRef Value) {
+ Gen->HandleDetectMismatch(Name, Value);
+ }
+
+ virtual void HandleDependentLibrary(llvm::StringRef Opts) {
+ Gen->HandleDependentLibrary(Opts);
+ }
+
static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
unsigned LocCookie) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 75c60edbba53..ce1b44559dcc 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -16,12 +16,14 @@
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/OpenCL.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
@@ -31,25 +33,23 @@ using namespace clang;
using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
- : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
- Builder(cgm.getModule().getContext()),
- SanitizePerformTypeCheck(CGM.getSanOpts().Null |
- CGM.getSanOpts().Alignment |
- CGM.getSanOpts().ObjectSize |
- CGM.getSanOpts().Vptr),
- SanOpts(&CGM.getSanOpts()),
- AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
- LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
- FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
- DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
- DidCallStackSave(false),
- IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
- NumReturnExprs(0), NumSimpleReturnExprs(0),
- CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
- CXXDefaultInitExprThis(0),
- CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
- OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
- TerminateHandler(0), TrapBB(0) {
+ : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
+ Builder(cgm.getModule().getContext()), CapturedStmtInfo(0),
+ SanitizePerformTypeCheck(CGM.getSanOpts().Null |
+ CGM.getSanOpts().Alignment |
+ CGM.getSanOpts().ObjectSize |
+ CGM.getSanOpts().Vptr),
+ SanOpts(&CGM.getSanOpts()), AutoreleaseResult(false), BlockInfo(0),
+ BlockPointer(0), LambdaThisCaptureField(0), NormalCleanupDest(0),
+ NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0),
+ ExceptionSlot(0), EHSelectorSlot(0), DebugInfo(CGM.getModuleDebugInfo()),
+ DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(0),
+ SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), NumReturnExprs(0),
+ NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0),
+ CXXThisValue(0), CXXDefaultInitExprThis(0),
+ CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
+ OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
+ TerminateHandler(0), TrapBB(0) {
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
@@ -64,6 +64,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
}
CodeGenFunction::~CodeGenFunction() {
+ assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
+
// If there are any unclaimed block infos, go ahead and destroy them
// now. This can happen if IR-gen gets clever and skips evaluating
// something.
@@ -189,15 +191,23 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
"mismatched push/pop in break/continue stack!");
bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
- && NumSimpleReturnExprs == NumReturnExprs;
- // If the function contains only a simple return statement, the
- // cleanup code may become the first breakpoint in the function. To
- // be safe, set the debug location for it to the location of the
- // return statement. Otherwise point it to end of the function's
- // lexical scope.
+ && NumSimpleReturnExprs == NumReturnExprs
+ && ReturnBlock.getBlock()->use_empty();
+ // Usually the return expression is evaluated before the cleanup
+ // code. If the function contains only a simple return statement,
+ // such as a constant, the location before the cleanup code becomes
+ // the last useful breakpoint in the function, because the simple
+ // return expression will be evaluated after the cleanup code. To be
+ // safe, set the debug location for cleanup code to the location of
+ // the return statement. Otherwise the cleanup code should be at the
+ // end of the function's lexical scope.
+ //
+ // If there are multiple branches to the return block, the branch
+ // instructions will get the location of the return statements and
+ // all will be fine.
if (CGDebugInfo *DI = getDebugInfo()) {
if (OnlySimpleReturnStmts)
- DI->EmitLocation(Builder, LastStopPoint);
+ DI->EmitLocation(Builder, LastStopPoint);
else
DI->EmitLocation(Builder, EndLoc);
}
@@ -208,7 +218,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// edges will be *really* confused.
bool EmitRetDbgLoc = true;
if (EHStack.stable_begin() != PrologueCleanupDepth) {
- PopCleanupBlocks(PrologueCleanupDepth, EndLoc);
+ PopCleanupBlocks(PrologueCleanupDepth);
// Make sure the line table doesn't jump back into the body for
// the ret after it's been at EndLoc.
@@ -230,7 +240,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
DI->EmitFunctionEnd(Builder);
}
- EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc);
+ EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc, EndLoc);
EmitEndEHSpec(CurCodeDecl);
assert(EHStack.empty() &&
@@ -511,6 +521,22 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
EmitOpenCLKernelMetadata(FD, Fn);
}
+ // If we are checking function types, emit a function type signature as
+ // prefix data.
+ if (getLangOpts().CPlusPlus && SanOpts->Function) {
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (llvm::Constant *PrefixSig =
+ CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
+ llvm::Constant *FTRTTIConst =
+ CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true);
+ llvm::Constant *PrefixStructElems[] = { PrefixSig, FTRTTIConst };
+ llvm::Constant *PrefixStructConst =
+ llvm::ConstantStruct::getAnon(PrefixStructElems, /*Packed=*/true);
+ Fn->setPrefixData(PrefixStructConst);
+ }
+ }
+ }
+
llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
// Create a marker to make it easy to insert allocas into the entryblock
@@ -583,7 +609,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
if (LambdaThisCaptureField) {
// If this lambda captures this, load it.
LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField);
- CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
+ CXXThisValue = EmitLoadOfLValue(ThisLValue,
+ SourceLocation()).getScalarVal();
}
} else {
// Not in a lambda; just use 'this' from the method.
@@ -616,13 +643,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
DI->EmitLocation(Builder, StartLoc);
}
-void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
- const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
- assert(FD->getBody());
- if (const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody()))
+void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args,
+ const Stmt *Body) {
+ if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
EmitCompoundStmtWithoutScope(*S);
else
- EmitStmt(FD->getBody());
+ EmitStmt(Body);
}
/// Tries to mark the given function nounwind based on the
@@ -645,30 +671,42 @@ static void TryMarkNoThrow(llvm::Function *F) {
F->setDoesNotThrow();
}
+static void EmitSizedDeallocationFunction(CodeGenFunction &CGF,
+ const FunctionDecl *UnsizedDealloc) {
+ // This is a weak discardable definition of the sized deallocation function.
+ CGF.CurFn->setLinkage(llvm::Function::LinkOnceAnyLinkage);
+
+ // Call the unsized deallocation function and forward the first argument
+ // unchanged.
+ llvm::Constant *Unsized = CGF.CGM.GetAddrOfFunction(UnsizedDealloc);
+ CGF.Builder.CreateCall(Unsized, &*CGF.CurFn->arg_begin());
+}
+
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
- if (!FD->hasAttr<NoDebugAttr>())
- maybeInitializeDebugInfo();
+ if (FD->hasAttr<NoDebugAttr>())
+ DebugInfo = NULL; // disable debug info indefinitely for this function
FunctionArgList Args;
QualType ResTy = FD->getResultType();
CurGD = GD;
- if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
+ const CXXMethodDecl *MD;
+ if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
+ if (CGM.getCXXABI().HasThisReturn(GD))
+ ResTy = MD->getThisType(getContext());
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
+ }
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
Args.push_back(FD->getParamDecl(i));
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
-
- // CalleeWithThisReturn keeps track of the last callee inside this function
- // that returns 'this'. Before starting the function, we set it to null.
- CalleeWithThisReturn = 0;
+ CurEHLocation = BodyRange.getEnd();
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -689,17 +727,24 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitLambdaToBlockPointerBody(Args);
} else if (isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
- // The lambda "__invoke" function is special, because it forwards or
+ // 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));
} else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
- cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator()) {
+ (cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() ||
+ cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator())) {
// Implicit copy-assignment gets the same special treatment as implicit
// copy-constructors.
emitImplicitAssignmentOperatorBody(Args);
- }
- else
- EmitFunctionBody(Args);
+ } else if (Stmt *Body = FD->getBody()) {
+ EmitFunctionBody(Args, Body);
+ } else if (FunctionDecl *UnsizedDealloc =
+ FD->getCorrespondingUnsizedGlobalDeallocationFunction()) {
+ // Global sized deallocation functions get an implicit weak definition if
+ // they don't have an explicit definition.
+ EmitSizedDeallocationFunction(*this, UnsizedDealloc);
+ } else
+ llvm_unreachable("no definition for emitted function");
// C++11 [stmt.return]p2:
// Flowing off the end of a function [...] results in undefined behavior in
@@ -721,9 +766,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
- // CalleeWithThisReturn keeps track of the last callee inside this function
- // that returns 'this'. After finishing the function, we set it to null.
- CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
@@ -945,9 +987,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
-void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
- bool OmitOnError) {
- CGM.ErrorUnsupported(S, Type, OmitOnError);
+void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type) {
+ CGM.ErrorUnsupported(S, Type);
}
/// emitNonZeroVLAInit - Emit the "zero" initialization of a
@@ -1267,6 +1308,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::ObjCObjectPointer:
llvm_unreachable("type class is never variably-modified!");
+ case Type::Decayed:
+ type = cast<DecayedType>(ty)->getPointeeType();
+ break;
+
case Type::Pointer:
type = cast<PointerType>(ty)->getPointeeType();
break;
@@ -1338,6 +1383,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::UnaryTransform:
case Type::Attributed:
case Type::SubstTemplateTypeParm:
+ case Type::PackExpansion:
// Keep walking after single level desugaring.
type = type.getSingleStepDesugaredType(getContext());
break;
@@ -1447,3 +1493,5 @@ llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
return V;
}
+
+CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { }
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index ff74c15c38c3..db291e3b1ddd 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -17,12 +17,14 @@
#include "CGBuilder.h"
#include "CGDebugInfo.h"
#include "CGValue.h"
+#include "EHScopeStack.h"
#include "CodeGenModule.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
+#include "clang/Basic/CapturedStmt.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/ArrayRef.h"
@@ -89,457 +91,6 @@ enum TypeEvaluationKind {
TEK_Aggregate
};
-/// A branch fixup. These are required when emitting a goto to a
-/// label which hasn't been emitted yet. The goto is optimistically
-/// emitted as a branch to the basic block for the label, and (if it
-/// occurs in a scope with non-trivial cleanups) a fixup is added to
-/// the innermost cleanup. When a (normal) cleanup is popped, any
-/// unresolved fixups in that scope are threaded through the cleanup.
-struct BranchFixup {
- /// The block containing the terminator which needs to be modified
- /// into a switch if this fixup is resolved into the current scope.
- /// If null, LatestBranch points directly to the destination.
- llvm::BasicBlock *OptimisticBranchBlock;
-
- /// The ultimate destination of the branch.
- ///
- /// This can be set to null to indicate that this fixup was
- /// successfully resolved.
- llvm::BasicBlock *Destination;
-
- /// The destination index value.
- unsigned DestinationIndex;
-
- /// The initial branch of the fixup.
- llvm::BranchInst *InitialBranch;
-};
-
-template <class T> struct InvariantValue {
- typedef T type;
- typedef T saved_type;
- static bool needsSaving(type value) { return false; }
- static saved_type save(CodeGenFunction &CGF, type value) { return value; }
- static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
-};
-
-/// A metaprogramming class for ensuring that a value will dominate an
-/// arbitrary position in a function.
-template <class T> struct DominatingValue : InvariantValue<T> {};
-
-template <class T, bool mightBeInstruction =
- llvm::is_base_of<llvm::Value, T>::value &&
- !llvm::is_base_of<llvm::Constant, T>::value &&
- !llvm::is_base_of<llvm::BasicBlock, T>::value>
-struct DominatingPointer;
-template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
-// template <class T> struct DominatingPointer<T,true> at end of file
-
-template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
-
-enum CleanupKind {
- EHCleanup = 0x1,
- NormalCleanup = 0x2,
- NormalAndEHCleanup = EHCleanup | NormalCleanup,
-
- InactiveCleanup = 0x4,
- InactiveEHCleanup = EHCleanup | InactiveCleanup,
- InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
- InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup
-};
-
-/// A stack of scopes which respond to exceptions, including cleanups
-/// and catch blocks.
-class EHScopeStack {
-public:
- /// A saved depth on the scope stack. This is necessary because
- /// pushing scopes onto the stack invalidates iterators.
- class stable_iterator {
- friend class EHScopeStack;
-
- /// Offset from StartOfData to EndOfBuffer.
- ptrdiff_t Size;
-
- stable_iterator(ptrdiff_t Size) : Size(Size) {}
-
- public:
- static stable_iterator invalid() { return stable_iterator(-1); }
- stable_iterator() : Size(-1) {}
-
- bool isValid() const { return Size >= 0; }
-
- /// Returns true if this scope encloses I.
- /// Returns false if I is invalid.
- /// This scope must be valid.
- bool encloses(stable_iterator I) const { return Size <= I.Size; }
-
- /// Returns true if this scope strictly encloses I: that is,
- /// if it encloses I and is not I.
- /// Returns false is I is invalid.
- /// This scope must be valid.
- bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; }
-
- friend bool operator==(stable_iterator A, stable_iterator B) {
- return A.Size == B.Size;
- }
- friend bool operator!=(stable_iterator A, stable_iterator B) {
- return A.Size != B.Size;
- }
- };
-
- /// Information for lazily generating a cleanup. Subclasses must be
- /// POD-like: cleanups will not be destructed, and they will be
- /// allocated on the cleanup stack and freely copied and moved
- /// around.
- ///
- /// Cleanup implementations should generally be declared in an
- /// anonymous namespace.
- class Cleanup {
- // Anchor the construction vtable.
- virtual void anchor();
- public:
- /// Generation flags.
- class Flags {
- enum {
- F_IsForEH = 0x1,
- F_IsNormalCleanupKind = 0x2,
- F_IsEHCleanupKind = 0x4
- };
- unsigned flags;
-
- public:
- Flags() : flags(0) {}
-
- /// isForEH - true if the current emission is for an EH cleanup.
- bool isForEHCleanup() const { return flags & F_IsForEH; }
- bool isForNormalCleanup() const { return !isForEHCleanup(); }
- void setIsForEHCleanup() { flags |= F_IsForEH; }
-
- bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
- void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
-
- /// isEHCleanupKind - true if the cleanup was pushed as an EH
- /// cleanup.
- bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
- void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
- };
-
- // Provide a virtual destructor to suppress a very common warning
- // that unfortunately cannot be suppressed without this. Cleanups
- // should not rely on this destructor ever being called.
- virtual ~Cleanup() {}
-
- /// Emit the cleanup. For normal cleanups, this is run in the
- /// same EH context as when the cleanup was pushed, i.e. the
- /// immediately-enclosing context of the cleanup scope. For
- /// EH cleanups, this is run in a terminate context.
- ///
- // \param flags cleanup kind.
- virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
- };
-
- /// ConditionalCleanupN stores the saved form of its N parameters,
- /// then restores them and performs the cleanup.
- template <class T, class A0>
- class ConditionalCleanup1 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- A0_saved a0_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- T(a0).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup1(A0_saved a0)
- : a0_saved(a0) {}
- };
-
- template <class T, class A0, class A1>
- class ConditionalCleanup2 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- T(a0, a1).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup2(A0_saved a0, A1_saved a1)
- : a0_saved(a0), a1_saved(a1) {}
- };
-
- template <class T, class A0, class A1, class A2>
- class ConditionalCleanup3 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- typedef typename DominatingValue<A2>::saved_type A2_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
- A2_saved a2_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
- T(a0, a1, a2).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2)
- : a0_saved(a0), a1_saved(a1), a2_saved(a2) {}
- };
-
- template <class T, class A0, class A1, class A2, class A3>
- class ConditionalCleanup4 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- typedef typename DominatingValue<A2>::saved_type A2_saved;
- typedef typename DominatingValue<A3>::saved_type A3_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
- A2_saved a2_saved;
- A3_saved a3_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
- A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
- T(a0, a1, a2, a3).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3)
- : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {}
- };
-
-private:
- // The implementation for this class is in CGException.h and
- // CGException.cpp; the definition is here because it's used as a
- // member of CodeGenFunction.
-
- /// The start of the scope-stack buffer, i.e. the allocated pointer
- /// for the buffer. All of these pointers are either simultaneously
- /// null or simultaneously valid.
- char *StartOfBuffer;
-
- /// The end of the buffer.
- char *EndOfBuffer;
-
- /// The first valid entry in the buffer.
- char *StartOfData;
-
- /// The innermost normal cleanup on the stack.
- stable_iterator InnermostNormalCleanup;
-
- /// The innermost EH scope on the stack.
- stable_iterator InnermostEHScope;
-
- /// The current set of branch fixups. A branch fixup is a jump to
- /// an as-yet unemitted label, i.e. a label for which we don't yet
- /// know the EH stack depth. Whenever we pop a cleanup, we have
- /// to thread all the current branch fixups through it.
- ///
- /// Fixups are recorded as the Use of the respective branch or
- /// switch statement. The use points to the final destination.
- /// When popping out of a cleanup, these uses are threaded through
- /// the cleanup and adjusted to point to the new cleanup.
- ///
- /// Note that branches are allowed to jump into protected scopes
- /// in certain situations; e.g. the following code is legal:
- /// struct A { ~A(); }; // trivial ctor, non-trivial dtor
- /// goto foo;
- /// A a;
- /// foo:
- /// bar();
- SmallVector<BranchFixup, 8> BranchFixups;
-
- char *allocate(size_t Size);
-
- void *pushCleanup(CleanupKind K, size_t DataSize);
-
-public:
- EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0),
- InnermostNormalCleanup(stable_end()),
- InnermostEHScope(stable_end()) {}
- ~EHScopeStack() { delete[] StartOfBuffer; }
-
- // Variadic templates would make this not terrible.
-
- /// Push a lazily-created cleanup on the stack.
- template <class T>
- void pushCleanup(CleanupKind Kind) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T();
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class A0>
- void pushCleanup(CleanupKind Kind, A0 a0) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T(a0);
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class A0, class A1>
- void pushCleanup(CleanupKind Kind, A0 a0, A1 a1) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T(a0, a1);
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class A0, class A1, class A2>
- void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T(a0, a1, a2);
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class A0, class A1, class A2, class A3>
- void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3);
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class A0, class A1, class A2, class A3, class A4>
- void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3, a4);
- (void) Obj;
- }
-
- // Feel free to add more variants of the following:
-
- /// Push a cleanup with non-constant storage requirements on the
- /// stack. The cleanup type must provide an additional static method:
- /// static size_t getExtraSize(size_t);
- /// The argument to this method will be the value N, which will also
- /// be passed as the first argument to the constructor.
- ///
- /// The data stored in the extra storage must obey the same
- /// restrictions as normal cleanup member data.
- ///
- /// The pointer returned from this method is valid until the cleanup
- /// stack is modified.
- template <class T, class A0, class A1, class A2>
- T *pushCleanupWithExtra(CleanupKind Kind, size_t N, A0 a0, A1 a1, A2 a2) {
- void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N));
- return new (Buffer) T(N, a0, a1, a2);
- }
-
- /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp.
- void popCleanup();
-
- /// Push a set of catch handlers on the stack. The catch is
- /// uninitialized and will need to have the given number of handlers
- /// set on it.
- class EHCatchScope *pushCatch(unsigned NumHandlers);
-
- /// Pops a catch scope off the stack. This is private to CGException.cpp.
- void popCatch();
-
- /// Push an exceptions filter on the stack.
- class EHFilterScope *pushFilter(unsigned NumFilters);
-
- /// Pops an exceptions filter off the stack.
- void popFilter();
-
- /// Push a terminate handler on the stack.
- void pushTerminate();
-
- /// Pops a terminate handler off the stack.
- void popTerminate();
-
- /// Determines whether the exception-scopes stack is empty.
- bool empty() const { return StartOfData == EndOfBuffer; }
-
- bool requiresLandingPad() const {
- return InnermostEHScope != stable_end();
- }
-
- /// Determines whether there are any normal cleanups on the stack.
- bool hasNormalCleanups() const {
- return InnermostNormalCleanup != stable_end();
- }
-
- /// Returns the innermost normal cleanup on the stack, or
- /// stable_end() if there are no normal cleanups.
- stable_iterator getInnermostNormalCleanup() const {
- return InnermostNormalCleanup;
- }
- stable_iterator getInnermostActiveNormalCleanup() const;
-
- stable_iterator getInnermostEHScope() const {
- return InnermostEHScope;
- }
-
- stable_iterator getInnermostActiveEHScope() const;
-
- /// An unstable reference to a scope-stack depth. Invalidated by
- /// pushes but not pops.
- class iterator;
-
- /// Returns an iterator pointing to the innermost EH scope.
- iterator begin() const;
-
- /// Returns an iterator pointing to the outermost EH scope.
- iterator end() const;
-
- /// Create a stable reference to the top of the EH stack. The
- /// returned reference is valid until that scope is popped off the
- /// stack.
- stable_iterator stable_begin() const {
- return stable_iterator(EndOfBuffer - StartOfData);
- }
-
- /// Create a stable reference to the bottom of the EH stack.
- static stable_iterator stable_end() {
- return stable_iterator(0);
- }
-
- /// Translates an iterator into a stable_iterator.
- stable_iterator stabilize(iterator it) const;
-
- /// Turn a stable reference to a scope depth into a unstable pointer
- /// to the EH stack.
- iterator find(stable_iterator save) const;
-
- /// Removes the cleanup pointed to by the given stable_iterator.
- void removeCleanup(stable_iterator save);
-
- /// Add a branch fixup to the current cleanup scope.
- BranchFixup &addBranchFixup() {
- assert(hasNormalCleanups() && "adding fixup in scope without cleanups");
- BranchFixups.push_back(BranchFixup());
- return BranchFixups.back();
- }
-
- unsigned getNumBranchFixups() const { return BranchFixups.size(); }
- BranchFixup &getBranchFixup(unsigned I) {
- assert(I < getNumBranchFixups());
- return BranchFixups[I];
- }
-
- /// Pops lazily-removed fixups from the end of the list. This
- /// should only be called by procedures which have just popped a
- /// cleanup or resolved one or more fixups.
- void popNullFixups();
-
- /// Clears the branch-fixups list. This should only be called by
- /// ResolveAllBranchFixups.
- void clearFixups() { BranchFixups.clear(); }
-};
-
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache {
@@ -606,6 +157,65 @@ public:
/// we prefer to insert allocas.
llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
+ /// \brief API for captured statement code generation.
+ class CGCapturedStmtInfo {
+ public:
+ explicit CGCapturedStmtInfo(const CapturedStmt &S,
+ CapturedRegionKind K = CR_Default)
+ : Kind(K), ThisValue(0), CXXThisFieldDecl(0) {
+
+ RecordDecl::field_iterator Field =
+ S.getCapturedRecordDecl()->field_begin();
+ for (CapturedStmt::const_capture_iterator I = S.capture_begin(),
+ E = S.capture_end();
+ I != E; ++I, ++Field) {
+ if (I->capturesThis())
+ CXXThisFieldDecl = *Field;
+ else
+ CaptureFields[I->getCapturedVar()] = *Field;
+ }
+ }
+
+ virtual ~CGCapturedStmtInfo();
+
+ CapturedRegionKind getKind() const { return Kind; }
+
+ void setContextValue(llvm::Value *V) { ThisValue = V; }
+ // \brief Retrieve the value of the context parameter.
+ llvm::Value *getContextValue() const { return ThisValue; }
+
+ /// \brief Lookup the captured field decl for a variable.
+ const FieldDecl *lookup(const VarDecl *VD) const {
+ return CaptureFields.lookup(VD);
+ }
+
+ bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != 0; }
+ FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
+
+ /// \brief Emit the captured statement body.
+ virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) {
+ CGF.EmitStmt(S);
+ }
+
+ /// \brief Get the name of the capture helper.
+ virtual StringRef getHelperName() const { return "__captured_stmt"; }
+
+ private:
+ /// \brief The kind of captured statement being generated.
+ CapturedRegionKind Kind;
+
+ /// \brief Keep the map between VarDecl and FieldDecl.
+ llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+
+ /// \brief The base address of the captured record, passed in as the first
+ /// argument of the parallel region function.
+ llvm::Value *ThisValue;
+
+ /// \brief Captured 'this' type.
+ FieldDecl *CXXThisFieldDecl;
+ };
+ CGCapturedStmtInfo *CapturedStmtInfo;
+
/// BoundsChecking - Emit run-time bounds checks. Higher values mean
/// potentially higher performance penalties.
unsigned char BoundsChecking;
@@ -631,6 +241,18 @@ public:
llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
EHScopeStack EHStack;
+ llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
+
+ /// Header for data within LifetimeExtendedCleanupStack.
+ struct LifetimeExtendedCleanupHeader {
+ /// The size of the following cleanup object.
+ size_t Size : 29;
+ /// The kind of cleanup to push: a value from the CleanupKind enumeration.
+ unsigned Kind : 3;
+
+ size_t getSize() const { return Size; }
+ CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); }
+ };
/// i32s containing the indexes of the cleanup destinations.
llvm::AllocaInst *NormalCleanupDest;
@@ -766,6 +388,23 @@ public:
initFullExprCleanup();
}
+ /// \brief Queue a cleanup to be pushed after finishing the current
+ /// full-expression.
+ template <class T, class A0, class A1, class A2, class A3>
+ void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
+ assert(!isInConditionalBranch() && "can't defer conditional cleanup");
+
+ LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };
+
+ size_t OldSize = LifetimeExtendedCleanupStack.size();
+ LifetimeExtendedCleanupStack.resize(
+ LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size);
+
+ char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
+ new (Buffer) LifetimeExtendedCleanupHeader(Header);
+ new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);
+ }
+
/// Set up the last cleaup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup();
@@ -784,9 +423,7 @@ public:
/// PopCleanupBlock - Will pop the cleanup entry on the stack and
/// process all branch fixups.
- /// \param EHLoc - Optional debug location for EH code.
- void PopCleanupBlock(bool FallThroughIsBranchThrough = false,
- SourceLocation EHLoc=SourceLocation());
+ void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
/// DeactivateCleanupBlock - Deactivates the given cleanup block.
/// The block cannot be reactivated. Pops it if it's the top of the
@@ -813,6 +450,7 @@ public:
/// will be executed once the scope is exited.
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth;
+ size_t LifetimeExtendedCleanupStackSize;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
@@ -830,6 +468,8 @@ public:
: PerformCleanup(true), CGF(CGF)
{
CleanupStackDepth = CGF.EHStack.stable_begin();
+ LifetimeExtendedCleanupStackSize =
+ CGF.LifetimeExtendedCleanupStack.size();
OldDidCallStackSave = CGF.DidCallStackSave;
CGF.DidCallStackSave = false;
}
@@ -839,7 +479,8 @@ public:
~RunCleanupsScope() {
if (PerformCleanup) {
CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth);
+ CGF.PopCleanupBlocks(CleanupStackDepth,
+ LifetimeExtendedCleanupStackSize);
}
}
@@ -853,7 +494,8 @@ public:
void ForceCleanup() {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth);
+ CGF.PopCleanupBlocks(CleanupStackDepth,
+ LifetimeExtendedCleanupStackSize);
PerformCleanup = false;
}
};
@@ -905,11 +547,15 @@ public:
};
- /// PopCleanupBlocks - Takes the old cleanup stack size and emits
- /// the cleanup blocks that have been added.
- /// \param EHLoc - Optional debug location for EH code.
+ /// \brief Takes the old cleanup stack size and emits the cleanup blocks
+ /// that have been added.
+ void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize);
+
+ /// \brief Takes the old cleanup stack size and emits the cleanup blocks
+ /// that have been added, then adds all lifetime-extended cleanups from
+ /// the given position to the stack.
void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
- SourceLocation EHLoc=SourceLocation());
+ size_t OldLifetimeExtendedStackSize);
void ResolveBranchFixups(llvm::BasicBlock *Target);
@@ -1152,10 +798,6 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
- /// If the current function returns 'this', use the field to keep track of
- /// the callee that returns 'this'.
- llvm::Value *CalleeWithThisReturn;
-
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
@@ -1279,6 +921,10 @@ private:
/// The current lexical scope.
LexicalScope *CurLexicalScope;
+ /// The current source location that should be used for exception
+ /// handling code.
+ SourceLocation CurEHLocation;
+
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
/// type as well as the field number that contains the actual data.
llvm::DenseMap<const ValueDecl *, std::pair<llvm::Type *,
@@ -1307,14 +953,6 @@ public:
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
ASTContext &getContext() const { return CGM.getContext(); }
- /// Returns true if DebugInfo is actually initialized.
- bool maybeInitializeDebugInfo() {
- if (CGM.getModuleDebugInfo()) {
- DebugInfo = CGM.getModuleDebugInfo();
- return true;
- }
- return false;
- }
CGDebugInfo *getDebugInfo() {
if (DisableDebugInfo)
return NULL;
@@ -1378,12 +1016,15 @@ public:
llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
+ void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
+ QualType type, Destroyer *destroyer,
+ bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
- llvm::Function *generateDestroyHelper(llvm::Constant *addr,
- QualType type,
+ llvm::Function *generateDestroyHelper(llvm::Constant *addr, QualType type,
Destroyer *destroyer,
- bool useEHCleanupForArray);
+ bool useEHCleanupForArray,
+ const VarDecl *VD);
void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
QualType type, Destroyer *destroyer,
bool checkZeroLength, bool useEHCleanup);
@@ -1495,9 +1136,9 @@ public:
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
- void EmitFunctionBody(FunctionArgList &Args);
+ void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body);
- void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
+ void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
void EmitLambdaBlockInvokeBody();
@@ -1512,6 +1153,11 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
+ void StartThunk(llvm::Function *Fn, GlobalDecl GD, const CGFunctionInfo &FnInfo);
+
+ void EmitCallAndReturnForThunk(GlobalDecl GD, llvm::Value *Callee,
+ const ThunkInfo *Thunk);
+
/// GenerateThunk - Generate a thunk for the given method.
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk);
@@ -1531,7 +1177,6 @@ public:
void InitializeVTablePointer(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
CharUnits OffsetFromNearestVBase,
- llvm::Constant *VTable,
const CXXRecordDecl *VTableClass);
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
@@ -1539,7 +1184,6 @@ public:
const CXXRecordDecl *NearestVBase,
CharUnits OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
- llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
VisitedVirtualBasesSetTy& VBases);
@@ -1549,6 +1193,12 @@ public:
/// to by This.
llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
+
+ /// 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
@@ -1576,7 +1226,8 @@ public:
/// EmitFunctionEpilog - Emit the target specific LLVM code to return the
/// given temporary.
- void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc);
+ void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc,
+ SourceLocation EndLoc);
/// EmitStartEHSpec - Emit the start of the exception spec.
void EmitStartEHSpec(const Decl *D);
@@ -1678,8 +1329,7 @@ public:
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
- void ErrorUnsupported(const Stmt *S, const char *Type,
- bool OmitOnError=false);
+ void ErrorUnsupported(const Stmt *S, const char *Type);
//===--------------------------------------------------------------------===//
// Helpers
@@ -1915,10 +1565,6 @@ public:
CastExpr::path_const_iterator PathEnd,
bool NullCheckValue);
- llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
-
/// GetVTTParameter - Return the VTT parameter that should be passed to a
/// base constructor/destructor with virtual bases.
/// FIXME: VTTs are Itanium ABI-specific, so the definition should move
@@ -1928,7 +1574,8 @@ public:
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
- const FunctionArgList &Args);
+ const FunctionArgList &Args,
+ SourceLocation Loc);
// It's important not to confuse this and the previous function. Delegating
// constructors are the C++0x feature. The constructor delegate optimization
// is used to reduce duplication in the base and complete consturctors where
@@ -1982,10 +1629,6 @@ public:
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E);
- void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init);
- void EmitStdInitializerListCleanup(llvm::Value *loc,
- const InitListExpr *init);
-
/// \brief Situations in which we might emit a check for the suitability of a
/// pointer or glvalue.
enum TypeCheckKind {
@@ -2161,11 +1804,12 @@ public:
/// \return True if the statement was handled.
bool EmitSimpleStmt(const Stmt *S);
- RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
- AggValueSlot AVS = AggValueSlot::ignored());
- RValue EmitCompoundStmtWithoutScope(const CompoundStmt &S,
- bool GetLast = false, AggValueSlot AVS =
- AggValueSlot::ignored());
+ llvm::Value *EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
+ AggValueSlot AVS = AggValueSlot::ignored());
+ llvm::Value *EmitCompoundStmtWithoutScope(const CompoundStmt &S,
+ bool GetLast = false,
+ AggValueSlot AVS =
+ AggValueSlot::ignored());
/// EmitLabel - Emit the block for the given label. It is legal to call this
/// function even if there is no current insertion point.
@@ -2188,7 +1832,6 @@ public:
void EmitCaseStmt(const CaseStmt &S);
void EmitCaseStmtRange(const CaseStmt &S);
void EmitAsmStmt(const AsmStmt &S);
- void EmitCapturedStmt(const CapturedStmt &S);
void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
@@ -2202,8 +1845,14 @@ public:
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void EmitCXXTryStmt(const CXXTryStmt &S);
+ void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
+ llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
+ llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD,
+ const RecordDecl *RD,
+ SourceLocation Loc);
+
//===--------------------------------------------------------------------===//
// LValue Expression Emission
//===--------------------------------------------------------------------===//
@@ -2245,11 +1894,12 @@ public:
/// that the address will be used to access the object.
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
- RValue convertTempToRValue(llvm::Value *addr, QualType type);
+ RValue convertTempToRValue(llvm::Value *addr, QualType type,
+ SourceLocation Loc);
void EmitAtomicInit(Expr *E, LValue lvalue);
- RValue EmitAtomicLoad(LValue lvalue,
+ RValue EmitAtomicLoad(LValue lvalue, SourceLocation loc,
AggValueSlot slot = AggValueSlot::ignored());
void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
@@ -2267,6 +1917,7 @@ public:
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
+ SourceLocation Loc,
llvm::MDNode *TBAAInfo = 0,
QualType TBAABaseTy = QualType(),
uint64_t TBAAOffset = 0);
@@ -2275,7 +1926,7 @@ public:
/// care to appropriately convert from the memory representation to
/// the LLVM value representation. The l-value must be a simple
/// l-value.
- llvm::Value *EmitLoadOfScalar(LValue lvalue);
+ llvm::Value *EmitLoadOfScalar(LValue lvalue, SourceLocation Loc);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
@@ -2296,7 +1947,7 @@ public:
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
/// this method emits the address of the lvalue, then loads the result as an
/// rvalue, returning the rvalue.
- RValue EmitLoadOfLValue(LValue V);
+ RValue EmitLoadOfLValue(LValue V, SourceLocation Loc);
RValue EmitLoadOfExtVectorElementLValue(LValue V);
RValue EmitLoadOfBitfieldLValue(LValue LV);
@@ -2306,8 +1957,8 @@ public:
void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
- /// EmitStoreThroughLValue - Store Src into Dst with same constraints as
- /// EmitStoreThroughLValue.
+ /// EmitStoreThroughBitfieldLValue - Store Src into Dst with same constraints
+ /// as EmitStoreThroughLValue.
///
/// \param Result [out] - If non-null, this will be set to a Value* for the
/// bit-field contents after the store, appropriate for use as the result of
@@ -2318,6 +1969,8 @@ public:
/// Emit an l-value for an assignment (simple or compound) of complex type.
LValue EmitComplexAssignmentLValue(const BinaryOperator *E);
LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E);
+ LValue EmitScalarCompooundAssignWithComplex(const CompoundAssignOperator *E,
+ llvm::Value *&Result);
// Note: only available for agg return types
LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
@@ -2340,11 +1993,10 @@ public:
LValue EmitInitListLValue(const InitListExpr *E);
LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
- LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
- RValue EmitRValueForField(LValue LV, const FieldDecl *FD);
+ RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc);
class ConstantEmission {
llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
@@ -2359,7 +2011,7 @@ public:
return ConstantEmission(C, false);
}
- operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; }
+ LLVM_EXPLICIT operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; }
bool isReference() const { return ValueAndIsReference.getInt(); }
LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const {
@@ -2426,6 +2078,7 @@ public:
llvm::Instruction **callOrInvoke = 0);
RValue EmitCall(QualType FnType, llvm::Value *Callee,
+ SourceLocation CallLoc,
ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
@@ -2457,10 +2110,6 @@ public:
void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
ArrayRef<llvm::Value*> args);
- llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
- llvm::Type *Ty);
- llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
- llvm::Value *This, llvm::Type *Ty);
llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
llvm::Type *Ty);
@@ -2503,6 +2152,11 @@ public:
/// is unhandled by the current target.
llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty,
+ const llvm::CmpInst::Predicate Fp,
+ const llvm::CmpInst::Predicate Ip,
+ const llvm::Twine &Name = "");
+ llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty);
llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitNeonCall(llvm::Function *F,
@@ -2512,6 +2166,8 @@ public:
llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx);
llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty,
bool negateForRightShift);
+ llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt,
+ llvm::Type *Ty, bool usgn, const char *name);
llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
@@ -2587,10 +2243,8 @@ public:
void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr);
void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr);
- /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
- /// expression. Will emit a temporary variable if E is not an LValue.
- RValue EmitReferenceBindingToExpr(const Expr* E,
- const NamedDecl *InitializedDecl);
+ /// \brief Emits a reference binding to the passed in expression.
+ RValue EmitReferenceBindingToExpr(const Expr *E);
//===--------------------------------------------------------------------===//
// Expression Emission
@@ -2646,7 +2300,7 @@ public:
void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
/// EmitLoadOfComplex - Load a complex number from the specified l-value.
- ComplexPairTy EmitLoadOfComplex(LValue src);
+ ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
/// a static local variable.
@@ -2670,7 +2324,8 @@ public:
/// Call atexit() with a function that passes the given argument to
/// the given function.
- void registerGlobalDtorWithAtExit(llvm::Constant *fn, llvm::Constant *addr);
+ void registerGlobalDtorWithAtExit(const VarDecl &D, llvm::Constant *fn,
+ llvm::Constant *addr);
/// Emit code in this function to perform a guarded variable
/// initialization. Guarded initializations are used when it's not
@@ -2801,7 +2456,8 @@ public:
/// EmitDelegateCallArg - We are performing a delegate call; that
/// is, the current function is delegating to another one. Produce
/// a r-value suitable for passing the given parameter.
- void EmitDelegateCallArg(CallArgList &args, const VarDecl *param);
+ void EmitDelegateCallArg(CallArgList &args, const VarDecl *param,
+ SourceLocation loc);
/// SetFPAccuracy - Set the minimum required accuracy of the given floating
/// point operation, expressed as the maximum relative error in ulp.
@@ -2825,7 +2481,7 @@ private:
/// Ty, into individual arguments on the provided vector \arg Args. See
/// ABIArgInfo::Expand.
void ExpandTypeToArgs(QualType Ty, RValue Src,
- SmallVector<llvm::Value*, 16> &Args,
+ SmallVectorImpl<llvm::Value *> &Args,
llvm::FunctionType *IRFuncTy);
llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
@@ -2833,7 +2489,8 @@ private:
llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
- std::string &ConstraintStr);
+ std::string &ConstraintStr,
+ SourceLocation Loc);
/// EmitCallArgs - Emit call arguments for a function.
/// The CallArgTypeInfo parameter is used for iterating over the known
@@ -2841,8 +2498,13 @@ private:
template<typename T>
void EmitCallArgs(CallArgList& Args, const T* CallArgTypeInfo,
CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- CallExpr::const_arg_iterator Arg = ArgBeg;
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo = false) {
+ CGDebugInfo *DI = getDebugInfo();
+ SourceLocation CallLoc;
+ if (DI) CallLoc = DI->getLocation();
+
+ CallExpr::const_arg_iterator Arg = ArgBeg;
// First, use the argument types that the type info knows about
if (CallArgTypeInfo) {
@@ -2871,6 +2533,10 @@ private:
"type mismatch in call argument!");
#endif
EmitCallArg(Args, *Arg, ArgType);
+
+ // Each argument expression could modify the debug
+ // location. Restore it.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
}
// Either we've emitted all the call args, or we have a call to a
@@ -2881,8 +2547,12 @@ private:
}
// If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg)
+ for (; Arg != ArgEnd; ++Arg) {
EmitCallArg(Args, *Arg, Arg->getType());
+
+ // Restore the debug location.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
+ }
}
const TargetCodeGenInfo &getTargetHooks() const {
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 0b03a3c4b67d..792fbfce3349 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -35,7 +35,9 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/CallingConv.h"
@@ -67,25 +69,23 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
llvm_unreachable("invalid C++ ABI kind");
}
-
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
- : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
- Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()),
- ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0),
- TheTargetCodeGenInfo(0), Types(*this), VTables(*this),
- ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
- DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0),
- RRData(0), CFConstantStringClassRef(0),
- ConstantStringClassRef(0), NSConstantStringType(0),
- NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
- BlockObjectAssign(0), BlockObjectDispose(0),
- BlockDescriptorType(0), GenericBlockLiteralType(0),
- LifetimeStartFn(0), LifetimeEndFn(0),
- SanitizerBlacklist(CGO.SanitizerBlacklistFile),
- SanOpts(SanitizerBlacklist.isIn(M) ?
- SanitizerOptions::Disabled : LangOpts.Sanitize) {
+ : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
+ Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()),
+ ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0),
+ TheTargetCodeGenInfo(0), Types(*this), VTables(*this), ObjCRuntime(0),
+ OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0),
+ NoObjCARCExceptionsMetadata(0), RRData(0), CFConstantStringClassRef(0),
+ ConstantStringClassRef(0), NSConstantStringType(0),
+ NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0),
+ BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0),
+ LifetimeStartFn(0), LifetimeEndFn(0),
+ SanitizerBlacklist(
+ llvm::SpecialCaseList::createOrDie(CGO.SanitizerBlacklistFile)),
+ SanOpts(SanitizerBlacklist->isIn(M) ? SanitizerOptions::Disabled
+ : LangOpts.Sanitize) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
@@ -172,8 +172,71 @@ void CodeGenModule::createCUDARuntime() {
CUDARuntime = CreateNVCUDARuntime(*this);
}
+void CodeGenModule::applyReplacements() {
+ for (ReplacementsTy::iterator I = Replacements.begin(),
+ E = Replacements.end();
+ I != E; ++I) {
+ StringRef MangledName = I->first();
+ llvm::Constant *Replacement = I->second;
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+ if (!Entry)
+ continue;
+ llvm::Function *OldF = cast<llvm::Function>(Entry);
+ llvm::Function *NewF = dyn_cast<llvm::Function>(Replacement);
+ if (!NewF) {
+ llvm::ConstantExpr *CE = cast<llvm::ConstantExpr>(Replacement);
+ assert(CE->getOpcode() == llvm::Instruction::BitCast ||
+ CE->getOpcode() == llvm::Instruction::GetElementPtr);
+ NewF = dyn_cast<llvm::Function>(CE->getOperand(0));
+ }
+
+ // Replace old with new, but keep the old order.
+ OldF->replaceAllUsesWith(Replacement);
+ if (NewF) {
+ NewF->removeFromParent();
+ OldF->getParent()->getFunctionList().insertAfter(OldF, NewF);
+ }
+ OldF->eraseFromParent();
+ }
+}
+
+void CodeGenModule::checkAliases() {
+ bool Error = false;
+ for (std::vector<GlobalDecl>::iterator I = Aliases.begin(),
+ E = Aliases.end(); I != E; ++I) {
+ const GlobalDecl &GD = *I;
+ const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
+ const AliasAttr *AA = D->getAttr<AliasAttr>();
+ StringRef MangledName = getMangledName(GD);
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+ llvm::GlobalAlias *Alias = cast<llvm::GlobalAlias>(Entry);
+ llvm::GlobalValue *GV = Alias->getAliasedGlobal();
+ if (GV->isDeclaration()) {
+ Error = true;
+ getDiags().Report(AA->getLocation(), diag::err_alias_to_undefined);
+ } else if (!Alias->resolveAliasedGlobal(/*stopOnWeak*/ false)) {
+ Error = true;
+ getDiags().Report(AA->getLocation(), diag::err_cyclic_alias);
+ }
+ }
+ if (!Error)
+ return;
+
+ for (std::vector<GlobalDecl>::iterator I = Aliases.begin(),
+ E = Aliases.end(); I != E; ++I) {
+ const GlobalDecl &GD = *I;
+ StringRef MangledName = getMangledName(GD);
+ llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+ llvm::GlobalAlias *Alias = cast<llvm::GlobalAlias>(Entry);
+ Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType()));
+ Alias->eraseFromParent();
+ }
+}
+
void CodeGenModule::Release() {
EmitDeferred();
+ applyReplacements();
+ checkAliases();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
EmitCXXThreadLocalInitFunc();
@@ -186,9 +249,23 @@ void CodeGenModule::Release() {
EmitStaticExternCAliases();
EmitLLVMUsed();
- if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) {
+ if (CodeGenOpts.Autolink &&
+ (Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
EmitModuleLinkOptions();
}
+ 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.
+ getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version",
+ CodeGenOpts.DwarfVersion);
+ if (DebugInfo)
+ // We support a single version in the linked module: error out when
+ // modules do not have the same version. We are going to implement dropping
+ // debug info when the version number is not up-to-date. Once that is
+ // done, the bitcode linker is not going to see modules with different
+ // version numbers.
+ getModule().addModuleFlag(llvm::Module::Error, "Debug Info Version",
+ llvm::DEBUG_METADATA_VERSION);
SimplifyPersonality();
@@ -200,6 +277,8 @@ void CodeGenModule::Release() {
if (DebugInfo)
DebugInfo->finalize();
+
+ EmitVersionIdentMetadata();
}
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -239,14 +318,14 @@ llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
}
-/// 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.
+/// 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::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo,
bool ConvertTypeToTag) {
- if (ConvertTypeToTag && TBAA && CodeGenOpts.StructPathTBAA)
+ if (ConvertTypeToTag && TBAA)
Inst->setMetadata(llvm::LLVMContext::MD_tbaa,
TBAA->getTBAAScalarTagInfo(TBAAInfo));
else
@@ -260,10 +339,7 @@ void CodeGenModule::Error(SourceLocation loc, StringRef error) {
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
-void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type,
- bool OmitOnError) {
- if (OmitOnError && getDiags().hasErrorOccurred())
- return;
+void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
@@ -273,10 +349,7 @@ void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type,
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified decl yet.
-void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type,
- bool OmitOnError) {
- if (OmitOnError && getDiags().hasErrorOccurred())
- return;
+void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
@@ -428,9 +501,6 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
else if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
- else if (const BlockDecl *BD = dyn_cast<BlockDecl>(ND))
- getCXXABI().getMangleContext().mangleBlock(BD, Out,
- dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()));
else
getCXXABI().getMangleContext().mangleName(ND, Out);
@@ -508,7 +578,14 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
}
llvm::GlobalValue::LinkageTypes
-CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
+CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
+ const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
+
+ if (isa<CXXDestructorDecl>(D) &&
+ getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
+ GD.getDtorType()))
+ return llvm::Function::LinkOnceODRLinkage;
+
GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
if (Linkage == GVA_Internal)
@@ -597,61 +674,66 @@ static bool hasUnwindExceptions(const LangOptions &LangOpts) {
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
+ llvm::AttrBuilder B;
+
if (CodeGenOpts.UnwindTables)
- F->setHasUWTable();
+ B.addAttribute(llvm::Attribute::UWTable);
if (!hasUnwindExceptions(LangOpts))
- F->addFnAttr(llvm::Attribute::NoUnwind);
+ B.addAttribute(llvm::Attribute::NoUnwind);
if (D->hasAttr<NakedAttr>()) {
// Naked implies noinline: we should not be inlining such functions.
- F->addFnAttr(llvm::Attribute::Naked);
- F->addFnAttr(llvm::Attribute::NoInline);
+ B.addAttribute(llvm::Attribute::Naked);
+ B.addAttribute(llvm::Attribute::NoInline);
+ } else if (D->hasAttr<NoInlineAttr>()) {
+ B.addAttribute(llvm::Attribute::NoInline);
+ } else if ((D->hasAttr<AlwaysInlineAttr>() ||
+ D->hasAttr<ForceInlineAttr>()) &&
+ !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoInline)) {
+ // (noinline wins over always_inline, and we can't specify both in IR)
+ B.addAttribute(llvm::Attribute::AlwaysInline);
}
- if (D->hasAttr<NoInlineAttr>())
- F->addFnAttr(llvm::Attribute::NoInline);
-
- // (noinline wins over always_inline, and we can't specify both in IR)
- if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) &&
- !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoInline))
- F->addFnAttr(llvm::Attribute::AlwaysInline);
-
- // FIXME: Communicate hot and cold attributes to LLVM more directly.
- if (D->hasAttr<ColdAttr>())
- F->addFnAttr(llvm::Attribute::OptimizeForSize);
+ if (D->hasAttr<ColdAttr>()) {
+ B.addAttribute(llvm::Attribute::OptimizeForSize);
+ B.addAttribute(llvm::Attribute::Cold);
+ }
if (D->hasAttr<MinSizeAttr>())
- F->addFnAttr(llvm::Attribute::MinSize);
-
- if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
- F->setUnnamedAddr(true);
-
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
- if (MD->isVirtual())
- F->setUnnamedAddr(true);
+ B.addAttribute(llvm::Attribute::MinSize);
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- F->addFnAttr(llvm::Attribute::StackProtect);
+ B.addAttribute(llvm::Attribute::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- F->addFnAttr(llvm::Attribute::StackProtectReq);
+ B.addAttribute(llvm::Attribute::StackProtectReq);
// Add sanitizer attributes if function is not blacklisted.
- if (!SanitizerBlacklist.isIn(*F)) {
+ if (!SanitizerBlacklist->isIn(*F)) {
// When AddressSanitizer is enabled, set SanitizeAddress attribute
// unless __attribute__((no_sanitize_address)) is used.
if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
- F->addFnAttr(llvm::Attribute::SanitizeAddress);
+ B.addAttribute(llvm::Attribute::SanitizeAddress);
// Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>()) {
- F->addFnAttr(llvm::Attribute::SanitizeThread);
+ B.addAttribute(llvm::Attribute::SanitizeThread);
}
// Same for MemorySanitizer and __attribute__((no_sanitize_memory))
if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
- F->addFnAttr(llvm::Attribute::SanitizeMemory);
+ B.addAttribute(llvm::Attribute::SanitizeMemory);
}
+ F->addAttributes(llvm::AttributeSet::FunctionIndex,
+ llvm::AttributeSet::get(
+ F->getContext(), llvm::AttributeSet::FunctionIndex, B));
+
+ if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
+ F->setUnnamedAddr(true);
+ else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
+ if (MD->isVirtual())
+ F->setUnnamedAddr(true);
+
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
F->setAlignment(alignment);
@@ -706,6 +788,14 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (!IsIncompleteFunction)
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
+ if (getCXXABI().HasThisReturn(GD)) {
+ assert(!F->arg_empty() &&
+ F->arg_begin()->getType()
+ ->canLosslesslyBitCastTo(F->getReturnType()) &&
+ "unexpected this return");
+ F->addAttribute(1, llvm::Attribute::Returned);
+ }
+
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
@@ -727,6 +817,12 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
+
+ // 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.
+ if (FD->isReplaceableGlobalAllocationFunction())
+ F->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoBuiltin);
}
void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
@@ -762,31 +858,48 @@ void CodeGenModule::EmitLLVMUsed() {
GV->setSection("llvm.metadata");
}
+void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
+ llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
+ LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
+}
+
+void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) {
+ llvm::SmallString<32> Opt;
+ getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt);
+ llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
+ LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
+}
+
+void CodeGenModule::AddDependentLib(StringRef Lib) {
+ llvm::SmallString<24> Opt;
+ getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt);
+ llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
+ LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
+}
+
/// \brief Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
-static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
+static void addLinkOptionsPostorder(CodeGenModule &CGM,
Module *Mod,
SmallVectorImpl<llvm::Value *> &Metadata,
llvm::SmallPtrSet<Module *, 16> &Visited) {
// Import this module's parent.
if (Mod->Parent && Visited.insert(Mod->Parent)) {
- addLinkOptionsPostorder(Context, Mod->Parent, Metadata, Visited);
+ addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited);
}
// Import this module's dependencies.
for (unsigned I = Mod->Imports.size(); I > 0; --I) {
if (Visited.insert(Mod->Imports[I-1]))
- addLinkOptionsPostorder(Context, Mod->Imports[I-1], Metadata, Visited);
+ addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited);
}
// Add linker options to link against the libraries/frameworks
// described by this module.
+ llvm::LLVMContext &Context = CGM.getLLVMContext();
for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
- // FIXME: -lfoo is Unix-centric and -framework Foo is Darwin-centric.
- // We need to know more about the linker to know how to encode these
- // options propertly.
-
- // Link against a framework.
+ // Link against a framework. Frameworks are currently Darwin only, so we
+ // don't to ask TargetCodeGenInfo for the spelling of the linker option.
if (Mod->LinkLibraries[I-1].IsFramework) {
llvm::Value *Args[2] = {
llvm::MDString::get(Context, "-framework"),
@@ -798,9 +911,10 @@ static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
}
// Link against a library.
- llvm::Value *OptString
- = llvm::MDString::get(Context,
- "-l" + Mod->LinkLibraries[I-1].Library);
+ llvm::SmallString<24> Opt;
+ CGM.getTargetCodeGenInfo().getDependentLibraryOption(
+ Mod->LinkLibraries[I-1].Library, Opt);
+ llvm::Value *OptString = llvm::MDString::get(Context, Opt);
Metadata.push_back(llvm::MDNode::get(Context, OptString));
}
}
@@ -824,8 +938,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
// Find all of the modules to import, making a little effort to prune
// non-leaf modules.
while (!Stack.empty()) {
- clang::Module *Mod = Stack.back();
- Stack.pop_back();
+ clang::Module *Mod = Stack.pop_back_val();
bool AnyChildren = false;
@@ -852,20 +965,23 @@ void CodeGenModule::EmitModuleLinkOptions() {
}
// Add link options for all of the imported modules in reverse topological
- // order.
+ // 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::Value *, 16> MetadataArgs;
Visited.clear();
for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(),
MEnd = LinkModules.end();
M != MEnd; ++M) {
if (Visited.insert(*M))
- addLinkOptionsPostorder(getLLVMContext(), *M, MetadataArgs, Visited);
+ addLinkOptionsPostorder(*this, *M, MetadataArgs, Visited);
}
std::reverse(MetadataArgs.begin(), MetadataArgs.end());
+ LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
// Add the linker options metadata flag.
getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
- llvm::MDNode::get(getLLVMContext(), MetadataArgs));
+ llvm::MDNode::get(getLLVMContext(),
+ LinkerOptionsMetadata));
}
void CodeGenModule::EmitDeferred() {
@@ -928,9 +1044,9 @@ void CodeGenModule::EmitGlobalAnnotations() {
}
llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
- llvm::StringMap<llvm::Constant*>::iterator i = AnnotationStrings.find(Str);
- if (i != AnnotationStrings.end())
- return i->second;
+ llvm::Constant *&AStr = AnnotationStrings[Str];
+ if (AStr)
+ return AStr;
// Not found yet, create a new global.
llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str);
@@ -938,7 +1054,7 @@ llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
true, llvm::GlobalValue::PrivateLinkage, s, ".str");
gv->setSection(AnnotationSection);
gv->setUnnamedAddr(true);
- AnnotationStrings[Str] = gv;
+ AStr = gv;
return gv;
}
@@ -998,18 +1114,9 @@ llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
const CXXUuidofExpr* E) {
// Sema has verified that IIDSource has a __declspec(uuid()), and that its
// well-formed.
- StringRef Uuid;
- if (E->isTypeOperand())
- Uuid = CXXUuidofExpr::GetUuidAttrOfType(E->getTypeOperand())->getGuid();
- else {
- // Special case: __uuidof(0) means an all-zero GUID.
- Expr *Op = E->getExprOperand();
- if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
- Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid();
- else
- Uuid = "00000000-0000-0000-0000-000000000000";
- }
- std::string Name = "__uuid_" + Uuid.str();
+ StringRef Uuid = E->getUuidAsStringRef(Context);
+ std::string Name = "_GUID_" + Uuid.lower();
+ std::replace(Name.begin(), Name.end(), '-', '_');
// Look for an existing global.
if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
@@ -1018,22 +1125,9 @@ llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType());
assert(Init && "failed to initialize as constant");
- // GUIDs are assumed to be 16 bytes, spread over 4-2-2-8 bytes. However, the
- // first field is declared as "long", which for many targets is 8 bytes.
- // Those architectures are not supported. (With the MS abi, long is always 4
- // bytes.)
- llvm::Type *GuidType = getTypes().ConvertType(E->getType());
- if (Init->getType() != GuidType) {
- DiagnosticsEngine &Diags = getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "__uuidof codegen is not supported on this architecture");
- Diags.Report(E->getExprLoc(), DiagID) << E->getSourceRange();
- Init = llvm::UndefValue::get(GuidType);
- }
-
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), GuidType,
- /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, Name);
- GV->setUnnamedAddr(true);
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+ getModule(), Init->getType(),
+ /*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name);
return GV;
}
@@ -1203,9 +1297,10 @@ CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
}
bool
-CodeGenModule::shouldEmitFunction(const FunctionDecl *F) {
- if (getFunctionLinkage(F) != llvm::Function::AvailableExternallyLinkage)
+CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
+ if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
return true;
+ const FunctionDecl *F = cast<FunctionDecl>(GD.getDecl());
if (CodeGenOpts.OptimizationLevel == 0 &&
!F->hasAttr<AlwaysInlineAttr>() && !F->hasAttr<ForceInlineAttr>())
return false;
@@ -1217,6 +1312,23 @@ CodeGenModule::shouldEmitFunction(const FunctionDecl *F) {
return !isTriviallyRecursive(F);
}
+/// If the type for the method's class was generated by
+/// CGDebugInfo::createContextChain(), the cache contains only a
+/// limited DIType without any declarations. Since EmitFunctionStart()
+/// needs to find the canonical declaration for each method, we need
+/// to construct the complete type prior to emitting the method.
+void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) {
+ if (!D->isInstance())
+ return;
+
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
+ const PointerType *ThisPtr =
+ cast<PointerType>(D->getThisType(getContext()));
+ DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation());
+ }
+}
+
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
@@ -1224,13 +1336,14 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ if (isa<FunctionDecl>(D)) {
// At -O0, don't generate IR for functions with available_externally
// linkage.
- if (!shouldEmitFunction(Function))
+ if (!shouldEmitFunction(GD))
return;
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ CompleteDIClassType(Method);
// Make sure to emit the definition(s) before we emit the thunks.
// This is necessary for the generation of certain thunks.
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
@@ -1265,13 +1378,15 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Type *Ty,
- GlobalDecl D, bool ForVTable,
+ GlobalDecl GD, bool ForVTable,
llvm::AttributeSet ExtraAttrs) {
+ const Decl *D = GD.getDecl();
+
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
if (WeakRefReferences.erase(Entry)) {
- const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
+ const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
if (FD && !FD->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
@@ -1283,6 +1398,14 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo());
}
+ // All MSVC dtors other than the base dtor are linkonce_odr and delegate to
+ // each other bottoming out with the base dtor. Therefore we emit non-base
+ // dtors on usage, even if there is no dtor definition in the TU.
+ if (D && isa<CXXDestructorDecl>(D) &&
+ getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
+ GD.getDtorType()))
+ DeferredDeclsToEmit.push_back(GD);
+
// This function doesn't have a complete type (for example, the return
// type is an incomplete struct). Use a fake type instead, and make
// sure not to try to set attributes.
@@ -1300,8 +1423,8 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Function::ExternalLinkage,
MangledName, &getModule());
assert(F->getName() == MangledName && "name was uniqued!");
- if (D.getDecl())
- SetFunctionAttributes(D, F, IsIncompleteFunction);
+ if (D)
+ SetFunctionAttributes(GD, F, IsIncompleteFunction);
if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) {
llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex);
F->addAttributes(llvm::AttributeSet::FunctionIndex,
@@ -1320,6 +1443,12 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
DeferredDeclsToEmit.push_back(DDI->second);
DeferredDecls.erase(DDI);
+ // Otherwise, if this is a sized deallocation function, emit a weak definition
+ // for it at the end of the translation unit.
+ } else if (D && cast<FunctionDecl>(D)
+ ->getCorrespondingUnsizedGlobalDeallocationFunction()) {
+ DeferredDeclsToEmit.push_back(GD);
+
// Otherwise, there are cases we have to worry about where we're
// using a declaration for which we must emit a definition but where
// we might not find a top-level definition:
@@ -1331,18 +1460,18 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
//
// We also don't emit a definition for a function if it's going to be an entry
// in a vtable, unless it's already marked as used.
- } else if (getLangOpts().CPlusPlus && D.getDecl()) {
+ } else if (getLangOpts().CPlusPlus && D) {
// Look for a declaration that's lexically in a record.
- const FunctionDecl *FD = cast<FunctionDecl>(D.getDecl());
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
FD = FD->getMostRecentDecl();
do {
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
if (FD->isImplicit() && !ForVTable) {
assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
- DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
+ DeferredDeclsToEmit.push_back(GD.getWithDecl(FD));
break;
} else if (FD->doesThisDeclarationHaveABody()) {
- DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
+ DeferredDeclsToEmit.push_back(GD.getWithDecl(FD));
break;
}
}
@@ -1436,6 +1565,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return Entry;
// Make sure the result is of the correct type.
+ if (Entry->getType()->getAddressSpace() != Ty->getAddressSpace())
+ return llvm::ConstantExpr::getAddrSpaceCast(Entry, Ty);
+
return llvm::ConstantExpr::getBitCast(Entry, Ty);
}
@@ -1483,12 +1615,19 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
CXXThreadLocals.push_back(std::make_pair(D, GV));
setTLSMode(GV, *D);
}
+
+ // If required by the ABI, treat declarations of static data members with
+ // inline initializers as definitions.
+ if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
+ D->isStaticDataMember() && D->hasInit() &&
+ !D->isThisDeclarationADefinition())
+ EmitGlobalVarDefinition(D);
}
if (AddrSpace != Ty->getAddressSpace())
- return llvm::ConstantExpr::getBitCast(GV, Ty);
- else
- return GV;
+ return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty);
+
+ return GV;
}
@@ -1581,125 +1720,6 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
TheDataLayout.getTypeStoreSizeInBits(Ty));
}
-llvm::Constant *
-CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
- const Expr *rawInit) {
- ArrayRef<ExprWithCleanups::CleanupObject> cleanups;
- if (const ExprWithCleanups *withCleanups =
- dyn_cast<ExprWithCleanups>(rawInit)) {
- cleanups = withCleanups->getObjects();
- rawInit = withCleanups->getSubExpr();
- }
-
- const InitListExpr *init = dyn_cast<InitListExpr>(rawInit);
- if (!init || !init->initializesStdInitializerList() ||
- init->getNumInits() == 0)
- return 0;
-
- ASTContext &ctx = getContext();
- unsigned numInits = init->getNumInits();
- // FIXME: This check is here because we would otherwise silently miscompile
- // nested global std::initializer_lists. Better would be to have a real
- // implementation.
- for (unsigned i = 0; i < numInits; ++i) {
- const InitListExpr *inner = dyn_cast<InitListExpr>(init->getInit(i));
- if (inner && inner->initializesStdInitializerList()) {
- ErrorUnsupported(inner, "nested global std::initializer_list");
- return 0;
- }
- }
-
- // Synthesize a fake VarDecl for the array and initialize that.
- QualType elementType = init->getInit(0)->getType();
- llvm::APInt numElements(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType arrayType = ctx.getConstantArrayType(elementType, numElements,
- ArrayType::Normal, 0);
-
- IdentifierInfo *name = &ctx.Idents.get(D->getNameAsString() + "__initlist");
- TypeSourceInfo *sourceInfo = ctx.getTrivialTypeSourceInfo(
- arrayType, D->getLocation());
- VarDecl *backingArray = VarDecl::Create(ctx, const_cast<DeclContext*>(
- D->getDeclContext()),
- D->getLocStart(), D->getLocation(),
- name, arrayType, sourceInfo,
- SC_Static);
- backingArray->setTSCSpec(D->getTSCSpec());
-
- // Now clone the InitListExpr to initialize the array instead.
- // Incredible hack: we want to use the existing InitListExpr here, so we need
- // to tell it that it no longer initializes a std::initializer_list.
- ArrayRef<Expr*> Inits(const_cast<InitListExpr*>(init)->getInits(),
- init->getNumInits());
- Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), Inits,
- init->getRBraceLoc());
- arrayInit->setType(arrayType);
-
- if (!cleanups.empty())
- arrayInit = ExprWithCleanups::Create(ctx, arrayInit, cleanups);
-
- backingArray->setInit(arrayInit);
-
- // Emit the definition of the array.
- EmitGlobalVarDefinition(backingArray);
-
- // Inspect the initializer list to validate it and determine its type.
- // FIXME: doing this every time is probably inefficient; caching would be nice
- RecordDecl *record = init->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator field = record->field_begin();
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- QualType elementPtr = ctx.getPointerType(elementType.withConst());
- // Start pointer.
- if (!ctx.hasSameType(field->getType(), elementPtr)) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- ++field;
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- bool isStartEnd = false;
- if (ctx.hasSameType(field->getType(), elementPtr)) {
- // End pointer.
- isStartEnd = true;
- } else if(!ctx.hasSameType(field->getType(), ctx.getSizeType())) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
-
- // Now build an APValue representing the std::initializer_list.
- APValue initListValue(APValue::UninitStruct(), 0, 2);
- APValue &startField = initListValue.getStructField(0);
- APValue::LValuePathEntry startOffsetPathEntry;
- startOffsetPathEntry.ArrayIndex = 0;
- startField = APValue(APValue::LValueBase(backingArray),
- CharUnits::fromQuantity(0),
- llvm::makeArrayRef(startOffsetPathEntry),
- /*IsOnePastTheEnd=*/false, 0);
-
- if (isStartEnd) {
- APValue &endField = initListValue.getStructField(1);
- APValue::LValuePathEntry endOffsetPathEntry;
- endOffsetPathEntry.ArrayIndex = numInits;
- endField = APValue(APValue::LValueBase(backingArray),
- ctx.getTypeSizeInChars(elementType) * numInits,
- llvm::makeArrayRef(endOffsetPathEntry),
- /*IsOnePastTheEnd=*/true, 0);
- } else {
- APValue &sizeField = initListValue.getStructField(1);
- sizeField = APValue(llvm::APSInt(numElements));
- }
-
- // Emit the constant for the initializer_list.
- llvm::Constant *llvmInit =
- EmitConstantValueForMemory(initListValue, D->getType());
- assert(llvmInit && "failed to initialize as constant");
- return llvmInit;
-}
-
unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
unsigned AddrSpace) {
if (LangOpts.CUDA && CodeGenOpts.CUDAIsDevice) {
@@ -1726,12 +1746,12 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
return;
// Must have internal linkage and an ordinary name.
- if (!D->getIdentifier() || D->getLinkage() != InternalLinkage)
+ if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage)
return;
// Must be in an extern "C" context. Entities declared directly within
// a record are not extern "C" even if the record is in such a context.
- const SomeDecl *First = D->getFirstDeclaration();
+ const SomeDecl *First = D->getFirstDecl();
if (First->getDeclContext()->isRecord() || !First->isInExternCContext())
return;
@@ -1770,18 +1790,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- // If this is a std::initializer_list, emit the special initializer.
- Init = MaybeEmitGlobalStdInitializerListInitializer(D, InitExpr);
- // An empty init list will perform zero-initialization, which happens
- // to be exactly what we want.
- // FIXME: It does so in a global constructor, which is *not* what we
- // want.
+ initializedGlobalDecl = GlobalDecl(D);
+ Init = EmitConstantInit(*InitDecl);
if (!Init) {
- initializedGlobalDecl = GlobalDecl(D);
- Init = EmitConstantInit(*InitDecl);
- }
- if (!Init) {
QualType T = InitExpr->getType();
if (D->getType()->isReferenceType())
T = D->getType();
@@ -1808,7 +1820,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// Strip off a bitcast if we got one back.
if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
assert(CE->getOpcode() == llvm::Instruction::BitCast ||
- // all zero index gep.
+ CE->getOpcode() == llvm::Instruction::AddrSpaceCast ||
+ // All zero index gep.
CE->getOpcode() == llvm::Instruction::GetElementPtr);
Entry = CE->getOperand(0);
}
@@ -1860,8 +1873,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// Set the llvm linkage type as appropriate.
llvm::GlobalValue::LinkageTypes Linkage =
- GetLLVMLinkageVarDefinition(D, GV);
+ GetLLVMLinkageVarDefinition(D, GV->isConstant());
GV->setLinkage(Linkage);
+
+ // If required by the ABI, give definitions of static data members with inline
+ // initializers linkonce_odr linkage.
+ if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
+ D->isStaticDataMember() && InitExpr &&
+ !InitDecl->isThisDeclarationADefinition())
+ GV->setLinkage(llvm::GlobalVariable::LinkOnceODRLinkage);
+
if (Linkage == llvm::GlobalVariable::CommonLinkage)
// common vars aren't constant even if declared const.
GV->setConstant(false);
@@ -1891,8 +1912,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
}
llvm::GlobalValue::LinkageTypes
-CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
- llvm::GlobalVariable *GV) {
+CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
if (Linkage == GVA_Internal)
return llvm::Function::InternalLinkage;
@@ -1900,8 +1920,14 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
return llvm::Function::DLLImportLinkage;
else if (D->hasAttr<DLLExportAttr>())
return llvm::Function::DLLExportLinkage;
- else if (D->hasAttr<WeakAttr>()) {
- if (GV->isConstant())
+ else if (D->hasAttr<SelectAnyAttr>()) {
+ // selectany symbols are externally visible, so use weak instead of
+ // linkonce. MSVC optimizes away references to const selectany globals, so
+ // all definitions should be the same and ODR linkage should be used.
+ // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
+ return llvm::GlobalVariable::WeakODRLinkage;
+ } else if (D->hasAttr<WeakAttr>()) {
+ if (isConstant)
return llvm::GlobalVariable::WeakODRLinkage;
else
return llvm::GlobalVariable::WeakAnyLinkage;
@@ -2077,6 +2103,10 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
Entry = CE->getOperand(0);
}
+ if (!cast<llvm::GlobalValue>(Entry)->isDeclaration()) {
+ getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name);
+ return;
+ }
if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != Ty) {
llvm::GlobalValue *OldFn = cast<llvm::GlobalValue>(Entry);
@@ -2126,7 +2156,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// want to propagate this information down (e.g. to local static
// declarations).
llvm::Function *Fn = cast<llvm::Function>(Entry);
- setFunctionLinkage(D, Fn);
+ setFunctionLinkage(GD, Fn);
// FIXME: this is redundant with part of SetFunctionDefinitionAttributes
setGlobalVisibility(Fn, D);
@@ -2159,6 +2189,8 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
if (Entry && !Entry->isDeclaration())
return;
+ Aliases.push_back(GD);
+
llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Create a reference to the named value. This ensures that it is emitted
@@ -2624,11 +2656,16 @@ static llvm::GlobalVariable *GenerateStringLiteral(StringRef str,
llvm::Constant *C =
llvm::ConstantDataArray::getString(CGM.getLLVMContext(), str, false);
+ // OpenCL v1.1 s6.5.3: a string literal is in the constant address space.
+ unsigned AddrSpace = 0;
+ if (CGM.getLangOpts().OpenCL)
+ AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_constant);
+
// Create a global variable for this string
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant,
- llvm::GlobalValue::PrivateLinkage,
- C, GlobalName);
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+ CGM.getModule(), C->getType(), constant,
+ llvm::GlobalValue::PrivateLinkage, C, GlobalName, 0,
+ llvm::GlobalVariable::NotThreadLocal, AddrSpace);
GV->setAlignment(Alignment);
GV->setUnnamedAddr(true);
return GV;
@@ -2684,6 +2721,74 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);
}
+llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
+ const MaterializeTemporaryExpr *E, const Expr *Init) {
+ assert((E->getStorageDuration() == SD_Static ||
+ E->getStorageDuration() == SD_Thread) && "not a global temporary");
+ const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());
+
+ // If we're not materializing a subobject of the temporary, keep the
+ // cv-qualifiers from the type of the MaterializeTemporaryExpr.
+ QualType MaterializedType = Init->getType();
+ if (Init == E->GetTemporaryExpr())
+ MaterializedType = E->getType();
+
+ llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E];
+ if (Slot)
+ return Slot;
+
+ // FIXME: If an externally-visible declaration extends multiple temporaries,
+ // we need to give each temporary the same name in every translation unit (and
+ // we also need to make the temporaries externally-visible).
+ SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
+ Out.flush();
+
+ APValue *Value = 0;
+ if (E->getStorageDuration() == SD_Static) {
+ // We might have a cached constant initializer for this temporary. Note
+ // that this might have a different value from the value computed by
+ // evaluating the initializer if the surrounding constant expression
+ // modifies the temporary.
+ Value = getContext().getMaterializedTemporaryValue(E, false);
+ if (Value && Value->isUninit())
+ Value = 0;
+ }
+
+ // Try evaluating it now, it might have a constant initializer.
+ Expr::EvalResult EvalResult;
+ if (!Value && Init->EvaluateAsRValue(EvalResult, getContext()) &&
+ !EvalResult.hasSideEffects())
+ Value = &EvalResult.Val;
+
+ llvm::Constant *InitialValue = 0;
+ bool Constant = false;
+ llvm::Type *Type;
+ if (Value) {
+ // The temporary has a constant initializer, use it.
+ InitialValue = EmitConstantValue(*Value, MaterializedType, 0);
+ Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
+ Type = InitialValue->getType();
+ } else {
+ // No initializer, the initialization will be provided when we
+ // initialize the declaration which performed lifetime extension.
+ Type = getTypes().ConvertTypeForMem(MaterializedType);
+ }
+
+ // Create a global variable for this lifetime-extended temporary.
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), Type, Constant,
+ llvm::GlobalValue::PrivateLinkage,
+ InitialValue, Name.c_str());
+ GV->setAlignment(
+ getContext().getTypeAlignInChars(MaterializedType).getQuantity());
+ if (VD->getTLSKind())
+ setTLSMode(GV, *VD);
+ Slot = GV;
+ return GV;
+}
+
/// EmitObjCPropertyImplementations - Emit information for synthesized
/// properties for an implementation.
void CodeGenModule::EmitObjCPropertyImplementations(const
@@ -2767,8 +2872,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
/// EmitNamespace - Emit all declarations in a namespace.
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end();
- I != E; ++I)
+ I != E; ++I) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(*I))
+ if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
+ VD->getTemplateSpecializationKind() != TSK_Undeclared)
+ continue;
EmitTopLevelDecl(*I);
+ }
}
// EmitLinkageSpec - Emit all declarations in a linkage spec.
@@ -2795,12 +2905,6 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void CodeGenModule::EmitTopLevelDecl(Decl *D) {
- // If an error has occurred, stop code generation, but continue
- // parsing and semantic analysis (to ensure all warnings and errors
- // are emitted).
- if (Diags.hasErrorOccurred())
- return;
-
// Ignore dependent declarations.
if (D->getDeclContext() && D->getDeclContext()->isDependentContext())
return;
@@ -2816,8 +2920,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitGlobal(cast<FunctionDecl>(D));
break;
-
+
case Decl::Var:
+ // Skip variable templates
+ if (cast<VarDecl>(D)->getDescribedVarTemplate())
+ return;
+ case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
break;
@@ -2834,12 +2942,17 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::UsingShadow:
case Decl::Using:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
- case Decl::NamespaceAlias:
case Decl::Block:
case Decl::Empty:
break;
+ case Decl::NamespaceAlias:
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(*D));
+ return;
case Decl::UsingDirective: // using namespace X; [C++]
if (CGDebugInfo *DI = getModuleDebugInfo())
DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D));
@@ -2850,12 +2963,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
- EmitCXXConstructors(cast<CXXConstructorDecl>(D));
+ getCXXABI().EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
if (cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
- EmitCXXDestructors(cast<CXXDestructorDecl>(D));
+ getCXXABI().EmitCXXDestructors(cast<CXXDestructorDecl>(D));
break;
case Decl::StaticAssert:
@@ -3032,6 +3145,18 @@ void CodeGenFunction::EmitDeclMetadata() {
}
}
+void CodeGenModule::EmitVersionIdentMetadata() {
+ llvm::NamedMDNode *IdentMetadata =
+ TheModule.getOrInsertNamedMetadata("llvm.ident");
+ std::string Version = getClangFullVersion();
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+
+ llvm::Value *IdentNode[] = {
+ llvm::MDString::get(Ctx, Version)
+ };
+ IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode));
+}
+
void CodeGenModule::EmitCoverageFile() {
if (!getCodeGenOpts().CoverageFile.empty()) {
if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) {
@@ -3054,26 +3179,24 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
// Sema has checked that all uuid strings are of the form
// "12345678-1234-1234-1234-1234567890ab".
assert(Uuid.size() == 36);
- const char *Uuidstr = Uuid.data();
- for (int i = 0; i < 36; ++i) {
- if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuidstr[i] == '-');
- else assert(isHexDigit(Uuidstr[i]));
+ for (unsigned i = 0; i < 36; ++i) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuid[i] == '-');
+ else assert(isHexDigit(Uuid[i]));
}
-
- llvm::APInt Field0(32, StringRef(Uuidstr , 8), 16);
- llvm::APInt Field1(16, StringRef(Uuidstr + 9, 4), 16);
- llvm::APInt Field2(16, StringRef(Uuidstr + 14, 4), 16);
- static const int Field3ValueOffsets[] = { 19, 21, 24, 26, 28, 30, 32, 34 };
-
- APValue InitStruct(APValue::UninitStruct(), /*NumBases=*/0, /*NumFields=*/4);
- InitStruct.getStructField(0) = APValue(llvm::APSInt(Field0));
- InitStruct.getStructField(1) = APValue(llvm::APSInt(Field1));
- InitStruct.getStructField(2) = APValue(llvm::APSInt(Field2));
- APValue& Arr = InitStruct.getStructField(3);
- Arr = APValue(APValue::UninitArray(), 8, 8);
- for (int t = 0; t < 8; ++t)
- Arr.getArrayInitializedElt(t) = APValue(llvm::APSInt(
- llvm::APInt(8, StringRef(Uuidstr + Field3ValueOffsets[t], 2), 16)));
-
- return EmitConstantValue(InitStruct, GuidType);
+
+ const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 };
+
+ llvm::Constant *Field3[8];
+ for (unsigned Idx = 0; Idx < 8; ++Idx)
+ Field3[Idx] = llvm::ConstantInt::get(
+ Int8Ty, Uuid.substr(Field3ValueOffsets[Idx], 2), 16);
+
+ llvm::Constant *Fields[4] = {
+ llvm::ConstantInt::get(Int32Ty, Uuid.substr(0, 8), 16),
+ llvm::ConstantInt::get(Int16Ty, Uuid.substr(9, 4), 16),
+ llvm::ConstantInt::get(Int16Ty, Uuid.substr(14, 4), 16),
+ llvm::ConstantArray::get(llvm::ArrayType::get(Int8Ty, 8), Field3)
+ };
+
+ return llvm::ConstantStruct::getAnon(Fields);
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 91138c607c36..c16122405d43 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -31,7 +31,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ValueHandle.h"
-#include "llvm/Transforms/Utils/BlackList.h"
+#include "llvm/Transforms/Utils/SpecialCaseList.h"
namespace llvm {
class Module;
@@ -250,7 +250,6 @@ class CodeGenModule : public CodeGenTypeCache {
/// VTables - Holds information about C++ vtables.
CodeGenVTables VTables;
- friend class CodeGenVTables;
CGObjCRuntime* ObjCRuntime;
CGOpenCLRuntime* OpenCLRuntime;
@@ -276,6 +275,13 @@ class CodeGenModule : public CodeGenTypeCache {
/// is done.
std::vector<GlobalDecl> DeferredDeclsToEmit;
+ /// List of alias we have emitted. Used to make sure that what they point to
+ /// is defined once we get to the end of the of the translation unit.
+ std::vector<GlobalDecl> Aliases;
+
+ typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy;
+ ReplacementsTy Replacements;
+
/// DeferredVTables - A queue of (optional) vtables to consider emitting.
std::vector<const CXXRecordDecl*> DeferredVTables;
@@ -307,10 +313,14 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
-
+ llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
+
llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
+ /// Map used to get unique type descriptor constants for sanitizers.
+ llvm::DenseMap<QualType, llvm::Constant *> TypeDescriptorMap;
+
/// Map used to track internal linkage functions declared within
/// extern "C" regions.
typedef llvm::MapVector<IdentifierInfo *,
@@ -355,6 +365,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// \brief The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
+ /// \brief A vector of metadata strings.
+ SmallVector<llvm::Value *, 16> LinkerOptionsMetadata;
+
/// @name Cache for Objective-C runtime types
/// @{
@@ -382,7 +395,7 @@ class CodeGenModule : public CodeGenTypeCache {
void createCUDARuntime();
bool isTriviallyRecursive(const FunctionDecl *F);
- bool shouldEmitFunction(const FunctionDecl *F);
+ bool shouldEmitFunction(GlobalDecl GD);
/// @name Cache for Blocks Runtime Globals
/// @{
@@ -408,7 +421,7 @@ class CodeGenModule : public CodeGenTypeCache {
GlobalDecl initializedGlobalDecl;
- llvm::BlackList SanitizerBlacklist;
+ llvm::OwningPtr<llvm::SpecialCaseList> SanitizerBlacklist;
const SanitizerOptions &SanOpts;
@@ -488,6 +501,13 @@ public:
AtomicGetterHelperFnMap[Ty] = Fn;
}
+ llvm::Constant *getTypeDescriptor(QualType Ty) {
+ return TypeDescriptorMap[Ty];
+ }
+ void setTypeDescriptor(QualType Ty, llvm::Constant *C) {
+ TypeDescriptorMap[Ty] = C;
+ }
+
CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
llvm::MDNode *getNoObjCARCExceptionsMetadata() {
@@ -515,7 +535,14 @@ public:
CodeGenTypes &getTypes() { return Types; }
CodeGenVTables &getVTables() { return VTables; }
- VTableContext &getVTableContext() { return VTables.getVTableContext(); }
+
+ ItaniumVTableContext &getItaniumVTableContext() {
+ return VTables.getItaniumVTableContext();
+ }
+
+ MicrosoftVTableContext &getMicrosoftVTableContext() {
+ return VTables.getMicrosoftVTableContext();
+ }
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
@@ -728,7 +755,12 @@ public:
/// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global
/// variable for the given file-scope compound literal expression.
llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
-
+
+ /// \brief Returns a pointer to a global variable representing a temporary
+ /// with static or thread storage duration.
+ llvm::Constant *GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,
+ const Expr *Inner);
+
/// \brief Retrieve the record type that describes the state of an
/// Objective-C fast enumeration loop (for..in).
QualType getObjCFastEnumerationStateType();
@@ -743,7 +775,8 @@ public:
/// given type.
llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
CXXDtorType dtorType,
- const CGFunctionInfo *fnInfo = 0);
+ const CGFunctionInfo *fnInfo = 0,
+ llvm::FunctionType *fnType = 0);
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
@@ -842,17 +875,11 @@ public:
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
- /// \param OmitOnError - If true, then this error should only be emitted if no
- /// other errors have been reported.
- void ErrorUnsupported(const Stmt *S, const char *Type,
- bool OmitOnError=false);
+ void ErrorUnsupported(const Stmt *S, const char *Type);
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified decl yet.
- /// \param OmitOnError - If true, then this error should only be emitted if no
- /// other errors have been reported.
- void ErrorUnsupported(const Decl *D, const char *Type,
- bool OmitOnError=false);
+ void ErrorUnsupported(const Decl *D, const char *Type);
/// SetInternalFunctionAttributes - Set the attributes on the LLVM
/// function for the given decl and function info. This applies
@@ -906,11 +933,23 @@ public:
void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
- llvm::GlobalVariable::LinkageTypes
- getFunctionLinkage(const FunctionDecl *FD);
+ /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the
+ /// builtin types.
+ void EmitFundamentalRTTIDescriptors();
+
+ /// \brief Appends Opts to the "Linker Options" metadata value.
+ void AppendLinkerOptions(StringRef Opts);
- void setFunctionLinkage(const FunctionDecl *FD, llvm::GlobalValue *V) {
- V->setLinkage(getFunctionLinkage(FD));
+ /// \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.
+ void AddDependentLib(StringRef Lib);
+
+ llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
+
+ void setFunctionLinkage(GlobalDecl GD, llvm::GlobalValue *V) {
+ V->setLinkage(getFunctionLinkage(GD));
}
/// getVTableLinkage - Return the appropriate linkage for the vtable, VTT,
@@ -924,8 +963,7 @@ public:
/// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global
/// variable.
llvm::GlobalValue::LinkageTypes
- GetLLVMLinkageVarDefinition(const VarDecl *D,
- llvm::GlobalVariable *GV);
+ GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant);
/// Emit all the global annotations.
void EmitGlobalAnnotations();
@@ -954,8 +992,8 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
- const llvm::BlackList &getSanitizerBlacklist() const {
- return SanitizerBlacklist;
+ const llvm::SpecialCaseList &getSanitizerBlacklist() const {
+ return *SanitizerBlacklist;
}
const SanitizerOptions &getSanOpts() const { return SanOpts; }
@@ -964,6 +1002,10 @@ public:
DeferredVTables.push_back(RD);
}
+ /// EmitGlobal - Emit code for a singal global function or var decl. Forward
+ /// declarations are emitted lazily.
+ void EmitGlobal(GlobalDecl D);
+
private:
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
@@ -995,40 +1037,28 @@ private:
llvm::Function *F,
bool IsIncompleteFunction);
- /// EmitGlobal - Emit code for a singal global function or var decl. Forward
- /// declarations are emitted lazily.
- void EmitGlobal(GlobalDecl D);
-
void EmitGlobalDefinition(GlobalDecl D);
void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D);
- llvm::Constant *MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
- const Expr *init);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
// C++ related functions.
- bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
+ bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target,
+ bool InEveryTU);
bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
void EmitNamespace(const NamespaceDecl *D);
void EmitLinkageSpec(const LinkageSpecDecl *D);
-
- /// EmitCXXConstructors - Emit constructors (base, complete) from a
- /// C++ constructor Decl.
- void EmitCXXConstructors(const CXXConstructorDecl *D);
+ void CompleteDIClassType(const CXXMethodDecl* D);
/// EmitCXXConstructor - Emit a single constructor with the given type from
/// a C++ constructor Decl.
void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type);
- /// EmitCXXDestructors - Emit destructors (base, complete) from a
- /// C++ destructor Decl.
- void EmitCXXDestructors(const CXXDestructorDecl *D);
-
/// EmitCXXDestructor - Emit a single destructor with the given type from
/// a C++ destructor Decl.
void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
@@ -1061,14 +1091,15 @@ private:
/// given type.
void EmitFundamentalRTTIDescriptor(QualType Type);
- /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the
- /// builtin types.
- void EmitFundamentalRTTIDescriptors();
-
/// EmitDeferred - Emit any needed decls for which code generation
/// was deferred.
void EmitDeferred();
+ /// Call replaceAllUsesWith on all pairs in Replacements.
+ void applyReplacements();
+
+ void checkAliases();
+
/// EmitDeferredVTables - Emit any vtables which we deferred and
/// still have a use for.
void EmitDeferredVTables();
@@ -1086,6 +1117,9 @@ private:
void EmitDeclMetadata();
+ /// \brief Emit the Clang version as llvm.ident metadata.
+ void EmitVersionIdentMetadata();
+
/// EmitCoverageFile - 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();
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 5ff1560a4886..699cc2eabe18 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -50,16 +50,11 @@ llvm::MDNode *CodeGenTBAA::getRoot() {
return Root;
}
-// For struct-path aware TBAA, the scalar type has the same format as
-// the struct type: name, offset, pointer to another node in the type DAG.
-// For scalar TBAA, the scalar type is the same as the scalar tag:
-// name and a parent pointer.
+// For both scalar TBAA and struct-path aware TBAA, the scalar type has the
+// same format: name, parent node, and offset.
llvm::MDNode *CodeGenTBAA::createTBAAScalarType(StringRef Name,
llvm::MDNode *Parent) {
- if (CodeGenOpts.StructPathTBAA)
- return MDHelper.createTBAAScalarTypeNode(Name, Parent);
- else
- return MDHelper.createTBAANode(Name, Parent);
+ return MDHelper.createTBAAScalarTypeNode(Name, Parent);
}
llvm::MDNode *CodeGenTBAA::getChar() {
@@ -91,7 +86,7 @@ static bool TypeHasMayAlias(QualType QTy) {
llvm::MDNode *
CodeGenTBAA::getTBAAInfo(QualType QTy) {
- // At -O0 TBAA is not emitted for regular types.
+ // At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
return NULL;
@@ -150,27 +145,16 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// Enum types are distinct types. In C++ they have "underlying types",
// however they aren't related for TBAA.
if (const EnumType *ETy = dyn_cast<EnumType>(Ty)) {
- // In C mode, two anonymous enums are compatible iff their members
- // are the same -- see C99 6.2.7p1. For now, be conservative. We could
- // theoretically implement this by combining information about all the
- // members into a single identifying MDNode.
- if (!Features.CPlusPlus &&
- ETy->getDecl()->getTypedefNameForAnonDecl())
- return MetadataCache[Ty] = getChar();
-
// In C++ mode, types have linkage, so we can rely on the ODR and
// on their mangled names, if they're external.
// TODO: Is there a way to get a program-wide unique name for a
// decl with local linkage or no linkage?
- if (Features.CPlusPlus &&
- ETy->getDecl()->getLinkage() != ExternalLinkage)
+ if (!Features.CPlusPlus || !ETy->getDecl()->isExternallyVisible())
return MetadataCache[Ty] = getChar();
- // TODO: This is using the RTTI name. Is there a better way to get
- // a unique string for a type?
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
- MContext.mangleCXXRTTIName(QualType(ETy, 0), Out);
+ MContext.mangleTypeName(QualType(ETy, 0), Out);
Out.flush();
return MetadataCache[Ty] = createTBAAScalarType(OutName, getChar());
}
@@ -204,18 +188,8 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
unsigned idx = 0;
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(Context);
for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i, ++idx) {
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored.
- if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) {
- --idx;
- continue;
- }
- LastFD = *i;
- }
uint64_t Offset = BaseOffset +
Layout.getFieldOffset(idx) / Context.getCharWidth();
QualType FieldQTy = i->getType();
@@ -230,8 +204,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
uint64_t Offset = BaseOffset;
uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy);
- llvm::MDNode *TBAATag = CodeGenOpts.StructPathTBAA ?
- getTBAAScalarTagInfo(TBAAInfo) : TBAAInfo;
+ llvm::MDNode *TBAATag = getTBAAScalarTagInfo(TBAAInfo);
Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag));
return true;
}
@@ -279,19 +252,8 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
SmallVector <std::pair<llvm::MDNode*, uint64_t>, 4> Fields;
unsigned idx = 0;
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(Context);
for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i, ++idx) {
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored.
- if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) {
- --idx;
- continue;
- }
- LastFD = *i;
- }
-
QualType FieldQTy = i->getType();
llvm::MDNode *FieldNode;
if (isTBAAPathStruct(FieldQTy))
@@ -304,12 +266,15 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth()));
}
- // TODO: This is using the RTTI name. Is there a better way to get
- // a unique string for a type?
SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- MContext.mangleCXXRTTIName(QualType(Ty, 0), Out);
- Out.flush();
+ if (Features.CPlusPlus) {
+ // Don't use the mangler for C code.
+ llvm::raw_svector_ostream Out(OutName);
+ MContext.mangleTypeName(QualType(Ty, 0), Out);
+ Out.flush();
+ } else {
+ OutName = RD->getName();
+ }
// Create the struct type node with a vector of pairs (offset, type).
return StructTypeMetadataCache[Ty] =
MDHelper.createTBAAStructTypeNode(OutName, Fields);
@@ -318,11 +283,15 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
return StructMetadataCache[Ty] = NULL;
}
+/// 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)
+ return NULL;
+
if (!CodeGenOpts.StructPathTBAA)
- return AccessNode;
+ return getTBAAScalarTagInfo(AccessNode);
const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
@@ -342,6 +311,8 @@ CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
llvm::MDNode *
CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) {
+ if (!AccessNode)
+ return NULL;
if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode])
return N;
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index f0c9e06f02bd..0ad4be24fd24 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -117,7 +117,7 @@ public:
llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType,
llvm::MDNode *AccessNode, uint64_t Offset);
- /// Get the sclar tag MDNode for a given scalar type.
+ /// Get the scalar tag MDNode for a given scalar type.
llvm::MDNode *getTBAAScalarTagInfo(llvm::MDNode *AccessNode);
};
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 4240216b230c..5f3c59c197a6 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
@@ -32,7 +33,6 @@ CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
: CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()),
TheDataLayout(cgm.getDataLayout()),
Target(cgm.getTarget()), TheCXXABI(cgm.getCXXABI()),
- CodeGenOpts(cgm.getCodeGenOpts()),
TheABIInfo(cgm.getTargetCodeGenInfo().getABIInfo()) {
SkippedLayout = false;
}
@@ -260,6 +260,11 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
// yet, we'll just do it lazily.
if (RecordDeclTypes.count(Context.getTagDeclType(RD).getTypePtr()))
ConvertRecordDeclType(RD);
+
+ // If necessary, provide the full definition of a type only used with a
+ // declaration so far.
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+ DI->completeType(RD);
}
static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 452375f374c4..94ca9e21e5fe 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -16,6 +16,7 @@
#include "CGCall.h"
#include "clang/AST/GlobalDecl.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/Module.h"
#include <vector>
@@ -58,21 +59,18 @@ namespace CodeGen {
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
-public:
- // Some of this stuff should probably be left on the CGM.
CodeGenModule &CGM;
+ // Some of this stuff should probably be left on the CGM.
ASTContext &Context;
llvm::Module &TheModule;
const llvm::DataLayout &TheDataLayout;
const TargetInfo &Target;
CGCXXABI &TheCXXABI;
- const CodeGenOptions &CodeGenOpts;
// This should not be moved earlier, since its initialization depends on some
// of the previous reference members being already initialized
const ABIInfo &TheABIInfo;
-private:
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
/// responsible for coercing to the appropriate type; these opaque
@@ -116,7 +114,6 @@ public:
const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
- const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
new file mode 100644
index 000000000000..e9d9a339ffc7
--- /dev/null
+++ b/lib/CodeGen/EHScopeStack.h
@@ -0,0 +1,489 @@
+//===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes should be the minimum interface required for other parts of
+// CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other
+// implemenentation details that are not widely needed are in CGCleanup.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_EHSCOPESTACK_H
+#define CLANG_CODEGEN_EHSCOPESTACK_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/Instructions.h"
+
+namespace clang {
+namespace CodeGen {
+
+class CodeGenFunction;
+
+/// A branch fixup. These are required when emitting a goto to a
+/// label which hasn't been emitted yet. The goto is optimistically
+/// emitted as a branch to the basic block for the label, and (if it
+/// occurs in a scope with non-trivial cleanups) a fixup is added to
+/// the innermost cleanup. When a (normal) cleanup is popped, any
+/// unresolved fixups in that scope are threaded through the cleanup.
+struct BranchFixup {
+ /// The block containing the terminator which needs to be modified
+ /// into a switch if this fixup is resolved into the current scope.
+ /// If null, LatestBranch points directly to the destination.
+ llvm::BasicBlock *OptimisticBranchBlock;
+
+ /// The ultimate destination of the branch.
+ ///
+ /// This can be set to null to indicate that this fixup was
+ /// successfully resolved.
+ llvm::BasicBlock *Destination;
+
+ /// The destination index value.
+ unsigned DestinationIndex;
+
+ /// The initial branch of the fixup.
+ llvm::BranchInst *InitialBranch;
+};
+
+template <class T> struct InvariantValue {
+ typedef T type;
+ typedef T saved_type;
+ static bool needsSaving(type value) { return false; }
+ static saved_type save(CodeGenFunction &CGF, type value) { return value; }
+ static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
+};
+
+/// A metaprogramming class for ensuring that a value will dominate an
+/// arbitrary position in a function.
+template <class T> struct DominatingValue : InvariantValue<T> {};
+
+template <class T, bool mightBeInstruction =
+ llvm::is_base_of<llvm::Value, T>::value &&
+ !llvm::is_base_of<llvm::Constant, T>::value &&
+ !llvm::is_base_of<llvm::BasicBlock, T>::value>
+struct DominatingPointer;
+template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
+// template <class T> struct DominatingPointer<T,true> at end of file
+
+template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
+
+enum CleanupKind {
+ EHCleanup = 0x1,
+ NormalCleanup = 0x2,
+ NormalAndEHCleanup = EHCleanup | NormalCleanup,
+
+ InactiveCleanup = 0x4,
+ InactiveEHCleanup = EHCleanup | InactiveCleanup,
+ InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
+ InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup
+};
+
+/// A stack of scopes which respond to exceptions, including cleanups
+/// and catch blocks.
+class EHScopeStack {
+public:
+ /// A saved depth on the scope stack. This is necessary because
+ /// pushing scopes onto the stack invalidates iterators.
+ class stable_iterator {
+ friend class EHScopeStack;
+
+ /// Offset from StartOfData to EndOfBuffer.
+ ptrdiff_t Size;
+
+ stable_iterator(ptrdiff_t Size) : Size(Size) {}
+
+ public:
+ static stable_iterator invalid() { return stable_iterator(-1); }
+ stable_iterator() : Size(-1) {}
+
+ bool isValid() const { return Size >= 0; }
+
+ /// Returns true if this scope encloses I.
+ /// Returns false if I is invalid.
+ /// This scope must be valid.
+ bool encloses(stable_iterator I) const { return Size <= I.Size; }
+
+ /// Returns true if this scope strictly encloses I: that is,
+ /// if it encloses I and is not I.
+ /// Returns false is I is invalid.
+ /// This scope must be valid.
+ bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; }
+
+ friend bool operator==(stable_iterator A, stable_iterator B) {
+ return A.Size == B.Size;
+ }
+ friend bool operator!=(stable_iterator A, stable_iterator B) {
+ return A.Size != B.Size;
+ }
+ };
+
+ /// Information for lazily generating a cleanup. Subclasses must be
+ /// POD-like: cleanups will not be destructed, and they will be
+ /// allocated on the cleanup stack and freely copied and moved
+ /// around.
+ ///
+ /// Cleanup implementations should generally be declared in an
+ /// anonymous namespace.
+ class Cleanup {
+ // Anchor the construction vtable.
+ virtual void anchor();
+ public:
+ /// Generation flags.
+ class Flags {
+ enum {
+ F_IsForEH = 0x1,
+ F_IsNormalCleanupKind = 0x2,
+ F_IsEHCleanupKind = 0x4
+ };
+ unsigned flags;
+
+ public:
+ Flags() : flags(0) {}
+
+ /// isForEH - true if the current emission is for an EH cleanup.
+ bool isForEHCleanup() const { return flags & F_IsForEH; }
+ bool isForNormalCleanup() const { return !isForEHCleanup(); }
+ void setIsForEHCleanup() { flags |= F_IsForEH; }
+
+ bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
+ void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
+
+ /// isEHCleanupKind - true if the cleanup was pushed as an EH
+ /// cleanup.
+ bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
+ void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
+ };
+
+ // Provide a virtual destructor to suppress a very common warning
+ // that unfortunately cannot be suppressed without this. Cleanups
+ // should not rely on this destructor ever being called.
+ virtual ~Cleanup() {}
+
+ /// Emit the cleanup. For normal cleanups, this is run in the
+ /// same EH context as when the cleanup was pushed, i.e. the
+ /// immediately-enclosing context of the cleanup scope. For
+ /// EH cleanups, this is run in a terminate context.
+ ///
+ // \param flags cleanup kind.
+ virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
+ };
+
+ /// ConditionalCleanupN stores the saved form of its N parameters,
+ /// then restores them and performs the cleanup.
+ template <class T, class A0>
+ class ConditionalCleanup1 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ A0_saved a0_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ T(a0).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup1(A0_saved a0)
+ : a0_saved(a0) {}
+ };
+
+ template <class T, class A0, class A1>
+ class ConditionalCleanup2 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ typedef typename DominatingValue<A1>::saved_type A1_saved;
+ A0_saved a0_saved;
+ A1_saved a1_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
+ T(a0, a1).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup2(A0_saved a0, A1_saved a1)
+ : a0_saved(a0), a1_saved(a1) {}
+ };
+
+ template <class T, class A0, class A1, class A2>
+ class ConditionalCleanup3 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ typedef typename DominatingValue<A1>::saved_type A1_saved;
+ typedef typename DominatingValue<A2>::saved_type A2_saved;
+ A0_saved a0_saved;
+ A1_saved a1_saved;
+ A2_saved a2_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
+ A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
+ T(a0, a1, a2).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2)
+ : a0_saved(a0), a1_saved(a1), a2_saved(a2) {}
+ };
+
+ template <class T, class A0, class A1, class A2, class A3>
+ class ConditionalCleanup4 : public Cleanup {
+ typedef typename DominatingValue<A0>::saved_type A0_saved;
+ typedef typename DominatingValue<A1>::saved_type A1_saved;
+ typedef typename DominatingValue<A2>::saved_type A2_saved;
+ typedef typename DominatingValue<A3>::saved_type A3_saved;
+ A0_saved a0_saved;
+ A1_saved a1_saved;
+ A2_saved a2_saved;
+ A3_saved a3_saved;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
+ A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
+ A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
+ A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
+ T(a0, a1, a2, a3).Emit(CGF, flags);
+ }
+
+ public:
+ ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3)
+ : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {}
+ };
+
+private:
+ // The implementation for this class is in CGException.h and
+ // CGException.cpp; the definition is here because it's used as a
+ // member of CodeGenFunction.
+
+ /// The start of the scope-stack buffer, i.e. the allocated pointer
+ /// for the buffer. All of these pointers are either simultaneously
+ /// null or simultaneously valid.
+ char *StartOfBuffer;
+
+ /// The end of the buffer.
+ char *EndOfBuffer;
+
+ /// The first valid entry in the buffer.
+ char *StartOfData;
+
+ /// The innermost normal cleanup on the stack.
+ stable_iterator InnermostNormalCleanup;
+
+ /// The innermost EH scope on the stack.
+ stable_iterator InnermostEHScope;
+
+ /// The current set of branch fixups. A branch fixup is a jump to
+ /// an as-yet unemitted label, i.e. a label for which we don't yet
+ /// know the EH stack depth. Whenever we pop a cleanup, we have
+ /// to thread all the current branch fixups through it.
+ ///
+ /// Fixups are recorded as the Use of the respective branch or
+ /// switch statement. The use points to the final destination.
+ /// When popping out of a cleanup, these uses are threaded through
+ /// the cleanup and adjusted to point to the new cleanup.
+ ///
+ /// Note that branches are allowed to jump into protected scopes
+ /// in certain situations; e.g. the following code is legal:
+ /// struct A { ~A(); }; // trivial ctor, non-trivial dtor
+ /// goto foo;
+ /// A a;
+ /// foo:
+ /// bar();
+ SmallVector<BranchFixup, 8> BranchFixups;
+
+ char *allocate(size_t Size);
+
+ void *pushCleanup(CleanupKind K, size_t DataSize);
+
+public:
+ EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0),
+ InnermostNormalCleanup(stable_end()),
+ InnermostEHScope(stable_end()) {}
+ ~EHScopeStack() { delete[] StartOfBuffer; }
+
+ // Variadic templates would make this not terrible.
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T>
+ void pushCleanup(CleanupKind Kind) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T();
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0>
+ void pushCleanup(CleanupKind Kind, A0 a0) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T(a0);
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0, class A1>
+ void pushCleanup(CleanupKind Kind, A0 a0, A1 a1) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T(a0, a1);
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0, class A1, class A2>
+ void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T(a0, a1, a2);
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0, class A1, class A2, class A3>
+ void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3);
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0, class A1, class A2, class A3, class A4>
+ void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3, a4);
+ (void) Obj;
+ }
+
+ // Feel free to add more variants of the following:
+
+ /// Push a cleanup with non-constant storage requirements on the
+ /// stack. The cleanup type must provide an additional static method:
+ /// static size_t getExtraSize(size_t);
+ /// The argument to this method will be the value N, which will also
+ /// be passed as the first argument to the constructor.
+ ///
+ /// The data stored in the extra storage must obey the same
+ /// restrictions as normal cleanup member data.
+ ///
+ /// The pointer returned from this method is valid until the cleanup
+ /// stack is modified.
+ template <class T, class A0, class A1, class A2>
+ T *pushCleanupWithExtra(CleanupKind Kind, size_t N, A0 a0, A1 a1, A2 a2) {
+ void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N));
+ return new (Buffer) T(N, a0, a1, a2);
+ }
+
+ void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
+ void *Buffer = pushCleanup(Kind, Size);
+ std::memcpy(Buffer, Cleanup, Size);
+ }
+
+ /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp.
+ void popCleanup();
+
+ /// Push a set of catch handlers on the stack. The catch is
+ /// uninitialized and will need to have the given number of handlers
+ /// set on it.
+ class EHCatchScope *pushCatch(unsigned NumHandlers);
+
+ /// Pops a catch scope off the stack. This is private to CGException.cpp.
+ void popCatch();
+
+ /// Push an exceptions filter on the stack.
+ class EHFilterScope *pushFilter(unsigned NumFilters);
+
+ /// Pops an exceptions filter off the stack.
+ void popFilter();
+
+ /// Push a terminate handler on the stack.
+ void pushTerminate();
+
+ /// Pops a terminate handler off the stack.
+ void popTerminate();
+
+ /// Determines whether the exception-scopes stack is empty.
+ bool empty() const { return StartOfData == EndOfBuffer; }
+
+ bool requiresLandingPad() const {
+ return InnermostEHScope != stable_end();
+ }
+
+ /// Determines whether there are any normal cleanups on the stack.
+ bool hasNormalCleanups() const {
+ return InnermostNormalCleanup != stable_end();
+ }
+
+ /// Returns the innermost normal cleanup on the stack, or
+ /// stable_end() if there are no normal cleanups.
+ stable_iterator getInnermostNormalCleanup() const {
+ return InnermostNormalCleanup;
+ }
+ stable_iterator getInnermostActiveNormalCleanup() const;
+
+ stable_iterator getInnermostEHScope() const {
+ return InnermostEHScope;
+ }
+
+ stable_iterator getInnermostActiveEHScope() const;
+
+ /// An unstable reference to a scope-stack depth. Invalidated by
+ /// pushes but not pops.
+ class iterator;
+
+ /// Returns an iterator pointing to the innermost EH scope.
+ iterator begin() const;
+
+ /// Returns an iterator pointing to the outermost EH scope.
+ iterator end() const;
+
+ /// Create a stable reference to the top of the EH stack. The
+ /// returned reference is valid until that scope is popped off the
+ /// stack.
+ stable_iterator stable_begin() const {
+ return stable_iterator(EndOfBuffer - StartOfData);
+ }
+
+ /// Create a stable reference to the bottom of the EH stack.
+ static stable_iterator stable_end() {
+ return stable_iterator(0);
+ }
+
+ /// Translates an iterator into a stable_iterator.
+ stable_iterator stabilize(iterator it) const;
+
+ /// Turn a stable reference to a scope depth into a unstable pointer
+ /// to the EH stack.
+ iterator find(stable_iterator save) const;
+
+ /// Removes the cleanup pointed to by the given stable_iterator.
+ void removeCleanup(stable_iterator save);
+
+ /// Add a branch fixup to the current cleanup scope.
+ BranchFixup &addBranchFixup() {
+ assert(hasNormalCleanups() && "adding fixup in scope without cleanups");
+ BranchFixups.push_back(BranchFixup());
+ return BranchFixups.back();
+ }
+
+ unsigned getNumBranchFixups() const { return BranchFixups.size(); }
+ BranchFixup &getBranchFixup(unsigned I) {
+ assert(I < getNumBranchFixups());
+ return BranchFixups[I];
+ }
+
+ /// Pops lazily-removed fixups from the end of the list. This
+ /// should only be called by procedures which have just popped a
+ /// cleanup or resolved one or more fixups.
+ void popNullFixups();
+
+ /// Clears the branch-fixups list. This should only be called by
+ /// ResolveAllBranchFixups.
+ void clearFixups() { BranchFixups.clear(); }
+};
+
+} // namespace CodeGen
+} // namespace clang
+
+#endif
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index e117e2867bdd..0e8f31a48454 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -34,12 +34,23 @@ using namespace CodeGen;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
+ /// VTables - All the vtables which have been defined.
+ llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
+
protected:
- bool IsARM;
+ bool UseARMMethodPtrABI;
+ bool UseARMGuardVarABI;
+
+ ItaniumMangleContext &getMangleContext() {
+ return cast<ItaniumMangleContext>(CodeGen::CGCXXABI::getMangleContext());
+ }
public:
- ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
- CGCXXABI(CGM), IsARM(IsARM) { }
+ ItaniumCXXABI(CodeGen::CodeGenModule &CGM,
+ bool UseARMMethodPtrABI = false,
+ bool UseARMGuardVarABI = false) :
+ CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI),
+ UseARMGuardVarABI(UseARMGuardVarABI) { }
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
// Structures with either a non-trivial destructor or a non-trivial
@@ -98,36 +109,82 @@ public:
llvm::Value *ptr,
QualType type);
+ llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
+
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
+ void EmitCXXConstructors(const CXXConstructorDecl *D);
+
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
+ bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
+ CXXDtorType DT) const {
+ // Itanium does not emit any destructor variant as an inline thunk.
+ // Delegating may occur as an optimization, but all variants are either
+ // emitted with external linkage or as linkonce if they are inline and used.
+ return false;
+ }
+
+ void EmitCXXDestructors(const CXXDestructorDecl *D);
+
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params);
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
+ void EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
- RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- llvm::Value *This);
+ void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD);
+
+ llvm::Value *getVTableAddressPointInStructor(
+ CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
+ BaseSubobject Base, const CXXRecordDecl *NearestVBase,
+ bool &NeedsVirtualOffset);
+
+ llvm::Constant *
+ getVTableAddressPointForConstExpr(BaseSubobject Base,
+ const CXXRecordDecl *VTableClass);
+
+ llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
+ CharUnits VPtrOffset);
+
+ llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This, llvm::Type *Ty);
+
+ void EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType, SourceLocation CallLoc,
+ llvm::Value *This);
+
+ void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+ // Allow inlining of thunks by emitting them with available_externally
+ // linkage together with vtables when needed.
+ if (ForVTable)
+ Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+ }
+
+ llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
+ const ThisAdjustment &TA);
+
+ llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+ const ReturnAdjustment &RA);
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
@@ -154,27 +211,21 @@ public:
llvm::Function *InitFunc);
LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
const DeclRefExpr *DRE);
+
+ bool NeedsVTTParameter(GlobalDecl GD);
};
class ARMCXXABI : public ItaniumCXXABI {
public:
- ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
+ ARMCXXABI(CodeGen::CodeGenModule &CGM) :
+ ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
+ /* UseARMGuardVarABI = */ true) {}
- void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
-
- void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
-
- void BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params);
-
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ bool HasThisReturn(GlobalDecl GD) const {
+ return (isa<CXXConstructorDecl>(GD.getDecl()) || (
+ isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Deleting));
+ }
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
@@ -186,15 +237,6 @@ public:
QualType ElementType);
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize);
-
- /// \brief Returns true if the given instance method is one of the
- /// kinds that the ARM ABI says returns 'this'.
- bool HasThisReturn(GlobalDecl GD) const {
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
- if (!MD) return false;
- return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
- (isa<CXXConstructorDecl>(MD)));
- }
};
}
@@ -210,9 +252,18 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
// include the other 32-bit ARM oddities: constructor/destructor return values
// and array cookies.
case TargetCXXABI::GenericAArch64:
- return new ItaniumCXXABI(CGM, /*IsARM = */ true);
+ return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
+ /* UseARMGuardVarABI = */ true);
case TargetCXXABI::GenericItanium:
+ if (CGM.getContext().getTargetInfo().getTriple().getArch()
+ == llvm::Triple::le32) {
+ // For PNaCl, use ARM-style method pointers so that PNaCl code
+ // does not assume anything about the alignment of function
+ // pointers.
+ return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
+ /* UseARMGuardVarABI = */ false);
+ }
return new ItaniumCXXABI(CGM);
case TargetCXXABI::Microsoft:
@@ -275,7 +326,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
// Compute the true adjustment.
llvm::Value *Adj = RawAdj;
- if (IsARM)
+ if (UseARMMethodPtrABI)
Adj = Builder.CreateAShr(Adj, ptrdiff_1, "memptr.adj.shifted");
// Apply the adjustment and cast back to the original struct type
@@ -290,7 +341,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
// If the LSB in the function pointer is 1, the function pointer points to
// a virtual function.
llvm::Value *IsVirtual;
- if (IsARM)
+ if (UseARMMethodPtrABI)
IsVirtual = Builder.CreateAnd(RawAdj, ptrdiff_1);
else
IsVirtual = Builder.CreateAnd(FnAsInt, ptrdiff_1);
@@ -309,7 +360,8 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
// Apply the offset.
llvm::Value *VTableOffset = FnAsInt;
- if (!IsARM) VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
+ if (!UseARMMethodPtrABI)
+ VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
VTable = Builder.CreateGEP(VTable, VTableOffset);
// Load the virtual function to call.
@@ -419,7 +471,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
}
// The this-adjustment is left-shifted by 1 on ARM.
- if (IsARM) {
+ if (UseARMMethodPtrABI) {
uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
offset <<= 1;
adj = llvm::ConstantInt::get(adj->getType(), offset);
@@ -467,7 +519,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
}
// The this-adjustment is left-shifted by 1 on ARM.
- if (IsARM) {
+ if (UseARMMethodPtrABI) {
uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
offset <<= 1;
adj = llvm::ConstantInt::get(adj->getType(), offset);
@@ -518,14 +570,14 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// Get the function pointer (or index if this is a virtual function).
llvm::Constant *MemPtr[2];
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVTableContext().getMethodVTableIndex(MD);
+ uint64_t Index = CGM.getItaniumVTableContext().getMethodVTableIndex(MD);
const ASTContext &Context = getContext();
CharUnits PointerWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
- if (IsARM) {
+ if (UseARMMethodPtrABI) {
// ARM C++ ABI 3.2.1:
// This ABI specifies that adj contains twice the this
// adjustment, plus 1 if the member function is virtual. The
@@ -559,7 +611,8 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
- MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, (IsARM ? 2 : 1) *
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
+ (UseARMMethodPtrABI ? 2 : 1) *
ThisAdjustment.getQuantity());
}
@@ -573,22 +626,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,
if (!MPD)
return EmitNullMemberPointer(MPT);
- // Compute the this-adjustment.
- CharUnits ThisAdjustment = CharUnits::Zero();
- ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
- bool DerivedMember = MP.isMemberPointerToDerivedMember();
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- const CXXRecordDecl *Base = RD;
- const CXXRecordDecl *Derived = Path[I];
- if (DerivedMember)
- std::swap(Base, Derived);
- ThisAdjustment +=
- getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
- RD = Path[I];
- }
- if (DerivedMember)
- ThisAdjustment = -ThisAdjustment;
+ CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
return BuildMemberPointer(MD, ThisAdjustment);
@@ -658,7 +696,7 @@ ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
// Null member function pointers on ARM clear the low bit of Adj,
// so the zero condition has to check that neither low bit is set.
- if (IsARM) {
+ if (UseARMMethodPtrABI) {
llvm::Value *One = llvm::ConstantInt::get(LPtr->getType(), 1);
// Compute (l.adj | r.adj) & 1 and test it against zero.
@@ -698,7 +736,7 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
// On ARM, a member function pointer is also non-null if the low bit of 'adj'
// (the virtual bit) is set.
- if (IsARM) {
+ if (UseARMMethodPtrABI) {
llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1);
llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj");
llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit");
@@ -735,6 +773,28 @@ llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return CGF.Builder.CreateInBoundsGEP(ptr, offset);
}
+llvm::Value *
+ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ llvm::Value *VTablePtr = CGF.GetVTablePtr(This, CGM.Int8PtrTy);
+ CharUnits VBaseOffsetOffset =
+ CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(ClassDecl,
+ BaseClassDecl);
+
+ llvm::Value *VBaseOffsetPtr =
+ CGF.Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
+ "vbase.offset.ptr");
+ VBaseOffsetPtr = CGF.Builder.CreateBitCast(VBaseOffsetPtr,
+ CGM.PtrDiffTy->getPointerTo());
+
+ llvm::Value *VBaseOffset =
+ CGF.Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+
+ return VBaseOffset;
+}
+
/// The generic ABI passes 'this', plus a VTT if it's initializing a
/// base subobject.
void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
@@ -743,20 +803,28 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' is already there.
+ // 'this' parameter is already there, as well as 'this' return if
+ // HasThisReturn(GlobalDecl(Ctor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **).
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
}
-/// The ARM ABI does the same as the Itanium ABI, but returns 'this'.
-void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys);
- ResTy = ArgTys[0];
+void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
+ // Just make sure we're in sync with TargetCXXABI.
+ assert(CGM.getTarget().getCXXABI().hasConstructorVariants());
+
+ // The constructor used for constructing this as a complete class;
+ // constucts the virtual bases, then calls the base constructor.
+ if (!D->getParent()->isAbstract()) {
+ // We don't need to emit the complete ctor if the class is abstract.
+ CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ }
+
+ // The constructor used for constructing this as a base class;
+ // ignores virtual bases.
+ CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
}
/// The generic ABI passes 'this', plus a VTT if it's destroying a
@@ -767,23 +835,28 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' is already there.
+ // 'this' parameter is already there, as well as 'this' return if
+ // HasThisReturn(GlobalDecl(Dtor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **).
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
}
-/// The ARM ABI does the same as the Itanium ABI, but returns 'this'
-/// for non-deleting destructors.
-void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys);
+void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ // The destructor in a virtual table is always a 'deleting'
+ // destructor, which calls the complete destructor and then uses the
+ // appropriate operator delete.
+ if (D->isVirtual())
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Deleting));
+
+ // The destructor used for destructing this as a most-derived class;
+ // call the base destructor and then destructs any virtual bases.
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Complete));
- if (Type != Dtor_Deleting)
- ResTy = ArgTys[0];
+ // The destructor used for destructing this as a base class; ignores
+ // virtual bases.
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
}
void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
@@ -796,7 +869,7 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
assert(MD->isInstance());
// Check if we need a VTT parameter as well.
- if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
+ if (NeedsVTTParameter(CGF.CurGD)) {
ASTContext &Context = getContext();
// FIXME: avoid the fake decl
@@ -809,16 +882,6 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
}
}
-void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) {
- ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params);
-
- // Return 'this' from certain constructors and destructors.
- if (HasThisReturn(CGF.CurGD))
- ResTy = Params[0]->getType();
-}
-
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
/// Initialize the 'this' slot.
EmitThisParam(CGF);
@@ -829,21 +892,23 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
"vtt");
}
-}
-void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);
-
- /// Initialize the return slot to 'this' at the start of the
- /// function.
+ /// If this is a function that the ABI specifies returns 'this', initialize
+ /// the return slot to 'this' at the start of the function.
+ ///
+ /// Unlike the setting of return types, this is done within the ABI
+ /// implementation instead of by clients of CGCXXABI because:
+ /// 1) getThisValue is currently protected
+ /// 2) in theory, an ABI could implement 'this' returns some other way;
+ /// HasThisReturn only specifies a contract, not the implementation
if (HasThisReturn(CGF.CurGD))
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
-llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -853,26 +918,217 @@ llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, VTTTy, ArgBeg, ArgEnd);
- return Callee;
+ CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(),
+ This, VTT, VTTTy, ArgBeg, ArgEnd);
+}
+
+void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
+ const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *VTable = getAddrOfVTable(RD, CharUnits());
+ if (VTable->hasInitializer())
+ return;
+
+ ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
+ const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+
+ // Create and set the initializer.
+ llvm::Constant *Init = CGVT.CreateVTableInitializer(
+ RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(),
+ VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks());
+ VTable->setInitializer(Init);
+
+ // Set the correct linkage.
+ VTable->setLinkage(Linkage);
+
+ // Set the right visibility.
+ CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable);
+
+ // If this is the magic class __cxxabiv1::__fundamental_type_info,
+ // we will emit the typeinfo for the fundamental types. This is the
+ // same behaviour as GCC.
+ const DeclContext *DC = RD->getDeclContext();
+ if (RD->getIdentifier() &&
+ RD->getIdentifier()->isStr("__fundamental_type_info") &&
+ isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
+ DC->getParent()->isTranslationUnit())
+ CGM.EmitFundamentalRTTIDescriptors();
+}
+
+llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
+ CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
+ bool NeedsVTTParam = CGM.getCXXABI().NeedsVTTParameter(CGF.CurGD);
+ NeedsVirtualOffset = (NeedsVTTParam && NearestVBase);
+
+ llvm::Value *VTableAddressPoint;
+ if (NeedsVTTParam && (Base.getBase()->getNumVBases() || NearestVBase)) {
+ // Get the secondary vpointer index.
+ uint64_t VirtualPointerIndex =
+ CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
+
+ /// Load the VTT.
+ llvm::Value *VTT = CGF.LoadCXXVTT();
+ if (VirtualPointerIndex)
+ VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
+
+ // And load the address point from the VTT.
+ VTableAddressPoint = CGF.Builder.CreateLoad(VTT);
+ } else {
+ llvm::Constant *VTable =
+ CGM.getCXXABI().getAddrOfVTable(VTableClass, CharUnits());
+ uint64_t AddressPoint = CGM.getItaniumVTableContext()
+ .getVTableLayout(VTableClass)
+ .getAddressPoint(Base);
+ VTableAddressPoint =
+ CGF.Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
+ }
+
+ return VTableAddressPoint;
}
-RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- llvm::Value *This) {
+llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
+ BaseSubobject Base, const CXXRecordDecl *VTableClass) {
+ llvm::Constant *VTable = getAddrOfVTable(VTableClass, CharUnits());
+
+ // Find the appropriate vtable within the vtable group.
+ uint64_t AddressPoint = CGM.getItaniumVTableContext()
+ .getVTableLayout(VTableClass)
+ .getAddressPoint(Base);
+ llvm::Value *Indices[] = {
+ llvm::ConstantInt::get(CGM.Int64Ty, 0),
+ llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
+ };
+
+ return llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
+}
+
+llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
+ CharUnits VPtrOffset) {
+ assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
+
+ llvm::GlobalVariable *&VTable = VTables[RD];
+ if (VTable)
+ return VTable;
+
+ // Queue up this v-table for possible deferred emission.
+ CGM.addDeferredVTable(RD);
+
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ getMangleContext().mangleCXXVTable(RD, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
+ llvm::ArrayType *ArrayType = llvm::ArrayType::get(
+ CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents());
+
+ VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
+ Name, ArrayType, llvm::GlobalValue::ExternalLinkage);
+ VTable->setUnnamedAddr(true);
+ return VTable;
+}
+
+llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) {
+ GD = GD.getCanonicalDecl();
+ Ty = Ty->getPointerTo()->getPointerTo();
+ llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
+
+ uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+ return CGF.Builder.CreateLoad(VFuncPtr);
+}
+
+void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ llvm::Value *This) {
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
const CGFunctionInfo *FInfo
= &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
+ llvm::Value *Callee =
+ getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty);
- return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
- /*ImplicitParam=*/0, QualType(), 0, 0);
+ CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
+ /*ImplicitParam=*/0, QualType(), 0, 0);
+}
+
+void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
+ CodeGenVTables &VTables = CGM.getVTables();
+ llvm::GlobalVariable *VTT = VTables.GetAddrOfVTT(RD);
+ VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
+}
+
+static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ int64_t NonVirtualAdjustment,
+ int64_t VirtualAdjustment,
+ bool IsReturnAdjustment) {
+ if (!NonVirtualAdjustment && !VirtualAdjustment)
+ return Ptr;
+
+ llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+ llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
+
+ if (NonVirtualAdjustment && !IsReturnAdjustment) {
+ // Perform the non-virtual adjustment for a base-to-derived cast.
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+ }
+
+ if (VirtualAdjustment) {
+ llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ // Perform the virtual adjustment.
+ llvm::Value *VTablePtrPtr =
+ CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
+
+ llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
+
+ llvm::Value *OffsetPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+
+ OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
+
+ // Load the adjustment offset from the vtable.
+ llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
+
+ // Adjust our pointer.
+ V = CGF.Builder.CreateInBoundsGEP(V, Offset);
+ }
+
+ if (NonVirtualAdjustment && IsReturnAdjustment) {
+ // Perform the non-virtual adjustment for a derived-to-base cast.
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+ }
+
+ // Cast back to the original type.
+ return CGF.Builder.CreateBitCast(V, Ptr->getType());
+}
+
+llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const ThisAdjustment &TA) {
+ return performTypeAdjustment(CGF, This, TA.NonVirtual,
+ TA.Virtual.Itanium.VCallOffsetOffset,
+ /*IsReturnAdjustment=*/false);
+}
+
+llvm::Value *
+ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+ const ReturnAdjustment &RA) {
+ return performTypeAdjustment(CGF, Ret, RA.NonVirtual,
+ RA.Virtual.Itanium.VBaseOffsetOffset,
+ /*IsReturnAdjustment=*/true);
}
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
@@ -1079,7 +1335,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
} else {
// Guard variables are 64 bits in the generic ABI and size width on ARM
// (i.e. 32-bit on AArch32, 64-bit on AArch64).
- guardTy = (IsARM ? CGF.SizeTy : CGF.Int64Ty);
+ guardTy = (UseARMGuardVarABI ? CGF.SizeTy : CGF.Int64Ty);
}
llvm::PointerType *guardPtrTy = guardTy->getPointerTo();
@@ -1091,7 +1347,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
SmallString<256> guardName;
{
llvm::raw_svector_ostream out(guardName);
- getMangleContext().mangleItaniumGuardVariable(&D, out);
+ getMangleContext().mangleStaticGuardVariable(&D, out);
out.flush();
}
@@ -1122,7 +1378,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// if (__cxa_guard_acquire(&obj_guard))
// ...
// }
- if (IsARM && !useInt8GuardVariable) {
+ if (UseARMGuardVarABI && !useInt8GuardVariable) {
llvm::Value *V = Builder.CreateLoad(guard);
llvm::Value *Test1 = llvm::ConstantInt::get(guardTy, 1);
V = Builder.CreateAnd(V, Test1);
@@ -1259,7 +1515,7 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
return CGM.AddCXXDtorEntry(dtor, addr);
}
- CGF.registerGlobalDtorWithAtExit(dtor, addr);
+ CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
}
/// Get the appropriate linkage for the wrapper function. This is essentially
@@ -1396,3 +1652,23 @@ LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
// FIXME: need setObjCGCLValueClass?
return LV;
}
+
+/// Return whether the given global decl needs a VTT parameter, which it does
+/// if it's a base constructor or destructor with virtual bases.
+bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index f5242eaaa2fb..7318fe72a3c3 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -16,8 +16,12 @@
#include "CGCXXABI.h"
#include "CodeGenModule.h"
+#include "CGVTables.h"
+#include "MicrosoftVBTables.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/VTableBuilder.h"
+#include "llvm/ADT/StringSet.h"
using namespace clang;
using namespace CodeGen;
@@ -28,13 +32,15 @@ class MicrosoftCXXABI : public CGCXXABI {
public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
+ bool HasThisReturn(GlobalDecl GD) const;
+
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
// Structures that are not C++03 PODs are always indirect.
return !RD->isPOD();
}
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
- if (RD->hasNonTrivialCopyConstructor())
+ if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
return RAA_DirectInMemory;
return RAA_Default;
}
@@ -44,42 +50,153 @@ public:
// arbitrary.
StringRef GetDeletedVirtualCallName() { return "_purecall"; }
+ bool isInlineInitializedStaticDataMemberLinkOnce() { return true; }
+
llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
llvm::Value *ptr,
QualType type);
+ llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
+
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
- llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+ llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD);
+
+ void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD);
+
+ void EmitCXXConstructors(const CXXConstructorDecl *D);
+
+ // Background on MSVC destructors
+ // ==============================
+ //
+ // Both Itanium and MSVC ABIs have destructor variants. The variant names
+ // roughly correspond in the following way:
+ // Itanium Microsoft
+ // Base -> no name, just ~Class
+ // Complete -> vbase destructor
+ // Deleting -> scalar deleting destructor
+ // vector deleting destructor
+ //
+ // The base and complete destructors are the same as in Itanium, although the
+ // complete destructor does not accept a VTT parameter when there are virtual
+ // bases. A separate mechanism involving vtordisps is used to ensure that
+ // virtual methods of destroyed subobjects are not called.
+ //
+ // The deleting destructors accept an i32 bitfield as a second parameter. Bit
+ // 1 indicates if the memory should be deleted. Bit 2 indicates if the this
+ // pointer points to an array. The scalar deleting destructor assumes that
+ // bit 2 is zero, and therefore does not contain a loop.
+ //
+ // For virtual destructors, only one entry is reserved in the vftable, and it
+ // always points to the vector deleting destructor. The vector deleting
+ // destructor is the most general, so it can be used to destroy objects in
+ // place, delete single heap objects, or delete arrays.
+ //
+ // A TU defining a non-inline destructor is only guaranteed to emit a base
+ // destructor, and all of the other variants are emitted on an as-needed basis
+ // in COMDATs. Because a non-base destructor can be emitted in a TU that
+ // lacks a definition for the destructor, non-base destructors must always
+ // delegate to or alias the base destructor.
- void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
+ void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
+ /// Non-base dtors should be emitted as delegating thunks in this ABI.
+ bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
+ CXXDtorType DT) const {
+ return DT != Dtor_Base;
+ }
+
+ void EmitCXXDestructors(const CXXDestructorDecl *D);
+
+ const CXXRecordDecl *getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
+ MD = MD->getCanonicalDecl();
+ if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD)) {
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
+ // The vbases might be ordered differently in the final overrider object
+ // and the complete object, so the "this" argument may sometimes point to
+ // memory that has no particular type (e.g. past the complete object).
+ // In this case, we just use a generic pointer type.
+ // FIXME: might want to have a more precise type in the non-virtual
+ // multiple inheritance case.
+ if (ML.VBase || !ML.VFPtrOffset.isZero())
+ return 0;
+ }
+ return MD->getParent();
+ }
+
+ llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This);
+
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params);
+ llvm::Value *adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This);
+
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
+ void EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
- RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- llvm::Value *This);
+ void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD);
+
+ llvm::Value *getVTableAddressPointInStructor(
+ CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
+ BaseSubobject Base, const CXXRecordDecl *NearestVBase,
+ bool &NeedsVirtualOffset);
+
+ llvm::Constant *
+ getVTableAddressPointForConstExpr(BaseSubobject Base,
+ const CXXRecordDecl *VTableClass);
+
+ llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
+ CharUnits VPtrOffset);
+
+ llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This, llvm::Type *Ty);
+
+ void EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType, SourceLocation CallLoc,
+ llvm::Value *This);
+
+ void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
+ CallArgList &CallArgs) {
+ assert(GD.getDtorType() == Dtor_Deleting &&
+ "Only deleting destructor thunks are available in this ABI");
+ CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
+ CGM.getContext().IntTy);
+ }
+
+ void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+ Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+ }
+
+ llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
+ const ThisAdjustment &TA);
+
+ llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+ const ReturnAdjustment &RA);
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
@@ -119,9 +236,12 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize);
- static bool needThisReturn(GlobalDecl GD);
private:
+ MicrosoftMangleContext &getMangleContext() {
+ return cast<MicrosoftMangleContext>(CodeGen::CGCXXABI::getMangleContext());
+ }
+
llvm::Constant *getZeroInt() {
return llvm::ConstantInt::get(CGM.IntTy, 0);
}
@@ -130,10 +250,44 @@ private:
return llvm::Constant::getAllOnesValue(CGM.IntTy);
}
+ llvm::Constant *getConstantOrZeroInt(llvm::Constant *C) {
+ return C ? C : getZeroInt();
+ }
+
+ llvm::Value *getValueOrZeroInt(llvm::Value *C) {
+ return C ? C : getZeroInt();
+ }
+
void
GetNullMemberPointerFields(const MemberPointerType *MPT,
llvm::SmallVectorImpl<llvm::Constant *> &fields);
+ /// \brief Finds the offset from the base of RD to the vbptr it uses, even if
+ /// it is reusing a vbptr from a non-virtual base. RD must have morally
+ /// virtual bases.
+ CharUnits GetVBPtrOffsetFromBases(const CXXRecordDecl *RD);
+
+ /// \brief Shared code for virtual base adjustment. Returns the offset from
+ /// the vbptr to the virtual base. Optionally returns the address of the
+ /// vbptr itself.
+ llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ llvm::Value *VBPtrOffset,
+ llvm::Value *VBTableOffset,
+ llvm::Value **VBPtr = 0);
+
+ llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ int32_t VBPtrOffset,
+ int32_t VBTableOffset,
+ llvm::Value **VBPtr = 0) {
+ llvm::Value *VBPOffset = llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
+ *VBTOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableOffset);
+ return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
+ }
+
+ /// \brief Performs a full virtual base adjustment. Used to dereference
+ /// pointers to members of virtual bases.
llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
llvm::Value *Base,
llvm::Value *VirtualBaseAdjustmentOffset,
@@ -143,7 +297,25 @@ private:
/// function member pointers.
llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
bool IsMemberFunction,
- const CXXRecordDecl *RD);
+ const CXXRecordDecl *RD,
+ CharUnits NonVirtualBaseAdjustment);
+
+ llvm::Constant *BuildMemberPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD,
+ CharUnits NonVirtualBaseAdjustment);
+
+ bool MemberPointerConstantIsNull(const MemberPointerType *MPT,
+ llvm::Constant *MP);
+
+ /// \brief - Initialize all vbptrs of 'this' with RD as the complete type.
+ void EmitVBPtrStores(CodeGenFunction &CGF, const CXXRecordDecl *RD);
+
+ /// \brief Caching wrapper around VBTableBuilder::enumerateVBTables().
+ const VBTableVector &EnumerateVBTables(const CXXRecordDecl *RD);
+
+ /// \brief Generate a thunk for calling a virtual member function MD.
+ llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ StringRef ThunkName);
public:
virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
@@ -172,12 +344,43 @@ public:
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+ virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src);
+
+ virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src);
+
virtual llvm::Value *
EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+private:
+ typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
+ typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VFTablesMapTy;
+ /// \brief All the vftables that have been referenced.
+ VFTablesMapTy VFTablesMap;
+
+ /// \brief This set holds the record decls we've deferred vtable emission for.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> DeferredVFTables;
+
+
+ /// \brief All the vbtables which have been referenced.
+ llvm::DenseMap<const CXXRecordDecl *, VBTableVector> VBTablesMap;
+
+ /// Info on the global variable used to guard initialization of static locals.
+ /// The BitIndex field is only used for externally invisible declarations.
+ struct GuardInfo {
+ GuardInfo() : Guard(0), BitIndex(0) {}
+ llvm::GlobalVariable *Guard;
+ unsigned BitIndex;
+ };
+
+ /// Map from DeclContext to the current guard variable. We assume that the
+ /// AST is visited in source code order.
+ llvm::DenseMap<const DeclContext *, GuardInfo> GuardVariableMap;
};
}
@@ -189,19 +392,65 @@ llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return ptr;
}
-bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
- const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
- return isa<CXXConstructorDecl>(MD);
+/// \brief Finds the first non-virtual base of RD that has virtual bases. If RD
+/// doesn't have a vbptr, it will reuse the vbptr of the returned class.
+static const CXXRecordDecl *FindFirstNVBaseWithVBases(const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ if (!I->isVirtual() && Base->getNumVBases() > 0)
+ return Base;
+ }
+ llvm_unreachable("RD must have an nv base with vbases");
+}
+
+CharUnits MicrosoftCXXABI::GetVBPtrOffsetFromBases(const CXXRecordDecl *RD) {
+ assert(RD->getNumVBases());
+ CharUnits Total = CharUnits::Zero();
+ while (RD) {
+ const ASTRecordLayout &RDLayout = getContext().getASTRecordLayout(RD);
+ CharUnits VBPtrOffset = RDLayout.getVBPtrOffset();
+ // -1 is the sentinel for no vbptr.
+ if (VBPtrOffset != CharUnits::fromQuantity(-1)) {
+ Total += VBPtrOffset;
+ break;
+ }
+ RD = FindFirstNVBaseWithVBases(RD);
+ Total += RDLayout.getBaseClassOffset(RD);
+ }
+ return Total;
+}
+
+llvm::Value *
+MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ int64_t VBPtrChars = GetVBPtrOffsetFromBases(ClassDecl).getQuantity();
+ llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
+ CharUnits IntSize = getContext().getTypeSizeInChars(getContext().IntTy);
+ CharUnits VBTableChars =
+ IntSize *
+ CGM.getMicrosoftVTableContext().getVBTableIndex(ClassDecl, BaseClassDecl);
+ llvm::Value *VBTableOffset =
+ llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity());
+
+ llvm::Value *VBPtrToNewBase =
+ GetVBaseOffsetFromVBPtr(CGF, This, VBPtrOffset, VBTableOffset);
+ VBPtrToNewBase =
+ CGF.Builder.CreateSExtOrBitCast(VBPtrToNewBase, CGM.PtrDiffTy);
+ return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
+}
+
+bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
+ return isa<CXXConstructorDecl>(GD.getDecl());
}
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
-
- // Ctor returns this ptr
- ResTy = ArgTys[0];
+ // 'this' parameter and 'this' return are already in place
const CXXRecordDecl *Class = Ctor->getParent();
if (Class->getNumVBases()) {
@@ -210,13 +459,14 @@ void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
}
}
-llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
- CodeGenFunction &CGF) {
+llvm::BasicBlock *
+MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {
llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
assert(IsMostDerivedClass &&
"ctor for a class with virtual bases must have an implicit parameter");
- llvm::Value *IsCompleteObject
- = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
+ llvm::Value *IsCompleteObject =
+ CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
@@ -224,24 +474,200 @@ llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
CallVbaseCtorsBB, SkipVbaseCtorsBB);
CGF.EmitBlock(CallVbaseCtorsBB);
- // FIXME: emit vbtables somewhere around here.
+
+ // Fill in the vbtable pointers here.
+ EmitVBPtrStores(CGF, RD);
// CGF will put the base ctor calls in this basic block for us later.
return SkipVbaseCtorsBB;
}
+void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
+ CodeGenFunction &CGF, const CXXRecordDecl *RD) {
+ // In most cases, an override for a vbase virtual method can adjust
+ // the "this" parameter by applying a constant offset.
+ // However, this is not enough while a constructor or a destructor of some
+ // class X is being executed if all the following conditions are met:
+ // - X has virtual bases, (1)
+ // - X overrides a virtual method M of a vbase Y, (2)
+ // - X itself is a vbase of the most derived class.
+ //
+ // If (1) and (2) are true, the vtorDisp for vbase Y is a hidden member of X
+ // which holds the extra amount of "this" adjustment we must do when we use
+ // the X vftables (i.e. during X ctor or dtor).
+ // Outside the ctors and dtors, the values of vtorDisps are zero.
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ typedef ASTRecordLayout::VBaseOffsetsMapTy VBOffsets;
+ const VBOffsets &VBaseMap = Layout.getVBaseOffsetsMap();
+ CGBuilderTy &Builder = CGF.Builder;
+
+ unsigned AS =
+ cast<llvm::PointerType>(getThisValue(CGF)->getType())->getAddressSpace();
+ llvm::Value *Int8This = 0; // Initialize lazily.
+
+ for (VBOffsets::const_iterator I = VBaseMap.begin(), E = VBaseMap.end();
+ I != E; ++I) {
+ if (!I->second.hasVtorDisp())
+ continue;
+
+ llvm::Value *VBaseOffset =
+ GetVirtualBaseClassOffset(CGF, getThisValue(CGF), RD, I->first);
+ // FIXME: it doesn't look right that we SExt in GetVirtualBaseClassOffset()
+ // just to Trunc back immediately.
+ VBaseOffset = Builder.CreateTruncOrBitCast(VBaseOffset, CGF.Int32Ty);
+ uint64_t ConstantVBaseOffset =
+ Layout.getVBaseClassOffset(I->first).getQuantity();
+
+ // vtorDisp_for_vbase = vbptr[vbase_idx] - offsetof(RD, vbase).
+ llvm::Value *VtorDispValue = Builder.CreateSub(
+ VBaseOffset, llvm::ConstantInt::get(CGM.Int32Ty, ConstantVBaseOffset),
+ "vtordisp.value");
+
+ if (!Int8This)
+ Int8This = Builder.CreateBitCast(getThisValue(CGF),
+ CGF.Int8Ty->getPointerTo(AS));
+ llvm::Value *VtorDispPtr = Builder.CreateInBoundsGEP(Int8This, VBaseOffset);
+ // vtorDisp is always the 32-bits before the vbase in the class layout.
+ VtorDispPtr = Builder.CreateConstGEP1_32(VtorDispPtr, -4);
+ VtorDispPtr = Builder.CreateBitCast(
+ VtorDispPtr, CGF.Int32Ty->getPointerTo(AS), "vtordisp.ptr");
+
+ Builder.CreateStore(VtorDispValue, VtorDispPtr);
+ }
+}
+
+void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
+ // There's only one constructor type in this ABI.
+ CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
+}
+
+void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {
+ llvm::Value *ThisInt8Ptr =
+ CGF.Builder.CreateBitCast(getThisValue(CGF), CGM.Int8PtrTy, "this.int8");
+
+ const VBTableVector &VBTables = EnumerateVBTables(RD);
+ for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
+ I != E; ++I) {
+ const ASTRecordLayout &SubobjectLayout =
+ CGM.getContext().getASTRecordLayout(I->VBPtrSubobject.getBase());
+ uint64_t Offs = (I->VBPtrSubobject.getBaseOffset() +
+ SubobjectLayout.getVBPtrOffset()).getQuantity();
+ llvm::Value *VBPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs);
+ VBPtr = CGF.Builder.CreateBitCast(VBPtr, I->GV->getType()->getPointerTo(0),
+ "vbptr." + I->ReusingBase->getName());
+ CGF.Builder.CreateStore(I->GV, VBPtr);
+ }
+}
+
void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
+
// TODO: 'for base' flag
if (Type == Dtor_Deleting) {
- // The scalar deleting destructor takes an implicit bool parameter.
- ArgTys.push_back(CGM.getContext().BoolTy);
+ // The scalar deleting destructor takes an implicit int parameter.
+ ArgTys.push_back(CGM.getContext().IntTy);
+ }
+}
+
+void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ // The TU defining a dtor is only guaranteed to emit a base destructor. All
+ // other destructor variants are delegating thunks.
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
+}
+
+llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ GD = GD.getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ // FIXME: consider splitting the vdtor vs regular method code into two
+ // functions.
+
+ GlobalDecl LookupGD = GD;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Complete dtors take a pointer to the complete object,
+ // thus don't need adjustment.
+ if (GD.getDtorType() == Dtor_Complete)
+ return This;
+
+ // There's only Dtor_Deleting in vftable but it shares the this adjustment
+ // with the base one, so look up the deleting one instead.
+ LookupGD = GlobalDecl(DD, Dtor_Deleting);
+ }
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
+
+ unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
+ llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
+ CharUnits StaticOffset = ML.VFPtrOffset;
+ if (ML.VBase) {
+ bool AvoidVirtualOffset = false;
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) {
+ // A base destructor can only be called from a complete destructor of the
+ // same record type or another destructor of a more derived type;
+ // or a constructor of the same record type if an exception is thrown.
+ assert(isa<CXXDestructorDecl>(CGF.CurGD.getDecl()) ||
+ isa<CXXConstructorDecl>(CGF.CurGD.getDecl()));
+ const CXXRecordDecl *CurRD =
+ cast<CXXMethodDecl>(CGF.CurGD.getDecl())->getParent();
+
+ if (MD->getParent() == CurRD) {
+ if (isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
+ assert(CGF.CurGD.getDtorType() == Dtor_Complete);
+ if (isa<CXXConstructorDecl>(CGF.CurGD.getDecl()))
+ assert(CGF.CurGD.getCtorType() == Ctor_Complete);
+ // We're calling the main base dtor from a complete structor,
+ // so we know the "this" offset statically.
+ AvoidVirtualOffset = true;
+ } else {
+ // Let's see if we try to call a destructor of a non-virtual base.
+ for (CXXRecordDecl::base_class_const_iterator I = CurRD->bases_begin(),
+ E = CurRD->bases_end(); I != E; ++I) {
+ if (I->getType()->getAsCXXRecordDecl() != MD->getParent())
+ continue;
+ // If we call a base destructor for a non-virtual base, we statically
+ // know where it expects the vfptr and "this" to be.
+ // The total offset should reflect the adjustment done by
+ // adjustThisParameterInVirtualFunctionPrologue().
+ AvoidVirtualOffset = true;
+ break;
+ }
+ }
+ }
+
+ if (AvoidVirtualOffset) {
+ const ASTRecordLayout &Layout =
+ CGF.getContext().getASTRecordLayout(MD->getParent());
+ StaticOffset += Layout.getVBaseClassOffset(ML.VBase);
+ } else {
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ llvm::Value *VBaseOffset =
+ GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
+ This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
+ }
+ }
+ if (!StaticOffset.isZero()) {
+ assert(StaticOffset.isPositive());
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ if (ML.VBase) {
+ // Non-virtual adjustment might result in a pointer outside the allocated
+ // object, e.g. if the final overrider class is laid out after the virtual
+ // base that declares a method in the most derived class.
+ // FIXME: Update the code that emits this adjustment in thunks prologues.
+ This = CGF.Builder.CreateConstGEP1_32(This, StaticOffset.getQuantity());
+ } else {
+ This = CGF.Builder.CreateConstInBoundsGEP1_32(This,
+ StaticOffset.getQuantity());
+ }
}
+ return This;
}
static bool IsDeletingDtor(GlobalDecl GD) {
@@ -256,9 +682,6 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
BuildThisParam(CGF, Params);
- if (needThisReturn(CGF.CurGD)) {
- ResTy = Params[0]->getType();
- }
ASTContext &Context = getContext();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
@@ -275,17 +698,71 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
= ImplicitParamDecl::Create(Context, 0,
CGF.CurGD.getDecl()->getLocation(),
&Context.Idents.get("should_call_delete"),
- Context.BoolTy);
+ Context.IntTy);
Params.push_back(ShouldDelete);
getStructorImplicitParamDecl(CGF) = ShouldDelete;
}
}
+llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ GD = GD.getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ GlobalDecl LookupGD = GD;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Complete destructors take a pointer to the complete object as a
+ // parameter, thus don't need this adjustment.
+ if (GD.getDtorType() == Dtor_Complete)
+ return This;
+
+ // There's no Dtor_Base in vftable but it shares the this adjustment with
+ // the deleting one, so look it up instead.
+ LookupGD = GlobalDecl(DD, Dtor_Deleting);
+ }
+
+ // In this ABI, every virtual function takes a pointer to one of the
+ // subobjects that first defines it as the 'this' parameter, rather than a
+ // pointer to ther final overrider subobject. Thus, we need to adjust it back
+ // to the final overrider subobject before use.
+ // See comments in the MicrosoftVFTableContext implementation for the details.
+
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
+ CharUnits Adjustment = ML.VFPtrOffset;
+ if (ML.VBase) {
+ const ASTRecordLayout &DerivedLayout =
+ CGF.getContext().getASTRecordLayout(MD->getParent());
+ Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
+ }
+
+ if (Adjustment.isZero())
+ return This;
+
+ unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
+ llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS),
+ *thisTy = This->getType();
+
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ assert(Adjustment.isPositive());
+ This =
+ CGF.Builder.CreateConstInBoundsGEP1_32(This, -Adjustment.getQuantity());
+ return CGF.Builder.CreateBitCast(This, thisTy);
+}
+
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
EmitThisParam(CGF);
- if (needThisReturn(CGF.CurGD)) {
+
+ /// If this is a function that the ABI specifies returns 'this', initialize
+ /// the return slot to 'this' at the start of the function.
+ ///
+ /// Unlike the setting of return types, this is done within the ABI
+ /// implementation instead of by clients of CGCXXABI because:
+ /// 1) getThisValue is currently protected
+ /// 2) in theory, an ABI could implement 'this' returns some other way;
+ /// HasThisReturn only specifies a contract, not the implementation
+ if (HasThisReturn(CGF.CurGD))
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
- }
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
@@ -307,9 +784,10 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
}
}
-llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
+ CXXCtorType Type,
+ bool ForVirtualBase,
bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
@@ -326,33 +804,291 @@ llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
// FIXME: Provide a source location here.
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- ImplicitParam, ImplicitParamTy,
- ArgBeg, ArgEnd);
- return Callee;
+ ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd);
+}
+
+void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
+ const CXXRecordDecl *RD) {
+ MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
+ MicrosoftVTableContext::VFPtrListTy VFPtrs = VFTContext.getVFPtrOffsets(RD);
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+
+ for (MicrosoftVTableContext::VFPtrListTy::iterator I = VFPtrs.begin(),
+ E = VFPtrs.end(); I != E; ++I) {
+ llvm::GlobalVariable *VTable = getAddrOfVTable(RD, I->VFPtrFullOffset);
+ if (VTable->hasInitializer())
+ continue;
+
+ const VTableLayout &VTLayout =
+ VFTContext.getVFTableLayout(RD, I->VFPtrFullOffset);
+ llvm::Constant *Init = CGVT.CreateVTableInitializer(
+ RD, VTLayout.vtable_component_begin(),
+ VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
+ VTLayout.getNumVTableThunks());
+ VTable->setInitializer(Init);
+
+ VTable->setLinkage(Linkage);
+ CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable);
+ }
+}
+
+llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor(
+ CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
+ NeedsVirtualOffset = (NearestVBase != 0);
+
+ llvm::Value *VTableAddressPoint =
+ getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ if (!VTableAddressPoint) {
+ assert(Base.getBase()->getNumVBases() &&
+ !CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
+ }
+ return VTableAddressPoint;
+}
+
+static void mangleVFTableName(MicrosoftMangleContext &MangleContext,
+ const CXXRecordDecl *RD, const VFPtrInfo &VFPtr,
+ SmallString<256> &Name) {
+ llvm::raw_svector_ostream Out(Name);
+ MangleContext.mangleCXXVFTable(RD, VFPtr.PathToMangle, Out);
+}
+
+llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
+ BaseSubobject Base, const CXXRecordDecl *VTableClass) {
+ llvm::Constant *VTable = getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ assert(VTable && "Couldn't find a vftable for the given base?");
+ return VTable;
+}
+
+llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
+ CharUnits VPtrOffset) {
+ // getAddrOfVTable may return 0 if asked to get an address of a vtable which
+ // shouldn't be used in the given record type. We want to cache this result in
+ // VFTablesMap, thus a simple zero check is not sufficient.
+ VFTableIdTy ID(RD, VPtrOffset);
+ VFTablesMapTy::iterator I;
+ bool Inserted;
+ llvm::tie(I, Inserted) = VFTablesMap.insert(
+ std::make_pair(ID, static_cast<llvm::GlobalVariable *>(0)));
+ if (!Inserted)
+ return I->second;
+
+ llvm::GlobalVariable *&VTable = I->second;
+
+ MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext();
+ const MicrosoftVTableContext::VFPtrListTy &VFPtrs =
+ VTContext.getVFPtrOffsets(RD);
+
+ if (DeferredVFTables.insert(RD)) {
+ // We haven't processed this record type before.
+ // Queue up this v-table for possible deferred emission.
+ CGM.addDeferredVTable(RD);
+
+#ifndef NDEBUG
+ // Create all the vftables at once in order to make sure each vftable has
+ // a unique mangled name.
+ llvm::StringSet<> ObservedMangledNames;
+ for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
+ SmallString<256> Name;
+ mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
+ if (!ObservedMangledNames.insert(Name.str()))
+ llvm_unreachable("Already saw this mangling before?");
+ }
+#endif
+ }
+
+ for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
+ if (VFPtrs[J].VFPtrFullOffset != VPtrOffset)
+ continue;
+
+ llvm::ArrayType *ArrayType = llvm::ArrayType::get(
+ CGM.Int8PtrTy,
+ VTContext.getVFTableLayout(RD, VFPtrs[J].VFPtrFullOffset)
+ .getNumVTableComponents());
+
+ SmallString<256> Name;
+ mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
+ VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
+ Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage);
+ VTable->setUnnamedAddr(true);
+ break;
+ }
+
+ return VTable;
}
-RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- llvm::Value *This) {
+llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) {
+ GD = GD.getCanonicalDecl();
+ CGBuilderTy &Builder = CGF.Builder;
+
+ Ty = Ty->getPointerTo()->getPointerTo();
+ llvm::Value *VPtr = adjustThisArgumentForVirtualCall(CGF, GD, This);
+ llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty);
+
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
+ llvm::Value *VFuncPtr =
+ Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
+ return Builder.CreateLoad(VFuncPtr);
+}
+
+void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ llvm::Value *This) {
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
// We have only one destructor in the vftable but can get both behaviors
- // by passing an implicit bool parameter.
- const CGFunctionInfo *FInfo
- = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ // by passing an implicit int parameter.
+ GlobalDecl GD(Dtor, Dtor_Deleting);
+ const CGFunctionInfo *FInfo =
+ &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, This, Ty);
+ llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
ASTContext &Context = CGF.getContext();
- llvm::Value *ImplicitParam
- = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
+ llvm::Value *ImplicitParam =
+ llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting);
- return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
- ImplicitParam, Context.BoolTy, 0, 0);
+ This = adjustThisArgumentForVirtualCall(CGF, GD, This);
+ CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
+ ImplicitParam, Context.IntTy, 0, 0);
+}
+
+const VBTableVector &
+MicrosoftCXXABI::EnumerateVBTables(const CXXRecordDecl *RD) {
+ // At this layer, we can key the cache off of a single class, which is much
+ // easier than caching at the GlobalVariable layer.
+ llvm::DenseMap<const CXXRecordDecl*, VBTableVector>::iterator I;
+ bool added;
+ llvm::tie(I, added) = VBTablesMap.insert(std::make_pair(RD, VBTableVector()));
+ VBTableVector &VBTables = I->second;
+ if (!added)
+ return VBTables;
+
+ VBTableBuilder(CGM, RD).enumerateVBTables(VBTables);
+
+ return VBTables;
+}
+
+llvm::Function *
+MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ StringRef ThunkName) {
+ // If the thunk has been generated previously, just return it.
+ if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
+ return cast<llvm::Function>(GV);
+
+ // Create the llvm::Function.
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
+ llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *ThunkFn =
+ llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
+ ThunkName.str(), &CGM.getModule());
+ assert(ThunkFn->getName() == ThunkName && "name was uniqued!");
+
+ ThunkFn->setLinkage(MD->isExternallyVisible()
+ ? llvm::GlobalValue::LinkOnceODRLinkage
+ : llvm::GlobalValue::InternalLinkage);
+
+ CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
+ CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
+
+ // Start codegen.
+ CodeGenFunction CGF(CGM);
+ CGF.StartThunk(ThunkFn, MD, FnInfo);
+
+ // Get to the Callee.
+ llvm::Value *This = CGF.LoadCXXThis();
+ llvm::Value *Callee = getVirtualFunctionPointer(CGF, MD, This, ThunkTy);
+
+ // Make the call and return the result.
+ CGF.EmitCallAndReturnForThunk(MD, Callee, 0);
+
+ return ThunkFn;
+}
+
+void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
+ const VBTableVector &VBTables = EnumerateVBTables(RD);
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+
+ for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
+ I != E; ++I) {
+ I->EmitVBTableDefinition(CGM, RD, Linkage);
+ }
+}
+
+llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
+ llvm::Value *This,
+ const ThisAdjustment &TA) {
+ if (TA.isEmpty())
+ return This;
+
+ llvm::Value *V = CGF.Builder.CreateBitCast(This, CGF.Int8PtrTy);
+
+ if (!TA.Virtual.isEmpty()) {
+ assert(TA.Virtual.Microsoft.VtordispOffset < 0);
+ // Adjust the this argument based on the vtordisp value.
+ llvm::Value *VtorDispPtr =
+ CGF.Builder.CreateConstGEP1_32(V, TA.Virtual.Microsoft.VtordispOffset);
+ VtorDispPtr =
+ CGF.Builder.CreateBitCast(VtorDispPtr, CGF.Int32Ty->getPointerTo());
+ llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp");
+ V = CGF.Builder.CreateGEP(V, CGF.Builder.CreateNeg(VtorDisp));
+
+ if (TA.Virtual.Microsoft.VBPtrOffset) {
+ // If the final overrider is defined in a virtual base other than the one
+ // that holds the vfptr, we have to use a vtordispex thunk which looks up
+ // the vbtable of the derived class.
+ assert(TA.Virtual.Microsoft.VBPtrOffset > 0);
+ assert(TA.Virtual.Microsoft.VBOffsetOffset >= 0);
+ llvm::Value *VBPtr;
+ llvm::Value *VBaseOffset =
+ GetVBaseOffsetFromVBPtr(CGF, V, -TA.Virtual.Microsoft.VBPtrOffset,
+ TA.Virtual.Microsoft.VBOffsetOffset, &VBPtr);
+ V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
+ }
+ }
+
+ if (TA.NonVirtual) {
+ // Non-virtual adjustment might result in a pointer outside the allocated
+ // object, e.g. if the final overrider class is laid out after the virtual
+ // base that declares a method in the most derived class.
+ V = CGF.Builder.CreateConstGEP1_32(V, TA.NonVirtual);
+ }
+
+ // Don't need to bitcast back, the call CodeGen will handle this.
+ return V;
+}
+
+llvm::Value *
+MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+ const ReturnAdjustment &RA) {
+ if (RA.isEmpty())
+ return Ret;
+
+ llvm::Value *V = CGF.Builder.CreateBitCast(Ret, CGF.Int8PtrTy);
+
+ if (RA.Virtual.Microsoft.VBIndex) {
+ assert(RA.Virtual.Microsoft.VBIndex > 0);
+ int32_t IntSize =
+ getContext().getTypeSizeInChars(getContext().IntTy).getQuantity();
+ llvm::Value *VBPtr;
+ llvm::Value *VBaseOffset =
+ GetVBaseOffsetFromVBPtr(CGF, V, RA.Virtual.Microsoft.VBPtrOffset,
+ IntSize * RA.Virtual.Microsoft.VBIndex, &VBPtr);
+ V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
+ }
+
+ if (RA.NonVirtual)
+ V = CGF.Builder.CreateConstInBoundsGEP1_32(V, RA.NonVirtual);
+
+ // Cast back to the original type.
+ return CGF.Builder.CreateBitCast(V, Ret->getType());
}
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
@@ -411,17 +1147,86 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
}
void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr,
+ llvm::GlobalVariable *GV,
bool PerformInit) {
- // FIXME: this code was only tested for global initialization.
- // Not sure whether we want thread-safe static local variables as VS
- // doesn't make them thread-safe.
+ // MSVC always uses an i32 bitfield to guard initialization, which is *not*
+ // threadsafe. Since the user may be linking in inline functions compiled by
+ // cl.exe, there's no reason to provide a false sense of security by using
+ // critical sections here.
if (D.getTLSKind())
CGM.ErrorUnsupported(&D, "dynamic TLS initialization");
- // Emit the initializer and add a global destructor if appropriate.
- CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::IntegerType *GuardTy = CGF.Int32Ty;
+ llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0);
+
+ // Get the guard variable for this function if we have one already.
+ GuardInfo &GI = GuardVariableMap[D.getDeclContext()];
+
+ unsigned BitIndex;
+ if (D.isExternallyVisible()) {
+ // Externally visible variables have to be numbered in Sema to properly
+ // handle unreachable VarDecls.
+ BitIndex = getContext().getManglingNumber(&D);
+ assert(BitIndex > 0);
+ BitIndex--;
+ } else {
+ // Non-externally visible variables are numbered here in CodeGen.
+ BitIndex = GI.BitIndex++;
+ }
+
+ if (BitIndex >= 32) {
+ if (D.isExternallyVisible())
+ ErrorUnsupportedABI(CGF, "more than 32 guarded initializations");
+ BitIndex %= 32;
+ GI.Guard = 0;
+ }
+
+ // Lazily create the i32 bitfield for this function.
+ if (!GI.Guard) {
+ // Mangle the name for the guard.
+ SmallString<256> GuardName;
+ {
+ llvm::raw_svector_ostream Out(GuardName);
+ getMangleContext().mangleStaticGuardVariable(&D, Out);
+ Out.flush();
+ }
+
+ // Create the guard variable with a zero-initializer. Just absorb linkage
+ // and visibility from the guarded variable.
+ GI.Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false,
+ GV->getLinkage(), Zero, GuardName.str());
+ GI.Guard->setVisibility(GV->getVisibility());
+ } else {
+ assert(GI.Guard->getLinkage() == GV->getLinkage() &&
+ "static local from the same function had different linkage");
+ }
+
+ // Pseudo code for the test:
+ // if (!(GuardVar & MyGuardBit)) {
+ // GuardVar |= MyGuardBit;
+ // ... initialize the object ...;
+ // }
+
+ // Test our bit from the guard variable.
+ llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1U << BitIndex);
+ llvm::LoadInst *LI = Builder.CreateLoad(GI.Guard);
+ llvm::Value *IsInitialized =
+ Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero);
+ llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
+ llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
+ Builder.CreateCondBr(IsInitialized, EndBlock, InitBlock);
+
+ // Set our bit in the guard variable and emit the initializer and add a global
+ // destructor if appropriate.
+ CGF.EmitBlock(InitBlock);
+ Builder.CreateStore(Builder.CreateOr(LI, Bit), GI.Guard);
+ CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
+ Builder.CreateBr(EndBlock);
+
+ // Continue.
+ CGF.EmitBlock(EndBlock);
}
// Member pointer helpers.
@@ -429,8 +1234,10 @@ static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) {
return Inheritance == MSIM_Unspecified;
}
-static bool hasOnlyOneField(MSInheritanceModel Inheritance) {
- return Inheritance <= MSIM_SinglePolymorphic;
+static bool hasOnlyOneField(bool IsMemberFunction,
+ MSInheritanceModel Inheritance) {
+ return Inheritance <= MSIM_SinglePolymorphic ||
+ (!IsMemberFunction && Inheritance <= MSIM_MultiplePolymorphic);
}
// Only member pointers to functions need a this adjustment, since it can be
@@ -531,27 +1338,28 @@ MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
llvm::Constant *
MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
bool IsMemberFunction,
- const CXXRecordDecl *RD)
+ const CXXRecordDecl *RD,
+ CharUnits NonVirtualBaseAdjustment)
{
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
// Single inheritance class member pointer are represented as scalars instead
// of aggregates.
- if (hasOnlyOneField(Inheritance))
+ if (hasOnlyOneField(IsMemberFunction, Inheritance))
return FirstField;
llvm::SmallVector<llvm::Constant *, 4> fields;
fields.push_back(FirstField);
if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
- fields.push_back(getZeroInt());
+ fields.push_back(llvm::ConstantInt::get(
+ CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
if (hasVBPtrOffsetField(Inheritance)) {
- int64_t VBPtrOffset =
- getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
- if (VBPtrOffset == -1)
- VBPtrOffset = 0;
- fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset));
+ CharUnits Offs = CharUnits::Zero();
+ if (RD->getNumVBases())
+ Offs = GetVBPtrOffsetFromBases(RD);
+ fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Offs.getQuantity()));
}
// The rest of the fields are adjusted by conversions to a more derived class.
@@ -567,22 +1375,44 @@ MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
llvm::Constant *FirstField =
llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
- return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD);
+ return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
+ CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+ return BuildMemberPointer(MD->getParent(), MD, CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
+ QualType MPType) {
+ const MemberPointerType *MPT = MPType->castAs<MemberPointerType>();
+ const ValueDecl *MPD = MP.getMemberPointerDecl();
+ if (!MPD)
+ return EmitNullMemberPointer(MPT);
+
+ CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP);
+
+ // FIXME PR15713: Support virtual inheritance paths.
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
+ return BuildMemberPointer(MPT->getClass()->getAsCXXRecordDecl(),
+ MD, ThisAdjustment);
+
+ CharUnits FieldOffset =
+ getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
+ return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset);
}
llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD,
+ CharUnits NonVirtualBaseAdjustment) {
assert(MD->isInstance() && "Member function must not be static!");
MD = MD->getCanonicalDecl();
- const CXXRecordDecl *RD = MD->getParent();
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
- if (MD->isVirtual()) {
- // FIXME: We have to instantiate a thunk that loads the vftable and jumps to
- // the right offset.
- FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
- } else {
+ if (!MD->isVirtual()) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
@@ -596,18 +1426,38 @@ MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
}
FirstField = CGM.GetAddrOfFunction(MD, Ty);
FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
+ } else {
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
+ if (MD->isVariadic()) {
+ CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (!CGM.getTypes().isFuncTypeConvertible(
+ MD->getType()->castAs<FunctionType>())) {
+ CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
+ "incomplete return or parameter type");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (ML.VBase) {
+ CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
+ "member function in virtual base class");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else {
+ SmallString<256> ThunkName;
+ CharUnits PointerWidth = getContext().toCharUnitsFromBits(
+ getContext().getTargetInfo().getPointerWidth(0));
+ uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
+ llvm::raw_svector_ostream Out(ThunkName);
+ getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out);
+ Out.flush();
+
+ llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str());
+ FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
+ }
}
// The rest of the fields are common with data member pointers.
- return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD);
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
- // FIXME PR15875: Implement member pointer conversions for Constants.
- const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
- return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy),
- /*IsMemberFunction=*/true, RD);
+ return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD,
+ NonVirtualBaseAdjustment);
}
/// Member pointers are the same if they're either bitwise identical *or* both
@@ -638,7 +1488,7 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
// single icmp.
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- if (hasOnlyOneField(Inheritance))
+ if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance))
return Builder.CreateICmp(Eq, L, R);
// Compare the first field.
@@ -703,12 +1553,64 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
return Res;
}
+bool MicrosoftCXXABI::MemberPointerConstantIsNull(const MemberPointerType *MPT,
+ llvm::Constant *Val) {
+ // Function pointers are null if the pointer in the first field is null.
+ if (MPT->isMemberFunctionPointer()) {
+ llvm::Constant *FirstField = Val->getType()->isStructTy() ?
+ Val->getAggregateElement(0U) : Val;
+ return FirstField->isNullValue();
+ }
+
+ // If it's not a function pointer and it's zero initializable, we can easily
+ // check zero.
+ if (isZeroInitializable(MPT) && Val->isNullValue())
+ return true;
+
+ // Otherwise, break down all the fields for comparison. Hopefully these
+ // little Constants are reused, while a big null struct might not be.
+ llvm::SmallVector<llvm::Constant *, 4> Fields;
+ GetNullMemberPointerFields(MPT, Fields);
+ if (Fields.size() == 1) {
+ assert(Val->getType()->isIntegerTy());
+ return Val == Fields[0];
+ }
+
+ unsigned I, E;
+ for (I = 0, E = Fields.size(); I != E; ++I) {
+ if (Val->getAggregateElement(I) != Fields[I])
+ break;
+ }
+ return I == E;
+}
+
+llvm::Value *
+MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
+ llvm::Value *This,
+ llvm::Value *VBPtrOffset,
+ llvm::Value *VBTableOffset,
+ llvm::Value **VBPtrOut) {
+ CGBuilderTy &Builder = CGF.Builder;
+ // Load the vbtable pointer from the vbptr in the instance.
+ This = Builder.CreateBitCast(This, CGM.Int8PtrTy);
+ llvm::Value *VBPtr =
+ Builder.CreateInBoundsGEP(This, VBPtrOffset, "vbptr");
+ if (VBPtrOut) *VBPtrOut = VBPtr;
+ VBPtr = Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
+ llvm::Value *VBTable = Builder.CreateLoad(VBPtr, "vbtable");
+
+ // Load an i32 offset from the vb-table.
+ llvm::Value *VBaseOffs = Builder.CreateInBoundsGEP(VBTable, VBTableOffset);
+ VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
+ return Builder.CreateLoad(VBaseOffs, "vbase_offs");
+}
+
// Returns an adjusted base cast to i8*, since we do more address arithmetic on
// it.
llvm::Value *
MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
const CXXRecordDecl *RD, llvm::Value *Base,
- llvm::Value *VirtualBaseAdjustmentOffset,
+ llvm::Value *VBTableOffset,
llvm::Value *VBPtrOffset) {
CGBuilderTy &Builder = CGF.Builder;
Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy);
@@ -725,7 +1627,7 @@ MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust");
SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust");
llvm::Value *IsVirtual =
- Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(),
+ Builder.CreateICmpNE(VBTableOffset, getZeroInt(),
"memptr.is_vbase");
Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB);
CGF.EmitBlock(VBaseAdjustBB);
@@ -734,21 +1636,15 @@ MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
// If we weren't given a dynamic vbptr offset, RD should be complete and we'll
// know the vbptr offset.
if (!VBPtrOffset) {
- CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
+ CharUnits offs = CharUnits::Zero();
+ if (RD->getNumVBases()) {
+ offs = GetVBPtrOffsetFromBases(RD);
+ }
VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
}
- // Load the vbtable pointer from the vbtable offset in the instance.
- llvm::Value *VBPtr =
- Builder.CreateInBoundsGEP(Base, VBPtrOffset, "memptr.vbptr");
- llvm::Value *VBTable =
- Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
- VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable");
- // Load an i32 offset from the vb-table.
+ llvm::Value *VBPtr = 0;
llvm::Value *VBaseOffs =
- Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset);
- VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
- VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs");
- // Add it to VBPtr. GEP will sign extend the i32 value for us.
+ GetVBaseOffsetFromVBPtr(CGF, Base, VBPtrOffset, VBTableOffset, &VBPtr);
llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
// Merge control flow with the case where we didn't have to adjust.
@@ -803,6 +1699,194 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
return Builder.CreateBitCast(Addr, PType);
}
+static MSInheritanceModel
+getInheritanceFromMemptr(const MemberPointerType *MPT) {
+ return MPT->getClass()->getAsCXXRecordDecl()->getMSInheritanceModel();
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src) {
+ assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
+ E->getCastKind() == CK_BaseToDerivedMemberPointer ||
+ E->getCastKind() == CK_ReinterpretMemberPointer);
+
+ // Use constant emission if we can.
+ if (isa<llvm::Constant>(Src))
+ return EmitMemberPointerConversion(E, cast<llvm::Constant>(Src));
+
+ // We may be adding or dropping fields from the member pointer, so we need
+ // both types and the inheritance models of both records.
+ const MemberPointerType *SrcTy =
+ E->getSubExpr()->getType()->castAs<MemberPointerType>();
+ const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+ MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+ MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+ bool IsFunc = SrcTy->isMemberFunctionPointer();
+
+ // If the classes use the same null representation, reinterpret_cast is a nop.
+ bool IsReinterpret = E->getCastKind() == CK_ReinterpretMemberPointer;
+ if (IsReinterpret && (IsFunc ||
+ nullFieldOffsetIsZero(SrcInheritance) ==
+ nullFieldOffsetIsZero(DstInheritance)))
+ return Src;
+
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // Branch past the conversion if Src is null.
+ llvm::Value *IsNotNull = EmitMemberPointerIsNotNull(CGF, Src, SrcTy);
+ llvm::Constant *DstNull = EmitNullMemberPointer(DstTy);
+
+ // C++ 5.2.10p9: The null member pointer value is converted to the null member
+ // pointer value of the destination type.
+ if (IsReinterpret) {
+ // For reinterpret casts, sema ensures that src and dst are both functions
+ // or data and have the same size, which means the LLVM types should match.
+ assert(Src->getType() == DstNull->getType());
+ return Builder.CreateSelect(IsNotNull, Src, DstNull);
+ }
+
+ llvm::BasicBlock *OriginalBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *ConvertBB = CGF.createBasicBlock("memptr.convert");
+ llvm::BasicBlock *ContinueBB = CGF.createBasicBlock("memptr.converted");
+ Builder.CreateCondBr(IsNotNull, ConvertBB, ContinueBB);
+ CGF.EmitBlock(ConvertBB);
+
+ // Decompose src.
+ llvm::Value *FirstField = Src;
+ llvm::Value *NonVirtualBaseAdjustment = 0;
+ llvm::Value *VirtualBaseAdjustmentOffset = 0;
+ llvm::Value *VBPtrOffset = 0;
+ if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ // We need to extract values.
+ unsigned I = 0;
+ FirstField = Builder.CreateExtractValue(Src, I++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
+ if (hasVBPtrOffsetField(SrcInheritance))
+ VBPtrOffset = Builder.CreateExtractValue(Src, I++);
+ if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
+ }
+
+ // For data pointers, we adjust the field offset directly. For functions, we
+ // have a separate field.
+ llvm::Constant *Adj = getMemberPointerAdjustment(E);
+ if (Adj) {
+ Adj = llvm::ConstantExpr::getTruncOrBitCast(Adj, CGM.IntTy);
+ llvm::Value *&NVAdjustField = IsFunc ? NonVirtualBaseAdjustment : FirstField;
+ bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+ if (!NVAdjustField) // If this field didn't exist in src, it's zero.
+ NVAdjustField = getZeroInt();
+ if (isDerivedToBase)
+ NVAdjustField = Builder.CreateNSWSub(NVAdjustField, Adj, "adj");
+ else
+ NVAdjustField = Builder.CreateNSWAdd(NVAdjustField, Adj, "adj");
+ }
+
+ // FIXME PR15713: Support conversions through virtually derived classes.
+
+ // Recompose dst from the null struct and the adjusted fields from src.
+ llvm::Value *Dst;
+ if (hasOnlyOneField(IsFunc, DstInheritance)) {
+ Dst = FirstField;
+ } else {
+ Dst = llvm::UndefValue::get(DstNull->getType());
+ unsigned Idx = 0;
+ Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(NonVirtualBaseAdjustment), Idx++);
+ if (hasVBPtrOffsetField(DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(VBPtrOffset), Idx++);
+ if (hasVirtualBaseAdjustmentField(DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(VirtualBaseAdjustmentOffset), Idx++);
+ }
+ Builder.CreateBr(ContinueBB);
+
+ // In the continuation, choose between DstNull and Dst.
+ CGF.EmitBlock(ContinueBB);
+ llvm::PHINode *Phi = Builder.CreatePHI(DstNull->getType(), 2, "memptr.converted");
+ Phi->addIncoming(DstNull, OriginalBB);
+ Phi->addIncoming(Dst, ConvertBB);
+ return Phi;
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src) {
+ const MemberPointerType *SrcTy =
+ E->getSubExpr()->getType()->castAs<MemberPointerType>();
+ const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+
+ // If src is null, emit a new null for dst. We can't return src because dst
+ // might have a new representation.
+ if (MemberPointerConstantIsNull(SrcTy, Src))
+ return EmitNullMemberPointer(DstTy);
+
+ // We don't need to do anything for reinterpret_casts of non-null member
+ // pointers. We should only get here when the two type representations have
+ // the same size.
+ if (E->getCastKind() == CK_ReinterpretMemberPointer)
+ return Src;
+
+ MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+ MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+
+ // Decompose src.
+ llvm::Constant *FirstField = Src;
+ llvm::Constant *NonVirtualBaseAdjustment = 0;
+ llvm::Constant *VirtualBaseAdjustmentOffset = 0;
+ llvm::Constant *VBPtrOffset = 0;
+ bool IsFunc = SrcTy->isMemberFunctionPointer();
+ if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ // We need to extract values.
+ unsigned I = 0;
+ FirstField = Src->getAggregateElement(I++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ NonVirtualBaseAdjustment = Src->getAggregateElement(I++);
+ if (hasVBPtrOffsetField(SrcInheritance))
+ VBPtrOffset = Src->getAggregateElement(I++);
+ if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++);
+ }
+
+ // For data pointers, we adjust the field offset directly. For functions, we
+ // have a separate field.
+ llvm::Constant *Adj = getMemberPointerAdjustment(E);
+ if (Adj) {
+ Adj = llvm::ConstantExpr::getTruncOrBitCast(Adj, CGM.IntTy);
+ llvm::Constant *&NVAdjustField =
+ IsFunc ? NonVirtualBaseAdjustment : FirstField;
+ bool IsDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+ if (!NVAdjustField) // If this field didn't exist in src, it's zero.
+ NVAdjustField = getZeroInt();
+ if (IsDerivedToBase)
+ NVAdjustField = llvm::ConstantExpr::getNSWSub(NVAdjustField, Adj);
+ else
+ NVAdjustField = llvm::ConstantExpr::getNSWAdd(NVAdjustField, Adj);
+ }
+
+ // FIXME PR15713: Support conversions through virtually derived classes.
+
+ // Recompose dst from the null struct and the adjusted fields from src.
+ if (hasOnlyOneField(IsFunc, DstInheritance))
+ return FirstField;
+
+ llvm::SmallVector<llvm::Constant *, 4> Fields;
+ Fields.push_back(FirstField);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment));
+ if (hasVBPtrOffsetField(DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(VBPtrOffset));
+ if (hasVirtualBaseAdjustmentField(DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset));
+ return llvm::ConstantStruct::getAnon(Fields);
+}
+
llvm::Value *
MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
@@ -855,4 +1939,3 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
return new MicrosoftCXXABI(CGM);
}
-
diff --git a/lib/CodeGen/MicrosoftVBTables.cpp b/lib/CodeGen/MicrosoftVBTables.cpp
new file mode 100644
index 000000000000..dabf52c1ccc1
--- /dev/null
+++ b/lib/CodeGen/MicrosoftVBTables.cpp
@@ -0,0 +1,233 @@
+//===--- MicrosoftVBTables.cpp - Virtual Base Table Emission --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class generates data about MSVC virtual base tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MicrosoftVBTables.h"
+#include "CodeGenModule.h"
+#include "CGCXXABI.h"
+
+namespace clang {
+namespace CodeGen {
+
+/// Holds intermediate data about a path to a vbptr inside a base subobject.
+struct VBTablePath {
+ VBTablePath(const VBTableInfo &VBInfo)
+ : VBInfo(VBInfo), NextBase(VBInfo.VBPtrSubobject.getBase()) { }
+
+ /// All the data needed to build a vbtable, minus the GlobalVariable whose
+ /// name we haven't computed yet.
+ VBTableInfo VBInfo;
+
+ /// Next base to use for disambiguation. Can be null if we've already
+ /// disambiguated this path once.
+ const CXXRecordDecl *NextBase;
+
+ /// Path is not really a full path like a CXXBasePath. It holds the subset of
+ /// records that need to be mangled into the vbtable symbol name in order to get
+ /// a unique name.
+ llvm::SmallVector<const CXXRecordDecl *, 1> Path;
+};
+
+VBTableBuilder::VBTableBuilder(CodeGenModule &CGM,
+ const CXXRecordDecl *MostDerived)
+ : CGM(CGM), MostDerived(MostDerived),
+ DerivedLayout(CGM.getContext().getASTRecordLayout(MostDerived)) {}
+
+void VBTableBuilder::enumerateVBTables(VBTableVector &VBTables) {
+ VBTablePathVector Paths;
+ findUnambiguousPaths(MostDerived, BaseSubobject(MostDerived,
+ CharUnits::Zero()), Paths);
+ for (VBTablePathVector::iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ VBTablePath *P = *I;
+ P->VBInfo.GV = getAddrOfVBTable(P->VBInfo.ReusingBase, P->Path);
+ VBTables.push_back(P->VBInfo);
+ }
+}
+
+
+void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
+ BaseSubobject CurSubobject,
+ VBTablePathVector &Paths) {
+ size_t PathsStart = Paths.size();
+ bool ReuseVBPtrFromBase = true;
+ const CXXRecordDecl *CurBase = CurSubobject.getBase();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase);
+
+ // If this base has a vbptr, then we've found a path. These are not full
+ // paths, so we don't use CXXBasePath.
+ if (Layout.hasOwnVBPtr()) {
+ ReuseVBPtrFromBase = false;
+ VBTablePath *Info = new VBTablePath(
+ VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0));
+ Paths.push_back(Info);
+ }
+
+ // Recurse onto any bases which themselves have virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(),
+ E = CurBase->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ if (!Base->getNumVBases())
+ continue; // Bases without virtual bases have no vbptrs.
+ CharUnits NextOffset;
+ const CXXRecordDecl *NextReusingBase = Base;
+ if (I->isVirtual()) {
+ if (!VBasesSeen.insert(Base))
+ continue; // Don't visit virtual bases twice.
+ NextOffset = DerivedLayout.getVBaseClassOffset(Base);
+ } else {
+ NextOffset = (CurSubobject.getBaseOffset() +
+ Layout.getBaseClassOffset(Base));
+
+ // If CurBase didn't have a vbptr, then ReusingBase will reuse the vbptr
+ // from the first non-virtual base with vbases for its vbptr.
+ if (ReuseVBPtrFromBase) {
+ NextReusingBase = ReusingBase;
+ ReuseVBPtrFromBase = false;
+ }
+ }
+
+ size_t NumPaths = Paths.size();
+ findUnambiguousPaths(NextReusingBase, BaseSubobject(Base, NextOffset),
+ Paths);
+
+ // Tag paths through this base with the base itself. We might use it to
+ // disambiguate.
+ for (size_t I = NumPaths, E = Paths.size(); I != E; ++I)
+ Paths[I]->NextBase = Base;
+ }
+
+ bool AmbiguousPaths = rebucketPaths(Paths, PathsStart);
+ if (AmbiguousPaths)
+ rebucketPaths(Paths, PathsStart, /*SecondPass=*/true);
+
+#ifndef NDEBUG
+ // Check that the paths are in fact unique.
+ for (size_t I = PathsStart + 1, E = Paths.size(); I != E; ++I) {
+ assert(Paths[I]->Path != Paths[I - 1]->Path && "vbtable paths are not unique");
+ }
+#endif
+}
+
+static bool pathCompare(VBTablePath *LHS, VBTablePath *RHS) {
+ return LHS->Path < RHS->Path;
+}
+
+void VBTableBuilder::extendPath(VBTablePath *P, bool SecondPass) {
+ assert(P->NextBase || SecondPass);
+ if (P->NextBase) {
+ P->Path.push_back(P->NextBase);
+ P->NextBase = 0; // Prevent the path from being extended twice.
+ }
+}
+
+bool VBTableBuilder::rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
+ bool SecondPass) {
+ // What we're essentially doing here is bucketing together ambiguous paths.
+ // Any bucket with more than one path in it gets extended by NextBase, which
+ // is usually the direct base of the inherited the vbptr. This code uses a
+ // sorted vector to implement a multiset to form the buckets. Note that the
+ // ordering is based on pointers, but it doesn't change our output order. The
+ // current algorithm is designed to match MSVC 2012's names.
+ // TODO: Implement MSVC 2010 or earlier names to avoid extra vbtable cruft.
+ VBTablePathVector PathsSorted(&Paths[PathsStart], &Paths.back() + 1);
+ std::sort(PathsSorted.begin(), PathsSorted.end(), pathCompare);
+ bool AmbiguousPaths = false;
+ for (size_t I = 0, E = PathsSorted.size(); I != E;) {
+ // Scan forward to find the end of the bucket.
+ size_t BucketStart = I;
+ do {
+ ++I;
+ } while (I != E && PathsSorted[BucketStart]->Path == PathsSorted[I]->Path);
+
+ // If this bucket has multiple paths, extend them all.
+ if (I - BucketStart > 1) {
+ AmbiguousPaths = true;
+ for (size_t II = BucketStart; II != I; ++II)
+ extendPath(PathsSorted[II], SecondPass);
+ }
+ }
+ return AmbiguousPaths;
+}
+
+llvm::GlobalVariable *
+VBTableBuilder::getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
+ ArrayRef<const CXXRecordDecl *> BasePath) {
+ // Caching at this layer is redundant with the caching in EnumerateVBTables().
+
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ MicrosoftMangleContext &Mangler =
+ cast<MicrosoftMangleContext>(CGM.getCXXABI().getMangleContext());
+ Mangler.mangleCXXVBTable(MostDerived, BasePath, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ llvm::ArrayType *VBTableType =
+ llvm::ArrayType::get(CGM.IntTy, 1 + ReusingBase->getNumVBases());
+
+ assert(!CGM.getModule().getNamedGlobal(Name) &&
+ "vbtable with this name already exists: mangling bug?");
+ llvm::GlobalVariable *VBTable =
+ CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType,
+ llvm::GlobalValue::ExternalLinkage);
+ VBTable->setUnnamedAddr(true);
+ return VBTable;
+}
+
+void VBTableInfo::EmitVBTableDefinition(
+ CodeGenModule &CGM, const CXXRecordDecl *RD,
+ llvm::GlobalVariable::LinkageTypes Linkage) const {
+ assert(RD->getNumVBases() && ReusingBase->getNumVBases() &&
+ "should only emit vbtables for classes with vbtables");
+
+ const ASTRecordLayout &BaseLayout =
+ CGM.getContext().getASTRecordLayout(VBPtrSubobject.getBase());
+ const ASTRecordLayout &DerivedLayout =
+ CGM.getContext().getASTRecordLayout(RD);
+
+ SmallVector<llvm::Constant *, 4> Offsets(1 + ReusingBase->getNumVBases(), 0);
+
+ // The offset from ReusingBase's vbptr to itself always leads.
+ CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset();
+ Offsets[0] = llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity());
+
+ MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
+ for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(),
+ E = ReusingBase->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl();
+ CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase);
+ assert(!Offset.isNegative());
+ // Make it relative to the subobject vbptr.
+ Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset;
+ unsigned VBIndex = Context.getVBTableIndex(ReusingBase, VBase);
+ assert(Offsets[VBIndex] == 0 && "The same vbindex seen twice?");
+ Offsets[VBIndex] = llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity());
+ }
+
+ assert(Offsets.size() ==
+ cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType())
+ ->getElementType())->getNumElements());
+ llvm::ArrayType *VBTableType =
+ llvm::ArrayType::get(CGM.IntTy, Offsets.size());
+ llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
+ GV->setInitializer(Init);
+
+ // Set the correct linkage.
+ GV->setLinkage(Linkage);
+
+ // Set the right visibility.
+ CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForVTable);
+}
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/lib/CodeGen/MicrosoftVBTables.h b/lib/CodeGen/MicrosoftVBTables.h
new file mode 100644
index 000000000000..4ad8e07582ef
--- /dev/null
+++ b/lib/CodeGen/MicrosoftVBTables.h
@@ -0,0 +1,129 @@
+//===--- MicrosoftVBTables.h - Virtual Base Table Emission ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class generates data about MSVC virtual base tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/BaseSubobject.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/GlobalVariable.h"
+#include <vector>
+
+namespace clang {
+
+class ASTRecordLayout;
+
+namespace CodeGen {
+
+class CodeGenModule;
+
+struct VBTableInfo {
+ VBTableInfo(const CXXRecordDecl *ReusingBase, BaseSubobject VBPtrSubobject,
+ llvm::GlobalVariable *GV)
+ : ReusingBase(ReusingBase), VBPtrSubobject(VBPtrSubobject), GV(GV) { }
+
+ /// The vbtable will hold all of the virtual bases of ReusingBase. This may
+ /// or may not be the same class as VBPtrSubobject.Base. A derived class will
+ /// reuse the vbptr of the first non-virtual base subobject that has one.
+ const CXXRecordDecl *ReusingBase;
+
+ /// The vbptr is stored inside this subobject.
+ BaseSubobject VBPtrSubobject;
+
+ /// The GlobalVariable for this vbtable.
+ llvm::GlobalVariable *GV;
+
+ /// \brief Emits a definition for GV by setting it's initializer.
+ void EmitVBTableDefinition(CodeGenModule &CGM, const CXXRecordDecl *RD,
+ llvm::GlobalVariable::LinkageTypes Linkage) const;
+};
+
+// These are embedded in a DenseMap and the elements are large, so we don't want
+// SmallVector.
+typedef std::vector<VBTableInfo> VBTableVector;
+
+struct VBTablePath;
+
+typedef llvm::SmallVector<VBTablePath *, 6> VBTablePathVector;
+
+/// Produces MSVC-compatible vbtable data. The symbols produced by this builder
+/// match those produced by MSVC 2012, which is different from MSVC 2010.
+///
+/// Unlike Itanium, which uses only one vtable per class, MSVC uses a different
+/// symbol for every "address point" installed in base subobjects. As a result,
+/// we have to compute unique symbols for every table. Since there can be
+/// multiple non-virtual base subobjects of the same class, combining the most
+/// derived class with the base containing the vtable is insufficient. The most
+/// trivial algorithm would be to mangle in the entire path from base to most
+/// derived, but that would be too easy and would create unnecessarily large
+/// symbols. ;)
+///
+/// MSVC 2012 appears to minimize the vbtable names using the following
+/// algorithm. First, walk the class hierarchy in the usual order, depth first,
+/// left to right, to find all of the subobjects which contain a vbptr field.
+/// Visiting each class node yields a list of inheritance paths to vbptrs. Each
+/// record with a vbptr creates an initially empty path.
+///
+/// To combine paths from child nodes, the paths are compared to check for
+/// ambiguity. Paths are "ambiguous" if multiple paths have the same set of
+/// components in the same order. Each group of ambiguous paths is extended by
+/// appending the class of the base from which it came. If the current class
+/// node produced an ambiguous path, its path is extended with the current class.
+/// After extending paths, MSVC again checks for ambiguity, and extends any
+/// ambiguous path which wasn't already extended. Because each node yields an
+/// unambiguous set of paths, MSVC doesn't need to extend any path more than once
+/// to produce an unambiguous set of paths.
+///
+/// The VBTableBuilder class attempts to implement this algorithm by repeatedly
+/// bucketing paths together by sorting them.
+///
+/// TODO: Presumably vftables use the same algorithm.
+///
+/// TODO: Implement the MSVC 2010 name mangling scheme to avoid emitting
+/// duplicate vbtables with different symbols.
+class VBTableBuilder {
+public:
+ VBTableBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerived);
+
+ void enumerateVBTables(VBTableVector &VBTables);
+
+private:
+ bool hasVBPtr(const CXXRecordDecl *RD);
+
+ llvm::GlobalVariable *getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
+ ArrayRef<const CXXRecordDecl *> BasePath);
+
+ /// Enumerates paths to bases with vbptrs. The paths elements are compressed
+ /// to contain only the classes necessary to form an unambiguous path.
+ void findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
+ BaseSubobject CurSubobject,
+ VBTablePathVector &Paths);
+
+ void extendPath(VBTablePath *Info, bool SecondPass);
+
+ bool rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
+ bool SecondPass = false);
+
+ CodeGenModule &CGM;
+
+ const CXXRecordDecl *MostDerived;
+
+ /// Caches the layout of the most derived class.
+ const ASTRecordLayout &DerivedLayout;
+
+ /// Set of vbases to avoid re-visiting the same vbases.
+ llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
+};
+
+} // namespace CodeGen
+
+} // namespace clang
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 69e5b323045c..bc7acbc39cab 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -13,6 +13,7 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "CodeGenModule.h"
+#include "CGDebugInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -20,6 +21,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -58,13 +60,22 @@ namespace {
TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD,
Diags));
+
+ for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; ++i)
+ HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
}
virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ if (Diags.hasErrorOccurred())
+ return;
+
Builder->HandleCXXStaticMemberVarInstantiation(VD);
}
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ if (Diags.hasErrorOccurred())
+ return true;
+
// Make sure to emit all elements of a Decl.
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
Builder->EmitTopLevelDecl(*I);
@@ -76,6 +87,9 @@ namespace {
/// client hack on the type, which can occur at any point in the file
/// (because these can be defined in declspecs).
virtual void HandleTagDeclDefinition(TagDecl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
Builder->UpdateCompletedType(D);
// In C++, we may have member functions that need to be emitted at this
@@ -92,6 +106,15 @@ namespace {
}
}
+ virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) LLVM_OVERRIDE {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ DI->completeRequiredType(RD);
+ }
+
virtual void HandleTranslationUnit(ASTContext &Ctx) {
if (Diags.hasErrorOccurred()) {
M.reset();
@@ -115,6 +138,19 @@ namespace {
Builder->EmitVTable(RD, DefinitionRequired);
}
+
+ virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ Builder->AppendLinkerOptions(Opts);
+ }
+
+ virtual void HandleDetectMismatch(llvm::StringRef Name,
+ llvm::StringRef Value) {
+ Builder->AddDetectMismatch(Name, Value);
+ }
+
+ virtual void HandleDependentLibrary(llvm::StringRef Lib) {
+ Builder->AddDependentLib(Lib);
+ }
};
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 32b27b3172a6..76acf871da26 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -17,6 +17,7 @@
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
@@ -44,35 +45,40 @@ static bool isAggregateTypeForABI(QualType T) {
ABIInfo::~ABIInfo() {}
-static bool isRecordReturnIndirect(const RecordType *RT, CodeGen::CodeGenTypes &CGT) {
+static bool isRecordReturnIndirect(const RecordType *RT,
+ CGCXXABI &CXXABI) {
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return false;
- return CGT.CGM.getCXXABI().isReturnTypeIndirect(RD);
+ return CXXABI.isReturnTypeIndirect(RD);
}
-static bool isRecordReturnIndirect(QualType T, CodeGen::CodeGenTypes &CGT) {
+static bool isRecordReturnIndirect(QualType T, CGCXXABI &CXXABI) {
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return false;
- return isRecordReturnIndirect(RT, CGT);
+ return isRecordReturnIndirect(RT, CXXABI);
}
static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
- CodeGen::CodeGenTypes &CGT) {
+ CGCXXABI &CXXABI) {
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return CGCXXABI::RAA_Default;
- return CGT.CGM.getCXXABI().getRecordArgABI(RD);
+ return CXXABI.getRecordArgABI(RD);
}
static CGCXXABI::RecordArgABI getRecordArgABI(QualType T,
- CodeGen::CodeGenTypes &CGT) {
+ CGCXXABI &CXXABI) {
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return CGCXXABI::RAA_Default;
- return getRecordArgABI(RT, CGT);
+ return getRecordArgABI(RT, CXXABI);
+}
+
+CGCXXABI &ABIInfo::getCXXABI() const {
+ return CGT.getCXXABI();
}
ASTContext &ABIInfo::getContext() const {
@@ -143,6 +149,16 @@ bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
return false;
}
+void
+TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const {
+ // This assumes the user is passing a library name like "rt" instead of a
+ // filename like "librt.a/so", and that they don't care whether it's static or
+ // dynamic.
+ Opt = "-l";
+ Opt += Lib;
+}
+
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
/// isEmptyField - Return true iff a the field is "empty", that is it
@@ -381,7 +397,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
if (isAggregateTypeForABI(Ty)) {
// Records with non trivial destructors/constructors should not be passed
// by value.
- if (isRecordReturnIndirect(Ty, CGT))
+ if (isRecordReturnIndirect(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
return ABIArgInfo::getIndirect(0);
@@ -451,7 +467,7 @@ llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
/// \brief Classify argument of given type \p Ty.
ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const {
if (isAggregateTypeForABI(Ty)) {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
return ABIArgInfo::getIndirect(0);
} else if (const EnumType *EnumTy = Ty->getAs<EnumType>()) {
@@ -493,8 +509,16 @@ 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())
+ if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) {
+ if (cast<llvm::VectorType>(Ty)->getBitWidth() != 64) {
+ // Invalid MMX constraint
+ return 0;
+ }
+
return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
+ }
+
+ // No operation needed
return Ty;
}
@@ -557,6 +581,9 @@ public:
bool d, bool p, bool w, unsigned r)
:TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, w, r)) {}
+ static bool isStructReturnInRegABI(
+ const llvm::Triple &Triple, const CodeGenOptions &Opts);
+
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -575,6 +602,14 @@ public:
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
+ llvm::Constant *getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
+ unsigned Sig = (0xeb << 0) | // jmp rel8
+ (0x06 << 8) | // .+0x08
+ ('F' << 16) |
+ ('T' << 24);
+ return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
+ }
+
};
}
@@ -674,7 +709,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
if (isAggregateTypeForABI(RetTy)) {
if (const RecordType *RT = RetTy->getAs<RecordType>()) {
- if (isRecordReturnIndirect(RT, CGT))
+ if (isRecordReturnIndirect(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// Structures with flexible arrays are always indirect.
@@ -859,7 +894,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
if (IsWin32StructABI)
return getIndirectResult(Ty, true, FreeRegs);
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory, FreeRegs);
// Structures with flexible arrays are always indirect.
@@ -876,9 +911,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
bool NeedsPadding;
if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) {
unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- SmallVector<llvm::Type*, 3> Elements;
- for (unsigned I = 0; I < SizeInRegs; ++I)
- Elements.push_back(Int32);
+ SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
return ABIArgInfo::getDirectInReg(Result);
}
@@ -1110,6 +1143,9 @@ class X86_64ABIInfo : public ABIInfo {
/// containing object. Some parameters are classified different
/// depending on whether they straddle an eightbyte boundary.
///
+ /// \param isNamedArg - Whether the argument in question is a "named"
+ /// argument, as used in AMD64-ABI 3.5.7.
+ ///
/// If a word is unused its result will be NoClass; if a type should
/// be passed in Memory then at least the classification of \arg Lo
/// will be Memory.
@@ -1118,7 +1154,8 @@ class X86_64ABIInfo : public ABIInfo {
///
/// If the \arg Lo class is ComplexX87, then the \arg Hi class will
/// also be ComplexX87.
- void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi) const;
+ void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi,
+ bool isNamedArg) const;
llvm::Type *GetByteVectorType(QualType Ty) const;
llvm::Type *GetSSETypeAtOffset(llvm::Type *IRType,
@@ -1144,7 +1181,8 @@ class X86_64ABIInfo : public ABIInfo {
ABIArgInfo classifyArgumentType(QualType Ty,
unsigned freeIntRegs,
unsigned &neededInt,
- unsigned &neededSSE) const;
+ unsigned &neededSSE,
+ bool isNamedArg) const;
bool IsIllegalVectorType(QualType Ty) const;
@@ -1171,7 +1209,8 @@ public:
bool isPassedUsingAVXType(QualType type) const {
unsigned neededInt, neededSSE;
// The freeIntRegs argument doesn't matter here.
- ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE);
+ ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE,
+ /*isNamedArg*/true);
if (info.isDirect()) {
llvm::Type *ty = info.getCoerceToType();
if (llvm::VectorType *vectorTy = dyn_cast_or_null<llvm::VectorType>(ty))
@@ -1237,7 +1276,7 @@ public:
// that when AVX types are involved: the ABI explicitly states it is
// undefined, and it doesn't work in practice because of how the ABI
// defines varargs anyway.
- if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) {
+ if (fnType->getCallConv() == CC_C) {
bool HasAVXType = false;
for (CallArgList::const_iterator
it = args.begin(), ie = args.end(); it != ie; ++it) {
@@ -1254,6 +1293,42 @@ public:
return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType);
}
+ llvm::Constant *getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
+ unsigned Sig = (0xeb << 0) | // jmp rel8
+ (0x0a << 8) | // .+0x0c
+ ('F' << 16) |
+ ('T' << 24);
+ return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
+ }
+
+};
+
+static std::string qualifyWindowsLibrary(llvm::StringRef Lib) {
+ // If the argument does not end in .lib, automatically add the suffix. This
+ // matches the behavior of MSVC.
+ std::string ArgStr = Lib;
+ if (!Lib.endswith_lower(".lib"))
+ ArgStr += ".lib";
+ return ArgStr;
+}
+
+class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo {
+public:
+ WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
+ bool d, bool p, bool w, unsigned RegParms)
+ : X86_32TargetCodeGenInfo(CGT, d, p, w, RegParms) {}
+
+ void getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const {
+ Opt = "/DEFAULTLIB:";
+ Opt += qualifyWindowsLibrary(Lib);
+ }
+
+ void getDetectMismatchOption(llvm::StringRef Name,
+ llvm::StringRef Value,
+ llvm::SmallString<32> &Opt) const {
+ Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
+ }
};
class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -1274,6 +1349,18 @@ public:
AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
return false;
}
+
+ void getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const {
+ Opt = "/DEFAULTLIB:";
+ Opt += qualifyWindowsLibrary(Lib);
+ }
+
+ void getDetectMismatchOption(llvm::StringRef Name,
+ llvm::StringRef Value,
+ llvm::SmallString<32> &Opt) const {
+ Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
+ }
};
}
@@ -1352,7 +1439,7 @@ X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
}
void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
- Class &Lo, Class &Hi) const {
+ Class &Lo, Class &Hi, bool isNamedArg) const {
// FIXME: This code can be simplified by introducing a simple value class for
// Class pairs with appropriate constructor methods for the various
// situations.
@@ -1378,7 +1465,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Current = Integer;
} else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
(k == BuiltinType::LongDouble &&
- getTarget().getTriple().getOS() == llvm::Triple::NaCl)) {
+ getTarget().getTriple().isOSNaCl())) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1391,7 +1478,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
if (const EnumType *ET = Ty->getAs<EnumType>()) {
// Classify the underlying integer type.
- classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi);
+ classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi, isNamedArg);
return;
}
@@ -1439,7 +1526,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// split.
if (OffsetBase && OffsetBase != 64)
Hi = Lo;
- } else if (Size == 128 || (HasAVX && Size == 256)) {
+ } else if (Size == 128 || (HasAVX && isNamedArg && Size == 256)) {
// Arguments of 256-bits are split into four eightbyte chunks. The
// least significant one belongs to class SSE and all the others to class
// SSEUP. The original Lo and Hi design considers that types can't be
@@ -1447,6 +1534,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// This design isn't correct for 256-bits, but since there're no cases
// where the upper parts would need to be inspected, avoid adding
// complexity and just consider Hi to match the 64-256 part.
+ //
+ // Note that per 3.5.7 of AMD64-ABI, 256-bit args are only passed in
+ // registers if they are "named", i.e. not part of the "..." of a
+ // variadic function.
Lo = SSE;
Hi = SSEUp;
}
@@ -1466,7 +1557,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Current = SSE;
else if (ET == getContext().DoubleTy ||
(ET == getContext().LongDoubleTy &&
- getTarget().getTriple().getOS() == llvm::Triple::NaCl))
+ getTarget().getTriple().isOSNaCl()))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -1512,7 +1603,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
Class FieldLo, FieldHi;
- classify(AT->getElementType(), Offset, FieldLo, FieldHi);
+ classify(AT->getElementType(), Offset, FieldLo, FieldHi, isNamedArg);
Lo = merge(Lo, FieldLo);
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
@@ -1535,7 +1626,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
// copy constructor or a non-trivial destructor, it is passed by invisible
// reference.
- if (getRecordArgABI(RT, CGT))
+ if (getRecordArgABI(RT, getCXXABI()))
return;
const RecordDecl *RD = RT->getDecl();
@@ -1566,7 +1657,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Class FieldLo, FieldHi;
uint64_t Offset =
OffsetBase + getContext().toBits(Layout.getBaseClassOffset(Base));
- classify(i->getType(), Offset, FieldLo, FieldHi);
+ classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg);
Lo = merge(Lo, FieldLo);
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
@@ -1619,7 +1710,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
uint64_t EB_Lo = Offset / 64;
uint64_t EB_Hi = (Offset + Size - 1) / 64;
- FieldLo = FieldHi = NoClass;
+
if (EB_Lo) {
assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
FieldLo = NoClass;
@@ -1629,7 +1720,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
FieldHi = EB_Hi ? Integer : NoClass;
}
} else
- classify(i->getType(), Offset, FieldLo, FieldHi);
+ classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg);
Lo = merge(Lo, FieldLo);
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
@@ -1685,7 +1776,7 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
// Compute the byval alignment. We specify the alignment of the byval in all
@@ -2017,7 +2108,7 @@ classifyReturnType(QualType RetTy) const {
// AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
// classification algorithm.
X86_64ABIInfo::Class Lo, Hi;
- classify(RetTy, 0, Lo, Hi);
+ classify(RetTy, 0, Lo, Hi, /*isNamedArg*/ true);
// Check some invariants.
assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
@@ -2142,11 +2233,12 @@ classifyReturnType(QualType RetTy) const {
}
ABIArgInfo X86_64ABIInfo::classifyArgumentType(
- QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE)
+ QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE,
+ bool isNamedArg)
const
{
X86_64ABIInfo::Class Lo, Hi;
- classify(Ty, 0, Lo, Hi);
+ classify(Ty, 0, Lo, Hi, isNamedArg);
// Check some invariants.
// FIXME: Enforce these by construction.
@@ -2174,7 +2266,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
// COMPLEX_X87, it is passed in memory.
case X87:
case ComplexX87:
- if (getRecordArgABI(Ty, CGT) == CGCXXABI::RAA_Indirect)
+ if (getRecordArgABI(Ty, getCXXABI()) == CGCXXABI::RAA_Indirect)
++neededInt;
return getIndirectResult(Ty, freeIntRegs);
@@ -2279,13 +2371,23 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getReturnInfo().isIndirect())
--freeIntRegs;
+ bool isVariadic = FI.isVariadic();
+ unsigned numRequiredArgs = 0;
+ if (isVariadic)
+ numRequiredArgs = FI.getRequiredArgs().getNumRequiredArgs();
+
// AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
// get assigned (in left-to-right order) for passing as follows...
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it) {
+ bool isNamedArg = true;
+ if (isVariadic)
+ isNamedArg = (it - FI.arg_begin()) <
+ static_cast<signed>(numRequiredArgs);
+
unsigned neededInt, neededSSE;
it->info = classifyArgumentType(it->type, freeIntRegs, neededInt,
- neededSSE);
+ neededSSE, isNamedArg);
// AMD64-ABI 3.2.3p3: If there are no registers available for any
// eightbyte of an argument, the whole argument is passed on the
@@ -2361,7 +2463,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
unsigned neededInt, neededSSE;
Ty = CGF.getContext().getCanonicalType(Ty);
- ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE);
+ ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE,
+ /*isNamedArg*/false);
// AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
// in the registers. If not go to step 7.
@@ -2425,7 +2528,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// FIXME: Cleanup.
assert(AI.isDirect() && "Unexpected ABI info for mixed regs");
llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
- llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
+ llvm::Value *Tmp = CGF.CreateMemTemp(Ty);
+ Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo());
assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
llvm::Type *TyLo = ST->getElementType(0);
llvm::Type *TyHi = ST->getElementType(1);
@@ -2449,6 +2553,17 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
RegAddr = CGF.Builder.CreateBitCast(RegAddr,
llvm::PointerType::getUnqual(LTy));
+
+ // Copy to a temporary if necessary to ensure the appropriate alignment.
+ std::pair<CharUnits, CharUnits> SizeAlign =
+ CGF.getContext().getTypeInfoInChars(Ty);
+ uint64_t TySize = SizeAlign.first.getQuantity();
+ unsigned TyAlign = SizeAlign.second.getQuantity();
+ if (TyAlign > 8) {
+ llvm::Value *Tmp = CGF.CreateMemTemp(Ty);
+ CGF.Builder.CreateMemCpy(Tmp, RegAddr, TySize, 8, false);
+ RegAddr = Tmp;
+ }
} else if (neededSSE == 1) {
RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
RegAddr = CGF.Builder.CreateBitCast(RegAddr,
@@ -2462,9 +2577,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Type *DoubleTy = CGF.DoubleTy;
llvm::Type *DblPtrTy =
llvm::PointerType::getUnqual(DoubleTy);
- llvm::StructType *ST = llvm::StructType::get(DoubleTy,
- DoubleTy, NULL);
- llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
+ llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, NULL);
+ llvm::Value *V, *Tmp = CGF.CreateMemTemp(Ty);
+ Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo());
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
DblPtrTy));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
@@ -2517,10 +2632,10 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
if (IsReturnType) {
- if (isRecordReturnIndirect(RT, CGT))
+ if (isRecordReturnIndirect(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, false);
} else {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
}
@@ -2702,11 +2817,11 @@ public:
it != ie; ++it) {
// We rely on the default argument classification for the most part.
// One exception: An aggregate containing a single floating-point
- // item must be passed in a register if one is available.
+ // or vector item must be passed in a register if one is available.
const Type *T = isSingleElementStruct(it->type, getContext());
if (T) {
const BuiltinType *BT = T->getAs<BuiltinType>();
- if (BT && BT->isFloatingPoint()) {
+ if (T->isVectorType() || (BT && BT->isFloatingPoint())) {
QualType QT(T, 0);
it->info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
continue;
@@ -2782,7 +2897,7 @@ PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
return ABIArgInfo::getDirect();
if (isAggregateTypeForABI(Ty)) {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
return ABIArgInfo::getIndirect(0);
@@ -2961,9 +3076,9 @@ public:
Env == "android" || Env == "androideabi");
}
-private:
ABIKind getABIKind() const { return Kind; }
+private:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
unsigned &AllocatedVFP,
@@ -3010,6 +3125,45 @@ public:
if (getABIInfo().isEABI()) return 88;
return TargetCodeGenInfo::getSizeOfUnwindException();
}
+
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD)
+ return;
+
+ const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>();
+ if (!Attr)
+ return;
+
+ const char *Kind;
+ switch (Attr->getInterrupt()) {
+ case ARMInterruptAttr::Generic: Kind = ""; break;
+ case ARMInterruptAttr::IRQ: Kind = "IRQ"; break;
+ case ARMInterruptAttr::FIQ: Kind = "FIQ"; break;
+ case ARMInterruptAttr::SWI: Kind = "SWI"; break;
+ case ARMInterruptAttr::ABORT: Kind = "ABORT"; break;
+ case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break;
+ }
+
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+
+ Fn->addFnAttr("interrupt", Kind);
+
+ if (cast<ARMABIInfo>(getABIInfo()).getABIKind() == ARMABIInfo::APCS)
+ return;
+
+ // AAPCS guarantees that sp will be 8-byte aligned on any public interface,
+ // however this is not necessarily true on taking any interrupt. Instruct
+ // 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));
+ }
+
};
}
@@ -3243,13 +3397,13 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+
// Ignore empty records.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
- return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
-
if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
// Homogeneous Aggregates need to be expanded when we can fit the aggregate
// into VFP registers.
@@ -3411,7 +3565,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, CGT))
+ if (isRecordReturnIndirect(RetTy, getCXXABI()))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// Are we following APCS?
@@ -3496,6 +3650,12 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ if (isEmptyRecord(getContext(), Ty, true)) {
+ // These are ignored for parameter passing purposes.
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ return Builder.CreateBitCast(Addr, PTy);
+ }
+
uint64_t Size = CGF.getContext().getTypeSize(Ty) / 8;
uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
bool IsIndirect = false;
@@ -3735,7 +3895,7 @@ ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty,
return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true);
}
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) {
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
if (FreeIntRegs > 0 && RAA == CGCXXABI::RAA_Indirect)
--FreeIntRegs;
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
@@ -4037,16 +4197,26 @@ private:
ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
- if (isAggregateTypeForABI(RetTy))
- return ABIArgInfo::getIndirect(0);
- return ABIArgInfo::getDirect();
+
+ // note: this is different from default ABI
+ if (!RetTy->isScalarType())
+ return ABIArgInfo::getDirect();
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty))
- return ABIArgInfo::getIndirect(0);
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
- return ABIArgInfo::getDirect();
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
@@ -4351,6 +4521,36 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return ResAddr;
}
+bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
+ const llvm::Triple &Triple, const CodeGenOptions &Opts) {
+ assert(Triple.getArch() == llvm::Triple::x86);
+
+ switch (Opts.getStructReturnConvention()) {
+ case CodeGenOptions::SRCK_Default:
+ break;
+ case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return
+ return false;
+ case CodeGenOptions::SRCK_InRegs: // -freg-struct-return
+ return true;
+ }
+
+ if (Triple.isOSDarwin())
+ return true;
+
+ switch (Triple.getOS()) {
+ case llvm::Triple::Cygwin:
+ case llvm::Triple::MinGW32:
+ case llvm::Triple::AuroraUX:
+ case llvm::Triple::DragonFly:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::OpenBSD:
+ case llvm::Triple::Bitrig:
+ case llvm::Triple::Win32:
+ return true;
+ default:
+ return false;
+ }
+}
ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
@@ -4363,7 +4563,7 @@ ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
// Handle the generic C++ ABI.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
// Integers and enums are extended to full register width.
@@ -4373,7 +4573,7 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
// Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly.
uint64_t Size = getContext().getTypeSize(Ty);
if (Size != 8 && Size != 16 && Size != 32 && Size != 64)
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// Handle small structures.
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -4381,7 +4581,7 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
// fail the size test above.
const RecordDecl *RD = RT->getDecl();
if (RD->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// The structure is passed as an unextended integer, a float, or a double.
llvm::Type *PassTy;
@@ -4398,122 +4598,12 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
// Non-structure compounds are passed indirectly.
if (isCompoundType(Ty))
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
return ABIArgInfo::getDirect(0);
}
//===----------------------------------------------------------------------===//
-// MBlaze ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class MBlazeABIInfo : public ABIInfo {
-public:
- MBlazeABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
- bool isPromotableIntegerType(QualType Ty) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
-
- virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-class MBlazeTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- MBlazeTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new MBlazeABIInfo(CGT)) {}
- void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const;
-};
-
-}
-
-bool MBlazeABIInfo::isPromotableIntegerType(QualType Ty) const {
- // MBlaze ABI requires all 8 and 16 bit quantities to be extended.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- return true;
- default:
- return false;
- }
- return false;
-}
-
-llvm::Value *MBlazeABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // FIXME: Implement
- return 0;
-}
-
-
-ABIArgInfo MBlazeABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
- if (isAggregateTypeForABI(RetTy))
- return ABIArgInfo::getIndirect(0);
-
- return (isPromotableIntegerType(RetTy) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo MBlazeABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty))
- return ABIArgInfo::getIndirect(0);
-
- return (isPromotableIntegerType(Ty) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-}
-
-void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M)
- const {
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) return;
-
- llvm::CallingConv::ID CC = llvm::CallingConv::C;
- if (FD->hasAttr<MBlazeInterruptHandlerAttr>())
- CC = llvm::CallingConv::MBLAZE_INTR;
- else if (FD->hasAttr<MBlazeSaveVolatilesAttr>())
- CC = llvm::CallingConv::MBLAZE_SVOL;
-
- if (CC != llvm::CallingConv::C) {
- // Handle 'interrupt_handler' attribute:
- llvm::Function *F = cast<llvm::Function>(GV);
-
- // Step 1: Set ISR calling convention.
- F->setCallingConv(CC);
-
- // Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
- }
-
- // Step 3: Emit _interrupt_handler alias.
- if (CC == llvm::CallingConv::MBLAZE_INTR)
- new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
- "_interrupt_handler", GV, &M.getModule());
-}
-
-
-//===----------------------------------------------------------------------===//
// MSP430 ABI Implementation
//===----------------------------------------------------------------------===//
@@ -4562,7 +4652,7 @@ class MipsABIInfo : public ABIInfo {
bool IsO32;
unsigned MinABIStackAlignInBytes, StackAlignInBytes;
void CoerceToIntArgs(uint64_t TySize,
- SmallVector<llvm::Type*, 8> &ArgList) const;
+ SmallVectorImpl<llvm::Type *> &ArgList) const;
llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;
llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
@@ -4612,7 +4702,7 @@ public:
}
void MipsABIInfo::CoerceToIntArgs(uint64_t TySize,
- SmallVector<llvm::Type*, 8> &ArgList) const {
+ SmallVectorImpl<llvm::Type *> &ArgList) const {
llvm::IntegerType *IntTy =
llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);
@@ -4685,13 +4775,12 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
return llvm::StructType::get(getVMContext(), ArgList);
}
-llvm::Type *MipsABIInfo::getPaddingType(uint64_t Align, uint64_t Offset) const {
- assert((Offset % MinABIStackAlignInBytes) == 0);
-
- if ((Align - 1) & Offset)
- return llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);
+llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
+ uint64_t Offset) const {
+ if (OrigOffset + MinABIStackAlignInBytes > Offset)
+ return 0;
- return 0;
+ return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);
}
ABIArgInfo
@@ -4702,15 +4791,15 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes),
(uint64_t)StackAlignInBytes);
- Offset = llvm::RoundUpToAlignment(Offset, Align);
- Offset += llvm::RoundUpToAlignment(TySize, Align * 8) / 8;
+ unsigned CurrOffset = llvm::RoundUpToAlignment(Offset, Align);
+ Offset = CurrOffset + llvm::RoundUpToAlignment(TySize, Align * 8) / 8;
if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {
// Ignore empty aggregates.
if (TySize == 0)
return ABIArgInfo::getIgnore();
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) {
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
Offset = OrigOffset + MinABIStackAlignInBytes;
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
}
@@ -4719,7 +4808,7 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
// another structure type. Padding is inserted if the offset of the
// aggregate is unaligned.
return ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0,
- getPaddingType(Align, OrigOffset));
+ getPaddingType(OrigOffset, CurrOffset));
}
// Treat an enum type as its underlying type.
@@ -4729,8 +4818,8 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
if (Ty->isPromotableIntegerType())
return ABIArgInfo::getExtend();
- return ABIArgInfo::getDirect(0, 0,
- IsO32 ? 0 : getPaddingType(Align, OrigOffset));
+ return ABIArgInfo::getDirect(
+ 0, 0, IsO32 ? 0 : getPaddingType(OrigOffset, CurrOffset));
}
llvm::Type*
@@ -4782,7 +4871,7 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIgnore();
if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {
- if (isRecordReturnIndirect(RetTy, CGT))
+ if (isRecordReturnIndirect(RetTy, getCXXABI()))
return ABIArgInfo::getIndirect(0);
if (Size <= 128) {
@@ -5003,7 +5092,7 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
uint64_t Size = getContext().getTypeSize(Ty);
@@ -5039,7 +5128,7 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, CGT))
+ if (isRecordReturnIndirect(RetTy, getCXXABI()))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
if (isEmptyRecord(getContext(), RetTy, true))
@@ -5086,6 +5175,335 @@ llvm::Value *HexagonABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
+//===----------------------------------------------------------------------===//
+// SPARC v9 ABI Implementation.
+// Based on the SPARC Compliance Definition version 2.4.1.
+//
+// Function arguments a mapped to a nominal "parameter array" and promoted to
+// registers depending on their type. Each argument occupies 8 or 16 bytes in
+// the array, structs larger than 16 bytes are passed indirectly.
+//
+// One case requires special care:
+//
+// struct mixed {
+// int i;
+// float f;
+// };
+//
+// When a struct mixed is passed by value, it only occupies 8 bytes in the
+// parameter array, but the int is passed in an integer register, and the float
+// is passed in a floating point register. This is represented as two arguments
+// with the LLVM IR inreg attribute:
+//
+// declare void f(i32 inreg %i, float inreg %f)
+//
+// The code generator will only allocate 4 bytes from the parameter array for
+// the inreg arguments. All other arguments are allocated a multiple of 8
+// bytes.
+//
+namespace {
+class SparcV9ABIInfo : public ABIInfo {
+public:
+ SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+private:
+ ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ // Coercion type builder for structs passed in registers. The coercion type
+ // serves two purposes:
+ //
+ // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'
+ // in registers.
+ // 2. Expose aligned floating point elements as first-level elements, so the
+ // code generator knows to pass them in floating point registers.
+ //
+ // We also compute the InReg flag which indicates that the struct contains
+ // aligned 32-bit floats.
+ //
+ struct CoerceBuilder {
+ llvm::LLVMContext &Context;
+ const llvm::DataLayout &DL;
+ SmallVector<llvm::Type*, 8> Elems;
+ uint64_t Size;
+ bool InReg;
+
+ CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
+ : Context(c), DL(dl), Size(0), InReg(false) {}
+
+ // Pad Elems with integers until Size is ToSize.
+ void pad(uint64_t ToSize) {
+ assert(ToSize >= Size && "Cannot remove elements");
+ if (ToSize == Size)
+ return;
+
+ // Finish the current 64-bit word.
+ uint64_t Aligned = llvm::RoundUpToAlignment(Size, 64);
+ if (Aligned > Size && Aligned <= ToSize) {
+ Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));
+ Size = Aligned;
+ }
+
+ // Add whole 64-bit words.
+ while (Size + 64 <= ToSize) {
+ Elems.push_back(llvm::Type::getInt64Ty(Context));
+ Size += 64;
+ }
+
+ // Final in-word padding.
+ if (Size < ToSize) {
+ Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size));
+ Size = ToSize;
+ }
+ }
+
+ // Add a floating point element at Offset.
+ void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
+ // Unaligned floats are treated as integers.
+ if (Offset % Bits)
+ return;
+ // The InReg flag is only required if there are any floats < 64 bits.
+ if (Bits < 64)
+ InReg = true;
+ pad(Offset);
+ Elems.push_back(Ty);
+ Size = Offset + Bits;
+ }
+
+ // Add a struct type to the coercion type, starting at Offset (in bits).
+ void addStruct(uint64_t Offset, llvm::StructType *StrTy) {
+ const llvm::StructLayout *Layout = DL.getStructLayout(StrTy);
+ for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) {
+ llvm::Type *ElemTy = StrTy->getElementType(i);
+ uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i);
+ switch (ElemTy->getTypeID()) {
+ case llvm::Type::StructTyID:
+ addStruct(ElemOffset, cast<llvm::StructType>(ElemTy));
+ break;
+ case llvm::Type::FloatTyID:
+ addFloat(ElemOffset, ElemTy, 32);
+ break;
+ case llvm::Type::DoubleTyID:
+ addFloat(ElemOffset, ElemTy, 64);
+ break;
+ case llvm::Type::FP128TyID:
+ addFloat(ElemOffset, ElemTy, 128);
+ break;
+ case llvm::Type::PointerTyID:
+ if (ElemOffset % 64 == 0) {
+ pad(ElemOffset);
+ Elems.push_back(ElemTy);
+ Size += 64;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Check if Ty is a usable substitute for the coercion type.
+ bool isUsableType(llvm::StructType *Ty) const {
+ if (Ty->getNumElements() != Elems.size())
+ return false;
+ for (unsigned i = 0, e = Elems.size(); i != e; ++i)
+ if (Elems[i] != Ty->getElementType(i))
+ return false;
+ return true;
+ }
+
+ // Get the coercion type as a literal struct type.
+ llvm::Type *getType() const {
+ if (Elems.size() == 1)
+ return Elems.front();
+ else
+ return llvm::StructType::get(Context, Elems);
+ }
+ };
+};
+} // end anonymous namespace
+
+ABIArgInfo
+SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
+ if (Ty->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ uint64_t Size = getContext().getTypeSize(Ty);
+
+ // Anything too big to fit in registers is passed with an explicit indirect
+ // pointer / sret pointer.
+ if (Size > SizeLimit)
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ // Integer types smaller than a register are extended.
+ if (Size < 64 && Ty->isIntegerType())
+ return ABIArgInfo::getExtend();
+
+ // Other non-aggregates go in registers.
+ if (!isAggregateTypeForABI(Ty))
+ return ABIArgInfo::getDirect();
+
+ // This is a small aggregate type that should be passed in registers.
+ // Build a coercion type from the LLVM struct type.
+ llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
+ if (!StrTy)
+ return ABIArgInfo::getDirect();
+
+ CoerceBuilder CB(getVMContext(), getDataLayout());
+ CB.addStruct(0, StrTy);
+ CB.pad(llvm::RoundUpToAlignment(CB.DL.getTypeSizeInBits(StrTy), 64));
+
+ // Try to use the original type for coercion.
+ llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
+
+ if (CB.InReg)
+ return ABIArgInfo::getDirectInReg(CoerceTy);
+ else
+ return ABIArgInfo::getDirect(CoerceTy);
+}
+
+llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ ABIArgInfo AI = classifyType(Ty, 16 * 8);
+ llvm::Type *ArgTy = CGT.ConvertType(Ty);
+ if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
+ AI.setCoerceToType(ArgTy);
+
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy);
+ llvm::Value *ArgAddr;
+ unsigned Stride;
+
+ switch (AI.getKind()) {
+ case ABIArgInfo::Expand:
+ llvm_unreachable("Unsupported ABI kind for va_arg");
+
+ case ABIArgInfo::Extend:
+ Stride = 8;
+ ArgAddr = Builder
+ .CreateConstGEP1_32(Addr, 8 - getDataLayout().getTypeAllocSize(ArgTy),
+ "extend");
+ break;
+
+ case ABIArgInfo::Direct:
+ Stride = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
+ ArgAddr = Addr;
+ break;
+
+ case ABIArgInfo::Indirect:
+ Stride = 8;
+ ArgAddr = Builder.CreateBitCast(Addr,
+ llvm::PointerType::getUnqual(ArgPtrTy),
+ "indirect");
+ ArgAddr = Builder.CreateLoad(ArgAddr, "indirect.arg");
+ break;
+
+ case ABIArgInfo::Ignore:
+ return llvm::UndefValue::get(ArgPtrTy);
+ }
+
+ // Update VAList.
+ Addr = Builder.CreateConstGEP1_32(Addr, Stride, "ap.next");
+ Builder.CreateStore(Addr, VAListAddrAsBPP);
+
+ return Builder.CreatePointerCast(ArgAddr, ArgPtrTy, "arg.addr");
+}
+
+void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyType(it->type, 16 * 8);
+}
+
+namespace {
+class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
+};
+} // end anonymous namespace
+
+
+//===----------------------------------------------------------------------===//
+// Xcore ABI Implementation
+//===----------------------------------------------------------------------===//
+namespace {
+class XCoreABIInfo : public DefaultABIInfo {
+public:
+ XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class XcoreTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ XcoreTargetCodeGenInfo(CodeGenTypes &CGT)
+ :TargetCodeGenInfo(new XCoreABIInfo(CGT)) {}
+};
+} // End anonymous namespace.
+
+llvm::Value *XCoreABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // Get the VAList.
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr,
+ CGF.Int8PtrPtrTy);
+ llvm::Value *AP = Builder.CreateLoad(VAListAddrAsBPP);
+
+ // Handle the argument.
+ ABIArgInfo AI = classifyArgumentType(Ty);
+ llvm::Type *ArgTy = CGT.ConvertType(Ty);
+ if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
+ AI.setCoerceToType(ArgTy);
+ llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy);
+ llvm::Value *Val;
+ uint64_t ArgSize = 0;
+ switch (AI.getKind()) {
+ case ABIArgInfo::Expand:
+ llvm_unreachable("Unsupported ABI kind for va_arg");
+ case ABIArgInfo::Ignore:
+ Val = llvm::UndefValue::get(ArgPtrTy);
+ ArgSize = 0;
+ break;
+ case ABIArgInfo::Extend:
+ case ABIArgInfo::Direct:
+ Val = Builder.CreatePointerCast(AP, ArgPtrTy);
+ ArgSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
+ if (ArgSize < 4)
+ ArgSize = 4;
+ break;
+ case ABIArgInfo::Indirect:
+ llvm::Value *ArgAddr;
+ ArgAddr = Builder.CreateBitCast(AP, llvm::PointerType::getUnqual(ArgPtrTy));
+ ArgAddr = Builder.CreateLoad(ArgAddr);
+ Val = Builder.CreatePointerCast(ArgAddr, ArgPtrTy);
+ ArgSize = 4;
+ break;
+ }
+
+ // Increment the VAList.
+ if (ArgSize) {
+ llvm::Value *APN = Builder.CreateConstGEP1_32(AP, ArgSize);
+ Builder.CreateStore(APN, VAListAddrAsBPP);
+ }
+ return Val;
+}
+
+//===----------------------------------------------------------------------===//
+// Driver code
+//===----------------------------------------------------------------------===//
+
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
@@ -5136,14 +5554,14 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
else
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
+ case llvm::Triple::ppc64le:
+ assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
+ return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
return *(TheTargetCodeGenInfo = new NVPTXTargetCodeGenInfo(Types));
- case llvm::Triple::mblaze:
- return *(TheTargetCodeGenInfo = new MBlazeTargetCodeGenInfo(Types));
-
case llvm::Triple::msp430:
return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));
@@ -5154,31 +5572,22 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
case llvm::Triple::x86: {
- if (Triple.isOSDarwin())
- return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, true, true, false,
- CodeGenOpts.NumRegisterParameters));
-
- switch (Triple.getOS()) {
- case llvm::Triple::Cygwin:
- case llvm::Triple::MinGW32:
- case llvm::Triple::AuroraUX:
- case llvm::Triple::DragonFly:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::OpenBSD:
- case llvm::Triple::Bitrig:
- return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, false,
- CodeGenOpts.NumRegisterParameters));
+ bool IsDarwinVectorABI = Triple.isOSDarwin();
+ bool IsSmallStructInRegABI =
+ X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
+ bool IsWin32FloatStructABI = (Triple.getOS() == llvm::Triple::Win32);
- case llvm::Triple::Win32:
+ if (Triple.getOS() == llvm::Triple::Win32) {
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, true,
- CodeGenOpts.NumRegisterParameters));
-
- default:
+ new WinX86_32TargetCodeGenInfo(Types,
+ IsDarwinVectorABI, IsSmallStructInRegABI,
+ IsWin32FloatStructABI,
+ CodeGenOpts.NumRegisterParameters));
+ } else {
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, false, false,
+ new X86_32TargetCodeGenInfo(Types,
+ IsDarwinVectorABI, IsSmallStructInRegABI,
+ IsWin32FloatStructABI,
CodeGenOpts.NumRegisterParameters));
}
}
@@ -5201,5 +5610,10 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
case llvm::Triple::hexagon:
return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
+ case llvm::Triple::sparcv9:
+ return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types));
+ case llvm::Triple::xcore:
+ return *(TheTargetCodeGenInfo = new XcoreTargetCodeGenInfo(Types));
+
}
}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index bb50ce69e312..f631f3102d0d 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -18,8 +18,10 @@
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
namespace llvm {
+ class Constant;
class GlobalValue;
class Type;
class Value;
@@ -110,8 +112,13 @@ namespace clang {
return Address;
}
+ /// Corrects the low-level LLVM type for a given constraint and "usual"
+ /// type.
+ ///
+ /// \returns A pointer to a new LLVM type, possibly the same as the original
+ /// on success; 0 on failure.
virtual llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- StringRef Constraint,
+ StringRef Constraint,
llvm::Type* Ty) const {
return Ty;
}
@@ -130,6 +137,13 @@ namespace clang {
return "";
}
+ /// Return a constant used by UBSan as a signature to identify functions
+ /// possessing type information, or 0 if the platform is unsupported.
+ virtual llvm::Constant *getUBSanFunctionSignature(
+ CodeGen::CodeGenModule &CGM) const {
+ return 0;
+ }
+
/// Determine whether a call to an unprototyped functions under
/// the given calling convention should use the variadic
/// convention or the non-variadic convention.
@@ -165,8 +179,26 @@ namespace clang {
/// arguments in %al. On these platforms, it is desireable to
/// call unprototyped functions using the variadic convention so
/// that unprototyped calls to varargs functions still succeed.
+ ///
+ /// Relatedly, platforms which pass the fixed arguments to this:
+ /// A foo(B, C, D);
+ /// differently than they would pass them to this:
+ /// A foo(B, C, D, ...);
+ /// may need to adjust the debugger-support code in Sema to do the
+ /// right thing when calling a function with no know signature.
virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
const FunctionNoProtoType *fnType) const;
+
+ /// Gets the linker options necessary to link a dependent library on this
+ /// platform.
+ virtual void getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const;
+
+ /// Gets the linker options necessary to detect object file mismatches on
+ /// this platform.
+ virtual void getDetectMismatchOption(llvm::StringRef Name,
+ llvm::StringRef Value,
+ llvm::SmallString<32> &Opt) const {}
};
}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 2b5bbee3db21..ddd2d599da06 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -11,6 +11,7 @@
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
using namespace clang::driver;
+using namespace llvm::opt;
Action::~Action() {
if (OwnsInputs) {
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
deleted file mode 100644
index 93d70a9fefed..000000000000
--- a/lib/Driver/Arg.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-//===--- Arg.cpp - Argument Implementations -------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/Arg.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Option.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang::driver;
-using clang::StringRef;
-
-Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
- Claimed(false), OwnsValues(false) {
-}
-
-Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
- const char *Value0, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
- Claimed(false), OwnsValues(false) {
- Values.push_back(Value0);
-}
-
-Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
- const char *Value0, const char *Value1, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
- Claimed(false), OwnsValues(false) {
- Values.push_back(Value0);
- Values.push_back(Value1);
-}
-
-Arg::~Arg() {
- if (OwnsValues) {
- for (unsigned i = 0, e = Values.size(); i != e; ++i)
- delete[] Values[i];
- }
-}
-
-void Arg::dump() const {
- llvm::errs() << "<";
-
- llvm::errs() << " Opt:";
- Opt.dump();
-
- llvm::errs() << " Index:" << Index;
-
- llvm::errs() << " Values: [";
- for (unsigned i = 0, e = Values.size(); i != e; ++i) {
- if (i) llvm::errs() << ", ";
- llvm::errs() << "'" << Values[i] << "'";
- }
-
- llvm::errs() << "]>\n";
-}
-
-std::string Arg::getAsString(const ArgList &Args) const {
- SmallString<256> Res;
- llvm::raw_svector_ostream OS(Res);
-
- ArgStringList ASL;
- render(Args, ASL);
- for (ArgStringList::iterator
- it = ASL.begin(), ie = ASL.end(); it != ie; ++it) {
- if (it != ASL.begin())
- OS << ' ';
- OS << *it;
- }
-
- return OS.str();
-}
-
-void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const {
- if (!getOption().hasNoOptAsInput()) {
- render(Args, Output);
- return;
- }
-
- for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(i));
-}
-
-void Arg::render(const ArgList &Args, ArgStringList &Output) const {
- switch (getOption().getRenderStyle()) {
- case Option::RenderValuesStyle:
- for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(i));
- break;
-
- case Option::RenderCommaJoinedStyle: {
- SmallString<256> Res;
- llvm::raw_svector_ostream OS(Res);
- OS << getSpelling();
- for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
- if (i) OS << ',';
- OS << getValue(i);
- }
- Output.push_back(Args.MakeArgString(OS.str()));
- break;
- }
-
- case Option::RenderJoinedStyle:
- Output.push_back(Args.GetOrMakeJoinedArgString(
- getIndex(), getSpelling(), getValue(0)));
- for (unsigned i = 1, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(i));
- break;
-
- case Option::RenderSeparateStyle:
- Output.push_back(Args.MakeArgString(getSpelling()));
- for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(i));
- break;
- }
-}
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
deleted file mode 100644
index 4b8d151d195a..000000000000
--- a/lib/Driver/ArgList.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-//===--- ArgList.cpp - Argument List Management ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Option.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace clang::driver;
-
-void arg_iterator::SkipToNextArg() {
- for (; Current != Args.end(); ++Current) {
- // Done if there are no filters.
- if (!Id0.isValid())
- break;
-
- // Otherwise require a match.
- const Option &O = (*Current)->getOption();
- if (O.matches(Id0) ||
- (Id1.isValid() && O.matches(Id1)) ||
- (Id2.isValid() && O.matches(Id2)))
- break;
- }
-}
-
-//
-
-ArgList::ArgList() {
-}
-
-ArgList::~ArgList() {
-}
-
-void ArgList::append(Arg *A) {
- Args.push_back(A);
-}
-
-void ArgList::eraseArg(OptSpecifier Id) {
- for (iterator it = begin(), ie = end(); it != ie; ) {
- if ((*it)->getOption().matches(Id)) {
- it = Args.erase(it);
- ie = end();
- } else {
- ++it;
- }
- }
-}
-
-Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const {
- // FIXME: Make search efficient?
- for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it)
- if ((*it)->getOption().matches(Id))
- return *it;
- return 0;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2, OptSpecifier Id3) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2) ||
- (*it)->getOption().matches(Id3)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2, OptSpecifier Id3,
- OptSpecifier Id4) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2) ||
- (*it)->getOption().matches(Id3) ||
- (*it)->getOption().matches(Id4)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2, OptSpecifier Id3,
- OptSpecifier Id4, OptSpecifier Id5) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2) ||
- (*it)->getOption().matches(Id3) ||
- (*it)->getOption().matches(Id4) ||
- (*it)->getOption().matches(Id5)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2, OptSpecifier Id3,
- OptSpecifier Id4, OptSpecifier Id5,
- OptSpecifier Id6) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2) ||
- (*it)->getOption().matches(Id3) ||
- (*it)->getOption().matches(Id4) ||
- (*it)->getOption().matches(Id5) ||
- (*it)->getOption().matches(Id6)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
- OptSpecifier Id2, OptSpecifier Id3,
- OptSpecifier Id4, OptSpecifier Id5,
- OptSpecifier Id6, OptSpecifier Id7) const {
- Arg *Res = 0;
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->getOption().matches(Id0) ||
- (*it)->getOption().matches(Id1) ||
- (*it)->getOption().matches(Id2) ||
- (*it)->getOption().matches(Id3) ||
- (*it)->getOption().matches(Id4) ||
- (*it)->getOption().matches(Id5) ||
- (*it)->getOption().matches(Id6) ||
- (*it)->getOption().matches(Id7)) {
- Res = *it;
- Res->claim();
- }
- }
-
- return Res;
-}
-
-bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
- if (Arg *A = getLastArg(Pos, Neg))
- return A->getOption().matches(Pos);
- return Default;
-}
-
-bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg,
- bool Default) const {
- if (Arg *A = getLastArg(Pos, PosAlias, Neg))
- return A->getOption().matches(Pos) || A->getOption().matches(PosAlias);
- return Default;
-}
-
-StringRef ArgList::getLastArgValue(OptSpecifier Id,
- StringRef Default) const {
- if (Arg *A = getLastArg(Id))
- return A->getValue();
- return Default;
-}
-
-int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
- clang::DiagnosticsEngine *Diags) const {
- int Res = Default;
-
- if (Arg *A = getLastArg(Id)) {
- if (StringRef(A->getValue()).getAsInteger(10, Res)) {
- if (Diags)
- Diags->Report(diag::err_drv_invalid_int_value)
- << A->getAsString(*this) << A->getValue();
- }
- }
-
- return Res;
-}
-
-std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
- SmallVector<const char *, 16> Values;
- AddAllArgValues(Values, Id);
- return std::vector<std::string>(Values.begin(), Values.end());
-}
-
-void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
- if (Arg *A = getLastArg(Id)) {
- A->claim();
- A->render(*this, Output);
- }
-}
-
-void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const {
- if (Arg *A = getLastArg(Id0, Id1)) {
- A->claim();
- A->render(*this, Output);
- }
-}
-
-void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1, OptSpecifier Id2) const {
- for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
- ie = filtered_end(); it != ie; ++it) {
- (*it)->claim();
- (*it)->render(*this, Output);
- }
-}
-
-void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1, OptSpecifier Id2) const {
- for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
- ie = filtered_end(); it != ie; ++it) {
- (*it)->claim();
- for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
- Output.push_back((*it)->getValue(i));
- }
-}
-
-void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
- const char *Translation,
- bool Joined) const {
- for (arg_iterator it = filtered_begin(Id0),
- ie = filtered_end(); it != ie; ++it) {
- (*it)->claim();
-
- if (Joined) {
- Output.push_back(MakeArgString(StringRef(Translation) +
- (*it)->getValue(0)));
- } else {
- Output.push_back(Translation);
- Output.push_back((*it)->getValue(0));
- }
- }
-}
-
-void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
- for (arg_iterator it = filtered_begin(Id0),
- ie = filtered_end(); it != ie; ++it)
- (*it)->claim();
-}
-
-void ArgList::ClaimAllArgs() const {
- for (const_iterator it = begin(), ie = end(); it != ie; ++it)
- if (!(*it)->isClaimed())
- (*it)->claim();
-}
-
-const char *ArgList::MakeArgString(const Twine &T) const {
- SmallString<256> Str;
- T.toVector(Str);
- return MakeArgString(Str.str());
-}
-
-const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
- StringRef LHS,
- StringRef RHS) const {
- StringRef Cur = getArgString(Index);
- if (Cur.size() == LHS.size() + RHS.size() &&
- Cur.startswith(LHS) && Cur.endswith(RHS))
- return Cur.data();
-
- return MakeArgString(LHS + RHS);
-}
-
-void ArgList::dump() {
- llvm::errs() << "ArgList:";
- for (iterator it = begin(), ie = end(); it != ie; ++it) {
- llvm::errs() << " " << (*it)->getSpelling();
- }
- llvm::errs() << "\n";
-}
-
-//
-
-InputArgList::InputArgList(const char* const *ArgBegin,
- const char* const *ArgEnd)
- : NumInputArgStrings(ArgEnd - ArgBegin) {
- ArgStrings.append(ArgBegin, ArgEnd);
-}
-
-InputArgList::~InputArgList() {
- // An InputArgList always owns its arguments.
- for (iterator it = begin(), ie = end(); it != ie; ++it)
- delete *it;
-}
-
-unsigned InputArgList::MakeIndex(StringRef String0) const {
- unsigned Index = ArgStrings.size();
-
- // Tuck away so we have a reliable const char *.
- SynthesizedStrings.push_back(String0);
- ArgStrings.push_back(SynthesizedStrings.back().c_str());
-
- return Index;
-}
-
-unsigned InputArgList::MakeIndex(StringRef String0,
- StringRef String1) const {
- unsigned Index0 = MakeIndex(String0);
- unsigned Index1 = MakeIndex(String1);
- assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
- (void) Index1;
- return Index0;
-}
-
-const char *InputArgList::MakeArgString(StringRef Str) const {
- return getArgString(MakeIndex(Str));
-}
-
-//
-
-DerivedArgList::DerivedArgList(const InputArgList &_BaseArgs)
- : BaseArgs(_BaseArgs) {
-}
-
-DerivedArgList::~DerivedArgList() {
- // We only own the arguments we explicitly synthesized.
- for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
- it != ie; ++it)
- delete *it;
-}
-
-const char *DerivedArgList::MakeArgString(StringRef Str) const {
- return BaseArgs.MakeArgString(Str);
-}
-
-Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
- Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
- Twine(Opt.getName())),
- BaseArgs.MakeIndex(Opt.getName()), BaseArg);
- SynthesizedArgs.push_back(A);
- return A;
-}
-
-Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Value);
- Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
- Twine(Opt.getName())),
- Index, BaseArgs.getArgString(Index), BaseArg);
- SynthesizedArgs.push_back(A);
- return A;
-}
-
-Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
- Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
- Twine(Opt.getName())),
- Index, BaseArgs.getArgString(Index + 1), BaseArg);
- SynthesizedArgs.push_back(A);
- return A;
-}
-
-Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
- StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str());
- Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
- Twine(Opt.getName())), Index,
- BaseArgs.getArgString(Index) + Opt.getName().size(),
- BaseArg);
- SynthesizedArgs.push_back(A);
- return A;
-}
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index 904804383670..22180c92ca7f 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -8,27 +8,25 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/CC1AsOptions.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
using namespace clang;
using namespace clang::driver;
-using namespace clang::driver::options;
+using namespace llvm::opt;
using namespace clang::driver::cc1asoptions;
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
- HELPTEXT, METAVAR)
+#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
#include "clang/Driver/CC1AsOptions.inc"
-#undef OPTION
#undef PREFIX
static const OptTable::Info CC1AsInfoTable[] = {
-#define PREFIX(NAME, VALUE)
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#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 },
+ FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "clang/Driver/CC1AsOptions.inc"
+#undef OPTION
};
namespace {
@@ -36,8 +34,7 @@ namespace {
class CC1AsOptTable : public OptTable {
public:
CC1AsOptTable()
- : OptTable(CC1AsInfoTable,
- sizeof(CC1AsInfoTable) / sizeof(CC1AsInfoTable[0])) {}
+ : OptTable(CC1AsInfoTable, llvm::array_lengthof(CC1AsInfoTable)) {}
};
}
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 4ada7d92c3d1..0152b19d4c59 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -1,15 +1,12 @@
add_clang_library(clangDriver
Action.cpp
- Arg.cpp
- ArgList.cpp
CC1AsOptions.cpp
Compilation.cpp
Driver.cpp
DriverOptions.cpp
Job.cpp
- Option.cpp
- OptTable.cpp
Phases.cpp
+ SanitizerArgs.cpp
Tool.cpp
ToolChain.cpp
ToolChains.cpp
@@ -28,4 +25,6 @@ add_dependencies(clangDriver
target_link_libraries(clangDriver
clangBasic
+ LLVMOption
+ LLVMTransformUtils
)
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 1bff4a3d7a72..f077fd68cc4f 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -9,20 +9,20 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Action.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Program.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <errno.h>
#include <sys/stat.h>
using namespace clang::driver;
using namespace clang;
+using namespace llvm::opt;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
InputArgList *_Args, DerivedArgList *_TranslatedArgs)
@@ -69,160 +69,34 @@ const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
return *Entry;
}
-void Compilation::PrintJob(raw_ostream &OS, const Job &J,
- const char *Terminator, bool Quote) const {
- if (const Command *C = dyn_cast<Command>(&J)) {
- OS << " \"" << C->getExecutable() << '"';
- for (ArgStringList::const_iterator it = C->getArguments().begin(),
- ie = C->getArguments().end(); it != ie; ++it) {
- OS << ' ';
- if (!Quote && !std::strpbrk(*it, " \"\\$")) {
- OS << *it;
- continue;
- }
-
- // Quote the argument and escape shell special characters; this isn't
- // really complete but is good enough.
- OS << '"';
- for (const char *s = *it; *s; ++s) {
- if (*s == '"' || *s == '\\' || *s == '$')
- OS << '\\';
- OS << *s;
- }
- OS << '"';
- }
- OS << Terminator;
- } else {
- const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator
- it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
- PrintJob(OS, **it, Terminator, Quote);
- }
-}
-
-static bool skipArg(const char *Flag, bool &SkipNextArg) {
- StringRef FlagRef(Flag);
-
- // Assume we're going to see -Flag <Arg>.
- SkipNextArg = true;
-
- // These flags are all of the form -Flag <Arg> and are treated as two
- // arguments. Therefore, we need to skip the flag and the next argument.
- bool Res = llvm::StringSwitch<bool>(Flag)
- .Cases("-I", "-MF", "-MT", "-MQ", true)
- .Cases("-o", "-coverage-file", "-dependency-file", true)
- .Cases("-fdebug-compilation-dir", "-idirafter", true)
- .Cases("-include", "-include-pch", "-internal-isystem", true)
- .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
- .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
- .Cases("-resource-dir", "-serialize-diagnostic-file", true)
- .Case("-dwarf-debug-flags", true)
- .Default(false);
-
- // Match found.
- if (Res)
- return Res;
-
- // The remaining flags are treated as a single argument.
- SkipNextArg = false;
-
- // These flags are all of the form -Flag and have no second argument.
- Res = llvm::StringSwitch<bool>(Flag)
- .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
- .Case("-MMD", true)
- .Default(false);
-
- // Match found.
- if (Res)
- return Res;
-
- // These flags are treated as a single argument (e.g., -F<Dir>).
- if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
- return true;
-
- return false;
-}
-
-static bool quoteNextArg(const char *flag) {
- return llvm::StringSwitch<bool>(flag)
- .Case("-D", true)
- .Default(false);
-}
-
-void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const {
- if (const Command *C = dyn_cast<Command>(&J)) {
- OS << C->getExecutable();
- unsigned QuoteNextArg = 0;
- for (ArgStringList::const_iterator it = C->getArguments().begin(),
- ie = C->getArguments().end(); it != ie; ++it) {
-
- bool SkipNext;
- if (skipArg(*it, SkipNext)) {
- if (SkipNext) ++it;
- continue;
- }
-
- if (!QuoteNextArg)
- QuoteNextArg = quoteNextArg(*it) ? 2 : 0;
-
- OS << ' ';
-
- if (QuoteNextArg == 1)
- OS << '"';
-
- if (!std::strpbrk(*it, " \"\\$")) {
- OS << *it;
- } else {
- // Quote the argument and escape shell special characters; this isn't
- // really complete but is good enough.
- OS << '"';
- for (const char *s = *it; *s; ++s) {
- if (*s == '"' || *s == '\\' || *s == '$')
- OS << '\\';
- OS << *s;
- }
- OS << '"';
- }
+bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
+ std::string P(File);
- if (QuoteNextArg) {
- if (QuoteNextArg == 1)
- OS << '"';
- --QuoteNextArg;
- }
- }
- OS << '\n';
- } else {
- const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator
- it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
- PrintDiagnosticJob(OS, **it);
- }
-}
+ // FIXME: Why are we trying to remove files that we have not created? For
+ // example we should only try to remove a temporary assembly file if
+ // "clang -cc1" succeed in writing it. Was this a workaround for when
+ // clang was writing directly to a .s file and sometimes leaving it behind
+ // during a failure?
-bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
- llvm::sys::Path P(File);
- std::string Error;
+ // FIXME: If this is necessary, we can still try to split
+ // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
+ // duplicated stat from is_regular_file.
// Don't try to remove files which we don't have write access to (but may be
// able to remove), or non-regular files. Underlying tools may have
// intentionally not overwritten them.
- if (!P.canWrite() || !P.isRegularFile())
+ if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
return true;
- if (P.eraseFromDisk(false, &Error)) {
- // Failure is only failure if the file exists and is "regular". There is
- // a race condition here due to the limited interface of
- // llvm::sys::Path, we want to know if the removal gave ENOENT.
+ if (llvm::error_code EC = llvm::sys::fs::remove(File)) {
+ // Failure is only failure if the file exists and is "regular". We checked
+ // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
+ // so we don't need to check again.
- // FIXME: Grumble, P.exists() is broken. PR3837.
- struct stat buf;
- if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
- (errno != ENOENT)) {
- if (IssueErrors)
- getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
- << Error;
- return false;
- }
+ if (IssueErrors)
+ getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
+ << EC.message();
+ return false;
}
return true;
}
@@ -254,13 +128,7 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files,
int Compilation::ExecuteCommand(const Command &C,
const Command *&FailingCommand) const {
- llvm::sys::Path Prog(C.getExecutable());
- const char **Argv = new const char*[C.getArguments().size() + 2];
- Argv[0] = C.getExecutable();
- std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
- Argv[C.getArguments().size() + 1] = 0;
-
- if ((getDriver().CCCEcho || getDriver().CCPrintOptions ||
+ if ((getDriver().CCPrintOptions ||
getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
raw_ostream *OS = &llvm::errs();
@@ -268,9 +136,8 @@ int Compilation::ExecuteCommand(const Command &C,
// output stream.
if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
std::string Error;
- OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename,
- Error,
- llvm::raw_fd_ostream::F_Append);
+ OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
+ llvm::sys::fs::F_Append);
if (!Error.empty()) {
getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
<< Error;
@@ -283,7 +150,7 @@ int Compilation::ExecuteCommand(const Command &C,
if (getDriver().CCPrintOptions)
*OS << "[Logging clang options]";
- PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions);
+ C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
if (OS != &llvm::errs())
delete OS;
@@ -291,11 +158,7 @@ int Compilation::ExecuteCommand(const Command &C,
std::string Error;
bool ExecutionFailed;
- int Res =
- llvm::sys::Program::ExecuteAndWait(Prog, Argv,
- /*env*/0, Redirects,
- /*secondsToWait*/0, /*memoryLimit*/0,
- &Error, &ExecutionFailed);
+ int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
if (!Error.empty()) {
assert(Res && "Error string set with 0 result code!");
getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
@@ -304,7 +167,6 @@ int Compilation::ExecuteCommand(const Command &C,
if (Res)
FailingCommand = &C;
- delete[] Argv;
return ExecutionFailed ? 1 : Res;
}
@@ -370,9 +232,10 @@ void Compilation::initCompilationForDiagnostics() {
TranslatedArgs->ClaimAllArgs();
// Redirect stdout/stderr to /dev/null.
- Redirects = new const llvm::sys::Path*[3]();
- Redirects[1] = new const llvm::sys::Path();
- Redirects[2] = new const llvm::sys::Path();
+ Redirects = new const StringRef*[3]();
+ Redirects[0] = 0;
+ Redirects[1] = new const StringRef();
+ Redirects[2] = new const StringRef();
}
StringRef Compilation::getSysRoot() const {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 1dbbc9a342bb..530791072fa0 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -12,19 +12,22 @@
#include "ToolChains.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Job.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Option/OptSpecifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
@@ -40,20 +43,21 @@
using namespace clang::driver;
using namespace clang;
+using namespace llvm::opt;
Driver::Driver(StringRef ClangExecutable,
StringRef DefaultTargetTriple,
StringRef DefaultImageName,
DiagnosticsEngine &Diags)
- : Opts(createDriverOptTable()), Diags(Diags),
+ : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
DefaultImageName(DefaultImageName),
DriverTitle("clang LLVM compiler"),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
- CCLogDiagnosticsFilename(0), CCCIsCXX(false),
- CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
- CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
+ CCLogDiagnosticsFilename(0),
+ CCCPrintBindings(false),
+ CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
CCCUsePCH(true), SuppressMissingInputWarning(false) {
@@ -79,11 +83,43 @@ Driver::~Driver() {
delete I->second;
}
+void Driver::ParseDriverMode(ArrayRef<const char *> Args) {
+ const std::string OptName =
+ getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
+
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ const StringRef Arg = Args[I];
+ if (!Arg.startswith(OptName))
+ continue;
+
+ const StringRef Value = Arg.drop_front(OptName.size());
+ const unsigned M = llvm::StringSwitch<unsigned>(Value)
+ .Case("gcc", GCCMode)
+ .Case("g++", GXXMode)
+ .Case("cpp", CPPMode)
+ .Case("cl", CLMode)
+ .Default(~0U);
+
+ if (M != ~0U)
+ Mode = static_cast<DriverMode>(M);
+ else
+ Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
+ }
+}
+
InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+
+ unsigned IncludedFlagsBitmask;
+ unsigned ExcludedFlagsBitmask;
+ llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+ getIncludeExcludeOptionFlagMasks();
+
unsigned MissingArgIndex, MissingArgCount;
InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
- MissingArgIndex, MissingArgCount);
+ MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask,
+ ExcludedFlagsBitmask);
// Check for missing argument error.
if (MissingArgCount)
@@ -107,6 +143,11 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
}
}
+ for (arg_iterator it = Args->filtered_begin(options::OPT_UNKNOWN),
+ ie = Args->filtered_end(); it != ie; ++it) {
+ Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);
+ }
+
return Args;
}
@@ -119,7 +160,7 @@ const {
phases::ID FinalPhase;
// -{E,M,MM} only run the preprocessor.
- if (CCCIsCPP ||
+ if (CCCIsCPP() ||
(PhaseArg = DAL.getLastArg(options::OPT_E)) ||
(PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) {
FinalPhase = phases::Preprocess;
@@ -150,6 +191,14 @@ const {
return FinalPhase;
}
+static Arg* MakeInputArg(const DerivedArgList &Args, OptTable *Opts,
+ StringRef Value) {
+ Arg *A = new Arg(Opts->getOption(options::OPT_INPUT), Value,
+ Args.getBaseArgs().MakeIndex(Value), Value.data());
+ A->claim();
+ return A;
+}
+
DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
DerivedArgList *DAL = new DerivedArgList(Args);
@@ -215,6 +264,14 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
}
}
+ // Pick up inputs via the -- option.
+ if (A->getOption().matches(options::OPT__DASH_DASH)) {
+ A->claim();
+ for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
+ DAL->append(MakeInputArg(*DAL, Opts, A->getValue(i)));
+ continue;
+ }
+
DAL->append(*it);
}
@@ -241,16 +298,20 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
StringRef CompilerPath = env;
while (!CompilerPath.empty()) {
std::pair<StringRef, StringRef> Split
- = CompilerPath.split(llvm::sys::PathSeparator);
+ = CompilerPath.split(llvm::sys::EnvPathSeparator);
PrefixDirs.push_back(Split.first);
CompilerPath = Split.second;
}
}
+ // We look for the driver mode option early, because the mode can affect
+ // how other options are parsed.
+ ParseDriverMode(ArgList.slice(1));
+
// FIXME: What are we going to do with -V and -b?
// FIXME: This stuff needs to go into the Compilation, not the driver.
- bool CCCPrintOptions, CCCPrintActions;
+ bool CCCPrintActions;
InputArgList *Args = ParseArgStrings(ArgList.slice(1));
@@ -266,17 +327,20 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// should be outside in the client; the parts that aren't should have proper
// options, either by introducing new ones or by overloading gcc ones like -V
// or -b.
- CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options);
CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases);
CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings);
- CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
- CCCEcho = Args->hasArg(options::OPT_ccc_echo);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
CCCGenericGCCName = A->getValue();
CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch,
options::OPT_ccc_pch_is_pth);
// FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
+ if (IsCLMode()) {
+ // clang-cl targets Win32.
+ llvm::Triple T(DefaultTargetTriple);
+ T.setOSName(llvm::Triple::getOSTypeName(llvm::Triple::Win32));
+ DefaultTargetTriple = T.str();
+ }
if (const Arg *A = Args->getLastArg(options::OPT_target))
DefaultTargetTriple = A->getValue();
if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
@@ -289,6 +353,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
}
if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ))
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;
@@ -304,18 +370,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// The compilation takes ownership of Args.
Compilation *C = new Compilation(*this, TC, Args, TranslatedArgs);
- // FIXME: This behavior shouldn't be here.
- if (CCCPrintOptions) {
- PrintOptions(C->getInputArgs());
- return C;
- }
-
if (!HandleImmediateArgs(*C))
return C;
// Construct the list of inputs.
InputList Inputs;
- BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs);
+ BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs);
// Construct the list of abstract actions to perform for this compilation. On
// Darwin target OSes this uses the driver-driver and universal actions.
@@ -357,7 +417,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
"crash backtrace, preprocessed source, and associated run script.";
// Suppress driver output and emit preprocessor output to temp file.
- CCCIsCPP = true;
+ Mode = CPPMode;
CCGenDiagnostics = true;
C.getArgs().AddFlagArg(0, Opts->getOption(options::OPT_frewrite_includes));
@@ -365,11 +425,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
std::string Cmd;
llvm::raw_string_ostream OS(Cmd);
if (FailingCommand)
- C.PrintDiagnosticJob(OS, *FailingCommand);
+ FailingCommand->Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true);
else
// Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an
// associated FailingCommand, so just pass all jobs.
- C.PrintDiagnosticJob(OS, C.getJobs());
+ C.getJobs().Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true);
OS.flush();
// Keep track of whether we produce any errors while trying to produce
@@ -463,9 +523,8 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
std::string Err;
std::string Script = StringRef(*it).rsplit('.').first;
Script += ".sh";
- llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err,
- llvm::raw_fd_ostream::F_Excl |
- llvm::raw_fd_ostream::F_Binary);
+ llvm::raw_fd_ostream ScriptOS(
+ Script.c_str(), Err, llvm::sys::fs::F_Excl | llvm::sys::fs::F_Binary);
if (!Err.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + Err;
@@ -503,7 +562,7 @@ int Driver::ExecuteCompilation(const Compilation &C,
SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const {
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
- C.PrintJob(llvm::errs(), C.getJobs(), "\n", true);
+ C.getJobs().Print(llvm::errs(), "\n", true);
return 0;
}
@@ -559,28 +618,18 @@ int Driver::ExecuteCompilation(const Compilation &C,
return 0;
}
-void Driver::PrintOptions(const ArgList &Args) const {
- unsigned i = 0;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it, ++i) {
- Arg *A = *it;
- llvm::errs() << "Option " << i << " - "
- << "Name: \"" << A->getOption().getPrefixedName() << "\", "
- << "Values: {";
- for (unsigned j = 0; j < A->getNumValues(); ++j) {
- if (j)
- llvm::errs() << ", ";
- llvm::errs() << '"' << A->getValue(j) << '"';
- }
- llvm::errs() << "}\n";
- }
-}
-
void Driver::PrintHelp(bool ShowHidden) const {
+ unsigned IncludedFlagsBitmask;
+ unsigned ExcludedFlagsBitmask;
+ llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+ getIncludeExcludeOptionFlagMasks();
+
+ ExcludedFlagsBitmask |= options::NoDriverOption;
+ if (!ShowHidden)
+ ExcludedFlagsBitmask |= HelpHidden;
+
getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
- /*Include*/0,
- /*Exclude*/options::NoDriverOption |
- (ShowHidden ? 0 : options::HelpHidden));
+ IncludedFlagsBitmask, ExcludedFlagsBitmask);
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -649,6 +698,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
const ToolChain &TC = C.getDefaultToolChain();
+
+ if (C.getArgs().hasArg(options::OPT_v))
+ TC.printVerboseInfo(llvm::errs());
+
if (C.getArgs().hasArg(options::OPT_print_search_dirs)) {
llvm::outs() << "programs: =";
for (ToolChain::path_list::const_iterator it = TC.getProgramPaths().begin(),
@@ -707,6 +760,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
case llvm::Triple::ppc64:
llvm::outs() << "ppc64;@m64" << "\n";
break;
+
+ case llvm::Triple::ppc64le:
+ llvm::outs() << "ppc64le;@m64" << "\n";
+ break;
}
return false;
}
@@ -729,6 +786,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
case llvm::Triple::ppc64:
llvm::outs() << "ppc64" << "\n";
break;
+
+ case llvm::Triple::ppc64le:
+ llvm::outs() << "ppc64le" << "\n";
+ break;
}
return false;
}
@@ -790,7 +851,7 @@ static bool ContainsCompileOrAssembleAction(const Action *A) {
}
void Driver::BuildUniversalActions(const ToolChain &TC,
- const DerivedArgList &Args,
+ DerivedArgList &Args,
const InputList &BAInputs,
ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building universal build actions");
@@ -885,6 +946,33 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
}
+/// \brief Check that the file referenced by Value exists. If it doesn't,
+/// issue a diagnostic and return false.
+static bool DiagnoseInputExistance(const Driver &D, const DerivedArgList &Args,
+ StringRef Value) {
+ if (!D.getCheckInputsExist())
+ return true;
+
+ // stdin always exists.
+ if (Value == "-")
+ return true;
+
+ SmallString<64> Path(Value);
+ if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
+ if (!llvm::sys::path::is_absolute(Path.str())) {
+ SmallString<64> Directory(WorkDir->getValue());
+ llvm::sys::path::append(Directory, Value);
+ Path.assign(Directory);
+ }
+ }
+
+ if (llvm::sys::fs::exists(Twine(Path)))
+ return true;
+
+ D.Diag(clang::diag::err_drv_no_such_file) << Path.str();
+ return false;
+}
+
// Construct a the list of inputs and their types.
void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
InputList &Inputs) const {
@@ -894,6 +982,31 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
types::ID InputType = types::TY_Nothing;
Arg *InputTypeArg = 0;
+ // The last /TC or /TP option sets the input type to C or C++ globally.
+ if (Arg *TCTP = Args.getLastArg(options::OPT__SLASH_TC,
+ options::OPT__SLASH_TP)) {
+ InputTypeArg = TCTP;
+ InputType = TCTP->getOption().matches(options::OPT__SLASH_TC)
+ ? types::TY_C : types::TY_CXX;
+
+ arg_iterator it = Args.filtered_begin(options::OPT__SLASH_TC,
+ options::OPT__SLASH_TP);
+ const arg_iterator ie = Args.filtered_end();
+ Arg *Previous = *it++;
+ bool ShowNote = false;
+ while (it != ie) {
+ Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Previous->getSpelling() << (*it)->getSpelling();
+ Previous = *it++;
+ ShowNote = true;
+ }
+ if (ShowNote)
+ Diag(clang::diag::note_drv_t_option_is_global);
+
+ // No driver mode exposes -x and /TC or /TP; we don't support mixing them.
+ assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed");
+ }
+
for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it) {
Arg *A = *it;
@@ -915,7 +1028,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
//
// Otherwise emit an error but still use a valid type to avoid
// spurious errors (e.g., no inputs).
- if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP)
+ if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP())
Diag(clang::diag::err_drv_unknown_stdin_type);
Ty = types::TY_C;
} else {
@@ -927,7 +1040,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
Ty = TC.LookupTypeForExtension(Ext + 1);
if (Ty == types::TY_INVALID) {
- if (CCCIsCPP)
+ if (CCCIsCPP())
Ty = types::TY_C;
else
Ty = types::TY_Object;
@@ -935,7 +1048,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
// If the driver is invoked as C++ compiler (like clang++ or c++) it
// should autodetect some input files as C++ for g++ compatibility.
- if (CCCIsCXX) {
+ if (CCCIsCXX()) {
types::ID OldTy = Ty;
Ty = types::lookupCXXTypeForCType(Ty);
@@ -962,25 +1075,23 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
Ty = InputType;
}
- // Check that the file exists, if enabled.
- if (CheckInputsExist && memcmp(Value, "-", 2) != 0) {
- SmallString<64> Path(Value);
- if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
- if (!llvm::sys::path::is_absolute(Path.str())) {
- SmallString<64> Directory(WorkDir->getValue());
- llvm::sys::path::append(Directory, Value);
- Path.assign(Directory);
- }
- }
-
- bool exists = false;
- if (llvm::sys::fs::exists(Path.c_str(), exists) || !exists)
- Diag(clang::diag::err_drv_no_such_file) << Path.str();
- else
- Inputs.push_back(std::make_pair(Ty, A));
- } else
+ if (DiagnoseInputExistance(*this, Args, Value))
Inputs.push_back(std::make_pair(Ty, A));
+ } else if (A->getOption().matches(options::OPT__SLASH_Tc)) {
+ StringRef Value = A->getValue();
+ if (DiagnoseInputExistance(*this, Args, Value)) {
+ Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
+ Inputs.push_back(std::make_pair(types::TY_C, InputArg));
+ }
+ A->claim();
+ } else if (A->getOption().matches(options::OPT__SLASH_Tp)) {
+ StringRef Value = A->getValue();
+ if (DiagnoseInputExistance(*this, Args, Value)) {
+ Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
+ Inputs.push_back(std::make_pair(types::TY_CXX, InputArg));
+ }
+ A->claim();
} else if (A->getOption().hasFlag(options::LinkerInput)) {
// Just treat as object type, we could make a special type for this if
// necessary.
@@ -1000,17 +1111,15 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
}
}
}
- if (CCCIsCPP && Inputs.empty()) {
+ if (CCCIsCPP() && Inputs.empty()) {
// If called as standalone preprocessor, stdin is processed
// if no other input is present.
- unsigned Index = Args.getBaseArgs().MakeIndex("-");
- Arg *A = Opts->ParseOneArg(Args, Index);
- A->claim();
+ Arg *A = MakeInputArg(Args, Opts, "-");
Inputs.push_back(std::make_pair(types::TY_C, A));
}
}
-void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
+void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
const InputList &Inputs, ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
@@ -1022,11 +1131,50 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
Arg *FinalPhaseArg;
phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
+ if (FinalPhase == phases::Link && Args.hasArg(options::OPT_emit_llvm)) {
+ Diag(clang::diag::err_drv_emit_llvm_link);
+ }
+
// Reject -Z* at the top level, these options should never have been exposed
// by gcc.
if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
+ // Diagnose misuse of /Fo.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
+ StringRef V = A->getValue();
+ if (V.empty()) {
+ // It has to have a value.
+ Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
+ Args.eraseArg(options::OPT__SLASH_Fo);
+ } else if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) {
+ // Check whether /Fo tries to name an output file for multiple inputs.
+ Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
+ << A->getSpelling() << V;
+ Args.eraseArg(options::OPT__SLASH_Fo);
+ }
+ }
+
+ // Diagnose misuse of /Fa.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) {
+ StringRef V = A->getValue();
+ if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) {
+ // Check whether /Fa tries to name an asm file for multiple inputs.
+ Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
+ << A->getSpelling() << V;
+ Args.eraseArg(options::OPT__SLASH_Fa);
+ }
+ }
+
+ // Diagnose misuse of /Fe.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fe)) {
+ if (A->getValue()[0] == '\0') {
+ // It has to have a value.
+ Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
+ Args.eraseArg(options::OPT__SLASH_Fe);
+ }
+ }
+
// Construct the actions to perform.
ActionList LinkerInputs;
ActionList SplitInputs;
@@ -1051,7 +1199,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Special case when final phase determined by binary name, rather than
// by a command-line argument with a corresponding Arg.
- if (CCCIsCPP)
+ if (CCCIsCPP())
Diag(clang::diag::warn_drv_input_file_unused_by_cpp)
<< InputArg->getAsString(Args)
<< getPhaseName(InitialPhase);
@@ -1075,7 +1223,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Build the pipeline for this file.
OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
- for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator
+ for (SmallVectorImpl<phases::ID>::iterator
i = PL.begin(), e = PL.end(); i != e; ++i) {
phases::ID Phase = *i;
@@ -1113,8 +1261,13 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// If we are linking, claim any options which are obviously only used for
// compilation.
- if (FinalPhase == phases::Link && PL.size() == 1)
+ if (FinalPhase == phases::Link && PL.size() == 1) {
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
+ Args.ClaimAllArgs(options::OPT_cl_compile_Group);
+ }
+
+ // Claim ignored clang-cl options.
+ Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
}
Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
@@ -1165,6 +1318,10 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
return new CompileJobAction(Input, Output);
+ } else if (Args.hasArg(options::OPT_emit_llvm)) {
+ types::ID Output =
+ Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
+ return new CompileJobAction(Input, Output);
} else {
return new CompileJobAction(Input, types::TY_PP_Asm);
}
@@ -1177,15 +1334,9 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
}
bool Driver::IsUsingLTO(const ArgList &Args) const {
- // Check for -emit-llvm or -flto.
- if (Args.hasArg(options::OPT_emit_llvm) ||
- Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false))
+ if (Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false))
return true;
- // Check for -O4.
- if (const Arg *A = Args.getLastArg(options::OPT_O_Group))
- return A->getOption().matches(options::OPT_O4);
-
return false;
}
@@ -1256,6 +1407,9 @@ void Driver::BuildJobs(Compilation &C) const {
// Claim -### here.
(void) C.getArgs().hasArg(options::OPT__HASH_HASH_HASH);
+ // Claim --driver-mode, it was handled earlier.
+ (void) C.getArgs().hasArg(options::OPT_driver_mode);
+
for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
it != ie; ++it) {
Arg *A = *it;
@@ -1302,6 +1456,8 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
if (TC->useIntegratedAs() &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
+ !C.getArgs().hasArg(options::OPT__SLASH_FA) &&
+ !C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
const Tool *Compiler =
@@ -1424,6 +1580,38 @@ void Driver::BuildJobsForAction(Compilation &C,
}
}
+/// \brief Create output filename based on ArgValue, which could either be a
+/// full filename, filename without extension, or a directory. If ArgValue
+/// does not provide a filename, then use BaseName, and use the extension
+/// suitable for FileType.
+static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue,
+ StringRef BaseName, types::ID FileType) {
+ SmallString<128> Filename = ArgValue;
+
+ if (ArgValue.empty()) {
+ // If the argument is empty, output to BaseName in the current dir.
+ Filename = BaseName;
+ } else if (llvm::sys::path::is_separator(Filename.back())) {
+ // If the argument is a directory, output to BaseName in that dir.
+ llvm::sys::path::append(Filename, BaseName);
+ }
+
+ if (!llvm::sys::path::has_extension(ArgValue)) {
+ // If the argument didn't provide an extension, then set it.
+ const char *Extension = types::getTypeTempSuffix(FileType, true);
+
+ if (FileType == types::TY_Image &&
+ Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd)) {
+ // The output file is a dll.
+ Extension = "dll";
+ }
+
+ llvm::sys::path::replace_extension(Filename, Extension);
+ }
+
+ return Args.MakeArgString(Filename.c_str());
+}
+
const char *Driver::GetNamedOutputPath(Compilation &C,
const JobAction &JA,
const char *BaseInput,
@@ -1443,13 +1631,26 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
(isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile))
return "-";
+ // Is this the assembly listing for /FA?
+ if (JA.getType() == types::TY_PP_Asm &&
+ (C.getArgs().hasArg(options::OPT__SLASH_FA) ||
+ C.getArgs().hasArg(options::OPT__SLASH_Fa))) {
+ // Use /Fa and the input filename to determine the asm file name.
+ StringRef BaseName = llvm::sys::path::filename(BaseInput);
+ StringRef FaValue = C.getArgs().getLastArgValue(options::OPT__SLASH_Fa);
+ return C.addResultFile(MakeCLOutputFilename(C.getArgs(), FaValue, BaseName,
+ JA.getType()), &JA);
+ }
+
// Output to a temporary file?
- if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) ||
+ if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps) &&
+ !C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
std::string TmpName =
- GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType()));
+ GetTemporaryPath(Split.first,
+ types::getTypeTempSuffix(JA.getType(), IsCLMode()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
@@ -1464,8 +1665,25 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
// Determine what the derived output name should be.
const char *NamedOutput;
- if (JA.getType() == types::TY_Image) {
- if (MultipleArchs && BoundArch) {
+
+ if (JA.getType() == types::TY_Object &&
+ C.getArgs().hasArg(options::OPT__SLASH_Fo)) {
+ // The /Fo flag decides the object filename.
+ StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue();
+ NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
+ types::TY_Object);
+ } else if (JA.getType() == types::TY_Image &&
+ C.getArgs().hasArg(options::OPT__SLASH_Fe)) {
+ // The /Fe flag names the linked file.
+ StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe)->getValue();
+ NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
+ types::TY_Image);
+ } else if (JA.getType() == types::TY_Image) {
+ if (IsCLMode()) {
+ // clang-cl uses BaseName for the executable name.
+ NamedOutput = MakeCLOutputFilename(C.getArgs(), "", BaseName,
+ types::TY_Image);
+ } else if (MultipleArchs && BoundArch) {
SmallString<128> Output(DefaultImageName.c_str());
Output += "-";
Output.append(BoundArch);
@@ -1473,7 +1691,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
} else
NamedOutput = DefaultImageName.c_str();
} else {
- const char *Suffix = types::getTypeTempSuffix(JA.getType());
+ const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
assert(Suffix && "All types used for output should have a suffix.");
std::string::size_type End = std::string::npos;
@@ -1504,7 +1722,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
std::string TmpName =
- GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType()));
+ GetTemporaryPath(Split.first,
+ types::getTypeTempSuffix(JA.getType(), IsCLMode()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
}
@@ -1532,17 +1751,15 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
continue;
if (Dir[0] == '=')
Dir = SysRoot + Dir.substr(1);
- llvm::sys::Path P(Dir);
- P.appendComponent(Name);
- bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ SmallString<128> P(Dir);
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::exists(Twine(P)))
return P.str();
}
- llvm::sys::Path P(ResourceDir);
- P.appendComponent(Name);
- bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ SmallString<128> P(ResourceDir);
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::exists(Twine(P)))
return P.str();
const ToolChain::path_list &List = TC.getFilePaths();
@@ -1553,10 +1770,9 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
continue;
if (Dir[0] == '=')
Dir = SysRoot + Dir.substr(1);
- llvm::sys::Path P(Dir);
- P.appendComponent(Name);
- bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ SmallString<128> P(Dir);
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::exists(Twine(P)))
return P.str();
}
@@ -1571,69 +1787,58 @@ std::string Driver::GetProgramPath(const char *Name,
// attempting to use this prefix when looking for program paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
- bool IsDirectory;
- if (!llvm::sys::fs::is_directory(*it, IsDirectory) && IsDirectory) {
- llvm::sys::Path P(*it);
- P.appendComponent(TargetSpecificExecutable);
- if (P.canExecute()) return P.str();
- P.eraseComponent();
- P.appendComponent(Name);
- if (P.canExecute()) return P.str();
+ if (llvm::sys::fs::is_directory(*it)) {
+ SmallString<128> P(*it);
+ llvm::sys::path::append(P, TargetSpecificExecutable);
+ if (llvm::sys::fs::can_execute(Twine(P)))
+ return P.str();
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::can_execute(Twine(P)))
+ return P.str();
} else {
- llvm::sys::Path P(*it + Name);
- if (P.canExecute()) return P.str();
+ SmallString<128> P(*it + Name);
+ if (llvm::sys::fs::can_execute(Twine(P)))
+ return P.str();
}
}
const ToolChain::path_list &List = TC.getProgramPaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
- llvm::sys::Path P(*it);
- P.appendComponent(TargetSpecificExecutable);
- if (P.canExecute()) return P.str();
- P.eraseComponent();
- P.appendComponent(Name);
- if (P.canExecute()) return P.str();
+ SmallString<128> P(*it);
+ llvm::sys::path::append(P, TargetSpecificExecutable);
+ if (llvm::sys::fs::can_execute(Twine(P)))
+ return P.str();
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::can_execute(Twine(P)))
+ return P.str();
}
// If all else failed, search the path.
- llvm::sys::Path
- P(llvm::sys::Program::FindProgramByName(TargetSpecificExecutable));
+ std::string P(llvm::sys::FindProgramByName(TargetSpecificExecutable));
if (!P.empty())
- return P.str();
+ return P;
- P = llvm::sys::Path(llvm::sys::Program::FindProgramByName(Name));
+ P = llvm::sys::FindProgramByName(Name);
if (!P.empty())
- return P.str();
+ return P;
return Name;
}
std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix)
const {
- // FIXME: This is lame; sys::Path should provide this function (in particular,
- // it should know how to find the temporary files dir).
- std::string Error;
- const char *TmpDir = ::getenv("TMPDIR");
- if (!TmpDir)
- TmpDir = ::getenv("TEMP");
- if (!TmpDir)
- TmpDir = ::getenv("TMP");
- if (!TmpDir)
- TmpDir = "/tmp";
- llvm::sys::Path P(TmpDir);
- P.appendComponent(Prefix);
- if (P.makeUnique(false, &Error)) {
- Diag(clang::diag::err_unable_to_make_temp) << Error;
+ SmallString<128> Path;
+ llvm::error_code EC =
+ llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path);
+ if (EC) {
+ Diag(clang::diag::err_unable_to_make_temp) << EC.message();
return "";
}
- // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
- P.eraseFromDisk(false, 0);
-
- if (Suffix)
- P.appendSuffix(Suffix);
- return P.str();
+ return Path.str();
}
/// \brief Compute target triple from args.
@@ -1772,6 +1977,10 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = new toolchains::Hexagon_TC(*this, Target, Args);
break;
}
+ if (Target.getArch() == llvm::Triple::xcore) {
+ TC = new toolchains::XCore(*this, Target, Args);
+ break;
+ }
TC = new toolchains::Generic_GCC(*this, Target, Args);
break;
}
@@ -1831,3 +2040,18 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major,
HadExtra = true;
return true;
}
+
+std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const {
+ unsigned IncludedFlagsBitmask = 0;
+ unsigned ExcludedFlagsBitmask = options::NoDriverOption;
+
+ if (Mode == CLMode) {
+ // Include CL and Core options.
+ IncludedFlagsBitmask |= options::CLOption;
+ IncludedFlagsBitmask |= options::CoreOption;
+ } else {
+ ExcludedFlagsBitmask |= options::CLOption;
+ }
+
+ return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
+}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 3925b8aa35c5..6ff1cbafb3bc 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -8,26 +8,25 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Options.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
using namespace clang::driver;
using namespace clang::driver::options;
+using namespace llvm::opt;
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
- HELPTEXT, METAVAR)
+#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
#include "clang/Driver/Options.inc"
-#undef OPTION
#undef PREFIX
static const OptTable::Info InfoTable[] = {
-#define PREFIX(NAME, VALUE)
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#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 },
+ FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "clang/Driver/Options.inc"
+#undef OPTION
};
namespace {
@@ -35,7 +34,7 @@ namespace {
class DriverOptTable : public OptTable {
public:
DriverOptTable()
- : OptTable(InfoTable, sizeof(InfoTable) / sizeof(InfoTable[0])) {}
+ : OptTable(InfoTable, llvm::array_lengthof(InfoTable)) {}
};
}
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index a243d322ee21..4eedd22a62da 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -10,8 +10,8 @@
#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
#define CLANG_LIB_DRIVER_INPUTINFO_H_
-#include "clang/Driver/Arg.h"
#include "clang/Driver/Types.h"
+#include "llvm/Option/Arg.h"
#include <cassert>
#include <string>
@@ -35,7 +35,7 @@ class InputInfo {
union {
const char *Filename;
- const Arg *InputArg;
+ const llvm::opt::Arg *InputArg;
} Data;
Class Kind;
types::ID Type;
@@ -50,8 +50,9 @@ public:
: Kind(Filename), Type(_Type), BaseInput(_BaseInput) {
Data.Filename = _Filename;
}
- InputInfo(const Arg *_InputArg, types::ID _Type, const char *_BaseInput)
- : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) {
+ InputInfo(const llvm::opt::Arg *_InputArg, types::ID _Type,
+ const char *_BaseInput)
+ : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) {
Data.InputArg = _InputArg;
}
@@ -65,7 +66,7 @@ public:
assert(isFilename() && "Invalid accessor.");
return Data.Filename;
}
- const Arg &getInputArg() const {
+ const llvm::opt::Arg &getInputArg() const {
assert(isInputArg() && "Invalid accessor.");
return *Data.InputArg;
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 8c467050d563..ee68e6f14d51 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -9,18 +9,158 @@
#include "clang/Driver/Job.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
using namespace clang::driver;
+using llvm::raw_ostream;
+using llvm::StringRef;
Job::~Job() {}
-void Command::anchor() {}
-
Command::Command(const Action &_Source, const Tool &_Creator,
- const char *_Executable, const ArgStringList &_Arguments)
- : Job(CommandClass), Source(_Source), Creator(_Creator),
- Executable(_Executable), Arguments(_Arguments)
-{
+ const char *_Executable,
+ const ArgStringList &_Arguments)
+ : Job(CommandClass), Source(_Source), Creator(_Creator),
+ Executable(_Executable), Arguments(_Arguments) {}
+
+static int skipArgs(const char *Flag) {
+ // These flags are all of the form -Flag <Arg> and are treated as two
+ // arguments. Therefore, we need to skip the flag and the next argument.
+ bool Res = llvm::StringSwitch<bool>(Flag)
+ .Cases("-I", "-MF", "-MT", "-MQ", true)
+ .Cases("-o", "-coverage-file", "-dependency-file", true)
+ .Cases("-fdebug-compilation-dir", "-idirafter", true)
+ .Cases("-include", "-include-pch", "-internal-isystem", true)
+ .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
+ .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
+ .Cases("-resource-dir", "-serialize-diagnostic-file", true)
+ .Case("-dwarf-debug-flags", true)
+ .Default(false);
+
+ // Match found.
+ if (Res)
+ return 2;
+
+ // The remaining flags are treated as a single argument.
+
+ // These flags are all of the form -Flag and have no second argument.
+ Res = llvm::StringSwitch<bool>(Flag)
+ .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
+ .Case("-MMD", true)
+ .Default(false);
+
+ // Match found.
+ if (Res)
+ return 1;
+
+ // These flags are treated as a single argument (e.g., -F<Dir>).
+ StringRef FlagRef(Flag);
+ if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
+ return 1;
+
+ return 0;
+}
+
+static bool quoteNextArg(const char *flag) {
+ return llvm::StringSwitch<bool>(flag)
+ .Case("-D", true)
+ .Default(false);
+}
+
+static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
+ const bool Escape = std::strpbrk(Arg, "\"\\$");
+
+ if (!Quote && !Escape) {
+ OS << Arg;
+ return;
+ }
+
+ // Quote and escape. This isn't really complete, but good enough.
+ OS << '"';
+ while (const char c = *Arg++) {
+ if (c == '"' || c == '\\' || c == '$')
+ OS << '\\';
+ OS << c;
+ }
+ OS << '"';
+}
+
+void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
+ bool CrashReport) const {
+ OS << " \"" << Executable << '"';
+
+ for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
+ const char *const Arg = Arguments[i];
+
+ if (CrashReport) {
+ if (int Skip = skipArgs(Arg)) {
+ i += Skip - 1;
+ continue;
+ }
+ }
+
+ OS << ' ';
+ PrintArg(OS, Arg, Quote);
+
+ if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
+ OS << ' ';
+ PrintArg(OS, Arguments[++i], true);
+ }
+ }
+ OS << Terminator;
+}
+
+int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
+ bool *ExecutionFailed) const {
+ SmallVector<const char*, 128> Argv;
+ Argv.push_back(Executable);
+ for (size_t i = 0, e = Arguments.size(); i != e; ++i)
+ Argv.push_back(Arguments[i]);
+ Argv.push_back(0);
+
+ return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ 0,
+ Redirects, /*secondsToWait*/ 0,
+ /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
+}
+
+FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
+ const char *Executable_,
+ const ArgStringList &Arguments_,
+ Command *Fallback_)
+ : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) {
+}
+
+void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
+ bool Quote, bool CrashReport) const {
+ Command::Print(OS, "", Quote, CrashReport);
+ OS << " ||";
+ Fallback->Print(OS, Terminator, Quote, CrashReport);
+}
+
+static bool ShouldFallback(int ExitCode) {
+ // FIXME: We really just want to fall back for internal errors, such
+ // as when some symbol cannot be mangled, when we should be able to
+ // parse something but can't, etc.
+ return ExitCode != 0;
+}
+
+int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
+ bool *ExecutionFailed) const {
+ int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
+ if (!ShouldFallback(PrimaryStatus))
+ return PrimaryStatus;
+
+ // Clear ExecutionFailed and ErrMsg before falling back.
+ if (ErrMsg)
+ ErrMsg->clear();
+ if (ExecutionFailed)
+ *ExecutionFailed = false;
+
+ int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
+ return SecondaryStatus;
}
JobList::JobList() : Job(JobListClass) {}
@@ -30,11 +170,12 @@ JobList::~JobList() {
delete *it;
}
-void JobList::clear() {
- DeleteContainerPointers(Jobs);
+void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
+ bool CrashReport) const {
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it)
+ (*it)->Print(OS, Terminator, Quote, CrashReport);
}
-void Job::addCommand(Command *C) {
- cast<JobList>(this)->addJob(C);
+void JobList::clear() {
+ DeleteContainerPointers(Jobs);
}
-
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
deleted file mode 100644
index 20214a68d5cd..000000000000
--- a/lib/Driver/OptTable.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-//===--- OptTable.cpp - Option Table Implementation -----------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Option.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <map>
-using namespace clang::driver;
-using namespace clang::driver::options;
-using namespace clang;
-
-// Ordering on Info. The ordering is *almost* lexicographic, with two
-// exceptions. First, '\0' comes at the end of the alphabet instead of
-// the beginning (thus options precede any other options which prefix
-// them). Second, for options with the same name, the less permissive
-// version should come first; a Flag option should precede a Joined
-// option, for example.
-
-static int StrCmpOptionName(const char *A, const char *B) {
- char a = *A, b = *B;
- while (a == b) {
- if (a == '\0')
- return 0;
-
- a = *++A;
- b = *++B;
- }
-
- if (a == '\0') // A is a prefix of B.
- return 1;
- if (b == '\0') // B is a prefix of A.
- return -1;
-
- // Otherwise lexicographic.
- return (a < b) ? -1 : 1;
-}
-
-namespace clang {
-namespace driver {
-static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
- if (&A == &B)
- return false;
-
- if (int N = StrCmpOptionName(A.Name, B.Name))
- return N == -1;
-
- for (const char * const *APre = A.Prefixes,
- * const *BPre = B.Prefixes;
- *APre != 0 && *BPre != 0; ++APre, ++BPre) {
- if (int N = StrCmpOptionName(*APre, *BPre))
- return N == -1;
- }
-
- // Names are the same, check that classes are in order; exactly one
- // should be joined, and it should succeed the other.
- assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
- "Unexpected classes for options with same name.");
- return B.Kind == Option::JoinedClass;
-}
-
-// Support lower_bound between info and an option name.
-static inline bool operator<(const OptTable::Info &I, const char *Name) {
- return StrCmpOptionName(I.Name, Name) == -1;
-}
-static inline bool operator<(const char *Name, const OptTable::Info &I) {
- return StrCmpOptionName(Name, I.Name) == -1;
-}
-}
-}
-
-//
-
-OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
-
-//
-
-OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
- : OptionInfos(_OptionInfos),
- NumOptionInfos(_NumOptionInfos),
- TheInputOptionID(0),
- TheUnknownOptionID(0),
- FirstSearchableIndex(0)
-{
- // Explicitly zero initialize the error to work around a bug in array
- // value-initialization on MinGW with gcc 4.3.5.
-
- // Find start of normal options.
- for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
- unsigned Kind = getInfo(i + 1).Kind;
- if (Kind == Option::InputClass) {
- assert(!TheInputOptionID && "Cannot have multiple input options!");
- TheInputOptionID = getInfo(i + 1).ID;
- } else if (Kind == Option::UnknownClass) {
- assert(!TheUnknownOptionID && "Cannot have multiple unknown options!");
- TheUnknownOptionID = getInfo(i + 1).ID;
- } else if (Kind != Option::GroupClass) {
- FirstSearchableIndex = i;
- break;
- }
- }
- assert(FirstSearchableIndex != 0 && "No searchable options?");
-
-#ifndef NDEBUG
- // Check that everything after the first searchable option is a
- // regular option class.
- for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
- Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
- assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
- Kind != Option::GroupClass) &&
- "Special options should be defined first!");
- }
-
- // Check that options are in order.
- for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
- if (!(getInfo(i) < getInfo(i + 1))) {
- getOption(i).dump();
- getOption(i + 1).dump();
- llvm_unreachable("Options are not in order!");
- }
- }
-#endif
-
- // Build prefixes.
- for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
- if (const char *const *P = getInfo(i).Prefixes) {
- for (; *P != 0; ++P) {
- PrefixesUnion.insert(*P);
- }
- }
- }
-
- // Build prefix chars.
- for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
- E = PrefixesUnion.end(); I != E; ++I) {
- StringRef Prefix = I->getKey();
- for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
- C != CE; ++C)
- if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
- == PrefixChars.end())
- PrefixChars.push_back(*C);
- }
-}
-
-OptTable::~OptTable() {
-}
-
-const Option OptTable::getOption(OptSpecifier Opt) const {
- unsigned id = Opt.getID();
- if (id == 0)
- return Option(0, 0);
- assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
- return Option(&getInfo(id), this);
-}
-
-static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
- if (Arg == "-")
- return true;
- for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
- E = Prefixes.end(); I != E; ++I)
- if (Arg.startswith(I->getKey()))
- return false;
- return true;
-}
-
-/// \returns Matched size. 0 means no match.
-static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
- for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
- StringRef Prefix(*Pre);
- if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
- return Prefix.size() + StringRef(I->Name).size();
- }
- return 0;
-}
-
-Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
- unsigned Prev = Index;
- const char *Str = Args.getArgString(Index);
-
- // Anything that doesn't start with PrefixesUnion is an input, as is '-'
- // itself.
- if (isInput(PrefixesUnion, Str))
- return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
-
- const Info *Start = OptionInfos + FirstSearchableIndex;
- const Info *End = OptionInfos + getNumOptions();
- StringRef Name = StringRef(Str).ltrim(PrefixChars);
-
- // Search for the first next option which could be a prefix.
- Start = std::lower_bound(Start, End, Name.data());
-
- // Options are stored in sorted order, with '\0' at the end of the
- // alphabet. Since the only options which can accept a string must
- // prefix it, we iteratively search for the next option which could
- // be a prefix.
- //
- // FIXME: This is searching much more than necessary, but I am
- // blanking on the simplest way to make it fast. We can solve this
- // problem when we move to TableGen.
- for (; Start != End; ++Start) {
- unsigned ArgSize = 0;
- // Scan for first option which is a proper prefix.
- for (; Start != End; ++Start)
- if ((ArgSize = matchOption(Start, Str)))
- break;
- if (Start == End)
- break;
-
- // See if this option matches.
- if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
- return A;
-
- // Otherwise, see if this argument was missing values.
- if (Prev != Index)
- return 0;
- }
-
- return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
-}
-
-InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
- const char* const *ArgEnd,
- unsigned &MissingArgIndex,
- unsigned &MissingArgCount) const {
- InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
-
- // FIXME: Handle '@' args (or at least error on them).
-
- MissingArgIndex = MissingArgCount = 0;
- unsigned Index = 0, End = ArgEnd - ArgBegin;
- while (Index < End) {
- // Ignore empty arguments (other things may still take them as arguments).
- if (Args->getArgString(Index)[0] == '\0') {
- ++Index;
- continue;
- }
-
- unsigned Prev = Index;
- Arg *A = ParseOneArg(*Args, Index);
- assert(Index > Prev && "Parser failed to consume argument.");
-
- // Check for missing argument error.
- if (!A) {
- assert(Index >= End && "Unexpected parser error.");
- assert(Index - Prev - 1 && "No missing arguments!");
- MissingArgIndex = Prev;
- MissingArgCount = Index - Prev - 1;
- break;
- }
-
- Args->append(A);
- }
-
- return Args;
-}
-
-static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
- const Option O = Opts.getOption(Id);
- std::string Name = O.getPrefixedName();
-
- // Add metavar, if used.
- switch (O.getKind()) {
- case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
- llvm_unreachable("Invalid option with help text.");
-
- case Option::MultiArgClass:
- llvm_unreachable("Cannot print metavar for this kind of option.");
-
- case Option::FlagClass:
- break;
-
- case Option::SeparateClass: case Option::JoinedOrSeparateClass:
- Name += ' ';
- // FALLTHROUGH
- case Option::JoinedClass: case Option::CommaJoinedClass:
- case Option::JoinedAndSeparateClass:
- if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
- Name += MetaVarName;
- else
- Name += "<value>";
- break;
- }
-
- return Name;
-}
-
-static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
- std::vector<std::pair<std::string,
- const char*> > &OptionHelp) {
- OS << Title << ":\n";
-
- // Find the maximum option length.
- unsigned OptionFieldWidth = 0;
- for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
- // Skip titles.
- if (!OptionHelp[i].second)
- continue;
-
- // Limit the amount of padding we are willing to give up for alignment.
- unsigned Length = OptionHelp[i].first.size();
- if (Length <= 23)
- OptionFieldWidth = std::max(OptionFieldWidth, Length);
- }
-
- const unsigned InitialPad = 2;
- for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
- const std::string &Option = OptionHelp[i].first;
- int Pad = OptionFieldWidth - int(Option.size());
- OS.indent(InitialPad) << Option;
-
- // Break on long option names.
- if (Pad < 0) {
- OS << "\n";
- Pad = OptionFieldWidth + InitialPad;
- }
- OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
- }
-}
-
-static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
- unsigned GroupID = Opts.getOptionGroupID(Id);
-
- // If not in a group, return the default help group.
- if (!GroupID)
- return "OPTIONS";
-
- // Abuse the help text of the option groups to store the "help group"
- // name.
- //
- // FIXME: Split out option groups.
- if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
- return GroupHelp;
-
- // Otherwise keep looking.
- return getOptionHelpGroup(Opts, GroupID);
-}
-
-void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
- const char *Title, unsigned short FlagsToInclude,
- unsigned short FlagsToExclude) const {
- OS << "OVERVIEW: " << Title << "\n";
- OS << '\n';
- OS << "USAGE: " << Name << " [options] <inputs>\n";
- OS << '\n';
-
- // Render help text into a map of group-name to a list of (option, help)
- // pairs.
- typedef std::map<std::string,
- std::vector<std::pair<std::string, const char*> > > helpmap_ty;
- helpmap_ty GroupedOptionHelp;
-
- for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
- unsigned Id = i + 1;
-
- // FIXME: Split out option groups.
- if (getOptionKind(Id) == Option::GroupClass)
- continue;
-
- if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) ||
- getInfo(Id).Flags & FlagsToExclude)
- continue;
-
- if (const char *Text = getOptionHelpText(Id)) {
- const char *HelpGroup = getOptionHelpGroup(*this, Id);
- const std::string &OptName = getOptionHelpName(*this, Id);
- GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
- }
- }
-
- for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
- ie = GroupedOptionHelp.end(); it != ie; ++it) {
- if (it != GroupedOptionHelp .begin())
- OS << "\n";
- PrintHelpOptionList(OS, it->first, it->second);
- }
-
- OS.flush();
-}
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
deleted file mode 100644
index dbc61ea3a4f7..000000000000
--- a/lib/Driver/Option.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-//===--- Option.cpp - Abstract Driver Options -----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/Option.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-using namespace clang::driver;
-
-Option::Option(const OptTable::Info *info, const OptTable *owner)
- : Info(info), Owner(owner) {
-
- // Multi-level aliases are not supported, and alias options cannot
- // have groups. This just simplifies option tracking, it is not an
- // inherent limitation.
- assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
- !getGroup().isValid())) &&
- "Multi-level aliases and aliases with groups are unsupported.");
-}
-
-Option::~Option() {
-}
-
-void Option::dump() const {
- llvm::errs() << "<";
- switch (getKind()) {
-#define P(N) case N: llvm::errs() << #N; break
- P(GroupClass);
- P(InputClass);
- P(UnknownClass);
- P(FlagClass);
- P(JoinedClass);
- P(SeparateClass);
- P(CommaJoinedClass);
- P(MultiArgClass);
- P(JoinedOrSeparateClass);
- P(JoinedAndSeparateClass);
-#undef P
- }
-
- llvm::errs() << " Prefixes:[";
- for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
- llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
- }
- llvm::errs() << ']';
-
- llvm::errs() << " Name:\"" << getName() << '"';
-
- const Option Group = getGroup();
- if (Group.isValid()) {
- llvm::errs() << " Group:";
- Group.dump();
- }
-
- const Option Alias = getAlias();
- if (Alias.isValid()) {
- llvm::errs() << " Alias:";
- Alias.dump();
- }
-
- if (getKind() == MultiArgClass)
- llvm::errs() << " NumArgs:" << getNumArgs();
-
- llvm::errs() << ">\n";
-}
-
-bool Option::matches(OptSpecifier Opt) const {
- // Aliases are never considered in matching, look through them.
- const Option Alias = getAlias();
- if (Alias.isValid())
- return Alias.matches(Opt);
-
- // Check exact match.
- if (getID() == Opt.getID())
- return true;
-
- const Option Group = getGroup();
- if (Group.isValid())
- return Group.matches(Opt);
- return false;
-}
-
-Arg *Option::accept(const ArgList &Args,
- unsigned &Index,
- unsigned ArgSize) const {
- const Option &UnaliasedOption = getUnaliasedOption();
- StringRef Spelling;
- // If the option was an alias, get the spelling from the unaliased one.
- if (getID() == UnaliasedOption.getID()) {
- Spelling = StringRef(Args.getArgString(Index), ArgSize);
- } else {
- Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
- Twine(UnaliasedOption.getName()));
- }
-
- switch (getKind()) {
- case FlagClass:
- if (ArgSize != strlen(Args.getArgString(Index)))
- return 0;
-
- return new Arg(UnaliasedOption, Spelling, Index++);
- case JoinedClass: {
- const char *Value = Args.getArgString(Index) + ArgSize;
- return new Arg(UnaliasedOption, Spelling, Index++, Value);
- }
- case CommaJoinedClass: {
- // Always matches.
- const char *Str = Args.getArgString(Index) + ArgSize;
- Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
-
- // Parse out the comma separated values.
- const char *Prev = Str;
- for (;; ++Str) {
- char c = *Str;
-
- if (!c || c == ',') {
- if (Prev != Str) {
- char *Value = new char[Str - Prev + 1];
- memcpy(Value, Prev, Str - Prev);
- Value[Str - Prev] = '\0';
- A->getValues().push_back(Value);
- }
-
- if (!c)
- break;
-
- Prev = Str + 1;
- }
- }
- A->setOwnsValues(true);
-
- return A;
- }
- case SeparateClass:
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (ArgSize != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(UnaliasedOption, Spelling,
- Index - 2, Args.getArgString(Index - 1));
- case MultiArgClass: {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (ArgSize != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 1 + getNumArgs();
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
- Args.getArgString(Index - getNumArgs()));
- for (unsigned i = 1; i != getNumArgs(); ++i)
- A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
- return A;
- }
- case JoinedOrSeparateClass: {
- // If this is not an exact match, it is a joined arg.
- // FIXME: Avoid strlen.
- if (ArgSize != strlen(Args.getArgString(Index))) {
- const char *Value = Args.getArgString(Index) + ArgSize;
- return new Arg(*this, Spelling, Index++, Value);
- }
-
- // Otherwise it must be separate.
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(UnaliasedOption, Spelling,
- Index - 2, Args.getArgString(Index - 1));
- }
- case JoinedAndSeparateClass:
- // Always matches.
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(UnaliasedOption, Spelling, Index - 2,
- Args.getArgString(Index - 2) + ArgSize,
- Args.getArgString(Index - 1));
- default:
- llvm_unreachable("Invalid option kind!");
- }
-}
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
new file mode 100644
index 000000000000..43209f01e247
--- /dev/null
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -0,0 +1,389 @@
+//===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Driver/SanitizerArgs.h"
+
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Transforms/Utils/SpecialCaseList.h"
+
+using namespace clang::driver;
+using namespace llvm::opt;
+
+void SanitizerArgs::clear() {
+ Kind = 0;
+ BlacklistFile = "";
+ MsanTrackOrigins = false;
+ AsanZeroBaseShadow = false;
+ UbsanTrapOnError = false;
+}
+
+SanitizerArgs::SanitizerArgs() {
+ clear();
+}
+
+SanitizerArgs::SanitizerArgs(const ToolChain &TC,
+ const llvm::opt::ArgList &Args) {
+ clear();
+ unsigned AllAdd = 0; // All kinds of sanitizers that were turned on
+ // at least once (possibly, disabled further).
+ unsigned AllRemove = 0; // During the loop below, the accumulated set of
+ // sanitizers disabled by the current sanitizer
+ // argument or any argument after it.
+ unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
+ // Used to deduplicate diagnostics.
+ const Driver &D = TC.getDriver();
+ for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
+ I != E; ++I) {
+ unsigned Add, Remove;
+ if (!parse(D, Args, *I, Add, Remove, true))
+ continue;
+ (*I)->claim();
+
+ AllAdd |= expandGroups(Add);
+ AllRemove |= expandGroups(Remove);
+
+ // Avoid diagnosing any sanitizer which is disabled later.
+ Add &= ~AllRemove;
+ // At this point we have not expanded groups, so any unsupported sanitizers
+ // in Add are those which have been explicitly enabled. Diagnose them.
+ Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true,
+ DiagnosedKinds);
+ Add = expandGroups(Add);
+ // Group expansion may have enabled a sanitizer which is disabled later.
+ Add &= ~AllRemove;
+ // Silently discard any unsupported sanitizers implicitly enabled through
+ // group expansion.
+ Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false,
+ DiagnosedKinds);
+
+ Kind |= Add;
+ }
+
+ UbsanTrapOnError =
+ Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
+ Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, false);
+
+ if (Args.hasArg(options::OPT_fcatch_undefined_behavior) &&
+ !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, true)) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fcatch-undefined-behavior"
+ << "-fno-sanitize-undefined-trap-on-error";
+ }
+
+ // Warn about undefined sanitizer options that require runtime support.
+ if (UbsanTrapOnError && notAllowedWithTrap()) {
+ if (Args.hasArg(options::OPT_fcatch_undefined_behavior))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ << "-fcatch-undefined-behavior";
+ else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error,
+ false))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ << "-fsanitize-undefined-trap-on-error";
+ }
+
+ // Only one runtime library can be used at once.
+ bool NeedsAsan = needsAsanRt();
+ bool NeedsTsan = needsTsanRt();
+ bool NeedsMsan = needsMsanRt();
+ bool NeedsLsan = needsLeakDetection();
+ if (NeedsAsan && NeedsTsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsTsanRt);
+ if (NeedsAsan && NeedsMsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+ if (NeedsTsan && NeedsMsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsTsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+ if (NeedsLsan && NeedsTsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsLeakDetection)
+ << lastArgumentForKind(D, Args, NeedsTsanRt);
+ if (NeedsLsan && NeedsMsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsLeakDetection)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+ // FIXME: Currenly -fsanitize=leak is silently ignored in the presence of
+ // -fsanitize=address. Perhaps it should print an error, or perhaps
+ // -f(-no)sanitize=leak should change whether leak detection is enabled by
+ // default in ASan?
+
+ // If -fsanitize contains extra features of ASan, it should also
+ // explicitly contain -fsanitize=address (probably, turned off later in the
+ // command line).
+ if ((Kind & AddressFull) != 0 && (AllAdd & Address) == 0)
+ D.Diag(diag::warn_drv_unused_sanitizer)
+ << lastArgumentForKind(D, Args, AddressFull)
+ << "-fsanitize=address";
+
+ // Parse -f(no-)sanitize-blacklist options.
+ if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
+ options::OPT_fno_sanitize_blacklist)) {
+ if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
+ std::string BLPath = BLArg->getValue();
+ if (llvm::sys::fs::exists(BLPath)) {
+ // Validate the blacklist format.
+ std::string BLError;
+ llvm::OwningPtr<llvm::SpecialCaseList> SCL(
+ llvm::SpecialCaseList::create(BLPath, BLError));
+ if (!SCL.get())
+ D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError;
+ else
+ BlacklistFile = BLPath;
+ } else {
+ D.Diag(diag::err_drv_no_such_file) << BLPath;
+ }
+ }
+ } else {
+ // If no -fsanitize-blacklist option is specified, try to look up for
+ // blacklist in the resource directory.
+ std::string BLPath;
+ if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
+ llvm::sys::fs::exists(BLPath))
+ BlacklistFile = BLPath;
+ }
+
+ // Parse -f(no-)sanitize-memory-track-origins options.
+ if (NeedsMsan)
+ MsanTrackOrigins =
+ Args.hasFlag(options::OPT_fsanitize_memory_track_origins,
+ options::OPT_fno_sanitize_memory_track_origins,
+ /* Default */false);
+
+ // Parse -f(no-)sanitize-address-zero-base-shadow options.
+ if (NeedsAsan) {
+ bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android);
+ bool ZeroBaseShadowDefault = IsAndroid;
+ AsanZeroBaseShadow =
+ Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow,
+ ZeroBaseShadowDefault);
+ // Zero-base shadow is a requirement on Android.
+ if (IsAndroid && !AsanZeroBaseShadow) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fno-sanitize-address-zero-base-shadow"
+ << lastArgumentForKind(D, Args, Address);
+ }
+ }
+}
+
+void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ if (!Kind)
+ return;
+ SmallString<256> SanitizeOpt("-fsanitize=");
+#define SANITIZER(NAME, ID) \
+ if (Kind & ID) \
+ SanitizeOpt += NAME ",";
+#include "clang/Basic/Sanitizers.def"
+ SanitizeOpt.pop_back();
+ CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
+ if (!BlacklistFile.empty()) {
+ SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
+ BlacklistOpt += BlacklistFile;
+ CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
+ }
+
+ if (MsanTrackOrigins)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
+
+ if (AsanZeroBaseShadow)
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-address-zero-base-shadow"));
+
+ // Workaround for PR16386.
+ if (needsMsanRt())
+ CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
+}
+
+unsigned SanitizerArgs::parse(const char *Value) {
+ unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
+#define SANITIZER(NAME, ID) .Case(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
+#include "clang/Basic/Sanitizers.def"
+ .Default(SanitizeKind());
+ // Assume -fsanitize=address implies -fsanitize=init-order,use-after-return.
+ // FIXME: This should be either specified in Sanitizers.def, or go away when
+ // we get rid of "-fsanitize=init-order,use-after-return" flags at all.
+ if (ParsedKind & Address)
+ ParsedKind |= InitOrder | UseAfterReturn;
+ return ParsedKind;
+}
+
+unsigned SanitizerArgs::expandGroups(unsigned Kinds) {
+#define SANITIZER(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
+#include "clang/Basic/Sanitizers.def"
+ return Kinds;
+}
+
+void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
+ unsigned Mask,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds) {
+ unsigned MaskedKinds = Kinds & Mask;
+ if (!MaskedKinds)
+ return;
+ Kinds &= ~Mask;
+ // Do we have new kinds to diagnose?
+ if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) {
+ // Only diagnose the new kinds.
+ std::string Desc =
+ describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds);
+ TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << Desc << TC.getTriple().str();
+ DiagnosedKinds |= MaskedKinds;
+ }
+}
+
+unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC,
+ unsigned Kinds,
+ const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ bool DiagnoseErrors,
+ unsigned &DiagnosedKinds) {
+ bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
+ bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
+ bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
+ if (!(IsLinux && IsX86_64)) {
+ filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
+ DiagnoseErrors, DiagnosedKinds);
+ }
+ if (!(IsLinux && (IsX86 || IsX86_64))) {
+ filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
+ DiagnosedKinds);
+ }
+ return Kinds;
+}
+
+unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
+ unsigned Kind = 0;
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+ if (unsigned K = parse(A->getValue(I)))
+ Kind |= K;
+ else if (DiagnoseErrors)
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue(I);
+ }
+ return Kind;
+}
+
+bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A, unsigned &Add,
+ unsigned &Remove, bool DiagnoseErrors) {
+ Add = 0;
+ Remove = 0;
+ const char *DeprecatedReplacement = 0;
+ if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
+ Add = Address;
+ DeprecatedReplacement = "-fsanitize=address";
+ } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
+ Remove = Address;
+ DeprecatedReplacement = "-fno-sanitize=address";
+ } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
+ Add = Thread;
+ DeprecatedReplacement = "-fsanitize=thread";
+ } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
+ Remove = Thread;
+ DeprecatedReplacement = "-fno-sanitize=thread";
+ } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
+ Add = UndefinedTrap;
+ DeprecatedReplacement =
+ "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error";
+ } else if (A->getOption().matches(options::OPT_fbounds_checking) ||
+ A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
+ Add = LocalBounds;
+ DeprecatedReplacement = "-fsanitize=local-bounds";
+ } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
+ Add = parse(D, A, DiagnoseErrors);
+ } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+ Remove = parse(D, A, DiagnoseErrors);
+ } else {
+ // Flag is not relevant to sanitizers.
+ return false;
+ }
+ // If this is a deprecated synonym, produce a warning directing users
+ // towards the new spelling.
+ if (DeprecatedReplacement && DiagnoseErrors)
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << A->getAsString(Args) << DeprecatedReplacement;
+ return true;
+}
+
+std::string SanitizerArgs::lastArgumentForKind(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ unsigned Kind) {
+ for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
+ E = Args.rend();
+ I != E; ++I) {
+ unsigned Add, Remove;
+ if (parse(D, Args, *I, Add, Remove, false) &&
+ (expandGroups(Add) & Kind))
+ return describeSanitizeArg(Args, *I, Kind);
+ Kind &= ~Remove;
+ }
+ llvm_unreachable("arg list didn't provide expected value");
+}
+
+std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
+ const llvm::opt::Arg *A,
+ unsigned Mask) {
+ if (!A->getOption().matches(options::OPT_fsanitize_EQ))
+ return A->getAsString(Args);
+
+ std::string Sanitizers;
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+ if (expandGroups(parse(A->getValue(I))) & Mask) {
+ if (!Sanitizers.empty())
+ Sanitizers += ",";
+ Sanitizers += A->getValue(I);
+ }
+ }
+
+ assert(!Sanitizers.empty() && "arg didn't provide expected value");
+ return "-fsanitize=" + Sanitizers;
+}
+
+bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
+ std::string &BLPath) {
+ const char *BlacklistFile = 0;
+ if (Kind & NeedsAsanRt)
+ BlacklistFile = "asan_blacklist.txt";
+ else if (Kind & NeedsMsanRt)
+ BlacklistFile = "msan_blacklist.txt";
+ else if (Kind & NeedsTsanRt)
+ BlacklistFile = "tsan_blacklist.txt";
+ else if (Kind & NeedsDfsanRt)
+ BlacklistFile = "dfsan_abilist.txt";
+
+ if (BlacklistFile) {
+ SmallString<64> Path(D.ResourceDir);
+ llvm::sys::path::append(Path, BlacklistFile);
+ BLPath = Path.str();
+ return true;
+ }
+ return false;
+}
diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h
deleted file mode 100644
index 326d80db72e1..000000000000
--- a/lib/Driver/SanitizerArgs.h
+++ /dev/null
@@ -1,220 +0,0 @@
-//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
-#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
-
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Options.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Path.h"
-
-namespace clang {
-namespace driver {
-
-class SanitizerArgs {
- /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
- /// bit positions within \c Kind.
- enum SanitizeOrdinal {
-#define SANITIZER(NAME, ID) SO_##ID,
-#include "clang/Basic/Sanitizers.def"
- SO_Count
- };
-
- /// Bugs to catch at runtime.
- enum SanitizeKind {
-#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
-#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
-#include "clang/Basic/Sanitizers.def"
- NeedsAsanRt = Address,
- NeedsTsanRt = Thread,
- NeedsMsanRt = Memory,
- NeedsUbsanRt = Undefined | Integer,
- NotAllowedWithTrap = Vptr,
- HasZeroBaseShadow = Thread | Memory
- };
- unsigned Kind;
- std::string BlacklistFile;
- bool MsanTrackOrigins;
- bool AsanZeroBaseShadow;
- bool UbsanTrapOnError;
-
- public:
- SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
- AsanZeroBaseShadow(false), UbsanTrapOnError(false) {}
- /// Parses the sanitizer arguments from an argument list.
- SanitizerArgs(const ToolChain &TC, const ArgList &Args);
-
- bool needsAsanRt() const { return Kind & NeedsAsanRt; }
- bool needsTsanRt() const { return Kind & NeedsTsanRt; }
- bool needsMsanRt() const { return Kind & NeedsMsanRt; }
- bool needsUbsanRt() const {
- if (UbsanTrapOnError)
- return false;
- return Kind & NeedsUbsanRt;
- }
-
- bool sanitizesVptr() const { return Kind & Vptr; }
- bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
- bool hasZeroBaseShadow() const {
- return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow;
- }
-
- void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
- if (!Kind)
- return;
- SmallString<256> SanitizeOpt("-fsanitize=");
-#define SANITIZER(NAME, ID) \
- if (Kind & ID) \
- SanitizeOpt += NAME ",";
-#include "clang/Basic/Sanitizers.def"
- SanitizeOpt.pop_back();
- CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
- if (!BlacklistFile.empty()) {
- SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
- BlacklistOpt += BlacklistFile;
- CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
- }
-
- if (MsanTrackOrigins)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
-
- if (AsanZeroBaseShadow)
- CmdArgs.push_back(Args.MakeArgString(
- "-fsanitize-address-zero-base-shadow"));
- }
-
- private:
- /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
- /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
- /// if \p Value is not known.
- static unsigned parse(const char *Value) {
- unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
-#define SANITIZER(NAME, ID) .Case(NAME, ID)
-#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
-#include "clang/Basic/Sanitizers.def"
- .Default(SanitizeKind());
- // Assume -fsanitize=address implies -fsanitize=init-order.
- // FIXME: This should be either specified in Sanitizers.def, or go away when
- // we get rid of "-fsanitize=init-order" flag at all.
- if (ParsedKind & Address)
- ParsedKind |= InitOrder;
- return ParsedKind;
- }
-
- /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
- /// invalid components.
- static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) {
- unsigned Kind = 0;
- for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
- if (unsigned K = parse(A->getValue(I)))
- Kind |= K;
- else if (DiagnoseErrors)
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue(I);
- }
- return Kind;
- }
-
- /// Parse a single flag of the form -f[no]sanitize=, or
- /// -f*-sanitizer. Sets the masks defining required change of Kind value.
- /// Returns true if the flag was parsed successfully.
- static bool parse(const Driver &D, const ArgList &Args, const Arg *A,
- unsigned &Add, unsigned &Remove, bool DiagnoseErrors) {
- Add = 0;
- Remove = 0;
- const char *DeprecatedReplacement = 0;
- if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
- Add = Address;
- DeprecatedReplacement = "-fsanitize=address";
- } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
- Remove = Address;
- DeprecatedReplacement = "-fno-sanitize=address";
- } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
- Add = Thread;
- DeprecatedReplacement = "-fsanitize=thread";
- } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
- Remove = Thread;
- DeprecatedReplacement = "-fno-sanitize=thread";
- } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
- Add = UndefinedTrap;
- DeprecatedReplacement =
- "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error";
- } else if (A->getOption().matches(options::OPT_fbounds_checking) ||
- A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
- Add = Bounds;
- DeprecatedReplacement = "-fsanitize=bounds";
- } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
- Add = parse(D, A, DiagnoseErrors);
- } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
- Remove = parse(D, A, DiagnoseErrors);
- } else {
- // Flag is not relevant to sanitizers.
- return false;
- }
- // If this is a deprecated synonym, produce a warning directing users
- // towards the new spelling.
- if (DeprecatedReplacement && DiagnoseErrors)
- D.Diag(diag::warn_drv_deprecated_arg)
- << A->getAsString(Args) << DeprecatedReplacement;
- return true;
- }
-
- /// Produce an argument string from ArgList \p Args, which shows how it
- /// provides a sanitizer kind in \p Mask. For example, the argument list
- /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
- /// would produce "-fsanitize=vptr".
- static std::string lastArgumentForKind(const Driver &D, const ArgList &Args,
- unsigned Kind) {
- for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
- I != E; ++I) {
- unsigned Add, Remove;
- if (parse(D, Args, *I, Add, Remove, false) &&
- (Add & Kind))
- return describeSanitizeArg(Args, *I, Kind);
- Kind &= ~Remove;
- }
- llvm_unreachable("arg list didn't provide expected value");
- }
-
- /// Produce an argument string from argument \p A, which shows how it provides
- /// a value in \p Mask. For instance, the argument
- /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
- /// "-fsanitize=alignment".
- static std::string describeSanitizeArg(const ArgList &Args, const Arg *A,
- unsigned Mask) {
- if (!A->getOption().matches(options::OPT_fsanitize_EQ))
- return A->getAsString(Args);
-
- for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
- if (parse(A->getValue(I)) & Mask)
- return std::string("-fsanitize=") + A->getValue(I);
-
- llvm_unreachable("arg didn't provide expected value");
- }
-
- static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
- std::string &BLPath) {
- // For now, specify the default blacklist location for ASan only.
- if (Kind & NeedsAsanRt) {
- SmallString<64> Path(D.ResourceDir);
- llvm::sys::path::append(Path, "asan_blacklist.txt");
- BLPath = Path.str();
- return true;
- }
- return false;
- }
-};
-
-} // namespace driver
-} // namespace clang
-
-#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 71f53933e2af..efd3945b3dd4 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -8,20 +8,22 @@
//===----------------------------------------------------------------------===//
#include "Tools.h"
-#include "clang/Driver/ToolChain.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Driver/Action.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
using namespace clang::driver;
using namespace clang;
+using namespace llvm::opt;
ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
const ArgList &A)
@@ -41,6 +43,12 @@ bool ToolChain::useIntegratedAs() const {
IsIntegratedAssemblerDefault());
}
+const SanitizerArgs& ToolChain::getSanitizerArgs() const {
+ if (!SanitizerArguments.get())
+ SanitizerArguments.reset(new SanitizerArgs(*this, Args));
+ return *SanitizerArguments.get();
+}
+
std::string ToolChain::getDefaultUniversalArchName() const {
// In universal driver terms, the arch name accepted by -arch isn't exactly
// the same as the ones that appear in the triple. Roughly speaking, this is
@@ -51,6 +59,8 @@ std::string ToolChain::getDefaultUniversalArchName() const {
return "ppc";
case llvm::Triple::ppc64:
return "ppc64";
+ case llvm::Triple::ppc64le:
+ return "ppc64le";
default:
return Triple.getArchName();
}
@@ -173,11 +183,17 @@ static const char *getARMTargetCPU(const ArgList &Args,
MArch = Triple.getArchName();
}
- return llvm::StringSwitch<const char *>(MArch)
+ if (Triple.getOS() == llvm::Triple::NetBSD) {
+ if (MArch == "armv6")
+ return "arm1176jzf-s";
+ }
+
+ const char *result = llvm::StringSwitch<const char *>(MArch)
.Cases("armv2", "armv2a","arm2")
.Case("armv3", "arm6")
.Case("armv3m", "arm7m")
- .Cases("armv4", "armv4t", "arm7tdmi")
+ .Case("armv4", "strongarm")
+ .Case("armv4t", "arm7tdmi")
.Cases("armv5", "armv5t", "arm10tdmi")
.Cases("armv5e", "armv5te", "arm1026ejs")
.Case("armv5tej", "arm926ej-s")
@@ -193,11 +209,21 @@ static const char *getARMTargetCPU(const ArgList &Args,
.Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
.Cases("armv7em", "armv7e-m", "cortex-m4")
+ .Cases("armv8", "armv8a", "armv8-a", "cortex-a53")
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- // If all else failed, return the most base CPU LLVM supports.
- .Default("arm7tdmi");
+ // If all else failed, return the most base CPU with thumb interworking
+ // supported by LLVM.
+ .Default(0);
+
+ if (result)
+ return result;
+
+ return
+ Triple.getEnvironment() == llvm::Triple::GNUEABIHF
+ ? "arm1176jzf-s"
+ : "arm7tdmi";
}
/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
@@ -207,6 +233,7 @@ static const char *getARMTargetCPU(const ArgList &Args,
// FIXME: tblgen this, or kill it!
static const char *getLLVMArchSuffixForARM(StringRef CPU) {
return llvm::StringSwitch<const char *>(CPU)
+ .Case("strongarm", "v4")
.Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
.Cases("arm720t", "arm9", "arm9tdmi", "v4t")
.Cases("arm920", "arm920t", "arm922t", "v4t")
@@ -219,22 +246,37 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
- .Cases("cortex-a9", "cortex-a15", "v7")
- .Case("cortex-r5", "v7r")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7")
+ .Cases("cortex-r4", "cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
+ .Cases("cortex-a53", "cortex-a57", "v8")
.Default("");
}
-std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
+std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
types::ID InputType) const {
switch (getTriple().getArch()) {
default:
return getTripleString();
+ case llvm::Triple::x86_64: {
+ llvm::Triple Triple = getTriple();
+ if (!Triple.isOSDarwin())
+ return getTripleString();
+
+ if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ // x86_64h goes in the triple. Other -march options just use the
+ // vanilla triple we already have.
+ StringRef MArch = A->getValue();
+ if (MArch == "x86_64h")
+ Triple.setArchName(MArch);
+ }
+ return Triple.getTriple();
+ }
case llvm::Triple::arm:
case llvm::Triple::thumb: {
// FIXME: Factor into subclasses.
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index fffba0e4e50f..e5528f0a646b 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -8,27 +8,28 @@
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
-#include "SanitizerArgs.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Support/Program.h"
// FIXME: This needs to be listed last until we fix the broken include guards
// in these files and the LLVM config.h files.
@@ -39,6 +40,7 @@
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
+using namespace llvm::opt;
/// Darwin - Darwin tool chain for i386 and x86_64.
@@ -122,7 +124,9 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Case("xscale", "xscale")
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
.Case("cortex-m0", "armv6m")
- .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "armv7")
+ .Cases("cortex-r4", "cortex-r5", "armv7r")
.Case("cortex-a9-mp", "armv7f")
.Case("cortex-m3", "armv7m")
.Case("cortex-m4", "armv7em")
@@ -162,10 +166,18 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
if (!isTargetInitialized())
return Triple.getTriple();
- SmallString<16> Str;
- Str += isTargetIPhoneOS() ? "ios" : "macosx";
- Str += getTargetVersion().getAsString();
- Triple.setOSName(Str);
+ if (Triple.getArchName() == "thumbv6m" ||
+ Triple.getArchName() == "thumbv7m" ||
+ Triple.getArchName() == "thumbv7em") {
+ // OS is ios or macosx unless it's the v6m or v7m.
+ Triple.setOS(llvm::Triple::Darwin);
+ Triple.setEnvironment(llvm::Triple::EABI);
+ } else {
+ SmallString<16> Str;
+ Str += isTargetIPhoneOS() ? "ios" : "macosx";
+ Str += getTargetVersion().getAsString();
+ Triple.setOSName(Str);
+ }
return Triple.getTriple();
}
@@ -217,39 +229,33 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-force_load");
- llvm::sys::Path P(getDriver().ClangExecutable);
- P.eraseComponent(); // 'clang'
- P.eraseComponent(); // 'bin'
- P.appendComponent("lib");
- P.appendComponent("arc");
- P.appendComponent("libarclite_");
- std::string s = P.str();
+ SmallString<128> P(getDriver().ClangExecutable);
+ llvm::sys::path::remove_filename(P); // 'clang'
+ llvm::sys::path::remove_filename(P); // 'bin'
+ llvm::sys::path::append(P, "lib", "arc", "libarclite_");
// Mash in the platform.
if (isTargetIOSSimulator())
- s += "iphonesimulator";
+ P += "iphonesimulator";
else if (isTargetIPhoneOS())
- s += "iphoneos";
+ P += "iphoneos";
else
- s += "macosx";
- s += ".a";
+ P += "macosx";
+ P += ".a";
- CmdArgs.push_back(Args.MakeArgString(s));
+ CmdArgs.push_back(Args.MakeArgString(P));
}
void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
ArgStringList &CmdArgs,
const char *DarwinStaticLib,
bool AlwaysLink) const {
- llvm::sys::Path P(getDriver().ResourceDir);
- P.appendComponent("lib");
- P.appendComponent("darwin");
- P.appendComponent(DarwinStaticLib);
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "lib", "darwin", DarwinStaticLib);
// 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).
- bool Exists;
- if (AlwaysLink || (!llvm::sys::fs::exists(P.str(), Exists) && Exists))
+ if (AlwaysLink || llvm::sys::fs::exists(P.str()))
CmdArgs.push_back(Args.MakeArgString(P.str()));
}
@@ -294,10 +300,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
- SanitizerArgs Sanitize(*this, Args);
+ const SanitizerArgs &Sanitize = getSanitizerArgs();
// Add Ubsan runtime library, if required.
if (Sanitize.needsUbsanRt()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
if (isTargetIPhoneOS()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=undefined";
@@ -312,19 +319,27 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
if (Sanitize.needsAsanRt()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
if (isTargetIPhoneOS() && !isTargetIOSSimulator()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=address";
} else {
- if (Args.hasArg(options::OPT_dynamiclib) ||
- Args.hasArg(options::OPT_bundle)) {
- // Assume the binary will provide the ASan runtime.
- } else {
- AddLinkRuntimeLib(Args, CmdArgs,
- "libclang_rt.asan_osx_dynamic.dylib", true);
+ if (!Args.hasArg(options::OPT_dynamiclib) &&
+ !Args.hasArg(options::OPT_bundle)) {
// The ASAN runtime library requires C++.
AddCXXStdlibLibArgs(Args, CmdArgs);
}
+ if (isTargetMacOS()) {
+ AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.asan_osx_dynamic.dylib",
+ true);
+ } else {
+ if (isTargetIOSSimulator()) {
+ AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.asan_iossim_dynamic.dylib",
+ true);
+ }
+ }
}
}
@@ -376,8 +391,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// isysroot.
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
// Warn if the path does not exist.
- bool Exists;
- if (llvm::sys::fs::exists(A->getValue(), Exists) || !Exists)
+ if (!llvm::sys::fs::exists(A->getValue()))
getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
} else {
if (char *env = ::getenv("SDKROOT")) {
@@ -538,17 +552,14 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
// explicitly if we can't see an obvious -lstdc++ candidate.
// Check in the sysroot first.
- bool Exists;
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- llvm::sys::Path P(A->getValue());
- P.appendComponent("usr");
- P.appendComponent("lib");
- P.appendComponent("libstdc++.dylib");
-
- if (llvm::sys::fs::exists(P.str(), Exists) || !Exists) {
- P.eraseComponent();
- P.appendComponent("libstdc++.6.dylib");
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) {
+ SmallString<128> P(A->getValue());
+ llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib");
+
+ if (!llvm::sys::fs::exists(P.str())) {
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, "libstdc++.6.dylib");
+ if (llvm::sys::fs::exists(P.str())) {
CmdArgs.push_back(Args.MakeArgString(P.str()));
return;
}
@@ -558,8 +569,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
// Otherwise, look in the root.
// FIXME: This should be removed someday when we don't have to care about
// 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist.
- if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&&
- (!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){
+ if (!llvm::sys::fs::exists("/usr/lib/libstdc++.dylib") &&
+ llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib")) {
CmdArgs.push_back("/usr/lib/libstdc++.6.dylib");
return;
}
@@ -578,22 +589,20 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
// instead of the gcc-provided one (which is also incidentally
// only present in the gcc lib dir, which makes it hard to find).
- llvm::sys::Path P(getDriver().ResourceDir);
- P.appendComponent("lib");
- P.appendComponent("darwin");
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "lib", "darwin");
// Use the newer cc_kext for iOS ARM after 6.0.
if (!isTargetIPhoneOS() || isTargetIOSSimulator() ||
!isIPhoneOSVersionLT(6, 0)) {
- P.appendComponent("libclang_rt.cc_kext.a");
+ llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
} else {
- P.appendComponent("libclang_rt.cc_kext_ios5.a");
+ llvm::sys::path::append(P, "libclang_rt.cc_kext_ios5.a");
}
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build.
- bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ if (llvm::sys::fs::exists(P.str()))
CmdArgs.push_back(Args.MakeArgString(P.str()));
}
@@ -762,7 +771,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
else if (Name == "ppc970")
DAL->AddJoinedArg(0, MCpu, "970");
- else if (Name == "ppc64")
+ else if (Name == "ppc64" || Name == "ppc64le")
DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
else if (Name == "i386")
@@ -784,6 +793,10 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
else if (Name == "x86_64")
DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
+ else if (Name == "x86_64h") {
+ DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
+ DAL->AddJoinedArg(0, MArch, "x86_64h");
+ }
else if (Name == "arm")
DAL->AddJoinedArg(0, MArch, "armv4t");
@@ -839,6 +852,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
}
}
+ // Default to use libc++ on OS X 10.9+ and iOS 7+.
+ if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) ||
+ (isTargetIPhoneOS() && !isIPhoneOSVersionLT(7, 0))) &&
+ !Args.getLastArg(options::OPT_stdlib_EQ))
+ DAL->AddJoinedArg(0, Opts.getOption(options::OPT_stdlib_EQ), "libc++");
+
// Validate the C++ standard library choice.
CXXStdlibType Type = GetCXXStdlibType(*DAL);
if (Type == ToolChain::CST_Libcxx) {
@@ -917,17 +936,19 @@ Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args,
/// 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, "" };
+ 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, "" };
+ 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 (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
@@ -945,7 +966,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
GoodVersion.Patch < 0)
return BadVersion;
- GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str();
+ GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
}
}
@@ -953,31 +974,33 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
}
/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
-bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
- if (Major != RHS.Major)
- return Major < RHS.Major;
- if (Minor != RHS.Minor)
- return Minor < RHS.Minor;
- if (Patch != RHS.Patch) {
+bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
+ int RHSPatch,
+ StringRef RHSPatchSuffix) const {
+ if (Major != RHSMajor)
+ return Major < RHSMajor;
+ if (Minor != RHSMinor)
+ return Minor < RHSMinor;
+ if (Patch != RHSPatch) {
// Note that versions without a specified patch sort higher than those with
// a patch.
- if (RHS.Patch == -1)
+ if (RHSPatch == -1)
return true;
if (Patch == -1)
return false;
// Otherwise just sort on the patch itself.
- return Patch < RHS.Patch;
+ return Patch < RHSPatch;
}
- if (PatchSuffix != RHS.PatchSuffix) {
+ if (PatchSuffix != RHSPatchSuffix) {
// Sort empty suffixes higher.
- if (RHS.PatchSuffix.empty())
+ if (RHSPatchSuffix.empty())
return true;
if (PatchSuffix.empty())
return false;
// Provide a lexicographic sort to make this a total ordering.
- return PatchSuffix < RHS.PatchSuffix;
+ return PatchSuffix < RHSPatchSuffix;
}
// The versions are equal.
@@ -1001,23 +1024,20 @@ static StringRef getGCCToolchainDir(const ArgList &Args) {
/// necessary because the driver doesn't store the final version of the target
/// triple.
Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
- const Driver &D,
- const llvm::Triple &TargetTriple,
- const ArgList &Args)
- : IsValid(false) {
- llvm::Triple MultiarchTriple
- = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
+ const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args)
+ : IsValid(false), D(D) {
+ llvm::Triple BiarchVariantTriple =
+ TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
// The library directories which may contain GCC installations.
- SmallVector<StringRef, 4> CandidateLibDirs, CandidateMultiarchLibDirs;
+ SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
// The compatible GCC triples for this particular architecture.
SmallVector<StringRef, 10> CandidateTripleAliases;
- SmallVector<StringRef, 10> CandidateMultiarchTripleAliases;
- CollectLibDirsAndTriples(TargetTriple, MultiarchTriple, CandidateLibDirs,
- CandidateTripleAliases,
- CandidateMultiarchLibDirs,
- CandidateMultiarchTripleAliases);
+ SmallVector<StringRef, 10> CandidateBiarchTripleAliases;
+ CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
+ CandidateTripleAliases, CandidateBiarchLibDirs,
+ CandidateBiarchTripleAliases);
// Compute the set of prefixes for our search.
SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
@@ -1030,9 +1050,18 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
Prefixes.push_back(GCCToolchainDir);
} else {
- Prefixes.push_back(D.SysRoot);
- Prefixes.push_back(D.SysRoot + "/usr");
+ // If we have a SysRoot, try that first.
+ if (!D.SysRoot.empty()) {
+ Prefixes.push_back(D.SysRoot);
+ Prefixes.push_back(D.SysRoot + "/usr");
+ }
+
+ // Then look for gcc installed alongside clang.
Prefixes.push_back(D.InstalledDir + "/..");
+
+ // And finally in /usr.
+ if (D.SysRoot.empty())
+ Prefixes.push_back("/usr");
}
// Loop over the various components which exist and select the best GCC
@@ -1049,217 +1078,216 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
CandidateTripleAliases[k]);
}
- for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
- const std::string LibDir
- = Prefixes[i] + CandidateMultiarchLibDirs[j].str();
+ for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) {
+ const std::string LibDir = Prefixes[i] + CandidateBiarchLibDirs[j].str();
if (!llvm::sys::fs::exists(LibDir))
continue;
- for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
+ for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke;
++k)
ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
- CandidateMultiarchTripleAliases[k],
- /*NeedsMultiarchSuffix=*/true);
+ CandidateBiarchTripleAliases[k],
+ /*NeedsBiarchSuffix=*/ true);
}
}
}
+void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
+ for (std::set<std::string>::const_iterator
+ I = CandidateGCCInstallPaths.begin(),
+ E = CandidateGCCInstallPaths.end();
+ I != E; ++I)
+ OS << "Found candidate GCC installation: " << *I << "\n";
+
+ OS << "Selected GCC installation: " << GCCInstallPath << "\n";
+}
+
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
- const llvm::Triple &TargetTriple,
- const llvm::Triple &MultiarchTriple,
+ const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple,
SmallVectorImpl<StringRef> &LibDirs,
SmallVectorImpl<StringRef> &TripleAliases,
- SmallVectorImpl<StringRef> &MultiarchLibDirs,
- SmallVectorImpl<StringRef> &MultiarchTripleAliases) {
+ SmallVectorImpl<StringRef> &BiarchLibDirs,
+ SmallVectorImpl<StringRef> &BiarchTripleAliases) {
// Declare a bunch of static data sets that we'll select between below. These
// are specifically designed to always refer to string literals to avoid any
// lifetime or initialization issues.
static const char *const AArch64LibDirs[] = { "/lib" };
- static const char *const AArch64Triples[] = {
- "aarch64-none-linux-gnu",
- "aarch64-linux-gnu"
- };
+ static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu",
+ "aarch64-linux-gnu" };
static const char *const ARMLibDirs[] = { "/lib" };
- static const char *const ARMTriples[] = {
- "arm-linux-gnueabi",
- "arm-linux-androideabi"
- };
- static const char *const ARMHFTriples[] = {
- "arm-linux-gnueabihf",
- "armv7hl-redhat-linux-gnueabi"
- };
+ static const char *const ARMTriples[] = { "arm-linux-gnueabi",
+ "arm-linux-androideabi" };
+ static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf",
+ "armv7hl-redhat-linux-gnueabi" };
static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
static const char *const X86_64Triples[] = {
- "x86_64-linux-gnu",
- "x86_64-unknown-linux-gnu",
- "x86_64-pc-linux-gnu",
- "x86_64-redhat-linux6E",
- "x86_64-redhat-linux",
- "x86_64-suse-linux",
- "x86_64-manbo-linux-gnu",
- "x86_64-linux-gnu",
- "x86_64-slackware-linux"
+ "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu",
+ "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux",
+ "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux"
};
static const char *const X86LibDirs[] = { "/lib32", "/lib" };
static const char *const X86Triples[] = {
- "i686-linux-gnu",
- "i686-pc-linux-gnu",
- "i486-linux-gnu",
- "i386-linux-gnu",
- "i386-redhat-linux6E",
- "i686-redhat-linux",
- "i586-redhat-linux",
- "i386-redhat-linux",
- "i586-suse-linux",
- "i486-slackware-linux",
+ "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu",
+ "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux",
+ "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux",
"i686-montavista-linux"
};
static const char *const MIPSLibDirs[] = { "/lib" };
- static const char *const MIPSTriples[] = { "mips-linux-gnu" };
+ static const char *const MIPSTriples[] = { "mips-linux-gnu",
+ "mips-mti-linux-gnu" };
static const char *const MIPSELLibDirs[] = { "/lib" };
- static const char *const MIPSELTriples[] = {
- "mipsel-linux-gnu",
- "mipsel-linux-android",
- "mips-linux-gnu"
- };
+ static const char *const MIPSELTriples[] = { "mipsel-linux-gnu",
+ "mipsel-linux-android" };
static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" };
- static const char *const MIPS64Triples[] = { "mips64-linux-gnu" };
+ static const char *const MIPS64Triples[] = { "mips64-linux-gnu",
+ "mips-mti-linux-gnu" };
static const char *const MIPS64ELLibDirs[] = { "/lib64", "/lib" };
- static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu" };
+ static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu",
+ "mips-mti-linux-gnu" };
static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
static const char *const PPCTriples[] = {
- "powerpc-linux-gnu",
- "powerpc-unknown-linux-gnu",
- "powerpc-linux-gnuspe",
- "powerpc-suse-linux",
- "powerpc-montavista-linuxspe"
+ "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
+ "powerpc-suse-linux", "powerpc-montavista-linuxspe"
};
static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
- static const char *const PPC64Triples[] = {
- "powerpc64-linux-gnu",
- "powerpc64-unknown-linux-gnu",
- "powerpc64-suse-linux",
- "ppc64-redhat-linux"
- };
+ static const char *const PPC64Triples[] = { "powerpc64-linux-gnu",
+ "powerpc64-unknown-linux-gnu",
+ "powerpc64-suse-linux",
+ "ppc64-redhat-linux" };
+ static const char *const PPC64LELibDirs[] = { "/lib64", "/lib" };
+ static const char *const PPC64LETriples[] = { "powerpc64le-linux-gnu",
+ "powerpc64le-unknown-linux-gnu",
+ "powerpc64le-suse-linux",
+ "ppc64le-redhat-linux" };
static const char *const SystemZLibDirs[] = { "/lib64", "/lib" };
static const char *const SystemZTriples[] = {
- "s390x-linux-gnu",
- "s390x-unknown-linux-gnu",
- "s390x-ibm-linux-gnu",
- "s390x-suse-linux",
- "s390x-redhat-linux"
+ "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
+ "s390x-suse-linux", "s390x-redhat-linux"
};
switch (TargetTriple.getArch()) {
case llvm::Triple::aarch64:
- LibDirs.append(AArch64LibDirs, AArch64LibDirs
- + llvm::array_lengthof(AArch64LibDirs));
- TripleAliases.append(
- AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
- MultiarchLibDirs.append(
- AArch64LibDirs, AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
- MultiarchTripleAliases.append(
- AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ LibDirs.append(AArch64LibDirs,
+ AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
+ TripleAliases.append(AArch64Triples,
+ AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ BiarchLibDirs.append(AArch64LibDirs,
+ AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
+ BiarchTripleAliases.append(
+ AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
- TripleAliases.append(
- ARMHFTriples, ARMHFTriples + llvm::array_lengthof(ARMHFTriples));
+ TripleAliases.append(ARMHFTriples,
+ ARMHFTriples + llvm::array_lengthof(ARMHFTriples));
} else {
- TripleAliases.append(
- ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
+ TripleAliases.append(ARMTriples,
+ ARMTriples + llvm::array_lengthof(ARMTriples));
}
break;
case llvm::Triple::x86_64:
- LibDirs.append(
- X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
- TripleAliases.append(
- X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
- MultiarchLibDirs.append(
- X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
- MultiarchTripleAliases.append(
- X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+ LibDirs.append(X86_64LibDirs,
+ X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+ TripleAliases.append(X86_64Triples,
+ X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ BiarchLibDirs.append(X86LibDirs,
+ X86LibDirs + llvm::array_lengthof(X86LibDirs));
+ BiarchTripleAliases.append(X86Triples,
+ X86Triples + llvm::array_lengthof(X86Triples));
break;
case llvm::Triple::x86:
LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
- TripleAliases.append(
- X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
- MultiarchLibDirs.append(
- X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
- MultiarchTripleAliases.append(
- X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ TripleAliases.append(X86Triples,
+ X86Triples + llvm::array_lengthof(X86Triples));
+ BiarchLibDirs.append(X86_64LibDirs,
+ X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+ BiarchTripleAliases.append(
+ X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
break;
case llvm::Triple::mips:
- LibDirs.append(
- MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
- TripleAliases.append(
- MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
- MultiarchLibDirs.append(
- MIPS64LibDirs, MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
- MultiarchTripleAliases.append(
- MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
+ LibDirs.append(MIPSLibDirs,
+ MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
+ TripleAliases.append(MIPSTriples,
+ MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ BiarchLibDirs.append(MIPS64LibDirs,
+ MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
+ BiarchTripleAliases.append(
+ MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
break;
case llvm::Triple::mipsel:
- LibDirs.append(
- MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
- TripleAliases.append(
- MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
- MultiarchLibDirs.append(
- MIPS64ELLibDirs, MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
- MultiarchTripleAliases.append(
- MIPS64ELTriples, MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
+ LibDirs.append(MIPSELLibDirs,
+ MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
+ TripleAliases.append(MIPSELTriples,
+ MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
+ TripleAliases.append(MIPSTriples,
+ MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ BiarchLibDirs.append(
+ MIPS64ELLibDirs,
+ MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
+ BiarchTripleAliases.append(
+ MIPS64ELTriples,
+ MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
break;
case llvm::Triple::mips64:
- LibDirs.append(
- MIPS64LibDirs, MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
- TripleAliases.append(
- MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
- MultiarchLibDirs.append(
- MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
- MultiarchTripleAliases.append(
- MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ LibDirs.append(MIPS64LibDirs,
+ MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
+ TripleAliases.append(MIPS64Triples,
+ MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
+ BiarchLibDirs.append(MIPSLibDirs,
+ MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
+ BiarchTripleAliases.append(MIPSTriples,
+ MIPSTriples + llvm::array_lengthof(MIPSTriples));
break;
case llvm::Triple::mips64el:
- LibDirs.append(
- MIPS64ELLibDirs, MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
+ LibDirs.append(MIPS64ELLibDirs,
+ MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
TripleAliases.append(
- MIPS64ELTriples, MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
- MultiarchLibDirs.append(
- MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
- MultiarchTripleAliases.append(
- MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
+ MIPS64ELTriples,
+ MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
+ BiarchLibDirs.append(MIPSELLibDirs,
+ MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
+ BiarchTripleAliases.append(
+ MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
+ BiarchTripleAliases.append(
+ MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
break;
case llvm::Triple::ppc:
LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
- TripleAliases.append(
- PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
- MultiarchLibDirs.append(
- PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
- MultiarchTripleAliases.append(
- PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ TripleAliases.append(PPCTriples,
+ PPCTriples + llvm::array_lengthof(PPCTriples));
+ BiarchLibDirs.append(PPC64LibDirs,
+ PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+ BiarchTripleAliases.append(
+ PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
break;
case llvm::Triple::ppc64:
- LibDirs.append(
- PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
- TripleAliases.append(
- PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
- MultiarchLibDirs.append(
- PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
- MultiarchTripleAliases.append(
- PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+ LibDirs.append(PPC64LibDirs,
+ PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+ TripleAliases.append(PPC64Triples,
+ PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ BiarchLibDirs.append(PPCLibDirs,
+ PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
+ BiarchTripleAliases.append(PPCTriples,
+ PPCTriples + llvm::array_lengthof(PPCTriples));
+ break;
+ case llvm::Triple::ppc64le:
+ LibDirs.append(PPC64LELibDirs,
+ PPC64LELibDirs + llvm::array_lengthof(PPC64LELibDirs));
+ TripleAliases.append(PPC64LETriples,
+ PPC64LETriples + llvm::array_lengthof(PPC64LETriples));
break;
case llvm::Triple::systemz:
- LibDirs.append(
- SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
- TripleAliases.append(
- SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples));
+ LibDirs.append(SystemZLibDirs,
+ SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
+ TripleAliases.append(SystemZTriples,
+ SystemZTriples + llvm::array_lengthof(SystemZTriples));
break;
default:
@@ -1273,8 +1301,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
TripleAliases.push_back(TargetTriple.str());
// Also include the multiarch variant if it's different.
- if (TargetTriple.str() != MultiarchTriple.str())
- MultiarchTripleAliases.push_back(MultiarchTriple.str());
+ if (TargetTriple.str() != BiarchTriple.str())
+ BiarchTripleAliases.push_back(BiarchTriple.str());
}
static bool isSoftFloatABI(const ArgList &Args) {
@@ -1301,87 +1329,168 @@ static bool isMips16(const ArgList &Args) {
return A && A->getOption().matches(options::OPT_mips16);
}
+static bool isMips32r2(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_march_EQ,
+ options::OPT_mcpu_EQ);
+
+ return A && A->getValue() == StringRef("mips32r2");
+}
+
+static bool isMips64r2(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_march_EQ,
+ options::OPT_mcpu_EQ);
+
+ return A && A->getValue() == StringRef("mips64r2");
+}
+
static bool isMicroMips(const ArgList &Args) {
Arg *A = Args.getLastArg(options::OPT_mmicromips,
options::OPT_mno_micromips);
return A && A->getOption().matches(options::OPT_mmicromips);
}
+static bool isMipsFP64(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mfp64, options::OPT_mfp32);
+ return A && A->getOption().matches(options::OPT_mfp64);
+}
+
+static bool isMipsNan2008(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mnan_EQ);
+ return A && A->getValue() == StringRef("2008");
+}
+
// FIXME: There is the same routine in the Tools.cpp.
static bool hasMipsN32ABIArg(const ArgList &Args) {
Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
return A && (A->getValue() == StringRef("n32"));
}
-static void appendMipsTargetSuffix(std::string &Path,
+static bool hasCrtBeginObj(Twine Path) {
+ return llvm::sys::fs::exists(Path + "/crtbegin.o");
+}
+
+static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path,
llvm::Triple::ArchType TargetArch,
const ArgList &Args) {
- if (isMips16(Args))
- Path += "/mips16";
- else if (isMicroMips(Args))
- Path += "/micromips";
-
- if (isSoftFloatABI(Args))
- Path += "/soft-float";
+ // FIXME: This routine was only intended to model bi-arch toolchains which
+ // use -m32 and -m64 to swap between variants of a target. It shouldn't be
+ // doing ABI-based builtin location for MIPS.
+ if (hasMipsN32ABIArg(Args))
+ Suffix = "/n32";
+ else if (TargetArch == llvm::Triple::x86_64 ||
+ TargetArch == llvm::Triple::ppc64 ||
+ TargetArch == llvm::Triple::systemz ||
+ TargetArch == llvm::Triple::mips64 ||
+ TargetArch == llvm::Triple::mips64el)
+ Suffix = "/64";
+ else
+ Suffix = "/32";
- if (TargetArch == llvm::Triple::mipsel ||
- TargetArch == llvm::Triple::mips64el)
- Path += "/el";
+ return hasCrtBeginObj(Path + Suffix);
}
-static StringRef getMipsTargetABISuffix(llvm::Triple::ArchType TargetArch,
- const ArgList &Args) {
- if (TargetArch == llvm::Triple::mips64 ||
- TargetArch == llvm::Triple::mips64el)
- return hasMipsN32ABIArg(Args) ? "/n32" : "/64";
-
- return "/32";
-}
+void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix(
+ std::string &Suffix, llvm::Triple::ArchType TargetArch, StringRef Path,
+ const llvm::opt::ArgList &Args) {
+ if (!isMipsArch(TargetArch))
+ return;
-static bool findTargetMultiarchSuffix(std::string &Suffix,
- StringRef Path,
- llvm::Triple::ArchType TargetArch,
- const ArgList &Args) {
- if (isMipsArch(TargetArch)) {
- StringRef ABISuffix = getMipsTargetABISuffix(TargetArch, Args);
+ // Some MIPS toolchains put libraries and object files compiled
+ // using different options in to the sub-directoris which names
+ // reflects the flags used for compilation. For example sysroot
+ // directory might looks like the following examples:
+ //
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips32'
+ // /mips16
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips16'
+ // /el
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips16 -EL'
+ //
+ // or
+ //
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips32r2'
+ // /mips16
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips32r2 -mips16'
+ // /mips32
+ // /usr
+ // /lib <= crt*.o files compiled with '-mips32'
+ //
+ // Unfortunately different toolchains use different and partially
+ // overlapped naming schemes. So we have to make a trick for detection
+ // of using toolchain. We lookup a path which unique for each toolchains.
+
+ bool IsMentorToolChain = hasCrtBeginObj(Path + "/mips16/soft-float");
+ bool IsFSFToolChain = hasCrtBeginObj(Path + "/mips32/mips16/sof");
+
+ if (IsMentorToolChain && IsFSFToolChain)
+ D.Diag(diag::err_drv_unknown_toolchain);
+
+ if (IsMentorToolChain) {
+ if (isMips16(Args))
+ Suffix += "/mips16";
+ else if (isMicroMips(Args))
+ Suffix += "/micromips";
+
+ if (isSoftFloatABI(Args))
+ Suffix += "/soft-float";
+
+ if (TargetArch == llvm::Triple::mipsel ||
+ TargetArch == llvm::Triple::mips64el)
+ Suffix += "/el";
+ } else if (IsFSFToolChain) {
+ if (TargetArch == llvm::Triple::mips ||
+ TargetArch == llvm::Triple::mipsel) {
+ if (isMicroMips(Args))
+ Suffix += "/micromips";
+ else if (isMips32r2(Args))
+ Suffix += "";
+ else
+ Suffix += "/mips32";
- // First build and check a complex path to crtbegin.o
- // depends on command line options (-mips16, -msoft-float, ...)
- // like mips-linux-gnu/4.7/mips16/soft-float/el/crtbegin.o
- appendMipsTargetSuffix(Suffix, TargetArch, Args);
+ if (isMips16(Args))
+ Suffix += "/mips16";
+ } else {
+ if (isMips64r2(Args))
+ Suffix += hasMipsN32ABIArg(Args) ? "/mips64r2" : "/mips64r2/64";
+ else
+ Suffix += hasMipsN32ABIArg(Args) ? "/mips64" : "/mips64/64";
+ }
- if (TargetArch == llvm::Triple::mips64 ||
+ if (TargetArch == llvm::Triple::mipsel ||
TargetArch == llvm::Triple::mips64el)
- Suffix += ABISuffix;
+ Suffix += "/el";
- if (llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"))
- return true;
+ if (isSoftFloatABI(Args))
+ Suffix += "/sof";
+ else {
+ if (isMipsFP64(Args))
+ Suffix += "/fp64";
- // Then fall back and probe a simple case like
- // mips-linux-gnu/4.7/32/crtbegin.o
- Suffix = ABISuffix;
- return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o");
+ if (isMipsNan2008(Args))
+ Suffix += "/nan2008";
+ }
}
- if (TargetArch == llvm::Triple::x86_64 ||
- TargetArch == llvm::Triple::ppc64 ||
- TargetArch == llvm::Triple::systemz)
- Suffix = "/64";
- else
- Suffix = "/32";
-
- return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o");
+ if (!hasCrtBeginObj(Path + Suffix))
+ Suffix.clear();
}
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
llvm::Triple::ArchType TargetArch, const ArgList &Args,
- const std::string &LibDir,
- StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
+ const std::string &LibDir, StringRef CandidateTriple,
+ bool NeedsBiarchSuffix) {
// There are various different suffixes involving the triple we
// check for. We also record what is necessary to walk from each back
// up to the lib directory.
const std::string LibSuffixes[] = {
"/gcc/" + CandidateTriple.str(),
+ // Debian puts cross-compilers in gcc-cross
+ "/gcc-cross/" + CandidateTriple.str(),
"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
// The Freescale PPC SDK has the gcc libraries in
@@ -1395,14 +1504,15 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
"/i386-linux-gnu/gcc/" + CandidateTriple.str()
};
const std::string InstallSuffixes[] = {
- "/../../..",
- "/../../../..",
- "/../..",
- "/../../../.."
+ "/../../..", // gcc/
+ "/../../..", // gcc-cross/
+ "/../../../..", // <triple>/gcc/
+ "/../..", // <triple>/
+ "/../../../.." // i386-linux-gnu/gcc/<triple>/
};
// Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
- const unsigned NumLibSuffixes = (llvm::array_lengthof(LibSuffixes) -
- (TargetArch != llvm::Triple::x86));
+ const unsigned NumLibSuffixes =
+ (llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86));
for (unsigned i = 0; i < NumLibSuffixes; ++i) {
StringRef LibSuffix = LibSuffixes[i];
llvm::error_code EC;
@@ -1410,28 +1520,34 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef VersionText = llvm::sys::path::filename(LI->path());
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
- static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" };
- if (CandidateVersion < MinVersion)
+ if (CandidateVersion.Major != -1) // Filter obviously bad entries.
+ if (!CandidateGCCInstallPaths.insert(LI->path()).second)
+ continue; // Saw this path before; no need to look at it again.
+ if (CandidateVersion.isOlderThan(4, 1, 1))
continue;
if (CandidateVersion <= Version)
continue;
+ std::string MIPSABIDirSuffix;
+ findMIPSABIDirSuffix(MIPSABIDirSuffix, TargetArch, LI->path(), Args);
+
// Some versions of SUSE and Fedora on ppc64 put 32-bit libs
// in what would normally be GCCInstallPath and put the 64-bit
// libs in a subdirectory named 64. The simple logic we follow is that
// *if* there is a subdirectory of the right name with crtbegin.o in it,
- // we use that. If not, and if not a multiarch triple, we look for
+ // we use that. If not, and if not a biarch triple alias, we look for
// crtbegin.o without the subdirectory.
- std::string MultiarchSuffix;
- if (findTargetMultiarchSuffix(MultiarchSuffix,
- LI->path(), TargetArch, Args)) {
- GCCMultiarchSuffix = MultiarchSuffix;
+ std::string BiarchSuffix;
+ if (findTargetBiarchSuffix(BiarchSuffix,
+ LI->path() + MIPSABIDirSuffix,
+ TargetArch, Args)) {
+ GCCBiarchSuffix = BiarchSuffix;
+ } else if (NeedsBiarchSuffix ||
+ !hasCrtBeginObj(LI->path() + MIPSABIDirSuffix)) {
+ continue;
} else {
- if (NeedsMultiarchSuffix ||
- !llvm::sys::fs::exists(LI->path() + "/crtbegin.o"))
- continue;
- GCCMultiarchSuffix.clear();
+ GCCBiarchSuffix.clear();
}
Version = CandidateVersion;
@@ -1441,6 +1557,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
// Linux.
GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str();
GCCParentLibPath = GCCInstallPath + InstallSuffixes[i];
+ GCCMIPSABIDirSuffix = MIPSABIDirSuffix;
IsValid = true;
}
}
@@ -1484,6 +1601,11 @@ Tool *Generic_GCC::buildLinker() const {
return new tools::gcc::Link(*this);
}
+void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
+ // Print the information about how we detected the GCC installation.
+ GCCInstallation.print(OS);
+}
+
bool Generic_GCC::IsUnwindTablesDefault() const {
return getArch() == llvm::Triple::x86_64;
}
@@ -1628,7 +1750,6 @@ void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
- llvm::sys::Path InstallDir(D.InstalledDir);
std::string Ver(GetGCCLibAndIncVersion());
std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir);
std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
@@ -1646,10 +1767,10 @@ void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
const Driver &D = getDriver();
std::string Ver(GetGCCLibAndIncVersion());
- llvm::sys::Path IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir));
+ SmallString<128> IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir));
- IncludeDir.appendComponent("hexagon/include/c++/");
- IncludeDir.appendComponent(Ver);
+ llvm::sys::path::append(IncludeDir, "hexagon/include/c++/");
+ llvm::sys::path::append(IncludeDir, Ver);
addSystemInclude(DriverArgs, CC1Args, IncludeDir.str());
}
@@ -1668,40 +1789,47 @@ Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const {
return ToolChain::CST_Libstdcxx;
}
-static Arg *GetLastHexagonArchArg(const ArgList &Args)
-{
- Arg *A = NULL;
-
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- if ((*it)->getOption().matches(options::OPT_march_EQ) ||
- (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
- A = *it;
- A->claim();
- } else if ((*it)->getOption().matches(options::OPT_m_Joined)) {
- StringRef Value = (*it)->getValue(0);
- if (Value.startswith("v")) {
- A = *it;
- A->claim();
- }
- }
+static int getHexagonVersion(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ);
+ // Select the default CPU (v4) if none was given.
+ if (!A)
+ return 4;
+
+ // FIXME: produce errors if we cannot parse the version.
+ StringRef WhichHexagon = A->getValue();
+ if (WhichHexagon.startswith("hexagonv")) {
+ int Val;
+ if (!WhichHexagon.substr(sizeof("hexagonv") - 1).getAsInteger(10, Val))
+ return Val;
+ }
+ if (WhichHexagon.startswith("v")) {
+ int Val;
+ if (!WhichHexagon.substr(1).getAsInteger(10, Val))
+ return Val;
}
- return A;
+
+ // FIXME: should probably be an error.
+ return 4;
}
StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args)
{
- // Select the default CPU (v4) if none was given or detection failed.
- Arg *A = GetLastHexagonArchArg (Args);
- if (A) {
- StringRef WhichHexagon = A->getValue();
- if (WhichHexagon.startswith("hexagon"))
- return WhichHexagon.substr(sizeof("hexagon") - 1);
- if (WhichHexagon != "")
- return WhichHexagon;
+ int V = getHexagonVersion(Args);
+ // FIXME: We don't support versions < 4. We should error on them.
+ switch (V) {
+ default:
+ llvm_unreachable("Unexpected version");
+ case 5:
+ return "v5";
+ case 4:
+ return "v4";
+ case 3:
+ return "v3";
+ case 2:
+ return "v2";
+ case 1:
+ return "v1";
}
-
- return "v4";
}
// End Hexagon
@@ -1830,6 +1958,43 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
+ToolChain::CXXStdlibType
+FreeBSD::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "libstdc++")
+ return ToolChain::CST_Libstdcxx;
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+ if (getTriple().getOSMajorVersion() >= 10)
+ return ToolChain::CST_Libcxx;
+ return ToolChain::CST_Libstdcxx;
+}
+
+void FreeBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/v1");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/4.2");
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/4.2/backward");
+ break;
+ }
+}
+
Tool *FreeBSD::buildAssembler() const {
return new tools::freebsd::Assemble(*this);
}
@@ -1890,6 +2055,12 @@ NetBSD::GetCXXStdlibType(const ArgList &Args) const {
<< A->getAsString(Args);
}
+ unsigned Major, Minor, Micro;
+ getTriple().getOSVersion(Major, Minor, Micro);
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) {
+ if (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64)
+ return ToolChain::CST_Libcxx;
+ }
return ToolChain::CST_Libstdcxx;
}
@@ -1989,15 +2160,8 @@ enum Distro {
RHEL4,
RHEL5,
RHEL6,
- Fedora13,
- Fedora14,
- Fedora15,
- Fedora16,
- FedoraRawhide,
- OpenSuse11_3,
- OpenSuse11_4,
- OpenSuse12_1,
- OpenSuse12_2,
+ Fedora,
+ OpenSUSE,
UbuntuHardy,
UbuntuIntrepid,
UbuntuJaunty,
@@ -2009,16 +2173,17 @@ enum Distro {
UbuntuPrecise,
UbuntuQuantal,
UbuntuRaring,
+ UbuntuSaucy,
+ UbuntuTrusty,
UnknownDistro
};
static bool IsRedhat(enum Distro Distro) {
- return (Distro >= Fedora13 && Distro <= FedoraRawhide) ||
- (Distro >= RHEL4 && Distro <= RHEL6);
+ return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL6);
}
-static bool IsOpenSuse(enum Distro Distro) {
- return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2;
+static bool IsOpenSUSE(enum Distro Distro) {
+ return Distro == OpenSUSE;
}
static bool IsDebian(enum Distro Distro) {
@@ -2026,7 +2191,7 @@ static bool IsDebian(enum Distro Distro) {
}
static bool IsUbuntu(enum Distro Distro) {
- return Distro >= UbuntuHardy && Distro <= UbuntuRaring;
+ return Distro >= UbuntuHardy && Distro <= UbuntuTrusty;
}
static Distro DetectDistro(llvm::Triple::ArchType Arch) {
@@ -2050,23 +2215,16 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) {
.Case("precise", UbuntuPrecise)
.Case("quantal", UbuntuQuantal)
.Case("raring", UbuntuRaring)
+ .Case("saucy", UbuntuSaucy)
+ .Case("trusty", UbuntuTrusty)
.Default(UnknownDistro);
return Version;
}
if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) {
StringRef Data = File.get()->getBuffer();
- if (Data.startswith("Fedora release 16"))
- return Fedora16;
- else if (Data.startswith("Fedora release 15"))
- return Fedora15;
- else if (Data.startswith("Fedora release 14"))
- return Fedora14;
- else if (Data.startswith("Fedora release 13"))
- return Fedora13;
- else if (Data.startswith("Fedora release") &&
- Data.find("Rawhide") != StringRef::npos)
- return FedoraRawhide;
+ if (Data.startswith("Fedora release"))
+ return Fedora;
else if (Data.startswith("Red Hat Enterprise Linux") &&
Data.find("release 6") != StringRef::npos)
return RHEL6;
@@ -2094,19 +2252,13 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) {
return UnknownDistro;
}
- if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File))
- return llvm::StringSwitch<Distro>(File.get()->getBuffer())
- .StartsWith("openSUSE 11.3", OpenSuse11_3)
- .StartsWith("openSUSE 11.4", OpenSuse11_4)
- .StartsWith("openSUSE 12.1", OpenSuse12_1)
- .StartsWith("openSUSE 12.2", OpenSuse12_2)
- .Default(UnknownDistro);
+ if (llvm::sys::fs::exists("/etc/SuSE-release"))
+ return OpenSUSE;
- bool Exists;
- if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists)
+ if (llvm::sys::fs::exists("/etc/exherbo-release"))
return Exherbo;
- if (!llvm::sys::fs::exists("/etc/arch-release", Exists) && Exists)
+ if (llvm::sys::fs::exists("/etc/arch-release"))
return ArchLinux;
return UnknownDistro;
@@ -2151,6 +2303,7 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
case llvm::Triple::aarch64:
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
return "aarch64-linux-gnu";
+ return TargetTriple.str();
case llvm::Triple::mips:
if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu"))
return "mips-linux-gnu";
@@ -2168,6 +2321,9 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
case llvm::Triple::ppc64:
if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu"))
return "powerpc64-linux-gnu";
+ case llvm::Triple::ppc64le:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64le-linux-gnu"))
+ return "powerpc64le-linux-gnu";
return TargetTriple.str();
}
}
@@ -2176,34 +2332,28 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
}
-static bool isMipsR2Arch(llvm::Triple::ArchType Arch,
- const ArgList &Args) {
- if (Arch != llvm::Triple::mips &&
- Arch != llvm::Triple::mipsel)
- return false;
-
- Arg *A = Args.getLastArg(options::OPT_march_EQ,
- options::OPT_mcpu_EQ,
- options::OPT_mips_CPUs_Group);
-
- if (!A)
- return false;
-
- if (A->getOption().matches(options::OPT_mips_CPUs_Group))
- return A->getOption().matches(options::OPT_mips32r2);
-
- return A->getValue() == StringRef("mips32r2");
-}
-
static StringRef getMultilibDir(const llvm::Triple &Triple,
const ArgList &Args) {
- if (!isMipsArch(Triple.getArch()))
- return Triple.isArch32Bit() ? "lib32" : "lib64";
+ if (isMipsArch(Triple.getArch())) {
+ // lib32 directory has a special meaning on MIPS targets.
+ // It contains N32 ABI binaries. Use this folder if produce
+ // code for N32 ABI only.
+ if (hasMipsN32ABIArg(Args))
+ return "lib32";
+ return Triple.isArch32Bit() ? "lib" : "lib64";
+ }
- // lib32 directory has a special meaning on MIPS targets.
- // It contains N32 ABI binaries. Use this folder if produce
- // code for N32 ABI only.
- if (hasMipsN32ABIArg(Args))
+ // It happens that only x86 and PPC use the 'lib32' variant of multilib, and
+ // using that variant while targeting other architectures causes problems
+ // because the libraries are laid out in shared system roots that can't cope
+ // with a 'lib32' multilib search path being considered. So we only enable
+ // them when we know we may need it.
+ //
+ // FIXME: This is a bit of a hack. We should really unify this code for
+ // reasoning about multilib spellings with the lib dir spellings in the
+ // GCCInstallationDetector, but that is a more significant refactoring.
+ if (Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::ppc)
return "lib32";
return Triple.isArch32Bit() ? "lib" : "lib64";
@@ -2212,10 +2362,16 @@ static StringRef getMultilibDir(const llvm::Triple &Triple,
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
llvm::Triple::ArchType Arch = Triple.getArch();
- std::string SysRoot = computeSysRoot(Args);
-
- // OpenSuse stores the linker with the compiler, add that to the search
- // path.
+ std::string SysRoot = computeSysRoot();
+
+ // Cross-compiling binutils and GCC installations (vanilla and openSUSE at
+ // least) put various tools in a triple-prefixed directory off of the parent
+ // of the GCC installation. We use the GCC triple here to ensure that we end
+ // up with tools that support the same amount of cross compiling as the
+ // detected GCC installation. For example, if we find a GCC installation
+ // targeting x86_64, but it is a bi-arch GCC installation, it can also be
+ // used to target i386.
+ // FIXME: This seems unlikely to be Linux-specific.
ToolChain::path_list &PPaths = getProgramPaths();
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
GCCInstallation.getTriple().str() + "/bin").str());
@@ -2224,7 +2380,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
Distro Distro = DetectDistro(Arch);
- if (IsOpenSuse(Distro) || IsUbuntu(Distro)) {
+ if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("relro");
}
@@ -2244,11 +2400,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// ABI requires a mapping between the GOT and the symbol table.
// Android loader does not support .gnu.hash.
if (!IsMips && !IsAndroid) {
- if (IsRedhat(Distro) || IsOpenSuse(Distro) ||
+ if (IsRedhat(Distro) || IsOpenSUSE(Distro) ||
(IsUbuntu(Distro) && Distro >= UbuntuMaverick))
ExtraOpts.push_back("--hash-style=gnu");
- if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid ||
+ if (IsDebian(Distro) || IsOpenSUSE(Distro) || Distro == UbuntuLucid ||
Distro == UbuntuJaunty || Distro == UbuntuKarmic)
ExtraOpts.push_back("--hash-style=both");
}
@@ -2257,12 +2413,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
ExtraOpts.push_back("--no-add-needed");
if (Distro == DebianSqueeze || Distro == DebianWheezy ||
- Distro == DebianJessie || IsOpenSuse(Distro) ||
+ Distro == DebianJessie || IsOpenSUSE(Distro) ||
(IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
(IsUbuntu(Distro) && Distro >= UbuntuKarmic))
ExtraOpts.push_back("--build-id");
- if (IsOpenSuse(Distro))
+ if (IsOpenSUSE(Distro))
ExtraOpts.push_back("--enable-new-dtags");
// The selection of paths to try here is designed to match the patterns which
@@ -2280,15 +2436,43 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
- if (IsAndroid && isMipsR2Arch(Triple.getArch(), Args))
- addPathIfExists(GCCInstallation.getInstallPath() +
- GCCInstallation.getMultiarchSuffix() +
- "/mips-r2",
- Paths);
- else
+ // Sourcery CodeBench MIPS toolchain holds some libraries under
+ // a biarch-like suffix of the GCC installation.
+ //
+ // FIXME: It would be cleaner to model this as a variant of bi-arch. IE,
+ // instead of a '64' biarch suffix it would be 'el' or something.
+ if (IsAndroid && IsMips && isMips32r2(Args)) {
+ assert(GCCInstallation.getBiarchSuffix().empty() &&
+ "Unexpected bi-arch suffix");
+ addPathIfExists(GCCInstallation.getInstallPath() + "/mips-r2", Paths);
+ } else {
addPathIfExists((GCCInstallation.getInstallPath() +
- GCCInstallation.getMultiarchSuffix()),
+ GCCInstallation.getMIPSABIDirSuffix() +
+ GCCInstallation.getBiarchSuffix()),
Paths);
+ }
+
+ // GCC cross compiling toolchains will install target libraries which ship
+ // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
+ // any part of the GCC installation in
+ // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
+ // debatable, but is the reality today. We need to search this tree even
+ // when we have a sysroot somewhere else. It is the responsibility of
+ // whomever is doing the cross build targetting a sysroot using a GCC
+ // installation that is *not* within the system root to ensure two things:
+ //
+ // 1) Any DSOs that are linked in from this tree or from the install path
+ // above must be preasant on the system root and found via an
+ // appropriate rpath.
+ // 2) There must not be libraries installed into
+ // <prefix>/<triple>/<libdir> unless they should be preferred over
+ // those within the system root.
+ //
+ // Note that this matches the GCC behavior. See the below comment for where
+ // Clang diverges from GCC's behavior.
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib +
+ GCCInstallation.getMIPSABIDirSuffix(),
+ Paths);
// If the GCC installation we found is inside of the sysroot, we want to
// prefer libraries installed in the parent prefix of the GCC installation.
@@ -2296,55 +2480,48 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// outside of the system root as that can pick up unintended libraries.
// This usually happens when there is an external cross compiler on the
// host system, and a more minimal sysroot available that is the target of
- // the cross.
+ // the cross. Note that GCC does include some of these directories in some
+ // configurations but this seems somewhere between questionable and simply
+ // a bug.
if (StringRef(LibPath).startswith(SysRoot)) {
- addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib,
- Paths);
addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
addPathIfExists(LibPath + "/../" + Multilib, Paths);
}
- // On Android, libraries in the parent prefix of the GCC installation are
- // preferred to the ones under sysroot.
- if (IsAndroid) {
- addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
- }
- // Sourcery CodeBench MIPS toolchain holds some libraries under
- // the parent prefix of the GCC installation.
- if (IsMips) {
- std::string Suffix;
- appendMipsTargetSuffix(Suffix, Arch, Args);
- addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" +
- Multilib + Suffix,
- Paths);
- }
}
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths);
- // Try walking via the GCC triple path in case of multiarch GCC
+ // Try walking via the GCC triple path in case of biarch or multiarch GCC
// installations with strange symlinks.
- if (GCCInstallation.isValid())
+ if (GCCInstallation.isValid()) {
addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
"/../../" + Multilib, Paths);
- // Add the non-multilib suffixed paths (if potentially different).
- if (GCCInstallation.isValid()) {
+ // Add the non-multilib suffixed paths (if potentially different).
const std::string &LibPath = GCCInstallation.getParentLibPath();
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
- if (!GCCInstallation.getMultiarchSuffix().empty())
- addPathIfExists(GCCInstallation.getInstallPath(), Paths);
+ if (!GCCInstallation.getBiarchSuffix().empty())
+ addPathIfExists(GCCInstallation.getInstallPath() +
+ GCCInstallation.getMIPSABIDirSuffix(), Paths);
- if (StringRef(LibPath).startswith(SysRoot)) {
- addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
+ // See comments above on the multilib variant for details of why this is
+ // included even from outside the sysroot.
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() +
+ "/lib" + GCCInstallation.getMIPSABIDirSuffix(), Paths);
+
+ // See comments above on the multilib variant for details of why this is
+ // only included from within the sysroot.
+ if (StringRef(LibPath).startswith(SysRoot))
addPathIfExists(LibPath, Paths);
- }
}
addPathIfExists(SysRoot + "/lib", Paths);
addPathIfExists(SysRoot + "/usr/lib", Paths);
+}
- IsPIEDefault = SanitizerArgs(*this, Args).hasZeroBaseShadow();
+bool FreeBSD::HasNativeLLVMSupport() const {
+ return true;
}
bool Linux::HasNativeLLVMSupport() const {
@@ -2362,8 +2539,8 @@ Tool *Linux::buildAssembler() const {
void Linux::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- bool UseInitArrayDefault
- = V >= Generic_GCC::GCCVersion::Parse("4.7.0") ||
+ bool UseInitArrayDefault =
+ !V.isOlderThan(4, 7, 0) ||
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getEnvironment() == llvm::Triple::Android;
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
@@ -2372,25 +2549,39 @@ void Linux::addClangTargetOptions(const ArgList &DriverArgs,
CC1Args.push_back("-fuse-init-array");
}
-std::string Linux::computeSysRoot(const ArgList &Args) const {
+std::string Linux::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
return getDriver().SysRoot;
if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch()))
return std::string();
- std::string Path =
- (GCCInstallation.getInstallPath() +
- "/../../../../" + GCCInstallation.getTriple().str() + "/libc").str();
- appendMipsTargetSuffix(Path, getTriple().getArch(), Args);
+ // Standalone MIPS toolchains use different names for sysroot folder
+ // and put it into different places. Here we try to check some known
+ // variants.
+
+ const StringRef InstallDir = GCCInstallation.getInstallPath();
+ const StringRef TripleStr = GCCInstallation.getTriple().str();
+ const StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix();
+
+ std::string Path = (InstallDir + "/../../../../" + TripleStr + "/libc" +
+ MIPSABIDirSuffix).str();
+
+ if (llvm::sys::fs::exists(Path))
+ return Path;
+
+ Path = (InstallDir + "/../../../../sysroot" + MIPSABIDirSuffix).str();
+
+ if (llvm::sys::fs::exists(Path))
+ return Path;
- return llvm::sys::fs::exists(Path) ? Path : "";
+ return std::string();
}
void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Driver &D = getDriver();
- std::string SysRoot = computeSysRoot(DriverArgs);
+ std::string SysRoot = computeSysRoot();
if (DriverArgs.hasArg(options::OPT_nostdinc))
return;
@@ -2399,8 +2590,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- llvm::sys::Path P(D.ResourceDir);
- P.appendComponent("include");
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
addSystemInclude(DriverArgs, CC1Args, P.str());
}
@@ -2426,15 +2617,17 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Sourcery CodeBench and modern FSF Mips toolchains put extern C
// system includes under three additional directories.
if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) {
- addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
- GCCInstallation.getInstallPath() +
- "/include");
+ addExternCSystemIncludeIfExists(
+ DriverArgs, CC1Args, GCCInstallation.getInstallPath() + "/include");
- addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
- GCCInstallation.getInstallPath() +
- "/../../../../" +
- GCCInstallation.getTriple().str() +
- "/libc/usr/include");
+ addExternCSystemIncludeIfExists(
+ DriverArgs, CC1Args,
+ GCCInstallation.getInstallPath() + "/../../../../" +
+ GCCInstallation.getTriple().str() + "/libc/usr/include");
+
+ addExternCSystemIncludeIfExists(
+ DriverArgs, CC1Args,
+ GCCInstallation.getInstallPath() + "/../../../../sysroot/usr/include");
}
// Implement generic Debian multiarch support.
@@ -2444,8 +2637,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// FIXME: These are older forms of multiarch. It's not clear that they're
// in use in any released version of Debian, so we should consider
// removing them.
- "/usr/include/i686-linux-gnu/64",
- "/usr/include/i486-linux-gnu/64"
+ "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"
};
const StringRef X86MultiarchIncludeDirs[] = {
"/usr/include/i386-linux-gnu",
@@ -2453,8 +2645,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// FIXME: These are older forms of multiarch. It's not clear that they're
// in use in any released version of Debian, so we should consider
// removing them.
- "/usr/include/x86_64-linux-gnu/32",
- "/usr/include/i686-linux-gnu",
+ "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu",
"/usr/include/i486-linux-gnu"
};
const StringRef AArch64MultiarchIncludeDirs[] = {
@@ -2535,15 +2726,17 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
/// libstdc++ installation.
/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
Twine TargetArchDir,
- Twine MultiLibSuffix,
+ Twine BiarchSuffix,
+ Twine MIPSABIDirSuffix,
const ArgList &DriverArgs,
ArgStringList &CC1Args) {
- if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix,
+ if (!addLibStdCXXIncludePaths(Base + Suffix,
+ TargetArchDir + MIPSABIDirSuffix + BiarchSuffix,
DriverArgs, CC1Args))
return false;
addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix
- + MultiLibSuffix);
+ + MIPSABIDirSuffix + BiarchSuffix);
return true;
}
@@ -2571,37 +2764,39 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
// equivalent to '/usr/include/c++/X.Y' in almost all cases.
StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = GCCInstallation.getInstallPath();
- StringRef Version = GCCInstallation.getVersion().Text;
StringRef TripleStr = GCCInstallation.getTriple().str();
+ StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix();
+ StringRef BiarchSuffix = GCCInstallation.getBiarchSuffix();
+ const GCCVersion &Version = GCCInstallation.getVersion();
- if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
- "/c++/" + Version.str(),
- TripleStr,
- GCCInstallation.getMultiarchSuffix(),
- DriverArgs, CC1Args))
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.Text, TripleStr, BiarchSuffix,
+ MIPSABIDirSuffix, DriverArgs, CC1Args))
return;
const std::string IncludePathCandidates[] = {
// Gentoo is weird and places its headers inside the GCC install, so if the
- // first attempt to find the headers fails, try this pattern.
- InstallDir.str() + "/include/g++-v4",
+ // first attempt to find the headers fails, try these patterns.
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
+ Version.MinorStr,
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr,
// Android standalone toolchain has C++ headers in yet another place.
- LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.str(),
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
// Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
// without a subdirectory corresponding to the gcc version.
LibDir.str() + "/../include/c++",
};
for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) {
- if (addLibStdCXXIncludePaths(IncludePathCandidates[i], (TripleStr +
- GCCInstallation.getMultiarchSuffix()),
- DriverArgs, CC1Args))
+ if (addLibStdCXXIncludePaths(IncludePathCandidates[i],
+ TripleStr + MIPSABIDirSuffix + BiarchSuffix,
+ DriverArgs, CC1Args))
break;
}
}
bool Linux::isPIEDefault() const {
- return IsPIEDefault;
+ return getSanitizerArgs().hasZeroBaseShadow();
}
/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
@@ -2629,3 +2824,77 @@ Tool *DragonFly::buildAssembler() const {
Tool *DragonFly::buildLinker() const {
return new tools::dragonfly::Link(*this);
}
+
+
+/// XCore tool chain
+XCore::XCore(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args) : ToolChain(D, Triple, Args) {
+ // ProgramPaths are found via 'PATH' environment variable.
+}
+
+Tool *XCore::buildAssembler() const {
+ return new tools::XCore::Assemble(*this);
+}
+
+Tool *XCore::buildLinker() const {
+ return new tools::XCore::Link(*this);
+}
+
+bool XCore::isPICDefault() const {
+ return false;
+}
+
+bool XCore::isPIEDefault() const {
+ return false;
+}
+
+bool XCore::isPICDefaultForced() const {
+ return false;
+}
+
+bool XCore::SupportsProfiling() const {
+ return false;
+}
+
+bool XCore::hasBlocksRuntime() const {
+ return false;
+}
+
+
+void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+ if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) {
+ SmallVector<StringRef, 4> Dirs;
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator,'\0'};
+ StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
+ ArrayRef<StringRef> DirVec(Dirs);
+ addSystemIncludes(DriverArgs, CC1Args, DirVec);
+ }
+}
+
+void XCore::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ CC1Args.push_back("-nostdsysteminc");
+}
+
+void XCore::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+ if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) {
+ SmallVector<StringRef, 4> Dirs;
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator,'\0'};
+ StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
+ ArrayRef<StringRef> DirVec(Dirs);
+ addSystemIncludes(DriverArgs, CC1Args, DirVec);
+ }
+}
+
+void XCore::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // We don't output any lib args. This is handled by xcc.
+}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 3afd8dd228b6..50d370003bac 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -16,6 +16,8 @@
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Compiler.h"
+#include <vector>
+#include <set>
namespace clang {
namespace driver {
@@ -48,11 +50,18 @@ protected:
/// \brief The parsed major, minor, and patch numbers.
int Major, Minor, Patch;
+ /// \brief The text of the parsed major, and major+minor versions.
+ std::string MajorStr, MinorStr;
+
/// \brief Any textual suffix on the patch number.
std::string PatchSuffix;
static GCCVersion Parse(StringRef VersionText);
- bool operator<(const GCCVersion &RHS) const;
+ bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch,
+ StringRef RHSPatchSuffix = StringRef()) const;
+ bool operator<(const GCCVersion &RHS) const {
+ return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix);
+ }
bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
@@ -66,20 +75,25 @@ protected:
/// information about it. It starts from the host information provided to the
/// Driver, and has logic for fuzzing that where appropriate.
class GCCInstallationDetector {
-
bool IsValid;
+ const Driver &D;
llvm::Triple GCCTriple;
// FIXME: These might be better as path objects.
std::string GCCInstallPath;
- std::string GCCMultiarchSuffix;
+ std::string GCCBiarchSuffix;
std::string GCCParentLibPath;
+ std::string GCCMIPSABIDirSuffix;
GCCVersion Version;
+ // We retain the list of install paths that were considered and rejected in
+ // order to print out detailed information in verbose mode.
+ std::set<std::string> CandidateGCCInstallPaths;
+
public:
GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple,
- const ArgList &Args);
+ const llvm::opt::ArgList &Args);
/// \brief Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
@@ -90,37 +104,62 @@ protected:
/// \brief Get the detected GCC installation path.
StringRef getInstallPath() const { return GCCInstallPath; }
- /// \brief Get the detected GCC installation path suffix for multiarch GCCs.
- StringRef getMultiarchSuffix() const { return GCCMultiarchSuffix; }
+ /// \brief Get the detected GCC installation path suffix for the bi-arch
+ /// target variant.
+ StringRef getBiarchSuffix() const { return GCCBiarchSuffix; }
/// \brief Get the detected GCC parent lib path.
StringRef getParentLibPath() const { return GCCParentLibPath; }
+ /// \brief Get the detected GCC MIPS ABI directory suffix.
+ ///
+ /// This is used as a suffix both to the install directory of GCC and as
+ /// a suffix to its parent lib path in order to select a MIPS ABI-specific
+ /// subdirectory.
+ ///
+ /// This will always be empty for any non-MIPS target.
+ ///
+ // FIXME: This probably shouldn't exist at all, and should be factored
+ // into the multiarch and/or biarch support. Please don't add more uses of
+ // this interface, it is meant as a legacy crutch for the MIPS driver
+ // logic.
+ StringRef getMIPSABIDirSuffix() const { return GCCMIPSABIDirSuffix; }
+
/// \brief Get the detected GCC version string.
const GCCVersion &getVersion() const { return Version; }
+ /// \brief Print information about the detected GCC installation.
+ void print(raw_ostream &OS) const;
+
private:
- static void CollectLibDirsAndTriples(
- const llvm::Triple &TargetTriple,
- const llvm::Triple &MultiarchTriple,
- SmallVectorImpl<StringRef> &LibDirs,
- SmallVectorImpl<StringRef> &TripleAliases,
- SmallVectorImpl<StringRef> &MultiarchLibDirs,
- SmallVectorImpl<StringRef> &MultiarchTripleAliases);
+ static void
+ CollectLibDirsAndTriples(const llvm::Triple &TargetTriple,
+ const llvm::Triple &BiarchTriple,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &TripleAliases,
+ SmallVectorImpl<StringRef> &BiarchLibDirs,
+ SmallVectorImpl<StringRef> &BiarchTripleAliases);
void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
- const ArgList &Args,
+ const llvm::opt::ArgList &Args,
const std::string &LibDir,
StringRef CandidateTriple,
- bool NeedsMultiarchSuffix = false);
+ bool NeedsBiarchSuffix = false);
+
+ void findMIPSABIDirSuffix(std::string &Suffix,
+ llvm::Triple::ArchType TargetArch, StringRef Path,
+ const llvm::opt::ArgList &Args);
};
GCCInstallationDetector GCCInstallation;
public:
- Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Generic_GCC(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
~Generic_GCC();
+ virtual void printVerboseInfo(raw_ostream &OS) const;
+
virtual bool IsUnwindTablesDefault() const;
virtual bool isPICDefault() const;
virtual bool isPIEDefault() const;
@@ -190,13 +229,14 @@ private:
std::string iOSVersionMin;
private:
- void AddDeploymentTarget(DerivedArgList &Args) const;
+ void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const;
public:
- Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Darwin(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
~Darwin();
- std::string ComputeEffectiveClangTriple(const ArgList &Args,
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const;
/// @name Darwin Specific Toolchain API
@@ -246,7 +286,7 @@ public:
/// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
/// invocation. For example, Darwin treats different ARM variations as
/// distinct architectures.
- StringRef getDarwinArchName(const ArgList &Args) const;
+ StringRef getDarwinArchName(const llvm::opt::ArgList &Args) const;
bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
assert(isTargetIPhoneOS() && "Unexpected call for OS X target!");
@@ -259,14 +299,15 @@ public:
}
/// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library.
- virtual void AddLinkARCArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const = 0;
-
+ virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const = 0;
+
/// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
/// runtime library.
- virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const = 0;
-
+ virtual void
+ AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const = 0;
+
/// }
/// @name ToolChain Implementation
/// {
@@ -278,8 +319,9 @@ public:
virtual ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const;
virtual bool hasBlocksRuntime() const;
- virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
- const char *BoundArch) const;
+ virtual llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ const char *BoundArch) const;
virtual bool IsBlocksDefault() const {
// Always allow blocks on Darwin; users interested in versioning are
@@ -287,19 +329,8 @@ public:
return true;
}
virtual bool IsIntegratedAssemblerDefault() const {
-#ifdef DISABLE_DEFAULT_INTEGRATED_ASSEMBLER
- return false;
-#else
// Default integrated assembler to on for Darwin.
return true;
-#endif
- }
- virtual bool IsStrictAliasingDefault() const {
-#ifdef DISABLE_DEFAULT_STRICT_ALIASING
- return false;
-#else
- return ToolChain::IsStrictAliasingDefault();
-#endif
}
virtual bool IsMathErrnoDefault() const {
@@ -352,35 +383,38 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
public:
- DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ DarwinClang(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
/// @name Darwin ToolChain Implementation
/// {
- virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
- void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
const char *DarwinStaticLib,
bool AlwaysLink = false) const;
- virtual void AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
- virtual void AddCCKextLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
- virtual void AddLinkARCArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
/// }
};
/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC {
public:
- Darwin_Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {}
+ Darwin_Generic_GCC(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {}
- std::string ComputeEffectiveClangTriple(const ArgList &Args,
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const;
virtual bool isPICDefault() const { return false; }
@@ -389,8 +423,9 @@ public:
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
virtual void anchor();
public:
- Generic_ELF(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {}
+ Generic_ELF(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {}
virtual bool IsIntegratedAssemblerDefault() const {
// Default integrated assembler to on for x86.
@@ -402,7 +437,8 @@ public:
class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
- AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ AuroraUX(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
protected:
virtual Tool *buildAssembler() const;
@@ -411,7 +447,8 @@ protected:
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
public:
- Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Solaris(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsIntegratedAssemblerDefault() const { return true; }
protected:
@@ -423,10 +460,16 @@ protected:
class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
public:
- OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ OpenBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ virtual bool isPIEDefault() const { return true; }
+
+ virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
+ return 1;
+ }
protected:
virtual Tool *buildAssembler() const;
@@ -435,16 +478,18 @@ protected:
class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
public:
- Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Bitrig(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
virtual bool IsObjCLegacyDispatchDefault() const { return false; }
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual void AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
return 1;
}
@@ -456,11 +501,19 @@ protected:
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
public:
- FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ FreeBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ virtual bool HasNativeLLVMSupport() const;
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
+
virtual bool UseSjLjExceptions() const;
protected:
virtual Tool *buildAssembler() const;
@@ -469,15 +522,25 @@ protected:
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
public:
- NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ NetBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
+ virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual bool IsUnwindTablesDefault() const {
+ return true;
+ }
+ virtual bool IsIntegratedAssemblerDefault() const {
+ if (getTriple().getArch() == llvm::Triple::ppc)
+ return true;
+ return Generic_ELF::IsIntegratedAssemblerDefault();
+ }
protected:
virtual Tool *buildAssembler() const;
@@ -486,7 +549,8 @@ protected:
class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
public:
- Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Minix(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
protected:
virtual Tool *buildAssembler() const;
@@ -495,7 +559,8 @@ protected:
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
public:
- DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ DragonFly(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsMathErrnoDefault() const { return false; }
@@ -506,21 +571,23 @@ protected:
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
public:
- Linux(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Linux(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool HasNativeLLVMSupport() const;
- virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual void addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
virtual bool isPIEDefault() const;
std::string Linker;
std::vector<std::string> ExtraOpts;
- bool IsPIEDefault;
protected:
virtual Tool *buildAssembler() const;
@@ -529,14 +596,15 @@ protected:
private:
static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
Twine TargetArchDir,
- Twine MultiLibSuffix,
- const ArgList &DriverArgs,
- ArgStringList &CC1Args);
+ Twine BiarchSuffix,
+ Twine MIPSABIDirSuffix,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args);
static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
- const ArgList &DriverArgs,
- ArgStringList &CC1Args);
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args);
- std::string computeSysRoot(const ArgList &Args) const;
+ std::string computeSysRoot() const;
};
class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux {
@@ -547,28 +615,30 @@ protected:
public:
Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args);
+ const llvm::opt::ArgList &Args);
~Hexagon_TC();
- virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
+ virtual void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
static std::string GetGnuDir(const std::string &InstalledDir);
- static StringRef GetTargetCPU(const ArgList &Args);
+ static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
};
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
- TCEToolChain(const Driver &D, const llvm::Triple& Triple,
- const ArgList &Args);
+ TCEToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
~TCEToolChain();
bool IsMathErrnoDefault() const;
@@ -579,7 +649,8 @@ public:
class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
public:
- Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+ Windows(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
@@ -587,15 +658,42 @@ public:
virtual bool isPIEDefault() const;
virtual bool isPICDefaultForced() const;
- virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
- virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const;
+ virtual void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
protected:
virtual Tool *buildLinker() const;
virtual Tool *buildAssembler() const;
};
+
+class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain {
+public:
+ XCore(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+public:
+ virtual bool isPICDefault() const;
+ virtual bool isPIEDefault() const;
+ virtual bool isPICDefaultForced() const;
+ virtual bool SupportsProfiling() const;
+ virtual bool hasBlocksRuntime() const;
+ virtual void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+};
+
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index aba1fe4d2d9e..29713ed1b4ce 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -7,43 +7,48 @@
//
//===----------------------------------------------------------------------===//
-#include <sys/stat.h>
#include "Tools.h"
#include "InputInfo.h"
-#include "SanitizerArgs.h"
#include "ToolChains.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Job.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
+#include <sys/stat.h>
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
+using namespace llvm::opt;
/// CheckPreprocessingOptions - Perform some validation of preprocessing
/// arguments that is shared with gcc.
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
- if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP)
+ if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP())
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
}
@@ -107,7 +112,7 @@ static void addDirectoryList(const ArgList &Args,
return;
StringRef::size_type Delim;
- while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
+ while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) {
if (Delim == 0) { // Leading colon.
if (CombinedArg) {
CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
@@ -223,7 +228,9 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args,
}
static bool forwardToGCC(const Option &O) {
- return !O.hasFlag(options::NoForward) &&
+ // Don't forward inputs from the original command line. They are added from
+ // InputInfoList.
+ return O.getKind() != Option::InputClass &&
!O.hasFlag(options::DriverOption) &&
!O.hasFlag(options::LinkerInput);
}
@@ -339,32 +346,28 @@ void Clang::AddPreprocessingOptions(Compilation &C,
bool FoundPTH = false;
bool FoundPCH = false;
- llvm::sys::Path P(A->getValue());
- bool Exists;
+ SmallString<128> P(A->getValue());
+ // We want the files to have a name like foo.h.pch. Add a dummy extension
+ // so that replace_extension does the right thing.
+ P += ".dummy";
if (UsePCH) {
- P.appendSuffix("pch");
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ llvm::sys::path::replace_extension(P, "pch");
+ if (llvm::sys::fs::exists(P.str()))
FoundPCH = true;
- else
- P.eraseSuffix();
}
if (!FoundPCH) {
- P.appendSuffix("pth");
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ llvm::sys::path::replace_extension(P, "pth");
+ if (llvm::sys::fs::exists(P.str()))
FoundPTH = true;
- else
- P.eraseSuffix();
}
if (!FoundPCH && !FoundPTH) {
- P.appendSuffix("gch");
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) {
+ llvm::sys::path::replace_extension(P, "gch");
+ if (llvm::sys::fs::exists(P.str())) {
FoundPCH = UsePCH;
FoundPTH = !UsePCH;
}
- else
- P.eraseSuffix();
}
if (FoundPCH || FoundPTH) {
@@ -446,6 +449,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
// FIXME: tblgen this, or kill it!
static const char *getLLVMArchSuffixForARM(StringRef CPU) {
return llvm::StringSwitch<const char *>(CPU)
+ .Case("strongarm", "v4")
.Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
.Cases("arm720t", "arm9", "arm9tdmi", "v4t")
.Cases("arm920", "arm920t", "arm922t", "v4t")
@@ -458,13 +462,14 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
- .Cases("cortex-a9", "cortex-a15", "v7")
- .Case("cortex-r5", "v7r")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7")
+ .Cases("cortex-r4", "cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
+ .Cases("cortex-a53", "cortex-a57", "v8")
.Default("");
}
@@ -494,6 +499,11 @@ static std::string getARMTargetCPU(const ArgList &Args,
MArch = Triple.getArchName();
}
+ if (Triple.getOS() == llvm::Triple::NetBSD) {
+ if (MArch == "armv6")
+ return "arm1176jzf-s";
+ }
+
// Handle -march=native.
std::string NativeMArch;
if (MArch == "native") {
@@ -510,7 +520,8 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Cases("armv2", "armv2a","arm2")
.Case("armv3", "arm6")
.Case("armv3m", "arm7m")
- .Cases("armv4", "armv4t", "arm7tdmi")
+ .Case("armv4", "strongarm")
+ .Case("armv4t", "arm7tdmi")
.Cases("armv5", "armv5t", "arm10tdmi")
.Cases("armv5e", "armv5te", "arm1022e")
.Case("armv5tej", "arm926ej-s")
@@ -525,13 +536,35 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
+ .Cases("armv8", "armv8a", "armv8-a", "cortex-a53")
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- // If all else failed, return the most base CPU LLVM supports.
+ // If all else failed, return the most base CPU with thumb interworking
+ // supported by LLVM.
.Default("arm7tdmi");
}
+/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are targeting.
+//
+// FIXME: tblgen this.
+static std::string getAArch64TargetCPU(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ // FIXME: Warn on inconsistent use of -mcpu and -march.
+
+ // If we have -mcpu=, use that.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef MCPU = A->getValue();
+ // Handle -mcpu=native.
+ if (MCPU == "native")
+ return llvm::sys::getHostCPUName();
+ else
+ return MCPU;
+ }
+
+ return "generic";
+}
+
// FIXME: Move to target hook.
static bool isSignedCharDefault(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
@@ -546,73 +579,117 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
return true;
return false;
+ case llvm::Triple::ppc64le:
case llvm::Triple::systemz:
+ case llvm::Triple::xcore:
return false;
}
}
+static bool isNoCommonDefault(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return false;
+
+ case llvm::Triple::xcore:
+ return true;
+ }
+}
+
+// Handle -mfpu=.
+//
+// FIXME: Centralize feature selection, defaulting shouldn't be also in the
+// frontend target.
+static void getAArch64FPUFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef FPU = A->getValue();
+ if (FPU == "fp-armv8") {
+ Features.push_back("+fp-armv8");
+ } else if (FPU == "neon-fp-armv8") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+neon");
+ } else if (FPU == "crypto-neon-fp-armv8") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+neon");
+ Features.push_back("+crypto");
+ } else if (FPU == "neon") {
+ Features.push_back("+neon");
+ } else if (FPU == "none") {
+ Features.push_back("-fp-armv8");
+ Features.push_back("-crypto");
+ Features.push_back("-neon");
+ } else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
+// Handle -mhwdiv=.
+static void getARMHWDivFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef HWDiv = A->getValue();
+ if (HWDiv == "arm") {
+ Features.push_back("+hwdiv-arm");
+ Features.push_back("-hwdiv");
+ } else if (HWDiv == "thumb") {
+ Features.push_back("-hwdiv-arm");
+ Features.push_back("+hwdiv");
+ } else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") {
+ Features.push_back("+hwdiv-arm");
+ Features.push_back("+hwdiv");
+ } else if (HWDiv == "none") {
+ Features.push_back("-hwdiv-arm");
+ Features.push_back("-hwdiv");
+ } else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
// Handle -mfpu=.
//
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
// frontend target.
-static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
- ArgStringList &CmdArgs) {
+static void getARMFPUFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
StringRef FPU = A->getValue();
// Set the target features based on the FPU.
if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
// Disable any default FPU support.
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-vfp2");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-vfp3");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
+ Features.push_back("-vfp2");
+ Features.push_back("-vfp3");
+ Features.push_back("-neon");
} else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+vfp3");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+d16");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
+ Features.push_back("+vfp3");
+ Features.push_back("+d16");
+ Features.push_back("-neon");
} else if (FPU == "vfp") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+vfp2");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
+ Features.push_back("+vfp2");
+ Features.push_back("-neon");
} else if (FPU == "vfp3" || FPU == "vfpv3") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+vfp3");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
+ Features.push_back("+vfp3");
+ Features.push_back("-neon");
+ } else if (FPU == "fp-armv8") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("-neon");
+ Features.push_back("-crypto");
+ } else if (FPU == "neon-fp-armv8") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+neon");
+ Features.push_back("-crypto");
+ } else if (FPU == "crypto-neon-fp-armv8") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+neon");
+ Features.push_back("+crypto");
} else if (FPU == "neon") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+neon");
- } else
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
-// Handle -mfpmath=.
-static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
- ArgStringList &CmdArgs, StringRef CPU) {
- StringRef FPMath = A->getValue();
-
- // Set the target features based on the FPMath.
- if (FPMath == "neon") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+neonfp");
-
- if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
- CPU != "cortex-a8" && CPU != "cortex-a9" &&
- CPU != "cortex-a9-mp" && CPU != "cortex-a15")
- D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
-
- } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
- FPMath == "vfp4") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neonfp");
-
- // FIXME: Add warnings when disabling a feature not present for a given CPU.
+ Features.push_back("+neon");
+ } else if (FPU == "none") {
+ Features.push_back("-vfp2");
+ Features.push_back("-vfp3");
+ Features.push_back("-vfp4");
+ Features.push_back("-fp-armv8");
+ Features.push_back("-crypto");
+ Features.push_back("-neon");
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
@@ -697,6 +774,41 @@ static StringRef getARMFloatABI(const Driver &D,
return FloatABI;
}
+static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef FloatABI = getARMFloatABI(D, Args, Triple);
+ // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
+ // yet (it uses the -mfloat-abi and -msoft-float options), and it is
+ // stripped out by the ARM target.
+ // Use software floating point operations?
+ if (FloatABI == "soft")
+ Features.push_back("+soft-float");
+
+ // Use software floating point argument passing?
+ if (FloatABI != "hard")
+ Features.push_back("+soft-float-abi");
+
+ // Honor -mfpu=.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
+ getARMFPUFeatures(D, A, Args, Features);
+ if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ))
+ getARMHWDivFeatures(D, A, Args, Features);
+
+ // Setting -msoft-float effectively disables NEON because of the GCC
+ // implementation, although the same isn't true of VFP or VFP3.
+ if (FloatABI == "soft")
+ Features.push_back("-neon");
+
+ // En/disable crc
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc,
+ options::OPT_mnocrc)) {
+ if (A->getOption().matches(options::OPT_mcrc))
+ Features.push_back("+crc");
+ else
+ Features.push_back("-crc");
+ }
+}
void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs,
@@ -716,7 +828,8 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
} else if (Triple.isOSDarwin()) {
// The backend is hardwired to assume AAPCS for M-class processors, ensure
// the frontend matches that.
- if (StringRef(CPUName).startswith("cortex-m")) {
+ if (Triple.getEnvironment() == llvm::Triple::EABI ||
+ StringRef(CPUName).startswith("cortex-m")) {
ABIName = "aapcs";
} else {
ABIName = "apcs-gnu";
@@ -739,10 +852,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
- // Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(CPUName));
-
// Determine floating point ABI from the options & target defaults.
StringRef FloatABI = getARMFloatABI(D, Args, Triple);
if (FloatABI == "soft") {
@@ -763,42 +872,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("hard");
}
- // Set appropriate target features for floating point mode.
- //
- // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
- // yet (it uses the -mfloat-abi and -msoft-float options above), and it is
- // stripped out by the ARM target.
-
- // Use software floating point operations?
- if (FloatABI == "soft") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+soft-float");
- }
-
- // Use software floating point argument passing?
- if (FloatABI != "hard") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+soft-float-abi");
- }
-
- // Honor -mfpu=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
- addFPUArgs(D, A, Args, CmdArgs);
-
- // Honor -mfpmath=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
- addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
-
- // Setting -msoft-float effectively disables NEON because of the GCC
- // implementation, although the same isn't true of VFP or VFP3.
- if (FloatABI == "soft") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
- }
-
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
- if (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6)) {
+ if (!Triple.isiOS() || Triple.isOSVersionLT(6)) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-long-calls");
}
@@ -808,7 +884,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// The kext linker doesn't know how to deal with movw/movt.
CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-darwin-use-movt=0");
+ CmdArgs.push_back("-arm-use-movt=0");
}
// Setting -mno-global-merge disables the codegen global merge pass. Setting
@@ -823,39 +899,28 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
options::OPT_mno_implicit_float,
true))
CmdArgs.push_back("-no-implicit-float");
-}
-// Translate MIPS CPU name alias option to CPU name.
-static StringRef getMipsCPUFromAlias(const Arg &A) {
- if (A.getOption().matches(options::OPT_mips32))
- return "mips32";
- if (A.getOption().matches(options::OPT_mips32r2))
- return "mips32r2";
- if (A.getOption().matches(options::OPT_mips64))
- return "mips64";
- if (A.getOption().matches(options::OPT_mips64r2))
- return "mips64r2";
- llvm_unreachable("Unexpected option");
- return "";
+ // llvm does not support reserving registers in general. There is support
+ // for reserving r9 on ARM though (defined as a platform-specific register
+ // in ARM EABI).
+ if (Args.hasArg(options::OPT_ffixed_r9)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-reserve-r9");
+ }
}
// Get CPU and ABI names. They are not independent
// so we have to calculate them together.
static void getMipsCPUAndABI(const ArgList &Args,
- const ToolChain &TC,
+ const llvm::Triple &Triple,
StringRef &CPUName,
StringRef &ABIName) {
const char *DefMips32CPU = "mips32";
const char *DefMips64CPU = "mips64";
if (Arg *A = Args.getLastArg(options::OPT_march_EQ,
- options::OPT_mcpu_EQ,
- options::OPT_mips_CPUs_Group)) {
- if (A->getOption().matches(options::OPT_mips_CPUs_Group))
- CPUName = getMipsCPUFromAlias(*A);
- else
- CPUName = A->getValue();
- }
+ options::OPT_mcpu_EQ))
+ CPUName = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
@@ -869,7 +934,7 @@ static void getMipsCPUAndABI(const ArgList &Args,
// Setup default CPU and ABI names.
if (CPUName.empty() && ABIName.empty()) {
- switch (TC.getTriple().getArch()) {
+ switch (Triple.getArch()) {
default:
llvm_unreachable("Unexpected triple arch name");
case llvm::Triple::mips:
@@ -941,28 +1006,56 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
}
static void AddTargetFeature(const ArgList &Args,
- ArgStringList &CmdArgs,
- OptSpecifier OnOpt,
- OptSpecifier OffOpt,
+ std::vector<const char *> &Features,
+ OptSpecifier OnOpt, OptSpecifier OffOpt,
StringRef FeatureName) {
if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) {
- CmdArgs.push_back("-target-feature");
if (A->getOption().matches(OnOpt))
- CmdArgs.push_back(Args.MakeArgString("+" + FeatureName));
+ Features.push_back(Args.MakeArgString("+" + FeatureName));
else
- CmdArgs.push_back(Args.MakeArgString("-" + FeatureName));
+ Features.push_back(Args.MakeArgString("-" + FeatureName));
}
}
+static void getMIPSTargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef FloatABI = getMipsFloatABI(D, Args);
+ bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL;
+ if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) {
+ // FIXME: Note, this is a hack. We need to pass the selected float
+ // mode to the MipsTargetInfoBase to define appropriate macros there.
+ // Now it is the only method.
+ Features.push_back("+soft-float");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
+ if (StringRef(A->getValue()) == "2008")
+ Features.push_back("+nan2008");
+ }
+
+ AddTargetFeature(Args, Features, options::OPT_msingle_float,
+ options::OPT_mdouble_float, "single-float");
+ AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
+ "mips16");
+ AddTargetFeature(Args, Features, options::OPT_mmicromips,
+ options::OPT_mno_micromips, "micromips");
+ AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
+ "dsp");
+ AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
+ "dspr2");
+ AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
+ "msa");
+ AddTargetFeature(Args, Features, options::OPT_mfp64, options::OPT_mfp32,
+ "fp64");
+}
+
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
-
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(CPUName.data());
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
@@ -977,12 +1070,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
- // FIXME: Note, this is a hack. We need to pass the selected float
- // mode to the MipsTargetInfoBase to define appropriate macros there.
- // Now it is the only method.
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+soft-float");
-
if (FloatABI == "hard" && IsMips16) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mips16-hard-float");
@@ -995,22 +1082,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back("hard");
}
- AddTargetFeature(Args, CmdArgs,
- options::OPT_msingle_float, options::OPT_mdouble_float,
- "single-float");
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mips16, options::OPT_mno_mips16,
- "mips16");
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mmicromips, options::OPT_mno_micromips,
- "micromips");
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mdsp, options::OPT_mno_dsp,
- "dsp");
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mdspr2, options::OPT_mno_dspr2,
- "dspr2");
-
if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
if (A->getOption().matches(options::OPT_mxgot)) {
CmdArgs.push_back("-mllvm");
@@ -1018,6 +1089,22 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
}
}
+ if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1,
+ options::OPT_mno_ldc1_sdc1)) {
+ if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mno-ldc1-sdc1");
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division,
+ options::OPT_mno_check_zero_division)) {
+ if (A->getOption().matches(options::OPT_mno_check_zero_division)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mno-check-zero-division");
+ }
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
@@ -1081,62 +1168,48 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("pwr7", "pwr7")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
+ .Case("powerpc64le", "ppc64le")
.Default("");
}
return "";
}
-void Clang::AddPPCTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- std::string TargetCPUName = getPPCTargetCPU(Args);
-
- // LLVM may default to generating code for the native CPU,
- // but, like gcc, we default to a more generic option for
- // each architecture. (except on Darwin)
- llvm::Triple Triple = getToolChain().getTriple();
- if (TargetCPUName.empty() && !Triple.isOSDarwin()) {
- if (Triple.getArch() == llvm::Triple::ppc64)
- TargetCPUName = "ppc64";
- else
- TargetCPUName = "ppc";
- }
-
- if (!TargetCPUName.empty()) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(TargetCPUName.c_str()));
- }
-
- // Allow override of the Altivec feature.
- AddTargetFeature(Args, CmdArgs,
- options::OPT_faltivec, options::OPT_fno_altivec,
- "altivec");
+static void getPPCTargetFeatures(const ArgList &Args,
+ std::vector<const char *> &Features) {
+ for (arg_iterator it = Args.filtered_begin(options::OPT_m_ppc_Features_Group),
+ ie = Args.filtered_end();
+ it != ie; ++it) {
+ StringRef Name = (*it)->getOption().getName();
+ (*it)->claim();
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mfprnd, options::OPT_mno_fprnd,
- "fprnd");
+ // Skip over "-m".
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
- // Note that gcc calls this mfcrf and LLVM calls this mfocrf.
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mmfcrf, options::OPT_mno_mfcrf,
- "mfocrf");
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
- AddTargetFeature(Args, CmdArgs,
- options::OPT_mpopcntd, options::OPT_mno_popcntd,
- "popcntd");
+ // Note that gcc calls this mfcrf and LLVM calls this mfocrf so we
+ // pass the correct option to the backend while calling the frontend
+ // option the same.
+ // TODO: Change the LLVM backend option maybe?
+ if (Name == "mfcrf")
+ Name = "mfocrf";
- // It is really only possible to turn qpx off because turning qpx on is tied
- // to using the a2q CPU.
- if (Args.hasFlag(options::OPT_mno_qpx, options::OPT_mqpx, false)) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-qpx");
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
+
+ // Altivec is a bit weird, allow overriding of the Altivec feature here.
+ AddTargetFeature(Args, Features, options::OPT_faltivec,
+ options::OPT_fno_altivec, "altivec");
}
/// Get the (LLVM) name of the R600 gpu we are targeting.
static std::string getR600TargetGPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- std::string GPUName = A->getValue();
+ const char *GPUName = A->getValue();
return llvm::StringSwitch<const char *>(GPUName)
.Cases("rv630", "rv635", "r600")
.Cases("rv610", "rv620", "rs780", "rs880")
@@ -1145,27 +1218,27 @@ static std::string getR600TargetGPU(const ArgList &Args) {
.Cases("sumo", "sumo2", "sumo")
.Case("hemlock", "cypress")
.Case("aruba", "cayman")
- .Default(GPUName.c_str());
+ .Default(GPUName);
}
return "";
}
-void Clang::AddR600TargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- std::string TargetGPUName = getR600TargetGPU(Args);
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(TargetGPUName.c_str()));
+static void getSparcTargetFeatures(const ArgList &Args,
+ std::vector<const char *> Features) {
+ bool SoftFloatABI = true;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
+ if (A->getOption().matches(options::OPT_mhard_float))
+ SoftFloatABI = false;
+ }
+ if (SoftFloatABI)
+ Features.push_back("+soft-float");
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(A->getValue());
- }
-
// Select the float ABI as determined by -msoft-float, -mhard-float, and
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
@@ -1178,13 +1251,9 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
- switch (getToolChain().getTriple().getOS()) {
- default:
- // Assume "soft", but warn the user we are guessing.
- FloatABI = "soft";
- D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
- break;
- }
+ // Assume "soft", but warn the user we are guessing.
+ FloatABI = "soft";
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
}
if (FloatABI == "soft") {
@@ -1192,19 +1261,27 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
//
// FIXME: This changes CPP defines, we need -target-soft-float.
CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+soft-float");
} else {
assert(FloatABI == "hard" && "Invalid float abi!");
CmdArgs.push_back("-mhard-float");
}
}
+static const char *getSystemZTargetCPU(const ArgList &Args) {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+ return "z10";
+}
+
static const char *getX86TargetCPU(const ArgList &Args,
const llvm::Triple &Triple) {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue()) != "native")
+ if (StringRef(A->getValue()) != "native") {
+ if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h")
+ return "core-avx2";
+
return A->getValue();
+ }
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
@@ -1225,30 +1302,128 @@ static const char *getX86TargetCPU(const ArgList &Args,
bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
// FIXME: Need target hooks.
- if (Triple.isOSDarwin())
+ if (Triple.isOSDarwin()) {
+ if (Triple.getArchName() == "x86_64h")
+ return "core-avx2";
return Is64Bit ? "core2" : "yonah";
+ }
+
+ // All x86 devices running Android have core2 as their common
+ // denominator. This makes a better choice than pentium4.
+ if (Triple.getEnvironment() == llvm::Triple::Android)
+ return "core2";
// Everything else goes to x86-64 in 64-bit mode.
if (Is64Bit)
return "x86-64";
- if (Triple.getOSName().startswith("haiku"))
- return "i586";
- if (Triple.getOSName().startswith("openbsd"))
+ switch (Triple.getOS()) {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
return "i486";
- if (Triple.getOSName().startswith("bitrig"))
+ case llvm::Triple::Haiku:
+ return "i586";
+ case llvm::Triple::Bitrig:
return "i686";
- if (Triple.getOSName().startswith("freebsd"))
- return "i486";
- if (Triple.getOSName().startswith("netbsd"))
- return "i486";
- // All x86 devices running Android have core2 as their common
- // denominator. This makes a better choice than pentium4.
- if (Triple.getEnvironment() == llvm::Triple::Android)
- return "core2";
+ default:
+ // Fallback to p4.
+ return "pentium4";
+ }
+}
+
+static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
+ switch(T.getArch()) {
+ default:
+ return "";
- // Fallback to p4.
- return "pentium4";
+ case llvm::Triple::aarch64:
+ return getAArch64TargetCPU(Args, T);
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ return getARMTargetCPU(Args, T);
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, T, CPUName, ABIName);
+ return CPUName;
+ }
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le: {
+ std::string TargetCPUName = getPPCTargetCPU(Args);
+ // LLVM may default to generating code for the native CPU,
+ // but, like gcc, we default to a more generic option for
+ // each architecture. (except on Darwin)
+ if (TargetCPUName.empty() && !T.isOSDarwin()) {
+ if (T.getArch() == llvm::Triple::ppc64)
+ TargetCPUName = "ppc64";
+ else if (T.getArch() == llvm::Triple::ppc64le)
+ TargetCPUName = "ppc64le";
+ else
+ TargetCPUName = "ppc";
+ }
+ return TargetCPUName;
+ }
+
+ case llvm::Triple::sparc:
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+ return "";
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return getX86TargetCPU(Args, T);
+
+ case llvm::Triple::hexagon:
+ return "hexagon" + toolchains::Hexagon_TC::GetTargetCPU(Args).str();
+
+ case llvm::Triple::systemz:
+ return getSystemZTargetCPU(Args);
+
+ case llvm::Triple::r600:
+ return getR600TargetGPU(Args);
+ }
+}
+
+static void getX86TargetFeatures(const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ if (Triple.getArchName() == "x86_64h") {
+ // x86_64h implies quite a few of the more modern subtarget features
+ // for Haswell class CPUs, but not all of them. Opt-out of a few.
+ Features.push_back("-rdrnd");
+ Features.push_back("-aes");
+ Features.push_back("-pclmul");
+ Features.push_back("-rtm");
+ Features.push_back("-hle");
+ Features.push_back("-fsgsbase");
+ }
+
+ // Now add any that the user explicitly requested on the command line,
+ // which may override the defaults.
+ for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
+ ie = Args.filtered_end();
+ it != ie; ++it) {
+ StringRef Name = (*it)->getOption().getName();
+ (*it)->claim();
+
+ // Skip over "-m".
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
+
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
+
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
}
void Clang::AddX86TargetArgs(const ArgList &Args,
@@ -1274,45 +1449,6 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
if (NoImplicitFloat)
CmdArgs.push_back("-no-implicit-float");
-
- if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(CPUName);
- }
-
- // The required algorithm here is slightly strange: the options are applied
- // in order (so -mno-sse -msse2 disables SSE3), but any option that gets
- // directly overridden later is ignored (so "-mno-sse -msse2 -mno-sse2 -msse"
- // is equivalent to "-mno-sse2 -msse"). The -cc1 handling deals with the
- // former correctly, but not the latter; handle directly-overridden
- // attributes here.
- llvm::StringMap<unsigned> PrevFeature;
- std::vector<const char*> Features;
- for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
- ie = Args.filtered_end(); it != ie; ++it) {
- StringRef Name = (*it)->getOption().getName();
- (*it)->claim();
-
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
-
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
-
- unsigned& Prev = PrevFeature[Name];
- if (Prev)
- Features[Prev - 1] = 0;
- Prev = Features.size() + 1;
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
- for (unsigned i = 0; i < Features.size(); i++) {
- if (Features[i]) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Features[i]);
- }
- }
}
static inline bool HasPICArg(const ArgList &Args) {
@@ -1339,12 +1475,6 @@ static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) {
void Clang::AddHexagonTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- llvm::Triple Triple = getToolChain().getTriple();
-
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(
- "hexagon"
- + toolchains::Hexagon_TC::GetTargetCPU(Args)));
CmdArgs.push_back("-fno-signed-char");
CmdArgs.push_back("-mqdsp6-compat");
CmdArgs.push_back("-Wreturn-type");
@@ -1366,6 +1496,70 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
CmdArgs.push_back ("-machine-sink-split=0");
}
+static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<const char *> &Features) {
+ // Honor -mfpu=.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
+ getAArch64FPUFeatures(D, A, Args, Features);
+}
+
+static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs) {
+ std::vector<const char *> Features;
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ getMIPSTargetFeatures(D, Args, Features);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ getARMTargetFeatures(D, Triple, Args, Features);
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ getPPCTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::sparc:
+ getSparcTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ getAArch64TargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ getX86TargetFeatures(Triple, Args, Features);
+ break;
+ }
+
+ // Find the last of each feature.
+ llvm::StringMap<unsigned> LastOpt;
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ const char *Name = Features[I];
+ assert(Name[0] == '-' || Name[0] == '+');
+ LastOpt[Name + 1] = I;
+ }
+
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ // If this feature was overridden, ignore it.
+ const char *Name = Features[I];
+ llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name + 1);
+ assert(LastI != LastOpt.end());
+ unsigned Last = LastI->second;
+ if (Last != I)
+ continue;
+
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Name);
+ }
+}
+
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -1532,117 +1726,75 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
-SanitizerArgs::SanitizerArgs(const ToolChain &TC, const ArgList &Args)
- : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
- AsanZeroBaseShadow(false) {
- unsigned AllKinds = 0; // All kinds of sanitizers that were turned on
- // at least once (possibly, disabled further).
- const Driver &D = TC.getDriver();
- for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
- unsigned Add, Remove;
- if (!parse(D, Args, *I, Add, Remove, true))
- continue;
- (*I)->claim();
- Kind |= Add;
- Kind &= ~Remove;
- AllKinds |= Add;
- }
+static void CollectArgsForIntegratedAssembler(Compilation &C,
+ const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const Driver &D) {
+ if (UseRelaxAll(C, Args))
+ CmdArgs.push_back("-mrelax-all");
- UbsanTrapOnError =
- Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
- Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, false);
+ // When passing -I arguments to the assembler we sometimes need to
+ // unconditionally take the next argument. For example, when parsing
+ // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
+ // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo'
+ // arg after parsing the '-I' arg.
+ bool TakeNextArg = false;
- if (Args.hasArg(options::OPT_fcatch_undefined_behavior) &&
- !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, true)) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fcatch-undefined-behavior"
- << "-fno-sanitize-undefined-trap-on-error";
- }
+ // When using an integrated assembler, translate -Wa, and -Xassembler
+ // options.
+ for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA,
+ options::OPT_Xassembler),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ A->claim();
- // Warn about undefined sanitizer options that require runtime support.
- if (UbsanTrapOnError && notAllowedWithTrap()) {
- if (Args.hasArg(options::OPT_fcatch_undefined_behavior))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NotAllowedWithTrap)
- << "-fcatch-undefined-behavior";
- else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error,
- false))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NotAllowedWithTrap)
- << "-fsanitize-undefined-trap-on-error";
- }
-
- // Only one runtime library can be used at once.
- bool NeedsAsan = needsAsanRt();
- bool NeedsTsan = needsTsanRt();
- bool NeedsMsan = needsMsanRt();
- if (NeedsAsan && NeedsTsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsAsanRt)
- << lastArgumentForKind(D, Args, NeedsTsanRt);
- if (NeedsAsan && NeedsMsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsAsanRt)
- << lastArgumentForKind(D, Args, NeedsMsanRt);
- if (NeedsTsan && NeedsMsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsTsanRt)
- << lastArgumentForKind(D, Args, NeedsMsanRt);
-
- // If -fsanitize contains extra features of ASan, it should also
- // explicitly contain -fsanitize=address (probably, turned off later in the
- // command line).
- if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0)
- D.Diag(diag::warn_drv_unused_sanitizer)
- << lastArgumentForKind(D, Args, AddressFull)
- << "-fsanitize=address";
-
- // Parse -f(no-)sanitize-blacklist options.
- if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
- options::OPT_fno_sanitize_blacklist)) {
- if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
- std::string BLPath = BLArg->getValue();
- bool BLExists = false;
- if (!llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
- BlacklistFile = BLPath;
- else
- D.Diag(diag::err_drv_no_such_file) << BLPath;
- }
- } else {
- // If no -fsanitize-blacklist option is specified, try to look up for
- // blacklist in the resource directory.
- std::string BLPath;
- bool BLExists = false;
- if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
- !llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
- BlacklistFile = BLPath;
- }
-
- // Parse -f(no-)sanitize-memory-track-origins options.
- if (NeedsMsan)
- MsanTrackOrigins =
- Args.hasFlag(options::OPT_fsanitize_memory_track_origins,
- options::OPT_fno_sanitize_memory_track_origins,
- /* Default */false);
-
- // Parse -f(no-)sanitize-address-zero-base-shadow options.
- if (NeedsAsan) {
- bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android);
- bool ZeroBaseShadowDefault = IsAndroid;
- AsanZeroBaseShadow =
- Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
- options::OPT_fno_sanitize_address_zero_base_shadow,
- ZeroBaseShadowDefault);
- // Zero-base shadow is a requirement on Android.
- if (IsAndroid && !AsanZeroBaseShadow) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fno-sanitize-address-zero-base-shadow"
- << lastArgumentForKind(D, Args, Address);
+ for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
+ StringRef Value = A->getValue(i);
+ if (TakeNextArg) {
+ CmdArgs.push_back(Value.data());
+ TakeNextArg = false;
+ continue;
+ }
+
+ if (Value == "-force_cpusubtype_ALL") {
+ // Do nothing, this is the default and we don't support anything else.
+ } else if (Value == "-L") {
+ CmdArgs.push_back("-msave-temp-labels");
+ } else if (Value == "--fatal-warnings") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-fatal-assembler-warnings");
+ } else if (Value == "--noexecstack") {
+ CmdArgs.push_back("-mnoexecstack");
+ } else if (Value.startswith("-I")) {
+ CmdArgs.push_back(Value.data());
+ // We need to consume the next argument if the current arg is a plain
+ // -I. The next arg will be the include directory.
+ if (Value == "-I")
+ TakeNextArg = true;
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
}
- }
+}
+
+static void addProfileRTLinux(
+ const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
+ if (!(Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)))
+ return;
+
+ // The profile runtime is located in the Linux library directory and has name
+ // "libclang_rt.profile-<ArchName>.a".
+ SmallString<128> LibProfile(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(
+ LibProfile, "lib", "linux",
+ Twine("libclang_rt.profile-") + TC.getArchName() + ".a");
+
+ CmdArgs.push_back(Args.MakeArgString(LibProfile));
}
static void addSanitizerRTLinkFlagsLinux(
@@ -1673,6 +1825,7 @@ static void addSanitizerRTLinkFlagsLinux(
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lrt");
CmdArgs.push_back("-ldl");
+ CmdArgs.push_back("-lm");
// If possible, use a dynamic symbols file to export the symbols from the
// runtime library. If we can't do so, use -export-dynamic instead to export
@@ -1690,16 +1843,15 @@ static void addSanitizerRTLinkFlagsLinux(
/// This needs to be called before we add the C run-time (malloc, etc).
static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- if(TC.getTriple().getEnvironment() == llvm::Triple::Android) {
+ if (TC.getTriple().getEnvironment() == llvm::Triple::Android) {
SmallString<128> LibAsan(TC.getDriver().ResourceDir);
llvm::sys::path::append(LibAsan, "lib", "linux",
(Twine("libclang_rt.asan-") +
TC.getArchName() + "-android.so"));
CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan));
} else {
- if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true);
- }
}
}
@@ -1707,18 +1859,24 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
/// This needs to be called before we add the C run-time (malloc, etc).
static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true);
- }
}
/// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true);
- }
+}
+
+/// If LeakSanitizer is enabled, add appropriate linker flags (Linux).
+/// This needs to be called before we add the C run-time (malloc, etc).
+static void addLsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!Args.hasArg(options::OPT_shared))
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "lsan", true);
}
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
@@ -1726,9 +1884,6 @@ static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool IsCXX,
bool HasOtherSanitizerRt) {
- if (Args.hasArg(options::OPT_shared))
- return;
-
// Need a copy of sanitizer_common. This could come from another sanitizer
// runtime; if we're not including one, include our own copy.
if (!HasOtherSanitizerRt)
@@ -1742,22 +1897,42 @@ static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false);
}
+static void addDfsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!Args.hasArg(options::OPT_shared))
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true);
+}
+
+static bool shouldUseFramePointerForTarget(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ // Don't use a frame pointer on linux if optimizing for certain targets.
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::systemz:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (Triple.isOSLinux())
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ if (!A->getOption().matches(options::OPT_O0))
+ return false;
+ return true;
+ case llvm::Triple::xcore:
+ return false;
+ default:
+ return true;
+ }
+}
+
static bool shouldUseFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
return A->getOption().matches(options::OPT_fno_omit_frame_pointer);
- // Don't use a frame pointer on linux x86 and x86_64 if optimizing.
- if ((Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::x86) &&
- Triple.getOS() == llvm::Triple::Linux) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- if (!A->getOption().matches(options::OPT_O0))
- return false;
- }
-
- return true;
+ return shouldUseFramePointerForTarget(Args, Triple);
}
static bool shouldUseLeafFramePointer(const ArgList &Args,
@@ -1766,38 +1941,11 @@ static bool shouldUseLeafFramePointer(const ArgList &Args,
options::OPT_momit_leaf_frame_pointer))
return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
- // Don't use a leaf frame pointer on linux x86 and x86_64 if optimizing.
- if ((Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::x86) &&
- Triple.getOS() == llvm::Triple::Linux) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- if (!A->getOption().matches(options::OPT_O0))
- return false;
- }
-
- return true;
+ return shouldUseFramePointerForTarget(Args, Triple);
}
-/// If the PWD environment variable is set, add a CC1 option to specify the
-/// debug compilation directory.
+/// Add a CC1 option to specify the debug compilation directory.
static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
- struct stat StatPWDBuf, StatDotBuf;
-
- const char *pwd = ::getenv("PWD");
- if (!pwd)
- return;
-
- if (llvm::sys::path::is_absolute(pwd) &&
- stat(pwd, &StatPWDBuf) == 0 &&
- stat(".", &StatDotBuf) == 0 &&
- StatPWDBuf.st_ino == StatDotBuf.st_ino &&
- StatPWDBuf.st_dev == StatDotBuf.st_dev) {
- CmdArgs.push_back("-fdebug-compilation-dir");
- CmdArgs.push_back(Args.MakeArgString(pwd));
- return;
- }
-
- // Fall back to using getcwd.
SmallString<128> cwd;
if (!llvm::sys::fs::current_path(cwd)) {
CmdArgs.push_back("-fdebug-compilation-dir");
@@ -1854,6 +2002,37 @@ static bool isOptimizationLevelFast(const ArgList &Args) {
return false;
}
+/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
+static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ return true;
+
+ if (A->getOption().matches(options::OPT_O0))
+ return false;
+
+ assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag");
+
+ // Vectorize -Os.
+ StringRef S(A->getValue());
+ if (S == "s")
+ return true;
+
+ // Don't vectorize -Oz.
+ if (S == "z")
+ return false;
+
+ unsigned OptLevel = 0;
+ if (S.getAsInteger(10, OptLevel))
+ return false;
+
+ return OptLevel > 1;
+ }
+
+ return false;
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -1896,35 +2075,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
- if (UseRelaxAll(C, Args))
- CmdArgs.push_back("-mrelax-all");
-
- // When using an integrated assembler, translate -Wa, and -Xassembler
- // options.
- for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA,
- options::OPT_Xassembler),
- ie = Args.filtered_end(); it != ie; ++it) {
- const Arg *A = *it;
- A->claim();
-
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
- StringRef Value = A->getValue(i);
-
- if (Value == "-force_cpusubtype_ALL") {
- // Do nothing, this is the default and we don't support anything else.
- } else if (Value == "-L") {
- CmdArgs.push_back("-msave-temp-labels");
- } else if (Value == "--fatal-warnings") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-fatal-assembler-warnings");
- } else if (Value == "--noexecstack") {
- CmdArgs.push_back("-mnoexecstack");
- } else {
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
- }
+ CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);
// Also ignore explicit -force_cpusubtype_ALL option.
(void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
@@ -2071,7 +2222,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Inroduce a Darwin-specific hack. If the default is PIC but the flags
+ // Introduce a Darwin-specific hack. If the default is PIC but the flags
// specified while enabling PIC enabled level 1 PIC, just force it back to
// level 2 PIC instead. This matches the behavior of Darwin GCC (based on my
// informal testing).
@@ -2082,8 +2233,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// PIC or PIE options above, if these show up, PIC is disabled.
llvm::Triple Triple(TripleStr);
if (KernelOrKext &&
- (Triple.getOS() != llvm::Triple::IOS ||
- Triple.isOSVersionLT(6)))
+ (!Triple.isiOS() || Triple.isOSVersionLT(6)))
PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
PIC = PIE = false;
@@ -2134,6 +2284,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
+ options::OPT_freg_struct_return)) {
+ if (getToolChain().getArch() != llvm::Triple::x86) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getToolChain().getTriple().str();
+ } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
+ CmdArgs.push_back("-fpcc-struct-return");
+ } else {
+ assert(A->getOption().matches(options::OPT_freg_struct_return));
+ CmdArgs.push_back("-freg-struct-return");
+ }
+ }
+
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-mrtd");
@@ -2149,11 +2312,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast :
options::OPT_fstrict_aliasing;
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
- options::OPT_fno_strict_aliasing,
- getToolChain().IsStrictAliasingDefault()))
+ options::OPT_fno_strict_aliasing, true))
CmdArgs.push_back("-relaxed-aliasing");
- if (Args.hasArg(options::OPT_fstruct_path_tbaa))
- CmdArgs.push_back("-struct-path-tbaa");
+ if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
+ options::OPT_fno_struct_path_tbaa))
+ CmdArgs.push_back("-no-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
@@ -2201,8 +2364,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
options::OPT_fno_fast_math,
options::OPT_fmath_errno,
- options::OPT_fno_math_errno))
- MathErrno = A->getOption().getID() == 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");
@@ -2349,8 +2521,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
- // Add target specific cpu and features flags.
- switch(getToolChain().getTriple().getArch()) {
+ // Add the target cpu
+ std::string ETripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
+ llvm::Triple ETriple(ETripleStr);
+ std::string CPU = getCPUName(Args, ETriple);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
+ CmdArgs.push_back("-mfpmath");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ // Add the target features
+ getTargetFeatures(D, ETriple, Args, CmdArgs);
+
+ // Add target specific flags.
+ switch(getToolChain().getArch()) {
default:
break;
@@ -2366,15 +2555,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AddMIPSTargetArgs(Args, CmdArgs);
break;
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- AddPPCTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::r600:
- AddR600TargetArgs(Args, CmdArgs);
- break;
-
case llvm::Triple::sparc:
AddSparcTargetArgs(Args, CmdArgs);
break;
@@ -2389,7 +2569,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
-
+ // Add clang-cl arguments.
+ if (getToolChain().getDriver().IsCLMode())
+ AddClangCLArgs(Args, CmdArgs);
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
@@ -2407,7 +2589,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Arg *Unsupported;
if (types::isCXX(InputType) &&
getToolChain().getTriple().isOSDarwin() &&
- getToolChain().getTriple().getArch() == llvm::Triple::x86) {
+ 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)
@@ -2437,9 +2619,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
if (A->getOption().matches(options::OPT_gline_tables_only))
CmdArgs.push_back("-gline-tables-only");
+ else if (A->getOption().matches(options::OPT_gdwarf_2))
+ CmdArgs.push_back("-gdwarf-2");
+ else if (A->getOption().matches(options::OPT_gdwarf_3))
+ CmdArgs.push_back("-gdwarf-3");
+ else if (A->getOption().matches(options::OPT_gdwarf_4))
+ CmdArgs.push_back("-gdwarf-4");
else if (!A->getOption().matches(options::OPT_g0) &&
- !A->getOption().matches(options::OPT_ggdb0))
- CmdArgs.push_back("-g");
+ !A->getOption().matches(options::OPT_ggdb0)) {
+ // Default is dwarf-2 for darwin.
+ if (getToolChain().getTriple().isOSDarwin())
+ CmdArgs.push_back("-gdwarf-2");
+ else
+ CmdArgs.push_back("-g");
+ }
}
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
@@ -2447,16 +2640,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_gcolumn_info))
CmdArgs.push_back("-dwarf-column-info");
+ // FIXME: Move backend command line options to the module.
// -gsplit-dwarf should turn on -g and enable the backend dwarf
// splitting and extraction.
// FIXME: Currently only works on Linux.
- if (getToolChain().getTriple().getOS() == llvm::Triple::Linux &&
+ if (getToolChain().getTriple().isOSLinux() &&
Args.hasArg(options::OPT_gsplit_dwarf)) {
CmdArgs.push_back("-g");
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-split-dwarf=Enable");
}
+ // -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");
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_fdebug_types_section);
+
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -2475,12 +2677,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-coverage-file");
SmallString<128> CoverageFilename(Output.getFilename());
if (llvm::sys::path::is_relative(CoverageFilename.str())) {
- if (const char *pwd = ::getenv("PWD")) {
- if (llvm::sys::path::is_absolute(pwd)) {
- SmallString<128> Pwd(pwd);
- llvm::sys::path::append(Pwd, CoverageFilename.str());
- CoverageFilename.swap(Pwd);
- }
+ SmallString<128> Pwd;
+ if (!llvm::sys::fs::current_path(Pwd)) {
+ llvm::sys::path::append(Pwd, CoverageFilename.str());
+ CoverageFilename.swap(Pwd);
}
}
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
@@ -2505,7 +2705,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)) {
+ 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)) {
@@ -2529,6 +2729,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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)) {
@@ -2540,14 +2744,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
- options::OPT_objcmt_migrate_subscripting)) {
+ 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_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_white_list_dir_path);
}
// Add preprocessing options like -I, -D, etc. if we are using the
@@ -2563,16 +2785,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// preprocessed inputs and configure concludes that -fPIC is not supported.
Args.ClaimAllArgs(options::OPT_D);
- // Manually translate -O to -O2 and -O4 to -O3; let clang reject
- // others.
+ // Manually translate -O4 to -O3; let clang reject others.
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- if (A->getOption().matches(options::OPT_O4))
+ if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
- else if (A->getOption().matches(options::OPT_O) &&
- A->getValue()[0] == '\0')
- CmdArgs.push_back("-O2");
- else
+ D.Diag(diag::warn_O4_is_O3);
+ } else {
A->render(Args, CmdArgs);
+ }
}
// Don't warn about unused -flto. This can happen when we're preprocessing or
@@ -2586,7 +2806,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_w);
// Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
- // (-ansi is equivalent to -std=c89).
+ // (-ansi is equivalent to -std=c89 or -std=c++98).
//
// If a std is supplied, only add -trigraphs if it follows the
// option.
@@ -2619,13 +2839,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
- // Map the bizarre '-Wwrite-strings' flag to a more sensible
- // '-fconst-strings'; this better indicates its actual behavior.
- if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings,
- false)) {
- // For perfect compatibility with GCC, we do this even in the presence of
- // '-w'. This flag names something other than a warning for GCC.
- CmdArgs.push_back("-fconst-strings");
+ // GCC's behavior for -Wwrite-strings is a bit strange:
+ // * In C, this "warning flag" changes the types of string literals from
+ // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning
+ // for the discarded qualifier.
+ // * In C++, this is just a normal warning flag.
+ //
+ // Implementing this warning correctly in C is hard, so we follow GCC's
+ // behavior for now. FIXME: Directly diagnose uses of a string literal as
+ // a non-const char* in C, rather than using this crude hack.
+ if (!types::isCXX(InputType)) {
+ DiagnosticsEngine::Level DiagLevel = D.getDiags().getDiagnosticLevel(
+ diag::warn_deprecated_string_literal_conversion_c, SourceLocation());
+ if (DiagLevel > DiagnosticsEngine::Ignored)
+ CmdArgs.push_back("-fconst-strings");
}
// GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
@@ -2663,11 +2890,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
+ CmdArgs.push_back("-foperator-arrow-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
CmdArgs.push_back("-fconstexpr-depth");
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
+ CmdArgs.push_back("-fconstexpr-steps");
+ CmdArgs.push_back(A->getValue());
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
CmdArgs.push_back("-fbracket-depth");
CmdArgs.push_back(A->getValue());
@@ -2758,11 +2995,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
- Args.AddLastArg(CmdArgs, options::OPT_faltivec);
+ // AltiVec language extensions aren't relevant for assembling.
+ if (!isa<PreprocessJobAction>(JA) ||
+ Output.getType() != types::TY_PP_Asm)
+ Args.AddLastArg(CmdArgs, options::OPT_faltivec);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
- SanitizerArgs Sanitize(getToolChain(), Args);
+ const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
Sanitize.addArgs(Args, CmdArgs);
if (!Args.hasFlag(options::OPT_fsanitize_recover,
@@ -2777,10 +3017,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Report an error for -faltivec on anything other than PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
- if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
- getToolChain().getTriple().getArch() == llvm::Triple::ppc64))
+ if (!(getToolChain().getArch() == llvm::Triple::ppc ||
+ getToolChain().getArch() == llvm::Triple::ppc64 ||
+ getToolChain().getArch() == llvm::Triple::ppc64le))
D.Diag(diag::err_drv_argument_only_allowed_with)
- << A->getAsString(Args) << "ppc/ppc64";
+ << A->getAsString(Args) << "ppc/ppc64/ppc64le";
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
@@ -2821,8 +3062,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
}
+
+ if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
+ options::OPT_fno_reroll_loops))
+ if (A->getOption().matches(options::OPT_freroll_loops))
+ CmdArgs.push_back("-freroll-loops");
+
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
- Args.AddLastArg(CmdArgs, options::OPT_funroll_loops);
+ Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
+ options::OPT_fno_unroll_loops);
Args.AddLastArg(CmdArgs, options::OPT_pthread);
@@ -2875,13 +3123,39 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
// -mkernel implies -mstrict-align; don't add the redundant option.
- if (Args.hasArg(options::OPT_mstrict_align) && !KernelOrKext) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-strict-align");
+ if (!KernelOrKext) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access)) {
+ if (A->getOption().matches(options::OPT_mno_unaligned_access)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-strict-align");
+ } else {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-no-strict-align");
+ }
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
+ options::OPT_mno_restrict_it)) {
+ if (A->getOption().matches(options::OPT_mrestrict_it)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-restrict-it");
+ } else {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-no-restrict-it");
+ }
}
// Forward -f options with positive and negative forms; we translate
// these by hand.
+ if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) {
+ StringRef fname = A->getValue();
+ if (!llvm::sys::fs::exists(fname))
+ D.Diag(diag::err_drv_no_such_file) << fname;
+ else
+ A->render(Args, CmdArgs);
+ }
if (Args.hasArg(options::OPT_mkernel)) {
if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType))
@@ -2925,6 +3199,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // -fmodule-maps enables module map processing (off by default) for header
+ // checking. It is implied by -fmodules.
+ if (Args.hasFlag(options::OPT_fmodule_maps, options::OPT_fno_module_maps,
+ false)) {
+ CmdArgs.push_back("-fmodule-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");
+ }
+
+ // -fmodule-name specifies the module that is currently being built (or
+ // used for header checking by -fmodule-maps).
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_name)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
+ // -fmodule-map-file can be used to specify a file containing module
+ // definitions.
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
// If a module path was provided, pass it along. Otherwise, use a temporary
// directory.
if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) {
@@ -2980,7 +3283,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fshort-enums=0 is default for all architectures except Hexagon.
if (Args.hasFlag(options::OPT_fshort_enums,
options::OPT_fno_short_enums,
- getToolChain().getTriple().getArch() ==
+ getToolChain().getArch() ==
llvm::Triple::hexagon))
CmdArgs.push_back("-fshort-enums");
@@ -2995,11 +3298,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-threadsafe-statics");
// -fuse-cxa-atexit is default.
- if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
- options::OPT_fno_use_cxa_atexit,
- getToolChain().getTriple().getOS() != llvm::Triple::Cygwin &&
- getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 &&
- getToolChain().getTriple().getArch() != llvm::Triple::hexagon) ||
+ if (!Args.hasFlag(
+ options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
+ getToolChain().getTriple().getOS() != llvm::Triple::Cygwin &&
+ getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 &&
+ getToolChain().getArch() != llvm::Triple::hexagon &&
+ getToolChain().getArch() != llvm::Triple::xcore) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
@@ -3017,13 +3321,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
true))))
CmdArgs.push_back("-fms-compatibility");
- // -fmsc-version=1300 is default.
+ // -fmsc-version=1700 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32) ||
Args.hasArg(options::OPT_fmsc_version)) {
StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version);
if (msc_ver.empty())
- CmdArgs.push_back("-fmsc-version=1300");
+ CmdArgs.push_back("-fmsc-version=1700");
else
CmdArgs.push_back(Args.MakeArgString("-fmsc-version=" + msc_ver));
}
@@ -3061,12 +3365,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
// -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
- // legacy is the default.
- if (objcRuntime.isNonFragile()) {
+ // legacy is the default. Next runtime is always legacy dispatch and
+ // -fno-objc-legacy-dispatch gets ignored silently.
+ if (objcRuntime.isNonFragile() && !objcRuntime.isNeXTFamily()) {
if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
options::OPT_fno_objc_legacy_dispatch,
objcRuntime.isLegacyDispatchDefaultForArch(
- getToolChain().getTriple().getArch()))) {
+ getToolChain().getArch()))) {
if (getToolChain().UseObjCMixedDispatch())
CmdArgs.push_back("-fobjc-dispatch-method=mixed");
else
@@ -3074,12 +3379,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // -fobjc-default-synthesize-properties=1 is default. This only has an effect
- // if the nonfragile objc abi is used.
- if (getToolChain().IsObjCDefaultSynthPropertiesDefault()) {
- CmdArgs.push_back("-fobjc-default-synthesize-properties");
- }
-
+ // When ObjectiveC legacy runtime is in effect on MacOSX,
+ // turn on the option to do Array/Dictionary subscripting
+ // by default.
+ if (getToolChain().getTriple().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");
@@ -3159,16 +3468,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar))
A->render(Args, CmdArgs);
- // -fno-pascal-strings is default, only pass non-default. If the tool chain
- // happened to translate to -mpascal-strings, we want to back translate here.
- //
- // FIXME: This is gross; that translation should be pulled from the
- // tool chain.
+ // -fno-pascal-strings is default, only pass non-default.
if (Args.hasFlag(options::OPT_fpascal_strings,
options::OPT_fno_pascal_strings,
- false) ||
- Args.hasFlag(options::OPT_mpascal_strings,
- options::OPT_mno_pascal_strings,
false))
CmdArgs.push_back("-fpascal-strings");
@@ -3183,7 +3485,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fpack-struct=1");
}
- if (KernelOrKext) {
+ if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
Args.ClaimAllArgs(options::OPT_fno_common);
@@ -3283,6 +3585,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
(ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors()))
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");
@@ -3302,31 +3607,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fasm-blocks");
- // If -Ofast is the optimization level, then -fvectorize should be enabled.
- // This alias option is being used to simplify the hasFlag logic.
- OptSpecifier VectorizeAliasOption = OFastEnabled ? options::OPT_Ofast :
+ // Enable vectorization per default according to the optimization level
+ // selected. For optimization levels that want vectorization we use the alias
+ // option to simplify the hasFlag logic.
+ bool EnableVec = shouldEnableVectorizerAtOLevel(Args);
+ OptSpecifier VectorizeAliasOption = EnableVec ? options::OPT_O_Group :
options::OPT_fvectorize;
-
- // -fvectorize is default.
if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
- options::OPT_fno_vectorize, true)) {
- CmdArgs.push_back("-backend-option");
+ options::OPT_fno_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-loops");
- }
- // -fno-slp-vectorize is default.
+ // -fslp-vectorize is default.
if (Args.hasFlag(options::OPT_fslp_vectorize,
- options::OPT_fno_slp_vectorize, false)) {
- CmdArgs.push_back("-backend-option");
+ options::OPT_fno_slp_vectorize, true))
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("-backend-option");
+ 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);
@@ -3353,13 +3652,20 @@ 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");
+ }
+
// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
//
// FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941.
#if 0
if (getToolChain().getTriple().isOSDarwin() &&
- (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
- getToolChain().getTriple().getArch() == llvm::Triple::thumb)) {
+ (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))
@@ -3456,7 +3762,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add the split debug info name to the command lines here so we
// can propagate it to the backend.
bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) &&
- (getToolChain().getTriple().getOS() == llvm::Triple::Linux) &&
+ getToolChain().getTriple().isOSLinux() &&
(isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA));
const char *SplitDwarfOut;
if (SplitDwarf) {
@@ -3466,7 +3772,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Finally add the compile command to the compilation.
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ if (Args.hasArg(options::OPT__SLASH_fallback)) {
+ tools::visualstudio::Compile CL(getToolChain());
+ Command *CLCommand = CL.GetCommand(C, JA, Output, Inputs, Args,
+ LinkingOutput);
+ C.addCommand(new FallbackCommand(JA, *this, Exec, CmdArgs, CLCommand));
+ } else {
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ }
+
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -3491,38 +3805,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
- // Disable warnings for clang -E -use-gold-plugin -emit-llvm foo.c
- Args.ClaimAllArgs(options::OPT_use_gold_plugin);
+ // Disable warnings for clang -E -emit-llvm foo.c
Args.ClaimAllArgs(options::OPT_emit_llvm);
}
-void ClangAs::AddARMTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
- llvm::Triple Triple = getToolChain().getTriple();
-
- // Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(getARMTargetCPU(Args, Triple)));
-
- // Honor -mfpu=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
- addFPUArgs(D, A, Args, CmdArgs);
-
- // Honor -mfpmath=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
- addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
-}
-
-void ClangAs::AddX86TargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Set the CPU based on -march=.
- if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(CPUName);
- }
-}
-
/// Add options related to the Objective-C runtime/ABI.
///
/// Returns true if the runtime is non-fragile.
@@ -3648,6 +3934,67 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
return runtime;
}
+void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ // The /LDd option implies /MTd. The dependent lib part can be overridden,
+ // but defining _DEBUG is sticky.
+ RTOptionID = options::OPT__SLASH_MTd;
+
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
+ RTOptionID = A->getOption().getID();
+
+ switch(RTOptionID) {
+ case options::OPT__SLASH_MD:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ CmdArgs.push_back("--dependent-lib=msvcrt");
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ CmdArgs.push_back("--dependent-lib=msvcrtd");
+ break;
+ case options::OPT__SLASH_MT:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("--dependent-lib=libcmt");
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("--dependent-lib=libcmtd");
+ break;
+ default:
+ llvm_unreachable("Unexpected option ID.");
+ }
+
+ // This provides POSIX compatibility (maps 'open' to '_open'), which most
+ // users want. The /Za flag to cl.exe turns this off, but it's not
+ // implemented in clang.
+ CmdArgs.push_back("--dependent-lib=oldnames");
+
+ // FIXME: Make this default for the win32 triple.
+ CmdArgs.push_back("-cxx-abi");
+ CmdArgs.push_back("microsoft");
+
+ if (Arg *A = Args.getLastArg(options::OPT_show_includes))
+ A->render(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ if (Args.hasArg(options::OPT__SLASH_fallback))
+ CmdArgs.push_back("msvc-fallback");
+ else
+ CmdArgs.push_back("msvc");
+ }
+}
+
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -3662,8 +4009,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
Args.ClaimAllArgs(options::OPT_w);
// and "clang -emit-llvm -c foo.s"
Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and "clang -use-gold-plugin -c foo.s"
- Args.ClaimAllArgs(options::OPT_use_gold_plugin);
// Invoke ourselves in -cc1as mode.
//
@@ -3686,25 +4031,18 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-main-file-name");
CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs));
- if (UseRelaxAll(C, Args))
- CmdArgs.push_back("-relax-all");
-
- // Add target specific cpu and features flags.
- switch(getToolChain().getTriple().getArch()) {
- default:
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- AddARMTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- AddX86TargetArgs(Args, CmdArgs);
- break;
+ // Add the target cpu
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ std::string CPU = getCPUName(Args, Triple);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
}
+ // Add the target features
+ const Driver &D = getToolChain().getDriver();
+ getTargetFeatures(D, Triple, Args, CmdArgs);
+
// Ignore explicit -force_cpusubtype_ALL option.
(void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
@@ -3754,8 +4092,9 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// FIXME: Add -static support, once we have it.
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
- options::OPT_Xassembler);
+ CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
+ getToolChain().getDriver());
+
Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
assert(Output.isFilename() && "Unexpected lipo output.");
@@ -3772,7 +4111,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// creating an object.
// TODO: Currently only works on linux with newer objcopy.
if (Args.hasArg(options::OPT_gsplit_dwarf) &&
- (getToolChain().getTriple().getOS() == llvm::Triple::Linux))
+ getToolChain().getTriple().isOSLinux())
SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
SplitDebugName(Args, Inputs));
}
@@ -3794,6 +4133,11 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
A->getOption().matches(options::OPT_g_Group))
continue;
+ // Don't forward any -W arguments to assembly and link steps.
+ if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) &&
+ A->getOption().matches(options::OPT_W_Group))
+ continue;
+
// It is unfortunate that we have to claim here, as this means
// we will basically never report anything interesting for
// platforms using a generic gcc, even if we are just using gcc
@@ -3815,6 +4159,8 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("ppc");
else if (Arch == llvm::Triple::ppc64)
CmdArgs.push_back("ppc64");
+ else if (Arch == llvm::Triple::ppc64le)
+ CmdArgs.push_back("ppc64le");
else
CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
}
@@ -3826,7 +4172,8 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// here.
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
- else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64)
+ else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64 ||
+ Arch == llvm::Triple::ppc64le)
CmdArgs.push_back("-m64");
if (Output.isFilename()) {
@@ -3889,7 +4236,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const char *GCCName;
if (!customGCCName.empty())
GCCName = customGCCName.c_str();
- else if (D.CCCIsCXX) {
+ else if (D.CCCIsCXX()) {
GCCName = "g++";
} else
GCCName = "gcc";
@@ -4151,7 +4498,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Libraries
//----------------------------------------------------------------------------
if (incStdLib && incDefLibs) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
@@ -4178,10 +4525,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
- C.addCommand(
- new Command(
- JA, *this,
- Args.MakeArgString(Linker), CmdArgs));
+ C.addCommand(new Command(JA, *this, Args.MakeArgString(Linker), CmdArgs));
}
// Hexagon tools end.
@@ -4205,7 +4549,7 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
.Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
.Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
llvm::Triple::x86)
- .Case("x86_64", llvm::Triple::x86_64)
+ .Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
// This is derived from the driver driver.
.Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
.Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm)
@@ -4265,6 +4609,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
SourceAction = SourceAction->getInputs()[0];
}
+ // If -no_integrated_as is used add -Q to the darwin assember driver to make
+ // sure it runs its system assembler not clang's integrated assembler.
+ if (Args.hasArg(options::OPT_no_integrated_as))
+ CmdArgs.push_back("-Q");
+
// Forward -g, assuming we are dealing with an actual assembly file.
if (SourceAction->getType() == types::TY_Asm ||
SourceAction->getType() == types::TY_PP_Asm) {
@@ -4278,12 +4627,12 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
AddDarwinArch(Args, CmdArgs);
// Use -force_cpusubtype_ALL on x86 by default.
- if (getToolChain().getTriple().getArch() == llvm::Triple::x86 ||
- getToolChain().getTriple().getArch() == llvm::Triple::x86_64 ||
+ if (getToolChain().getArch() == llvm::Triple::x86 ||
+ getToolChain().getArch() == llvm::Triple::x86_64 ||
Args.hasArg(options::OPT_force__cpusubtype__ALL))
CmdArgs.push_back("-force_cpusubtype_ALL");
- if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 &&
+ if (getToolChain().getArch() != llvm::Triple::x86_64 &&
(((Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext)) &&
(!getDarwinToolChain().isTargetIPhoneOS() ||
@@ -4374,6 +4723,9 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back("-demangle");
}
+ if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
+ CmdArgs.push_back("-export_dynamic");
+
// If we are using LTO, then automatically create a temporary file path for
// the linker to use, so that it's lifetime will extend past a possible
// dsymutil step.
@@ -4572,7 +4924,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
Args.AddLastArg(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_m_Separate);
Args.AddAllArgs(CmdArgs, options::OPT_r);
// Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading
@@ -4581,9 +4932,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX))
CmdArgs.push_back("-ObjC");
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export_dynamic");
-
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -4680,19 +5028,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
- SanitizerArgs Sanitize(getToolChain(), Args);
- // If we're building a dynamic lib with -fsanitize=address,
- // unresolved symbols may appear. Mark all
- // of them as dynamic_lookup. Linking executables is handled in
- // lib/Driver/ToolChains.cpp.
- if (Sanitize.needsAsanRt()) {
- if (Args.hasArg(options::OPT_dynamiclib) ||
- Args.hasArg(options::OPT_bundle)) {
- CmdArgs.push_back("-undefined");
- CmdArgs.push_back("dynamic_lookup");
- }
- }
-
if (Args.hasArg(options::OPT_fopenmp))
// This is more complicated in gcc...
CmdArgs.push_back("-lgomp");
@@ -4732,7 +5067,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (getToolChain().getDriver().CCCIsCXX)
+ if (getToolChain().getDriver().CCCIsCXX())
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
// link_ssp spec is empty.
@@ -4857,18 +5192,17 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
std::string LibPath = "/usr/lib/";
llvm::Triple::ArchType Arch = T.getArch();
switch (Arch) {
- case llvm::Triple::x86:
- GCCLibPath += ("i386-" + T.getVendorName() + "-" +
- T.getOSName()).str() + "/4.5.2/";
- break;
- case llvm::Triple::x86_64:
- GCCLibPath += ("i386-" + T.getVendorName() + "-" +
- T.getOSName()).str();
- GCCLibPath += "/4.5.2/amd64/";
- LibPath += "amd64/";
- break;
- default:
- assert(0 && "Unsupported architecture");
+ case llvm::Triple::x86:
+ GCCLibPath +=
+ ("i386-" + T.getVendorName() + "-" + T.getOSName()).str() + "/4.5.2/";
+ break;
+ case llvm::Triple::x86_64:
+ GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str();
+ GCCLibPath += "/4.5.2/amd64/";
+ LibPath += "amd64/";
+ break;
+ default:
+ llvm_unreachable("Unsupported architecture");
}
ArgStringList CmdArgs;
@@ -4914,7 +5248,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o"));
CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
}
- if (getToolChain().getDriver().CCCIsCXX)
+ if (getToolChain().getDriver().CCCIsCXX())
CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o"));
}
@@ -4929,7 +5263,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (getToolChain().getDriver().CCCIsCXX)
+ if (getToolChain().getDriver().CCCIsCXX())
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lgcc_s");
if (!Args.hasArg(options::OPT_shared)) {
@@ -5071,6 +5405,40 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ // When building 32-bit code on OpenBSD/amd64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ if (getToolChain().getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("--32");
+ else if (getToolChain().getArch() == llvm::Triple::ppc) {
+ CmdArgs.push_back("-mppc");
+ CmdArgs.push_back("-many");
+ } else if (getToolChain().getArch() == llvm::Triple::mips64 ||
+ getToolChain().getArch() == llvm::Triple::mips64el) {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (LastPICArg &&
+ (LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic) ||
+ LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie))) {
+ CmdArgs.push_back("-KPIC");
+ }
+ }
+
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
@@ -5104,6 +5472,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else if (getToolChain().getArch() == llvm::Triple::mips64el)
+ CmdArgs.push_back("-EL");
+
if ((!Args.hasArg(options::OPT_nostdlib)) &&
(!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-e");
@@ -5125,6 +5498,9 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ if (Args.hasArg(options::OPT_nopie))
+ CmdArgs.push_back("-nopie");
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -5167,7 +5543,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
@@ -5297,7 +5673,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
@@ -5320,23 +5696,21 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lc");
}
- std::string myarch = "-lclang_rt.";
- const llvm::Triple &T = getToolChain().getTriple();
- llvm::Triple::ArchType Arch = T.getArch();
- switch (Arch) {
- case llvm::Triple::arm:
- myarch += ("arm");
- break;
- case llvm::Triple::x86:
- myarch += ("i386");
- break;
- case llvm::Triple::x86_64:
- myarch += ("amd64");
- break;
- default:
- assert(0 && "Unsupported architecture");
- }
- CmdArgs.push_back(Args.MakeArgString(myarch));
+ StringRef MyArch;
+ switch (getToolChain().getTriple().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) &&
@@ -5373,7 +5747,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getArch() == llvm::Triple::mips64el) {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
+ getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
@@ -5533,11 +5907,31 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
+ // Tell the linker to load the plugin. This has to come before AddLinkerInputs
+ // as gold requires -plugin to come before any -plugin-opt that -Wl might
+ // forward.
+ if (D.IsUsingLTO(Args)) {
+ CmdArgs.push_back("-plugin");
+ std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
+ CmdArgs.push_back(Args.MakeArgString(Plugin));
+
+ // Try to pass driver level flags relevant to LTO code generation down to
+ // the plugin.
+
+ // Handle flags for selecting CPU variants.
+ std::string CPU = getCPUName(Args, ToolChain.getTriple());
+ if (!CPU.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ CPU));
+ }
+ }
+
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
@@ -5617,11 +6011,45 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
- // Set byte order explicitly
- if (getToolChain().getArch() == llvm::Triple::mips)
- CmdArgs.push_back("-EB");
- else if (getToolChain().getArch() == llvm::Triple::mipsel)
- CmdArgs.push_back("-EL");
+ // Pass the target CPU to GNU as for ARM, since the source code might
+ // not have the correct .cpu annotation.
+ if (getToolChain().getArch() == llvm::Triple::arm) {
+ std::string MArch(getARMTargetCPU(Args, getToolChain().getTriple()));
+ CmdArgs.push_back(Args.MakeArgString("-mcpu=" + MArch));
+ }
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mipsel ||
+ getToolChain().getArch() == llvm::Triple::mips64 ||
+ getToolChain().getArch() == llvm::Triple::mips64el) {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (LastPICArg &&
+ (LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic) ||
+ LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie))) {
+ CmdArgs.push_back("-KPIC");
+ }
+ }
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
@@ -5705,34 +6133,39 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+ unsigned Major, Minor, Micro;
+ getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
+ bool useLibgcc = true;
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) {
+ if (getToolChain().getArch() == llvm::Triple::x86 ||
+ getToolChain().getArch() == llvm::Triple::x86_64)
+ useLibgcc = false;
+ }
+
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
- // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
- // the default system libraries. Just mimic this for now.
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lgcc_eh");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
- }
- CmdArgs.push_back("-lgcc");
-
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lgcc_eh");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
+ if (useLibgcc) {
+ if (Args.hasArg(options::OPT_static)) {
+ // libgcc_eh depends on libc, so resolve as much as possible,
+ // pull in any new requirements from libc and then get the rest
+ // of libgcc.
+ CmdArgs.push_back("-lgcc_eh");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
}
}
@@ -5775,10 +6208,16 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-many");
+ } else if (getToolChain().getArch() == llvm::Triple::ppc64le) {
+ CmdArgs.push_back("-a64");
+ CmdArgs.push_back("-mppc64le");
+ CmdArgs.push_back("-many");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
CmdArgs.push_back("-mfpu=neon");
+ if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a")
+ CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
StringRef ARMFloatABI = getARMFloatABI(getToolChain().getDriver(), Args,
getToolChain().getTriple());
@@ -5793,7 +6232,7 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getArch() == llvm::Triple::mips64el) {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
+ getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
@@ -5807,12 +6246,31 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-EL");
+ if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
+ if (StringRef(A->getValue()) == "2008")
+ CmdArgs.push_back(Args.MakeArgString("-mnan=2008"));
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfp64)) {
+ if (A->getOption().matches(options::OPT_mfp32))
+ CmdArgs.push_back(Args.MakeArgString("-mfp32"));
+ else
+ CmdArgs.push_back(Args.MakeArgString("-mfp64"));
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_mips16, options::OPT_mno_mips16);
Args.AddLastArg(CmdArgs, options::OPT_mmicromips,
options::OPT_mno_micromips);
Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp);
Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2);
+ if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) {
+ // Do not use AddLastArg because not all versions of MIPS assembler
+ // support -mmsa / -mno-msa options.
+ if (A->getOption().matches(options::OPT_mmsa))
+ CmdArgs.push_back(Args.MakeArgString("-mmsa"));
+ }
+
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,
@@ -5825,8 +6283,10 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-KPIC");
}
} else if (getToolChain().getArch() == llvm::Triple::systemz) {
- // At the moment we always produce z10 code.
- CmdArgs.push_back("-march=z10");
+ // Always pass an -march option, since our default of z10 is later
+ // than the GNU assembler's default.
+ StringRef CPUName = getSystemZTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5844,6 +6304,14 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (Args.hasArg(options::OPT_gsplit_dwarf) &&
+ getToolChain().getTriple().isOSLinux())
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
+ SplitDebugName(Args, Inputs));
}
static void AddLibgcc(llvm::Triple Triple, const Driver &D,
@@ -5851,23 +6319,23 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
Args.hasArg(options::OPT_static);
- if (!D.CCCIsCXX)
+ if (!D.CCCIsCXX())
CmdArgs.push_back("-lgcc");
if (StaticLibgcc || isAndroid) {
- if (D.CCCIsCXX)
+ if (D.CCCIsCXX())
CmdArgs.push_back("-lgcc");
} else {
- if (!D.CCCIsCXX)
+ if (!D.CCCIsCXX())
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lgcc_s");
- if (!D.CCCIsCXX)
+ if (!D.CCCIsCXX())
CmdArgs.push_back("--no-as-needed");
}
if (StaticLibgcc && !isAndroid)
CmdArgs.push_back("-lgcc_eh");
- else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
+ else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
CmdArgs.push_back("-lgcc");
// According to Android ABI, we have to link with libdl if we are
@@ -5884,6 +6352,39 @@ static bool hasMipsN32ABIArg(const ArgList &Args) {
return A && (A->getValue() == StringRef("n32"));
}
+static StringRef getLinuxDynamicLinker(const ArgList &Args,
+ const toolchains::Linux &ToolChain) {
+ if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android)
+ return "/system/bin/linker";
+ else if (ToolChain.getArch() == llvm::Triple::x86)
+ return "/lib/ld-linux.so.2";
+ else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ return "/lib/ld-linux-aarch64.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::thumb) {
+ if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
+ return "/lib/ld-linux-armhf.so.3";
+ else
+ return "/lib/ld-linux.so.3";
+ } else if (ToolChain.getArch() == llvm::Triple::mips ||
+ ToolChain.getArch() == llvm::Triple::mipsel)
+ return "/lib/ld.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ return "/lib32/ld.so.1";
+ else
+ return "/lib64/ld.so.1";
+ } else if (ToolChain.getArch() == llvm::Triple::ppc)
+ return "/lib/ld.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
+ ToolChain.getArch() == llvm::Triple::ppc64le ||
+ ToolChain.getArch() == llvm::Triple::systemz)
+ return "/lib64/ld64.so.1";
+ else
+ return "/lib64/ld-linux-x86-64.so.2";
+}
+
void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -5894,7 +6395,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = ToolChain.getDriver();
const bool isAndroid =
ToolChain.getTriple().getEnvironment() == llvm::Triple::Android;
- SanitizerArgs Sanitize(getToolChain(), Args);
+ const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
(Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow());
@@ -5981,36 +6482,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
(!Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-dynamic-linker");
- if (isAndroid)
- CmdArgs.push_back("/system/bin/linker");
- else if (ToolChain.getArch() == llvm::Triple::x86)
- CmdArgs.push_back("/lib/ld-linux.so.2");
- else if (ToolChain.getArch() == llvm::Triple::aarch64)
- CmdArgs.push_back("/lib/ld-linux-aarch64.so.1");
- else if (ToolChain.getArch() == llvm::Triple::arm ||
- ToolChain.getArch() == llvm::Triple::thumb) {
- if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
- CmdArgs.push_back("/lib/ld-linux-armhf.so.3");
- else
- CmdArgs.push_back("/lib/ld-linux.so.3");
- }
- else if (ToolChain.getArch() == llvm::Triple::mips ||
- ToolChain.getArch() == llvm::Triple::mipsel)
- CmdArgs.push_back("/lib/ld.so.1");
- else if (ToolChain.getArch() == llvm::Triple::mips64 ||
- ToolChain.getArch() == llvm::Triple::mips64el) {
- if (hasMipsN32ABIArg(Args))
- CmdArgs.push_back("/lib32/ld.so.1");
- else
- CmdArgs.push_back("/lib64/ld.so.1");
- }
- else if (ToolChain.getArch() == llvm::Triple::ppc)
- CmdArgs.push_back("/lib/ld.so.1");
- else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
- ToolChain.getArch() == llvm::Triple::systemz)
- CmdArgs.push_back("/lib64/ld64.so.1");
- else
- CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
+ CmdArgs.push_back(Args.MakeArgString(
+ D.DyldPrefix + getLinuxDynamicLinker(Args, ToolChain)));
}
CmdArgs.push_back("-o");
@@ -6021,7 +6494,9 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!isAndroid) {
const char *crt1 = NULL;
if (!Args.hasArg(options::OPT_shared)){
- if (IsPIE)
+ if (Args.hasArg(options::OPT_pg))
+ crt1 = "gcrt1.o";
+ else if (IsPIE)
crt1 = "Scrt1.o";
else
crt1 = "crt1.o";
@@ -6058,7 +6533,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Tell the linker to load the plugin. This has to come before AddLinkerInputs
// as gold requires -plugin to come before any -plugin-opt that -Wl might
// forward.
- if (D.IsUsingLTO(Args) || Args.hasArg(options::OPT_use_gold_plugin)) {
+ if (D.IsUsingLTO(Args)) {
CmdArgs.push_back("-plugin");
std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
CmdArgs.push_back(Args.MakeArgString(Plugin));
@@ -6066,20 +6541,13 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Try to pass driver level flags relevant to LTO code generation down to
// the plugin.
- // Handle architecture-specific flags for selecting CPU variants.
- if (ToolChain.getArch() == llvm::Triple::x86 ||
- ToolChain.getArch() == llvm::Triple::x86_64)
+ // Handle flags for selecting CPU variants.
+ std::string CPU = getCPUName(Args, ToolChain.getTriple());
+ if (!CPU.empty()) {
CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
- getX86TargetCPU(Args, ToolChain.getTriple())));
- else if (ToolChain.getArch() == llvm::Triple::arm ||
- ToolChain.getArch() == llvm::Triple::thumb)
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
- getARMTargetCPU(Args, ToolChain.getTriple())));
-
- // FIXME: Factor out logic for MIPS, PPC, and other targets to support this
- // as well.
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ CPU));
+ }
}
@@ -6090,17 +6558,24 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Call these before we add the C++ ABI library.
if (Sanitize.needsUbsanRt())
- addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX,
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX(),
Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
- Sanitize.needsMsanRt());
+ Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
if (Sanitize.needsAsanRt())
addAsanRTLinux(getToolChain(), Args, CmdArgs);
if (Sanitize.needsTsanRt())
addTsanRTLinux(getToolChain(), Args, CmdArgs);
if (Sanitize.needsMsanRt())
addMsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsLsanRt())
+ addLsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsDfsanRt())
+ addDfsanRTLinux(getToolChain(), Args, CmdArgs);
- if (D.CCCIsCXX &&
+ // The profile runtime also needs access to system libraries.
+ addProfileRTLinux(getToolChain(), Args, CmdArgs);
+
+ if (D.CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
@@ -6156,8 +6631,6 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
@@ -6218,7 +6691,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
@@ -6366,7 +6839,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (D.CCCIsCXX) {
+ if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
@@ -6438,22 +6911,223 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ !Args.hasArg(options::OPT_nostartfiles) &&
+ !C.getDriver().IsCLMode()) {
CmdArgs.push_back("-defaultlib:libcmt");
}
CmdArgs.push_back("-nologo");
+ bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd);
+
+ if (DLL) {
+ CmdArgs.push_back(Args.MakeArgString("-dll"));
+
+ SmallString<128> ImplibName(Output.getFilename());
+ llvm::sys::path::replace_extension(ImplibName, "lib");
+ CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") +
+ ImplibName.str()));
+ }
+
+ if (getToolChain().getSanitizerArgs().needsAsanRt()) {
+ CmdArgs.push_back(Args.MakeArgString("-debug"));
+ CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
+ SmallString<128> LibSanitizer(getToolChain().getDriver().ResourceDir);
+ llvm::sys::path::append(LibSanitizer, "lib", "windows");
+ if (DLL) {
+ llvm::sys::path::append(LibSanitizer, "clang_rt.asan_dll_thunk-i386.lib");
+ } else {
+ llvm::sys::path::append(LibSanitizer, "clang_rt.asan-i386.lib");
+ }
+ // FIXME: Handle 64-bit.
+ CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
+ }
+
Args.AddAllArgValues(CmdArgs, options::OPT_l);
+ Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
// Add filenames immediately.
for (InputInfoList::const_iterator
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
if (it->isFilename())
CmdArgs.push_back(it->getFilename());
+ else
+ it->getInputArg().renderAsInput(Args, CmdArgs);
}
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("link.exe"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+
+void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
+}
+
+// Try to find FallbackName on PATH that is not identical to ClangProgramPath.
+// If one cannot be found, return FallbackName.
+// We do this special search to prevent clang-cl from falling back onto itself
+// if it's available as cl.exe on the path.
+static std::string FindFallback(const char *FallbackName,
+ const char *ClangProgramPath) {
+ llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
+ if (!OptPath.hasValue())
+ return FallbackName;
+
+#ifdef LLVM_ON_WIN32
+ const StringRef PathSeparators = ";";
+#else
+ const StringRef PathSeparators = ":";
+#endif
+
+ SmallVector<StringRef, 8> PathSegments;
+ llvm::SplitString(OptPath.getValue(), PathSegments, PathSeparators);
+
+ for (size_t i = 0, e = PathSegments.size(); i != e; ++i) {
+ const StringRef &PathSegment = PathSegments[i];
+ if (PathSegment.empty())
+ continue;
+
+ SmallString<128> FilePath(PathSegment);
+ llvm::sys::path::append(FilePath, FallbackName);
+ if (llvm::sys::fs::can_execute(Twine(FilePath)) &&
+ !llvm::sys::fs::equivalent(Twine(FilePath), ClangProgramPath))
+ return FilePath.str();
+ }
+
+ return FallbackName;
+}
+
+Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("/nologo");
+ CmdArgs.push_back("/c"); // Compile only.
+ CmdArgs.push_back("/W0"); // No warnings.
+
+ // The goal is to be able to invoke this tool correctly based on
+ // any flag accepted by clang-cl.
+
+ // These are spelled the same way in clang and cl.exe,.
+ Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
+ Args.AddAllArgs(CmdArgs, options::OPT_I);
+
+ // Optimization level.
+ if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) {
+ if (A->getOption().getID() == options::OPT_O0) {
+ CmdArgs.push_back("/Od");
+ } else {
+ StringRef OptLevel = A->getValue();
+ if (OptLevel == "1" || OptLevel == "2" || OptLevel == "s")
+ A->render(Args, CmdArgs);
+ else if (OptLevel == "3")
+ CmdArgs.push_back("/Ox");
+ }
+ }
+
+ // Flags for which clang-cl have an alias.
+ // FIXME: How can we ensure this stays in sync with relevant clang-cl options?
+
+ if (Arg *A = Args.getLastArg(options::OPT_frtti, options::OPT_fno_rtti))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_frtti ? "/GR"
+ : "/GR-");
+ if (Args.hasArg(options::OPT_fsyntax_only))
+ CmdArgs.push_back("/Zs");
+
+ std::vector<std::string> Includes = Args.getAllArgValues(options::OPT_include);
+ for (size_t I = 0, E = Includes.size(); I != E; ++I)
+ CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Includes[I]));
+
+ // Flags that can simply be passed through.
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
+
+ // The order of these flags is relevant, so pick the last one.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
+ options::OPT__SLASH_MT, options::OPT__SLASH_MTd))
+ A->render(Args, CmdArgs);
+
+
+ // Input filename.
+ assert(Inputs.size() == 1);
+ const InputInfo &II = Inputs[0];
+ assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX);
+ CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp");
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+
+ // Output filename.
+ assert(Output.getType() == types::TY_Object);
+ const char *Fo = Args.MakeArgString(std::string("/Fo") +
+ Output.getFilename());
+ CmdArgs.push_back(Fo);
+
+ const Driver &D = getToolChain().getDriver();
+ std::string Exec = FindFallback("cl.exe", D.getClangProgramPath());
+
+ return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs);
+}
+
+
+/// XCore Tools
+// We pass assemble and link construction to the xcc tool.
+
+void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ CmdArgs.push_back("-c");
+
+ if (Args.hasArg(options::OPT_g_Group)) {
+ CmdArgs.push_back("-g");
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
+void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index d6471716e660..d5b2848c9b01 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -14,12 +14,14 @@
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Compiler.h"
namespace clang {
class ObjCRuntime;
namespace driver {
+ class Command;
class Driver;
namespace toolchains {
@@ -27,40 +29,53 @@ namespace toolchains {
}
namespace tools {
+using llvm::opt::ArgStringList;
/// \brief Clang compiler tool.
class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
public:
- static const char *getBaseInputName(const ArgList &Args,
+ static const char *getBaseInputName(const llvm::opt::ArgList &Args,
const InputInfoList &Inputs);
- static const char *getBaseInputStem(const ArgList &Args,
+ static const char *getBaseInputStem(const llvm::opt::ArgList &Args,
const InputInfoList &Inputs);
- static const char *getDependencyFileName(const ArgList &Args,
+ static const char *getDependencyFileName(const llvm::opt::ArgList &Args,
const InputInfoList &Inputs);
private:
- void AddPreprocessingOptions(Compilation &C,
- const JobAction &JA,
+ void AddPreprocessingOptions(Compilation &C, const JobAction &JA,
const Driver &D,
- const ArgList &Args,
- ArgStringList &CmdArgs,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
const InputInfo &Output,
const InputInfoList &Inputs) const;
- void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddARMTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
bool KernelOrKext) const;
- void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddR600TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddR600TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddSparcTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddSystemZTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
- ObjCRuntime AddObjCRuntimeArgs(const ArgList &args, ArgStringList &cmdArgs,
+ ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args,
+ llvm::opt::ArgStringList &cmdArgs,
RewriteKind rewrite) const;
+ void AddClangCLArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
public:
Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {}
@@ -71,14 +86,12 @@ namespace tools {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
/// \brief Clang integrated assembler tool.
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
- void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
ClangAs(const ToolChain &TC) : Tool("clang::as",
"clang integrated assembler", TC) {}
@@ -90,7 +103,7 @@ namespace tools {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -104,16 +117,16 @@ namespace gcc {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
- virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const = 0;
+ virtual void
+ RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const = 0;
};
-
class LLVM_LIBRARY_VISIBILITY Preprocess : public Common {
public:
Preprocess(const ToolChain &TC) : Common("gcc::Preprocess",
@@ -123,7 +136,7 @@ namespace gcc {
virtual bool hasIntegratedCPP() const { return false; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
};
class LLVM_LIBRARY_VISIBILITY Precompile : public Common {
@@ -135,7 +148,7 @@ namespace gcc {
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
};
class LLVM_LIBRARY_VISIBILITY Compile : public Common {
@@ -147,7 +160,7 @@ namespace gcc {
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
};
class LLVM_LIBRARY_VISIBILITY Assemble : public Common {
@@ -158,7 +171,7 @@ namespace gcc {
virtual bool hasIntegratedCPP() const { return false; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Common {
@@ -170,7 +183,7 @@ namespace gcc {
virtual bool isLinkJob() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
};
} // end namespace gcc
@@ -185,11 +198,11 @@ namespace hexagon {
virtual bool hasIntegratedCPP() const { return false; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -202,11 +215,11 @@ namespace hexagon {
virtual bool isLinkJob() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace hexagon.
@@ -218,7 +231,8 @@ namespace darwin {
class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
virtual void anchor();
protected:
- void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddDarwinArch(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
const toolchains::Darwin &getDarwinToolChain() const {
return reinterpret_cast<const toolchains::Darwin&>(getToolChain());
@@ -239,14 +253,15 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool {
bool NeedsTempPath(const InputInfoList &Inputs) const;
- void AddLinkArgs(Compilation &C, const ArgList &Args,
- ArgStringList &CmdArgs, const InputInfoList &Inputs) const;
+ void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const;
public:
Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
@@ -257,7 +272,7 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -270,7 +285,7 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -285,7 +300,7 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -299,7 +314,7 @@ namespace darwin {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
@@ -317,7 +332,7 @@ namespace openbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -330,7 +345,7 @@ namespace openbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace openbsd
@@ -347,7 +362,7 @@ namespace bitrig {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -360,7 +375,7 @@ namespace bitrig {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace bitrig
@@ -377,7 +392,7 @@ namespace freebsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -390,7 +405,7 @@ namespace freebsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace freebsd
@@ -408,7 +423,7 @@ namespace netbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -423,7 +438,7 @@ namespace netbsd {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace netbsd
@@ -439,7 +454,7 @@ namespace gnutools {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -452,7 +467,7 @@ namespace gnutools {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
}
@@ -468,7 +483,7 @@ namespace minix {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -481,7 +496,7 @@ namespace minix {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace minix
@@ -498,7 +513,7 @@ namespace solaris {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -511,7 +526,7 @@ namespace solaris {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace solaris
@@ -528,7 +543,7 @@ namespace auroraux {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -541,7 +556,7 @@ namespace auroraux {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace auroraux
@@ -558,7 +573,7 @@ namespace dragonfly {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -571,14 +586,14 @@ namespace dragonfly {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
};
} // end namespace dragonfly
/// Visual studio tools.
namespace visualstudio {
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {}
@@ -588,11 +603,64 @@ namespace visualstudio {
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
- const ArgList &TCArgs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class LLVM_LIBRARY_VISIBILITY Compile : public Tool {
+ public:
+ Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC) {}
+
+ virtual bool hasIntegratedAssembler() const { return true; }
+ virtual bool hasIntegratedCPP() const { return true; }
+ virtual bool isLinkJob() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const;
+
+ Command *GetCommand(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
};
} // end namespace visualstudio
+namespace XCore {
+ // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and Compile.
+ // We simply use "clang -cc1" for those actions.
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("XCore::Assemble",
+ "XCore-as", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("XCore::Link",
+ "XCore-ld", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+} // end namespace XCore.
+
+
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 7d22596a17ef..d947ae7c03d6 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Types.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include <cassert>
#include <string.h>
@@ -28,7 +29,7 @@ static const TypeInfo TypeInfos[] = {
#include "clang/Driver/Types.def"
#undef TYPE
};
-static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]);
+static const unsigned numTypes = llvm::array_lengthof(TypeInfos);
static const TypeInfo &getInfo(unsigned id) {
assert(id > 0 && id - 1 < numTypes && "Invalid Type ID.");
@@ -43,7 +44,13 @@ types::ID types::getPreprocessedType(ID Id) {
return getInfo(Id).PreprocessedType;
}
-const char *types::getTypeTempSuffix(ID Id) {
+const char *types::getTypeTempSuffix(ID Id, bool CLMode) {
+ if (Id == TY_Object && CLMode)
+ return "obj";
+ if (Id == TY_Image && CLMode)
+ return "exe";
+ if (Id == TY_PP_Asm && CLMode)
+ return "asm";
return getInfo(Id).TempSuffix;
}
@@ -132,8 +139,10 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("f", TY_PP_Fortran)
.Case("F", TY_Fortran)
.Case("s", TY_PP_Asm)
+ .Case("asm", TY_PP_Asm)
.Case("S", TY_Asm)
.Case("o", TY_Object)
+ .Case("obj", TY_Object)
.Case("ii", TY_PP_CXX)
.Case("mi", TY_PP_ObjC)
.Case("mm", TY_ObjCXX)
@@ -180,9 +189,7 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
}
// FIXME: Why don't we just put this list in the defs file, eh.
-void types::getCompilationPhases(
- ID Id,
- llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) {
+void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) {
if (Id != TY_Object) {
if (getPreprocessedType(Id) != TY_INVALID) {
P.push_back(phases::Preprocess);
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index 622c49296de8..2b6320ac12e3 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -10,12 +10,12 @@
#include "ToolChains.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
@@ -31,6 +31,7 @@
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
+using namespace llvm::opt;
Windows::Windows(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
@@ -44,7 +45,7 @@ Tool *Windows::buildLinker() const {
Tool *Windows::buildAssembler() const {
if (getTriple().getEnvironment() == llvm::Triple::MachO)
return new tools::darwin::Assemble(*this);
- getDriver().Diag(clang::diag::err_no_external_windows_assembler);
+ getDriver().Diag(clang::diag::err_no_external_assembler);
return NULL;
}
@@ -125,7 +126,8 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
strncpy(partialKey, subKey, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
- lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
+ lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
+ &hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
int bestIndex = -1;
@@ -144,33 +146,34 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
- double value = strtod(numBuf, NULL);
- if (value > bestValue) {
- bestIndex = (int)index;
- bestValue = value;
+ double dvalue = strtod(numBuf, NULL);
+ if (dvalue > bestValue) {
+ // Test that InstallDir is indeed there before keeping this index.
+ // Open the chosen key path remainder.
strcpy(bestName, keyName);
+ // Append rest of key.
+ strncat(bestName, nextKey, sizeof(bestName) - 1);
+ bestName[sizeof(bestName) - 1] = '\0';
+ lResult = RegOpenKeyEx(hTopKey, bestName, 0,
+ KEY_READ | KEY_WOW64_32KEY, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS) {
+ bestIndex = (int)index;
+ bestValue = dvalue;
+ returnValue = true;
+ }
+ RegCloseKey(hKey);
+ }
}
size = sizeof(keyName) - 1;
}
- // If we found the highest versioned key, open the key and get the value.
- if (bestIndex != -1) {
- // Append rest of key.
- strncat(bestName, nextKey, sizeof(bestName) - 1);
- bestName[sizeof(bestName) - 1] = '\0';
- // Open the chosen key path remainder.
- lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS)
- returnValue = true;
- RegCloseKey(hKey);
- }
- }
RegCloseKey(hTopKey);
}
} else {
- lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
+ lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ | KEY_WOW64_32KEY,
+ &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
@@ -282,8 +285,8 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- llvm::sys::Path P(getDriver().ResourceDir);
- P.appendComponent("include");
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "include");
addSystemInclude(DriverArgs, CC1Args, P.str());
}
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
index 0b4ea3e0cdad..706c732dba45 100644
--- a/lib/Edit/Commit.cpp
+++ b/lib/Edit/Commit.cpp
@@ -38,7 +38,9 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
Commit::Commit(EditedSource &Editor)
: SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
PPRec(Editor.getPPCondDirectiveRecord()),
- Editor(&Editor), IsCommitable(true) { }
+ Editor(&Editor),
+ ForceCommitInSystemHeader(Editor.getForceCommitInSystemHeader()),
+ IsCommitable(true) { }
bool Commit::insert(SourceLocation loc, StringRef text,
bool afterToken, bool beforePreviousInsertions) {
@@ -183,7 +185,7 @@ void Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
data.Kind = Act_Insert;
data.OrigLoc = OrigLoc;
data.Offset = Offs;
- data.Text = text;
+ data.Text = copyString(text);
data.BeforePrev = beforePreviousInsertions;
CachedEdits.push_back(data);
}
@@ -232,7 +234,7 @@ bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
if (!isAtStartOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc))
+ if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
return false;
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -263,7 +265,7 @@ bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
if (!isAtEndOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc))
+ if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
return false;
loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
@@ -301,8 +303,8 @@ bool Commit::canRemoveRange(CharSourceRange range,
if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
return false;
- if (SM.isInSystemHeader(range.getBegin()) ||
- SM.isInSystemHeader(range.getEnd()))
+ if ((SM.isInSystemHeader(range.getBegin()) ||
+ SM.isInSystemHeader(range.getEnd())) && ForceCommitInSystemHeader)
return false;
if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 3e2e0ce7cf3d..d720ce990b52 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -13,166 +13,432 @@
///
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "format-token-breaker"
+
#include "BreakableToken.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Format/Format.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
#include <algorithm>
namespace clang {
namespace format {
-BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex,
- unsigned TailOffset,
- unsigned ColumnLimit) const {
- StringRef Text = getLine(LineIndex).substr(TailOffset);
- unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset);
+static const char *const Blanks = " \t\v\f\r";
+static bool IsBlank(char C) {
+ switch (C) {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ return true;
+ default:
+ return false;
+ }
+}
+
+static BreakableToken::Split getCommentSplit(StringRef Text,
+ unsigned ContentStartColumn,
+ unsigned ColumnLimit,
+ unsigned TabWidth,
+ encoding::Encoding Encoding) {
if (ColumnLimit <= ContentStartColumn + 1)
- return Split(StringRef::npos, 0);
+ return BreakableToken::Split(StringRef::npos, 0);
unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1;
- StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit);
+ unsigned MaxSplitBytes = 0;
+
+ for (unsigned NumChars = 0;
+ NumChars < MaxSplit && MaxSplitBytes < Text.size();) {
+ unsigned BytesInChar =
+ encoding::getCodePointNumBytes(Text[MaxSplitBytes], Encoding);
+ NumChars +=
+ encoding::columnWidthWithTabs(Text.substr(MaxSplitBytes, BytesInChar),
+ ContentStartColumn, TabWidth, Encoding);
+ MaxSplitBytes += BytesInChar;
+ }
+
+ StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
if (SpaceOffset == StringRef::npos ||
- Text.find_last_not_of(' ', SpaceOffset) == StringRef::npos) {
- SpaceOffset = Text.find(' ', MaxSplit);
+ // Don't break at leading whitespace.
+ Text.find_last_not_of(Blanks, SpaceOffset) == StringRef::npos) {
+ // Make sure that we don't break at leading whitespace that
+ // reaches past MaxSplit.
+ StringRef::size_type FirstNonWhitespace = Text.find_first_not_of(Blanks);
+ if (FirstNonWhitespace == StringRef::npos)
+ // If the comment is only whitespace, we cannot split.
+ return BreakableToken::Split(StringRef::npos, 0);
+ SpaceOffset = Text.find_first_of(
+ Blanks, std::max<unsigned>(MaxSplitBytes, FirstNonWhitespace));
}
if (SpaceOffset != StringRef::npos && SpaceOffset != 0) {
- StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim();
- StringRef AfterCut = Text.substr(SpaceOffset).ltrim();
+ StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(Blanks);
+ StringRef AfterCut = Text.substr(SpaceOffset).ltrim(Blanks);
return BreakableToken::Split(BeforeCut.size(),
AfterCut.begin() - BeforeCut.end());
}
return BreakableToken::Split(StringRef::npos, 0);
}
-void BreakableComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
- Split Split, bool InPPDirective,
- WhitespaceManager &Whitespaces) {
- StringRef Text = getLine(LineIndex).substr(TailOffset);
- StringRef AdditionalPrefix = Decoration;
- if (Text.size() == Split.first + Split.second) {
- // For all but the last line handle trailing space in trimLine.
- if (LineIndex < Lines.size() - 1)
- return;
- // For the last line we need to break before "*/", but not to add "* ".
- AdditionalPrefix = "";
+static BreakableToken::Split getStringSplit(StringRef Text,
+ unsigned UsedColumns,
+ unsigned ColumnLimit,
+ unsigned TabWidth,
+ encoding::Encoding Encoding) {
+ // FIXME: Reduce unit test case.
+ if (Text.empty())
+ return BreakableToken::Split(StringRef::npos, 0);
+ if (ColumnLimit <= UsedColumns)
+ return BreakableToken::Split(StringRef::npos, 0);
+ unsigned MaxSplit = std::min<unsigned>(
+ ColumnLimit - UsedColumns,
+ encoding::columnWidthWithTabs(Text, UsedColumns, TabWidth, Encoding) - 1);
+ StringRef::size_type SpaceOffset = 0;
+ StringRef::size_type SlashOffset = 0;
+ StringRef::size_type WordStartOffset = 0;
+ StringRef::size_type SplitPoint = 0;
+ for (unsigned Chars = 0;;) {
+ unsigned Advance;
+ if (Text[0] == '\\') {
+ Advance = encoding::getEscapeSequenceLength(Text);
+ Chars += Advance;
+ } else {
+ Advance = encoding::getCodePointNumBytes(Text[0], Encoding);
+ Chars += encoding::columnWidthWithTabs(
+ Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
+ }
+
+ if (Chars > MaxSplit)
+ break;
+
+ if (IsBlank(Text[0]))
+ SpaceOffset = SplitPoint;
+ if (Text[0] == '/')
+ SlashOffset = SplitPoint;
+ if (Advance == 1 && !isAlphanumeric(Text[0]))
+ WordStartOffset = SplitPoint;
+
+ SplitPoint += Advance;
+ Text = Text.substr(Advance);
}
- unsigned WhitespaceStartColumn =
- getContentStartColumn(LineIndex, TailOffset) + Split.first;
- unsigned BreakOffset = Text.data() - TokenText.data() + Split.first;
- unsigned CharsToRemove = Split.second;
- Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", AdditionalPrefix,
- InPPDirective, IndentAtLineBreak,
- WhitespaceStartColumn);
+ if (SpaceOffset != 0)
+ return BreakableToken::Split(SpaceOffset + 1, 0);
+ if (SlashOffset != 0)
+ return BreakableToken::Split(SlashOffset + 1, 0);
+ if (WordStartOffset != 0)
+ return BreakableToken::Split(WordStartOffset + 1, 0);
+ if (SplitPoint != 0)
+ return BreakableToken::Split(SplitPoint, 0);
+ return BreakableToken::Split(StringRef::npos, 0);
}
-BreakableBlockComment::BreakableBlockComment(const SourceManager &SourceMgr,
- const AnnotatedToken &Token,
- unsigned StartColumn)
- : BreakableComment(SourceMgr, Token.FormatTok, StartColumn + 2) {
- assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
+unsigned BreakableSingleLineToken::getLineCount() const { return 1; }
+
+unsigned BreakableSingleLineToken::getLineLengthAfterSplit(
+ unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
+ return StartColumn + Prefix.size() + Postfix.size() +
+ encoding::columnWidthWithTabs(Line.substr(Offset, Length),
+ StartColumn + Prefix.size(),
+ Style.TabWidth, Encoding);
+}
+
+BreakableSingleLineToken::BreakableSingleLineToken(
+ const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
+ StringRef Prefix, StringRef Postfix, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style)
+ : BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style),
+ StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
+ assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
+ Line = Tok.TokenText.substr(
+ Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
+}
+
+BreakableStringLiteral::BreakableStringLiteral(
+ const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
+ StringRef Prefix, StringRef Postfix, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style)
+ : BreakableSingleLineToken(Tok, IndentLevel, StartColumn, Prefix, Postfix,
+ InPPDirective, Encoding, Style) {}
+
+BreakableToken::Split
+BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ return getStringSplit(Line.substr(TailOffset),
+ StartColumn + Prefix.size() + Postfix.size(),
+ ColumnLimit, Style.TabWidth, Encoding);
+}
+
+void BreakableStringLiteral::insertBreak(unsigned LineIndex,
+ unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) {
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
+ Prefix, InPPDirective, 1, IndentLevel, StartColumn);
+}
+
+static StringRef getLineCommentPrefix(StringRef Comment) {
+ static const char *const KnownPrefixes[] = { "/// ", "///", "// ", "//" };
+ for (size_t i = 0, e = llvm::array_lengthof(KnownPrefixes); i != e; ++i)
+ if (Comment.startswith(KnownPrefixes[i]))
+ return KnownPrefixes[i];
+ return "";
+}
+
+BreakableLineComment::BreakableLineComment(
+ const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
+ bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
+ : BreakableSingleLineToken(Token, IndentLevel, StartColumn,
+ getLineCommentPrefix(Token.TokenText), "",
+ InPPDirective, Encoding, Style) {
+ OriginalPrefix = Prefix;
+ if (Token.TokenText.size() > Prefix.size() &&
+ isAlphanumeric(Token.TokenText[Prefix.size()])) {
+ if (Prefix == "//")
+ Prefix = "// ";
+ else if (Prefix == "///")
+ Prefix = "/// ";
+ }
+}
+
+BreakableToken::Split
+BreakableLineComment::getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ return getCommentSplit(Line.substr(TailOffset), StartColumn + Prefix.size(),
+ ColumnLimit, Style.TabWidth, Encoding);
+}
+
+void BreakableLineComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces) {
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second,
+ Postfix, Prefix, InPPDirective, /*Newlines=*/1, IndentLevel, StartColumn);
+}
+
+void BreakableLineComment::replaceWhitespace(unsigned LineIndex,
+ unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) {
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second, "",
+ "", /*InPPDirective=*/false, /*Newlines=*/0, /*IndentLevel=*/0,
+ /*Spaces=*/1);
+}
- OriginalStartColumn =
- SourceMgr.getSpellingColumnNumber(Tok.getStartOfNonWhitespace()) - 1;
+void
+BreakableLineComment::replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) {
+ if (OriginalPrefix != Prefix) {
+ Whitespaces.replaceWhitespaceInToken(Tok, OriginalPrefix.size(), 0, "", "",
+ /*InPPDirective=*/false,
+ /*Newlines=*/0, /*IndentLevel=*/0,
+ /*Spaces=*/1);
+ }
+}
+BreakableBlockComment::BreakableBlockComment(
+ const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
+ unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style)
+ : BreakableToken(Token, IndentLevel, InPPDirective, Encoding, Style) {
+ StringRef TokenText(Token.TokenText);
+ assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n");
- bool NeedsStar = true;
- CommonPrefixLength = UINT_MAX;
- if (Lines.size() == 1) {
- if (Token.Parent == 0) {
- // Standalone block comments will be aligned and prefixed with *s.
- CommonPrefixLength = OriginalStartColumn + 1;
- } else {
- // Trailing comments can start on arbitrary column, and available
- // horizontal space can be too small to align consecutive lines with
- // the first one. We could, probably, align them to current
- // indentation level, but now we just wrap them without indentation
- // and stars.
- CommonPrefixLength = 0;
- NeedsStar = false;
- }
- } else {
- for (size_t i = 1; i < Lines.size(); ++i) {
- size_t FirstNonWhitespace = Lines[i].find_first_not_of(" ");
- if (FirstNonWhitespace != StringRef::npos) {
- NeedsStar = NeedsStar && (Lines[i][FirstNonWhitespace] == '*');
- CommonPrefixLength =
- std::min<unsigned>(CommonPrefixLength, FirstNonWhitespace);
+ int IndentDelta = StartColumn - OriginalStartColumn;
+ LeadingWhitespace.resize(Lines.size());
+ StartOfLineColumn.resize(Lines.size());
+ StartOfLineColumn[0] = StartColumn + 2;
+ for (size_t i = 1; i < Lines.size(); ++i)
+ adjustWhitespace(i, IndentDelta);
+
+ Decoration = "* ";
+ if (Lines.size() == 1 && !FirstInLine) {
+ // Comments for which FirstInLine is false can start on arbitrary column,
+ // and available horizontal space can be too small to align consecutive
+ // lines with the first one.
+ // FIXME: We could, probably, align them to current indentation level, but
+ // now we just wrap them without stars.
+ Decoration = "";
+ }
+ for (size_t i = 1, e = Lines.size(); i < e && !Decoration.empty(); ++i) {
+ // If the last line is empty, the closing "*/" will have a star.
+ if (i + 1 == e && Lines[i].empty())
+ break;
+ while (!Lines[i].startswith(Decoration))
+ Decoration = Decoration.substr(0, Decoration.size() - 1);
+ }
+
+ LastLineNeedsDecoration = true;
+ IndentAtLineBreak = StartOfLineColumn[0] + 1;
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ if (Lines[i].empty()) {
+ if (i + 1 == Lines.size()) {
+ // Empty last line means that we already have a star as a part of the
+ // trailing */. We also need to preserve whitespace, so that */ is
+ // correctly indented.
+ LastLineNeedsDecoration = false;
+ } else if (Decoration.empty()) {
+ // For all other lines, set the start column to 0 if they're empty, so
+ // we do not insert trailing whitespace anywhere.
+ StartOfLineColumn[i] = 0;
}
+ continue;
}
+ // The first line already excludes the star.
+ // For all other lines, adjust the line to exclude the star and
+ // (optionally) the first whitespace.
+ StartOfLineColumn[i] += Decoration.size();
+ Lines[i] = Lines[i].substr(Decoration.size());
+ LeadingWhitespace[i] += Decoration.size();
+ IndentAtLineBreak = std::min<int>(IndentAtLineBreak, StartOfLineColumn[i]);
}
- if (CommonPrefixLength == UINT_MAX)
- CommonPrefixLength = 0;
+ IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
+ DEBUG({
+ llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n";
+ for (size_t i = 0; i < Lines.size(); ++i) {
+ llvm::dbgs() << i << " |" << Lines[i] << "| " << LeadingWhitespace[i]
+ << "\n";
+ }
+ });
+}
+
+void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
+ int IndentDelta) {
+ // When in a preprocessor directive, the trailing backslash in a block comment
+ // is not needed, but can serve a purpose of uniformity with necessary escaped
+ // newlines outside the comment. In this case we remove it here before
+ // trimming the trailing whitespace. The backslash will be re-added later when
+ // inserting a line break.
+ size_t EndOfPreviousLine = Lines[LineIndex - 1].size();
+ if (InPPDirective && Lines[LineIndex - 1].endswith("\\"))
+ --EndOfPreviousLine;
- Decoration = NeedsStar ? "* " : "";
+ // Calculate the end of the non-whitespace text in the previous line.
+ EndOfPreviousLine =
+ Lines[LineIndex - 1].find_last_not_of(Blanks, EndOfPreviousLine);
+ if (EndOfPreviousLine == StringRef::npos)
+ EndOfPreviousLine = 0;
+ else
+ ++EndOfPreviousLine;
+ // Calculate the start of the non-whitespace text in the current line.
+ size_t StartOfLine = Lines[LineIndex].find_first_not_of(Blanks);
+ if (StartOfLine == StringRef::npos)
+ StartOfLine = Lines[LineIndex].size();
- IndentAtLineBreak =
- std::max<int>(StartColumn - OriginalStartColumn + CommonPrefixLength, 0);
+ StringRef Whitespace = Lines[LineIndex].substr(0, StartOfLine);
+ // Adjust Lines to only contain relevant text.
+ Lines[LineIndex - 1] = Lines[LineIndex - 1].substr(0, EndOfPreviousLine);
+ Lines[LineIndex] = Lines[LineIndex].substr(StartOfLine);
+ // Adjust LeadingWhitespace to account all whitespace between the lines
+ // to the current line.
+ LeadingWhitespace[LineIndex] =
+ Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
+
+ // Adjust the start column uniformly accross all lines.
+ StartOfLineColumn[LineIndex] = std::max<int>(
+ 0,
+ encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
+ IndentDelta);
}
-void BreakableBlockComment::alignLines(WhitespaceManager &Whitespaces) {
- SourceLocation TokenLoc = Tok.getStartOfNonWhitespace();
- int IndentDelta = (StartColumn - 2) - OriginalStartColumn;
- if (IndentDelta > 0) {
- std::string WhiteSpace(IndentDelta, ' ');
- for (size_t i = 1; i < Lines.size(); ++i) {
- Whitespaces.addReplacement(
- TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), 0,
- WhiteSpace);
- }
- } else if (IndentDelta < 0) {
- std::string WhiteSpace(-IndentDelta, ' ');
- // Check that the line is indented enough.
- for (size_t i = 1; i < Lines.size(); ++i) {
- if (!Lines[i].startswith(WhiteSpace))
- return;
- }
- for (size_t i = 1; i < Lines.size(); ++i) {
- Whitespaces.addReplacement(
- TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()),
- -IndentDelta, "");
- }
+unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); }
+
+unsigned BreakableBlockComment::getLineLengthAfterSplit(
+ unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
+ unsigned ContentStartColumn = getContentStartColumn(LineIndex, Offset);
+ return ContentStartColumn +
+ encoding::columnWidthWithTabs(Lines[LineIndex].substr(Offset, Length),
+ ContentStartColumn, Style.TabWidth,
+ Encoding) +
+ // The last line gets a "*/" postfix.
+ (LineIndex + 1 == Lines.size() ? 2 : 0);
+}
+
+BreakableToken::Split
+BreakableBlockComment::getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ return getCommentSplit(Lines[LineIndex].substr(TailOffset),
+ getContentStartColumn(LineIndex, TailOffset),
+ ColumnLimit, Style.TabWidth, Encoding);
+}
+
+void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces) {
+ StringRef Text = Lines[LineIndex].substr(TailOffset);
+ StringRef Prefix = Decoration;
+ if (LineIndex + 1 == Lines.size() &&
+ Text.size() == Split.first + Split.second) {
+ // For the last line we need to break before "*/", but not to add "* ".
+ Prefix = "";
}
- for (unsigned i = 1; i < Lines.size(); ++i)
- Lines[i] = Lines[i].substr(CommonPrefixLength + Decoration.size());
+ unsigned BreakOffsetInToken =
+ Text.data() - Tok.TokenText.data() + Split.first;
+ unsigned CharsToRemove = Split.second;
+ assert(IndentAtLineBreak >= Decoration.size());
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, BreakOffsetInToken, CharsToRemove, "", Prefix, InPPDirective, 1,
+ IndentLevel, IndentAtLineBreak - Decoration.size());
}
-void BreakableBlockComment::trimLine(unsigned LineIndex, unsigned TailOffset,
- unsigned InPPDirective,
- WhitespaceManager &Whitespaces) {
- if (LineIndex == Lines.size() - 1)
- return;
+void BreakableBlockComment::replaceWhitespace(unsigned LineIndex,
+ unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) {
StringRef Text = Lines[LineIndex].substr(TailOffset);
- if (!Text.endswith(" ") && !InPPDirective)
+ unsigned BreakOffsetInToken =
+ Text.data() - Tok.TokenText.data() + Split.first;
+ unsigned CharsToRemove = Split.second;
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, BreakOffsetInToken, CharsToRemove, "", "", /*InPPDirective=*/false,
+ /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1);
+}
+
+void
+BreakableBlockComment::replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) {
+ if (LineIndex == 0)
return;
+ StringRef Prefix = Decoration;
+ if (Lines[LineIndex].empty()) {
+ if (LineIndex + 1 == Lines.size()) {
+ if (!LastLineNeedsDecoration) {
+ // If the last line was empty, we don't need a prefix, as the */ will
+ // line up with the decoration (if it exists).
+ Prefix = "";
+ }
+ } else if (!Decoration.empty()) {
+ // For other empty lines, if we do have a decoration, adapt it to not
+ // contain a trailing whitespace.
+ Prefix = Prefix.substr(0, 1);
+ }
+ } else {
+ if (StartOfLineColumn[LineIndex] == 1) {
+ // This line starts immediately after the decorating *.
+ Prefix = Prefix.substr(0, 1);
+ }
+ }
- StringRef TrimmedLine = Text.rtrim();
- unsigned WhitespaceStartColumn =
- getLineLengthAfterSplit(LineIndex, TailOffset);
- unsigned BreakOffset = TrimmedLine.end() - TokenText.data();
- unsigned CharsToRemove = Text.size() - TrimmedLine.size() + 1;
- Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", "", InPPDirective,
- 0, WhitespaceStartColumn);
-}
-
-BreakableLineComment::BreakableLineComment(const SourceManager &SourceMgr,
- const AnnotatedToken &Token,
- unsigned StartColumn)
- : BreakableComment(SourceMgr, Token.FormatTok, StartColumn) {
- assert(TokenText.startswith("//"));
- Decoration = getLineCommentPrefix(TokenText);
- Lines.push_back(TokenText.substr(Decoration.size()));
- IndentAtLineBreak = StartColumn;
- this->StartColumn += Decoration.size(); // Start column of the contents.
-}
-
-StringRef BreakableLineComment::getLineCommentPrefix(StringRef Comment) {
- const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" };
- for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i)
- if (Comment.startswith(KnownPrefixes[i]))
- return KnownPrefixes[i];
- return "";
+ unsigned WhitespaceOffsetInToken = Lines[LineIndex].data() -
+ Tok.TokenText.data() -
+ LeadingWhitespace[LineIndex];
+ assert(StartOfLineColumn[LineIndex] >= Prefix.size());
+ Whitespaces.replaceWhitespaceInToken(
+ Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
+ InPPDirective, 1, IndentLevel,
+ StartOfLineColumn[LineIndex] - Prefix.size());
+}
+
+unsigned
+BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const {
+ // If we break, we always break at the predefined indent.
+ if (TailOffset != 0)
+ return IndentAtLineBreak;
+ return StartOfLineColumn[LineIndex];
}
} // namespace format
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index c1303183d312..b965190d54de 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -17,6 +17,7 @@
#ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
#define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
+#include "Encoding.h"
#include "TokenAnnotator.h"
#include "WhitespaceManager.h"
#include <utility>
@@ -24,214 +25,218 @@
namespace clang {
namespace format {
+struct FormatStyle;
+
+/// \brief Base class for strategies on how to break tokens.
+///
+/// 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 {
public:
- BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok,
- unsigned StartColumn)
- : Tok(Tok), StartColumn(StartColumn),
- TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()),
- Tok.TokenLength) {}
+ /// \brief Contains starting character index and length of split.
+ typedef std::pair<StringRef::size_type, unsigned> Split;
+
virtual ~BreakableToken() {}
+
+ /// \brief Returns the number of lines in this token in the original code.
virtual unsigned getLineCount() const = 0;
- virtual unsigned getLineSize(unsigned Index) const = 0;
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset) const = 0;
- // Contains starting character index and length of split.
- typedef std::pair<StringRef::size_type, unsigned> Split;
+ /// \brief Returns the number of columns required to format the piece of line
+ /// at \p LineIndex, from byte offset \p Offset with length \p Length.
+ ///
+ /// Note that previous breaks are not taken into account. \p Offset is always
+ /// specified from the start of the (original) line.
+ /// \p Length can be set to StringRef::npos, which means "to the end of line".
+ virtual unsigned
+ getLineLengthAfterSplit(unsigned LineIndex, unsigned Offset,
+ StringRef::size_type Length) const = 0;
+
+ /// \brief Returns a range (offset, length) at which to break the line at
+ /// \p LineIndex, if previously broken at \p TailOffset. If possible, do not
+ /// violate \p ColumnLimit.
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit) const = 0;
+
+ /// \brief Emits the previously retrieved \p Split via \p Whitespaces.
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- bool InPPDirective,
WhitespaceManager &Whitespaces) = 0;
- virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
- unsigned InPPDirective,
- WhitespaceManager &Whitespaces) {}
+
+ /// \brief Replaces the whitespace range described by \p Split with a single
+ /// space.
+ virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces) = 0;
+
+ /// \brief Replaces the whitespace between \p LineIndex-1 and \p LineIndex.
+ virtual void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) {}
+
protected:
+ BreakableToken(const FormatToken &Tok, unsigned IndentLevel,
+ bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style)
+ : Tok(Tok), IndentLevel(IndentLevel), InPPDirective(InPPDirective),
+ Encoding(Encoding), Style(Style) {}
+
const FormatToken &Tok;
- unsigned StartColumn;
- StringRef TokenText;
+ const unsigned IndentLevel;
+ const bool InPPDirective;
+ const encoding::Encoding Encoding;
+ const FormatStyle &Style;
};
-class BreakableStringLiteral : public BreakableToken {
+/// \brief Base class for single line tokens that can be broken.
+///
+/// \c getSplit() needs to be implemented by child classes.
+class BreakableSingleLineToken : public BreakableToken {
public:
- BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok,
- unsigned StartColumn)
- : BreakableToken(SourceMgr, Tok, StartColumn) {
- assert(TokenText.startswith("\"") && TokenText.endswith("\""));
- }
+ virtual unsigned getLineCount() const;
+ virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
+ unsigned TailOffset,
+ StringRef::size_type Length) const;
- virtual unsigned getLineCount() const { return 1; }
+protected:
+ BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
+ unsigned StartColumn, StringRef Prefix,
+ StringRef Postfix, bool InPPDirective,
+ encoding::Encoding Encoding,
+ const FormatStyle &Style);
- virtual unsigned getLineSize(unsigned Index) const {
- return Tok.TokenLength - 2; // Should be in sync with getLine
- }
+ // The column in which the token starts.
+ unsigned StartColumn;
+ // The prefix a line needs after a break in the token.
+ StringRef Prefix;
+ // The postfix a line needs before introducing a break.
+ StringRef Postfix;
+ // The token text excluding the prefix and postfix.
+ StringRef Line;
+};
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset) const {
- return getDecorationLength() + getLine().size() - TailOffset;
- }
+class BreakableStringLiteral : public BreakableSingleLineToken {
+public:
+ /// \brief Creates a breakable token for a single line string literal.
+ ///
+ /// \p StartColumn specifies the column in which the token will start
+ /// after formatting.
+ BreakableStringLiteral(const FormatToken &Tok, unsigned IndentLevel,
+ unsigned StartColumn, StringRef Prefix,
+ StringRef Postfix, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style);
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const {
- StringRef Text = getLine().substr(TailOffset);
- if (ColumnLimit <= getDecorationLength())
- return Split(StringRef::npos, 0);
- unsigned MaxSplit = ColumnLimit - getDecorationLength();
- assert(MaxSplit < Text.size());
- StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit);
- if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
- return Split(SpaceOffset + 1, 0);
- StringRef::size_type SlashOffset = Text.rfind('/', MaxSplit);
- if (SlashOffset != StringRef::npos && SlashOffset != 0)
- return Split(SlashOffset + 1, 0);
- StringRef::size_type SplitPoint = getStartOfCharacter(Text, MaxSplit);
- if (SplitPoint != StringRef::npos && SplitPoint > 1)
- // Do not split at 0.
- return Split(SplitPoint, 0);
- return Split(StringRef::npos, 0);
- }
-
+ unsigned ColumnLimit) const;
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- bool InPPDirective, WhitespaceManager &Whitespaces) {
- unsigned WhitespaceStartColumn = StartColumn + Split.first + 2;
- Whitespaces.breakToken(Tok, 1 + TailOffset + Split.first, Split.second,
- "\"", "\"", InPPDirective, StartColumn,
- WhitespaceStartColumn);
- }
-
-private:
- StringRef getLine() const {
- // Get string without quotes.
- // FIXME: Handle string prefixes.
- return TokenText.substr(1, TokenText.size() - 2);
- }
-
- unsigned getDecorationLength() const { return StartColumn + 2; }
-
- static StringRef::size_type getStartOfCharacter(StringRef Text,
- StringRef::size_type Offset) {
- StringRef::size_type NextEscape = Text.find('\\');
- while (NextEscape != StringRef::npos && NextEscape < Offset) {
- StringRef::size_type SequenceLength =
- getEscapeSequenceLength(Text.substr(NextEscape));
- if (Offset < NextEscape + SequenceLength)
- return NextEscape;
- NextEscape = Text.find('\\', NextEscape + SequenceLength);
- }
- return Offset;
- }
-
- static unsigned getEscapeSequenceLength(StringRef Text) {
- assert(Text[0] == '\\');
- if (Text.size() < 2)
- return 1;
-
- switch (Text[1]) {
- case 'u':
- return 6;
- case 'U':
- return 10;
- case 'x':
- return getHexLength(Text);
- default:
- if (Text[1] >= '0' && Text[1] <= '7')
- return getOctalLength(Text);
- return 2;
- }
- }
-
- static unsigned getHexLength(StringRef Text) {
- unsigned I = 2; // Point after '\x'.
- while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
- (Text[I] >= 'a' && Text[I] <= 'f') ||
- (Text[I] >= 'A' && Text[I] <= 'F'))) {
- ++I;
- }
- return I;
- }
-
- static unsigned getOctalLength(StringRef Text) {
- unsigned I = 1;
- while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
- ++I;
- }
- return I;
- }
-
+ WhitespaceManager &Whitespaces);
+ virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces) {}
};
-class BreakableComment : public BreakableToken {
+class BreakableLineComment : public BreakableSingleLineToken {
public:
- virtual unsigned getLineSize(unsigned Index) const {
- return getLine(Index).size();
- }
-
- virtual unsigned getLineCount() const { return Lines.size(); }
-
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset) const {
- return getContentStartColumn(LineIndex, TailOffset) +
- getLine(LineIndex).size() - TailOffset;
- }
+ /// \brief Creates a breakable token for a line comment.
+ ///
+ /// \p StartColumn specifies the column in which the comment will start
+ /// after formatting.
+ BreakableLineComment(const FormatToken &Token, unsigned IndentLevel,
+ unsigned StartColumn, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style);
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit) const;
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- bool InPPDirective, WhitespaceManager &Whitespaces);
-
-protected:
- BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok,
- unsigned StartColumn)
- : BreakableToken(SourceMgr, Tok, StartColumn) {}
-
- // Get comment lines without /* */, common prefix and trailing whitespace.
- // Last line is not trimmed, as it is terminated by */, so its trailing
- // whitespace is not really trailing.
- StringRef getLine(unsigned Index) const {
- return Index < Lines.size() - 1 ? Lines[Index].rtrim() : Lines[Index];
- }
-
- unsigned getContentStartColumn(unsigned LineIndex,
- unsigned TailOffset) const {
- return (TailOffset == 0 && LineIndex == 0)
- ? StartColumn
- : IndentAtLineBreak + Decoration.size();
- }
+ WhitespaceManager &Whitespaces);
+ virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces);
+ virtual void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces);
- unsigned IndentAtLineBreak;
- StringRef Decoration;
- SmallVector<StringRef, 16> Lines;
+private:
+ // The prefix without an additional space if one was added.
+ StringRef OriginalPrefix;
};
-class BreakableBlockComment : public BreakableComment {
+class BreakableBlockComment : public BreakableToken {
public:
- BreakableBlockComment(const SourceManager &SourceMgr,
- const AnnotatedToken &Token, unsigned StartColumn);
-
- void alignLines(WhitespaceManager &Whitespaces);
-
+ /// \brief Creates a breakable token for a block comment.
+ ///
+ /// \p StartColumn specifies the column in which the comment will start
+ /// after formatting, while \p OriginalStartColumn specifies in which
+ /// column the comment started before formatting.
+ /// If the comment starts a line after formatting, set \p FirstInLine to true.
+ BreakableBlockComment(const FormatToken &Token, unsigned IndentLevel,
+ unsigned StartColumn, unsigned OriginaStartColumn,
+ bool FirstInLine, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style);
+
+ virtual unsigned getLineCount() const;
virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset) const {
- return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) +
- (LineIndex + 1 < Lines.size() ? 0 : 2);
- }
-
- virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
- unsigned InPPDirective, WhitespaceManager &Whitespaces);
+ unsigned TailOffset,
+ StringRef::size_type Length) const;
+ virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const;
+ virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces);
+ virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces);
+ virtual void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces);
private:
- unsigned OriginalStartColumn;
- unsigned CommonPrefixLength;
-};
+ // Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex],
+ // so that all whitespace between the lines is accounted to Lines[LineIndex]
+ // as leading whitespace:
+ // - Lines[LineIndex] points to the text after that whitespace
+ // - Lines[LineIndex-1] shrinks by its trailing whitespace
+ // - LeadingWhitespace[LineIndex] is updated with the complete whitespace
+ // between the end of the text of Lines[LineIndex-1] and Lines[LineIndex]
+ //
+ // Sets StartOfLineColumn to the intended column in which the text at
+ // Lines[LineIndex] starts (note that the decoration, if present, is not
+ // considered part of the text).
+ void adjustWhitespace(unsigned LineIndex, int IndentDelta);
+
+ // Returns the column at which the text in line LineIndex starts, when broken
+ // at TailOffset. Note that the decoration (if present) is not considered part
+ // of the text.
+ unsigned getContentStartColumn(unsigned LineIndex, unsigned TailOffset) const;
+
+ // Contains the text of the lines of the block comment, excluding the leading
+ // /* in the first line and trailing */ in the last line, and excluding all
+ // trailing whitespace between the lines. Note that the decoration (if
+ // present) is also not considered part of the text.
+ SmallVector<StringRef, 16> Lines;
-class BreakableLineComment : public BreakableComment {
-public:
- BreakableLineComment(const SourceManager &SourceMgr,
- const AnnotatedToken &Token, unsigned StartColumn);
+ // LeadingWhitespace[i] is the number of characters regarded as whitespace in
+ // front of Lines[i]. Note that this can include "* " sequences, which we
+ // regard as whitespace when all lines have a "*" prefix.
+ SmallVector<unsigned, 16> LeadingWhitespace;
+
+ // StartOfLineColumn[i] is the target column at which Line[i] should be.
+ // Note that this excludes a leading "* " or "*" in case all lines have
+ // a "*" prefix.
+ SmallVector<unsigned, 16> StartOfLineColumn;
+
+ // The column at which the text of a broken line should start.
+ // Note that an optional decoration would go before that column.
+ // IndentAtLineBreak is a uniform position for all lines in a block comment,
+ // regardless of their relative position.
+ // FIXME: Revisit the decision to do this; the main reason was to support
+ // patterns like
+ // /**************//**
+ // * Comment
+ // We could also support such patterns by special casing the first line
+ // instead.
+ unsigned IndentAtLineBreak;
-private:
- static StringRef getLineCommentPrefix(StringRef Comment);
+ // This is to distinguish between the case when the last line was empty and
+ // the case when it started with a decoration ("*" or "* ").
+ bool LastLineNeedsDecoration;
+
+ // Either "* " if all lines begin with a "*", or empty.
+ StringRef Decoration;
};
} // namespace format
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index 560e38b4bfaa..e3ef5bd21ee9 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -2,7 +2,9 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangFormat
BreakableToken.cpp
+ ContinuationIndenter.cpp
Format.cpp
+ FormatToken.cpp
TokenAnnotator.cpp
UnwrappedLineParser.cpp
WhitespaceManager.cpp
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
new file mode 100644
index 000000000000..971acc2b7a3c
--- /dev/null
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -0,0 +1,884 @@
+//===--- ContinuationIndenter.cpp - Format C++ code -----------------------===//
+//
+// 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 the continuation indenter.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-formatter"
+
+#include "BreakableToken.h"
+#include "ContinuationIndenter.h"
+#include "WhitespaceManager.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include <string>
+
+namespace clang {
+namespace format {
+
+// Returns the length of everything up to the first possible line break after
+// the ), ], } or > matching \c Tok.
+static unsigned getLengthToMatchingParen(const FormatToken &Tok) {
+ if (Tok.MatchingParen == NULL)
+ return 0;
+ FormatToken *End = Tok.MatchingParen;
+ while (End->Next && !End->Next->CanBreakBefore) {
+ End = End->Next;
+ }
+ return End->TotalLength - Tok.TotalLength + 1;
+}
+
+// Returns \c true if \c Tok is the "." or "->" of a call and starts the next
+// segment of a builder type call.
+static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
+ return Tok.isMemberAccess() && Tok.Previous && Tok.Previous->closesScope();
+}
+
+// Returns \c true if \c Current starts a new parameter.
+static bool startsNextParameter(const FormatToken &Current,
+ const FormatStyle &Style) {
+ const FormatToken &Previous = *Current.Previous;
+ if (Current.Type == TT_CtorInitializerComma &&
+ Style.BreakConstructorInitializersBeforeComma)
+ return true;
+ return Previous.is(tok::comma) && !Current.isTrailingComment() &&
+ (Previous.Type != TT_CtorInitializerComma ||
+ !Style.BreakConstructorInitializersBeforeComma);
+}
+
+ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
+ SourceManager &SourceMgr,
+ WhitespaceManager &Whitespaces,
+ encoding::Encoding Encoding,
+ bool BinPackInconclusiveFunctions)
+ : Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces),
+ Encoding(Encoding),
+ BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {}
+
+LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
+ const AnnotatedLine *Line,
+ bool DryRun) {
+ LineState State;
+ State.FirstIndent = FirstIndent;
+ State.Column = FirstIndent;
+ State.Line = Line;
+ State.NextToken = Line->First;
+ State.Stack.push_back(ParenState(FirstIndent, Line->Level, FirstIndent,
+ /*AvoidBinPacking=*/false,
+ /*NoLineBreak=*/false));
+ State.LineContainsContinuedForLoopSection = false;
+ State.ParenLevel = 0;
+ State.StartOfStringLiteral = 0;
+ State.StartOfLineLevel = State.ParenLevel;
+ State.LowestLevelOnLine = State.ParenLevel;
+ State.IgnoreStackForComparison = false;
+
+ // The first token has already been indented and thus consumed.
+ moveStateToNextToken(State, DryRun, /*Newline=*/false);
+ return State;
+}
+
+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.closesBlockTypeList(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.
+ if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
+ Previous.Type != TT_DictLiteral &&
+ Previous.BlockKind == BK_BracedInit && Previous.Previous &&
+ Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
+ return false;
+ // This prevents breaks like:
+ // ...
+ // SomeParameter, OtherParameter).DoSomething(
+ // ...
+ // As they hide "DoSomething" and are generally bad for readability.
+ if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel)
+ return false;
+ if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder)
+ return false;
+ return !State.Stack.back().NoLineBreak;
+}
+
+bool ContinuationIndenter::mustBreak(const LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *Current.Previous;
+ if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
+ return true;
+ if (State.Stack.back().BreakBeforeClosingBrace &&
+ Current.closesBlockTypeList(Style))
+ return true;
+ if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
+ return true;
+ if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
+ (Style.BreakBeforeTernaryOperators &&
+ (Current.is(tok::question) || (Current.Type == TT_ConditionalExpr &&
+ Previous.isNot(tok::question)))) ||
+ (!Style.BreakBeforeTernaryOperators &&
+ (Previous.is(tok::question) || Previous.Type == TT_ConditionalExpr))) &&
+ State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() &&
+ !Current.isOneOf(tok::r_paren, tok::r_brace))
+ return true;
+ if (Style.AlwaysBreakBeforeMultilineStrings &&
+ State.Column > State.Stack.back().Indent && // Breaking saves columns.
+ !Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) &&
+ Previous.Type != TT_InlineASMColon && NextIsMultilineString(State))
+ return true;
+ if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
+ Previous.Type == TT_ArrayInitializerLSquare) &&
+ getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
+ return true;
+
+ if (!Style.BreakBeforeBinaryOperators) {
+ // If we need to break somewhere inside the LHS of a binary expression, we
+ // should also break after the operator. Otherwise, the formatting would
+ // hide the operator precedence, e.g. in:
+ // if (aaaaaaaaaaaaaa ==
+ // bbbbbbbbbbbbbb && c) {..
+ // For comparisons, we only apply this rule, if the LHS is a binary
+ // expression itself as otherwise, the line breaks seem superfluous.
+ // We need special cases for ">>" which we have split into two ">" while
+ // lexing in order to make template parsing easier.
+ //
+ // FIXME: We'll need something similar for styles that break before binary
+ // operators.
+ bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
+ Previous.getPrecedence() == prec::Equality) &&
+ Previous.Previous &&
+ Previous.Previous->Type != TT_BinaryOperator; // For >>.
+ bool LHSIsBinaryExpr =
+ Previous.Previous && Previous.Previous->EndsBinaryExpression;
+ if (Previous.Type == TT_BinaryOperator &&
+ (!IsComparison || LHSIsBinaryExpr) &&
+ Current.Type != TT_BinaryOperator && // For >>.
+ !Current.isTrailingComment() &&
+ !Previous.isOneOf(tok::lessless, tok::question) &&
+ Previous.getPrecedence() != prec::Assignment &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ }
+
+ // Same as above, but for the first "<<" operator.
+ if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter &&
+ State.Stack.back().FirstLessLess == 0)
+ return true;
+
+ // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
+ // out whether it is the first parameter. Clean this up.
+ if (Current.Type == TT_ObjCSelectorName &&
+ Current.LongestObjCSelectorName == 0 &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ if ((Current.Type == TT_CtorInitializerColon ||
+ (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 &&
+ !Current.isTrailingComment())))
+ return true;
+
+ if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
+ State.Line->MightBeFunctionDecl &&
+ State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0)
+ return true;
+ if (startsSegmentOfBuilderTypeCall(Current) &&
+ (State.Stack.back().CallContinuation != 0 ||
+ (State.Stack.back().BreakBeforeParameter &&
+ State.Stack.back().ContainsUnwrappedBuilder)))
+ return true;
+ return false;
+}
+
+unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
+ bool DryRun,
+ unsigned ExtraSpaces) {
+ const FormatToken &Current = *State.NextToken;
+
+ if (State.Stack.size() == 0 ||
+ (Current.Type == TT_ImplicitStringLiteral &&
+ (Current.Previous->Tok.getIdentifierInfo() == NULL ||
+ Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
+ tok::pp_not_keyword))) {
+ // FIXME: Is this correct?
+ int WhitespaceLength = SourceMgr.getSpellingColumnNumber(
+ State.NextToken->WhitespaceRange.getEnd()) -
+ SourceMgr.getSpellingColumnNumber(
+ State.NextToken->WhitespaceRange.getBegin());
+ State.Column += WhitespaceLength + State.NextToken->ColumnWidth;
+ State.NextToken = State.NextToken->Next;
+ return 0;
+ }
+
+ unsigned Penalty = 0;
+ if (Newline)
+ Penalty = addTokenOnNewLine(State, DryRun);
+ else
+ addTokenOnCurrentLine(State, DryRun, ExtraSpaces);
+
+ return moveStateToNextToken(State, DryRun, Newline) + Penalty;
+}
+
+void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
+ unsigned ExtraSpaces) {
+ FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *State.NextToken->Previous;
+ if (Current.is(tok::equal) &&
+ (State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) &&
+ State.Stack.back().VariablePos == 0) {
+ State.Stack.back().VariablePos = State.Column;
+ // Move over * and & if they are bound to the variable name.
+ const FormatToken *Tok = &Previous;
+ while (Tok && State.Stack.back().VariablePos >= Tok->ColumnWidth) {
+ State.Stack.back().VariablePos -= Tok->ColumnWidth;
+ if (Tok->SpacesRequiredBefore != 0)
+ break;
+ Tok = Tok->Previous;
+ }
+ if (Previous.PartOfMultiVariableDeclStmt)
+ State.Stack.back().LastSpace = State.Stack.back().VariablePos;
+ }
+
+ unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces;
+
+ if (!DryRun)
+ Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
+ Spaces, State.Column + Spaces);
+
+ if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) {
+ if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.ColumnWidth)
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ else
+ State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
+ }
+
+ if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
+ Current.Type != TT_LineComment)
+ State.Stack.back().Indent = State.Column + Spaces;
+ if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
+ State.Stack.back().NoLineBreak = true;
+ if (startsSegmentOfBuilderTypeCall(Current))
+ State.Stack.back().ContainsUnwrappedBuilder = true;
+
+ State.Column += Spaces;
+ if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
+ // 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 + 1; // 1 is length of "(".
+ else if (Previous.is(tok::comma) || Previous.Type == TT_ObjCMethodExpr)
+ State.Stack.back().LastSpace = State.Column;
+ else if ((Previous.Type == TT_BinaryOperator ||
+ Previous.Type == TT_ConditionalExpr ||
+ Previous.Type == TT_UnaryOperator ||
+ Previous.Type == TT_CtorInitializerColon) &&
+ (Previous.getPrecedence() != prec::Assignment ||
+ Current.StartsBinaryExpression))
+ // Always indent relative to the RHS of the expression unless this is a
+ // simple assignment without binary expression on the RHS. Also indent
+ // relative to unary operators and the colons of constructor initializers.
+ State.Stack.back().LastSpace = State.Column;
+ else if (Previous.Type == TT_InheritanceColon) {
+ State.Stack.back().Indent = State.Column;
+ State.Stack.back().LastSpace = State.Column;
+ } else if (Previous.opensScope()) {
+ // If a function has a trailing call, indent all parameters from the
+ // opening parenthesis. This avoids confusing indents like:
+ // OuterFunction(InnerFunctionCall( // break
+ // ParameterToInnerFunction)) // break
+ // .SecondInnerFunctionCall();
+ bool HasTrailingCall = false;
+ if (Previous.MatchingParen) {
+ const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
+ HasTrailingCall = Next && Next->isMemberAccess();
+ }
+ if (HasTrailingCall &&
+ State.Stack[State.Stack.size() - 2].CallContinuation == 0)
+ State.Stack.back().LastSpace = State.Column;
+ }
+}
+
+unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
+ bool DryRun) {
+ FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *State.NextToken->Previous;
+ // If we are continuing an expression, we want to use the continuation indent.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
+ Style.ContinuationIndentWidth;
+ // Extra penalty that needs to be added because of the way certain line
+ // breaks are chosen.
+ unsigned Penalty = 0;
+
+ const FormatToken *PreviousNonComment =
+ State.NextToken->getPreviousNonComment();
+ // The first line break on any ParenLevel causes an extra penalty in order
+ // prefer similar line breaks.
+ if (!State.Stack.back().ContainsLineBreak)
+ Penalty += 15;
+ State.Stack.back().ContainsLineBreak = true;
+
+ Penalty += State.NextToken->SplitPenalty;
+
+ // Breaking before the first "<<" is generally not desirable if the LHS is
+ // short.
+ if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 &&
+ State.Column <= Style.ColumnLimit / 2)
+ Penalty += Style.PenaltyBreakFirstLessLess;
+
+ if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
+ State.Column = State.FirstIndent;
+ } else if (Current.isOneOf(tok::r_brace, tok::r_square)) {
+ if (Current.closesBlockTypeList(Style) ||
+ (Current.MatchingParen &&
+ Current.MatchingParen->BlockKind == BK_BracedInit))
+ State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
+ else
+ State.Column = State.FirstIndent;
+ } else if (Current.is(tok::string_literal) &&
+ State.StartOfStringLiteral != 0) {
+ State.Column = State.StartOfStringLiteral;
+ State.Stack.back().BreakBeforeParameter = true;
+ } else if (Current.is(tok::lessless) &&
+ State.Stack.back().FirstLessLess != 0) {
+ State.Column = State.Stack.back().FirstLessLess;
+ } else if (Current.isMemberAccess()) {
+ if (State.Stack.back().CallContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().CallContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().CallContinuation;
+ }
+ } else if (State.Stack.back().QuestionColumn != 0 &&
+ (Current.Type == TT_ConditionalExpr ||
+ Previous.Type == TT_ConditionalExpr)) {
+ State.Column = State.Stack.back().QuestionColumn;
+ } else if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) {
+ State.Column = State.Stack.back().VariablePos;
+ } else if ((PreviousNonComment &&
+ PreviousNonComment->ClosesTemplateDeclaration) ||
+ ((Current.Type == TT_StartOfName ||
+ Current.is(tok::kw_operator)) &&
+ State.ParenLevel == 0 &&
+ (!Style.IndentFunctionDeclarationAfterType ||
+ State.Line->StartsDefinition))) {
+ State.Column = State.Stack.back().Indent;
+ } else if (Current.Type == TT_ObjCSelectorName) {
+ if (State.Stack.back().ColonPos == 0) {
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
+ } else if (State.Stack.back().ColonPos > Current.ColumnWidth) {
+ State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
+ }
+ } else if (Current.Type == TT_ArraySubscriptLSquare) {
+ if (State.Stack.back().StartOfArraySubscripts != 0)
+ State.Column = State.Stack.back().StartOfArraySubscripts;
+ else
+ State.Column = ContinuationIndent;
+ } else if (Current.Type == TT_StartOfName ||
+ Previous.isOneOf(tok::coloncolon, tok::equal) ||
+ Previous.Type == TT_ObjCMethodExpr) {
+ State.Column = ContinuationIndent;
+ } else if (Current.Type == TT_CtorInitializerColon) {
+ State.Column = State.FirstIndent + Style.ConstructorInitializerIndentWidth;
+ } else if (Current.Type == TT_CtorInitializerComma) {
+ State.Column = State.Stack.back().Indent;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ // Ensure that we fall back to the continuation indent width instead of just
+ // flushing continuations left.
+ if (State.Column == State.FirstIndent &&
+ PreviousNonComment->isNot(tok::r_brace))
+ State.Column += Style.ContinuationIndentWidth;
+ }
+
+ if ((Previous.isOneOf(tok::comma, tok::semi) &&
+ !State.Stack.back().AvoidBinPacking) ||
+ Previous.Type == TT_BinaryOperator)
+ State.Stack.back().BreakBeforeParameter = false;
+ if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
+ State.Stack.back().BreakBeforeParameter = false;
+ if (Current.is(tok::question) ||
+ (PreviousNonComment && PreviousNonComment->is(tok::question)))
+ State.Stack.back().BreakBeforeParameter = true;
+
+ if (!DryRun) {
+ unsigned Newlines = 1;
+ if (Current.is(tok::comment))
+ Newlines = std::max(Newlines, std::min(Current.NewlinesBefore,
+ Style.MaxEmptyLinesToKeep + 1));
+ Whitespaces.replaceWhitespace(Current, Newlines,
+ State.Stack.back().IndentLevel, State.Column,
+ State.Column, State.Line->InPPDirective);
+ }
+
+ if (!Current.isTrailingComment())
+ State.Stack.back().LastSpace = State.Column;
+ if (Current.isMemberAccess())
+ State.Stack.back().LastSpace += Current.ColumnWidth;
+ State.StartOfLineLevel = State.ParenLevel;
+ State.LowestLevelOnLine = State.ParenLevel;
+
+ // Any break on this level means that the parent level has been broken
+ // and we need to avoid bin packing there.
+ 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->Type != TT_TemplateCloser &&
+ PreviousNonComment->Type != TT_BinaryOperator &&
+ Current.Type != TT_BinaryOperator &&
+ !PreviousNonComment->opensScope())
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // If we break after { or the [ of an array initializer, we should also break
+ // before the corresponding } or ].
+ if (Previous.is(tok::l_brace) || Previous.Type == TT_ArrayInitializerLSquare)
+ State.Stack.back().BreakBeforeClosingBrace = true;
+
+ if (State.Stack.back().AvoidBinPacking) {
+ // If we are breaking after '(', '{', '<', this is not bin packing
+ // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
+ Previous.Type == TT_BinaryOperator) ||
+ (!Style.AllowAllParametersOfDeclarationOnNextLine &&
+ State.Line->MustBeDeclaration))
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
+ return Penalty;
+}
+
+unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
+ bool DryRun, bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ assert(State.Stack.size());
+
+ if (Current.Type == TT_InheritanceColon)
+ State.Stack.back().AvoidBinPacking = true;
+ if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
+ State.Stack.back().FirstLessLess = State.Column;
+ if (Current.Type == TT_ArraySubscriptLSquare &&
+ State.Stack.back().StartOfArraySubscripts == 0)
+ State.Stack.back().StartOfArraySubscripts = State.Column;
+ if ((Current.is(tok::question) && Style.BreakBeforeTernaryOperators) ||
+ (Current.getPreviousNonComment() && Current.isNot(tok::colon) &&
+ Current.getPreviousNonComment()->is(tok::question) &&
+ !Style.BreakBeforeTernaryOperators))
+ State.Stack.back().QuestionColumn = State.Column;
+ if (!Current.opensScope() && !Current.closesScope())
+ State.LowestLevelOnLine =
+ std::min(State.LowestLevelOnLine, State.ParenLevel);
+ if (Current.isMemberAccess())
+ State.Stack.back().StartOfFunctionCall =
+ Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+ if (Current.Type == TT_CtorInitializerColon) {
+ // Indent 2 from the column, so:
+ // SomeClass::SomeClass()
+ // : First(...), ...
+ // Next(...)
+ // ^ line up here.
+ State.Stack.back().Indent =
+ State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = false;
+ }
+
+ // In ObjC method declaration we align on the ":" of parameters, but we need
+ // to ensure that we indent parameters on subsequent lines by at least our
+ // continuation indent width.
+ if (Current.Type == TT_ObjCMethodSpecifier)
+ State.Stack.back().Indent += Style.ContinuationIndentWidth;
+
+ // Insert scopes created by fake parenthesis.
+ const FormatToken *Previous = Current.getPreviousNonComment();
+ // Don't add extra indentation for the first fake parenthesis after
+ // 'return', assignements or opening <({[. The indentation for these cases
+ // is special cased.
+ bool SkipFirstExtraIndent =
+ (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
+ Previous->getPrecedence() == prec::Assignment ||
+ Previous->Type == TT_ObjCMethodExpr));
+ for (SmallVectorImpl<prec::Level>::const_reverse_iterator
+ I = Current.FakeLParens.rbegin(),
+ E = Current.FakeLParens.rend();
+ I != E; ++I) {
+ ParenState NewParenState = State.Stack.back();
+ NewParenState.ContainsLineBreak = false;
+
+ // Indent from 'LastSpace' unless this the fake parentheses encapsulating a
+ // builder type call after 'return'. If such a call is line-wrapped, we
+ // commonly just want to indent from the start of the line.
+ if (!Previous || Previous->isNot(tok::kw_return) || *I > 0)
+ NewParenState.Indent =
+ std::max(std::max(State.Column, NewParenState.Indent),
+ State.Stack.back().LastSpace);
+
+ // Do not indent relative to the fake parentheses inserted for "." or "->".
+ // This is a special case to make the following to statements consistent:
+ // OuterFunction(InnerFunctionCall( // break
+ // ParameterToInnerFunction));
+ // OuterFunction(SomeObject.InnerFunctionCall( // break
+ // ParameterToInnerFunction));
+ if (*I > prec::Unknown)
+ NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
+
+ // Always indent conditional expressions. Never indent expression where
+ // the 'operator' is ',', ';' or an assignment (i.e. *I <=
+ // prec::Assignment) as those have different indentation rules. Indent
+ // other expression, unless the indentation needs to be skipped.
+ if (*I == prec::Conditional ||
+ (!SkipFirstExtraIndent && *I > prec::Assignment &&
+ !Style.BreakBeforeBinaryOperators))
+ NewParenState.Indent += Style.ContinuationIndentWidth;
+ if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
+ NewParenState.BreakBeforeParameter = false;
+ State.Stack.push_back(NewParenState);
+ SkipFirstExtraIndent = false;
+ }
+
+ // If we encounter an opening (, [, { or <, we add a level to our stacks to
+ // prepare for the following tokens.
+ if (Current.opensScope()) {
+ unsigned NewIndent;
+ unsigned NewIndentLevel = State.Stack.back().IndentLevel;
+ bool AvoidBinPacking;
+ bool BreakBeforeParameter = false;
+ if (Current.is(tok::l_brace) ||
+ Current.Type == TT_ArrayInitializerLSquare) {
+ if (Current.MatchingParen && Current.BlockKind == BK_Block) {
+ // If this is an l_brace starting a nested block, we pretend (wrt. to
+ // indentation) that we already consumed the corresponding r_brace.
+ // Thus, we remove all ParenStates caused bake fake parentheses that end
+ // at the r_brace. The net effect of this is that we don't indent
+ // relative to the l_brace, if the nested block is the last parameter of
+ // a function. For example, this formats:
+ //
+ // SomeFunction(a, [] {
+ // f(); // break
+ // });
+ //
+ // instead of:
+ // SomeFunction(a, [] {
+ // f(); // break
+ // });
+ for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i)
+ State.Stack.pop_back();
+ NewIndent = State.Stack.back().LastSpace + Style.IndentWidth;
+ ++NewIndentLevel;
+ BreakBeforeParameter = true;
+ } else {
+ NewIndent = State.Stack.back().LastSpace;
+ if (Current.opensBlockTypeList(Style)) {
+ NewIndent += Style.IndentWidth;
+ ++NewIndentLevel;
+ } else {
+ NewIndent += Style.ContinuationIndentWidth;
+ }
+ }
+ const FormatToken *NextNoComment = Current.getNextNonComment();
+ AvoidBinPacking = Current.BlockKind == BK_Block ||
+ Current.Type == TT_ArrayInitializerLSquare ||
+ Current.Type == TT_DictLiteral ||
+ (NextNoComment &&
+ NextNoComment->Type == TT_DesignatedInitializerPeriod);
+ } else {
+ NewIndent = Style.ContinuationIndentWidth +
+ std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking = !Style.BinPackParameters ||
+ (Style.ExperimentalAutoDetectBinPacking &&
+ (Current.PackingKind == PPK_OnePerLine ||
+ (!BinPackInconclusiveFunctions &&
+ Current.PackingKind == PPK_Inconclusive)));
+ // If this '[' opens an ObjC call, determine whether all parameters fit
+ // into one line and put one per line if they don't.
+ if (Current.Type == TT_ObjCMethodExpr &&
+ getLengthToMatchingParen(Current) + State.Column >
+ getColumnLimit(State))
+ BreakBeforeParameter = true;
+ }
+
+ bool NoLineBreak = State.Stack.back().NoLineBreak ||
+ (Current.Type == TT_TemplateOpener &&
+ State.Stack.back().ContainsUnwrappedBuilder);
+ State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
+ State.Stack.back().LastSpace,
+ AvoidBinPacking, NoLineBreak));
+ State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
+ ++State.ParenLevel;
+ }
+
+ // If we encounter a closing ), ], } or >, we can remove a level from our
+ // stacks.
+ if (State.Stack.size() > 1 &&
+ (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
+ State.NextToken->Type == TT_TemplateCloser)) {
+ State.Stack.pop_back();
+ --State.ParenLevel;
+ }
+ if (Current.is(tok::r_square)) {
+ // If this ends the array subscript expr, reset the corresponding value.
+ const FormatToken *NextNonComment = Current.getNextNonComment();
+ if (NextNonComment && NextNonComment->isNot(tok::l_square))
+ State.Stack.back().StartOfArraySubscripts = 0;
+ }
+
+ // Remove scopes created by fake parenthesis.
+ if (Current.isNot(tok::r_brace) ||
+ (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
+ // Don't remove FakeRParens attached to r_braces that surround nested blocks
+ // as they will have been removed early (see above).
+ for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
+ unsigned VariablePos = State.Stack.back().VariablePos;
+ State.Stack.pop_back();
+ State.Stack.back().VariablePos = VariablePos;
+ }
+ }
+
+ if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
+ State.StartOfStringLiteral = State.Column;
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
+ tok::string_literal)) {
+ State.StartOfStringLiteral = 0;
+ }
+
+ State.Column += Current.ColumnWidth;
+ State.NextToken = State.NextToken->Next;
+ unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
+ if (State.Column > getColumnLimit(State)) {
+ unsigned ExcessCharacters = State.Column - getColumnLimit(State);
+ Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
+ }
+
+ // If the previous has a special role, let it consume tokens as appropriate.
+ // It is necessary to start at the previous token for the only implemented
+ // role (comma separated list). That way, the decision whether or not to break
+ // after the "{" is already done and both options are tried and evaluated.
+ // FIXME: This is ugly, find a better way.
+ if (Previous && Previous->Role)
+ Penalty += Previous->Role->format(State, this, DryRun);
+
+ return Penalty;
+}
+
+unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
+ LineState &State) {
+ // Break before further function parameters on all levels.
+ for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
+ State.Stack[i].BreakBeforeParameter = true;
+
+ unsigned ColumnsUsed = State.Column;
+ // We can only affect layout of the first and the last line, so the penalty
+ // for all other lines is constant, and we ignore it.
+ State.Column = Current.LastLineColumnWidth;
+
+ if (ColumnsUsed > getColumnLimit(State))
+ return Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit(State));
+ return 0;
+}
+
+static bool getRawStringLiteralPrefixPostfix(StringRef Text,
+ StringRef &Prefix,
+ StringRef &Postfix) {
+ if (Text.startswith(Prefix = "R\"") || Text.startswith(Prefix = "uR\"") ||
+ Text.startswith(Prefix = "UR\"") || Text.startswith(Prefix = "u8R\"") ||
+ Text.startswith(Prefix = "LR\"")) {
+ size_t ParenPos = Text.find('(');
+ if (ParenPos != StringRef::npos) {
+ StringRef Delimiter =
+ Text.substr(Prefix.size(), ParenPos - Prefix.size());
+ Prefix = Text.substr(0, ParenPos + 1);
+ Postfix = Text.substr(Text.size() - 2 - Delimiter.size());
+ return Postfix.front() == ')' && Postfix.back() == '"' &&
+ Postfix.substr(1).startswith(Delimiter);
+ }
+ }
+ return false;
+}
+
+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.Type != TT_BlockComment && Current.IsMultiline)
+ return addMultilineToken(Current, State);
+
+ // Don't break implicit string literals.
+ if (Current.Type == TT_ImplicitStringLiteral)
+ return 0;
+
+ if (!Current.isOneOf(tok::string_literal, tok::wide_string_literal,
+ tok::utf8_string_literal, tok::utf16_string_literal,
+ tok::utf32_string_literal, tok::comment))
+ return 0;
+
+ llvm::OwningPtr<BreakableToken> Token;
+ unsigned StartColumn = State.Column - Current.ColumnWidth;
+ unsigned ColumnLimit = getColumnLimit(State);
+
+ if (Current.isOneOf(tok::string_literal, tok::wide_string_literal,
+ tok::utf8_string_literal, tok::utf16_string_literal,
+ tok::utf32_string_literal) &&
+ Current.Type != TT_ImplicitStringLiteral) {
+ // Don't break string literals inside preprocessor directives (except for
+ // #define directives, as their contents are stored in separate lines and
+ // are not affected by this check).
+ // This way we avoid breaking code with line directives and unknown
+ // preprocessor directives that contain long string literals.
+ if (State.Line->Type == LT_PreprocessorDirective)
+ return 0;
+ // Exempts unterminated string literals from line breaking. The user will
+ // likely want to terminate the string before any line breaking is done.
+ if (Current.IsUnterminatedLiteral)
+ return 0;
+
+ StringRef Text = Current.TokenText;
+ StringRef Prefix;
+ StringRef Postfix;
+ // 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.endswith(Postfix = "\"") &&
+ (Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") ||
+ Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") ||
+ Text.startswith(Prefix = "L\""))) ||
+ (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
+ getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
+ Token.reset(new BreakableStringLiteral(
+ Current, State.Line->Level, StartColumn, Prefix, Postfix,
+ State.Line->InPPDirective, Encoding, Style));
+ } else {
+ return 0;
+ }
+ } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ Token.reset(new BreakableBlockComment(
+ Current, State.Line->Level, StartColumn, Current.OriginalColumn,
+ !Current.Previous, State.Line->InPPDirective, Encoding, Style));
+ } else if (Current.Type == TT_LineComment &&
+ (Current.Previous == NULL ||
+ Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ Token.reset(new BreakableLineComment(Current, State.Line->Level,
+ StartColumn, /*InPPDirective=*/false,
+ Encoding, Style));
+ // We don't insert backslashes when breaking line comments.
+ ColumnLimit = Style.ColumnLimit;
+ } else {
+ return 0;
+ }
+ if (Current.UnbreakableTailLength >= ColumnLimit)
+ return 0;
+
+ unsigned RemainingSpace = ColumnLimit - Current.UnbreakableTailLength;
+ bool BreakInserted = false;
+ unsigned Penalty = 0;
+ unsigned RemainingTokenColumns = 0;
+ for (unsigned LineIndex = 0, EndIndex = Token->getLineCount();
+ LineIndex != EndIndex; ++LineIndex) {
+ if (!DryRun)
+ Token->replaceWhitespaceBefore(LineIndex, Whitespaces);
+ unsigned TailOffset = 0;
+ RemainingTokenColumns =
+ Token->getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ while (RemainingTokenColumns > RemainingSpace) {
+ BreakableToken::Split Split =
+ Token->getSplit(LineIndex, TailOffset, ColumnLimit);
+ if (Split.first == StringRef::npos) {
+ // The last line's penalty is handled in addNextStateToQueue().
+ if (LineIndex < EndIndex - 1)
+ Penalty += Style.PenaltyExcessCharacter *
+ (RemainingTokenColumns - RemainingSpace);
+ break;
+ }
+ assert(Split.first != 0);
+ unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit(
+ LineIndex, TailOffset + Split.first + Split.second, StringRef::npos);
+
+ // We can remove extra whitespace instead of breaking the line.
+ if (RemainingTokenColumns + 1 - Split.second <= RemainingSpace) {
+ RemainingTokenColumns = 0;
+ if (!DryRun)
+ Token->replaceWhitespace(LineIndex, TailOffset, Split, Whitespaces);
+ break;
+ }
+
+ assert(NewRemainingTokenColumns < RemainingTokenColumns);
+ if (!DryRun)
+ Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
+ Penalty += Current.SplitPenalty;
+ unsigned ColumnsUsed =
+ Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first);
+ if (ColumnsUsed > ColumnLimit) {
+ Penalty += Style.PenaltyExcessCharacter * (ColumnsUsed - ColumnLimit);
+ }
+ TailOffset += Split.first + Split.second;
+ RemainingTokenColumns = NewRemainingTokenColumns;
+ BreakInserted = true;
+ }
+ }
+
+ State.Column = RemainingTokenColumns;
+
+ if (BreakInserted) {
+ // If we break the token inside a parameter list, we need to break before
+ // the next parameter on all levels, so that the next parameter is clearly
+ // visible. Line comments already introduce a break.
+ if (Current.Type != TT_LineComment) {
+ for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+
+ Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString
+ : Style.PenaltyBreakComment;
+
+ State.Stack.back().LastSpace = StartColumn;
+ }
+ return Penalty;
+}
+
+unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0);
+}
+
+bool ContinuationIndenter::NextIsMultilineString(const LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ if (!Current.is(tok::string_literal))
+ return false;
+ // We never consider raw string literals "multiline" for the purpose of
+ // AlwaysBreakBeforeMultilineStrings implementation.
+ if (Current.TokenText.startswith("R\""))
+ return false;
+ if (Current.IsMultiline)
+ return true;
+ if (Current.getNextNonComment() &&
+ Current.getNextNonComment()->is(tok::string_literal))
+ return true; // Implicit concatenation.
+ if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength >
+ Style.ColumnLimit)
+ return true; // String will be split.
+ return false;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
new file mode 100644
index 000000000000..b31756583389
--- /dev/null
+++ b/lib/Format/ContinuationIndenter.h
@@ -0,0 +1,327 @@
+//===--- ContinuationIndenter.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 implements an indenter that manages the indentation of
+/// continuations.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+#define LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+
+#include "Encoding.h"
+#include "clang/Format/Format.h"
+
+namespace clang {
+class SourceManager;
+
+namespace format {
+
+class AnnotatedLine;
+struct FormatToken;
+struct LineState;
+struct ParenState;
+class WhitespaceManager;
+
+class ContinuationIndenter {
+public:
+ /// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
+ /// column \p FirstIndent.
+ ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr,
+ WhitespaceManager &Whitespaces,
+ encoding::Encoding Encoding,
+ 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);
+
+ // FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a
+ // better home.
+ /// \brief Returns \c true, if a line break after \p State is allowed.
+ bool canBreak(const LineState &State);
+
+ /// \brief Returns \c true, if a line break after \p State is mandatory.
+ bool mustBreak(const LineState &State);
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Puts the token on the current line if \p Newline is \c false and adds a
+ /// line break and necessary indentation otherwise.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ unsigned addTokenToState(LineState &State, bool Newline, bool DryRun,
+ unsigned ExtraSpaces = 0);
+
+ /// \brief Get the column limit for this line. This is the style's column
+ /// limit, potentially reduced for preprocessor definitions.
+ unsigned getColumnLimit(const LineState &State) const;
+
+private:
+ /// \brief Mark the next token as consumed in \p State and modify its stacks
+ /// accordingly.
+ unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline);
+
+ /// \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.
+ unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
+ bool DryRun);
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Puts the token on the current line.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ void addTokenOnCurrentLine(LineState &State, bool DryRun,
+ unsigned ExtraSpaces);
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Adds a line break and necessary indentation.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ unsigned addTokenOnNewLine(LineState &State, bool DryRun);
+
+ /// \brief Adds a multiline token to the \p State.
+ ///
+ /// \returns Extra penalty for the first line of the literal: last line is
+ /// handled in \c addNextStateToQueue, and the penalty for other lines doesn't
+ /// matter, as we don't change them.
+ unsigned addMultilineToken(const FormatToken &Current, LineState &State);
+
+ /// \brief Returns \c true if the next token starts a multiline string
+ /// literal.
+ ///
+ /// This includes implicitly concatenated strings, strings that will be broken
+ /// by clang-format and string literals with escaped newlines.
+ bool NextIsMultilineString(const LineState &State);
+
+ FormatStyle Style;
+ SourceManager &SourceMgr;
+ WhitespaceManager &Whitespaces;
+ encoding::Encoding Encoding;
+ bool BinPackInconclusiveFunctions;
+};
+
+struct ParenState {
+ ParenState(unsigned Indent, unsigned IndentLevel, unsigned LastSpace,
+ bool AvoidBinPacking, bool NoLineBreak)
+ : Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
+ FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
+ AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
+ NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
+ StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
+ CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
+ ContainsUnwrappedBuilder(0) {}
+
+ /// \brief The position to which a specific parenthesis level needs to be
+ /// indented.
+ unsigned Indent;
+
+ /// \brief The number of indentation levels of the block.
+ unsigned IndentLevel;
+
+ /// \brief The position of the last space on each level.
+ ///
+ /// Used e.g. to break like:
+ /// functionCall(Parameter, otherCall(
+ /// OtherParameter));
+ unsigned LastSpace;
+
+ /// \brief The position the first "<<" operator encountered on each level.
+ ///
+ /// Used to align "<<" operators. 0 if no such operator has been encountered
+ /// on a level.
+ unsigned FirstLessLess;
+
+ /// \brief Whether a newline needs to be inserted before the block's closing
+ /// brace.
+ ///
+ /// We only want to insert a newline before the closing brace if there also
+ /// was a newline after the beginning left brace.
+ bool BreakBeforeClosingBrace;
+
+ /// \brief The column of a \c ? in a conditional expression;
+ unsigned QuestionColumn;
+
+ /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
+ /// lines, in this context.
+ bool AvoidBinPacking;
+
+ /// \brief Break after the next comma (or all the commas in this context if
+ /// \c AvoidBinPacking is \c true).
+ bool BreakBeforeParameter;
+
+ /// \brief Line breaking in this context would break a formatting rule.
+ bool NoLineBreak;
+
+ /// \brief The position of the colon in an ObjC method declaration/call.
+ unsigned ColonPos;
+
+ /// \brief The start of the most recent function in a builder-type call.
+ unsigned StartOfFunctionCall;
+
+ /// \brief Contains the start of array subscript expressions, so that they
+ /// can be aligned.
+ unsigned StartOfArraySubscripts;
+
+ /// \brief If a nested name specifier was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned NestedNameSpecifierContinuation;
+
+ /// \brief If a call expression was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned CallContinuation;
+
+ /// \brief The column of the first variable name in a variable declaration.
+ ///
+ /// Used to align further variables if necessary.
+ unsigned VariablePos;
+
+ /// \brief \c true if this \c ParenState already contains a line-break.
+ ///
+ /// The first line break in a certain \c ParenState causes extra penalty so
+ /// that clang-format prefers similar breaks, i.e. breaks in the same
+ /// parenthesis.
+ bool ContainsLineBreak;
+
+ /// \brief \c true if this \c ParenState contains multiple segments of a
+ /// builder-type call on one line.
+ bool ContainsUnwrappedBuilder;
+
+ bool operator<(const ParenState &Other) const {
+ if (Indent != Other.Indent)
+ return Indent < Other.Indent;
+ if (LastSpace != Other.LastSpace)
+ return LastSpace < Other.LastSpace;
+ if (FirstLessLess != Other.FirstLessLess)
+ return FirstLessLess < Other.FirstLessLess;
+ if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
+ return BreakBeforeClosingBrace;
+ if (QuestionColumn != Other.QuestionColumn)
+ return QuestionColumn < Other.QuestionColumn;
+ if (AvoidBinPacking != Other.AvoidBinPacking)
+ return AvoidBinPacking;
+ if (BreakBeforeParameter != Other.BreakBeforeParameter)
+ return BreakBeforeParameter;
+ if (NoLineBreak != Other.NoLineBreak)
+ return NoLineBreak;
+ if (ColonPos != Other.ColonPos)
+ return ColonPos < Other.ColonPos;
+ if (StartOfFunctionCall != Other.StartOfFunctionCall)
+ return StartOfFunctionCall < Other.StartOfFunctionCall;
+ if (StartOfArraySubscripts != Other.StartOfArraySubscripts)
+ return StartOfArraySubscripts < Other.StartOfArraySubscripts;
+ if (CallContinuation != Other.CallContinuation)
+ return CallContinuation < Other.CallContinuation;
+ if (VariablePos != Other.VariablePos)
+ return VariablePos < Other.VariablePos;
+ if (ContainsLineBreak != Other.ContainsLineBreak)
+ return ContainsLineBreak < Other.ContainsLineBreak;
+ if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
+ return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
+ return false;
+ }
+};
+
+/// \brief The current state when indenting a unwrapped line.
+///
+/// As the indenting tries different combinations this is copied by value.
+struct LineState {
+ /// \brief The number of used columns in the current line.
+ unsigned Column;
+
+ /// \brief The token that needs to be next formatted.
+ FormatToken *NextToken;
+
+ /// \brief \c true if this line contains a continued for-loop section.
+ bool LineContainsContinuedForLoopSection;
+
+ /// \brief The level of nesting inside (), [], <> and {}.
+ unsigned ParenLevel;
+
+ /// \brief The \c ParenLevel at the start of this line.
+ unsigned StartOfLineLevel;
+
+ /// \brief The lowest \c ParenLevel on the current line.
+ unsigned LowestLevelOnLine;
+
+ /// \brief The start column of the string literal, if we're in a string
+ /// literal sequence, 0 otherwise.
+ unsigned StartOfStringLiteral;
+
+ /// \brief A stack keeping track of properties applying to parenthesis
+ /// levels.
+ std::vector<ParenState> Stack;
+
+ /// \brief Ignore the stack of \c ParenStates for state comparison.
+ ///
+ /// In long and deeply nested unwrapped lines, the current algorithm can
+ /// be insufficient for finding the best formatting with a reasonable amount
+ /// of time and memory. Setting this flag will effectively lead to the
+ /// algorithm not analyzing some combinations. However, these combinations
+ /// rarely contain the optimal solution: In short, accepting a higher
+ /// penalty early would need to lead to different values in the \c
+ /// ParenState stack (in an otherwise identical state) and these different
+ /// values would need to lead to a significant amount of avoided penalty
+ /// later.
+ ///
+ /// FIXME: Come up with a better algorithm instead.
+ bool IgnoreStackForComparison;
+
+ /// \brief The indent of the first token.
+ unsigned FirstIndent;
+
+ /// \brief The line that is being formatted.
+ ///
+ /// Does not need to be considered for memoization because it doesn't change.
+ const AnnotatedLine *Line;
+
+ /// \brief Comparison operator to be able to used \c LineState in \c map.
+ bool operator<(const LineState &Other) const {
+ if (NextToken != Other.NextToken)
+ return NextToken < Other.NextToken;
+ if (Column != Other.Column)
+ return Column < Other.Column;
+ if (LineContainsContinuedForLoopSection !=
+ Other.LineContainsContinuedForLoopSection)
+ return LineContainsContinuedForLoopSection;
+ if (ParenLevel != Other.ParenLevel)
+ return ParenLevel < Other.ParenLevel;
+ if (StartOfLineLevel != Other.StartOfLineLevel)
+ return StartOfLineLevel < Other.StartOfLineLevel;
+ if (LowestLevelOnLine != Other.LowestLevelOnLine)
+ return LowestLevelOnLine < Other.LowestLevelOnLine;
+ if (StartOfStringLiteral != Other.StartOfStringLiteral)
+ return StartOfStringLiteral < Other.StartOfStringLiteral;
+ if (IgnoreStackForComparison || Other.IgnoreStackForComparison)
+ return false;
+ return Stack < Other.Stack;
+ }
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h
new file mode 100644
index 000000000000..356334d5376f
--- /dev/null
+++ b/lib/Format/Encoding.h
@@ -0,0 +1,144 @@
+//===--- Encoding.h - Format C++ code -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Contains functions for text encoding manipulation. Supports UTF-8,
+/// 8-bit encodings and escape sequences in C++ string literals.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_ENCODING_H
+#define LLVM_CLANG_FORMAT_ENCODING_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Unicode.h"
+
+namespace clang {
+namespace format {
+namespace encoding {
+
+enum Encoding {
+ Encoding_UTF8,
+ Encoding_Unknown // We treat all other encodings as 8-bit encodings.
+};
+
+/// \brief Detects encoding of the Text. If the Text can be decoded using UTF-8,
+/// it is considered UTF8, otherwise we treat it as some 8-bit encoding.
+inline Encoding detectEncoding(StringRef Text) {
+ const UTF8 *Ptr = reinterpret_cast<const UTF8 *>(Text.begin());
+ const UTF8 *BufEnd = reinterpret_cast<const UTF8 *>(Text.end());
+ if (::isLegalUTF8String(&Ptr, BufEnd))
+ return Encoding_UTF8;
+ return Encoding_Unknown;
+}
+
+inline unsigned getCodePointCountUTF8(StringRef Text) {
+ unsigned CodePoints = 0;
+ for (size_t i = 0, e = Text.size(); i < e; i += getNumBytesForUTF8(Text[i])) {
+ ++CodePoints;
+ }
+ return CodePoints;
+}
+
+/// \brief Gets the number of code points in the Text using the specified
+/// Encoding.
+inline unsigned getCodePointCount(StringRef Text, Encoding Encoding) {
+ switch (Encoding) {
+ case Encoding_UTF8:
+ return getCodePointCountUTF8(Text);
+ default:
+ return Text.size();
+ }
+}
+
+/// \brief Returns the number of columns required to display the \p Text on a
+/// generic Unicode-capable terminal. Text is assumed to use the specified
+/// \p Encoding.
+inline unsigned columnWidth(StringRef Text, Encoding Encoding) {
+ if (Encoding == Encoding_UTF8) {
+ int ContentWidth = llvm::sys::unicode::columnWidthUTF8(Text);
+ if (ContentWidth >= 0)
+ return ContentWidth;
+ }
+ return Text.size();
+}
+
+/// \brief Returns the number of columns required to display the \p Text,
+/// starting from the \p StartColumn on a terminal with the \p TabWidth. The
+/// text is assumed to use the specified \p Encoding.
+inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn,
+ unsigned TabWidth, Encoding Encoding) {
+ unsigned TotalWidth = 0;
+ StringRef Tail = Text;
+ for (;;) {
+ StringRef::size_type TabPos = Tail.find('\t');
+ if (TabPos == StringRef::npos)
+ return TotalWidth + columnWidth(Tail, Encoding);
+ int Width = columnWidth(Tail.substr(0, TabPos), Encoding);
+ assert(Width >= 0);
+ TotalWidth += Width;
+ TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
+ Tail = Tail.substr(TabPos + 1);
+ }
+}
+
+/// \brief Gets the number of bytes in a sequence representing a single
+/// codepoint and starting with FirstChar in the specified Encoding.
+inline unsigned getCodePointNumBytes(char FirstChar, Encoding Encoding) {
+ switch (Encoding) {
+ case Encoding_UTF8:
+ return getNumBytesForUTF8(FirstChar);
+ default:
+ return 1;
+ }
+}
+
+inline bool isOctDigit(char c) { return '0' <= c && c <= '7'; }
+
+inline bool isHexDigit(char c) {
+ return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F');
+}
+
+/// \brief Gets the length of an escape sequence inside a C++ string literal.
+/// Text should span from the beginning of the escape sequence (starting with a
+/// backslash) to the end of the string literal.
+inline unsigned getEscapeSequenceLength(StringRef Text) {
+ assert(Text[0] == '\\');
+ if (Text.size() < 2)
+ return 1;
+
+ switch (Text[1]) {
+ case 'u':
+ return 6;
+ case 'U':
+ return 10;
+ case 'x': {
+ unsigned I = 2; // Point after '\x'.
+ while (I < Text.size() && isHexDigit(Text[I]))
+ ++I;
+ return I;
+ }
+ default:
+ if (isOctDigit(Text[1])) {
+ unsigned I = 1;
+ while (I < Text.size() && I < 4 && isOctDigit(Text[I]))
+ ++I;
+ return I;
+ }
+ return 2;
+ }
+}
+
+} // namespace encoding
+} // namespace format
+} // namespace clang
+
+#endif // LLVM_CLANG_FORMAT_ENCODING_H
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index a0557f781824..01c122ecc7bf 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -15,43 +15,219 @@
#define DEBUG_TYPE "format-formatter"
-#include "BreakableToken.h"
+#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/Path.h"
#include <queue>
#include <string>
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> {
+ static void enumeration(IO &IO,
+ clang::format::FormatStyle::LanguageStandard &Value) {
+ IO.enumCase(Value, "Cpp03", clang::format::FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "Cpp11", clang::format::FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::UseTabStyle> {
+ static void enumeration(IO &IO,
+ clang::format::FormatStyle::UseTabStyle &Value) {
+ IO.enumCase(Value, "Never", clang::format::FormatStyle::UT_Never);
+ IO.enumCase(Value, "false", clang::format::FormatStyle::UT_Never);
+ IO.enumCase(Value, "Always", clang::format::FormatStyle::UT_Always);
+ IO.enumCase(Value, "true", clang::format::FormatStyle::UT_Always);
+ IO.enumCase(Value, "ForIndentation",
+ clang::format::FormatStyle::UT_ForIndentation);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> {
+ static void
+ enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) {
+ IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach);
+ IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux);
+ IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup);
+ IO.enumCase(Value, "Allman", clang::format::FormatStyle::BS_Allman);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<
+ clang::format::FormatStyle::NamespaceIndentationKind> {
+ static void
+ enumeration(IO &IO,
+ clang::format::FormatStyle::NamespaceIndentationKind &Value) {
+ IO.enumCase(Value, "None", clang::format::FormatStyle::NI_None);
+ IO.enumCase(Value, "Inner", clang::format::FormatStyle::NI_Inner);
+ IO.enumCase(Value, "All", clang::format::FormatStyle::NI_All);
+ }
+};
+
+template <> struct MappingTraits<clang::format::FormatStyle> {
+ static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) {
+ if (IO.outputting()) {
+ StringRef StylesArray[] = { "LLVM", "Google", "Chromium",
+ "Mozilla", "WebKit" };
+ ArrayRef<StringRef> Styles(StylesArray);
+ for (size_t i = 0, e = Styles.size(); i < e; ++i) {
+ StringRef StyleName(Styles[i]);
+ clang::format::FormatStyle PredefinedStyle;
+ if (clang::format::getPredefinedStyle(StyleName, &PredefinedStyle) &&
+ Style == PredefinedStyle) {
+ IO.mapOptional("# BasedOnStyle", StyleName);
+ break;
+ }
+ }
+ } else {
+ StringRef BasedOnStyle;
+ IO.mapOptional("BasedOnStyle", BasedOnStyle);
+ if (!BasedOnStyle.empty())
+ if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) {
+ IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
+ return;
+ }
+ }
+
+ IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
+ IO.mapOptional("ConstructorInitializerIndentWidth",
+ Style.ConstructorInitializerIndentWidth);
+ IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
+ IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
+ IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
+ Style.AllowAllParametersOfDeclarationOnNextLine);
+ IO.mapOptional("AllowShortIfStatementsOnASingleLine",
+ Style.AllowShortIfStatementsOnASingleLine);
+ IO.mapOptional("AllowShortLoopsOnASingleLine",
+ Style.AllowShortLoopsOnASingleLine);
+ IO.mapOptional("AlwaysBreakTemplateDeclarations",
+ Style.AlwaysBreakTemplateDeclarations);
+ IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
+ Style.AlwaysBreakBeforeMultilineStrings);
+ IO.mapOptional("BreakBeforeBinaryOperators",
+ Style.BreakBeforeBinaryOperators);
+ IO.mapOptional("BreakBeforeTernaryOperators",
+ Style.BreakBeforeTernaryOperators);
+ IO.mapOptional("BreakConstructorInitializersBeforeComma",
+ Style.BreakConstructorInitializersBeforeComma);
+ IO.mapOptional("BinPackParameters", Style.BinPackParameters);
+ IO.mapOptional("ColumnLimit", Style.ColumnLimit);
+ IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
+ Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
+ IO.mapOptional("DerivePointerBinding", Style.DerivePointerBinding);
+ IO.mapOptional("ExperimentalAutoDetectBinPacking",
+ Style.ExperimentalAutoDetectBinPacking);
+ IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
+ IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+ IO.mapOptional("ObjCSpaceBeforeProtocolList",
+ Style.ObjCSpaceBeforeProtocolList);
+ IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
+ Style.PenaltyBreakBeforeFirstCallParameter);
+ IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
+ IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
+ IO.mapOptional("PenaltyBreakFirstLessLess",
+ Style.PenaltyBreakFirstLessLess);
+ IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
+ IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
+ Style.PenaltyReturnTypeOnItsOwnLine);
+ IO.mapOptional("PointerBindsToType", Style.PointerBindsToType);
+ IO.mapOptional("SpacesBeforeTrailingComments",
+ Style.SpacesBeforeTrailingComments);
+ IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
+ IO.mapOptional("Standard", Style.Standard);
+ IO.mapOptional("IndentWidth", Style.IndentWidth);
+ IO.mapOptional("TabWidth", Style.TabWidth);
+ IO.mapOptional("UseTab", Style.UseTab);
+ IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
+ IO.mapOptional("IndentFunctionDeclarationAfterType",
+ Style.IndentFunctionDeclarationAfterType);
+ IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
+ IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
+ IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
+ IO.mapOptional("SpacesInCStyleCastParentheses",
+ Style.SpacesInCStyleCastParentheses);
+ IO.mapOptional("SpaceAfterControlStatementKeyword",
+ Style.SpaceAfterControlStatementKeyword);
+ IO.mapOptional("SpaceBeforeAssignmentOperators",
+ Style.SpaceBeforeAssignmentOperators);
+ IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
+ }
+};
+}
+}
+
namespace clang {
namespace format {
+void setDefaultPenalties(FormatStyle &Style) {
+ Style.PenaltyBreakComment = 60;
+ Style.PenaltyBreakFirstLessLess = 120;
+ Style.PenaltyBreakString = 1000;
+ Style.PenaltyExcessCharacter = 1000000;
+}
+
FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlinesLeft = false;
+ LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
+ LLVMStyle.AllowShortLoopsOnASingleLine = false;
+ LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
+ LLVMStyle.AlwaysBreakTemplateDeclarations = false;
LLVMStyle.BinPackParameters = true;
+ LLVMStyle.BreakBeforeBinaryOperators = false;
+ LLVMStyle.BreakBeforeTernaryOperators = true;
+ LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
+ LLVMStyle.BreakConstructorInitializersBeforeComma = false;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
+ LLVMStyle.ConstructorInitializerIndentWidth = 4;
+ LLVMStyle.Cpp11BracedListStyle = false;
LLVMStyle.DerivePointerBinding = false;
+ LLVMStyle.ExperimentalAutoDetectBinPacking = false;
LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.IndentFunctionDeclarationAfterType = false;
+ LLVMStyle.IndentWidth = 2;
+ LLVMStyle.TabWidth = 8;
LLVMStyle.MaxEmptyLinesToKeep = 1;
+ LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
- LLVMStyle.PenaltyExcessCharacter = 1000000;
- LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 75;
LLVMStyle.PointerBindsToType = false;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.UseTab = FormatStyle::UT_Never;
+ LLVMStyle.SpacesInParentheses = false;
+ LLVMStyle.SpaceInEmptyParentheses = false;
+ LLVMStyle.SpacesInCStyleCastParentheses = false;
+ LLVMStyle.SpaceAfterControlStatementKeyword = true;
+ LLVMStyle.SpaceBeforeAssignmentOperators = true;
+ LLVMStyle.ContinuationIndentWidth = 4;
+ LLVMStyle.SpacesInAngles = false;
+
+ setDefaultPenalties(LLVMStyle);
+ LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
+ LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
+
return LLVMStyle;
}
@@ -59,20 +235,46 @@ FormatStyle getGoogleStyle() {
FormatStyle GoogleStyle;
GoogleStyle.AccessModifierOffset = -1;
GoogleStyle.AlignEscapedNewlinesLeft = true;
+ GoogleStyle.AlignTrailingComments = true;
GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
+ GoogleStyle.AllowShortLoopsOnASingleLine = true;
+ GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
+ GoogleStyle.AlwaysBreakTemplateDeclarations = true;
GoogleStyle.BinPackParameters = true;
+ GoogleStyle.BreakBeforeBinaryOperators = false;
+ GoogleStyle.BreakBeforeTernaryOperators = true;
+ GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
+ GoogleStyle.BreakConstructorInitializersBeforeComma = false;
GoogleStyle.ColumnLimit = 80;
GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ GoogleStyle.ConstructorInitializerIndentWidth = 4;
+ GoogleStyle.Cpp11BracedListStyle = true;
GoogleStyle.DerivePointerBinding = true;
+ GoogleStyle.ExperimentalAutoDetectBinPacking = false;
GoogleStyle.IndentCaseLabels = true;
+ GoogleStyle.IndentFunctionDeclarationAfterType = true;
+ GoogleStyle.IndentWidth = 2;
+ GoogleStyle.TabWidth = 8;
GoogleStyle.MaxEmptyLinesToKeep = 1;
+ GoogleStyle.NamespaceIndentation = FormatStyle::NI_None;
GoogleStyle.ObjCSpaceBeforeProtocolList = false;
- GoogleStyle.PenaltyExcessCharacter = 1000000;
- GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
GoogleStyle.PointerBindsToType = true;
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
+ GoogleStyle.UseTab = FormatStyle::UT_Never;
+ GoogleStyle.SpacesInParentheses = false;
+ GoogleStyle.SpaceInEmptyParentheses = false;
+ GoogleStyle.SpacesInCStyleCastParentheses = false;
+ GoogleStyle.SpaceAfterControlStatementKeyword = true;
+ GoogleStyle.SpaceBeforeAssignmentOperators = true;
+ GoogleStyle.ContinuationIndentWidth = 4;
+ GoogleStyle.SpacesInAngles = false;
+
+ setDefaultPenalties(GoogleStyle);
+ GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
+ GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
+
return GoogleStyle;
}
@@ -80,9 +282,10 @@ FormatStyle getChromiumStyle() {
FormatStyle ChromiumStyle = getGoogleStyle();
ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
+ ChromiumStyle.AllowShortLoopsOnASingleLine = false;
ChromiumStyle.BinPackParameters = false;
- ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
ChromiumStyle.DerivePointerBinding = false;
+ ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
return ChromiumStyle;
}
@@ -98,614 +301,376 @@ FormatStyle getMozillaStyle() {
return MozillaStyle;
}
-// Returns the length of everything up to the first possible line break after
-// the ), ], } or > matching \c Tok.
-static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) {
- if (Tok.MatchingParen == NULL)
- return 0;
- AnnotatedToken *End = Tok.MatchingParen;
- while (!End->Children.empty() && !End->Children[0].CanBreakBefore) {
- End = &End->Children[0];
- }
- return End->TotalLength - Tok.TotalLength + 1;
+FormatStyle getWebKitStyle() {
+ FormatStyle Style = getLLVMStyle();
+ Style.AccessModifierOffset = -4;
+ Style.AlignTrailingComments = false;
+ Style.BreakBeforeBinaryOperators = true;
+ Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ Style.BreakConstructorInitializersBeforeComma = true;
+ Style.ColumnLimit = 0;
+ Style.IndentWidth = 4;
+ Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ Style.PointerBindsToType = true;
+ return Style;
}
-class UnwrappedLineFormatter {
-public:
- UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
- const AnnotatedLine &Line, unsigned FirstIndent,
- const AnnotatedToken &RootToken,
- WhitespaceManager &Whitespaces)
- : Style(Style), SourceMgr(SourceMgr), Line(Line),
- FirstIndent(FirstIndent), RootToken(RootToken),
- Whitespaces(Whitespaces), Count(0) {}
-
- /// \brief Formats an \c UnwrappedLine.
- ///
- /// \returns The column after the last token in the last line of the
- /// \c UnwrappedLine.
- unsigned format(const AnnotatedLine *NextLine) {
- // Initialize state dependent on indent.
- LineState State;
- State.Column = FirstIndent;
- State.NextToken = &RootToken;
- State.Stack.push_back(
- ParenState(FirstIndent, FirstIndent, !Style.BinPackParameters,
- /*NoLineBreak=*/ false));
- State.LineContainsContinuedForLoopSection = false;
- State.ParenLevel = 0;
- State.StartOfStringLiteral = 0;
- State.StartOfLineLevel = State.ParenLevel;
-
- // The first token has already been indented and thus consumed.
- moveStateToNextToken(State, /*DryRun=*/ false);
-
- // If everything fits on a single line, just put it there.
- unsigned ColumnLimit = Style.ColumnLimit;
- if (NextLine && NextLine->InPPDirective &&
- !NextLine->First.FormatTok.HasUnescapedNewline)
- ColumnLimit = getColumnLimit();
- if (Line.Last->TotalLength <= ColumnLimit - FirstIndent) {
- while (State.NextToken != NULL) {
- addTokenToState(false, false, State);
- }
- return State.Column;
- }
-
- // If the ObjC method declaration does not fit on a line, we should format
- // it with one arg per line.
- if (Line.Type == LT_ObjCMethodDecl)
- State.Stack.back().BreakBeforeParameter = true;
+bool getPredefinedStyle(StringRef Name, FormatStyle *Style) {
+ if (Name.equals_lower("llvm"))
+ *Style = getLLVMStyle();
+ else if (Name.equals_lower("chromium"))
+ *Style = getChromiumStyle();
+ else if (Name.equals_lower("mozilla"))
+ *Style = getMozillaStyle();
+ else if (Name.equals_lower("google"))
+ *Style = getGoogleStyle();
+ else if (Name.equals_lower("webkit"))
+ *Style = getWebKitStyle();
+ else
+ return false;
- // Find best solution in solution space.
- return analyzeSolutionSpace(State);
- }
+ return true;
+}
-private:
- void DebugTokenState(const AnnotatedToken &AnnotatedTok) {
- const Token &Tok = AnnotatedTok.FormatTok.Tok;
- llvm::errs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
- Tok.getLength());
- llvm::errs();
- }
+llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+ if (Text.trim().empty())
+ return llvm::make_error_code(llvm::errc::invalid_argument);
+ llvm::yaml::Input Input(Text);
+ Input >> *Style;
+ return Input.error();
+}
- struct ParenState {
- ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
- bool NoLineBreak)
- : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
- BreakBeforeClosingBrace(false), QuestionColumn(0),
- AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- NestedNameSpecifierContinuation(0), CallContinuation(0),
- VariablePos(0) {}
-
- /// \brief The position to which a specific parenthesis level needs to be
- /// indented.
- unsigned Indent;
-
- /// \brief The position of the last space on each level.
- ///
- /// Used e.g. to break like:
- /// functionCall(Parameter, otherCall(
- /// OtherParameter));
- unsigned LastSpace;
-
- /// \brief The position the first "<<" operator encountered on each level.
- ///
- /// Used to align "<<" operators. 0 if no such operator has been encountered
- /// on a level.
- unsigned FirstLessLess;
-
- /// \brief Whether a newline needs to be inserted before the block's closing
- /// brace.
- ///
- /// We only want to insert a newline before the closing brace if there also
- /// was a newline after the beginning left brace.
- bool BreakBeforeClosingBrace;
-
- /// \brief The column of a \c ? in a conditional expression;
- unsigned QuestionColumn;
-
- /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
- /// lines, in this context.
- bool AvoidBinPacking;
-
- /// \brief Break after the next comma (or all the commas in this context if
- /// \c AvoidBinPacking is \c true).
- bool BreakBeforeParameter;
-
- /// \brief Line breaking in this context would break a formatting rule.
- bool NoLineBreak;
-
- /// \brief The position of the colon in an ObjC method declaration/call.
- unsigned ColonPos;
-
- /// \brief The start of the most recent function in a builder-type call.
- unsigned StartOfFunctionCall;
-
- /// \brief If a nested name specifier was broken over multiple lines, this
- /// contains the start column of the second line. Otherwise 0.
- unsigned NestedNameSpecifierContinuation;
-
- /// \brief If a call expression was broken over multiple lines, this
- /// contains the start column of the second line. Otherwise 0.
- unsigned CallContinuation;
-
- /// \brief The column of the first variable name in a variable declaration.
- ///
- /// Used to align further variables if necessary.
- unsigned VariablePos;
-
- bool operator<(const ParenState &Other) const {
- if (Indent != Other.Indent)
- return Indent < Other.Indent;
- if (LastSpace != Other.LastSpace)
- return LastSpace < Other.LastSpace;
- if (FirstLessLess != Other.FirstLessLess)
- return FirstLessLess < Other.FirstLessLess;
- if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
- return BreakBeforeClosingBrace;
- if (QuestionColumn != Other.QuestionColumn)
- return QuestionColumn < Other.QuestionColumn;
- if (AvoidBinPacking != Other.AvoidBinPacking)
- return AvoidBinPacking;
- if (BreakBeforeParameter != Other.BreakBeforeParameter)
- return BreakBeforeParameter;
- if (NoLineBreak != Other.NoLineBreak)
- return NoLineBreak;
- if (ColonPos != Other.ColonPos)
- return ColonPos < Other.ColonPos;
- if (StartOfFunctionCall != Other.StartOfFunctionCall)
- return StartOfFunctionCall < Other.StartOfFunctionCall;
- if (NestedNameSpecifierContinuation !=
- Other.NestedNameSpecifierContinuation)
- return NestedNameSpecifierContinuation <
- Other.NestedNameSpecifierContinuation;
- if (CallContinuation != Other.CallContinuation)
- return CallContinuation < Other.CallContinuation;
- if (VariablePos != Other.VariablePos)
- return VariablePos < Other.VariablePos;
- return false;
- }
- };
+std::string configurationAsText(const FormatStyle &Style) {
+ std::string Text;
+ llvm::raw_string_ostream Stream(Text);
+ llvm::yaml::Output Output(Stream);
+ // We use the same mapping method for input and output, so we need a non-const
+ // reference here.
+ FormatStyle NonConstStyle = Style;
+ Output << NonConstStyle;
+ return Stream.str();
+}
- /// \brief The current state when indenting a unwrapped line.
- ///
- /// As the indenting tries different combinations this is copied by value.
- struct LineState {
- /// \brief The number of used columns in the current line.
- unsigned Column;
-
- /// \brief The token that needs to be next formatted.
- const AnnotatedToken *NextToken;
-
- /// \brief \c true if this line contains a continued for-loop section.
- bool LineContainsContinuedForLoopSection;
-
- /// \brief The level of nesting inside (), [], <> and {}.
- unsigned ParenLevel;
-
- /// \brief The \c ParenLevel at the start of this line.
- unsigned StartOfLineLevel;
-
- /// \brief The start column of the string literal, if we're in a string
- /// literal sequence, 0 otherwise.
- unsigned StartOfStringLiteral;
-
- /// \brief A stack keeping track of properties applying to parenthesis
- /// levels.
- std::vector<ParenState> Stack;
-
- /// \brief Comparison operator to be able to used \c LineState in \c map.
- bool operator<(const LineState &Other) const {
- if (NextToken != Other.NextToken)
- return NextToken < Other.NextToken;
- if (Column != Other.Column)
- return Column < Other.Column;
- if (LineContainsContinuedForLoopSection !=
- Other.LineContainsContinuedForLoopSection)
- return LineContainsContinuedForLoopSection;
- if (ParenLevel != Other.ParenLevel)
- return ParenLevel < Other.ParenLevel;
- if (StartOfLineLevel != Other.StartOfLineLevel)
- return StartOfLineLevel < Other.StartOfLineLevel;
- if (StartOfStringLiteral != Other.StartOfStringLiteral)
- return StartOfStringLiteral < Other.StartOfStringLiteral;
- return Stack < Other.Stack;
- }
- };
+namespace {
- /// \brief Appends the next token to \p State and updates information
- /// necessary for indentation.
- ///
- /// Puts the token on the current line if \p Newline is \c true and adds a
- /// line break and necessary indentation otherwise.
- ///
- /// If \p DryRun is \c false, also creates and stores the required
- /// \c Replacement.
- unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) {
- const AnnotatedToken &Current = *State.NextToken;
- const AnnotatedToken &Previous = *State.NextToken->Parent;
-
- if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
- State.Column += State.NextToken->FormatTok.WhiteSpaceLength +
- State.NextToken->FormatTok.TokenLength;
- if (State.NextToken->Children.empty())
- State.NextToken = NULL;
- else
- State.NextToken = &State.NextToken->Children[0];
- return 0;
+class NoColumnLimitFormatter {
+public:
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
+
+ /// \brief Formats the line starting at \p State, simply keeping all of the
+ /// input's line breaking decisions.
+ void format(unsigned FirstIndent, const AnnotatedLine *Line) {
+ LineState State =
+ Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
+ while (State.NextToken != NULL) {
+ bool Newline =
+ Indenter->mustBreak(State) ||
+ (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
+ Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
}
+ }
- // If we are continuing an expression, we want to indent an extra 4 spaces.
- unsigned ContinuationIndent =
- std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4;
- if (Newline) {
- unsigned WhitespaceStartColumn = State.Column;
- if (Current.is(tok::r_brace)) {
- State.Column = Line.Level * 2;
- } else if (Current.is(tok::string_literal) &&
- State.StartOfStringLiteral != 0) {
- State.Column = State.StartOfStringLiteral;
- State.Stack.back().BreakBeforeParameter = true;
- } else if (Current.is(tok::lessless) &&
- State.Stack.back().FirstLessLess != 0) {
- State.Column = State.Stack.back().FirstLessLess;
- } else if (Previous.is(tok::coloncolon)) {
- if (State.Stack.back().NestedNameSpecifierContinuation == 0) {
- State.Column = ContinuationIndent;
- State.Stack.back().NestedNameSpecifierContinuation = State.Column;
- } else {
- State.Column = State.Stack.back().NestedNameSpecifierContinuation;
- }
- } else if (Current.isOneOf(tok::period, tok::arrow)) {
- if (State.Stack.back().CallContinuation == 0) {
- State.Column = ContinuationIndent;
- State.Stack.back().CallContinuation = State.Column;
- } else {
- State.Column = State.Stack.back().CallContinuation;
- }
- } else if (Current.Type == TT_ConditionalExpr) {
- State.Column = State.Stack.back().QuestionColumn;
- } else if (Previous.is(tok::comma) &&
- State.Stack.back().VariablePos != 0) {
- State.Column = State.Stack.back().VariablePos;
- } else if (Previous.ClosesTemplateDeclaration ||
- (Current.Type == TT_StartOfName && State.ParenLevel == 0 &&
- Line.StartsDefinition)) {
- State.Column = State.Stack.back().Indent;
- } else if (Current.Type == TT_ObjCSelectorName) {
- if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) {
- State.Column =
- State.Stack.back().ColonPos - Current.FormatTok.TokenLength;
- } else {
- State.Column = State.Stack.back().Indent;
- State.Stack.back().ColonPos =
- State.Column + Current.FormatTok.TokenLength;
- }
- } else if (Current.Type == TT_StartOfName || Previous.is(tok::equal) ||
- Previous.Type == TT_ObjCMethodExpr) {
- State.Column = ContinuationIndent;
- } else {
- State.Column = State.Stack.back().Indent;
- // Ensure that we fall back to indenting 4 spaces instead of just
- // flushing continuations left.
- if (State.Column == FirstIndent)
- State.Column += 4;
- }
-
- if (Current.is(tok::question))
- State.Stack.back().BreakBeforeParameter = true;
- if (Previous.isOneOf(tok::comma, tok::semi) &&
- !State.Stack.back().AvoidBinPacking)
- State.Stack.back().BreakBeforeParameter = false;
-
- if (!DryRun) {
- unsigned NewLines = 1;
- if (Current.Type == TT_LineComment)
- NewLines =
- std::max(NewLines, std::min(Current.FormatTok.NewlinesBefore,
- Style.MaxEmptyLinesToKeep + 1));
- if (!Line.InPPDirective)
- Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
- WhitespaceStartColumn);
- else
- Whitespaces.replacePPWhitespace(Current, NewLines, State.Column,
- WhitespaceStartColumn);
- }
+private:
+ ContinuationIndenter *Indenter;
+};
- State.Stack.back().LastSpace = State.Column;
- State.StartOfLineLevel = State.ParenLevel;
+class LineJoiner {
+public:
+ LineJoiner(const FormatStyle &Style) : Style(Style) {}
- // Any break on this level means that the parent level has been broken
- // and we need to avoid bin packing there.
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].BreakBeforeParameter = true;
- }
- const AnnotatedToken *TokenBefore = Current.getPreviousNoneComment();
- if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) &&
- !TokenBefore->opensScope())
- State.Stack.back().BreakBeforeParameter = true;
-
- // If we break after {, we should also break before the corresponding }.
- if (Previous.is(tok::l_brace))
- State.Stack.back().BreakBeforeClosingBrace = true;
-
- if (State.Stack.back().AvoidBinPacking) {
- // If we are breaking after '(', '{', '<', this is not bin packing
- // unless AllowAllParametersOfDeclarationOnNextLine is false.
- if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace)) ||
- (!Style.AllowAllParametersOfDeclarationOnNextLine &&
- Line.MustBeDeclaration))
- State.Stack.back().BreakBeforeParameter = true;
- }
- } else {
- if (Current.is(tok::equal) &&
- (RootToken.is(tok::kw_for) || State.ParenLevel == 0) &&
- State.Stack.back().VariablePos == 0) {
- State.Stack.back().VariablePos = State.Column;
- // Move over * and & if they are bound to the variable name.
- const AnnotatedToken *Tok = &Previous;
- while (Tok &&
- State.Stack.back().VariablePos >= Tok->FormatTok.TokenLength) {
- State.Stack.back().VariablePos -= Tok->FormatTok.TokenLength;
- if (Tok->SpacesRequiredBefore != 0)
- break;
- Tok = Tok->Parent;
- }
- if (Previous.PartOfMultiVariableDeclStmt)
- State.Stack.back().LastSpace = State.Stack.back().VariablePos;
- }
+ /// \brief Calculates how many lines can be merged into 1 starting at \p I.
+ unsigned
+ tryFitMultipleLinesInOne(unsigned Indent,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ // We can never merge stuff if there are trailing line comments.
+ AnnotatedLine *TheLine = *I;
+ if (TheLine->Last->Type == TT_LineComment)
+ return 0;
- unsigned Spaces = State.NextToken->SpacesRequiredBefore;
+ if (Indent > Style.ColumnLimit)
+ return 0;
- if (!DryRun)
- Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column);
+ unsigned Limit =
+ Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
+ // If we already exceed the column limit, we set 'Limit' to 0. The different
+ // tryMerge..() functions can then decide whether to still do merging.
+ Limit = TheLine->Last->TotalLength > Limit
+ ? 0
+ : Limit - TheLine->Last->TotalLength;
- if (Current.Type == TT_ObjCSelectorName &&
- State.Stack.back().ColonPos == 0) {
- if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
- State.Column + Spaces + Current.FormatTok.TokenLength)
- State.Stack.back().ColonPos =
- State.Stack.back().Indent + Current.LongestObjCSelectorName;
- else
- State.Stack.back().ColonPos =
- State.Column + Spaces + Current.FormatTok.TokenLength;
- }
+ if (I + 1 == E || I[1]->Type == LT_Invalid)
+ return 0;
- if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- Current.Type != TT_LineComment)
- State.Stack.back().Indent = State.Column + Spaces;
- if (Previous.is(tok::comma) && !Current.isTrailingComment() &&
- State.Stack.back().AvoidBinPacking)
- State.Stack.back().NoLineBreak = true;
-
- State.Column += Spaces;
- if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
- // Treat the condition inside an if as if it was a second function
- // parameter, i.e. let nested calls have an indent of 4.
- State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
- else if (Previous.is(tok::comma))
- State.Stack.back().LastSpace = State.Column;
- else if ((Previous.Type == TT_BinaryOperator ||
- Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_CtorInitializerColon) &&
- getPrecedence(Previous) != prec::Assignment)
- State.Stack.back().LastSpace = State.Column;
- else if (Previous.Type == TT_InheritanceColon)
- State.Stack.back().Indent = State.Column;
- else if (Previous.opensScope() && Previous.ParameterCount > 1)
- // If this function has multiple parameters, indent nested calls from
- // the start of the first parameter.
- State.Stack.back().LastSpace = State.Column;
+ if (TheLine->Last->is(tok::l_brace)) {
+ return tryMergeSimpleBlock(I, E, Limit);
+ } else if (Style.AllowShortIfStatementsOnASingleLine &&
+ TheLine->First->is(tok::kw_if)) {
+ return tryMergeSimpleControlStatement(I, E, Limit);
+ } else if (Style.AllowShortLoopsOnASingleLine &&
+ TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
+ return tryMergeSimpleControlStatement(I, E, Limit);
+ } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline ||
+ TheLine->First->IsFirst)) {
+ return tryMergeSimplePPDirective(I, E, Limit);
}
+ return 0;
+ }
- return moveStateToNextToken(State, DryRun);
+private:
+ unsigned
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
+ return 0;
+ if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ return 1;
}
- /// \brief Mark the next token as consumed in \p State and modify its stacks
- /// accordingly.
- unsigned moveStateToNextToken(LineState &State, bool DryRun) {
- const AnnotatedToken &Current = *State.NextToken;
- assert(State.Stack.size());
-
- if (Current.Type == TT_InheritanceColon)
- State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
- State.Stack.back().FirstLessLess = State.Column;
- if (Current.is(tok::question))
- State.Stack.back().QuestionColumn = State.Column;
- if (Current.isOneOf(tok::period, tok::arrow) &&
- Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
- State.Stack.back().StartOfFunctionCall =
- Current.LastInChainOfCalls ? 0 : State.Column;
- if (Current.Type == TT_CtorInitializerColon) {
- State.Stack.back().Indent = State.Column + 2;
- if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
- State.Stack.back().AvoidBinPacking = true;
- State.Stack.back().BreakBeforeParameter = false;
- }
+ unsigned tryMergeSimpleControlStatement(
+ SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman &&
+ I[1]->First->is(tok::l_brace))
+ return 0;
+ if (I[1]->InPPDirective != (*I)->InPPDirective ||
+ (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
+ return 0;
+ AnnotatedLine &Line = **I;
+ if (Line.Last->isNot(tok::r_paren))
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
+ tok::kw_while) ||
+ I[1]->First->Type == TT_LineComment)
+ return 0;
+ // Only inline simple if's (no nested if or else).
+ if (I + 2 != E && Line.First->is(tok::kw_if) &&
+ I[2]->First->is(tok::kw_else))
+ return 0;
+ return 1;
+ }
- // If return returns a binary expression, align after it.
- if (Current.is(tok::kw_return) && !Current.FakeLParens.empty())
- State.Stack.back().LastSpace = State.Column + 7;
-
- // In ObjC method declaration we align on the ":" of parameters, but we need
- // to ensure that we indent parameters on subsequent lines by at least 4.
- if (Current.Type == TT_ObjCMethodSpecifier)
- State.Stack.back().Indent += 4;
-
- // Insert scopes created by fake parenthesis.
- const AnnotatedToken *Previous = Current.getPreviousNoneComment();
- // Don't add extra indentation for the first fake parenthesis after
- // 'return', assignements or opening <({[. The indentation for these cases
- // is special cased.
- bool SkipFirstExtraIndent =
- Current.is(tok::kw_return) ||
- (Previous && (Previous->opensScope() ||
- getPrecedence(*Previous) == prec::Assignment));
- for (SmallVector<prec::Level, 4>::const_reverse_iterator
- I = Current.FakeLParens.rbegin(),
- E = Current.FakeLParens.rend();
- I != E; ++I) {
- ParenState NewParenState = State.Stack.back();
- NewParenState.Indent =
- std::max(std::max(State.Column, NewParenState.Indent),
- State.Stack.back().LastSpace);
-
- // Always indent conditional expressions. Never indent expression where
- // the 'operator' is ',', ';' or an assignment (i.e. *I <=
- // prec::Assignment) as those have different indentation rules. Indent
- // other expression, unless the indentation needs to be skipped.
- if (*I == prec::Conditional ||
- (!SkipFirstExtraIndent && *I > prec::Assignment))
- NewParenState.Indent += 4;
- if (Previous && !Previous->opensScope())
- NewParenState.BreakBeforeParameter = false;
- State.Stack.push_back(NewParenState);
- SkipFirstExtraIndent = false;
- }
+ unsigned
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ // No merging if the brace already is on the next line.
+ if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
+ return 0;
- // If we encounter an opening (, [, { or <, we add a level to our stacks to
- // prepare for the following tokens.
- if (Current.opensScope()) {
- unsigned NewIndent;
- bool AvoidBinPacking;
- if (Current.is(tok::l_brace)) {
- NewIndent = 2 + State.Stack.back().LastSpace;
- AvoidBinPacking = false;
- } else {
- NewIndent = 4 + std::max(State.Stack.back().LastSpace,
- State.Stack.back().StartOfFunctionCall);
- AvoidBinPacking = !Style.BinPackParameters;
- }
- State.Stack.push_back(
- ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking,
- State.Stack.back().NoLineBreak));
-
- if (Current.NoMoreTokensOnLevel && Current.FakeLParens.empty()) {
- // This parenthesis was the last token possibly making use of Indent and
- // LastSpace of the next higher ParenLevel. Thus, erase them to acieve
- // better memoization results.
- State.Stack[State.Stack.size() - 2].Indent = 0;
- State.Stack[State.Stack.size() - 2].LastSpace = 0;
- }
+ // First, check that the current line allows merging. This is the case if
+ // we're not in a control flow statement and the last token is an opening
+ // brace.
+ AnnotatedLine &Line = **I;
+ if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
+ tok::kw_else, tok::kw_try, tok::kw_catch,
+ tok::kw_for,
+ // This gets rid of all ObjC @ keywords and methods.
+ tok::at, tok::minus, tok::plus))
+ return 0;
- ++State.ParenLevel;
- }
+ FormatToken *Tok = I[1]->First;
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+ (Tok->getNextNonComment() == NULL ||
+ 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.First->isNot(tok::kw_namespace)) {
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || I[2]->Type == LT_Invalid)
+ return 0;
- // If this '[' opens an ObjC call, determine whether all parameters fit into
- // one line and put one per line if they don't.
- if (Current.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr &&
- Current.MatchingParen != NULL) {
- if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit())
- State.Stack.back().BreakBeforeParameter = true;
- }
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
- // If we encounter a closing ), ], } or >, we can remove a level from our
- // stacks.
- if (Current.isOneOf(tok::r_paren, tok::r_square) ||
- (Current.is(tok::r_brace) && State.NextToken != &RootToken) ||
- State.NextToken->Type == TT_TemplateCloser) {
- State.Stack.pop_back();
- --State.ParenLevel;
- }
+ // 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->Type == TT_LineComment || Tok->MustBreakBefore)
+ return 0;
+ do {
+ if (Tok->isOneOf(tok::l_brace, tok::r_brace))
+ return 0;
+ Tok = Tok->Next;
+ } while (Tok != NULL);
- // Remove scopes created by fake parenthesis.
- for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
- unsigned VariablePos = State.Stack.back().VariablePos;
- State.Stack.pop_back();
- State.Stack.back().VariablePos = VariablePos;
- }
+ // Last, check that the third line contains a single closing brace.
+ Tok = I[2]->First;
+ if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) ||
+ Tok->MustBreakBefore)
+ return 0;
- if (Current.is(tok::string_literal)) {
- State.StartOfStringLiteral = State.Column;
- } else if (Current.isNot(tok::comment)) {
- State.StartOfStringLiteral = 0;
+ return 2;
}
+ return 0;
+ }
- State.Column += Current.FormatTok.TokenLength;
+ bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ unsigned Limit) {
+ return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
+ }
- if (State.NextToken->Children.empty())
- State.NextToken = NULL;
- else
- State.NextToken = &State.NextToken->Children[0];
+ const FormatStyle &Style;
+};
- return breakProtrudingToken(Current, State, DryRun);
- }
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(SourceManager &SourceMgr,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ContinuationIndenter *Indenter,
+ WhitespaceManager *Whitespaces,
+ const FormatStyle &Style)
+ : SourceMgr(SourceMgr), Ranges(Ranges), Indenter(Indenter),
+ Whitespaces(Whitespaces), Style(Style), Joiner(Style) {}
+
+ unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
+ int AdditionalIndent = 0) {
+ assert(!Lines.empty());
+ unsigned Penalty = 0;
+ std::vector<int> IndentForLevel;
+ for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
+ IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
+ bool PreviousLineWasTouched = false;
+ const AnnotatedLine *PreviousLine = NULL;
+ bool FormatPPDirective = false;
+ for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
+ E = Lines.end();
+ I != E; ++I) {
+ const AnnotatedLine &TheLine = **I;
+ const FormatToken *FirstTok = TheLine.First;
+ int Offset = getIndentOffset(*FirstTok);
+
+ // Check whether this line is part of a formatted preprocessor directive.
+ if (FirstTok->HasUnescapedNewline)
+ FormatPPDirective = false;
+ if (!FormatPPDirective && TheLine.InPPDirective &&
+ (touchesLine(TheLine) || touchesPPDirective(I + 1, E)))
+ FormatPPDirective = true;
+
+ // Determine indent and try to merge multiple unwrapped lines.
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ unsigned Indent = getIndent(IndentForLevel, TheLine.Level);
+ if (static_cast<int>(Indent) + Offset >= 0)
+ Indent += Offset;
+ unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
+ if (!DryRun) {
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ join(*I[i], *I[i + 1]);
+ }
+ }
+ I += MergedLines;
+
+ bool WasMoved = PreviousLineWasTouched && FirstTok->NewlinesBefore == 0;
+ if (TheLine.First->is(tok::eof)) {
+ if (PreviousLineWasTouched && !DryRun) {
+ unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
+ Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
+ /*IndentLevel=*/0, /*Spaces=*/0,
+ /*TargetColumn=*/0);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (WasMoved || FormatPPDirective || touchesLine(TheLine))) {
+ unsigned LevelIndent =
+ getIndent(IndentForLevel, TheLine.Level);
+ if (FirstTok->WhitespaceRange.isValid()) {
+ if (!DryRun)
+ formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
+ Indent, TheLine.InPPDirective);
+ } else {
+ Indent = LevelIndent = FirstTok->OriginalColumn;
+ }
- /// \brief If the current token sticks out over the end of the line, break
- /// it if possible.
- unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State,
- bool DryRun) {
- llvm::OwningPtr<BreakableToken> Token;
- unsigned StartColumn = State.Column - Current.FormatTok.TokenLength;
- if (Current.is(tok::string_literal)) {
- // Only break up default narrow strings.
- const char *LiteralData = SourceMgr.getCharacterData(
- Current.FormatTok.getStartOfNonWhitespace());
- if (!LiteralData || *LiteralData != '"')
- return 0;
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if (I + 1 != E) {
+ AnnotatedLine *NextLine = I[1];
+ if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)
+ ColumnLimit = getColumnLimit(TheLine.InPPDirective);
+ }
- Token.reset(new BreakableStringLiteral(SourceMgr, Current.FormatTok,
- StartColumn));
- } else if (Current.Type == TT_BlockComment) {
- BreakableBlockComment *BBC =
- new BreakableBlockComment(SourceMgr, Current, StartColumn);
- if (!DryRun)
- BBC->alignLines(Whitespaces);
- Token.reset(BBC);
- } else if (Current.Type == TT_LineComment &&
- (Current.Parent == NULL ||
- Current.Parent->Type != TT_ImplicitStringLiteral)) {
- Token.reset(new BreakableLineComment(SourceMgr, Current, StartColumn));
- } else {
- return 0;
- }
+ if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
+ LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
+ while (State.NextToken != NULL)
+ Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ } else if (Style.ColumnLimit == 0) {
+ NoColumnLimitFormatter Formatter(Indenter);
+ if (!DryRun)
+ Formatter.format(Indent, &TheLine);
+ } else {
+ Penalty += format(TheLine, Indent, DryRun);
+ }
- bool BreakInserted = false;
- unsigned Penalty = 0;
- for (unsigned LineIndex = 0; LineIndex < Token->getLineCount();
- ++LineIndex) {
- unsigned TailOffset = 0;
- unsigned RemainingLength =
- Token->getLineLengthAfterSplit(LineIndex, TailOffset);
- while (RemainingLength > getColumnLimit()) {
- BreakableToken::Split Split =
- Token->getSplit(LineIndex, TailOffset, getColumnLimit());
- if (Split.first == StringRef::npos)
- break;
- assert(Split.first != 0);
- unsigned NewRemainingLength = Token->getLineLengthAfterSplit(
- LineIndex, TailOffset + Split.first + Split.second);
- if (NewRemainingLength >= RemainingLength)
- break;
- if (!DryRun) {
- Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective,
- Whitespaces);
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ PreviousLineWasTouched = true;
+ } else {
+ // Format the first token if necessary, and notify the WhitespaceManager
+ // about the unchanged whitespace.
+ for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ if (Tok == TheLine.First &&
+ (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
+ unsigned LevelIndent = Tok->OriginalColumn;
+ if (!DryRun) {
+ // Remove trailing whitespace of the previous line if it was
+ // touched.
+ if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) {
+ formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
+ TheLine.InPPDirective);
+ } else {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
+ }
+
+ if (static_cast<int>(LevelIndent) - Offset >= 0)
+ LevelIndent -= Offset;
+ if (Tok->isNot(tok::comment))
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (!DryRun) {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
}
- TailOffset += Split.first + Split.second;
- RemainingLength = NewRemainingLength;
- Penalty += Style.PenaltyExcessCharacter;
- BreakInserted = true;
+ // If we did not reformat this unwrapped line, the column at the end of
+ // the last token is unchanged - thus, we can calculate the end of the
+ // last token.
+ PreviousLineWasTouched = false;
}
- State.Column = RemainingLength;
if (!DryRun) {
- Token->trimLine(LineIndex, TailOffset, Line.InPPDirective, Whitespaces);
+ for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ Tok->Finalized = true;
+ }
}
- }
-
- if (BreakInserted) {
- for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
- State.Stack[i].BreakBeforeParameter = true;
- State.Stack.back().LastSpace = StartColumn;
+ PreviousLine = *I;
}
return Penalty;
}
- unsigned getColumnLimit() {
- // In preprocessor directives reserve two chars for trailing " \"
- return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0);
+private:
+ /// \brief Formats an \c AnnotatedLine and returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
+ bool DryRun) {
+ LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+
+ // If the ObjC method declaration does not fit on a line, we should format
+ // it with one arg per line.
+ if (State.Line->Type == LT_ObjCMethodDecl)
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // Find best solution in solution space.
+ return analyzeSolutionSpace(State, DryRun);
}
/// \brief An edge in the solution space from \c Previous->State to \c State,
@@ -733,69 +698,206 @@ private:
typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
std::greater<QueueItem> > QueueType;
+ /// \brief Get the offset of the line relatively to the level.
+ ///
+ /// For example, 'public:' labels in classes are offset by 1 or 2
+ /// characters to the left from their level.
+ int getIndentOffset(const FormatToken &RootToken) {
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ return Style.AccessModifierOffset;
+ return 0;
+ }
+
+ /// \brief Add a new line and the required indent before the first Token
+ /// of the \c UnwrappedLine if there was no structural parsing error.
+ void formatFirstToken(FormatToken &RootToken,
+ const AnnotatedLine *PreviousLine, unsigned IndentLevel,
+ unsigned Indent, bool InPPDirective) {
+ unsigned Newlines =
+ std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
+ // Remove empty lines before "}" where applicable.
+ if (RootToken.is(tok::r_brace) &&
+ (!RootToken.Next ||
+ (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
+ Newlines = std::min(Newlines, 1u);
+ if (Newlines == 0 && !RootToken.IsFirst)
+ Newlines = 1;
+
+ // Insert extra new line before access specifiers.
+ if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
+ RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
+ ++Newlines;
+
+ // Remove empty lines after access specifiers.
+ if (PreviousLine && PreviousLine->First->isAccessSpecifier())
+ Newlines = std::min(1u, Newlines);
+
+ Whitespaces->replaceWhitespace(
+ RootToken, Newlines, IndentLevel, Indent, Indent,
+ InPPDirective && !RootToken.HasUnescapedNewline);
+ }
+
+ /// \brief Get the indent of \p Level from \p IndentForLevel.
+ ///
+ /// \p IndentForLevel must contain the indent for the level \c l
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for
+ /// that level is unknown.
+ unsigned getIndent(const std::vector<int> IndentForLevel, unsigned Level) {
+ if (IndentForLevel[Level] != -1)
+ return IndentForLevel[Level];
+ if (Level == 0)
+ return 0;
+ return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
+ }
+
+ void join(AnnotatedLine &A, const AnnotatedLine &B) {
+ assert(!A.Last->Next);
+ assert(!B.First->Previous);
+ A.Last->Next = B.First;
+ B.First->Previous = A.Last;
+ B.First->CanBreakBefore = true;
+ unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
+ for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
+ Tok->TotalLength += LengthA;
+ A.Last = Tok;
+ }
+ }
+
+ unsigned getColumnLimit(bool InPPDirective) const {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);
+ }
+
+ bool touchesRanges(const CharSourceRange &Range) {
+ for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
+ return true;
+ }
+ return false;
+ }
+
+ bool touchesLine(const AnnotatedLine &TheLine) {
+ const FormatToken *First = TheLine.First;
+ const FormatToken *Last = TheLine.Last;
+ CharSourceRange LineRange = CharSourceRange::getCharRange(
+ First->WhitespaceRange.getBegin().getLocWithOffset(
+ First->LastNewlineOffset),
+ Last->getStartOfNonWhitespace().getLocWithOffset(
+ Last->TokenText.size() - 1));
+ return touchesRanges(LineRange);
+ }
+
+ bool touchesPPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ for (; I != E; ++I) {
+ if ((*I)->First->HasUnescapedNewline)
+ return false;
+ if (touchesLine(**I))
+ return true;
+ }
+ return false;
+ }
+
+ bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
+ const FormatToken *First = TheLine.First;
+ CharSourceRange LineRange = CharSourceRange::getCharRange(
+ First->WhitespaceRange.getBegin(),
+ First->WhitespaceRange.getBegin().getLocWithOffset(
+ First->LastNewlineOffset));
+ return touchesRanges(LineRange);
+ }
+
/// \brief Analyze the entire solution space starting from \p InitialState.
///
/// This implements a variant of Dijkstra's algorithm on the graph that spans
/// the solution space (\c LineStates are the nodes). The algorithm tries to
/// find the shortest path (the one with lowest penalty) from \p InitialState
- /// to a state where all tokens are placed.
- unsigned analyzeSolutionSpace(LineState &InitialState) {
+ /// to a state where all tokens are placed. Returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {
std::set<LineState> Seen;
+ // Increasing count of \c StateNode items we have created. This is used to
+ // create a deterministic order independent of the container.
+ unsigned Count = 0;
+ QueueType Queue;
+
// Insert start element into queue.
StateNode *Node =
new (Allocator.Allocate()) StateNode(InitialState, false, NULL);
Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
++Count;
+ unsigned Penalty = 0;
+
// While not empty, take first element and follow edges.
while (!Queue.empty()) {
- unsigned Penalty = Queue.top().first.first;
+ Penalty = Queue.top().first.first;
StateNode *Node = Queue.top().second;
if (Node->State.NextToken == NULL) {
- DEBUG(llvm::errs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
break;
}
Queue.pop();
+ // Cut off the analysis of certain solutions if the analysis gets too
+ // complex. See description of IgnoreStackForComparison.
+ if (Count > 10000)
+ Node->State.IgnoreStackForComparison = true;
+
if (!Seen.insert(Node->State).second)
// State already examined with lower penalty.
continue;
- addNextStateToQueue(Penalty, Node, /*NewLine=*/ false);
- addNextStateToQueue(Penalty, Node, /*NewLine=*/ true);
+ FormatDecision LastFormat = Node->State.NextToken->Decision;
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
}
- if (Queue.empty())
+ if (Queue.empty()) {
// We were unable to find a solution, do nothing.
// FIXME: Add diagnostic?
+ DEBUG(llvm::dbgs() << "Could not find a solution.\n");
return 0;
+ }
// Reconstruct the solution.
- reconstructPath(InitialState, Queue.top().second);
- DEBUG(llvm::errs() << "---\n");
+ if (!DryRun)
+ reconstructPath(InitialState, Queue.top().second);
+
+ DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
+ DEBUG(llvm::dbgs() << "---\n");
- // Return the column after the last token of the solution.
- return Queue.top().second->State.Column;
+ return Penalty;
}
void reconstructPath(LineState &State, StateNode *Current) {
- // FIXME: This recursive implementation limits the possible number
- // of tokens per line if compiled into a binary with small stack space.
- // To become more independent of stack frame limitations we would need
- // to also change the TokenAnnotator.
- if (Current->Previous == NULL)
- return;
- reconstructPath(State, Current->Previous);
- DEBUG({
- if (Current->NewLine) {
- llvm::errs()
- << "Penalty for splitting before "
- << Current->Previous->State.NextToken->FormatTok.Tok.getName()
- << ": " << Current->Previous->State.NextToken->SplitPenalty << "\n";
- }
- });
- addTokenToState(Current->NewLine, false, State);
+ std::deque<StateNode *> Path;
+ // We do not need a break before the initial token.
+ while (Current->Previous) {
+ Path.push_front(Current);
+ Current = Current->Previous;
+ }
+ for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
+ I != E; ++I) {
+ unsigned Penalty = 0;
+ formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
+ Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
+
+ DEBUG({
+ if ((*I)->NewLine) {
+ llvm::dbgs() << "Penalty for placing "
+ << (*I)->Previous->State.NextToken->Tok.getName() << ": "
+ << Penalty << "\n";
+ }
+ });
+ }
}
/// \brief Add the following state to the analysis queue \c Queue.
@@ -803,331 +905,415 @@ private:
/// Assume the current state is \p PreviousNode and has been reached with a
/// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
- bool NewLine) {
- if (NewLine && !canBreak(PreviousNode->State))
+ bool NewLine, unsigned *Count, QueueType *Queue) {
+ if (NewLine && !Indenter->canBreak(PreviousNode->State))
return;
- if (!NewLine && mustBreak(PreviousNode->State))
+ if (!NewLine && Indenter->mustBreak(PreviousNode->State))
return;
- if (NewLine)
- Penalty += PreviousNode->State.NextToken->SplitPenalty;
StateNode *Node = new (Allocator.Allocate())
StateNode(PreviousNode->State, NewLine, PreviousNode);
- Penalty += addTokenToState(NewLine, true, Node->State);
- if (Node->State.Column > getColumnLimit()) {
- unsigned ExcessCharacters = Node->State.Column - getColumnLimit();
- Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
- }
+ if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
+ return;
- Queue.push(QueueItem(OrderedPenalty(Penalty, Count), Node));
- ++Count;
- }
+ Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
- /// \brief Returns \c true, if a line break after \p State is allowed.
- bool canBreak(const LineState &State) {
- if (!State.NextToken->CanBreakBefore &&
- !(State.NextToken->is(tok::r_brace) &&
- State.Stack.back().BreakBeforeClosingBrace))
- return false;
- return !State.Stack.back().NoLineBreak;
+ Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
+ ++(*Count);
}
- /// \brief Returns \c true, if a line break after \p State is mandatory.
- bool mustBreak(const LineState &State) {
- if (State.NextToken->MustBreakBefore)
- return true;
- if (State.NextToken->is(tok::r_brace) &&
- State.Stack.back().BreakBeforeClosingBrace)
- return true;
- if (State.NextToken->Parent->is(tok::semi) &&
- State.LineContainsContinuedForLoopSection)
- return true;
- if ((State.NextToken->Parent->isOneOf(tok::comma, tok::semi) ||
- State.NextToken->is(tok::question) ||
- State.NextToken->Type == TT_ConditionalExpr) &&
- State.Stack.back().BreakBeforeParameter &&
- !State.NextToken->isTrailingComment() &&
- State.NextToken->isNot(tok::r_paren) &&
- State.NextToken->isNot(tok::r_brace))
- return true;
- // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
- // out whether it is the first parameter. Clean this up.
- if (State.NextToken->Type == TT_ObjCSelectorName &&
- State.NextToken->LongestObjCSelectorName == 0 &&
- State.Stack.back().BreakBeforeParameter)
- return true;
- if ((State.NextToken->Type == TT_CtorInitializerColon ||
- (State.NextToken->Parent->ClosesTemplateDeclaration &&
- State.ParenLevel == 0)))
- return true;
- if (State.NextToken->Type == TT_InlineASMColon)
+ /// \brief If the \p State's next token is an r_brace closing a nested block,
+ /// format the nested block before it.
+ ///
+ /// Returns \c true if all children could be placed successfully and adapts
+ /// \p Penalty as well as \p State. If \p DryRun is false, also directly
+ /// creates changes using \c Whitespaces.
+ ///
+ /// The crucial idea here is that children always get formatted upon
+ /// encountering the closing brace right after the nested block. Now, if we
+ /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
+ /// \c false), the entire block has to be kept on the same line (which is only
+ /// possible if it fits on the line, only contains a single statement, etc.
+ ///
+ /// If \p NewLine is true, we format the nested block on separate lines, i.e.
+ /// break after the "{", format all lines with correct indentation and the put
+ /// the closing "}" on yet another new line.
+ ///
+ /// This enables us to keep the simple structure of the
+ /// \c UnwrappedLineFormatter, where we only have two options for each token:
+ /// break or don't break.
+ bool formatChildren(LineState &State, bool NewLine, bool DryRun,
+ unsigned &Penalty) {
+ FormatToken &Previous = *State.NextToken->Previous;
+ const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
+ if (!LBrace || LBrace->isNot(tok::l_brace) ||
+ LBrace->BlockKind != BK_Block || Previous.Children.size() == 0)
+ // The previous token does not open a block. Nothing to do. We don't
+ // assert so that we can simply call this function for all tokens.
return true;
- // This prevents breaks like:
- // ...
- // SomeParameter, OtherParameter).DoSomething(
- // ...
- // As they hide "DoSomething" and generally bad for readability.
- if (State.NextToken->isOneOf(tok::period, tok::arrow) &&
- getRemainingLength(State) + State.Column > getColumnLimit() &&
- State.ParenLevel < State.StartOfLineLevel)
+
+ if (NewLine) {
+ int AdditionalIndent = State.Stack.back().Indent -
+ Previous.Children[0]->Level * Style.IndentWidth;
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent);
return true;
- return false;
- }
+ }
- // Returns the total number of columns required for the remaining tokens.
- unsigned getRemainingLength(const LineState &State) {
- if (State.NextToken && State.NextToken->Parent)
- return Line.Last->TotalLength - State.NextToken->Parent->TotalLength;
- return 0;
+ // Cannot merge multiple statements into a single line.
+ if (Previous.Children.size() > 1)
+ return false;
+
+ // We can't put the closing "}" on a line with a trailing comment.
+ if (Previous.Children[0]->Last->isTrailingComment())
+ return false;
+
+ if (!DryRun) {
+ Whitespaces->replaceWhitespace(
+ *Previous.Children[0]->First,
+ /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
+ /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
+ }
+ Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
+
+ State.Column += 1 + Previous.Children[0]->Last->TotalLength;
+ return true;
}
- FormatStyle Style;
SourceManager &SourceMgr;
- const AnnotatedLine &Line;
- const unsigned FirstIndent;
- const AnnotatedToken &RootToken;
- WhitespaceManager &Whitespaces;
+ SmallVectorImpl<CharSourceRange> &Ranges;
+ ContinuationIndenter *Indenter;
+ WhitespaceManager *Whitespaces;
+ FormatStyle Style;
+ LineJoiner Joiner;
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
- QueueType Queue;
- // Increasing count of \c StateNode items we have created. This is used
- // to create a deterministic order independent of the container.
- unsigned Count;
};
-class LexerBasedFormatTokenSource : public FormatTokenSource {
+class FormatTokenLexer {
public:
- LexerBasedFormatTokenSource(Lexer &Lex, SourceManager &SourceMgr)
- : GreaterStashed(false), Lex(Lex), SourceMgr(SourceMgr),
- IdentTable(Lex.getLangOpts()) {
+ FormatTokenLexer(Lexer &Lex, SourceManager &SourceMgr, FormatStyle &Style,
+ encoding::Encoding Encoding)
+ : FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0),
+ TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
+ IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
Lex.SetKeepWhitespaceMode(true);
}
- virtual FormatToken getNextToken() {
+ ArrayRef<FormatToken *> lex() {
+ assert(Tokens.empty());
+ do {
+ Tokens.push_back(getNextToken());
+ maybeJoinPreviousTokens();
+ } while (Tokens.back()->Tok.isNot(tok::eof));
+ return Tokens;
+ }
+
+ IdentifierTable &getIdentTable() { return IdentTable; }
+
+private:
+ void maybeJoinPreviousTokens() {
+ if (Tokens.size() < 4)
+ return;
+ FormatToken *Last = Tokens.back();
+ if (!Last->is(tok::r_paren))
+ return;
+
+ FormatToken *String = Tokens[Tokens.size() - 2];
+ if (!String->is(tok::string_literal) || String->IsMultiline)
+ return;
+
+ if (!Tokens[Tokens.size() - 3]->is(tok::l_paren))
+ return;
+
+ FormatToken *Macro = Tokens[Tokens.size() - 4];
+ if (Macro->TokenText != "_T")
+ return;
+
+ const char *Start = Macro->TokenText.data();
+ const char *End = Last->TokenText.data() + Last->TokenText.size();
+ String->TokenText = StringRef(Start, End - Start);
+ String->IsFirst = Macro->IsFirst;
+ String->LastNewlineOffset = Macro->LastNewlineOffset;
+ String->WhitespaceRange = Macro->WhitespaceRange;
+ String->OriginalColumn = Macro->OriginalColumn;
+ String->ColumnWidth = encoding::columnWidthWithTabs(
+ String->TokenText, String->OriginalColumn, Style.TabWidth, Encoding);
+
+ Tokens.pop_back();
+ Tokens.pop_back();
+ Tokens.pop_back();
+ Tokens.back() = String;
+ }
+
+ FormatToken *getNextToken() {
if (GreaterStashed) {
- FormatTok.NewlinesBefore = 0;
- FormatTok.WhiteSpaceStart =
- FormatTok.Tok.getLocation().getLocWithOffset(1);
- FormatTok.WhiteSpaceLength = 0;
+ // Create a synthesized second '>' token.
+ // FIXME: Increment Column and set OriginalColumn.
+ Token Greater = FormatTok->Tok;
+ FormatTok = new (Allocator.Allocate()) FormatToken;
+ FormatTok->Tok = Greater;
+ SourceLocation GreaterLocation =
+ FormatTok->Tok.getLocation().getLocWithOffset(1);
+ FormatTok->WhitespaceRange =
+ SourceRange(GreaterLocation, GreaterLocation);
+ FormatTok->TokenText = ">";
+ FormatTok->ColumnWidth = 1;
GreaterStashed = false;
return FormatTok;
}
- FormatTok = FormatToken();
- Lex.LexFromRawLexer(FormatTok.Tok);
- StringRef Text = rawTokenText(FormatTok.Tok);
- FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
- if (SourceMgr.getFileOffset(FormatTok.WhiteSpaceStart) == 0)
- FormatTok.IsFirst = true;
+ FormatTok = new (Allocator.Allocate()) FormatToken;
+ readRawToken(*FormatTok);
+ SourceLocation WhitespaceStart =
+ FormatTok->Tok.getLocation().getLocWithOffset(-TrailingWhitespace);
+ FormatTok->IsFirst = IsFirstToken;
+ IsFirstToken = false;
// Consume and record whitespace until we find a significant token.
- while (FormatTok.Tok.is(tok::unknown)) {
- unsigned Newlines = Text.count('\n');
- if (Newlines > 0)
- FormatTok.LastNewlineOffset =
- FormatTok.WhiteSpaceLength + Text.rfind('\n') + 1;
- unsigned EscapedNewlines = Text.count("\\\n");
- FormatTok.NewlinesBefore += Newlines;
- FormatTok.HasUnescapedNewline |= EscapedNewlines != Newlines;
- FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
-
- if (FormatTok.Tok.is(tok::eof))
- return FormatTok;
- Lex.LexFromRawLexer(FormatTok.Tok);
- Text = rawTokenText(FormatTok.Tok);
- }
+ unsigned WhitespaceLength = TrailingWhitespace;
+ while (FormatTok->Tok.is(tok::unknown)) {
+ for (int i = 0, e = FormatTok->TokenText.size(); i != e; ++i) {
+ switch (FormatTok->TokenText[i]) {
+ case '\n':
+ ++FormatTok->NewlinesBefore;
+ // FIXME: This is technically incorrect, as it could also
+ // be a literal backslash at the end of the line.
+ if (i == 0 || (FormatTok->TokenText[i - 1] != '\\' &&
+ (FormatTok->TokenText[i - 1] != '\r' || i == 1 ||
+ FormatTok->TokenText[i - 2] != '\\')))
+ FormatTok->HasUnescapedNewline = true;
+ FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
+ Column = 0;
+ break;
+ case '\r':
+ case '\f':
+ case '\v':
+ Column = 0;
+ break;
+ case ' ':
+ ++Column;
+ break;
+ case '\t':
+ Column += Style.TabWidth - Column % Style.TabWidth;
+ break;
+ case '\\':
+ ++Column;
+ if (i + 1 == e || (FormatTok->TokenText[i + 1] != '\r' &&
+ FormatTok->TokenText[i + 1] != '\n'))
+ FormatTok->Type = TT_ImplicitStringLiteral;
+ break;
+ default:
+ FormatTok->Type = TT_ImplicitStringLiteral;
+ ++Column;
+ break;
+ }
+ }
- // Now FormatTok is the next non-whitespace token.
- FormatTok.TokenLength = Text.size();
+ if (FormatTok->Type == TT_ImplicitStringLiteral)
+ break;
+ WhitespaceLength += FormatTok->Tok.getLength();
- if (FormatTok.Tok.is(tok::comment)) {
- FormatTok.TrailingWhiteSpaceLength = Text.size() - Text.rtrim().size();
- FormatTok.TokenLength -= FormatTok.TrailingWhiteSpaceLength;
+ readRawToken(*FormatTok);
}
// 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: What do we want to do with other escaped spaces, and escaped
- // spaces or newlines in the middle of tokens?
// FIXME: Add a more explicit test.
- unsigned i = 0;
- while (i + 1 < Text.size() && Text[i] == '\\' && Text[i + 1] == '\n') {
- // FIXME: ++FormatTok.NewlinesBefore is missing...
- FormatTok.WhiteSpaceLength += 2;
- FormatTok.TokenLength -= 2;
- i += 2;
+ while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
+ FormatTok->TokenText[1] == '\n') {
+ // FIXME: ++FormatTok->NewlinesBefore is missing...
+ WhitespaceLength += 2;
+ Column = 0;
+ FormatTok->TokenText = FormatTok->TokenText.substr(2);
}
- if (FormatTok.Tok.is(tok::raw_identifier)) {
- IdentifierInfo &Info = IdentTable.get(Text);
- FormatTok.Tok.setIdentifierInfo(&Info);
- FormatTok.Tok.setKind(Info.getTokenID());
+ FormatTok->WhitespaceRange = SourceRange(
+ WhitespaceStart, WhitespaceStart.getLocWithOffset(WhitespaceLength));
+
+ FormatTok->OriginalColumn = Column;
+
+ TrailingWhitespace = 0;
+ if (FormatTok->Tok.is(tok::comment)) {
+ // FIXME: Add the trimmed whitespace to Column.
+ StringRef UntrimmedText = FormatTok->TokenText;
+ FormatTok->TokenText = FormatTok->TokenText.rtrim(" \t\v\f");
+ TrailingWhitespace = UntrimmedText.size() - FormatTok->TokenText.size();
+ } else if (FormatTok->Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = IdentTable.get(FormatTok->TokenText);
+ FormatTok->Tok.setIdentifierInfo(&Info);
+ FormatTok->Tok.setKind(Info.getTokenID());
+ } else if (FormatTok->Tok.is(tok::greatergreater)) {
+ FormatTok->Tok.setKind(tok::greater);
+ FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
+ GreaterStashed = true;
}
- if (FormatTok.Tok.is(tok::greatergreater)) {
- FormatTok.Tok.setKind(tok::greater);
- FormatTok.TokenLength = 1;
- GreaterStashed = true;
+ // Now FormatTok is the next non-whitespace token.
+
+ StringRef Text = FormatTok->TokenText;
+ size_t FirstNewlinePos = Text.find('\n');
+ if (FirstNewlinePos == StringRef::npos) {
+ // FIXME: ColumnWidth actually depends on the start column, we need to
+ // take this into account when the token is moved.
+ FormatTok->ColumnWidth =
+ encoding::columnWidthWithTabs(Text, Column, Style.TabWidth, Encoding);
+ Column += FormatTok->ColumnWidth;
+ } else {
+ FormatTok->IsMultiline = true;
+ // FIXME: ColumnWidth actually depends on the start column, we need to
+ // take this into account when the token is moved.
+ FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
+ Text.substr(0, FirstNewlinePos), Column, Style.TabWidth, Encoding);
+
+ // The last line of the token always starts in column 0.
+ // Thus, the length can be precomputed even in the presence of tabs.
+ FormatTok->LastLineColumnWidth = encoding::columnWidthWithTabs(
+ Text.substr(Text.find_last_of('\n') + 1), 0, Style.TabWidth,
+ Encoding);
+ Column = FormatTok->LastLineColumnWidth;
}
return FormatTok;
}
- IdentifierTable &getIdentTable() { return IdentTable; }
-
-private:
- FormatToken FormatTok;
+ FormatToken *FormatTok;
+ bool IsFirstToken;
bool GreaterStashed;
+ unsigned Column;
+ unsigned TrailingWhitespace;
Lexer &Lex;
SourceManager &SourceMgr;
+ FormatStyle &Style;
IdentifierTable IdentTable;
-
- /// Returns the text of \c FormatTok.
- StringRef rawTokenText(Token &Tok) {
- return StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
- Tok.getLength());
+ encoding::Encoding Encoding;
+ llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
+ SmallVector<FormatToken *, 16> Tokens;
+
+ void readRawToken(FormatToken &Tok) {
+ Lex.LexFromRawLexer(Tok.Tok);
+ Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
+ Tok.Tok.getLength());
+ // For formatting, treat unterminated string literals like normal string
+ // literals.
+ if (Tok.is(tok::unknown) && !Tok.TokenText.empty() &&
+ Tok.TokenText[0] == '"') {
+ Tok.Tok.setKind(tok::string_literal);
+ Tok.IsUnterminatedLiteral = true;
+ }
}
};
class Formatter : public UnwrappedLineConsumer {
public:
- Formatter(DiagnosticsEngine &Diag, const FormatStyle &Style, Lexer &Lex,
- SourceManager &SourceMgr,
+ Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
const std::vector<CharSourceRange> &Ranges)
- : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr),
- Whitespaces(SourceMgr, Style), Ranges(Ranges) {}
-
- virtual ~Formatter() {}
+ : Style(Style), Lex(Lex), SourceMgr(SourceMgr),
+ Whitespaces(SourceMgr, Style, inputUsesCRLF(Lex.getBuffer())),
+ Ranges(Ranges.begin(), Ranges.end()), UnwrappedLines(1),
+ Encoding(encoding::detectEncoding(Lex.getBuffer())) {
+ DEBUG(llvm::dbgs() << "File encoding: "
+ << (Encoding == encoding::Encoding_UTF8 ? "UTF8"
+ : "unknown")
+ << "\n");
+ }
tooling::Replacements format() {
- LexerBasedFormatTokenSource Tokens(Lex, SourceMgr);
- UnwrappedLineParser Parser(Diag, Style, Tokens, *this);
+ tooling::Replacements Result;
+ FormatTokenLexer Tokens(Lex, SourceMgr, Style, Encoding);
+
+ UnwrappedLineParser Parser(Style, Tokens.lex(), *this);
bool StructuralError = Parser.parse();
- unsigned PreviousEndOfLineColumn = 0;
- TokenAnnotator Annotator(Style, SourceMgr, Lex,
- Tokens.getIdentTable().get("in"));
- for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
- Annotator.annotate(AnnotatedLines[i]);
+ assert(UnwrappedLines.rbegin()->empty());
+ for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE;
+ ++Run) {
+ DEBUG(llvm::dbgs() << "Run " << Run << "...\n");
+ SmallVector<AnnotatedLine *, 16> AnnotatedLines;
+ for (unsigned i = 0, e = UnwrappedLines[Run].size(); i != e; ++i) {
+ AnnotatedLines.push_back(new AnnotatedLine(UnwrappedLines[Run][i]));
+ }
+ tooling::Replacements RunResult =
+ format(AnnotatedLines, StructuralError, Tokens);
+ DEBUG({
+ llvm::dbgs() << "Replacements for run " << Run << ":\n";
+ for (tooling::Replacements::iterator I = RunResult.begin(),
+ E = RunResult.end();
+ I != E; ++I) {
+ llvm::dbgs() << I->toString() << "\n";
+ }
+ });
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ delete AnnotatedLines[i];
+ }
+ Result.insert(RunResult.begin(), RunResult.end());
+ Whitespaces.reset();
}
- deriveLocalStyle();
+ return Result;
+ }
+
+ tooling::Replacements format(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ bool StructuralError, FormatTokenLexer &Tokens) {
+ TokenAnnotator Annotator(Style, Tokens.getIdentTable().get("in"));
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
- Annotator.calculateFormattingInformation(AnnotatedLines[i]);
+ Annotator.annotate(*AnnotatedLines[i]);
}
-
- // Adapt level to the next line if this is a comment.
- // FIXME: Can/should this be done in the UnwrappedLineParser?
- const AnnotatedLine *NextNoneCommentLine = NULL;
- for (unsigned i = AnnotatedLines.size() - 1; i > 0; --i) {
- if (NextNoneCommentLine && AnnotatedLines[i].First.is(tok::comment) &&
- AnnotatedLines[i].First.Children.empty())
- AnnotatedLines[i].Level = NextNoneCommentLine->Level;
- else
- NextNoneCommentLine =
- AnnotatedLines[i].First.isNot(tok::r_brace) ? &AnnotatedLines[i]
- : NULL;
+ deriveLocalStyle(AnnotatedLines);
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
}
- std::vector<int> IndentForLevel;
- bool PreviousLineWasTouched = false;
- const AnnotatedToken *PreviousLineLastToken = 0;
- for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(),
- E = AnnotatedLines.end();
- I != E; ++I) {
- const AnnotatedLine &TheLine = *I;
- const FormatToken &FirstTok = TheLine.First.FormatTok;
- int Offset = getIndentOffset(TheLine.First);
- while (IndentForLevel.size() <= TheLine.Level)
- IndentForLevel.push_back(-1);
- IndentForLevel.resize(TheLine.Level + 1);
- bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0;
- if (TheLine.First.is(tok::eof)) {
- if (PreviousLineWasTouched) {
- unsigned NewLines = std::min(FirstTok.NewlinesBefore, 1u);
- Whitespaces.replaceWhitespace(TheLine.First, NewLines, /*Indent*/ 0,
- /*WhitespaceStartColumn*/ 0);
- }
- } else if (TheLine.Type != LT_Invalid &&
- (WasMoved || touchesLine(TheLine))) {
- unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level);
- unsigned Indent = LevelIndent;
- if (static_cast<int>(Indent) + Offset >= 0)
- Indent += Offset;
- if (FirstTok.WhiteSpaceStart.isValid() &&
- // Insert a break even if there is a structural error in case where
- // we break apart a line consisting of multiple unwrapped lines.
- (FirstTok.NewlinesBefore == 0 || !StructuralError)) {
- formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
- TheLine.InPPDirective, PreviousEndOfLineColumn);
- } else {
- Indent = LevelIndent =
- SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
- }
- tryFitMultipleLinesInOne(Indent, I, E);
- UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
- TheLine.First, Whitespaces);
- PreviousEndOfLineColumn =
- Formatter.format(I + 1 != E ? &*(I + 1) : NULL);
- IndentForLevel[TheLine.Level] = LevelIndent;
- PreviousLineWasTouched = true;
- } else {
- if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) {
- unsigned Indent =
- SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
- unsigned LevelIndent = Indent;
- if (static_cast<int>(LevelIndent) - Offset >= 0)
- LevelIndent -= Offset;
- if (TheLine.First.isNot(tok::comment))
- IndentForLevel[TheLine.Level] = LevelIndent;
-
- // Remove trailing whitespace of the previous line if it was touched.
- if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine))
- formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
- TheLine.InPPDirective, PreviousEndOfLineColumn);
- }
- // If we did not reformat this unwrapped line, the column at the end of
- // the last token is unchanged - thus, we can calculate the end of the
- // last token.
- SourceLocation LastLoc = TheLine.Last->FormatTok.Tok.getLocation();
- PreviousEndOfLineColumn =
- SourceMgr.getSpellingColumnNumber(LastLoc) +
- Lex.MeasureTokenLength(LastLoc, SourceMgr, Lex.getLangOpts()) - 1;
- PreviousLineWasTouched = false;
- if (TheLine.Last->is(tok::comment))
- Whitespaces.addUntouchableComment(SourceMgr.getSpellingColumnNumber(
- TheLine.Last->FormatTok.Tok.getLocation()) - 1);
- else
- Whitespaces.alignComments();
- }
- PreviousLineLastToken = I->Last;
- }
+ Annotator.setCommentLineLevels(AnnotatedLines);
+ ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,
+ BinPackInconclusiveFunctions);
+ UnwrappedLineFormatter Formatter(SourceMgr, Ranges, &Indenter, &Whitespaces,
+ Style);
+ Formatter.format(AnnotatedLines, /*DryRun=*/false);
return Whitespaces.generateReplacements();
}
private:
- void deriveLocalStyle() {
+ static bool inputUsesCRLF(StringRef Text) {
+ return Text.count('\r') * 2 > Text.count('\n');
+ }
+
+ void
+ deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
unsigned CountBoundToVariable = 0;
unsigned CountBoundToType = 0;
bool HasCpp03IncompatibleFormat = false;
+ bool HasBinPackedFunction = false;
+ bool HasOnePerLineFunction = false;
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
- if (AnnotatedLines[i].First.Children.empty())
+ if (!AnnotatedLines[i]->First->Next)
continue;
- AnnotatedToken *Tok = &AnnotatedLines[i].First.Children[0];
- while (!Tok->Children.empty()) {
+ FormatToken *Tok = AnnotatedLines[i]->First->Next;
+ while (Tok->Next) {
if (Tok->Type == TT_PointerOrReference) {
- bool SpacesBefore = Tok->FormatTok.WhiteSpaceLength > 0;
- bool SpacesAfter = Tok->Children[0].FormatTok.WhiteSpaceLength > 0;
+ bool SpacesBefore =
+ Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
+ bool SpacesAfter = Tok->Next->WhitespaceRange.getBegin() !=
+ Tok->Next->WhitespaceRange.getEnd();
if (SpacesBefore && !SpacesAfter)
++CountBoundToVariable;
else if (!SpacesBefore && SpacesAfter)
++CountBoundToType;
}
- if (Tok->Type == TT_TemplateCloser &&
- Tok->Parent->Type == TT_TemplateCloser &&
- Tok->FormatTok.WhiteSpaceLength == 0)
- HasCpp03IncompatibleFormat = true;
- Tok = &Tok->Children[0];
+ if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
+ if (Tok->is(tok::coloncolon) &&
+ Tok->Previous->Type == TT_TemplateOpener)
+ HasCpp03IncompatibleFormat = true;
+ if (Tok->Type == TT_TemplateCloser &&
+ Tok->Previous->Type == TT_TemplateCloser)
+ HasCpp03IncompatibleFormat = true;
+ }
+
+ if (Tok->PackingKind == PPK_BinPacked)
+ HasBinPackedFunction = true;
+ if (Tok->PackingKind == PPK_OnePerLine)
+ HasOnePerLineFunction = true;
+
+ Tok = Tok->Next;
}
}
if (Style.DerivePointerBinding) {
@@ -1140,259 +1326,69 @@ private:
Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11
: FormatStyle::LS_Cpp03;
}
- }
-
- /// \brief Get the indent of \p Level from \p IndentForLevel.
- ///
- /// \p IndentForLevel must contain the indent for the level \c l
- /// at \p IndentForLevel[l], or a value < 0 if the indent for
- /// that level is unknown.
- unsigned getIndent(const std::vector<int> IndentForLevel, unsigned Level) {
- if (IndentForLevel[Level] != -1)
- return IndentForLevel[Level];
- if (Level == 0)
- return 0;
- return getIndent(IndentForLevel, Level - 1) + 2;
- }
-
- /// \brief Get the offset of the line relatively to the level.
- ///
- /// For example, 'public:' labels in classes are offset by 1 or 2
- /// characters to the left from their level.
- int getIndentOffset(const AnnotatedToken &RootToken) {
- if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
- return Style.AccessModifierOffset;
- return 0;
- }
-
- /// \brief Tries to merge lines into one.
- ///
- /// This will change \c Line and \c AnnotatedLine to contain the merged line,
- /// if possible; note that \c I will be incremented when lines are merged.
- ///
- /// Returns whether the resulting \c Line can fit in a single line.
- void tryFitMultipleLinesInOne(unsigned Indent,
- std::vector<AnnotatedLine>::iterator &I,
- std::vector<AnnotatedLine>::iterator E) {
- // We can never merge stuff if there are trailing line comments.
- if (I->Last->Type == TT_LineComment)
- return;
-
- unsigned Limit = Style.ColumnLimit - Indent;
- // If we already exceed the column limit, we set 'Limit' to 0. The different
- // tryMerge..() functions can then decide whether to still do merging.
- Limit = I->Last->TotalLength > Limit ? 0 : Limit - I->Last->TotalLength;
-
- if (I + 1 == E || (I + 1)->Type == LT_Invalid)
- return;
-
- if (I->Last->is(tok::l_brace)) {
- tryMergeSimpleBlock(I, E, Limit);
- } else if (I->First.is(tok::kw_if)) {
- tryMergeSimpleIf(I, E, Limit);
- } else if (I->InPPDirective && (I->First.FormatTok.HasUnescapedNewline ||
- I->First.FormatTok.IsFirst)) {
- tryMergeSimplePPDirective(I, E, Limit);
- }
- return;
- }
-
- void tryMergeSimplePPDirective(std::vector<AnnotatedLine>::iterator &I,
- std::vector<AnnotatedLine>::iterator E,
- unsigned Limit) {
- if (Limit == 0)
- return;
- AnnotatedLine &Line = *I;
- if (!(I + 1)->InPPDirective || (I + 1)->First.FormatTok.HasUnescapedNewline)
- return;
- if (I + 2 != E && (I + 2)->InPPDirective &&
- !(I + 2)->First.FormatTok.HasUnescapedNewline)
- return;
- if (1 + (I + 1)->Last->TotalLength > Limit)
- return;
- join(Line, *(++I));
- }
-
- void tryMergeSimpleIf(std::vector<AnnotatedLine>::iterator &I,
- std::vector<AnnotatedLine>::iterator E,
- unsigned Limit) {
- if (Limit == 0)
- return;
- if (!Style.AllowShortIfStatementsOnASingleLine)
- return;
- if ((I + 1)->InPPDirective != I->InPPDirective ||
- ((I + 1)->InPPDirective &&
- (I + 1)->First.FormatTok.HasUnescapedNewline))
- return;
- AnnotatedLine &Line = *I;
- if (Line.Last->isNot(tok::r_paren))
- return;
- if (1 + (I + 1)->Last->TotalLength > Limit)
- return;
- if ((I + 1)->First.is(tok::kw_if) || (I + 1)->First.Type == TT_LineComment)
- return;
- // Only inline simple if's (no nested if or else).
- if (I + 2 != E && (I + 2)->First.is(tok::kw_else))
- return;
- join(Line, *(++I));
- }
-
- void tryMergeSimpleBlock(std::vector<AnnotatedLine>::iterator &I,
- std::vector<AnnotatedLine>::iterator E,
- unsigned Limit) {
- // First, check that the current line allows merging. This is the case if
- // we're not in a control flow statement and the last token is an opening
- // brace.
- AnnotatedLine &Line = *I;
- if (Line.First.isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
- tok::kw_else, tok::kw_try, tok::kw_catch,
- tok::kw_for,
- // This gets rid of all ObjC @ keywords and methods.
- tok::at, tok::minus, tok::plus))
- return;
-
- AnnotatedToken *Tok = &(I + 1)->First;
- if (Tok->Children.empty() && Tok->is(tok::r_brace) &&
- !Tok->MustBreakBefore) {
- // We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
- Tok->CanBreakBefore = true;
- join(Line, *(I + 1));
- I += 1;
- } else if (Limit != 0) {
- // Check that we still have three lines and they fit into the limit.
- if (I + 2 == E || (I + 2)->Type == LT_Invalid ||
- !nextTwoLinesFitInto(I, Limit))
- return;
-
- // 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->Type == TT_LineComment || Tok->MustBreakBefore)
- return;
- do {
- if (Tok->isOneOf(tok::l_brace, tok::r_brace))
- return;
- Tok = Tok->Children.empty() ? NULL : &Tok->Children.back();
- } while (Tok != NULL);
-
- // Last, check that the third line contains a single closing brace.
- Tok = &(I + 2)->First;
- if (!Tok->Children.empty() || Tok->isNot(tok::r_brace) ||
- Tok->MustBreakBefore)
- return;
-
- join(Line, *(I + 1));
- join(Line, *(I + 2));
- I += 2;
- }
- }
-
- bool nextTwoLinesFitInto(std::vector<AnnotatedLine>::iterator I,
- unsigned Limit) {
- return 1 + (I + 1)->Last->TotalLength + 1 + (I + 2)->Last->TotalLength <=
- Limit;
- }
-
- void join(AnnotatedLine &A, const AnnotatedLine &B) {
- unsigned LengthA = A.Last->TotalLength + B.First.SpacesRequiredBefore;
- A.Last->Children.push_back(B.First);
- while (!A.Last->Children.empty()) {
- A.Last->Children[0].Parent = A.Last;
- A.Last->Children[0].TotalLength += LengthA;
- A.Last = &A.Last->Children[0];
- }
- }
-
- bool touchesRanges(const CharSourceRange &Range) {
- for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
- if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),
- Ranges[i].getBegin()) &&
- !SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
- Range.getBegin()))
- return true;
- }
- return false;
- }
-
- bool touchesLine(const AnnotatedLine &TheLine) {
- const FormatToken *First = &TheLine.First.FormatTok;
- const FormatToken *Last = &TheLine.Last->FormatTok;
- CharSourceRange LineRange = CharSourceRange::getTokenRange(
- First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset),
- Last->Tok.getLocation());
- return touchesRanges(LineRange);
- }
-
- bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
- const FormatToken *First = &TheLine.First.FormatTok;
- CharSourceRange LineRange = CharSourceRange::getCharRange(
- First->WhiteSpaceStart,
- First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset));
- return touchesRanges(LineRange);
+ BinPackInconclusiveFunctions =
+ HasBinPackedFunction || !HasOnePerLineFunction;
}
virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
- AnnotatedLines.push_back(AnnotatedLine(TheLine));
+ assert(!UnwrappedLines.empty());
+ UnwrappedLines.back().push_back(TheLine);
}
- /// \brief Add a new line and the required indent before the first Token
- /// of the \c UnwrappedLine if there was no structural parsing error.
- /// Returns the indent level of the \c UnwrappedLine.
- void formatFirstToken(const AnnotatedToken &RootToken,
- const AnnotatedToken *PreviousToken, unsigned Indent,
- bool InPPDirective, unsigned PreviousEndOfLineColumn) {
- const FormatToken &Tok = RootToken.FormatTok;
-
- unsigned Newlines =
- std::min(Tok.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
- if (Newlines == 0 && !Tok.IsFirst)
- Newlines = 1;
-
- if (!InPPDirective || Tok.HasUnescapedNewline) {
- // Insert extra new line before access specifiers.
- if (PreviousToken && PreviousToken->isOneOf(tok::semi, tok::r_brace) &&
- RootToken.isAccessSpecifier() && Tok.NewlinesBefore == 1)
- ++Newlines;
-
- Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0);
- } else {
- Whitespaces.replacePPWhitespace(RootToken, Newlines, Indent,
- PreviousEndOfLineColumn);
- }
+ virtual void finishRun() {
+ UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>());
}
- DiagnosticsEngine &Diag;
FormatStyle Style;
Lexer &Lex;
SourceManager &SourceMgr;
WhitespaceManager Whitespaces;
- std::vector<CharSourceRange> Ranges;
- std::vector<AnnotatedLine> AnnotatedLines;
+ SmallVector<CharSourceRange, 8> Ranges;
+ SmallVector<SmallVector<UnwrappedLine, 16>, 2> UnwrappedLines;
+
+ encoding::Encoding Encoding;
+ bool BinPackInconclusiveFunctions;
};
+} // end anonymous namespace
+
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
SourceManager &SourceMgr,
- std::vector<CharSourceRange> Ranges,
- DiagnosticConsumer *DiagClient) {
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- OwningPtr<DiagnosticConsumer> DiagPrinter;
- if (DiagClient == 0) {
- DiagPrinter.reset(new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts));
- DiagPrinter->BeginSourceFile(Lex.getLangOpts(), Lex.getPP());
- DiagClient = DiagPrinter.get();
- }
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
- DiagClient, false);
- Diagnostics.setSourceManager(&SourceMgr);
- Formatter formatter(Diagnostics, Style, Lex, SourceMgr, Ranges);
+ std::vector<CharSourceRange> Ranges) {
+ Formatter formatter(Style, Lex, SourceMgr, Ranges);
return formatter.format();
}
-LangOptions getFormattingLangOpts() {
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ std::vector<tooling::Range> Ranges,
+ StringRef FileName) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager SourceMgr(Diagnostics, Files);
+ llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, FileName);
+ const clang::FileEntry *Entry =
+ Files.getVirtualFile(FileName, Buf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(Entry, Buf);
+ FileID ID =
+ SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+ Lexer Lex(ID, SourceMgr.getBuffer(ID), SourceMgr,
+ getFormattingLangOpts(Style.Standard));
+ SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);
+ std::vector<CharSourceRange> CharRanges;
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ SourceLocation Start = StartOfFile.getLocWithOffset(Ranges[i].getOffset());
+ SourceLocation End = Start.getLocWithOffset(Ranges[i].getLength());
+ CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
+ }
+ return reformat(Style, Lex, SourceMgr, CharRanges);
+}
+
+LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard) {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
- LangOpts.CPlusPlus11 = 1;
+ LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
@@ -1400,5 +1396,82 @@ LangOptions getFormattingLangOpts() {
return LangOpts;
}
+const char *StyleOptionHelpDescription =
+ "Coding style, currently supports:\n"
+ " LLVM, Google, Chromium, Mozilla, WebKit.\n"
+ "Use -style=file to load style configuration from\n"
+ ".clang-format file located in one of the parent\n"
+ "directories of the source file (or current\n"
+ "directory for stdin).\n"
+ "Use -style=\"{key: value, ...}\" to set specific\n"
+ "parameters, e.g.:\n"
+ " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
+
+FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
+ // Fallback style in case the rest of this function can't determine a style.
+ StringRef FallbackStyle = "LLVM";
+ FormatStyle Style;
+ getPredefinedStyle(FallbackStyle, &Style);
+
+ if (StyleName.startswith("{")) {
+ // Parse YAML/JSON style from the command line.
+ if (llvm::error_code ec = parseConfiguration(StyleName, &Style)) {
+ llvm::errs() << "Error parsing -style: " << ec.message() << ", using "
+ << FallbackStyle << " style\n";
+ }
+ return Style;
+ }
+
+ if (!StyleName.equals_lower("file")) {
+ if (!getPredefinedStyle(StyleName, &Style))
+ llvm::errs() << "Invalid value for -style, using " << FallbackStyle
+ << " style\n";
+ return Style;
+ }
+
+ SmallString<128> Path(FileName);
+ llvm::sys::fs::make_absolute(Path);
+ for (StringRef Directory = Path; !Directory.empty();
+ Directory = llvm::sys::path::parent_path(Directory)) {
+ if (!llvm::sys::fs::is_directory(Directory))
+ continue;
+ SmallString<128> ConfigFile(Directory);
+
+ llvm::sys::path::append(ConfigFile, ".clang-format");
+ DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+ bool IsFile = false;
+ // Ignore errors from is_regular_file: we only need to know if we can read
+ // the file or not.
+ llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
+
+ if (!IsFile) {
+ // Try _clang-format too, since dotfiles are not commonly used on Windows.
+ ConfigFile = Directory;
+ llvm::sys::path::append(ConfigFile, "_clang-format");
+ DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+ llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
+ }
+
+ if (IsFile) {
+ OwningPtr<llvm::MemoryBuffer> Text;
+ if (llvm::error_code ec =
+ llvm::MemoryBuffer::getFile(ConfigFile.c_str(), Text)) {
+ llvm::errs() << ec.message() << "\n";
+ continue;
+ }
+ if (llvm::error_code ec = parseConfiguration(Text->getBuffer(), &Style)) {
+ llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()
+ << "\n";
+ continue;
+ }
+ DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
+ return Style;
+ }
+ }
+ llvm::errs() << "Can't find usable .clang-format, using " << FallbackStyle
+ << " style\n";
+ return Style;
+}
+
} // namespace format
} // namespace clang
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
new file mode 100644
index 000000000000..8ac704a3bb6d
--- /dev/null
+++ b/lib/Format/FormatToken.cpp
@@ -0,0 +1,204 @@
+//===--- FormatToken.cpp - Format C++ code --------------------------------===//
+//
+// 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 specific functions of \c FormatTokens and their
+/// roles.
+///
+//===----------------------------------------------------------------------===//
+
+#include "FormatToken.h"
+#include "ContinuationIndenter.h"
+#include "clang/Format/Format.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
+
+namespace clang {
+namespace format {
+
+TokenRole::~TokenRole() {}
+
+void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
+
+unsigned CommaSeparatedList::format(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (!State.NextToken->Previous || !State.NextToken->Previous->Previous ||
+ Commas.size() <= 2)
+ return 0;
+
+ // Ensure that we start on the opening brace.
+ const FormatToken *LBrace = State.NextToken->Previous->Previous;
+ if (LBrace->isNot(tok::l_brace) ||
+ LBrace->BlockKind == BK_Block ||
+ LBrace->Type == TT_DictLiteral ||
+ LBrace->Next->Type == TT_DesignatedInitializerPeriod)
+ return 0;
+
+ // Calculate the number of code points we have to format this list. As the
+ // first token is already placed, we have to subtract it.
+ unsigned RemainingCodePoints = Style.ColumnLimit - State.Column +
+ State.NextToken->Previous->ColumnWidth;
+
+ // Find the best ColumnFormat, i.e. the best number of columns to use.
+ const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
+ if (!Format)
+ return 0;
+
+ // Format the entire list.
+ unsigned Penalty = 0;
+ unsigned Column = 0;
+ unsigned Item = 0;
+ while (State.NextToken != LBrace->MatchingParen) {
+ bool NewLine = false;
+ unsigned ExtraSpaces = 0;
+
+ // If the previous token was one of our commas, we are now on the next item.
+ if (Item < Commas.size() && State.NextToken->Previous == Commas[Item]) {
+ if (!State.NextToken->isTrailingComment()) {
+ ExtraSpaces += Format->ColumnSizes[Column] - ItemLengths[Item];
+ ++Column;
+ }
+ ++Item;
+ }
+
+ if (Column == Format->Columns || State.NextToken->MustBreakBefore) {
+ Column = 0;
+ NewLine = true;
+ }
+
+ // Place token using the continuation indenter and store the penalty.
+ Penalty += Indenter->addTokenToState(State, NewLine, DryRun, ExtraSpaces);
+ }
+ return Penalty;
+}
+
+// Returns the lengths in code points between Begin and End (both included),
+// assuming that the entire sequence is put on a single line.
+static unsigned CodePointsBetween(const FormatToken *Begin,
+ const FormatToken *End) {
+ assert(End->TotalLength >= Begin->TotalLength);
+ return End->TotalLength - Begin->TotalLength + Begin->ColumnWidth;
+}
+
+void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
+ // FIXME: At some point we might want to do this for other lists, too.
+ if (!Token->MatchingParen || Token->isNot(tok::l_brace))
+ return;
+
+ FormatToken *ItemBegin = Token->Next;
+ SmallVector<bool, 8> MustBreakBeforeItem;
+
+ // The lengths of an item if it is put at the end of the line. This includes
+ // trailing comments which are otherwise ignored for column alignment.
+ SmallVector<unsigned, 8> EndOfLineItemLength;
+
+ bool HasNestedBracedList = false;
+ for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
+ // Skip comments on their own line.
+ while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment())
+ ItemBegin = ItemBegin->Next;
+
+ MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore);
+ if (ItemBegin->is(tok::l_brace))
+ HasNestedBracedList = true;
+ const FormatToken *ItemEnd = NULL;
+ if (i == Commas.size()) {
+ ItemEnd = Token->MatchingParen;
+ const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment();
+ ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd));
+ if (Style.Cpp11BracedListStyle) {
+ // In Cpp11 braced list style, the } and possibly other subsequent
+ // tokens will need to stay on a line with the last element.
+ while (ItemEnd->Next && !ItemEnd->Next->CanBreakBefore)
+ ItemEnd = ItemEnd->Next;
+ } else {
+ // In other braced lists styles, the "}" can be wrapped to the new line.
+ ItemEnd = Token->MatchingParen->Previous;
+ }
+ } else {
+ ItemEnd = Commas[i];
+ // The comma is counted as part of the item when calculating the length.
+ ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd));
+ // Consume trailing comments so the are included in EndOfLineItemLength.
+ if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline &&
+ ItemEnd->Next->isTrailingComment())
+ ItemEnd = ItemEnd->Next;
+ }
+ EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd));
+ // If there is a trailing comma in the list, the next item will start at the
+ // closing brace. Don't create an extra item for this.
+ if (ItemEnd->getNextNonComment() == Token->MatchingParen)
+ break;
+ ItemBegin = ItemEnd->Next;
+ }
+
+ // We can never place more than ColumnLimit / 3 items in a row (because of the
+ // spaces and the comma).
+ for (unsigned Columns = 1; Columns <= Style.ColumnLimit / 3; ++Columns) {
+ ColumnFormat Format;
+ Format.Columns = Columns;
+ Format.ColumnSizes.resize(Columns);
+ Format.LineCount = 1;
+ bool HasRowWithSufficientColumns = false;
+ unsigned Column = 0;
+ for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) {
+ assert(i < MustBreakBeforeItem.size());
+ if (MustBreakBeforeItem[i] || Column == Columns) {
+ ++Format.LineCount;
+ Column = 0;
+ }
+ if (Column == Columns - 1)
+ HasRowWithSufficientColumns = true;
+ unsigned length =
+ (Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i];
+ Format.ColumnSizes[Column] =
+ std::max(Format.ColumnSizes[Column], length);
+ ++Column;
+ }
+ // If all rows are terminated early (e.g. by trailing comments), we don't
+ // need to look further.
+ if (!HasRowWithSufficientColumns)
+ break;
+ Format.TotalWidth = Columns - 1; // Width of the N-1 spaces.
+ for (unsigned i = 0; i < Columns; ++i) {
+ Format.TotalWidth += Format.ColumnSizes[i];
+ }
+
+ // Ignore layouts that are bound to violate the column limit.
+ if (Format.TotalWidth > Style.ColumnLimit)
+ continue;
+
+ // If this braced list has nested braced list, we format it either with one
+ // element per line or with all elements on one line.
+ if (HasNestedBracedList && Columns > 1 && Format.LineCount > 1)
+ continue;
+
+ Formats.push_back(Format);
+ }
+}
+
+const CommaSeparatedList::ColumnFormat *
+CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
+ const ColumnFormat *BestFormat = NULL;
+ for (SmallVector<ColumnFormat, 4>::const_reverse_iterator
+ I = Formats.rbegin(),
+ E = Formats.rend();
+ I != E; ++I) {
+ if (I->TotalWidth <= RemainingCharacters) {
+ if (BestFormat && I->LineCount > BestFormat->LineCount)
+ break;
+ BestFormat = &*I;
+ }
+ }
+ return BestFormat;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
new file mode 100644
index 000000000000..2145ee28dcc0
--- /dev/null
+++ b/lib/Format/FormatToken.h
@@ -0,0 +1,452 @@
+//===--- FormatToken.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 contains the declaration of the FormatToken, a wrapper
+/// around Token with additional information related to formatting.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
+#define LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
+
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+namespace format {
+
+enum TokenType {
+ TT_ArrayInitializerLSquare,
+ TT_ArraySubscriptLSquare,
+ TT_BinaryOperator,
+ TT_BitFieldColon,
+ TT_BlockComment,
+ TT_CastRParen,
+ TT_ConditionalExpr,
+ TT_CtorInitializerColon,
+ TT_CtorInitializerComma,
+ TT_DesignatedInitializerPeriod,
+ TT_DictLiteral,
+ TT_ImplicitStringLiteral,
+ TT_InlineASMColon,
+ TT_InheritanceColon,
+ TT_FunctionTypeLParen,
+ TT_LambdaLSquare,
+ TT_LineComment,
+ TT_ObjCBlockLParen,
+ TT_ObjCDecl,
+ TT_ObjCForIn,
+ TT_ObjCMethodExpr,
+ TT_ObjCMethodSpecifier,
+ TT_ObjCProperty,
+ TT_ObjCSelectorName,
+ TT_OverloadedOperator,
+ TT_OverloadedOperatorLParen,
+ TT_PointerOrReference,
+ TT_PureVirtualSpecifier,
+ TT_RangeBasedForLoopColon,
+ TT_StartOfName,
+ TT_TemplateCloser,
+ TT_TemplateOpener,
+ TT_TrailingReturnArrow,
+ TT_TrailingUnaryOperator,
+ TT_UnaryOperator,
+ TT_Unknown
+};
+
+// Represents what type of block a set of braces open.
+enum BraceBlockKind {
+ BK_Unknown,
+ BK_Block,
+ BK_BracedInit
+};
+
+// The packing kind of a function's parameters.
+enum ParameterPackingKind {
+ PPK_BinPacked,
+ PPK_OnePerLine,
+ PPK_Inconclusive
+};
+
+enum FormatDecision {
+ FD_Unformatted,
+ FD_Continue,
+ FD_Break
+};
+
+class TokenRole;
+class AnnotatedLine;
+
+/// \brief A wrapper around a \c Token storing information about the
+/// whitespace characters preceeding it.
+struct FormatToken {
+ FormatToken()
+ : NewlinesBefore(0), HasUnescapedNewline(false), LastNewlineOffset(0),
+ ColumnWidth(0), LastLineColumnWidth(0), IsMultiline(false),
+ IsFirst(false), MustBreakBefore(false), IsUnterminatedLiteral(false),
+ BlockKind(BK_Unknown), Type(TT_Unknown), SpacesRequiredBefore(0),
+ CanBreakBefore(false), ClosesTemplateDeclaration(false),
+ ParameterCount(0), PackingKind(PPK_Inconclusive), TotalLength(0),
+ UnbreakableTailLength(0), BindingStrength(0), SplitPenalty(0),
+ LongestObjCSelectorName(0), FakeRParens(0),
+ StartsBinaryExpression(false), EndsBinaryExpression(false),
+ LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
+ MatchingParen(NULL), Previous(NULL), Next(NULL),
+ Decision(FD_Unformatted), Finalized(false) {}
+
+ /// \brief The \c Token.
+ Token Tok;
+
+ /// \brief The number of newlines immediately before the \c Token.
+ ///
+ /// This can be used to determine what the user wrote in the original code
+ /// and thereby e.g. leave an empty line between two function definitions.
+ unsigned NewlinesBefore;
+
+ /// \brief Whether there is at least one unescaped newline before the \c
+ /// Token.
+ bool HasUnescapedNewline;
+
+ /// \brief The range of the whitespace immediately preceeding the \c Token.
+ SourceRange WhitespaceRange;
+
+ /// \brief The offset just past the last '\n' in this token's leading
+ /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
+ unsigned LastNewlineOffset;
+
+ /// \brief The width of the non-whitespace parts of the token (or its first
+ /// line for multi-line tokens) in columns.
+ /// We need this to correctly measure number of columns a token spans.
+ unsigned ColumnWidth;
+
+ /// \brief Contains the width in columns of the last line of a multi-line
+ /// token.
+ unsigned LastLineColumnWidth;
+
+ /// \brief Whether the token text contains newlines (escaped or not).
+ bool IsMultiline;
+
+ /// \brief Indicates that this is the first token.
+ bool IsFirst;
+
+ /// \brief Whether there must be a line break before this token.
+ ///
+ /// This happens for example when a preprocessor directive ended directly
+ /// before the token.
+ bool MustBreakBefore;
+
+ /// \brief Returns actual token start location without leading escaped
+ /// newlines and whitespace.
+ ///
+ /// This can be different to Tok.getLocation(), which includes leading escaped
+ /// newlines.
+ SourceLocation getStartOfNonWhitespace() const {
+ return WhitespaceRange.getEnd();
+ }
+
+ /// \brief The raw text of the token.
+ ///
+ /// Contains the raw token text without leading whitespace and without leading
+ /// escaped newlines.
+ StringRef TokenText;
+
+ /// \brief Set to \c true if this token is an unterminated literal.
+ bool IsUnterminatedLiteral;
+
+ /// \brief Contains the kind of block if this token is a brace.
+ BraceBlockKind BlockKind;
+
+ TokenType Type;
+
+ /// \brief The number of spaces that should be inserted before this token.
+ unsigned SpacesRequiredBefore;
+
+ /// \brief \c true if it is allowed to break before this token.
+ bool CanBreakBefore;
+
+ bool ClosesTemplateDeclaration;
+
+ /// \brief Number of parameters, if this is "(", "[" or "<".
+ ///
+ /// This is initialized to 1 as we don't need to distinguish functions with
+ /// 0 parameters from functions with 1 parameter. Thus, we can simply count
+ /// the number of commas.
+ unsigned ParameterCount;
+
+ /// \brief A token can have a special role that can carry extra information
+ /// about the token's formatting.
+ llvm::OwningPtr<TokenRole> Role;
+
+ /// \brief If this is an opening parenthesis, how are the parameters packed?
+ ParameterPackingKind PackingKind;
+
+ /// \brief The total length of the unwrapped line up to and including this
+ /// token.
+ unsigned TotalLength;
+
+ /// \brief The original 0-based column of this token, including expanded tabs.
+ /// The configured TabWidth is used as tab width.
+ unsigned OriginalColumn;
+
+ /// \brief The length of following tokens until the next natural split point,
+ /// or the next token that can be broken.
+ unsigned UnbreakableTailLength;
+
+ // FIXME: Come up with a 'cleaner' concept.
+ /// \brief The binding strength of a token. This is a combined value of
+ /// operator precedence, parenthesis nesting, etc.
+ unsigned BindingStrength;
+
+ /// \brief Penalty for inserting a line break before this token.
+ unsigned SplitPenalty;
+
+ /// \brief If this is the first ObjC selector name in an ObjC method
+ /// definition or call, this contains the length of the longest name.
+ unsigned LongestObjCSelectorName;
+
+ /// \brief Stores the number of required fake parentheses and the
+ /// corresponding operator precedence.
+ ///
+ /// If multiple fake parentheses start at a token, this vector stores them in
+ /// reverse order, i.e. inner fake parenthesis first.
+ SmallVector<prec::Level, 4> FakeLParens;
+ /// \brief Insert this many fake ) after this token for correct indentation.
+ unsigned FakeRParens;
+
+ /// \brief \c true if this token starts a binary expression, i.e. has at least
+ /// one fake l_paren with a precedence greater than prec::Unknown.
+ bool StartsBinaryExpression;
+ /// \brief \c true if this token ends a binary expression.
+ bool EndsBinaryExpression;
+
+ /// \brief Is this the last "." or "->" in a builder-type call?
+ bool LastInChainOfCalls;
+
+ /// \brief Is this token part of a \c DeclStmt defining multiple variables?
+ ///
+ /// Only set if \c Type == \c TT_StartOfName.
+ bool PartOfMultiVariableDeclStmt;
+
+ bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
+ return is(K1) || is(K2);
+ }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
+ return is(K1) || is(K2) || is(K3);
+ }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
+ tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
+ tok::TokenKind K6 = tok::NUM_TOKENS,
+ tok::TokenKind K7 = tok::NUM_TOKENS,
+ tok::TokenKind K8 = tok::NUM_TOKENS,
+ tok::TokenKind K9 = tok::NUM_TOKENS,
+ tok::TokenKind K10 = tok::NUM_TOKENS,
+ tok::TokenKind K11 = tok::NUM_TOKENS,
+ tok::TokenKind K12 = tok::NUM_TOKENS) const {
+ return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
+ is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
+ }
+
+ bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
+
+ bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
+ return Tok.isObjCAtKeyword(Kind);
+ }
+
+ bool isAccessSpecifier(bool ColonRequired = true) const {
+ return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
+ (!ColonRequired || (Next && Next->is(tok::colon)));
+ }
+
+ 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));
+ }
+
+ /// \brief Returns whether \p Tok is ([{ or a template opening <.
+ bool opensScope() const {
+ return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
+ Type == TT_TemplateOpener;
+ }
+ /// \brief Returns whether \p Tok is )]} or a template closing >.
+ bool closesScope() const {
+ return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
+ Type == TT_TemplateCloser;
+ }
+
+ /// \brief Returns \c true if this is a "." or "->" accessing a member.
+ bool isMemberAccess() const {
+ return isOneOf(tok::arrow, tok::period) &&
+ Type != TT_DesignatedInitializerPeriod;
+ }
+
+ bool isUnaryOperator() const {
+ switch (Tok.getKind()) {
+ case tok::plus:
+ case tok::plusplus:
+ case tok::minus:
+ case tok::minusminus:
+ case tok::exclaim:
+ case tok::tilde:
+ case tok::kw_sizeof:
+ case tok::kw_alignof:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isBinaryOperator() const {
+ // Comma is a binary operator, but does not behave as such wrt. formatting.
+ return getPrecedence() > prec::Comma;
+ }
+
+ bool isTrailingComment() const {
+ return is(tok::comment) && (!Next || Next->NewlinesBefore > 0);
+ }
+
+ prec::Level getPrecedence() const {
+ return getBinOpPrecedence(Tok.getKind(), true, true);
+ }
+
+ /// \brief Returns the previous token ignoring comments.
+ FormatToken *getPreviousNonComment() const {
+ FormatToken *Tok = Previous;
+ while (Tok != NULL && Tok->is(tok::comment))
+ Tok = Tok->Previous;
+ return Tok;
+ }
+
+ /// \brief Returns the next token ignoring comments.
+ const FormatToken *getNextNonComment() const {
+ const FormatToken *Tok = Next;
+ while (Tok != NULL && Tok->is(tok::comment))
+ Tok = Tok->Next;
+ return Tok;
+ }
+
+ /// \brief Returns \c true if this tokens starts a block-type list, i.e. a
+ /// list that should be indented with a block indent.
+ bool opensBlockTypeList(const FormatStyle &Style) const {
+ return Type == TT_ArrayInitializerLSquare ||
+ (is(tok::l_brace) &&
+ (BlockKind == BK_Block || Type == TT_DictLiteral ||
+ !Style.Cpp11BracedListStyle));
+ }
+
+ /// \brief Same as opensBlockTypeList, but for the closing token.
+ bool closesBlockTypeList(const FormatStyle &Style) const {
+ return MatchingParen && MatchingParen->opensBlockTypeList(Style);
+ }
+
+ FormatToken *MatchingParen;
+
+ FormatToken *Previous;
+ FormatToken *Next;
+
+ SmallVector<AnnotatedLine *, 1> Children;
+
+ /// \brief Stores the formatting decision for the token once it was made.
+ FormatDecision Decision;
+
+ /// \brief If \c true, this token has been fully formatted (indented and
+ /// potentially re-formatted inside), and we do not allow further formatting
+ /// changes.
+ bool Finalized;
+
+private:
+ // Disallow copying.
+ FormatToken(const FormatToken &) LLVM_DELETED_FUNCTION;
+ void operator=(const FormatToken &) LLVM_DELETED_FUNCTION;
+};
+
+class ContinuationIndenter;
+struct LineState;
+
+class TokenRole {
+public:
+ TokenRole(const FormatStyle &Style) : Style(Style) {}
+ virtual ~TokenRole();
+
+ /// \brief After the \c TokenAnnotator has finished annotating all the tokens,
+ /// this function precomputes required information for formatting.
+ virtual void precomputeFormattingInfos(const FormatToken *Token);
+
+ /// \brief Apply the special formatting that the given role demands.
+ ///
+ /// Continues formatting from \p State leaving indentation to \p Indenter and
+ /// returns the total penalty that this formatting incurs.
+ virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun) {
+ return 0;
+ }
+
+ /// \brief Notifies the \c Role that a comma was found.
+ virtual void CommaFound(const FormatToken *Token) {}
+
+protected:
+ const FormatStyle &Style;
+};
+
+class CommaSeparatedList : public TokenRole {
+public:
+ CommaSeparatedList(const FormatStyle &Style) : TokenRole(Style) {}
+
+ virtual void precomputeFormattingInfos(const FormatToken *Token);
+
+ virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun);
+
+ /// \brief Adds \p Token as the next comma to the \c CommaSeparated list.
+ virtual void CommaFound(const FormatToken *Token) { Commas.push_back(Token); }
+
+private:
+ /// \brief A struct that holds information on how to format a given list with
+ /// a specific number of columns.
+ struct ColumnFormat {
+ /// \brief The number of columns to use.
+ unsigned Columns;
+
+ /// \brief The total width in characters.
+ unsigned TotalWidth;
+
+ /// \brief The number of lines required for this format.
+ unsigned LineCount;
+
+ /// \brief The size of each column in characters.
+ SmallVector<unsigned, 8> ColumnSizes;
+ };
+
+ /// \brief Calculate which \c ColumnFormat fits best into
+ /// \p RemainingCharacters.
+ const ColumnFormat *getColumnFormat(unsigned RemainingCharacters) const;
+
+ /// \brief The ordered \c FormatTokens making up the commas of this list.
+ SmallVector<const FormatToken *, 8> Commas;
+
+ /// \brief The length of each of the list's items in characters including the
+ /// trailing comma.
+ SmallVector<unsigned, 8> ItemLengths;
+
+ /// \brief Precomputed formats that can be used for this list.
+ SmallVector<ColumnFormat, 4> Formats;
+};
+
+} // namespace format
+} // namespace clang
+
+#endif // LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 17abb01d181d..074e1d78454b 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -15,61 +15,12 @@
#include "TokenAnnotator.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
#include "llvm/Support/Debug.h"
namespace clang {
namespace format {
-bool AnnotatedToken::isUnaryOperator() const {
- switch (FormatTok.Tok.getKind()) {
- case tok::plus:
- case tok::plusplus:
- case tok::minus:
- case tok::minusminus:
- case tok::exclaim:
- case tok::tilde:
- case tok::kw_sizeof:
- case tok::kw_alignof:
- return true;
- default:
- return false;
- }
-}
-
-bool AnnotatedToken::isBinaryOperator() const {
- // Comma is a binary operator, but does not behave as such wrt. formatting.
- return getPrecedence(*this) > prec::Comma;
-}
-
-bool AnnotatedToken::isTrailingComment() const {
- return is(tok::comment) &&
- (Children.empty() || Children[0].FormatTok.NewlinesBefore > 0);
-}
-
-AnnotatedToken *AnnotatedToken::getPreviousNoneComment() const {
- AnnotatedToken *Tok = Parent;
- while (Tok != NULL && Tok->is(tok::comment))
- Tok = Tok->Parent;
- return Tok;
-}
-
-const AnnotatedToken *AnnotatedToken::getNextNoneComment() const {
- const AnnotatedToken *Tok = Children.empty() ? NULL : &Children[0];
- while (Tok != NULL && Tok->is(tok::comment))
- Tok = Tok->Children.empty() ? NULL : &Tok->Children[0];
- return Tok;
-}
-
-bool AnnotatedToken::closesScope() const {
- return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
- Type == TT_TemplateCloser;
-}
-
-bool AnnotatedToken::opensScope() const {
- return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
- Type == TT_TemplateOpener;
-}
+namespace {
/// \brief A parser that gathers additional information about tokens.
///
@@ -78,11 +29,11 @@ bool AnnotatedToken::opensScope() const {
/// into template parameter lists.
class AnnotatingParser {
public:
- AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line,
+ AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
IdentifierInfo &Ident_in)
- : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
- KeywordVirtualFound(false), NameFound(false), Ident_in(Ident_in) {
- Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false));
+ : Style(Style), Line(Line), CurrentToken(Line.First),
+ KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) {
+ Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
}
private:
@@ -90,7 +41,7 @@ private:
if (CurrentToken == NULL)
return false;
ScopedContextCreator ContextCreator(*this, tok::less, 10);
- AnnotatedToken *Left = CurrentToken->Parent;
+ FormatToken *Left = CurrentToken->Previous;
Contexts.back().IsExpression = false;
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::greater)) {
@@ -101,8 +52,18 @@ private:
return true;
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace,
- tok::pipepipe, tok::ampamp, tok::question,
- tok::colon))
+ tok::question, tok::colon))
+ 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
+ // angles are inside an expression, the ||/&& might also be a binary
+ // operator that was misinterpreted because we are parsing template
+ // parameters.
+ // FIXME: This is getting out of hand, write a decent parser.
+ if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
+ (CurrentToken->Previous->Type == TT_BinaryOperator ||
+ Contexts[Contexts.size() - 2].IsExpression) &&
+ Line.First->isNot(tok::kw_template))
return false;
updateParameterCount(Left, CurrentToken);
if (!consumeToken())
@@ -121,42 +82,66 @@ private:
Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
bool StartsObjCMethodExpr = false;
- AnnotatedToken *Left = CurrentToken->Parent;
+ FormatToken *Left = CurrentToken->Previous;
if (CurrentToken->is(tok::caret)) {
// ^( starts a block.
Left->Type = TT_ObjCBlockLParen;
- } else if (AnnotatedToken *MaybeSel = Left->Parent) {
+ } else if (FormatToken *MaybeSel = Left->Previous) {
// @selector( starts a selector.
- if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
- MaybeSel->Parent->is(tok::at)) {
+ if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
+ MaybeSel->Previous->is(tok::at)) {
StartsObjCMethodExpr = true;
}
}
+ if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert,
+ tok::kw_if, tok::kw_while)) {
+ // static_assert, if and while usually contain expressions.
+ Contexts.back().IsExpression = true;
+ } else if (Left->Previous && Left->Previous->is(tok::r_square) &&
+ Left->Previous->MatchingParen &&
+ Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
+ // This is a parameter list of a lambda expression.
+ Contexts.back().IsExpression = false;
+ }
+
if (StartsObjCMethodExpr) {
Contexts.back().ColonIsObjCMethodExpr = true;
Left->Type = TT_ObjCMethodExpr;
}
+ bool MightBeFunctionType = CurrentToken->is(tok::star);
+ bool HasMultipleLines = false;
+ bool HasMultipleParametersOnALine = false;
while (CurrentToken != NULL) {
// LookForDecls is set when "if (" has been seen. Check for
// 'identifier' '*' 'identifier' followed by not '=' -- this
// '*' has to be a binary operator but determineStarAmpUsage() will
// categorize it as an unary operator, so set the right type here.
- if (LookForDecls && !CurrentToken->Children.empty()) {
- AnnotatedToken &Prev = *CurrentToken->Parent;
- AnnotatedToken &Next = CurrentToken->Children[0];
- if (Prev.Parent->is(tok::identifier) &&
- Prev.isOneOf(tok::star, tok::amp, tok::ampamp) &&
- CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
- Prev.Type = TT_BinaryOperator;
- LookForDecls = false;
+ if (LookForDecls && CurrentToken->Next) {
+ FormatToken *Prev = CurrentToken->getPreviousNonComment();
+ if (Prev) {
+ FormatToken *PrevPrev = Prev->getPreviousNonComment();
+ FormatToken *Next = CurrentToken->Next;
+ if (PrevPrev && PrevPrev->is(tok::identifier) &&
+ Prev->isOneOf(tok::star, tok::amp, tok::ampamp) &&
+ CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) {
+ Prev->Type = TT_BinaryOperator;
+ LookForDecls = false;
+ }
}
}
+ if (CurrentToken->Previous->Type == TT_PointerOrReference &&
+ CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
+ tok::coloncolon))
+ MightBeFunctionType = true;
if (CurrentToken->is(tok::r_paren)) {
- if (CurrentToken->Parent->closesScope())
- CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true;
+ if (MightBeFunctionType && CurrentToken->Next &&
+ (CurrentToken->Next->is(tok::l_paren) ||
+ (CurrentToken->Next->is(tok::l_square) &&
+ !Contexts.back().IsExpression)))
+ Left->Type = TT_FunctionTypeLParen;
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -168,14 +153,27 @@ private:
}
}
+ if (!HasMultipleLines)
+ Left->PackingKind = PPK_Inconclusive;
+ else if (HasMultipleParametersOnALine)
+ Left->PackingKind = PPK_BinPacked;
+ else
+ Left->PackingKind = PPK_OnePerLine;
+
next();
return true;
}
if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
return false;
updateParameterCount(Left, CurrentToken);
+ if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
+ !CurrentToken->Next->HasUnescapedNewline &&
+ !CurrentToken->Next->isTrailingComment())
+ HasMultipleParametersOnALine = true;
if (!consumeToken())
return false;
+ if (CurrentToken && CurrentToken->HasUnescapedNewline)
+ HasMultipleLines = true;
}
return false;
}
@@ -184,34 +182,35 @@ private:
if (!CurrentToken)
return false;
- // A '[' could be an index subscript (after an indentifier or after
+ // A '[' could be an index subscript (after an identifier or after
// ')' or ']'), it could be the start of an Objective-C method
// expression, or it could the the start of an Objective-C array literal.
- AnnotatedToken *Left = CurrentToken->Parent;
- AnnotatedToken *Parent = Left->getPreviousNoneComment();
+ FormatToken *Left = CurrentToken->Previous;
+ FormatToken *Parent = Left->getPreviousNonComment();
bool StartsObjCMethodExpr =
- Contexts.back().CanBeExpression &&
+ Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare &&
(!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
tok::kw_return, tok::kw_throw) ||
Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn ||
Parent->Type == TT_CastRParen ||
- getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) >
- prec::Unknown);
+ getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown);
ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
Contexts.back().IsExpression = true;
- bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at);
+ bool ColonFound = false;
if (StartsObjCMethodExpr) {
Contexts.back().ColonIsObjCMethodExpr = true;
Left->Type = TT_ObjCMethodExpr;
- } else if (StartsObjCArrayLiteral) {
- Left->Type = TT_ObjCArrayLiteral;
+ } else if (Parent && Parent->is(tok::at)) {
+ Left->Type = TT_ArrayInitializerLSquare;
+ } else if (Left->Type == TT_Unknown) {
+ Left->Type = TT_ArraySubscriptLSquare;
}
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::r_square)) {
- if (!CurrentToken->Children.empty() &&
- CurrentToken->Children[0].is(tok::l_paren)) {
+ if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
+ Left->Type == TT_ObjCMethodExpr) {
// An ObjC method call is rarely followed by an open parenthesis.
// FIXME: Do we incorrectly label ":" with this?
StartsObjCMethodExpr = false;
@@ -224,8 +223,6 @@ private:
// binary operator.
if (Parent != NULL && Parent->Type == TT_PointerOrReference)
Parent->Type = TT_BinaryOperator;
- } else if (StartsObjCArrayLiteral) {
- CurrentToken->Type = TT_ObjCArrayLiteral;
}
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -237,6 +234,12 @@ private:
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
return false;
+ if (CurrentToken->is(tok::colon))
+ ColonFound = true;
+ if (CurrentToken->is(tok::comma) &&
+ (Left->Type == TT_ArraySubscriptLSquare ||
+ (Left->Type == TT_ObjCMethodExpr && !ColonFound)))
+ Left->Type = TT_ArrayInitializerLSquare;
updateParameterCount(Left, CurrentToken);
if (!consumeToken())
return false;
@@ -246,8 +249,10 @@ private:
bool parseBrace() {
if (CurrentToken != NULL) {
+ FormatToken *Left = CurrentToken->Previous;
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
- AnnotatedToken *Left = CurrentToken->Parent;
+ Contexts.back().ColonIsDictLiteral = true;
+
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::r_brace)) {
Left->MatchingParen = CurrentToken;
@@ -258,6 +263,8 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
+ if (CurrentToken->is(tok::colon))
+ Left->Type = TT_DictLiteral;
if (!consumeToken())
return false;
}
@@ -267,11 +274,15 @@ private:
return true;
}
- void updateParameterCount(AnnotatedToken *Left, AnnotatedToken *Current) {
- if (Current->is(tok::comma))
+ void updateParameterCount(FormatToken *Left, FormatToken *Current) {
+ if (Current->is(tok::comma)) {
++Left->ParameterCount;
- else if (Left->ParameterCount == 0 && Current->isNot(tok::comment))
+ if (!Left->Role)
+ Left->Role.reset(new CommaSeparatedList(Style));
+ Left->Role->CommaFound(Current);
+ } else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) {
Left->ParameterCount = 1;
+ }
}
bool parseConditional() {
@@ -294,40 +305,45 @@ private:
if (!parseAngle())
return false;
if (CurrentToken != NULL)
- CurrentToken->Parent->ClosesTemplateDeclaration = true;
+ CurrentToken->Previous->ClosesTemplateDeclaration = true;
return true;
}
return false;
}
bool consumeToken() {
- AnnotatedToken *Tok = CurrentToken;
+ FormatToken *Tok = CurrentToken;
next();
- switch (Tok->FormatTok.Tok.getKind()) {
+ switch (Tok->Tok.getKind()) {
case tok::plus:
case tok::minus:
- if (Tok->Parent == NULL && Line.MustBeDeclaration)
+ if (Tok->Previous == NULL && Line.MustBeDeclaration)
Tok->Type = TT_ObjCMethodSpecifier;
break;
case tok::colon:
- if (Tok->Parent == NULL)
+ if (Tok->Previous == NULL)
return false;
// Colons from ?: are handled in parseConditional().
- if (Tok->Parent->is(tok::r_paren) && Contexts.size() == 1) {
+ if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) {
Tok->Type = TT_CtorInitializerColon;
+ } else if (Contexts.back().ColonIsDictLiteral) {
+ Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
- Line.First.Type == TT_ObjCMethodSpecifier) {
+ Line.First->Type == TT_ObjCMethodSpecifier) {
Tok->Type = TT_ObjCMethodExpr;
- Tok->Parent->Type = TT_ObjCSelectorName;
- if (Tok->Parent->FormatTok.TokenLength >
- Contexts.back().LongestObjCSelectorName)
- Contexts.back().LongestObjCSelectorName =
- Tok->Parent->FormatTok.TokenLength;
+ Tok->Previous->Type = TT_ObjCSelectorName;
+ if (Tok->Previous->ColumnWidth >
+ Contexts.back().LongestObjCSelectorName) {
+ Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth;
+ }
if (Contexts.back().FirstObjCSelectorName == NULL)
- Contexts.back().FirstObjCSelectorName = Tok->Parent;
+ Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
Tok->Type = TT_RangeBasedForLoopColon;
- } else if (Contexts.size() == 1) {
+ } else if (CurrentToken != NULL &&
+ CurrentToken->is(tok::numeric_constant)) {
+ Tok->Type = TT_BitFieldColon;
+ } else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) {
Tok->Type = TT_InheritanceColon;
} else if (Contexts.back().ContextKind == tok::l_paren) {
Tok->Type = TT_InlineASMColon;
@@ -337,7 +353,7 @@ private:
case tok::kw_while:
if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
next();
- if (!parseParens(/*LookForDecls=*/ true))
+ if (!parseParens(/*LookForDecls=*/true))
return false;
}
break;
@@ -350,7 +366,8 @@ private:
case tok::l_paren:
if (!parseParens())
return false;
- if (Line.MustBeDeclaration && NameFound && !Contexts.back().IsExpression)
+ if (Line.MustBeDeclaration && Contexts.size() == 1 &&
+ !Contexts.back().IsExpression)
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -362,7 +379,7 @@ private:
return false;
break;
case tok::less:
- if (parseAngle())
+ if (Tok->Previous && !Tok->Previous->Tok.isLiteral() && parseAngle())
Tok->Type = TT_TemplateOpener;
else {
Tok->Type = TT_BinaryOperator;
@@ -375,20 +392,26 @@ private:
return false;
case tok::r_brace:
// Lines can start with '}'.
- if (Tok->Parent != NULL)
+ if (Tok->Previous != NULL)
return false;
break;
case tok::greater:
Tok->Type = TT_BinaryOperator;
break;
case tok::kw_operator:
- while (CurrentToken && CurrentToken->isNot(tok::l_paren)) {
+ while (CurrentToken &&
+ !CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) {
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
+ if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator)
+ CurrentToken->Previous->Type = TT_OverloadedOperator;
}
- if (CurrentToken)
+ if (CurrentToken) {
CurrentToken->Type = TT_OverloadedOperatorLParen;
+ if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ CurrentToken->Previous->Type = TT_OverloadedOperator;
+ }
break;
case tok::question:
parseConditional();
@@ -397,13 +420,15 @@ private:
parseTemplateDeclaration();
break;
case tok::identifier:
- if (Line.First.is(tok::kw_for) &&
- Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in)
+ if (Line.First->is(tok::kw_for) &&
+ Tok->Tok.getIdentifierInfo() == &Ident_in)
Tok->Type = TT_ObjCForIn;
break;
case tok::comma:
if (Contexts.back().FirstStartOfName)
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
+ if (Contexts.back().InCtorInitializer)
+ Tok->Type = TT_CtorInitializerComma;
break;
default:
break;
@@ -416,8 +441,7 @@ private:
if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
next();
while (CurrentToken != NULL) {
- if (CurrentToken->isNot(tok::comment) ||
- !CurrentToken->Children.empty())
+ if (CurrentToken->isNot(tok::comment) || CurrentToken->Next)
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
@@ -447,11 +471,15 @@ private:
next();
if (CurrentToken == NULL)
return;
+ if (CurrentToken->Tok.is(tok::numeric_constant)) {
+ CurrentToken->SpacesRequiredBefore = 1;
+ return;
+ }
// Hashes in the middle of a line can lead to any strange token
// sequence.
- if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
+ if (CurrentToken->Tok.getIdentifierInfo() == NULL)
return;
- switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
parseIncludeDirective();
@@ -473,9 +501,6 @@ private:
public:
LineType parseLine() {
- int PeriodsAndArrows = 0;
- AnnotatedToken *LastPeriodOrArrow = NULL;
- bool CanBeBuilderTypeStmt = true;
if (CurrentToken->is(tok::hash)) {
parsePreprocessorDirective();
return LT_PreprocessorDirective;
@@ -483,27 +508,13 @@ public:
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
- if (CurrentToken->isOneOf(tok::period, tok::arrow)) {
- ++PeriodsAndArrows;
- LastPeriodOrArrow = CurrentToken;
- }
- AnnotatedToken *TheToken = CurrentToken;
if (!consumeToken())
return LT_Invalid;
- if (getPrecedence(*TheToken) > prec::Assignment &&
- TheToken->Type == TT_BinaryOperator)
- CanBeBuilderTypeStmt = false;
}
if (KeywordVirtualFound)
return LT_VirtualFunctionDecl;
- // Assume a builder-type call if there are 2 or more "." and "->".
- if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt) {
- LastPeriodOrArrow->LastInChainOfCalls = true;
- return LT_BuilderTypeCall;
- }
-
- if (Line.First.Type == TT_ObjCMethodSpecifier) {
+ if (Line.First->Type == TT_ObjCMethodSpecifier) {
if (Contexts.back().FirstObjCSelectorName != NULL)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
@@ -520,15 +531,20 @@ private:
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
}
- if (CurrentToken != NULL && !CurrentToken->Children.empty())
- CurrentToken = &CurrentToken->Children[0];
- else
- CurrentToken = NULL;
-
- // Reset token type in case we have already looked at it and then recovered
- // from an error (e.g. failure to find the matching >).
if (CurrentToken != NULL)
- CurrentToken->Type = TT_Unknown;
+ CurrentToken = CurrentToken->Next;
+
+ if (CurrentToken != NULL) {
+ // Reset token type in case we have already looked at it and then
+ // recovered from an error (e.g. failure to find the matching >).
+ if (CurrentToken->Type != TT_LambdaLSquare &&
+ CurrentToken->Type != TT_ImplicitStringLiteral)
+ CurrentToken->Type = TT_Unknown;
+ if (CurrentToken->Role)
+ CurrentToken->Role.reset(NULL);
+ CurrentToken->FakeLParens.clear();
+ CurrentToken->FakeRParens = 0;
+ }
}
/// \brief A struct to hold information valid in a specific context, e.g.
@@ -538,19 +554,22 @@ private:
bool IsExpression)
: ContextKind(ContextKind), BindingStrength(BindingStrength),
LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
- ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
- FirstStartOfName(NULL), IsExpression(IsExpression),
- CanBeExpression(true) {}
+ ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false),
+ FirstObjCSelectorName(NULL), FirstStartOfName(NULL),
+ IsExpression(IsExpression), CanBeExpression(true),
+ InCtorInitializer(false) {}
tok::TokenKind ContextKind;
unsigned BindingStrength;
unsigned LongestObjCSelectorName;
bool ColonIsForRangeExpr;
+ bool ColonIsDictLiteral;
bool ColonIsObjCMethodExpr;
- AnnotatedToken *FirstObjCSelectorName;
- AnnotatedToken *FirstStartOfName;
+ FormatToken *FirstObjCSelectorName;
+ FormatToken *FirstStartOfName;
bool IsExpression;
bool CanBeExpression;
+ bool InCtorInitializer;
};
/// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -561,21 +580,22 @@ private:
ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind,
unsigned Increase)
: P(P) {
- P.Contexts.push_back(
- Context(ContextKind, P.Contexts.back().BindingStrength + Increase,
- P.Contexts.back().IsExpression));
+ P.Contexts.push_back(Context(ContextKind,
+ P.Contexts.back().BindingStrength + Increase,
+ P.Contexts.back().IsExpression));
}
~ScopedContextCreator() { P.Contexts.pop_back(); }
};
- void determineTokenType(AnnotatedToken &Current) {
- if (getPrecedence(Current) == prec::Assignment &&
- (!Current.Parent || Current.Parent->isNot(tok::kw_operator))) {
+ void determineTokenType(FormatToken &Current) {
+ if (Current.getPrecedence() == prec::Assignment &&
+ !Line.First->isOneOf(tok::kw_template, tok::kw_using) &&
+ (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
- for (AnnotatedToken *Previous = Current.Parent;
- Previous && Previous->isNot(tok::comma);
- Previous = Previous->Parent) {
+ for (FormatToken *Previous = Current.Previous;
+ Previous && !Previous->isOneOf(tok::comma, tok::semi);
+ Previous = Previous->Previous) {
if (Previous->is(tok::r_square))
Previous = Previous->MatchingParen;
if (Previous->Type == TT_BinaryOperator &&
@@ -585,69 +605,93 @@ private:
}
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw) ||
(Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
- (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
+ !Line.InPPDirective &&
+ (!Current.Previous ||
+ !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) {
Contexts.back().IsExpression = true;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
- for (AnnotatedToken *Previous = Current.Parent;
+ for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
- Previous = Previous->Parent)
+ Previous = Previous->Previous)
Previous->Type = TT_PointerOrReference;
- } else if (Current.Parent &&
- Current.Parent->Type == TT_CtorInitializerColon) {
+ } else if (Current.Previous &&
+ Current.Previous->Type == TT_CtorInitializerColon) {
Contexts.back().IsExpression = true;
+ Contexts.back().InCtorInitializer = true;
} else if (Current.is(tok::kw_new)) {
Contexts.back().CanBeExpression = false;
- } else if (Current.is(tok::semi)) {
+ } else if (Current.is(tok::semi) || Current.is(tok::exclaim)) {
// This should be the condition or increment in a for-loop.
Contexts.back().IsExpression = true;
}
if (Current.Type == TT_Unknown) {
- if (Current.Parent && Current.is(tok::identifier) &&
- ((Current.Parent->is(tok::identifier) &&
- Current.Parent->FormatTok.Tok.getIdentifierInfo()
- ->getPPKeywordID() == tok::pp_not_keyword) ||
- isSimpleTypeSpecifier(*Current.Parent) ||
- Current.Parent->Type == TT_PointerOrReference ||
- Current.Parent->Type == TT_TemplateCloser)) {
+ // Line.MightBeFunctionDecl can only be true after the parentheses of a
+ // function declaration have been found. In this case, 'Current' is a
+ // trailing token of this declaration and thus cannot be a name.
+ if (isStartOfName(Current) && !Line.MightBeFunctionDecl) {
Contexts.back().FirstStartOfName = &Current;
Current.Type = TT_StartOfName;
- NameFound = true;
+ } else if (Current.is(tok::kw_auto)) {
+ AutoFound = true;
+ } else if (Current.is(tok::arrow) && AutoFound &&
+ Line.MustBeDeclaration) {
+ Current.Type = TT_TrailingReturnArrow;
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
Current.Type =
- determineStarAmpUsage(Current, Contexts.back().IsExpression);
+ determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
+ Contexts.back().IsExpression);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
Current.Type = determineIncrementUsage(Current);
} else if (Current.is(tok::exclaim)) {
Current.Type = TT_UnaryOperator;
- } else if (Current.isBinaryOperator()) {
+ } else if (Current.isBinaryOperator() &&
+ (!Current.Previous ||
+ Current.Previous->isNot(tok::l_square))) {
Current.Type = TT_BinaryOperator;
} else if (Current.is(tok::comment)) {
- std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
- Lex.getLangOpts()));
- if (StringRef(Data).startswith("//"))
+ if (Current.TokenText.startswith("//"))
Current.Type = TT_LineComment;
else
Current.Type = TT_BlockComment;
} else if (Current.is(tok::r_paren)) {
- bool ParensNotExpr = !Current.Parent ||
- Current.Parent->Type == TT_PointerOrReference ||
- Current.Parent->Type == TT_TemplateCloser;
+ FormatToken *LeftOfParens = NULL;
+ if (Current.MatchingParen)
+ LeftOfParens = Current.MatchingParen->getPreviousNonComment();
+ bool IsCast = false;
+ bool ParensAreEmpty = Current.Previous == Current.MatchingParen;
+ bool ParensAreType = !Current.Previous ||
+ Current.Previous->Type == TT_PointerOrReference ||
+ Current.Previous->Type == TT_TemplateCloser ||
+ isSimpleTypeSpecifier(*Current.Previous);
bool ParensCouldEndDecl =
- !Current.Children.empty() &&
- Current.Children[0].isOneOf(tok::equal, tok::semi, tok::l_brace);
+ Current.Next &&
+ Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
bool IsSizeOfOrAlignOf =
- Current.MatchingParen && Current.MatchingParen->Parent &&
- Current.MatchingParen->Parent->isOneOf(tok::kw_sizeof,
- tok::kw_alignof);
- if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
- Contexts.back().IsExpression)
- // FIXME: We need to get smarter and understand more cases of casts.
+ LeftOfParens &&
+ LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
+ if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
+ (Contexts.back().IsExpression ||
+ (Current.Next && Current.Next->isBinaryOperator())))
+ IsCast = true;
+ if (Current.Next && Current.Next->isNot(tok::string_literal) &&
+ (Current.Next->Tok.isLiteral() ||
+ Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
+ IsCast = true;
+ // If there is an identifier after the (), it is likely a cast, unless
+ // there is also an identifier before the ().
+ if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL ||
+ LeftOfParens->is(tok::kw_return)) &&
+ LeftOfParens->Type != TT_OverloadedOperator &&
+ LeftOfParens->Type != TT_TemplateCloser && Current.Next &&
+ Current.Next->is(tok::identifier))
+ IsCast = true;
+ if (IsCast && !ParensAreEmpty)
Current.Type = TT_CastRParen;
- } else if (Current.is(tok::at) && Current.Children.size()) {
- switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
+ } else if (Current.is(tok::at) && Current.Next) {
+ switch (Current.Next->Tok.getObjCKeywordID()) {
case tok::objc_interface:
case tok::objc_implementation:
case tok::objc_protocol:
@@ -659,27 +703,63 @@ private:
default:
break;
}
+ } else if (Current.is(tok::period)) {
+ FormatToken *PreviousNoComment = Current.getPreviousNonComment();
+ if (PreviousNoComment &&
+ PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
+ Current.Type = TT_DesignatedInitializerPeriod;
}
}
}
+ /// \brief Take a guess at whether \p Tok starts a name of a function or
+ /// variable declaration.
+ ///
+ /// This is a heuristic based on whether \p Tok is an identifier following
+ /// something that is likely a type.
+ bool isStartOfName(const FormatToken &Tok) {
+ if (Tok.isNot(tok::identifier) || Tok.Previous == NULL)
+ return false;
+
+ // Skip "const" as it does not have an influence on whether this is a name.
+ FormatToken *PreviousNotConst = Tok.Previous;
+ while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const))
+ PreviousNotConst = PreviousNotConst->Previous;
+
+ if (PreviousNotConst == NULL)
+ return false;
+
+ bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
+ PreviousNotConst->Previous &&
+ PreviousNotConst->Previous->is(tok::hash);
+
+ if (PreviousNotConst->Type == TT_TemplateCloser)
+ return PreviousNotConst && PreviousNotConst->MatchingParen &&
+ PreviousNotConst->MatchingParen->Previous &&
+ PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template);
+
+ return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
+ PreviousNotConst->Type == TT_PointerOrReference ||
+ isSimpleTypeSpecifier(*PreviousNotConst);
+ }
+
/// \brief Return the type of the given token assuming it is * or &.
- TokenType
- determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
- const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment();
+ TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) {
+ const FormatToken *PrevToken = Tok.getPreviousNonComment();
if (PrevToken == NULL)
return TT_UnaryOperator;
- const AnnotatedToken *NextToken = Tok.getNextNoneComment();
+ const FormatToken *NextToken = Tok.getNextNonComment();
if (NextToken == NULL)
return TT_Unknown;
- if (PrevToken->is(tok::l_paren) && !IsExpression)
+ if (PrevToken->is(tok::coloncolon) ||
+ (PrevToken->is(tok::l_paren) && !IsExpression))
return TT_PointerOrReference;
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
tok::comma, tok::semi, tok::kw_return, tok::colon,
- tok::equal) ||
+ tok::equal, tok::kw_delete, tok::kw_sizeof) ||
PrevToken->Type == TT_BinaryOperator ||
PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
@@ -687,9 +767,14 @@ private:
if (NextToken->is(tok::l_square))
return TT_PointerOrReference;
- if (PrevToken->FormatTok.Tok.isLiteral() ||
+ if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
+ PrevToken->MatchingParen->Previous &&
+ PrevToken->MatchingParen->Previous->is(tok::kw_typeof))
+ return TT_PointerOrReference;
+
+ if (PrevToken->Tok.isLiteral() ||
PrevToken->isOneOf(tok::r_paren, tok::r_square) ||
- NextToken->FormatTok.Tok.isLiteral() || NextToken->isUnaryOperator())
+ NextToken->Tok.isLiteral() || NextToken->isUnaryOperator())
return TT_BinaryOperator;
// It is very unlikely that we are going to find a pointer or reference type
@@ -700,9 +785,9 @@ private:
return TT_PointerOrReference;
}
- TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
- const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment();
- if (PrevToken == NULL)
+ TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
+ const FormatToken *PrevToken = Tok.getPreviousNonComment();
+ if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@@ -720,9 +805,9 @@ private:
}
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
- TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
- const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment();
- if (PrevToken == NULL)
+ TokenType determineIncrementUsage(const FormatToken &Tok) {
+ const FormatToken *PrevToken = Tok.getPreviousNonComment();
+ if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@@ -733,8 +818,8 @@ private:
// FIXME: This is copy&pasted from Sema. Put it in a common place and remove
// duplication.
/// \brief Determine whether the token kind starts a simple-type-specifier.
- bool isSimpleTypeSpecifier(const AnnotatedToken &Tok) const {
- switch (Tok.FormatTok.Tok.getKind()) {
+ bool isSimpleTypeSpecifier(const FormatToken &Tok) const {
+ switch (Tok.Tok.getKind()) {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
@@ -750,71 +835,90 @@ private:
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw___underlying_type:
- return true;
case tok::annot_typename:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::kw_decltype:
- return Lex.getLangOpts().CPlusPlus;
+ return true;
default:
- break;
+ return false;
}
- return false;
}
SmallVector<Context, 8> Contexts;
- SourceManager &SourceMgr;
- Lexer &Lex;
+ const FormatStyle &Style;
AnnotatedLine &Line;
- AnnotatedToken *CurrentToken;
+ FormatToken *CurrentToken;
bool KeywordVirtualFound;
- bool NameFound;
+ bool AutoFound;
IdentifierInfo &Ident_in;
};
+static int PrecedenceUnaryOperator = prec::PointerToMember + 1;
+static int PrecedenceArrowAndPeriod = prec::PointerToMember + 2;
+
/// \brief Parses binary expressions by inserting fake parenthesis based on
/// operator precedence.
class ExpressionParser {
public:
- ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
+ ExpressionParser(AnnotatedLine &Line) : Current(Line.First) {
+ // Skip leading "}", e.g. in "} else if (...) {".
+ if (Current->is(tok::r_brace))
+ next();
+ }
/// \brief Parse expressions with the given operatore precedence.
void parse(int Precedence = 0) {
- if (Precedence > prec::PointerToMember || Current == NULL)
+ // Skip 'return' and ObjC selector colons as they are not part of a binary
+ // expression.
+ while (Current &&
+ (Current->is(tok::kw_return) ||
+ (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr)))
+ next();
+
+ if (Current == NULL || Precedence > PrecedenceArrowAndPeriod)
return;
- // Eagerly consume trailing comments.
- while (Current && Current->isTrailingComment()) {
- next();
+ // Conditional expressions need to be parsed separately for proper nesting.
+ if (Precedence == prec::Conditional) {
+ parseConditionalExpr();
+ return;
}
- AnnotatedToken *Start = Current;
- bool OperatorFound = false;
+ // Parse unary operators, which all have a higher precedence than binary
+ // operators.
+ if (Precedence == PrecedenceUnaryOperator) {
+ parseUnaryOperator();
+ return;
+ }
+
+ FormatToken *Start = Current;
+ FormatToken *LatestOperator = NULL;
while (Current) {
// Consume operators with higher precedence.
parse(Precedence + 1);
- int CurrentPrecedence = 0;
- if (Current) {
- if (Current->Type == TT_ConditionalExpr)
- CurrentPrecedence = 1 + (int) prec::Conditional;
- else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon)
- CurrentPrecedence = 1;
- else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
- CurrentPrecedence = 1 + (int) getPrecedence(*Current);
- }
+ int CurrentPrecedence = getCurrentPrecedence();
+
+ if (Current && Current->Type == TT_ObjCSelectorName &&
+ Precedence == CurrentPrecedence)
+ Start = Current;
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
if (Current == NULL || Current->closesScope() ||
- (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) {
- if (OperatorFound) {
- Start->FakeLParens.push_back(prec::Level(Precedence - 1));
- if (Current)
- ++Current->Parent->FakeRParens;
+ (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) {
+ if (LatestOperator) {
+ if (Precedence == PrecedenceArrowAndPeriod) {
+ LatestOperator->LastInChainOfCalls = true;
+ // Call expressions don't have a binary operator precedence.
+ addFakeParenthesis(Start, prec::Unknown);
+ } else {
+ addFakeParenthesis(Start, prec::Level(Precedence));
+ }
}
return;
}
@@ -829,7 +933,7 @@ public:
} else {
// Operator found.
if (CurrentPrecedence == Precedence)
- OperatorFound = true;
+ LatestOperator = Current;
next();
}
@@ -837,16 +941,99 @@ public:
}
private:
+ /// \brief Gets the precedence (+1) of the given token for binary operators
+ /// and other tokens that we treat like binary operators.
+ int getCurrentPrecedence() {
+ if (Current) {
+ if (Current->Type == TT_ConditionalExpr)
+ return prec::Conditional;
+ else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
+ Current->Type == TT_ObjCSelectorName)
+ return 0;
+ else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
+ return Current->getPrecedence();
+ else if (Current->isOneOf(tok::period, tok::arrow))
+ return PrecedenceArrowAndPeriod;
+ }
+ return -1;
+ }
+
+ void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) {
+ Start->FakeLParens.push_back(Precedence);
+ if (Precedence > prec::Unknown)
+ Start->StartsBinaryExpression = true;
+ if (Current) {
+ ++Current->Previous->FakeRParens;
+ if (Precedence > prec::Unknown)
+ Current->Previous->EndsBinaryExpression = true;
+ }
+ }
+
+ /// \brief Parse unary operator expressions and surround them with fake
+ /// parentheses if appropriate.
+ void parseUnaryOperator() {
+ if (Current == NULL || Current->Type != TT_UnaryOperator) {
+ parse(PrecedenceArrowAndPeriod);
+ return;
+ }
+
+ FormatToken *Start = Current;
+ next();
+ parseUnaryOperator();
+
+ // The actual precedence doesn't matter.
+ addFakeParenthesis(Start, prec::Unknown);
+ }
+
+ void parseConditionalExpr() {
+ FormatToken *Start = Current;
+ parse(prec::LogicalOr);
+ if (!Current || !Current->is(tok::question))
+ return;
+ next();
+ parse(prec::LogicalOr);
+ if (!Current || Current->Type != TT_ConditionalExpr)
+ return;
+ next();
+ parseConditionalExpr();
+ addFakeParenthesis(Start, prec::Conditional);
+ }
+
void next() {
- if (Current != NULL)
- Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ if (Current)
+ Current = Current->Next;
+ while (Current && Current->isTrailingComment())
+ Current = Current->Next;
}
- AnnotatedToken *Current;
+ FormatToken *Current;
};
+} // end anonymous namespace
+
+void
+TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) {
+ const AnnotatedLine *NextNonCommentLine = NULL;
+ for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
+ E = Lines.rend();
+ I != E; ++I) {
+ if (NextNonCommentLine && (*I)->First->is(tok::comment) &&
+ (*I)->First->Next == NULL)
+ (*I)->Level = NextNonCommentLine->Level;
+ else
+ NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL;
+
+ setCommentLineLevels((*I)->Children);
+ }
+}
+
void TokenAnnotator::annotate(AnnotatedLine &Line) {
- AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
+ for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
+ E = Line.Children.end();
+ I != E; ++I) {
+ annotate(**I);
+ }
+ AnnotatingParser Parser(Style, Line, Ident_in);
Line.Type = Parser.parseLine();
if (Line.Type == LT_Invalid)
return;
@@ -854,84 +1041,114 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
ExpressionParser ExprParser(Line);
ExprParser.parse();
- if (Line.First.Type == TT_ObjCMethodSpecifier)
+ if (Line.First->Type == TT_ObjCMethodSpecifier)
Line.Type = LT_ObjCMethodDecl;
- else if (Line.First.Type == TT_ObjCDecl)
+ else if (Line.First->Type == TT_ObjCDecl)
Line.Type = LT_ObjCDecl;
- else if (Line.First.Type == TT_ObjCProperty)
+ else if (Line.First->Type == TT_ObjCProperty)
Line.Type = LT_ObjCProperty;
- Line.First.SpacesRequiredBefore = 1;
- Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
- Line.First.CanBreakBefore = Line.First.MustBreakBefore;
-
- Line.First.TotalLength = Line.First.FormatTok.TokenLength;
+ Line.First->SpacesRequiredBefore = 1;
+ Line.First->CanBreakBefore = Line.First->MustBreakBefore;
}
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
- if (Line.First.Children.empty())
+ Line.First->TotalLength =
+ Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
+ if (!Line.First->Next)
return;
- AnnotatedToken *Current = &Line.First.Children[0];
+ FormatToken *Current = Line.First->Next;
+ bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current != NULL) {
if (Current->Type == TT_LineComment)
Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
- else
- Current->SpacesRequiredBefore =
- spaceRequiredBefore(Line, *Current) ? 1 : 0;
-
- if (Current->FormatTok.MustBreakBefore) {
- Current->MustBreakBefore = true;
- } else if (Current->Type == TT_LineComment) {
- Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
- } else if (Current->Parent->isTrailingComment() ||
- (Current->is(tok::string_literal) &&
- Current->Parent->is(tok::string_literal))) {
- Current->MustBreakBefore = true;
- } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
- Current->Parent->is(tok::string_literal) &&
- Current->Children[0].is(tok::string_literal)) {
- Current->MustBreakBefore = true;
- } else {
- Current->MustBreakBefore = false;
- }
+ else if (Current->SpacesRequiredBefore == 0 &&
+ spaceRequiredBefore(Line, *Current))
+ Current->SpacesRequiredBefore = 1;
+
+ Current->MustBreakBefore =
+ Current->MustBreakBefore || mustBreakBefore(Line, *Current);
+
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
- if (Current->MustBreakBefore)
- Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
+ if (Current->MustBreakBefore || !Current->Children.empty() ||
+ Current->IsMultiline)
+ Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit;
else
- Current->TotalLength =
- Current->Parent->TotalLength + Current->FormatTok.TokenLength +
- Current->SpacesRequiredBefore;
+ Current->TotalLength = Current->Previous->TotalLength +
+ Current->ColumnWidth +
+ Current->SpacesRequiredBefore;
+
+ if (Current->Type == TT_CtorInitializerColon)
+ InFunctionDecl = false;
+
// FIXME: Only calculate this if CanBreakBefore is true once static
// initializers etc. are sorted out.
// FIXME: Move magic numbers to a better place.
- Current->SplitPenalty =
- 20 * Current->BindingStrength + splitPenalty(Line, *Current);
+ Current->SplitPenalty = 20 * Current->BindingStrength +
+ splitPenalty(Line, *Current, InFunctionDecl);
- Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ Current = Current->Next;
}
- DEBUG({
- printDebugInfo(Line);
- });
+ calculateUnbreakableTailLengths(Line);
+ for (Current = Line.First; Current != NULL; Current = Current->Next) {
+ if (Current->Role)
+ Current->Role->precomputeFormattingInfos(Current);
+ }
+
+ DEBUG({ printDebugInfo(Line); });
+
+ for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
+ E = Line.Children.end();
+ I != E; ++I) {
+ calculateFormattingInformation(**I);
+ }
+}
+
+void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) {
+ unsigned UnbreakableTailLength = 0;
+ FormatToken *Current = Line.Last;
+ while (Current != NULL) {
+ Current->UnbreakableTailLength = UnbreakableTailLength;
+ if (Current->CanBreakBefore ||
+ Current->isOneOf(tok::comment, tok::string_literal)) {
+ UnbreakableTailLength = 0;
+ } else {
+ UnbreakableTailLength +=
+ Current->ColumnWidth + Current->SpacesRequiredBefore;
+ }
+ Current = Current->Previous;
+ }
}
unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
- const AnnotatedToken &Tok) {
- const AnnotatedToken &Left = *Tok.Parent;
- const AnnotatedToken &Right = Tok;
+ const FormatToken &Tok,
+ bool InFunctionDecl) {
+ const FormatToken &Left = *Tok.Previous;
+ const FormatToken &Right = Tok;
- if (Right.Type == TT_StartOfName) {
- if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
+ if (Left.is(tok::semi))
+ return 0;
+ if (Left.is(tok::comma))
+ return 1;
+ if (Right.is(tok::l_square))
+ return 150;
+
+ if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) {
+ if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
return 3;
- else if (Line.MightBeFunctionDecl && Right.BindingStrength == 1)
+ if (Left.Type == TT_StartOfName)
+ return 20;
+ if (InFunctionDecl && Right.BindingStrength == 1)
// FIXME: Clean up hack of using BindingStrength to find top-level names.
return Style.PenaltyReturnTypeOnItsOwnLine;
- else
- return 200;
+ return 200;
}
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 150;
+ if (Left.Type == TT_CastRParen)
+ return 100;
if (Left.is(tok::coloncolon))
return 500;
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
@@ -941,50 +1158,53 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Left.Type == TT_InheritanceColon)
return 2;
- if (Right.isOneOf(tok::arrow, tok::period)) {
- if (Line.Type == LT_BuilderTypeCall)
- return prec::PointerToMember;
+ if (Right.isMemberAccess()) {
if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
Left.MatchingParen->ParameterCount > 0)
return 20; // Should be smaller than breaking at a nested comma.
return 150;
}
+ // Breaking before a trailing 'const' or not-function-like annotation is bad.
+ if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty &&
+ (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->isNot(tok::l_paren))))
+ return 100;
+
// In for-loops, prefer breaking at ',' and ';'.
- if (Line.First.is(tok::kw_for) && Left.is(tok::equal))
+ if (Line.First->is(tok::kw_for) && Left.is(tok::equal))
return 4;
- if (Left.is(tok::semi))
- return 0;
- if (Left.is(tok::comma))
- return 1;
-
// In Objective-C method expressions, prefer breaking before "param:" over
// breaking after it.
if (Right.Type == TT_ObjCSelectorName)
return 0;
if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
- return 20;
+ return 50;
- if (Left.is(tok::l_paren) && Line.MightBeFunctionDecl)
+ if (Left.is(tok::l_paren) && InFunctionDecl)
return 100;
if (Left.opensScope())
- return Left.ParameterCount > 1 ? prec::Comma : 20;
+ return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
+ : 19;
if (Right.is(tok::lessless)) {
if (Left.is(tok::string_literal)) {
- StringRef Content = StringRef(Left.FormatTok.Tok.getLiteralData(),
- Left.FormatTok.TokenLength);
- Content = Content.drop_back(1).drop_front(1).trim();
+ StringRef Content = Left.TokenText;
+ if (Content.startswith("\""))
+ Content = Content.drop_front(1);
+ if (Content.endswith("\""))
+ Content = Content.drop_back(1);
+ Content = Content.trim();
if (Content.size() > 1 &&
(Content.back() == ':' || Content.back() == '='))
- return 100;
+ return 25;
}
- return prec::Shift;
+ return 1; // Breaking at a << is really cheap.
}
if (Left.Type == TT_ConditionalExpr)
return prec::Conditional;
- prec::Level Level = getPrecedence(Left);
+ prec::Level Level = Left.getPrecedence();
if (Level != prec::Unknown)
return Level;
@@ -993,13 +1213,23 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
- const AnnotatedToken &Left,
- const AnnotatedToken &Right) {
+ const FormatToken &Left,
+ const FormatToken &Right) {
if (Right.is(tok::hashhash))
return Left.is(tok::hash);
if (Left.isOneOf(tok::hashhash, tok::hash))
return Right.is(tok::hash);
- if (Right.isOneOf(tok::r_paren, tok::semi, tok::comma))
+ if (Left.is(tok::l_paren) && Right.is(tok::r_paren))
+ return Style.SpaceInEmptyParentheses;
+ if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
+ return (Right.Type == TT_CastRParen ||
+ (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen))
+ ? Style.SpacesInCStyleCastParentheses
+ : Style.SpacesInParentheses;
+ if (Style.SpacesInAngles &&
+ ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser)))
+ return true;
+ if (Right.isOneOf(tok::semi, tok::comma))
return false;
if (Right.is(tok::less) &&
(Left.is(tok::kw_template) ||
@@ -1017,186 +1247,282 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::coloncolon))
return false;
if (Right.is(tok::coloncolon))
- return !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren);
+ return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) ||
+ !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren,
+ tok::r_paren, tok::less);
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less))
return false;
+ if (Right.is(tok::ellipsis))
+ return Left.Tok.isLiteral();
+ if (Left.is(tok::l_square) && Right.is(tok::amp))
+ return false;
if (Right.Type == TT_PointerOrReference)
- return Left.FormatTok.Tok.isLiteral() ||
+ return Left.Tok.isLiteral() ||
((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
!Style.PointerBindsToType);
+ if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) &&
+ (Left.Type != TT_PointerOrReference || Style.PointerBindsToType))
+ return true;
if (Left.Type == TT_PointerOrReference)
- return Right.FormatTok.Tok.isLiteral() ||
+ return Right.Tok.isLiteral() || Right.Type == TT_BlockComment ||
((Right.Type != TT_PointerOrReference) &&
Right.isNot(tok::l_paren) && Style.PointerBindsToType &&
- Left.Parent && Left.Parent->isNot(tok::l_paren));
+ Left.Previous &&
+ !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
if (Left.is(tok::l_square))
- return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
+ return Left.Type == TT_ArrayInitializerLSquare &&
+ Right.isNot(tok::r_square);
if (Right.is(tok::r_square))
- return Right.Type == TT_ObjCArrayLiteral;
- if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
- return false;
- if (Left.is(tok::period) || Right.is(tok::period))
+ return Right.MatchingParen &&
+ Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
+ if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
+ Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant))
return false;
if (Left.is(tok::colon))
return Left.Type != TT_ObjCMethodExpr;
if (Right.is(tok::colon))
- return Right.Type != TT_ObjCMethodExpr;
- if (Left.is(tok::l_paren))
- return false;
+ return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question);
if (Right.is(tok::l_paren)) {
+ if (Left.is(tok::r_paren) && Left.MatchingParen &&
+ Left.MatchingParen->Previous &&
+ Left.MatchingParen->Previous->is(tok::kw___attribute))
+ return true;
return Line.Type == LT_ObjCDecl ||
- Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
- tok::kw_return, tok::kw_catch, tok::kw_new,
- tok::kw_delete, tok::semi);
+ Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,
+ tok::semi) ||
+ (Style.SpaceAfterControlStatementKeyword &&
+ Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
+ tok::kw_catch));
}
- if (Left.is(tok::at) &&
- Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
+ if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
+ return !Left.Children.empty(); // No spaces in "{}".
+ if (Left.is(tok::l_brace) || Right.is(tok::r_brace))
+ return !Style.Cpp11BracedListStyle;
+ if (Right.Type == TT_UnaryOperator)
+ return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
+ (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
+ if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) &&
+ Right.is(tok::l_brace) && Right.getNextNonComment() &&
+ Right.BlockKind != BK_Block)
return false;
- if (Right.is(tok::ellipsis))
+ if (Left.is(tok::period) || Right.is(tok::period))
+ return false;
+ if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/"))
+ return false;
+ if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
return false;
return true;
}
bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
- const AnnotatedToken &Tok) {
- if (Tok.FormatTok.Tok.getIdentifierInfo() &&
- Tok.Parent->FormatTok.Tok.getIdentifierInfo())
+ const FormatToken &Tok) {
+ if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
+ if (Tok.Previous->Type == TT_ImplicitStringLiteral)
+ return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd();
if (Line.Type == LT_ObjCMethodDecl) {
- if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
+ if (Tok.Previous->Type == TT_ObjCMethodSpecifier)
return true;
- if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
+ if (Tok.Previous->is(tok::r_paren) && Tok.is(tok::identifier))
// Don't space between ')' and <id>
return false;
}
if (Line.Type == LT_ObjCProperty &&
- (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
+ (Tok.is(tok::equal) || Tok.Previous->is(tok::equal)))
return false;
- if (Tok.Parent->is(tok::comma))
+ if (Tok.Type == TT_TrailingReturnArrow ||
+ Tok.Previous->Type == TT_TrailingReturnArrow)
+ return true;
+ if (Tok.Previous->is(tok::comma))
return true;
if (Tok.is(tok::comma))
return false;
if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
return true;
- if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
- return false;
+ if (Tok.Previous->Tok.is(tok::kw_operator))
+ return Tok.is(tok::coloncolon);
if (Tok.Type == TT_OverloadedOperatorLParen)
return false;
if (Tok.is(tok::colon))
- return !Line.First.isOneOf(tok::kw_case, tok::kw_default) &&
- Tok.getNextNoneComment() != NULL && Tok.Type != TT_ObjCMethodExpr;
- if (Tok.is(tok::l_paren) && !Tok.Children.empty() &&
- Tok.Children[0].Type == TT_PointerOrReference &&
- !Tok.Children[0].Children.empty() &&
- Tok.Children[0].Children[0].isNot(tok::r_paren) &&
- Tok.Parent->isNot(tok::l_paren) &&
- (Tok.Parent->Type != TT_PointerOrReference || Style.PointerBindsToType))
- return true;
- if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
+ return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
+ Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr &&
+ !Tok.Previous->is(tok::question);
+ if (Tok.Previous->Type == TT_UnaryOperator ||
+ Tok.Previous->Type == TT_CastRParen)
return false;
- if (Tok.Type == TT_UnaryOperator)
- return !Tok.Parent->isOneOf(tok::l_paren, tok::l_square, tok::at) &&
- (Tok.Parent->isNot(tok::colon) ||
- Tok.Parent->Type != TT_ObjCMethodExpr);
- if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
+ if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) {
return Tok.Type == TT_TemplateCloser &&
- Tok.Parent->Type == TT_TemplateCloser &&
- Style.Standard != FormatStyle::LS_Cpp11;
+ Tok.Previous->Type == TT_TemplateCloser &&
+ (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
}
if (Tok.isOneOf(tok::arrowstar, tok::periodstar) ||
- Tok.Parent->isOneOf(tok::arrowstar, tok::periodstar))
+ Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar))
+ return false;
+ if (!Style.SpaceBeforeAssignmentOperators &&
+ Tok.getPrecedence() == prec::Assignment)
return false;
- if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
+ if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) ||
+ Tok.Previous->Type == TT_BinaryOperator)
return true;
- if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
+ if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
return false;
- if (Tok.is(tok::less) && Line.First.is(tok::hash))
+ if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) &&
+ Line.First->is(tok::hash))
return true;
if (Tok.Type == TT_TrailingUnaryOperator)
return false;
- return spaceRequiredBetween(Line, *Tok.Parent, Tok);
+ return spaceRequiredBetween(Line, *Tok.Previous, Tok);
+}
+
+bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
+ const FormatToken &Right) {
+ if (Right.is(tok::comment)) {
+ return Right.NewlinesBefore > 0;
+ } else if (Right.Previous->isTrailingComment() ||
+ (Right.is(tok::string_literal) &&
+ Right.Previous->is(tok::string_literal))) {
+ return true;
+ } else if (Right.Previous->IsUnterminatedLiteral) {
+ return true;
+ } else if (Right.is(tok::lessless) && Right.Next &&
+ Right.Previous->is(tok::string_literal) &&
+ Right.Next->is(tok::string_literal)) {
+ return true;
+ } else if (Right.Previous->ClosesTemplateDeclaration &&
+ Right.Previous->MatchingParen &&
+ Right.Previous->MatchingParen->BindingStrength == 1 &&
+ Style.AlwaysBreakTemplateDeclarations) {
+ // FIXME: Fix horrible hack of using BindingStrength to find top-level <>.
+ return true;
+ } else if (Right.Type == TT_CtorInitializerComma &&
+ Style.BreakConstructorInitializersBeforeComma &&
+ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
+ return true;
+ } else if (Right.Previous->BlockKind == BK_Block &&
+ Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) {
+ return true;
+ } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Allman;
+ }
+ return false;
}
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
- const AnnotatedToken &Right) {
- const AnnotatedToken &Left = *Right.Parent;
- if (Right.Type == TT_StartOfName)
+ const FormatToken &Right) {
+ const FormatToken &Left = *Right.Previous;
+ if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator))
return true;
- if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+ if (Right.isTrailingComment())
+ // We rely on MustBreakBefore being set correctly here as we should not
+ // change the "binding" behavior of a comment.
return false;
- if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ if (Left.is(tok::question) && Right.is(tok::colon))
+ return false;
+ if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ return Style.BreakBeforeTernaryOperators;
+ if (Left.Type == TT_ConditionalExpr || Left.is(tok::question))
+ return !Style.BreakBeforeTernaryOperators;
+ if (Right.is(tok::colon) &&
+ (Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr))
+ return false;
+ if (Left.is(tok::colon) &&
+ (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr))
return true;
if (Right.Type == TT_ObjCSelectorName)
return true;
- if (Left.ClosesTemplateDeclaration)
+ if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty)
return true;
- if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ if (Left.ClosesTemplateDeclaration)
return true;
if (Right.Type == TT_RangeBasedForLoopColon ||
- Right.Type == TT_OverloadedOperatorLParen)
+ Right.Type == TT_OverloadedOperatorLParen ||
+ Right.Type == TT_OverloadedOperator)
return false;
if (Left.Type == TT_RangeBasedForLoopColon)
return true;
if (Right.Type == TT_RangeBasedForLoopColon)
return false;
if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
- Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
- Left.isOneOf(tok::question, tok::kw_operator))
+ Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator))
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
- if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Parent &&
- Left.Parent->is(tok::kw___attribute))
+ if (Left.Previous) {
+ if (Left.is(tok::l_paren) && Right.is(tok::l_paren) &&
+ Left.Previous->is(tok::kw___attribute))
+ return false;
+ if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator ||
+ Left.Previous->Type == TT_CastRParen))
+ return false;
+ }
+ if (Right.Type == TT_ImplicitStringLiteral)
return false;
- if (Right.Type == TT_LineComment)
- // We rely on MustBreakBefore being set correctly here as we should not
- // change the "binding" behavior of a comment.
+ if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser)
return false;
+ // We only break before r_brace if there was a corresponding break before
+ // the l_brace, which is tracked by BreakBeforeClosingBrace.
+ if (Right.is(tok::r_brace))
+ return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block;
+
// Allow breaking after a trailing 'const', e.g. after a method declaration,
// unless it is follow by ';', '{' or '='.
- if (Left.is(tok::kw_const) && Left.Parent != NULL &&
- Left.Parent->is(tok::r_paren))
+ if (Left.is(tok::kw_const) && Left.Previous != NULL &&
+ Left.Previous->is(tok::r_paren))
return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
if (Right.is(tok::kw___attribute))
return true;
- // We only break before r_brace if there was a corresponding break before
- // the l_brace, which is tracked by BreakBeforeClosingBrace.
- if (Right.isOneOf(tok::r_brace, tok::r_paren, tok::greater))
- return false;
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
- return (Left.isBinaryOperator() && Left.isNot(tok::lessless)) ||
+
+ if (Left.Type == TT_CtorInitializerComma &&
+ Style.BreakConstructorInitializersBeforeComma)
+ return false;
+ if (Right.Type == TT_CtorInitializerComma &&
+ Style.BreakConstructorInitializersBeforeComma)
+ return true;
+ if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators)
+ return true;
+ if (Left.is(tok::greater) && Right.is(tok::greater) &&
+ Left.Type != TT_TemplateCloser)
+ return false;
+ if (Left.Type == TT_ArrayInitializerLSquare)
+ return true;
+ return (Left.isBinaryOperator() && Left.isNot(tok::lessless) &&
+ !Style.BreakBeforeBinaryOperators) ||
Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct) ||
- Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) ||
- (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
- Right.isOneOf(tok::identifier, tok::kw___attribute)) ||
- (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
- (Left.is(tok::l_square) && !Right.is(tok::r_square));
+ Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon,
+ tok::l_square, tok::at) ||
+ (Left.is(tok::r_paren) &&
+ Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) ||
+ (Left.is(tok::l_paren) && !Right.is(tok::r_paren));
}
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
llvm::errs() << "AnnotatedTokens:\n";
- const AnnotatedToken *Tok = &Line.First;
+ const FormatToken *Tok = Line.First;
while (Tok) {
llvm::errs() << " M=" << Tok->MustBreakBefore
<< " C=" << Tok->CanBreakBefore << " T=" << Tok->Type
<< " S=" << Tok->SpacesRequiredBefore
- << " P=" << Tok->SplitPenalty
- << " Name=" << Tok->FormatTok.Tok.getName() << " FakeLParens=";
+ << " 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 << "\n";
- Tok = Tok->Children.empty() ? NULL : &Tok->Children[0];
+ if (Tok->Next == NULL)
+ assert(Tok == Line.Last);
+ Tok = Tok->Next;
}
llvm::errs() << "----\n";
}
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index b364082391f8..aa49b2a5c078 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -17,50 +17,17 @@
#define LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
#include "UnwrappedLineParser.h"
-#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include <string>
namespace clang {
-class Lexer;
class SourceManager;
namespace format {
-enum TokenType {
- TT_BinaryOperator,
- TT_BlockComment,
- TT_CastRParen,
- TT_ConditionalExpr,
- TT_CtorInitializerColon,
- TT_ImplicitStringLiteral,
- TT_InlineASMColon,
- TT_InheritanceColon,
- TT_LineComment,
- TT_ObjCArrayLiteral,
- TT_ObjCBlockLParen,
- TT_ObjCDecl,
- TT_ObjCForIn,
- TT_ObjCMethodExpr,
- TT_ObjCMethodSpecifier,
- TT_ObjCProperty,
- TT_ObjCSelectorName,
- TT_OverloadedOperatorLParen,
- TT_PointerOrReference,
- TT_PureVirtualSpecifier,
- TT_RangeBasedForLoopColon,
- TT_StartOfName,
- TT_TemplateCloser,
- TT_TemplateOpener,
- TT_TrailingUnaryOperator,
- TT_UnaryOperator,
- TT_Unknown
-};
-
enum LineType {
LT_Invalid,
LT_Other,
- LT_BuilderTypeCall,
LT_PreprocessorDirective,
LT_VirtualFunctionDecl,
LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
@@ -68,175 +35,50 @@ enum LineType {
LT_ObjCProperty // An @property line.
};
-class AnnotatedToken {
-public:
- explicit AnnotatedToken(const FormatToken &FormatTok)
- : FormatTok(FormatTok), Type(TT_Unknown), SpacesRequiredBefore(0),
- CanBreakBefore(false), MustBreakBefore(false),
- ClosesTemplateDeclaration(false), MatchingParen(NULL),
- ParameterCount(0), BindingStrength(0), SplitPenalty(0),
- LongestObjCSelectorName(0), Parent(NULL),
- FakeRParens(0), LastInChainOfCalls(false),
- PartOfMultiVariableDeclStmt(false), NoMoreTokensOnLevel(false) {}
-
- bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); }
-
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
- return is(K1) || is(K2);
- }
-
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
- return is(K1) || is(K2) || is(K3);
- }
-
- bool isOneOf(
- tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
- tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
- tok::TokenKind K6 = tok::NUM_TOKENS, tok::TokenKind K7 = tok::NUM_TOKENS,
- tok::TokenKind K8 = tok::NUM_TOKENS, tok::TokenKind K9 = tok::NUM_TOKENS,
- tok::TokenKind K10 = tok::NUM_TOKENS,
- tok::TokenKind K11 = tok::NUM_TOKENS,
- tok::TokenKind K12 = tok::NUM_TOKENS) const {
- return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
- is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
- }
-
- bool isNot(tok::TokenKind Kind) const { return FormatTok.Tok.isNot(Kind); }
-
- bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
- return FormatTok.Tok.isObjCAtKeyword(Kind);
- }
-
- bool isAccessSpecifier(bool ColonRequired = true) const {
- return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
- (!ColonRequired ||
- (!Children.empty() && Children[0].is(tok::colon)));
- }
-
- bool isObjCAccessSpecifier() const {
- return is(tok::at) && !Children.empty() &&
- (Children[0].isObjCAtKeyword(tok::objc_public) ||
- Children[0].isObjCAtKeyword(tok::objc_protected) ||
- Children[0].isObjCAtKeyword(tok::objc_package) ||
- Children[0].isObjCAtKeyword(tok::objc_private));
- }
-
- /// \brief Returns whether \p Tok is ([{ or a template opening <.
- bool opensScope() const;
- /// \brief Returns whether \p Tok is )]} or a template opening >.
- bool closesScope() const;
-
- bool isUnaryOperator() const;
- bool isBinaryOperator() const;
- bool isTrailingComment() const;
-
- FormatToken FormatTok;
-
- TokenType Type;
-
- unsigned SpacesRequiredBefore;
- bool CanBreakBefore;
- bool MustBreakBefore;
-
- bool ClosesTemplateDeclaration;
-
- AnnotatedToken *MatchingParen;
-
- /// \brief Number of parameters, if this is "(", "[" or "<".
- ///
- /// This is initialized to 1 as we don't need to distinguish functions with
- /// 0 parameters from functions with 1 parameter. Thus, we can simply count
- /// the number of commas.
- unsigned ParameterCount;
-
- /// \brief The total length of the line up to and including this token.
- unsigned TotalLength;
-
- // FIXME: Come up with a 'cleaner' concept.
- /// \brief The binding strength of a token. This is a combined value of
- /// operator precedence, parenthesis nesting, etc.
- unsigned BindingStrength;
-
- /// \brief Penalty for inserting a line break before this token.
- unsigned SplitPenalty;
-
- /// \brief If this is the first ObjC selector name in an ObjC method
- /// definition or call, this contains the length of the longest name.
- unsigned LongestObjCSelectorName;
-
- std::vector<AnnotatedToken> Children;
- AnnotatedToken *Parent;
-
- /// \brief Stores the number of required fake parentheses and the
- /// corresponding operator precedence.
- ///
- /// If multiple fake parentheses start at a token, this vector stores them in
- /// reverse order, i.e. inner fake parenthesis first.
- SmallVector<prec::Level, 4> FakeLParens;
- /// \brief Insert this many fake ) after this token for correct indentation.
- unsigned FakeRParens;
-
- /// \brief Is this the last "." or "->" in a builder-type call?
- bool LastInChainOfCalls;
-
- /// \brief Is this token part of a \c DeclStmt defining multiple variables?
- ///
- /// Only set if \c Type == \c TT_StartOfName.
- bool PartOfMultiVariableDeclStmt;
-
- /// \brief Set to \c true for "("-tokens if this is the last token other than
- /// ")" in the next higher parenthesis level.
- ///
- /// If this is \c true, no more formatting decisions have to be made on the
- /// next higher parenthesis level, enabling optimizations.
- ///
- /// Example:
- /// \code
- /// aaaaaa(aaaaaa());
- /// ^ // Set to true for this parenthesis.
- /// \endcode
- bool NoMoreTokensOnLevel;
-
- /// \brief Returns the previous token ignoring comments.
- AnnotatedToken *getPreviousNoneComment() const;
-
- /// \brief Returns the next token ignoring comments.
- const AnnotatedToken *getNextNoneComment() const;
-};
-
class AnnotatedLine {
public:
AnnotatedLine(const UnwrappedLine &Line)
- : First(Line.Tokens.front()), Level(Line.Level),
+ : First(Line.Tokens.front().Tok), Level(Line.Level),
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
StartsDefinition(false) {
assert(!Line.Tokens.empty());
- AnnotatedToken *Current = &First;
- for (std::list<FormatToken>::const_iterator I = ++Line.Tokens.begin(),
- E = Line.Tokens.end();
+
+ // Calculate Next and Previous for all tokens. Note that we must overwrite
+ // Next and Previous for every token, as previous formatting runs might have
+ // left them in a different state.
+ First->Previous = NULL;
+ FormatToken *Current = First;
+ for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(),
+ E = Line.Tokens.end();
I != E; ++I) {
- Current->Children.push_back(AnnotatedToken(*I));
- Current->Children[0].Parent = Current;
- Current = &Current->Children[0];
+ const UnwrappedLineNode &Node = *I;
+ Current->Next = I->Tok;
+ I->Tok->Previous = Current;
+ Current = Current->Next;
+ Current->Children.clear();
+ for (SmallVectorImpl<UnwrappedLine>::const_iterator
+ I = Node.Children.begin(),
+ E = Node.Children.end();
+ I != E; ++I) {
+ Children.push_back(new AnnotatedLine(*I));
+ Current->Children.push_back(Children.back());
+ }
}
Last = Current;
+ Last->Next = NULL;
}
- AnnotatedLine(const AnnotatedLine &Other)
- : First(Other.First), Type(Other.Type), Level(Other.Level),
- InPPDirective(Other.InPPDirective),
- MustBeDeclaration(Other.MustBeDeclaration),
- MightBeFunctionDecl(Other.MightBeFunctionDecl),
- StartsDefinition(Other.StartsDefinition) {
- Last = &First;
- while (!Last->Children.empty()) {
- Last->Children[0].Parent = Last;
- Last = &Last->Children[0];
+
+ ~AnnotatedLine() {
+ for (unsigned i = 0, e = Children.size(); i != e; ++i) {
+ delete Children[i];
}
}
- AnnotatedToken First;
- AnnotatedToken *Last;
+ FormatToken *First;
+ FormatToken *Last;
+
+ SmallVector<AnnotatedLine *, 0> Children;
LineType Type;
unsigned Level;
@@ -244,42 +86,47 @@ public:
bool MustBeDeclaration;
bool MightBeFunctionDecl;
bool StartsDefinition;
-};
-inline prec::Level getPrecedence(const AnnotatedToken &Tok) {
- return getBinOpPrecedence(Tok.FormatTok.Tok.getKind(), true, true);
-}
+private:
+ // Disallow copying.
+ AnnotatedLine(const AnnotatedLine &) LLVM_DELETED_FUNCTION;
+ void operator=(const AnnotatedLine &) LLVM_DELETED_FUNCTION;
+};
/// \brief Determines extra information about the tokens comprising an
/// \c UnwrappedLine.
class TokenAnnotator {
public:
- TokenAnnotator(const FormatStyle &Style, SourceManager &SourceMgr, Lexer &Lex,
- IdentifierInfo &Ident_in)
- : Style(Style), SourceMgr(SourceMgr), Lex(Lex), Ident_in(Ident_in) {
- }
+ TokenAnnotator(const FormatStyle &Style, IdentifierInfo &Ident_in)
+ : Style(Style), Ident_in(Ident_in) {}
+
+ /// \brief Adapts the indent levels of comment lines to the indent of the
+ /// subsequent line.
+ // FIXME: Can/should this be done in the UnwrappedLineParser?
+ void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines);
void annotate(AnnotatedLine &Line);
void calculateFormattingInformation(AnnotatedLine &Line);
private:
/// \brief Calculate the penalty for splitting before \c Tok.
- unsigned splitPenalty(const AnnotatedLine &Line, const AnnotatedToken &Tok);
+ unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
+ bool InFunctionDecl);
+
+ bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
+ const FormatToken &Right);
- bool spaceRequiredBetween(const AnnotatedLine &Line,
- const AnnotatedToken &Left,
- const AnnotatedToken &Right);
+ bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Tok);
- bool spaceRequiredBefore(const AnnotatedLine &Line,
- const AnnotatedToken &Tok);
+ bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
- bool canBreakBefore(const AnnotatedLine &Line, const AnnotatedToken &Right);
+ bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
void printDebugInfo(const AnnotatedLine &Line);
+ void calculateUnbreakableTailLengths(AnnotatedLine &Line);
+
const FormatStyle &Style;
- SourceManager &SourceMgr;
- Lexer &Lex;
// Contextual keywords:
IdentifierInfo &Ident_in;
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 722af5d2b763..e0b090f6abc9 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -16,12 +16,22 @@
#define DEBUG_TYPE "format-parser"
#include "UnwrappedLineParser.h"
-#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Debug.h"
namespace clang {
namespace format {
+class FormatTokenSource {
+public:
+ virtual ~FormatTokenSource() {}
+ virtual FormatToken *getNextToken() = 0;
+
+ virtual unsigned getPosition() = 0;
+ virtual FormatToken *setPosition(unsigned Position) = 0;
+};
+
+namespace {
+
class ScopedDeclarationState {
public:
ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack,
@@ -37,6 +47,7 @@ public:
else
Line.MustBeDeclaration = true;
}
+
private:
UnwrappedLine &Line;
std::vector<bool> &Stack;
@@ -45,11 +56,11 @@ private:
class ScopedMacroState : public FormatTokenSource {
public:
ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
- FormatToken &ResetToken, bool &StructuralError)
+ FormatToken *&ResetToken, bool &StructuralError)
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
StructuralError(StructuralError),
- PreviousStructuralError(StructuralError) {
+ PreviousStructuralError(StructuralError), Token(NULL) {
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
@@ -63,44 +74,60 @@ public:
StructuralError = PreviousStructuralError;
}
- virtual FormatToken getNextToken() {
+ virtual FormatToken *getNextToken() {
// The \c UnwrappedLineParser guards against this by never calling
// \c getNextToken() after it has encountered the first eof token.
assert(!eof());
Token = PreviousTokenSource->getNextToken();
if (eof())
- return createEOF();
+ return getFakeEOF();
return Token;
}
-private:
- bool eof() { return Token.HasUnescapedNewline; }
+ virtual unsigned getPosition() { return PreviousTokenSource->getPosition(); }
- FormatToken createEOF() {
- FormatToken FormatTok;
- FormatTok.Tok.startToken();
- FormatTok.Tok.setKind(tok::eof);
- return FormatTok;
+ virtual FormatToken *setPosition(unsigned Position) {
+ Token = PreviousTokenSource->setPosition(Position);
+ return Token;
+ }
+
+private:
+ bool eof() { return Token && Token->HasUnescapedNewline; }
+
+ FormatToken *getFakeEOF() {
+ static bool EOFInitialized = false;
+ static FormatToken FormatTok;
+ if (!EOFInitialized) {
+ FormatTok.Tok.startToken();
+ FormatTok.Tok.setKind(tok::eof);
+ EOFInitialized = true;
+ }
+ return &FormatTok;
}
UnwrappedLine &Line;
FormatTokenSource *&TokenSource;
- FormatToken &ResetToken;
+ FormatToken *&ResetToken;
unsigned PreviousLineLevel;
FormatTokenSource *PreviousTokenSource;
bool &StructuralError;
bool PreviousStructuralError;
- FormatToken Token;
+ FormatToken *Token;
};
+} // end anonymous namespace
+
class ScopedLineState {
public:
ScopedLineState(UnwrappedLineParser &Parser,
bool SwitchToPreprocessorLines = false)
- : Parser(Parser), SwitchToPreprocessorLines(SwitchToPreprocessorLines) {
+ : Parser(Parser) {
+ OriginalLines = Parser.CurrentLines;
if (SwitchToPreprocessorLines)
Parser.CurrentLines = &Parser.PreprocessorDirectives;
+ else if (!Parser.Line->Tokens.empty())
+ Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
PreBlockLine = Parser.Line.take();
Parser.Line.reset(new UnwrappedLine());
Parser.Line->Level = PreBlockLine->Level;
@@ -113,37 +140,102 @@ public:
}
assert(Parser.Line->Tokens.empty());
Parser.Line.reset(PreBlockLine);
- Parser.MustBreakBeforeNextToken = true;
- if (SwitchToPreprocessorLines)
- Parser.CurrentLines = &Parser.Lines;
+ if (Parser.CurrentLines == &Parser.PreprocessorDirectives)
+ Parser.MustBreakBeforeNextToken = true;
+ Parser.CurrentLines = OriginalLines;
}
private:
UnwrappedLineParser &Parser;
- const bool SwitchToPreprocessorLines;
UnwrappedLine *PreBlockLine;
+ SmallVectorImpl<UnwrappedLine> *OriginalLines;
};
-UnwrappedLineParser::UnwrappedLineParser(
- clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
- FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback)
+namespace {
+
+class IndexedTokenSource : public FormatTokenSource {
+public:
+ IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
+ : Tokens(Tokens), Position(-1) {}
+
+ virtual FormatToken *getNextToken() {
+ ++Position;
+ return Tokens[Position];
+ }
+
+ virtual unsigned getPosition() {
+ assert(Position >= 0);
+ return Position;
+ }
+
+ virtual FormatToken *setPosition(unsigned P) {
+ Position = P;
+ return Tokens[Position];
+ }
+
+ void reset() { Position = -1; }
+
+private:
+ ArrayRef<FormatToken *> Tokens;
+ int Position;
+};
+
+} // end anonymous namespace
+
+UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
+ ArrayRef<FormatToken *> Tokens,
+ UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
- CurrentLines(&Lines), StructuralError(false), Diag(Diag), Style(Style),
- Tokens(&Tokens), Callback(Callback) {}
+ CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(NULL),
+ Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+
+void UnwrappedLineParser::reset() {
+ PPBranchLevel = -1;
+ Line.reset(new UnwrappedLine);
+ CommentsBeforeNextToken.clear();
+ FormatTok = NULL;
+ MustBreakBeforeNextToken = false;
+ PreprocessorDirectives.clear();
+ CurrentLines = &Lines;
+ DeclarationScopeStack.clear();
+ StructuralError = false;
+ PPStack.clear();
+}
bool UnwrappedLineParser::parse() {
- DEBUG(llvm::dbgs() << "----\n");
- readToken();
- parseFile();
- for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), E = Lines.end();
- I != E; ++I) {
- Callback.consumeUnwrappedLine(*I);
- }
+ IndexedTokenSource TokenSource(AllTokens);
+ do {
+ DEBUG(llvm::dbgs() << "----\n");
+ reset();
+ Tokens = &TokenSource;
+ TokenSource.reset();
+
+ readToken();
+ parseFile();
+ // Create line with eof token.
+ pushToken(FormatTok);
+ addUnwrappedLine();
+
+ for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(),
+ E = Lines.end();
+ I != E; ++I) {
+ Callback.consumeUnwrappedLine(*I);
+ }
+ Callback.finishRun();
+ Lines.clear();
+ while (!PPLevelBranchIndex.empty() &&
+ PPLevelBranchIndex.back() + 1 >= PPLevelBranchCount.back()) {
+ PPLevelBranchIndex.resize(PPLevelBranchIndex.size() - 1);
+ PPLevelBranchCount.resize(PPLevelBranchCount.size() - 1);
+ }
+ if (!PPLevelBranchIndex.empty()) {
+ ++PPLevelBranchIndex.back();
+ assert(PPLevelBranchIndex.size() == PPLevelBranchCount.size());
+ assert(PPLevelBranchIndex.back() <= PPLevelBranchCount.back());
+ }
+ } while (!PPLevelBranchIndex.empty());
- // Create line with eof token.
- pushToken(FormatTok);
- Callback.consumeUnwrappedLine(*Line);
return StructuralError;
}
@@ -151,15 +243,16 @@ void UnwrappedLineParser::parseFile() {
ScopedDeclarationState DeclarationState(
*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/ !Line->InPPDirective);
- parseLevel(/*HasOpeningBrace=*/ false);
+ parseLevel(/*HasOpeningBrace=*/false);
// Make sure to format the remaining tokens.
flushComments(true);
addUnwrappedLine();
}
void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
+ bool SwitchLabelEncountered = false;
do {
- switch (FormatTok.Tok.getKind()) {
+ switch (FormatTok->Tok.getKind()) {
case tok::comment:
nextToken();
addUnwrappedLine();
@@ -167,19 +260,24 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
case tok::l_brace:
// FIXME: Add parameter whether this can happen - if this happens, we must
// be in a non-declaration context.
- parseBlock(/*MustBeDeclaration=*/ false);
+ parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
break;
case tok::r_brace:
if (HasOpeningBrace)
return;
- Diag.Report(FormatTok.Tok.getLocation(),
- Diag.getCustomDiagID(clang::DiagnosticsEngine::Error,
- "unexpected '}'"));
StructuralError = true;
nextToken();
addUnwrappedLine();
break;
+ case tok::kw_default:
+ case tok::kw_case:
+ if (!SwitchLabelEncountered &&
+ (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
+ ++Line->Level;
+ SwitchLabelEncountered = true;
+ parseStructuralElement();
+ break;
default:
parseStructuralElement();
break;
@@ -187,41 +285,150 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
} while (!eof());
}
-void UnwrappedLineParser::parseBlock(bool MustBeDeclaration,
- unsigned AddLevels) {
- assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
+void UnwrappedLineParser::calculateBraceTypes() {
+ // We'll parse forward through the tokens until we hit
+ // a closing brace or eof - note that getNextToken() will
+ // parse macros, so this will magically work inside macro
+ // definitions, too.
+ unsigned StoredPosition = Tokens->getPosition();
+ unsigned Position = StoredPosition;
+ FormatToken *Tok = FormatTok;
+ // 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.
+ SmallVector<FormatToken *, 8> LBraceStack;
+ assert(Tok->Tok.is(tok::l_brace));
+ do {
+ // Get next none-comment token.
+ FormatToken *NextTok;
+ unsigned ReadTokens = 0;
+ do {
+ NextTok = Tokens->getNextToken();
+ ++ReadTokens;
+ } while (NextTok->is(tok::comment));
+
+ switch (Tok->Tok.getKind()) {
+ case tok::l_brace:
+ LBraceStack.push_back(Tok);
+ break;
+ case tok::r_brace:
+ if (!LBraceStack.empty()) {
+ if (LBraceStack.back()->BlockKind == BK_Unknown) {
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // 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).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren,
+ tok::r_square, tok::l_brace, tok::colon) ||
+ (NextTok->isBinaryOperator() &&
+ !NextTok->isOneOf(tok::plus, tok::minus))) {
+ Tok->BlockKind = BK_BracedInit;
+ LBraceStack.back()->BlockKind = BK_BracedInit;
+ } else {
+ Tok->BlockKind = BK_Block;
+ LBraceStack.back()->BlockKind = BK_Block;
+ }
+ }
+ LBraceStack.pop_back();
+ }
+ break;
+ case tok::semi:
+ case tok::kw_if:
+ case tok::kw_while:
+ case tok::kw_for:
+ case tok::kw_switch:
+ case tok::kw_try:
+ if (!LBraceStack.empty())
+ LBraceStack.back()->BlockKind = BK_Block;
+ break;
+ default:
+ break;
+ }
+ Tok = NextTok;
+ Position += ReadTokens;
+ } while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
+ // Assume other blocks for all unclosed opening braces.
+ for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
+ if (LBraceStack[i]->BlockKind == BK_Unknown)
+ LBraceStack[i]->BlockKind = BK_Block;
+ }
+
+ FormatTok = Tokens->setPosition(StoredPosition);
+}
+
+void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
+ bool MunchSemi) {
+ assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected");
+ unsigned InitialLevel = Line->Level;
nextToken();
addUnwrappedLine();
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
- Line->Level += AddLevels;
- parseLevel(/*HasOpeningBrace=*/ true);
+ if (AddLevel)
+ ++Line->Level;
+ parseLevel(/*HasOpeningBrace=*/true);
- if (!FormatTok.Tok.is(tok::r_brace)) {
- Line->Level -= AddLevels;
+ if (!FormatTok->Tok.is(tok::r_brace)) {
+ Line->Level = InitialLevel;
StructuralError = true;
return;
}
nextToken(); // Munch the closing brace.
- Line->Level -= AddLevels;
+ if (MunchSemi && FormatTok->Tok.is(tok::semi))
+ nextToken();
+ Line->Level = InitialLevel;
+}
+
+void UnwrappedLineParser::parseChildBlock() {
+ FormatTok->BlockKind = BK_Block;
+ nextToken();
+ {
+ ScopedLineState LineState(*this);
+ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+ /*MustBeDeclaration=*/false);
+ Line->Level += 1;
+ parseLevel(/*HasOpeningBrace=*/true);
+ Line->Level -= 1;
+ }
+ nextToken();
}
void UnwrappedLineParser::parsePPDirective() {
- assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
+ assert(FormatTok->Tok.is(tok::hash) && "'#' expected");
ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError);
nextToken();
- if (FormatTok.Tok.getIdentifierInfo() == NULL) {
+ if (FormatTok->Tok.getIdentifierInfo() == NULL) {
parsePPUnknown();
return;
}
- switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ switch (FormatTok->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_define:
parsePPDefine();
+ return;
+ case tok::pp_if:
+ parsePPIf(/*IfDef=*/false);
+ break;
+ case tok::pp_ifdef:
+ case tok::pp_ifndef:
+ parsePPIf(/*IfDef=*/true);
+ break;
+ case tok::pp_else:
+ parsePPElse();
+ break;
+ case tok::pp_elif:
+ parsePPElIf();
+ break;
+ case tok::pp_endif:
+ parsePPEndIf();
break;
default:
parsePPUnknown();
@@ -229,16 +436,77 @@ void UnwrappedLineParser::parsePPDirective() {
}
}
+void UnwrappedLineParser::pushPPConditional() {
+ if (!PPStack.empty() && PPStack.back() == PP_Unreachable)
+ PPStack.push_back(PP_Unreachable);
+ else
+ PPStack.push_back(PP_Conditional);
+}
+
+void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ ++PPBranchLevel;
+ assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
+ if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
+ PPLevelBranchIndex.push_back(0);
+ PPLevelBranchCount.push_back(0);
+ }
+ PPChainBranchIndex.push(0);
+ nextToken();
+ bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ StringRef(FormatTok->Tok.getLiteralData(),
+ FormatTok->Tok.getLength()) == "0") ||
+ FormatTok->Tok.is(tok::kw_false);
+ if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) {
+ PPStack.push_back(PP_Unreachable);
+ } else {
+ pushPPConditional();
+ }
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElse() {
+ if (!PPStack.empty())
+ PPStack.pop_back();
+ assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
+ if (!PPChainBranchIndex.empty())
+ ++PPChainBranchIndex.top();
+ if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
+ PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) {
+ PPStack.push_back(PP_Unreachable);
+ } else {
+ pushPPConditional();
+ }
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
+
+void UnwrappedLineParser::parsePPEndIf() {
+ assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
+ if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
+ if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
+ PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
+ }
+ }
+ --PPBranchLevel;
+ if (!PPChainBranchIndex.empty())
+ PPChainBranchIndex.pop();
+ if (!PPStack.empty())
+ PPStack.pop_back();
+ parsePPUnknown();
+}
+
void UnwrappedLineParser::parsePPDefine() {
nextToken();
- if (FormatTok.Tok.getKind() != tok::identifier) {
+ if (FormatTok->Tok.getKind() != tok::identifier) {
parsePPUnknown();
return;
}
nextToken();
- if (FormatTok.Tok.getKind() == tok::l_paren &&
- FormatTok.WhiteSpaceLength == 0) {
+ if (FormatTok->Tok.getKind() == tok::l_paren &&
+ FormatTok->WhitespaceRange.getBegin() ==
+ FormatTok->WhitespaceRange.getEnd()) {
parseParens();
}
addUnwrappedLine();
@@ -287,15 +555,15 @@ bool tokenCanStartNewLine(clang::Token Tok) {
}
void UnwrappedLineParser::parseStructuralElement() {
- assert(!FormatTok.Tok.is(tok::l_brace));
- switch (FormatTok.Tok.getKind()) {
+ assert(!FormatTok->Tok.is(tok::l_brace));
+ switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
+ if (FormatTok->Tok.is(tok::l_brace)) {
parseBracedList();
break;
}
- switch (FormatTok.Tok.getObjCKeywordID()) {
+ switch (FormatTok->Tok.getObjCKeywordID()) {
case tok::objc_public:
case tok::objc_protected:
case tok::objc_package:
@@ -322,7 +590,7 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
case tok::kw_inline:
nextToken();
- if (FormatTok.Tok.is(tok::kw_namespace)) {
+ if (FormatTok->Tok.is(tok::kw_namespace)) {
parseNamespace();
return;
}
@@ -357,10 +625,10 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
case tok::kw_extern:
nextToken();
- if (FormatTok.Tok.is(tok::string_literal)) {
+ if (FormatTok->Tok.is(tok::string_literal)) {
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ true, 0);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
addUnwrappedLine();
return;
}
@@ -371,10 +639,10 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
}
do {
- switch (FormatTok.Tok.getKind()) {
+ switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
- if (FormatTok.Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace))
parseBracedList();
break;
case tok::kw_enum:
@@ -397,38 +665,63 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::l_paren:
parseParens();
break;
+ case tok::caret:
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ parseChildBlock();
+ }
+ break;
case tok::l_brace:
- // A block outside of parentheses must be the last part of a
- // structural element.
- // FIXME: Figure out cases where this is not true, and add projections for
- // them (the one we know is missing are lambdas).
- parseBlock(/*MustBeDeclaration=*/ false);
- addUnwrappedLine();
- return;
- case tok::identifier:
+ if (!tryToParseBracedList()) {
+ // A block outside of parentheses must be the last part of a
+ // structural element.
+ // FIXME: Figure out cases where this is not true, and add projections
+ // for them (the one we know is missing are lambdas).
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
+ addUnwrappedLine();
+ return;
+ }
+ // Otherwise this was a braced init list, and the structural
+ // element continues.
+ break;
+ case tok::identifier: {
+ StringRef Text = FormatTok->TokenText;
nextToken();
if (Line->Tokens.size() == 1) {
- if (FormatTok.Tok.is(tok::colon)) {
+ if (FormatTok->Tok.is(tok::colon)) {
parseLabel();
return;
}
// Recognize function-like macro usages without trailing semicolon.
- if (FormatTok.Tok.is(tok::l_paren)) {
+ if (FormatTok->Tok.is(tok::l_paren)) {
parseParens();
- if (FormatTok.HasUnescapedNewline &&
- tokenCanStartNewLine(FormatTok.Tok)) {
+ if (FormatTok->HasUnescapedNewline &&
+ tokenCanStartNewLine(FormatTok->Tok)) {
addUnwrappedLine();
return;
}
+ } else if (FormatTok->HasUnescapedNewline && Text.size() >= 5 &&
+ Text == Text.upper()) {
+ // Recognize free-standing macros like Q_OBJECT.
+ addUnwrappedLine();
+ return;
}
}
break;
+ }
case tok::equal:
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
+ if (FormatTok->Tok.is(tok::l_brace)) {
parseBracedList();
}
break;
+ case tok::l_square:
+ tryToParseLambda();
+ break;
default:
nextToken();
break;
@@ -436,52 +729,146 @@ void UnwrappedLineParser::parseStructuralElement() {
} while (!eof());
}
-void UnwrappedLineParser::parseBracedList() {
+void UnwrappedLineParser::tryToParseLambda() {
+ // FIXME: This is a dirty way to access the previous token. Find a better
+ // solution.
+ if (!Line->Tokens.empty() &&
+ Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator)) {
+ nextToken();
+ return;
+ }
+ assert(FormatTok->is(tok::l_square));
+ FormatToken &LSquare = *FormatTok;
+ if (!tryToParseLambdaIntroducer())
+ return;
+
+ while (FormatTok->isNot(tok::l_brace)) {
+ switch (FormatTok->Tok.getKind()) {
+ case tok::l_brace:
+ break;
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::identifier:
+ case tok::kw_mutable:
+ nextToken();
+ break;
+ default:
+ return;
+ }
+ }
+ LSquare.Type = TT_LambdaLSquare;
+ parseChildBlock();
+}
+
+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)) {
+ nextToken();
+ return true;
+ }
+ do {
+ if (FormatTok->is(tok::amp))
+ nextToken();
+ if (!FormatTok->isOneOf(tok::identifier, tok::kw_this))
+ return false;
+ nextToken();
+ if (FormatTok->is(tok::comma)) {
+ nextToken();
+ } else if (FormatTok->is(tok::r_square)) {
+ nextToken();
+ return true;
+ } else {
+ return false;
+ }
+ } while (!eof());
+ return false;
+}
+
+bool UnwrappedLineParser::tryToParseBracedList() {
+ if (FormatTok->BlockKind == BK_Unknown)
+ calculateBraceTypes();
+ assert(FormatTok->BlockKind != BK_Unknown);
+ if (FormatTok->BlockKind == BK_Block)
+ return false;
+ parseBracedList();
+ return true;
+}
+
+bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
+ bool HasError = false;
nextToken();
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
- bool StartOfExpression = true;
do {
// FIXME: When we start to support lambdas, we'll want to parse them away
// here, otherwise our bail-out scenarios below break. The better solution
// might be to just implement a more or less complete expression parser.
- switch (FormatTok.Tok.getKind()) {
- case tok::l_brace:
- if (!StartOfExpression) {
- // Probably a missing closing brace. Bail out.
- addUnwrappedLine();
- return;
+ switch (FormatTok->Tok.getKind()) {
+ case tok::caret:
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ parseChildBlock();
}
+ break;
+ case tok::l_square:
+ tryToParseLambda();
+ break;
+ case tok::l_brace:
+ // Assume there are no blocks inside a braced init list apart
+ // from the ones we explicitly parse out (like lambdas).
+ FormatTok->BlockKind = BK_BracedInit;
parseBracedList();
- StartOfExpression = false;
break;
case tok::r_brace:
nextToken();
- return;
+ return !HasError;
case tok::semi:
- // Probably a missing closing brace. Bail out.
- return;
+ HasError = true;
+ if (!ContinueOnSemicolons)
+ return !HasError;
+ nextToken();
+ break;
case tok::comma:
nextToken();
- StartOfExpression = true;
break;
default:
nextToken();
- StartOfExpression = false;
break;
}
} while (!eof());
+ return false;
}
void UnwrappedLineParser::parseReturn() {
nextToken();
do {
- switch (FormatTok.Tok.getKind()) {
+ switch (FormatTok->Tok.getKind()) {
case tok::l_brace:
parseBracedList();
- if (FormatTok.Tok.isNot(tok::semi)) {
+ if (FormatTok->Tok.isNot(tok::semi)) {
// Assume missing ';'.
addUnwrappedLine();
return;
@@ -498,6 +885,9 @@ void UnwrappedLineParser::parseReturn() {
nextToken();
addUnwrappedLine();
return;
+ case tok::l_square:
+ tryToParseLambda();
+ break;
default:
nextToken();
break;
@@ -506,29 +896,31 @@ void UnwrappedLineParser::parseReturn() {
}
void UnwrappedLineParser::parseParens() {
- assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
+ assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected.");
nextToken();
do {
- switch (FormatTok.Tok.getKind()) {
+ switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
parseParens();
break;
case tok::r_paren:
nextToken();
return;
+ case tok::r_brace:
+ // A "}" inside parenthesis is an error if there wasn't a matching "{".
+ return;
+ case tok::l_square:
+ tryToParseLambda();
+ break;
case tok::l_brace: {
- nextToken();
- ScopedLineState LineState(*this);
- ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
- /*MustBeDeclaration=*/ false);
- Line->Level += 1;
- parseLevel(/*HasOpeningBrace=*/ true);
- Line->Level -= 1;
+ if (!tryToParseBracedList()) {
+ parseChildBlock();
+ }
break;
}
case tok::at:
nextToken();
- if (FormatTok.Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace))
parseBracedList();
break;
default:
@@ -539,26 +931,33 @@ void UnwrappedLineParser::parseParens() {
}
void UnwrappedLineParser::parseIfThenElse() {
- assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
+ assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
nextToken();
- if (FormatTok.Tok.is(tok::l_paren))
+ if (FormatTok->Tok.is(tok::l_paren))
parseParens();
bool NeedsUnwrappedLine = false;
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false);
- NeedsUnwrappedLine = true;
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ else
+ NeedsUnwrappedLine = true;
} else {
addUnwrappedLine();
++Line->Level;
parseStructuralElement();
--Line->Level;
}
- if (FormatTok.Tok.is(tok::kw_else)) {
+ if (FormatTok->Tok.is(tok::kw_else)) {
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
- } else if (FormatTok.Tok.is(tok::kw_if)) {
+ } else if (FormatTok->Tok.is(tok::kw_if)) {
parseIfThenElse();
} else {
addUnwrappedLine();
@@ -572,15 +971,22 @@ void UnwrappedLineParser::parseIfThenElse() {
}
void UnwrappedLineParser::parseNamespace() {
- assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
+ assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
nextToken();
- if (FormatTok.Tok.is(tok::identifier))
+ if (FormatTok->Tok.is(tok::identifier))
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ true, 0);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+
+ bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
+ (Style.NamespaceIndentation == FormatStyle::NI_Inner &&
+ DeclarationScopeStack.size() > 1);
+ parseBlock(/*MustBeDeclaration=*/true, AddLevel);
// Munch the semicolon after a namespace. This is more common than one would
// think. Puttin the semicolon into its own line is very ugly.
- if (FormatTok.Tok.is(tok::semi))
+ if (FormatTok->Tok.is(tok::semi))
nextToken();
addUnwrappedLine();
}
@@ -588,13 +994,15 @@ void UnwrappedLineParser::parseNamespace() {
}
void UnwrappedLineParser::parseForOrWhileLoop() {
- assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
+ assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&
"'for' or 'while' expected");
nextToken();
- if (FormatTok.Tok.is(tok::l_paren))
+ if (FormatTok->Tok.is(tok::l_paren))
parseParens();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
addUnwrappedLine();
@@ -605,10 +1013,12 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
}
void UnwrappedLineParser::parseDoWhile() {
- assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
+ assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
nextToken();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
} else {
addUnwrappedLine();
++Line->Level;
@@ -617,7 +1027,7 @@ void UnwrappedLineParser::parseDoWhile() {
}
// FIXME: Add error handling.
- if (!FormatTok.Tok.is(tok::kw_while)) {
+ if (!FormatTok->Tok.is(tok::kw_while)) {
addUnwrappedLine();
return;
}
@@ -627,90 +1037,84 @@ void UnwrappedLineParser::parseDoWhile() {
}
void UnwrappedLineParser::parseLabel() {
- if (FormatTok.Tok.isNot(tok::colon))
- return;
nextToken();
unsigned OldLineLevel = Line->Level;
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
--Line->Level;
- if (CommentsBeforeNextToken.empty() && FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false);
- if (FormatTok.Tok.is(tok::kw_break))
- parseStructuralElement(); // "break;" after "}" goes on the same line.
+ if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (FormatTok->Tok.is(tok::kw_break)) {
+ // "break;" after "}" on its own line only for BS_Allman
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseStructuralElement();
+ }
}
addUnwrappedLine();
Line->Level = OldLineLevel;
}
void UnwrappedLineParser::parseCaseLabel() {
- assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
+ assert(FormatTok->Tok.is(tok::kw_case) && "'case' expected");
// FIXME: fix handling of complex expressions here.
do {
nextToken();
- } while (!eof() && !FormatTok.Tok.is(tok::colon));
+ } while (!eof() && !FormatTok->Tok.is(tok::colon));
parseLabel();
}
void UnwrappedLineParser::parseSwitch() {
- assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
+ assert(FormatTok->Tok.is(tok::kw_switch) && "'switch' expected");
nextToken();
- if (FormatTok.Tok.is(tok::l_paren))
+ if (FormatTok->Tok.is(tok::l_paren))
parseParens();
- if (FormatTok.Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/ false, Style.IndentCaseLabels ? 2 : 1);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
addUnwrappedLine();
- Line->Level += (Style.IndentCaseLabels ? 2 : 1);
+ ++Line->Level;
parseStructuralElement();
- Line->Level -= (Style.IndentCaseLabels ? 2 : 1);
+ --Line->Level;
}
}
void UnwrappedLineParser::parseAccessSpecifier() {
nextToken();
// Otherwise, we don't know what it is, and we'd better keep the next token.
- if (FormatTok.Tok.is(tok::colon))
+ if (FormatTok->Tok.is(tok::colon))
nextToken();
addUnwrappedLine();
}
void UnwrappedLineParser::parseEnum() {
nextToken();
- if (FormatTok.Tok.is(tok::identifier) ||
- FormatTok.Tok.is(tok::kw___attribute) ||
- FormatTok.Tok.is(tok::kw___declspec)) {
+ // Eat up enum class ...
+ if (FormatTok->Tok.is(tok::kw_class) ||
+ FormatTok->Tok.is(tok::kw_struct))
+ nextToken();
+ while (FormatTok->Tok.getIdentifierInfo() ||
+ FormatTok->isOneOf(tok::colon, tok::coloncolon)) {
nextToken();
// We can have macros or attributes in between 'enum' and the enum name.
- if (FormatTok.Tok.is(tok::l_paren)) {
+ if (FormatTok->Tok.is(tok::l_paren)) {
parseParens();
}
- if (FormatTok.Tok.is(tok::identifier))
+ if (FormatTok->Tok.is(tok::identifier))
nextToken();
}
- if (FormatTok.Tok.is(tok::l_brace)) {
- nextToken();
- addUnwrappedLine();
- ++Line->Level;
- do {
- switch (FormatTok.Tok.getKind()) {
- case tok::l_paren:
- parseParens();
- break;
- case tok::r_brace:
- addUnwrappedLine();
- nextToken();
- --Line->Level;
- return;
- case tok::comma:
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ FormatTok->BlockKind = BK_Block;
+ bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
+ if (HasError) {
+ if (FormatTok->is(tok::semi))
nextToken();
- addUnwrappedLine();
- break;
- default:
- nextToken();
- break;
- }
- } while (!eof());
+ addUnwrappedLine();
+ }
}
// We fall through to parsing a structural element afterwards, so that in
// enum A {} n, m;
@@ -719,18 +1123,20 @@ void UnwrappedLineParser::parseEnum() {
void UnwrappedLineParser::parseRecord() {
nextToken();
- if (FormatTok.Tok.is(tok::identifier) ||
- FormatTok.Tok.is(tok::kw___attribute) ||
- FormatTok.Tok.is(tok::kw___declspec)) {
+ if (FormatTok->Tok.is(tok::identifier) ||
+ FormatTok->Tok.is(tok::kw___attribute) ||
+ FormatTok->Tok.is(tok::kw___declspec) ||
+ FormatTok->Tok.is(tok::kw_alignas)) {
nextToken();
// We can have macros or attributes in between 'class' and the class name.
- if (FormatTok.Tok.is(tok::l_paren)) {
+ if (FormatTok->Tok.is(tok::l_paren)) {
parseParens();
}
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
- while (FormatTok.Tok.is(tok::identifier) ||
- FormatTok.Tok.is(tok::coloncolon) || FormatTok.Tok.is(tok::hashhash))
+ while (FormatTok->Tok.is(tok::identifier) ||
+ FormatTok->Tok.is(tok::coloncolon) ||
+ FormatTok->Tok.is(tok::hashhash))
nextToken();
// Note that parsing away template declarations here leads to incorrectly
@@ -743,37 +1149,49 @@ void UnwrappedLineParser::parseRecord() {
// and thus rule out the record production in case there is no template
// (this would still leave us with an ambiguity between template function
// and class declarations).
- if (FormatTok.Tok.is(tok::colon) || FormatTok.Tok.is(tok::less)) {
- while (!eof() && FormatTok.Tok.isNot(tok::l_brace)) {
- if (FormatTok.Tok.is(tok::semi))
+ if (FormatTok->Tok.is(tok::colon) || FormatTok->Tok.is(tok::less)) {
+ while (!eof() && FormatTok->Tok.isNot(tok::l_brace)) {
+ if (FormatTok->Tok.is(tok::semi))
return;
nextToken();
}
}
}
- if (FormatTok.Tok.is(tok::l_brace))
- parseBlock(/*MustBeDeclaration=*/ true);
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ addUnwrappedLine();
+
+ parseBlock(/*MustBeDeclaration=*/true, /*Addlevel=*/true,
+ /*MunchSemi=*/false);
+ }
// We fall through to parsing a structural element afterwards, so
// class A {} n, m;
// will end up in one unwrapped line.
}
void UnwrappedLineParser::parseObjCProtocolList() {
- assert(FormatTok.Tok.is(tok::less) && "'<' expected.");
+ assert(FormatTok->Tok.is(tok::less) && "'<' expected.");
do
nextToken();
- while (!eof() && FormatTok.Tok.isNot(tok::greater));
+ while (!eof() && FormatTok->Tok.isNot(tok::greater));
nextToken(); // Skip '>'.
}
void UnwrappedLineParser::parseObjCUntilAtEnd() {
do {
- if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) {
+ if (FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) {
nextToken();
addUnwrappedLine();
break;
}
- parseStructuralElement();
+ if (FormatTok->is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/false);
+ // In ObjC interfaces, nothing should be following the "}".
+ addUnwrappedLine();
+ } else {
+ parseStructuralElement();
+ }
} while (!eof());
}
@@ -782,19 +1200,19 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
nextToken(); // interface name
// @interface can be followed by either a base class, or a category.
- if (FormatTok.Tok.is(tok::colon)) {
+ if (FormatTok->Tok.is(tok::colon)) {
nextToken();
nextToken(); // base class name
- } else if (FormatTok.Tok.is(tok::l_paren))
+ } else if (FormatTok->Tok.is(tok::l_paren))
// Skip category, if present.
parseParens();
- if (FormatTok.Tok.is(tok::less))
+ if (FormatTok->Tok.is(tok::less))
parseObjCProtocolList();
// If instance variables are present, keep the '{' on the first line too.
- if (FormatTok.Tok.is(tok::l_brace))
- parseBlock(/*MustBeDeclaration=*/ true);
+ if (FormatTok->Tok.is(tok::l_brace))
+ parseBlock(/*MustBeDeclaration=*/true);
// With instance variables, this puts '}' on its own line. Without instance
// variables, this ends the @interface line.
@@ -807,11 +1225,11 @@ void UnwrappedLineParser::parseObjCProtocol() {
nextToken();
nextToken(); // protocol name
- if (FormatTok.Tok.is(tok::less))
+ if (FormatTok->Tok.is(tok::less))
parseObjCProtocolList();
// Check for protocol declaration.
- if (FormatTok.Tok.is(tok::semi)) {
+ if (FormatTok->Tok.is(tok::semi)) {
nextToken();
return addUnwrappedLine();
}
@@ -820,24 +1238,40 @@ void UnwrappedLineParser::parseObjCProtocol() {
parseObjCUntilAtEnd();
}
+LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
+ StringRef Prefix = "") {
+ llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
+ << (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() << "[" << I->Tok->Type << "] ";
+ }
+ for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
+ E = Line.Tokens.end();
+ I != E; ++I) {
+ const UnwrappedLineNode &Node = *I;
+ for (SmallVectorImpl<UnwrappedLine>::const_iterator
+ I = Node.Children.begin(),
+ E = Node.Children.end();
+ I != E; ++I) {
+ printDebugInfo(*I, "\nChild: ");
+ }
+ }
+ llvm::dbgs() << "\n";
+}
+
void UnwrappedLineParser::addUnwrappedLine() {
if (Line->Tokens.empty())
return;
DEBUG({
- llvm::dbgs() << "Line(" << Line->Level << ")"
- << (Line->InPPDirective ? " MACRO" : "") << ": ";
- for (std::list<FormatToken>::iterator I = Line->Tokens.begin(),
- E = Line->Tokens.end();
- I != E; ++I) {
- llvm::dbgs() << I->Tok.getName() << " ";
-
- }
- llvm::dbgs() << "\n";
+ if (CurrentLines == &Lines)
+ printDebugInfo(*Line);
});
CurrentLines->push_back(*Line);
Line->Tokens.clear();
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
- for (std::vector<UnwrappedLine>::iterator
+ for (SmallVectorImpl<UnwrappedLine>::iterator
I = PreprocessorDirectives.begin(),
E = PreprocessorDirectives.end();
I != E; ++I) {
@@ -847,15 +1281,15 @@ void UnwrappedLineParser::addUnwrappedLine() {
}
}
-bool UnwrappedLineParser::eof() const { return FormatTok.Tok.is(tok::eof); }
+bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
- for (SmallVectorImpl<FormatToken>::const_iterator
+ for (SmallVectorImpl<FormatToken *>::const_iterator
I = CommentsBeforeNextToken.begin(),
E = CommentsBeforeNextToken.end();
I != E; ++I) {
- if (I->NewlinesBefore && JustComments) {
+ if ((*I)->NewlinesBefore && JustComments) {
addUnwrappedLine();
}
pushToken(*I);
@@ -869,7 +1303,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
void UnwrappedLineParser::nextToken() {
if (eof())
return;
- flushComments(FormatTok.NewlinesBefore > 0);
+ flushComments(FormatTok->NewlinesBefore > 0);
pushToken(FormatTok);
readToken();
}
@@ -878,8 +1312,8 @@ void UnwrappedLineParser::readToken() {
bool CommentsInCurrentLine = true;
do {
FormatTok = Tokens->getNextToken();
- while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
- (FormatTok.HasUnescapedNewline || FormatTok.IsFirst)) {
+ while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) &&
+ (FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
// If there is an unfinished unwrapped line, we flush the preprocessor
// directives only after that unwrapped line was finished later.
bool SwitchToPreprocessorLines =
@@ -888,12 +1322,18 @@ void UnwrappedLineParser::readToken() {
// 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.
- flushComments(FormatTok.NewlinesBefore > 0);
+ flushComments(FormatTok->NewlinesBefore > 0);
parsePPDirective();
}
- if (!FormatTok.Tok.is(tok::comment))
+
+ if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
+ !Line->InPPDirective) {
+ continue;
+ }
+
+ if (!FormatTok->Tok.is(tok::comment))
return;
- if (FormatTok.NewlinesBefore > 0 || FormatTok.IsFirst) {
+ if (FormatTok->NewlinesBefore > 0 || FormatTok->IsFirst) {
CommentsInCurrentLine = false;
}
if (CommentsInCurrentLine) {
@@ -904,10 +1344,10 @@ void UnwrappedLineParser::readToken() {
} while (!eof());
}
-void UnwrappedLineParser::pushToken(const FormatToken &Tok) {
- Line->Tokens.push_back(Tok);
+void UnwrappedLineParser::pushToken(FormatToken *Tok) {
+ Line->Tokens.push_back(UnwrappedLineNode(Tok));
if (MustBreakBeforeNextToken) {
- Line->Tokens.back().MustBreakBefore = true;
+ Line->Tokens.back().Tok->MustBreakBefore = true;
MustBreakBeforeNextToken = false;
}
}
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 0c618e24d44e..f1f4e57a20b3 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -17,78 +17,14 @@
#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
-#include "clang/Lex/Lexer.h"
+#include "FormatToken.h"
#include <list>
namespace clang {
-
-class DiagnosticsEngine;
-
namespace format {
-/// \brief A wrapper around a \c Token storing information about the
-/// whitespace characters preceeding it.
-struct FormatToken {
- FormatToken()
- : NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
- LastNewlineOffset(0), TokenLength(0), IsFirst(false),
- MustBreakBefore(false), TrailingWhiteSpaceLength(0) {}
-
- /// \brief The \c Token.
- Token Tok;
-
- /// \brief The number of newlines immediately before the \c Token.
- ///
- /// This can be used to determine what the user wrote in the original code
- /// and thereby e.g. leave an empty line between two function definitions.
- unsigned NewlinesBefore;
-
- /// \brief Whether there is at least one unescaped newline before the \c
- /// Token.
- bool HasUnescapedNewline;
-
- /// \brief The location of the start of the whitespace immediately preceeding
- /// the \c Token.
- ///
- /// Used together with \c WhiteSpaceLength to create a \c Replacement.
- SourceLocation WhiteSpaceStart;
-
- /// \brief The length in characters of the whitespace immediately preceeding
- /// the \c Token.
- unsigned WhiteSpaceLength;
-
- /// \brief The offset just past the last '\n' in this token's leading
- /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
- unsigned LastNewlineOffset;
-
- /// \brief The length of the non-whitespace parts of the token. This is
- /// necessary because we need to handle escaped newlines that are stored
- /// with the token.
- unsigned TokenLength;
-
- /// \brief Indicates that this is the first token.
- bool IsFirst;
-
- /// \brief Whether there must be a line break before this token.
- ///
- /// This happens for example when a preprocessor directive ended directly
- /// before the token.
- bool MustBreakBefore;
-
- /// \brief Number of characters of trailing whitespace.
- unsigned TrailingWhiteSpaceLength;
-
- /// \brief Returns actual token start location without leading escaped
- /// newlines and whitespace.
- ///
- /// This can be different to Tok.getLocation(), which includes leading escaped
- /// newlines.
- SourceLocation getStartOfNonWhitespace() const {
- return WhiteSpaceStart.getLocWithOffset(WhiteSpaceLength);
- }
-};
+struct UnwrappedLineNode;
/// \brief An unwrapped line is a sequence of \c Token, that we would like to
/// put on a single line if there was no column limit.
@@ -97,12 +33,11 @@ struct FormatToken {
/// \c UnwrappedLineFormatter. The key property is that changing the formatting
/// within an unwrapped line does not affect any other unwrapped lines.
struct UnwrappedLine {
- UnwrappedLine() : Level(0), InPPDirective(false), MustBeDeclaration(false) {
- }
+ UnwrappedLine();
// FIXME: Don't use std::list here.
/// \brief The \c Tokens comprising this \c UnwrappedLine.
- std::list<FormatToken> Tokens;
+ std::list<UnwrappedLineNode> Tokens;
/// \brief The indent level of the \c UnwrappedLine.
unsigned Level;
@@ -115,36 +50,38 @@ struct UnwrappedLine {
class UnwrappedLineConsumer {
public:
- virtual ~UnwrappedLineConsumer() {
- }
+ virtual ~UnwrappedLineConsumer() {}
virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0;
+ virtual void finishRun() = 0;
};
-class FormatTokenSource {
-public:
- virtual ~FormatTokenSource() {
- }
- virtual FormatToken getNextToken() = 0;
-};
+class FormatTokenSource;
class UnwrappedLineParser {
public:
- UnwrappedLineParser(clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
- FormatTokenSource &Tokens,
+ UnwrappedLineParser(const FormatStyle &Style, ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback);
/// Returns true in case of a structural error.
bool parse();
private:
+ void reset();
void parseFile();
void parseLevel(bool HasOpeningBrace);
- void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1);
+ void parseBlock(bool MustBeDeclaration, bool AddLevel = true,
+ bool MunchSemi = true);
+ void parseChildBlock();
void parsePPDirective();
void parsePPDefine();
+ void parsePPIf(bool IfDef);
+ void parsePPElIf();
+ void parsePPElse();
+ void parsePPEndIf();
void parsePPUnknown();
void parseStructuralElement();
- void parseBracedList();
+ bool tryToParseBracedList();
+ bool parseBracedList(bool ContinueOnSemicolons = false);
void parseReturn();
void parseParens();
void parseIfThenElse();
@@ -161,12 +98,16 @@ private:
void parseObjCUntilAtEnd();
void parseObjCInterfaceOrImplementation();
void parseObjCProtocol();
+ void tryToParseLambda();
+ bool tryToParseLambdaIntroducer();
void addUnwrappedLine();
bool eof() const;
void nextToken();
void readToken();
void flushComments(bool NewlineBeforeNext);
- void pushToken(const FormatToken &Tok);
+ void pushToken(FormatToken *Tok);
+ void calculateBraceTypes();
+ void pushPPConditional();
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
@@ -177,23 +118,23 @@ private:
// line as the previous token, or not. If not, they belong to the next token.
// Since the next token might already be in a new unwrapped line, we need to
// store the comments belonging to that token.
- SmallVector<FormatToken, 1> CommentsBeforeNextToken;
- FormatToken FormatTok;
+ SmallVector<FormatToken *, 1> CommentsBeforeNextToken;
+ FormatToken *FormatTok;
bool MustBreakBeforeNextToken;
// The parsed lines. Only added to through \c CurrentLines.
- std::vector<UnwrappedLine> Lines;
+ SmallVector<UnwrappedLine, 8> Lines;
// 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.
- std::vector<UnwrappedLine> PreprocessorDirectives;
+ SmallVector<UnwrappedLine, 4> PreprocessorDirectives;
// New unwrapped lines are added via CurrentLines.
// Usually points to \c &Lines. While parsing a preprocessor directive when
// there is an unfinished previous unwrapped line, will point to
// \c &PreprocessorDirectives.
- std::vector<UnwrappedLine> *CurrentLines;
+ SmallVectorImpl<UnwrappedLine> *CurrentLines;
// We store for each line whether it must be a declaration depending on
// whether we are in a compound statement or not.
@@ -203,14 +144,60 @@ private:
// indentation levels.
bool StructuralError;
- clang::DiagnosticsEngine &Diag;
const FormatStyle &Style;
FormatTokenSource *Tokens;
UnwrappedLineConsumer &Callback;
+ // FIXME: This is a temporary measure until we have reworked the ownership
+ // of the format tokens. The goal is to have the actual tokens created and
+ // owned outside of and handed into the UnwrappedLineParser.
+ ArrayRef<FormatToken *> AllTokens;
+
+ // Represents preprocessor branch type, so we can find matching
+ // #if/#else/#endif directives.
+ enum PPBranchKind {
+ PP_Conditional, // Any #if, #ifdef, #ifndef, #elif, block outside #if 0
+ PP_Unreachable // #if 0 or a conditional preprocessor block inside #if 0
+ };
+
+ // Keeps a stack of currently active preprocessor branching directives.
+ SmallVector<PPBranchKind, 16> PPStack;
+
+ // The \c UnwrappedLineParser re-parses the code for each combination
+ // of preprocessor branches that can be taken.
+ // To that end, we take the same branch (#if, #else, or one of the #elif
+ // branches) for each nesting level of preprocessor branches.
+ // \c PPBranchLevel stores the current nesting level of preprocessor
+ // branches during one pass over the code.
+ int PPBranchLevel;
+
+ // Contains the current branch (#if, #else or one of the #elif branches)
+ // for each nesting level.
+ SmallVector<int, 8> PPLevelBranchIndex;
+
+ // Contains the maximum number of branches at each nesting level.
+ SmallVector<int, 8> PPLevelBranchCount;
+
+ // Contains the number of branches per nesting level we are currently
+ // in while parsing a preprocessor branch sequence.
+ // This is used to update PPLevelBranchCount at the end of a branch
+ // sequence.
+ std::stack<int> PPChainBranchIndex;
+
friend class ScopedLineState;
};
+struct UnwrappedLineNode {
+ UnwrappedLineNode() : Tok(NULL) {}
+ UnwrappedLineNode(FormatToken *Tok) : Tok(Tok) {}
+
+ FormatToken *Tok;
+ SmallVector<UnwrappedLine, 0> Children;
+};
+
+inline UnwrappedLine::UnwrappedLine()
+ : Level(0), InPPDirective(false), MustBeDeclaration(false) {}
+
} // end namespace format
} // end namespace clang
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index a75c592bfeda..26a8d41e8741 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -18,193 +18,302 @@
namespace clang {
namespace format {
-void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok,
- unsigned NewLines, unsigned Spaces,
- unsigned WhitespaceStartColumn) {
- if (NewLines > 0)
- alignEscapedNewlines();
-
- // 2+ newlines mean an empty line separating logic scopes.
- if (NewLines >= 2)
- alignComments();
-
- // Align line comments if they are trailing or if they continue other
- // trailing comments.
- if (Tok.isTrailingComment()) {
- SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace()
- .getLocWithOffset(Tok.FormatTok.TokenLength);
- // Remove the comment's trailing whitespace.
- if (Tok.FormatTok.TrailingWhiteSpaceLength != 0)
- Replaces.insert(tooling::Replacement(
- SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, ""));
-
- bool LineExceedsColumnLimit =
- Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength >
- Style.ColumnLimit;
- // Align comment with other comments.
- if ((Tok.Parent != NULL || !Comments.empty()) &&
- !LineExceedsColumnLimit) {
- unsigned MinColumn =
- NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces;
- unsigned MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength;
- Comments.push_back(StoredToken(
- Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength,
- MinColumn, MaxColumn, NewLines, Spaces));
- return;
- }
- }
-
- // If this line does not have a trailing comment, align the stored comments.
- if (Tok.Children.empty() && !Tok.isTrailingComment())
- alignComments();
-
- storeReplacement(Tok.FormatTok.WhiteSpaceStart,
- Tok.FormatTok.WhiteSpaceLength,
- getNewLineText(NewLines, Spaces));
-}
-
-void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok,
- unsigned NewLines, unsigned Spaces,
- unsigned WhitespaceStartColumn) {
- if (NewLines == 0) {
- replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn);
- } else {
- // The earliest position for "\" is 2 after the last token.
- unsigned MinColumn = WhitespaceStartColumn + 2;
- unsigned MaxColumn = Style.ColumnLimit;
- EscapedNewlines.push_back(StoredToken(
- Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength,
- MinColumn, MaxColumn, NewLines, Spaces));
- }
+bool
+WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
+ const Change &C2) const {
+ return SourceMgr.isBeforeInTranslationUnit(
+ C1.OriginalWhitespaceRange.getBegin(),
+ C2.OriginalWhitespaceRange.getBegin());
}
-void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset,
- unsigned ReplaceChars, StringRef Prefix,
- StringRef Postfix, bool InPPDirective,
- unsigned Spaces,
- unsigned WhitespaceStartColumn) {
- SourceLocation Location =
- Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
- if (InPPDirective) {
- // The earliest position for "\" is 2 after the last token.
- unsigned MinColumn = WhitespaceStartColumn + 2;
- unsigned MaxColumn = Style.ColumnLimit;
- StoredToken StoredTok = StoredToken(Location, ReplaceChars, MinColumn,
- MaxColumn, /*NewLines=*/ 1, Spaces);
- StoredTok.Prefix = Prefix;
- StoredTok.Postfix = Postfix;
- EscapedNewlines.push_back(StoredTok);
- } else {
- std::string ReplacementText =
- (Prefix + getNewLineText(1, Spaces) + Postfix).str();
- Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars,
- ReplacementText));
- }
+WhitespaceManager::Change::Change(
+ bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
+ unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned NewlinesBefore, StringRef PreviousLinePostfix,
+ StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
+ : CreateReplacement(CreateReplacement),
+ OriginalWhitespaceRange(OriginalWhitespaceRange),
+ StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
+ PreviousLinePostfix(PreviousLinePostfix),
+ CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
+ ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel),
+ Spaces(Spaces) {}
+
+void WhitespaceManager::reset() {
+ Changes.clear();
+ Replaces.clear();
}
-const tooling::Replacements &WhitespaceManager::generateReplacements() {
- alignComments();
- alignEscapedNewlines();
- return Replaces;
+void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
+ unsigned IndentLevel, unsigned Spaces,
+ unsigned StartOfTokenColumn,
+ bool InPPDirective) {
+ if (Tok.Finalized)
+ return;
+ Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
+ Changes.push_back(Change(true, Tok.WhitespaceRange, IndentLevel, Spaces,
+ StartOfTokenColumn, Newlines, "", "",
+ Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst));
}
-void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc,
- unsigned ReplaceChars, StringRef Text) {
- Replaces.insert(
- tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text));
+void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
+ bool InPPDirective) {
+ if (Tok.Finalized)
+ return;
+ Changes.push_back(Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
+ /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore,
+ "", "", Tok.Tok.getKind(),
+ InPPDirective && !Tok.IsFirst));
}
-void WhitespaceManager::addUntouchableComment(unsigned Column) {
- StoredToken Tok = StoredToken(SourceLocation(), 0, Column, Column, 0, 0);
- Tok.Untouchable = true;
- Comments.push_back(Tok);
+void WhitespaceManager::replaceWhitespaceInToken(
+ const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
+ StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
+ unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
+ if (Tok.Finalized)
+ return;
+ Changes.push_back(Change(
+ true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
+ Tok.getStartOfNonWhitespace().getLocWithOffset(
+ Offset + ReplaceChars)),
+ IndentLevel, Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
+ // If we don't add a newline this change doesn't start a comment. Thus,
+ // when we align line comments, we don't need to treat this change as one.
+ // FIXME: We still need to take this change in account to properly
+ // calculate the new length of the comment and to calculate the changes
+ // for which to do the alignment when aligning comments.
+ Tok.Type == TT_LineComment && Newlines > 0 ? tok::comment : tok::unknown,
+ InPPDirective && !Tok.IsFirst));
}
-std::string WhitespaceManager::getNewLineText(unsigned NewLines,
- unsigned Spaces) {
- return std::string(NewLines, '\n') + std::string(Spaces, ' ');
+const tooling::Replacements &WhitespaceManager::generateReplacements() {
+ if (Changes.empty())
+ return Replaces;
+
+ std::sort(Changes.begin(), Changes.end(), Change::IsBeforeInFile(SourceMgr));
+ calculateLineBreakInformation();
+ alignTrailingComments();
+ alignEscapedNewlines();
+ generateChanges();
+
+ return Replaces;
}
-std::string WhitespaceManager::getNewLineText(unsigned NewLines,
- unsigned Spaces,
- unsigned WhitespaceStartColumn,
- unsigned EscapedNewlineColumn) {
- std::string NewLineText;
- if (NewLines > 0) {
- unsigned Offset =
- std::min<int>(EscapedNewlineColumn - 1, WhitespaceStartColumn);
- for (unsigned i = 0; i < NewLines; ++i) {
- NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' ');
- NewLineText += "\\\n";
- Offset = 0;
- }
+void WhitespaceManager::calculateLineBreakInformation() {
+ Changes[0].PreviousEndOfTokenColumn = 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();
+
+ Changes[i].PreviousEndOfTokenColumn =
+ Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
+
+ Changes[i - 1].IsTrailingComment =
+ (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof) &&
+ Changes[i - 1].Kind == tok::comment;
}
- return NewLineText + std::string(Spaces, ' ');
+ // FIXME: The last token is currently not always an eof token; in those
+ // cases, setting TokenLength of the last token to 0 is wrong.
+ Changes.back().TokenLength = 0;
+ Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
}
-void WhitespaceManager::alignComments() {
+void WhitespaceManager::alignTrailingComments() {
unsigned MinColumn = 0;
unsigned MaxColumn = UINT_MAX;
- token_iterator Start = Comments.begin();
- for (token_iterator I = Start, E = Comments.end(); I != E; ++I) {
- if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) {
- alignComments(Start, I, MinColumn);
- MinColumn = I->MinColumn;
- MaxColumn = I->MaxColumn;
- Start = I;
- } else {
- MinColumn = std::max(MinColumn, I->MinColumn);
- MaxColumn = std::min(MaxColumn, I->MaxColumn);
+ unsigned StartOfSequence = 0;
+ bool BreakBeforeNext = false;
+ unsigned Newlines = 0;
+ for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
+ // FIXME: Correctly handle ChangeMaxColumn in PP directives.
+ unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ Newlines += Changes[i].NewlinesBefore;
+ if (Changes[i].IsTrailingComment) {
+ // If this comment follows an } in column 0, it probably documents the
+ // closing of a namespace and we don't want to align it.
+ bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
+ Changes[i - 1].Kind == tok::r_brace &&
+ Changes[i - 1].StartOfTokenColumn == 0;
+ bool WasAlignedWithStartOfNextLine = false;
+ if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ for (unsigned j = i + 1; j != e; ++j) {
+ if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ // The start of the next token was previously aligned with the
+ // start of this comment.
+ WasAlignedWithStartOfNextLine =
+ (SourceMgr.getSpellingColumnNumber(
+ Changes[i].OriginalWhitespaceRange.getEnd()) ==
+ SourceMgr.getSpellingColumnNumber(
+ Changes[j].OriginalWhitespaceRange.getEnd()));
+ break;
+ }
+ }
+ }
+ if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMinColumn;
+ StartOfSequence = i;
+ } else if (BreakBeforeNext || Newlines > 1 ||
+ (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
+ // Break the comment sequence if the previous line did not end
+ // in a trailing comment.
+ (Changes[i].NewlinesBefore == 1 && i > 0 &&
+ !Changes[i - 1].IsTrailingComment) ||
+ WasAlignedWithStartOfNextLine) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMaxColumn;
+ StartOfSequence = i;
+ } else {
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+ BreakBeforeNext =
+ (i == 0) || (Changes[i].NewlinesBefore > 1) ||
+ // Never start a sequence with a comment at the beginning of
+ // the line.
+ (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
+ Newlines = 0;
}
}
- alignComments(Start, Comments.end(), MinColumn);
- Comments.clear();
+ alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
}
-void WhitespaceManager::alignComments(token_iterator I, token_iterator E,
- unsigned Column) {
- while (I != E) {
- if (!I->Untouchable) {
- unsigned Spaces = I->Spaces + Column - I->MinColumn;
- storeReplacement(I->ReplacementLoc, I->ReplacementLength,
- getNewLineText(I->NewLines, Spaces));
+void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
+ unsigned Column) {
+ for (unsigned i = Start; i != End; ++i) {
+ if (Changes[i].IsTrailingComment) {
+ assert(Column >= Changes[i].StartOfTokenColumn);
+ Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
+ Changes[i].StartOfTokenColumn = Column;
}
- ++I;
}
}
void WhitespaceManager::alignEscapedNewlines() {
- unsigned MinColumn;
- if (Style.AlignEscapedNewlinesLeft) {
- MinColumn = 0;
- for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
- I != E; ++I) {
- if (I->MinColumn > MinColumn)
- MinColumn = I->MinColumn;
+ unsigned MaxEndOfLine =
+ Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ unsigned StartOfMacro = 0;
+ for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
+ Change &C = Changes[i];
+ if (C.NewlinesBefore > 0) {
+ if (C.ContinuesPPDirective) {
+ MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
+ } else {
+ alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
+ MaxEndOfLine = Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ StartOfMacro = i;
+ }
}
- } else {
- MinColumn = Style.ColumnLimit;
}
+ alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
+}
- for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
- I != E; ++I) {
- // I->MinColumn - 2 is the end of the previous token (i.e. the
- // WhitespaceStartColumn).
- storeReplacement(
- I->ReplacementLoc, I->ReplacementLength,
- I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2,
- MinColumn) + I->Postfix);
+void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
+ unsigned Column) {
+ for (unsigned i = Start; i < End; ++i) {
+ Change &C = Changes[i];
+ if (C.NewlinesBefore > 0) {
+ assert(C.ContinuesPPDirective);
+ if (C.PreviousEndOfTokenColumn + 1 > Column)
+ C.EscapedNewlineColumn = 0;
+ else
+ C.EscapedNewlineColumn = Column;
+ }
+ }
+}
+void WhitespaceManager::generateChanges() {
+ for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ const Change &C = Changes[i];
+ if (C.CreateReplacement) {
+ std::string ReplacementText = C.PreviousLinePostfix;
+ if (C.ContinuesPPDirective)
+ appendNewlineText(ReplacementText, C.NewlinesBefore,
+ C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
+ else
+ appendNewlineText(ReplacementText, C.NewlinesBefore);
+ appendIndentText(ReplacementText, C.IndentLevel, C.Spaces,
+ C.StartOfTokenColumn - C.Spaces);
+ ReplacementText.append(C.CurrentLinePrefix);
+ storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
+ }
}
- EscapedNewlines.clear();
}
-void WhitespaceManager::storeReplacement(SourceLocation Loc, unsigned Length,
- const std::string Text) {
+void WhitespaceManager::storeReplacement(const 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.
- if (StringRef(SourceMgr.getCharacterData(Loc), Length) == Text)
+ if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
+ WhitespaceLength) == Text)
return;
- Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text));
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, CharSourceRange::getCharRange(Range), Text));
+}
+
+void WhitespaceManager::appendNewlineText(std::string &Text,
+ unsigned Newlines) {
+ for (unsigned i = 0; i < Newlines; ++i)
+ Text.append(UseCRLF ? "\r\n" : "\n");
+}
+
+void WhitespaceManager::appendNewlineText(std::string &Text, unsigned Newlines,
+ unsigned PreviousEndOfTokenColumn,
+ unsigned EscapedNewlineColumn) {
+ if (Newlines > 0) {
+ unsigned Offset =
+ std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
+ for (unsigned i = 0; i < Newlines; ++i) {
+ Text.append(std::string(EscapedNewlineColumn - Offset - 1, ' '));
+ Text.append(UseCRLF ? "\\\r\n" : "\\\n");
+ Offset = 0;
+ }
+ }
+}
+
+void WhitespaceManager::appendIndentText(std::string &Text,
+ unsigned IndentLevel, unsigned Spaces,
+ unsigned WhitespaceStartColumn) {
+ switch (Style.UseTab) {
+ case FormatStyle::UT_Never:
+ Text.append(std::string(Spaces, ' '));
+ break;
+ case FormatStyle::UT_Always: {
+ unsigned FirstTabWidth =
+ Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
+ // Indent with tabs only when there's at least one full tab.
+ if (FirstTabWidth + Style.TabWidth <= Spaces) {
+ Spaces -= FirstTabWidth;
+ Text.append("\t");
+ }
+ Text.append(std::string(Spaces / Style.TabWidth, '\t'));
+ Text.append(std::string(Spaces % Style.TabWidth, ' '));
+ break;
+ }
+ case FormatStyle::UT_ForIndentation:
+ if (WhitespaceStartColumn == 0) {
+ unsigned Indentation = IndentLevel * Style.IndentWidth;
+ // This happens, e.g. when a line in a block comment is indented less than
+ // the first one.
+ if (Indentation > Spaces)
+ Indentation = Spaces;
+ unsigned Tabs = Indentation / Style.TabWidth;
+ Text.append(std::string(Tabs, '\t'));
+ Spaces -= Tabs * Style.TabWidth;
+ }
+ Text.append(std::string(Spaces, ' '));
+ break;
+ }
}
} // namespace format
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 5f3dc55edacc..ae6202395f6b 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -28,89 +28,153 @@ namespace format {
///
/// This includes special handling for certain constructs, e.g. the alignment of
/// trailing line comments.
+///
+/// To guarantee correctness of alignment operations, the \c WhitespaceManager
+/// must be informed about every token in the source file; for each token, there
+/// must be exactly one call to either \c replaceWhitespace or
+/// \c addUntouchableToken.
+///
+/// There may be multiple calls to \c breakToken for a given token.
class WhitespaceManager {
public:
- WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style)
- : SourceMgr(SourceMgr), Style(Style) {}
+ WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style,
+ bool UseCRLF)
+ : SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {}
+
+ /// \brief Prepares the \c WhitespaceManager for another run.
+ void reset();
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken.
- void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
- unsigned Spaces, unsigned WhitespaceStartColumn);
+ void replaceWhitespace(FormatToken &Tok, unsigned Newlines,
+ unsigned IndentLevel, unsigned Spaces,
+ unsigned StartOfTokenColumn,
+ bool InPPDirective = false);
- /// \brief Like \c replaceWhitespace, but additionally adds right-aligned
- /// backslashes to escape newlines inside a preprocessor directive.
+ /// \brief Adds information about an unchangable token's whitespace.
///
- /// This function and \c replaceWhitespace have the same behavior if
- /// \c Newlines == 0.
- void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
- unsigned Spaces, unsigned WhitespaceStartColumn);
+ /// Needs to be called for every token for which \c replaceWhitespace
+ /// was not called.
+ void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
- /// \brief Inserts a line break into the middle of a token.
+ /// \brief Inserts or replaces whitespace in the middle of a token.
///
- /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line
- /// break and \p Postfix before the rest of the token starts in the next line.
+ /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix
+ /// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
+ /// characters.
///
- /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are
- /// used to generate the correct line break.
- void breakToken(const FormatToken &Tok, unsigned Offset,
- unsigned ReplaceChars, StringRef Prefix, StringRef Postfix,
- bool InPPDirective, unsigned Spaces,
- unsigned WhitespaceStartColumn);
+ /// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
+ /// used to align backslashes correctly.
+ void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
+ unsigned ReplaceChars,
+ StringRef PreviousPostfix,
+ StringRef CurrentPrefix, bool InPPDirective,
+ unsigned Newlines, unsigned IndentLevel,
+ unsigned Spaces);
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
- void addReplacement(const SourceLocation &SourceLoc, unsigned ReplaceChars,
- StringRef Text);
+private:
+ /// \brief Represents a change before a token, a break inside a token,
+ /// or the layout of an unchanged token (or whitespace within).
+ struct Change {
+ /// \brief Functor to sort changes in original source order.
+ class IsBeforeInFile {
+ public:
+ IsBeforeInFile(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
+ bool operator()(const Change &C1, const Change &C2) const;
+
+ private:
+ const SourceManager &SourceMgr;
+ };
+
+ Change() {}
+
+ /// \brief Creates a \c Change.
+ ///
+ /// The generated \c Change will replace the characters at
+ /// \p OriginalWhitespaceRange with a concatenation of
+ /// \p PreviousLinePostfix, \p NewlinesBefore line breaks, \p Spaces spaces
+ /// and \p CurrentLinePrefix.
+ ///
+ /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
+ /// trailing comments and escaped newlines.
+ Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
+ unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned NewlinesBefore, StringRef PreviousLinePostfix,
+ StringRef CurrentLinePrefix, tok::TokenKind Kind,
+ bool ContinuesPPDirective);
+
+ bool CreateReplacement;
+ // Changes might be in the middle of a token, so we cannot just keep the
+ // FormatToken around to query its information.
+ SourceRange OriginalWhitespaceRange;
+ unsigned StartOfTokenColumn;
+ unsigned NewlinesBefore;
+ std::string PreviousLinePostfix;
+ std::string CurrentLinePrefix;
+ // The kind of the token whose whitespace this change replaces, or in which
+ // this change inserts whitespace.
+ // FIXME: Currently this is not set correctly for breaks inside comments, as
+ // the \c BreakableToken is still doing its own alignment.
+ tok::TokenKind Kind;
+ bool ContinuesPPDirective;
+
+ // The number of nested blocks the token is in. This is used to add tabs
+ // only for the indentation, and not for alignment, when
+ // UseTab = US_ForIndentation.
+ unsigned IndentLevel;
+
+ // The number of spaces in front of the token or broken part of the token.
+ // This will be adapted when aligning tokens.
+ unsigned Spaces;
+
+ // \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
+ // \c EscapedNewlineColumn will be calculated in
+ // \c calculateLineBreakInformation.
+ bool IsTrailingComment;
+ unsigned TokenLength;
+ unsigned PreviousEndOfTokenColumn;
+ unsigned EscapedNewlineColumn;
+ };
+
+ /// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens
+ /// or token parts in a line and \c PreviousEndOfTokenColumn and
+ /// \c EscapedNewlineColumn for the first tokens or token parts in a line.
+ void calculateLineBreakInformation();
+
+ /// \brief Align trailing comments over all \c Changes.
+ void alignTrailingComments();
- void addUntouchableComment(unsigned Column);
+ /// \brief Align trailing comments from change \p Start to change \p End at
+ /// the specified \p Column.
+ void alignTrailingComments(unsigned Start, unsigned End, unsigned Column);
- /// \brief Try to align all stashed comments.
- void alignComments();
- /// \brief Try to align all stashed escaped newlines.
+ /// \brief Align escaped newlines over all \c Changes.
void alignEscapedNewlines();
-private:
- std::string getNewLineText(unsigned NewLines, unsigned Spaces);
-
- std::string getNewLineText(unsigned NewLines, unsigned Spaces,
- unsigned WhitespaceStartColumn,
- unsigned EscapedNewlineColumn);
-
- /// \brief Structure to store tokens for later layout and alignment.
- struct StoredToken {
- StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength,
- unsigned MinColumn, unsigned MaxColumn, unsigned NewLines,
- unsigned Spaces)
- : ReplacementLoc(ReplacementLoc), ReplacementLength(ReplacementLength),
- MinColumn(MinColumn), MaxColumn(MaxColumn), NewLines(NewLines),
- Spaces(Spaces), Untouchable(false) {}
- SourceLocation ReplacementLoc;
- unsigned ReplacementLength;
- unsigned MinColumn;
- unsigned MaxColumn;
- unsigned NewLines;
- unsigned Spaces;
- bool Untouchable;
- std::string Prefix;
- std::string Postfix;
- };
- SmallVector<StoredToken, 16> Comments;
- SmallVector<StoredToken, 16> EscapedNewlines;
- typedef SmallVector<StoredToken, 16>::iterator token_iterator;
+ /// \brief Align escaped newlines from change \p Start to change \p End at
+ /// the specified \p Column.
+ void alignEscapedNewlines(unsigned Start, unsigned End, unsigned Column);
- /// \brief Put all the comments between \p I and \p E into \p Column.
- void alignComments(token_iterator I, token_iterator E, unsigned Column);
+ /// \brief Fill \c Replaces with the replacements for all effective changes.
+ void generateChanges();
- /// \brief Stores \p Text as the replacement for the whitespace in front of
- /// \p Tok.
- void storeReplacement(SourceLocation Loc, unsigned Length,
- const std::string Text);
+ /// \brief Stores \p Text as the replacement for the whitespace in \p Range.
+ void storeReplacement(const SourceRange &Range, StringRef Text);
+ void appendNewlineText(std::string &Text, unsigned Newlines);
+ void appendNewlineText(std::string &Text, unsigned Newlines,
+ unsigned PreviousEndOfTokenColumn,
+ unsigned EscapedNewlineColumn);
+ void appendIndentText(std::string &Text, unsigned IndentLevel,
+ unsigned Spaces, unsigned WhitespaceStartColumn);
+ SmallVector<Change, 16> Changes;
SourceManager &SourceMgr;
tooling::Replacements Replaces;
const FormatStyle &Style;
+ bool UseCRLF;
};
} // namespace format
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 4a63d76a73e3..1ef4c1868112 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -37,20 +37,15 @@ namespace {
public:
ASTPrinter(raw_ostream *Out = NULL, bool Dump = false,
- StringRef FilterString = "")
+ StringRef FilterString = "", bool DumpLookups = false)
: Out(Out ? *Out : llvm::outs()), Dump(Dump),
- FilterString(FilterString) {}
+ FilterString(FilterString), DumpLookups(DumpLookups) {}
virtual void HandleTranslationUnit(ASTContext &Context) {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
- if (FilterString.empty()) {
- if (Dump)
- D->dump(Out);
- else
- D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
- return;
- }
+ if (FilterString.empty())
+ return print(D);
TraverseDecl(D);
}
@@ -65,10 +60,7 @@ namespace {
Out << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
if (ShowColors)
Out.resetColor();
- if (Dump)
- D->dump(Out);
- else
- D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ print(D);
Out << "\n";
// Don't traverse child nodes to avoid output duplication.
return true;
@@ -85,10 +77,22 @@ namespace {
bool filterMatches(Decl *D) {
return getName(D).find(FilterString) != std::string::npos;
}
+ void print(Decl *D) {
+ if (DumpLookups) {
+ if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ DC->dumpLookups(Out);
+ else
+ Out << "Not a DeclContext\n";
+ } else if (Dump)
+ D->dump(Out);
+ else
+ D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ }
raw_ostream &Out;
bool Dump;
std::string FilterString;
+ bool DumpLookups;
};
class ASTDeclNodeLister : public ASTConsumer,
@@ -119,8 +123,8 @@ ASTConsumer *clang::CreateASTPrinter(raw_ostream *Out,
return new ASTPrinter(Out, /*Dump=*/ false, FilterString);
}
-ASTConsumer *clang::CreateASTDumper(StringRef FilterString) {
- return new ASTPrinter(0, /*Dump=*/ true, FilterString);
+ASTConsumer *clang::CreateASTDumper(StringRef FilterString, bool DumpLookups) {
+ return new ASTPrinter(0, /*Dump=*/ true, FilterString, DumpLookups);
}
ASTConsumer *clang::CreateASTDeclNodeLister() {
@@ -476,23 +480,3 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
ASTConsumer *clang::CreateDeclContextPrinter() {
return new DeclContextPrinter();
}
-
-//===----------------------------------------------------------------------===//
-/// ASTDumperXML - In-depth XML dumping.
-
-namespace {
-class ASTDumpXML : public ASTConsumer {
- raw_ostream &OS;
-
-public:
- ASTDumpXML(raw_ostream &OS) : OS(OS) {}
-
- void HandleTranslationUnit(ASTContext &C) {
- C.getTranslationUnitDecl()->dumpXML(OS);
- }
-};
-}
-
-ASTConsumer *clang::CreateASTDumperXML(raw_ostream &OS) {
- return new ASTDumpXML(OS);
-}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 8bd5172454ca..a8c587638a28 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -29,6 +29,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/ArrayRef.h"
@@ -83,10 +84,10 @@ namespace {
/// \brief The file in which the precompiled preamble is stored.
std::string PreambleFile;
- /// \brief Temporary files that should be removed when the ASTUnit is
+ /// \brief Temporary files that should be removed when the ASTUnit is
/// destroyed.
- SmallVector<llvm::sys::Path, 4> TemporaryFiles;
-
+ SmallVector<std::string, 4> TemporaryFiles;
+
/// \brief Erase temporary files.
void CleanTemporaryFiles();
@@ -165,13 +166,13 @@ static const std::string &getPreambleFile(const ASTUnit *AU) {
void OnDiskData::CleanTemporaryFiles() {
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
- TemporaryFiles[I].eraseFromDisk();
- TemporaryFiles.clear();
+ llvm::sys::fs::remove(TemporaryFiles[I]);
+ TemporaryFiles.clear();
}
void OnDiskData::CleanPreambleFile() {
if (!PreambleFile.empty()) {
- llvm::sys::Path(PreambleFile).eraseFromDisk();
+ llvm::sys::fs::remove(PreambleFile);
PreambleFile.clear();
}
}
@@ -200,7 +201,7 @@ void ASTUnit::CleanTemporaryFiles() {
getOnDiskData(this).CleanTemporaryFiles();
}
-void ASTUnit::addTemporaryFile(const llvm::sys::Path &TempFile) {
+void ASTUnit::addTemporaryFile(StringRef TempFile) {
getOnDiskData(this).TemporaryFiles.push_back(TempFile);
}
@@ -216,7 +217,8 @@ const unsigned DefaultPreambleRebuildInterval = 5;
static llvm::sys::cas_flag ActiveASTUnitObjects;
ASTUnit::ASTUnit(bool _MainFileIsAST)
- : Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false),
+ : Reader(0), HadModuleLoaderFatalFailure(false),
+ OnlyLocalDecls(false), CaptureDiagnostics(false),
MainFileIsAST(_MainFileIsAST),
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
@@ -509,23 +511,19 @@ class ASTInfoCollector : public ASTReaderListener {
Preprocessor &PP;
ASTContext &Context;
LangOptions &LangOpt;
- HeaderSearch &HSI;
IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
unsigned &Counter;
- unsigned NumHeaderInfos;
-
bool InitializedLanguage;
public:
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
- HeaderSearch &HSI,
IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target,
unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI),
+ : PP(PP), Context(Context), LangOpt(LangOpt),
TargetOpts(TargetOpts), Target(Target),
- Counter(Counter), NumHeaderInfos(0),
+ Counter(Counter),
InitializedLanguage(false) {}
virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
@@ -554,10 +552,6 @@ public:
return false;
}
- virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
- HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
- }
-
virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {
Counter = Value;
}
@@ -646,6 +640,12 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
StoredDiags.push_back(StoredDiagnostic(Level, Info));
}
+ASTMutationListener *ASTUnit::getASTMutationListener() {
+ if (WriterData)
+ return &WriterData->Writer;
+ return 0;
+}
+
ASTDeserializationListener *ASTUnit::getDeserializationListener() {
if (WriterData)
return &WriterData->Writer;
@@ -707,7 +707,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->HSOpts = new HeaderSearchOptions();
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
- AST->getFileManager(),
+ AST->getSourceManager(),
AST->getDiagnostics(),
AST->ASTFileLangOpts,
/*Target=*/0));
@@ -798,7 +798,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
ReaderCleanup(Reader.get());
Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
- AST->ASTFileLangOpts, HeaderInfo,
+ AST->ASTFileLangOpts,
AST->TargetOpts, AST->Target,
Counter));
@@ -877,6 +877,18 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
return;
if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (EnumDecl *EnumD = dyn_cast<EnumDecl>(D)) {
+ // For an unscoped enum include the enumerators in the hash since they
+ // enter the top-level namespace.
+ if (!EnumD->isScoped()) {
+ for (EnumDecl::enumerator_iterator EI = EnumD->enumerator_begin(),
+ EE = EnumD->enumerator_end(); EI != EE; ++EI) {
+ if ((*EI)->getIdentifier())
+ Hash = llvm::HashString((*EI)->getIdentifier()->getName(), Hash);
+ }
+ }
+ }
+
if (ND->getIdentifier())
Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash);
else if (DeclarationName Name = ND->getDeclName()) {
@@ -884,7 +896,15 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
Hash = llvm::HashString(NameStr, Hash);
}
return;
- }
+ }
+
+ if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D)) {
+ if (Module *Mod = ImportD->getImportedModule()) {
+ std::string ModName = Mod->getFullModuleName();
+ Hash = llvm::HashString(ModName, Hash);
+ }
+ return;
+ }
}
class TopLevelDeclTrackerConsumer : public ASTConsumer {
@@ -937,6 +957,10 @@ public:
handleTopLevelDecl(*it);
}
+ virtual ASTMutationListener *GetASTMutationListener() {
+ return Unit.getASTMutationListener();
+ }
+
virtual ASTDeserializationListener *GetASTDeserializationListener() {
return Unit.getDeserializationListener();
}
@@ -963,16 +987,37 @@ public:
}
};
+class PrecompilePreambleAction : public ASTFrontendAction {
+ ASTUnit &Unit;
+ bool HasEmittedPreamblePCH;
+
+public:
+ explicit PrecompilePreambleAction(ASTUnit &Unit)
+ : Unit(Unit), HasEmittedPreamblePCH(false) {}
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile);
+ bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
+ void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
+ virtual bool shouldEraseOutputFiles() { return !hasEmittedPreamblePCH(); }
+
+ virtual bool hasCodeCompletionSupport() const { return false; }
+ virtual bool hasASTFileSupport() const { return false; }
+ virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
+};
+
class PrecompilePreambleConsumer : public PCHGenerator {
ASTUnit &Unit;
- unsigned &Hash;
+ unsigned &Hash;
std::vector<Decl *> TopLevelDecls;
-
+ PrecompilePreambleAction *Action;
+
public:
- PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP,
- StringRef isysroot, raw_ostream *Out)
- : PCHGenerator(PP, "", 0, isysroot, Out), Unit(Unit),
- Hash(Unit.getCurrentTopLevelHashValue()) {
+ PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action,
+ const Preprocessor &PP, StringRef isysroot,
+ raw_ostream *Out)
+ : PCHGenerator(PP, "", 0, isysroot, Out, /*AllowASTWithErrors=*/true),
+ Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action) {
Hash = 0;
}
@@ -993,48 +1038,42 @@ public:
virtual void HandleTranslationUnit(ASTContext &Ctx) {
PCHGenerator::HandleTranslationUnit(Ctx);
- if (!Unit.getDiagnostics().hasErrorOccurred()) {
+ if (hasEmittedPCH()) {
// 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 (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I)
- Unit.addTopLevelDeclFromPreamble(
- getWriter().getDeclID(TopLevelDecls[I]));
+ for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I) {
+ Decl *D = TopLevelDecls[I];
+ // Invalid top-level decls may not have been serialized.
+ if (D->isInvalidDecl())
+ continue;
+ Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D));
+ }
+
+ Action->setHasEmittedPreamblePCH();
}
}
};
-class PrecompilePreambleAction : public ASTFrontendAction {
- ASTUnit &Unit;
-
-public:
- explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {}
-
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- std::string Sysroot;
- std::string OutputFile;
- raw_ostream *OS = 0;
- if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
- OutputFile,
- OS))
- return 0;
-
- if (!CI.getFrontendOpts().RelocatablePCH)
- Sysroot.clear();
+}
- CI.getPreprocessor().addPPCallbacks(
- new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
- return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot,
- OS);
- }
+ASTConsumer *PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ std::string Sysroot;
+ std::string OutputFile;
+ raw_ostream *OS = 0;
+ if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile, OS))
+ return 0;
- virtual bool hasCodeCompletionSupport() const { return false; }
- virtual bool hasASTFileSupport() const { return false; }
- virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
-};
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+ CI.getPreprocessor().addPPCallbacks(new MacroDefinitionTrackerPPCallbacks(
+ Unit.getCurrentTopLevelHashValue()));
+ return new PrecompilePreambleConsumer(Unit, this, CI.getPreprocessor(),
+ Sysroot, OS);
}
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
@@ -1214,36 +1253,17 @@ error:
/// \brief Simple function to retrieve a path for a preamble precompiled header.
static std::string GetPreamblePCHPath() {
- // FIXME: This is lame; sys::Path should provide this function (in particular,
- // it should know how to find the temporary files dir).
- // FIXME: This is really lame. I copied this code from the Driver!
// 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.
+ // are not necessarily cleaned up.
const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
if (TmpFile)
return TmpFile;
-
- std::string Error;
- const char *TmpDir = ::getenv("TMPDIR");
- if (!TmpDir)
- TmpDir = ::getenv("TEMP");
- if (!TmpDir)
- TmpDir = ::getenv("TMP");
-#ifdef LLVM_ON_WIN32
- if (!TmpDir)
- TmpDir = ::getenv("USERPROFILE");
-#endif
- if (!TmpDir)
- TmpDir = "/tmp";
- llvm::sys::Path P(TmpDir);
- P.createDirectoryOnDisk(true);
- P.appendComponent("preamble");
- P.appendSuffix("pch");
- if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0))
- return std::string();
-
- return P.str();
+
+ 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
@@ -1260,17 +1280,19 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// command line (to another file) or directly through the compiler invocation
// (to a memory buffer).
llvm::MemoryBuffer *Buffer = 0;
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
- if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
+ 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 (PreprocessorOptions::remapped_file_iterator
M = PreprocessorOpts.remapped_file_begin(),
E = PreprocessorOpts.remapped_file_end();
M != E;
++M) {
- llvm::sys::PathWithStatus MPath(M->first);
- if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
- if (MainFileStatus->uniqueID == MStatus->uniqueID) {
+ std::string MPath(M->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.
if (CreatedBuffer) {
delete Buffer;
@@ -1293,10 +1315,11 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
E = PreprocessorOpts.remapped_file_buffer_end();
M != E;
++M) {
- llvm::sys::PathWithStatus MPath(M->first);
- if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
- if (MainFileStatus->uniqueID == MStatus->uniqueID) {
- // We found a remapping.
+ std::string MPath(M->first);
+ llvm::sys::fs::UniqueID MID;
+ if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
+ if (MainFileID == MID) {
+ // We found a remapping.
if (CreatedBuffer) {
delete Buffer;
CreatedBuffer = false;
@@ -1411,16 +1434,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
REnd = PreprocessorOpts.remapped_file_end();
!AnyFileChanged && R != REnd;
++R) {
- struct stat StatBuf;
- if (FileMgr->getNoncachedStatValue(R->second, StatBuf)) {
+ llvm::sys::fs::file_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[R->first] = std::make_pair(StatBuf.st_size,
- StatBuf.st_mtime);
+
+ OverriddenFiles[R->first] = std::make_pair(
+ Status.getSize(), Status.getLastModificationTime().toEpochTime());
}
for (PreprocessorOptions::remapped_file_buffer_iterator
R = PreprocessorOpts.remapped_file_buffer_begin(),
@@ -1449,12 +1472,13 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
}
// The file was not remapped; check whether it has changed on disk.
- struct stat StatBuf;
- if (FileMgr->getNoncachedStatValue(F->first(), StatBuf)) {
+ llvm::sys::fs::file_status Status;
+ if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
// If we can't stat the file, assume that something horrible happened.
AnyFileChanged = true;
- } else if (StatBuf.st_size != F->second.first ||
- StatBuf.st_mtime != F->second.second)
+ } else if (Status.getSize() != uint64_t(F->second.first) ||
+ Status.getLastModificationTime().toEpochTime() !=
+ uint64_t(F->second.second))
AnyFileChanged = true;
}
@@ -1541,11 +1565,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
' ', PreambleReservedSize - Preamble.size() - 1);
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
-
+
// Remap the main source file to the preamble buffer.
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
- PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
-
+ StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
+ PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer);
+
// Tell the compiler invocation to generate a temporary precompiled header.
FrontendOpts.ProgramAction = frontend::GeneratePCH;
// FIXME: Generate the precompiled header into memory?
@@ -1570,7 +1594,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
&Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
- llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
+ llvm::sys::fs::remove(FrontendOpts.OutputFile);
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
@@ -1608,7 +1632,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
OwningPtr<PrecompilePreambleAction> Act;
Act.reset(new PrecompilePreambleAction(*this));
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
+ llvm::sys::fs::remove(FrontendOpts.OutputFile);
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
@@ -1619,11 +1643,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Act->Execute();
Act->EndSourceFile();
- if (Diagnostics->hasErrorOccurred()) {
- // There were errors parsing the preamble, so no precompiled header was
- // generated. Forget that we even tried.
+ 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::Path(FrontendOpts.OutputFile).eraseFromDisk();
+ llvm::sys::fs::remove(FrontendOpts.OutputFile);
Preamble.clear();
TopLevelDeclsInPreamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
@@ -1703,6 +1727,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
CI.setFileManager(0);
Target = &CI.getTarget();
Reader = CI.getModuleManager();
+ HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
}
StringRef ASTUnit::getMainFileName() const {
@@ -2403,10 +2428,10 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Set up diagnostics, capturing any diagnostics produced.
Clang->setDiagnostics(&Diag);
- ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts());
CaptureDroppedDiagnostics Capture(true,
Clang->getDiagnostics(),
StoredDiagnostics);
+ ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts());
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
@@ -2461,16 +2486,19 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// preamble.
llvm::MemoryBuffer *OverrideMainBuffer = 0;
if (!getPreambleFile(this).empty()) {
- using llvm::sys::FileStatus;
- llvm::sys::PathWithStatus CompleteFilePath(File);
- llvm::sys::PathWithStatus MainPath(OriginalSourceFile);
- if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus())
- if (const FileStatus *MainStatus = MainPath.getFileStatus())
- if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() &&
- Line > 1)
+ std::string CompleteFilePath(File);
+ llvm::sys::fs::UniqueID CompleteFileID;
+
+ if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) {
+ std::string MainPath(OriginalSourceFile);
+ llvm::sys::fs::UniqueID MainID;
+ if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
+ if (CompleteFileID == MainID && Line > 1)
OverrideMainBuffer
= getMainBufferWithPrecompiledPreamble(*CCInvocation, false,
Line - 1);
+ }
+ }
}
// If the main file has been overridden due to the use of a preamble,
@@ -2502,14 +2530,16 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
}
bool ASTUnit::Save(StringRef File) {
+ if (HadModuleLoaderFatalFailure)
+ return true;
+
// Write to a temporary file and later rename it to the actual file, to avoid
// possible race conditions.
SmallString<128> TempPath;
TempPath = File;
TempPath += "-%%%%%%%%";
int fd;
- if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
- /*makeAbsolute=*/false))
+ if (llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath))
return true;
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
@@ -2627,11 +2657,6 @@ void ASTUnit::TranslateStoredDiagnostics(
Result.swap(Out);
}
-static inline bool compLocDecl(std::pair<unsigned, Decl *> L,
- std::pair<unsigned, Decl *> R) {
- return L.first < R.first;
-}
-
void ASTUnit::addFileLevelDecl(Decl *D) {
assert(D);
@@ -2667,8 +2692,8 @@ void ASTUnit::addFileLevelDecl(Decl *D) {
return;
}
- LocDeclsTy::iterator
- I = std::upper_bound(Decls->begin(), Decls->end(), LocDecl, compLocDecl);
+ LocDeclsTy::iterator I = std::upper_bound(Decls->begin(), Decls->end(),
+ LocDecl, llvm::less_first());
Decls->insert(I, LocDecl);
}
@@ -2692,9 +2717,9 @@ void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
if (LocDecls.empty())
return;
- LocDeclsTy::iterator
- BeginIt = std::lower_bound(LocDecls.begin(), LocDecls.end(),
- std::make_pair(Offset, (Decl*)0), compLocDecl);
+ LocDeclsTy::iterator BeginIt =
+ std::lower_bound(LocDecls.begin(), LocDecls.end(),
+ std::make_pair(Offset, (Decl *)0), llvm::less_first());
if (BeginIt != LocDecls.begin())
--BeginIt;
@@ -2705,10 +2730,9 @@ void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
BeginIt->second->isTopLevelDeclInObjCContainer())
--BeginIt;
- LocDeclsTy::iterator
- EndIt = std::upper_bound(LocDecls.begin(), LocDecls.end(),
- std::make_pair(Offset+Length, (Decl*)0),
- compLocDecl);
+ LocDeclsTy::iterator EndIt = std::upper_bound(
+ LocDecls.begin(), LocDecls.end(),
+ std::make_pair(Offset + Length, (Decl *)0), llvm::less_first());
if (EndIt != LocDecls.end())
++EndIt;
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 3f80a16b403a..0c30b049579d 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -58,16 +58,16 @@ public:
class PTHEntryKeyVariant {
union { const FileEntry* FE; const char* Path; };
enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
- struct stat *StatBuf;
+ FileData *Data;
+
public:
- PTHEntryKeyVariant(const FileEntry *fe)
- : FE(fe), Kind(IsFE), StatBuf(0) {}
+ PTHEntryKeyVariant(const FileEntry *fe) : FE(fe), Kind(IsFE), Data(0) {}
- PTHEntryKeyVariant(struct stat* statbuf, const char* path)
- : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {}
+ PTHEntryKeyVariant(FileData *Data, const char *path)
+ : Path(path), Kind(IsDE), Data(new FileData(*Data)) {}
- explicit PTHEntryKeyVariant(const char* path)
- : Path(path), Kind(IsNoExist), StatBuf(0) {}
+ explicit PTHEntryKeyVariant(const char *path)
+ : Path(path), Kind(IsNoExist), Data(0) {}
bool isFile() const { return Kind == IsFE; }
@@ -79,22 +79,21 @@ public:
void EmitData(raw_ostream& Out) {
switch (Kind) {
- case IsFE:
+ case IsFE: {
// Emit stat information.
- ::Emit32(Out, FE->getInode());
- ::Emit32(Out, FE->getDevice());
- ::Emit16(Out, FE->getFileMode());
+ llvm::sys::fs::UniqueID UID = FE->getUniqueID();
+ ::Emit64(Out, UID.getFile());
+ ::Emit64(Out, UID.getDevice());
::Emit64(Out, FE->getModificationTime());
::Emit64(Out, FE->getSize());
- break;
+ } break;
case IsDE:
// Emit stat information.
- ::Emit32(Out, (uint32_t) StatBuf->st_ino);
- ::Emit32(Out, (uint32_t) StatBuf->st_dev);
- ::Emit16(Out, (uint16_t) StatBuf->st_mode);
- ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
- ::Emit64(Out, (uint64_t) StatBuf->st_size);
- delete StatBuf;
+ ::Emit64(Out, Data->UniqueID.getFile());
+ ::Emit64(Out, Data->UniqueID.getDevice());
+ ::Emit64(Out, Data->ModTime);
+ ::Emit64(Out, Data->Size);
+ delete Data;
break;
default:
break;
@@ -516,18 +515,18 @@ public:
StatListener(PTHMap &pm) : PM(pm) {}
~StatListener() {}
- LookupResult getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
+ LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
+ LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
if (Result == CacheMissing) // Failed 'stat'.
PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
- else if (S_ISDIR(StatBuf.st_mode)) {
+ else if (Data.IsDirectory) {
// Only cache directories with absolute paths.
if (llvm::sys::path::is_relative(Path))
return Result;
- PM.insert(PTHEntryKeyVariant(&StatBuf, Path), PTHEntry());
+ PM.insert(PTHEntryKeyVariant(&Data, Path), PTHEntry());
}
return Result;
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index cde84caade5d..442177ec3197 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -26,9 +26,9 @@
using namespace clang;
static ASTReader *createASTReader(CompilerInstance &CI,
- StringRef pchFile,
- SmallVector<llvm::MemoryBuffer *, 4> &memBufs,
- SmallVector<std::string, 4> &bufNames,
+ StringRef pchFile,
+ SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
+ SmallVectorImpl<std::string> &bufNames,
ASTDeserializationListener *deserialListener = 0) {
Preprocessor &PP = CI.getPreprocessor();
OwningPtr<ASTReader> Reader;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index cf856fc2ab65..eccb94cc4a4f 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -111,8 +111,8 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
llvm::raw_fd_ostream *FileOS(
- new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(),
- ErrorInfo, llvm::raw_fd_ostream::F_Append));
+ new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo,
+ llvm::sys::fs::F_Append));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
<< DiagOpts->DiagnosticLogFile << ErrorInfo;
@@ -138,8 +138,8 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
std::string ErrorInfo;
OwningPtr<llvm::raw_fd_ostream> OS;
OS.reset(new llvm::raw_fd_ostream(OutputFile.str().c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary));
-
+ llvm::sys::fs::F_Binary));
+
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_serialized_diag_failure)
<< OutputFile << ErrorInfo;
@@ -218,7 +218,7 @@ void CompilerInstance::createPreprocessor() {
// Create the Preprocessor.
HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(),
- getFileManager(),
+ getSourceManager(),
getDiagnostics(),
getLangOpts(),
&getTarget());
@@ -259,7 +259,7 @@ void CompilerInstance::createPreprocessor() {
AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
getHeaderSearchOpts().Sysroot);
-
+
// Handle generating header include information, if requested.
if (DepOpts.ShowHeaderIncludes)
AttachHeaderIncludeGen(*PP);
@@ -270,6 +270,11 @@ void CompilerInstance::createPreprocessor() {
AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
/*ShowDepth=*/false);
}
+
+ if (DepOpts.PrintShowIncludes) {
+ AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/false, /*OutputPath=*/"",
+ /*ShowDepth=*/true, /*MSStyle=*/true);
+ }
}
// ASTContext
@@ -384,7 +389,7 @@ void CompilerInstance::createCodeCompletionConsumer() {
}
if (CompletionConsumer->isOutputBinary() &&
- llvm::sys::Program::ChangeStdoutToBinary()) {
+ llvm::sys::ChangeStdoutToBinary()) {
getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
setCodeCompletionConsumer(0);
}
@@ -445,7 +450,7 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
}
}
} else if (!it->Filename.empty() && EraseFiles)
- llvm::sys::Path(it->Filename).eraseFromDisk();
+ llvm::sys::fs::remove(it->Filename);
}
OutputFiles.clear();
@@ -509,9 +514,8 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
} else if (InFile == "-") {
OutFile = "-";
} else if (!Extension.empty()) {
- llvm::sys::Path Path(InFile);
- Path.eraseSuffix();
- Path.appendSuffix(Extension);
+ SmallString<128> Path(InFile);
+ llvm::sys::path::replace_extension(Path, Extension);
OutFile = Path.str();
} else {
OutFile = "-";
@@ -520,47 +524,64 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
OwningPtr<llvm::raw_fd_ostream> OS;
std::string OSFile;
- if (UseTemporary && OutFile != "-") {
- // Only create the temporary if the parent directory exists (or create
- // missing directories is true) and we can actually write to OutPath,
- // otherwise we want to fail early.
- SmallString<256> AbsPath(OutputPath);
- llvm::sys::fs::make_absolute(AbsPath);
- llvm::sys::Path OutPath(AbsPath);
- bool ParentExists = false;
- if (llvm::sys::fs::exists(llvm::sys::path::parent_path(AbsPath.str()),
- ParentExists))
- ParentExists = false;
- bool Exists;
- if ((CreateMissingDirectories || ParentExists) &&
- ((llvm::sys::fs::exists(AbsPath.str(), Exists) || !Exists) ||
- (OutPath.isRegularFile() && OutPath.canWrite()))) {
- // Create a temporary file.
- SmallString<128> TempPath;
- TempPath = OutFile;
- TempPath += "-%%%%%%%%";
- int fd;
- if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
- /*makeAbsolute=*/false, 0664)
- == llvm::errc::success) {
- OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
- OSFile = TempFile = TempPath.str();
+ if (UseTemporary) {
+ if (OutFile == "-")
+ UseTemporary = false;
+ else {
+ llvm::sys::fs::file_status Status;
+ llvm::sys::fs::status(OutputPath, Status);
+ if (llvm::sys::fs::exists(Status)) {
+ // Fail early if we can't write to the final destination.
+ if (!llvm::sys::fs::can_write(OutputPath))
+ return 0;
+
+ // Don't use a temporary if the output is a special file. This handles
+ // things like '-o /dev/null'
+ if (!llvm::sys::fs::is_regular_file(Status))
+ UseTemporary = false;
}
}
}
+ if (UseTemporary) {
+ // Create a temporary file.
+ SmallString<128> TempPath;
+ TempPath = OutFile;
+ TempPath += "-%%%%%%%%";
+ int fd;
+ llvm::error_code EC =
+ llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath);
+
+ if (CreateMissingDirectories &&
+ EC == llvm::errc::no_such_file_or_directory) {
+ StringRef Parent = llvm::sys::path::parent_path(OutputPath);
+ EC = llvm::sys::fs::create_directories(Parent);
+ if (!EC) {
+ EC = llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath);
+ }
+ }
+
+ if (!EC) {
+ OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
+ OSFile = TempFile = TempPath.str();
+ }
+ // If we failed to create the temporary, fallback to writing to the file
+ // directly. This handles the corner case where we cannot write to the
+ // directory, but can write to the file.
+ }
+
if (!OS) {
OSFile = OutFile;
- OS.reset(
- new llvm::raw_fd_ostream(OSFile.c_str(), Error,
- (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
+ OS.reset(new llvm::raw_fd_ostream(
+ OSFile.c_str(), Error,
+ (Binary ? llvm::sys::fs::F_Binary : llvm::sys::fs::F_None)));
if (!Error.empty())
return 0;
}
// Make sure the out stream file gets removed if we crash.
if (RemoveFileOnSignal)
- llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile));
+ llvm::sys::RemoveFileOnSignal(OSFile);
if (ResultPathName)
*ResultPathName = OutFile;
@@ -597,7 +618,7 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
// Figure out where to get and map in the main file.
if (InputFile != "-") {
- const FileEntry *File = FileMgr.getFile(InputFile);
+ const FileEntry *File = FileMgr.getFile(InputFile, /*OpenFile=*/true);
if (!File) {
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
@@ -605,26 +626,27 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
// The natural SourceManager infrastructure can't currently handle named
// pipes, but we would at least like to accept them for the main
- // file. Detect them here, read them with the more generic MemoryBuffer
- // function, and simply override their contents as we do for STDIN.
+ // file. Detect them here, read them with the volatile flag so FileMgr will
+ // pick up the correct size, and simply override their contents as we do for
+ // STDIN.
if (File->isNamedPipe()) {
- OwningPtr<llvm::MemoryBuffer> MB;
- if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) {
- Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message();
+ std::string ErrorStr;
+ if (llvm::MemoryBuffer *MB =
+ FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true)) {
+ // Create a new virtual file that will have the correct size.
+ File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(File, MB);
+ } else {
+ Diags.Report(diag::err_cannot_open_file) << InputFile << ErrorStr;
return false;
}
-
- // Create a new virtual file that will have the correct size.
- File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0);
- SourceMgr.overrideFileContents(File, MB.take());
}
SourceMgr.createMainFileID(File, Kind);
} else {
OwningPtr<llvm::MemoryBuffer> SB;
- if (llvm::MemoryBuffer::getSTDIN(SB)) {
- // FIXME: Give ec.message() in this diag.
- Diags.Report(diag::err_fe_error_reading_stdin);
+ if (llvm::error_code ec = llvm::MemoryBuffer::getSTDIN(SB)) {
+ Diags.Report(diag::err_fe_error_reading_stdin) << ec.message();
return false;
}
const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
@@ -764,6 +786,11 @@ static void compileModule(CompilerInstance &ImportingInstance,
SourceLocation ImportLoc,
Module *Module,
StringRef ModuleFileName) {
+ // FIXME: have LockFileManager return an error_code so that we can
+ // avoid the mkdir when the directory already exists.
+ StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
+ llvm::sys::fs::create_directories(Dir);
+
llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
case llvm::LockFileManager::LFS_Error:
@@ -824,33 +851,6 @@ static void compileModule(CompilerInstance &ImportingInstance,
FrontendOpts.Inputs.clear();
InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
- // Get or create the module map that we'll use to build this module.
- SmallString<128> TempModuleMapFileName;
- if (const FileEntry *ModuleMapFile
- = ModMap.getContainingModuleMapFile(Module)) {
- // Use the module map where this module resides.
- FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(),
- IK));
- } else {
- // Create a temporary module map file.
- TempModuleMapFileName = Module->Name;
- TempModuleMapFileName += "-%%%%%%%%.map";
- int FD;
- if (llvm::sys::fs::unique_file(TempModuleMapFileName.str(), FD,
- TempModuleMapFileName,
- /*makeAbsolute=*/true)
- != llvm::errc::success) {
- ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file)
- << TempModuleMapFileName;
- return;
- }
- // Print the module map to this file.
- llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
- Module->print(OS);
- FrontendOpts.Inputs.push_back(
- FrontendInputFile(TempModuleMapFileName.str().str(), IK));
- }
-
// Don't free the remapped file buffers; they are owned by our caller.
PPOpts.RetainRemappedFileBuffers = true;
@@ -877,9 +877,29 @@ static void compileModule(CompilerInstance &ImportingInstance,
SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
+ // 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.push_back(
+ FrontendInputFile(ModuleMapFile->getName(), IK));
+ } else {
+ llvm::raw_string_ostream OS(InferredModuleMapContent);
+ Module->print(OS);
+ OS.flush();
+ FrontendOpts.Inputs.push_back(
+ FrontendInputFile("__inferred_module.map", IK));
+
+ const llvm::MemoryBuffer *ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ "__inferred_module.map", InferredModuleMapContent.size(), 0);
+ SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer);
+ }
// Construct a module-generating action.
- GenerateModuleAction CreateModuleAction;
+ GenerateModuleAction CreateModuleAction(Module->IsSystem);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
@@ -894,8 +914,6 @@ static void compileModule(CompilerInstance &ImportingInstance,
// be nice to do this with RemoveFileOnSignal when we can. However, that
// doesn't make sense for all clients, so clean this up manually.
Instance.clearOutputFiles(/*EraseFiles=*/true);
- if (!TempModuleMapFileName.empty())
- llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
// 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.
@@ -994,7 +1012,7 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
static void writeTimestampFile(StringRef TimestampFile) {
std::string ErrorInfo;
llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary);
+ llvm::sys::fs::F_Binary);
}
/// \brief Prune the module cache of modules that haven't been accessed in
@@ -1035,8 +1053,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
Dir(ModuleCachePathNative.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
// If we don't have a directory, there's nothing to look into.
- bool IsDirectory;
- if (llvm::sys::fs::is_directory(Dir->path(), IsDirectory) || !IsDirectory)
+ if (!llvm::sys::fs::is_directory(Dir->path()))
continue;
// Walk all of the files within this directory.
@@ -1086,23 +1103,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) {
+ // Determine what file we're searching from.
+ StringRef ModuleName = Path[0].first->getName();
+ SourceLocation ModuleNameLoc = Path[0].second;
+
// If we've already handled this import, just return the cached result.
// This one-element cache is important to eliminate redundant diagnostics
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
- if (LastModuleImportResult)
+ if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule)
ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
}
-
- // Determine what file we're searching from.
- StringRef ModuleName = Path[0].first->getName();
- SourceLocation ModuleNameLoc = Path[0].second;
clang::Module *Module = 0;
-
+
// If we don't already have information on this module, load the module now.
llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known
= KnownModules.find(Path[0].first);
@@ -1164,15 +1181,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::Success:
break;
- case ASTReader::OutOfDate: {
- // The module file is out-of-date. Remove it, then rebuild it.
- bool Existed;
- llvm::sys::fs::remove(ModuleFileName, Existed);
- }
- // Fall through to build the module again.
-
+ case ASTReader::OutOfDate:
case ASTReader::Missing: {
- // The module file is (now) missing. Build it.
+ // The module file is missing or out-of-date. Build it.
// If we don't have a module, we don't know how to build the module file.
// Complain and return.
@@ -1247,12 +1258,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
case ASTReader::HadErrors:
+ ModuleLoader::HadFatalFailure = true;
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = 0;
return ModuleLoadResult();
case ASTReader::Failure:
+ ModuleLoader::HadFatalFailure = true;
// Already complained, but note now that we failed.
KnownModules[Path[0].first] = 0;
ModuleBuildFailed = true;
@@ -1346,11 +1359,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Check whether this module is available.
- StringRef Feature;
- if (!Module->isAvailable(getLangOpts(), getTarget(), Feature)) {
+ clang::Module::Requirement Requirement;
+ if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement)) {
getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
<< Module->getFullModuleName()
- << Feature
+ << Requirement.second << Requirement.first
<< SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 42ea96f0f2ad..8db5cf1bc21a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -11,13 +11,11 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/Util.h"
#include "clang/Frontend/LangStandard.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
@@ -26,10 +24,17 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/system_error.h"
+#include <sys/stat.h>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -56,6 +61,7 @@ CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
using namespace clang::driver;
using namespace clang::driver::options;
+using namespace llvm::opt;
//
@@ -78,7 +84,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
if (S == "s" || S == "z" || S.empty())
return 2;
- return Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags);
+ return getLastArgIntValue(Args, OPT_O, DefaultOpt, Diags);
}
return DefaultOpt;
@@ -162,7 +168,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
StringRef Name = A->getValue();
AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, PD_##NAME)
#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
@@ -221,11 +227,12 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
- Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
+ Opts.maxBlockVisitOnPath =
+ getLastArgIntValue(Args, OPT_analyzer_max_loop, 4, Diags);
Opts.PrintStats = Args.hasArg(OPT_analyzer_stats);
Opts.InlineMaxStackDepth =
- Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth,
- Opts.InlineMaxStackDepth, Diags);
+ getLastArgIntValue(Args, OPT_analyzer_inline_max_stack_depth,
+ Opts.InlineMaxStackDepth, Diags);
Opts.CheckersControlList.clear();
for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
@@ -292,14 +299,15 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
using namespace options;
bool Success = true;
- unsigned OptLevel = getOptimizationLevel(Args, IK, Diags);
- if (OptLevel > 3) {
- Diags.Report(diag::err_drv_invalid_value)
- << Args.getLastArg(OPT_O)->getAsString(Args) << OptLevel;
- OptLevel = 3;
- Success = false;
+ Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
+ // TODO: This could be done in Driver
+ unsigned MaxOptLevel = 3;
+ if (Opts.OptimizationLevel > MaxOptLevel) {
+ // If the optimization level is not supported, fall back on the default optimization
+ Diags.Report(diag::warn_drv_optimization_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << "-O" << MaxOptLevel;
+ Opts.OptimizationLevel = MaxOptLevel;
}
- Opts.OptimizationLevel = OptLevel;
// We must always run at least the always inlining pass.
Opts.setInlining(
@@ -312,7 +320,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_gline_tables_only)) {
Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
- } else if (Args.hasArg(OPT_g_Flag)) {
+ } else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) ||
+ Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) {
if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true))
Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
else
@@ -320,6 +329,15 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
+ if (Args.hasArg(OPT_gdwarf_2))
+ Opts.DwarfVersion = 2;
+ else if (Args.hasArg(OPT_gdwarf_3))
+ Opts.DwarfVersion = 3;
+ else if (Args.hasArg(OPT_gdwarf_4))
+ Opts.DwarfVersion = 4;
+ else if (Opts.getDebugInfo() != CodeGenOptions::NoDebugInfo)
+ // Default Dwarf version is 4 if we are generating debug information.
+ Opts.DwarfVersion = 4;
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
@@ -327,7 +345,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
- Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa);
+ Opts.StructPathTBAA = !Args.hasArg(OPT_no_struct_path_tbaa);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
@@ -335,10 +353,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.OptimizeSize = getOptimizationLevelSize(Args);
Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
Args.hasArg(OPT_ffreestanding));
- Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) ||
- (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
+ Opts.UnrollLoops =
+ Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
+ (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize));
+ Opts.RerollLoops = Args.hasArg(OPT_freroll_loops);
Opts.Autolink = !Args.hasArg(OPT_fno_autolink);
+ Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);
@@ -347,6 +368,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
+ Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables);
@@ -360,7 +382,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
- Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
+ Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags);
Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
@@ -379,8 +401,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array);
- Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
- Opts.DataSections = Args.hasArg(OPT_fdata_sections);
+ Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections,
+ OPT_fno_function_sections, false);
+ Opts.DataSections = Args.hasFlag(OPT_fdata_sections,
+ OPT_fno_data_sections, false);
+
+ Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive);
+ Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops);
+ Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp);
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
@@ -419,7 +447,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeUndefinedTrapOnError =
Args.hasArg(OPT_fsanitize_undefined_trap_on_error);
Opts.SSPBufferSize =
- Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags);
+ getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) {
StringRef Val = A->getValue();
@@ -472,6 +500,17 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
}
+ if (Arg *A = Args.getLastArg(OPT_fpcc_struct_return, OPT_freg_struct_return)) {
+ if (A->getOption().matches(OPT_fpcc_struct_return)) {
+ Opts.setStructReturnConvention(CodeGenOptions::SRCK_OnStack);
+ } else {
+ assert(A->getOption().matches(OPT_freg_struct_return));
+ Opts.setStructReturnConvention(CodeGenOptions::SRCK_InRegs);
+ }
+ }
+
+ Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
+
return Success;
}
@@ -485,6 +524,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file);
Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG);
+ Opts.PrintShowIncludes = Args.hasArg(OPT_show_includes);
Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot);
}
@@ -509,6 +549,8 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
+ llvm::sys::Process::UseANSIEscapeCodes(Args.hasArg(OPT_fansi_escape_codes));
+
// Default behavior is to not to show note include stacks.
Opts.ShowNoteIncludeStack = false;
if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack,
@@ -552,7 +594,10 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.setFormat(DiagnosticOptions::Clang);
else if (Format == "msvc")
Opts.setFormat(DiagnosticOptions::Msvc);
- else if (Format == "vi")
+ else if (Format == "msvc-fallback") {
+ Opts.setFormat(DiagnosticOptions::Msvc);
+ Opts.CLFallbackMode = true;
+ } else if (Format == "vi")
Opts.setFormat(DiagnosticOptions::Vi);
else {
Success = false;
@@ -568,19 +613,17 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.ElideType = !Args.hasArg(OPT_fno_elide_type);
Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree);
- Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
- Opts.MacroBacktraceLimit
- = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
+ Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
+ Opts.MacroBacktraceLimit =
+ getLastArgIntValue(Args, OPT_fmacro_backtrace_limit,
DiagnosticOptions::DefaultMacroBacktraceLimit, Diags);
- Opts.TemplateBacktraceLimit
- = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
- DiagnosticOptions::DefaultTemplateBacktraceLimit,
- Diags);
- Opts.ConstexprBacktraceLimit
- = Args.getLastArgIntValue(OPT_fconstexpr_backtrace_limit,
- DiagnosticOptions::DefaultConstexprBacktraceLimit,
- Diags);
- Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop,
+ Opts.TemplateBacktraceLimit = getLastArgIntValue(
+ Args, OPT_ftemplate_backtrace_limit,
+ DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags);
+ Opts.ConstexprBacktraceLimit = getLastArgIntValue(
+ Args, OPT_fconstexpr_backtrace_limit,
+ DiagnosticOptions::DefaultConstexprBacktraceLimit, Diags);
+ Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
Opts.TabStop = DiagnosticOptions::DefaultTabStop;
@@ -588,7 +631,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Diags->Report(diag::warn_ignoring_ftabstop_value)
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
}
- Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
+ Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
addWarningArgs(Args, Opts.Warnings);
return Success;
@@ -610,8 +653,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::ASTDeclList; break;
case OPT_ast_dump:
Opts.ProgramAction = frontend::ASTDump; break;
- case OPT_ast_dump_xml:
- Opts.ProgramAction = frontend::ASTDumpXML; break;
case OPT_ast_print:
Opts.ProgramAction = frontend::ASTPrint; break;
case OPT_ast_view:
@@ -717,6 +758,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
+ Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
@@ -758,6 +800,30 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Literals;
if (Args.hasArg(OPT_objcmt_migrate_subscripting))
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Subscripting;
+ if (Args.hasArg(OPT_objcmt_migrate_property))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Property;
+ if (Args.hasArg(OPT_objcmt_migrate_readonly_property))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_ReadonlyProperty;
+ if (Args.hasArg(OPT_objcmt_migrate_readwrite_property))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_ReadwriteProperty;
+ if (Args.hasArg(OPT_objcmt_migrate_annotation))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Annotation;
+ if (Args.hasArg(OPT_objcmt_returns_innerpointer_property))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_ReturnsInnerPointerProperty;
+ if (Args.hasArg(OPT_objcmt_migrate_instancetype))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Instancetype;
+ if (Args.hasArg(OPT_objcmt_migrate_nsmacros))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_NsMacros;
+ if (Args.hasArg(OPT_objcmt_migrate_protocol_conformance))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_ProtocolConformance;
+ if (Args.hasArg(OPT_objcmt_atomic_property))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_AtomicProperty;
+ if (Args.hasArg(OPT_objcmt_ns_nonatomic_iosonly))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty;
+ if (Args.hasArg(OPT_objcmt_migrate_all))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_MigrateDecls;
+
+ Opts.ObjCMTWhiteListPath = Args.getLastArgValue(OPT_objcmt_white_list_dir_path);
if (Opts.ARCMTAction != FrontendOptions::ARCMT_None &&
Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
@@ -816,16 +882,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
void *MainAddr) {
- llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+ SmallString<128> P(llvm::sys::fs::getMainExecutable(Argv0, MainAddr));
- if (!P.isEmpty()) {
- P.eraseComponent(); // Remove /clang from foo/bin/clang
- P.eraseComponent(); // Remove /bin from foo/bin
+ if (!P.empty()) {
+ llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang
+ llvm::sys::path::remove_filename(P); // Remove /bin from foo/bin
// Get foo/lib/clang/<version>/include
- P.appendComponent("lib");
- P.appendComponent("clang");
- P.appendComponent(CLANG_VERSION_STRING);
+ llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING);
}
return P.str();
@@ -843,15 +907,21 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
- Opts.ModuleCachePruneInterval
- = Args.getLastArgIntValue(OPT_fmodules_prune_interval, 7*24*60*60);
- Opts.ModuleCachePruneAfter
- = Args.getLastArgIntValue(OPT_fmodules_prune_after, 31*24*60*60);
+ // -fmodules implies -fmodule-maps
+ Opts.ModuleMaps = Args.hasArg(OPT_fmodule_maps) || Args.hasArg(OPT_fmodules);
+ Opts.ModuleCachePruneInterval =
+ getLastArgIntValue(Args, OPT_fmodules_prune_interval, 7 * 24 * 60 * 60);
+ Opts.ModuleCachePruneAfter =
+ getLastArgIntValue(Args, OPT_fmodules_prune_after, 31 * 24 * 60 * 60);
for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro),
- ie = Args.filtered_end(); it != ie; ++it) {
+ ie = Args.filtered_end();
+ it != ie; ++it) {
StringRef MacroDef = (*it)->getValue();
Opts.ModulesIgnoreMacros.insert(MacroDef.split('=').first);
}
+ std::vector<std::string> ModuleMapFiles =
+ Args.getAllArgValues(OPT_fmodule_map_file);
+ Opts.ModuleMapFiles.insert(ModuleMapFiles.begin(), ModuleMapFiles.end());
// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
@@ -1032,6 +1102,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.Trigraphs = !Opts.GNUMode;
Opts.DollarIdents = !Opts.AsmPreprocessor;
+
+ // C++1y onwards has sized global deallocation functions.
+ Opts.SizedDeallocation = Opts.CPlusPlus1y;
}
/// Attempt to parse a visibility value out of the given argument.
@@ -1157,6 +1230,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
Opts.ObjCInferRelatedResultType = 0;
+
+ if (Args.hasArg(OPT_fobjc_subscripting_legacy_runtime))
+ Opts.ObjCSubscriptingLegacyRuntime =
+ (Opts.ObjCRuntime.getKind() == ObjCRuntime::FragileMacOSX);
}
if (Args.hasArg(OPT_fgnu89_inline))
@@ -1217,7 +1294,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
= Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility);
Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
- Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
+ Opts.MSCVersion = getLastArgIntValue(Args, OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
@@ -1236,36 +1313,43 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
- Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+ Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
+ Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+ Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
+ Opts.SizedDeallocation |= Args.hasArg(OPT_fsized_deallocation);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
- Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
- Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 256,
- Diags);
- Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512,
- Diags);
- Opts.BracketDepth = Args.getLastArgIntValue(OPT_fbracket_depth, 256, Diags);
+ Opts.MathErrno = !Opts.OpenCL && Args.hasArg(OPT_fmath_errno);
+ Opts.InstantiationDepth =
+ getLastArgIntValue(Args, OPT_ftemplate_depth, 256, Diags);
+ Opts.ArrowDepth =
+ getLastArgIntValue(Args, OPT_foperator_arrow_depth, 256, Diags);
+ Opts.ConstexprCallDepth =
+ getLastArgIntValue(Args, OPT_fconstexpr_depth, 512, Diags);
+ Opts.ConstexprStepLimit =
+ getLastArgIntValue(Args, OPT_fconstexpr_steps, 1048576, Diags);
+ Opts.BracketDepth = getLastArgIntValue(Args, OPT_fbracket_depth, 256, Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
- Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ,
- 0, Diags);
+ Opts.NumLargeByValueCopy =
+ getLastArgIntValue(Args, OPT_Wlarge_by_value_copy_EQ, 0, Diags);
Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields);
Opts.ObjCConstantStringClass =
Args.getLastArgValue(OPT_fconstant_string_class);
Opts.ObjCDefaultSynthProperties =
- Args.hasArg(OPT_fobjc_default_synthesize_properties);
+ !Args.hasArg(OPT_disable_objc_default_synthesize_properties);
Opts.EncodeExtendedBlockSig =
Args.hasArg(OPT_fencode_extended_block_signature);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
- Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct_EQ, 0, Diags);
- Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
- Opts.PIELevel = Args.getLastArgIntValue(OPT_pie_level, 0, Diags);
+ Opts.PackStruct = getLastArgIntValue(Args, OPT_fpack_struct_EQ, 0, Diags);
+ Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+ Opts.PIELevel = getLastArgIntValue(Args, OPT_pie_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
Opts.DumpRecordLayoutsSimple = Args.hasArg(OPT_fdump_record_layouts_simple);
Opts.DumpRecordLayouts = Opts.DumpRecordLayoutsSimple
@@ -1285,6 +1369,28 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
+ switch (llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("target", LangOptions::ASMM_Target)
+ .Case("no", LangOptions::ASMM_Off)
+ .Case("yes", LangOptions::ASMM_On)
+ .Default(255)) {
+ default:
+ Diags.Report(diag::err_drv_invalid_value)
+ << "-faddress-space-map-mangling=" << A->getValue();
+ break;
+ case LangOptions::ASMM_Target:
+ Opts.setAddressSpaceMapMangling(LangOptions::ASMM_Target);
+ break;
+ case LangOptions::ASMM_On:
+ Opts.setAddressSpaceMapMangling(LangOptions::ASMM_On);
+ break;
+ case LangOptions::ASMM_Off:
+ Opts.setAddressSpaceMapMangling(LangOptions::ASMM_Off);
+ break;
+ }
+ }
+
// Check if -fopenmp is specified.
Opts.OpenMP = Args.hasArg(OPT_fopenmp);
@@ -1310,7 +1416,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
- unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
+ unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags);
switch (SSP) {
default:
Diags.Report(diag::err_drv_invalid_value)
@@ -1454,7 +1560,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
switch (Action) {
case frontend::ASTDeclList:
case frontend::ASTDump:
- case frontend::ASTDumpXML:
case frontend::ASTPrint:
case frontend::ASTView:
case frontend::EmitAssembly:
@@ -1502,6 +1607,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
Opts.ABI = Args.getLastArgValue(OPT_target_abi);
Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
+ Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
@@ -1521,9 +1627,11 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// Parse the arguments.
OwningPtr<OptTable> Opts(createDriverOptTable());
+ const unsigned IncludedFlagsBitmask = options::CC1Option;
unsigned MissingArgIndex, MissingArgCount;
OwningPtr<InputArgList> Args(
- Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
+ Opts->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask));
// Check for missing argument error.
if (MissingArgCount) {
@@ -1539,15 +1647,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Success = false;
}
- // Issue errors on arguments that are not valid for CC1.
- for (ArgList::iterator I = Args->begin(), E = Args->end();
- I != E; ++I) {
- if (!(*I)->getOption().hasFlag(options::CC1Option)) {
- Diags.Report(diag::err_drv_unknown_argument) << (*I)->getAsString(*Args);
- Success = false;
- }
- }
-
Success = ParseAnalyzerArgs(*Res.getAnalyzerOpts(), *Args, Diags) && Success;
Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success;
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
@@ -1687,7 +1786,8 @@ std::string CompilerInvocation::getModuleHash() const {
hsOpts.UseStandardCXXIncludes,
hsOpts.UseLibcxx);
- // Darwin-specific hack: if we have a sysroot, use the contents of
+ // 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()) {
@@ -1698,10 +1798,31 @@ std::string CompilerInvocation::getModuleHash() const {
llvm::sys::path::append(systemVersionFile, "Library");
llvm::sys::path::append(systemVersionFile, "CoreServices");
llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
- if (!llvm::MemoryBuffer::getFile(systemVersionFile, buffer)) {
+ if (!llvm::MemoryBuffer::getFile(systemVersionFile.str(), buffer)) {
code = hash_combine(code, buffer.get()->getBuffer());
+
+ struct stat statBuf;
+ if (stat(systemVersionFile.c_str(), &statBuf) == 0)
+ code = hash_combine(code, statBuf.st_mtime);
}
}
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
+
+namespace clang {
+
+// Declared in clang/Frontend/Utils.h.
+int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags) {
+ int Res = Default;
+ if (Arg *A = Args.getLastArg(Id)) {
+ if (StringRef(A->getValue()).getAsInteger(10, Res)) {
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_int_value) << A->getAsString(Args)
+ << A->getValue();
+ }
+ }
+ return Res;
+}
+}
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index e25eb4322c55..78f39d4298af 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -13,15 +13,16 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
using namespace clang;
+using namespace llvm::opt;
/// createInvocationFromCommandLine - Construct a compiler invocation object for
/// a command line argument vector.
@@ -55,7 +56,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
- C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
+ C->getJobs().Print(llvm::errs(), "\n", true);
return 0;
}
@@ -65,7 +66,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
- C->PrintJob(OS, C->getJobs(), "; ", true);
+ Jobs.Print(OS, "; ", true);
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
return 0;
}
@@ -76,7 +77,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
return 0;
}
- const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ const ArgStringList &CCArgs = Cmd->getArguments();
OwningPtr<CompilerInvocation> CI(new CompilerInvocation());
if (!CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 628def68e5e0..4037af9055d5 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -21,6 +21,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -165,7 +166,8 @@ static void PrintFilename(raw_ostream &OS, StringRef Filename) {
void DependencyFileCallback::OutputDependencyFile() {
if (SeenMissingHeader) {
- llvm::sys::Path(OutputFile).eraseFromDisk();
+ bool existed;
+ llvm::sys::fs::remove(OutputFile, existed);
return;
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index ece51a35707d..075fe93d5841 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -429,9 +429,9 @@ void FrontendAction::EndSourceFile() {
llvm::errs() << "\n";
}
- // Cleanup the output streams, and erase the output files if we encountered
- // an error.
- CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred());
+ // Cleanup the output streams, and erase the output files if instructed by the
+ // FrontendAction.
+ CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
if (isCurrentFileAST()) {
CI.takeSema();
@@ -445,12 +445,18 @@ void FrontendAction::EndSourceFile() {
setCurrentInput(FrontendInputFile());
}
+bool FrontendAction::shouldEraseOutputFiles() {
+ return getCompilerInstance().getDiagnostics().hasErrorOccurred();
+}
+
//===----------------------------------------------------------------------===//
// Utility Actions
//===----------------------------------------------------------------------===//
void ASTFrontendAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
+ if (!CI.hasPreprocessor())
+ return;
// FIXME: Move the truncation aspect of this into Sema, we delayed this till
// here so the source manager would be initialized.
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 5c7567fa8c02..a3ab1be4a97a 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -54,7 +54,8 @@ ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter);
+ return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter,
+ CI.getFrontendOpts().ASTDumpLookups);
}
ASTConsumer *ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI,
@@ -62,17 +63,6 @@ ASTConsumer *ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI,
return CreateASTDeclNodeLister();
}
-ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- raw_ostream *OS;
- if (CI.getFrontendOpts().OutputFile.empty())
- OS = &llvm::outs();
- else
- OS = CI.createDefaultOutputFile(false, InFile);
- if (!OS) return 0;
- return CreateASTDumperXML(*OS);
-}
-
ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
return CreateASTViewer();
@@ -172,11 +162,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
return;
// Add includes for each of these headers.
- for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
- const FileEntry *Header = Module->Headers[I];
+ for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
+ const FileEntry *Header = Module->NormalHeaders[I];
Module->addTopHeader(Header);
addHeaderInclude(Header, Includes, LangOpts);
}
+ // Note that Module->PrivateHeaders will not be a TopHeader.
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
Module->addTopHeader(UmbrellaHeader);
@@ -231,7 +222,7 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
// Parse the module map file.
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- if (HS.loadModuleMapFile(ModuleMap))
+ if (HS.loadModuleMapFile(ModuleMap, IsSystem))
return false;
if (CI.getLangOpts().CurrentModule.empty()) {
@@ -255,11 +246,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
}
// Check whether we can build this module at all.
- StringRef Feature;
- if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Feature)) {
+ clang::Module::Requirement Requirement;
+ if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement)) {
CI.getDiagnostics().Report(diag::err_module_unavailable)
<< Module->getFullModuleName()
- << Feature;
+ << Requirement.second << Requirement.first;
return false;
}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index f1823c69e96c..1869d0c78d19 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -22,7 +22,6 @@ InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
.Case("mi", IK_PreprocessedObjC)
.Cases("mm", "M", IK_ObjCXX)
.Case("mii", IK_PreprocessedObjCXX)
- .Case("C", IK_CXX)
.Cases("C", "cc", "cp", IK_CXX)
.Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
.Case("cl", IK_OpenCL)
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 79920df20af7..237e5b1ac0c6 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -24,15 +24,16 @@ class HeaderIncludesCallback : public PPCallbacks {
bool OwnsOutputFile;
bool ShowAllHeaders;
bool ShowDepth;
+ bool MSStyle;
public:
HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
raw_ostream *OutputFile_, bool OwnsOutputFile_,
- bool ShowDepth_)
+ bool ShowDepth_, bool MSStyle_)
: SM(PP->getSourceManager()), OutputFile(OutputFile_),
CurrentIncludeDepth(0), HasProcessedPredefines(false),
OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
- ShowDepth(ShowDepth_) {}
+ ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
~HeaderIncludesCallback() {
if (OwnsOutputFile)
@@ -46,7 +47,8 @@ public:
}
void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
- StringRef OutputPath, bool ShowDepth) {
+ StringRef OutputPath, bool ShowDepth,
+ bool MSStyle) {
raw_ostream *OutputFile = &llvm::errs();
bool OwnsOutputFile = false;
@@ -54,7 +56,7 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
if (!OutputPath.empty()) {
std::string Error;
llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
- OutputPath.str().c_str(), Error, llvm::raw_fd_ostream::F_Append);
+ OutputPath.str().c_str(), Error, llvm::sys::fs::F_Append);
if (!Error.empty()) {
PP.getDiagnostics().Report(
clang::diag::warn_fe_cc_print_header_failure) << Error;
@@ -69,7 +71,7 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
OutputFile, OwnsOutputFile,
- ShowDepth));
+ ShowDepth, MSStyle));
}
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
@@ -109,14 +111,20 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
if (ShowHeader && Reason == PPCallbacks::EnterFile) {
// Write to a temporary string to avoid unnecessary flushing on errs().
SmallString<512> Filename(UserLoc.getFilename());
- Lexer::Stringify(Filename);
+ if (!MSStyle)
+ Lexer::Stringify(Filename);
SmallString<256> Msg;
+ if (MSStyle)
+ Msg += "Note: including file:";
+
if (ShowDepth) {
// The main source file is at depth 1, so skip one dot.
for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
- Msg += '.';
- Msg += ' ';
+ Msg += MSStyle ? ' ' : '.';
+
+ if (!MSStyle)
+ Msg += ' ';
}
Msg += Filename;
Msg += '\n';
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index f4ca4d498aec..d144cbb8945d 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -244,8 +244,8 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
if (HSOpts.UseBuiltinIncludes) {
// Ignore the sys root, we *always* look for clang headers relative to
// supplied path.
- llvm::sys::Path P(HSOpts.ResourceDir);
- P.appendComponent("include");
+ SmallString<128> P = StringRef(HSOpts.ResourceDir);
+ llvm::sys::path::append(P, "include");
AddUnmappedPath(P.str(), ExternCSystem, false);
}
@@ -312,15 +312,20 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
case llvm::Triple::MinGW32: {
// mingw-w64 crt include paths
- llvm::sys::Path P(HSOpts.ResourceDir);
- P.appendComponent("../../../i686-w64-mingw32/include"); // <sysroot>/i686-w64-mingw32/include
+ // <sysroot>/i686-w64-mingw32/include
+ SmallString<128> P = StringRef(HSOpts.ResourceDir);
+ llvm::sys::path::append(P, "../../../i686-w64-mingw32/include");
AddPath(P.str(), System, false);
- P = llvm::sys::Path(HSOpts.ResourceDir);
- P.appendComponent("../../../x86_64-w64-mingw32/include"); // <sysroot>/x86_64-w64-mingw32/include
+
+ // <sysroot>/x86_64-w64-mingw32/include
+ P.resize(HSOpts.ResourceDir.size());
+ llvm::sys::path::append(P, "../../../x86_64-w64-mingw32/include");
AddPath(P.str(), System, false);
+
// mingw.org crt include paths
- P = llvm::sys::Path(HSOpts.ResourceDir);
- P.appendComponent("../../../include"); // <sysroot>/include
+ // <sysroot>/include
+ P.resize(HSOpts.ResourceDir.size());
+ llvm::sys::path::append(P, "../../../include");
AddPath(P.str(), System, false);
AddPath("/mingw/include", System, false);
#if defined(_WIN32)
@@ -382,6 +387,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
case llvm::Triple::Cygwin:
// Cygwin-1.7
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3");
AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
// g++-4 / Cygwin-1.5
@@ -402,6 +408,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
// mingw.org C++ include paths
AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
#if defined(_WIN32)
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.8.1");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2");
@@ -468,15 +475,17 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
if (HSOpts.UseLibcxx) {
if (triple.isOSDarwin()) {
// On Darwin, libc++ may be installed alongside the compiler in
- // lib/c++/v1.
- llvm::sys::Path P(HSOpts.ResourceDir);
- if (!P.isEmpty()) {
- P.eraseComponent(); // Remove version from foo/lib/clang/version
- P.eraseComponent(); // Remove clang from foo/lib/clang
-
- // Get foo/lib/c++/v1
- P.appendComponent("c++");
- P.appendComponent("v1");
+ // include/c++/v1.
+ if (!HSOpts.ResourceDir.empty()) {
+ // Remove version from foo/lib/clang/version
+ StringRef NoVer = llvm::sys::path::parent_path(HSOpts.ResourceDir);
+ // Remove clang from foo/lib/clang
+ StringRef Lib = llvm::sys::path::parent_path(NoVer);
+ // Remove lib from foo/lib
+ SmallString<128> P = llvm::sys::path::parent_path(Lib);
+
+ // Get foo/include/c++/v1
+ llvm::sys::path::append(P, "include", "c++", "v1");
AddUnmappedPath(P.str(), CXXSystem, false);
}
}
@@ -686,8 +695,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
if (HSOpts.UseBuiltinIncludes) {
// Set up the builtin include directory in the module map.
- llvm::sys::Path P(HSOpts.ResourceDir);
- P.appendComponent("include");
+ SmallString<128> P = StringRef(HSOpts.ResourceDir);
+ llvm::sys::path::append(P, "include");
if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P.str()))
HS.getModuleMap().setBuiltinIncludeDir(Dir);
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index dc3ab53eda09..c7d25509e595 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -29,6 +29,12 @@
#include "llvm/Support/Path.h"
using namespace clang;
+static bool MacroBodyEndsInBackslash(StringRef MacroBody) {
+ while (!MacroBody.empty() && isWhitespace(MacroBody.back()))
+ MacroBody = MacroBody.drop_back();
+ return !MacroBody.empty() && MacroBody.back() == '\\';
+}
+
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
@@ -43,7 +49,14 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro,
if (End != StringRef::npos)
Diags.Report(diag::warn_fe_macro_contains_embedded_newline)
<< MacroName;
- Builder.defineMacro(MacroName, MacroBody.substr(0, End));
+ MacroBody = MacroBody.substr(0, End);
+ // We handle macro bodies which end in a backslash by appending an extra
+ // backslash+newline. This makes sure we don't accidentally treat the
+ // backslash as a line continuation marker.
+ if (MacroBodyEndsInBackslash(MacroBody))
+ Builder.defineMacro(MacroName, Twine(MacroBody) + "\\\n");
+ else
+ Builder.defineMacro(MacroName, MacroBody);
} else {
// Push "macroname 1".
Builder.defineMacro(Macro);
@@ -317,6 +330,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__cplusplus", "199711L");
}
+ // In C11 these are environment macros. In C++11 they are only defined
+ // as part of <cuchar>. To prevent breakage when mixing C and C++
+ // code, define these macros unconditionally. We can define them
+ // unconditionally, as Clang always uses UTF-16 and UTF-32 for 16-bit
+ // and 32-bit character literals.
+ Builder.defineMacro("__STDC_UTF_16__", "1");
+ Builder.defineMacro("__STDC_UTF_32__", "1");
+
if (LangOpts.ObjC1)
Builder.defineMacro("__OBJC__");
@@ -325,6 +346,38 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__ASSEMBLER__");
}
+/// Initialize the predefined C++ language feature test macros defined in
+/// ISO/IEC JTC1/SC22/WG21 (C++) SD-6: "SG10 Feature Test Recommendations".
+static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
+ MacroBuilder &Builder) {
+ // C++11 features.
+ if (LangOpts.CPlusPlus11) {
+ Builder.defineMacro("__cpp_unicode_characters", "200704");
+ Builder.defineMacro("__cpp_raw_strings", "200710");
+ Builder.defineMacro("__cpp_unicode_literals", "200710");
+ Builder.defineMacro("__cpp_user_defined_literals", "200809");
+ Builder.defineMacro("__cpp_lambdas", "200907");
+ Builder.defineMacro("__cpp_constexpr",
+ LangOpts.CPlusPlus1y ? "201304" : "200704");
+ Builder.defineMacro("__cpp_static_assert", "200410");
+ Builder.defineMacro("__cpp_decltype", "200707");
+ Builder.defineMacro("__cpp_attributes", "200809");
+ Builder.defineMacro("__cpp_rvalue_references", "200610");
+ Builder.defineMacro("__cpp_variadic_templates", "200704");
+ }
+
+ // C++14 features.
+ if (LangOpts.CPlusPlus1y) {
+ Builder.defineMacro("__cpp_binary_literals", "201304");
+ Builder.defineMacro("__cpp_init_captures", "201304");
+ Builder.defineMacro("__cpp_generic_lambdas", "201304");
+ Builder.defineMacro("__cpp_decltype_auto", "201304");
+ Builder.defineMacro("__cpp_return_type_deduction", "201304");
+ Builder.defineMacro("__cpp_aggregate_nsdmi", "201304");
+ Builder.defineMacro("__cpp_variable_templates", "201304");
+ }
+}
+
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@@ -395,12 +448,31 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.ObjCRuntime.isNeXTFamily())
Builder.defineMacro("__NEXT_RUNTIME__");
+ if (LangOpts.ObjCRuntime.getKind() == ObjCRuntime::ObjFW) {
+ VersionTuple tuple = LangOpts.ObjCRuntime.getVersion();
+
+ unsigned minor = 0;
+ if (tuple.getMinor().hasValue())
+ minor = tuple.getMinor().getValue();
+
+ unsigned subminor = 0;
+ if (tuple.getSubminor().hasValue())
+ subminor = tuple.getSubminor().getValue();
+
+ Builder.defineMacro("__OBJFW_RUNTIME_ABI__",
+ Twine(tuple.getMajor() * 10000 + minor * 100 +
+ subminor));
+ }
+
Builder.defineMacro("IBOutlet", "__attribute__((iboutlet))");
Builder.defineMacro("IBOutletCollection(ClassName)",
"__attribute__((iboutletcollection(ClassName)))");
Builder.defineMacro("IBAction", "void)__attribute__((ibaction)");
}
+ if (LangOpts.CPlusPlus)
+ InitializeCPlusPlusFeatureTestMacros(LangOpts, Builder);
+
// darwin_constant_cfstrings controls this. This is also dependent
// on other things like the runtime I believe. This is set even for C code.
if (!LangOpts.NoConstantCFStrings)
@@ -484,7 +556,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
Builder.defineMacro("__CHAR_BIT__", "8");
- DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder);
+ DefineTypeSize("__SCHAR_MAX__", TargetInfo::SignedChar, TI, Builder);
DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index ba83580cb69c..9cf68a5e9b25 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -94,8 +94,12 @@ public:
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D);
+ virtual void
+ AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
+ const VarTemplateSpecializationDecl *D);
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D);
+ virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
virtual void StaticDataMemberInstantiated(const VarDecl *D);
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
@@ -103,6 +107,8 @@ public:
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt);
+ void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE;
+
private:
std::vector<ASTMutationListener*> Listeners;
};
@@ -134,10 +140,20 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
+ const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
+}
+void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
const FunctionTemplateDecl *TD, const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
+void MultiplexASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
+ QualType ReturnType) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DeducedReturnType(FD, ReturnType);
+}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
@@ -161,6 +177,10 @@ void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
}
+void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DeclarationMarkedUsed(D);
+}
} // end namespace clang
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 9fd364943580..55a66d87f8bf 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -140,6 +140,9 @@ public:
virtual void PragmaCaptured(SourceLocation Loc, StringRef Str);
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str);
+ virtual void PragmaDetectMismatch(SourceLocation Loc,
+ const std::string &Name,
+ const std::string &Value);
virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
PragmaMessageKind Kind, StringRef Str);
virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType);
@@ -149,6 +152,10 @@ public:
StringRef Namespace);
virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
diag::Mapping Map, StringRef Str);
+ virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
+ ArrayRef<int> Ids);
+ virtual void PragmaWarningPush(SourceLocation Loc, int Level);
+ virtual void PragmaWarningPop(SourceLocation Loc);
bool HandleFirstTokOnLine(Token &Tok);
@@ -187,11 +194,11 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
// Emit #line directives or GNU line markers depending on what mode we're in.
if (UseLineDirective) {
OS << "#line" << ' ' << LineNo << ' ' << '"';
- OS.write(CurFilename.data(), CurFilename.size());
+ OS.write_escaped(CurFilename);
OS << '"';
} else {
OS << '#' << ' ' << LineNo << ' ' << '"';
- OS.write(CurFilename.data(), CurFilename.size());
+ OS.write_escaped(CurFilename);
OS << '"';
if (ExtraLen)
@@ -282,7 +289,6 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
CurFilename.clear();
CurFilename += UserLoc.getFilename();
- Lexer::Stringify(CurFilename);
FileType = NewFileType;
if (DisableLineMarkers) {
@@ -382,16 +388,8 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
setEmittedDirectiveOnThisLine();
}
-void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
- const IdentifierInfo *Kind,
+static void outputPrintable(llvm::raw_ostream& OS,
const std::string &Str) {
- startNewLineIfNeeded();
- MoveToLine(Loc);
- OS << "#pragma comment(" << Kind->getName();
-
- if (!Str.empty()) {
- OS << ", \"";
-
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char Char = Str[i];
if (isPrintable(Char) && Char != '\\' && Char != '"')
@@ -402,6 +400,18 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
<< (char)('0'+ ((Char >> 3) & 7))
<< (char)('0'+ ((Char >> 0) & 7));
}
+}
+
+void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
+ const IdentifierInfo *Kind,
+ const std::string &Str) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma comment(" << Kind->getName();
+
+ if (!Str.empty()) {
+ OS << ", \"";
+ outputPrintable(OS, Str);
OS << '"';
}
@@ -409,6 +419,19 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
setEmittedDirectiveOnThisLine();
}
+void PrintPPOutputPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
+ const std::string &Name,
+ const std::string &Value) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma detect_mismatch(\"" << Name << '"';
+ outputPrintable(OS, Name);
+ OS << "\", \"";
+ outputPrintable(OS, Value);
+ OS << "\")";
+ setEmittedDirectiveOnThisLine();
+}
+
void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
StringRef Namespace,
PragmaMessageKind Kind,
@@ -430,16 +453,7 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
break;
}
- for (unsigned i = 0, e = Str.size(); i != e; ++i) {
- unsigned char Char = Str[i];
- if (isPrintable(Char) && Char != '\\' && Char != '"')
- OS << (char)Char;
- else // Output anything hard as an octal escape.
- OS << '\\'
- << (char)('0'+ ((Char >> 6) & 7))
- << (char)('0'+ ((Char >> 3) & 7))
- << (char)('0'+ ((Char >> 0) & 7));
- }
+ outputPrintable(OS, Str);
OS << '"';
if (Kind == PMK_Message)
OS << ')';
@@ -497,6 +511,36 @@ PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
setEmittedDirectiveOnThisLine();
}
+void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,
+ StringRef WarningSpec,
+ ArrayRef<int> Ids) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma warning(" << WarningSpec << ':';
+ for (ArrayRef<int>::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I)
+ OS << ' ' << *I;
+ OS << ')';
+ setEmittedDirectiveOnThisLine();
+}
+
+void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,
+ int Level) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma warning(push";
+ if (Level >= 0)
+ OS << ", " << Level;
+ OS << ')';
+ setEmittedDirectiveOnThisLine();
+}
+
+void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma warning(pop)";
+ 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.
@@ -613,6 +657,11 @@ 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)) {
+ // PrintPPOutputPPCallbacks::InclusionDirective handles producing
+ // appropriate output here. Ignore this token entirely.
+ PP.Lex(Tok);
+ continue;
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
@@ -647,9 +696,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
}
typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair;
-static int MacroIDCompare(const void* a, const void* b) {
- const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a);
- const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b);
+static int MacroIDCompare(const id_macro_pair *LHS, const id_macro_pair *RHS) {
return LHS->first->getName().compare(RHS->first->getName());
}
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 1572d0f1d07f..a2dc9537bc05 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -336,13 +336,10 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
if (MaxColumns <= Columns)
return;
- // no special characters allowed in CaretLine or FixItInsertionLine
+ // No special characters are allowed in CaretLine.
assert(CaretLine.end() ==
std::find_if(CaretLine.begin(), CaretLine.end(),
char_out_of_range(' ','~')));
- assert(FixItInsertionLine.end() ==
- std::find_if(FixItInsertionLine.begin(), FixItInsertionLine.end(),
- char_out_of_range(' ','~')));
// Find the slice that we need to display the full caret line
// correctly.
@@ -370,8 +367,15 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
break;
- CaretStart = std::min(FixItStart, CaretStart);
- CaretEnd = std::max(FixItEnd, CaretEnd);
+ // We can safely use the byte offset FixItStart as the column offset
+ // because the characters up until FixItStart are all ASCII whitespace
+ // characters.
+ unsigned FixItStartCol = FixItStart;
+ unsigned FixItEndCol
+ = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
+
+ CaretStart = std::min(FixItStartCol, CaretStart);
+ CaretEnd = std::max(FixItEndCol, CaretEnd);
}
// CaretEnd may have been set at the middle of a character
@@ -689,7 +693,8 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
if (DiagOpts->ShowColors)
OS.resetColor();
- printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
+ DiagOpts->CLFallbackMode);
printDiagnosticMessage(OS, Level, Message,
OS.tell() - StartOfLocationInfo,
DiagOpts->MessageLength, DiagOpts->ShowColors);
@@ -698,7 +703,8 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
/*static*/ void
TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
DiagnosticsEngine::Level Level,
- bool ShowColors) {
+ bool ShowColors,
+ bool CLFallbackMode) {
if (ShowColors) {
// Print diagnostic category in bold and color
switch (Level) {
@@ -714,12 +720,21 @@ TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
switch (Level) {
case DiagnosticsEngine::Ignored:
llvm_unreachable("Invalid diagnostic type");
- case DiagnosticsEngine::Note: OS << "note: "; break;
- case DiagnosticsEngine::Warning: OS << "warning: "; break;
- case DiagnosticsEngine::Error: OS << "error: "; break;
- case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
+ case DiagnosticsEngine::Note: OS << "note"; break;
+ case DiagnosticsEngine::Warning: OS << "warning"; break;
+ case DiagnosticsEngine::Error: OS << "error"; break;
+ case DiagnosticsEngine::Fatal: OS << "fatal error"; break;
}
+ // In clang-cl /fallback mode, print diagnostics as "error(clang):". This
+ // makes it more clear whether a message is coming from clang or cl.exe,
+ // and it prevents MSBuild from concluding that the build failed just because
+ // there is an "error:" in the output.
+ if (CLFallbackMode)
+ OS << "(clang)";
+
+ OS << ": ";
+
if (ShowColors)
OS.resetColor();
}
@@ -774,11 +789,8 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
const FileEntry* FE = SM.getFileEntryForID(FID);
if (FE && FE->getName()) {
OS << FE->getName();
- if (FE->getDevice() == 0 && FE->getInode() == 0
- && FE->getFileMode() == 0) {
- // in PCH is a guess, but a good one:
+ if (FE->isInPCH())
OS << " (in PCH)";
- }
OS << ": ";
}
}
@@ -1023,24 +1035,18 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
if (HintCol < PrevHintEndCol)
HintCol = PrevHintEndCol + 1;
- // FIXME: This function handles multibyte characters in the source, but
- // not in the fixits. This assertion is intended to catch unintended
- // use of multibyte characters in fixits. If we decide to do this, we'll
- // have to track separate byte widths for the source and fixit lines.
- assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
- I->CodeToInsert.size());
-
- // This relies on one byte per column in our fixit hints.
// This should NOT use HintByteOffset, because the source might have
// Unicode characters in earlier columns.
- unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
- if (LastColumnModified > FixItInsertionLine.size())
- FixItInsertionLine.resize(LastColumnModified, ' ');
+ unsigned NewFixItLineSize = FixItInsertionLine.size() +
+ (HintCol - PrevHintEndCol) + I->CodeToInsert.size();
+ if (NewFixItLineSize > FixItInsertionLine.size())
+ FixItInsertionLine.resize(NewFixItLineSize, ' ');
std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
- FixItInsertionLine.begin() + HintCol);
+ FixItInsertionLine.end() - I->CodeToInsert.size());
- PrevHintEndCol = LastColumnModified;
+ PrevHintEndCol =
+ HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
} else {
FixItInsertionLine.clear();
break;
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index c22798af60ac..994a8f74ed46 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -132,7 +132,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
// diagnostics in a context that lacks language options, a source manager, or
// other infrastructure necessary when emitting more rich diagnostics.
if (!Info.getLocation().isValid()) {
- TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+ TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
+ DiagOpts->CLFallbackMode);
TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
OS.tell() - StartOfLocationInfo,
DiagOpts->MessageLength,
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 46745b6b9a4f..045e60add1fc 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -371,7 +371,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir;
- const FileEntry *FE = PP->LookupFile(Filename, false, NULL, CurDir,
+ const FileEntry *FE = PP->LookupFile(Pos, Filename, false, NULL, CurDir,
NULL, NULL, 0);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
@@ -555,7 +555,7 @@ static bool findDirectives(SourceManager &SM, FileID FID,
VerifyDiagnosticConsumer::DirectiveStatus Status =
VerifyDiagnosticConsumer::HasNoDirectives;
while (Tok.isNot(tok::eof)) {
- RawLex.Lex(Tok);
+ RawLex.LexFromRawLexer(Tok);
if (!Tok.is(tok::comment)) continue;
std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
@@ -628,11 +628,11 @@ static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
while (DiagnosticLoc.isMacroID())
DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
- if (SM.isFromSameFile(DirectiveLoc, DiagnosticLoc))
+ if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
return true;
const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
- if (!DiagFile && SM.isFromMainFile(DirectiveLoc))
+ if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
return true;
return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 176511b0e4c8..28a864a633ed 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -14,8 +14,18 @@ target_link_libraries(clangFrontendTool
clangRewriteCore
clangRewriteFrontend
clangCodeGen
- clangStaticAnalyzerFrontend
- clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
- clangARCMigrate
)
+
+if(CLANG_ENABLE_ARCMT)
+ target_link_libraries(clangFrontendTool
+ clangARCMigrate
+ )
+endif()
+
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ target_link_libraries(clangFrontendTool
+ clangStaticAnalyzerFrontend
+ clangStaticAnalyzerCheckers
+ clangStaticAnalyzerCore
+ )
+endif()
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index b0d76da33425..d755839c0f77 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -15,8 +15,6 @@
#include "clang/FrontendTool/Utils.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -25,9 +23,12 @@
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
+using namespace llvm::opt;
static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
@@ -36,7 +37,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return new ASTDeclListAction();
case ASTDump: return new ASTDumpAction();
- case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
case ASTView: return new ASTViewAction();
case DumpRawTokens: return new DumpRawTokensAction();
@@ -141,28 +141,29 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
#endif
#ifdef CLANG_ENABLE_ARCMT
- // Potentially wrap the base FE action in an ARC Migrate Tool action.
- switch (FEOpts.ARCMTAction) {
- case FrontendOptions::ARCMT_None:
- break;
- case FrontendOptions::ARCMT_Check:
- Act = new arcmt::CheckAction(Act);
- break;
- case FrontendOptions::ARCMT_Modify:
- Act = new arcmt::ModifyAction(Act);
- break;
- case FrontendOptions::ARCMT_Migrate:
- Act = new arcmt::MigrateAction(Act,
- FEOpts.MTMigrateDir,
- FEOpts.ARCMTMigrateReportOut,
- FEOpts.ARCMTMigrateEmitARCErrors);
- break;
- }
+ if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource) {
+ // Potentially wrap the base FE action in an ARC Migrate Tool action.
+ switch (FEOpts.ARCMTAction) {
+ case FrontendOptions::ARCMT_None:
+ break;
+ case FrontendOptions::ARCMT_Check:
+ Act = new arcmt::CheckAction(Act);
+ break;
+ case FrontendOptions::ARCMT_Modify:
+ Act = new arcmt::ModifyAction(Act);
+ break;
+ case FrontendOptions::ARCMT_Migrate:
+ Act = new arcmt::MigrateAction(Act,
+ FEOpts.MTMigrateDir,
+ FEOpts.ARCMTMigrateReportOut,
+ FEOpts.ARCMTMigrateEmitARCErrors);
+ break;
+ }
- if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
- Act = new arcmt::ObjCMigrateAction(Act, FEOpts.MTMigrateDir,
- FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals,
- FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting);
+ if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
+ Act = new arcmt::ObjCMigrateAction(Act, FEOpts.MTMigrateDir,
+ FEOpts.ObjCMTAction);
+ }
}
#endif
@@ -177,12 +178,11 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
- OwningPtr<driver::OptTable> Opts(driver::createDriverOptTable());
+ OwningPtr<OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org",
- /*Include=*/driver::options::CC1Option,
- /*Exclude=*/0);
- return 0;
+ /*Include=*/ driver::options::CC1Option, /*Exclude=*/ 0);
+ return true;
}
// Honor -version.
@@ -190,7 +190,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// FIXME: Use a better -version message?
if (Clang->getFrontendOpts().ShowVersion) {
llvm::cl::PrintVersionMessage();
- return 0;
+ return true;
}
// Load any requested plugins.
@@ -222,7 +222,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// This should happen AFTER plugins have been loaded!
if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
- return 0;
+ return true;
}
#endif
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 8be33b7b4a15..2da1a28aca42 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -12,6 +12,7 @@ set(files
fmaintrin.h
immintrin.h
iso646.h
+ Intrin.h
limits.h
lzcntintrin.h
mm3dnow.h
@@ -23,6 +24,7 @@ set(files
prfchwintrin.h
rdseedintrin.h
rtmintrin.h
+ shaintrin.h
smmintrin.h
stdalign.h
stdarg.h
@@ -30,6 +32,7 @@ set(files
stddef.h
stdint.h
stdnoreturn.h
+ tbmintrin.h
tgmath.h
tmmintrin.h
varargs.h
@@ -44,13 +47,13 @@ set(files
module.map
)
-set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
+set(output_dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/clang/${CLANG_VERSION}/include)
# If we are in an IDE that has a configuration directory, we need to
# create a second copy of the headers so that 'clang' can find them if
# it's run from the build directory.
if(MSVC_IDE OR XCODE)
- set(other_output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
+ set(other_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib/clang/${CLANG_VERSION}/include)
endif()
# Generate arm_neon.h
@@ -96,11 +99,11 @@ add_custom_target(clang-headers ALL DEPENDS ${out_files})
set_target_properties(clang-headers PROPERTIES FOLDER "Misc")
if (other_output_dir)
- if(UNIX)
- add_custom_command(TARGET clang-headers POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}"
- COMMAND ${CMAKE_COMMAND} -E create_symlink "${LLVM_BINARY_DIR}/bin/lib/clang" "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/clang")
- endif()
+ if(UNIX)
+ add_custom_command(TARGET clang-headers POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}"
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib/clang" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/clang")
+ endif()
endif ()
install(FILES ${files} ${output_dir}/arm_neon.h
diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h
new file mode 100644
index 000000000000..437646471dab
--- /dev/null
+++ b/lib/Headers/Intrin.h
@@ -0,0 +1,784 @@
+/* ===-------- Intrin.h ---------------------------------------------------===
+ *
+ * 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 <Intrin.h>
+#else
+
+#ifndef __INTRIN_H
+#define __INTRIN_H
+
+/* First include the standard intrinsics. */
+#include <x86intrin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* And the random ones that aren't in those files. */
+__m64 _m_from_float(float);
+__m64 _m_from_int(int _l);
+void _m_prefetch(void *);
+float _m_to_float(__m64);
+int _m_to_int(__m64 _M);
+
+/* Other assorted instruction intrinsics. */
+void __addfsbyte(unsigned long, unsigned char);
+void __addfsdword(unsigned long, unsigned long);
+void __addfsword(unsigned long, unsigned short);
+void __code_seg(const char *);
+void __cpuid(int[4], int);
+void __cpuidex(int[4], int, int);
+void __debugbreak(void);
+__int64 __emul(int, int);
+unsigned __int64 __emulu(unsigned int, unsigned int);
+void __cdecl __fastfail(unsigned int);
+unsigned int __getcallerseflags(void);
+void __halt(void);
+unsigned char __inbyte(unsigned short);
+void __inbytestring(unsigned short, unsigned char *, unsigned long);
+void __incfsbyte(unsigned long);
+void __incfsdword(unsigned long);
+void __incfsword(unsigned long);
+unsigned long __indword(unsigned short);
+void __indwordstring(unsigned short, unsigned long *, unsigned long);
+void __int2c(void);
+void __invlpg(void *);
+unsigned short __inword(unsigned short);
+void __inwordstring(unsigned short, unsigned short *, unsigned long);
+void __lidt(void *);
+unsigned __int64 __ll_lshift(unsigned __int64, int);
+__int64 __ll_rshift(__int64, int);
+void __llwpcb(void *);
+unsigned char __lwpins32(unsigned int, unsigned int, unsigned int);
+void __lwpval32(unsigned int, unsigned int, unsigned int);
+unsigned int __lzcnt(unsigned int);
+unsigned short __lzcnt16(unsigned short);
+void __movsb(unsigned char *, unsigned char const *, size_t);
+void __movsd(unsigned long *, unsigned long const *, size_t);
+void __movsw(unsigned short *, unsigned short const *, size_t);
+void __nop(void);
+void __nvreg_restore_fence(void);
+void __nvreg_save_fence(void);
+void __outbyte(unsigned short, unsigned char);
+void __outbytestring(unsigned short, unsigned char *, unsigned long);
+void __outdword(unsigned short, unsigned long);
+void __outdwordstring(unsigned short, unsigned long *, unsigned long);
+void __outword(unsigned short, unsigned short);
+void __outwordstring(unsigned short, unsigned short *, unsigned long);
+static __inline__
+unsigned int __popcnt(unsigned int);
+static __inline__
+unsigned short __popcnt16(unsigned short);
+unsigned __int64 __rdtsc(void);
+unsigned __int64 __rdtscp(unsigned int *);
+unsigned long __readcr0(void);
+unsigned long __readcr2(void);
+unsigned long __readcr3(void);
+unsigned long __readcr5(void);
+unsigned long __readcr8(void);
+unsigned int __readdr(unsigned int);
+unsigned int __readeflags(void);
+unsigned char __readfsbyte(unsigned long);
+unsigned long __readfsdword(unsigned long);
+unsigned __int64 __readfsqword(unsigned long);
+unsigned short __readfsword(unsigned long);
+unsigned __int64 __readmsr(unsigned long);
+unsigned __int64 __readpmc(unsigned long);
+unsigned long __segmentlimit(unsigned long);
+void __sidt(void *);
+void *__slwpcb(void);
+void __stosb(unsigned char *, unsigned char, size_t);
+void __stosd(unsigned long *, unsigned long, size_t);
+void __stosw(unsigned short *, unsigned short, size_t);
+void __svm_clgi(void);
+void __svm_invlpga(void *, int);
+void __svm_skinit(int);
+void __svm_stgi(void);
+void __svm_vmload(size_t);
+void __svm_vmrun(size_t);
+void __svm_vmsave(size_t);
+void __ud2(void);
+unsigned __int64 __ull_rshift(unsigned __int64, int);
+void __vmx_off(void);
+void __vmx_vmptrst(unsigned __int64 *);
+void __wbinvd(void);
+void __writecr0(unsigned int);
+void __writecr3(unsigned int);
+void __writecr4(unsigned int);
+void __writecr8(unsigned int);
+void __writedr(unsigned int, unsigned int);
+void __writeeflags(unsigned int);
+void __writefsbyte(unsigned long, unsigned char);
+void __writefsdword(unsigned long, unsigned long);
+void __writefsqword(unsigned long, unsigned __int64);
+void __writefsword(unsigned long, unsigned short);
+void __writemsr(unsigned long, unsigned __int64);
+static __inline__
+void *_AddressOfReturnAddress(void);
+unsigned int _andn_u32(unsigned int, unsigned int);
+unsigned int _bextr_u32(unsigned int, unsigned int, unsigned int);
+unsigned int _bextr_u32(unsigned int, unsigned int, unsigned int);
+unsigned int _bextri_u32(unsigned int, unsigned int);
+static __inline__
+unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
+static __inline__
+unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
+static __inline__
+unsigned char _bittest(long const *, long);
+static __inline__
+unsigned char _bittestandcomplement(long *, long);
+static __inline__
+unsigned char _bittestandreset(long *, long);
+static __inline__
+unsigned char _bittestandset(long *, long);
+unsigned int _blcfill_u32(unsigned int);
+unsigned int _blci_u32(unsigned int);
+unsigned int _blcic_u32(unsigned int);
+unsigned int _blcmsk_u32(unsigned int);
+unsigned int _blcs_u32(unsigned int);
+unsigned int _blsfill_u32(unsigned int);
+unsigned int _blsi_u32(unsigned int);
+unsigned int _blsic_u32(unsigned int);
+unsigned int _blsmsk_u32(unsigned int);
+unsigned int _blsmsk_u32(unsigned int);
+unsigned int _blsr_u32(unsigned int);
+unsigned int _blsr_u32(unsigned int);
+unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
+unsigned long __cdecl _byteswap_ulong(unsigned long);
+unsigned short __cdecl _byteswap_ushort(unsigned short);
+unsigned _bzhi_u32(unsigned int, unsigned int);
+void __cdecl _disable(void);
+void __cdecl _enable(void);
+void __cdecl _fxrstor(void const *);
+void __cdecl _fxsave(void *);
+long _InterlockedAddLargeStatistic(__int64 volatile *_Addend, long _Value);
+static __inline__
+long _InterlockedAnd(long volatile *_Value, long _Mask);
+static __inline__
+short _InterlockedAnd16(short volatile *_Value, short _Mask);
+static __inline__
+char _InterlockedAnd8(char volatile *_Value, char _Mask);
+unsigned char _interlockedbittestandreset(long volatile *, long);
+unsigned char _interlockedbittestandset(long volatile *, long);
+static __inline__
+long __cdecl _InterlockedCompareExchange(long volatile *_Destination,
+ long _Exchange, long _Comparand);
+long _InterlockedCompareExchange_HLEAcquire(long volatile *, long, long);
+long _InterlockedCompareExchange_HLERelease(long volatile *, long, long);
+static __inline__
+short _InterlockedCompareExchange16(short volatile *_Destination,
+ short _Exchange, short _Comparand);
+static __inline__
+__int64 _InterlockedCompareExchange64(__int64 volatile *_Destination,
+ __int64 _Exchange, __int64 _Comparand);
+__int64 _InterlockedcompareExchange64_HLEAcquire(__int64 volatile *, __int64,
+ __int64);
+__int64 _InterlockedCompareExchange64_HLERelease(__int64 volatile *, __int64,
+ __int64);
+static __inline__
+char _InterlockedCompareExchange8(char volatile *_Destination, char _Exchange,
+ char _Comparand);
+void *_InterlockedCompareExchangePointer_HLEAcquire(void *volatile *, void *,
+ void *);
+void *_InterlockedCompareExchangePointer_HLERelease(void *volatile *, void *,
+ void *);
+static __inline__
+long __cdecl _InterlockedDecrement(long volatile *_Addend);
+static __inline__
+short _InterlockedDecrement16(short volatile *_Addend);
+static __inline__
+long __cdecl _InterlockedExchange(long volatile *_Target, long _Value);
+static __inline__
+short _InterlockedExchange16(short volatile *_Target, short _Value);
+static __inline__
+char _InterlockedExchange8(char volatile *_Target, char _Value);
+static __inline__
+long __cdecl _InterlockedExchangeAdd(long volatile *_Addend, long _Value);
+long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long);
+long _InterlockedExchangeAdd_HLERelease(long volatile *, long);
+static __inline__
+char _InterlockedExchangeAdd8(char volatile *_Addend, char _Value);
+static __inline__
+long __cdecl _InterlockedIncrement(long volatile *_Addend);
+static __inline__
+short _InterlockedIncrement16(short volatile *_Addend);
+static __inline__
+long _InterlockedOr(long volatile *_Value, long _Mask);
+static __inline__
+short _InterlockedOr16(short volatile *_Value, short _Mask);
+static __inline__
+char _InterlockedOr8(char volatile *_Value, char _Mask);
+static __inline__
+long _InterlockedXor(long volatile *_Value, long _Mask);
+static __inline__
+short _InterlockedXor16(short volatile *_Value, short _Mask);
+static __inline__
+char _InterlockedXor8(char volatile *_Value, char _Mask);
+void __cdecl _invpcid(unsigned int, void *);
+static __inline__
+unsigned long __cdecl _lrotl(unsigned long, int);
+static __inline__
+unsigned long __cdecl _lrotr(unsigned long, int);
+static __inline__
+unsigned int _lzcnt_u32(unsigned int);
+static __inline__
+void _ReadBarrier(void);
+static __inline__
+void _ReadWriteBarrier(void);
+static __inline__
+void *_ReturnAddress(void);
+unsigned int _rorx_u32(unsigned int, const unsigned int);
+int __cdecl _rdrand16_step(unsigned short *);
+int __cdecl _rdrand32_step(unsigned int *);
+static __inline__
+unsigned int __cdecl _rotl(unsigned int _Value, int _Shift);
+static __inline__
+unsigned short _rotl16(unsigned short _Value, unsigned char _Shift);
+static __inline__
+unsigned __int64 __cdecl _rotl64(unsigned __int64 _Value, int _Shift);
+static __inline__
+unsigned char _rotl8(unsigned char _Value, unsigned char _Shift);
+static __inline__
+unsigned int __cdecl _rotr(unsigned int _Value, int _Shift);
+static __inline__
+unsigned short _rotr16(unsigned short _Value, unsigned char _Shift);
+static __inline__
+unsigned __int64 __cdecl _rotr64(unsigned __int64 _Value, int _Shift);
+static __inline__
+unsigned char _rotr8(unsigned char _Value, unsigned char _Shift);
+int _sarx_i32(int, unsigned int);
+
+/* FIXME: Need definition for jmp_buf.
+ int __cdecl _setjmp(jmp_buf); */
+
+unsigned int _shlx_u32(unsigned int, unsigned int);
+unsigned int _shrx_u32(unsigned int, unsigned int);
+void _Store_HLERelease(long volatile *, long);
+void _Store64_HLERelease(__int64 volatile *, __int64);
+void _StorePointer_HLERelease(void *volatile *, void *);
+unsigned int _t1mskc_u32(unsigned int);
+unsigned int _tzcnt_u32(unsigned int);
+unsigned int _tzcnt_u32(unsigned int);
+unsigned int _tzmsk_u32(unsigned int);
+static __inline__
+void _WriteBarrier(void);
+void _xabort(const unsigned int imm);
+unsigned __int32 xbegin(void);
+void _xend(void);
+unsigned __int64 __cdecl _xgetbv(unsigned int);
+void __cdecl _xrstor(void const *, unsigned __int64);
+void __cdecl _xsave(void *, unsigned __int64);
+void __cdecl _xsaveopt(void *, unsigned __int64);
+void __cdecl _xsetbv(unsigned int, unsigned __int64);
+unsigned char _xtest(void);
+
+/* These additional intrinsics are turned on in x64/amd64/x86_64 mode. */
+#ifdef __x86_64__
+void __addgsbyte(unsigned long, unsigned char);
+void __addgsdword(unsigned long, unsigned long);
+void __addgsqword(unsigned long, unsigned __int64);
+void __addgsword(unsigned long, unsigned short);
+void __faststorefence(void);
+void __incgsbyte(unsigned long);
+void __incgsdword(unsigned long);
+void __incgsqword(unsigned long);
+void __incgsword(unsigned long);
+unsigned __int64 __popcnt64(unsigned __int64);
+unsigned __int64 __shiftleft128(unsigned __int64 _LowPart,
+ unsigned __int64 _HighPart,
+ unsigned char _Shift);
+unsigned __int64 __shiftright128(unsigned __int64 _LowPart,
+ unsigned __int64 _HighPart,
+ unsigned char _Shift);
+void __stosq(unsigned __int64 *, unsigned __int64, size_t);
+unsigned __int64 _andn_u64(unsigned __int64, unsigned __int64);
+unsigned __int64 _bextr_u64(unsigned __int64, unsigned int, unsigned int);
+unsigned __int64 _bextri_u64(unsigned __int64, unsigned int);
+static __inline__
+unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
+static __inline__
+unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
+static __inline__
+unsigned char _bittest64(__int64 const *, __int64);
+static __inline__
+unsigned char _bittestandcomplement64(__int64 *, __int64);
+static __inline__
+unsigned char _bittestandreset64(__int64 *, __int64);
+static __inline__
+unsigned char _bittestandset64(__int64 *, __int64);
+unsigned __int64 _blcfill_u64(unsigned __int64);
+unsigned __int64 _blci_u64(unsigned __int64);
+unsigned __int64 _blcic_u64(unsigned __int64);
+unsigned __int64 _blcmsk_u64(unsigned __int64);
+unsigned __int64 _blcs_u64(unsigned __int64);
+unsigned __int64 _blsfill_u64(unsigned __int64);
+unsigned __int64 _blsi_u64(unsigned __int64);
+unsigned __int64 _blsic_u64(unsigned __int64);
+unsigned __int64 _blmsk_u64(unsigned __int64);
+unsigned __int64 _blsr_u64(unsigned __int64);
+unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
+unsigned __int64 _bzhi_u64(unsigned __int64, unsigned int);
+void __cdecl _fxrstor64(void const *);
+void __cdecl _fxsave64(void *);
+long _InterlockedAnd_np(long volatile *_Value, long _Mask);
+short _InterlockedAnd16_np(short volatile *_Value, short _Mask);
+__int64 _InterlockedAnd64_np(__int64 volatile *_Value, __int64 _Mask);
+char _InterlockedAnd8_np(char volatile *_Value, char _Mask);
+unsigned char _interlockedbittestandreset64(__int64 volatile *, __int64);
+unsigned char _interlockedbittestandset64(__int64 volatile *, __int64);
+long _InterlockedCompareExchange_np(long volatile *_Destination, long _Exchange,
+ long _Comparand);
+unsigned char _InterlockedCompareExchange128(__int64 volatile *_Destination,
+ __int64 _ExchangeHigh,
+ __int64 _ExchangeLow,
+ __int64 *_CompareandResult);
+unsigned char _InterlockedCompareExchange128_np(__int64 volatile *_Destination,
+ __int64 _ExchangeHigh,
+ __int64 _ExchangeLow,
+ __int64 *_ComparandResult);
+short _InterlockedCompareExchange16_np(short volatile *_Destination,
+ short _Exchange, short _Comparand);
+__int64 _InterlockedCompareExchange64_np(__int64 volatile *_Destination,
+ __int64 _Exchange, __int64 _Comparand);
+void *_InterlockedCompareExchangePointer_np(void *volatile *_Destination,
+ void *_Exchange, void *_Comparand);
+long _InterlockedOr_np(long volatile *_Value, long _Mask);
+short _InterlockedOr16_np(short volatile *_Value, short _Mask);
+__int64 _InterlockedOr64_np(__int64 volatile *_Value, __int64 _Mask);
+char _InterlockedOr8_np(char volatile *_Value, char _Mask);
+long _InterlockedXor_np(long volatile *_Value, long _Mask);
+short _InterlockedXor16_np(short volatile *_Value, short _Mask);
+__int64 _InterlockedXor64_np(__int64 volatile *_Value, __int64 _Mask);
+char _InterlockedXor8_np(char volatile *_Value, char _Mask);
+unsigned __int64 _lzcnt_u64(unsigned __int64);
+__int64 _mul128(__int64 _Multiplier, __int64 _Multiplicand,
+ __int64 *_HighProduct);
+unsigned int __cdecl _readfsbase_u32(void);
+unsigned __int64 __cdecl _readfsbase_u64(void);
+unsigned int __cdecl _readgsbase_u32(void);
+unsigned __int64 __cdecl _readgsbase_u64(void);
+unsigned __int64 _rorx_u64(unsigned __int64, const unsigned int);
+unsigned __int64 _tzcnt_u64(unsigned __int64);
+unsigned __int64 _tzmsk_u64(unsigned __int64);
+unsigned __int64 _umul128(unsigned __int64 _Multiplier,
+ unsigned __int64 _Multiplicand,
+ unsigned __int64 *_HighProduct);
+void __cdecl _writefsbase_u32(unsigned int);
+void _cdecl _writefsbase_u64(unsigned __int64);
+void __cdecl _writegsbase_u32(unsigned int);
+void __cdecl _writegsbase_u64(unsigned __int64);
+void __cdecl _xrstor64(void const *, unsigned __int64);
+void __cdecl _xsave64(void *, unsigned __int64);
+void __cdecl _xsaveopt64(void *, unsigned __int64);
+
+#endif /* __x86_64__ */
+
+/*----------------------------------------------------------------------------*\
+|* Bit Twiddling
+\*----------------------------------------------------------------------------*/
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_rotl8(unsigned char _Value, unsigned char _Shift) {
+ _Shift &= 0x7;
+ return _Shift ? (_Value << _Shift) | (_Value >> (8 - _Shift)) : _Value;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_rotr8(unsigned char _Value, unsigned char _Shift) {
+ _Shift &= 0x7;
+ return _Shift ? (_Value >> _Shift) | (_Value << (8 - _Shift)) : _Value;
+}
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+_rotl16(unsigned short _Value, unsigned char _Shift) {
+ _Shift &= 0xf;
+ return _Shift ? (_Value << _Shift) | (_Value >> (16 - _Shift)) : _Value;
+}
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+_rotr16(unsigned short _Value, unsigned char _Shift) {
+ _Shift &= 0xf;
+ return _Shift ? (_Value >> _Shift) | (_Value << (16 - _Shift)) : _Value;
+}
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_rotl(unsigned int _Value, int _Shift) {
+ _Shift &= 0x1f;
+ return _Shift ? (_Value << _Shift) | (_Value >> (32 - _Shift)) : _Value;
+}
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_rotr(unsigned int _Value, int _Shift) {
+ _Shift &= 0x1f;
+ return _Shift ? (_Value >> _Shift) | (_Value << (32 - _Shift)) : _Value;
+}
+static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
+_lrotl(unsigned long _Value, int _Shift) {
+ _Shift &= 0x1f;
+ return _Shift ? (_Value << _Shift) | (_Value >> (32 - _Shift)) : _Value;
+}
+static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
+_lrotr(unsigned long _Value, int _Shift) {
+ _Shift &= 0x1f;
+ return _Shift ? (_Value >> _Shift) | (_Value << (32 - _Shift)) : _Value;
+}
+static
+__inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+_rotl64(unsigned __int64 _Value, int _Shift) {
+ _Shift &= 0x3f;
+ return _Shift ? (_Value << _Shift) | (_Value >> (64 - _Shift)) : _Value;
+}
+static
+__inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+_rotr64(unsigned __int64 _Value, int _Shift) {
+ _Shift &= 0x3f;
+ return _Shift ? (_Value >> _Shift) | (_Value << (64 - _Shift)) : _Value;
+}
+/*----------------------------------------------------------------------------*\
+|* Bit Counting and Testing
+\*----------------------------------------------------------------------------*/
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_BitScanForward(unsigned long *_Index, unsigned long _Mask) {
+ if (!_Mask)
+ return 0;
+ *_Index = __builtin_ctzl(_Mask);
+ return 1;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_BitScanReverse(unsigned long *_Index, unsigned long _Mask) {
+ if (!_Mask)
+ return 0;
+ *_Index = 31 - __builtin_clzl(_Mask);
+ return 1;
+}
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_lzcnt_u32(unsigned int a) {
+ if (!a)
+ return 32;
+ return __builtin_clzl(a);
+}
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+__popcnt16(unsigned short value) {
+ return __builtin_popcount((int)value);
+}
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__popcnt(unsigned int value) {
+ return __builtin_popcount(value);
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittest(long const *a, long b) {
+ return (*a >> b) & 1;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandcomplement(long *a, long b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a ^ (1 << b);
+ return x;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandreset(long *a, long b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a & ~(1 << b);
+ return x;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandset(long *a, long b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a | (1 << b);
+ return x;
+}
+#ifdef __x86_64__
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask) {
+ if (!_Mask)
+ return 0;
+ *_Index = __builtin_ctzll(_Mask);
+ return 1;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask) {
+ if (!_Mask)
+ return 0;
+ *_Index = 63 - __builtin_clzll(_Mask);
+ return 1;
+}
+static
+__inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+_lzcnt_u64(unsigned __int64 a) {
+ if (!a)
+ return 64;
+ return __builtin_clzll(a);
+}
+static __inline__
+unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+ __popcnt64(unsigned __int64 value) {
+ return __builtin_popcountll(value);
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittest64(__int64 const *a, __int64 b) {
+ return (*a >> b) & 1;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandcomplement64(__int64 *a, __int64 b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a ^ (1ll << b);
+ return x;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandreset64(__int64 *a, __int64 b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a & ~(1ll << b);
+ return x;
+}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_bittestandset64(__int64 *a, __int64 b) {
+ unsigned char x = (*a >> b) & 1;
+ *a = *a | (1ll << b);
+ return x;
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Exchange Add
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeAdd8(char volatile *_Addend, char _Value) {
+ return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeAdd16(short volatile *_Addend, short _Value) {
+ return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeAdd(long volatile *_Addend, long _Value) {
+ return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) {
+ return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Exchange Sub
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeSub8(char volatile *_Subend, char _Value) {
+ return __atomic_sub_fetch(_Subend, _Value, 0) + _Value;
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeSub16(short volatile *_Subend, short _Value) {
+ return __atomic_sub_fetch(_Subend, _Value, 0) + _Value;
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeSub(long volatile *_Subend, long _Value) {
+ return __atomic_sub_fetch(_Subend, _Value, 0) + _Value;
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) {
+ return __atomic_sub_fetch(_Subend, _Value, 0) + _Value;
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Increment
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedIncrement16(char volatile *_Value) {
+ return __atomic_add_fetch(_Value, 1, 0);
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedIncrement(long volatile *_Value) {
+ return __atomic_add_fetch(_Value, 1, 0);
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedIncrement64(__int64 volatile *_Value) {
+ return __atomic_add_fetch(_Value, 1, 0);
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Decrement
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedDecrement16(char volatile *_Value) {
+ return __atomic_sub_fetch(_Value, 1, 0);
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedDecrement(long volatile *_Value) {
+ return __atomic_sub_fetch(_Value, 1, 0);
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedDecrement64(__int64 volatile *_Value) {
+ return __atomic_sub_fetch(_Value, 1, 0);
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked And
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedAnd8(char volatile *_Value, char _Mask) {
+ return __atomic_and_fetch(_Value, _Mask, 0);
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedAnd16(short volatile *_Value, short _Mask) {
+ return __atomic_and_fetch(_Value, _Mask, 0);
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedAnd(long volatile *_Value, long _Mask) {
+ return __atomic_and_fetch(_Value, _Mask, 0);
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask) {
+ return __atomic_and_fetch(_Value, _Mask, 0);
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Or
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedOr8(char volatile *_Value, char _Mask) {
+ return __atomic_or_fetch(_Value, _Mask, 0);
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedOr16(short volatile *_Value, short _Mask) {
+ return __atomic_or_fetch(_Value, _Mask, 0);
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedOr(long volatile *_Value, long _Mask) {
+ return __atomic_or_fetch(_Value, _Mask, 0);
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedOr64(__int64 volatile *_Value, __int64 _Mask) {
+ return __atomic_or_fetch(_Value, _Mask, 0);
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Xor
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedXor8(char volatile *_Value, char _Mask) {
+ return __atomic_xor_fetch(_Value, _Mask, 0);
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedXor16(short volatile *_Value, short _Mask) {
+ return __atomic_xor_fetch(_Value, _Mask, 0);
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedXor(long volatile *_Value, long _Mask) {
+ return __atomic_xor_fetch(_Value, _Mask, 0);
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedXor64(__int64 volatile *_Value, __int64 _Mask) {
+ return __atomic_xor_fetch(_Value, _Mask, 0);
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Exchange
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchange8(char volatile *_Target, char _Value) {
+ __atomic_exchange(_Target, &_Value, &_Value, 0);
+ return _Value;
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchange16(short volatile *_Target, short _Value) {
+ __atomic_exchange(_Target, &_Value, &_Value, 0);
+ return _Value;
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchange(long volatile *_Target, long _Value) {
+ __atomic_exchange(_Target, &_Value, &_Value, 0);
+ return _Value;
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) {
+ __atomic_exchange(_Target, &_Value, &_Value, 0);
+ return _Value;
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Interlocked Compare Exchange
+\*----------------------------------------------------------------------------*/
+static __inline__ char __attribute__((__always_inline__, __nodebug__))
+_InterlockedCompareExchange8(char volatile *_Destination,
+ char _Exchange, char _Comparand) {
+ __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
+ return _Comparand;
+}
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedCompareExchange16(short volatile *_Destination,
+ short _Exchange, short _Comparand) {
+ __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
+ return _Comparand;
+}
+static __inline__ long __attribute__((__always_inline__, __nodebug__))
+_InterlockedCompareExchange(long volatile *_Destination,
+ long _Exchange, long _Comparand) {
+ __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
+ return _Comparand;
+}
+#ifdef __x86_64__
+static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
+_InterlockedCompareExchange64(__int64 volatile *_Destination,
+ __int64 _Exchange, __int64 _Comparand) {
+ __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
+ return _Comparand;
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* Barriers
+\*----------------------------------------------------------------------------*/
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__attribute__((deprecated("use other intrinsics or C++11 atomics instead")))
+_ReadWriteBarrier(void) {
+ __asm__ volatile ("" : : : "memory");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__attribute__((deprecated("use other intrinsics or C++11 atomics instead")))
+_ReadBarrier(void) {
+ __asm__ volatile ("" : : : "memory");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__attribute__((deprecated("use other intrinsics or C++11 atomics instead")))
+_WriteBarrier(void) {
+ __asm__ volatile ("" : : : "memory");
+}
+/*----------------------------------------------------------------------------*\
+|* Misc
+\*----------------------------------------------------------------------------*/
+static __inline__ void * __attribute__((__always_inline__, __nodebug__))
+_AddressOfReturnAddress(void) {
+ return (void*)((char*)__builtin_frame_address(0) + sizeof(void*));
+}
+static __inline__ void * __attribute__((__always_inline__, __nodebug__))
+_ReturnAddress(void) {
+ return __builtin_return_address(0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INTRIN_H */
+#endif /* _MSC_VER */
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 63b1efc10537..95744693ac77 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -25,6 +25,9 @@
#error "Never use <avx2intrin.h> directly; include <immintrin.h> instead."
#endif
+#ifndef __AVX2INTRIN_H
+#define __AVX2INTRIN_H
+
/* SSE4 Multiple Packed Sums of Absolute Difference. */
#define _mm256_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw256((X), (Y), (M))
@@ -750,9 +753,9 @@ _mm256_broadcastsd_pd(__m128d __X)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm_broadcastsi128_si256(__m128i const *__a)
+_mm256_broadcastsi128_si256(__m128i __X)
{
- return (__m256i)__builtin_ia32_vbroadcastsi256(__a);
+ return (__m256i)__builtin_ia32_vbroadcastsi256(__X);
}
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
@@ -1058,7 +1061,7 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y)
#define _mm_mask_i32gather_epi64(a, m, i, mask, s) __extension__ ({ \
__m128i __a = (a); \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
__m128i __mask = (mask); \
(__m128i)__builtin_ia32_gatherd_q((__v2di)__a, (const __v2di *)__m, \
@@ -1066,7 +1069,7 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y)
#define _mm256_mask_i32gather_epi64(a, m, i, mask, s) __extension__ ({ \
__m256i __a = (a); \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
__m256i __mask = (mask); \
(__m256i)__builtin_ia32_gatherd_q256((__v4di)__a, (const __v4di *)__m, \
@@ -1074,7 +1077,7 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y)
#define _mm_mask_i64gather_epi64(a, m, i, mask, s) __extension__ ({ \
__m128i __a = (a); \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
__m128i __mask = (mask); \
(__m128i)__builtin_ia32_gatherq_q((__v2di)__a, (const __v2di *)__m, \
@@ -1082,7 +1085,7 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y)
#define _mm256_mask_i64gather_epi64(a, m, i, mask, s) __extension__ ({ \
__m256i __a = (a); \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m256i __i = (i); \
__m256i __mask = (mask); \
(__m256i)__builtin_ia32_gatherq_q256((__v4di)__a, (const __v4di *)__m, \
@@ -1173,29 +1176,31 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y)
(__v4si)_mm_set1_epi32(-1), (s)); })
#define _mm_i32gather_epi64(m, i, s) __extension__ ({ \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
(__m128i)__builtin_ia32_gatherd_q((__v2di)_mm_setzero_si128(), \
(const __v2di *)__m, (__v4si)__i, \
(__v2di)_mm_set1_epi64x(-1), (s)); })
#define _mm256_i32gather_epi64(m, i, s) __extension__ ({ \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
(__m256i)__builtin_ia32_gatherd_q256((__v4di)_mm256_setzero_si256(), \
(const __v4di *)__m, (__v4si)__i, \
(__v4di)_mm256_set1_epi64x(-1), (s)); })
#define _mm_i64gather_epi64(m, i, s) __extension__ ({ \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m128i __i = (i); \
(__m128i)__builtin_ia32_gatherq_q((__v2di)_mm_setzero_si128(), \
(const __v2di *)__m, (__v2di)__i, \
(__v2di)_mm_set1_epi64x(-1), (s)); })
#define _mm256_i64gather_epi64(m, i, s) __extension__ ({ \
- int const *__m = (m); \
+ long long const *__m = (m); \
__m256i __i = (i); \
(__m256i)__builtin_ia32_gatherq_q256((__v4di)_mm256_setzero_si256(), \
(const __v4di *)__m, (__v4di)__i, \
(__v4di)_mm256_set1_epi64x(-1), (s)); })
+
+#endif /* __AVX2INTRIN_H */
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 0683a65facc9..141c4d994bbc 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -25,6 +25,9 @@
#error "Never use <avxintrin.h> directly; include <immintrin.h> instead."
#endif
+#ifndef __AVXINTRIN_H
+#define __AVXINTRIN_H
+
typedef double __v4df __attribute__ ((__vector_size__ (32)));
typedef float __v8sf __attribute__ ((__vector_size__ (32)));
typedef long long __v4di __attribute__ ((__vector_size__ (32)));
@@ -432,21 +435,21 @@ static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi32(__m256i __a, int const __imm)
{
__v8si __b = (__v8si)__a;
- return __b[__imm];
+ return __b[__imm & 7];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi16(__m256i __a, int const __imm)
{
__v16hi __b = (__v16hi)__a;
- return __b[__imm];
+ return __b[__imm & 15];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi8(__m256i __a, int const __imm)
{
__v32qi __b = (__v32qi)__a;
- return __b[__imm];
+ return __b[__imm & 31];
}
#ifdef __x86_64__
@@ -454,7 +457,7 @@ static __inline long long __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi64(__m256i __a, const int __imm)
{
__v4di __b = (__v4di)__a;
- return __b[__imm];
+ return __b[__imm & 3];
}
#endif
@@ -1134,22 +1137,19 @@ _mm256_castsi256_si128(__m256i __a)
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_castpd128_pd256(__m128d __a)
{
- __m128d __zero = _mm_setzero_pd();
- return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 1, -1, -1);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
_mm256_castps128_ps256(__m128 __a)
{
- __m128 __zero = _mm_setzero_ps();
- return __builtin_shufflevector(__a, __zero, 0, 1, 2, 3, 4, 4, 4, 4);
+ return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, -1, -1, -1, -1);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_castsi128_si256(__m128i __a)
{
- __m128i __zero = _mm_setzero_si128();
- return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 1, -1, -1);
}
/* SIMD load ops (unaligned) */
@@ -1220,3 +1220,5 @@ _mm256_storeu2_m128i(__m128i *__addr_hi, __m128i *__addr_lo, __m256i __a)
__v128 = _mm256_extractf128_si256(__a, 1);
__builtin_ia32_storedqu((char *)__addr_hi, (__v16qi)__v128);
}
+
+#endif /* __AVXINTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 7b012384a2aa..8f12caeb4978 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -25,10 +25,132 @@
#error this header is for x86 only
#endif
+/* Features in %ecx for level 1 */
+#define bit_SSE3 0x00000001
+#define bit_PCLMULQDQ 0x00000002
+#define bit_DTES64 0x00000004
+#define bit_MONITOR 0x00000008
+#define bit_DSCPL 0x00000010
+#define bit_VMX 0x00000020
+#define bit_SMX 0x00000040
+#define bit_EIST 0x00000080
+#define bit_TM2 0x00000100
+#define bit_SSSE3 0x00000200
+#define bit_CNXTID 0x00000400
+#define bit_FMA 0x00001000
+#define bit_CMPXCHG16B 0x00002000
+#define bit_xTPR 0x00004000
+#define bit_PDCM 0x00008000
+#define bit_PCID 0x00020000
+#define bit_DCA 0x00040000
+#define bit_SSE41 0x00080000
+#define bit_SSE42 0x00100000
+#define bit_x2APIC 0x00200000
+#define bit_MOVBE 0x00400000
+#define bit_POPCNT 0x00800000
+#define bit_TSCDeadline 0x01000000
+#define bit_AESNI 0x02000000
+#define bit_XSAVE 0x04000000
+#define bit_OSXSAVE 0x08000000
+#define bit_AVX 0x10000000
+#define bit_RDRAND 0x40000000
+
+/* Features in %edx for level 1 */
+#define bit_FPU 0x00000001
+#define bit_VME 0x00000002
+#define bit_DE 0x00000004
+#define bit_PSE 0x00000008
+#define bit_TSC 0x00000010
+#define bit_MSR 0x00000020
+#define bit_PAE 0x00000040
+#define bit_MCE 0x00000080
+#define bit_CX8 0x00000100
+#define bit_APIC 0x00000200
+#define bit_SEP 0x00000800
+#define bit_MTRR 0x00001000
+#define bit_PGE 0x00002000
+#define bit_MCA 0x00004000
+#define bit_CMOV 0x00008000
+#define bit_PAT 0x00010000
+#define bit_PSE36 0x00020000
+#define bit_PSN 0x00040000
+#define bit_CLFSH 0x00080000
+#define bit_DS 0x00200000
+#define bit_ACPI 0x00400000
+#define bit_MMX 0x00800000
+#define bit_FXSR 0x01000000
+#define bit_SSE 0x02000000
+#define bit_SSE2 0x04000000
+#define bit_SS 0x08000000
+#define bit_HTT 0x10000000
+#define bit_TM 0x20000000
+#define bit_PBE 0x80000000
+
+/* Features in %ebx for level 7 sub-leaf 0 */
+#define bit_FSGSBASE 0x00000001
+#define bit_SMEP 0x00000080
+#define bit_ENH_MOVSB 0x00000200
+
+/* PIC on i386 uses %ebx, so preserve it. */
+#if __i386__
+#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+ __asm(" pushl %%ebx\n" \
+ " cpuid\n" \
+ " mov %%ebx,%1\n" \
+ " popl %%ebx" \
+ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level))
+
+#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+ __asm(" pushl %%ebx\n" \
+ " cpuid\n" \
+ " mov %%ebx,%1\n" \
+ " popl %%ebx" \
+ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level), "2"(__count))
+#else
+#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level))
+
+#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level), "2"(__count))
+#endif
+
static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
unsigned int *__ebx, unsigned int *__ecx,
unsigned int *__edx) {
- __asm("cpuid" : "=a"(*__eax), "=b" (*__ebx), "=c"(*__ecx), "=d"(*__edx)
- : "0"(__level));
+ __cpuid(__level, *__eax, *__ebx, *__ecx, *__edx);
return 1;
}
+
+static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig)
+{
+ unsigned int __eax, __ebx, __ecx, __edx;
+#if __i386__
+ int __cpuid_supported;
+
+ __asm(" pushfl\n"
+ " popl %%eax\n"
+ " movl %%eax,%%ecx\n"
+ " xorl $0x00200000,%%eax\n"
+ " pushl %%eax\n"
+ " popfl\n"
+ " pushfl\n"
+ " popl %%eax\n"
+ " movl $0,%0\n"
+ " cmpl %%eax,%%ecx\n"
+ " je 1f\n"
+ " movl $1,%0\n"
+ "1:"
+ : "=r" (__cpuid_supported) : : "eax", "ecx");
+ if (!__cpuid_supported)
+ return 0;
+#endif
+
+ __cpuid(__level, __eax, __ebx, __ecx, __edx);
+ if (__sig)
+ *__sig = __ebx;
+ return __eax;
+}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 56c6c2285546..b3f8569524b9 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -245,13 +245,15 @@ _mm_cmple_sd(__m128d __a, __m128d __b)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__b, __a, 1);
+ __m128d __c = __builtin_ia32_cmpsd(__b, __a, 1);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__b, __a, 2);
+ __m128d __c = __builtin_ia32_cmpsd(__b, __a, 2);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -287,13 +289,15 @@ _mm_cmpnle_sd(__m128d __a, __m128d __b)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__b, __a, 5);
+ __m128d __c = __builtin_ia32_cmpsd(__b, __a, 5);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__b, __a, 6);
+ __m128d __c = __builtin_ia32_cmpsd(__b, __a, 6);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
@@ -822,7 +826,9 @@ _mm_xor_si128(__m128i __a, __m128i __b)
}
#define _mm_slli_si128(a, count) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128i __a = (a); \
+ _Pragma("clang diagnostic pop"); \
(__m128i)__builtin_ia32_pslldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -887,7 +893,9 @@ _mm_sra_epi32(__m128i __a, __m128i __count)
#define _mm_srli_si128(a, count) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128i __a = (a); \
+ _Pragma("clang diagnostic pop"); \
(__m128i)__builtin_ia32_psrldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1210,6 +1218,14 @@ _mm_stream_si32(int *__p, int __a)
__builtin_ia32_movnti(__p, __a);
}
+#ifdef __x86_64__
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_si64(long long *__p, long long __a)
+{
+ __builtin_ia32_movnti64(__p, __a);
+}
+#endif
+
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_clflush(void const *__p)
{
@@ -1250,7 +1266,7 @@ static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_extract_epi16(__m128i __a, int __imm)
{
__v8hi __b = (__v8hi)__a;
- return (unsigned short)__b[__imm];
+ return (unsigned short)__b[__imm & 7];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1268,20 +1284,26 @@ _mm_movemask_epi8(__m128i __a)
}
#define _mm_shuffle_epi32(a, imm) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128i __a = (a); \
+ _Pragma("clang diagnostic pop"); \
(__m128i)__builtin_shufflevector((__v4si)__a, (__v4si) _mm_set1_epi32(0), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6); })
#define _mm_shufflelo_epi16(a, imm) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128i __a = (a); \
+ _Pragma("clang diagnostic pop"); \
(__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi) _mm_set1_epi16(0), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
4, 5, 6, 7); })
#define _mm_shufflehi_epi16(a, imm) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128i __a = (a); \
+ _Pragma("clang diagnostic pop"); \
(__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi) _mm_set1_epi16(0), \
0, 1, 2, 3, \
4 + (((imm) & 0x03) >> 0), \
@@ -1344,7 +1366,7 @@ _mm_movepi64_pi64(__m128i __a)
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_movpi64_pi64(__m64 __a)
+_mm_movpi64_epi64(__m64 __a)
{
return (__m128i){ (long long)__a, 0 };
}
@@ -1374,8 +1396,10 @@ _mm_movemask_pd(__m128d __a)
}
#define _mm_shuffle_pd(a, b, i) __extension__ ({ \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\""); \
__m128d __a = (a); \
__m128d __b = (b); \
+ _Pragma("clang diagnostic pop"); \
__builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index a6d7812a4696..f3614c0e3912 100644
--- a/lib/Headers/f16cintrin.h
+++ b/lib/Headers/f16cintrin.h
@@ -1,6 +1,6 @@
-/*===---- f16cintrin.h - F16C intrinsics ---------------------------------===
+/*===---- f16cintrin.h - F16C intrinsics -----------------------------------===
*
- * Permission is hereby granted, free of charge, to any person obtaining __a copy
+ * 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
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index fea7c3ba29f1..15d6e05f979a 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -111,4 +111,8 @@ _xtest(void)
}
#endif
+#ifdef __SHA__
+#include <shaintrin.h>
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h
index ecd09a4a246d..91bd404650e8 100644
--- a/lib/Headers/limits.h
+++ b/lib/Headers/limits.h
@@ -87,8 +87,10 @@
#define CHAR_MAX __SCHAR_MAX__
#endif
-/* C99 5.2.4.2.1: Added long long. */
-#if __STDC_VERSION__ >= 199901
+/* C99 5.2.4.2.1: Added long long.
+ C++11 18.3.3.2: same contents as the Standard C Library header <limits.h>.
+ */
+#if __STDC_VERSION__ >= 199901 || __cplusplus >= 201103L
#undef LLONG_MIN
#undef LLONG_MAX
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
index aa219cb407c9..9f7944dedbb0 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.map
@@ -4,6 +4,16 @@ module _Builtin_intrinsics [system] {
header "altivec.h"
}
+ explicit module arm {
+ requires arm
+
+ explicit module neon {
+ requires neon
+ header "arm_neon.h"
+ export *
+ }
+ }
+
explicit module intel {
requires x86
export *
@@ -34,6 +44,7 @@ module _Builtin_intrinsics [system] {
explicit module sse {
requires sse
export mmx
+ export * // note: for hackish <emmintrin.h> dependency
header "xmmintrin.h"
}
diff --git a/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h
index 2d529c66349c..9825bd8c9700 100644
--- a/lib/Headers/prfchwintrin.h
+++ b/lib/Headers/prfchwintrin.h
@@ -25,6 +25,9 @@
#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> or <mm3dnow.h> instead."
#endif
+#ifndef __PRFCHWINTRIN_H
+#define __PRFCHWINTRIN_H
+
#if defined(__PRFCHW__) || defined(__3dNOW__)
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_m_prefetchw(void *__P)
@@ -32,3 +35,5 @@ _m_prefetchw(void *__P)
__builtin_prefetch (__P, 1, 3 /* _MM_HINT_T0 */);
}
#endif
+
+#endif /* __PRFCHWINTRIN_H */
diff --git a/lib/Headers/rdseedintrin.h b/lib/Headers/rdseedintrin.h
index 54aabd177a1d..0fef1fa49680 100644
--- a/lib/Headers/rdseedintrin.h
+++ b/lib/Headers/rdseedintrin.h
@@ -25,6 +25,9 @@
#error "Never use <rdseedintrin.h> directly; include <x86intrin.h> instead."
#endif
+#ifndef __RDSEEDINTRIN_H
+#define __RDSEEDINTRIN_H
+
#ifdef __RDSEED__
static __inline__ int __attribute__((__always_inline__, __nodebug__))
_rdseed16_step(unsigned short *__p)
@@ -46,3 +49,4 @@ _rdseed64_step(unsigned long long *__p)
}
#endif
#endif /* __RDSEED__ */
+#endif /* __RDSEEDINTRIN_H */
diff --git a/lib/Headers/rtmintrin.h b/lib/Headers/rtmintrin.h
index bdc2b994264f..26149ca8522d 100644
--- a/lib/Headers/rtmintrin.h
+++ b/lib/Headers/rtmintrin.h
@@ -25,6 +25,9 @@
#error "Never use <rtmintrin.h> directly; include <immintrin.h> instead."
#endif
+#ifndef __RTMINTRIN_H
+#define __RTMINTRIN_H
+
#define _XBEGIN_STARTED (~0u)
#define _XABORT_EXPLICIT (1 << 0)
#define _XABORT_RETRY (1 << 1)
@@ -47,3 +50,5 @@ _xend(void)
}
#define _xabort(imm) __builtin_ia32_xabort((imm))
+
+#endif /* __RTMINTRIN_H */
diff --git a/lib/Headers/shaintrin.h b/lib/Headers/shaintrin.h
new file mode 100644
index 000000000000..66ed0554b64d
--- /dev/null
+++ b/lib/Headers/shaintrin.h
@@ -0,0 +1,74 @@
+/*===---- shaintrin.h - SHA 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 <shaintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __SHAINTRIN_H
+#define __SHAINTRIN_H
+
+#if !defined (__SHA__)
+# error "SHA instructions not enabled"
+#endif
+
+#define _mm_sha1rnds4_epu32(V1, V2, M) __extension__ ({ \
+ __builtin_ia32_sha1rnds4((V1), (V2), (M)); })
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha1nexte_epu32(__m128i __X, __m128i __Y)
+{
+ return __builtin_ia32_sha1nexte(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha1msg1_epu32(__m128i __X, __m128i __Y)
+{
+ return __builtin_ia32_sha1msg1(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha1msg2_epu32(__m128i __X, __m128i __Y)
+{
+ return __builtin_ia32_sha1msg2(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha256rnds2_epu32(__m128i __X, __m128i __Y, __m128i __Z)
+{
+ return __builtin_ia32_sha256rnds2(__X, __Y, __Z);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha256msg1_epu32(__m128i __X, __m128i __Y)
+{
+ return __builtin_ia32_sha256msg1(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sha256msg2_epu32(__m128i __X, __m128i __Y)
+{
+ return __builtin_ia32_sha256msg2(__X, __Y);
+}
+
+#endif /* __SHAINTRIN_H */
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 498f6f0dcd86..53b3ccb4310c 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -197,7 +197,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
#define _mm_extract_ps(X, N) (__extension__ \
({ union { int __i; float __f; } __t; \
__v4sf __a = (__v4sf)(X); \
- __t.__f = __a[N]; \
+ __t.__f = __a[(N) & 3]; \
__t.__i;}))
/* Miscellaneous insert and extract macros. */
@@ -215,14 +215,14 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* Insert int into packed integer array at index. */
#define _mm_insert_epi8(X, I, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- __a[(N)] = (I); \
+ __a[(N) & 15] = (I); \
__a;}))
#define _mm_insert_epi32(X, I, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- __a[(N)] = (I); \
+ __a[(N) & 3] = (I); \
__a;}))
#ifdef __x86_64__
#define _mm_insert_epi64(X, I, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[(N)] = (I); \
+ __a[(N) & 1] = (I); \
__a;}))
#endif /* __x86_64__ */
@@ -230,12 +230,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
* as a zero extended value, so it is unsigned.
*/
#define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- (unsigned char)__a[(N)];}))
+ (int)(unsigned char) \
+ __a[(N) & 15];}))
#define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- (unsigned)__a[(N)];}))
+ __a[(N) & 3];}))
#ifdef __x86_64__
#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[(N)];}))
+ __a[(N) & 1];}))
#endif /* __x86_64 */
/* SSE4 128-bit Packed Integer Comparisons. */
diff --git a/lib/Headers/tbmintrin.h b/lib/Headers/tbmintrin.h
new file mode 100644
index 000000000000..f95e34fbc185
--- /dev/null
+++ b/lib/Headers/tbmintrin.h
@@ -0,0 +1,158 @@
+/*===---- tbmintrin.h - TBM 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 __TBM__
+#error "TBM instruction set is not enabled"
+#endif
+
+#ifndef __X86INTRIN_H
+#error "Never use <tbmintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __TBMINTRIN_H
+#define __TBMINTRIN_H
+
+#define __bextri_u32(a, b) (__builtin_ia32_bextri_u32((a), (b)))
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blcfill_u32(unsigned int a)
+{
+ return a & (a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blci_u32(unsigned int a)
+{
+ return a | ~(a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blcic_u32(unsigned int a)
+{
+ return ~a & (a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blcmsk_u32(unsigned int a)
+{
+ return a ^ (a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blcs_u32(unsigned int a)
+{
+ return a | (a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blsfill_u32(unsigned int a)
+{
+ return a | (a - 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blsic_u32(unsigned int a)
+{
+ return ~a | (a - 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__t1mskc_u32(unsigned int a)
+{
+ return ~a | (a + 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__tzmsk_u32(unsigned int a)
+{
+ return ~a & (a - 1);
+}
+
+#ifdef __x86_64__
+#define __bextri_u64(a, b) (__builtin_ia32_bextri_u64((a), (int)(b)))
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blcfill_u64(unsigned long long a)
+{
+ return a & (a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blci_u64(unsigned long long a)
+{
+ return a | ~(a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blcic_u64(unsigned long long a)
+{
+ return ~a & (a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blcmsk_u64(unsigned long long a)
+{
+ return a ^ (a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blcs_u64(unsigned long long a)
+{
+ return a | (a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blsfill_u64(unsigned long long a)
+{
+ return a | (a - 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__blsic_u64(unsigned long long a)
+{
+ return ~a | (a - 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__t1mskc_u64(unsigned long long a)
+{
+ return ~a | (a + 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__,
+ __nodebug__))
+__tzmsk_u64(unsigned long long a)
+{
+ return ~a & (a - 1);
+}
+#endif
+
+#endif /* __TBMINTRIN_H */
diff --git a/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
index 4fa1cf72f2af..a48e267e60d0 100644
--- a/lib/Headers/tgmath.h
+++ b/lib/Headers/tgmath.h
@@ -1340,15 +1340,15 @@ static long double _Complex
// creal
-static float _Complex
+static float
_TG_ATTRS
__tg_creal(float __x) {return __x;}
-static double _Complex
+static double
_TG_ATTRS
__tg_creal(double __x) {return __x;}
-static long double _Complex
+static long double
_TG_ATTRS
__tg_creal(long double __x) {return __x;}
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index e94fd70900cc..685c1dfd04e8 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -27,8 +27,8 @@
#define __CLANG_UNWIND_H
#if __has_include_next(<unwind.h>)
-/* Darwin and libunwind provide an unwind.h. If that's available, use
- * it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
+/* Darwin (from 11.x on) and libunwind provide an unwind.h. If that's available,
+ * use it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
* so define that around the include.*/
# ifndef _GNU_SOURCE
# define _SHOULD_UNDEFINE_GNU_SOURCE
@@ -66,7 +66,17 @@ extern "C" {
#pragma GCC visibility push(default)
#endif
+typedef uintptr_t _Unwind_Word;
+typedef intptr_t _Unwind_Sword;
+typedef uintptr_t _Unwind_Ptr;
+typedef uintptr_t _Unwind_Internal_Ptr;
+typedef uint64_t _Unwind_Exception_Class;
+
+typedef intptr_t _sleb128_t;
+typedef uintptr_t _uleb128_t;
+
struct _Unwind_Context;
+struct _Unwind_Exception;
typedef enum {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
@@ -81,8 +91,43 @@ typedef enum {
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16 /* gcc extension to C++ ABI */
+} _Unwind_Action;
+
+typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code,
+ struct _Unwind_Exception *);
+
+struct _Unwind_Exception {
+ _Unwind_Exception_Class exception_class;
+ _Unwind_Exception_Cleanup_Fn exception_cleanup;
+ _Unwind_Word private_1;
+ _Unwind_Word private_2;
+ /* The Itanium ABI requires that _Unwind_Exception objects are "double-word
+ * aligned". GCC has interpreted this to mean "use the maximum useful
+ * alignment for the target"; so do we. */
+} __attribute__((__aligned__));
-#ifdef __arm__
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action,
+ _Unwind_Exception_Class,
+ struct _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_Personality_Fn __personality_routine;
+
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
+ void *);
+
+#if defined(__arm__) && !defined(__APPLE__)
typedef enum {
_UVRSC_CORE = 0, /* integer register */
@@ -111,14 +156,116 @@ _Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context,
_Unwind_VRS_DataRepresentation __representation,
void *__valuep);
+_Unwind_VRS_Result _Unwind_VRS_Set(struct _Unwind_Context *__context,
+ _Unwind_VRS_RegClass __regclass,
+ uint32_t __regno,
+ _Unwind_VRS_DataRepresentation __representation,
+ void *__valuep);
+
+static __inline__
+_Unwind_Word _Unwind_GetGR(struct _Unwind_Context *__context, int __index) {
+ _Unwind_Word __value;
+ _Unwind_VRS_Get(__context, _UVRSC_CORE, __index, _UVRSD_UINT32, &__value);
+ return __value;
+}
+
+static __inline__
+void _Unwind_SetGR(struct _Unwind_Context *__context, int __index,
+ _Unwind_Word __value) {
+ _Unwind_VRS_Set(__context, _UVRSC_CORE, __index, _UVRSD_UINT32, &__value);
+}
+
+static __inline__
+_Unwind_Word _Unwind_GetIP(struct _Unwind_Context *__context) {
+ _Unwind_Word __ip = _Unwind_GetGR(__context, 15);
+ return __ip & ~(_Unwind_Word)(0x1); /* Remove thumb mode bit. */
+}
+
+static __inline__
+void _Unwind_SetIP(struct _Unwind_Context *__context, _Unwind_Word __value) {
+ _Unwind_Word __thumb_mode_bit = _Unwind_GetGR(__context, 15) & 0x1;
+ _Unwind_SetGR(__context, 15, __value | __thumb_mode_bit);
+}
+#else
+_Unwind_Word _Unwind_GetGR(struct _Unwind_Context *, int);
+void _Unwind_SetGR(struct _Unwind_Context *, int, _Unwind_Word);
+
+_Unwind_Word _Unwind_GetIP(struct _Unwind_Context *);
+void _Unwind_SetIP(struct _Unwind_Context *, _Unwind_Word);
+#endif
+
+
+_Unwind_Word _Unwind_GetIPInfo(struct _Unwind_Context *, int *);
+
+_Unwind_Word _Unwind_GetCFA(struct _Unwind_Context *);
+
+void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *);
+
+_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 *);
+
+#endif
+
+_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
+
+/* setjmp(3)/longjmp(3) stuff */
+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_Stop_Fn, void *);
+void _Unwind_SjLj_Resume(struct _Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *);
+
+void *_Unwind_FindEnclosingFunction(void *);
+
+#ifdef __APPLE__
+
+_Unwind_Ptr _Unwind_GetDataRelBase(struct _Unwind_Context *)
+ __attribute__((unavailable));
+_Unwind_Ptr _Unwind_GetTextRelBase(struct _Unwind_Context *)
+ __attribute__((unavailable));
+
+/* Darwin-specific functions */
+void __register_frame(const void *);
+void __deregister_frame(const void *);
+
+struct dwarf_eh_bases {
+ uintptr_t tbase;
+ uintptr_t dbase;
+ uintptr_t func;
+};
+void *_Unwind_Find_FDE(const void *, struct dwarf_eh_bases *);
+
+void __register_frame_info_bases(const void *, void *, void *, void *)
+ __attribute__((unavailable));
+void __register_frame_info(const void *, void *) __attribute__((unavailable));
+void __register_frame_info_table_bases(const void *, void*, void *, void *)
+ __attribute__((unavailable));
+void __register_frame_info_table(const void *, void *)
+ __attribute__((unavailable));
+void __register_frame_table(const void *) __attribute__((unavailable));
+void __deregister_frame_info(const void *) __attribute__((unavailable));
+void __deregister_frame_info_bases(const void *)__attribute__((unavailable));
+
#else
-uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
+_Unwind_Ptr _Unwind_GetDataRelBase(struct _Unwind_Context *);
+_Unwind_Ptr _Unwind_GetTextRelBase(struct _Unwind_Context *);
#endif
-typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
-_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 94fbe2fe234d..399016f11c97 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -66,6 +66,10 @@
#include <xopintrin.h>
#endif
+#ifdef __TBM__
+#include <tbmintrin.h>
+#endif
+
#ifdef __F16C__
#include <f16cintrin.h>
#endif
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 8c5fc9528cf0..c68d3ed7b678 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -218,7 +218,9 @@ _mm_cmple_ps(__m128 __a, __m128 __b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__b, __a, 1);
+ return (__m128)__builtin_shufflevector(__a,
+ __builtin_ia32_cmpss(__b, __a, 1),
+ 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -230,7 +232,9 @@ _mm_cmpgt_ps(__m128 __a, __m128 __b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__b, __a, 2);
+ return (__m128)__builtin_shufflevector(__a,
+ __builtin_ia32_cmpss(__b, __a, 2),
+ 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -278,7 +282,9 @@ _mm_cmpnle_ps(__m128 __a, __m128 __b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__b, __a, 5);
+ return (__m128)__builtin_shufflevector(__a,
+ __builtin_ia32_cmpss(__b, __a, 5),
+ 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -290,7 +296,9 @@ _mm_cmpngt_ps(__m128 __a, __m128 __b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__b, __a, 6);
+ return (__m128)__builtin_shufflevector(__a,
+ __builtin_ia32_cmpss(__b, __a, 6),
+ 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -983,12 +991,10 @@ do { \
#define _m_ _mm_
#define _m_ _mm_
-#if !__has_feature(modules)
/* Ugly hack for backwards-compatibility (compatible with gcc) */
#ifdef __SSE2__
#include <emmintrin.h>
#endif
-#endif
#endif /* __SSE__ */
diff --git a/lib/Headers/xopintrin.h b/lib/Headers/xopintrin.h
index 9a5824c97105..cc94ca0264c0 100644
--- a/lib/Headers/xopintrin.h
+++ b/lib/Headers/xopintrin.h
@@ -342,6 +342,399 @@ _mm_sha_epi64(__m128i __A, __m128i __B)
__m128i __B = (B); \
(__m128i)__builtin_ia32_vpcomq((__v2di)__A, (__v2di)__B, (N)); })
+#define _MM_PCOMCTRL_LT 0
+#define _MM_PCOMCTRL_LE 1
+#define _MM_PCOMCTRL_GT 2
+#define _MM_PCOMCTRL_GE 3
+#define _MM_PCOMCTRL_EQ 4
+#define _MM_PCOMCTRL_NEQ 5
+#define _MM_PCOMCTRL_FALSE 6
+#define _MM_PCOMCTRL_TRUE 7
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epu8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu8(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epu16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu16(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epu32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu32(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epu64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epu64(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epi8(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi8(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epi16(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi16(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epi32(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi32(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comlt_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_LT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comle_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_LE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comgt_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_GT);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comge_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_GE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comeq_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_EQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comneq_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_NEQ);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comfalse_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_FALSE);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_comtrue_epi64(__m128i __A, __m128i __B)
+{
+ return _mm_com_epi64(__A, __B, _MM_PCOMCTRL_TRUE);
+}
+
#define _mm_permute2_pd(X, Y, C, I) __extension__ ({ \
__m128d __X = (X); \
__m128d __Y = (Y); \
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
new file mode 100644
index 000000000000..c4ff5a01307e
--- /dev/null
+++ b/lib/Index/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_clang_library(clangIndex
+ CommentToXML.cpp
+ SimpleFormatContext.h
+ USRGeneration.cpp
+ )
+
+target_link_libraries(clangIndex
+ clangBasic
+ clangAST
+ clangFormat
+ )
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
new file mode 100644
index 000000000000..0a9619dfe086
--- /dev/null
+++ b/lib/Index/CommentToXML.cpp
@@ -0,0 +1,1136 @@
+//===--- CommentToXML.cpp - Convert comments to XML representation --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/CommentToXML.h"
+#include "SimpleFormatContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/Format/Format.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::comments;
+using namespace clang::index;
+
+namespace {
+
+/// This comparison will sort parameters with valid index by index, then vararg
+/// parameters, and invalid (unresolved) parameters last.
+class ParamCommandCommentCompareIndex {
+public:
+ bool operator()(const ParamCommandComment *LHS,
+ const ParamCommandComment *RHS) const {
+ unsigned LHSIndex = UINT_MAX;
+ unsigned RHSIndex = UINT_MAX;
+
+ if (LHS->isParamIndexValid()) {
+ if (LHS->isVarArgParam())
+ LHSIndex = UINT_MAX - 1;
+ else
+ LHSIndex = LHS->getParamIndex();
+ }
+ if (RHS->isParamIndexValid()) {
+ if (RHS->isVarArgParam())
+ RHSIndex = UINT_MAX - 1;
+ else
+ RHSIndex = RHS->getParamIndex();
+ }
+ return LHSIndex < RHSIndex;
+ }
+};
+
+/// This comparison will sort template parameters in the following order:
+/// \li real template parameters (depth = 1) in index order;
+/// \li all other names (depth > 1);
+/// \li unresolved names.
+class TParamCommandCommentComparePosition {
+public:
+ bool operator()(const TParamCommandComment *LHS,
+ const TParamCommandComment *RHS) const {
+ // Sort unresolved names last.
+ if (!LHS->isPositionValid())
+ return false;
+ if (!RHS->isPositionValid())
+ return true;
+
+ if (LHS->getDepth() > 1)
+ return false;
+ if (RHS->getDepth() > 1)
+ return true;
+
+ // Sort template parameters in index order.
+ if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
+ return LHS->getIndex(0) < RHS->getIndex(0);
+
+ // Leave all other names in source order.
+ return true;
+ }
+};
+
+/// Separate parts of a FullComment.
+struct FullCommentParts {
+ /// Take a full comment apart and initialize members accordingly.
+ FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits);
+
+ const BlockContentComment *Brief;
+ const BlockContentComment *Headerfile;
+ const ParagraphComment *FirstParagraph;
+ SmallVector<const BlockCommandComment *, 4> Returns;
+ SmallVector<const ParamCommandComment *, 8> Params;
+ SmallVector<const TParamCommandComment *, 4> TParams;
+ llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
+ SmallVector<const BlockContentComment *, 8> MiscBlocks;
+};
+
+FullCommentParts::FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits) :
+ Brief(NULL), Headerfile(NULL), FirstParagraph(NULL) {
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ const Comment *Child = *I;
+ if (!Child)
+ continue;
+ switch (Child->getCommentKind()) {
+ case Comment::NoCommentKind:
+ continue;
+
+ case Comment::ParagraphCommentKind: {
+ const ParagraphComment *PC = cast<ParagraphComment>(Child);
+ if (PC->isWhitespace())
+ break;
+ if (!FirstParagraph)
+ FirstParagraph = PC;
+
+ MiscBlocks.push_back(PC);
+ break;
+ }
+
+ case Comment::BlockCommandCommentKind: {
+ const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
+ const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
+ if (!Brief && Info->IsBriefCommand) {
+ Brief = BCC;
+ break;
+ }
+ if (!Headerfile && Info->IsHeaderfileCommand) {
+ Headerfile = BCC;
+ break;
+ }
+ if (Info->IsReturnsCommand) {
+ Returns.push_back(BCC);
+ break;
+ }
+ if (Info->IsThrowsCommand) {
+ Exceptions.push_back(BCC);
+ break;
+ }
+ MiscBlocks.push_back(BCC);
+ break;
+ }
+
+ case Comment::ParamCommandCommentKind: {
+ const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
+ if (!PCC->hasParamName())
+ break;
+
+ if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
+ break;
+
+ Params.push_back(PCC);
+ break;
+ }
+
+ case Comment::TParamCommandCommentKind: {
+ const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
+ if (!TPCC->hasParamName())
+ break;
+
+ if (!TPCC->hasNonWhitespaceParagraph())
+ break;
+
+ TParams.push_back(TPCC);
+ break;
+ }
+
+ case Comment::VerbatimBlockCommentKind:
+ MiscBlocks.push_back(cast<BlockCommandComment>(Child));
+ break;
+
+ case Comment::VerbatimLineCommentKind: {
+ const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
+ const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
+ if (!Info->IsDeclarationCommand)
+ MiscBlocks.push_back(VLC);
+ break;
+ }
+
+ case Comment::TextCommentKind:
+ case Comment::InlineCommandCommentKind:
+ case Comment::HTMLStartTagCommentKind:
+ case Comment::HTMLEndTagCommentKind:
+ case Comment::VerbatimBlockLineCommentKind:
+ case Comment::FullCommentKind:
+ llvm_unreachable("AST node of this kind can't be a child of "
+ "a FullComment");
+ }
+ }
+
+ // Sort params in order they are declared in the function prototype.
+ // Unresolved parameters are put at the end of the list in the same order
+ // they were seen in the comment.
+ std::stable_sort(Params.begin(), Params.end(),
+ ParamCommandCommentCompareIndex());
+
+ std::stable_sort(TParams.begin(), TParams.end(),
+ TParamCommandCommentComparePosition());
+}
+
+void printHTMLStartTagComment(const HTMLStartTagComment *C,
+ llvm::raw_svector_ostream &Result) {
+ Result << "<" << C->getTagName();
+
+ if (C->getNumAttrs() != 0) {
+ for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
+ Result << " ";
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+ Result << Attr.Name;
+ if (!Attr.Value.empty())
+ Result << "=\"" << Attr.Value << "\"";
+ }
+ }
+
+ if (!C->isSelfClosing())
+ Result << ">";
+ else
+ Result << "/>";
+}
+
+class CommentASTToHTMLConverter :
+ public ConstCommentVisitor<CommentASTToHTMLConverter> {
+public:
+ /// \param Str accumulator for HTML.
+ CommentASTToHTMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits) :
+ FC(FC), Result(Str), Traits(Traits)
+ { }
+
+ // Inline content.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block content.
+ void visitParagraphComment(const ParagraphComment *C);
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+ void visitFullComment(const FullComment *C);
+
+ // Helpers.
+
+ /// Convert a paragraph that is not a block by itself (an argument to some
+ /// command).
+ void visitNonStandaloneParagraphComment(const ParagraphComment *C);
+
+ void appendToResultWithHTMLEscaping(StringRef S);
+
+private:
+ const FullComment *FC;
+ /// Output stream for HTML.
+ llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
+};
+} // end unnamed namespace
+
+void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
+ appendToResultWithHTMLEscaping(C->getText());
+}
+
+void CommentASTToHTMLConverter::visitInlineCommandComment(
+ const InlineCommandComment *C) {
+ // Nothing to render if no arguments supplied.
+ if (C->getNumArgs() == 0)
+ return;
+
+ // Nothing to render if argument is empty.
+ StringRef Arg0 = C->getArgText(0);
+ if (Arg0.empty())
+ return;
+
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
+ appendToResultWithHTMLEscaping(C->getArgText(i));
+ Result << " ";
+ }
+ return;
+
+ case InlineCommandComment::RenderBold:
+ assert(C->getNumArgs() == 1);
+ Result << "<b>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result << "</b>";
+ return;
+ case InlineCommandComment::RenderMonospaced:
+ assert(C->getNumArgs() == 1);
+ Result << "<tt>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result<< "</tt>";
+ return;
+ case InlineCommandComment::RenderEmphasized:
+ assert(C->getNumArgs() == 1);
+ Result << "<em>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result << "</em>";
+ return;
+ }
+}
+
+void CommentASTToHTMLConverter::visitHTMLStartTagComment(
+ const HTMLStartTagComment *C) {
+ printHTMLStartTagComment(C, Result);
+}
+
+void CommentASTToHTMLConverter::visitHTMLEndTagComment(
+ const HTMLEndTagComment *C) {
+ Result << "</" << C->getTagName() << ">";
+}
+
+void CommentASTToHTMLConverter::visitParagraphComment(
+ const ParagraphComment *C) {
+ if (C->isWhitespace())
+ return;
+
+ Result << "<p>";
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+ Result << "</p>";
+}
+
+void CommentASTToHTMLConverter::visitBlockCommandComment(
+ const BlockCommandComment *C) {
+ const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
+ if (Info->IsBriefCommand) {
+ Result << "<p class=\"para-brief\">";
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</p>";
+ return;
+ }
+ if (Info->IsReturnsCommand) {
+ Result << "<p class=\"para-returns\">"
+ "<span class=\"word-returns\">Returns</span> ";
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</p>";
+ return;
+ }
+ // We don't know anything about this command. Just render the paragraph.
+ visit(C->getParagraph());
+}
+
+void CommentASTToHTMLConverter::visitParamCommandComment(
+ const ParamCommandComment *C) {
+ if (C->isParamIndexValid()) {
+ if (C->isVarArgParam()) {
+ Result << "<dt class=\"param-name-index-vararg\">";
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ } else {
+ Result << "<dt class=\"param-name-index-"
+ << C->getParamIndex()
+ << "\">";
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ }
+ } else {
+ Result << "<dt class=\"param-name-index-invalid\">";
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
+ Result << "</dt>";
+
+ if (C->isParamIndexValid()) {
+ if (C->isVarArgParam())
+ Result << "<dd class=\"param-descr-index-vararg\">";
+ else
+ Result << "<dd class=\"param-descr-index-"
+ << C->getParamIndex()
+ << "\">";
+ } else
+ Result << "<dd class=\"param-descr-index-invalid\">";
+
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</dd>";
+}
+
+void CommentASTToHTMLConverter::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ if (C->isPositionValid()) {
+ if (C->getDepth() == 1)
+ Result << "<dt class=\"tparam-name-index-"
+ << C->getIndex(0)
+ << "\">";
+ else
+ Result << "<dt class=\"tparam-name-index-other\">";
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ } else {
+ Result << "<dt class=\"tparam-name-index-invalid\">";
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
+
+ Result << "</dt>";
+
+ if (C->isPositionValid()) {
+ if (C->getDepth() == 1)
+ Result << "<dd class=\"tparam-descr-index-"
+ << C->getIndex(0)
+ << "\">";
+ else
+ Result << "<dd class=\"tparam-descr-index-other\">";
+ } else
+ Result << "<dd class=\"tparam-descr-index-invalid\">";
+
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</dd>";
+}
+
+void CommentASTToHTMLConverter::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ unsigned NumLines = C->getNumLines();
+ if (NumLines == 0)
+ return;
+
+ Result << "<pre>";
+ for (unsigned i = 0; i != NumLines; ++i) {
+ appendToResultWithHTMLEscaping(C->getText(i));
+ if (i + 1 != NumLines)
+ Result << '\n';
+ }
+ Result << "</pre>";
+}
+
+void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ llvm_unreachable("should not see this AST node");
+}
+
+void CommentASTToHTMLConverter::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ Result << "<pre>";
+ appendToResultWithHTMLEscaping(C->getText());
+ Result << "</pre>";
+}
+
+void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
+ FullCommentParts Parts(C, Traits);
+
+ bool FirstParagraphIsBrief = false;
+ if (Parts.Headerfile)
+ visit(Parts.Headerfile);
+ if (Parts.Brief)
+ visit(Parts.Brief);
+ else if (Parts.FirstParagraph) {
+ Result << "<p class=\"para-brief\">";
+ visitNonStandaloneParagraphComment(Parts.FirstParagraph);
+ Result << "</p>";
+ FirstParagraphIsBrief = true;
+ }
+
+ for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
+ const Comment *C = Parts.MiscBlocks[i];
+ if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
+ continue;
+ visit(C);
+ }
+
+ if (Parts.TParams.size() != 0) {
+ Result << "<dl>";
+ for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
+ visit(Parts.TParams[i]);
+ Result << "</dl>";
+ }
+
+ if (Parts.Params.size() != 0) {
+ Result << "<dl>";
+ for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
+ visit(Parts.Params[i]);
+ Result << "</dl>";
+ }
+
+ if (Parts.Returns.size() != 0) {
+ Result << "<div class=\"result-discussion\">";
+ for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
+ visit(Parts.Returns[i]);
+ Result << "</div>";
+ }
+
+ Result.flush();
+}
+
+void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
+ const ParagraphComment *C) {
+ if (!C)
+ return;
+
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+}
+
+void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
+ for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ const char C = *I;
+ switch (C) {
+ case '&':
+ Result << "&amp;";
+ break;
+ case '<':
+ Result << "&lt;";
+ break;
+ case '>':
+ Result << "&gt;";
+ break;
+ case '"':
+ Result << "&quot;";
+ break;
+ case '\'':
+ Result << "&#39;";
+ break;
+ case '/':
+ Result << "&#47;";
+ break;
+ default:
+ Result << C;
+ break;
+ }
+ }
+}
+
+namespace {
+class CommentASTToXMLConverter :
+ public ConstCommentVisitor<CommentASTToXMLConverter> {
+public:
+ /// \param Str accumulator for XML.
+ CommentASTToXMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits,
+ const SourceManager &SM,
+ SimpleFormatContext &SFC,
+ unsigned FUID) :
+ FC(FC), Result(Str), Traits(Traits), SM(SM),
+ FormatRewriterContext(SFC),
+ FormatInMemoryUniqueId(FUID) { }
+
+ // Inline content.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block content.
+ void visitParagraphComment(const ParagraphComment *C);
+
+ void appendParagraphCommentWithKind(const ParagraphComment *C,
+ StringRef Kind);
+
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+ void visitFullComment(const FullComment *C);
+
+ // Helpers.
+ void appendToResultWithXMLEscaping(StringRef S);
+
+ void formatTextOfDeclaration(const DeclInfo *DI,
+ SmallString<128> &Declaration);
+
+private:
+ const FullComment *FC;
+
+ /// Output stream for XML.
+ llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
+ const SourceManager &SM;
+ SimpleFormatContext &FormatRewriterContext;
+ unsigned FormatInMemoryUniqueId;
+};
+
+void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
+ SmallVectorImpl<char> &Str) {
+ ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ llvm::raw_svector_ostream OS(Str);
+ PrintingPolicy PPolicy(LangOpts);
+ PPolicy.PolishForDeclaration = true;
+ PPolicy.TerseOutput = true;
+ ThisDecl->CurrentDecl->print(OS, PPolicy,
+ /*Indentation*/0, /*PrintInstantiation*/false);
+}
+
+void CommentASTToXMLConverter::formatTextOfDeclaration(
+ const DeclInfo *DI, SmallString<128> &Declaration) {
+ // FIXME. formatting API expects null terminated input string.
+ // There might be more efficient way of doing this.
+ std::string StringDecl = Declaration.str();
+
+ // Formatter specific code.
+ // Form a unique in memory buffer name.
+ SmallString<128> filename;
+ filename += "xmldecl";
+ filename += llvm::utostr(FormatInMemoryUniqueId);
+ filename += ".xd";
+ FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
+ SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
+ .getLocWithOffset(0);
+ unsigned Length = Declaration.size();
+
+ std::vector<CharSourceRange> Ranges(
+ 1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
+ ASTContext &Context = DI->CurrentDecl->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
+ FormatRewriterContext.Sources, LangOpts);
+ tooling::Replacements Replace = reformat(
+ format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
+ applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
+ Declaration = FormatRewriterContext.getRewrittenText(ID);
+}
+
+} // end unnamed namespace
+
+void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
+ appendToResultWithXMLEscaping(C->getText());
+}
+
+void CommentASTToXMLConverter::visitInlineCommandComment(
+ const InlineCommandComment *C) {
+ // Nothing to render if no arguments supplied.
+ if (C->getNumArgs() == 0)
+ return;
+
+ // Nothing to render if argument is empty.
+ StringRef Arg0 = C->getArgText(0);
+ if (Arg0.empty())
+ return;
+
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
+ appendToResultWithXMLEscaping(C->getArgText(i));
+ Result << " ";
+ }
+ return;
+ case InlineCommandComment::RenderBold:
+ assert(C->getNumArgs() == 1);
+ Result << "<bold>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</bold>";
+ return;
+ case InlineCommandComment::RenderMonospaced:
+ assert(C->getNumArgs() == 1);
+ Result << "<monospaced>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</monospaced>";
+ return;
+ case InlineCommandComment::RenderEmphasized:
+ assert(C->getNumArgs() == 1);
+ Result << "<emphasized>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</emphasized>";
+ return;
+ }
+}
+
+void CommentASTToXMLConverter::visitHTMLStartTagComment(
+ const HTMLStartTagComment *C) {
+ Result << "<rawHTML><![CDATA[";
+ printHTMLStartTagComment(C, Result);
+ Result << "]]></rawHTML>";
+}
+
+void
+CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+ Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
+}
+
+void
+CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
+ appendParagraphCommentWithKind(C, StringRef());
+}
+
+void CommentASTToXMLConverter::appendParagraphCommentWithKind(
+ const ParagraphComment *C,
+ StringRef ParagraphKind) {
+ if (C->isWhitespace())
+ return;
+
+ if (ParagraphKind.empty())
+ Result << "<Para>";
+ else
+ Result << "<Para kind=\"" << ParagraphKind << "\">";
+
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+ Result << "</Para>";
+}
+
+void CommentASTToXMLConverter::visitBlockCommandComment(
+ const BlockCommandComment *C) {
+ StringRef ParagraphKind;
+
+ switch (C->getCommandID()) {
+ case CommandTraits::KCI_attention:
+ case CommandTraits::KCI_author:
+ case CommandTraits::KCI_authors:
+ case CommandTraits::KCI_bug:
+ case CommandTraits::KCI_copyright:
+ case CommandTraits::KCI_date:
+ case CommandTraits::KCI_invariant:
+ case CommandTraits::KCI_note:
+ case CommandTraits::KCI_post:
+ case CommandTraits::KCI_pre:
+ case CommandTraits::KCI_remark:
+ case CommandTraits::KCI_remarks:
+ case CommandTraits::KCI_sa:
+ case CommandTraits::KCI_see:
+ case CommandTraits::KCI_since:
+ case CommandTraits::KCI_todo:
+ case CommandTraits::KCI_version:
+ case CommandTraits::KCI_warning:
+ ParagraphKind = C->getCommandName(Traits);
+ default:
+ break;
+ }
+
+ appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
+}
+
+void CommentASTToXMLConverter::visitParamCommandComment(
+ const ParamCommandComment *C) {
+ Result << "<Parameter><Name>";
+ appendToResultWithXMLEscaping(C->isParamIndexValid()
+ ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
+ Result << "</Name>";
+
+ if (C->isParamIndexValid()) {
+ if (C->isVarArgParam())
+ Result << "<IsVarArg />";
+ else
+ Result << "<Index>" << C->getParamIndex() << "</Index>";
+ }
+
+ Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
+ switch (C->getDirection()) {
+ case ParamCommandComment::In:
+ Result << "in";
+ break;
+ case ParamCommandComment::Out:
+ Result << "out";
+ break;
+ case ParamCommandComment::InOut:
+ Result << "in,out";
+ break;
+ }
+ Result << "</Direction><Discussion>";
+ visit(C->getParagraph());
+ Result << "</Discussion></Parameter>";
+}
+
+void CommentASTToXMLConverter::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ Result << "<Parameter><Name>";
+ appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
+ Result << "</Name>";
+
+ if (C->isPositionValid() && C->getDepth() == 1) {
+ Result << "<Index>" << C->getIndex(0) << "</Index>";
+ }
+
+ Result << "<Discussion>";
+ visit(C->getParagraph());
+ Result << "</Discussion></Parameter>";
+}
+
+void CommentASTToXMLConverter::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ unsigned NumLines = C->getNumLines();
+ if (NumLines == 0)
+ return;
+
+ switch (C->getCommandID()) {
+ case CommandTraits::KCI_code:
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
+ break;
+ default:
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
+ break;
+ }
+ for (unsigned i = 0; i != NumLines; ++i) {
+ appendToResultWithXMLEscaping(C->getText(i));
+ if (i + 1 != NumLines)
+ Result << '\n';
+ }
+ Result << "</Verbatim>";
+}
+
+void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ llvm_unreachable("should not see this AST node");
+}
+
+void CommentASTToXMLConverter::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
+ appendToResultWithXMLEscaping(C->getText());
+ Result << "</Verbatim>";
+}
+
+void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
+ FullCommentParts Parts(C, Traits);
+
+ const DeclInfo *DI = C->getDeclInfo();
+ StringRef RootEndTag;
+ if (DI) {
+ switch (DI->getKind()) {
+ case DeclInfo::OtherKind:
+ RootEndTag = "</Other>";
+ Result << "<Other";
+ break;
+ case DeclInfo::FunctionKind:
+ RootEndTag = "</Function>";
+ Result << "<Function";
+ switch (DI->TemplateKind) {
+ case DeclInfo::NotTemplate:
+ break;
+ case DeclInfo::Template:
+ Result << " templateKind=\"template\"";
+ break;
+ case DeclInfo::TemplateSpecialization:
+ Result << " templateKind=\"specialization\"";
+ break;
+ case DeclInfo::TemplatePartialSpecialization:
+ llvm_unreachable("partial specializations of functions "
+ "are not allowed in C++");
+ }
+ if (DI->IsInstanceMethod)
+ Result << " isInstanceMethod=\"1\"";
+ if (DI->IsClassMethod)
+ Result << " isClassMethod=\"1\"";
+ break;
+ case DeclInfo::ClassKind:
+ RootEndTag = "</Class>";
+ Result << "<Class";
+ switch (DI->TemplateKind) {
+ case DeclInfo::NotTemplate:
+ break;
+ case DeclInfo::Template:
+ Result << " templateKind=\"template\"";
+ break;
+ case DeclInfo::TemplateSpecialization:
+ Result << " templateKind=\"specialization\"";
+ break;
+ case DeclInfo::TemplatePartialSpecialization:
+ Result << " templateKind=\"partialSpecialization\"";
+ break;
+ }
+ break;
+ case DeclInfo::VariableKind:
+ RootEndTag = "</Variable>";
+ Result << "<Variable";
+ break;
+ case DeclInfo::NamespaceKind:
+ RootEndTag = "</Namespace>";
+ Result << "<Namespace";
+ break;
+ case DeclInfo::TypedefKind:
+ RootEndTag = "</Typedef>";
+ Result << "<Typedef";
+ break;
+ case DeclInfo::EnumKind:
+ RootEndTag = "</Enum>";
+ Result << "<Enum";
+ break;
+ }
+
+ {
+ // Print line and column number.
+ SourceLocation Loc = DI->CurrentDecl->getLocation();
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (!FID.isInvalid()) {
+ if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
+ Result << " file=\"";
+ appendToResultWithXMLEscaping(FE->getName());
+ Result << "\"";
+ }
+ Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
+ << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
+ << "\"";
+ }
+ }
+
+ // Finish the root tag.
+ Result << ">";
+
+ bool FoundName = false;
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
+ if (DeclarationName DeclName = ND->getDeclName()) {
+ Result << "<Name>";
+ std::string Name = DeclName.getAsString();
+ appendToResultWithXMLEscaping(Name);
+ FoundName = true;
+ Result << "</Name>";
+ }
+ }
+ if (!FoundName)
+ Result << "<Name>&lt;anonymous&gt;</Name>";
+
+ {
+ // Print USR.
+ SmallString<128> USR;
+ generateUSRForDecl(DI->CommentDecl, USR);
+ if (!USR.empty()) {
+ Result << "<USR>";
+ appendToResultWithXMLEscaping(USR);
+ Result << "</USR>";
+ }
+ }
+ } else {
+ // No DeclInfo -- just emit some root tag and name tag.
+ RootEndTag = "</Other>";
+ Result << "<Other><Name>unknown</Name>";
+ }
+
+ if (Parts.Headerfile) {
+ Result << "<Headerfile>";
+ visit(Parts.Headerfile);
+ Result << "</Headerfile>";
+ }
+
+ {
+ // Pretty-print the declaration.
+ Result << "<Declaration>";
+ SmallString<128> Declaration;
+ getSourceTextOfDeclaration(DI, Declaration);
+ formatTextOfDeclaration(DI, Declaration);
+ appendToResultWithXMLEscaping(Declaration);
+ Result << "</Declaration>";
+ }
+
+ bool FirstParagraphIsBrief = false;
+ if (Parts.Brief) {
+ Result << "<Abstract>";
+ visit(Parts.Brief);
+ Result << "</Abstract>";
+ } else if (Parts.FirstParagraph) {
+ Result << "<Abstract>";
+ visit(Parts.FirstParagraph);
+ Result << "</Abstract>";
+ FirstParagraphIsBrief = true;
+ }
+
+ if (Parts.TParams.size() != 0) {
+ Result << "<TemplateParameters>";
+ for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
+ visit(Parts.TParams[i]);
+ Result << "</TemplateParameters>";
+ }
+
+ if (Parts.Params.size() != 0) {
+ Result << "<Parameters>";
+ for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
+ visit(Parts.Params[i]);
+ Result << "</Parameters>";
+ }
+
+ if (Parts.Exceptions.size() != 0) {
+ Result << "<Exceptions>";
+ for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
+ visit(Parts.Exceptions[i]);
+ Result << "</Exceptions>";
+ }
+
+ if (Parts.Returns.size() != 0) {
+ Result << "<ResultDiscussion>";
+ for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
+ visit(Parts.Returns[i]);
+ Result << "</ResultDiscussion>";
+ }
+
+ if (DI->CommentDecl->hasAttrs()) {
+ const AttrVec &Attrs = DI->CommentDecl->getAttrs();
+ for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
+ const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
+ if (!AA) {
+ if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
+ if (DA->getMessage().empty())
+ Result << "<Deprecated/>";
+ else {
+ Result << "<Deprecated>";
+ appendToResultWithXMLEscaping(DA->getMessage());
+ Result << "</Deprecated>";
+ }
+ }
+ else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
+ if (UA->getMessage().empty())
+ Result << "<Unavailable/>";
+ else {
+ Result << "<Unavailable>";
+ appendToResultWithXMLEscaping(UA->getMessage());
+ Result << "</Unavailable>";
+ }
+ }
+ continue;
+ }
+
+ // 'availability' attribute.
+ Result << "<Availability";
+ StringRef Distribution;
+ if (AA->getPlatform()) {
+ Distribution = AvailabilityAttr::getPrettyPlatformName(
+ AA->getPlatform()->getName());
+ if (Distribution.empty())
+ Distribution = AA->getPlatform()->getName();
+ }
+ Result << " distribution=\"" << Distribution << "\">";
+ VersionTuple IntroducedInVersion = AA->getIntroduced();
+ if (!IntroducedInVersion.empty()) {
+ Result << "<IntroducedInVersion>"
+ << IntroducedInVersion.getAsString()
+ << "</IntroducedInVersion>";
+ }
+ VersionTuple DeprecatedInVersion = AA->getDeprecated();
+ if (!DeprecatedInVersion.empty()) {
+ Result << "<DeprecatedInVersion>"
+ << DeprecatedInVersion.getAsString()
+ << "</DeprecatedInVersion>";
+ }
+ VersionTuple RemovedAfterVersion = AA->getObsoleted();
+ if (!RemovedAfterVersion.empty()) {
+ Result << "<RemovedAfterVersion>"
+ << RemovedAfterVersion.getAsString()
+ << "</RemovedAfterVersion>";
+ }
+ StringRef DeprecationSummary = AA->getMessage();
+ if (!DeprecationSummary.empty()) {
+ Result << "<DeprecationSummary>";
+ appendToResultWithXMLEscaping(DeprecationSummary);
+ Result << "</DeprecationSummary>";
+ }
+ if (AA->getUnavailable())
+ Result << "<Unavailable/>";
+ Result << "</Availability>";
+ }
+ }
+
+ {
+ bool StartTagEmitted = false;
+ for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
+ const Comment *C = Parts.MiscBlocks[i];
+ if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
+ continue;
+ if (!StartTagEmitted) {
+ Result << "<Discussion>";
+ StartTagEmitted = true;
+ }
+ visit(C);
+ }
+ if (StartTagEmitted)
+ Result << "</Discussion>";
+ }
+
+ Result << RootEndTag;
+
+ Result.flush();
+}
+
+void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
+ for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ const char C = *I;
+ switch (C) {
+ case '&':
+ Result << "&amp;";
+ break;
+ case '<':
+ Result << "&lt;";
+ break;
+ case '>':
+ Result << "&gt;";
+ break;
+ case '"':
+ Result << "&quot;";
+ break;
+ case '\'':
+ Result << "&apos;";
+ break;
+ default:
+ Result << C;
+ break;
+ }
+ }
+}
+
+void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
+ SmallVectorImpl<char> &HTML,
+ const ASTContext &Context) {
+ CommentASTToHTMLConverter Converter(FC, HTML,
+ Context.getCommentCommandTraits());
+ Converter.visit(FC);
+}
+
+void CommentToXMLConverter::convertHTMLTagNodeToText(
+ const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
+ const ASTContext &Context) {
+ CommentASTToHTMLConverter Converter(0, Text,
+ Context.getCommentCommandTraits());
+ Converter.visit(HTC);
+}
+
+void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
+ SmallVectorImpl<char> &XML,
+ const ASTContext &Context) {
+ if (!FormatContext) {
+ FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ } else if ((FormatInMemoryUniqueId % 1000) == 0) {
+ // Delete after some number of iterations, so the buffers don't grow
+ // too large.
+ delete FormatContext;
+ FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ }
+
+ CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
+ Context.getSourceManager(), *FormatContext,
+ FormatInMemoryUniqueId++);
+ Converter.visit(FC);
+}
+
diff --git a/lib/Index/Makefile b/lib/Index/Makefile
new file mode 100644
index 000000000000..c53fccd1890e
--- /dev/null
+++ b/lib/Index/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/Index/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangIndex
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/tools/libclang/SimpleFormatContext.h b/lib/Index/SimpleFormatContext.h
index 016d0b67d443..fde43aed211f 100644
--- a/tools/libclang/SimpleFormatContext.h
+++ b/lib/Index/SimpleFormatContext.h
@@ -27,6 +27,7 @@
#include "llvm/Support/raw_ostream.h"
namespace clang {
+namespace index {
/// \brief A small class to be used by libclang clients to format
/// a declaration string in memory. This object is instantiated once
@@ -35,7 +36,7 @@ class SimpleFormatContext {
public:
SimpleFormatContext(LangOptions Options)
: DiagOpts(new DiagnosticOptions()),
- Diagnostics(new DiagnosticsEngine(new DiagnosticIDs,
+ Diagnostics(new DiagnosticsEngine(new DiagnosticIDs,
DiagOpts.getPtr())),
Files((FileSystemOptions())),
Sources(*Diagnostics, Files),
@@ -47,9 +48,9 @@ public:
FileID createInMemoryFile(StringRef Name, StringRef Content) {
const llvm::MemoryBuffer *Source =
- llvm::MemoryBuffer::getMemBuffer(Content);
+ llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
- Files.getVirtualFile(Name, Source->getBufferSize(), 0);
+ Files.getVirtualFile(Name, Source->getBufferSize(), 0);
Sources.overrideFileContents(Entry, Source, true);
assert(Entry != NULL);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
@@ -70,6 +71,7 @@ public:
Rewriter Rewrite;
};
+} // end namespace index
} // end namespace clang
#endif
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
new file mode 100644
index 000000000000..16d89f8944a7
--- /dev/null
+++ b/lib/Index/USRGeneration.cpp
@@ -0,0 +1,803 @@
+//===- USRGeneration.cpp - Routines for USR generation --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/USRGeneration.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+
+//===----------------------------------------------------------------------===//
+// USR generation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class USRGenerator : public ConstDeclVisitor<USRGenerator> {
+ SmallVectorImpl<char> &Buf;
+ llvm::raw_svector_ostream Out;
+ bool IgnoreResults;
+ ASTContext *Context;
+ bool generatedLoc;
+
+ llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;
+
+public:
+ explicit USRGenerator(ASTContext *Ctx, SmallVectorImpl<char> &Buf)
+ : Buf(Buf),
+ Out(Buf),
+ IgnoreResults(false),
+ Context(Ctx),
+ generatedLoc(false)
+ {
+ // Add the USR space prefix.
+ Out << getUSRSpacePrefix();
+ }
+
+ bool ignoreResults() const { return IgnoreResults; }
+
+ // Visitation methods from generating USRs from AST elements.
+ void VisitDeclContext(const DeclContext *D);
+ void VisitFieldDecl(const FieldDecl *D);
+ void VisitFunctionDecl(const FunctionDecl *D);
+ void VisitNamedDecl(const NamedDecl *D);
+ void VisitNamespaceDecl(const NamespaceDecl *D);
+ void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
+ void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(const ClassTemplateDecl *D);
+ void VisitObjCContainerDecl(const ObjCContainerDecl *CD);
+ void VisitObjCMethodDecl(const ObjCMethodDecl *MD);
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
+ void VisitTagDecl(const TagDecl *D);
+ void VisitTypedefDecl(const TypedefDecl *D);
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
+ void VisitVarDecl(const VarDecl *D);
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUsingDecl(const UsingDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
+ IgnoreResults = true;
+ }
+
+ /// Generate the string component containing the location of the
+ /// declaration.
+ bool GenLoc(const Decl *D);
+
+ /// String generation methods used both by the visitation methods
+ /// and from other clients that want to directly generate USRs. These
+ /// methods do not construct complete USRs (which incorporate the parents
+ /// of an AST element), but only the fragments concerning the AST element
+ /// itself.
+
+ /// Generate a USR for an Objective-C class.
+ void GenObjCClass(StringRef cls) {
+ generateUSRForObjCClass(cls, Out);
+ }
+ /// Generate a USR for an Objective-C class category.
+ void GenObjCCategory(StringRef cls, StringRef cat) {
+ generateUSRForObjCCategory(cls, cat, Out);
+ }
+ /// Generate a USR fragment for an Objective-C instance variable. The
+ /// complete USR can be created by concatenating the USR for the
+ /// encompassing class with this USR fragment.
+ void GenObjCIvar(StringRef ivar) {
+ generateUSRForObjCIvar(ivar, Out);
+ }
+ /// Generate a USR fragment for an Objective-C method.
+ void GenObjCMethod(StringRef sel, bool isInstanceMethod) {
+ generateUSRForObjCMethod(sel, isInstanceMethod, Out);
+ }
+ /// Generate a USR fragment for an Objective-C property.
+ void GenObjCProperty(StringRef prop) {
+ generateUSRForObjCProperty(prop, Out);
+ }
+ /// Generate a USR for an Objective-C protocol.
+ void GenObjCProtocol(StringRef prot) {
+ generateUSRForObjCProtocol(prot, Out);
+ }
+
+ void VisitType(QualType T);
+ void VisitTemplateParameterList(const TemplateParameterList *Params);
+ void VisitTemplateName(TemplateName Name);
+ void VisitTemplateArgument(const TemplateArgument &Arg);
+
+ /// Emit a Decl's name using NamedDecl::printName() and return true if
+ /// the decl had no name.
+ bool EmitDeclName(const NamedDecl *D);
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Generating USRs from ASTS.
+//===----------------------------------------------------------------------===//
+
+bool USRGenerator::EmitDeclName(const NamedDecl *D) {
+ Out.flush();
+ const unsigned startSize = Buf.size();
+ D->printName(Out);
+ Out.flush();
+ const unsigned endSize = Buf.size();
+ return startSize == endSize;
+}
+
+static inline bool ShouldGenerateLocation(const NamedDecl *D) {
+ return !D->isExternallyVisible();
+}
+
+void USRGenerator::VisitDeclContext(const DeclContext *DC) {
+ if (const NamedDecl *D = dyn_cast<NamedDecl>(DC))
+ Visit(D);
+}
+
+void USRGenerator::VisitFieldDecl(const FieldDecl *D) {
+ // The USR for an ivar declared in a class extension is based on the
+ // ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ VisitDeclContext(D->getDeclContext());
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
+ if (EmitDeclName(D)) {
+ // Bit fields can be anonymous.
+ IgnoreResults = true;
+ return;
+ }
+}
+
+void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+ if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
+ Out << "@FT@";
+ VisitTemplateParameterList(FunTmpl->getTemplateParameters());
+ } else
+ Out << "@F@";
+ D->printName(Out);
+
+ ASTContext &Ctx = *Context;
+ if (!Ctx.getLangOpts().CPlusPlus || D->isExternC())
+ return;
+
+ if (const TemplateArgumentList *
+ SpecArgs = D->getTemplateSpecializationArgs()) {
+ Out << '<';
+ for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(SpecArgs->get(I));
+ }
+ Out << '>';
+ }
+
+ // Mangle in type information for the arguments.
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ Out << '#';
+ if (ParmVarDecl *PD = *I)
+ VisitType(PD->getType());
+ }
+ if (D->isVariadic())
+ Out << '.';
+ Out << '#';
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->isStatic())
+ Out << 'S';
+ if (unsigned quals = MD->getTypeQualifiers())
+ Out << (char)('0' + quals);
+ }
+}
+
+void USRGenerator::VisitNamedDecl(const NamedDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@";
+
+ if (EmitDeclName(D)) {
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type,
+ // e.g.: void (*f)(void *);
+ // In this case, don't generate a USR.
+ IgnoreResults = true;
+ }
+}
+
+void USRGenerator::VisitVarDecl(const VarDecl *D) {
+ // VarDecls can be declared 'extern' within a function or method body,
+ // but their enclosing DeclContext is the function, not the TU. We need
+ // to check the storage class to correctly generate the USR.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+
+ // Variables always have simple names.
+ StringRef s = D->getName();
+
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ Out << '@' << s;
+}
+
+void USRGenerator::VisitNonTypeTemplateParmDecl(
+ const NonTypeTemplateParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+void USRGenerator::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+void USRGenerator::VisitNamespaceDecl(const NamespaceDecl *D) {
+ if (D->isAnonymousNamespace()) {
+ Out << "@aN";
+ return;
+ }
+
+ VisitDeclContext(D->getDeclContext());
+ if (!IgnoreResults)
+ Out << "@N@" << D->getName();
+}
+
+void USRGenerator::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+ VisitFunctionDecl(D->getTemplatedDecl());
+}
+
+void USRGenerator::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ VisitTagDecl(D->getTemplatedDecl());
+}
+
+void USRGenerator::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ if (!IgnoreResults)
+ Out << "@NA@" << D->getName();
+}
+
+void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ const DeclContext *container = D->getDeclContext();
+ if (const ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {
+ Visit(pd);
+ }
+ else {
+ // The USR for a method declared in a class extension or category is based on
+ // the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
+ if (!ID) {
+ IgnoreResults = true;
+ return;
+ }
+ Visit(ID);
+ }
+ // Ideally we would use 'GenObjCMethod', but this is such a hot path
+ // for Objective-C code that we don't want to use
+ // DeclarationName::getAsString().
+ Out << (D->isInstanceMethod() ? "(im)" : "(cm)")
+ << DeclarationName(D->getSelector());
+}
+
+void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
+ switch (D->getKind()) {
+ default:
+ llvm_unreachable("Invalid ObjC container.");
+ case Decl::ObjCInterface:
+ case Decl::ObjCImplementation:
+ GenObjCClass(D->getName());
+ break;
+ case Decl::ObjCCategory: {
+ const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ const ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ // Specially handle class extensions, which are anonymous categories.
+ // We want to mangle in the location to uniquely distinguish them.
+ if (CD->IsClassExtension()) {
+ Out << "objc(ext)" << ID->getName() << '@';
+ GenLoc(CD);
+ }
+ else
+ GenObjCCategory(ID->getName(), CD->getName());
+
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ const ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
+ const ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
+ break;
+ }
+ case Decl::ObjCProtocol:
+ GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
+ break;
+ }
+}
+
+void USRGenerator::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ // The USR for a property declared in a class extension or category is based
+ // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ Visit(cast<Decl>(D->getDeclContext()));
+ GenObjCProperty(D->getName());
+}
+
+void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
+ VisitObjCPropertyDecl(PD);
+ return;
+ }
+
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitTagDecl(const TagDecl *D) {
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ D = D->getCanonicalDecl();
+ VisitDeclContext(D->getDeclContext());
+
+ bool AlreadyStarted = false;
+ if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
+ if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) {
+ AlreadyStarted = true;
+
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@ST"; break;
+ case TTK_Class: Out << "@CT"; break;
+ case TTK_Union: Out << "@UT"; break;
+ case TTK_Enum: llvm_unreachable("enum template");
+ }
+ VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
+ } else if (const ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) {
+ AlreadyStarted = true;
+
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@SP"; break;
+ case TTK_Class: Out << "@CP"; break;
+ case TTK_Union: Out << "@UP"; break;
+ case TTK_Enum: llvm_unreachable("enum partial specialization");
+ }
+ VisitTemplateParameterList(PartialSpec->getTemplateParameters());
+ }
+ }
+
+ if (!AlreadyStarted) {
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@S"; break;
+ case TTK_Class: Out << "@C"; break;
+ case TTK_Union: Out << "@U"; break;
+ case TTK_Enum: Out << "@E"; break;
+ }
+ }
+
+ Out << '@';
+ Out.flush();
+ assert(Buf.size() > 0);
+ const unsigned off = Buf.size() - 1;
+
+ if (EmitDeclName(D)) {
+ if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {
+ Buf[off] = 'A';
+ Out << '@' << *TD;
+ }
+ else
+ Buf[off] = 'a';
+ }
+
+ // For a class template specialization, mangle the template arguments.
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
+ Out << '>';
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(Args.get(I));
+ }
+ }
+}
+
+void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+ const DeclContext *DC = D->getDeclContext();
+ if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
+ Visit(DCN);
+ Out << "@T@";
+ Out << D->getName();
+}
+
+void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+bool USRGenerator::GenLoc(const Decl *D) {
+ if (generatedLoc)
+ return IgnoreResults;
+ generatedLoc = true;
+
+ // Guard against null declarations in invalid code.
+ if (!D) {
+ IgnoreResults = true;
+ return true;
+ }
+
+ // Use the location of canonical decl.
+ D = D->getCanonicalDecl();
+
+ const SourceManager &SM = Context->getSourceManager();
+ SourceLocation L = D->getLocStart();
+ if (L.isInvalid()) {
+ IgnoreResults = true;
+ return true;
+ }
+ L = SM.getExpansionLoc(L);
+ const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
+ const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+ if (FE) {
+ Out << llvm::sys::path::filename(FE->getName());
+ }
+ else {
+ // This case really isn't interesting.
+ IgnoreResults = true;
+ return true;
+ }
+ // Use the offest into the FileID to represent the location. Using
+ // a line/column can cause us to look back at the original source file,
+ // which is expensive.
+ Out << '@' << Decomposed.second;
+ return IgnoreResults;
+}
+
+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
+ // requirements for USRs might not be the same.
+ ASTContext &Ctx = *Context;
+
+ do {
+ T = Ctx.getCanonicalType(T);
+ Qualifiers Q = T.getQualifiers();
+ unsigned qVal = 0;
+ if (Q.hasConst())
+ qVal |= 0x1;
+ if (Q.hasVolatile())
+ qVal |= 0x2;
+ if (Q.hasRestrict())
+ qVal |= 0x4;
+ if(qVal)
+ Out << ((char) ('0' + qVal));
+
+ // Mangle in ObjC GC qualifiers?
+
+ if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) {
+ Out << 'P';
+ T = Expansion->getPattern();
+ }
+
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ unsigned char c = '\0';
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ c = 'v'; break;
+ case BuiltinType::Bool:
+ c = 'b'; break;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ c = 'c'; break;
+ case BuiltinType::Char16:
+ c = 'q'; break;
+ case BuiltinType::Char32:
+ c = 'w'; break;
+ case BuiltinType::UShort:
+ c = 's'; break;
+ case BuiltinType::UInt:
+ c = 'i'; break;
+ case BuiltinType::ULong:
+ c = 'l'; break;
+ case BuiltinType::ULongLong:
+ c = 'k'; break;
+ case BuiltinType::UInt128:
+ c = 'j'; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ c = 'C'; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ c = 'W'; break;
+ case BuiltinType::Short:
+ c = 'S'; break;
+ case BuiltinType::Int:
+ c = 'I'; break;
+ case BuiltinType::Long:
+ c = 'L'; break;
+ case BuiltinType::LongLong:
+ c = 'K'; break;
+ case BuiltinType::Int128:
+ c = 'J'; break;
+ case BuiltinType::Half:
+ c = 'h'; break;
+ case BuiltinType::Float:
+ c = 'f'; break;
+ case BuiltinType::Double:
+ c = 'd'; break;
+ case BuiltinType::LongDouble:
+ c = 'D'; break;
+ case BuiltinType::NullPtr:
+ c = 'n'; break;
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLSampler:
+ IgnoreResults = true;
+ return;
+ case BuiltinType::ObjCId:
+ c = 'o'; break;
+ case BuiltinType::ObjCClass:
+ c = 'O'; break;
+ case BuiltinType::ObjCSel:
+ c = 'e'; break;
+ }
+ Out << c;
+ return;
+ }
+
+ // If we have already seen this (non-built-in) type, use a substitution
+ // encoding.
+ llvm::DenseMap<const Type *, unsigned>::iterator Substitution
+ = TypeSubstitutions.find(T.getTypePtr());
+ if (Substitution != TypeSubstitutions.end()) {
+ Out << 'S' << Substitution->second << '_';
+ return;
+ } else {
+ // Record this as a substitution.
+ unsigned Number = TypeSubstitutions.size();
+ TypeSubstitutions[T.getTypePtr()] = Number;
+ }
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ Out << '*';
+ T = PT->getPointeeType();
+ continue;
+ }
+ if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ Out << '&';
+ T = RT->getPointeeType();
+ continue;
+ }
+ if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
+ Out << 'F';
+ VisitType(FT->getResultType());
+ for (FunctionProtoType::arg_type_iterator
+ I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
+ VisitType(*I);
+ }
+ if (FT->isVariadic())
+ Out << '.';
+ return;
+ }
+ if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ Out << 'B';
+ T = BT->getPointeeType();
+ continue;
+ }
+ if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ Out << '<';
+ T = CT->getElementType();
+ continue;
+ }
+ if (const TagType *TT = T->getAs<TagType>()) {
+ Out << '$';
+ VisitTagDecl(TT->getDecl());
+ return;
+ }
+ if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) {
+ Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
+ return;
+ }
+ if (const TemplateSpecializationType *Spec
+ = T->getAs<TemplateSpecializationType>()) {
+ Out << '>';
+ VisitTemplateName(Spec->getTemplateName());
+ Out << Spec->getNumArgs();
+ for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+ VisitTemplateArgument(Spec->getArg(I));
+ return;
+ }
+
+ // Unhandled type.
+ Out << ' ';
+ break;
+ } while (true);
+}
+
+void USRGenerator::VisitTemplateParameterList(
+ const TemplateParameterList *Params) {
+ if (!Params)
+ return;
+ Out << '>' << Params->size();
+ for (TemplateParameterList::const_iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ Out << '#';
+ if (isa<TemplateTypeParmDecl>(*P)) {
+ if (cast<TemplateTypeParmDecl>(*P)->isParameterPack())
+ Out<< 'p';
+ Out << 'T';
+ continue;
+ }
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->isParameterPack())
+ Out << 'p';
+ Out << 'N';
+ VisitType(NTTP->getType());
+ continue;
+ }
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+ if (TTP->isParameterPack())
+ Out << 'p';
+ Out << 't';
+ VisitTemplateParameterList(TTP->getTemplateParameters());
+ }
+}
+
+void USRGenerator::VisitTemplateName(TemplateName Name) {
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+ Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
+ return;
+ }
+
+ Visit(Template);
+ return;
+ }
+
+ // FIXME: Visit dependent template names.
+}
+
+void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+
+ case TemplateArgument::Declaration:
+ Visit(Arg.getAsDecl());
+ break;
+
+ case TemplateArgument::NullPtr:
+ break;
+
+ case TemplateArgument::TemplateExpansion:
+ Out << 'P'; // pack expansion of...
+ // Fall through
+ case TemplateArgument::Template:
+ VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());
+ break;
+
+ case TemplateArgument::Expression:
+ // FIXME: Visit expressions.
+ break;
+
+ case TemplateArgument::Pack:
+ Out << 'p' << Arg.pack_size();
+ for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end();
+ P != PEnd; ++P)
+ VisitTemplateArgument(*P);
+ break;
+
+ case TemplateArgument::Type:
+ VisitType(Arg.getAsType());
+ break;
+
+ case TemplateArgument::Integral:
+ Out << 'V';
+ VisitType(Arg.getIntegralType());
+ Out << Arg.getAsIntegral();
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// USR generation functions.
+//===----------------------------------------------------------------------===//
+
+void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS) {
+ OS << "objc(cs)" << Cls;
+}
+
+void clang::index::generateUSRForObjCCategory(StringRef Cls, StringRef Cat,
+ raw_ostream &OS) {
+ OS << "objc(cy)" << Cls << '@' << Cat;
+}
+
+void clang::index::generateUSRForObjCIvar(StringRef Ivar, raw_ostream &OS) {
+ OS << '@' << Ivar;
+}
+
+void clang::index::generateUSRForObjCMethod(StringRef Sel,
+ bool IsInstanceMethod,
+ raw_ostream &OS) {
+ OS << (IsInstanceMethod ? "(im)" : "(cm)") << Sel;
+}
+
+void clang::index::generateUSRForObjCProperty(StringRef Prop, raw_ostream &OS) {
+ OS << "(py)" << Prop;
+}
+
+void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS) {
+ OS << "objc(pl)" << Prot;
+}
+
+bool clang::index::generateUSRForDecl(const Decl *D,
+ SmallVectorImpl<char> &Buf) {
+ // Don't generate USRs for things with invalid locations.
+ if (!D || D->getLocStart().isInvalid())
+ return true;
+
+ USRGenerator UG(&D->getASTContext(), Buf);
+ UG.Visit(D);
+ return UG.ignoreResults();
+}
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index dcf1f0c70c54..478462c3c20d 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -82,7 +82,7 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
if (FileSize <= sizeof(HMapHeader)) return 0;
OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
- if (FileBuffer == 0) return 0; // Unreadable file?
+ if (!FileBuffer) return 0; // Unreadable file?
const char *FileStart = FileBuffer->getBufferStart();
// We know the file is at least as big as the header, check it now.
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 304bd6969a68..9e43dda226bf 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Capacity.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#if defined(LLVM_ON_UNIX)
#include <limits.h>
@@ -43,11 +44,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
- FileManager &FM, DiagnosticsEngine &Diags,
+ SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
- : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
- ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this)
+ : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
+ ModMap(SourceMgr, *Diags.getClient(), LangOpts, Target, *this)
{
AngledDirIdx = 0;
SystemDirIdx = 0;
@@ -160,9 +161,11 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
// Only deal with normal search directories.
if (!SearchDirs[Idx].isNormalDir())
continue;
-
+
+ bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
// Search for a module map file in this directory.
- if (loadModuleMapFile(SearchDirs[Idx].getDir()) == LMM_NewlyLoaded) {
+ if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem)
+ == LMM_NewlyLoaded) {
// We just loaded a module map file; check whether the module is
// available now.
Module = ModMap.findModule(ModuleName);
@@ -175,7 +178,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
SmallString<128> NestedModuleMapDirName;
NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
- if (loadModuleMapFile(NestedModuleMapDirName) == LMM_NewlyLoaded) {
+ if (loadModuleMapFile(NestedModuleMapDirName, IsSystem) == LMM_NewlyLoaded){
// If we just loaded a module map file, look for the module again.
Module = ModMap.findModule(ModuleName);
if (Module)
@@ -223,7 +226,7 @@ const FileEntry *DirectoryLookup::LookupFile(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const {
InUserSpecifiedSystemFramework = false;
@@ -244,15 +247,18 @@ const FileEntry *DirectoryLookup::LookupFile(
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- if (SuggestedModule && HS.hasModuleMap(TmpDir, getDir())) {
- const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
+ HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory());
+ if (SuggestedModule) {
+ const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
/*openFile=*/false);
if (!File)
return File;
- // If there is a module that corresponds to this header,
- // suggest it.
+ // If there is a module that corresponds to this header, suggest it.
*SuggestedModule = HS.findModuleForHeader(File);
+ if (!SuggestedModule->getModule() &&
+ HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory()))
+ *SuggestedModule = HS.findModuleForHeader(File);
return File;
}
@@ -337,7 +343,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const
{
FileManager &FileMgr = HS.getFileMgr();
@@ -496,11 +502,29 @@ const FileEntry *HeaderSearch::LookupFile(
const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache)
{
+ if (!HSOpts->ModuleMapFiles.empty()) {
+ // Preload all explicitly specified module map files. This enables modules
+ // map files lying in a directory structure separate from the header files
+ // that they describe. These cannot be loaded lazily upon encountering a
+ // header file, as there is no other knwon mapping from a header file to its
+ // module map file.
+ for (llvm::SetVector<std::string>::iterator
+ I = HSOpts->ModuleMapFiles.begin(),
+ E = HSOpts->ModuleMapFiles.end();
+ I != E; ++I) {
+ const FileEntry *File = FileMgr.getFile(*I);
+ if (!File)
+ continue;
+ loadModuleMapFile(File, /*IsSystem=*/false);
+ }
+ HSOpts->ModuleMapFiles.clear();
+ }
+
if (SuggestedModule)
- *SuggestedModule = 0;
+ *SuggestedModule = ModuleMap::KnownHeader();
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
@@ -676,7 +700,7 @@ LookupSubframeworkHeader(StringRef Filename,
const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule) {
+ ModuleMap::KnownHeader *SuggestedModule) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
@@ -866,19 +890,16 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
HFI.ControllingMacro || HFI.ControllingMacroID;
}
-void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE) {
+void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
+ ModuleMap::ModuleHeaderRole Role,
+ bool isCompilingModuleHeader) {
if (FE->getUID() >= FileInfo.size())
FileInfo.resize(FE->getUID()+1);
HeaderFileInfo &HFI = FileInfo[FE->getUID()];
HFI.isModuleHeader = true;
-}
-
-void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
- if (UID >= FileInfo.size())
- FileInfo.resize(UID+1);
- HFI.Resolved = true;
- FileInfo[UID] = HFI;
+ HFI.isCompilingModuleHeader = isCompilingModuleHeader;
+ HFI.setHeaderRole(Role);
}
bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
@@ -930,7 +951,8 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
}
bool HeaderSearch::hasModuleMap(StringRef FileName,
- const DirectoryEntry *Root) {
+ const DirectoryEntry *Root,
+ bool IsSystem) {
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
StringRef DirName = FileName;
@@ -939,21 +961,20 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
DirName = llvm::sys::path::parent_path(DirName);
if (DirName.empty())
return false;
-
+
// Determine whether this directory exists.
const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
if (!Dir)
return false;
-
- // Try to load the module map file in this directory.
- switch (loadModuleMapFile(Dir)) {
+
+ // Try to load the "module.map" file in this directory.
+ switch (loadModuleMapFile(Dir, IsSystem)) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
// Success. All of the directories we stepped through inherit this module
// map file.
for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
DirectoryHasModuleMap[FixUpDirectories[I]] = true;
-
return true;
case LMM_NoDirectory:
@@ -971,19 +992,17 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
} while (true);
}
-Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const {
+ModuleMap::KnownHeader
+HeaderSearch::findModuleForHeader(const FileEntry *File) const {
if (ExternalSource) {
// Make sure the external source has handled header info about this file,
// which includes whether the file is part of a module.
(void)getFileInfo(File);
}
- if (Module *Mod = ModMap.findModuleForHeader(File))
- return Mod;
-
- return 0;
+ return ModMap.findModuleForHeader(File);
}
-bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
+bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
const DirectoryEntry *Dir = File->getDir();
llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
@@ -991,14 +1010,14 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
if (KnownDir != DirectoryHasModuleMap.end())
return !KnownDir->second;
- bool Result = ModMap.parseModuleMapFile(File);
+ bool Result = ModMap.parseModuleMapFile(File, IsSystem);
if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
// If the file we loaded was a module.map, look for the corresponding
// module_private.map.
SmallString<128> PrivateFilename(Dir->getName());
llvm::sys::path::append(PrivateFilename, "module_private.map");
if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
- Result = ModMap.parseModuleMapFile(PrivateFile);
+ Result = ModMap.parseModuleMapFile(PrivateFile, IsSystem);
}
DirectoryHasModuleMap[Dir] = !Result;
@@ -1012,7 +1031,7 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
return Module;
// Try to load a module map file.
- switch (loadModuleMapFile(Dir)) {
+ switch (loadModuleMapFile(Dir, IsSystem)) {
case LMM_InvalidModuleMap:
break;
@@ -1052,15 +1071,15 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(StringRef DirName) {
+HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem) {
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
- return loadModuleMapFile(Dir);
+ return loadModuleMapFile(Dir, IsSystem);
return LMM_NoDirectory;
}
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem) {
llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
= DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
@@ -1072,7 +1091,7 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
llvm::sys::path::append(ModuleMapFileName, "module.map");
if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
// We have found a module map file. Try to parse it.
- if (ModMap.parseModuleMapFile(ModuleMapFile)) {
+ if (ModMap.parseModuleMapFile(ModuleMapFile, IsSystem)) {
// No suitable module map.
DirectoryHasModuleMap[Dir] = false;
return LMM_InvalidModuleMap;
@@ -1087,7 +1106,7 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
llvm::sys::path::append(ModuleMapFileName, "module_private.map");
if (const FileEntry *PrivateModuleMapFile
= FileMgr.getFile(ModuleMapFileName)) {
- if (ModMap.parseModuleMapFile(PrivateModuleMapFile)) {
+ if (ModMap.parseModuleMapFile(PrivateModuleMapFile, IsSystem)) {
// No suitable module map.
DirectoryHasModuleMap[Dir] = false;
return LMM_InvalidModuleMap;
@@ -1107,6 +1126,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
// Load module maps for each of the header search directories.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+ bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
if (SearchDirs[Idx].isFramework()) {
llvm::error_code EC;
SmallString<128> DirNative;
@@ -1114,7 +1134,6 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
DirNative);
// Search each of the ".framework" directories to load them as modules.
- bool IsSystem = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (llvm::sys::path::extension(Dir->path()) != ".framework")
@@ -1136,7 +1155,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
continue;
// Try to load a module map file for the search directory.
- loadModuleMapFile(SearchDirs[Idx].getDir());
+ loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem);
// Try to load module map files for immediate subdirectories of this search
// directory.
@@ -1151,6 +1170,20 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
}
}
+void HeaderSearch::loadTopLevelSystemModules() {
+ // Load module maps for each of the header search directories.
+ for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+ // We only care about normal header directories.
+ if (!SearchDirs[Idx].isNormalDir()) {
+ continue;
+ }
+
+ // Try to load a module map file for the search directory.
+ loadModuleMapFile(SearchDirs[Idx].getDir(),
+ SearchDirs[Idx].isSystemHeaderDirectory());
+ }
+}
+
void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
if (SearchDir.haveSearchedAllModuleMaps())
return;
@@ -1160,7 +1193,7 @@ void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path());
+ loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory());
}
SearchDir.setSearchedAllModuleMaps(true);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 9958287ba474..c071455da662 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -29,6 +29,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@@ -93,6 +94,10 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
// Start of the file is a start of line.
IsAtStartOfLine = true;
+ IsAtPhysicalStartOfLine = true;
+
+ HasLeadingSpace = false;
+ HasLeadingEmptyMacro = false;
// We are not after parsing a #.
ParsingPreprocessorDirective = false;
@@ -430,7 +435,8 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
/// \returns true if there was a failure, false on success.
bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const LangOptions &LangOpts,
+ bool IgnoreWhiteSpace) {
// TODO: this could be special cased for common tokens like identifiers, ')',
// etc to make this faster, if it mattered. Just look at StrData[0] to handle
// all obviously single-char tokens. This could use
@@ -448,7 +454,7 @@ bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
const char *StrData = Buffer.data()+LocInfo.second;
- if (isWhitespace(StrData[0]))
+ if (!IgnoreWhiteSpace && isWhitespace(StrData[0]))
return true;
// Create a lexer starting at the beginning of this token.
@@ -798,14 +804,10 @@ bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
SourceLocation *MacroBegin) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
- std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
- // FIXME: If the token comes from the macro token paste operator ('##')
- // this function will always return false;
- if (infoLoc.second > 0)
- return false; // Does not point at the start of token.
+ SourceLocation expansionLoc;
+ if (!SM.isAtStartOfImmediateMacroExpansion(loc, &expansionLoc))
+ return false;
- SourceLocation expansionLoc =
- SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart();
if (expansionLoc.isFileID()) {
// No other macro expansions, this is the first.
if (MacroBegin)
@@ -829,16 +831,11 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
if (tokLen == 0)
return false;
- FileID FID = SM.getFileID(loc);
- SourceLocation afterLoc = loc.getLocWithOffset(tokLen+1);
- if (SM.isInFileID(afterLoc, FID))
- return false; // Still in the same FileID, does not point to the last token.
-
- // FIXME: If the token comes from the macro token paste operator ('##')
- // or the stringify operator ('#') this function will always return false;
+ SourceLocation afterLoc = loc.getLocWithOffset(tokLen);
+ SourceLocation expansionLoc;
+ if (!SM.isAtEndOfImmediateMacroExpansion(afterLoc, &expansionLoc))
+ return false;
- SourceLocation expansionLoc =
- SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd();
if (expansionLoc.isFileID()) {
// No other macro expansions.
if (MacroEnd)
@@ -916,25 +913,25 @@ CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range,
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
- FileID FID;
- unsigned BeginOffs;
- llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
- if (FID.isInvalid())
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &BeginEntry = SM.getSLocEntry(SM.getFileID(Begin),
+ &Invalid);
+ if (Invalid)
return CharSourceRange();
- unsigned EndOffs;
- if (!SM.isInFileID(End, FID, &EndOffs) ||
- BeginOffs > EndOffs)
- return CharSourceRange();
+ if (BeginEntry.getExpansion().isMacroArgExpansion()) {
+ const SrcMgr::SLocEntry &EndEntry = SM.getSLocEntry(SM.getFileID(End),
+ &Invalid);
+ if (Invalid)
+ return CharSourceRange();
- const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
- const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
- if (Expansion.isMacroArgExpansion() &&
- Expansion.getSpellingLoc().isFileID()) {
- SourceLocation SpellLoc = Expansion.getSpellingLoc();
- Range.setBegin(SpellLoc.getLocWithOffset(BeginOffs));
- Range.setEnd(SpellLoc.getLocWithOffset(EndOffs));
- return makeRangeFromFileLocs(Range, SM, LangOpts);
+ if (EndEntry.getExpansion().isMacroArgExpansion() &&
+ BeginEntry.getExpansion().getExpansionLocStart() ==
+ EndEntry.getExpansion().getExpansionLocStart()) {
+ Range.setBegin(SM.getImmediateSpellingLoc(Begin));
+ Range.setEnd(SM.getImmediateSpellingLoc(End));
+ return makeFileCharRange(Range, SM, LangOpts);
+ }
}
return CharSourceRange();
@@ -1369,26 +1366,42 @@ void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
BufferPtr += Bytes;
if (BufferPtr > BufferEnd)
BufferPtr = BufferEnd;
+ // FIXME: What exactly does the StartOfLine bit mean? There are two
+ // possible meanings for the "start" of the line: the first token on the
+ // unexpanded line, or the first token on the expanded line.
IsAtStartOfLine = StartOfLine;
+ IsAtPhysicalStartOfLine = StartOfLine;
}
static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
- if (LangOpts.CPlusPlus11 || LangOpts.C11)
- return isCharInSet(C, C11AllowedIDChars);
- else if (LangOpts.CPlusPlus)
- return isCharInSet(C, CXX03AllowedIDChars);
- else
- return isCharInSet(C, C99AllowedIDChars);
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
+ static const llvm::sys::UnicodeCharSet C11AllowedIDChars(
+ C11AllowedIDCharRanges);
+ return C11AllowedIDChars.contains(C);
+ } else if (LangOpts.CPlusPlus) {
+ static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars(
+ CXX03AllowedIDCharRanges);
+ return CXX03AllowedIDChars.contains(C);
+ } else {
+ static const llvm::sys::UnicodeCharSet C99AllowedIDChars(
+ C99AllowedIDCharRanges);
+ return C99AllowedIDChars.contains(C);
+ }
}
static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
assert(isAllowedIDChar(C, LangOpts));
- if (LangOpts.CPlusPlus11 || LangOpts.C11)
- return !isCharInSet(C, C11DisallowedInitialIDChars);
- else if (LangOpts.CPlusPlus)
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
+ static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars(
+ C11DisallowedInitialIDCharRanges);
+ return !C11DisallowedInitialIDChars.contains(C);
+ } else if (LangOpts.CPlusPlus) {
return true;
- else
- return !isCharInSet(C, C99DisallowedInitialIDChars);
+ } else {
+ static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars(
+ C99DisallowedInitialIDCharRanges);
+ return !C99DisallowedInitialIDChars.contains(C);
+ }
}
static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
@@ -1407,11 +1420,15 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
CannotStartIdentifier
};
- if (!isCharInSet(C, C99AllowedIDChars)) {
+ static const llvm::sys::UnicodeCharSet C99AllowedIDChars(
+ C99AllowedIDCharRanges);
+ static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars(
+ C99DisallowedInitialIDCharRanges);
+ if (!C99AllowedIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
<< Range
<< CannotAppearInIdentifier;
- } else if (IsFirst && isCharInSet(C, C99DisallowedInitialIDChars)) {
+ } else if (IsFirst && C99DisallowedInitialIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
<< Range
<< CannotStartIdentifier;
@@ -1421,14 +1438,16 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
// Check C++98 compatibility.
if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_unicode_id,
Range.getBegin()) > DiagnosticsEngine::Ignored) {
- if (!isCharInSet(C, CXX03AllowedIDChars)) {
+ static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars(
+ CXX03AllowedIDCharRanges);
+ if (!CXX03AllowedIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id)
<< Range;
}
}
}
-void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
+bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
unsigned char C = *CurPtr++;
@@ -1452,7 +1471,7 @@ FinishIdentifier:
// If we are in raw mode, return this identifier raw. There is no need to
// look up identifier information or attempt to macro expand it.
if (LexingRawMode)
- return;
+ return true;
// Fill in Result.IdentifierInfo and update the token kind,
// looking up the identifier in the identifier table.
@@ -1461,9 +1480,9 @@ FinishIdentifier:
// Finally, now that we know we have an identifier, pass this off to the
// preprocessor, which may macro expand it or something.
if (II->isHandleIdentifierCase())
- PP->HandleIdentifier(Result);
+ return PP->HandleIdentifier(Result);
- return;
+ return true;
}
// Otherwise, $,\,? in identifier found. Enter slower path.
@@ -1553,7 +1572,7 @@ bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
/// LexNumericConstant - Lex the remainder of a integer or floating point
/// constant. From[-1] is the first character lexed. Return the end of the
/// constant.
-void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
+bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
@@ -1587,15 +1606,29 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
+ // If we have a digit separator, continue.
+ if (C == '\'' && getLangOpts().CPlusPlus1y) {
+ unsigned NextSize;
+ char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts());
+ if (isIdentifierBody(Next)) {
+ if (!isLexingRawMode())
+ Diag(CurPtr, diag::warn_cxx11_compat_digit_separator);
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ return LexNumericConstant(Result, CurPtr);
+ }
+ }
+
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::numeric_constant);
Result.setLiteralData(TokStart);
+ return true;
}
/// LexUDSuffix - Lex the ud-suffix production for user-defined literal suffixes
/// in C++11, or warn on a ud-suffix in C++98.
-const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
+const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
+ bool IsStringLiteral) {
assert(getLangOpts().CPlusPlus);
// Maximally munch an identifier. FIXME: UCNs.
@@ -1615,9 +1648,41 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
// that does not start with an underscore is ill-formed. As a conforming
// extension, we treat all such suffixes as if they had whitespace before
// them.
- if (C != '_') {
+ bool IsUDSuffix = false;
+ if (C == '_')
+ IsUDSuffix = true;
+ else if (IsStringLiteral && getLangOpts().CPlusPlus1y) {
+ // In C++1y, we need to look ahead a few characters to see if this is a
+ // valid suffix for a string literal or a numeric literal (this could be
+ // the 'operator""if' defining a numeric literal operator).
+ const unsigned MaxStandardSuffixLength = 3;
+ char Buffer[MaxStandardSuffixLength] = { C };
+ unsigned Consumed = Size;
+ unsigned Chars = 1;
+ while (true) {
+ unsigned NextSize;
+ char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize,
+ getLangOpts());
+ if (!isIdentifierBody(Next)) {
+ // End of suffix. Check whether this is on the whitelist.
+ IsUDSuffix = (Chars == 1 && Buffer[0] == 's') ||
+ NumericLiteralParser::isValidUDSuffix(
+ getLangOpts(), StringRef(Buffer, Chars));
+ break;
+ }
+
+ if (Chars == MaxStandardSuffixLength)
+ // Too long: can't be a standard suffix.
+ break;
+
+ Buffer[Chars++] = Next;
+ Consumed += NextSize;
+ }
+ }
+
+ if (!IsUDSuffix) {
if (!isLexingRawMode())
- Diag(CurPtr, getLangOpts().MicrosoftMode ?
+ Diag(CurPtr, getLangOpts().MicrosoftMode ?
diag::ext_ms_reserved_user_defined_literal :
diag::ext_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
@@ -1635,7 +1700,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
/// LexStringLiteral - Lex the remainder of a string literal, after having lexed
/// either " or L" or u8" or u" or U".
-void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
+bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0; // Does this string contain the \0 character?
@@ -1659,14 +1724,15 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_string);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
- return;
+ return true;
}
if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
- return cutOffLexing();
+ cutOffLexing();
+ return true;
}
NulCharacter = CurPtr-1;
@@ -1676,7 +1742,7 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
// If we are in C++11, lex the optional ud-suffix.
if (getLangOpts().CPlusPlus)
- CurPtr = LexUDSuffix(Result, CurPtr);
+ CurPtr = LexUDSuffix(Result, CurPtr, true);
// If a nul character existed in the string, warn about it.
if (NulCharacter && !isLexingRawMode())
@@ -1686,11 +1752,12 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
+ return true;
}
/// LexRawStringLiteral - Lex the remainder of a raw string literal, after
/// having lexed R", LR", u8R", uR", or UR".
-void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
+bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
// This function doesn't use getAndAdvanceChar because C++0x [lex.pptoken]p3:
// Between the initial and final double quote characters of the raw string,
@@ -1732,7 +1799,7 @@ void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
}
FormTokenWithChars(Result, CurPtr, tok::unknown);
- return;
+ return true;
}
// Save prefix and move CurPtr past it
@@ -1753,23 +1820,24 @@ void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
Diag(BufferPtr, diag::err_unterminated_raw_string)
<< StringRef(Prefix, PrefixLen);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
- return;
+ return true;
}
}
// If we are in C++11, lex the optional ud-suffix.
if (getLangOpts().CPlusPlus)
- CurPtr = LexUDSuffix(Result, CurPtr);
+ CurPtr = LexUDSuffix(Result, CurPtr, true);
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
+ return true;
}
/// LexAngledStringLiteral - Lex the remainder of an angled string literal,
/// after having lexed the '<' character. This is used for #include filenames.
-void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
+bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
const char *NulCharacter = 0; // Does this string contain the \0 character?
const char *AfterLessPos = CurPtr;
char C = getAndAdvanceChar(CurPtr, Result);
@@ -1784,7 +1852,7 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
// If the filename is unterminated, then it must just be a lone <
// character. Return this as such.
FormTokenWithChars(Result, AfterLessPos, tok::less);
- return;
+ return true;
} else if (C == 0) {
NulCharacter = CurPtr-1;
}
@@ -1799,12 +1867,13 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::angle_string_literal);
Result.setLiteralData(TokStart);
+ return true;
}
/// LexCharConstant - Lex the remainder of a character constant, after having
/// lexed either ' or L' or u' or U'.
-void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
+bool Lexer::LexCharConstant(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0; // Does this character contain the \0 character?
@@ -1819,7 +1888,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_empty_character);
FormTokenWithChars(Result, CurPtr, tok::unknown);
- return;
+ return true;
}
while (C != '\'') {
@@ -1832,14 +1901,15 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
- return;
+ return true;
}
if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
- return cutOffLexing();
+ cutOffLexing();
+ return true;
}
NulCharacter = CurPtr-1;
@@ -1849,7 +1919,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
// If we are in C++11, lex the optional ud-suffix.
if (getLangOpts().CPlusPlus)
- CurPtr = LexUDSuffix(Result, CurPtr);
+ CurPtr = LexUDSuffix(Result, CurPtr, false);
// If a nul character existed in the character, warn about it.
if (NulCharacter && !isLexingRawMode())
@@ -1859,6 +1929,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
+ return true;
}
/// SkipWhitespace - Efficiently skip over a series of whitespace characters.
@@ -1866,11 +1937,14 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
///
/// This method forms a token and returns true if KeepWhitespaceMode is enabled.
///
-bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
+bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine) {
// Whitespace - Skip it, then return the token after the whitespace.
bool SawNewline = isVerticalWhitespace(CurPtr[-1]);
- unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently.
+ unsigned char Char = *CurPtr;
+
+ // Skip consecutive spaces efficiently.
while (1) {
// Skip horizontal whitespace very aggressively.
while (isHorizontalWhitespace(Char))
@@ -1886,7 +1960,7 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
return false;
}
- // ok, but handle newline.
+ // OK, but handle newline.
SawNewline = true;
Char = *++CurPtr;
}
@@ -1894,8 +1968,10 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
// If the client wants us to return whitespace, return it now.
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
- if (SawNewline)
+ if (SawNewline) {
IsAtStartOfLine = true;
+ IsAtPhysicalStartOfLine = true;
+ }
// FIXME: The next token will not have LeadingSpace set.
return true;
}
@@ -1905,8 +1981,10 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
bool HasLeadingSpace = !isVerticalWhitespace(PrevChar);
Result.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
- if (SawNewline)
+ if (SawNewline) {
Result.setFlag(Token::StartOfLine);
+ TokAtPhysicalStartOfLine = true;
+ }
BufferPtr = CurPtr;
return false;
@@ -1918,7 +1996,8 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
///
/// If we're in KeepCommentMode or any CommentHandler has inserted
/// some tokens, this will store the first token and return true.
-bool Lexer::SkipLineComment(Token &Result, const char *CurPtr) {
+bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine) {
// If Line comments aren't explicitly enabled for this language, emit an
// extension warning.
if (!LangOpts.LineComment && !isLexingRawMode()) {
@@ -2037,6 +2116,7 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr) {
// The next returned token is at the start of the line.
Result.setFlag(Token::StartOfLine);
+ TokAtPhysicalStartOfLine = true;
// No leading whitespace seen so far.
Result.clearFlag(Token::LeadingSpace);
BufferPtr = CurPtr;
@@ -2147,7 +2227,8 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
///
/// If we're in KeepCommentMode or any CommentHandler has inserted
/// some tokens, this will store the first token and return true.
-bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
+bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
+ bool &TokAtPhysicalStartOfLine) {
// Scan one character past where we should, looking for a '/' character. Once
// we find it, check to see if it was preceded by a *. This common
// optimization helps people who like to put a lot of * characters in their
@@ -2202,7 +2283,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// Adjust the pointer to point directly after the first slash. It's
// not necessary to set C here, it will be overwritten at the end of
// the outer loop.
- CurPtr += llvm::CountTrailingZeros_32(cmp) + 1;
+ CurPtr += llvm::countTrailingZeros<unsigned>(cmp) + 1;
goto FoundSlash;
}
CurPtr += 16;
@@ -2298,7 +2379,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// efficiently now. This is safe even in KeepWhitespaceMode because we would
// have already returned above with the comment as a token.
if (isHorizontalWhitespace(*CurPtr)) {
- SkipWhitespace(Result, CurPtr+1);
+ SkipWhitespace(Result, CurPtr+1, TokAtPhysicalStartOfLine);
return false;
}
@@ -2404,10 +2485,28 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
- if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
- Diag(BufferEnd, LangOpts.CPlusPlus11 ? // C++11 [lex.phases] 2.2 p2
- diag::warn_cxx98_compat_no_newline_eof : diag::ext_no_newline_eof)
- << FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
+ if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
+ DiagnosticsEngine &Diags = PP->getDiagnostics();
+ SourceLocation EndLoc = getSourceLocation(BufferEnd);
+ unsigned DiagID;
+
+ if (LangOpts.CPlusPlus11) {
+ // C++11 [lex.phases] 2.2 p2
+ // Prefer the C++98 pedantic compatibility warning over the generic,
+ // non-extension, user-requested "missing newline at EOF" warning.
+ if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_no_newline_eof,
+ EndLoc) != DiagnosticsEngine::Ignored) {
+ DiagID = diag::warn_cxx98_compat_no_newline_eof;
+ } else {
+ DiagID = diag::warn_no_newline_eof;
+ }
+ } else {
+ DiagID = diag::ext_no_newline_eof;
+ }
+
+ Diag(BufferEnd, DiagID)
+ << FixItHint::CreateInsertion(EndLoc, "\n");
+ }
BufferPtr = CurPtr;
@@ -2430,14 +2529,19 @@ unsigned Lexer::isNextPPTokenLParen() {
// Save state that can be changed while lexing so that we can restore it.
const char *TmpBufferPtr = BufferPtr;
bool inPPDirectiveMode = ParsingPreprocessorDirective;
+ bool atStartOfLine = IsAtStartOfLine;
+ bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
+ bool leadingSpace = HasLeadingSpace;
Token Tok;
- Tok.startToken();
- LexTokenInternal(Tok);
+ Lex(Tok);
// Restore state that may have changed.
BufferPtr = TmpBufferPtr;
ParsingPreprocessorDirective = inPPDirectiveMode;
+ HasLeadingSpace = leadingSpace;
+ IsAtStartOfLine = atStartOfLine;
+ IsAtPhysicalStartOfLine = atPhysicalStartOfLine;
// Restore the lexer back to non-skipping mode.
LexingRawMode = false;
@@ -2626,6 +2730,10 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
StartPtr = CurPtr;
}
+ // Don't apply C family restrictions to UCNs in assembly mode
+ if (LangOpts.AsmPreprocessor)
+ return CodePoint;
+
// C99 6.4.3p2: A universal character name shall not specify a character whose
// short identifier is less than 00A0 other than 0024 ($), 0040 (@), or
// 0060 (`), nor one in the range D800 through DFFF inclusive.)
@@ -2670,19 +2778,22 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
return CodePoint;
}
-void Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) {
+bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C,
+ const char *CurPtr) {
+ static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars(
+ UnicodeWhitespaceCharRanges);
if (!isLexingRawMode() && !PP->isPreprocessedOutput() &&
- isCharInSet(C, UnicodeWhitespaceChars)) {
+ UnicodeWhitespaceChars.contains(C)) {
Diag(BufferPtr, diag::ext_unicode_whitespace)
<< makeCharRange(*this, BufferPtr, CurPtr);
Result.setFlag(Token::LeadingSpace);
- if (SkipWhitespace(Result, CurPtr))
- return; // KeepWhitespaceMode
-
- return LexTokenInternal(Result);
+ return true;
}
+ return false;
+}
+bool Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) {
if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) {
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
!PP->isPreprocessedOutput()) {
@@ -2711,22 +2822,59 @@ void Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) {
<< FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr));
BufferPtr = CurPtr;
- return LexTokenInternal(Result);
+ return false;
}
// Otherwise, we have an explicit UCN or a character that's unlikely to show
// up by accident.
MIOpt.ReadToken();
FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return true;
}
+void Lexer::PropagateLineStartLeadingSpaceInfo(Token &Result) {
+ IsAtStartOfLine = Result.isAtStartOfLine();
+ HasLeadingSpace = Result.hasLeadingSpace();
+ HasLeadingEmptyMacro = Result.hasLeadingEmptyMacro();
+ // Note that this doesn't affect IsAtPhysicalStartOfLine.
+}
+
+bool Lexer::Lex(Token &Result) {
+ // Start a new token.
+ Result.startToken();
+
+ // Set up misc whitespace flags for LexTokenInternal.
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+
+ if (HasLeadingSpace) {
+ Result.setFlag(Token::LeadingSpace);
+ HasLeadingSpace = false;
+ }
+
+ if (HasLeadingEmptyMacro) {
+ Result.setFlag(Token::LeadingEmptyMacro);
+ HasLeadingEmptyMacro = false;
+ }
+
+ bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
+ IsAtPhysicalStartOfLine = false;
+ bool isRawLex = isLexingRawMode();
+ (void) isRawLex;
+ bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine);
+ // (After the LexTokenInternal call, the lexer might be destroyed.)
+ assert((returnedToken || !isRawLex) && "Raw lex must succeed");
+ return returnedToken;
+}
/// LexTokenInternal - This implements a simple C family lexer. It is an
/// extremely performance critical piece of code. This assumes that the buffer
/// has a null character at the end of the file. This returns a preprocessing
/// token, not a normal token, as such, it is an internal interface. It assumes
/// that the Flags of result have been cleared before calling this.
-void Lexer::LexTokenInternal(Token &Result) {
+bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
LexNextToken:
// New token, can't need cleaning yet.
Result.clearFlag(Token::NeedsCleaning);
@@ -2747,7 +2895,7 @@ LexNextToken:
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
// FIXME: The next token will not have LeadingSpace set.
- return;
+ return true;
}
BufferPtr = CurPtr;
@@ -2763,43 +2911,32 @@ LexNextToken:
switch (Char) {
case 0: // Null.
// Found end of file?
- if (CurPtr-1 == BufferEnd) {
- // Read the PP instance variable into an automatic variable, because
- // LexEndOfFile will often delete 'this'.
- Preprocessor *PPCache = PP;
- if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file.
- return; // Got a token to return.
- assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
- return PPCache->Lex(Result);
- }
+ if (CurPtr-1 == BufferEnd)
+ return LexEndOfFile(Result, CurPtr-1);
// Check if we are performing code completion.
if (isCodeCompletionPoint(CurPtr-1)) {
// Return the code-completion token.
Result.startToken();
FormTokenWithChars(Result, CurPtr, tok::code_completion);
- return;
+ return true;
}
if (!isLexingRawMode())
Diag(CurPtr-1, diag::null_in_file);
Result.setFlag(Token::LeadingSpace);
- if (SkipWhitespace(Result, CurPtr))
- return; // KeepWhitespaceMode
+ if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
+ return true; // KeepWhitespaceMode
- goto LexNextToken; // GCC isn't tail call eliminating.
+ // We know the lexer hasn't changed, so just try again with this lexer.
+ // (We manually eliminate the tail call to avoid recursion.)
+ goto LexNextToken;
case 26: // DOS & CP/M EOF: "^Z".
// If we're in Microsoft extensions mode, treat this as end of file.
- if (LangOpts.MicrosoftExt) {
- // Read the PP instance variable into an automatic variable, because
- // LexEndOfFile will often delete 'this'.
- Preprocessor *PPCache = PP;
- if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file.
- return; // Got a token to return.
- assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
- return PPCache->Lex(Result);
- }
+ if (LangOpts.MicrosoftExt)
+ return LexEndOfFile(Result, CurPtr-1);
+
// If Microsoft extensions are disabled, this is just random garbage.
Kind = tok::unknown;
break;
@@ -2818,6 +2955,7 @@ LexNextToken:
// Since we consumed a newline, we are back at the start of a line.
IsAtStartOfLine = true;
+ IsAtPhysicalStartOfLine = true;
Kind = tok::eod;
break;
@@ -2826,17 +2964,20 @@ LexNextToken:
// No leading whitespace seen so far.
Result.clearFlag(Token::LeadingSpace);
- if (SkipWhitespace(Result, CurPtr))
- return; // KeepWhitespaceMode
- goto LexNextToken; // GCC isn't tail call eliminating.
+ 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;
case ' ':
case '\t':
case '\f':
case '\v':
SkipHorizontalWhitespace:
Result.setFlag(Token::LeadingSpace);
- if (SkipWhitespace(Result, CurPtr))
- return; // KeepWhitespaceMode
+ if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
+ return true; // KeepWhitespaceMode
SkipIgnoredUnits:
CurPtr = BufferPtr;
@@ -2844,18 +2985,21 @@ LexNextToken:
// If the next token is obviously a // or /* */ comment, skip it efficiently
// too (without going through the big switch stmt).
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
- LangOpts.LineComment && !LangOpts.TraditionalCPP) {
- if (SkipLineComment(Result, CurPtr+2))
- return; // There is a token to return.
+ LangOpts.LineComment &&
+ (LangOpts.CPlusPlus || !LangOpts.TraditionalCPP)) {
+ if (SkipLineComment(Result, CurPtr+2, TokAtPhysicalStartOfLine))
+ return true; // There is a token to return.
goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
- if (SkipBlockComment(Result, CurPtr+2))
- return; // There is a token to return.
+ if (SkipBlockComment(Result, CurPtr+2, TokAtPhysicalStartOfLine))
+ return true; // There is a token to return.
goto SkipIgnoredUnits;
} else if (isHorizontalWhitespace(*CurPtr)) {
goto SkipHorizontalWhitespace;
}
- goto LexNextToken; // GCC isn't tail call eliminating.
+ // We only saw whitespace, so just try again with this lexer.
+ // (We manually eliminate the tail call to avoid recursion.)
+ goto LexNextToken;
// C99 6.4.4.1: Integer Constants.
// C99 6.4.4.2: Floating Constants.
@@ -3141,14 +3285,16 @@ LexNextToken:
// "foo". Check to see if the character after the second slash is a '*'.
// If so, we will lex that as a "/" instead of the start of a comment.
// However, we never do this if we are just preprocessing.
- bool TreatAsComment = LangOpts.LineComment && !LangOpts.TraditionalCPP;
+ bool TreatAsComment = LangOpts.LineComment &&
+ (LangOpts.CPlusPlus || !LangOpts.TraditionalCPP);
if (!TreatAsComment)
if (!(PP && PP->isPreprocessedOutput()))
TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*';
if (TreatAsComment) {
- if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
- return; // There is a token to return.
+ if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ TokAtPhysicalStartOfLine))
+ return true; // There is a token to return.
// It is common for the tokens immediately after a // comment to be
// whitespace (indentation for the next line). Instead of going through
@@ -3158,9 +3304,13 @@ LexNextToken:
}
if (Char == '*') { // /**/ comment.
- if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
- return; // There is a token to return.
- goto LexNextToken; // GCC isn't tail call eliminating.
+ if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ TokAtPhysicalStartOfLine))
+ return true; // There is a token to return.
+
+ // We only saw whitespace, so just try again with this lexer.
+ // (We manually eliminate the tail call to avoid recursion.)
+ goto LexNextToken;
}
if (Char == '=') {
@@ -3195,7 +3345,7 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
@@ -3361,7 +3511,7 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
@@ -3378,8 +3528,18 @@ LexNextToken:
// UCNs (C99 6.4.3, C++11 [lex.charset]p2)
case '\\':
- if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result))
+ 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;
+ }
+
return LexUnicode(Result, CodePoint, CurPtr);
+ }
Kind = tok::unknown;
break;
@@ -3400,8 +3560,17 @@ LexNextToken:
(const UTF8 *)BufferEnd,
&CodePoint,
strictConversion);
- if (Status == conversionOK)
+ if (Status == conversionOK) {
+ 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;
+ }
return LexUnicode(Result, CodePoint, CurPtr);
+ }
if (isLexingRawMode() || ParsingPreprocessorDirective ||
PP->isPreprocessedOutput()) {
@@ -3416,6 +3585,9 @@ LexNextToken:
Diag(CurPtr, diag::err_invalid_utf8);
BufferPtr = CurPtr+1;
+ // We're pretending the character didn't exist, so just try again with
+ // this lexer.
+ // (We manually eliminate the tail call to avoid recursion.)
goto LexNextToken;
}
}
@@ -3425,7 +3597,7 @@ LexNextToken:
// Update the location of token as well as BufferPtr.
FormTokenWithChars(Result, CurPtr, Kind);
- return;
+ return true;
HandleDirective:
// We parsed a # character and it's the start of a preprocessing directive.
@@ -3433,18 +3605,12 @@ HandleDirective:
FormTokenWithChars(Result, CurPtr, tok::hash);
PP->HandleDirective(Result);
- // As an optimization, if the preprocessor didn't switch lexers, tail
- // recurse.
- if (PP->isCurrentLexer(this)) {
- // Start a new token. If this is a #include or something, the PP may
- // want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag and clear LeadingSpace.
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- Result.clearFlag(Token::LeadingSpace);
- IsAtStartOfLine = false;
- }
- goto LexNextToken; // GCC isn't tail call eliminating.
+ if (PP->hadModuleLoaderFatalFailure()) {
+ // With a fatal failure in the module loader, we abort parsing.
+ assert(Result.is(tok::eof) && "Preprocessor did not set tok:eof");
+ return true;
}
- return PP->Lex(Result);
+
+ // We parsed the directive; lex a token with the new state.
+ return false;
}
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 09f4a682f05d..17c6bb3049bc 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -157,7 +157,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
// Check for overflow.
if (Overflow && Diags) // Too many digits to fit in
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::warn_hex_escape_too_large);
+ diag::err_hex_escape_too_large);
break;
}
case '0': case '1': case '2': case '3':
@@ -180,7 +180,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::warn_octal_escape_too_large);
+ diag::err_octal_escape_too_large);
ResultChar &= ~0U >> (32-CharWidth);
}
break;
@@ -336,7 +336,7 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
return;
}
- assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth) &&
+ assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth == 4) &&
"only character widths of 1, 2, or 4 bytes supported");
(void)UcnLen;
@@ -413,10 +413,12 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
/// decimal-constant integer-suffix
/// octal-constant integer-suffix
/// hexadecimal-constant integer-suffix
+/// binary-literal integer-suffix [GNU, C++1y]
/// user-defined-integer-literal: [C++11 lex.ext]
/// decimal-literal ud-suffix
/// octal-literal ud-suffix
/// hexadecimal-literal ud-suffix
+/// binary-literal ud-suffix [GNU, C++1y]
/// decimal-constant:
/// nonzero-digit
/// decimal-constant digit
@@ -428,6 +430,10 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
/// hexadecimal-constant hexadecimal-digit
/// hexadecimal-prefix: one of
/// 0x 0X
+/// binary-literal:
+/// 0b binary-digit
+/// 0B binary-digit
+/// binary-literal binary-digit
/// integer-suffix:
/// unsigned-suffix [long-suffix]
/// unsigned-suffix [long-long-suffix]
@@ -441,6 +447,9 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
/// 0 1 2 3 4 5 6 7 8 9
/// a b c d e f
/// A B C D E F
+/// binary-digit:
+/// 0
+/// 1
/// unsigned-suffix: one of
/// u U
/// long-suffix: one of
@@ -489,15 +498,19 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
hadError = true;
return;
} else if (*s == '.') {
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
s++;
saw_period = true;
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = SkipDigits(s);
}
if ((*s == 'e' || *s == 'E')) { // exponent
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
const char *Exponent = s;
s++;
saw_exponent = true;
if (*s == '+' || *s == '-') s++; // sign
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
const char *first_non_digit = SkipDigits(s);
if (first_non_digit != s) {
s = first_non_digit;
@@ -511,10 +524,12 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
SuffixBegin = s;
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
bool isFPConstant = isFloatingLiteral();
+ const char *ImaginarySuffixLoc = 0;
// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
@@ -594,13 +609,15 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
break;
}
}
+ // "i", "if", and "il" are user-defined suffixes in C++1y.
+ if (PP.getLangOpts().CPlusPlus1y && *s == 'i')
+ break;
// fall through.
case 'j':
case 'J':
if (isImaginary) break; // Cannot be repeated.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
- diag::ext_imaginary_constant);
isImaginary = true;
+ ImaginarySuffixLoc = s;
continue; // Success.
}
// If we reached here, there was an error or a ud-suffix.
@@ -608,9 +625,17 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
if (s != ThisTokEnd) {
- if (PP.getLangOpts().CPlusPlus11 && s == SuffixBegin && *s == '_') {
- // We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting
- // with an '_' are ill-formed.
+ if (isValidUDSuffix(PP.getLangOpts(),
+ StringRef(SuffixBegin, ThisTokEnd - SuffixBegin))) {
+ // Any suffix pieces we might have parsed are actually part of the
+ // ud-suffix.
+ isLong = false;
+ isUnsigned = false;
+ isLongLong = false;
+ isFloat = false;
+ isImaginary = false;
+ isMicrosoftInteger = false;
+
saw_ud_suffix = true;
return;
}
@@ -623,6 +648,53 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
hadError = true;
return;
}
+
+ if (isImaginary) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc,
+ ImaginarySuffixLoc - ThisTokBegin),
+ diag::ext_imaginary_constant);
+ }
+}
+
+/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved
+/// suffixes as ud-suffixes, because the diagnostic experience is better if we
+/// treat it as an invalid suffix.
+bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts,
+ StringRef Suffix) {
+ if (!LangOpts.CPlusPlus11 || Suffix.empty())
+ return false;
+
+ // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid.
+ if (Suffix[0] == '_')
+ return true;
+
+ // In C++11, there are no library suffixes.
+ if (!LangOpts.CPlusPlus1y)
+ return false;
+
+ // In C++1y, "s", "h", "min", "ms", "us", and "ns" are used in the library.
+ // Per tweaked N3660, "il", "i", and "if" are also used in the library.
+ return llvm::StringSwitch<bool>(Suffix)
+ .Cases("h", "min", "s", true)
+ .Cases("ms", "us", "ns", true)
+ .Cases("il", "i", "if", true)
+ .Default(false);
+}
+
+void NumericLiteralParser::checkSeparator(SourceLocation TokLoc,
+ const char *Pos,
+ CheckSeparatorKind IsAfterDigits) {
+ if (IsAfterDigits == CSK_AfterDigits) {
+ if (Pos == ThisTokBegin)
+ return;
+ --Pos;
+ } else if (Pos == ThisTokEnd)
+ return;
+
+ if (isDigitSeparator(*Pos))
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Pos - ThisTokBegin),
+ diag::err_digit_separator_not_between_digits)
+ << IsAfterDigits;
}
/// ParseNumberStartingWithZero - This method is called when the first character
@@ -634,8 +706,11 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
assert(s[0] == '0' && "Invalid method call");
s++;
+ int c1 = s[0];
+ int c2 = s[1];
+
// Handle a hex number like 0x1234.
- if ((*s == 'x' || *s == 'X') && (isHexDigit(s[1]) || s[1] == '.')) {
+ if ((c1 == 'x' || c1 == 'X') && (isHexDigit(c2) || c2 == '.')) {
s++;
radix = 16;
DigitsBegin = s;
@@ -685,7 +760,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
// Handle simple binary numbers 0b01010
- if (*s == 'b' || *s == 'B') {
+ if ((c1 == 'b' || c1 == 'B') && (c2 == '0' || c2 == '1')) {
// 0b101010 is a C++1y / GCC extension.
PP.Diag(TokLoc,
PP.getLangOpts().CPlusPlus1y
@@ -789,7 +864,8 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
if (alwaysFitsInto64Bits(radix, NumDigits)) {
uint64_t N = 0;
for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr)
- N = N * radix + llvm::hexDigitValue(*Ptr);
+ if (!isDigitSeparator(*Ptr))
+ N = N * radix + llvm::hexDigitValue(*Ptr);
// This will truncate the value to Val's input width. Simply check
// for overflow by comparing.
@@ -806,6 +882,11 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
bool OverflowOccurred = false;
while (Ptr < SuffixBegin) {
+ if (isDigitSeparator(*Ptr)) {
+ ++Ptr;
+ continue;
+ }
+
unsigned C = llvm::hexDigitValue(*Ptr++);
// If this letter is out of bound for this radix, reject it.
@@ -834,8 +915,17 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
using llvm::APFloat;
unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin);
- return Result.convertFromString(StringRef(ThisTokBegin, n),
- APFloat::rmNearestTiesToEven);
+
+ llvm::SmallString<16> Buffer;
+ StringRef Str(ThisTokBegin, n);
+ if (Str.find('\'') != StringRef::npos) {
+ Buffer.reserve(n);
+ std::remove_copy_if(Str.begin(), Str.end(), std::back_inserter(Buffer),
+ &isDigitSeparator);
+ Str = Buffer;
+ }
+
+ return Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
}
@@ -921,8 +1011,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
assert(PP.getTargetInfo().getWCharWidth() <= 64 &&
"Assumes sizeof(wchar) on target is <= 64");
- SmallVector<uint32_t,4> codepoint_buffer;
- codepoint_buffer.resize(end-begin);
+ SmallVector<uint32_t, 4> codepoint_buffer;
+ codepoint_buffer.resize(end - begin);
uint32_t *buffer_begin = &codepoint_buffer.front();
uint32_t *buffer_end = buffer_begin + codepoint_buffer.size();
@@ -931,7 +1021,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
// by this implementation.
uint32_t largest_character_for_kind;
if (tok::wide_char_constant == Kind) {
- largest_character_for_kind = 0xFFFFFFFFu >> (32-PP.getTargetInfo().getWCharWidth());
+ largest_character_for_kind =
+ 0xFFFFFFFFu >> (32-PP.getTargetInfo().getWCharWidth());
} else if (tok::utf16_char_constant == Kind) {
largest_character_for_kind = 0xFFFF;
} else if (tok::utf32_char_constant == Kind) {
@@ -940,7 +1031,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
largest_character_for_kind = 0x7Fu;
}
- while (begin!=end) {
+ while (begin != end) {
// Is this a span of non-escape characters?
if (begin[0] != '\\') {
char const *start = begin;
@@ -951,12 +1042,12 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
char const *tmp_in_start = start;
uint32_t *tmp_out_start = buffer_begin;
ConversionResult res =
- ConvertUTF8toUTF32(reinterpret_cast<UTF8 const **>(&start),
- reinterpret_cast<UTF8 const *>(begin),
- &buffer_begin,buffer_end,strictConversion);
- if (res!=conversionOK) {
- // If we see bad encoding for unprefixed character literals, warn and
- // simply copy the byte values, for compatibility with gcc and
+ ConvertUTF8toUTF32(reinterpret_cast<UTF8 const **>(&start),
+ reinterpret_cast<UTF8 const *>(begin),
+ &buffer_begin, buffer_end, strictConversion);
+ if (res != conversionOK) {
+ // If we see bad encoding for unprefixed character literals, warn and
+ // simply copy the byte values, for compatibility with gcc and
// older versions of clang.
bool NoErrorOnBadEncoding = isAscii();
unsigned Msg = diag::err_bad_character_encoding;
@@ -966,13 +1057,13 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
if (NoErrorOnBadEncoding) {
start = tmp_in_start;
buffer_begin = tmp_out_start;
- for ( ; start != begin; ++start, ++buffer_begin)
+ for (; start != begin; ++start, ++buffer_begin)
*buffer_begin = static_cast<uint8_t>(*start);
} else {
HadError = true;
}
} else {
- for (; tmp_out_start <buffer_begin; ++tmp_out_start) {
+ for (; tmp_out_start < buffer_begin; ++tmp_out_start) {
if (*tmp_out_start > largest_character_for_kind) {
HadError = true;
PP.Diag(Loc, diag::err_character_too_large);
@@ -982,14 +1073,12 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
continue;
}
- // Is this a Universal Character Name excape?
+ // Is this a Universal Character Name escape?
if (begin[1] == 'u' || begin[1] == 'U') {
unsigned short UcnLen = 0;
if (!ProcessUCNEscape(TokBegin, begin, end, *buffer_begin, UcnLen,
FullSourceLoc(Loc, PP.getSourceManager()),
- &PP.getDiagnostics(), PP.getLangOpts(),
- true))
- {
+ &PP.getDiagnostics(), PP.getLangOpts(), true)) {
HadError = true;
} else if (*buffer_begin > largest_character_for_kind) {
HadError = true;
@@ -1007,7 +1096,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
*buffer_begin++ = result;
}
- unsigned NumCharsSoFar = buffer_begin-&codepoint_buffer.front();
+ unsigned NumCharsSoFar = buffer_begin - &codepoint_buffer.front();
if (NumCharsSoFar > 1) {
if (isWide())
@@ -1019,8 +1108,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
else
PP.Diag(Loc, diag::err_multichar_utf_character_literal);
IsMultiChar = true;
- } else
+ } else {
IsMultiChar = false;
+ }
llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
@@ -1029,7 +1119,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
bool multi_char_too_long = false;
if (isAscii() && isMultiChar()) {
LitVal = 0;
- for (size_t i=0;i<NumCharsSoFar;++i) {
+ for (size_t i = 0; i < NumCharsSoFar; ++i) {
// check for enough leading zeros to shift into
multi_char_too_long |= (LitVal.countLeadingZeros() < 8);
LitVal <<= 8;
@@ -1041,7 +1131,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
}
if (!HadError && multi_char_too_long) {
- PP.Diag(Loc,diag::warn_char_constant_too_large);
+ PP.Diag(Loc, diag::warn_char_constant_too_large);
}
// Transfer the value from APInt to uint64_t
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 3e7a44c0e35d..f4dfa12854a3 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -27,7 +27,7 @@
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <stdlib.h>
#if defined(LLVM_ON_UNIX)
@@ -83,18 +83,18 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
return Context;
}
-ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC,
+ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo)
- : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo),
- BuiltinIncludeDir(0)
-{
+ : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target),
+ HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0),
+ SourceModule(0) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
Diags->setClient(new ForwardingDiagnosticConsumer(DC),
/*ShouldOwnClient=*/true);
- SourceMgr = new SourceManager(*Diags, FileMgr);
+ Diags->setSourceManager(&SourceMgr);
}
ModuleMap::~ModuleMap() {
@@ -103,8 +103,6 @@ ModuleMap::~ModuleMap() {
I != IEnd; ++I) {
delete I->getValue();
}
-
- delete SourceMgr;
}
void ModuleMap::setTarget(const TargetInfo &Target) {
@@ -168,14 +166,41 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false);
}
-Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
+ModuleMap::KnownHeader
+ModuleMap::findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule) {
HeadersMap::iterator Known = Headers.find(File);
if (Known != Headers.end()) {
- // If a header is not available, don't report that it maps to anything.
- if (!Known->second.isAvailable())
- return 0;
+ ModuleMap::KnownHeader Result = KnownHeader();
+
+ // Iterate over all modules that 'File' is part of to find the best fit.
+ for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ // Cannot use a module if the header is excluded or unavailable in it.
+ if (I->getRole() == ModuleMap::ExcludedHeader ||
+ !I->getModule()->isAvailable())
+ continue;
- return Known->second.getModule();
+ // If 'File' is part of 'RequestingModule', 'RequestingModule' is the
+ // module we are looking for.
+ if (I->getModule() == RequestingModule)
+ return *I;
+
+ // If uses need to be specified explicitly, we are only allowed to return
+ // modules that are explicitly used by the requesting module.
+ if (RequestingModule && LangOpts.ModulesDeclUse &&
+ std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ I->getModule()) == RequestingModule->DirectUses.end())
+ continue;
+ Result = *I;
+ // If 'File' is a public header of this module, this is as good as we
+ // are going to get.
+ if (I->getRole() == ModuleMap::NormalHeader)
+ break;
+ }
+ return Result;
}
// If we've found a builtin header within Clang's builtin include directory,
@@ -183,18 +208,11 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
// specific module (e.g., in /usr/include).
if (File->getDir() == BuiltinIncludeDir &&
isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
- SmallVector<Module *, 4> AllModules;
- HeaderInfo.collectAllModules(AllModules);
+ HeaderInfo.loadTopLevelSystemModules();
// Check again.
- Known = Headers.find(File);
- if (Known != Headers.end()) {
- // If a header is not available, don't report that it maps to anything.
- if (!Known->second.isAvailable())
- return 0;
-
- return Known->second.getModule();
- }
+ if (Headers.find(File) != Headers.end())
+ return findModuleForHeader(File, RequestingModule);
}
const DirectoryEntry *Dir = File->getDir();
@@ -204,7 +222,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
// frameworks moving from top-level frameworks to embedded frameworks tend
// to be symlinked from the top-level location to the embedded location,
// and we need to resolve lookups as if we had found the embedded location.
- StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir);
+ StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
@@ -263,14 +281,14 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
UmbrellaDirs[SkippedDirs[I]] = Result;
}
- Headers[File] = KnownHeader(Result, /*Excluded=*/false);
+ Headers[File].push_back(KnownHeader(Result, NormalHeader));
// If a header corresponds to an unavailable module, don't report
// that it maps to anything.
if (!Result->isAvailable())
- return 0;
+ return KnownHeader();
- return Result;
+ return Headers[File].back();
}
SkippedDirs.push_back(Dir);
@@ -281,16 +299,24 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
} while (Dir);
- return 0;
+ return KnownHeader();
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
HeadersMap::const_iterator Known = Headers.find(Header);
- if (Known != Headers.end())
- return !Known->second.isAvailable();
+ if (Known != Headers.end()) {
+ for (SmallVectorImpl<KnownHeader>::const_iterator
+ I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ if (I->isAvailable())
+ return false;
+ }
+ return true;
+ }
const DirectoryEntry *Dir = Header->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -347,7 +373,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
} while (Dir);
return false;
@@ -388,8 +414,17 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
// Create a new module with this name.
Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
IsExplicit);
- if (!Parent)
+ if (LangOpts.CurrentModule == Name) {
+ SourceModule = Result;
+ SourceModuleName = Name;
+ }
+ if (!Parent) {
Modules[Name] = Result;
+ if (!LangOpts.CurrentModule.empty() && !CompilingModule &&
+ Name == LangOpts.CurrentModule) {
+ CompilingModule = Result;
+ }
+ }
return std::make_pair(Result, true);
}
@@ -443,7 +478,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
return Mod;
- FileManager &FileMgr = SourceMgr->getFileManager();
+ FileManager &FileMgr = SourceMgr.getFileManager();
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
@@ -455,7 +490,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// top-level framework, and we need to infer as if we were naming the
// top-level framework.
StringRef FrameworkDirName
- = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
+ = SourceMgr.getFileManager().getCanonicalName(FrameworkDir);
bool canInfer = false;
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
@@ -472,7 +507,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
SmallString<128> ModMapPath = Parent;
llvm::sys::path::append(ModMapPath, "module.map");
if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
- parseModuleMapFile(ModMapFile);
+ parseModuleMapFile(ModMapFile, IsSystem);
inferred = InferredDirectories.find(ParentDir);
}
@@ -503,8 +538,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
- llvm::sys::path::append(UmbrellaName, "Headers");
- llvm::sys::path::append(UmbrellaName, ModuleName + ".h");
+ llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
const FileEntry *UmbrellaHeader = FileMgr.getFile(UmbrellaName);
// FIXME: If there's no umbrella header, we could probably scan the
@@ -515,6 +549,10 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false);
+ if (LangOpts.CurrentModule == ModuleName) {
+ SourceModule = Result;
+ SourceModuleName = ModuleName;
+ }
if (IsSystem)
Result->IsSystem = IsSystem;
@@ -523,7 +561,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
- Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Result, NormalHeader));
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
@@ -538,11 +576,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
SmallString<128> SubframeworksDirName
= StringRef(FrameworkDir->getName());
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
- SmallString<128> SubframeworksDirNameNative;
- llvm::sys::path::native(SubframeworksDirName.str(),
- SubframeworksDirNameNative);
+ llvm::sys::path::native(SubframeworksDirName);
for (llvm::sys::fs::directory_iterator
- Dir(SubframeworksDirNameNative.str(), EC), DirEnd;
+ Dir(SubframeworksDirName.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
@@ -589,7 +625,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
- Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
@@ -600,23 +636,27 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
}
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
- bool Excluded) {
- if (Excluded) {
+ ModuleHeaderRole Role) {
+ if (Role == ExcludedHeader) {
Mod->ExcludedHeaders.push_back(Header);
} else {
- Mod->Headers.push_back(Header);
- HeaderInfo.MarkFileModuleHeader(Header);
+ if (Role == PrivateHeader)
+ Mod->PrivateHeaders.push_back(Header);
+ else
+ Mod->NormalHeaders.push_back(Header);
+ bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule;
+ HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader);
}
- Headers[Header] = KnownHeader(Mod, Excluded);
+ Headers[Header].push_back(KnownHeader(Mod, Role));
}
const FileEntry *
ModuleMap::getContainingModuleMapFile(Module *Module) const {
- if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
+ if (Module->DefinitionLoc.isInvalid())
return 0;
- return SourceMgr->getFileEntryForID(
- SourceMgr->getFileID(Module->DefinitionLoc));
+ return SourceMgr.getFileEntryForID(
+ SourceMgr.getFileID(Module->DefinitionLoc));
}
void ModuleMap::dump() {
@@ -629,8 +669,15 @@ void ModuleMap::dump() {
llvm::errs() << "Headers:";
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
- llvm::errs() << " \"" << H->first->getName() << "\" -> "
- << H->second.getModule()->getFullModuleName() << "\n";
+ llvm::errs() << " \"" << H->first->getName() << "\" -> ";
+ for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),
+ E = H->second.end();
+ I != E; ++I) {
+ if (I != H->second.begin())
+ llvm::errs() << ",";
+ llvm::errs() << I->getModule()->getFullModuleName();
+ }
+ llvm::errs() << "\n";
}
}
@@ -648,6 +695,20 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
return HadError;
}
+bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) {
+ Module *DirectUse =
+ resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain);
+ if (DirectUse)
+ Mod->DirectUses.push_back(DirectUse);
+ else
+ HadError = true;
+ }
+ Mod->UnresolvedDirectUses.clear();
+ return HadError;
+}
+
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
bool HadError = false;
for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
@@ -683,7 +744,7 @@ Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
while (const FileEntry *ExpansionFile
= SrcMgr.getFileEntryForID(ExpansionFileID)) {
// Find the module that owns this header (if any).
- if (Module *Mod = findModuleForHeader(ExpansionFile))
+ if (Module *Mod = findModuleForHeader(ExpansionFile).getModule())
return Mod;
// No module owns this header, so look up the inclusion chain to see if
@@ -712,14 +773,18 @@ namespace clang {
EndOfFile,
HeaderKeyword,
Identifier,
+ Exclaim,
ExcludeKeyword,
ExplicitKeyword,
ExportKeyword,
+ ExternKeyword,
FrameworkKeyword,
LinkKeyword,
ModuleKeyword,
Period,
+ PrivateKeyword,
UmbrellaKeyword,
+ UseKeyword,
RequiresKeyword,
Star,
StringLiteral,
@@ -780,6 +845,9 @@ namespace clang {
/// \brief The directory containing Clang-supplied headers.
const DirectoryEntry *BuiltinIncludeDir;
+ /// \brief Whether this module map is in a system header directory.
+ bool IsSystem;
+
/// \brief Whether an error occurred.
bool HadError;
@@ -803,10 +871,13 @@ namespace clang {
typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
+ void parseExternModuleDecl();
void parseRequiresDecl();
- void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
+ void parseHeaderDecl(clang::MMToken::TokenKind,
+ SourceLocation LeadingLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
+ void parseUseDecl();
void parseLinkDecl();
void parseConfigMacros();
void parseConflict();
@@ -821,10 +892,11 @@ namespace clang {
DiagnosticsEngine &Diags,
ModuleMap &Map,
const DirectoryEntry *Directory,
- const DirectoryEntry *BuiltinIncludeDir)
+ const DirectoryEntry *BuiltinIncludeDir,
+ bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
- HadError(false), ActiveModule(0)
+ Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
+ IsSystem(IsSystem), HadError(false), ActiveModule(0)
{
Tok.clear();
consumeToken();
@@ -852,12 +924,15 @@ retry:
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
+ .Case("extern", MMToken::ExternKeyword)
.Case("framework", MMToken::FrameworkKeyword)
.Case("header", MMToken::HeaderKeyword)
.Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword)
+ .Case("private", MMToken::PrivateKeyword)
.Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
+ .Case("use", MMToken::UseKeyword)
.Default(MMToken::Identifier);
break;
@@ -893,6 +968,10 @@ retry:
Tok.Kind = MMToken::Star;
break;
+ case tok::exclaim:
+ Tok.Kind = MMToken::Exclaim;
+ break;
+
case tok::string_literal: {
if (LToken.hasUDSuffix()) {
Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
@@ -1019,6 +1098,7 @@ namespace {
/// \brief Parse a module declaration.
///
/// module-declaration:
+/// 'extern' 'module' module-id string-literal
/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
/// { module-member* }
///
@@ -1034,7 +1114,12 @@ namespace {
/// inferred-submodule-declaration
void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
- Tok.is(MMToken::FrameworkKeyword));
+ Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword));
+ if (Tok.is(MMToken::ExternKeyword)) {
+ parseExternModuleDecl();
+ return;
+ }
+
// Parse 'explicit' or 'framework' keyword, if present.
SourceLocation ExplicitLoc;
bool Explicit = false;
@@ -1159,7 +1244,7 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
- if (Attrs.IsSystem)
+ if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
bool Done = false;
@@ -1179,14 +1264,19 @@ void ModuleMapParser::parseModuleDecl() {
break;
case MMToken::ExplicitKeyword:
+ case MMToken::ExternKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
parseModuleDecl();
break;
-
+
case MMToken::ExportKeyword:
parseExportDecl();
break;
+
+ case MMToken::UseKeyword:
+ parseUseDecl();
+ break;
case MMToken::RequiresKeyword:
parseRequiresDecl();
@@ -1195,7 +1285,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
- parseHeaderDecl(UmbrellaLoc, SourceLocation());
+ parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
else
parseUmbrellaDirDecl(UmbrellaLoc);
break;
@@ -1204,7 +1294,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::ExcludeKeyword: {
SourceLocation ExcludeLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword)) {
- parseHeaderDecl(SourceLocation(), ExcludeLoc);
+ parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
} else {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
<< "exclude";
@@ -1212,8 +1302,19 @@ void ModuleMapParser::parseModuleDecl() {
break;
}
+ case MMToken::PrivateKeyword: {
+ SourceLocation PrivateLoc = consumeToken();
+ if (Tok.is(MMToken::HeaderKeyword)) {
+ parseHeaderDecl(MMToken::PrivateKeyword, PrivateLoc);
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "private";
+ }
+ break;
+ }
+
case MMToken::HeaderKeyword:
- parseHeaderDecl(SourceLocation(), SourceLocation());
+ parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation());
break;
case MMToken::LinkKeyword:
@@ -1246,14 +1347,61 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = PreviousActiveModule;
}
+/// \brief Parse an extern module declaration.
+///
+/// extern module-declaration:
+/// 'extern' 'module' module-id string-literal
+void ModuleMapParser::parseExternModuleDecl() {
+ assert(Tok.is(MMToken::ExternKeyword));
+ consumeToken(); // 'extern' keyword
+
+ // Parse 'module' keyword.
+ if (!Tok.is(MMToken::ModuleKeyword)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
+ consumeToken();
+ HadError = true;
+ return;
+ }
+ consumeToken(); // 'module' keyword
+
+ // Parse the module name.
+ ModuleId Id;
+ if (parseModuleId(Id)) {
+ HadError = true;
+ return;
+ }
+
+ // Parse the referenced module map file name.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);
+ HadError = true;
+ return;
+ }
+ std::string FileName = Tok.getString();
+ consumeToken(); // filename
+
+ StringRef FileNameRef = FileName;
+ SmallString<128> ModuleMapFileName;
+ if (llvm::sys::path::is_relative(FileNameRef)) {
+ ModuleMapFileName += Directory->getName();
+ llvm::sys::path::append(ModuleMapFileName, FileName);
+ FileNameRef = ModuleMapFileName.str();
+ }
+ if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef))
+ Map.parseModuleMapFile(File, /*IsSystem=*/false);
+}
+
/// \brief Parse a requires declaration.
///
/// requires-declaration:
/// 'requires' feature-list
///
/// feature-list:
-/// identifier ',' feature-list
-/// identifier
+/// feature ',' feature-list
+/// feature
+///
+/// feature:
+/// '!'[opt] identifier
void ModuleMapParser::parseRequiresDecl() {
assert(Tok.is(MMToken::RequiresKeyword));
@@ -1262,6 +1410,12 @@ void ModuleMapParser::parseRequiresDecl() {
// Parse the feature-list.
do {
+ bool RequiredState = true;
+ if (Tok.is(MMToken::Exclaim)) {
+ RequiredState = false;
+ consumeToken();
+ }
+
if (!Tok.is(MMToken::Identifier)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
HadError = true;
@@ -1273,7 +1427,8 @@ void ModuleMapParser::parseRequiresDecl() {
consumeToken();
// Add this feature.
- ActiveModule->addRequirement(Feature, Map.LangOpts, *Map.Target);
+ ActiveModule->addRequirement(Feature, RequiredState,
+ Map.LangOpts, *Map.Target);
if (!Tok.is(MMToken::Comma))
break;
@@ -1298,10 +1453,8 @@ static void appendSubframeworkPaths(Module *Mod,
return;
// Add Frameworks/Name.framework for each subframework.
- for (unsigned I = Paths.size() - 1; I != 0; --I) {
- llvm::sys::path::append(Path, "Frameworks");
- llvm::sys::path::append(Path, Paths[I-1] + ".framework");
- }
+ for (unsigned I = Paths.size() - 1; I != 0; --I)
+ llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
}
/// \brief Parse a header declaration.
@@ -1309,14 +1462,11 @@ static void appendSubframeworkPaths(Module *Mod,
/// header-declaration:
/// 'umbrella'[opt] 'header' string-literal
/// 'exclude'[opt] 'header' string-literal
-void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
- SourceLocation ExcludeLoc) {
+void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
+ SourceLocation LeadingLoc) {
assert(Tok.is(MMToken::HeaderKeyword));
consumeToken();
- bool Umbrella = UmbrellaLoc.isValid();
- bool Exclude = ExcludeLoc.isValid();
- assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'");
// Parse the header name.
if (!Tok.is(MMToken::StringLiteral)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
@@ -1328,7 +1478,7 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
SourceLocation FileNameLoc = consumeToken();
// Check whether we already have an umbrella.
- if (Umbrella && ActiveModule->Umbrella) {
+ if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
@@ -1355,15 +1505,13 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
appendSubframeworkPaths(ActiveModule, PathName);
// Check whether this file is in the public headers.
- llvm::sys::path::append(PathName, "Headers");
- llvm::sys::path::append(PathName, FileName);
+ llvm::sys::path::append(PathName, "Headers", FileName);
File = SourceMgr.getFileManager().getFile(PathName);
if (!File) {
// Check whether this file is in the private headers.
PathName.resize(PathLength);
- llvm::sys::path::append(PathName, "PrivateHeaders");
- llvm::sys::path::append(PathName, FileName);
+ llvm::sys::path::append(PathName, "PrivateHeaders", FileName);
File = SourceMgr.getFileManager().getFile(PathName);
}
} else {
@@ -1374,8 +1522,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
// 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 && !Umbrella && BuiltinIncludeDir &&
- BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) {
+ if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
+ BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
+ isBuiltinHeader(FileName)) {
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
@@ -1394,14 +1543,10 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
// 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 (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
- Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
- << FileName << OwningModule.getModule()->getFullModuleName();
- HadError = true;
- } else if (Umbrella) {
+ if (LeadingToken == MMToken::UmbrellaKeyword) {
const DirectoryEntry *UmbrellaDir = File->getDir();
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
- Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
+ Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
<< UmbrellaModule->getFullModuleName();
HadError = true;
} else {
@@ -1410,17 +1555,25 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
}
} else {
// Record this header.
- Map.addHeader(ActiveModule, File, Exclude);
+ ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
+ if (LeadingToken == MMToken::ExcludeKeyword)
+ Role = ModuleMap::ExcludedHeader;
+ else if (LeadingToken == MMToken::PrivateKeyword)
+ Role = ModuleMap::PrivateHeader;
+ else
+ assert(LeadingToken == MMToken::HeaderKeyword);
+
+ Map.addHeader(ActiveModule, File, Role);
// If there is a builtin counterpart to this file, add it now.
if (BuiltinFile)
- Map.addHeader(ActiveModule, BuiltinFile, Exclude);
+ Map.addHeader(ActiveModule, BuiltinFile, Role);
}
- } else if (!Exclude) {
+ } else if (LeadingToken != MMToken::ExcludeKeyword) {
// Ignore excluded header files. They're optional anyway.
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
- << Umbrella << FileName;
+ << (LeadingToken == MMToken::UmbrellaKeyword) << FileName;
HadError = true;
}
}
@@ -1514,7 +1667,7 @@ void ModuleMapParser::parseExportDecl() {
break;
}
- Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
HadError = true;
return;
} while (true);
@@ -1525,6 +1678,38 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
+/// \brief Parse a module uses declaration.
+///
+/// uses-declaration:
+/// 'uses' wildcard-module-id
+void ModuleMapParser::parseUseDecl() {
+ assert(Tok.is(MMToken::UseKeyword));
+ consumeToken();
+ // Parse the module-id.
+ ModuleId ParsedModuleId;
+
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ ParsedModuleId.push_back(
+ std::make_pair(Tok.getString(), Tok.getLocation()));
+ consumeToken();
+
+ if (Tok.is(MMToken::Period)) {
+ consumeToken();
+ continue;
+ }
+
+ break;
+ }
+
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
+ HadError = true;
+ return;
+ } while (true);
+
+ ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
+}
+
/// \brief Parse a link declaration.
///
/// module-declaration:
@@ -1787,6 +1972,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword:
+ case MMToken::PrivateKeyword:
case MMToken::UmbrellaKeyword:
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
@@ -1897,6 +2083,7 @@ bool ModuleMapParser::parseModuleMapFile() {
return HadError;
case MMToken::ExplicitKeyword:
+ case MMToken::ExternKeyword:
case MMToken::ModuleKeyword:
case MMToken::FrameworkKeyword:
parseModuleDecl();
@@ -1905,6 +2092,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::Comma:
case MMToken::ConfigMacros:
case MMToken::Conflict:
+ case MMToken::Exclaim:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
@@ -1913,12 +2101,14 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::LinkKeyword:
case MMToken::LSquare:
case MMToken::Period:
+ case MMToken::PrivateKeyword:
case MMToken::RBrace:
case MMToken::RSquare:
case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
case MMToken::UmbrellaKeyword:
+ case MMToken::UseKeyword:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
HadError = true;
consumeToken();
@@ -1927,23 +2117,23 @@ bool ModuleMapParser::parseModuleMapFile() {
} while (true);
}
-bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
llvm::DenseMap<const FileEntry *, bool>::iterator Known
= ParsedModuleMap.find(File);
if (Known != ParsedModuleMap.end())
return Known->second;
assert(Target != 0 && "Missing target information");
- FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
- const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
+ FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
// Parse this module map file.
- Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+ Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
Diags->getClient()->BeginSourceFile(MMapLangOpts);
- ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(),
- BuiltinIncludeDir);
+ ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(),
+ BuiltinIncludeDir, IsSystem);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
ParsedModuleMap[File] = Result;
diff --git a/lib/Lex/PPConditionalDirectiveRecord.cpp b/lib/Lex/PPConditionalDirectiveRecord.cpp
index 16ce3efb0461..16dc1d8f0913 100644
--- a/lib/Lex/PPConditionalDirectiveRecord.cpp
+++ b/lib/Lex/PPConditionalDirectiveRecord.cpp
@@ -76,7 +76,8 @@ void PPConditionalDirectiveRecord::addCondDirectiveLoc(
}
void PPConditionalDirectiveRecord::If(SourceLocation Loc,
- SourceRange ConditionRange) {
+ SourceRange ConditionRange,
+ bool ConditionValue) {
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
CondDirectiveStack.push_back(Loc);
}
@@ -97,6 +98,7 @@ void PPConditionalDirectiveRecord::Ifndef(SourceLocation Loc,
void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
SourceRange ConditionRange,
+ bool ConditionValue,
SourceLocation IfLoc) {
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
CondDirectiveStack.back() = Loc;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 50a0cb55f736..86c508fe9b1b 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
@@ -241,7 +242,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
bool FoundElse,
SourceLocation ElseLoc) {
++NumSkipped;
- assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?");
+ assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");
CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
FoundNonSkipPortion, FoundElse);
@@ -430,7 +431,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (Callbacks)
Callbacks->Elif(Tok.getLocation(),
SourceRange(ConditionalBegin, ConditionalEnd),
- CondInfo.IfLoc);
+ ShouldEnter, CondInfo.IfLoc);
break;
}
}
@@ -531,14 +532,97 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
}
}
+Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) {
+ ModuleMap &ModMap = HeaderInfo.getModuleMap();
+ if (SourceMgr.isInMainFile(FilenameLoc)) {
+ if (Module *CurMod = getCurrentModule())
+ return CurMod; // Compiling a module.
+ return HeaderInfo.getModuleMap().SourceModule; // Compiling a source.
+ }
+ // Try to determine the module of the include directive.
+ FileID IDOfIncl = SourceMgr.getFileID(FilenameLoc);
+ if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) {
+ // The include comes from a file.
+ return ModMap.findModuleForHeader(EntryOfIncl).getModule();
+ } else {
+ // The include does not come from a file,
+ // so it is probably a module compilation.
+ return getCurrentModule();
+ }
+}
+
+bool Preprocessor::violatesPrivateInclude(
+ Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule) {
+ #ifndef NDEBUG
+ // Check for consistency between the module header role
+ // as obtained from the lookup and as obtained from the module.
+ // This check is not cheap, so enable it only for debugging.
+ SmallVectorImpl<const FileEntry *> &PvtHdrs
+ = RequestedModule->PrivateHeaders;
+ SmallVectorImpl<const FileEntry *>::iterator Look
+ = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
+ bool IsPrivate = Look != PvtHdrs.end();
+ assert((IsPrivate && Role == ModuleMap::PrivateHeader)
+ || (!IsPrivate && Role != ModuleMap::PrivateHeader));
+ #endif
+ return Role == ModuleMap::PrivateHeader &&
+ RequestedModule->getTopLevelModule() != RequestingModule;
+}
+
+bool Preprocessor::violatesUseDeclarations(
+ Module *RequestingModule,
+ Module *RequestedModule) {
+ ModuleMap &ModMap = HeaderInfo.getModuleMap();
+ ModMap.resolveUses(RequestingModule, /*Complain=*/false);
+ const SmallVectorImpl<Module *> &AllowedUses = RequestingModule->DirectUses;
+ SmallVectorImpl<Module *>::const_iterator Declared =
+ std::find(AllowedUses.begin(), AllowedUses.end(), RequestedModule);
+ return Declared == AllowedUses.end();
+}
+
+void Preprocessor::verifyModuleInclude(SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *IncFileEnt) {
+ Module *RequestingModule = getModuleForLocation(FilenameLoc);
+ if (RequestingModule)
+ HeaderInfo.getModuleMap().resolveUses(RequestingModule, /*Complain=*/false);
+ ModuleMap::KnownHeader RequestedModule =
+ HeaderInfo.getModuleMap().findModuleForHeader(IncFileEnt,
+ RequestingModule);
+
+ if (RequestingModule == RequestedModule.getModule())
+ return; // No faults wihin a module, or between files both not in modules.
+
+ if (RequestingModule != HeaderInfo.getModuleMap().SourceModule)
+ return; // No errors for indirect modules.
+ // This may be a bit of a problem for modules with no source files.
+
+ if (RequestedModule && violatesPrivateInclude(RequestingModule, IncFileEnt,
+ RequestedModule.getRole(),
+ RequestedModule.getModule()))
+ Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
+ << Filename;
+
+ // FIXME: Add support for FixIts in module map files and offer adding the
+ // required use declaration.
+ if (RequestingModule && getLangOpts().ModulesDeclUse &&
+ violatesUseDeclarations(RequestingModule, RequestedModule.getModule()))
+ Diag(FilenameLoc, diag::error_undeclared_use_of_module)
+ << Filename;
+}
+
const FileEntry *Preprocessor::LookupFile(
+ SourceLocation FilenameLoc,
StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- Module **SuggestedModule,
+ ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache) {
// If the header lookup mechanism may be relative to the current file, pass in
// info about where the current file is.
@@ -564,7 +648,11 @@ const FileEntry *Preprocessor::LookupFile(
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, isAngled, FromDir, CurDir, CurFileEnt,
SearchPath, RelativePath, SuggestedModule, SkipCache);
- if (FE) return FE;
+ if (FE) {
+ if (SuggestedModule)
+ verifyModuleInclude(FilenameLoc, Filename, FE);
+ return FE;
+ }
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
@@ -626,6 +714,10 @@ void Preprocessor::HandleDirective(Token &Result) {
CurPPLexer->ParsingPreprocessorDirective = true;
if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);
+ bool ImmediatelyAfterTopLevelIfndef =
+ CurPPLexer->MIOpt.getImmediatelyAfterTopLevelIfndef();
+ CurPPLexer->MIOpt.resetImmediatelyAfterTopLevelIfndef();
+
++NumDirectives;
// We are about to read a token. For the multiple-include optimization FA to
@@ -713,7 +805,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// C99 6.10.3 - Macro Replacement.
case tok::pp_define:
- return HandleDefineDirective(Result);
+ return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef);
case tok::pp_undef:
return HandleUndefDirective(Result);
@@ -727,7 +819,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// C99 6.10.6 - Pragma Directive.
case tok::pp_pragma:
- return HandlePragmaDirective(PIK_HashPragma);
+ return HandlePragmaDirective(SavedHash.getLocation(), PIK_HashPragma);
// GNU Extensions.
case tok::pp_import:
@@ -819,6 +911,11 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
// here.
Val = 0;
for (unsigned i = 0; i != ActualLength; ++i) {
+ // C++1y [lex.fcon]p1:
+ // Optional separating single quotes in a digit-sequence are ignored
+ if (DigitTokBegin[i] == '\'')
+ continue;
+
if (!isDigit(DigitTokBegin[i])) {
PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i),
diag::err_pp_line_digit_sequence) << IsGNULineDirective;
@@ -1386,11 +1483,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
SmallString<1024> RelativePath;
// We get the raw path only if we have 'Callbacks' to which we later pass
// the path.
- Module *SuggestedModule = 0;
+ ModuleMap::KnownHeader SuggestedModule;
+ SourceLocation FilenameLoc = FilenameTok.getLocation();
const FileEntry *File = LookupFile(
- Filename, isAngled, LookupFrom, CurDir,
+ FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
- getLangOpts().Modules? &SuggestedModule : 0);
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
if (Callbacks) {
if (!File) {
@@ -1403,14 +1501,16 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache.
- File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0,
- getLangOpts().Modules? &SuggestedModule : 0,
- /*SkipCache*/true);
+ File = LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
+ 0, 0, HeaderInfo.getHeaderSearchOpts().ModuleMaps
+ ? &SuggestedModule
+ : 0,
+ /*SkipCache*/ true);
}
}
}
- if (!SuggestedModule) {
+ if (!SuggestedModule || !getLangOpts().Modules) {
// Notify the callback object that we've seen an inclusion directive.
Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
FilenameRange, File,
@@ -1425,10 +1525,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// brackets, we can attempt a lookup as though it were a quoted path to
// provide the user with a possible fixit.
if (isAngled) {
- File = LookupFile(Filename, false, LookupFrom, CurDir,
- Callbacks ? &SearchPath : 0,
- Callbacks ? &RelativePath : 0,
- getLangOpts().Modules ? &SuggestedModule : 0);
+ File = LookupFile(
+ FilenameLoc, Filename, false, LookupFrom, CurDir,
+ Callbacks ? &SearchPath : 0, Callbacks ? &RelativePath : 0,
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) <<
@@ -1446,12 +1546,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// If we are supposed to import a module rather than including the header,
// do so now.
- if (SuggestedModule) {
+ if (SuggestedModule && getLangOpts().Modules) {
// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
- for (Module *Mod = SuggestedModule; Mod; Mod = Mod->Parent)
+ for (Module *Mod = SuggestedModule.getModule(); Mod; Mod = Mod->Parent)
Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation()));
std::reverse(Path.begin(), Path.end());
@@ -1503,16 +1603,29 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
"@import " + PathString.str().str() + ";");
}
- // Load the module.
- // If this was an #__include_macros directive, only make macros visible.
- Module::NameVisibilityKind Visibility
- = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
+ // Load the module. Only make macros visible. We'll make the declarations
+ // visible when the parser gets here.
+ Module::NameVisibilityKind Visibility = Module::MacrosVisible;
ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
- assert((Imported == 0 || Imported == SuggestedModule) &&
+ assert((Imported == 0 || Imported == SuggestedModule.getModule()) &&
"the imported module is different than the suggested one");
-
+
+ if (!Imported && hadModuleLoaderFatalFailure()) {
+ // With a fatal failure in the module loader, we abort parsing.
+ Token &Result = IncludeTok;
+ if (CurLexer) {
+ Result.startToken();
+ CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
+ CurLexer->cutOffLexing();
+ } else {
+ assert(CurPTHLexer && "#include but no current lexer set!");
+ CurPTHLexer->getEOF(Result);
+ }
+ return;
+ }
+
// If this header isn't part of the module we're building, we're done.
if (!BuildingImportedModule && Imported) {
if (Callbacks) {
@@ -1520,6 +1633,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FilenameRange, File,
SearchPath, RelativePath, Imported);
}
+
+ if (IncludeKind != 3) {
+ // Let the parser know that we hit a module import, and it should
+ // make the module visible.
+ // FIXME: Produce this as the current token directly, rather than
+ // allocating a new token for it.
+ Token *Tok = new Token[1];
+ Tok[0].startToken();
+ Tok[0].setKind(tok::annot_module_include);
+ Tok[0].setLocation(HashLoc);
+ Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setAnnotationValue(Imported);
+ EnterTokenStream(Tok, 1, true, true);
+ }
return;
}
@@ -1746,7 +1873,8 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
/// HandleDefineDirective - Implements \#define. This consumes the entire macro
/// line then lets the caller lex the next real token.
-void Preprocessor::HandleDefineDirective(Token &DefineTok) {
+void Preprocessor::HandleDefineDirective(Token &DefineTok,
+ bool ImmediatelyAfterHeaderGuard) {
++NumDefined;
Token MacroNameTok;
@@ -1772,6 +1900,11 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// marking each of the identifiers as being used as macro arguments. Also,
// check other constraints on the first token of the macro body.
if (Tok.is(tok::eod)) {
+ if (ImmediatelyAfterHeaderGuard) {
+ // Save this macro information since it may part of a header guard.
+ CurPPLexer->MIOpt.SetDefinedMacro(MacroNameTok.getIdentifierInfo(),
+ MacroNameTok.getLocation());
+ }
// If there is no body to this macro, we have no special handling here.
} else if (Tok.hasLeadingSpace()) {
// This is a normal token with leading space. Clear the leading space
@@ -1854,6 +1987,18 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
continue;
}
+ // If we're in -traditional mode, then we should ignore stringification
+ // and token pasting. Mark the tokens as unknown so as not to confuse
+ // things.
+ if (getLangOpts().TraditionalCPP) {
+ Tok.setKind(tok::unknown);
+ MI->AddTokenToBody(Tok);
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ continue;
+ }
+
if (Tok.is(tok::hashhash)) {
// If we see token pasting, check if it looks like the gcc comma
@@ -1873,13 +2018,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
MI->getReplacementToken(NumTokens-1).is(tok::comma))
MI->setHasCommaPasting();
- // Things look ok, add the '##' and param name tokens to the macro.
+ // Things look ok, add the '##' token to the macro.
MI->AddTokenToBody(LastTok);
- MI->AddTokenToBody(Tok);
- LastTok = Tok;
-
- // Get the next token of the macro.
- LexUnexpandedToken(Tok);
continue;
}
@@ -1896,6 +2036,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// confused.
if (getLangOpts().AsmPreprocessor && Tok.isNot(tok::eod)) {
LastTok.setKind(tok::unknown);
+ MI->AddTokenToBody(LastTok);
+ continue;
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter);
ReleaseMacroInfo(MI);
@@ -1972,7 +2114,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
assert(!MI->isUsed());
// If we need warning for not using the macro, add its location in the
// warn-because-unused-macro set. If it gets used it will be removed from set.
- if (isInPrimaryFile() && // don't warn for include'd macros.
+ if (getSourceManager().isInMainFile(MI->getDefinitionLoc()) &&
Diags->getDiagnosticLevel(diag::pp_macro_not_used,
MI->getDefinitionLoc()) != DiagnosticsEngine::Ignored) {
MI->setIsWarnIfUnused(true);
@@ -2062,7 +2204,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
// handle.
if (!ReadAnyTokensBeforeDirective && MI == 0) {
assert(isIfndef && "#ifdef shouldn't reach here");
- CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MII);
+ CurPPLexer->MIOpt.EnterTopLevelIfndef(MII, MacroNameTok.getLocation());
} else
CurPPLexer->MIOpt.EnterTopLevelConditional();
}
@@ -2108,14 +2250,16 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
// directive seen, handle it for the multiple-include optimization.
if (CurPPLexer->getConditionalStackDepth() == 0) {
if (!ReadAnyTokensBeforeDirective && IfNDefMacro && ConditionalTrue)
- CurPPLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro);
+ // FIXME: Pass in the location of the macro name, not the 'if' token.
+ CurPPLexer->MIOpt.EnterTopLevelIfndef(IfNDefMacro, IfToken.getLocation());
else
CurPPLexer->MIOpt.EnterTopLevelConditional();
}
if (Callbacks)
Callbacks->If(IfToken.getLocation(),
- SourceRange(ConditionalBegin, ConditionalEnd));
+ SourceRange(ConditionalBegin, ConditionalEnd),
+ ConditionalTrue);
// Should we include the stuff contained by this directive?
if (ConditionalTrue) {
@@ -2211,7 +2355,8 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
if (Callbacks)
Callbacks->Elif(ElifToken.getLocation(),
- SourceRange(ConditionalBegin, ConditionalEnd), CI.IfLoc);
+ SourceRange(ConditionalBegin, ConditionalEnd),
+ true, CI.IfLoc);
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index d9ce8bff237c..87c0a6ace6cb 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -82,7 +82,8 @@ struct DefinedTracker {
static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
bool ValueLive, Preprocessor &PP) {
IdentifierInfo *II;
- Result.setBegin(PeekTok.getLocation());
+ SourceLocation beginLoc(PeekTok.getLocation());
+ Result.setBegin(beginLoc);
// Get the next token, don't expand it.
PP.LexUnexpandedNonComment(PeekTok);
@@ -119,14 +120,8 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.markMacroAsUsed(Macro->getMacroInfo());
}
- // Invoke the 'defined' callback.
- if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
- MacroDirective *MD = Macro;
- // Pass the MacroInfo for the macro name even if the value is dead.
- if (!MD && Result.Val != 0)
- MD = PP.getMacroDirective(II);
- Callbacks->Defined(PeekTok, MD);
- }
+ // Save macro token for callback.
+ Token macroToken(PeekTok);
// If we are in parens, ensure we have a trailing ).
if (LParenLoc.isValid()) {
@@ -148,6 +143,16 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexNonComment(PeekTok);
}
+ // Invoke the 'defined' callback.
+ if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
+ MacroDirective *MD = Macro;
+ // Pass the MacroInfo for the macro name even if the value is dead.
+ if (!MD && Result.Val != 0)
+ MD = PP.getMacroDirective(II);
+ Callbacks->Defined(macroToken, MD,
+ SourceRange(beginLoc, PeekTok.getLocation()));
+ }
+
// Success, remember that we saw defined(X).
DT.State = DefinedTracker::DefinedMacro;
DT.TheMacro = II;
@@ -240,7 +245,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
// Overflow parsing integer literal.
- if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large);
+ if (ValueLive) PP.Diag(PeekTok, diag::err_integer_too_large);
Result.Val.setIsUnsigned(true);
} else {
// Set the signedness of the result to match whether there was a U suffix
@@ -252,8 +257,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// large that it is unsigned" e.g. on 12345678901234567890 where intmax_t
// is 64-bits.
if (!Literal.isUnsigned && Result.Val.isNegative()) {
- // Don't warn for a hex literal: 0x8000..0 shouldn't warn.
- if (ValueLive && Literal.getRadix() != 16)
+ // Don't warn for a hex or octal literal: 0x8000..0 shouldn't warn.
+ if (ValueLive && Literal.getRadix() == 10)
PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed);
Result.Val.setIsUnsigned(true);
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index be4defe78648..1f970a4450de 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -21,7 +21,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
using namespace clang;
PPCallbacks::~PPCallbacks() {}
@@ -70,7 +70,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
/// start lexing tokens from it instead of the current buffer.
void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
SourceLocation Loc) {
- assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
+ assert(!CurTokenLexer && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
if (MaxIncludeStackDepth < IncludeMacroStack.size())
@@ -231,6 +231,19 @@ static void computeRelativePath(FileManager &FM, const DirectoryEntry *Dir,
Result = File->getName();
}
+void Preprocessor::PropagateLineStartLeadingSpaceInfo(Token &Result) {
+ if (CurTokenLexer) {
+ CurTokenLexer->PropagateLineStartLeadingSpaceInfo(Result);
+ return;
+ }
+ if (CurLexer) {
+ CurLexer->PropagateLineStartLeadingSpaceInfo(Result);
+ return;
+ }
+ // FIXME: Handle other kinds of lexers? It generally shouldn't matter,
+ // but it might if they're empty?
+}
+
/// 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
/// the include stack and keeps going.
@@ -244,8 +257,42 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
// Okay, this has a controlling macro, remember in HeaderFileInfo.
if (const FileEntry *FE =
- SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))
+ SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
+ if (const IdentifierInfo *DefinedMacro =
+ CurPPLexer->MIOpt.GetDefinedMacro()) {
+ if (!ControllingMacro->hasMacroDefinition() &&
+ DefinedMacro != ControllingMacro &&
+ HeaderInfo.FirstTimeLexingFile(FE)) {
+
+ // If the edit distance between the two macros is more than 50%,
+ // DefinedMacro may not be header guard, or can be header guard of
+ // another header file. Therefore, it maybe defining something
+ // completely different. This can be observed in the wild when
+ // handling feature macros or header guards in different files.
+
+ const StringRef ControllingMacroName = ControllingMacro->getName();
+ const StringRef DefinedMacroName = DefinedMacro->getName();
+ const size_t MaxHalfLength = std::max(ControllingMacroName.size(),
+ DefinedMacroName.size()) / 2;
+ const unsigned ED = ControllingMacroName.edit_distance(
+ DefinedMacroName, true, MaxHalfLength);
+ if (ED <= MaxHalfLength) {
+ // Emit a warning for a bad header guard.
+ Diag(CurPPLexer->MIOpt.GetMacroLocation(),
+ diag::warn_header_guard)
+ << CurPPLexer->MIOpt.GetMacroLocation() << ControllingMacro;
+ Diag(CurPPLexer->MIOpt.GetDefinedLocation(),
+ diag::note_header_guard)
+ << CurPPLexer->MIOpt.GetDefinedLocation() << DefinedMacro
+ << ControllingMacro
+ << FixItHint::CreateReplacement(
+ CurPPLexer->MIOpt.GetDefinedLocation(),
+ ControllingMacro->getName());
+ }
+ }
+ }
+ }
}
}
@@ -299,6 +346,9 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// We're done with the #included file.
RemoveTopOfLexerStack();
+ // Propagate info about start-of-line/leading white-space/etc.
+ PropagateLineStartLeadingSpaceInfo(Result);
+
// Notify the client, if desired, that we are in a new source file.
if (Callbacks && !isEndOfMacro && CurPPLexer) {
SrcMgr::CharacteristicKind FileType =
@@ -401,8 +451,36 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
}
}
+
+ // Check whether there are any headers that were included, but not
+ // mentioned at all in the module map. Such headers
+ SourceLocation StartLoc
+ = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_forgotten_module_header,
+ StartLoc)
+ != DiagnosticsEngine::Ignored) {
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ for (unsigned I = 0, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
+ // We only care about file entries.
+ const SrcMgr::SLocEntry &Entry = SourceMgr.getLocalSLocEntry(I);
+ if (!Entry.isFile())
+ continue;
+
+ // Dig out the actual file.
+ const FileEntry *File = Entry.getFile().getContentCache()->OrigEntry;
+ if (!File)
+ continue;
+
+ // If it's not part of a module and not unknown, complain.
+ if (!ModMap.findModuleForHeader(File) &&
+ !ModMap.isHeaderInUnavailableModule(File)) {
+ Diag(StartLoc, diag::warn_forgotten_module_header)
+ << File->getName() << Mod->getFullModuleName();
+ }
+ }
+ }
}
-
+
return true;
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 24c6217ced2a..f20633fda8c9 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -225,7 +225,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (Callbacks) Callbacks->MacroExpands(Identifier, MD,
Identifier.getLocation(),/*Args=*/0);
ExpandBuiltinMacro(Identifier);
- return false;
+ return true;
}
/// Args - If this is a function-like macro expansion, this contains,
@@ -239,11 +239,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// If this is a function-like macro, read the arguments.
if (MI->isFunctionLike()) {
- // C99 6.10.3p10: If the preprocessing token immediately after the macro
- // name isn't a '(', this macro should not be expanded.
- if (!isNextPPTokenLParen())
- return true;
-
// Remember that we are now parsing the arguments to a macro invocation.
// Preprocessor directives used inside macro arguments are not portable, and
// this enables the warning.
@@ -254,7 +249,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
InMacroArgs = false;
// If there was an error parsing the arguments, bail out.
- if (Args == 0) return false;
+ if (Args == 0) return true;
++NumFnMacroExpanded;
} else {
@@ -314,25 +309,12 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// No need for arg info.
if (Args) Args->destroy(*this);
- // Ignore this macro use, just return the next token in the current
- // buffer.
- bool HadLeadingSpace = Identifier.hasLeadingSpace();
- bool IsAtStartOfLine = Identifier.isAtStartOfLine();
-
- Lex(Identifier);
-
- // If the identifier isn't on some OTHER line, inherit the leading
- // whitespace/first-on-a-line property of this token. This handles
- // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is
- // empty.
- if (!Identifier.isAtStartOfLine()) {
- if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine);
- if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
- }
+ // Propagate whitespace info as if we had pushed, then popped,
+ // a macro context.
Identifier.setFlag(Token::LeadingEmptyMacro);
+ PropagateLineStartLeadingSpaceInfo(Identifier);
++NumFastMacroExpanded;
return false;
-
} else if (MI->getNumTokens() == 1 &&
isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(),
*this)) {
@@ -378,18 +360,144 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Since this is not an identifier token, it can't be macro expanded, so
// we're done.
++NumFastMacroExpanded;
- return false;
+ return true;
}
// Start expanding the macro.
EnterMacro(Identifier, ExpansionEnd, MI, Args);
-
- // Now that the macro is at the top of the include stack, ask the
- // preprocessor to read the next token from it.
- Lex(Identifier);
return false;
}
+enum Bracket {
+ Brace,
+ Paren
+};
+
+/// CheckMatchedBrackets - Returns true if the braces and parentheses in the
+/// token vector are properly nested.
+static bool CheckMatchedBrackets(const SmallVectorImpl<Token> &Tokens) {
+ SmallVector<Bracket, 8> Brackets;
+ for (SmallVectorImpl<Token>::const_iterator I = Tokens.begin(),
+ E = Tokens.end();
+ I != E; ++I) {
+ if (I->is(tok::l_paren)) {
+ Brackets.push_back(Paren);
+ } else if (I->is(tok::r_paren)) {
+ if (Brackets.empty() || Brackets.back() == Brace)
+ return false;
+ Brackets.pop_back();
+ } else if (I->is(tok::l_brace)) {
+ Brackets.push_back(Brace);
+ } else if (I->is(tok::r_brace)) {
+ if (Brackets.empty() || Brackets.back() == Paren)
+ return false;
+ Brackets.pop_back();
+ }
+ }
+ if (!Brackets.empty())
+ return false;
+ return true;
+}
+
+/// GenerateNewArgTokens - Returns true if OldTokens can be converted to a new
+/// vector of tokens in NewTokens. The new number of arguments will be placed
+/// in NumArgs and the ranges which need to surrounded in parentheses will be
+/// in ParenHints.
+/// Returns false if the token stream cannot be changed. If this is because
+/// of an initializer list starting a macro argument, the range of those
+/// initializer lists will be place in InitLists.
+static bool GenerateNewArgTokens(Preprocessor &PP,
+ SmallVectorImpl<Token> &OldTokens,
+ SmallVectorImpl<Token> &NewTokens,
+ unsigned &NumArgs,
+ SmallVectorImpl<SourceRange> &ParenHints,
+ SmallVectorImpl<SourceRange> &InitLists) {
+ if (!CheckMatchedBrackets(OldTokens))
+ return false;
+
+ // Once it is known that the brackets are matched, only a simple count of the
+ // braces is needed.
+ unsigned Braces = 0;
+
+ // First token of a new macro argument.
+ SmallVectorImpl<Token>::iterator ArgStartIterator = OldTokens.begin();
+
+ // First closing brace in a new macro argument. Used to generate
+ // SourceRanges for InitLists.
+ SmallVectorImpl<Token>::iterator ClosingBrace = OldTokens.end();
+ NumArgs = 0;
+ Token TempToken;
+ // Set to true when a macro separator token is found inside a braced list.
+ // If true, the fixed argument spans multiple old arguments and ParenHints
+ // will be updated.
+ bool FoundSeparatorToken = false;
+ for (SmallVectorImpl<Token>::iterator I = OldTokens.begin(),
+ E = OldTokens.end();
+ I != E; ++I) {
+ if (I->is(tok::l_brace)) {
+ ++Braces;
+ } else if (I->is(tok::r_brace)) {
+ --Braces;
+ if (Braces == 0 && ClosingBrace == E && FoundSeparatorToken)
+ ClosingBrace = I;
+ } else if (I->is(tok::eof)) {
+ // EOF token is used to separate macro arguments
+ if (Braces != 0) {
+ // Assume comma separator is actually braced list separator and change
+ // it back to a comma.
+ FoundSeparatorToken = true;
+ I->setKind(tok::comma);
+ I->setLength(1);
+ } else { // Braces == 0
+ // Separator token still separates arguments.
+ ++NumArgs;
+
+ // If the argument starts with a brace, it can't be fixed with
+ // parentheses. A different diagnostic will be given.
+ if (FoundSeparatorToken && ArgStartIterator->is(tok::l_brace)) {
+ InitLists.push_back(
+ SourceRange(ArgStartIterator->getLocation(),
+ PP.getLocForEndOfToken(ClosingBrace->getLocation())));
+ ClosingBrace = E;
+ }
+
+ // Add left paren
+ if (FoundSeparatorToken) {
+ TempToken.startToken();
+ TempToken.setKind(tok::l_paren);
+ TempToken.setLocation(ArgStartIterator->getLocation());
+ TempToken.setLength(0);
+ NewTokens.push_back(TempToken);
+ }
+
+ // Copy over argument tokens
+ NewTokens.insert(NewTokens.end(), ArgStartIterator, I);
+
+ // Add right paren and store the paren locations in ParenHints
+ if (FoundSeparatorToken) {
+ SourceLocation Loc = PP.getLocForEndOfToken((I - 1)->getLocation());
+ TempToken.startToken();
+ TempToken.setKind(tok::r_paren);
+ TempToken.setLocation(Loc);
+ TempToken.setLength(0);
+ NewTokens.push_back(TempToken);
+ ParenHints.push_back(SourceRange(ArgStartIterator->getLocation(),
+ Loc));
+ }
+
+ // Copy separator token
+ NewTokens.push_back(*I);
+
+ // Reset values
+ ArgStartIterator = I + 1;
+ FoundSeparatorToken = false;
+ }
+ }
+ }
+
+ return !ParenHints.empty() && InitLists.empty();
+}
+
/// ReadFunctionLikeMacroArgs - After reading "MACRO" and knowing that the next
/// 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
@@ -415,6 +523,8 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
SmallVector<Token, 64> ArgTokens;
bool ContainsCodeCompletionTok = false;
+ SourceLocation TooManyArgsLoc;
+
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
if (ContainsCodeCompletionTok && (Tok.is(tok::eof) || Tok.is(tok::eod)))
@@ -458,7 +568,12 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
}
} else if (Tok.is(tok::l_paren)) {
++NumParens;
- } else if (Tok.is(tok::comma) && NumParens == 0) {
+ } else if (Tok.is(tok::comma) && NumParens == 0 &&
+ !(Tok.getFlags() & Token::IgnoredComma)) {
+ // In Microsoft-compatibility mode, single commas from nested macro
+ // expansions should not be considered as argument separators. We test
+ // for this with the IgnoredComma token flag above.
+
// Comma ends this argument if there are more fixed arguments expected.
// However, if this is a variadic macro, and this is part of the
// variadic part, then the comma is just an argument token.
@@ -499,22 +614,15 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// If this is not a variadic macro, and too many args were specified, emit
// an error.
- if (!isVariadic && NumFixedArgsLeft == 0) {
+ if (!isVariadic && NumFixedArgsLeft == 0 && TooManyArgsLoc.isInvalid()) {
if (ArgTokens.size() != ArgTokenStart)
- ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
-
- if (!ContainsCodeCompletionTok) {
- // Emit the diagnostic at the macro name in case there is a missing ).
- // Emitting it at the , could be far away from the macro name.
- Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
- Diag(MI->getDefinitionLoc(), diag::note_macro_here)
- << MacroName.getIdentifierInfo();
- return 0;
- }
+ TooManyArgsLoc = ArgTokens[ArgTokenStart].getLocation();
+ else
+ TooManyArgsLoc = ArgStartLoc;
}
- // Empty arguments are standard in C99 and C++0x, and are supported as an extension in
- // other modes.
+ // Empty arguments are standard in C99 and C++0x, and are supported as an
+ // extension in other modes.
if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99)
Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_empty_fnmacro_arg :
@@ -528,16 +636,66 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
EOFTok.setLength(0);
ArgTokens.push_back(EOFTok);
++NumActuals;
- if (!ContainsCodeCompletionTok || NumFixedArgsLeft != 0) {
- assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
+ if (!ContainsCodeCompletionTok && NumFixedArgsLeft != 0)
--NumFixedArgsLeft;
- }
}
// Okay, we either found the r_paren. Check to see if we parsed too few
// arguments.
unsigned MinArgsExpected = MI->getNumArgs();
+ // If this is not a variadic macro, and too many args were specified, emit
+ // an error.
+ if (!isVariadic && NumActuals > MinArgsExpected &&
+ !ContainsCodeCompletionTok) {
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(TooManyArgsLoc, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+
+ // Commas from braced initializer lists will be treated as argument
+ // separators inside macros. Attempt to correct for this with parentheses.
+ // TODO: See if this can be generalized to angle brackets for templates
+ // inside macro arguments.
+
+ SmallVector<Token, 4> FixedArgTokens;
+ unsigned FixedNumArgs = 0;
+ SmallVector<SourceRange, 4> ParenHints, InitLists;
+ if (!GenerateNewArgTokens(*this, ArgTokens, FixedArgTokens, FixedNumArgs,
+ ParenHints, InitLists)) {
+ if (!InitLists.empty()) {
+ DiagnosticBuilder DB =
+ Diag(MacroName,
+ diag::note_init_list_at_beginning_of_macro_argument);
+ for (SmallVector<SourceRange, 4>::iterator
+ Range = InitLists.begin(), RangeEnd = InitLists.end();
+ Range != RangeEnd; ++Range) {
+ if (DB.hasMaxRanges())
+ break;
+ DB << *Range;
+ }
+ }
+ return 0;
+ }
+ if (FixedNumArgs != MinArgsExpected)
+ return 0;
+
+ DiagnosticBuilder DB = Diag(MacroName, diag::note_suggest_parens_for_macro);
+ for (SmallVector<SourceRange, 4>::iterator
+ ParenLocation = ParenHints.begin(), ParenEnd = ParenHints.end();
+ ParenLocation != ParenEnd; ++ParenLocation) {
+ if (DB.hasMaxFixItHints())
+ break;
+ DB << FixItHint::CreateInsertion(ParenLocation->getBegin(), "(");
+ if (DB.hasMaxFixItHints())
+ break;
+ DB << FixItHint::CreateInsertion(ParenLocation->getEnd(), ")");
+ }
+ ArgTokens.swap(FixedArgTokens);
+ NumActuals = FixedNumArgs;
+ }
+
// See MacroArgs instance var for description of this.
bool isVarargsElided = false;
@@ -722,11 +880,13 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("attribute_unavailable_with_message", true)
.Case("attribute_unused_on_fields", true)
.Case("blocks", LangOpts.Blocks)
+ .Case("c_thread_safety_attributes", true)
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
.Case("memory_sanitizer", LangOpts.Sanitize.Memory)
.Case("thread_sanitizer", LangOpts.Sanitize.Thread)
+ .Case("dataflow_sanitizer", LangOpts.Sanitize.DataFlow)
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
@@ -737,6 +897,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
.Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword?
+ .Case("objc_protocol_qualifier_mangling", true)
.Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
.Case("ownership_holds", true)
.Case("ownership_returns", true)
@@ -785,7 +946,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
.Case("cxx_strong_enums", LangOpts.CPlusPlus11)
.Case("cxx_static_assert", LangOpts.CPlusPlus11)
- .Case("cxx_thread_local",
+ .Case("cxx_thread_local",
LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported())
.Case("cxx_trailing_return", LangOpts.CPlusPlus11)
.Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
@@ -793,15 +954,15 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_user_literals", LangOpts.CPlusPlus11)
.Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
// C++1y features
- .Case("cxx_binary_literals", LangOpts.CPlusPlus1y)
- //.Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y)
- //.Case("cxx_generalized_capture", LangOpts.CPlusPlus1y)
- //.Case("cxx_generic_lambda", LangOpts.CPlusPlus1y)
- //.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y)
- //.Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y)
- //.Case("cxx_runtime_array", LangOpts.CPlusPlus1y)
.Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y)
- //.Case("cxx_variable_templates", LangOpts.CPlusPlus1y)
+ .Case("cxx_binary_literals", LangOpts.CPlusPlus1y)
+ .Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y)
+ //.Case("cxx_generic_lambdas", LangOpts.CPlusPlus1y)
+ .Case("cxx_init_captures", LangOpts.CPlusPlus1y)
+ .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y)
+ .Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y)
+ //.Case("cxx_runtime_arrays", LangOpts.CPlusPlus1y)
+ .Case("cxx_variable_templates", LangOpts.CPlusPlus1y)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
.Case("has_nothrow_copy", LangOpts.CPlusPlus)
@@ -822,6 +983,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_standard_layout", LangOpts.CPlusPlus)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
+ .Case("is_sealed", LangOpts.MicrosoftExt)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
.Case("is_trivially_constructible", LangOpts.CPlusPlus)
@@ -862,6 +1024,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("c_atomic", true)
.Case("c_generic_selections", true)
.Case("c_static_assert", true)
+ .Case("c_thread_local", PP.getTargetInfo().isTLSSupported())
// C++11 features supported by other languages as extensions.
.Case("cxx_atomic", LangOpts.CPlusPlus)
.Case("cxx_deleted_functions", LangOpts.CPlusPlus)
@@ -875,6 +1038,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_rvalue_references", LangOpts.CPlusPlus)
// C++1y features supported by other languages as extensions.
.Case("cxx_binary_literals", true)
+ .Case("cxx_init_captures", LangOpts.CPlusPlus11)
+ .Case("cxx_variable_templates", true)
.Default(false);
}
@@ -992,7 +1157,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File =
- PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL);
+ PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir, NULL,
+ NULL, NULL);
// Get the result value. A result of true means the file exists.
return File != 0;
@@ -1212,9 +1378,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
if (Tok.is(tok::l_paren)) {
// Read the identifier
LexUnexpandedToken(Tok);
- if (Tok.is(tok::identifier) || Tok.is(tok::kw_const)) {
- FeatureII = Tok.getIdentifierInfo();
-
+ if ((FeatureII = Tok.getIdentifierInfo())) {
// Read the ')'.
LexUnexpandedToken(Tok);
if (Tok.is(tok::r_paren))
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index e8f43f7e50a7..e2629a3b2c49 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -43,9 +43,7 @@ PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D,
FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID);
}
-void PTHLexer::Lex(Token& Tok) {
-LexNextToken:
-
+bool PTHLexer::Lex(Token& Tok) {
//===--------------------------------------==//
// Read the raw token data.
//===--------------------------------------==//
@@ -90,8 +88,9 @@ LexNextToken:
Tok.setKind(II->getTokenID());
if (II->isHandleIdentifierCase())
- PP->HandleIdentifier(Tok);
- return;
+ return PP->HandleIdentifier(Tok);
+
+ return true;
}
//===--------------------------------------==//
@@ -101,16 +100,10 @@ LexNextToken:
// Save the end-of-file token.
EofToken = Tok;
- // Save 'PP' to 'PPCache' as LexEndOfFile can delete 'this'.
- Preprocessor *PPCache = PP;
-
assert(!ParsingPreprocessorDirective);
assert(!LexingRawMode);
-
- if (LexEndOfFile(Tok))
- return;
- return PPCache->Lex(Tok);
+ return LexEndOfFile(Tok);
}
if (TKind == tok::hash && Tok.isAtStartOfLine()) {
@@ -118,19 +111,17 @@ LexNextToken:
assert(!LexingRawMode);
PP->HandleDirective(Tok);
- if (PP->isCurrentLexer(this))
- goto LexNextToken;
-
- return PP->Lex(Tok);
+ return false;
}
if (TKind == tok::eod) {
assert(ParsingPreprocessorDirective);
ParsingPreprocessorDirective = false;
- return;
+ return true;
}
MIOpt.ReadToken();
+ return true;
}
bool PTHLexer::LexEndOfFile(Token &Result) {
@@ -619,18 +610,18 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
namespace {
class PTHStatData {
public:
- const bool hasStat;
- const ino_t ino;
- const dev_t dev;
- const mode_t mode;
- const time_t mtime;
- const off_t size;
-
- PTHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
- : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
-
- PTHStatData()
- : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
+ const bool HasData;
+ uint64_t Size;
+ time_t ModTime;
+ llvm::sys::fs::UniqueID UniqueID;
+ bool IsDirectory;
+
+ PTHStatData(uint64_t Size, time_t ModTime, llvm::sys::fs::UniqueID UniqueID,
+ bool IsDirectory)
+ : HasData(true), Size(Size), ModTime(ModTime), UniqueID(UniqueID),
+ IsDirectory(IsDirectory) {}
+
+ PTHStatData() : HasData(false) {}
};
class PTHStatLookupTrait : public PTHFileLookupCommonTrait {
@@ -653,12 +644,18 @@ public:
unsigned) {
if (k.first /* File or Directory */) {
- if (k.first == 0x1 /* File */) d += 4 * 2; // Skip the first 2 words.
- ino_t ino = (ino_t) ReadUnalignedLE32(d);
- dev_t dev = (dev_t) ReadUnalignedLE32(d);
- mode_t mode = (mode_t) ReadUnalignedLE16(d);
- time_t mtime = (time_t) ReadUnalignedLE64(d);
- return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
+ bool IsDirectory = true;
+ if (k.first == 0x1 /* File */) {
+ IsDirectory = false;
+ d += 4 * 2; // Skip the first 2 words.
+ }
+
+ uint64_t File = ReadUnalignedLE64(d);
+ uint64_t Device = ReadUnalignedLE64(d);
+ llvm::sys::fs::UniqueID UniqueID(File, Device);
+ time_t ModTime = ReadUnalignedLE64(d);
+ uint64_t Size = ReadUnalignedLE64(d);
+ return data_type(Size, ModTime, UniqueID, IsDirectory);
}
// Negative stat. Don't read anything.
@@ -677,25 +674,27 @@ public:
~PTHStatCache() {}
- LookupResult getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
+ LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
// Do the lookup for the file's data in the PTH file.
CacheTy::iterator I = Cache.find(Path);
// If we don't get a hit in the PTH file just forward to 'stat'.
if (I == Cache.end())
- return statChained(Path, StatBuf, isFile, FileDescriptor);
+ return statChained(Path, Data, isFile, FileDescriptor);
- const PTHStatData &Data = *I;
+ const PTHStatData &D = *I;
- if (!Data.hasStat)
+ if (!D.HasData)
return CacheMissing;
- StatBuf.st_ino = Data.ino;
- StatBuf.st_dev = Data.dev;
- StatBuf.st_mtime = Data.mtime;
- StatBuf.st_mode = Data.mode;
- StatBuf.st_size = Data.size;
+ Data.Size = D.Size;
+ Data.ModTime = D.ModTime;
+ Data.UniqueID = D.UniqueID;
+ Data.IsDirectory = D.IsDirectory;
+ Data.IsNamedPipe = false;
+ Data.InPCH = true;
+
return CacheExists;
}
};
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index b2ae4c9c443e..e4059eeb6fc0 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -20,11 +20,15 @@
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
using namespace clang;
+#include "llvm/Support/raw_ostream.h"
+
// Out-of-line destructor to provide a home for the class.
PragmaHandler::~PragmaHandler() {
}
@@ -101,7 +105,11 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
/// HandlePragmaDirective - The "\#pragma" directive has been parsed. Lex the
/// rest of the pragma, passing it to the registered pragma handlers.
-void Preprocessor::HandlePragmaDirective(unsigned Introducer) {
+void Preprocessor::HandlePragmaDirective(SourceLocation IntroducerLoc,
+ PragmaIntroducerKind Introducer) {
+ if (Callbacks)
+ Callbacks->PragmaDirective(IntroducerLoc, Introducer);
+
if (!PragmasEnabled)
return;
@@ -109,7 +117,7 @@ void Preprocessor::HandlePragmaDirective(unsigned Introducer) {
// Invoke the first level of pragma handlers which reads the namespace id.
Token Tok;
- PragmaHandlers->HandlePragma(*this, PragmaIntroducerKind(Introducer), Tok);
+ PragmaHandlers->HandlePragma(*this, Introducer, Tok);
// If the pragma handler didn't read the rest of the line, consume it now.
if ((CurTokenLexer && CurTokenLexer->isParsingPreprocessorDirective())
@@ -255,14 +263,14 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Remove escaped quotes and escapes.
unsigned ResultPos = 1;
- for (unsigned i = 1, e = StrVal.size() - 2; i != e; ++i) {
- if (StrVal[i] != '\\' ||
- (StrVal[i + 1] != '\\' && StrVal[i + 1] != '"')) {
- // \\ -> '\' and \" -> '"'.
- StrVal[ResultPos++] = StrVal[i];
- }
+ for (unsigned i = 1, e = StrVal.size() - 1; i != e; ++i) {
+ // Skip escapes. \\ -> '\' and \" -> '"'.
+ if (StrVal[i] == '\\' && i + 1 < e &&
+ (StrVal[i + 1] == '\\' || StrVal[i + 1] == '"'))
+ ++i;
+ StrVal[ResultPos++] = StrVal[i];
}
- StrVal.erase(StrVal.begin() + ResultPos, StrVal.end() - 2);
+ StrVal.erase(StrVal.begin() + ResultPos, StrVal.end() - 1);
}
// Remove the front quote, replacing it with a space, so that the pragma
@@ -287,7 +295,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
EnterSourceFileWithLexer(TL, 0);
// With everything set up, lex this as a #pragma directive.
- HandlePragmaDirective(PIK__Pragma);
+ HandlePragmaDirective(PragmaLoc, PIK__Pragma);
// Finally, return whatever came after the pragma directive.
return Lex(Tok);
@@ -336,7 +344,7 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
EnterTokenStream(TokArray, PragmaToks.size(), true, true);
// With everything set up, lex this as a #pragma directive.
- HandlePragmaDirective(PIK___pragma);
+ HandlePragmaDirective(PragmaLoc, PIK___pragma);
// Finally, return whatever came after the pragma directive.
return Lex(Tok);
@@ -466,8 +474,8 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL,
- NULL);
+ const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename,
+ isAngled, 0, CurDir, NULL, NULL, NULL);
if (File == 0) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
@@ -999,12 +1007,137 @@ public:
}
};
+// Returns -1 on failure.
+static int LexSimpleInt(Preprocessor &PP, Token &Tok) {
+ assert(Tok.is(tok::numeric_constant));
+ SmallString<8> IntegerBuffer;
+ bool NumberInvalid = false;
+ StringRef Spelling = PP.getSpelling(Tok, IntegerBuffer, &NumberInvalid);
+ if (NumberInvalid)
+ return -1;
+ NumericLiteralParser Literal(Spelling, Tok.getLocation(), PP);
+ if (Literal.hadError || !Literal.isIntegerLiteral() || Literal.hasUDSuffix())
+ return -1;
+ llvm::APInt APVal(32, 0);
+ if (Literal.GetIntegerValue(APVal))
+ return -1;
+ PP.Lex(Tok);
+ return int(APVal.getLimitedValue(INT_MAX));
+}
+
+/// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's
+/// diagnostics, so we don't really implement this pragma. We parse it and
+/// ignore it to avoid -Wunknown-pragma warnings.
+struct PragmaWarningHandler : public PragmaHandler {
+ PragmaWarningHandler() : PragmaHandler("warning") {}
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // Parse things like:
+ // warning(push, 1)
+ // warning(pop)
+ // warning(disable : 1 2 3 ; error : 4 5 6 ; suppress : 7 8 9)
+ SourceLocation DiagLoc = Tok.getLocation();
+ PPCallbacks *Callbacks = PP.getPPCallbacks();
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok, diag::warn_pragma_warning_expected) << "(";
+ return;
+ }
+
+ PP.Lex(Tok);
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II) {
+ PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid);
+ return;
+ }
+
+ if (II->isStr("push")) {
+ // #pragma warning( push[ ,n ] )
+ int Level = -1;
+ PP.Lex(Tok);
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+ if (Tok.is(tok::numeric_constant))
+ Level = LexSimpleInt(PP, Tok);
+ if (Level < 0 || Level > 4) {
+ PP.Diag(Tok, diag::warn_pragma_warning_push_level);
+ return;
+ }
+ }
+ if (Callbacks)
+ Callbacks->PragmaWarningPush(DiagLoc, Level);
+ } else if (II->isStr("pop")) {
+ // #pragma warning( pop )
+ PP.Lex(Tok);
+ if (Callbacks)
+ Callbacks->PragmaWarningPop(DiagLoc);
+ } else {
+ // #pragma warning( warning-specifier : warning-number-list
+ // [; warning-specifier : warning-number-list...] )
+ while (true) {
+ II = Tok.getIdentifierInfo();
+ if (!II) {
+ PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid);
+ return;
+ }
+
+ // Figure out which warning specifier this is.
+ StringRef Specifier = II->getName();
+ bool SpecifierValid =
+ llvm::StringSwitch<bool>(Specifier)
+ .Cases("1", "2", "3", "4", true)
+ .Cases("default", "disable", "error", "once", "suppress", true)
+ .Default(false);
+ if (!SpecifierValid) {
+ PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid);
+ return;
+ }
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::colon)) {
+ PP.Diag(Tok, diag::warn_pragma_warning_expected) << ":";
+ return;
+ }
+
+ // Collect the warning ids.
+ SmallVector<int, 4> Ids;
+ PP.Lex(Tok);
+ while (Tok.is(tok::numeric_constant)) {
+ int Id = LexSimpleInt(PP, Tok);
+ if (Id <= 0) {
+ PP.Diag(Tok, diag::warn_pragma_warning_expected_number);
+ return;
+ }
+ Ids.push_back(Id);
+ }
+ if (Callbacks)
+ Callbacks->PragmaWarning(DiagLoc, Specifier, Ids);
+
+ // Parse the next specifier if there is a semicolon.
+ if (Tok.isNot(tok::semi))
+ break;
+ PP.Lex(Tok);
+ }
+ }
+
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok, diag::warn_pragma_warning_expected) << ")";
+ return;
+ }
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma warning";
+ }
+};
+
/// PragmaIncludeAliasHandler - "\#pragma include_alias("...")".
struct PragmaIncludeAliasHandler : public PragmaHandler {
PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &IncludeAliasTok) {
- PP.HandlePragmaIncludeAlias(IncludeAliasTok);
+ PP.HandlePragmaIncludeAlias(IncludeAliasTok);
}
};
@@ -1204,28 +1337,28 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
}
};
- /// \brief Handle "\#pragma region [...]"
- ///
- /// The syntax is
- /// \code
- /// #pragma region [optional name]
- /// #pragma endregion [optional comment]
- /// \endcode
- ///
- /// \note This is
- /// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a>
- /// pragma, just skipped by compiler.
- struct PragmaRegionHandler : public PragmaHandler {
- PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { }
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &NameTok) {
- // #pragma region: endregion matches can be verified
- // __pragma(region): no sense, but ignored by msvc
- // _Pragma is not valid for MSVC, but there isn't any point
- // to handle a _Pragma differently.
- }
- };
+/// \brief Handle "\#pragma region [...]"
+///
+/// The syntax is
+/// \code
+/// #pragma region [optional name]
+/// #pragma endregion [optional comment]
+/// \endcode
+///
+/// \note This is
+/// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a>
+/// pragma, just skipped by compiler.
+struct PragmaRegionHandler : public PragmaHandler {
+ PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { }
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) {
+ // #pragma region: endregion matches can be verified
+ // __pragma(region): no sense, but ignored by msvc
+ // _Pragma is not valid for MSVC, but there isn't any point
+ // to handle a _Pragma differently.
+ }
+};
} // end anonymous namespace
@@ -1262,6 +1395,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
// MS extensions.
if (LangOpts.MicrosoftExt) {
+ AddPragmaHandler(new PragmaWarningHandler());
AddPragmaHandler(new PragmaIncludeAliasHandler());
AddPragmaHandler(new PragmaRegionHandler("region"));
AddPragmaHandler(new PragmaRegionHandler("endregion"));
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 426b92256264..090aeedb7150 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -398,7 +398,8 @@ void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
}
void PreprocessingRecord::Defined(const Token &MacroNameTok,
- const MacroDirective *MD) {
+ const MacroDirective *MD,
+ SourceRange Range) {
// This is not actually a macro expansion but record it as a macro reference.
if (MD)
addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 66f23f101886..b500efee4e61 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -65,6 +65,7 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
TheModuleLoader(TheModuleLoader), ExternalSource(0),
Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing),
CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0),
+ LastTokenWasAt(false), ModuleImportExpectsIdentifier(false),
CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0),
MacroArgCache(0), Record(0), MIChainHead(0), MICache(0),
@@ -614,7 +615,7 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
/// IdentifierInfo's 'isHandleIdentifierCase' bit. If this method changes, the
/// IdentifierInfo methods that compute these properties will need to change to
/// match.
-void Preprocessor::HandleIdentifier(Token &Identifier) {
+bool Preprocessor::HandleIdentifier(Token &Identifier) {
assert(Identifier.getIdentifierInfo() &&
"Can't handle identifiers without identifier info!");
@@ -648,8 +649,10 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
MacroInfo *MI = MD->getMacroInfo();
if (!DisableMacroExpansion) {
if (!Identifier.isExpandDisabled() && MI->isEnabled()) {
- if (!HandleMacroExpandedIdentifier(Identifier, MD))
- return;
+ // C99 6.10.3p10: If the preprocessing token immediately after the
+ // macro name isn't a '(', this macro should not be expanded.
+ if (!MI->isFunctionLike() || isNextPPTokenLParen())
+ return HandleMacroExpandedIdentifier(Identifier, MD);
} else {
// C99 6.10.3.4p2 says that a disabled macro may never again be
// expanded, even if it's in a context where it could be expanded in the
@@ -685,21 +688,52 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
- // If this is the 'import' contextual keyword, note
+ // If this is the 'import' contextual keyword following an '@', note
// that the next token indicates a module name.
//
// Note that we do not treat 'import' as a contextual
// keyword when we're in a caching lexer, because caching lexers only get
// used in contexts where import declarations are disallowed.
- if (II.isModulesImport() && !InMacroArgs && !DisableMacroExpansion &&
- getLangOpts().Modules && CurLexerKind != CLK_CachingLexer) {
+ if (LastTokenWasAt && II.isModulesImport() && !InMacroArgs &&
+ !DisableMacroExpansion && getLangOpts().Modules &&
+ CurLexerKind != CLK_CachingLexer) {
ModuleImportLoc = Identifier.getLocation();
ModuleImportPath.clear();
ModuleImportExpectsIdentifier = true;
CurLexerKind = CLK_LexAfterModuleImport;
}
+ return true;
+}
+
+void Preprocessor::Lex(Token &Result) {
+ // We loop here until a lex function retuns a token; this avoids recursion.
+ bool ReturnedToken;
+ do {
+ switch (CurLexerKind) {
+ case CLK_Lexer:
+ ReturnedToken = CurLexer->Lex(Result);
+ break;
+ case CLK_PTHLexer:
+ ReturnedToken = CurPTHLexer->Lex(Result);
+ break;
+ case CLK_TokenLexer:
+ ReturnedToken = CurTokenLexer->Lex(Result);
+ break;
+ case CLK_CachingLexer:
+ CachingLex(Result);
+ ReturnedToken = true;
+ break;
+ case CLK_LexAfterModuleImport:
+ LexAfterModuleImport(Result);
+ ReturnedToken = true;
+ break;
+ }
+ } while (!ReturnedToken);
+
+ LastTokenWasAt = Result.is(tok::at);
}
+
/// \brief Lex a token following the 'import' contextual keyword.
///
void Preprocessor::LexAfterModuleImport(Token &Result) {
@@ -734,7 +768,7 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
// If we have a non-empty module path, load the named module.
- if (!ModuleImportPath.empty()) {
+ if (!ModuleImportPath.empty() && getLangOpts().Modules) {
Module *Imported = TheModuleLoader.loadModule(ModuleImportLoc,
ModuleImportPath,
Module::MacrosVisible,
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index 5a59849720f6..33ccbc0cfc94 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -38,7 +38,10 @@ void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {
ParsingFilename = true;
// Lex the filename.
- IndirectLex(FilenameTok);
+ if (LexingRawMode)
+ IndirectLex(FilenameTok);
+ else
+ PP->Lex(FilenameTok);
// We should have obtained the filename now.
ParsingFilename = false;
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 07753c7d7c36..0213afcee921 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -121,7 +121,7 @@ void TokenLexer::destroy() {
/// Remove comma ahead of __VA_ARGS__, if present, according to compiler dialect
/// settings. Returns true if the comma is removed.
-static bool MaybeRemoveCommaBeforeVaArgs(SmallVector<Token, 128> &ResultToks,
+static bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
bool &NextTokGetsSpace,
bool HasPasteOperator,
MacroInfo *Macro, unsigned MacroArgNo,
@@ -244,9 +244,11 @@ void TokenLexer::ExpandFunctionArguments() {
// Otherwise, this is a use of the argument. Find out if there is a paste
// (##) operator before or after the argument.
- bool PasteBefore =
+ 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);
// In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
// are no trailing commas if __VA_ARGS__ is empty.
@@ -276,6 +278,14 @@ void TokenLexer::ExpandFunctionArguments() {
unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
+ // In Microsoft-compatibility mode, we follow MSVC's preprocessing
+ // behavior by not considering single commas from nested macro
+ // expansions as argument separators. Set a flag on the token so we can
+ // test for this later when the macro expansion is processed.
+ if (PP.getLangOpts().MicrosoftMode && NumToks == 1 &&
+ ResultToks.back().is(tok::comma))
+ ResultToks.back().setFlag(Token::IgnoredComma);
+
// If the '##' came from expanding an argument, turn it into 'unknown'
// to avoid pasting.
for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) {
@@ -314,13 +324,12 @@ void TokenLexer::ExpandFunctionArguments() {
// 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 (PasteBefore && ResultToks.size() >= 2 &&
+ if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
ResultToks[ResultToks.size()-2].is(tok::comma) &&
(unsigned)ArgNo == Macro->getNumArgs()-1 &&
Macro->isVariadic()) {
// Remove the paste operator, report use of the extension.
- PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
- ResultToks.pop_back();
+ PP.Diag(ResultToks.pop_back_val().getLocation(), diag::ext_paste_comma);
}
ResultToks.append(ArgToks, ArgToks+NumToks);
@@ -350,7 +359,7 @@ void TokenLexer::ExpandFunctionArguments() {
// case, we do not want the extra whitespace to be added. For example,
// we want ". ## foo" -> ".foo" not ". foo".
if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
- !PasteBefore)
+ !NonEmptyPasteBefore)
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
@@ -371,10 +380,13 @@ void TokenLexer::ExpandFunctionArguments() {
}
// If this is on the RHS of a paste operator, we've already copied the
- // paste operator to the ResultToks list. Remove it.
- assert(PasteBefore && ResultToks.back().is(tok::hashhash));
- NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
- ResultToks.pop_back();
+ // paste operator to the ResultToks list, unless the LHS was empty too.
+ // Remove it.
+ assert(PasteBefore);
+ if (NonEmptyPasteBefore) {
+ assert(ResultToks.back().is(tok::hashhash));
+ NextTokGetsSpace |= ResultToks.pop_back_val().hasLeadingSpace();
+ }
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
// and if the macro had at least one real argument, and if the token before
@@ -404,22 +416,19 @@ void TokenLexer::ExpandFunctionArguments() {
/// Lex - Lex and return a token from this macro stream.
///
-void TokenLexer::Lex(Token &Tok) {
+bool TokenLexer::Lex(Token &Tok) {
// Lexing off the end of the macro, pop this macro off the expansion stack.
if (isAtEnd()) {
// If this is a macro (not a token stream), mark the macro enabled now
// that it is no longer being expanded.
if (Macro) Macro->EnableMacro();
- // Pop this context off the preprocessors lexer stack and get the next
- // token. This will delete "this" so remember the PP instance var.
- Preprocessor &PPCache = PP;
- if (PP.HandleEndOfTokenLexer(Tok))
- return;
-
- // HandleEndOfTokenLexer may not return a token. If it doesn't, lex
- // whatever is next.
- return PPCache.Lex(Tok);
+ Tok.startToken();
+ Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
+ Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ if (CurToken == 0)
+ Tok.setFlag(Token::LeadingEmptyMacro);
+ return PP.HandleEndOfTokenLexer(Tok);
}
SourceManager &SM = PP.getSourceManager();
@@ -439,7 +448,7 @@ void TokenLexer::Lex(Token &Tok) {
// When handling the microsoft /##/ extension, the final token is
// returned by PasteTokens, not the pasted token.
if (PasteTokens(Tok))
- return;
+ return true;
TokenIsFromPaste = true;
}
@@ -470,6 +479,8 @@ void TokenLexer::Lex(Token &Tok) {
if (isFirstToken) {
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ AtStartOfLine = false;
+ HasLeadingSpace = false;
}
// Handle recursive expansion!
@@ -487,10 +498,11 @@ void TokenLexer::Lex(Token &Tok) {
}
if (!DisableMacroExpansion && II->isHandleIdentifierCase())
- PP.HandleIdentifier(Tok);
+ return PP.HandleIdentifier(Tok);
}
// Otherwise, return a normal token.
+ return true;
}
/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
@@ -812,3 +824,8 @@ void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
updateConsecutiveMacroArgTokens(SM, InstLoc, begin_tokens, end_tokens);
}
}
+
+void TokenLexer::PropagateLineStartLeadingSpaceInfo(Token &Result) {
+ AtStartOfLine = Result.isAtStartOfLine();
+ HasLeadingSpace = Result.hasLeadingSpace();
+}
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
index 37ff8af10f68..01ae7e839dfd 100644
--- a/lib/Lex/UnicodeCharSets.h
+++ b/lib/Lex/UnicodeCharSets.h
@@ -9,98 +9,10 @@
#ifndef CLANG_LEX_UNICODECHARSETS_H
#define CLANG_LEX_UNICODECHARSETS_H
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Mutex.h"
-#include "llvm/Support/MutexGuard.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace {
- struct UnicodeCharRange {
- uint32_t Lower;
- uint32_t Upper;
- };
- typedef llvm::ArrayRef<UnicodeCharRange> UnicodeCharSet;
-
- typedef llvm::SmallPtrSet<const UnicodeCharRange *, 16> ValidatedCharSetsTy;
-}
-
-static inline ValidatedCharSetsTy &getValidatedCharSets() {
- static ValidatedCharSetsTy Validated;
- return Validated;
-}
-
-/// Returns true if each of the ranges in \p CharSet is a proper closed range
-/// [min, max], and if the ranges themselves are ordered and non-overlapping.
-static inline bool isValidCharSet(UnicodeCharSet CharSet) {
-#ifndef NDEBUG
- static llvm::sys::Mutex ValidationMutex;
-
- // Check the validation cache.
- {
- llvm::MutexGuard Guard(ValidationMutex);
- if (getValidatedCharSets().count(CharSet.data()))
- return true;
- }
-
- // Walk through the ranges.
- uint32_t Prev = 0;
- for (UnicodeCharSet::iterator I = CharSet.begin(), E = CharSet.end();
- I != E; ++I) {
- if (Prev >= I->Lower) {
- DEBUG(llvm::dbgs() << "Upper bound 0x");
- DEBUG(llvm::dbgs().write_hex(Prev));
- DEBUG(llvm::dbgs() << " should be less than succeeding lower bound 0x");
- DEBUG(llvm::dbgs().write_hex(I->Lower) << "\n");
- return false;
- }
- if (I->Upper < I->Lower) {
- DEBUG(llvm::dbgs() << "Upper bound 0x");
- DEBUG(llvm::dbgs().write_hex(I->Lower));
- DEBUG(llvm::dbgs() << " should not be less than lower bound 0x");
- DEBUG(llvm::dbgs().write_hex(I->Upper) << "\n");
- return false;
- }
- Prev = I->Upper;
- }
-
- // Update the validation cache.
- {
- llvm::MutexGuard Guard(ValidationMutex);
- getValidatedCharSets().insert(CharSet.data());
- }
-#endif
- return true;
-}
-
-/// Returns true if the Unicode code point \p C is within the set of
-/// characters specified by \p CharSet.
-LLVM_READONLY static inline bool isCharInSet(uint32_t C,
- UnicodeCharSet CharSet) {
- assert(isValidCharSet(CharSet));
-
- size_t LowPoint = 0;
- size_t HighPoint = CharSet.size();
-
- // Binary search the set of char ranges.
- while (HighPoint != LowPoint) {
- size_t MidPoint = (HighPoint + LowPoint) / 2;
- if (C < CharSet[MidPoint].Lower)
- HighPoint = MidPoint;
- else if (C > CharSet[MidPoint].Upper)
- LowPoint = MidPoint + 1;
- else
- return true;
- }
-
- return false;
-}
-
+#include "llvm/Support/UnicodeCharRanges.h"
// C11 D.1, C++11 [charname.allowed]
-static const UnicodeCharRange C11AllowedIDChars[] = {
+static const llvm::sys::UnicodeCharRange C11AllowedIDCharRanges[] = {
// 1
{ 0x00A8, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AD, 0x00AD },
{ 0x00AF, 0x00AF }, { 0x00B2, 0x00B5 }, { 0x00B7, 0x00BA },
@@ -132,7 +44,7 @@ static const UnicodeCharRange C11AllowedIDChars[] = {
// C++03 [extendid]
// Note that this is not the same as C++98, but we don't distinguish C++98
// and C++03 in Clang.
-static const UnicodeCharRange CXX03AllowedIDChars[] = {
+static const llvm::sys::UnicodeCharRange CXX03AllowedIDCharRanges[] = {
// Latin
{ 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 },
{ 0x01FA, 0x0217 }, { 0x0250, 0x02A8 },
@@ -251,7 +163,7 @@ static const UnicodeCharRange CXX03AllowedIDChars[] = {
};
// C99 Annex D
-static const UnicodeCharRange C99AllowedIDChars[] = {
+static const llvm::sys::UnicodeCharRange C99AllowedIDCharRanges[] = {
// Latin (1)
{ 0x00AA, 0x00AA },
@@ -470,7 +382,7 @@ static const UnicodeCharRange C99AllowedIDChars[] = {
};
// C11 D.2, C++11 [charname.disallowed]
-static const UnicodeCharRange C11DisallowedInitialIDChars[] = {
+static const llvm::sys::UnicodeCharRange C11DisallowedInitialIDCharRanges[] = {
{ 0x0300, 0x036F }, { 0x1DC0, 0x1DFF }, { 0x20D0, 0x20FF },
{ 0xFE20, 0xFE2F }
};
@@ -478,7 +390,7 @@ static const UnicodeCharRange C11DisallowedInitialIDChars[] = {
// C99 6.4.2.1p3: The initial character [of an identifier] shall not be a
// universal character name designating a digit.
// C99 Annex D defines these characters as "Digits".
-static const UnicodeCharRange C99DisallowedInitialIDChars[] = {
+static const llvm::sys::UnicodeCharRange C99DisallowedInitialIDCharRanges[] = {
{ 0x0660, 0x0669 }, { 0x06F0, 0x06F9 }, { 0x0966, 0x096F },
{ 0x09E6, 0x09EF }, { 0x0A66, 0x0A6F }, { 0x0AE6, 0x0AEF },
{ 0x0B66, 0x0B6F }, { 0x0BE7, 0x0BEF }, { 0x0C66, 0x0C6F },
@@ -487,7 +399,7 @@ static const UnicodeCharRange C99DisallowedInitialIDChars[] = {
};
// Unicode v6.2, chapter 6.2, table 6-2.
-static const UnicodeCharRange UnicodeWhitespaceChars[] = {
+static const llvm::sys::UnicodeCharRange UnicodeWhitespaceCharRanges[] = {
{ 0x0085, 0x0085 }, { 0x00A0, 0x00A0 }, { 0x1680, 0x1680 },
{ 0x180E, 0x180E }, { 0x2000, 0x200A }, { 0x2028, 0x2029 },
{ 0x202F, 0x202F }, { 0x205F, 0x205F }, { 0x3000, 0x3000 }
diff --git a/lib/Makefile b/lib/Makefile
index 2e32dfec35a4..66632688d933 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,8 +10,8 @@ CLANG_LEVEL := ..
# ARCMigrate and Rewrite are always needed because of libclang.
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Frontend \
- FrontendTool Tooling Driver Format Edit ARCMigrate Rewrite \
- Serialization
+ FrontendTool Tooling Driver Format Edit Rewrite Serialization \
+ Index
include $(CLANG_LEVEL)/../../Makefile.config
@@ -23,4 +23,8 @@ ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
PARALLEL_DIRS += StaticAnalyzer
endif
+ifeq ($(ENABLE_CLANG_ARCMT),1)
+PARALLEL_DIRS += ARCMigrate
+endif
+
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 01c0694d0359..08bf4e196155 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -17,10 +17,11 @@ add_clang_library(clangParse
add_dependencies(clangParse
ClangAttrClasses
- ClangAttrExprArgs
+ ClangAttrIdentifierArg
ClangAttrLateParsed
ClangAttrList
ClangAttrParsedAttrList
+ ClangAttrTypeArg
ClangCommentNodes
ClangDeclNodes
ClangDiagnosticCommon
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 7cd8a21ac451..5678ece0c822 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -145,7 +145,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
}
// Process any TopLevelDecls generated by #pragma weak.
- for (SmallVector<Decl*,2>::iterator
+ for (SmallVectorImpl<Decl *>::iterator
I = S.WeakTopLevelDecls().begin(),
E = S.WeakTopLevelDecls().end(); I != E; ++I)
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 5fc4189742cf..779230516532 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -55,11 +55,10 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateParams, 0,
VS, ICIS_NoInit);
if (FnD) {
- Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
- false, true);
+ Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs);
bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType();
if (Init.isUsable())
- Actions.AddInitializerToDecl(FnD, Init.get(), false,
+ Actions.AddInitializerToDecl(FnD, Init.get(), false,
TypeSpecContainsAuto);
else
Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto);
@@ -110,28 +109,27 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
return FnD;
}
-
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
- if (getLangOpts().DelayedTemplateParsing &&
- DefinitionKind == FDK_Definition &&
+ if (getLangOpts().DelayedTemplateParsing &&
+ DefinitionKind == FDK_Definition &&
+ !D.getDeclSpec().isConstexprSpecified() &&
+ !(FnD && getFunctionDecl(FnD) &&
+ getFunctionDecl(FnD)->getResultType()->getContainedAutoType()) &&
((Actions.CurContext->isDependentContext() ||
- TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) &&
- !Actions.IsInsideALocalClassWithinATemplateFunction())) {
+ (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) &&
+ !Actions.IsInsideALocalClassWithinATemplateFunction())) {
- if (FnD) {
- LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD);
+ CachedTokens Toks;
+ LexTemplateFunctionForLateParsing(Toks);
+ if (FnD) {
FunctionDecl *FD = getFunctionDecl(FnD);
Actions.CheckForFunctionRedefinition(FD);
-
- LateParsedTemplateMap[FD] = LPT;
- Actions.MarkAsLateParsedTemplate(FD);
- LexTemplateFunctionForLateParsing(LPT->Toks);
- } else {
- CachedTokens Toks;
- LexTemplateFunctionForLateParsing(Toks);
+ Actions.MarkAsLateParsedTemplate(FD, FnD, Toks);
}
return FnD;
@@ -151,9 +149,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
// We didn't find the left-brace we expected after the
// constructor initializer; we already printed an error, and it's likely
// impossible to recover, so don't try to parse this method later.
- // If we stopped at a semicolon, consume it to avoid an extra warning.
- if (Tok.is(tok::semi))
- ConsumeToken();
+ // Skip over the rest of the decl and back to somewhere that looks
+ // reasonable.
+ SkipMalformedDecl();
delete getCurrentClass().LateParsedDeclarations.back();
getCurrentClass().LateParsedDeclarations.pop_back();
return FnD;
@@ -170,27 +168,28 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
}
}
-
- if (!FnD) {
+ 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 = getFunctionDecl(FnD);
+ Actions.CheckForFunctionRedefinition(FD);
+ FD->setLateTemplateParsed(true);
+ }
+ } else {
// If semantic analysis could not build a function declaration,
// just throw away the late-parsed declaration.
delete getCurrentClass().LateParsedDeclarations.back();
getCurrentClass().LateParsedDeclarations.pop_back();
}
- // 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()) {
- getFunctionDecl(FnD)->setLateTemplateParsed(true);
- }
-
return FnD;
}
@@ -222,8 +221,7 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true);
} else {
// Consume everything up to (but excluding) the comma or semicolon.
- ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true,
- /*ConsumeFinalToken=*/false);
+ ConsumeAndStoreInitializer(Toks, CIK_DefaultInitializer);
}
// Store an artificial EOF token to ensure that we don't run off the end of
@@ -352,8 +350,15 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
else {
if (Tok.is(tok::cxx_defaultarg_end))
ConsumeToken();
- else
- Diag(Tok.getLocation(), diag::err_default_arg_unparsed);
+ else {
+ // The last two tokens are the terminator and the saved value of
+ // Tok; the last token in the default argument is the one before
+ // those.
+ assert(Toks->size() >= 3 && "expected a token in default arg");
+ Diag(Tok.getLocation(), diag::err_default_arg_unparsed)
+ << SourceRange(Tok.getLocation(),
+ (*Toks)[Toks->size() - 3].getLocation());
+ }
Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
DefArgResult.take());
}
@@ -653,83 +658,444 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
/// the opening brace of the function body. The opening brace will be consumed
/// if and only if there was no error.
///
-/// \return True on error.
+/// \return True on error.
bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
if (Tok.is(tok::kw_try)) {
Toks.push_back(Tok);
ConsumeToken();
}
- bool ReadInitializer = false;
- if (Tok.is(tok::colon)) {
- // Initializers can contain braces too.
+
+ if (Tok.isNot(tok::colon)) {
+ // Easy case, just a function body.
+
+ // Grab any remaining garbage to be diagnosed later. We stop when we reach a
+ // brace: an opening one is the function body, while a closing one probably
+ // means we've reached the end of the class.
+ ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false);
+ if (Tok.isNot(tok::l_brace))
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+
Toks.push_back(Tok);
- ConsumeToken();
+ ConsumeBrace();
+ return false;
+ }
- while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) {
- if (Tok.is(tok::eof) || Tok.is(tok::semi))
- return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ Toks.push_back(Tok);
+ ConsumeToken();
- // Grab the identifier.
- if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks,
- /*StopAtSemi=*/true,
- /*ConsumeFinalToken=*/false))
- return Diag(Tok.getLocation(), diag::err_expected_lparen);
+ // We can't reliably skip over a mem-initializer-id, because it could be
+ // a template-id involving not-yet-declared names. Given:
+ //
+ // S ( ) : a < b < c > ( e )
+ //
+ // 'e' might be an initializer or part of a template argument, depending
+ // on whether 'b' is a template.
+
+ // Track whether we might be inside a template argument. We can give
+ // significantly better diagnostics if we know that we're not.
+ bool MightBeTemplateArgument = false;
- tok::TokenKind kind = Tok.getKind();
+ while (true) {
+ // Skip over the mem-initializer-id, if possible.
+ if (Tok.is(tok::kw_decltype)) {
Toks.push_back(Tok);
- bool IsLParen = (kind == tok::l_paren);
- SourceLocation LOpen = Tok.getLocation();
+ SourceLocation OpenLoc = ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return Diag(Tok.getLocation(), diag::err_expected_lparen_after)
+ << "decltype";
+ Toks.push_back(Tok);
+ ConsumeParen();
+ if (!ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/true)) {
+ Diag(Tok.getLocation(), diag::err_expected_rparen);
+ Diag(OpenLoc, diag::note_matching) << "(";
+ return true;
+ }
+ }
+ do {
+ // Walk over a component of a nested-name-specifier.
+ if (Tok.is(tok::coloncolon)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
- if (IsLParen) {
- ConsumeParen();
+ if (Tok.is(tok::kw_template)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
+ }
+
+ if (Tok.is(tok::identifier) || Tok.is(tok::kw_template)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ } else if (Tok.is(tok::code_completion)) {
+ Toks.push_back(Tok);
+ ConsumeCodeCompletionToken();
+ // Consume the rest of the initializers permissively.
+ // FIXME: We should be able to perform code-completion here even if
+ // there isn't a subsequent '{' token.
+ MightBeTemplateArgument = true;
+ break;
} else {
- assert(kind == tok::l_brace && "Must be left paren or brace here.");
- ConsumeBrace();
- // In C++03, this has to be the start of the function body, which
- // means the initializer is malformed; we'll diagnose it later.
- if (!getLangOpts().CPlusPlus11)
- return false;
+ break;
}
+ } while (Tok.is(tok::coloncolon));
+
+ if (Tok.is(tok::less))
+ MightBeTemplateArgument = true;
+
+ if (MightBeTemplateArgument) {
+ // We may be inside a template argument list. Grab up to the start of the
+ // next parenthesized initializer or braced-init-list. This *might* be the
+ // initializer, or it might be a subexpression in the template argument
+ // list.
+ // FIXME: Count angle brackets, and clear MightBeTemplateArgument
+ // if all angles are closed.
+ if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false)) {
+ // We're not just missing the initializer, we're also missing the
+ // function body!
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ }
+ } else if (Tok.isNot(tok::l_paren) && Tok.isNot(tok::l_brace)) {
+ // We found something weird in a mem-initializer-id.
+ return Diag(Tok.getLocation(), getLangOpts().CPlusPlus11
+ ? diag::err_expected_lparen_or_lbrace
+ : diag::err_expected_lparen);
+ }
+
+ tok::TokenKind kind = Tok.getKind();
+ Toks.push_back(Tok);
+ bool IsLParen = (kind == tok::l_paren);
+ SourceLocation OpenLoc = Tok.getLocation();
+
+ if (IsLParen) {
+ ConsumeParen();
+ } else {
+ assert(kind == tok::l_brace && "Must be left paren or brace here.");
+ ConsumeBrace();
+ // In C++03, this has to be the start of the function body, which
+ // means the initializer is malformed; we'll diagnose it later.
+ if (!getLangOpts().CPlusPlus11)
+ return false;
+ }
- // Grab the initializer
- if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace,
- Toks, /*StopAtSemi=*/true)) {
- Diag(Tok, IsLParen ? diag::err_expected_rparen :
- diag::err_expected_rbrace);
- Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{");
+ // Grab the initializer (or the subexpression of the template argument).
+ // FIXME: If we support lambdas here, we'll need to set StopAtSemi to false
+ // if we might be inside the braces of a lambda-expression.
+ if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace,
+ Toks, /*StopAtSemi=*/true)) {
+ Diag(Tok, IsLParen ? diag::err_expected_rparen :
+ diag::err_expected_rbrace);
+ Diag(OpenLoc, diag::note_matching) << (IsLParen ? "(" : "{");
+ return true;
+ }
+
+ // Grab pack ellipsis, if present.
+ if (Tok.is(tok::ellipsis)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
+
+ // If we know we just consumed a mem-initializer, we must have ',' or '{'
+ // next.
+ if (Tok.is(tok::comma)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ } else if (Tok.is(tok::l_brace)) {
+ // This is the function body if the ')' or '}' is immediately followed by
+ // a '{'. That cannot happen within a template argument, apart from the
+ // case where a template argument contains a compound literal:
+ //
+ // S ( ) : a < b < c > ( d ) { }
+ // // End of declaration, or still inside the template argument?
+ //
+ // ... and the case where the template argument contains a lambda:
+ //
+ // S ( ) : a < 0 && b < c > ( d ) + [ ] ( ) { return 0; }
+ // ( ) > ( ) { }
+ //
+ // FIXME: Disambiguate these cases. Note that the latter case is probably
+ // going to be made ill-formed by core issue 1607.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ return false;
+ } else if (!MightBeTemplateArgument) {
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ }
+ }
+}
+
+/// \brief Consume and store tokens from the '?' to the ':' in a conditional
+/// expression.
+bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) {
+ // Consume '?'.
+ assert(Tok.is(tok::question));
+ Toks.push_back(Tok);
+ ConsumeToken();
+
+ while (Tok.isNot(tok::colon)) {
+ if (!ConsumeAndStoreUntil(tok::question, tok::colon, Toks, /*StopAtSemi*/true,
+ /*ConsumeFinalToken*/false))
+ return false;
+
+ // If we found a nested conditional, consume it.
+ if (Tok.is(tok::question) && !ConsumeAndStoreConditional(Toks))
+ return false;
+ }
+
+ // Consume ':'.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ return true;
+}
+
+/// \brief A tentative parsing action that can also revert token annotations.
+class Parser::UnannotatedTentativeParsingAction : public TentativeParsingAction {
+public:
+ explicit UnannotatedTentativeParsingAction(Parser &Self,
+ tok::TokenKind EndKind)
+ : TentativeParsingAction(Self), Self(Self), EndKind(EndKind) {
+ // Stash away the old token stream, so we can restore it once the
+ // tentative parse is complete.
+ TentativeParsingAction Inner(Self);
+ Self.ConsumeAndStoreUntil(EndKind, Toks, true, /*ConsumeFinalToken*/false);
+ Inner.Revert();
+ }
+
+ void RevertAnnotations() {
+ Revert();
+
+ // Put back the original tokens.
+ Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch);
+ if (Toks.size()) {
+ Token *Buffer = new Token[Toks.size()];
+ std::copy(Toks.begin() + 1, Toks.end(), Buffer);
+ Buffer[Toks.size() - 1] = Self.Tok;
+ Self.PP.EnterTokenStream(Buffer, Toks.size(), true, /*Owned*/true);
+
+ Self.Tok = Toks.front();
+ }
+ }
+
+private:
+ Parser &Self;
+ CachedTokens Toks;
+ tok::TokenKind EndKind;
+};
+
+/// ConsumeAndStoreInitializer - Consume and store the token at the passed token
+/// container until the end of the current initializer expression (either a
+/// default argument or an in-class initializer for a non-static data member).
+/// The final token is not consumed.
+bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
+ CachedInitKind CIK) {
+ // We always want this function to consume at least one token if not at EOF.
+ bool IsFirstTokenConsumed = true;
+
+ // Number of possible unclosed <s we've seen so far. These might be templates,
+ // and might not, but if there were none of them (or we know for sure that
+ // we're within a template), we can avoid a tentative parse.
+ unsigned AngleCount = 0;
+ unsigned KnownTemplateCount = 0;
+
+ while (1) {
+ switch (Tok.getKind()) {
+ case tok::comma:
+ // If we might be in a template, perform a tentative parse to check.
+ if (!AngleCount)
+ // Not a template argument: this is the end of the initializer.
return true;
+ if (KnownTemplateCount)
+ goto consume_token;
+
+ // We hit a comma inside angle brackets. This is the hard case. The
+ // rule we follow is:
+ // * For a default argument, if the tokens after the comma form a
+ // syntactically-valid parameter-declaration-clause, in which each
+ // parameter has an initializer, then this comma ends the default
+ // argument.
+ // * For a default initializer, if the tokens after the comma form a
+ // syntactically-valid init-declarator-list, then this comma ends
+ // the default initializer.
+ {
+ UnannotatedTentativeParsingAction PA(*this,
+ CIK == CIK_DefaultInitializer
+ ? tok::semi : tok::r_paren);
+ Sema::TentativeAnalysisScope Scope(Actions);
+
+ TPResult Result = TPResult::Error();
+ ConsumeToken();
+ switch (CIK) {
+ case CIK_DefaultInitializer:
+ Result = TryParseInitDeclaratorList();
+ // If we parsed a complete, ambiguous init-declarator-list, this
+ // is only syntactically-valid if it's followed by a semicolon.
+ if (Result == TPResult::Ambiguous() && Tok.isNot(tok::semi))
+ Result = TPResult::False();
+ break;
+
+ case CIK_DefaultArgument:
+ bool InvalidAsDeclaration = false;
+ Result = TryParseParameterDeclarationClause(
+ &InvalidAsDeclaration, /*VersusTemplateArgument*/true);
+ // If this is an expression or a declaration with a missing
+ // 'typename', assume it's not a declaration.
+ if (Result == TPResult::Ambiguous() && InvalidAsDeclaration)
+ Result = TPResult::False();
+ break;
+ }
+
+ // If what follows could be a declaration, it is a declaration.
+ if (Result != TPResult::False() && Result != TPResult::Error()) {
+ PA.Revert();
+ return true;
+ }
+
+ // In the uncommon case that we decide the following tokens are part
+ // of a template argument, revert any annotations we've performed in
+ // those tokens. We're not going to look them up until we've parsed
+ // the rest of the class, and that might add more declarations.
+ PA.RevertAnnotations();
}
- // Grab pack ellipsis, if present
- if (Tok.is(tok::ellipsis)) {
+ // Keep going. We know we're inside a template argument list now.
+ ++KnownTemplateCount;
+ goto consume_token;
+
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::less:
+ // FIXME: A '<' can only start a template-id if it's preceded by an
+ // identifier, an operator-function-id, or a literal-operator-id.
+ ++AngleCount;
+ goto consume_token;
+
+ case tok::question:
+ // In 'a ? b : c', 'b' can contain an unparenthesized comma. If it does,
+ // that is *never* the end of the initializer. Skip to the ':'.
+ if (!ConsumeAndStoreConditional(Toks))
+ return false;
+ break;
+
+ case tok::greatergreatergreater:
+ if (!getLangOpts().CPlusPlus11)
+ goto consume_token;
+ if (AngleCount) --AngleCount;
+ if (KnownTemplateCount) --KnownTemplateCount;
+ // Fall through.
+ case tok::greatergreater:
+ if (!getLangOpts().CPlusPlus11)
+ goto consume_token;
+ if (AngleCount) --AngleCount;
+ if (KnownTemplateCount) --KnownTemplateCount;
+ // Fall through.
+ case tok::greater:
+ if (AngleCount) --AngleCount;
+ if (KnownTemplateCount) --KnownTemplateCount;
+ goto consume_token;
+
+ case tok::kw_template:
+ // 'template' identifier '<' is known to start a template argument list,
+ // and can be used to disambiguate the parse.
+ // FIXME: Support all forms of 'template' unqualified-id '<'.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ if (Tok.is(tok::identifier)) {
Toks.push_back(Tok);
ConsumeToken();
+ if (Tok.is(tok::less)) {
+ ++KnownTemplateCount;
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
}
+ break;
- // Grab the separating comma, if any.
- if (Tok.is(tok::comma)) {
+ case tok::kw_operator:
+ // If 'operator' precedes other punctuation, that punctuation loses
+ // its special behavior.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ switch (Tok.getKind()) {
+ case tok::comma:
+ case tok::greatergreatergreater:
+ case tok::greatergreater:
+ case tok::greater:
+ case tok::less:
Toks.push_back(Tok);
ConsumeToken();
- } else if (Tok.isNot(tok::l_brace)) {
- ReadInitializer = true;
+ break;
+ default:
break;
}
- }
- }
+ break;
- // Grab any remaining garbage to be diagnosed later. We stop when we reach a
- // brace: an opening one is the function body, while a closing one probably
- // means we've reached the end of the class.
- ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
- /*StopAtSemi=*/true,
- /*ConsumeFinalToken=*/false);
- if (Tok.isNot(tok::l_brace)) {
- if (ReadInitializer)
- return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
- return Diag(Tok.getLocation(), diag::err_expected_lbrace);
- }
+ case tok::l_paren:
+ // Recursively consume properly-nested parens.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
+ break;
+ case tok::l_square:
+ // Recursively consume properly-nested square brackets.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false);
+ break;
+ case tok::l_brace:
+ // Recursively consume properly-nested braces.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+ break;
- Toks.push_back(Tok);
- ConsumeBrace();
- return false;
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (CIK == CIK_DefaultArgument)
+ return true; // End of the default argument.
+ if (ParenCount && !IsFirstTokenConsumed)
+ return false; // Matches something.
+ goto consume_token;
+ case tok::r_square:
+ if (BracketCount && !IsFirstTokenConsumed)
+ return false; // Matches something.
+ goto consume_token;
+ case tok::r_brace:
+ if (BraceCount && !IsFirstTokenConsumed)
+ return false; // Matches something.
+ goto consume_token;
+
+ 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 (CIK == CIK_DefaultInitializer)
+ return true; // End of the default initializer.
+ // FALL THROUGH.
+ default:
+ consume_token:
+ Toks.push_back(Tok);
+ ConsumeToken();
+ break;
+ }
+ IsFirstTokenConsumed = false;
+ }
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 6a87b78879e8..7b8093408bfd 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OpenCL.h"
@@ -99,18 +100,21 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
/// typequal
/// storageclass
///
-/// FIXME: The GCC grammar/code for this construct implies we need two
-/// token lookahead. Comment from gcc: "If they start with an identifier
-/// which is followed by a comma or close parenthesis, then the arguments
-/// start with that identifier; otherwise they are an expression list."
+/// Whether an attribute takes an 'identifier' is determined by the
+/// attrib-name. GCC's behavior here is not worth imitating:
///
-/// GCC does not require the ',' between attribs in an attribute-list.
+/// * In C mode, if the attribute argument list starts with an identifier
+/// followed by a ',' or an ')', and the identifier doesn't resolve to
+/// a type, it is parsed as an identifier. If the attribute actually
+/// wanted an expression, it's out of luck (but it turns out that no
+/// attributes work that way, because C constant expressions are very
+/// limited).
+/// * In C++ mode, if the attribute argument list starts with an identifier,
+/// and the attribute *wants* an identifier, it is parsed as an identifier.
+/// At block scope, any additional tokens between the identifier and the
+/// ',' or ')' are ignored, otherwise they produce a parse error.
///
-/// At the moment, I am not doing 2 token lookahead. I am also unaware of
-/// any attributes that don't work (based on my limited testing). Most
-/// attributes are very simple in practice. Until we find a bug, I don't see
-/// a pressing need to implement the 2 token lookahead.
-
+/// We follow the C++ model, but don't allow junk after the identifier.
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc,
LateParsedAttrList *LateAttrs) {
@@ -120,11 +124,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
ConsumeToken();
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
"attribute")) {
- SkipUntil(tok::r_paren, true); // skip until ) or ;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ;
return;
}
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
- SkipUntil(tok::r_paren, true); // skip until ) or ;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ;
return;
}
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
@@ -163,28 +167,76 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
0, SourceLocation(), AttributeList::AS_GNU);
}
} else {
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0, AttributeList::AS_GNU);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_GNU);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
- SkipUntil(tok::r_paren, false);
+ SkipUntil(tok::r_paren, StopAtSemi);
SourceLocation Loc = Tok.getLocation();
- if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
- SkipUntil(tok::r_paren, false);
- }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ SkipUntil(tok::r_paren, StopAtSemi);
if (endLoc)
*endLoc = Loc;
}
}
-/// \brief Determine whether the given attribute has all expression arguments.
-static bool attributeHasExprArgs(const IdentifierInfo &II) {
- return llvm::StringSwitch<bool>(II.getName())
-#include "clang/Parse/AttrExprArgs.inc"
+/// \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) {
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrIdentifierArg.inc"
+ .Default(false);
+}
+
+/// \brief Determine whether the given attribute parses a type argument.
+static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrTypeArg.inc"
.Default(false);
}
+IdentifierLoc *Parser::ParseIdentifierLoc() {
+ assert(Tok.is(tok::identifier) && "expected an identifier");
+ IdentifierLoc *IL = IdentifierLoc::create(Actions.Context,
+ Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ return IL;
+}
+
+void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+
+ TypeResult T;
+ if (Tok.isNot(tok::r_paren))
+ T = ParseTypeName();
+
+ if (Parens.consumeClose())
+ return;
+
+ if (T.isInvalid())
+ return;
+
+ if (T.isUsable())
+ Attrs.addNewTypeAttr(&AttrName,
+ SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0,
+ AttrNameLoc, T.get(), AttributeList::AS_GNU);
+ else
+ Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()),
+ 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU);
+}
+
/// Parse the arguments to a parameterized GNU attribute or
/// a C++11 attribute in "gnu" namespace.
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
@@ -197,89 +249,65 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+ AttributeList::Kind AttrKind =
+ AttributeList::getKind(AttrName, ScopeName, Syntax);
+
// Availability attributes have their own grammar.
- if (AttrName->isStr("availability")) {
+ // FIXME: All these cases fail to pass in the syntax and scope, and might be
+ // written as C++11 gnu:: attributes.
+ if (AttrKind == AttributeList::AT_Availability) {
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
- // Thread safety attributes fit into the FIXME case above, so we
- // just parse the arguments as a list of expressions
+ // Thread safety attributes are parsed in an unevaluated context.
+ // FIXME: Share the bulk of the parsing code here and just pull out
+ // the unevaluated context.
if (IsThreadSafetyAttribute(AttrName->getName())) {
ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
// Type safety attributes have their own grammar.
- if (AttrName->isStr("type_tag_for_datatype")) {
+ if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
+ // Some attributes expect solely a type parameter.
+ if (attributeIsTypeArgAttr(*AttrName)) {
+ ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ return;
+ }
- ConsumeParen(); // ignore the left paren loc for now
-
- IdentifierInfo *ParmName = 0;
- SourceLocation ParmLoc;
- bool BuiltinType = false;
+ // Ignore the left paren location for now.
+ ConsumeParen();
- TypeResult T;
- SourceRange TypeRange;
- bool TypeParsed = false;
+ ArgsVector ArgExprs;
- switch (Tok.getKind()) {
- case tok::kw_char:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_bool:
- case tok::kw_short:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_void:
- case tok::kw_typeof:
- // __attribute__(( vec_type_hint(char) ))
- BuiltinType = true;
- T = ParseTypeName(&TypeRange);
- TypeParsed = true;
- break;
-
- case tok::identifier:
- if (AttrName->isStr("vec_type_hint")) {
- T = ParseTypeName(&TypeRange);
- TypeParsed = true;
- break;
+ if (Tok.is(tok::identifier)) {
+ // If this attribute wants an 'identifier' argument, make it so.
+ bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName);
+
+ // If we don't know how to parse this attribute, but this is the only
+ // token in this argument, assume it's meant to be an identifier.
+ if (AttrKind == AttributeList::UnknownAttribute ||
+ AttrKind == AttributeList::IgnoredAttribute) {
+ const Token &Next = NextToken();
+ IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma);
}
- // If the attribute has all expression arguments, and not a "parameter",
- // break out to handle it below.
- if (attributeHasExprArgs(*AttrName))
- break;
- ParmName = Tok.getIdentifierInfo();
- ParmLoc = ConsumeToken();
- break;
- default:
- break;
+ if (IsIdentifierArg)
+ ArgExprs.push_back(ParseIdentifierLoc());
}
- ExprVector ArgExprs;
- bool isInvalid = false;
- bool isParmType = false;
-
- if (!BuiltinType && !AttrName->isStr("vec_type_hint") &&
- (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
+ if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) {
// Eat the comma.
- if (ParmLoc.isValid())
+ if (!ArgExprs.empty())
ConsumeToken();
// Parse the non-empty comma-separated list of expressions.
while (1) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
ArgExprs.push_back(ArgExpr.release());
@@ -288,48 +316,12 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
ConsumeToken(); // Eat the comma, move to the next argument
}
}
- else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) {
- if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<",
- tok::greater)) {
- while (Tok.is(tok::identifier)) {
- ConsumeToken();
- if (Tok.is(tok::greater))
- break;
- if (Tok.is(tok::comma)) {
- ConsumeToken();
- continue;
- }
- }
- if (Tok.isNot(tok::greater))
- Diag(Tok, diag::err_iboutletcollection_with_protocol);
- SkipUntil(tok::r_paren, false, true); // skip until ')'
- }
- } else if (AttrName->isStr("vec_type_hint")) {
- if (T.get() && !T.isInvalid())
- isParmType = true;
- else {
- if (Tok.is(tok::identifier))
- ConsumeToken();
- if (TypeParsed)
- isInvalid = true;
- }
- }
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) &&
- !isInvalid) {
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- if (isParmType) {
- Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName,
- ScopeLoc, ParmName, ParmLoc, T.get(), Syntax);
- } else {
- AttributeList *attr = Attrs.addNew(
- AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName,
- ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax);
- if (BuiltinType &&
- attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
- }
+ Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+ ArgExprs.data(), ArgExprs.size(), Syntax);
}
}
@@ -349,9 +341,9 @@ void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName,
T.skipToEnd();
return;
}
- Expr *ExprList = ArgExpr.take();
- Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
- &ExprList, 1, AttributeList::AS_Declspec);
+ ArgsUnion ExprList = ArgExpr.take();
+ Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, &ExprList, 1,
+ AttributeList::AS_Declspec);
T.consumeClose();
}
@@ -399,8 +391,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
if (Tok.getKind() == tok::l_paren)
ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs);
else
- Attrs.addNew(Ident, Loc, 0, Loc, 0, SourceLocation(), 0, 0,
- AttributeList::AS_Declspec);
+ Attrs.addNew(Ident, Loc, 0, Loc, 0, 0, AttributeList::AS_Declspec);
} else if (Ident->getName() == "property") {
// The property declspec is more complex in that it can take one or two
// assignment expressions as a parameter, but the lhs of the assignment
@@ -513,8 +504,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
// Only add the property attribute if it was well-formed.
if (!HasInvalidAccessor) {
- Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0,
- SourceLocation(),
+ Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(),
AccessorNames[AK_Get], AccessorNames[AK_Put],
AttributeList::AS_Declspec);
}
@@ -588,8 +578,8 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) {
//
// Alternatively, if the identifier is a simple one, then it requires no
// arguments and can be turned into an attribute directly.
- Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
- 0, 0, AttributeList::AS_Declspec);
+ Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_Declspec);
else
ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs);
}
@@ -601,11 +591,12 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
+ Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) ||
+ Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_Keyword);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_Keyword);
}
}
@@ -614,8 +605,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___pascal)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_Keyword);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_Keyword);
}
}
@@ -624,8 +615,8 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___kernel)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_Keyword);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_Keyword);
}
}
@@ -692,7 +683,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
if (!Tok.is(tok::numeric_constant)) {
Diag(Tok, diag::err_expected_version);
- SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ SkipUntil(tok::comma, tok::r_paren,
+ StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
@@ -720,7 +712,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
if (AfterMajor == 0) {
Diag(Tok, diag::err_expected_version);
- SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ SkipUntil(tok::comma, tok::r_paren,
+ StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
@@ -738,7 +731,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) {
Diag(Tok, diag::err_expected_version);
- SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ SkipUntil(tok::comma, tok::r_paren,
+ StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
@@ -765,7 +759,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// If what follows is not a '.', we have a problem.
if (ThisTokBegin[AfterMinor] != '.') {
Diag(Tok, diag::err_expected_version);
- SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ SkipUntil(tok::comma, tok::r_paren,
+ StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
@@ -779,7 +774,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
if (AfterSubminor != ActualLength) {
Diag(Tok, diag::err_expected_version);
- SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ SkipUntil(tok::comma, tok::r_paren,
+ StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
ConsumeToken();
@@ -809,9 +805,6 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
SourceLocation AvailabilityLoc,
ParsedAttributes &attrs,
SourceLocation *endLoc) {
- SourceLocation PlatformLoc;
- IdentifierInfo *Platform = 0;
-
enum { Introduced, Deprecated, Obsoleted, Unknown };
AvailabilityChange Changes[Unknown];
ExprResult MessageExpr;
@@ -826,11 +819,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
// Parse the platform name,
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_availability_expected_platform);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
- Platform = Tok.getIdentifierInfo();
- PlatformLoc = ConsumeToken();
+ IdentifierLoc *Platform = ParseIdentifierLoc();
// Parse the ',' following the platform name.
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren))
@@ -851,7 +843,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
do {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_availability_expected_change);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
IdentifierInfo *Keyword = Tok.getIdentifierInfo();
@@ -874,15 +866,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
if (Tok.isNot(tok::equal)) {
Diag(Tok, diag::err_expected_equal_after)
<< Keyword;
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
ConsumeToken();
if (Keyword == Ident_message) {
- if (!isTokenStringLiteral()) {
+ if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals.
Diag(Tok, diag::err_expected_string_literal)
<< /*Source='availability attribute'*/2;
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
MessageExpr = ParseStringLiteralExpression();
@@ -893,7 +885,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
VersionTuple Version = ParseVersionTuple(VersionRange);
if (Version.empty()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
@@ -959,7 +951,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
attrs.addNew(&Availability,
SourceRange(AvailabilityLoc, T.getCloseLocation()),
0, AvailabilityLoc,
- Platform, PlatformLoc,
+ Platform,
Changes[Introduced],
Changes[Deprecated],
Changes[Obsoleted],
@@ -1062,9 +1054,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
// Allow 'this' within late-parsed attributes.
- Sema::CXXThisScopeRAII ThisScope(Actions, RD,
- /*TypeQuals=*/0,
- ND && RD && ND->isCXXInstanceMember());
+ Sema::CXXThisScopeRAII ThisScope(Actions, RD, /*TypeQuals=*/0,
+ ND && ND->isCXXInstanceMember());
if (LA.Decls.size() == 1) {
// If the Decl is templatized, add template parameters to scope.
@@ -1161,7 +1152,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector ArgExprs;
+ ArgsVector ArgExprs;
bool ArgExprsOk = true;
// now parse the list of expressions
@@ -1181,8 +1172,8 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
}
// Match the ')'.
if (ArgExprsOk && !T.consumeClose()) {
- Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
- ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU);
+ Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(),
+ ArgExprs.size(), AttributeList::AS_GNU);
}
if (EndLoc)
*EndLoc = T.getCloseLocation();
@@ -1202,8 +1193,7 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
T.skipToEnd();
return;
}
- IdentifierInfo *ArgumentKind = Tok.getIdentifierInfo();
- SourceLocation ArgumentKindLoc = ConsumeToken();
+ IdentifierLoc *ArgumentKind = ParseIdentifierLoc();
if (Tok.isNot(tok::comma)) {
Diag(Tok, diag::err_expected_comma);
@@ -1243,9 +1233,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
if (!T.consumeClose()) {
Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc,
- ArgumentKind, ArgumentKindLoc,
- MatchingCType.release(), LayoutCompatible,
- MustBeNull, AttributeList::AS_GNU);
+ ArgumentKind, MatchingCType.release(),
+ LayoutCompatible, MustBeNull,
+ AttributeList::AS_GNU);
}
if (EndLoc)
@@ -1276,7 +1266,7 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
// Parse and discard the attributes.
SourceLocation BeginLoc = ConsumeBracket();
ConsumeBracket();
- SkipUntil(tok::r_square, /*StopAtSemi*/ false);
+ SkipUntil(tok::r_square);
assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
SourceLocation EndLoc = ConsumeBracket();
Diag(BeginLoc, diag::err_attributes_not_allowed)
@@ -1412,8 +1402,14 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
- getDeclSpecContextFromDeclaratorContext(Context));
+ DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext))
+ return DeclGroupPtrTy();
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -1507,7 +1503,7 @@ void Parser::SkipMalformedDecl() {
// Skip until matching }, then stop. We've probably skipped over
// a malformed class or function definition or similar.
ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi*/false);
+ SkipUntil(tok::r_brace);
if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) {
// This declaration isn't over yet. Keep skipping.
continue;
@@ -1518,12 +1514,12 @@ void Parser::SkipMalformedDecl() {
case tok::l_square:
ConsumeBracket();
- SkipUntil(tok::r_square, /*StopAtSemi*/false);
+ SkipUntil(tok::r_square);
continue;
case tok::l_paren:
ConsumeParen();
- SkipUntil(tok::r_paren, /*StopAtSemi*/false);
+ SkipUntil(tok::r_paren);
continue;
case tok::r_brace:
@@ -1636,7 +1632,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
} else {
if (Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_function_definition_not_allowed);
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
}
}
}
@@ -1666,7 +1662,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
D.complete(ThisDecl);
- return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
+ return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, ThisDecl);
}
SmallVector<Decl *, 8> DeclsInGroup;
@@ -1727,15 +1723,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// declaration specifier, just assume it was missing and continue parsing.
// Otherwise things are very confused and we skip to recover.
if (!isDeclarationSpecifier()) {
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
}
}
- return Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
- DeclsInGroup.data(),
- DeclsInGroup.size());
+ return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
}
/// Parse an optional simple-asm-expr and attributes, and attach them to a
@@ -1746,7 +1740,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
return true;
}
@@ -1798,24 +1792,53 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
break;
case ParsedTemplateInfo::Template:
- case ParsedTemplateInfo::ExplicitSpecialization:
+ case ParsedTemplateInfo::ExplicitSpecialization: {
ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
*TemplateInfo.TemplateParams,
D);
+ if (VarTemplateDecl *VT = dyn_cast_or_null<VarTemplateDecl>(ThisDecl))
+ // Re-direct this decl to refer to the templated decl so that we can
+ // initialize it.
+ ThisDecl = VT->getTemplatedDecl();
break;
-
+ }
case ParsedTemplateInfo::ExplicitInstantiation: {
- DeclResult ThisRes
- = Actions.ActOnExplicitInstantiation(getCurScope(),
- TemplateInfo.ExternLoc,
- TemplateInfo.TemplateLoc,
- D);
- if (ThisRes.isInvalid()) {
- SkipUntil(tok::semi, true, true);
- return 0;
+ if (Tok.is(tok::semi)) {
+ DeclResult ThisRes = Actions.ActOnExplicitInstantiation(
+ getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D);
+ if (ThisRes.isInvalid()) {
+ SkipUntil(tok::semi, StopBeforeMatch);
+ return 0;
+ }
+ ThisDecl = ThisRes.get();
+ } else {
+ // FIXME: This check should be for a variable template instantiation only.
+
+ // Check that this is a valid instantiation
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ // If the declarator-id is not a template-id, issue a diagnostic and
+ // recover by ignoring the 'template' keyword.
+ Diag(Tok, diag::err_template_defn_explicit_instantiation)
+ << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
+ ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
+ } else {
+ SourceLocation LAngleLoc =
+ PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Recover as if it were an explicit specialization.
+ TemplateParameterLists FakedParamLists;
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
+ LAngleLoc));
+
+ ThisDecl =
+ Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
+ }
}
-
- ThisDecl = ThisRes.get();
break;
}
}
@@ -1826,6 +1849,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
// If a '==' or '+=' is found, suggest a fixit to '='.
if (isTokenEqualOrEqualTypo()) {
ConsumeToken();
+
if (Tok.is(tok::kw_delete)) {
if (D.isFunctionDeclarator())
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
@@ -1859,7 +1883,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
if (Init.isInvalid()) {
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
Actions.ActOnInitializerError(ThisDecl);
} else
Actions.AddInitializerToDecl(ThisDecl, Init.take(),
@@ -1880,7 +1904,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
if (ParseExpressionList(Exprs, CommaLocs)) {
Actions.ActOnInitializerError(ThisDecl);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
@@ -2063,6 +2087,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
// Don't require a type specifier if we have the 'auto' storage class
// specifier in C++98 -- we'll promote it to a type specifier.
+ if (SS)
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
return false;
}
@@ -2124,16 +2150,6 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// Look ahead to the next token to try to figure out what this declaration
// was supposed to be.
switch (NextToken().getKind()) {
- case tok::comma:
- case tok::equal:
- case tok::kw_asm:
- case tok::l_brace:
- case tok::l_square:
- case tok::semi:
- // This looks like a variable declaration. The type is probably missing.
- // We're done parsing decl-specifiers.
- return false;
-
case tok::l_paren: {
// static x(4); // 'x' is not a type
// x(int n); // 'x' is not a type
@@ -2146,12 +2162,37 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
ConsumeToken();
TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);
PA.Revert();
- if (TPR == TPResult::False())
- return false;
- // The identifier is followed by a parenthesized declarator.
- // It's supposed to be a type.
- break;
+
+ if (TPR != TPResult::False()) {
+ // The identifier is followed by a parenthesized declarator.
+ // It's supposed to be a type.
+ break;
+ }
+
+ // If we're in a context where we could be declaring a constructor,
+ // check whether this is a constructor declaration with a bogus name.
+ if (DSC == DSC_class || (DSC == DSC_top_level && SS)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (Actions.isCurrentClassNameTypo(II, SS)) {
+ Diag(Loc, diag::err_constructor_bad_name)
+ << Tok.getIdentifierInfo() << II
+ << FixItHint::CreateReplacement(Tok.getLocation(), II->getName());
+ Tok.setIdentifierInfo(II);
+ }
+ }
+ // Fall through.
}
+ case tok::comma:
+ case tok::equal:
+ case tok::kw_asm:
+ case tok::l_brace:
+ case tok::l_square:
+ case tok::semi:
+ // This looks like a variable or function declaration. The type is
+ // probably missing. We're done parsing decl-specifiers.
+ if (SS)
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
+ return false;
default:
// This is probably supposed to be a type. This includes cases like:
@@ -2270,7 +2311,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation EllipsisLoc;
ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc);
if (ArgExpr.isInvalid()) {
- SkipUntil(tok::r_paren);
+ T.skipToEnd();
return;
}
@@ -2278,10 +2319,105 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
if (EndLoc)
*EndLoc = T.getCloseLocation();
- ExprVector ArgExprs;
+ ArgsVector ArgExprs;
ArgExprs.push_back(ArgExpr.release());
- Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(),
- ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc);
+ Attrs.addNew(KWName, KWLoc, 0, KWLoc, ArgExprs.data(), 1,
+ AttributeList::AS_Keyword, EllipsisLoc);
+}
+
+/// Determine whether we're looking at something that might be a declarator
+/// in a simple-declaration. If it can't possibly be a declarator, maybe
+/// diagnose a missing semicolon after a prior tag definition in the decl
+/// specifier.
+///
+/// \return \c true if an error occurred and this can't be any kind of
+/// declaration.
+bool
+Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+ DeclSpecContext DSContext,
+ LateParsedAttrList *LateAttrs) {
+ assert(DS.hasTagDefinition() && "shouldn't call this");
+
+ bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
+ bool HasMissingSemi = false;
+
+ if (getLangOpts().CPlusPlus &&
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) &&
+ TryAnnotateCXXScopeToken(EnteringContext)) {
+ SkipMalformedDecl();
+ return true;
+ }
+
+ // Determine whether the following tokens could possibly be a
+ // declarator.
+ if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
+ const Token &Next = NextToken();
+ // These tokens cannot come after the declarator-id in a
+ // simple-declaration, and are likely to come after a type-specifier.
+ HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) ||
+ Next.is(tok::ampamp) || Next.is(tok::identifier) ||
+ Next.is(tok::annot_cxxscope) ||
+ Next.is(tok::coloncolon);
+ } else if (Tok.is(tok::annot_cxxscope) &&
+ NextToken().is(tok::identifier) &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
+ // We almost certainly have a missing semicolon. Look up the name and
+ // check; if it names a type, we're missing a semicolon.
+ CXXScopeSpec SS;
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(), SS);
+ const Token &Next = NextToken();
+ IdentifierInfo *Name = Next.getIdentifierInfo();
+ Sema::NameClassification Classification =
+ Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(),
+ NextToken(), /*IsAddressOfOperand*/false);
+ switch (Classification.getKind()) {
+ case Sema::NC_Error:
+ SkipMalformedDecl();
+ return true;
+
+ case Sema::NC_Keyword:
+ case Sema::NC_NestedNameSpecifier:
+ llvm_unreachable("typo correction and nested name specifiers not "
+ "possible here");
+
+ case Sema::NC_Type:
+ case Sema::NC_TypeTemplate:
+ // Not a previously-declared non-type entity.
+ HasMissingSemi = true;
+ break;
+
+ case Sema::NC_Unknown:
+ case Sema::NC_Expression:
+ case Sema::NC_VarTemplate:
+ case Sema::NC_FunctionTemplate:
+ // Might be a redeclaration of a prior entity.
+ HasMissingSemi = false;
+ break;
+ }
+ } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
+ HasMissingSemi = true;
+ }
+
+ if (!HasMissingSemi)
+ return false;
+
+ Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()),
+ diag::err_expected_semi_after_tagdecl)
+ << DeclSpec::getSpecifierName(DS.getTypeSpecType());
+
+ // Try to recover from the typo, by dropping the tag definition and parsing
+ // the problematic tokens as a type.
+ //
+ // FIXME: Split the DeclSpec into pieces for the standalone
+ // declaration and pieces for the following declaration, instead
+ // of assuming that all the other pieces attach to new declaration,
+ // and call ParsedFreeStandingDeclSpec as appropriate.
+ DS.ClearTypeSpecType();
+ ParsedTemplateInfo NotATemplate;
+ ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);
+ return false;
}
/// ParseDeclarationSpecifiers
@@ -2402,7 +2538,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::coloncolon: // ::foo::bar
// C++ scope specifier. Annotate and loop, or bail out on error.
- if (TryAnnotateCXXScopeToken(true)) {
+ if (TryAnnotateCXXScopeToken(EnteringContext)) {
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
goto DoneWithDeclSpec;
@@ -2524,7 +2660,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// erroneous: We already checked about that it has no type specifier, and
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
- if (TypeRep == 0) {
+ if (!TypeRep) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
@@ -2552,6 +2688,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
case tok::annot_typename: {
+ // If we've previously seen a tag definition, we were almost surely
+ // missing a semicolon after it.
+ if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
+ goto DoneWithDeclSpec;
+
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
@@ -2584,10 +2725,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// then treat __is_signed as an identifier rather than as a keyword.
if (DS.getTypeSpecType() == TST_bool &&
DS.getTypeQualifiers() == DeclSpec::TQ_const &&
- DS.getStorageClassSpec() == DeclSpec::SCS_static) {
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
- Tok.setKind(tok::identifier);
- }
+ DS.getStorageClassSpec() == DeclSpec::SCS_static)
+ TryKeywordIdentFallback(true);
// We're done with the declaration-specifiers.
goto DoneWithDeclSpec;
@@ -2598,7 +2737,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// In C++, check to see if this is a scope specifier like foo::bar::, if
// so handle it as such. This is important for ctor parsing.
if (getLangOpts().CPlusPlus) {
- if (TryAnnotateCXXScopeToken(true)) {
+ if (TryAnnotateCXXScopeToken(EnteringContext)) {
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
goto DoneWithDeclSpec;
@@ -2701,16 +2840,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Microsoft single token adornments.
case tok::kw___forceinline: {
- isInvalid = DS.setFunctionSpecInline(Loc);
+ isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = Tok.getLocation();
// FIXME: This does not work correctly if it is set to be a declspec
// attribute, and a GNU attribute is simply incorrect.
- DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_GNU);
+ DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_GNU);
break;
}
+ case tok::kw___sptr:
+ case tok::kw___uptr:
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___w64:
@@ -2791,18 +2932,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// function-specifier
case tok::kw_inline:
- isInvalid = DS.setFunctionSpecInline(Loc);
+ isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
break;
case tok::kw_virtual:
- isInvalid = DS.setFunctionSpecVirtual(Loc);
+ isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
break;
case tok::kw_explicit:
- isInvalid = DS.setFunctionSpecExplicit(Loc);
+ isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
break;
case tok::kw__Noreturn:
if (!getLangOpts().C11)
Diag(Loc, diag::ext_c11_noreturn);
- isInvalid = DS.setFunctionSpecNoreturn(Loc);
+ isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
break;
// alignment-specifier
@@ -3168,7 +3309,7 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
ConsumeToken();
ExprResult Res(ParseConstantExpression());
if (Res.isInvalid())
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
else
DeclaratorInfo.BitfieldSize = Res.release();
}
@@ -3214,12 +3355,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- // Empty structs are an extension in C (C99 6.7.2.1p7).
- if (Tok.is(tok::r_brace)) {
- Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
- Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
- }
-
SmallVector<Decl *, 32> FieldDecls;
// While we still have something to read, read the declarations in the struct.
@@ -3276,14 +3411,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
Diag(Tok, diag::err_unexpected_at);
- SkipUntil(tok::semi, true);
+ SkipUntil(tok::semi);
continue;
}
ConsumeToken();
ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::semi, true);
+ SkipUntil(tok::semi);
continue;
}
SmallVector<Decl *, 16> Fields;
@@ -3302,7 +3437,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
} else {
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
// Skip to end of block or statement to avoid ext-warning on extra ';'.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
// If we stopped at a ';', eat it.
if (Tok.is(tok::semi)) ConsumeToken();
}
@@ -3426,7 +3561,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.isNot(tok::l_brace)) {
// Has no name and is not a definition.
// Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
+ SkipUntil(tok::comma, StopAtSemi);
return;
}
}
@@ -3438,7 +3573,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Diag(Tok, diag::err_expected_ident_lbrace);
// Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
+ SkipUntil(tok::comma, StopAtSemi);
return;
}
@@ -3556,7 +3691,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
<< SourceRange(DS.getFriendSpecLoc());
ConsumeBrace();
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
TUK = Sema::TUK_Friend;
} else {
TUK = Sema::TUK_Definition;
@@ -3589,7 +3724,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!getLangOpts().CPlusPlus11 || !SS.isSet()) {
// Skip the rest of this declarator, up until the comma or semicolon.
Diag(Tok, diag::err_enum_template);
- SkipUntil(tok::comma, true);
+ SkipUntil(tok::comma, StopAtSemi);
return;
}
@@ -3612,7 +3747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Diag(Tok, diag::err_enumerator_unnamed_no_def);
// Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
+ SkipUntil(tok::comma, StopAtSemi);
return;
}
@@ -3656,7 +3791,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// definition, consume the entire definition.
if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
ConsumeBrace();
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
}
DS.SetTypeSpecError();
@@ -3717,7 +3852,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
EqualLoc = ConsumeToken();
AssignedVal = ParseConstantExpression();
if (AssignedVal.isInvalid())
- SkipUntil(tok::comma, tok::r_brace, true, true);
+ SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch);
}
// Install the enumerator constant into EnumDecl.
@@ -4145,6 +4280,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___fastcall:
case tok::kw___thiscall:
case tok::kw___w64:
+ case tok::kw___sptr:
+ case tok::kw___uptr:
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___forceinline:
@@ -4199,6 +4336,15 @@ bool Parser::isConstructorDeclarator() {
return true;
}
+ // A C++11 attribute here signals that we have a constructor, and is an
+ // attribute on the first constructor parameter.
+ if (getLangOpts().CPlusPlus11 &&
+ isCXX11AttributeSpecifier(/*Disambiguate*/ false,
+ /*OuterMightBeMessageSend*/ true)) {
+ TPA.Revert();
+ return true;
+ }
+
// If we need to, enter the specified scope.
DeclaratorScopeObj DeclScopeObj(*this, SS);
if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
@@ -4267,7 +4413,8 @@ bool Parser::isConstructorDeclarator() {
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
bool VendorAttributesAllowed,
bool CXX11AttributesAllowed,
- bool AtomicAllowed) {
+ bool AtomicAllowed,
+ bool IdentifierRequired) {
if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
@@ -4321,6 +4468,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
ParseOpenCLQualifiers(DS);
break;
+ case tok::kw___uptr:
+ // GNU libc headers in C mode use '__uptr' as an identifer which conflicts
+ // with the MS modifier keyword.
+ if (VendorAttributesAllowed && !getLangOpts().CPlusPlus &&
+ IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
+ if (TryKeywordIdentFallback(false))
+ continue;
+ }
+ case tok::kw___sptr:
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___ptr32:
@@ -4476,7 +4632,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
DeclSpec DS(AttrFactory);
// FIXME: GNU attributes are not allowed here in a new-type-id.
- ParseTypeQualifierListOpt(DS);
+ ParseTypeQualifierListOpt(DS, true, true, true, !D.mayOmitIdentifier());
D.ExtendWithDeclSpec(DS);
// Recursively parse the declarator.
@@ -4636,6 +4792,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// as part of the parameter-declaration-clause.
if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
!((D.getContext() == Declarator::PrototypeContext ||
+ D.getContext() == Declarator::LambdaExprParameterContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
!D.hasGroupingParens() &&
@@ -4697,6 +4854,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetIdentifier(Tok.getIdentifierInfo(), 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)) {
+ Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
+ << FixItHint::CreateRemoval(Tok.getLocation());
+ D.SetIdentifier(0, Tok.getLocation());
+ ConsumeToken();
+ goto PastIdentifier;
+ }
}
if (Tok.is(tok::l_paren)) {
@@ -4736,8 +4904,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
else if (getLangOpts().CPlusPlus) {
if (Tok.is(tok::period) || Tok.is(tok::arrow))
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
- else
- Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
+ else {
+ SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
+ if (Tok.isAtStartOfLine() && Loc.isValid())
+ Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus;
+ else
+ Diag(Tok, diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus;
+ }
} else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());
@@ -4948,7 +5123,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
TypeResult TrailingReturnType;
Actions.ActOnStartFunctionDeclarator();
-
/* LocalEndLoc is the end location for the local FunctionTypeLoc.
EndLoc is the end location for the function declarator.
They differ for trailing return types. */
@@ -4969,7 +5143,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
EndLoc = RParenLoc;
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
+ ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
+ EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -5117,7 +5292,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() {
///
void Parser::ParseFunctionDeclaratorIdentifierList(
Declarator &D,
- SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) {
+ SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) {
// If there was no identifier specified for the declarator, either we are in
// an abstract-declarator, or we are in a parameter declarator which was found
// to be abstract. In abstract-declarators, identifier lists are not valid:
@@ -5132,7 +5307,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
// If this isn't an identifier, report the error and skip until ')'.
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
// Forget we parsed anything.
ParamInfo.clear();
return;
@@ -5198,9 +5373,8 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
void Parser::ParseParameterDeclarationClause(
Declarator &D,
ParsedAttributes &FirstArgAttrs,
- SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
-
while (1) {
if (Tok.is(tok::ellipsis)) {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
@@ -5230,16 +5404,21 @@ void Parser::ParseParameterDeclarationClause(
ParseDeclarationSpecifiers(DS);
- // Parse the declarator. This is "PrototypeContext", because we must
- // accept either 'declarator' or 'abstract-declarator' here.
- Declarator ParmDecl(DS, Declarator::PrototypeContext);
- ParseDeclarator(ParmDecl);
+
+ // Parse the declarator. This is "PrototypeContext" or
+ // "LambdaExprParameterContext", because we must accept either
+ // 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDeclarator(DS,
+ D.getContext() == Declarator::LambdaExprContext ?
+ Declarator::LambdaExprParameterContext :
+ Declarator::PrototypeContext);
+ ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present.
- MaybeParseGNUAttributes(ParmDecl);
+ MaybeParseGNUAttributes(ParmDeclarator);
// Remember this parsed parameter in ParamInfo.
- IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+ IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
// DefArgToks is used when the parsing of default arguments needs
// to be delayed.
@@ -5247,8 +5426,8 @@ void Parser::ParseParameterDeclarationClause(
// If no parameter was specified, verify that *something* was specified,
// otherwise we have a missing type and identifier.
- if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
- ParmDecl.getNumTypeObjects() == 0) {
+ if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 &&
+ ParmDeclarator.getNumTypeObjects() == 0) {
// Completely missing, emit error.
Diag(DSStart, diag::err_missing_param);
} else {
@@ -5257,8 +5436,8 @@ void Parser::ParseParameterDeclarationClause(
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
- Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
-
+ Decl *Param = Actions.ActOnParamDeclarator(getCurScope(),
+ ParmDeclarator);
// Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in
@@ -5274,9 +5453,7 @@ void Parser::ParseParameterDeclarationClause(
// FIXME: Can we use a smart pointer for Toks?
DefArgToks = new CachedTokens;
- if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
- /*StopAtSemi=*/true,
- /*ConsumeFinalToken=*/false)) {
+ if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) {
delete DefArgToks;
DefArgToks = 0;
Actions.ActOnParamDefaultArgumentError(Param);
@@ -5309,7 +5486,7 @@ void Parser::ParseParameterDeclarationClause(
DefArgResult = ParseAssignmentExpression();
if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(Param);
- SkipUntil(tok::comma, tok::r_paren, true, true);
+ SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
} else {
// Inform the actions module about the default argument
Actions.ActOnParamDefaultArgument(Param, EqualLoc,
@@ -5319,8 +5496,8 @@ void Parser::ParseParameterDeclarationClause(
}
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
- ParmDecl.getIdentifierLoc(), Param,
- DefArgToks));
+ ParmDeclarator.getIdentifierLoc(),
+ Param, DefArgToks));
}
// If the next token is a comma, consume it and keep reading arguments.
@@ -5444,7 +5621,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
if (NumElements.isInvalid()) {
D.setInvalidType(true);
// If the expression was invalid, skip it.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return;
}
@@ -5541,7 +5718,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
TypeResult Result = ParseTypeName();
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
@@ -5586,6 +5763,10 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() {
Tok.setKind(tok::kw___vector);
return true;
}
+ if (Next.getIdentifierInfo() == Ident_bool) {
+ Tok.setKind(tok::kw___vector);
+ return true;
+ }
return false;
}
}
@@ -5614,6 +5795,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
return true;
}
+ if (Next.getIdentifierInfo() == Ident_bool) {
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ return true;
+ }
break;
default:
break;
@@ -5622,6 +5807,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
DS.isTypeAltiVecVector()) {
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
return true;
+ } else if ((Tok.getIdentifierInfo() == Ident_bool) &&
+ DS.isTypeAltiVecVector()) {
+ isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID);
+ return true;
}
return false;
}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f1fbbb15fed5..16d06d7d152c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -15,6 +15,7 @@
#include "RAIIObjectsForParser.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -123,13 +124,13 @@ Decl *Parser::ParseNamespace(unsigned Context,
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
}
Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
- SkipUntil(tok::r_brace, false);
+ SkipUntil(tok::r_brace);
return 0;
}
if (!ExtraIdent.empty()) {
TentativeParsingAction TPA(*this);
- SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true);
+ SkipUntil(tok::r_brace, StopBeforeMatch);
Token rBraceToken = Tok;
TPA.Revert();
@@ -451,20 +452,18 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Decl **OwnedType) {
CXXScopeSpec SS;
SourceLocation TypenameLoc;
- bool IsTypeName = false;
- ParsedAttributesWithRange Attrs(AttrFactory);
+ bool HasTypenameKeyword = false;
- // FIXME: Simply skip the attributes and diagnose, don't bother parsing them.
- MaybeParseCXX11Attributes(Attrs);
- ProhibitAttributes(Attrs);
- Attrs.clear();
- Attrs.Range = SourceRange();
+ // Check for misplaced attributes before the identifier in an
+ // alias-declaration.
+ ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(MisplacedAttrs);
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
TypenameLoc = ConsumeToken();
- IsTypeName = true;
+ HasTypenameKeyword = true;
}
// Parse nested-name-specifier.
@@ -508,13 +507,25 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseGNUAttributes(Attrs);
MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
- bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
+ bool IsAliasDecl = Tok.is(tok::equal);
if (IsAliasDecl) {
- // TODO: Can GNU attributes appear here?
+ // If we had any misplaced attributes from earlier, this is where they
+ // should have been written.
+ if (MisplacedAttrs.Range.isValid()) {
+ Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
+ << FixItHint::CreateInsertionFromRange(
+ Tok.getLocation(),
+ CharSourceRange::getTokenRange(MisplacedAttrs.Range))
+ << FixItHint::CreateRemoval(MisplacedAttrs.Range);
+ Attrs.takeAllFrom(MisplacedAttrs);
+ }
+
ConsumeToken();
Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
@@ -549,7 +560,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// No removal fixit: can't recover from this.
SkipUntil(tok::semi);
return 0;
- } else if (IsTypeName)
+ } else if (HasTypenameKeyword)
Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc,
SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc));
@@ -564,6 +575,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
} else {
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
+ ProhibitAttributes(MisplacedAttrs);
ProhibitAttributes(Attrs);
// Parse (optional) attributes (most likely GNU strong-using extension).
@@ -593,11 +605,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// "typename" keyword is allowed for identifiers only,
// because it may be a type definition.
- if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) {
+ if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc));
- // Proceed parsing, but reset the IsTypeName flag.
- IsTypeName = false;
+ // Proceed parsing, but reset the HasTypenameKeyword flag.
+ HasTypenameKeyword = false;
}
if (IsAliasDecl) {
@@ -610,9 +622,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias);
}
- return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
- Name, Attrs.getList(),
- IsTypeName, TypenameLoc);
+ return Actions.ActOnUsingDeclaration(getCurScope(), AS,
+ /* HasUsingKeyword */ true, UsingLoc,
+ SS, Name, Attrs.getList(),
+ HasTypenameKeyword, TypenameLoc);
}
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
@@ -729,8 +742,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
Result = ParseExpression();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
- if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true,
- /*DontConsume=*/true)) {
+ if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
EndLoc = ConsumeParen();
} else {
if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) {
@@ -813,7 +825,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
TypeResult Result = ParseTypeName();
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
@@ -827,6 +839,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
DiagID, Result.release()))
Diag(StartLoc, DiagID) << PrevSpec;
+ DS.setTypeofParensRange(T.getRange());
}
/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
@@ -917,8 +930,13 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
<< Id;
}
- if (!Template)
+ if (!Template) {
+ TemplateArgList TemplateArgs;
+ SourceLocation LAngleLoc, RAngleLoc;
+ ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS,
+ true, LAngleLoc, TemplateArgs, RAngleLoc);
return true;
+ }
// Form the template name
UnqualifiedId TemplateName;
@@ -979,8 +997,8 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
Tok.is(tok::kw___virtual_inheritance)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_GNU);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ AttributeList::AS_GNU);
}
}
@@ -1140,8 +1158,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ParsedAttributesWithRange attrs(AttrFactory);
// If attributes exist after tag, parse them.
- if (Tok.is(tok::kw___attribute))
- ParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(attrs);
// If declspecs exist after tag, parse them.
while (Tok.is(tok::kw___declspec))
@@ -1151,7 +1168,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::kw___single_inheritance) ||
Tok.is(tok::kw___multiple_inheritance) ||
Tok.is(tok::kw___virtual_inheritance))
- ParseMicrosoftInheritanceClassAttributes(attrs);
+ ParseMicrosoftInheritanceClassAttributes(attrs);
// If C++0x attributes exist here, parse them.
// FIXME: Are we consistent with the ordering of parsing of different
@@ -1180,15 +1197,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Tok.is(tok::kw___is_scalar) ||
Tok.is(tok::kw___is_signed) ||
Tok.is(tok::kw___is_unsigned) ||
- Tok.is(tok::kw___is_void))) {
+ Tok.is(tok::kw___is_void)))
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
// name of struct templates, but some are keywords in GCC >= 4.3
// and Clang. Therefore, when we see the token sequence "struct
// X", make X into a normal identifier rather than a keyword, to
// allow libstdc++ 4.2 and libc++ to work properly.
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
- Tok.setKind(tok::identifier);
- }
+ TryKeywordIdentFallback(true);
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
@@ -1231,7 +1246,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
<< (TagType == DeclSpec::TST_class? 0
: TagType == DeclSpec::TST_struct? 1
- : TagType == DeclSpec::TST_interface? 2
+ : TagType == DeclSpec::TST_union? 2
: 3)
<< Name
<< SourceRange(LAngleLoc, RAngleLoc);
@@ -1272,10 +1287,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Range.setBegin(SS.getBeginLoc());
Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
- << Name << static_cast<int>(TemplateId->Kind) << Range;
+ << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;
DS.SetTypeSpecError();
- SkipUntil(tok::semi, false, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
return;
}
}
@@ -1323,7 +1338,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Skip everything up to the semicolon, so that this looks like a proper
// friend class (or template thereof) declaration.
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
TUK = Sema::TUK_Friend;
} else {
// Okay, this is a class definition.
@@ -1342,12 +1357,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
while (true) {
if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
ConsumeBracket();
- if (!SkipUntil(tok::r_square))
+ if (!SkipUntil(tok::r_square, StopAtSemi))
break;
} else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) {
ConsumeToken();
ConsumeParen();
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
break;
} else {
break;
@@ -1412,7 +1427,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
<< DeclSpec::getSpecifierName(TagType);
}
- SkipUntil(tok::comma, true);
+ SkipUntil(tok::comma, StopAtSemi);
return;
}
@@ -1465,7 +1480,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// This is an explicit specialization or a class template
// partial specialization.
TemplateParameterLists FakedParamLists;
-
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
// This looks like an explicit instantiation, because we have
// something like
@@ -1475,25 +1489,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// but it actually has a definition. Most likely, this was
// meant to be an explicit specialization, but the user forgot
// the '<>' after 'template'.
- assert(TUK == Sema::TUK_Definition && "Expected a definition here");
-
- SourceLocation LAngleLoc
- = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
- Diag(TemplateId->TemplateNameLoc,
- diag::err_explicit_instantiation_with_definition)
- << SourceRange(TemplateInfo.TemplateLoc)
- << FixItHint::CreateInsertion(LAngleLoc, "<>");
-
- // Create a fake template parameter list that contains only
- // "template<>", so that we treat this construct as a class
- // template specialization.
- FakedParamLists.push_back(
- Actions.ActOnTemplateParameterList(0, SourceLocation(),
- TemplateInfo.TemplateLoc,
- LAngleLoc,
- 0, 0,
- LAngleLoc));
- TemplateParams = &FakedParamLists;
+ // It this is friend declaration however, since it cannot have a
+ // template header, it is most likely that the user meant to
+ // remove the 'template' keyword.
+ assert((TUK == Sema::TUK_Definition || TUK == Sema::TUK_Friend) &&
+ "Expected a definition here");
+
+ if (TUK == Sema::TUK_Friend) {
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation);
+ TemplateParams = 0;
+ } else {
+ SourceLocation LAngleLoc =
+ PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Create a fake template parameter list that contains only
+ // "template<>", so that we treat this construct as a class
+ // template specialization.
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
+ LAngleLoc));
+ TemplateParams = &FakedParamLists;
+ }
}
// Build the class template specialization.
@@ -1540,6 +1560,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
ProhibitAttributes(attrs);
+ if (TUK == Sema::TUK_Definition &&
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ // If the declarator-id is not a template-id, issue a diagnostic and
+ // recover by ignoring the 'template' keyword.
+ Diag(Tok, diag::err_template_defn_explicit_instantiation)
+ << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
+ TemplateParams = 0;
+ }
+
bool IsDependent = false;
// Don't pass down template parameter lists if this is just a tag
@@ -1641,7 +1670,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
if (Result.isInvalid()) {
// Skip the rest of this base specifier, up until the comma or
// opening brace.
- SkipUntil(tok::comma, tok::l_brace, true, true);
+ SkipUntil(tok::comma, tok::l_brace, StopAtSemi | StopBeforeMatch);
} else {
// Add this to our array of base specifiers.
BaseInfo.push_back(Result.get());
@@ -1800,12 +1829,17 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
// Initialize the contextual keywords.
if (!Ident_final) {
Ident_final = &PP.getIdentifierTable().get("final");
+ if (getLangOpts().MicrosoftExt)
+ Ident_sealed = &PP.getIdentifierTable().get("sealed");
Ident_override = &PP.getIdentifierTable().get("override");
}
if (II == Ident_override)
return VirtSpecifiers::VS_Override;
+ if (II == Ident_sealed)
+ return VirtSpecifiers::VS_Sealed;
+
if (II == Ident_final)
return VirtSpecifiers::VS_Final;
}
@@ -1833,14 +1867,18 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
<< PrevSpec
<< FixItHint::CreateRemoval(Tok.getLocation());
- if (IsInterface && Specifier == VirtSpecifiers::VS_Final) {
+ if (IsInterface && (Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_Sealed)) {
Diag(Tok.getLocation(), diag::err_override_control_interface)
<< VirtSpecifiers::getSpecifierName(Specifier);
+ } else if (Specifier == VirtSpecifiers::VS_Sealed) {
+ Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword);
} else {
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword)
- << VirtSpecifiers::getSpecifierName(Specifier);
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_override_control_keyword
+ : diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
}
ConsumeToken();
}
@@ -1858,10 +1896,13 @@ bool Parser::isCXX11FinalKeyword() const {
// Initialize the contextual keywords.
if (!Ident_final) {
Ident_final = &PP.getIdentifierTable().get("final");
+ if (getLangOpts().MicrosoftExt)
+ Ident_sealed = &PP.getIdentifierTable().get("sealed");
Ident_override = &PP.getIdentifierTable().get("override");
}
-
- return Tok.getIdentifierInfo() == Ident_final;
+
+ return Tok.getIdentifierInfo() == Ident_final ||
+ Tok.getIdentifierInfo() == Ident_sealed;
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -1892,6 +1933,7 @@ bool Parser::isCXX11FinalKeyword() const {
/// virt-specifier:
/// override
/// final
+/// [MS] sealed
///
/// pure-specifier:
/// '= 0'
@@ -1908,12 +1950,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Diag(Tok, diag::err_at_defs_cxx);
else
Diag(Tok, diag::err_at_in_class);
-
+
ConsumeToken();
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
return;
}
-
+
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
@@ -1952,10 +1994,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
Actions.ActOnUsingDeclaration(getCurScope(), AS,
- false, SourceLocation(),
+ /* HasUsingKeyword */ false,
+ SourceLocation(),
SS, Name,
/* AttrList */ 0,
- /* IsTypeName */ false,
+ /* HasTypenameKeyword */ false,
SourceLocation());
return;
}
@@ -2010,7 +2053,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
} else {
SourceLocation DeclEnd;
// Otherwise, it must be a using-declaration or an alias-declaration.
@@ -2032,6 +2075,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
&CommonLateParsedAttrs);
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
+ &CommonLateParsedAttrs))
+ return;
+
MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
@@ -2066,7 +2117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
// If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
return;
@@ -2085,7 +2136,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
EqualLoc = ConsumeToken();
Init = ParseInitializer();
if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
else
HasInitializer = true;
}
@@ -2123,7 +2174,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);
ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi*/false);
+ SkipUntil(tok::r_brace);
// Consume the optional ';'
if (Tok.is(tok::semi))
@@ -2143,11 +2194,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
VS, DefinitionKind, Init);
- for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
- CommonLateParsedAttrs[i]->addDecl(FunDecl);
- }
- for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
- LateParsedAttrs[i]->addDecl(FunDecl);
+ if (FunDecl) {
+ for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
+ CommonLateParsedAttrs[i]->addDecl(FunDecl);
+ }
+ for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
+ LateParsedAttrs[i]->addDecl(FunDecl);
+ }
}
LateParsedAttrs.clear();
@@ -2176,7 +2229,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ConsumeToken();
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
}
// If a simple-asm-expr is present, parse it.
@@ -2184,7 +2237,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid())
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
DeclaratorInfo.setAsmLabel(AsmLabel.release());
DeclaratorInfo.SetRangeEnd(Loc);
@@ -2201,7 +2254,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
if (BitfieldSize.get()) {
Diag(Tok, diag::err_bitfield_member_init);
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
} else {
HasInitializer = true;
if (!DeclaratorInfo.isDeclarationOfFunction() &&
@@ -2225,7 +2278,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SmallVector<SourceRange, 4> Ranges;
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
if (!Ranges.empty()) {
- for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(),
+ for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
E = Ranges.end(); I != E; ++I) {
Diag((*I).getBegin(), diag::err_attributes_not_allowed)
<< *I;
@@ -2241,28 +2294,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
TemplateParams,
BitfieldSize.release(),
VS, HasInClassInit);
- if (AccessAttrs)
- Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs,
- false, true);
- }
-
- // Set the Decl for any late parsed attributes
- for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
- CommonLateParsedAttrs[i]->addDecl(ThisDecl);
- }
- for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
- LateParsedAttrs[i]->addDecl(ThisDecl);
+
+ if (VarTemplateDecl *VT =
+ ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0)
+ // Re-direct this decl to refer to the templated decl so that we can
+ // initialize it.
+ ThisDecl = VT->getTemplatedDecl();
+
+ if (ThisDecl && AccessAttrs)
+ Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs);
}
- LateParsedAttrs.clear();
// Handle the initializer.
if (HasInClassInit != ICIS_NoInit &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
DeclSpec::SCS_static) {
// The initializer was deferred; parse it and cache the tokens.
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_nonstatic_member_init :
- diag::ext_nonstatic_member_init);
+ Diag(Tok, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_nonstatic_member_init
+ : diag::ext_nonstatic_member_init);
if (DeclaratorInfo.isArrayOfUnknownBound()) {
// C++11 [dcl.array]p3: An array bound may also be omitted when the
@@ -2271,38 +2321,46 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// A brace-or-equal-initializer for a member-declarator is not an
// initializer in the grammar, so this is ill-formed.
Diag(Tok, diag::err_incomplete_array_member_init);
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+
+ // Avoid later warnings about a class member of incomplete type.
if (ThisDecl)
- // Avoid later warnings about a class member of incomplete type.
ThisDecl->setInvalidDecl();
} else
ParseCXXNonStaticMemberInitializer(ThisDecl);
} else if (HasInitializer) {
// Normal initializer.
if (!Init.isUsable())
- Init = ParseCXXMemberInitializer(ThisDecl,
- DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
-
+ Init = ParseCXXMemberInitializer(
+ ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
+
if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
else if (ThisDecl)
Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(),
DS.containsPlaceholderType());
- } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static)
// No initializer.
Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType());
- }
-
+
if (ThisDecl) {
+ if (!ThisDecl->isInvalidDecl()) {
+ // Set the Decl for any late parsed attributes
+ for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i)
+ CommonLateParsedAttrs[i]->addDecl(ThisDecl);
+
+ for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i)
+ LateParsedAttrs[i]->addDecl(ThisDecl);
+ }
Actions.FinalizeDeclaration(ThisDecl);
DeclsInGroup.push_back(ThisDecl);
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
+ DeclSpec::SCS_typedef)
+ HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl);
}
-
- if (ThisDecl && DeclaratorInfo.isFunctionDeclarator() &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_typedef) {
- HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl);
- }
+ LateParsedAttrs.clear();
DeclaratorInfo.complete(ThisDecl);
@@ -2343,14 +2401,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (ExpectSemi &&
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
// Skip to end of block or statement.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
// If we stopped at a ';', eat it.
if (Tok.is(tok::semi)) ConsumeToken();
return;
}
- Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(),
- DeclsInGroup.size());
+ Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
}
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
@@ -2369,7 +2426,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
/// assignment-expression
/// braced-init-list
///
-/// defaulted/deleted function-definition:
+/// defaulted/deleted function-definition:
/// '=' 'default'
/// '=' 'delete'
///
@@ -2476,20 +2533,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
SourceLocation FinalLoc;
+ bool IsFinalSpelledSealed = false;
// Parse the optional 'final' keyword.
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
- assert(isCXX11FinalKeyword() && "not a class definition");
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok);
+ assert((Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_Sealed) &&
+ "not a class definition");
FinalLoc = ConsumeToken();
+ IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed;
- if (TagType == DeclSpec::TST_interface) {
+ if (TagType == DeclSpec::TST_interface)
Diag(FinalLoc, diag::err_override_control_interface)
- << "final";
- } else {
- Diag(FinalLoc, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword) << "final";
- }
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ else if (Specifier == VirtSpecifiers::VS_Final)
+ Diag(FinalLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_override_control_keyword
+ : diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ else if (Specifier == VirtSpecifiers::VS_Sealed)
+ Diag(FinalLoc, diag::ext_ms_sealed_keyword);
// Parse any C++11 attributes after 'final' keyword.
// These attributes are not allowed to appear here,
@@ -2516,6 +2580,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl)
Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc,
+ IsFinalSpelledSealed,
T.getOpenLocation());
// C++ 11p3: Members of a class defined with the keyword class are private
@@ -2565,6 +2630,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ // If we see a namespace here, a close brace was missing somewhere.
+ if (Tok.is(tok::kw_namespace)) {
+ DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
+ break;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2606,15 +2677,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
- // FIXME: Make sure we don't have a template here.
-
// Parse all the comma separated declarators.
ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
}
T.consumeClose();
} else {
- SkipUntil(tok::r_brace, false, false);
+ SkipUntil(tok::r_brace);
}
// If attributes exist after class contents, parse them.
@@ -2658,6 +2727,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ClassScope.Exit();
}
+void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) {
+ assert(Tok.is(tok::kw_namespace));
+
+ // FIXME: Suggest where the close brace should have gone by looking
+ // at indentation changes within the definition body.
+ Diag(D->getLocation(),
+ diag::err_missing_end_of_definition) << D;
+ Diag(Tok.getLocation(),
+ diag::note_missing_end_of_definition_before) << D;
+
+ // Push '};' onto the token stream to recover.
+ PP.EnterToken(Tok);
+
+ Tok.startToken();
+ Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation));
+ Tok.setKind(tok::semi);
+ PP.EnterToken(Tok);
+
+ Tok.setKind(tok::r_brace);
+}
+
/// ParseConstructorInitializer - Parse a C++ constructor initializer,
/// which explicitly initializes the members or base classes of a
/// class (C++ [class.base.init]). For example, the three initializers
@@ -2691,9 +2781,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
do {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
- MemInitializers.data(),
- MemInitializers.size());
+ Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
+ MemInitializers);
return cutOffParsing();
} else {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
@@ -2716,7 +2805,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
} else {
// Skip over garbage, until we get to '{'. Don't eat the '{'.
Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
- SkipUntil(tok::l_brace, true, true);
+ SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
break;
}
} while (true);
@@ -2797,7 +2886,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return true;
}
@@ -2809,9 +2898,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
- T.getOpenLocation(), ArgExprs.data(),
- ArgExprs.size(), T.getCloseLocation(),
- EllipsisLoc);
+ T.getOpenLocation(), ArgExprs,
+ T.getCloseLocation(), EllipsisLoc);
}
Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace
@@ -2894,6 +2982,16 @@ Parser::tryParseExceptionSpecification(
return Result;
}
+static void diagnoseDynamicExceptionSpecification(
+ Parser &P, const SourceRange &Range, bool IsNoexcept) {
+ if (P.getLangOpts().CPlusPlus11) {
+ const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)";
+ P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range;
+ P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated)
+ << Replacement << FixItHint::CreateReplacement(Range, Replacement);
+ }
+}
+
/// ParseDynamicExceptionSpecification - Parse a C++
/// dynamic-exception-specification (C++ [except.spec]).
///
@@ -2927,6 +3025,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
T.consumeClose();
SpecificationRange.setEnd(T.getCloseLocation());
+ diagnoseDynamicExceptionSpecification(*this, SpecificationRange, false);
return EST_MSAny;
}
@@ -2958,6 +3057,8 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
T.consumeClose();
SpecificationRange.setEnd(T.getCloseLocation());
+ diagnoseDynamicExceptionSpecification(*this, SpecificationRange,
+ Exceptions.empty());
return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
}
@@ -3167,7 +3268,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
if (!AttrName) {
Diag(Tok.getLocation(), diag::err_expected_ident);
- SkipUntil(tok::r_square, tok::comma, true, true);
+ SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch);
continue;
}
}
@@ -3193,7 +3294,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
// FIXME: handle other formats of c++11 attribute arguments
ConsumeParen();
- SkipUntil(tok::r_paren, false);
+ SkipUntil(tok::r_paren);
}
}
@@ -3201,8 +3302,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
attrs.addNew(AttrName,
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
AttrLoc),
- ScopeName, ScopeLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_CXX11);
+ ScopeName, ScopeLoc, 0, 0, AttributeList::AS_CXX11);
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
@@ -3213,11 +3313,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
}
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
- SkipUntil(tok::r_square, false);
+ SkipUntil(tok::r_square);
if (endLoc)
*endLoc = Tok.getLocation();
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
- SkipUntil(tok::r_square, false);
+ SkipUntil(tok::r_square);
}
/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq.
@@ -3239,6 +3339,37 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
attrs.Range = SourceRange(StartLoc, *endLoc);
}
+void Parser::DiagnoseAndSkipCXX11Attributes() {
+ if (!isCXX11AttributeSpecifier())
+ return;
+
+ // Start and end location of an attribute or an attribute list.
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+
+ do {
+ if (Tok.is(tok::l_square)) {
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ T.skipToEnd();
+ EndLoc = T.getCloseLocation();
+ } else {
+ assert(Tok.is(tok::kw_alignas) && "not an attribute specifier");
+ ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (!T.consumeOpen())
+ T.skipToEnd();
+ EndLoc = T.getCloseLocation();
+ }
+ } while (isCXX11AttributeSpecifier());
+
+ if (EndLoc.isValid()) {
+ SourceRange Range(StartLoc, EndLoc);
+ Diag(StartLoc, diag::err_attributes_not_allowed)
+ << Range;
+ }
+}
+
/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr]
///
/// [MS] ms-attribute:
@@ -3254,7 +3385,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
while (Tok.is(tok::l_square)) {
// FIXME: If this is actually a C++11 attribute, parse it as one.
ConsumeBracket();
- SkipUntil(tok::r_square, true, true);
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
if (endLoc) *endLoc = Tok.getLocation();
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare);
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 9521ffbc0e3f..45f1b1da2e7f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -389,7 +389,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// parentheses so that the code remains well-formed in C++0x.
if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
SuggestParentheses(OpToken.getLocation(),
- diag::warn_cxx0x_right_shift_in_template_arg,
+ diag::warn_cxx11_right_shift_in_template_arg,
SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
Actions.getExprRange(RHS.get()).getEnd()));
@@ -491,6 +491,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
/// [C11] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
+/// [MS] '__FUNCDNAME__'
+/// [MS] 'L__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
/// [GNU] '(' compound-statement ')'
/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
@@ -591,6 +593,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
/// '__is_final'
/// '__is_pod'
/// '__is_polymorphic'
+/// '__is_sealed' [MS]
/// '__is_trivial'
/// '__is_union'
///
@@ -741,19 +744,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
REVERTABLE_TYPE_TRAIT(__is_void);
#undef REVERTABLE_TYPE_TRAIT
#undef RTT_JOIN
- }
+ }
- // If we find that this is in fact the name of a type trait,
- // update the token kind in place and parse again to treat it as
- // the appropriate kind of type trait.
- llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
- = RevertableTypeTraits.find(II);
- if (Known != RevertableTypeTraits.end()) {
- Tok.setKind(Known->second);
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
- }
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
+ = RevertableTypeTraits.find(II);
+ if (Known != RevertableTypeTraits.end()) {
+ Tok.setKind(Known->second);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
}
+ }
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
@@ -869,6 +872,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
+ case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
@@ -888,6 +892,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
+ case tok::kw___builtin_convertvector:
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
@@ -1042,12 +1047,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// typename-specifier braced-init-list
if (TryAnnotateTypeOrScopeToken())
return ExprError();
+
+ if (!Actions.isSimpleTypeSpecifier(Tok.getKind()))
+ // We are trying to parse a simple-type-specifier but might not get such
+ // a token after error recovery.
+ return ExprError();
}
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
// simple-type-specifier braced-init-list
//
DeclSpec DS(AttrFactory);
+
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren) &&
(!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
@@ -1193,6 +1204,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___is_final:
+ case tok::kw___is_sealed:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_move_constructor:
case tok::kw___has_trivial_copy:
@@ -1371,7 +1383,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CommaLocsTy ExecConfigCommaLocs;
SourceLocation OpenLoc = ConsumeToken();
- if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
+ if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
LHS = ExprError();
}
@@ -1379,12 +1391,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.is(tok::greatergreatergreater)) {
ConsumeToken();
} else if (LHS.isInvalid()) {
- SkipUntil(tok::greatergreatergreater);
+ SkipUntil(tok::greatergreatergreater, StopAtSemi);
} else {
// There was an error closing the brackets
Diag(Tok, diag::err_expected_ggg);
Diag(OpenLoc, diag::note_matching) << "<<<";
- SkipUntil(tok::greatergreatergreater);
+ SkipUntil(tok::greatergreatergreater, StopAtSemi);
LHS = ExprError();
}
@@ -1430,7 +1442,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// Match the ')'.
if (LHS.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
} else if (Tok.isNot(tok::r_paren)) {
PT.consumeClose();
LHS = ExprError();
@@ -1457,7 +1469,18 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
- LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(),
+ Expr *Base = LHS.take();
+ const Type* BaseType = Base->getType().getTypePtrOrNull();
+ if (BaseType && Tok.is(tok::l_paren) &&
+ (BaseType->isFunctionType() ||
+ BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) {
+ Diag(OpLoc, diag::err_function_is_not_record)
+ << (OpKind == tok::arrow) << Base->getSourceRange()
+ << FixItHint::CreateRemoval(OpLoc);
+ return ParsePostfixExpressionSuffix(Base);
+ }
+
+ LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base,
OpLoc, OpKind, ObjectType,
MayBePseudoDestructor);
if (LHS.isInvalid())
@@ -1570,6 +1593,28 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
// If the operand doesn't start with an '(', it must be an expression.
if (Tok.isNot(tok::l_paren)) {
+ // If construct allows a form without parenthesis, user may forget to put
+ // pathenthesis around type name.
+ if (OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) ||
+ OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) {
+ bool isAmbiguousTypeId;
+ if (isTypeIdInParens(isAmbiguousTypeId)) {
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS);
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation());
+ SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ Diag(LParenLoc, diag::err_expected_parentheses_around_typename)
+ << OpTok.getName()
+ << FixItHint::CreateInsertion(LParenLoc, "(")
+ << FixItHint::CreateInsertion(RParenLoc, ")");
+ isCastExpr = true;
+ return ExprEmpty();
+ }
+ }
+
isCastExpr = false;
if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
@@ -1651,7 +1696,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
RParenLoc = PP.getLocForEndOfToken(NameLoc);
} else {
Diag(Tok, diag::err_expected_parameter_pack);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
}
} else if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
@@ -1669,6 +1714,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (!Name)
return ExprError();
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
+
return Actions.ActOnSizeofParameterPackExpr(getCurScope(),
OpTok.getLocation(),
*Name, NameLoc,
@@ -1774,7 +1822,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SourceLocation TypeLoc = Tok.getLocation();
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1784,7 +1832,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// We must have at least one identifier here.
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1806,7 +1854,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
@@ -1824,7 +1872,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().LocStart = ST.getOpenLocation();
Res = ParseExpression();
if (Res.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return Res;
}
Comps.back().U.E = Res.release();
@@ -1851,7 +1899,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
case tok::kw___builtin_choose_expr: {
ExprResult Cond(ParseAssignmentExpression());
if (Cond.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return Cond;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
@@ -1859,7 +1907,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr1(ParseAssignmentExpression());
if (Expr1.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return Expr1;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
@@ -1867,7 +1915,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr2(ParseAssignmentExpression());
if (Expr2.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return Expr2;
}
if (Tok.isNot(tok::r_paren)) {
@@ -1882,7 +1930,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// The first argument is an expression to be converted, followed by a comma.
ExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1898,7 +1946,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// Attempt to consume the r-paren.
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1906,6 +1954,34 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ConsumeParen());
break;
}
+ case tok::kw___builtin_convertvector: {
+ // The first argument is an expression to be converted, followed by a comma.
+ ExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",
+ tok::r_paren))
+ return ExprError();
+
+ // Second argument is the type to bitcast to.
+ TypeResult DestTy = ParseTypeName();
+ if (DestTy.isInvalid())
+ return ExprError();
+
+ // Attempt to consume the r-paren.
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return ExprError();
+ }
+
+ Res = Actions.ActOnConvertVectorExpr(Expr.take(), DestTy.get(), StartLoc,
+ ConsumeParen());
+ break;
+ }
}
if (Res.isInvalid())
@@ -2129,7 +2205,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
ExprVector ArgExprs;
CommaLocsTy CommaLocs;
- if (!ParseExpressionList(ArgExprs, CommaLocs)) {
+ if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
ArgExprs);
@@ -2147,7 +2223,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Match the ')'.
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2233,13 +2309,13 @@ ExprResult Parser::ParseGenericSelectionExpression() {
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ControllingExpr = ParseAssignmentExpression();
if (ControllingExpr.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2254,7 +2330,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
if (!DefaultLoc.isInvalid()) {
Diag(Tok, diag::err_duplicate_default_assoc);
Diag(DefaultLoc, diag::note_previous_default_assoc);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
DefaultLoc = ConsumeToken();
@@ -2263,7 +2339,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
ColonProtectionRAIIObject X(*this);
TypeResult TR = ParseTypeName();
if (TR.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
Ty = TR.release();
@@ -2271,7 +2347,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
Types.push_back(Ty);
if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2279,7 +2355,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
// evaluated context.
ExprResult ER(ParseAssignmentExpression());
if (ER.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
Exprs.push_back(ER.release());
@@ -2358,6 +2434,32 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
}
+/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
+/// used for misc language extensions.
+///
+/// \verbatim
+/// simple-expression-list:
+/// assignment-expression
+/// simple-expression-list , assignment-expression
+/// \endverbatim
+bool
+Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
+ SmallVectorImpl<SourceLocation> &CommaLocs) {
+ while (1) {
+ ExprResult Expr = ParseAssignmentExpression();
+ if (Expr.isInvalid())
+ return true;
+
+ Exprs.push_back(Expr.release());
+
+ if (Tok.isNot(tok::comma))
+ return false;
+
+ // Move to the next argument, remember where the comma was.
+ CommaLocs.push_back(ConsumeToken());
+ }
+}
+
/// ParseBlockId - Parse a block-id, which roughly looks like int (int x).
///
/// \verbatim
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index f259d5f59b48..5fe47fc9711c 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -10,7 +10,7 @@
// This file implements the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
-
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Basic/PrettyStackTrace.h"
@@ -21,6 +21,7 @@
#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
+
using namespace clang;
static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
@@ -195,6 +196,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (Tok.is(tok::annot_template_id)) {
+ // If the current token is an annotated template id, it may already have
+ // a scope specifier. Restore it.
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ SS = TemplateId->SS;
+ }
+
if (LastII)
*LastII = 0;
@@ -465,8 +473,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TemplateName, false))
return true;
continue;
- }
-
+ }
+
if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
(IsTypename || IsTemplateArgumentList(1))) {
// We have something like t::getAs<T>, where getAs is a
@@ -583,7 +591,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
Tok.is(tok::l_paren), isAddressOfOperand);
}
-/// ParseLambdaExpression - Parse a C++0x lambda expression.
+/// ParseLambdaExpression - Parse a C++11 lambda expression.
///
/// lambda-expression:
/// lambda-introducer lambda-declarator[opt] compound-statement
@@ -605,10 +613,18 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/// capture-list ',' capture
///
/// capture:
+/// simple-capture
+/// init-capture [C++1y]
+///
+/// simple-capture:
/// identifier
/// '&' identifier
/// 'this'
///
+/// init-capture: [C++1y]
+/// identifier initializer
+/// '&' identifier initializer
+///
/// lambda-declarator:
/// '(' parameter-declaration-clause ')' attribute-specifier[opt]
/// 'mutable'[opt] exception-specification[opt]
@@ -617,13 +633,12 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
LambdaIntroducer Intro;
-
- Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro);
if (DiagID) {
Diag(Tok, DiagID.getValue());
- SkipUntil(tok::r_square);
- SkipUntil(tok::l_brace);
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_square, StopAtSemi);
+ SkipUntil(tok::l_brace, StopAtSemi);
+ SkipUntil(tok::r_brace, StopAtSemi);
return ExprError();
}
@@ -658,7 +673,7 @@ ExprResult Parser::TryParseLambdaExpression() {
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
return ExprEmpty();
}
-
+
// Here, we're stuck: lambda introducers and Objective-C message sends are
// unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a
// lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of
@@ -668,13 +683,21 @@ ExprResult Parser::TryParseLambdaExpression() {
LambdaIntroducer Intro;
if (TryParseLambdaIntroducer(Intro))
return ExprEmpty();
+
return ParseLambdaExpressionAfterIntroducer(Intro);
}
-/// ParseLambdaExpression - Parse a lambda introducer.
-///
-/// Returns a DiagnosticID if it hit something unexpected.
-Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
+/// \brief Parse a lambda introducer.
+/// \param Intro A LambdaIntroducer filled in with information about the
+/// contents of the lambda-introducer.
+/// \param SkippedInits If non-null, we are disambiguating between an Obj-C
+/// message send and a lambda expression. In this mode, we will
+/// sometimes skip the initializers for init-captures and not fully
+/// populate \p Intro. This flag will be set to \c true if we do so.
+/// \return A DiagnosticID if it hit something unexpected. The location for
+/// for the diagnostic is that of the current token.
+Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
+ bool *SkippedInits) {
typedef Optional<unsigned> DiagResult;
assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
@@ -737,6 +760,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
SourceLocation Loc;
IdentifierInfo* Id = 0;
SourceLocation EllipsisLoc;
+ ExprResult Init;
if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
@@ -757,9 +781,6 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
-
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
// FIXME: If we want to suggest a fixit here, will need to return more
// than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
@@ -768,14 +789,139 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
} else {
return DiagResult(diag::err_expected_capture);
}
- }
- Intro.addCapture(Kind, Loc, Id, EllipsisLoc);
+ if (Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+
+ ExprVector Exprs;
+ CommaLocsTy Commas;
+ if (SkippedInits) {
+ Parens.skipToEnd();
+ *SkippedInits = true;
+ } else if (ParseExpressionList(Exprs, Commas)) {
+ Parens.skipToEnd();
+ Init = ExprError();
+ } else {
+ Parens.consumeClose();
+ Init = Actions.ActOnParenListExpr(Parens.getOpenLocation(),
+ Parens.getCloseLocation(),
+ Exprs);
+ }
+ } else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) {
+ // 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);
+ if (Tok.is(tok::equal))
+ ConsumeToken();
+
+ if (!SkippedInits)
+ Init = ParseInitializer();
+ else if (Tok.is(tok::l_brace)) {
+ BalancedDelimiterTracker Braces(*this, tok::l_brace);
+ Braces.consumeOpen();
+ Braces.skipToEnd();
+ *SkippedInits = true;
+ } else {
+ // We're disambiguating this:
+ //
+ // [..., x = expr
+ //
+ // We need to find the end of the following expression in order to
+ // determine whether this is an Obj-C message send's receiver, or a
+ // lambda init-capture.
+ //
+ // Parse the expression to find where it ends, and annotate it back
+ // onto the tokens. We would have parsed this expression the same way
+ // in either case: both the RHS of an init-capture and the RHS of an
+ // assignment expression are parsed as an initializer-clause, and in
+ // neither case can anything be added to the scope between the '[' and
+ // here.
+ //
+ // FIXME: This is horrible. Adding a mechanism to skip an expression
+ // would be much cleaner.
+ // FIXME: If there is a ',' before the next ']' or ':', we can skip to
+ // that instead. (And if we see a ':' with no matching '?', we can
+ // classify this as an Obj-C message send.)
+ SourceLocation StartLoc = Tok.getLocation();
+ InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true);
+ Init = ParseInitializer();
+
+ if (Tok.getLocation() != StartLoc) {
+ // Back out the lexing of the token after the initializer.
+ PP.RevertCachedTokens(1);
+
+ // Replace the consumed tokens with an appropriate annotation.
+ Tok.setLocation(StartLoc);
+ Tok.setKind(tok::annot_primary_expr);
+ setExprAnnotation(Tok, Init);
+ Tok.setAnnotationEndLoc(PP.getLastCachedTokenLocation());
+ PP.AnnotateCachedTokens(Tok);
+
+ // Consume the annotated initializer.
+ ConsumeToken();
+ }
+ }
+ } else if (Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
+ }
+ // If this is an init capture, process the initialization expression
+ // right away. For lambda init-captures such as the following:
+ // const int x = 10;
+ // auto L = [i = x+1](int a) {
+ // return [j = x+2,
+ // &k = x](char b) { };
+ // };
+ // keep in mind that each lambda init-capture has to have:
+ // - its initialization expression executed in the context
+ // of the enclosing/parent decl-context.
+ // - but the variable itself has to be 'injected' into the
+ // decl-context of its lambda's call-operator (which has
+ // not yet been created).
+ // Each init-expression is a full-expression that has to get
+ // Sema-analyzed (for capturing etc.) before its lambda's
+ // call-operator's decl-context, scope & scopeinfo are pushed on their
+ // respective stacks. Thus if any variable is odr-used in the init-capture
+ // it will correctly get captured in the enclosing lambda, if one exists.
+ // The init-variables above are created later once the lambdascope and
+ // call-operators decl-context is pushed onto its respective stack.
+
+ // Since the lambda init-capture's initializer expression occurs in the
+ // context of the enclosing function or lambda, therefore we can not wait
+ // till a lambda scope has been pushed on before deciding whether the
+ // variable needs to be captured. We also need to process all
+ // lvalue-to-rvalue conversions and discarded-value conversions,
+ // so that we can avoid capturing certain constant variables.
+ // For e.g.,
+ // void test() {
+ // const int x = 10;
+ // auto L = [&z = x](char a) { <-- don't capture by the current lambda
+ // return [y = x](int i) { <-- don't capture by enclosing lambda
+ // return y;
+ // }
+ // };
+ // If x was not const, the second use would require 'L' to capture, and
+ // that would be an error.
+
+ ParsedType InitCaptureParsedType;
+ if (Init.isUsable()) {
+ // Get the pointer and store it in an lvalue, so we can use it as an
+ // out argument.
+ Expr *InitExpr = Init.get();
+ // This performs any lvalue-to-rvalue conversions if necessary, which
+ // can affect what gets captured in the containing decl-context.
+ QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization(
+ Loc, Kind == LCK_ByRef, Id, InitExpr);
+ Init = InitExpr;
+ InitCaptureParsedType.set(InitCaptureType);
+ }
+ Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType);
}
T.consumeClose();
Intro.Range.setEnd(T.getCloseLocation());
-
return DiagResult();
}
@@ -785,13 +931,23 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
TentativeParsingAction PA(*this);
- Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ bool SkippedInits = false;
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits));
if (DiagID) {
PA.Revert();
return true;
}
+ if (SkippedInits) {
+ // Parse it again, but this time parse the init-captures too.
+ PA.Revert();
+ Intro = LambdaIntroducer();
+ DiagID = ParseLambdaIntroducer(Intro);
+ assert(!DiagID && "parsing lambda-introducer failed on reparse");
+ return false;
+ }
+
PA.Commit();
return false;
}
@@ -806,9 +962,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing");
+
+
+ // FIXME: Call into Actions to add any init-capture declarations to the
+ // scope while parsing the lambda-declarator and compound-statement.
+
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::LambdaExprContext);
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+ Actions.PushLambdaScope();
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -826,9 +989,15 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
- if (Tok.isNot(tok::r_paren))
+
+ if (Tok.isNot(tok::r_paren)) {
+ Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
-
+ // For a generic lambda, each 'auto' within the parameter declaration
+ // clause creates a template type parameter, so increment the depth.
+ if (Actions.getCurGenericLambda())
+ ++CurTemplateDepthTracker;
+ }
T.consumeClose();
SourceLocation RParenLoc = T.getCloseLocation();
DeclEndLoc = RParenLoc;
@@ -1089,7 +1258,7 @@ ExprResult Parser::ParseCXXTypeid() {
// Match the ')'.
if (Result.isInvalid())
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
else {
T.consumeClose();
RParenLoc = T.getCloseLocation();
@@ -1139,7 +1308,7 @@ ExprResult Parser::ParseCXXUuidof() {
// Match the ')'.
if (Result.isInvalid())
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
else {
T.consumeClose();
@@ -1325,7 +1494,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(Exprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
}
@@ -1411,7 +1580,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
- SkipUntil(tok::semi);
+ SkipUntil(tok::semi, StopAtSemi);
return true;
}
DeclaratorInfo.setAsmLabel(AsmLabel.release());
@@ -1443,7 +1612,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
} else if (Tok.is(tok::l_paren)) {
// This was probably an attempt to initialize the variable.
SourceLocation LParen = ConsumeParen(), RParen = LParen;
- if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true))
+ if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch))
RParen = ConsumeParen();
Diag(DeclOut ? DeclOut->getLocation() : LParen,
diag::err_expected_init_in_condition_lparen)
@@ -2303,14 +2472,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
T.consumeOpen();
PlacementLParen = T.getOpenLocation();
if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
- SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
T.consumeClose();
PlacementRParen = T.getCloseLocation();
if (PlacementRParen.isInvalid()) {
- SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
@@ -2353,7 +2522,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
}
}
if (DeclaratorInfo.isInvalidType()) {
- SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
@@ -2368,14 +2537,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (Tok.isNot(tok::r_paren)) {
CommaLocsTy CommaLocs;
if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
- SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
}
T.consumeClose();
ConstructorRParen = T.getCloseLocation();
if (ConstructorRParen.isInvalid()) {
- SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
return ExprError();
}
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
@@ -2416,7 +2585,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
: ParseConstantExpression());
if (Size.isInvalid()) {
// Recover
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return;
}
first = false;
@@ -2553,6 +2722,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_reference: return UTT_IsReference;
case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference;
case tok::kw___is_scalar: return UTT_IsScalar;
+ case tok::kw___is_sealed: return UTT_IsSealed;
case tok::kw___is_signed: return UTT_IsSigned;
case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
case tok::kw___is_trivial: return UTT_IsTrivial;
@@ -2645,18 +2815,18 @@ ExprResult Parser::ParseBinaryTypeTrait() {
TypeResult LhsTy = ParseTypeName();
if (LhsTy.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
TypeResult RhsTy = ParseTypeName();
if (RhsTy.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2735,8 +2905,8 @@ ExprResult Parser::ParseArrayTypeTrait() {
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
- SkipUntil(tok::comma);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::comma, StopAtSemi);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2748,7 +2918,7 @@ ExprResult Parser::ParseArrayTypeTrait() {
}
case ATT_ArrayExtent: {
if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2905,7 +3075,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Match the ')'.
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 8311aa22075e..37f74bbcd51b 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -244,7 +244,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
bool IsExpr;
void *TypeOrExpr;
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -285,7 +285,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
0);
ConsumeToken(); // the identifier
if (!ReceiverType) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -312,7 +312,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
if (!Idx.get()) {
Idx = ParseAssignmentExpression();
if (Idx.isInvalid()) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return Idx;
}
}
@@ -340,7 +340,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
ExprResult RHS(ParseConstantExpression());
if (RHS.isInvalid()) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return RHS;
}
Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
@@ -457,7 +457,7 @@ ExprResult Parser::ParseBraceInitializer() {
// immediately, it can't be an error, since there is no other way of
// leaving this loop except through this if.
if (Tok.isNot(tok::comma)) {
- SkipUntil(tok::r_brace, false, true);
+ SkipUntil(tok::r_brace, StopBeforeMatch);
break;
}
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 4a572f199328..86f38cfee37a 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -289,6 +289,9 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
LAngleLoc, EndProtoLoc))
return 0;
+ if (Tok.isNot(tok::less))
+ Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
+
Decl *ClsType =
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
superClassId, superClassLoc,
@@ -348,9 +351,10 @@ public:
if (SetterName)
SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
else
- SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(),
- P.PP.getSelectorTable(),
- FD.D.getIdentifier());
+ SetterSel =
+ SelectorTable::constructSetterSelector(P.PP.getIdentifierTable(),
+ P.PP.getSelectorTable(),
+ FD.D.getIdentifier());
bool isOverridingProperty = false;
Decl *Property =
P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc,
@@ -399,7 +403,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// method definitions.
if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
// We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
- SkipUntil(tok::at, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
}
@@ -472,7 +476,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// or something like that.
Diag(AtLoc, diag::err_objc_illegal_interface_qual);
// Skip until we see an '@' or '}' or ';'.
- SkipUntil(tok::r_brace, tok::at);
+ SkipUntil(tok::r_brace, tok::at, StopAtSemi);
break;
case tok::objc_implementation:
@@ -536,10 +540,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(getCurScope(), AtEnd,
- allMethods.data(), allMethods.size(),
- allProperties.data(), allProperties.size(),
- allTUVariables.data(), allTUVariables.size());
+ Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
}
/// Parse property attribute declarations.
@@ -627,7 +628,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
if (!SelIdent) {
Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
<< IsSetter;
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
@@ -645,7 +646,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
}
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
}
@@ -942,7 +943,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
else if (Tok.getLocation() == TypeStartLoc) {
// If we didn't eat any tokens, then this isn't a type.
Diag(Tok, diag::err_expected_type);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
} else {
// Otherwise, we found *something*, but didn't get a ')' in the right
// place. Emit an error then return what we have as the type.
@@ -1019,7 +1020,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Diag(Tok, diag::err_expected_selector_for_method)
<< SourceRange(mLoc, Tok.getLocation());
// Skip until we get a ; or @.
- SkipUntil(tok::at, true /*StopAtSemi*/, true /*don't consume*/);
+ SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
return 0;
}
@@ -1079,9 +1080,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/true,
- ReturnType,
- KeyIdents.data(),
- KeyIdents.size());
+ ReturnType, KeyIdents);
cutOffParsing();
return 0;
}
@@ -1107,9 +1106,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/false,
- ReturnType,
- KeyIdents.data(),
- KeyIdents.size());
+ ReturnType, KeyIdents);
cutOffParsing();
return 0;
}
@@ -1202,7 +1199,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::greater);
+ SkipUntil(tok::greater, StopAtSemi);
return true;
}
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
@@ -1375,7 +1372,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
} else {
Diag(Tok, diag::err_expected_semi_decl_list);
// Skip to end of block or statement
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
}
}
HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
@@ -1537,10 +1534,16 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
- SkipUntil(tok::r_paren, false); // don't stop at ';'
+ SkipUntil(tok::r_paren); // don't stop at ';'
return DeclGroupPtrTy();
}
rparenLoc = ConsumeParen();
+ if (Tok.is(tok::less)) { // we have illegal '<' try to recover
+ Diag(Tok, diag::err_unexpected_protocol_qualifier);
+ AttributeFactory attr;
+ DeclSpec DS(attr);
+ (void)ParseObjCProtocolQualifiers(DS);
+ }
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
AtLoc, nameId, nameLoc, categoryId,
categoryLoc);
@@ -1806,7 +1809,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_rparen);
// Skip forward until we see a left brace, but don't consume it.
- SkipUntil(tok::l_brace, true, true);
+ SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
}
// Require a compound statement.
@@ -1896,7 +1899,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else // Skip over garbage, until we get to ')'. Eat the ')'.
- SkipUntil(tok::r_paren, true, false);
+ SkipUntil(tok::r_paren, StopAtSemi);
StmtResult CatchBody(true);
if (Tok.is(tok::l_brace))
@@ -2029,7 +2032,7 @@ Decl *Parser::ParseObjCMethodDefinition() {
Diag(Tok, diag::err_expected_method_body);
// Skip over garbage, until we get to '{'. Don't eat the '{'.
- SkipUntil(tok::l_brace, true, true);
+ SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
// If we didn't find the '{', bail out.
if (Tok.isNot(tok::l_brace))
@@ -2038,7 +2041,7 @@ Decl *Parser::ParseObjCMethodDefinition() {
if (!MDecl) {
ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi=*/false);
+ SkipUntil(tok::r_brace);
return 0;
}
@@ -2348,7 +2351,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
bool IsExpr;
void *TypeOrExpr = NULL;
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -2376,7 +2379,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
case Sema::ObjCClassMessage:
if (!ReceiverType) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -2394,7 +2397,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
// Otherwise, an arbitrary expression can be the receiver of a send.
ExprResult Res(ParseExpression());
if (Res.isInvalid()) {
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return Res;
}
@@ -2449,14 +2452,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (Tok.is(tok::code_completion)) {
if (SuperLoc.isValid())
- Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0,
+ Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
false);
else if (ReceiverType)
- Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0,
+ Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
false);
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- 0, 0, false);
+ None, false);
cutOffParsing();
return ExprError();
}
@@ -2480,7 +2483,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -2490,18 +2493,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (Tok.is(tok::code_completion)) {
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/true);
else if (ReceiverType)
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/true);
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/true);
cutOffParsing();
@@ -2520,7 +2520,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return Res;
}
@@ -2531,18 +2531,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (Tok.is(tok::code_completion)) {
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/false);
else if (ReceiverType)
Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/false);
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- KeyIdents.data(),
- KeyIdents.size(),
+ KeyIdents,
/*AtArgumentEpression=*/false);
cutOffParsing();
return ExprError();
@@ -2567,7 +2564,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return Res;
}
@@ -2580,7 +2577,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -2592,7 +2589,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
}
@@ -2718,7 +2715,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_square);
+ SkipUntil(tok::r_square, StopAtSemi);
return Res;
}
@@ -2753,7 +2750,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// We must manually skip to a '}', otherwise the expression skipper will
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
return KeyExpr;
}
}
@@ -2762,7 +2759,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
ConsumeToken();
} else {
Diag(Tok, diag::err_expected_colon);
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
return ExprError();
}
@@ -2771,7 +2768,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// We must manually skip to a '}', otherwise the expression skipper will
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
- SkipUntil(tok::r_brace);
+ SkipUntil(tok::r_brace, StopAtSemi);
return ValueExpr;
}
@@ -2864,8 +2861,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
T.consumeOpen();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
- KeyIdents.size());
+ Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
return ExprError();
}
@@ -2891,8 +2887,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
break;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
- KeyIdents.size());
+ Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
return ExprError();
}
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 507a6b1bcd87..89e4147e285c 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -12,8 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/Parse/Parser.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Scope.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -21,98 +24,358 @@ using namespace clang;
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
-/// \brief Parses OpenMP declarative directive
-/// threadprivate-directive
-/// annot_pragma_openmp threadprivate simple-variable-list
+/// \brief Parsing of declarative OpenMP directives.
+///
+/// threadprivate-directive:
+/// annot_pragma_openmp 'threadprivate' simple-variable-list
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParenBraceBracketBalancer BalancerRAIIObj(*this);
SourceLocation Loc = ConsumeToken();
- SmallVector<DeclarationNameInfo, 5> Identifiers;
- OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
- OMPD_unknown :
- getOpenMPDirectiveKind(PP.getSpelling(Tok));
- switch(Kind) {
+ SmallVector<Expr *, 5> Identifiers;
+ OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+
+ switch (DKind) {
case OMPD_threadprivate:
ConsumeToken();
- if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(OMPD_threadprivate);
- SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
+ // Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
- getCurScope(),
Identifiers);
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
- default:
+ case OMPD_parallel:
+ case OMPD_task:
+ case NUM_OPENMP_DIRECTIVES:
Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(Kind);
+ << getOpenMPDirectiveName(DKind);
break;
}
- SkipUntil(tok::annot_pragma_openmp_end, false);
+ SkipUntil(tok::annot_pragma_openmp_end);
return DeclGroupPtrTy();
}
+/// \brief Parsing of declarative or executable OpenMP directives.
+///
+/// threadprivate-directive:
+/// annot_pragma_openmp 'threadprivate' simple-variable-list
+/// annot_pragma_openmp_end
+///
+/// parallel-directive:
+/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
+///
+StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
+ assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParenBraceBracketBalancer BalancerRAIIObj(*this);
+ SmallVector<Expr *, 5> Identifiers;
+ SmallVector<OMPClause *, 5> Clauses;
+ SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
+ FirstClauses(NUM_OPENMP_CLAUSES);
+ const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
+ Scope::OpenMPDirectiveScope;
+ SourceLocation Loc = ConsumeToken(), EndLoc;
+ OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ // Name of critical directive.
+ DeclarationNameInfo DirName;
+ StmtResult Directive = StmtError();
+
+ switch (DKind) {
+ case OMPD_threadprivate:
+ ConsumeToken();
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
+ // The last seen token is annot_pragma_openmp_end - need to check for
+ // extra tokens.
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ DeclGroupPtrTy Res =
+ Actions.ActOnOpenMPThreadprivateDirective(Loc,
+ Identifiers);
+ Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
+ }
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ case OMPD_parallel: {
+ ConsumeToken();
+
+ Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
+
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ OpenMPClauseKind CKind = Tok.isAnnotation() ?
+ OMPC_unknown :
+ getOpenMPClauseKind(PP.getSpelling(Tok));
+ OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
+ !FirstClauses[CKind].getInt());
+ FirstClauses[CKind].setInt(true);
+ if (Clause) {
+ FirstClauses[CKind].setPointer(Clause);
+ Clauses.push_back(Clause);
+ }
+
+ // Skip ',' if any.
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ // End location of the directive.
+ EndLoc = Tok.getLocation();
+ // Consume final annot_pragma_openmp_end.
+ ConsumeToken();
+
+ StmtResult AssociatedStmt;
+ bool CreateDirective = true;
+ ParseScope OMPDirectiveScope(this, ScopeFlags);
+ {
+ // The body is a block scope like in Lambdas and Blocks.
+ Sema::CompoundScopeRAII CompoundScope(Actions);
+ Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
+ Actions.ActOnStartOfCompoundStmt();
+ // Parse statement
+ AssociatedStmt = ParseStatement();
+ Actions.ActOnFinishOfCompoundStmt();
+ if (!AssociatedStmt.isUsable()) {
+ Actions.ActOnCapturedRegionError();
+ CreateDirective = false;
+ } else {
+ AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
+ CreateDirective = AssociatedStmt.isUsable();
+ }
+ }
+ if (CreateDirective)
+ Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
+ AssociatedStmt.take(),
+ Loc, EndLoc);
+
+ // Exit scope.
+ Actions.EndOpenMPDSABlock(Directive.get());
+ OMPDirectiveScope.Exit();
+ }
+ break;
+ case OMPD_unknown:
+ Diag(Tok, diag::err_omp_unknown_directive);
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ case OMPD_task:
+ case NUM_OPENMP_DIRECTIVES:
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ }
+ return Directive;
+}
+
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
-/// directive
-/// simple-variable-list:
-/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+/// directive.
+///
+/// simple-variable-list:
+/// '(' id-expression {, id-expression} ')'
///
-bool Parser::ParseOpenMPSimpleVarList(
- OpenMPDirectiveKind Kind,
- SmallVectorImpl<DeclarationNameInfo> &IdList) {
+bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
+ SmallVectorImpl<Expr *> &VarList,
+ bool AllowScopeSpecifier) {
+ VarList.clear();
// Parse '('.
- bool IsCorrect = true;
- BalancedDelimiterTracker T(*this, tok::l_paren);
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(Kind))) {
- SkipUntil(tok::annot_pragma_openmp_end, false, true);
- return false;
- }
+ getOpenMPDirectiveName(Kind)))
+ return true;
+ bool IsCorrect = true;
+ bool NoIdentIsFound = true;
// Read tokens while ')' or annot_pragma_openmp_end is not found.
- do {
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
// Read var name.
Token PrevTok = Tok;
+ NoIdentIsFound = false;
- if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
- TemplateKWLoc, Name)) {
+ if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- false, true);
- }
- else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
+ StopBeforeMatch);
+ } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ TemplateKWLoc, Name)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- false, true);
- Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus
+ StopBeforeMatch);
+ Diag(PrevTok.getLocation(), diag::err_expected_ident)
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
- IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+ DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
+ ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
+ NameInfo);
+ if (Res.isUsable())
+ VarList.push_back(Res.take());
}
// Consume ','.
if (Tok.is(tok::comma)) {
ConsumeToken();
}
- } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+ }
+
+ if (NoIdentIsFound) {
+ Diag(Tok, diag::err_expected_ident);
+ IsCorrect = false;
+ }
- if (IsCorrect || Tok.is(tok::r_paren)) {
- IsCorrect = !T.consumeClose() && IsCorrect;
+ // Parse ')'.
+ IsCorrect = !T.consumeClose() && IsCorrect;
+
+ return !IsCorrect && VarList.empty();
+}
+
+/// \brief Parsing of OpenMP clauses.
+///
+/// clause:
+/// default-clause|private-clause|firstprivate-clause|shared-clause
+///
+OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind CKind, bool FirstClause) {
+ OMPClause *Clause = 0;
+ bool ErrorFound = false;
+ // Check if clause is allowed for the given directive.
+ if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ ErrorFound = true;
}
- return !IsCorrect && IdList.empty();
+ switch (CKind) {
+ case OMPC_default:
+ // OpenMP [2.9.3.1, Restrictions]
+ // Only a single default clause may be specified on a parallel or task
+ // directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPSimpleClause(CKind);
+ break;
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_shared:
+ Clause = ParseOpenMPVarListClause(CKind);
+ break;
+ case OMPC_unknown:
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ break;
+ case OMPC_threadprivate:
+ case NUM_OPENMP_CLAUSES:
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ break;
+ }
+ return ErrorFound ? 0 : Clause;
}
+
+/// \brief Parsing of simple OpenMP clauses like 'default'.
+///
+/// default-clause:
+/// 'default' '(' 'none' | 'shared' ')
+///
+OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = Tok.getLocation();
+ SourceLocation LOpen = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return 0;
+
+ unsigned Type = Tok.isAnnotation() ?
+ unsigned(OMPC_DEFAULT_unknown) :
+ getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
+ SourceLocation TypeLoc = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+
+ // Parse ')'.
+ T.consumeClose();
+
+ return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
+ Tok.getLocation());
+}
+
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
+/// 'shared', 'copyin', or 'reduction'.
+///
+/// private-clause:
+/// 'private' '(' list ')'
+/// firstprivate-clause:
+/// 'firstprivate' '(' list ')'
+/// shared-clause:
+/// 'shared' '(' list ')'
+///
+OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = Tok.getLocation();
+ SourceLocation LOpen = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return 0;
+
+ SmallVector<Expr *, 5> Vars;
+ bool IsComma = true;
+ while (IsComma || (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))) {
+ // Parse variable
+ ExprResult VarExpr = ParseAssignmentExpression();
+ if (VarExpr.isUsable()) {
+ Vars.push_back(VarExpr.take());
+ } else {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+ // Skip ',' if any
+ IsComma = Tok.is(tok::comma);
+ if (IsComma) {
+ ConsumeToken();
+ } else if (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::err_omp_expected_punc)
+ << 1 << getOpenMPClauseName(Kind);
+ }
+ }
+
+ // Parse ')'.
+ T.consumeClose();
+ if (Vars.empty())
+ return 0;
+
+ return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
+ Tok.getLocation());
+}
+
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 3d1249aa684a..8a374e0fce61 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -728,6 +728,7 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
return;
}
+ SourceLocation StateLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
@@ -747,6 +748,10 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
Toks[0].setAnnotationValue(data.getOpaqueValue());
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
+
+ if (PP.getPPCallbacks())
+ PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename,
+ StateLoc, state);
}
/// \brief Handle '#pragma omp ...' when OpenMP is disabled.
@@ -794,6 +799,63 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
}
+/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
+///
+/// The syntax is:
+/// \code
+/// #pragma detect_mismatch("name", "value")
+/// \endcode
+/// Where 'name' and 'value' are quoted strings. The values are embedded in
+/// the object file and passed along to the linker. If the linker detects a
+/// mismatch in the object file's values for the given name, a LNK2038 error
+/// is emitted. See MSDN for more details.
+void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ SourceLocation CommentLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(CommentLoc, diag::err_expected_lparen);
+ return;
+ }
+
+ // Read the name to embed, which must be a string literal.
+ std::string NameString;
+ if (!PP.LexStringLiteral(Tok, NameString,
+ "pragma detect_mismatch",
+ /*MacroExpansion=*/true))
+ return;
+
+ // Read the comma followed by a second string literal.
+ std::string ValueString;
+ if (Tok.isNot(tok::comma)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
+ return;
+ }
+
+ if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch",
+ /*MacroExpansion=*/true))
+ return;
+
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected_rparen);
+ return;
+ }
+ PP.Lex(Tok); // Eat the r_paren.
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
+ return;
+ }
+
+ // If the pragma is lexically sound, notify any interested PPCallbacks.
+ if (PP.getPPCallbacks())
+ PP.getPPCallbacks()->PragmaDetectMismatch(CommentLoc, NameString,
+ ValueString);
+
+ Actions.ActOnPragmaDetectMismatch(NameString, ValueString);
+}
+
/// \brief Handle the microsoft \#pragma comment extension.
///
/// The syntax is:
@@ -821,10 +883,16 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
}
// Verify that this is one of the 5 whitelisted options.
- // FIXME: warn that 'exestr' is deprecated.
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") &&
- !II->isStr("linker") && !II->isStr("user")) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ Sema::PragmaMSCommentKind Kind =
+ llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName())
+ .Case("linker", Sema::PCK_Linker)
+ .Case("lib", Sema::PCK_Lib)
+ .Case("compiler", Sema::PCK_Compiler)
+ .Case("exestr", Sema::PCK_ExeStr)
+ .Case("user", Sema::PCK_User)
+ .Default(Sema::PCK_Unknown);
+ if (Kind == Sema::PCK_Unknown) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
return;
}
@@ -837,11 +905,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
/*MacroExpansion=*/true))
return;
+ // FIXME: warn that 'exestr' is deprecated.
// FIXME: If the kind is "compiler" warn if the string is present (it is
// ignored).
- // FIXME: 'lib' requires a comment string.
- // FIXME: 'linker' requires a comment string, and has a specific list of
- // things that are allowable.
+ // The MSDN docs say that "lib" and "linker" require a string and have a short
+ // whitelist of linker options they support, but in practice MSVC doesn't
+ // issue a diagnostic. Therefore neither does clang.
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
@@ -857,4 +926,6 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
// If the pragma is lexically sound, notify any interested PPCallbacks.
if (PP.getPPCallbacks())
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
+
+ Actions.ActOnPragmaMSComment(Kind, ArgumentString);
}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index d9560f3181d6..b41450f4eadf 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -116,9 +116,22 @@ public:
/// PragmaCommentHandler - "\#pragma comment ...".
class PragmaCommentHandler : public PragmaHandler {
public:
- PragmaCommentHandler() : PragmaHandler("comment") {}
+ PragmaCommentHandler(Sema &Actions)
+ : PragmaHandler("comment"), Actions(Actions) {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
+private:
+ Sema &Actions;
+};
+
+class PragmaDetectMismatchHandler : public PragmaHandler {
+public:
+ PragmaDetectMismatchHandler(Sema &Actions)
+ : PragmaHandler("detect_mismatch"), Actions(Actions) {}
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+private:
+ Sema &Actions;
};
} // end namespace clang
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 43b6965d314f..d1f2138db48f 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -41,6 +41,21 @@ using namespace clang;
// C99 6.8: Statements and Blocks.
//===----------------------------------------------------------------------===//
+/// \brief Parse a standalone statement (for instance, as the body of an 'if',
+/// 'while', or 'for').
+StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc) {
+ StmtResult Res;
+
+ // We may get back a null statement if we found a #pragma. Keep going until
+ // we get an actual statement.
+ do {
+ StmtVector Stmts;
+ Res = ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
+ } while (!Res.isInvalid() && !Res.get());
+
+ return Res;
+}
+
/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
/// StatementOrDeclaration:
/// statement
@@ -111,6 +126,38 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range);
}
+namespace {
+class StatementFilterCCC : public CorrectionCandidateCallback {
+public:
+ StatementFilterCCC(Token nextTok) : NextToken(nextTok) {
+ WantTypeSpecifiers = nextTok.is(tok::l_paren) || nextTok.is(tok::less) ||
+ nextTok.is(tok::identifier) || nextTok.is(tok::star) ||
+ nextTok.is(tok::amp) || nextTok.is(tok::l_square);
+ WantExpressionKeywords = nextTok.is(tok::l_paren) ||
+ nextTok.is(tok::identifier) ||
+ nextTok.is(tok::arrow) || nextTok.is(tok::period);
+ WantRemainingKeywords = nextTok.is(tok::l_paren) || nextTok.is(tok::semi) ||
+ nextTok.is(tok::identifier) ||
+ nextTok.is(tok::l_brace);
+ WantCXXNamedCasts = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>())
+ return !candidate.getCorrectionSpecifier() || isa<ObjCIvarDecl>(FD);
+ if (NextToken.is(tok::equal))
+ return candidate.getCorrectionDeclAs<VarDecl>();
+ if (NextToken.is(tok::period) &&
+ candidate.getCorrectionDeclAs<NamespaceDecl>())
+ return false;
+ return CorrectionCandidateCallback::ValidateCandidate(candidate);
+ }
+
+private:
+ Token NextToken;
+};
+}
+
StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
bool OnlyStatement, SourceLocation *TrailingElseLoc,
@@ -149,25 +196,12 @@ Retry:
if (Next.isNot(tok::coloncolon)) {
// Try to limit which sets of keywords should be included in typo
// correction based on what the next token is.
- // FIXME: Pass the next token into the CorrectionCandidateCallback and
- // do this filtering in a more fine-grained manner.
- CorrectionCandidateCallback DefaultValidator;
- DefaultValidator.WantTypeSpecifiers =
- Next.is(tok::l_paren) || Next.is(tok::less) ||
- Next.is(tok::identifier) || Next.is(tok::star) ||
- Next.is(tok::amp) || Next.is(tok::l_square);
- DefaultValidator.WantExpressionKeywords =
- Next.is(tok::l_paren) || Next.is(tok::identifier) ||
- Next.is(tok::arrow) || Next.is(tok::period);
- DefaultValidator.WantRemainingKeywords =
- Next.is(tok::l_paren) || Next.is(tok::semi) ||
- Next.is(tok::identifier) || Next.is(tok::l_brace);
- DefaultValidator.WantCXXNamedCasts = false;
- if (TryAnnotateName(/*IsAddressOfOperand*/false, &DefaultValidator)
+ StatementFilterCCC Validator(Next);
+ if (TryAnnotateName(/*IsAddressOfOperand*/false, &Validator)
== ANK_Error) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
- SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
@@ -293,6 +327,7 @@ Retry:
return StmtEmpty();
case tok::annot_pragma_fp_contract:
+ ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_fp_contract_scope);
ConsumeToken();
return StmtError();
@@ -303,12 +338,13 @@ Retry:
return StmtEmpty();
case tok::annot_pragma_captured:
+ ProhibitAttributes(Attrs);
return HandlePragmaCaptured();
case tok::annot_pragma_openmp:
- SourceLocation DeclStart = Tok.getLocation();
- DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective();
- return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation());
+ ProhibitAttributes(Attrs);
+ return ParseOpenMPDeclarativeOrExecutableDirective();
+
}
// If we reached this code, the statement must end in a semicolon.
@@ -320,7 +356,7 @@ Retry:
// succeed.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError);
// Skip until we see a } or ;, but don't eat it.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
}
return Res;
@@ -337,7 +373,7 @@ StmtResult Parser::ParseExprStatement() {
// If the expression is invalid, skip ahead to the next semicolon or '}'.
// Not doing this opens us up to the possibility of infinite loops if
// ParseExpression does not consume any tokens.
- SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
return Actions.ActOnExprStmtError();
@@ -480,11 +516,40 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) {
// identifier ':' statement
SourceLocation ColonLoc = ConsumeToken();
- // Read label attributes, if present. attrs will contain both C++11 and GNU
- // attributes (if present) after this point.
- MaybeParseGNUAttributes(attrs);
+ // Read label attributes, if present.
+ StmtResult SubStmt;
+ if (Tok.is(tok::kw___attribute)) {
+ ParsedAttributesWithRange TempAttrs(AttrFactory);
+ ParseGNUAttributes(TempAttrs);
+
+ // In C++, GNU attributes only apply to the label if they are followed by a
+ // semicolon, to disambiguate label attributes from attributes on a labeled
+ // declaration.
+ //
+ // This doesn't quite match what GCC does; if the attribute list is empty
+ // and followed by a semicolon, GCC will reject (it appears to parse the
+ // attributes as part of a statement in that case). That looks like a bug.
+ if (!getLangOpts().CPlusPlus || Tok.is(tok::semi))
+ attrs.takeAllFrom(TempAttrs);
+ else if (isDeclarationStatement()) {
+ StmtVector Stmts;
+ // FIXME: We should do this whether or not we have a declaration
+ // statement, but that doesn't work correctly (because ProhibitAttributes
+ // can't handle GNU attributes), so only call it in the one case where
+ // GNU attributes are allowed.
+ SubStmt = ParseStatementOrDeclarationAfterAttributes(
+ Stmts, /*OnlyStmts*/ true, 0, TempAttrs);
+ if (!TempAttrs.empty() && !SubStmt.isInvalid())
+ SubStmt = Actions.ProcessStmtAttributes(
+ SubStmt.get(), TempAttrs.getList(), TempAttrs.Range);
+ } else {
+ Diag(Tok, diag::err_expected_semi_after) << "__attribute__";
+ }
+ }
- StmtResult SubStmt(ParseStatement());
+ // If we've not parsed a statement yet, parse one now.
+ if (!SubStmt.isInvalid() && !SubStmt.isUsable())
+ SubStmt = ParseStatement();
// Broken substmt shouldn't prevent the label from being added to the AST.
if (SubStmt.isInvalid())
@@ -521,7 +586,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// out of stack space in our recursive descent parser. As a special case,
// flatten this recursion into an iterative loop. This is complex and gross,
// but all the grossness is constrained to ParseCaseStatement (and some
- // wierdness in the actions), so this is just local grossness :).
+ // weirdness in the actions), so this is just local grossness :).
// TopLevelCase - This is the highest level we have parsed. 'case 1' in the
// example above.
@@ -552,7 +617,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
MissingCase = false;
if (LHS.isInvalid()) {
- SkipUntil(tok::colon);
+ SkipUntil(tok::colon, StopAtSemi);
return StmtError();
}
@@ -565,7 +630,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
RHS = ParseConstantExpression();
if (RHS.isInvalid()) {
- SkipUntil(tok::colon);
+ SkipUntil(tok::colon, StopAtSemi);
return StmtError();
}
}
@@ -798,7 +863,6 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// only allowed at the start of a compound stmt regardless of the language.
while (Tok.is(tok::kw___label__)) {
SourceLocation LabelLoc = ConsumeToken();
- Diag(LabelLoc, diag::ext_gnu_local_label);
SmallVector<Decl *, 8> DeclsInGroup;
while (1) {
@@ -817,8 +881,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
}
DeclSpec DS(AttrFactory);
- DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
- DeclsInGroup.data(), DeclsInGroup.size());
+ DeclGroupPtrTy Res =
+ Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
@@ -1132,7 +1196,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
// will have no place to connect back with the switch.
if (Tok.is(tok::l_brace)) {
ConsumeBrace();
- SkipUntil(tok::r_brace, false, false);
+ SkipUntil(tok::r_brace);
} else
SkipUntil(tok::semi);
return Switch;
@@ -1283,7 +1347,7 @@ StmtResult Parser::ParseDoStatement() {
if (!Body.isInvalid()) {
Diag(Tok, diag::err_expected_while);
Diag(DoLoc, diag::note_matching) << "do";
- SkipUntil(tok::semi, false, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
}
return StmtError();
}
@@ -1291,18 +1355,16 @@ StmtResult Parser::ParseDoStatement() {
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "do/while";
- SkipUntil(tok::semi, false, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
return StmtError();
}
- // Parse the parenthesized condition.
+ // Parse the parenthesized expression.
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- // FIXME: Do not just parse the attribute contents and throw them away
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- ProhibitAttributes(attrs);
+ // A do-while expression is not a condition, so can't have attributes.
+ DiagnoseAndSkipCXX11Attributes();
ExprResult Cond = ParseExpression();
T.consumeClose();
@@ -1469,14 +1531,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// for (expr : expr) { ... }
Diag(Tok, diag::err_for_range_expected_decl)
<< FirstPart.get()->getSourceRange();
- SkipUntil(tok::r_paren, false, true);
+ SkipUntil(tok::r_paren, StopBeforeMatch);
SecondPartIsInvalid = true;
} else {
if (!Value.isInvalid()) {
Diag(Tok, diag::err_expected_semi_for);
} else {
// Skip until semicolon or rparen, don't consume it.
- SkipUntil(tok::r_paren, true, true);
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
}
@@ -1508,7 +1570,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
Diag(Tok, diag::err_expected_semi_for);
else
// Skip until semicolon or rparen, don't consume it.
- SkipUntil(tok::r_paren, true, true);
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
}
if (Tok.is(tok::semi)) {
@@ -1610,7 +1672,7 @@ StmtResult Parser::ParseGotoStatement() {
SourceLocation StarLoc = ConsumeToken();
ExprResult R(ParseExpression());
if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
- SkipUntil(tok::semi, false, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
return StmtError();
}
Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take());
@@ -1669,7 +1731,7 @@ StmtResult Parser::ParseReturnStatement() {
} else
R = ParseExpression();
if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
- SkipUntil(tok::semi, false, true);
+ SkipUntil(tok::semi, StopBeforeMatch);
return StmtError();
}
}
@@ -2067,14 +2129,22 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
// We need an actual supported target.
llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple();
llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+ const std::string &TT = TheTriple.getTriple();
+ const llvm::Target *TheTarget = 0;
bool UnsupportedArch = (ArchTy != llvm::Triple::x86 &&
ArchTy != llvm::Triple::x86_64);
- if (UnsupportedArch)
+ if (UnsupportedArch) {
Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
-
+ } else {
+ std::string Error;
+ TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
+ if (!TheTarget)
+ Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
+ }
+
// If we don't support assembly, or the assembly is empty, we don't
// need to instantiate the AsmParser, etc.
- if (UnsupportedArch || AsmToks.empty()) {
+ if (!TheTarget || AsmToks.empty()) {
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),
/*NumOutputs*/ 0, /*NumInputs*/ 0,
ConstraintRefs, ClobberRefs, Exprs, EndLoc);
@@ -2086,19 +2156,16 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
return StmtError();
- // Find the target and create the target specific parser.
- std::string Error;
- const std::string &TT = TheTriple.getTriple();
- const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
-
- OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+ OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
+ // Get the instruction descriptor.
+ const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
OwningPtr<llvm::MCSubtargetInfo>
STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
llvm::SourceMgr TempSrcMgr;
- llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &TempSrcMgr);
+ llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
llvm::MemoryBuffer *Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
@@ -2109,10 +2176,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
OwningPtr<llvm::MCAsmParser>
Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
OwningPtr<llvm::MCTargetAsmParser>
- TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
+ TargetParser(TheTarget->createMCAsmParser(*STI, *Parser, *MII));
- // Get the instruction descriptor.
- const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
llvm::MCInstPrinter *IP =
TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
@@ -2214,7 +2279,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return StmtError();
}
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -2333,7 +2398,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return true;
}
@@ -2347,14 +2412,14 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
ExprResult Constraint(ParseAsmStringLiteral());
if (Constraint.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return true;
}
Constraints.push_back(Constraint.release());
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return true;
}
@@ -2364,7 +2429,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
ExprResult Res(ParseExpression());
T.consumeClose();
if (Res.isInvalid()) {
- SkipUntil(tok::r_paren);
+ SkipUntil(tok::r_paren, StopAtSemi);
return true;
}
Exprs.push_back(Res.release());
@@ -2395,8 +2460,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
// If the function body could not be parsed, make a bogus compoundstmt.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(), false);
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
}
BodyScope.Exit();
@@ -2433,8 +2497,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
// compound statement as the body.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(), false);
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
}
BodyScope.Exit();
@@ -2448,7 +2511,7 @@ bool Parser::trySkippingFunctionBody() {
if (!PP.isCodeCompletionEnabled()) {
ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false);
+ SkipUntil(tok::r_brace);
return true;
}
@@ -2456,8 +2519,7 @@ bool Parser::trySkippingFunctionBody() {
// the body contains the code-completion point.
TentativeParsingAction PA(*this);
ConsumeBrace();
- if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false,
- /*StopAtCodeCompletion=*/true)) {
+ if (SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
PA.Commit();
return true;
}
@@ -2530,9 +2592,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
}
else {
StmtVector Handlers;
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- ProhibitAttributes(attrs);
+
+ // C++11 attributes can't appear here, despite this context seeming
+ // statement-like.
+ DiagnoseAndSkipCXX11Attributes();
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
@@ -2546,7 +2609,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Handlers.empty())
return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers);
+ return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), Handlers);
}
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 84b7df7295f6..076edb93fa11 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -120,7 +120,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
TemplateParams, LAngleLoc, RAngleLoc)) {
// Skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
return 0;
@@ -216,7 +216,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
// If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, true, true);
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
return 0;
@@ -236,6 +236,35 @@ Parser::ParseSingleDeclarationAfterTemplate(
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
DS.ClearStorageClassSpecs();
}
+
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ if (DeclaratorInfo.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ // If the declarator-id is not a template-id, issue a diagnostic and
+ // recover by ignoring the 'template' keyword.
+ Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
+ return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
+ &LateParsedAttrs);
+ } else {
+ SourceLocation LAngleLoc
+ = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(DeclaratorInfo.getIdentifierLoc(),
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Recover as if it were an explicit specialization.
+ TemplateParameterLists FakedParamLists;
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
+ LAngleLoc));
+
+ return ParseFunctionDefinition(
+ DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
+ /*isSpecialization=*/true,
+ /*LastParamListWasEmpty=*/true),
+ &LateParsedAttrs);
+ }
+ }
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
&LateParsedAttrs);
}
@@ -247,7 +276,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (Tok.is(tok::comma)) {
Diag(Tok, diag::err_multiple_template_declarators)
<< (int)TemplateInfo.Kind;
- SkipUntil(tok::semi, true, false);
+ SkipUntil(tok::semi);
return ThisDecl;
}
@@ -320,7 +349,8 @@ Parser::ParseTemplateParameterList(unsigned Depth,
} else {
// If we failed to parse a template parameter, skip until we find
// a comma or closing brace.
- SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
}
// Did we find a comma or the end of the template parameter list?
@@ -334,7 +364,8 @@ Parser::ParseTemplateParameterList(unsigned Depth,
// try to get out of the expression. This error is currently
// subsumed by whatever goes on in ParseTemplateParameter.
Diag(Tok.getLocation(), diag::err_expected_comma_greater);
- SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
return false;
}
}
@@ -582,7 +613,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
- SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
}
}
@@ -632,7 +664,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
DefaultArg = ParseAssignmentExpression();
if (DefaultArg.isInvalid())
- SkipUntil(tok::comma, tok::greater, true, true);
+ SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
}
// Create the parameter.
@@ -650,6 +682,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
/// \param RAngleLoc the location of the consumed '>'.
///
/// \param ConsumeLastToken if true, the '>' is not consumed.
+///
+/// \returns true, if current token does not start with '>', false otherwise.
bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
bool ConsumeLastToken) {
// What will be left once we've consumed the '>'.
@@ -794,8 +828,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
if (Invalid) {
// Try to find the closing '>'.
- SkipUntil(tok::greater, true, !ConsumeLastToken);
-
+ if (ConsumeLastToken)
+ SkipUntil(tok::greater, StopAtSemi);
+ else
+ SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch);
return true;
}
}
@@ -1160,7 +1196,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
}
if (Arg.isInvalid()) {
- SkipUntil(tok::comma, tok::greater, true, true);
+ SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
return true;
}
@@ -1212,30 +1248,19 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
return R;
}
-void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) {
- ((Parser*)P)->LateTemplateParser(FD);
-}
-
-
-void Parser::LateTemplateParser(const FunctionDecl *FD) {
- LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD];
- if (LPT) {
- ParseLateTemplatedFuncDef(*LPT);
- return;
- }
-
- llvm_unreachable("Late templated function without associated lexed tokens");
+void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) {
+ ((Parser *)P)->ParseLateTemplatedFuncDef(LPT);
}
/// \brief Late parse a C++ function template in Microsoft mode.
-void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
- if(!LMT.D)
+void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
+ if (!LPT.D)
return;
// Get the FunctionDecl.
- FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LMT.D);
+ FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LPT.D);
FunctionDecl *FunD =
- FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LMT.D);
+ FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LPT.D);
// Track template parameter depth.
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
@@ -1253,7 +1278,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
}
// Reenter template scopes from outermost to innermost.
- SmallVector<DeclContext*, 4>::reverse_iterator II =
+ SmallVectorImpl<DeclContext *>::reverse_iterator II =
DeclContextsToReenter.rbegin();
for (; II != DeclContextsToReenter.rend(); ++II) {
if (ClassTemplatePartialSpecializationDecl *MD =
@@ -1263,12 +1288,14 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
Actions.ActOnReenterTemplateScope(getCurScope(), MD);
++CurTemplateDepthTracker;
} else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
- bool ManageScope = MD->getDescribedClassTemplate() != 0;
+ bool IsClassTemplate = MD->getDescribedClassTemplate() != 0;
TemplateParamScopeStack.push_back(
- new ParseScope(this, Scope::TemplateParamScope, ManageScope));
+ new ParseScope(this, Scope::TemplateParamScope,
+ /*ManageScope*/IsClassTemplate));
Actions.ActOnReenterTemplateScope(getCurScope(),
MD->getDescribedClassTemplate());
- ++CurTemplateDepthTracker;
+ if (IsClassTemplate)
+ ++CurTemplateDepthTracker;
}
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
Actions.PushDeclContext(Actions.getCurScope(), *II);
@@ -1281,15 +1308,15 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
++CurTemplateDepthTracker;
}
- Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+ Actions.ActOnReenterTemplateScope(getCurScope(), LPT.D);
++CurTemplateDepthTracker;
- assert(!LMT.Toks.empty() && "Empty body!");
+ assert(!LPT.Toks.empty() && "Empty body!");
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
- LMT.Toks.push_back(Tok);
- PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
+ LPT.Toks.push_back(Tok);
+ PP.EnterTokenStream(LPT.Toks.data(), LPT.Toks.size(), true, false);
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
@@ -1306,34 +1333,30 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
if (Tok.is(tok::kw_try)) {
- ParseFunctionTryBlock(LMT.D, FnScope);
+ ParseFunctionTryBlock(LPT.D, FnScope);
} else {
if (Tok.is(tok::colon))
- ParseConstructorInitializer(LMT.D);
+ ParseConstructorInitializer(LPT.D);
else
- Actions.ActOnDefaultCtorInitializers(LMT.D);
+ Actions.ActOnDefaultCtorInitializers(LPT.D);
if (Tok.is(tok::l_brace)) {
assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() <
TemplateParameterDepth) &&
"TemplateParameterDepth should be greater than the depth of "
"current template being instantiated!");
- ParseFunctionStatementBody(LMT.D, FnScope);
- Actions.MarkAsLateParsedTemplate(FunD, false);
+ ParseFunctionStatementBody(LPT.D, FnScope);
+ Actions.UnmarkAsLateParsedTemplate(FunD);
} else
- Actions.ActOnFinishFunctionBody(LMT.D, 0);
+ Actions.ActOnFinishFunctionBody(LPT.D, 0);
}
// Exit scopes.
FnScope.Exit();
- SmallVector<ParseScope*, 4>::reverse_iterator I =
+ SmallVectorImpl<ParseScope *>::reverse_iterator I =
TemplateParamScopeStack.rbegin();
for (; I != TemplateParamScopeStack.rend(); ++I)
delete *I;
-
- DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D);
- if (grp)
- Actions.getASTConsumer().HandleTopLevelDecl(grp.get());
}
/// \brief Lex a delayed template function for late parsing.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index dff3b64c5b3f..a1d6b13fdab8 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -142,6 +142,82 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
return TPR == TPResult::True();
}
+/// Try to consume a token sequence that we've already identified as
+/// (potentially) starting a decl-specifier.
+Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
+ switch (Tok.getKind()) {
+ case tok::kw__Atomic:
+ if (NextToken().isNot(tok::l_paren)) {
+ ConsumeToken();
+ break;
+ }
+ // Fall through.
+ case tok::kw_typeof:
+ case tok::kw___attribute:
+ case tok::kw___underlying_type: {
+ ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return TPResult::Error();
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ break;
+ }
+
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ case tok::kw___interface:
+ case tok::kw_enum:
+ // elaborated-type-specifier:
+ // class-key attribute-specifier-seq[opt]
+ // nested-name-specifier[opt] identifier
+ // class-key nested-name-specifier[opt] template[opt] simple-template-id
+ // enum nested-name-specifier[opt] identifier
+ //
+ // FIXME: We don't support class-specifiers nor enum-specifiers here.
+ ConsumeToken();
+
+ // Skip attributes.
+ while (Tok.is(tok::l_square) || Tok.is(tok::kw___attribute) ||
+ Tok.is(tok::kw___declspec) || Tok.is(tok::kw_alignas)) {
+ if (Tok.is(tok::l_square)) {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ return TPResult::Error();
+ } else {
+ ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return TPResult::Error();
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+ }
+
+ if (TryAnnotateCXXScopeToken())
+ return TPResult::Error();
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ return TPResult::Error();
+ ConsumeToken();
+ break;
+
+ case tok::annot_cxxscope:
+ ConsumeToken();
+ // Fall through.
+ default:
+ ConsumeToken();
+
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
+ return TryParseProtocolQualifiers();
+ break;
+ }
+
+ return TPResult::Ambiguous();
+}
+
/// simple-declaration:
/// decl-specifier-seq init-declarator-list[opt] ';'
///
@@ -151,16 +227,8 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
/// attribute-specifier-seqopt type-specifier-seq declarator
///
Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error())
+ return TPResult::Error();
// Two decl-specifiers in a row conclusively disambiguate this as being a
// simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
@@ -226,14 +294,14 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
if (Tok.is(tok::l_paren)) {
// Parse through the parens.
ConsumeParen();
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
return TPResult::Error();
} else if (Tok.is(tok::l_brace)) {
// A left-brace here is sufficient to disambiguate the parse; an
// expression can never be followed directly by a braced-init-list.
return TPResult::True();
} else if (Tok.is(tok::equal) || isTokIdentifier_in()) {
- // MSVC and g++ won't examine the rest of declarators if '=' is
+ // MSVC and g++ won't examine the rest of declarators if '=' is
// encountered; they just conclude that we have a declaration.
// EDG parses the initializer completely, which is the proper behavior
// for this case.
@@ -241,12 +309,14 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
// At present, Clang follows MSVC and g++, since the parser does not have
// the ability to parse an expression fully without recording the
// results of that parse.
- // Also allow 'in' after on objective-c declaration as in:
- // for (int (^b)(void) in array). Ideally this should be done in the
+ // FIXME: Handle this case correctly.
+ //
+ // Also allow 'in' after an Objective-C declaration as in:
+ // for (int (^b)(void) in array). Ideally this should be done in the
// context of parsing for-init-statement of a foreach statement only. But,
// in any other context 'in' is invalid after a declaration and parser
// issues the error regardless of outcome of this decision.
- // FIXME. Change if above assumption does not hold.
+ // FIXME: Change if above assumption does not hold.
return TPResult::True();
}
@@ -286,14 +356,7 @@ bool Parser::isCXXConditionDeclaration() {
TentativeParsingAction PA(*this);
// type-specifier-seq
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
+ TryConsumeDeclarationSpecifier();
assert(Tok.is(tok::l_paren) && "Expected '('");
// declarator
@@ -363,15 +426,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
TentativeParsingAction PA(*this);
// type-specifier-seq
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
-
+ TryConsumeDeclarationSpecifier();
assert(Tok.is(tok::l_paren) && "Expected '('");
// declarator
@@ -462,7 +517,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
if (!getLangOpts().ObjC1) {
ConsumeBracket();
- bool IsAttribute = SkipUntil(tok::r_square, false);
+ bool IsAttribute = SkipUntil(tok::r_square);
IsAttribute &= Tok.is(tok::r_square);
PA.Revert();
@@ -534,7 +589,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
// Parse the attribute-argument-clause, if present.
if (Tok.is(tok::l_paren)) {
ConsumeParen();
- if (!SkipUntil(tok::r_paren, false)) {
+ if (!SkipUntil(tok::r_paren)) {
IsAttribute = false;
break;
}
@@ -569,6 +624,121 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
return CAK_NotAttributeSpecifier;
}
+Parser::TPResult Parser::TryParsePtrOperatorSeq() {
+ while (true) {
+ if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
+ if (TryAnnotateCXXScopeToken(true))
+ return TPResult::Error();
+
+ if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
+ Tok.is(tok::ampamp) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
+ // ptr-operator
+ ConsumeToken();
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict))
+ ConsumeToken();
+ } else {
+ return TPResult::True();
+ }
+ }
+}
+
+/// operator-function-id:
+/// 'operator' operator
+///
+/// operator: one of
+/// new delete new[] delete[] + - * / % ^ [...]
+///
+/// conversion-function-id:
+/// 'operator' conversion-type-id
+///
+/// conversion-type-id:
+/// type-specifier-seq conversion-declarator[opt]
+///
+/// conversion-declarator:
+/// ptr-operator conversion-declarator[opt]
+///
+/// literal-operator-id:
+/// 'operator' string-literal identifier
+/// 'operator' user-defined-string-literal
+Parser::TPResult Parser::TryParseOperatorId() {
+ assert(Tok.is(tok::kw_operator));
+ ConsumeToken();
+
+ // Maybe this is an operator-function-id.
+ switch (Tok.getKind()) {
+ case tok::kw_new: case tok::kw_delete:
+ ConsumeToken();
+ if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
+ ConsumeBracket();
+ ConsumeBracket();
+ }
+ return TPResult::True();
+
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemOnly) \
+ case tok::Token:
+#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemOnly)
+#include "clang/Basic/OperatorKinds.def"
+ ConsumeToken();
+ return TPResult::True();
+
+ case tok::l_square:
+ if (NextToken().is(tok::r_square)) {
+ ConsumeBracket();
+ ConsumeBracket();
+ return TPResult::True();
+ }
+ break;
+
+ case tok::l_paren:
+ if (NextToken().is(tok::r_paren)) {
+ ConsumeParen();
+ ConsumeParen();
+ return TPResult::True();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Maybe this is a literal-operator-id.
+ if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) {
+ bool FoundUDSuffix = false;
+ do {
+ FoundUDSuffix |= Tok.hasUDSuffix();
+ ConsumeStringToken();
+ } while (isTokenStringLiteral());
+
+ if (!FoundUDSuffix) {
+ if (Tok.is(tok::identifier))
+ ConsumeToken();
+ else
+ return TPResult::Error();
+ }
+ return TPResult::True();
+ }
+
+ // Maybe this is a conversion-function-id.
+ bool AnyDeclSpecifiers = false;
+ while (true) {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR == TPResult::Error())
+ return TPR;
+ if (TPR == TPResult::False()) {
+ if (!AnyDeclSpecifiers)
+ return TPResult::Error();
+ break;
+ }
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error())
+ return TPResult::Error();
+ AnyDeclSpecifiers = true;
+ }
+ return TryParsePtrOperatorSeq();
+}
+
/// declarator:
/// direct-declarator
/// ptr-operator declarator
@@ -615,9 +785,11 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
///
/// unqualified-id:
/// identifier
-/// operator-function-id [TODO]
-/// conversion-function-id [TODO]
+/// operator-function-id
+/// conversion-function-id
+/// literal-operator-id
/// '~' class-name [TODO]
+/// '~' decltype-specifier [TODO]
/// template-id [TODO]
///
Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
@@ -625,40 +797,28 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// declarator:
// direct-declarator
// ptr-operator declarator
-
- while (1) {
- if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
- if (TryAnnotateCXXScopeToken(true))
- return TPResult::Error();
-
- if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
- Tok.is(tok::ampamp) ||
- (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
- // ptr-operator
- ConsumeToken();
- while (Tok.is(tok::kw_const) ||
- Tok.is(tok::kw_volatile) ||
- Tok.is(tok::kw_restrict))
- ConsumeToken();
- } else {
- break;
- }
- }
+ if (TryParsePtrOperatorSeq() == TPResult::Error())
+ return TPResult::Error();
// direct-declarator:
// direct-abstract-declarator:
if (Tok.is(tok::ellipsis))
ConsumeToken();
-
- if ((Tok.is(tok::identifier) ||
- (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) &&
+
+ if ((Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
+ (Tok.is(tok::annot_cxxscope) && (NextToken().is(tok::identifier) ||
+ NextToken().is(tok::kw_operator)))) &&
mayHaveIdentifier) {
// declarator-id
if (Tok.is(tok::annot_cxxscope))
ConsumeToken();
- else
+ else if (Tok.is(tok::identifier))
TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
- ConsumeToken();
+ if (Tok.is(tok::kw_operator)) {
+ if (TryParseOperatorId() == TPResult::Error())
+ return TPResult::Error();
+ } else
+ ConsumeToken();
} else if (Tok.is(tok::l_paren)) {
ConsumeParen();
if (mayBeAbstract &&
@@ -780,6 +940,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___imag:
case tok::kw___real:
case tok::kw___FUNCTION__:
+ case tok::kw___FUNCDNAME__:
case tok::kw_L__FUNCTION__:
case tok::kw___PRETTY_FUNCTION__:
case tok::kw___has_nothrow_assign:
@@ -802,6 +963,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_literal_type:
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
+ case tok::kw___is_sealed:
case tok::kw___is_trivial:
case tok::kw___is_trivially_assignable:
case tok::kw___is_trivially_constructible:
@@ -836,14 +998,15 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_wchar_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
- case tok::kw___underlying_type:
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
+ case tok::kw___interface:
case tok::kw___thread:
case tok::kw_thread_local:
case tok::kw__Thread_local:
case tok::kw_typeof:
+ case tok::kw___underlying_type:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
@@ -1103,6 +1266,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union:
+ case tok::kw___interface:
// enum-specifier
case tok::kw_enum:
// cv-qualifier
@@ -1122,6 +1286,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw___fastcall:
case tok::kw___thiscall:
case tok::kw___w64:
+ case tok::kw___sptr:
+ case tok::kw___uptr:
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___forceinline:
@@ -1323,6 +1489,56 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
}
}
+bool Parser::isCXXDeclarationSpecifierAType() {
+ switch (Tok.getKind()) {
+ // typename-specifier
+ case tok::annot_decltype:
+ case tok::annot_template_id:
+ case tok::annot_typename:
+ case tok::kw_typeof:
+ case tok::kw___underlying_type:
+ return true;
+
+ // elaborated-type-specifier
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ case tok::kw___interface:
+ case tok::kw_enum:
+ return true;
+
+ // simple-type-specifier
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw___unknown_anytype:
+ return true;
+
+ case tok::kw_auto:
+ return getLangOpts().CPlusPlus11;
+
+ case tok::kw__Atomic:
+ // "_Atomic foo"
+ return NextToken().is(tok::l_paren);
+
+ default:
+ return false;
+ }
+}
+
/// [GNU] typeof-specifier:
/// 'typeof' '(' expressions ')'
/// 'typeof' '(' type-name ')'
@@ -1334,7 +1550,7 @@ Parser::TPResult Parser::TryParseTypeofSpecifier() {
assert(Tok.is(tok::l_paren) && "Expected '('");
// Parse through the parens after 'typeof'.
ConsumeParen();
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
return TPResult::Error();
return TPResult::Ambiguous();
@@ -1364,27 +1580,6 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() {
return TPResult::Error();
}
-Parser::TPResult
-Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) {
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
- HasMissingTypename);
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
-
- return TPResult::Ambiguous();
-}
-
/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
/// a constructor-style initializer, when parsing declaration statements.
/// Returns true for function declarator and false for constructor-style
@@ -1459,7 +1654,8 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
/// attributes[opt] '=' assignment-expression
///
Parser::TPResult
-Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
+Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
+ bool VersusTemplateArgument) {
if (Tok.is(tok::r_paren))
return TPResult::Ambiguous();
@@ -1492,8 +1688,32 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
// decl-specifier-seq
// A parameter-declaration's initializer must be preceded by an '=', so
// decl-specifier-seq '{' is not a parameter in C++11.
- TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration);
- if (TPR != TPResult::Ambiguous())
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ InvalidAsDeclaration);
+
+ if (VersusTemplateArgument && TPR == TPResult::True()) {
+ // Consume the decl-specifier-seq. We have to look past it, since a
+ // type-id might appear here in a template argument.
+ bool SeenType = false;
+ do {
+ SeenType |= isCXXDeclarationSpecifierAType();
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error())
+ return TPResult::Error();
+
+ // If we see a parameter name, this can't be a template argument.
+ if (SeenType && Tok.is(tok::identifier))
+ return TPResult::True();
+
+ TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ InvalidAsDeclaration);
+ if (TPR == TPResult::Error())
+ return TPR;
+ } while (TPR != TPResult::False());
+ } else if (TPR == TPResult::Ambiguous()) {
+ // Disambiguate what follows the decl-specifier.
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error())
+ return TPResult::Error();
+ } else
return TPR;
// declarator
@@ -1506,11 +1726,25 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
if (Tok.is(tok::kw___attribute))
return TPResult::True();
+ // If we're disambiguating a template argument in a default argument in
+ // a class definition versus a parameter declaration, an '=' here
+ // disambiguates the parse one way or the other.
+ // If this is a parameter, it must have a default argument because
+ // (a) the previous parameter did, and
+ // (b) this must be the first declaration of the function, so we can't
+ // inherit any default arguments from elsewhere.
+ // If we see an ')', then we've reached the end of a
+ // parameter-declaration-clause, and the last param is missing its default
+ // argument.
+ if (VersusTemplateArgument)
+ return (Tok.is(tok::equal) || Tok.is(tok::r_paren)) ? TPResult::True()
+ : TPResult::False();
+
if (Tok.is(tok::equal)) {
// '=' assignment-expression
// Parse through assignment-expression.
- if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/,
- true/*DontConsume*/))
+ // FIXME: assignment-expression may contain an unparenthesized comma.
+ if (!SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch))
return TPResult::Error();
}
@@ -1554,7 +1788,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
return TPR;
// Parse through the parens.
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
return TPResult::Error();
// cv-qualifier-seq
@@ -1575,7 +1809,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
// Parse through the parens after 'throw'.
ConsumeParen();
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
return TPResult::Error();
}
if (Tok.is(tok::kw_noexcept)) {
@@ -1584,7 +1818,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
if (Tok.is(tok::l_paren)) {
// Find the matching rparen.
ConsumeParen();
- if (!SkipUntil(tok::r_paren))
+ if (!SkipUntil(tok::r_paren, StopAtSemi))
return TPResult::Error();
}
}
@@ -1596,7 +1830,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
///
Parser::TPResult Parser::TryParseBracketDeclarator() {
ConsumeBracket();
- if (!SkipUntil(tok::r_square))
+ if (!SkipUntil(tok::r_square, StopAtSemi))
return TPResult::Error();
return TPResult::Ambiguous();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 455139b881aa..457dd36cbe9b 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -103,8 +103,10 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.AddPragmaHandler(OpenMPHandler.get());
if (getLangOpts().MicrosoftExt) {
- MSCommentHandler.reset(new PragmaCommentHandler());
+ MSCommentHandler.reset(new PragmaCommentHandler(actions));
PP.AddPragmaHandler(MSCommentHandler.get());
+ MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(actions));
+ PP.AddPragmaHandler(MSDetectMismatchHandler.get());
}
CommentSemaHandler.reset(new ActionCommentHandler(actions));
@@ -188,7 +190,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
Diag(Tok, DiagID) << Msg;
if (SkipToTok != tok::unknown)
- SkipUntil(SkipToTok);
+ SkipUntil(SkipToTok, StopAtSemi);
return true;
}
@@ -251,16 +253,19 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
// Error recovery.
//===----------------------------------------------------------------------===//
+static bool HasFlagsSet(Parser::SkipUntilFlags L, Parser::SkipUntilFlags R) {
+ return (static_cast<unsigned>(L) & static_cast<unsigned>(R)) != 0;
+}
+
/// SkipUntil - Read tokens until we get to the specified token, then consume
-/// it (unless DontConsume is true). Because we cannot guarantee that the
+/// it (unless no flag StopBeforeMatch). Because we cannot guarantee that the
/// token will ever occur, this skips to the next token, or to some likely
/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
/// character.
///
/// If SkipUntil finds the specified token, it returns true, otherwise it
/// returns false.
-bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi,
- bool DontConsume, bool StopAtCodeCompletion) {
+bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
// We always want this function to skip at least one token if the first token
// isn't T and if not at EOF.
bool isFirstTokenSkipped = true;
@@ -268,7 +273,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi,
// If we found one of the tokens, stop and return true.
for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) {
if (Tok.is(Toks[i])) {
- if (DontConsume) {
+ if (HasFlagsSet(Flags, StopBeforeMatch)) {
// Noop, don't consume the token.
} else {
ConsumeAnyToken();
@@ -277,30 +282,50 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi,
}
}
+ // Important special case: The caller has given up and just wants us to
+ // skip the rest of the file. Do this without recursing, since we can
+ // get here precisely because the caller detected too much recursion.
+ if (Toks.size() == 1 && Toks[0] == tok::eof &&
+ !HasFlagsSet(Flags, StopAtSemi) &&
+ !HasFlagsSet(Flags, StopAtCodeCompletion)) {
+ while (Tok.getKind() != tok::eof)
+ ConsumeAnyToken();
+ return true;
+ }
+
switch (Tok.getKind()) {
case tok::eof:
// Ran out of tokens.
return false;
case tok::code_completion:
- if (!StopAtCodeCompletion)
+ if (!HasFlagsSet(Flags, StopAtCodeCompletion))
ConsumeToken();
return false;
case tok::l_paren:
// Recursively skip properly-nested parens.
ConsumeParen();
- SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion);
+ if (HasFlagsSet(Flags, StopAtCodeCompletion))
+ SkipUntil(tok::r_paren, StopAtCodeCompletion);
+ else
+ SkipUntil(tok::r_paren);
break;
case tok::l_square:
// Recursively skip properly-nested square brackets.
ConsumeBracket();
- SkipUntil(tok::r_square, false, false, StopAtCodeCompletion);
+ if (HasFlagsSet(Flags, StopAtCodeCompletion))
+ SkipUntil(tok::r_square, StopAtCodeCompletion);
+ else
+ SkipUntil(tok::r_square);
break;
case tok::l_brace:
// Recursively skip properly-nested braces.
ConsumeBrace();
- SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion);
+ if (HasFlagsSet(Flags, StopAtCodeCompletion))
+ SkipUntil(tok::r_brace, StopAtCodeCompletion);
+ else
+ SkipUntil(tok::r_brace);
break;
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
@@ -333,7 +358,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi,
break;
case tok::semi:
- if (StopAtSemi)
+ if (HasFlagsSet(Flags, StopAtSemi))
return false;
// FALL THROUGH.
default:
@@ -410,11 +435,6 @@ Parser::~Parser() {
for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
delete ScopeCache[i];
- // Free LateParsedTemplatedFunction nodes.
- for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin();
- it != LateParsedTemplateMap.end(); ++it)
- delete it->second;
-
// Remove the pragma handlers we installed.
PP.RemovePragmaHandler(AlignHandler.get());
AlignHandler.reset();
@@ -444,6 +464,8 @@ Parser::~Parser() {
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
+ PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
+ MSDetectMismatchHandler.reset();
}
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
@@ -477,6 +499,7 @@ void Parser::Initialize() {
Ident_instancetype = 0;
Ident_final = 0;
+ Ident_sealed = 0;
Ident_override = 0;
Ident_super = &PP.getIdentifierTable().get("super");
@@ -484,6 +507,7 @@ void Parser::Initialize() {
if (getLangOpts().AltiVec) {
Ident_vector = &PP.getIdentifierTable().get("vector");
Ident_pixel = &PP.getIdentifierTable().get("pixel");
+ Ident_bool = &PP.getIdentifierTable().get("bool");
}
Ident_introduced = 0;
@@ -555,19 +579,30 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof))
ConsumeToken();
- while (Tok.is(tok::annot_pragma_unused))
+ Result = DeclGroupPtrTy();
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_unused:
HandlePragmaUnused();
+ return false;
- Result = DeclGroupPtrTy();
- if (Tok.is(tok::eof)) {
+ case tok::annot_module_include:
+ Actions.ActOnModuleInclude(Tok.getLocation(),
+ reinterpret_cast<Module *>(
+ Tok.getAnnotationValue()));
+ ConsumeToken();
+ return false;
+
+ case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
if (!PP.isIncrementalProcessingEnabled())
Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
-
return true;
+
+ default:
+ break;
}
ParsedAttributesWithRange attrs(AttrFactory);
@@ -840,6 +875,12 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
+ // If we had a free-standing type definition with a missing semicolon, we
+ // may get this far before the problem becomes obvious.
+ if (DS.hasTagDefinition() &&
+ DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level))
+ return DeclGroupPtrTy();
+
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
@@ -908,6 +949,26 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
}
}
+
+static inline bool isFunctionDeclaratorRequiringReturnTypeDeduction(
+ const Declarator &D) {
+ if (!D.isFunctionDeclarator() || !D.getDeclSpec().containsPlaceholderType())
+ return false;
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+ unsigned chunkIndex = E - I - 1;
+ const DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
+ if (DeclType.Kind == DeclaratorChunk::Function) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (!FTI.hasTrailingReturnType())
+ return true;
+ QualType TrailingRetType = FTI.getTrailingReturnType().get();
+ return TrailingRetType->getCanonicalTypeInternal()
+ ->getContainedAutoType();
+ }
+ }
+ return false;
+}
+
/// ParseFunctionDefinition - We parsed and verified that the specified
/// Declarator is well formed. If this is a K&R-style function, read the
/// parameters declaration-list, then start the compound-statement.
@@ -956,7 +1017,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
Diag(Tok, diag::err_expected_fn_body);
// Skip over garbage, until we get to '{'. Don't eat the '{'.
- SkipUntil(tok::l_brace, true, true);
+ SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
// If we didn't find the '{', bail out.
if (Tok.isNot(tok::l_brace))
@@ -979,9 +1040,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// In delayed template parsing mode, for function template we consume the
// tokens and store them for late parsing at the end of the translation unit.
- if (getLangOpts().DelayedTemplateParsing &&
- Tok.isNot(tok::equal) &&
- TemplateInfo.Kind == ParsedTemplateInfo::Template) {
+ if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) &&
+ TemplateInfo.Kind == ParsedTemplateInfo::Template &&
+ !D.getDeclSpec().isConstexprSpecified() &&
+ !isFunctionDeclaratorRequiringReturnTypeDeduction(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -993,22 +1055,18 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
D.complete(DP);
D.getMutableDeclSpec().abort();
- if (DP) {
- LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(DP);
+ CachedTokens Toks;
+ LexTemplateFunctionForLateParsing(Toks);
+ if (DP) {
FunctionDecl *FnD = 0;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP))
FnD = FunTmpl->getTemplatedDecl();
else
FnD = cast<FunctionDecl>(DP);
- Actions.CheckForFunctionRedefinition(FnD);
- LateParsedTemplateMap[FnD] = LPT;
- Actions.MarkAsLateParsedTemplate(FnD);
- LexTemplateFunctionForLateParsing(LPT->Toks);
- } else {
- CachedTokens Toks;
- LexTemplateFunctionForLateParsing(Toks);
+ Actions.CheckForFunctionRedefinition(FnD);
+ Actions.MarkAsLateParsedTemplate(FnD, DP, Toks);
}
return DP;
}
@@ -1215,7 +1273,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
if (ExpectAndConsumeSemi(diag::err_expected_semi_declaration)) {
// Skip to end of block or statement
- SkipUntil(tok::semi, true);
+ SkipUntil(tok::semi);
if (Tok.is(tok::semi))
ConsumeToken();
}
@@ -1283,7 +1341,7 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
ExprResult Result(ParseAsmStringLiteral());
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren, true, true);
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
if (EndLoc)
*EndLoc = Tok.getLocation();
ConsumeAnyToken();
@@ -1422,8 +1480,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
return ANK_TemplateName;
}
// Fall through.
+ case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate: {
- // We have a type or function template followed by '<'.
+ // We have a type, variable or function template followed by '<'.
ConsumeToken();
UnqualifiedId Id;
Id.setIdentifier(Name, NameLoc);
@@ -1444,6 +1503,17 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
return ANK_Unresolved;
}
+bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
+ assert(Tok.isNot(tok::identifier));
+ Diag(Tok, diag::ext_keyword_as_ident)
+ << PP.getSpelling(Tok)
+ << DisableKeyword;
+ if (DisableKeyword)
+ Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
+ Tok.setKind(tok::identifier);
+ return true;
+}
+
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
@@ -1473,6 +1543,23 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
&& "Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
+ // MSVC lets you do stuff like:
+ // typename typedef T_::D D;
+ //
+ // We will consume the typedef token here and put it back after we have
+ // parsed the first identifier, transforming it into something more like:
+ // typename T_::D typedef D;
+ if (getLangOpts().MicrosoftMode && NextToken().is(tok::kw_typedef)) {
+ Token TypedefToken;
+ PP.Lex(TypedefToken);
+ bool Result = TryAnnotateTypeOrScopeToken(EnteringContext, NeedType);
+ PP.EnterToken(Tok);
+ Tok = TypedefToken;
+ if (!Result)
+ Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename);
+ return Result;
+ }
+
// Parse a C++ typename-specifier, e.g., "typename T::type".
//
// typename-specifier:
@@ -1491,7 +1578,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
// Attempt to recover by skipping the invalid 'typename'
if (Tok.is(tok::annot_decltype) ||
(!TryAnnotateTypeOrScopeToken(EnteringContext, NeedType) &&
- Tok.isAnnotation())) {
+ Tok.isAnnotation())) {
unsigned DiagID = diag::err_expected_qualified_after_typename;
// MS compatibility: MSVC permits using known types with typename.
// e.g. "typedef typename T* pointer_type"
@@ -1638,7 +1725,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
// annotation token to a type annotation token now.
AnnotateTemplateIdTokenAsType();
return false;
- }
+ } else if (TemplateId->Kind == TNK_Var_template)
+ return false;
}
if (SS.isEmpty())
@@ -1884,7 +1972,13 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
break;
} while (true);
-
+
+ if (PP.hadModuleLoaderFatalFailure()) {
+ // With a fatal failure in the module loader, we abort parsing.
+ cutOffParsing();
+ return DeclGroupPtrTy();
+ }
+
DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
@@ -1927,11 +2021,19 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() {
}
P.Diag(P.Tok, DID);
P.Diag(LOpen, diag::note_matching) << LHSName;
- if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true))
+
+ // If we're not already at some kind of closing bracket, skip to our closing
+ // token.
+ if (P.Tok.isNot(tok::r_paren) && P.Tok.isNot(tok::r_brace) &&
+ P.Tok.isNot(tok::r_square) &&
+ P.SkipUntil(Close, FinalToken,
+ Parser::StopAtSemi | Parser::StopBeforeMatch) &&
+ P.Tok.is(Close))
LClose = P.ConsumeAnyToken();
return true;
}
void BalancedDelimiterTracker::skipToEnd() {
- P.SkipUntil(Close, false);
+ P.SkipUntil(Close, Parser::StopBeforeMatch);
+ consumeClose();
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 213950a6db92..f68a2e09fe91 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -358,7 +358,7 @@ namespace clang {
/// pair, such as braces { ... } or parentheses ( ... ).
class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
Parser& P;
- tok::TokenKind Kind, Close;
+ tok::TokenKind Kind, Close, FinalToken;
SourceLocation (Parser::*Consumer)();
SourceLocation LOpen, LClose;
@@ -377,9 +377,10 @@ namespace clang {
bool diagnoseMissingClose();
public:
- BalancedDelimiterTracker(Parser& p, tok::TokenKind k)
+ BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
+ tok::TokenKind FinalToken = tok::semi)
: GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
- P(p), Kind(k)
+ P(p), Kind(k), FinalToken(FinalToken)
{
switch (Kind) {
default: llvm_unreachable("Unexpected balanced token");
diff --git a/lib/Rewrite/Core/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp
index 2d279f1ee4a1..4da00a8cc97b 100644
--- a/lib/Rewrite/Core/HTMLRewrite.cpp
+++ b/lib/Rewrite/Core/HTMLRewrite.cpp
@@ -164,8 +164,7 @@ void html::EscapeText(Rewriter &R, FileID FID,
}
}
-std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
- bool ReplaceTabs) {
+std::string html::EscapeText(StringRef s, bool EscapeSpaces, bool ReplaceTabs) {
unsigned len = s.size();
std::string Str;
@@ -361,7 +360,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
const SourceManager &SM = PP.getSourceManager();
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
Lexer L(FID, FromFile, SM, PP.getLangOpts());
- const char *BufferStart = L.getBufferStart();
+ const char *BufferStart = L.getBuffer().data();
// Inform the preprocessor that we want to retain comments as tokens, so we
// can highlight them.
diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp
index c1c6595d1622..afb1080c66a1 100644
--- a/lib/Rewrite/Core/Rewriter.cpp
+++ b/lib/Rewrite/Core/Rewriter.cpp
@@ -433,8 +433,7 @@ public:
TempFilename = Filename;
TempFilename += "-%%%%%%%%";
int FD;
- if (llvm::sys::fs::unique_file(TempFilename.str(), FD, TempFilename,
- /*makeAbsolute=*/true, 0664)) {
+ if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) {
AllWritten = false;
Diagnostics.Report(clang::diag::err_unable_to_make_temp)
<< TempFilename;
@@ -463,7 +462,7 @@ public:
}
}
- bool ok() { return FileStream; }
+ bool ok() { return FileStream.isValid(); }
raw_ostream &getStream() { return *FileStream; }
private:
diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp
index 166c607d020e..8930c35d06c4 100644
--- a/lib/Rewrite/Frontend/FixItRewriter.cpp
+++ b/lib/Rewrite/Frontend/FixItRewriter.cpp
@@ -92,7 +92,7 @@ bool FixItRewriter::WriteFixedFiles(
OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
} else {
OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary));
+ llvm::sys::fs::F_Binary));
}
if (!Err.empty()) {
Diags.Report(clang::diag::err_fe_unable_to_open_output)
diff --git a/lib/Rewrite/Frontend/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp
index 9935aeb63e58..e9ec38818265 100644
--- a/lib/Rewrite/Frontend/FrontendActions.cpp
+++ b/lib/Rewrite/Frontend/FrontendActions.cpp
@@ -76,12 +76,10 @@ class FixItRewriteToTemp : public FixItOptions {
public:
std::string RewriteFilename(const std::string &Filename, int &fd) {
SmallString<128> Path;
- Path = llvm::sys::path::filename(Filename);
- Path += "-%%%%%%%%";
- Path += llvm::sys::path::extension(Filename);
- SmallString<128> NewPath;
- llvm::sys::fs::unique_file(Path.str(), fd, NewPath);
- return NewPath.str();
+ llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
+ llvm::sys::path::extension(Filename), fd,
+ Path);
+ return Path.str();
}
};
} // end anonymous namespace
diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 878be84224ae..71ceb5f0b6aa 100644
--- a/lib/Rewrite/Frontend/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,6 +40,7 @@ class InclusionRewriter : public PPCallbacks {
Preprocessor &PP; ///< Used to find inclusion directives.
SourceManager &SM; ///< Used to read and manage source files.
raw_ostream &OS; ///< The destination stream for rewritten contents.
+ const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines.
bool ShowLineMarkers; ///< Show #line markers.
bool UseLineDirective; ///< Use of line directives or line markers.
typedef std::map<unsigned, FileChange> FileChangeMap;
@@ -49,6 +51,9 @@ class InclusionRewriter : public PPCallbacks {
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers);
bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
+ void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
+ PredefinesBuffer = Buf;
+ }
private:
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -88,7 +93,7 @@ private:
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers)
- : PP(PP), SM(PP.getSourceManager()), OS(OS),
+ : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(0),
ShowLineMarkers(ShowLineMarkers),
LastInsertedFileChange(FileChanges.end()) {
// If we're in microsoft mode, use normal #line instead of line markers.
@@ -105,11 +110,15 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
if (!ShowLineMarkers)
return;
if (UseLineDirective) {
- OS << "#line" << ' ' << Line << ' ' << '"' << Filename << '"';
+ OS << "#line" << ' ' << Line << ' ' << '"';
+ OS.write_escaped(Filename);
+ OS << '"';
} else {
// Use GNU linemarkers as described here:
// http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
- OS << '#' << ' ' << Line << ' ' << '"' << Filename << '"';
+ OS << '#' << ' ' << Line << ' ' << '"';
+ OS.write_escaped(Filename);
+ OS << '"';
if (!Extra.empty())
OS << Extra;
if (FileType == SrcMgr::C_System)
@@ -213,6 +222,11 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
bool EnsureNewline) {
if (WriteTo <= WriteFrom)
return;
+ if (&FromFile == PredefinesBuffer) {
+ // Ignore the #defines of the predefines buffer.
+ WriteFrom = WriteTo;
+ return;
+ }
OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom);
// count lines manually, it's faster than getPresumedLoc()
Line += std::count(FromFile.getBufferStart() + WriteFrom,
@@ -328,7 +342,7 @@ bool InclusionRewriter::HandleHasInclude(
return true;
}
-/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it
+/// 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)
@@ -353,6 +367,11 @@ bool InclusionRewriter::Process(FileID FileId,
unsigned NextToWrite = 0;
int Line = 1; // The current input file line number.
+ // Ignore UTF-8 BOM, otherwise it'd end up somewhere else than the start
+ // of the resulting file.
+ if (FromFile.getBuffer().startswith("\xEF\xBB\xBF"))
+ NextToWrite = 3;
+
Token RawToken;
RawLex.LexFromRawLexer(RawToken);
@@ -365,7 +384,7 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
- if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) {
+ if (RawToken.getIdentifierInfo() != NULL) {
switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_include_next:
@@ -412,7 +431,9 @@ bool InclusionRewriter::Process(FileID FileId,
break;
}
case tok::pp_if:
- case tok::pp_elif:
+ case tok::pp_elif: {
+ bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() ==
+ tok::pp_elif);
// Rewrite special builtin macros to avoid pulling in host details.
do {
// Walk over the directive.
@@ -453,8 +474,33 @@ bool InclusionRewriter::Process(FileID FileId,
OS << "*/";
}
} while (RawToken.isNot(tok::eod));
-
+ if (elif) {
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) +
+ RawToken.getLength(),
+ EOL, Line, /*EnsureNewLine*/ true);
+ WriteLineInfo(FileName, Line, FileType, EOL);
+ }
break;
+ }
+ case tok::pp_endif:
+ case tok::pp_else: {
+ // We surround every #include by #if 0 to comment it out, but that
+ // changes line numbers. These are fixed up right after that, but
+ // the whole #include could be inside a preprocessor conditional
+ // that is not processed. So it is necessary to fix the line
+ // numbers one the next line after each #else/#endif as well.
+ RawLex.SetKeepWhitespaceMode(true);
+ do {
+ RawLex.LexFromRawLexer(RawToken);
+ } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof));
+ OutputContentUpTo(
+ FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(),
+ EOL, Line, /*EnsureNewLine*/ true);
+ WriteLineInfo(FileName, Line, FileType, EOL);
+ RawLex.SetKeepWhitespaceMode(false);
+ }
default:
break;
}
@@ -464,7 +510,7 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
}
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(SM.getLocForEndOfFile(FileId)) + 1, EOL, Line,
+ SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line,
/*EnsureNewline*/true);
return true;
}
@@ -476,6 +522,13 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
Opts.ShowLineMarkers);
PP.addPPCallbacks(Rewrite);
+ // Ignore all pragmas, otherwise there will be warnings about unknown pragmas
+ // (because there's nothing to handle them).
+ PP.AddPragmaHandler(new EmptyPragmaHandler());
+ // Ignore also all pragma in all namespaces created
+ // in Preprocessor::RegisterBuiltinPragmas().
+ PP.AddPragmaHandler("GCC", new EmptyPragmaHandler());
+ PP.AddPragmaHandler("clang", new EmptyPragmaHandler());
// First let the preprocessor process the entire file and call callbacks.
// Callbacks will record which #include's were actually performed.
@@ -490,6 +543,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
+ Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
+ Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User);
OS->flush();
}
diff --git a/lib/Rewrite/Frontend/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp
index 3c1d2e11903d..4f6a93f7e0eb 100644
--- a/lib/Rewrite/Frontend/RewriteMacros.cpp
+++ b/lib/Rewrite/Frontend/RewriteMacros.cpp
@@ -115,7 +115,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation());
// If PPTok is from a different source file, ignore it.
- if (!SM.isFromMainFile(PPLoc)) {
+ if (!SM.isWrittenInMainFile(PPLoc)) {
PP.Lex(PPTok);
continue;
}
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index 0e59b113c965..ae33ac816e3d 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -58,7 +58,6 @@ namespace {
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};
- static const int OBJC_ABI_VERSION = 7;
Rewriter Rewrite;
DiagnosticsEngine &Diags;
@@ -103,7 +102,7 @@ namespace {
FunctionDecl *GetSuperClassFunctionDecl;
FunctionDecl *SelGetUidFunctionDecl;
FunctionDecl *CFStringFunctionDecl;
- FunctionDecl *SuperContructorFunctionDecl;
+ FunctionDecl *SuperConstructorFunctionDecl;
FunctionDecl *CurFunctionDef;
/* Misc. containers needed for meta-data rewrite. */
@@ -222,6 +221,21 @@ namespace {
}
return true;
}
+
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(*I)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ else
+ RewriteObjCQualifiedInterfaceTypes(TD);
+ }
+ }
+ return;
+ }
+
void HandleTopLevelSingleDecl(Decl *D);
void HandleDeclInMainFile(Decl *D);
RewriteModernObjC(std::string inFile, raw_ostream *OS,
@@ -307,7 +321,7 @@ namespace {
void ConvertSourceLocationToLineDirective(SourceLocation Loc,
std::string &LineString);
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -325,7 +339,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -411,7 +425,6 @@ namespace {
SourceLocation EndLoc=SourceLocation());
Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor,
- QualType msgSendType,
QualType returnType,
SmallVectorImpl<QualType> &ArgTypes,
SmallVectorImpl<Expr*> &MsgExprs,
@@ -431,7 +444,7 @@ namespace {
void SynthGetMetaClassFunctionDecl();
void SynthGetSuperClassFunctionDecl();
void SynthSelGetUidFunctionDecl();
- void SynthSuperContructorFunctionDecl();
+ void SynthSuperConstructorFunctionDecl();
// Rewriting metadata
template<typename MethodIterator>
@@ -478,7 +491,7 @@ namespace {
StringRef FunName);
FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
Stmt *SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs);
+ const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs);
// Misc. helper routines.
QualType getProtocolType();
@@ -490,8 +503,8 @@ namespace {
bool IsDeclStmtInForeachHeader(DeclStmt *DS);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
void GetBlockDeclRefExprs(Stmt *S);
- void GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+ void GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
@@ -686,7 +699,7 @@ void RewriteModernObjC::InitializeCommon(ASTContext &context) {
ProtocolTypeDecl = 0;
ConstantStringDecl = 0;
BcLabelCount = 0;
- SuperContructorFunctionDecl = 0;
+ SuperConstructorFunctionDecl = 0;
NumObjCStringLiterals = 0;
PropParentMap = 0;
CurrentBody = 0;
@@ -791,7 +804,7 @@ void RewriteModernObjC::HandleTopLevelSingleDecl(Decl *D) {
}
}
// If we have a decl in the main file, see if we should rewrite it.
- if (SM->isFromMainFile(Loc))
+ if (SM->isWrittenInMainFile(Loc))
return HandleDeclInMainFile(D);
}
@@ -1068,23 +1081,26 @@ void RewriteModernObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl
void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
std::string typedefString;
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
- ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I);
- if (I == D.begin()) {
- // Translate to typedef's that forward reference structs with the same name
- // as the class. As a convenience, we include the original declaration
- // as a comment.
- typedefString += "// @class ";
- typedefString += ForwardDecl->getNameAsString();
- typedefString += ";";
+ if (ObjCInterfaceDecl *ForwardDecl = dyn_cast<ObjCInterfaceDecl>(*I)) {
+ if (I == D.begin()) {
+ // Translate to typedef's that forward reference structs with the same name
+ // as the class. As a convenience, we include the original declaration
+ // as a comment.
+ typedefString += "// @class ";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";";
+ }
+ RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
- RewriteOneForwardClassDecl(ForwardDecl, typedefString);
+ else
+ HandleTopLevelSingleDecl(*I);
}
DeclGroupRef::iterator I = D.begin();
RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
void RewriteModernObjC::RewriteForwardClassDecl(
- const SmallVector<Decl *, 8> &D) {
+ const SmallVectorImpl<Decl *> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
@@ -1202,7 +1218,7 @@ void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteModernObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
+RewriteModernObjC::RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -1618,23 +1634,23 @@ Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseud
}
/// SynthCountByEnumWithState - To print:
-/// ((unsigned int (*)
-/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+/// ((NSUInteger (*)
+/// (id, SEL, struct __objcFastEnumerationState *, id *, NSUInteger))
/// (void *)objc_msgSend)((id)l_collection,
/// sel_registerName(
/// "countByEnumeratingWithState:objects:count:"),
/// &enumState,
-/// (id *)__rw_items, (unsigned int)16)
+/// (id *)__rw_items, (NSUInteger)16)
///
void RewriteModernObjC::SynthCountByEnumWithState(std::string &buf) {
- buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
- "id *, unsigned int))(void *)objc_msgSend)";
+ buf += "((_WIN_NSUInteger (*) (id, SEL, struct __objcFastEnumerationState *, "
+ "id *, _WIN_NSUInteger))(void *)objc_msgSend)";
buf += "\n\t\t";
buf += "((id)l_collection,\n\t\t";
buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
buf += "\n\t\t";
buf += "&enumState, "
- "(id *)__rw_items, (unsigned int)16)";
+ "(id *)__rw_items, (_WIN_NSUInteger)16)";
}
/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
@@ -1694,7 +1710,7 @@ Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) {
/// struct __objcFastEnumerationState enumState = { 0 };
/// id __rw_items[16];
/// id l_collection = (id)collection;
-/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+/// NSUInteger limit = [l_collection countByEnumeratingWithState:&enumState
/// objects:__rw_items count:16];
/// if (limit) {
/// unsigned long startMutations = *enumState.mutationsPtr;
@@ -1707,8 +1723,8 @@ Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) {
/// stmts;
/// __continue_label: ;
/// } while (counter < limit);
-/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
-/// objects:__rw_items count:16]);
+/// } while ((limit = [l_collection countByEnumeratingWithState:&enumState
+/// objects:__rw_items count:16]));
/// elem = nil;
/// __break_label: ;
/// }
@@ -1791,15 +1807,15 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
// objects:__rw_items count:16];
// which is synthesized into:
- // unsigned int limit =
- // ((unsigned int (*)
- // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+ // NSUInteger limit =
+ // ((NSUInteger (*)
+ // (id, SEL, struct __objcFastEnumerationState *, id *, NSUInteger))
// (void *)objc_msgSend)((id)l_collection,
// sel_registerName(
// "countByEnumeratingWithState:objects:count:"),
// (struct __objcFastEnumerationState *)&state,
- // (id *)__rw_items, (unsigned int)16);
- buf += "unsigned long limit =\n\t\t";
+ // (id *)__rw_items, (NSUInteger)16);
+ buf += "_WIN_NSUInteger limit =\n\t\t";
SynthCountByEnumWithState(buf);
buf += ";\n\t";
/// if (limit) {
@@ -1826,8 +1842,8 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
/// __continue_label: ;
/// } while (counter < limit);
- /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
- /// objects:__rw_items count:16]);
+ /// } while ((limit = [l_collection countByEnumeratingWithState:&enumState
+ /// objects:__rw_items count:16]));
/// elem = nil;
/// __break_label: ;
/// }
@@ -1841,9 +1857,9 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
buf += ": ;";
buf += "\n\t\t";
buf += "} while (counter < limit);\n\t";
- buf += "} while (limit = ";
+ buf += "} while ((limit = ";
SynthCountByEnumWithState(buf);
- buf += ");\n\t";
+ buf += "));\n\t";
buf += elementName;
buf += " = ((";
buf += elementTypeAsString;
@@ -1906,7 +1922,7 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
std::string buf;
SourceLocation SynchLoc = S->getAtSynchronizedLoc();
ConvertSourceLocationToLineDirective(SynchLoc, buf);
- buf += "{ id _rethrow = 0; id _sync_obj = ";
+ buf += "{ id _rethrow = 0; id _sync_obj = (id)";
const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++;
@@ -2447,9 +2463,9 @@ void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
InsertText(FunLocStart, FdStr);
}
-// SynthSuperContructorFunctionDecl - id __rw_objc_super(id obj, id super);
-void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
- if (SuperContructorFunctionDecl)
+// SynthSuperConstructorFunctionDecl - id __rw_objc_super(id obj, id super);
+void RewriteModernObjC::SynthSuperConstructorFunctionDecl() {
+ if (SuperConstructorFunctionDecl)
return;
IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");
SmallVector<QualType, 16> ArgTys;
@@ -2459,7 +2475,7 @@ void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
ArgTys);
- SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SuperConstructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
msgSendIdent, msgSendType,
@@ -3183,7 +3199,6 @@ void RewriteModernObjC::RewriteLineDirective(const Decl *D) {
/// starting with receiver.
/// Method - Method being rewritten.
Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor,
- QualType msgSendType,
QualType returnType,
SmallVectorImpl<QualType> &ArgTypes,
SmallVectorImpl<Expr*> &MsgExprs,
@@ -3199,6 +3214,7 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
std::string name = "__Stret"; name += utostr(stretCount);
std::string str =
"extern \"C\" void * __cdecl memset(void *_Dst, int _Val, size_t _Size);\n";
+ str += "namespace {\n";
str += "struct "; str += name;
str += " {\n\t";
str += name;
@@ -3217,9 +3233,27 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
}
str += ") {\n";
- str += "\t if (receiver == 0)\n";
+ str += "\t unsigned size = sizeof(";
+ str += returnType.getAsString(Context->getPrintingPolicy()); str += ");\n";
+
+ str += "\t if (size == 1 || size == 2 || size == 4 || size == 8)\n";
+
+ str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy());
+ str += ")(void *)objc_msgSend)(receiver, sel";
+ for (unsigned i = 2; i < ArgTypes.size(); i++) {
+ str += ", arg"; str += utostr(i);
+ }
+ // could be vararg.
+ for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) {
+ str += ", arg"; str += utostr(i);
+ }
+ str+= ");\n";
+
+ str += "\t else if (receiver == 0)\n";
str += "\t memset((void*)&s, 0, sizeof(s));\n";
str += "\t else\n";
+
+
str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy());
str += ")(void *)objc_msgSend_stret)(receiver, sel";
for (unsigned i = 2; i < ArgTypes.size(); i++) {
@@ -3229,12 +3263,13 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) {
str += ", arg"; str += utostr(i);
}
-
str += ");\n";
+
+
str += "\t}\n";
str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy());
str += " s;\n";
- str += "};\n\n";
+ str += "};\n};\n\n";
SourceLocation FunLocStart;
if (CurFunctionDef)
FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef);
@@ -3357,9 +3392,9 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Expr *SuperRep;
if (LangOpts.MicrosoftExt) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ SynthSuperConstructorFunctionDecl();
+ // Simulate a constructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
@@ -3465,9 +3500,9 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Expr *SuperRep;
if (LangOpts.MicrosoftExt) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ SynthSuperConstructorFunctionDecl();
+ // Simulate a constructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
@@ -3651,39 +3686,11 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// expression which dictate which one to envoke depending on size of
// method's return type.
- Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor,
- msgSendType, returnType,
+ Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor,
+ returnType,
ArgTypes, MsgExprs,
Exp->getMethodDecl());
-
- // Build sizeof(returnType)
- UnaryExprOrTypeTraitExpr *sizeofExpr =
- new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf,
- Context->getTrivialTypeSourceInfo(returnType),
- Context->getSizeType(), SourceLocation(),
- SourceLocation());
- // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
- // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
- // For X86 it is more complicated and some kind of target specific routine
- // is needed to decide what to do.
- unsigned IntSize =
- static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
- IntegerLiteral *limit = IntegerLiteral::Create(*Context,
- llvm::APInt(IntSize, 8),
- Context->IntTy,
- SourceLocation());
- BinaryOperator *lessThanExpr =
- new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
- VK_RValue, OK_Ordinary, SourceLocation(),
- false);
- // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
- ConditionalOperator *CondExpr =
- new (Context) ConditionalOperator(lessThanExpr,
- SourceLocation(), CE,
- SourceLocation(), STCE,
- returnType, VK_RValue, OK_Ordinary);
- ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
- CondExpr);
+ ReplacingStmt = STCE;
}
// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
return ReplacingStmt;
@@ -4262,7 +4269,7 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -4273,7 +4280,7 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
// Handle nested closure invocation. For example:
@@ -4374,7 +4381,7 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Ta
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -4403,7 +4410,7 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Ta
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -4422,7 +4429,7 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Ta
Constructor += ", int flags=0)";
// Initialize all "by copy" arguments.
bool firsTime = true;
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -4437,7 +4444,7 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Ta
Constructor += Name + "(_" + Name + ")";
}
// Initialize all "by ref" arguments.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -4662,8 +4669,8 @@ void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) {
return;
}
-void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
@@ -5407,7 +5414,7 @@ FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) {
}
Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs) {
+ const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs) {
const BlockDecl *block = Exp->getBlockDecl();
@@ -5474,7 +5481,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
FunctionDecl *FD;
Expr *NewRep;
- // Simulate a contructor call...
+ // Simulate a constructor call...
std::string Tag;
if (GlobalBlockExpr)
@@ -5520,7 +5527,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
@@ -5554,7 +5561,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
ValueDecl *ND = (*I);
std::string Name(ND->getNameAsString());
@@ -6166,6 +6173,11 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);\n";
Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);\n";
Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+ Preamble += "#ifdef _WIN64\n";
+ Preamble += "typedef unsigned long long _WIN_NSUInteger;\n";
+ Preamble += "#else\n";
+ Preamble += "typedef unsigned int _WIN_NSUInteger;\n";
+ Preamble += "#endif\n";
Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
Preamble += "struct __objcFastEnumerationState {\n\t";
Preamble += "unsigned long state;\n\t";
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index 2f5cd0f6c6c6..3dda2c56f5dc 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -100,7 +100,7 @@ namespace {
FunctionDecl *GetSuperClassFunctionDecl;
FunctionDecl *SelGetUidFunctionDecl;
FunctionDecl *CFStringFunctionDecl;
- FunctionDecl *SuperContructorFunctionDecl;
+ FunctionDecl *SuperConstructorFunctionDecl;
FunctionDecl *CurFunctionDef;
FunctionDecl *CurFunctionDeclToDeclareForBlock;
@@ -267,7 +267,7 @@ namespace {
void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -285,7 +285,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -377,7 +377,7 @@ namespace {
void SynthGetMetaClassFunctionDecl();
void SynthGetSuperClassFunctionDecl();
void SynthSelGetUidFunctionDecl();
- void SynthSuperContructorFunctionDecl();
+ void SynthSuperConstructorFunctionDecl();
std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
@@ -395,7 +395,7 @@ namespace {
StringRef FunName);
FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
Stmt *SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs);
+ const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs);
// Misc. helper routines.
QualType getProtocolType();
@@ -408,8 +408,8 @@ namespace {
bool IsDeclStmtInForeachHeader(DeclStmt *DS);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
void GetBlockDeclRefExprs(Stmt *S);
- void GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+ void GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
@@ -623,7 +623,7 @@ void RewriteObjC::InitializeCommon(ASTContext &context) {
ProtocolTypeDecl = 0;
ConstantStringDecl = 0;
BcLabelCount = 0;
- SuperContructorFunctionDecl = 0;
+ SuperConstructorFunctionDecl = 0;
NumObjCStringLiterals = 0;
PropParentMap = 0;
CurrentBody = 0;
@@ -721,7 +721,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
}
}
// If we have a decl in the main file, see if we should rewrite it.
- if (SM->isFromMainFile(Loc))
+ if (SM->isWrittenInMainFile(Loc))
return HandleDeclInMainFile(D);
}
@@ -926,7 +926,7 @@ void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
-void RewriteObjC::RewriteForwardClassDecl(const SmallVector<Decl *, 8> &D) {
+void RewriteObjC::RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
@@ -1038,7 +1038,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
+RewriteObjC::RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -2347,9 +2347,9 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
CurFunctionDeclToDeclareForBlock = 0;
}
-// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super);
-void RewriteObjC::SynthSuperContructorFunctionDecl() {
- if (SuperContructorFunctionDecl)
+// SynthSuperConstructorFunctionDecl - id objc_super(id obj, id super);
+void RewriteObjC::SynthSuperConstructorFunctionDecl() {
+ if (SuperConstructorFunctionDecl)
return;
IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");
SmallVector<QualType, 16> ArgTys;
@@ -2359,7 +2359,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
ArgTys);
- SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SuperConstructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
msgSendIdent, msgSendType,
@@ -2746,9 +2746,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Expr *SuperRep;
if (LangOpts.MicrosoftExt) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ SynthSuperConstructorFunctionDecl();
+ // Simulate a constructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
@@ -2854,9 +2854,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Expr *SuperRep;
if (LangOpts.MicrosoftExt) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ SynthSuperConstructorFunctionDecl();
+ // Simulate a constructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
@@ -3366,7 +3366,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3377,7 +3377,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
// Handle nested closure invocation. For example:
@@ -3478,7 +3478,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3507,7 +3507,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3526,7 +3526,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += ", int flags=0)";
// Initialize all "by copy" arguments.
bool firsTime = true;
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -3541,7 +3541,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + "(_" + Name + ")";
}
// Initialize all "by ref" arguments.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -3743,8 +3743,8 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
return;
}
-void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
@@ -4452,7 +4452,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs) {
+ const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs) {
const BlockDecl *block = Exp->getBlockDecl();
Blocks.push_back(Exp);
@@ -4510,7 +4510,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
FunctionDecl *FD;
Expr *NewRep;
- // Simulate a contructor call...
+ // Simulate a constructor call...
FD = SynthBlockInitFunctionDecl(Tag);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue,
SourceLocation());
@@ -4548,7 +4548,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
@@ -4582,7 +4582,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
ValueDecl *ND = (*I);
std::string Name(ND->getNameAsString());
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 1295339aa332..93e3ecfb2947 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
@@ -438,22 +439,22 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
<< FixItHint::CreateInsertion(VD->getLocation(), "__block ");
return true;
}
-
+
// Don't issue a fixit if there is already an initializer.
if (VD->getInit())
return false;
-
- // Suggest possible initialization (if any).
- std::string Init = S.getFixItZeroInitializerForType(VariableTy);
- if (Init.empty())
- return false;
// Don't suggest a fixit inside macros.
if (VD->getLocEnd().isMacroID())
return false;
SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
-
+
+ // Suggest possible initialization (if any).
+ std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
+ if (Init.empty())
+ return false;
+
S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
<< FixItHint::CreateInsertion(Loc, Init);
return true;
@@ -492,6 +493,31 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
bool IsCapturedByBlock) {
bool Diagnosed = false;
+ switch (Use.getKind()) {
+ case UninitUse::Always:
+ S.Diag(Use.getUser()->getLocStart(), diag::warn_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock
+ << Use.getUser()->getSourceRange();
+ return;
+
+ case UninitUse::AfterDecl:
+ case UninitUse::AfterCall:
+ S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock
+ << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5)
+ << const_cast<DeclContext*>(VD->getLexicalDeclContext())
+ << VD->getSourceRange();
+ S.Diag(Use.getUser()->getLocStart(), diag::note_uninit_var_use)
+ << IsCapturedByBlock << Use.getUser()->getSourceRange();
+ return;
+
+ case UninitUse::Maybe:
+ case UninitUse::Sometimes:
+ // Carry on to report sometimes-uninitialized branches, if possible,
+ // or a 'may be used uninitialized' diagnostic otherwise.
+ break;
+ }
+
// Diagnose each branch which leads to a sometimes-uninitialized use.
for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();
I != E; ++I) {
@@ -514,14 +540,10 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
: (I->Output ? "1" : "0");
FixItHint Fixit1, Fixit2;
- switch (Term->getStmtClass()) {
+ switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
default:
// Don't know how to report this. Just fall back to 'may be used
- // uninitialized'. This happens for range-based for, which the user
- // can't explicitly fix.
- // FIXME: This also happens if the first use of a variable is always
- // uninitialized, eg "for (int n; n < 10; ++n)". We should report that
- // with the 'is uninitialized' diagnostic.
+ // uninitialized'. FIXME: Can this happen?
continue;
// "condition is true / condition is false".
@@ -582,6 +604,17 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
else
Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
break;
+ case Stmt::CXXForRangeStmtClass:
+ if (I->Output == 1) {
+ // The use occurs if a range-based for loop's body never executes.
+ // That may be impossible, and there's no syntactic fix for this,
+ // so treat it as a 'may be uninitialized' case.
+ continue;
+ }
+ DiagKind = 1;
+ Str = "for";
+ Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
+ break;
// "condition is true / loop is exited".
case Stmt::DoStmtClass:
@@ -618,9 +651,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
}
if (!Diagnosed)
- S.Diag(Use.getUser()->getLocStart(),
- Use.getKind() == UninitUse::Always ? diag::warn_uninit_var
- : diag::warn_maybe_uninit_var)
+ S.Diag(Use.getUser()->getLocStart(), diag::warn_maybe_uninit_var)
<< VD->getDeclName() << IsCapturedByBlock
<< Use.getUser()->getSourceRange();
}
@@ -1123,7 +1154,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Show the first time the object was read.
S.Diag(FirstRead->getLocStart(), DiagKind)
- << ObjectKind << D << FunctionKind
+ << int(ObjectKind) << D << int(FunctionKind)
<< FirstRead->getSourceRange();
// Print all the other accesses as notes.
@@ -1154,7 +1185,7 @@ struct SLocSort {
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
typedef SmallVector<UninitUse, 2> UsesVec;
- typedef std::pair<UsesVec*, bool> MappedType;
+ typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
// Prefer using MapVector to DenseMap, so that iteration order will be
// the same as insertion order. This is needed to obtain a deterministic
// order of diagnostics when calling flushDiagnostics().
@@ -1172,19 +1203,18 @@ public:
uses = new UsesMap();
MappedType &V = (*uses)[vd];
- UsesVec *&vec = V.first;
- if (!vec)
- vec = new UsesVec();
+ if (!V.getPointer())
+ V.setPointer(new UsesVec());
return V;
}
void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) {
- getUses(vd).first->push_back(use);
+ getUses(vd).getPointer()->push_back(use);
}
void handleSelfInit(const VarDecl *vd) {
- getUses(vd).second = true;
+ getUses(vd).setInt(true);
}
void flushDiagnostics() {
@@ -1195,8 +1225,8 @@ public:
const VarDecl *vd = i->first;
const MappedType &V = i->second;
- UsesVec *vec = V.first;
- bool hasSelfInit = V.second;
+ UsesVec *vec = V.getPointer();
+ bool hasSelfInit = V.getInt();
// Specially handle the case where we have uses of an uninitialized
// variable, but the root cause is an idiomatic self-init. We want
@@ -1233,7 +1263,9 @@ public:
private:
static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
for (UsesVec::const_iterator i = vec->begin(), e = vec->end(); i != e; ++i) {
- if (i->getKind() == UninitUse::Always) {
+ if (i->getKind() == UninitUse::Always ||
+ i->getKind() == UninitUse::AfterCall ||
+ i->getKind() == UninitUse::AfterDecl) {
return true;
}
}
@@ -1242,12 +1274,8 @@ private:
};
}
-
-//===----------------------------------------------------------------------===//
-// -Wthread-safety
-//===----------------------------------------------------------------------===//
namespace clang {
-namespace thread_safety {
+namespace {
typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
typedef std::list<DelayedDiag> DiagList;
@@ -1262,7 +1290,13 @@ struct SortDiagBySourceLocation {
return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
}
};
+}}
+//===----------------------------------------------------------------------===//
+// -Wthread-safety
+//===----------------------------------------------------------------------===//
+namespace clang {
+namespace thread_safety {
namespace {
class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
Sema &S;
@@ -1413,6 +1447,102 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
}
//===----------------------------------------------------------------------===//
+// -Wconsumed
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace consumed {
+namespace {
+class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
+
+ Sema &S;
+ DiagList Warnings;
+
+public:
+
+ ConsumedWarningsHandler(Sema &S) : S(S) {}
+
+ void emitDiagnostics() {
+ Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
+
+ for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
+ I != E; ++I) {
+
+ const OptionalNotes &Notes = I->second;
+ S.Diag(I->first.first, I->first.second);
+
+ for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI) {
+ S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+ }
+ }
+ }
+
+ void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName) {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
+ VariableName);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_return_typestate_mismatch) << VariableName <<
+ ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
+ StringRef TypeName) {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_for_unconsumable_type) << TypeName);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
+ SourceLocation Loc) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
+ StringRef State, SourceLocation Loc) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
+ MethodName << VariableName << State);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+};
+}}}
+
+//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
@@ -1421,6 +1551,7 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
enableCheckUnreachable = 0;
enableThreadSafetyAnalysis = 0;
+ enableConsumedAnalysis = 0;
}
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
@@ -1441,7 +1572,9 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
(D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
DiagnosticsEngine::Ignored);
-
+ DefaultPolicy.enableConsumedAnalysis = (unsigned)
+ (D.getDiagnosticLevel(diag::warn_use_in_invalid_state, SourceLocation()) !=
+ DiagnosticsEngine::Ignored);
}
static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
@@ -1486,10 +1619,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
const Stmt *Body = D->getBody();
assert(Body);
+ // Construct the analysis context with the specified CFG build options.
AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D);
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
- // explosion for destrutors that can result and the compile time hit.
+ // explosion for destructors that can result and the compile time hit.
AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
AC.getCFGBuildOptions().AddEHEdges = false;
AC.getCFGBuildOptions().AddInitializers = true;
@@ -1502,7 +1636,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// prototyping, but we need a way for analyses to say what expressions they
// expect to always be CFGElements and then fill in the BuildOptions
// appropriately. This is essentially a layering violation.
- if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {
+ if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
+ P.enableConsumedAnalysis) {
// Unreachable code analysis and thread safety require a linearized CFG.
AC.getCFGBuildOptions().setAllAlwaysAdd();
}
@@ -1518,8 +1653,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
- // Construct the analysis context with the specified CFG build options.
-
+
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
bool analyzed = false;
@@ -1606,6 +1740,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
Reporter.emitDiagnostics();
}
+ // Check for violations of consumed properties.
+ if (P.enableConsumedAnalysis) {
+ consumed::ConsumedWarningsHandler WarningHandler(S);
+ consumed::ConsumedAnalyzer Analyzer(WarningHandler);
+ Analyzer.run(AC);
+ }
+
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
!= DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 9ac4c63e191e..c9807723f064 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -19,13 +19,21 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
+IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
+ IdentifierInfo *Ident) {
+ IdentifierLoc *Result = new (Ctx) IdentifierLoc;
+ Result->Loc = Loc;
+ Result->Ident = Ident;
+ return Result;
+}
+
size_t AttributeList::allocated_size() const {
if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
else if (IsTypeTagForDatatype)
return AttributeFactory::TypeTagForDatatypeAllocSize;
else if (IsProperty)
return AttributeFactory::PropertyAllocSize;
- return (sizeof(AttributeList) + NumArgs * sizeof(Expr*));
+ return (sizeof(AttributeList) + NumArgs * sizeof(ArgsUnion));
}
AttributeFactory::AttributeFactory() {
@@ -98,10 +106,9 @@ void AttributePool::takePool(AttributeList *pool) {
AttributeList *
AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
SourceLocation TokLoc, int Arg) {
- Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
+ ArgsUnion IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
C.IntTy, TokLoc);
- return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1,
- AttributeList::AS_GNU);
+ return create(Name, TokLoc, 0, TokLoc, &IArg, 1, AttributeList::AS_GNU);
}
#include "clang/Sema/AttrParsedAttrKinds.inc"
@@ -138,3 +145,28 @@ unsigned AttributeList::getAttributeSpellingListIndex() const {
}
+struct ParsedAttrInfo {
+ unsigned NumArgs : 4;
+ unsigned OptArgs : 4;
+ unsigned HasCustomParsing : 1;
+};
+
+namespace {
+ #include "clang/Sema/AttrParsedAttrImpl.inc"
+}
+
+static const ParsedAttrInfo &getInfo(const AttributeList &A) {
+ return AttrInfoMap[A.getKind()];
+}
+
+unsigned AttributeList::getMinArgs() const {
+ return getInfo(*this).NumArgs;
+}
+
+unsigned AttributeList::getMaxArgs() const {
+ return getMinArgs() + getInfo(*this).OptArgs;
+}
+
+bool AttributeList::hasCustomParsing() const {
+ return getInfo(*this).HasCustomParsing;
+}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index e92f76713422..5e0914086c28 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -51,6 +51,7 @@ add_clang_library(clangSema
SemaTemplateVariadic.cpp
SemaType.cpp
TargetAttributesSema.cpp
+ TypeLocBuilder.cpp
)
add_dependencies(clangSema
@@ -59,6 +60,7 @@ add_dependencies(clangSema
ClangAttrList
ClangAttrParsedAttrList
ClangAttrParsedAttrKinds
+ ClangAttrParsedAttrImpl
ClangAttrSpellingListIndex
ClangAttrTemplateInstantiate
ClangCommentNodes
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 3b3ab2c27b4a..c2f16157b8eb 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
@@ -325,6 +326,19 @@ bool Declarator::isDeclarationOfFunction() const {
llvm_unreachable("Invalid TypeSpecType!");
}
+bool Declarator::isStaticMember() {
+ assert(getContext() == MemberContext);
+ return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+ CXXMethodDecl::isStaticOverloadedOperator(
+ getName().OperatorFunctionId.Operator);
+}
+
+bool DeclSpec::hasTagDefinition() const {
+ if (!TypeSpecOwned)
+ return false;
+ return cast<TagDecl>(getRepAsDecl())->isCompleteDefinition();
+}
+
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
/// declaration specifier includes.
///
@@ -341,7 +355,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
Res |= PQ_TypeSpecifier;
if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
- FS_noreturn_specified)
+ FS_noreturn_specified || FS_forceinline_specified)
Res |= PQ_FunctionSpecifier;
return Res;
}
@@ -651,7 +665,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
DeclRep = Rep;
TSTLoc = TagKwLoc;
TSTNameLoc = TagNameLoc;
- TypeSpecOwned = Owned;
+ TypeSpecOwned = Owned && Rep != 0;
return false;
}
@@ -707,6 +721,20 @@ bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
return false;
}
+bool DeclSpec::SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID) {
+ if (!TypeAltiVecVector || TypeAltiVecBool ||
+ (TypeSpecType != TST_unspecified)) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_vector_bool_decl_spec;
+ return true;
+ }
+ TypeAltiVecBool = isAltiVecBool;
+ TSTLoc = Loc;
+ TSTNameLoc = Loc;
+ return false;
+}
+
bool DeclSpec::SetTypeSpecError() {
TypeSpecType = TST_error;
TypeSpecOwned = false;
@@ -717,9 +745,10 @@ bool DeclSpec::SetTypeSpecError() {
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, const LangOptions &Lang) {
- // Duplicates are permitted in C99, but are not permitted in C++. However,
- // since this is likely not what the user intended, we will always warn. We
- // do not need to set the qualifier's location since we already have it.
+ // Duplicates are permitted in C99 onwards, but are not permitted in C89 or
+ // C++. However, since this is likely not what the user intended, we will
+ // always warn. We do not need to set the qualifier's location since we
+ // already have it.
if (TypeQualifiers & T) {
bool IsExtension = true;
if (Lang.C99)
@@ -739,29 +768,72 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
llvm_unreachable("Unknown type qualifier!");
}
-bool DeclSpec::setFunctionSpecInline(SourceLocation Loc) {
- // 'inline inline' is ok.
+bool DeclSpec::setFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
+ // 'inline inline' is ok. However, since this is likely not what the user
+ // intended, we will always warn, similar to duplicates of type qualifiers.
+ if (FS_inline_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "inline";
+ return true;
+ }
FS_inline_specified = true;
FS_inlineLoc = Loc;
return false;
}
-bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc) {
- // 'virtual virtual' is ok.
+bool DeclSpec::setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
+ if (FS_forceinline_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "__forceinline";
+ return true;
+ }
+ FS_forceinline_specified = true;
+ FS_forceinlineLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
+ // 'virtual virtual' is ok, but warn as this is likely not what the user
+ // intended.
+ if (FS_virtual_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "virtual";
+ return true;
+ }
FS_virtual_specified = true;
FS_virtualLoc = Loc;
return false;
}
-bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc) {
- // 'explicit explicit' is ok.
+bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
+ // 'explicit explicit' is ok, but warn as this is likely not what the user
+ // intended.
+ if (FS_explicit_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "explicit";
+ return true;
+ }
FS_explicit_specified = true;
FS_explicitLoc = Loc;
return false;
}
-bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc) {
- // '_Noreturn _Noreturn' is ok.
+bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc,
+ const char *&PrevSpec,
+ unsigned &DiagID) {
+ // '_Noreturn _Noreturn' is ok, but warn as this is likely not what the user
+ // intended.
+ if (FS_noreturn_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "_Noreturn";
+ return true;
+ }
FS_noreturn_specified = true;
FS_noreturnLoc = Loc;
return false;
@@ -1096,6 +1168,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
switch (VS) {
default: llvm_unreachable("Unknown specifier!");
case VS_Override: VS_overrideLoc = Loc; break;
+ case VS_Sealed:
case VS_Final: VS_finalLoc = Loc; break;
}
@@ -1107,5 +1180,6 @@ const char *VirtSpecifiers::getSpecifierName(Specifier VS) {
default: llvm_unreachable("Unknown specifier");
case VS_Override: return "override";
case VS_Final: return "final";
+ case VS_Sealed: return "sealed";
}
}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index d44c1fb926f5..6e354b9060e3 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -78,19 +78,6 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
llvm_unreachable("Didn't find this decl on its identifier's chain!");
}
-bool
-IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
- for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
- if (Old == *(I-1)) {
- *(I - 1) = New;
- return true;
- }
- }
-
- return false;
-}
-
-
//===----------------------------------------------------------------------===//
// IdentifierResolver Implementation
//===----------------------------------------------------------------------===//
@@ -113,8 +100,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
// Ignore the scopes associated within transparent declaration contexts.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext())
+ while (S->getEntity() && S->getEntity()->isTransparentContext())
S = S->getParent();
if (S->isDeclScope(D))
@@ -235,30 +221,6 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
return toIdDeclInfo(Ptr)->RemoveDecl(D);
}
-bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
- assert(Old->getDeclName() == New->getDeclName() &&
- "Cannot replace a decl with another decl of a different name");
-
- DeclarationName Name = Old->getDeclName();
- if (IdentifierInfo *II = Name.getAsIdentifierInfo())
- updatingIdentifier(*II);
-
- void *Ptr = Name.getFETokenInfo<void>();
-
- if (!Ptr)
- return false;
-
- if (isDeclPtr(Ptr)) {
- if (Ptr == Old) {
- Name.setFETokenInfo(New);
- return true;
- }
- return false;
- }
-
- return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
-}
-
/// begin - Returns an iterator for decls with name 'Name'.
IdentifierResolver::iterator
IdentifierResolver::begin(DeclarationName Name) {
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 5f92cfffc6b0..d3de1732766e 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -175,8 +175,9 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
const MaterializeTemporaryExpr *M = NULL;
Init = Init->findMaterializedTemporary(M);
+ SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- Init = Init->skipRValueSubobjectAdjustments(Adjustments);
+ Init = Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
QualType QT = Init->getType();
if (QT.isNull())
@@ -198,7 +199,11 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
const CXXConstructorDecl *ctor = cce->getConstructor();
- if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+ // For a variable declared without an initializer, we will have
+ // call-style initialization and the initializer will be the
+ // CXXConstructExpr with no intervening nodes.
+ if (ctor->isTrivial() && ctor->isDefaultConstructor() &&
+ VD->getInit() == Init && VD->getInitStyle() == VarDecl::CallInit) {
if (OutDiag)
InDiag = diag::note_protected_by_variable_nontriv_destructor;
else if (!Record->isPOD())
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index d85624ba6f64..ad7627a45715 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -267,3 +267,34 @@ void MultiplexExternalSemaSource::ReadPendingInstantiations(
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadPendingInstantiations(Pending);
}
+
+void MultiplexExternalSemaSource::ReadLateParsedTemplates(
+ llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadLateParsedTemplates(LPTMap);
+}
+
+TypoCorrection MultiplexExternalSemaSource::CorrectTypo(
+ const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+ for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+ if (TypoCorrection C = Sources[I]->CorrectTypo(Typo, LookupKind, S, SS, CCC,
+ MemberContext,
+ EnteringContext, OPT))
+ return C;
+ }
+ return TypoCorrection();
+}
+
+bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType(
+ SourceLocation Loc, QualType T) {
+ for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+ if (Sources[I]->MaybeDiagnoseMissingCompleteType(Loc, T))
+ return true;
+ }
+ return false;
+}
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 2f48bec123bf..8b3493ebfef8 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -184,6 +184,21 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
ThisUse->markSafe();
}
+void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) {
+ assert(Idx < getNumPotentialVariableCaptures() &&
+ "Index of potential capture must be within 0 to less than the "
+ "number of captures!");
+ E = PotentiallyCapturingExprs[Idx];
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
+ else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ VD = dyn_cast<VarDecl>(ME->getMemberDecl());
+ else
+ llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "
+ "potential captures");
+ assert(VD);
+}
+
FunctionScopeInfo::~FunctionScopeInfo() { }
BlockScopeInfo::~BlockScopeInfo() { }
LambdaScopeInfo::~LambdaScopeInfo() { }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index e718be2f8bd5..4d01fb0a6be6 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -89,8 +89,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
NumSFINAEErrors(0), InFunctionDeclarator(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(0), TyposCorrected(0),
- AnalysisWarnings(*this), CurScope(0), Ident_super(0)
+ CurrentInstantiationScope(0), DisableTypoCorrection(false),
+ TyposCorrected(0), AnalysisWarnings(*this),
+ VarDataSharingAttributesStack(0), CurScope(0),
+ Ident_super(0), Ident___float128(0)
{
TUScope = 0;
@@ -113,6 +115,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
false, 0, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
+
+ // Initilization of data sharing attributes stack for OpenMP
+ InitDataSharingAttributesStack();
}
void Sema::Initialize() {
@@ -173,6 +178,10 @@ void Sema::Initialize() {
}
Sema::~Sema() {
+ for (LateParsedTemplateMapT::iterator I = LateParsedTemplateMap.begin(),
+ E = LateParsedTemplateMap.end();
+ I != E; ++I)
+ delete I->second;
if (PackContext) FreePackedContext();
if (VisContext) FreeVisContext();
delete TheTargetAttributesSema;
@@ -195,6 +204,9 @@ Sema::~Sema() {
// If Sema's ExternalSource is the multiplexer - we own it.
if (isMultiplexExternalSource)
delete ExternalSource;
+
+ // Destroys data sharing attributes stack for OpenMP
+ DestroyDataSharingAttributesStack();
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -284,9 +296,6 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
if (ExprTy == TypeTy)
return Owned(E);
- if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
-
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
if (Kind == CK_DerivedToBase &&
@@ -332,7 +341,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
if (D->getMostRecentDecl()->isUsed())
return true;
- if (D->hasExternalLinkage())
+ if (D->isExternallyVisible())
return true;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -350,6 +359,15 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
}
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // If a variable usable in constant expressions is referenced,
+ // don't warn if it isn't used: if the value of a variable is required
+ // for the computation of a constant expression, it doesn't make sense to
+ // warn even if the variable isn't odr-used. (isReferenced doesn't
+ // precisely reflect that, but it's a decent approximation.)
+ if (VD->isReferenced() &&
+ VD->isUsableInConstantExpressions(SemaRef->Context))
+ return true;
+
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
const VarDecl *DeclToCheck = VD->getDefinition();
@@ -402,13 +420,13 @@ void Sema::getUndefinedButUsed(
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isDefined())
continue;
- if (FD->hasExternalLinkage() &&
+ if (FD->isExternallyVisible() &&
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (ND->hasExternalLinkage())
+ if (ND->isExternallyVisible())
continue;
}
@@ -435,7 +453,7 @@ static void checkUndefinedButUsed(Sema &S) {
I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
NamedDecl *ND = I->first;
- if (ND->getLinkage() != ExternalLinkage) {
+ if (!ND->isExternallyVisible()) {
S.Diag(ND->getLocation(), diag::warn_undefined_internal)
<< isa<VarDecl>(ND) << ND;
} else {
@@ -551,9 +569,9 @@ void Sema::ActOnEndOfTranslationUnit() {
if (PP.isCodeCompletionEnabled())
return;
- // Only complete translation units define vtables and perform implicit
- // instantiations.
- if (TUKind == TU_Complete) {
+ // Complete translation units and modules define vtables and perform implicit
+ // instantiations. PCH files do not.
+ if (TUKind != TU_Prefix) {
DiagnoseUseOfUnimplementedSelectors();
// If any dynamic classes have their key function defined within
@@ -582,13 +600,18 @@ void Sema::ActOnEndOfTranslationUnit() {
// carefully keep track of the point of instantiation (C++ [temp.point]).
// This means that name lookup that occurs within the template
// instantiation will always happen at the end of the translation unit,
- // so it will find some names that should not be found. Although this is
- // common behavior for C++ compilers, it is technically wrong. In the
- // future, we either need to be able to filter the results of name lookup
- // or we need to perform template instantiations earlier.
+ // so it will find some names that are not required to be found. This is
+ // valid, but we could do better by diagnosing if an instantiation uses a
+ // name that was not visible at its first point of instantiation.
PerformPendingInstantiations();
+ CheckDelayedMemberExceptionSpecs();
}
+ // All delayed member exception specs should be checked or we end up accepting
+ // incompatible declarations.
+ assert(DelayedDefaultedMemberExceptionSpecs.empty());
+ assert(DelayedDestructorExceptionSpecChecks.empty());
+
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(
std::remove_if(UnusedFileScopedDecls.begin(0, true),
@@ -630,14 +653,14 @@ void Sema::ActOnEndOfTranslationUnit() {
SmallVector<Module *, 2> Stack;
Stack.push_back(CurrentModule);
while (!Stack.empty()) {
- Module *Mod = Stack.back();
- Stack.pop_back();
+ Module *Mod = Stack.pop_back_val();
// Resolve the exported declarations and conflicts.
// FIXME: Actually complain, once we figure out how to teach the
// diagnostic client to deal with complaints in the module map at this
// point.
ModMap.resolveExports(Mod, /*Complain=*/false);
+ ModMap.resolveUses(Mod, /*Complain=*/false);
ModMap.resolveConflicts(Mod, /*Complain=*/false);
// Queue the submodules, so their exports will also be resolved.
@@ -681,13 +704,6 @@ void Sema::ActOnEndOfTranslationUnit() {
if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(VD->getType())) {
- if (RequireCompleteType(VD->getLocation(),
- ArrayT->getElementType(),
- diag::err_tentative_def_incomplete_type_arr)) {
- VD->setInvalidDecl();
- continue;
- }
-
// Set the length of the array to 1 (C99 6.9.2p5).
Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true);
@@ -729,7 +745,7 @@ void Sema::ActOnEndOfTranslationUnit() {
else {
if (FD->getStorageClass() == SC_Static &&
!FD->isInlineSpecified() &&
- !SourceMgr.isFromMainFile(
+ !SourceMgr.isInMainFile(
SourceMgr.getExpansionLoc(FD->getLocation())))
Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl)
<< DiagD->getDeclName();
@@ -750,11 +766,10 @@ void Sema::ActOnEndOfTranslationUnit() {
if (DiagD->isReferenced()) {
Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
<< /*variable*/1 << DiagD->getDeclName();
- } else if (getSourceManager().isFromMainFile(DiagD->getLocation())) {
- // If the declaration is in a header which is included into multiple
- // TUs, it will declare one variable per TU, and one of the other
- // variables may be used. So, only warn if the declaration is in the
- // main file.
+ } else if (DiagD->getType().isConstQualified()) {
+ Diag(DiagD->getLocation(), diag::warn_unused_const_variable)
+ << DiagD->getDeclName();
+ } else {
Diag(DiagD->getLocation(), diag::warn_unused_variable)
<< DiagD->getDeclName();
}
@@ -824,6 +839,8 @@ FunctionDecl *Sema::getCurFunctionDecl() {
ObjCMethodDecl *Sema::getCurMethodDecl() {
DeclContext *DC = getFunctionLevelDeclContext();
+ while (isa<RecordDecl>(DC))
+ DC = DC->getParent();
return dyn_cast<ObjCMethodDecl>(DC);
}
@@ -986,7 +1003,7 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) {
// Ignore scopes that cannot have declarations. This is important for
// out-of-line definitions of static class members.
if (S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope))
- if (DeclContext *Entity = static_cast<DeclContext *> (S->getEntity()))
+ if (DeclContext *Entity = S->getEntity())
if (Ctx == Entity->getPrimaryContext())
return S;
}
@@ -1012,10 +1029,19 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
- CXXMethodDecl *CallOperator) {
- FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
- CallOperator));
+LambdaScopeInfo *Sema::PushLambdaScope() {
+ LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics());
+ FunctionScopes.push_back(LSI);
+ return LSI;
+}
+
+void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
+ if (LambdaScopeInfo *const LSI = getCurLambda()) {
+ LSI->AutoTemplateParameterDepth = Depth;
+ return;
+ }
+ llvm_unreachable(
+ "Remove assertion if intentionally called in a non-lambda context.");
}
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
@@ -1071,6 +1097,16 @@ LambdaScopeInfo *Sema::getCurLambda() {
return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
}
+// We have a generic lambda if we parsed auto parameters, or we have
+// an associated template parameter list.
+LambdaScopeInfo *Sema::getCurGenericLambda() {
+ if (LambdaScopeInfo *LSI = getCurLambda()) {
+ return (LSI->AutoTemplateParams.size() ||
+ LSI->GLTemplateParameterList) ? LSI : 0;
+ }
+ return 0;
+}
+
void Sema::ActOnComment(SourceRange Comment) {
if (!LangOpts.RetainCommentsFromSystemHeaders &&
@@ -1141,33 +1177,68 @@ void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
/// call; otherwise, it is set to an empty QualType.
/// \param OverloadSet - If the expression is an overloaded function
/// name, this parameter is populated with the decls of the various overloads.
-bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
- UnresolvedSetImpl &OverloadSet) {
+bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
+ UnresolvedSetImpl &OverloadSet) {
ZeroArgCallReturnTy = QualType();
OverloadSet.clear();
+ const OverloadExpr *Overloads = NULL;
+ bool IsMemExpr = false;
if (E.getType() == Context.OverloadTy) {
OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E));
- const OverloadExpr *Overloads = FR.Expression;
+ // Ignore overloads that are pointer-to-member constants.
+ if (FR.HasFormOfMemberPointer)
+ return false;
+
+ Overloads = FR.Expression;
+ } else if (E.getType() == Context.BoundMemberTy) {
+ Overloads = dyn_cast<UnresolvedMemberExpr>(E.IgnoreParens());
+ IsMemExpr = true;
+ }
+
+ bool Ambiguous = false;
+
+ if (Overloads) {
for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
OverloadSet.addDecl(*it);
- // Check whether the function is a non-template which takes no
+ // Check whether the function is a non-template, non-member which takes no
// arguments.
+ if (IsMemExpr)
+ continue;
if (const FunctionDecl *OverloadDecl
= dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) {
- if (OverloadDecl->getMinRequiredArguments() == 0)
- ZeroArgCallReturnTy = OverloadDecl->getResultType();
+ if (OverloadDecl->getMinRequiredArguments() == 0) {
+ if (!ZeroArgCallReturnTy.isNull() && !Ambiguous) {
+ ZeroArgCallReturnTy = QualType();
+ Ambiguous = true;
+ } else
+ ZeroArgCallReturnTy = OverloadDecl->getResultType();
+ }
}
}
- // Ignore overloads that are pointer-to-member constants.
- if (FR.HasFormOfMemberPointer)
- return false;
+ // If it's not a member, use better machinery to try to resolve the call
+ if (!IsMemExpr)
+ return !ZeroArgCallReturnTy.isNull();
+ }
- return true;
+ // Attempt to call the member with no arguments - this will correctly handle
+ // member templates with defaults/deduction of template arguments, overloads
+ // with default arguments, etc.
+ if (IsMemExpr && !E.isTypeDependent()) {
+ bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
+ getDiagnostics().setSuppressAllDiagnostics(true);
+ ExprResult R = BuildCallToMemberFunction(NULL, &E, SourceLocation(), None,
+ SourceLocation());
+ getDiagnostics().setSuppressAllDiagnostics(Suppress);
+ if (R.isUsable()) {
+ ZeroArgCallReturnTy = R.get()->getType();
+ return true;
+ }
+ return false;
}
if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) {
@@ -1187,14 +1258,6 @@ bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
FunTy = PointeeTy->getAs<FunctionType>();
if (!FunTy)
FunTy = ExprTy->getAs<FunctionType>();
- if (!FunTy && ExprTy == Context.BoundMemberTy) {
- // Look for the bound-member type. If it's still overloaded, give up,
- // although we probably should have fallen into the OverloadExpr case above
- // if we actually have an overloaded bound member.
- QualType BoundMemberTy = Expr::findBoundMemberType(&E);
- if (!BoundMemberTy.isNull())
- FunTy = BoundMemberTy->castAs<FunctionType>();
- }
if (const FunctionProtoType *FPT =
dyn_cast_or_null<FunctionProtoType>(FunTy)) {
@@ -1207,7 +1270,7 @@ bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
/// \brief Give notes for a set of overloads.
///
-/// A companion to isExprCallable. In cases when the name that the programmer
+/// A companion to tryExprAsCall. In cases when the name that the programmer
/// wrote was an overloaded function, we may be able to make some guesses about
/// plausible overloads based on their return types; such guesses can be handed
/// off to this method to be emitted as notes.
@@ -1277,15 +1340,14 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
QualType ZeroArgCallTy;
UnresolvedSet<4> Overloads;
- if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) &&
+ if (tryExprAsCall(*E.get(), ZeroArgCallTy, Overloads) &&
!ZeroArgCallTy.isNull() &&
(!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) {
// At this point, we know E is potentially callable with 0
// arguments and that it returns something of a reasonable type,
// so we can emit a fixit and carry on pretending that E was
// actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(Range.getEnd());
+ SourceLocation ParenInsertionLoc = PP.getLocForEndOfToken(Range.getEnd());
Diag(Loc, PD)
<< /*zero-arg*/ 1 << Range
<< (IsCallableWithAppend(E.get())
@@ -1295,8 +1357,8 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
- E = ActOnCallExpr(0, E.take(), ParenInsertionLoc,
- None, ParenInsertionLoc.getLocWithOffset(1));
+ E = ActOnCallExpr(0, E.take(), Range.getEnd(), None,
+ Range.getEnd().getLocWithOffset(1));
return true;
}
@@ -1314,6 +1376,12 @@ IdentifierInfo *Sema::getSuperIdentifier() const {
return Ident_super;
}
+IdentifierInfo *Sema::getFloat128Identifier() const {
+ if (!Ident___float128)
+ Ident___float128 = &Context.Idents.get("__float128");
+ return Ident___float128;
+}
+
void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
CapturedRegionKind K) {
CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), S, CD, RD,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 3ef1fdebaac7..61dc157f8589 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -315,8 +315,7 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
if (Queue.empty()) break;
- Derived = Queue.back();
- Queue.pop_back();
+ Derived = Queue.pop_back_val();
}
return OnFailure;
@@ -1484,7 +1483,9 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
DeclContext *DC = D->getDeclContext();
if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
- if (!DC->isFunctionOrMethod())
+ if (D->getLexicalDeclContext()->isFunctionOrMethod())
+ DC = D->getLexicalDeclContext();
+ else
DC = FN;
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
DC = cast<DeclContext>(TD->getTemplatedDecl());
@@ -1649,9 +1650,9 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
}
case InitializedEntity::EK_LambdaCapture: {
- const VarDecl *Var = Entity.getCapturedVar();
+ StringRef VarName = Entity.getCapturedVarName();
PD = PDiag(diag::err_access_lambda_capture);
- PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor);
+ PD << VarName << Entity.getType() << getSpecialMember(Constructor);
break;
}
@@ -1710,6 +1711,21 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
return CheckAccess(*this, OpLoc, Entity);
}
+/// \brief Checks access to a member.
+Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair Found) {
+ if (!getLangOpts().AccessControl ||
+ !NamingClass ||
+ Found.getAccess() == AS_public)
+ return AR_accessible;
+
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
+ Found, QualType());
+
+ return CheckAccess(*this, UseLoc, Entity);
+}
+
/// Checks access to an overloaded member operator, including
/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
@@ -1872,9 +1888,7 @@ bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
return true;
-
-
-
+
// If we are inside a class or category implementation, determine the
// interface we're in.
ObjCInterfaceDecl *ClassOfMethodDecl = 0;
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index e12bbde0d0dd..8f9ab32517d6 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
@@ -263,6 +264,30 @@ void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
MSStructPragmaOn = (Kind == PMSST_ON);
}
+void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg) {
+ // FIXME: Serialize this.
+ switch (Kind) {
+ case PCK_Unknown:
+ llvm_unreachable("unexpected pragma comment kind");
+ case PCK_Linker:
+ Consumer.HandleLinkerOptionPragma(Arg);
+ return;
+ case PCK_Lib:
+ Consumer.HandleDependentLibrary(Arg);
+ return;
+ case PCK_Compiler:
+ case PCK_ExeStr:
+ case PCK_User:
+ return; // We ignore all of these.
+ }
+ llvm_unreachable("invalid pragma comment kind");
+}
+
+void Sema::ActOnPragmaDetectMismatch(StringRef Name, StringRef Value) {
+ // FIXME: Serialize this.
+ Consumer.HandleDetectMismatch(Name, Value);
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
@@ -343,21 +368,12 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
SourceLocation PragmaLoc) {
if (VisType) {
// Compute visibility to use.
- VisibilityAttr::VisibilityType type;
- if (VisType->isStr("default"))
- type = VisibilityAttr::Default;
- else if (VisType->isStr("hidden"))
- type = VisibilityAttr::Hidden;
- else if (VisType->isStr("internal"))
- type = VisibilityAttr::Hidden; // FIXME
- else if (VisType->isStr("protected"))
- type = VisibilityAttr::Protected;
- else {
- Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) <<
- VisType->getName();
+ VisibilityAttr::VisibilityType T;
+ if (!VisibilityAttr::ConvertStrToVisibilityType(VisType->getName(), T)) {
+ Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) << VisType;
return;
}
- PushPragmaVisibility(*this, type, PragmaLoc);
+ PushPragmaVisibility(*this, T, PragmaLoc);
} else {
PopPragmaVisibility(false, PragmaLoc);
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 01ac8f7fb62d..554a114bae60 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -160,16 +160,6 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
return SS.getScopeRep()->isDependent();
}
-// \brief Determine whether this C++ scope specifier refers to an
-// unknown specialization, i.e., a dependent type that is not the
-// current instantiation.
-bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
- if (!isDependentScopeSpecifier(SS))
- return false;
-
- return getCurrentInstantiationOf(SS.getScopeRep()) == 0;
-}
-
/// \brief If the given nested name specifier refers to the current
/// instantiation, return the declaration that corresponds to that
/// current instantiation (C++0x [temp.dep.type]p1).
@@ -494,32 +484,30 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// FIXME: Deal with ambiguities cleanly.
- if (Found.empty() && !ErrorRecoveryLookup) {
+ if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MicrosoftMode) {
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
NestedNameSpecifierValidatorCCC Validator(*this);
- TypoCorrection Corrected;
Found.clear();
- if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
- Found.getLookupKind(), S, &SS, Validator,
- LookupCtx, EnteringContext))) {
- std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
- if (LookupCtx)
- Diag(Found.getNameLoc(), diag::err_no_member_suggest)
- << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- else
- Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
- << Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
-
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
- Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
+ if (TypoCorrection Corrected =
+ CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
+ &SS, Validator, LookupCtx, EnteringContext)) {
+ if (LookupCtx) {
+ bool DroppedSpecifier =
+ Corrected.WillReplaceSpecifier() &&
+ Name.getAsString() == Corrected.getAsString(getLangOpts());
+ if (DroppedSpecifier)
+ SS.clear();
+ diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
+ << Name << LookupCtx << DroppedSpecifier
+ << SS.getRange());
+ } else
+ diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
+ << Name);
+
+ if (NamedDecl *ND = Corrected.getCorrectionDecl())
Found.addDecl(ND);
- }
Found.setLookupName(Corrected.getCorrection());
} else {
Found.setLookupName(&Identifier);
@@ -658,7 +646,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// public:
// void foo() { D::foo2(); }
// };
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MicrosoftMode) {
DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index eb11a577cb0a..ba00b712aad5 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -200,8 +200,9 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath,
bool ListInitialization);
-static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
- bool CStyle, unsigned &msg);
+static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
+ QualType DestType, bool CStyle,
+ unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
@@ -242,7 +243,9 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
- bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent();
+ bool TypeDependent = DestType->isDependentType() ||
+ Ex.get()->isTypeDependent() ||
+ Ex.get()->isValueDependent();
CastOperation Op(*this, DestType, E);
Op.OpRange = SourceRange(OpLoc, Parens.getEnd());
@@ -383,11 +386,6 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
SourceRange opRange, Expr *src, QualType destType,
bool listInitialization) {
- if (src->getType() == S.Context.BoundMemberTy) {
- (void) S.CheckPlaceholderExpr(src); // will always fail
- return;
- }
-
if (msg == diag::err_bad_cxx_cast_generic &&
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType,
listInitialization))
@@ -515,8 +513,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
QualType SrcConstruct = Self.Context.VoidTy;
QualType DestConstruct = Self.Context.VoidTy;
ASTContext &Context = Self.Context;
- for (SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(),
- i2 = cv2.rbegin();
+ for (SmallVectorImpl<Qualifiers>::reverse_iterator i1 = cv1.rbegin(),
+ i2 = cv2.rbegin();
i1 != cv1.rend(); ++i1, ++i2) {
SrcConstruct
= Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1));
@@ -558,6 +556,7 @@ void CastOperation::CheckDynamicCast() {
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
<< this->DestType << DestRange;
+ SrcExpr = ExprError();
return;
}
@@ -567,11 +566,14 @@ void CastOperation::CheckDynamicCast() {
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
diag::err_bad_dynamic_cast_incomplete,
- DestRange))
+ DestRange)) {
+ SrcExpr = ExprError();
return;
+ }
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
<< DestPointee.getUnqualifiedType() << DestRange;
+ SrcExpr = ExprError();
return;
}
@@ -587,6 +589,7 @@ void CastOperation::CheckDynamicCast() {
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
<< OrigSrcType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
return;
}
} else if (DestReference->isLValueReferenceType()) {
@@ -603,11 +606,14 @@ void CastOperation::CheckDynamicCast() {
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
diag::err_bad_dynamic_cast_incomplete,
- SrcExpr.get()))
+ SrcExpr.get())) {
+ SrcExpr = ExprError();
return;
+ }
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
<< SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
return;
}
@@ -621,6 +627,7 @@ void CastOperation::CheckDynamicCast() {
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
<< CT_Dynamic << OrigSrcType << this->DestType << OpRange;
+ SrcExpr = ExprError();
return;
}
@@ -636,8 +643,10 @@ void CastOperation::CheckDynamicCast() {
if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
OpRange.getBegin(), OpRange,
- &BasePath))
- return;
+ &BasePath)) {
+ SrcExpr = ExprError();
+ return;
+ }
Kind = CK_DerivedToBase;
@@ -655,10 +664,20 @@ void CastOperation::CheckDynamicCast() {
if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
<< SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
}
Self.MarkVTableUsed(OpRange.getBegin(),
cast<CXXRecordDecl>(SrcRecord->getDecl()));
+ // dynamic_cast is not available with -fno-rtti.
+ // As an exception, dynamic_cast to void* is available because it doesn't
+ // use RTTI.
+ if (!Self.getLangOpts().RTTI && !DestPointee->isVoidType()) {
+ Self.Diag(OpRange.getBegin(), diag::err_no_dynamic_cast_with_fno_rtti);
+ SrcExpr = ExprError();
+ return;
+ }
+
// Done. Everything else is run-time checks.
Kind = CK_Dynamic;
}
@@ -677,10 +696,12 @@ void CastOperation::CheckConstCast() {
return;
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success
- && msg != 0)
+ if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
+ && msg != 0) {
Self.Diag(OpRange.getBegin(), msg) << CT_Const
<< SrcExpr.get()->getType() << DestType << OpRange;
+ SrcExpr = ExprError();
+ }
}
/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
@@ -758,6 +779,7 @@ static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
VirtualBase = VirtualBase && IsVirtual;
}
+ (void) NonZeroOffset; // Silence set but not used warning.
assert((VirtualBase || NonZeroOffset) &&
"Should have returned if has non-virtual base with zero offset");
@@ -768,10 +790,10 @@ static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
SourceLocation BeginLoc = OpRange.getBegin();
Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static)
- << DerivedType << BaseType << !VirtualBase << ReinterpretKind
+ << DerivedType << BaseType << !VirtualBase << int(ReinterpretKind)
<< OpRange;
Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static)
- << ReinterpretKind
+ << int(ReinterpretKind)
<< FixItHint::CreateReplacement(BeginLoc, "static_cast");
}
@@ -807,6 +829,7 @@ void CastOperation::CheckReinterpretCast() {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
DestType, /*listInitialization=*/false);
}
+ SrcExpr = ExprError();
} else if (tcr == TC_Success) {
if (Self.getLangOpts().ObjCAutoRefCount)
checkObjCARCConversion(Sema::CCK_OtherCast);
@@ -868,6 +891,7 @@ void CastOperation::CheckStaticCast() {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType,
/*listInitialization=*/false);
}
+ SrcExpr = ExprError();
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
checkCastAlign();
@@ -1447,12 +1471,26 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// TryConstCast - See if a const_cast from source to destination is allowed,
/// and perform it if it is.
-static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
- bool CStyle, unsigned &msg) {
+static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
+ QualType DestType, bool CStyle,
+ unsigned &msg) {
DestType = Self.Context.getCanonicalType(DestType);
- QualType SrcType = SrcExpr->getType();
+ QualType SrcType = SrcExpr.get()->getType();
+ bool NeedToMaterializeTemporary = false;
+
if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) {
- if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) {
+ // C++11 5.2.11p4:
+ // if a pointer to T1 can be explicitly converted to the type "pointer to
+ // T2" using a const_cast, then the following conversions can also be
+ // made:
+ // -- an lvalue of type T1 can be explicitly converted to an lvalue of
+ // type T2 using the cast const_cast<T2&>;
+ // -- a glvalue of type T1 can be explicitly converted to an xvalue of
+ // type T2 using the cast const_cast<T2&&>; and
+ // -- if T1 is a class type, a prvalue of type T1 can be explicitly
+ // converted to an xvalue of type T2 using the cast const_cast<T2&&>.
+
+ if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr.get()->isLValue()) {
// Cannot const_cast non-lvalue to lvalue reference type. But if this
// is C-style, static_cast might find a way, so we simply suggest a
// message and tell the parent to keep searching.
@@ -1460,18 +1498,29 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_NotApplicable;
}
+ if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
+ if (!SrcType->isRecordType()) {
+ // Cannot const_cast non-class prvalue to rvalue reference type. But if
+ // this is C-style, static_cast can do this.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ // Materialize the class prvalue so that the const_cast can bind a
+ // reference to it.
+ NeedToMaterializeTemporary = true;
+ }
+
// It's not completely clear under the standard whether we can
// const_cast bit-field gl-values. Doing so would not be
// intrinsically complicated, but for now, we say no for
// consistency with other compilers and await the word of the
// committee.
- if (SrcExpr->refersToBitField()) {
+ if (SrcExpr.get()->refersToBitField()) {
msg = diag::err_bad_cxx_cast_bitfield;
return TC_NotApplicable;
}
- // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
- // [...] if a pointer to T1 can be [cast] to the type pointer to T2.
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
SrcType = Self.Context.getPointerType(SrcType);
}
@@ -1525,6 +1574,13 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (SrcType != DestType)
return TC_NotApplicable;
+ if (NeedToMaterializeTemporary)
+ // This is a const_cast from a class prvalue to an rvalue reference type.
+ // Materialize a temporary to store the result of the conversion.
+ SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
+ SrcType, SrcExpr.take(), /*IsLValueReference*/ false,
+ /*ExtendingDecl*/ 0);
+
return TC_Success;
}
@@ -1614,8 +1670,18 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
&& !SrcType->isBooleanType()
&& !SrcType->isEnumeralType()
&& !SrcExpr->isIntegerConstantExpr(Self.Context)
- && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType))
- Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType;
+ && Self.Context.getTypeSize(DestType) >
+ Self.Context.getTypeSize(SrcType)) {
+ // Separate between casts to void* and non-void* pointers.
+ // Some APIs use (abuse) void* for something like a user context,
+ // and often that value is an integer even if it isn't a pointer itself.
+ // Having a separate warning flag allows users to control the warning
+ // for their workflow.
+ unsigned Diag = DestType->isVoidPointerType() ?
+ diag::warn_int_to_void_pointer_cast
+ : diag::warn_int_to_pointer_cast;
+ Self.Diag(Loc, Diag) << SrcType << DestType;
+ }
}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
@@ -1803,10 +1869,12 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
assert(srcIsPtr && "One type must be a pointer");
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
// type large enough to hold it; except in Microsoft mode, where the
- // integral type size doesn't matter.
+ // integral type size doesn't matter (except we don't allow bool).
+ bool MicrosoftException = Self.getLangOpts().MicrosoftExt &&
+ !DestType->isBooleanType();
if ((Self.Context.getTypeSize(SrcType) >
Self.Context.getTypeSize(DestType)) &&
- !Self.getLangOpts().MicrosoftExt) {
+ !MicrosoftException) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
@@ -1940,14 +2008,12 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
- if (SrcExpr.isInvalid())
- return;
-
return;
}
// If the type is dependent, we won't do any other semantic analysis now.
- if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) {
+ if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent() ||
+ SrcExpr.get()->isValueDependent()) {
assert(Kind == CK_Dependent);
return;
}
@@ -1980,8 +2046,10 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
// even if a cast resulting from that interpretation is ill-formed.
// In plain language, this means trying a const_cast ...
unsigned msg = diag::err_bad_cxx_cast_generic;
- TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType,
+ TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType,
/*CStyle*/true, msg);
+ if (SrcExpr.isInvalid())
+ return;
if (tcr == TC_Success)
Kind = CK_NoOp;
@@ -2298,9 +2366,9 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
return ExprError();
if (CXXConstructExpr *ConstructExpr = dyn_cast<CXXConstructExpr>(Op.SrcExpr.get()))
- ConstructExpr->setParenRange(SourceRange(LPLoc, RPLoc));
+ ConstructExpr->setParenOrBraceRange(SourceRange(LPLoc, RPLoc));
return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, CastTypeInfo, Op.DestRange.getBegin(),
- Op.Kind, Op.SrcExpr.take(), &Op.BasePath, RPLoc));
+ Op.ValueKind, CastTypeInfo, Op.Kind,
+ Op.SrcExpr.take(), &Op.BasePath, LPLoc, RPLoc));
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index a0998a46c666..0b95c48d4f8e 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -32,9 +32,9 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
#include <limits>
@@ -95,6 +95,22 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
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) {
+ if (checkArgCount(S, TheCall, 1))
+ return true;
+
+ ExprResult Arg(S.Owned(TheCall->getArg(0)));
+ QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getLocStart());
+ if (ResultType.isNull())
+ return true;
+
+ TheCall->setArg(0, Arg.take());
+ TheCall->setType(ResultType);
+ return false;
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult TheCallResult(Owned(TheCall));
@@ -275,6 +291,10 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_addressof:
+ if (SemaBuiltinAddressof(*this, TheCall))
+ return ExprError();
+ break;
}
// Since the target specific builtins for each arch overlap, only check those
@@ -286,6 +306,10 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::aarch64:
+ if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -315,6 +339,7 @@ static unsigned RFT(unsigned t, bool shift = false) {
case NeonTypeFlags::Int32:
return shift ? 31 : (2 << IsQuad) - 1;
case NeonTypeFlags::Int64:
+ case NeonTypeFlags::Poly64:
return shift ? 63 : (1 << IsQuad) - 1;
case NeonTypeFlags::Float16:
assert(!shift && "cannot shift float types!");
@@ -322,6 +347,9 @@ static unsigned RFT(unsigned t, bool shift = false) {
case NeonTypeFlags::Float32:
assert(!shift && "cannot shift float types!");
return (2 << IsQuad) - 1;
+ case NeonTypeFlags::Float64:
+ assert(!shift && "cannot shift float types!");
+ return (1 << IsQuad) - 1;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
@@ -329,7 +357,8 @@ static unsigned RFT(unsigned t, bool shift = false) {
/// getNeonEltType - Return the QualType corresponding to the elements of
/// the vector type specified by the NeonTypeFlags. This is used to check
/// the pointer arguments for Neon load/store intrinsics.
-static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
+static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
+ bool IsAArch64) {
switch (Flags.getEltType()) {
case NeonTypeFlags::Int8:
return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
@@ -340,20 +369,213 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
case NeonTypeFlags::Int64:
return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy;
case NeonTypeFlags::Poly8:
- return Context.SignedCharTy;
+ return IsAArch64 ? Context.UnsignedCharTy : Context.SignedCharTy;
case NeonTypeFlags::Poly16:
- return Context.ShortTy;
+ return IsAArch64 ? Context.UnsignedShortTy : Context.ShortTy;
+ case NeonTypeFlags::Poly64:
+ return Context.UnsignedLongLongTy;
case NeonTypeFlags::Float16:
- return Context.UnsignedShortTy;
+ return Context.HalfTy;
case NeonTypeFlags::Float32:
return Context.FloatTy;
+ case NeonTypeFlags::Float64:
+ return Context.DoubleTy;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
+bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+
+ llvm::APSInt Result;
+
+ uint64_t mask = 0;
+ unsigned TV = 0;
+ int PtrArgNum = -1;
+ bool HasConstPtr = false;
+ switch (BuiltinID) {
+#define GET_NEON_AARCH64_OVERLOAD_CHECK
+#include "clang/Basic/arm_neon.inc"
+#undef GET_NEON_AARCH64_OVERLOAD_CHECK
+ }
+
+ // For NEON intrinsics which are overloaded on vector element type, validate
+ // the immediate which specifies which variant to emit.
+ unsigned ImmArg = TheCall->getNumArgs() - 1;
+ if (mask) {
+ if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
+ return true;
+
+ TV = Result.getLimitedValue(64);
+ if ((TV > 63) || (mask & (1ULL << TV)) == 0)
+ return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
+ << TheCall->getArg(ImmArg)->getSourceRange();
+ }
+
+ if (PtrArgNum >= 0) {
+ // Check that pointer arguments have the specified type.
+ Expr *Arg = TheCall->getArg(PtrArgNum);
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = ICE->getSubExpr();
+ ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
+ QualType RHSTy = RHS.get()->getType();
+ QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, true);
+ if (HasConstPtr)
+ EltTy = EltTy.withConst();
+ QualType LHSTy = Context.getPointerType(EltTy);
+ AssignConvertType ConvTy;
+ ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
+ if (RHS.isInvalid())
+ return true;
+ if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
+ RHS.get(), AA_Assigning))
+ return true;
+ }
+
+ // For NEON intrinsics which take an immediate value as part of the
+ // instruction, range check them here.
+ unsigned i = 0, l = 0, u = 0;
+ switch (BuiltinID) {
+ default:
+ return false;
+#define GET_NEON_AARCH64_IMMEDIATE_CHECK
+#include "clang/Basic/arm_neon.inc"
+#undef GET_NEON_AARCH64_IMMEDIATE_CHECK
+ }
+ ;
+
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
+ return false;
+
+ // Check that the immediate argument is actually a constant.
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return true;
+
+ // Range check against the upper/lower values for this isntruction.
+ unsigned Val = Result.getZExtValue();
+ if (Val < l || Val > (u + l))
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << l << u + l << TheCall->getArg(i)->getSourceRange();
+
+ return false;
+}
+
+bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
+ assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
+ BuiltinID == ARM::BI__builtin_arm_strex) &&
+ "unexpected ARM builtin");
+ bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex;
+
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+
+ // Ensure that we have the proper number of arguments.
+ if (checkArgCount(*this, TheCall, IsLdrex ? 1 : 2))
+ return true;
+
+ // Inspect the pointer argument of the atomic builtin. This should always be
+ // a pointer type, whose element is an integral scalar or pointer type.
+ // Because it is a pointer type, we don't have to worry about any implicit
+ // casts here.
+ Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1);
+ ExprResult PointerArgRes = DefaultFunctionArrayLvalueConversion(PointerArg);
+ if (PointerArgRes.isInvalid())
+ return true;
+ PointerArg = PointerArgRes.take();
+
+ const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
+ if (!pointerType) {
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
+ << PointerArg->getType() << PointerArg->getSourceRange();
+ return true;
+ }
+
+ // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
+ // task is to insert the appropriate casts into the AST. First work out just
+ // what the appropriate type is.
+ QualType ValType = pointerType->getPointeeType();
+ QualType AddrType = ValType.getUnqualifiedType().withVolatile();
+ if (IsLdrex)
+ AddrType.addConst();
+
+ // Issue a warning if the cast is dodgy.
+ CastKind CastNeeded = CK_NoOp;
+ if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {
+ CastNeeded = CK_BitCast;
+ Diag(DRE->getLocStart(), diag::ext_typecheck_convert_discards_qualifiers)
+ << PointerArg->getType()
+ << Context.getPointerType(AddrType)
+ << AA_Passing << PointerArg->getSourceRange();
+ }
+
+ // Finally, do the cast and replace the argument with the corrected version.
+ AddrType = Context.getPointerType(AddrType);
+ PointerArgRes = ImpCastExprToType(PointerArg, AddrType, CastNeeded);
+ if (PointerArgRes.isInvalid())
+ return true;
+ PointerArg = PointerArgRes.take();
+
+ TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);
+
+ // In general, we allow ints, floats and pointers to be loaded and stored.
+ if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
+ !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intfltptr)
+ << PointerArg->getType() << PointerArg->getSourceRange();
+ return true;
+ }
+
+ // But ARM doesn't have instructions to deal with 128-bit versions.
+ if (Context.getTypeSize(ValType) > 64) {
+ Diag(DRE->getLocStart(), diag::err_atomic_exclusive_builtin_pointer_size)
+ << PointerArg->getType() << PointerArg->getSourceRange();
+ return true;
+ }
+
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
+ << ValType << PointerArg->getSourceRange();
+ return true;
+ }
+
+
+ if (IsLdrex) {
+ TheCall->setType(ValType);
+ return false;
+ }
+
+ // Initialize the argument to be stored.
+ ExprResult ValArg = TheCall->getArg(0);
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(
+ Context, ValType, /*consume*/ false);
+ ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg);
+ if (ValArg.isInvalid())
+ return true;
+ TheCall->setArg(0, ValArg.get());
+
+ // __builtin_arm_strex always returns an int. It's marked as such in the .def,
+ // but the custom checker bypasses all default analysis.
+ TheCall->setType(Context.IntTy);
+ return false;
+}
+
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
+ if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
+ BuiltinID == ARM::BI__builtin_arm_strex) {
+ return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall);
+ }
+
uint64_t mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
@@ -384,7 +606,7 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
Arg = ICE->getSubExpr();
ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
QualType RHSTy = RHS.get()->getType();
- QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context);
+ QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, false);
if (HasConstPtr)
EltTy = EltTy.withConst();
QualType LHSTy = Context.getPointerType(EltTy);
@@ -406,6 +628,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case ARM::BI__builtin_arm_usat: i = 1; u = 31; break;
case ARM::BI__builtin_arm_vcvtr_f:
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
+ case ARM::BI__builtin_arm_dmb:
+ case ARM::BI__builtin_arm_dsb: l = 0; u = 15; break;
#define GET_NEON_IMMEDIATE_CHECK
#include "clang/Basic/arm_neon.inc"
#undef GET_NEON_IMMEDIATE_CHECK
@@ -494,36 +718,50 @@ void Sema::checkCall(NamedDecl *FDecl,
SourceLocation Loc,
SourceRange Range,
VariadicCallType CallType) {
+ // FIXME: We should check as much as we can in the template definition.
if (CurContext->isDependentContext())
return;
// Printf and scanf checking.
- bool HandledFormatString = false;
- for (specific_attr_iterator<FormatAttr>
- I = FDecl->specific_attr_begin<FormatAttr>(),
- E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
- if (CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range))
- HandledFormatString = true;
+ llvm::SmallBitVector CheckedVarArgs;
+ if (FDecl) {
+ for (specific_attr_iterator<FormatAttr>
+ I = FDecl->specific_attr_begin<FormatAttr>(),
+ E = FDecl->specific_attr_end<FormatAttr>();
+ I != E; ++I) {
+ // Only create vector if there are format attributes.
+ CheckedVarArgs.resize(Args.size());
+
+ CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range,
+ CheckedVarArgs);
+ }
+ }
// Refuse POD arguments that weren't caught by the format string
// checks above.
- if (!HandledFormatString && CallType != VariadicDoesNotApply)
+ if (CallType != VariadicDoesNotApply) {
for (unsigned ArgIdx = NumProtoArgs; ArgIdx < Args.size(); ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
- if (const Expr *Arg = Args[ArgIdx])
- variadicArgumentPODCheck(Arg, CallType);
+ if (const Expr *Arg = Args[ArgIdx]) {
+ if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx])
+ checkVariadicArgument(Arg, CallType);
+ }
}
+ }
- for (specific_attr_iterator<NonNullAttr>
- I = FDecl->specific_attr_begin<NonNullAttr>(),
- E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
- CheckNonNullArguments(*I, Args.data(), Loc);
+ if (FDecl) {
+ for (specific_attr_iterator<NonNullAttr>
+ I = FDecl->specific_attr_begin<NonNullAttr>(),
+ E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
+ CheckNonNullArguments(*I, Args.data(), Loc);
- // Type safety checking.
- for (specific_attr_iterator<ArgumentWithTypeTagAttr>
- i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
- e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>(); i != e; ++i) {
- CheckArgumentWithTypeTag(*i, Args.data());
+ // Type safety checking.
+ for (specific_attr_iterator<ArgumentWithTypeTagAttr>
+ i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
+ e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>();
+ i != e; ++i) {
+ CheckArgumentWithTypeTag(*i, Args.data());
+ }
}
}
@@ -597,18 +835,24 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
return false;
}
-bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
- const FunctionProtoType *Proto) {
+bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto) {
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
return false;
QualType Ty = V->getType();
- if (!Ty->isBlockPointerType())
+ if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType())
return false;
- VariadicCallType CallType =
- Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
+ VariadicCallType CallType;
+ if (!Proto || !Proto->isVariadic()) {
+ CallType = VariadicDoesNotApply;
+ } else if (Ty->isBlockPointerType()) {
+ CallType = VariadicBlock;
+ } else { // Ty->isFunctionPointerType()
+ CallType = VariadicFunction;
+ }
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
checkCall(NDecl,
@@ -621,6 +865,23 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
return false;
}
+/// Checks function calls when a FunctionDecl or a NamedDecl is not available,
+/// such as function pointers returned from functions.
+bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
+ VariadicCallType CallType = getVariadicCallType(/*FDecl=*/0, Proto,
+ TheCall->getCallee());
+ unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+
+ checkCall(/*FDecl=*/0,
+ llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
+ TheCall->getNumArgs()),
+ NumProtoArgs, /*IsMemberFunction=*/false,
+ TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange(), CallType);
+
+ return false;
+}
+
ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
@@ -786,7 +1047,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
return ExprError();
}
- if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context)) {
+ if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) &&
+ !AtomTy->isScalarType()) {
// For GNU atomics, require a trivially-copyable type. This is not part of
// the GNU atomics specification, but we enforce it for sanity.
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_trivial_copy)
@@ -908,10 +1170,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
SubExprs.push_back(TheCall->getArg(3)); // Weak
break;
}
+
+ 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)) &&
+ Context.AtomicUsesUnsupportedLibcall(AE))
+ Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) <<
+ ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1);
- return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
- SubExprs, ResultType, Op,
- TheCall->getRParenLoc()));
+ return Owned(AE);
}
@@ -1355,6 +1625,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
bool SecondArgIsLastNamedArgument = false;
const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
+ // These are valid if SecondArgIsLastNamedArgument is false after the next
+ // block.
+ QualType Type;
+ SourceLocation ParamLoc;
+
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).
@@ -1367,12 +1642,22 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
else
LastArg = *(getCurMethodDecl()->param_end()-1);
SecondArgIsLastNamedArgument = PV == LastArg;
+
+ Type = PV->getType();
+ ParamLoc = PV->getLocation();
}
}
if (!SecondArgIsLastNamedArgument)
Diag(TheCall->getArg(1)->getLocStart(),
diag::warn_second_parameter_of_va_start_not_last_named_argument);
+ else if (Type->isReferenceType()) {
+ Diag(Arg->getLocStart(),
+ diag::warn_va_start_of_reference_type_is_undefined);
+ Diag(ParamLoc, diag::note_parameter_type) << Type;
+ }
+
+ TheCall->setType(Context.VoidTy);
return false;
}
@@ -1464,8 +1749,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_few_args_at_least)
- << 0 /*function call*/ << 2 << TheCall->getNumArgs()
- << TheCall->getSourceRange());
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
// Determine which of the following types of shufflevector we're checking:
// 1) unary, vector mask: (lhs, mask)
@@ -1473,19 +1758,18 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
// 3) binary, scalar mask: (lhs, rhs, index, ..., index)
QualType resType = TheCall->getArg(0)->getType();
unsigned numElements = 0;
-
+
if (!TheCall->getArg(0)->isTypeDependent() &&
!TheCall->getArg(1)->isTypeDependent()) {
QualType LHSType = TheCall->getArg(0)->getType();
QualType RHSType = TheCall->getArg(1)->getType();
-
- if (!LHSType->isVectorType() || !RHSType->isVectorType()) {
- Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector)
- << SourceRange(TheCall->getArg(0)->getLocStart(),
- TheCall->getArg(1)->getLocEnd());
- return ExprError();
- }
-
+
+ if (!LHSType->isVectorType() || !RHSType->isVectorType())
+ return ExprError(Diag(TheCall->getLocStart(),
+ diag::err_shufflevector_non_vector)
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd()));
+
numElements = LHSType->getAs<VectorType>()->getNumElements();
unsigned numResElements = TheCall->getNumArgs() - 2;
@@ -1493,18 +1777,17 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
// with mask. If so, verify that RHS is an integer vector type with the
// same number of elts as lhs.
if (TheCall->getNumArgs() == 2) {
- if (!RHSType->hasIntegerRepresentation() ||
+ if (!RHSType->hasIntegerRepresentation() ||
RHSType->getAs<VectorType>()->getNumElements() != numElements)
- Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
- << SourceRange(TheCall->getArg(1)->getLocStart(),
- TheCall->getArg(1)->getLocEnd());
- numResElements = numElements;
- }
- else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
- Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
- << SourceRange(TheCall->getArg(0)->getLocStart(),
- TheCall->getArg(1)->getLocEnd());
- return ExprError();
+ return ExprError(Diag(TheCall->getLocStart(),
+ diag::err_shufflevector_incompatible_vector)
+ << 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)
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd()));
} else if (numElements != numResElements) {
QualType eltType = LHSType->getAs<VectorType>()->getElementType();
resType = Context.getVectorType(eltType, numResElements,
@@ -1520,13 +1803,17 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
llvm::APSInt Result(32);
if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_nonconstant_argument)
- << TheCall->getArg(i)->getSourceRange());
+ diag::err_shufflevector_nonconstant_argument)
+ << TheCall->getArg(i)->getSourceRange());
+
+ // Allow -1 which will be translated to undef in the IR.
+ if (Result.isSigned() && Result.isAllOnesValue())
+ continue;
if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2)
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_argument_too_large)
- << TheCall->getArg(i)->getSourceRange());
+ diag::err_shufflevector_argument_too_large)
+ << TheCall->getArg(i)->getSourceRange());
}
SmallVector<Expr*, 32> exprs;
@@ -1541,6 +1828,37 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getRParenLoc()));
}
+/// SemaConvertVectorExpr - Handle __builtin_convertvector
+ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc) {
+ ExprValueKind VK = VK_RValue;
+ ExprObjectKind OK = OK_Ordinary;
+ QualType DstTy = TInfo->getType();
+ QualType SrcTy = E->getType();
+
+ if (!SrcTy->isVectorType() && !SrcTy->isDependentType())
+ return ExprError(Diag(BuiltinLoc,
+ diag::err_convertvector_non_vector)
+ << E->getSourceRange());
+ if (!DstTy->isVectorType() && !DstTy->isDependentType())
+ return ExprError(Diag(BuiltinLoc,
+ diag::err_convertvector_non_vector_type));
+
+ if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
+ unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements();
+ unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements();
+ if (SrcElts != DstElts)
+ return ExprError(Diag(BuiltinLoc,
+ diag::err_convertvector_incompatible_vector)
+ << E->getSourceRange());
+ }
+
+ return Owned(new (Context) ConvertVectorExpr(E, TInfo, DstTy, VK, OK,
+ BuiltinLoc, RParenLoc));
+
+}
+
/// SemaBuiltinPrefetch - Handle __builtin_prefetch.
// This is declared to take (const void*, ...) and can take two
// optional constant int args.
@@ -1642,28 +1960,36 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
return false;
}
+namespace {
+enum StringLiteralCheckType {
+ SLCT_NotALiteral,
+ SLCT_UncheckedLiteral,
+ SLCT_CheckedLiteral
+};
+}
+
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
// format string, we will usually need to emit a warning.
// True string literals are then checked by CheckFormatString.
-Sema::StringLiteralCheckType
-Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
- bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- FormatStringType Type, VariadicCallType CallType,
- bool inFunctionCall) {
+static StringLiteralCheckType
+checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, Sema::FormatStringType Type,
+ Sema::VariadicCallType CallType, bool InFunctionCall,
+ llvm::SmallBitVector &CheckedVarArgs) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
return SLCT_NotALiteral;
E = E->IgnoreParenCasts();
- if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ if (E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
// Technically -Wformat-nonliteral does not warn about this case.
// The behavior of printf and friends in this case is implementation
// dependent. Ideally if the format string cannot be null then
// it should have a 'nonnull' attribute in the function prototype.
- return SLCT_CheckedLiteral;
+ return SLCT_UncheckedLiteral;
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
@@ -1673,15 +1999,15 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
const AbstractConditionalOperator *C =
cast<AbstractConditionalOperator>(E);
StringLiteralCheckType Left =
- checkFormatStringExpr(C->getTrueExpr(), Args,
+ checkFormatStringExpr(S, C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
- Type, CallType, inFunctionCall);
+ Type, CallType, InFunctionCall, CheckedVarArgs);
if (Left == SLCT_NotALiteral)
return SLCT_NotALiteral;
StringLiteralCheckType Right =
- checkFormatStringExpr(C->getFalseExpr(), Args,
+ checkFormatStringExpr(S, C->getFalseExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
- Type, CallType, inFunctionCall);
+ Type, CallType, InFunctionCall, CheckedVarArgs);
return Left < Right ? Left : Right;
}
@@ -1712,15 +2038,15 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
bool isConstant = false;
QualType T = DR->getType();
- if (const ArrayType *AT = Context.getAsArrayType(T)) {
- isConstant = AT->getElementType().isConstant(Context);
+ if (const ArrayType *AT = S.Context.getAsArrayType(T)) {
+ isConstant = AT->getElementType().isConstant(S.Context);
} else if (const PointerType *PT = T->getAs<PointerType>()) {
- isConstant = T.isConstant(Context) &&
- PT->getPointeeType().isConstant(Context);
+ isConstant = T.isConstant(S.Context) &&
+ PT->getPointeeType().isConstant(S.Context);
} else if (T->isObjCObjectPointerType()) {
// In ObjC, there is usually no "const ObjectPointer" type,
// so don't check if the pointee type is constant.
- isConstant = T.isConstant(Context);
+ isConstant = T.isConstant(S.Context);
}
if (isConstant) {
@@ -1730,10 +2056,10 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(Init, Args,
+ return checkFormatStringExpr(S, Init, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
- /*inFunctionCall*/false);
+ /*InFunctionCall*/false, CheckedVarArgs);
}
}
@@ -1750,7 +2076,7 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
// va_start(ap, fmt);
// vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
// ...
- //
+ // }
if (HasVAListArg) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) {
@@ -1766,7 +2092,7 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
// We also check if the formats are compatible.
// We can't pass a 'scanf' string to a 'printf' function.
if (PVIndex == PVFormat->getFormatIdx() &&
- Type == GetFormatStringType(PVFormat))
+ Type == S.GetFormatStringType(PVFormat))
return SLCT_UncheckedLiteral;
}
}
@@ -1788,24 +2114,46 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return checkFormatStringExpr(Arg, Args,
+ return checkFormatStringExpr(S, Arg, Args,
HasVAListArg, format_idx, firstDataArg,
- Type, CallType, inFunctionCall);
+ Type, CallType, InFunctionCall,
+ CheckedVarArgs);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
unsigned BuiltinID = FD->getBuiltinID();
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(Arg, Args,
+ return checkFormatStringExpr(S, Arg, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
- inFunctionCall);
+ InFunctionCall, CheckedVarArgs);
}
}
}
return SLCT_NotALiteral;
}
+
+ case Stmt::ObjCMessageExprClass: {
+ const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(E);
+ if (const ObjCMethodDecl *MDecl = ME->getMethodDecl()) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(MDecl)) {
+ if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
+ unsigned ArgIndex = FA->getFormatIdx();
+ if (ArgIndex <= ME->getNumArgs()) {
+ const Expr *Arg = ME->getArg(ArgIndex-1);
+ return checkFormatStringExpr(S, Arg, Args,
+ HasVAListArg, format_idx,
+ firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs);
+ }
+ }
+ }
+ }
+
+ return SLCT_NotALiteral;
+ }
+
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
const StringLiteral *StrE = NULL;
@@ -1816,8 +2164,8 @@ Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, Args, HasVAListArg, format_idx,
- firstDataArg, Type, inFunctionCall, CallType);
+ S.CheckFormatString(StrE, E, Args, HasVAListArg, format_idx, firstDataArg,
+ Type, InFunctionCall, CallType, CheckedVarArgs);
return SLCT_CheckedLiteral;
}
@@ -1856,7 +2204,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
}
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
- return llvm::StringSwitch<FormatStringType>(Format->getType())
+ return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)
.Cases("printf", "printf0", FST_Printf)
.Cases("NSString", "CFString", FST_NSString)
@@ -1873,12 +2221,13 @@ bool Sema::CheckFormatArguments(const FormatAttr *Format,
ArrayRef<const Expr *> Args,
bool IsCXXMember,
VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range) {
+ SourceLocation Loc, SourceRange Range,
+ llvm::SmallBitVector &CheckedVarArgs) {
FormatStringInfo FSI;
if (getFormatStringInfo(Format, IsCXXMember, &FSI))
return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
- CallType, Loc, Range);
+ CallType, Loc, Range, CheckedVarArgs);
return false;
}
@@ -1886,7 +2235,8 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range) {
+ SourceLocation Loc, SourceRange Range,
+ llvm::SmallBitVector &CheckedVarArgs) {
// CHECK: printf/scanf-like function is called with no format string.
if (format_idx >= Args.size()) {
Diag(Loc, diag::warn_missing_format_string) << Range;
@@ -1908,8 +2258,9 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
StringLiteralCheckType CT =
- checkFormatStringExpr(OrigFormatExpr, Args, HasVAListArg,
- format_idx, firstDataArg, Type, CallType);
+ checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg,
+ format_idx, firstDataArg, Type, CallType,
+ /*IsFunctionCall*/true, CheckedVarArgs);
if (CT != SLCT_NotALiteral)
// Literal format string found, check done!
return CT == SLCT_CheckedLiteral;
@@ -1929,7 +2280,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (Args.size() == format_idx+1)
+ if (Args.size() == firstDataArg)
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
@@ -1952,27 +2303,30 @@ protected:
const bool HasVAListArg;
ArrayRef<const Expr *> Args;
unsigned FormatIdx;
- llvm::BitVector CoveredArgs;
+ llvm::SmallBitVector CoveredArgs;
bool usesPositionalArgs;
bool atFirstArg;
bool inFunctionCall;
Sema::VariadicCallType CallType;
+ llvm::SmallBitVector &CheckedVarArgs;
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
- Sema::VariadicCallType callType)
+ Sema::VariadicCallType callType,
+ llvm::SmallBitVector &CheckedVarArgs)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg),
Args(Args), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
- inFunctionCall(inFunctionCall), CallType(callType) {
- CoveredArgs.resize(numDataArgs);
- CoveredArgs.reset();
- }
+ inFunctionCall(inFunctionCall), CallType(callType),
+ CheckedVarArgs(CheckedVarArgs) {
+ CoveredArgs.resize(numDataArgs);
+ CoveredArgs.reset();
+ }
void DoneProcessing();
@@ -2361,10 +2715,12 @@ public:
const char *beg, bool hasVAListArg,
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
- Sema::VariadicCallType CallType)
- : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args,
- formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
+ Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs)
+ : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
+ numDataArgs, beg, hasVAListArg, Args,
+ formatIdx, inFunctionCall, CallType, CheckedVarArgs),
+ ObjCContext(isObjC)
{}
@@ -2790,7 +3146,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// 'unichar' is defined as a typedef of unsigned short, but we should
// prefer using the typedef if it is visible.
IntendedTy = S.Context.UnsignedShortTy;
-
+
+ // While we are here, check if the value is an IntegerLiteral that happens
+ // to be within the valid range.
+ if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E)) {
+ const llvm::APInt &V = IL->getValue();
+ if (V.getActiveBits() <= S.Context.getTypeSize(IntendedTy))
+ return true;
+ }
+
LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getLocStart(),
Sema::LookupOrdinaryName);
if (S.LookupName(Result, S.getCurScope())) {
@@ -2918,15 +3282,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
- if (S.isValidVarArgType(ExprTy) == Sema::VAK_Invalid) {
- unsigned DiagKind;
- if (ExprTy->isObjCObjectType())
- DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
- else
- DiagKind = diag::warn_non_pod_vararg_with_format_string;
+ switch (S.isValidVarArgType(ExprTy)) {
+ case Sema::VAK_Valid:
+ case Sema::VAK_ValidInCXX11:
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
+ break;
+ case Sema::VAK_Undefined:
EmitFormatDiagnostic(
- S.PDiag(DiagKind)
+ S.PDiag(diag::warn_non_pod_vararg_with_format_string)
<< S.getLangOpts().CPlusPlus11
<< ExprTy
<< CallType
@@ -2934,15 +3303,33 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
-
checkForCStrMembers(AT, E, CSR);
- } else
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << ExprTy
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
+ break;
+
+ case Sema::VAK_Invalid:
+ if (ExprTy->isObjCObjectType())
+ EmitFormatDiagnostic(
+ S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
+ << S.getLangOpts().CPlusPlus11
+ << ExprTy
+ << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
+ else
+ // FIXME: If this is an initializer list, suggest removing the braces
+ // or inserting a cast to the target type.
+ S.Diag(E->getLocStart(), diag::err_cannot_pass_to_vararg_format)
+ << isa<InitListExpr>(E) << ExprTy << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << E->getSourceRange();
+ break;
+ }
+
+ assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() &&
+ "format string specifier index out of range");
+ CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true;
}
return true;
@@ -2958,10 +3345,12 @@ public:
unsigned numDataArgs, const char *beg, bool hasVAListArg,
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
- Sema::VariadicCallType CallType)
- : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, beg, hasVAListArg,
- Args, formatIdx, inFunctionCall, CallType)
+ Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs)
+ : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
+ numDataArgs, beg, hasVAListArg,
+ Args, formatIdx, inFunctionCall, CallType,
+ CheckedVarArgs)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
@@ -3116,7 +3505,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
- bool inFunctionCall, VariadicCallType CallType) {
+ bool inFunctionCall, VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
@@ -3146,7 +3536,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, (Type == FST_NSString),
Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType);
+ inFunctionCall, CallType, CheckedVarArgs);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
getLangOpts(),
@@ -3155,7 +3545,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType);
+ inFunctionCall, CallType, CheckedVarArgs);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
getLangOpts(),
@@ -3654,7 +4044,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
Decl *ParentDecl) {
if (E->isTypeDependent())
- return NULL;
+ return NULL;
// We should only be called for evaluating pointer expressions.
assert((E->getType()->isAnyPointerType() ||
@@ -4096,6 +4486,13 @@ static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
+static QualType GetExprType(Expr *E) {
+ QualType Ty = E->getType();
+ if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>())
+ Ty = AtomicRHS->getValueType();
+ return Ty;
+}
+
/// Pseudo-evaluate the given integer expression, estimating the
/// range of values it might take.
///
@@ -4106,7 +4503,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Try a full evaluation first.
Expr::EvalResult result;
if (E->EvaluateAsRValue(result, C))
- return GetValueRange(C, result.Val, E->getType(), MaxWidth);
+ return GetValueRange(C, result.Val, GetExprType(E), MaxWidth);
// I think we only want to look through implicit casts here; if the
// user has an explicit widening cast, we should treat the value as
@@ -4115,7 +4512,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
return GetExprRange(C, CE->getSubExpr(), MaxWidth);
- IntRange OutputTypeRange = IntRange::forValueOfType(C, CE->getType());
+ IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast);
@@ -4175,7 +4572,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BO_XorAssign:
case BO_OrAssign:
// TODO: bitfields?
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
// Simple assignments just pass through the RHS, which will have
// been coerced to the LHS type.
@@ -4186,7 +4583,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Operations with opaque sources are black-listed.
case BO_PtrMemD:
case BO_PtrMemI:
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
// Bitwise-and uses the *infinum* of the two source ranges.
case BO_And:
@@ -4201,14 +4598,14 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
if (IntegerLiteral *I
= dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
if (I->getValue() == 1) {
- IntRange R = IntRange::forValueOfType(C, E->getType());
+ IntRange R = IntRange::forValueOfType(C, GetExprType(E));
return IntRange(R.Width, /*NonNegative*/ true);
}
}
// fallthrough
case BO_ShlAssign:
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
// Right shift by a constant can narrow its left argument.
case BO_Shr:
@@ -4237,14 +4634,14 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Black-list pointer subtractions.
case BO_Sub:
if (BO->getLHS()->getType()->isPointerType())
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
break;
// The width of a division result is mostly determined by the size
// of the LHS.
case BO_Div: {
// Don't 'pre-truncate' the operands.
- unsigned opWidth = C.getIntWidth(E->getType());
+ unsigned opWidth = C.getIntWidth(GetExprType(E));
IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
// If the divisor is constant, use that.
@@ -4267,7 +4664,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// either side.
case BO_Rem: {
// Don't 'pre-truncate' the operands.
- unsigned opWidth = C.getIntWidth(E->getType());
+ unsigned opWidth = C.getIntWidth(GetExprType(E));
IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
@@ -4300,26 +4697,25 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Operations with opaque sources are black-listed.
case UO_Deref:
case UO_AddrOf: // should be impossible
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
default:
return GetExprRange(C, UO->getSubExpr(), MaxWidth);
}
}
-
- if (dyn_cast<OffsetOfExpr>(E)) {
- IntRange::forValueOfType(C, E->getType());
- }
+
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ return GetExprRange(C, OVE->getSourceExpr(), MaxWidth);
if (FieldDecl *BitField = E->getSourceBitField())
return IntRange(BitField->getBitWidthValue(C),
BitField->getType()->isUnsignedIntegerOrEnumerationType());
- return IntRange::forValueOfType(C, E->getType());
+ return IntRange::forValueOfType(C, GetExprType(E));
}
static IntRange GetExprRange(ASTContext &C, Expr *E) {
- return GetExprRange(C, E, C.getIntWidth(E->getType()));
+ return GetExprRange(C, E, C.getIntWidth(GetExprType(E)));
}
/// Checks whether the given value, which currently has the given
@@ -4390,6 +4786,10 @@ static bool HasEnumType(Expr *E) {
}
static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+ // Disable warning in template instantiations.
+ if (!S.ActiveTemplateInstantiations.empty())
+ return;
+
BinaryOperatorKind op = E->getOpcode();
if (E->isValueDependent())
return;
@@ -4417,6 +4817,10 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
Expr *Constant, Expr *Other,
llvm::APSInt Value,
bool RhsConstant) {
+ // Disable warning in template instantiations.
+ if (!S.ActiveTemplateInstantiations.empty())
+ return;
+
// 0 values are handled later by CheckTrivialUnsignedComparison().
if (Value == 0)
return;
@@ -4736,8 +5140,16 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
== llvm::APFloat::opOK && isExact)
return;
+ // FIXME: Force the precision of the source value down so we don't print
+ // digits which are usually useless (we don't really care here if we
+ // truncate a digit by accident in edge cases). Ideally, APFloat::toString
+ // would automatically print the shortest representation, but it's a bit
+ // tricky to implement.
SmallString<16> PrettySourceValue;
- Value.toString(PrettySourceValue);
+ unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
+ precision = (precision * 59 + 195) / 196;
+ Value.toString(PrettySourceValue, precision);
+
SmallString<16> PrettyTargetValue;
if (T->isSpecificBuiltinType(BuiltinType::Bool))
PrettyTargetValue = IntegerValue == 0 ? "false" : "true";
@@ -4843,7 +5255,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
<< FixItHint::CreateInsertion(E->getExprLoc(), "&");
QualType ReturnType;
UnresolvedSet<4> NonTemplateOverloads;
- S.isExprCallable(*E, ReturnType, NonTemplateOverloads);
+ S.tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
if (!ReturnType.isNull()
&& ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
S.Diag(E->getExprLoc(), diag::note_function_to_bool_call)
@@ -4966,7 +5378,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (!Loc.isMacroID() || CC.isMacroID())
S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
<< T << clang::SourceRange(CC)
- << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T));
+ << FixItHint::CreateReplacement(Loc,
+ S.getFixItZeroLiteralForType(T, Loc));
}
if (!Source->isIntegerType() || !Target->isIntegerType())
@@ -5133,7 +5546,15 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
CheckImplicitConversion(S, E, T, CC);
// Now continue drilling into this expression.
-
+
+ if (PseudoObjectExpr * POE = dyn_cast<PseudoObjectExpr>(E)) {
+ if (POE->getResultExpr())
+ E = POE->getResultExpr();
+ }
+
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ return AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
+
// Skip past explicit casts.
if (isa<ExplicitCastExpr>(E)) {
E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
@@ -5206,16 +5627,16 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
/// Diagnose when expression is an integer constant expression and its evaluation
/// results in integer overflow
void Sema::CheckForIntOverflow (Expr *E) {
- if (isa<BinaryOperator>(E->IgnoreParens())) {
- llvm::SmallVector<PartialDiagnosticAt, 4> Diags;
- E->EvaluateForOverflow(Context, &Diags);
- }
+ if (isa<BinaryOperator>(E->IgnoreParens()))
+ E->EvaluateForOverflow(Context);
}
namespace {
/// \brief Visitor for expressions which looks for unsequenced operations on the
/// same object.
class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
+ typedef EvaluatedExprVisitor<SequenceChecker> Base;
+
/// \brief A tree of sequenced regions within an expression. Two regions are
/// unsequenced if one is an ancestor or a descendent of the other. When we
/// finish processing an expression with sequencing, such as a comma
@@ -5227,7 +5648,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
unsigned Parent : 31;
bool Merged : 1;
};
- llvm::SmallVector<Value, 8> Values;
+ SmallVector<Value, 8> Values;
public:
/// \brief A region within an expression which may be sequenced with respect
@@ -5289,7 +5710,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// A read of an object. Multiple unsequenced reads are OK.
UK_Use,
/// A modification of an object which is sequenced before the value
- /// computation of the expression, such as ++n.
+ /// computation of the expression, such as ++n in C++.
UK_ModAsValue,
/// A modification of an object which is not sequenced before the value
/// computation of the expression, such as n++.
@@ -5321,10 +5742,10 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
SequenceTree::Seq Region;
/// Filled in with declarations which were modified as a side-effect
/// (that is, post-increment operations).
- llvm::SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
+ SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
/// Expressions to check later. We defer checking these to reduce
/// stack usage.
- llvm::SmallVectorImpl<Expr*> &WorkList;
+ SmallVectorImpl<Expr *> &WorkList;
/// RAII object wrapping the visitation of a sequenced subexpression of an
/// expression. At the end of this process, the side-effects of the evaluation
@@ -5347,10 +5768,39 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
}
SequenceChecker &Self;
- llvm::SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
- llvm::SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
+ SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
+ SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
};
+ /// RAII object wrapping the visitation of a subexpression which we might
+ /// choose to evaluate as a constant. If any subexpression is evaluated and
+ /// found to be non-constant, this allows us to suppress the evaluation of
+ /// the outer expression.
+ class EvaluationTracker {
+ public:
+ EvaluationTracker(SequenceChecker &Self)
+ : Self(Self), Prev(Self.EvalTracker), EvalOK(true) {
+ Self.EvalTracker = this;
+ }
+ ~EvaluationTracker() {
+ Self.EvalTracker = Prev;
+ if (Prev)
+ Prev->EvalOK &= EvalOK;
+ }
+
+ bool evaluate(const Expr *E, bool &Result) {
+ if (!EvalOK || E->isValueDependent())
+ return false;
+ EvalOK = E->EvaluateAsBooleanCondition(Result, Self.SemaRef.Context);
+ return EvalOK;
+ }
+
+ private:
+ SequenceChecker &Self;
+ EvaluationTracker *Prev;
+ bool EvalOK;
+ } *EvalTracker;
+
/// \brief Find the object which is produced by the specified expression,
/// if any.
Object getObject(Expr *E, bool Mod) const {
@@ -5429,10 +5879,9 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
}
public:
- SequenceChecker(Sema &S, Expr *E,
- llvm::SmallVectorImpl<Expr*> &WorkList)
- : EvaluatedExprVisitor<SequenceChecker>(S.Context), SemaRef(S),
- Region(Tree.root()), ModAsSideEffect(0), WorkList(WorkList) {
+ SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
+ : Base(S.Context), SemaRef(S), Region(Tree.root()), ModAsSideEffect(0),
+ WorkList(WorkList), EvalTracker(0) {
Visit(E);
}
@@ -5442,7 +5891,7 @@ public:
void VisitExpr(Expr *E) {
// By default, just recurse to evaluated subexpressions.
- EvaluatedExprVisitor<SequenceChecker>::VisitStmt(E);
+ Base::VisitStmt(E);
}
void VisitCastExpr(CastExpr *E) {
@@ -5509,7 +5958,12 @@ public:
Visit(BO->getRHS());
- notePostMod(O, BO, UK_ModAsValue);
+ // C++11 [expr.ass]p1:
+ // the assignment is sequenced [...] before the value computation of the
+ // assignment expression.
+ // C11 6.5.16/3 has no such rule.
+ notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
}
void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
VisitBinAssign(CAO);
@@ -5524,7 +5978,10 @@ public:
notePreMod(O, UO);
Visit(UO->getSubExpr());
- notePostMod(O, UO, UK_ModAsValue);
+ // C++11 [expr.pre.incr]p1:
+ // the expression ++x is equivalent to x+=1
+ notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
}
void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
@@ -5545,14 +6002,14 @@ public:
// value computation of the RHS, and hence before the value computation
// of the '&&' itself, unless the LHS evaluates to zero. We treat them
// as if they were unconditionally sequenced.
+ EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
Visit(BO->getLHS());
}
bool Result;
- if (!BO->getLHS()->isValueDependent() &&
- BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (Eval.evaluate(BO->getLHS(), Result)) {
if (!Result)
Visit(BO->getRHS());
} else {
@@ -5566,14 +6023,14 @@ public:
}
}
void VisitBinLAnd(BinaryOperator *BO) {
+ EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
Visit(BO->getLHS());
}
bool Result;
- if (!BO->getLHS()->isValueDependent() &&
- BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (Eval.evaluate(BO->getLHS(), Result)) {
if (Result)
Visit(BO->getRHS());
} else {
@@ -5584,12 +6041,14 @@ public:
// Only visit the condition, unless we can be sure which subexpression will
// be chosen.
void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
- SequencedSubexpression Sequenced(*this);
- Visit(CO->getCond());
+ EvaluationTracker Eval(*this);
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(CO->getCond());
+ }
bool Result;
- if (!CO->getCond()->isValueDependent() &&
- CO->getCond()->EvaluateAsBooleanCondition(Result, SemaRef.Context))
+ if (Eval.evaluate(CO->getCond(), Result))
Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
else {
WorkList.push_back(CO->getTrueExpr());
@@ -5597,12 +6056,28 @@ public:
}
}
+ void VisitCallExpr(CallExpr *CE) {
+ // C++11 [intro.execution]p15:
+ // When calling a function [...], every value computation and side effect
+ // associated with any argument expression, or with the postfix expression
+ // designating the called function, is sequenced before execution of every
+ // expression or statement in the body of the function [and thus before
+ // the value computation of its result].
+ SequencedSubexpression Sequenced(*this);
+ Base::VisitCallExpr(CE);
+
+ // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
+ }
+
void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ // This is a call, so all subexpressions are sequenced before the result.
+ SequencedSubexpression Sequenced(*this);
+
if (!CCE->isListInitialization())
return VisitExpr(CCE);
// In C++11, list initializations are sequenced.
- llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
E = CCE->arg_end();
@@ -5623,7 +6098,7 @@ public:
return VisitExpr(ILE);
// In C++11, list initializations are sequenced.
- llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
Expr *E = ILE->getInit(I);
@@ -5642,11 +6117,10 @@ public:
}
void Sema::CheckUnsequencedOperations(Expr *E) {
- llvm::SmallVector<Expr*, 8> WorkList;
+ SmallVector<Expr *, 8> WorkList;
WorkList.push_back(E);
while (!WorkList.empty()) {
- Expr *Item = WorkList.back();
- WorkList.pop_back();
+ Expr *Item = WorkList.pop_back_val();
SequenceChecker(*this, Item, WorkList);
}
}
@@ -5670,7 +6144,8 @@ void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
/// takes care of any checks that cannot be performed on the
/// declaration itself, e.g., that the types of each of the function
/// parameters are complete.
-bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
+bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
+ ParmVarDecl *const *PEnd,
bool CheckParameterNames) {
bool HasInvalidParm = false;
for (; P != PEnd; ++P) {
@@ -5711,6 +6186,15 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
}
PType= AT->getElementType();
}
+
+ // MSVC destroys objects passed by value in the callee. Therefore a
+ // function definition which takes such a parameter must be able to call the
+ // object's destructor.
+ if (getLangOpts().CPlusPlus &&
+ Context.getTargetInfo().getCXXABI().isArgumentDestroyedByCallee()) {
+ if (const RecordType *RT = Param->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(Param, RT);
+ }
}
return HasInvalidParm;
@@ -5892,7 +6376,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (SourceMgr.isInSystemHeader(RBracketLoc)) {
SourceLocation IndexLoc = SourceMgr.getSpellingLoc(
IndexExpr->getLocStart());
- if (SourceMgr.isFromSameFile(RBracketLoc, IndexLoc))
+ if (SourceMgr.isWrittenInSameFile(RBracketLoc, IndexLoc))
return;
}
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index fd2ce1749fe8..7a1b36b2d7ee 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -464,9 +464,8 @@ getRequiredQualification(ASTContext &Context,
NestedNameSpecifier *Result = 0;
while (!TargetParents.empty()) {
- const DeclContext *Parent = TargetParents.back();
- TargetParents.pop_back();
-
+ const DeclContext *Parent = TargetParents.pop_back_val();
+
if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
if (!Namespace->getIdentifier())
continue;
@@ -716,8 +715,8 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
return CCP_Unlikely;
// Context-based decisions.
- const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
+ const DeclContext *LexicalDC = ND->getLexicalDeclContext();
+ if (LexicalDC->isFunctionOrMethod()) {
// _cmd is relatively rare
if (const ImplicitParamDecl *ImplicitParam =
dyn_cast<ImplicitParamDecl>(ND))
@@ -727,6 +726,8 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
return CCP_LocalDeclaration;
}
+
+ const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
return CCP_MemberDeclaration;
@@ -877,8 +878,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
if (I->first->hasTagIdentifierNamespace() &&
- (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
- Decl::IDNS_ObjCProtocol)))
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol)))
continue;
// Protocols are in distinct namespaces from everything else.
@@ -1039,7 +1040,9 @@ void ResultBuilder::ExitScope() {
bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- unsigned IDNS = Decl::IDNS_Ordinary;
+ // If name lookup finds a local extern declaration, then we are in a
+ // context where it behaves like an ordinary name.
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
else if (SemaRef.getLangOpts().ObjC1) {
@@ -1057,7 +1060,7 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
return false;
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
else if (SemaRef.getLangOpts().ObjC1) {
@@ -1084,7 +1087,7 @@ bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const {
bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
@@ -3183,12 +3186,12 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
Builder.getAllocator().CopyString(Modules[I]->Name));
Results.AddResult(Result(Builder.TakeString(),
CCP_Declaration,
- CXCursor_NotImplemented,
+ CXCursor_ModuleImportDecl,
Modules[I]->isAvailable()
? CXAvailability_Available
: CXAvailability_NotAvailable));
}
- } else {
+ } else if (getLangOpts().Modules) {
// Load the named module.
Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path,
Module::AllVisible,
@@ -3203,7 +3206,7 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
Builder.getAllocator().CopyString((*Sub)->Name));
Results.AddResult(Result(Builder.TakeString(),
CCP_Declaration,
- CXCursor_NotImplemented,
+ CXCursor_ModuleImportDecl,
(*Sub)->isAvailable()
? CXAvailability_Available
: CXAvailability_NotAvailable));
@@ -3303,8 +3306,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
ParsedType Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
bool IsSuper,
ResultBuilder &Results);
@@ -3360,7 +3362,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
Scope::AtCatchScope)) == 0) {
ParsedType T = DS.getRepAsType();
if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType())
- AddClassMessageCompletions(*this, S, T, 0, 0, false, false, Results);
+ AddClassMessageCompletions(*this, S, T, None, false, false, Results);
}
// Note that we intentionally suppress macro results here, since we do not
@@ -3436,7 +3438,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
if (E.isInvalid())
CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
else if (getLangOpts().ObjC1)
- CodeCompleteObjCInstanceMessage(S, E.take(), 0, 0, false);
+ CodeCompleteObjCInstanceMessage(S, E.take(), None, false);
}
/// \brief The set of properties that have already been added, referenced by
@@ -3611,7 +3613,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
bool IsDependent = BaseType->isDependentType();
if (!IsDependent) {
for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
- if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) {
+ if (DeclContext *Ctx = DepScope->getEntity()) {
IsDependent = Ctx->isDependentContext();
break;
}
@@ -3847,7 +3849,7 @@ namespace {
};
}
-static bool anyNullArguments(llvm::ArrayRef<Expr*> Args) {
+static bool anyNullArguments(ArrayRef<Expr *> Args) {
if (Args.size() && !Args.data())
return true;
@@ -3858,8 +3860,7 @@ static bool anyNullArguments(llvm::ArrayRef<Expr*> Args) {
return false;
}
-void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
- llvm::ArrayRef<Expr *> Args) {
+void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
if (!CodeCompleter)
return;
@@ -4150,7 +4151,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
if (!CodeCompleter)
return;
- DeclContext *Ctx = (DeclContext *)S->getEntity();
+ DeclContext *Ctx = S->getEntity();
if (!S->getParent())
Ctx = Context.getTranslationUnitDecl();
@@ -4242,9 +4243,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
Results.data(),Results.size());
}
-void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
- CXXCtorInitializer** Initializers,
- unsigned NumInitializers) {
+void Sema::CodeCompleteConstructorInitializer(
+ Decl *ConstructorD,
+ ArrayRef <CXXCtorInitializer *> Initializers) {
PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
CXXConstructorDecl *Constructor
= static_cast<CXXConstructorDecl *>(ConstructorD);
@@ -4259,7 +4260,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
// Fill in any already-initialized fields or base classes.
llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
llvm::SmallPtrSet<CanQualType, 4> InitializedBases;
- for (unsigned I = 0; I != NumInitializers; ++I) {
+ for (unsigned I = 0, E = Initializers.size(); I != E; ++I) {
if (Initializers[I]->isBaseInitializer())
InitializedBases.insert(
Context.getCanonicalType(QualType(Initializers[I]->getBaseClass(), 0)));
@@ -4271,17 +4272,17 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
// Add completions for base classes.
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
- bool SawLastInitializer = (NumInitializers == 0);
+ bool SawLastInitializer = Initializers.empty();
CXXRecordDecl *ClassDecl = Constructor->getParent();
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
Base != BaseEnd; ++Base) {
if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) {
SawLastInitializer
- = NumInitializers > 0 &&
- Initializers[NumInitializers - 1]->isBaseInitializer() &&
+ = !Initializers.empty() &&
+ Initializers.back()->isBaseInitializer() &&
Context.hasSameUnqualifiedType(Base->getType(),
- QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0));
+ QualType(Initializers.back()->getBaseClass(), 0));
continue;
}
@@ -4303,10 +4304,10 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Base != BaseEnd; ++Base) {
if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) {
SawLastInitializer
- = NumInitializers > 0 &&
- Initializers[NumInitializers - 1]->isBaseInitializer() &&
+ = !Initializers.empty() &&
+ Initializers.back()->isBaseInitializer() &&
Context.hasSameUnqualifiedType(Base->getType(),
- QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0));
+ QualType(Initializers.back()->getBaseClass(), 0));
continue;
}
@@ -4328,9 +4329,9 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Field != FieldEnd; ++Field) {
if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))) {
SawLastInitializer
- = NumInitializers > 0 &&
- Initializers[NumInitializers - 1]->isAnyMemberInitializer() &&
- Initializers[NumInitializers - 1]->getAnyMember() == *Field;
+ = !Initializers.empty() &&
+ Initializers.back()->isAnyMemberInitializer() &&
+ Initializers.back()->getAnyMember() == *Field;
continue;
}
@@ -4358,7 +4359,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
/// \brief Determine whether this scope denotes a namespace.
static bool isNamespaceScope(Scope *S) {
- DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *DC = S->getEntity();
if (!DC)
return false;
@@ -4786,9 +4787,9 @@ enum ObjCMethodKind {
static bool isAcceptableObjCSelector(Selector Sel,
ObjCMethodKind WantKind,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AllowSameLength = true) {
+ unsigned NumSelIdents = SelIdents.size();
if (NumSelIdents > Sel.getNumArgs())
return false;
@@ -4810,11 +4811,10 @@ static bool isAcceptableObjCSelector(Selector Sel,
static bool isAcceptableObjCMethod(ObjCMethodDecl *Method,
ObjCMethodKind WantKind,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AllowSameLength = true) {
return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents,
- NumSelIdents, AllowSameLength);
+ AllowSameLength);
}
namespace {
@@ -4846,8 +4846,7 @@ namespace {
static void AddObjCMethods(ObjCContainerDecl *Container,
bool WantInstanceMethods,
ObjCMethodKind WantKind,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
DeclContext *CurContext,
VisitedSelectorSet &Selectors,
bool AllowSameLength,
@@ -4866,15 +4865,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
(isRootClass && !WantInstanceMethods)) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
- if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents,
- AllowSameLength))
+ if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, AllowSameLength))
continue;
if (!Selectors.insert(M->getSelector()))
continue;
Result R = Result(*M, Results.getBasePriority(*M), 0);
- R.StartParameter = NumSelIdents;
+ R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = (WantKind != MK_Any);
if (!InOriginalClass)
R.Priority += CCD_InBaseClass;
@@ -4891,8 +4889,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
E = Protocols.end();
I != E; ++I)
AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- NumSelIdents, CurContext, Selectors, AllowSameLength,
- Results, false);
+ CurContext, Selectors, AllowSameLength, Results, false);
}
}
@@ -4903,7 +4900,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
E = IFace->protocol_end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents,
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
CurContext, Selectors, AllowSameLength, Results, false);
// Add methods in categories.
@@ -4914,7 +4911,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
ObjCCategoryDecl *CatDecl = *Cat;
AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
- NumSelIdents, CurContext, Selectors, AllowSameLength,
+ CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
// Add a categories protocol methods.
@@ -4924,26 +4921,26 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
E = Protocols.end();
I != E; ++I)
AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- NumSelIdents, CurContext, Selectors, AllowSameLength,
+ CurContext, Selectors, AllowSameLength,
Results, false);
// Add methods in category implementations.
if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- NumSelIdents, CurContext, Selectors, AllowSameLength,
+ CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
}
// Add methods in superclass.
if (IFace->getSuperClass())
AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
- SelIdents, NumSelIdents, CurContext, Selectors,
+ SelIdents, CurContext, Selectors,
AllowSameLength, Results, false);
// Add methods in our implementation, if any.
if (ObjCImplementationDecl *Impl = IFace->getImplementation())
AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- NumSelIdents, CurContext, Selectors, AllowSameLength,
+ CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
}
@@ -4967,7 +4964,7 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -4995,7 +4992,7 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext,
+ AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext,
Selectors, /*AllowSameLength=*/true, Results);
Results.ExitScope();
@@ -5159,16 +5156,14 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
/// \param SelIdents The identifiers in the selector that have already been
/// provided as arguments for a send to "super".
///
-/// \param NumSelIdents The number of identifiers in \p SelIdents.
-///
/// \param Results The set of results to augment.
///
/// \returns the Objective-C method declaration that would be invoked by
/// this "super" completion. If NULL, no completion was added.
-static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
- ResultBuilder &Results) {
+static ObjCMethodDecl *AddSuperSendCompletion(
+ Sema &S, bool NeedSuperKeyword,
+ ArrayRef<IdentifierInfo *> SelIdents,
+ ResultBuilder &Results) {
ObjCMethodDecl *CurMethod = S.getCurMethodDecl();
if (!CurMethod)
return 0;
@@ -5244,14 +5239,14 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
} else {
ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin();
for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) {
- if (I > NumSelIdents)
+ if (I > SelIdents.size())
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- if (I < NumSelIdents)
+ if (I < SelIdents.size())
Builder.AddInformativeChunk(
Builder.getAllocator().CopyString(
Sel.getNameForSlot(I) + ":"));
- else if (NeedSuperKeyword || I > NumSelIdents) {
+ else if (NeedSuperKeyword || I > SelIdents.size()) {
Builder.AddTextChunk(
Builder.getAllocator().CopyString(
Sel.getNameForSlot(I) + ":"));
@@ -5293,7 +5288,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
if (Iface->getSuperClass()) {
Results.AddResult(Result("super"));
- AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
+ AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results);
}
if (getLangOpts().CPlusPlus11)
@@ -5309,8 +5304,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
}
void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression) {
ObjCInterfaceDecl *CDecl = 0;
if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
@@ -5328,8 +5322,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
// We are inside an instance method, which means that the message
// send [super ...] is actually calling an instance method on the
// current object.
- return CodeCompleteObjCInstanceMessage(S, 0,
- SelIdents, NumSelIdents,
+ return CodeCompleteObjCInstanceMessage(S, 0, SelIdents,
AtArgumentExpression,
CDecl);
}
@@ -5358,7 +5351,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
ExprResult SuperExpr = ActOnIdExpression(S, SS, TemplateKWLoc, id,
false, false);
return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),
- SelIdents, NumSelIdents,
+ SelIdents,
AtArgumentExpression);
}
@@ -5369,7 +5362,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
if (CDecl)
Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl));
return CodeCompleteObjCClassMessage(S, Receiver, SelIdents,
- NumSelIdents, AtArgumentExpression,
+ AtArgumentExpression,
/*IsSuper=*/true);
}
@@ -5409,8 +5402,7 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results,
static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
ParsedType Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
bool IsSuper,
ResultBuilder &Results) {
@@ -5434,8 +5426,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
// completion.
if (IsSuper) {
if (ObjCMethodDecl *SuperMethod
- = AddSuperSendCompletion(SemaRef, false, SelIdents, NumSelIdents,
- Results))
+ = AddSuperSendCompletion(SemaRef, false, SelIdents, Results))
Results.Ignore(SuperMethod);
}
@@ -5446,7 +5437,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
VisitedSelectorSet Selectors;
if (CDecl)
- AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents,
+ AddObjCMethods(CDecl, false, MK_Any, SelIdents,
SemaRef.CurContext, Selectors, AtArgumentExpression,
Results);
else {
@@ -5472,12 +5463,11 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
for (ObjCMethodList *MethList = &M->second.second;
MethList && MethList->Method;
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
- NumSelIdents))
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
continue;
Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
- R.StartParameter = NumSelIdents;
+ R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, SemaRef.CurContext);
}
@@ -5488,8 +5478,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
}
void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
bool IsSuper) {
@@ -5498,9 +5487,9 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage,
- T, SelIdents, NumSelIdents));
+ T, SelIdents));
- AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents,
+ AddClassMessageCompletions(*this, S, Receiver, SelIdents,
AtArgumentExpression, IsSuper, Results);
// If we're actually at the argument expression (rather than prior to the
@@ -5510,7 +5499,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
// our preferred type, improving completion results.
if (AtArgumentExpression) {
QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results,
- NumSelIdents);
+ SelIdents.size());
if (PreferredType.isNull())
CodeCompleteOrdinaryName(S, PCC_Expression);
else
@@ -5524,8 +5513,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
}
void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents,
+ ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression,
ObjCInterfaceDecl *Super) {
typedef CodeCompletionResult Result;
@@ -5553,7 +5541,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
if (ReceiverType->isObjCClassType())
return CodeCompleteObjCClassMessage(S,
ParsedType::make(Context.getObjCInterfaceType(IFace)),
- SelIdents, NumSelIdents,
+ SelIdents,
AtArgumentExpression, Super);
ReceiverType = Context.getObjCObjectPointerType(
@@ -5564,7 +5552,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage,
- ReceiverType, SelIdents, NumSelIdents));
+ ReceiverType, SelIdents));
Results.EnterNewScope();
@@ -5572,8 +5560,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
// completion.
if (Super) {
if (ObjCMethodDecl *SuperMethod
- = AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents,
- Results))
+ = AddSuperSendCompletion(*this, false, SelIdents, Results))
Results.Ignore(SuperMethod);
}
@@ -5592,7 +5579,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
ReceiverType->isObjCQualifiedClassType()) {
if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface())
- AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, NumSelIdents,
+ AddObjCMethods(ClassDecl, false, MK_Any, SelIdents,
CurContext, Selectors, AtArgumentExpression, Results);
}
}
@@ -5603,7 +5590,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(),
E = QualID->qual_end();
I != E; ++I)
- AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
+ AddObjCMethods(*I, true, MK_Any, SelIdents, CurContext,
Selectors, AtArgumentExpression, Results);
}
// Handle messages to a pointer to interface type.
@@ -5611,14 +5598,14 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
= ReceiverType->getAsObjCInterfacePointerType()) {
// Search the class, its superclasses, etc., for instance methods.
AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents,
- NumSelIdents, CurContext, Selectors, AtArgumentExpression,
+ CurContext, Selectors, AtArgumentExpression,
Results);
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(),
E = IFacePtr->qual_end();
I != E; ++I)
- AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
+ AddObjCMethods(*I, true, MK_Any, SelIdents, CurContext,
Selectors, AtArgumentExpression, Results);
}
// Handle messages to "id".
@@ -5645,15 +5632,14 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
for (ObjCMethodList *MethList = &M->second.first;
MethList && MethList->Method;
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
- NumSelIdents))
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
continue;
if (!Selectors.insert(MethList->Method->getSelector()))
continue;
Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
- R.StartParameter = NumSelIdents;
+ R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, CurContext);
}
@@ -5669,7 +5655,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
// our preferred type, improving completion results.
if (AtArgumentExpression) {
QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results,
- NumSelIdents);
+ SelIdents.size());
if (PreferredType.isNull())
CodeCompleteOrdinaryName(S, PCC_Expression);
else
@@ -5688,7 +5674,7 @@ void Sema::CodeCompleteObjCForCollection(Scope *S,
Data.ObjCCollection = true;
if (IterationVar.getAsOpaquePtr()) {
- DeclGroupRef DG = IterationVar.getAsVal<DeclGroupRef>();
+ DeclGroupRef DG = IterationVar.get();
for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) {
if (*I)
Data.IgnoreDecls.push_back(*I);
@@ -5698,8 +5684,8 @@ void Sema::CodeCompleteObjCForCollection(Scope *S,
CodeCompleteExpression(S, Data);
}
-void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
- unsigned NumSelIdents) {
+void Sema::CodeCompleteObjCSelector(Scope *S,
+ ArrayRef<IdentifierInfo *> SelIdents) {
// If we have an external source, load the entire class method
// pool from the AST file.
if (ExternalSource) {
@@ -5722,7 +5708,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
M != MEnd; ++M) {
Selector Sel = M->first;
- if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents))
+ if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents))
continue;
CodeCompletionBuilder Builder(Results.getAllocator(),
@@ -5736,7 +5722,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
std::string Accumulator;
for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) {
- if (I == NumSelIdents) {
+ if (I == SelIdents.size()) {
if (!Accumulator.empty()) {
Builder.AddInformativeChunk(Builder.getAllocator().CopyString(
Accumulator));
@@ -6128,8 +6114,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
// Mapping from selectors to the methods that implement that selector, along
// with the "in original class" flag.
-typedef llvm::DenseMap<Selector, std::pair<ObjCMethodDecl *, bool> >
- KnownMethodsMap;
+typedef llvm::DenseMap<
+ Selector, llvm::PointerIntPair<ObjCMethodDecl *, 1, bool> > KnownMethodsMap;
/// \brief Find all of the methods that reside in the given container
/// (and its superclasses, protocols, etc.) that meet the given
@@ -6218,7 +6204,8 @@ static void FindImplementableMethods(ASTContext &Context,
!Context.hasSameUnqualifiedType(ReturnType, M->getResultType()))
continue;
- KnownMethods[M->getSelector()] = std::make_pair(*M, InOriginalClass);
+ KnownMethods[M->getSelector()] =
+ KnownMethodsMap::mapped_type(*M, InOriginalClass);
}
}
}
@@ -6906,7 +6893,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
}
if (!SearchDecl && S) {
- if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity()))
+ if (DeclContext *DC = S->getEntity())
SearchDecl = dyn_cast<ObjCContainerDecl>(DC);
}
@@ -6932,7 +6919,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
for (KnownMethodsMap::iterator M = KnownMethods.begin(),
MEnd = KnownMethods.end();
M != MEnd; ++M) {
- ObjCMethodDecl *Method = M->second.first;
+ ObjCMethodDecl *Method = M->second.getPointer();
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -7000,7 +6987,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
}
unsigned Priority = CCP_CodePattern;
- if (!M->second.second)
+ if (!M->second.getInt())
Priority += CCD_InBaseClass;
Results.AddResult(Result(Builder.TakeString(), Method, Priority));
@@ -7054,8 +7041,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
bool IsInstanceMethod,
bool AtParameterName,
ParsedType ReturnTy,
- IdentifierInfo **SelIdents,
- unsigned NumSelIdents) {
+ ArrayRef<IdentifierInfo *> SelIdents) {
// If we have an external source, load the entire class method
// pool from the AST file.
if (ExternalSource) {
@@ -7086,12 +7072,12 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
&M->second.second;
MethList && MethList->Method;
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
- NumSelIdents))
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
continue;
if (AtParameterName) {
// Suggest parameter names we've seen before.
+ unsigned NumSelIdents = SelIdents.size();
if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) {
ParmVarDecl *Param = MethList->Method->param_begin()[NumSelIdents-1];
if (Param->getIdentifier()) {
@@ -7107,7 +7093,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
}
Result R(MethList->Method, Results.getBasePriority(MethList->Method), 0);
- R.StartParameter = NumSelIdents;
+ R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
R.DeclaringEntity = true;
Results.MaybeAddResult(R, CurContext);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e0e8bd646b32..328ce7059631 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -15,6 +15,7 @@
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
@@ -39,6 +40,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
@@ -108,6 +110,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_typeof:
+ case tok::annot_decltype:
case tok::kw_decltype:
return getLangOpts().CPlusPlus;
@@ -126,9 +129,6 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
/// determine whether the name refers to a type. If so, returns an
/// opaque pointer (actually a QualType) corresponding to that
/// type. Otherwise, returns NULL.
-///
-/// If name lookup results in an ambiguity, this routine will complain
-/// and then return NULL.
ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS,
bool isClassName, bool HasTrailingDot,
@@ -237,17 +237,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
IsCtorOrDtorName,
WantNontrivialTypeSourceInfo);
if (Ty) {
- std::string CorrectedStr(Correction.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(
- Correction.getQuoted(getLangOpts()));
- Diag(NameLoc, diag::err_unknown_type_or_class_name_suggest)
- << Result.getLookupName() << CorrectedQuotedStr << isClassName
- << FixItHint::CreateReplacement(SourceRange(NameLoc),
- CorrectedStr);
- if (NamedDecl *FirstDecl = Correction.getCorrectionDecl())
- Diag(FirstDecl->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
+ diagnoseTypo(Correction,
+ PDiag(diag::err_unknown_type_or_class_name_suggest)
+ << Result.getLookupName() << isClassName);
if (SS && NNS)
SS->MakeTrivial(Context, NNS, SourceRange(NameLoc));
*CorrectedII = NewII;
@@ -412,38 +404,33 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
Validator)) {
- std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
-
if (Corrected.isKeyword()) {
// We corrected to a keyword.
- IdentifierInfo *NewII = Corrected.getCorrectionAsIdentifierInfo();
- if (!isSimpleTypeSpecifier(NewII->getTokenID()))
- CorrectedQuotedStr = "the keyword " + CorrectedQuotedStr;
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << II << CorrectedQuotedStr
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- II = NewII;
+ diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
+ II = Corrected.getCorrectionAsIdentifierInfo();
} else {
- NamedDecl *Result = Corrected.getCorrectionDecl();
// We found a similarly-named type or interface; suggest that.
- if (!SS || !SS->isSet())
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << II << CorrectedQuotedStr
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << II << DC << CorrectedQuotedStr << SS->getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- else
+ if (!SS || !SS->isSet()) {
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_unknown_typename_suggest) << II);
+ } 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());
+ } else {
llvm_unreachable("could not have corrected a typo here");
+ }
- Diag(Result->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
- SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
- false, false, ParsedType(),
+ CXXScopeSpec tmpSS;
+ if (Corrected.getCorrectionSpecifier())
+ tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
+ SourceRange(IILoc));
+ SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(),
+ IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false,
+ false, ParsedType(),
/*IsCtorOrDtorName=*/false,
/*NonTrivialTypeSourceInfo=*/true);
}
@@ -460,7 +447,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false,
Name, ParsedType(), true, TemplateResult,
MemberOfUnknownSpecialization) == TNK_Type_template) {
- TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
+ TemplateName TplName = TemplateResult.get();
Diag(IILoc, diag::err_template_missing_args) << TplName;
if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
Diag(TplDecl->getLocation(), diag::note_template_decl_here)
@@ -662,9 +649,7 @@ Corrected:
&SS, *CCC)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
- std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
-
+
NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
NamedDecl *UnderlyingFirstDecl
= FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
@@ -680,33 +665,30 @@ Corrected:
QualifiedDiag = diag::err_unknown_nested_typename_suggest;
}
- if (SS.isEmpty())
- Diag(NameLoc, UnqualifiedDiag)
- << Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
- else // FIXME: is this even reachable? Test it.
- Diag(NameLoc, QualifiedDiag)
- << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
- << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
+ if (SS.isEmpty()) {
+ diagnoseTypo(Corrected, PDiag(UnqualifiedDiag) << Name);
+ } else {// FIXME: is this even reachable? Test it.
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
+ Name->getName().equals(CorrectedStr);
+ diagnoseTypo(Corrected, PDiag(QualifiedDiag)
+ << Name << computeDeclContext(SS, false)
+ << DroppedSpecifier << SS.getRange());
+ }
// Update the name, so that the caller has the new name.
Name = Corrected.getCorrectionAsIdentifierInfo();
-
+
// Typo correction corrected to a keyword.
if (Corrected.isKeyword())
- return Corrected.getCorrectionAsIdentifierInfo();
+ return Name;
// Also update the LookupResult...
// FIXME: This should probably go away at some point
Result.clear();
Result.setLookupName(Corrected.getCorrection());
- if (FirstDecl) {
+ if (FirstDecl)
Result.addDecl(FirstDecl);
- Diag(FirstDecl->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
- }
// If we found an Objective-C instance variable, let
// LookupInObjCMethod build the appropriate expression to
@@ -789,6 +771,7 @@ Corrected:
if (!Result.empty()) {
bool IsFunctionTemplate;
+ bool IsVarTemplate;
TemplateName Template;
if (Result.end() - Result.begin() > 1) {
IsFunctionTemplate = true;
@@ -798,7 +781,8 @@ Corrected:
TemplateDecl *TD
= cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl());
IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
-
+ IsVarTemplate = isa<VarTemplateDecl>(TD);
+
if (SS.isSet() && !SS.isInvalid())
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false,
@@ -815,8 +799,9 @@ Corrected:
return NameClassification::FunctionTemplate(Template);
}
-
- return NameClassification::TypeTemplate(Template);
+
+ return IsVarTemplate ? NameClassification::VarTemplate(Template)
+ : NameClassification::TypeTemplate(Template);
}
}
@@ -858,18 +843,16 @@ Corrected:
// Check for a tag type hidden by a non-type decl in a few cases where it
// seems likely a type is wanted instead of the non-type that was found.
- if (!getLangOpts().ObjC1) {
- bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
- if ((NextToken.is(tok::identifier) ||
- (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
- isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
- TypeDecl *Type = Result.getAsSingle<TypeDecl>();
- DiagnoseUseOfDecl(Type, NameLoc);
- QualType T = Context.getTypeDeclType(Type);
- if (SS.isNotEmpty())
- return buildNestedType(*this, SS, T, NameLoc);
- return ParsedType::make(T);
- }
+ bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
+ if ((NextToken.is(tok::identifier) ||
+ (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
+ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
+ TypeDecl *Type = Result.getAsSingle<TypeDecl>();
+ DiagnoseUseOfDecl(Type, NameLoc);
+ QualType T = Context.getTypeDeclType(Type);
+ if (SS.isNotEmpty())
+ return buildNestedType(*this, SS, T, NameLoc);
+ return ParsedType::make(T);
}
if (FirstDecl->isCXXClassMember())
@@ -887,7 +870,16 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) {
// Functions defined inline within classes aren't parsed until we've
// finished parsing the top-level class, so the top-level class is
// the context we'll need to return to.
- if (isa<FunctionDecl>(DC)) {
+ // A Lambda call operator whose parent is a class must not be treated
+ // as an inline member function. A Lambda can be used legally
+ // either as an in-class member initializer or a default argument. These
+ // are parsed once the class has been marked complete and so the containing
+ // context would be the nested class (when the lambda is defined in one);
+ // If the class is not complete, then the lambda is being used in an
+ // ill-formed fashion (such as to specify the width of a bit-field, or
+ // in an array-bound) - in which case we still want to return the
+ // lexically containing DC (which could be a nested class).
+ if (isa<FunctionDecl>(DC) && !isLambdaCallOperator(DC)) {
DC = DC->getLexicalParent();
// A function not defined within a class will always return to its
@@ -962,7 +954,7 @@ void Sema::ExitDeclaratorContext(Scope *S) {
// enforced by an assert in EnterDeclaratorContext.
Scope *Ancestor = S->getParent();
while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
- CurContext = (DeclContext*) Ancestor->getEntity();
+ CurContext = Ancestor->getEntity();
// We don't need to do anything with the scope, which is going to
// disappear.
@@ -1032,8 +1024,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// Move up the scope chain until we find the nearest enclosing
// non-transparent context. The declaration will be introduced into this
// scope.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext())
+ while (S->getEntity() && S->getEntity()->isTransparentContext())
S = S->getParent();
// Add scoped declarations into their context, so that they can be
@@ -1042,12 +1033,12 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
if (AddToContext)
CurContext->addDecl(D);
- // Out-of-line definitions shouldn't be pushed into scope in C++.
- // Out-of-line variable and function definitions shouldn't even in C.
- if ((getLangOpts().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
- D->isOutOfLine() &&
+ // Out-of-line definitions shouldn't be pushed into scope in C++, unless they
+ // are function-local declarations.
+ if (getLangOpts().CPlusPlus && D->isOutOfLine() &&
!D->getDeclContext()->getRedeclContext()->Equals(
- D->getLexicalDeclContext()->getRedeclContext()))
+ D->getLexicalDeclContext()->getRedeclContext()) &&
+ !D->getLexicalDeclContext()->isFunctionOrMethod())
return;
// Template instantiations should also not be pushed into scope.
@@ -1094,7 +1085,7 @@ void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
TUScope->AddDecl(D);
}
-bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
+bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) {
return IdResolver.isDeclInScope(D, Ctx, S,
ExplicitInstantiationOrSpecialization);
@@ -1103,7 +1094,7 @@ bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
DeclContext *TargetDC = DC->getPrimaryContext();
do {
- if (DeclContext *ScopeDC = (DeclContext*) S->getEntity())
+ if (DeclContext *ScopeDC = S->getEntity())
if (ScopeDC->getPrimaryContext() == TargetDC)
return S;
} while ((S = S->getParent()));
@@ -1196,7 +1187,15 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
DC = DC->getParent();
}
- return !D->hasExternalLinkage();
+ return !D->isExternallyVisible();
+}
+
+// FIXME: This needs to be refactored; some other isInMainFile users want
+// these semantics.
+static bool isMainFileLoc(const Sema &S, SourceLocation Loc) {
+ if (S.TUKind != TU_Complete)
+ return false;
+ return S.SourceMgr.isInMainFile(Loc);
}
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
@@ -1218,12 +1217,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD))
return false;
} else {
- // 'static inline' functions are used in headers; don't warn.
- // Make sure we get the storage class from the canonical declaration,
- // since otherwise we will get spurious warnings on specialized
- // static template functions.
- if (FD->getCanonicalDecl()->getStorageClass() == SC_Static &&
- FD->isInlineSpecified())
+ // 'static inline' functions are defined in headers; don't warn.
+ if (FD->isInlineSpecified() &&
+ !isMainFileLoc(*this, FD->getLocation()))
return false;
}
@@ -1231,21 +1227,18 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
Context.DeclMustBeEmitted(FD))
return false;
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- // Don't warn on variables of const-qualified or reference type, since their
- // values can be used even if though they're not odr-used, and because const
- // qualified variables can appear in headers in contexts where they're not
- // intended to be used.
- // FIXME: Use more principled rules for these exemptions.
- if (!VD->isFileVarDecl() ||
- VD->getType().isConstQualified() ||
- VD->getType()->isReferenceType() ||
- Context.DeclMustBeEmitted(VD))
+ // Constants and utility variables are defined in headers with internal
+ // linkage; don't warn. (Unlike functions, there isn't a convenient marker
+ // like "inline".)
+ if (!isMainFileLoc(*this, VD->getLocation()))
+ return false;
+
+ if (Context.DeclMustBeEmitted(VD))
return false;
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
-
} else {
return false;
}
@@ -1259,13 +1252,13 @@ void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
return;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- const FunctionDecl *First = FD->getFirstDeclaration();
+ const FunctionDecl *First = FD->getFirstDecl();
if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First))
return; // First should already be in the vector.
}
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- const VarDecl *First = VD->getFirstDeclaration();
+ const VarDecl *First = VD->getFirstDecl();
if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First))
return; // First should already be in the vector.
}
@@ -1312,7 +1305,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- if (!RD->hasTrivialDestructor())
+ if (!RD->hasTrivialDestructor() && !RD->hasAttr<WarnUnusedAttr>())
return false;
if (const Expr *Init = VD->getInit()) {
@@ -1322,7 +1315,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
CXXConstructorDecl *CD = Construct->getConstructor();
- if (!CD->isTrivial())
+ if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>())
return false;
}
}
@@ -1402,6 +1395,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
+ DiagnoseUnusedBackingIvarInAccessor(S);
}
void Sema::ActOnStartFunctionDeclarator() {
@@ -1440,13 +1434,8 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
LookupOrdinaryName, TUScope, NULL,
Validator)) {
+ diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
- Diag(IdLoc, diag::err_undef_interface_suggest)
- << Id << IDecl->getDeclName()
- << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
- Diag(IDecl->getLocation(), diag::note_previous_decl)
- << IDecl->getDeclName();
-
Id = IDecl->getIdentifier();
}
}
@@ -1482,8 +1471,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
/// contain non-field names.
Scope *Sema::getNonFieldDeclScope(Scope *S) {
while (((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext()) ||
+ (S->getEntity() && S->getEntity()->isTransparentContext()) ||
(S->isClassScope() && !getLangOpts().CPlusPlus))
S = S->getParent();
return S;
@@ -1556,8 +1544,17 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
<< Context.BuiltinInfo.GetName(BID);
}
+ DeclContext *Parent = Context.getTranslationUnitDecl();
+ if (getLangOpts().CPlusPlus) {
+ LinkageSpecDecl *CLinkageDecl =
+ LinkageSpecDecl::Create(Context, Parent, Loc, Loc,
+ LinkageSpecDecl::lang_c, false);
+ Parent->addDecl(CLinkageDecl);
+ Parent = CLinkageDecl;
+ }
+
FunctionDecl *New = FunctionDecl::Create(Context,
- Context.getTranslationUnitDecl(),
+ Parent,
Loc, Loc, II, R, /*TInfo=*/0,
SC_Extern,
false,
@@ -1581,13 +1578,14 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
}
AddKnownFunctionAttributes(New);
+ RegisterLocallyScopedExternCDecl(New, S);
// TUScope is the translation-unit scope to insert this function into.
// FIXME: This is hideous. We need to teach PushOnScopeChains to
// relate Scopes to DeclContexts, and probably eliminate CurContext
// entirely, but we're not there yet.
DeclContext *SavedContext = CurContext;
- CurContext = Context.getTranslationUnitDecl();
+ CurContext = Parent;
PushOnScopeChains(New, TUScope);
CurContext = SavedContext;
return New;
@@ -1616,7 +1614,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
if (!old->isHidden())
continue;
- if (old->getLinkage() != ExternalLinkage)
+ if (!old->isExternallyVisible())
filter.erase();
}
@@ -1730,10 +1728,12 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
if (isIncompatibleTypedef(Old, New))
return;
- // The types match. Link up the redeclaration chain if the old
- // declaration was a typedef.
- if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
- New->setPreviousDeclaration(Typedef);
+ // The types match. Link up the redeclaration chain and merge attributes if
+ // the old declaration was a typedef.
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old)) {
+ New->setPreviousDecl(Typedef);
+ mergeDeclAttributes(New, Old);
+ }
if (getLangOpts().MicrosoftExt)
return;
@@ -2014,11 +2014,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
static const Decl *getDefinition(const Decl *D) {
if (const TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- return VD->getDefinition();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ const VarDecl *Def = VD->getDefinition();
+ if (Def)
+ return Def;
+ return VD->getActingDefinition();
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
const FunctionDecl* Def;
- if (FD->hasBody(Def))
+ if (FD->isDefined(Def))
return Def;
}
return NULL;
@@ -2047,6 +2051,32 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
AttrVec &NewAttributes = New->getAttrs();
for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
const Attr *NewAttribute = NewAttributes[I];
+
+ if (isa<AliasAttr>(NewAttribute)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New))
+ S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def));
+ else {
+ VarDecl *VD = cast<VarDecl>(New);
+ unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() ==
+ VarDecl::TentativeDefinition
+ ? diag::err_alias_after_tentative
+ : diag::err_redefinition;
+ S.Diag(VD->getLocation(), Diag) << VD->getDeclName();
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
+ VD->setInvalidDecl();
+ }
+ ++I;
+ continue;
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(Def)) {
+ // Tentative definitions are only interesting for the alias check above.
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition) {
+ ++I;
+ continue;
+ }
+ }
+
if (hasAttribute(Def, NewAttribute->getKind())) {
++I;
continue; // regular attr merging will take care of validating this.
@@ -2087,6 +2117,12 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK) {
+ if (UsedAttr *OldAttr = Old->getMostRecentDecl()->getAttr<UsedAttr>()) {
+ UsedAttr *NewAttr = OldAttr->clone(Context);
+ NewAttr->setInherited(true);
+ New->addAttr(NewAttr);
+ }
+
if (!Old->hasAttrs() && !New->hasAttrs())
return;
@@ -2124,6 +2160,10 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}
+ // Already handled.
+ if (isa<UsedAttr>(*i))
+ continue;
+
if (mergeDeclAttribute(*this, New, *i, Override))
foundAny = true;
}
@@ -2150,7 +2190,7 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
// Find the first declaration of the parameter.
// FIXME: Should we build redeclaration chains for function parameters?
const FunctionDecl *FirstFD =
- cast<FunctionDecl>(oldDecl->getDeclContext())->getFirstDeclaration();
+ cast<FunctionDecl>(oldDecl->getDeclContext())->getFirstDecl();
const ParmVarDecl *FirstVD =
FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex());
S.Diag(FirstVD->getLocation(),
@@ -2226,17 +2266,11 @@ static bool canRedefineFunction(const FunctionDecl *FD,
FD->getStorageClass() == SC_Extern);
}
-/// Is the given calling convention the ABI default for the given
-/// declaration?
-static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
- CallingConv ABIDefaultCC;
- if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
- ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic());
- } else {
- // Free C function or a static method.
- ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C);
- }
- return ABIDefaultCC == CC;
+const AttributedType *Sema::getCallingConvAttributedType(QualType T) const {
+ const AttributedType *AT = T->getAs<AttributedType>();
+ while (AT && !AT->isCallingConv())
+ AT = AT->getModifiedType()->getAs<AttributedType>();
+ return AT;
}
template <typename T>
@@ -2264,7 +2298,8 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) {
/// merged with.
///
/// Returns true if there was an error, false otherwise.
-bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
+bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
+ bool MergeTypeWithOld) {
// Verify the old decl was also a function.
FunctionDecl *Old = 0;
if (FunctionTemplateDecl *OldFunctionTemplate
@@ -2297,6 +2332,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
return true;
}
+ // If the old declaration is invalid, just give up here.
+ if (Old->isInvalidDecl())
+ return true;
+
// Determine whether the previous declaration was a definition,
// implicit declaration, or a declaration.
diag::kind PrevDiag;
@@ -2307,16 +2346,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
else
PrevDiag = diag::note_previous_declaration;
- QualType OldQType = Context.getCanonicalType(Old->getType());
- QualType NewQType = Context.getCanonicalType(New->getType());
-
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
// Don't complain about specializations. They are not supposed to have
// storage classes.
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == SC_Static &&
- isExternalLinkage(Old->getLinkage()) &&
+ Old->hasExternalFormalLinkage() &&
!New->getTemplateSpecializationInfo() &&
!canRedefineFunction(Old, getLangOpts())) {
if (getLangOpts().MicrosoftExt) {
@@ -2329,53 +2365,52 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
}
}
- // If a function is first declared with a calling convention, but is
- // later declared or defined without one, the second decl assumes the
- // calling convention of the first.
+
+ // 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.
//
// It's OK if a function is first declared without a calling convention,
// but is later declared or defined with the default calling convention.
//
- // For the new decl, we have to look at the NON-canonical type to tell the
- // difference between a function that really doesn't have a calling
- // convention and one that is declared cdecl. That's because in
- // canonicalization (see ASTContext.cpp), cdecl is canonicalized away
- // because it is the default calling convention.
+ // To test if either decl has an explicit calling convention, we look for
+ // AttributedType sugar nodes on the type as written. If they are missing or
+ // were canonicalized away, we assume the calling convention was implicit.
//
// Note also that we DO NOT return at this point, because we still have
// other tests to run.
+ QualType OldQType = Context.getCanonicalType(Old->getType());
+ QualType NewQType = Context.getCanonicalType(New->getType());
const FunctionType *OldType = cast<FunctionType>(OldQType);
- const FunctionType *NewType = New->getType()->getAs<FunctionType>();
+ const FunctionType *NewType = cast<FunctionType>(NewQType);
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
bool RequiresAdjustment = false;
- if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) {
- // Fast path: nothing to do.
-
- // Inherit the CC from the previous declaration if it was specified
- // there but not here.
- } else if (NewTypeInfo.getCC() == CC_Default) {
- NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
- RequiresAdjustment = true;
- // Don't complain about mismatches when the default CC is
- // effectively the same as the explict one. Only Old decl contains correct
- // information about storage class of CXXMethod.
- } else if (OldTypeInfo.getCC() == CC_Default &&
- isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) {
- NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
- RequiresAdjustment = true;
-
- } else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
- NewTypeInfo.getCC())) {
- // Calling conventions really aren't compatible, so complain.
- Diag(New->getLocation(), diag::err_cconv_change)
- << FunctionType::getNameForCallConv(NewTypeInfo.getCC())
- << (OldTypeInfo.getCC() == CC_Default)
- << (OldTypeInfo.getCC() == CC_Default ? "" :
- FunctionType::getNameForCallConv(OldTypeInfo.getCC()));
- Diag(Old->getLocation(), diag::note_previous_declaration);
- return true;
+ if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) {
+ FunctionDecl *First = Old->getFirstDecl();
+ const FunctionType *FT =
+ First->getType().getCanonicalType()->castAs<FunctionType>();
+ FunctionType::ExtInfo FI = FT->getExtInfo();
+ bool NewCCExplicit = getCallingConvAttributedType(New->getType());
+ if (!NewCCExplicit) {
+ // Inherit the CC from the previous declaration if it was specified
+ // there but not here.
+ NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
+ RequiresAdjustment = true;
+ } else {
+ // Calling conventions aren't compatible, so complain.
+ bool FirstCCExplicit = getCallingConvAttributedType(First->getType());
+ Diag(New->getLocation(), diag::err_cconv_change)
+ << FunctionType::getNameForCallConv(NewTypeInfo.getCC())
+ << !FirstCCExplicit
+ << (!FirstCCExplicit ? "" :
+ FunctionType::getNameForCallConv(FI.getCC()));
+
+ // Put the note on the first decl, since it is the one that matters.
+ Diag(First->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
}
// FIXME: diagnose the other way around?
@@ -2412,9 +2447,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
}
if (RequiresAdjustment) {
- NewType = Context.adjustFunctionType(NewType, NewTypeInfo);
- New->setType(QualType(NewType, 0));
+ const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>();
+ AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo);
+ New->setType(QualType(AdjustedType, 0));
NewQType = Context.getCanonicalType(New->getType());
+ NewType = cast<FunctionType>(NewQType);
}
// If this redeclaration makes the function inline, we may need to add it to
@@ -2441,7 +2478,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// cannot be overloaded.
// Go back to the type source info to compare the declared return types,
- // per C++1y [dcl.type.auto]p??:
+ // per C++1y [dcl.type.auto]p13:
// Redeclarations or specializations of a function or function template
// with a declared return type that uses a placeholder type shall also
// use that placeholder, not a deduced type.
@@ -2452,7 +2489,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getResultType();
QualType ResQT;
- if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) {
+ if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
+ !((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl())) {
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
@@ -2476,9 +2515,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// defined, copy the deduced value from the old declaration.
AutoType *OldAT = Old->getResultType()->getContainedAutoType();
if (OldAT && OldAT->isDeduced()) {
- New->setType(SubstAutoType(New->getType(), OldAT->getDeducedType()));
+ New->setType(
+ SubstAutoType(New->getType(),
+ OldAT->isDependentType() ? Context.DependentTy
+ : OldAT->getDeducedType()));
NewQType = Context.getCanonicalType(
- SubstAutoType(NewQType, OldAT->getDeducedType()));
+ SubstAutoType(NewQType,
+ OldAT->isDependentType() ? Context.DependentTy
+ : OldAT->getDeducedType()));
}
}
@@ -2501,7 +2545,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
// is a static member function declaration.
- if (OldMethod->isStatic() || NewMethod->isStatic()) {
+ if (OldMethod->isStatic() != NewMethod->isStatic()) {
Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
return true;
@@ -2559,7 +2603,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
!Old->hasAttr<CXX11NoReturnAttr>()) {
Diag(New->getAttr<CXX11NoReturnAttr>()->getLocation(),
diag::err_noreturn_missing_on_first_decl);
- Diag(Old->getFirstDeclaration()->getLocation(),
+ Diag(Old->getFirstDecl()->getLocation(),
diag::note_noreturn_missing_first_decl);
}
@@ -2571,7 +2615,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
!Old->hasAttr<CarriesDependencyAttr>()) {
Diag(New->getAttr<CarriesDependencyAttr>()->getLocation(),
diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/;
- Diag(Old->getFirstDeclaration()->getLocation(),
+ Diag(Old->getFirstDecl()->getLocation(),
diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
}
@@ -2591,13 +2635,34 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
}
if (haveIncompatibleLanguageLinkages(Old, New)) {
- Diag(New->getLocation(), diag::err_different_language_linkage) << New;
- Diag(Old->getLocation(), PrevDiag);
- return true;
+ // As a special case, retain the language linkage from previous
+ // declarations of a friend function as an extension.
+ //
+ // This liberal interpretation of C++ [class.friend]p3 matches GCC/MSVC
+ // and is useful because there's otherwise no way to specify language
+ // linkage within class scope.
+ //
+ // Check cautiously as the friend object kind isn't yet complete.
+ if (New->getFriendObjectKind() != Decl::FOK_None) {
+ Diag(New->getLocation(), diag::ext_retained_language_linkage) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ } else {
+ Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ return true;
+ }
}
if (OldQTypeForComparison == NewQType)
- return MergeCompatibleFunctionDecls(New, Old, S);
+ return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+
+ if ((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl()) {
+ // It's OK if we couldn't merge types for a local function declaraton
+ // if either the old or new type is dependent. We'll merge the types
+ // when we instantiate the function.
+ return false;
+ }
// Fall through for conflicting redeclarations and redefinitions.
}
@@ -2609,7 +2674,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
const FunctionProtoType *OldProto = 0;
- if (isa<FunctionNoProtoType>(NewFuncType) &&
+ if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
(OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
@@ -2642,7 +2707,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
New->setParams(Params);
}
- return MergeCompatibleFunctionDecls(New, Old, S);
+ return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
}
// GNU C permits a K&R definition to follow a prototype declaration
@@ -2700,9 +2765,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
diag::note_previous_declaration);
}
- New->setType(Context.getFunctionType(MergedReturn, ArgTypes,
- OldProto->getExtProtoInfo()));
- return MergeCompatibleFunctionDecls(New, Old, S);
+ if (MergeTypeWithOld)
+ New->setType(Context.getFunctionType(MergedReturn, ArgTypes,
+ OldProto->getExtProtoInfo()));
+ return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
}
// Fall through to diagnose conflicting types.
@@ -2730,7 +2796,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// local declaration will produce a hard error; if it doesn't
// remain visible, a single bogus local redeclaration (which is
// actually only a warning) could break all the downstream code.
- if (!New->getDeclContext()->isFunctionOrMethod())
+ if (!New->getLexicalDeclContext()->isFunctionOrMethod())
New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin);
return false;
@@ -2748,13 +2814,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
/// known to be compatible.
///
/// This routine handles the merging of attributes and other
-/// properties of function declarations form the old declaration to
+/// properties of function declarations from the old declaration to
/// the new declaration, once we know that New is in fact a
/// redeclaration of Old.
///
/// \returns false
bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
- Scope *S) {
+ Scope *S, bool MergeTypeWithOld) {
// Merge the attributes
mergeDeclAttributes(New, Old);
@@ -2763,8 +2829,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
New->setPure();
// Merge "used" flag.
- if (Old->isUsed(false))
- New->setUsed();
+ if (Old->getMostRecentDecl()->isUsed(false))
+ New->setIsUsed();
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
@@ -2777,9 +2843,10 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
return MergeCXXFunctionDecl(New, Old, S);
// Merge the function types so the we get the composite types for the return
- // and argument types.
+ // and argument types. Per C11 6.2.7/4, only update the type if the old decl
+ // was visible.
QualType Merged = Context.mergeTypes(Old->getType(), New->getType());
- if (!Merged.isNull())
+ if (!Merged.isNull() && MergeTypeWithOld)
New->setType(Merged);
return false;
@@ -2813,7 +2880,8 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
/// to here in AddInitializerToDecl. We can't check them before the initializer
/// is attached.
-void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
+ bool MergeTypeWithOld) {
if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
@@ -2839,21 +2907,48 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
NewArray->getElementType()))
MergedT = New->getType();
} else if (Old->getType()->isArrayType() &&
- New->getType()->isIncompleteArrayType()) {
+ New->getType()->isIncompleteArrayType()) {
const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
const ArrayType *NewArray = Context.getAsArrayType(New->getType());
if (Context.hasSameType(OldArray->getElementType(),
NewArray->getElementType()))
MergedT = Old->getType();
- } else if (New->getType()->isObjCObjectPointerType()
- && Old->getType()->isObjCObjectPointerType()) {
- MergedT = Context.mergeObjCGCQualifiers(New->getType(),
- Old->getType());
+ } else if (New->getType()->isObjCObjectPointerType() &&
+ Old->getType()->isObjCObjectPointerType()) {
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(),
+ Old->getType());
}
} else {
+ // C 6.2.7p2:
+ // All declarations that refer to the same object or function shall have
+ // compatible type.
MergedT = Context.mergeTypes(New->getType(), Old->getType());
}
if (MergedT.isNull()) {
+ // It's OK if we couldn't merge types if either type is dependent, for a
+ // block-scope variable. In other cases (static data members of class
+ // templates, variable templates, ...), we require the types to be
+ // equivalent.
+ // FIXME: The C++ standard doesn't say anything about this.
+ if ((New->getType()->isDependentType() ||
+ Old->getType()->isDependentType()) && New->isLocalVarDecl()) {
+ // If the old type was dependent, we can't merge with it, so the new type
+ // becomes dependent for now. We'll reproduce the original type when we
+ // instantiate the TypeSourceInfo for the variable.
+ if (!New->getType()->isDependentType() && MergeTypeWithOld)
+ New->setType(Context.DependentTy);
+ return;
+ }
+
+ // FIXME: Even if this merging succeeds, some other non-visible declaration
+ // of this variable might have an incompatible type. For instance:
+ //
+ // extern int arr[];
+ // void f() { extern int arr[2]; }
+ // void g() { extern int arr[3]; }
+ //
+ // Neither C nor C++ requires a diagnostic for this, but we should still try
+ // to diagnose it.
Diag(New->getLocation(), diag::err_redefinition_different_type)
<< New->getDeclName() << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_previous_definition);
@@ -2861,11 +2956,40 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
}
// Don't actually update the type on the new declaration if the old
- // declaration was a extern declaration in a different scope.
- if (!OldWasHidden)
+ // declaration was an extern declaration in a different scope.
+ if (MergeTypeWithOld)
New->setType(MergedT);
}
+static bool mergeTypeWithPrevious(Sema &S, VarDecl *NewVD, VarDecl *OldVD,
+ LookupResult &Previous) {
+ // C11 6.2.7p4:
+ // For an identifier with internal or external linkage declared
+ // in a scope in which a prior declaration of that identifier is
+ // visible, if the prior declaration specifies internal or
+ // external linkage, the type of the identifier at the later
+ // declaration becomes the composite type.
+ //
+ // If the variable isn't visible, we do not merge with its type.
+ if (Previous.isShadowed())
+ return false;
+
+ if (S.getLangOpts().CPlusPlus) {
+ // C++11 [dcl.array]p3:
+ // If there is a preceding declaration of the entity in the same
+ // scope in which the bound was specified, an omitted array bound
+ // is taken to be the same as in that earlier declaration.
+ return NewVD->isPreviousDeclInSameBlockScope() ||
+ (!OldVD->getLexicalDeclContext()->isFunctionOrMethod() &&
+ !NewVD->getLexicalDeclContext()->isFunctionOrMethod());
+ } else {
+ // If the old declaration was function-local, don't merge with its
+ // type unless we're in the same function.
+ return !OldVD->getLexicalDeclContext()->isFunctionOrMethod() ||
+ OldVD->getLexicalDeclContext() == NewVD->getLexicalDeclContext();
+ }
+}
+
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
/// situation, merging decls or emitting diagnostics as appropriate.
@@ -2874,16 +2998,21 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
/// definitions here, since the initializer hasn't been attached.
///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
- bool PreviousWasHidden) {
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// If the new decl is already invalid, don't do any other checking.
if (New->isInvalidDecl())
return;
- // Verify the old decl was also a variable.
+ // Verify the old decl was also a variable or variable template.
VarDecl *Old = 0;
- if (!Previous.isSingleResult() ||
- !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
+ if (Previous.isSingleResult() &&
+ (Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
+ if (New->getDescribedVarTemplate())
+ Old = Old->getDescribedVarTemplate() ? Old : 0;
+ else
+ Old = Old->getDescribedVarTemplate() ? 0 : Old;
+ }
+ if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
Diag(Previous.getRepresentativeDecl()->getLocation(),
@@ -2918,14 +3047,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
}
// Merge the types.
- MergeVarDeclTypes(New, Old, PreviousWasHidden);
+ MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous));
+
if (New->isInvalidDecl())
return;
// [dcl.stc]p8: Check if we have a non-static decl followed by a static.
if (New->getStorageClass() == SC_Static &&
!New->isStaticDataMember() &&
- isExternalLinkage(Old->getLinkage())) {
+ Old->hasExternalFormalLinkage()) {
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2999,8 +3129,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
if (getLangOpts().CPlusPlus &&
New->isThisDeclarationADefinition() == VarDecl::Definition &&
(Def = Old->getDefinition())) {
- Diag(New->getLocation(), diag::err_redefinition)
- << New->getDeclName();
+ Diag(New->getLocation(), diag::err_redefinition) << New;
Diag(Def->getLocation(), diag::note_previous_definition);
New->setInvalidDecl();
return;
@@ -3014,14 +3143,19 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
}
// Merge "used" flag.
- if (Old->isUsed(false))
- New->setUsed();
+ if (Old->getMostRecentDecl()->isUsed(false))
+ New->setIsUsed();
// Keep a chain of previous declarations.
- New->setPreviousDeclaration(Old);
+ New->setPreviousDecl(Old);
// Inherit access appropriately.
New->setAccess(Old->getAccess());
+
+ if (VarTemplateDecl *VTD = New->getDescribedVarTemplate()) {
+ if (New->isStaticDataMember() && New->isOutOfLine())
+ VTD->setAccess(New->getAccess());
+ }
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -3031,6 +3165,30 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
}
+static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
+ if (!S.Context.getLangOpts().CPlusPlus)
+ return;
+
+ if (isa<CXXRecordDecl>(Tag->getParent())) {
+ // If this tag is the direct child of a class, number it if
+ // it is anonymous.
+ if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl())
+ return;
+ MangleNumberingContext &MCtx =
+ S.Context.getManglingNumberContext(Tag->getParent());
+ S.Context.setManglingNumber(Tag, MCtx.getManglingNumber(Tag));
+ return;
+ }
+
+ // If this tag isn't a direct child of a class, number it if it is local.
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ S.getCurrentMangleNumberContext(Tag->getDeclContext(),
+ ManglingContextDecl)) {
+ S.Context.setManglingNumber(Tag, MCtx->getManglingNumber(Tag));
+ }
+}
+
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
@@ -3060,7 +3218,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
if (Tag) {
- getASTContext().addUnnamedTag(Tag);
+ HandleTagNumbering(*this, Tag);
Tag->setFreeStanding();
if (Tag->isInvalidDecl())
return Tag;
@@ -3301,11 +3459,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
/// This routine is recursive, injecting the names of nested anonymous
/// structs/unions into the owning context and scope as well.
static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
- DeclContext *Owner,
- RecordDecl *AnonRecord,
- AccessSpecifier AS,
- SmallVector<NamedDecl*, 2> &Chaining,
- bool MSAnonStruct) {
+ DeclContext *Owner,
+ RecordDecl *AnonRecord,
+ AccessSpecifier AS,
+ SmallVectorImpl<NamedDecl *> &Chaining,
+ bool MSAnonStruct) {
unsigned diagKind
= AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
@@ -3961,7 +4119,7 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
DeclarationName Name,
SourceLocation Loc) {
DeclContext *Cur = CurContext;
- while (isa<LinkageSpecDecl>(Cur))
+ while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur))
Cur = Cur->getParent();
// C++ [dcl.meaning]p1:
@@ -3999,6 +4157,9 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
else if (isa<FunctionDecl>(Cur))
Diag(Loc, diag::err_invalid_declarator_in_function)
<< Name << SS.getRange();
+ else if (isa<BlockDecl>(Cur))
+ Diag(Loc, diag::err_invalid_declarator_in_block)
+ << Name << SS.getRange();
else
Diag(Loc, diag::err_invalid_declarator_scope)
<< Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange();
@@ -4071,7 +4232,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
bool EnteringContext = !D.getDeclSpec().isFriendSpecified();
DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext);
- if (!DC) {
+ if (!DC || isa<EnumDecl>(DC)) {
// If we could not compute the declaration context, it's because the
// declaration context is dependent but does not refer to a class,
// class template, or class template partial specialization. Complain
@@ -4132,26 +4293,31 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// See if this is a redefinition of a variable in the same scope.
if (!D.getCXXScopeSpec().isSet()) {
bool IsLinkageLookup = false;
+ bool CreateBuiltins = false;
// If the declaration we're planning to build will be a function
// or object with linkage, then look for another declaration with
// linkage (C99 6.2.2p4-5 and C++ [basic.link]p6).
+ //
+ // If the declaration we're planning to build will be declared with
+ // external linkage in the translation unit, create any builtin with
+ // the same name.
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
/* Do nothing*/;
- else if (R->isFunctionType()) {
- if (CurContext->isFunctionOrMethod() ||
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
- IsLinkageLookup = true;
- } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern)
- IsLinkageLookup = true;
- else if (CurContext->getRedeclContext()->isTranslationUnit() &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
+ else if (CurContext->isFunctionOrMethod() &&
+ (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern ||
+ R->isFunctionType())) {
IsLinkageLookup = true;
+ CreateBuiltins =
+ CurContext->getEnclosingNamespaceContext()->isTranslationUnit();
+ } else if (CurContext->getRedeclContext()->isTranslationUnit() &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
+ CreateBuiltins = true;
if (IsLinkageLookup)
Previous.clear(LookupRedeclarationWithLinkage);
- LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup);
+ LookupName(Previous, S, CreateBuiltins);
} else { // Something like "int foo::x;"
LookupQualifiedName(Previous, DC);
@@ -4223,8 +4389,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
TemplateParamLists,
AddToScope);
} else {
- New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
- TemplateParamLists);
+ New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists,
+ AddToScope);
}
if (New == 0)
@@ -4233,8 +4399,15 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
if (New->getDeclName() && AddToScope &&
- !(D.isRedeclaration() && New->isInvalidDecl()))
- PushOnScopeChains(New, S);
+ !(D.isRedeclaration() && New->isInvalidDecl())) {
+ // Only make a locally-scoped extern declaration visible if it is the first
+ // declaration of this entity. Qualified lookup for such an entity should
+ // only find this declaration if there is no visible declaration of it.
+ bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl();
+ PushOnScopeChains(New, S, AddToContext);
+ if (!AddToContext)
+ CurContext->addHiddenDecl(New);
+ }
return New;
}
@@ -4356,21 +4529,26 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
}
/// \brief Register the given locally-scoped extern "C" declaration so
-/// that it can be found later for redeclarations
+/// that it can be found later for redeclarations. We include any extern "C"
+/// declaration that is not visible in the translation unit here, not just
+/// function-scope declarations.
void
-Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
- const LookupResult &Previous,
- Scope *S) {
- assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
- "Decl is not a locally-scoped decl!");
+Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) {
+ if (!getLangOpts().CPlusPlus &&
+ ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit())
+ // Don't need to track declarations in the TU in C.
+ return;
+
// Note that we have a locally-scoped external with this name.
+ // FIXME: There can be multiple such declarations if they are functions marked
+ // __attribute__((overloadable)) declared in function scope in C.
LocallyScopedExternCDecls[ND->getDeclName()] = ND;
}
-llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
-Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
+NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
if (ExternalSource) {
// Load locally-scoped external decls from the external source.
+ // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls?
SmallVector<NamedDecl *, 4> Decls;
ExternalSource->ReadLocallyScopedExternCDecls(Decls);
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
@@ -4380,8 +4558,9 @@ Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
}
}
-
- return LocallyScopedExternCDecls.find(Name);
+
+ NamedDecl *D = LocallyScopedExternCDecls.lookup(Name);
+ return D ? D->getMostRecentDecl() : 0;
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
@@ -4627,17 +4806,26 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// 'weak' only applies to declarations with external linkage.
if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) {
- if (ND.getLinkage() != ExternalLinkage) {
+ if (!ND.isExternallyVisible()) {
S.Diag(Attr->getLocation(), diag::err_attribute_weak_static);
ND.dropAttr<WeakAttr>();
}
}
if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) {
- if (ND.hasExternalLinkage()) {
+ if (ND.isExternallyVisible()) {
S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
ND.dropAttr<WeakRefAttr>();
}
}
+
+ // 'selectany' only applies to externally visible varable declarations.
+ // It does not apply to functions.
+ if (SelectAnyAttr *Attr = ND.getAttr<SelectAnyAttr>()) {
+ if (isa<FunctionDecl>(ND) || !ND.isExternallyVisible()) {
+ S.Diag(Attr->getLocation(), diag::err_attribute_selectany_non_extern_data);
+ ND.dropAttr<SelectAnyAttr>();
+ }
+ }
}
/// Given that we are within the definition of the given function,
@@ -4672,6 +4860,32 @@ static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) {
return isC99Inline;
}
+/// Determine whether a variable is extern "C" prior to attaching
+/// an initializer. We can't just call isExternC() here, because that
+/// will also compute and cache whether the declaration is externally
+/// visible, which might change when we attach the initializer.
+///
+/// This can only be used if the declaration is known to not be a
+/// redeclaration of an internal linkage declaration.
+///
+/// For instance:
+///
+/// auto x = []{};
+///
+/// Attaching the initializer here makes this declaration not externally
+/// visible, because its type has internal linkage.
+///
+/// FIXME: This is a hack.
+template<typename T>
+static bool isIncompleteDeclExternC(Sema &S, const T *D) {
+ if (S.getLangOpts().CPlusPlus) {
+ // In C++, the overloadable attribute negates the effects of extern "C".
+ if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>())
+ return false;
+ }
+ return D->isExternC();
+}
+
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
if (DC->isFunctionOrMethod())
@@ -4692,10 +4906,35 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) {
llvm_unreachable("Unexpected context");
}
-NamedDecl*
+/// Adjust the \c DeclContext for a function or variable that might be a
+/// function-local external declaration.
+bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) {
+ if (!DC->isFunctionOrMethod())
+ return false;
+
+ // If this is a local extern function or variable declared within a function
+ // template, don't add it into the enclosing namespace scope until it is
+ // instantiated; it might have a dependent type right now.
+ if (DC->isDependentContext())
+ return true;
+
+ // C++11 [basic.link]p7:
+ // When a block scope declaration of an entity with linkage is not found to
+ // refer to some other declaration, then that entity is a member of the
+ // innermost enclosing namespace.
+ //
+ // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a
+ // semantically-enclosing namespace, not a lexically-enclosing one.
+ while (!DC->isFileContext() && !isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+ return true;
+}
+
+NamedDecl *
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists) {
+ MultiTemplateParamsArg TemplateParamLists,
+ bool &AddToScope) {
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
@@ -4703,6 +4942,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
VarDecl::StorageClass SC =
StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = SC == SC_Extern &&
+ adjustContextForLocalExternDecl(DC);
+
if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) {
// OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
// half array type (unless the cl_khr_fp16 extension is enabled).
@@ -4720,15 +4963,16 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SC = SC_None;
}
- // C++11 [dcl.stc]p4:
- // When thread_local is applied to a variable of block scope the
- // storage-class-specifier static is implied if it does not appear
- // explicitly.
- // Core issue: 'static' is not implied if the variable is declared 'extern'.
- if (SCSpec == DeclSpec::SCS_unspecified &&
- D.getDeclSpec().getThreadStorageClassSpec() ==
- DeclSpec::TSCS_thread_local && DC->isFunctionOrMethod())
- SC = SC_Static;
+ if (getLangOpts().CPlusPlus11 && SCSpec == DeclSpec::SCS_register &&
+ !D.getAsmLabel() && !getSourceManager().isInSystemMacro(
+ D.getDeclSpec().getStorageClassSpecLoc())) {
+ // In C++11, the 'register' storage class specifier is deprecated.
+ // Suppress the warning in system macros, it's used in macros in some
+ // popular C system headers, such as in glibc's htonl() macro.
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::warn_deprecated_register)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ }
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -4743,7 +4987,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C99 6.9p2: The storage-class specifiers auto and register shall not
// appear in the declaration specifiers in an external declaration.
if (SC == SC_Auto || SC == SC_Register) {
-
// If this is a register variable with an asm label specified, then this
// is a GNU extension.
if (SC == SC_Register && D.getAsmLabel())
@@ -4753,7 +4996,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setInvalidType();
}
}
-
+
if (getLangOpts().OpenCL) {
// Set up the special work-group-local storage class for variables in the
// OpenCL __local address space.
@@ -4786,8 +5029,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- bool isExplicitSpecialization = false;
- VarDecl *NewVD;
+ bool IsExplicitSpecialization = false;
+ bool IsVariableTemplateSpecialization = false;
+ bool IsPartialSpecialization = false;
+ bool IsVariableTemplate = false;
+ VarTemplateDecl *PrevVarTemplate = 0;
+ VarDecl *NewVD = 0;
+ VarTemplateDecl *NewTemplate = 0;
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
@@ -4796,14 +5044,37 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.isInvalidType())
NewVD->setInvalidDecl();
} else {
+ bool Invalid = false;
+
if (DC->isRecord() && !CurContext->isRecord()) {
// This is an out-of-line definition of a static data member.
- if (SC == SC_Static) {
+ switch (SC) {
+ case SC_None:
+ break;
+ case SC_Static:
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ break;
+ case SC_Auto:
+ case SC_Register:
+ case SC_Extern:
+ // [dcl.stc] p2: The auto or register specifiers shall be applied only
+ // to names of variables declared in a block or to function parameters.
+ // [dcl.stc] p6: The extern specifier cannot be used in the declaration
+ // of class members
+
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_storage_class_for_static_member)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ break;
+ case SC_PrivateExtern:
+ llvm_unreachable("C storage class in c++!");
+ case SC_OpenCLWorkGroupLocal:
+ llvm_unreachable("OpenCL storage class in c++!");
}
- }
+ }
+
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
if (RD->isLocalClass())
@@ -4826,28 +5097,21 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ NamedDecl *PrevDecl = 0;
+ if (Previous.begin() != Previous.end())
+ PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ PrevVarTemplate = dyn_cast_or_null<VarTemplateDecl>(PrevDecl);
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- isExplicitSpecialization = false;
- bool Invalid = false;
- if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getLocStart(),
- D.getIdentifierLoc(),
- D.getCXXScopeSpec(),
- TemplateParamLists.data(),
- TemplateParamLists.size(),
- /*never a friend*/ false,
- isExplicitSpecialization,
- Invalid)) {
- if (TemplateParams->size() > 0) {
- // There is no such thing as a variable template.
- Diag(D.getIdentifierLoc(), diag::err_template_variable)
- << II
- << SourceRange(TemplateParams->getTemplateLoc(),
- TemplateParams->getRAngleLoc());
- return 0;
- } else {
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(), TemplateParamLists,
+ /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+ if (TemplateParams) {
+ if (!TemplateParams->size() &&
+ D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
// There is an extraneous 'template<>' for this variable. Complain
// about it, but allow the declaration of the variable.
Diag(TemplateParams->getTemplateLoc(),
@@ -4855,24 +5119,148 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
+ } else {
+ // Only C++1y supports variable templates (N3651).
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_variable_template
+ : diag::ext_variable_template);
+
+ if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
+ // This is an explicit specialization or a partial specialization.
+ // Check that we can declare a specialization here
+
+ IsVariableTemplateSpecialization = true;
+ IsPartialSpecialization = TemplateParams->size() > 0;
+
+ } else { // if (TemplateParams->size() > 0)
+ // This is a template declaration.
+ IsVariableTemplate = true;
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
+ // If there is a previous declaration with the same name, check
+ // whether this is a valid redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S))
+ PrevDecl = PrevVarTemplate = 0;
+
+ if (PrevVarTemplate) {
+ // Ensure that the template parameter lists are compatible.
+ if (!TemplateParameterListsAreEqual(
+ TemplateParams, PrevVarTemplate->getTemplateParameters(),
+ /*Complain=*/true, TPL_TemplateMatch))
+ return 0;
+ } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ } else if (PrevDecl) {
+ // C++ [temp]p5:
+ // ... a template name declared in namespace scope or in class
+ // scope shall be unique in that scope.
+ Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind)
+ << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return 0;
+ }
+
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous variable
+ // template declaration.
+ if (CheckTemplateParameterList(
+ TemplateParams,
+ PrevVarTemplate ? PrevVarTemplate->getTemplateParameters()
+ : 0,
+ (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
+ DC->isDependentContext())
+ ? TPC_ClassTemplateMember
+ : TPC_VarTemplate))
+ Invalid = true;
+
+ if (D.getCXXScopeSpec().isSet()) {
+ // If the name of the template was qualified, we must be defining
+ // the template out-of-line.
+ if (!D.getCXXScopeSpec().isInvalid() && !Invalid &&
+ !PrevVarTemplate) {
+ Diag(D.getIdentifierLoc(), diag::err_member_decl_does_not_match)
+ << Name << DC << /*IsDefinition*/true
+ << D.getCXXScopeSpec().getRange();
+ Invalid = true;
+ }
+ }
+ }
}
+ } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+
+ // We have encountered something that the user meant to be a
+ // specialization (because it has explicitly-specified template
+ // arguments) but that was not introduced with a "template<>" (or had
+ // too few of them).
+ // FIXME: Differentiate between attempts for explicit instantiations
+ // (starting with "template") and the rest.
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
+ << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
+ << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(),
+ "template<> ");
+ IsVariableTemplateSpecialization = true;
}
- NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
- D.getIdentifierLoc(), II,
- R, TInfo, SC);
+ if (IsVariableTemplateSpecialization) {
+ if (!PrevVarTemplate) {
+ Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template)
+ << IsPartialSpecialization;
+ return 0;
+ }
+
+ SourceLocation TemplateKWLoc =
+ TemplateParamLists.size() > 0
+ ? TemplateParamLists[0]->getTemplateLoc()
+ : SourceLocation();
+ DeclResult Res = ActOnVarTemplateSpecialization(
+ S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC,
+ IsPartialSpecialization);
+ if (Res.isInvalid())
+ return 0;
+ NewVD = cast<VarDecl>(Res.get());
+ AddToScope = false;
+ } else
+ NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
+ D.getIdentifierLoc(), II, R, TInfo, SC);
+
+ // If this is supposed to be a variable template, create it as such.
+ if (IsVariableTemplate) {
+ NewTemplate =
+ VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
+ TemplateParams, NewVD, PrevVarTemplate);
+ NewVD->setDescribedVarTemplate(NewTemplate);
+ }
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
ParsingInitForAutoVars.insert(NewVD);
- if (D.isInvalidType() || Invalid)
+ if (D.isInvalidType() || Invalid) {
NewVD->setInvalidDecl();
+ if (NewTemplate)
+ NewTemplate->setInvalidDecl();
+ }
SetNestedNameSpecifier(NewVD, D);
- if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) {
+ // FIXME: Do we need D.getCXXScopeSpec().isSet()?
+ if (TemplateParams && TemplateParamLists.size() > 1 &&
+ (!IsVariableTemplateSpecialization || D.getCXXScopeSpec().isSet())) {
+ NewVD->setTemplateParameterListsInfo(
+ Context, TemplateParamLists.size() - 1, TemplateParamLists.data());
+ } else if (IsVariableTemplateSpecialization ||
+ (!TemplateParams && TemplateParamLists.size() > 0 &&
+ (D.getCXXScopeSpec().isSet()))) {
NewVD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
TemplateParamLists.data());
@@ -4885,13 +5273,29 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Set the lexical context. If the declarator has a C++ scope specifier, the
// lexical context will be different from the semantic context.
NewVD->setLexicalDeclContext(CurContext);
+ if (NewTemplate)
+ NewTemplate->setLexicalDeclContext(CurContext);
+
+ if (IsLocalExternDecl)
+ NewVD->setLocalExternDecl();
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
- if (NewVD->hasLocalStorage())
- Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
- diag::err_thread_non_global)
- << DeclSpec::getSpecifierName(TSCS);
- else if (!Context.getTargetInfo().isTLSSupported())
+ if (NewVD->hasLocalStorage()) {
+ // C++11 [dcl.stc]p4:
+ // When thread_local is applied to a variable of block scope the
+ // storage-class-specifier static is implied if it does not appear
+ // explicitly.
+ // Core issue: 'static' is not implied if the variable is declared
+ // 'extern'.
+ if (SCSpec == DeclSpec::SCS_unspecified &&
+ TSCS == DeclSpec::TSCS_thread_local &&
+ DC->isFunctionOrMethod())
+ NewVD->setTSCSpec(TSCS);
+ else
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_thread_non_global)
+ << DeclSpec::getSpecifierName(TSCS);
+ } else if (!Context.getTargetInfo().isTLSSupported())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
else
@@ -4918,7 +5322,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (D.getDeclSpec().isModulePrivateSpecified()) {
- if (isExplicitSpecialization)
+ if (IsVariableTemplateSpecialization)
+ Diag(NewVD->getLocation(), diag::err_module_private_specialization)
+ << (IsPartialSpecialization ? 1 : 0)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getModulePrivateSpecLoc());
+ else if (IsExplicitSpecialization)
Diag(NewVD->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
@@ -4927,8 +5336,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< 0 << NewVD->getDeclName()
<< SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
<< FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
- else
+ else {
NewVD->setModulePrivate();
+ if (NewTemplate)
+ NewTemplate->setModulePrivate();
+ }
}
// Handle attributes prior to checking for duplicates in MergeVarDecl
@@ -4993,9 +5405,18 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD),
- isExplicitSpecialization);
-
+ FilterLookupForScope(
+ Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
+ IsExplicitSpecialization || IsVariableTemplateSpecialization);
+
+ // Check whether the previous declaration is in the same block scope. This
+ // affects whether we merge types with it, per C++11 [dcl.array]p3.
+ if (getLangOpts().CPlusPlus &&
+ NewVD->isLocalVarDecl() && NewVD->hasExternalStorage())
+ NewVD->setPreviousDeclInSameBlockScope(
+ Previous.isSingleResult() && !Previous.isShadowed() &&
+ isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false));
+
if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
@@ -5019,10 +5440,18 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
- D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ if (!IsVariableTemplateSpecialization) {
+ if (PrevVarTemplate) {
+ LookupResult PrevDecl(*this, GetNameForDeclarator(D),
+ LookupOrdinaryName, ForRedeclaration);
+ PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
+ } else
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ }
// This is an explicit specialization of a static data member. Check it.
- if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ if (IsExplicitSpecialization && !NewVD->isInvalidDecl() &&
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
}
@@ -5030,11 +5459,30 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
ProcessPragmaWeak(S, NewVD);
checkAttributesAfterMerging(*this, *NewVD);
- // If this is a locally-scoped extern C variable, update the map of
- // such variables.
- if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
- !NewVD->isInvalidDecl())
- RegisterLocallyScopedExternCDecl(NewVD, Previous, S);
+ // If this is the first declaration of an extern C variable, update
+ // the map of such variables.
+ if (NewVD->isFirstDecl() && !NewVD->isInvalidDecl() &&
+ isIncompleteDeclExternC(*this, NewVD))
+ RegisterLocallyScopedExternCDecl(NewVD, S);
+
+ if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ getCurrentMangleNumberContext(NewVD->getDeclContext(),
+ ManglingContextDecl)) {
+ Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD));
+ }
+ }
+
+ // If we are providing an explicit specialization of a static variable
+ // template, make a note of that.
+ if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate())
+ PrevVarTemplate->setMemberSpecialization();
+
+ if (NewTemplate) {
+ ActOnDocumentableDecl(NewTemplate);
+ return NewTemplate;
+ }
return NewVD;
}
@@ -5134,30 +5582,121 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
CheckShadow(S, D, R);
}
+/// Check for conflict between this global or extern "C" declaration and
+/// previous global or extern "C" declarations. This is only used in C++.
template<typename T>
-static bool mayConflictWithNonVisibleExternC(const T *ND) {
- const DeclContext *DC = ND->getDeclContext();
- if (DC->getRedeclContext()->isTranslationUnit())
- return true;
+static bool checkGlobalOrExternCConflict(
+ Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) {
+ assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\"");
+ NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName());
+
+ if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) {
+ // The common case: this global doesn't conflict with any extern "C"
+ // declaration.
+ return false;
+ }
- // We know that is the first decl we see, other than function local
- // extern C ones. If this is C++ and the decl is not in a extern C context
- // it cannot have C language linkage. Avoid calling isExternC in that case.
- // We need to this because of code like
- //
- // namespace { struct bar {}; }
- // auto foo = bar();
- //
- // This code runs before the init of foo is set, and therefore before
- // the type of foo is known. Not knowing the type we cannot know its linkage
- // unless it is in an extern C block.
- if (!ND->isInExternCContext()) {
- const ASTContext &Context = ND->getASTContext();
- if (Context.getLangOpts().CPlusPlus)
+ if (Prev) {
+ if (!IsGlobal || isIncompleteDeclExternC(S, ND)) {
+ // Both the old and new declarations have C language linkage. This is a
+ // redeclaration.
+ Previous.clear();
+ Previous.addDecl(Prev);
+ return true;
+ }
+
+ // This is a global, non-extern "C" declaration, and there is a previous
+ // non-global extern "C" declaration. Diagnose if this is a variable
+ // declaration.
+ if (!isa<VarDecl>(ND))
return false;
+ } else {
+ // The declaration is extern "C". Check for any declaration in the
+ // translation unit which might conflict.
+ if (IsGlobal) {
+ // We have already performed the lookup into the translation unit.
+ IsGlobal = false;
+ for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+ I != E; ++I) {
+ if (isa<VarDecl>(*I)) {
+ Prev = *I;
+ break;
+ }
+ }
+ } else {
+ DeclContext::lookup_result R =
+ S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName());
+ for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end();
+ I != E; ++I) {
+ if (isa<VarDecl>(*I)) {
+ Prev = *I;
+ break;
+ }
+ // FIXME: If we have any other entity with this name in global scope,
+ // the declaration is ill-formed, but that is a defect: it breaks the
+ // 'stat' hack, for instance. Only variables can have mangled name
+ // clashes with extern "C" declarations, so only they deserve a
+ // diagnostic.
+ }
+ }
+
+ if (!Prev)
+ return false;
+ }
+
+ // Use the first declaration's location to ensure we point at something which
+ // is lexically inside an extern "C" linkage-spec.
+ assert(Prev && "should have found a previous declaration to diagnose");
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev))
+ Prev = FD->getFirstDecl();
+ else
+ Prev = cast<VarDecl>(Prev)->getFirstDecl();
+
+ S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict)
+ << IsGlobal << ND;
+ S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict)
+ << IsGlobal;
+ return false;
+}
+
+/// Apply special rules for handling extern "C" declarations. Returns \c true
+/// if we have found that this is a redeclaration of some prior entity.
+///
+/// Per C++ [dcl.link]p6:
+/// Two declarations [for a function or variable] with C language linkage
+/// with the same name that appear in different scopes refer to the same
+/// [entity]. An entity with C language linkage shall not be declared with
+/// the same name as an entity in global scope.
+template<typename T>
+static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND,
+ LookupResult &Previous) {
+ if (!S.getLangOpts().CPlusPlus) {
+ // In C, when declaring a global variable, look for a corresponding 'extern'
+ // variable declared in function scope. We don't need this in C++, because
+ // we find local extern decls in the surrounding file-scope DeclContext.
+ if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+ if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
+ Previous.clear();
+ Previous.addDecl(Prev);
+ return true;
+ }
+ }
+ return false;
}
- return ND->isExternC();
+ // A declaration in the translation unit can conflict with an extern "C"
+ // declaration.
+ if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit())
+ return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous);
+
+ // An extern "C" declaration can conflict with a declaration in the
+ // translation unit or can be a redeclaration of an extern "C" declaration
+ // in another scope.
+ if (isIncompleteDeclExternC(S,ND))
+ return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous);
+
+ // Neither global nor extern "C": nothing to do.
+ return false;
}
void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
@@ -5239,7 +5778,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope)
<< SizeRange;
- else if (NewVD->getStorageClass() == SC_Static)
+ else if (NewVD->isStaticLocal())
Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage)
<< SizeRange;
else
@@ -5263,11 +5802,15 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setTypeSourceInfo(FixedTInfo);
}
- if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) {
- Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
- << T;
- NewVD->setInvalidDecl();
- return;
+ if (T->isVoidType()) {
+ // C++98 [dcl.stc]p5: The extern specifier can be applied only to the names
+ // of objects and functions.
+ if (NewVD->isThisDeclarationADefinition() || getLangOpts().CPlusPlus) {
+ Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
+ << T;
+ NewVD->setInvalidDecl();
+ return;
+ }
}
if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) {
@@ -5303,8 +5846,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
/// Sets NewVD->isInvalidDecl() if an error was encountered.
///
/// Returns true if the variable declaration is a redeclaration.
-bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
- LookupResult &Previous) {
+bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) {
CheckVariableDeclarationType(NewVD);
// If the decl is already known invalid, don't check it.
@@ -5313,44 +5855,15 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
// If we did not find anything by this name, look for a non-visible
// extern "C" declaration with the same name.
- //
- // Clang has a lot of problems with extern local declarations.
- // The actual standards text here is:
- //
- // C++11 [basic.link]p6:
- // The name of a function declared in block scope and the name
- // of a variable declared by a block scope extern declaration
- // have linkage. If there is a visible declaration of an entity
- // with linkage having the same name and type, ignoring entities
- // declared outside the innermost enclosing namespace scope, the
- // block scope declaration declares that same entity and
- // receives the linkage of the previous declaration.
- //
- // C11 6.2.7p4:
- // For an identifier with internal or external linkage declared
- // in a scope in which a prior declaration of that identifier is
- // visible, if the prior declaration specifies internal or
- // external linkage, the type of the identifier at the later
- // declaration becomes the composite type.
- //
- // The most important point here is that we're not allowed to
- // update our understanding of the type according to declarations
- // not in scope.
- bool PreviousWasHidden = false;
- if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternCDecl(NewVD->getDeclName());
- if (Pos != LocallyScopedExternCDecls.end()) {
- Previous.addDecl(Pos->second);
- PreviousWasHidden = true;
- }
- }
+ if (Previous.empty() &&
+ checkForConflictWithNonVisibleExternC(*this, NewVD, Previous))
+ Previous.setShadowed();
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
if (!Previous.empty()) {
- MergeVarDecl(NewVD, Previous, PreviousWasHidden);
+ MergeVarDecl(NewVD, Previous);
return true;
}
return false;
@@ -5524,24 +6037,27 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
///
/// Returns a NamedDecl iff typo correction was performed and substituting in
/// the new declaration name does not cause new errors.
-static NamedDecl* DiagnoseInvalidRedeclaration(
+static NamedDecl *DiagnoseInvalidRedeclaration(
Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD,
- ActOnFDArgs &ExtraArgs) {
- NamedDecl *Result = NULL;
+ ActOnFDArgs &ExtraArgs, bool IsLocalFriend, Scope *S) {
DeclarationName Name = NewFD->getDeclName();
DeclContext *NewDC = NewFD->getDeclContext();
- LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
SmallVector<unsigned, 1> MismatchedParams;
SmallVector<std::pair<FunctionDecl *, unsigned>, 1> NearMatches;
TypoCorrection Correction;
- bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus &&
- ExtraArgs.D.getDeclSpec().isFriendSpecified());
- unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend
- : diag::err_member_def_does_not_match;
+ bool IsDefinition = ExtraArgs.D.isFunctionDefinition();
+ unsigned DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend
+ : diag::err_member_decl_does_not_match;
+ LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
+ IsLocalFriend ? Sema::LookupLocalFriendName
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
NewFD->setInvalidDecl();
- SemaRef.LookupQualifiedName(Prev, NewDC);
+ if (IsLocalFriend)
+ SemaRef.LookupName(Prev, S);
+ else
+ SemaRef.LookupQualifiedName(Prev, NewDC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
@@ -5561,12 +6077,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
}
// If the qualified name lookup yielded nothing, try typo correction
- } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(),
- Prev.getLookupKind(), 0, 0,
- Validator, NewDC))) {
- // Trap errors.
- Sema::SFINAETrap Trap(SemaRef);
-
+ } else if ((Correction = SemaRef.CorrectTypo(
+ Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
+ &ExtraArgs.D.getCXXScopeSpec(), Validator,
+ IsLocalFriend ? 0 : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
@@ -5582,85 +6096,85 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
}
bool wasRedeclaration = ExtraArgs.D.isRedeclaration();
- // TODO: Refactor ActOnFunctionDeclarator so that we can call only the
- // pieces need to verify the typo-corrected C++ declaraction and hopefully
- // eliminate the need for the parameter pack ExtraArgs.
- Result = SemaRef.ActOnFunctionDeclarator(
- ExtraArgs.S, ExtraArgs.D,
- Correction.getCorrectionDecl()->getDeclContext(),
- NewFD->getTypeSourceInfo(), Previous, ExtraArgs.TemplateParamLists,
- ExtraArgs.AddToScope);
- if (Trap.hasErrorOccurred()) {
- // Pretend the typo correction never occurred
- ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(),
- ExtraArgs.D.getIdentifierLoc());
- ExtraArgs.D.setRedeclaration(wasRedeclaration);
- Previous.clear();
- Previous.setLookupName(Name);
- Result = NULL;
- } else {
- for (LookupResult::iterator Func = Previous.begin(),
- FuncEnd = Previous.end();
- Func != FuncEnd; ++Func) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
- NearMatches.push_back(std::make_pair(FD, 0));
- }
+
+ NamedDecl *Result;
+ // Retry building the function declaration with the new previous
+ // declarations, and with errors suppressed.
+ {
+ // Trap errors.
+ Sema::SFINAETrap Trap(SemaRef);
+
+ // TODO: Refactor ActOnFunctionDeclarator so that we can call only the
+ // pieces need to verify the typo-corrected C++ declaration and hopefully
+ // eliminate the need for the parameter pack ExtraArgs.
+ Result = SemaRef.ActOnFunctionDeclarator(
+ ExtraArgs.S, ExtraArgs.D,
+ Correction.getCorrectionDecl()->getDeclContext(),
+ NewFD->getTypeSourceInfo(), Previous, ExtraArgs.TemplateParamLists,
+ ExtraArgs.AddToScope);
+
+ if (Trap.hasErrorOccurred())
+ Result = 0;
+ }
+
+ if (Result) {
+ // Determine which correction we picked.
+ Decl *Canonical = Result->getCanonicalDecl();
+ for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+ I != E; ++I)
+ if ((*I)->getCanonicalDecl() == Canonical)
+ Correction.setCorrectionDecl(*I);
+
+ SemaRef.diagnoseTypo(
+ Correction,
+ SemaRef.PDiag(IsLocalFriend
+ ? diag::err_no_matching_local_friend_suggest
+ : diag::err_member_decl_does_not_match_suggest)
+ << Name << NewDC << IsDefinition);
+ return Result;
}
- if (NearMatches.empty()) {
- // Ignore the correction if it didn't yield any close FunctionDecl matches
- Correction = TypoCorrection();
- } else {
- DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest
- : diag::err_member_def_does_not_match_suggest;
- }
- }
-
- if (Correction) {
- // FIXME: use Correction.getCorrectionRange() instead of computing the range
- // here. This requires passing in the CXXScopeSpec to CorrectTypo which in
- // turn causes the correction to fully qualify the name. If we fix
- // CorrectTypo to minimally qualify then this change should be good.
- SourceRange FixItLoc(NewFD->getLocation());
- CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec();
- if (Correction.getCorrectionSpecifier() && SS.isValid())
- FixItLoc.setBegin(SS.getBeginLoc());
- SemaRef.Diag(NewFD->getLocStart(), DiagMsg)
- << Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts())
- << FixItHint::CreateReplacement(
- FixItLoc, Correction.getAsString(SemaRef.getLangOpts()));
- } else {
- SemaRef.Diag(NewFD->getLocation(), DiagMsg)
- << Name << NewDC << NewFD->getLocation();
+
+ // Pretend the typo correction never occurred
+ ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(),
+ ExtraArgs.D.getIdentifierLoc());
+ ExtraArgs.D.setRedeclaration(wasRedeclaration);
+ Previous.clear();
+ Previous.setLookupName(Name);
}
+ SemaRef.Diag(NewFD->getLocation(), DiagMsg)
+ << Name << NewDC << IsDefinition << NewFD->getLocation();
+
bool NewFDisConst = false;
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
NewFDisConst = NewMD->isConst();
- for (SmallVector<std::pair<FunctionDecl *, unsigned>, 1>::iterator
+ for (SmallVectorImpl<std::pair<FunctionDecl *, unsigned> >::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
NearMatch != NearMatchEnd; ++NearMatch) {
FunctionDecl *FD = NearMatch->first;
- bool FDisConst = false;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- FDisConst = MD->isConst();
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ bool FDisConst = MD && MD->isConst();
+ bool IsMember = MD || !IsLocalFriend;
+ // FIXME: These notes are poorly worded for the local friend case.
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
SourceLocation Loc = FDParam->getTypeSpecStartLoc();
if (Loc.isInvalid()) Loc = FD->getLocation();
- SemaRef.Diag(Loc, diag::note_member_def_close_param_match)
- << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();
- } else if (Correction) {
- SemaRef.Diag(FD->getLocation(), diag::note_previous_decl)
- << Correction.getQuoted(SemaRef.getLangOpts());
+ SemaRef.Diag(Loc, IsMember ? diag::note_member_def_close_param_match
+ : diag::note_local_decl_close_param_match)
+ << Idx << FDParam->getType()
+ << NewFD->getParamDecl(Idx - 1)->getType();
} else if (FDisConst != NewFDisConst) {
SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match)
<< NewFDisConst << FD->getSourceRange().getEnd();
} else
- SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match);
+ SemaRef.Diag(FD->getLocation(),
+ IsMember ? diag::note_member_def_close_match
+ : diag::note_local_decl_close_match);
}
- return Result;
+ return 0;
}
static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef,
@@ -5778,6 +6292,15 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
}
+ // The Microsoft ABI requires that we perform the destructor body
+ // checks (i.e. operator delete() lookup) at every declaration, as
+ // any translation unit may need to emit a deleting destructor.
+ if (SemaRef.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ !Record->isDependentType() && Record->getDefinition() &&
+ !Record->isBeingDefined()) {
+ SemaRef.CheckDestructor(NewDD);
+ }
+
IsVirtualOkay = true;
return NewDD;
@@ -5856,6 +6379,173 @@ void Sema::checkVoidParamDecl(ParmVarDecl *Param) {
}
}
+enum OpenCLParamType {
+ ValidKernelParam,
+ PtrPtrKernelParam,
+ PtrKernelParam,
+ InvalidKernelParam,
+ RecordKernelParam
+};
+
+static OpenCLParamType getOpenCLKernelParameterType(QualType PT) {
+ if (PT->isPointerType()) {
+ QualType PointeeType = PT->getPointeeType();
+ return PointeeType->isPointerType() ? PtrPtrKernelParam : PtrKernelParam;
+ }
+
+ // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can
+ // be used as builtin types.
+
+ if (PT->isImageType())
+ return PtrKernelParam;
+
+ if (PT->isBooleanType())
+ return InvalidKernelParam;
+
+ if (PT->isEventT())
+ return InvalidKernelParam;
+
+ if (PT->isHalfType())
+ return InvalidKernelParam;
+
+ if (PT->isRecordType())
+ return RecordKernelParam;
+
+ return ValidKernelParam;
+}
+
+static void checkIsValidOpenCLKernelParameter(
+ Sema &S,
+ Declarator &D,
+ ParmVarDecl *Param,
+ llvm::SmallPtrSet<const Type *, 16> &ValidTypes) {
+ QualType PT = Param->getType();
+
+ // Cache the valid types we encounter to avoid rechecking structs that are
+ // used again
+ if (ValidTypes.count(PT.getTypePtr()))
+ return;
+
+ switch (getOpenCLKernelParameterType(PT)) {
+ case PtrPtrKernelParam:
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to a pointer type.
+ S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param);
+ D.setInvalidType();
+ return;
+
+ // OpenCL v1.2 s6.9.k:
+ // Arguments to kernel functions in a program cannot be declared with the
+ // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and
+ // uintptr_t or a struct and/or union that contain fields declared to be
+ // one of these built-in scalar types.
+
+ case InvalidKernelParam:
+ // OpenCL v1.2 s6.8 n:
+ // A kernel function argument cannot be declared
+ // of event_t type.
+ S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+ D.setInvalidType();
+ return;
+
+ case PtrKernelParam:
+ case ValidKernelParam:
+ ValidTypes.insert(PT.getTypePtr());
+ return;
+
+ case RecordKernelParam:
+ break;
+ }
+
+ // Track nested structs we will inspect
+ SmallVector<const Decl *, 4> VisitStack;
+
+ // Track where we are in the nested structs. Items will migrate from
+ // VisitStack to HistoryStack as we do the DFS for bad field.
+ SmallVector<const FieldDecl *, 4> HistoryStack;
+ HistoryStack.push_back((const FieldDecl *) 0);
+
+ const RecordDecl *PD = PT->castAs<RecordType>()->getDecl();
+ VisitStack.push_back(PD);
+
+ assert(VisitStack.back() && "First decl null?");
+
+ do {
+ const Decl *Next = VisitStack.pop_back_val();
+ if (!Next) {
+ assert(!HistoryStack.empty());
+ // Found a marker, we have gone up a level
+ if (const FieldDecl *Hist = HistoryStack.pop_back_val())
+ ValidTypes.insert(Hist->getType().getTypePtr());
+
+ continue;
+ }
+
+ // Adds everything except the original parameter declaration (which is not a
+ // field itself) to the history stack.
+ const RecordDecl *RD;
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(Next)) {
+ HistoryStack.push_back(Field);
+ RD = Field->getType()->castAs<RecordType>()->getDecl();
+ } else {
+ RD = cast<RecordDecl>(Next);
+ }
+
+ // Add a null marker so we know when we've gone back up a level
+ VisitStack.push_back((const Decl *) 0);
+
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+ QualType QT = FD->getType();
+
+ if (ValidTypes.count(QT.getTypePtr()))
+ continue;
+
+ OpenCLParamType ParamType = getOpenCLKernelParameterType(QT);
+ if (ParamType == ValidKernelParam)
+ continue;
+
+ if (ParamType == RecordKernelParam) {
+ VisitStack.push_back(FD);
+ continue;
+ }
+
+ // OpenCL v1.2 s6.9.p:
+ // Arguments to kernel functions that are declared to be a struct or union
+ // do not allow OpenCL objects to be passed as elements of the struct or
+ // union.
+ if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam) {
+ S.Diag(Param->getLocation(),
+ diag::err_record_with_pointers_kernel_param)
+ << PT->isUnionType()
+ << PT;
+ } else {
+ S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+ }
+
+ S.Diag(PD->getLocation(), diag::note_within_field_of_type)
+ << PD->getDeclName();
+
+ // We have an error, now let's go back up through history and show where
+ // the offending field came from
+ for (ArrayRef<const FieldDecl *>::const_iterator I = HistoryStack.begin() + 1,
+ E = HistoryStack.end(); I != E; ++I) {
+ const FieldDecl *OuterField = *I;
+ S.Diag(OuterField->getLocation(), diag::note_within_field_of_type)
+ << OuterField->getType();
+ }
+
+ S.Diag(FD->getLocation(), diag::note_illegal_field_declared_here)
+ << QT->isPointerType()
+ << QT;
+ D.setInvalidType();
+ return;
+ }
+ } while (!VisitStack.empty());
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -5875,25 +6565,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_invalid_thread)
<< DeclSpec::getSpecifierName(TSCS);
- // Do not allow returning a objc interface by-value.
- if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_object_cannot_be_passed_returned_by_value) << 0
- << R->getAs<FunctionType>()->getResultType()
- << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
-
- QualType T = R->getAs<FunctionType>()->getResultType();
- T = Context.getObjCObjectPointerType(T);
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- R = Context.getFunctionType(T,
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
- }
- else if (isa<FunctionNoProtoType>(R))
- R = Context.getFunctionNoProtoType(T);
- }
+ if (D.isFirstDeclarationOfMember())
+ adjustMemberFunctionCC(R, D.isStaticMember());
bool isFriend = false;
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -5906,6 +6579,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isVirtualOkay = false;
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC);
+
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
isVirtualOkay);
if (!NewFD) return 0;
@@ -5913,6 +6589,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
NewFD->setTopLevelDeclInObjCContainer();
+ // Set the lexical context. If this is a function-scope declaration, or has a
+ // C++ scope specifier, or is the object of a friend declaration, the lexical
+ // context will be different from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
+ if (IsLocalExternDecl)
+ NewFD->setLocalExternDecl();
+
if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -5940,25 +6624,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
isFunctionTemplateSpecialization = false;
if (D.isInvalidType())
NewFD->setInvalidDecl();
-
- // Set the lexical context. If the declarator has a C++
- // scope specifier, or is the object of a friend declaration, the
- // lexical context will be different from the semantic context.
- NewFD->setLexicalDeclContext(CurContext);
-
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
- if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getLocStart(),
- D.getIdentifierLoc(),
- D.getCXXScopeSpec(),
- TemplateParamLists.data(),
- TemplateParamLists.size(),
- isFriend,
- isExplicitSpecialization,
- Invalid)) {
+ if (TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(), TemplateParamLists, isFriend,
+ isExplicitSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -6072,6 +6746,24 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
+ if (getLangOpts().CPlusPlus1y &&
+ (NewFD->isDependentContext() ||
+ (isFriend && CurContext->isDependentContext())) &&
+ NewFD->getResultType()->isUndeducedType()) {
+ // If the function template is referenced directly (for instance, as a
+ // member of the current instantiation), pretend it has a dependent type.
+ // This is not really justified by the standard, but is the only sane
+ // thing to do.
+ // FIXME: For a friend function, we have not marked the function as being
+ // a friend yet, so 'isDependentContext' on the FD doesn't work.
+ const FunctionProtoType *FPT =
+ NewFD->getType()->castAs<FunctionProtoType>();
+ QualType Result = SubstAutoType(FPT->getResultType(),
+ Context.DependentTy);
+ NewFD->setType(Context.getFunctionType(Result, FPT->getArgTypes(),
+ FPT->getExtProtoInfo()));
+ }
+
// C++ [dcl.fct.spec]p3:
// The inline specifier shall not appear on a block scope function
// declaration.
@@ -6132,12 +6824,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (isFriend) {
- // For now, claim that the objects have no previous declaration.
if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(false);
+ FunctionTemplate->setObjectOfFriendDecl();
FunctionTemplate->setAccess(AS_public);
}
- NewFD->setObjectOfFriendDecl(false);
+ NewFD->setObjectOfFriendDecl();
NewFD->setAccess(AS_public);
}
@@ -6188,17 +6879,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExceptionSpecType = EST_BasicNoexcept;
NewFD->setType(Context.getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI));
+ FPT->getArgTypes(), EPI));
}
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD),
+ FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
-
+
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
@@ -6282,10 +6971,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
Context));
- // Process the non-inheritable attributes on this declaration.
- ProcessDeclAttributes(S, NewFD, D,
- /*NonInheritable=*/true, /*Inheritable=*/false);
-
// Functions returning a variably modified type violate C99 6.7.5.2p2
// because all functions have linkage.
if (!NewFD->isInvalidDecl() &&
@@ -6295,8 +6980,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Handle attributes.
- ProcessDeclAttributes(S, NewFD, D,
- /*NonInheritable=*/false, /*Inheritable=*/true);
+ ProcessDeclAttributes(S, NewFD, D);
QualType RetType = NewFD->getResultType();
const CXXRecordDecl *Ret = RetType->isRecordType() ?
@@ -6304,7 +6988,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl() && !NewFD->hasAttr<WarnUnusedResultAttr>() &&
Ret && Ret->hasAttr<WarnUnusedResultAttr>()) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- if (!(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
+ // Attach the attribute to the new decl. Don't apply the attribute if it
+ // returns an instance of the class (e.g. assignment operators).
+ if (!MD || MD->getParent() != Ret) {
NewFD->addAttr(new (Context) WarnUnusedResultAttr(SourceRange(),
Context));
}
@@ -6313,19 +6999,36 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
- if (!NewFD->isInvalidDecl()) {
- if (NewFD->isMain())
- CheckMain(NewFD, D.getDeclSpec());
+ if (!NewFD->isInvalidDecl() && NewFD->isMain())
+ CheckMain(NewFD, D.getDeclSpec());
+
+ if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
+ CheckMSVCRTEntryPoint(NewFD);
+
+ if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isExplicitSpecialization));
- }
- // Make graceful recovery from an invalid redeclaration.
else if (!Previous.empty())
- D.setRedeclaration(true);
+ // Make graceful recovery from an invalid redeclaration.
+ D.setRedeclaration(true);
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
} else {
+ // C++11 [replacement.functions]p3:
+ // The program's definitions shall not be specified as inline.
+ //
+ // N.B. We diagnose declarations instead of definitions per LWG issue 2340.
+ //
+ // Suppress the diagnostic if the function is __attribute__((used)), since
+ // that forces an external definition to be emitted.
+ if (D.getDeclSpec().isInlineSpecified() &&
+ NewFD->isReplaceableGlobalAllocationFunction() &&
+ !NewFD->hasAttr<UsedAttr>())
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
+ diag::ext_operator_new_delete_declared_inline)
+ << NewFD->getDeclName();
+
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
@@ -6353,6 +7056,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// specialization (because it has explicitly-specified template
// arguments) but that was not introduced with a "template<>" (or had
// too few of them).
+ // FIXME: Differentiate between attempts for explicit instantiations
+ // (starting with "template") and the rest.
Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
<< FixItHint::CreateInsertion(
@@ -6406,8 +7111,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++ [dcl.stc]p1:
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
- if (SC != SC_None) {
- if (SC != NewFD->getTemplateSpecializationInfo()->getTemplate()->getTemplatedDecl()->getStorageClass())
+ FunctionTemplateSpecializationInfo *Info =
+ NewFD->getTemplateSpecializationInfo();
+ if (Info && SC != SC_None) {
+ if (SC != Info->getTemplate()->getTemplatedDecl()->getStorageClass())
Diag(NewFD->getLocation(),
diag::err_explicit_specialization_inconsistent_storage_class)
<< SC
@@ -6428,17 +7135,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Perform semantic checking on the function declaration.
if (!isDependentClassScopeExplicitSpecialization) {
+ if (!NewFD->isInvalidDecl() && NewFD->isMain())
+ CheckMain(NewFD, D.getDeclSpec());
+
+ if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
+ CheckMSVCRTEntryPoint(NewFD);
+
if (NewFD->isInvalidDecl()) {
// If this is a class member, mark the class invalid immediately.
// This avoids some consistency errors later.
if (CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(NewFD))
methodDecl->getParent()->setInvalidDecl();
- } else {
- if (NewFD->isMain())
- CheckMain(NewFD, D.getDeclSpec());
+ } else
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isExplicitSpecialization));
- }
}
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
@@ -6456,8 +7166,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setAccess(Access);
if (FunctionTemplate) FunctionTemplate->setAccess(Access);
-
- PrincipalDecl->setObjectOfFriendDecl(true);
}
if (NewFD->isOverloadedOperator() && !DC->isRecord() &&
@@ -6523,9 +7231,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
- if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
- NewFD,
- ExtraArgs)) {
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(
+ *this, Previous, NewFD, ExtraArgs, false, 0)) {
AddToScope = ExtraArgs.AddToScope;
return Result;
}
@@ -6534,9 +7241,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Unqualified local friend declarations are required to resolve
// to something.
} else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
- if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
- NewFD,
- ExtraArgs)) {
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(
+ *this, Previous, NewFD, ExtraArgs, true, S)) {
AddToScope = ExtraArgs.AddToScope;
return Result;
}
@@ -6570,7 +7276,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Turn this into a variadic function with no parameters.
const FunctionType *FT = NewFD->getType()->getAs<FunctionType>();
- FunctionProtoType::ExtProtoInfo EPI;
+ FunctionProtoType::ExtProtoInfo EPI(
+ Context.getDefaultCallingConvention(true, false));
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();
@@ -6580,18 +7287,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this function.
- if (!DC->isRecord() && NewFD->hasExternalLinkage())
+ if (!DC->isRecord() && NewFD->isExternallyVisible())
AddPushedVisibilityAttribute(NewFD);
// If there's a #pragma clang arc_cf_code_audited in scope, consider
// marking the function.
AddCFAuditedAttribute(NewFD);
- // If this is a locally-scoped extern C function, update the
- // map of such names.
- if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
- && !NewFD->isInvalidDecl())
- RegisterLocallyScopedExternCDecl(NewFD, Previous, S);
+ // If this is the first declaration of an extern C variable, update
+ // the map of such variables.
+ if (NewFD->isFirstDecl() && !NewFD->isInvalidDecl() &&
+ isIncompleteDeclExternC(*this, NewFD))
+ RegisterLocallyScopedExternCDecl(NewFD, S);
// Set this FunctionDecl's range up to the right paren.
NewFD->setRangeEnd(D.getSourceRange().getEnd());
@@ -6618,27 +7325,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_expected_kernel_void_return_type);
D.setInvalidType();
}
-
+
+ llvm::SmallPtrSet<const Type *, 16> ValidTypes;
for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
PE = NewFD->param_end(); PI != PE; ++PI) {
ParmVarDecl *Param = *PI;
- QualType PT = Param->getType();
-
- // OpenCL v1.2 s6.9.a:
- // A kernel function argument cannot be declared as a
- // pointer to a pointer type.
- if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
- Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
- D.setInvalidType();
- }
-
- // OpenCL v1.2 s6.8 n:
- // A kernel function argument cannot be declared
- // of event_t type.
- if (PT->isEventT()) {
- Diag(Param->getLocation(), diag::err_event_t_kernel_arg);
- D.setInvalidType();
- }
+ checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
}
}
@@ -6694,15 +7386,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
assert(!NewFD->getResultType()->isVariablyModifiedType()
&& "Variably modified return types are not handled here");
- // Check for a previous declaration of this name.
- if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
- // Since we did not find anything by this name, look for a non-visible
- // extern "C" declaration with the same name.
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternCDecl(NewFD->getDeclName());
- if (Pos != LocallyScopedExternCDecls.end())
- Previous.addDecl(Pos->second);
- }
+ // Determine whether the type of this function should be merged with
+ // a previous visible declaration. This never happens for functions in C++,
+ // and always happens in C if the previous declaration was visible.
+ bool MergeTypeWithPrevious = !getLangOpts().CPlusPlus &&
+ !Previous.isShadowed();
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewFD, Previous);
@@ -6758,6 +7446,35 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
+ // Check for a previous extern "C" declaration with this name.
+ if (!Redeclaration &&
+ checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
+ filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+ if (!Previous.empty()) {
+ // This is an extern "C" declaration with the same name as a previous
+ // declaration, and thus redeclares that entity...
+ Redeclaration = true;
+ OldDecl = Previous.getFoundDecl();
+ 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(::new (Context) OverloadableAttr(SourceLocation(),
+ Context));
+ }
+ if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+ Redeclaration = false;
+ OldDecl = 0;
+ }
+ }
+ }
+ }
+
// C++11 [dcl.constexpr]p8:
// A constexpr specifier for a non-static member function that is not
// a constructor declares that member function to be const.
@@ -6781,9 +7498,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
MD->setType(Context.getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI));
+ FPT->getArgTypes(), EPI));
// Warn that we did this, if we're not performing template instantiation.
// In that case, we'll have warned already when the template was defined.
@@ -6802,7 +7517,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
- if (MergeFunctionDecl(NewFD, OldDecl, S)) {
+ if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious)) {
NewFD->setInvalidDecl();
return Redeclaration;
}
@@ -6850,7 +7565,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// setNonKeyFunction needs to work with the original
// declaration from the class definition, and isVirtual() is
// just faster in that case, so map back to that now.
- oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDeclaration());
+ oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDecl());
if (oldMethod->isVirtual()) {
Context.setNonKeyFunction(oldMethod);
}
@@ -6922,7 +7637,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// during delayed parsing anyway.
if (!CurContext->isRecord())
CheckCXXDefaultArguments(NewFD);
-
+
// If this function declares a builtin function, check the type of this
// declaration against the expected type for the builtin.
if (unsigned BuiltinID = NewFD->getBuiltinID()) {
@@ -6935,7 +7650,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents);
}
}
-
+
// If this function is declared as being extern "C", then check to see if
// the function returns a UDT (class, struct, or union type) that is not C
// compatible, and if it does, warn the user.
@@ -6998,6 +7713,13 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
FD->setConstexpr(false);
}
+ if (getLangOpts().OpenCL) {
+ Diag(FD->getLocation(), diag::err_opencl_no_main)
+ << FD->hasAttr<OpenCLKernelAttr>();
+ FD->setInvalidDecl();
+ return;
+ }
+
QualType T = FD->getType();
assert(T->isFunctionType() && "function decl is not of function type");
const FunctionType* FT = T->castAs<FunctionType>();
@@ -7096,7 +7818,27 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
}
if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
- Diag(FD->getLocation(), diag::err_main_template_decl);
+ Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
+ FD->setInvalidDecl();
+ }
+}
+
+void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
+ QualType T = FD->getType();
+ assert(T->isFunctionType() && "function decl is not of function type");
+ const FunctionType *FT = T->castAs<FunctionType>();
+
+ // Set an implicit return of 'zero' if the function can return some integral,
+ // enumeration, pointer or nullptr type.
+ if (FT->getResultType()->isIntegralOrEnumerationType() ||
+ FT->getResultType()->isAnyPointerType() ||
+ FT->getResultType()->isNullPtrType())
+ // DllMain is exempt because a return value of zero means it failed.
+ if (FD->getName() != "DllMain")
+ FD->setHasImplicitReturnZero(true);
+
+ if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
+ Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
FD->setInvalidDecl();
}
}
@@ -7313,7 +8055,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
RealDecl->setInvalidDecl();
return;
}
-
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
@@ -7326,14 +8067,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// It isn't possible to write this directly, but it is possible to
// end up in this situation with "auto x(some_pack...);"
Diag(CXXDirectInit->getLocStart(),
- diag::err_auto_var_init_no_expression)
+ VDecl->isInitCapture() ? diag::err_init_capture_no_expression
+ : diag::err_auto_var_init_no_expression)
<< VDecl->getDeclName() << VDecl->getType()
<< VDecl->getSourceRange();
RealDecl->setInvalidDecl();
return;
} else if (CXXDirectInit->getNumExprs() > 1) {
Diag(CXXDirectInit->getExpr(1)->getLocStart(),
- diag::err_auto_var_init_multiple_expressions)
+ VDecl->isInitCapture()
+ ? diag::err_init_capture_multiple_expressions
+ : diag::err_auto_var_init_multiple_expressions)
<< VDecl->getDeclName() << VDecl->getType()
<< VDecl->getSourceRange();
RealDecl->setInvalidDecl();
@@ -7385,8 +8129,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDecl())
- MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
+ if (VarDecl *Old = VDecl->getPreviousDecl()) {
+ // We never need to merge the type, because we cannot form an incomplete
+ // array of auto, nor deduce such a type.
+ MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/false);
+ }
// Check the deduced type is valid for a variable declaration.
CheckVariableDeclarationType(VDecl);
@@ -7576,9 +8323,20 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// 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() &&
- VDecl->getStorageClass() == SC_Static)
- CheckForConstantInitializer(Init, DclT);
+ if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
+ 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))
+ Diag(Init->getExprLoc(),
+ diag::ext_aggregate_init_not_constant)
+ << Init->getSourceRange();
+ }
} else if (VDecl->isStaticDataMember() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
@@ -7679,7 +8437,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (VDecl->getStorageClass() == SC_Extern &&
(!getLangOpts().CPlusPlus ||
!(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
- VDecl->isExternC())))
+ VDecl->isExternC())) &&
+ !isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
// C99 6.7.8p4. All file scoped initializers need to be constant.
@@ -7817,7 +8576,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// declared with no linkage (C99 6.2.2p6), the type for the
// object shall be complete.
if (!Type->isDependentType() && Var->isLocalVarDecl() &&
- !Var->getLinkage() && !Var->isInvalidDecl() &&
+ !Var->hasLinkage() && !Var->isInvalidDecl() &&
RequireCompleteType(Var->getLocation(), Type,
diag::err_typecheck_decl_incomplete_type))
Var->setInvalidDecl();
@@ -7859,7 +8618,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// is accepted by gcc. Hence here we issue a warning instead of
// an error and we do not invalidate the static declaration.
// NOTE: to avoid multiple warnings, only check the first declaration.
- if (Var->getPreviousDecl() == 0)
+ if (Var->isFirstDecl())
RequireCompleteType(Var->getLocation(), Type,
diag::ext_typecheck_decl_incomplete_type);
}
@@ -8030,7 +8789,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
if (var->isThisDeclarationADefinition() &&
- var->hasExternalLinkage() &&
+ var->isExternallyVisible() && var->hasLinkage() &&
getDiagnostics().getDiagnosticLevel(
diag::warn_missing_variable_declarations,
var->getLocation())) {
@@ -8091,10 +8850,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (IsGlobal && !var->isConstexpr() &&
getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
var->getLocation())
- != DiagnosticsEngine::Ignored &&
- !Init->isConstantInitializer(Context, baseType->isReferenceType()))
- Diag(var->getLocation(), diag::warn_global_constructor)
- << Init->getSourceRange();
+ != DiagnosticsEngine::Ignored) {
+ // Warn about globals which don't have a constant initializer. Don't
+ // warn about globals with a non-trivial destructor because we already
+ // warned about them.
+ CXXRecordDecl *RD = baseType->getAsCXXRecordDecl();
+ if (!(RD && !RD->hasTrivialDestructor()) &&
+ !Init->isConstantInitializer(Context, baseType->isReferenceType()))
+ Diag(var->getLocation(), diag::warn_global_constructor)
+ << Init->getSourceRange();
+ }
if (var->isConstexpr()) {
SmallVector<PartialDiagnosticAt, 8> Notes;
@@ -8136,10 +8901,29 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;
+ if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
+ if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
+ Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "used";
+ VD->dropAttr<UsedAttr>();
+ }
+ }
+
+ if (!VD->isInvalidDecl() &&
+ VD->isThisDeclarationADefinition() == VarDecl::TentativeDefinition) {
+ if (const VarDecl *Def = VD->getDefinition()) {
+ if (Def->hasAttr<AliasAttr>()) {
+ Diag(VD->getLocation(), diag::err_tentative_after_alias)
+ << VD->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ VD->setInvalidDecl();
+ }
+ }
+ }
+
const DeclContext *DC = VD->getDeclContext();
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this variable.
- if (!DC->isRecord() && VD->hasExternalLinkage())
+ if (!DC->isRecord() && VD->isExternallyVisible())
AddPushedVisibilityAttribute(VD);
if (VD->isFileVarDecl())
@@ -8181,30 +8965,37 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
-Sema::DeclGroupPtrTy
-Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
- Decl **Group, unsigned NumDecls) {
+Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
+ ArrayRef<Decl *> Group) {
SmallVector<Decl*, 8> Decls;
if (DS.isTypeSpecOwned())
Decls.push_back(DS.getRepAsDecl());
- for (unsigned i = 0; i != NumDecls; ++i)
- if (Decl *D = Group[i])
+ DeclaratorDecl *FirstDeclaratorInGroup = 0;
+ for (unsigned i = 0, e = Group.size(); i != e; ++i)
+ if (Decl *D = Group[i]) {
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
+ if (!FirstDeclaratorInGroup)
+ FirstDeclaratorInGroup = DD;
Decls.push_back(D);
+ }
- if (DeclSpec::isDeclRep(DS.getTypeSpecType()))
- if (const TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()))
- getASTContext().addUnnamedTag(Tag);
+ if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
+ if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) {
+ HandleTagNumbering(*this, Tag);
+ if (!Tag->hasNameForLinkage() && !Tag->hasDeclaratorForAnonDecl())
+ Tag->setDeclaratorForAnonDecl(FirstDeclaratorInGroup);
+ }
+ }
- return BuildDeclaratorGroup(Decls.data(), Decls.size(),
- DS.containsPlaceholderType());
+ return BuildDeclaratorGroup(Decls, DS.containsPlaceholderType());
}
/// BuildDeclaratorGroup - convert a list of declarations into a declaration
/// group, performing any necessary semantic checking.
Sema::DeclGroupPtrTy
-Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
+Sema::BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *> Group,
bool TypeMayContainAuto) {
// C++0x [dcl.spec.auto]p7:
// If the type deduced for the template parameter U is not the same in each
@@ -8213,11 +9004,11 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
// between the deduced type U and the deduced type which 'auto' stands for.
// auto a = 0, b = { 1, 2, 3 };
// is legal because the deduced type U is 'int' in both cases.
- if (TypeMayContainAuto && NumDecls > 1) {
+ if (TypeMayContainAuto && Group.size() > 1) {
QualType Deduced;
CanQualType DeducedCanon;
VarDecl *DeducedDecl = 0;
- for (unsigned i = 0; i != NumDecls; ++i) {
+ for (unsigned i = 0, e = Group.size(); i != e; ++i) {
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
AutoType *AT = D->getType()->getContainedAutoType();
// Don't reissue diagnostics when instantiating a template.
@@ -8246,18 +9037,19 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
}
}
- ActOnDocumentableDecls(Group, NumDecls);
+ ActOnDocumentableDecls(Group);
- return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls));
+ return DeclGroupPtrTy::make(
+ DeclGroupRef::Create(Context, Group.data(), Group.size()));
}
void Sema::ActOnDocumentableDecl(Decl *D) {
- ActOnDocumentableDecls(&D, 1);
+ ActOnDocumentableDecls(D);
}
-void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
+void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
// Don't parse the comment if Doxygen diagnostics are ignored.
- if (NumDecls == 0 || !Group[0])
+ if (Group.empty() || !Group[0])
return;
if (Diags.getDiagnosticLevel(diag::warn_doc_param_not_found,
@@ -8265,9 +9057,9 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
== DiagnosticsEngine::Ignored)
return;
- if (NumDecls >= 2) {
+ if (Group.size() >= 2) {
// This is a decl group. Normally it will contain only declarations
- // procuded from declarator list. But in case we have any definitions or
+ // produced from declarator list. But in case we have any definitions or
// additional declaration references:
// 'typedef struct S {} S;'
// 'typedef struct S *S;'
@@ -8275,8 +9067,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
// FinalizeDeclaratorGroup adds these as separate declarations.
Decl *MaybeTagDecl = Group[0];
if (MaybeTagDecl && isa<TagDecl>(MaybeTagDecl)) {
- Group++;
- NumDecls--;
+ Group = Group.slice(1);
}
}
@@ -8291,7 +9082,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
// declaration, but also comments that *follow* the declaration -- thanks to
// the lookahead in the lexer: we've consumed the semicolon and looked
// ahead through comments.
- for (unsigned i = 0; i != NumDecls; ++i)
+ for (unsigned i = 0, e = Group.size(); i != e; ++i)
Context.getCommentForDecl(Group[i], &PP);
}
}
@@ -8302,6 +9093,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+
// C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
@@ -8614,38 +9406,90 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
// Don't warn for OpenCL kernels.
if (FD->hasAttr<OpenCLKernelAttr>())
return false;
-
+
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
// scope, because they aren't visible from the header.
- if (Prev->getDeclContext()->isFunctionOrMethod())
+ if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
continue;
-
+
MissingPrototype = !Prev->getType()->isFunctionProtoType();
if (FD->getNumParams() == 0)
PossibleZeroParamPrototype = Prev;
break;
}
-
+
return MissingPrototype;
}
-void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
+void
+Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
+ const FunctionDecl *EffectiveDefinition) {
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
- const FunctionDecl *Definition;
- if (FD->isDefined(Definition) &&
- !canRedefineFunction(Definition, getLangOpts())) {
- if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
- Definition->getStorageClass() == SC_Extern)
- Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
+ const FunctionDecl *Definition = EffectiveDefinition;
+ if (!Definition)
+ if (!FD->isDefined(Definition))
+ return;
+
+ if (canRedefineFunction(Definition, getLangOpts()))
+ return;
+
+ if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
+ Definition->getStorageClass() == SC_Extern)
+ Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
<< FD->getDeclName() << getLangOpts().CPlusPlus;
- else
- Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
- Diag(Definition->getLocation(), diag::note_previous_definition);
- FD->setInvalidDecl();
+ else
+ Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
+
+ Diag(Definition->getLocation(), diag::note_previous_definition);
+ FD->setInvalidDecl();
+}
+
+
+static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
+ Sema &S) {
+ CXXRecordDecl *const LambdaClass = CallOperator->getParent();
+
+ LambdaScopeInfo *LSI = S.PushLambdaScope();
+ LSI->CallOperator = CallOperator;
+ LSI->Lambda = LambdaClass;
+ LSI->ReturnType = CallOperator->getResultType();
+ const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();
+
+ if (LCD == LCD_None)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_None;
+ else if (LCD == LCD_ByCopy)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByval;
+ else if (LCD == LCD_ByRef)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref;
+ DeclarationNameInfo DNI = CallOperator->getNameInfo();
+
+ LSI->IntroducerRange = DNI.getCXXOperatorNameRange();
+ LSI->Mutable = !CallOperator->isConst();
+
+ // Add the captures to the LSI so they can be noted as already
+ // captured within tryCaptureVar.
+ for (LambdaExpr::capture_iterator C = LambdaClass->captures_begin(),
+ CEnd = LambdaClass->captures_end(); C != CEnd; ++C) {
+ if (C->capturesVariable()) {
+ VarDecl *VD = C->getCapturedVar();
+ if (VD->isInitCapture())
+ S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
+ QualType CaptureType = VD->getType();
+ const bool ByRef = C->getCaptureKind() == LCK_ByRef;
+ LSI->addCapture(VD, /*IsBlock*/false, ByRef,
+ /*RefersToEnclosingLocal*/true, C->getLocation(),
+ /*EllipsisLoc*/C->isPackExpansion()
+ ? C->getEllipsisLoc() : SourceLocation(),
+ CaptureType, /*Expr*/ 0);
+
+ } else if (C->capturesThis()) {
+ LSI->addThisCapture(/*Nested*/ false, C->getLocation(),
+ S.getCurrentThisType(), /*Expr*/ 0);
+ }
}
}
@@ -8661,9 +9505,24 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
FD = FunTmpl->getTemplatedDecl();
else
FD = cast<FunctionDecl>(D);
-
- // Enter a new function scope
- PushFunctionScope();
+ // If we are instantiating a generic lambda call operator, push
+ // a LambdaScopeInfo onto the function stack. But use the information
+ // that's already been calculated (ActOnLambdaExpr) to prime the current
+ // LambdaScopeInfo.
+ // When the template operator is being specialized, the LambdaScopeInfo,
+ // has to be properly restored so that tryCaptureVariable doesn't try
+ // and capture any new variables. In addition when calculating potential
+ // captures during transformation of nested lambdas, it is necessary to
+ // have the LSI properly restored.
+ if (isGenericLambdaCallOperatorSpecialization(FD)) {
+ assert(ActiveTemplateInstantiations.size() &&
+ "There should be an active template instantiation on the stack "
+ "when instantiating a generic lambda!");
+ RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D), *this);
+ }
+ else
+ // Enter a new function scope
+ PushFunctionScope();
// See if this is a redefinition.
if (!FD->isLateTemplateParsed())
@@ -8671,7 +9530,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// Builtin functions cannot be defined.
if (unsigned BuiltinID = FD->getBuiltinID()) {
- if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) &&
+ !Context.BuiltinInfo.isPredefinedRuntimeFunction(BuiltinID)) {
Diag(FD->getLocation(), diag::err_builtin_definition) << FD;
FD->setInvalidDecl();
}
@@ -8694,17 +9554,19 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
const FunctionDecl *PossibleZeroParamPrototype = 0;
if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
-
+
if (PossibleZeroParamPrototype) {
- // We found a declaration that is not a prototype,
+ // We found a declaration that is not a prototype,
// but that could be a zero-parameter prototype
- TypeSourceInfo* TI = PossibleZeroParamPrototype->getTypeSourceInfo();
- TypeLoc TL = TI->getTypeLoc();
- if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
- Diag(PossibleZeroParamPrototype->getLocation(),
- diag::note_declaration_not_a_prototype)
- << PossibleZeroParamPrototype
- << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ if (TypeSourceInfo *TI =
+ PossibleZeroParamPrototype->getTypeSourceInfo()) {
+ TypeLoc TL = TI->getTypeLoc();
+ if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
+ Diag(PossibleZeroParamPrototype->getLocation(),
+ diag::note_declaration_not_a_prototype)
+ << PossibleZeroParamPrototype
+ << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ }
}
}
@@ -8731,8 +9593,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// If we had any tags defined in the function prototype,
// introduce them into the function scope.
if (FnBodyScope) {
- for (llvm::ArrayRef<NamedDecl*>::iterator I = FD->getDeclsInPrototypeScope().begin(),
- E = FD->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ for (ArrayRef<NamedDecl *>::iterator
+ I = FD->getDeclsInPrototypeScope().begin(),
+ E = FD->getDeclsInPrototypeScope().end();
+ I != E; ++I) {
NamedDecl *D = *I;
// Some of these decls (like enums) may have been pinned to the translation unit
@@ -8851,7 +9715,9 @@ bool Sema::canSkipFunctionBody(Decl *D) {
// We cannot skip the body of a function (or function template) which is
// constexpr, since we may need to evaluate its body in order to parse the
// rest of the file.
- return !FD->isConstexpr();
+ // We cannot skip the body of a function with an undeduced return type,
+ // because any callers of that function need to know the type.
+ return !FD->isConstexpr() && !FD->getResultType()->isUndeducedType();
}
Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
@@ -8881,26 +9747,29 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
- if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() &&
- !FD->isDependentContext()) {
- if (FD->getResultType()->isUndeducedType()) {
- // If the function has a deduced result type but contains no 'return'
- // statements, the result type as written must be exactly 'auto', and
- // the deduced result type is 'void'.
- if (!FD->getResultType()->getAs<AutoType>()) {
- Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
- << FD->getResultType();
- FD->setInvalidDecl();
- }
- Context.adjustDeducedFunctionResultType(FD, Context.VoidTy);
+ if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && Body &&
+ !FD->isDependentContext() && FD->getResultType()->isUndeducedType()) {
+ // If the function has a deduced result type but contains no 'return'
+ // statements, the result type as written must be exactly 'auto', and
+ // the deduced result type is 'void'.
+ if (!FD->getResultType()->getAs<AutoType>()) {
+ Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
+ << FD->getResultType();
+ FD->setInvalidDecl();
+ } else {
+ // Substitute 'void' for the 'auto' in the type.
+ TypeLoc ResultType = FD->getTypeSourceInfo()->getTypeLoc().
+ IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
+ Context.adjustDeducedFunctionResultType(
+ FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
}
}
// 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->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) {
- if (FD->getLinkage() != ExternalLinkage)
+ if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) {
+ if (!FD->isExternallyVisible())
UndefinedButUsed.erase(FD);
else if (FD->isInlined() &&
(LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
@@ -8915,7 +9784,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// MSVC permits the use of pure specifier (=0) on function definition,
// defined at class scope, warn about this non standard construct.
- if (getLangOpts().MicrosoftExt && FD->isPure())
+ if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl())
Diag(FD->getLocation(), diag::warn_pure_function_definition);
if (!FD->isInvalidDecl()) {
@@ -9013,7 +9882,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
PopDeclContext();
PopFunctionScopeInfo(ActivePolicy, dcl);
-
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
@@ -9048,12 +9916,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// 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.
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternCDecl(&II);
- if (Pos != LocallyScopedExternCDecls.end()) {
- Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
- Diag(Pos->second->getLocation(), diag::note_previous_declaration);
- return Pos->second;
+ if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) {
+ Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev;
+ Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
+ return ExternCPrev;
}
// Extension in C99. Legal in C90, but warn about it.
@@ -9072,19 +9938,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
TypoCorrection Corrected;
DeclFilterCCC<FunctionDecl> Validator;
if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
- LookupOrdinaryName, S, 0, Validator))) {
- std::string CorrectedStr = Corrected.getAsString(getLangOpts());
- std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
- FunctionDecl *Func = Corrected.getCorrectionDeclAs<FunctionDecl>();
-
- Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr
- << FixItHint::CreateReplacement(Loc, CorrectedStr);
-
- if (Func->getLocation().isValid()
- && !II.getName().startswith("__builtin_"))
- Diag(Func->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
- }
+ LookupOrdinaryName, S, 0, Validator)))
+ diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
+ /*ErrorRecovery*/false);
}
// Set a Declarator for the implicit definition: int foo();
@@ -9163,7 +10019,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType())
fmt = "NSString";
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
- fmt, FormatIdx+1,
+ &Context.Idents.get(fmt),
+ FormatIdx+1,
HasVAListArg ? 0 : FormatIdx+2));
}
}
@@ -9171,7 +10028,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
HasVAListArg)) {
if (!FD->getAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
- "scanf", FormatIdx+1,
+ &Context.Idents.get("scanf"),
+ FormatIdx+1,
HasVAListArg ? 0 : FormatIdx+2));
}
@@ -9211,7 +10069,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
- "printf", 2,
+ &Context.Idents.get("printf"), 2,
Name->isStr("vasprintf") ? 0 : 3));
}
@@ -9245,7 +10103,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
NewTD->setInvalidDecl();
return NewTD;
}
-
+
if (D.getDeclSpec().isModulePrivateSpecified()) {
if (CurContext->isFunctionOrMethod())
Diag(NewTD->getLocation(), diag::err_module_private_local)
@@ -9496,13 +10354,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// for non-C++ cases.
if (TemplateParameterLists.size() > 0 ||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
- if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
- TemplateParameterLists.data(),
- TemplateParameterLists.size(),
- TUK == TUK_Friend,
- isExplicitSpecialization,
- Invalid)) {
+ if (TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ KWLoc, NameLoc, SS, TemplateParameterLists, TUK == TUK_Friend,
+ isExplicitSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
return 0;
@@ -9571,7 +10426,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Redecl = NotForRedeclaration;
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
-
+ bool FriendSawTagOutsideEnclosingNamespace = false;
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -9664,8 +10519,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
while (F.hasNext()) {
NamedDecl *ND = F.next();
DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext()))
+ if (DC->isFileContext() &&
+ !EnclosingNS->Encloses(ND->getDeclContext())) {
F.erase();
+ FriendSawTagOutsideEnclosingNamespace = true;
+ }
}
F.done();
}
@@ -9756,8 +10614,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
(getLangOpts().CPlusPlus &&
S->isFunctionPrototypeScope()) ||
((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext()))
+ (S->getEntity() && S->getEntity()->isTransparentContext()))
S = S->getParent();
} else {
assert(TUK == TUK_Friend);
@@ -9864,6 +10721,16 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return TUK == TUK_Declaration ? PrevTagDecl : 0;
}
+ // C++11 [class.mem]p1:
+ // A member shall not be declared twice in the member-specification,
+ // except that a nested class or member class template can be declared
+ // and then later defined.
+ if (TUK == TUK_Declaration && PrevDecl->isCXXClassMember() &&
+ S->isDeclScope(PrevDecl)) {
+ Diag(NameLoc, diag::ext_member_redeclared);
+ Diag(PrevTagDecl->getLocation(), diag::note_previous_declaration);
+ }
+
if (!Invalid) {
// If this is a use, just return the declaration we found.
@@ -10154,7 +11021,7 @@ CreateNewDecl:
// declaration so we always pass true to setObjectOfFriendDecl to make
// the tag name visible.
if (TUK == TUK_Friend)
- New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
+ New->setObjectOfFriendDecl(!FriendSawTagOutsideEnclosingNamespace &&
getLangOpts().MicrosoftExt);
// Set the access specifier.
@@ -10238,6 +11105,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
SourceLocation FinalLoc,
+ bool IsFinalSpelledSealed,
SourceLocation LBraceLoc) {
AdjustDeclIfTemplate(TagD);
CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD);
@@ -10248,8 +11116,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
return;
if (FinalLoc.isValid())
- Record->addAttr(new (Context) FinalAttr(FinalLoc, Context));
-
+ Record->addAttr(new (Context)
+ FinalAttr(FinalLoc, Context, IsFinalSpelledSealed));
+
// C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
// class itself; this is known as the injected-class-name. For
@@ -10295,7 +11164,8 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
Tag->setTopLevelDeclInObjCContainer();
// Notify the consumer that we've defined a tag.
- Consumer.HandleTagDeclDefinition(Tag);
+ if (!Tag->isInvalidDecl())
+ Consumer.HandleTagDeclDefinition(Tag);
}
void Sema::ActOnObjCContainerFinishDefinition() {
@@ -10335,8 +11205,8 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
// Note that FieldName may be null for anonymous bitfields.
ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
IdentifierInfo *FieldName,
- QualType FieldTy, Expr *BitWidth,
- bool *ZeroWidth) {
+ QualType FieldTy, bool IsMsStruct,
+ Expr *BitWidth, bool *ZeroWidth) {
// Default to true; that shouldn't confuse checks for emptiness
if (ZeroWidth)
*ZeroWidth = true;
@@ -10385,7 +11255,7 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
if (!FieldTy->isDependentType()) {
uint64_t TypeSize = Context.getTypeSize(FieldTy);
if (Value.getZExtValue() > TypeSize) {
- if (!getLangOpts().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus || IsMsStruct) {
if (FieldName)
return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
<< FieldName << (unsigned)Value.getZExtValue()
@@ -10603,7 +11473,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
bool ZeroWidth = false;
// If this is declared as a bit-field, check the bit-field.
if (!InvalidDecl && BitWidth) {
- BitWidth = VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth).take();
+ BitWidth = VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth,
+ &ZeroWidth).take();
if (!BitWidth) {
InvalidDecl = true;
BitWidth = 0;
@@ -10656,11 +11527,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
// C++ [class.union]p1: If a union contains a member of reference type,
- // the program is ill-formed.
+ // the program is ill-formed, except when compiling with MSVC extensions
+ // enabled.
if (EltTy->isReferenceType()) {
- Diag(NewFD->getLocation(), diag::err_union_member_of_reference_type)
+ Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ?
+ diag::ext_union_member_of_reference_type :
+ diag::err_union_member_of_reference_type)
<< NewFD->getDeclName() << EltTy;
- NewFD->setInvalidDecl();
+ if (!getLangOpts().MicrosoftExt)
+ NewFD->setInvalidDecl();
}
}
}
@@ -10691,8 +11566,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
assert(FD);
assert(getLangOpts().CPlusPlus && "valid check only for C++");
- if (FD->isInvalidDecl())
- return true;
+ if (FD->isInvalidDecl() || FD->getType()->isDependentType())
+ return false;
QualType EltTy = Context.getBaseElementType(FD->getType());
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
@@ -10780,7 +11655,7 @@ Decl *Sema::ActOnIvar(Scope *S,
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
- BitWidth = VerifyBitField(Loc, II, T, BitWidth).take();
+ BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).take();
if (!BitWidth)
D.setInvalidType();
} else {
@@ -10910,11 +11785,9 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
AllIvarDecls.push_back(Ivar);
}
-void Sema::ActOnFields(Scope* S,
- SourceLocation RecLoc, Decl *EnclosingDecl,
- llvm::ArrayRef<Decl *> Fields,
- SourceLocation LBrac, SourceLocation RBrac,
- AttributeList *Attr) {
+void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
+ ArrayRef<Decl *> Fields, SourceLocation LBrac,
+ SourceLocation RBrac, AttributeList *Attr) {
assert(EnclosingDecl && "missing record or interface decl");
// If this is an Objective-C @implementation or category and we have
@@ -10952,7 +11825,7 @@ void Sema::ActOnFields(Scope* S,
SmallVector<FieldDecl*, 32> RecFields;
bool ARCErrReported = false;
- for (llvm::ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
+ for (ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
i != end; ++i) {
FieldDecl *FD = cast<FieldDecl>(*i);
@@ -10997,34 +11870,38 @@ void Sema::ActOnFields(Scope* S,
// 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.
- if (getLangOpts().MicrosoftExt) {
- if (Record->isUnion())
- Diag(FD->getLocation(), diag::ext_flexible_array_union_ms)
- << FD->getDeclName();
- else if (Fields.size() == 1)
- Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms)
- << FD->getDeclName() << Record->getTagKind();
- } else if (getLangOpts().CPlusPlus) {
- if (Record->isUnion())
- Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
- << FD->getDeclName();
- else if (Fields.size() == 1)
- Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu)
- << FD->getDeclName() << Record->getTagKind();
- } else if (!getLangOpts().C99) {
+ unsigned DiagID = 0;
if (Record->isUnion())
- Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
- << FD->getDeclName();
- else
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_union_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_union_gnu
+ : diag::err_flexible_array_union;
+ else if (Fields.size() == 1)
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_empty_aggregate_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_empty_aggregate_gnu
+ : NumNamedMembers < 1
+ ? diag::err_flexible_array_empty_aggregate
+ : 0;
+
+ 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();
- } else if (NumNamedMembers < 1) {
- Diag(FD->getLocation(), diag::err_flexible_array_empty_struct)
- << FD->getDeclName();
- FD->setInvalidDecl();
- EnclosingDecl->setInvalidDecl();
- continue;
- }
+
if (!FD->getType()->isDependentType() &&
!Context.getBaseElementType(FD->getType()).isPODType(Context)) {
Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
@@ -11139,10 +12016,18 @@ void Sema::ActOnFields(Scope* S,
I.setAccess((*I)->getAccess());
if (!CXXRecord->isDependentType()) {
- // Adjust user-defined destructor exception spec.
- if (getLangOpts().CPlusPlus11 &&
- CXXRecord->hasUserDeclaredDestructor())
- AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
+ if (CXXRecord->hasUserDeclaredDestructor()) {
+ // Adjust user-defined destructor exception spec.
+ if (getLangOpts().CPlusPlus11)
+ AdjustDestructorExceptionSpec(CXXRecord,
+ CXXRecord->getDestructor());
+
+ // The Microsoft ABI requires that we perform the destructor body
+ // checks (i.e. operator delete() lookup) at every declaration, as
+ // any translation unit may need to emit a deleting destructor.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ CheckDestructor(CXXRecord->getDestructor());
+ }
// Add any implicitly-declared members to this class.
AddImplicitlyDeclaredMembersToClass(CXXRecord);
@@ -11195,6 +12080,59 @@ void Sema::ActOnFields(Scope* S,
if (Record->hasAttrs())
CheckAlignasUnderalignment(Record);
+
+ // Check if the structure/union declaration is a type that can have zero
+ // size in C. For C this is a language extension, for C++ it may cause
+ // compatibility problems.
+ bool CheckForZeroSize;
+ if (!getLangOpts().CPlusPlus) {
+ CheckForZeroSize = true;
+ } else {
+ // For C++ filter out types that cannot be referenced in C code.
+ CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record);
+ CheckForZeroSize =
+ CXXRecord->getLexicalDeclContext()->isExternCContext() &&
+ !CXXRecord->isDependentType() &&
+ CXXRecord->isCLike();
+ }
+ if (CheckForZeroSize) {
+ bool ZeroSize = true;
+ bool IsEmpty = true;
+ unsigned NonBitFields = 0;
+ for (RecordDecl::field_iterator I = Record->field_begin(),
+ E = Record->field_end();
+ (NonBitFields == 0 || ZeroSize) && I != E; ++I) {
+ IsEmpty = false;
+ if (I->isUnnamedBitfield()) {
+ if (I->getBitWidthValue(Context) > 0)
+ ZeroSize = false;
+ } else {
+ ++NonBitFields;
+ QualType FieldType = I->getType();
+ if (FieldType->isIncompleteType() ||
+ !Context.getTypeSizeInChars(FieldType).isZero())
+ ZeroSize = false;
+ }
+ }
+
+ // Empty structs are an extension in C (C99 6.7.2.1p7). They are
+ // allowed in C++, but warn if its declaration is inside
+ // extern "C" block.
+ if (ZeroSize) {
+ Diag(RecLoc, getLangOpts().CPlusPlus ?
+ diag::warn_zero_size_struct_union_in_extern_c :
+ diag::warn_zero_size_struct_union_compat)
+ << IsEmpty << Record->isUnion() << (NonBitFields > 1);
+ }
+
+ // Structs without named members are extension in C (C99 6.7.2.1p7),
+ // but are accepted by GCC.
+ if (NonBitFields == 0 && !getLangOpts().CPlusPlus) {
+ Diag(RecLoc, IsEmpty ? diag::ext_empty_struct_union :
+ diag::ext_no_named_members_in_struct_union)
+ << Record->isUnion();
+ }
+ }
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -11989,6 +12927,12 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
return Import;
}
+void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ // FIXME: Should we synthesize an ImportDecl here?
+ PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc,
+ /*Complain=*/true);
+}
+
void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
// Create the implicit import declaration.
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 7b3345a33217..3e583862092c 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -23,6 +23,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
@@ -52,7 +53,11 @@ enum AttributeDeclKind {
ExpectedTLSVar,
ExpectedVariableOrField,
ExpectedVariableFieldOrTag,
- ExpectedTypeOrNamespace
+ ExpectedTypeOrNamespace,
+ ExpectedObjectiveCInterface,
+ ExpectedMethodOrProperty,
+ ExpectedStructOrUnion,
+ ExpectedStructOrUnionOrClass
};
//===----------------------------------------------------------------------===//
@@ -204,12 +209,18 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
}
+static unsigned getNumAttributeArgs(const AttributeList &Attr) {
+ // FIXME: Include the type in the argument list.
+ return Attr.getNumArgs() + Attr.hasParsedType();
+}
+
/// \brief Check if the attribute has exactly as many args as Num. May
/// output an error.
static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
- unsigned int Num) {
- if (Attr.getNumArgs() != Num) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num;
+ unsigned Num) {
+ if (getNumAttributeArgs(Attr) != Num) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << Num;
return false;
}
@@ -220,8 +231,8 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
/// \brief Check if the attribute has at least as many args as Num. May
/// output an error.
static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
- unsigned int Num) {
- if (Attr.getNumArgs() < Num) {
+ unsigned Num) {
+ if (getNumAttributeArgs(Attr) < Num) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num;
return false;
}
@@ -240,24 +251,27 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
const Expr *IdxExpr,
uint64_t &Idx)
{
- assert(isFunctionOrMethod(D) && hasFunctionProto(D));
+ assert(isFunctionOrMethod(D));
// In C++ the implicit 'this' function parameter also counts.
// Parameters are counted from one.
- const bool HasImplicitThisParam = isInstanceMethod(D);
- const unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
- const unsigned FirstIdx = 1;
+ bool HP = hasFunctionProto(D);
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ bool IV = HP && isFunctionOrMethodVariadic(D);
+ unsigned NumArgs = (HP ? getFunctionOrMethodNumArgs(D) : 0) +
+ HasImplicitThisParam;
llvm::APSInt IdxInt;
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
- S.Diag(AttrLoc, diag::err_attribute_argument_n_not_int)
- << AttrName << AttrArgNum << IdxExpr->getSourceRange();
+ std::string Name = std::string("'") + AttrName.str() + std::string("'");
+ S.Diag(AttrLoc, diag::err_attribute_argument_n_type) << Name.c_str()
+ << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange();
return false;
}
Idx = IdxInt.getLimitedValue();
- if (Idx < FirstIdx || (!isFunctionOrMethodVariadic(D) && Idx > NumArgs)) {
+ if (Idx < 1 || (!IV && Idx > NumArgs)) {
S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds)
<< AttrName << AttrArgNum << IdxExpr->getSourceRange();
return false;
@@ -276,6 +290,42 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
return true;
}
+/// \brief Check if the argument \p ArgNum of \p Attr is a ASCII string literal.
+/// If not emit an error and return false. If the argument is an identifier it
+/// will emit an error with a fixit hint and treat it as if it was a string
+/// literal.
+bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr,
+ unsigned ArgNum, StringRef &Str,
+ SourceLocation *ArgLocation) {
+ // Look for identifiers. If we have one emit a hint to fix it to a literal.
+ if (Attr.isArgIdent(ArgNum)) {
+ IdentifierLoc *Loc = Attr.getArgAsIdent(ArgNum);
+ Diag(Loc->Loc, diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentString
+ << FixItHint::CreateInsertion(Loc->Loc, "\"")
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(Loc->Loc), "\"");
+ Str = Loc->Ident->getName();
+ if (ArgLocation)
+ *ArgLocation = Loc->Loc;
+ return true;
+ }
+
+ // Now check for an actual string literal.
+ Expr *ArgExpr = Attr.getArgAsExpr(ArgNum);
+ StringLiteral *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
+ if (ArgLocation)
+ *ArgLocation = ArgExpr->getLocStart();
+
+ if (!Literal || !Literal->isAscii()) {
+ Diag(ArgExpr->getLocStart(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentString;
+ return false;
+ }
+
+ Str = Literal->getString();
+ return true;
+}
+
///
/// \brief Check if passed in Decl is a field or potentially shared global var
/// \return true if the Decl is a field or potentially shared global variable
@@ -414,7 +464,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
int Sidx = 0,
bool ParamIdxOk = false) {
for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
- Expr *ArgExp = Attr.getArg(Idx);
+ Expr *ArgExp = Attr.getArgAsExpr(Idx);
if (ArgExp->isTypeDependent()) {
// FIXME -- need to check this again on template instantiation
@@ -424,7 +474,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
if (StrLit->getLength() == 0 ||
- StrLit->getString() == StringRef("*")) {
+ (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) {
// Pass empty strings to the analyzer without warnings.
// Treat "*" as the universal lock.
Args.push_back(ArgExp);
@@ -492,11 +542,6 @@ enum ThreadAttributeDeclKind {
static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return false;
-
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -532,11 +577,6 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D,
static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
Expr* &Arg) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 1))
- return false;
-
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -579,13 +619,8 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D,
static bool checkLockableAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return false;
-
// FIXME: Lockable structs for C code.
- if (!isa<CXXRecordDecl>(D)) {
+ if (!isa<RecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
<< Attr.getName() << ThreadExpectedClassOrStruct;
return false;
@@ -613,11 +648,6 @@ static void handleScopedLockableAttr(Sema &S, Decl *D,
static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
<< Attr.getName() << ThreadExpectedFunctionOrMethod;
@@ -630,11 +660,6 @@ static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
@@ -648,11 +673,6 @@ static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
static void handleNoSanitizeMemory(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
@@ -665,11 +685,6 @@ static void handleNoSanitizeMemory(Sema &S, Decl *D,
static void handleNoSanitizeThread(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
@@ -682,9 +697,7 @@ static void handleNoSanitizeThread(Sema &S, Decl *D,
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
- SmallVector<Expr*, 1> &Args) {
- assert(!Attr.isInvalid());
-
+ SmallVectorImpl<Expr *> &Args) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return false;
@@ -743,9 +756,7 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
static bool checkLockFunAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
- SmallVector<Expr*, 1> &Args) {
- assert(!Attr.isInvalid());
-
+ SmallVectorImpl<Expr *> &Args) {
// zero or more arguments ok
// check that the attribute is applied to a function
@@ -788,11 +799,37 @@ static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleAssertSharedLockAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context)
+ AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context)
+ AssertExclusiveLockAttr(Attr.getRange(), S.Context,
+ StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+
static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
- SmallVector<Expr*, 2> &Args) {
- assert(!Attr.isInvalid());
-
+ SmallVectorImpl<Expr *> &Args) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return false;
@@ -802,9 +839,9 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
return false;
}
- if (!isIntOrBool(Attr.getArg(0))) {
- S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
- << Attr.getName();
+ if (!isIntOrBool(Attr.getArgAsExpr(0))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIntOrBool;
return false;
}
@@ -820,11 +857,10 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
D->addAttr(::new (S.Context)
SharedTrylockFunctionAttr(Attr.getRange(), S.Context,
- Attr.getArg(0), StartArg, Size,
+ Attr.getArgAsExpr(0),
+ Args.data(), Args.size(),
Attr.getAttributeSpellingListIndex()));
}
@@ -834,19 +870,16 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
D->addAttr(::new (S.Context)
ExclusiveTrylockFunctionAttr(Attr.getRange(), S.Context,
- Attr.getArg(0), StartArg, Size,
+ Attr.getArgAsExpr(0),
+ Args.data(), Args.size(),
Attr.getAttributeSpellingListIndex()));
}
static bool checkLocksRequiredCommon(Sema &S, Decl *D,
const AttributeList &Attr,
- SmallVector<Expr*, 1> &Args) {
- assert(!Attr.isInvalid());
-
+ SmallVectorImpl<Expr *> &Args) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return false;
@@ -892,8 +925,6 @@ static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
static void handleUnlockFunAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
// zero or more arguments ok
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
@@ -915,11 +946,6 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
static void handleLockReturnedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
<< Attr.getName() << ThreadExpectedFunctionOrMethod;
@@ -940,8 +966,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
static void handleLocksExcludedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(!Attr.isInvalid());
-
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
@@ -964,6 +988,260 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ ConsumableAttr::ConsumedState DefaultState;
+
+ if (Attr.isArgIdent(0)) {
+ IdentifierLoc *IL = Attr.getArgAsIdent(0);
+ if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(),
+ DefaultState)) {
+ S.Diag(IL->Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << IL->Ident;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ if (!isa<CXXRecordDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedClass;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ ConsumableAttr(Attr.getRange(), S.Context, DefaultState,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
+ const AttributeList &Attr) {
+ ASTContext &CurrContext = S.getASTContext();
+ QualType ThisType = MD->getThisType(CurrContext)->getPointeeType();
+
+ if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) {
+ if (!RD->hasAttr<ConsumableAttr>()) {
+ S.Diag(Attr.getLoc(), diag::warn_attr_on_unconsumable_class) <<
+ RD->getNameAsString();
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+static void handleCallableWhenAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ if (!isa<CXXMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedMethod;
+ return;
+ }
+
+ if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
+ return;
+
+ SmallVector<CallableWhenAttr::ConsumedState, 3> States;
+ for (unsigned ArgIndex = 0; ArgIndex < Attr.getNumArgs(); ++ArgIndex) {
+ CallableWhenAttr::ConsumedState CallableState;
+
+ StringRef StateString;
+ SourceLocation Loc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc))
+ return;
+
+ if (!CallableWhenAttr::ConvertStrToConsumedState(StateString,
+ CallableState)) {
+ S.Diag(Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << StateString;
+ return;
+ }
+
+ States.push_back(CallableState);
+ }
+
+ D->addAttr(::new (S.Context)
+ CallableWhenAttr(Attr.getRange(), S.Context, States.data(),
+ States.size(), Attr.getAttributeSpellingListIndex()));
+}
+
+
+static void handleParamTypestateAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1)) return;
+
+ if (!isa<ParmVarDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedParameter;
+ return;
+ }
+
+ ParamTypestateAttr::ConsumedState ParamState;
+
+ if (Attr.isArgIdent(0)) {
+ IdentifierLoc *Ident = Attr.getArgAsIdent(0);
+ StringRef StateString = Ident->Ident->getName();
+
+ if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString,
+ ParamState)) {
+ S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << StateString;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+ Attr.getName() << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ // FIXME: This check is currently being done in the analysis. It can be
+ // enabled here only after the parser propagates attributes at
+ // template specialization definition, not declaration.
+ //QualType ReturnType = cast<ParmVarDecl>(D)->getType();
+ //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
+ //
+ //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
+ // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
+ // ReturnType.getAsString();
+ // return;
+ //}
+
+ D->addAttr(::new (S.Context)
+ ParamTypestateAttr(Attr.getRange(), S.Context, ParamState,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+
+static void handleReturnTypestateAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1)) return;
+
+ if (!(isa<FunctionDecl>(D) || isa<ParmVarDecl>(D))) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedFunctionMethodOrParameter;
+ return;
+ }
+
+ ReturnTypestateAttr::ConsumedState ReturnState;
+
+ if (Attr.isArgIdent(0)) {
+ IdentifierLoc *IL = Attr.getArgAsIdent(0);
+ if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(),
+ ReturnState)) {
+ S.Diag(IL->Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << IL->Ident;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+ Attr.getName() << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ // FIXME: This check is currently being done in the analysis. It can be
+ // enabled here only after the parser propagates attributes at
+ // template specialization definition, not declaration.
+ //QualType ReturnType;
+ //
+ //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
+ // ReturnType = Param->getType();
+ //
+ //} else if (const CXXConstructorDecl *Constructor =
+ // dyn_cast<CXXConstructorDecl>(D)) {
+ // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType();
+ //
+ //} else {
+ //
+ // ReturnType = cast<FunctionDecl>(D)->getCallResultType();
+ //}
+ //
+ //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
+ //
+ //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
+ // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
+ // ReturnType.getAsString();
+ // return;
+ //}
+
+ D->addAttr(::new (S.Context)
+ ReturnTypestateAttr(Attr.getRange(), S.Context, ReturnState,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+
+static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ if (!isa<CXXMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedMethod;
+ return;
+ }
+
+ if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
+ return;
+
+ SetTypestateAttr::ConsumedState NewState;
+ if (Attr.isArgIdent(0)) {
+ IdentifierLoc *Ident = Attr.getArgAsIdent(0);
+ StringRef Param = Ident->Ident->getName();
+ if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) {
+ S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << Param;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+ Attr.getName() << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ SetTypestateAttr(Attr.getRange(), S.Context, NewState,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleTestTypestateAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ if (!isa<CXXMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ Attr.getName() << ExpectedMethod;
+ return;
+ }
+
+ if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
+ return;
+
+ TestTypestateAttr::ConsumedState TestState;
+ if (Attr.isArgIdent(0)) {
+ IdentifierLoc *Ident = Attr.getArgAsIdent(0);
+ StringRef Param = Ident->Ident->getName();
+ if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) {
+ S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << Param;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) <<
+ Attr.getName() << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ TestTypestateAttr(Attr.getRange(), S.Context, TestState,
+ Attr.getAttributeSpellingListIndex()));
+}
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
@@ -980,10 +1258,6 @@ static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
}
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
@@ -1012,10 +1286,6 @@ static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
// The IBAction attributes only apply to instance methods.
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
if (MD->isInstanceMethod()) {
@@ -1055,10 +1325,6 @@ static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!checkIBOutletCommon(S, D, Attr))
return;
@@ -1071,36 +1337,46 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
const AttributeList &Attr) {
// The iboutletcollection attribute can have zero or one arguments.
- if (Attr.getParameterName() && Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
return;
}
if (!checkIBOutletCommon(S, D, Attr))
return;
- IdentifierInfo *II = Attr.getParameterName();
- if (!II)
- II = &S.Context.Idents.get("NSObject");
-
- ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(),
- S.getScopeForContext(D->getDeclContext()->getParent()));
- if (!TypeRep) {
- S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
- return;
+ ParsedType PT;
+
+ if (Attr.hasParsedType())
+ PT = Attr.getTypeArg();
+ else {
+ PT = S.getTypeName(S.Context.Idents.get("NSObject"), Attr.getLoc(),
+ S.getScopeForContext(D->getDeclContext()->getParent()));
+ if (!PT) {
+ S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
+ return;
+ }
}
- QualType QT = TypeRep.get();
+
+ TypeSourceInfo *QTLoc = 0;
+ QualType QT = S.GetTypeFromParser(PT, &QTLoc);
+ if (!QTLoc)
+ QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc());
+
// Diagnose use of non-object type in iboutletcollection attribute.
// FIXME. Gnu attribute extension ignores use of builtin types in
// attributes. So, __attribute__((iboutletcollection(char))) will be
// treated as __attribute__((iboutletcollection())).
if (!QT->isObjCIdType() && !QT->isObjCObjectType()) {
- S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
+ S.Diag(Attr.getLoc(),
+ QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype
+ : diag::err_iboutletcollection_type) << QT;
return;
}
+
D->addAttr(::new (S.Context)
- IBOutletCollectionAttr(Attr.getRange(),S.Context,
- QT, Attr.getParameterLoc(),
+ IBOutletCollectionAttr(Attr.getRange(), S.Context, QTLoc,
Attr.getAttributeSpellingListIndex()));
}
@@ -1122,70 +1398,36 @@ static void possibleTransparentUnionPointerType(QualType &T) {
static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << "alloc_size" << ExpectedFunctionOrMethod;
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- // In C++ the implicit 'this' function parameter also counts, and they are
- // counted from one.
- bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs;
- if (hasFunctionProto(D))
- NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
- else
- NumArgs = 0;
-
SmallVector<unsigned, 8> SizeArgs;
-
- for (AttributeList::arg_iterator I = Attr.arg_begin(),
- E = Attr.arg_end(); I!=E; ++I) {
- // The argument must be an integer constant expression.
- Expr *Ex = *I;
- llvm::APSInt ArgNum;
- if (Ex->isTypeDependent() || Ex->isValueDependent() ||
- !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "alloc_size" << Ex->getSourceRange();
- return;
- }
-
- uint64_t x = ArgNum.getZExtValue();
-
- if (x < 1 || x > NumArgs) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "alloc_size" << I.getArgNum() << Ex->getSourceRange();
+ for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
+ Expr *Ex = Attr.getArgAsExpr(i);
+ uint64_t Idx;
+ if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
+ Attr.getLoc(), i + 1, Ex, Idx))
return;
- }
-
- --x;
- if (HasImplicitThisParam) {
- if (x == 0) {
- S.Diag(Attr.getLoc(),
- diag::err_attribute_invalid_implicit_this_argument)
- << "alloc_size" << Ex->getSourceRange();
- return;
- }
- --x;
- }
// check if the function argument is of an integer type
- QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
if (!T->isIntegerType()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "alloc_size" << Ex->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << Ex->getSourceRange();
return;
}
-
- SizeArgs.push_back(x);
+ SizeArgs.push_back(Idx);
}
// check if the function returns a pointer
if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
- << "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
+ << Attr.getName() << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
}
D->addAttr(::new (S.Context)
@@ -1203,47 +1445,16 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // In C++ the implicit 'this' function parameter also counts, and they are
- // counted from one.
- bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
-
- // The nonnull attribute only applies to pointers.
- SmallVector<unsigned, 10> NonNullArgs;
-
- for (AttributeList::arg_iterator I = Attr.arg_begin(),
- E = Attr.arg_end(); I != E; ++I) {
- // The argument must be an integer constant expression.
- Expr *Ex = *I;
- llvm::APSInt ArgNum(32);
- if (Ex->isTypeDependent() || Ex->isValueDependent() ||
- !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "nonnull" << Ex->getSourceRange();
+ SmallVector<unsigned, 8> NonNullArgs;
+ for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
+ Expr *Ex = Attr.getArgAsExpr(i);
+ uint64_t Idx;
+ if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
+ Attr.getLoc(), i + 1, Ex, Idx))
return;
- }
-
- unsigned x = (unsigned) ArgNum.getZExtValue();
-
- if (x < 1 || x > NumArgs) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "nonnull" << I.getArgNum() << Ex->getSourceRange();
- return;
- }
-
- --x;
- if (HasImplicitThisParam) {
- if (x == 0) {
- S.Diag(Attr.getLoc(),
- diag::err_attribute_invalid_implicit_this_argument)
- << "nonnull" << Ex->getSourceRange();
- return;
- }
- --x;
- }
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
possibleTransparentUnionPointerType(T);
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
@@ -1253,7 +1464,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
continue;
}
- NonNullArgs.push_back(x);
+ NonNullArgs.push_back(Idx);
}
// If no arguments were specified to __attribute__((nonnull)) then all pointer
@@ -1284,43 +1495,52 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static const char *ownershipKindToDiagName(OwnershipAttr::OwnershipKind K) {
+ switch (K) {
+ case OwnershipAttr::Holds: return "'ownership_holds'";
+ case OwnershipAttr::Takes: return "'ownership_takes'";
+ case OwnershipAttr::Returns: return "'ownership_returns'";
+ }
+ llvm_unreachable("unknown ownership");
+}
+
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
- // This attribute must be applied to a function declaration.
- // The first argument to the attribute must be a string,
- // the name of the resource, for example "malloc".
- // The following arguments must be argument indexes, the arguments must be
- // of integer type for Returns, otherwise of pointer type.
+ // This attribute must be applied to a function declaration. The first
+ // argument to the attribute must be an identifier, the name of the resource,
+ // for example: malloc. The following arguments must be argument indexes, the
+ // arguments must be of integer type for Returns, otherwise of pointer type.
// The difference between Holds and Takes is that a pointer may still be used
- // after being held. free() should be __attribute((ownership_takes)), whereas
+ // after being held. free() should be __attribute((ownership_takes)), whereas
// a list append function may well be __attribute((ownership_holds)).
- if (!AL.getParameterName()) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_not_string)
- << AL.getName()->getName() << 1;
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
+
// Figure out our Kind, and check arguments while we're at it.
OwnershipAttr::OwnershipKind K;
switch (AL.getKind()) {
case AttributeList::AT_ownership_takes:
K = OwnershipAttr::Takes;
- if (AL.getNumArgs() < 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
+ if (AL.getNumArgs() < 2) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
return;
}
break;
case AttributeList::AT_ownership_holds:
K = OwnershipAttr::Holds;
- if (AL.getNumArgs() < 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
+ if (AL.getNumArgs() < 2) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
return;
}
break;
case AttributeList::AT_ownership_returns:
K = OwnershipAttr::Returns;
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL.getNumArgs() + 1;
+
+ if (AL.getNumArgs() > 2) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
break;
@@ -1335,107 +1555,58 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
return;
}
- // In C++ the implicit 'this' function parameter also counts, and they are
- // counted from one.
- bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
-
- StringRef Module = AL.getParameterName()->getName();
+ StringRef Module = AL.getArgAsIdent(0)->Ident->getName();
// Normalize the argument, __foo__ becomes foo.
if (Module.startswith("__") && Module.endswith("__"))
Module = Module.substr(2, Module.size() - 4);
- SmallVector<unsigned, 10> OwnershipArgs;
-
- for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E;
- ++I) {
-
- Expr *IdxExpr = *I;
- llvm::APSInt ArgNum(32);
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
- || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_not_int)
- << AL.getName()->getName() << IdxExpr->getSourceRange();
- continue;
- }
-
- unsigned x = (unsigned) ArgNum.getZExtValue();
-
- if (x > NumArgs || x < 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL.getName()->getName() << x << IdxExpr->getSourceRange();
- continue;
- }
- --x;
- if (HasImplicitThisParam) {
- if (x == 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
- << "ownership" << IdxExpr->getSourceRange();
- return;
- }
- --x;
- }
+ SmallVector<unsigned, 8> OwnershipArgs;
+ for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
+ Expr *Ex = AL.getArgAsExpr(i);
+ uint64_t Idx;
+ if (!checkFunctionOrMethodArgumentIndex(S, D, AL.getName()->getName(),
+ AL.getLoc(), i, Ex, Idx))
+ return;
+ // Is the function argument a pointer type?
+ QualType T = getFunctionOrMethodArgType(D, Idx);
+ int Err = -1; // No error
switch (K) {
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds: {
- // Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(D, x);
- if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
- // FIXME: Should also highlight argument in decl.
- S.Diag(AL.getLoc(), diag::err_ownership_type)
- << ((K==OwnershipAttr::Takes)?"ownership_takes":"ownership_holds")
- << "pointer"
- << IdxExpr->getSourceRange();
- continue;
- }
- break;
+ case OwnershipAttr::Takes:
+ case OwnershipAttr::Holds:
+ if (!T->isAnyPointerType() && !T->isBlockPointerType())
+ Err = 0;
+ break;
+ case OwnershipAttr::Returns:
+ if (!T->isIntegerType())
+ Err = 1;
+ break;
}
- case OwnershipAttr::Returns: {
- if (AL.getNumArgs() > 1) {
- // Is the function argument an integer type?
- Expr *IdxExpr = AL.getArg(0);
- llvm::APSInt ArgNum(32);
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
- || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_ownership_type)
- << "ownership_returns" << "integer"
- << IdxExpr->getSourceRange();
- return;
- }
- }
- break;
+ if (-1 != Err) {
+ S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err
+ << Ex->getSourceRange();
+ return;
}
- } // switch
// Check we don't have a conflict with another ownership attribute.
for (specific_attr_iterator<OwnershipAttr>
- i = D->specific_attr_begin<OwnershipAttr>(),
- e = D->specific_attr_end<OwnershipAttr>();
- i != e; ++i) {
- if ((*i)->getOwnKind() != K) {
- for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end();
- I!=E; ++I) {
- if (x == *I) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL.getName()->getName() << "ownership_*";
- }
- }
+ i = D->specific_attr_begin<OwnershipAttr>(),
+ e = D->specific_attr_end<OwnershipAttr>(); i != e; ++i) {
+ if ((*i)->getOwnKind() != K && (*i)->args_end() !=
+ std::find((*i)->args_begin(), (*i)->args_end(), Idx)) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL.getName() << ownershipKindToDiagName((*i)->getOwnKind());
+ return;
}
}
- OwnershipArgs.push_back(x);
+ OwnershipArgs.push_back(Idx);
}
unsigned* start = OwnershipArgs.data();
unsigned size = OwnershipArgs.size();
llvm::array_pod_sort(start, start + size);
- if (K != OwnershipAttr::Returns && OwnershipArgs.empty()) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
- return;
- }
-
D->addAttr(::new (S.Context)
OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size,
AL.getAttributeSpellingListIndex()));
@@ -1444,7 +1615,8 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.getNumArgs() > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
return;
}
@@ -1495,21 +1667,15 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// static ((alias ("y"), weakref)).
// Should we? How to check that weakref is before or after alias?
- if (Attr.getNumArgs() == 1) {
- Expr *Arg = Attr.getArg(0);
- Arg = Arg->IgnoreParenCasts();
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
- if (!Str || !Str->isAscii()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "weakref" << 1;
- return;
- }
+ // FIXME: it would be good for us to keep the WeakRefAttr as-written instead
+ // of transforming it into an AliasAttr. The WeakRefAttr never uses the
+ // StringRef parameter it was given anyway.
+ StringRef Str;
+ if (Attr.getNumArgs() && S.checkStringLiteralArgumentAttr(Attr, 0, Str))
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
- Str->getString()));
- }
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
D->addAttr(::new (S.Context)
WeakRefAttr(Attr.getRange(), S.Context,
@@ -1517,21 +1683,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
- Expr *Arg = Attr.getArg(0);
- Arg = Arg->IgnoreParenCasts();
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
- if (!Str || !Str->isAscii()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "alias" << 1;
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
return;
- }
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin);
@@ -1540,16 +1694,11 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: check if target symbol exists in current file
- D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
- Str->getString(),
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str,
Attr.getAttributeSpellingListIndex()));
}
static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
@@ -1562,10 +1711,6 @@ static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -1583,10 +1728,6 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -1604,10 +1745,6 @@ static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -1621,12 +1758,6 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // Check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -1640,21 +1771,11 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
static void handleTLSModelAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
- Expr *Arg = Attr.getArg(0);
- Arg = Arg->IgnoreParenCasts();
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
+ StringRef Model;
+ SourceLocation LiteralLoc;
// Check that it is a string.
- if (!Str) {
- S.Diag(Attr.getLoc(), diag::err_attribute_not_string) << "tls_model";
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc))
return;
- }
if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
@@ -1663,10 +1784,9 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
}
// Check that the value.
- StringRef Model = Str->getString();
if (Model != "global-dynamic" && Model != "local-dynamic"
&& Model != "initial-exec" && Model != "local-exec") {
- S.Diag(Attr.getLoc(), diag::err_attr_tlsmodel_arg);
+ S.Diag(LiteralLoc, diag::err_attr_tlsmodel_arg);
return;
}
@@ -1676,12 +1796,6 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
}
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
@@ -1696,17 +1810,12 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
MayAliasAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
D->addAttr(::new (S.Context)
NoCommonAttr(Attr.getRange(), S.Context,
@@ -1717,7 +1826,11 @@ static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- assert(!Attr.isInvalid());
+ if (S.LangOpts.CPlusPlus) {
+ S.Diag(Attr.getLoc(), diag::err_common_not_supported_cplusplus);
+ return;
+ }
+
if (isa<VarDecl>(D))
D->addAttr(::new (S.Context)
CommonAttr(Attr.getRange(), S.Context,
@@ -1744,8 +1857,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
- if (attr.hasParameterOrArguments()) {
- Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(*this, attr, 0)) {
attr.setInvalid();
return true;
}
@@ -1758,10 +1870,6 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
-
- if(!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (VD == 0 || (!VD->getType()->isBlockPointerType()
@@ -1881,12 +1989,6 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
}
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
!isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1901,12 +2003,6 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleReturnsTwiceAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -1919,14 +2015,8 @@ static void handleReturnsTwiceAttr(Sema &S, Decl *D,
}
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
+ if (VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
return;
}
@@ -1950,12 +2040,13 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
- Expr *E = Attr.getArg(0);
+ Expr *E = Attr.getArgAsExpr(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "constructor" << 1 << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
priority = Idx.getZExtValue();
@@ -1981,12 +2072,13 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
- Expr *E = Attr.getArg(0);
+ Expr *E = Attr.getArgAsExpr(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "destructor" << 1 << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
priority = Idx.getZExtValue();
@@ -2004,8 +2096,8 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
template <typename AttrTy>
-static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
- const char *Name) {
+static void handleAttrWithMessage(Sema &S, Decl *D,
+ const AttributeList &Attr) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -2014,15 +2106,8 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
// Handle the case where the attribute has a text message.
StringRef Str;
- if (NumArgs == 1) {
- StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
- if (!SE) {
- S.Diag(Attr.getArg(0)->getLocStart(), diag::err_attribute_not_string)
- << Name;
- return;
- }
- Str = SE->getString();
- }
+ if (NumArgs == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ return;
D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str,
Attr.getAttributeSpellingListIndex()));
@@ -2030,12 +2115,6 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
- return;
- }
-
D->addAttr(::new (S.Context)
ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
@@ -2044,13 +2123,8 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
static void handleObjCRootClassAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!isa<ObjCInterfaceDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
- return;
- }
-
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedObjectiveCInterface;
return;
}
@@ -2066,12 +2140,6 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
return;
}
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
- return;
- }
-
D->addAttr(::new (S.Context)
ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
@@ -2261,13 +2329,15 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
static void handleAvailabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- IdentifierInfo *Platform = Attr.getParameterName();
- SourceLocation PlatformLoc = Attr.getParameterLoc();
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+ IdentifierLoc *Platform = Attr.getArgAsIdent(0);
unsigned Index = Attr.getAttributeSpellingListIndex();
- if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
- S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
- << Platform;
+ IdentifierInfo *II = Platform->Ident;
+ if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
+ S.Diag(Platform->Loc, diag::warn_availability_unknown_platform)
+ << Platform->Ident;
NamedDecl *ND = dyn_cast<NamedDecl>(D);
if (!ND) {
@@ -2280,13 +2350,11 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
bool IsUnavailable = Attr.getUnavailableLoc().isValid();
StringRef Str;
- const StringLiteral *SE =
- dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
- if (SE)
+ if (const StringLiteral *SE =
+ dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr()))
Str = SE->getString();
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(),
- Platform,
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
@@ -2346,41 +2414,25 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
return;
}
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
+ // Check that the argument is a string literal.
+ StringRef TypeStr;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, TypeStr, &LiteralLoc))
return;
- Expr *Arg = Attr.getArg(0);
- Arg = Arg->IgnoreParenCasts();
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
- if (!Str || !Str->isAscii()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
+ VisibilityAttr::VisibilityType type;
+ if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) {
+ S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
+ << Attr.getName() << TypeStr;
return;
}
-
- StringRef TypeStr = Str->getString();
- VisibilityAttr::VisibilityType type;
- if (TypeStr == "default")
+ // Complain about attempts to use protected visibility on targets
+ // (like Darwin) that don't support it.
+ if (type == VisibilityAttr::Protected &&
+ !S.Context.getTargetInfo().hasProtectedVisibility()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility);
type = VisibilityAttr::Default;
- else if (TypeStr == "hidden")
- type = VisibilityAttr::Hidden;
- else if (TypeStr == "internal")
- type = VisibilityAttr::Hidden; // FIXME
- else if (TypeStr == "protected") {
- // Complain about attempts to use protected visibility on targets
- // (like Darwin) that don't support it.
- if (!S.Context.getTargetInfo().hasProtectedVisibility()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility);
- type = VisibilityAttr::Default;
- } else {
- type = VisibilityAttr::Protected;
- }
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
- return;
}
unsigned Index = Attr.getAttributeSpellingListIndex();
@@ -2405,39 +2457,21 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
return;
}
- if (Attr.getNumArgs() != 0 || !Attr.getParameterName()) {
- if (!Attr.getParameterName() && Attr.getNumArgs() == 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "objc_method_family" << 1;
- } else {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- }
- Attr.setInvalid();
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
- StringRef param = Attr.getParameterName()->getName();
- ObjCMethodFamilyAttr::FamilyKind family;
- if (param == "none")
- family = ObjCMethodFamilyAttr::OMF_None;
- else if (param == "alloc")
- family = ObjCMethodFamilyAttr::OMF_alloc;
- else if (param == "copy")
- family = ObjCMethodFamilyAttr::OMF_copy;
- else if (param == "init")
- family = ObjCMethodFamilyAttr::OMF_init;
- else if (param == "mutableCopy")
- family = ObjCMethodFamilyAttr::OMF_mutableCopy;
- else if (param == "new")
- family = ObjCMethodFamilyAttr::OMF_new;
- else {
- // Just warn and ignore it. This is future-proof against new
- // families being used in system headers.
- S.Diag(Attr.getParameterLoc(), diag::warn_unknown_method_family);
+ IdentifierLoc *IL = Attr.getArgAsIdent(0);
+ ObjCMethodFamilyAttr::FamilyKind F;
+ if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) {
+ S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << Attr.getName()
+ << IL->Ident;
return;
}
- if (family == ObjCMethodFamilyAttr::OMF_init &&
+ if (F == ObjCMethodFamilyAttr::OMF_init &&
!method->getResultType()->isObjCObjectPointerType()) {
S.Diag(method->getLocation(), diag::err_init_method_bad_return_type)
<< method->getResultType();
@@ -2446,17 +2480,15 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
}
method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(),
- S.Context, family));
+ S.Context, F));
}
static void handleObjCExceptionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
if (OCI == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedObjectiveCInterface;
return;
}
@@ -2466,10 +2498,6 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D,
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isCARCBridgableType()) {
@@ -2500,11 +2528,6 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
static void
handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
return;
@@ -2516,23 +2539,17 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!Attr.getParameterName()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "blocks" << 1;
- return;
- }
-
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
+ IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
BlocksAttr::BlockType type;
- if (Attr.getParameterName()->isStr("byref"))
- type = BlocksAttr::ByRef;
- else {
+ if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
- << "blocks" << Attr.getParameterName();
+ << Attr.getName() << II;
return;
}
@@ -2550,12 +2567,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned sentinel = 0;
if (Attr.getNumArgs() > 0) {
- Expr *E = Attr.getArg(0);
+ Expr *E = Attr.getArgAsExpr(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "sentinel" << 1 << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
@@ -2570,12 +2588,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned nullPos = 0;
if (Attr.getNumArgs() > 1) {
- Expr *E = Attr.getArg(1);
+ Expr *E = Attr.getArgAsExpr(1);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "sentinel" << 2 << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 2 << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
nullPos = Idx.getZExtValue();
@@ -2635,11 +2654,14 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
+static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrClass;
@@ -2664,12 +2686,6 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
}
static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
if (isa<CXXRecordDecl>(D)) {
D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
@@ -2688,18 +2704,12 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
// weak_import only applies to variable & function declarations.
bool isDef = false;
if (!D->canBeWeakImported(isDef)) {
if (isDef)
- S.Diag(Attr.getLoc(),
- diag::warn_attribute_weak_import_invalid_on_definition)
- << "weak_import" << 2 /*variable and function*/;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_invalid_on_definition)
+ << "weak_import";
else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
(S.Context.getTargetInfo().getTriple().isOSDarwin() &&
(isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) {
@@ -2719,20 +2729,15 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Handles reqd_work_group_size and work_group_size_hint.
static void handleWorkGroupSize(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
- || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
-
- // Attribute has 3 arguments.
- if (!checkAttributeNumArgs(S, Attr, 3)) return;
-
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
- Expr *E = Attr.getArg(i);
+ Expr *E = Attr.getArgAsExpr(i);
llvm::APSInt ArgNum(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << Attr.getName()->getName() << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
WGSize[i] = (unsigned) ArgNum.getZExtValue();
@@ -2775,11 +2780,15 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
assert(Attr.getKind() == AttributeList::AT_VecTypeHint);
- // Attribute has 1 argument.
- if (!checkAttributeNumArgs(S, Attr, 1))
+ if (!Attr.hasParsedType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
return;
+ }
- QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg());
+ TypeSourceInfo *ParmTSI = 0;
+ QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI);
+ assert(ParmTSI && "no type source info for attribute argument");
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
@@ -2792,23 +2801,14 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
D->hasAttr<VecTypeHintAttr>()) {
VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
- if (A->getTypeHint() != ParmType) {
+ if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) {
S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
return;
}
}
D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
- ParmType, Attr.getLoc()));
-}
-
-static void handleEndianAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!dyn_cast<VarDecl>(D))
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "endian"
- << 9;
- StringRef EndianType = Attr.getParameterName()->getName();
- if (EndianType != "host" && EndianType != "device")
- S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_endian) << EndianType;
+ ParmTSI));
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
@@ -2826,48 +2826,35 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Attribute has no arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
// Make sure that there is a string literal as the sections's single
// argument.
- Expr *ArgExpr = Attr.getArg(0);
- StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
- if (!SE) {
- S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
return;
- }
// If the target wants to validate the section specifier, make it happen.
- std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(SE->getString());
+ std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str);
if (!Error.empty()) {
- S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
<< Error;
return;
}
// This attribute cannot be applied to local variables.
if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) {
- S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
+ S.Diag(LiteralLoc, diag::err_attribute_section_local_variable);
return;
}
unsigned Index = Attr.getAttributeSpellingListIndex();
- SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(),
- SE->getString(), Index);
+ SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index);
if (NewAttr)
D->addAttr(NewAttr);
}
static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
@@ -2879,12 +2866,6 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
@@ -2896,56 +2877,55 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
PureAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!Attr.getParameterName()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
VarDecl *VD = dyn_cast<VarDecl>(D);
-
if (!VD || !VD->hasLocalStorage()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
- // Look up the function
- // FIXME: Lookup probably isn't looking in the right place
- NamedDecl *CleanupDecl
- = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
- Attr.getParameterLoc(), Sema::LookupOrdinaryName);
- if (!CleanupDecl) {
- S.Diag(Attr.getParameterLoc(), diag::err_attribute_cleanup_arg_not_found) <<
- Attr.getParameterName();
- return;
- }
+ Expr *E = Attr.getArgAsExpr(0);
+ SourceLocation Loc = E->getExprLoc();
+ FunctionDecl *FD = 0;
+ DeclarationNameInfo NI;
- FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
- if (!FD) {
- S.Diag(Attr.getParameterLoc(),
- diag::err_attribute_cleanup_arg_not_function)
- << Attr.getParameterName();
+ // gcc only allows for simple identifiers. Since we support more than gcc, we
+ // will warn the user.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (DRE->hasQualifier())
+ S.Diag(Loc, diag::warn_cleanup_ext);
+ FD = dyn_cast<FunctionDecl>(DRE->getDecl());
+ NI = DRE->getNameInfo();
+ if (!FD) {
+ S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1
+ << NI.getName();
+ return;
+ }
+ } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+ if (ULE->hasExplicitTemplateArgs())
+ S.Diag(Loc, diag::warn_cleanup_ext);
+ FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
+ NI = ULE->getNameInfo();
+ if (!FD) {
+ S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2
+ << NI.getName();
+ if (ULE->getType() == S.Context.OverloadTy)
+ S.NoteAllOverloadCandidates(ULE);
+ return;
+ }
+ } else {
+ S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 0;
return;
}
if (FD->getNumParams() != 1) {
- S.Diag(Attr.getParameterLoc(),
- diag::err_attribute_cleanup_func_must_take_one_arg)
- << Attr.getParameterName();
+ S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg)
+ << NI.getName();
return;
}
@@ -2955,63 +2935,30 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
QualType ParamTy = FD->getParamDecl(0)->getType();
if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
ParamTy, Ty) != Sema::Compatible) {
- S.Diag(Attr.getParameterLoc(),
- diag::err_attribute_cleanup_func_arg_incompatible_type) <<
- Attr.getParameterName() << ParamTy << Ty;
+ S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type)
+ << NI.getName() << ParamTy << Ty;
return;
}
D->addAttr(::new (S.Context)
CleanupAttr(Attr.getRange(), S.Context, FD,
Attr.getAttributeSpellingListIndex()));
- S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
- S.DiagnoseUseOfDecl(FD, Attr.getParameterLoc());
}
/// 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) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- // In C++ the implicit 'this' function parameter also counts, and they are
- // counted from one.
- bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
- unsigned FirstIdx = 1;
-
- // checks for the 2nd argument
- Expr *IdxExpr = Attr.getArg(0);
- llvm::APSInt Idx(32);
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
- !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "format" << 2 << IdxExpr->getSourceRange();
- return;
- }
-
- if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "format" << 2 << IdxExpr->getSourceRange();
+ Expr *IdxExpr = Attr.getArgAsExpr(0);
+ uint64_t ArgIdx;
+ if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
+ Attr.getLoc(), 1, IdxExpr, ArgIdx))
return;
- }
-
- unsigned ArgIdx = Idx.getZExtValue() - 1;
-
- if (HasImplicitThisParam) {
- if (ArgIdx == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
- << "format_arg" << IdxExpr->getSourceRange();
- return;
- }
- ArgIdx--;
- }
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
@@ -3039,8 +2986,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
+ // We cannot use the ArgIdx returned from checkFunctionOrMethodArgumentIndex
+ // because that has corrected for the implicit this parameter, and is zero-
+ // based. The attribute expects what the user wrote explicitly.
+ llvm::APSInt Val;
+ IdxExpr->EvaluateAsInt(Val, S.Context);
+
D->addAttr(::new (S.Context)
- FormatArgAttr(Attr.getRange(), S.Context, Idx.getZExtValue(),
+ FormatArgAttr(Attr.getRange(), S.Context, Val.getZExtValue(),
Attr.getAttributeSpellingListIndex()));
}
@@ -3094,18 +3047,14 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
return;
}
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- Attr.setInvalid();
- return;
- }
- Expr *priorityExpr = Attr.getArg(0);
+ Expr *priorityExpr = Attr.getArgAsExpr(0);
llvm::APSInt priority(32);
if (priorityExpr->isTypeDependent() || priorityExpr->isValueDependent() ||
!priorityExpr->isIntegerConstantExpr(priority, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "init_priority" << priorityExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << priorityExpr->getSourceRange();
Attr.setInvalid();
return;
}
@@ -3121,8 +3070,9 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
- int FormatIdx, int FirstArg,
+FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Format, int FormatIdx,
+ int FirstArg,
unsigned AttrSpellingListIndex) {
// Check whether we already have an equivalent format attribute.
for (specific_attr_iterator<FormatAttr>
@@ -3141,22 +3091,16 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
}
}
- return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx, FirstArg,
- AttrSpellingListIndex);
+ return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
+ FirstArg, AttrSpellingListIndex);
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-
- if (!Attr.getParameterName()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "format" << 1;
- return;
- }
-
- if (Attr.getNumArgs() != 2) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 3;
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
@@ -3172,11 +3116,15 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
- StringRef Format = Attr.getParameterName()->getName();
+ IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
+ StringRef Format = II->getName();
// Normalize the argument, __foo__ becomes foo.
- if (Format.startswith("__") && Format.endswith("__"))
+ if (Format.startswith("__") && Format.endswith("__")) {
Format = Format.substr(2, Format.size() - 4);
+ // If we've modified the string name, we need a new identifier for it.
+ II = &S.Context.Idents.get(Format);
+ }
// Check for supported formats.
FormatAttrKind Kind = getFormatAttrKind(Format);
@@ -3186,17 +3134,18 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Kind == InvalidFormat) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
- << "format" << Attr.getParameterName()->getName();
+ << "format" << II->getName();
return;
}
// checks for the 2nd argument
- Expr *IdxExpr = Attr.getArg(0);
+ Expr *IdxExpr = Attr.getArgAsExpr(1);
llvm::APSInt Idx(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "format" << 2 << IdxExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 2 << AANT_ArgumentIntegerConstant
+ << IdxExpr->getSourceRange();
return;
}
@@ -3246,12 +3195,13 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// check the 3rd argument
- Expr *FirstArgExpr = Attr.getArg(1);
+ Expr *FirstArgExpr = Attr.getArgAsExpr(2);
llvm::APSInt FirstArg(32);
if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "format" << 3 << FirstArgExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 3 << AANT_ArgumentIntegerConstant
+ << FirstArgExpr->getSourceRange();
return;
}
@@ -3280,7 +3230,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), Format,
+ FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II,
Idx.getZExtValue(),
FirstArg.getZExtValue(),
Attr.getAttributeSpellingListIndex());
@@ -3290,11 +3240,6 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleTransparentUnionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
// Try to find the underlying union declaration.
RecordDecl *RD = 0;
TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
@@ -3358,37 +3303,30 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
}
static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
- Expr *ArgExpr = Attr.getArg(0);
- StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
-
// Make sure that there is a string literal as the annotation's single
// argument.
- if (!SE) {
- S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
return;
- }
// Don't duplicate annotations that are already set.
for (specific_attr_iterator<AnnotateAttr>
i = D->specific_attr_begin<AnnotateAttr>(),
e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) {
- if ((*i)->getAnnotation() == SE->getString())
- return;
+ if ((*i)->getAnnotation() == Str)
+ return;
}
D->addAttr(::new (S.Context)
- AnnotateAttr(Attr.getRange(), S.Context, SE->getString(),
+ AnnotateAttr(Attr.getRange(), S.Context, Str,
Attr.getAttributeSpellingListIndex()));
}
static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
return;
}
@@ -3398,7 +3336,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- Expr *E = Attr.getArg(0);
+ Expr *E = Attr.getArgAsExpr(0);
if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
S.Diag(Attr.getEllipsisLoc(),
diag::err_pack_expansion_without_parameter_packs);
@@ -3555,19 +3493,14 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// This attribute isn't documented, but glibc uses it. It changes
// the width of an int or unsigned int to the specified size.
-
- // Check that there aren't any arguments
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
- IdentifierInfo *Name = Attr.getParameterName();
- if (!Name) {
- S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name);
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
+ << AANT_ArgumentIdentifier;
return;
}
-
- StringRef Str = Attr.getParameterName()->getName();
+
+ IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
+ StringRef Str = Name->getName();
// Normalize the attribute name, __foo__ becomes foo.
if (Str.startswith("__") && Str.endswith("__"))
@@ -3639,73 +3572,24 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
// and friends, at least with glibc.
- // FIXME: Make sure 32/64-bit integers don't get defined to types of the wrong
- // width on unusual platforms.
// FIXME: Make sure floating-point mappings are accurate
// FIXME: Support XF and TF types
- QualType NewTy;
- switch (DestWidth) {
- case 0:
+ if (!DestWidth) {
S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name;
return;
- default:
+ }
+
+ QualType NewTy;
+
+ if (IntegerMode)
+ NewTy = S.Context.getIntTypeForBitwidth(DestWidth,
+ OldTy->isSignedIntegerType());
+ else
+ NewTy = S.Context.getRealTypeForBitwidth(DestWidth);
+
+ if (NewTy.isNull()) {
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
return;
- case 8:
- if (!IntegerMode) {
- S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
- return;
- }
- if (OldTy->isSignedIntegerType())
- NewTy = S.Context.SignedCharTy;
- else
- NewTy = S.Context.UnsignedCharTy;
- break;
- case 16:
- if (!IntegerMode) {
- S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
- return;
- }
- if (OldTy->isSignedIntegerType())
- NewTy = S.Context.ShortTy;
- else
- NewTy = S.Context.UnsignedShortTy;
- break;
- case 32:
- if (!IntegerMode)
- NewTy = S.Context.FloatTy;
- else if (OldTy->isSignedIntegerType())
- NewTy = S.Context.IntTy;
- else
- NewTy = S.Context.UnsignedIntTy;
- break;
- case 64:
- if (!IntegerMode)
- NewTy = S.Context.DoubleTy;
- else if (OldTy->isSignedIntegerType())
- if (S.Context.getTargetInfo().getLongWidth() == 64)
- NewTy = S.Context.LongTy;
- else
- NewTy = S.Context.LongLongTy;
- else
- if (S.Context.getTargetInfo().getLongWidth() == 64)
- NewTy = S.Context.UnsignedLongTy;
- else
- NewTy = S.Context.UnsignedLongLongTy;
- break;
- case 96:
- NewTy = S.Context.LongDoubleTy;
- break;
- case 128:
- if (!IntegerMode) {
- S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
- return;
- }
- if (OldTy->isSignedIntegerType())
- NewTy = S.Context.Int128Ty;
- else
- NewTy = S.Context.UnsignedInt128Ty;
- break;
}
if (ComplexMode) {
@@ -3713,18 +3597,17 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// Install the new type.
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- // FIXME: preserve existing source info.
- TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy));
- } else
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy);
+ else
cast<ValueDecl>(D)->setType(NewTy);
+
+ D->addAttr(::new (S.Context)
+ ModeAttr(Attr.getRange(), S.Context, Name,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->hasGlobalStorage())
S.Diag(Attr.getLoc(),
@@ -3743,11 +3626,6 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -3761,11 +3639,6 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -3779,12 +3652,6 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -3803,7 +3670,8 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
@@ -3823,10 +3691,6 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -3858,11 +3722,6 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -3879,10 +3738,6 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -3898,10 +3753,6 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -3961,6 +3812,16 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
PascalAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
+ case AttributeList::AT_MSABI:
+ D->addAttr(::new (S.Context)
+ MSABIAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
+ case AttributeList::AT_SysVABI:
+ D->addAttr(::new (S.Context)
+ SysVABIAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
case AttributeList::AT_Pcs: {
PcsAttr::PCSType PCS;
switch (CC) {
@@ -3996,19 +3857,17 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
- assert(!Attr.isInvalid());
D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
}
static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){
- assert(!Attr.isInvalid());
-
- Expr *E = Attr.getArg(0);
+ Expr *E = Attr.getArgAsExpr(0);
llvm::APSInt ArgNum(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << Attr.getName()->getName() << E->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
return;
}
@@ -4022,8 +3881,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
return true;
unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0;
- if (attr.getNumArgs() != ReqArgs || attr.getParameterName()) {
- Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << ReqArgs;
+ if (!checkAttributeNumArgs(*this, attr, ReqArgs)) {
attr.setInvalid();
return true;
}
@@ -4036,17 +3894,20 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break;
case AttributeList::AT_Pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_MSABI:
+ CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
+ CC_X86_64Win64;
+ break;
+ case AttributeList::AT_SysVABI:
+ CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
+ CC_C;
+ break;
case AttributeList::AT_Pcs: {
- Expr *Arg = attr.getArg(0);
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (!Str || !Str->isAscii()) {
- Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "pcs" << 1;
+ StringRef StrRef;
+ if (!checkStringLiteralArgumentAttr(attr, 0, StrRef)) {
attr.setInvalid();
return true;
}
-
- StringRef StrRef = Str->getString();
if (StrRef == "aapcs") {
CC = CC_AAPCS;
break;
@@ -4103,18 +3964,18 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
if (Attr.isInvalid())
return true;
- if (Attr.getNumArgs() != 1) {
- Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(*this, Attr, 1)) {
Attr.setInvalid();
return true;
}
- Expr *NumParamsExpr = Attr.getArg(0);
+ Expr *NumParamsExpr = Attr.getArgAsExpr(0);
llvm::APSInt NumParams(32);
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
!NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
- Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "regparm" << NumParamsExpr->getSourceRange();
+ Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << NumParamsExpr->getSourceRange();
Attr.setInvalid();
return true;
}
@@ -4152,24 +4013,26 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
return;
}
- Expr *MaxThreadsExpr = Attr.getArg(0);
+ Expr *MaxThreadsExpr = Attr.getArgAsExpr(0);
llvm::APSInt MaxThreads(32);
if (MaxThreadsExpr->isTypeDependent() ||
MaxThreadsExpr->isValueDependent() ||
!MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "launch_bounds" << 1 << MaxThreadsExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
+ << MaxThreadsExpr->getSourceRange();
return;
}
llvm::APSInt MinBlocks(32);
if (Attr.getNumArgs() > 1) {
- Expr *MinBlocksExpr = Attr.getArg(1);
+ Expr *MinBlocksExpr = Attr.getArgAsExpr(1);
if (MinBlocksExpr->isTypeDependent() ||
MinBlocksExpr->isValueDependent() ||
!MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
- << "launch_bounds" << 2 << MinBlocksExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 2 << AANT_ArgumentIntegerConstant
+ << MinBlocksExpr->getSourceRange();
return;
}
}
@@ -4186,20 +4049,17 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- StringRef AttrName = Attr.getName()->getName();
- if (!Attr.getParameterName()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
- << Attr.getName() << /* arg num = */ 1;
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier;
return;
}
-
- if (Attr.getNumArgs() != 2) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << /* required args = */ 3;
+
+ if (!checkAttributeNumArgs(S, Attr, 3))
return;
- }
- IdentifierInfo *ArgumentKind = Attr.getParameterName();
+ StringRef AttrName = Attr.getName()->getName();
+ IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident;
if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
@@ -4210,13 +4070,13 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
uint64_t ArgumentIdx;
if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
Attr.getLoc(), 2,
- Attr.getArg(0), ArgumentIdx))
+ Attr.getArgAsExpr(1), ArgumentIdx))
return;
uint64_t TypeTagIdx;
if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
Attr.getLoc(), 3,
- Attr.getArg(1), TypeTagIdx))
+ Attr.getArgAsExpr(2), TypeTagIdx))
return;
bool IsPointer = (AttrName == "pointer_with_type_tag");
@@ -4225,7 +4085,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx);
if (!BufferTy->isPointerType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
- << AttrName;
+ << Attr.getName();
}
}
@@ -4237,18 +4097,23 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- IdentifierInfo *PointerKind = Attr.getParameterName();
- if (!PointerKind) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
- << "type_tag_for_datatype" << 1;
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
+
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
- QualType MatchingCType = S.GetTypeFromParser(Attr.getMatchingCType(), NULL);
+ IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident;
+ TypeSourceInfo *MatchingCTypeLoc = 0;
+ S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc);
+ assert(MatchingCTypeLoc && "no type source info for attribute argument");
D->addAttr(::new (S.Context)
TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind,
- MatchingCType,
+ MatchingCTypeLoc,
Attr.getLayoutCompatible(),
Attr.getMustBeNull(),
Attr.getAttributeSpellingListIndex()));
@@ -4393,30 +4258,39 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
const AttributeList &attr) {
+ const int EP_ObjCMethod = 1;
+ const int EP_ObjCProperty = 2;
+
SourceLocation loc = attr.getLoc();
-
+ QualType resultType;
+
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
if (!method) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
- return;
+ ObjCPropertyDecl *property = dyn_cast<ObjCPropertyDecl>(D);
+ if (!property) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(loc, loc) << attr.getName() << ExpectedMethodOrProperty;
+ return;
+ }
+ resultType = property->getType();
}
+ else
+ // Check that the method returns a normal pointer.
+ resultType = method->getResultType();
- // Check that the method returns a normal pointer.
- QualType resultType = method->getResultType();
-
if (!resultType->isReferenceType() &&
(!resultType->isPointerType() || resultType->isObjCRetainableType())) {
- S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
<< SourceRange(loc)
- << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2;
+ << attr.getName() << (method ? EP_ObjCMethod : EP_ObjCProperty)
+ << /*non-retainable pointer*/ 2;
// Drop the attribute.
return;
}
- method->addAttr(::new (S.Context)
+ D->addAttr(::new (S.Context)
ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context,
attr.getAttributeSpellingListIndex()));
}
@@ -4494,14 +4368,14 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
<< Attr.getRange() << Attr.getName() << ExpectedStruct;
}
- IdentifierInfo *ParmName = Attr.getParameterName();
+ IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
// In Objective-C, verify that the type names an Objective-C type.
// We don't want to check this outside of ObjC because people sometimes
// do crazy C declarations of Objective-C types.
- if (ParmName && S.getLangOpts().ObjC1) {
+ if (Parm && S.getLangOpts().ObjC1) {
// Check for an existing type with this name.
- LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(),
+ LookupResult R(S, DeclarationName(Parm->Ident), Parm->Loc,
Sema::LookupOrdinaryName);
if (S.LookupName(R, Sc)) {
NamedDecl *Target = R.getFoundDecl();
@@ -4513,7 +4387,32 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
}
D->addAttr(::new (S.Context)
- NSBridgedAttr(Attr.getRange(), S.Context, ParmName,
+ NSBridgedAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<RecordDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName()
+ << (S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass
+ : ExpectedStructOrUnion);
+ return;
+ }
+
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id);
+ return;
+ }
+ IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
+ if (!Parm) {
+ S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id);
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ ObjCBridgeAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0,
Attr.getAttributeSpellingListIndex()));
}
@@ -4576,66 +4475,55 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.MicrosoftExt || S.LangOpts.Borland) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
- Expr *Arg = Attr.getArg(0);
- StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (!Str || !Str->isAscii()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "uuid" << 1;
- return;
- }
+// Check if MS extensions or some other language extensions are enabled. If
+// not, issue a diagnostic that the given attribute is unused.
+static bool checkMicrosoftExt(Sema &S, const AttributeList &Attr,
+ bool OtherExtension = false) {
+ if (S.LangOpts.MicrosoftExt || OtherExtension)
+ return true;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return false;
+}
- StringRef StrRef = Str->getString();
+static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland))
+ return;
- bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' &&
- StrRef.back() == '}';
+ StringRef StrRef;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc))
+ return;
- // Validate GUID length.
- if (IsCurly && StrRef.size() != 38) {
- S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
- return;
- }
- if (!IsCurly && StrRef.size() != 36) {
- S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
- return;
- }
+ // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
+ // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former.
+ if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}')
+ StrRef = StrRef.drop_front().drop_back();
- // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
- // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
- StringRef::iterator I = StrRef.begin();
- if (IsCurly) // Skip the optional '{'
- ++I;
+ // Validate GUID length.
+ if (StrRef.size() != 36) {
+ S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
+ return;
+ }
- for (int i = 0; i < 36; ++i) {
- if (i == 8 || i == 13 || i == 18 || i == 23) {
- if (*I != '-') {
- S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
- return;
- }
- } else if (!isHexDigit(*I)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
+ for (unsigned i = 0; i < 36; ++i) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (StrRef[i] != '-') {
+ S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
return;
}
- I++;
+ } else if (!isHexDigit(StrRef[i])) {
+ S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
+ return;
}
+ }
- D->addAttr(::new (S.Context)
- UuidAttr(Attr.getRange(), S.Context, Str->getString(),
- Attr.getAttributeSpellingListIndex()));
- } else
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
+ D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context, StrRef,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!S.LangOpts.MicrosoftExt) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ if (!checkMicrosoftExt(S, Attr))
return;
- }
AttributeList::Kind Kind = Attr.getKind();
if (Kind == AttributeList::AT_SingleInheritance)
@@ -4656,50 +4544,78 @@ static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.MicrosoftExt) {
- AttributeList::Kind Kind = Attr.getKind();
- if (Kind == AttributeList::AT_Ptr32)
- D->addAttr(
- ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else if (Kind == AttributeList::AT_Ptr64)
- D->addAttr(
- ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else if (Kind == AttributeList::AT_Win64)
- D->addAttr(
- ::new (S.Context) Win64Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- } else
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ if (!checkMicrosoftExt(S, Attr))
+ return;
+
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_Win64)
+ D->addAttr(
+ ::new (S.Context) Win64Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.MicrosoftExt)
- D->addAttr(::new (S.Context)
- ForceInlineAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ if (!checkMicrosoftExt(S, Attr))
+ return;
+ D->addAttr(::new (S.Context)
+ ForceInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkMicrosoftExt(S, Attr))
+ return;
+ // Check linkage after possibly merging declaratinos. See
+ // checkAttributesAfterMerging().
+ D->addAttr(::new (S.Context)
+ SelectAnyAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+/// Handles semantic checking for features that are common to all attributes,
+/// such as checking whether a parameter was properly specified, or the correct
+/// number of arguments were passed, etc.
+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.
+ //
+ // 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 ||
+ Attr.getKind() == AttributeList::IgnoredAttribute)
+ return false;
+
+ // If there are no optional arguments, then checking for the argument count
+ // is trivial.
+ if (Attr.getMinArgs() == Attr.getMaxArgs() &&
+ !checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
+ return true;
+ return false;
}
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
-static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
- const AttributeList &Attr) {
- switch (Attr.getKind()) {
- case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break;
- case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break;
- case AttributeList::AT_Overloadable:handleOverloadableAttr(S, D, Attr); break;
- default:
- break;
- }
-}
+/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
+/// the attribute applies to decls. If the attribute is a type attribute, just
+/// silently ignore it if a GNU attribute.
+static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr,
+ bool IncludeCXX11Attributes) {
+ if (Attr.isInvalid())
+ return;
+
+ // Ignore C++11 attributes on declarator chunks: they appertain to the type
+ // instead.
+ if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
+ return;
+
+ if (handleCommonAttributeFeatures(S, scope, D, Attr))
+ return;
-static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
- const AttributeList &Attr) {
switch (Attr.getKind()) {
case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
@@ -4710,15 +4626,13 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_VectorSize:
case AttributeList::AT_NeonVectorType:
case AttributeList::AT_NeonPolyVectorType:
+ case AttributeList::AT_Ptr32:
+ case AttributeList::AT_Ptr64:
+ case AttributeList::AT_SPtr:
+ case AttributeList::AT_UPtr:
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
- case AttributeList::AT_CUDADevice:
- case AttributeList::AT_CUDAHost:
- case AttributeList::AT_Overloadable:
- // Ignore, this is a non-inheritable attribute, handled
- // by ProcessNonInheritableDeclAttr.
- break;
case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break;
case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break;
case AttributeList::AT_AllocSize: handleAllocSizeAttr (S, D, Attr); break;
@@ -4739,7 +4653,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleCXX11NoReturnAttr(S, D, Attr);
break;
case AttributeList::AT_Deprecated:
- handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated");
+ handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
break;
case AttributeList::AT_Destructor: handleDestructorAttr (S, D, Attr); break;
case AttributeList::AT_ExtVectorType:
@@ -4751,15 +4665,18 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break;
case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break;
case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break;
case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break;
case AttributeList::AT_CUDALaunchBounds:
handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break;
case AttributeList::AT_Malloc: handleMallocAttr (S, D, Attr); break;
case AttributeList::AT_MayAlias: handleMayAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break;
case AttributeList::AT_NoCommon: handleNoCommonAttr (S, D, Attr); break;
case AttributeList::AT_NonNull: handleNonNullAttr (S, D, Attr); break;
+ case AttributeList::AT_Overloadable:handleOverloadableAttr(S, D, Attr); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
@@ -4785,6 +4702,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
+
+ case AttributeList::AT_ObjCBridge:
+ handleObjCBridgeAttr(S, scope, D, Attr); break;
case AttributeList::AT_CFAuditedTransfer:
case AttributeList::AT_CFUnknownTransfer:
@@ -4810,17 +4730,13 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_VecTypeHint:
handleVecTypeHint(S, D, Attr); break;
- case AttributeList::AT_Endian:
- handleEndianAttr(S, D, Attr);
- break;
-
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
case AttributeList::AT_Packed: handlePackedAttr (S, D, Attr); break;
case AttributeList::AT_Section: handleSectionAttr (S, D, Attr); break;
case AttributeList::AT_Unavailable:
- handleAttrWithMessage<UnavailableAttr>(S, D, Attr, "unavailable");
+ handleAttrWithMessage<UnavailableAttr>(S, D, Attr);
break;
case AttributeList::AT_ArcWeakrefUnavailable:
handleArcWeakrefUnavailableAttr (S, D, Attr);
@@ -4842,6 +4758,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeVisibility:
handleVisibilityAttr(S, D, Attr, true);
break;
+ case AttributeList::AT_WarnUnused:
+ handleWarnUnusedAttr(S, D, Attr);
+ break;
case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
@@ -4876,6 +4795,8 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_FastCall:
case AttributeList::AT_ThisCall:
case AttributeList::AT_Pascal:
+ case AttributeList::AT_MSABI:
+ case AttributeList::AT_SysVABI:
case AttributeList::AT_Pcs:
case AttributeList::AT_PnaclCall:
case AttributeList::AT_IntelOclBicc:
@@ -4889,7 +4810,6 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
break;
// Microsoft attributes:
- case AttributeList::AT_MsProperty: break;
case AttributeList::AT_MsStruct:
handleMsStructAttr(S, D, Attr);
break;
@@ -4902,15 +4822,22 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleInheritanceAttr(S, D, Attr);
break;
case AttributeList::AT_Win64:
- case AttributeList::AT_Ptr32:
- case AttributeList::AT_Ptr64:
handlePortabilityAttr(S, D, Attr);
break;
case AttributeList::AT_ForceInline:
handleForceInlineAttr(S, D, Attr);
break;
+ case AttributeList::AT_SelectAny:
+ handleSelectAnyAttr(S, D, Attr);
+ break;
// Thread safety attributes:
+ case AttributeList::AT_AssertExclusiveLock:
+ handleAssertExclusiveLockAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_AssertSharedLock:
+ handleAssertSharedLockAttr(S, D, Attr);
+ break;
case AttributeList::AT_GuardedVar:
handleGuardedVarAttr(S, D, Attr);
break;
@@ -4975,6 +4902,26 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleAcquiredAfterAttr(S, D, Attr);
break;
+ // Consumed analysis attributes.
+ case AttributeList::AT_Consumable:
+ handleConsumableAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_CallableWhen:
+ handleCallableWhenAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ParamTypestate:
+ handleParamTypestateAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ReturnTypestate:
+ handleReturnTypestateAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_SetTypestate:
+ handleSetTypestateAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_TestTypestate:
+ handleTestTypestateAttr(S, D, Attr);
+ break;
+
// Type safety attributes.
case AttributeList::AT_ArgumentWithTypeTag:
handleArgumentWithTypeTagAttr(S, D, Attr);
@@ -4994,42 +4941,18 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
}
}
-/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
-/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it if a GNU attribute.
-static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
- const AttributeList &Attr,
- bool NonInheritable, bool Inheritable,
- bool IncludeCXX11Attributes) {
- if (Attr.isInvalid())
- return;
-
- // Ignore C++11 attributes on declarator chunks: they appertain to the type
- // instead.
- if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
- return;
-
- if (NonInheritable)
- ProcessNonInheritableDeclAttr(S, scope, D, Attr);
-
- if (Inheritable)
- ProcessInheritableDeclAttr(S, scope, D, Attr);
-}
-
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
/// attribute list to the specified decl, ignoring any type attributes.
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
const AttributeList *AttrList,
- bool NonInheritable, bool Inheritable,
bool IncludeCXX11Attributes) {
for (const AttributeList* l = AttrList; l; l = l->getNext())
- ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable,
- IncludeCXX11Attributes);
+ ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes);
// GCC accepts
// static int a9 __attribute__((weakref));
// but that looks really pointless. We reject it.
- if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
+ if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
cast<NamedDecl>(D)->getNameAsString();
D->dropAttr<WeakRefAttr>();
@@ -5182,11 +5105,10 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
/// it, apply them to D. This is a bit tricky because PD can have attributes
/// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable, bool Inheritable) {
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList())
- ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
+ ProcessDeclAttributeList(S, D, Attrs);
// Walk the declarator structure, applying decl attributes that were in a type
// position to the decl itself. This handles cases like:
@@ -5194,12 +5116,11 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
// when X is a decl attribute.
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
- ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable,
- /*IncludeCXX11Attributes=*/false);
+ ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false);
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
- ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
+ ProcessDeclAttributeList(S, D, Attrs);
}
/// Is the given declaration allowed to use a forbidden type?
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e6a131a0761c..6b3400adac6e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
@@ -27,6 +28,7 @@
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/DeclSpec.h"
@@ -339,9 +341,7 @@ void Sema::ActOnParamUnparsedDefaultArgument(Decl *param,
return;
ParmVarDecl *Param = cast<ParmVarDecl>(param);
- if (Param)
- Param->setUnparsedDefaultArg();
-
+ Param->setUnparsedDefaultArg();
UnparsedDefaultArgLocs[Param] = ArgLoc;
}
@@ -352,9 +352,7 @@ void Sema::ActOnParamDefaultArgumentError(Decl *param) {
return;
ParmVarDecl *Param = cast<ParmVarDecl>(param);
-
Param->setInvalidDecl();
-
UnparsedDefaultArgLocs.erase(Param);
}
@@ -404,6 +402,17 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
}
}
+static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) {
+ for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) {
+ const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1);
+ if (!PVD->hasDefaultArg())
+ return false;
+ if (!PVD->hasInheritedDefaultArg())
+ return true;
+ }
+ return false;
+}
+
/// MergeCXXFunctionDecl - Merge two declarations of the same C++
/// function, once we already know that they have the same
/// type. Subroutine of MergeFunctionDecl. Returns true if there was an
@@ -426,9 +435,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// declaration (not even to the same value).
//
// C++ [dcl.fct.default]p6:
- // Except for member functions of class templates, the default arguments
- // in a member function definition that appears outside of the class
- // definition are added to the set of default arguments provided by the
+ // Except for member functions of class templates, the default arguments
+ // in a member function definition that appears outside of the class
+ // definition are added to the set of default arguments provided by the
// member function declaration in the class definition.
for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *OldParam = Old->getParamDecl(p);
@@ -438,9 +447,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
bool NewParamHasDfl = NewParam->hasDefaultArg();
NamedDecl *ND = Old;
- if (S && !isDeclInScope(ND, New->getDeclContext(), S))
+
+ // The declaration context corresponding to the scope is the semantic
+ // parent, unless this is a local function declaration, in which case
+ // it is that surrounding function.
+ DeclContext *ScopeDC = New->getLexicalDeclContext();
+ if (!ScopeDC->isFunctionOrMethod())
+ ScopeDC = New->getDeclContext();
+ if (S && !isDeclInScope(ND, ScopeDC, S) &&
+ !New->getDeclContext()->isRecord())
// Ignore default parameters of old decl if they are not in
- // the same scope.
+ // the same scope and this is not an out-of-line definition of
+ // a member function.
OldParamHasDfl = false;
if (OldParamHasDfl && NewParamHasDfl) {
@@ -578,6 +596,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}
+ // C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
+ // argument expression, that declaration shall be a definition and shall be
+ // the only declaration of the function or function template in the
+ // translation unit.
+ if (Old->getFriendObjectKind() == Decl::FOK_Undeclared &&
+ functionDeclHasDefaultArgument(Old)) {
+ Diag(New->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ Invalid = true;
+ }
+
if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
@@ -851,7 +880,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
diag::err_constexpr_local_var_non_literal_type,
isa<CXXConstructorDecl>(Dcl)))
return false;
- if (!VD->hasInit()) {
+ if (!VD->hasInit() && !VD->isCXXForRangeDecl()) {
SemaRef.Diag(VD->getLocation(),
diag::err_constexpr_local_var_no_init)
<< isa<CXXConstructorDecl>(Dcl);
@@ -897,6 +926,9 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
FieldDecl *Field,
llvm::SmallSet<Decl*, 16> &Inits,
bool &Diagnosed) {
+ if (Field->isInvalidDecl())
+ return;
+
if (Field->isUnnamedBitfield())
return;
@@ -925,7 +957,7 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
/// definition.
static bool
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
- llvm::SmallVectorImpl<SourceLocation> &ReturnStmts,
+ SmallVectorImpl<SourceLocation> &ReturnStmts,
SourceLocation &Cxx1yLoc) {
// - its function-body shall be [...] a compound-statement that contains only
switch (S->getStmtClass()) {
@@ -1192,8 +1224,33 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
if (CurDecl && CurDecl->getIdentifier())
return &II == CurDecl->getIdentifier();
- else
+ return false;
+}
+
+/// \brief Determine whether the identifier II is a typo for the name of
+/// the class type currently being defined. If so, update it to the identifier
+/// that should have been used.
+bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) {
+ assert(getLangOpts().CPlusPlus && "No class names in C!");
+
+ if (!getLangOpts().SpellChecking)
return false;
+
+ CXXRecordDecl *CurDecl;
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ DeclContext *DC = computeDeclContext(*SS, true);
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
+ } else
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
+
+ if (CurDecl && CurDecl->getIdentifier() && II != CurDecl->getIdentifier() &&
+ 3 * II->getName().edit_distance(CurDecl->getIdentifier()->getName())
+ < II->getLength()) {
+ II = CurDecl->getIdentifier();
+ return true;
+ }
+
+ return false;
}
/// \brief Determine whether the given class is a base class of the given
@@ -1224,8 +1281,7 @@ static bool findCircularInheritance(const CXXRecordDecl *Class,
if (Queue.empty())
return false;
- Current = Queue.back();
- Queue.pop_back();
+ Current = Queue.pop_back_val();
}
return false;
@@ -1311,15 +1367,28 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
assert(BaseDecl && "Record type has no declaration");
BaseDecl = BaseDecl->getDefinition();
assert(BaseDecl && "Base type is not incomplete, but has no definition");
- CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
+ CXXRecordDecl *CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
+ // A class which contains a flexible array member is not suitable for use as a
+ // base class:
+ // - If the layout determines that a base comes before another base,
+ // the flexible array member would index into the subsequent base.
+ // - If the layout determines that base comes before the derived class,
+ // the flexible array member would index into the derived class.
+ if (CXXBaseDecl->hasFlexibleArrayMember()) {
+ Diag(BaseLoc, diag::err_base_class_has_flexible_array_member)
+ << CXXBaseDecl->getDeclName();
+ return 0;
+ }
+
// C++ [class]p3:
- // If a class is marked final and it appears as a base-type-specifier in
+ // If a class is marked final and it appears as a base-type-specifier in
// base-clause, the program is ill-formed.
- if (CXXBaseDecl->hasAttr<FinalAttr>()) {
- Diag(BaseLoc, diag::err_class_marked_final_used_as_base)
- << CXXBaseDecl->getDeclName();
+ if (FinalAttr *FA = CXXBaseDecl->getAttr<FinalAttr>()) {
+ Diag(BaseLoc, diag::err_class_marked_final_used_as_base)
+ << CXXBaseDecl->getDeclName()
+ << FA->isSpelledAsSealed();
Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl)
<< CXXBaseDecl->getDeclName();
return 0;
@@ -1327,7 +1396,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (BaseDecl->isInvalidDecl())
Class->setInvalidDecl();
-
+
// Create the base specifier.
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
Class->getTagKind() == TTK_Class,
@@ -1465,8 +1534,7 @@ void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
return;
AdjustDeclIfTemplate(ClassDecl);
- AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl),
- (CXXBaseSpecifier**)(Bases), NumBases);
+ AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl), Bases, NumBases);
}
/// \brief Determine whether the type \p Derived is a C++ class that is
@@ -1590,26 +1658,28 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
return false;
}
- // We know that the derived-to-base conversion is ambiguous, and
- // we're going to produce a diagnostic. Perform the derived-to-base
- // search just one more time to compute all of the possible paths so
- // that we can print them out. This is more expensive than any of
- // the previous derived-to-base checks we've done, but at this point
- // performance isn't as much of an issue.
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
- assert(StillOkay && "Can only be used with a derived-to-base conversion");
- (void)StillOkay;
-
- // Build up a textual representation of the ambiguous paths, e.g.,
- // D -> B -> A, that will be used to illustrate the ambiguous
- // conversions in the diagnostic. We only print one of the paths
- // to each base class subobject.
- std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
-
- Diag(Loc, AmbigiousBaseConvID)
- << Derived << Base << PathDisplayStr << Range << Name;
+ 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
+ // search just one more time to compute all of the possible paths so
+ // that we can print them out. This is more expensive than any of
+ // the previous derived-to-base checks we've done, but at this point
+ // performance isn't as much of an issue.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
+ assert(StillOkay && "Can only be used with a derived-to-base conversion");
+ (void)StillOkay;
+
+ // Build up a textual representation of the ambiguous paths, e.g.,
+ // D -> B -> A, that will be used to illustrate the ambiguous
+ // conversions in the diagnostic. We only print one of the paths
+ // to each base class subobject.
+ std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
+
+ Diag(Loc, AmbigiousBaseConvID)
+ << Derived << Base << PathDisplayStr << Range << Name;
+ }
return true;
}
@@ -1675,37 +1745,63 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
}
/// CheckOverrideControl - Check C++11 override control semantics.
-void Sema::CheckOverrideControl(Decl *D) {
+void Sema::CheckOverrideControl(NamedDecl *D) {
if (D->isInvalidDecl())
return;
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
+ // We only care about "override" and "final" declarations.
+ if (!D->hasAttr<OverrideAttr>() && !D->hasAttr<FinalAttr>())
+ return;
- // Do we know which functions this declaration might be overriding?
- bool OverridesAreKnown = !MD ||
- (!MD->getParent()->hasAnyDependentBases() &&
- !MD->getType()->isDependentType());
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
- if (!MD || !MD->isVirtual()) {
- if (OverridesAreKnown) {
+ // We can't check dependent instance methods.
+ if (MD && MD->isInstance() &&
+ (MD->getParent()->hasAnyDependentBases() ||
+ MD->getType()->isDependentType()))
+ return;
+
+ if (MD && !MD->isVirtual()) {
+ // If we have a non-virtual method, check if if hides a virtual method.
+ // (In that case, it's most likely the method has the wrong type.)
+ SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
+ FindHiddenVirtualMethods(MD, OverloadedMethods);
+
+ if (!OverloadedMethods.empty()) {
if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) {
Diag(OA->getLocation(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "override" << FixItHint::CreateRemoval(OA->getLocation());
- D->dropAttr<OverrideAttr>();
- }
- if (FinalAttr *FA = D->getAttr<FinalAttr>()) {
+ diag::override_keyword_hides_virtual_member_function)
+ << "override" << (OverloadedMethods.size() > 1);
+ } else if (FinalAttr *FA = D->getAttr<FinalAttr>()) {
Diag(FA->getLocation(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "final" << FixItHint::CreateRemoval(FA->getLocation());
- D->dropAttr<FinalAttr>();
+ diag::override_keyword_hides_virtual_member_function)
+ << (FA->isSpelledAsSealed() ? "sealed" : "final")
+ << (OverloadedMethods.size() > 1);
}
+ NoteHiddenVirtualMethods(MD, OverloadedMethods);
+ MD->setInvalidDecl();
+ return;
}
- return;
+ // Fall through into the general case diagnostic.
+ // FIXME: We might want to attempt typo correction here.
}
- if (!OverridesAreKnown)
+ if (!MD || !MD->isVirtual()) {
+ if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) {
+ Diag(OA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << "override" << FixItHint::CreateRemoval(OA->getLocation());
+ D->dropAttr<OverrideAttr>();
+ }
+ if (FinalAttr *FA = D->getAttr<FinalAttr>()) {
+ Diag(FA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << (FA->isSpelledAsSealed() ? "sealed" : "final")
+ << FixItHint::CreateRemoval(FA->getLocation());
+ D->dropAttr<FinalAttr>();
+ }
return;
+ }
// C++11 [class.virtual]p5:
// If a virtual function is marked with the virt-specifier override and
@@ -1723,11 +1819,13 @@ void Sema::CheckOverrideControl(Decl *D) {
/// C++11 [class.virtual]p4.
bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- if (!Old->hasAttr<FinalAttr>())
+ FinalAttr *FA = Old->getAttr<FinalAttr>();
+ if (!FA)
return false;
Diag(New->getLocation(), diag::err_final_function_overridden)
- << New->getDeclName();
+ << New->getDeclName()
+ << FA->isSpelledAsSealed();
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
@@ -1933,19 +2031,20 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (MSPropertyAttr) {
Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D,
BitWidth, InitStyle, AS, MSPropertyAttr);
+ if (!Member)
+ return 0;
isInstField = false;
} else {
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D,
BitWidth, InitStyle, AS);
+ assert(Member && "HandleField never returns null");
}
- assert(Member && "HandleField never returns null");
} else {
assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static);
Member = HandleDeclarator(S, D, TemplateParameterLists);
- if (!Member) {
+ if (!Member)
return 0;
- }
// Non-instance-fields can't have a bitfield.
if (BitWidth) {
@@ -1974,16 +2073,19 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member->setAccess(AS);
- // If we have declared a member function template, set the access of the
- // templated declaration as well.
+ // If we have declared a member function template or static data member
+ // template, set the access of the templated declaration as well.
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
FunTmpl->getTemplatedDecl()->setAccess(AS);
+ else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member))
+ VarTmpl->getTemplatedDecl()->setAccess(AS);
}
if (VS.isOverrideSpecified())
Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
if (VS.isFinalSpecified())
- Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
+ Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context,
+ VS.isFinalSpelledSealed()));
if (VS.getLastLocation().isValid()) {
// Update the end location of a method that has a virt-specifiers.
@@ -2020,57 +2122,71 @@ namespace {
class UninitializedFieldVisitor
: public EvaluatedExprVisitor<UninitializedFieldVisitor> {
Sema &S;
- ValueDecl *VD;
+ // List of Decls to generate a warning on. Also remove Decls that become
+ // initialized.
+ llvm::SmallPtrSet<ValueDecl*, 4> &Decls;
+ // If non-null, add a note to the warning pointing back to the constructor.
+ const CXXConstructorDecl *Constructor;
public:
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
- UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
- S(S) {
- if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(VD))
- this->VD = IFD->getAnonField();
- else
- this->VD = VD;
- }
-
- void HandleExpr(Expr *E) {
- if (!E) return;
+ UninitializedFieldVisitor(Sema &S,
+ llvm::SmallPtrSet<ValueDecl*, 4> &Decls,
+ const CXXConstructorDecl *Constructor)
+ : Inherited(S.Context), S(S), Decls(Decls),
+ Constructor(Constructor) { }
+
+ void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly) {
+ if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ return;
- // Expressions like x(x) sometimes lack the surrounding expressions
- // but need to be checked anyways.
- HandleValue(E);
- Visit(E);
- }
+ // FieldME is the inner-most MemberExpr that is not an anonymous struct
+ // or union.
+ MemberExpr *FieldME = ME;
- void HandleValue(Expr *E) {
- E = E->IgnoreParens();
+ Expr *Base = ME;
+ while (isa<MemberExpr>(Base)) {
+ ME = cast<MemberExpr>(Base);
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ if (isa<VarDecl>(ME->getMemberDecl()))
return;
- // FieldME is the inner-most MemberExpr that is not an anonymous struct
- // or union.
- MemberExpr *FieldME = ME;
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (!FD->isAnonymousStructOrUnion())
+ FieldME = ME;
- Expr *Base = E;
- while (isa<MemberExpr>(Base)) {
- ME = cast<MemberExpr>(Base);
+ Base = ME->getBase();
+ }
- if (isa<VarDecl>(ME->getMemberDecl()))
- return;
+ if (!isa<CXXThisExpr>(Base))
+ return;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- if (!FD->isAnonymousStructOrUnion())
- FieldME = ME;
+ ValueDecl* FoundVD = FieldME->getMemberDecl();
- Base = ME->getBase();
- }
+ if (!Decls.count(FoundVD))
+ return;
- if (VD == FieldME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
- unsigned diag = VD->getType()->isReferenceType()
- ? diag::warn_reference_field_is_uninit
- : diag::warn_field_is_uninit;
- S.Diag(FieldME->getExprLoc(), diag) << VD;
- }
+ const bool IsReference = FoundVD->getType()->isReferenceType();
+
+ // Prevent double warnings on use of unbounded references.
+ if (IsReference != CheckReferenceOnly)
+ return;
+
+ unsigned diag = IsReference
+ ? diag::warn_reference_field_is_uninit
+ : diag::warn_field_is_uninit;
+ S.Diag(FieldME->getExprLoc(), diag) << FoundVD;
+ if (Constructor)
+ S.Diag(Constructor->getLocation(),
+ diag::note_uninit_in_this_constructor)
+ << (Constructor->isDefaultConstructor() && Constructor->isImplicit());
+
+ }
+
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParens();
+
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ HandleMemberExpr(ME, false /*CheckReferenceOnly*/);
return;
}
@@ -2102,6 +2218,13 @@ namespace {
}
}
+ void VisitMemberExpr(MemberExpr *ME) {
+ // All uses of unbounded reference fields will warn.
+ HandleMemberExpr(ME, true /*CheckReferenceOnly*/);
+
+ Inherited::VisitMemberExpr(ME);
+ }
+
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
if (E->getCastKind() == CK_LValueToRValue)
HandleValue(E->getSubExpr());
@@ -2109,6 +2232,16 @@ namespace {
Inherited::VisitImplicitCastExpr(E);
}
+ void VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->getConstructor()->isCopyConstructor())
+ if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E->getArg(0)))
+ if (ICE->getCastKind() == CK_NoOp)
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(ICE->getSubExpr()))
+ HandleMemberExpr(ME, false /*CheckReferenceOnly*/);
+
+ Inherited::VisitCXXConstructExpr(E);
+ }
+
void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
Expr *Callee = E->getCallee();
if (isa<MemberExpr>(Callee))
@@ -2116,10 +2249,85 @@ namespace {
Inherited::VisitCXXMemberCallExpr(E);
}
+
+ void VisitBinaryOperator(BinaryOperator *E) {
+ // If a field assignment is detected, remove the field from the
+ // uninitiailized field set.
+ if (E->getOpcode() == BO_Assign)
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getLHS()))
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (!FD->getType()->isReferenceType())
+ Decls.erase(FD);
+
+ Inherited::VisitBinaryOperator(E);
+ }
};
- static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
- ValueDecl *VD) {
- UninitializedFieldVisitor(S, VD).HandleExpr(E);
+ static void CheckInitExprContainsUninitializedFields(
+ Sema &S, Expr *E, llvm::SmallPtrSet<ValueDecl*, 4> &Decls,
+ const CXXConstructorDecl *Constructor) {
+ if (Decls.size() == 0)
+ return;
+
+ if (!E)
+ return;
+
+ if (CXXDefaultInitExpr *Default = dyn_cast<CXXDefaultInitExpr>(E)) {
+ E = Default->getExpr();
+ if (!E)
+ return;
+ // In class initializers will point to the constructor.
+ UninitializedFieldVisitor(S, Decls, Constructor).Visit(E);
+ } else {
+ UninitializedFieldVisitor(S, Decls, 0).Visit(E);
+ }
+ }
+
+ // Diagnose value-uses of fields to initialize themselves, e.g.
+ // foo(foo)
+ // where foo is not also a parameter to the constructor.
+ // Also diagnose across field uninitialized use such as
+ // x(y), y(x)
+ // TODO: implement -Wuninitialized and fold this into that framework.
+ static void DiagnoseUninitializedFields(
+ Sema &SemaRef, const CXXConstructorDecl *Constructor) {
+
+ if (SemaRef.getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit,
+ Constructor->getLocation())
+ == DiagnosticsEngine::Ignored) {
+ return;
+ }
+
+ if (Constructor->isInvalidDecl())
+ return;
+
+ const CXXRecordDecl *RD = Constructor->getParent();
+
+ // Holds fields that are uninitialized.
+ llvm::SmallPtrSet<ValueDecl*, 4> UninitializedFields;
+
+ // At the beginning, all fields are uninitialized.
+ for (DeclContext::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
+ I != E; ++I) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(*I)) {
+ UninitializedFields.insert(FD);
+ } else if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*I)) {
+ UninitializedFields.insert(IFD->getAnonField());
+ }
+ }
+
+ for (CXXConstructorDecl::init_const_iterator FieldInit =
+ Constructor->init_begin(),
+ FieldInitEnd = Constructor->init_end();
+ FieldInit != FieldInitEnd; ++FieldInit) {
+
+ Expr *InitExpr = (*FieldInit)->getInit();
+
+ CheckInitExprContainsUninitializedFields(
+ SemaRef, InitExpr, UninitializedFields, Constructor);
+
+ if (FieldDecl *Field = (*FieldInit)->getAnyMember())
+ UninitializedFields.erase(Field);
+ }
}
} // namespace
@@ -2146,17 +2354,8 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
return;
}
- if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, InitLoc)
- != DiagnosticsEngine::Ignored) {
- CheckInitExprContainsUninitializedFields(*this, InitExpr, FD);
- }
-
ExprResult Init = InitExpr;
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
- Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
- << /*at end of ctor*/1 << InitExpr->getSourceRange();
- }
InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit
? InitializationKind::CreateDirectList(InitExpr->getLocStart())
@@ -2254,12 +2453,11 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
const DeclSpec &DS,
SourceLocation IdLoc,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc) {
Expr *List = new (Context) ParenListExpr(Context, LParenLoc,
- llvm::makeArrayRef(Args, NumArgs),
- RParenLoc);
+ Args, RParenLoc);
return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
DS, IdLoc, List, EllipsisLoc);
}
@@ -2269,21 +2467,20 @@ namespace {
// Callback to only accept typo corrections that can be a valid C++ member
// intializer: either a non-static field member or a base class.
class MemInitializerValidatorCCC : public CorrectionCandidateCallback {
- public:
+public:
explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl)
: ClassDecl(ClassDecl) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) LLVM_OVERRIDE {
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
if (FieldDecl *Member = dyn_cast<FieldDecl>(ND))
return Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl);
- else
- return isa<TypeDecl>(ND);
+ return isa<TypeDecl>(ND);
}
return false;
}
- private:
+private:
CXXRecordDecl *ClassDecl;
};
@@ -2389,18 +2586,13 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
Validator, ClassDecl))) {
- std::string CorrectedStr(Corr.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corr.getQuoted(getLangOpts()));
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
// member.
- Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << true << CorrectedQuotedStr
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
- Diag(Member->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
+ diagnoseTypo(Corr,
+ PDiag(diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << true);
return BuildMemberInitializer(Member, Init, IdLoc);
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
@@ -2411,12 +2603,13 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// We have found a direct or virtual base class with a
// similar name to what was typed; complain and initialize
// that base class.
- Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << false << CorrectedQuotedStr
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ diagnoseTypo(Corr,
+ PDiag(diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << false,
+ PDiag() /*Suppress note, we provide our own.*/);
- const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
- : VirtualBaseSpec;
+ const CXXBaseSpecifier *BaseSpec = DirectBaseSpec ? DirectBaseSpec
+ : VirtualBaseSpec;
Diag(BaseSpec->getLocStart(),
diag::note_base_class_specified_here)
<< BaseSpec->getType()
@@ -2480,15 +2673,7 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
}
}
- if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) {
- // Taking the address of a temporary will be diagnosed as a hard error.
- if (IsPointer)
- return;
-
- S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary)
- << Member << Init->getSourceRange();
- } else if (const DeclRefExpr *DRE
- = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
// We only warn when referring to a non-reference parameter declaration.
const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl());
if (!Parameter || Parameter->getType()->isReferenceType())
@@ -2521,10 +2706,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (Member->isInvalidDecl())
return true;
- // Diagnose value-uses of fields to initialize themselves, e.g.
- // foo(foo)
- // where foo is not also a parameter to the constructor.
- // TODO: implement -Wuninitialized and fold this into that framework.
MultiExprArg Args;
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs());
@@ -2535,19 +2716,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
Args = Init;
}
- if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
- != DiagnosticsEngine::Ignored)
- for (unsigned i = 0, e = Args.size(); i != e; ++i)
- // FIXME: Warn about the case when other fields are used before being
- // initialized. For example, let this field be the i'th field. When
- // initializing the i'th field, throw a warning if any of the >= i'th
- // fields are used, as they are not yet initialized.
- // Right now we are only handling the case where the i'th field uses
- // itself in its initializer.
- // Also need to take into account that some fields may be initialized by
- // in-class initializers, see C++11 [class.base.init]p9.
- CheckInitExprContainsUninitializedFields(*this, Args[i], Member);
-
SourceRange InitRange = Init->getSourceRange();
if (Member->getType()->isDependentType() || Init->isTypeDependent()) {
@@ -2559,11 +2727,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (isa<InitListExpr>(Init)) {
InitList = true;
Args = Init;
-
- if (isStdInitializerList(Member->getType(), 0)) {
- Diag(IdLoc, diag::warn_dangling_std_initializer_list)
- << /*at end of ctor*/1 << InitRange;
- }
}
// Initialize the member.
@@ -2580,6 +2743,8 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (MemberInit.isInvalid())
return true;
+ CheckForDanglingReferenceOrPointer(*this, Member, MemberInit.get(), IdLoc);
+
// C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
@@ -2588,7 +2753,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
return true;
Init = MemberInit.get();
- CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
}
if (DirectMember) {
@@ -2742,9 +2906,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
<< BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
- CXXBaseSpecifier *BaseSpec = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
+ const CXXBaseSpecifier *BaseSpec = DirectBaseSpec;
if (!BaseSpec)
- BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec);
+ BaseSpec = VirtualBaseSpec;
// Initialize the base.
bool InitList = true;
@@ -3228,6 +3392,8 @@ static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Field,
IndirectFieldDecl *Indirect = 0) {
+ if (Field->isInvalidDecl())
+ return false;
// Overwhelmingly common case: we have a direct initializer for this field.
if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
@@ -3266,7 +3432,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
// Don't try to build an implicit initializer if there were semantic
// errors in any of the initializers (and therefore we might be
// missing some that the user actually wrote).
- if (Info.AnyErrorsInInits || Field->isInvalidDecl())
+ if (Info.AnyErrorsInInits)
return false;
CXXCtorInitializer *Init = 0;
@@ -3333,7 +3499,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
for (unsigned i = 0; i < Initializers.size(); i++) {
CXXCtorInitializer *Member = Initializers[i];
-
+
if (Member->isBaseInitializer())
Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
else
@@ -3354,12 +3520,28 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (CXXCtorInitializer *Value
= Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ // [class.base.init]p7, per DR257:
+ // A mem-initializer where the mem-initializer-id names a virtual base
+ // class is ignored during execution of a constructor of any class that
+ // is not the most derived class.
+ if (ClassDecl->isAbstract()) {
+ // FIXME: Provide a fixit to remove the base specifier. This requires
+ // tracking the location of the associated comma for a base specifier.
+ Diag(Value->getSourceLocation(), diag::warn_abstract_vbase_init_ignored)
+ << VBase->getType() << ClassDecl;
+ DiagnoseAbstractType(ClassDecl);
+ }
+
Info.AllToInit.push_back(Value);
- } else if (!AnyErrors) {
+ } else if (!AnyErrors && !ClassDecl->isAbstract()) {
+ // [class.base.init]p8, per DR257:
+ // If a given [...] base class is not named by a mem-initializer-id
+ // [...] and the entity is not a virtual base class of an abstract
+ // class, then [...] the entity is default-initialized.
bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
CXXCtorInitializer *CXXBaseInit;
if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
- VBase, IsInheritedVirtualBase,
+ VBase, IsInheritedVirtualBase,
CXXBaseInit)) {
HadError = true;
continue;
@@ -3465,12 +3647,12 @@ static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*>
IdealInits.push_back(Field);
}
-static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
- return const_cast<Type*>(Context.getCanonicalType(BaseType).getTypePtr());
+static const void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
+ return Context.getCanonicalType(BaseType).getTypePtr();
}
-static void *GetKeyForMember(ASTContext &Context,
- CXXCtorInitializer *Member) {
+static const void *GetKeyForMember(ASTContext &Context,
+ CXXCtorInitializer *Member) {
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
@@ -3534,7 +3716,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
CXXCtorInitializer *PrevInit = 0;
for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
- void *InitKey = GetKeyForMember(SemaRef.Context, Init);
+ const void *InitKey = GetKeyForMember(SemaRef.Context, Init);
// Scan forward to try to find this initializer in the idealized
// initializers list.
@@ -3660,7 +3842,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
// Mapping for the duplicate initializers check.
// For member initializers, this is keyed with a FieldDecl*.
// For base initializers, this is keyed with a Type*.
- llvm::DenseMap<void*, CXXCtorInitializer *> Members;
+ llvm::DenseMap<const void *, CXXCtorInitializer *> Members;
// Mapping for the inconsistent anonymous-union initializers check.
RedundantUnionMap MemberUnions;
@@ -3678,7 +3860,8 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
CheckRedundantUnionInit(*this, Init, MemberUnions))
HadError = true;
} else if (Init->isBaseInitializer()) {
- void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ const void *Key =
+ GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
if (CheckRedundantInit(*this, Init, Members[Key]))
HadError = true;
} else {
@@ -3702,6 +3885,8 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits);
SetCtorInitializers(Constructor, AnyErrors, MemInits);
+
+ DiagnoseUninitializedFields(*this, Constructor);
}
void
@@ -3750,7 +3935,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Field->getDeclName()
<< FieldType);
- MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
@@ -3783,7 +3968,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Base->getSourceRange(),
Context.getTypeDeclType(ClassDecl));
- MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
@@ -3807,12 +3992,19 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
assert(Dtor && "No dtor found for BaseClassDecl!");
- CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
- PDiag(diag::err_access_dtor_vbase)
- << VBase->getType(),
- Context.getTypeDeclType(ClassDecl));
-
- MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ if (CheckDestructorAccess(
+ ClassDecl->getLocation(), Dtor,
+ PDiag(diag::err_access_dtor_vbase)
+ << Context.getTypeDeclType(ClassDecl) << VBase->getType(),
+ Context.getTypeDeclType(ClassDecl)) ==
+ AR_accessible) {
+ CheckDerivedToBaseConversion(
+ Context.getTypeDeclType(ClassDecl), VBase->getType(),
+ diag::err_access_dtor_vbase, 0, ClassDecl->getLocation(),
+ SourceRange(), DeclarationName(), 0);
+ }
+
+ MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
}
@@ -3822,8 +4014,10 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) {
return;
if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(CDtorDecl))
+ = dyn_cast<CXXConstructorDecl>(CDtorDecl)) {
SetCtorInitializers(Constructor, /*AnyErrors=*/false);
+ DiagnoseUninitializedFields(*this, Constructor);
+ }
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
@@ -3835,8 +4029,8 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
public:
NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID)
: TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { }
-
- virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) LLVM_OVERRIDE {
if (Suppressed) return;
if (SelID == -1)
S.Diag(Loc, DiagID) << T;
@@ -3893,6 +4087,12 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
return;
+ // If the diagnostic is suppressed, don't emit the notes. We're only
+ // going to emit them once, so try to attach them to a diagnostic we're
+ // actually going to show.
+ if (Diags.isLastDiagnosticIgnored())
+ return;
+
CXXFinalOverriderMap FinalOverriders;
RD->getFinalOverriders(FinalOverriders);
@@ -4172,9 +4372,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
diag::warn_non_virtual_dtor) << Context.getRecordType(Record);
}
- if (Record->isAbstract() && Record->hasAttr<FinalAttr>()) {
- Diag(Record->getLocation(), diag::warn_abstract_final_class);
- DiagnoseAbstractType(Record);
+ if (Record->isAbstract()) {
+ if (FinalAttr *FA = Record->getAttr<FinalAttr>()) {
+ Diag(Record->getLocation(), diag::warn_abstract_final_class)
+ << FA->isSpelledAsSealed();
+ DiagnoseAbstractType(Record);
+ }
}
if (!Record->isDependentType()) {
@@ -4184,7 +4387,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// See if a method overloads virtual methods in a base
// class without overriding any.
if (!M->isStatic())
- DiagnoseHiddenVirtualMethods(Record, *M);
+ DiagnoseHiddenVirtualMethods(*M);
// Check whether the explicitly-defaulted special members are valid.
if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
@@ -4243,6 +4446,13 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ // Check to see if we're trying to lay out a struct using the ms_struct
+ // attribute that is dynamic.
+ if (Record->isMsStruct(Context) && Record->isDynamicClass()) {
+ Diag(Record->getLocation(), diag::warn_pragma_ms_struct_failed);
+ Record->dropAttr<MsStructAttr>();
+ }
+
// Declare inheriting constructors. We do this eagerly here because:
// - The standard requires an eager diagnostic for conflicting inheriting
// constructors from different classes.
@@ -4278,6 +4488,7 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// C++11 [dcl.constexpr]p4:
// In the definition of a constexpr constructor [...]
+ bool Ctor = true;
switch (CSM) {
case Sema::CXXDefaultConstructor:
// Since default constructor lookup is essentially trivial (and cannot
@@ -4295,6 +4506,12 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
case Sema::CXXCopyAssignment:
case Sema::CXXMoveAssignment:
+ if (!S.getLangOpts().CPlusPlus1y)
+ return false;
+ // In C++1y, we need to perform overload resolution.
+ Ctor = false;
+ break;
+
case Sema::CXXDestructor:
case Sema::CXXInvalid:
return false;
@@ -4307,15 +4524,22 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// If we squint, this is guaranteed, since exactly one non-static data member
// will be initialized (if the constructor isn't deleted), we just don't know
// which one.
- if (ClassDecl->isUnion())
+ if (Ctor && ClassDecl->isUnion())
return true;
// -- the class shall not have any virtual base classes;
- if (ClassDecl->getNumVBases())
+ if (Ctor && ClassDecl->getNumVBases())
+ return false;
+
+ // C++1y [class.copy]p26:
+ // -- [the class] is a literal type, and
+ if (!Ctor && !ClassDecl->isLiteral())
return false;
// -- every constructor involved in initializing [...] base class
// sub-objects shall be a constexpr constructor;
+ // -- the assignment operator selected to copy/move each direct base
+ // class is a constexpr function, and
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
BEnd = ClassDecl->bases_end();
B != BEnd; ++B) {
@@ -4331,6 +4555,9 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// [...] shall be a constexpr constructor;
// -- every non-static data member and base class sub-object shall be
// initialized
+ // -- for each non-stastic data member of X that is of class type (or array
+ // thereof), the assignment operator selected to copy/move that member is
+ // a constexpr function
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
@@ -4380,6 +4607,21 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FPT->getArgTypes(), EPI));
}
+static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
+ CXXMethodDecl *MD) {
+ FunctionProtoType::ExtProtoInfo EPI;
+
+ // Build an exception specification pointing back at this member.
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = MD;
+
+ // Set the calling convention to the default for C++ instance methods.
+ EPI.ExtInfo = EPI.ExtInfo.withCallingConv(
+ S.Context.getDefaultCallingConvention(/*IsVariadic=*/false,
+ /*IsCXXMethod=*/true));
+ return EPI;
+}
+
void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
if (FPT->getExceptionSpecType() != EST_Unevaluated)
@@ -4461,7 +4703,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// A defaulted special member cannot have cv-qualifiers.
if (Type->getTypeQuals()) {
Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
- << (CSM == CXXMoveAssignment);
+ << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus1y;
HadError = true;
}
}
@@ -4506,13 +4748,16 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// would have been implicitly declared as constexpr,
// Do not apply this rule to members of class templates, since core issue 1358
// makes such functions always instantiate to constexpr functions. For
- // non-constructors, this is checked elsewhere.
+ // functions which cannot be constexpr (for non-constructors in C++11 and for
+ // destructors in C++1y), this is checked elsewhere.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
- if (isa<CXXConstructorDecl>(MD) && MD->isConstexpr() && !Constexpr &&
+ if ((getLangOpts().CPlusPlus1y ? !isa<CXXDestructorDecl>(MD)
+ : isa<CXXConstructorDecl>(MD)) &&
+ MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM;
- // FIXME: Explain why the constructor can't be constexpr.
+ // FIXME: Explain why the special member can't be constexpr.
HadError = true;
}
@@ -4573,7 +4818,9 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
// Compute the implicit exception specification.
- FunctionProtoType::ExtProtoInfo EPI;
+ CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false,
+ /*IsCXXMethod=*/true);
+ FunctionProtoType::ExtProtoInfo EPI(CC);
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
Context.getFunctionType(Context.VoidTy, None, EPI));
@@ -4586,14 +4833,28 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
SpecifiedType, MD->getLocation());
}
-void Sema::CheckDelayedExplicitlyDefaultedMemberExceptionSpecs() {
- for (unsigned I = 0, N = DelayedDefaultedMemberExceptionSpecs.size();
- I != N; ++I)
- CheckExplicitlyDefaultedMemberExceptionSpec(
- DelayedDefaultedMemberExceptionSpecs[I].first,
- DelayedDefaultedMemberExceptionSpecs[I].second);
+void Sema::CheckDelayedMemberExceptionSpecs() {
+ SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>,
+ 2> Checks;
+ SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs;
- DelayedDefaultedMemberExceptionSpecs.clear();
+ std::swap(Checks, DelayedDestructorExceptionSpecChecks);
+ std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
+
+ // Perform any deferred checking of exception specifications for virtual
+ // destructors.
+ for (unsigned i = 0, e = Checks.size(); i != e; ++i) {
+ const CXXDestructorDecl *Dtor = Checks[i].first;
+ assert(!Dtor->getParent()->isDependentType() &&
+ "Should not ever add destructors of templates into the list.");
+ CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second);
+ }
+
+ // Check that any explicitly-defaulted methods have exception specifications
+ // compatible with their implicit exception specifications.
+ for (unsigned I = 0, N = Specs.size(); I != N; ++I)
+ CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first,
+ Specs[I].second);
}
namespace {
@@ -4652,6 +4913,10 @@ struct SpecialMemberDeletionInfo {
// cv-qualifiers on class members don't affect default ctor / dtor calls.
if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor)
Quals = 0;
+ // cv-qualifiers on class members affect the type of both '*this' and the
+ // argument for an assignment.
+ if (IsAssignment)
+ TQ |= Quals;
return S.LookupSpecialMember(Class, CSM,
ConstArg || (Quals & Qualifiers::Const),
VolatileArg || (Quals & Qualifiers::Volatile),
@@ -5015,10 +5280,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
SMI.shouldDeleteForBase(BI))
return true;
- for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end(); BI != BE; ++BI)
- if (SMI.shouldDeleteForBase(BI))
- return true;
+ // Per DR1611, do not consider virtual bases of constructors of abstract
+ // classes, since we are not going to construct them.
+ if (!RD->isAbstract() || !SMI.IsConstructor) {
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI)
+ if (SMI.shouldDeleteForBase(BI))
+ return true;
+ }
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end(); FI != FE; ++FI)
@@ -5310,9 +5580,9 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
bool ConstArg = false;
- // C++11 [class.copy]p12, p25:
- // A [special member] is trivial if its declared parameter type is the same
- // as if it had been implicitly declared [...]
+ // C++11 [class.copy]p12, p25: [DR1593]
+ // A [special member] is trivial if [...] its parameter-type-list is
+ // equivalent to the parameter-type-list of an implicit declaration [...]
switch (CSM) {
case CXXDefaultConstructor:
case CXXDestructor:
@@ -5356,11 +5626,6 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
llvm_unreachable("not a special member");
}
- // FIXME: We require that the parameter-declaration-clause is equivalent to
- // that of an implicit declaration, not just that the declared parameter type
- // matches, in order to prevent absuridities like a function simultaneously
- // being a trivial copy constructor and a non-trivial default constructor.
- // This issue has not yet been assigned a core issue number.
if (MD->getMinRequiredArguments() < MD->getNumParams()) {
if (Diagnose)
Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(),
@@ -5524,12 +5789,10 @@ static void AddMostOverridenMethods(const CXXMethodDecl *MD,
AddMostOverridenMethods(*I, Methods);
}
-/// \brief See if a method overloads virtual methods in a base class without
+/// \brief Check if a method overloads virtual methods in a base class without
/// overriding any.
-void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
- if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
- MD->getLocation()) == DiagnosticsEngine::Ignored)
- return;
+void Sema::FindHiddenVirtualMethods(CXXMethodDecl *MD,
+ SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods) {
if (!MD->getDeclName().isIdentifier())
return;
@@ -5542,6 +5805,7 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
// Keep the base methods that were overriden or introduced in the subclass
// by 'using' in a set. A base method not in this set is hidden.
+ CXXRecordDecl *DC = MD->getParent();
DeclContext::lookup_result R = DC->lookup(MD->getDeclName());
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *ND = *I;
@@ -5551,18 +5815,38 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
}
- if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) &&
- !Data.OverloadedMethods.empty()) {
+ if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths))
+ OverloadedMethods = Data.OverloadedMethods;
+}
+
+void Sema::NoteHiddenVirtualMethods(CXXMethodDecl *MD,
+ SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods) {
+ for (unsigned i = 0, e = OverloadedMethods.size(); i != e; ++i) {
+ CXXMethodDecl *overloadedMD = OverloadedMethods[i];
+ PartialDiagnostic PD = PDiag(
+ diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD;
+ HandleFunctionTypeMismatch(PD, MD->getType(), overloadedMD->getType());
+ Diag(overloadedMD->getLocation(), PD);
+ }
+}
+
+/// \brief Diagnose methods which overload virtual methods in a base class
+/// without overriding any.
+void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) {
+ if (MD->isInvalidDecl())
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
+ MD->getLocation()) == DiagnosticsEngine::Ignored)
+ return;
+
+ SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
+ FindHiddenVirtualMethods(MD, OverloadedMethods);
+ if (!OverloadedMethods.empty()) {
Diag(MD->getLocation(), diag::warn_overloaded_virtual)
- << MD << (Data.OverloadedMethods.size() > 1);
+ << MD << (OverloadedMethods.size() > 1);
- for (unsigned i = 0, e = Data.OverloadedMethods.size(); i != e; ++i) {
- CXXMethodDecl *overloadedMD = Data.OverloadedMethods[i];
- PartialDiagnostic PD = PDiag(
- diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD;
- HandleFunctionTypeMismatch(PD, MD->getType(), overloadedMD->getType());
- Diag(overloadedMD->getLocation(), PD);
- }
+ NoteHiddenVirtualMethods(MD, OverloadedMethods);
}
}
@@ -5877,7 +6161,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
- if (Destructor->isVirtual()) {
+ if (!Destructor->getOperatorDelete() && Destructor->isVirtual()) {
SourceLocation Loc;
if (!Destructor->isImplicit())
@@ -5891,6 +6175,10 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
return true;
+ // If there's no class-specific operator delete, look up the global
+ // non-array delete.
+ if (!OperatorDelete)
+ OperatorDelete = FindUsualDeallocationFunction(Loc, true, Name);
MarkFunctionReferenced(Loc, OperatorDelete);
@@ -6029,8 +6317,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
if (SC == SC_Static) {
if (!D.isInvalidType())
Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member)
- << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
- << SourceRange(D.getIdentifierLoc());
+ << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
+ << D.getName().getSourceRange();
D.setInvalidType();
SC = SC_None;
}
@@ -6541,11 +6829,10 @@ namespace {
// Callback to only accept typo corrections that are namespaces.
class NamespaceValidatorCCC : public CorrectionCandidateCallback {
- public:
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
- if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+public:
+ bool ValidateCandidate(const TypoCorrection &candidate) LLVM_OVERRIDE {
+ if (NamedDecl *ND = candidate.getCorrectionDecl())
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
- }
return false;
}
};
@@ -6561,21 +6848,19 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), Sc, &SS,
Validator)) {
- std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOpts()));
- if (DeclContext *DC = S.computeDeclContext(SS, false))
- S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << Ident << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- else
- S.Diag(IdentLoc, diag::err_using_directive_suggest)
- << Ident << CorrectedQuotedStr
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
-
- S.Diag(Corrected.getCorrectionDecl()->getLocation(),
- diag::note_namespace_defined_here) << CorrectedQuotedStr;
-
+ if (DeclContext *DC = S.computeDeclContext(SS, false)) {
+ std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
+ bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
+ Ident->getName().equals(CorrectedStr);
+ S.diagnoseTypo(Corrected,
+ S.PDiag(diag::err_using_directive_member_suggest)
+ << Ident << DC << DroppedSpecifier << SS.getRange(),
+ S.PDiag(diag::note_namespace_defined_here));
+ } else {
+ S.diagnoseTypo(Corrected,
+ S.PDiag(diag::err_using_directive_suggest) << Ident,
+ S.PDiag(diag::note_namespace_defined_here));
+ }
R.addDecl(Corrected.getCorrectionDecl());
return true;
}
@@ -6649,7 +6934,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
IdentLoc, Named, CommonAncestor);
if (IsUsingDirectiveInToplevelContext(CurContext) &&
- !SourceMgr.isFromMainFile(SourceMgr.getExpansionLoc(IdentLoc))) {
+ !SourceMgr.isInMainFile(SourceMgr.getExpansionLoc(IdentLoc))) {
Diag(IdentLoc, diag::warn_using_directive_in_header);
}
@@ -6668,7 +6953,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
// If the scope has an associated entity and the using directive is at
// namespace or translation unit scope, add the UsingDirectiveDecl into
// its lookup structure so qualified name lookup can find it.
- DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ DeclContext *Ctx = S->getEntity();
if (Ctx && !Ctx->isFunctionOrMethod())
Ctx->addDecl(UDir);
else
@@ -6685,7 +6970,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName,
+ bool HasTypenameKeyword,
SourceLocation TypenameLoc) {
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
@@ -6727,13 +7012,10 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
return 0;
// Warn about access declarations.
- // TODO: store that the declaration was written without 'using' and
- // talk about access decls instead of using decls in the
- // diagnostics.
if (!HasUsingKeyword) {
- UsingLoc = Name.getLocStart();
-
- Diag(UsingLoc, diag::warn_access_decl_deprecated)
+ Diag(Name.getLocStart(),
+ getLangOpts().CPlusPlus11 ? diag::err_access_decl
+ : diag::warn_access_decl_deprecated)
<< FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
}
@@ -6744,7 +7026,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
TargetNameInfo, AttrList,
/* IsInstantiation */ false,
- IsTypeName, TypenameLoc);
+ HasTypenameKeyword, TypenameLoc);
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
@@ -6754,20 +7036,15 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
/// \brief Determine whether a using declaration considers the given
/// declarations as "equivalent", e.g., if they are redeclarations of
/// the same entity or are both typedefs of the same type.
-static bool
-IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2,
- bool &SuppressRedeclaration) {
- if (D1->getCanonicalDecl() == D2->getCanonicalDecl()) {
- SuppressRedeclaration = false;
+static bool
+IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2) {
+ if (D1->getCanonicalDecl() == D2->getCanonicalDecl())
return true;
- }
if (TypedefNameDecl *TD1 = dyn_cast<TypedefNameDecl>(D1))
- if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2)) {
- SuppressRedeclaration = true;
+ if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2))
return Context.hasSameType(TD1->getUnderlyingType(),
TD2->getUnderlyingType());
- }
return false;
}
@@ -6776,7 +7053,8 @@ IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2,
/// Determines whether to create a using shadow decl for a particular
/// decl, given the set of decls existing prior to this using lookup.
bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
- const LookupResult &Previous) {
+ const LookupResult &Previous,
+ UsingShadowDecl *&PrevShadow) {
// Diagnose finding a decl which is not from a base class of the
// current class. We do this now because there are cases where this
// function will silently decide not to build a shadow decl, which
@@ -6836,16 +7114,22 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// FIXME: but we might be increasing its access, in which case we
// should redeclare it.
NamedDecl *NonTag = 0, *Tag = 0;
+ bool FoundEquivalentDecl = false;
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
- bool Result;
- if (IsEquivalentForUsingDecl(Context, D, Target, Result))
- return Result;
+ if (IsEquivalentForUsingDecl(Context, D, Target)) {
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
+ PrevShadow = Shadow;
+ FoundEquivalentDecl = true;
+ }
(isa<TagDecl>(D) ? Tag : NonTag) = D;
}
+ if (FoundEquivalentDecl)
+ return false;
+
if (Target->isFunctionOrFunctionTemplate()) {
FunctionDecl *FD;
if (isa<FunctionTemplateDecl>(Target))
@@ -6904,7 +7188,8 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
/// Builds a shadow declaration corresponding to a 'using' declaration.
UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
UsingDecl *UD,
- NamedDecl *Orig) {
+ NamedDecl *Orig,
+ UsingShadowDecl *PrevDecl) {
// If we resolved to another shadow declaration, just coalesce them.
NamedDecl *Target = Orig;
@@ -6912,16 +7197,18 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
Target = cast<UsingShadowDecl>(Target)->getTargetDecl();
assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
-
+
UsingShadowDecl *Shadow
= UsingShadowDecl::Create(Context, CurContext,
UD->getLocation(), UD, Target);
UD->addShadowDecl(Shadow);
-
+
Shadow->setAccess(UD->getAccess());
if (Orig->isInvalidDecl() || UD->isInvalidDecl())
Shadow->setInvalidDecl();
-
+
+ Shadow->setPreviousDecl(PrevDecl);
+
if (S)
PushOnScopeChains(Shadow, S);
else
@@ -6979,6 +7266,42 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
// be possible for this to happen, because...?
}
+namespace {
+class UsingValidatorCCC : public CorrectionCandidateCallback {
+public:
+ UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation,
+ bool RequireMember)
+ : HasTypenameKeyword(HasTypenameKeyword),
+ IsInstantiation(IsInstantiation), RequireMember(RequireMember) {}
+
+ bool ValidateCandidate(const TypoCorrection &Candidate) LLVM_OVERRIDE {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+
+ // Keywords are not valid here.
+ if (!ND || isa<NamespaceDecl>(ND))
+ return false;
+
+ if (RequireMember && !isa<FieldDecl>(ND) && !isa<CXXMethodDecl>(ND) &&
+ !isa<TypeDecl>(ND))
+ return false;
+
+ // Completely unqualified names are invalid for a 'using' declaration.
+ if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
+ return false;
+
+ if (isa<TypeDecl>(ND))
+ return HasTypenameKeyword || !IsInstantiation;
+
+ return !HasTypenameKeyword;
+ }
+
+private:
+ bool HasTypenameKeyword;
+ bool IsInstantiation;
+ bool RequireMember;
+};
+} // end anonymous namespace
+
/// Builds a using declaration.
///
/// \param IsInstantiation - Whether this call arises from an
@@ -6990,7 +7313,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
const DeclarationNameInfo &NameInfo,
AttributeList *AttrList,
bool IsInstantiation,
- bool IsTypeName,
+ bool HasTypenameKeyword,
SourceLocation TypenameLoc) {
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
SourceLocation IdentLoc = NameInfo.getLoc();
@@ -7025,7 +7348,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
// Check for invalid redeclarations.
- if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
+ if (CheckUsingDeclRedeclaration(UsingLoc, HasTypenameKeyword,
+ SS, IdentLoc, Previous))
return 0;
// Check for bad qualifiers.
@@ -7036,7 +7360,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
NamedDecl *D;
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
if (!LookupContext) {
- if (IsTypeName) {
+ if (HasTypenameKeyword) {
// FIXME: not all declaration name kinds are legal here
D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
UsingLoc, TypenameLoc,
@@ -7048,7 +7372,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
} else {
D = UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
- NameInfo, IsTypeName);
+ NameInfo, HasTypenameKeyword);
}
D->setAccess(AS);
CurContext->addDecl(D);
@@ -7088,11 +7412,27 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
LookupQualifiedName(R, LookupContext);
+ // Try to correct typos if possible.
if (R.empty()) {
- Diag(IdentLoc, diag::err_no_member)
- << NameInfo.getName() << LookupContext << SS.getRange();
- UD->setInvalidDecl();
- return UD;
+ UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
+ CurContext->isRecord());
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), S, &SS, CCC)){
+ // We reject any correction for which ND would be NULL.
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ R.setLookupName(Corrected.getCorrection());
+ R.addDecl(ND);
+ // We reject candidates where DroppedSpecifier == true, hence the
+ // literal '0' below.
+ diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
+ << NameInfo.getName() << LookupContext << 0
+ << SS.getRange());
+ } else {
+ Diag(IdentLoc, diag::err_no_member)
+ << NameInfo.getName() << LookupContext << SS.getRange();
+ UD->setInvalidDecl();
+ return UD;
+ }
}
if (R.isAmbiguous()) {
@@ -7100,7 +7440,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return UD;
}
- if (IsTypeName) {
+ if (HasTypenameKeyword) {
// If we asked for a typename and got a non-type decl, error out.
if (!R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_typename_non_type);
@@ -7132,8 +7472,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- if (!CheckUsingShadowDecl(UD, *I, Previous))
- BuildUsingShadowDecl(S, UD, *I);
+ UsingShadowDecl *PrevDecl = 0;
+ if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
+ BuildUsingShadowDecl(S, UD, *I, PrevDecl);
}
return UD;
@@ -7141,7 +7482,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
/// Additional checks for a using declaration referring to a constructor name.
bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
- assert(!UD->isTypeName() && "expecting a constructor name");
+ assert(!UD->hasTypename() && "expecting a constructor name");
const Type *SourceType = UD->getQualifier()->getAsType();
assert(SourceType &&
@@ -7162,7 +7503,7 @@ bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
if (BaseIt == BaseE) {
// Did not find SourceType in the bases.
- Diag(UD->getUsingLocation(),
+ Diag(UD->getUsingLoc(),
diag::err_using_decl_constructor_not_in_direct_base)
<< UD->getNameInfo().getSourceRange()
<< QualType(SourceType, 0) << TargetClass;
@@ -7179,7 +7520,7 @@ bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
/// redeclaration. Note that this is checking only for the using decl
/// itself, not for any ill-formedness among the UsingShadowDecls.
bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
- bool isTypeName,
+ bool HasTypenameKeyword,
const CXXScopeSpec &SS,
SourceLocation NameLoc,
const LookupResult &Prev) {
@@ -7202,7 +7543,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
bool DTypename;
NestedNameSpecifier *DQual;
if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
- DTypename = UD->isTypeName();
+ DTypename = UD->hasTypename();
DQual = UD->getQualifier();
} else if (UnresolvedUsingValueDecl *UD
= dyn_cast<UnresolvedUsingValueDecl>(D)) {
@@ -7216,7 +7557,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
// using decls differ if one says 'typename' and the other doesn't.
// FIXME: non-dependent using decls?
- if (isTypeName != DTypename) continue;
+ if (HasTypenameKeyword != DTypename) continue;
// using decls differ if they name different scopes (but note that
// template instantiation can cause this check to trigger when it
@@ -7498,7 +7839,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewDecl->setInvalidDecl();
else if (OldDecl)
- NewDecl->setPreviousDeclaration(OldDecl);
+ NewDecl->setPreviousDecl(OldDecl);
NewND = NewDecl;
} else {
@@ -7788,9 +8129,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setImplicit();
// Build an exception specification pointing back at this constructor.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = DefaultCon;
+ FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon);
DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
// We don't need to use SpecialMemberIsTrivial here; triviality for default
@@ -7833,18 +8172,19 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
SourceLocation Loc = Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
- Constructor->setUsed();
+ Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
+
+ DiagnoseUninitializedFields(*this, Constructor);
}
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
- // Check that any explicitly-defaulted methods have exception specifications
- // compatible with their implicit exception specifications.
- CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
+ // Perform any delayed checks on exception specifications.
+ CheckDelayedMemberExceptionSpecs();
}
namespace {
@@ -7887,8 +8227,8 @@ private:
/// constructors.
struct InheritingConstructorsForType {
InheritingConstructor NonTemplate;
- llvm::SmallVector<
- std::pair<TemplateParameterList*, InheritingConstructor>, 4> Templates;
+ SmallVector<std::pair<TemplateParameterList *, InheritingConstructor>, 4>
+ Templates;
InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) {
if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) {
@@ -8171,7 +8511,7 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
SourceLocation Loc = Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
- Constructor->setUsed();
+ Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -8252,9 +8592,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setImplicit();
// Build an exception specification pointing back at this destructor.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = Destructor;
+ FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
AddOverriddenMethods(ClassDecl, Destructor);
@@ -8305,8 +8643,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
SourceLocation Loc = Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc));
- Destructor->setImplicitlyDefined(true);
- Destructor->setUsed();
+ Destructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -8320,23 +8657,11 @@ void Sema::ActOnFinishCXXMemberDecls() {
// If the context is an invalid C++ class, just suppress these checks.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
if (Record->isInvalidDecl()) {
+ DelayedDefaultedMemberExceptionSpecs.clear();
DelayedDestructorExceptionSpecChecks.clear();
return;
}
}
-
- // Perform any deferred checking of exception specifications for virtual
- // destructors.
- for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
- i != e; ++i) {
- const CXXDestructorDecl *Dtor =
- DelayedDestructorExceptionSpecChecks[i].first;
- assert(!Dtor->getParent()->isDependentType() &&
- "Should not ever add destructors of templates into the list.");
- CheckOverridingFunctionExceptionSpec(Dtor,
- DelayedDestructorExceptionSpecChecks[i].second);
- }
- DelayedDestructorExceptionSpecChecks.clear();
}
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
@@ -8368,13 +8693,144 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
// needs to be done somewhere else.
}
+namespace {
+/// \brief An abstract base class for all helper classes used in building the
+// copy/move operators. These classes serve as factory functions and help us
+// avoid using the same Expr* in the AST twice.
+class ExprBuilder {
+ ExprBuilder(const ExprBuilder&) LLVM_DELETED_FUNCTION;
+ ExprBuilder &operator=(const ExprBuilder&) LLVM_DELETED_FUNCTION;
+
+protected:
+ static Expr *assertNotNull(Expr *E) {
+ assert(E && "Expression construction must not fail.");
+ return E;
+ }
+
+public:
+ ExprBuilder() {}
+ virtual ~ExprBuilder() {}
+
+ virtual Expr *build(Sema &S, SourceLocation Loc) const = 0;
+};
+
+class RefBuilder: public ExprBuilder {
+ VarDecl *Var;
+ QualType VarType;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).take());
+ }
+
+ RefBuilder(VarDecl *Var, QualType VarType)
+ : Var(Var), VarType(VarType) {}
+};
+
+class ThisBuilder: public ExprBuilder {
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(S.ActOnCXXThis(Loc).takeAs<Expr>());
+ }
+};
+
+class CastBuilder: public ExprBuilder {
+ const ExprBuilder &Builder;
+ QualType Type;
+ ExprValueKind Kind;
+ const CXXCastPath &Path;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(S.ImpCastExprToType(Builder.build(S, Loc), Type,
+ CK_UncheckedDerivedToBase, Kind,
+ &Path).take());
+ }
+
+ CastBuilder(const ExprBuilder &Builder, QualType Type, ExprValueKind Kind,
+ const CXXCastPath &Path)
+ : Builder(Builder), Type(Type), Kind(Kind), Path(Path) {}
+};
+
+class DerefBuilder: public ExprBuilder {
+ const ExprBuilder &Builder;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(
+ S.CreateBuiltinUnaryOp(Loc, UO_Deref, Builder.build(S, Loc)).take());
+ }
+
+ DerefBuilder(const ExprBuilder &Builder) : Builder(Builder) {}
+};
+
+class MemberBuilder: public ExprBuilder {
+ const ExprBuilder &Builder;
+ QualType Type;
+ CXXScopeSpec SS;
+ bool IsArrow;
+ LookupResult &MemberLookup;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(S.BuildMemberReferenceExpr(
+ Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(), 0,
+ MemberLookup, 0).take());
+ }
+
+ MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow,
+ LookupResult &MemberLookup)
+ : Builder(Builder), Type(Type), IsArrow(IsArrow),
+ MemberLookup(MemberLookup) {}
+};
+
+class MoveCastBuilder: public ExprBuilder {
+ const ExprBuilder &Builder;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(CastForMoving(S, Builder.build(S, Loc)));
+ }
+
+ MoveCastBuilder(const ExprBuilder &Builder) : Builder(Builder) {}
+};
+
+class LvalueConvBuilder: public ExprBuilder {
+ const ExprBuilder &Builder;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ return assertNotNull(
+ S.DefaultLvalueConversion(Builder.build(S, Loc)).take());
+ }
+
+ LvalueConvBuilder(const ExprBuilder &Builder) : Builder(Builder) {}
+};
+
+class SubscriptBuilder: public ExprBuilder {
+ const ExprBuilder &Base;
+ const ExprBuilder &Index;
+
+public:
+ virtual Expr *build(Sema &S, SourceLocation Loc) const
+ LLVM_OVERRIDE {
+ return assertNotNull(S.CreateBuiltinArraySubscriptExpr(
+ Base.build(S, Loc), Loc, Index.build(S, Loc), Loc).take());
+ }
+
+ SubscriptBuilder(const ExprBuilder &Base, const ExprBuilder &Index)
+ : Base(Base), Index(Index) {}
+};
+
+} // end anonymous namespace
+
/// When generating a defaulted copy or move assignment operator, if a field
/// should be copied with __builtin_memcpy rather than via explicit assignments,
/// do so. This optimization only applies for arrays of scalars, and for arrays
/// of class type where the selected copy/move-assignment operator is trivial.
static StmtResult
buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
- Expr *To, Expr *From) {
+ const ExprBuilder &ToB, const ExprBuilder &FromB) {
// Compute the size of the memory buffer to be copied.
QualType SizeType = S.Context.getSizeType();
llvm::APInt Size(S.Context.getTypeSize(SizeType),
@@ -8383,9 +8839,11 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
// Take the address of the field references for "from" and "to". We
// directly construct UnaryOperators here because semantic analysis
// does not permit us to take the address of an xvalue.
+ Expr *From = FromB.build(S, Loc);
From = new (S.Context) UnaryOperator(From, UO_AddrOf,
S.Context.getPointerType(From->getType()),
VK_RValue, OK_Ordinary, Loc);
+ Expr *To = ToB.build(S, Loc);
To = new (S.Context) UnaryOperator(To, UO_AddrOf,
S.Context.getPointerType(To->getType()),
VK_RValue, OK_Ordinary, Loc);
@@ -8451,7 +8909,7 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
/// if a memcpy should be used instead.
static StmtResult
buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
- Expr *To, Expr *From,
+ const ExprBuilder &To, const ExprBuilder &From,
bool CopyingBaseSubobject, bool Copying,
unsigned Depth = 0) {
// C++11 [class.copy]p28:
@@ -8524,8 +8982,8 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Create the reference to operator=.
ExprResult OpEqualRef
- = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
- /*TemplateKWLoc=*/SourceLocation(),
+ = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*isArrow=*/false,
+ SS, /*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/0,
OpLookup,
/*TemplateArgs=*/0,
@@ -8535,9 +8993,10 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Build the call to the assignment operator.
+ Expr *FromInst = From.build(S, Loc);
ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
OpEqualRef.takeAs<Expr>(),
- Loc, &From, 1, Loc);
+ Loc, FromInst, Loc);
if (Call.isInvalid())
return StmtError();
@@ -8556,7 +9015,8 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// operator is used.
const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
if (!ArrayTy) {
- ExprResult Assignment = S.CreateBuiltinBinOp(Loc, BO_Assign, To, From);
+ ExprResult Assignment = S.CreateBuiltinBinOp(
+ Loc, BO_Assign, To.build(S, Loc), From.build(S, Loc));
if (Assignment.isInvalid())
return StmtError();
return S.ActOnExprStmt(Assignment);
@@ -8589,31 +9049,28 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
- // Create a reference to the iteration variable; we'll use this several
- // times throughout.
- Expr *IterationVarRef
- = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc).take();
- assert(IterationVarRef && "Reference to invented variable cannot fail!");
- Expr *IterationVarRefRVal = S.DefaultLvalueConversion(IterationVarRef).take();
- assert(IterationVarRefRVal && "Conversion of invented variable cannot fail!");
+ // Creates a reference to the iteration variable.
+ RefBuilder IterationVarRef(IterationVar, SizeType);
+ LvalueConvBuilder IterationVarRefRVal(IterationVarRef);
// Create the DeclStmt that holds the iteration variable.
Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
// Subscript the "from" and "to" expressions with the iteration variable.
- From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
- IterationVarRefRVal,
- Loc));
- To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
- IterationVarRefRVal,
- Loc));
- if (!Copying) // Cast to rvalue
- From = CastForMoving(S, From);
+ SubscriptBuilder FromIndexCopy(From, IterationVarRefRVal);
+ MoveCastBuilder FromIndexMove(FromIndexCopy);
+ const ExprBuilder *FromIndex;
+ if (Copying)
+ FromIndex = &FromIndexCopy;
+ else
+ FromIndex = &FromIndexMove;
+
+ SubscriptBuilder ToIndex(To, IterationVarRefRVal);
// Build the copy/move for an individual element of the array.
StmtResult Copy =
buildSingleCopyAssignRecursively(S, Loc, ArrayTy->getElementType(),
- To, From, CopyingBaseSubobject,
+ ToIndex, *FromIndex, CopyingBaseSubobject,
Copying, Depth + 1);
// Bail out if copying fails or if we determined that we should use memcpy.
if (Copy.isInvalid() || !Copy.get())
@@ -8623,15 +9080,15 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
llvm::APInt Upper
= ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType));
Expr *Comparison
- = new (S.Context) BinaryOperator(IterationVarRefRVal,
+ = 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);
// Create the pre-increment of the iteration variable.
Expr *Increment
- = new (S.Context) UnaryOperator(IterationVarRef, UO_PreInc, SizeType,
- VK_LValue, OK_Ordinary, Loc);
+ = new (S.Context) UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc,
+ SizeType, VK_LValue, OK_Ordinary, Loc);
// Construct the loop that copies all elements of this array.
return S.ActOnForStmt(Loc, Loc, InitStmt,
@@ -8642,7 +9099,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
static StmtResult
buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
- Expr *To, Expr *From,
+ const ExprBuilder &To, const ExprBuilder &From,
bool CopyingBaseSubobject, bool Copying) {
// Maybe we should use a memcpy?
if (T->isArrayType() && !T.isConstQualified() && !T.isVolatileQualified() &&
@@ -8736,29 +9193,31 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
- if (ClassDecl->implicitCopyAssignmentHasConstParam())
+ bool Const = ClassDecl->implicitCopyAssignmentHasConstParam();
+ if (Const)
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXCopyAssignment,
+ Const);
+
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *CopyAssignment
- = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0,
- /*StorageClass=*/SC_None,
- /*isInline=*/true, /*isConstexpr=*/false,
- SourceLocation());
+ CXXMethodDecl *CopyAssignment =
+ CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/ 0, /*StorageClass=*/ SC_None,
+ /*isInline=*/ true, Constexpr, SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
// Build an exception specification pointing back at this member.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = CopyAssignment;
+ FunctionProtoType::ExtProtoInfo EPI =
+ getImplicitMethodEPI(*this, CopyAssignment);
CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
@@ -8775,11 +9234,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
: ClassDecl->hasTrivialCopyAssignment());
- // C++0x [class.copy]p19:
- // .... If the class definition does not explicitly declare a copy
- // assignment operator, there is no user-declared move constructor, and
- // there is no user-declared move assignment operator, a copy assignment
- // operator is implicitly declared as defaulted.
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
SetDeclDeleted(CopyAssignment, ClassLoc);
@@ -8793,6 +9247,58 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return CopyAssignment;
}
+/// 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) {
+ assert(CopyOp->isImplicit());
+
+ CXXRecordDecl *RD = CopyOp->getParent();
+ CXXMethodDecl *UserDeclaredOperation = 0;
+
+ // In Microsoft mode, assignment operations don't affect constructors and
+ // vice versa.
+ if (RD->hasUserDeclaredDestructor()) {
+ UserDeclaredOperation = RD->getDestructor();
+ } else if (!isa<CXXConstructorDecl>(CopyOp) &&
+ RD->hasUserDeclaredCopyConstructor() &&
+ !S.getLangOpts().MicrosoftMode) {
+ // Find any user-declared copy constructor.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
+ E = RD->ctor_end(); I != E; ++I) {
+ if (I->isCopyConstructor()) {
+ UserDeclaredOperation = *I;
+ break;
+ }
+ }
+ assert(UserDeclaredOperation);
+ } else if (isa<CXXConstructorDecl>(CopyOp) &&
+ RD->hasUserDeclaredCopyAssignment() &&
+ !S.getLangOpts().MicrosoftMode) {
+ // Find any user-declared move assignment operator.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ if (I->isCopyAssignmentOperator()) {
+ UserDeclaredOperation = *I;
+ break;
+ }
+ }
+ assert(UserDeclaredOperation);
+ }
+
+ if (UserDeclaredOperation) {
+ S.Diag(UserDeclaredOperation->getLocation(),
+ 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() &&
@@ -8808,8 +9314,15 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setInvalidDecl();
return;
}
-
- CopyAssignOperator->setUsed();
+
+ // 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);
@@ -8838,15 +9351,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Our location for everything implicitly-generated.
SourceLocation Loc = CopyAssignOperator->getLocation();
- // Construct a reference to the "other" object. We'll be using this
- // throughout the generated ASTs.
- Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take();
- assert(OtherRef && "Reference to parameter cannot fail!");
-
- // Construct the "this" pointer. We'll be using this throughout the generated
- // ASTs.
- Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
- assert(This && "Reference to this cannot fail!");
+ // Builds a DeclRefExpr for the "other" object.
+ RefBuilder OtherRef(Other, OtherRefType);
+
+ // Builds the "this" pointer.
+ ThisBuilder This;
// Assign base classes.
bool Invalid = false;
@@ -8865,24 +9374,19 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Construct the "from" expression, which is an implicit cast to the
// appropriately-qualified base type.
- Expr *From = OtherRef;
- From = ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath).take();
+ CastBuilder From(OtherRef, Context.getQualifiedType(BaseType, OtherQuals),
+ VK_LValue, BasePath);
// Dereference "this".
- ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
-
- // Implicitly cast "this" to the appropriately-qualified base type.
- To = ImpCastExprToType(To.take(),
- Context.getCVRQualifiedType(BaseType,
- CopyAssignOperator->getTypeQualifiers()),
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath);
+ DerefBuilder DerefThis(This);
+ CastBuilder To(DerefThis,
+ Context.getCVRQualifiedType(
+ BaseType, CopyAssignOperator->getTypeQualifiers()),
+ VK_LValue, BasePath);
// Build the copy.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, BaseType,
- To.get(), From,
+ To, From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/true);
if (Copy.isInvalid()) {
@@ -8902,7 +9406,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Field != FieldEnd; ++Field) {
if (Field->isUnnamedBitfield())
continue;
-
+
+ if (Field->isInvalidDecl()) {
+ Invalid = true;
+ continue;
+ }
+
// Check for members of reference type; we can't copy those.
if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
@@ -8943,20 +9452,14 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
LookupMemberName);
MemberLookup.addDecl(*Field);
MemberLookup.resolveKind();
- ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType,
- Loc, /*IsArrow=*/false,
- SS, SourceLocation(), 0,
- MemberLookup, 0);
- ExprResult To = BuildMemberReferenceExpr(This, This->getType(),
- Loc, /*IsArrow=*/true,
- SS, SourceLocation(), 0,
- MemberLookup, 0);
- assert(!From.isInvalid() && "Implicit field reference cannot fail");
- assert(!To.isInvalid() && "Implicit field reference cannot fail");
+
+ MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup);
+
+ MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup);
// Build the copy of this field.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
- To.get(), From.get(),
+ To, From,
/*CopyingBaseSubobject=*/false,
/*Copying=*/true);
if (Copy.isInvalid()) {
@@ -8972,7 +9475,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+ ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
@@ -9067,120 +9570,13 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
return ExceptSpec;
}
-/// Determine whether the class type has any direct or indirect virtual base
-/// classes which have a non-trivial move assignment operator.
-static bool
-hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- CXXRecordDecl *BaseClass =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- // Try to declare the move assignment. If it would be deleted, then the
- // class does not have a non-trivial move assignment.
- if (BaseClass->needsImplicitMoveAssignment())
- S.DeclareImplicitMoveAssignment(BaseClass);
-
- if (BaseClass->hasNonTrivialMoveAssignment())
- return true;
- }
-
- return false;
-}
-
-/// Determine whether the given type either has a move constructor or is
-/// trivially copyable.
-static bool
-hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
- Type = S.Context.getBaseElementType(Type);
-
- // FIXME: Technically, non-trivially-copyable non-class types, such as
- // reference types, are supposed to return false here, but that appears
- // to be a standard defect.
- CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl || !ClassDecl->getDefinition() || ClassDecl->isInvalidDecl())
- return true;
-
- if (Type.isTriviallyCopyableType(S.Context))
- return true;
-
- if (IsConstructor) {
- // FIXME: Need this because otherwise hasMoveConstructor isn't guaranteed to
- // give the right answer.
- if (ClassDecl->needsImplicitMoveConstructor())
- S.DeclareImplicitMoveConstructor(ClassDecl);
- return ClassDecl->hasMoveConstructor();
- }
-
- // FIXME: Need this because otherwise hasMoveAssignment isn't guaranteed to
- // give the right answer.
- if (ClassDecl->needsImplicitMoveAssignment())
- S.DeclareImplicitMoveAssignment(ClassDecl);
- return ClassDecl->hasMoveAssignment();
-}
-
-/// Determine whether all non-static data members and direct or virtual bases
-/// of class \p ClassDecl have either a move operation, or are trivially
-/// copyable.
-static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl,
- bool IsConstructor) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- if (Base->isVirtual())
- continue;
-
- if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
- return false;
- }
-
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
- return false;
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(), IsConstructor))
- return false;
- }
-
- return true;
-}
-
CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
- // C++11 [class.copy]p20:
- // If the definition of a class X does not explicitly declare a move
- // assignment operator, one will be implicitly declared as defaulted
- // if and only if:
- //
- // - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveAssignment());
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
if (DSM.isAlreadyBeingDeclared())
return 0;
- // [Checked after we build the declaration]
- // - the move assignment operator would not be implicitly defined as
- // deleted,
-
- // [DR1402]:
- // - X has no direct or indirect virtual base class with a non-trivial
- // move assignment operator, and
- // - each of X's non-static data members and direct or virtual base classes
- // has a type that either has a move assignment operator or is trivially
- // copyable.
- if (hasVirtualBaseWithNonTrivialMoveAssignment(*this, ClassDecl) ||
- !subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl,/*Constructor*/false)) {
- ClassDecl->setFailedImplicitMoveAssignment();
- return 0;
- }
-
// Note: The following rules are largely analoguous to the move
// constructor rules.
@@ -9188,26 +9584,26 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
QualType RetType = Context.getLValueReferenceType(ArgType);
ArgType = Context.getRValueReferenceType(ArgType);
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXMoveAssignment,
+ false);
+
// An implicitly-declared move assignment operator is an inline public
// member of its class.
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *MoveAssignment
- = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0,
- /*StorageClass=*/SC_None,
- /*isInline=*/true,
- /*isConstexpr=*/false,
- SourceLocation());
+ CXXMethodDecl *MoveAssignment =
+ CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/0, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr, SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
// Build an exception specification pointing back at this member.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = MoveAssignment;
+ FunctionProtoType::ExtProtoInfo EPI =
+ getImplicitMethodEPI(*this, MoveAssignment);
MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
@@ -9224,18 +9620,9 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
: ClassDecl->hasTrivialMoveAssignment());
- // C++0x [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // assignment operator, one will be implicitly declared as defaulted if and
- // only if:
- // [...]
- // - the move assignment operator would not be implicitly defined as
- // deleted.
if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
- // Cache this result so that we don't try to generate this over and over
- // on every lookup, leaking memory and wasting time.
- ClassDecl->setFailedImplicitMoveAssignment();
- return 0;
+ ClassDecl->setImplicitMoveAssignmentIsDeleted();
+ SetDeclDeleted(MoveAssignment, ClassLoc);
}
// Note that we have added this copy-assignment operator.
@@ -9248,6 +9635,94 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
return MoveAssignment;
}
+/// Check if we're implicitly defining a move assignment operator for a class
+/// with virtual bases. Such a move assignment might move-assign the virtual
+/// base multiple times.
+static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
+ SourceLocation CurrentLocation) {
+ assert(!Class->isDependentContext() && "should not define dependent move");
+
+ // Only a virtual base could get implicitly move-assigned multiple times.
+ // Only a non-trivial move assignment can observe this. We only want to
+ // diagnose if we implicitly define an assignment operator that assigns
+ // two base classes, both of which move-assign the same virtual base.
+ if (Class->getNumVBases() == 0 || Class->hasTrivialMoveAssignment() ||
+ Class->getNumBases() < 2)
+ return;
+
+ llvm::SmallVector<CXXBaseSpecifier *, 16> Worklist;
+ typedef llvm::DenseMap<CXXRecordDecl*, CXXBaseSpecifier*> VBaseMap;
+ VBaseMap VBases;
+
+ for (CXXRecordDecl::base_class_iterator BI = Class->bases_begin(),
+ BE = Class->bases_end();
+ BI != BE; ++BI) {
+ Worklist.push_back(&*BI);
+ while (!Worklist.empty()) {
+ CXXBaseSpecifier *BaseSpec = Worklist.pop_back_val();
+ CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
+
+ // If the base has no non-trivial move assignment operators,
+ // we don't care about moves from it.
+ if (!Base->hasNonTrivialMoveAssignment())
+ continue;
+
+ // If there's nothing virtual here, skip it.
+ if (!BaseSpec->isVirtual() && !Base->getNumVBases())
+ continue;
+
+ // If we're not actually going to call a move assignment for this base,
+ // or the selected move assignment is trivial, skip it.
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(Base, Sema::CXXMoveAssignment,
+ /*ConstArg*/false, /*VolatileArg*/false,
+ /*RValueThis*/true, /*ConstThis*/false,
+ /*VolatileThis*/false);
+ if (!SMOR->getMethod() || SMOR->getMethod()->isTrivial() ||
+ !SMOR->getMethod()->isMoveAssignmentOperator())
+ continue;
+
+ if (BaseSpec->isVirtual()) {
+ // We're going to move-assign this virtual base, and its move
+ // assignment operator is not trivial. If this can happen for
+ // multiple distinct direct bases of Class, diagnose it. (If it
+ // only happens in one base, we'll diagnose it when synthesizing
+ // that base class's move assignment operator.)
+ CXXBaseSpecifier *&Existing =
+ VBases.insert(std::make_pair(Base->getCanonicalDecl(), BI))
+ .first->second;
+ if (Existing && Existing != BI) {
+ S.Diag(CurrentLocation, diag::warn_vbase_moved_multiple_times)
+ << Class << Base;
+ S.Diag(Existing->getLocStart(), diag::note_vbase_moved_here)
+ << (Base->getCanonicalDecl() ==
+ Existing->getType()->getAsCXXRecordDecl()->getCanonicalDecl())
+ << Base << Existing->getType() << Existing->getSourceRange();
+ S.Diag(BI->getLocStart(), diag::note_vbase_moved_here)
+ << (Base->getCanonicalDecl() ==
+ BI->getType()->getAsCXXRecordDecl()->getCanonicalDecl())
+ << Base << BI->getType() << BaseSpec->getSourceRange();
+
+ // Only diagnose each vbase once.
+ Existing = 0;
+ }
+ } else {
+ // Only walk over bases that have defaulted move assignment operators.
+ // We assume that any user-provided move assignment operator handles
+ // the multiple-moves-of-vbase case itself somehow.
+ if (!SMOR->getMethod()->isDefaulted())
+ continue;
+
+ // We're going to move the base classes of Base. Add them to the list.
+ for (CXXRecordDecl::base_class_iterator BI = Base->bases_begin(),
+ BE = Base->bases_end();
+ BI != BE; ++BI)
+ Worklist.push_back(&*BI);
+ }
+ }
+ }
+}
+
void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MoveAssignOperator) {
assert((MoveAssignOperator->isDefaulted() &&
@@ -9264,7 +9739,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
return;
}
- MoveAssignOperator->setUsed();
+ MoveAssignOperator->markUsed(Context);
SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
DiagnosticErrorTrap Trap(Diags);
@@ -9277,6 +9752,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// are assigned, in the order in which they were declared in the class
// definition.
+ // Issue a warning if our implicit move assignment operator will move
+ // from a virtual base more than once.
+ checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation);
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
@@ -9284,28 +9763,32 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
QualType OtherRefType = Other->getType()->
getAs<RValueReferenceType>()->getPointeeType();
- assert(OtherRefType.getQualifiers() == 0 &&
+ assert(!OtherRefType.getQualifiers() &&
"Bad argument type of defaulted move assignment");
// Our location for everything implicitly-generated.
SourceLocation Loc = MoveAssignOperator->getLocation();
- // Construct a reference to the "other" object. We'll be using this
- // throughout the generated ASTs.
- Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take();
- assert(OtherRef && "Reference to parameter cannot fail!");
+ // Builds a reference to the "other" object.
+ RefBuilder OtherRef(Other, OtherRefType);
// Cast to rvalue.
- OtherRef = CastForMoving(*this, OtherRef);
+ MoveCastBuilder MoveOther(OtherRef);
- // Construct the "this" pointer. We'll be using this throughout the generated
- // ASTs.
- Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
- assert(This && "Reference to this cannot fail!");
+ // Builds the "this" pointer.
+ ThisBuilder This;
// Assign base classes.
bool Invalid = false;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // C++11 [class.copy]p28:
+ // It is unspecified whether subobjects representing virtual base classes
+ // are assigned more than once by the implicitly-defined copy assignment
+ // operator.
+ // FIXME: Do not assign to a vbase that will be assigned by some other base
+ // class. For a move-assignment, this can result in the vbase being moved
+ // multiple times.
+
// Form the assignment:
// static_cast<Base*>(this)->Base::operator=(static_cast<Base&&>(other));
QualType BaseType = Base->getType().getUnqualifiedType();
@@ -9319,23 +9802,20 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Construct the "from" expression, which is an implicit cast to the
// appropriately-qualified base type.
- Expr *From = OtherRef;
- From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase,
- VK_XValue, &BasePath).take();
+ CastBuilder From(OtherRef, BaseType, VK_XValue, BasePath);
// Dereference "this".
- ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+ DerefBuilder DerefThis(This);
// Implicitly cast "this" to the appropriately-qualified base type.
- To = ImpCastExprToType(To.take(),
- Context.getCVRQualifiedType(BaseType,
- MoveAssignOperator->getTypeQualifiers()),
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath);
+ CastBuilder To(DerefThis,
+ Context.getCVRQualifiedType(
+ BaseType, MoveAssignOperator->getTypeQualifiers()),
+ VK_LValue, BasePath);
// Build the move.
StmtResult Move = buildSingleCopyAssign(*this, Loc, BaseType,
- To.get(), From,
+ To, From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/false);
if (Move.isInvalid()) {
@@ -9356,6 +9836,11 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
if (Field->isUnnamedBitfield())
continue;
+ if (Field->isInvalidDecl()) {
+ Invalid = true;
+ continue;
+ }
+
// Check for members of reference type; we can't move those.
if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
@@ -9391,29 +9876,22 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
// Build references to the field in the object we're copying from and to.
- CXXScopeSpec SS; // Intentionally empty
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
LookupMemberName);
MemberLookup.addDecl(*Field);
MemberLookup.resolveKind();
- ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType,
- Loc, /*IsArrow=*/false,
- SS, SourceLocation(), 0,
- MemberLookup, 0);
- ExprResult To = BuildMemberReferenceExpr(This, This->getType(),
- Loc, /*IsArrow=*/true,
- SS, SourceLocation(), 0,
- MemberLookup, 0);
- assert(!From.isInvalid() && "Implicit field reference cannot fail");
- assert(!To.isInvalid() && "Implicit field reference cannot fail");
-
- assert(!From.get()->isLValue() && // could be xvalue or prvalue
+ MemberBuilder From(MoveOther, OtherRefType,
+ /*IsArrow=*/false, MemberLookup);
+ MemberBuilder To(This, getCurrentThisType(),
+ /*IsArrow=*/true, MemberLookup);
+
+ assert(!From.build(*this, Loc)->isLValue() && // could be xvalue or prvalue
"Member reference with rvalue base must be rvalue except for reference "
"members, which aren't allowed for move assignment.");
// Build the move of this field.
StmtResult Move = buildSingleCopyAssign(*this, Loc, FieldType,
- To.get(), From.get(),
+ To, From,
/*CopyingBaseSubobject=*/false,
/*Copying=*/false);
if (Move.isInvalid()) {
@@ -9429,7 +9907,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+ ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
@@ -9557,9 +10035,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CopyConstructor->setDefaulted();
// Build an exception specification pointing back at this member.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = CopyConstructor;
+ FunctionProtoType::ExtProtoInfo EPI =
+ getImplicitMethodEPI(*this, CopyConstructor);
CopyConstructor->setType(
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
@@ -9576,11 +10053,6 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
: ClassDecl->hasTrivialCopyConstructor());
- // C++11 [class.copy]p8:
- // ... If the class definition does not explicitly declare a copy
- // constructor, there is no user-declared move constructor, and there is no
- // user-declared move assignment operator, a copy constructor is implicitly
- // declared as defaulted.
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
SetDeclDeleted(CopyConstructor, ClassLoc);
@@ -9605,6 +10077,13 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+ // 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);
@@ -9615,15 +10094,12 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CopyConstructor->setInvalidDecl();
} else {
Sema::CompoundScopeRAII CompoundScope(*this);
- CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
- CopyConstructor->getLocation(),
- MultiStmtArg(),
- /*isStmtExpr=*/false)
- .takeAs<Stmt>());
- CopyConstructor->setImplicitlyDefined(true);
+ CopyConstructor->setBody(ActOnCompoundStmt(
+ CopyConstructor->getLocation(), CopyConstructor->getLocation(), None,
+ /*isStmtExpr=*/ false).takeAs<Stmt>());
}
-
- CopyConstructor->setUsed();
+
+ CopyConstructor->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
@@ -9696,29 +10172,12 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
CXXRecordDecl *ClassDecl) {
- // C++11 [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // constructor, one will be implicitly declared as defaulted if and only if:
- //
- // - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveConstructor());
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
if (DSM.isAlreadyBeingDeclared())
return 0;
- // [Checked after we build the declaration]
- // - the move assignment operator would not be implicitly defined as
- // deleted,
-
- // [DR1402]:
- // - each of X's non-static data members and direct or virtual base classes
- // has a type that either has a move constructor or is trivially copyable.
- if (!subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl, /*Constructor*/true)) {
- ClassDecl->setFailedImplicitMoveConstructor();
- return 0;
- }
-
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = Context.getRValueReferenceType(ClassType);
@@ -9732,7 +10191,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- // C++0x [class.copy]p11:
+ // C++11 [class.copy]p11:
// An implicitly-declared copy/move constructor is an inline public
// member of its class.
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
@@ -9743,9 +10202,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
MoveConstructor->setDefaulted();
// Build an exception specification pointing back at this member.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = MoveConstructor;
+ FunctionProtoType::ExtProtoInfo EPI =
+ getImplicitMethodEPI(*this, MoveConstructor);
MoveConstructor->setType(
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
@@ -9762,16 +10220,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
: ClassDecl->hasTrivialMoveConstructor());
- // C++0x [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // constructor, one will be implicitly declared as defaulted if and only if:
- // [...]
- // - the move constructor would not be implicitly defined as deleted.
if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
- // Cache this result so that we don't try to generate this over and over
- // on every lookup, leaking memory and wasting time.
- ClassDecl->setFailedImplicitMoveConstructor();
- return 0;
+ ClassDecl->setImplicitMoveConstructorIsDeleted();
+ SetDeclDeleted(MoveConstructor, ClassLoc);
}
// Note that we have declared this constructor.
@@ -9805,15 +10256,12 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
MoveConstructor->setInvalidDecl();
} else {
Sema::CompoundScopeRAII CompoundScope(*this);
- MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(),
- MoveConstructor->getLocation(),
- MultiStmtArg(),
- /*isStmtExpr=*/false)
- .takeAs<Stmt>());
- MoveConstructor->setImplicitlyDefined(true);
+ MoveConstructor->setBody(ActOnCompoundStmt(
+ MoveConstructor->getLocation(), MoveConstructor->getLocation(), None,
+ /*isStmtExpr=*/ false).takeAs<Stmt>());
}
- MoveConstructor->setUsed();
+ MoveConstructor->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveConstructor);
@@ -9821,64 +10269,96 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
}
bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
- return FD->isDeleted() &&
- (FD->isDefaulted() || FD->isImplicit()) &&
- isa<CXXMethodDecl>(FD);
-}
-
-/// \brief Mark the call operator of the given lambda closure type as "used".
-static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
- CXXMethodDecl *CallOperator
- = cast<CXXMethodDecl>(
- Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
- CallOperator->setReferenced();
- CallOperator->setUsed();
+ return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);
}
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
+ SourceLocation CurrentLocation,
+ CXXConversionDecl *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.
+ const TemplateArgumentList *DeducedTemplateArgs = 0;
+
- // Make sure that the lambda call operator is marked used.
- markLambdaCallOperatorUsed(*this, Lambda);
-
- Conv->setUsed();
-
+ // Retrieve the corresponding call-operator specialization.
+ if (Lambda->isGenericLambda()) {
+ assert(Conv->isFunctionTemplateSpecialization());
+ FunctionTemplateDecl *CallOpTemplate =
+ CallOp->getDescribedFunctionTemplate();
+ DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
+ void *InsertPos = 0;
+ FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ 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
+ // we construct their body's in this function, so no need to add them
+ // to the PendingInstantiations.
+ MarkFunctionReferenced(CurrentLocation, CallOp);
+
SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
+
+ // Retreive the static invoker...
+ CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
+ // ... and get the corresponding specialization for a generic lambda.
+ if (Lambda->isGenericLambda()) {
+ assert(DeducedTemplateArgs &&
+ "Must have deduced template arguments from Conversion Operator");
+ FunctionTemplateDecl *InvokeTemplate =
+ Invoker->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ assert(InvokeSpec &&
+ "Must have a corresponding static invoker specialization");
+ Invoker = cast<CXXMethodDecl>(InvokeSpec);
+ }
+ // Construct the body of the conversion function { return __invoke; }.
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
+ VK_LValue, Conv->getLocation()).take();
+ assert(FunctionRef && "Can't refer to __invoke function?");
+ Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Conv->setBody(new (Context) CompoundStmt(Context, Return,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ Conv->markUsed(Context);
+ Conv->setReferenced();
- // Return the address of the __invoke function.
- DeclarationName InvokeName = &Context.Idents.get("__invoke");
- CXXMethodDecl *Invoke
- = cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
- Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
- VK_LValue, Conv->getLocation()).take();
- assert(FunctionRef && "Can't refer to __invoke function?");
- Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
- Conv->setBody(new (Context) CompoundStmt(Context, Return,
- Conv->getLocation(),
- Conv->getLocation()));
-
// Fill in the __invoke function with a dummy implementation. IR generation
// will fill in the actual details.
- Invoke->setUsed();
- Invoke->setReferenced();
- Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
- L->CompletedImplicitDefinition(Invoke);
- }
+ L->CompletedImplicitDefinition(Invoker);
+ }
}
+
+
void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
- Conv->setUsed();
+ assert(!Conv->getParent()->isGenericLambda());
+
+ Conv->markUsed(Context);
SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
@@ -10057,12 +10537,14 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
- Proto, 0, Args, NumArgs, AllArgs,
+ Proto, 0,
+ llvm::makeArrayRef(Args, NumArgs),
+ AllArgs,
CallType, AllowExplicit,
IsListInitialization);
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
- DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
+ DiagnoseSentinelCalls(Constructor, Loc, AllArgs);
CheckConstructorCall(Constructor,
llvm::makeArrayRef<const Expr *>(AllArgs.data(),
@@ -10356,11 +10838,12 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (!TpDecl)
TpDecl = FnDecl->getPrimaryTemplate();
- // template <char...> type operator "" name() is the only valid template
- // signature, and the only valid signature with no parameters.
+ // template <char...> type operator "" name() and
+ // template <class T, T...> type operator "" name() are the only valid
+ // template signatures, and the only valid signatures with no parameters.
if (TpDecl) {
if (FnDecl->param_size() == 0) {
- // Must have only one template parameter
+ // Must have one or two template parameters
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
@@ -10370,6 +10853,27 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (PmDecl && PmDecl->isTemplateParameterPack() &&
Context.hasSameType(PmDecl->getType(), Context.CharTy))
Valid = true;
+ } else if (Params->size() == 2) {
+ TemplateTypeParmDecl *PmType =
+ dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
+ NonTypeTemplateParmDecl *PmArgs =
+ dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
+
+ // The second template parameter must be a parameter pack with the
+ // first template parameter as its type.
+ if (PmType && PmArgs &&
+ !PmType->isTemplateParameterPack() &&
+ PmArgs->isTemplateParameterPack()) {
+ const TemplateTypeParmType *TArgs =
+ PmArgs->getType()->getAs<TemplateTypeParmType>();
+ if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
+ TArgs->getIndex() == PmType->getIndex()) {
+ Valid = true;
+ if (ActiveTemplateInstantiations.empty())
+ Diag(FnDecl->getLocation(),
+ diag::ext_string_literal_operator_template);
+ }
+ }
}
}
} else if (FnDecl->param_size()) {
@@ -10383,7 +10887,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)) {
if (++Param == FnDecl->param_end())
@@ -10413,7 +10917,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// const char *, const wchar_t*, const char16_t*, and const char32_t*
// are allowed as the first parameter to a two-parameter function
if (!(Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)))
goto FinishedParams;
@@ -10452,7 +10956,8 @@ FinishedParams:
// C++11 [usrlit.suffix]p1:
// Literal suffix identifiers that do not start with an underscore
// are reserved for future standardization.
- Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved);
+ Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved)
+ << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName);
}
return false;
@@ -10599,13 +11104,13 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
// C++ [except.handle]p16:
- // The object declared in an exception-declaration or, if the
- // exception-declaration does not specify a name, a temporary (12.2) is
+ // The object declared in an exception-declaration or, if the
+ // exception-declaration does not specify a name, a temporary (12.2) is
// copy-initialized (8.5) from the exception object. [...]
// The object is destroyed when the handler exits, after the destruction
// of any automatic objects initialized within the handler.
//
- // We just pretend to initialize the object with itself, then make sure
+ // We just pretend to initialize the object with itself, then make sure
// it can be destroyed later.
QualType initType = ExDeclType;
@@ -10623,7 +11128,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
else {
// If the constructor used was non-trivial, set this as the
// "initializer".
- CXXConstructExpr *construct = cast<CXXConstructExpr>(result.take());
+ CXXConstructExpr *construct = result.takeAs<CXXConstructExpr>();
if (!construct->getConstructor()->isTrivial()) {
Expr *init = MaybeCreateExprWithCleanups(construct);
ExDecl->setInit(init);
@@ -10826,13 +11331,10 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool isExplicitSpecialization = false;
bool Invalid = false;
- if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
- TempParamLists.data(),
- TempParamLists.size(),
- /*friend*/ true,
- isExplicitSpecialization,
- Invalid)) {
+ if (TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ TagLoc, NameLoc, SS, TempParamLists, /*friend*/ true,
+ isExplicitSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
@@ -10916,6 +11418,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
// Handle the case of a templated-scope friend class. e.g.
// template <class T> class A<T>::B;
// FIXME: we don't support these right now.
+ Diag(NameLoc, diag::warn_template_qualified_friend_unsupported)
+ << SS.getScopeRep() << SS.getRange() << cast<CXXRecordDecl>(CurContext);
ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
@@ -11080,28 +11584,61 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForRedeclaration);
- // FIXME: there are different rules in local classes
+ // There are five cases here.
+ // - There's no scope specifier and we're in a local class. Only look
+ // for functions declared in the immediately-enclosing block scope.
+ // We recover from invalid scope qualifiers as if they just weren't there.
+ FunctionDecl *FunctionContainingLocalClass = 0;
+ if ((SS.isInvalid() || !SS.isSet()) &&
+ (FunctionContainingLocalClass =
+ cast<CXXRecordDecl>(CurContext)->isLocalClass())) {
+ // C++11 [class.friend]p11:
+ // If a friend declaration appears in a local class and the name
+ // specified is an unqualified name, a prior declaration is
+ // looked up without considering scopes that are outside the
+ // innermost enclosing non-class scope. For a friend function
+ // declaration, if there is no prior declaration, the program is
+ // ill-formed.
+
+ // Find the innermost enclosing non-class scope. This is the block
+ // scope containing the local class definition (or for a nested class,
+ // the outer local class).
+ DCScope = S->getFnParent();
+
+ // Look up the function name in the scope.
+ Previous.clear(LookupLocalFriendName);
+ LookupName(Previous, S, /*AllowBuiltinCreation*/false);
+
+ if (!Previous.empty()) {
+ // All possible previous declarations must have the same context:
+ // either they were declared at block scope or they are members of
+ // one of the enclosing local classes.
+ DC = Previous.getRepresentativeDecl()->getDeclContext();
+ } else {
+ // This is ill-formed, but provide the context that we would have
+ // declared the function in, if we were permitted to, for error recovery.
+ DC = FunctionContainingLocalClass;
+ }
+ adjustContextForLocalExternDecl(DC);
+
+ // C++ [class.friend]p6:
+ // 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.
+ if (D.isFunctionDefinition()) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+ }
- // There are four cases here.
// - There's no scope specifier, in which case we just go to the
// appropriate scope and look for a function or function template
// there as appropriate.
- // Recover from invalid scope qualifiers as if they just weren't there.
- if (SS.isInvalid() || !SS.isSet()) {
- // C++0x [namespace.memdef]p3:
+ } else if (SS.isInvalid() || !SS.isSet()) {
+ // C++11 [namespace.memdef]p3:
// If the name in a friend declaration is neither qualified nor
// a template-id and the declaration is a function or an
// elaborated-type-specifier, the lookup to determine whether
// the entity has been previously declared shall not consider
// any scopes outside the innermost enclosing namespace.
- // C++0x [class.friend]p11:
- // If a friend declaration appears in a local class and the name
- // specified is an unqualified name, a prior declaration is
- // looked up without considering scopes that are outside the
- // innermost enclosing non-class scope. For a friend function
- // declaration, if there is no prior declaration, the program is
- // ill-formed.
- bool isLocal = cast<CXXRecordDecl>(CurContext)->isLocalClass();
bool isTemplateId = D.getName().getKind() == UnqualifiedId::IK_TemplateId;
// Find the appropriate context according to the above.
@@ -11124,10 +11661,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
while (true) {
LookupQualifiedName(Previous, LookupDC);
- // TODO: decide what we think about using declarations.
- if (isLocal)
- break;
-
if (!Previous.empty()) {
DC = LookupDC;
break;
@@ -11142,15 +11675,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
DCScope = getScopeForDeclContext(S, DC);
-
- // C++ [class.friend]p6:
- // 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.
- if (isLocal && D.isFunctionDefinition()) {
- Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
- }
-
+
// - There's a non-dependent scope specifier, in which case we
// compute it and do a previous lookup there for a function
// or function template.
@@ -11242,15 +11767,18 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
FakeDCScope.setEntity(DC);
DCScope = &FakeDCScope;
}
-
+
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
TemplateParams, AddToScope);
if (!ND) return 0;
- assert(ND->getDeclContext() == DC);
assert(ND->getLexicalDeclContext() == CurContext);
+ // If we performed typo correction, we might have added a scope specifier
+ // and changed the decl context.
+ DC = ND->getDeclContext();
+
// Add the function declaration to the appropriate lookup tables,
// adjusting the redeclarations list as necessary. We don't
// want to do this yet if the friending class is dependent.
@@ -11281,6 +11809,18 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
else
FD = cast<FunctionDecl>(ND);
+ // C++11 [dcl.fct.default]p4: If a friend declaration specifies a
+ // default argument expression, that declaration shall be a definition
+ // and shall be the only declaration of the function or function
+ // template in the translation unit.
+ if (functionDeclHasDefaultArgument(FD)) {
+ if (FunctionDecl *OldFD = FD->getPreviousDecl()) {
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
+ Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ } else if (!D.isFunctionDefinition())
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def);
+ }
+
// Mark templated-scope function declarations as unsupported.
if (FD->getNumTemplateParameterLists())
FrD->setUnsupportedFriend(true);
@@ -11346,7 +11886,8 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
CXXSpecialMember Member = getSpecialMember(MD);
if (Member == CXXInvalid) {
- Diag(DefaultLoc, diag::err_default_special_members);
+ if (!MD->isInvalidDecl())
+ Diag(DefaultLoc, diag::err_default_special_members);
return;
}
@@ -11374,47 +11915,29 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
ResolveExceptionSpec(DefaultLoc,
MD->getType()->castAs<FunctionProtoType>());
+ if (MD->isInvalidDecl())
+ return;
+
switch (Member) {
- case CXXDefaultConstructor: {
- CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- if (!CD->isInvalidDecl())
- DefineImplicitDefaultConstructor(DefaultLoc, CD);
+ case CXXDefaultConstructor:
+ DefineImplicitDefaultConstructor(DefaultLoc,
+ cast<CXXConstructorDecl>(MD));
break;
- }
-
- case CXXCopyConstructor: {
- CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- if (!CD->isInvalidDecl())
- DefineImplicitCopyConstructor(DefaultLoc, CD);
+ case CXXCopyConstructor:
+ DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
break;
- }
-
- case CXXCopyAssignment: {
- if (!MD->isInvalidDecl())
- DefineImplicitCopyAssignment(DefaultLoc, MD);
+ case CXXCopyAssignment:
+ DefineImplicitCopyAssignment(DefaultLoc, MD);
break;
- }
-
- case CXXDestructor: {
- CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
- if (!DD->isInvalidDecl())
- DefineImplicitDestructor(DefaultLoc, DD);
+ case CXXDestructor:
+ DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
break;
- }
-
- case CXXMoveConstructor: {
- CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- if (!CD->isInvalidDecl())
- DefineImplicitMoveConstructor(DefaultLoc, CD);
+ case CXXMoveConstructor:
+ DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
break;
- }
-
- case CXXMoveAssignment: {
- if (!MD->isInvalidDecl())
- DefineImplicitMoveAssignment(DefaultLoc, MD);
+ case CXXMoveAssignment:
+ DefineImplicitMoveAssignment(DefaultLoc, MD);
break;
- }
-
case CXXInvalid:
llvm_unreachable("Invalid special member.");
}
@@ -11454,27 +11977,11 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
if (NewCC == OldCC)
return false;
- // If either of the calling conventions are set to "default", we need to pick
- // something more sensible based on the target. This supports code where the
- // one method explicitly sets thiscall, and another has no explicit calling
- // convention.
- CallingConv Default =
- Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member);
- if (NewCC == CC_Default)
- NewCC = Default;
- if (OldCC == CC_Default)
- OldCC = Default;
-
- // If the calling conventions still don't match, then report the error
- if (NewCC != OldCC) {
- Diag(New->getLocation(),
- diag::err_conflicting_overriding_cc_attributes)
- << New->getDeclName() << New->getType() << Old->getType();
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
- return true;
- }
-
- return false;
+ Diag(New->getLocation(),
+ diag::err_conflicting_overriding_cc_attributes)
+ << New->getDeclName() << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
}
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
@@ -11595,13 +12102,13 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
}
/// \brief Determine whether the given declaration is a static data member.
-static bool isStaticDataMember(Decl *D) {
- VarDecl *Var = dyn_cast_or_null<VarDecl>(D);
- if (!Var)
- return false;
-
- return Var->isStaticDataMember();
+static bool isStaticDataMember(const Decl *D) {
+ if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
+ return Var->isStaticDataMember();
+
+ 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.
@@ -11744,19 +12251,14 @@ bool Sema::DefineUsedVTables() {
// vtable even though we're using it.
const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
if (KeyFunction && !KeyFunction->hasBody()) {
- switch (KeyFunction->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- // The key function is in another translation unit.
- DefineVTable = false;
- break;
-
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ImplicitInstantiation:
- // We will be instantiating the key function.
- break;
- }
+ // The key function is in another translation unit.
+ DefineVTable = false;
+ TemplateSpecializationKind TSK =
+ KeyFunction->getTemplateSpecializationKind();
+ assert(TSK != TSK_ExplicitInstantiationDefinition &&
+ TSK != TSK_ImplicitInstantiation &&
+ "Instantiations don't have key functions");
+ (void)TSK;
} else if (!KeyFunction) {
// If we have a class with no key function that is the subject
// of an explicit instantiation declaration, suppress the
@@ -11799,7 +12301,7 @@ bool Sema::DefineUsedVTables() {
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
// Optionally warn if we're emitting a weak vtable.
- if (Class->hasExternalLinkage() &&
+ if (Class->isExternallyVisible() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
const FunctionDecl *KeyFunctionDef = 0;
if (!KeyFunction ||
@@ -11920,8 +12422,6 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid,
llvm::SmallSet<CXXConstructorDecl*, 4> &Current,
Sema &S) {
- llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
- CE = Current.end();
if (Ctor->isInvalidDecl())
return;
@@ -11946,8 +12446,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
// We know that beyond here, we aren't chaining into a cycle.
if (!Target || !Target->isDelegatingConstructor() ||
Target->isInvalidDecl() || Valid.count(TCanonical)) {
- for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
- Valid.insert(*CI);
+ Valid.insert(Current.begin(), Current.end());
Current.clear();
// We've hit a cycle.
} else if (TCanonical == Canonical || Invalid.count(TCanonical) ||
@@ -11974,8 +12473,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
}
}
- for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
- Invalid.insert(*CI);
+ Invalid.insert(Current.begin(), Current.end());
Current.clear();
} else {
DelegatingCycleHelper(Target, Valid, Invalid, Current, S);
@@ -11986,16 +12484,15 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
void Sema::CheckDelegatingCtorCycles() {
llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
- llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
- CE = Current.end();
-
for (DelegatingCtorDeclsType::iterator
I = DelegatingCtorDecls.begin(ExternalSource),
E = DelegatingCtorDecls.end();
I != E; ++I)
DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
- for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
+ for (llvm::SmallSet<CXXConstructorDecl *, 4>::iterator CI = Invalid.begin(),
+ CE = Invalid.end();
+ CI != CE; ++CI)
(*CI)->setInvalidDecl();
}
@@ -12211,8 +12708,7 @@ Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
if (D->hasAttr<CUDADeviceAttr>()) {
if (D->hasAttr<CUDAHostAttr>())
return CFT_HostDevice;
- else
- return CFT_Device;
+ return CFT_Device;
}
return CFT_Host;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f33e7bcb1671..f44fb3251141 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -324,15 +324,15 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope);
PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope);
+ // The ObjC parser requires parameter names so there's no need to check.
+ CheckParmsForFunctionDef(MDecl->param_begin(), MDecl->param_end(),
+ /*CheckParameterNames=*/false);
+
// Introduce all of the other parameters into this scope.
for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
E = MDecl->param_end(); PI != E; ++PI) {
ParmVarDecl *Param = (*PI);
if (!Param->isInvalidDecl() &&
- RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type))
- Param->setInvalidDecl();
- if (!Param->isInvalidDecl() &&
getLangOpts().ObjCAutoRefCount &&
!HasExplicitOwnershipAttr(*this, Param))
Diag(Param->getLocation(), diag::warn_arc_strong_pointer_objc_pointer) <<
@@ -350,7 +350,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
case OMF_release:
case OMF_autorelease:
Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
- << MDecl->getSelector();
+ << 0 << MDecl->getSelector();
break;
case OMF_None:
@@ -459,6 +459,23 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Create a declaration to describe this @interface.
ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+
+ if (PrevIDecl && PrevIDecl->getIdentifier() != ClassName) {
+ // A previous decl with a different name is because of
+ // @compatibility_alias, for example:
+ // \code
+ // @class NewImage;
+ // @compatibility_alias OldImage NewImage;
+ // \endcode
+ // A lookup for 'OldImage' will return the 'NewImage' decl.
+ //
+ // In such a case use the real declaration name, instead of the alias one,
+ // otherwise we will break IdentifierResolver and redecls-chain invariants.
+ // FIXME: If necessary, add a bit to indicate that this ObjCInterfaceDecl
+ // has been aliased.
+ ClassName = PrevIDecl->getIdentifier();
+ }
+
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
PrevIDecl, ClassLoc);
@@ -494,11 +511,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
NULL, Validator)) {
+ diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
+ << SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
- Diag(SuperLoc, diag::err_undef_superclass_suggest)
- << SuperName << ClassName << PrevDecl->getDeclName();
- Diag(PrevDecl->getLocation(), diag::note_previous_decl)
- << PrevDecl->getDeclName();
}
}
@@ -575,6 +590,29 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
return ActOnObjCContainerStartDefinition(IDecl);
}
+/// ActOnTypedefedProtocols - this action finds protocol list as part of the
+/// typedef'ed use for a qualified super class and adds them to the list
+/// of the protocols.
+void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc) {
+ if (!SuperName)
+ return;
+ NamedDecl* IDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
+ LookupOrdinaryName);
+ if (!IDecl)
+ return;
+
+ if (const TypedefNameDecl *TDecl = dyn_cast_or_null<TypedefNameDecl>(IDecl)) {
+ QualType T = TDecl->getUnderlyingType();
+ if (T->isObjCObjectType())
+ if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>())
+ for (ObjCObjectType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ ProtocolRefs.push_back(*I);
+ }
+}
+
/// ActOnCompatibilityAlias - this action is called after complete parsing of
/// a \@compatibility_alias declaration. It sets up the alias relationships.
Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
@@ -586,10 +624,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
LookupOrdinaryName, ForRedeclaration);
if (ADecl) {
- if (isa<ObjCCompatibleAliasDecl>(ADecl))
- Diag(AliasLocation, diag::warn_previous_alias_decl);
- else
- Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
+ Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
Diag(ADecl->getLocation(), diag::note_previous_declaration);
return 0;
}
@@ -732,12 +767,9 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
LookupObjCProtocolName, TUScope, NULL, Validator);
- if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
- Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
- << ProtocolId[i].first << Corrected.getCorrection();
- Diag(PDecl->getLocation(), diag::note_previous_decl)
- << PDecl->getDeclName();
- }
+ if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
+ diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
+ << ProtocolId[i].first);
}
if (!PDecl) {
@@ -819,7 +851,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
DeclsInGroup.push_back(PDecl);
}
- return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
+ return BuildDeclaratorGroup(DeclsInGroup, false);
}
Decl *Sema::
@@ -935,6 +967,7 @@ Decl *Sema::ActOnStartCategoryImplementation(
<< CatName;
Diag(CatIDecl->getImplementation()->getLocation(),
diag::note_previous_definition);
+ CDecl->setInvalidDecl();
} else {
CatIDecl->setImplementation(CDecl);
// Warn on implementating category of deprecated class under
@@ -954,7 +987,7 @@ Decl *Sema::ActOnStartClassImplementation(
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc) {
- ObjCInterfaceDecl* IDecl = 0;
+ ObjCInterfaceDecl *IDecl = 0;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
@@ -966,24 +999,19 @@ Decl *Sema::ActOnStartClassImplementation(
RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
diag::warn_undef_interface);
} else {
- // We did not find anything with the name ClassName; try to correct for
+ // We did not find anything with the name ClassName; try to correct for
// typos in the class name.
ObjCInterfaceValidatorCCC Validator;
- if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
- NULL, Validator)) {
- // Suggest the (potentially) correct interface name. However, put the
- // fix-it hint itself in a separate note, since changing the name in
- // the warning would make the fix-it change semantics.However, don't
- // provide a code-modification hint or use the typo name for recovery,
- // because this is just a warning. The program may actually be correct.
- IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
- DeclarationName CorrectedName = Corrected.getCorrection();
- Diag(ClassLoc, diag::warn_undef_interface_suggest)
- << ClassName << CorrectedName;
- Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName
- << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString());
- IDecl = 0;
+ TypoCorrection Corrected =
+ CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
+ LookupOrdinaryName, TUScope, NULL, Validator);
+ if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
+ // Suggest the (potentially) correct interface name. Don't provide a
+ // code-modification hint or use the typo name for recovery, because
+ // this is just a warning. The program may actually be correct.
+ diagnoseTypo(Corrected,
+ PDiag(diag::warn_undef_interface_suggest) << ClassName,
+ /*ErrorRecovery*/false);
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
}
@@ -1056,6 +1084,7 @@ Decl *Sema::ActOnStartClassImplementation(
Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName;
Diag(IDecl->getImplementation()->getLocation(),
diag::note_previous_definition);
+ IMPDecl->setInvalidDecl();
} else { // add it to the list.
IDecl->setImplementation(IMPDecl);
PushOnScopeChains(IMPDecl, TUScope);
@@ -1084,7 +1113,7 @@ Sema::ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef<Decl *> Decls) {
DeclsInGroup.push_back(ObjCImpDecl);
- return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
+ return BuildDeclaratorGroup(DeclsInGroup, false);
}
void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
@@ -1124,6 +1153,19 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
+ // Check class extensions (unnamed categories) for duplicate ivars.
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ ObjCCategoryDecl *CDecl = *Ext;
+ if (const ObjCIvarDecl *ClsExtIvar =
+ CDecl->getIvarDecl(ImplIvar->getIdentifier())) {
+ Diag(ImplIvar->getLocation(), diag::err_duplicate_ivar_declaration);
+ Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
+ continue;
+ }
+ }
// Instance ivar to Implementation's DeclContext.
ImplIvar->setLexicalDeclContext(ImpDecl);
IDecl->makeDeclVisibleInContext(ImplIvar);
@@ -1469,8 +1511,8 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
reasonSelector = R_NonObjectReturn;
}
- S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
- S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+ S.Diag(impl->getLocation(), errorID) << int(familySelector) << int(reasonSelector);
+ S.Diag(decl->getLocation(), noteID) << int(familySelector) << int(reasonSelector);
return true;
}
@@ -1689,9 +1731,8 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// implemented in the implementation class. If so, their types match.
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
E = CDecl->instmeth_end(); I != E; ++I) {
- if (InsMapSeen.count((*I)->getSelector()))
- continue;
- InsMapSeen.insert((*I)->getSelector());
+ if (!InsMapSeen.insert((*I)->getSelector()))
+ continue;
if (!(*I)->isPropertyAccessor() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
@@ -1718,11 +1759,11 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// Check and see if class methods in class interface have been
// implemented in the implementation class. If so, their types match.
- for (ObjCInterfaceDecl::classmeth_iterator
- I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I) {
- if (ClsMapSeen.count((*I)->getSelector()))
- continue;
- ClsMapSeen.insert((*I)->getSelector());
+ for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(),
+ E = CDecl->classmeth_end();
+ I != E; ++I) {
+ if (!ClsMapSeen.insert((*I)->getSelector()))
+ continue;
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
@@ -1742,6 +1783,16 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
}
}
+ if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl> (CDecl)) {
+ // Also, check for methods declared in protocols inherited by
+ // this protocol.
+ for (ObjCProtocolDecl::protocol_iterator
+ PI = PD->protocol_begin(), E = PD->protocol_end(); PI != E; ++PI)
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl, (*PI), IncompleteImpl, false,
+ WarnCategoryMethodImpl);
+ }
+
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
// when checking that methods in implementation match their declaration,
// i.e. when WarnCategoryMethodImpl is false, check declarations in class
@@ -1901,13 +1952,6 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
NamedDecl *PrevDecl
= LookupSingleName(TUScope, IdentList[i], IdentLocs[i],
LookupOrdinaryName, ForRedeclaration);
- if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
- }
-
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
// GCC apparently allows the following idiom:
//
@@ -1936,17 +1980,35 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// Create a declaration to describe this forward declaration.
ObjCInterfaceDecl *PrevIDecl
= dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+
+ IdentifierInfo *ClassName = IdentList[i];
+ if (PrevIDecl && PrevIDecl->getIdentifier() != ClassName) {
+ // A previous decl with a different name is because of
+ // @compatibility_alias, for example:
+ // \code
+ // @class NewImage;
+ // @compatibility_alias OldImage NewImage;
+ // \endcode
+ // A lookup for 'OldImage' will return the 'NewImage' decl.
+ //
+ // In such a case use the real declaration name, instead of the alias one,
+ // otherwise we will break IdentifierResolver and redecls-chain invariants.
+ // FIXME: If necessary, add a bit to indicate that this ObjCInterfaceDecl
+ // has been aliased.
+ ClassName = PrevIDecl->getIdentifier();
+ }
+
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i], PrevIDecl, IdentLocs[i]);
+ ClassName, PrevIDecl, IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
}
-
- return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
+
+ return BuildDeclaratorGroup(DeclsInGroup, false);
}
static bool tryMatchRecordTypes(ASTContext &Context,
@@ -2093,6 +2155,10 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
// signature.
ObjCMethodList *Previous = List;
for (; List; Previous = List, List = List->getNext()) {
+ // If we are building a module, keep all of the methods.
+ if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty())
+ continue;
+
if (!MatchTwoMethodDeclarations(Method, List->Method))
continue;
@@ -2182,7 +2248,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
// Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
- llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
+ SmallVector<ObjCMethodDecl *, 4> Methods;
for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
if (M->Method && !M->Method->isHidden()) {
// If we're not supposed to warn about mismatches, we're done.
@@ -2269,7 +2335,140 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
return 0;
}
-/// DiagnoseDuplicateIvars -
+static void
+HelperSelectorsForTypoCorrection(
+ SmallVectorImpl<const ObjCMethodDecl *> &BestMethod,
+ StringRef Typo, const ObjCMethodDecl * Method) {
+ const unsigned MaxEditDistance = 1;
+ unsigned BestEditDistance = MaxEditDistance + 1;
+ std::string MethodName = Method->getSelector().getAsString();
+
+ unsigned MinPossibleEditDistance = abs((int)MethodName.size() - (int)Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 1)
+ return;
+ unsigned EditDistance = Typo.edit_distance(MethodName, true, MaxEditDistance);
+ if (EditDistance > MaxEditDistance)
+ return;
+ if (EditDistance == BestEditDistance)
+ BestMethod.push_back(Method);
+ else if (EditDistance < BestEditDistance) {
+ BestMethod.clear();
+ BestMethod.push_back(Method);
+ }
+}
+
+static bool HelperIsMethodInObjCType(Sema &S, Selector Sel,
+ QualType ObjectType) {
+ if (ObjectType.isNull())
+ return true;
+ if (S.LookupMethodInObjectType(Sel, ObjectType, true/*Instance method*/))
+ return true;
+ return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) != 0;
+}
+
+const ObjCMethodDecl *
+Sema::SelectorsForTypoCorrection(Selector Sel,
+ QualType ObjectType) {
+ unsigned NumArgs = Sel.getNumArgs();
+ SmallVector<const ObjCMethodDecl *, 8> Methods;
+ bool ObjectIsId = true, ObjectIsClass = true;
+ if (ObjectType.isNull())
+ ObjectIsId = ObjectIsClass = false;
+ else if (!ObjectType->isObjCObjectPointerType())
+ return 0;
+ else if (const ObjCObjectPointerType *ObjCPtr =
+ ObjectType->getAsObjCInterfacePointerType()) {
+ ObjectType = QualType(ObjCPtr->getInterfaceType(), 0);
+ ObjectIsId = ObjectIsClass = false;
+ }
+ else if (ObjectType->isObjCIdType() || ObjectType->isObjCQualifiedIdType())
+ ObjectIsClass = false;
+ else if (ObjectType->isObjCClassType() || ObjectType->isObjCQualifiedClassType())
+ ObjectIsId = false;
+ else
+ return 0;
+
+ for (GlobalMethodPool::iterator b = MethodPool.begin(),
+ e = MethodPool.end(); b != e; b++) {
+ // instance methods
+ for (ObjCMethodList *M = &b->second.first; M; M=M->getNext())
+ if (M->Method &&
+ (M->Method->getSelector().getNumArgs() == NumArgs) &&
+ (M->Method->getSelector() != Sel)) {
+ if (ObjectIsId)
+ Methods.push_back(M->Method);
+ else if (!ObjectIsClass &&
+ HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
+ Methods.push_back(M->Method);
+ }
+ // class methods
+ for (ObjCMethodList *M = &b->second.second; M; M=M->getNext())
+ if (M->Method &&
+ (M->Method->getSelector().getNumArgs() == NumArgs) &&
+ (M->Method->getSelector() != Sel)) {
+ if (ObjectIsClass)
+ Methods.push_back(M->Method);
+ else if (!ObjectIsId &&
+ HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
+ Methods.push_back(M->Method);
+ }
+ }
+
+ SmallVector<const ObjCMethodDecl *, 8> SelectedMethods;
+ for (unsigned i = 0, e = Methods.size(); i < e; i++) {
+ HelperSelectorsForTypoCorrection(SelectedMethods,
+ Sel.getAsString(), Methods[i]);
+ }
+ return (SelectedMethods.size() == 1) ? SelectedMethods[0] : NULL;
+}
+
+static void
+HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
+ ObjCMethodList &MethList) {
+ ObjCMethodList *M = &MethList;
+ ObjCMethodDecl *TargetMethod = M->Method;
+ while (TargetMethod &&
+ isa<ObjCImplDecl>(TargetMethod->getDeclContext())) {
+ M = M->getNext();
+ TargetMethod = M ? M->Method : 0;
+ }
+ if (!TargetMethod)
+ return;
+ bool FirstTime = true;
+ for (M = M->getNext(); M; M=M->getNext()) {
+ ObjCMethodDecl *MatchingMethodDecl = M->Method;
+ if (isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()))
+ continue;
+ if (!S.MatchTwoMethodDeclarations(TargetMethod,
+ MatchingMethodDecl, Sema::MMS_loose)) {
+ if (FirstTime) {
+ FirstTime = false;
+ S.Diag(TargetMethod->getLocation(), diag::warning_multiple_selectors)
+ << TargetMethod->getSelector();
+ }
+ S.Diag(MatchingMethodDecl->getLocation(), diag::note_also_found);
+ }
+ }
+}
+
+void Sema::DiagnoseMismatchedMethodsInGlobalPool() {
+ unsigned DIAG = diag::warning_multiple_selectors;
+ if (Diags.getDiagnosticLevel(DIAG, SourceLocation())
+ == DiagnosticsEngine::Ignored)
+ return;
+ for (GlobalMethodPool::iterator b = MethodPool.begin(),
+ e = MethodPool.end(); b != e; b++) {
+ // first, instance methods
+ ObjCMethodList &InstMethList = b->second.first;
+ HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, InstMethList);
+ // second, class methods
+ ObjCMethodList &ClsMethList = b->second.second;
+ HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, ClsMethList);
+ }
+}
+
+/// DiagnoseDuplicateIvars -
/// Check for duplicate ivars in the entire class at the start of
/// \@implementation. This becomes necesssary because class extension can
/// add ivars to a class in random order which will not be known until
@@ -2313,13 +2512,9 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
}
}
-// Note: For class/category implemenations, allMethods/allProperties is
-// always null.
-Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
- Decl **allMethods, unsigned allNum,
- Decl **allProperties, unsigned pNum,
- DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
-
+// Note: For class/category implementations, allMethods is always null.
+Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
+ ArrayRef<DeclGroupPtrTy> allTUVars) {
if (getObjCContainerKind() == Sema::OCK_None)
return 0;
@@ -2337,7 +2532,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
- for (unsigned i = 0; i < allNum; i++ ) {
+ for (unsigned i = 0, e = allMethods.size(); i != e; i++ ) {
ObjCMethodDecl *Method =
cast_or_null<ObjCMethodDecl>(allMethods[i]);
@@ -2504,8 +2699,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
if (isInterfaceDeclKind) {
// Reject invalid vardecls.
- for (unsigned i = 0; i != tuvNum; i++) {
- DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>();
+ for (unsigned i = 0, e = allTUVars.size(); i != e; i++) {
+ DeclGroupRef DG = allTUVars[i].get();
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
if (VarDecl *VDecl = dyn_cast<VarDecl>(*I)) {
if (!VDecl->hasExternalStorage())
@@ -2515,8 +2710,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
ActOnObjCContainerFinishDefinition();
- for (unsigned i = 0; i != tuvNum; i++) {
- DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>();
+ for (unsigned i = 0, e = allTUVars.size(); i != e; i++) {
+ DeclGroupRef DG = allTUVars[i].get();
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
(*I)->setTopLevelDeclInObjCContainer();
Consumer.HandleTopLevelDeclInObjCContainer(DG);
@@ -2911,14 +3106,9 @@ Decl *Sema::ActOnMethodDeclaration(
if (ReturnType) {
resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
- // Methods cannot return interface types. All ObjC objects are
- // passed by reference.
- if (resultDeclType->isObjCObjectType()) {
- Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
- << 0 << resultDeclType;
+ if (CheckFunctionReturnType(resultDeclType, MethodLoc))
return 0;
- }
-
+
HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
} else { // get the type for "id".
resultDeclType = Context.getObjCIdType();
@@ -2945,7 +3135,7 @@ Decl *Sema::ActOnMethodDeclaration(
QualType ArgType;
TypeSourceInfo *DI;
- if (ArgInfo[i].Type == 0) {
+ if (!ArgInfo[i].Type) {
ArgType = Context.getObjCIdType();
DI = 0;
} else {
@@ -3001,14 +3191,8 @@ Decl *Sema::ActOnMethodDeclaration(
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
ArgType = Context.getAdjustedParameterType(ArgType);
- if (ArgType->isObjCObjectType()) {
- Diag(Param->getLocation(),
- diag::err_object_cannot_be_passed_returned_by_value)
- << 1 << ArgType;
- Param->setInvalidDecl();
- }
+
Param->setDeclContext(ObjCMethod);
-
Params.push_back(Param);
}
@@ -3034,6 +3218,12 @@ Decl *Sema::ActOnMethodDeclaration(
if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface())
IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod());
+ if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() &&
+ !ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) {
+ // merge the attribute into implementation.
+ ObjCMethod->addAttr(
+ new (Context) ObjCRequiresSuperAttr(ObjCMethod->getLocation(), Context));
+ }
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(IMD, ObjCMethod->getAttrs())) {
SourceLocation MethodLoc = IMD->getLocation();
@@ -3052,6 +3242,8 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl)
<< ObjCMethod->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ ObjCMethod->setInvalidDecl();
+ return ObjCMethod;
}
// If this Objective-C method does not have a related result type, but we
@@ -3290,6 +3482,8 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() {
ReferencedSelectors[Sels[I].first] = Sels[I].second;
}
+ DiagnoseMismatchedMethodsInGlobalPool();
+
// Warning will be issued only when selector table is
// generated (which means there is at lease one implementation
// in the TU). This is to match gcc's behavior.
@@ -3305,3 +3499,43 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() {
}
return;
}
+
+ObjCIvarDecl *
+Sema::GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method,
+ const ObjCPropertyDecl *&PDecl) const {
+
+ const ObjCInterfaceDecl *IDecl = Method->getClassInterface();
+ if (!IDecl)
+ return 0;
+ Method = IDecl->lookupMethod(Method->getSelector(), true);
+ if (!Method || !Method->isPropertyAccessor())
+ return 0;
+ if ((PDecl = Method->findPropertyDecl())) {
+ if (!PDecl->getDeclContext())
+ return 0;
+ // Make sure property belongs to accessor's class and not to
+ // one of its super classes.
+ if (const ObjCInterfaceDecl *CID =
+ dyn_cast<ObjCInterfaceDecl>(PDecl->getDeclContext()))
+ if (CID != IDecl)
+ return 0;
+ return PDecl->getPropertyIvarDecl();
+ }
+ return 0;
+}
+
+void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S) {
+ if (S->hasUnrecoverableErrorOccurred() || !S->isInObjcMethodScope())
+ return;
+
+ const ObjCMethodDecl *CurMethod = getCurMethodDecl();
+ if (!CurMethod)
+ return;
+ const ObjCPropertyDecl *PDecl;
+ const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
+ if (IV && !IV->getBackingIvarReferencedInAccessor()) {
+ Diag(getCurMethodDecl()->getLocation(), diag::warn_unused_property_backing_ivar)
+ << IV->getDeclName();
+ Diag(PDecl->getLocation(), diag::note_property_declare);
+ }
+}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 1a5f4824d091..3e8f324027dc 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -181,13 +181,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
return false;
}
- // The failure was something other than an empty exception
+ // The failure was something other than an missing exception
// specification; return an error.
- if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
+ if (!MissingExceptionSpecification)
return true;
const FunctionProtoType *NewProto =
- New->getType()->getAs<FunctionProtoType>();
+ New->getType()->castAs<FunctionProtoType>();
// The new function declaration is only missing an empty exception
// specification "throw()". If the throw() specification came from a
@@ -203,123 +203,94 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Old->isExternC()) {
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_DynamicNone;
- QualType NewType =
- Context.getFunctionType(NewProto->getResultType(),
- ArrayRef<QualType>(NewProto->arg_type_begin(),
- NewProto->getNumArgs()),
- EPI);
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->getArgTypes(), EPI);
New->setType(NewType);
return false;
}
- if (MissingExceptionSpecification && NewProto) {
- const FunctionProtoType *OldProto =
- Old->getType()->getAs<FunctionProtoType>();
-
- FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
- EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
- if (EPI.ExceptionSpecType == EST_Dynamic) {
- EPI.NumExceptions = OldProto->getNumExceptions();
- EPI.Exceptions = OldProto->exception_begin();
- } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
- // FIXME: We can't just take the expression from the old prototype. It
- // likely contains references to the old prototype's parameters.
- }
-
- // Update the type of the function with the appropriate exception
- // specification.
- QualType NewType =
- Context.getFunctionType(NewProto->getResultType(),
- ArrayRef<QualType>(NewProto->arg_type_begin(),
- NewProto->getNumArgs()),
- EPI);
- New->setType(NewType);
-
- // If exceptions are disabled, suppress the warning about missing
- // exception specifications for new and delete operators.
- if (!getLangOpts().CXXExceptions) {
- switch (New->getDeclName().getCXXOverloadedOperator()) {
- case OO_New:
- case OO_Array_New:
- case OO_Delete:
- case OO_Array_Delete:
- if (New->getDeclContext()->isTranslationUnit())
- return false;
- break;
-
- default:
- break;
- }
- }
-
- // Warn about the lack of exception specification.
- SmallString<128> ExceptionSpecString;
- llvm::raw_svector_ostream OS(ExceptionSpecString);
- switch (OldProto->getExceptionSpecType()) {
- case EST_DynamicNone:
- OS << "throw()";
- break;
+ const FunctionProtoType *OldProto =
+ Old->getType()->castAs<FunctionProtoType>();
+
+ FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
+ EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = OldProto->getNumExceptions();
+ EPI.Exceptions = OldProto->exception_begin();
+ } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ // FIXME: We can't just take the expression from the old prototype. It
+ // likely contains references to the old prototype's parameters.
+ }
- case EST_Dynamic: {
- OS << "throw(";
- bool OnFirstException = true;
- for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
- EEnd = OldProto->exception_end();
- E != EEnd;
- ++E) {
- if (OnFirstException)
- OnFirstException = false;
- else
- OS << ", ";
-
- OS << E->getAsString(getPrintingPolicy());
- }
- OS << ")";
- break;
+ // Update the type of the function with the appropriate exception
+ // specification.
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->getArgTypes(), EPI);
+ New->setType(NewType);
+
+ // Warn about the lack of exception specification.
+ SmallString<128> ExceptionSpecString;
+ llvm::raw_svector_ostream OS(ExceptionSpecString);
+ switch (OldProto->getExceptionSpecType()) {
+ case EST_DynamicNone:
+ OS << "throw()";
+ break;
+
+ case EST_Dynamic: {
+ OS << "throw(";
+ bool OnFirstException = true;
+ for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
+ EEnd = OldProto->exception_end();
+ E != EEnd;
+ ++E) {
+ if (OnFirstException)
+ OnFirstException = false;
+ else
+ OS << ", ";
+
+ OS << E->getAsString(getPrintingPolicy());
}
+ OS << ")";
+ break;
+ }
- case EST_BasicNoexcept:
- OS << "noexcept";
- break;
-
- case EST_ComputedNoexcept:
- OS << "noexcept(";
- OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy());
- OS << ")";
- break;
+ case EST_BasicNoexcept:
+ OS << "noexcept";
+ break;
- default:
- llvm_unreachable("This spec type is compatible with none.");
- }
- OS.flush();
+ case EST_ComputedNoexcept:
+ OS << "noexcept(";
+ OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy());
+ OS << ")";
+ break;
- SourceLocation FixItLoc;
- if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
- TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
- if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
- FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
- }
-
- if (FixItLoc.isInvalid())
- Diag(New->getLocation(), diag::warn_missing_exception_specification)
- << New << OS.str();
- else {
- // FIXME: This will get more complicated with C++0x
- // late-specified return types.
- Diag(New->getLocation(), diag::warn_missing_exception_specification)
- << New << OS.str()
- << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
- }
+ default:
+ llvm_unreachable("This spec type is compatible with none.");
+ }
+ OS.flush();
- if (!Old->getLocation().isInvalid())
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ SourceLocation FixItLoc;
+ if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
+ if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
+ FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
+ }
- return false;
+ if (FixItLoc.isInvalid())
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str();
+ else {
+ // FIXME: This will get more complicated with C++0x
+ // late-specified return types.
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str()
+ << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
}
- Diag(New->getLocation(), DiagID);
- Diag(Old->getLocation(), diag::note_previous_declaration);
- return true;
+ if (!Old->getLocation().isInvalid())
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+
+ return false;
}
/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
@@ -819,11 +790,8 @@ static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
return R;
}
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
- const Decl *D,
- bool NullThrows = true) {
- if (!D)
- return NullThrows ? CT_Can : CT_Cannot;
+static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
+ assert(D && "Expected decl");
// See if we can get a function type from the decl somehow.
const ValueDecl *VD = dyn_cast<ValueDecl>(D);
@@ -927,8 +895,10 @@ CanThrowResult Sema::canThrow(const Expr *E) {
CT = CT_Dependent;
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
CT = CT_Cannot;
- else
+ else if (CE->getCalleeDecl())
CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
+ else
+ CT = CT_Can;
if (CT == CT_Can)
return CT;
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
@@ -974,7 +944,9 @@ CanThrowResult Sema::canThrow(const Expr *E) {
cast<CXXDeleteExpr>(E)->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor()));
+ const CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD)
+ CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
}
if (CT == CT_Can)
return CT;
@@ -1012,6 +984,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CompoundLiteralExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::ExtVectorElementExprClass:
@@ -1022,6 +995,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ParenExprClass:
case Expr::ParenListExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
return canSubExprsThrow(*this, E);
@@ -1052,7 +1026,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ChooseExprClass:
if (E->isTypeDependent() || E->isValueDependent())
return CT_Dependent;
- return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
+ return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
case Expr::GenericSelectionExprClass:
if (cast<GenericSelectionExpr>(E)->isResultDependent())
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index dd05b822364d..e1f65f4a4e1b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -15,6 +15,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -140,11 +141,13 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
return Result;
}
-/// \brief Emit a note explaining that this function is deleted or unavailable.
+/// \brief Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
+ assert(Decl->isDeleted());
+
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
- if (Method && Method->isDeleted() && !Method->isDeletedAsWritten()) {
+ if (Method && Method->isDeleted() && Method->isDefaulted()) {
// If the method was explicitly defaulted, point at that declaration.
if (!Method->isImplicit())
Diag(Decl->getLocation(), diag::note_implicitly_deleted);
@@ -158,8 +161,23 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
return;
}
+ if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Decl)) {
+ if (CXXConstructorDecl *BaseCD =
+ const_cast<CXXConstructorDecl*>(CD->getInheritedConstructor())) {
+ Diag(Decl->getLocation(), diag::note_inherited_deleted_here);
+ if (BaseCD->isDeleted()) {
+ NoteDeletedFunction(BaseCD);
+ } else {
+ // FIXME: An explanation of why exactly it can't be inherited
+ // would be nice.
+ Diag(BaseCD->getLocation(), diag::note_cannot_inherit);
+ }
+ return;
+ }
+ }
+
Diag(Decl->getLocation(), diag::note_unavailable_here)
- << 1 << Decl->isDeleted();
+ << 1 << true;
}
/// \brief Determine whether a FunctionDecl was ever declared with an
@@ -197,11 +215,11 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
return;
if (!Current->isInlined())
return;
- if (Current->getLinkage() != ExternalLinkage)
+ if (!Current->isExternallyVisible())
return;
-
+
// Check if the decl has internal linkage.
- if (D->getLinkage() != InternalLinkage)
+ if (D->getFormalLinkage() != InternalLinkage)
return;
// Downgrade from ExtWarn to Extension if
@@ -212,7 +230,7 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
// This last can give us false negatives, but it's better than warning on
// wrappers for simple C library functions.
const FunctionDecl *UsedFn = dyn_cast<FunctionDecl>(D);
- bool DowngradeWarning = S.getSourceManager().isFromMainFile(Loc);
+ bool DowngradeWarning = S.getSourceManager().isInMainFile(Loc);
if (!DowngradeWarning && UsedFn)
DowngradeWarning = UsedFn->isInlined() || UsedFn->hasAttr<ConstAttr>();
@@ -228,7 +246,7 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
}
void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
- const FunctionDecl *First = Cur->getFirstDeclaration();
+ const FunctionDecl *First = Cur->getFirstDecl();
// Suggest "static" on the function, if possible.
if (!hasAnyExplicitStorageClass(First)) {
@@ -255,7 +273,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
- llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator
+ SuppressedDiagnosticsMap::iterator
Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
if (Pos != SuppressedDiagnostics.end()) {
SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second;
@@ -316,7 +334,7 @@ std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
/// if so, it checks that the requirements of the sentinel are
/// satisfied.
void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
- Expr **args, unsigned numArgs) {
+ ArrayRef<Expr *> Args) {
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
if (!attr)
return;
@@ -370,14 +388,14 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
// If there aren't enough arguments for all the formal parameters,
// the sentinel, and the args after the sentinel, complain.
- if (numArgs < numFormalParams + numArgsAfterSentinel + 1) {
+ if (Args.size() < numFormalParams + numArgsAfterSentinel + 1) {
Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
- Diag(D->getLocation(), diag::note_sentinel_here) << calleeType;
+ Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType);
return;
}
// Otherwise, find the sentinel expression.
- Expr *sentinelExpr = args[numArgs - numArgsAfterSentinel - 1];
+ Expr *sentinelExpr = Args[Args.size() - numArgsAfterSentinel - 1];
if (!sentinelExpr) return;
if (sentinelExpr->isValueDependent()) return;
if (Context.isSentinelNullExpr(sentinelExpr)) return;
@@ -398,12 +416,12 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
NullValue = "(void*) 0";
if (MissingNilLoc.isInvalid())
- Diag(Loc, diag::warn_missing_sentinel) << calleeType;
+ Diag(Loc, diag::warn_missing_sentinel) << int(calleeType);
else
Diag(MissingNilLoc, diag::warn_missing_sentinel)
- << calleeType
+ << int(calleeType)
<< FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue);
- Diag(D->getLocation(), diag::note_sentinel_here) << calleeType;
+ Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType);
}
SourceRange Sema::getExprRange(Expr *E) const {
@@ -725,6 +743,17 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// when we're in an unevaluated context.
Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isIncompleteType()) {
+ // C++11 [expr.call]p7:
+ // After these conversions, if the argument does not have arithmetic,
+ // enumeration, pointer, pointer to member, or class type, the program
+ // is ill-formed.
+ //
+ // Since we've already performed array-to-pointer and function-to-pointer
+ // decay, the only such type in C++ is cv void. This also handles
+ // initializer lists as variadic arguments.
+ if (Ty->isVoidType())
+ return VAK_Invalid;
+
if (Ty->isObjCObjectType())
return VAK_Invalid;
return VAK_Valid;
@@ -747,35 +776,50 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())
return VAK_Valid;
- return VAK_Invalid;
+
+ if (Ty->isObjCObjectType())
+ return VAK_Invalid;
+
+ // FIXME: In C++11, these cases are conditionally-supported, meaning we're
+ // permitted to reject them. We should consider doing so.
+ return VAK_Undefined;
}
-bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
+void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
// Don't allow one to pass an Objective-C interface to a vararg.
- const QualType & Ty = E->getType();
+ const QualType &Ty = E->getType();
+ VarArgKind VAK = isValidVarArgType(Ty);
// Complain about passing non-POD types through varargs.
- switch (isValidVarArgType(Ty)) {
+ switch (VAK) {
case VAK_Valid:
break;
+
case VAK_ValidInCXX11:
- DiagRuntimeBehavior(E->getLocStart(), 0,
+ DiagRuntimeBehavior(
+ E->getLocStart(), 0,
PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
- << E->getType() << CT);
+ << E->getType() << CT);
break;
- case VAK_Invalid: {
- if (Ty->isObjCObjectType())
- return DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << Ty << CT);
- return DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << getLangOpts().CPlusPlus11 << Ty << CT);
- }
+ case VAK_Undefined:
+ DiagRuntimeBehavior(
+ E->getLocStart(), 0,
+ PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << getLangOpts().CPlusPlus11 << Ty << CT);
+ break;
+
+ case VAK_Invalid:
+ if (Ty->isObjCObjectType())
+ DiagRuntimeBehavior(
+ E->getLocStart(), 0,
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << Ty << CT);
+ else
+ Diag(E->getLocStart(), diag::err_cannot_pass_to_vararg)
+ << isa<InitListExpr>(E) << Ty << CT;
+ break;
}
- // c++ rules are enforced elsewhere.
- return false;
}
/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
@@ -805,7 +849,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
// Diagnostics regarding non-POD argument types are
// emitted along with format string checking in Sema::CheckFunctionCall().
- if (isValidVarArgType(E->getType()) == VAK_Invalid) {
+ if (isValidVarArgType(E->getType()) == VAK_Undefined) {
// Turn this into a trap.
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
@@ -1230,25 +1274,23 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- MultiTypeArg ArgTypes,
- MultiExprArg ArgExprs) {
+ ArrayRef<ParsedType> ArgTypes,
+ ArrayRef<Expr *> ArgExprs) {
unsigned NumAssocs = ArgTypes.size();
assert(NumAssocs == ArgExprs.size());
- ParsedType *ParsedTypes = ArgTypes.data();
- Expr **Exprs = ArgExprs.data();
-
TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
- if (ParsedTypes[i])
- (void) GetTypeFromParser(ParsedTypes[i], &Types[i]);
+ if (ArgTypes[i])
+ (void) GetTypeFromParser(ArgTypes[i], &Types[i]);
else
Types[i] = 0;
}
ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
- ControllingExpr, Types, Exprs,
- NumAssocs);
+ ControllingExpr,
+ llvm::makeArrayRef(Types, NumAssocs),
+ ArgExprs);
delete [] Types;
return ER;
}
@@ -1258,9 +1300,10 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- TypeSourceInfo **Types,
- Expr **Exprs,
- unsigned NumAssocs) {
+ ArrayRef<TypeSourceInfo *> Types,
+ ArrayRef<Expr *> Exprs) {
+ unsigned NumAssocs = Types.size();
+ assert(NumAssocs == Exprs.size());
if (ControllingExpr->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(ControllingExpr);
if (result.isInvalid()) return ExprError();
@@ -1328,8 +1371,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
if (IsResultDependent)
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- llvm::makeArrayRef(Types, NumAssocs),
- llvm::makeArrayRef(Exprs, NumAssocs),
+ Types, Exprs,
DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack));
SmallVector<unsigned, 1> CompatIndices;
@@ -1352,7 +1394,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
<< ControllingExpr->getSourceRange() << ControllingExpr->getType()
<< (unsigned) CompatIndices.size();
- for (SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
+ for (SmallVectorImpl<unsigned>::iterator I = CompatIndices.begin(),
E = CompatIndices.end(); I != E; ++I) {
Diag(Types[*I]->getTypeLoc().getBeginLoc(),
diag::note_compat_assoc)
@@ -1384,8 +1426,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- llvm::makeArrayRef(Types, NumAssocs),
- llvm::makeArrayRef(Exprs, NumAssocs),
+ Types, Exprs,
DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack,
ResultIndex));
}
@@ -1421,7 +1462,8 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
- /*AllowRawAndTemplate*/false) == Sema::LOLR_Error)
+ /*AllowRaw*/false, /*AllowTemplate*/false,
+ /*AllowStringTemplate*/false) == Sema::LOLR_Error)
return ExprError();
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
@@ -1446,36 +1488,39 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
for (unsigned i = 0; i != NumStringToks; ++i)
StringTokLocs.push_back(StringToks[i].getLocation());
- QualType StrTy = Context.CharTy;
- if (Literal.isWide())
- StrTy = Context.getWCharType();
- else if (Literal.isUTF16())
- StrTy = Context.Char16Ty;
- else if (Literal.isUTF32())
- StrTy = Context.Char32Ty;
- else if (Literal.isPascal())
- StrTy = Context.UnsignedCharTy;
-
+ QualType CharTy = Context.CharTy;
StringLiteral::StringKind Kind = StringLiteral::Ascii;
- if (Literal.isWide())
+ if (Literal.isWide()) {
+ CharTy = Context.getWideCharType();
Kind = StringLiteral::Wide;
- else if (Literal.isUTF8())
+ } else if (Literal.isUTF8()) {
Kind = StringLiteral::UTF8;
- else if (Literal.isUTF16())
+ } else if (Literal.isUTF16()) {
+ CharTy = Context.Char16Ty;
Kind = StringLiteral::UTF16;
- else if (Literal.isUTF32())
+ } else if (Literal.isUTF32()) {
+ CharTy = Context.Char32Ty;
Kind = StringLiteral::UTF32;
+ } else if (Literal.isPascal()) {
+ CharTy = Context.UnsignedCharTy;
+ }
+ QualType CharTyConst = CharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
- StrTy.addConst();
+ CharTyConst.addConst();
// Get an array type for the string, according to C99 6.4.5. This includes
// the nul terminator character as well as the string length for pascal
// strings.
- StrTy = Context.getConstantArrayType(StrTy,
+ QualType StrTy = Context.getConstantArrayType(CharTyConst,
llvm::APInt(32, Literal.GetNumStringChars()+1),
- ArrayType::Normal, 0);
+ ArrayType::Normal, 0);
+
+ // OpenCL v1.1 s6.5.3: a string literal is in the constant address space.
+ if (getLangOpts().OpenCL) {
+ StrTy = Context.getAddrSpaceQualType(StrTy, LangAS::opencl_constant);
+ }
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(),
@@ -1498,12 +1543,57 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
// C++11 [lex.ext]p5: The literal L is treated as a call of the form
// operator "" X (str, len)
QualType SizeType = Context.getSizeType();
- llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
- IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
- StringTokLocs[0]);
- Expr *Args[] = { Lit, LenArg };
- return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
- Args, StringTokLocs.back());
+
+ DeclarationName OpName =
+ Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
+ DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
+ OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+
+ QualType ArgTy[] = {
+ Context.getArrayDecayedType(StrTy), SizeType
+ };
+
+ LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
+ switch (LookupLiteralOperator(UDLScope, R, ArgTy,
+ /*AllowRaw*/false, /*AllowTemplate*/false,
+ /*AllowStringTemplate*/true)) {
+
+ case LOLR_Cooked: {
+ llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
+ IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
+ StringTokLocs[0]);
+ Expr *Args[] = { Lit, LenArg };
+
+ return BuildLiteralOperatorCall(R, OpNameInfo, Args, StringTokLocs.back());
+ }
+
+ case LOLR_StringTemplate: {
+ TemplateArgumentListInfo ExplicitArgs;
+
+ unsigned CharBits = Context.getIntWidth(CharTy);
+ bool CharIsUnsigned = CharTy->isUnsignedIntegerType();
+ llvm::APSInt Value(CharBits, CharIsUnsigned);
+
+ TemplateArgument TypeArg(CharTy);
+ TemplateArgumentLocInfo TypeArgInfo(Context.getTrivialTypeSourceInfo(CharTy));
+ ExplicitArgs.addArgument(TemplateArgumentLoc(TypeArg, TypeArgInfo));
+
+ for (unsigned I = 0, N = Lit->getLength(); I != N; ++I) {
+ Value = Lit->getCodeUnit(I);
+ TemplateArgument Arg(Context, Value, CharTy);
+ TemplateArgumentLocInfo ArgInfo;
+ ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
+ }
+ return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
+ &ExplicitArgs);
+ }
+ case LOLR_Raw:
+ case LOLR_Template:
+ llvm_unreachable("unexpected literal operator lookup result");
+ case LOLR_Error:
+ return ExprError();
+ }
+ llvm_unreachable("unexpected literal operator lookup result");
}
ExprResult
@@ -1519,7 +1609,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS, NamedDecl *FoundD) {
+ const CXXScopeSpec *SS, NamedDecl *FoundD,
+ const TemplateArgumentListInfo *TemplateArgs) {
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
@@ -1536,14 +1627,28 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
bool refersToEnclosingScope =
(CurContext != D->getDeclContext() &&
- D->getDeclContext()->isFunctionOrMethod());
-
- DeclRefExpr *E = DeclRefExpr::Create(Context,
- SS ? SS->getWithLocInContext(Context)
- : NestedNameSpecifierLoc(),
- SourceLocation(),
- D, refersToEnclosingScope,
- NameInfo, Ty, VK, FoundD);
+ D->getDeclContext()->isFunctionOrMethod()) ||
+ (isa<VarDecl>(D) &&
+ cast<VarDecl>(D)->isInitCapture());
+
+ DeclRefExpr *E;
+ if (isa<VarTemplateSpecializationDecl>(D)) {
+ VarTemplateSpecializationDecl *VarSpec =
+ cast<VarTemplateSpecializationDecl>(D);
+
+ E = DeclRefExpr::Create(
+ Context,
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
+ VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope,
+ NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs);
+ } else {
+ assert(!TemplateArgs && "No template arguments for non-variable"
+ " template specialization referrences");
+ E = DeclRefExpr::Create(
+ Context,
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
+ SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD);
+ }
MarkDeclRefReferenced(E);
@@ -1553,7 +1658,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
E->getLocStart());
if (Level != DiagnosticsEngine::Ignored)
- getCurFunction()->recordUseOfWeak(E);
+ recordUseOfEvaluatedWeak(E);
}
// Just in case we're building an illegal pointer-to-member.
@@ -1602,7 +1707,7 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1722,10 +1827,14 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
S, &SS, CCC))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+ bool DroppedSpecifier =
+ Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
R.setLookupName(Corrected.getCorrection());
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ bool AcceptableWithRecovery = false;
+ bool AcceptableWithoutRecovery = false;
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ if (ND) {
if (Corrected.isOverloaded()) {
OverloadCandidateSet OCS(R.getNameLoc());
OverloadCandidateSet::iterator Best;
@@ -1743,63 +1852,49 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
Args, OCS);
}
switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
- case OR_Success:
- ND = Best->Function;
- break;
- default:
- break;
+ case OR_Success:
+ ND = Best->Function;
+ Corrected.setCorrectionDecl(ND);
+ break;
+ default:
+ // FIXME: Arbitrarily pick the first declaration for the note.
+ Corrected.setCorrectionDecl(ND);
+ break;
}
}
R.addDecl(ND);
- if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
- if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
- else
- Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
- << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- unsigned diag = isa<ImplicitParamDecl>(ND)
- ? diag::note_implicit_param_decl
- : diag::note_previous_decl;
-
- Diag(ND->getLocation(), diag)
- << CorrectedQuotedStr;
-
- // Tell the callee to try to recover.
- return false;
- }
-
- if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) {
- // FIXME: If we ended up with a typo for a type name or
- // Objective-C class name, we're in trouble because the parser
- // is in the wrong place to recover. Suggest the typo
- // correction, but don't make it a fix-it since we're not going
- // to recover well anyway.
- if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest)
- << Name << CorrectedQuotedStr;
- else
- Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
- << SS.getRange();
-
- // Don't try to recover; it won't work.
- return true;
- }
+ AcceptableWithRecovery =
+ isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND);
+ // FIXME: If we ended up with a typo for a type name or
+ // Objective-C class name, we're in trouble because the parser
+ // is in the wrong place to recover. Suggest the typo
+ // correction, but don't make it a fix-it since we're not going
+ // to recover well anyway.
+ AcceptableWithoutRecovery =
+ isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
} else {
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
+ AcceptableWithoutRecovery = true;
+ }
+
+ if (AcceptableWithRecovery || AcceptableWithoutRecovery) {
+ unsigned NoteID = (Corrected.getCorrectionDecl() &&
+ isa<ImplicitParamDecl>(Corrected.getCorrectionDecl()))
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
+ diagnoseTypo(Corrected, PDiag(diagnostic_suggest) << Name,
+ PDiag(NoteID), AcceptableWithRecovery);
else
- Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
- << SS.getRange();
- return true;
+ diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false)
+ << DroppedSpecifier << SS.getRange(),
+ PDiag(NoteID), AcceptableWithRecovery);
+
+ // Tell the callee whether to try to recover.
+ return !AcceptableWithRecovery;
}
}
R.clear();
@@ -1824,10 +1919,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
UnqualifiedId &Id,
bool HasTrailingLParen,
bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC) {
+ CorrectionCandidateCallback *CCC,
+ bool IsInlineAsmIdentifier) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
-
if (SS.isInvalid())
return ExprError();
@@ -1918,6 +2013,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
if (R.empty() && !ADL) {
+
// Otherwise, this could be an implicitly declared function reference (legal
// in C90, extension in C99, forbidden in C++).
if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
@@ -1930,16 +2026,32 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (R.empty()) {
// In Microsoft mode, if we are inside a template class member function
// whose parent class has dependent base classes, and we can't resolve
- // an identifier, then assume the identifier is type dependent. The
- // goal is to postpone name lookup to instantiation time to be able to
- // search into the type dependent base classes.
+ // an identifier, then assume the identifier is a member of a dependent
+ // base class. The goal is to postpone name lookup to instantiation time
+ // to be able to search into the type dependent base classes.
+ // FIXME: If we want 100% compatibility with MSVC, we will have delay all
+ // unqualified name lookup. Any name lookup during template parsing means
+ // clang might find something that MSVC doesn't. For now, we only handle
+ // the common case of members of a dependent base class.
if (getLangOpts().MicrosoftMode) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
- if (MD && MD->getParent()->hasAnyDependentBases())
- return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
- IsAddressOfOperand, TemplateArgs);
+ if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) {
+ assert(SS.isEmpty() && "qualifiers should be already handled");
+ QualType ThisType = MD->getThisType(Context);
+ // Since the 'this' expression is synthesized, we don't need to
+ // perform the double-lookup check.
+ NamedDecl *FirstQualifierInScope = 0;
+ return Owned(CXXDependentScopeMemberExpr::Create(
+ Context, /*This=*/0, ThisType, /*IsArrow=*/true,
+ /*Op=*/SourceLocation(), SS.getWithLocInContext(Context),
+ TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs));
+ }
}
+ // Don't diagnose an empty lookup for inline assmebly.
+ if (IsInlineAsmIdentifier)
+ return ExprError();
+
CorrectionCandidateCallback DefaultValidator;
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
return ExprError();
@@ -2001,15 +2113,27 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
- isa<IndirectFieldDecl>(R.getFoundDecl());
+ isa<IndirectFieldDecl>(R.getFoundDecl()) ||
+ isa<MSPropertyDecl>(R.getFoundDecl());
if (MightBeImplicitMember)
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
R, TemplateArgs);
}
- if (TemplateArgs || TemplateKWLoc.isValid())
+ if (TemplateArgs || TemplateKWLoc.isValid()) {
+
+ // In C++1y, if this is a variable template id, then check it
+ // in BuildTemplateIdExpr().
+ // The single lookup result must be a variable template declaration.
+ if (Id.getKind() == UnqualifiedId::IK_TemplateId && Id.TemplateId &&
+ Id.TemplateId->Kind == TNK_Var_template) {
+ assert(R.getAsSingle<VarTemplateDecl>() &&
+ "There should only be one declaration found.");
+ }
+
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
+ }
return BuildDeclarationNameExpr(SS, R, ADL);
}
@@ -2139,6 +2263,14 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprError();
MarkAnyDeclReferenced(Loc, IV, true);
+ if (!IV->getBackingIvarReferencedInAccessor()) {
+ // Mark this ivar 'referenced' in this method, if it is a backing ivar
+ // of a property and current method is one of its property accessor.
+ const ObjCPropertyDecl *PDecl;
+ const ObjCIvarDecl *BIV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
+ if (BIV && BIV == IV)
+ IV->setBackingIvarReferencedInAccessor(true);
+ }
ObjCMethodFamily MF = CurMethod->getMethodFamily();
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
@@ -2155,7 +2287,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
DiagnosticsEngine::Level Level =
Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
if (Level != DiagnosticsEngine::Ignored)
- getCurFunction()->recordUseOfWeak(Result);
+ recordUseOfEvaluatedWeak(Result);
}
if (CurContext->isClosure())
Diag(Loc, diag::warn_implicitly_retains_self)
@@ -2289,9 +2421,8 @@ Sema::PerformObjectMemberConversion(Expr *From,
// x = 17; // error: ambiguous base subobjects
// Derived1::x = 17; // okay, pick the Base subobject of Derived1
// }
- if (Qualifier) {
+ if (Qualifier && Qualifier->getAsType()) {
QualType QType = QualType(Qualifier->getAsType(), 0);
- assert(!QType.isNull() && "lookup done with dependent qualifier?");
assert(QType->isRecordType() && "lookup done with non-record type");
QualType QRecordType = QualType(QType->getAs<RecordType>(), 0);
@@ -2400,7 +2531,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
// turn off ADL anyway).
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- else if (D->getDeclContext()->isFunctionOrMethod())
+ else if (D->getLexicalDeclContext()->isFunctionOrMethod())
return false;
// C++0x [basic.lookup.argdep]p3:
@@ -2477,10 +2608,9 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
/// \brief Complete semantic analysis for a reference to the given declaration.
-ExprResult
-Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- NamedDecl *D, NamedDecl *FoundD) {
+ExprResult Sema::BuildDeclarationNameExpr(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
+ NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) {
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
@@ -2492,8 +2622,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
// a template argument list.
- Diag(Loc, diag::err_template_decl_ref)
- << Template << SS.getRange();
+ Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0)
+ << Template << SS.getRange();
Diag(Template->getLocation(), diag::note_template_decl_here);
return ExprError();
}
@@ -2583,6 +2713,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
case Decl::Var:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
// In C, "extern void blah;" is valid and is an r-value.
if (!getLangOpts().CPlusPlus &&
!type.hasQualifiers() &&
@@ -2680,32 +2812,23 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD);
+ return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+ TemplateArgs);
}
}
-ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
- PredefinedExpr::IdentType IT;
-
- switch (Kind) {
- default: llvm_unreachable("Unknown simple primary expr!");
- case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
- case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
- case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
- case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
- }
-
- // Pre-defined identifiers are of type char[x], where x is the length of the
- // string.
-
- Decl *currentDecl = getCurFunctionOrMethodDecl();
- // Blocks and lambdas can occur at global scope. Don't emit a warning.
- if (!currentDecl) {
- if (const BlockScopeInfo *BSI = getCurBlock())
- currentDecl = BSI->TheDecl;
- else if (const LambdaScopeInfo *LSI = getCurLambda())
- currentDecl = LSI->CallOperator;
- }
+ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
+ PredefinedExpr::IdentType IT) {
+ // Pick the current block, lambda, captured statement or function.
+ Decl *currentDecl = 0;
+ if (const BlockScopeInfo *BSI = getCurBlock())
+ currentDecl = BSI->TheDecl;
+ else if (const LambdaScopeInfo *LSI = getCurLambda())
+ currentDecl = LSI->CallOperator;
+ else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion())
+ currentDecl = CSI->TheCapturedDecl;
+ else
+ currentDecl = getCurFunctionOrMethodDecl();
if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
@@ -2713,21 +2836,39 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
}
QualType ResTy;
- if (cast<DeclContext>(currentDecl)->isDependentContext()) {
+ if (cast<DeclContext>(currentDecl)->isDependentContext())
ResTy = Context.DependentTy;
- } else {
+ else {
+ // Pre-defined identifiers are of type char[x], where x is the length of
+ // the string.
unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
if (IT == PredefinedExpr::LFunction)
- ResTy = Context.WCharTy.withConst();
+ ResTy = Context.WideCharTy.withConst();
else
ResTy = Context.CharTy.withConst();
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
}
+
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
}
+ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
+ PredefinedExpr::IdentType IT;
+
+ switch (Kind) {
+ default: llvm_unreachable("Unknown simple primary expr!");
+ case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
+ case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
+ case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS]
+ case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
+ case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
+ }
+
+ return BuildPredefinedExpr(Loc, IT);
+}
+
ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
SmallString<16> CharBuffer;
bool Invalid = false;
@@ -2742,7 +2883,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
QualType Ty;
if (Literal.isWide())
- Ty = Context.WCharTy; // L'x' -> wchar_t in C and C++.
+ Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++.
else if (Literal.isUTF16())
Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
else if (Literal.isUTF32())
@@ -2872,11 +3013,14 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+ SourceLocation TokLoc = Tok.getLocation();
+
// Perform literal operator lookup to determine if we're building a raw
// literal or a cooked one.
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, CookedTy,
- /*AllowRawAndTemplate*/true)) {
+ /*AllowRaw*/true, /*AllowTemplate*/true,
+ /*AllowStringTemplate*/false)) {
case LOLR_Error:
return ExprError();
@@ -2887,19 +3031,17 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0);
if (Literal.GetIntegerValue(ResultVal))
- Diag(Tok.getLocation(), diag::warn_integer_too_large);
+ Diag(Tok.getLocation(), diag::err_integer_too_large);
Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy,
Tok.getLocation());
}
- return BuildLiteralOperatorCall(R, OpNameInfo, Lit,
- Tok.getLocation());
+ return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
}
case LOLR_Raw: {
// C++11 [lit.ext]p3, p4: If S contains a raw literal operator, the
// literal is treated as a call of the form
// operator "" X ("n")
- SourceLocation TokLoc = Tok.getLocation();
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
Context.CharTy.withConst(), llvm::APInt(32, Length + 1),
@@ -2910,7 +3052,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
}
- case LOLR_Template:
+ case LOLR_Template: {
// C++11 [lit.ext]p3, p4: Otherwise (S contains a literal operator
// template), L is treated as a call fo the form
// operator "" X <'c1', 'c2', ... 'ck'>()
@@ -2925,11 +3067,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, Tok.getLocation(),
+ return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc,
&ExplicitArgs);
}
-
- llvm_unreachable("unexpected literal operator lookup result");
+ case LOLR_StringTemplate:
+ llvm_unreachable("unexpected literal operator lookup result");
+ }
}
Expr *Res;
@@ -2980,8 +3123,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
llvm::APInt ResultVal(MaxWidth, 0);
if (Literal.GetIntegerValue(ResultVal)) {
- // If this value didn't fit into uintmax_t, warn and force to ull.
- Diag(Tok.getLocation(), diag::warn_integer_too_large);
+ // If this value didn't fit into uintmax_t, error and force to ull.
+ Diag(Tok.getLocation(), diag::err_integer_too_large);
Ty = Context.UnsignedLongLongTy;
assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() &&
"long long is not intmax_t?");
@@ -3103,6 +3246,10 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
SourceLocation Loc,
SourceRange ArgRange,
UnaryExprOrTypeTrait TraitKind) {
+ // Invalid types must be hard errors for SFINAE in C++.
+ if (S.LangOpts.CPlusPlus)
+ return true;
+
// C99 6.5.3.4p1:
if (T->isFunctionType() &&
(TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) {
@@ -3185,6 +3332,12 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
ExprTy = E->getType();
assert(!ExprTy->isReferenceType());
+ if (ExprTy->isFunctionType()) {
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_function_type)
+ << ExprKind << E->getSourceRange();
+ return true;
+ }
+
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
E->getSourceRange(), ExprKind))
return true;
@@ -3258,6 +3411,12 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
ExprKind, ExprRange))
return true;
+ if (ExprType->isFunctionType()) {
+ Diag(OpLoc, diag::err_sizeof_alignof_function_type)
+ << ExprKind << ExprRange;
+ return true;
+ }
+
if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
ExprKind))
return true;
@@ -3487,7 +3646,8 @@ static bool checkArithmeticOnObjCPointer(Sema &S,
SourceLocation opLoc,
Expr *op) {
assert(op->getType()->isObjCObjectPointerType());
- if (S.LangOpts.ObjCRuntime.allowsPointerArithmetic())
+ if (S.LangOpts.ObjCRuntime.allowsPointerArithmetic() &&
+ !S.LangOpts.ObjCSubscriptingLegacyRuntime)
return false;
S.Diag(opLoc, diag::err_arithmetic_nonfragile_interface)
@@ -3592,15 +3752,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// Use custom logic if this should be the pseudo-object subscript
// expression.
- if (!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic())
+ if (!LangOpts.isSubscriptPointerArithmetic())
return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
ResultType = PTy->getPointeeType();
- if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
- Diag(LLoc, diag::err_subscript_nonfragile_interface)
- << ResultType << BaseExpr->getSourceRange();
- return ExprError();
- }
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
@@ -3612,7 +3767,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
- if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
+ if (!LangOpts.isSubscriptPointerArithmetic()) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
@@ -3720,7 +3875,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
InstantiatingTemplate Inst(*this, CallLoc, Param,
MutiLevelArgList.getInnermost());
- if (Inst)
+ if (Inst.isInvalid())
return ExprError();
ExprResult Result;
@@ -3795,12 +3950,71 @@ Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto,
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
if (Method->isInstance())
return VariadicMethod;
- }
+ } else if (Fn && Fn->getType() == Context.BoundMemberTy)
+ return VariadicMethod;
return VariadicFunction;
}
return VariadicDoesNotApply;
}
+namespace {
+class FunctionCallCCC : public FunctionCallFilterCCC {
+public:
+ FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName,
+ unsigned NumArgs, bool HasExplicitTemplateArgs)
+ : FunctionCallFilterCCC(SemaRef, NumArgs, HasExplicitTemplateArgs),
+ FunctionName(FuncName) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (!candidate.getCorrectionSpecifier() ||
+ candidate.getCorrectionAsIdentifierInfo() != FunctionName) {
+ return false;
+ }
+
+ return FunctionCallFilterCCC::ValidateCandidate(candidate);
+ }
+
+private:
+ const IdentifierInfo *const FunctionName;
+};
+}
+
+static TypoCorrection TryTypoCorrectionForCall(Sema &S,
+ DeclarationNameInfo FuncName,
+ ArrayRef<Expr *> Args) {
+ FunctionCallCCC CCC(S, FuncName.getName().getAsIdentifierInfo(),
+ Args.size(), false);
+ if (TypoCorrection Corrected =
+ S.CorrectTypo(FuncName, Sema::LookupOrdinaryName,
+ S.getScopeForContext(S.CurContext), NULL, CCC)) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ if (Corrected.isOverloaded()) {
+ OverloadCandidateSet OCS(FuncName.getLoc());
+ OverloadCandidateSet::iterator Best;
+ for (TypoCorrection::decl_iterator CD = Corrected.begin(),
+ CDEnd = Corrected.end();
+ CD != CDEnd; ++CD) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
+ S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args,
+ OCS);
+ }
+ switch (OCS.BestViableFunction(S, FuncName.getLoc(), Best)) {
+ case OR_Success:
+ ND = Best->Function;
+ Corrected.setCorrectionDecl(ND);
+ break;
+ default:
+ break;
+ }
+ }
+ if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
+ return Corrected;
+ }
+ }
+ }
+ return TypoCorrection();
+}
+
/// ConvertArgumentsForCall - Converts the arguments specified in
/// Args/NumArgs to the parameter types of the function FDecl with
/// function prototype Proto. Call is the call expression itself, and
@@ -3811,7 +4025,7 @@ bool
Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool IsExecConfig) {
// Bail out early if calling a builtin with custom typechecking.
@@ -3833,9 +4047,23 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// If too few arguments are available (and we don't have default
// arguments for the remaining parameters), don't make the call.
- if (NumArgs < NumArgsInProto) {
- if (NumArgs < MinArgs) {
- if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
+ if (Args.size() < NumArgsInProto) {
+ if (Args.size() < MinArgs) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
+ TypoCorrection TC;
+ if (FDecl && (TC = TryTypoCorrectionForCall(
+ *this, DeclarationNameInfo(FDecl->getDeclName(),
+ (ME ? ME->getMemberLoc()
+ : Fn->getLocStart())),
+ Args))) {
+ unsigned diag_id =
+ MinArgs == NumArgsInProto && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_few_args_suggest
+ : diag::err_typecheck_call_too_few_args_at_least_suggest;
+ diagnoseTypo(TC, PDiag(diag_id) << FnKind << MinArgs
+ << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange());
+ } else if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args_one
: diag::err_typecheck_call_too_few_args_at_least_one)
@@ -3846,10 +4074,11 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
? diag::err_typecheck_call_too_few_args
: diag::err_typecheck_call_too_few_args_at_least)
<< FnKind
- << MinArgs << NumArgs << Fn->getSourceRange();
+ << MinArgs << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange();
// Emit the location of the prototype.
- if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
+ if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
Diag(FDecl->getLocStart(), diag::note_callee_decl)
<< FDecl;
@@ -3860,29 +4089,44 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// If too many are passed and not variadic, error on the extras and drop
// them.
- if (NumArgs > NumArgsInProto) {
+ if (Args.size() > NumArgsInProto) {
if (!Proto->isVariadic()) {
- if (NumArgsInProto == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
+ TypoCorrection TC;
+ if (FDecl && (TC = TryTypoCorrectionForCall(
+ *this, DeclarationNameInfo(FDecl->getDeclName(),
+ Fn->getLocStart()),
+ Args))) {
+ unsigned diag_id =
+ MinArgs == NumArgsInProto && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_many_args_suggest
+ : diag::err_typecheck_call_too_many_args_at_most_suggest;
+ diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumArgsInProto
+ << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange());
+ } else if (NumArgsInProto == 1 && FDecl &&
+ FDecl->getParamDecl(0)->getDeclName())
Diag(Args[NumArgsInProto]->getLocStart(),
MinArgs == NumArgsInProto
? diag::err_typecheck_call_too_many_args_one
: diag::err_typecheck_call_too_many_args_at_most_one)
<< FnKind
- << FDecl->getParamDecl(0) << NumArgs << Fn->getSourceRange()
+ << FDecl->getParamDecl(0) << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
- Args[NumArgs-1]->getLocEnd());
+ Args.back()->getLocEnd());
else
Diag(Args[NumArgsInProto]->getLocStart(),
MinArgs == NumArgsInProto
? diag::err_typecheck_call_too_many_args
: diag::err_typecheck_call_too_many_args_at_most)
<< FnKind
- << NumArgsInProto << NumArgs << Fn->getSourceRange()
+ << NumArgsInProto << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
- Args[NumArgs-1]->getLocEnd());
+ Args.back()->getLocEnd());
// Emit the location of the prototype.
- if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
+ if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
Diag(FDecl->getLocStart(), diag::note_callee_decl)
<< FDecl;
@@ -3895,7 +4139,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
- Proto, 0, Args, NumArgs, AllArgs, CallType);
+ Proto, 0, Args, AllArgs, CallType);
if (Invalid)
return true;
unsigned TotalNumArgs = AllArgs.size();
@@ -3909,15 +4153,15 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
unsigned FirstProtoArg,
- Expr **Args, unsigned NumArgs,
- SmallVector<Expr *, 8> &AllArgs,
+ ArrayRef<Expr *> Args,
+ SmallVectorImpl<Expr *> &AllArgs,
VariadicCallType CallType,
bool AllowExplicit,
bool IsListInitialization) {
unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumArgsToCheck = NumArgs;
+ unsigned NumArgsToCheck = Args.size();
bool Invalid = false;
- if (NumArgs != NumArgsInProto)
+ if (Args.size() != NumArgsInProto)
// Use default arguments for missing arguments
NumArgsToCheck = NumArgsInProto;
unsigned ArgIx = 0;
@@ -3927,7 +4171,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Expr *Arg;
ParmVarDecl *Param;
- if (ArgIx < NumArgs) {
+ if (ArgIx < Args.size()) {
Arg = Args[ArgIx++];
if (RequireCompleteType(Arg->getLocStart(),
@@ -3941,15 +4185,25 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Param = FDecl->getParamDecl(i);
// Strip the unbridged-cast placeholder expression off, if applicable.
+ bool CFAudited = false;
if (Arg->getType() == Context.ARCUnbridgedCastTy &&
FDecl && FDecl->hasAttr<CFAuditedTransferAttr>() &&
(!Param || !Param->hasAttr<CFConsumedAttr>()))
Arg = stripARCUnbridgedCast(Arg);
+ else if (getLangOpts().ObjCAutoRefCount &&
+ FDecl && FDecl->hasAttr<CFAuditedTransferAttr>() &&
+ (!Param || !Param->hasAttr<CFConsumedAttr>()))
+ CFAudited = true;
InitializedEntity Entity = Param ?
InitializedEntity::InitializeParameter(Context, Param, ProtoArgType)
: InitializedEntity::InitializeParameter(Context, ProtoArgType,
Proto->isArgConsumed(i));
+
+ // Remember that parameter belongs to a CF audited API.
+ if (CFAudited)
+ Entity.setParameterCFAudited();
+
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg),
@@ -3988,7 +4242,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// return __unknown_anytype aren't *really* variadic.
if (Proto->getResultType() == Context.UnknownAnyTy &&
FDecl && FDecl->isExternC()) {
- for (unsigned i = ArgIx; i != NumArgs; ++i) {
+ for (unsigned i = ArgIx, e = Args.size(); i != e; ++i) {
QualType paramType; // ignored
ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
Invalid |= arg.isInvalid();
@@ -3997,7 +4251,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// Otherwise do argument promotion, (C99 6.5.2.2p7).
} else {
- for (unsigned i = ArgIx; i != NumArgs; ++i) {
+ for (unsigned i = ArgIx, e = Args.size(); i != e; ++i) {
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType,
FDecl);
Invalid |= Arg.isInvalid();
@@ -4006,7 +4260,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
}
// Check for array bounds violations.
- for (unsigned i = ArgIx; i != NumArgs; ++i)
+ for (unsigned i = ArgIx, e = Args.size(); i != e; ++i)
CheckArrayAccess(Args[i]);
}
return Invalid;
@@ -4014,6 +4268,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) {
TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc();
+ if (DecayedTypeLoc DTL = TL.getAs<DecayedTypeLoc>())
+ TL = DTL.getOriginalLoc();
if (ArrayTypeLoc ATL = TL.getAs<ArrayTypeLoc>())
S.Diag(PVD->getLocation(), diag::note_callee_static_array)
<< ATL.getLocalSourceRange();
@@ -4188,8 +4444,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
// Determine whether this is a call to an object (C++ [over.call.object]).
if (Fn->getType()->isRecordType())
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc,
- ArgExprs.data(),
- ArgExprs.size(), RParenLoc));
+ ArgExprs, RParenLoc));
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
@@ -4198,8 +4453,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
}
if (Fn->getType() == Context.BoundMemberTy) {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
- ArgExprs.size(), RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc);
}
}
@@ -4212,11 +4466,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
OverloadExpr *ovl = find.Expression;
if (isa<UnresolvedLookupExpr>(ovl)) {
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
- return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs.data(),
- ArgExprs.size(), RParenLoc, ExecConfig);
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs,
+ RParenLoc, ExecConfig);
} else {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
- ArgExprs.size(), RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs,
+ RParenLoc);
}
}
}
@@ -4240,9 +4494,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
else if (isa<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
- return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs.data(),
- ArgExprs.size(), RParenLoc, ExecConfig,
- IsExecConfig);
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig, IsExecConfig);
}
ExprResult
@@ -4283,6 +4536,19 @@ ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
RParenLoc));
}
+/// ActOnConvertVectorExpr - create a new convert-vector expression from the
+/// provided arguments.
+///
+/// __builtin_convertvector( value, dst type )
+///
+ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc) {
+ TypeSourceInfo *TInfo;
+ GetTypeFromParser(ParsedDestTy, &TInfo);
+ return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
+}
+
/// BuildResolvedCallExpr - Build a call to a resolved expression,
/// i.e. an expression not of \p OverloadTy. The expression should
/// unary-convert to an expression of function-pointer or
@@ -4292,7 +4558,7 @@ ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
ExprResult
Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RParenLoc,
Expr *Config, bool IsExecConfig) {
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
@@ -4318,17 +4584,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
CallExpr *TheCall;
if (Config)
TheCall = new (Context) CUDAKernelCallExpr(Context, Fn,
- cast<CallExpr>(Config),
- llvm::makeArrayRef(Args,NumArgs),
- Context.BoolTy,
- VK_RValue,
+ cast<CallExpr>(Config), Args,
+ Context.BoolTy, VK_RValue,
RParenLoc);
else
- TheCall = new (Context) CallExpr(Context, Fn,
- llvm::makeArrayRef(Args, NumArgs),
- Context.BoolTy,
- VK_RValue,
- RParenLoc);
+ TheCall = new (Context) CallExpr(Context, Fn, Args, Context.BoolTy,
+ VK_RValue, RParenLoc);
// Bail out early if calling a builtin with custom typechecking.
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
@@ -4391,8 +4652,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
if (Proto) {
- if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
- RParenLoc, IsExecConfig))
+ if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc,
+ IsExecConfig))
return ExprError();
} else {
assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!");
@@ -4401,11 +4662,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// Check if we have too few/too many template arguments, based
// on our knowledge of the function definition.
const FunctionDecl *Def = 0;
- if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
+ if (FDecl->hasBody(Def) && Args.size() != Def->param_size()) {
Proto = Def->getType()->getAs<FunctionProtoType>();
- if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
+ if (!Proto || !(Proto->isVariadic() && Args.size() >= Def->param_size()))
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
- << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
+ << (Args.size() > Def->param_size()) << FDecl << Fn->getSourceRange();
}
// If the function we're calling isn't a function prototype, but we have
@@ -4415,7 +4676,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}
// Promote the arguments (C99 6.5.2.2p6).
- for (unsigned i = 0; i != NumArgs; i++) {
+ for (unsigned i = 0, e = Args.size(); i != e; i++) {
Expr *Arg = Args[i];
if (Proto && i < Proto->getNumArgs()) {
@@ -4456,7 +4717,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// Check for sentinels
if (NDecl)
- DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
+ DiagnoseSentinelCalls(NDecl, LParenLoc, Args);
// Do special checking on direct calls to functions.
if (FDecl) {
@@ -4466,7 +4727,10 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (BuiltinID)
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
} else if (NDecl) {
- if (CheckBlockCall(NDecl, TheCall, Proto))
+ if (CheckPointerCall(NDecl, TheCall, Proto))
+ return ExprError();
+ } else {
+ if (CheckOtherCall(TheCall, Proto))
return ExprError();
}
@@ -4476,7 +4740,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
ExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty,
SourceLocation RParenLoc, Expr *InitExpr) {
- assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
+ assert(Ty && "ActOnCompoundLiteral(): missing type");
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
@@ -4522,7 +4786,10 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
LiteralExpr = Result.get();
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
- if (isFileScope) { // 6.5.2.5p3
+ if (isFileScope &&
+ !LiteralExpr->isTypeDependent() &&
+ !LiteralExpr->isValueDependent() &&
+ !literalType->isDependentType()) { // 6.5.2.5p3
if (CheckForConstantInitializer(LiteralExpr, literalType))
return ExprError();
}
@@ -5108,9 +5375,11 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
QualType lhptee, rhptee;
// Get the pointee types.
+ bool IsBlockPointer = false;
if (const BlockPointerType *LHSBTy = LHSTy->getAs<BlockPointerType>()) {
lhptee = LHSBTy->getPointeeType();
rhptee = RHSTy->castAs<BlockPointerType>()->getPointeeType();
+ IsBlockPointer = true;
} else {
lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
@@ -5152,7 +5421,10 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
// The pointer types are compatible.
QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
- ResultTy = S.Context.getPointerType(ResultTy);
+ if (IsBlockPointer)
+ ResultTy = S.Context.getBlockPointerType(ResultTy);
+ else
+ ResultTy = S.Context.getPointerType(ResultTy);
LHS = S.ImpCastExprToType(LHS.take(), ResultTy, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.take(), ResultTy, CK_BitCast);
@@ -5266,28 +5538,26 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
VK = VK_RValue;
OK = OK_Ordinary;
+ // First, check the condition.
Cond = UsualUnaryConversions(Cond.take());
if (Cond.isInvalid())
return QualType();
- LHS = UsualUnaryConversions(LHS.take());
- if (LHS.isInvalid())
+ if (checkCondition(*this, Cond.get()))
return QualType();
- RHS = UsualUnaryConversions(RHS.take());
- if (RHS.isInvalid())
+
+ // Now check the two expressions.
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
+
+ UsualArithmeticConversions(LHS, RHS);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
QualType CondTy = Cond.get()->getType();
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
- // first, check the condition.
- if (checkCondition(*this, Cond.get()))
- return QualType();
-
- // Now check the two expressions.
- if (LHSTy->isVectorType() || RHSTy->isVectorType())
- return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
-
// If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
// built in select. (OpenCL v1.1 s6.3.i)
@@ -5297,12 +5567,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
- if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
- UsualArithmeticConversions(LHS, RHS);
- if (LHS.isInvalid() || RHS.isInvalid())
- return QualType();
+ if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType())
return LHS.get()->getType();
- }
// If both operands are the same structure or union type, the result is that
// type.
@@ -5638,7 +5904,14 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Expr *commonExpr = 0;
if (LHSExpr == 0) {
commonExpr = CondExpr;
-
+ // Lower out placeholder types first. This is important so that we don't
+ // try to capture a placeholder. This happens in few cases in C++; such
+ // as Objective-C++'s dictionary subscripting syntax.
+ if (commonExpr->hasPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(commonExpr);
+ if (!result.isUsable()) return ExprError();
+ commonExpr = result.take();
+ }
// We usually want to apply unary conversions *before* saving, except
// in the special case of a C++ l-value conditional.
if (!(getLangOpts().CPlusPlus
@@ -6248,7 +6521,8 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
- bool Diagnose) {
+ bool Diagnose,
+ bool DiagnoseCFAudited) {
if (getLangOpts().CPlusPlus) {
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
// C++ 5.17p3: If the left operand is not of class type, the
@@ -6290,12 +6564,14 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
- if ((LHSType->isPointerType() ||
- LHSType->isObjCObjectPointerType() ||
- LHSType->isBlockPointerType())
- && RHS.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
+ if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() ||
+ LHSType->isBlockPointerType()) &&
+ RHS.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
+ CastKind Kind;
+ CXXCastPath Path;
+ CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
+ RHS = ImpCastExprToType(RHS.take(), LHSType, Kind, VK_RValue, &Path);
return Compatible;
}
@@ -6321,9 +6597,14 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// so that we can use references in built-in functions even in C.
// The getNonReferenceType() call makes sure that the resulting expression
// does not have reference type.
- if (result != Incompatible && RHS.get()->getType() != LHSType)
- RHS = ImpCastExprToType(RHS.take(),
- LHSType.getNonLValueExprType(Context), Kind);
+ if (result != Incompatible && RHS.get()->getType() != LHSType) {
+ QualType Ty = LHSType.getNonLValueExprType(Context);
+ Expr *E = RHS.take();
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
+ DiagnoseCFAudited);
+ RHS = ImpCastExprToType(E, Ty, Kind);
+ }
return result;
}
@@ -6402,12 +6683,19 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return LHSType;
}
}
- if (EltTy->isRealFloatingType() && RHSType->isScalarType() &&
- RHSType->isRealFloatingType()) {
- int order = Context.getFloatingTypeOrder(EltTy, RHSType);
- if (order > 0)
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
- if (order >= 0) {
+ if (EltTy->isRealFloatingType() && RHSType->isScalarType()) {
+ if (RHSType->isRealFloatingType()) {
+ int order = Context.getFloatingTypeOrder(EltTy, RHSType);
+ if (order > 0)
+ RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
+ if (order >= 0) {
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
+ if (swapped) std::swap(RHS, LHS);
+ return LHSType;
+ }
+ }
+ if (RHSType->isIntegralType(Context)) {
+ RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralToFloating);
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
if (swapped) std::swap(RHS, LHS);
return LHSType;
@@ -6480,11 +6768,12 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
// Check for division by zero.
- if (IsDiv &&
- RHS.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_division_by_zero)
- << RHS.get()->getSourceRange());
+ llvm::APSInt RHSValue;
+ if (IsDiv && !RHS.get()->isValueDependent() &&
+ RHS.get()->EvaluateAsInt(RHSValue, Context) && RHSValue == 0)
+ DiagRuntimeBehavior(Loc, RHS.get(),
+ PDiag(diag::warn_division_by_zero)
+ << RHS.get()->getSourceRange());
return compType;
}
@@ -6509,10 +6798,12 @@ QualType Sema::CheckRemainderOperands(
return InvalidOperands(Loc, LHS, RHS);
// Check for remainder by zero.
- if (RHS.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_remainder_by_zero)
- << RHS.get()->getSourceRange());
+ llvm::APSInt RHSValue;
+ if (!RHS.get()->isValueDependent() &&
+ RHS.get()->EvaluateAsInt(RHSValue, Context) && RHSValue == 0)
+ DiagRuntimeBehavior(Loc, RHS.get(),
+ PDiag(diag::warn_remainder_by_zero)
+ << RHS.get()->getSourceRange());
return compType;
}
@@ -6685,12 +6976,63 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
// Only print a fixit for "str" + int, not for int + "str".
if (IndexExpr == RHSExpr) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
- Self.Diag(OpLoc, diag::note_string_plus_int_silence)
+ Self.Diag(OpLoc, diag::note_string_plus_scalar_silence)
<< FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
<< FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
<< FixItHint::CreateInsertion(EndLoc, "]");
} else
- Self.Diag(OpLoc, diag::note_string_plus_int_silence);
+ Self.Diag(OpLoc, diag::note_string_plus_scalar_silence);
+}
+
+/// \brief Emit a warning when adding a char literal to a string.
+static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc,
+ Expr *LHSExpr, Expr *RHSExpr) {
+ const DeclRefExpr *StringRefExpr =
+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreImpCasts());
+ const CharacterLiteral *CharExpr =
+ dyn_cast<CharacterLiteral>(RHSExpr->IgnoreImpCasts());
+ if (!StringRefExpr) {
+ StringRefExpr = dyn_cast<DeclRefExpr>(RHSExpr->IgnoreImpCasts());
+ CharExpr = dyn_cast<CharacterLiteral>(LHSExpr->IgnoreImpCasts());
+ }
+
+ if (!CharExpr || !StringRefExpr)
+ return;
+
+ const QualType StringType = StringRefExpr->getType();
+
+ // Return if not a PointerType.
+ if (!StringType->isAnyPointerType())
+ return;
+
+ // Return if not a CharacterType.
+ if (!StringType->getPointeeType()->isAnyCharacterType())
+ return;
+
+ ASTContext &Ctx = Self.getASTContext();
+ SourceRange DiagRange(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
+
+ const QualType CharType = CharExpr->getType();
+ if (!CharType->isAnyCharacterType() &&
+ CharType->isIntegerType() &&
+ llvm::isUIntN(Ctx.getCharWidth(), CharExpr->getValue())) {
+ Self.Diag(OpLoc, diag::warn_string_plus_char)
+ << DiagRange << Ctx.CharTy;
+ } else {
+ Self.Diag(OpLoc, diag::warn_string_plus_char)
+ << DiagRange << CharExpr->getType();
+ }
+
+ // Only print a fixit for str + char, not for char + str.
+ if (isa<CharacterLiteral>(RHSExpr->IgnoreImpCasts())) {
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
+ Self.Diag(OpLoc, diag::note_string_plus_scalar_silence)
+ << FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
+ << FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
+ << FixItHint::CreateInsertion(EndLoc, "]");
+ } else {
+ Self.Diag(OpLoc, diag::note_string_plus_scalar_silence);
+ }
}
/// \brief Emit error when two pointers are incompatible.
@@ -6719,9 +7061,11 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- // Diagnose "string literal" '+' int.
- if (Opc == BO_Add)
+ // Diagnose "string literal" '+' int and string '+' "char literal".
+ if (Opc == BO_Add) {
diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get());
+ diagnoseStringPlusChar(*this, Loc, LHS.get(), RHS.get());
+ }
// handle the common case first (both operands are arithmetic).
if (!compType.isNull() && compType->isArithmeticType()) {
@@ -6846,6 +7190,18 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
LHS.get(), RHS.get()))
return QualType();
+ // 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.
+ if (!rpointee->isVoidType() && !rpointee->isFunctionType()) {
+ CharUnits ElementSize = Context.getTypeSizeInChars(rpointee);
+ if (ElementSize.isZero()) {
+ Diag(Loc,diag::warn_sub_ptr_zero_size_types)
+ << rpointee.getUnqualifiedType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ }
+ }
+
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
return Context.getPointerDiffType();
}
@@ -7234,6 +7590,65 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
}
}
+static void diagnoseLogicalNotOnLHSofComparison(Sema &S, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc,
+ unsigned OpaqueOpc) {
+ // This checking requires bools.
+ if (!S.getLangOpts().Bool) return;
+
+ // Check that left hand side is !something.
+ UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS.get()->IgnoreImpCasts());
+ if (!UO || UO->getOpcode() != UO_LNot) return;
+
+ // Only check if the right hand side is non-bool arithmetic type.
+ if (RHS.get()->getType()->isBooleanType()) return;
+
+ // Make sure that the something in !something is not bool.
+ Expr *SubExpr = UO->getSubExpr()->IgnoreImpCasts();
+ if (SubExpr->getType()->isBooleanType()) return;
+
+ // Emit warning.
+ S.Diag(UO->getOperatorLoc(), diag::warn_logical_not_on_lhs_of_comparison)
+ << Loc;
+
+ // First note suggest !(x < y)
+ SourceLocation FirstOpen = SubExpr->getLocStart();
+ SourceLocation FirstClose = RHS.get()->getLocEnd();
+ FirstClose = S.getPreprocessor().getLocForEndOfToken(FirstClose);
+ if (FirstClose.isInvalid())
+ FirstOpen = SourceLocation();
+ S.Diag(UO->getOperatorLoc(), diag::note_logical_not_fix)
+ << FixItHint::CreateInsertion(FirstOpen, "(")
+ << FixItHint::CreateInsertion(FirstClose, ")");
+
+ // Second note suggests (!x) < y
+ SourceLocation SecondOpen = LHS.get()->getLocStart();
+ SourceLocation SecondClose = LHS.get()->getLocEnd();
+ SecondClose = S.getPreprocessor().getLocForEndOfToken(SecondClose);
+ if (SecondClose.isInvalid())
+ SecondOpen = SourceLocation();
+ S.Diag(UO->getOperatorLoc(), diag::note_logical_not_silence_with_parens)
+ << FixItHint::CreateInsertion(SecondOpen, "(")
+ << FixItHint::CreateInsertion(SecondClose, ")");
+}
+
+// Get the decl for a simple expression: a reference to a variable,
+// an implicit C++ field reference, or an implicit ObjC ivar reference.
+static ValueDecl *getCompareDecl(Expr *E) {
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
+ return DR->getDecl();
+ if (ObjCIvarRefExpr* Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
+ if (Ivar->isFreeIvar())
+ return Ivar->getDecl();
+ }
+ if (MemberExpr* Mem = dyn_cast<MemberExpr>(E)) {
+ if (Mem->isImplicitAccess())
+ return Mem->getMemberDecl();
+ }
+ return 0;
+}
+
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned OpaqueOpc,
@@ -7254,11 +7669,13 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
+ diagnoseLogicalNotOnLHSofComparison(*this, LHS, RHS, Loc, OpaqueOpc);
if (!LHSType->hasFloatingRepresentation() &&
!(LHSType->isBlockPointerType() && IsRelational) &&
!LHS.get()->getLocStart().isMacroID() &&
- !RHS.get()->getLocStart().isMacroID()) {
+ !RHS.get()->getLocStart().isMacroID() &&
+ ActiveTemplateInstantiations.empty()) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
@@ -7269,37 +7686,34 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
- if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) {
- if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
- if (DRL->getDecl() == DRR->getDecl() &&
- !IsWithinTemplateSpecialization(DRL->getDecl())) {
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
- << 0 // self-
- << (Opc == BO_EQ
- || Opc == BO_LE
- || Opc == BO_GE));
- } else if (LHSType->isArrayType() && RHSType->isArrayType() &&
- !DRL->getDecl()->getType()->isReferenceType() &&
- !DRR->getDecl()->getType()->isReferenceType()) {
- // what is it always going to eval to?
- char always_evals_to;
- switch(Opc) {
- case BO_EQ: // e.g. array1 == array2
- always_evals_to = 0; // false
- break;
- case BO_NE: // e.g. array1 != array2
- always_evals_to = 1; // true
- break;
- default:
- // best we can say is 'a constant'
- always_evals_to = 2; // e.g. array1 <= array2
- break;
- }
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
- << 1 // array
- << always_evals_to);
+ ValueDecl *DL = getCompareDecl(LHSStripped);
+ ValueDecl *DR = getCompareDecl(RHSStripped);
+ if (DL && DR && DL == DR && !IsWithinTemplateSpecialization(DL)) {
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ << 0 // self-
+ << (Opc == BO_EQ
+ || Opc == BO_LE
+ || Opc == BO_GE));
+ } else if (DL && DR && LHSType->isArrayType() && RHSType->isArrayType() &&
+ !DL->getType()->isReferenceType() &&
+ !DR->getType()->isReferenceType()) {
+ // what is it always going to eval to?
+ char always_evals_to;
+ switch(Opc) {
+ case BO_EQ: // e.g. array1 == array2
+ always_evals_to = 0; // false
+ break;
+ case BO_NE: // e.g. array1 != array2
+ always_evals_to = 1; // true
+ break;
+ default:
+ // best we can say is 'a constant'
+ always_evals_to = 2; // e.g. array1 <= array2
+ break;
}
- }
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ << 1 // array
+ << always_evals_to);
}
if (isa<CastExpr>(LHSStripped))
@@ -7333,21 +7747,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// C99 6.5.8p3 / C99 6.5.9p4
- if (LHS.get()->getType()->isArithmeticType() &&
- RHS.get()->getType()->isArithmeticType()) {
- UsualArithmeticConversions(LHS, RHS);
- if (LHS.isInvalid() || RHS.isInvalid())
- return QualType();
- }
- else {
- LHS = UsualUnaryConversions(LHS.take());
- if (LHS.isInvalid())
- return QualType();
-
- RHS = UsualUnaryConversions(RHS.take());
- if (RHS.isInvalid())
- return QualType();
- }
+ UsualArithmeticConversions(LHS, RHS);
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
LHSType = LHS.get()->getType();
RHSType = RHS.get()->getType();
@@ -7534,12 +7936,20 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
}
- if (LHSIsNull && !RHSIsNull)
- LHS = ImpCastExprToType(LHS.take(), RHSType,
+ if (LHSIsNull && !RHSIsNull) {
+ Expr *E = LHS.take();
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), RHSType, E, CCK_ImplicitConversion);
+ LHS = ImpCastExprToType(E, RHSType,
RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
- else
- RHS = ImpCastExprToType(RHS.take(), LHSType,
+ }
+ else {
+ Expr *E = RHS.take();
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion);
+ RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
+ }
return ResultTy;
}
if (LHSType->isObjCObjectPointerType() &&
@@ -7651,7 +8061,8 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
- if (!LHSType->hasFloatingRepresentation()) {
+ if (!LHSType->hasFloatingRepresentation() &&
+ ActiveTemplateInstantiations.empty()) {
if (DeclRefExpr* DRL
= dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts()))
if (DeclRefExpr* DRR
@@ -7806,28 +8217,6 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
return Context.BoolTy;
}
-/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
-/// is a read-only property; return true if so. A readonly property expression
-/// depends on various declarations and thus must be treated specially.
-///
-static bool IsReadonlyProperty(Expr *E, Sema &S) {
- const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
- if (!PropExpr) return false;
- if (PropExpr->isImplicitProperty()) return false;
-
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType BaseType = PropExpr->isSuperReceiver() ?
- PropExpr->getSuperReceiverType() :
- PropExpr->getBase()->getType();
-
- if (const ObjCObjectPointerType *OPT =
- BaseType->getAsObjCInterfacePointerType())
- if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
- return false;
-}
-
static bool IsReadonlyMessage(Expr *E, Sema &S) {
const MemberExpr *ME = dyn_cast<MemberExpr>(E);
if (!ME) return false;
@@ -7858,9 +8247,14 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
assert(var->hasLocalStorage() && "capture added 'const' to non-local?");
// Decide whether the first capture was for a block or a lambda.
- DeclContext *DC = S.CurContext;
- while (DC->getParent() != var->getDeclContext())
+ DeclContext *DC = S.CurContext, *Prev = 0;
+ while (DC != var->getDeclContext()) {
+ Prev = DC;
DC = DC->getParent();
+ }
+ // Unless we have an init-capture, we've gone one step too far.
+ if (!var->isInitCapture())
+ DC = Prev;
return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda);
}
@@ -7871,9 +8265,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
SourceLocation OrigLoc = Loc;
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
- if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
- IsLV = Expr::MLV_ReadonlyProperty;
- else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S))
+ if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S))
IsLV = Expr::MLV_InvalidMessageExpression;
if (IsLV == Expr::MLV_Valid)
return false;
@@ -7956,7 +8348,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
- case Expr::MLV_ReadonlyProperty:
case Expr::MLV_NoSetterProperty:
llvm_unreachable("readonly properties should be processed differently");
case Expr::MLV_InvalidMessageExpression:
@@ -8163,6 +8554,10 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
}
// Increment of bool sets it to true, but is deprecated.
S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
+ } else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) {
+ // Error on enum increments and decrements in C++ mode
+ S.Diag(OpLoc, diag::err_increment_decrement_enum) << IsInc << ResType;
+ return QualType();
} else if (ResType->isRealType()) {
// OK!
} else if (ResType->isPointerType()) {
@@ -8186,6 +8581,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
IsInc, IsPrefix);
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
+ } else if(S.getLangOpts().OpenCL && ResType->isVectorType() &&
+ ResType->getAs<VectorType>()->getElementType()->isIntegerType()) {
+ // OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types.
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
<< ResType << int(IsInc) << Op->getSourceRange();
@@ -8289,43 +8687,50 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
/// In C++, the operand might be an overloaded function name, in which case
/// we allow the '&' but retain the overloaded-function type.
-static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
- SourceLocation OpLoc) {
+QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
if (PTy->getKind() == BuiltinType::Overload) {
- if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
- assert(cast<UnaryOperator>(OrigOp.get()->IgnoreParens())->getOpcode()
- == UO_AddrOf);
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function)
+ Expr *E = OrigOp.get()->IgnoreParens();
+ if (!isa<OverloadExpr>(E)) {
+ assert(cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf);
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function)
<< OrigOp.get()->getSourceRange();
return QualType();
}
-
- return S.Context.OverloadTy;
+
+ OverloadExpr *Ovl = cast<OverloadExpr>(E);
+ if (isa<UnresolvedMemberExpr>(Ovl))
+ if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) {
+ Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ << OrigOp.get()->getSourceRange();
+ return QualType();
+ }
+
+ return Context.OverloadTy;
}
if (PTy->getKind() == BuiltinType::UnknownAny)
- return S.Context.UnknownAnyTy;
+ return Context.UnknownAnyTy;
if (PTy->getKind() == BuiltinType::BoundMember) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
<< OrigOp.get()->getSourceRange();
return QualType();
}
- OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
+ OrigOp = CheckPlaceholderExpr(OrigOp.take());
if (OrigOp.isInvalid()) return QualType();
}
if (OrigOp.get()->isTypeDependent())
- return S.Context.DependentTy;
+ return Context.DependentTy;
assert(!OrigOp.get()->getType()->isPlaceholderType());
// Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp.get()->IgnoreParens();
- if (S.getLangOpts().C99) {
+ if (getLangOpts().C99) {
// Implement C99-only parts of addressof rules.
if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
if (uOp->getOpcode() == UO_Deref)
@@ -8337,28 +8742,28 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// expressions here, but the result of one is always an lvalue anyway.
}
ValueDecl *dcl = getPrimaryDecl(op);
- Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
+ Expr::LValueClassification lval = op->ClassifyLValue(Context);
unsigned AddressOfError = AO_No_Error;
if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) {
- bool sfinae = (bool)S.isSFINAEContext();
- S.Diag(OpLoc, S.isSFINAEContext() ? diag::err_typecheck_addrof_temporary
- : diag::ext_typecheck_addrof_temporary)
+ bool sfinae = (bool)isSFINAEContext();
+ Diag(OpLoc, isSFINAEContext() ? diag::err_typecheck_addrof_temporary
+ : diag::ext_typecheck_addrof_temporary)
<< op->getType() << op->getSourceRange();
if (sfinae)
return QualType();
// Materialize the temporary as an lvalue so that we can take its address.
- OrigOp = op = new (S.Context)
- MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true);
+ OrigOp = op = new (Context)
+ MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);
} else if (isa<ObjCSelectorExpr>(op)) {
- return S.Context.getPointerType(op->getType());
+ return Context.getPointerType(op->getType());
} else if (lval == Expr::LV_MemberFunction) {
// If it's an instance method, make a member pointer.
// The expression must have exactly the form &A::foo.
// If the underlying expression isn't a decl ref, give up.
if (!isa<DeclRefExpr>(op)) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
<< OrigOp.get()->getSourceRange();
return QualType();
}
@@ -8367,25 +8772,29 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// The id-expression was parenthesized.
if (OrigOp.get() != DRE) {
- S.Diag(OpLoc, diag::err_parens_pointer_member_function)
+ Diag(OpLoc, diag::err_parens_pointer_member_function)
<< OrigOp.get()->getSourceRange();
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
if (MD->getParent()->getName().empty())
- S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< op->getSourceRange();
else {
SmallString<32> Str;
StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str);
- S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< op->getSourceRange()
<< FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual);
}
}
- return S.Context.getMemberPointerType(op->getType(),
- S.Context.getTypeDeclType(MD->getParent()).getTypePtr());
+ // Taking the address of a dtor is illegal per C++ [class.dtor]p2.
+ if (isa<CXXDestructorDecl>(MD))
+ Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange();
+
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(MD->getParent()).getTypePtr());
} else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
@@ -8394,7 +8803,7 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
if (isa<PseudoObjectExpr>(op)) {
AddressOfError = AO_Property_Expansion;
} else {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
<< op->getType() << op->getSourceRange();
return QualType();
}
@@ -8412,11 +8821,11 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// in C++ it is not error to take address of a register
// variable (c++03 7.1.1P3)
if (vd->getStorageClass() == SC_Register &&
- !S.getLangOpts().CPlusPlus) {
+ !getLangOpts().CPlusPlus) {
AddressOfError = AO_Register_Variable;
}
} else if (isa<FunctionTemplateDecl>(dcl)) {
- return S.Context.OverloadTy;
+ return Context.OverloadTy;
} else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(dcl)) {
// Okay: we can take the address of a field.
// Could be a pointer to member, though, if there is an explicit
@@ -8425,16 +8834,16 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
DeclContext *Ctx = dcl->getDeclContext();
if (Ctx && Ctx->isRecord()) {
if (dcl->getType()->isReferenceType()) {
- S.Diag(OpLoc,
- diag::err_cannot_form_pointer_to_member_of_reference_type)
+ Diag(OpLoc,
+ diag::err_cannot_form_pointer_to_member_of_reference_type)
<< dcl->getDeclName() << dcl->getType();
return QualType();
}
while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
Ctx = Ctx->getParent();
- return S.Context.getMemberPointerType(op->getType(),
- S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
}
}
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl))
@@ -8442,7 +8851,7 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
}
if (AddressOfError != AO_No_Error) {
- diagnoseAddressOfInvalidType(S, OpLoc, op, AddressOfError);
+ diagnoseAddressOfInvalidType(*this, OpLoc, op, AddressOfError);
return QualType();
}
@@ -8450,13 +8859,13 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// Taking the address of a void variable is technically illegal, but we
// allow it in cases which are otherwise valid.
// Example: "extern void x; void* y = &x;".
- S.Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange();
+ Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange();
}
// If the operand has type "type", the result has type "pointer to type".
if (op->getType()->isObjCObjectType())
- return S.Context.getObjCObjectPointerType(op->getType());
- return S.Context.getPointerType(op->getType());
+ return Context.getObjCObjectPointerType(op->getType());
+ return Context.getPointerType(op->getType());
}
/// CheckIndirectionOperand - Type check unary indirection (prefix '*').
@@ -8630,7 +9039,20 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
// looks for code trying to introspect into tagged pointers, which
// code should generally never do.
if (ObjCPointerExpr && isa<IntegerLiteral>(OtherExpr->IgnoreParenCasts())) {
- S.Diag(OpLoc, diag::warn_objc_pointer_masking)
+ unsigned Diag = diag::warn_objc_pointer_masking;
+ // Determine if we are introspecting the result of performSelectorXXX.
+ const Expr *Ex = ObjCPointerExpr->IgnoreParenCasts();
+ // Special case messages to -performSelector and friends, which
+ // can return non-pointer values boxed in a pointer value.
+ // Some clients may wish to silence warnings in this subcase.
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
+ Selector S = ME->getSelector();
+ StringRef SelArg0 = S.getNameForSlot(0);
+ if (SelArg0.startswith("performSelector"))
+ Diag = diag::warn_objc_pointer_masking_performSelector;
+ }
+
+ S.Diag(OpLoc, Diag)
<< ObjCPointerExpr->getSourceRange();
}
}
@@ -8884,14 +9306,16 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
/// 'true'.
static bool EvaluatesAsTrue(Sema &S, Expr *E) {
bool Res;
- return E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res;
+ return !E->isValueDependent() &&
+ E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res;
}
/// \brief Returns true if the given expression can be evaluated as a constant
/// 'false'.
static bool EvaluatesAsFalse(Sema &S, Expr *E) {
bool Res;
- return E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res;
+ return !E->isValueDependent() &&
+ E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res;
}
/// \brief Look for '&&' in the left hand of a '||' expr.
@@ -9147,7 +9571,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PreDec);
break;
case UO_AddrOf:
- resultType = CheckAddressOfOperand(*this, Input, OpLoc);
+ resultType = CheckAddressOfOperand(Input, OpLoc);
break;
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.take());
@@ -9165,9 +9589,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (resultType->isArithmeticType() || // C99 6.5.3.3p1
resultType->isVectorType())
break;
- else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6-7
- resultType->isEnumeralType())
- break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
Opc == UO_Plus &&
resultType->isPointerType())
@@ -9390,7 +9811,7 @@ ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) {
- TheDecl->setUsed();
+ TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'.
return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
Context.getPointerType(Context.VoidTy)));
@@ -9655,9 +10076,15 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// If the member was found in a base class, introduce OffsetOfNodes for
// the base class indirections.
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
+ CXXBasePaths Paths;
if (IsDerivedFrom(CurrentType, Context.getTypeDeclType(Parent), Paths)) {
+ if (Paths.getDetectedVirtual()) {
+ Diag(OC.LocEnd, diag::err_offsetof_field_of_virtual_base)
+ << MemberDecl->getDeclName()
+ << SourceRange(BuiltinLoc, RParenLoc);
+ return ExprError();
+ }
+
CXXBasePath &Path = Paths.front();
for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end();
B != BEnd; ++B)
@@ -9713,6 +10140,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
ExprObjectKind OK = OK_Ordinary;
QualType resType;
bool ValueDependent = false;
+ bool CondIsTrue = false;
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
resType = Context.DependentTy;
ValueDependent = true;
@@ -9725,9 +10153,10 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
if (CondICE.isInvalid())
return ExprError();
CondExpr = CondICE.take();
+ CondIsTrue = condEval.getZExtValue();
// If the condition is > zero, then the AST type is the same as the LSHExpr.
- Expr *ActiveExpr = condEval.getZExtValue() ? LHSExpr : RHSExpr;
+ Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr;
resType = ActiveExpr->getType();
ValueDependent = ActiveExpr->isValueDependent();
@@ -9736,7 +10165,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
}
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
- resType, VK, OK, RPLoc,
+ resType, VK, OK, RPLoc, CondIsTrue,
resType->isDependentType(),
ValueDependent));
}
@@ -9748,6 +10177,17 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
/// ActOnBlockStart - This callback is invoked when a block literal is started.
void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
+
+ if (LangOpts.CPlusPlus) {
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ getCurrentMangleNumberContext(Block->getDeclContext(),
+ ManglingContextDecl)) {
+ unsigned ManglingNumber = MCtx->getManglingNumber(Block);
+ Block->setBlockMangling(ManglingNumber, ManglingContextDecl);
+ }
+ }
+
PushBlockScope(CurScope, Block);
CurContext->addDecl(Block);
if (CurScope)
@@ -9820,13 +10260,6 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
CurBlock->TheDecl->setIsVariadic(isVariadic);
- // Don't allow returning a objc interface by value.
- if (RetTy->isObjCObjectType()) {
- Diag(ParamInfo.getLocStart(),
- diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
- return;
- }
-
// Context.DependentTy is used as a placeholder for a missing block
// return type. TODO: what should we do with declarators like:
// ^ * { ... }
@@ -9874,11 +10307,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Finally we can process decl attributes.
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
- // Put the parameter variables in scope. We can bail out immediately
- // if we don't have any.
- if (Params.empty())
- return;
-
+ // Put the parameter variables in scope.
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
(*AI)->setOwningFunction(CurBlock->TheDecl);
@@ -9940,7 +10369,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (Cap.isThisCapture())
continue;
BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
- Cap.isNested(), Cap.getCopyExpr());
+ Cap.isNested(), Cap.getInitExpr());
Captures.push_back(NewCap);
}
BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
@@ -9971,11 +10400,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = 0; // FIXME: silently?
EPI.ExtInfo = Ext;
- BlockTy =
- Context.getFunctionType(RetTy,
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ BlockTy = Context.getFunctionType(RetTy, FPT->getArgTypes(), EPI);
}
// If we don't have a function type, just build one from nothing.
@@ -10005,7 +10430,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
computeNRVO(Body, getCurBlock());
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
- const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
+ AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
// If the block isn't obviously global, i.e. it captures anything at
@@ -10143,7 +10568,8 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
}
static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
- Expr *SrcExpr, FixItHint &Hint) {
+ Expr *SrcExpr, FixItHint &Hint,
+ bool &IsNSString) {
if (!SemaRef.getLangOpts().ObjC1)
return;
@@ -10157,6 +10583,7 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
if (!ID || !ID->getIdentifier()->isStr("NSString"))
return;
+ IsNSString = true;
}
// Ignore any parens, implicit casts (should only be
@@ -10190,6 +10617,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ConversionFixItGenerator ConvHints;
bool MayHaveConvFixit = false;
bool MayHaveFunctionDiff = false;
+ bool IsNSString = false;
switch (ConvTy) {
case Compatible:
@@ -10207,8 +10635,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
MayHaveConvFixit = true;
break;
case IncompatiblePointer:
- MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
- DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
+ MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint, IsNSString);
+ DiagKind =
+ (Action == AA_Passing_CFAudited ?
+ diag::err_arc_typecheck_convert_incompatible_pointer :
+ diag::ext_typecheck_convert_incompatible_pointer);
CheckInferredResultType = DstType->isObjCObjectPointerType() &&
SrcType->isObjCObjectPointerType();
if (Hint.isNull() && !CheckInferredResultType) {
@@ -10218,6 +10649,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SrcType = SrcType.getUnqualifiedType();
DstType = DstType.getUnqualifiedType();
}
+ else if (IsNSString && !Hint.isNull())
+ DiagKind = diag::warn_missing_atsign_prefix;
MayHaveConvFixit = true;
break;
case IncompatiblePointerSign:
@@ -10300,6 +10733,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case AA_Returning:
case AA_Passing:
+ case AA_Passing_CFAudited:
case AA_Converting:
case AA_Sending:
case AA_Casting:
@@ -10310,7 +10744,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
}
PartialDiagnostic FDiag = PDiag(DiagKind);
- FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange();
+ if (Action == AA_Passing_CFAudited)
+ FDiag << FirstType << SecondType << SrcExpr->getSourceRange();
+ else
+ FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange();
// If we can fix the conversion, suggest the FixIts.
assert(ConvHints.isNull() || Hint.isNull());
@@ -10392,112 +10829,52 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// have a single non-explicit conversion function to an integral or
// unscoped enumeration type
ExprResult Converted;
- if (!Diagnoser.Suppress) {
- class CXX11ConvertDiagnoser : public ICEConvertDiagnoser {
- public:
- CXX11ConvertDiagnoser() : ICEConvertDiagnoser(false, true) { }
-
- virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_ice_not_integral) << T;
- }
-
- virtual DiagnosticBuilder diagnoseIncomplete(Sema &S,
- SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_ice_incomplete_type) << T;
- }
-
- virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
- SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy;
- }
-
- virtual DiagnosticBuilder noteExplicitConv(Sema &S,
- CXXConversionDecl *Conv,
- QualType ConvTy) {
- return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
- << ConvTy->isEnumeralType() << ConvTy;
- }
-
- virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T;
- }
-
- virtual DiagnosticBuilder noteAmbiguous(Sema &S,
- CXXConversionDecl *Conv,
- QualType ConvTy) {
- return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
- << ConvTy->isEnumeralType() << ConvTy;
- }
-
- virtual DiagnosticBuilder diagnoseConversion(Sema &S,
- SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
- }
- } ConvertDiagnoser;
+ class CXX11ConvertDiagnoser : public ICEConvertDiagnoser {
+ public:
+ CXX11ConvertDiagnoser(bool Silent)
+ : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false,
+ Silent, true) {}
+
+ virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_ice_not_integral) << T;
+ }
- Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E,
- ConvertDiagnoser,
- /*AllowScopedEnumerations*/ false);
- } else {
- // The caller wants to silently enquire whether this is an ICE. Don't
- // produce any diagnostics if it isn't.
- class SilentICEConvertDiagnoser : public ICEConvertDiagnoser {
- public:
- SilentICEConvertDiagnoser() : ICEConvertDiagnoser(true, true) { }
-
- virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder diagnoseIncomplete(Sema &S,
- SourceLocation Loc,
- QualType T) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
- SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder noteExplicitConv(Sema &S,
- CXXConversionDecl *Conv,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder noteAmbiguous(Sema &S,
- CXXConversionDecl *Conv,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
- }
-
- virtual DiagnosticBuilder diagnoseConversion(Sema &S,
- SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
- }
- } ConvertDiagnoser;
-
- Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E,
- ConvertDiagnoser, false);
- }
+ virtual SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) {
+ return S.Diag(Loc, diag::err_ice_incomplete_type) << T;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseAmbiguous(
+ Sema &S, SourceLocation Loc, QualType T) {
+ return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T;
+ }
+
+ virtual SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ llvm_unreachable("conversion functions are permitted");
+ }
+ } ConvertDiagnoser(Diagnoser.Suppress);
+
+ Converted = PerformContextualImplicitConversion(DiagLoc, E,
+ ConvertDiagnoser);
if (Converted.isInvalid())
return Converted;
E = Converted.take();
@@ -10645,21 +11022,30 @@ void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
ReuseLambdaContextDecl_t,
bool IsDecltype) {
- Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl;
- PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype);
+ Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
+ PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
}
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
if (!Rec.Lambdas.empty()) {
- if (Rec.isUnevaluated()) {
- // C++11 [expr.prim.lambda]p2:
- // A lambda-expression shall not appear in an unevaluated operand
- // (Clause 5).
+ if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
+ unsigned D;
+ if (Rec.isUnevaluated()) {
+ // C++11 [expr.prim.lambda]p2:
+ // A lambda-expression shall not appear in an unevaluated operand
+ // (Clause 5).
+ D = diag::err_lambda_unevaluated_operand;
+ } else {
+ // 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
+ // evaluate [...] a lambda-expression.
+ D = diag::err_lambda_in_constant_expression;
+ }
for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I)
- Diag(Rec.Lambdas[I]->getLocStart(),
- diag::err_lambda_unevaluated_operand);
+ Diag(Rec.Lambdas[I]->getLocStart(), D);
} else {
// Mark the capture expressions odr-used. This was deferred
// during lambda expression creation.
@@ -10872,7 +11258,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
if (!AlreadyInstantiated || Func->isConstexpr()) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ ActiveTemplateInstantiations.size())
PendingLocalImplicitInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
else if (Func->isConstexpr())
@@ -10906,14 +11293,14 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
}
- // Normally the must current decl is marked used while processing the use and
+ // Normally the most current decl is marked used while processing the use and
// any subsequent decls are marked used by decl merging. This fails with
// template instantiation since marking can happen at the end of the file
// and, because of the two phase lookup, this function is called with at
// decl in the middle of a decl chain. We loop to maintain the invariant
// that once a decl is used, all decls after it are also used.
for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
- F->setUsed(true);
+ F->markUsed(Context);
if (F == Func)
break;
}
@@ -10965,36 +11352,251 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// capture.
}
-/// \brief Capture the given variable in the captured region.
-static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI,
- VarDecl *Var, QualType FieldType,
- QualType DeclRefType,
- SourceLocation Loc,
- bool RefersToEnclosingLocal) {
- // The current implemention assumes that all variables are captured
- // by references. Since there is no capture by copy, no expression evaluation
- // will be needed.
- //
- RecordDecl *RD = RSI->TheRecordDecl;
+
+static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
+ bool &SubCapturesAreNested,
+ QualType &CaptureType,
+ QualType &DeclRefType) {
+ // Check whether we've already captured it.
+ if (CSI->CaptureMap.count(Var)) {
+ // If we found a capture, any subcaptures are nested.
+ SubCapturesAreNested = true;
+
+ // Retrieve the capture type for this variable.
+ CaptureType = CSI->getCapture(Var).getCaptureType();
+
+ // Compute the type of an expression that refers to this variable.
+ DeclRefType = CaptureType.getNonReferenceType();
+
+ const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
+ if (Cap.isCopyCapture() &&
+ !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable))
+ DeclRefType.addConst();
+ return true;
+ }
+ return false;
+}
- FieldDecl *Field
- = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, FieldType,
- S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
- 0, false, ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- RD->addDecl(Field);
+// Only block literals, captured statements, and lambda expressions can
+// capture; other scopes don't work.
+static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
+ SourceLocation Loc,
+ const bool Diagnose, Sema &S) {
+ if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
+ return getLambdaAwareParentOfDeclContext(DC);
+ else {
+ if (Diagnose)
+ diagnoseUncapturableValueReference(S, Loc, Var, DC);
+ }
+ return 0;
+}
- Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
- DeclRefType, VK_LValue, Loc);
- Var->setReferenced(true);
- Var->setUsed(true);
+// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+// certain types of variables (unnamed, variably modified types etc.)
+// so check for eligibility.
+static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
+ SourceLocation Loc,
+ const bool Diagnose, Sema &S) {
+
+ bool IsBlock = isa<BlockScopeInfo>(CSI);
+ bool IsLambda = isa<LambdaScopeInfo>(CSI);
+
+ // Lambdas are not allowed to capture unnamed variables
+ // (e.g. anonymous unions).
+ // FIXME: The C++11 rule don't actually state this explicitly, but I'm
+ // assuming that's the intent.
+ if (IsLambda && !Var->getDeclName()) {
+ if (Diagnose) {
+ S.Diag(Loc, diag::err_lambda_capture_anonymous_var);
+ S.Diag(Var->getLocation(), diag::note_declared_at);
+ }
+ return false;
+ }
+
+ // Prohibit variably-modified types; they're difficult to deal with.
+ if (Var->getType()->isVariablyModifiedType()) {
+ if (Diagnose) {
+ if (IsBlock)
+ S.Diag(Loc, diag::err_ref_vm_type);
+ else
+ S.Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
+ // Prohibit structs with flexible array members too.
+ // We cannot capture what is in the tail end of the struct.
+ if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) {
+ if (VTTy->getDecl()->hasFlexibleArrayMember()) {
+ if (Diagnose) {
+ if (IsBlock)
+ S.Diag(Loc, diag::err_ref_flexarray_type);
+ else
+ S.Diag(Loc, diag::err_lambda_capture_flexarray_type)
+ << Var->getDeclName();
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
+ }
+ const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
+ // Lambdas and captured statements are not allowed to capture __block
+ // variables; they don't support the expected semantics.
+ if (HasBlocksAttr && (IsLambda || isa<CapturedRegionScopeInfo>(CSI))) {
+ if (Diagnose) {
+ S.Diag(Loc, diag::err_capture_block_variable)
+ << Var->getDeclName() << !IsLambda;
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
- return Ref;
+ return true;
}
-/// \brief Capture the given variable in the given lambda expression.
-static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
+// Returns true if the capture by block was successful.
+static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
+ QualType &CaptureType,
+ QualType &DeclRefType,
+ const bool Nested,
+ Sema &S) {
+ Expr *CopyExpr = 0;
+ bool ByRef = false;
+
+ // Blocks are not allowed to capture arrays.
+ if (CaptureType->isArrayType()) {
+ if (BuildAndDiagnose) {
+ S.Diag(Loc, diag::err_ref_array_type);
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
+
+ // Forbid the block-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ S.Diag(Loc, diag::err_arc_autoreleasing_capture)
+ << /*block*/ 0;
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
+ const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
+ if (HasBlocksAttr || CaptureType->isReferenceType()) {
+ // Block capture by reference does not change the capture or
+ // declaration reference types.
+ ByRef = true;
+ } else {
+ // Block capture by copy introduces 'const'.
+ CaptureType = CaptureType.getNonReferenceType().withConst();
+ DeclRefType = CaptureType;
+
+ if (S.getLangOpts().CPlusPlus && BuildAndDiagnose) {
+ if (const RecordType *Record = DeclRefType->getAs<RecordType>()) {
+ // The capture logic needs the destructor, so make sure we mark it.
+ // Usually this is unnecessary because most local variables have
+ // their destructors marked at declaration time, but parameters are
+ // an exception because it's technically only the call site that
+ // actually requires the destructor.
+ if (isa<ParmVarDecl>(Var))
+ S.FinalizeVarWithDestructor(Var, Record);
+
+ // Enter a new evaluation context to insulate the copy
+ // full-expression.
+ EnterExpressionEvaluationContext scope(S, S.PotentiallyEvaluated);
+
+ // According to the blocks spec, the capture of a variable from
+ // the stack requires a const copy constructor. This is not true
+ // of the copy/move done to move a __block variable to the heap.
+ Expr *DeclRef = new (S.Context) DeclRefExpr(Var, Nested,
+ DeclRefType.withConst(),
+ VK_LValue, Loc);
+
+ ExprResult Result
+ = S.PerformCopyInitialization(
+ InitializedEntity::InitializeBlock(Var->getLocation(),
+ CaptureType, false),
+ Loc, S.Owned(DeclRef));
+
+ // Build a full-expression copy expression if initialization
+ // succeeded and used a non-trivial constructor. Recover from
+ // errors by pretending that the copy isn't necessary.
+ if (!Result.isInvalid() &&
+ !cast<CXXConstructExpr>(Result.get())->getConstructor()
+ ->isTrivial()) {
+ Result = S.MaybeCreateExprWithCleanups(Result);
+ CopyExpr = Result.take();
+ }
+ }
+ }
+ }
+
+ // Actually capture the variable.
+ if (BuildAndDiagnose)
+ BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
+ SourceLocation(), CaptureType, CopyExpr);
+
+ return true;
+
+}
+
+
+/// \brief Capture the given variable in the captured region.
+static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
+ VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
+ QualType &CaptureType,
+ QualType &DeclRefType,
+ const bool RefersToEnclosingLocal,
+ Sema &S) {
+
+ // By default, capture variables by reference.
+ bool ByRef = true;
+ // Using an LValue reference type is consistent with Lambdas (see below).
+ CaptureType = S.Context.getLValueReferenceType(DeclRefType);
+ Expr *CopyExpr = 0;
+ if (BuildAndDiagnose) {
+ // The current implementation assumes that all variables are captured
+ // by references. Since there is no capture by copy, no expression evaluation
+ // will be needed.
+ //
+ RecordDecl *RD = RSI->TheRecordDecl;
+
+ FieldDecl *Field
+ = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, CaptureType,
+ S.Context.getTrivialTypeSourceInfo(CaptureType, Loc),
+ 0, false, ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ RD->addDecl(Field);
+
+ CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
+ DeclRefType, VK_LValue, Loc);
+ Var->setReferenced(true);
+ Var->markUsed(S.Context);
+ }
+
+ // Actually capture the variable.
+ if (BuildAndDiagnose)
+ RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToEnclosingLocal, Loc,
+ SourceLocation(), CaptureType, CopyExpr);
+
+
+ return true;
+}
+
+/// \brief Create a field within the lambda class for the variable
+/// being captured. Handle Array captures.
+static ExprResult addAsFieldToClosureType(Sema &S,
+ LambdaScopeInfo *LSI,
VarDecl *Var, QualType FieldType,
QualType DeclRefType,
SourceLocation Loc,
@@ -11030,7 +11632,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
- Var->setUsed(true);
+ Var->markUsed(S.Context);
// When the field has array type, create index variables for each
// dimension of the array. We use these index variables to subscript
@@ -11086,7 +11688,8 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
SmallVector<InitializedEntity, 4> Entities;
Entities.reserve(1 + IndexVariables.size());
Entities.push_back(
- InitializedEntity::InitializeLambdaCapture(Var, Field, Loc));
+ InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(),
+ Field->getType(), Loc));
for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
Entities.push_back(InitializedEntity::InitializeElement(S.Context,
0,
@@ -11111,127 +11714,207 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
return Result;
}
-bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+
+
+/// \brief Capture the given variable in the lambda.
+static bool captureInLambda(LambdaScopeInfo *LSI,
+ VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
+ QualType &CaptureType,
+ QualType &DeclRefType,
+ const bool RefersToEnclosingLocal,
+ const Sema::TryCaptureKind Kind,
+ SourceLocation EllipsisLoc,
+ const bool IsTopScope,
+ Sema &S) {
+
+ // Determine whether we are capturing by reference or by value.
+ bool ByRef = false;
+ if (IsTopScope && Kind != Sema::TryCapture_Implicit) {
+ ByRef = (Kind == Sema::TryCapture_ExplicitByRef);
+ } else {
+ ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
+ }
+
+ // Compute the type of the field that will capture this variable.
+ if (ByRef) {
+ // C++11 [expr.prim.lambda]p15:
+ // An entity is captured by reference if it is implicitly or
+ // explicitly captured but not captured by copy. It is
+ // unspecified whether additional unnamed non-static data
+ // members are declared in the closure type for entities
+ // captured by reference.
+ //
+ // FIXME: It is not clear whether we want to build an lvalue reference
+ // to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears
+ // to do the former, while EDG does the latter. Core issue 1249 will
+ // clarify, but for now we follow GCC because it's a more permissive and
+ // easily defensible position.
+ CaptureType = S.Context.getLValueReferenceType(DeclRefType);
+ } else {
+ // C++11 [expr.prim.lambda]p14:
+ // For each entity captured by copy, an unnamed non-static
+ // data member is declared in the closure type. The
+ // declaration order of these members is unspecified. The type
+ // of such a data member is the type of the corresponding
+ // captured entity if the entity is not a reference to an
+ // object, or the referenced type otherwise. [Note: If the
+ // captured entity is a reference to a function, the
+ // corresponding data member is also a reference to a
+ // function. - end note ]
+ if (const ReferenceType *RefType = CaptureType->getAs<ReferenceType>()){
+ if (!RefType->getPointeeType()->isFunctionType())
+ CaptureType = RefType->getPointeeType();
+ }
+
+ // Forbid the lambda copy-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ S.Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return false;
+ }
+
+ if (S.RequireNonAbstractType(Loc, CaptureType,
+ diag::err_capture_of_abstract_type))
+ return false;
+ }
+
+ // Capture this variable in the lambda.
+ Expr *CopyExpr = 0;
+ if (BuildAndDiagnose) {
+ ExprResult Result = addAsFieldToClosureType(S, LSI, Var,
+ CaptureType, DeclRefType, Loc,
+ RefersToEnclosingLocal);
+ if (!Result.isInvalid())
+ CopyExpr = Result.take();
+ }
+
+ // Compute the type of a reference to this captured variable.
+ if (ByRef)
+ DeclRefType = CaptureType.getNonReferenceType();
+ else {
+ // C++ [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline
+ // function call operator [...]. This function call operator is
+ // declared const (9.3.1) if and only if the lambda-expression’s
+ // parameter-declaration-clause is not followed by mutable.
+ DeclRefType = CaptureType.getNonReferenceType();
+ if (!LSI->Mutable && !CaptureType->isReferenceType())
+ DeclRefType.addConst();
+ }
+
+ // Add the capture.
+ if (BuildAndDiagnose)
+ LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToEnclosingLocal,
+ Loc, EllipsisLoc, CaptureType, CopyExpr);
+
+ return true;
+}
+
+
+bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
TryCaptureKind Kind, SourceLocation EllipsisLoc,
bool BuildAndDiagnose,
QualType &CaptureType,
- QualType &DeclRefType) {
+ QualType &DeclRefType,
+ const unsigned *const FunctionScopeIndexToStopAt) {
bool Nested = false;
DeclContext *DC = CurContext;
- if (Var->getDeclContext() == DC) return true;
- if (!Var->hasLocalStorage()) return true;
+ const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
+ ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
+ // We need to sync up the Declaration Context with the
+ // FunctionScopeIndexToStopAt
+ if (FunctionScopeIndexToStopAt) {
+ unsigned FSIndex = FunctionScopes.size() - 1;
+ while (FSIndex != MaxFunctionScopesIndex) {
+ DC = getLambdaAwareParentOfDeclContext(DC);
+ --FSIndex;
+ }
+ }
- bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
+
+ // If the variable is declared in the current context (and is not an
+ // init-capture), there is no need to capture it.
+ if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true;
+ if (!Var->hasLocalStorage()) return true;
// 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
// we've either hit the declared scope of the variable or find an existing
- // capture of that variable.
+ // capture of that variable. We start from the innermost capturing-entity
+ // (the DC) and ensure that all intervening capturing-entities
+ // (blocks/lambdas etc.) between the innermost capturer and the variable`s
+ // declcontext can either capture the variable or have already captured
+ // the variable.
CaptureType = Var->getType();
DeclRefType = CaptureType.getNonReferenceType();
bool Explicit = (Kind != TryCapture_Implicit);
- unsigned FunctionScopesIndex = FunctionScopes.size() - 1;
+ unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
do {
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
- DeclContext *ParentDC;
- if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC))
- ParentDC = DC->getParent();
- else if (isa<CXXMethodDecl>(DC) &&
- cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
- cast<CXXRecordDecl>(DC->getParent())->isLambda())
- ParentDC = DC->getParent()->getParent();
- else {
- if (BuildAndDiagnose)
- diagnoseUncapturableValueReference(*this, Loc, Var, DC);
- return true;
- }
+ DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var,
+ ExprLoc,
+ BuildAndDiagnose,
+ *this);
+ if (!ParentDC) return true;
+
+ FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex];
+ CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
- CapturingScopeInfo *CSI =
- cast<CapturingScopeInfo>(FunctionScopes[FunctionScopesIndex]);
// Check whether we've already captured it.
- if (CSI->CaptureMap.count(Var)) {
- // If we found a capture, any subcaptures are nested.
- Nested = true;
-
- // Retrieve the capture type for this variable.
- CaptureType = CSI->getCapture(Var).getCaptureType();
-
- // Compute the type of an expression that refers to this variable.
- DeclRefType = CaptureType.getNonReferenceType();
-
- const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
- if (Cap.isCopyCapture() &&
- !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable))
- DeclRefType.addConst();
+ if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
+ DeclRefType))
break;
- }
-
- bool IsBlock = isa<BlockScopeInfo>(CSI);
- bool IsLambda = isa<LambdaScopeInfo>(CSI);
-
- // Lambdas are not allowed to capture unnamed variables
- // (e.g. anonymous unions).
- // FIXME: The C++11 rule don't actually state this explicitly, but I'm
- // assuming that's the intent.
- if (IsLambda && !Var->getDeclName()) {
+ // If we are instantiating a generic lambda call operator body,
+ // we do not want to capture new variables. What was captured
+ // during either a lambdas transformation or initial parsing
+ // should be used.
+ if (isGenericLambdaCallOperatorSpecialization(DC)) {
if (BuildAndDiagnose) {
- Diag(Loc, diag::err_lambda_capture_anonymous_var);
- Diag(Var->getLocation(), diag::note_declared_at);
- }
- return true;
- }
-
- // Prohibit variably-modified types; they're difficult to deal with.
- if (Var->getType()->isVariablyModifiedType()) {
- if (BuildAndDiagnose) {
- if (IsBlock)
- Diag(Loc, diag::err_ref_vm_type);
- else
- Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
- }
- return true;
- }
- // Prohibit structs with flexible array members too.
- // We cannot capture what is in the tail end of the struct.
- if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) {
- if (VTTy->getDecl()->hasFlexibleArrayMember()) {
- if (BuildAndDiagnose) {
- if (IsBlock)
- Diag(Loc, diag::err_ref_flexarray_type);
- else
- Diag(Loc, diag::err_lambda_capture_flexarray_type)
- << Var->getDeclName();
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
- }
- return true;
- }
- }
- // Lambdas are not allowed to capture __block variables; they don't
- // support the expected semantics.
- if (IsLambda && HasBlocksAttr) {
- if (BuildAndDiagnose) {
- Diag(Loc, diag::err_lambda_capture_block)
- << Var->getDeclName();
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+ if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
+ Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ Diag(LSI->Lambda->getLocStart(), diag::note_lambda_decl);
+ } else
+ diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
}
return true;
}
-
+ // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+ // certain types of variables (unnamed, variably modified types etc.)
+ // so check for eligibility.
+ if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this))
+ return true;
+
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
- // No capture-default
+ // No capture-default, and this is not an explicit capture
+ // so cannot capture this variable.
if (BuildAndDiagnose) {
- Diag(Loc, diag::err_lambda_impcap) << Var->getDeclName();
+ Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
diag::note_lambda_decl);
+ // FIXME: If we error out because an outer lambda can not implicitly
+ // capture a variable that an inner lambda explicitly captures, we
+ // should have the inner lambda do the explicit capture - because
+ // it makes for cleaner diagnostics later. This would purely be done
+ // so that the diagnostic does not misleadingly claim that a variable
+ // can not be captured by a lambda implicitly even though it is captured
+ // explicitly. Suggestion:
+ // - create const bool VariableCaptureWasInitiallyExplicit = Explicit
+ // at the function head
+ // - cache the StartingDeclContext - this must be a lambda
+ // - captureInLambda in the innermost lambda the variable.
}
return true;
}
@@ -11241,203 +11924,37 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
Explicit = false;
} while (!Var->getDeclContext()->Equals(DC));
- // Walk back down the scope stack, computing the type of the capture at
- // each step, checking type-specific requirements, and adding captures if
- // requested.
- for (unsigned I = ++FunctionScopesIndex, N = FunctionScopes.size(); I != N;
+ // Walk back down the scope stack, (e.g. from outer lambda to inner lambda)
+ // computing the type of the capture at each step, checking type-specific
+ // requirements, and adding captures if requested.
+ // If the variable had already been captured previously, we start capturing
+ // at the lambda nested within that one.
+ for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
++I) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
- // Compute the type of the capture and of a reference to the capture within
- // this scope.
- if (isa<BlockScopeInfo>(CSI)) {
- Expr *CopyExpr = 0;
- bool ByRef = false;
-
- // Blocks are not allowed to capture arrays.
- if (CaptureType->isArrayType()) {
- if (BuildAndDiagnose) {
- Diag(Loc, diag::err_ref_array_type);
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
- }
- return true;
- }
-
- // Forbid the block-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
- if (BuildAndDiagnose) {
- Diag(Loc, diag::err_arc_autoreleasing_capture)
- << /*block*/ 0;
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
- }
+ if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
+ if (!captureInBlock(BSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, *this))
return true;
- }
-
- if (HasBlocksAttr || CaptureType->isReferenceType()) {
- // Block capture by reference does not change the capture or
- // declaration reference types.
- ByRef = true;
- } else {
- // Block capture by copy introduces 'const'.
- CaptureType = CaptureType.getNonReferenceType().withConst();
- DeclRefType = CaptureType;
-
- if (getLangOpts().CPlusPlus && BuildAndDiagnose) {
- if (const RecordType *Record = DeclRefType->getAs<RecordType>()) {
- // The capture logic needs the destructor, so make sure we mark it.
- // Usually this is unnecessary because most local variables have
- // their destructors marked at declaration time, but parameters are
- // an exception because it's technically only the call site that
- // actually requires the destructor.
- if (isa<ParmVarDecl>(Var))
- FinalizeVarWithDestructor(Var, Record);
-
- // Enter a new evaluation context to insulate the copy
- // full-expression.
- EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
-
- // According to the blocks spec, the capture of a variable from
- // the stack requires a const copy constructor. This is not true
- // of the copy/move done to move a __block variable to the heap.
- Expr *DeclRef = new (Context) DeclRefExpr(Var, Nested,
- DeclRefType.withConst(),
- VK_LValue, Loc);
-
- ExprResult Result
- = PerformCopyInitialization(
- InitializedEntity::InitializeBlock(Var->getLocation(),
- CaptureType, false),
- Loc, Owned(DeclRef));
-
- // Build a full-expression copy expression if initialization
- // succeeded and used a non-trivial constructor. Recover from
- // errors by pretending that the copy isn't necessary.
- if (!Result.isInvalid() &&
- !cast<CXXConstructExpr>(Result.get())->getConstructor()
- ->isTrivial()) {
- Result = MaybeCreateExprWithCleanups(Result);
- CopyExpr = Result.take();
- }
- }
- }
- }
-
- // Actually capture the variable.
- if (BuildAndDiagnose)
- CSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
- SourceLocation(), CaptureType, CopyExpr);
Nested = true;
- continue;
- }
-
- if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- // By default, capture variables by reference.
- bool ByRef = true;
- // Using an LValue reference type is consistent with Lambdas (see below).
- CaptureType = Context.getLValueReferenceType(DeclRefType);
-
- Expr *CopyExpr = 0;
- if (BuildAndDiagnose) {
- ExprResult Result = captureInCapturedRegion(*this, RSI, Var,
- CaptureType, DeclRefType,
- Loc, Nested);
- if (!Result.isInvalid())
- CopyExpr = Result.take();
- }
-
- // Actually capture the variable.
- if (BuildAndDiagnose)
- CSI->addCapture(Var, /*isBlock*/false, ByRef, Nested, Loc,
- SourceLocation(), CaptureType, CopyExpr);
+ } else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
+ if (!captureInCapturedRegion(RSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, *this))
+ return true;
Nested = true;
- continue;
- }
-
- LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
-
- // Determine whether we are capturing by reference or by value.
- bool ByRef = false;
- if (I == N - 1 && Kind != TryCapture_Implicit) {
- ByRef = (Kind == TryCapture_ExplicitByRef);
- } else {
- ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
- }
-
- // Compute the type of the field that will capture this variable.
- if (ByRef) {
- // C++11 [expr.prim.lambda]p15:
- // An entity is captured by reference if it is implicitly or
- // explicitly captured but not captured by copy. It is
- // unspecified whether additional unnamed non-static data
- // members are declared in the closure type for entities
- // captured by reference.
- //
- // FIXME: It is not clear whether we want to build an lvalue reference
- // to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears
- // to do the former, while EDG does the latter. Core issue 1249 will
- // clarify, but for now we follow GCC because it's a more permissive and
- // easily defensible position.
- CaptureType = Context.getLValueReferenceType(DeclRefType);
} else {
- // C++11 [expr.prim.lambda]p14:
- // For each entity captured by copy, an unnamed non-static
- // data member is declared in the closure type. The
- // declaration order of these members is unspecified. The type
- // of such a data member is the type of the corresponding
- // captured entity if the entity is not a reference to an
- // object, or the referenced type otherwise. [Note: If the
- // captured entity is a reference to a function, the
- // corresponding data member is also a reference to a
- // function. - end note ]
- if (const ReferenceType *RefType = CaptureType->getAs<ReferenceType>()){
- if (!RefType->getPointeeType()->isFunctionType())
- CaptureType = RefType->getPointeeType();
- }
-
- // Forbid the lambda copy-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
- if (BuildAndDiagnose) {
- Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
- Diag(Var->getLocation(), diag::note_previous_decl)
- << Var->getDeclName();
- }
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+ if (!captureInLambda(LSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, Kind, EllipsisLoc,
+ /*IsTopScope*/I == N - 1, *this))
return true;
- }
- }
-
- // Capture this variable in the lambda.
- Expr *CopyExpr = 0;
- if (BuildAndDiagnose) {
- ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType,
- DeclRefType, Loc,
- Nested);
- if (!Result.isInvalid())
- CopyExpr = Result.take();
- }
-
- // Compute the type of a reference to this captured variable.
- if (ByRef)
- DeclRefType = CaptureType.getNonReferenceType();
- else {
- // C++ [expr.prim.lambda]p5:
- // The closure type for a lambda-expression has a public inline
- // function call operator [...]. This function call operator is
- // declared const (9.3.1) if and only if the lambda-expression’s
- // parameter-declaration-clause is not followed by mutable.
- DeclRefType = CaptureType.getNonReferenceType();
- if (!LSI->Mutable && !CaptureType->isReferenceType())
- DeclRefType.addConst();
+ Nested = true;
}
-
- // Add the capture.
- if (BuildAndDiagnose)
- CSI->addCapture(Var, /*IsBlock=*/false, ByRef, Nested, Loc,
- EllipsisLoc, CaptureType, CopyExpr);
- Nested = true;
}
-
return false;
}
@@ -11447,7 +11964,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
QualType DeclRefType;
return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,
/*BuildAndDiagnose=*/true, CaptureType,
- DeclRefType);
+ DeclRefType, 0);
}
QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
@@ -11456,28 +11973,36 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
// Determine whether we can capture this variable.
if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
- /*BuildAndDiagnose=*/false, CaptureType, DeclRefType))
+ /*BuildAndDiagnose=*/false, CaptureType,
+ DeclRefType, 0))
return QualType();
return DeclRefType;
}
-static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
- SourceLocation Loc) {
- // 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->getLinkage() != ExternalLinkage &&
- !(Var->isStaticDataMember() && Var->hasInit())) {
- SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
- }
- SemaRef.tryCaptureVariable(Var, Loc);
- Var->setUsed(true);
+// If either the type of the variable or the initializer is dependent,
+// return false. Otherwise, determine whether the variable is a constant
+// expression. Use this if you need to know if a variable that might or
+// might not be dependent is truly a constant expression.
+static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
+ ASTContext &Context) {
+
+ if (Var->getType()->isDependentType())
+ return false;
+ const VarDecl *DefVD = 0;
+ Var->getAnyInitializer(DefVD);
+ if (!DefVD)
+ return false;
+ EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
+ Expr *Init = cast<Expr>(Eval->Value);
+ if (Init->isValueDependent())
+ return false;
+ return IsVariableAConstantExpression(Var, Context);
}
+
void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
// Per C++11 [basic.def.odr], a variable is odr-used "unless it is
// an object that satisfies the requirements for appearing in a
@@ -11485,6 +12010,22 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
// is immediately applied." This function handles the lvalue-to-rvalue
// conversion part.
MaybeODRUseExprs.erase(E->IgnoreParens());
+
+ // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
+ // to a variable that is a constant expression, and if so, identify it as
+ // a reference to a variable that does not involve an odr-use of that
+ // variable.
+ if (LambdaScopeInfo *LSI = getCurLambda()) {
+ Expr *SansParensExpr = E->IgnoreParens();
+ VarDecl *Var = 0;
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
+ Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
+ else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
+ Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+
+ if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
+ LSI->markVariableExprAsNonODRUsed(SansParensExpr);
+ }
}
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
@@ -11515,46 +12056,105 @@ void Sema::CleanupVarDeclMarking() {
llvm_unreachable("Unexpcted expression");
}
- MarkVarDeclODRUsed(*this, Var, Loc);
+ MarkVarDeclODRUsed(Var, Loc, *this, /*MaxFunctionScopeIndex Pointer*/ 0);
}
MaybeODRUseExprs.clear();
}
-// Mark a VarDecl referenced, and perform the necessary handling to compute
-// odr-uses.
+
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
VarDecl *Var, Expr *E) {
+ assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) &&
+ "Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
- if (!IsPotentiallyEvaluatedContext(SemaRef))
- return;
-
- // Implicit instantiation of static data members of class templates.
- if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) {
- MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
- if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation &&
- (!AlreadyInstantiated ||
- Var->isUsableInConstantExpressions(SemaRef.Context))) {
- if (!AlreadyInstantiated) {
+ // If the context is not PotentiallyEvaluated and not Unevaluated
+ // (i.e PotentiallyEvaluatedIfUsed) do not bother to consider variables
+ // in this context for odr-use unless we are within a lambda.
+ // If we don't know whether the context is potentially evaluated or not
+ // (for e.g., if we're in a generic lambda), we want to add a potential
+ // capture and eventually analyze for odr-use.
+ // We should also be able to analyze certain constructs in a non-generic
+ // lambda setting for potential odr-use and capture violation:
+ // template<class T> void foo(T t) {
+ // auto L = [](int i) { return t; };
+ // }
+ //
+ if (!IsPotentiallyEvaluatedContext(SemaRef)) {
+
+ if (SemaRef.isUnevaluatedContext()) return;
+
+ const bool refersToEnclosingScope =
+ (SemaRef.CurContext != Var->getDeclContext() &&
+ Var->getDeclContext()->isFunctionOrMethod());
+ if (!refersToEnclosingScope) return;
+
+ if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ const bool IsConstantExpr = IsVariableNonDependentAndAConstantExpression(
+ Var, SemaRef.Context);
+ assert(E && "Capture variable should be used in an expression.");
+ if (!IsConstantExpr || !Var->getType()->isReferenceType())
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ return;
+ }
+
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
+ assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
+ "Can't instantiate a partial template specialization.");
+
+ // Implicit instantiation of static data members, static data member
+ // templates of class templates, and variable template specializations.
+ // Delay instantiations of variable templates, except for those
+ // that could be used in a constant expression.
+ TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ if (isTemplateInstantiation(TSK)) {
+ bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
+
+ 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);
- MSInfo->setPointOfInstantiation(Loc);
+ } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
+ // 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;
+ }
+
+ if (Var->getPointOfInstantiation().isInvalid())
+ Var->setTemplateSpecializationKind(TSK, Loc);
+
+ if (TryInstantiating) {
+ SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
+ bool InstantiationDependent = false;
+ bool IsNonDependent =
+ VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
+ VarSpec->getTemplateArgsInfo(), InstantiationDependent)
+ : true;
+
+ // Do not instantiate specializations that are still type-dependent.
+ if (IsNonDependent) {
+ if (Var->isUsableInConstantExpressions(SemaRef.Context)) {
+ // Do not defer instantiations of variables which could be used in a
+ // constant expression.
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ } else {
+ SemaRef.PendingInstantiations
+ .push_back(std::make_pair(Var, PointOfInstantiation));
+ }
}
- SourceLocation PointOfInstantiation = MSInfo->getPointOfInstantiation();
- if (Var->isUsableInConstantExpressions(SemaRef.Context))
- // Do not defer instantiations of variables which could be used in a
- // constant expression.
- SemaRef.InstantiateStaticDataMemberDefinition(PointOfInstantiation,Var);
- else
- SemaRef.PendingInstantiations.push_back(
- std::make_pair(Var, PointOfInstantiation));
}
}
-
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
// the requirements for appearing in a constant expression (5.19) and, if
// it is an object, the lvalue-to-rvalue conversion (4.1)
@@ -11563,14 +12163,16 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// Note that we use the C++11 definition everywhere because nothing in
// C++03 depends on whether we get the C++03 version correct. The second
// part does not apply to references, since they are not objects.
- const VarDecl *DefVD;
- if (E && !isa<ParmVarDecl>(Var) &&
- Var->isUsableInConstantExpressions(SemaRef.Context) &&
- Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {
+ if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
+ // A reference initialized by a constant expression can never be
+ // odr-used, so simply ignore it.
+ // But a non-reference might get odr-used if it doesn't undergo
+ // an lvalue-to-rvalue or is discarded, so track it.
if (!Var->getType()->isReferenceType())
SemaRef.MaybeODRUseExprs.insert(E);
- } else
- MarkVarDeclODRUsed(SemaRef, Var, Loc);
+ }
+ else
+ MarkVarDeclODRUsed(Var, Loc, SemaRef, /*MaxFunctionScopeIndex ptr*/0);
}
/// \brief Mark a variable referenced, and check whether it is odr-used
@@ -11887,7 +12489,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
Selector Sel = ME->getSelector();
// self = [<foo> init...]
- if (isSelfExpr(Op->getLHS()) && Sel.getNameForSlot(0).startswith("init"))
+ if (isSelfExpr(Op->getLHS()) && ME->getMethodFamily() == OMF_init)
diagnostic = diag::warn_condition_is_idiomatic_assignment;
// <foo> = [<bar> nextObject]
@@ -12202,15 +12804,49 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
assert(E->getObjectKind() == OK_Ordinary);
// Rebuild the function type, replacing the result type with DestType.
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
- DestType =
- S.Context.getFunctionType(DestType,
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- Proto->getExtProtoInfo());
- else
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType);
+ if (Proto) {
+ // __unknown_anytype(...) is a special case used by the debugger when
+ // it has no idea what a function's signature is.
+ //
+ // We want to build this call essentially under the K&R
+ // unprototyped rules, but making a FunctionNoProtoType in C++
+ // would foul up all sorts of assumptions. However, we cannot
+ // simply pass all arguments as variadic arguments, nor can we
+ // portably just call the function under a non-variadic type; see
+ // the comment on IR-gen's TargetInfo::isNoProtoCallVariadic.
+ // However, it turns out that in practice it is generally safe to
+ // call a function declared as "A foo(B,C,D);" under the prototype
+ // "A foo(B,C,D,...);". The only known exception is with the
+ // Windows ABI, where any variadic function is implicitly cdecl
+ // regardless of its normal CC. Therefore we change the parameter
+ // types to match the types of the arguments.
+ //
+ // This is a hack, but it is far superior to moving the
+ // corresponding target-specific code from IR-gen to Sema/AST.
+
+ ArrayRef<QualType> ParamTypes = Proto->getArgTypes();
+ SmallVector<QualType, 8> ArgTypes;
+ if (ParamTypes.empty() && Proto->isVariadic()) { // the special case
+ ArgTypes.reserve(E->getNumArgs());
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
+ Expr *Arg = E->getArg(i);
+ QualType ArgType = Arg->getType();
+ if (E->isLValue()) {
+ ArgType = S.Context.getLValueReferenceType(ArgType);
+ } else if (E->isXValue()) {
+ ArgType = S.Context.getRValueReferenceType(ArgType);
+ }
+ ArgTypes.push_back(ArgType);
+ }
+ ParamTypes = ArgTypes;
+ }
+ DestType = S.Context.getFunctionType(DestType, ParamTypes,
+ Proto->getExtProtoInfo());
+ } else {
DestType = S.Context.getFunctionNoProtoType(DestType,
FnType->getExtInfo());
+ }
// Rebuild the appropriate pointer-to-function type.
switch (Kind) {
@@ -12343,6 +12979,8 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
return ExprError();
}
+ // Modifying the declaration like this is friendly to IR-gen but
+ // also really dangerous.
VD->setType(DestType);
E->setType(Type);
E->setValueKind(ValueKind);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 27032a911147..07e465766b74 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
@@ -31,6 +32,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
@@ -305,7 +307,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
SemaDiagnosticBuilder DtorDiag = Diag(NameLoc,
diag::err_destructor_class_name);
if (S) {
- const DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ const DeclContext *Ctx = S->getEntity();
if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx))
DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc),
Class->getNameAsString());
@@ -462,11 +464,16 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
if (!Operand->getType()->isDependentType()) {
- if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType()))
- return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ bool HasMultipleGUIDs = false;
+ if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType(),
+ &HasMultipleGUIDs)) {
+ if (HasMultipleGUIDs)
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+ else
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ }
}
- // FIXME: add __uuidof semantic analysis for type operand.
return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
Operand,
SourceRange(TypeidLoc, RParenLoc)));
@@ -478,11 +485,16 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
Expr *E,
SourceLocation RParenLoc) {
if (!E->getType()->isDependentType()) {
- if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType()) &&
- !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
- return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ bool HasMultipleGUIDs = false;
+ if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType(), &HasMultipleGUIDs) &&
+ !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ if (HasMultipleGUIDs)
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+ else
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ }
}
- // FIXME: add __uuidof semantic analysis for type operand.
+
return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
E,
SourceRange(TypeidLoc, RParenLoc)));
@@ -741,21 +753,30 @@ static Expr *captureThis(ASTContext &Context, RecordDecl *RD,
return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true);
}
-void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
+bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit,
+ bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) {
// We don't need to capture this in an unevaluated context.
if (isUnevaluatedContext() && !Explicit)
- return;
+ return true;
- // Otherwise, check that we can capture 'this'.
+ const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ?
+ *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
+ // Otherwise, check that we can capture 'this'.
unsigned NumClosures = 0;
- for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
+ for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) {
if (CapturingScopeInfo *CSI =
dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
if (CSI->CXXThisCaptureIndex != 0) {
// 'this' is already being captured; there isn't anything more to do.
break;
}
-
+ LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);
+ if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) {
+ // This context can't implicitly capture 'this'; fail out.
+ if (BuildAndDiagnose)
+ Diag(Loc, diag::err_this_capture) << Explicit;
+ return true;
+ }
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
@@ -767,17 +788,18 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
continue;
}
// This context can't implicitly capture 'this'; fail out.
- Diag(Loc, diag::err_this_capture) << Explicit;
- return;
+ if (BuildAndDiagnose)
+ Diag(Loc, diag::err_this_capture) << Explicit;
+ return true;
}
break;
}
-
+ if (!BuildAndDiagnose) return false;
// Mark that we're implicitly capturing 'this' in all the scopes we skipped.
// FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
// contexts.
- for (unsigned idx = FunctionScopes.size() - 1;
- NumClosures; --idx, --NumClosures) {
+ for (unsigned idx = MaxFunctionScopesIndex; NumClosures;
+ --idx, --NumClosures) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
Expr *ThisExpr = 0;
QualType ThisTy = getCurrentThisType();
@@ -791,6 +813,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
bool isNested = NumClosures > 1;
CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);
}
+ return false;
}
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
@@ -893,17 +916,21 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
- if (!Result.isInvalid() && ListInitialization &&
- isa<InitListExpr>(Result.get())) {
+ if (Result.isInvalid() || !ListInitialization)
+ return Result;
+
+ Expr *Inner = Result.get();
+ if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner))
+ Inner = BTE->getSubExpr();
+ if (isa<InitListExpr>(Inner)) {
// If the list-initialization doesn't involve a constructor call, we'll get
// the initializer-list (with corrected type) back, but that's not what we
// want, since it will be treated as an initializer list in further
// processing. Explicitly insert a cast here.
- InitListExpr *List = cast<InitListExpr>(Result.take());
- Result = Owned(CXXFunctionalCastExpr::Create(Context, List->getType(),
- Expr::getValueKindForType(TInfo->getType()),
- TInfo, TyBeginLoc, CK_NoOp,
- List, /*Path=*/0, RParenLoc));
+ QualType ResultType = Result.get()->getType();
+ Result = Owned(CXXFunctionalCastExpr::Create(
+ Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
+ CK_NoOp, Result.take(), /*Path=*/ 0, LParenLoc, RParenLoc));
}
// FIXME: Improve AST representation?
@@ -1017,10 +1044,23 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
if (Expr *NumElts = (Expr *)Array.NumElts) {
if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) {
- Array.NumElts
- = VerifyIntegerConstantExpression(NumElts, 0,
- diag::err_new_array_nonconst)
- .take();
+ if (getLangOpts().CPlusPlus1y) {
+ // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator
+ // shall be a converted constant expression (5.19) of type std::size_t
+ // and shall evaluate to a strictly positive value.
+ unsigned IntWidth = Context.getTargetInfo().getIntWidth();
+ assert(IntWidth && "Builtin type of size 0?");
+ llvm::APSInt Value(IntWidth);
+ Array.NumElts
+ = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value,
+ CCEK_NewExpr)
+ .take();
+ } else {
+ Array.NumElts
+ = VerifyIntegerConstantExpression(NumElts, 0,
+ diag::err_new_array_nonconst)
+ .take();
+ }
if (!Array.NumElts)
return ExprError();
}
@@ -1180,70 +1220,85 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped
// enumeration type, or a class type for which a single non-explicit
// conversion function to integral or unscoped enumeration type exists.
+ // C++1y [expr.new]p6: The expression [...] is implicitly converted to
+ // std::size_t.
if (ArraySize && !ArraySize->isTypeDependent()) {
- class SizeConvertDiagnoser : public ICEConvertDiagnoser {
- Expr *ArraySize;
-
- public:
- SizeConvertDiagnoser(Expr *ArraySize)
- : ICEConvertDiagnoser(false, false), ArraySize(ArraySize) { }
-
- virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_array_size_not_integral)
- << S.getLangOpts().CPlusPlus11 << T;
- }
-
- virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_array_size_incomplete_type)
- << T << ArraySize->getSourceRange();
- }
-
- virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
- SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy;
- }
-
- virtual DiagnosticBuilder noteExplicitConv(Sema &S,
- CXXConversionDecl *Conv,
- QualType ConvTy) {
- return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
- << ConvTy->isEnumeralType() << ConvTy;
- }
-
- virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
- return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T;
- }
-
- virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) {
- return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
- << ConvTy->isEnumeralType() << ConvTy;
- }
-
- virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return S.Diag(Loc,
- S.getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_array_size_conversion
- : diag::ext_array_size_conversion)
- << T << ConvTy->isEnumeralType() << ConvTy;
- }
- } SizeDiagnoser(ArraySize);
+ ExprResult ConvertedSize;
+ if (getLangOpts().CPlusPlus1y) {
+ unsigned IntWidth = Context.getTargetInfo().getIntWidth();
+ assert(IntWidth && "Builtin type of size 0?");
+ llvm::APSInt Value(IntWidth);
+ ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(),
+ AA_Converting);
+
+ if (!ConvertedSize.isInvalid() &&
+ ArraySize->getType()->getAs<RecordType>())
+ // Diagnose the compatibility of this conversion.
+ Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
+ << ArraySize->getType() << 0 << "'size_t'";
+ } else {
+ class SizeConvertDiagnoser : public ICEConvertDiagnoser {
+ protected:
+ Expr *ArraySize;
+
+ public:
+ SizeConvertDiagnoser(Expr *ArraySize)
+ : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false),
+ ArraySize(ArraySize) {}
+
+ virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_array_size_not_integral)
+ << S.getLangOpts().CPlusPlus11 << T;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) {
+ return S.Diag(Loc, diag::err_array_size_incomplete_type)
+ << T << ArraySize->getSourceRange();
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseAmbiguous(
+ Sema &S, SourceLocation Loc, QualType T) {
+ return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T;
+ }
+
+ virtual SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ return S.Diag(Loc,
+ S.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_array_size_conversion
+ : diag::ext_array_size_conversion)
+ << T << ConvTy->isEnumeralType() << ConvTy;
+ }
+ } SizeDiagnoser(ArraySize);
- ExprResult ConvertedSize
- = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, SizeDiagnoser,
- /*AllowScopedEnumerations*/ false);
+ ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize,
+ SizeDiagnoser);
+ }
if (ConvertedSize.isInvalid())
return ExprError();
ArraySize = ConvertedSize.take();
QualType SizeType = ArraySize->getType();
+
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
@@ -1306,16 +1361,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
FunctionDecl *OperatorNew = 0;
FunctionDecl *OperatorDelete = 0;
- Expr **PlaceArgs = PlacementArgs.data();
- unsigned NumPlaceArgs = PlacementArgs.size();
if (!AllocType->isDependentType() &&
- !Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(PlaceArgs, NumPlaceArgs)) &&
+ !Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
FindAllocationFunctions(StartLoc,
SourceRange(PlacementLParen, PlacementRParen),
- UseGlobal, AllocType, ArraySize, PlaceArgs,
- NumPlaceArgs, OperatorNew, OperatorDelete))
+ UseGlobal, AllocType, ArraySize, PlacementArgs,
+ OperatorNew, OperatorDelete))
return ExprError();
// If this is an array allocation, compute whether the usual array
@@ -1333,24 +1385,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
VariadicCallType CallType =
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
- if (GatherArgumentsForCall(PlacementLParen, OperatorNew,
- Proto, 1, PlaceArgs, NumPlaceArgs,
- AllPlaceArgs, CallType))
+ if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1,
+ PlacementArgs, AllPlaceArgs, CallType))
return ExprError();
- NumPlaceArgs = AllPlaceArgs.size();
- if (NumPlaceArgs > 0)
- PlaceArgs = &AllPlaceArgs[0];
+ if (!AllPlaceArgs.empty())
+ PlacementArgs = AllPlaceArgs;
- DiagnoseSentinelCalls(OperatorNew, PlacementLParen,
- PlaceArgs, NumPlaceArgs);
+ DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs);
// FIXME: Missing call to CheckFunctionCall or equivalent
}
// Warn if the type is over-aligned and is being allocated by global operator
// new.
- if (NumPlaceArgs == 0 && OperatorNew &&
+ if (PlacementArgs.empty() && OperatorNew &&
(OperatorNew->isImplicit() ||
getSourceManager().isInSystemHeader(OperatorNew->getLocStart()))) {
if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){
@@ -1458,8 +1507,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
OperatorDelete,
UsualArrayDeleteWantsSize,
- llvm::makeArrayRef(PlaceArgs, NumPlaceArgs),
- TypeIdParens,
+ PlacementArgs, TypeIdParens,
ArraySize, initStyle, Initializer,
ResultType, AllocTypeInfo,
Range, DirectInitRange));
@@ -1504,24 +1552,30 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
/// \brief Determine whether the given function is a non-placement
/// deallocation function.
-static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) {
+static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
if (FD->isInvalidDecl())
return false;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
return Method->isUsualDeallocationFunction();
- return ((FD->getOverloadedOperator() == OO_Delete ||
- FD->getOverloadedOperator() == OO_Array_Delete) &&
- FD->getNumParams() == 1);
+ if (FD->getOverloadedOperator() != OO_Delete &&
+ FD->getOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ if (FD->getNumParams() == 1)
+ return true;
+
+ return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 &&
+ S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(),
+ S.Context.getSizeType());
}
/// FindAllocationFunctions - Finds the overloads of operator new and delete
/// that are appropriate for the allocation.
bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool UseGlobal, QualType AllocType,
- bool IsArray, Expr **PlaceArgs,
- unsigned NumPlaceArgs,
+ bool IsArray, MultiExprArg PlaceArgs,
FunctionDecl *&OperatorNew,
FunctionDecl *&OperatorDelete) {
// --- Choosing an allocation function ---
@@ -1533,7 +1587,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 3) The first argument is always size_t. Append the arguments from the
// placement form.
- SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs);
+ SmallVector<Expr*, 8> AllocArgs(1 + PlaceArgs.size());
// We don't care about the actual value of this argument.
// FIXME: Should the Sema create the expression and embed it in the syntax
// tree? Or should the consumer just recalculate the value?
@@ -1542,7 +1596,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
Context.getSizeType(),
SourceLocation());
AllocArgs[0] = &Size;
- std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
+ std::copy(PlaceArgs.begin(), PlaceArgs.end(), AllocArgs.begin() + 1);
// C++ [expr.new]p8:
// If the allocated type is a non-array type, the allocation
@@ -1560,19 +1614,32 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (AllocElemType->isRecordType() && !UseGlobal) {
CXXRecordDecl *Record
= cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl());
- if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
- AllocArgs.size(), Record, /*AllowMissing=*/true,
- OperatorNew))
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, Record,
+ /*AllowMissing=*/true, OperatorNew))
return true;
}
+
if (!OperatorNew) {
// Didn't find a member overload. Look for a global one.
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
- if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
- AllocArgs.size(), TUDecl, /*AllowMissing=*/false,
- OperatorNew))
+ bool FallbackEnabled = IsArray && Context.getLangOpts().MicrosoftMode;
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl,
+ /*AllowMissing=*/FallbackEnabled, OperatorNew,
+ /*Diagnose=*/!FallbackEnabled)) {
+ if (!FallbackEnabled)
+ return true;
+
+ // MSVC will fall back on trying to find a matching global operator new
+ // if operator new[] cannot be found. Also, MSVC will leak by not
+ // generating a call to operator delete or operator delete[], but we
+ // will not replicate that bug.
+ NewName = Context.DeclarationNames.getCXXOperatorName(OO_New);
+ DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl,
+ /*AllowMissing=*/false, OperatorNew))
return true;
+ }
}
// We don't need an operator delete if we're running under
@@ -1584,8 +1651,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// FindAllocationOverload can change the passed in arguments, so we need to
// copy them back.
- if (NumPlaceArgs > 0)
- std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
+ if (!PlaceArgs.empty())
+ std::copy(AllocArgs.begin() + 1, AllocArgs.end(), PlaceArgs.data());
// C++ [expr.new]p19:
//
@@ -1619,7 +1686,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// we had explicit placement arguments. This matters for things like
// struct A { void *operator new(size_t, int = 0); ... };
// A *a = new A()
- bool isPlacementNew = (NumPlaceArgs > 0 || OperatorNew->param_size() != 1);
+ bool isPlacementNew = (!PlaceArgs.empty() || OperatorNew->param_size() != 1);
if (isPlacementNew) {
// C++ [expr.new]p20:
@@ -1676,9 +1743,28 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
DEnd = FoundDelete.end();
D != DEnd; ++D) {
if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
- if (isNonPlacementDeallocationFunction(Fn))
+ if (isNonPlacementDeallocationFunction(*this, Fn))
Matches.push_back(std::make_pair(D.getPair(), Fn));
}
+
+ // C++1y [expr.new]p22:
+ // For a non-placement allocation function, the normal deallocation
+ // function lookup is used
+ // C++1y [expr.delete]p?:
+ // If [...] deallocation function lookup finds both a usual deallocation
+ // function with only a pointer parameter and a usual deallocation
+ // function with both a pointer parameter and a size parameter, then the
+ // selected deallocation function shall be the one with two parameters.
+ // Otherwise, the selected deallocation function shall be the function
+ // with one parameter.
+ if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+ if (Matches[0].second->getNumParams() == 1)
+ Matches.erase(Matches.begin());
+ else
+ Matches.erase(Matches.begin() + 1);
+ assert(Matches[0].second->getNumParams() == 2 &&
+ "found an unexpected uusal deallocation function");
+ }
}
// C++ [expr.new]p20:
@@ -1694,13 +1780,14 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// as a placement deallocation function, would have been
// selected as a match for the allocation function, the program
// is ill-formed.
- if (NumPlaceArgs && getLangOpts().CPlusPlus11 &&
- isNonPlacementDeallocationFunction(OperatorDelete)) {
+ if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 &&
+ isNonPlacementDeallocationFunction(*this, OperatorDelete)) {
Diag(StartLoc, diag::err_placement_new_non_placement_delete)
- << SourceRange(PlaceArgs[0]->getLocStart(),
- PlaceArgs[NumPlaceArgs - 1]->getLocEnd());
- Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
- << DeleteName;
+ << SourceRange(PlaceArgs.front()->getLocStart(),
+ PlaceArgs.back()->getLocEnd());
+ if (!OperatorDelete->isImplicit())
+ Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
+ << DeleteName;
} else {
CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
Matches[0].first);
@@ -1713,8 +1800,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
/// FindAllocationOverload - Find an fitting overload for the allocation
/// function in the specified scope.
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
- DeclarationName Name, Expr** Args,
- unsigned NumArgs, DeclContext *Ctx,
+ DeclarationName Name, MultiExprArg Args,
+ DeclContext *Ctx,
bool AllowMissing, FunctionDecl *&Operator,
bool Diagnose) {
LookupResult R(*this, Name, StartLoc, LookupOrdinaryName);
@@ -1741,15 +1828,13 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
/*ExplicitTemplateArgs=*/0,
- llvm::makeArrayRef(Args, NumArgs),
- Candidates,
+ Args, Candidates,
/*SuppressUserConversions=*/false);
continue;
}
FunctionDecl *Fn = cast<FunctionDecl>(D);
- AddOverloadCandidate(Fn, Alloc.getPair(),
- llvm::makeArrayRef(Args, NumArgs), Candidates,
+ AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates,
/*SuppressUserConversions=*/false);
}
@@ -1765,7 +1850,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// asserted on, though, since invalid decls are left in there.)
// Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
- for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
+ for (unsigned i = 0; (i < Args.size() && i < NumArgsInFnDecl); ++i) {
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(i));
@@ -1793,8 +1878,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (Diagnose) {
Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args);
}
return true;
@@ -1802,8 +1886,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (Diagnose) {
Diag(StartLoc, diag::err_ovl_ambiguous_call)
<< Name << Range;
- Candidates.NoteCandidates(*this, OCD_ViableCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args);
}
return true;
@@ -1814,8 +1897,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
<< Name
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args);
}
return true;
}
@@ -1832,13 +1914,19 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
/// void* operator new[](std::size_t) throw(std::bad_alloc);
/// void operator delete(void *) throw();
/// void operator delete[](void *) throw();
-/// // C++0x:
+/// // C++11:
+/// void* operator new(std::size_t);
+/// void* operator new[](std::size_t);
+/// void operator delete(void *) noexcept;
+/// void operator delete[](void *) noexcept;
+/// // C++1y:
/// void* operator new(std::size_t);
/// void* operator new[](std::size_t);
-/// void operator delete(void *);
-/// void operator delete[](void *);
+/// void operator delete(void *) noexcept;
+/// void operator delete[](void *) noexcept;
+/// void operator delete(void *, std::size_t) noexcept;
+/// void operator delete[](void *, std::size_t) noexcept;
/// @endcode
-/// C++0x operator delete is implicitly noexcept.
/// Note that the placement and nothrow forms of new are *not* implicitly
/// declared. Their use requires including \<new\>.
void Sema::DeclareGlobalNewDelete() {
@@ -1855,11 +1943,18 @@ void Sema::DeclareGlobalNewDelete() {
// void* operator new[](std::size_t) throw(std::bad_alloc);
// void operator delete(void*) throw();
// void operator delete[](void*) throw();
- // C++0x:
+ // C++11:
+ // void* operator new(std::size_t);
+ // void* operator new[](std::size_t);
+ // void operator delete(void*) noexcept;
+ // void operator delete[](void*) noexcept;
+ // C++1y:
// void* operator new(std::size_t);
// void* operator new[](std::size_t);
- // void operator delete(void*);
- // void operator delete[](void*);
+ // void operator delete(void*) noexcept;
+ // void operator delete[](void*) noexcept;
+ // void operator delete(void*, std::size_t) noexcept;
+ // void operator delete[](void*, std::size_t) noexcept;
//
// These implicit declarations introduce only the function names operator
// new, operator new[], operator delete, operator delete[].
@@ -1868,8 +1963,6 @@ void Sema::DeclareGlobalNewDelete() {
// "std" or "bad_alloc" as necessary to form the exception specification.
// However, we do not make these implicit declarations visible to name
// lookup.
- // Note that the C++0x versions of operator delete are deallocation functions,
- // and thus are implicitly noexcept.
if (!StdBadAlloc && !getLangOpts().CPlusPlus11) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
@@ -1889,40 +1982,61 @@ void Sema::DeclareGlobalNewDelete() {
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_New),
- VoidPtr, SizeT, AssumeSaneOperatorNew);
+ VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
- VoidPtr, SizeT, AssumeSaneOperatorNew);
+ VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Delete),
Context.VoidTy, VoidPtr);
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
Context.VoidTy, VoidPtr);
+ if (getLangOpts().SizedDeallocation) {
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete),
+ Context.VoidTy, VoidPtr, Context.getSizeType());
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
+ Context.VoidTy, VoidPtr, Context.getSizeType());
+ }
}
/// DeclareGlobalAllocationFunction - Declares a single implicit global
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
- QualType Return, QualType Argument,
+ QualType Return,
+ QualType Param1, QualType Param2,
bool AddMallocAttr) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
+ unsigned NumParams = Param2.isNull() ? 1 : 2;
// Check if this function is already declared.
- {
- DeclContext::lookup_result R = GlobalCtx->lookup(Name);
- for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end();
- Alloc != AllocEnd; ++Alloc) {
- // Only look at non-template functions, as it is the predefined,
- // non-templated allocation function we are trying to declare here.
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) {
- QualType InitialParamType =
- Context.getCanonicalType(
- Func->getParamDecl(0)->getType().getUnqualifiedType());
+ DeclContext::lookup_result R = GlobalCtx->lookup(Name);
+ for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end();
+ Alloc != AllocEnd; ++Alloc) {
+ // Only look at non-template functions, as it is the predefined,
+ // non-templated allocation function we are trying to declare here.
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) {
+ if (Func->getNumParams() == NumParams) {
+ QualType InitialParam1Type =
+ Context.getCanonicalType(Func->getParamDecl(0)
+ ->getType().getUnqualifiedType());
+ QualType InitialParam2Type =
+ NumParams == 2
+ ? Context.getCanonicalType(Func->getParamDecl(1)
+ ->getType().getUnqualifiedType())
+ : QualType();
// FIXME: Do we need to check for default arguments here?
- if (Func->getNumParams() == 1 && InitialParamType == Argument) {
- if(AddMallocAttr && !Func->hasAttr<MallocAttr>())
- Func->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
+ if (InitialParam1Type == Param1 &&
+ (NumParams == 1 || InitialParam2Type == Param2)) {
+ if (AddMallocAttr && !Func->hasAttr<MallocAttr>())
+ Func->addAttr(::new (Context) MallocAttr(SourceLocation(),
+ Context));
+ // 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);
return;
}
}
@@ -1950,7 +2064,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
EST_BasicNoexcept : EST_DynamicNone;
}
- QualType FnType = Context.getFunctionType(Return, Argument, EPI);
+ QualType Params[] = { Param1, Param2 };
+
+ QualType FnType = Context.getFunctionType(
+ Return, ArrayRef<QualType>(Params, NumParams), EPI);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
@@ -1960,11 +2077,13 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
if (AddMallocAttr)
Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
- ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- SourceLocation(), 0,
- Argument, /*TInfo=*/0,
- SC_None, 0);
- Alloc->setParams(Param);
+ ParmVarDecl *ParamDecls[2];
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
+ SourceLocation(), 0,
+ Params[I], /*TInfo=*/0,
+ SC_None, 0);
+ Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams));
// FIXME: Also add this declaration to the IdentifierResolver, but
// make sure it is at the end of the chain to coincide with the
@@ -1972,6 +2091,48 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Context.getTranslationUnitDecl()->addDecl(Alloc);
}
+FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
+ bool CanProvideSize,
+ DeclarationName Name) {
+ DeclareGlobalNewDelete();
+
+ LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName);
+ LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
+
+ // C++ [expr.new]p20:
+ // [...] Any non-placement deallocation function matches a
+ // non-placement allocation function. [...]
+ llvm::SmallVector<FunctionDecl*, 2> Matches;
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*D))
+ if (isNonPlacementDeallocationFunction(*this, Fn))
+ Matches.push_back(Fn);
+ }
+
+ // C++1y [expr.delete]p?:
+ // If the type is complete and deallocation function lookup finds both a
+ // usual deallocation function with only a pointer parameter and a usual
+ // deallocation function with both a pointer parameter and a size
+ // parameter, then the selected deallocation function shall be the one
+ // with two parameters. Otherwise, the selected deallocation function
+ // shall be the function with one parameter.
+ if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+ unsigned NumArgs = CanProvideSize ? 2 : 1;
+ if (Matches[0]->getNumParams() != NumArgs)
+ Matches.erase(Matches.begin());
+ else
+ Matches.erase(Matches.begin() + 1);
+ assert(Matches[0]->getNumParams() == NumArgs &&
+ "found an unexpected uusal deallocation function");
+ }
+
+ assert(Matches.size() == 1 &&
+ "unexpectedly have multiple usual deallocation functions");
+ return Matches.front();
+}
+
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
FunctionDecl* &Operator, bool Diagnose) {
@@ -2045,19 +2206,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
return true;
}
- // Look for a global declaration.
- DeclareGlobalNewDelete();
- DeclContext *TUDecl = Context.getTranslationUnitDecl();
-
- CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation());
- Expr* DeallocArgs[1];
- DeallocArgs[0] = &Null;
- if (FindAllocationOverload(StartLoc, SourceRange(), Name,
- DeallocArgs, 1, TUDecl, !Diagnose,
- Operator, Diagnose))
- return true;
-
- assert(Operator && "Did not find a deallocation function!");
+ Operator = 0;
return false;
}
@@ -2070,7 +2219,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
bool ArrayForm, Expr *ExE) {
// C++ [expr.delete]p1:
// The operand shall have a pointer type, or a class type having a single
- // conversion function to a pointer type. The result has type void.
+ // non-explicit conversion function to a pointer type. The result has type
+ // void.
//
// DR599 amends "pointer type" to "pointer to object type" in both cases.
@@ -2087,59 +2237,65 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Type = Ex.get()->getType();
- if (const RecordType *Record = Type->getAs<RecordType>()) {
- if (RequireCompleteType(StartLoc, Type,
- diag::err_delete_incomplete_class_type))
- return ExprError();
+ class DeleteConverter : public ContextualImplicitConverter {
+ public:
+ DeleteConverter() : ContextualImplicitConverter(false, true) {}
- SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
+ bool match(QualType ConvType) {
+ // FIXME: If we have an operator T* and an operator void*, we must pick
+ // the operator T*.
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType())
+ return true;
+ return false;
+ }
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- std::pair<CXXRecordDecl::conversion_iterator,
- CXXRecordDecl::conversion_iterator>
- Conversions = RD->getVisibleConversionFunctions();
- for (CXXRecordDecl::conversion_iterator
- I = Conversions.first, E = Conversions.second; I != E; ++I) {
- NamedDecl *D = I.getDecl();
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_delete_operand) << T;
+ }
- // Skip over templated conversion functions; they aren't considered.
- if (isa<FunctionTemplateDecl>(D))
- continue;
+ SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
+ }
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
+ SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
+ QualType T, QualType ConvTy) {
+ return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
+ }
- QualType ConvType = Conv->getConversionType().getNonReferenceType();
- if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
- if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType())
- ObjectPtrConversions.push_back(Conv);
+ SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_delete_conversion)
+ << ConvTy;
}
- if (ObjectPtrConversions.size() == 1) {
- // We have a single conversion to a pointer-to-object type. Perform
- // that conversion.
- // TODO: don't redo the conversion calculation.
- ExprResult Res =
- PerformImplicitConversion(Ex.get(),
- ObjectPtrConversions.front()->getConversionType(),
- AA_Converting);
- if (Res.isUsable()) {
- Ex = Res;
- Type = Ex.get()->getType();
- }
+
+ SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T;
}
- else if (ObjectPtrConversions.size() > 1) {
- Diag(StartLoc, diag::err_ambiguous_delete_operand)
- << Type << Ex.get()->getSourceRange();
- for (unsigned i= 0; i < ObjectPtrConversions.size(); i++)
- NoteOverloadCandidate(ObjectPtrConversions[i]);
- return ExprError();
+
+ SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_delete_conversion)
+ << ConvTy;
}
- }
- if (!Type->isPointerType())
- return ExprError(Diag(StartLoc, diag::err_delete_operand)
- << Type << Ex.get()->getSourceRange());
+ SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+ QualType T, QualType ConvTy) {
+ llvm_unreachable("conversion functions are permitted");
+ }
+ } Converter;
+
+ Ex = PerformContextualImplicitConversion(StartLoc, Ex.take(), Converter);
+ if (Ex.isInvalid())
+ return ExprError();
+ Type = Ex.get()->getType();
+ if (!Converter.match(Type))
+ // FIXME: PerformContextualImplicitConversion should return ExprError
+ // itself in this case.
+ return ExprError();
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
@@ -2200,7 +2356,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// Otherwise, the usual operator delete[] should be the
// function we just found.
- else if (isa<CXXMethodDecl>(OperatorDelete))
+ else if (OperatorDelete && isa<CXXMethodDecl>(OperatorDelete))
UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
@@ -2238,19 +2394,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
- if (!OperatorDelete) {
+ if (!OperatorDelete)
// Look for a global declaration.
- DeclareGlobalNewDelete();
- DeclContext *TUDecl = Context.getTranslationUnitDecl();
- Expr *Arg = Ex.get();
- if (!Context.hasSameType(Arg->getType(), Context.VoidPtrTy))
- Arg = ImplicitCastExpr::Create(Context, Context.VoidPtrTy,
- CK_BitCast, Arg, 0, VK_RValue);
- if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
- &Arg, 1, TUDecl, /*AllowMissing=*/false,
- OperatorDelete))
- return ExprError();
- }
+ OperatorDelete = FindUsualDeallocationFunction(
+ StartLoc, !RequireCompleteType(StartLoc, Pointee, 0) &&
+ (!ArrayForm || UsualArrayDeleteWantsSize ||
+ Pointee.isDestructedType()),
+ DeleteName);
MarkFunctionReferenced(StartLoc, OperatorDelete);
@@ -2261,7 +2411,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
PDiag(diag::err_access_dtor) << PointeeElem);
}
}
-
}
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
@@ -2377,6 +2526,10 @@ static ExprResult BuildCXXCastArgument(Sema &S,
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method);
SmallVector<Expr*, 8> ConstructorArgs;
+ if (S.RequireNonAbstractType(CastLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs))
return ExprError();
@@ -2462,7 +2615,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType();
}
}
- // Watch out for elipsis conversion.
+ // Watch out for ellipsis conversion.
if (!ICS.UserDefined.EllipsisConversion) {
ExprResult Res =
PerformImplicitConversion(From, BeforeToType,
@@ -2566,6 +2719,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
FromType = From->getType();
}
+ // If we're converting to an atomic type, first convert to the corresponding
+ // non-atomic type.
+ QualType ToAtomicType;
+ if (const AtomicType *ToAtomic = ToType->getAs<AtomicType>()) {
+ ToAtomicType = ToType;
+ ToType = ToAtomic->getValueType();
+ }
+
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -2715,7 +2876,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
(void) PrepareCastToObjCObjectPointer(E);
From = E.take();
}
-
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), ToType, From, CCK);
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
.take();
break;
@@ -2875,7 +3037,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
<< ToType.getNonReferenceType();
break;
- }
+ }
default:
llvm_unreachable("Improper third standard conversion");
@@ -2883,11 +3045,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// If this conversion sequence involved a scalar -> atomic conversion, perform
// that conversion now.
- if (const AtomicType *ToAtomic = ToType->getAs<AtomicType>())
- if (Context.hasSameType(ToAtomic->getValueType(), From->getType()))
- From = ImpCastExprToType(From, ToType, CK_NonAtomicToAtomic, VK_RValue, 0,
- CCK).take();
-
+ if (!ToAtomicType.isNull()) {
+ assert(Context.hasSameType(
+ ToAtomicType->castAs<AtomicType>()->getValueType(), From->getType()));
+ From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic,
+ VK_RValue, 0, CCK).take();
+ }
+
return Owned(From);
}
@@ -2979,6 +3143,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// These traits require a complete type.
case UTT_IsFinal:
+ case UTT_IsSealed:
// These trait expressions are designed to help implement predicates in
// [meta.unary.prop] despite not being named the same. They are specified
@@ -3152,6 +3317,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->hasAttr<FinalAttr>();
return false;
+ case UTT_IsSealed:
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (FinalAttr *FA = RD->getAttr<FinalAttr>())
+ return FA->isSpelledAsSealed();
+ return false;
case UTT_IsSigned:
return T->isSignedIntegerType();
case UTT_IsUnsigned:
@@ -3444,8 +3614,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
// is_trivially_constructible is defined as:
//
// is_constructible<T, Args...>::value is true and the variable
- // definition for is_constructible, as defined below, is known to call no
- // operation that is not trivial.
+ // definition for is_constructible, as defined below, is known to call
+ // no operation that is not trivial.
//
// The predicate condition for a template specialization
// is_constructible<T, Args...> shall be satisfied if and only if the
@@ -3458,24 +3628,24 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
<< 1 << 1 << 1 << (int)Args.size();
return false;
}
-
- bool SawVoid = false;
+
+ // Precondition: T and all types in the parameter pack Args shall be
+ // complete types, (possibly cv-qualified) void, or arrays of
+ // unknown bound.
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
- if (Args[I]->getType()->isVoidType()) {
- SawVoid = true;
+ QualType ArgTy = Args[I]->getType();
+ if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
continue;
- }
-
- if (!Args[I]->getType()->isIncompleteType() &&
- S.RequireCompleteType(KWLoc, Args[I]->getType(),
+
+ if (S.RequireCompleteType(KWLoc, ArgTy,
diag::err_incomplete_type_used_in_type_trait_expr))
return false;
}
-
- // If any argument was 'void', of course it won't type-check.
- if (SawVoid)
+
+ // Make sure the first argument is a complete type.
+ if (Args[0]->getType()->isIncompleteType())
return false;
-
+
SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
@@ -4259,8 +4429,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// ... and one of the following shall hold:
// -- The second or the third operand (but not both) is a throw-
// expression; the result is of the type of the other and is a prvalue.
- bool LThrow = isa<CXXThrowExpr>(LHS.get());
- bool RThrow = isa<CXXThrowExpr>(RHS.get());
+ bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenCasts());
+ bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenCasts());
if (LThrow && !RThrow)
return RTy;
if (RThrow && !LThrow)
@@ -4991,6 +5161,32 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return Owned(E);
}
+/// Note a set of 'operator->' functions that were used for a member access.
+static void noteOperatorArrows(Sema &S,
+ llvm::ArrayRef<FunctionDecl *> OperatorArrows) {
+ unsigned SkipStart = OperatorArrows.size(), SkipCount = 0;
+ // FIXME: Make this configurable?
+ unsigned Limit = 9;
+ if (OperatorArrows.size() > Limit) {
+ // Produce Limit-1 normal notes and one 'skipping' note.
+ SkipStart = (Limit - 1) / 2 + (Limit - 1) % 2;
+ SkipCount = OperatorArrows.size() - (Limit - 1);
+ }
+
+ for (unsigned I = 0; I < OperatorArrows.size(); /**/) {
+ if (I == SkipStart) {
+ S.Diag(OperatorArrows[I]->getLocation(),
+ diag::note_operator_arrows_suppressed)
+ << SkipCount;
+ I += SkipCount;
+ } else {
+ S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrow_here)
+ << OperatorArrows[I]->getCallResultType();
+ ++I;
+ }
+ }
+}
+
ExprResult
Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind, ParsedType &ObjectType,
@@ -5023,29 +5219,68 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
// [...] When operator->returns, the operator-> is applied to the value
// returned, with the original second operand.
if (OpKind == tok::arrow) {
+ QualType StartingType = BaseType;
+ bool NoArrowOperatorFound = false;
+ bool FirstIteration = true;
+ FunctionDecl *CurFD = dyn_cast<FunctionDecl>(CurContext);
// The set of types we've considered so far.
llvm::SmallPtrSet<CanQualType,8> CTypes;
- SmallVector<SourceLocation, 8> Locations;
+ SmallVector<FunctionDecl*, 8> OperatorArrows;
CTypes.insert(Context.getCanonicalType(BaseType));
while (BaseType->isRecordType()) {
- Result = BuildOverloadedArrowExpr(S, Base, OpLoc);
- if (Result.isInvalid())
+ if (OperatorArrows.size() >= getLangOpts().ArrowDepth) {
+ Diag(OpLoc, diag::err_operator_arrow_depth_exceeded)
+ << StartingType << getLangOpts().ArrowDepth << Base->getSourceRange();
+ noteOperatorArrows(*this, OperatorArrows);
+ Diag(OpLoc, diag::note_operator_arrow_depth)
+ << getLangOpts().ArrowDepth;
+ return ExprError();
+ }
+
+ Result = BuildOverloadedArrowExpr(
+ S, Base, OpLoc,
+ // When in a template specialization and on the first loop iteration,
+ // potentially give the default diagnostic (with the fixit in a
+ // separate note) instead of having the error reported back to here
+ // and giving a diagnostic with a fixit attached to the error itself.
+ (FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization())
+ ? 0
+ : &NoArrowOperatorFound);
+ if (Result.isInvalid()) {
+ if (NoArrowOperatorFound) {
+ if (FirstIteration) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << 1 << Base->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ OpKind = tok::period;
+ break;
+ }
+ Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << Base->getSourceRange();
+ CallExpr *CE = dyn_cast<CallExpr>(Base);
+ if (Decl *CD = (CE ? CE->getCalleeDecl() : 0)) {
+ Diag(CD->getLocStart(),
+ diag::note_member_reference_arrow_from_operator_arrow);
+ }
+ }
return ExprError();
+ }
Base = Result.get();
if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(Base))
- Locations.push_back(OpCall->getDirectCallee()->getLocation());
+ OperatorArrows.push_back(OpCall->getDirectCallee());
BaseType = Base->getType();
CanQualType CBaseType = Context.getCanonicalType(BaseType);
if (!CTypes.insert(CBaseType)) {
- Diag(OpLoc, diag::err_operator_arrow_circular);
- for (unsigned i = 0; i < Locations.size(); i++)
- Diag(Locations[i], diag::note_declared_at);
+ Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType;
+ noteOperatorArrows(*this, OperatorArrows);
return ExprError();
}
+ FirstIteration = false;
}
- if (BaseType->isPointerType() || BaseType->isObjCObjectPointerType())
+ if (OpKind == tok::arrow &&
+ (BaseType->isPointerType() || BaseType->isObjCObjectPointerType()))
BaseType = BaseType->getPointeeType();
}
@@ -5555,7 +5790,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
if (Res.isInvalid())
return Owned(E);
E = Res.take();
- }
+ }
return Owned(E);
}
@@ -5579,15 +5814,144 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E);
}
+// If we can unambiguously determine whether Var can never be used
+// in a constant expression, return true.
+// - if the variable and its initializer are non-dependent, then
+// we can unambiguously check if the variable is a constant expression.
+// - if the initializer is not value dependent - we can determine whether
+// it can be used to initialize a constant expression. If Init can not
+// be used to initialize a constant expression we conclude that Var can
+// never be a constant expression.
+// - FXIME: if the initializer is dependent, we can still do some analysis and
+// identify certain cases unambiguously as non-const by using a Visitor:
+// - such as those that involve odr-use of a ParmVarDecl, involve a new
+// delete, lambda-expr, dynamic-cast, reinterpret-cast etc...
+static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
+ ASTContext &Context) {
+ if (isa<ParmVarDecl>(Var)) return true;
+ const VarDecl *DefVD = 0;
+
+ // If there is no initializer - this can not be a constant expression.
+ if (!Var->getAnyInitializer(DefVD)) return true;
+ assert(DefVD);
+ if (DefVD->isWeak()) return false;
+ EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
+
+ Expr *Init = cast<Expr>(Eval->Value);
+
+ if (Var->getType()->isDependentType() || Init->isValueDependent()) {
+ if (!Init->isValueDependent())
+ return !DefVD->checkInitIsICE();
+ // FIXME: We might still be able to do some analysis of Init here
+ // to conclude that even in a dependent setting, Init can never
+ // be a constexpr - but for now admit agnosticity.
+ return false;
+ }
+ return !IsVariableAConstantExpression(Var, Context);
+}
+
+/// \brief Check if the current lambda scope has any potential captures, and
+/// whether they can be captured by any of the enclosing lambdas that are
+/// ready to capture. If there is a lambda that can capture a nested
+/// potential-capture, go ahead and do so. Also, check to see if any
+/// variables are uncaptureable or do not involve an odr-use so do not
+/// need to be captured.
+
+static void CheckLambdaCaptures(Expr *const FE,
+ LambdaScopeInfo *const CurrentLSI, Sema &S) {
+
+ assert(!S.isUnevaluatedContext());
+ assert(S.CurContext->isDependentContext());
+ const bool IsFullExprInstantiationDependent =
+ FE->isInstantiationDependent();
+ // All the potentially captureable variables in the current nested
+ // lambda (within a generic outer lambda), must be captured by an
+ // outer lambda that is enclosed within a non-dependent context.
+
+ for (size_t I = 0, N = CurrentLSI->getNumPotentialVariableCaptures();
+ I != N; ++I) {
+ Expr *VarExpr = 0;
+ VarDecl *Var = 0;
+ CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
+ //
+ if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
+ !IsFullExprInstantiationDependent)
+ continue;
+ // Climb up until we find a lambda that can capture:
+ // - a generic-or-non-generic lambda call operator that is enclosed
+ // within a non-dependent context.
+ unsigned FunctionScopeIndexOfCapturableLambda = 0;
+ if (GetInnermostEnclosingCapturableLambda(
+ S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
+ S.CurContext, Var, S)) {
+ MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(),
+ S, &FunctionScopeIndexOfCapturableLambda);
+ }
+ const bool IsVarNeverAConstantExpression =
+ VariableCanNeverBeAConstantExpression(Var, S.Context);
+ if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
+ // This full expression is not instantiation dependent or the variable
+ // can not be used in a constant expression - which means
+ // this variable must be odr-used here, so diagnose a
+ // capture violation early, if the variable is un-captureable.
+ // This is purely for diagnosing errors early. Otherwise, this
+ // error would get diagnosed when the lambda becomes capture ready.
+ QualType CaptureType, DeclRefType;
+ SourceLocation ExprLoc = VarExpr->getExprLoc();
+ if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/false, CaptureType,
+ DeclRefType, 0)) {
+ // We will never be able to capture this variable, and we need
+ // to be able to in any and all instantiations, so diagnose it.
+ S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/true, CaptureType,
+ DeclRefType, 0);
+ }
+ }
+ }
+
+ if (CurrentLSI->hasPotentialThisCapture()) {
+ unsigned FunctionScopeIndexOfCapturableLambda = 0;
+ if (GetInnermostEnclosingCapturableLambda(
+ S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
+ S.CurContext, /*0 is 'this'*/ 0, S)) {
+ S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
+ /*Explicit*/false, /*BuildAndDiagnose*/true,
+ &FunctionScopeIndexOfCapturableLambda);
+ }
+ }
+ CurrentLSI->clearPotentialCaptures();
+}
+
+
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
- bool IsConstexpr) {
+ bool IsConstexpr,
+ bool IsLambdaInitCaptureInitializer) {
ExprResult FullExpr = Owned(FE);
if (!FullExpr.get())
return ExprError();
-
- if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+
+ // If we are an init-expression in a lambdas init-capture, we should not
+ // diagnose an unexpanded pack now (will be diagnosed once lambda-expr
+ // containing full-expression is done).
+ // template<class ... Ts> void test(Ts ... t) {
+ // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
+ // return a;
+ // }() ...);
+ // }
+ // FIXME: This is a hack. It would be better if we pushed the lambda scope
+ // when we parse the lambda introducer, and teach capturing (but not
+ // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a
+ // corresponding class yet (that is, have LambdaScopeInfo either represent a
+ // lambda where we've entered the introducer but not the body, or represent a
+ // lambda where we've entered the body, depending on where the
+ // parser/instantiation has got to).
+ if (!IsLambdaInitCaptureInitializer &&
+ DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
// Top-level expressions default to 'id' when we're in a debugger.
@@ -5609,6 +5973,56 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
}
CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
+
+ // At the end of this full expression (which could be a deeply nested
+ // lambda), if there is a potential capture within the nested lambda,
+ // have the outer capture-able lambda try and capture it.
+ // Consider the following code:
+ // void f(int, int);
+ // void f(const int&, double);
+ // void foo() {
+ // const int x = 10, y = 20;
+ // auto L = [=](auto a) {
+ // auto M = [=](auto b) {
+ // f(x, b); <-- requires x to be captured by L and M
+ // f(y, a); <-- requires y to be captured by L, but not all Ms
+ // };
+ // };
+ // }
+
+ // FIXME: Also consider what happens for something like this that involves
+ // the gnu-extension statement-expressions or even lambda-init-captures:
+ // void f() {
+ // const int n = 0;
+ // auto L = [&](auto a) {
+ // +n + ({ 0; a; });
+ // };
+ // }
+ //
+ // Here, we see +n, and then the full-expression 0; ends, so we don't
+ // capture n (and instead remove it from our list of potential captures),
+ // and then the full-expression +n + ({ 0; }); ends, but it's too late
+ // for us to see that we need to capture n after all.
+
+ LambdaScopeInfo *const CurrentLSI = getCurLambda();
+ // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer
+ // even if CurContext is not a lambda call operator. Refer to that Bug Report
+ // for an example of the code that might cause this asynchrony.
+ // By ensuring we are in the context of a lambda's call operator
+ // we can fix the bug (we only need to check whether we need to capture
+ // if we are within a lambda's body); but per the comments in that
+ // PR, a proper fix would entail :
+ // "Alternative suggestion:
+ // - Add to Sema an integer holding the smallest (outermost) scope
+ // index that we are *lexically* within, and save/restore/set to
+ // FunctionScopes.size() in InstantiatingTemplate's
+ // constructor/destructor.
+ // - Teach the handful of places that iterate over FunctionScopes to
+ // stop at the outermost enclosing lexical scope."
+ const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
+ if (IsInLambdaDeclContext && CurrentLSI &&
+ CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid())
+ CheckLambdaCaptures(FE, CurrentLSI, *this);
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 545ac2746d6d..f6accb15bf98 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -538,13 +539,42 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
namespace {
// Callback to only accept typo corrections that are either a ValueDecl or a
-// FunctionTemplateDecl.
+// FunctionTemplateDecl and are declared in the current record or, for a C++
+// classes, one of its base classes.
class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
public:
+ explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
+ : Record(RTy->getDecl()) {}
+
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
NamedDecl *ND = candidate.getCorrectionDecl();
- return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
+ // Don't accept candidates that cannot be member functions, constants,
+ // variables, or templates.
+ if (!ND || !(isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)))
+ return false;
+
+ // Accept candidates that occur in the current record.
+ if (Record->containsDecl(ND))
+ return true;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) {
+ // Accept candidates that occur in any of the current class' base classes.
+ for (CXXRecordDecl::base_class_const_iterator BS = RD->bases_begin(),
+ BSEnd = RD->bases_end();
+ BS != BSEnd; ++BS) {
+ if (const RecordType *BSTy = dyn_cast_or_null<RecordType>(
+ BS->getType().getTypePtrOrNull())) {
+ if (BSTy->getDecl()->containsDecl(ND))
+ return true;
+ }
+ }
+ }
+
+ return false;
}
+
+ private:
+ const RecordDecl *const Record;
};
}
@@ -600,24 +630,31 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
- RecordMemberExprValidatorCCC Validator;
+ RecordMemberExprValidatorCCC Validator(RTy);
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
&SS, Validator, DC);
R.clear();
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
- std::string CorrectedStr(
- Corrected.getAsString(SemaRef.getLangOpts()));
- std::string CorrectedQuotedStr(
- Corrected.getQuoted(SemaRef.getLangOpts()));
+ if (Corrected.isResolved() && !Corrected.isKeyword()) {
R.setLookupName(Corrected.getCorrection());
- R.addDecl(ND);
- SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ for (TypoCorrection::decl_iterator DI = Corrected.begin(),
+ DIEnd = Corrected.end();
+ DI != DIEnd; ++DI) {
+ R.addDecl(*DI);
+ }
+ R.resolveKind();
+
+ // If we're typo-correcting to an overloaded name, we don't yet have enough
+ // information to do overload resolution, so we don't know which previous
+ // declaration to point to.
+ if (Corrected.isOverloaded())
+ Corrected.setCorrectionDecl(0);
+ bool DroppedSpecifier =
+ Corrected.WillReplaceSpecifier() &&
+ Name.getAsString() == Corrected.getAsString(SemaRef.getLangOpts());
+ SemaRef.diagnoseTypo(Corrected,
+ SemaRef.PDiag(diag::err_no_member_suggest)
+ << Name << DC << DroppedSpecifier << SS.getRange());
}
return false;
@@ -687,6 +724,7 @@ ExprResult
Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation loc,
IndirectFieldDecl *indirectField,
+ DeclAccessPair foundDecl,
Expr *baseObjectExpr,
SourceLocation opLoc) {
// First, build the expression that refers to the base object.
@@ -764,15 +802,15 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
if (!baseVariable) {
FieldDecl *field = cast<FieldDecl>(*FI);
- // FIXME: use the real found-decl info!
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
// Make a nameInfo that properly uses the anonymous name.
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
EmptySS, field, foundDecl,
memberNameInfo).take();
+ if (!result)
+ return ExprError();
+
baseObjectIsPointer = false;
// FIXME: check qualified member access
@@ -783,14 +821,15 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
while (FI != FEnd) {
FieldDecl *field = cast<FieldDecl>(*FI++);
-
+
// FIXME: these are somewhat meaningless
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
+ DeclAccessPair fakeFoundDecl =
+ DeclAccessPair::make(field, field->getAccess());
+
result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- foundDecl, memberNameInfo).take();
+ (FI == FEnd? SS : EmptySS), field,
+ fakeFoundDecl, memberNameInfo).take();
}
return Owned(result);
@@ -845,7 +884,54 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
R.setBaseObjectType(BaseType);
-
+
+ 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();
@@ -974,7 +1060,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
- BaseExpr, OpLoc);
+ FoundDecl, BaseExpr,
+ OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
@@ -1117,10 +1204,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// foo->bar
// This is actually well-formed in C++ if MyRecord has an
// overloaded operator->, but that should have been dealt with
- // by now.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
+ // by now--or a diagnostic message already issued if a problem
+ // was encountered while looking for the overloaded operator->.
+ if (!getLangOpts().CPlusPlus) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ }
IsArrow = false;
} else if (BaseType->isFunctionType()) {
goto fail;
@@ -1190,14 +1280,10 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
LookupMemberName, NULL, NULL,
Validator, IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
- Diag(R.getNameLoc(),
- diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName << IV->getDeclName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
- Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
-
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName);
+
// Figure out the class that declares the ivar.
assert(!ClassDeclared);
Decl *D = cast<Decl>(IV->getDeclContext());
@@ -1297,7 +1383,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
MemberLoc);
if (Level != DiagnosticsEngine::Ignored)
- getCurFunction()->recordUseOfWeak(Result);
+ recordUseOfEvaluatedWeak(Result);
}
}
@@ -1348,8 +1434,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ Member);
ObjCMethodDecl *SMD = 0;
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
@@ -1396,8 +1483,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// If we found a getter then this may be a valid dot-reference, we
// will look for the matching setter, in case it is needed.
Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ Member);
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
@@ -1670,7 +1758,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// (C++ [class.union]).
// FIXME: template-ids inside anonymous structs?
if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
- return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
+ return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD,
+ R.begin().getPair());
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cf77896cb8c3..cc8eacee6103 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -266,7 +266,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
break;
case CharacterLiteral::Wide:
- NumberType = Context.getWCharType();
+ NumberType = Context.getWideCharType();
break;
case CharacterLiteral::UTF16:
@@ -324,7 +324,8 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc,
/// \brief Check that the given expression is a valid element of an Objective-C
/// collection literal.
static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
- QualType T) {
+ QualType T,
+ bool ArrayLiteral = false) {
// If the expression is type-dependent, there's nothing for us to do.
if (Element->isTypeDependent())
return Element;
@@ -401,14 +402,34 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
Recovered = true;
}
}
-
+
if (!Recovered) {
S.Diag(Element->getLocStart(), diag::err_invalid_collection_element)
<< Element->getType();
return ExprError();
}
}
-
+ if (ArrayLiteral)
+ if (ObjCStringLiteral *getString =
+ dyn_cast<ObjCStringLiteral>(OrigElement)) {
+ if (StringLiteral *SL = getString->getString()) {
+ unsigned numConcat = SL->getNumConcatenated();
+ if (numConcat > 1) {
+ // Only warn if the concatenated string doesn't come from a macro.
+ bool hasMacro = false;
+ for (unsigned i = 0; i < numConcat ; ++i)
+ if (SL->getStrTokenLoc(i).isMacroID()) {
+ hasMacro = true;
+ break;
+ }
+ if (!hasMacro)
+ S.Diag(Element->getLocStart(),
+ diag::warn_concatenated_nsarray_literal)
+ << Element->getType();
+ }
+ }
+ }
+
// Make sure that the element has the type that the container factory
// function expects.
return S.PerformCopyInitialization(
@@ -521,7 +542,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
break;
case CharacterLiteral::Wide:
- ValueType = Context.getWCharType();
+ ValueType = Context.getWideCharType();
break;
case CharacterLiteral::UTF16:
@@ -581,7 +602,7 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
Expr *IndexExpr,
ObjCMethodDecl *getterMethod,
ObjCMethodDecl *setterMethod) {
- assert(!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic());
+ assert(!LangOpts.isSubscriptPointerArithmetic());
// We can't get dependent types here; our callers should have
// filtered them out.
@@ -710,7 +731,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
ElementsBuffer[I],
- RequiredType);
+ RequiredType, true);
if (Converted.isInvalid())
return ExprError();
@@ -902,14 +923,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
QualType Ty
= Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(NSDictionaryDecl));
- return MaybeBindToTemporary(
- ObjCDictionaryLiteral::Create(Context,
- llvm::makeArrayRef(Elements,
- NumElements),
- HasPackExpansions,
- Ty,
- DictionaryWithObjectsMethod, SR));
+ Context.getObjCInterfaceType(NSDictionaryDecl));
+ return MaybeBindToTemporary(ObjCDictionaryLiteral::Create(
+ Context, makeArrayRef(Elements, NumElements), HasPackExpansions, Ty,
+ DictionaryWithObjectsMethod, SR));
}
ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
@@ -968,8 +985,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
- if (!Method)
- Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
+ if (!Method) {
+ if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) {
+ Selector MatchedSel = OM->getSelector();
+ SourceRange SelectorRange(LParenLoc.getLocWithOffset(1),
+ RParenLoc.getLocWithOffset(-1));
+ Diag(SelLoc, diag::warn_undeclared_selector_with_typo)
+ << Sel << MatchedSel
+ << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
+
+ } else
+ Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
+ }
if (!Method ||
Method->getImplementationControl() != ObjCMethodDecl::Optional) {
@@ -1184,8 +1211,8 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
}
bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
- Expr **Args, unsigned NumArgs,
- Selector Sel,
+ MultiExprArg Args,
+ Selector Sel,
ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage,
@@ -1199,7 +1226,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (!Method) {
// Apply default argument promotion as for (C99 6.5.2.2p6).
- for (unsigned i = 0; i != NumArgs; i++) {
+ for (unsigned i = 0, e = Args.size(); i != e; i++) {
if (Args[i]->isTypeDependent())
continue;
@@ -1221,10 +1248,31 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
else
DiagID = isClassMessage ? diag::warn_class_method_not_found
: diag::warn_inst_method_not_found;
- if (!getLangOpts().DebuggerSupport)
- Diag(SelLoc, DiagID)
- << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
+ if (!getLangOpts().DebuggerSupport) {
+ const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType);
+ if (OMD && !OMD->isInvalidDecl()) {
+ if (getLangOpts().ObjCAutoRefCount)
+ DiagID = diag::error_method_not_found_with_typo;
+ else
+ DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo
+ : diag::warn_instance_method_not_found_with_typo;
+ Selector MatchedSel = OMD->getSelector();
+ SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back());
+ Diag(SelLoc, DiagID)
+ << Sel<< isClassMessage << MatchedSel
+ << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
+ }
+ else
+ Diag(SelLoc, DiagID)
+ << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
SelectorLocs.back());
+ // Find the class to which we are sending this message.
+ if (ReceiverType->isObjCObjectPointerType()) {
+ if (ObjCInterfaceDecl *Class =
+ ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl())
+ Diag(Class->getLocation(), diag::note_receiver_class_declared);
+ }
+ }
// In debuggers, we want to use __unknown_anytype for these
// results so that clients can cast them.
@@ -1247,9 +1295,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (Method->param_size() > Sel.getNumArgs())
NumNamedArgs = Method->param_size();
// FIXME. This need be cleaned up.
- if (NumArgs < NumNamedArgs) {
+ if (Args.size() < NumNamedArgs) {
Diag(SelLoc, diag::err_typecheck_call_too_few_args)
- << 2 << NumNamedArgs << NumArgs;
+ << 2 << NumNamedArgs << static_cast<unsigned>(Args.size());
return false;
}
@@ -1302,7 +1350,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
// Promote additional arguments to variadic methods.
if (Method->isVariadic()) {
- for (unsigned i = NumNamedArgs; i < NumArgs; ++i) {
+ for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
if (Args[i]->isTypeDependent())
continue;
@@ -1313,21 +1361,21 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
}
} else {
// Check for extra arguments to non-variadic methods.
- if (NumArgs != NumNamedArgs) {
+ if (Args.size() != NumNamedArgs) {
Diag(Args[NumNamedArgs]->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 2 /*method*/ << NumNamedArgs << NumArgs
+ << 2 /*method*/ << NumNamedArgs << static_cast<unsigned>(Args.size())
<< Method->getSourceRange()
<< SourceRange(Args[NumNamedArgs]->getLocStart(),
- Args[NumArgs-1]->getLocEnd());
+ Args.back()->getLocEnd());
}
}
- DiagnoseSentinelCalls(Method, SelLoc, Args, NumArgs);
+ DiagnoseSentinelCalls(Method, SelLoc, Args);
// Do additional checkings on method.
- IsError |= CheckObjCMethodCall(Method, SelLoc,
- llvm::makeArrayRef<const Expr *>(Args, NumArgs));
+ IsError |= CheckObjCMethodCall(
+ Method, SelLoc, makeArrayRef<const Expr *>(Args.data(), Args.size()));
return IsError;
}
@@ -1534,8 +1582,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// If we found a getter then this may be a valid dot-reference, we
// will look for the matching setter, in case it is needed.
Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
// May be founf in property's qualified list.
@@ -1569,16 +1617,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Attempt to correct for typos in property names.
DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
- NULL, Validator, IFace, false, OPT)) {
- ObjCPropertyDecl *Property =
- Corrected.getCorrectionDeclAs<ObjCPropertyDecl>();
+ DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
+ NULL, Validator, IFace, false, OPT)) {
+ diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
+ << MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
- Diag(MemberLoc, diag::err_property_not_found_suggest)
- << MemberName << QualType(OPT, 0) << TypoResult
- << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
- Diag(Property->getLocation(), diag::note_previous_decl)
- << Property->getDeclName();
return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
TypoResult, MemberLoc,
SuperLoc, SuperType, Super);
@@ -1681,8 +1724,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
// Look for the matching setter, in case it is needed.
Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), &propertyName);
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ &propertyName);
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
@@ -1809,34 +1853,28 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
}
ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
- if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
- Result.getLookupKind(), S, NULL,
- Validator)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
+ NULL, Validator, NULL, false, NULL, false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
- Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected.getCorrection()
- << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_unknown_receiver_suggest) << Name);
return ObjCSuperMessage;
} else if (ObjCInterfaceDecl *Class =
- Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
+ Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// If we found a declaration, correct when it refers to an Objective-C
// class.
- Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected.getCorrection()
- << FixItHint::CreateReplacement(SourceRange(NameLoc),
- Class->getNameAsString());
- Diag(Class->getLocation(), diag::note_previous_decl)
- << Corrected.getCorrection();
-
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_unknown_receiver_suggest) << Name);
QualType T = Context.getObjCInterfaceType(Class);
TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
ReceiverType = CreateParsedType(T, TSInfo);
return ObjCClassMessage;
}
}
-
+
// Fall back: let the parser try to parse it as an instance message.
return ObjCInstanceMessage;
}
@@ -2065,7 +2103,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, SelectorLocs,
+ if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
+ Sel, SelectorLocs,
Method, true,
SuperLoc.isValid(), LBracLoc, RBracLoc,
ReturnType, VK))
@@ -2246,6 +2285,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
ReceiverType = Receiver->getType();
} else if (getLangOpts().CPlusPlus) {
+ // The receiver must be a complete type.
+ if (RequireCompleteType(Loc, Receiver->getType(),
+ diag::err_incomplete_receiver_type))
+ return ExprError();
+
ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
if (result.isUsable()) {
Receiver = result.take();
@@ -2410,8 +2454,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ExprValueKind VK = VK_RValue;
bool ClassMessage = (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel,
- SelectorLocs, Method,
+ if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
+ Sel, SelectorLocs, Method,
ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
@@ -3121,9 +3165,112 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
<< castRange << castExpr->getSourceRange();
}
+static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) {
+ TypedefNameDecl *TDNDecl = TD->getDecl();
+ QualType QT = TDNDecl->getUnderlyingType();
+ if (QT->isPointerType()) {
+ QT = QT->getPointeeType();
+ if (const RecordType *RT = QT->getAs<RecordType>())
+ if (RecordDecl *RD = RT->getDecl())
+ if (RD->hasAttr<ObjCBridgeAttr>())
+ return RD->getAttr<ObjCBridgeAttr>();
+ }
+ return 0;
+}
+
+static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
+ QualType T = castExpr->getType();
+ while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ TypedefNameDecl *TDNDecl = TD->getDecl();
+ if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+ if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
+ NamedDecl *Target = 0;
+ // Check for an existing type with this name.
+ LookupResult R(S, DeclarationName(Parm), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(R, S.TUScope)) {
+ Target = R.getFoundDecl();
+ if (Target && isa<ObjCInterfaceDecl>(Target)) {
+ ObjCInterfaceDecl *ExprClass = cast<ObjCInterfaceDecl>(Target);
+ if (const ObjCObjectPointerType *InterfacePointerType =
+ castType->getAsObjCInterfacePointerType()) {
+ ObjCInterfaceDecl *CastClass
+ = InterfacePointerType->getObjectType()->getInterface();
+ if ((CastClass == ExprClass) || (CastClass && ExprClass->isSuperClassOf(CastClass)))
+ return true;
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
+ << T << Target->getName() << castType->getPointeeType();
+ return true;
+ } else {
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
+ << T << Target->getName() << castType;
+ return true;
+ }
+ }
+ }
+ S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface)
+ << castExpr->getType() << Parm->getName();
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
+ }
+ return true;
+ }
+ T = TDNDecl->getUnderlyingType();
+ }
+ return false;
+}
+
+// (CFErrorRef)ns
+static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) {
+ QualType T = castType;
+ while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ TypedefNameDecl *TDNDecl = TD->getDecl();
+ if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+ if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
+ NamedDecl *Target = 0;
+ // Check for an existing type with this name.
+ LookupResult R(S, DeclarationName(Parm), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(R, S.TUScope)) {
+ Target = R.getFoundDecl();
+ if (Target && isa<ObjCInterfaceDecl>(Target)) {
+ ObjCInterfaceDecl *CastClass = cast<ObjCInterfaceDecl>(Target);
+ if (const ObjCObjectPointerType *InterfacePointerType =
+ castExpr->getType()->getAsObjCInterfacePointerType()) {
+ ObjCInterfaceDecl *ExprClass
+ = InterfacePointerType->getObjectType()->getInterface();
+ if ((CastClass == ExprClass) || (ExprClass && CastClass->isSuperClassOf(ExprClass)))
+ return true;
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
+ << castExpr->getType()->getPointeeType() << T;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ return true;
+ } else {
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
+ << castExpr->getType() << castType;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ return true;
+ }
+ }
+ }
+ S.Diag(castExpr->getLocStart(), diag::err_objc_ns_bridged_invalid_cfobject)
+ << castExpr->getType() << castType;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
+ }
+ return true;
+ }
+ T = TDNDecl->getUnderlyingType();
+ }
+ return false;
+}
+
Sema::ARCConversionResult
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
- Expr *&castExpr, CheckedConversionKind CCK) {
+ Expr *&castExpr, CheckedConversionKind CCK,
+ bool DiagnoseCFAudited) {
QualType castExprType = castExpr->getType();
// For the purposes of the classification, we assume reference types
@@ -3177,6 +3324,17 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr &&
CCK != CCK_ImplicitConversion)
return ACR_okay;
+
+ if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation &&
+ (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
+ if (CheckObjCBridgeNSCast(*this, castType, castExpr))
+ return ACR_okay;
+
+ if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
+ (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
+ if (CheckObjCBridgeCFCast(*this, castType, castExpr))
+ return ACR_okay;
+
switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {
// For invalid casts, fall through.
@@ -3204,8 +3362,14 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
CCK != CCK_ImplicitConversion)
return ACR_unbridged;
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, castExpr, exprACTC, CCK);
+ // Do not issue "bridge cast" diagnostic when implicit casting
+ // a retainable object to a CF type parameter belonging to an audited
+ // CF API function. Let caller issue a normal type mismatched diagnostic
+ // instead.
+ if (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
+ castACTC != ACTC_coreFoundation)
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
+ castExpr, castExpr, exprACTC, CCK);
return ACR_okay;
}
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index 2a845ba9898b..32b56bcddc63 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -160,27 +160,33 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
return false;
}
-static bool isMacroDefined(const Sema &S, StringRef Name) {
- return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name));
+static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
+ const IdentifierInfo *II = &S.getASTContext().Idents.get(Name);
+ if (!II->hadMacroDefinition()) return false;
+
+ MacroDirective *Macro = S.PP.getMacroDirectiveHistory(II);
+ return Macro && Macro->findDirectiveAtLoc(Loc, S.getSourceManager());
}
-static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) {
+static std::string getScalarZeroExpressionForType(
+ const Type &T, SourceLocation Loc, const Sema &S) {
assert(T.isScalarType() && "use scalar types only");
// Suggest "0" for non-enumeration scalar types, unless we can find a
// better initializer.
if (T.isEnumeralType())
return std::string();
if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
- isMacroDefined(S, "nil"))
+ isMacroDefined(S, Loc, "nil"))
return "nil";
if (T.isRealFloatingType())
return "0.0";
- if (T.isBooleanType() && S.LangOpts.CPlusPlus)
+ if (T.isBooleanType() &&
+ (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false")))
return "false";
if (T.isPointerType() || T.isMemberPointerType()) {
if (S.LangOpts.CPlusPlus11)
return "nullptr";
- if (isMacroDefined(S, "NULL"))
+ if (isMacroDefined(S, Loc, "NULL"))
return "NULL";
}
if (T.isCharType())
@@ -194,9 +200,10 @@ static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S)
return "0";
}
-std::string Sema::getFixItZeroInitializerForType(QualType T) const {
+std::string
+Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
if (T->isScalarType()) {
- std::string s = getScalarZeroExpressionForType(*T, *this);
+ std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
if (!s.empty())
s = " = " + s;
return s;
@@ -212,6 +219,7 @@ std::string Sema::getFixItZeroInitializerForType(QualType T) const {
return std::string();
}
-std::string Sema::getFixItZeroLiteralForType(QualType T) const {
- return getScalarZeroExpressionForType(*T, *this);
+std::string
+Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
+ return getScalarZeroExpressionForType(*T, Loc, *this);
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 9e8936e17b8a..034c1b6c7184 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -32,53 +32,99 @@ using namespace clang;
// Sema Initialization Checking
//===----------------------------------------------------------------------===//
-static Expr *IsStringInit(Expr *Init, const ArrayType *AT,
- ASTContext &Context) {
+/// \brief Check whether T is compatible with a wide character type (wchar_t,
+/// char16_t or char32_t).
+static bool IsWideCharCompatible(QualType T, ASTContext &Context) {
+ if (Context.typesAreCompatible(Context.getWideCharType(), T))
+ return true;
+ if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) {
+ return Context.typesAreCompatible(Context.Char16Ty, T) ||
+ Context.typesAreCompatible(Context.Char32Ty, T);
+ }
+ return false;
+}
+
+enum StringInitFailureKind {
+ SIF_None,
+ SIF_NarrowStringIntoWideChar,
+ SIF_WideStringIntoChar,
+ SIF_IncompatWideStringIntoWideChar,
+ SIF_Other
+};
+
+/// \brief Check whether the array of type AT can be initialized by the Init
+/// expression by means of string initialization. Returns SIF_None if so,
+/// otherwise returns a StringInitFailureKind that describes why the
+/// initialization would not work.
+static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
+ ASTContext &Context) {
if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT))
- return 0;
+ return SIF_Other;
// See if this is a string literal or @encode.
Init = Init->IgnoreParens();
// Handle @encode, which is a narrow string.
if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType())
- return Init;
+ return SIF_None;
// Otherwise we can only handle string literals.
StringLiteral *SL = dyn_cast<StringLiteral>(Init);
- if (SL == 0) return 0;
+ if (SL == 0)
+ return SIF_Other;
- QualType ElemTy = Context.getCanonicalType(AT->getElementType());
+ const QualType ElemTy =
+ Context.getCanonicalType(AT->getElementType()).getUnqualifiedType();
switch (SL->getKind()) {
case StringLiteral::Ascii:
case StringLiteral::UTF8:
// char array can be initialized with a narrow string.
// Only allow char x[] = "foo"; not char x[] = L"foo";
- return ElemTy->isCharType() ? Init : 0;
+ if (ElemTy->isCharType())
+ return SIF_None;
+ if (IsWideCharCompatible(ElemTy, Context))
+ return SIF_NarrowStringIntoWideChar;
+ return SIF_Other;
+ // C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15:
+ // "An array with element type compatible with a qualified or unqualified
+ // version of wchar_t, char16_t, or char32_t may be initialized by a wide
+ // string literal with the corresponding encoding prefix (L, u, or U,
+ // respectively), optionally enclosed in braces.
case StringLiteral::UTF16:
- return ElemTy->isChar16Type() ? Init : 0;
+ if (Context.typesAreCompatible(Context.Char16Ty, ElemTy))
+ return SIF_None;
+ if (ElemTy->isCharType())
+ return SIF_WideStringIntoChar;
+ if (IsWideCharCompatible(ElemTy, Context))
+ return SIF_IncompatWideStringIntoWideChar;
+ return SIF_Other;
case StringLiteral::UTF32:
- return ElemTy->isChar32Type() ? Init : 0;
+ if (Context.typesAreCompatible(Context.Char32Ty, ElemTy))
+ return SIF_None;
+ if (ElemTy->isCharType())
+ return SIF_WideStringIntoChar;
+ if (IsWideCharCompatible(ElemTy, Context))
+ return SIF_IncompatWideStringIntoWideChar;
+ return SIF_Other;
case StringLiteral::Wide:
- // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with
- // correction from DR343): "An array with element type compatible with a
- // qualified or unqualified version of wchar_t may be initialized by a wide
- // string literal, optionally enclosed in braces."
- if (Context.typesAreCompatible(Context.getWCharType(),
- ElemTy.getUnqualifiedType()))
- return Init;
-
- return 0;
+ if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy))
+ return SIF_None;
+ if (ElemTy->isCharType())
+ return SIF_WideStringIntoChar;
+ if (IsWideCharCompatible(ElemTy, Context))
+ return SIF_IncompatWideStringIntoWideChar;
+ return SIF_Other;
}
llvm_unreachable("missed a StringLiteral kind?");
}
-static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) {
+static StringInitFailureKind IsStringInit(Expr *init, QualType declType,
+ ASTContext &Context) {
const ArrayType *arrayType = Context.getAsArrayType(declType);
- if (!arrayType) return 0;
-
+ if (!arrayType)
+ return SIF_Other;
return IsStringInit(init, arrayType, Context);
}
@@ -190,7 +236,6 @@ class InitListChecker {
Sema &SemaRef;
bool hadError;
bool VerifyOnly; // no diagnostics, no structure building
- bool AllowBraceElision;
llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
@@ -200,8 +245,7 @@ class InitListChecker {
unsigned &StructuredIndex);
void CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
- unsigned &Index, InitListExpr *StructuredList,
- unsigned &StructuredIndex,
+ InitListExpr *StructuredList,
bool TopLevelObject = false);
void CheckListElementTypes(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
@@ -281,8 +325,7 @@ class InitListChecker {
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool AllowBraceElision);
+ InitListExpr *IL, QualType &T, bool VerifyOnly);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
@@ -513,16 +556,13 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T,
- bool VerifyOnly, bool AllowBraceElision)
- : SemaRef(S), VerifyOnly(VerifyOnly), AllowBraceElision(AllowBraceElision) {
+ bool VerifyOnly)
+ : SemaRef(S), VerifyOnly(VerifyOnly) {
hadError = false;
- unsigned newIndex = 0;
- unsigned newStructuredIndex = 0;
- FullyStructuredList
- = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
- CheckExplicitInitList(Entity, IL, T, newIndex,
- FullyStructuredList, newStructuredIndex,
+ FullyStructuredList =
+ getStructuredSubobjectInit(IL, 0, T, 0, 0, IL->getSourceRange());
+ CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
if (!hadError && !VerifyOnly) {
@@ -559,6 +599,12 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
+/// 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.
+///
+/// This also fills in \p StructuredList, from element \p StructuredIndex
+/// onwards, with the fully-braced, desugared form of the initialization.
void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList,
QualType T, unsigned &Index,
@@ -599,10 +645,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
- if (VerifyOnly) {
- if (!AllowBraceElision && (T->isArrayType() || T->isRecordType()))
- hadError = true;
- } else {
+ if (!VerifyOnly) {
StructuredSubobjectInitList->setType(T);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -617,8 +660,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
// Complain about missing braces.
if (T->isArrayType() || T->isRecordType()) {
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
- AllowBraceElision ? diag::warn_missing_braces :
- diag::err_missing_braces)
+ diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
<< FixItHint::CreateInsertion(
StructuredSubobjectInitList->getLocStart(), "{")
@@ -626,23 +668,26 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
SemaRef.PP.getLocForEndOfToken(
StructuredSubobjectInitList->getLocEnd()),
"}");
- if (!AllowBraceElision)
- hadError = true;
}
}
}
+/// Check whether the initializer \p IList (that was written with explicit
+/// braces) can be used to initialize an object of type \p T.
+///
+/// This also fills in \p StructuredList with the fully-braced, desugared
+/// form of the initialization.
void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
- unsigned &Index,
InitListExpr *StructuredList,
- unsigned &StructuredIndex,
bool TopLevelObject) {
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
if (!VerifyOnly) {
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
}
+
+ unsigned Index = 0, StructuredIndex = 0;
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
if (!VerifyOnly) {
@@ -667,7 +712,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
}
if (StructuredIndex == 1 &&
- IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) {
+ IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
+ SIF_None) {
unsigned DK = diag::warn_excess_initializers_in_char_array_initializer;
if (SemaRef.getLangOpts().CPlusPlus) {
DK = diag::err_excess_initializers_in_char_array_initializer;
@@ -774,16 +820,19 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
Expr *expr = IList->getInit(Index);
+
+ if (ElemType->isReferenceType())
+ return CheckReferenceType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
+
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
if (!ElemType->isRecordType() || ElemType->isAggregateType()) {
- unsigned newIndex = 0;
- unsigned newStructuredIndex = 0;
- InitListExpr *newStructuredList
+ InitListExpr *InnerStructuredList
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
- CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
- newStructuredList, newStructuredIndex);
+ CheckExplicitInitList(Entity, SubInitList, ElemType,
+ InnerStructuredList);
++StructuredIndex;
++Index;
return;
@@ -793,23 +842,23 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// C++ initialization is handled later.
}
- if (ElemType->isScalarType()) {
+ // FIXME: Need to handle atomic aggregate types with implicit init lists.
+ if (ElemType->isScalarType() || ElemType->isAtomicType())
return CheckScalarType(Entity, IList, ElemType, Index,
StructuredList, StructuredIndex);
- } else if (ElemType->isReferenceType()) {
- return CheckReferenceType(Entity, IList, ElemType, Index,
- StructuredList, StructuredIndex);
- }
+
+ assert((ElemType->isRecordType() || ElemType->isVectorType() ||
+ ElemType->isArrayType()) && "Unexpected type");
if (const ArrayType *arrayType = SemaRef.Context.getAsArrayType(ElemType)) {
// arrayType can be incomplete if we're initializing a flexible
// array member. There's nothing we can do with the completed
// type here, though.
- if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) {
+ if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
if (!VerifyOnly) {
- CheckStringInit(Str, ElemType, arrayType, SemaRef);
- UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ CheckStringInit(expr, ElemType, arrayType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
}
++Index;
return;
@@ -857,7 +906,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes,
!VerifyOnly)
- == Sema::Compatible) {
+ != Sema::Incompatible) {
if (ExprRes.isInvalid())
hadError = true;
else {
@@ -1189,16 +1238,17 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
- if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType,
- SemaRef.Context)) {
+ if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) ==
+ SIF_None) {
// We place the string literal directly into the resulting
// initializer list. This is the only place where the structure
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
if (!VerifyOnly) {
- CheckStringInit(Str, DeclType, arrayType, SemaRef);
- UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ IList->getInit(Index));
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
}
++Index;
@@ -1768,22 +1818,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
FieldInitializerValidatorCCC Validator(RT->getDecl());
- TypoCorrection Corrected = SemaRef.CorrectTypo(
- DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/0, /*SS=*/0, Validator,
- RT->getDecl());
- if (Corrected) {
- std::string CorrectedStr(
- Corrected.getAsString(SemaRef.getLangOpts()));
- std::string CorrectedQuotedStr(
- Corrected.getQuoted(SemaRef.getLangOpts()));
+ if (TypoCorrection Corrected = SemaRef.CorrectTypo(
+ DeclarationNameInfo(FieldName, D->getFieldLoc()),
+ Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator,
+ RT->getDecl())) {
+ SemaRef.diagnoseTypo(
+ Corrected,
+ SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
+ << FieldName << CurrentObjectType);
ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
- SemaRef.Diag(D->getFieldLoc(),
- diag::err_field_designator_unknown_suggest)
- << FieldName << CurrentObjectType << CorrectedQuotedStr
- << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr);
- SemaRef.Diag(ReplacementField->getLocation(),
- diag::note_previous_decl) << CorrectedQuotedStr;
hadError = true;
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
@@ -1825,8 +1868,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
- if (!VerifyOnly)
+ if (!VerifyOnly) {
+ FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
+ if (CurrentField && CurrentField != *Field) {
+ 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();
+
+ // remove existing initializer
+ StructuredList->resizeInits(SemaRef.Context, 0);
+ StructuredList->setInitializedFieldInUnion(0);
+ }
+
StructuredList->setInitializedFieldInUnion(*Field);
+ }
}
// Make sure we can use this declaration.
@@ -2034,6 +2098,64 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedEndIndex.setIsUnsigned(true);
}
+ if (!VerifyOnly && StructuredList->isStringLiteralInit()) {
+ // We're modifying a string literal init; we have to decompose the string
+ // so we can modify the individual characters.
+ ASTContext &Context = SemaRef.Context;
+ Expr *SubExpr = StructuredList->getInit(0)->IgnoreParens();
+
+ // Compute the character type
+ QualType CharTy = AT->getElementType();
+
+ // Compute the type of the integer literals.
+ QualType PromotedCharTy = CharTy;
+ if (CharTy->isPromotableIntegerType())
+ PromotedCharTy = Context.getPromotedIntegerType(CharTy);
+ unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy);
+
+ if (StringLiteral *SL = dyn_cast<StringLiteral>(SubExpr)) {
+ // Get the length of the string.
+ uint64_t StrLen = SL->getLength();
+ if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
+ StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
+ StructuredList->resizeInits(Context, StrLen);
+
+ // Build a literal for each character in the string, and put them into
+ // the init list.
+ for (unsigned i = 0, e = StrLen; i != e; ++i) {
+ llvm::APInt CodeUnit(PromotedCharTyWidth, SL->getCodeUnit(i));
+ Expr *Init = new (Context) IntegerLiteral(
+ Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
+ if (CharTy != PromotedCharTy)
+ Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
+ Init, 0, VK_RValue);
+ StructuredList->updateInit(Context, i, Init);
+ }
+ } else {
+ ObjCEncodeExpr *E = cast<ObjCEncodeExpr>(SubExpr);
+ std::string Str;
+ Context.getObjCEncodingForType(E->getEncodedType(), Str);
+
+ // Get the length of the string.
+ uint64_t StrLen = Str.size();
+ if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
+ StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
+ StructuredList->resizeInits(Context, StrLen);
+
+ // Build a literal for each character in the string, and put them into
+ // the init list.
+ for (unsigned i = 0, e = StrLen; i != e; ++i) {
+ llvm::APInt CodeUnit(PromotedCharTyWidth, Str[i]);
+ Expr *Init = new (Context) IntegerLiteral(
+ Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
+ if (CharTy != PromotedCharTy)
+ Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
+ Init, 0, VK_RValue);
+ StructuredList->updateInit(Context, i, Init);
+ }
+ }
+ }
+
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
if (!VerifyOnly &&
@@ -2356,12 +2478,13 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
}
}
-InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base,
- bool IsInheritedVirtualBase)
-{
+InitializedEntity
+InitializedEntity::InitializeBase(ASTContext &Context,
+ const CXXBaseSpecifier *Base,
+ bool IsInheritedVirtualBase) {
InitializedEntity Result;
Result.Kind = EK_Base;
+ Result.Parent = 0;
Result.Base = reinterpret_cast<uintptr_t>(Base);
if (IsInheritedVirtualBase)
Result.Base |= 0x01;
@@ -2372,7 +2495,8 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
DeclarationName InitializedEntity::getName() const {
switch (getKind()) {
- case EK_Parameter: {
+ case EK_Parameter:
+ case EK_Parameter_CF_Audited: {
ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
return (D ? D->getDeclName() : DeclarationName());
}
@@ -2382,7 +2506,7 @@ DeclarationName InitializedEntity::getName() const {
return VariableOrMember->getDeclName();
case EK_LambdaCapture:
- return Capture.Var->getDeclName();
+ return DeclarationName(Capture.VarID);
case EK_Result:
case EK_Exception:
@@ -2395,6 +2519,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_ComplexElement:
case EK_BlockElement:
case EK_CompoundLiteralInit:
+ case EK_RelatedResult:
return DeclarationName();
}
@@ -2408,6 +2533,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
return VariableOrMember;
case EK_Parameter:
+ case EK_Parameter_CF_Audited:
return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
case EK_Result:
@@ -2422,6 +2548,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_BlockElement:
case EK_LambdaCapture:
case EK_CompoundLiteralInit:
+ case EK_RelatedResult:
return 0;
}
@@ -2436,6 +2563,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Variable:
case EK_Parameter:
+ case EK_Parameter_CF_Audited:
case EK_Member:
case EK_New:
case EK_Temporary:
@@ -2447,12 +2575,57 @@ bool InitializedEntity::allowsNRVO() const {
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaCapture:
+ case EK_RelatedResult:
break;
}
return false;
}
+unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
+ assert(getParent() != this);
+ unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
+ for (unsigned I = 0; I != Depth; ++I)
+ OS << "`-";
+
+ switch (getKind()) {
+ case EK_Variable: OS << "Variable"; break;
+ case EK_Parameter: OS << "Parameter"; break;
+ case EK_Parameter_CF_Audited: OS << "CF audited function Parameter";
+ break;
+ case EK_Result: OS << "Result"; break;
+ case EK_Exception: OS << "Exception"; break;
+ case EK_Member: OS << "Member"; break;
+ case EK_New: OS << "New"; break;
+ case EK_Temporary: OS << "Temporary"; break;
+ case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
+ case EK_RelatedResult: OS << "RelatedResult"; break;
+ case EK_Base: OS << "Base"; break;
+ case EK_Delegating: OS << "Delegating"; break;
+ case EK_ArrayElement: OS << "ArrayElement " << Index; break;
+ case EK_VectorElement: OS << "VectorElement " << Index; break;
+ case EK_ComplexElement: OS << "ComplexElement " << Index; break;
+ case EK_BlockElement: OS << "Block"; break;
+ case EK_LambdaCapture:
+ OS << "LambdaCapture ";
+ OS << DeclarationName(Capture.VarID);
+ break;
+ }
+
+ if (Decl *D = getDecl()) {
+ OS << " ";
+ cast<NamedDecl>(D)->printQualifiedName(OS);
+ }
+
+ OS << " '" << getType().getAsString() << "'\n";
+
+ return Depth + 1;
+}
+
+void InitializedEntity::dump() const {
+ dumpImpl(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -2491,6 +2664,7 @@ void InitializationSequence::Step::Destroy() {
break;
case SK_ConversionSequence:
+ case SK_ConversionSequenceNoNarrowing:
delete ICS;
}
}
@@ -2507,6 +2681,10 @@ bool InitializationSequence::isAmbiguous() const {
case FK_TooManyInitsForReference:
case FK_ArrayNeedsInitList:
case FK_ArrayNeedsInitListOrStringLiteral:
+ case FK_ArrayNeedsInitListOrWideStringLiteral:
+ case FK_NarrowStringIntoWideCharArray:
+ case FK_WideStringIntoCharArray:
+ case FK_IncompatWideStringIntoWideChar:
case FK_AddressOfOverloadFailed: // FIXME: Could do better
case FK_NonConstLValueReferenceBindingToTemporary:
case FK_NonConstLValueReferenceBindingToUnrelated:
@@ -2525,7 +2703,6 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ListInitializationFailed:
case FK_VariableLengthArrayHasInitializer:
case FK_PlaceholderType:
- case FK_InitListElementCopyFailure:
case FK_ExplicitConstructor:
return false;
@@ -2627,10 +2804,11 @@ void InitializationSequence::AddLValueToRValueStep(QualType Ty) {
}
void InitializationSequence::AddConversionSequenceStep(
- const ImplicitConversionSequence &ICS,
- QualType T) {
+ const ImplicitConversionSequence &ICS, QualType T,
+ bool TopLevelOfInitList) {
Step S;
- S.Kind = SK_ConversionSequence;
+ S.Kind = TopLevelOfInitList ? SK_ConversionSequenceNoNarrowing
+ : SK_ConversionSequence;
S.Type = T;
S.ICS = new ImplicitConversionSequence(ICS);
Steps.push_back(S);
@@ -2772,7 +2950,7 @@ static void MaybeProduceObjCObject(Sema &S,
/// When initializing a parameter, produce the value if it's marked
/// __attribute__((ns_consumed)).
- if (Entity.getKind() == InitializedEntity::EK_Parameter) {
+ if (Entity.isParameterKind()) {
if (!Entity.isParameterConsumed())
return;
@@ -2792,6 +2970,12 @@ static void MaybeProduceObjCObject(Sema &S,
}
}
+static void TryListInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence);
+
/// \brief When initializing from init list via constructor, handle
/// initialization of an object of type std::initializer_list<T>.
///
@@ -2805,25 +2989,23 @@ static bool TryInitializerListConstruction(Sema &S,
if (!S.isStdInitializerList(DestType, &E))
return false;
- // Check that each individual element can be copy-constructed. But since we
- // have no place to store further information, we'll recalculate everything
- // later.
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- ArrayType::Normal, 0));
- InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
- Element.setElementIndex(i);
- if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
- Sequence.SetFailed(
- InitializationSequence::FK_InitListElementCopyFailure);
- return true;
- }
+ if (S.RequireCompleteType(List->getExprLoc(), E, 0)) {
+ Sequence.setIncompleteTypeFailure(E);
+ return true;
}
- Sequence.AddStdInitializerListConstructionStep(DestType);
+
+ // Try initializing a temporary array from the init list.
+ QualType ArrayType = S.Context.getConstantArrayType(
+ E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ clang::ArrayType::Normal, 0);
+ InitializedEntity HiddenArray =
+ InitializedEntity::InitializeTemporary(ArrayType);
+ InitializationKind Kind =
+ InitializationKind::CreateDirectList(List->getExprLoc());
+ TryListInitialization(S, HiddenArray, Kind, List, Sequence);
+ if (Sequence)
+ Sequence.AddStdInitializerListConstructionStep(DestType);
return true;
}
@@ -2852,9 +3034,19 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
else {
Constructor = cast<CXXConstructorDecl>(D);
- // If we're performing copy initialization using a copy constructor, we
- // suppress user-defined conversions on the arguments. We do the same for
- // move constructors.
+ // C++11 [over.best.ics]p4:
+ // However, when considering the argument of a constructor or
+ // user-defined conversion function that is a candidate:
+ // -- by 13.3.1.3 when invoked for the copying/moving of a temporary
+ // in the second step of a class copy-initialization,
+ // -- by 13.3.1.7 when passing the initializer list as a single
+ // argument or when the initializer list has exactly one elementand
+ // a conversion to some class X or reference to (possibly
+ // cv-qualified) X is considered for the first parameter of a
+ // constructor of X, or
+ // -- by 13.3.1.4, 13.3.1.5, or 13.3.1.6 in all cases,
+ // only standard conversion sequences and ellipsis conversion sequences
+ // are considered.
if ((CopyInitializing || (InitListSyntax && Args.size() == 1)) &&
Constructor->isCopyOrMoveConstructor())
SuppressUserConversions = true;
@@ -3053,19 +3245,12 @@ static void TryValueInitialization(Sema &S,
InitializationSequence &Sequence,
InitListExpr *InitList = 0);
-static void TryListInitialization(Sema &S,
- const InitializedEntity &Entity,
- const InitializationKind &Kind,
- InitListExpr *InitList,
- InitializationSequence &Sequence);
-
/// \brief Attempt list initialization of a reference.
static void TryReferenceListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
- InitializationSequence &Sequence)
-{
+ InitializationSequence &Sequence) {
// First, catch C++03 where this isn't possible.
if (!S.getLangOpts().CPlusPlus11) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
@@ -3182,11 +3367,36 @@ static void TryListInitialization(Sema &S,
return;
}
}
+ if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
+ InitList->getNumInits() == 1 &&
+ InitList->getInit(0)->getType()->isRecordType()) {
+ // - Otherwise, if the initializer list has a single element of type E
+ // [...references are handled above...], the object or reference is
+ // initialized from that element; if a narrowing conversion is required
+ // to convert the element to T, the program is ill-formed.
+ //
+ // Per core-24034, this is direct-initialization if we were performing
+ // direct-list-initialization and copy-initialization otherwise.
+ // We can't use InitListChecker for this, because it always performs
+ // copy-initialization. This only matters if we might use an 'explicit'
+ // conversion operator, so we only need to handle the cases where the source
+ // is of record type.
+ InitializationKind SubKind =
+ Kind.getKind() == InitializationKind::IK_DirectList
+ ? InitializationKind::CreateDirect(Kind.getLocation(),
+ InitList->getLBraceLoc(),
+ InitList->getRBraceLoc())
+ : Kind;
+ Expr *SubInit[1] = { InitList->getInit(0) };
+ Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+ /*TopLevelOfInitList*/true);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
InitListChecker CheckInitList(S, Entity, InitList,
- DestType, /*VerifyOnly=*/true,
- Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus11);
+ DestType, /*VerifyOnly=*/true);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
@@ -3230,8 +3440,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit();
- bool AllowExplicitConvs = Kind.allowExplicitConversionFunctions();
-
+ bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding();
+
const RecordType *T1RecordType = 0;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
!S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
@@ -3244,7 +3454,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// be changed while iterating (e.g. because of deserialization).
// To be safe we copy the lookup results to a new container.
SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
- for (SmallVector<NamedDecl*, 16>::iterator
+ for (SmallVectorImpl<NamedDecl *>::iterator
CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
NamedDecl *D = *CI;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -3498,7 +3708,7 @@ static void TryReferenceInitializationCore(Sema &S,
//
// - If the reference is an lvalue reference and the initializer
// expression
- // Note the analogous bullet points for rvlaue refs to functions. Because
+ // Note the analogous bullet points for rvalue refs to functions. Because
// there are no function rvalues in C++, rvalue refs to functions are treated
// like lvalue refs.
OverloadingResult ConvOvlResult = OR_Success;
@@ -3539,20 +3749,17 @@ static void TryReferenceInitializationCore(Sema &S,
// applicable conversion functions (13.3.1.6) and choosing the best
// one through overload resolution (13.3)),
// If we have an rvalue ref to function type here, the rhs must be
- // an rvalue.
+ // an rvalue. DR1287 removed the "implicitly" here.
if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
(isLValueRef || InitCategory.isRValue())) {
- ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind,
- Initializer,
- /*AllowRValues=*/isRValueRef,
- Sequence);
+ ConvOvlResult = TryRefInitWithConversionFunction(
+ S, Entity, Kind, Initializer, /*AllowRValues*/isRValueRef, Sequence);
if (ConvOvlResult == OR_Success)
return;
- if (ConvOvlResult != OR_No_Viable_Function) {
+ if (ConvOvlResult != OR_No_Viable_Function)
Sequence.SetOverloadFailure(
- InitializationSequence::FK_ReferenceInitOverloadFailed,
- ConvOvlResult);
- }
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
}
}
@@ -3624,16 +3831,16 @@ static void TryReferenceInitializationCore(Sema &S,
// reference-related to T2, and can be implicitly converted to an
// xvalue, class prvalue, or function lvalue of type "cv3 T3",
// where "cv1 T1" is reference-compatible with "cv3 T3",
+ //
+ // DR1287 removes the "implicitly" here.
if (T2->isRecordType()) {
if (RefRelationship == Sema::Ref_Incompatible) {
- ConvOvlResult = TryRefInitWithConversionFunction(S, Entity,
- Kind, Initializer,
- /*AllowRValues=*/true,
- Sequence);
+ ConvOvlResult = TryRefInitWithConversionFunction(
+ S, Entity, Kind, Initializer, /*AllowRValues*/true, Sequence);
if (ConvOvlResult)
Sequence.SetOverloadFailure(
- InitializationSequence::FK_ReferenceInitOverloadFailed,
- ConvOvlResult);
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
return;
}
@@ -3652,19 +3859,17 @@ static void TryReferenceInitializationCore(Sema &S,
// - Otherwise, a temporary of type "cv1 T1" is created and initialized
// from the initializer expression using the rules for a non-reference
- // copy initialization (8.5). The reference is then bound to the
+ // copy-initialization (8.5). The reference is then bound to the
// temporary. [...]
- // Determine whether we are allowed to call explicit constructors or
- // explicit conversion operators.
- bool AllowExplicit = Kind.AllowExplicit();
-
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
+ // FIXME: Why do we use an implicit conversion here rather than trying
+ // copy-initialization?
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, TempEntity.getType(),
- /*SuppressUserConversions*/ false,
- AllowExplicit,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
/*FIXME:InOverloadResolution=*/false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
/*AllowObjCWritebackConversion=*/false);
@@ -3843,7 +4048,8 @@ static void TryUserDefinedConversion(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TopLevelOfInitList) {
QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
@@ -3872,7 +4078,7 @@ static void TryUserDefinedConversion(Sema &S,
// be changed while iterating. To be safe we copy the lookup results
// to a new container.
SmallVector<NamedDecl*, 8> CopyOfCon(R.begin(), R.end());
- for (SmallVector<NamedDecl*, 8>::iterator
+ for (SmallVectorImpl<NamedDecl *>::iterator
Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
@@ -3994,10 +4200,28 @@ static void TryUserDefinedConversion(Sema &S,
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard = Best->FinalConversion;
- Sequence.AddConversionSequenceStep(ICS, DestType);
+ Sequence.AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
}
}
+/// An egregious hack for compatibility with libstdc++-4.2: in <tr1/hashtable>,
+/// a function with a pointer return type contains a 'return false;' statement.
+/// In C++11, 'false' is not a null pointer, so this breaks the build of any
+/// code using that header.
+///
+/// Work around this by treating 'return false;' as zero-initializing the result
+/// if it's used in a pointer-returning function in a system header.
+static bool isLibstdcxxPointerReturnFalseHack(Sema &S,
+ const InitializedEntity &Entity,
+ const Expr *Init) {
+ return S.getLangOpts().CPlusPlus11 &&
+ Entity.getKind() == InitializedEntity::EK_Result &&
+ Entity.getType()->isPointerType() &&
+ isa<CXXBoolLiteralExpr>(Init) &&
+ !cast<CXXBoolLiteralExpr>(Init)->getValue() &&
+ S.getSourceManager().isInSystemHeader(Init->getExprLoc());
+}
+
/// The non-zero enum values here are indexes into diagnostic alternatives.
enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
@@ -4187,8 +4411,17 @@ static bool TryOCLZeroEventInitialization(Sema &S,
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
- MultiExprArg Args)
+ MultiExprArg Args,
+ bool TopLevelOfInitList)
: FailedCandidateSet(Kind.getLocation()) {
+ InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
+}
+
+void InitializationSequence::InitializeFrom(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ MultiExprArg Args,
+ bool TopLevelOfInitList) {
ASTContext &Context = S.Context;
// Eliminate non-overload placeholder types in the arguments. We
@@ -4278,9 +4511,23 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
- if (Initializer && IsStringInit(Initializer, DestAT, Context)) {
- TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
- return;
+ if (Initializer) {
+ switch (IsStringInit(Initializer, DestAT, Context)) {
+ case SIF_None:
+ TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
+ return;
+ case SIF_NarrowStringIntoWideChar:
+ SetFailed(FK_NarrowStringIntoWideCharArray);
+ return;
+ case SIF_WideStringIntoChar:
+ SetFailed(FK_WideStringIntoCharArray);
+ return;
+ case SIF_IncompatWideStringIntoWideChar:
+ SetFailed(FK_IncompatWideStringIntoWideChar);
+ return;
+ case SIF_Other:
+ break;
+ }
}
// Note: as an GNU C extension, we allow initialization of an
@@ -4307,8 +4554,10 @@ InitializationSequence::InitializationSequence(Sema &S,
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
*this);
AddParenthesizedArrayInitStep(DestType);
- } else if (DestAT->getElementType()->isAnyCharacterType())
+ } else if (DestAT->getElementType()->isCharType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
+ else if (IsWideCharCompatible(DestAT->getElementType(), Context))
+ SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
else
SetFailed(FK_ArrayNeedsInitList);
@@ -4318,7 +4567,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// Determine whether we should consider writeback conversions for
// Objective-C ARC.
bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&
- Entity.getKind() == InitializedEntity::EK_Parameter;
+ Entity.isParameterKind();
// We're at the end of the line for C: it's either a write-back conversion
// or it's a C assignment. There's no need to check anything else.
@@ -4362,7 +4611,8 @@ InitializationSequence::InitializationSequence(Sema &S,
// 13.3.1.4, and the best one is chosen through overload resolution
// (13.3).
else
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ TopLevelOfInitList);
return;
}
@@ -4375,7 +4625,8 @@ InitializationSequence::InitializationSequence(Sema &S,
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
return;
}
@@ -4418,14 +4669,16 @@ InitializationSequence::InitializationSequence(Sema &S,
AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
- if (Initializer->getType() == Context.OverloadTy &&
- !S.ResolveAddressOfOverloadedFunction(Initializer
- , DestType, false, dap))
+ if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) {
+ AddZeroInitializationStep(Entity.getType());
+ } else if (Initializer->getType() == Context.OverloadTy &&
+ !S.ResolveAddressOfOverloadedFunction(Initializer, DestType,
+ false, dap))
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
- AddConversionSequenceStep(ICS, Entity.getType());
+ AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
}
@@ -4442,7 +4695,7 @@ InitializationSequence::~InitializationSequence() {
// Perform initialization
//===----------------------------------------------------------------------===//
static Sema::AssignmentAction
-getAssignmentAction(const InitializedEntity &Entity) {
+getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
switch(Entity.getKind()) {
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_New:
@@ -4458,10 +4711,18 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Passing;
+ case InitializedEntity::EK_Parameter_CF_Audited:
+ if (Entity.getDecl() &&
+ isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
+ return Sema::AA_Sending;
+
+ return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited;
+
case InitializedEntity::EK_Result:
return Sema::AA_Returning;
case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_RelatedResult:
// FIXME: Can we tell apart casting vs. converting?
return Sema::AA_Casting;
@@ -4498,7 +4759,9 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
return false;
case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_RelatedResult:
return true;
}
@@ -4522,10 +4785,12 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_CompoundLiteralInit:
+ case InitializedEntity::EK_RelatedResult:
return true;
}
@@ -4543,7 +4808,7 @@ static void LookupCopyAndMoveConstructors(Sema &S,
// be changed while iterating (e.g. because of deserialization).
// To be safe we copy the lookup results to a new container.
SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
- for (SmallVector<NamedDecl*, 16>::iterator
+ for (SmallVectorImpl<NamedDecl *>::iterator
CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
NamedDecl *D = *CI;
CXXConstructorDecl *Constructor = 0;
@@ -4600,6 +4865,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
@@ -4608,6 +4874,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_CompoundLiteralInit:
+ case InitializedEntity::EK_RelatedResult:
return Initializer->getLocStart();
}
llvm_unreachable("missed an InitializedEntity kind?");
@@ -4818,7 +5085,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
void InitializationSequence::PrintInitLocationNote(Sema &S,
const InitializedEntity &Entity) {
- if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) {
+ if (Entity.isParameterKind() && Entity.getDecl()) {
if (Entity.getDecl()->getLocation().isInvalid())
return;
@@ -4828,6 +5095,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
else
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
}
+ else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
+ Entity.getMethodDecl())
+ S.Diag(Entity.getMethodDecl()->getLocation(),
+ diag::note_method_return_type_change)
+ << Entity.getMethodDecl()->getDeclName();
}
static bool isReferenceBinding(const InitializationSequence::Step &s) {
@@ -4843,6 +5115,7 @@ static bool isExplicitTemporary(const InitializedEntity &Entity,
switch (Entity.getKind()) {
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
+ case InitializedEntity::EK_RelatedResult:
break;
default:
return false;
@@ -4867,7 +5140,9 @@ PerformConstructorInitialization(Sema &S,
MultiExprArg Args,
const InitializationSequence::Step& Step,
bool &ConstructorInitRequiresZeroInit,
- bool IsListInitialization) {
+ bool IsListInitialization,
+ SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc) {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step.Function.Function);
@@ -4919,15 +5194,17 @@ PerformConstructorInitialization(Sema &S,
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
- SourceRange ParenRange;
- if (Kind.getKind() != InitializationKind::IK_DirectList)
- ParenRange = Kind.getParenRange();
+ SourceRange ParenOrBraceRange =
+ (Kind.getKind() == InitializationKind::IK_DirectList)
+ ? SourceRange(LBraceLoc, RBraceLoc)
+ : Kind.getParenRange();
CurInit = S.Owned(
new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor,
TSInfo, ConstructorArgs,
- ParenRange, IsListInitialization,
+ ParenOrBraceRange,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit));
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
@@ -4977,7 +5254,7 @@ PerformConstructorInitialization(Sema &S,
return ExprError();
if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ CurInit = S.MaybeBindToTemporary(CurInit.take());
return CurInit;
}
@@ -5010,9 +5287,11 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
return false;
case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_CompoundLiteralInit:
+ case InitializedEntity::EK_RelatedResult:
// The entity being initialized might not outlive the full-expression.
return false;
}
@@ -5020,6 +5299,220 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
llvm_unreachable("unknown entity kind");
}
+/// Determine the declaration which an initialized entity ultimately refers to,
+/// for the purpose of lifetime-extending a temporary bound to a reference in
+/// the initialization of \p Entity.
+static const ValueDecl *
+getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
+ const ValueDecl *FallbackDecl = 0) {
+ // C++11 [class.temporary]p5:
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Variable:
+ // The temporary [...] persists for the lifetime of the reference
+ return Entity.getDecl();
+
+ case InitializedEntity::EK_Member:
+ // For subobjects, we look at the complete object.
+ if (Entity.getParent())
+ return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
+ Entity.getDecl());
+
+ // except:
+ // -- A temporary bound to a reference member in a constructor's
+ // ctor-initializer persists until the constructor exits.
+ return Entity.getDecl();
+
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Parameter_CF_Audited:
+ // -- A temporary bound to a reference parameter in a function call
+ // persists until the completion of the full-expression containing
+ // the call.
+ case InitializedEntity::EK_Result:
+ // -- The lifetime of a temporary bound to the returned value in a
+ // function return statement is not extended; the temporary is
+ // destroyed at the end of the full-expression in the return statement.
+ case InitializedEntity::EK_New:
+ // -- A temporary bound to a reference in a new-initializer persists
+ // until the completion of the full-expression containing the
+ // new-initializer.
+ return 0;
+
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_CompoundLiteralInit:
+ case InitializedEntity::EK_RelatedResult:
+ // We don't yet know the storage duration of the surrounding temporary.
+ // Assume it's got full-expression duration for now, it will patch up our
+ // storage duration if that's not correct.
+ return 0;
+
+ case InitializedEntity::EK_ArrayElement:
+ // For subobjects, we look at the complete object.
+ return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
+ FallbackDecl);
+
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
+ // We can reach this case for aggregate initialization in a constructor:
+ // struct A { int &&r; };
+ // struct B : A { B() : A{0} {} };
+ // In this case, use the innermost field decl as the context.
+ return FallbackDecl;
+
+ case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaCapture:
+ case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
+ return 0;
+ }
+ llvm_unreachable("unknown entity kind");
+}
+
+static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD);
+
+/// Update a glvalue expression that is used as the initializer of a reference
+/// to note that its lifetime is extended.
+/// \return \c true if any temporary had its lifetime extended.
+static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
+ // This is just redundant braces around an initializer. Step over it.
+ Init = ILE->getInit(0);
+ }
+ }
+
+ // Walk past any constructs which we can lifetime-extend across.
+ Expr *Old;
+ do {
+ Old = Init;
+
+ // Step over any subobject adjustments; we may have a materialized
+ // temporary inside them.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ Init = const_cast<Expr *>(
+ Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
+
+ // Per current approach for DR1376, look through casts to reference type
+ // when performing lifetime extension.
+ if (CastExpr *CE = dyn_cast<CastExpr>(Init))
+ if (CE->getSubExpr()->isGLValue())
+ Init = CE->getSubExpr();
+
+ // FIXME: Per DR1213, subscripting on an array temporary produces an xvalue.
+ // It's unclear if binding a reference to that xvalue extends the array
+ // temporary.
+ } while (Init != Old);
+
+ if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
+ // Update the storage duration of the materialized temporary.
+ // FIXME: Rebuild the expression instead of mutating it.
+ ME->setExtendingDecl(ExtendingD);
+ performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);
+ return true;
+ }
+
+ return false;
+}
+
+/// Update a prvalue expression that is going to be materialized as a
+/// lifetime-extended temporary.
+static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
+ // Dig out the expression which constructs the extended temporary.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ Init = const_cast<Expr *>(
+ Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
+
+ if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = BTE->getSubExpr();
+
+ if (CXXStdInitializerListExpr *ILE =
+ dyn_cast<CXXStdInitializerListExpr>(Init)) {
+ performReferenceExtension(ILE->getSubExpr(), ExtendingD);
+ return;
+ }
+
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (ILE->getType()->isArrayType()) {
+ for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
+ performLifetimeExtension(ILE->getInit(I), ExtendingD);
+ return;
+ }
+
+ if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) {
+ assert(RD->isAggregate() && "aggregate init on non-aggregate");
+
+ // If we lifetime-extend a braced initializer which is initializing an
+ // aggregate, and that aggregate contains reference members which are
+ // bound to temporaries, those temporaries are also lifetime-extended.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
+ ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
+ performReferenceExtension(ILE->getInit(0), ExtendingD);
+ else {
+ unsigned Index = 0;
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
+ I != E; ++I) {
+ if (Index >= ILE->getNumInits())
+ break;
+ if (I->isUnnamedBitfield())
+ continue;
+ Expr *SubInit = ILE->getInit(Index);
+ if (I->getType()->isReferenceType())
+ performReferenceExtension(SubInit, ExtendingD);
+ else if (isa<InitListExpr>(SubInit) ||
+ isa<CXXStdInitializerListExpr>(SubInit))
+ // This may be either aggregate-initialization of a member or
+ // initialization of a std::initializer_list object. Either way,
+ // we should recursively lifetime-extend that initializer.
+ performLifetimeExtension(SubInit, ExtendingD);
+ ++Index;
+ }
+ }
+ }
+ }
+}
+
+static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity,
+ const Expr *Init, bool IsInitializerList,
+ const ValueDecl *ExtendingDecl) {
+ // Warn if a field lifetime-extends a temporary.
+ if (isa<FieldDecl>(ExtendingDecl)) {
+ if (IsInitializerList) {
+ S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list)
+ << /*at end of constructor*/true;
+ return;
+ }
+
+ bool IsSubobjectMember = false;
+ for (const InitializedEntity *Ent = Entity.getParent(); Ent;
+ Ent = Ent->getParent()) {
+ if (Ent->getKind() != InitializedEntity::EK_Base) {
+ IsSubobjectMember = true;
+ break;
+ }
+ }
+ S.Diag(Init->getExprLoc(),
+ diag::warn_bind_ref_member_to_temporary)
+ << ExtendingDecl << Init->getSourceRange()
+ << IsSubobjectMember << IsInitializerList;
+ if (IsSubobjectMember)
+ S.Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_subobject_of_member_declared_here);
+ else
+ S.Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << /*is pointer*/false;
+ }
+}
+
+static void DiagnoseNarrowingInInitList(Sema &S,
+ const ImplicitConversionSequence &ICS,
+ QualType PreNarrowingType,
+ QualType EntityType,
+ const Expr *PostInit);
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -5089,7 +5582,7 @@ InitializationSequence::Perform(Sema &S,
if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() &&
Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
- Entity.getKind() != InitializedEntity::EK_Parameter) {
+ !Entity.isParameterKind()) {
// Produce a C++98 compatibility warning if we are initializing a reference
// from an initializer list. For parameters, we produce a better warning
// elsewhere.
@@ -5137,6 +5630,7 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionRValue:
case SK_LValueToRValue:
case SK_ConversionSequence:
+ case SK_ConversionSequenceNoNarrowing:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
@@ -5255,9 +5749,19 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
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.
+ if (const ValueDecl *ExtendingDecl =
+ getDeclForTemporaryLifetimeExtension(Entity)) {
+ if (performReferenceExtension(CurInit.get(), ExtendingDecl))
+ warnOnLifetimeExtension(S, Entity, CurInit.get(), false,
+ ExtendingDecl);
+ }
+
break;
- case SK_BindReferenceToTemporary:
+ case SK_BindReferenceToTemporary: {
// Make sure the "temporary" is actually an rvalue.
assert(CurInit.get()->isRValue() && "not a temporary");
@@ -5265,19 +5769,33 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
+ // Maybe lifetime-extend the temporary's subobjects to match the
+ // entity's lifetime.
+ const ValueDecl *ExtendingDecl =
+ getDeclForTemporaryLifetimeExtension(Entity);
+ if (ExtendingDecl) {
+ performLifetimeExtension(CurInit.get(), ExtendingDecl);
+ warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl);
+ }
+
// Materialize the temporary into memory.
- CurInit = new (S.Context) MaterializeTemporaryExpr(
- Entity.getType().getNonReferenceType(),
- CurInit.get(),
- Entity.getType()->isLValueReferenceType());
+ MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
+ Entity.getType().getNonReferenceType(), CurInit.get(),
+ Entity.getType()->isLValueReferenceType(), ExtendingDecl);
// If we're binding to an Objective-C object that has lifetime, we
- // need cleanups.
- if (S.getLangOpts().ObjCAutoRefCount &&
- CurInit.get()->getType()->isObjCLifetimeType())
+ // 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()))
S.ExprNeedsCleanups = true;
-
+
+ CurInit = S.Owned(MTE);
break;
+ }
case SK_ExtraneousCopyToTemporary:
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
@@ -5411,8 +5929,9 @@ InitializationSequence::Perform(Sema &S,
break;
}
- case SK_ConversionSequence: {
- Sema::CheckedConversionKind CCK
+ case SK_ConversionSequence:
+ case SK_ConversionSequenceNoNarrowing: {
+ Sema::CheckedConversionKind CCK
= Kind.isCStyleCast()? Sema::CCK_CStyleCast
: Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
: Kind.isExplicitCast()? Sema::CCK_OtherCast
@@ -5423,31 +5942,32 @@ InitializationSequence::Perform(Sema &S,
if (CurInitExprRes.isInvalid())
return ExprError();
CurInit = CurInitExprRes;
+
+ if (Step->Kind == SK_ConversionSequenceNoNarrowing &&
+ S.getLangOpts().CPlusPlus && !CurInit.get()->isValueDependent())
+ DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, Entity.getType(),
+ CurInit.get());
break;
}
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
- // Hack: We must pass *ResultType if available in order to set the type
- // of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
- // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a
- // temporary, not a reference, so we should pass Ty.
- // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
- // Since this step is never used for a reference directly, we explicitly
- // unwrap references here and rewrap them afterwards.
- // We also need to create a InitializeTemporary entity for this.
- QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
- bool IsTemporary = Entity.getType()->isReferenceType();
+ // If we're not initializing the top-level entity, we need to create an
+ // InitializeTemporary entity for our target type.
+ QualType Ty = Step->Type;
+ bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty);
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
InitListChecker PerformInitList(S, InitEntity,
- InitList, Ty, /*VerifyOnly=*/false,
- Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus11);
+ InitList, Ty, /*VerifyOnly=*/false);
if (PerformInitList.HadError())
return ExprError();
- if (ResultType) {
+ // Hack: We must update *ResultType if available in order to set the
+ // bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
+ // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
+ if (ResultType &&
+ ResultType->getNonReferenceType()->isIncompleteArrayType()) {
if ((*ResultType)->isRValueReferenceType())
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
@@ -5484,7 +6004,9 @@ InitializationSequence::Perform(Sema &S,
Entity,
Kind, Arg, *Step,
ConstructorInitRequiresZeroInit,
- /*IsListInitialization*/ true);
+ /*IsListInitialization*/ true,
+ InitList->getLBraceLoc(),
+ InitList->getRBraceLoc());
break;
}
@@ -5518,7 +6040,9 @@ InitializationSequence::Perform(Sema &S,
: Entity,
Kind, Args, *Step,
ConstructorInitRequiresZeroInit,
- /*IsListInitialization*/ false);
+ /*IsListInitialization*/ false,
+ /*LBraceLoc*/ SourceLocation(),
+ /*RBraceLoc*/ SourceLocation());
break;
}
@@ -5553,7 +6077,8 @@ InitializationSequence::Perform(Sema &S,
QualType SourceType = CurInit.get()->getType();
ExprResult Result = CurInit;
Sema::AssignConvertType ConvTy =
- S.CheckSingleAssignmentConstraints(Step->Type, Result);
+ S.CheckSingleAssignmentConstraints(Step->Type, Result, true,
+ Entity.getKind() == InitializedEntity::EK_Parameter_CF_Audited);
if (Result.isInvalid())
return ExprError();
CurInit = Result;
@@ -5561,7 +6086,7 @@ InitializationSequence::Perform(Sema &S,
// If this is a call, allow conversion to a transparent union.
ExprResult CurInitExprRes = CurInit;
if (ConvTy != Sema::Compatible &&
- Entity.getKind() == InitializedEntity::EK_Parameter &&
+ Entity.isParameterKind() &&
S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes)
== Sema::Compatible)
ConvTy = Sema::Compatible;
@@ -5573,7 +6098,7 @@ InitializationSequence::Perform(Sema &S,
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
Step->Type, SourceType,
CurInit.get(),
- getAssignmentAction(Entity),
+ getAssignmentAction(Entity, true),
&Complained)) {
PrintInitLocationNote(S, Entity);
return ExprError();
@@ -5640,67 +6165,46 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_StdInitializerList: {
- QualType Dest = Step->Type;
- QualType E;
- bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E);
- (void)Success;
- assert(Success && "Destination type changed?");
-
- // If the element type has a destructor, check it.
- if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) {
- if (!RD->hasIrrelevantDestructor()) {
- if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) {
- S.MarkFunctionReferenced(Kind.getLocation(), Destructor);
- S.CheckDestructorAccess(Kind.getLocation(), Destructor,
- S.PDiag(diag::err_access_dtor_temp) << E);
- if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation()))
- return ExprError();
- }
- }
- }
+ S.Diag(CurInit.get()->getExprLoc(),
+ diag::warn_cxx98_compat_initializer_list_init)
+ << CurInit.get()->getSourceRange();
- InitListExpr *ILE = cast<InitListExpr>(CurInit.take());
- S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init)
- << ILE->getSourceRange();
- unsigned NumInits = ILE->getNumInits();
- SmallVector<Expr*, 16> Converted(NumInits);
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- NumInits),
- ArrayType::Normal, 0));
- InitializedEntity Element =InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0; i < NumInits; ++i) {
- Element.setElementIndex(i);
- ExprResult Init = S.Owned(ILE->getInit(i));
- ExprResult Res = S.PerformCopyInitialization(
- Element, Init.get()->getExprLoc(), Init,
- /*TopLevelOfInitList=*/ true);
- assert(!Res.isInvalid() && "Result changed since try phase.");
- Converted[i] = Res.take();
+ // Maybe lifetime-extend the array temporary's subobjects to match the
+ // entity's lifetime.
+ const ValueDecl *ExtendingDecl =
+ getDeclForTemporaryLifetimeExtension(Entity);
+ if (ExtendingDecl) {
+ performLifetimeExtension(CurInit.get(), ExtendingDecl);
+ warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl);
}
- InitListExpr *Semantic = new (S.Context)
- InitListExpr(S.Context, ILE->getLBraceLoc(),
- Converted, ILE->getRBraceLoc());
- Semantic->setSyntacticForm(ILE);
- Semantic->setType(Dest);
- Semantic->setInitializesStdInitializerList();
- CurInit = S.Owned(Semantic);
+
+ // Materialize the temporary into memory.
+ MaterializeTemporaryExpr *MTE = new (S.Context)
+ MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(),
+ /*lvalue reference*/ false, ExtendingDecl);
+
+ // Wrap it in a construction of a std::initializer_list<T>.
+ CurInit = S.Owned(
+ new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE));
+
+ // Bind the result, in case the library has given initializer_list a
+ // non-trivial destructor.
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.take());
break;
}
+
case SK_OCLSamplerInit: {
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non sampler type.");
QualType SourceType = CurInit.get()->getType();
- InitializedEntity::EntityKind EntityKind = Entity.getKind();
- if (EntityKind == InitializedEntity::EK_Parameter) {
+ if (Entity.isParameterKind()) {
if (!SourceType->isSamplerT())
S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
<< SourceType;
- } else if (EntityKind != InitializedEntity::EK_Variable) {
+ } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
llvm_unreachable("Invalid EntityKind!");
}
@@ -5789,6 +6293,28 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
}
}
+static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
+ InitListExpr *InitList) {
+ QualType DestType = Entity.getType();
+
+ QualType E;
+ if (S.getLangOpts().CPlusPlus11 && S.isStdInitializerList(DestType, &E)) {
+ QualType ArrayType = S.Context.getConstantArrayType(
+ E.withConst(),
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ InitList->getNumInits()),
+ clang::ArrayType::Normal, 0);
+ InitializedEntity HiddenArray =
+ InitializedEntity::InitializeTemporary(ArrayType);
+ return diagnoseListInit(S, HiddenArray, InitList);
+ }
+
+ InitListChecker DiagnoseInitList(S, Entity, InitList, DestType,
+ /*VerifyOnly=*/false);
+ assert(DiagnoseInitList.HadError() &&
+ "Inconsistent init list check result.");
+}
+
bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -5816,14 +6342,27 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case FK_ArrayNeedsInitList:
+ S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0;
+ break;
case FK_ArrayNeedsInitListOrStringLiteral:
- S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list)
- << (Failure == FK_ArrayNeedsInitListOrStringLiteral);
+ S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 1;
+ break;
+ case FK_ArrayNeedsInitListOrWideStringLiteral:
+ S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 2;
+ break;
+ case FK_NarrowStringIntoWideCharArray:
+ S.Diag(Kind.getLocation(), diag::err_array_init_narrow_string_into_wchar);
+ break;
+ case FK_WideStringIntoCharArray:
+ S.Diag(Kind.getLocation(), diag::err_array_init_wide_string_into_char);
+ break;
+ case FK_IncompatWideStringIntoWideChar:
+ S.Diag(Kind.getLocation(),
+ diag::err_array_init_incompat_wide_string_into_wchar);
break;
-
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
- S.Diag(Kind.getLocation(),
+ S.Diag(Kind.getLocation(),
(Failure == FK_ArrayTypeMismatch
? diag::err_array_init_different_type
: diag::err_array_init_non_constant_array))
@@ -5863,9 +6402,14 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case OR_No_Viable_Function:
- S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
- << Args[0]->getType() << DestType.getNonReferenceType()
- << Args[0]->getSourceRange();
+ if (!S.RequireCompleteType(Kind.getLocation(),
+ DestType.getNonReferenceType(),
+ diag::err_typecheck_nonviable_condition_incomplete,
+ Args[0]->getType(), Args[0]->getSourceRange()))
+ S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
+ << Args[0]->getType() << Args[0]->getSourceRange()
+ << DestType.getNonReferenceType();
+
FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
break;
@@ -6110,14 +6654,8 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_ListInitializationFailed: {
// Run the init list checker again to emit diagnostics.
- InitListExpr* InitList = cast<InitListExpr>(Args[0]);
- QualType DestType = Entity.getType();
- InitListChecker DiagnoseInitList(S, Entity, InitList,
- DestType, /*VerifyOnly=*/false,
- Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus11);
- assert(DiagnoseInitList.HadError() &&
- "Inconsistent init list check result.");
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ diagnoseListInit(S, Entity, InitList);
break;
}
@@ -6126,37 +6664,6 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
- case FK_InitListElementCopyFailure: {
- // Try to perform all copies again.
- InitListExpr* InitList = cast<InitListExpr>(Args[0]);
- unsigned NumInits = InitList->getNumInits();
- QualType DestType = Entity.getType();
- QualType E;
- bool Success = S.isStdInitializerList(DestType.getNonReferenceType(), &E);
- (void)Success;
- assert(Success && "Where did the std::initializer_list go?");
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- NumInits),
- ArrayType::Normal, 0));
- InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- // Show at most 3 errors. Otherwise, you'd get a lot of errors for errors
- // where the init list type is wrong, e.g.
- // std::initializer_list<void*> list = { 1, 2, 3, 4, 5, 6, 7, 8 };
- // FIXME: Emit a note if we hit the limit?
- int ErrorCount = 0;
- for (unsigned i = 0; i < NumInits && ErrorCount < 3; ++i) {
- Element.setElementIndex(i);
- ExprResult Init = S.Owned(InitList->getInit(i));
- if (S.PerformCopyInitialization(Element, Init.get()->getExprLoc(), Init)
- .isInvalid())
- ++ErrorCount;
- }
- break;
- }
-
case FK_ExplicitConstructor: {
S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
<< Args[0]->getSourceRange();
@@ -6192,6 +6699,22 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "array requires initializer list or string literal";
break;
+ case FK_ArrayNeedsInitListOrWideStringLiteral:
+ OS << "array requires initializer list or wide string literal";
+ break;
+
+ case FK_NarrowStringIntoWideCharArray:
+ OS << "narrow string into wide char array";
+ break;
+
+ case FK_WideStringIntoCharArray:
+ OS << "wide string into char array";
+ break;
+
+ case FK_IncompatWideStringIntoWideChar:
+ OS << "incompatible wide string into wide char array";
+ break;
+
case FK_ArrayTypeMismatch:
OS << "array type mismatch";
break;
@@ -6280,10 +6803,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "list constructor overloading failed";
break;
- case FK_InitListElementCopyFailure:
- OS << "copy construction of initializer list element failed";
- break;
-
case FK_ExplicitConstructor:
OS << "list copy initialization chose explicit constructor";
break;
@@ -6357,7 +6876,13 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_ConversionSequence:
OS << "implicit conversion sequence (";
- S->ICS->DebugPrint(); // FIXME: use OS
+ S->ICS->dump(); // FIXME: use OS
+ OS << ")";
+ break;
+
+ case SK_ConversionSequenceNoNarrowing:
+ OS << "implicit conversion sequence with narrowing prohibited (";
+ S->ICS->dump(); // FIXME: use OS
OS << ")";
break;
@@ -6440,20 +6965,11 @@ void InitializationSequence::dump() const {
dump(llvm::errs());
}
-static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
+static void DiagnoseNarrowingInInitList(Sema &S,
+ const ImplicitConversionSequence &ICS,
+ QualType PreNarrowingType,
QualType EntityType,
- const Expr *PreInit,
const Expr *PostInit) {
- if (Seq.step_begin() == Seq.step_end() || PreInit->isValueDependent())
- return;
-
- // A narrowing conversion can only appear as the final implicit conversion in
- // an initialization sequence.
- const InitializationSequence::Step &LastStep = Seq.step_end()[-1];
- if (LastStep.Kind != InitializationSequence::SK_ConversionSequence)
- return;
-
- const ImplicitConversionSequence &ICS = *LastStep.ICS;
const StandardConversionSequence *SCS = 0;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
@@ -6468,13 +6984,6 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
return;
}
- // Determine the type prior to the narrowing conversion. If a conversion
- // operator was used, this may be different from both the type of the entity
- // and of the pre-initialization expression.
- QualType PreNarrowingType = PreInit->getType();
- if (Seq.step_begin() + 1 != Seq.step_end())
- PreNarrowingType = Seq.step_end()[-2].Type;
-
// C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
APValue ConstantValue;
QualType ConstantType;
@@ -6489,11 +6998,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
- diag::warn_init_list_type_narrowing
- : S.isSFINAEContext()?
- diag::err_init_list_type_narrowing_sfinae
- : diag::err_init_list_type_narrowing)
+ (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11)
+ ? diag::warn_init_list_type_narrowing
+ : diag::ext_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
@@ -6502,11 +7009,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Constant_Narrowing:
// A constant value was narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
- diag::warn_init_list_constant_narrowing
- : S.isSFINAEContext()?
- diag::err_init_list_constant_narrowing_sfinae
- : diag::err_init_list_constant_narrowing)
+ (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11)
+ ? diag::warn_init_list_constant_narrowing
+ : diag::ext_init_list_constant_narrowing)
<< PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getLocalUnqualifiedType();
@@ -6515,11 +7020,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Variable_Narrowing:
// A variable's value may have been narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
- diag::warn_init_list_variable_narrowing
- : S.isSFINAEContext()?
- diag::err_init_list_variable_narrowing_sfinae
- : diag::err_init_list_variable_narrowing)
+ (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11)
+ ? diag::warn_init_list_variable_narrowing
+ : diag::ext_init_list_variable_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
@@ -6587,14 +7090,10 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
EqualLoc,
AllowExplicit);
- InitializationSequence Seq(*this, Entity, Kind, InitE);
+ InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
Init.release();
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
- if (!Result.isInvalid() && TopLevelOfInitList)
- DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(),
- InitE, Result.get());
-
return Result;
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index c7ba3cc822f3..a7d5b6526464 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -11,27 +11,163 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprCXX.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 "clang/Sema/SemaLambda.h"
+#include "TypeLocBuilder.h"
using namespace clang;
using namespace sema;
+// returns -1 if none of the lambdas on the scope stack can capture.
+// A lambda 'L' is capture-ready for a certain variable 'V' if,
+// - its enclosing context is non-dependent
+// - and if the chain of lambdas between L and the lambda in which
+// V is potentially used, call all capture or have captured V.
+static inline int GetScopeIndexOfNearestCaptureReadyLambda(
+ ArrayRef<clang::sema::FunctionScopeInfo*> FunctionScopes,
+ DeclContext *const CurContext, VarDecl *VD) {
+
+ DeclContext *EnclosingDC = CurContext;
+ // If VD is null, we are attempting to capture 'this'
+ const bool IsCapturingThis = !VD;
+ const bool IsCapturingVariable = !IsCapturingThis;
+ int RetIndex = -1;
+ unsigned CurScopeIndex = FunctionScopes.size() - 1;
+ while (!EnclosingDC->isTranslationUnit() &&
+ EnclosingDC->isDependentContext() && isLambdaCallOperator(EnclosingDC)) {
+ RetIndex = CurScopeIndex;
+ clang::sema::LambdaScopeInfo *LSI =
+ cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
+ // We have crawled up to an intervening lambda that contains the
+ // variable declaration - so not only does it not need to capture;
+ // none of the enclosing lambdas need to capture it, and since all
+ // other nested lambdas are dependent (otherwise we wouldn't have
+ // arrived here) - we don't yet have a lambda that can capture the
+ // variable.
+ if (IsCapturingVariable && VD->getDeclContext()->Equals(EnclosingDC))
+ return -1;
+ // All intervening lambda call operators have to be able to capture.
+ // If they do not have a default implicit capture, check to see
+ // if the entity has already been explicitly captured.
+ // If even a single dependent enclosing lambda lacks the capability
+ // to ever capture this variable, there is no further enclosing
+ // non-dependent lambda that can capture this variable.
+ if (LSI->ImpCaptureStyle == sema::LambdaScopeInfo::ImpCap_None) {
+ if (IsCapturingVariable && !LSI->isCaptured(VD))
+ return -1;
+ if (IsCapturingThis && !LSI->isCXXThisCaptured())
+ return -1;
+ }
+ EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);
+ --CurScopeIndex;
+ }
+ // If the enclosingDC is not dependent, then the immediately nested lambda
+ // is capture-ready.
+ if (!EnclosingDC->isDependentContext())
+ return RetIndex;
+ return -1;
+}
+// Given a lambda's call operator and a variable (or null for 'this'),
+// compute the nearest enclosing lambda that is capture-ready (i.e
+// the enclosing context is not dependent, and all intervening lambdas can
+// either implicitly or explicitly capture Var)
+//
+// The approach is as follows, for the entity VD ('this' if null):
+// - start with the current lambda
+// - if it is non-dependent and can capture VD, return it.
+// - if it is dependent and has an implicit or explicit capture, check its parent
+// whether the parent is non-depdendent and all its intervening lambdas
+// can capture, if so return the child.
+// [Note: When we hit a generic lambda specialization, do not climb up
+// the scope stack any further since not only do we not need to,
+// the scope stack will often not be synchronized with any lambdas
+// enclosing the specialized generic lambda]
+//
+// Return the CallOperator of the capturable lambda and set function scope
+// index to the correct index within the function scope stack to correspond
+// to the capturable lambda.
+// If VarDecl *VD is null, we check for 'this' capture.
+CXXMethodDecl* clang::GetInnermostEnclosingCapturableLambda(
+ ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
+ unsigned &FunctionScopeIndex,
+ DeclContext *const CurContext, VarDecl *VD,
+ Sema &S) {
+
+ const int IndexOfCaptureReadyLambda =
+ GetScopeIndexOfNearestCaptureReadyLambda(FunctionScopes,CurContext, VD);
+ if (IndexOfCaptureReadyLambda == -1) return 0;
+ assert(IndexOfCaptureReadyLambda >= 0);
+ const unsigned IndexOfCaptureReadyLambdaU =
+ static_cast<unsigned>(IndexOfCaptureReadyLambda);
+ sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
+ cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambdaU]);
+ // If VD is null, we are attempting to capture 'this'
+ const bool IsCapturingThis = !VD;
+ const bool IsCapturingVariable = !IsCapturingThis;
+
+ if (IsCapturingVariable) {
+ // Now check to see if this lambda can truly capture, and also
+ // if all enclosing lambdas of this lambda allow this capture.
+ QualType CaptureType, DeclRefType;
+ const bool CanCaptureVariable = !S.tryCaptureVariable(VD,
+ /*ExprVarIsUsedInLoc*/SourceLocation(), clang::Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/false, CaptureType, DeclRefType,
+ &IndexOfCaptureReadyLambdaU);
+ if (!CanCaptureVariable) return 0;
+ } else {
+ const bool CanCaptureThis = !S.CheckCXXThisCapture(
+ CaptureReadyLambdaLSI->PotentialThisCaptureLocation, false, false,
+ &IndexOfCaptureReadyLambdaU);
+ if (!CanCaptureThis) return 0;
+ } // end 'this' capture test
+ FunctionScopeIndex = IndexOfCaptureReadyLambdaU;
+ return CaptureReadyLambdaLSI->CallOperator;
+}
+
+static inline TemplateParameterList *
+getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
+ if (LSI->GLTemplateParameterList)
+ return LSI->GLTemplateParameterList;
+
+ if (LSI->AutoTemplateParams.size()) {
+ SourceRange IntroRange = LSI->IntroducerRange;
+ SourceLocation LAngleLoc = IntroRange.getBegin();
+ SourceLocation RAngleLoc = IntroRange.getEnd();
+ LSI->GLTemplateParameterList = TemplateParameterList::Create(
+ SemaRef.Context,
+ /*Template kw loc*/SourceLocation(),
+ LAngleLoc,
+ (NamedDecl**)LSI->AutoTemplateParams.data(),
+ LSI->AutoTemplateParams.size(), RAngleLoc);
+ }
+ return LSI->GLTemplateParameterList;
+}
+
+
+
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
TypeSourceInfo *Info,
- bool KnownDependent) {
+ bool KnownDependent,
+ LambdaCaptureDefault CaptureDefault) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
-
+ bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
+ *this);
// Start constructing the lambda class.
CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info,
IntroducerRange.getBegin(),
- KnownDependent);
+ KnownDependent,
+ IsGenericLambda,
+ CaptureDefault);
DC->addDecl(Class);
return Class;
@@ -51,55 +187,12 @@ static bool isInInlineFunction(const DeclContext *DC) {
return false;
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodType,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params) {
- // C++11 [expr.prim.lambda]p5:
- // The closure type for a lambda-expression has a public inline function
- // call operator (13.5.4) whose parameters and return type are described by
- // the lambda-expression's parameter-declaration-clause and
- // trailing-return-type respectively.
- DeclarationName MethodName
- = Context.DeclarationNames.getCXXOperatorName(OO_Call);
- DeclarationNameLoc MethodNameLoc;
- MethodNameLoc.CXXOperatorName.BeginOpNameLoc
- = IntroducerRange.getBegin().getRawEncoding();
- MethodNameLoc.CXXOperatorName.EndOpNameLoc
- = IntroducerRange.getEnd().getRawEncoding();
- CXXMethodDecl *Method
- = CXXMethodDecl::Create(Context, Class, EndLoc,
- DeclarationNameInfo(MethodName,
- IntroducerRange.getBegin(),
- MethodNameLoc),
- MethodType->getType(), MethodType,
- SC_None,
- /*isInline=*/true,
- /*isConstExpr=*/false,
- EndLoc);
- Method->setAccess(AS_public);
-
- // Temporarily set the lexical declaration context to the current
- // context, so that the Scope stack matches the lexical nesting.
- Method->setLexicalDeclContext(CurContext);
-
- // Add parameters.
- if (!Params.empty()) {
- Method->setParams(Params);
- CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
- const_cast<ParmVarDecl **>(Params.end()),
- /*CheckParameterNames=*/false);
-
- for (CXXMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd; ++P)
- (*P)->setOwningFunction(Method);
- }
-
- // Allocate a mangling number for this lambda expression, if the ABI
- // requires one.
- Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+MangleNumberingContext *
+Sema::getCurrentMangleNumberContext(const DeclContext *DC,
+ Decl *&ManglingContextDecl) {
+ // Compute the context for allocating mangling numbers in the current
+ // expression, if the ABI requires them.
+ ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
enum ContextKind {
Normal,
@@ -111,16 +204,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// Default arguments of member function parameters that appear in a class
// definition, as well as the initializers of data members, receive special
// treatment. Identify them.
- if (ContextDecl) {
- if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
+ if (ManglingContextDecl) {
+ if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ManglingContextDecl)) {
if (const DeclContext *LexicalDC
= Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
Kind = DefaultArgument;
- } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
- } else if (isa<FieldDecl>(ContextDecl)) {
+ } else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
}
}
@@ -130,57 +223,147 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// types in different translation units to "correspond":
bool IsInNonspecializedTemplate =
!ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
- unsigned ManglingNumber;
switch (Kind) {
case Normal:
// -- the bodies of non-exported nonspecialized template functions
// -- the bodies of inline functions
if ((IsInNonspecializedTemplate &&
- !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) ||
- isInInlineFunction(CurContext))
- ManglingNumber = Context.getLambdaManglingNumber(Method);
- else
- ManglingNumber = 0;
+ !(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
+ isInInlineFunction(CurContext)) {
+ ManglingContextDecl = 0;
+ return &Context.getManglingNumberContext(DC);
+ }
- // There is no special context for this lambda.
- ContextDecl = 0;
- break;
+ ManglingContextDecl = 0;
+ return 0;
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate) {
- ManglingNumber = 0;
- ContextDecl = 0;
- break;
+ ManglingContextDecl = 0;
+ return 0;
}
- // Fall through to assign a mangling number.
+ // Fall through to get the current context.
case DataMember:
// -- the in-class initializers of class members
case DefaultArgument:
// -- default arguments appearing in class definitions
- ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
- .getManglingNumber(Method);
- break;
+ return &ExprEvalContexts.back().getMangleNumberingContext(Context);
}
- Class->setLambdaMangling(ManglingNumber, ContextDecl);
+ llvm_unreachable("unexpected context");
+}
+
+MangleNumberingContext &
+Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
+ ASTContext &Ctx) {
+ assert(ManglingContextDecl && "Need to have a context declaration");
+ if (!MangleNumbering)
+ MangleNumbering = Ctx.createMangleNumberingContext();
+ return *MangleNumbering;
+}
+
+CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params) {
+ QualType MethodType = MethodTypeInfo->getType();
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(getCurLambda(), *this);
+ // If a lambda appears in a dependent context or is a generic lambda (has
+ // template parameters) and has an 'auto' return type, deduce it to a
+ // dependent type.
+ if (Class->isDependentContext() || TemplateParams) {
+ const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
+ QualType Result = FPT->getResultType();
+ if (Result->isUndeducedType()) {
+ Result = SubstAutoType(Result, Context.DependentTy);
+ MethodType = Context.getFunctionType(Result, FPT->getArgTypes(),
+ FPT->getExtProtoInfo());
+ }
+ }
+
+ // C++11 [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline function
+ // call operator (13.5.4) whose parameters and return type are described by
+ // the lambda-expression's parameter-declaration-clause and
+ // trailing-return-type respectively.
+ DeclarationName MethodName
+ = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclarationNameLoc MethodNameLoc;
+ MethodNameLoc.CXXOperatorName.BeginOpNameLoc
+ = IntroducerRange.getBegin().getRawEncoding();
+ MethodNameLoc.CXXOperatorName.EndOpNameLoc
+ = IntroducerRange.getEnd().getRawEncoding();
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(Context, Class, EndLoc,
+ DeclarationNameInfo(MethodName,
+ IntroducerRange.getBegin(),
+ MethodNameLoc),
+ MethodType, MethodTypeInfo,
+ SC_None,
+ /*isInline=*/true,
+ /*isConstExpr=*/false,
+ EndLoc);
+ Method->setAccess(AS_public);
+
+ // Temporarily set the lexical declaration context to the current
+ // context, so that the Scope stack matches the lexical nesting.
+ Method->setLexicalDeclContext(CurContext);
+ // Create a function template if we have a template parameter list
+ FunctionTemplateDecl *const TemplateMethod = TemplateParams ?
+ FunctionTemplateDecl::Create(Context, Class,
+ Method->getLocation(), MethodName,
+ TemplateParams,
+ Method) : 0;
+ if (TemplateMethod) {
+ TemplateMethod->setLexicalDeclContext(CurContext);
+ TemplateMethod->setAccess(AS_public);
+ Method->setDescribedFunctionTemplate(TemplateMethod);
+ }
+
+ // Add parameters.
+ if (!Params.empty()) {
+ Method->setParams(Params);
+ CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
+ const_cast<ParmVarDecl **>(Params.end()),
+ /*CheckParameterNames=*/false);
+
+ for (CXXMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P)
+ (*P)->setOwningFunction(Method);
+ }
+
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ getCurrentMangleNumberContext(Class->getDeclContext(),
+ ManglingContextDecl)) {
+ unsigned ManglingNumber = MCtx->getManglingNumber(Method);
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
+ }
return Method;
}
-LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
+void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
bool ExplicitParams,
bool ExplicitResultType,
bool Mutable) {
- PushLambdaScope(CallOperator->getParent(), CallOperator);
- LambdaScopeInfo *LSI = getCurLambda();
+ LSI->CallOperator = CallOperator;
+ CXXRecordDecl *LambdaClass = CallOperator->getParent();
+ LSI->Lambda = LambdaClass;
if (CaptureDefault == LCD_ByCopy)
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
else if (CaptureDefault == LCD_ByRef)
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+ LSI->CaptureDefaultLoc = CaptureDefaultLoc;
LSI->IntroducerRange = IntroducerRange;
LSI->ExplicitParams = ExplicitParams;
LSI->Mutable = Mutable;
@@ -193,16 +376,11 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType,
diag::err_lambda_incomplete_result)) {
// Do nothing.
- } else if (LSI->ReturnType->isObjCObjectOrInterfaceType()) {
- Diag(CallOperator->getLocStart(), diag::err_lambda_objc_object_result)
- << LSI->ReturnType;
}
}
} else {
LSI->HasImplicitReturnType = true;
}
-
- return LSI;
}
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
@@ -275,11 +453,12 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
// - it is an implicit integral conversion applied to an
// enumerator-like expression of type T or
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- // We can only see integral conversions in valid enumerator-like
- // expressions.
+ // We can sometimes see integral conversions in valid
+ // enumerator-like expressions.
if (ICE->getCastKind() == CK_IntegralCast)
return findEnumForBlockReturn(ICE->getSubExpr());
- return 0;
+
+ // Otherwise, just rely on the type.
}
// - it is an expression of that formal enum type.
@@ -351,6 +530,8 @@ static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
+ // If it was ever a placeholder, it had to been deduced to DependentTy.
+ assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType());
// C++ Core Issue #975, proposed resolution:
// If a lambda-expression does not include a trailing-return-type,
@@ -428,16 +609,160 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
}
}
+QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
+ bool ByRef,
+ IdentifierInfo *Id,
+ Expr *&Init) {
+
+ // We do not need to distinguish between direct-list-initialization
+ // and copy-list-initialization here, because we will always deduce
+ // std::initializer_list<T>, and direct- and copy-list-initialization
+ // always behave the same for such a type.
+ // FIXME: We should model whether an '=' was present.
+ const bool IsDirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
+
+ // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
+ // deduce against.
+ QualType DeductType = Context.getAutoDeductType();
+ TypeLocBuilder TLB;
+ TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
+ if (ByRef) {
+ DeductType = BuildReferenceType(DeductType, true, Loc, Id);
+ assert(!DeductType.isNull() && "can't build reference to auto");
+ TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
+ }
+ TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
+
+ // Are we a non-list direct initialization?
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+
+ Expr *DeduceInit = Init;
+ // Initializer could be a C++ direct-initializer. Deduction only works if it
+ // contains exactly one expression.
+ if (CXXDirectInit) {
+ if (CXXDirectInit->getNumExprs() == 0) {
+ Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_no_expression)
+ << DeclarationName(Id) << TSI->getType() << Loc;
+ return QualType();
+ } else if (CXXDirectInit->getNumExprs() > 1) {
+ Diag(CXXDirectInit->getExpr(1)->getLocStart(),
+ diag::err_init_capture_multiple_expressions)
+ << DeclarationName(Id) << TSI->getType() << Loc;
+ return QualType();
+ } else {
+ DeduceInit = CXXDirectInit->getExpr(0);
+ }
+ }
+
+ // Now deduce against the initialization expression and store the deduced
+ // type below.
+ QualType DeducedType;
+ if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+ if (isa<InitListExpr>(Init))
+ Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
+ << DeclarationName(Id)
+ << (DeduceInit->getType().isNull() ? TSI->getType()
+ : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ else
+ Diag(Loc, diag::err_init_capture_deduction_failure)
+ << DeclarationName(Id) << TSI->getType()
+ << (DeduceInit->getType().isNull() ? TSI->getType()
+ : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ }
+ if (DeducedType.isNull())
+ return QualType();
+
+ // Perform initialization analysis and ensure any implicit conversions
+ // (such as lvalue-to-rvalue) are enforced.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeLambdaCapture(Id, DeducedType, Loc);
+ InitializationKind Kind =
+ IsDirectInit
+ ? (CXXDirectInit ? InitializationKind::CreateDirect(
+ Loc, Init->getLocStart(), Init->getLocEnd())
+ : InitializationKind::CreateDirectList(Loc))
+ : InitializationKind::CreateCopy(Loc, Init->getLocStart());
+
+ MultiExprArg Args = Init;
+ if (CXXDirectInit)
+ Args =
+ MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs());
+ QualType DclT;
+ InitializationSequence InitSeq(*this, Entity, Kind, Args);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
+
+ if (Result.isInvalid())
+ return QualType();
+ Init = Result.takeAs<Expr>();
+
+ // The init-capture initialization is a full-expression that must be
+ // processed as one before we enter the declcontext of the lambda's
+ // call-operator.
+ Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/ false,
+ /*IsConstexpr*/ false,
+ /*IsLambdaInitCaptureInitalizer*/ true);
+ if (Result.isInvalid())
+ return QualType();
+
+ Init = Result.takeAs<Expr>();
+ return DeducedType;
+}
+
+VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
+ QualType InitCaptureType, IdentifierInfo *Id, Expr *Init) {
+
+ TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
+ Loc);
+ // Create a dummy variable representing the init-capture. This is not actually
+ // used as a variable, and only exists as a way to name and refer to the
+ // init-capture.
+ // FIXME: Pass in separate source locations for '&' and identifier.
+ VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
+ Loc, Id, InitCaptureType, TSI, SC_Auto);
+ NewVD->setInitCapture(true);
+ NewVD->setReferenced(true);
+ NewVD->markUsed(Context);
+ NewVD->setInit(Init);
+ return NewVD;
+
+}
+
+FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
+ FieldDecl *Field = FieldDecl::Create(
+ Context, LSI->Lambda, Var->getLocation(), Var->getLocation(),
+ 0, Var->getType(), Var->getTypeSourceInfo(), 0, false, ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ LSI->Lambda->addDecl(Field);
+
+ LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
+ /*isNested*/false, Var->getLocation(), SourceLocation(),
+ Var->getType(), Var->getInit());
+ return Field;
+}
+
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
- Declarator &ParamInfo,
- Scope *CurScope) {
+ Declarator &ParamInfo, Scope *CurScope) {
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
bool KnownDependent = false;
- if (Scope *TmplScope = CurScope->getTemplateParamParent())
- if (!TmplScope->decl_empty())
+ LambdaScopeInfo *const LSI = getCurLambda();
+ assert(LSI && "LambdaScopeInfo should be on stack!");
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(LSI, *this);
+
+ if (Scope *TmplScope = CurScope->getTemplateParamParent()) {
+ // Since we have our own TemplateParams, so check if an outer scope
+ // has template params, only then are we in a dependent scope.
+ if (TemplateParams) {
+ TmplScope = TmplScope->getParent();
+ TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : 0;
+ }
+ if (TmplScope && !TmplScope->decl_empty())
KnownDependent = true;
-
+ }
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
@@ -449,11 +774,21 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
// if the lambda-declarator were ().
- FunctionProtoType::ExtProtoInfo EPI;
+ FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
- QualType MethodTy = Context.getFunctionType(Context.DependentTy, None,
- EPI);
+ // C++1y [expr.prim.lambda]:
+ // The lambda return type is 'auto', which is replaced by the
+ // trailing-return type if provided and/or deduced from 'return'
+ // statements
+ // We don't do this before C++1y, because we don't support deduced return
+ // types there.
+ QualType DefaultTypeForNoTrailingReturn =
+ getLangOpts().CPlusPlus1y ? Context.getAutoDeductType()
+ : Context.DependentTy;
+ QualType MethodTy =
+ Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -462,21 +797,19 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
assert(ParamInfo.isFunctionDeclarator() &&
"lambda-declarator is a function");
DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
-
+
// C++11 [expr.prim.lambda]p5:
// This function call operator is declared const (9.3.1) if and only if
// the lambda-expression's parameter-declaration-clause is not followed
// by mutable. It is neither virtual nor declared volatile. [...]
if (!FTI.hasMutableQualifier())
FTI.TypeQuals |= DeclSpec::TQ_const;
-
+
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
assert(MethodTyInfo && "no type from lambda-declarator");
EndLoc = ParamInfo.getSourceRange().getEnd();
-
- ExplicitResultType
- = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
- != Context.DependentTy;
+
+ ExplicitResultType = FTI.hasTrailingReturnType();
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
@@ -494,11 +827,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
- KnownDependent);
+ KnownDependent, Intro.Default);
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
-
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -508,19 +840,24 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
- // Introduce the lambda scope.
- LambdaScopeInfo *LSI
- = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
+ // Build the lambda scope.
+ buildLambdaScope(LSI, Method,
+ Intro.Range,
+ Intro.Default, Intro.DefaultLoc,
+ ExplicitParams,
ExplicitResultType,
!Method->isConst());
-
+
+ // Distinct capture names, for diagnostics.
+ llvm::SmallSet<IdentifierInfo*, 8> CaptureNames;
+
// Handle explicit captures.
SourceLocation PrevCaptureLoc
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
- for (SmallVector<LambdaCapture, 4>::const_iterator
- C = Intro.Captures.begin(),
- E = Intro.Captures.end();
- C != E;
+ for (SmallVectorImpl<LambdaCapture>::const_iterator
+ C = Intro.Captures.begin(),
+ E = Intro.Captures.end();
+ C != E;
PrevCaptureLoc = C->Loc, ++C) {
if (C->Kind == LCK_This) {
// C++11 [expr.prim.lambda]p8:
@@ -560,44 +897,89 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
assert(C->Id && "missing identifier for capture");
- // C++11 [expr.prim.lambda]p8:
- // If a lambda-capture includes a capture-default that is &, the
- // identifiers in the lambda-capture shall not be preceded by &.
- // If a lambda-capture includes a capture-default that is =, [...]
- // each identifier it contains shall be preceded by &.
- if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
- Diag(C->Loc, diag::err_reference_capture_with_reference_default)
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
- continue;
- } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
- Diag(C->Loc, diag::err_copy_capture_with_copy_default)
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ if (C->Init.isInvalid())
continue;
+
+ VarDecl *Var = 0;
+ if (C->Init.isUsable()) {
+ Diag(C->Loc, getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_init_capture
+ : diag::ext_init_capture);
+
+ if (C->Init.get()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ // If the initializer expression is usable, but the InitCaptureType
+ // is not, then an error has occurred - so ignore the capture for now.
+ // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
+ // FIXME: we should create the init capture variable and mark it invalid
+ // in this case.
+ if (C->InitCaptureType.get().isNull())
+ continue;
+ Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
+ C->Id, C->Init.take());
+ // C++1y [expr.prim.lambda]p11:
+ // An init-capture behaves as if it declares and explicitly
+ // captures a variable [...] whose declarative region is the
+ // lambda-expression's compound-statement
+ if (Var)
+ PushOnScopeChains(Var, CurScope, false);
+ } else {
+ // C++11 [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is &, the
+ // identifiers in the lambda-capture shall not be preceded by &.
+ // If a lambda-capture includes a capture-default that is =, [...]
+ // each identifier it contains shall be preceded by &.
+ if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
+ Diag(C->Loc, diag::err_reference_capture_with_reference_default)
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_copy_capture_with_copy_default)
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p10:
+ // The identifiers in a capture-list are looked up using the usual
+ // rules for unqualified name lookup (3.4.1)
+ DeclarationNameInfo Name(C->Id, C->Loc);
+ LookupResult R(*this, Name, LookupOrdinaryName);
+ LookupName(R, CurScope);
+ if (R.isAmbiguous())
+ continue;
+ if (R.empty()) {
+ // FIXME: Disable corrections that would add qualification?
+ CXXScopeSpec ScopeSpec;
+ DeclFilterCCC<VarDecl> Validator;
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
+ continue;
+ }
+
+ Var = R.getAsSingle<VarDecl>();
}
- DeclarationNameInfo Name(C->Id, C->Loc);
- LookupResult R(*this, Name, LookupOrdinaryName);
- LookupName(R, CurScope);
- if (R.isAmbiguous())
+ // C++11 [expr.prim.lambda]p8:
+ // An identifier or this shall not appear more than once in a
+ // lambda-capture.
+ if (!CaptureNames.insert(C->Id)) {
+ if (Var && LSI->isCaptured(Var)) {
+ Diag(C->Loc, diag::err_capture_more_than_once)
+ << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ } else
+ // Previous capture captured something different (one or both was
+ // an init-cpature): no fixit.
+ Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
continue;
- if (R.empty()) {
- // FIXME: Disable corrections that would add qualification?
- CXXScopeSpec ScopeSpec;
- DeclFilterCCC<VarDecl> Validator;
- if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
- continue;
}
// C++11 [expr.prim.lambda]p10:
- // The identifiers in a capture-list are looked up using the usual rules
- // for unqualified name lookup (3.4.1); each such lookup shall find a
- // variable with automatic storage duration declared in the reaching
- // scope of the local lambda expression.
- //
+ // [...] each such lookup shall find a variable with automatic storage
+ // duration declared in the reaching scope of the local lambda expression.
// Note that the 'reaching scope' check happens in tryCaptureVariable().
- VarDecl *Var = R.getAsSingle<VarDecl>();
if (!Var) {
Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
continue;
@@ -613,18 +995,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- // C++11 [expr.prim.lambda]p8:
- // An identifier or this shall not appear more than once in a
- // lambda-capture.
- if (LSI->isCaptured(Var)) {
- Diag(C->Loc, diag::err_capture_more_than_once)
- << C->Id
- << SourceRange(LSI->getCapture(Var).getLocation())
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
- continue;
- }
-
// C++11 [expr.prim.lambda]p23:
// A capture followed by an ellipsis is a pack expansion (14.5.3).
SourceLocation EllipsisLoc;
@@ -640,10 +1010,14 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
} else if (Var->isParameterPack()) {
ContainsUnexpandedParameterPack = true;
}
-
- TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
- TryCapture_ExplicitByVal;
- tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
+
+ if (C->Init.isUsable()) {
+ buildInitCaptureField(LSI, Var);
+ } else {
+ TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
+ TryCapture_ExplicitByVal;
+ tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
+ }
}
finishLambdaExplicitCaptures(LSI);
@@ -689,72 +1063,173 @@ static void addFunctionPointerConversion(Sema &S,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
// Add the conversion to function pointer.
- const FunctionProtoType *Proto
- = CallOperator->getType()->getAs<FunctionProtoType>();
- QualType FunctionPtrTy;
- QualType FunctionTy;
+ const FunctionProtoType *CallOpProto =
+ CallOperator->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
+ CallOpProto->getExtProtoInfo();
+ QualType PtrToFunctionTy;
+ QualType InvokerFunctionTy;
{
- FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
- ExtInfo.TypeQuals = 0;
- FunctionTy =
- S.Context.getFunctionType(Proto->getResultType(),
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- ExtInfo);
- FunctionPtrTy = S.Context.getPointerType(FunctionTy);
+ FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
+ CallingConv CC = S.Context.getDefaultCallingConvention(
+ CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
+ InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
+ InvokerExtInfo.TypeQuals = 0;
+ assert(InvokerExtInfo.RefQualifier == RQ_None &&
+ "Lambda's call operator should not have a reference qualifier");
+ InvokerFunctionTy = S.Context.getFunctionType(CallOpProto->getResultType(),
+ CallOpProto->getArgTypes(), InvokerExtInfo);
+ PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
}
-
- FunctionProtoType::ExtProtoInfo ExtInfo;
- ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy =
- S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
-
+
+ // Create the type of the conversion function.
+ FunctionProtoType::ExtProtoInfo ConvExtInfo(
+ S.Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
+ // The conversion function is always const.
+ ConvExtInfo.TypeQuals = Qualifiers::Const;
+ QualType ConvTy =
+ S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
+
SourceLocation Loc = IntroducerRange.getBegin();
- DeclarationName Name
+ DeclarationName ConversionName
= S.Context.DeclarationNames.getCXXConversionFunctionName(
- S.Context.getCanonicalType(FunctionPtrTy));
- DeclarationNameLoc NameLoc;
- NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy,
- Loc);
+ S.Context.getCanonicalType(PtrToFunctionTy));
+ DeclarationNameLoc ConvNameLoc;
+ // Construct a TypeSourceInfo for the conversion function, and wire
+ // all the parameters appropriately for the FunctionProtoTypeLoc
+ // so that everything works during transformation/instantiation of
+ // generic lambdas.
+ // The main reason for wiring up the parameters of the conversion
+ // function with that of the call operator is so that constructs
+ // like the following work:
+ // auto L = [](auto b) { <-- 1
+ // return [](auto a) -> decltype(a) { <-- 2
+ // return a;
+ // };
+ // };
+ // int (*fp)(int) = L(5);
+ // Because the trailing return type can contain DeclRefExprs that refer
+ // to the original call operator's variables, we hijack the call
+ // operators ParmVarDecls below.
+ TypeSourceInfo *ConvNamePtrToFunctionTSI =
+ S.Context.getTrivialTypeSourceInfo(PtrToFunctionTy, Loc);
+ ConvNameLoc.NamedType.TInfo = ConvNamePtrToFunctionTSI;
+
+ // The conversion function is a conversion to a pointer-to-function.
+ TypeSourceInfo *ConvTSI = S.Context.getTrivialTypeSourceInfo(ConvTy, Loc);
+ FunctionProtoTypeLoc ConvTL =
+ ConvTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ // Get the result of the conversion function which is a pointer-to-function.
+ PointerTypeLoc PtrToFunctionTL =
+ ConvTL.getResultLoc().getAs<PointerTypeLoc>();
+ // Do the same for the TypeSourceInfo that is used to name the conversion
+ // operator.
+ PointerTypeLoc ConvNamePtrToFunctionTL =
+ ConvNamePtrToFunctionTSI->getTypeLoc().getAs<PointerTypeLoc>();
+
+ // Get the underlying function types that the conversion function will
+ // be converting to (should match the type of the call operator).
+ FunctionProtoTypeLoc CallOpConvTL =
+ PtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
+ FunctionProtoTypeLoc CallOpConvNameTL =
+ ConvNamePtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
+
+ // Wire up the FunctionProtoTypeLocs with the call operator's parameters.
+ // These parameter's are essentially used to transform the name and
+ // the type of the conversion operator. By using the same parameters
+ // as the call operator's we don't have to fix any back references that
+ // the trailing return type of the call operator's uses (such as
+ // decltype(some_type<decltype(a)>::type{} + decltype(a){}) etc.)
+ // - we can simply use the return type of the call operator, and
+ // everything should work.
+ SmallVector<ParmVarDecl *, 4> InvokerParams;
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+ ParmVarDecl *From = CallOperator->getParamDecl(I);
+
+ InvokerParams.push_back(ParmVarDecl::Create(S.Context,
+ // Temporarily add to the TU. This is set to the invoker below.
+ S.Context.getTranslationUnitDecl(),
+ From->getLocStart(),
+ From->getLocation(),
+ From->getIdentifier(),
+ From->getType(),
+ From->getTypeSourceInfo(),
+ From->getStorageClass(),
+ /*DefaultArg=*/0));
+ CallOpConvTL.setArg(I, From);
+ CallOpConvNameTL.setArg(I, From);
+ }
+
CXXConversionDecl *Conversion
= CXXConversionDecl::Create(S.Context, Class, Loc,
- DeclarationNameInfo(Name, Loc, NameLoc),
+ DeclarationNameInfo(ConversionName,
+ Loc, ConvNameLoc),
ConvTy,
- S.Context.getTrivialTypeSourceInfo(ConvTy,
- Loc),
- /*isInline=*/false, /*isExplicit=*/false,
+ ConvTSI,
+ /*isInline=*/true, /*isExplicit=*/false,
/*isConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
- Class->addDecl(Conversion);
-
- // Add a non-static member function "__invoke" that will be the result of
- // the conversion.
- Name = &S.Context.Idents.get("__invoke");
+
+ if (Class->isGenericLambda()) {
+ // Create a template version of the conversion operator, using the template
+ // parameter list of the function call operator.
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *ConversionTemplate =
+ FunctionTemplateDecl::Create(S.Context, Class,
+ Loc, ConversionName,
+ TemplateCallOperator->getTemplateParameters(),
+ Conversion);
+ ConversionTemplate->setAccess(AS_public);
+ ConversionTemplate->setImplicit(true);
+ Conversion->setDescribedFunctionTemplate(ConversionTemplate);
+ Class->addDecl(ConversionTemplate);
+ } else
+ Class->addDecl(Conversion);
+ // Add a non-static member function that will be the result of
+ // the conversion with a certain unique ID.
+ DeclarationName InvokerName = &S.Context.Idents.get(
+ getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
+ // trailing return type of the invoker would require a visitor to rebuild
+ // the trailing return type and adjusting all back DeclRefExpr's to refer
+ // to the new static invoker parameters - not the call operator's.
CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc,
- DeclarationNameInfo(Name, Loc), FunctionTy,
- CallOperator->getTypeSourceInfo(),
+ DeclarationNameInfo(InvokerName, Loc),
+ InvokerFunctionTy,
+ CallOperator->getTypeSourceInfo(),
SC_Static, /*IsInline=*/true,
/*IsConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
- SmallVector<ParmVarDecl *, 4> InvokeParams;
- for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
- ParmVarDecl *From = CallOperator->getParamDecl(I);
- InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke,
- From->getLocStart(),
- From->getLocation(),
- From->getIdentifier(),
- From->getType(),
- From->getTypeSourceInfo(),
- From->getStorageClass(),
- /*DefaultArg=*/0));
- }
- Invoke->setParams(InvokeParams);
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
+ InvokerParams[I]->setOwningFunction(Invoke);
+ Invoke->setParams(InvokerParams);
Invoke->setAccess(AS_private);
Invoke->setImplicit(true);
- Class->addDecl(Invoke);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, InvokerName,
+ TemplateCallOperator->getTemplateParameters(),
+ Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
}
/// \brief Add a lambda's conversion to block pointer.
@@ -768,15 +1243,13 @@ static void addBlockPointerConversion(Sema &S,
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
- QualType FunctionTy
- = S.Context.getFunctionType(Proto->getResultType(),
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- ExtInfo);
+ QualType FunctionTy = S.Context.getFunctionType(
+ Proto->getResultType(), Proto->getArgTypes(), ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
-
- FunctionProtoType::ExtProtoInfo ExtInfo;
+
+ FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
ExtInfo.TypeQuals = Qualifiers::Const;
QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo);
@@ -791,7 +1264,7 @@ static void addBlockPointerConversion(Sema &S,
DeclarationNameInfo(Name, Loc, NameLoc),
ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
- /*isInline=*/false, /*isExplicit=*/false,
+ /*isInline=*/true, /*isExplicit=*/false,
/*isConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
@@ -806,6 +1279,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
SmallVector<LambdaExpr::Capture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
LambdaCaptureDefault CaptureDefault;
+ SourceLocation CaptureDefaultLoc;
CXXRecordDecl *Class;
CXXMethodDecl *CallOperator;
SourceRange IntroducerRange;
@@ -848,7 +1322,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
Kind, Var, From.getEllipsisLoc()));
- CaptureInits.push_back(From.getCopyExpr());
+ CaptureInits.push_back(From.getInitExpr());
}
switch (LSI->ImpCaptureStyle) {
@@ -869,13 +1343,18 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
llvm_unreachable("block capture in lambda");
break;
}
+ CaptureDefaultLoc = LSI->CaptureDefaultLoc;
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a
// trailing-return-type, it is as if the trailing-return-type
// denotes the following type:
+ //
+ // Skip for C++1y return type deduction semantics which uses
+ // different machinery.
+ // FIXME: Refactor and Merge the return type deduction machinery.
// FIXME: Assumes current resolution to core issue 975.
- if (LSI->HasImplicitReturnType) {
+ if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus1y) {
deduceClosureReturnType(*LSI);
// - if there are no return statements in the
@@ -889,20 +1368,23 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// Create a function type with the inferred return type.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
- QualType FunctionTy
- = Context.getFunctionType(LSI->ReturnType,
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- Proto->getExtProtoInfo());
+ QualType FunctionTy = Context.getFunctionType(
+ LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
-
// C++ [expr.prim.lambda]p7:
// The lambda-expression's compound-statement yields the
// function-body (8.4) of the function call operator [...].
ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
CallOperator->setLexicalDeclContext(Class);
- Class->addDecl(CallOperator);
+ Decl *TemplateOrNonTemplateCallOperatorDecl =
+ CallOperator->getDescribedFunctionTemplate()
+ ? CallOperator->getDescribedFunctionTemplate()
+ : cast<Decl>(CallOperator);
+
+ TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
+ Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
+
PopExpressionEvaluationContext();
// C++11 [expr.prim.lambda]p6:
@@ -919,7 +1401,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// non-explicit const conversion function to a block pointer having the
// same parameter and return types as the closure type's function call
// operator.
- if (getLangOpts().Blocks && getLangOpts().ObjC1)
+ // FIXME: Fix generic lambda to block conversions.
+ if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
+ !Class->isGenericLambda())
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
@@ -936,32 +1420,42 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
ExprNeedsCleanups = true;
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
- CaptureDefault, Captures,
+ CaptureDefault, CaptureDefaultLoc,
+ Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(),
ContainsUnexpandedParameterPack);
- // C++11 [expr.prim.lambda]p2:
- // A lambda-expression shall not appear in an unevaluated operand
- // (Clause 5).
if (!CurContext->isDependentContext()) {
switch (ExprEvalContexts.back().Context) {
+ // C++11 [expr.prim.lambda]p2:
+ // A lambda-expression shall not appear in an unevaluated operand
+ // (Clause 5).
case Unevaluated:
case 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
+ // evaluate [...] a lambda-expression.
+ //
+ // This is technically incorrect, there are some constant evaluated contexts
+ // 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:
// 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 ConstantEvaluated:
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
break;
}
}
-
+
return MaybeBindToTemporary(Lambda);
}
@@ -976,7 +1470,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Lambda->lookup(
Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced();
- CallOperator->setUsed();
+ CallOperator->markUsed(Context);
ExprResult Init = PerformCopyInitialization(
InitializedEntity::InitializeBlock(ConvLocation,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 9ab3b2d08ec0..919c6ad61ab2 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -102,15 +102,14 @@ namespace {
// During unqualified name lookup, the names appear as if they
// were declared in the nearest enclosing namespace which contains
// both the using-directive and the nominated namespace.
- DeclContext *InnermostFileDC
- = static_cast<DeclContext*>(InnermostFileScope->getEntity());
+ DeclContext *InnermostFileDC = InnermostFileScope->getEntity();
assert(InnermostFileDC && InnermostFileDC->isFileContext());
for (; S; S = S->getParent()) {
// C++ [namespace.udir]p1:
// A using-directive shall not appear in class scope, but may
// appear in namespace scope or in block scope.
- DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ DeclContext *Ctx = S->getEntity();
if (Ctx && Ctx->isFileContext()) {
visit(Ctx, Ctx);
} else if (!Ctx || Ctx->isFunctionOrMethod()) {
@@ -167,8 +166,7 @@ namespace {
if (queue.empty())
return;
- DC = queue.back();
- queue.pop_back();
+ DC = queue.pop_back_val();
}
}
@@ -217,12 +215,15 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCImplicitSelfParam:
case Sema::LookupOrdinaryName:
case Sema::LookupRedeclarationWithLinkage:
+ case Sema::LookupLocalFriendName:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
if (Redeclaration)
IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_LocalExtern;
break;
case Sema::LookupOperatorName:
@@ -336,10 +337,19 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
delete Paths;
}
-static NamedDecl *getVisibleDecl(NamedDecl *D);
-
-NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
- return getVisibleDecl(D);
+/// Get a representative context for a declaration such that two declarations
+/// will have the same context if they were found within the same scope.
+static DeclContext *getContextForScopeMatching(Decl *D) {
+ // For function-local declarations, use that function as the context. This
+ // doesn't account for scopes within the function; the caller must deal with
+ // those.
+ DeclContext *DC = D->getLexicalDeclContext();
+ if (DC->isFunctionOrMethod())
+ return DC;
+
+ // Otherwise, look at the semantic context of the declaration. The
+ // declaration must have been found there.
+ return D->getDeclContext()->getRedeclContext();
}
/// Resolves the result kind of this lookup.
@@ -442,8 +452,8 @@ void LookupResult::resolveKind() {
// even if they're not visible. (ref?)
if (HideTags && HasTag && !Ambiguous &&
(HasFunction || HasNonFunction || HasUnresolved)) {
- if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals(
- Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext()))
+ if (getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
+ getContextForScopeMatching(Decls[UniqueTagIndex ? 0 : N - 1])))
Decls[UniqueTagIndex] = Decls[--N];
else
Ambiguous = true;
@@ -511,6 +521,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
NameKind == Sema::LookupRedeclarationWithLinkage) {
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
if (II) {
+ if (S.getLangOpts().CPlusPlus11 && S.getLangOpts().GNUMode &&
+ II == S.getFloat128Identifier()) {
+ // libstdc++4.7's type_traits expects type __float128 to exist, so
+ // insert a dummy type to make that header build in gnu++11 mode.
+ R.addDecl(S.getASTContext().getFloat128StubType());
+ return true;
+ }
+
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++, we don't have any predefined library functions like
@@ -726,7 +744,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// function to have, if it were to match the name given.
// FIXME: Calling convention!
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
- EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default);
+ EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
EPI.ExceptionSpecType = EST_None;
EPI.NumExceptions = 0;
QualType ExpectedType
@@ -771,7 +789,7 @@ CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
}
static bool isNamespaceOrTranslationUnitScope(Scope *S) {
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
+ if (DeclContext *Ctx = S->getEntity())
return Ctx->isFileContext();
return false;
}
@@ -784,12 +802,12 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
// name lookup should continue searching in this semantic context when
// it leaves the current template parameter scope.
static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
- DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *DC = S->getEntity();
DeclContext *Lexical = 0;
for (Scope *OuterS = S->getParent(); OuterS;
OuterS = OuterS->getParent()) {
if (OuterS->getEntity()) {
- Lexical = static_cast<DeclContext *>(OuterS->getEntity());
+ Lexical = OuterS->getEntity();
break;
}
}
@@ -845,16 +863,37 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
return std::make_pair(Lexical, false);
}
+namespace {
+/// An RAII object to specify that we want to find block scope extern
+/// declarations.
+struct FindLocalExternScope {
+ FindLocalExternScope(LookupResult &R)
+ : R(R), OldFindLocalExtern(R.getIdentifierNamespace() &
+ Decl::IDNS_LocalExtern) {
+ R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary);
+ }
+ void restore() {
+ R.setFindLocalExtern(OldFindLocalExtern);
+ }
+ ~FindLocalExternScope() {
+ restore();
+ }
+ LookupResult &R;
+ bool OldFindLocalExtern;
+};
+}
+
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup");
DeclarationName Name = R.getLookupName();
+ Sema::LookupNameKind NameKind = R.getLookupKind();
// If this is the name of an implicitly-declared special member function,
// go through the scope stack to implicitly declare
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
- if (DeclContext *DC = static_cast<DeclContext *>(PreS->getEntity()))
+ if (DeclContext *DC = PreS->getEntity())
DeclareImplicitMemberFunctionsWithName(*this, Name, DC);
}
@@ -886,14 +925,35 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
//
UnqualUsingDirectiveSet UDirs;
bool VisitedUsingDirectives = false;
+ bool LeftStartingScope = false;
DeclContext *OutsideOfTemplateParamDC = 0;
+
+ // When performing a scope lookup, we want to find local extern decls.
+ FindLocalExternScope FindLocals(R);
+
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
- DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ DeclContext *Ctx = S->getEntity();
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(*I); ++I) {
if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
+ if (NameKind == LookupRedeclarationWithLinkage) {
+ // Determine whether this (or a previous) declaration is
+ // out-of-scope.
+ if (!LeftStartingScope && !Initial->isDeclScope(*I))
+ LeftStartingScope = true;
+
+ // If we found something outside of our starting scope that
+ // does not have linkage, skip it. If it's a template parameter,
+ // we still find it, so we can diagnose the invalid redeclaration.
+ if (LeftStartingScope && !((*I)->hasLinkage()) &&
+ !(*I)->isTemplateParameter()) {
+ R.setShadowed();
+ continue;
+ }
+ }
+
Found = true;
R.addDecl(ND);
}
@@ -906,6 +966,15 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return true;
}
+ if (NameKind == LookupLocalFriendName && !S->isClassScope()) {
+ // C++11 [class.friend]p11:
+ // If a friend declaration appears in a local class and the name
+ // specified is an unqualified name, a prior declaration is
+ // looked up without considering scopes that are outside the
+ // innermost enclosing non-class scope.
+ return false;
+ }
+
if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
S->getParent() && !S->getParent()->isTemplateParamScope()) {
// We've just searched the last template parameter scope and
@@ -1007,7 +1076,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (!S) return false;
// If we are looking for members, no need to look into global/namespace scope.
- if (R.getLookupKind() == LookupMemberName)
+ if (NameKind == LookupMemberName)
return false;
// Collect UsingDirectiveDecls in all scopes, and recursively all
@@ -1019,7 +1088,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
UDirs.visitScopeChain(Initial, S);
UDirs.done();
}
-
+
+ // If we're not performing redeclaration lookup, do not look for local
+ // extern declarations outside of a function scope.
+ if (!R.isForRedeclaration())
+ FindLocals.restore();
+
// Lookup namespace scope, and global scope.
// Unqualified name lookup in C++ requires looking into scopes
// that aren't strictly lexical, and therefore we walk through the
@@ -1043,7 +1117,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return true;
}
- DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *Ctx = S->getEntity();
if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
S->getParent() && !S->getParent()->isTemplateParamScope()) {
// We've just searched the last template parameter scope and
@@ -1098,29 +1172,127 @@ 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();
+}
+
+/// \brief Find the module in which the given declaration was defined.
+static Module *getDefiningModule(Decl *Entity) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Entity)) {
+ // If this function was instantiated from a template, the defining module is
+ // the module containing the pattern.
+ if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+ Entity = Pattern;
+ } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Entity)) {
+ // If it's a class template specialization, find the template or partial
+ // specialization from which it was instantiated.
+ if (ClassTemplateSpecializationDecl *SpecRD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ llvm::PointerUnion<ClassTemplateDecl*,
+ ClassTemplatePartialSpecializationDecl*> From =
+ SpecRD->getInstantiatedFrom();
+ if (ClassTemplateDecl *FromTemplate = From.dyn_cast<ClassTemplateDecl*>())
+ Entity = FromTemplate->getTemplatedDecl();
+ else if (From)
+ Entity = From.get<ClassTemplatePartialSpecializationDecl*>();
+ // Otherwise, it's an explicit specialization.
+ } else if (MemberSpecializationInfo *MSInfo =
+ RD->getMemberSpecializationInfo())
+ Entity = getInstantiatedFrom(RD, MSInfo);
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) {
+ if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo())
+ Entity = getInstantiatedFrom(ED, MSInfo);
+ } 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);
+ }
+
+ // Walk up to the containing context. That might also have been instantiated
+ // from a template.
+ DeclContext *Context = Entity->getDeclContext();
+ if (Context->isFileContext())
+ return Entity->getOwningModule();
+ return getDefiningModule(cast<Decl>(Context));
+}
+
+llvm::DenseSet<Module*> &Sema::getLookupModules() {
+ unsigned N = ActiveTemplateInstantiations.size();
+ for (unsigned I = ActiveTemplateInstantiationLookupModules.size();
+ I != N; ++I) {
+ Module *M = getDefiningModule(ActiveTemplateInstantiations[I].Entity);
+ if (M && !LookupModulesCache.insert(M).second)
+ M = 0;
+ ActiveTemplateInstantiationLookupModules.push_back(M);
+ }
+ return LookupModulesCache;
+}
+
+/// \brief Determine whether a declaration is visible to name lookup.
+///
+/// This routine determines whether the declaration D is visible in the current
+/// lookup context, taking into account the current template instantiation
+/// stack. During template instantiation, a declaration is visible if it is
+/// visible from a module containing any entity on the template instantiation
+/// path (by instantiating a template, you allow it to see the declarations that
+/// your module can see, including those later on in your module).
+bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
+ assert(D->isHidden() && !SemaRef.ActiveTemplateInstantiations.empty() &&
+ "should not call this: not in slow case");
+ Module *DeclModule = D->getOwningModule();
+ assert(DeclModule && "hidden decl not from a module");
+
+ // Find the extra places where we need to look.
+ llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules();
+ if (LookupModules.empty())
+ return false;
+
+ // If our lookup set contains the decl's module, it's visible.
+ if (LookupModules.count(DeclModule))
+ return true;
+
+ // If the declaration isn't exported, it's not visible in any other module.
+ if (D->isModulePrivate())
+ return false;
+
+ // Check whether DeclModule is transitively exported to an import of
+ // the lookup set.
+ for (llvm::DenseSet<Module *>::iterator I = LookupModules.begin(),
+ E = LookupModules.end();
+ I != E; ++I)
+ if ((*I)->isModuleVisible(DeclModule))
+ return true;
+ return false;
+}
+
/// \brief Retrieve the visible declaration corresponding to D, if any.
///
/// This routine determines whether the declaration D is visible in the current
/// module, with the current imports. If not, it checks whether any
/// redeclaration of D is visible, and if so, returns that declaration.
-///
+///
/// \returns D, or a visible previous declaration of D, whichever is more recent
/// and visible. If no declaration of D is visible, returns null.
-static NamedDecl *getVisibleDecl(NamedDecl *D) {
- if (LookupResult::isVisible(D))
- return D;
-
+static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
+ assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
+
for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end();
RD != RDEnd; ++RD) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*RD)) {
- if (LookupResult::isVisible(ND))
+ if (LookupResult::isVisible(SemaRef, ND))
return ND;
}
}
-
+
return 0;
}
+NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
+ return findAcceptableDecl(SemaRef, D);
+}
+
/// @brief Perform unqualified name lookup starting from a given
/// scope.
///
@@ -1161,13 +1333,12 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (NameKind == Sema::LookupRedeclarationWithLinkage) {
// Find the nearest non-transparent declaration scope.
while (!(S->getFlags() & Scope::DeclScope) ||
- (S->getEntity() &&
- static_cast<DeclContext *>(S->getEntity())
- ->isTransparentContext()))
+ (S->getEntity() && S->getEntity()->isTransparentContext()))
S = S->getParent();
}
- unsigned IDNS = R.getIdentifierNamespace();
+ // When performing a scope lookup, we want to find local extern decls.
+ FindLocalExternScope FindLocals(R);
// Scan up the scope chain looking for a decl that matches this
// identifier that is in the appropriate namespace. This search
@@ -1178,7 +1349,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
IEnd = IdResolver.end();
I != IEnd; ++I)
- if ((*I)->isInIdentifierNamespace(IDNS)) {
+ if (NamedDecl *D = R.getAcceptableDecl(*I)) {
if (NameKind == LookupRedeclarationWithLinkage) {
// Determine whether this (or a previous) declaration is
// out-of-scope.
@@ -1187,19 +1358,15 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// If we found something outside of our starting scope that
// does not have linkage, skip it.
- if (LeftStartingScope && !((*I)->hasLinkage()))
+ if (LeftStartingScope && !((*I)->hasLinkage())) {
+ R.setShadowed();
continue;
+ }
}
else if (NameKind == LookupObjCImplicitSelfParam &&
!isa<ImplicitParamDecl>(*I))
continue;
-
- // If this declaration is module-private and it came from an AST
- // file, we can't see it.
- NamedDecl *D = R.isHiddenDeclarationVisible()? *I : getVisibleDecl(*I);
- if (!D)
- continue;
-
+
R.addDecl(D);
// Check whether there are any other declarations with the same name
@@ -1234,18 +1401,15 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (!LastDC->Equals(DC))
break;
}
-
- // If the declaration isn't in the right namespace, skip it.
- if (!(*LastI)->isInIdentifierNamespace(IDNS))
- continue;
-
- D = R.isHiddenDeclarationVisible()? *LastI : getVisibleDecl(*LastI);
- if (D)
- R.addDecl(D);
+
+ // If the declaration is in the right namespace and visible, add it.
+ if (NamedDecl *LastD = R.getAcceptableDecl(*LastI))
+ R.addDecl(LastD);
}
R.resolveKind();
}
+
return true;
}
} else {
@@ -1330,8 +1494,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
bool Found = false;
while (!Queue.empty()) {
- NamespaceDecl *ND = Queue.back();
- Queue.pop_back();
+ NamespaceDecl *ND = Queue.pop_back_val();
// We go through some convolutions here to avoid copying results
// between LookupResults.
@@ -1510,6 +1673,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupOrdinaryName:
case LookupMemberName:
case LookupRedeclarationWithLinkage:
+ case LookupLocalFriendName:
BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
break;
@@ -1681,9 +1845,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
/// from name lookup.
///
/// \param Result The result of the ambiguous lookup to be diagnosed.
-///
-/// \returns true
-bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
+void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
DeclarationName Name = Result.getLookupName();
@@ -1704,8 +1866,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
++Found;
Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
-
- return true;
+ break;
}
case LookupResult::AmbiguousBaseSubobjectTypes: {
@@ -1721,8 +1882,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
if (DeclsPrinted.insert(D).second)
Diag(D->getLocation(), diag::note_ambiguous_member_found);
}
-
- return true;
+ break;
}
case LookupResult::AmbiguousTagHiding: {
@@ -1748,8 +1908,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
F.erase();
}
F.done();
-
- return true;
+ break;
}
case LookupResult::AmbiguousReference: {
@@ -1758,12 +1917,9 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
LookupResult::iterator DI = Result.begin(), DE = Result.end();
for (; DI != DE; ++DI)
Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
-
- return true;
+ break;
}
}
-
- llvm_unreachable("unknown ambiguity kind");
}
namespace {
@@ -1922,8 +2078,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
Bases.push_back(Class);
while (!Bases.empty()) {
// Pop this class off the stack.
- Class = Bases.back();
- Bases.pop_back();
+ Class = Bases.pop_back_val();
// Visit the base classes.
for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
@@ -2107,9 +2262,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
continue;
}
- if (Queue.empty()) break;
- T = Queue.back();
- Queue.pop_back();
+ if (Queue.empty())
+ break;
+ T = Queue.pop_back_val();
}
}
@@ -2120,11 +2275,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
/// This routine computes the sets of associated classes and associated
/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
-void
-Sema::FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
- llvm::ArrayRef<Expr *> Args,
- AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses) {
+void Sema::FindAssociatedClassesAndNamespaces(
+ SourceLocation InstantiationLoc, ArrayRef<Expr *> Args,
+ AssociatedNamespaceSet &AssociatedNamespaces,
+ AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
@@ -2393,11 +2547,17 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// will always be a (possibly implicit) declaration to shadow any others.
OverloadCandidateSet OCS((SourceLocation()));
DeclContext::lookup_result R = RD->lookup(Name);
-
assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
- Decl *Cand = *I;
+
+ // Copy the candidates as our processing of them may load new declarations
+ // from an external source and invalidate lookup_result.
+ SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
+
+ for (SmallVectorImpl<NamedDecl *>::iterator I = Candidates.begin(),
+ E = Candidates.end();
+ I != E; ++I) {
+ NamedDecl *Cand = *I;
if (Cand->isInvalidDecl())
continue;
@@ -2565,7 +2725,8 @@ CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
Sema::LiteralOperatorLookupResult
Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
- bool AllowRawAndTemplate) {
+ bool AllowRaw, bool AllowTemplate,
+ bool AllowStringTemplate) {
LookupName(R, S);
assert(R.getResultKind() != LookupResult::Ambiguous &&
"literal operator lookup can't be ambiguous");
@@ -2573,8 +2734,9 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
// Filter the lookup results appropriately.
LookupResult::Filter F = R.makeFilter();
- bool FoundTemplate = false;
bool FoundRaw = false;
+ bool FoundTemplate = false;
+ bool FoundStringTemplate = false;
bool FoundExactMatch = false;
while (F.hasNext()) {
@@ -2582,16 +2744,17 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
D = USD->getTargetDecl();
- bool IsTemplate = isa<FunctionTemplateDecl>(D);
- bool IsRaw = false;
- bool IsExactMatch = false;
-
// If the declaration we found is invalid, skip it.
if (D->isInvalidDecl()) {
F.erase();
continue;
}
+ bool IsRaw = false;
+ bool IsTemplate = false;
+ bool IsStringTemplate = false;
+ bool IsExactMatch = false;
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getNumParams() == 1 &&
FD->getParamDecl(0)->getType()->getAs<PointerType>())
@@ -2607,19 +2770,31 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
}
}
}
+ if (FunctionTemplateDecl *FD = dyn_cast<FunctionTemplateDecl>(D)) {
+ TemplateParameterList *Params = FD->getTemplateParameters();
+ if (Params->size() == 1)
+ IsTemplate = true;
+ else
+ IsStringTemplate = true;
+ }
if (IsExactMatch) {
FoundExactMatch = true;
- AllowRawAndTemplate = false;
- if (FoundRaw || FoundTemplate) {
+ AllowRaw = false;
+ AllowTemplate = false;
+ AllowStringTemplate = false;
+ if (FoundRaw || FoundTemplate || FoundStringTemplate) {
// Go through again and remove the raw and template decls we've
// already found.
F.restart();
- FoundRaw = FoundTemplate = false;
+ FoundRaw = FoundTemplate = FoundStringTemplate = false;
}
- } else if (AllowRawAndTemplate && (IsTemplate || IsRaw)) {
- FoundTemplate |= IsTemplate;
- FoundRaw |= IsRaw;
+ } else if (AllowRaw && IsRaw) {
+ FoundRaw = true;
+ } else if (AllowTemplate && IsTemplate) {
+ FoundTemplate = true;
+ } else if (AllowStringTemplate && IsStringTemplate) {
+ FoundStringTemplate = true;
} else {
F.erase();
}
@@ -2654,10 +2829,14 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (FoundTemplate)
return LOLR_Template;
+ if (FoundStringTemplate)
+ 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()) << AllowRawAndTemplate;
+ << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
+ << (AllowTemplate || AllowStringTemplate);
return LOLR_Error;
}
@@ -2699,8 +2878,7 @@ void ADLResult::insert(NamedDecl *New) {
}
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc,
- llvm::ArrayRef<Expr *> Args,
+ SourceLocation Loc, ArrayRef<Expr *> Args,
ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
@@ -2748,9 +2926,21 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
NamedDecl *D = *I;
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
- if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
- DeclContext *LexDC = D->getLexicalDeclContext();
- if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) {
+ // If it's neither ordinarily visible nor a friend, we can't find it.
+ if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0)
+ continue;
+
+ bool DeclaredInAssociatedClass = false;
+ for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) {
+ DeclContext *LexDC = DI->getLexicalDeclContext();
+ if (isa<CXXRecordDecl>(LexDC) &&
+ AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) {
+ DeclaredInAssociatedClass = true;
+ break;
+ }
+ }
+ if (!DeclaredInAssociatedClass)
continue;
}
@@ -2775,6 +2965,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
//----------------------------------------------------------------------------
VisibleDeclConsumer::~VisibleDeclConsumer() { }
+bool VisibleDeclConsumer::includeHiddenDecls() const { return false; }
+
namespace {
class ShadowContextRAII;
@@ -3038,8 +3230,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (!S->getEntity() ||
(!S->getParent() &&
- !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) ||
- ((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ !Visited.alreadyVisitedContext(S->getEntity())) ||
+ (S->getEntity())->isFunctionOrMethod()) {
+ FindLocalExternScope FindLocals(Result);
// Walk through the declarations in this Scope.
for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
@@ -3057,7 +3250,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
// where we hit the context stored in the next outer scope.
- Entity = (DeclContext *)S->getEntity();
+ Entity = S->getEntity();
DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
@@ -3069,7 +3262,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
Result.getNameLoc(), Sema::LookupMemberName);
if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited);
+ /*InBaseClass=*/false, Consumer, Visited);
}
}
@@ -3134,6 +3327,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
// Look for visible declarations.
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
VisibleDeclsRecord Visited;
if (!IncludeGlobalScope)
Visited.visitedContext(Context.getTranslationUnitDecl());
@@ -3145,6 +3339,7 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope) {
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
VisibleDeclsRecord Visited;
if (!IncludeGlobalScope)
Visited.visitedContext(Context.getTranslationUnitDecl());
@@ -3214,14 +3409,16 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
public:
explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
: Typo(Typo->getName()),
- SemaRef(SemaRef) { }
+ SemaRef(SemaRef) {}
+
+ bool includeHiddenDecls() const { return true; }
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass);
void FoundName(StringRef Name);
void addKeywordResult(StringRef Keyword);
- void addName(StringRef Name, NamedDecl *ND, unsigned Distance,
- NestedNameSpecifier *NNS=NULL, bool isKeyword=false);
+ void addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS = NULL,
+ bool isKeyword = false);
void addCorrection(TypoCorrection Correction);
typedef TypoResultsMap::iterator result_iterator;
@@ -3265,37 +3462,42 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
if (!Name)
return;
+ // Only consider visible declarations and declarations from modules with
+ // names that exactly match.
+ if (!LookupResult::isVisible(SemaRef, ND) && Name->getName() != Typo &&
+ !findAcceptableDecl(SemaRef, ND))
+ return;
+
FoundName(Name->getName());
}
void TypoCorrectionConsumer::FoundName(StringRef Name) {
- // Use a simple length-based heuristic to determine the minimum possible
- // edit distance. If the minimum isn't good enough, bail out early.
- unsigned MinED = abs((int)Name.size() - (int)Typo.size());
- if (MinED && Typo.size() / MinED < 3)
- return;
-
- // Compute an upper bound on the allowable edit distance, so that the
- // edit-distance algorithm can short-circuit.
- unsigned UpperBound = (Typo.size() + 2) / 3;
-
// Compute the edit distance between the typo and the name of this
// entity, and add the identifier to the list of results.
- addName(Name, NULL, Typo.edit_distance(Name, true, UpperBound));
+ addName(Name, NULL);
}
void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) {
// Compute the edit distance between the typo and this keyword,
// and add the keyword to the list of results.
- addName(Keyword, NULL, Typo.edit_distance(Keyword), NULL, true);
+ addName(Keyword, NULL, NULL, true);
}
-void TypoCorrectionConsumer::addName(StringRef Name,
- NamedDecl *ND,
- unsigned Distance,
- NestedNameSpecifier *NNS,
- bool isKeyword) {
- TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance);
+void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND,
+ NestedNameSpecifier *NNS, bool isKeyword) {
+ // Use a simple length-based heuristic to determine the minimum possible
+ // edit distance. If the minimum isn't good enough, bail out early.
+ unsigned MinED = abs((int)Name.size() - (int)Typo.size());
+ if (MinED && Typo.size() / MinED < 3)
+ return;
+
+ // Compute an upper bound on the allowable edit distance, so that the
+ // edit-distance algorithm can short-circuit.
+ unsigned UpperBound = (Typo.size() + 2) / 3 + 1;
+ unsigned ED = Typo.edit_distance(Name, true, UpperBound);
+ if (ED >= UpperBound) return;
+
+ TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED);
if (isKeyword) TC.makeKeyword();
addCorrection(TC);
}
@@ -3388,6 +3590,7 @@ typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
class NamespaceSpecifierSet {
ASTContext &Context;
DeclContextList CurContextChain;
+ std::string CurNameSpecifier;
SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
bool isSorted;
@@ -3406,10 +3609,14 @@ class NamespaceSpecifierSet {
NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
CXXScopeSpec *CurScopeSpec)
: Context(Context), CurContextChain(BuildContextChain(CurContext)),
- isSorted(true) {
- if (CurScopeSpec && CurScopeSpec->getScopeRep())
- getNestedNameSpecifierIdentifiers(CurScopeSpec->getScopeRep(),
- CurNameSpecifierIdentifiers);
+ isSorted(false) {
+ if (NestedNameSpecifier *NNS =
+ CurScopeSpec ? CurScopeSpec->getScopeRep() : 0) {
+ llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier);
+ NNS->print(SpecifierOStream, Context.getPrintingPolicy());
+
+ getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers);
+ }
// Build the list of identifiers that would be used for an absolute
// (from the global context) NestedNameSpecifier referring to the current
// context.
@@ -3419,11 +3626,17 @@ class NamespaceSpecifierSet {
if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C))
CurContextIdentifiers.push_back(ND->getIdentifier());
}
+
+ // Add the global context as a NestedNameSpecifier
+ Distances.insert(1);
+ DistanceMap[1].push_back(
+ SpecifierInfo(cast<DeclContext>(Context.getTranslationUnitDecl()),
+ NestedNameSpecifier::GlobalSpecifier(Context), 1));
}
- /// \brief Add the namespace to the set, computing the corresponding
- /// NestedNameSpecifier and its distance in the process.
- void AddNamespace(NamespaceDecl *ND);
+ /// \brief Add the DeclContext (a namespace or record) to the set, computing
+ /// the corresponding NestedNameSpecifier and its distance in the process.
+ void AddNameSpecifier(DeclContext *Ctx);
typedef SpecifierInfoList::iterator iterator;
iterator begin() {
@@ -3456,8 +3669,8 @@ void NamespaceSpecifierSet::SortNamespaces() {
std::sort(sortedDistances.begin(), sortedDistances.end());
Specifiers.clear();
- for (SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
- DIEnd = sortedDistances.end();
+ for (SmallVectorImpl<unsigned>::iterator DI = sortedDistances.begin(),
+ DIEnd = sortedDistances.end();
DI != DIEnd; ++DI) {
SpecifierInfoList &SpecList = DistanceMap[*DI];
Specifiers.append(SpecList.begin(), SpecList.end());
@@ -3466,8 +3679,26 @@ void NamespaceSpecifierSet::SortNamespaces() {
isSorted = true;
}
-void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
- DeclContext *Ctx = cast<DeclContext>(ND);
+static unsigned BuildNestedNameSpecifier(ASTContext &Context,
+ DeclContextList &DeclChain,
+ NestedNameSpecifier *&NNS) {
+ unsigned NumSpecifiers = 0;
+ for (DeclContextList::reverse_iterator C = DeclChain.rbegin(),
+ CEnd = DeclChain.rend();
+ C != CEnd; ++C) {
+ if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) {
+ NNS = NestedNameSpecifier::Create(Context, NNS, ND);
+ ++NumSpecifiers;
+ } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) {
+ NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(),
+ RD->getTypeForDecl());
+ ++NumSpecifiers;
+ }
+ }
+ return NumSpecifiers;
+}
+
+void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
NestedNameSpecifier *NNS = NULL;
unsigned NumSpecifiers = 0;
DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
@@ -3481,29 +3712,37 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
NamespaceDeclChain.pop_back();
}
+ // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
+ NumSpecifiers = BuildNestedNameSpecifier(Context, NamespaceDeclChain, NNS);
+
// Add an explicit leading '::' specifier if needed.
- if (NamespaceDecl *ND =
- NamespaceDeclChain.empty() ? NULL :
- dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) {
+ if (NamespaceDeclChain.empty()) {
+ // Rebuild the NestedNameSpecifier as a globally-qualified specifier.
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ NumSpecifiers =
+ BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
+ } else if (NamedDecl *ND =
+ dyn_cast_or_null<NamedDecl>(NamespaceDeclChain.back())) {
IdentifierInfo *Name = ND->getIdentifier();
- if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
- Name) != CurContextIdentifiers.end() ||
- std::find(CurNameSpecifierIdentifiers.begin(),
+ bool SameNameSpecifier = false;
+ if (std::find(CurNameSpecifierIdentifiers.begin(),
CurNameSpecifierIdentifiers.end(),
Name) != CurNameSpecifierIdentifiers.end()) {
- NamespaceDeclChain = FullNamespaceDeclChain;
- NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ std::string NewNameSpecifier;
+ llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier);
+ SmallVector<const IdentifierInfo *, 4> NewNameSpecifierIdentifiers;
+ getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
+ NNS->print(SpecifierOStream, Context.getPrintingPolicy());
+ SpecifierOStream.flush();
+ SameNameSpecifier = NewNameSpecifier == CurNameSpecifier;
}
- }
-
- // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
- for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
- CEnd = NamespaceDeclChain.rend();
- C != CEnd; ++C) {
- NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C);
- if (ND) {
- NNS = NestedNameSpecifier::Create(Context, NNS, ND);
- ++NumSpecifiers;
+ if (SameNameSpecifier ||
+ std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
+ Name) != CurContextIdentifiers.end()) {
+ // Rebuild the NestedNameSpecifier as a globally-qualified specifier.
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ NumSpecifiers =
+ BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
}
}
@@ -3515,8 +3754,8 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers;
getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
NumSpecifiers = llvm::ComputeEditDistance(
- llvm::ArrayRef<const IdentifierInfo*>(CurNameSpecifierIdentifiers),
- llvm::ArrayRef<const IdentifierInfo*>(NewNameSpecifierIdentifiers));
+ ArrayRef<const IdentifierInfo *>(CurNameSpecifierIdentifiers),
+ ArrayRef<const IdentifierInfo *>(NewNameSpecifierIdentifiers));
}
isSorted = false;
@@ -3531,10 +3770,12 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
Scope *S, CXXScopeSpec *SS,
DeclContext *MemberContext,
bool EnteringContext,
- bool isObjCIvarLookup) {
+ bool isObjCIvarLookup,
+ bool FindHidden) {
Res.suppressDiagnostics();
Res.clear();
Res.setLookupName(Name);
+ Res.setAllowHidden(FindHidden);
if (MemberContext) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) {
if (isObjCIvarLookup) {
@@ -3593,7 +3834,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
if (CCC.WantTypeSpecifiers) {
// Add type-specifier keywords to the set of results.
- const char *CTypeSpecs[] = {
+ static const char *const CTypeSpecs[] = {
"char", "const", "double", "enum", "float", "int", "long", "short",
"signed", "struct", "union", "unsigned", "void", "volatile",
"_Complex", "_Imaginary",
@@ -3601,7 +3842,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
"extern", "inline", "static", "typedef"
};
- const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
+ const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs);
for (unsigned I = 0; I != NumCTypeSpecs; ++I)
Consumer.addKeywordResult(CTypeSpecs[I]);
@@ -3645,10 +3886,10 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
}
if (SemaRef.getLangOpts().CPlusPlus) {
- const char *CXXExprs[] = {
+ static const char *const CXXExprs[] = {
"delete", "new", "operator", "throw", "typeid"
};
- const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
+ const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs);
for (unsigned I = 0; I != NumCXXExprs; ++I)
Consumer.addKeywordResult(CXXExprs[I]);
@@ -3672,9 +3913,9 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
if (CCC.WantRemainingKeywords) {
if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
// Statements.
- const char *CStmts[] = {
+ static const char *const CStmts[] = {
"do", "else", "for", "goto", "if", "return", "switch", "while" };
- const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
+ const unsigned NumCStmts = llvm::array_lengthof(CStmts);
for (unsigned I = 0; I != NumCStmts; ++I)
Consumer.addKeywordResult(CStmts[I]);
@@ -3725,6 +3966,50 @@ static bool isCandidateViable(CorrectionCandidateCallback &CCC,
return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance;
}
+/// \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.
+static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC,
+ DeclarationName TypoName) {
+ 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)
+ return;
+
+ llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI);
+ bool AnyVisibleDecls = !NewDecls.empty();
+
+ for (/**/; DI != DE; ++DI) {
+ NamedDecl *VisibleDecl = *DI;
+ if (!LookupResult::isVisible(SemaRef, *DI))
+ VisibleDecl = findAcceptableDecl(SemaRef, *DI);
+
+ if (VisibleDecl) {
+ if (!AnyVisibleDecls) {
+ // Found a visible decl, discard all hidden ones.
+ AnyVisibleDecls = true;
+ NewDecls.clear();
+ }
+ NewDecls.push_back(VisibleDecl);
+ } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate())
+ NewDecls.push_back(*DI);
+ }
+
+ if (NewDecls.empty())
+ TC = TypoCorrection();
+ else {
+ TC.setCorrectionDecls(NewDecls);
+ TC.setRequiresImport(!AnyVisibleDecls);
+ }
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
@@ -3762,8 +4047,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
CorrectionCandidateCallback &CCC,
DeclContext *MemberContext,
bool EnteringContext,
- const ObjCObjectPointerType *OPT) {
- if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking)
+ const ObjCObjectPointerType *OPT,
+ bool RecordFailure) {
+ // Always let the ExternalSource have the first chance at correction, even
+ // if we would otherwise have given up.
+ if (ExternalSource) {
+ if (TypoCorrection Correction = ExternalSource->CorrectTypo(
+ TypoName, LookupKind, S, SS, CCC, MemberContext, EnteringContext, OPT))
+ return Correction;
+ }
+
+ if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking ||
+ DisableTypoCorrection)
return TypoCorrection();
// In Microsoft mode, don't perform typo correction in a template member
@@ -3792,6 +4087,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier())
return TypoCorrection();
+ // Abort if typo correction already failed for this specific typo.
+ IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo);
+ if (locs != TypoCorrectionFailures.end() &&
+ locs->second.count(TypoName.getLoc()))
+ return TypoCorrection();
+
+ // Don't try to correct the identifier "vector" when in AltiVec mode.
+ // TODO: Figure out why typo correction misbehaves in this case, fix it, and
+ // remove this workaround.
+ if (getLangOpts().AltiVec && Typo->isStr("vector"))
+ return TypoCorrection();
+
NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
TypoCorrectionConsumer Consumer(*this, Typo);
@@ -3836,8 +4143,15 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// keyword case, we'll end up adding the keyword below.
if (Cached->second) {
if (!Cached->second.isKeyword() &&
- isCandidateViable(CCC, Cached->second))
- Consumer.addCorrection(Cached->second);
+ isCandidateViable(CCC, Cached->second)) {
+ // Do not use correction that is unaccessible in the given scope.
+ NamedDecl *CorrectionDecl = Cached->second.getCorrectionDecl();
+ DeclarationNameInfo NameInfo(CorrectionDecl->getDeclName(),
+ CorrectionDecl->getLocation());
+ LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ if (LookupName(R, S))
+ Consumer.addCorrection(Cached->second);
+ }
} else {
// Only honor no-correction cache hits when a callback that will validate
// correction candidates is not being used.
@@ -3858,11 +4172,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// corrections.
bool SearchNamespaces
= getLangOpts().CPlusPlus &&
- (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace()));
- // In a few cases we *only* want to search for corrections bases on just
+ (IsUnqualifiedLookup || (SS && SS->isSet()));
+ // In a few cases we *only* want to search for corrections based on just
// adding or changing the nested name specifier.
- bool AllowOnlyNNSChanges = Typo->getName().size() < 3;
-
+ unsigned TypoLen = Typo->getName().size();
+ bool AllowOnlyNNSChanges = TypoLen < 3;
+
if (IsUnqualifiedLookup || SearchNamespaces) {
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
@@ -3890,24 +4205,16 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
AddKeywordsToConsumer(*this, Consumer, S, CCC, SS && SS->isNotEmpty());
// If we haven't found anything, we're done.
- if (Consumer.empty()) {
- // If this was an unqualified lookup, note that no correction was found.
- if (IsUnqualifiedLookup)
- (void)UnqualifiedTyposCorrected[Typo];
-
- return TypoCorrection();
- }
+ if (Consumer.empty())
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
+ IsUnqualifiedLookup);
// Make sure the best edit distance (prior to adding any namespace qualifiers)
// is not more that about a third of the length of the typo's identifier.
unsigned ED = Consumer.getBestEditDistance(true);
- if (ED > 0 && Typo->getName().size() / ED < 3) {
- // If this was an unqualified lookup, note that no correction was found.
- if (IsUnqualifiedLookup)
- (void)UnqualifiedTyposCorrected[Typo];
-
- return TypoCorrection();
- }
+ if (ED > 0 && TypoLen / ED < 3)
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
+ IsUnqualifiedLookup);
// Build the NestedNameSpecifiers for the KnownNamespaces, if we're going
// to search those namespaces.
@@ -3920,12 +4227,24 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
KnownNamespaces[ExternalKnownNamespaces[I]] = true;
}
-
- for (llvm::MapVector<NamespaceDecl*, bool>::iterator
+
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
KNI = KnownNamespaces.begin(),
KNIEnd = KnownNamespaces.end();
KNI != KNIEnd; ++KNI)
- Namespaces.AddNamespace(KNI->first);
+ Namespaces.AddNameSpecifier(KNI->first);
+
+ for (ASTContext::type_iterator TI = Context.types_begin(),
+ TIEnd = Context.types_end();
+ TI != TIEnd; ++TI) {
+ if (CXXRecordDecl *CD = (*TI)->getAsCXXRecordDecl()) {
+ CD = CD->getCanonicalDecl();
+ if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() &&
+ !CD->isUnion() &&
+ (CD->isBeingDefined() || CD->isCompleteDefinition()))
+ Namespaces.AddNameSpecifier(CD);
+ }
+ }
}
// Weed out any names that could not be found by name lookup or, if a
@@ -3935,7 +4254,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
TmpRes.suppressDiagnostics();
while (!Consumer.empty()) {
TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
- unsigned ED = DI->first;
for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
IEnd = DI->second.end();
I != IEnd; /* Increment in loop. */) {
@@ -3976,13 +4294,31 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Perform name lookup on this name.
TypoCorrection &Candidate = I->second.front();
IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
- LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
- EnteringContext, CCC.IsObjCIvarLookup);
+ DeclContext *TempMemberContext = MemberContext;
+ CXXScopeSpec *TempSS = SS;
+retry_lookup:
+ LookupPotentialTypoResult(*this, TmpRes, Name, S, TempSS,
+ TempMemberContext, EnteringContext,
+ CCC.IsObjCIvarLookup,
+ Name == TypoName.getName() &&
+ !Candidate.WillReplaceSpecifier());
switch (TmpRes.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundUnresolvedValue:
+ if (TempSS) {
+ // Immediately retry the lookup without the given CXXScopeSpec
+ TempSS = NULL;
+ Candidate.WillReplaceSpecifier(true);
+ goto retry_lookup;
+ }
+ if (TempMemberContext) {
+ if (SS && !TempSS)
+ TempSS = SS;
+ TempMemberContext = NULL;
+ goto retry_lookup;
+ }
QualifiedResults.push_back(Candidate);
// We didn't find this name in our scope, or didn't like what we found;
// ignore it.
@@ -3996,7 +4332,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
case LookupResult::Ambiguous:
// We don't deal with ambiguities.
- return TypoCorrection();
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
case LookupResult::FoundOverloaded: {
TypoCorrectionConsumer::result_iterator Prev = I;
@@ -4006,8 +4342,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
TRD != TRDEnd; ++TRD)
Candidate.addCorrectionDecl(*TRD);
++I;
- if (!isCandidateViable(CCC, Candidate))
+ if (!isCandidateViable(CCC, Candidate)) {
+ QualifiedResults.push_back(Candidate);
DI->second.erase(Prev);
+ }
break;
}
@@ -4015,8 +4353,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
TypoCorrectionConsumer::result_iterator Prev = I;
Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
++I;
- if (!isCandidateViable(CCC, Candidate))
+ if (!isCandidateViable(CCC, Candidate)) {
+ QualifiedResults.push_back(Candidate);
DI->second.erase(Prev);
+ }
break;
}
@@ -4025,7 +4365,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (DI->second.empty())
Consumer.erase(DI);
- else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !ED)
+ else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !DI->first)
// If there are results in the closest possible bucket, stop
break;
@@ -4040,10 +4380,31 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
NIEnd = Namespaces.end();
NI != NIEnd; ++NI) {
DeclContext *Ctx = NI->DeclCtx;
+ const Type *NSType = NI->NameSpecifier->getAsType();
+
+ // If the current NestedNameSpecifier refers to a class and the
+ // current correction candidate is the name of that class, then skip
+ // it as it is unlikely a qualified version of the class' constructor
+ // is an appropriate correction.
+ if (CXXRecordDecl *NSDecl =
+ NSType ? NSType->getAsCXXRecordDecl() : 0) {
+ if (NSDecl->getIdentifier() == QRI->getCorrectionAsIdentifierInfo())
+ continue;
+ }
- // FIXME: Stop searching once the namespaces are too far away to create
- // acceptable corrections for this identifier (since the namespaces
- // are sorted in ascending order by edit distance).
+ TypoCorrection TC(*QRI);
+ TC.ClearCorrectionDecls();
+ TC.setCorrectionSpecifier(NI->NameSpecifier);
+ TC.setQualifierDistance(NI->EditDistance);
+ TC.setCallbackDistance(0); // Reset the callback distance
+
+ // If the current correction candidate and namespace combination are
+ // too far away from the original typo based on the normalized edit
+ // distance, then skip performing a qualified name lookup.
+ unsigned TmpED = TC.getEditDistance(true);
+ if (QRI->getCorrectionAsIdentifierInfo() != Typo &&
+ TmpED && TypoLen / TmpED < 3)
+ continue;
TmpRes.clear();
TmpRes.setLookupName(QRI->getCorrectionAsIdentifierInfo());
@@ -4052,23 +4413,30 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Any corrections added below will be validated in subsequent
// iterations of the main while() loop over the Consumer's contents.
switch (TmpRes.getResultKind()) {
- case LookupResult::Found: {
- TypoCorrection TC(*QRI);
- TC.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
- TC.setCorrectionSpecifier(NI->NameSpecifier);
- TC.setQualifierDistance(NI->EditDistance);
- Consumer.addCorrection(TC);
- break;
- }
+ case LookupResult::Found:
case LookupResult::FoundOverloaded: {
- TypoCorrection TC(*QRI);
- TC.setCorrectionSpecifier(NI->NameSpecifier);
- TC.setQualifierDistance(NI->EditDistance);
+ if (SS && SS->isValid()) {
+ std::string NewQualified = TC.getAsString(getLangOpts());
+ std::string OldQualified;
+ llvm::raw_string_ostream OldOStream(OldQualified);
+ SS->getScopeRep()->print(OldOStream, getPrintingPolicy());
+ OldOStream << TypoName;
+ // If correction candidate would be an identical written qualified
+ // identifer, then the existing CXXScopeSpec probably included a
+ // typedef that didn't get accounted for properly.
+ if (OldOStream.str() == NewQualified)
+ break;
+ }
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
- TRD != TRDEnd; ++TRD)
- TC.addCorrectionDecl(*TRD);
- Consumer.addCorrection(TC);
+ TRD != TRDEnd; ++TRD) {
+ if (CheckMemberAccess(TC.getCorrectionRange().getBegin(),
+ NSType ? NSType->getAsCXXRecordDecl() : 0,
+ TRD.getPair()) == AR_accessible)
+ TC.addCorrectionDecl(*TRD);
+ }
+ if (TC.isResolved())
+ Consumer.addCorrection(TC);
break;
}
case LookupResult::NotFound:
@@ -4085,30 +4453,31 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
}
// No corrections remain...
- if (Consumer.empty()) return TypoCorrection();
+ if (Consumer.empty())
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
TypoResultsMap &BestResults = Consumer.getBestResults();
ED = Consumer.getBestEditDistance(true);
- if (!AllowOnlyNNSChanges && ED > 0 && Typo->getName().size() / ED < 3) {
+ if (!AllowOnlyNNSChanges && ED > 0 && TypoLen / ED < 3) {
// If this was an unqualified lookup and we believe the callback
// object wouldn't have filtered out possible corrections, note
// that no correction was found.
- if (IsUnqualifiedLookup && !ValidatingCallback)
- (void)UnqualifiedTyposCorrected[Typo];
-
- return TypoCorrection();
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
+ IsUnqualifiedLookup && !ValidatingCallback);
}
// If only a single name remains, return that result.
if (BestResults.size() == 1) {
const TypoResultList &CorrectionList = BestResults.begin()->second;
const TypoCorrection &Result = CorrectionList.front();
- if (CorrectionList.size() != 1) return TypoCorrection();
+ if (CorrectionList.size() != 1)
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
- if (ED == 0 && Result.isKeyword()) return TypoCorrection();
+ if (ED == 0 && Result.isKeyword())
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
@@ -4116,6 +4485,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
TypoCorrection TC = Result;
TC.setCorrectionRange(SS, TypoName);
+ checkCorrectionVisibility(*this, TC, TypoName.getName());
return TC;
}
else if (BestResults.size() > 1
@@ -4130,7 +4500,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
- if (ED == 0) return TypoCorrection();
+ if (ED == 0)
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
@@ -4146,7 +4517,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (IsUnqualifiedLookup && !ValidatingCallback)
(void)UnqualifiedTyposCorrected[Typo];
- return TypoCorrection();
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
}
void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
@@ -4166,7 +4537,7 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const {
std::string tmpBuffer;
llvm::raw_string_ostream PrefixOStream(tmpBuffer);
CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO));
- CorrectionName.printName(PrefixOStream);
+ PrefixOStream << CorrectionName;
return PrefixOStream.str();
}
@@ -4190,3 +4561,122 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid
return WantTypeSpecifiers;
}
+
+FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
+ bool HasExplicitTemplateArgs)
+ : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) {
+ WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
+ WantRemainingKeywords = false;
+}
+
+bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) {
+ if (!candidate.getCorrectionDecl())
+ return candidate.isKeyword();
+
+ for (TypoCorrection::const_decl_iterator DI = candidate.begin(),
+ DIEnd = candidate.end();
+ DI != DIEnd; ++DI) {
+ FunctionDecl *FD = 0;
+ NamedDecl *ND = (*DI)->getUnderlyingDecl();
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ FD = FTD->getTemplatedDecl();
+ if (!HasExplicitTemplateArgs && !FD) {
+ if (!(FD = dyn_cast<FunctionDecl>(ND)) && isa<ValueDecl>(ND)) {
+ // If the Decl is neither a function nor a template function,
+ // determine if it is a pointer or reference to a function. If so,
+ // check against the number of arguments expected for the pointee.
+ QualType ValType = cast<ValueDecl>(ND)->getType();
+ if (ValType->isAnyPointerType() || ValType->isReferenceType())
+ ValType = ValType->getPointeeType();
+ if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>())
+ if (FPT->getNumArgs() == NumArgs)
+ return true;
+ }
+ }
+ if (FD && FD->getNumParams() >= NumArgs &&
+ FD->getMinRequiredArguments() <= NumArgs)
+ return true;
+ }
+ return false;
+}
+
+void Sema::diagnoseTypo(const TypoCorrection &Correction,
+ const PartialDiagnostic &TypoDiag,
+ bool ErrorRecovery) {
+ diagnoseTypo(Correction, TypoDiag, PDiag(diag::note_previous_decl),
+ ErrorRecovery);
+}
+
+/// Find which declaration we should import to provide the definition of
+/// the given declaration.
+static const NamedDecl *getDefinitionToImport(const NamedDecl *D) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getDefinition();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->isDefined(FD) ? FD : 0;
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getDefinition();
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return ID->getDefinition();
+ if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
+ return PD->getDefinition();
+ if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
+ return getDefinitionToImport(TD->getTemplatedDecl());
+ return 0;
+}
+
+/// \brief Diagnose a successfully-corrected typo. Separated from the correction
+/// itself to allow external validation of the result, etc.
+///
+/// \param Correction The result of performing typo correction.
+/// \param TypoDiag The diagnostic to produce. This will have the corrected
+/// string added to it (and usually also a fixit).
+/// \param PrevNote A note to use when indicating the location of the entity to
+/// which we are correcting. Will have the correction string added to it.
+/// \param ErrorRecovery If \c true (the default), the caller is going to
+/// recover from the typo as if the corrected string had been typed.
+/// In this case, \c PDiag must be an error, and we will attach a fixit
+/// to it.
+void Sema::diagnoseTypo(const TypoCorrection &Correction,
+ const PartialDiagnostic &TypoDiag,
+ const PartialDiagnostic &PrevNote,
+ bool ErrorRecovery) {
+ std::string CorrectedStr = Correction.getAsString(getLangOpts());
+ std::string CorrectedQuotedStr = Correction.getQuoted(getLangOpts());
+ FixItHint FixTypo = FixItHint::CreateReplacement(
+ Correction.getCorrectionRange(), CorrectedStr);
+
+ // Maybe we're just missing a module import.
+ if (Correction.requiresImport()) {
+ NamedDecl *Decl = Correction.getCorrectionDecl();
+ assert(Decl && "import required but no declaration to import");
+
+ // Suggest importing a module providing the definition of this entity, if
+ // possible.
+ const NamedDecl *Def = getDefinitionToImport(Decl);
+ if (!Def)
+ Def = Decl;
+ Module *Owner = Def->getOwningModule();
+ assert(Owner && "definition of hidden declaration is not in a module");
+
+ Diag(Correction.getCorrectionRange().getBegin(),
+ diag::err_module_private_declaration)
+ << Def << Owner->getFullModuleName();
+ Diag(Def->getLocation(), diag::note_previous_declaration);
+
+ // Recover by implicitly importing this module.
+ if (!isSFINAEContext() && ErrorRecovery)
+ createImplicitModuleImport(Correction.getCorrectionRange().getBegin(),
+ Owner);
+ return;
+ }
+
+ Diag(Correction.getCorrectionRange().getBegin(), TypoDiag)
+ << CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint());
+
+ NamedDecl *ChosenDecl =
+ Correction.isKeyword() ? 0 : Correction.getCorrectionDecl();
+ if (PrevNote.getDiagID() && ChosenDecl)
+ Diag(ChosenDecl->getLocation(), PrevNote)
+ << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo);
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 91f0881ae09c..d9d9cec1b700 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -126,7 +126,7 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName());
for (unsigned I = 0, N = R.size(); I != N; ++I) {
if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
- S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier());
+ S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true);
return;
}
}
@@ -208,7 +208,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
DeclContext::lookup_result R = Super->lookup(Res->getDeclName());
for (unsigned I = 0, N = R.size(); I != N; ++I) {
if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
- DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier());
+ DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
FoundInSuper = true;
break;
}
@@ -321,6 +321,21 @@ static unsigned getOwnershipRule(unsigned attr) {
ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
}
+static const char *NameOfOwnershipAttribute(unsigned attr) {
+ if (attr & ObjCPropertyDecl::OBJC_PR_assign)
+ return "assign";
+ if (attr & ObjCPropertyDecl::OBJC_PR_retain )
+ return "retain";
+ if (attr & ObjCPropertyDecl::OBJC_PR_copy)
+ return "copy";
+ if (attr & ObjCPropertyDecl::OBJC_PR_weak)
+ return "weak";
+ if (attr & ObjCPropertyDecl::OBJC_PR_strong)
+ return "strong";
+ assert(attr & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ return "unsafe_unretained";
+}
+
ObjCPropertyDecl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
@@ -434,6 +449,8 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// with continuation class's readwrite property attribute!
unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
+ PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
+ PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType());
unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
@@ -442,6 +459,22 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
+ else if (getLangOpts().ObjCAutoRefCount) {
+ QualType PrimaryPropertyQT =
+ Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
+ if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
+ bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0);
+ Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
+ PrimaryPropertyQT.getObjCLifetime();
+ if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
+ !PropertyIsWeak) {
+ Diag(AtLoc, diag::warn_property_implicitly_mismatched);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+
DeclContext *DC = cast<DeclContext>(CCPrimary);
if (!ObjCPropertyDecl::findPropertyDecl(DC,
PIDecl->getDeclName().getAsIdentifierInfo())) {
@@ -529,8 +562,16 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (IDecl->ClassImplementsProtocol(PNSCopying, true))
Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
- if (T->isObjCObjectType())
- Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
+
+ if (T->isObjCObjectType()) {
+ SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd();
+ StarLoc = PP.getLocForEndOfToken(StarLoc);
+ Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
+ << FixItHint::CreateInsertion(StarLoc, "*");
+ T = Context.getObjCObjectPointerType(T);
+ SourceLocation TLoc = TInfo->getTypeLoc().getLocStart();
+ TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);
+ }
DeclContext *DC = cast<DeclContext>(CDecl);
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
@@ -714,73 +755,57 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
return;
}
-/// DiagnoseClassAndClassExtPropertyMismatch - diagnose inconsistant property
-/// attribute declared in primary class and attributes overridden in any of its
-/// class extensions.
+/// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
+/// in inherited protocols with mismatched types. Since any of them can
+/// be candidate for synthesis.
static void
-DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
- ObjCPropertyDecl *property) {
- unsigned Attributes = property->getPropertyAttributesAsWritten();
- bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = ClassDecl->known_extensions_begin(),
- ExtEnd = ClassDecl->known_extensions_end();
- Ext != ExtEnd; ++Ext) {
- ObjCPropertyDecl *ClassExtProperty = 0;
- DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
- for (unsigned I = 0, N = R.size(); I != N; ++I) {
- ClassExtProperty = dyn_cast<ObjCPropertyDecl>(R[0]);
- if (ClassExtProperty)
- break;
- }
-
- if (ClassExtProperty) {
- warn = false;
- unsigned classExtPropertyAttr =
- ClassExtProperty->getPropertyAttributesAsWritten();
- // We are issuing the warning that we postponed because class extensions
- // can override readonly->readwrite and 'setter' attributes originally
- // placed on class's property declaration now make sense in the overridden
- // property.
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
- if (!classExtPropertyAttr ||
- (classExtPropertyAttr &
- (ObjCDeclSpec::DQ_PR_readwrite|
- ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong)))
- continue;
- warn = true;
- break;
- }
- }
+DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
+ ObjCInterfaceDecl *ClassDecl,
+ ObjCPropertyDecl *Property) {
+ ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
+ for (ObjCInterfaceDecl::all_protocol_iterator
+ PI = ClassDecl->all_referenced_protocol_begin(),
+ E = ClassDecl->all_referenced_protocol_end(); PI != E; ++PI) {
+ if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+ PDecl->collectInheritedProtocolProperties(Property, PropMap);
}
- if (warn) {
- unsigned setterAttrs = (ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong);
- if (Attributes & setterAttrs) {
- const char * which =
- (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
- "assign" :
- (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
- "unsafe_unretained" :
- (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
- "copy" :
- (Attributes & ObjCDeclSpec::DQ_PR_retain) ?
- "retain" : "strong";
-
- S.Diag(property->getLocation(),
- diag::warn_objc_property_attr_mutually_exclusive)
- << "readonly" << which;
+ if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
+ while (SDecl) {
+ for (ObjCInterfaceDecl::all_protocol_iterator
+ PI = SDecl->all_referenced_protocol_begin(),
+ E = SDecl->all_referenced_protocol_end(); PI != E; ++PI) {
+ if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+ PDecl->collectInheritedProtocolProperties(Property, PropMap);
+ }
+ SDecl = SDecl->getSuperClass();
}
- }
+ if (PropMap.empty())
+ return;
+ 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;
+ 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();
+ }
+ }
+ }
+ if (!FirsTime && AtLoc.isValid())
+ S.Diag(AtLoc, diag::note_property_synthesize);
}
/// ActOnPropertyImplDecl - This routine performs semantic checks and
@@ -879,8 +904,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
}
}
-
- DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property);
+ if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
+ DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
} else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
@@ -1027,8 +1052,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PropertyIvarType, /*Dinfo=*/0,
ObjCIvarDecl::Private,
(Expr *)0, true);
- if (CompleteTypeErr)
+ if (RequireNonAbstractType(PropertyIvarLoc,
+ PropertyIvarType,
+ diag::err_abstract_type_in_decl,
+ AbstractSynthesizedIvarType)) {
+ Diag(property->getLocation(), diag::note_property_declare);
Ivar->setInvalidDecl();
+ } else if (CompleteTypeErr)
+ Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar);
@@ -1158,6 +1189,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
diag::warn_property_getter_owning_mismatch);
Diag(property->getLocation(), diag::note_property_declare);
}
+ if (getLangOpts().ObjCAutoRefCount && Synthesize)
+ switch (getterMethod->getMethodFamily()) {
+ case OMF_retain:
+ case OMF_retainCount:
+ case OMF_release:
+ case OMF_autorelease:
+ Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)
+ << 1 << getterMethod->getSelector();
+ break;
+ default:
+ break;
+ }
}
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
@@ -1272,31 +1315,41 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
void
Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
- const IdentifierInfo *inheritedName) {
+ const IdentifierInfo *inheritedName,
+ bool OverridingProtocolProperty) {
ObjCPropertyDecl::PropertyAttributeKind CAttr =
- Property->getPropertyAttributes();
+ Property->getPropertyAttributes();
ObjCPropertyDecl::PropertyAttributeKind SAttr =
- SuperProperty->getPropertyAttributes();
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
- && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
- Diag(Property->getLocation(), diag::warn_readonly_property)
- << Property->getDeclName() << inheritedName;
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "copy" << inheritedName;
- else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){
- unsigned CAttrRetain =
- (CAttr &
- (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
- unsigned SAttrRetain =
- (SAttr &
- (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
- bool CStrong = (CAttrRetain != 0);
- bool SStrong = (SAttrRetain != 0);
- if (CStrong != SStrong)
+ SuperProperty->getPropertyAttributes();
+
+ // We allow readonly properties without an explicit ownership
+ // (assign/unsafe_unretained/weak/retain/strong/copy) in super class
+ // to be overridden by a property with any explicit ownership in the subclass.
+ if (!OverridingProtocolProperty &&
+ !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
+ ;
+ else {
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
+ && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
+ Diag(Property->getLocation(), diag::warn_readonly_property)
+ << Property->getDeclName() << inheritedName;
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain (or strong)" << inheritedName;
+ << Property->getDeclName() << "copy" << inheritedName;
+ else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){
+ unsigned CAttrRetain =
+ (CAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ unsigned SAttrRetain =
+ (SAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ bool CStrong = (CAttrRetain != 0);
+ bool SStrong = (SAttrRetain != 0);
+ if (CStrong != SStrong)
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain (or strong)" << inheritedName;
+ }
}
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
@@ -1378,110 +1431,6 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
return false;
}
-/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
-/// of properties declared in a protocol and compares their attribute against
-/// the same property declared in the class or category.
-void
-Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) {
- if (!CDecl)
- return;
-
- // Category case.
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- // FIXME: We should perform this check when the property in the category
- // is declared.
- assert (CatDecl && "MatchOneProtocolPropertiesInClass");
- if (!CatDecl->IsClassExtension())
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *ProtoProp = *P;
- DeclContext::lookup_result R
- = CatDecl->lookup(ProtoProp->getDeclName());
- for (unsigned I = 0, N = R.size(); I != N; ++I) {
- if (ObjCPropertyDecl *CatProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
- if (CatProp != ProtoProp) {
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(CatProp, ProtoProp,
- PDecl->getIdentifier());
- }
- }
- }
- }
- return;
- }
-
- // Class
- // FIXME: We should perform this check when the property in the class
- // is declared.
- ObjCInterfaceDecl *IDecl = cast<ObjCInterfaceDecl>(CDecl);
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *ProtoProp = *P;
- DeclContext::lookup_result R
- = IDecl->lookup(ProtoProp->getDeclName());
- for (unsigned I = 0, N = R.size(); I != N; ++I) {
- if (ObjCPropertyDecl *ClassProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
- if (ClassProp != ProtoProp) {
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(ClassProp, ProtoProp,
- PDecl->getIdentifier());
- }
- }
- }
- }
-}
-
-/// isPropertyReadonly - Return true if property is readonly, by searching
-/// for the property in the class and in its categories and implementations
-///
-bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
- ObjCInterfaceDecl *IDecl) {
- // by far the most common case.
- if (!PDecl->isReadOnly())
- return false;
- // Even if property is ready only, if interface has a user defined setter,
- // it is not considered read only.
- if (IDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
-
- // Main class has the property as 'readonly'. Must search
- // through the category list to see if the property's
- // attribute has been over-ridden to 'readwrite'.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = IDecl->visible_categories_begin(),
- CatEnd = IDecl->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- if (Cat->getInstanceMethod(PDecl->getSetterName()))
- return false;
- ObjCPropertyDecl *P =
- Cat->FindPropertyDeclaration(PDecl->getIdentifier());
- if (P && !P->isReadOnly())
- return false;
- }
-
- // Also, check for definition of a setter method in the implementation if
- // all else failed.
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
- if (ObjCImplementationDecl *IMD =
- dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
- if (IMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- } else if (ObjCCategoryImplDecl *CIMD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
- if (CIMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- }
- }
- // Lastly, look through the implementation (if one is in scope).
- if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
- if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
- // If all fails, look at the super class.
- if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
- return isPropertyReadonly(PDecl, SIDecl);
- return true;
-}
-
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those in its super class.
void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
@@ -1588,6 +1537,19 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
ObjCPropertyDecl *Prop = PropertyOrder[i];
+ // Is there a matching property synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ continue;
+ // Property may have been synthesized by user.
+ if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
+ continue;
+ if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
+ continue;
+ if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
+ continue;
+ }
// If property to be implemented in the super class, ignore.
if (SuperPropMap[Prop->getIdentifier()]) {
ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
@@ -1602,29 +1564,16 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
}
continue;
}
- // Is there a matching property synthesize/dynamic?
- if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
- continue;
if (ObjCPropertyImplDecl *PID =
- IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
+ IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
if (PID->getPropertyDecl() != Prop) {
Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
- << Prop->getIdentifier()->getName();
+ << Prop->getIdentifier()->getName();
if (!PID->getLocation().isInvalid())
Diag(PID->getLocation(), diag::note_property_synthesize);
}
continue;
}
- // Property may have been synthesized by user.
- if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
- continue;
- if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
- continue;
- if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
- continue;
- }
if (isa<ObjCProtocolDecl>(Prop->getDeclContext())) {
// We won't auto-synthesize properties declared in protocols.
Diag(IMPDecl->getLocation(),
@@ -1966,6 +1915,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(
::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
+
+ if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
+ GetterMethod->addAttr(
+ ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@@ -2064,55 +2017,30 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
// FIXME: Improve the reported location.
if (!PDecl || PDecl->isInvalidDecl())
return;
-
+
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "readonly" << "readwrite";
+
ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
- QualType PropertyTy = PropertyDecl->getType();
-
- if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- PropertyTy->isObjCRetainableType()) {
- // 'readonly' property with no obvious lifetime.
- // its life time will be determined by its backing ivar.
- unsigned rel = (ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong |
- ObjCDeclSpec::DQ_PR_weak |
- ObjCDeclSpec::DQ_PR_assign);
- if ((Attributes & rel) == 0)
+ QualType PropertyTy = PropertyDecl->getType();
+ unsigned PropertyOwnership = getOwnershipRule(Attributes);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
+ if (getLangOpts().ObjCAutoRefCount &&
+ PropertyTy->isObjCRetainableType() &&
+ !PropertyOwnership) {
+ // 'readonly' property with no obvious lifetime.
+ // its life time will be determined by its backing ivar.
return;
- }
-
- if (propertyInPrimaryClass) {
- // we postpone most property diagnosis until class's implementation
- // because, its readonly attribute may be overridden in its class
- // extensions making other attributes, which make no sense, to make sense.
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "readonly" << "readwrite";
- }
- // readonly and readwrite/assign/retain/copy conflict.
- else if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
- ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong))) {
- const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
- "readwrite" :
- (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
- "assign" :
- (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
- "unsafe_unretained" :
- (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
- "copy" : "retain";
-
- Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
- diag::err_objc_property_attr_mutually_exclusive :
- diag::warn_objc_property_attr_mutually_exclusive)
- << "readonly" << which;
+ }
+ else if (PropertyOwnership) {
+ if (!getSourceManager().isInSystemHeader(Loc))
+ Diag(Loc, diag::warn_objc_property_attr_mutually_exclusive)
+ << "readonly" << NameOfOwnershipAttribute(Attributes);
+ return;
+ }
}
// Check for copy or retain on non-object types.
@@ -2151,6 +2079,8 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "assign" << "weak";
Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
}
+ if (PropertyDecl->getAttr<IBOutletCollectionAttr>())
+ Diag(Loc, diag::warn_iboutletcollection_property_assign);
} else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index c815d4f9abc7..c63caf46b9e0 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -8,131 +8,516 @@
//===----------------------------------------------------------------------===//
/// \file
/// \brief This file implements semantic analysis for OpenMP directives and
-/// clauses
+/// clauses.
///
//===----------------------------------------------------------------------===//
#include "clang/Basic/OpenMPKinds.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
using namespace clang;
+//===----------------------------------------------------------------------===//
+// Stack of data-sharing attributes for variables
+//===----------------------------------------------------------------------===//
+
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'.
+};
+
+/// \brief Stack for tracking declarations used in OpenMP directives and
+/// clauses and their data-sharing attributes.
+class DSAStackTy {
+public:
+ struct DSAVarData {
+ OpenMPDirectiveKind DKind;
+ OpenMPClauseKind CKind;
+ DeclRefExpr *RefExpr;
+ DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(0) { }
+ };
+private:
+ struct DSAInfo {
+ OpenMPClauseKind Attributes;
+ DeclRefExpr *RefExpr;
+ };
+ typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
+
+ struct SharingMapTy {
+ DeclSAMapTy SharingMap;
+ DefaultDataSharingAttributes DefaultAttr;
+ OpenMPDirectiveKind Directive;
+ DeclarationNameInfo DirectiveName;
+ Scope *CurScope;
+ SharingMapTy(OpenMPDirectiveKind DKind,
+ const DeclarationNameInfo &Name,
+ Scope *CurScope)
+ : SharingMap(), DefaultAttr(DSA_unspecified), Directive(DKind),
+ DirectiveName(Name), CurScope(CurScope) { }
+ SharingMapTy()
+ : SharingMap(), DefaultAttr(DSA_unspecified),
+ Directive(OMPD_unknown), DirectiveName(),
+ CurScope(0) { }
+ };
+
+ typedef SmallVector<SharingMapTy, 64> StackTy;
+
+ /// \brief Stack of used declaration and their data-sharing attributes.
+ StackTy Stack;
+ Sema &Actions;
+
+ typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;
+
+ DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D);
+public:
+ explicit DSAStackTy(Sema &S) : Stack(1), Actions(S) { }
+
+ void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
+ Scope *CurScope) {
+ Stack.push_back(SharingMapTy(DKind, DirName, CurScope));
+ }
+
+ void pop() {
+ assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!");
+ Stack.pop_back();
+ }
+
+ /// \brief Adds explicit data sharing attribute to the specified declaration.
+ void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);
+
+ /// \brief Checks if the variable is a local for OpenMP region.
+ bool isOpenMPLocal(VarDecl *D);
+
+ /// \brief Returns data sharing attributes from top of the stack for the
+ /// specified declaration.
+ DSAVarData getTopDSA(VarDecl *D);
+ /// \brief Returns data-sharing attributes for the specified declaration.
+ DSAVarData getImplicitDSA(VarDecl *D);
+ /// \brief Checks if the specified variables has \a CKind data-sharing
+ /// attribute in \a DKind directive.
+ DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
+ OpenMPDirectiveKind DKind = OMPD_unknown);
+
+
+ /// \brief Returns currently analyzed directive.
+ OpenMPDirectiveKind getCurrentDirective() const {
+ return Stack.back().Directive;
+ }
+
+ /// \brief Set default data sharing attribute to none.
+ void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; }
+ /// \brief Set default data sharing attribute to shared.
+ void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; }
+
+ DefaultDataSharingAttributes getDefaultDSA() const {
+ return Stack.back().DefaultAttr;
+ }
+
+ Scope *getCurScope() { return Stack.back().CurScope; }
+};
+} // end anonymous namespace.
+
+DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
+ VarDecl *D) {
+ DSAVarData DVar;
+ if (Iter == Stack.rend() - 1) {
+ // 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
+ // in the region are shared unless they appear in a threadprivate
+ // directive.
+ // TODO
+ if (!D->isFunctionOrMethodVarDecl())
+ DVar.CKind = OMPC_shared;
+
+ // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
+ // in a region but not in construct]
+ // Variables with static storage duration that are declared in called
+ // routines in the region are shared.
+ if (D->hasGlobalStorage())
+ DVar.CKind = OMPC_shared;
+
+ return DVar;
+ }
+ DVar.DKind = Iter->Directive;
+ // Explicitly specified attributes and local variables with predetermined
+ // attributes.
+ if (Iter->SharingMap.count(D)) {
+ DVar.RefExpr = Iter->SharingMap[D].RefExpr;
+ DVar.CKind = Iter->SharingMap[D].Attributes;
+ return DVar;
+ }
+
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, implicitly determined, p.1]
+ // In a parallel or task construct, the data-sharing attributes of these
+ // variables are determined by the default clause, if present.
+ switch (Iter->DefaultAttr) {
+ case DSA_shared:
+ DVar.CKind = OMPC_shared;
+ return DVar;
+ case DSA_none:
+ return DVar;
+ case DSA_unspecified:
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, implicitly determined, p.2]
+ // In a parallel construct, if no default clause is present, these
+ // variables are shared.
+ if (DVar.DKind == OMPD_parallel) {
+ DVar.CKind = OMPC_shared;
+ return DVar;
+ }
- class VarDeclFilterCCC : public CorrectionCandidateCallback {
- private:
- Sema &Actions;
- public:
- VarDeclFilterCCC(Sema &S) : Actions(S) { }
- virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
- NamedDecl *ND = Candidate.getCorrectionDecl();
- if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
- return VD->hasGlobalStorage() &&
- Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
- Actions.getCurScope());
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, implicitly determined, p.4]
+ // In a task construct, if no default clause is present, a variable that in
+ // the enclosing context is determined to be shared by all implicit tasks
+ // bound to the current team is shared.
+ // TODO
+ if (DVar.DKind == OMPD_task) {
+ DSAVarData DVarTemp;
+ for (StackTy::reverse_iterator I = Iter + 1,
+ EE = Stack.rend() - 1;
+ I != EE; ++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
+ // whose data-sharing attribute is not determined by the rules above is
+ // firstprivate.
+ DVarTemp = getDSA(I, D);
+ if (DVarTemp.CKind != OMPC_shared) {
+ DVar.RefExpr = 0;
+ DVar.DKind = OMPD_task;
+ DVar.CKind = OMPC_firstprivate;
+ return DVar;
}
- return false;
+ if (I->Directive == OMPD_parallel) break;
}
- };
+ DVar.DKind = OMPD_task;
+ DVar.CKind =
+ (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
+ return DVar;
+ }
+ }
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, implicitly determined, p.3]
+ // For constructs other than task, if no default clause is present, these
+ // variables inherit their data-sharing attributes from the enclosing
+ // context.
+ return getDSA(Iter + 1, D);
}
-Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
- SourceLocation Loc,
- Scope *CurScope,
- ArrayRef<DeclarationNameInfo> IdList) {
- SmallVector<DeclRefExpr *, 5> Vars;
- for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(),
- E = IdList.end();
+
+void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
+ if (A == OMPC_threadprivate) {
+ Stack[0].SharingMap[D].Attributes = A;
+ Stack[0].SharingMap[D].RefExpr = E;
+ } else {
+ assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ Stack.back().SharingMap[D].Attributes = A;
+ Stack.back().SharingMap[D].RefExpr = E;
+ }
+}
+
+bool DSAStackTy::isOpenMPLocal(VarDecl *D) {
+ Scope *CurScope = getCurScope();
+ while (CurScope && !CurScope->isDeclScope(D))
+ CurScope = CurScope->getParent();
+ while (CurScope && !CurScope->isOpenMPDirectiveScope())
+ CurScope = CurScope->getParent();
+ bool isOpenMPLocal = !!CurScope;
+ if (!isOpenMPLocal) {
+ CurScope = getCurScope();
+ while (CurScope && !CurScope->isOpenMPDirectiveScope())
+ CurScope = CurScope->getParent();
+ isOpenMPLocal =
+ CurScope &&
+ isa<CapturedDecl>(D->getDeclContext()) &&
+ CurScope->getFnParent()->getEntity()->Encloses(D->getDeclContext());
+ }
+ return isOpenMPLocal;
+}
+
+DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
+ DSAVarData DVar;
+
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.1]
+ // Variables appearing in threadprivate directives are threadprivate.
+ if (D->getTLSKind() != VarDecl::TLS_None) {
+ DVar.CKind = OMPC_threadprivate;
+ return DVar;
+ }
+ if (Stack[0].SharingMap.count(D)) {
+ DVar.RefExpr = Stack[0].SharingMap[D].RefExpr;
+ DVar.CKind = OMPC_threadprivate;
+ return DVar;
+ }
+
+ // 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
+ // inside the construct are private.
+ if (isOpenMPLocal(D) && D->isLocalVarDecl() &&
+ (D->getStorageClass() == SC_Auto ||
+ D->getStorageClass() == SC_None)) {
+ DVar.CKind = OMPC_private;
+ return DVar;
+ }
+
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.4]
+ // Static data memebers are shared.
+ if (D->isStaticDataMember()) {
+ // Variables with const-qualified type having no mutable member may be listed
+ // in a firstprivate clause, even if they are static data members.
+ DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+ if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
+ return DVar;
+
+ DVar.CKind = OMPC_shared;
+ return DVar;
+ }
+
+ QualType Type = D->getType().getNonReferenceType().getCanonicalType();
+ bool IsConstant = Type.isConstant(Actions.getASTContext());
+ while (Type->isArrayType()) {
+ QualType ElemType = cast<ArrayType>(Type.getTypePtr())->getElementType();
+ Type = ElemType.getNonReferenceType().getCanonicalType();
+ }
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.6]
+ // Variables with const qualified type having no mutable member are
+ // shared.
+ CXXRecordDecl *RD = Actions.getLangOpts().CPlusPlus ?
+ Type->getAsCXXRecordDecl() : 0;
+ if (IsConstant &&
+ !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
+ // Variables with const-qualified type having no mutable member may be
+ // listed in a firstprivate clause, even if they are static data members.
+ DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+ if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
+ return DVar;
+
+ DVar.CKind = OMPC_shared;
+ return DVar;
+ }
+
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.7]
+ // Variables with static storage duration that are declared in a scope
+ // inside the construct are shared.
+ if (isOpenMPLocal(D) && D->isStaticLocal()) {
+ DVar.CKind = OMPC_shared;
+ return DVar;
+ }
+
+ // Explicitly specified attributes and local variables with predetermined
+ // attributes.
+ if (Stack.back().SharingMap.count(D)) {
+ DVar.RefExpr = Stack.back().SharingMap[D].RefExpr;
+ DVar.CKind = Stack.back().SharingMap[D].Attributes;
+ }
+
+ return DVar;
+}
+
+DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) {
+ return getDSA(Stack.rbegin() + 1, D);
+}
+
+DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind,
+ OpenMPDirectiveKind DKind) {
+ for (StackTy::reverse_iterator I = Stack.rbegin() + 1,
+ E = Stack.rend() - 1;
I != E; ++I) {
- LookupResult Lookup(*this, *I, LookupOrdinaryName);
- LookupParsedName(Lookup, CurScope, NULL, true);
-
- if (Lookup.isAmbiguous())
- continue;
-
- VarDecl *VD;
- if (!Lookup.isSingleResult()) {
- VarDeclFilterCCC Validator(*this);
- TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
- 0, Validator);
- std::string CorrectedStr = Corrected.getAsString(getLangOpts());
- std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
- if (Lookup.empty()) {
- if (Corrected.isResolved()) {
- Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
- << I->getName() << CorrectedQuotedStr
- << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
- } else {
- Diag(I->getLoc(), diag::err_undeclared_var_use)
- << I->getName();
- }
- } else {
- Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
- << I->getName() << Corrected.isResolved() << CorrectedQuotedStr
- << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
- }
- if (!Corrected.isResolved()) continue;
+ if (DKind != OMPD_unknown && DKind != I->Directive) continue;
+ DSAVarData DVar = getDSA(I, D);
+ if (DVar.CKind == CKind)
+ return DVar;
+ }
+ return DSAVarData();
+}
+
+void Sema::InitDataSharingAttributesStack() {
+ VarDataSharingAttributesStack = new DSAStackTy(*this);
+}
+
+#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
+
+void Sema::DestroyDataSharingAttributesStack() {
+ delete DSAStack;
+}
+
+void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
+ const DeclarationNameInfo &DirName,
+ Scope *CurScope) {
+ DSAStack->push(DKind, DirName, CurScope);
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+}
+
+void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
+ DSAStack->pop();
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+}
+
+namespace {
+
+class VarDeclFilterCCC : public CorrectionCandidateCallback {
+private:
+ Sema &Actions;
+public:
+ VarDeclFilterCCC(Sema &S) : Actions(S) { }
+ virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
+ return VD->hasGlobalStorage() &&
+ Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
+ Actions.getCurScope());
+ }
+ return false;
+ }
+};
+}
+
+ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id) {
+ LookupResult Lookup(*this, Id, LookupOrdinaryName);
+ LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+
+ if (Lookup.isAmbiguous())
+ return ExprError();
+
+ VarDecl *VD;
+ if (!Lookup.isSingleResult()) {
+ VarDeclFilterCCC Validator(*this);
+ if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
+ 0, Validator)) {
+ diagnoseTypo(Corrected,
+ PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
+ : diag::err_omp_expected_var_arg_suggest)
+ << Id.getName());
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
- if (!(VD = Lookup.getAsSingle<VarDecl>())) {
- Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
- << I->getName() << 0;
- Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
- continue;
- }
+ Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use
+ : diag::err_omp_expected_var_arg)
+ << Id.getName();
+ return ExprError();
+ }
+ } else {
+ if (!(VD = Lookup.getAsSingle<VarDecl>())) {
+ Diag(Id.getLoc(), diag::err_omp_expected_var_arg)
+ << Id.getName();
+ Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
+ return ExprError();
}
+ }
+ Lookup.suppressDiagnostics();
- // OpenMP [2.9.2, Syntax, C/C++]
- // Variables must be file-scope, namespace-scope, or static block-scope.
- if (!VD->hasGlobalStorage()) {
- Diag(I->getLoc(), diag::err_omp_global_var_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate)
- << !VD->isStaticLocal();
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
- continue;
- }
-
- // OpenMP [2.9.2, Restrictions, C/C++, p.2]
- // A threadprivate directive for file-scope variables must appear outside
- // any definition or declaration.
- // OpenMP [2.9.2, Restrictions, C/C++, p.3]
- // A threadprivate directive for static class member variables must appear
- // in the class definition, in the same scope in which the member
- // variables are declared.
- // OpenMP [2.9.2, Restrictions, C/C++, p.4]
- // A threadprivate directive for namespace-scope variables must appear
- // outside any definition or declaration other than the namespace
- // definition itself.
- // OpenMP [2.9.2, Restrictions, C/C++, p.6]
- // A threadprivate directive for static block-scope variables must appear
- // in the scope of the variable and not in a nested scope.
- NamedDecl *ND = cast<NamedDecl>(VD);
- if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
- Diag(I->getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
- continue;
- }
-
- // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
- // A threadprivate directive must lexically precede all references to any
- // of the variables in its list.
- if (VD->isUsed()) {
- Diag(I->getLoc(), diag::err_omp_var_used)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- continue;
- }
-
- QualType ExprType = VD->getType().getNonReferenceType();
- DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD,
- ExprType,
- VK_RValue,
- I->getLoc()).take());
- Vars.push_back(Var);
- }
- if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
+ // OpenMP [2.9.2, Syntax, C/C++]
+ // Variables must be file-scope, namespace-scope, or static block-scope.
+ if (!VD->hasGlobalStorage()) {
+ Diag(Id.getLoc(), diag::err_omp_global_var_arg)
+ << getOpenMPDirectiveName(OMPD_threadprivate)
+ << !VD->isStaticLocal();
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD;
+ return ExprError();
+ }
+
+ VarDecl *CanonicalVD = VD->getCanonicalDecl();
+ NamedDecl *ND = cast<NamedDecl>(CanonicalVD);
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2]
+ // A threadprivate directive for file-scope variables must appear outside
+ // any definition or declaration.
+ if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
+ !getCurLexicalContext()->isTranslationUnit()) {
+ Diag(Id.getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ return ExprError();
+ }
+ // OpenMP [2.9.2, Restrictions, C/C++, p.3]
+ // A threadprivate directive for static class member variables must appear
+ // in the class definition, in the same scope in which the member
+ // variables are declared.
+ if (CanonicalVD->isStaticDataMember() &&
+ !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
+ Diag(Id.getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ return ExprError();
+ }
+ // OpenMP [2.9.2, Restrictions, C/C++, p.4]
+ // A threadprivate directive for namespace-scope variables must appear
+ // outside any definition or declaration other than the namespace
+ // definition itself.
+ if (CanonicalVD->getDeclContext()->isNamespace() &&
+ (!getCurLexicalContext()->isFileContext() ||
+ !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
+ Diag(Id.getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ return ExprError();
+ }
+ // OpenMP [2.9.2, Restrictions, C/C++, p.6]
+ // A threadprivate directive for static block-scope variables must appear
+ // in the scope of the variable and not in a nested scope.
+ if (CanonicalVD->isStaticLocal() && CurScope &&
+ !isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
+ Diag(Id.getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ return ExprError();
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
+ // A threadprivate directive must lexically precede all references to any
+ // of the variables in its list.
+ if (VD->isUsed()) {
+ Diag(Id.getLoc(), diag::err_omp_var_used)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ return ExprError();
+ }
+
+ QualType ExprType = VD->getType().getNonReferenceType();
+ ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc());
+ DSAStack->addDSA(VD, cast<DeclRefExpr>(DE.get()), OMPC_threadprivate);
+ return DE;
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
+ SourceLocation Loc,
+ ArrayRef<Expr *> VarList) {
+ if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
@@ -141,18 +526,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
SourceLocation Loc,
- ArrayRef<DeclRefExpr *> VarList) {
- SmallVector<DeclRefExpr *, 5> Vars;
- for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
+ ArrayRef<Expr *> VarList) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(),
E = VarList.end();
I != E; ++I) {
- VarDecl *VD = cast<VarDecl>((*I)->getDecl());
- SourceLocation ILoc = (*I)->getLocation();
+ DeclRefExpr *DE = cast<DeclRefExpr>(*I);
+ VarDecl *VD = cast<VarDecl>(DE->getDecl());
+ SourceLocation ILoc = DE->getExprLoc();
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have an incomplete type.
if (RequireCompleteType(ILoc, VD->getType(),
- diag::err_omp_incomplete_type)) {
+ diag::err_omp_threadprivate_incomplete_type)) {
continue;
}
@@ -160,15 +546,22 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
// A threadprivate variable must not have a reference type.
if (VD->getType()->isReferenceType()) {
Diag(ILoc, diag::err_omp_ref_type_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate)
+ << VD->getType();
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
continue;
}
// Check if this is a TLS variable.
if (VD->getTLSKind()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
continue;
}
@@ -179,3 +572,591 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
getCurLexicalContext(),
Loc, Vars);
}
+
+namespace {
+class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
+ DSAStackTy *Stack;
+ Sema &Actions;
+ bool ErrorFound;
+ CapturedStmt *CS;
+ llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
+public:
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if(VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ // Skip internally declared variables.
+ if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return;
+
+ SourceLocation ELoc = E->getExprLoc();
+
+ OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
+ DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
+ if (DVar.CKind != OMPC_unknown) {
+ if (DKind == OMPD_task && DVar.CKind != OMPC_shared &&
+ DVar.CKind != OMPC_threadprivate && !DVar.RefExpr)
+ ImplicitFirstprivate.push_back(DVar.RefExpr);
+ return;
+ }
+ // The default(none) clause requires that each variable that is referenced
+ // in the construct, and does not have a predetermined data-sharing
+ // attribute, must have its data-sharing attribute explicitly determined
+ // by being listed in a data-sharing attribute clause.
+ if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
+ (DKind == OMPD_parallel || DKind == OMPD_task)) {
+ ErrorFound = true;
+ Actions.Diag(ELoc, diag::err_omp_no_dsa_for_variable) << VD;
+ 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
+ // explicit task.
+ // TODO:
+
+ // Define implicit data-sharing attributes for task.
+ DVar = Stack->getImplicitDSA(VD);
+ if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
+ ImplicitFirstprivate.push_back(DVar.RefExpr);
+ }
+ }
+ void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
+ for (ArrayRef<OMPClause *>::iterator I = S->clauses().begin(),
+ E = S->clauses().end();
+ I != E; ++I)
+ if (OMPClause *C = *I)
+ for (StmtRange R = C->children(); R; ++R)
+ if (Stmt *Child = *R)
+ Visit(Child);
+ }
+ void VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();
+ I != E; ++I)
+ if (Stmt *Child = *I)
+ if (!isa<OMPExecutableDirective>(Child))
+ Visit(Child);
+ }
+
+ bool isErrorFound() { return ErrorFound; }
+ ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
+
+ DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS)
+ : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { }
+};
+}
+
+StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ StmtResult Res = StmtError();
+
+ // Check default data sharing attributes for referenced variables.
+ DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt));
+ DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
+ if (DSAChecker.isErrorFound())
+ return StmtError();
+ // Generate list of implicitly defined firstprivate variables.
+ llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
+ ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
+
+ bool ErrorFound = false;
+ if (!DSAChecker.getImplicitFirstprivate().empty()) {
+ if (OMPClause *Implicit =
+ ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(),
+ SourceLocation(), SourceLocation(),
+ SourceLocation())) {
+ ClausesWithImplicit.push_back(Implicit);
+ ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
+ DSAChecker.getImplicitFirstprivate().size();
+ } else
+ ErrorFound = true;
+ }
+
+ switch (Kind) {
+ case OMPD_parallel:
+ Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
+ break;
+ case OMPD_threadprivate:
+ case OMPD_task:
+ llvm_unreachable("OpenMP Directive is not allowed");
+ case OMPD_unknown:
+ case NUM_OPENMP_DIRECTIVES:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+
+ if (ErrorFound) return StmtError();
+ return Res;
+}
+
+StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc,
+ Clauses, AStmt));
+}
+
+OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
+ unsigned Argument,
+ SourceLocation ArgumentLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ OMPClause *Res = 0;
+ switch (Kind) {
+ case OMPC_default:
+ Res =
+ ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_shared:
+ case OMPC_threadprivate:
+ case OMPC_unknown:
+ case NUM_OPENMP_CLAUSES:
+ llvm_unreachable("Clause is not allowed.");
+ }
+ return Res;
+}
+
+OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_DEFAULT_unknown) {
+ std::string Values;
+ std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : "");
+ for (unsigned i = OMPC_DEFAULT_unknown + 1;
+ i < NUM_OPENMP_DEFAULT_KINDS; ++i) {
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(OMPC_default, i);
+ Values += "'";
+ switch (i) {
+ case NUM_OPENMP_DEFAULT_KINDS - 2:
+ Values += " or ";
+ break;
+ case NUM_OPENMP_DEFAULT_KINDS - 1:
+ break;
+ default:
+ Values += Sep;
+ break;
+ }
+ }
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_default);
+ return 0;
+ }
+ switch (Kind) {
+ case OMPC_DEFAULT_none:
+ DSAStack->setDefaultDSANone();
+ break;
+ case OMPC_DEFAULT_shared:
+ DSAStack->setDefaultDSAShared();
+ break;
+ default:
+ break;
+ }
+ return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc,
+ EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
+ ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ OMPClause *Res = 0;
+ switch (Kind) {
+ case OMPC_private:
+ Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_firstprivate:
+ Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_shared:
+ Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_default:
+ case OMPC_threadprivate:
+ case OMPC_unknown:
+ case NUM_OPENMP_CLAUSES:
+ llvm_unreachable("Clause is not allowed.");
+ }
+ return Res;
+}
+
+OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+ I != E; ++I) {
+ assert(*I && "NULL expr in OpenMP private clause.");
+ if (isa<DependentScopeDeclRefExpr>(*I)) {
+ // It will be analyzed later.
+ Vars.push_back(*I);
+ continue;
+ }
+
+ SourceLocation ELoc = (*I)->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.9.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name)
+ << (*I)->getSourceRange();
+ continue;
+ }
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // 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_private_incomplete_type)) {
+ continue;
+ }
+ if (Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_private) << Type;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
+ // A variable of class type (or array thereof) that appears in a private
+ // clause requires an accesible, unambiguous default constructor for the
+ // class type.
+ while (Type.getNonReferenceType()->isArrayType()) {
+ Type = cast<ArrayType>(
+ Type.getNonReferenceType().getTypePtr())->getElementType();
+ }
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
+ Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
+ if (RD) {
+ CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (!CD ||
+ CheckConstructorAccess(ELoc, CD,
+ InitializedEntity::InitializeTemporary(Type),
+ CD->getAccess(), PD) == AR_inaccessible ||
+ CD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_private) << 0;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, CD);
+ DiagnoseUseOfDecl(CD, ELoc);
+
+ CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD) {
+ if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+ DD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_private) << 4;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, DD);
+ DiagnoseUseOfDecl(DD, ELoc);
+ }
+ }
+
+ // OpenMP [2.9.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. For these exceptions only, listing a predetermined
+ // variable in a data-sharing attribute clause is allowed and overrides
+ // the variable's predetermined data-sharing attributes.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_private);
+ if (DVar.RefExpr) {
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ } else {
+ Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ }
+ continue;
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_private);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty()) return 0;
+
+ return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+ I != E; ++I) {
+ assert(*I && "NULL expr in OpenMP firstprivate clause.");
+ if (isa<DependentScopeDeclRefExpr>(*I)) {
+ // It will be analyzed later.
+ Vars.push_back(*I);
+ continue;
+ }
+
+ SourceLocation ELoc = (*I)->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.9.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name)
+ << (*I)->getSourceRange();
+ continue;
+ }
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // 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_firstprivate_incomplete_type)) {
+ continue;
+ }
+ if (Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_firstprivate) << Type;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
+ // A variable of class type (or array thereof) that appears in a private
+ // clause requires an accesible, unambiguous copy constructor for the
+ // class type.
+ Type = Context.getBaseElementType(Type);
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
+ Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
+ if (RD) {
+ CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (!CD ||
+ CheckConstructorAccess(ELoc, CD,
+ InitializedEntity::InitializeTemporary(Type),
+ CD->getAccess(), PD) == AR_inaccessible ||
+ CD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_firstprivate) << 1;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, CD);
+ DiagnoseUseOfDecl(CD, ELoc);
+
+ CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD) {
+ if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+ DD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_firstprivate) << 4;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, DD);
+ DiagnoseUseOfDecl(DD, ELoc);
+ }
+ }
+
+ // If StartLoc and EndLoc are invalid - this is an implicit firstprivate
+ // variable and it was checked already.
+ if (StartLoc.isValid() && EndLoc.isValid()) {
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ Type = Type.getNonReferenceType().getCanonicalType();
+ bool IsConstant = Type.isConstant(Context);
+ Type = Context.getBaseElementType(Type);
+ // 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.
+ // TODO: add processing for lastprivate.
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
+ DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ // OpenMP [2.9.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. For these exceptions only, listing a predetermined
+ // variable in a data-sharing attribute clause is allowed and overrides
+ // the variable's predetermined data-sharing attributes.
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, p.2]
+ // Variables with const-qualified type having no mutable member may be
+ // listed in a firstprivate clause, even if they are static data members.
+ if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&
+ DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ // 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.
+ // OpenMP [2.9.3.4, Restrictions, p.3]
+ // A list item that appears in a reduction clause of a parallel construct
+ // must not appear in a firstprivate clause on a worksharing or task
+ // construct if any of the worksharing or task regions arising from the
+ // worksharing or task construct ever bind to any of the parallel regions
+ // arising from the parallel construct.
+ // OpenMP [2.9.3.4, Restrictions, p.4]
+ // A list item that appears in a reduction clause in worksharing
+ // construct must not appear in a firstprivate clause in a task construct
+ // encountered during execution of any of the worksharing regions arising
+ // from the worksharing construct.
+ // TODO:
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_firstprivate);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty()) return 0;
+
+ return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+ I != E; ++I) {
+ assert(*I && "NULL expr in OpenMP shared clause.");
+ if (isa<DependentScopeDeclRefExpr>(*I)) {
+ // It will be analyzed later.
+ Vars.push_back(*I);
+ continue;
+ }
+
+ SourceLocation ELoc = (*I)->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.9.3.4, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name)
+ << (*I)->getSourceRange();
+ continue;
+ }
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // OpenMP [2.9.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. For these exceptions only, listing a predetermined
+ // variable in a data-sharing attribute clause is allowed and overrides
+ // the variable's predetermined data-sharing attributes.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_shared);
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_shared);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty()) return 0;
+
+ return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+#undef DSAStack
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 529ba127cbab..802f2b7290b3 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
@@ -43,8 +44,15 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
+ return ExprError();
+ // If FoundDecl is different from Fn (such as if one is a template
+ // 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 (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
-
DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(),
VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
@@ -74,7 +82,8 @@ static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
- bool AllowExplicit);
+ bool AllowExplicit,
+ bool AllowObjCConversionOnExplicit);
static ImplicitConversionSequence::CompareKind
@@ -441,9 +450,9 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
}
}
-/// DebugPrint - Print this standard conversion sequence to standard
+/// dump - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
-void StandardConversionSequence::DebugPrint() const {
+void StandardConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
@@ -480,12 +489,12 @@ void StandardConversionSequence::DebugPrint() const {
}
}
-/// DebugPrint - Print this user-defined conversion sequence to standard
+/// dump - Print this user-defined conversion sequence to standard
/// error. Useful for debugging overloading issues.
-void UserDefinedConversionSequence::DebugPrint() const {
+void UserDefinedConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
if (Before.First || Before.Second || Before.Third) {
- Before.DebugPrint();
+ Before.dump();
OS << " -> ";
}
if (ConversionFunction)
@@ -494,22 +503,24 @@ void UserDefinedConversionSequence::DebugPrint() const {
OS << "aggregate initialization";
if (After.First || After.Second || After.Third) {
OS << " -> ";
- After.DebugPrint();
+ After.dump();
}
}
-/// DebugPrint - Print this implicit conversion sequence to standard
+/// dump - Print this implicit conversion sequence to standard
/// error. Useful for debugging overloading issues.
-void ImplicitConversionSequence::DebugPrint() const {
+void ImplicitConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
+ if (isStdInitializerListElement())
+ OS << "Worst std::initializer_list element conversion: ";
switch (ConversionKind) {
case StandardConversion:
OS << "Standard conversion: ";
- Standard.DebugPrint();
+ Standard.dump();
break;
case UserDefinedConversion:
OS << "User-defined conversion: ";
- UserDefined.DebugPrint();
+ UserDefined.dump();
break;
case EllipsisConversion:
OS << "Ellipsis conversion";
@@ -541,13 +552,13 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
}
namespace {
- // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // Structure used by DeductionFailureInfo to store
// template argument information.
struct DFIArguments {
TemplateArgument FirstArg;
TemplateArgument SecondArg;
};
- // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // Structure used by DeductionFailureInfo to store
// template parameter and template argument information.
struct DFIParamWithArguments : DFIArguments {
TemplateParameter Param;
@@ -556,11 +567,10 @@ namespace {
/// \brief Convert from Sema's representation of template deduction information
/// to the form used in overload-candidate information.
-OverloadCandidate::DeductionFailureInfo
-static MakeDeductionFailureInfo(ASTContext &Context,
- Sema::TemplateDeductionResult TDK,
- TemplateDeductionInfo &Info) {
- OverloadCandidate::DeductionFailureInfo Result;
+DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context,
+ Sema::TemplateDeductionResult TDK,
+ TemplateDeductionInfo &Info) {
+ DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
Result.Data = 0;
@@ -618,7 +628,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
return Result;
}
-void OverloadCandidate::DeductionFailureInfo::Destroy() {
+void DeductionFailureInfo::Destroy() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -652,15 +662,13 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
}
}
-PartialDiagnosticAt *
-OverloadCandidate::DeductionFailureInfo::getSFINAEDiagnostic() {
+PartialDiagnosticAt *DeductionFailureInfo::getSFINAEDiagnostic() {
if (HasDiagnostic)
return static_cast<PartialDiagnosticAt*>(static_cast<void*>(Diagnostic));
return 0;
}
-TemplateParameter
-OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
+TemplateParameter DeductionFailureInfo::getTemplateParameter() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -688,8 +696,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
return TemplateParameter();
}
-TemplateArgumentList *
-OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
+TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -715,7 +722,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
return 0;
}
-const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
+const TemplateArgument *DeductionFailureInfo::getFirstArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -741,8 +748,7 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
return 0;
}
-const TemplateArgument *
-OverloadCandidate::DeductionFailureInfo::getSecondArg() {
+const TemplateArgument *DeductionFailureInfo::getSecondArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -768,8 +774,7 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
return 0;
}
-Expr *
-OverloadCandidate::DeductionFailureInfo::getExpr() {
+Expr *DeductionFailureInfo::getExpr() {
if (static_cast<Sema::TemplateDeductionResult>(Result) ==
Sema::TDK_FailedOverloadResolution)
return static_cast<Expr*>(Data);
@@ -854,11 +859,11 @@ static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
/// checkArgPlaceholdersForOverload - Check a set of call operands for
/// placeholders.
-static bool checkArgPlaceholdersForOverload(Sema &S, Expr **args,
- unsigned numArgs,
+static bool checkArgPlaceholdersForOverload(Sema &S,
+ MultiExprArg Args,
UnbridgedCastsSet &unbridged) {
- for (unsigned i = 0; i != numArgs; ++i)
- if (checkPlaceholderForOverload(S, args[i], &unbridged))
+ for (unsigned i = 0, e = Args.size(); i != e; ++i)
+ if (checkPlaceholderForOverload(S, Args[i], &unbridged))
return true;
return false;
@@ -970,21 +975,16 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
return Ovl_Overload;
}
-static bool canBeOverloaded(const FunctionDecl &D) {
- if (D.getAttr<OverloadableAttr>())
- return true;
- if (D.isExternC())
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
+ // C++ [basic.start.main]p2: This function shall not be overloaded.
+ if (New->isMain())
return false;
- // Main cannot be overloaded (basic.start.main).
- if (D.isMain())
+ // MSVCRT user defined entry points cannot be overloaded.
+ if (New->isMSVCRTEntryPoint())
return false;
- return true;
-}
-
-static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -995,8 +995,8 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
return true;
// Is the function New an overload of the function Old?
- QualType OldQType = S.Context.getCanonicalType(Old->getType());
- QualType NewQType = S.Context.getCanonicalType(New->getType());
+ QualType OldQType = Context.getCanonicalType(Old->getType());
+ QualType NewQType = Context.getCanonicalType(New->getType());
// Compare the signatures (C++ 1.3.10) of the two functions to
// determine whether they are overloads. If we find any mismatch
@@ -1017,7 +1017,7 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !S.FunctionArgTypesAreEqual(OldType, NewType)))
+ !FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -1033,9 +1033,9 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
if (!UseUsingDeclRules && NewTemplate &&
- (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, S.TPL_TemplateMatch) ||
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
@@ -1061,9 +1061,9 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
// declarations with the same name, the same parameter-type-list, and
// the same template parameter lists cannot be overloaded if any of
// them, but not all, have a ref-qualifier (8.3.5).
- S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+ Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
- S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ Diag(OldMethod->getLocation(), diag::note_previous_declaration);
}
return true;
}
@@ -1072,10 +1072,16 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
// function yet (because we haven't yet resolved whether this is a static
// or non-static member function). Add it now, on the assumption that this
// is a redeclaration of OldMethod.
+ unsigned OldQuals = OldMethod->getTypeQualifiers();
unsigned NewQuals = NewMethod->getTypeQualifiers();
- if (NewMethod->isConstexpr() && !isa<CXXConstructorDecl>(NewMethod))
+ if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
+ !isa<CXXConstructorDecl>(NewMethod))
NewQuals |= Qualifiers::Const;
- if (OldMethod->getTypeQualifiers() != NewQuals)
+
+ // We do not allow overloading based off of '__restrict'.
+ OldQuals &= ~Qualifiers::Restrict;
+ NewQuals &= ~Qualifiers::Restrict;
+ if (OldQuals != NewQuals)
return true;
}
@@ -1083,19 +1089,6 @@ static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
return false;
}
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
- if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
- return false;
-
- // If both of the functions are extern "C", then they are not
- // overloads.
- if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
- return false;
-
- return true;
-}
-
/// \brief Checks availability of the function depending on the current
/// function context. Inside an unavailable function, unavailability is ignored.
///
@@ -1115,7 +1108,8 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool AllowExplicit,
bool InOverloadResolution,
bool CStyle,
- bool AllowObjCWritebackConversion) {
+ bool AllowObjCWritebackConversion,
+ bool AllowObjCConversionOnExplicit) {
ImplicitConversionSequence ICS;
if (SuppressUserConversions) {
@@ -1129,7 +1123,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
OverloadCandidateSet Conversions(From->getExprLoc());
OverloadingResult UserDefResult
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
- AllowExplicit);
+ AllowExplicit, AllowObjCConversionOnExplicit);
if (UserDefResult == OR_Success) {
ICS.setUserDefined();
@@ -1218,7 +1212,8 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
bool AllowExplicit,
bool InOverloadResolution,
bool CStyle,
- bool AllowObjCWritebackConversion) {
+ bool AllowObjCWritebackConversion,
+ bool AllowObjCConversionOnExplicit) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(S, From, ToType, InOverloadResolution,
ICS.Standard, CStyle, AllowObjCWritebackConversion)){
@@ -1262,7 +1257,8 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
AllowExplicit, InOverloadResolution, CStyle,
- AllowObjCWritebackConversion);
+ AllowObjCWritebackConversion,
+ AllowObjCConversionOnExplicit);
}
ImplicitConversionSequence
@@ -1275,7 +1271,8 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
return clang::TryImplicitConversion(*this, From, ToType,
SuppressUserConversions, AllowExplicit,
InOverloadResolution, CStyle,
- AllowObjCWritebackConversion);
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
}
/// PerformImplicitConversion - Perform an implicit conversion of the
@@ -1307,7 +1304,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AllowExplicit,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
- AllowObjCWritebackConversion);
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
@@ -1591,7 +1589,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Integral conversions (C++ 4.7).
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (FromType->isAnyComplexType() && ToType->isComplexType()) {
+ } else if (FromType->isAnyComplexType() && ToType->isAnyComplexType()) {
// Complex conversions (C99 6.3.1.6)
SCS.Second = ICK_Complex_Conversion;
FromType = ToType.getUnqualifiedType();
@@ -2596,48 +2594,16 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
/// FunctionArgTypesAreEqual - This routine checks two function proto types
/// for equality of their argument types. Caller has already checked that
-/// they have same number of arguments. This routine assumes that Objective-C
-/// pointer types which only differ in their protocol qualifiers are equal.
-/// If the parameters are different, ArgPos will have the parameter index
-/// of the first different parameter.
+/// they have same number of arguments. If the parameters are different,
+/// ArgPos will have the parameter index of the first different parameter.
bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType,
unsigned *ArgPos) {
- if (!getLangOpts().ObjC1) {
- for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
- N = NewType->arg_type_begin(),
- E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
- if (!Context.hasSameType(*O, *N)) {
- if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
- return false;
- }
- }
- return true;
- }
-
for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
N = NewType->arg_type_begin(),
E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
- QualType ToType = (*O);
- QualType FromType = (*N);
- if (!Context.hasSameType(ToType, FromType)) {
- if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
- if (const PointerType *PTFr = FromType->getAs<PointerType>())
- if ((PTTo->getPointeeType()->isObjCQualifiedIdType() &&
- PTFr->getPointeeType()->isObjCQualifiedIdType()) ||
- (PTTo->getPointeeType()->isObjCQualifiedClassType() &&
- PTFr->getPointeeType()->isObjCQualifiedClassType()))
- continue;
- }
- else if (const ObjCObjectPointerType *PTTo =
- ToType->getAs<ObjCObjectPointerType>()) {
- if (const ObjCObjectPointerType *PTFr =
- FromType->getAs<ObjCObjectPointerType>())
- if (Context.hasSameUnqualifiedType(
- PTTo->getObjectType()->getBaseType(),
- PTFr->getObjectType()->getBaseType()))
- continue;
- }
+ if (!Context.hasSameType(O->getUnqualifiedType(),
+ N->getUnqualifiedType())) {
if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
return false;
}
@@ -2824,6 +2790,18 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
return false;
}
+/// Determine whether the lifetime conversion between the two given
+/// qualifiers sets is nontrivial.
+static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
+ Qualifiers ToQuals) {
+ // Converting anything to const __unsafe_unretained is trivial.
+ if (ToQuals.hasConst() &&
+ ToQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
+ return false;
+
+ return true;
+}
+
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
@@ -2865,7 +2843,8 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
UnwrappedAnyPointer) {
if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
- ObjCLifetimeConversion = true;
+ if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
+ ObjCLifetimeConversion = true;
FromQuals.removeObjCLifetime();
ToQuals.removeObjCLifetime();
} else {
@@ -3030,11 +3009,18 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
/// \param AllowExplicit true if the conversion should consider C++0x
/// "explicit" conversion functions as well as non-explicit conversion
/// functions (C++0x [class.conv.fct]p2).
+///
+/// \param AllowObjCConversionOnExplicit true if the conversion should
+/// allow an extra Objective-C pointer conversion on uses of explicit
+/// constructors. Requires \c AllowExplicit to also be set.
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ bool AllowObjCConversionOnExplicit) {
+ assert(AllowExplicit || !AllowObjCConversionOnExplicit);
+
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
@@ -3067,7 +3053,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
unsigned NumArgs = 1;
bool ListInitializing = false;
if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
- // But first, see if there is an init-list-contructor that will work.
+ // But first, see if there is an init-list-constructor that will work.
OverloadingResult Result = IsInitializerListConstructorConversion(
S, From, ToType, ToRecordDecl, User, CandidateSet, AllowExplicit);
if (Result != OR_No_Viable_Function)
@@ -3161,10 +3147,12 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl,
ActingContext, From, ToType,
- CandidateSet);
+ CandidateSet,
+ AllowObjCConversionOnExplicit);
else
S.AddConversionCandidate(Conv, FoundDecl, ActingContext,
- From, ToType, CandidateSet);
+ From, ToType, CandidateSet,
+ AllowObjCConversionOnExplicit);
}
}
}
@@ -3251,15 +3239,19 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
- CandidateSet, false);
+ CandidateSet, false, false);
if (OvResult == OR_Ambiguous)
Diag(From->getLocStart(),
diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
- else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty())
- Diag(From->getLocStart(),
- diag::err_typecheck_nonviable_condition)
- << From->getType() << ToType << From->getSourceRange();
+ else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) {
+ if (!RequireCompleteType(From->getLocStart(), ToType,
+ diag::err_typecheck_nonviable_condition_incomplete,
+ From->getType(), From->getSourceRange()))
+ Diag(From->getLocStart(),
+ diag::err_typecheck_nonviable_condition)
+ << From->getType() << From->getSourceRange() << ToType;
+ }
else
return false;
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From);
@@ -3364,9 +3356,7 @@ CompareImplicitConversionSequences(Sema &S,
// list-initialization sequence L2 if L1 converts to std::initializer_list<X>
// for some X and L2 does not.
if (Result == ImplicitConversionSequence::Indistinguishable &&
- !ICS1.isBad() &&
- ICS1.isListInitializationSequence() &&
- ICS2.isListInitializationSequence()) {
+ !ICS1.isBad()) {
if (ICS1.isStdInitializerListElement() &&
!ICS2.isStdInitializerListElement())
return ImplicitConversionSequence::Better;
@@ -4019,9 +4009,11 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// space 2.
if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
+ if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
+ ObjCLifetimeConversion = true;
+
T1Quals.removeObjCLifetime();
T2Quals.removeObjCLifetime();
- ObjCLifetimeConversion = true;
}
if (T1Quals == T2Quals)
@@ -4105,10 +4097,12 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet);
+ Init, DeclType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet);
+ DeclType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -4390,7 +4384,8 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
/*AllowExplicit=*/false,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
- /*AllowObjCWritebackConversion=*/false);
+ /*AllowObjCWritebackConversion=*/false,
+ /*AllowObjCConversionOnExplicit=*/false);
// Of course, that's still a reference binding.
if (ICS.isStandard()) {
@@ -4445,7 +4440,6 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
ImplicitConversionSequence Result;
Result.setBad(BadConversionSequence::no_conversion, From, ToType);
- Result.setListInitializationSequence();
// We need a complete type for what follows. Incomplete types can never be
// initialized from init lists.
@@ -4491,7 +4485,6 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
Result.Standard.setAllToTypes(ToType);
}
- Result.setListInitializationSequence();
Result.setStdInitializerListElement(toStdInitializerList);
return Result;
}
@@ -4504,12 +4497,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// implicit conversion sequence is a user-defined conversion sequence.
if (ToType->isRecordType() && !ToType->isAggregateType()) {
// This function can deal with initializer lists.
- Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
- /*AllowExplicit=*/false,
- InOverloadResolution, /*CStyle=*/false,
- AllowObjCWritebackConversion);
- Result.setListInitializationSequence();
- return Result;
+ return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ InOverloadResolution, /*CStyle=*/false,
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
}
// C++11 [over.ics.list]p4:
@@ -4572,11 +4564,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
= S.CompareReferenceRelationship(From->getLocStart(), T1, T2, dummy1,
dummy2, dummy3);
- if (RefRelationship >= Sema::Ref_Related)
- return TryReferenceInit(S, Init, ToType,
- /*FIXME:*/From->getLocStart(),
+ if (RefRelationship >= Sema::Ref_Related) {
+ return TryReferenceInit(S, Init, ToType, /*FIXME*/From->getLocStart(),
SuppressUserConversions,
/*AllowExplicit=*/false);
+ }
}
// Otherwise, we bind the reference to a temporary created from the
@@ -4626,7 +4618,6 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
Result.Standard.setFromType(ToType);
Result.Standard.setAllToTypes(ToType);
}
- Result.setListInitializationSequence();
return Result;
}
@@ -4662,7 +4653,8 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
/*AllowExplicit=*/false,
InOverloadResolution,
/*CStyle=*/false,
- AllowObjCWritebackConversion);
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
}
static bool TryCopyInitialization(const CanQualType FromQTy,
@@ -4857,14 +4849,13 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
/// expression From to bool (C++0x [conv]p3).
static ImplicitConversionSequence
TryContextuallyConvertToBool(Sema &S, Expr *From) {
- // FIXME: This is pretty broken.
return TryImplicitConversion(S, From, S.Context.BoolTy,
- // FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
- /*AllowObjCWritebackConversion=*/false);
+ /*AllowObjCWritebackConversion=*/false,
+ /*AllowObjCConversionOnExplicit=*/false);
}
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -5009,17 +5000,13 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
break;
case NK_Constant_Narrowing:
- Diag(From->getLocStart(),
- isSFINAEContext() ? diag::err_cce_narrowing_sfinae :
- diag::err_cce_narrowing)
+ Diag(From->getLocStart(), diag::ext_cce_narrowing)
<< CCE << /*Constant*/1
<< PreNarrowingValue.getAsString(Context, PreNarrowingType) << T;
break;
case NK_Type_Narrowing:
- Diag(From->getLocStart(),
- isSFINAEContext() ? diag::err_cce_narrowing_sfinae :
- diag::err_cce_narrowing)
+ Diag(From->getLocStart(), diag::ext_cce_narrowing)
<< CCE << /*Constant*/0 << From->getType() << T;
break;
}
@@ -5079,7 +5066,8 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
- /*AllowObjCWritebackConversion=*/false);
+ /*AllowObjCWritebackConversion=*/false,
+ /*AllowObjCConversionOnExplicit=*/true);
// Strip off any final conversions to 'id'.
switch (ICS.getKind()) {
@@ -5116,34 +5104,157 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
/// Determine whether the provided type is an integral type, or an enumeration
/// type of a permitted flavor.
-static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) {
- return AllowScopedEnum ? T->isIntegralOrEnumerationType()
- : T->isIntegralOrUnscopedEnumerationType();
+bool Sema::ICEConvertDiagnoser::match(QualType T) {
+ return AllowScopedEnumerations ? T->isIntegralOrEnumerationType()
+ : T->isIntegralOrUnscopedEnumerationType();
+}
+
+static ExprResult
+diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From,
+ Sema::ContextualImplicitConverter &Converter,
+ QualType T, UnresolvedSetImpl &ViableConversions) {
+
+ if (Converter.Suppress)
+ return ExprError();
+
+ Converter.diagnoseAmbiguous(SemaRef, Loc, T) << From->getSourceRange();
+ for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+ CXXConversionDecl *Conv =
+ cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
+ QualType ConvTy = Conv->getConversionType().getNonReferenceType();
+ Converter.noteAmbiguous(SemaRef, Conv, ConvTy);
+ }
+ return SemaRef.Owned(From);
+}
+
+static bool
+diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
+ Sema::ContextualImplicitConverter &Converter,
+ QualType T, bool HadMultipleCandidates,
+ UnresolvedSetImpl &ExplicitConversions) {
+ if (ExplicitConversions.size() == 1 && !Converter.Suppress) {
+ DeclAccessPair Found = ExplicitConversions[0];
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+
+ // The user probably meant to invoke the given explicit
+ // conversion; use it.
+ QualType ConvTy = Conversion->getConversionType().getNonReferenceType();
+ std::string TypeStr;
+ ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy());
+
+ Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy)
+ << FixItHint::CreateInsertion(From->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << FixItHint::CreateInsertion(
+ SemaRef.PP.getLocForEndOfToken(From->getLocEnd()), ")");
+ Converter.noteExplicitConv(SemaRef, Conversion, ConvTy);
+
+ // If we aren't in a SFINAE context, build a call to the
+ // explicit conversion function.
+ if (SemaRef.isSFINAEContext())
+ return true;
+
+ SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+ ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
+ HadMultipleCandidates);
+ if (Result.isInvalid())
+ return true;
+ // Record usage of conversion in an implicit cast.
+ From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
+ CK_UserDefinedConversion, Result.get(), 0,
+ Result.get()->getValueKind());
+ }
+ return false;
+}
+
+static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
+ Sema::ContextualImplicitConverter &Converter,
+ QualType T, bool HadMultipleCandidates,
+ DeclAccessPair &Found) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+ SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+
+ QualType ToType = Conversion->getConversionType().getNonReferenceType();
+ if (!Converter.SuppressConversion) {
+ if (SemaRef.isSFINAEContext())
+ return true;
+
+ Converter.diagnoseConversion(SemaRef, Loc, T, ToType)
+ << From->getSourceRange();
+ }
+
+ ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
+ HadMultipleCandidates);
+ if (Result.isInvalid())
+ return true;
+ // Record usage of conversion in an implicit cast.
+ From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
+ CK_UserDefinedConversion, Result.get(), 0,
+ Result.get()->getValueKind());
+ return false;
+}
+
+static ExprResult finishContextualImplicitConversion(
+ Sema &SemaRef, SourceLocation Loc, Expr *From,
+ Sema::ContextualImplicitConverter &Converter) {
+ if (!Converter.match(From->getType()) && !Converter.Suppress)
+ Converter.diagnoseNoMatch(SemaRef, Loc, From->getType())
+ << From->getSourceRange();
+
+ return SemaRef.DefaultLvalueConversion(From);
+}
+
+static void
+collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,
+ UnresolvedSetImpl &ViableConversions,
+ OverloadCandidateSet &CandidateSet) {
+ for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+ DeclAccessPair FoundDecl = ViableConversions[I];
+ NamedDecl *D = FoundDecl.getDecl();
+ CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(D);
+
+ if (ConvTemplate)
+ SemaRef.AddTemplateConversionCandidate(
+ ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false);
+ else
+ SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
+ ToType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false);
+ }
}
-/// \brief Attempt to convert the given expression to an integral or
-/// enumeration type.
+/// \brief Attempt to convert the given expression to a type which is accepted
+/// by the given converter.
///
-/// This routine will attempt to convert an expression of class type to an
-/// integral or enumeration type, if that class type only has a single
-/// conversion to an integral or enumeration type.
+/// This routine will attempt to convert an expression of class type to a
+/// type accepted by the specified converter. In C++11 and before, the class
+/// must have a single non-explicit conversion function converting to a matching
+/// type. In C++1y, there can be multiple such conversion functions, but only
+/// one target type.
///
/// \param Loc The source location of the construct that requires the
/// conversion.
///
/// \param From The expression we're converting from.
///
-/// \param Diagnoser Used to output any diagnostics.
-///
-/// \param AllowScopedEnumerations Specifies whether conversions to scoped
-/// enumerations should be considered.
+/// \param Converter Used to control and diagnose the conversion process.
///
/// \returns The expression, converted to an integral or enumeration type if
/// successful.
-ExprResult
-Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
- ICEConvertDiagnoser &Diagnoser,
- bool AllowScopedEnumerations) {
+ExprResult Sema::PerformContextualImplicitConversion(
+ SourceLocation Loc, Expr *From, ContextualImplicitConverter &Converter) {
// We can't perform any more checking for type-dependent expressions.
if (From->isTypeDependent())
return Owned(From);
@@ -5151,158 +5262,180 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
// Process placeholders immediately.
if (From->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(From);
- if (result.isInvalid()) return result;
+ if (result.isInvalid())
+ return result;
From = result.take();
}
- // If the expression already has integral or enumeration type, we're golden.
+ // If the expression already has a matching type, we're golden.
QualType T = From->getType();
- if (isIntegralOrEnumerationType(T, AllowScopedEnumerations))
+ if (Converter.match(T))
return DefaultLvalueConversion(From);
// FIXME: Check for missing '()' if T is a function type?
- // If we don't have a class type in C++, there's no way we can get an
- // expression of integral or enumeration type.
+ // We can only perform contextual implicit conversions on objects of class
+ // type.
const RecordType *RecordTy = T->getAs<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) {
- if (!Diagnoser.Suppress)
- Diagnoser.diagnoseNotInt(*this, Loc, T) << From->getSourceRange();
+ if (!Converter.Suppress)
+ Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
return Owned(From);
}
// We must have a complete class type.
struct TypeDiagnoserPartialDiag : TypeDiagnoser {
- ICEConvertDiagnoser &Diagnoser;
+ ContextualImplicitConverter &Converter;
Expr *From;
-
- TypeDiagnoserPartialDiag(ICEConvertDiagnoser &Diagnoser, Expr *From)
- : TypeDiagnoser(Diagnoser.Suppress), Diagnoser(Diagnoser), From(From) {}
-
+
+ TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From)
+ : TypeDiagnoser(Converter.Suppress), Converter(Converter), From(From) {}
+
virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
- Diagnoser.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
+ Converter.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
}
- } IncompleteDiagnoser(Diagnoser, From);
+ } IncompleteDiagnoser(Converter, From);
if (RequireCompleteType(Loc, T, IncompleteDiagnoser))
return Owned(From);
// Look for a conversion to an integral or enumeration type.
- UnresolvedSet<4> ViableConversions;
+ UnresolvedSet<4>
+ ViableConversions; // These are *potentially* viable in C++1y.
UnresolvedSet<4> ExplicitConversions;
std::pair<CXXRecordDecl::conversion_iterator,
- CXXRecordDecl::conversion_iterator> Conversions
- = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+ CXXRecordDecl::conversion_iterator> Conversions =
+ cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+
+ bool HadMultipleCandidates =
+ (std::distance(Conversions.first, Conversions.second) > 1);
+
+ // To check that there is only one target type, in C++1y:
+ QualType ToType;
+ bool HasUniqueTargetType = true;
+
+ // Collect explicit or viable (potentially in C++1y) conversions.
+ for (CXXRecordDecl::conversion_iterator I = Conversions.first,
+ E = Conversions.second;
+ I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ CXXConversionDecl *Conversion;
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ if (ConvTemplate) {
+ if (getLangOpts().CPlusPlus1y)
+ Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ continue; // C++11 does not consider conversion operator templates(?).
+ } else
+ Conversion = cast<CXXConversionDecl>(D);
- bool HadMultipleCandidates
- = (std::distance(Conversions.first, Conversions.second) > 1);
+ assert((!ConvTemplate || getLangOpts().CPlusPlus1y) &&
+ "Conversion operator templates are considered potentially "
+ "viable in C++1y");
- for (CXXRecordDecl::conversion_iterator
- I = Conversions.first, E = Conversions.second; I != E; ++I) {
- if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
- if (isIntegralOrEnumerationType(
- Conversion->getConversionType().getNonReferenceType(),
- AllowScopedEnumerations)) {
- if (Conversion->isExplicit())
+ QualType CurToType = Conversion->getConversionType().getNonReferenceType();
+ if (Converter.match(CurToType) || ConvTemplate) {
+
+ if (Conversion->isExplicit()) {
+ // FIXME: For C++1y, do we need this restriction?
+ // cf. diagnoseNoViableConversion()
+ if (!ConvTemplate)
ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
- else
- ViableConversions.addDecl(I.getDecl(), I.getAccess());
+ } else {
+ if (!ConvTemplate && getLangOpts().CPlusPlus1y) {
+ if (ToType.isNull())
+ ToType = CurToType.getUnqualifiedType();
+ else if (HasUniqueTargetType &&
+ (CurToType.getUnqualifiedType() != ToType))
+ HasUniqueTargetType = false;
+ }
+ ViableConversions.addDecl(I.getDecl(), I.getAccess());
}
}
}
- switch (ViableConversions.size()) {
- case 0:
- if (ExplicitConversions.size() == 1 && !Diagnoser.Suppress) {
- DeclAccessPair Found = ExplicitConversions[0];
- CXXConversionDecl *Conversion
- = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+ if (getLangOpts().CPlusPlus1y) {
+ // C++1y [conv]p6:
+ // ... An expression e of class type E appearing in such a context
+ // is said to be contextually implicitly converted to a specified
+ // type T and is well-formed if and only if e can be implicitly
+ // converted to a type T that is determined as follows: E is searched
+ // for conversion functions whose return type is cv T or reference to
+ // cv T such that T is allowed by the context. There shall be
+ // exactly one such T.
- // The user probably meant to invoke the given explicit
- // conversion; use it.
- QualType ConvTy
- = Conversion->getConversionType().getNonReferenceType();
- std::string TypeStr;
- ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());
+ // If no unique T is found:
+ if (ToType.isNull()) {
+ if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+ HadMultipleCandidates,
+ ExplicitConversions))
+ return ExprError();
+ return finishContextualImplicitConversion(*this, Loc, From, Converter);
+ }
- Diagnoser.diagnoseExplicitConv(*this, Loc, T, ConvTy)
- << FixItHint::CreateInsertion(From->getLocStart(),
- "static_cast<" + TypeStr + ">(")
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()),
- ")");
- Diagnoser.noteExplicitConv(*this, Conversion, ConvTy);
+ // If more than one unique Ts are found:
+ if (!HasUniqueTargetType)
+ return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+ ViableConversions);
- // If we aren't in a SFINAE context, build a call to the
- // explicit conversion function.
- if (isSFINAEContext())
- return ExprError();
+ // If one unique T is found:
+ // First, build a candidate set from the previously recorded
+ // potentially viable conversions.
+ OverloadCandidateSet CandidateSet(Loc);
+ collectViableConversionCandidates(*this, From, ToType, ViableConversions,
+ CandidateSet);
- CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
- ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
- HadMultipleCandidates);
- if (Result.isInvalid())
+ // Then, perform overload resolution over the candidate set.
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(*this, Loc, Best)) {
+ case OR_Success: {
+ // Apply this conversion.
+ DeclAccessPair Found =
+ DeclAccessPair::make(Best->Function, Best->FoundDecl.getAccess());
+ if (recordConversion(*this, Loc, From, Converter, T,
+ HadMultipleCandidates, Found))
return ExprError();
- // Record usage of conversion in an implicit cast.
- From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
- CK_UserDefinedConversion,
- Result.get(), 0,
- Result.get()->getValueKind());
+ break;
}
-
- // We'll complain below about a non-integral condition type.
- break;
-
- case 1: {
- // Apply this conversion.
- DeclAccessPair Found = ViableConversions[0];
- CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
-
- CXXConversionDecl *Conversion
- = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
- QualType ConvTy
- = Conversion->getConversionType().getNonReferenceType();
- if (!Diagnoser.SuppressConversion) {
- if (isSFINAEContext())
+ case OR_Ambiguous:
+ return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+ ViableConversions);
+ case OR_No_Viable_Function:
+ if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+ HadMultipleCandidates,
+ ExplicitConversions))
return ExprError();
-
- Diagnoser.diagnoseConversion(*this, Loc, T, ConvTy)
- << From->getSourceRange();
+ // fall through 'OR_Deleted' case.
+ case OR_Deleted:
+ // We'll complain below about a non-integral condition type.
+ break;
}
+ } else {
+ switch (ViableConversions.size()) {
+ case 0: {
+ if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+ HadMultipleCandidates,
+ ExplicitConversions))
+ return ExprError();
- ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
- HadMultipleCandidates);
- if (Result.isInvalid())
- return ExprError();
- // Record usage of conversion in an implicit cast.
- From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
- CK_UserDefinedConversion,
- Result.get(), 0,
- Result.get()->getValueKind());
- break;
- }
-
- default:
- if (Diagnoser.Suppress)
- return ExprError();
-
- Diagnoser.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange();
- for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
- CXXConversionDecl *Conv
- = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
- QualType ConvTy = Conv->getConversionType().getNonReferenceType();
- Diagnoser.noteAmbiguous(*this, Conv, ConvTy);
+ // We'll complain below about a non-integral condition type.
+ break;
+ }
+ case 1: {
+ // Apply this conversion.
+ DeclAccessPair Found = ViableConversions[0];
+ if (recordConversion(*this, Loc, From, Converter, T,
+ HadMultipleCandidates, Found))
+ return ExprError();
+ break;
+ }
+ default:
+ return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+ ViableConversions);
}
- return Owned(From);
- }
-
- if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations) &&
- !Diagnoser.Suppress) {
- Diagnoser.diagnoseNotInt(*this, Loc, From->getType())
- << From->getSourceRange();
}
- return DefaultLvalueConversion(From);
+ return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
/// AddOverloadCandidate - Adds the given function to the set of
@@ -5348,10 +5481,18 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (!CandidateSet.isNewCandidate(Function))
return;
+ // C++11 [class.copy]p11: [DR1402]
+ // A defaulted move constructor that is defined as deleted is ignored by
+ // overload resolution.
+ CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function);
+ if (Constructor && Constructor->isDefaulted() && Constructor->isDeleted() &&
+ Constructor->isMoveConstructor())
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){
+ if (Constructor) {
// C++ [class.copy]p3:
// A member function template is never instantiated to perform the copy
// of a class object to an object of its class type.
@@ -5437,7 +5578,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
/// \brief Add all of the function declarations in the given function set to
-/// the overload canddiate set.
+/// the overload candidate set.
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
@@ -5526,6 +5667,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
if (!CandidateSet.isNewCandidate(Method))
return;
+ // C++11 [class.copy]p23: [DR1402]
+ // A defaulted move assignment operator that is defined as deleted is
+ // ignored by overload resolution.
+ if (Method->isDefaulted() && Method->isDeleted() &&
+ Method->isMoveAssignmentOperator())
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
@@ -5708,6 +5856,45 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
SuppressUserConversions);
}
+/// Determine whether this is an allowable conversion from the result
+/// of an explicit conversion operator to the expected type, per C++
+/// [over.match.conv]p1 and [over.match.ref]p1.
+///
+/// \param ConvType The return type of the conversion function.
+///
+/// \param ToType The type we are converting to.
+///
+/// \param AllowObjCPointerConversion Allow a conversion from one
+/// Objective-C pointer to another.
+///
+/// \returns true if the conversion is allowable, false otherwise.
+static bool isAllowableExplicitConversion(Sema &S,
+ QualType ConvType, QualType ToType,
+ bool AllowObjCPointerConversion) {
+ QualType ToNonRefType = ToType.getNonReferenceType();
+
+ // Easy case: the types are the same.
+ if (S.Context.hasSameUnqualifiedType(ConvType, ToNonRefType))
+ return true;
+
+ // Allow qualification conversions.
+ bool ObjCLifetimeConversion;
+ if (S.IsQualificationConversion(ConvType, ToNonRefType, /*CStyle*/false,
+ ObjCLifetimeConversion))
+ return true;
+
+ // If we're not allowed to consider Objective-C pointer conversions,
+ // we're done.
+ if (!AllowObjCPointerConversion)
+ return false;
+
+ // Is this an Objective-C pointer conversion?
+ bool IncompatibleObjC = false;
+ QualType ConvertedType;
+ 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,
@@ -5719,7 +5906,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
- OverloadCandidateSet& CandidateSet) {
+ OverloadCandidateSet& CandidateSet,
+ bool AllowObjCConversionOnExplicit) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -5734,6 +5922,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
ConvType = Conversion->getConversionType().getNonReferenceType();
}
+ // 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,
+ AllowObjCConversionOnExplicit))
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
@@ -5868,7 +6064,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
- OverloadCandidateSet &CandidateSet) {
+ OverloadCandidateSet &CandidateSet,
+ bool AllowObjCConversionOnExplicit) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
"Only conversion function templates permitted here");
@@ -5897,7 +6094,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
- CandidateSet);
+ CandidateSet, AllowObjCConversionOnExplicit);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -6119,6 +6316,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
}
}
+namespace {
+
/// BuiltinCandidateTypeSet - A set of types that will be used for the
/// candidate operator functions for built-in operators (C++
/// [over.built]). The types are separated into pointer types and
@@ -6208,6 +6407,8 @@ public:
bool hasNullPtrType() const { return HasNullPtrType; }
};
+} // end anonymous namespace
+
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
/// the set of pointer types along with any more-qualified variants of
/// that type. For example, if @p Ty is "int const *", this routine
@@ -7560,11 +7761,10 @@ public:
/// on the operator @p Op and the arguments given. For example, if the
/// operator is a binary '+', this routine might add "int
/// operator+(int, int)" to cover integer addition.
-void
-Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
- SourceLocation OpLoc,
- llvm::ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet) {
+void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet) {
// Find all of the types that the arguments can convert to, but only
// if the operator we're looking at has built-in operator candidates
// that make use of these types. Also record whether we encounter non-record
@@ -7869,7 +8069,8 @@ isBetterOverloadCandidate(Sema &S,
Loc,
isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
: TPOC_Call,
- Cand1.ExplicitCallArguments))
+ Cand1.ExplicitCallArguments,
+ Cand2.ExplicitCallArguments))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
@@ -8024,7 +8225,7 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
return isTemplate ? oc_function_template : oc_function;
}
-void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) {
+void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) {
const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn);
if (!Ctor) return;
@@ -8047,7 +8248,7 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType) {
MaybeEmitInheritedConstructorNote(*this, Fn);
}
-//Notes the location of all overload candidates designated through
+// Notes the location of all overload candidates designated through
// OverloadedExpr
void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) {
assert(OverloadedExpr->getType() == Context.OverloadTy);
@@ -8310,30 +8511,52 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
MaybeEmitInheritedConstructorNote(S, Fn);
}
-void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
- unsigned NumFormalArgs) {
- // TODO: treat calls to a missing default constructor as a special case
-
+/// Additional arity mismatch diagnosis specific to a function overload
+/// candidates. This is not covered by the more general DiagnoseArityMismatch()
+/// over a candidate in any candidate set.
+bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
- const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
-
unsigned MinParams = Fn->getMinRequiredArguments();
// With invalid overloaded operators, it's possible that we think we
- // have an arity mismatch when it fact it looks like we have the
+ // have an arity mismatch when in fact it looks like we have the
// 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() &&
Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
- return;
+ return true;
- // at least / at most / exactly
- unsigned mode, modeCount;
- if (NumFormalArgs < MinParams) {
+ if (NumArgs < MinParams) {
assert((Cand->FailureKind == ovl_fail_too_few_arguments) ||
(Cand->FailureKind == ovl_fail_bad_deduction &&
Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments));
+ } else {
+ assert((Cand->FailureKind == ovl_fail_too_many_arguments) ||
+ (Cand->FailureKind == ovl_fail_bad_deduction &&
+ Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments));
+ }
+
+ return false;
+}
+
+/// General arity mismatch diagnosis over a candidate in a candidate set.
+void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
+ assert(isa<FunctionDecl>(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();
+
+ // at least / at most / exactly
+ unsigned mode, modeCount;
+ if (NumFormalArgs < MinParams) {
if (MinParams != FnTy->getNumArgs() ||
FnTy->isVariadic() || FnTy->isTemplateVariadic())
mode = 0; // "at least"
@@ -8341,9 +8564,6 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
mode = 2; // "exactly"
modeCount = MinParams;
} else {
- assert((Cand->FailureKind == ovl_fail_too_many_arguments) ||
- (Cand->FailureKind == ovl_fail_bad_deduction &&
- Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments));
if (MinParams != FnTy->getNumArgs())
mode = 1; // "at most"
else
@@ -8365,25 +8585,42 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
MaybeEmitInheritedConstructorNote(S, Fn);
}
+/// Arity mismatch diagnosis specific to a function overload candidate.
+void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumFormalArgs) {
+ if (!CheckArityMismatch(S, Cand, NumFormalArgs))
+ DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs);
+}
+
+TemplateDecl *getDescribedTemplate(Decl *Templated) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated))
+ return FD->getDescribedFunctionTemplate();
+ else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated))
+ return RD->getDescribedClassTemplate();
+
+ llvm_unreachable("Unsupported: Getting the described template declaration"
+ " for bad deduction diagnosis");
+}
+
/// Diagnose a failed template-argument deduction.
-void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
+void DiagnoseBadDeduction(Sema &S, Decl *Templated,
+ DeductionFailureInfo &DeductionFailure,
unsigned NumArgs) {
- FunctionDecl *Fn = Cand->Function; // pattern
-
- TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter();
+ TemplateParameter Param = DeductionFailure.getTemplateParameter();
NamedDecl *ParamD;
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
(ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
(ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
- switch (Cand->DeductionFailure.Result) {
+ switch (DeductionFailure.Result) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
case Sema::TDK_Incomplete: {
assert(ParamD && "no parameter found for incomplete deduction result");
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
- << ParamD->getDeclName();
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_incomplete_deduction)
+ << ParamD->getDeclName();
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
}
@@ -8391,7 +8628,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
assert(ParamD && "no parameter found for bad qualifiers deduction result");
TemplateTypeParmDecl *TParam = cast<TemplateTypeParmDecl>(ParamD);
- QualType Param = Cand->DeductionFailure.getFirstArg()->getAsType();
+ QualType Param = DeductionFailure.getFirstArg()->getAsType();
// Param will have been canonicalized, but it should just be a
// qualified version of ParamD, so move the qualifiers to that.
@@ -8404,11 +8641,11 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
// about that. It also doesn't matter as much, because it won't
// have any template parameters in it (because deduction isn't
// done on dependent types).
- QualType Arg = Cand->DeductionFailure.getSecondArg()->getAsType();
+ QualType Arg = DeductionFailure.getSecondArg()->getAsType();
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified)
- << ParamD->getDeclName() << Arg << NonCanonParam;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified)
+ << ParamD->getDeclName() << Arg << NonCanonParam;
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
}
@@ -8423,20 +8660,20 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
which = 2;
}
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction)
- << which << ParamD->getDeclName()
- << *Cand->DeductionFailure.getFirstArg()
- << *Cand->DeductionFailure.getSecondArg();
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_inconsistent_deduction)
+ << which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
+ << *DeductionFailure.getSecondArg();
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
}
case Sema::TDK_InvalidExplicitArguments:
assert(ParamD && "no parameter found for invalid explicit arguments");
if (ParamD->getDeclName())
- S.Diag(Fn->getLocation(),
+ S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_explicit_arg_mismatch_named)
- << ParamD->getDeclName();
+ << ParamD->getDeclName();
else {
int index = 0;
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
@@ -8446,35 +8683,36 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
index = NTTP->getIndex();
else
index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex();
- S.Diag(Fn->getLocation(),
+ S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
- << (index + 1);
+ << (index + 1);
}
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
- DiagnoseArityMismatch(S, Cand, NumArgs);
+ DiagnoseArityMismatch(S, Templated, NumArgs);
return;
case Sema::TDK_InstantiationDepth:
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_instantiation_depth);
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
case Sema::TDK_SubstitutionFailure: {
// Format the template argument list into the argument string.
SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
- Cand->DeductionFailure.getTemplateArgumentList()) {
+ DeductionFailure.getTemplateArgumentList()) {
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
- Fn->getDescribedFunctionTemplate()->getTemplateParameters(), *Args);
+ getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
}
// If this candidate was disabled by enable_if, say so.
- PartialDiagnosticAt *PDiag = Cand->DeductionFailure.getSFINAEDiagnostic();
+ PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic();
if (PDiag && PDiag->second.getDiagID() ==
diag::err_typename_nested_not_found_enable_if) {
// FIXME: Use the source range of the condition, and the fully-qualified
@@ -8495,25 +8733,25 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString);
}
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
- << TemplateArgString << SFINAEArgString << R;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_substitution_failure)
+ << TemplateArgString << SFINAEArgString << R;
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
}
case Sema::TDK_FailedOverloadResolution: {
- OverloadExpr::FindResult R =
- OverloadExpr::find(Cand->DeductionFailure.getExpr());
- S.Diag(Fn->getLocation(),
+ OverloadExpr::FindResult R = OverloadExpr::find(DeductionFailure.getExpr());
+ S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_failed_overload_resolution)
- << R.Expression->getName();
+ << R.Expression->getName();
return;
}
case Sema::TDK_NonDeducedMismatch: {
// FIXME: Provide a source location to indicate what we couldn't match.
- TemplateArgument FirstTA = *Cand->DeductionFailure.getFirstArg();
- TemplateArgument SecondTA = *Cand->DeductionFailure.getSecondArg();
+ TemplateArgument FirstTA = *DeductionFailure.getFirstArg();
+ TemplateArgument SecondTA = *DeductionFailure.getSecondArg();
if (FirstTA.getKind() == TemplateArgument::Template &&
SecondTA.getKind() == TemplateArgument::Template) {
TemplateName FirstTN = FirstTA.getAsTemplate();
@@ -8528,26 +8766,42 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
// 2) The diagnostic printer only attempts to find a better
// name for types, not decls.
// Ideally, this should folded into the diagnostic printer.
- S.Diag(Fn->getLocation(),
+ S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch_qualified)
<< FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl();
return;
}
}
}
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch)
- << FirstTA << SecondTA;
+ // 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
+ // (or instead of?) the canonical template type parameters.
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_non_deduced_mismatch)
+ << FirstTA << SecondTA;
return;
}
// TODO: diagnose these individually, then kill off
// note_ovl_candidate_bad_deduction, which is uselessly vague.
case Sema::TDK_MiscellaneousDeductionFailure:
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction);
+ MaybeEmitInheritedConstructorNote(S, Templated);
return;
}
}
+/// Diagnose a failed template-argument deduction, for function calls.
+void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) {
+ unsigned TDK = Cand->DeductionFailure.Result;
+ if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) {
+ if (CheckArityMismatch(S, Cand, NumArgs))
+ return;
+ }
+ DiagnoseBadDeduction(S, Cand->Function, // pattern
+ Cand->DeductionFailure, NumArgs);
+}
+
/// CUDA: diagnose an invalid call across targets.
void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext);
@@ -8695,7 +8949,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
}
}
-SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
+static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
if (Cand->Function)
return Cand->Function->getLocation();
if (Cand->IsSurrogate)
@@ -8703,8 +8957,7 @@ SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
return SourceLocation();
}
-static unsigned
-RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
+static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
@@ -8997,6 +9250,108 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
S.Diag(OpLoc, diag::note_ovl_too_many_candidates) << int(E - I);
}
+static SourceLocation
+GetLocationForCandidate(const TemplateSpecCandidate *Cand) {
+ return Cand->Specialization ? Cand->Specialization->getLocation()
+ : SourceLocation();
+}
+
+struct CompareTemplateSpecCandidatesForDisplay {
+ Sema &S;
+ CompareTemplateSpecCandidatesForDisplay(Sema &S) : S(S) {}
+
+ bool operator()(const TemplateSpecCandidate *L,
+ const TemplateSpecCandidate *R) {
+ // Fast-path this check.
+ if (L == R)
+ return false;
+
+ // Assuming that both candidates are not matches...
+
+ // Sort by the ranking of deduction failures.
+ if (L->DeductionFailure.Result != R->DeductionFailure.Result)
+ return RankDeductionFailure(L->DeductionFailure) <
+ RankDeductionFailure(R->DeductionFailure);
+
+ // Sort everything else by location.
+ SourceLocation LLoc = GetLocationForCandidate(L);
+ SourceLocation RLoc = GetLocationForCandidate(R);
+
+ // Put candidates without locations (e.g. builtins) at the end.
+ if (LLoc.isInvalid())
+ return false;
+ if (RLoc.isInvalid())
+ return true;
+
+ return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
+ }
+};
+
+/// Diagnose a template argument deduction failure.
+/// We are treating these failures as overload failures due to bad
+/// deductions.
+void TemplateSpecCandidate::NoteDeductionFailure(Sema &S) {
+ DiagnoseBadDeduction(S, Specialization, // pattern
+ DeductionFailure, /*NumArgs=*/0);
+}
+
+void TemplateSpecCandidateSet::destroyCandidates() {
+ for (iterator i = begin(), e = end(); i != e; ++i) {
+ i->DeductionFailure.Destroy();
+ }
+}
+
+void TemplateSpecCandidateSet::clear() {
+ destroyCandidates();
+ Candidates.clear();
+}
+
+/// NoteCandidates - When no template specialization match is found, prints
+/// diagnostic messages containing the non-matching specializations that form
+/// the candidate set.
+/// This is analoguous to OverloadCandidateSet::NoteCandidates() with
+/// OCD == OCD_AllCandidates and Cand->Viable == false.
+void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
+ // Sort the candidates by position (assuming no candidate is a match).
+ // Sorting directly would be prohibitive, so we make a set of pointers
+ // and sort those.
+ SmallVector<TemplateSpecCandidate *, 32> Cands;
+ Cands.reserve(size());
+ for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
+ if (Cand->Specialization)
+ Cands.push_back(Cand);
+ // Otherwise, this is a non matching builtin candidate. We do not,
+ // in general, want to list every possible builtin candidate.
+ }
+
+ std::sort(Cands.begin(), Cands.end(),
+ CompareTemplateSpecCandidatesForDisplay(S));
+
+ // FIXME: Perhaps rename OverloadsShown and getShowOverloads()
+ // for generalization purposes (?).
+ const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
+
+ SmallVectorImpl<TemplateSpecCandidate *>::iterator I, E;
+ unsigned CandsShown = 0;
+ for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ TemplateSpecCandidate *Cand = *I;
+
+ // Set an arbitrary limit on the number of candidates we'll spam
+ // the user with. FIXME: This limit should depend on details of the
+ // candidate list.
+ if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
+ break;
+ ++CandsShown;
+
+ assert(Cand->Specialization &&
+ "Non-matching built-in candidates are not added to Cands.");
+ Cand->NoteDeductionFailure(S);
+ }
+
+ if (I != E)
+ S.Diag(Loc, diag::note_ovl_too_many_candidates) << int(E - I);
+}
+
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
@@ -9034,47 +9389,51 @@ class AddressOfFunctionResolver
bool TargetTypeIsNonStaticMemberFunction;
bool FoundNonTemplateFunction;
+ bool StaticMemberFunctionFromBoundPointer;
OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+ TemplateSpecCandidateSet FailedCandidates;
public:
- AddressOfFunctionResolver(Sema &S, Expr* SourceExpr,
- const QualType& TargetType, bool Complain)
- : S(S), SourceExpr(SourceExpr), TargetType(TargetType),
- Complain(Complain), Context(S.getASTContext()),
- TargetTypeIsNonStaticMemberFunction(
- !!TargetType->getAs<MemberPointerType>()),
- FoundNonTemplateFunction(false),
- OvlExprInfo(OverloadExpr::find(SourceExpr)),
- OvlExpr(OvlExprInfo.Expression)
- {
+ AddressOfFunctionResolver(Sema &S, Expr *SourceExpr,
+ const QualType &TargetType, bool Complain)
+ : S(S), SourceExpr(SourceExpr), TargetType(TargetType),
+ Complain(Complain), Context(S.getASTContext()),
+ TargetTypeIsNonStaticMemberFunction(
+ !!TargetType->getAs<MemberPointerType>()),
+ FoundNonTemplateFunction(false),
+ StaticMemberFunctionFromBoundPointer(false),
+ OvlExprInfo(OverloadExpr::find(SourceExpr)),
+ OvlExpr(OvlExprInfo.Expression),
+ FailedCandidates(OvlExpr->getNameLoc()) {
ExtractUnqualifiedFunctionTypeFromTargetType();
-
- if (!TargetFunctionType->isFunctionType()) {
- if (OvlExpr->hasExplicitTemplateArgs()) {
- DeclAccessPair dap;
- if (FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
- OvlExpr, false, &dap) ) {
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
- if (!Method->isStatic()) {
- // If the target type is a non-function type and the function
- // found is a non-static member function, pretend as if that was
- // the target, it's the only possible type to end up with.
- TargetTypeIsNonStaticMemberFunction = true;
-
- // And skip adding the function if its not in the proper form.
- // We'll diagnose this due to an empty set of functions.
- if (!OvlExprInfo.HasFormOfMemberPointer)
- return;
- }
+
+ if (TargetFunctionType->isFunctionType()) {
+ if (UnresolvedMemberExpr *UME = dyn_cast<UnresolvedMemberExpr>(OvlExpr))
+ if (!UME->isImplicitAccess() &&
+ !S.ResolveSingleFunctionTemplateSpecialization(UME))
+ StaticMemberFunctionFromBoundPointer = true;
+ } else if (OvlExpr->hasExplicitTemplateArgs()) {
+ DeclAccessPair dap;
+ if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization(
+ OvlExpr, false, &dap)) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
+ if (!Method->isStatic()) {
+ // If the target type is a non-function type and the function found
+ // is a non-static member function, pretend as if that was the
+ // target, it's the only possible type to end up with.
+ TargetTypeIsNonStaticMemberFunction = true;
+
+ // And skip adding the function if its not in the proper form.
+ // We'll diagnose this due to an empty set of functions.
+ if (!OvlExprInfo.HasFormOfMemberPointer)
+ return;
}
- Matches.push_back(std::make_pair(dap,Fn));
- }
+ Matches.push_back(std::make_pair(dap, Fn));
}
return;
}
@@ -9128,14 +9487,16 @@ private:
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(OvlExpr->getNameLoc());
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (Sema::TemplateDeductionResult Result
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
TargetFunctionType, Specialization,
Info, /*InOverloadResolution=*/true)) {
- // FIXME: make a note of the failed deduction for diagnostics.
- (void)Result;
+ // Make a note of the failed deduction for diagnostics.
+ FailedCandidates.addCandidate()
+ .set(FunctionTemplate->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, Result, Info));
return false;
}
@@ -9239,15 +9600,15 @@ private:
for (unsigned I = 0, E = Matches.size(); I != E; ++I)
MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
- UnresolvedSetIterator Result =
- S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
- TPOC_Other, 0, SourceExpr->getLocStart(),
- S.PDiag(),
- S.PDiag(diag::err_addr_ovl_ambiguous)
- << Matches[0].second->getDeclName(),
- S.PDiag(diag::note_ovl_candidate)
- << (unsigned) oc_function_template,
- Complain, TargetFunctionType);
+ // TODO: It looks like FailedCandidates does not serve much purpose
+ // here, since the no_viable diagnostic has index 0.
+ UnresolvedSetIterator Result = S.getMostSpecialized(
+ MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates,
+ SourceExpr->getLocStart(), S.PDiag(),
+ S.PDiag(diag::err_addr_ovl_ambiguous) << Matches[0]
+ .second->getDeclName(),
+ S.PDiag(diag::note_ovl_candidate) << (unsigned)oc_function_template,
+ Complain, TargetFunctionType);
if (Result != MatchesCopy.end()) {
// Make it the first and only element
@@ -9276,14 +9637,27 @@ public:
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable)
<< OvlExpr->getName() << TargetFunctionType
<< OvlExpr->getSourceRange();
- S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType);
- }
-
+ if (FailedCandidates.empty())
+ S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType);
+ else {
+ // We have some deduction failure messages. Use them to diagnose
+ // the function templates, and diagnose the non-template candidates
+ // normally.
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ IEnd = OvlExpr->decls_end();
+ I != IEnd; ++I)
+ if (FunctionDecl *Fun =
+ dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
+ S.NoteOverloadCandidate(Fun, TargetFunctionType);
+ FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart());
+ }
+ }
+
bool IsInvalidFormOfPointerToMemberFunction() const {
return TargetTypeIsNonStaticMemberFunction &&
!OvlExprInfo.HasFormOfMemberPointer;
}
-
+
void ComplainIsInvalidFormOfPointerToMemberFunction() const {
// TODO: Should we condition this on whether any functions might
// have matched, or is it more appropriate to do that in callers?
@@ -9291,7 +9665,17 @@ public:
S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
<< TargetType << OvlExpr->getSourceRange();
}
-
+
+ bool IsStaticMemberFunctionFromBoundPointer() const {
+ return StaticMemberFunctionFromBoundPointer;
+ }
+
+ void ComplainIsStaticMemberFunctionFromBoundPointer() const {
+ S.Diag(OvlExpr->getLocStart(),
+ diag::err_invalid_form_pointer_member_function)
+ << OvlExpr->getSourceRange();
+ }
+
void ComplainOfInvalidConversion() const {
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
<< OvlExpr->getName() << TargetType;
@@ -9359,8 +9743,12 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
- if (Complain)
- CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
+ if (Complain) {
+ if (Resolver.IsStaticMemberFunctionFromBoundPointer())
+ Resolver.ComplainIsStaticMemberFunctionFromBoundPointer();
+ else
+ CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
+ }
}
if (pHadMultipleCandidates)
@@ -9375,6 +9763,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
/// template, where that template-id refers to a single template whose template
/// arguments are either provided by the template-id or have defaults,
/// as described in C++0x [temp.arg.explicit]p3.
+///
+/// If no template-ids are found, no diagnostics are emitted and NULL is
+/// returned.
FunctionDecl *
Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain,
@@ -9392,6 +9783,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
TemplateArgumentListInfo ExplicitTemplateArgs;
ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
+ TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc());
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
@@ -9414,13 +9806,16 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(ovl->getNameLoc());
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info,
/*InOverloadResolution=*/true)) {
- // FIXME: make a note of the failed deduction for diagnostics.
- (void)Result;
+ // Make a note of the failed deduction for diagnostics.
+ // TODO: Actually use the failed-deduction info?
+ FailedCandidates.addCandidate()
+ .set(FunctionTemplate->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, Result, Info));
continue;
}
@@ -9623,6 +10018,19 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
CandidateSet, PartialOverloading);
}
+/// Determine whether a declaration with the specified name could be moved into
+/// a different namespace.
+static bool canBeDeclaredInNamespace(const DeclarationName &Name) {
+ switch (Name.getCXXOverloadedOperator()) {
+ case OO_New: case OO_Array_New:
+ case OO_Delete: case OO_Array_Delete:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
/// Attempt to recover from an ill-formed use of a non-dependent name in a
/// template, where the non-dependent name was declared after the template
/// was defined. This is common in code written for a compilers which do not
@@ -9675,22 +10083,24 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
AssociatedNamespaces,
AssociatedClasses);
Sema::AssociatedNamespaceSet SuggestedNamespaces;
- DeclContext *Std = SemaRef.getStdNamespace();
- for (Sema::AssociatedNamespaceSet::iterator
- it = AssociatedNamespaces.begin(),
- end = AssociatedNamespaces.end(); it != end; ++it) {
- // Never suggest declaring a function within namespace 'std'.
- if (Std && Std->Encloses(*it))
- continue;
-
- // Never suggest declaring a function within a namespace with a reserved
- // name, like __gnu_cxx.
- NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
- if (NS &&
- NS->getQualifiedNameAsString().find("__") != std::string::npos)
- continue;
+ if (canBeDeclaredInNamespace(R.getLookupName())) {
+ DeclContext *Std = SemaRef.getStdNamespace();
+ for (Sema::AssociatedNamespaceSet::iterator
+ it = AssociatedNamespaces.begin(),
+ end = AssociatedNamespaces.end(); it != end; ++it) {
+ // Never suggest declaring a function within namespace 'std'.
+ if (Std && Std->Encloses(*it))
+ continue;
- SuggestedNamespaces.insert(*it);
+ // Never suggest declaring a function within a namespace with a
+ // reserved name, like __gnu_cxx.
+ NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
+ if (NS &&
+ NS->getQualifiedNameAsString().find("__") != std::string::npos)
+ continue;
+
+ SuggestedNamespaces.insert(*it);
+ }
}
SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
@@ -9739,67 +10149,6 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
}
namespace {
-// Callback to limit the allowed keywords and to only accept typo corrections
-// that are keywords or whose decls refer to functions (or template functions)
-// that accept the given number of arguments.
-class RecoveryCallCCC : public CorrectionCandidateCallback {
- public:
- RecoveryCallCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs)
- : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) {
- WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
- WantRemainingKeywords = false;
- }
-
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
- if (!candidate.getCorrectionDecl())
- return candidate.isKeyword();
-
- for (TypoCorrection::const_decl_iterator DI = candidate.begin(),
- DIEnd = candidate.end(); DI != DIEnd; ++DI) {
- FunctionDecl *FD = 0;
- NamedDecl *ND = (*DI)->getUnderlyingDecl();
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- FD = FTD->getTemplatedDecl();
- if (!HasExplicitTemplateArgs && !FD) {
- if (!(FD = dyn_cast<FunctionDecl>(ND)) && isa<ValueDecl>(ND)) {
- // If the Decl is neither a function nor a template function,
- // determine if it is a pointer or reference to a function. If so,
- // check against the number of arguments expected for the pointee.
- QualType ValType = cast<ValueDecl>(ND)->getType();
- if (ValType->isAnyPointerType() || ValType->isReferenceType())
- ValType = ValType->getPointeeType();
- if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>())
- if (FPT->getNumArgs() == NumArgs)
- return true;
- }
- }
- if (FD && FD->getNumParams() >= NumArgs &&
- FD->getMinRequiredArguments() <= NumArgs)
- return true;
- }
- return false;
- }
-
- private:
- unsigned NumArgs;
- bool HasExplicitTemplateArgs;
-};
-
-// Callback that effectively disabled typo correction
-class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
- public:
- NoTypoCorrectionCCC() {
- WantTypeSpecifiers = false;
- WantExpressionKeywords = false;
- WantCXXNamedCasts = false;
- WantRemainingKeywords = false;
- }
-
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
- return false;
- }
-};
-
class BuildRecoveryCallExprRAII {
Sema &SemaRef;
public:
@@ -9848,7 +10197,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- RecoveryCallCCC Validator(SemaRef, Args.size(), ExplicitTemplateArgs != 0);
+ FunctionCallFilterCCC Validator(SemaRef, Args.size(),
+ ExplicitTemplateArgs != 0);
NoTypoCorrectionCCC RejectAll;
CorrectionCandidateCallback *CCC = AllowTypoCorrection ?
(CorrectionCandidateCallback*)&Validator :
@@ -9890,7 +10240,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
/// \returns true when an the ExprResult output parameter has been set.
bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc,
OverloadCandidateSet *CandidateSet,
ExprResult *Result) {
@@ -9913,15 +10263,14 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
#endif
UnbridgedCastsSet UnbridgedCasts;
- if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) {
+ if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
*Result = ExprError();
return true;
}
// Add the functions denoted by the callee to the set of candidate
// functions, including those from argument-dependent lookup.
- AddOverloadedCallCandidates(ULE, llvm::makeArrayRef(Args, NumArgs),
- *CandidateSet);
+ AddOverloadedCallCandidates(ULE, Args, *CandidateSet);
// If we found nothing, try to recover.
// BuildRecoveryCallExpr diagnoses the error itself, so we just bail
@@ -9933,8 +10282,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// classes.
if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
(isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
- CallExpr *CE = new (Context) CallExpr(Context, Fn,
- llvm::makeArrayRef(Args, NumArgs),
+ CallExpr *CE = new (Context) CallExpr(Context, Fn, Args,
Context.DependentTy, VK_RValue,
RParenLoc);
CE->setTypeDependent(true);
@@ -9954,7 +10302,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
OverloadCandidateSet *CandidateSet,
@@ -9962,8 +10310,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
OverloadingResult OverloadResult,
bool AllowTypoCorrection) {
if (CandidateSet->empty())
- return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
- llvm::MutableArrayRef<Expr *>(Args, NumArgs),
+ return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, Args,
RParenLoc, /*EmptyLookup=*/true,
AllowTypoCorrection);
@@ -9974,16 +10321,15 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()))
return ExprError();
Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
- return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
+ return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc,
+ ExecConfig);
}
case OR_No_Viable_Function: {
// Try to recover by looking for viable functions which the user might
// have meant to call.
ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
- llvm::MutableArrayRef<Expr *>(Args, NumArgs),
- RParenLoc,
+ Args, RParenLoc,
/*EmptyLookup=*/false,
AllowTypoCorrection);
if (!Recovery.isInvalid())
@@ -9992,16 +10338,14 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
SemaRef.Diag(Fn->getLocStart(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
break;
}
case OR_Ambiguous:
SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates, Args);
break;
case OR_Deleted: {
@@ -10010,15 +10354,14 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
<< ULE->getName()
<< SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function)
<< Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
// We emitted an error for the unvailable/deleted function call but keep
// the call in the AST.
FunctionDecl *FDecl = (*Best)->Function;
Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
- return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
+ return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc,
+ ExecConfig);
}
}
@@ -10035,22 +10378,22 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection) {
OverloadCandidateSet CandidateSet(Fn->getExprLoc());
ExprResult result;
- if (buildOverloadedCallSet(S, Fn, ULE, Args, NumArgs, LParenLoc,
- &CandidateSet, &result))
+ if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
+ &result))
return result;
OverloadCandidateSet::iterator Best;
OverloadingResult OverloadResult =
CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best);
- return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
+ return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args,
RParenLoc, ExecConfig, &CandidateSet,
&Best, OverloadResult,
AllowTypoCorrection);
@@ -10180,17 +10523,17 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input = InputInit.take();
}
- // Determine the result type.
- QualType ResultTy = FnDecl->getResultType();
- ExprValueKind VK = Expr::getValueKindForType(ResultTy);
- ResultTy = ResultTy.getNonLValueExprType(Context);
-
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
+ // Determine the result type.
+ QualType ResultTy = FnDecl->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(ResultTy);
+ ResultTy = ResultTy.getNonLValueExprType(Context);
+
Args[0] = Input;
CallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), ArgsArray,
@@ -10414,11 +10757,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Args[1] = RHS = Arg1.takeAs<Expr>();
}
- // Determine the result type.
- QualType ResultTy = FnDecl->getResultType();
- ExprValueKind VK = Expr::getValueKindForType(ResultTy);
- ResultTy = ResultTy.getNonLValueExprType(Context);
-
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
Best->FoundDecl,
@@ -10426,6 +10764,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (FnExpr.isInvalid())
return ExprError();
+ // Determine the result type.
+ QualType ResultTy = FnDecl->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(ResultTy);
+ ResultTy = ResultTy.getNonLValueExprType(Context);
+
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
Args, ResultTy, VK, OpLoc,
@@ -10481,6 +10824,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ if (Args[0]->getType()->isIncompleteType()) {
+ Diag(OpLoc, diag::note_assign_lhs_incomplete)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ }
} else {
// This is an erroneous use of an operator which can be overloaded by
// a non-member function. Check for non-member operators which were
@@ -10621,11 +10969,6 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Args[1] = InputInit.takeAs<Expr>();
- // Determine the result type
- QualType ResultTy = FnDecl->getResultType();
- ExprValueKind VK = Expr::getValueKindForType(ResultTy);
- ResultTy = ResultTy.getNonLValueExprType(Context);
-
// Build the actual expression node.
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
@@ -10637,6 +10980,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
if (FnExpr.isInvalid())
return ExprError();
+ // Determine the result type
+ QualType ResultTy = FnDecl->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(ResultTy);
+ ResultTy = ResultTy.getNonLValueExprType(Context);
+
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
FnExpr.take(), Args,
@@ -10716,8 +11064,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
/// member function.
ExprResult
Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
- SourceLocation LParenLoc, Expr **Args,
- unsigned NumArgs, SourceLocation RParenLoc) {
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc) {
assert(MemExprE->getType() == Context.BoundMemberTy ||
MemExprE->getType() == Context.OverloadTy);
@@ -10758,8 +11107,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
CXXMemberCallExpr *call
- = new (Context) CXXMemberCallExpr(Context, MemExprE,
- llvm::makeArrayRef(Args, NumArgs),
+ = new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
resultType, valueKind, RParenLoc);
if (CheckCallReturnType(proto->getResultType(),
@@ -10767,14 +11115,17 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
call, 0))
return ExprError();
- if (ConvertArgumentsForCall(call, op, 0, proto, Args, NumArgs, RParenLoc))
+ if (ConvertArgumentsForCall(call, op, 0, proto, Args, RParenLoc))
+ return ExprError();
+
+ if (CheckOtherCall(call, proto))
return ExprError();
return MaybeBindToTemporary(call);
}
UnbridgedCastsSet UnbridgedCasts;
- if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
+ if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();
MemberExpr *MemExpr;
@@ -10818,7 +11169,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Microsoft supports direct constructor calls.
if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(),
- llvm::makeArrayRef(Args, NumArgs), CandidateSet);
+ Args, CandidateSet);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
@@ -10826,15 +11177,13 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
continue;
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
- ObjectClassification,
- llvm::makeArrayRef(Args, NumArgs), CandidateSet,
+ ObjectClassification, Args, CandidateSet,
/*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
I.getPair(), ActingDC, TemplateArgs,
ObjectType, ObjectClassification,
- llvm::makeArrayRef(Args, NumArgs),
- CandidateSet,
+ Args, CandidateSet,
/*SuppressUsedConversions=*/false);
}
}
@@ -10852,22 +11201,29 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
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
+ // 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() &&
+ DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
+ return ExprError();
break;
case OR_No_Viable_Function:
Diag(UnresExpr->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -10877,8 +11233,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< DeclName
<< getDeletedOrUnavailableSuffix(Best->Function)
<< MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
}
@@ -10888,8 +11243,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// If overload resolution picked a static member, build a
// non-member call based on that function.
if (Method->isStatic()) {
- return BuildResolvedCallExpr(MemExprE, Method, LParenLoc,
- Args, NumArgs, RParenLoc);
+ return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, Args,
+ RParenLoc);
}
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
@@ -10901,8 +11256,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
assert(Method && "Member call to something that isn't a method?");
CXXMemberCallExpr *TheCall =
- new (Context) CXXMemberCallExpr(Context, MemExprE,
- llvm::makeArrayRef(Args, NumArgs),
+ new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
ResultType, VK, RParenLoc);
// Check for a valid return type.
@@ -10925,11 +11279,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Convert the rest of the arguments
const FunctionProtoType *Proto =
Method->getType()->getAs<FunctionProtoType>();
- if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args, NumArgs,
+ if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args,
RParenLoc))
return ExprError();
- DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
+ DiagnoseSentinelCalls(Method, LParenLoc, Args);
if (CheckFunctionCall(Method, TheCall, Proto))
return ExprError();
@@ -10958,14 +11312,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
ExprResult
Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg Args,
SourceLocation RParenLoc) {
if (checkPlaceholderForOverload(*this, Obj))
return ExprError();
ExprResult Object = Owned(Obj);
UnbridgedCastsSet UnbridgedCasts;
- if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
+ if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();
assert(Object.get()->getType()->isRecordType() && "Requires object type argument");
@@ -10992,8 +11346,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
- Object.get()->Classify(Context),
- llvm::makeArrayRef(Args, NumArgs), CandidateSet,
+ Object.get()->Classify(Context),
+ Args, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -11040,8 +11394,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
{
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
- Object.get(), llvm::makeArrayRef(Args, NumArgs),
- CandidateSet);
+ Object.get(), Args, CandidateSet);
}
}
}
@@ -11066,16 +11419,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Diag(Object.get()->getLocStart(),
diag::err_ovl_no_viable_object_call)
<< Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
break;
case OR_Ambiguous:
Diag(Object.get()->getLocStart(),
diag::err_ovl_ambiguous_object_call)
<< Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args);
break;
case OR_Deleted:
@@ -11085,8 +11436,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
<< Object.get()->getType()
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
break;
}
@@ -11105,7 +11455,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
return ExprError();
-
+ 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
// on the object argument, then let ActOnCallExpr finish the job.
@@ -11121,8 +11472,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CK_UserDefinedConversion,
Call.get(), 0, VK_RValue));
- return ActOnCallExpr(S, Call.get(), LParenLoc, MultiExprArg(Args, NumArgs),
- RParenLoc);
+ return ActOnCallExpr(S, Call.get(), LParenLoc, Args, RParenLoc);
}
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
@@ -11140,21 +11490,6 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Method->getType()->getAs<FunctionProtoType>();
unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumArgsToCheck = NumArgs;
-
- // Build the full argument list for the method call (the
- // implicit object parameter is placed at the beginning of the
- // list).
- Expr **MethodArgs;
- if (NumArgs < NumArgsInProto) {
- NumArgsToCheck = NumArgsInProto;
- MethodArgs = new Expr*[NumArgsInProto + 1];
- } else {
- MethodArgs = new Expr*[NumArgs + 1];
- }
- MethodArgs[0] = Object.get();
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- MethodArgs[ArgIdx + 1] = Args[ArgIdx];
DeclarationNameInfo OpLocInfo(
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
@@ -11166,17 +11501,23 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (NewFn.isInvalid())
return true;
+ // Build the full argument list for the method call (the implicit object
+ // parameter is placed at the beginning of the list).
+ llvm::OwningArrayPtr<Expr *> MethodArgs(new Expr*[Args.size() + 1]);
+ MethodArgs[0] = Object.get();
+ std::copy(Args.begin(), Args.end(), &MethodArgs[1]);
+
// Once we've built TheCall, all of the expressions are properly
// owned.
QualType ResultTy = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
- llvm::makeArrayRef(MethodArgs, NumArgs+1),
- ResultTy, VK, RParenLoc, false);
- delete [] MethodArgs;
+ CXXOperatorCallExpr *TheCall = new (Context)
+ CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
+ llvm::makeArrayRef(MethodArgs.get(), Args.size() + 1),
+ ResultTy, VK, RParenLoc, false);
+ MethodArgs.reset();
if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall,
Method))
@@ -11184,10 +11525,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// We may have default arguments. If so, we need to allocate more
// slots in the call for them.
- if (NumArgs < NumArgsInProto)
+ if (Args.size() < NumArgsInProto)
TheCall->setNumArgs(Context, NumArgsInProto + 1);
- else if (NumArgs > NumArgsInProto)
- NumArgsToCheck = NumArgsInProto;
bool IsError = false;
@@ -11202,9 +11541,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
TheCall->setArg(0, Object.take());
// Check the argument types.
- for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ for (unsigned i = 0; i != NumArgsInProto; i++) {
Expr *Arg;
- if (i < NumArgs) {
+ if (i < Args.size()) {
Arg = Args[i];
// Pass the argument.
@@ -11234,7 +11573,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i < NumArgs; i++) {
+ for (unsigned i = NumArgsInProto, e = Args.size(); i < e; i++) {
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
IsError |= Arg.isInvalid();
TheCall->setArg(i + 1, Arg.take());
@@ -11243,7 +11582,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (IsError) return true;
- DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
+ DiagnoseSentinelCalls(Method, LParenLoc, Args);
if (CheckFunctionCall(Method, TheCall, Proto))
return true;
@@ -11255,7 +11594,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
/// (if one exists), where @c Base is an expression of class type and
/// @c Member is the name of the member we're trying to find.
ExprResult
-Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
+Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
+ bool *NoArrowOperatorFound) {
assert(Base->getType()->isRecordType() &&
"left-hand side must have class type");
@@ -11299,10 +11639,21 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
break;
case OR_No_Viable_Function:
- if (CandidateSet.empty())
+ if (CandidateSet.empty()) {
+ QualType BaseType = Base->getType();
+ if (NoArrowOperatorFound) {
+ // Report this specific error to the caller instead of emitting a
+ // diagnostic, as requested.
+ *NoArrowOperatorFound = true;
+ return ExprError();
+ }
Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
- << Base->getType() << Base->getSourceRange();
- else
+ << BaseType << Base->getSourceRange();
+ if (BaseType->isRecordType() && !BaseType->isPointerType()) {
+ Diag(OpLoc, diag::note_typecheck_member_reference_suggestion)
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ }
+ } else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
@@ -11473,7 +11824,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
/*NeedsADL=*/true, /*Overloaded=*/false,
FoundNames.begin(), FoundNames.end());
- bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc,
+ bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, Range, Loc,
CandidateSet, CallExpr);
if (CandidateSet->empty() || CandidateSetError) {
*CallExpr = ExprError();
@@ -11487,7 +11838,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
*CallExpr = ExprError();
return FRS_NoViableFunction;
}
- *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, &Range, 1,
+ *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, Range,
Loc, 0, CandidateSet, &Best,
OverloadResult,
/*AllowTypoCorrection=*/false);
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 054d557e92d0..af74f0d4a3e8 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -101,6 +101,25 @@ namespace {
resultIndex);
}
+ if (ChooseExpr *ce = dyn_cast<ChooseExpr>(e)) {
+ assert(!ce->isConditionDependent());
+
+ Expr *LHS = ce->getLHS(), *RHS = ce->getRHS();
+ Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS : RHS;
+ rebuiltExpr = rebuild(rebuiltExpr);
+
+ return new (S.Context) ChooseExpr(ce->getBuiltinLoc(),
+ ce->getCond(),
+ LHS, RHS,
+ rebuiltExpr->getType(),
+ rebuiltExpr->getValueKind(),
+ rebuiltExpr->getObjectKind(),
+ ce->getRParenLoc(),
+ ce->isConditionTrue(),
+ rebuiltExpr->isTypeDependent(),
+ rebuiltExpr->isValueDependent());
+ }
+
llvm_unreachable("bad expression to rebuild!");
}
};
@@ -575,9 +594,9 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
RefExpr->getImplicitPropertyGetter()->getSelector()
.getIdentifierInfoForSlot(0);
SetterSelector =
- SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
- S.PP.getSelectorTable(),
- getterName);
+ SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(),
+ S.PP.getSelectorTable(),
+ getterName);
return false;
}
}
@@ -711,6 +730,16 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
op = opResult.take();
assert(op && "successful assignment left argument invalid?");
}
+ else if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(op)) {
+ Expr *Initializer = OVE->getSourceExpr();
+ // passing C++11 style initialized temporaries to objc++ properties
+ // requires special treatment by removing OpaqueValueExpr so type
+ // conversion takes place and adding the OpaqueValueExpr later on.
+ if (isa<InitListExpr>(Initializer) &&
+ Initializer->getType()->isVoidType()) {
+ op = Initializer;
+ }
+ }
}
// Arguments.
@@ -882,8 +911,8 @@ ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
SyntacticForm->getLocStart());
if (Level != DiagnosticsEngine::Ignored)
- S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr,
- SyntacticRefExpr->isMessagingGetter());
+ S.recordUseOfEvaluatedWeak(SyntacticRefExpr,
+ SyntacticRefExpr->isMessagingGetter());
}
return PseudoOpBuilder::complete(SyntacticForm);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 248665ac86cb..9bd8678c876a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -65,7 +65,7 @@ StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
SourceLocation EndLoc) {
- DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
+ DeclGroupRef DG = dg.get();
// If we have an invalid decl, just return an error.
if (DG.isNull()) return StmtError();
@@ -74,7 +74,7 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
}
void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
- DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
+ DeclGroupRef DG = dg.get();
// If we don't have a declaration, or we have an invalid declaration,
// just return.
@@ -93,9 +93,6 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
return;
}
- // suppress any potential 'unused variable' warning.
- var->setUsed();
-
// foreach variables are never actually initialized in the way that
// the parser came up with.
var->setInit(0);
@@ -294,11 +291,10 @@ sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
return getCurFunction()->CompoundScopes.back();
}
-StmtResult
-Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
- MultiStmtArg elts, bool isStmtExpr) {
- unsigned NumElts = elts.size();
- Stmt **Elts = elts.data();
+StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ ArrayRef<Stmt *> Elts, bool isStmtExpr) {
+ const unsigned NumElts = Elts.size();
+
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
@@ -335,9 +331,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
}
- return Owned(new (Context) CompoundStmt(Context,
- llvm::makeArrayRef(Elts, NumElts),
- L, R));
+ return Owned(new (Context) CompoundStmt(Context, Elts, L, R));
}
StmtResult
@@ -592,52 +586,50 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
public:
SwitchConvertDiagnoser(Expr *Cond)
- : ICEConvertDiagnoser(false, true), Cond(Cond) { }
+ : ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true),
+ Cond(Cond) {}
- virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
+ virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T;
}
- virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
- QualType T) {
+ virtual SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) {
return S.Diag(Loc, diag::err_switch_incomplete_class_type)
<< T << Cond->getSourceRange();
}
- virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
+ virtual SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy;
}
- virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) {
+ virtual SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
+ virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
return S.Diag(Loc, diag::err_switch_multiple_conversions) << T;
}
- virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) {
+ virtual SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
- QualType T,
- QualType ConvTy) {
- return DiagnosticBuilder::getEmpty();
+ virtual SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ llvm_unreachable("conversion functions are permitted");
}
} SwitchDiagnoser(Cond);
- CondResult
- = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser,
- /*AllowScopedEnumerations*/ true);
+ CondResult =
+ PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser);
if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.take();
@@ -1122,9 +1114,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
void
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
Expr *SrcExpr) {
- unsigned DIAG = diag::warn_not_in_enum_assignement;
- if (Diags.getDiagnosticLevel(DIAG, SrcExpr->getExprLoc())
- == DiagnosticsEngine::Ignored)
+ if (Diags.getDiagnosticLevel(diag::warn_not_in_enum_assignment,
+ SrcExpr->getExprLoc()) ==
+ DiagnosticsEngine::Ignored)
return;
if (const EnumType *ET = DstType->getAs<EnumType>())
@@ -1133,13 +1125,14 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
SrcExpr->isIntegerConstantExpr(Context)) {
// Get the bitwidth of the enum value before promotions.
- unsigned DstWith = Context.getIntWidth(DstType);
+ unsigned DstWidth = Context.getIntWidth(DstType);
bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
+ AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
const EnumDecl *ED = ET->getDecl();
- typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
- EnumValsTy;
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
+ EnumValsTy;
EnumValsTy EnumVals;
// Gather all enum values, set their type and sort them,
@@ -1147,21 +1140,21 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
EDI != ED->enumerator_end(); ++EDI) {
llvm::APSInt Val = EDI->getInitVal();
- AdjustAPSInt(Val, DstWith, DstIsSigned);
+ AdjustAPSInt(Val, DstWidth, DstIsSigned);
EnumVals.push_back(std::make_pair(Val, *EDI));
}
if (EnumVals.empty())
return;
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
EnumValsTy::iterator EIend =
- std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
- // See which case values aren't in enum.
+ // See which values aren't in the enum.
EnumValsTy::const_iterator EI = EnumVals.begin();
while (EI != EIend && EI->first < RhsVal)
EI++;
if (EI == EIend || EI->first != RhsVal) {
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignement)
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
<< DstType;
}
}
@@ -1220,77 +1213,77 @@ namespace {
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
llvm::SmallPtrSet<VarDecl*, 8> &Decls;
- SmallVector<SourceRange, 10> &Ranges;
+ SmallVectorImpl<SourceRange> &Ranges;
bool Simple;
-public:
- typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
-
- DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
- SmallVector<SourceRange, 10> &Ranges) :
- Inherited(S.Context),
- Decls(Decls),
- Ranges(Ranges),
- Simple(true) {}
+ public:
+ typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
- bool isSimple() { return Simple; }
+ DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ SmallVectorImpl<SourceRange> &Ranges) :
+ Inherited(S.Context),
+ Decls(Decls),
+ Ranges(Ranges),
+ Simple(true) {}
- // Replaces the method in EvaluatedExprVisitor.
- void VisitMemberExpr(MemberExpr* E) {
- Simple = false;
- }
+ bool isSimple() { return Simple; }
- // Any Stmt not whitelisted will cause the condition to be marked complex.
- void VisitStmt(Stmt *S) {
- Simple = false;
- }
+ // Replaces the method in EvaluatedExprVisitor.
+ void VisitMemberExpr(MemberExpr* E) {
+ Simple = false;
+ }
- void VisitBinaryOperator(BinaryOperator *E) {
- Visit(E->getLHS());
- Visit(E->getRHS());
- }
+ // Any Stmt not whitelisted will cause the condition to be marked complex.
+ void VisitStmt(Stmt *S) {
+ Simple = false;
+ }
- void VisitCastExpr(CastExpr *E) {
- Visit(E->getSubExpr());
- }
+ void VisitBinaryOperator(BinaryOperator *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ }
- void VisitUnaryOperator(UnaryOperator *E) {
- // Skip checking conditionals with derefernces.
- if (E->getOpcode() == UO_Deref)
- Simple = false;
- else
+ void VisitCastExpr(CastExpr *E) {
Visit(E->getSubExpr());
- }
+ }
- void VisitConditionalOperator(ConditionalOperator *E) {
- Visit(E->getCond());
- Visit(E->getTrueExpr());
- Visit(E->getFalseExpr());
- }
+ void VisitUnaryOperator(UnaryOperator *E) {
+ // Skip checking conditionals with derefernces.
+ if (E->getOpcode() == UO_Deref)
+ Simple = false;
+ else
+ Visit(E->getSubExpr());
+ }
- void VisitParenExpr(ParenExpr *E) {
- Visit(E->getSubExpr());
- }
+ void VisitConditionalOperator(ConditionalOperator *E) {
+ Visit(E->getCond());
+ Visit(E->getTrueExpr());
+ Visit(E->getFalseExpr());
+ }
- void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
- Visit(E->getOpaqueValue()->getSourceExpr());
- Visit(E->getFalseExpr());
- }
+ void VisitParenExpr(ParenExpr *E) {
+ Visit(E->getSubExpr());
+ }
+
+ void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ Visit(E->getOpaqueValue()->getSourceExpr());
+ Visit(E->getFalseExpr());
+ }
- void VisitIntegerLiteral(IntegerLiteral *E) { }
- void VisitFloatingLiteral(FloatingLiteral *E) { }
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { }
- void VisitCharacterLiteral(CharacterLiteral *E) { }
- void VisitGNUNullExpr(GNUNullExpr *E) { }
- void VisitImaginaryLiteral(ImaginaryLiteral *E) { }
+ void VisitIntegerLiteral(IntegerLiteral *E) { }
+ void VisitFloatingLiteral(FloatingLiteral *E) { }
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { }
+ void VisitCharacterLiteral(CharacterLiteral *E) { }
+ void VisitGNUNullExpr(GNUNullExpr *E) { }
+ void VisitImaginaryLiteral(ImaginaryLiteral *E) { }
- void VisitDeclRefExpr(DeclRefExpr *E) {
- VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
- if (!VD) return;
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
+ if (!VD) return;
- Ranges.push_back(E->getSourceRange());
+ Ranges.push_back(E->getSourceRange());
- Decls.insert(VD);
- }
+ Decls.insert(VD);
+ }
}; // end class DeclExtractor
@@ -1300,66 +1293,67 @@ public:
llvm::SmallPtrSet<VarDecl*, 8> &Decls;
bool FoundDecl;
-public:
- typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
+ public:
+ typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
- DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, Stmt *Statement) :
- Inherited(S.Context), Decls(Decls), FoundDecl(false) {
- if (!Statement) return;
+ DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ Stmt *Statement) :
+ Inherited(S.Context), Decls(Decls), FoundDecl(false) {
+ if (!Statement) return;
- Visit(Statement);
- }
+ Visit(Statement);
+ }
- void VisitReturnStmt(ReturnStmt *S) {
- FoundDecl = true;
- }
+ void VisitReturnStmt(ReturnStmt *S) {
+ FoundDecl = true;
+ }
- void VisitBreakStmt(BreakStmt *S) {
- FoundDecl = true;
- }
+ void VisitBreakStmt(BreakStmt *S) {
+ FoundDecl = true;
+ }
- void VisitGotoStmt(GotoStmt *S) {
- FoundDecl = true;
- }
+ void VisitGotoStmt(GotoStmt *S) {
+ FoundDecl = true;
+ }
- void VisitCastExpr(CastExpr *E) {
- if (E->getCastKind() == CK_LValueToRValue)
- CheckLValueToRValueCast(E->getSubExpr());
- else
- Visit(E->getSubExpr());
- }
+ void VisitCastExpr(CastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ CheckLValueToRValueCast(E->getSubExpr());
+ else
+ Visit(E->getSubExpr());
+ }
- void CheckLValueToRValueCast(Expr *E) {
- E = E->IgnoreParenImpCasts();
+ void CheckLValueToRValueCast(Expr *E) {
+ E = E->IgnoreParenImpCasts();
- if (isa<DeclRefExpr>(E)) {
- return;
- }
+ if (isa<DeclRefExpr>(E)) {
+ return;
+ }
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- Visit(CO->getCond());
- CheckLValueToRValueCast(CO->getTrueExpr());
- CheckLValueToRValueCast(CO->getFalseExpr());
- return;
- }
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ Visit(CO->getCond());
+ CheckLValueToRValueCast(CO->getTrueExpr());
+ CheckLValueToRValueCast(CO->getFalseExpr());
+ return;
+ }
- if (BinaryConditionalOperator *BCO =
- dyn_cast<BinaryConditionalOperator>(E)) {
- CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr());
- CheckLValueToRValueCast(BCO->getFalseExpr());
- return;
- }
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr());
+ CheckLValueToRValueCast(BCO->getFalseExpr());
+ return;
+ }
- Visit(E);
- }
+ Visit(E);
+ }
- void VisitDeclRefExpr(DeclRefExpr *E) {
- if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
- if (Decls.count(VD))
- FoundDecl = true;
- }
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (Decls.count(VD))
+ FoundDecl = true;
+ }
- bool FoundDeclInUse() { return FoundDecl; }
+ bool FoundDeclInUse() { return FoundDecl; }
}; // end class DeclMatcher
@@ -1411,7 +1405,7 @@ public:
// Load SourceRanges into diagnostic if there is room.
// Otherwise, load the SourceRange of the conditional expression.
if (Ranges.size() <= PartialDiagnostic::MaxArguments)
- for (SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
+ for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I)
PDiag << *I;
@@ -1421,6 +1415,104 @@ public:
S.Diag(Ranges.begin()->getBegin(), PDiag);
}
+ // If Statement is an incemement or decrement, return true and sets the
+ // variables Increment and DRE.
+ bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment,
+ DeclRefExpr *&DRE) {
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) {
+ switch (UO->getOpcode()) {
+ default: return false;
+ case UO_PostInc:
+ case UO_PreInc:
+ Increment = true;
+ break;
+ case UO_PostDec:
+ case UO_PreDec:
+ Increment = false;
+ break;
+ }
+ DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr());
+ return DRE;
+ }
+
+ if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(Statement)) {
+ FunctionDecl *FD = Call->getDirectCallee();
+ if (!FD || !FD->isOverloadedOperator()) return false;
+ switch (FD->getOverloadedOperator()) {
+ default: return false;
+ case OO_PlusPlus:
+ Increment = true;
+ break;
+ case OO_MinusMinus:
+ Increment = false;
+ break;
+ }
+ DRE = dyn_cast<DeclRefExpr>(Call->getArg(0));
+ return DRE;
+ }
+
+ return false;
+ }
+
+ // A visitor to determine if a continue statement is a subexpression.
+ class ContinueFinder : public EvaluatedExprVisitor<ContinueFinder> {
+ bool Found;
+ public:
+ ContinueFinder(Sema &S, Stmt* Body) :
+ Inherited(S.Context),
+ Found(false) {
+ Visit(Body);
+ }
+
+ typedef EvaluatedExprVisitor<ContinueFinder> Inherited;
+
+ void VisitContinueStmt(ContinueStmt* E) {
+ Found = true;
+ }
+
+ bool ContinueFound() { return Found; }
+
+ }; // end class ContinueFinder
+
+ // Emit a warning when a loop increment/decrement appears twice per loop
+ // iteration. The conditions which trigger this warning are:
+ // 1) The last statement in the loop body and the third expression in the
+ // for loop are both increment or both decrement of the same variable
+ // 2) No continue statements in the loop body.
+ void CheckForRedundantIteration(Sema &S, Expr *Third, Stmt *Body) {
+ // Return when there is nothing to check.
+ if (!Body || !Third) return;
+
+ if (S.Diags.getDiagnosticLevel(diag::warn_redundant_loop_iteration,
+ Third->getLocStart())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ // Get the last statement from the loop body.
+ CompoundStmt *CS = dyn_cast<CompoundStmt>(Body);
+ if (!CS || CS->body_empty()) return;
+ Stmt *LastStmt = CS->body_back();
+ if (!LastStmt) return;
+
+ bool LoopIncrement, LastIncrement;
+ DeclRefExpr *LoopDRE, *LastDRE;
+
+ if (!ProcessIterationStmt(S, Third, LoopIncrement, LoopDRE)) return;
+ if (!ProcessIterationStmt(S, LastStmt, LastIncrement, LastDRE)) return;
+
+ // Check that the two statements are both increments or both decrements
+ // on the same varaible.
+ if (LoopIncrement != LastIncrement ||
+ LoopDRE->getDecl() != LastDRE->getDecl()) return;
+
+ if (ContinueFinder(S, Body).ContinueFound()) return;
+
+ S.Diag(LastDRE->getLocation(), diag::warn_redundant_loop_iteration)
+ << LastDRE->getDecl() << LastIncrement;
+ S.Diag(LoopDRE->getLocation(), diag::note_loop_iteration_here)
+ << LoopIncrement;
+ }
+
} // end namespace
StmtResult
@@ -1447,6 +1539,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
+ CheckForRedundantIteration(*this, third.get(), Body);
ExprResult SecondResult(second.release());
VarDecl *ConditionVar = 0;
@@ -1618,6 +1711,9 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
<< First->getSourceRange());
FirstType = static_cast<Expr*>(First)->getType();
+ if (FirstType.isConstQualified())
+ Diag(ForLoc, diag::err_selector_element_const_type)
+ << FirstType << First->getSourceRange();
}
if (!FirstType->isDependentType() &&
!FirstType->isObjCObjectPointerType() &&
@@ -1738,10 +1834,10 @@ StmtResult
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
Stmt *First, SourceLocation ColonLoc, Expr *Range,
SourceLocation RParenLoc, BuildForRangeKind Kind) {
- if (!First || !Range)
+ if (!First)
return StmtError();
- if (ObjCEnumerationCollection(Range))
+ if (Range && ObjCEnumerationCollection(Range))
return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc);
DeclStmt *DS = dyn_cast<DeclStmt>(First);
@@ -1751,11 +1847,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range);
return StmtError();
}
- if (DS->getSingleDecl()->isInvalidDecl())
- return StmtError();
- if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression))
+ Decl *LoopVar = DS->getSingleDecl();
+ if (LoopVar->isInvalidDecl() || !Range ||
+ DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) {
+ LoopVar->setInvalidDecl();
return StmtError();
+ }
// Build auto && __range = range-init
SourceLocation RangeLoc = Range->getLocStart();
@@ -1763,15 +1861,20 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
Context.getAutoRRefDeductType(),
"__range");
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
- diag::err_for_range_deduction_failure))
+ diag::err_for_range_deduction_failure)) {
+ LoopVar->setInvalidDecl();
return StmtError();
+ }
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy RangeGroup =
- BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false);
+ BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>((Decl **)&RangeVar, 1),
+ /*TypeMayContainAuto=*/ false);
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
- if (RangeDecl.isInvalid())
+ if (RangeDecl.isInvalid()) {
+ LoopVar->setInvalidDecl();
return StmtError();
+ }
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
/*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
@@ -1900,6 +2003,22 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
Sema::BFRK_Rebuild);
}
+namespace {
+/// RAII object to automatically invalidate a declaration if an error occurs.
+struct InvalidateOnErrorScope {
+ InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled)
+ : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {}
+ ~InvalidateOnErrorScope() {
+ if (Enabled && Trap.hasErrorOccurred())
+ D->setInvalidDecl();
+ }
+
+ DiagnosticErrorTrap Trap;
+ Decl *D;
+ bool Enabled;
+};
+}
+
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
@@ -1915,12 +2034,17 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
+ // If we hit any errors, mark the loop variable as invalid if its type
+ // contains 'auto'.
+ InvalidateOnErrorScope Invalidate(*this, LoopVar,
+ LoopVar->getType()->isUndeducedType());
+
StmtResult BeginEndDecl = BeginEnd;
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
if (RangeVarType->isDependentType()) {
// The range is implicitly used as a placeholder when it is dependent.
- RangeVar->setUsed();
+ RangeVar->markUsed(Context);
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
// them in properly when we instantiate the loop.
@@ -1981,8 +2105,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
RangeLoc));
else if (const VariableArrayType *VAT =
dyn_cast<VariableArrayType>(UnqAT))
- // FIXME: Need to build an OpaqueValueExpr for this rather than
- // recomputing it!
BoundExpr = VAT->getSizeExpr();
else {
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
@@ -2009,10 +2131,25 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
BeginVar, EndVar, ColonLoc, &CandidateSet,
&BeginExpr, &EndExpr, &BEFFailure);
- // If building the range failed, try dereferencing the range expression
- // unless a diagnostic was issued or the end function is problematic.
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
BEFFailure == BEF_begin) {
+ // If the range is being built from an array parameter, emit a
+ // a diagnostic that it is being treated as a pointer.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ QualType ArrayTy = PVD->getOriginalType();
+ QualType PointerTy = PVD->getType();
+ if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
+ Diag(Range->getLocStart(), diag::err_range_on_array_parameter)
+ << RangeLoc << PVD << ArrayTy << PointerTy;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ return StmtError();
+ }
+ }
+ }
+
+ // If building the range failed, try dereferencing the range expression
+ // unless a diagnostic was issued or the end function is problematic.
StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
LoopVarDecl, ColonLoc,
Range, RangeLoc,
@@ -2048,7 +2185,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Decl *BeginEndDecls[] = { BeginVar, EndVar };
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy BeginEndGroup =
- BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false);
+ BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>(BeginEndDecls, 2),
+ /*TypeMayContainAuto=*/ false);
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
@@ -2162,7 +2300,7 @@ StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
LabelDecl *TheDecl) {
getCurFunction()->setHasBranchIntoScope();
- TheDecl->setUsed();
+ TheDecl->markUsed(Context);
return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc));
}
@@ -2356,28 +2494,51 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
return Res;
}
+/// \brief Determine whether the declared return type of the specified function
+/// contains 'auto'.
+static bool hasDeducedReturnType(FunctionDecl *FD) {
+ const FunctionProtoType *FPT =
+ FD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
+ return FPT->getResultType()->isUndeducedType();
+}
+
/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
/// for capturing scopes.
///
StmtResult
Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If this is the first return we've seen, infer the return type.
- // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those
- // rules which allows multiple return statements.
+ // [expr.prim.lambda]p4 in C++11; block literals follow the same rules.
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
QualType FnRetType = CurCap->ReturnType;
+ LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap);
- // For blocks/lambdas with implicit return types, we check each return
- // statement individually, and deduce the common return type when the block
- // or lambda is completed.
- if (CurCap->HasImplicitReturnType) {
+ if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) {
+ // In C++1y, the return type may involve 'auto'.
+ // FIXME: Blocks might have a return type of 'auto' explicitly specified.
+ FunctionDecl *FD = CurLambda->CallOperator;
+ if (CurCap->ReturnType.isNull())
+ CurCap->ReturnType = FD->getResultType();
+
+ AutoType *AT = CurCap->ReturnType->getContainedAutoType();
+ assert(AT && "lost auto type from lambda return type");
+ if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
+ FD->setInvalidDecl();
+ return StmtError();
+ }
+ CurCap->ReturnType = FnRetType = FD->getResultType();
+ } else if (CurCap->HasImplicitReturnType) {
+ // For blocks/lambdas with implicit return types, we check each return
+ // statement individually, and deduce the common return type when the block
+ // or lambda is completed.
+ // FIXME: Fold this into the 'auto' codepath above.
if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- if (!RetValExp->isTypeDependent())
+ if (!CurContext->isDependentContext())
FnRetType = RetValExp->getType();
else
FnRetType = CurCap->ReturnType = Context.DependentTy;
@@ -2410,8 +2571,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
return StmtError();
} else {
- LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap);
- if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){
+ assert(CurLambda && "unknown kind of captured scope");
+ if (CurLambda->CallOperator->getType()->getAs<FunctionType>()
+ ->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
return StmtError();
}
@@ -2492,7 +2654,24 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
QualType Deduced;
- if (RetExpr) {
+ if (RetExpr && isa<InitListExpr>(RetExpr)) {
+ // If the deduction is for a return statement and the initializer is
+ // a braced-init-list, the program is ill-formed.
+ Diag(RetExpr->getExprLoc(),
+ getCurLambda() ? diag::err_lambda_return_init_list
+ : diag::err_auto_fn_return_init_list)
+ << RetExpr->getSourceRange();
+ return true;
+ }
+
+ if (FD->isDependentContext()) {
+ // C++1y [dcl.spec.auto]p12:
+ // Return type deduction [...] occurs when the definition is
+ // instantiated even if the function body contains a return
+ // statement with a non-type-dependent operand.
+ assert(AT->isDeduced() && "should have deduced to dependent type");
+ return false;
+ } else if (RetExpr) {
// If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed.
if (isa<InitListExpr>(RetExpr)) {
@@ -2533,10 +2712,18 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
// the program is ill-formed.
if (AT->isDeduced() && !FD->isInvalidDecl()) {
AutoType *NewAT = Deduced->getContainedAutoType();
- if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
- Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << AT->getDeducedType();
+ if (!FD->isDependentContext() &&
+ !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
+ const LambdaScopeInfo *LambdaSI = getCurLambda();
+ if (LambdaSI && LambdaSI->HasImplicitReturnType) {
+ Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
+ << NewAT->getDeducedType() << AT->getDeducedType()
+ << true /*IsLambda*/;
+ } else {
+ Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
+ << (AT->isDecltypeAuto() ? 1 : 0)
+ << NewAT->getDeducedType() << AT->getDeducedType();
+ }
return true;
}
} else if (!FD->isInvalidDecl()) {
@@ -2553,9 +2740,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
- // FIXME: Unify this and C++1y auto function handling. In particular, we
- // should allow 'return { 1, 2, 3 };' in a lambda to deduce
- // 'std::initializer_list<int>'.
if (isa<CapturingScopeInfo>(getCurFunction()))
return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
@@ -2580,13 +2764,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// FIXME: Add a flag to the ScopeInfo to indicate whether we're performing
// deduction.
- bool HasDependentReturnType = FnRetType->isDependentType();
if (getLangOpts().CPlusPlus1y) {
if (AutoType *AT = FnRetType->getContainedAutoType()) {
FunctionDecl *FD = cast<FunctionDecl>(CurContext);
- if (CurContext->isDependentContext())
- HasDependentReturnType = true;
- else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
+ if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl();
return StmtError();
} else {
@@ -2595,6 +2776,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
}
+ bool HasDependentReturnType = FnRetType->isDependentType();
+
ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
if (RetValExp) {
@@ -2699,11 +2882,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we have a related result type, we need to implicitly
// convert back to the formal result type. We can't pretend to
// initialize the result again --- we might end double-retaining
- // --- so instead we initialize a notional temporary; this can
- // lead to less-than-great diagnostics, but this stage is much
- // less likely to fail than the previous stage.
+ // --- so instead we initialize a notional temporary.
if (!RelatedRetType.isNull()) {
- Entity = InitializedEntity::InitializeTemporary(FnRetType);
+ Entity = InitializedEntity::InitializeRelatedResult(getCurMethodDecl(),
+ FnRetType);
Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp);
if (Res.isInvalid()) {
// FIXME: Clean up temporaries here anyway?
@@ -2886,18 +3068,16 @@ public:
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
/// handlers and creates a try statement from them.
-StmtResult
-Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
- MultiStmtArg RawHandlers) {
+StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
+ ArrayRef<Stmt *> Handlers) {
// Don't report an error if 'try' is used in system headers.
if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(TryLoc))
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
- unsigned NumHandlers = RawHandlers.size();
+ const unsigned NumHandlers = Handlers.size();
assert(NumHandlers > 0 &&
"The parser shouldn't call this if there are no handlers.");
- Stmt **Handlers = RawHandlers.data();
SmallVector<TypeWithHandler, 8> TypesWithHandlers;
@@ -2945,8 +3125,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
// Neither of these are explicitly forbidden, but every compiler detects them
// and warns.
- return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
- llvm::makeArrayRef(Handlers, NumHandlers)));
+ return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers));
}
StmtResult
@@ -3051,7 +3230,7 @@ static void buildCapturedStmtCaptureList(
if (Cap->isThisCapture()) {
Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
CapturedStmt::VCK_This));
- CaptureInits.push_back(Cap->getCopyExpr());
+ CaptureInits.push_back(Cap->getInitExpr());
continue;
}
@@ -3061,7 +3240,7 @@ static void buildCapturedStmtCaptureList(
Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
CapturedStmt::VCK_ByRef,
Cap->getVariable()));
- CaptureInits.push_back(Cap->getCopyExpr());
+ CaptureInits.push_back(Cap->getInitExpr());
}
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index fce95bebd1a9..9169032178fe 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -77,13 +77,12 @@ static bool isOperandMentioned(unsigned OpNo,
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
bool IsVolatile, unsigned NumOutputs,
unsigned NumInputs, IdentifierInfo **Names,
- MultiExprArg constraints, MultiExprArg exprs,
+ MultiExprArg constraints, MultiExprArg Exprs,
Expr *asmString, MultiExprArg clobbers,
SourceLocation RParenLoc) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
reinterpret_cast<StringLiteral**>(constraints.data());
- Expr **Exprs = exprs.data();
StringLiteral *AsmString = cast<StringLiteral>(asmString);
StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data());
@@ -204,8 +203,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
GCCAsmStmt *NS =
new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
- NumInputs, Names, Constraints, Exprs, AsmString,
- NumClobbers, Clobbers, RParenLoc);
+ NumInputs, Names, Constraints, Exprs.data(),
+ AsmString, NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
@@ -382,7 +381,9 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
/*trailing lparen*/ false,
- /*is & operand*/ false);
+ /*is & operand*/ false,
+ /*CorrectionCandidateCallback=*/0,
+ /*IsInlineAsmIdentifier=*/ true);
if (IsUnevaluatedContext)
PopExpressionEvaluationContext();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index b9695cc1e166..28603daa267c 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -11,6 +11,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -207,8 +208,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
R.suppressDiagnostics();
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
- isa<TypeAliasTemplateDecl>(TD));
- TemplateKind = TNK_Type_template;
+ isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD));
+ TemplateKind =
+ isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
}
}
@@ -256,7 +258,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
- assert((isDependent || !ObjectType->isIncompleteType()) &&
+ assert((isDependent || !ObjectType->isIncompleteType() ||
+ ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
// Template names cannot appear inside an Objective-C class or object type.
@@ -328,20 +331,16 @@ void Sema::LookupTemplateName(LookupResult &Found,
Found.addDecl(Corrected.getCorrectionDecl());
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
- std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
- if (LookupCtx)
- Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
- << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
- CorrectedStr);
- else
- Diag(Found.getNameLoc(), diag::err_no_template_suggest)
- << Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
- if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
- Diag(Template->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
+ if (LookupCtx) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
+ Name.getAsString() == CorrectedStr;
+ diagnoseTypo(Corrected, PDiag(diag::err_no_member_template_suggest)
+ << Name << LookupCtx << DroppedSpecifier
+ << SS.getRange());
+ } else {
+ diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name);
+ }
}
} else {
Found.setLookupName(Name);
@@ -356,7 +355,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope &&
- !(getLangOpts().CPlusPlus11 && !Found.empty())) {
+ !getLangOpts().CPlusPlus11) {
// C++03 [basic.lookup.classref]p1:
// [...] If the lookup in the class of the object expression finds a
// template, the name is also looked up in the context of the entire
@@ -533,6 +532,15 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
TemplateArgsIn[I]));
}
+static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
+ SourceLocation Loc,
+ IdentifierInfo *Name) {
+ NamedDecl *PrevDecl = SemaRef.LookupSingleName(
+ S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ if (PrevDecl && PrevDecl->isTemplateParameter())
+ SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl);
+}
+
/// ActOnTypeParameter - Called when a C++ template type parameter
/// (e.g., "typename T") has been parsed. Typename specifies whether
/// the keyword "typename" was used to declare the type parameter
@@ -554,16 +562,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
"Template type parameter not in template parameter scope!");
bool Invalid = false;
- if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc,
- LookupOrdinaryName,
- ForRedeclaration);
- if (PrevDecl && PrevDecl->isTemplateParameter()) {
- DiagnoseTemplateParameterShadow(ParamNameLoc, PrevDecl);
- PrevDecl = 0;
- }
- }
-
SourceLocation Loc = ParamNameLoc;
if (!ParamName)
Loc = KeyLoc;
@@ -577,6 +575,8 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
Param->setInvalidDecl();
if (ParamName) {
+ maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
+
// Add the template parameter into the current scope.
S->AddDecl(Param);
IdResolver.AddDecl(Param);
@@ -682,23 +682,13 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
"Non-type template parameter not in template parameter scope!");
bool Invalid = false;
- IdentifierInfo *ParamName = D.getIdentifier();
- if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(),
- LookupOrdinaryName,
- ForRedeclaration);
- if (PrevDecl && PrevDecl->isTemplateParameter()) {
- DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
- PrevDecl = 0;
- }
- }
-
T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
if (T.isNull()) {
T = Context.IntTy; // Recover with an 'int' type.
Invalid = true;
}
+ IdentifierInfo *ParamName = D.getIdentifier();
bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
@@ -707,11 +697,14 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Depth, Position, ParamName, T,
IsParameterPack, TInfo);
Param->setAccess(AS_public);
-
+
if (Invalid)
Param->setInvalidDecl();
- if (D.getIdentifier()) {
+ if (ParamName) {
+ maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
+ ParamName);
+
// Add the template parameter into the current scope.
S->AddDecl(Param);
IdResolver.AddDecl(Param);
@@ -773,6 +766,8 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
+ maybeDiagnoseTemplateParameterShadow(*this, S, NameLoc, Name);
+
S->AddDecl(Param);
IdResolver.AddDecl(Param);
}
@@ -882,10 +877,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// FIXME: Horrible, horrible hack! We can't currently represent this
// in the AST, and historically we have just ignored such friend
// class templates, so don't complain here.
- if (TUK != TUK_Friend)
- Diag(NameLoc, diag::err_template_qualified_declarator_no_match)
+ Diag(NameLoc, TUK == TUK_Friend
+ ? diag::warn_template_qualified_friend_ignored
+ : diag::err_template_qualified_declarator_no_match)
<< SS.getScopeRep() << SS.getRange();
- return true;
+ return TUK != TUK_Friend;
}
if (RequireCompleteDeclContext(SS, SemanticContext))
@@ -1032,13 +1028,14 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// template declaration. Skip this check for a friend in a dependent
// context, because the template parameter list might be dependent.
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
- CheckTemplateParameterList(TemplateParams,
- PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
- (SS.isSet() && SemanticContext &&
- SemanticContext->isRecord() &&
- SemanticContext->isDependentContext())
- ? TPC_ClassTemplateMember
- : TPC_ClassTemplate))
+ CheckTemplateParameterList(
+ TemplateParams,
+ PrevClassTemplate ? PrevClassTemplate->getTemplateParameters() : 0,
+ (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
+ SemanticContext->isDependentContext())
+ ? TPC_ClassTemplateMember
+ : TUK == TUK_Friend ? TPC_FriendClassTemplate
+ : TPC_ClassTemplate))
Invalid = true;
if (SS.isSet()) {
@@ -1046,8 +1043,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// template out-of-line.
if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) {
Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match
- : diag::err_member_def_does_not_match)
- << Name << SemanticContext << SS.getRange();
+ : diag::err_member_decl_does_not_match)
+ << Name << SemanticContext << /*IsDefinition*/true << SS.getRange();
Invalid = true;
}
}
@@ -1118,8 +1115,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NewClass->setAccess(PrevClassTemplate->getAccess());
}
- NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
- PrevClassTemplate != NULL);
+ NewTemplate->setObjectOfFriendDecl();
// Friend templates are visible in fairly strange ways.
if (!CurContext->isDependentContext()) {
@@ -1158,6 +1154,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
SourceRange DefArgRange) {
switch (TPC) {
case Sema::TPC_ClassTemplate:
+ case Sema::TPC_VarTemplate:
case Sema::TPC_TypeAliasTemplate:
return false;
@@ -1186,6 +1183,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
<< DefArgRange;
return true;
+ case Sema::TPC_FriendClassTemplate:
case Sema::TPC_FriendFunctionTemplate:
// C++ [temp.param]p9:
// A default template-argument shall not be specified in a
@@ -1317,7 +1315,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- SawDefaultArgument = true;
NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgumentInfo(),
true);
PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc();
@@ -1354,7 +1351,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (!NewNonTypeParm->isPackExpansion())
SawParameterPack = true;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
- NewNonTypeParm->hasDefaultArgument()) {
+ NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
@@ -1363,7 +1360,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- SawDefaultArgument = true;
// FIXME: We need to create a new kind of "default argument"
// expression that points to a previous non-type template
// parameter.
@@ -1411,7 +1407,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- SawDefaultArgument = true;
// FIXME: We need to create a new kind of "default argument" expression
// that points to a previous template template parameter.
NewTemplateParm->setDefaultArgument(
@@ -1431,7 +1426,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template parameter of a primary class template or alias template
// is a template parameter pack, it shall be the last template parameter.
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
- (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
+ (TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate ||
+ TPC == TPC_TypeAliasTemplate)) {
Diag((*NewParam)->getLocation(),
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
@@ -1584,8 +1580,6 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// \param ParamLists the template parameter lists, from the outermost to the
/// innermost template parameter lists.
///
-/// \param NumParamLists the number of template parameter lists in ParamLists.
-///
/// \param IsFriend Whether to apply the slightly different rules for
/// matching template parameters to scope specifiers in friend
/// declarations.
@@ -1599,15 +1593,10 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// template) or may have no template parameters (if we're declaring a
/// template specialization), or may be NULL (if what we're declaring isn't
/// itself a template).
-TemplateParameterList *
-Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
- SourceLocation DeclLoc,
- const CXXScopeSpec &SS,
- TemplateParameterList **ParamLists,
- unsigned NumParamLists,
- bool IsFriend,
- bool &IsExplicitSpecialization,
- bool &Invalid) {
+TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
+ SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
+ ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
+ bool &IsExplicitSpecialization, bool &Invalid) {
IsExplicitSpecialization = false;
Invalid = false;
@@ -1780,7 +1769,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
- if (ParamIdx < NumParamLists) {
+ if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() == 0) {
if (SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
@@ -1798,8 +1787,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// here, then it's an explicit specialization.
if (TypeIdx == NumTypes - 1)
IsExplicitSpecialization = true;
-
- if (ParamIdx < NumParamLists) {
+
+ if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() > 0) {
// The header has template parameters when it shouldn't. Complain.
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
@@ -1820,7 +1809,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
if (!IsFriend) {
// We don't have a template header, but we should.
SourceLocation ExpectedTemplateLoc;
- if (NumParamLists > 0)
+ if (!ParamLists.empty())
ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
ExpectedTemplateLoc = DeclStartLoc;
@@ -1839,15 +1828,15 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// assume that empty parameter lists are supposed to match this
// template-id.
if (IsFriend && T->isDependentType()) {
- if (ParamIdx < NumParamLists &&
+ if (ParamIdx < ParamLists.size() &&
DependsOnTemplateParameters(T, ParamLists[ParamIdx]))
ExpectedTemplateParams = 0;
else
continue;
}
- if (ParamIdx < NumParamLists) {
- // Check the template parameter list, if we can.
+ if (ParamIdx < ParamLists.size()) {
+ // Check the template parameter list, if we can.
if (ExpectedTemplateParams &&
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
@@ -1874,25 +1863,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (ParamIdx >= NumParamLists)
+ if (ParamIdx >= ParamLists.size())
return 0;
// If there were too many template parameter lists, complain about that now.
- if (ParamIdx < NumParamLists - 1) {
+ if (ParamIdx < ParamLists.size() - 1) {
bool HasAnyExplicitSpecHeader = false;
bool AllExplicitSpecHeaders = true;
- for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) {
+ for (unsigned I = ParamIdx, E = ParamLists.size() - 1; I != E; ++I) {
if (ParamLists[I]->size() == 0)
HasAnyExplicitSpecHeader = true;
else
AllExplicitSpecHeaders = false;
}
-
+
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[NumParamLists - 2]->getRAngleLoc());
+ AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[ParamLists.size() - 2]->getRAngleLoc());
// If there was a specialization somewhere, such that 'template<>' is
// not required, and there were any 'template<>' headers, note where the
@@ -1916,8 +1905,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
- if (ParamLists[NumParamLists - 1]->size() == 0 &&
- SawNonEmptyTemplateParameterList) {
+ if (ParamLists.back()->size() == 0 && SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< ParamLists[ParamIdx]->getSourceRange();
Invalid = true;
@@ -1927,17 +1915,20 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// Return the last template parameter list, which corresponds to the
// entity being declared.
- return ParamLists[NumParamLists - 1];
+ return ParamLists.back();
}
void Sema::NoteAllFoundTemplates(TemplateName Name) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
Diag(Template->getLocation(), diag::note_template_declared_here)
- << (isa<FunctionTemplateDecl>(Template)? 0
- : isa<ClassTemplateDecl>(Template)? 1
- : isa<TypeAliasTemplateDecl>(Template)? 2
- : 3)
- << Template->getDeclName();
+ << (isa<FunctionTemplateDecl>(Template)
+ ? 0
+ : isa<ClassTemplateDecl>(Template)
+ ? 1
+ : isa<VarTemplateDecl>(Template)
+ ? 2
+ : isa<TypeAliasTemplateDecl>(Template) ? 3 : 4)
+ << Template->getDeclName();
return;
}
@@ -2007,11 +1998,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
for (unsigned I = 0; I < Depth; ++I)
- TemplateArgLists.addOuterTemplateArguments(0, 0);
+ TemplateArgLists.addOuterTemplateArguments(None);
LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
- if (Inst)
+ if (Inst.isInvalid())
return QualType();
CanonType = SubstType(Pattern->getUnderlyingType(),
@@ -2102,6 +2093,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
}
+ // Diagnose uses of this specialization.
+ (void)DiagnoseUseOfDecl(Decl, TemplateLoc);
+
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
@@ -2123,7 +2117,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
if (SS.isInvalid())
return true;
- TemplateName Template = TemplateD.getAsVal<TemplateName>();
+ TemplateName Template = TemplateD.get();
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
@@ -2190,7 +2184,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
- TemplateName Template = TemplateD.getAsVal<TemplateName>();
+ TemplateName Template = TemplateD.get();
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
@@ -2272,6 +2266,499 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
+static bool CheckTemplatePartialSpecializationArgs(
+ Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<TemplateArgument> &TemplateArgs);
+
+static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
+ NamedDecl *PrevDecl,
+ SourceLocation Loc,
+ bool IsPartialSpecialization);
+
+static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
+
+static bool isTemplateArgumentTemplateParameter(
+ const TemplateArgument &Arg, unsigned Depth, unsigned Index) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Pack:
+ case TemplateArgument::TemplateExpansion:
+ return false;
+
+ case TemplateArgument::Type: {
+ QualType Type = Arg.getAsType();
+ const TemplateTypeParmType *TPT =
+ Arg.getAsType()->getAs<TemplateTypeParmType>();
+ return TPT && !Type.hasQualifiers() &&
+ TPT->getDepth() == Depth && TPT->getIndex() == Index;
+ }
+
+ case TemplateArgument::Expression: {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg.getAsExpr());
+ if (!DRE || !DRE->getDecl())
+ return false;
+ const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
+ return NTTP && NTTP->getDepth() == Depth && NTTP->getIndex() == Index;
+ }
+
+ case TemplateArgument::Template:
+ const TemplateTemplateParmDecl *TTP =
+ dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl());
+ return TTP && TTP->getDepth() == Depth && TTP->getIndex() == Index;
+ }
+ llvm_unreachable("unexpected kind of template argument");
+}
+
+static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
+ ArrayRef<TemplateArgument> Args) {
+ if (Params->size() != Args.size())
+ return false;
+
+ unsigned Depth = Params->getDepth();
+
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ TemplateArgument Arg = Args[I];
+
+ // If the parameter is a pack expansion, the argument must be a pack
+ // whose only element is a pack expansion.
+ if (Params->getParam(I)->isParameterPack()) {
+ if (Arg.getKind() != TemplateArgument::Pack || Arg.pack_size() != 1 ||
+ !Arg.pack_begin()->isPackExpansion())
+ return false;
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+
+ if (!isTemplateArgumentTemplateParameter(Arg, Depth, I))
+ return false;
+ }
+
+ return true;
+}
+
+DeclResult Sema::ActOnVarTemplateSpecialization(
+ Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
+ SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
+ VarDecl::StorageClass SC, bool IsPartialSpecialization) {
+ assert(VarTemplate && "A variable template id without template?");
+
+ // D must be variable template id.
+ assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId &&
+ "Variable template specialization is declared with a template it.");
+
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ SourceLocation TemplateNameLoc = D.getIdentifierLoc();
+ SourceLocation LAngleLoc = TemplateId->LAngleLoc;
+ SourceLocation RAngleLoc = TemplateId->RAngleLoc;
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateName Name(VarTemplate);
+
+ // Check for unexpanded parameter packs in any of the template arguments.
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ if (DiagnoseUnexpandedParameterPack(TemplateArgs[I],
+ UPPC_PartialSpecialization))
+ return true;
+
+ // Check that the template argument list is well-formed for this
+ // template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
+ false, Converted))
+ return true;
+
+ // Check that the type of this variable template specialization
+ // matches the expected type.
+ TypeSourceInfo *ExpectedDI;
+ {
+ // Do substitution on the type of the declaration
+ TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+ InstantiatingTemplate Inst(*this, TemplateKWLoc, VarTemplate);
+ if (Inst.isInvalid())
+ return true;
+ VarDecl *Templated = VarTemplate->getTemplatedDecl();
+ ExpectedDI =
+ SubstType(Templated->getTypeSourceInfo(),
+ MultiLevelTemplateArgumentList(TemplateArgList),
+ Templated->getTypeSpecStartLoc(), Templated->getDeclName());
+ }
+ if (!ExpectedDI)
+ return true;
+
+ // Find the variable template (partial) specialization declaration that
+ // corresponds to these arguments.
+ if (IsPartialSpecialization) {
+ if (CheckTemplatePartialSpecializationArgs(
+ *this, VarTemplate->getTemplateParameters(), Converted))
+ return true;
+
+ bool InstantiationDependent;
+ if (!Name.isDependent() &&
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ InstantiationDependent)) {
+ Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
+ << VarTemplate->getDeclName();
+ IsPartialSpecialization = false;
+ }
+
+ if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
+ Converted)) {
+ // C++ [temp.class.spec]p9b3:
+ //
+ // -- The argument list of the specialization shall not be identical
+ // to the implicit argument list of the primary template.
+ Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
+ << /*variable template*/ 1
+ << /*is definition*/(SC != SC_Extern && !CurContext->isRecord())
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
+ // FIXME: Recover from this by treating the declaration as a redeclaration
+ // of the primary template.
+ return true;
+ }
+ }
+
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *PrevDecl = 0;
+
+ if (IsPartialSpecialization)
+ // FIXME: Template parameter list matters too
+ PrevDecl = VarTemplate->findPartialSpecialization(
+ Converted.data(), Converted.size(), InsertPos);
+ else
+ PrevDecl = VarTemplate->findSpecialization(Converted.data(),
+ Converted.size(), InsertPos);
+
+ VarTemplateSpecializationDecl *Specialization = 0;
+
+ // Check whether we can declare a variable template specialization in
+ // the current scope.
+ if (CheckTemplateSpecializationScope(*this, VarTemplate, PrevDecl,
+ TemplateNameLoc,
+ IsPartialSpecialization))
+ return true;
+
+ if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+ // Since the only prior variable template specialization with these
+ // arguments was referenced but not declared, reuse that
+ // declaration node as our own, updating its source location and
+ // the list of outer template parameters to reflect our new declaration.
+ Specialization = PrevDecl;
+ Specialization->setLocation(TemplateNameLoc);
+ PrevDecl = 0;
+ } else if (IsPartialSpecialization) {
+ // Create a new class template partial specialization declaration node.
+ VarTemplatePartialSpecializationDecl *PrevPartial =
+ cast_or_null<VarTemplatePartialSpecializationDecl>(PrevDecl);
+ VarTemplatePartialSpecializationDecl *Partial =
+ VarTemplatePartialSpecializationDecl::Create(
+ Context, VarTemplate->getDeclContext(), TemplateKWLoc,
+ TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
+ Converted.data(), Converted.size(), TemplateArgs);
+
+ if (!PrevPartial)
+ VarTemplate->AddPartialSpecialization(Partial, InsertPos);
+ Specialization = Partial;
+
+ // If we are providing an explicit specialization of a member variable
+ // template specialization, make a note of that.
+ if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+ PrevPartial->setMemberSpecialization();
+
+ // Check that all of the template parameters of the variable template
+ // partial specialization are deducible from the template
+ // arguments. If not, this variable template partial specialization
+ // will never be used.
+ llvm::SmallBitVector DeducibleParams(TemplateParams->size());
+ MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ TemplateParams->getDepth(), DeducibleParams);
+
+ if (!DeducibleParams.all()) {
+ unsigned NumNonDeducible =
+ DeducibleParams.size() - DeducibleParams.count();
+ Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
+ << /*variable template*/ 1 << (NumNonDeducible > 1)
+ << SourceRange(TemplateNameLoc, RAngleLoc);
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+ if (!DeducibleParams[I]) {
+ NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+ if (Param->getDeclName())
+ Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
+ << Param->getDeclName();
+ else
+ Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
+ << "<anonymous>";
+ }
+ }
+ }
+ } else {
+ // Create a new class template specialization declaration node for
+ // this explicit specialization or friend declaration.
+ Specialization = VarTemplateSpecializationDecl::Create(
+ Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
+ VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size());
+ Specialization->setTemplateArgsInfo(TemplateArgs);
+
+ if (!PrevDecl)
+ VarTemplate->AddSpecialization(Specialization, InsertPos);
+ }
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that specialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
+ bool Okay = false;
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+ Okay = true;
+ break;
+ }
+ }
+
+ if (!Okay) {
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+ << Name << Range;
+
+ Diag(PrevDecl->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (PrevDecl->getTemplateSpecializationKind() !=
+ TSK_ImplicitInstantiation);
+ return true;
+ }
+ }
+
+ Specialization->setTemplateKeywordLoc(TemplateKWLoc);
+ Specialization->setLexicalDeclContext(CurContext);
+
+ // Add the specialization into its lexical context, so that it can
+ // be seen when iterating through the list of declarations in that
+ // context. However, specializations are not found by name lookup.
+ CurContext->addDecl(Specialization);
+
+ // Note that this is an explicit specialization.
+ Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
+
+ if (PrevDecl) {
+ // Check that this isn't a redefinition of this specialization,
+ // merging with previous declarations.
+ LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
+ ForRedeclaration);
+ PrevSpec.addDecl(PrevDecl);
+ D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
+ } else if (Specialization->isStaticDataMember() &&
+ Specialization->isOutOfLine()) {
+ Specialization->setAccess(VarTemplate->getAccess());
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Specialization->isStaticDataMember())
+ Specialization->setInstantiationOfStaticDataMember(
+ VarTemplate->getTemplatedDecl(),
+ Specialization->getSpecializationKind());
+
+ return Specialization;
+}
+
+namespace {
+/// \brief A partial specialization whose template arguments have matched
+/// a given template-id.
+struct PartialSpecMatchResult {
+ VarTemplatePartialSpecializationDecl *Partial;
+ TemplateArgumentList *Args;
+};
+}
+
+DeclResult
+Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation TemplateNameLoc,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ assert(Template && "A variable template id without template?");
+
+ // Check that the template argument list is well-formed for this template.
+ SmallVector<TemplateArgument, 4> Converted;
+ bool ExpansionIntoFixedList = false;
+ if (CheckTemplateArgumentList(
+ Template, TemplateNameLoc,
+ const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
+ Converted, &ExpansionIntoFixedList))
+ return true;
+
+ // Find the variable template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = 0;
+ if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
+ Converted.data(), Converted.size(), InsertPos))
+ // If we already have a variable template specialization, return it.
+ return Spec;
+
+ // This is the first time we have referenced this variable template
+ // specialization. Create the canonical declaration and add it to
+ // the set of specializations, based on the closest partial specialization
+ // that it represents. That is,
+ VarDecl *InstantiationPattern = Template->getTemplatedDecl();
+ TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+ TemplateArgumentList *InstantiationArgs = &TemplateArgList;
+ bool AmbiguousPartialSpec = false;
+ typedef PartialSpecMatchResult MatchResult;
+ SmallVector<MatchResult, 4> Matched;
+ SourceLocation PointOfInstantiation = TemplateNameLoc;
+ TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
+
+ // 1. Attempt to find the closest partial specialization that this
+ // specializes, if any.
+ // If any of the template arguments is dependent, then this is probably
+ // a placeholder for an incomplete declarative context; which must be
+ // complete by instantiation time. Thus, do not search through the partial
+ // specializations yet.
+ // TODO: Unify with InstantiateClassTemplateSpecialization()?
+ // Perhaps better after unification of DeduceTemplateArguments() and
+ // getMoreSpecializedPartialSpecialization().
+ bool InstantiationDependent = false;
+ if (!TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, InstantiationDependent)) {
+
+ SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ Template->getPartialSpecializations(PartialSpecs);
+
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
+
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
+ // Store the failed-deduction information for use in diagnostics, later.
+ // TODO: Actually use the failed-deduction info?
+ FailedCandidates.addCandidate()
+ .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
+ (void)Result;
+ } else {
+ Matched.push_back(PartialSpecMatchResult());
+ Matched.back().Partial = Partial;
+ Matched.back().Args = Info.take();
+ }
+ }
+
+ // If we're dealing with a member template where the template parameters
+ // have been instantiated, this provides the original template parameters
+ // from which the member template's parameters were instantiated.
+ SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
+
+ if (Matched.size() >= 1) {
+ SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ if (Matched.size() == 1) {
+ // -- If exactly one matching specialization is found, the
+ // instantiation is generated from that specialization.
+ // We don't need to do anything for this.
+ } else {
+ // -- If more than one matching specialization is found, the
+ // partial order rules (14.5.4.2) are used to determine
+ // whether one of the specializations is more specialized
+ // than the others. If none of the specializations is more
+ // specialized than all of the other matching
+ // specializations, then the use of the variable template is
+ // ambiguous and the program is ill-formed.
+ for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
+ PointOfInstantiation) ==
+ P->Partial)
+ Best = P;
+ }
+
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (P != Best && getMoreSpecializedPartialSpecialization(
+ P->Partial, Best->Partial,
+ PointOfInstantiation) != Best->Partial) {
+ AmbiguousPartialSpec = true;
+ break;
+ }
+ }
+ }
+
+ // Instantiate using the best variable template partial specialization.
+ InstantiationPattern = Best->Partial;
+ InstantiationArgs = Best->Args;
+ } else {
+ // -- If no match is found, the instantiation is generated
+ // from the primary template.
+ // InstantiationPattern = Template->getTemplatedDecl();
+ }
+ }
+
+ // 2. Create the canonical declaration.
+ // Note that we do not instantiate the variable just yet, since
+ // instantiation is handled in DoMarkVarDeclReferenced().
+ // FIXME: LateAttrs et al.?
+ VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
+ Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
+ Converted, TemplateNameLoc, InsertPos /*, LateAttrs, StartingScope*/);
+ if (!Decl)
+ return true;
+
+ if (AmbiguousPartialSpec) {
+ // Partial ordering did not produce a clear winner. Complain.
+ Decl->setInvalidDecl();
+ Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+ << Decl;
+
+ // Print the matching partial specializations.
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(
+ P->Partial->getTemplateParameters(), *P->Args);
+ return true;
+ }
+
+ if (VarTemplatePartialSpecializationDecl *D =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
+ Decl->setInstantiationOf(D, InstantiationArgs);
+
+ assert(Decl && "No variable template specialization?");
+ return Decl;
+}
+
+ExprResult
+Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ VarTemplateDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+
+ DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
+ *TemplateArgs);
+ if (Decl.isInvalid())
+ return ExprError();
+
+ VarDecl *Var = cast<VarDecl>(Decl.get());
+ if (!Var->getTemplateSpecializationKind())
+ Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
+ NameInfo.getLoc());
+
+ // Build an ordinary singleton decl ref.
+ return BuildDeclarationNameExpr(SS, NameInfo, Var,
+ /*FoundD=*/0, TemplateArgs);
+}
+
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -2291,6 +2778,13 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
assert(!R.empty() && "empty lookup results when building templateid");
assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
+ // In C++1y, check variable template ids.
+ if (R.getAsSingle<VarTemplateDecl>()) {
+ return Owned(CheckVarTemplateId(SS, R.getLookupNameInfo(),
+ R.getAsSingle<VarTemplateDecl>(),
+ TemplateKWLoc, TemplateArgs));
+ }
+
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
@@ -2311,6 +2805,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
+
assert(TemplateArgs || TemplateKWLoc.isValid());
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
@@ -2564,22 +3059,25 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isDependentType()) {
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
-
- MultiLevelTemplateArgumentList AllTemplateArgs
- = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
-
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
- if (Inst)
+ if (Inst.isInvalid())
return 0;
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+
+ // Only substitute for the innermost template argument list.
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
+ TemplateArgLists.addOuterTemplateArguments(None);
+
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
- ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
- Param->getDefaultArgumentLoc(),
- Param->getDeclName());
+ ArgType =
+ SemaRef.SubstType(ArgType, TemplateArgLists,
+ Param->getDefaultArgumentLoc(), Param->getDeclName());
}
return ArgType;
@@ -2614,21 +3112,24 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
SourceLocation RAngleLoc,
NonTypeTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted) {
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
-
- MultiLevelTemplateArgumentList AllTemplateArgs
- = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
-
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
- if (Inst)
+ if (Inst.isInvalid())
return ExprError();
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+
+ // Only substitute for the innermost template argument list.
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
+ TemplateArgLists.addOuterTemplateArguments(None);
+
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
- return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs);
+ return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
}
/// \brief Substitute template arguments into the default template argument for
@@ -2664,32 +3165,35 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted,
NestedNameSpecifierLoc &QualifierLoc) {
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted,
+ SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst.isInvalid())
+ return TemplateName();
+
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
- MultiLevelTemplateArgumentList AllTemplateArgs
- = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
-
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
- if (Inst)
- return TemplateName();
+ // Only substitute for the innermost template argument list.
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
+ TemplateArgLists.addOuterTemplateArguments(None);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
- // Substitute into the nested-name-specifier first,
+ // Substitute into the nested-name-specifier first,
QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc();
if (QualifierLoc) {
- QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
- AllTemplateArgs);
+ QualifierLoc =
+ SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgLists);
if (!QualifierLoc)
return TemplateName();
}
-
- return SemaRef.SubstTemplateName(QualifierLoc,
- Param->getDefaultArgument().getArgument().getAsTemplate(),
- Param->getDefaultArgument().getTemplateNameLoc(),
- AllTemplateArgs);
+
+ return SemaRef.SubstTemplateName(
+ QualifierLoc,
+ Param->getDefaultArgument().getArgument().getAsTemplate(),
+ Param->getDefaultArgument().getTemplateNameLoc(),
+ TemplateArgLists);
}
/// \brief If the given template parameter has a default template
@@ -2700,11 +3204,16 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
- if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ SmallVectorImpl<TemplateArgument>
+ &Converted,
+ bool &HasDefaultArg) {
+ HasDefaultArg = false;
+
+ if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (!TypeParm->hasDefaultArgument())
return TemplateArgumentLoc();
+ HasDefaultArg = true;
TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
@@ -2721,6 +3230,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (!NonTypeParm->hasDefaultArgument())
return TemplateArgumentLoc();
+ HasDefaultArg = true;
ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
@@ -2738,7 +3248,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (!TempTempParm->hasDefaultArgument())
return TemplateArgumentLoc();
-
+ HasDefaultArg = true;
NestedNameSpecifierLoc QualifierLoc;
TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
@@ -2808,7 +3318,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
InstantiatingTemplate Inst(*this, TemplateLoc, Template,
NTTP, Converted,
SourceRange(TemplateLoc, RAngleLoc));
- if (Inst)
+ if (Inst.isInvalid())
return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
@@ -2943,7 +3453,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
InstantiatingTemplate Inst(*this, TemplateLoc, Template,
TempParm, Converted,
SourceRange(TemplateLoc, RAngleLoc));
- if (Inst)
+ if (Inst.isInvalid())
return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
@@ -3110,8 +3620,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// deduced argument and place it on the argument pack. Note that we
// stay on the same template parameter so that we can deduce more
// arguments.
- ArgumentPack.push_back(Converted.back());
- Converted.pop_back();
+ ArgumentPack.push_back(Converted.pop_back_val());
} else {
// Move to the next template parameter.
++Param;
@@ -3255,10 +3764,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Introduce an instantiation record that describes where we are using
// the default template argument.
- InstantiatingTemplate Instantiating(*this, RAngleLoc, Template,
- *Param, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
- if (Instantiating)
+ InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted,
+ SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst.isInvalid())
return true;
// Check the default template argument.
@@ -3655,6 +4163,63 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
return NPV_NotNullPointer;
}
+/// \brief Checks whether the given template argument is compatible with its
+/// template parameter.
+static bool CheckTemplateArgumentIsCompatibleWithParameter(
+ Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
+ Expr *Arg, QualType ArgType) {
+ bool ObjCLifetimeConversion;
+ if (ParamType->isPointerType() &&
+ !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ S.IsQualificationConversion(ArgType, ParamType, false,
+ ObjCLifetimeConversion)) {
+ // For pointer-to-object types, qualification conversions are
+ // permitted.
+ } else {
+ if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) {
+ if (!ParamRef->getPointeeType()->isFunctionType()) {
+ // C++ [temp.arg.nontype]p5b3:
+ // For a non-type template-parameter of type reference to
+ // object, no conversions apply. The type referred to by the
+ // reference may be more cv-qualified than the (otherwise
+ // identical) type of the template- argument. The
+ // template-parameter is bound directly to the
+ // template-argument, which shall be an lvalue.
+
+ // FIXME: Other qualifiers?
+ unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers();
+ unsigned ArgQuals = ArgType.getCVRQualifiers();
+
+ if ((ParamQuals | ArgQuals) != ParamQuals) {
+ S.Diag(Arg->getLocStart(),
+ diag::err_template_arg_ref_bind_ignores_quals)
+ << ParamType << Arg->getType() << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+ }
+
+ // At this point, the template argument refers to an object or
+ // function with external linkage. We now need to check whether the
+ // argument and parameter types are compatible.
+ if (!S.Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
+ // We can't perform this conversion or binding.
+ if (ParamType->isReferenceType())
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
+ << ParamType << ArgIn->getType() << Arg->getSourceRange();
+ else
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
+ << ArgIn->getType() << ParamType << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
static bool
@@ -3682,68 +4247,110 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
break;
}
}
-
- // See through any implicit casts we added to fix the type.
- Arg = Arg->IgnoreImpCasts();
- // C++ [temp.arg.nontype]p1:
- //
- // A template-argument for a non-type, non-template
- // template-parameter shall be one of: [...]
- //
- // -- the address of an object or function with external
- // linkage, including function templates and function
- // template-ids but excluding non-static class members,
- // expressed as & id-expression where the & is optional if
- // the name refers to a function or array, or if the
- // corresponding template-parameter is a reference; or
-
- // In C++98/03 mode, give an extension warning on any extra parentheses.
- // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
- bool ExtraParens = false;
- while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
- if (!Invalid && !ExtraParens) {
- S.Diag(Arg->getLocStart(),
- S.getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_template_arg_extra_parens :
- diag::ext_template_arg_extra_parens)
- << Arg->getSourceRange();
- ExtraParens = true;
+ bool AddressTaken = false;
+ SourceLocation AddrOpLoc;
+ if (S.getLangOpts().MicrosoftExt) {
+ // Microsoft Visual C++ strips all casts, allows an arbitrary number of
+ // dereference and address-of operators.
+ Arg = Arg->IgnoreParenCasts();
+
+ bool ExtWarnMSTemplateArg = false;
+ UnaryOperatorKind FirstOpKind;
+ SourceLocation FirstOpLoc;
+ while (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
+ UnaryOperatorKind UnOpKind = UnOp->getOpcode();
+ if (UnOpKind == UO_Deref)
+ ExtWarnMSTemplateArg = true;
+ if (UnOpKind == UO_AddrOf || UnOpKind == UO_Deref) {
+ Arg = UnOp->getSubExpr()->IgnoreParenCasts();
+ if (!AddrOpLoc.isValid()) {
+ FirstOpKind = UnOpKind;
+ FirstOpLoc = UnOp->getOperatorLoc();
+ }
+ } else
+ break;
+ }
+ if (FirstOpLoc.isValid()) {
+ if (ExtWarnMSTemplateArg)
+ S.Diag(ArgIn->getLocStart(), diag::ext_ms_deref_template_argument)
+ << ArgIn->getSourceRange();
+
+ if (FirstOpKind == UO_AddrOf)
+ AddressTaken = true;
+ else if (Arg->getType()->isPointerType()) {
+ // We cannot let pointers get dereferenced here, that is obviously not a
+ // constant expression.
+ assert(FirstOpKind == UO_Deref);
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+ }
}
+ } else {
+ // See through any implicit casts we added to fix the type.
+ Arg = Arg->IgnoreImpCasts();
- Arg = Parens->getSubExpr();
- }
+ // C++ [temp.arg.nontype]p1:
+ //
+ // A template-argument for a non-type, non-template
+ // template-parameter shall be one of: [...]
+ //
+ // -- the address of an object or function with external
+ // linkage, including function templates and function
+ // template-ids but excluding non-static class members,
+ // expressed as & id-expression where the & is optional if
+ // the name refers to a function or array, or if the
+ // corresponding template-parameter is a reference; or
+
+ // In C++98/03 mode, give an extension warning on any extra parentheses.
+ // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
+ bool ExtraParens = false;
+ while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
+ if (!Invalid && !ExtraParens) {
+ S.Diag(Arg->getLocStart(),
+ S.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_template_arg_extra_parens
+ : diag::ext_template_arg_extra_parens)
+ << Arg->getSourceRange();
+ ExtraParens = true;
+ }
- while (SubstNonTypeTemplateParmExpr *subst =
- dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
- Arg = subst->getReplacement()->IgnoreImpCasts();
+ Arg = Parens->getSubExpr();
+ }
- bool AddressTaken = false;
- SourceLocation AddrOpLoc;
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
- if (UnOp->getOpcode() == UO_AddrOf) {
- Arg = UnOp->getSubExpr();
- AddressTaken = true;
- AddrOpLoc = UnOp->getOperatorLoc();
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
+ if (UnOp->getOpcode() == UO_AddrOf) {
+ Arg = UnOp->getSubExpr();
+ AddressTaken = true;
+ AddrOpLoc = UnOp->getOperatorLoc();
+ }
}
+
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
}
- if (S.getLangOpts().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) {
+ // Stop checking the precise nature of the argument if it is value dependent,
+ // it should be checked when instantiated.
+ if (Arg->isValueDependent()) {
Converted = TemplateArgument(ArgIn);
return false;
}
- while (SubstNonTypeTemplateParmExpr *subst =
- dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
- Arg = subst->getReplacement()->IgnoreImpCasts();
+ if (isa<CXXUuidofExpr>(Arg)) {
+ if (CheckTemplateArgumentIsCompatibleWithParameter(S, Param, ParamType,
+ ArgIn, Arg, ArgType))
+ return true;
- // Stop checking the precise nature of the argument if it is value dependent,
- // it should be checked when instantiated.
- if (Arg->isValueDependent()) {
Converted = TemplateArgument(ArgIn);
return false;
}
-
+
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
@@ -3752,20 +4359,12 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
- if (!isa<ValueDecl>(DRE->getDecl())) {
- S.Diag(Arg->getLocStart(),
- diag::err_template_arg_not_object_or_func_form)
- << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
ValueDecl *Entity = DRE->getDecl();
// Cannot refer to non-static data members
- if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) {
+ if (isa<FieldDecl>(Entity) || isa<IndirectFieldDecl>(Entity)) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_field)
- << Field << Arg->getSourceRange();
+ << Entity << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -3793,14 +4392,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
// Address / reference template args must have external linkage in C++98.
- if (Entity->getLinkage() == InternalLinkage) {
+ if (Entity->getFormalLinkage() == InternalLinkage) {
S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_object_internal :
diag::ext_template_arg_object_internal)
<< !Func << Entity << Arg->getSourceRange();
S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
<< !Func;
- } else if (Entity->getLinkage() == NoLinkage) {
+ } else if (!Entity->hasLinkage()) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage)
<< !Func << Entity << Arg->getSourceRange();
S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
@@ -3896,55 +4495,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
}
- bool ObjCLifetimeConversion;
- if (ParamType->isPointerType() &&
- !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
- S.IsQualificationConversion(ArgType, ParamType, false,
- ObjCLifetimeConversion)) {
- // For pointer-to-object types, qualification conversions are
- // permitted.
- } else {
- if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) {
- if (!ParamRef->getPointeeType()->isFunctionType()) {
- // C++ [temp.arg.nontype]p5b3:
- // For a non-type template-parameter of type reference to
- // object, no conversions apply. The type referred to by the
- // reference may be more cv-qualified than the (otherwise
- // identical) type of the template- argument. The
- // template-parameter is bound directly to the
- // template-argument, which shall be an lvalue.
-
- // FIXME: Other qualifiers?
- unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers();
- unsigned ArgQuals = ArgType.getCVRQualifiers();
-
- if ((ParamQuals | ArgQuals) != ParamQuals) {
- S.Diag(Arg->getLocStart(),
- diag::err_template_arg_ref_bind_ignores_quals)
- << ParamType << Arg->getType()
- << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
- }
- }
-
- // At this point, the template argument refers to an object or
- // function with external linkage. We now need to check whether the
- // argument and parameter types are compatible.
- if (!S.Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
- // We can't perform this conversion or binding.
- if (ParamType->isReferenceType())
- S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
- << ParamType << ArgIn->getType() << Arg->getSourceRange();
- else
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
- << ArgIn->getType() << ParamType << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
- }
+ if (CheckTemplateArgumentIsCompatibleWithParameter(S, Param, ParamType, ArgIn,
+ Arg, ArgType))
+ return true;
// Create the template argument.
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
@@ -4035,9 +4588,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) {
if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) {
if (VD->getType()->isMemberPointerType()) {
- if (isa<NonTypeTemplateParmDecl>(VD) ||
- (isa<VarDecl>(VD) &&
- S.Context.getCanonicalType(VD->getType()).isConstQualified())) {
+ if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
} else {
@@ -4057,8 +4608,11 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
diag::err_template_arg_not_pointer_to_member_form)
<< Arg->getSourceRange();
- if (isa<FieldDecl>(DRE->getDecl()) || isa<CXXMethodDecl>(DRE->getDecl())) {
+ if (isa<FieldDecl>(DRE->getDecl()) ||
+ isa<IndirectFieldDecl>(DRE->getDecl()) ||
+ isa<CXXMethodDecl>(DRE->getDecl())) {
assert((isa<FieldDecl>(DRE->getDecl()) ||
+ isa<IndirectFieldDecl>(DRE->getDecl()) ||
!cast<CXXMethodDecl>(DRE->getDecl())->isStatic()) &&
"Only non-static member pointers can make it here");
@@ -4520,7 +5074,8 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
if (VD->getDeclContext()->isRecord() &&
- (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
+ isa<IndirectFieldDecl>(VD))) {
// If the value is a class member, we might have a pointer-to-member.
// Determine whether the non-type template template parameter is of
// pointer-to-member type. If so, we need to build an appropriate
@@ -4898,7 +5453,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// C++ [temp]p2:
// A template-declaration can appear only as a namespace scope or
// class scope declaration.
- DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *Ctx = S->getEntity();
if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
@@ -4907,8 +5462,20 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
- if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
- return false;
+ if (Ctx) {
+ if (Ctx->isFileContext())
+ return false;
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Ctx)) {
+ // C++ [temp.mem]p2:
+ // A local class shall not have member templates.
+ if (RD->isLocalClass())
+ return Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_inside_local_class)
+ << TemplateParams->getSourceRange();
+ else
+ return false;
+ }
+ }
return Diag(TemplateParams->getTemplateLoc(),
diag::err_template_outside_namespace_or_class_scope)
@@ -4965,16 +5532,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
int EntityKind = 0;
if (isa<ClassTemplateDecl>(Specialized))
EntityKind = IsPartialSpecialization? 1 : 0;
+ else if (isa<VarTemplateDecl>(Specialized))
+ EntityKind = IsPartialSpecialization ? 3 : 2;
else if (isa<FunctionTemplateDecl>(Specialized))
- EntityKind = 2;
+ EntityKind = 4;
else if (isa<CXXMethodDecl>(Specialized))
- EntityKind = 3;
+ EntityKind = 5;
else if (isa<VarDecl>(Specialized))
- EntityKind = 4;
+ EntityKind = 6;
else if (isa<RecordDecl>(Specialized))
- EntityKind = 5;
+ EntityKind = 7;
else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11)
- EntityKind = 6;
+ EntityKind = 8;
else {
S.Diag(Loc, diag::err_template_spec_unknown_kind)
<< S.getLangOpts().CPlusPlus11;
@@ -5098,17 +5667,15 @@ static bool CheckTemplateSpecializationScope(Sema &S,
return false;
}
-/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs
+/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs
/// that checks non-type template partial specialization arguments.
-static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
- NonTypeTemplateParmDecl *Param,
- const TemplateArgument *Args,
- unsigned NumArgs) {
+static bool CheckNonTypeTemplatePartialSpecializationArgs(
+ Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args,
+ unsigned NumArgs) {
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].getKind() == TemplateArgument::Pack) {
- if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param,
- Args[I].pack_begin(),
- Args[I].pack_size()))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(
+ S, Param, Args[I].pack_begin(), Args[I].pack_size()))
return true;
continue;
@@ -5179,9 +5746,9 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
/// partial specialization.
///
/// \returns true if there was an error, false otherwise.
-static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
- TemplateParameterList *TemplateParams,
- SmallVectorImpl<TemplateArgument> &TemplateArgs) {
+static bool CheckTemplatePartialSpecializationArgs(
+ Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<TemplateArgument> &TemplateArgs) {
const TemplateArgument *ArgList = TemplateArgs.data();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -5190,8 +5757,7 @@ static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
if (!Param)
continue;
- if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param,
- &ArgList[I], 1))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1))
return true;
}
@@ -5219,7 +5785,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();
// Find the class template we're specializing
- TemplateName Name = TemplateD.getAsVal<TemplateName>();
+ TemplateName Name = TemplateD.get();
ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl());
@@ -5238,15 +5804,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// FIXME: We probably shouldn't complain about these headers for
// friend declarations.
bool Invalid = false;
- TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
- TemplateNameLoc,
- SS,
- TemplateParameterLists.data(),
- TemplateParameterLists.size(),
- TUK == TUK_Friend,
- isExplicitSpecialization,
- Invalid);
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ TemplateNameLoc, TemplateNameLoc, SS, TemplateParameterLists,
+ TUK == TUK_Friend, isExplicitSpecialization, Invalid);
if (Invalid)
return true;
@@ -5300,6 +5861,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
} else if (TUK != TUK_Friend) {
Diag(KWLoc, diag::err_template_spec_needs_header)
<< FixItHint::CreateInsertion(KWLoc, "template<> ");
+ TemplateKWLoc = KWLoc;
isExplicitSpecialization = true;
}
@@ -5341,9 +5903,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
if (isPartialSpecialization) {
- if (CheckClassTemplatePartialSpecializationArgs(*this,
- ClassTemplate->getTemplateParameters(),
- Converted))
+ if (CheckTemplatePartialSpecializationArgs(
+ *this, ClassTemplate->getTemplateParameters(), Converted))
return true;
bool InstantiationDependent;
@@ -5416,7 +5977,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TUK == TUK_Definition)
+ << /*class template*/0 << (TUK == TUK_Definition)
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
@@ -5431,8 +5992,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
- : ClassTemplate->getNextPartialSpecSequenceNumber();
ClassTemplatePartialSpecializationDecl *Partial
= ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
@@ -5443,8 +6002,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Converted.size(),
TemplateArgs,
CanonType,
- PrevPartial,
- SequenceNumber);
+ PrevPartial);
SetNestedNameSpecifier(Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(Context,
@@ -5473,7 +6031,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (!DeducibleParams.all()) {
unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count();
Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
- << (NumNonDeducible > 1)
+ << /*class template*/0 << (NumNonDeducible > 1)
<< SourceRange(TemplateNameLoc, RAngleLoc);
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
if (!DeducibleParams[I]) {
@@ -5710,7 +6268,10 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
switch (NewTSK) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- llvm_unreachable("Don't check implicit instantiations here");
+ assert(
+ (PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) &&
+ "previous declaration must be implicit!");
+ return false;
case TSK_ExplicitSpecialization:
switch (PrevTSK) {
@@ -5916,13 +6477,13 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
///
/// \param Previous the set of declarations that may be specialized by
/// this function specialization.
-bool
-Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- LookupResult &Previous) {
+bool Sema::CheckFunctionTemplateSpecialization(
+ FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
+ LookupResult &Previous) {
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
+ TemplateSpecCandidateSet FailedCandidates(FD->getLocation());
DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext();
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
@@ -5948,9 +6509,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
- FT = Context.getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
+ FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(),
EPI);
}
}
@@ -5962,13 +6521,16 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Perform template argument deduction to determine whether we may be
// specializing this template.
// FIXME: It is somewhat wasteful to build
- TemplateDeductionInfo Info(FD->getLocation());
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
FunctionDecl *Specialization = 0;
- if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT,
- Specialization, Info)) {
- // FIXME: Template argument deduction failed; record why it failed, so
+ if (TemplateDeductionResult TDK = DeduceTemplateArguments(
+ cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
+ ExplicitTemplateArgs, FT, Specialization, Info)) {
+ // Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
+ FailedCandidates.addCandidate()
+ .set(FunTmpl->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
}
@@ -5979,14 +6541,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
}
// Find the most specialized function template.
- UnresolvedSetIterator Result
- = getMostSpecialized(Candidates.begin(), Candidates.end(),
- TPOC_Other, 0, FD->getLocation(),
- PDiag(diag::err_function_template_spec_no_match)
- << FD->getDeclName(),
- PDiag(diag::err_function_template_spec_ambiguous)
- << FD->getDeclName() << (ExplicitTemplateArgs != 0),
- PDiag(diag::note_function_template_spec_matched));
+ UnresolvedSetIterator Result = getMostSpecialized(
+ Candidates.begin(), Candidates.end(), FailedCandidates,
+ FD->getLocation(),
+ PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(),
+ PDiag(diag::err_function_template_spec_ambiguous)
+ << FD->getDeclName() << (ExplicitTemplateArgs != 0),
+ PDiag(diag::note_function_template_spec_matched));
+
if (Result == Candidates.end())
return true;
@@ -6213,9 +6775,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
InstantiationVar->setLocation(Member->getLocation());
}
- Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
- cast<VarDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
+ cast<VarDecl>(Member)->setInstantiationOfStaticDataMember(
+ cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(InstantiationVar);
} else if (isa<CXXRecordDecl>(Member)) {
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
@@ -6340,15 +6901,23 @@ Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation RAngleLoc,
AttributeList *Attr) {
// Find the class template we're specializing
- TemplateName Name = TemplateD.getAsVal<TemplateName>();
- ClassTemplateDecl *ClassTemplate
- = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
-
+ TemplateName Name = TemplateD.get();
+ TemplateDecl *TD = Name.getAsTemplateDecl();
// Check that the specialization uses the same tag kind as the
// original template.
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
assert(Kind != TTK_Enum &&
"Invalid enum tag in class template explicit instantiation!");
+
+ if (isa<TypeAliasTemplateDecl>(TD)) {
+ Diag(KWLoc, diag::err_tag_reference_non_tag) << Kind;
+ Diag(TD->getTemplatedDecl()->getLocation(),
+ diag::note_previous_use);
+ return true;
+ }
+
+ ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(TD);
+
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, /*isDefinition*/false, KWLoc,
*ClassTemplate->getIdentifier())) {
@@ -6695,7 +7264,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType())
// FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
// not already specified.
Diag(D.getDeclSpec().getConstexprSpecLoc(),
@@ -6717,28 +7286,78 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A [...] static data member of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
+ // C++1y [temp.explicit]p1:
+ // A [...] variable [...] template specialization can be explicitly
+ // instantiated from its template.
if (Previous.isAmbiguous())
return true;
VarDecl *Prev = Previous.getAsSingle<VarDecl>();
- if (!Prev || !Prev->isStaticDataMember()) {
- // We expect to see a data data member here.
- Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
- << Name;
- for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
- P != PEnd; ++P)
- Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
- return true;
- }
+ VarTemplateDecl *PrevTemplate = Previous.getAsSingle<VarTemplateDecl>();
+
+ if (!PrevTemplate) {
+ if (!Prev || !Prev->isStaticDataMember()) {
+ // We expect to see a data data member here.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+ << Name;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P)
+ Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+ }
- if (!Prev->getInstantiatedFromStaticDataMember()) {
- // FIXME: Check for explicit specialization?
- Diag(D.getIdentifierLoc(),
- diag::err_explicit_instantiation_data_member_not_instantiated)
- << Prev;
- Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
- // FIXME: Can we provide a note showing where this was declared?
- return true;
+ if (!Prev->getInstantiatedFromStaticDataMember()) {
+ // FIXME: Check for explicit specialization?
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_data_member_not_instantiated)
+ << Prev;
+ Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+ // FIXME: Can we provide a note showing where this was declared?
+ return true;
+ }
+ } else {
+ // Explicitly instantiate a variable template.
+
+ // C++1y [dcl.spec.auto]p6:
+ // ... A program that uses auto or decltype(auto) in a context not
+ // explicitly allowed in this section is ill-formed.
+ //
+ // This includes auto-typed variable template instantiations.
+ if (R->isUndeducedType()) {
+ Diag(T->getTypeLoc().getLocStart(),
+ diag::err_auto_not_allowed_var_inst);
+ return true;
+ }
+
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ // C++1y [temp.explicit]p3:
+ // If the explicit instantiation is for a variable, the unqualified-id
+ // in the declaration shall be a template-id.
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_without_template_id)
+ << PrevTemplate;
+ Diag(PrevTemplate->getLocation(),
+ diag::note_explicit_instantiation_here);
+ return true;
+ }
+
+ // Translate the parser's template argument list into our AST format.
+ TemplateArgumentListInfo TemplateArgs;
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+
+ DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
+ D.getIdentifierLoc(), TemplateArgs);
+ if (Res.isInvalid())
+ return true;
+
+ // Ignore access control bits, we don't need them for redeclaration
+ // checking.
+ Prev = cast<VarDecl>(Res.get());
}
// C++0x [temp.explicit]p2:
@@ -6748,7 +7367,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// name shall be a simple-template-id.
//
// C++98 has the same restriction, just worded differently.
- if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()))
+ //
+ // This does not apply to variable template specializations, where the
+ // template-id is in the unqualified-id instead.
+ if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()) && !PrevTemplate)
Diag(D.getIdentifierLoc(),
diag::ext_explicit_instantiation_without_qualified_id)
<< Prev << D.getCXXScopeSpec().getRange();
@@ -6757,21 +7379,35 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
// Verify that it is okay to explicitly instantiate here.
- MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
- assert(MSInfo && "Missing static data member specialization info?");
+ TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
+ SourceLocation POI = Prev->getPointOfInstantiation();
bool HasNoEffect = false;
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
- MSInfo->getTemplateSpecializationKind(),
- MSInfo->getPointOfInstantiation(),
- HasNoEffect))
+ PrevTSK, POI, HasNoEffect))
return true;
- if (HasNoEffect)
- return (Decl*) 0;
- // Instantiate static data member.
- Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
- if (TSK == TSK_ExplicitInstantiationDefinition)
- InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev);
+ if (!HasNoEffect) {
+ // Instantiate static data member or variable template.
+
+ Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+ if (PrevTemplate) {
+ // Merge attributes.
+ if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
+ ProcessDeclAttributeList(S, Prev, Attr);
+ }
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
+ }
+
+ // Check the new variable specialization against the parsed input.
+ if (PrevTemplate && Prev && !Context.hasSameType(Prev->getType(), R)) {
+ Diag(T->getTypeLoc().getLocStart(),
+ diag::err_invalid_var_template_spec_type)
+ << 0 << PrevTemplate << R << Prev->getType();
+ Diag(PrevTemplate->getLocation(), diag::note_template_declared_here)
+ << 2 << PrevTemplate->getDeclName();
+ return true;
+ }
// FIXME: Create an ExplicitInstantiation node?
return (Decl*) 0;
@@ -6797,12 +7433,14 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// instantiated from the member definition associated with its class
// template.
UnresolvedSet<8> Matches;
+ TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc());
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
P != PEnd; ++P) {
NamedDecl *Prev = *P;
if (!HasExplicitTemplateArgs) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
- if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
+ QualType Adjusted = adjustCCAndNoReturn(R, Method->getType());
+ if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) {
Matches.clear();
Matches.addDecl(Method, P.getAccess());
@@ -6816,13 +7454,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(D.getIdentifierLoc());
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
R, Specialization, Info)) {
- // FIXME: Keep track of almost-matches?
+ // Keep track of almost-matches.
+ FailedCandidates.addCandidate()
+ .set(FunTmpl->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
}
@@ -6831,12 +7472,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// Find the most specialized function template specialization.
- UnresolvedSetIterator Result
- = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, 0,
- D.getIdentifierLoc(),
- PDiag(diag::err_explicit_instantiation_not_known) << Name,
- PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
- PDiag(diag::note_explicit_instantiation_candidate));
+ 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;
@@ -7373,11 +8014,26 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
return Out.str();
}
-void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag) {
+void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
+ CachedTokens &Toks) {
if (!FD)
return;
- FD->setLateTemplateParsed(Flag);
-}
+
+ LateParsedTemplate *LPT = new LateParsedTemplate;
+
+ // Take tokens to avoid allocations
+ LPT->Toks.swap(Toks);
+ LPT->D = FnD;
+ LateParsedTemplateMap[FD] = LPT;
+
+ FD->setLateTemplateParsed(true);
+}
+
+void Sema::UnmarkAsLateParsedTemplate(FunctionDecl *FD) {
+ if (!FD)
+ return;
+ FD->setLateTemplateParsed(false);
+}
bool Sema::IsInsideALocalClassWithinATemplateFunction() {
DeclContext *DC = CurContext;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 8efc7a026347..8d66ff68efa6 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -26,7 +27,6 @@
namespace clang {
using namespace sema;
-
/// \brief Various flags that control template argument deduction.
///
/// These flags can be bitwise-OR'd together.
@@ -89,7 +89,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
TemplateArgument Arg,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief Whether template argument deduction for two reference parameters
/// resulted in the argument type, parameter type, or neither type being more
@@ -375,10 +375,10 @@ DeduceNonTypeTemplateArgument(Sema &S,
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
- NonTypeTemplateParmDecl *NTTP,
- ValueDecl *D,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ NonTypeTemplateParmDecl *NTTP,
+ ValueDecl *D,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -405,7 +405,7 @@ DeduceTemplateArguments(Sema &S,
TemplateName Param,
TemplateName Arg,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -464,7 +464,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateSpecializationType *Param,
QualType Arg,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(Arg.isCanonical() && "Argument type must be canonical");
// Check whether the template argument is a dependent template-id.
@@ -575,20 +575,23 @@ getDepthAndIndex(UnexpandedParameterPack UPP) {
static TemplateParameter makeTemplateParameter(Decl *D) {
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
return TemplateParameter(TTP);
- else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
+typedef SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
+ NewlyDeducedPacksType;
+
/// \brief Prepare to perform template argument deduction for all of the
/// arguments in a set of argument packs.
-static void PrepareArgumentPackDeduction(Sema &S,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- SmallVectorImpl<
- SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) {
+static void
+PrepareArgumentPackDeduction(Sema &S,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ ArrayRef<unsigned> PackIndices,
+ SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
+ NewlyDeducedPacksType &NewlyDeducedPacks) {
// Save the deduced template arguments for each parameter pack expanded
// by this pack expansion, then clear out the deduction.
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
@@ -620,14 +623,13 @@ static void PrepareArgumentPackDeduction(Sema &S,
/// deductions.
static Sema::TemplateDeductionResult
FinishArgumentPackDeduction(Sema &S,
- TemplateParameterList *TemplateParams,
- bool HasAnyArguments,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- SmallVectorImpl<
- SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks,
- TemplateDeductionInfo &Info) {
+ TemplateParameterList *TemplateParams,
+ bool HasAnyArguments,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ ArrayRef<unsigned> PackIndices,
+ SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
+ NewlyDeducedPacksType &NewlyDeducedPacks,
+ TemplateDeductionInfo &Info) {
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
@@ -709,7 +711,7 @@ DeduceTemplateArguments(Sema &S,
const QualType *Params, unsigned NumParams,
const QualType *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false,
SmallVectorImpl<RefParamPartialOrderingComparison> *
@@ -793,8 +795,7 @@ DeduceTemplateArguments(Sema &S,
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
- SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacks(PackIndices.size());
+ NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
@@ -1430,8 +1431,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Deduced.end());
while (!ToVisit.empty()) {
// Retrieve the next class in the inheritance hierarchy.
- const RecordType *NextT = ToVisit.back();
- ToVisit.pop_back();
+ const RecordType *NextT = ToVisit.pop_back_val();
// If we have already seen this type, skip it.
if (!Visited.insert(NextT))
@@ -1635,7 +1635,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
TemplateArgument Arg,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// If the template argument is a pack expansion, perform template argument
// deduction against the pattern of that expansion. This only occurs during
// partial ordering.
@@ -1871,8 +1871,7 @@ DeduceTemplateArguments(Sema &S,
// by this pack expansion, then clear out the deduction.
SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
- SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacks(PackIndices.size());
+ NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
NewlyDeducedPacks);
@@ -1921,7 +1920,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceTemplateArguments(S, TemplateParams,
ParamList.data(), ParamList.size(),
ArgList.data(), ArgList.size(),
@@ -2064,14 +2063,15 @@ getTrivialTemplateArgumentLoc(Sema &S,
/// \brief Convert the given deduced template argument and add it to the set of
/// fully-converted template arguments.
-static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
- DeducedTemplateArgument Arg,
- NamedDecl *Template,
- QualType NTTPType,
- unsigned ArgumentPackIndex,
- TemplateDeductionInfo &Info,
- bool InFunctionTemplate,
- SmallVectorImpl<TemplateArgument> &Output) {
+static bool
+ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
+ DeducedTemplateArgument Arg,
+ NamedDecl *Template,
+ QualType NTTPType,
+ unsigned ArgumentPackIndex,
+ TemplateDeductionInfo &Info,
+ bool InFunctionTemplate,
+ SmallVectorImpl<TemplateArgument> &Output) {
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
@@ -2090,8 +2090,7 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
return true;
// Move the converted template argument into our argument pack.
- PackedArgsBuilder.push_back(Output.back());
- Output.pop_back();
+ PackedArgsBuilder.push_back(Output.pop_back_val());
}
// Create the resulting argument pack.
@@ -2200,14 +2199,15 @@ FinishTemplateArgumentDeduction(Sema &S,
// to the class template.
LocalInstantiationScope InstScope(S);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
- const TemplateArgumentLoc *PartialTemplateArgs
+ const ASTTemplateArgumentListInfo *PartialTemplArgInfo
= Partial->getTemplateArgsAsWritten();
+ const TemplateArgumentLoc *PartialTemplateArgs
+ = PartialTemplArgInfo->getTemplateArgs();
- // Note that we don't provide the langle and rangle locations.
- TemplateArgumentListInfo InstArgs;
+ TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
+ PartialTemplArgInfo->RAngleLoc);
- if (S.Subst(PartialTemplateArgs,
- Partial->getNumTemplateArgsAsWritten(),
+ if (S.Subst(PartialTemplateArgs, PartialTemplArgInfo->NumTemplateArgs,
InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= Partial->getTemplateParameters()->size())
@@ -2276,7 +2276,171 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
DeducedArgs, Info);
- if (Inst)
+ if (Inst.isInvalid())
+ return TDK_InstantiationDepth;
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs,
+ Deduced, Info);
+}
+
+/// Complete template argument deduction for a variable template partial
+/// specialization.
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, VarTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info) {
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ Sema::SFINAETrap Trap(S);
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ SmallVector<TemplateArgument, 4> Builder;
+ TemplateParameterList *PartialParams = Partial->getTemplateParameters();
+ for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
+ NamedDecl *Param = PartialParams->getParam(I);
+ if (Deduced[I].isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ return Sema::TDK_Incomplete;
+ }
+
+ // We have deduced this argument, so it still needs to be
+ // checked and converted.
+
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Builder.data(), Builder.size());
+ NTTPType =
+ S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(), NTTP->getDeclName());
+ if (NTTPType.isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
+ Builder.size()));
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+ }
+
+ if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType,
+ 0, Info, false, Builder)) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
+ Builder.size()));
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(
+ S.Context, Builder.data(), Builder.size());
+
+ Info.reset(DeducedArgumentList);
+
+ // Substitute the deduced template arguments into the template
+ // arguments of the class template partial specialization, and
+ // verify that the instantiated template arguments are both valid
+ // and are equivalent to the template arguments originally provided
+ // to the class template.
+ LocalInstantiationScope InstScope(S);
+ VarTemplateDecl *VarTemplate = Partial->getSpecializedTemplate();
+ const ASTTemplateArgumentListInfo *PartialTemplArgInfo
+ = Partial->getTemplateArgsAsWritten();
+ const TemplateArgumentLoc *PartialTemplateArgs
+ = PartialTemplArgInfo->getTemplateArgs();
+
+ TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
+ PartialTemplArgInfo->RAngleLoc);
+
+ if (S.Subst(PartialTemplateArgs, PartialTemplArgInfo->NumTemplateArgs,
+ InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
+ unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
+ if (ParamIdx >= Partial->getTemplateParameters()->size())
+ ParamIdx = Partial->getTemplateParameters()->size() - 1;
+
+ Decl *Param = const_cast<NamedDecl *>(
+ Partial->getTemplateParameters()->getParam(ParamIdx));
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument();
+ return Sema::TDK_SubstitutionFailure;
+ }
+ SmallVector<TemplateArgument, 4> ConvertedInstArgs;
+ if (S.CheckTemplateArgumentList(VarTemplate, Partial->getLocation(), InstArgs,
+ false, ConvertedInstArgs))
+ return Sema::TDK_SubstitutionFailure;
+
+ TemplateParameterList *TemplateParams = VarTemplate->getTemplateParameters();
+ for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
+ TemplateArgument InstArg = ConvertedInstArgs.data()[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
+ Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
+ Info.FirstArg = TemplateArgs[I];
+ Info.SecondArg = InstArg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return Sema::TDK_Success;
+}
+
+/// \brief Perform template argument deduction to determine whether
+/// the given template arguments match the given variable template
+/// partial specialization per C++ [temp.class.spec.match].
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
+ if (Partial->isInvalidDecl())
+ return TDK_Invalid;
+
+ // C++ [temp.class.spec.match]p2:
+ // A partial specialization matches a given actual template
+ // argument list if the template arguments of the partial
+ // specialization can be deduced from the actual template argument
+ // list (14.8.2).
+
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ SFINAETrap Trap(*this);
+
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
+ *this, Partial->getTemplateParameters(), Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
+
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
+ InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
+ DeducedArgs, Info);
+ if (Inst.isInvalid())
return TDK_InstantiationDepth;
if (Trap.hasErrorOccurred())
@@ -2364,7 +2528,7 @@ Sema::SubstituteExplicitTemplateArguments(
FunctionTemplate, DeducedArgs,
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
Info);
- if (Inst)
+ if (Inst.isInvalid())
return TDK_InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate,
@@ -2423,7 +2587,6 @@ Sema::SubstituteExplicitTemplateArguments(
}
// Instantiate the return type.
- // FIXME: exception-specifications?
QualType ResultType;
{
// C++11 [expr.prim.general]p3:
@@ -2524,13 +2687,16 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
- // Under Objective-C++ ARC, the deduced type may have implicitly been
- // given strong lifetime. If so, update the original qualifiers to
- // include this strong lifetime.
+ // Under Objective-C++ ARC, the deduced type may have implicitly
+ // been given strong or (when dealing with a const reference)
+ // unsafe_unretained lifetime. If so, update the original
+ // qualifiers to include this lifetime.
if (S.getLangOpts().ObjCAutoRefCount &&
- DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
- AQuals.getObjCLifetime() == Qualifiers::OCL_None) {
- AQuals.setObjCLifetime(Qualifiers::OCL_Strong);
+ ((DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
+ AQuals.getObjCLifetime() == Qualifiers::OCL_None) ||
+ (DeducedAQuals.hasConst() &&
+ DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone))) {
+ AQuals.setObjCLifetime(DeducedAQuals.getObjCLifetime());
}
if (AQuals == DeducedAQuals) {
@@ -2551,7 +2717,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
//
// Also allow conversions which merely strip [[noreturn]] from function types
// (recursively) as an extension.
- // FIXME: Currently, this doesn't place nicely with qualfication conversions.
+ // FIXME: Currently, this doesn't play nicely with qualification conversions.
bool ObjCLifetimeConversion = false;
QualType ResultTy;
if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
@@ -2616,7 +2782,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
FunctionTemplate, DeducedArgs,
ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
Info);
- if (Inst)
+ if (Inst.isInvalid())
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
@@ -2704,18 +2870,21 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
}
// Substitute into the default template argument, if available.
+ bool HasDefaultArg = false;
TemplateArgumentLoc DefArg
= SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
Param,
- Builder);
+ Builder, HasDefaultArg);
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
- return TDK_Incomplete;
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
+ Builder.size()));
+ return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete;
}
// Check whether we can actually use the default argument.
@@ -2792,7 +2961,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// keep track of these diagnostics. They'll be emitted if this specialization
// is actually used.
if (Info.diag_begin() != Info.diag_end()) {
- llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator
+ SuppressedDiagnosticsMap::iterator
Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl());
if (Pos == SuppressedDiagnostics.end())
SuppressedDiagnostics[Specialization->getCanonicalDecl()]
@@ -3099,12 +3268,10 @@ DeduceTemplateArgumentByListElement(Sema &S,
/// about template argument deduction.
///
/// \returns the result of template argument deduction.
-Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
- FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
+ FunctionDecl *&Specialization, TemplateDeductionInfo &Info) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3251,8 +3418,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
- SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacks(PackIndices.size());
+ NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks,
@@ -3335,6 +3501,28 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Specialization, Info, &OriginalCallArgs);
}
+QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
+ QualType FunctionType) {
+ if (ArgFunctionType.isNull())
+ return ArgFunctionType;
+
+ const FunctionProtoType *FunctionTypeP =
+ FunctionType->castAs<FunctionProtoType>();
+ CallingConv CC = FunctionTypeP->getCallConv();
+ bool NoReturn = FunctionTypeP->getNoReturnAttr();
+ const FunctionProtoType *ArgFunctionTypeP =
+ ArgFunctionType->getAs<FunctionProtoType>();
+ if (ArgFunctionTypeP->getCallConv() == CC &&
+ ArgFunctionTypeP->getNoReturnAttr() == NoReturn)
+ return ArgFunctionType;
+
+ FunctionType::ExtInfo EI = ArgFunctionTypeP->getExtInfo().withCallingConv(CC);
+ EI = EI.withNoReturn(NoReturn);
+ ArgFunctionTypeP =
+ cast<FunctionProtoType>(Context.adjustFunctionType(ArgFunctionTypeP, EI));
+ return QualType(ArgFunctionTypeP, 0);
+}
+
/// \brief Deduce template arguments when taking the address of a function
/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to
/// a template.
@@ -3372,6 +3560,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
+ if (!InOverloadResolution)
+ ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType);
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);
@@ -3397,11 +3587,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// If the function has a deduced return type, substitute it for a dependent
// type so that we treat it as a non-deduced context in what follows.
- bool HasUndeducedReturnType = false;
+ bool HasDeducedReturnType = false;
if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
- Function->getResultType()->isUndeducedType()) {
+ Function->getResultType()->getContainedAutoType()) {
FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
- HasUndeducedReturnType = true;
+ HasDeducedReturnType = true;
}
if (!ArgFunctionType.isNull()) {
@@ -3423,7 +3613,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// If the function has a deduced return type, deduce it now, so we can check
// that the deduced function type matches the requested type.
- if (HasUndeducedReturnType &&
+ if (HasDeducedReturnType &&
Specialization->getResultType()->isUndeducedType() &&
DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
@@ -3444,20 +3634,130 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return TDK_Success;
}
+/// \brief Given a function declaration (e.g. a generic lambda conversion
+/// function) that contains an 'auto' in its result type, substitute it
+/// with TypeToReplaceAutoWith. Be careful to pass in the type you want
+/// to replace 'auto' with and not the actual result type you want
+/// to set the function to.
+static inline void
+SubstAutoWithinFunctionReturnType(FunctionDecl *F,
+ QualType TypeToReplaceAutoWith, Sema &S) {
+ assert(!TypeToReplaceAutoWith->getContainedAutoType());
+ QualType AutoResultType = F->getResultType();
+ assert(AutoResultType->getContainedAutoType());
+ QualType DeducedResultType = S.SubstAutoType(AutoResultType,
+ TypeToReplaceAutoWith);
+ S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);
+}
+
+/// \brief Given a specialized conversion operator of a generic lambda
+/// create the corresponding specializations of the call operator and
+/// the static-invoker. If the return type of the call operator is auto,
+/// deduce its return type and check if that matches the
+/// return type of the destination function ptr.
+
+static inline Sema::TemplateDeductionResult
+SpecializeCorrespondingLambdaCallOperatorAndInvoker(
+ CXXConversionDecl *ConversionSpecialized,
+ SmallVectorImpl<DeducedTemplateArgument> &DeducedArguments,
+ QualType ReturnTypeOfDestFunctionPtr,
+ TemplateDeductionInfo &TDInfo,
+ Sema &S) {
+
+ CXXRecordDecl *LambdaClass = ConversionSpecialized->getParent();
+ assert(LambdaClass && LambdaClass->isGenericLambda());
+
+ CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator();
+ QualType CallOpResultType = CallOpGeneric->getResultType();
+ const bool GenericLambdaCallOperatorHasDeducedReturnType =
+ CallOpResultType->getContainedAutoType();
+
+ FunctionTemplateDecl *CallOpTemplate =
+ CallOpGeneric->getDescribedFunctionTemplate();
+
+ FunctionDecl *CallOpSpecialized = 0;
+ // Use the deduced arguments of the conversion function, to specialize our
+ // generic lambda's call operator.
+ if (Sema::TemplateDeductionResult Result
+ = S.FinishTemplateArgumentDeduction(CallOpTemplate,
+ DeducedArguments,
+ 0, CallOpSpecialized, TDInfo))
+ return Result;
+
+ // If we need to deduce the return type, do so (instantiates the callop).
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ CallOpSpecialized->getResultType()->isUndeducedType())
+ S.DeduceReturnType(CallOpSpecialized,
+ CallOpSpecialized->getPointOfInstantiation(),
+ /*Diagnose*/ true);
+
+ // Check to see if the return type of the destination ptr-to-function
+ // matches the return type of the call operator.
+ if (!S.Context.hasSameType(CallOpSpecialized->getResultType(),
+ ReturnTypeOfDestFunctionPtr))
+ return Sema::TDK_NonDeducedMismatch;
+ // Since we have succeeded in matching the source and destination
+ // ptr-to-functions (now including return type), and have successfully
+ // specialized our corresponding call operator, we are ready to
+ // specialize the static invoker with the deduced arguments of our
+ // ptr-to-function.
+ FunctionDecl *InvokerSpecialized = 0;
+ FunctionTemplateDecl *InvokerTemplate = LambdaClass->
+ getLambdaStaticInvoker()->getDescribedFunctionTemplate();
+
+ Sema::TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result
+ = S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0,
+ InvokerSpecialized, TDInfo);
+ assert(Result == Sema::TDK_Success &&
+ "If the call operator succeeded so should the invoker!");
+ // Set the result type to match the corresponding call operator
+ // specialization's result type.
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ InvokerSpecialized->getResultType()->isUndeducedType()) {
+ // Be sure to get the type to replace 'auto' with and not
+ // the full result type of the call op specialization
+ // to substitute into the 'auto' of the invoker and conversion
+ // function.
+ // For e.g.
+ // int* (*fp)(int*) = [](auto* a) -> auto* { return a; };
+ // We don't want to subst 'int*' into 'auto' to get int**.
+
+ QualType TypeToReplaceAutoWith =
+ CallOpSpecialized->getResultType()->
+ getContainedAutoType()->getDeducedType();
+ SubstAutoWithinFunctionReturnType(InvokerSpecialized,
+ TypeToReplaceAutoWith, S);
+ SubstAutoWithinFunctionReturnType(ConversionSpecialized,
+ TypeToReplaceAutoWith, S);
+ }
+
+ // Ensure that static invoker doesn't have a const qualifier.
+ // FIXME: When creating the InvokerTemplate in SemaLambda.cpp
+ // do not use the CallOperator's TypeSourceInfo which allows
+ // the const qualifier to leak through.
+ const FunctionProtoType *InvokerFPT = InvokerSpecialized->
+ getType().getTypePtr()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
+ EPI.TypeQuals = 0;
+ InvokerSpecialized->setType(S.Context.getFunctionType(
+ InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));
+ return Sema::TDK_Success;
+}
/// \brief Deduce template arguments for a templated conversion
/// function (C++ [temp.deduct.conv]) and, if successful, produce a
/// conversion function template specialization.
Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
- if (FunctionTemplate->isInvalidDecl())
+ if (ConversionTemplate->isInvalidDecl())
return TDK_Invalid;
- CXXConversionDecl *Conv
- = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
- QualType FromType = Conv->getConversionType();
+ CXXConversionDecl *ConversionGeneric
+ = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
+
+ QualType FromType = ConversionGeneric->getConversionType();
// Canonicalize the types for deduction.
QualType P = Context.getCanonicalType(FromType);
@@ -3512,7 +3812,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// type that is required as the result of the conversion (call it
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
- = FunctionTemplate->getTemplateParameters();
+ = ConversionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
@@ -3541,13 +3841,43 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
P, A, Info, Deduced, TDF))
return Result;
- // Finish template argument deduction.
+ // Create an Instantiation Scope for finalizing the operator.
LocalInstantiationScope InstScope(*this);
- FunctionDecl *Spec = 0;
+ // Finish template argument deduction.
+ FunctionDecl *ConversionSpecialized = 0;
TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,
- Info);
- Specialization = cast_or_null<CXXConversionDecl>(Spec);
+ = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
+ ConversionSpecialized, Info);
+ Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
+
+ // If the conversion operator is being invoked on a lambda closure to convert
+ // to a ptr-to-function, use the deduced arguments from the conversion function
+ // to specialize the corresponding call operator.
+ // e.g., int (*fp)(int) = [](auto a) { return a; };
+ if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) {
+
+ // Get the return type of the destination ptr-to-function we are converting
+ // to. This is necessary for matching the lambda call operator's return
+ // type to that of the destination ptr-to-function's return type.
+ assert(A->isPointerType() &&
+ "Can only convert from lambda to ptr-to-function");
+ const FunctionType *ToFunType =
+ A->getPointeeType().getTypePtr()->getAs<FunctionType>();
+ const QualType DestFunctionPtrReturnType = ToFunType->getResultType();
+
+ // Create the corresponding specializations of the call operator and
+ // the static-invoker; and if the return type is auto,
+ // deduce the return type and check if it matches the
+ // DestFunctionPtrReturnType.
+ // For instance:
+ // auto L = [](auto a) { return f(a); };
+ // int (*fp)(int) = L;
+ // char (*fp2)(int) = L; <-- Not OK.
+
+ Result = SpecializeCorrespondingLambdaCallOperatorAndInvoker(
+ Specialization, Deduced, DestFunctionPtrReturnType,
+ Info, *this);
+ }
return Result;
}
@@ -3750,17 +4080,29 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
return DAR_Succeeded;
}
-QualType Sema::SubstAutoType(QualType Type, QualType Deduced) {
- return SubstituteAutoTransform(*this, Deduced).TransformType(Type);
+QualType Sema::SubstAutoType(QualType TypeWithAuto,
+ QualType TypeToReplaceAuto) {
+ return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+ TransformType(TypeWithAuto);
+}
+
+TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+ QualType TypeToReplaceAuto) {
+ return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+ TransformType(TypeWithAuto);
}
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
if (isa<InitListExpr>(Init))
Diag(VDecl->getLocation(),
- diag::err_auto_var_deduction_failure_from_init_list)
+ VDecl->isInitCapture()
+ ? diag::err_init_capture_deduction_failure_from_init_list
+ : diag::err_auto_var_deduction_failure_from_init_list)
<< VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
else
- Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
+ Diag(VDecl->getLocation(),
+ VDecl->isInitCapture() ? diag::err_init_capture_deduction_failure
+ : diag::err_auto_var_deduction_failure)
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
<< Init->getSourceRange();
}
@@ -3788,9 +4130,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
llvm::SmallBitVector &Deduced);
/// \brief If this is a non-static member function,
-static void AddImplicitObjectParameterType(ASTContext &Context,
- CXXMethodDecl *Method,
- SmallVectorImpl<QualType> &ArgTypes) {
+static void
+AddImplicitObjectParameterType(ASTContext &Context,
+ CXXMethodDecl *Method,
+ SmallVectorImpl<QualType> &ArgTypes) {
// C++11 [temp.func.order]p3:
// [...] The new parameter is of type "reference to cv A," where cv are
// the cv-qualifiers of the function template (if any) and A is
@@ -3815,7 +4158,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments,
+ unsigned NumCallArguments1,
SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
@@ -3831,19 +4174,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// The types used to determine the ordering depend on the context in which
// the partial ordering is done:
TemplateDeductionInfo Info(Loc);
- CXXMethodDecl *Method1 = 0;
- CXXMethodDecl *Method2 = 0;
- bool IsNonStatic2 = false;
- bool IsNonStatic1 = false;
- unsigned Skip2 = 0;
+ SmallVector<QualType, 4> Args2;
switch (TPOC) {
case TPOC_Call: {
// - In the context of a function call, the function parameter types are
// used.
- Method1 = dyn_cast<CXXMethodDecl>(FD1);
- Method2 = dyn_cast<CXXMethodDecl>(FD2);
- IsNonStatic1 = Method1 && !Method1->isStatic();
- IsNonStatic2 = Method2 && !Method2->isStatic();
+ CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
+ CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
// C++11 [temp.func.order]p3:
// [...] If only one of the function templates is a non-static
@@ -3862,26 +4199,39 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// first argument of the free function, which seems to match
// existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1;
- if (S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2)
- AddImplicitObjectParameterType(S.Context, Method1, Args1);
+
+ unsigned Skip1 = 0, Skip2 = 0;
+ unsigned NumComparedArguments = NumCallArguments1;
+
+ if (!Method2 && Method1 && !Method1->isStatic()) {
+ if (S.getLangOpts().CPlusPlus11) {
+ // Compare 'this' from Method1 against first parameter from Method2.
+ AddImplicitObjectParameterType(S.Context, Method1, Args1);
+ ++NumComparedArguments;
+ } else
+ // Ignore first parameter from Method2.
+ ++Skip2;
+ } else if (!Method1 && Method2 && !Method2->isStatic()) {
+ if (S.getLangOpts().CPlusPlus11)
+ // Compare 'this' from Method2 against first parameter from Method1.
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
+ else
+ // Ignore first parameter from Method1.
+ ++Skip1;
+ }
+
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
-
- SmallVector<QualType, 4> Args2;
- Skip2 = !S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2;
- if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1)
- AddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
// C++ [temp.func.order]p5:
// The presence of unused ellipsis and default arguments has no effect on
// the partial ordering of function templates.
- if (Args1.size() > NumCallArguments)
- Args1.resize(NumCallArguments);
- if (Args2.size() > NumCallArguments)
- Args2.resize(NumCallArguments);
+ if (Args1.size() > NumComparedArguments)
+ Args1.resize(NumComparedArguments);
+ if (Args2.size() > NumComparedArguments)
+ Args2.resize(NumComparedArguments);
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true,
@@ -3935,20 +4285,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// Figure out which template parameters were used.
llvm::SmallBitVector UsedParameters(TemplateParams->size());
switch (TPOC) {
- case TPOC_Call: {
- unsigned NumParams = std::min(NumCallArguments,
- std::min(Proto1->getNumArgs(),
- Proto2->getNumArgs()));
- if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !IsNonStatic1)
- ::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
- false,
- TemplateParams->getDepth(), UsedParameters);
- for (unsigned I = Skip2; I < NumParams; ++I)
- ::MarkUsedTemplateParameters(S.Context, Proto2->getArgType(I), false,
+ case TPOC_Call:
+ for (unsigned I = 0, N = Args2.size(); I != N; ++I)
+ ::MarkUsedTemplateParameters(S.Context, Args2[I], false,
TemplateParams->getDepth(),
UsedParameters);
break;
- }
case TPOC_Conversion:
::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
@@ -4003,8 +4345,11 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// \param TPOC the context in which we are performing partial ordering of
/// function templates.
///
-/// \param NumCallArguments The number of arguments in a call, used only
-/// when \c TPOC is \c TPOC_Call.
+/// \param NumCallArguments1 The number of arguments in the call to FT1, used
+/// only when \c TPOC is \c TPOC_Call.
+///
+/// \param NumCallArguments2 The number of arguments in the call to FT2, used
+/// only when \c TPOC is \c TPOC_Call.
///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
@@ -4013,12 +4358,13 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments) {
+ unsigned NumCallArguments1,
+ unsigned NumCallArguments2) {
SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
- NumCallArguments, 0);
+ NumCallArguments1, 0);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
- NumCallArguments,
+ NumCallArguments2,
&RefParamComparisons);
if (Better1 != Better2) // We have a clear winner
@@ -4122,12 +4468,6 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// \param SpecEnd the end iterator of the function template
/// specializations, paired with \p SpecBegin.
///
-/// \param TPOC the partial ordering context to use to compare the function
-/// template specializations.
-///
-/// \param NumCallArguments The number of arguments in a call, used only
-/// when \c TPOC is \c TPOC_Call.
-///
/// \param Loc the location where the ambiguity or no-specializations
/// diagnostic should occur.
///
@@ -4144,23 +4484,17 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
///
/// \returns the most specialized function template specialization, if
/// found. Otherwise, returns SpecEnd.
-///
-/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
-/// template argument deduction.
-UnresolvedSetIterator
-Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
- UnresolvedSetIterator SpecEnd,
- TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- bool Complain,
- QualType TargetType) {
+UnresolvedSetIterator Sema::getMostSpecialized(
+ UnresolvedSetIterator SpecBegin, UnresolvedSetIterator SpecEnd,
+ TemplateSpecCandidateSet &FailedCandidates,
+ SourceLocation Loc, const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag,
+ bool Complain, QualType TargetType) {
if (SpecBegin == SpecEnd) {
- if (Complain)
+ if (Complain) {
Diag(Loc, NoneDiag);
+ FailedCandidates.NoteCandidates(*this, Loc);
+ }
return SpecEnd;
}
@@ -4178,7 +4512,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
assert(Challenger && "Not a function template specialization?");
if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- Loc, TPOC, NumCallArguments),
+ Loc, TPOC_Other, 0, 0),
Challenger)) {
Best = I;
BestTemplate = Challenger;
@@ -4193,7 +4527,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
if (I != Best &&
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- Loc, TPOC, NumCallArguments),
+ Loc, TPOC_Other, 0, 0),
BestTemplate)) {
Ambiguous = true;
break;
@@ -4279,6 +4613,67 @@ Sema::getMoreSpecializedPartialSpecialization(
/*RefParamComparisons=*/0);
if (Better1) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
+ InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs,
+ Info);
+ Better1 = !::FinishTemplateArgumentDeduction(
+ *this, PS2, PS1->getTemplateArgs(), Deduced, Info);
+ }
+
+ // Determine whether PS2 is at least as specialized as PS1
+ Deduced.clear();
+ Deduced.resize(PS1->getTemplateParameters()->size());
+ bool Better2 = !DeduceTemplateArgumentsByTypeMatch(
+ *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ /*RefParamComparisons=*/0);
+ if (Better2) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
+ InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, DeducedArgs,
+ Info);
+ Better2 = !::FinishTemplateArgumentDeduction(
+ *this, PS1, PS2->getTemplateArgs(), Deduced, Info);
+ }
+
+ if (Better1 == Better2)
+ return 0;
+
+ return Better1 ? PS1 : PS2;
+}
+
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+VarTemplatePartialSpecializationDecl *
+Sema::getMoreSpecializedPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *PS1,
+ VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) {
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
+ TemplateDeductionInfo Info(Loc);
+
+ assert(PS1->getSpecializedTemplate() == PS1->getSpecializedTemplate() &&
+ "the partial specializations being compared should specialize"
+ " the same template.");
+ TemplateName Name(PS1->getSpecializedTemplate());
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ QualType PT1 = Context.getTemplateSpecializationType(
+ CanonTemplate, PS1->getTemplateArgs().data(),
+ PS1->getTemplateArgs().size());
+ QualType PT2 = Context.getTemplateSpecializationType(
+ CanonTemplate, PS2->getTemplateArgs().data(),
+ PS2->getTemplateArgs().size());
+
+ // Determine whether PS1 is at least as specialized as PS2
+ Deduced.resize(PS2->getTemplateParameters()->size());
+ bool Better1 = !DeduceTemplateArgumentsByTypeMatch(
+ *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ /*RefParamComparisons=*/0);
+ if (Better1) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2,
DeducedArgs, Info);
Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 7ef04e964dc6..8904f3794955 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -14,6 +14,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LangOptions.h"
@@ -61,7 +62,24 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
DeclContext *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx) {
Ctx = D->getDeclContext();
-
+
+ // Add template arguments from a variable template instantiation.
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ // We're done when we hit an explicit specialization.
+ if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(Spec))
+ return Result;
+
+ Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(Spec->getSpecializedTemplate() && "No variable template?");
+ if (Spec->getSpecializedTemplate()->isMemberSpecialization())
+ return Result;
+ }
+
// If we have a template template parameter with translation unit context,
// then we're performing substitution into a default template argument of
// this template template parameter before we've constructed the template
@@ -72,7 +90,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(D)) {
for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
- Result.addOuterTemplateArguments(0, 0);
+ Result.addOuterTemplateArguments(None);
return Result;
}
}
@@ -113,12 +131,15 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
assert(Function->getPrimaryTemplate() && "No function template?");
if (Function->getPrimaryTemplate()->isMemberSpecialization())
break;
+
+ // If this function is a generic lambda specialization, we are done.
+ if (isGenericLambdaCallOperatorSpecialization(Function))
+ break;
+
} else if (FunctionTemplateDecl *FunTmpl
= Function->getDescribedFunctionTemplate()) {
// Add the "injected" template arguments.
- std::pair<const TemplateArgument *, unsigned>
- Injected = FunTmpl->getInjectedTemplateArgs();
- Result.addOuterTemplateArguments(Injected.first, Injected.second);
+ Result.addOuterTemplateArguments(FunTmpl->getInjectedTemplateArgs());
}
// If this is a friend declaration and it declares an entity at
@@ -135,9 +156,10 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
} else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
QualType T = ClassTemplate->getInjectedClassNameSpecialization();
- const TemplateSpecializationType *TST
- = cast<TemplateSpecializationType>(Context.getCanonicalType(T));
- Result.addOuterTemplateArguments(TST->getArgs(), TST->getNumArgs());
+ const TemplateSpecializationType *TST =
+ cast<TemplateSpecializationType>(Context.getCanonicalType(T));
+ Result.addOuterTemplateArguments(
+ llvm::makeArrayRef(TST->getArgs(), TST->getNumArgs()));
if (ClassTemplate->isMemberSpecialization())
break;
}
@@ -293,6 +315,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
}
}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ VarTemplatePartialSpecializationDecl *PartialSpec,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext) {
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind =
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = PartialSpec;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.DeductionInfo = &DeductionInfo;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
+}
+
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
@@ -399,6 +444,18 @@ void Sema::InstantiatingTemplate::Clear() {
}
SemaRef.InNonInstantiationSFINAEContext
= SavedInNonInstantiationSFINAEContext;
+
+ // Name lookup no longer looks in this template's defining module.
+ assert(SemaRef.ActiveTemplateInstantiations.size() >=
+ SemaRef.ActiveTemplateInstantiationLookupModules.size() &&
+ "forgot to remove a lookup module for a template instantiation");
+ if (SemaRef.ActiveTemplateInstantiations.size() ==
+ SemaRef.ActiveTemplateInstantiationLookupModules.size()) {
+ if (Module *M = SemaRef.ActiveTemplateInstantiationLookupModules.back())
+ SemaRef.LookupModulesCache.erase(M);
+ SemaRef.ActiveTemplateInstantiationLookupModules.pop_back();
+ }
+
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
@@ -436,7 +493,7 @@ void Sema::PrintInstantiationStack() {
// FIXME: In all of these cases, we need to show the template arguments
unsigned InstantiationIdx = 0;
- for (SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
+ for (SmallVectorImpl<ActiveTemplateInstantiation>::reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
@@ -473,7 +530,9 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Diags.Report(Active->PointOfInstantiation,
- diag::note_template_static_data_member_def_here)
+ VD->isStaticDataMember()?
+ diag::note_template_static_data_member_def_here
+ : diag::note_template_variable_def_here)
<< VD
<< Active->InstantiationRange;
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
@@ -616,7 +675,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
return Optional<TemplateDeductionInfo *>(0);
- for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
+ for (SmallVectorImpl<ActiveTemplateInstantiation>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
@@ -708,9 +767,8 @@ namespace {
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
- bool &ShouldExpand,
- bool &RetainExpansion,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
+ bool &ShouldExpand, bool &RetainExpansion,
Optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
@@ -859,13 +917,38 @@ namespace {
}
ExprResult TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *CallOperator) {
- CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
- TSK_ImplicitInstantiation);
- return TreeTransform<TemplateInstantiator>::
- TransformLambdaScope(E, CallOperator);
+ CXXMethodDecl *NewCallOperator,
+ ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
+ CXXMethodDecl *const OldCallOperator = E->getCallOperator();
+ // In the generic lambda case, we set the NewTemplate to be considered
+ // an "instantiation" of the OldTemplate.
+ if (FunctionTemplateDecl *const NewCallOperatorTemplate =
+ NewCallOperator->getDescribedFunctionTemplate()) {
+
+ FunctionTemplateDecl *const OldCallOperatorTemplate =
+ OldCallOperator->getDescribedFunctionTemplate();
+ NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
+ OldCallOperatorTemplate);
+ // Mark the NewCallOperatorTemplate a specialization.
+ NewCallOperatorTemplate->setMemberSpecialization();
+ } else
+ // For a non-generic lambda we set the NewCallOperator to
+ // be an instantiation of the OldCallOperator.
+ NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
+ TSK_ImplicitInstantiation);
+
+ return inherited::TransformLambdaScope(E, NewCallOperator,
+ InitCaptureExprsAndTypes);
+ }
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *OrigTPL) {
+ if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+
+ DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+ TemplateDeclInstantiator DeclInstantiator(getSema(),
+ /* DeclContext *Owner */ Owner, TemplateArgs);
+ return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
-
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
@@ -884,6 +967,16 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) {
return true;
}
+static TemplateArgument
+getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
+ assert(S.ArgumentPackSubstitutionIndex >= 0);
+ assert(S.ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
+ Arg = Arg.pack_begin()[S.ArgumentPackSubstitutionIndex];
+ if (Arg.isPackExpansion())
+ Arg = Arg.getPackExpansionPattern();
+ return Arg;
+}
+
Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!D)
return 0;
@@ -903,10 +996,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (TTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
-
- assert(getSema().ArgumentPackSubstitutionIndex >= 0);
- assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
- Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
TemplateName Template = Arg.getAsTemplate();
@@ -951,8 +1041,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
if (getSema().ArgumentPackSubstitutionIndex == -1)
return 0;
- assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
- Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
QualType T = Arg.getAsType();
@@ -1054,9 +1143,8 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
// keep the entire argument pack.
return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg);
}
-
- assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
- Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
TemplateName Template = Arg.getAsTemplate();
@@ -1078,11 +1166,9 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
if (getSema().ArgumentPackSubstitutionIndex == -1)
return Name;
- const TemplateArgument &ArgPack = SubstPack->getArgumentPack();
- assert(getSema().ArgumentPackSubstitutionIndex < (int)ArgPack.pack_size() &&
- "Pack substitution index out-of-range");
- return ArgPack.pack_begin()[getSema().ArgumentPackSubstitutionIndex]
- .getAsTemplate();
+ TemplateArgument Arg = SubstPack->getArgumentPack();
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ return Arg.getAsTemplate();
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -1094,25 +1180,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
return SemaRef.Owned(E);
- FunctionDecl *currentDecl = getSema().getCurFunctionDecl();
- assert(currentDecl && "Must have current function declaration when "
- "instantiating.");
-
- PredefinedExpr::IdentType IT = E->getIdentType();
-
- unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
-
- llvm::APInt LengthI(32, Length + 1);
- QualType ResTy;
- if (IT == PredefinedExpr::LFunction)
- ResTy = getSema().Context.WCharTy.withConst();
- else
- ResTy = getSema().Context.CharTy.withConst();
- ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI,
- ArrayType::Normal, 0);
- PredefinedExpr *PE =
- new (getSema().Context) PredefinedExpr(E->getLocation(), ResTy, IT);
- return getSema().Owned(PE);
+ return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentType());
}
ExprResult
@@ -1147,8 +1215,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg);
}
- assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
- Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
@@ -1161,14 +1228,6 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
ExprResult result;
QualType type;
- // If the argument is a pack expansion, the parameter must actually be a
- // parameter pack, and we should substitute the pattern itself, producing
- // an expression which contains an unexpanded parameter pack.
- if (arg.isPackExpansion()) {
- assert(parm->isParameterPack() && "pack expansion for non-pack");
- arg = arg.getPackExpansionPattern();
- }
-
// The template argument itself might be an expression, in which
// case we just return that expression.
if (arg.getKind() == TemplateArgument::Expression) {
@@ -1234,12 +1293,9 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
// We aren't expanding the parameter pack, so just return ourselves.
return getSema().Owned(E);
}
-
- const TemplateArgument &ArgPack = E->getArgumentPack();
- unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex;
- assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
-
- const TemplateArgument &Arg = ArgPack.pack_begin()[Index];
+
+ TemplateArgument Arg = E->getArgumentPack();
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
return transformNonTypeTemplateParmRef(E->getParameterPack(),
E->getParameterPackLocation(),
Arg);
@@ -1410,8 +1466,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
- assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
- Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
assert(Arg.getKind() == TemplateArgument::Type &&
@@ -1459,12 +1514,11 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
NewTL.setNameLoc(TL.getNameLoc());
return TL.getType();
}
-
- const TemplateArgument &ArgPack = TL.getTypePtr()->getArgumentPack();
- unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex;
- assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
-
- QualType Result = ArgPack.pack_begin()[Index].getAsType();
+
+ TemplateArgument Arg = TL.getTypePtr()->getArgumentPack();
+ Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ QualType Result = Arg.getAsType();
+
Result = getSema().Context.getSubstTemplateTypeParmType(
TL.getTypePtr()->getReplacedParameter(),
Result);
@@ -1577,6 +1631,9 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
ParmVarDecl *P = FP.getArg(I);
+ // This must be synthesized from a typedef.
+ if (!P) continue;
+
// The parameter's type as written might be dependent even if the
// decayed type was not dependent.
if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
@@ -1755,6 +1812,10 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
Base != BaseEnd; ++Base) {
if (!Base->getType()->isDependentType()) {
+ if (const CXXRecordDecl *RD = Base->getType()->getAsCXXRecordDecl()) {
+ if (RD->isInvalidDecl())
+ Instantiation->setInvalidDecl();
+ }
InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base));
continue;
}
@@ -1949,7 +2010,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
- if (Inst)
+ if (Inst.isInvalid())
return true;
// Enter the scope of this instantiation. We don't use
@@ -2081,6 +2142,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
E = LateAttrs.end(); I != E; ++I) {
assert(CurrentInstantiationScope == Instantiator.getStartingScope());
CurrentInstantiationScope = I->Scope;
+
+ // Allow 'this' within late-parsed attributes.
+ NamedDecl *ND = dyn_cast<NamedDecl>(I->NewDecl);
+ CXXRecordDecl *ThisContext =
+ dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+ CXXThisScopeRAII ThisScope(*this, ThisContext, /*TypeQuals*/0,
+ ND && ND->isCXXInstanceMember());
+
Attr *NewAttr =
instantiateTemplateAttribute(I->TmplAttr, Context, *this, TemplateArgs);
I->NewDecl->addAttr(NewAttr);
@@ -2104,13 +2173,25 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Instantiate any out-of-line class template partial
// specializations now.
- for (TemplateDeclInstantiator::delayed_partial_spec_iterator
+ for (TemplateDeclInstantiator::delayed_partial_spec_iterator
P = Instantiator.delayed_partial_spec_begin(),
PEnd = Instantiator.delayed_partial_spec_end();
P != PEnd; ++P) {
if (!Instantiator.InstantiateClassTemplatePartialSpecialization(
- P->first,
- P->second)) {
+ P->first, P->second)) {
+ Instantiation->setInvalidDecl();
+ break;
+ }
+ }
+
+ // Instantiate any out-of-line variable template partial
+ // specializations now.
+ for (TemplateDeclInstantiator::delayed_var_partial_spec_iterator
+ P = Instantiator.delayed_var_partial_spec_begin(),
+ PEnd = Instantiator.delayed_var_partial_spec_end();
+ P != PEnd; ++P) {
+ if (!Instantiator.InstantiateVarTemplatePartialSpecialization(
+ P->first, P->second)) {
Instantiation->setInvalidDecl();
break;
}
@@ -2166,7 +2247,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
- if (Inst)
+ if (Inst.isInvalid())
return true;
// Enter the scope of this instantiation. We don't use
@@ -2198,12 +2279,10 @@ namespace {
};
}
-bool
-Sema::InstantiateClassTemplateSpecialization(
- SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec,
- TemplateSpecializationKind TSK,
- bool Complain) {
+bool Sema::InstantiateClassTemplateSpecialization(
+ SourceLocation PointOfInstantiation,
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK, bool Complain) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
@@ -2252,15 +2331,18 @@ Sema::InstantiateClassTemplateSpecialization(
SmallVector<MatchResult, 4> Matched;
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
+ TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
- TemplateDeductionInfo Info(PointOfInstantiation);
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(Partial,
ClassTemplateSpec->getTemplateArgs(),
Info)) {
- // FIXME: Store the failed-deduction information for use in
- // diagnostics, later.
+ // Store the failed-deduction information for use in diagnostics, later.
+ // TODO: Actually use the failed-deduction info?
+ FailedCandidates.addCandidate()
+ .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
@@ -2275,7 +2357,7 @@ Sema::InstantiateClassTemplateSpecialization(
SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
if (Matched.size() >= 1) {
- SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ SmallVectorImpl<MatchResult>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
@@ -2288,8 +2370,8 @@ Sema::InstantiateClassTemplateSpecialization(
// specialized than all of the other matching
// specializations, then the use of the class template is
// ambiguous and the program is ill-formed.
- for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
- PEnd = Matched.end();
+ for (SmallVectorImpl<MatchResult>::iterator P = Best + 1,
+ PEnd = Matched.end();
P != PEnd; ++P) {
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
PointOfInstantiation)
@@ -2300,8 +2382,8 @@ Sema::InstantiateClassTemplateSpecialization(
// Determine if the best partial specialization is more specialized than
// the others.
bool Ambiguous = false;
- for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
- PEnd = Matched.end();
+ for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best &&
getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
@@ -2319,8 +2401,8 @@ Sema::InstantiateClassTemplateSpecialization(
<< ClassTemplateSpec;
// Print the matching partial specializations.
- for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
- PEnd = Matched.end();
+ for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
P != PEnd; ++P)
Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
<< getTemplateArgumentBindingsText(
@@ -2377,6 +2459,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
+ assert(
+ (TSK == TSK_ExplicitInstantiationDefinition ||
+ TSK == TSK_ExplicitInstantiationDeclaration ||
+ (TSK == TSK_ImplicitInstantiation && Instantiation->isLocalClass())) &&
+ "Unexpected template specialization kind!");
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
@@ -2417,9 +2504,15 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else {
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ if (TSK == TSK_ImplicitInstantiation)
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
}
}
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
+ if (isa<VarTemplateSpecializationDecl>(Var))
+ continue;
+
if (Var->isStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
@@ -2689,6 +2782,12 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
break;
}
+ // If we're performing a partial substitution during template argument
+ // deduction, we may not have values for template parameters yet.
+ if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
+ isa<TemplateTemplateParmDecl>(D))
+ return 0;
+
// If we didn't find the decl, then we either have a sema bug, or we have a
// forward reference to a label declaration. Return null to indicate that
// we have an uninstantiated label.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d1428c51a4f9..5c28e3b7a828 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -25,6 +25,17 @@
using namespace clang;
+static bool isDeclWithinFunction(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ if (DC->isFunctionOrMethod())
+ return true;
+
+ if (DC->isRecord())
+ return cast<CXXRecordDecl>(DC)->isLocalClass();
+
+ return false;
+}
+
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) {
if (!OldDecl->getQualifierLoc())
@@ -142,6 +153,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
Saved = CurrentInstantiationScope->cloneScopes(OuterMostScope);
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
} else {
+ // Allow 'this' within late-parsed attributes.
+ NamedDecl *ND = dyn_cast<NamedDecl>(New);
+ CXXRecordDecl *ThisContext =
+ dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+ CXXThisScopeRAII ThisScope(*this, ThisContext, /*TypeQuals*/0,
+ ND && ND->isCXXInstanceMember());
+
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
if (NewAttr)
@@ -247,7 +265,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
// If the typedef types are not identical, reject them.
SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef);
- Typedef->setPreviousDeclaration(InstPrevTypedef);
+ Typedef->setPreviousDecl(InstPrevTypedef);
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
@@ -299,7 +317,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
= TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDeclName(), InstParams, AliasInst);
if (PrevAliasTemplate)
- Inst->setPreviousDeclaration(PrevAliasTemplate);
+ Inst->setPreviousDecl(PrevAliasTemplate);
Inst->setAccess(D->getAccess());
@@ -312,6 +330,12 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+ return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
+}
+
+Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
+ bool InstantiatingVarTemplate) {
+
// If this is the variable for an anonymous struct or union,
// instantiate the anonymous struct/union type first.
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
@@ -333,105 +357,26 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
return 0;
}
- // Build the instantiated declaration
- VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
- D->getLocation(), D->getIdentifier(),
- DI->getType(), DI,
- D->getStorageClass());
- Var->setTSCSpec(D->getTSCSpec());
- Var->setInitStyle(D->getInitStyle());
- Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
- Var->setConstexpr(D->isConstexpr());
-
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Var))
- return 0;
-
- // If we are instantiating a static data member defined
- // out-of-line, the instantiation will have the same lexical
- // context (which will be a namespace scope) as the template.
- if (D->isOutOfLine())
- Var->setLexicalDeclContext(D->getLexicalDeclContext());
-
- Var->setAccess(D->getAccess());
-
- if (!D->isStaticDataMember()) {
- Var->setUsed(D->isUsed(false));
- Var->setReferenced(D->isReferenced());
- }
-
- SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
+ DeclContext *DC = Owner;
+ if (D->isLocalExternDecl())
+ SemaRef.adjustContextForLocalExternDecl(DC);
- if (Var->hasAttrs())
- SemaRef.CheckAlignasUnderalignment(Var);
+ // Build the instantiated declaration.
+ VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
+ D->getLocation(), D->getIdentifier(),
+ DI->getType(), DI, D->getStorageClass());
- // FIXME: In theory, we could have a previous declaration for variables that
- // are not static data members.
- // FIXME: having to fake up a LookupResult is dumb.
- LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (D->isStaticDataMember())
- SemaRef.LookupQualifiedName(Previous, Owner, false);
-
// In ARC, infer 'retaining' for variables of retainable type.
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
SemaRef.inferObjCARCLifetime(Var))
Var->setInvalidDecl();
- SemaRef.CheckVariableDeclaration(Var, Previous);
-
- if (D->isOutOfLine()) {
- D->getLexicalDeclContext()->addDecl(Var);
- Owner->makeDeclVisibleInContext(Var);
- } else {
- Owner->addDecl(Var);
- if (Owner->isFunctionOrMethod())
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
- }
-
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Var->isStaticDataMember())
- SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
- TSK_ImplicitInstantiation);
-
- if (Var->getAnyInitializer()) {
- // We already have an initializer in the class.
- } else if (D->getInit()) {
- if (Var->isStaticDataMember() && !D->isOutOfLine())
- SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated, D);
- else
- SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, D);
-
- // Instantiate the initializer.
- ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs,
- D->getInitStyle() == VarDecl::CallInit);
- if (!Init.isInvalid()) {
- bool TypeMayContainAuto = true;
- if (Init.get()) {
- bool DirectInit = D->isDirectInit();
- SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit,
- TypeMayContainAuto);
- } else
- SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
- } else {
- // FIXME: Not too happy about invalidating the declaration
- // because of a bogus initializer.
- Var->setInvalidDecl();
- }
-
- SemaRef.PopExpressionEvaluationContext();
- } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
- !Var->isCXXForRangeDecl())
- SemaRef.ActOnUninitializedDecl(Var, false);
-
- // Diagnose unused local variables with dependent types, where the diagnostic
- // will have been deferred.
- if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() &&
- D->getType()->isDependentType())
- SemaRef.DiagnoseUnusedDecl(Var);
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Var))
+ return 0;
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
+ StartingScope, InstantiatingVarTemplate);
return Var;
}
@@ -723,19 +668,17 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
}
}
- if (D->getDeclContext()->isFunctionOrMethod())
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
-
// C++11 [temp.inst]p1: The implicit instantiation of a class template
// specialization causes the implicit instantiation of the declarations, but
// not the definitions of scoped member enumerations.
- // FIXME: There appears to be no wording for what happens for an enum defined
- // within a block scope, but we treat that much like a member template. Only
- // instantiate the definition when visiting the definition in that case, since
- // we will visit all redeclarations.
- if (!Enum->isScoped() && Def &&
- (!D->getDeclContext()->isFunctionOrMethod() || D->isCompleteDefinition()))
+ //
+ // DR1484 clarifies that enumeration definitions inside of a template
+ // declaration aren't considered entities that can be separately instantiated
+ // from the rest of the entity they are declared inside of.
+ if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) {
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
InstantiateEnumDefinition(Enum, Def);
+ }
return Enum;
}
@@ -953,7 +896,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
else
Inst->setAccess(D->getAccess());
- Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
+ Inst->setObjectOfFriendDecl();
// TODO: do we want to track the instantiation progeny of this
// friend target decl?
} else {
@@ -988,7 +931,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
- if (PartialSpecs[I]->isOutOfLine())
+ if (PartialSpecs[I]->getFirstDecl()->isOutOfLine())
OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I]));
}
@@ -1019,6 +962,85 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D);
}
+Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ assert(D->getTemplatedDecl()->isStaticDataMember() &&
+ "Only static data member templates are allowed.");
+
+ // Create a local instantiation scope for this variable template, which
+ // will contain the instantiations of the template parameters.
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ VarDecl *Pattern = D->getTemplatedDecl();
+ VarTemplateDecl *PrevVarTemplate = 0;
+
+ if (Pattern->getPreviousDecl()) {
+ DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
+ if (!Found.empty())
+ PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
+ }
+
+ VarDecl *VarInst =
+ cast_or_null<VarDecl>(VisitVarDecl(Pattern,
+ /*InstantiatingVarTemplate=*/true));
+
+ DeclContext *DC = Owner;
+
+ VarTemplateDecl *Inst = VarTemplateDecl::Create(
+ SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams,
+ VarInst, PrevVarTemplate);
+ VarInst->setDescribedVarTemplate(Inst);
+
+ Inst->setAccess(D->getAccess());
+ if (!PrevVarTemplate)
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ if (D->isOutOfLine()) {
+ Inst->setLexicalDeclContext(D->getLexicalDeclContext());
+ VarInst->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
+ Owner->addDecl(Inst);
+
+ if (!PrevVarTemplate) {
+ // Queue up any out-of-line partial specializations of this member
+ // variable template; the client will force their instantiation once
+ // the enclosing class has been instantiated.
+ SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ D->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
+ if (PartialSpecs[I]->getFirstDecl()->isOutOfLine())
+ OutOfLineVarPartialSpecs.push_back(
+ std::make_pair(Inst, PartialSpecs[I]));
+ }
+
+ return Inst;
+}
+
+Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ assert(D->isStaticDataMember() &&
+ "Only static data member templates are allowed.");
+
+ VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
+
+ // Lookup the already-instantiated declaration and return that.
+ DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName());
+ assert(!Found.empty() && "Instantiation found nothing?");
+
+ VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
+ assert(InstVarTemplate && "Instantiation did not find a variable template?");
+
+ if (VarTemplatePartialSpecializationDecl *Result =
+ InstVarTemplate->findPartialSpecInstantiatedFromMember(D))
+ return Result;
+
+ return InstantiateVarTemplatePartialSpecialization(InstVarTemplate, D);
+}
+
Decl *
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// Create a local instantiation scope for this function template, which
@@ -1103,17 +1125,30 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// If the original function was part of a friend declaration,
// inherit its namespace state.
- if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
- Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+ if (D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl();
// Make sure that anonymous structs and unions are recorded.
- if (D->isAnonymousStructOrUnion()) {
+ if (D->isAnonymousStructOrUnion())
Record->setAnonymousStructOrUnion(true);
- if (Record->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
- }
+
+ if (D->isLocalClass())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
Owner->addDecl(Record);
+
+ // 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()) {
+ if (SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
+ TSK_ImplicitInstantiation,
+ /*Complain=*/true)) {
+ llvm_unreachable("InstantiateClass shouldn't fail here!");
+ } else {
+ SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+ TSK_ImplicitInstantiation);
+ }
+ }
return Record;
}
@@ -1136,9 +1171,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
return Context.getFunctionType(NewFunc->getResultType(),
- ArrayRef<QualType>(NewFunc->arg_type_begin(),
- NewFunc->getNumArgs()),
- NewEPI);
+ NewFunc->getArgTypes(), NewEPI);
}
/// Normal class members are of more specific types and therefore
@@ -1191,11 +1224,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
// If we're instantiating a local function declaration, put the result
- // in the owner; otherwise we need to find the instantiated context.
+ // in the enclosing namespace; otherwise we need to find the instantiated
+ // context.
DeclContext *DC;
- if (D->getDeclContext()->isFunctionOrMethod())
+ if (D->isLocalExternDecl()) {
DC = Owner;
- else if (isFriend && QualifierLoc) {
+ SemaRef.adjustContextForLocalExternDecl(DC);
+ } else if (isFriend && QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
@@ -1211,6 +1246,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getCanonicalDecl()->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
D->isConstexpr());
+ Function->setRangeEnd(D->getSourceRange().getEnd());
if (D->isInlined())
Function->setImplicitlyInline();
@@ -1218,8 +1254,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
+ if (D->isLocalExternDecl())
+ Function->setLocalExternDecl();
+
DeclContext *LexicalDC = Owner;
- if (!isFriend && D->isOutOfLine()) {
+ if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) {
assert(D->getDeclContext()->isFileContext());
LexicalDC = D->getDeclContext();
}
@@ -1227,26 +1266,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
- if (isa<FunctionProtoType>(Function->getType().IgnoreParens())) {
- // Adopt the already-instantiated parameters into our own context.
- for (unsigned P = 0; P < Params.size(); ++P)
- if (Params[P])
- Params[P]->setOwningFunction(Function);
- } else {
- // Since we were instantiated via a typedef of a function type, create
- // new parameters.
- const FunctionProtoType *Proto
- = Function->getType()->getAs<FunctionProtoType>();
- assert(Proto && "No function prototype in template instantiation?");
- for (FunctionProtoType::arg_type_iterator AI = Proto->arg_type_begin(),
- AE = Proto->arg_type_end(); AI != AE; ++AI) {
- ParmVarDecl *Param
- = SemaRef.BuildParmVarDeclForTypedef(Function, Function->getLocation(),
- *AI);
- Param->setScopeInfo(0, Params.size());
- Params.push_back(Param);
- }
- }
+ for (unsigned P = 0; P < Params.size(); ++P)
+ if (Params[P])
+ Params[P]->setOwningFunction(Function);
Function->setParams(Params);
SourceLocation InstantiateAtPOI;
@@ -1302,15 +1324,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
bool isExplicitSpecialization = false;
- LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ LookupResult Previous(
+ SemaRef, Function->getDeclName(), SourceLocation(),
+ D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
assert(isFriend && "non-friend has dependent specialization info?");
// This needs to be set now for future sanity.
- Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+ Function->setObjectOfFriendDecl();
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
@@ -1360,13 +1385,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
if (isFriend) {
- NamedDecl *PrevDecl;
- if (TemplateParams)
- PrevDecl = FunctionTemplate->getPreviousDecl();
- else
- PrevDecl = Function->getPreviousDecl();
-
- PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
+ PrincipalDecl->setObjectOfFriendDecl();
DC->makeDeclVisibleInContext(PrincipalDecl);
bool queuedInstantiation = false;
@@ -1441,6 +1460,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
+ if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
+ DC->makeDeclVisibleInContext(PrincipalDecl);
+
if (Function->isOverloadedOperator() && !DC->isRecord() &&
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
@@ -1502,24 +1524,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return 0;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
- // \brief If the type of this function, after ignoring parentheses,
- // is not *directly* a function type, then we're instantiating a function
- // that was declared via a typedef, e.g.,
- //
- // typedef int functype(int, int);
- // functype func;
- //
- // In this case, we'll just go instantiate the ParmVarDecls that we
- // synthesized in the method declaration.
- if (!isa<FunctionProtoType>(T.IgnoreParens())) {
- assert(!Params.size() && "Instantiating type could not yield parameters");
- SmallVector<QualType, 4> ParamTypes;
- if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
- D->getNumParams(), TemplateArgs, ParamTypes,
- &Params))
- return 0;
- }
-
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -1572,7 +1576,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
"inheriting constructor template in dependent context?");
Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(),
Inh);
- if (Inst)
+ if (Inst.isInvalid())
return 0;
Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext());
LocalInstantiationScope LocalScope(SemaRef);
@@ -1634,7 +1638,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParams, Method);
if (isFriend) {
FunctionTemplate->setLexicalDeclContext(Owner);
- FunctionTemplate->setObjectOfFriendDecl(true);
+ FunctionTemplate->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
@@ -1661,7 +1665,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TempParamLists.data());
Method->setLexicalDeclContext(Owner);
- Method->setObjectOfFriendDecl(true);
+ Method->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
@@ -1750,7 +1754,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
return VisitCXXMethodDecl(D);
}
-ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
+Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None,
/*ExpectParameterPack=*/ false);
}
@@ -1769,8 +1773,13 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->isParameterPack());
Inst->setAccess(AS_public);
- if (D->hasDefaultArgument())
- Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
+ if (D->hasDefaultArgument()) {
+ TypeSourceInfo *InstantiatedDefaultArg =
+ SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs,
+ D->getDefaultArgumentLoc(), D->getDeclName());
+ if (InstantiatedDefaultArg)
+ Inst->setDefaultArgument(InstantiatedDefaultArg, false);
+ }
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -1920,7 +1929,11 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
if (Invalid)
Param->setInvalidDecl();
- Param->setDefaultArgument(D->getDefaultArgument(), false);
+ if (D->hasDefaultArgument()) {
+ ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs);
+ if (!Value.isInvalid())
+ Param->setDefaultArgument(Value.get(), false);
+ }
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -2043,7 +2056,21 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
D->getPosition(),
D->isParameterPack(),
D->getIdentifier(), InstParams);
- Param->setDefaultArgument(D->getDefaultArgument(), false);
+ if (D->hasDefaultArgument()) {
+ NestedNameSpecifierLoc QualifierLoc =
+ D->getDefaultArgument().getTemplateQualifierLoc();
+ QualifierLoc =
+ SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
+ TemplateName TName = SemaRef.SubstTemplateName(
+ QualifierLoc, D->getDefaultArgument().getArgument().getAsTemplate(),
+ D->getDefaultArgument().getTemplateNameLoc(), TemplateArgs);
+ if (!TName.isNull())
+ Param->setDefaultArgument(
+ TemplateArgumentLoc(TemplateArgument(TName),
+ D->getDefaultArgument().getTemplateQualifierLoc(),
+ D->getDefaultArgument().getTemplateNameLoc()),
+ false);
+ }
Param->setAccess(AS_public);
// Introduce this template parameter's instantiation into the instantiation
@@ -2102,10 +2129,10 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
Sema::ForRedeclaration);
UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
- D->getUsingLocation(),
+ D->getUsingLoc(),
QualifierLoc,
NameInfo,
- D->isTypeName());
+ D->hasTypename());
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -2114,15 +2141,15 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
SemaRef.LookupQualifiedName(Prev, Owner);
// Check for invalid redeclarations.
- if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLocation(),
- D->isTypeName(), SS,
+ if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLoc(),
+ D->hasTypename(), SS,
D->getLocation(), Prev))
NewUD->setInvalidDecl();
}
if (!NewUD->isInvalidDecl() &&
- SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS,
+ SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS,
D->getLocation()))
NewUD->setInvalidDecl();
@@ -2147,19 +2174,22 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
I != E; ++I) {
UsingShadowDecl *Shadow = *I;
NamedDecl *InstTarget =
- cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
- Shadow->getLocation(),
- Shadow->getTargetDecl(),
- TemplateArgs));
+ cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
+ Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs));
if (!InstTarget)
return 0;
- if (CheckRedeclaration &&
- SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev))
- continue;
+ UsingShadowDecl *PrevDecl = 0;
+ if (CheckRedeclaration) {
+ if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl))
+ continue;
+ } else if (UsingShadowDecl *OldPrev = Shadow->getPreviousDecl()) {
+ PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl(
+ Shadow->getLocation(), OldPrev, TemplateArgs));
+ }
- UsingShadowDecl *InstShadow
- = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget);
+ UsingShadowDecl *InstShadow =
+ SemaRef.BuildUsingShadowDecl(/*Scope*/0, NewUD, InstTarget, PrevDecl);
SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow);
if (isFunctionScope)
@@ -2257,13 +2287,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
- SmallVector<DeclRefExpr *, 5> Vars;
- for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(),
- E = D->varlist_end();
+ SmallVector<Expr *, 5> Vars;
+ for (ArrayRef<Expr *>::iterator I = D->varlist_begin(),
+ E = D->varlist_end();
I != E; ++I) {
Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
- Vars.push_back(cast<DeclRefExpr>(Var));
+ Vars.push_back(Var);
}
OMPThreadPrivateDecl *TD =
@@ -2272,6 +2302,262 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
return TD;
}
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+ return VisitFunctionDecl(D, 0);
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ return VisitCXXMethodDecl(D, 0);
+}
+
+Decl *TemplateDeclInstantiator::VisitRecordDecl(RecordDecl *D) {
+ llvm_unreachable("There are only CXXRecordDecls in C++");
+}
+
+Decl *
+TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ // As a MS extension, we permit class-scope explicit specialization
+ // of member class templates.
+ ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
+ assert(ClassTemplate->getDeclContext()->isRecord() &&
+ D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ "can only instantiate an explicit specialization "
+ "for a member class template");
+
+ // Lookup the already-instantiated declaration in the instantiation
+ // of the class template. FIXME: Diagnose or assert if this fails?
+ DeclContext::lookup_result Found
+ = Owner->lookup(ClassTemplate->getDeclName());
+ if (Found.empty())
+ return 0;
+ ClassTemplateDecl *InstClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Found.front());
+ if (!InstClassTemplate)
+ return 0;
+
+ // Substitute into the template arguments of the class template explicit
+ // specialization.
+ TemplateSpecializationTypeLoc Loc = D->getTypeAsWritten()->getTypeLoc().
+ castAs<TemplateSpecializationTypeLoc>();
+ TemplateArgumentListInfo InstTemplateArgs(Loc.getLAngleLoc(),
+ Loc.getRAngleLoc());
+ SmallVector<TemplateArgumentLoc, 4> ArgLocs;
+ for (unsigned I = 0; I != Loc.getNumArgs(); ++I)
+ ArgLocs.push_back(Loc.getArgLoc(I));
+ if (SemaRef.Subst(ArgLocs.data(), ArgLocs.size(),
+ InstTemplateArgs, TemplateArgs))
+ return 0;
+
+ // Check that the template argument list is well-formed for this
+ // class template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (SemaRef.CheckTemplateArgumentList(InstClassTemplate,
+ D->getLocation(),
+ InstTemplateArgs,
+ false,
+ Converted))
+ return 0;
+
+ // Figure out where to insert this class template explicit specialization
+ // in the member template's set of class template explicit specializations.
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *PrevDecl =
+ InstClassTemplate->findSpecialization(Converted.data(), Converted.size(),
+ InsertPos);
+
+ // Check whether we've already seen a conflicting instantiation of this
+ // declaration (for instance, if there was a prior implicit instantiation).
+ bool Ignored;
+ if (PrevDecl &&
+ SemaRef.CheckSpecializationInstantiationRedecl(D->getLocation(),
+ D->getSpecializationKind(),
+ PrevDecl,
+ PrevDecl->getSpecializationKind(),
+ PrevDecl->getPointOfInstantiation(),
+ Ignored))
+ return 0;
+
+ // If PrevDecl was a definition and D is also a definition, diagnose.
+ // This happens in cases like:
+ //
+ // template<typename T, typename U>
+ // struct Outer {
+ // template<typename X> struct Inner;
+ // template<> struct Inner<T> {};
+ // template<> struct Inner<U> {};
+ // };
+ //
+ // Outer<int, int> outer; // error: the explicit specializations of Inner
+ // // have the same signature.
+ if (PrevDecl && PrevDecl->getDefinition() &&
+ D->isThisDeclarationADefinition()) {
+ SemaRef.Diag(D->getLocation(), diag::err_redefinition) << PrevDecl;
+ SemaRef.Diag(PrevDecl->getDefinition()->getLocation(),
+ diag::note_previous_definition);
+ return 0;
+ }
+
+ // Create the class template partial specialization declaration.
+ ClassTemplateSpecializationDecl *InstD
+ = ClassTemplateSpecializationDecl::Create(SemaRef.Context,
+ D->getTagKind(),
+ Owner,
+ D->getLocStart(),
+ D->getLocation(),
+ InstClassTemplate,
+ Converted.data(),
+ Converted.size(),
+ PrevDecl);
+
+ // Add this partial specialization to the set of class template partial
+ // specializations.
+ if (!PrevDecl)
+ InstClassTemplate->AddSpecialization(InstD, InsertPos);
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, InstD))
+ return 0;
+
+ // Build the canonical type that describes the converted template
+ // arguments of the class template explicit specialization.
+ QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(InstClassTemplate), Converted.data(), Converted.size(),
+ SemaRef.Context.getRecordType(InstD));
+
+ // Build the fully-sugared type for this class template
+ // specialization as the user wrote in the specialization
+ // itself. This means that we'll pretty-print the type retrieved
+ // from the specialization's declaration the way that the user
+ // actually wrote the specialization, rather than formatting the
+ // name based on the "canonical" representation used to store the
+ // template arguments in the specialization.
+ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
+ TemplateName(InstClassTemplate), D->getLocation(), InstTemplateArgs,
+ CanonType);
+
+ InstD->setAccess(D->getAccess());
+ InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
+ InstD->setSpecializationKind(D->getSpecializationKind());
+ InstD->setTypeAsWritten(WrittenTy);
+ InstD->setExternLoc(D->getExternLoc());
+ InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
+
+ Owner->addDecl(InstD);
+
+ // Instantiate the members of the class-scope explicit specialization eagerly.
+ // We don't have support for lazy instantiation of an explicit specialization
+ // yet, and MSVC eagerly instantiates in this case.
+ if (D->isThisDeclarationADefinition() &&
+ SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
+ TSK_ImplicitInstantiation,
+ /*Complain=*/true))
+ return 0;
+
+ return InstD;
+}
+
+Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+
+ TemplateArgumentListInfo VarTemplateArgsInfo;
+ VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
+ assert(VarTemplate &&
+ "A template specialization without specialized template?");
+
+ // Substitute the current template arguments.
+ const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
+ VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
+ VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc());
+
+ if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(),
+ TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs))
+ return 0;
+
+ // Check that the template argument list is well-formed for this template.
+ SmallVector<TemplateArgument, 4> Converted;
+ bool ExpansionIntoFixedList = false;
+ if (SemaRef.CheckTemplateArgumentList(
+ VarTemplate, VarTemplate->getLocStart(),
+ const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
+ Converted, &ExpansionIntoFixedList))
+ return 0;
+
+ // Find the variable template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = 0;
+ if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
+ Converted.data(), Converted.size(), InsertPos))
+ // If we already have a variable template specialization, return it.
+ return VarSpec;
+
+ return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
+ VarTemplateArgsInfo, Converted);
+}
+
+Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
+ VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ llvm::ArrayRef<TemplateArgument> Converted) {
+
+ // If this is the variable for an anonymous struct or union,
+ // instantiate the anonymous struct/union type first.
+ if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
+ if (RecordTy->getDecl()->isAnonymousStructOrUnion())
+ if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
+ return 0;
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI =
+ SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
+ D->getTypeSpecStartLoc(), D->getDeclName());
+ if (!DI)
+ return 0;
+
+ if (DI->getType()->isFunctionType()) {
+ SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
+ << D->isStaticDataMember() << DI->getType();
+ return 0;
+ }
+
+ // Build the instantiated declaration
+ VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
+ Converted.size());
+ Var->setTemplateArgsInfo(TemplateArgsInfo);
+ if (InsertPos)
+ VarTemplate->AddSpecialization(Var, InsertPos);
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Var))
+ return 0;
+
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
+ Owner, StartingScope);
+
+ return Var;
+}
+
+Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
+ llvm_unreachable("@defs is not supported in Objective-C++");
+}
+
+Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ // FIXME: We need to be able to instantiate FriendTemplateDecls.
+ unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot instantiate %0 yet");
+ SemaRef.Diag(D->getLocation(), DiagID)
+ << D->getDeclKindName();
+
+ return 0;
+}
+
+Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
+ llvm_unreachable("Unexpected decl");
+}
+
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
@@ -2343,9 +2629,12 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Substitute into the template arguments of the class template partial
// specialization.
- TemplateArgumentListInfo InstTemplateArgs; // no angle locations
- if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(),
- PartialSpec->getNumTemplateArgsAsWritten(),
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = PartialSpec->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc,
+ TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
InstTemplateArgs, TemplateArgs))
return 0;
@@ -2424,8 +2713,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
Converted.size(),
InstTemplateArgs,
CanonType,
- 0,
- ClassTemplate->getNextPartialSpecSequenceNumber());
+ 0);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return 0;
@@ -2439,6 +2727,137 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return InstPartialSpec;
}
+/// \brief Instantiate the declaration of a variable template partial
+/// specialization.
+///
+/// \param VarTemplate the (instantiated) variable template that is partially
+/// specialized by the instantiation of \p PartialSpec.
+///
+/// \param PartialSpec the (uninstantiated) variable template partial
+/// specialization that we are instantiating.
+///
+/// \returns The instantiated partial specialization, if successful; otherwise,
+/// NULL to indicate an error.
+VarTemplatePartialSpecializationDecl *
+TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
+ VarTemplateDecl *VarTemplate,
+ VarTemplatePartialSpecializationDecl *PartialSpec) {
+ // Create a local instantiation scope for this variable template partial
+ // specialization, which will contain the instantiations of the template
+ // parameters.
+ LocalInstantiationScope Scope(SemaRef);
+
+ // Substitute into the template parameters of the variable template partial
+ // specialization.
+ TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+
+ // Substitute into the template arguments of the variable template partial
+ // specialization.
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = PartialSpec->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc,
+ TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstTemplateArgs, TemplateArgs))
+ return 0;
+
+ // Check that the template argument list is well-formed for this
+ // class template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
+ InstTemplateArgs, false, Converted))
+ return 0;
+
+ // Figure out where to insert this variable template partial specialization
+ // in the member template's set of variable template partial specializations.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *PrevDecl =
+ VarTemplate->findPartialSpecialization(Converted.data(), Converted.size(),
+ InsertPos);
+
+ // Build the canonical type that describes the converted template
+ // arguments of the variable template partial specialization.
+ QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(VarTemplate), Converted.data(), Converted.size());
+
+ // Build the fully-sugared type for this variable template
+ // specialization as the user wrote in the specialization
+ // itself. This means that we'll pretty-print the type retrieved
+ // from the specialization's declaration the way that the user
+ // actually wrote the specialization, rather than formatting the
+ // name based on the "canonical" representation used to store the
+ // template arguments in the specialization.
+ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
+ TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs,
+ CanonType);
+
+ if (PrevDecl) {
+ // We've already seen a partial specialization with the same template
+ // parameters and template arguments. This can happen, for example, when
+ // substituting the outer template arguments ends up causing two
+ // variable template partial specializations of a member variable template
+ // to have identical forms, e.g.,
+ //
+ // template<typename T, typename U>
+ // struct Outer {
+ // template<typename X, typename Y> pair<X,Y> p;
+ // template<typename Y> pair<T, Y> p;
+ // template<typename Y> pair<U, Y> p;
+ // };
+ //
+ // Outer<int, int> outer; // error: the partial specializations of Inner
+ // // have the same signature.
+ SemaRef.Diag(PartialSpec->getLocation(),
+ diag::err_var_partial_spec_redeclared)
+ << WrittenTy->getType();
+ SemaRef.Diag(PrevDecl->getLocation(),
+ diag::note_var_prev_partial_spec_here);
+ return 0;
+ }
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI = SemaRef.SubstType(
+ PartialSpec->getTypeSourceInfo(), TemplateArgs,
+ PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName());
+ if (!DI)
+ return 0;
+
+ if (DI->getType()->isFunctionType()) {
+ SemaRef.Diag(PartialSpec->getLocation(),
+ diag::err_variable_instantiates_to_function)
+ << PartialSpec->isStaticDataMember() << DI->getType();
+ return 0;
+ }
+
+ // Create the variable template partial specialization declaration.
+ VarTemplatePartialSpecializationDecl *InstPartialSpec =
+ VarTemplatePartialSpecializationDecl::Create(
+ SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
+ PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
+ DI, PartialSpec->getStorageClass(), Converted.data(),
+ Converted.size(), InstTemplateArgs);
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(PartialSpec, InstPartialSpec))
+ return 0;
+
+ InstPartialSpec->setInstantiatedFromMember(PartialSpec);
+ InstPartialSpec->setTypeAsWritten(WrittenTy);
+
+ // Add this partial specialization to the set of variable template partial
+ // specializations. The instantiation of the initializer is not necessary.
+ VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
+
+ SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
+ LateAttrs, Owner, StartingScope);
+
+ return InstPartialSpec;
+}
+
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
SmallVectorImpl<ParmVarDecl *> &Params) {
@@ -2449,7 +2868,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
CXXRecordDecl *ThisContext = 0;
unsigned ThisTypeQuals = 0;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- ThisContext = Method->getParent();
+ ThisContext = cast<CXXRecordDecl>(Owner);
ThisTypeQuals = Method->getTypeQualifiers();
}
@@ -2461,11 +2880,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (!NewTInfo)
return 0;
- if (NewTInfo != OldTInfo) {
- // Get parameters from the new type info.
- TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc OldProtoLoc =
- OldTL.getAs<FunctionProtoTypeLoc>()) {
+ TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
+ if (FunctionProtoTypeLoc OldProtoLoc = OldTL.getAs<FunctionProtoTypeLoc>()) {
+ if (NewTInfo != OldTInfo) {
+ // Get parameters from the new type info.
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
unsigned NewIdx = 0;
@@ -2495,22 +2913,45 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
}
}
}
- }
- } else {
- // The function type itself was not dependent and therefore no
- // substitution occurred. However, we still need to instantiate
- // the function parameters themselves.
- TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc OldProtoLoc =
- OldTL.getAs<FunctionProtoTypeLoc>()) {
+ } else {
+ // The function type itself was not dependent and therefore no
+ // substitution occurred. However, we still need to instantiate
+ // the function parameters themselves.
+ const FunctionProtoType *OldProto =
+ cast<FunctionProtoType>(OldProtoLoc.getType());
for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
- ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc.getArg(i));
+ ParmVarDecl *OldParam = OldProtoLoc.getArg(i);
+ if (!OldParam) {
+ Params.push_back(SemaRef.BuildParmVarDeclForTypedef(
+ D, D->getLocation(), OldProto->getArgType(i)));
+ continue;
+ }
+
+ ParmVarDecl *Parm =
+ cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldParam));
if (!Parm)
return 0;
Params.push_back(Parm);
}
}
+ } else {
+ // If the type of this function, after ignoring parentheses, is not
+ // *directly* a function type, then we're instantiating a function that
+ // was declared via a typedef or with attributes, e.g.,
+ //
+ // typedef int functype(int, int);
+ // functype func;
+ // int __cdecl meth(int, int);
+ //
+ // In this case, we'll just go instantiate the ParmVarDecls that we
+ // synthesized in the method declaration.
+ SmallVector<QualType, 4> ParamTypes;
+ if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
+ D->getNumParams(), TemplateArgs, ParamTypes,
+ &Params))
+ return 0;
}
+
return NewTInfo;
}
@@ -2585,8 +3026,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
bool Expand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions
- = PackExpansion->getNumExpansions();
+ Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
SourceRange(),
Unexpanded,
@@ -2674,9 +3114,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
EPI.NoexceptExpr = NoexceptExpr;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- ArrayRef<QualType>(NewProto->arg_type_begin(),
- NewProto->getNumArgs()),
- EPI));
+ NewProto->getArgTypes(), EPI));
}
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
@@ -2687,15 +3125,13 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
InstantiatingTemplate::ExceptionSpecification());
- if (Inst) {
+ if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_None;
Decl->setType(Context.getFunctionType(Proto->getResultType(),
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- EPI));
+ Proto->getArgTypes(), EPI));
return;
}
@@ -2774,10 +3210,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpecType = NewEST;
EPI.ExceptionSpecDecl = New;
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
- New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- ArrayRef<QualType>(NewProto->arg_type_begin(),
- NewProto->getNumArgs()),
- EPI));
+ New->setType(SemaRef.Context.getFunctionType(
+ NewProto->getResultType(), NewProto->getArgTypes(), EPI));
} else {
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
}
@@ -2862,11 +3296,17 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
}
- // Call the LateTemplateParser callback if there a need to late parse
+ // Call the LateTemplateParser callback if there is a need to late parse
// a templated function definition.
if (!Pattern && PatternDecl->isLateTemplateParsed() &&
LateTemplateParser) {
- LateTemplateParser(OpaqueParser, PatternDecl);
+ // FIXME: Optimize to allow individual templates to be deserialized.
+ if (PatternDecl->isFromASTFile())
+ ExternalSource->ReadLateParsedTemplates(LateParsedTemplateMap);
+
+ LateParsedTemplate *LPT = LateParsedTemplateMap.lookup(PatternDecl);
+ assert(LPT && "missing LateParsedTemplate");
+ LateTemplateParser(OpaqueParser, *LPT);
Pattern = PatternDecl->getBody(PatternDecl);
}
@@ -2902,14 +3342,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Function->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration &&
!PatternDecl->isInlined() &&
- !PatternDecl->getResultType()->isUndeducedType())
+ !PatternDecl->getResultType()->getContainedAutoType())
return;
if (PatternDecl->isInlined())
Function->setImplicitlyInline();
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
- if (Inst)
+ if (Inst.isInvalid())
return;
// Copy the inner loc start from the pattern.
@@ -2920,6 +3360,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// while we're still within our own instantiation context.
SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ SavePendingLocalImplicitInstantiationsRAII
+ SavedPendingLocalImplicitInstantiations(*this);
if (Recursive) {
VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
@@ -3002,6 +3444,202 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
}
}
+VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
+ VarTemplateDecl *VarTemplate, VarDecl *FromVar,
+ const TemplateArgumentList &TemplateArgList,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ SmallVectorImpl<TemplateArgument> &Converted,
+ SourceLocation PointOfInstantiation, void *InsertPos,
+ LateInstantiatedAttrVec *LateAttrs,
+ LocalInstantiationScope *StartingScope) {
+ if (FromVar->isInvalidDecl())
+ return 0;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar);
+ if (Inst.isInvalid())
+ return 0;
+
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
+
+ // Instantiate the first declaration of the variable template: for a partial
+ // specialization of a static data member template, the first declaration may
+ // or may not be the declaration in the class; if it's in the class, we want
+ // to instantiate a member in the class (a declaration), and if it's outside,
+ // we want to instantiate a definition.
+ FromVar = FromVar->getFirstDecl();
+
+ MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList);
+ TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
+ MultiLevelList);
+
+ // TODO: Set LateAttrs and StartingScope ...
+
+ return cast_or_null<VarTemplateSpecializationDecl>(
+ Instantiator.VisitVarTemplateSpecializationDecl(
+ VarTemplate, FromVar, InsertPos, TemplateArgsInfo, Converted));
+}
+
+/// \brief Instantiates a variable template specialization by completing it
+/// with appropriate type information and initializer.
+VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI =
+ SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
+ PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
+ if (!DI)
+ return 0;
+
+ // Update the type of this variable template specialization.
+ VarSpec->setType(DI->getType());
+
+ // Instantiate the initializer.
+ InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
+
+ return VarSpec;
+}
+
+/// BuildVariableInstantiation - Used after a new variable has been created.
+/// Sets basic variable data and decides whether to postpone the
+/// variable instantiation.
+void Sema::BuildVariableInstantiation(
+ VarDecl *NewVar, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
+ LocalInstantiationScope *StartingScope,
+ bool InstantiatingVarTemplate) {
+
+ // If we are instantiating a local extern declaration, the
+ // instantiation belongs lexically to the containing function.
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (OldVar->isLocalExternDecl()) {
+ NewVar->setLocalExternDecl();
+ NewVar->setLexicalDeclContext(Owner);
+ } else if (OldVar->isOutOfLine())
+ NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext());
+ NewVar->setTSCSpec(OldVar->getTSCSpec());
+ NewVar->setInitStyle(OldVar->getInitStyle());
+ NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl());
+ NewVar->setConstexpr(OldVar->isConstexpr());
+ NewVar->setInitCapture(OldVar->isInitCapture());
+ NewVar->setPreviousDeclInSameBlockScope(
+ OldVar->isPreviousDeclInSameBlockScope());
+ NewVar->setAccess(OldVar->getAccess());
+
+ if (!OldVar->isStaticDataMember()) {
+ if (OldVar->isUsed(false))
+ NewVar->setIsUsed();
+ NewVar->setReferenced(OldVar->isReferenced());
+ }
+
+ // See if the old variable had a type-specifier that defined an anonymous tag.
+ // If it did, mark the new variable as being the declarator for the new
+ // anonymous tag.
+ if (const TagType *OldTagType = OldVar->getType()->getAs<TagType>()) {
+ TagDecl *OldTag = OldTagType->getDecl();
+ if (OldTag->getDeclaratorForAnonDecl() == OldVar) {
+ TagDecl *NewTag = NewVar->getType()->castAs<TagType>()->getDecl();
+ assert(!NewTag->hasNameForLinkage() &&
+ !NewTag->hasDeclaratorForAnonDecl());
+ NewTag->setDeclaratorForAnonDecl(NewVar);
+ }
+ }
+
+ InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
+
+ if (NewVar->hasAttrs())
+ CheckAlignasUnderalignment(NewVar);
+
+ LookupResult Previous(
+ *this, NewVar->getDeclName(), NewVar->getLocation(),
+ NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
+
+ if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl()) {
+ // We have a previous declaration. Use that one, so we merge with the
+ // right type.
+ if (NamedDecl *NewPrev = FindInstantiatedDecl(
+ NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs))
+ Previous.addDecl(NewPrev);
+ } else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
+ OldVar->hasLinkage())
+ LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
+ CheckVariableDeclaration(NewVar, Previous);
+
+ if (!InstantiatingVarTemplate) {
+ NewVar->getLexicalDeclContext()->addHiddenDecl(NewVar);
+ if (!NewVar->isLocalExternDecl() || !NewVar->getPreviousDecl())
+ NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar);
+ }
+
+ if (!OldVar->isOutOfLine()) {
+ if (NewVar->getDeclContext()->isFunctionOrMethod())
+ CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar);
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate)
+ NewVar->setInstantiationOfStaticDataMember(OldVar,
+ TSK_ImplicitInstantiation);
+
+ // Delay instantiation of the initializer for variable templates until a
+ // definition of the variable is needed.
+ if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate)
+ InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+
+ // Diagnose unused local variables with dependent types, where the diagnostic
+ // will have been deferred.
+ if (!NewVar->isInvalidDecl() &&
+ NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() &&
+ OldVar->getType()->isDependentType())
+ DiagnoseUnusedDecl(NewVar);
+}
+
+/// \brief Instantiate the initializer of a variable.
+void Sema::InstantiateVariableInitializer(
+ VarDecl *Var, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ if (Var->getAnyInitializer())
+ // We already have an initializer in the class.
+ return;
+
+ if (OldVar->getInit()) {
+ if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
+ PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar);
+ else
+ PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
+
+ // Instantiate the initializer.
+ ExprResult Init =
+ SubstInitializer(OldVar->getInit(), TemplateArgs,
+ OldVar->getInitStyle() == VarDecl::CallInit);
+ if (!Init.isInvalid()) {
+ bool TypeMayContainAuto = true;
+ if (Init.get()) {
+ bool DirectInit = OldVar->isDirectInit();
+ AddInitializerToDecl(Var, Init.take(), DirectInit, TypeMayContainAuto);
+ } else
+ ActOnUninitializedDecl(Var, TypeMayContainAuto);
+ } else {
+ // FIXME: Not too happy about invalidating the declaration
+ // because of a bogus initializer.
+ Var->setInvalidDecl();
+ }
+
+ PopExpressionEvaluationContext();
+ } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
+ !Var->isCXXForRangeDecl())
+ ActOnUninitializedDecl(Var, false);
+}
+
/// \brief Instantiate the definition of the given variable from its
/// template.
///
@@ -3023,26 +3661,151 @@ void Sema::InstantiateStaticDataMemberDefinition(
VarDecl *Var,
bool Recursive,
bool DefinitionRequired) {
+ InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive,
+ DefinitionRequired);
+}
+
+void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
+ VarDecl *Var, bool Recursive,
+ bool DefinitionRequired) {
if (Var->isInvalidDecl())
return;
- // Find the out-of-line definition of this static data member.
- VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
- assert(Def && "This data member was not instantiated from a template?");
- assert(Def->isStaticDataMember() && "Not a static data member?");
- Def = Def->getOutOfLineDefinition();
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
+ VarDecl *PatternDecl = 0, *Def = 0;
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Var);
+
+ if (VarSpec) {
+ // If this is a variable template specialization, make sure that it is
+ // non-dependent, then find its instantiation pattern.
+ bool InstantiationDependent = false;
+ assert(!TemplateSpecializationType::anyDependentTemplateArguments(
+ VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
+ "Only instantiate variable template specializations that are "
+ "not type-dependent");
+ (void)InstantiationDependent;
+
+ // Find the variable initialization that we'll be substituting. If the
+ // pattern was instantiated from a member template, look back further to
+ // find the real pattern.
+ assert(VarSpec->getSpecializedTemplate() &&
+ "Specialization without specialized template?");
+ llvm::PointerUnion<VarTemplateDecl *,
+ VarTemplatePartialSpecializationDecl *> PatternPtr =
+ VarSpec->getSpecializedTemplateOrPartial();
+ if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
+ VarTemplatePartialSpecializationDecl *Tmpl =
+ PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
+ while (VarTemplatePartialSpecializationDecl *From =
+ Tmpl->getInstantiatedFromMember()) {
+ if (Tmpl->isMemberSpecialization())
+ break;
+
+ Tmpl = From;
+ }
+ PatternDecl = Tmpl;
+ } else {
+ VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
+ while (VarTemplateDecl *From =
+ Tmpl->getInstantiatedFromMemberTemplate()) {
+ if (Tmpl->isMemberSpecialization())
+ break;
+
+ Tmpl = From;
+ }
+ PatternDecl = Tmpl->getTemplatedDecl();
+ }
+
+ // If this is a static data member template, there might be an
+ // uninstantiated initializer on the declaration. If so, instantiate
+ // it now.
+ if (PatternDecl->isStaticDataMember() &&
+ (PatternDecl = PatternDecl->getFirstDecl())->hasInit() &&
+ !Var->hasInit()) {
+ // FIXME: Factor out the duplicated instantiation context setup/tear down
+ // code here.
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst.isInvalid())
+ return;
+
+ // 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.
+ SmallVector<VTableUse, 16> SavedVTableUses;
+ std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ if (Recursive) {
+ VTableUses.swap(SavedVTableUses);
+ PendingInstantiations.swap(SavedPendingInstantiations);
+ }
+
+ LocalInstantiationScope Local(*this);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ ContextRAII PreviousContext(*this, Var->getDeclContext());
+ 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);
+
+ Local.Exit();
+
+ if (Recursive) {
+ // Define any newly required vtables.
+ DefineUsedVTables();
+
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingInstantiations();
+
+ // Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded.");
+ VTableUses.swap(SavedVTableUses);
+
+ // Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded.");
+ PendingInstantiations.swap(SavedPendingInstantiations);
+ }
+ }
+
+ // Find actual definition
+ Def = PatternDecl->getDefinition(getASTContext());
+ } else {
+ // If this is a static data member, find its out-of-line definition.
+ assert(Var->isStaticDataMember() && "not a static data member?");
+ PatternDecl = Var->getInstantiatedFromStaticDataMember();
+
+ assert(PatternDecl && "data member was not instantiated from a template?");
+ assert(PatternDecl->isStaticDataMember() && "not a static data member?");
+ Def = PatternDecl->getOutOfLineDefinition();
+ }
+
+ // If we don't have a definition of the variable template, we won't perform
+ // any instantiation. Rather, we rely on the user to instantiate this
+ // definition (or provide a specialization for it) in another translation
+ // unit.
if (!Def) {
- // We did not find an out-of-line definition of this static data member,
- // so we won't perform any instantiation. Rather, we rely on the user to
- // instantiate this definition (or provide a specialization for it) in
- // another translation unit.
if (DefinitionRequired) {
- Def = Var->getInstantiatedFromStaticDataMember();
- Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_member)
- << 2 << Var->getDeclName() << Var->getDeclContext();
- Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
+ if (VarSpec)
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_var_template) << Var;
+ else
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_member)
+ << 2 << Var->getDeclName() << Var->getDeclContext();
+ Diag(PatternDecl->getLocation(),
+ diag::note_explicit_instantiation_here);
+ if (VarSpec)
+ Var->setInvalidDecl();
} else if (Var->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDefinition) {
PendingInstantiations.push_back(
@@ -3058,8 +3821,8 @@ void Sema::InstantiateStaticDataMemberDefinition(
if (TSK == TSK_ExplicitSpecialization)
return;
- // C++0x [temp.explicit]p9:
- // Except for inline functions, other explicit instantiation declarations
+ // C++11 [temp.explicit]p10:
+ // Except for inline functions, [...] explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
if (TSK == TSK_ExplicitInstantiationDeclaration)
@@ -3088,7 +3851,7 @@ void Sema::InstantiateStaticDataMemberDefinition(
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
- if (Inst)
+ if (Inst.isInvalid())
return;
// If we're performing recursive template instantiation, create our own
@@ -3096,6 +3859,8 @@ void Sema::InstantiateStaticDataMemberDefinition(
// while we're still within our own instantiation context.
SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ SavePendingLocalImplicitInstantiationsRAII
+ SavedPendingLocalImplicitInstantiations(*this);
if (Recursive) {
VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
@@ -3103,22 +3868,58 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
- ContextRAII previousContext(*this, Var->getDeclContext());
+ ContextRAII PreviousContext(*this, Var->getDeclContext());
LocalInstantiationScope Local(*this);
-
+
VarDecl *OldVar = Var;
- Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
- getTemplateInstantiationArgs(Var)));
+ if (!VarSpec)
+ Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
+ TemplateArgs));
+ else if (Var->isStaticDataMember() &&
+ Var->getLexicalDeclContext()->isRecord()) {
+ // We need to instantiate the definition of a static data member template,
+ // and all we have is the in-class declaration of it. Instantiate a separate
+ // declaration of the definition.
+ TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
+ TemplateArgs);
+ Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
+ VarSpec->getSpecializedTemplate(), Def, 0,
+ VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray()));
+ if (Var) {
+ llvm::PointerUnion<VarTemplateDecl *,
+ VarTemplatePartialSpecializationDecl *> PatternPtr =
+ VarSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+ cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf(
+ Partial, &VarSpec->getTemplateInstantiationArgs());
+
+ // Merge the definition with the declaration.
+ LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
+ LookupOrdinaryName, ForRedeclaration);
+ R.addDecl(OldVar);
+ MergeVarDecl(Var, R);
+
+ // Attach the initializer.
+ InstantiateVariableInitializer(Var, Def, TemplateArgs);
+ }
+ } else
+ // Complete the existing variable's definition with an appropriately
+ // substituted type and initializer.
+ Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs);
- previousContext.pop();
+ PreviousContext.pop();
if (Var) {
PassToConsumerRAII.Var = Var;
- MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
- MSInfo->getPointOfInstantiation());
+ Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(),
+ OldVar->getPointOfInstantiation());
}
+
+ // This variable may have local implicit instantiations that need to be
+ // instantiated within this scope.
+ PerformPendingInstantiations(/*LocalOnly=*/true);
+
Local.Exit();
if (Recursive) {
@@ -3131,14 +3932,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Restore the set of pending vtables.
assert(VTableUses.empty() &&
- "VTableUses should be empty before it is discarded, "
- "while instantiating static data member.");
+ "VTableUses should be empty before it is discarded.");
VTableUses.swap(SavedVTableUses);
// Restore the set of pending implicit instantiations.
assert(PendingInstantiations.empty() &&
- "PendingInstantiations should be empty before it is discarded, "
- "while instantiating static data member.");
+ "PendingInstantiations should be empty before it is discarded.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -3167,8 +3966,9 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
if (Init->isPackExpansion()) {
// This is a pack expansion. We should expand it now.
TypeLoc BaseTL = Init->getTypeSourceInfo()->getTypeLoc();
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 4> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
+ collectUnexpandedParameterPacks(Init->getInit(), Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
Optional<unsigned> NumExpansions;
@@ -3523,14 +4323,33 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
/// template struct X<int>;
/// \endcode
///
-/// In the instantiation of X<int>::getKind(), we need to map the
-/// EnumConstantDecl for KnownValue (which refers to
-/// X<T>::\<Kind>\::KnownValue) to its instantiation
-/// (X<int>::\<Kind>\::KnownValue). InstantiateCurrentDeclRef() performs
-/// this mapping from within the instantiation of X<int>.
+/// In the instantiation of <tt>X<int>::getKind()</tt>, we need to map the
+/// \p EnumConstantDecl for \p KnownValue (which refers to
+/// <tt>X<T>::<Kind>::KnownValue</tt>) to its instantiation
+/// (<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) {
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
+ // - thus we can not consistently check if the ParentDC of such a parameter
+ // is Dependent or/and a FunctionOrMethod.
+ // For e.g. this code, during Template argument deduction tries to
+ // find an instantiated decl for (T y) when the ParentDC for y is
+ // the translation unit.
+ // e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {}
+ // float baz(float(*)()) { return 0.0; }
+ // Foo(baz);
+ // The better fix here is perhaps to ensure that a ParmVarDecl, by the time
+ // it gets here, always has a FunctionOrMethod as its ParentDC??
+ // For now:
+ // - as long as we have a ParmVarDecl whose parent is non-dependent and
+ // whose type is not instantiation dependent, do nothing to the decl
+ // - otherwise find its instantiated decl.
+ if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
+ !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
+ return D;
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||
@@ -3550,6 +4369,16 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
}
+ // If we're performing a partial substitution during template argument
+ // deduction, we may not have values for template parameters yet. They
+ // just map to themselves.
+ if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
+ isa<TemplateTemplateParmDecl>(D))
+ return D;
+
+ if (D->isInvalidDecl())
+ return 0;
+
// If we didn't find the decl, then we must have a label decl that hasn't
// been found yet. Lazily instantiate it and return it now.
assert(isa<LabelDecl>(D));
@@ -3561,6 +4390,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return cast<LabelDecl>(Inst);
}
+ // For variable template specializations, update those that are still
+ // type-dependent.
+ if (VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ bool InstantiationDependent = false;
+ const TemplateArgumentListInfo &VarTemplateArgs =
+ VarSpec->getTemplateArgsInfo();
+ if (TemplateSpecializationType::anyDependentTemplateArguments(
+ VarTemplateArgs, InstantiationDependent))
+ D = cast<NamedDecl>(
+ SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs));
+ return D;
+ }
+
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
@@ -3573,7 +4416,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
else if (ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl();
-
+
// Walk the current context to find either the record or an instantiation of
// it.
DeclContext *DC = CurContext;
@@ -3582,7 +4425,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// definition, we'll find our own context. We're done.
if (DC->Equals(Record))
return Record;
-
+
if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) {
// Check whether we're in the process of instantiating a class template
// specialization of the template we're mapping.
@@ -3592,13 +4435,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate))
return InstRecord;
}
-
+
// Check whether we're in the process of instantiating a member class.
if (isInstantiationOf(Record, InstRecord))
return InstRecord;
}
-
-
+
// Move to the outer template scope.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
@@ -3606,7 +4448,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
continue;
}
}
-
+
DC = DC->getParent();
}
@@ -3739,9 +4581,13 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
continue;
}
- // Instantiate static data member definitions.
+ // Instantiate variable definitions
VarDecl *Var = cast<VarDecl>(Inst.first);
- assert(Var->isStaticDataMember() && "Not a static data member?");
+
+ assert((Var->isStaticDataMember() ||
+ isa<VarTemplateSpecializationDecl>(Var)) &&
+ "Not a static data member, nor a variable template"
+ " specialization?");
// Don't try to instantiate declarations if the most recent redeclaration
// is invalid.
@@ -3764,14 +4610,15 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
break;
}
- PrettyDeclStackTraceEntry CrashInfo(*this, Var, Var->getLocation(),
- "instantiating static data member "
- "definition");
-
+ PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
+ "instantiating variable definition");
bool DefinitionRequired = Var->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
- InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
- DefinitionRequired);
+
+ // Instantiate static data member definitions or variable template
+ // specializations.
+ InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
+ DefinitionRequired);
}
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index db885aeec7b7..78aa7f893a1a 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include "TypeLocBuilder.h"
using namespace clang;
@@ -179,10 +180,14 @@ namespace {
// 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 (VarDecl *VD = I->getCapturedVar())
+ 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()));
+ }
+ }
inherited::TraverseLambdaExpr(Lambda);
@@ -459,17 +464,13 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
EllipsisLoc, NumExpansions);
if (Result.isNull())
return 0;
-
- TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
- PackExpansionTypeLoc TL =
- TSResult->getTypeLoc().castAs<PackExpansionTypeLoc>();
+
+ TypeLocBuilder TLB;
+ TLB.pushFullCopy(Pattern->getTypeLoc());
+ PackExpansionTypeLoc TL = TLB.push<PackExpansionTypeLoc>(Result);
TL.setEllipsisLoc(EllipsisLoc);
-
- // Copy over the source-location information from the type.
- memcpy(TL.getNextTypeLoc().getOpaqueData(),
- Pattern->getTypeLoc().getOpaqueData(),
- Pattern->getTypeLoc().getFullDataSize());
- return TSResult;
+
+ return TLB.getTypeSourceInfo(Context, Result);
}
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
@@ -818,16 +819,12 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), S, 0,
Validator)) {
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
+ PDiag(diag::note_parameter_pack_here));
ParameterPack = Corrected.getCorrectionDecl();
- Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
- << &Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(
- NameLoc, Corrected.getAsString(getLangOpts()));
- Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
- << CorrectedQuotedStr;
}
-
+
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
break;
@@ -848,3 +845,63 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
ParameterPack, NameLoc, RParenLoc);
}
+
+TemplateArgumentLoc
+Sema::getTemplateArgumentPackExpansionPattern(
+ TemplateArgumentLoc OrigLoc,
+ SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions) const {
+ const TemplateArgument &Argument = OrigLoc.getArgument();
+ assert(Argument.isPackExpansion());
+ switch (Argument.getKind()) {
+ case TemplateArgument::Type: {
+ // FIXME: We shouldn't ever have to worry about missing
+ // type-source info!
+ TypeSourceInfo *ExpansionTSInfo = OrigLoc.getTypeSourceInfo();
+ if (!ExpansionTSInfo)
+ ExpansionTSInfo = Context.getTrivialTypeSourceInfo(Argument.getAsType(),
+ Ellipsis);
+ PackExpansionTypeLoc Expansion =
+ ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
+ Ellipsis = Expansion.getEllipsisLoc();
+
+ TypeLoc Pattern = Expansion.getPatternLoc();
+ NumExpansions = Expansion.getTypePtr()->getNumExpansions();
+
+ // We need to copy the TypeLoc because TemplateArgumentLocs store a
+ // TypeSourceInfo.
+ // FIXME: Find some way to avoid the copy?
+ TypeLocBuilder TLB;
+ TLB.pushFullCopy(Pattern);
+ TypeSourceInfo *PatternTSInfo =
+ TLB.getTypeSourceInfo(Context, Pattern.getType());
+ return TemplateArgumentLoc(TemplateArgument(Pattern.getType()),
+ PatternTSInfo);
+ }
+
+ case TemplateArgument::Expression: {
+ PackExpansionExpr *Expansion
+ = cast<PackExpansionExpr>(Argument.getAsExpr());
+ Expr *Pattern = Expansion->getPattern();
+ Ellipsis = Expansion->getEllipsisLoc();
+ NumExpansions = Expansion->getNumExpansions();
+ return TemplateArgumentLoc(Pattern, Pattern);
+ }
+
+ case TemplateArgument::TemplateExpansion:
+ Ellipsis = OrigLoc.getTemplateEllipsisLoc();
+ NumExpansions = Argument.getNumTemplateExpansions();
+ return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
+ OrigLoc.getTemplateQualifierLoc(),
+ OrigLoc.getTemplateNameLoc());
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Template:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Pack:
+ case TemplateArgument::Null:
+ return TemplateArgumentLoc();
+ }
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 0959f7d66adf..aa7459de2726 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
@@ -33,8 +34,16 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
+#include "TypeLocBuilder.h"
+
using namespace clang;
+enum TypeDiagSelector {
+ TDS_Function,
+ TDS_Pointer,
+ TDS_ObjCObjOrBlock
+};
+
/// isOmittedBlockReturnType - Return true if this declarator is missing a
/// return type because this is a omitted return type on a block literal.
static bool isOmittedBlockReturnType(const Declarator &D) {
@@ -56,23 +65,15 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
/// doesn't apply to the given type.
static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
QualType type) {
- bool useExpansionLoc = false;
-
- unsigned diagID = 0;
+ TypeDiagSelector WhichType;
+ bool useExpansionLoc = true;
switch (attr.getKind()) {
- case AttributeList::AT_ObjCGC:
- diagID = diag::warn_pointer_attribute_wrong_type;
- useExpansionLoc = true;
- break;
-
- case AttributeList::AT_ObjCOwnership:
- diagID = diag::warn_objc_object_attribute_wrong_type;
- useExpansionLoc = true;
- break;
-
+ case AttributeList::AT_ObjCGC: WhichType = TDS_Pointer; break;
+ case AttributeList::AT_ObjCOwnership: WhichType = TDS_ObjCObjOrBlock; break;
default:
// Assume everything else was a function attribute.
- diagID = diag::warn_function_attribute_wrong_type;
+ WhichType = TDS_Function;
+ useExpansionLoc = false;
break;
}
@@ -80,15 +81,17 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
StringRef name = attr.getName()->getName();
// The GC attributes are usually written with macros; special-case them.
- if (useExpansionLoc && loc.isMacroID() && attr.getParameterName()) {
- if (attr.getParameterName()->isStr("strong")) {
+ IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident : 0;
+ if (useExpansionLoc && loc.isMacroID() && II) {
+ if (II->isStr("strong")) {
if (S.findMacroSpelling(loc, "__strong")) name = "__strong";
- } else if (attr.getParameterName()->isStr("weak")) {
+ } else if (II->isStr("weak")) {
if (S.findMacroSpelling(loc, "__weak")) name = "__weak";
}
}
- S.Diag(loc, diagID) << name << type;
+ S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType
+ << type;
}
// objc_gc applies to Objective-C pointers or, otherwise, to the
@@ -105,10 +108,19 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_StdCall: \
case AttributeList::AT_ThisCall: \
case AttributeList::AT_Pascal: \
+ case AttributeList::AT_MSABI: \
+ case AttributeList::AT_SysVABI: \
case AttributeList::AT_Regparm: \
case AttributeList::AT_Pcs: \
case AttributeList::AT_PnaclCall: \
- case AttributeList::AT_IntelOclBicc \
+ case AttributeList::AT_IntelOclBicc
+
+// Microsoft-specific type qualifiers.
+#define MS_TYPE_ATTRS_CASELIST \
+ case AttributeList::AT_Ptr32: \
+ case AttributeList::AT_Ptr64: \
+ case AttributeList::AT_SPtr: \
+ case AttributeList::AT_UPtr
namespace {
/// An object which stores processing state for the entire
@@ -223,26 +235,6 @@ namespace {
savedAttrs.back()->setNext(0);
}
};
-
- /// Basically std::pair except that we really want to avoid an
- /// implicit operator= for safety concerns. It's also a minor
- /// link-time optimization for this to be a private type.
- struct AttrAndList {
- /// The attribute.
- AttributeList &first;
-
- /// The head of the list the attribute is currently in.
- AttributeList *&second;
-
- AttrAndList(AttributeList &attr, AttributeList *&head)
- : first(attr), second(head) {}
- };
-}
-
-namespace llvm {
- template <> struct isPodLike<AttrAndList> {
- static const bool value = true;
- };
}
static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) {
@@ -292,6 +284,10 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
AttributeList &attr,
QualType &type);
+static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state,
+ AttributeList &attr,
+ QualType &type);
+
static bool handleObjCGCTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type);
@@ -533,12 +529,7 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state,
return true;
}
- if (handleFunctionTypeAttr(state, attr, declSpecType)) {
- spliceAttrOutOfList(attr, attrList);
- return true;
- }
-
- return false;
+ return handleFunctionTypeAttr(state, attr, declSpecType);
}
/// A function type attribute was written in the decl spec. Try to
@@ -626,6 +617,10 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
+ MS_TYPE_ATTRS_CASELIST:
+ // Microsoft type attributes cannot go after the declarator-id.
+ continue;
+
default:
break;
}
@@ -767,8 +762,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
// specified with a trailing return type or inferred.
- if (declarator.getContext() == Declarator::LambdaExprContext ||
- isOmittedBlockReturnType(declarator)) {
+ if (S.getLangOpts().CPlusPlus1y &&
+ declarator.getContext() == Declarator::LambdaExprContext) {
+ // In C++1y, a lambda's implicit return type is 'auto'.
+ Result = Context.getAutoDeductType();
+ break;
+ } else if (declarator.getContext() == Declarator::LambdaExprContext ||
+ isOmittedBlockReturnType(declarator)) {
Result = Context.DependentTy;
break;
}
@@ -994,11 +994,54 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_auto:
// TypeQuals handled by caller.
- Result = Context.getAutoType(QualType(), /*decltype(auto)*/false);
+ // If auto is mentioned in a lambda parameter context, convert it to a
+ // template parameter type immediately, with the appropriate depth and
+ // index, and update sema's state (LambdaScopeInfo) for the current lambda
+ // being analyzed (which tracks the invented type template parameter).
+ if (declarator.getContext() == Declarator::LambdaExprParameterContext) {
+ sema::LambdaScopeInfo *LSI = S.getCurLambda();
+ assert(LSI && "No LambdaScopeInfo on the stack!");
+ const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const bool IsParameterPack = declarator.hasEllipsis();
+
+ // Create a name for the invented template parameter type.
+ std::string InventedTemplateParamName = "$auto-";
+ llvm::raw_string_ostream ss(InventedTemplateParamName);
+ ss << TemplateParameterDepth;
+ ss << "-" << AutoParameterPosition;
+ ss.flush();
+
+ IdentifierInfo& TemplateParamII = Context.Idents.get(
+ InventedTemplateParamName.c_str());
+ // Turns out we must create the TemplateTypeParmDecl here to
+ // retrieve the corresponding template parameter type.
+ TemplateTypeParmDecl *CorrespondingTemplateParam =
+ TemplateTypeParmDecl::Create(Context,
+ // Temporarily add to the TranslationUnit DeclContext. When the
+ // associated TemplateParameterList is attached to a template
+ // declaration (such as FunctionTemplateDecl), the DeclContext
+ // for each template parameter gets updated appropriately via
+ // a call to AdoptTemplateParameterList.
+ Context.getTranslationUnitDecl(),
+ /*KeyLoc*/ SourceLocation(),
+ /*NameLoc*/ declarator.getLocStart(),
+ TemplateParameterDepth,
+ AutoParameterPosition, // our template param index
+ /* Identifier*/ &TemplateParamII, false, IsParameterPack);
+ LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
+ } else {
+ Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false);
+ }
break;
case DeclSpec::TST_decltype_auto:
- Result = Context.getAutoType(QualType(), /*decltype(auto)*/true);
+ Result = Context.getAutoType(QualType(),
+ /*decltype(auto)*/true,
+ /*IsDependent*/ false);
break;
case DeclSpec::TST_unknown_anytype:
@@ -1545,14 +1588,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
ASM = ArrayType::Normal;
}
} else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
- !T->isIncompleteType()) {
+ !T->isIncompleteType() && !T->isUndeducedType()) {
// Is the array too large?
unsigned ActiveSizeBits
= ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
- if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
+ if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
Diag(ArraySize->getLocStart(), diag::err_array_too_large)
<< ConstVal.toString(10)
<< ArraySize->getSourceRange();
+ return QualType();
+ }
}
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
@@ -1567,7 +1612,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
- // FIXME: C++1y allows this.
QualType BaseT = Context.getBaseElementType(T);
if (!T->isDependentType() &&
!BaseT.isPODType(Context) &&
@@ -1583,9 +1627,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
// Just extwarn about VLAs.
else
- Diag(Loc, getLangOpts().CPlusPlus1y
- ? diag::warn_cxx11_compat_array_of_runtime_bound
- : diag::ext_vla);
+ Diag(Loc, diag::ext_vla);
} else if (ASM != ArrayType::Normal || Quals != 0)
Diag(Loc,
getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx
@@ -1616,8 +1658,9 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) {
llvm::APSInt vecSize(32);
if (!ArraySize->isIntegerConstantExpr(vecSize, Context)) {
- Diag(AttrLoc, diag::err_attribute_argument_not_int)
- << "ext_vector_type" << ArraySize->getSourceRange();
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "ext_vector_type" << AANT_ArgumentIntegerConstant
+ << ArraySize->getSourceRange();
return QualType();
}
@@ -1631,30 +1674,50 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
+ if (VectorType::isVectorSizeTooLarge(vectorSize)) {
+ Diag(AttrLoc, diag::err_attribute_size_too_large)
+ << ArraySize->getSourceRange();
+ return QualType();
+ }
+
return Context.getExtVectorType(T, vectorSize);
}
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
}
-QualType Sema::BuildFunctionType(QualType T,
- llvm::MutableArrayRef<QualType> ParamTypes,
- SourceLocation Loc, DeclarationName Entity,
- const FunctionProtoType::ExtProtoInfo &EPI) {
+bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
- return QualType();
+ return true;
}
// Functions cannot return half FP.
if (T->isHalfType()) {
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 <<
FixItHint::CreateInsertion(Loc, "*");
- return QualType();
+ return true;
}
+ // 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;
+ }
+
+ return false;
+}
+
+QualType Sema::BuildFunctionType(QualType T,
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ SourceLocation Loc, DeclarationName Entity,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
bool Invalid = false;
+
+ Invalid |= CheckFunctionReturnType(T, Loc);
+
for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
// FIXME: Loc is too inprecise here, should use proper locations for args.
QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
@@ -1749,6 +1812,8 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
}
}
+ // FIXME: Adjust member function pointer calling conventions.
+
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@@ -1917,7 +1982,7 @@ static void diagnoseIgnoredQualifiers(
{ DeclSpec::TQ_atomic, "_Atomic", AtomicQualLoc }
};
- llvm::SmallString<32> QualStr;
+ SmallString<32> QualStr;
unsigned NumQuals = 0;
SourceLocation Loc;
FixItHint FixIts[4];
@@ -2062,6 +2127,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// In C++11, a function declarator using 'auto' must have a trailing return
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
+ // C++14 In generic lambdas allow 'auto' in their parameters.
if (ContainsPlaceholderType &&
(!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
@@ -2074,7 +2140,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
- Error = 0; // Function prototype
+ Error = 0;
+ break;
+ case Declarator::LambdaExprParameterContext:
+ if (!(SemaRef.getLangOpts().CPlusPlus1y
+ && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
+ Error = 14;
break;
case Declarator::MemberContext:
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
@@ -2154,8 +2225,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
AutoRange = D.getName().getSourceRange();
if (Error != -1) {
+ const bool IsDeclTypeAuto =
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto;
SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
- << Error << AutoRange;
+ << IsDeclTypeAuto << Error << AutoRange;
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
} else
@@ -2205,6 +2278,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType(true);
break;
case Declarator::PrototypeContext:
+ case Declarator::LambdaExprParameterContext:
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::KNRTypeListContext:
@@ -2375,7 +2449,8 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
S.Diag(DeclType.Loc, diag::note_empty_parens_default_ctor)
<< FixItHint::CreateRemoval(ParenRange);
else {
- std::string Init = S.getFixItZeroInitializerForType(RT);
+ std::string Init =
+ S.getFixItZeroInitializerForType(RT, ParenRange.getBegin());
if (Init.empty() && S.LangOpts.CPlusPlus11)
Init = "{}";
if (!Init.empty())
@@ -2385,6 +2460,52 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
}
}
+/// 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
+/// type or normal function type.
+static CallingConv
+getCCForDeclaratorChunk(Sema &S, Declarator &D,
+ const DeclaratorChunk::FunctionTypeInfo &FTI,
+ unsigned ChunkIndex) {
+ assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function);
+
+ bool IsCXXInstanceMethod = false;
+
+ if (S.getLangOpts().CPlusPlus) {
+ // Look inwards through parentheses to see if this chunk will form a
+ // member pointer type or if we're the declarator. Any type attributes
+ // between here and there will override the CC we choose here.
+ unsigned I = ChunkIndex;
+ bool FoundNonParen = false;
+ while (I && !FoundNonParen) {
+ --I;
+ if (D.getTypeObject(I).Kind != DeclaratorChunk::Paren)
+ FoundNonParen = true;
+ }
+
+ if (FoundNonParen) {
+ // If we're not the declarator, we're a regular function type unless we're
+ // in a member pointer.
+ IsCXXInstanceMethod =
+ D.getTypeObject(I).Kind == DeclaratorChunk::MemberPointer;
+ } else {
+ // We're the innermost decl chunk, so must be a function declarator.
+ assert(D.isFunctionDeclarator());
+
+ // If we're inside a record, we're declaring a method, but it could be
+ // explicitly or implicitly static.
+ IsCXXInstanceMethod =
+ D.isFirstDeclarationOfMember() &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ !D.isStaticMember();
+ }
+ }
+
+ return S.Context.getDefaultCallingConvention(FTI.isVariadic,
+ IsCXXInstanceMethod);
+}
+
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -2578,8 +2699,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
}
-
- if (const AutoType *AT = T->getContainedAutoType()) {
+ const AutoType *AT = T->getContainedAutoType();
+ // Allow arrays of auto if we are a generic lambda parameter.
+ // i.e. [](auto (&array)[5]) { return array[0]; }; OK
+ if (AT && D.getContext() != Declarator::LambdaExprParameterContext) {
// We've already diagnosed this for decltype(auto).
if (!AT->isDecltypeAuto())
S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
@@ -2665,6 +2788,33 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
+ // Methods cannot return interface types. All ObjC objects are
+ // passed by reference.
+ if (T->isObjCObjectType()) {
+ SourceLocation DiagLoc, FixitLoc;
+ if (TInfo) {
+ DiagLoc = TInfo->getTypeLoc().getLocStart();
+ FixitLoc = S.PP.getLocForEndOfToken(TInfo->getTypeLoc().getLocEnd());
+ } else {
+ DiagLoc = D.getDeclSpec().getTypeSpecTypeLoc();
+ FixitLoc = S.PP.getLocForEndOfToken(D.getDeclSpec().getLocEnd());
+ }
+ S.Diag(DiagLoc, diag::err_object_cannot_be_passed_returned_by_value)
+ << 0 << T
+ << FixItHint::CreateInsertion(FixitLoc, "*");
+
+ T = Context.getObjCObjectPointerType(T);
+ if (TInfo) {
+ TypeLocBuilder TLB;
+ TLB.pushFullCopy(TInfo->getTypeLoc());
+ ObjCObjectPointerTypeLoc TLoc = TLB.push<ObjCObjectPointerTypeLoc>(T);
+ TLoc.setStarLoc(FixitLoc);
+ TInfo = TLB.getTypeSourceInfo(Context, T);
+ }
+
+ D.setInvalidType(true);
+ }
+
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
if ((T.getCVRQualifiers() || T->isAtomicType()) &&
@@ -2710,13 +2860,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
- if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+ if (LangOpts.CPlusPlus && D.getDeclSpec().hasTagDefinition()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
- if (Tag->isCompleteDefinition())
- S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
- << Context.getTypeDeclType(Tag);
+ S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+ << Context.getTypeDeclType(Tag);
}
// Exception specs are not allowed in typedefs. Complain, but add it
@@ -2731,9 +2880,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);
+ FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
+
if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
- T = Context.getFunctionNoProtoType(T);
+ T = Context.getFunctionNoProtoType(T, EI);
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
@@ -2758,11 +2909,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
// Recover by creating a K&R-style function type.
- T = Context.getFunctionNoProtoType(T);
+ T = Context.getFunctionNoProtoType(T, EI);
break;
}
FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExtInfo = EI;
EPI.Variadic = FTI.isVariadic;
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
EPI.TypeQuals = FTI.TypeQuals;
@@ -2784,10 +2936,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType ArgTy = Param->getType();
assert(!ArgTy.isNull() && "Couldn't parse type?");
- // Adjust the parameter type.
- assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
- "Unadjusted type?");
-
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
// int(void) as a FunctionProtoType with an empty argument list.
@@ -3017,9 +3165,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- T = Context.getFunctionType(FnTy->getResultType(),
- ArrayRef<QualType>(FnTy->arg_type_begin(),
- FnTy->getNumArgs()),
+ T = Context.getFunctionType(FnTy->getResultType(), FnTy->getArgTypes(),
EPI);
// Rebuild any parens around the identifier in the function type.
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
@@ -3054,6 +3200,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// is a parameter pack (14.5.3). [...]
switch (D.getContext()) {
case Declarator::PrototypeContext:
+ case Declarator::LambdaExprParameterContext:
// C++0x [dcl.fct]p13:
// [...] When it is part of a parameter-declaration-clause, the
// parameter pack is a function parameter pack (14.5.3). The type T
@@ -3072,7 +3219,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getPackExpansionType(T, None);
}
break;
-
case Declarator::TemplateParamContext:
// C++0x [temp.param]p15:
// If a template-parameter is a [...] is a parameter-declaration that
@@ -3181,13 +3327,18 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break;
}
+ IdentifierLoc *Arg = new (S.Context) IdentifierLoc;
+ Arg->Ident = &S.Context.Idents.get(attrStr);
+ Arg->Loc = SourceLocation();
+
+ ArgsUnion Args(Arg);
+
// If there wasn't one, add one (with an invalid source location
// so that we don't make an AttributedType for it).
AttributeList *attr = D.getAttributePool()
.create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
/*scope*/ 0, SourceLocation(),
- &S.Context.Idents.get(attrStr), SourceLocation(),
- /*args*/ 0, 0, AttributeList::AS_GNU);
+ /*args*/ &Args, 1, AttributeList::AS_GNU);
spliceAttrIntoList(*attr, chunk.getAttrListRef());
// TODO: mark whether we did this inference?
@@ -3291,11 +3442,24 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
case AttributedType::attr_pascal:
return AttributeList::AT_Pascal;
case AttributedType::attr_pcs:
+ case AttributedType::attr_pcs_vfp:
return AttributeList::AT_Pcs;
case AttributedType::attr_pnaclcall:
return AttributeList::AT_PnaclCall;
case AttributedType::attr_inteloclbicc:
return AttributeList::AT_IntelOclBicc;
+ case AttributedType::attr_ms_abi:
+ return AttributeList::AT_MSABI;
+ case AttributedType::attr_sysv_abi:
+ return AttributeList::AT_SysVABI;
+ case AttributedType::attr_ptr32:
+ return AttributeList::AT_Ptr32;
+ case AttributedType::attr_ptr64:
+ return AttributeList::AT_Ptr64;
+ case AttributedType::attr_sptr:
+ return AttributeList::AT_SPtr;
+ case AttributedType::attr_uptr:
+ return AttributeList::AT_UPtr;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -3312,10 +3476,10 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
}
TL.setAttrNameLoc(attrs->getLoc());
- if (TL.hasAttrExprOperand())
- TL.setAttrExprOperand(attrs->getArg(0));
- else if (TL.hasAttrEnumOperand())
- TL.setAttrEnumOperandLoc(attrs->getParameterLoc());
+ if (TL.hasAttrExprOperand() && attrs->isArgExpr(0))
+ TL.setAttrExprOperand(attrs->getArgAsExpr(0));
+ else if (TL.hasAttrEnumOperand() && attrs->isArgIdent(0))
+ TL.setAttrEnumOperandLoc(attrs->getArgAsIdent(0)->Loc);
// FIXME: preserve this information to here.
if (TL.hasAttrOperand())
@@ -3393,9 +3557,11 @@ namespace {
TemplateSpecializationTypeLoc NamedTL = ElabTL.getNamedTypeLoc()
.castAs<TemplateSpecializationTypeLoc>();
TL.copy(NamedTL);
- }
- else
+ } else {
TL.copy(OldTL.castAs<TemplateSpecializationTypeLoc>());
+ assert(TL.getRAngleLoc() == OldTL.castAs<TemplateSpecializationTypeLoc>().getRAngleLoc());
+ }
+
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
@@ -3509,6 +3675,9 @@ namespace {
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
llvm_unreachable("qualified type locs not expected here!");
}
+ void VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ llvm_unreachable("decayed type locs not expected here!");
+ }
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
fillAttributedTypeLoc(TL, Chunk.getAttrs());
@@ -3769,15 +3938,17 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
- Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ 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_address_space_not_int)
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
<< ASArgExpr->getSourceRange();
Attr.setInvalid();
return;
@@ -3797,7 +3968,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
max = Qualifiers::MaxAddressSpace;
if (addrSpace > max) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
- << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange();
+ << int(Qualifiers::MaxAddressSpace) << ASArgExpr->getSourceRange();
Attr.setInvalid();
return;
}
@@ -3872,9 +4043,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (AttrLoc.isMacroID())
AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first;
- if (!attr.getParameterName()) {
- S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string)
- << "objc_ownership" << 1;
+ if (!attr.isArgIdent(0)) {
+ S.Diag(AttrLoc, diag::err_attribute_argument_type)
+ << attr.getName() << AANT_ArgumentString;
attr.setInvalid();
return true;
}
@@ -3884,18 +4055,19 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (!S.getLangOpts().ObjCAutoRefCount)
return true;
+ IdentifierInfo *II = attr.getArgAsIdent(0)->Ident;
Qualifiers::ObjCLifetime lifetime;
- if (attr.getParameterName()->isStr("none"))
+ if (II->isStr("none"))
lifetime = Qualifiers::OCL_ExplicitNone;
- else if (attr.getParameterName()->isStr("strong"))
+ else if (II->isStr("strong"))
lifetime = Qualifiers::OCL_Strong;
- else if (attr.getParameterName()->isStr("weak"))
+ else if (II->isStr("weak"))
lifetime = Qualifiers::OCL_Weak;
- else if (attr.getParameterName()->isStr("autoreleasing"))
+ else if (II->isStr("autoreleasing"))
lifetime = Qualifiers::OCL_Autoreleasing;
else {
S.Diag(AttrLoc, diag::warn_attribute_type_not_supported)
- << "objc_ownership" << attr.getParameterName();
+ << attr.getName() << II;
attr.setInvalid();
return true;
}
@@ -3936,8 +4108,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
case Qualifiers::OCL_Weak: name = "__weak"; break;
case Qualifiers::OCL_Autoreleasing: name = "__autoreleasing"; break;
}
- S.Diag(AttrLoc, diag::warn_objc_object_attribute_wrong_type)
- << name << type;
+ S.Diag(AttrLoc, diag::warn_type_attribute_wrong_type) << name
+ << TDS_ObjCObjOrBlock << type;
}
QualType origType = type;
@@ -4006,27 +4178,30 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state,
attr.setInvalid();
return true;
}
-
+
// Check the attribute arguments.
- if (!attr.getParameterName()) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "objc_gc" << 1;
+ if (!attr.isArgIdent(0)) {
+ S.Diag(attr.getLoc(), diag::err_attribute_argument_type)
+ << attr.getName() << AANT_ArgumentString;
attr.setInvalid();
return true;
}
Qualifiers::GC GCAttr;
- if (attr.getNumArgs() != 0) {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (attr.getNumArgs() > 1) {
+ S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << attr.getName() << 1;
attr.setInvalid();
return true;
}
- if (attr.getParameterName()->isStr("weak"))
+
+ IdentifierInfo *II = attr.getArgAsIdent(0)->Ident;
+ if (II->isStr("weak"))
GCAttr = Qualifiers::Weak;
- else if (attr.getParameterName()->isStr("strong"))
+ else if (II->isStr("strong"))
GCAttr = Qualifiers::Strong;
else {
S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
- << "objc_gc" << attr.getParameterName();
+ << attr.getName() << II;
attr.setInvalid();
return true;
}
@@ -4172,6 +4347,109 @@ namespace {
};
}
+static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
+ AttributeList &Attr,
+ QualType &Type) {
+ Sema &S = State.getSema();
+
+ AttributeList::Kind Kind = Attr.getKind();
+ QualType Desugared = Type;
+ const AttributedType *AT = dyn_cast<AttributedType>(Type);
+ while (AT) {
+ AttributedType::Kind CurAttrKind = AT->getAttrKind();
+
+ // You cannot specify duplicate type attributes, so if the attribute has
+ // already been applied, flag it.
+ if (getAttrListKind(CurAttrKind) == Kind) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact)
+ << Attr.getName();
+ return true;
+ }
+
+ // You cannot have both __sptr and __uptr on the same type, nor can you
+ // have __ptr32 and __ptr64.
+ if ((CurAttrKind == AttributedType::attr_ptr32 &&
+ Kind == AttributeList::AT_Ptr64) ||
+ (CurAttrKind == AttributedType::attr_ptr64 &&
+ Kind == AttributeList::AT_Ptr32)) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__ptr32'" << "'__ptr64'";
+ return true;
+ } else if ((CurAttrKind == AttributedType::attr_sptr &&
+ Kind == AttributeList::AT_UPtr) ||
+ (CurAttrKind == AttributedType::attr_uptr &&
+ Kind == AttributeList::AT_SPtr)) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__sptr'" << "'__uptr'";
+ return true;
+ }
+
+ Desugared = AT->getEquivalentType();
+ AT = dyn_cast<AttributedType>(Desugared);
+ }
+
+ // Pointer type qualifiers can only operate on pointer types, but not
+ // pointer-to-member types.
+ if (!isa<PointerType>(Desugared)) {
+ S.Diag(Attr.getLoc(), Type->isMemberPointerType() ?
+ diag::err_attribute_no_member_pointers :
+ diag::err_attribute_pointers_only) << Attr.getName();
+ return true;
+ }
+
+ AttributedType::Kind TAK;
+ switch (Kind) {
+ default: llvm_unreachable("Unknown attribute kind");
+ case AttributeList::AT_Ptr32: TAK = AttributedType::attr_ptr32; break;
+ case AttributeList::AT_Ptr64: TAK = AttributedType::attr_ptr64; break;
+ case AttributeList::AT_SPtr: TAK = AttributedType::attr_sptr; break;
+ case AttributeList::AT_UPtr: TAK = AttributedType::attr_uptr; break;
+ }
+
+ Type = S.Context.getAttributedType(TAK, Type, Type);
+ return false;
+}
+
+static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+ switch (Attr.getKind()) {
+ default:
+ llvm_unreachable("not a calling convention attribute");
+ case AttributeList::AT_CDecl:
+ return AttributedType::attr_cdecl;
+ case AttributeList::AT_FastCall:
+ return AttributedType::attr_fastcall;
+ case AttributeList::AT_StdCall:
+ return AttributedType::attr_stdcall;
+ case AttributeList::AT_ThisCall:
+ return AttributedType::attr_thiscall;
+ case AttributeList::AT_Pascal:
+ return AttributedType::attr_pascal;
+ case AttributeList::AT_Pcs: {
+ // The attribute may have had a fixit applied where we treated an
+ // identifier as a string literal. The contents of the string are valid,
+ // but the form may not be.
+ StringRef Str;
+ if (Attr.isArgExpr(0))
+ Str = cast<StringLiteral>(Attr.getArgAsExpr(0))->getString();
+ else
+ Str = Attr.getArgAsIdent(0)->Ident->getName();
+ return llvm::StringSwitch<AttributedType::Kind>(Str)
+ .Case("aapcs", AttributedType::attr_pcs)
+ .Case("aapcs-vfp", AttributedType::attr_pcs_vfp);
+ }
+ case AttributeList::AT_PnaclCall:
+ return AttributedType::attr_pnaclcall;
+ case AttributeList::AT_IntelOclBicc:
+ return AttributedType::attr_inteloclbicc;
+ case AttributeList::AT_MSABI:
+ return AttributedType::attr_ms_abi;
+ case AttributeList::AT_SysVABI:
+ return AttributedType::attr_sysv_abi;
+ }
+ llvm_unreachable("unexpected attribute kind!");
+}
+
/// Process an individual function attribute. Returns true to
/// indicate that the attribute was handled, false if it wasn't.
static bool handleFunctionTypeAttr(TypeProcessingState &state,
@@ -4248,34 +4526,41 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
- if (S.Context.getCanonicalCallConv(CC) ==
- S.Context.getCanonicalCallConv(CCOld)) {
- FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC);
- type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
- return true;
- }
+ AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
- if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) {
- // Should we diagnose reapplications of the same convention?
- S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
- << FunctionType::getNameForCallConv(CC)
- << FunctionType::getNameForCallConv(CCOld);
- attr.setInvalid();
- return true;
+ if (CCOld != CC) {
+ // Error out on when there's already an attribute on the type
+ // and the CCs don't match.
+ const AttributedType *AT = S.getCallingConvAttributedType(type);
+ if (AT && AT->getAttrKind() != CCAttrKind) {
+ S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << FunctionType::getNameForCallConv(CC)
+ << FunctionType::getNameForCallConv(CCOld);
+ attr.setInvalid();
+ return true;
+ }
}
- // Diagnose the use of X86 fastcall on varargs or unprototyped functions.
- if (CC == CC_X86FastCall) {
- if (isa<FunctionNoProtoType>(fn)) {
- S.Diag(attr.getLoc(), diag::err_cconv_knr)
- << FunctionType::getNameForCallConv(CC);
+ // Diagnose use of callee-cleanup calling convention on variadic functions.
+ if (isCalleeCleanup(CC)) {
+ const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
+ if (FnP && FnP->isVariadic()) {
+ unsigned DiagID = diag::err_cconv_varargs;
+ // stdcall and fastcall are ignored with a warning for GCC and MS
+ // compatibility.
+ if (CC == CC_X86StdCall || CC == CC_X86FastCall)
+ DiagID = diag::warn_cconv_varargs;
+
+ S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC);
attr.setInvalid();
return true;
}
+ }
- const FunctionProtoType *FnP = cast<FunctionProtoType>(fn);
- if (FnP->isVariadic()) {
- S.Diag(attr.getLoc(), diag::err_cconv_varargs)
+ // Diagnose the use of X86 fastcall on unprototyped functions.
+ if (CC == CC_X86FastCall) {
+ if (isa<FunctionNoProtoType>(fn)) {
+ S.Diag(attr.getLoc(), diag::err_cconv_knr)
<< FunctionType::getNameForCallConv(CC);
attr.setInvalid();
return true;
@@ -4291,27 +4576,66 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
}
+ // Modify the CC from the wrapped function type, wrap it all back, and then
+ // wrap the whole thing in an AttributedType as written. The modified type
+ // might have a different CC if we ignored the attribute.
FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
- type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ QualType Equivalent =
+ unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
return true;
}
+void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
+ const FunctionType *FT = T->castAs<FunctionType>();
+ bool IsVariadic = (isa<FunctionProtoType>(FT) &&
+ cast<FunctionProtoType>(FT)->isVariadic());
+ CallingConv CC = FT->getCallConv();
+
+ // Only adjust types with the default convention. For example, on Windows we
+ // should adjust a __cdecl type to __thiscall for instance methods, and a
+ // __thiscall type to __cdecl for static methods.
+ CallingConv DefaultCC =
+ Context.getDefaultCallingConvention(IsVariadic, IsStatic);
+ if (CC != DefaultCC)
+ return;
+
+ // Check if there was an explicit attribute, but only look through parens.
+ // The intent is to look for an attribute on the current declarator, but not
+ // one that came from a typedef.
+ QualType R = T.IgnoreParens();
+ while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
+ if (AT->isCallingConv())
+ return;
+ R = AT->getModifiedType().IgnoreParens();
+ }
+
+ // FIXME: This loses sugar. This should probably be fixed with an implicit
+ // AttributedType node that adjusts the convention.
+ CC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
+ FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC));
+ FunctionTypeUnwrapper Unwrapped(*this, T);
+ T = Unwrapped.wrap(*this, FT);
+}
+
/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
static void HandleOpenCLImageAccessAttribute(QualType& CurType,
const AttributeList &Attr,
Sema &S) {
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
- Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
llvm::APSInt arg(32);
if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
!sizeExpr->isIntegerConstantExpr(arg, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "opencl_image_access" << sizeExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << sizeExpr->getSourceRange();
Attr.setInvalid();
return;
}
@@ -4342,21 +4666,25 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
Sema &S) {
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
- Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
llvm::APSInt vecSize(32);
if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "vector_size" << sizeExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << sizeExpr->getSourceRange();
Attr.setInvalid();
return;
}
- // the base type must be integer or float, and can't already be a vector.
- if (!CurType->isIntegerType() && !CurType->isRealFloatingType()) {
+ // The base type must be integer (not Boolean or enumeration) or float, and
+ // can't already be a vector.
+ if (!CurType->isBuiltinType() || CurType->isBooleanType() ||
+ (!CurType->isIntegerType() && !CurType->isRealFloatingType())) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
Attr.setInvalid();
return;
@@ -4372,6 +4700,12 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
Attr.setInvalid();
return;
}
+ if (VectorType::isVectorSizeTooLarge(vectorSize / typeSize)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_size_too_large)
+ << sizeExpr->getSourceRange();
+ Attr.setInvalid();
+ return;
+ }
if (vectorSize == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
<< sizeExpr->getSourceRange();
@@ -4390,14 +4724,21 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
static void HandleExtVectorTypeAttr(QualType &CurType,
const AttributeList &Attr,
Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
+ return;
+ }
+
Expr *sizeExpr;
// Special case where the argument is a template id.
- if (Attr.getParameterName()) {
+ if (Attr.isArgIdent(0)) {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId id;
- id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+ id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc,
id, false, false);
@@ -4406,12 +4747,7 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
sizeExpr = Size.get();
} else {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
- sizeExpr = Attr.getArg(0);
+ sizeExpr = Attr.getArgAsExpr(0);
}
// Create the vector type.
@@ -4420,6 +4756,43 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
CurType = T;
}
+static bool isPermittedNeonBaseType(QualType &Ty,
+ VectorType::VectorKind VecKind,
+ bool IsAArch64) {
+ const BuiltinType *BTy = Ty->getAs<BuiltinType>();
+ if (!BTy)
+ return false;
+
+ if (VecKind == VectorType::NeonPolyVector) {
+ if (IsAArch64) {
+ // AArch64 polynomial vectors are unsigned and support poly64.
+ return BTy->getKind() == BuiltinType::UChar ||
+ BTy->getKind() == BuiltinType::UShort ||
+ BTy->getKind() == BuiltinType::ULongLong;
+ } else {
+ // AArch32 polynomial vector are signed.
+ return BTy->getKind() == BuiltinType::SChar ||
+ BTy->getKind() == BuiltinType::Short;
+ }
+ }
+
+ // Non-polynomial vector types: the usual suspects are allowed, as well as
+ // float64_t on AArch64.
+ if (IsAArch64 && BTy->getKind() == BuiltinType::Double)
+ return true;
+
+ return BTy->getKind() == BuiltinType::SChar ||
+ BTy->getKind() == BuiltinType::UChar ||
+ BTy->getKind() == BuiltinType::Short ||
+ BTy->getKind() == BuiltinType::UShort ||
+ BTy->getKind() == BuiltinType::Int ||
+ BTy->getKind() == BuiltinType::UInt ||
+ BTy->getKind() == BuiltinType::LongLong ||
+ BTy->getKind() == BuiltinType::ULongLong ||
+ BTy->getKind() == BuiltinType::Float ||
+ BTy->getKind() == BuiltinType::Half;
+}
+
/// HandleNeonVectorTypeAttr - The "neon_vector_type" and
/// "neon_polyvector_type" attributes are used to create vector types that
/// are mangled according to ARM's ABI. Otherwise, these types are identical
@@ -4429,43 +4802,41 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
/// match one of the standard Neon vector types.
static void HandleNeonVectorTypeAttr(QualType& CurType,
const AttributeList &Attr, Sema &S,
- VectorType::VectorKind VecKind,
- const char *AttrName) {
+ VectorType::VectorKind VecKind) {
+ // Target must have NEON
+ if (!S.Context.getTargetInfo().hasFeature("neon")) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr.getName();
+ Attr.setInvalid();
+ return;
+ }
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
// The number of elements must be an ICE.
- Expr *numEltsExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *numEltsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
llvm::APSInt numEltsInt(32);
if (numEltsExpr->isTypeDependent() || numEltsExpr->isValueDependent() ||
!numEltsExpr->isIntegerConstantExpr(numEltsInt, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << AttrName << numEltsExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << numEltsExpr->getSourceRange();
Attr.setInvalid();
return;
}
// Only certain element types are supported for Neon vectors.
- const BuiltinType* BTy = CurType->getAs<BuiltinType>();
- if (!BTy ||
- (VecKind == VectorType::NeonPolyVector &&
- BTy->getKind() != BuiltinType::SChar &&
- BTy->getKind() != BuiltinType::Short) ||
- (BTy->getKind() != BuiltinType::SChar &&
- BTy->getKind() != BuiltinType::UChar &&
- BTy->getKind() != BuiltinType::Short &&
- BTy->getKind() != BuiltinType::UShort &&
- BTy->getKind() != BuiltinType::Int &&
- BTy->getKind() != BuiltinType::UInt &&
- BTy->getKind() != BuiltinType::LongLong &&
- BTy->getKind() != BuiltinType::ULongLong &&
- BTy->getKind() != BuiltinType::Float)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) <<CurType;
+ llvm::Triple::ArchType Arch =
+ S.Context.getTargetInfo().getTriple().getArch();
+ if (!isPermittedNeonBaseType(CurType, VecKind,
+ Arch == llvm::Triple::aarch64)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
Attr.setInvalid();
return;
}
+
// The total size of the vector must be 64 or 128 bits.
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
unsigned numElts = static_cast<unsigned>(numEltsInt.getZExtValue());
@@ -4559,13 +4930,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
case AttributeList::AT_NeonVectorType:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
- VectorType::NeonVector, "neon_vector_type");
+ VectorType::NeonVector);
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_NeonPolyVectorType:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
- VectorType::NeonPolyVector,
- "neon_polyvector_type");
+ VectorType::NeonPolyVector);
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_OpenCLImageAccess:
@@ -4574,12 +4944,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
case AttributeList::AT_Win64:
- case AttributeList::AT_Ptr32:
- case AttributeList::AT_Ptr64:
- // FIXME: Don't ignore these. We have partial handling for them as
- // declaration attributes in SemaDeclAttr.cpp; that should be moved here.
attr.setUsedAsTypeAttr();
break;
+ MS_TYPE_ATTRS_CASELIST:
+ if (!handleMSPointerTypeQualifierAttr(state, attr, type))
+ attr.setUsedAsTypeAttr();
+ break;
case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
@@ -4621,41 +4991,46 @@ bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser){
// Fast path the case where the type is already complete.
if (!T->isIncompleteType())
+ // FIXME: The definition might not be visible.
return false;
// Incomplete array types may be completed by the initializer attached to
- // their definitions. For static data members of class templates we need to
- // instantiate the definition to get this initializer and complete the type.
+ // their definitions. For static data members of class templates and for
+ // variable templates, we need to instantiate the definition to get this
+ // initializer and complete the type.
if (T->isIncompleteArrayType()) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember()) {
+ if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
+ SourceLocation PointOfInstantiation = E->getExprLoc();
- MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- if (MSInfo->getTemplateSpecializationKind()
- != TSK_ExplicitSpecialization) {
+ if (MemberSpecializationInfo *MSInfo =
+ Var->getMemberSpecializationInfo()) {
// If we don't already have a point of instantiation, this is it.
if (MSInfo->getPointOfInstantiation().isInvalid()) {
- MSInfo->setPointOfInstantiation(E->getLocStart());
+ MSInfo->setPointOfInstantiation(PointOfInstantiation);
// This is a modification of an existing AST node. Notify
// listeners.
if (ASTMutationListener *L = getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
}
+ } else {
+ VarTemplateSpecializationDecl *VarSpec =
+ cast<VarTemplateSpecializationDecl>(Var);
+ if (VarSpec->getPointOfInstantiation().isInvalid())
+ VarSpec->setPointOfInstantiation(PointOfInstantiation);
+ }
- InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
- // Update the type to the newly instantiated definition's type both
- // here and within the expression.
- if (VarDecl *Def = Var->getDefinition()) {
- DRE->setDecl(Def);
- T = Def->getType();
- DRE->setType(T);
- E->setType(T);
- }
+ // Update the type to the newly instantiated definition's type both
+ // here and within the expression.
+ if (VarDecl *Def = Var->getDefinition()) {
+ DRE->setDecl(Def);
+ T = Def->getType();
+ DRE->setType(T);
+ E->setType(T);
}
// We still go on to try to complete the type independently, as it
@@ -4714,6 +5089,20 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
/// @c false otherwise.
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser) {
+ if (RequireCompleteTypeImpl(Loc, T, Diagnoser))
+ return true;
+ if (const TagType *Tag = T->getAs<TagType>()) {
+ if (!Tag->getDecl()->isCompleteDefinitionRequired()) {
+ Tag->getDecl()->setCompleteDefinitionRequired();
+ Consumer.HandleTagDeclRequiredDefinition(Tag->getDecl());
+ }
+ }
+ return false;
+}
+
+/// \brief The implementation of RequireCompleteType
+bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+ TypeDiagnoser &Diagnoser) {
// FIXME: Add this assertion to make sure we always get instantiation points.
// assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
// FIXME: Add this assertion to help us flush out problems with
@@ -4726,7 +5115,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
NamedDecl *Def = 0;
if (!T->isIncompleteType(&Def)) {
// If we know about the definition but it is not visible, complain.
- if (!Diagnoser.Suppressed && Def && !LookupResult::isVisible(Def)) {
+ if (!Diagnoser.Suppressed && Def && !LookupResult::isVisible(*this, Def)) {
// Suppress this error outside of a SFINAE context if we've already
// emitted the error once for this type. There's no usefulness in
// repeating the diagnostic.
@@ -4746,6 +5135,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
+ // FIXME: If there's an unimported definition of this type in a module (for
+ // instance, because we forward declared it, then imported the definition),
+ // import that definition now.
+ // FIXME: What about other cases where an import extends a redeclaration
+ // chain for a declaration that can be accessed through a mechanism other
+ // than name lookup (eg, referenced in a template, or a variable whose type
+ // could be completed by the module)?
+
const TagType *Tag = T->getAs<TagType>();
const ObjCInterfaceType *IFace = 0;
@@ -4808,6 +5205,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return true;
// We have an incomplete type. Produce a diagnostic.
+ if (Ident___float128 &&
+ T == Context.getTypeDeclType(Context.getFloat128StubType())) {
+ Diag(Loc, diag::err_typecheck_decl_incomplete_type___float128);
+ return true;
+ }
+
Diagnoser.diagnose(*this, Loc, T);
// If the type was a forward declaration of a class/struct/union
@@ -4822,6 +5225,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (IFace && !IFace->getDecl()->isInvalidDecl())
Diag(IFace->getDecl()->getLocation(), diag::note_forward_class);
+ // If we have external information that we can use to suggest a fix,
+ // produce a note.
+ if (ExternalSource)
+ ExternalSource->MaybeDiagnoseMissingCompleteType(Loc, T);
+
return true;
}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 2f7701227da6..45067dee9b8d 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -26,21 +26,67 @@ bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
return false;
}
+static void HandleARMInterruptAttr(Decl *d,
+ const AttributeList &Attr, Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << 1;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ if (Attr.getNumArgs() == 0)
+ Str = "";
+ else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
+ return;
+
+ ARMInterruptAttr::InterruptType Kind;
+ if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << Attr.getName() << Str << ArgLoc;
+ return;
+ }
+
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ d->addAttr(::new (S.Context)
+ ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
+}
+
+namespace {
+ class ARMAttributesSema : public TargetAttributesSema {
+ public:
+ ARMAttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ if (Attr.getName()->getName() == "interrupt") {
+ HandleARMInterruptAttr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
static void HandleMSP430InterruptAttr(Decl *d,
const AttributeList &Attr, Sema &S) {
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
return;
}
// FIXME: Check for decl - it should be void ()(void).
- Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
llvm::APSInt NumParams(32);
if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "interrupt" << NumParamsExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << NumParamsExpr->getSourceRange();
return;
}
@@ -71,61 +117,13 @@ namespace {
};
}
-static void HandleMBlazeInterruptHandlerAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
- // FIXME: Check for decl - it should be void ()(void).
-
- d->addAttr(::new (S.Context) MBlazeInterruptHandlerAttr(Attr.getLoc(),
- S.Context));
- d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
-}
-
-static void HandleMBlazeSaveVolatilesAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
-
- // FIXME: Check for decl - it should be void ()(void).
-
- d->addAttr(::new (S.Context) MBlazeSaveVolatilesAttr(Attr.getLoc(),
- S.Context));
- d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
-}
-
-
-namespace {
- class MBlazeAttributesSema : public TargetAttributesSema {
- public:
- MBlazeAttributesSema() { }
- bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
- Sema &S) const {
- if (Attr.getName()->getName() == "interrupt_handler") {
- HandleMBlazeInterruptHandlerAttr(D, Attr, S);
- return true;
- } else if (Attr.getName()->getName() == "save_volatiles") {
- HandleMBlazeSaveVolatilesAttr(D, Attr, S);
- return true;
- }
- return false;
- }
- };
-}
-
static void HandleX86ForceAlignArgPointerAttr(Decl *D,
const AttributeList& Attr,
Sema &S) {
// Check the attribute arguments.
if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
@@ -161,6 +159,15 @@ DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
if (D->hasAttr<DLLImportAttr>())
return NULL;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->hasDefinition()) {
+ // dllimport cannot be applied to definitions.
+ Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
+ << "dllimport";
+ return NULL;
+ }
+ }
+
return ::new (Context) DLLImportAttr(Range, Context,
AttrSpellingListIndex);
}
@@ -168,7 +175,8 @@ DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
@@ -214,7 +222,8 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
@@ -270,8 +279,9 @@ namespace {
static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (Attr.getNumArgs()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
// Attribute can only be applied to function types.
@@ -286,8 +296,9 @@ static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.hasParameterOrArguments()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (Attr.getNumArgs()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 0;
return;
}
// Attribute can only be applied to function types.
@@ -325,10 +336,11 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
switch (Triple.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ return *(TheTargetAttributesSema = new ARMAttributesSema);
case llvm::Triple::msp430:
return *(TheTargetAttributesSema = new MSP430AttributesSema);
- case llvm::Triple::mblaze:
- return *(TheTargetAttributesSema = new MBlazeAttributesSema);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return *(TheTargetAttributesSema = new X86AttributesSema);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 89e23ef46052..4351c2530719 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -24,6 +24,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Lookup.h"
@@ -141,7 +142,11 @@ public:
///
/// Subclasses may override this function to specify when the transformation
/// should rebuild all AST nodes.
- bool AlwaysRebuild() { return false; }
+ ///
+ /// We must always rebuild all AST nodes when performing variadic template
+ /// pack expansion, in order to avoid violating the AST invariant that each
+ /// statement node appears at most once in its containing declaration.
+ bool AlwaysRebuild() { return SemaRef.ArgumentPackSubstitutionIndex != -1; }
/// \brief Returns the location of the entity being transformed, if that
/// information was not available elsewhere in the AST.
@@ -313,6 +318,16 @@ public:
/// \returns the transformed statement.
StmtResult TransformStmt(Stmt *S);
+ /// \brief Transform the given statement.
+ ///
+ /// By default, this routine transforms a statement by delegating to the
+ /// appropriate TransformOMPXXXClause function to transform a specific kind
+ /// of clause. Subclasses may override this function to transform statements
+ /// using some other mechanism.
+ ///
+ /// \returns the transformed OpenMP clause.
+ OMPClause *TransformOMPClause(OMPClause *S);
+
/// \brief Transform the given expression.
///
/// By default, this routine transforms an expression by delegating to the
@@ -533,8 +548,7 @@ public:
CXXRecordDecl *ThisContext,
unsigned ThisTypeQuals);
- StmtResult
- TransformSEHHandler(Stmt *Handler);
+ StmtResult TransformSEHHandler(Stmt *Handler);
QualType
TransformTemplateSpecializationType(TypeLocBuilder &TLB,
@@ -579,21 +593,37 @@ public:
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
-
+
+ typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
/// \brief Transform the captures and body of a lambda expression.
- ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator,
+ ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes);
+
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *TPL) {
+ return TPL;
+ }
ExprResult TransformAddressOfOperand(Expr *E);
ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
bool IsAddressOfOperand);
+// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
+// amount of stack usage with clang.
#define STMT(Node, Parent) \
+ LLVM_ATTRIBUTE_NOINLINE \
StmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
+ LLVM_ATTRIBUTE_NOINLINE \
ExprResult Transform##Node(Node *E);
#define ABSTRACT_STMT(Stmt)
#include "clang/AST/StmtNodes.inc"
+#define OPENMP_CLAUSE(Name, Class) \
+ LLVM_ATTRIBUTE_NOINLINE \
+ OMPClause *Transform ## Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+
/// \brief Build a new pointer type given its pointee type.
///
/// By default, performs semantic analysis when building the pointer type.
@@ -767,7 +797,8 @@ public:
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
- return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
+ return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto,
+ /*IsDependent*/ false);
}
/// \brief Build a new template specialization type.
@@ -1163,10 +1194,9 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls,
- SourceLocation StartLoc,
- SourceLocation EndLoc) {
- Sema::DeclGroupPtrTy DG = getSema().BuildDeclaratorGroup(Decls, NumDecls);
+ StmtResult RebuildDeclStmt(llvm::MutableArrayRef<Decl *> Decls,
+ SourceLocation StartLoc, SourceLocation EndLoc) {
+ Sema::DeclGroupPtrTy DG = getSema().BuildDeclaratorGroup(Decls);
return getSema().ActOnDeclStmt(DG, StartLoc, EndLoc);
}
@@ -1256,6 +1286,63 @@ public:
return getSema().BuildObjCAtThrowStmt(AtLoc, Operand);
}
+ /// \brief Build a new OpenMP parallel directive.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildOMPParallelDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPParallelDirective(Clauses, AStmt,
+ StartLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'default' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDefaultClause(Kind, KindKwLoc,
+ StartLoc, LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'private' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPPrivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'firstprivate' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ OMPClause *RebuildOMPSharedClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1333,9 +1420,8 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
- Stmt *TryBlock,
- MultiStmtArg Handlers) {
+ StmtResult RebuildCXXTryStmt(SourceLocation TryLoc, Stmt *TryBlock,
+ ArrayRef<Stmt *> Handlers) {
return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers);
}
@@ -1392,22 +1478,18 @@ public:
return getSema().FinishCXXForRangeStmt(ForRange, Body);
}
- StmtResult RebuildSEHTryStmt(bool IsCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
- Stmt *Handler) {
- return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler);
+ StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc,
+ Stmt *TryBlock, Stmt *Handler) {
+ return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler);
}
- StmtResult RebuildSEHExceptStmt(SourceLocation Loc,
- Expr *FilterExpr,
+ StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr,
Stmt *Block) {
- return getSema().ActOnSEHExceptBlock(Loc,FilterExpr,Block);
+ return getSema().ActOnSEHExceptBlock(Loc, FilterExpr, Block);
}
- StmtResult RebuildSEHFinallyStmt(SourceLocation Loc,
- Stmt *Block) {
- return getSema().ActOnSEHFinallyBlock(Loc,Block);
+ StmtResult RebuildSEHFinallyStmt(SourceLocation Loc, Stmt *Block) {
+ return getSema().ActOnSEHFinallyBlock(Loc, Block);
}
/// \brief Build a new expression that references a declaration.
@@ -1767,12 +1849,10 @@ public:
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- TypeSourceInfo **Types,
- Expr **Exprs,
- unsigned NumAssocs) {
+ ArrayRef<TypeSourceInfo *> Types,
+ ArrayRef<Expr *> Exprs) {
return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
- ControllingExpr, Types, Exprs,
- NumAssocs);
+ ControllingExpr, Types, Exprs);
}
/// \brief Build a new overloaded operator call expression.
@@ -2485,6 +2565,14 @@ public:
return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.take()));
}
+ /// \brief Build a new convert vector expression.
+ ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc,
+ Expr *SrcExpr, TypeSourceInfo *DstTInfo,
+ SourceLocation RParenLoc) {
+ return SemaRef.SemaConvertVectorExpr(SrcExpr, DstTInfo,
+ BuiltinLoc, RParenLoc);
+ }
+
/// \brief Build a new template argument pack expansion.
///
/// By default, performs semantic analysis to build a new pack expansion
@@ -2603,6 +2691,23 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
return SemaRef.Owned(S);
}
+template<typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPClause(OMPClause *S) {
+ if (!S)
+ return S;
+
+ switch (S->getClauseKind()) {
+ default: break;
+ // Transform individual clause nodes
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_ ## Name : \
+ return getDerived().Transform ## Class(cast<Class>(S));
+#include "clang/Basic/OpenMPKinds.def"
+ }
+
+ return S;
+}
+
template<typename Derived>
ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
@@ -2632,12 +2737,19 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
Init = ExprTemp->getSubExpr();
+ if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
+ Init = MTE->GetTemporaryExpr();
+
while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = Binder->getSubExpr();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
Init = ICE->getSubExprAsWritten();
+ if (CXXStdInitializerListExpr *ILE =
+ dyn_cast<CXXStdInitializerListExpr>(Init))
+ return TransformInitializer(ILE->getSubExpr(), CXXDirectInit);
+
// If this is not a direct-initializer, we only need to reconstruct
// InitListExprs. Other forms of copy-initialization will be a no-op if
// the initializer is already the right type.
@@ -2675,7 +2787,7 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
Construct->getType());
// Build a ParenListExpr to represent anything else.
- SourceRange Parens = Construct->getParenRange();
+ SourceRange Parens = Construct->getParenOrBraceRange();
return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs,
Parens.getEnd());
}
@@ -3228,8 +3340,8 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
SourceLocation Ellipsis;
Optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
- = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
- getSema().Context);
+ = getSema().getTemplateArgumentPackExpansionPattern(
+ In, Ellipsis, OrigNumExpansions);
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
@@ -3421,12 +3533,13 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
Qs.removeObjCLifetime();
Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
Qs);
- Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto());
+ Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(),
+ AutoTy->isDependentType());
TLB.TypeWasModifiedSafely(Result);
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
- SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange();
+ SourceRange R = T.getUnqualifiedLoc().getSourceRange();
SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
<< Result << R;
@@ -3581,6 +3694,22 @@ QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
}
template<typename Derived>
+QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
+ DecayedTypeLoc TL) {
+ QualType OriginalType = getDerived().TransformType(TLB, TL.getOriginalLoc());
+ if (OriginalType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ OriginalType != TL.getOriginalLoc().getType())
+ Result = SemaRef.Context.getDecayedType(OriginalType);
+ TLB.push<DecayedTypeLoc>(Result);
+ // Nothing to set for DecayedTypeLoc.
+ return Result;
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL) {
QualType PointeeType
@@ -5582,8 +5711,7 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
if (!getDerived().AlwaysRebuild() && !DeclChanged)
return SemaRef.Owned(S);
- return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(),
- S->getStartLoc(), S->getEndLoc());
+ return getDerived().RebuildDeclStmt(Decls, S->getStartLoc(), S->getEndLoc());
}
template<typename Derived>
@@ -5877,23 +6005,19 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt(
Body.get());
}
-
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
// Transform the exception declaration, if any.
VarDecl *Var = 0;
- if (S->getExceptionDecl()) {
- VarDecl *ExceptionDecl = S->getExceptionDecl();
- TypeSourceInfo *T = getDerived().TransformType(
- ExceptionDecl->getTypeSourceInfo());
+ if (VarDecl *ExceptionDecl = S->getExceptionDecl()) {
+ TypeSourceInfo *T =
+ getDerived().TransformType(ExceptionDecl->getTypeSourceInfo());
if (!T)
return StmtError();
- Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T,
- ExceptionDecl->getInnerLocStart(),
- ExceptionDecl->getLocation(),
- ExceptionDecl->getIdentifier());
+ Var = getDerived().RebuildExceptionDecl(
+ ExceptionDecl, T, ExceptionDecl->getInnerLocStart(),
+ ExceptionDecl->getLocation(), ExceptionDecl->getIdentifier());
if (!Var || Var->isInvalidDecl())
return StmtError();
}
@@ -5903,31 +6027,25 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
if (Handler.isInvalid())
return StmtError();
- if (!getDerived().AlwaysRebuild() &&
- !Var &&
+ if (!getDerived().AlwaysRebuild() && !Var &&
Handler.get() == S->getHandlerBlock())
return SemaRef.Owned(S);
- return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(),
- Var,
- Handler.get());
+ return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(), Var, Handler.get());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
// Transform the try block itself.
- StmtResult TryBlock
- = getDerived().TransformCompoundStmt(S->getTryBlock());
+ StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock());
if (TryBlock.isInvalid())
return StmtError();
// Transform the handlers.
bool HandlerChanged = false;
- SmallVector<Stmt*, 8> Handlers;
+ SmallVector<Stmt *, 8> Handlers;
for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
- StmtResult Handler
- = getDerived().TransformCXXCatchStmt(S->getHandler(I));
+ StmtResult Handler = getDerived().TransformCXXCatchStmt(S->getHandler(I));
if (Handler.isInvalid())
return StmtError();
@@ -5935,8 +6053,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
Handlers.push_back(Handler.takeAs<Stmt>());
}
- if (!getDerived().AlwaysRebuild() &&
- TryBlock.get() == S->getTryBlock() &&
+ if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() &&
!HandlerChanged)
return SemaRef.Owned(S);
@@ -6108,57 +6225,166 @@ TreeTransform<Derived>::TransformMSPropertyRefExpr(MSPropertyRefExpr *E) {
QualifierLoc, E->getMemberLoc());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
- StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock());
- if(TryBlock.isInvalid()) return StmtError();
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
+ StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock());
+ if (TryBlock.isInvalid())
+ return StmtError();
StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler());
- if(!getDerived().AlwaysRebuild() &&
- TryBlock.get() == S->getTryBlock() &&
- Handler.get() == S->getHandler())
+ if (Handler.isInvalid())
+ return StmtError();
+
+ if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() &&
+ Handler.get() == S->getHandler())
return SemaRef.Owned(S);
- return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(),
- S->getTryLoc(),
- TryBlock.take(),
- Handler.take());
+ return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(),
+ TryBlock.take(), Handler.take());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
- StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock());
- if(Block.isInvalid()) return StmtError();
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
+ StmtResult Block = getDerived().TransformCompoundStmt(S->getBlock());
+ if (Block.isInvalid())
+ return StmtError();
- return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(),
- Block.take());
+ return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), Block.take());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr());
- if(FilterExpr.isInvalid()) return StmtError();
+ if (FilterExpr.isInvalid())
+ return StmtError();
- StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock());
- if(Block.isInvalid()) return StmtError();
+ StmtResult Block = getDerived().TransformCompoundStmt(S->getBlock());
+ if (Block.isInvalid())
+ return StmtError();
- return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(),
- FilterExpr.take(),
+ return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(), FilterExpr.take(),
Block.take());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
- if(isa<SEHFinallyStmt>(Handler))
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
+ if (isa<SEHFinallyStmt>(Handler))
return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler));
else
return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler));
}
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
+ DeclarationNameInfo DirName;
+ getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0);
+
+ // Transform the clauses
+ llvm::SmallVector<OMPClause *, 16> TClauses;
+ ArrayRef<OMPClause *> Clauses = D->clauses();
+ TClauses.reserve(Clauses.size());
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I) {
+ if (*I) {
+ OMPClause *Clause = getDerived().TransformOMPClause(*I);
+ if (!Clause) {
+ getSema().EndOpenMPDSABlock(0);
+ return StmtError();
+ }
+ TClauses.push_back(Clause);
+ }
+ else {
+ TClauses.push_back(0);
+ }
+ }
+ if (!D->getAssociatedStmt()) {
+ getSema().EndOpenMPDSABlock(0);
+ return StmtError();
+ }
+ StmtResult AssociatedStmt =
+ getDerived().TransformStmt(D->getAssociatedStmt());
+ if (AssociatedStmt.isInvalid()) {
+ getSema().EndOpenMPDSABlock(0);
+ return StmtError();
+ }
+
+ StmtResult Res = getDerived().RebuildOMPParallelDirective(TClauses,
+ AssociatedStmt.take(),
+ D->getLocStart(),
+ D->getLocEnd());
+ getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template<typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPDefaultClause(OMPDefaultClause *C) {
+ return getDerived().RebuildOMPDefaultClause(C->getDefaultKind(),
+ C->getDefaultKindKwLoc(),
+ C->getLocStart(),
+ C->getLParenLoc(),
+ C->getLocEnd());
+}
+
+template<typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.take());
+ }
+ return getDerived().RebuildOMPPrivateClause(Vars,
+ C->getLocStart(),
+ C->getLParenLoc(),
+ C->getLocEnd());
+}
+
+template<typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPFirstprivateClause(
+ OMPFirstprivateClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.take());
+ }
+ return getDerived().RebuildOMPFirstprivateClause(Vars,
+ C->getLocStart(),
+ C->getLParenLoc(),
+ C->getLocEnd());
+}
+
+template<typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (OMPSharedClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.take());
+ }
+ return getDerived().RebuildOMPSharedClause(Vars,
+ C->getLocStart(),
+ C->getLParenLoc(),
+ C->getLocEnd());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -6289,9 +6515,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
E->getDefaultLoc(),
E->getRParenLoc(),
ControllingExpr.release(),
- AssocTypes.data(),
- AssocExprs.data(),
- E->getNumAssocs());
+ AssocTypes,
+ AssocExprs);
}
template<typename Derived>
@@ -6323,7 +6548,11 @@ TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
- ExprResult SubExpr = TransformAddressOfOperand(E->getSubExpr());
+ ExprResult SubExpr;
+ if (E->getOpcode() == UO_AddrOf)
+ SubExpr = TransformAddressOfOperand(E->getSubExpr());
+ else
+ SubExpr = TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return ExprError();
@@ -7165,7 +7394,7 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
return SemaRef.Owned(E);
return getDerived().RebuildCXXFunctionalCastExpr(Type,
- /*FIXME:*/E->getSubExpr()->getLocStart(),
+ E->getLParenLoc(),
SubExpr.get(),
E->getRParenLoc());
}
@@ -7261,18 +7490,7 @@ TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
- DeclContext *DC = getSema().getFunctionLevelDeclContext();
- QualType T;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
- T = MD->getThisType(getSema().Context);
- else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
- T = getSema().Context.getPointerType(
- getSema().Context.getRecordType(Record));
- } else {
- assert(SemaRef.Context.getDiagnostics().hasErrorOccurred() &&
- "this in the wrong scope?");
- return ExprError();
- }
+ QualType T = getSema().getCurrentThisType();
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
// Make sure that we capture 'this'.
@@ -7602,8 +7820,10 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// This can happen because of dependent hiding.
if (isa<UsingShadowDecl>(*I))
continue;
- else
+ else {
+ R.clear();
return ExprError();
+ }
}
// Expand using declarations.
@@ -7638,8 +7858,10 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
= cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
Old->getNameLoc(),
Old->getNamingClass()));
- if (!NamingClass)
+ if (!NamingClass) {
+ R.clear();
return ExprError();
+ }
R.setNamingClass(NamingClass);
}
@@ -7657,8 +7879,10 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
if (Old->hasExplicitTemplateArgs() &&
getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
Old->getNumTemplateArgs(),
- TransArgs))
+ TransArgs)) {
+ R.clear();
return ExprError();
+ }
return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
Old->requiresADL(), &TransArgs);
@@ -7785,6 +8009,19 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
if (To.isNull())
return ExprError();
+ if (To->containsUnexpandedParameterPack()) {
+ To = getDerived().RebuildPackExpansionType(To,
+ PatternTL.getSourceRange(),
+ ExpansionTL.getEllipsisLoc(),
+ NumExpansions);
+ if (To.isNull())
+ return ExprError();
+
+ PackExpansionTypeLoc ToExpansionTL
+ = TLB.push<PackExpansionTypeLoc>(To);
+ ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
+ }
+
Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
}
@@ -7883,6 +8120,7 @@ ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E,
bool IsAddressOfOperand) {
+ assert(E->getQualifierLoc());
NestedNameSpecifierLoc QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
if (!QualifierLoc)
@@ -7974,7 +8212,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
E->isListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
- E->getParenRange());
+ E->getParenOrBraceRange());
}
/// \brief Transform a C++ temporary-binding expression.
@@ -8039,57 +8277,157 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- // Transform the type of the lambda parameters and start the definition of
- // the lambda itself.
- TypeSourceInfo *MethodTy
- = TransformType(E->getCallOperator()->getTypeSourceInfo());
- if (!MethodTy)
+
+ // Transform any init-capture expressions before entering the scope of the
+ // lambda body, because they are not semantically within that scope.
+ SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
+ InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
+ E->explicit_capture_begin());
+
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
+ if (!C->isInitCapture())
+ continue;
+ EnterExpressionEvaluationContext EEEC(getSema(),
+ Sema::PotentiallyEvaluated);
+ ExprResult NewExprInitResult = getDerived().TransformInitializer(
+ C->getCapturedVar()->getInit(),
+ C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
+
+ if (NewExprInitResult.isInvalid())
+ return ExprError();
+ Expr *NewExprInit = NewExprInitResult.get();
+
+ VarDecl *OldVD = C->getCapturedVar();
+ QualType NewInitCaptureType =
+ getSema().performLambdaInitCaptureInitialization(C->getLocation(),
+ OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
+ NewExprInit);
+ NewExprInitResult = NewExprInit;
+ InitCaptureExprsAndTypes[C - E->capture_begin()] =
+ std::make_pair(NewExprInitResult, NewInitCaptureType);
+
+ }
+
+ LambdaScopeInfo *LSI = getSema().PushLambdaScope();
+ // Transform the template parameters, and add them to the current
+ // instantiation scope. The null case is handled correctly.
+ LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList(
+ E->getTemplateParameterList());
+
+ // Check to see if the TypeSourceInfo of the call operator needs to
+ // be transformed, and if so do the transformation in the
+ // CurrentInstantiationScope.
+
+ TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+ FunctionProtoTypeLoc OldCallOpFPTL =
+ OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ TypeSourceInfo *NewCallOpTSI = 0;
+
+ const bool CallOpWasAlreadyTransformed =
+ getDerived().AlreadyTransformed(OldCallOpTSI->getType());
+
+ // Use the Old Call Operator's TypeSourceInfo if it is already transformed.
+ if (CallOpWasAlreadyTransformed)
+ NewCallOpTSI = OldCallOpTSI;
+ else {
+ // Transform the TypeSourceInfo of the Original Lambda's Call Operator.
+ // The transformation MUST be done in the CurrentInstantiationScope since
+ // it introduces a mapping of the original to the newly created
+ // transformed parameters.
+
+ TypeLocBuilder NewCallOpTLBuilder;
+ QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder,
+ OldCallOpFPTL,
+ 0, 0);
+ NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
+ NewCallOpType);
+ }
+ // Extract the ParmVarDecls from the NewCallOpTSI and add them to
+ // the vector below - this will be used to synthesize the
+ // NewCallOperator. Additionally, add the parameters of the untransformed
+ // lambda call operator to the CurrentInstantiationScope.
+ SmallVector<ParmVarDecl *, 4> Params;
+ {
+ FunctionProtoTypeLoc NewCallOpFPTL =
+ NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+ ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray();
+ const unsigned NewNumArgs = NewCallOpFPTL.getNumArgs();
+
+ for (unsigned I = 0; I < NewNumArgs; ++I) {
+ // If this call operator's type does not require transformation,
+ // the parameters do not get added to the current instantiation scope,
+ // - so ADD them! This allows the following to compile when the enclosing
+ // template is specialized and the entire lambda expression has to be
+ // transformed.
+ // template<class T> void foo(T t) {
+ // auto L = [](auto a) {
+ // auto M = [](char b) { <-- note: non-generic lambda
+ // auto N = [](auto c) {
+ // int x = sizeof(a);
+ // x = sizeof(b); <-- specifically this line
+ // x = sizeof(c);
+ // };
+ // };
+ // };
+ // }
+ // foo('a')
+ if (CallOpWasAlreadyTransformed)
+ getDerived().transformedLocalDecl(NewParamDeclArray[I],
+ NewParamDeclArray[I]);
+ // Add to Params array, so these parameters can be used to create
+ // the newly transformed call operator.
+ Params.push_back(NewParamDeclArray[I]);
+ }
+ }
+
+ if (!NewCallOpTSI)
return ExprError();
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
- MethodTy,
- /*KnownDependent=*/false);
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+ NewCallOpTSI,
+ /*KnownDependent=*/false,
+ E->getCaptureDefault());
- // Transform lambda parameters.
- SmallVector<QualType, 4> ParamTypes;
- SmallVector<ParmVarDecl *, 4> Params;
- if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
- E->getCallOperator()->param_begin(),
- E->getCallOperator()->param_size(),
- 0, ParamTypes, &Params))
- return ExprError();
+ getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
// Build the call operator.
- CXXMethodDecl *CallOperator
+ CXXMethodDecl *NewCallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- MethodTy,
+ NewCallOpTSI,
E->getCallOperator()->getLocEnd(),
Params);
- getDerived().transformAttrs(E->getCallOperator(), CallOperator);
+ LSI->CallOperator = NewCallOperator;
+
+ getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
- return getDerived().TransformLambdaScope(E, CallOperator);
+ return getDerived().TransformLambdaScope(E, NewCallOperator,
+ InitCaptureExprsAndTypes);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *CallOperator) {
+ CXXMethodDecl *CallOperator,
+ ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
+ bool Invalid = false;
+
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), CallOperator);
+ LambdaScopeInfo *const LSI = getSema().getCurLambda();
// Enter the scope of the lambda.
- sema::LambdaScopeInfo *LSI
- = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
+ getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(),
E->getCaptureDefault(),
+ E->getCaptureDefaultLoc(),
E->hasExplicitParameters(),
E->hasExplicitResultType(),
E->isMutable());
// Transform captures.
- bool Invalid = false;
bool FinishedExplicitCaptures = false;
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
@@ -8107,6 +8445,32 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
continue;
}
+ // Rebuild init-captures, including the implied field declaration.
+ if (C->isInitCapture()) {
+
+ InitCaptureInfoTy InitExprTypePair =
+ InitCaptureExprsAndTypes[C - E->capture_begin()];
+ ExprResult Init = InitExprTypePair.first;
+ QualType InitQualType = InitExprTypePair.second;
+ if (Init.isInvalid() || InitQualType.isNull()) {
+ Invalid = true;
+ continue;
+ }
+ VarDecl *OldVD = C->getCapturedVar();
+ VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
+ OldVD->getLocation(), InitExprTypePair.second,
+ OldVD->getIdentifier(), Init.get());
+ if (!NewVD)
+ Invalid = true;
+ else {
+ getDerived().transformedLocalDecl(OldVD, NewVD);
+ }
+ getSema().buildInitCaptureField(LSI, NewVD);
+ continue;
+ }
+
+ assert(C->capturesVariable() && "unexpected kind of lambda capture");
+
// Determine the capture kind for Sema.
Sema::TryCaptureKind Kind
= C->isImplicit()? Sema::TryCapture_Implicit
@@ -8123,8 +8487,10 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
C->getLocation(),
Unexpanded,
ShouldExpand, RetainExpansion,
- NumExpansions))
- return ExprError();
+ NumExpansions)) {
+ Invalid = true;
+ continue;
+ }
if (ShouldExpand) {
// The transform has determined that we should perform an expansion;
@@ -8519,6 +8885,13 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
+ CXXStdInitializerListExpr *E) {
+ return getDerived().TransformExpr(E->getSubExpr());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
return SemaRef.MaybeBindToTemporary(E);
}
@@ -8919,6 +9292,27 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformConvertVectorExpr(ConvertVectorExpr *E) {
+ ExprResult SrcExpr = getDerived().TransformExpr(E->getSrcExpr());
+ if (SrcExpr.isInvalid())
+ return ExprError();
+
+ TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+ if (!Type)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Type == E->getTypeSourceInfo() &&
+ SrcExpr.get() == E->getSrcExpr())
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildConvertVectorExpr(E->getBuiltinLoc(),
+ SrcExpr.get(), Type,
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockDecl *oldBlock = E->getBlockDecl();
@@ -8945,15 +9339,6 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getResultType());
- // Don't allow returning a objc interface by value.
- if (exprResultType->isObjCObjectType()) {
- getSema().Diag(E->getCaretLocation(),
- diag::err_object_cannot_be_passed_returned_by_value)
- << 0 << exprResultType;
- getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
- return ExprError();
- }
-
QualType functionType =
getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
exprFunctionType->getExtProtoInfo());
@@ -9080,7 +9465,7 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
};
- const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
+ const unsigned NumTypes = llvm::array_lengthof(Types);
QualType SizeType;
for (unsigned I = 0; I != NumTypes; ++I)
if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
@@ -9196,7 +9581,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
TypeDecl *Ty;
if (isa<UsingDecl>(D)) {
UsingDecl *Using = cast<UsingDecl>(D);
- assert(Using->isTypeName() &&
+ assert(Using->hasTypename() &&
"UnresolvedUsingTypenameDecl transformed to non-typename using");
// A valid resolved using typename decl points to exactly one type decl.
@@ -9295,7 +9680,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
Template);
- return Template.template getAsVal<TemplateName>();
+ return Template.get();
}
template<typename Derived>
diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp
new file mode 100644
index 000000000000..c7d43b704690
--- /dev/null
+++ b/lib/Sema/TypeLocBuilder.cpp
@@ -0,0 +1,136 @@
+//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines TypeLocBuilder, a class for building TypeLocs
+// bottom-up.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeLocBuilder.h"
+
+using namespace clang;
+
+void TypeLocBuilder::pushFullCopy(TypeLoc L) {
+ size_t Size = L.getFullDataSize();
+ reserve(Size);
+
+ SmallVector<TypeLoc, 4> TypeLocs;
+ TypeLoc CurTL = L;
+ while (CurTL) {
+ TypeLocs.push_back(CurTL);
+ CurTL = CurTL.getNextTypeLoc();
+ }
+
+ for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
+ TypeLoc CurTL = TypeLocs[e-i-1];
+ switch (CurTL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ case TypeLoc::CLASS: { \
+ CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
+ memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
+ break; \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ }
+ }
+}
+
+void TypeLocBuilder::grow(size_t NewCapacity) {
+ assert(NewCapacity > Capacity);
+
+ // Allocate the new buffer and copy the old data into it.
+ char *NewBuffer = new char[NewCapacity];
+ unsigned NewIndex = Index + NewCapacity - Capacity;
+ memcpy(&NewBuffer[NewIndex],
+ &Buffer[Index],
+ Capacity - Index);
+
+ if (Buffer != InlineBuffer.buffer)
+ delete[] Buffer;
+
+ Buffer = NewBuffer;
+ Capacity = NewCapacity;
+ Index = NewIndex;
+}
+
+TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
+#ifndef NDEBUG
+ QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
+ assert(TLast == LastTy &&
+ "mismatch between last type and new type's inner type");
+ LastTy = T;
+#endif
+
+ assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
+
+ // If we need to grow, grow by a factor of 2.
+ if (LocalSize > Index) {
+ size_t RequiredCapacity = Capacity + (LocalSize - Index);
+ size_t NewCapacity = Capacity * 2;
+ while (RequiredCapacity > NewCapacity)
+ NewCapacity *= 2;
+ grow(NewCapacity);
+ }
+
+ // Because we're adding elements to the TypeLoc backwards, we have to
+ // do some extra work to keep everything aligned appropriately.
+ // FIXME: This algorithm is a absolute mess because every TypeLoc returned
+ // needs to be valid. Partial TypeLocs are a terrible idea.
+ // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
+ // hardcode them.
+ if (LocalAlignment == 4) {
+ if (NumBytesAtAlign8 == 0) {
+ NumBytesAtAlign4 += LocalSize;
+ } else {
+ unsigned Padding = NumBytesAtAlign4 % 8;
+ if (Padding == 0) {
+ if (LocalSize % 8 == 0) {
+ // Everything is set: there's no padding and we don't need to add
+ // any.
+ } else {
+ assert(LocalSize % 8 == 4);
+ // No existing padding; add in 4 bytes padding
+ memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
+ Index -= 4;
+ }
+ } else {
+ assert(Padding == 4);
+ if (LocalSize % 8 == 0) {
+ // Everything is set: there's 4 bytes padding and we don't need
+ // to add any.
+ } else {
+ assert(LocalSize % 8 == 4);
+ // There are 4 bytes padding, but we don't need any; remove it.
+ memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
+ Index += 4;
+ }
+ }
+ NumBytesAtAlign4 += LocalSize;
+ }
+ } else if (LocalAlignment == 8) {
+ if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) {
+ // No existing padding and misaligned members; add in 4 bytes padding
+ memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
+ Index -= 4;
+ }
+ // Forget about any padding.
+ NumBytesAtAlign4 = 0;
+ NumBytesAtAlign8 += LocalSize;
+ } else {
+ assert(LocalSize == 0);
+ }
+
+ Index -= LocalSize;
+
+ assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
+ "incorrect data size provided to CreateTypeSourceInfo!");
+
+ return getTemporaryTypeLoc(T);
+}
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index f36ec9f3e209..b1e909859b2f 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -39,14 +39,19 @@ class TypeLocBuilder {
#endif
/// The inline buffer.
- char InlineBuffer[InlineCapacity];
+ enum { BufferMaxAlignment = llvm::AlignOf<void*>::Alignment };
+ llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
+ unsigned NumBytesAtAlign4, NumBytesAtAlign8;
public:
TypeLocBuilder()
- : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
+ : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
+ Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
+ {
+ }
~TypeLocBuilder() {
- if (Buffer != InlineBuffer)
+ if (Buffer != InlineBuffer.buffer)
delete[] Buffer;
}
@@ -59,23 +64,14 @@ class TypeLocBuilder {
/// Pushes a copy of the given TypeLoc onto this builder. The builder
/// must be empty for this to work.
- void pushFullCopy(TypeLoc L) {
- size_t Size = L.getFullDataSize();
- TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
- memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
- }
-
- /// Pushes uninitialized space for the given type. The builder must
- /// be empty.
- TypeLoc pushFullUninitialized(QualType T) {
- return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
- }
+ void pushFullCopy(TypeLoc L);
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
- return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
+ unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
+ return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
}
/// Resets this builder to the newly-initialized state.
@@ -84,6 +80,7 @@ class TypeLocBuilder {
LastTy = QualType();
#endif
Index = Capacity;
+ NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
}
/// \brief Tell the TypeLocBuilder that the type it is storing has been
@@ -97,8 +94,10 @@ class TypeLocBuilder {
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
- size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
- return pushImpl(T, LocalSize).castAs<TyLocType>();
+ TyLocType Loc = TypeLoc(T, 0).castAs<TyLocType>();
+ size_t LocalSize = Loc.getLocalDataSize();
+ unsigned LocalAlign = Loc.getLocalDataAlignment();
+ return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
}
/// Creates a TypeSourceInfo for the given type.
@@ -127,61 +126,12 @@ class TypeLocBuilder {
}
private:
- TypeLoc pushImpl(QualType T, size_t LocalSize) {
-#ifndef NDEBUG
- QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
- assert(TLast == LastTy &&
- "mismatch between last type and new type's inner type");
- LastTy = T;
-#endif
-
- // If we need to grow, grow by a factor of 2.
- if (LocalSize > Index) {
- size_t RequiredCapacity = Capacity + (LocalSize - Index);
- size_t NewCapacity = Capacity * 2;
- while (RequiredCapacity > NewCapacity)
- NewCapacity *= 2;
- grow(NewCapacity);
- }
- Index -= LocalSize;
-
- return getTemporaryTypeLoc(T);
- }
+ TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
/// Grow to the given capacity.
- void grow(size_t NewCapacity) {
- assert(NewCapacity > Capacity);
-
- // Allocate the new buffer and copy the old data into it.
- char *NewBuffer = new char[NewCapacity];
- unsigned NewIndex = Index + NewCapacity - Capacity;
- memcpy(&NewBuffer[NewIndex],
- &Buffer[Index],
- Capacity - Index);
-
- if (Buffer != InlineBuffer)
- delete[] Buffer;
-
- Buffer = NewBuffer;
- Capacity = NewCapacity;
- Index = NewIndex;
- }
-
- TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
-#ifndef NDEBUG
- assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
- LastTy = T;
-#endif
- assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
-
- reserve(Size);
- Index -= Size;
-
- return getTemporaryTypeLoc(T);
- }
+ void grow(size_t NewCapacity);
-public:
/// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
/// object.
///
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 24b268f36df2..a8176878dc4e 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -158,14 +158,18 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::CXXRecord:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::Function:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
+ case Decl::UsingShadow:
case Decl::Var:
case Decl::FunctionTemplate:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
case Decl::TypeAliasTemplate:
case Decl::ObjCProtocol:
case Decl::ObjCInterface:
@@ -189,7 +193,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::NonTypeTemplateParm:
case Decl::TemplateTemplateParm:
case Decl::Using:
- case Decl::UsingShadow:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl:
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index 76ef9040461c..ef81e6903243 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -25,7 +25,9 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
- UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER
+ UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+ UPD_CXX_DEDUCED_RETURN_TYPE,
+ UPD_DECL_MARKED_USED
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 22caeb8656b5..4d1b4b90b664 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -210,6 +210,8 @@ bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
namespace {
typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
MacroDefinitionsMap;
+ typedef llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> >
+ DeclsMap;
}
/// \brief Collect the macro definitions provided by the given preprocessor
@@ -377,12 +379,6 @@ bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
PP.getLangOpts());
}
-void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
- unsigned ID) {
- PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
- ++NumHeaderInfos;
-}
-
void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
PP.setCounterValue(Value);
}
@@ -765,6 +761,10 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
void ASTReader::Error(StringRef Msg) {
Error(diag::err_fe_pch_malformed, Msg);
+ if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
+ Diag(diag::note_module_cache_path)
+ << PP.getHeaderSearchInfo().getModuleCachePath();
+ }
}
void ASTReader::Error(unsigned DiagID,
@@ -1103,7 +1103,7 @@ bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
}
}
-Token ASTReader::ReadToken(ModuleFile &F, const RecordData &Record,
+Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
unsigned &Idx) {
Token Tok;
Tok.startToken();
@@ -1283,6 +1283,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
using namespace clang::io;
HeaderFileInfo HFI;
unsigned Flags = *d++;
+ HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
+ ((Flags >> 6) & 0x03);
HFI.isImport = (Flags >> 5) & 0x01;
HFI.isPragmaOnce = (Flags >> 4) & 0x01;
HFI.DirInfo = (Flags >> 2) & 0x03;
@@ -1309,7 +1311,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
FileManager &FileMgr = Reader.getFileManager();
ModuleMap &ModMap =
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
- ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false);
+ ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole());
}
}
@@ -1587,18 +1589,21 @@ void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
/// \brief For the given macro definitions, check if they are both in system
/// modules.
static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
- Module *NewOwner, ASTReader &Reader) {
+ Module *NewOwner, ASTReader &Reader) {
assert(PrevMI && NewMI);
- if (!NewOwner)
- return false;
Module *PrevOwner = 0;
if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
PrevOwner = Reader.getSubmodule(PrevModID);
- if (!PrevOwner)
- return false;
- if (PrevOwner == NewOwner)
+ SourceManager &SrcMgr = Reader.getSourceManager();
+ bool PrevInSystem
+ = PrevOwner? PrevOwner->IsSystem
+ : SrcMgr.isInSystemHeader(PrevMI->getDefinitionLoc());
+ bool NewInSystem
+ = NewOwner? NewOwner->IsSystem
+ : SrcMgr.isInSystemHeader(NewMI->getDefinitionLoc());
+ if (PrevOwner && PrevOwner == NewOwner)
return false;
- return PrevOwner->IsSystem && NewOwner->IsSystem;
+ return PrevInSystem && NewInSystem;
}
void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
@@ -1721,6 +1726,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
)) {
if (Complain) {
Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
+ if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
+ Diag(diag::note_module_cache_path)
+ << PP.getHeaderSearchInfo().getModuleCachePath();
+ }
}
IsOutOfDate = true;
@@ -2515,9 +2524,10 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case SEMA_DECL_REFS:
- // Later tables overwrite earlier ones.
- // FIXME: Modules will have some trouble with this.
- SemaDeclRefs.clear();
+ if (Record.size() != 2) {
+ Error("Invalid SEMA_DECL_REFS block");
+ return true;
+ }
for (unsigned I = 0, N = Record.size(); I != N; ++I)
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
@@ -2742,6 +2752,11 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// FIXME: Not used yet.
break;
}
+
+ case LATE_PARSED_TEMPLATE: {
+ LateParsedTemplates.append(Record.begin(), Record.end());
+ break;
+ }
}
}
}
@@ -2805,13 +2820,12 @@ void ASTReader::makeModuleVisible(Module *Mod,
bool Complain) {
llvm::SmallPtrSet<Module *, 4> Visited;
SmallVector<Module *, 4> Stack;
- Stack.push_back(Mod);
+ Stack.push_back(Mod);
while (!Stack.empty()) {
- Mod = Stack.back();
- Stack.pop_back();
+ Mod = Stack.pop_back_val();
if (NameVisibility <= Mod->NameVisibility) {
- // This module already has this level of visibility (or greater), so
+ // This module already has this level of visibility (or greater), so
// there is nothing more to do.
continue;
}
@@ -2831,16 +2845,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
makeNamesVisible(Hidden->second, Hidden->first);
HiddenNamesMap.erase(Hidden);
}
-
- // Push any non-explicit submodules onto the stack to be marked as
- // visible.
- for (Module::submodule_iterator Sub = Mod->submodule_begin(),
- SubEnd = Mod->submodule_end();
- Sub != SubEnd; ++Sub) {
- if (!(*Sub)->IsExplicit && Visited.insert(*Sub))
- Stack.push_back(*Sub);
- }
-
+
// Push any exported modules onto the stack to be marked as visible.
SmallVector<Module *, 16> Exports;
Mod->getExportedModules(Exports);
@@ -2898,6 +2903,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
SourceLocation ImportLoc,
unsigned ClientLoadCapabilities) {
+ llvm::SaveAndRestore<SourceLocation>
+ SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
+
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
@@ -3012,9 +3020,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
}
}
UnresolvedModuleRefs.clear();
+
+ // FIXME: How do we load the 'use'd modules? They may not be submodules.
+ // Might be unnecessary as use declarations are only used to build the
+ // module itself.
InitializeContext();
+ if (SemaObj)
+ UpdateSema();
+
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
@@ -3759,6 +3774,21 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
}
+ case SUBMODULE_PRIVATE_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // We lazily associate headers with their modules via the HeaderInfoTable.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
+ break;
+ }
+
case SUBMODULE_TOPHEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
@@ -3873,7 +3903,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- CurrentModule->addRequirement(Blob, Context.getLangOpts(),
+ CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
Context.getTargetInfo());
break;
}
@@ -4394,11 +4424,8 @@ namespace {
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
HeaderFileInfoVisitor Visitor(FE);
ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
- if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
- if (Listener)
- Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
+ if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
return *HFI;
- }
return HeaderFileInfo();
}
@@ -4509,6 +4536,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getPointerType(PointeeType);
}
+ case TYPE_DECAYED: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of decayed type");
+ return QualType();
+ }
+ QualType OriginalType = readType(*Loc.F, Record, Idx);
+ QualType DT = Context.getAdjustedParameterType(OriginalType);
+ if (!isa<DecayedType>(DT))
+ Error("Decayed type does not decay");
+ return DT;
+ }
+
case TYPE_BLOCK_POINTER: {
if (Record.size() != 1) {
Error("Incorrect encoding of block pointer type");
@@ -4955,6 +4994,9 @@ void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
TL.setStarLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ // nothing to do
+}
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
TL.setCaretLoc(ReadSourceLocation(Record, Idx));
}
@@ -5315,6 +5357,19 @@ ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
Record, Index));
}
+const ASTTemplateArgumentListInfo*
+ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Index) {
+ SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index);
+ SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index);
+ unsigned NumArgsAsWritten = Record[Index++];
+ TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
+ for (unsigned i = 0; i != NumArgsAsWritten; ++i)
+ TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index));
+ return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
+}
+
Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
@@ -5775,15 +5830,13 @@ namespace {
class DeclContextAllNamesVisitor {
ASTReader &Reader;
SmallVectorImpl<const DeclContext *> &Contexts;
- llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls;
+ DeclsMap &Decls;
bool VisitAll;
public:
DeclContextAllNamesVisitor(ASTReader &Reader,
SmallVectorImpl<const DeclContext *> &Contexts,
- llvm::DenseMap<DeclarationName,
- SmallVector<NamedDecl *, 8> > &Decls,
- bool VisitAll)
+ DeclsMap &Decls, bool VisitAll)
: Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
static bool visit(ModuleFile &M, void *UserData) {
@@ -5834,7 +5887,7 @@ namespace {
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
if (!DC->hasExternalVisibleStorage())
return;
- llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > Decls;
+ DeclsMap Decls;
// Compute the declaration contexts we need to look into. Multiple such
// declaration contexts occur when two declaration contexts from disjoint
@@ -5857,9 +5910,7 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
- for (llvm::DenseMap<DeclarationName,
- SmallVector<NamedDecl *, 8> >::iterator
- I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
SetExternalVisibleDeclsForName(DC, I->first, I->second);
}
const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
@@ -6080,21 +6131,13 @@ void ASTReader::InitializeSema(Sema &S) {
}
PreloadedDecls.clear();
- // Load the offsets of the declarations that Sema references.
- // They will be lazily deserialized when needed.
- if (!SemaDeclRefs.empty()) {
- assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!");
- if (!SemaObj->StdNamespace)
- SemaObj->StdNamespace = SemaDeclRefs[0];
- if (!SemaObj->StdBadAlloc)
- SemaObj->StdBadAlloc = SemaDeclRefs[1];
- }
-
+ // 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];
}
+ // FIXME: What happens if these are changed by a module import?
if (!OpenCLExtensions.empty()) {
unsigned I = 0;
#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++];
@@ -6102,6 +6145,25 @@ void ASTReader::InitializeSema(Sema &S) {
assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS");
}
+
+ UpdateSema();
+}
+
+void ASTReader::UpdateSema() {
+ assert(SemaObj && "no Sema to update");
+
+ // Load the offsets of the declarations that Sema references.
+ // They will be lazily deserialized when needed.
+ if (!SemaDeclRefs.empty()) {
+ assert(SemaDeclRefs.size() % 2 == 0);
+ for (unsigned I = 0; I != SemaDeclRefs.size(); I += 2) {
+ if (!SemaObj->StdNamespace)
+ SemaObj->StdNamespace = SemaDeclRefs[I];
+ if (!SemaObj->StdBadAlloc)
+ SemaObj->StdBadAlloc = SemaDeclRefs[I+1];
+ }
+ SemaDeclRefs.clear();
+ }
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
@@ -6440,6 +6502,29 @@ void ASTReader::ReadPendingInstantiations(
PendingInstantiations.clear();
}
+void ASTReader::ReadLateParsedTemplates(
+ llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
+ for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N;
+ /* In loop */) {
+ FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++]));
+
+ LateParsedTemplate *LT = new LateParsedTemplate;
+ LT->D = GetDecl(LateParsedTemplates[Idx++]);
+
+ ModuleFile *F = getOwningModuleFile(LT->D);
+ assert(F && "No module");
+
+ unsigned TokN = LateParsedTemplates[Idx++];
+ LT->Toks.reserve(TokN);
+ for (unsigned T = 0; T < TokN; ++T)
+ LT->Toks.push_back(ReadToken(*F, LateParsedTemplates, Idx));
+
+ LPTMap[FD] = LT;
+ }
+
+ LateParsedTemplates.clear();
+}
+
void ASTReader::LoadSelector(Selector Sel) {
// It would be complicated to avoid reading the methods anyway. So don't.
ReadMethodPool(Sel);
@@ -6887,7 +6972,7 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
void
ASTReader::
-ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
+ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
unsigned NumTemplateArgs = Record[Idx++];
@@ -6897,14 +6982,14 @@ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
}
/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
Set.reserve(Context, NumDecls);
while (NumDecls--) {
- NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
+ DeclID ID = ReadDeclID(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addDecl(Context, D, AS);
+ Set.addLazyDecl(Context, ID, AS);
}
}
@@ -6991,9 +7076,16 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
MemberOrEllipsisLoc, LParenLoc,
Init, RParenLoc);
} else {
- BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc,
- Indices.data(), Indices.size());
+ if (IndirectMember) {
+ assert(Indices.empty() && "Indirect field improperly initialized");
+ BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
+ MemberOrEllipsisLoc, LParenLoc,
+ Init, RParenLoc);
+ } else {
+ BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc,
+ Indices.data(), Indices.size());
+ }
}
if (IsWritten)
@@ -7168,7 +7260,7 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
}
DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
- return Diag(SourceLocation(), DiagID);
+ return Diag(CurrentImportLoc, DiagID);
}
DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
@@ -7251,10 +7343,14 @@ void ASTReader::ReadComments() {
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
- !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) {
+ !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
+ !PendingOdrMergeChecks.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
- llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > TopLevelDecls;
+ typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
+ TopLevelDeclsMap;
+ TopLevelDeclsMap TopLevelDecls;
+
while (!PendingIdentifierInfos.empty()) {
// FIXME: std::move
IdentifierInfo *II = PendingIdentifierInfos.back().first;
@@ -7272,9 +7368,8 @@ void ASTReader::finishPendingActions() {
PendingDeclChains.clear();
// Make the most recent of the top-level declarations visible.
- for (llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >::iterator
- TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end();
- TLD != TLDEnd; ++TLD) {
+ for (TopLevelDeclsMap::iterator TLD = TopLevelDecls.begin(),
+ TLDEnd = TopLevelDecls.end(); TLD != TLDEnd; ++TLD) {
IdentifierInfo *II = TLD->first;
for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) {
pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II);
@@ -7312,6 +7407,64 @@ void ASTReader::finishPendingActions() {
DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
}
+
+ // For each declaration from a merged context, check that the canonical
+ // definition of that context also contains a declaration of the same
+ // entity.
+ while (!PendingOdrMergeChecks.empty()) {
+ NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
+
+ // FIXME: Skip over implicit declarations for now. This matters for things
+ // like implicitly-declared special member functions. This isn't entirely
+ // correct; we can end up with multiple unmerged declarations of the same
+ // implicit entity.
+ if (D->isImplicit())
+ continue;
+
+ DeclContext *CanonDef = D->getDeclContext();
+ DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
+
+ bool Found = false;
+ const Decl *DCanon = D->getCanonicalDecl();
+
+ llvm::SmallVector<const NamedDecl*, 4> Candidates;
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
+ !Found && I != E; ++I) {
+ for (Decl::redecl_iterator RI = (*I)->redecls_begin(),
+ RE = (*I)->redecls_end();
+ RI != RE; ++RI) {
+ if ((*RI)->getLexicalDeclContext() == CanonDef) {
+ // This declaration is present in the canonical definition. If it's
+ // in the same redecl chain, it's the one we're looking for.
+ if ((*RI)->getCanonicalDecl() == DCanon)
+ Found = true;
+ else
+ Candidates.push_back(cast<NamedDecl>(*RI));
+ break;
+ }
+ }
+ }
+
+ if (!Found) {
+ D->setInvalidDecl();
+
+ Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule();
+ Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
+ << D << D->getOwningModule()->getFullModuleName()
+ << CanonDef << !CanonDefModule
+ << (CanonDefModule ? CanonDefModule->getFullModuleName() : "");
+
+ if (Candidates.empty())
+ Diag(cast<Decl>(CanonDef)->getLocation(),
+ diag::note_module_odr_violation_no_possible_decls) << D;
+ else {
+ for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
+ Diag(Candidates[I]->getLocation(),
+ diag::note_module_odr_violation_possible_decl)
+ << Candidates[I];
+ }
+ }
+ }
}
// If we deserialized any C++ or Objective-C class definitions, any
@@ -7418,7 +7571,7 @@ void ASTReader::FinishedDeserializing() {
}
void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
- D = cast<NamedDecl>(D->getMostRecentDecl());
+ D = D->getMostRecentDecl();
if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
SemaObj->TUScope->AddDecl(D);
@@ -7454,7 +7607,7 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
PassingDeclsToConsumer(false),
- NumCXXBaseSpecifiersLoaded(0)
+ NumCXXBaseSpecifiersLoaded(0), ReadingKind(Read_None)
{
SourceMgr.setExternalSLocEntrySource(this);
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index f7fa818e9b3a..b8102d84173e 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -223,16 +223,29 @@ namespace clang {
void VisitTypedefDecl(TypedefDecl *TD);
void VisitTypeAliasDecl(TypeAliasDecl *TD);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
- void VisitTagDecl(TagDecl *TD);
+ RedeclarableResult VisitTagDecl(TagDecl *TD);
void VisitEnumDecl(EnumDecl *ED);
- void VisitRecordDecl(RecordDecl *RD);
- void VisitCXXRecordDecl(CXXRecordDecl *D);
- void VisitClassTemplateSpecializationDecl(
+ RedeclarableResult VisitRecordDeclImpl(RecordDecl *RD);
+ void VisitRecordDecl(RecordDecl *RD) { VisitRecordDeclImpl(RD); }
+ RedeclarableResult VisitCXXRecordDeclImpl(CXXRecordDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D) { VisitCXXRecordDeclImpl(D); }
+ RedeclarableResult VisitClassTemplateSpecializationDeclImpl(
ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDeclImpl(D);
+ }
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
+ RedeclarableResult
+ VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDeclImpl(D);
+ }
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *VD);
void VisitEnumConstantDecl(EnumConstantDecl *ECD);
@@ -246,13 +259,15 @@ namespace clang {
void VisitFieldDecl(FieldDecl *FD);
void VisitMSPropertyDecl(MSPropertyDecl *FD);
void VisitIndirectFieldDecl(IndirectFieldDecl *FD);
- void VisitVarDecl(VarDecl *VD);
+ RedeclarableResult VisitVarDeclImpl(VarDecl *D);
+ void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); }
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
@@ -276,7 +291,14 @@ namespace clang {
template<typename T>
void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
-
+
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl);
+
+ template<typename T>
+ void mergeMergeable(Mergeable<T> *D);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -348,9 +370,11 @@ void ASTDeclReader::VisitDecl(Decl *D) {
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
// Avoid calling setLexicalDeclContext() directly because it uses
// Decl::getASTContext() internally which is unsafe during derialization.
- D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
+ D->setDeclContextsImpl(MergedSemaDC ? MergedSemaDC : SemaDC, LexicalDC,
+ Reader.getContext());
}
D->setLocation(Reader.ReadSourceLocation(F, RawLocation));
D->setInvalidDecl(Record[Idx++]);
@@ -362,7 +386,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setAttrsImpl(Attrs, Reader.getContext());
}
D->setImplicit(Record[Idx++]);
- D->setUsed(Record[Idx++]);
+ D->Used = Record[Idx++];
D->setReferenced(Record[Idx++]);
D->setTopLevelDeclInObjCContainer(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
@@ -411,8 +435,12 @@ void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
void ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
-
- TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ TypeSourceInfo *TInfo = GetTypeSourceInfo(Record, Idx);
+ if (Record[Idx++]) { // isModed
+ QualType modedT = Reader.readType(F, Record, Idx);
+ TD->setModedTypeSourceInfo(TInfo, modedT);
+ } else
+ TD->setTypeSourceInfo(TInfo);
mergeRedeclarable(TD, Redecl);
}
@@ -424,7 +452,7 @@ void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
VisitTypedefNameDecl(TD);
}
-void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
+ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
@@ -433,16 +461,18 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
TD->setCompleteDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setFreeStanding(Record[Idx++]);
+ TD->setCompleteDefinitionRequired(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
if (Record[Idx++]) { // hasExtInfo
TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
- TD->TypedefNameDeclOrQualifier = Info;
+ TD->NamedDeclOrQualifier = Info;
} else
- TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx));
+ TD->NamedDeclOrQualifier = ReadDeclAs<NamedDecl>(Record, Idx);
- mergeRedeclarable(TD, Redecl);
+ mergeRedeclarable(TD, Redecl);
+ return Redecl;
}
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -458,6 +488,19 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
ED->IsScopedUsingClassTag = Record[Idx++];
ED->IsFixed = Record[Idx++];
+ // If this is a definition subject to the ODR, and we already have a
+ // definition, merge this one into it.
+ if (ED->IsCompleteDefinition &&
+ Reader.getContext().getLangOpts().Modules &&
+ Reader.getContext().getLangOpts().CPlusPlus) {
+ if (EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]) {
+ Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef));
+ ED->IsCompleteDefinition = false;
+ } else {
+ OldDef = ED;
+ }
+ }
+
if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
@@ -466,12 +509,14 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
}
}
-void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
- VisitTagDecl(RD);
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
+ RedeclarableResult Redecl = VisitTagDecl(RD);
RD->setHasFlexibleArrayMember(Record[Idx++]);
RD->setAnonymousStructOrUnion(Record[Idx++]);
RD->setHasObjectMember(Record[Idx++]);
RD->setHasVolatileMember(Record[Idx++]);
+ return Redecl;
}
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
@@ -484,6 +529,7 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
if (Record[Idx++])
ECD->setInitExpr(Reader.ReadExpr(F));
ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
+ mergeMergeable(ECD);
}
void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
@@ -521,8 +567,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->HasImplicitReturnZero = Record[Idx++];
FD->IsConstexpr = Record[Idx++];
FD->HasSkippedBody = Record[Idx++];
- FD->HasCachedLinkage = true;
- FD->CachedLinkage = Record[Idx++];
+ FD->IsLateTemplateParsed = Record[Idx++];
+ FD->setCachedLinkage(Linkage(Record[Idx++]));
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
@@ -594,11 +640,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo::Profile(ID, TemplArgs.data(),
TemplArgs.size(), C);
void *InsertPos = 0;
- CanonTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ FunctionTemplateDecl::Common *CommonPtr = CanonTemplate->getCommonPtr();
+ CommonPtr->Specializations.FindNodeOrInsertPos(ID, InsertPos);
if (InsertPos)
- CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
- else
- assert(0 && "Another specialization already inserted!");
+ CommonPtr->Specializations.InsertNode(FTInfo, InsertPos);
+ else {
+ assert(Reader.getContext().getLangOpts().Modules &&
+ "already deserialized this template specialization");
+ // FIXME: This specialization is a redeclaration of one from another
+ // module. Merge it.
+ }
}
break;
}
@@ -747,6 +798,8 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
IVD->setNextIvar(0);
bool synth = Record[Idx++];
IVD->setSynthesize(synth);
+ bool backingIvarReferencedInAccessor = Record[Idx++];
+ IVD->setBackingIvarReferencedInAccessor(backingIvarReferencedInAccessor);
}
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
@@ -880,6 +933,7 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx))
Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
}
+ mergeMergeable(FD);
}
void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) {
@@ -899,7 +953,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx);
}
-void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
+ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
@@ -911,11 +965,18 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
VD->VarDeclBits.IsConstexpr = Record[Idx++];
- VD->HasCachedLinkage = true;
- VD->CachedLinkage = Record[Idx++];
-
+ VD->VarDeclBits.IsInitCapture = Record[Idx++];
+ VD->VarDeclBits.PreviousDeclInSameBlockScope = Record[Idx++];
+ Linkage VarLinkage = Linkage(Record[Idx++]);
+ VD->setCachedLinkage(VarLinkage);
+
+ // Reconstruct the one piece of the IdentifierNamespace that we need.
+ if (VarLinkage != NoLinkage &&
+ VD->getLexicalDeclContext()->isFunctionOrMethod())
+ VD->setLocalExternDecl();
+
// Only true variables (not parameters or implicit parameters) can be merged.
- if (VD->getKind() == Decl::Var)
+ if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
mergeRedeclarable(VD, Redecl);
if (uint64_t Val = Record[Idx++]) {
@@ -927,12 +988,25 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
}
}
- if (Record[Idx++]) { // HasMemberSpecializationInfo.
+ enum VarKind {
+ VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+ };
+ switch ((VarKind)Record[Idx++]) {
+ case VarNotTemplate:
+ break;
+ case VarTemplate:
+ VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
+ break;
+ case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ break;
}
+ }
+
+ return Redecl;
}
void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
@@ -956,6 +1030,9 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++];
if (Record[Idx++]) // hasUninstantiatedDefaultArg.
PD->setUninstantiatedDefaultArg(Reader.ReadExpr(F));
+
+ // FIXME: If this is a redeclaration of a function from another module, handle
+ // inheritance of default arguments.
}
void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
@@ -1022,6 +1099,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
D->setInline(Record[Idx++]);
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
+ // FIXME: At the point of this call, D->getCanonicalDecl() returns 0.
mergeRedeclarable(D, Redecl);
if (Redecl.getFirstID() == ThisDeclID) {
@@ -1034,7 +1112,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
} else {
// Link this namespace back to the first declaration, which has already
// been deserialized.
- D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDeclaration());
+ D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDecl());
}
}
@@ -1048,22 +1126,24 @@ void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
VisitNamedDecl(D);
- D->setUsingLocation(ReadSourceLocation(Record, Idx));
+ D->setUsingLoc(ReadSourceLocation(Record, Idx));
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>(Record, Idx));
- D->setTypeName(Record[Idx++]);
+ D->setTypename(Record[Idx++]);
if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
}
void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
D->setTargetDecl(ReadDeclAs<NamedDecl>(Record, Idx));
D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(Record, Idx);
UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>(Record, Idx);
if (Pattern)
Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern);
+ mergeRedeclarable(D, Redecl);
}
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
@@ -1128,8 +1208,6 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
- Data.FailedImplicitMoveConstructor = Record[Idx++];
- Data.FailedImplicitMoveAssignment = Record[Idx++];
Data.NumBases = Record[Idx++];
if (Data.NumBases)
@@ -1141,13 +1219,15 @@ void ASTDeclReader::ReadCXXDefinitionData(
Reader.ReadUnresolvedSet(F, Data.Conversions, Record, Idx);
Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx);
assert(Data.Definition && "Data.Definition should be already set!");
- Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx);
-
+ Data.FirstFriend = ReadDeclID(Record, Idx);
+
if (Data.IsLambda) {
typedef LambdaExpr::Capture Capture;
CXXRecordDecl::LambdaDefinitionData &Lambda
= static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
Lambda.Dependent = Record[Idx++];
+ Lambda.IsGenericLambda = Record[Idx++];
+ Lambda.CaptureDefault = Record[Idx++];
Lambda.NumCaptures = Record[Idx++];
Lambda.NumExplicitCaptures = Record[Idx++];
Lambda.ManglingNumber = Record[Idx++];
@@ -1160,41 +1240,65 @@ void ASTDeclReader::ReadCXXDefinitionData(
SourceLocation Loc = ReadSourceLocation(Record, Idx);
bool IsImplicit = Record[Idx++];
LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
- VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
- SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
- *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
+ switch (Kind) {
+ case LCK_This:
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, 0, SourceLocation());
+ break;
+ case LCK_ByCopy:
+ case LCK_ByRef:
+ VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
+ SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
+ break;
+ }
}
}
}
-void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
- VisitRecordDecl(D);
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
+ RedeclarableResult Redecl = VisitRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- if (Record[Idx++]) {
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition) {
// Determine whether this is a lambda closure type, so that we can
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record[Idx++];
if (IsLambda)
D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0,
- false);
+ false,
+ false, LCD_None);
else
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
-
+
+ ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
+
// Propagate the DefinitionData pointer to the canonical declaration, so
// that all other deserialized declarations will see it.
- // FIXME: Complain if there already is a DefinitionData!
- D->getCanonicalDecl()->DefinitionData = D->DefinitionData;
-
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
-
- // Note that we have deserialized a definition. Any declarations
- // deserialized before this one will be be given the DefinitionData pointer
- // at the end.
- Reader.PendingDefinitions.insert(D);
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (Canon == D) {
+ // Nothing to do.
+ } else if (!Canon->DefinitionData) {
+ Canon->DefinitionData = D->DefinitionData;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ // FIXME: Check DefinitionData for consistency with prior definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, D->getCanonicalDecl()->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ }
} else {
// Propagate DefinitionData pointer from the canonical declaration.
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
}
enum CXXRecKind {
@@ -1217,12 +1321,15 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
}
}
- // Load the key function to avoid deserializing every method so we can
+ // Lazily load the key function to avoid deserializing every method so we can
// compute it.
- if (D->IsCompleteDefinition) {
- if (CXXMethodDecl *Key = ReadDeclAs<CXXMethodDecl>(Record, Idx))
- C.KeyFunctions[D] = Key;
+ if (WasDefinition) {
+ DeclID KeyFn = ReadDeclID(Record, Idx);
+ if (KeyFn && D->IsCompleteDefinition)
+ C.KeyFunctions[D] = KeyFn;
}
+
+ return Redecl;
}
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
@@ -1240,7 +1347,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
VisitCXXMethodDecl(D);
D->IsExplicitSpecified = Record[Idx++];
- D->ImplicitlyDefined = Record[Idx++];
llvm::tie(D->CtorInitializers, D->NumCtorInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
@@ -1248,7 +1354,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- D->ImplicitlyDefined = Record[Idx++];
D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
}
@@ -1280,7 +1385,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
D->Friend = GetTypeSourceInfo(Record, Idx);
for (unsigned i = 0; i != D->NumTPLists; ++i)
D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
- D->NextFriend = Record[Idx++];
+ D->NextFriend = ReadDeclID(Record, Idx);
D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
}
@@ -1306,6 +1411,9 @@ void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
TemplateParameterList* TemplateParams
= Reader.ReadTemplateParameterList(F, Record, Idx);
D->init(TemplatedDecl, TemplateParams);
+
+ // FIXME: If this is a redeclaration of a template from another module, handle
+ // inheritance of default template arguments.
}
ASTDeclReader::RedeclarableResult
@@ -1339,6 +1447,11 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
mergeRedeclarable(D, Redecl);
+ // If we merged the template with a prior declaration chain, merge the common
+ // pointer.
+ // FIXME: Actually merge here, don't just overwrite.
+ D->Common = D->getCanonicalDecl()->Common;
+
return Redecl;
}
@@ -1378,9 +1491,47 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
}
-void ASTDeclReader::VisitClassTemplateSpecializationDecl(
- ClassTemplateSpecializationDecl *D) {
- VisitCXXRecordDecl(D);
+/// TODO: Unify with ClassTemplateDecl version?
+/// May require unifying ClassTemplateDecl and
+/// VarTemplateDecl beyond TemplateDecl...
+void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+
+ if (ThisDeclID == Redecl.getFirstID()) {
+ // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
+ // the specializations.
+ SmallVector<serialization::DeclID, 2> SpecIDs;
+ SpecIDs.push_back(0);
+
+ // Specializations.
+ unsigned Size = Record[Idx++];
+ SpecIDs[0] += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
+
+ // Partial specializations.
+ Size = Record[Idx++];
+ SpecIDs[0] += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
+
+ VarTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+ if (SpecIDs[0]) {
+ typedef serialization::DeclID DeclID;
+
+ // FIXME: Append specializations!
+ CommonPtr->LazySpecializations =
+ new (Reader.getContext()) DeclID[SpecIDs.size()];
+ memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
+ SpecIDs.size() * sizeof(DeclID));
+ }
+ }
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
+ ClassTemplateSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
if (Decl *InstD = ReadDecl(Record, Idx)) {
@@ -1402,16 +1553,6 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
}
}
- // Explicit info.
- if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
- ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
- = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
- ExplicitInfo->TypeAsWritten = TyInfo;
- ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
- ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
- D->ExplicitInfo = ExplicitInfo;
- }
-
SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
@@ -1423,35 +1564,60 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
if (writtenAsCanonicalDecl) {
ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
if (D->isCanonicalDecl()) { // It's kept in the folding set.
- if (ClassTemplatePartialSpecializationDecl *Partial
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
- CanonPattern->getCommonPtr()->PartialSpecializations.GetOrInsertNode(Partial);
+ // Set this as, or find, the canonical declaration for this specialization
+ ClassTemplateSpecializationDecl *CanonSpec;
+ if (ClassTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+ CanonSpec = CanonPattern->getCommonPtr()->PartialSpecializations
+ .GetOrInsertNode(Partial);
} else {
- CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ CanonSpec =
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ // If there was already a canonical specialization, merge into it.
+ if (CanonSpec != D) {
+ mergeRedeclarable<TagDecl>(D, CanonSpec, Redecl);
+
+ // This declaration might be a definition. Merge with any existing
+ // definition.
+ if (D->DefinitionData) {
+ if (!CanonSpec->DefinitionData) {
+ CanonSpec->DefinitionData = D->DefinitionData;
+ } else {
+ // FIXME: Check DefinitionData for consistency with prior definition
+ Reader.PendingDefinitions.erase(D);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonSpec->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = CanonSpec->DefinitionData;
+ }
+ }
}
}
}
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
+ = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ return Redecl;
}
void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
- VisitClassTemplateSpecializationDecl(D);
+ RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
- ASTContext &C = Reader.getContext();
D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
-
- unsigned NumArgs = Record[Idx++];
- if (NumArgs) {
- D->NumArgsAsWritten = NumArgs;
- D->ArgsAsWritten = new (C) TemplateArgumentLoc[NumArgs];
- for (unsigned i=0; i != NumArgs; ++i)
- D->ArgsAsWritten[i] = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
- }
-
- D->SequenceNumber = Record[Idx++];
+ D->ArgsAsWritten = Reader.ReadASTTemplateArgumentListInfo(F, Record, Idx);
// These are read/set from/to the first declaration.
- if (D->getPreviousDecl() == 0) {
+ if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx));
D->InstantiatedFromMember.setInt(Record[Idx++]);
@@ -1470,12 +1636,100 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
- // Read the function specialization declarations.
- // FunctionTemplateDecl's FunctionTemplateSpecializationInfos are filled
- // when reading the specialized FunctionDecl.
- unsigned NumSpecs = Record[Idx++];
- while (NumSpecs--)
- (void)ReadDecl(Record, Idx);
+ // Read the function specialization declaration IDs. The specializations
+ // themselves will be loaded if they're needed.
+ if (unsigned NumSpecs = Record[Idx++]) {
+ // FIXME: Append specializations!
+ FunctionTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = new (Reader.getContext())
+ serialization::DeclID[NumSpecs + 1];
+ CommonPtr->LazySpecializations[0] = NumSpecs;
+ for (unsigned I = 0; I != NumSpecs; ++I)
+ CommonPtr->LazySpecializations[I + 1] = ReadDeclID(Record, Idx);
+ }
+ }
+}
+
+/// TODO: Unify with ClassTemplateSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
+ VarTemplateSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+ if (Decl *InstD = ReadDecl(Record, Idx)) {
+ if (VarTemplateDecl *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
+ D->SpecializedTemplate = VTD;
+ } else {
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy(
+ C, TemplArgs.data(), TemplArgs.size());
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization *PS =
+ new (C)
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization();
+ PS->PartialSpecialization =
+ cast<VarTemplatePartialSpecializationDecl>(InstD);
+ PS->TemplateArgs = ArgList;
+ D->SpecializedTemplate = PS;
+ }
+ }
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ VarTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo =
+ new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ D->TemplateArgs =
+ TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size());
+ D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
+ D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
+ VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {
+ CanonPattern->getCommonPtr()->PartialSpecializations
+ .GetOrInsertNode(Partial);
+ } else {
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ }
+ }
+
+ return Redecl;
+}
+
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
+
+ D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->ArgsAsWritten = Reader.ReadASTTemplateArgumentListInfo(F, Record, Idx);
+
+ // These are read/set from/to the first declaration.
+ if (ThisDeclID == Redecl.getFirstID()) {
+ D->InstantiatedFromMember.setPointer(
+ ReadDeclAs<VarTemplatePartialSpecializationDecl>(Record, Idx));
+ D->InstantiatedFromMember.setInt(Record[Idx++]);
}
}
@@ -1584,70 +1838,98 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
RedeclarableResult &Redecl) {
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
-
- if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) {
- if (T *Existing = ExistingRes) {
- T *ExistingCanon = Existing->getCanonicalDecl();
- T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
- if (ExistingCanon != DCanon) {
- // Have our redeclaration link point back at the canonical declaration
- // of the existing declaration, so that this declaration has the
- // appropriate canonical declaration.
- D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
-
- // When we merge a namespace, update its pointer to the first namespace.
- if (NamespaceDecl *Namespace
- = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
- Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
- }
-
- // Don't introduce DCanon into the set of pending declaration chains.
- Redecl.suppress();
-
- // Introduce ExistingCanon into the set of pending declaration chains,
- // if in fact it came from a module file.
- if (ExistingCanon->isFromASTFile()) {
- GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
- assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
- if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
- Reader.PendingDeclChains.push_back(ExistingCanonID);
- }
-
- // If this declaration was the canonical declaration, make a note of
- // that. We accept the linear algorithm here because the number of
- // unique canonical declarations of an entity should always be tiny.
- if (DCanon == static_cast<T*>(D)) {
- SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
- if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
- == Merged.end())
- Merged.push_back(Redecl.getFirstID());
-
- // If ExistingCanon did not come from a module file, introduce the
- // first declaration that *does* come from a module file to the
- // set of pending declaration chains, so that we merge this
- // declaration.
- if (!ExistingCanon->isFromASTFile() &&
- Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
- Reader.PendingDeclChains.push_back(Merged[0]);
- }
- }
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (T *Existing = ExistingRes)
+ mergeRedeclarable(D, Existing, Redecl);
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl) {
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ if (ExistingCanon != DCanon) {
+ // Have our redeclaration link point back at the canonical declaration
+ // of the existing declaration, so that this declaration has the
+ // appropriate canonical declaration.
+ D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+
+ // When we merge a namespace, update its pointer to the first namespace.
+ if (NamespaceDecl *Namespace
+ = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
+ // Don't introduce DCanon into the set of pending declaration chains.
+ Redecl.suppress();
+
+ // Introduce ExistingCanon into the set of pending declaration chains,
+ // if in fact it came from a module file.
+ if (ExistingCanon->isFromASTFile()) {
+ GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
+ assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
+ Reader.PendingDeclChains.push_back(ExistingCanonID);
+ }
+
+ // If this declaration was the canonical declaration, make a note of
+ // that. We accept the linear algorithm here because the number of
+ // unique canonical declarations of an entity should always be tiny.
+ if (DCanon == static_cast<T*>(D)) {
+ SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
+ if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
+ == Merged.end())
+ Merged.push_back(Redecl.getFirstID());
+
+ // If ExistingCanon did not come from a module file, introduce the
+ // first declaration that *does* come from a module file to the
+ // set of pending declaration chains, so that we merge this
+ // declaration.
+ if (!ExistingCanon->isFromASTFile() &&
+ Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+ Reader.PendingDeclChains.push_back(Merged[0]);
}
}
}
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity, for the case where the entity is not actually
+/// redeclarable. This happens, for instance, when merging the fields of
+/// identical class definitions from two different modules.
+template<typename T>
+void ASTDeclReader::mergeMergeable(Mergeable<T> *D) {
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
+ return;
+
+ // ODR-based merging is only performed in C++. In C, identically-named things
+ // in different translation units are not redeclarations (but may still have
+ // compatible types).
+ if (!Reader.getContext().getLangOpts().CPlusPlus)
+ return;
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (T *Existing = ExistingRes)
+ Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D),
+ Existing->getCanonicalDecl());
+}
+
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
VisitDecl(D);
unsigned NumVars = D->varlist_size();
- SmallVector<DeclRefExpr *, 16> Vars;
+ SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i) {
- Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
+ Vars.push_back(Reader.ReadExpr(F));
}
D->setVars(Vars);
}
@@ -1741,6 +2023,48 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) {
return LocalOffset + M.GlobalBitOffset;
}
+static bool isSameTemplateParameterList(const TemplateParameterList *X,
+ const TemplateParameterList *Y);
+
+/// \brief Determine whether two template parameters are similar enough
+/// that they may be used in declarations of the same template.
+static bool isSameTemplateParameter(const NamedDecl *X,
+ const NamedDecl *Y) {
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ if (const TemplateTypeParmDecl *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
+ const TemplateTypeParmDecl *TY = cast<TemplateTypeParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack();
+ }
+
+ if (const NonTypeTemplateParmDecl *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
+ const NonTypeTemplateParmDecl *TY = cast<NonTypeTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ }
+
+ const TemplateTemplateParmDecl *TX = cast<TemplateTemplateParmDecl>(X);
+ const TemplateTemplateParmDecl *TY = cast<TemplateTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ isSameTemplateParameterList(TX->getTemplateParameters(),
+ TY->getTemplateParameters());
+}
+
+/// \brief Determine whether two template parameter lists are similar enough
+/// that they may be used in declarations of the same template.
+static bool isSameTemplateParameterList(const TemplateParameterList *X,
+ const TemplateParameterList *Y) {
+ if (X->size() != Y->size())
+ return false;
+
+ for (unsigned I = 0, N = X->size(); I != N; ++I)
+ if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
+ return false;
+
+ return true;
+}
+
/// \brief Determine whether the two declarations refer to the same entity.
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
@@ -1767,7 +2091,13 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
// Objective-C classes and protocols with the same name always match.
if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
return true;
-
+
+ if (isa<ClassTemplateSpecializationDecl>(X)) {
+ // No need to handle these here: we merge them when adding them to the
+ // template.
+ return false;
+ }
+
// Compatible tags match.
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
TagDecl *TagY = cast<TagDecl>(Y);
@@ -1777,48 +2107,90 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
(TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
TagY->getTagKind() == TTK_Interface));
}
-
+
// Functions with the same type and linkage match.
- // FIXME: This needs to cope with function templates, merging of
- //prototyped/non-prototyped functions, etc.
+ // FIXME: This needs to cope with function template specializations,
+ // merging of prototyped/non-prototyped functions, etc.
if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
FunctionDecl *FuncY = cast<FunctionDecl>(Y);
- return (FuncX->getLinkage() == FuncY->getLinkage()) &&
+ return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
}
// Variables with the same type and linkage match.
if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
VarDecl *VarY = cast<VarDecl>(Y);
- return (VarX->getLinkage() == VarY->getLinkage()) &&
+ return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) &&
VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
}
-
+
// Namespaces with the same name and inlinedness match.
if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
return NamespaceX->isInline() == NamespaceY->isInline();
}
- // Identical template names and kinds match.
- if (isa<TemplateDecl>(X))
+ // Identical template names and kinds match if their template parameter lists
+ // and patterns match.
+ if (TemplateDecl *TemplateX = dyn_cast<TemplateDecl>(X)) {
+ TemplateDecl *TemplateY = cast<TemplateDecl>(Y);
+ return isSameEntity(TemplateX->getTemplatedDecl(),
+ TemplateY->getTemplatedDecl()) &&
+ isSameTemplateParameterList(TemplateX->getTemplateParameters(),
+ TemplateY->getTemplateParameters());
+ }
+
+ // Fields with the same name and the same type match.
+ if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
+ FieldDecl *FDY = cast<FieldDecl>(Y);
+ // FIXME: Diagnose if the types don't match. More generally, diagnose if we
+ // get a declaration in a class definition that isn't in the canonical class
+ // definition.
+ // FIXME: Also check the bitwidth is odr-equivalent, if any.
+ return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
+ }
+
+ // Enumerators with the same name match.
+ if (isa<EnumConstantDecl>(X))
+ // FIXME: Also check the value is odr-equivalent.
return true;
+ // Using shadow declarations with the same target match.
+ if (UsingShadowDecl *USX = dyn_cast<UsingShadowDecl>(X)) {
+ UsingShadowDecl *USY = cast<UsingShadowDecl>(Y);
+ return USX->getTargetDecl() == USY->getTargetDecl();
+ }
+
// FIXME: Many other cases to implement.
return false;
}
+/// Find the context in which we should search for previous declarations when
+/// looking for declarations to merge.
+static DeclContext *getPrimaryContextForMerging(DeclContext *DC) {
+ if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ return ND->getOriginalNamespace();
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ return RD->getDefinition();
+
+ if (EnumDecl *ED = dyn_cast<EnumDecl>(DC))
+ return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition() : 0;
+
+ return 0;
+}
+
ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
-
- if (New->getDeclContext()->getRedeclContext()->isTranslationUnit()
- && Reader.SemaObj) {
+
+ DeclContext *DC = New->getDeclContext()->getRedeclContext();
+ if (DC->isTranslationUnit() && Reader.SemaObj) {
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
- } else {
- DeclContext *DC = New->getLexicalDeclContext();
- if (DC->isNamespace())
- DC->addDecl(New);
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
+ // Add the declaration to its redeclaration context so later merging
+ // lookups will find it.
+ MergeDC->makeDeclVisibleInContextImpl(New, /*Internal*/true);
}
}
@@ -1830,11 +2202,11 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
Result.suppress();
return Result;
}
-
+
+ // FIXME: Bail out for non-canonical declarations. We will have performed any
+ // necessary merging already.
+
DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (!DC->isFileContext())
- return FindExistingResult(Reader);
-
if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
@@ -1867,17 +2239,22 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
- }
-
- if (DC->isNamespace()) {
- DeclContext::lookup_result R = DC->lookup(Name);
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
- ++I) {
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
+ DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
+ } else {
+ // Not in a mergeable context.
+ return FindExistingResult(Reader);
}
-
+
+ // If this declaration is from a merged context, make a note that we need to
+ // check that the canonical definition of that context contains the decl.
+ if (Reader.MergedDeclContexts.count(D->getLexicalDeclContext()))
+ Reader.PendingOdrMergeChecks.push_back(D);
+
return FindExistingResult(Reader, D, /*Existing=*/0);
}
@@ -1891,6 +2268,8 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
VD->RedeclLink.setNext(cast<VarDecl>(previous));
} else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
TD->RedeclLink.setNext(cast<TypedefNameDecl>(previous));
+ } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
+ USD->RedeclLink.setNext(cast<UsingShadowDecl>(previous));
} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
ID->RedeclLink.setNext(cast<ObjCInterfaceDecl>(previous));
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
@@ -1901,6 +2280,15 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
TD->RedeclLink.setNext(cast<RedeclarableTemplateDecl>(previous));
}
+
+ // If the declaration was visible in one module, a redeclaration of it in
+ // another module remains visible even if it wouldn't be visible by itself.
+ //
+ // FIXME: In this case, the declaration should only be visible if a module
+ // that makes it visible has been imported.
+ D->IdentifierNamespace |=
+ previous->IdentifierNamespace &
+ (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
}
void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
@@ -1909,7 +2297,7 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
TD->RedeclLink
= Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest));
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- FD->RedeclLink
+ FD->RedeclLink
= Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest));
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
VD->RedeclLink
@@ -1918,6 +2306,10 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
TD->RedeclLink
= Redeclarable<TypedefNameDecl>::LatestDeclLink(
cast<TypedefNameDecl>(Latest));
+ } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
+ USD->RedeclLink
+ = Redeclarable<UsingShadowDecl>::LatestDeclLink(
+ cast<UsingShadowDecl>(Latest));
} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
ID->RedeclLink
= Redeclarable<ObjCInterfaceDecl>::LatestDeclLink(
@@ -1961,11 +2353,6 @@ ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
return Pos;
}
-void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
- Decl *previous = GetDecl(ID);
- ASTDeclReader::attachPreviousDecl(D, previous);
-}
-
/// \brief Read the declaration at the given offset from the AST file.
Decl *ASTReader::ReadDeclRecord(DeclID ID) {
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
@@ -2070,6 +2457,15 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_VAR_TEMPLATE:
+ D = VarTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_SPECIALIZATION:
+ D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION:
+ D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
break;
@@ -2397,7 +2793,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (Chain[I] == CanonDecl)
continue;
-
+
ASTDeclReader::attachPreviousDecl(Chain[I], MostRecent);
MostRecent = Chain[I];
}
@@ -2582,6 +2978,20 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
+
+ case UPD_CXX_DEDUCED_RETURN_TYPE: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ Reader.Context.adjustDeducedFunctionResultType(
+ FD, Reader.readType(ModuleFile, Record, Idx));
+ break;
+ }
+
+ case UPD_DECL_MARKED_USED: {
+ // FIXME: This doesn't send the right notifications if there are
+ // ASTMutationListeners other than an ASTWriter.
+ D->Used = true;
+ break;
+ }
}
}
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index e1357ba5e696..1115e8fd4f45 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -25,6 +25,7 @@ using namespace clang::serialization;
namespace clang {
class ASTStmtReader : public StmtVisitor<ASTStmtReader> {
+ friend class OMPClauseReader;
typedef ASTReader::RecordData RecordData;
ASTReader &Reader;
@@ -382,6 +383,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
+ ++Idx;
S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx));
S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++]));
S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx));
@@ -723,7 +725,6 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
} else
E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx);
E->sawArrayRangeDesignator(Record[Idx++]);
- E->setInitializesStdInitializerList(Record[Idx++]);
unsigned NumInits = Record[Idx++];
E->reserveInits(Reader.getContext(), NumInits);
if (isArrayFiller) {
@@ -834,6 +835,7 @@ void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) {
E->setRHS(Reader.ReadSubExpr());
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setIsConditionTrue(Record[Idx++]);
}
void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
@@ -847,11 +849,19 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
unsigned NumExprs = Record[Idx++];
while (NumExprs--)
Exprs.push_back(Reader.ReadSubExpr());
- E->setExprs(Reader.getContext(), Exprs.data(), Exprs.size());
+ E->setExprs(Reader.getContext(), Exprs);
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+ VisitExpr(E);
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->TInfo = GetTypeSourceInfo(Record, Idx);
+ E->SrcExpr = Reader.ReadSubExpr();
+}
+
void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
@@ -1190,7 +1200,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setListInitialization(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
- E->ParenRange = ReadSourceRange(Record, Idx);
+ E->ParenOrBraceRange = ReadSourceRange(Record, Idx);
}
void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
@@ -1205,6 +1215,7 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
unsigned NumArrayIndexVars = Record[Idx++];
E->IntroducerRange = ReadSourceRange(Record, Idx);
E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record[Idx++]);
+ E->CaptureDefaultLoc = ReadSourceLocation(Record, Idx);
E->ExplicitParams = Record[Idx++];
E->ExplicitResultType = Record[Idx++];
E->ClosingBrace = ReadSourceLocation(Record, Idx);
@@ -1227,6 +1238,12 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
}
}
+void
+ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ E->SubExpr = Reader.ReadSubExpr();
+}
+
void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
SourceRange R = ReadSourceRange(Record, Idx);
@@ -1254,7 +1271,7 @@ void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
VisitExplicitCastExpr(E);
- E->setTypeBeginLoc(ReadSourceLocation(Record, Idx));
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
@@ -1576,6 +1593,7 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
E->Temporary = Reader.ReadSubExpr();
+ E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);
}
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
@@ -1650,11 +1668,114 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
}
//===----------------------------------------------------------------------===//
+// OpenMP Clauses.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+class OMPClauseReader : public OMPClauseVisitor<OMPClauseReader> {
+ ASTStmtReader *Reader;
+ ASTContext &Context;
+ const ASTReader::RecordData &Record;
+ unsigned &Idx;
+public:
+ OMPClauseReader(ASTStmtReader *R, ASTContext &C,
+ const ASTReader::RecordData &Record, unsigned &Idx)
+ : Reader(R), Context(C), Record(Record), Idx(Idx) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+ OMPClause *readClause();
+};
+}
+
+OMPClause *OMPClauseReader::readClause() {
+ OMPClause *C;
+ switch (Record[Idx++]) {
+ case OMPC_default:
+ C = new (Context) OMPDefaultClause();
+ break;
+ case OMPC_private:
+ C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_firstprivate:
+ C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_shared:
+ C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ }
+ Visit(C);
+ C->setLocStart(Reader->ReadSourceLocation(Record, Idx));
+ C->setLocEnd(Reader->ReadSourceLocation(Record, Idx));
+
+ return C;
+}
+
+void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ C->setDefaultKind(
+ static_cast<OpenMPDefaultClauseKind>(Record[Idx++]));
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Directives.
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
+ VisitStmt(E);
+ ++Idx;
+ E->setLocStart(ReadSourceLocation(Record, Idx));
+ E->setLocEnd(ReadSourceLocation(Record, Idx));
+ OMPClauseReader ClauseReader(this, Reader.getContext(), Record, Idx);
+ SmallVector<OMPClause *, 5> Clauses;
+ for (unsigned i = 0; i < E->getNumClauses(); ++i)
+ Clauses.push_back(ClauseReader.readClause());
+ E->setClauses(Clauses);
+ E->setAssociatedStmt(Reader.ReadSubStmt());
+}
+
+void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
+//===----------------------------------------------------------------------===//
// ASTReader Implementation
//===----------------------------------------------------------------------===//
Stmt *ASTReader::ReadStmt(ModuleFile &F) {
switch (ReadingKind) {
+ case Read_None:
+ llvm_unreachable("should not call this when not reading anything");
case Read_Decl:
case Read_Type:
return ReadStmtFromStream(F);
@@ -1815,7 +1936,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case STMT_CAPTURED:
S = CapturedStmt::CreateDeserialized(Context,
- Record[ASTStmtReader::NumExprFields]);
+ Record[ASTStmtReader::NumStmtFields]);
break;
case EXPR_PREDEFINED:
@@ -2004,6 +2125,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) ShuffleVectorExpr(Empty);
break;
+ case EXPR_CONVERT_VECTOR:
+ S = new (Context) ConvertVectorExpr(Empty);
+ break;
+
case EXPR_BLOCK:
S = new (Context) BlockExpr(Empty);
break;
@@ -2115,6 +2240,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
DeclarationNameInfo(),
0);
break;
+ case STMT_OMP_PARALLEL_DIRECTIVE:
+ S =
+ OMPParallelDirective::CreateEmpty(Context,
+ Record[ASTStmtReader::NumStmtFields],
+ Empty);
+ break;
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(Context, Empty);
@@ -2160,6 +2291,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) UserDefinedLiteral(Context, Empty);
break;
+ case EXPR_CXX_STD_INITIALIZER_LIST:
+ S = new (Context) CXXStdInitializerListExpr(Empty);
+ break;
+
case EXPR_CXX_BOOL_LITERAL:
S = new (Context) CXXBoolLiteralExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b8ada04e5d8a..405488c35716 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -108,6 +108,11 @@ void ASTTypeWriter::VisitPointerType(const PointerType *T) {
Code = TYPE_POINTER;
}
+void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
+ Writer.AddTypeRef(T->getOriginalType(), Record);
+ Code = TYPE_DECAYED;
+}
+
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Code = TYPE_BLOCK_POINTER;
@@ -447,6 +452,9 @@ void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
}
+void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ // nothing to do
+}
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
}
@@ -735,6 +743,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_CONST_CAST);
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
RECORD(EXPR_USER_DEFINED_LITERAL);
+ RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
RECORD(EXPR_CXX_BOOL_LITERAL);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
@@ -839,6 +848,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
RECORD(MACRO_TABLE);
+ RECORD(LATE_PARSED_TEMPLATE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -937,6 +947,9 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_CLASS_TEMPLATE);
RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION);
RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE);
+ RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION);
RECORD(DECL_FUNCTION_TEMPLATE);
RECORD(DECL_TEMPLATE_TYPE_PARM);
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
@@ -1224,7 +1237,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
WriteInputFiles(Context.SourceMgr,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
- isysroot);
+ isysroot,
+ PP.getLangOpts().Modules);
Stream.ExitBlock();
}
@@ -1239,7 +1253,8 @@ namespace {
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
- StringRef isysroot) {
+ StringRef isysroot,
+ bool Modules) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
@@ -1293,6 +1308,19 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
}
}
+ // Add the compiler's own module.map in the set of (non-system) input files.
+ // This is a simple heuristic for detecting whether the compiler's headers
+ // have changed, because we don't want to stat() all of them.
+ if (Modules && !Chain) {
+ SmallString<128> P = StringRef(HSOpts.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ llvm::sys::path::append(P, "module.map");
+ if (const FileEntry *ModuleMapFile = FileMgr.getFile(P)) {
+ InputFileEntry Entry = { ModuleMapFile, false, false };
+ SortedFiles.push_front(Entry);
+ }
+ }
+
unsigned UserFilesNum = 0;
// Write out all of the input files.
std::vector<uint32_t> InputFileOffsets;
@@ -1475,7 +1503,8 @@ namespace {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
- unsigned char Flags = (Data.isImport << 5)
+ unsigned char Flags = (Data.HeaderRole << 6)
+ | (Data.isImport << 5)
| (Data.isPragmaOnce << 4)
| (Data.DirInfo << 2)
| (Data.Resolved << 1)
@@ -1506,7 +1535,7 @@ namespace {
Emit32(Out, Offset);
if (Data.isModuleHeader) {
- Module *Mod = HS.findModuleForHeader(key.FE);
+ Module *Mod = HS.findModuleForHeader(key.FE).getModule();
Emit32(Out, Writer.getExistingSubmoduleID(Mod));
}
@@ -1542,6 +1571,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
const HeaderFileInfo &HFI = HS.getFileInfo(File);
if (HFI.External && Chain)
continue;
+ if (HFI.isModuleHeader && !HFI.isCompilingModuleHeader)
+ continue;
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = File->getName();
@@ -1830,12 +1861,10 @@ public:
};
} // end anonymous namespace
-static int compareMacroDirectives(const void *XPtr, const void *YPtr) {
- const std::pair<const IdentifierInfo *, MacroDirective *> &X =
- *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr;
- const std::pair<const IdentifierInfo *, MacroDirective *> &Y =
- *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr;
- return X.first->getName().compare(Y.first->getName());
+static int compareMacroDirectives(
+ const std::pair<const IdentifierInfo *, MacroDirective *> *X,
+ const std::pair<const IdentifierInfo *, MacroDirective *> *Y) {
+ return X->first->getName().compare(Y->first->getName());
}
static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
@@ -2249,7 +2278,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // State
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
@@ -2258,6 +2288,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
@@ -2308,12 +2343,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
- for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Mod->Requirements.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_REQUIRES);
+ Record.push_back(Mod->Requirements[I].second);
Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
- Mod->Requires[I].data(),
- Mod->Requires[I].size());
+ Mod->Requirements[I].first);
}
// Emit the umbrella header, if there is one.
@@ -2330,11 +2365,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
// Emit the headers.
- for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Mod->NormalHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_HEADER);
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
- Mod->Headers[I]->getName());
+ Mod->NormalHeaders[I]->getName());
}
// Emit the excluded headers.
for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
@@ -2343,6 +2378,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
Mod->ExcludedHeaders[I]->getName());
}
+ // Emit the private headers.
+ for (unsigned I = 0, N = Mod->PrivateHeaders.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_PRIVATE_HEADER);
+ Stream.EmitRecordWithBlob(PrivateHeaderAbbrev, Record,
+ Mod->PrivateHeaders[I]->getName());
+ }
ArrayRef<const FileEntry *>
TopHeaders = Mod->getTopHeaders(PP->getFileManager());
for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {
@@ -2380,6 +2422,10 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
}
+ //FIXME: How do we emit the 'use'd modules? They may not be submodules.
+ // Might be unnecessary as use declarations are only used to build the
+ // module itself.
+
// Emit the link libraries.
for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
Record.clear();
@@ -3096,7 +3142,7 @@ public:
// Only emit declarations that aren't from a chained PCH, though.
SmallVector<Decl *, 16> Decls(IdResolver.begin(II),
IdResolver.end());
- for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
+ for (SmallVectorImpl<Decl *>::reverse_iterator D = Decls.rbegin(),
DEnd = Decls.rend();
D != DEnd; ++D)
clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D)));
@@ -3486,7 +3532,7 @@ void ASTWriter::WriteRedeclarations() {
for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
Decl *First = Redeclarations[I];
- assert(First->getPreviousDecl() == 0 && "Not the first declaration?");
+ assert(First->isFirstDecl() && "Not the first declaration?");
Decl *MostRecent = First->getMostRecentDecl();
@@ -3631,6 +3677,30 @@ void ASTWriter::WriteMergedDecls() {
Stream.EmitRecord(MERGED_DECLARATIONS, Record);
}
+void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) {
+ Sema::LateParsedTemplateMapT &LPTMap = SemaRef.LateParsedTemplateMap;
+
+ if (LPTMap.empty())
+ return;
+
+ RecordData Record;
+ for (Sema::LateParsedTemplateMapT::iterator It = LPTMap.begin(),
+ ItEnd = LPTMap.end();
+ It != ItEnd; ++It) {
+ LateParsedTemplate *LPT = It->second;
+ AddDeclRef(It->first, Record);
+ AddDeclRef(LPT->D, Record);
+ Record.push_back(LPT->Toks.size());
+
+ for (CachedTokens::iterator TokIt = LPT->Toks.begin(),
+ TokEnd = LPT->Toks.end();
+ TokIt != TokEnd; ++TokIt) {
+ AddToken(*TokIt, Record);
+ }
+ }
+ Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record);
+}
+
//===----------------------------------------------------------------------===//
// General Serialization Routines
//===----------------------------------------------------------------------===//
@@ -3812,8 +3882,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// FIXME: Modules won't like this at all.
IdentifierTable &Table = PP.getIdentifierTable();
SmallVector<const char *, 32> BuiltinNames;
- Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
- Context.getLangOpts().NoBuiltin);
+ if (!Context.getLangOpts().NoBuiltin) {
+ Context.BuiltinInfo.GetBuiltinNames(BuiltinNames);
+ }
for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
getIdentifierRef(&Table.get(BuiltinNames[I]));
}
@@ -3998,12 +4069,27 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Make sure visible decls, added to DeclContexts previously loaded from
// an AST file, are registered for serialization.
- for (SmallVector<const Decl *, 16>::iterator
+ for (SmallVectorImpl<const Decl *>::iterator
I = UpdatingVisibleDecls.begin(),
E = UpdatingVisibleDecls.end(); I != E; ++I) {
GetDeclRef(*I);
}
+ // Make sure all decls associated with an identifier are registered for
+ // serialization.
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID) {
+ const IdentifierInfo *II = ID->second;
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) {
+ for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II),
+ DEnd = SemaRef.IdResolver.end();
+ D != DEnd; ++D) {
+ GetDeclRef(*D);
+ }
+ }
+ }
+
// Resolve any declaration pointers within the declaration updates block.
ResolveDeclUpdatesBlocks();
@@ -4197,7 +4283,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
WriteRedeclarations();
WriteMergedDecls();
WriteObjCCategories();
-
+ WriteLateParsedTemplates(SemaRef);
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
@@ -4228,8 +4315,15 @@ void ASTWriter::ResolveDeclUpdatesBlocks() {
URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx]));
++Idx;
break;
-
+
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ case UPD_DECL_MARKED_USED:
+ ++Idx;
+ break;
+
+ case UPD_CXX_DEDUCED_RETURN_TYPE:
+ URec[Idx] = GetOrCreateTypeID(
+ QualType::getFromOpaquePtr(reinterpret_cast<void *>(URec[Idx])));
++Idx;
break;
}
@@ -4266,8 +4360,8 @@ void ASTWriter::WriteDeclReplacementsBlock() {
return;
RecordData Record;
- for (SmallVector<ReplacedDeclInfo, 16>::iterator
- I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
+ for (SmallVectorImpl<ReplacedDeclInfo>::iterator
+ I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
Record.push_back(I->ID);
Record.push_back(I->Offset);
Record.push_back(I->Loc);
@@ -4446,11 +4540,13 @@ void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) {
}
TypeID ASTWriter::GetOrCreateTypeID( QualType T) {
+ assert(Context);
return MakeTypeID(*Context, T,
std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
}
TypeID ASTWriter::getTypeID(QualType T) const {
+ assert(Context);
return MakeTypeID(*Context, T,
std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
}
@@ -4531,11 +4627,6 @@ DeclID ASTWriter::getDeclID(const Decl *D) {
return DeclIDs[D];
}
-static inline bool compLocDecl(std::pair<unsigned, serialization::DeclID> L,
- std::pair<unsigned, serialization::DeclID> R) {
- return L.first < R.first;
-}
-
void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
assert(ID);
assert(D);
@@ -4574,8 +4665,8 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
return;
}
- LocDeclIDsTy::iterator
- I = std::upper_bound(Decls.begin(), Decls.end(), LocDecl, compLocDecl);
+ LocDeclIDsTy::iterator I =
+ std::upper_bound(Decls.begin(), Decls.end(), LocDecl, llvm::less_first());
Decls.insert(I, LocDecl);
}
@@ -4874,6 +4965,17 @@ ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
AddTemplateArgument(TemplateArgs->get(i), Record);
}
+void
+ASTWriter::AddASTTemplateArgumentListInfo
+(const ASTTemplateArgumentListInfo *ASTTemplArgList, RecordDataImpl &Record) {
+ assert(ASTTemplArgList && "No ASTTemplArgList!");
+ AddSourceLocation(ASTTemplArgList->LAngleLoc, Record);
+ AddSourceLocation(ASTTemplArgList->RAngleLoc, Record);
+ Record.push_back(ASTTemplArgList->NumTemplateArgs);
+ const TemplateArgumentLoc *TemplArgs = ASTTemplArgList->getTemplateArgs();
+ for (int i=0, e = ASTTemplArgList->NumTemplateArgs; i != e; ++i)
+ AddTemplateArgumentLoc(TemplArgs[i], Record);
+}
void
ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) {
@@ -5004,8 +5106,6 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
- Record.push_back(Data.FailedImplicitMoveConstructor);
- Record.push_back(Data.FailedImplicitMoveAssignment);
// IsLambda bit is already saved.
Record.push_back(Data.NumBases);
@@ -5019,15 +5119,17 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases,
Record);
- AddUnresolvedSet(Data.Conversions, Record);
- AddUnresolvedSet(Data.VisibleConversions, Record);
+ AddUnresolvedSet(Data.Conversions.get(*Context), Record);
+ AddUnresolvedSet(Data.VisibleConversions.get(*Context), Record);
// Data.Definition is the owning decl, no need to write it.
- AddDeclRef(Data.FirstFriend, Record);
+ AddDeclRef(D->getFirstFriend(), Record);
// Add lambda-specific data.
if (Data.IsLambda) {
CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData();
Record.push_back(Lambda.Dependent);
+ Record.push_back(Lambda.IsGenericLambda);
+ Record.push_back(Lambda.CaptureDefault);
Record.push_back(Lambda.NumCaptures);
Record.push_back(Lambda.NumExplicitCaptures);
Record.push_back(Lambda.ManglingNumber);
@@ -5037,12 +5139,20 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
Record.push_back(Capture.isImplicit());
- Record.push_back(Capture.getCaptureKind()); // FIXME: stable!
- VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0;
- AddDeclRef(Var, Record);
- AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc()
- : SourceLocation(),
- Record);
+ Record.push_back(Capture.getCaptureKind());
+ switch (Capture.getCaptureKind()) {
+ case LCK_This:
+ break;
+ case LCK_ByCopy:
+ case LCK_ByRef:
+ VarDecl *Var =
+ Capture.capturesVariable() ? Capture.getCapturedVar() : 0;
+ AddDeclRef(Var, Record);
+ AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
+ : SourceLocation(),
+ Record);
+ break;
+ }
}
}
}
@@ -5174,6 +5284,19 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
Record.push_back(reinterpret_cast<uint64_t>(D));
}
+void ASTWriter::AddedCXXTemplateSpecialization(
+ const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
+ // The specializations set is kept in the canonical template.
+ assert(!WritingAST && "Already writing the AST!");
+ TD = TD->getCanonicalDecl();
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
+ return; // Not a source specialization added to a template from PCH.
+
+ UpdateRecord &Record = DeclUpdates[TD];
+ Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
+ Record.push_back(reinterpret_cast<uint64_t>(D));
+}
+
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {
// The specializations set is kept in the canonical template.
@@ -5187,6 +5310,17 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
Record.push_back(reinterpret_cast<uint64_t>(D));
}
+void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
+ assert(!WritingAST && "Already writing the AST!");
+ FD = FD->getCanonicalDecl();
+ if (!FD->isFromASTFile())
+ return; // Not a function declared in PCH and defined outside.
+
+ UpdateRecord &Record = DeclUpdates[FD];
+ Record.push_back(UPD_CXX_DEDUCED_RETURN_TYPE);
+ Record.push_back(reinterpret_cast<uint64_t>(ReturnType.getAsOpaquePtr()));
+}
+
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
@@ -5235,3 +5369,12 @@ void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
RewriteDecl(D);
}
+
+void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ UpdateRecord &Record = DeclUpdates[D];
+ Record.push_back(UPD_DECL_MARKED_USED);
+}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 67349db687db..55f830a4badd 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -68,6 +68,9 @@ namespace clang {
ClassTemplateSpecializationDecl *D);
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
@@ -90,6 +93,7 @@ namespace clang {
void VisitTemplateDecl(TemplateDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
@@ -184,7 +188,10 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
VisitRedeclarable(D);
VisitTypeDecl(D);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Record.push_back(D->isModed());
+ if (D->isModed())
+ Writer.AddTypeRef(D->getUnderlyingType(), Record);
}
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
@@ -192,7 +199,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->getFirstDeclaration() == D->getMostRecentDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -217,10 +224,13 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
Record.push_back(D->isCompleteDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
Record.push_back(D->isFreeStanding());
+ Record.push_back(D->isCompleteDefinitionRequired());
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
+ else if (D->hasDeclaratorForAnonDecl())
+ Writer.AddDeclRef(D->getDeclaratorForAnonDecl(), Record);
else
Writer.AddDeclRef(D->getTypedefNameForAnonDecl(), Record);
}
@@ -248,7 +258,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->getFirstDeclaration() == D->getMostRecentDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -274,7 +284,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->getFirstDeclaration() == D->getMostRecentDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -334,7 +344,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->hasImplicitReturnZero());
Record.push_back(D->isConstexpr());
Record.push_back(D->HasSkippedBody);
- Record.push_back(D->getLinkage());
+ Record.push_back(D->isLateTemplateParsed());
+ Record.push_back(D->getLinkageInternal());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->getTemplatedKind());
@@ -517,6 +528,7 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// FIXME: stable encoding for @public/@private/@protected/@package
Record.push_back(D->getAccessControl());
Record.push_back(D->getSynthesize());
+ Record.push_back(D->getBackingIvarReferencedInAccessor());
if (!D->hasAttrs() &&
!D->isImplicit() &&
@@ -694,7 +706,9 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->isConstexpr());
- Record.push_back(D->getLinkage());
+ Record.push_back(D->isInitCapture());
+ Record.push_back(D->isPreviousDeclInSameBlockScope());
+ Record.push_back(D->getLinkageInternal());
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
@@ -702,14 +716,21 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
} else {
Record.push_back(0);
}
-
- MemberSpecializationInfo *SpecInfo
- = D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
- Record.push_back(SpecInfo != 0);
- if (SpecInfo) {
+
+ enum {
+ VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+ };
+ if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) {
+ Record.push_back(VarTemplate);
+ Writer.AddDeclRef(TemplD, Record);
+ } else if (MemberSpecializationInfo *SpecInfo
+ = D->getMemberSpecializationInfo()) {
+ Record.push_back(StaticDataMemberSpecialization);
Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
Record.push_back(SpecInfo->getTemplateSpecializationKind());
Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
+ } else {
+ Record.push_back(VarNotTemplate);
}
if (!D->hasAttrs() &&
@@ -722,12 +743,15 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- D->getFirstDeclaration() == D->getMostRecentDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
D->getInitStyle() == VarDecl::CInit &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
+ !isa<VarTemplateSpecializationDecl>(D) &&
!D->isConstexpr() &&
- !SpecInfo)
+ !D->isInitCapture() &&
+ !D->isPreviousDeclInSameBlockScope() &&
+ !D->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclVarAbbrev();
Code = serialization::DECL_VAR;
@@ -905,16 +929,17 @@ void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
VisitNamedDecl(D);
- Writer.AddSourceLocation(D->getUsingLocation(), Record);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Writer.AddDeclRef(D->FirstUsingShadow.getPointer(), Record);
- Record.push_back(D->isTypeName());
+ Record.push_back(D->hasTypename());
Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record);
Code = serialization::DECL_USING;
}
void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ VisitRedeclarable(D);
VisitNamedDecl(D);
Writer.AddDeclRef(D->getTargetDecl(), Record);
Writer.AddDeclRef(D->UsingOrNextShadow, Record);
@@ -997,7 +1022,6 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
VisitCXXMethodDecl(D);
Record.push_back(D->IsExplicitSpecified);
- Record.push_back(D->ImplicitlyDefined);
Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers,
Record);
@@ -1007,7 +1031,6 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- Record.push_back(D->ImplicitlyDefined);
Writer.AddDeclRef(D->OperatorDelete, Record);
Code = serialization::DECL_CXX_DESTRUCTOR;
@@ -1089,7 +1112,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
// getCommonPtr() can be used while this is still initializing.
- if (D->isFirstDeclaration()) {
+ if (D->isFirstDecl()) {
// This declaration owns the 'common' pointer, so serialize that data now.
Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
if (D->getInstantiatedFromMemberTemplate())
@@ -1103,7 +1126,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->isFirstDeclaration()) {
+ if (D->isFirstDecl()) {
typedef llvm::FoldingSetVector<ClassTemplateSpecializationDecl> CTSDSetTy;
CTSDSetTy &CTSDSet = D->getSpecializations();
Record.push_back(CTSDSet.size());
@@ -1141,13 +1164,6 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
}
- // Explicit info.
- Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
- if (D->getTypeAsWritten()) {
- Writer.AddSourceLocation(D->getExternLoc(), Record);
- Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
- }
-
Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
Record.push_back(D->getSpecializationKind());
@@ -1158,6 +1174,13 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
}
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
}
@@ -1166,12 +1189,83 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
VisitClassTemplateSpecializationDecl(D);
Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+ Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDecl() == 0) {
+ Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+
+ if (D->isFirstDecl()) {
+ typedef llvm::FoldingSetVector<VarTemplateSpecializationDecl> VTSDSetTy;
+ VTSDSetTy &VTSDSet = D->getSpecializations();
+ Record.push_back(VTSDSet.size());
+ for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E;
+ ++I) {
+ assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
+ Writer.AddDeclRef(&*I, Record);
+ }
- Record.push_back(D->getNumTemplateArgsAsWritten());
- for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i)
- Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record);
+ typedef llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
+ VTPSDSetTy;
+ VTPSDSetTy &VTPSDSet = D->getPartialSpecializations();
+ Record.push_back(VTPSDSet.size());
+ for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E;
+ ++I) {
+ assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
+ Writer.AddDeclRef(&*I, Record);
+ }
+ }
+ Code = serialization::DECL_VAR_TEMPLATE;
+}
- Record.push_back(D->getSequenceNumber());
+void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ VisitVarDecl(D);
+
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ InstFrom = D->getSpecializedTemplateOrPartial();
+ if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
+ Writer.AddDeclRef(InstFromD, Record);
+ } else {
+ Writer.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>(),
+ Record);
+ Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
+ }
+
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
+ Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
+ Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
+ Record.push_back(D->getSpecializationKind());
+ Record.push_back(D->isCanonicalDecl());
+
+ if (D->isCanonicalDecl()) {
+ // When reading, we'll add it to the folding set of the following template.
+ Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
+ }
+
+ Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDecl(D);
+
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+ Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
// These are read/set from/to the first declaration.
if (D->getPreviousDecl() == 0) {
@@ -1179,7 +1273,7 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
Record.push_back(D->isMemberSpecialization());
}
- Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
+ Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
}
void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
@@ -1193,7 +1287,7 @@ void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->isFirstDeclaration()) {
+ if (D->isFirstDecl()) {
// This FunctionTemplateDecl owns the CommonPtr; write it.
// Write the function specialization declarations.
@@ -1310,7 +1404,7 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
- T *First = D->getFirstDeclaration();
+ T *First = D->getFirstDecl();
if (First->getMostRecentDecl() != First) {
assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
"Not considered redeclarable?");
@@ -1412,6 +1506,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// ObjC Ivar
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
+ // getBackingIvarReferencedInAccessor
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
@@ -1447,6 +1543,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
@@ -1494,6 +1591,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
@@ -1541,6 +1639,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
+ Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
Abv->Add(BitCodeAbbrevOp(0)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
@@ -1620,7 +1720,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Linkage
+ Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
+ Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 5f7ac01bae92..072fc98e3910 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file implements serialization for Statements and Expressions.
-//
+///
+/// \file
+/// \brief Implements serialization for Statements and Expressions.
+///
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
@@ -26,7 +27,9 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace clang {
+
class ASTStmtWriter : public StmtVisitor<ASTStmtWriter, void> {
+ friend class OMPClauseWriter;
ASTWriter &Writer;
ASTWriter::RecordData &Record;
@@ -683,7 +686,6 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
else
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
Record.push_back(E->hadArrayRangeDesignator());
- Record.push_back(E->initializesStdInitializerList());
Record.push_back(E->getNumInits());
if (isArrayFiller) {
// ArrayFiller may have filled "holes" due to designated initializer.
@@ -772,6 +774,7 @@ void ASTStmtWriter::VisitChooseExpr(ChooseExpr *E) {
Writer.AddStmt(E->getRHS());
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Record.push_back(E->isConditionDependent() ? false : E->isConditionTrue());
Code = serialization::EXPR_CHOOSE;
}
@@ -791,6 +794,15 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Code = serialization::EXPR_SHUFFLE_VECTOR;
}
+void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddStmt(E->getSrcExpr());
+ Code = serialization::EXPR_CONVERT_VECTOR;
+}
+
void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getBlockDecl(), Record);
@@ -1145,7 +1157,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Record.push_back(E->isListInitialization());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
- Writer.AddSourceRange(E->getParenRange(), Record);
+ Writer.AddSourceRange(E->getParenOrBraceRange(), Record);
Code = serialization::EXPR_CXX_CONSTRUCT;
}
@@ -1164,6 +1176,7 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
Record.push_back(NumArrayIndexVars);
Writer.AddSourceRange(E->IntroducerRange, Record);
Record.push_back(E->CaptureDefault); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->CaptureDefaultLoc, Record);
Record.push_back(E->ExplicitParams);
Record.push_back(E->ExplicitResultType);
Writer.AddSourceLocation(E->ClosingBrace, Record);
@@ -1187,6 +1200,12 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
Code = serialization::EXPR_LAMBDA;
}
+void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_CXX_STD_INITIALIZER_LIST;
+}
+
void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
@@ -1216,7 +1235,7 @@ void ASTStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
VisitExplicitCastExpr(E);
- Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Code = serialization::EXPR_CXX_FUNCTIONAL_CAST;
}
@@ -1572,6 +1591,7 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->Temporary);
+ Writer.AddDeclRef(E->ExtendingDecl, Record);
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}
@@ -1653,6 +1673,84 @@ void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) {
}
//===----------------------------------------------------------------------===//
+// OpenMP Clauses.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+class OMPClauseWriter : public OMPClauseVisitor<OMPClauseWriter> {
+ ASTStmtWriter *Writer;
+ ASTWriter::RecordData &Record;
+public:
+ OMPClauseWriter(ASTStmtWriter *W, ASTWriter::RecordData &Record)
+ : Writer(W), Record(Record) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+ void writeClause(OMPClause *C);
+};
+}
+
+void OMPClauseWriter::writeClause(OMPClause *C) {
+ Record.push_back(C->getClauseKind());
+ Visit(C);
+ Writer->Writer.AddSourceLocation(C->getLocStart(), Record);
+ Writer->Writer.AddSourceLocation(C->getLocEnd(), Record);
+}
+
+void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ Record.push_back(C->getDefaultKind());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I)
+ Writer->Writer.AddStmt(*I);
+}
+
+void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I)
+ Writer->Writer.AddStmt(*I);
+}
+
+void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (OMPSharedClause::varlist_iterator I = C->varlist_begin(),
+ E = C->varlist_end();
+ I != E; ++I)
+ Writer->Writer.AddStmt(*I);
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Directives.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
+ VisitStmt(E);
+ Record.push_back(E->getNumClauses());
+ Writer.AddSourceLocation(E->getLocStart(), Record);
+ Writer.AddSourceLocation(E->getLocEnd(), Record);
+ OMPClauseWriter ClauseWriter(this, Record);
+ for (unsigned i = 0; i < E->getNumClauses(); ++i) {
+ ClauseWriter.writeClause(E->getClause(i));
+ }
+ Writer.AddStmt(E->getAssociatedStmt());
+}
+
+void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE;
+}
+
+//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 32c2df3b88d2..7e8baa2c1095 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -28,22 +28,29 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
StringRef OutputFile,
clang::Module *Module,
StringRef isysroot,
- raw_ostream *OS)
+ raw_ostream *OS, bool AllowASTWithErrors)
: PP(PP), OutputFile(OutputFile), Module(Module),
isysroot(isysroot.str()), Out(OS),
- SemaPtr(0), Stream(Buffer), Writer(Stream) {
+ SemaPtr(0), Stream(Buffer), Writer(Stream),
+ AllowASTWithErrors(AllowASTWithErrors),
+ HasEmittedPCH(false) {
}
PCHGenerator::~PCHGenerator() {
}
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
- if (PP.getDiagnostics().hasErrorOccurred())
+ // Don't create a PCH if there were fatal failures during module loading.
+ if (PP.getModuleLoader().HadFatalFailure)
+ return;
+
+ bool hasErrors = PP.getDiagnostics().hasErrorOccurred();
+ if (hasErrors && !AllowASTWithErrors)
return;
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot);
+ Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, hasErrors);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@@ -53,6 +60,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Free up some memory, in case the process is kept alive.
Buffer.clear();
+
+ HasEmittedPCH = true;
}
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index b6693e40e51e..fb647b0be9bc 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -26,7 +26,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include <cstdio>
using namespace clang;
using namespace serialization;
@@ -229,7 +229,8 @@ GlobalModuleIndex::readIndex(StringRef Path) {
llvm::sys::path::append(IndexPath, IndexFileName);
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
- if (llvm::MemoryBuffer::getFile(IndexPath, Buffer) != llvm::errc::success)
+ if (llvm::MemoryBuffer::getFile(IndexPath.c_str(), Buffer) !=
+ llvm::errc::success)
return std::make_pair((GlobalModuleIndex *)0, EC_NotFound);
/// \brief The bitstream reader from which we'll read the AST file.
@@ -790,7 +791,8 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
// Write the global index file to a temporary file.
llvm::SmallString<128> IndexTmpPath;
int TmpFD;
- if (llvm::sys::fs::unique_file(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath))
+ if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD,
+ IndexTmpPath))
return EC_IOError;
// Open the temporary global index file for output.
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index f3d53adafa52..9c4b3d92befe 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -12,10 +12,10 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/ModuleMap.h"
-#include "clang/Serialization/ModuleManager.h"
#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/ModuleManager.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
@@ -62,11 +62,13 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Look for the file entry. This only fails if the expected size or
// modification time differ.
const FileEntry *Entry;
- if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry))
+ if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
+ ErrorStr = "module file out of date";
return OutOfDate;
+ }
if (!Entry && FileName != "-") {
- ErrorStr = "file not found";
+ ErrorStr = "module file not found";
return Missing;
}
@@ -332,8 +334,7 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
break;
// Pop the next module off the stack.
- NextModule = State->Stack.back();
- State->Stack.pop_back();
+ NextModule = State->Stack.pop_back_val();
} while (true);
}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index fba14a0fc498..f66f8b75ed38 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -58,17 +58,20 @@ enum FoundationClass {
FC_NSArray,
FC_NSDictionary,
FC_NSEnumerator,
+ FC_NSNull,
FC_NSOrderedSet,
FC_NSSet,
FC_NSString
};
-static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
+static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
+ bool IncludeSuperclasses = true) {
static llvm::StringMap<FoundationClass> Classes;
if (Classes.empty()) {
Classes["NSArray"] = FC_NSArray;
Classes["NSDictionary"] = FC_NSDictionary;
Classes["NSEnumerator"] = FC_NSEnumerator;
+ Classes["NSNull"] = FC_NSNull;
Classes["NSOrderedSet"] = FC_NSOrderedSet;
Classes["NSSet"] = FC_NSSet;
Classes["NSString"] = FC_NSString;
@@ -76,7 +79,7 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
// FIXME: Should we cache this at all?
FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
- if (result == FC_None)
+ if (result == FC_None && IncludeSuperclasses)
if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
return findKnownClass(Super);
@@ -88,20 +91,49 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
//===----------------------------------------------------------------------===//
namespace {
- class NilArgChecker : public Checker<check::PreObjCMessage> {
+ class NilArgChecker : public Checker<check::PreObjCMessage,
+ check::PostStmt<ObjCDictionaryLiteral>,
+ check::PostStmt<ObjCArrayLiteral> > {
mutable OwningPtr<APIMisuse> BT;
- void WarnIfNilArg(CheckerContext &C,
- const ObjCMethodCall &msg, unsigned Arg,
- FoundationClass Class,
- bool CanBeSubscript = false) const;
+ void warnIfNilExpr(const Expr *E,
+ const char *Msg,
+ CheckerContext &C) const;
+
+ void warnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg, unsigned Arg,
+ FoundationClass Class,
+ bool CanBeSubscript = false) const;
+
+ void generateBugReport(ExplodedNode *N,
+ StringRef Msg,
+ SourceRange Range,
+ const Expr *Expr,
+ CheckerContext &C) const;
public:
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+ void checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const;
+ void checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const;
};
}
-void NilArgChecker::WarnIfNilArg(CheckerContext &C,
+void NilArgChecker::warnIfNilExpr(const Expr *E,
+ const char *Msg,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
+
+ if (ExplodedNode *N = C.generateSink()) {
+ generateBugReport(N, Msg, E->getSourceRange(), E, C);
+ }
+
+ }
+}
+
+void NilArgChecker::warnIfNilArg(CheckerContext &C,
const ObjCMethodCall &msg,
unsigned int Arg,
FoundationClass Class,
@@ -111,9 +143,6 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C,
if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
return;
- if (!BT)
- BT.reset(new APIMisuse("nil argument"));
-
if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -147,14 +176,26 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C,
<< msg.getSelector().getAsString() << "' cannot be nil";
}
}
-
- BugReport *R = new BugReport(*BT, os.str(), N);
- R->addRange(msg.getArgSourceRange(Arg));
- bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
- C.emitReport(R);
+
+ generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
+ msg.getArgExpr(Arg), C);
}
}
+void NilArgChecker::generateBugReport(ExplodedNode *N,
+ StringRef Msg,
+ SourceRange Range,
+ const Expr *E,
+ CheckerContext &C) const {
+ if (!BT)
+ BT.reset(new APIMisuse("nil argument"));
+
+ BugReport *R = new BugReport(*BT, Msg, N);
+ R->addRange(Range);
+ bugreporter::trackNullOrUndefValue(N, E, *R);
+ C.emitReport(R);
+}
+
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
@@ -223,26 +264,43 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
S.getNameForSlot(1).equals("forKey")) {
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class);
+ warnIfNilArg(C, msg, /* Arg */1, Class);
} else if (S.getNameForSlot(0).equals("setObject") &&
S.getNameForSlot(1).equals("forKey")) {
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class);
+ warnIfNilArg(C, msg, /* Arg */1, Class);
} else if (S.getNameForSlot(0).equals("setObject") &&
S.getNameForSlot(1).equals("forKeyedSubscript")) {
CanBeSubscript = true;
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
+ warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
} else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
Arg = 0;
}
}
-
// If argument is '0', report a warning.
if ((Arg != InvalidArgIndex))
- WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
+ warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
+
+}
+void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const {
+ unsigned NumOfElements = AL->getNumElements();
+ for (unsigned i = 0; i < NumOfElements; ++i) {
+ warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
+ }
+}
+
+void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const {
+ unsigned NumOfElements = DL->getNumElements();
+ for (unsigned i = 0; i < NumOfElements; ++i) {
+ ObjCDictionaryElement Element = DL->getKeyValueElement(i);
+ warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
+ warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
+ }
}
//===----------------------------------------------------------------------===//
@@ -729,12 +787,31 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Improves the modeling of loops over Cocoa collections.
//===----------------------------------------------------------------------===//
+// The map from container symbol to the container count symbol.
+// We currently will remember the last countainer count symbol encountered.
+REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
+REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
+
namespace {
class ObjCLoopChecker
- : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
-
+ : public Checker<check::PostStmt<ObjCForCollectionStmt>,
+ check::PostObjCMessage,
+ check::DeadSymbols,
+ check::PointerEscape > {
+ mutable IdentifierInfo *CountSelectorII;
+
+ bool isCollectionCountMethod(const ObjCMethodCall &M,
+ CheckerContext &C) const;
+
public:
+ ObjCLoopChecker() : CountSelectorII(0) {}
void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
+ void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
};
}
@@ -819,23 +896,240 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
}
+/// Returns NULL state if the collection is known to contain elements
+/// (or is known not to contain elements if the Assumption parameter is false.)
+static ProgramStateRef
+assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
+ SymbolRef CollectionS, bool Assumption) {
+ if (!State || !CollectionS)
+ return State;
+
+ const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
+ if (!CountS) {
+ const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
+ if (!KnownNonEmpty)
+ return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
+ return (Assumption == *KnownNonEmpty) ? State : NULL;
+ }
+
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ SVal CountGreaterThanZeroVal =
+ SvalBuilder.evalBinOp(State, BO_GT,
+ nonloc::SymbolVal(*CountS),
+ SvalBuilder.makeIntVal(0, (*CountS)->getType()),
+ SvalBuilder.getConditionType());
+ Optional<DefinedSVal> CountGreaterThanZero =
+ CountGreaterThanZeroVal.getAs<DefinedSVal>();
+ if (!CountGreaterThanZero) {
+ // The SValBuilder cannot construct a valid SVal for this condition.
+ // This means we cannot properly reason about it.
+ return State;
+ }
+
+ return State->assume(*CountGreaterThanZero, Assumption);
+}
+
+static ProgramStateRef
+assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
+ const ObjCForCollectionStmt *FCS,
+ bool Assumption) {
+ if (!State)
+ return NULL;
+
+ SymbolRef CollectionS =
+ State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
+ return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
+}
+
+
+/// If the fist block edge is a back edge, we are reentering the loop.
+static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
+ const ObjCForCollectionStmt *FCS) {
+ if (!N)
+ return false;
+
+ ProgramPoint P = N->getLocation();
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ if (BE->getSrc()->getLoopTarget() == FCS)
+ return true;
+ return false;
+ }
+
+ // Keep looking for a block edge.
+ for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
+ E = N->pred_end(); I != E; ++I) {
+ if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
+ return true;
+ }
+
+ return false;
+}
+
void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
// Check if this is the branch for the end of the loop.
SVal CollectionSentinel = C.getSVal(FCS);
- if (CollectionSentinel.isZeroConstant())
- return;
-
- ProgramStateRef State = C.getState();
- State = checkCollectionNonNil(C, State, FCS);
- State = checkElementNonNil(C, State, FCS);
+ if (CollectionSentinel.isZeroConstant()) {
+ if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
+ State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
+ // Otherwise, this is a branch that goes through the loop body.
+ } else {
+ State = checkCollectionNonNil(C, State, FCS);
+ State = checkElementNonNil(C, State, FCS);
+ State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
+ }
+
if (!State)
C.generateSink();
else if (State != C.getState())
C.addTransition(State);
}
+bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
+ CheckerContext &C) const {
+ Selector S = M.getSelector();
+ // Initialize the identifiers on first use.
+ if (!CountSelectorII)
+ CountSelectorII = &C.getASTContext().Idents.get("count");
+
+ // If the method returns collection count, record the value.
+ if (S.isUnarySelector() &&
+ (S.getIdentifierInfoForSlot(0) == CountSelectorII))
+ return true;
+
+ return false;
+}
+
+void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
+ CheckerContext &C) const {
+ if (!M.isInstanceMessage())
+ return;
+
+ const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
+ if (!ClassID)
+ return;
+
+ FoundationClass Class = findKnownClass(ClassID);
+ if (Class != FC_NSDictionary &&
+ Class != FC_NSArray &&
+ Class != FC_NSSet &&
+ Class != FC_NSOrderedSet)
+ return;
+
+ SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
+ if (!ContainerS)
+ return;
+
+ // If we are processing a call to "count", get the symbolic value returned by
+ // a call to "count" and add it to the map.
+ if (!isCollectionCountMethod(M, C))
+ return;
+
+ const Expr *MsgExpr = M.getOriginExpr();
+ SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
+ if (CountS) {
+ ProgramStateRef State = C.getState();
+
+ C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
+ State = State->set<ContainerCountMap>(ContainerS, CountS);
+
+ if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
+ State = State->remove<ContainerNonEmptyMap>(ContainerS);
+ State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
+ }
+
+ C.addTransition(State);
+ }
+ return;
+}
+
+static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
+ const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
+ if (!Message)
+ return 0;
+
+ const ObjCMethodDecl *MD = Message->getDecl();
+ if (!MD)
+ return 0;
+
+ const ObjCInterfaceDecl *StaticClass;
+ if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
+ // We can't find out where the method was declared without doing more work.
+ // Instead, see if the receiver is statically typed as a known immutable
+ // collection.
+ StaticClass = Message->getOriginExpr()->getReceiverInterface();
+ } else {
+ StaticClass = MD->getClassInterface();
+ }
+
+ if (!StaticClass)
+ return 0;
+
+ switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
+ case FC_None:
+ return 0;
+ case FC_NSArray:
+ case FC_NSDictionary:
+ case FC_NSEnumerator:
+ case FC_NSNull:
+ case FC_NSOrderedSet:
+ case FC_NSSet:
+ case FC_NSString:
+ break;
+ }
+
+ return Message->getReceiverSVal().getAsSymbol();
+}
+
+ProgramStateRef
+ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
+
+ // Remove the invalidated symbols form the collection count map.
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
+ SymbolRef Sym = *I;
+
+ // Don't invalidate this symbol's count if we know the method being called
+ // is declared on an immutable class. This isn't completely correct if the
+ // receiver is also passed as an argument, but in most uses of NSArray,
+ // NSDictionary, etc. this isn't likely to happen in a dangerous way.
+ if (Sym == ImmutableReceiver)
+ continue;
+
+ // The symbol escaped. Pessimistically, assume that the count could have
+ // changed.
+ State = State->remove<ContainerCountMap>(Sym);
+ State = State->remove<ContainerNonEmptyMap>(Sym);
+ }
+ return State;
+}
+
+void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // Remove the dead symbols from the collection count map.
+ ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
+ for (ContainerCountMapTy::iterator I = Tracked.begin(),
+ E = Tracked.end(); I != E; ++I) {
+ SymbolRef Sym = I->first;
+ if (SymReaper.isDead(Sym)) {
+ State = State->remove<ContainerCountMap>(Sym);
+ State = State->remove<ContainerNonEmptyMap>(Sym);
+ }
+ }
+
+ C.addTransition(State);
+}
+
namespace {
/// \class ObjCNonNilReturnValueChecker
/// \brief The checker restricts the return values of APIs known to
@@ -845,6 +1139,7 @@ class ObjCNonNilReturnValueChecker
mutable bool Initialized;
mutable Selector ObjectAtIndex;
mutable Selector ObjectAtIndexedSubscript;
+ mutable Selector NullSelector;
public:
ObjCNonNilReturnValueChecker() : Initialized(false) {}
@@ -870,6 +1165,7 @@ void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
ASTContext &Ctx = C.getASTContext();
ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
+ NullSelector = GetNullarySelector("null", Ctx);
}
// Check the receiver type.
@@ -889,10 +1185,11 @@ void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
+ FoundationClass Cl = findKnownClass(Interface);
+
// Objects returned from
// [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
// are never 'nil'.
- FoundationClass Cl = findKnownClass(Interface);
if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
Selector Sel = M.getSelector();
if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
@@ -900,6 +1197,14 @@ void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
}
+
+ // Objects returned from [NSNull null] are not nil.
+ if (Cl == FC_NSNull) {
+ if (M.getSelector() == NullSelector) {
+ // Go ahead and assume the value is non-nil.
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+ }
}
C.addTransition(State);
}
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index a3327d8b3194..a87104984883 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -37,14 +37,15 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
if (!FD)
return false;
- unsigned id = FD->getBuiltinID();
-
- if (!id)
+ switch (FD->getBuiltinID()) {
+ default:
return false;
- switch (id) {
- case Builtin::BI__builtin_expect: {
+ case Builtin::BI__builtin_expect:
+ case Builtin::BI__builtin_addressof: {
// For __builtin_expect, just return the value of the subexpression.
+ // __builtin_addressof is going from a reference to a pointer, but those
+ // are represented the same way in the analyzer.
assert (CE->arg_begin() != CE->arg_end());
SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
C.addTransition(state->BindExpr(CE, LCtx, X));
@@ -73,9 +74,24 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
}
- }
- return false;
+ case Builtin::BI__builtin_object_size: {
+ // This must be resolvable at compile time, so we defer to the constant
+ // evaluator for a value.
+ SVal V = UnknownVal();
+ llvm::APSInt Result;
+ if (CE->EvaluateAsInt(Result, C.getASTContext(), Expr::SE_NoSideEffects)) {
+ // Make sure the result has the correct type.
+ SValBuilder &SVB = C.getSValBuilder();
+ BasicValueFactory &BVF = SVB.getBasicValueFactory();
+ BVF.getAPSIntType(CE->getType()).apply(Result);
+ V = SVB.makeIntVal(Result);
+ }
+
+ C.addTransition(state->BindExpr(CE, LCtx, V));
+ return true;
+ }
+ }
}
void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 7da68251063b..ebd337780228 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -23,7 +23,6 @@ add_clang_library(clangStaticAnalyzerCheckers
CheckerDocumentation.cpp
ChrootChecker.cpp
ClangCheckers.cpp
- CommonBugCategories.cpp
DeadStoresChecker.cpp
DebugCheckers.cpp
DereferenceChecker.cpp
@@ -34,6 +33,7 @@ add_clang_library(clangStaticAnalyzerCheckers
FixedAddressChecker.cpp
GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
+ IdenticalExprChecker.cpp
IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
MacOSKeychainAPIChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index aa1ca6f2f809..c3736d7e5d71 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -141,8 +141,9 @@ public:
SVal val) const;
static ProgramStateRef InvalidateBuffer(CheckerContext &C,
- ProgramStateRef state,
- const Expr *Ex, SVal V);
+ ProgramStateRef state,
+ const Expr *Ex, SVal V,
+ bool IsSourceBuffer);
static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR);
@@ -231,7 +232,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
return NULL;
if (!BT_Null)
- BT_Null.reset(new BuiltinBug("Unix API",
+ BT_Null.reset(new BuiltinBug(categories::UnixAPI,
"Null pointer argument in call to byte string function"));
SmallString<80> buf;
@@ -525,7 +526,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
return;
if (!BT_Overlap)
- BT_Overlap.reset(new BugType("Unix API", "Improper arguments"));
+ BT_Overlap.reset(new BugType(categories::UnixAPI, "Improper arguments"));
// Generate a report for this bug.
BugReport *report =
@@ -661,7 +662,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
if (Recorded)
return *Recorded;
}
-
+
// Otherwise, get a new symbol and update the state.
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
@@ -669,8 +670,21 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
MR, Ex, sizeTy,
C.blockCount());
- if (!hypothetical)
+ if (!hypothetical) {
+ if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
+ // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4
+ BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
+ const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
+ llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
+ const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
+ fourInt);
+ NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
+ SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn,
+ maxLength, sizeTy);
+ state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true);
+ }
state = state->set<CStringLength>(MR, strLength);
+ }
return strLength;
}
@@ -689,7 +703,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug("Unix API",
+ BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,
"Argument is not a null-terminated string."));
SmallString<120> buf;
@@ -749,7 +763,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug("Unix API",
+ BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,
"Argument is not a null-terminated string."));
SmallString<120> buf;
@@ -796,8 +810,9 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
}
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
- ProgramStateRef state,
- const Expr *E, SVal V) {
+ ProgramStateRef state,
+ const Expr *E, SVal V,
+ bool IsSourceBuffer) {
Optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
@@ -817,8 +832,20 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
// Invalidate this region.
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, C.blockCount(), LCtx,
- /*CausesPointerEscape*/ false);
+
+ bool CausesPointerEscape = false;
+ RegionAndSymbolInvalidationTraits ITraits;
+ // Invalidate and escape only indirect regions accessible through the source
+ // buffer.
+ if (IsSourceBuffer) {
+ ITraits.setTrait(R,
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+ ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
+ CausesPointerEscape = true;
+ }
+
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx,
+ CausesPointerEscape, 0, 0, &ITraits);
}
// If we have a non-region value by chance, just remove the binding.
@@ -955,13 +982,20 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
state = state->BindExpr(CE, LCtx, destVal);
}
- // Invalidate the destination.
+ // Invalidate the destination (regular invalidation without pointer-escaping
+ // the address of the top-level region).
// FIXME: Even if we can't perfectly model the copy, we should see if we
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest,
- state->getSVal(Dest, C.getLocationContext()));
+ state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest),
+ /*IsSourceBuffer*/false);
+
+ // Invalidate the source (const-invalidation without const-pointer-escaping
+ // the address of the top-level region).
+ state = InvalidateBuffer(C, state, Source, C.getSVal(Source),
+ /*IsSourceBuffer*/true);
+
C.addTransition(state);
}
}
@@ -1564,13 +1598,19 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
Result = lastElement;
}
- // Invalidate the destination. This must happen before we set the C string
- // length because invalidation will clear the length.
+ // Invalidate the destination (regular invalidation without pointer-escaping
+ // the address of the top-level region). This must happen before we set the
+ // C string length because invalidation will clear the length.
// FIXME: Even if we can't perfectly model the copy, we should see if we
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// string, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dst, *dstRegVal);
+ state = InvalidateBuffer(C, state, Dst, *dstRegVal,
+ /*IsSourceBuffer*/false);
+
+ // Invalidate the source (const-invalidation without const-pointer-escaping
+ // the address of the top-level region).
+ state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true);
// Set the C string length of the destination, if we know it.
if (isBounded && !isAppending) {
@@ -1792,7 +1832,8 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
// Invalidate the search string, representing the change of one delimiter
// character to NUL.
- State = InvalidateBuffer(C, State, SearchStrPtr, Result);
+ State = InvalidateBuffer(C, State, SearchStrPtr, Result,
+ /*IsSourceBuffer*/false);
// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
@@ -2018,10 +2059,7 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) {\
- static CStringChecker *TheChecker = 0; \
- if (TheChecker == 0) \
- TheChecker = mgr.registerChecker<CStringChecker>(); \
- TheChecker->Filter.Check##name = true; \
+ mgr.registerChecker<CStringChecker>()->Filter.Check##name = true; \
}
REGISTER_CHECKER(CStringNullArg)
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index 92c0eef3e880..d29a12a90eeb 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -141,7 +141,6 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (containsBadStrncatPattern(CE)) {
const Expr *DstArg = CE->getArg(0);
const Expr *LenArg = CE->getArg(2);
- SourceRange R = LenArg->getSourceRange();
PathDiagnosticLocation Loc =
PathDiagnosticLocation::createBegin(LenArg, BR.getSourceManager(), AC);
@@ -159,7 +158,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
os << "se a safer 'strlcat' API";
BR.EmitBasicReport(FD, "Anti-pattern in the argument", "C String API",
- os.str(), Loc, &R, 1);
+ os.str(), Loc, LenArg->getSourceRange());
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 4965d2299616..fefcbe7b09cb 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -28,21 +28,26 @@ using namespace ento;
namespace {
class CallAndMessageChecker
- : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage,
+ : public Checker< check::PreStmt<CallExpr>,
+ check::PreStmt<CXXDeleteExpr>,
+ check::PreObjCMessage,
check::PreCall > {
mutable OwningPtr<BugType> BT_call_null;
mutable OwningPtr<BugType> BT_call_undef;
mutable OwningPtr<BugType> BT_cxx_call_null;
mutable OwningPtr<BugType> BT_cxx_call_undef;
mutable OwningPtr<BugType> BT_call_arg;
+ mutable OwningPtr<BugType> BT_cxx_delete_undef;
mutable OwningPtr<BugType> BT_msg_undef;
mutable OwningPtr<BugType> BT_objc_prop_undef;
mutable OwningPtr<BugType> BT_objc_subscript_undef;
mutable OwningPtr<BugType> BT_msg_arg;
mutable OwningPtr<BugType> BT_msg_ret;
+ mutable OwningPtr<BugType> BT_call_few_args;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -244,11 +249,36 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
BT_call_null.reset(
new BuiltinBug("Called function pointer is null (null dereference)"));
emitBadCall(BT_call_null.get(), C, Callee);
+ return;
}
C.addTransition(StNonNull);
}
+void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
+ CheckerContext &C) const {
+
+ SVal Arg = C.getSVal(DE->getArgument());
+ if (Arg.isUndef()) {
+ StringRef Desc;
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ if (!BT_cxx_delete_undef)
+ BT_cxx_delete_undef.reset(new BuiltinBug("Uninitialized argument value"));
+ if (DE->isArrayFormAsWritten())
+ Desc = "Argument to 'delete[]' is uninitialized";
+ else
+ Desc = "Argument to 'delete' is uninitialized";
+ BugType *BT = BT_cxx_delete_undef.get();
+ BugReport *R = new BugReport(*BT, Desc, N);
+ bugreporter::trackNullOrUndefValue(N, DE, *R);
+ C.emitReport(R);
+ return;
+ }
+}
+
+
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
@@ -280,11 +310,33 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
State = StNonNull;
}
+ const Decl *D = Call.getDecl();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ // If we have a declaration, we can make sure we pass enough parameters to
+ // the function.
+ unsigned Params = FD->getNumParams();
+ if (Call.getNumArgs() < Params) {
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+
+ LazyInit_BT("Function call with too few arguments", BT_call_few_args);
+
+ SmallString<512> Str;
+ llvm::raw_svector_ostream os(Str);
+ os << "Function taking " << Params << " argument"
+ << (Params == 1 ? "" : "s") << " is called with less ("
+ << Call.getNumArgs() << ")";
+
+ BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
+ C.emitReport(R);
+ }
+ }
+
// Don't check for uninitialized field values in arguments if the
// caller has a body that is available and we have the chance to inline it.
// This is a hack, but is a reasonable compromise betweens sometimes warning
// and sometimes not depending on if we decide to inline a function.
- const Decl *D = Call.getDecl();
const bool checkUninitFields =
!(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
@@ -395,8 +447,7 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
return (triple.getVendor() == llvm::Triple::Apple &&
- (triple.getOS() == llvm::Triple::IOS ||
- !triple.isMacOSXVersionLT(10,5)));
+ (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 63080ea230f8..415d3ecc39b5 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -283,7 +283,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
bugType, "Security", os.str(),
- FSLoc, ranges.data(), ranges.size());
+ FSLoc, ranges);
}
//===----------------------------------------------------------------------===//
@@ -297,8 +297,7 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_gets)
return;
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT)
return;
@@ -307,7 +306,7 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Is the argument a 'char*'?
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+ const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>();
if (!PT)
return;
@@ -315,7 +314,6 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -323,7 +321,7 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
"Security",
"Call to function 'gets' is extremely insecure as it can "
"always result in a buffer overflow",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -335,8 +333,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_getpw)
return;
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT)
return;
@@ -349,7 +346,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify the second argument type is char*.
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
+ const PointerType *PT = FPT->getArgType(1)->getAs<PointerType>();
if (!PT)
return;
@@ -357,7 +354,6 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -365,7 +361,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
"Security",
"The getpw() function is dangerous as it may overflow the "
"provided buffer. It is obsoleted by getpwuid().",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -381,8 +377,7 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
return;
}
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
if(!FPT)
return;
@@ -391,7 +386,7 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify that the argument is Pointer Type.
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+ const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>();
if (!PT)
return;
@@ -400,7 +395,6 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a waring.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -409,7 +403,7 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
"Call to function 'mktemp' is insecure as it always "
"creates or uses insecure temporary file. Use 'mkstemp' "
"instead",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
@@ -473,7 +467,6 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = strArg->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
SmallString<512> buf;
@@ -492,7 +485,7 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
out << ')';
BR.EmitBasicReport(AC->getDecl(),
"Insecure temporary file creation", "Security",
- out.str(), CELoc, &R, 1);
+ out.str(), CELoc, strArg->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -509,7 +502,6 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -520,7 +512,7 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
"provide bounding of the memory buffer. Replace "
"unbounded copy functions with analogous functions that "
"support length arguments such as 'strlcpy'. CWE-119.",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -537,7 +529,6 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -548,15 +539,14 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
"provide bounding of the memory buffer. Replace "
"unbounded copy functions with analogous functions that "
"support length arguments such as 'strlcat'. CWE-119.",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
// Common check for str* functions with no bounds parameters.
//===----------------------------------------------------------------------===//
bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT)
return false;
@@ -568,7 +558,7 @@ bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
// Verify the type for both arguments.
for (int i = 0; i < 2; i++) {
// Verify that the arguments are pointers.
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(i));
+ const PointerType *PT = FPT->getArgType(i)->getAs<PointerType>();
if (!PT)
return false;
@@ -590,15 +580,14 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_rand || !CheckRand)
return;
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
if (!FTP)
return;
if (FTP->getNumArgs() == 1) {
// Is the argument an 'unsigned short *'?
// (Actually any integer type is allowed.)
- const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+ const PointerType *PT = FTP->getArgType(0)->getAs<PointerType>();
if (!PT)
return;
@@ -619,11 +608,10 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -635,8 +623,7 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
if (!CheckRand || !filter.check_rand)
return;
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
if (!FTP)
return;
@@ -645,7 +632,6 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -653,7 +639,7 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
"Security",
"The 'random' function produces a sequence of values that "
"an adversary may be able to predict. Use 'arc4random' "
- "instead", CELoc, &R, 1);
+ "instead", CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -666,7 +652,6 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
return;
// All calls to vfork() are insecure, issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
@@ -677,7 +662,7 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
"denial of service situations in the parent process. "
"Replace calls to vfork with calls to the safer "
"'posix_spawn' function",
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -713,8 +698,7 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
if (identifierid >= num_setids)
return;
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
if (!FTP)
return;
@@ -739,11 +723,10 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
<< "' is not checked. If an error occurs in '" << *FD
<< "', the following code may execute with unexpected privileges";
- SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
- CELoc, &R, 1);
+ CELoc, CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index f2c50501a65c..1207b67c97fa 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -60,15 +60,14 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
return;
- SourceRange R = ArgEx->getSourceRange();
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
"Potential unintended use of sizeof() on pointer type",
- "Logic",
+ categories::LogicError,
"The code calls sizeof() on a pointer type. "
"This can produce an unexpected result.",
- ELoc, &R, 1);
+ ELoc, ArgEx->getSourceRange());
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index a9dd19a395c5..956dca7d9258 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -190,7 +190,7 @@ public:
///
/// \returns true if the call has been successfully evaluated
/// and false otherwise. Note, that only one checker can evaluate a call. If
- /// more then one checker claim that they can evaluate the same call the
+ /// more than one checker claims that they can evaluate the same call the
/// first one wins.
///
/// eval::Call
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index fc35b223ee7f..862212d532fd 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -100,6 +100,10 @@ def CastToStructChecker : Checker<"CastToStruct">,
HelpText<"Check for cast from non-struct pointer to struct pointer">,
DescFile<"CastToStructChecker.cpp">;
+def IdenticalExprChecker : Checker<"IdenticalExpr">,
+ HelpText<"Warn about unintended use of identical expressions in operators">,
+ DescFile<"IdenticalExprChecker.cpp">;
+
def FixedAddressChecker : Checker<"FixedAddr">,
HelpText<"Check for assignment of a fixed address to a pointer">,
DescFile<"FixedAddressChecker.cpp">;
@@ -538,4 +542,8 @@ def ExprInspectionChecker : Checker<"ExprInspection">,
HelpText<"Check the analyzer's understanding of expressions">,
DescFile<"ExprInspectionChecker.cpp">;
+def ExplodedGraphViewer : Checker<"ViewExplodedGraph">,
+ HelpText<"View Exploded Graphs using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
} // end "debug"
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index bea908dfa687..de2ebce52c02 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
#define LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
-#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
namespace clang {
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index f336a6e68051..9d855ce649ac 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
@@ -86,10 +85,9 @@ void ReachableCode::computeReachableBlocks() {
SmallVector<const CFGBlock*, 10> worklist;
worklist.push_back(&cfg.getEntry());
-
+
while (!worklist.empty()) {
- const CFGBlock *block = worklist.back();
- worklist.pop_back();
+ const CFGBlock *block = worklist.pop_back_val();
llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
if (isReachable)
continue;
@@ -391,26 +389,24 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
- CFG *cfg;
+class FindEscaped {
public:
- FindEscaped(CFG *c) : cfg(c) {}
-
- CFG& getCFG() { return *cfg; }
-
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
- void VisitUnaryOperator(UnaryOperator* U) {
- // Check for '&'. Any VarDecl whose value has its address-taken we
- // treat as escaped.
- Expr *E = U->getSubExpr()->IgnoreParenCasts();
- if (U->getOpcode() == UO_AddrOf)
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
- if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- Escaped.insert(VD);
- return;
- }
- Visit(E);
+ void operator()(const Stmt *S) {
+ // Check for '&'. Any VarDecl whose address has been taken we treat as
+ // escaped.
+ // FIXME: What about references?
+ const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
+ if (!U)
+ return;
+ if (U->getOpcode() != UO_AddrOf)
+ return;
+
+ const Expr *E = U->getSubExpr()->IgnoreParenCasts();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ Escaped.insert(VD);
}
};
} // end anonymous namespace
@@ -438,8 +434,8 @@ public:
CFG &cfg = *mgr.getCFG(D);
AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
ParentMap &pmap = mgr.getParentMap(D);
- FindEscaped FS(&cfg);
- FS.getCFG().VisitBlockStmts(FS);
+ FindEscaped FS;
+ cfg.VisitBlockStmts(FS);
DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped);
L->runOnAllBlocks(A);
}
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index fe12866e51c3..a2c8d1fd8f39 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -17,6 +17,8 @@
#include "clang/Analysis/CallGraph.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/Support/Process.h"
using namespace clang;
@@ -152,25 +154,29 @@ void ento::registerCallGraphDumper(CheckerManager &mgr) {
namespace {
class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
+ typedef AnalyzerOptions::ConfigTable Table;
+
+ static int compareEntry(const Table::MapEntryTy *const *LHS,
+ const Table::MapEntryTy *const *RHS) {
+ return (*LHS)->getKey().compare((*RHS)->getKey());
+ }
+
public:
void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager& mgr,
BugReporter &BR) const {
+ const Table &Config = mgr.options.Config;
- const AnalyzerOptions::ConfigTable &Config = mgr.options.Config;
- AnalyzerOptions::ConfigTable::const_iterator I =
- Config.begin(), E = Config.end();
+ SmallVector<const Table::MapEntryTy *, 32> Keys;
+ for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
+ ++I)
+ Keys.push_back(&*I);
+ llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
- std::vector<StringRef> Keys;
- for (; I != E ; ++I) { Keys.push_back(I->getKey()); }
- sort(Keys.begin(), Keys.end());
-
llvm::errs() << "[config]\n";
- for (unsigned i = 0, n = Keys.size(); i < n ; ++i) {
- StringRef Key = Keys[i];
- I = Config.find(Key);
- llvm::errs() << Key << " = " << I->second << '\n';
- }
+ for (unsigned I = 0, E = Keys.size(); I != E; ++I)
+ llvm::errs() << Keys[I]->getKey() << " = " << Keys[I]->second << '\n';
+
llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
}
};
@@ -179,3 +185,22 @@ public:
void ento::registerConfigDumper(CheckerManager &mgr) {
mgr.registerChecker<ConfigDumper>();
}
+
+//===----------------------------------------------------------------------===//
+// ExplodedGraph Viewer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
+public:
+ ExplodedGraphViewer() {}
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
+ Eng.ViewGraph(0);
+ }
+};
+
+}
+
+void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
+ mgr.registerChecker<ExplodedGraphViewer>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index 6d3dd1e42f02..b43dc18c2179 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -40,21 +40,15 @@ namespace {
///
/// Checks for the init, dealloc, and any other functions that might be allowed
/// to perform direct instance variable assignment based on their name.
-struct MethodFilter {
- virtual ~MethodFilter() {}
- virtual bool operator()(ObjCMethodDecl *M) {
- if (M->getMethodFamily() == OMF_init ||
- M->getMethodFamily() == OMF_dealloc ||
- M->getMethodFamily() == OMF_copy ||
- M->getMethodFamily() == OMF_mutableCopy ||
- M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
- M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
- return true;
- return false;
- }
-};
-
-static MethodFilter DefaultMethodFilter;
+static bool DefaultMethodFilter(const ObjCMethodDecl *M) {
+ if (M->getMethodFamily() == OMF_init || M->getMethodFamily() == OMF_dealloc ||
+ M->getMethodFamily() == OMF_copy ||
+ M->getMethodFamily() == OMF_mutableCopy ||
+ M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
+ M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
+ return true;
+ return false;
+}
class DirectIvarAssignment :
public Checker<check::ASTDecl<ObjCImplementationDecl> > {
@@ -89,7 +83,7 @@ class DirectIvarAssignment :
};
public:
- MethodFilter *ShouldSkipMethod;
+ bool (*ShouldSkipMethod)(const ObjCMethodDecl *);
DirectIvarAssignment() : ShouldSkipMethod(&DefaultMethodFilter) {}
@@ -230,22 +224,16 @@ void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
// Register the checker that checks for direct accesses in functions annotated
// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
-namespace {
-struct InvalidatorMethodFilter : MethodFilter {
- virtual ~InvalidatorMethodFilter() {}
- virtual bool operator()(ObjCMethodDecl *M) {
- for (specific_attr_iterator<AnnotateAttr>
- AI = M->specific_attr_begin<AnnotateAttr>(),
- AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
- const AnnotateAttr *Ann = *AI;
- if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
- return false;
- }
- return true;
+static bool AttrFilter(const ObjCMethodDecl *M) {
+ for (specific_attr_iterator<AnnotateAttr>
+ AI = M->specific_attr_begin<AnnotateAttr>(),
+ AE = M->specific_attr_end<AnnotateAttr>();
+ AI != AE; ++AI) {
+ const AnnotateAttr *Ann = *AI;
+ if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
+ return false;
}
-};
-
-InvalidatorMethodFilter AttrFilter;
+ return true;
}
void ento::registerDirectIvarAssignmentForAnnotatedFunctions(
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 759aa6605ee7..7116e4dcd885 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -1,4 +1,4 @@
-//== DynamicTypePropagation.cpp ----------------------------------- -*- C++ -*--=//
+//== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -62,7 +62,7 @@ void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
// C++11 [class.cdtor]p4: When a virtual function is called directly or
// indirectly from a constructor or from a destructor, including during
- // the construction or destruction of the class’s non-static data members,
+ // the construction or destruction of the class's non-static data members,
// and the object to which the call applies is the object under
// construction or destruction, the function called is the final overrider
// in the constructor's or destructor's class and not one overriding it in
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 810473f1a6e0..3ed2435b92ed 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -22,6 +22,8 @@ class ExprInspectionChecker : public Checker< eval::Call > {
void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
CheckerContext &C) const;
@@ -39,6 +41,8 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE,
.Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
.Case("clang_analyzer_checkInlined",
&ExprInspectionChecker::analyzerCheckInlined)
+ .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
+ .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
.Default(0);
if (!Handler)
@@ -97,6 +101,17 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
C.emitReport(R);
}
+void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
+ CheckerContext &C) const {
+ ExplodedNode *N = C.getPredecessor();
+
+ if (!BT)
+ BT.reset(new BugType("Checking analyzer assumptions", "debug"));
+
+ BugReport *R = new BugReport(*BT, "REACHABLE", N);
+ C.emitReport(R);
+}
+
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
CheckerContext &C) const {
ExplodedNode *N = C.getPredecessor();
@@ -117,6 +132,11 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
C.emitReport(R);
}
+void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
+ CheckerContext &C) const {
+ LLVM_BUILTIN_TRAP;
+}
+
void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
Mgr.registerChecker<ExprInspectionChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index c67c597feced..1dc60c6dbddc 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -619,7 +619,8 @@ static bool getPrintfFormatArgumentNum(const CallExpr *CE,
const FormatAttr *Format = *i;
ArgNum = Format->getFormatIdx() - 1;
- if ((Format->getType() == "printf") && CE->getNumArgs() > ArgNum)
+ if ((Format->getType()->getName() == "printf") &&
+ CE->getNumArgs() > ArgNum)
return true;
}
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 271ba4702c57..4997f8d04ae8 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -25,8 +25,8 @@
// ^, ^= | 0 | | | x | x | |
// <<, <<= | | | | x | 0 | |
// >>, >>= | | | | x | 0 | |
-// || | 1 | 1 | 1 | x | x | 1 | 1
-// && | 1 | x | x | 0 | 0 | x | x
+// || | x | 1 | 1 | x | x | 1 | 1
+// && | x | x | x | 0 | 0 | x | x
// = | x | | | | | |
// == | 1 | | | | | |
// >= | 1 | | | | | |
@@ -678,19 +678,8 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
return CanVary(B->getRHS(), AC)
|| CanVary(B->getLHS(), AC);
}
- case Stmt::UnaryOperatorClass: {
- const UnaryOperator *U = cast<const UnaryOperator>(Ex);
- // Handle trivial case first
- switch (U->getOpcode()) {
- case UO_Extension:
- return false;
- default:
- return CanVary(U->getSubExpr(), AC);
- }
- }
- case Stmt::ChooseExprClass:
- return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr(
- AC->getASTContext()), AC);
+ case Stmt::UnaryOperatorClass:
+ return CanVary(cast<UnaryOperator>(Ex)->getSubExpr(), AC);
case Stmt::ConditionalOperatorClass:
case Stmt::BinaryConditionalOperatorClass:
return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC);
diff --git a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
new file mode 100644
index 000000000000..e696e38597bc
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -0,0 +1,226 @@
+//== IdenticalExprChecker.cpp - Identical expression checker----------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This defines IdenticalExprChecker, a check that warns about
+/// unintended use of identical expressions.
+///
+/// It checks for use of identical expressions with comparison operators.
+///
+//===----------------------------------------------------------------------===//
+
+#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/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
+ const Expr *Expr2);
+//===----------------------------------------------------------------------===//
+// FindIdenticalExprVisitor - Identify nodes using identical expressions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindIdenticalExprVisitor
+ : public RecursiveASTVisitor<FindIdenticalExprVisitor> {
+public:
+ explicit FindIdenticalExprVisitor(BugReporter &B, AnalysisDeclContext *A)
+ : BR(B), AC(A) {}
+ // FindIdenticalExprVisitor only visits nodes
+ // that are binary operators.
+ bool VisitBinaryOperator(const BinaryOperator *B);
+
+private:
+ BugReporter &BR;
+ AnalysisDeclContext *AC;
+};
+} // end anonymous namespace
+
+bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (!BinaryOperator::isComparisonOp(Op))
+ return true;
+ //
+ // Special case for floating-point representation.
+ //
+ // If expressions on both sides of comparison operator are of type float,
+ // then for some comparison operators no warning shall be
+ // reported even if the expressions are identical from a symbolic point of
+ // view. Comparison between expressions, declared variables and literals
+ // are treated differently.
+ //
+ // != and == between float literals that have the same value should NOT warn.
+ // < > between float literals that have the same value SHOULD warn.
+ //
+ // != and == between the same float declaration should NOT warn.
+ // < > between the same float declaration SHOULD warn.
+ //
+ // != and == between eq. expressions that evaluates into float
+ // should NOT warn.
+ // < > between eq. expressions that evaluates into float
+ // should NOT warn.
+ //
+ const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
+ const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
+
+ const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
+ const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
+ const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
+ const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
+ if ((DeclRef1) && (DeclRef2)) {
+ if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
+ (DeclRef2->getType()->hasFloatingRepresentation())) {
+ if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
+ if ((Op == BO_EQ) || (Op == BO_NE)) {
+ return true;
+ }
+ }
+ }
+ } else if ((FloatLit1) && (FloatLit2)) {
+ if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
+ if ((Op == BO_EQ) || (Op == BO_NE)) {
+ return true;
+ }
+ }
+ } else if (LHS->getType()->hasFloatingRepresentation()) {
+ // If any side of comparison operator still has floating-point
+ // representation, then it's an expression. Don't warn.
+ // Here only LHS is checked since RHS will be implicit casted to float.
+ return true;
+ } else {
+ // No special case with floating-point representation, report as usual.
+ }
+
+ if (isIdenticalExpr(AC->getASTContext(), B->getLHS(), B->getRHS())) {
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
+ StringRef Message;
+ if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
+ Message = "comparison of identical expressions always evaluates to true";
+ else
+ Message = "comparison of identical expressions always evaluates to false";
+ BR.EmitBasicReport(AC->getDecl(), "Compare of identical expressions",
+ categories::LogicError, Message, ELoc);
+ }
+ // We want to visit ALL nodes (subexpressions of binary comparison
+ // expressions too) that contains comparison operators.
+ // True is always returned to traverse ALL nodes.
+ return true;
+}
+/// \brief Determines whether two expression trees are identical regarding
+/// operators and symbols.
+///
+/// Exceptions: expressions containing macros or functions with possible side
+/// effects are never considered identical.
+/// Limitations: (t + u) and (u + t) are not considered identical.
+/// t*(u + t) and t*u + t*t are not considered identical.
+///
+static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
+ const Expr *Expr2) {
+ // If Expr1 & Expr2 are of different class then they are not
+ // identical expression.
+ if (Expr1->getStmtClass() != Expr2->getStmtClass())
+ return false;
+ // If Expr1 has side effects then don't warn even if expressions
+ // are identical.
+ if (Expr1->HasSideEffects(Ctx))
+ return false;
+ // Is expression is based on macro then don't warn even if
+ // the expressions are identical.
+ if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
+ return false;
+ // If all children of two expressions are identical, return true.
+ Expr::const_child_iterator I1 = Expr1->child_begin();
+ Expr::const_child_iterator I2 = Expr2->child_begin();
+ while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
+ const Expr *Child1 = dyn_cast<Expr>(*I1);
+ const Expr *Child2 = dyn_cast<Expr>(*I2);
+ if (!Child1 || !Child2 || !isIdenticalExpr(Ctx, Child1, Child2))
+ return false;
+ ++I1;
+ ++I2;
+ }
+ // If there are different number of children in the expressions, return false.
+ // (TODO: check if this is a redundant condition.)
+ if (I1 != Expr1->child_end())
+ return false;
+ if (I2 != Expr2->child_end())
+ return false;
+
+ switch (Expr1->getStmtClass()) {
+ default:
+ return false;
+ case Stmt::ArraySubscriptExprClass:
+ case Stmt::CStyleCastExprClass:
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::ParenExprClass:
+ return true;
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BinOp1 = dyn_cast<BinaryOperator>(Expr1);
+ const BinaryOperator *BinOp2 = dyn_cast<BinaryOperator>(Expr2);
+ return BinOp1->getOpcode() == BinOp2->getOpcode();
+ }
+ case Stmt::CharacterLiteralClass: {
+ const CharacterLiteral *CharLit1 = dyn_cast<CharacterLiteral>(Expr1);
+ const CharacterLiteral *CharLit2 = dyn_cast<CharacterLiteral>(Expr2);
+ return CharLit1->getValue() == CharLit2->getValue();
+ }
+ case Stmt::DeclRefExprClass: {
+ const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(Expr1);
+ const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(Expr2);
+ return DeclRef1->getDecl() == DeclRef2->getDecl();
+ }
+ case Stmt::IntegerLiteralClass: {
+ const IntegerLiteral *IntLit1 = dyn_cast<IntegerLiteral>(Expr1);
+ const IntegerLiteral *IntLit2 = dyn_cast<IntegerLiteral>(Expr2);
+ return IntLit1->getValue() == IntLit2->getValue();
+ }
+ case Stmt::FloatingLiteralClass: {
+ const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(Expr1);
+ const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(Expr2);
+ return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
+ }
+ case Stmt::MemberExprClass: {
+ const MemberExpr *MemberExpr1 = dyn_cast<MemberExpr>(Expr1);
+ const MemberExpr *MemberExpr2 = dyn_cast<MemberExpr>(Expr2);
+ return MemberExpr1->getMemberDecl() == MemberExpr2->getMemberDecl();
+ }
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UnaryOp1 = dyn_cast<UnaryOperator>(Expr1);
+ const UnaryOperator *UnaryOp2 = dyn_cast<UnaryOperator>(Expr2);
+ if (UnaryOp1->getOpcode() != UnaryOp2->getOpcode())
+ return false;
+ return !UnaryOp1->isIncrementDecrementOp();
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// FindIdenticalExprChecker
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
+public:
+ void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+ BugReporter &BR) const {
+ FindIdenticalExprVisitor Visitor(BR, Mgr.getAnalysisDeclContext(D));
+ Visitor.TraverseDecl(const_cast<Decl *>(D));
+ }
+};
+} // end anonymous namespace
+
+void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<FindIdenticalExprChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5d3eb65148dc..c7aa0fb150cb 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -100,7 +100,7 @@ public:
}
void dump(raw_ostream &OS) const {
- static const char *Table[] = {
+ static const char *const Table[] = {
"Allocated",
"Released",
"Relinquished"
@@ -279,13 +279,19 @@ private:
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
- /// Check if the function is known not to free memory, or if it is
+ /// Check if the function is known free memory, or if it is
/// "interesting" and should be modeled explicitly.
///
+ /// \param [out] EscapingSymbol A function might not free memory in general,
+ /// but could be known to free a particular symbol. In this case, false is
+ /// returned and the single escaping symbol is returned through the out
+ /// parameter.
+ ///
/// We assume that pointers do not escape through calls to system functions
/// not handled by this checker.
- bool doesNotFreeMemOrInteresting(const CallEvent *Call,
- ProgramStateRef State) const;
+ bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
+ ProgramStateRef State,
+ SymbolRef &EscapingSymbol) const;
// Implementation of the checkPointerEscape callabcks.
ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
@@ -307,7 +313,7 @@ private:
const Expr *DeallocExpr) const;
void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
const Expr *DeallocExpr, const RefState *RS,
- SymbolRef Sym) const;
+ SymbolRef Sym, bool OwnershipTransferred) const;
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr,
const Expr *AllocExpr = 0) const;
@@ -1036,7 +1042,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
if (!DeallocMatchesAlloc) {
ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
- ParentExpr, RsBase, SymBase);
+ ParentExpr, RsBase, SymBase, Hold);
return 0;
}
@@ -1054,7 +1060,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
}
}
- ReleasedAllocated = (RsBase != 0);
+ ReleasedAllocated = (RsBase != 0) && RsBase->isAllocated();
// Clean out the info on previous call to free return info.
State = State->remove<FreeReturnValue>(SymBase);
@@ -1254,7 +1260,8 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
SourceRange Range,
const Expr *DeallocExpr,
const RefState *RS,
- SymbolRef Sym) const {
+ SymbolRef Sym,
+ bool OwnershipTransferred) const {
if (!Filter.CMismatchedDeallocatorChecker)
return;
@@ -1273,15 +1280,27 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
SmallString<20> DeallocBuf;
llvm::raw_svector_ostream DeallocOs(DeallocBuf);
- os << "Memory";
- if (printAllocDeallocName(AllocOs, C, AllocExpr))
- os << " allocated by " << AllocOs.str();
+ if (OwnershipTransferred) {
+ if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
+ os << DeallocOs.str() << " cannot";
+ else
+ os << "Cannot";
+
+ os << " take ownership of memory";
+
+ if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ os << " allocated by " << AllocOs.str();
+ } else {
+ os << "Memory";
+ if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ os << " allocated by " << AllocOs.str();
- os << " should be deallocated by ";
- printExpectedDeallocName(os, RS->getAllocationFamily());
+ os << " should be deallocated by ";
+ printExpectedDeallocName(os, RS->getAllocationFamily());
- if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
- os << ", not " << DeallocOs.str();
+ if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
+ os << ", not " << DeallocOs.str();
+ }
BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N);
R->markInteresting(Sym);
@@ -1664,8 +1683,8 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (!Errors.empty()) {
static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
- for (SmallVector<SymbolRef, 2>::iterator
- I = Errors.begin(), E = Errors.end(); I != E; ++I) {
+ for (SmallVectorImpl<SymbolRef>::iterator
+ I = Errors.begin(), E = Errors.end(); I != E; ++I) {
reportLeak(*I, N, C);
}
}
@@ -1784,7 +1803,8 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const {
- if (isReleased(Sym, C)) {
+ // FIXME: Handle destructor called from delete more precisely.
+ if (isReleased(Sym, C) && S) {
ReportUseAfterFree(C, S->getSourceRange(), Sym);
return true;
}
@@ -1842,35 +1862,38 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
return state;
}
-bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
- ProgramStateRef State) const {
+bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
+ const CallEvent *Call,
+ ProgramStateRef State,
+ SymbolRef &EscapingSymbol) const {
assert(Call);
-
+ EscapingSymbol = 0;
+
// For now, assume that any C++ call can free memory.
// TODO: If we want to be more optimistic here, we'll need to make sure that
// regions escape to C++ containers. They seem to do that even now, but for
// mysterious reasons.
if (!(isa<FunctionCall>(Call) || isa<ObjCMethodCall>(Call)))
- return false;
+ return true;
// Check Objective-C messages by selector name.
if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
// If it's not a framework call, or if it takes a callback, assume it
// can free memory.
if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg())
- return false;
+ return true;
// If it's a method we know about, handle it explicitly post-call.
// This should happen before the "freeWhenDone" check below.
if (isKnownDeallocObjCMethodName(*Msg))
- return true;
+ return false;
// If there's a "freeWhenDone" parameter, but the method isn't one we know
// about, we can't be sure that the object will use free() to deallocate the
// memory, so we can't model it explicitly. The best we can do is use it to
// decide whether the pointer escapes.
if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
- return !*FreeWhenDone;
+ return *FreeWhenDone;
// If the first selector piece ends with "NoCopy", and there is no
// "freeWhenDone" parameter set to zero, we know ownership is being
@@ -1878,7 +1901,7 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
// free() to deallocate the memory, so we can't model it explicitly.
StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
if (FirstSlot.endswith("NoCopy"))
- return false;
+ return true;
// If the first selector starts with addPointer, insertPointer,
// or replacePointer, assume we are dealing with NSPointerArray or similar.
@@ -1887,34 +1910,42 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
if (FirstSlot.startswith("addPointer") ||
FirstSlot.startswith("insertPointer") ||
FirstSlot.startswith("replacePointer")) {
- return false;
+ return true;
+ }
+
+ // We should escape receiver on call to 'init'. This is especially relevant
+ // to the receiver, as the corresponding symbol is usually not referenced
+ // after the call.
+ if (Msg->getMethodFamily() == OMF_init) {
+ EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
+ return true;
}
// Otherwise, assume that the method does not free memory.
// Most framework methods do not free memory.
- return true;
+ return false;
}
// At this point the only thing left to handle is straight function calls.
const FunctionDecl *FD = cast<FunctionCall>(Call)->getDecl();
if (!FD)
- return false;
+ return true;
ASTContext &ASTC = State->getStateManager().getContext();
// If it's one of the allocation functions we can reason about, we model
// its behavior explicitly.
if (isMemFunction(FD, ASTC))
- return true;
+ return false;
// If it's not a system call, assume it frees memory.
if (!Call->isInSystemHeader())
- return false;
+ return true;
// White list the system functions whose arguments escape.
const IdentifierInfo *II = FD->getIdentifier();
if (!II)
- return false;
+ return true;
StringRef FName = II->getName();
// White list the 'XXXNoCopy' CoreFoundation functions.
@@ -1928,10 +1959,10 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
StringRef DeallocatorName = DE->getFoundDecl()->getName();
if (DeallocatorName == "kCFAllocatorNull")
- return true;
+ return false;
}
}
- return false;
+ return true;
}
// Associating streams with malloced buffers. The pointer can escape if
@@ -1940,7 +1971,7 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
// Currently, we do not inspect the 'closefn' function (PR12101).
if (FName == "funopen")
if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
- return true;
+ return false;
// Do not warn on pointers passed to 'setbuf' when used with std streams,
// these leaks might be intentional when setting the buffer for stdio.
@@ -1952,7 +1983,7 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
if (D->getCanonicalDecl()->getName().find("std") != StringRef::npos)
- return false;
+ return true;
}
}
@@ -1966,7 +1997,7 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
FName == "CVPixelBufferCreateWithBytes" ||
FName == "CVPixelBufferCreateWithPlanarBytes" ||
FName == "OSAtomicEnqueue") {
- return false;
+ return true;
}
// Handle cases where we know a buffer's /address/ can escape.
@@ -1974,11 +2005,11 @@ bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
// even though the address escapes, it's still our responsibility to free the
// buffer.
if (Call->argumentsMayEscape())
- return false;
+ return true;
// Otherwise, assume that the function does not free memory.
// Most system calls do not free the memory.
- return true;
+ return false;
}
static bool retTrue(const RefState *RS) {
@@ -2012,9 +2043,11 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
bool(*CheckRefState)(const RefState*)) const {
// If we know that the call does not free memory, or we want to process the
// call later, keep tracking the top level arguments.
- if ((Kind == PSK_DirectEscapeOnCall ||
- Kind == PSK_IndirectEscapeOnCall) &&
- doesNotFreeMemOrInteresting(Call, State)) {
+ SymbolRef EscapingSymbol = 0;
+ if (Kind == PSK_DirectEscapeOnCall &&
+ !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
+ EscapingSymbol) &&
+ !EscapingSymbol) {
return State;
}
@@ -2023,6 +2056,9 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
I != E; ++I) {
SymbolRef sym = *I;
+ if (EscapingSymbol && EscapingSymbol != sym)
+ continue;
+
if (const RefState *RS = State->get<RegionState>(sym)) {
if (RS->isAllocated() && CheckRefState(RS)) {
State = State->remove<RegionState>(sym);
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index 34425e314062..0cdf911bb4b1 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -213,11 +213,11 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows(
e = PossibleMallocOverflows.end();
i != e;
++i) {
- SourceRange R = i->mulop->getSourceRange();
BR.EmitBasicReport(D, "malloc() size overflow", categories::UnixAPI,
"the computation of the size of the memory allocation may overflow",
PathDiagnosticLocation::createOperatorLoc(i->mulop,
- BR.getSourceManager()), &R, 1);
+ BR.getSourceManager()),
+ i->mulop->getSourceRange());
}
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index d29f34fb03e2..6c776eb9ebb5 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -239,7 +239,7 @@ public:
BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
categories::UnixAPI,
OS.str(),
- L, Ranges.data(), Ranges.size());
+ L, Ranges);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 0009e1b7cf49..0e1064ef53a6 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -26,31 +26,29 @@ using namespace ento;
namespace {
-class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr>,
+class NoReturnFunctionChecker : public Checker< check::PostCall,
check::PostObjCMessage > {
public:
- void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
};
}
-void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
+void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
- const Expr *Callee = CE->getCallee();
+ bool BuildSinks = false;
- bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
+ BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
- if (!BuildSinks) {
- SVal L = state->getSVal(Callee, C.getLocationContext());
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return;
+ const Expr *Callee = CE.getOriginExpr();
+ if (!BuildSinks && Callee)
+ BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
- if (FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn())
- BuildSinks = true;
- else if (const IdentifierInfo *II = FD->getIdentifier()) {
+ if (!BuildSinks && CE.isGlobalCFunction()) {
+ if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
// HACK: Some functions are not marked noreturn, and don't return.
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.
@@ -66,6 +64,9 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
.Case("assfail", true)
.Case("db_error", true)
.Case("__assert", true)
+ // For the purpose of static analysis, we do not care that
+ // this MSVC function will return if the user decides to continue.
+ .Case("_wassert", true)
.Case("__assert_rtn", true)
.Case("__assert_fail", true)
.Case("dtrace_assfail", true)
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 4a0309de044e..503b1b501a71 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -140,12 +140,11 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
<< Name << "' must be a C array of pointer-sized values, not '"
<< Arg->getType().getAsString() << "'";
- SourceRange R = Arg->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport(AC->getDecl(),
OsName.str(), categories::CoreFoundationObjectiveC,
- Os.str(), CELoc, &R, 1);
+ Os.str(), CELoc, Arg->getSourceRange());
}
// Recurse and check children.
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 0f456ea8d785..c474e78310fa 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -28,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
@@ -41,116 +42,36 @@
using namespace clang;
using namespace ento;
+using namespace objc_retain;
using llvm::StrInStrNoCase;
//===----------------------------------------------------------------------===//
-// Primitives used for constructing summaries for function/method calls.
+// Adapters for FoldingSet.
//===----------------------------------------------------------------------===//
-/// ArgEffect is used to summarize a function/method call's effect on a
-/// particular argument.
-enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
- DecRefBridgedTransfered,
- IncRefMsg, IncRef, MakeCollectable, MayEscape,
-
- // Stop tracking the argument - the effect of the call is
- // unknown.
- StopTracking,
-
- // In some cases, we obtain a better summary for this checker
- // by looking at the call site than by inlining the function.
- // Signifies that we should stop tracking the symbol even if
- // the function is inlined.
- StopTrackingHard,
-
- // The function decrements the reference count and the checker
- // should stop tracking the argument.
- DecRefAndStopTrackingHard, DecRefMsgAndStopTrackingHard
- };
-
namespace llvm {
template <> struct FoldingSetTrait<ArgEffect> {
-static inline void Profile(const ArgEffect X, FoldingSetNodeID& ID) {
+static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
ID.AddInteger((unsigned) X);
}
};
+template <> struct FoldingSetTrait<RetEffect> {
+ static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) {
+ ID.AddInteger((unsigned) X.getKind());
+ ID.AddInteger((unsigned) X.getObjKind());
+}
+};
} // end llvm namespace
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+
/// ArgEffects summarizes the effects of a function/method call on all of
/// its arguments.
typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects;
namespace {
-
-/// RetEffect is used to summarize a function/method call's behavior with
-/// respect to its return value.
-class RetEffect {
-public:
- enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol,
- NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
- OwnedWhenTrackedReceiver,
- // Treat this function as returning a non-tracked symbol even if
- // the function has been inlined. This is used where the call
- // site summary is more presise than the summary indirectly produced
- // by inlining the function
- NoRetHard
- };
-
- enum ObjKind { CF, ObjC, AnyObj };
-
-private:
- Kind K;
- ObjKind O;
-
- RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
-
-public:
- Kind getKind() const { return K; }
-
- ObjKind getObjKind() const { return O; }
-
- bool isOwned() const {
- return K == OwnedSymbol || K == OwnedAllocatedSymbol ||
- K == OwnedWhenTrackedReceiver;
- }
-
- bool operator==(const RetEffect &Other) const {
- return K == Other.K && O == Other.O;
- }
-
- static RetEffect MakeOwnedWhenTrackedReceiver() {
- return RetEffect(OwnedWhenTrackedReceiver, ObjC);
- }
-
- static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) {
- return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o);
- }
- static RetEffect MakeNotOwned(ObjKind o) {
- return RetEffect(NotOwnedSymbol, o);
- }
- static RetEffect MakeGCNotOwned() {
- return RetEffect(GCNotOwnedSymbol, ObjC);
- }
- static RetEffect MakeARCNotOwned() {
- return RetEffect(ARCNotOwnedSymbol, ObjC);
- }
- static RetEffect MakeNoRet() {
- return RetEffect(NoRet);
- }
- static RetEffect MakeNoRetHard() {
- return RetEffect(NoRetHard);
- }
-
- void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddInteger((unsigned) K);
- ID.AddInteger((unsigned) O);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// Reference-counting logic (typestate + counts).
-//===----------------------------------------------------------------------===//
-
class RefVal {
public:
enum Kind {
@@ -396,7 +317,7 @@ public:
return DefaultArgEffect;
}
-
+
void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) {
Args = af.add(Args, idx, e);
}
@@ -496,8 +417,6 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
}
};
-template <>
-struct isPodLike<ObjCSummaryKey> { static const bool value = true; };
} // end llvm namespace
namespace {
@@ -631,7 +550,7 @@ class RetainSummaryManager {
/// data in ScratchArgs.
ArgEffects getArgEffects();
- enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
+ enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
const RetainSummary *getUnarySummary(const FunctionType* FT,
UnaryFuncKind func);
@@ -885,6 +804,10 @@ static bool isRelease(const FunctionDecl *FD, StringRef FName) {
return FName.endswith("Release");
}
+static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
+ return FName.endswith("Autorelease");
+}
+
static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
// FIXME: Remove FunctionDecl parameter.
// FIXME: Is it really okay if MakeCollectable isn't a suffix?
@@ -895,7 +818,7 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
switch (E) {
case DoNothing:
case Autorelease:
- case DecRefBridgedTransfered:
+ case DecRefBridgedTransferred:
case IncRef:
case IncRefMsg:
case MakeCollectable:
@@ -1144,12 +1067,19 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
- if (isRetain(FD, FName))
+ if (isRetain(FD, FName)) {
S = getUnarySummary(FT, cfretain);
- else if (isMakeCollectable(FD, FName))
+ } else if (isAutorelease(FD, FName)) {
+ S = getUnarySummary(FT, cfautorelease);
+ // The headers use cf_consumed, but we can fully model CFAutorelease
+ // ourselves.
+ AllowAnnotations = false;
+ } else if (isMakeCollectable(FD, FName)) {
S = getUnarySummary(FT, cfmakecollectable);
- else
+ AllowAnnotations = false;
+ } else {
S = getCFCreateGetRuleSummary(FD);
+ }
break;
}
@@ -1252,9 +1182,10 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
ArgEffect Effect;
switch (func) {
- case cfretain: Effect = IncRef; break;
- case cfrelease: Effect = DecRef; break;
- case cfmakecollectable: Effect = MakeCollectable; break;
+ case cfretain: Effect = IncRef; break;
+ case cfrelease: Effect = DecRef; break;
+ case cfautorelease: Effect = Autorelease; break;
+ case cfmakecollectable: Effect = MakeCollectable; break;
}
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
@@ -1823,16 +1754,6 @@ void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
addExtraText(GCModeDescription);
}
-// FIXME: This should be a method on SmallVector.
-static inline bool contains(const SmallVectorImpl<ArgEffect>& V,
- ArgEffect X) {
- for (SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end();
- I!=E; ++I)
- if (*I == X) return true;
-
- return false;
-}
-
static bool isNumericLiteralExpression(const Expr *E) {
// FIXME: This set of cases was copied from SemaExprObjC.
return isa<IntegerLiteral>(E) ||
@@ -1994,7 +1915,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
RefVal PrevV = *PrevT;
// Specially handle -dealloc.
- if (!GCEnabled && contains(AEffects, Dealloc)) {
+ if (!GCEnabled && std::find(AEffects.begin(), AEffects.end(), Dealloc) !=
+ AEffects.end()) {
// Determine if the object's reference count was pushed to zero.
assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
// We may not have transitioned to 'release' if we hit an error.
@@ -2007,7 +1929,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
}
// Specially handle CFMakeCollectable and friends.
- if (contains(AEffects, MakeCollectable)) {
+ if (std::find(AEffects.begin(), AEffects.end(), MakeCollectable) !=
+ AEffects.end()) {
// Get the name of the function.
const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
SVal X =
@@ -2686,7 +2609,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
AE = IncRef;
break;
case clang::OBC_BridgeTransfer:
- AE = DecRefBridgedTransfered;
+ AE = DecRefBridgedTransferred;
break;
}
@@ -3074,7 +2997,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
break;
case DecRef:
- case DecRefBridgedTransfered:
+ case DecRefBridgedTransferred:
case DecRefAndStopTrackingHard:
switch (V.getKind()) {
default:
@@ -3084,8 +3007,8 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case RefVal::Owned:
assert(V.getCount() > 0);
if (V.getCount() == 1)
- V = V ^ (E == DecRefBridgedTransfered ?
- RefVal::NotOwned : RefVal::Released);
+ V = V ^ (E == DecRefBridgedTransferred ? RefVal::NotOwned
+ : RefVal::Released);
else if (E == DecRefAndStopTrackingHard)
return removeRefBinding(state, sym);
@@ -3193,11 +3116,13 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
canEval = II->isStr("NSMakeCollectable");
} else if (ResultTy->isPointerType()) {
// Handle: (CF|CG)Retain
+ // CFAutorelease
// CFMakeCollectable
// It's okay to be a little sloppy here (CGMakeCollectable doesn't exist).
if (cocoa::isRefType(ResultTy, "CF", FName) ||
cocoa::isRefType(ResultTy, "CG", FName)) {
- canEval = isRetain(FD, FName) || isMakeCollectable(FD, FName);
+ canEval = isRetain(FD, FName) || isAutorelease(FD, FName) ||
+ isMakeCollectable(FD, FName);
}
}
@@ -3445,6 +3370,16 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
}
}
+ // If we are storing the value into an auto function scope variable annotated
+ // with (__attribute__((cleanup))), stop tracking the value to avoid leak
+ // false positives.
+ if (const VarRegion *LVR = dyn_cast_or_null<VarRegion>(loc.getAsRegion())) {
+ const VarDecl *VD = LVR->getDecl();
+ if (VD->getAttr<CleanupAttr>()) {
+ escapes = true;
+ }
+ }
+
// If our store can represent the binding and we aren't storing to something
// that doesn't have local storage then just return and have the simulation
// state continue as is.
@@ -3635,6 +3570,13 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
+ // Don't process anything within synthesized bodies.
+ const LocationContext *LCtx = Pred->getLocationContext();
+ if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ assert(LCtx->getParent());
+ return;
+ }
+
for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx,
I->first, I->second);
@@ -3646,7 +3588,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
// We will do that later.
// FIXME: we should instead check for imbalances of the retain/releases,
// and suggest annotations.
- if (Ctx.getLocationContext()->getParent())
+ if (LCtx->getParent())
return;
B = state->get<RefBindings>();
@@ -3747,3 +3689,37 @@ void ento::registerRetainCountChecker(CheckerManager &Mgr) {
Mgr.registerChecker<RetainCountChecker>(Mgr.getAnalyzerOptions());
}
+//===----------------------------------------------------------------------===//
+// Implementation of the CallEffects API.
+//===----------------------------------------------------------------------===//
+
+namespace clang { namespace ento { namespace objc_retain {
+
+// This is a bit gross, but it allows us to populate CallEffects without
+// creating a bunch of accessors. This kind is very localized, so the
+// damage of this macro is limited.
+#define createCallEffect(D, KIND)\
+ ASTContext &Ctx = D->getASTContext();\
+ LangOptions L = Ctx.getLangOpts();\
+ RetainSummaryManager M(Ctx, L.GCOnly, L.ObjCAutoRefCount);\
+ const RetainSummary *S = M.get ## KIND ## Summary(D);\
+ CallEffects CE(S->getRetEffect());\
+ CE.Receiver = S->getReceiverEffect();\
+ unsigned N = D->param_size();\
+ for (unsigned i = 0; i < N; ++i) {\
+ CE.Args.push_back(S->getArg(i));\
+ }
+
+CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
+ createCallEffect(MD, Method);
+ return CE;
+}
+
+CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
+ createCallEffect(FD, Function);
+ return CE;
+}
+
+#undef createCallEffect
+
+}}}
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 1ccf339bacc1..9ca0ab5d7fb7 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -227,8 +227,8 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
ExplodedNode *ErrNode) const {
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
- for (SmallVector<SymbolRef, 2>::iterator
- I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
+ for (SmallVectorImpl<SymbolRef>::iterator
+ I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
BugReport *R = new BugReport(*LeakBugType,
"Opened file is never closed; potential resource leak", ErrNode);
R->markInteresting(*I);
@@ -259,9 +259,7 @@ SimpleStreamChecker::checkPointerEscape(ProgramStateRef State,
const CallEvent *Call,
PointerEscapeKind Kind) const {
// If we know that the call cannot close a file, there is nothing to do.
- if ((Kind == PSK_DirectEscapeOnCall ||
- Kind == PSK_IndirectEscapeOnCall) &&
- guaranteedNotToCloseFile(*Call)) {
+ if (Kind == PSK_DirectEscapeOnCall && guaranteedNotToCloseFile(*Call)) {
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 673356319833..3f6549de56b0 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -40,6 +40,15 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
if (state->getSVal(B, LCtx).isUndef()) {
+
+ // Do not report assignments of uninitialized values inside swap functions.
+ // This should allow to swap partially uninitialized structs
+ // (radar://14129997)
+ if (const FunctionDecl *EnclosingFunctionDecl =
+ dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
+ if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
+ return;
+
// Generate an error node.
ExplodedNode *N = C.generateSink();
if (!N)
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index 176ee480826c..5df8846766e1 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -42,7 +43,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
// Don't warn if we're in an implicitly-generated constructor.
const Decl *D = C.getLocationContext()->getDecl();
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
- if (Ctor->isImplicitlyDefined())
+ if (Ctor->isDefaulted())
return;
ExplodedNode *N = C.generateSink();
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index e04f49c3746d..016e3c804592 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -38,6 +38,14 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (!val.isUndef())
return;
+ // Do not report assignments of uninitialized values inside swap functions.
+ // This should allow to swap partially uninitialized structs
+ // (radar://14129997)
+ if (const FunctionDecl *EnclosingFunctionDecl =
+ dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
+ if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
+ return;
+
ExplodedNode *N = C.generateSink();
if (!N)
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 91c2ffb5aabf..a40b5a3e8378 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -67,9 +67,12 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
I != E; ++I) {
const ProgramPoint &P = I->getLocation();
LC = P.getLocationContext();
+ if (!LC->inTopFrame())
+ continue;
if (!D)
D = LC->getAnalysisDeclContext()->getDecl();
+
// Save the CFG if we don't have it already
if (!C)
C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 06f01ad75422..7b6adbfad87c 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -191,7 +191,7 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
"Call pure virtual function during construction or "
"Destruction",
"Cplusplus",
- os.str(), CELoc, &R, 1);
+ os.str(), CELoc, R);
return;
}
else {
@@ -201,7 +201,7 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
"Call virtual function during construction or "
"Destruction",
"Cplusplus",
- os.str(), CELoc, &R, 1);
+ os.str(), CELoc, R);
return;
}
}
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index ae707395fc5a..9dcf58babd27 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -140,6 +140,12 @@ bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
/*Default=*/false);
}
+bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() {
+ return getBooleanOption(InlineCXXSharedPtrDtor,
+ "c++-shared_ptr-inlining",
+ /*Default=*/false);
+}
+
bool AnalyzerOptions::mayInlineObjCMethod() {
return getBooleanOption(ObjCInliningMode,
@@ -171,6 +177,12 @@ bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
/* Default = */ false);
}
+bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
+ return getBooleanOption(ReportIssuesInMainSourceFile,
+ "report-in-main-source-file",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index a85235c3e401..1940fa79fda3 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -18,8 +18,10 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/SourceManager.h"
@@ -162,13 +164,6 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front();
- // Throw away pieces with invalid locations. Note that we can't throw away
- // calls just yet because they might have something interesting inside them.
- // If so, their locations will be adjusted as necessary later.
- if (piece->getKind() != PathDiagnosticPiece::Call &&
- piece->getLocation().asLocation().isInvalid())
- continue;
-
switch (piece->getKind()) {
case PathDiagnosticPiece::Call: {
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
@@ -210,9 +205,15 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
return containsSomethingInteresting;
}
+/// Returns true if the given decl has been implicitly given a body, either by
+/// the analyzer or by the compiler proper.
+static bool hasImplicitBody(const Decl *D) {
+ assert(D);
+ return D->isImplicit() || !D->hasBody();
+}
+
/// Recursively scan through a path and make sure that all call pieces have
-/// valid locations. Note that all other pieces with invalid locations should
-/// have already been pruned out.
+/// valid locations.
static void adjustCallLocations(PathPieces &Pieces,
PathDiagnosticLocation *LastCallLocation = 0) {
for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
@@ -224,11 +225,10 @@ static void adjustCallLocations(PathPieces &Pieces,
}
if (LastCallLocation) {
- if (!Call->callEnter.asLocation().isValid() ||
- Call->getCaller()->isImplicit())
+ bool CallerIsImplicit = hasImplicitBody(Call->getCaller());
+ if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
Call->callEnter = *LastCallLocation;
- if (!Call->callReturn.asLocation().isValid() ||
- Call->getCaller()->isImplicit())
+ if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
Call->callReturn = *LastCallLocation;
}
@@ -236,7 +236,7 @@ static void adjustCallLocations(PathPieces &Pieces,
// it contains any informative diagnostics.
PathDiagnosticLocation *ThisCallLocation;
if (Call->callEnterWithin.asLocation().isValid() &&
- !Call->getCallee()->isImplicit())
+ !hasImplicitBody(Call->getCallee()))
ThisCallLocation = &Call->callEnterWithin;
else
ThisCallLocation = &Call->callEnter;
@@ -246,6 +246,61 @@ static void adjustCallLocations(PathPieces &Pieces,
}
}
+/// Remove edges in and out of C++ default initializer expressions. These are
+/// for fields that have in-class initializers, as opposed to being initialized
+/// explicitly in a constructor or braced list.
+static void removeEdgesToDefaultInitializers(PathPieces &Pieces) {
+ for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
+ if (PathDiagnosticCallPiece *C = dyn_cast<PathDiagnosticCallPiece>(*I))
+ removeEdgesToDefaultInitializers(C->path);
+
+ if (PathDiagnosticMacroPiece *M = dyn_cast<PathDiagnosticMacroPiece>(*I))
+ removeEdgesToDefaultInitializers(M->subPieces);
+
+ if (PathDiagnosticControlFlowPiece *CF =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*I)) {
+ const Stmt *Start = CF->getStartLocation().asStmt();
+ const Stmt *End = CF->getEndLocation().asStmt();
+ if (Start && isa<CXXDefaultInitExpr>(Start)) {
+ I = Pieces.erase(I);
+ continue;
+ } else if (End && isa<CXXDefaultInitExpr>(End)) {
+ PathPieces::iterator Next = llvm::next(I);
+ if (Next != E) {
+ if (PathDiagnosticControlFlowPiece *NextCF =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*Next)) {
+ NextCF->setStartLocation(CF->getStartLocation());
+ }
+ }
+ I = Pieces.erase(I);
+ continue;
+ }
+ }
+
+ I++;
+ }
+}
+
+/// Remove all pieces with invalid locations as these cannot be serialized.
+/// We might have pieces with invalid locations as a result of inlining Body
+/// Farm generated functions.
+static void removePiecesWithInvalidLocations(PathPieces &Pieces) {
+ for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
+ if (PathDiagnosticCallPiece *C = dyn_cast<PathDiagnosticCallPiece>(*I))
+ removePiecesWithInvalidLocations(C->path);
+
+ if (PathDiagnosticMacroPiece *M = dyn_cast<PathDiagnosticMacroPiece>(*I))
+ removePiecesWithInvalidLocations(M->subPieces);
+
+ if (!(*I)->getLocation().isValid() ||
+ !(*I)->getLocation().asLocation().isValid()) {
+ I = Pieces.erase(I);
+ continue;
+ }
+ I++;
+ }
+}
+
//===----------------------------------------------------------------------===//
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
@@ -344,42 +399,40 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
return Loc;
}
-static bool IsNested(const Stmt *S, ParentMap &PM) {
+static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
if (isa<Expr>(S) && PM.isConsumedExpr(cast<Expr>(S)))
- return true;
+ return PM.getParentIgnoreParens(S);
const Stmt *Parent = PM.getParentIgnoreParens(S);
+ if (!Parent)
+ return 0;
- if (Parent)
- switch (Parent->getStmtClass()) {
- case Stmt::ForStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::WhileStmtClass:
- return true;
- default:
- break;
- }
+ switch (Parent->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ return Parent;
+ default:
+ break;
+ }
- return false;
+ return 0;
}
-PathDiagnosticLocation
-PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
- assert(S && "Null Stmt *passed to getEnclosingStmtLocation");
- ParentMap &P = getParentMap();
- SourceManager &SMgr = getSourceManager();
-
- while (IsNested(S, P)) {
- const Stmt *Parent = P.getParentIgnoreParens(S);
-
- if (!Parent)
- break;
+static PathDiagnosticLocation
+getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P,
+ const LocationContext *LC, bool allowNestedContexts) {
+ if (!S)
+ return PathDiagnosticLocation();
+ while (const Stmt *Parent = getEnclosingParent(S, P)) {
switch (Parent->getStmtClass()) {
case Stmt::BinaryOperatorClass: {
const BinaryOperator *B = cast<BinaryOperator>(Parent);
if (B->isLogicalOp())
- return PathDiagnosticLocation(S, SMgr, LC);
+ return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
break;
}
case Stmt::CompoundStmtClass:
@@ -388,7 +441,7 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
case Stmt::ChooseExprClass:
// Similar to '?' if we are referring to condition, just have the edge
// point to the entire choose expression.
- if (cast<ChooseExpr>(Parent)->getCond() == S)
+ if (allowNestedContexts || cast<ChooseExpr>(Parent)->getCond() == S)
return PathDiagnosticLocation(Parent, SMgr, LC);
else
return PathDiagnosticLocation(S, SMgr, LC);
@@ -396,10 +449,15 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
case Stmt::ConditionalOperatorClass:
// For '?', if we are referring to condition, just have the edge point
// to the entire '?' expression.
- if (cast<AbstractConditionalOperator>(Parent)->getCond() == S)
+ if (allowNestedContexts ||
+ cast<AbstractConditionalOperator>(Parent)->getCond() == S)
return PathDiagnosticLocation(Parent, SMgr, LC);
else
return PathDiagnosticLocation(S, SMgr, LC);
+ case Stmt::CXXForRangeStmtClass:
+ if (cast<CXXForRangeStmt>(Parent)->getBody() == S)
+ return PathDiagnosticLocation(S, SMgr, LC);
+ break;
case Stmt::DoStmtClass:
return PathDiagnosticLocation(S, SMgr, LC);
case Stmt::ForStmtClass:
@@ -427,33 +485,16 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
- // Special case: DeclStmts can appear in for statement declarations, in which
- // case the ForStmt is the context.
- if (isa<DeclStmt>(S)) {
- if (const Stmt *Parent = P.getParent(S)) {
- switch (Parent->getStmtClass()) {
- case Stmt::ForStmtClass:
- case Stmt::ObjCForCollectionStmtClass:
- return PathDiagnosticLocation(Parent, SMgr, LC);
- default:
- break;
- }
- }
- }
- else if (isa<BinaryOperator>(S)) {
- // Special case: the binary operator represents the initialization
- // code in a for statement (this can happen when the variable being
- // initialized is an old variable.
- if (const ForStmt *FS =
- dyn_cast_or_null<ForStmt>(P.getParentIgnoreParens(S))) {
- if (FS->getInit() == S)
- return PathDiagnosticLocation(FS, SMgr, LC);
- }
- }
-
return PathDiagnosticLocation(S, SMgr, LC);
}
+PathDiagnosticLocation
+PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
+ assert(S && "Null Stmt passed to getEnclosingStmtLocation");
+ return ::getEnclosingStmtLocation(S, getSourceManager(), getParentMap(), LC,
+ /*allowNestedContexts=*/false);
+}
+
//===----------------------------------------------------------------------===//
// "Visitors only" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
@@ -1261,25 +1302,35 @@ static void reversePropagateInterestingSymbols(BugReport &R,
// Functions for determining if a loop was executed 0 times.
//===----------------------------------------------------------------------===//
-/// Return true if the terminator is a loop and the destination is the
-/// false branch.
-static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
+static bool isLoop(const Stmt *Term) {
switch (Term->getStmtClass()) {
case Stmt::ForStmtClass:
case Stmt::WhileStmtClass:
case Stmt::ObjCForCollectionStmtClass:
- break;
+ case Stmt::CXXForRangeStmtClass:
+ return true;
default:
// Note that we intentionally do not include do..while here.
return false;
}
+}
- // Did we take the false branch?
+static bool isJumpToFalseBranch(const BlockEdge *BE) {
const CFGBlock *Src = BE->getSrc();
assert(Src->succ_size() == 2);
return (*(Src->succ_begin()+1) == BE->getDst());
}
+/// Return true if the terminator is a loop and the destination is the
+/// false branch.
+static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
+ if (!isLoop(Term))
+ return false;
+
+ // Did we take the false branch?
+ return isJumpToFalseBranch(BE);
+}
+
static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
while (SubS) {
if (SubS == S)
@@ -1306,6 +1357,15 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
const Stmt *LoopBody = 0;
switch (Term->getStmtClass()) {
+ case Stmt::CXXForRangeStmtClass: {
+ const CXXForRangeStmt *FR = cast<CXXForRangeStmt>(Term);
+ if (isContainedByStmt(PM, FR->getInc(), S))
+ return true;
+ if (isContainedByStmt(PM, FR->getLoopVarStmt(), S))
+ return true;
+ LoopBody = FR->getBody();
+ break;
+ }
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(Term);
if (isContainedByStmt(PM, FS->getInc(), S))
@@ -1539,17 +1599,17 @@ static void addEdgeToPath(PathPieces &path,
return;
SourceLocation NewLocL = NewLoc.asLocation();
- if (NewLocL.isInvalid() || NewLocL.isMacroID())
+ if (NewLocL.isInvalid())
return;
- if (!PrevLoc.isValid()) {
+ if (!PrevLoc.isValid() || !PrevLoc.asLocation().isValid()) {
PrevLoc = NewLoc;
return;
}
- // FIXME: ignore intra-macro edges for now.
- if (NewLoc.asLocation().getExpansionLoc() ==
- PrevLoc.asLocation().getExpansionLoc())
+ // Ignore self-edges, which occur when there are multiple nodes at the same
+ // statement.
+ if (NewLoc.asStmt() && NewLoc.asStmt() == PrevLoc.asStmt())
return;
path.push_front(new PathDiagnosticControlFlowPiece(NewLoc,
@@ -1557,6 +1617,23 @@ static void addEdgeToPath(PathPieces &path,
PrevLoc = NewLoc;
}
+/// A customized wrapper for CFGBlock::getTerminatorCondition()
+/// which returns the element for ObjCForCollectionStmts.
+static const Stmt *getTerminatorCondition(const CFGBlock *B) {
+ const Stmt *S = B->getTerminatorCondition();
+ if (const ObjCForCollectionStmt *FS =
+ dyn_cast_or_null<ObjCForCollectionStmt>(S))
+ return FS->getElement();
+ return S;
+}
+
+static const char StrEnteringLoop[] = "Entering loop body";
+static const char StrLoopBodyZero[] = "Loop body executed 0 times";
+static const char StrLoopRangeEmpty[] =
+ "Loop body skipped when range is empty";
+static const char StrLoopCollectionEmpty[] =
+ "Loop body skipped when collection is empty";
+
static bool
GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
@@ -1569,35 +1646,81 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
StackDiagVector CallStack;
InterestingExprs IE;
- // Record the last location for a given visited stack frame.
- llvm::DenseMap<const StackFrameContext *, PathDiagnosticLocation>
- PrevLocMap;
+ PathDiagnosticLocation PrevLoc = PD.getLocation();
const ExplodedNode *NextNode = N->getFirstPred();
while (NextNode) {
N = NextNode;
NextNode = N->getFirstPred();
ProgramPoint P = N->getLocation();
- const LocationContext *LC = N->getLocationContext();
- assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == LC);
- LCM[&PD.getActivePath()] = LC;
- PathDiagnosticLocation &PrevLoc = PrevLocMap[LC->getCurrentStackFrame()];
do {
- if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
- // For expressions, make sure we propagate the
- // interesting symbols correctly.
- if (const Expr *Ex = PS->getStmtAs<Expr>())
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
- N->getLocationContext());
+ // Have we encountered an entrance to a call? It may be
+ // the case that we have not encountered a matching
+ // call exit before this point. This means that the path
+ // terminated within the call itself.
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
+ // 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);
+
+ // Did we visit an entire call?
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ PathDiagnosticPiece *P = PD.getActivePath().front().getPtr();
+ C = cast<PathDiagnosticCallPiece>(P);
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+
+ // Since we just transferred the path over to the call piece,
+ // reset the mapping from active to location context.
+ assert(PD.getActivePath().size() == 1 &&
+ PD.getActivePath().front() == C);
+ LCM[&PD.getActivePath()] = 0;
+
+ // Record the location context mapping for the path within
+ // the call.
+ assert(LCM[&C->path] == 0 ||
+ LCM[&C->path] == CE->getCalleeContext());
+ LCM[&C->path] = CE->getCalleeContext();
+
+ // If this is the first item in the active path, record
+ // the new mapping from active path to location context.
+ const LocationContext *&NewLC = LCM[&PD.getActivePath()];
+ if (!NewLC)
+ NewLC = N->getLocationContext();
- PathDiagnosticLocation L =
- PathDiagnosticLocation(PS->getStmt(), SM, LC);
- addEdgeToPath(PD.getActivePath(), PrevLoc, L, LC);
+ PDB.LC = NewLC;
+ }
+ C->setCallee(*CE, SM);
+
+ // Update the previous location in the active path.
+ PrevLoc = C->getLocation();
+
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
break;
}
+ // Query the location context here and the previous location
+ // as processing CallEnter may change the active path.
+ PDB.LC = N->getLocationContext();
+
+ // Record the mapping from the active path to the location
+ // context.
+ assert(!LCM[&PD.getActivePath()] ||
+ LCM[&PD.getActivePath()] == PDB.LC);
+ LCM[&PD.getActivePath()] = PDB.LC;
+
// Have we encountered an exit from a function call?
if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
const Stmt *S = CE->getCalleeContext()->getCallSite();
@@ -1617,7 +1740,9 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
LCM[&C->path] = CE->getCalleeContext();
// Add the edge to the return site.
- addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, PDB.LC);
+ PD.getActivePath().push_front(C);
+ PrevLoc.invalidate();
// Make the contents of the call the active path for now.
PD.pushActivePath(&C->path);
@@ -1625,33 +1750,21 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
break;
}
- // Have we encountered an entrance to a call? It may be
- // the case that we have not encountered a matching
- // call exit before this point. This means that the path
- // terminated within the call itself.
- if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
- // Add an edge to the start of the function.
- const Decl *D = CE->getCalleeContext()->getDecl();
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createBegin(D, SM), LC);
-
- // Did we visit an entire call?
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
-
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
- LCM[&C->path] = CE->getCalleeContext();
- }
- C->setCallee(*CE, SM);
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
+ // For expressions, make sure we propagate the
+ // interesting symbols correctly.
+ if (const Expr *Ex = PS->getStmtAs<Expr>())
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().getPtr(), Ex,
+ N->getLocationContext());
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
+ // Add an edge. If this is an ObjCForCollectionStmt do
+ // not add an edge here as it appears in the CFG both
+ // as a terminator and as a terminator condition.
+ if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation(PS->getStmt(), SM, PDB.LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
}
break;
}
@@ -1673,47 +1786,76 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC);
- const CompoundStmt *CS = NULL;
+ const Stmt *Body = NULL;
if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(FS->getBody());
+ Body = FS->getBody();
else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(WS->getBody());
+ Body = WS->getBody();
+ else if (const ObjCForCollectionStmt *OFS =
+ dyn_cast<ObjCForCollectionStmt>(Loop)) {
+ Body = OFS->getBody();
+ } else if (const CXXForRangeStmt *FRS =
+ dyn_cast<CXXForRangeStmt>(Loop)) {
+ Body = FRS->getBody();
+ }
+ // do-while statements are explicitly excluded here
PathDiagnosticEventPiece *p =
new PathDiagnosticEventPiece(L, "Looping back to the head "
"of the loop");
p->setPrunable(true);
- addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC);
PD.getActivePath().push_front(p);
- if (CS) {
+ if (const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createEndBrace(CS, SM), LC);
+ PathDiagnosticLocation::createEndBrace(CS, SM),
+ PDB.LC);
}
}
-
+
const CFGBlock *BSrc = BE->getSrc();
ParentMap &PM = PDB.getParentMap();
if (const Stmt *Term = BSrc->getTerminator()) {
// Are we jumping past the loop body without ever executing the
// loop (because the condition was false)?
- if (isLoopJumpPastBody(Term, &*BE) &&
- !isInLoopBody(PM,
- getStmtBeforeCond(PM,
- BSrc->getTerminatorCondition(),
- N),
- Term))
- {
+ if (isLoop(Term)) {
+ const Stmt *TermCond = getTerminatorCondition(BSrc);
+ bool IsInLoopBody =
+ isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term);
+
+ const char *str = 0;
+
+ if (isJumpToFalseBranch(&*BE)) {
+ if (!IsInLoopBody) {
+ if (isa<ObjCForCollectionStmt>(Term)) {
+ str = StrLoopCollectionEmpty;
+ } else if (isa<CXXForRangeStmt>(Term)) {
+ str = StrLoopRangeEmpty;
+ } else {
+ str = StrLoopBodyZero;
+ }
+ }
+ } else {
+ str = StrEnteringLoop;
+ }
+
+ if (str) {
+ PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
+ PathDiagnosticEventPiece *PE =
+ new PathDiagnosticEventPiece(L, str);
+ PE->setPrunable(true);
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PE->getLocation(), PDB.LC);
+ PD.getActivePath().push_front(PE);
+ }
+ } else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
+ isa<GotoStmt>(Term)) {
PathDiagnosticLocation L(Term, SM, PDB.LC);
- PathDiagnosticEventPiece *PE =
- new PathDiagnosticEventPiece(L, "Loop body executed 0 times");
- PE->setPrunable(true);
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PE->getLocation(), LC);
- PD.getActivePath().push_front(PE);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
}
}
break;
@@ -1728,32 +1870,61 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
E = visitors.end();
I != E; ++I) {
if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *report)) {
- addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC);
PD.getActivePath().push_front(p);
updateStackPiecesWithMessage(p, CallStack);
}
}
}
+ // Add an edge to the start of the function.
+ // We'll prune it out later, but it helps make diagnostics more uniform.
+ const StackFrameContext *CalleeLC = PDB.LC->getCurrentStackFrame();
+ const Decl *D = CalleeLC->getDecl();
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM),
+ CalleeLC);
+
return report->isValid();
}
-const Stmt *getLocStmt(PathDiagnosticLocation L) {
+static const Stmt *getLocStmt(PathDiagnosticLocation L) {
if (!L.isValid())
return 0;
return L.asStmt();
}
-const Stmt *getStmtParent(const Stmt *S, ParentMap &PM) {
+static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) {
if (!S)
return 0;
- return PM.getParentIgnoreParens(S);
+
+ while (true) {
+ S = PM.getParentIgnoreParens(S);
+
+ if (!S)
+ break;
+
+ if (isa<ExprWithCleanups>(S) ||
+ isa<CXXBindTemporaryExpr>(S) ||
+ isa<SubstNonTypeTemplateParmExpr>(S))
+ continue;
+
+ break;
+ }
+
+ return S;
}
-#if 0
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) {
- // Note that we intentionally to do not handle || and && here.
switch (S->getStmtClass()) {
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(S);
+ if (!BO->isLogicalOp())
+ return false;
+ return BO->getLHS() == Cond || BO->getRHS() == Cond;
+ }
+ case Stmt::IfStmtClass:
+ return cast<IfStmt>(S)->getCond() == Cond;
case Stmt::ForStmtClass:
return cast<ForStmt>(S)->getCond() == Cond;
case Stmt::WhileStmtClass:
@@ -1768,46 +1939,410 @@ static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) {
return cast<SwitchStmt>(S)->getCond() == Cond;
case Stmt::BinaryConditionalOperatorClass:
return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
- case Stmt::ConditionalOperatorClass:
- return cast<ConditionalOperator>(S)->getCond() == Cond;
+ case Stmt::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(S);
+ return CO->getCond() == Cond ||
+ CO->getLHS() == Cond ||
+ CO->getRHS() == Cond;
+ }
case Stmt::ObjCForCollectionStmtClass:
return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
+ case Stmt::CXXForRangeStmtClass: {
+ const CXXForRangeStmt *FRS = cast<CXXForRangeStmt>(S);
+ return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
+ }
default:
return false;
}
}
-#endif
-typedef llvm::DenseSet<const PathDiagnosticControlFlowPiece *>
- ControlFlowBarrierSet;
+static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL) {
+ if (const ForStmt *FS = dyn_cast<ForStmt>(FL))
+ return FS->getInc() == S || FS->getInit() == S;
+ if (const CXXForRangeStmt *FRS = dyn_cast<CXXForRangeStmt>(FL))
+ return FRS->getInc() == S || FRS->getRangeStmt() == S ||
+ FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
+ return false;
+}
typedef llvm::DenseSet<const PathDiagnosticCallPiece *>
OptimizedCallsSet;
-static bool isBarrier(ControlFlowBarrierSet &CFBS,
- const PathDiagnosticControlFlowPiece *P) {
- return CFBS.count(P);
+/// Adds synthetic edges from top-level statements to their subexpressions.
+///
+/// This avoids a "swoosh" effect, where an edge from a top-level statement A
+/// points to a sub-expression B.1 that's not at the start of B. In these cases,
+/// we'd like to see an edge from A to B, then another one from B to B.1.
+static void addContextEdges(PathPieces &pieces, SourceManager &SM,
+ const ParentMap &PM, const LocationContext *LCtx) {
+ PathPieces::iterator Prev = pieces.end();
+ for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
+ Prev = I, ++I) {
+ PathDiagnosticControlFlowPiece *Piece =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*I);
+
+ if (!Piece)
+ continue;
+
+ PathDiagnosticLocation SrcLoc = Piece->getStartLocation();
+ SmallVector<PathDiagnosticLocation, 4> SrcContexts;
+
+ PathDiagnosticLocation NextSrcContext = SrcLoc;
+ const Stmt *InnerStmt = 0;
+ while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
+ SrcContexts.push_back(NextSrcContext);
+ InnerStmt = NextSrcContext.asStmt();
+ NextSrcContext = getEnclosingStmtLocation(InnerStmt, SM, PM, LCtx,
+ /*allowNested=*/true);
+ }
+
+ // Repeatedly split the edge as necessary.
+ // This is important for nested logical expressions (||, &&, ?:) where we
+ // want to show all the levels of context.
+ while (true) {
+ const Stmt *Dst = getLocStmt(Piece->getEndLocation());
+
+ // We are looking at an edge. Is the destination within a larger
+ // expression?
+ PathDiagnosticLocation DstContext =
+ getEnclosingStmtLocation(Dst, SM, PM, LCtx, /*allowNested=*/true);
+ if (!DstContext.isValid() || DstContext.asStmt() == Dst)
+ break;
+
+ // If the source is in the same context, we're already good.
+ if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
+ SrcContexts.end())
+ break;
+
+ // Update the subexpression node to point to the context edge.
+ Piece->setStartLocation(DstContext);
+
+ // Try to extend the previous edge if it's at the same level as the source
+ // context.
+ if (Prev != E) {
+ PathDiagnosticControlFlowPiece *PrevPiece =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*Prev);
+
+ if (PrevPiece) {
+ if (const Stmt *PrevSrc = getLocStmt(PrevPiece->getStartLocation())) {
+ const Stmt *PrevSrcParent = getStmtParent(PrevSrc, PM);
+ if (PrevSrcParent == getStmtParent(getLocStmt(DstContext), PM)) {
+ PrevPiece->setEndLocation(DstContext);
+ break;
+ }
+ }
+ }
+ }
+
+ // Otherwise, split the current edge into a context edge and a
+ // subexpression edge. Note that the context statement may itself have
+ // context.
+ Piece = new PathDiagnosticControlFlowPiece(SrcLoc, DstContext);
+ I = pieces.insert(I, Piece);
+ }
+ }
+}
+
+/// \brief Move edges from a branch condition to a branch target
+/// when the condition is simple.
+///
+/// This restructures some of the work of addContextEdges. That function
+/// creates edges this may destroy, but they work together to create a more
+/// aesthetically set of edges around branches. After the call to
+/// addContextEdges, we may have (1) an edge to the branch, (2) an edge from
+/// the branch to the branch condition, and (3) an edge from the branch
+/// condition to the branch target. We keep (1), but may wish to remove (2)
+/// and move the source of (3) to the branch if the branch condition is simple.
+///
+static void simplifySimpleBranches(PathPieces &pieces) {
+ for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
+
+ PathDiagnosticControlFlowPiece *PieceI =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*I);
+
+ if (!PieceI)
+ continue;
+
+ const Stmt *s1Start = getLocStmt(PieceI->getStartLocation());
+ const Stmt *s1End = getLocStmt(PieceI->getEndLocation());
+
+ if (!s1Start || !s1End)
+ continue;
+
+ PathPieces::iterator NextI = I; ++NextI;
+ if (NextI == E)
+ break;
+
+ PathDiagnosticControlFlowPiece *PieceNextI = 0;
+
+ while (true) {
+ if (NextI == E)
+ break;
+
+ PathDiagnosticEventPiece *EV = dyn_cast<PathDiagnosticEventPiece>(*NextI);
+ if (EV) {
+ StringRef S = EV->getString();
+ if (S == StrEnteringLoop || S == StrLoopBodyZero ||
+ S == StrLoopCollectionEmpty || S == StrLoopRangeEmpty) {
+ ++NextI;
+ continue;
+ }
+ break;
+ }
+
+ PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(*NextI);
+ break;
+ }
+
+ if (!PieceNextI)
+ continue;
+
+ const Stmt *s2Start = getLocStmt(PieceNextI->getStartLocation());
+ const Stmt *s2End = getLocStmt(PieceNextI->getEndLocation());
+
+ if (!s2Start || !s2End || s1End != s2Start)
+ continue;
+
+ // We only perform this transformation for specific branch kinds.
+ // We don't want to do this for do..while, for example.
+ if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
+ isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
+ isa<CXXForRangeStmt>(s1Start)))
+ continue;
+
+ // Is s1End the branch condition?
+ if (!isConditionForTerminator(s1Start, s1End))
+ continue;
+
+ // Perform the hoisting by eliminating (2) and changing the start
+ // location of (3).
+ PieceNextI->setStartLocation(PieceI->getStartLocation());
+ I = pieces.erase(I);
+ }
+}
+
+/// Returns the number of bytes in the given (character-based) SourceRange.
+///
+/// If the locations in the range are not on the same line, returns None.
+///
+/// Note that this does not do a precise user-visible character or column count.
+static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
+ SourceRange Range) {
+ SourceRange ExpansionRange(SM.getExpansionLoc(Range.getBegin()),
+ SM.getExpansionRange(Range.getEnd()).second);
+
+ FileID FID = SM.getFileID(ExpansionRange.getBegin());
+ if (FID != SM.getFileID(ExpansionRange.getEnd()))
+ return None;
+
+ bool Invalid;
+ const llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, &Invalid);
+ if (Invalid)
+ return None;
+
+ unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin());
+ unsigned EndOffset = SM.getFileOffset(ExpansionRange.getEnd());
+ StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
+
+ // We're searching the raw bytes of the buffer here, which might include
+ // escaped newlines and such. That's okay; we're trying to decide whether the
+ // SourceRange is covering a large or small amount of space in the user's
+ // editor.
+ if (Snippet.find_first_of("\r\n") != StringRef::npos)
+ return None;
+
+ // This isn't Unicode-aware, but it doesn't need to be.
+ return Snippet.size();
+}
+
+/// \sa getLengthOnSingleLine(SourceManager, SourceRange)
+static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
+ const Stmt *S) {
+ return getLengthOnSingleLine(SM, S->getSourceRange());
+}
+
+/// Eliminate two-edge cycles created by addContextEdges().
+///
+/// Once all the context edges are in place, there are plenty of cases where
+/// there's a single edge from a top-level statement to a subexpression,
+/// followed by a single path note, and then a reverse edge to get back out to
+/// the top level. If the statement is simple enough, the subexpression edges
+/// just add noise and make it harder to understand what's going on.
+///
+/// This function only removes edges in pairs, because removing only one edge
+/// might leave other edges dangling.
+///
+/// This will not remove edges in more complicated situations:
+/// - if there is more than one "hop" leading to or from a subexpression.
+/// - if there is an inlined call between the edges instead of a single event.
+/// - if the whole statement is large enough that having subexpression arrows
+/// might be helpful.
+static void removeContextCycles(PathPieces &Path, SourceManager &SM,
+ ParentMap &PM) {
+ for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
+ // Pattern match the current piece and its successor.
+ PathDiagnosticControlFlowPiece *PieceI =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*I);
+
+ if (!PieceI) {
+ ++I;
+ continue;
+ }
+
+ const Stmt *s1Start = getLocStmt(PieceI->getStartLocation());
+ const Stmt *s1End = getLocStmt(PieceI->getEndLocation());
+
+ PathPieces::iterator NextI = I; ++NextI;
+ if (NextI == E)
+ break;
+
+ PathDiagnosticControlFlowPiece *PieceNextI =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*NextI);
+
+ if (!PieceNextI) {
+ if (isa<PathDiagnosticEventPiece>(*NextI)) {
+ ++NextI;
+ if (NextI == E)
+ break;
+ PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(*NextI);
+ }
+
+ if (!PieceNextI) {
+ ++I;
+ continue;
+ }
+ }
+
+ const Stmt *s2Start = getLocStmt(PieceNextI->getStartLocation());
+ const Stmt *s2End = getLocStmt(PieceNextI->getEndLocation());
+
+ if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
+ const size_t MAX_SHORT_LINE_LENGTH = 80;
+ Optional<size_t> s1Length = getLengthOnSingleLine(SM, s1Start);
+ if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
+ Optional<size_t> s2Length = getLengthOnSingleLine(SM, s2Start);
+ if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
+ Path.erase(I);
+ I = Path.erase(NextI);
+ continue;
+ }
+ }
+ }
+
+ ++I;
+ }
+}
+
+/// \brief Return true if X is contained by Y.
+static bool lexicalContains(ParentMap &PM,
+ const Stmt *X,
+ const Stmt *Y) {
+ while (X) {
+ if (X == Y)
+ return true;
+ X = PM.getParent(X);
+ }
+ return false;
+}
+
+// Remove short edges on the same line less than 3 columns in difference.
+static void removePunyEdges(PathPieces &path,
+ SourceManager &SM,
+ ParentMap &PM) {
+
+ bool erased = false;
+
+ for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
+ erased ? I : ++I) {
+
+ erased = false;
+
+ PathDiagnosticControlFlowPiece *PieceI =
+ dyn_cast<PathDiagnosticControlFlowPiece>(*I);
+
+ if (!PieceI)
+ continue;
+
+ const Stmt *start = getLocStmt(PieceI->getStartLocation());
+ const Stmt *end = getLocStmt(PieceI->getEndLocation());
+
+ if (!start || !end)
+ continue;
+
+ const Stmt *endParent = PM.getParent(end);
+ if (!endParent)
+ continue;
+
+ if (isConditionForTerminator(end, endParent))
+ continue;
+
+ SourceLocation FirstLoc = start->getLocStart();
+ SourceLocation SecondLoc = end->getLocStart();
+
+ if (!SM.isWrittenInSameFile(FirstLoc, SecondLoc))
+ continue;
+ if (SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
+ std::swap(SecondLoc, FirstLoc);
+
+ SourceRange EdgeRange(FirstLoc, SecondLoc);
+ Optional<size_t> ByteWidth = getLengthOnSingleLine(SM, EdgeRange);
+
+ // If the statements are on different lines, continue.
+ if (!ByteWidth)
+ continue;
+
+ const size_t MAX_PUNY_EDGE_LENGTH = 2;
+ if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
+ // FIXME: There are enough /bytes/ between the endpoints of the edge, but
+ // there might not be enough /columns/. A proper user-visible column count
+ // is probably too expensive, though.
+ I = path.erase(I);
+ erased = true;
+ continue;
+ }
+ }
+}
+
+static void removeIdenticalEvents(PathPieces &path) {
+ for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
+ PathDiagnosticEventPiece *PieceI =
+ dyn_cast<PathDiagnosticEventPiece>(*I);
+
+ if (!PieceI)
+ continue;
+
+ PathPieces::iterator NextI = I; ++NextI;
+ if (NextI == E)
+ return;
+
+ PathDiagnosticEventPiece *PieceNextI =
+ dyn_cast<PathDiagnosticEventPiece>(*NextI);
+
+ if (!PieceNextI)
+ continue;
+
+ // Erase the second piece if it has the same exact message text.
+ if (PieceI->getString() == PieceNextI->getString()) {
+ path.erase(NextI);
+ }
+ }
}
static bool optimizeEdges(PathPieces &path, SourceManager &SM,
- ControlFlowBarrierSet &CFBS,
OptimizedCallsSet &OCS,
LocationContextMap &LCM) {
bool hasChanges = false;
const LocationContext *LC = LCM[&path];
assert(LC);
- bool isFirst = true;
+ ParentMap &PM = LC->getParentMap();
for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
- bool wasFirst = isFirst;
- isFirst = false;
-
// Optimize subpaths.
if (PathDiagnosticCallPiece *CallI = dyn_cast<PathDiagnosticCallPiece>(*I)){
// Record the fact that a call has been optimized so we only do the
// effort once.
if (!OCS.count(CallI)) {
- while (optimizeEdges(CallI->path, SM, CFBS, OCS, LCM)) {}
+ while (optimizeEdges(CallI->path, SM, OCS, LCM)) {}
OCS.insert(CallI);
}
++I;
@@ -1823,33 +2358,11 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
continue;
}
- ParentMap &PM = LC->getParentMap();
const Stmt *s1Start = getLocStmt(PieceI->getStartLocation());
const Stmt *s1End = getLocStmt(PieceI->getEndLocation());
const Stmt *level1 = getStmtParent(s1Start, PM);
const Stmt *level2 = getStmtParent(s1End, PM);
- if (wasFirst) {
-#if 0
- // Apply the "first edge" case for Rule V. here.
- if (s1Start && level1 && isConditionForTerminator(level1, s1Start)) {
- PathDiagnosticLocation NewLoc(level2, SM, LC);
- PieceI->setStartLocation(NewLoc);
- CFBS.insert(PieceI);
- return true;
- }
-#endif
- // Apply the "first edge" case for Rule III. here.
- if (!isBarrier(CFBS, PieceI) &&
- level1 && level2 && level2 == PM.getParent(level1)) {
- path.erase(I);
- // Since we are erasing the current edge at the start of the
- // path, just return now so we start analyzing the start of the path
- // again.
- return true;
- }
- }
-
PathPieces::iterator NextI = I; ++NextI;
if (NextI == E)
break;
@@ -1891,101 +2404,137 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
// Rule II.
//
- // If we have two consecutive control edges where we decend to a
- // subexpression and then pop out merge them.
+ // Eliminate edges between subexpressions and parent expressions
+ // when the subexpression is consumed.
//
// NOTE: this will be limited later in cases where we add barriers
// to prevent this optimization.
//
- // For example:
- //
- // (1.1 -> 1.1.1) -> (1.1.1 -> 1.2) becomes (1.1 -> 1.2).
- if (level1 && level2 &&
- level1 == level4 &&
- level2 == level3 && PM.getParentIgnoreParens(level2) == level1) {
- PieceI->setEndLocation(PieceNextI->getEndLocation());
- path.erase(NextI);
- hasChanges = true;
- continue;
- }
+ if (s1End && s1End == s2Start && level2) {
+ bool removeEdge = false;
+ // Remove edges into the increment or initialization of a
+ // loop that have no interleaving event. This means that
+ // they aren't interesting.
+ if (isIncrementOrInitInForLoop(s1End, level2))
+ removeEdge = true;
+ // Next only consider edges that are not anchored on
+ // the condition of a terminator. This are intermediate edges
+ // that we might want to trim.
+ else if (!isConditionForTerminator(level2, s1End)) {
+ // Trim edges on expressions that are consumed by
+ // the parent expression.
+ if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) {
+ removeEdge = true;
+ }
+ // Trim edges where a lexical containment doesn't exist.
+ // For example:
+ //
+ // X -> Y -> Z
+ //
+ // If 'Z' lexically contains Y (it is an ancestor) and
+ // 'X' does not lexically contain Y (it is a descendant OR
+ // it has no lexical relationship at all) then trim.
+ //
+ // This can eliminate edges where we dive into a subexpression
+ // and then pop back out, etc.
+ else if (s1Start && s2End &&
+ lexicalContains(PM, s2Start, s2End) &&
+ !lexicalContains(PM, s1End, s1Start)) {
+ removeEdge = true;
+ }
+ // Trim edges from a subexpression back to the top level if the
+ // subexpression is on a different line.
+ //
+ // A.1 -> A -> B
+ // becomes
+ // A.1 -> B
+ //
+ // These edges just look ugly and don't usually add anything.
+ else if (s1Start && s2End &&
+ lexicalContains(PM, s1Start, s1End)) {
+ SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
+ PieceI->getStartLocation().asLocation());
+ if (!getLengthOnSingleLine(SM, EdgeRange).hasValue())
+ removeEdge = true;
+ }
+ }
- // Rule III.
- //
- // Eliminate unnecessary edges where we descend to a subexpression from
- // a statement at the same level as our parent.
- //
- // NOTE: this will be limited later in cases where we add barriers
- // to prevent this optimization.
- //
- // For example:
- //
- // (1.1 -> 1.1.1) -> (1.1.1 -> X) becomes (1.1 -> X).
- //
- if (level1 && level2 && level1 == PM.getParentIgnoreParens(level2)) {
- PieceI->setEndLocation(PieceNextI->getEndLocation());
- path.erase(NextI);
- hasChanges = true;
- continue;
+ if (removeEdge) {
+ PieceI->setEndLocation(PieceNextI->getEndLocation());
+ path.erase(NextI);
+ hasChanges = true;
+ continue;
+ }
}
- // Rule IV.
+ // Optimize edges for ObjC fast-enumeration loops.
//
- // Eliminate unnecessary edges where we ascend from a subexpression to
- // a statement at the same level as our parent.
+ // (X -> collection) -> (collection -> element)
//
- // NOTE: this will be limited later in cases where we add barriers
- // to prevent this optimization.
- //
- // For example:
+ // becomes:
//
- // (X -> 1.1.1) -> (1.1.1 -> 1.1) becomes (X -> 1.1).
- // [first edge] (1.1.1 -> 1.1) -> eliminate
- //
- if (level2 && level4 && level2 == level3 && level4 == PM.getParent(level2)){
- PieceI->setEndLocation(PieceNextI->getEndLocation());
- path.erase(NextI);
- hasChanges = true;
- continue;
- }
-#if 0
- // Rule V.
- //
- // Replace terminator conditions with terminators when the condition
- // itself has no control-flow.
- //
- // For example:
- //
- // (X -> condition) -> (condition -> Y) becomes (X -> term) -> (term -> Y)
- // [first edge] (condition -> Y) becomes (term -> Y)
- //
- // This applies to 'if', 'for', 'while', 'do .. while', 'switch'...
- //
- if (!isBarrier(CFBS, PieceNextI) &&
- s1End && s1End == s2Start && level2) {
- if (isConditionForTerminator(level2, s1End)) {
- PathDiagnosticLocation NewLoc(level2, SM, LC);
- PieceI->setEndLocation(NewLoc);
- PieceNextI->setStartLocation(NewLoc);
- CFBS.insert(PieceI);
+ // (X -> element)
+ if (s1End == s2Start) {
+ const ObjCForCollectionStmt *FS =
+ dyn_cast_or_null<ObjCForCollectionStmt>(level3);
+ if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
+ s2End == FS->getElement()) {
+ PieceI->setEndLocation(PieceNextI->getEndLocation());
+ path.erase(NextI);
hasChanges = true;
continue;
}
-
}
-#endif
// No changes at this index? Move to the next one.
++I;
}
- // No changes.
+ if (!hasChanges) {
+ // Adjust edges into subexpressions to make them more uniform
+ // and aesthetically pleasing.
+ addContextEdges(path, SM, PM, LC);
+ // Remove "cyclical" edges that include one or more context edges.
+ removeContextCycles(path, SM, PM);
+ // Hoist edges originating from branch conditions to branches
+ // for simple branches.
+ simplifySimpleBranches(path);
+ // Remove any puny edges left over after primary optimization pass.
+ removePunyEdges(path, SM, PM);
+ // Remove identical events.
+ removeIdenticalEvents(path);
+ }
+
return hasChanges;
}
+/// Drop the very first edge in a path, which should be a function entry edge.
+///
+/// If the first edge is not a function entry edge (say, because the first
+/// statement had an invalid source location), this function does nothing.
+// FIXME: We should just generate invalid edges anyway and have the optimizer
+// deal with them.
+static void dropFunctionEntryEdge(PathPieces &Path,
+ LocationContextMap &LCM,
+ SourceManager &SM) {
+ const PathDiagnosticControlFlowPiece *FirstEdge =
+ dyn_cast<PathDiagnosticControlFlowPiece>(Path.front());
+ if (!FirstEdge)
+ return;
+
+ const Decl *D = LCM[&Path]->getDecl();
+ PathDiagnosticLocation EntryLoc = PathDiagnosticLocation::createBegin(D, SM);
+ if (FirstEdge->getStartLocation() != EntryLoc)
+ return;
+
+ Path.pop_front();
+}
+
+
//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
-BugType::~BugType() { }
+void BugType::anchor() { }
void BugType::FlushReports(BugReporter &BR) {}
@@ -2148,10 +2697,8 @@ void BugReport::pushInterestingSymbolsAndRegions() {
}
void BugReport::popInterestingSymbolsAndRegions() {
- delete interestingSymbols.back();
- interestingSymbols.pop_back();
- delete interestingRegions.back();
- interestingRegions.pop_back();
+ delete interestingSymbols.pop_back_val();
+ delete interestingRegions.pop_back_val();
}
const Stmt *BugReport::getStmt() const {
@@ -2238,7 +2785,7 @@ void BugReporter::FlushReports() {
SmallVector<const BugType*, 16> bugTypes;
for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
bugTypes.push_back(*I);
- for (SmallVector<const BugType*, 16>::iterator
+ for (SmallVectorImpl<const BugType *>::iterator
I = bugTypes.begin(), E = bugTypes.end(); I != E; ++I)
const_cast<BugType*>(*I)->FlushReports(*this);
@@ -2561,8 +3108,8 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
PathGenerationScheme ActiveScheme = PC.getGenerationScheme();
if (ActiveScheme == PathDiagnosticConsumer::Extensive) {
- AnalyzerOptions &options = getEngine().getAnalysisManager().options;
- if (options.getBooleanOption("path-diagnostics-alternate", false)) {
+ AnalyzerOptions &options = getAnalyzerOptions();
+ if (options.getBooleanOption("path-diagnostics-alternate", true)) {
ActiveScheme = PathDiagnosticConsumer::AlternateExtensive;
}
}
@@ -2654,24 +3201,35 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
// Finally, prune the diagnostic path of uninteresting stuff.
if (!PD.path.empty()) {
- // Remove messages that are basically the same.
- removeRedundantMsgs(PD.getMutablePieces());
-
- if (R->shouldPrunePath() &&
- getEngine().getAnalysisManager().options.shouldPrunePaths()) {
+ if (R->shouldPrunePath() && getAnalyzerOptions().shouldPrunePaths()) {
bool stillHasNotes = removeUnneededCalls(PD.getMutablePieces(), R, LCM);
assert(stillHasNotes);
(void)stillHasNotes;
}
+ // Redirect all call pieces to have valid locations.
adjustCallLocations(PD.getMutablePieces());
+ removePiecesWithInvalidLocations(PD.getMutablePieces());
if (ActiveScheme == PathDiagnosticConsumer::AlternateExtensive) {
- ControlFlowBarrierSet CFBS;
+ SourceManager &SM = getSourceManager();
+
+ // Reduce the number of edges from a very conservative set
+ // to an aesthetically pleasing subset that conveys the
+ // necessary information.
OptimizedCallsSet OCS;
- while (optimizeEdges(PD.getMutablePieces(), getSourceManager(), CFBS,
- OCS, LCM)) {}
+ while (optimizeEdges(PD.getMutablePieces(), SM, OCS, LCM)) {}
+
+ // Drop the very first function-entry edge. It's not really necessary
+ // for top-level functions.
+ dropFunctionEntryEdge(PD.getMutablePieces(), LCM, SM);
}
+
+ // Remove messages that are basically the same, and edges that may not
+ // make sense.
+ // We have to do this after edge optimization in the Extensive mode.
+ removeRedundantMsgs(PD.getMutablePieces());
+ removeEdgesToDefaultInitializers(PD.getMutablePieces());
}
// We found a report and didn't suppress it.
@@ -2689,6 +3247,25 @@ void BugReporter::Register(BugType *BT) {
}
void BugReporter::emitReport(BugReport* R) {
+ // Defensive checking: throw the bug away if it comes from a BodyFarm-
+ // generated body. We do this very early because report processing relies
+ // on the report's location being valid.
+ // FIXME: Valid bugs can occur in BodyFarm-generated bodies, so really we
+ // need to just find a reasonable location like we do later on with the path
+ // pieces.
+ if (const ExplodedNode *E = R->getErrorNode()) {
+ const LocationContext *LCtx = E->getLocationContext();
+ if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized())
+ return;
+ }
+
+ bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
+ assert(ValidSourceLoc);
+ // If we mess up in a release build, we'd still prefer to just drop the bug
+ // instead of trying to go on.
+ if (!ValidSourceLoc)
+ return;
+
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
@@ -2865,6 +3442,12 @@ void BugReporter::FlushReport(BugReport *exampleReport,
MaxValidBugClassSize = std::max(bugReports.size(),
static_cast<size_t>(MaxValidBugClassSize));
+ // 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.
+ AnalyzerOptions& Opts = getAnalyzerOptions();
+ if (Opts.shouldReportIssuesInMainSourceFile() && !Opts.AnalyzeAll)
+ D->resetDiagnosticLocationToMainFile();
+
// If the path is empty, generate a single step path with the location
// of the issue.
if (D->path.empty()) {
@@ -2892,13 +3475,15 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
StringRef name,
StringRef category,
StringRef str, PathDiagnosticLocation Loc,
- SourceRange* RBeg, unsigned NumRanges) {
+ ArrayRef<SourceRange> Ranges) {
// 'BT' is owned by BugReporter.
BugType *BT = getBugTypeForName(name, category);
BugReport *R = new BugReport(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
- for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
+ for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I)
+ R->addRange(*I);
emitReport(R);
}
@@ -2915,3 +3500,78 @@ BugType *BugReporter::getBugTypeForName(StringRef name,
}
return BT;
}
+
+
+void PathPieces::dump() const {
+ unsigned index = 0;
+ for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
+ llvm::errs() << "[" << index++ << "] ";
+ (*I)->dump();
+ llvm::errs() << "\n";
+ }
+}
+
+void PathDiagnosticCallPiece::dump() const {
+ llvm::errs() << "CALL\n--------------\n";
+
+ if (const Stmt *SLoc = getLocStmt(getLocation()))
+ SLoc->dump();
+ else if (const NamedDecl *ND = dyn_cast<NamedDecl>(getCallee()))
+ llvm::errs() << *ND << "\n";
+ else
+ getLocation().dump();
+}
+
+void PathDiagnosticEventPiece::dump() const {
+ llvm::errs() << "EVENT\n--------------\n";
+ llvm::errs() << getString() << "\n";
+ llvm::errs() << " ---- at ----\n";
+ getLocation().dump();
+}
+
+void PathDiagnosticControlFlowPiece::dump() const {
+ llvm::errs() << "CONTROL\n--------------\n";
+ getStartLocation().dump();
+ llvm::errs() << " ---- to ----\n";
+ getEndLocation().dump();
+}
+
+void PathDiagnosticMacroPiece::dump() const {
+ llvm::errs() << "MACRO\n--------------\n";
+ // FIXME: Print which macro is being invoked.
+}
+
+void PathDiagnosticLocation::dump() const {
+ if (!isValid()) {
+ llvm::errs() << "<INVALID>\n";
+ return;
+ }
+
+ switch (K) {
+ case RangeK:
+ // FIXME: actually print the range.
+ llvm::errs() << "<range>\n";
+ break;
+ case SingleLocK:
+ asLocation().dump();
+ llvm::errs() << "\n";
+ break;
+ case StmtK:
+ if (S)
+ S->dump();
+ else
+ llvm::errs() << "<NULL STMT>\n";
+ break;
+ case DeclK:
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
+ llvm::errs() << *ND << "\n";
+ else if (isa<BlockDecl>(D))
+ // FIXME: Make this nicer.
+ llvm::errs() << "<block>\n";
+ else if (D)
+ llvm::errs() << "<unknown decl>\n";
+ else
+ llvm::errs() << "<NULL DECL>\n";
+ break;
+ }
+}
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e078745737f9..e1a92b30c6be 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -532,7 +532,8 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// If we have an expression that provided the value, try to track where it
// came from.
if (InitE) {
- if (V.isUndef() || V.getAs<loc::ConcreteInt>()) {
+ if (V.isUndef() ||
+ V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
if (!IsParam)
InitE = InitE->IgnoreParenCasts();
bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam,
@@ -697,10 +698,13 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (P.getAs<CallEnter>() && InitE)
L = PathDiagnosticLocation(InitE, BRC.getSourceManager(),
P.getLocationContext());
- else
+
+ if (!L.isValid() || !L.asLocation().isValid())
L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
- if (!L.isValid())
+
+ if (!L.isValid() || !L.asLocation().isValid())
return NULL;
+
return new PathDiagnosticEventPiece(L, os.str());
}
@@ -993,12 +997,15 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
BugReporterVisitor *ConstraintTracker =
new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
report.addVisitor(ConstraintTracker);
+ }
- // Add visitor, which will suppress inline defensive checks.
- if (LVState->isNull(V).isConstrainedTrue() &&
- EnableNullFPSuppression) {
+ // Add visitor, which will suppress inline defensive checks.
+ if (Optional<DefinedSVal> DV = V.getAs<DefinedSVal>()) {
+ if (!DV->isZeroConstant() &&
+ LVState->isNull(*DV).isConstrainedTrue() &&
+ EnableNullFPSuppression) {
BugReporterVisitor *IDCSuppressor =
- new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
+ new SuppressInlineDefensiveChecksVisitor(*DV,
LVNode);
report.addVisitor(IDCSuppressor);
}
@@ -1350,7 +1357,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
// For non-assignment operations, we require that we can understand
// both the LHS and RHS.
- if (LhsString.empty() || RhsString.empty())
+ if (LhsString.empty() || RhsString.empty() ||
+ !BinaryOperator::isComparisonOp(Op))
return 0;
// Should we invert the strings if the LHS is not a variable name?
@@ -1462,9 +1470,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf);
- Out << "Assuming '";
- VD->getDeclName().printName(Out);
- Out << "' is ";
+ Out << "Assuming '" << VD->getDeclName() << "' is ";
QualType VDTy = VD->getType();
@@ -1516,18 +1522,59 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
BugReport &BR) {
// Here we suppress false positives coming from system headers. This list is
// based on known issues.
-
- // Skip reports within the 'std' namespace. Although these can sometimes be
- // the user's fault, we currently don't report them very well, and
- // Note that this will not help for any other data structure libraries, like
- // TR1, Boost, or llvm/ADT.
ExprEngine &Eng = BRC.getBugReporter().getEngine();
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldSuppressFromCXXStandardLibrary()) {
- const LocationContext *LCtx = N->getLocationContext();
- if (isInStdNamespace(LCtx->getDecl())) {
+ const Decl *D = N->getLocationContext()->getDecl();
+
+ if (isInStdNamespace(D)) {
+ // Skip reports within the 'std' namespace. Although these can sometimes be
+ // the user's fault, we currently don't report them very well, and
+ // Note that this will not help for any other data structure libraries, like
+ // TR1, Boost, or llvm/ADT.
+ if (Options.shouldSuppressFromCXXStandardLibrary()) {
BR.markInvalid(getTag(), 0);
return 0;
+
+ } else {
+ // If the the complete 'std' suppression is not enabled, suppress reports
+ // from the 'std' namespace that are known to produce false positives.
+
+ // 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.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ const CXXRecordDecl *CD = MD->getParent();
+ if (CD->getName() == "list") {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ }
+ }
+
+ // The analyzer issues a false positive on
+ // std::basic_string<uint8_t> v; v.push_back(1);
+ // and
+ // std::u16string s; s += u'a';
+ // because we cannot reason about the internal invariants of the
+ // datastructure.
+ const LocationContext *LCtx = N->getLocationContext();
+ do {
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
+ if (!MD)
+ break;
+
+ const CXXRecordDecl *CD = MD->getParent();
+ if (CD->getName() == "basic_string") {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ } else if (CD->getName().find("allocator") == StringRef::npos) {
+ // Only keep searching if the current method is in a class with the
+ // word "allocator" in its name, e.g. std::allocator or
+ // allocator_traits.
+ break;
+ }
+
+ LCtx = LCtx->getParent();
+ } while (LCtx);
}
}
@@ -1536,12 +1583,11 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
SourceManager &SM = BRC.getSourceManager();
FullSourceLoc Loc = BR.getLocation(SM).asLocation();
while (Loc.isMacroID()) {
- if (SM.isInSystemMacro(Loc) &&
- (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) {
+ Loc = Loc.getSpellingLoc();
+ if (SM.getFilename(Loc).endswith("sys/queue.h")) {
BR.markInvalid(getTag(), 0);
return 0;
}
- Loc = Loc.getSpellingLoc();
}
return 0;
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 91f15b31da63..013f8a56b433 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangStaticAnalyzerCore
CheckerHelpers.cpp
CheckerManager.cpp
CheckerRegistry.cpp
+ CommonBugCategories.cpp
ConstraintManager.cpp
CoreEngine.cpp
Environment.cpp
@@ -38,7 +39,6 @@ add_clang_library(clangStaticAnalyzerCore
Store.cpp
SubEngine.cpp
SymbolManager.cpp
- TextPathDiagnostics.cpp
)
add_dependencies(clangStaticAnalyzerCore
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index dfd20b8b332b..a3b34f4790a9 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -140,8 +140,8 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig) const {
ProgramStateRef Result = (Orig ? Orig : getState());
- SmallVector<SVal, 8> ConstValues;
SmallVector<SVal, 8> ValuesToInvalidate;
+ RegionAndSymbolInvalidationTraits ETraits;
getExtraInvalidatedValues(ValuesToInvalidate);
@@ -154,9 +154,12 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// Mark this region for invalidation. We batch invalidate regions
// below for efficiency.
if (PreserveArgs.count(Idx))
- ConstValues.push_back(getArgSVal(Idx));
- else
- ValuesToInvalidate.push_back(getArgSVal(Idx));
+ if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
+ ETraits.setTrait(MR->StripCasts(),
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+ // TODO: Factor this out + handle the lower level const pointers.
+
+ ValuesToInvalidate.push_back(getArgSVal(Idx));
}
// Invalidate designated regions using the batch invalidation API.
@@ -165,7 +168,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
BlockCount, getLocationContext(),
/*CausedByPointerEscape*/ true,
- /*Symbols=*/0, this, ConstValues);
+ /*Symbols=*/0, this, &ETraits);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
@@ -245,15 +248,36 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
// Blocks are difficult because the return type may not be stored in the
// BlockDecl itself. The AST should probably be enhanced, but for now we
// just do what we can.
- QualType Ty = BD->getSignatureAsWritten()->getType();
- if (const FunctionType *FT = Ty->getAs<FunctionType>())
- if (!FT->getResultType()->isDependentType())
- return FT->getResultType();
+ // If the block is declared without an explicit argument list, the
+ // signature-as-written just includes the return type, not the entire
+ // function type.
+ // FIXME: All blocks should have signatures-as-written, even if the return
+ // type is inferred. (That's signified with a dependent result type.)
+ if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) {
+ QualType Ty = TSI->getType();
+ if (const FunctionType *FT = Ty->getAs<FunctionType>())
+ Ty = FT->getResultType();
+ if (!Ty->isDependentType())
+ return Ty;
+ }
return QualType();
}
- return QualType();
+ llvm_unreachable("unknown callable kind");
+}
+
+bool CallEvent::isVariadic(const Decl *D) {
+ assert(D);
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->isVariadic();
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->isVariadic();
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ return BD->isVariadic();
+
+ llvm_unreachable("unknown callable kind");
}
static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
@@ -264,8 +288,11 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
CallEvent::param_iterator E) {
MemRegionManager &MRMgr = SVB.getRegionManager();
+ // If the function has fewer parameters than the call has arguments, we simply
+ // do not bind any values to them.
+ unsigned NumArgs = Call.getNumArgs();
unsigned Idx = 0;
- for (; I != E; ++I, ++Idx) {
+ for (; I != E && Idx < NumArgs; ++I, ++Idx) {
const ParmVarDecl *ParamDecl = *I;
assert(ParamDecl && "Formal parameter has no decl?");
@@ -674,8 +701,12 @@ const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const {
ObjCMessageKind ObjCMethodCall::getMessageKind() const {
if (Data == 0) {
+
+ // Find the parent, ignoring implicit casts.
ParentMap &PM = getLocationContext()->getParentMap();
- const Stmt *S = PM.getParent(getOriginExpr());
+ const Stmt *S = PM.getParentIgnoreParenCasts(getOriginExpr());
+
+ // Check if parent is a PseudoObjectExpr.
if (const PseudoObjectExpr *POE = dyn_cast_or_null<PseudoObjectExpr>(S)) {
const Expr *Syntactic = POE->getSyntacticForm();
@@ -730,7 +761,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
// TODO: It could actually be subclassed if the subclass is private as well.
// This is probably very rare.
SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
- if (InterfLoc.isValid() && SM.isFromMainFile(InterfLoc))
+ if (InterfLoc.isValid() && SM.isInMainFile(InterfLoc))
return false;
// Assume that property accessors are not overridden.
@@ -752,7 +783,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
return false;
// If outside the main file,
- if (D->getLocation().isValid() && !SM.isFromMainFile(D->getLocation()))
+ if (D->getLocation().isValid() && !SM.isInMainFile(D->getLocation()))
return true;
if (D->isOverriding()) {
@@ -946,6 +977,8 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
const Stmt *Trigger;
if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>())
Trigger = AutoDtor->getTriggerStmt();
+ else if (Optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>())
+ Trigger = cast<Stmt>(DeleteDtor->getDeleteExpr());
else
Trigger = Dtor->getBody();
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 74eeef1c67a8..6b22bf411c29 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -68,7 +68,7 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
// If this function is not externally visible, it is not a C library function.
// Note that we make an exception for inline functions, which may be
// declared in header files without external linkage.
- if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage)
+ if (!FD->isInlined() && !FD->isExternallyVisible())
return false;
if (Name.empty())
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 8adf3262b379..c1ae7e9d812c 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -169,7 +169,7 @@ void CheckerManager::runCheckersForStmt(bool isPreVisit,
const Stmt *S,
ExprEngine &Eng,
bool WasInlined) {
- CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
+ CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),
S, Eng, WasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -487,10 +487,10 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
/// \brief Run checkers to process symbol escape event.
ProgramStateRef
CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- bool IsConst) {
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ RegionAndSymbolInvalidationTraits *ETraits) {
assert((Call != NULL ||
(Kind != PSK_DirectEscapeOnCall &&
Kind != PSK_IndirectEscapeOnCall)) &&
@@ -500,7 +500,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
// way), bail out.
if (!State)
return NULL;
- State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, IsConst);
+ State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits);
}
return State;
}
@@ -688,27 +688,23 @@ void CheckerManager::_registerForEndOfTranslationUnit(
// Implementation details.
//===----------------------------------------------------------------------===//
-CheckerManager::CachedStmtCheckers *
+const CheckerManager::CachedStmtCheckers &
CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
assert(S);
- CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
- CachedStmtCheckers *checkers = 0;
- CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
- if (CCI != CachedStmtCheckersMap.end()) {
- checkers = &(CCI->second);
- } else {
- // Find the checkers that should run for this Stmt and cache them.
- checkers = &CachedStmtCheckersMap[key];
- for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
- StmtCheckerInfo &info = StmtCheckers[i];
- if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
- checkers->push_back(info.CheckFn);
- }
+ unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
+ CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key);
+ if (CCI != CachedStmtCheckersMap.end())
+ return CCI->second;
+
+ // Find the checkers that should run for this Stmt and cache them.
+ CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key];
+ for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
+ StmtCheckerInfo &Info = StmtCheckers[i];
+ if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))
+ Checkers.push_back(Info.CheckFn);
}
-
- assert(checkers);
- return checkers;
+ return Checkers;
}
CheckerManager::~CheckerManager() {
diff --git a/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
index e2a8ea616611..3cb9323563b3 100644
--- a/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp
+++ b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
@@ -7,12 +7,14 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
+
// Common strings used for the "category" of many static analyzer issues.
namespace clang { namespace ento { namespace categories {
-const char *CoreFoundationObjectiveC = "Core Foundation/Objective-C";
-const char *MemoryCoreFoundationObjectiveC =
+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 *UnixAPI = "Unix API";
+const char * const UnixAPI = "Unix API";
}}}
-
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index af9518acc79d..e9c4a35de6e8 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -357,8 +357,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// Process the first worklist until it is empty.
while (!WL1.empty()) {
- const ExplodedNode *N = WL1.back();
- WL1.pop_back();
+ const ExplodedNode *N = WL1.pop_back_val();
// Have we already visited this node? If so, continue to the next one.
if (Pass1.count(N))
@@ -388,8 +387,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
- const ExplodedNode *N = WL2.back();
- WL2.pop_back();
+ const ExplodedNode *N = WL2.pop_back_val();
// Skip this node if we have already processed it.
if (Pass2.find(N) != Pass2.end())
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index bfe4e15a7156..9907d0cbf9b8 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -16,6 +16,7 @@
#define DEBUG_TYPE "ExprEngine"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
@@ -208,7 +209,18 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
// Create a temporary object region for the inner expression (which may have
// a more derived type) and bind the value into it.
- const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
+ const TypedValueRegion *TR = NULL;
+ if (const MaterializeTemporaryExpr *MT =
+ dyn_cast<MaterializeTemporaryExpr>(Result)) {
+ StorageDuration SD = MT->getStorageDuration();
+ // If this object is bound to a reference with static storage duration, we
+ // put it in a different region to prevent "address leakage" warnings.
+ if (SD == SD_Static || SD == SD_Thread)
+ TR = MRMgr.getCXXStaticTempObjectRegion(Inner);
+ }
+ if (!TR)
+ TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
+
SVal Reg = loc::MemRegionVal(TR);
if (V.isUnknown())
@@ -263,6 +275,7 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) {
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
currStmtIdx = StmtIdx;
currBldrCtx = Ctx;
@@ -274,13 +287,13 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
+ case CFGElement::DeleteDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
}
- currBldrCtx = 0;
}
static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
@@ -523,6 +536,9 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
case CFGElement::TemporaryDtor:
ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst);
break;
+ case CFGElement::DeleteDtor:
+ ProcessDeleteDtor(D.castAs<CFGDeleteDtor>(), Pred, Dst);
+ break;
default:
llvm_unreachable("Unexpected dtor kind.");
}
@@ -550,6 +566,35 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
Pred, Dst);
}
+void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const CXXDeleteExpr *DE = Dtor.getDeleteExpr();
+ const Stmt *Arg = DE->getArgument();
+ SVal ArgVal = State->getSVal(Arg, LCtx);
+
+ // If the argument to delete is known to be a null value,
+ // don't run destructor.
+ if (State->isNull(ArgVal).isConstrainedTrue()) {
+ QualType DTy = DE->getDestroyedType();
+ QualType BTy = getContext().getBaseElementType(DTy);
+ const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
+ const CXXDestructorDecl *Dtor = RD->getDestructor();
+
+ PostImplicitCall PP(Dtor, DE->getLocStart(), LCtx);
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateNode(PP, Pred->getState(), Pred);
+ return;
+ }
+
+ VisitCXXDestructor(DE->getDestroyedType(),
+ ArgVal.getAsRegion(),
+ DE, /*IsBase=*/ false,
+ Pred, Dst);
+}
+
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext();
@@ -589,7 +634,15 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {}
+ ExplodedNodeSet &Dst) {
+
+ QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType();
+
+ // FIXME: Inlining of temporary destructors is not supported yet anyway, so we
+ // just put a NULL region for now. This will need to be changed later.
+ VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(),
+ /*IsBase=*/ false, Pred, Dst);
+}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet &DstTop) {
@@ -604,9 +657,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
- case Stmt::CXXDefaultInitExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
@@ -651,13 +702,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::IfStmtClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::LabelStmtClass:
- case Stmt::AttributedStmtClass:
case Stmt::NoStmtClass:
case Stmt::NullStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
case Expr::MSDependentExistsStmtClass:
case Stmt::CapturedStmtClass:
+ case Stmt::OMPParallelDirectiveClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -698,6 +749,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
+ case Stmt::ConvertVectorExprClass:
case Stmt::VAArgExprClass:
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
@@ -708,6 +760,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
case Stmt::AddrLabelExprClass:
+ case Stmt::AttributedStmtClass:
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::ImplicitValueInitExprClass:
@@ -719,6 +772,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass: {
Bldr.takeNodes(Pred);
@@ -729,7 +783,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
- case Stmt::CXXDefaultArgExprClass: {
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDefaultInitExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet PreVisit;
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
@@ -737,9 +792,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
- const LocationContext *LCtx = Pred->getLocationContext();
- const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
- const Expr *ArgE = DefaultE->getExpr();
+ const Expr *ArgE;
+ if (const CXXDefaultArgExpr *DefE = dyn_cast<CXXDefaultArgExpr>(S))
+ ArgE = DefE->getExpr();
+ else if (const CXXDefaultInitExpr *DefE = dyn_cast<CXXDefaultInitExpr>(S))
+ ArgE = DefE->getExpr();
+ else
+ llvm_unreachable("unknown constant wrapper kind");
bool IsTemporary = false;
if (const MaterializeTemporaryExpr *MTE =
@@ -752,13 +811,15 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
if (!ConstantVal)
ConstantVal = UnknownVal();
+ const LocationContext *LCtx = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
I != E; ++I) {
ProgramStateRef State = (*I)->getState();
- State = State->BindExpr(DefaultE, LCtx, *ConstantVal);
+ State = State->BindExpr(S, LCtx, *ConstantVal);
if (IsTemporary)
- State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
- DefaultE);
+ State = createTemporaryRegionIfNeeded(State, LCtx,
+ cast<Expr>(S),
+ cast<Expr>(S));
Bldr2.generateNode(S, *I, State);
}
@@ -767,10 +828,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
+ // Cases we evaluate as opaque expressions, conjuring a symbol.
+ case Stmt::CXXStdInitializerListExprClass:
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
- // FIXME: explicitly model with a region and the actual contents
- // of the container. For now, conjure a symbol.
case Expr::ObjCBoxedExprClass: {
Bldr.takeNodes(Pred);
@@ -1188,7 +1249,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) {
-
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+
// FIXME: Refactor this into a checker.
if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
@@ -1312,6 +1374,8 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ PrettyStackTraceLocationContext StackCrashInfo(LCtx);
currBldrCtx = &BldCtx;
// Check for NULL conditions; e.g. "for(;;)"
@@ -1323,7 +1387,6 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
}
- // Resolve the condition in the precense of nested '||' and '&&'.
if (const Expr *Ex = dyn_cast<Expr>(Condition))
Condition = Ex->IgnoreParens();
@@ -1412,6 +1475,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS,
clang::ento::ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
currBldrCtx = &BuilderCtx;
const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
@@ -1477,6 +1541,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
/// nodes when the control reaches the end of a function.
void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred) {
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
StateMgr.EndPath(Pred->getState());
ExplodedNodeSet Dst;
@@ -1613,7 +1678,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
const LocationContext *LCtx = Pred->getLocationContext();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- assert(Ex->isGLValue());
+ // C permits "extern void v", and if you cast the address to a valid type,
+ // you can even do things with it. We simply pretend
+ assert(Ex->isGLValue() || VD->getType()->isVoidType());
SVal V = state->getLValue(VD, Pred->getLocationContext());
// For references, the 'lvalue' is the pointer address stored in the
@@ -1722,7 +1789,24 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
FieldDecl *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
- if (M->isGLValue()) {
+
+ if (M->isGLValue() || M->getType()->isArrayType()) {
+
+ // We special case rvalue of array type because the analyzer cannot reason
+ // about it, since we expect all regions to be wrapped in Locs. So we will
+ // treat these as lvalues assuming that they will decay to pointers as soon
+ // as they are used.
+ if (!M->isGLValue()) {
+ assert(M->getType()->isArrayType());
+ const ImplicitCastExpr *PE =
+ dyn_cast<ImplicitCastExpr>(Pred->getParentMap().getParent(M));
+ if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
+ assert(false &&
+ "We assume that array is always wrapped in ArrayToPointerDecay");
+ L = UnknownVal();
+ }
+ }
+
if (field->getType()->isReferenceType()) {
if (const MemRegion *R = L.getAsRegion())
L = state->getSVal(R);
@@ -1793,7 +1877,8 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
State = getCheckerManager().runCheckersForPointerEscape(State,
EscapedSymbols,
/*CallEvent*/ 0,
- PSK_EscapeOnBind);
+ PSK_EscapeOnBind,
+ 0);
return State;
}
@@ -1804,7 +1889,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call,
- bool IsConst) {
+ RegionAndSymbolInvalidationTraits &ITraits) {
if (!Invalidated || Invalidated->empty())
return State;
@@ -1814,17 +1899,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
*Invalidated,
0,
PSK_EscapeOther,
- IsConst);
-
- // Note: Due to current limitations of RegionStore, we only process the top
- // level const pointers correctly. The lower level const pointers are
- // currently treated as non-const.
- if (IsConst)
- return getCheckerManager().runCheckersForPointerEscape(State,
- *Invalidated,
- Call,
- PSK_DirectEscapeOnCall,
- true);
+ &ITraits);
// If the symbols were invalidated by a call, we want to find out which ones
// were invalidated directly due to being arguments to the call.
@@ -1846,12 +1921,12 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
if (!SymbolsDirectlyInvalidated.empty())
State = getCheckerManager().runCheckersForPointerEscape(State,
- SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall);
+ SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall, &ITraits);
// Notify about the symbols that get indirectly invalidated by the call.
if (!SymbolsIndirectlyInvalidated.empty())
State = getCheckerManager().runCheckersForPointerEscape(State,
- SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall);
+ SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall, &ITraits);
return State;
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 67aeab60033f..983fda00a2ff 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -184,7 +184,8 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
// Get the value of the block itself.
SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
- Pred->getLocationContext());
+ Pred->getLocationContext(),
+ currBldrCtx->blockCount());
ProgramStateRef State = Pred->getState();
@@ -309,7 +310,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
- case CK_ZeroToOCLEvent: {
+ case CK_ZeroToOCLEvent:
+ case CK_LValueBitCast: {
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
@@ -370,7 +372,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
}
case CK_NullToMemberPointer: {
// FIXME: For now, member pointers are represented by void *.
- SVal V = svalBuilder.makeIntValWithPtrWidth(0, true);
+ SVal V = svalBuilder.makeNull();
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
@@ -381,8 +383,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_ReinterpretMemberPointer:
- case CK_VectorSplat:
- case CK_LValueBitCast: {
+ case CK_VectorSplat: {
// Recover some path-sensitivty by conjuring a new value.
QualType resultType = CastE->getType();
if (CastE->isGLValue())
@@ -446,7 +447,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
- StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
+ ExplodedNodeSet dstEvaluated;
+ StmtNodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
@@ -499,6 +501,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
B.generateNode(DS, N, state);
}
}
+
+ getCheckerManager().runCheckersForPostStmt(Dst, B.getResults(), DS, *this);
}
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
@@ -579,9 +583,10 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
const LocationContext *LCtx = Pred->getLocationContext();
QualType T = getContext().getCanonicalType(IE->getType());
unsigned NumInitElements = IE->getNumInits();
-
- if (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
- T->isAnyComplexType()) {
+
+ if (!IE->isGLValue() &&
+ (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
+ T->isAnyComplexType())) {
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -595,8 +600,6 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) {
SVal V = state->getSVal(cast<Expr>(*it), LCtx);
- if (dyn_cast_or_null<CXXTempObjectRegion>(V.getAsRegion()))
- V = UnknownVal();
vals = getBasicVals().consVals(V, vals);
}
@@ -606,7 +609,9 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
return;
}
- // Handle scalars: int{5} and int{}.
+ // Handle scalars: int{5} and int{} and GLvalues.
+ // Note, if the InitListExpr is a GLvalue, it means that there is an address
+ // representing it, so it must have a single init element.
assert(NumInitElements <= 1);
SVal V;
@@ -735,15 +740,23 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- switch (U->getOpcode()) {
+ // FIXME: Prechecks eventually go in ::Visit().
+ ExplodedNodeSet CheckedSet;
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, U, *this);
+
+ ExplodedNodeSet EvalSet;
+ StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
+
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
+ switch (U->getOpcode()) {
default: {
- Bldr.takeNodes(Pred);
+ Bldr.takeNodes(*I);
ExplodedNodeSet Tmp;
- VisitIncrementDecrementOperator(U, Pred, Tmp);
+ VisitIncrementDecrementOperator(U, *I, Tmp);
Bldr.addNodes(Tmp);
- }
break;
+ }
case UO_Real: {
const Expr *Ex = U->getSubExpr()->IgnoreParens();
@@ -755,10 +768,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// For all other types, UO_Real is an identity operation.
assert (U->getType() == Ex->getType());
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx,
- state->getSVal(Ex, LCtx)));
+ ProgramStateRef state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
break;
}
@@ -770,10 +783,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
break;
}
// For all other types, UO_Imag returns 0.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
SVal X = svalBuilder.makeZeroVal(Ex->getType());
- Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx, X));
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X));
break;
}
@@ -791,10 +804,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// generate an extra node that just propagates the value of the
// subexpression.
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx,
- state->getSVal(Ex, LCtx)));
+ ProgramStateRef state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
break;
}
@@ -803,14 +816,14 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
case UO_Not: {
assert (!U->isGLValue());
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
// Get the value of the subexpression.
SVal V = state->getSVal(Ex, LCtx);
if (V.isUnknownOrUndef()) {
- Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx, V));
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V));
break;
}
@@ -847,11 +860,13 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
state = state->BindExpr(U, LCtx, Result);
break;
}
- Bldr.generateNode(U, Pred, state);
+ Bldr.generateNode(U, *I, state);
break;
}
+ }
}
+ getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, U, *this);
}
void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index ed90dc589181..eba4f94d80e6 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -30,21 +30,7 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
- SVal V = state->getSVal(tempExpr, LCtx);
-
- // If the value is already a CXXTempObjectRegion, it is fine as it is.
- // Otherwise, create a new CXXTempObjectRegion, and copy the value into it.
- // This is an optimization for when an rvalue is constructed and then
- // immediately materialized.
- const MemRegion *MR = V.getAsRegion();
- if (const CXXTempObjectRegion *TR =
- dyn_cast_or_null<CXXTempObjectRegion>(MR)) {
- if (getContext().hasSameUnqualifiedType(TR->getValueType(), ME->getType()))
- state = state->BindExpr(ME, LCtx, V);
- }
-
- if (state == Pred->getState())
- state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
+ state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
Bldr.generateNode(ME, Pred, state);
}
@@ -105,6 +91,12 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
/// If the type is not an array type at all, the original value is returned.
static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
QualType &Ty) {
+ // FIXME: This check is just a temporary workaround, because
+ // ProcessTemporaryDtor sends us NULL regions. It will not be necessary once
+ // we can properly process temporary destructors.
+ if (!LValue.getAsRegion())
+ return LValue;
+
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();
@@ -176,6 +168,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
}
// FIXME: This will eventually need to handle new-expressions as well.
+ // Don't forget to update the pre-constructor initialization code below.
}
// If we couldn't find an existing region to construct into, assume we're
@@ -187,8 +180,26 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
break;
}
- case CXXConstructExpr::CK_NonVirtualBase:
case CXXConstructExpr::CK_VirtualBase:
+ // Make sure we are not calling virtual base class initializers twice.
+ // Only the most-derived object should initialize virtual base classes.
+ if (const Stmt *Outer = LCtx->getCurrentStackFrame()->getCallSite()) {
+ const CXXConstructExpr *OuterCtor = dyn_cast<CXXConstructExpr>(Outer);
+ if (OuterCtor) {
+ switch (OuterCtor->getConstructionKind()) {
+ case CXXConstructExpr::CK_NonVirtualBase:
+ case CXXConstructExpr::CK_VirtualBase:
+ // Bail out!
+ destNodes.Add(Pred);
+ return;
+ case CXXConstructExpr::CK_Complete:
+ case CXXConstructExpr::CK_Delegating:
+ break;
+ }
+ }
+ }
+ // FALLTHROUGH
+ case CXXConstructExpr::CK_NonVirtualBase:
case CXXConstructExpr::CK_Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
@@ -215,8 +226,38 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
+
+ ExplodedNodeSet PreInitialized;
+ {
+ StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
+ if (CE->requiresZeroInitialization()) {
+ // Type of the zero doesn't matter.
+ SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy);
+
+ for (ExplodedNodeSet::iterator I = DstPreVisit.begin(),
+ E = DstPreVisit.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+ // FIXME: Once we properly handle constructors in new-expressions, we'll
+ // need to invalidate the region before setting a default value, to make
+ // sure there aren't any lingering bindings around. This probably needs
+ // to happen regardless of whether or not the object is zero-initialized
+ // to handle random fields of a placement-initialized object picking up
+ // old bindings. We might only want to do it when we need to, though.
+ // FIXME: This isn't actually correct for arrays -- we need to zero-
+ // initialize the entire array, not just the first element -- but our
+ // handling of arrays everywhere else is weak as well, so this shouldn't
+ // actually make things worse. Placement new makes this tricky as well,
+ // since it's then possible to be initializing one part of a multi-
+ // dimensional array.
+ State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
+ Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind);
+ }
+ }
+ }
+
ExplodedNodeSet DstPreCall;
- getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
+ getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
*Call, *this);
ExplodedNodeSet DstEvaluated;
@@ -255,7 +296,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
// invalidate the entire array).
- SVal DestVal = loc::MemRegionVal(Dest);
+ SVal DestVal = UnknownVal();
+ if (Dest)
+ DestVal = loc::MemRegionVal(Dest);
DestVal = makeZeroElementRegion(State, DestVal, ObjectType);
Dest = DestVal.getAsRegion();
@@ -332,11 +375,14 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (!State)
return;
- // If we're compiling with exceptions enabled, and this allocation function
- // is not declared as non-throwing, failures /must/ be signalled by
- // exceptions, and thus the return value will never be NULL.
+ // If this allocation function is not declared as non-throwing, failures
+ // /must/ be signalled by exceptions, and thus the return value will never be
+ // NULL. -fno-exceptions does not influence this semantics.
+ // FIXME: GCC has a -fcheck-new option, which forces it to consider the case
+ // where new can return NULL. If we end up supporting that option, we can
+ // consider adding a check for it here.
// C++11 [basic.stc.dynamic.allocation]p3.
- if (FD && getContext().getLangOpts().CXXExceptions) {
+ if (FD) {
QualType Ty = FD->getType();
if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>())
if (!ProtoType->isNothrow(getContext()))
@@ -382,8 +428,6 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (!isa<CXXConstructExpr>(Init)) {
assert(Bldr.getResults().size() == 1);
Bldr.takeNodes(NewN);
-
- assert(!CNE->getType()->getPointeeCXXRecordDecl());
evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx),
/*FirstInit=*/IsStandardGlobalOpNewFunction);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 06570a4b4a90..06328e4ffce9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -14,6 +14,7 @@
#define DEBUG_TYPE "ExprEngine"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ParentMap.h"
@@ -39,6 +40,8 @@ STATISTIC(NumReachedInlineCountMax,
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
+ PrettyStackTraceLocationContext CrashInfo(calleeCtx);
+
const CFG *CalleeCFG = calleeCtx->getCFG();
const CFGBlock *Entry = &(CalleeCFG->getEntry());
@@ -214,7 +217,7 @@ static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) {
/// 5. PostStmt<CallExpr>
void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// Step 1 CEBNode was generated before the call.
-
+ PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
const StackFrameContext *calleeCtx =
CEBNode->getLocationContext()->getCurrentStackFrame();
@@ -717,15 +720,30 @@ static bool isContainerCtorOrDtor(const ASTContext &Ctx,
return isContainerClass(Ctx, RD);
}
+/// Returns true if the given function is the destructor of a class named
+/// "shared_ptr".
+static bool isCXXSharedPtrDtor(const FunctionDecl *FD) {
+ const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(FD);
+ if (!Dtor)
+ return false;
+
+ const CXXRecordDecl *RD = Dtor->getParent();
+ if (const IdentifierInfo *II = RD->getDeclName().getAsIdentifierInfo())
+ if (II->isStr("shared_ptr"))
+ return true;
+
+ return false;
+}
+
/// Returns true if the function in \p CalleeADC may be inlined in general.
///
/// This checks static properties of the function, such as its signature and
/// CFG, to determine whether the analyzer should ever consider inlining it,
/// in any context.
-static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC,
+static bool mayInlineDecl(AnalysisDeclContext *CalleeADC,
AnalyzerOptions &Opts) {
// FIXME: Do not inline variadic calls.
- if (Call.isVariadic())
+ if (CallEvent::isVariadic(CalleeADC->getDecl()))
return false;
// Check certain C++-related inlining policies.
@@ -746,9 +764,18 @@ static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC,
// Conditionally control the inlining of methods on objects that look
// like C++ containers.
if (!Opts.mayInlineCXXContainerCtorsAndDtors())
- if (!Ctx.getSourceManager().isFromMainFile(FD->getLocation()))
+ if (!Ctx.getSourceManager().isInMainFile(FD->getLocation()))
if (isContainerCtorOrDtor(Ctx, FD))
return false;
+
+ // Conditionally control the inlining of the destructor of C++ shared_ptr.
+ // We don't currently do a good job modeling shared_ptr because we can't
+ // see the reference count, so treating as opaque is probably the best
+ // idea.
+ if (!Opts.mayInlineCXXSharedPtrDtor())
+ if (isCXXSharedPtrDtor(FD))
+ return false;
+
}
}
@@ -780,6 +807,14 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
+ // Temporary object destructor processing is currently broken, so we never
+ // inline them.
+ // FIXME: Remove this once temp destructors are working.
+ if (isa<CXXDestructorCall>(Call)) {
+ if ((*currBldrCtx->getBlock())[currStmtIdx].getAs<CFGTemporaryDtor>())
+ return false;
+ }
+
// The auto-synthesized bodies are essential to inline as they are
// usually small and commonly used. Note: we should do this check early on to
// ensure we always inline these calls.
@@ -798,7 +833,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
} else {
// We haven't actually checked the static properties of this function yet.
// Do that now, and record our decision in the function summaries.
- if (mayInlineDecl(Call, CalleeADC, Opts)) {
+ if (mayInlineDecl(CalleeADC, Opts)) {
Engine.FunctionSummaries->markMayInline(D);
} else {
Engine.FunctionSummaries->markShouldNotInline(D);
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 73426da2b4df..365f6ab70de7 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -36,7 +36,7 @@ using namespace ento;
namespace {
class HTMLDiagnostics : public PathDiagnosticConsumer {
- llvm::sys::Path Directory, FilePrefix;
+ std::string Directory;
bool createdDir, noDir;
const Preprocessor &PP;
public:
@@ -70,10 +70,7 @@ public:
HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
const Preprocessor &pp)
- : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
- PP(pp) {
- // All html files begin with "report"
- FilePrefix.appendComponent("report");
+ : Directory(prefix), createdDir(false), noDir(false), PP(pp) {
}
void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
@@ -102,15 +99,11 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
- std::string ErrorMsg;
- Directory.createDirectoryOnDisk(true, &ErrorMsg);
-
- bool IsDirectory;
- if (llvm::sys::fs::is_directory(Directory.str(), IsDirectory) ||
- !IsDirectory) {
+ bool existed;
+ if (llvm::error_code ec =
+ llvm::sys::fs::create_directories(Directory, existed)) {
llvm::errs() << "warning: could not create directory '"
- << Directory.str() << "'\n"
- << "reason: " << ErrorMsg << '\n';
+ << Directory << "': " << ec.message() << '\n';
noDir = true;
@@ -165,11 +158,11 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// working directory if we have no directory information. This is
// a work in progress.
- std::string DirName = "";
+ llvm::SmallString<0> DirName;
if (llvm::sys::path::is_relative(Entry->getName())) {
- llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
- DirName = P.str() + "/";
+ llvm::sys::fs::current_path(DirName);
+ DirName += '/';
}
// Add the name of the file as an <h1> tag.
@@ -228,6 +221,10 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< path.back()->getLocation().asLocation().getExpansionLineNumber()
<< " -->\n";
+ os << "\n<!-- BUGCOLUMN "
+ << path.back()->getLocation().asLocation().getExpansionColumnNumber()
+ << " -->\n";
+
os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
// Mark the end of the tags.
@@ -250,26 +247,22 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
}
// Create a path for the target HTML file.
- llvm::sys::Path F(FilePrefix);
- F.makeUnique(false, NULL);
-
- // Rename the file with an HTML extension.
- llvm::sys::Path H(F);
- H.appendSuffix("html");
- F.renamePathOnDisk(H, NULL);
-
- std::string ErrorMsg;
- llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
-
- if (!ErrorMsg.empty()) {
- llvm::errs() << "warning: could not create file '" << F.str()
- << "'\n";
+ int FD;
+ SmallString<128> Model, ResultPath;
+ llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
+
+ if (llvm::error_code EC =
+ llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) {
+ llvm::errs() << "warning: could not create file in '" << Directory
+ << "': " << EC.message() << '\n';
return;
}
- if (filesMade) {
- filesMade->addDiagnostic(D, getName(), llvm::sys::path::filename(H.str()));
- }
+ llvm::raw_fd_ostream os(FD, true);
+
+ if (filesMade)
+ filesMade->addDiagnostic(D, getName(),
+ llvm::sys::path::filename(ResultPath));
// Emit the HTML to disk.
for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 42073d4841f7..162cd3326495 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -186,7 +186,7 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const
if (isa<VariableArrayType>(T))
return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this));
- if (isa<IncompleteArrayType>(T))
+ if (T->isIncompleteType())
return UnknownVal();
CharUnits size = Ctx.getTypeSizeInChars(T);
@@ -383,15 +383,17 @@ void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockTextRegion *BC,
const LocationContext *LC,
+ unsigned BlkCount,
const MemRegion *sReg) {
ID.AddInteger(MemRegion::BlockDataRegionKind);
ID.AddPointer(BC);
ID.AddPointer(LC);
+ ID.AddInteger(BlkCount);
ID.AddPointer(sReg);
}
void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion());
+ BlockDataRegion::ProfileRegion(ID, BC, LC, BlockCount, getSuperRegion());
}
void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
@@ -464,7 +466,14 @@ void BlockTextRegion::dumpToStream(raw_ostream &os) const {
}
void BlockDataRegion::dumpToStream(raw_ostream &os) const {
- os << "block_data{" << BC << '}';
+ os << "block_data{" << BC;
+ os << "; ";
+ for (BlockDataRegion::referenced_vars_iterator
+ I = referenced_vars_begin(),
+ E = referenced_vars_end(); I != E; ++I)
+ os << "(" << I.getCapturedRegion() << "," <<
+ I.getOriginalRegion() << ") ";
+ os << '}';
}
void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
@@ -806,10 +815,19 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
getFunctionTextRegion(cast<NamedDecl>(STCD)));
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
+ // FIXME: The fallback type here is totally bogus -- though it should
+ // never be queried, it will prevent uniquing with the real
+ // BlockTextRegion. Ideally we'd fix the AST so that we always had a
+ // signature.
+ QualType T;
+ if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
+ T = TSI->getType();
+ else
+ T = getContext().getFunctionNoProtoType(getContext().VoidTy);
+
const BlockTextRegion *BTR =
- getBlockTextRegion(BD,
- C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
- STC->getAnalysisDeclContext());
+ getBlockTextRegion(BD, C.getCanonicalType(T),
+ STC->getAnalysisDeclContext());
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
BTR);
}
@@ -830,7 +848,8 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
const BlockDataRegion *
MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
- const LocationContext *LC) {
+ const LocationContext *LC,
+ unsigned blockCount) {
const MemRegion *sReg = 0;
const BlockDecl *BD = BC->getDecl();
if (!BD->hasCaptures()) {
@@ -852,7 +871,13 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
}
}
- return getSubRegion<BlockDataRegion>(BC, LC, sReg);
+ return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
+}
+
+const CXXTempObjectRegion *
+MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
+ return getSubRegion<CXXTempObjectRegion>(
+ Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, NULL));
}
const CompoundLiteralRegion*
@@ -966,7 +991,7 @@ MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
bool IsVirtual) {
if (isa<TypedValueRegion>(Super)) {
assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
- (void)isValidBaseClass;
+ (void)&isValidBaseClass;
if (IsVirtual) {
// Virtual base regions should not be layered, since the layout rules
@@ -1435,3 +1460,45 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
}
return 0;
}
+
+//===----------------------------------------------------------------------===//
+// RegionAndSymbolInvalidationTraits
+//===----------------------------------------------------------------------===//
+
+void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
+ InvalidationKinds IK) {
+ SymTraitsMap[Sym] |= IK;
+}
+
+void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
+ InvalidationKinds IK) {
+ assert(MR);
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+ setTrait(SR->getSymbol(), IK);
+ else
+ MRTraitsMap[MR] |= IK;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
+ InvalidationKinds IK) {
+ const_symbol_iterator I = SymTraitsMap.find(Sym);
+ if (I != SymTraitsMap.end())
+ return I->second & IK;
+
+ return false;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
+ InvalidationKinds IK) {
+ if (!MR)
+ return false;
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+ return hasTrait(SR->getSymbol(), IK);
+
+ const_region_iterator I = MRTraitsMap.find(MR);
+ if (I != MRTraitsMap.end())
+ return I->second & IK;
+
+ return false;
+}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 03513106ecd3..b504db6349ee 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -48,10 +48,11 @@ static StringRef StripTrailingDots(StringRef s) {
PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
Kind k, DisplayHint hint)
- : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
+ : str(StripTrailingDots(s)), kind(k), Hint(hint),
+ LastInMainSourceFile(false) {}
PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
- : kind(k), Hint(hint) {}
+ : kind(k), Hint(hint), LastInMainSourceFile(false) {}
PathDiagnosticPiece::~PathDiagnosticPiece() {}
PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
@@ -119,6 +120,71 @@ PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
UniqueingDecl(DeclToUnique),
path(pathImpl) {}
+static PathDiagnosticCallPiece *
+getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
+ const SourceManager &SMgr) {
+ SourceLocation CallLoc = CP->callEnter.asLocation();
+
+ // If the call is within a macro, don't do anything (for now).
+ if (CallLoc.isMacroID())
+ return 0;
+
+ assert(SMgr.isInMainFile(CallLoc) &&
+ "The call piece should be in the main file.");
+
+ // Check if CP represents a path through a function outside of the main file.
+ if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
+ return CP;
+
+ const PathPieces &Path = CP->path;
+ if (Path.empty())
+ return 0;
+
+ // Check if the last piece in the callee path is a call to a function outside
+ // of the main file.
+ if (PathDiagnosticCallPiece *CPInner =
+ dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
+ return getFirstStackedCallToHeaderFile(CPInner, SMgr);
+ }
+
+ // Otherwise, the last piece is in the main file.
+ return 0;
+}
+
+void PathDiagnostic::resetDiagnosticLocationToMainFile() {
+ if (path.empty())
+ return;
+
+ PathDiagnosticPiece *LastP = path.back().getPtr();
+ assert(LastP);
+ const SourceManager &SMgr = LastP->getLocation().getManager();
+
+ // We only need to check if the report ends inside headers, if the last piece
+ // is a call piece.
+ if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
+ CP = getFirstStackedCallToHeaderFile(CP, SMgr);
+ if (CP) {
+ // Mark the piece.
+ CP->setAsLastInMainSourceFile();
+
+ // Update the path diagnostic message.
+ const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
+ if (ND) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << " (within a call to '" << ND->getDeclName() << "')";
+ appendToDesc(os.str());
+ }
+
+ // Reset the report containing declaration and location.
+ DeclWithIssue = CP->getCaller();
+ Loc = CP->getLocation();
+
+ return;
+ }
+ }
+}
+
void PathDiagnosticConsumer::anchor() { }
PathDiagnosticConsumer::~PathDiagnosticConsumer() {
@@ -150,11 +216,10 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
- const PathPieces &path = *WorkList.back();
- WorkList.pop_back();
+ const PathPieces &path = *WorkList.pop_back_val();
- for (PathPieces::const_iterator I = path.begin(), E = path.end();
- I != E; ++I) {
+ for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
+ ++I) {
const PathDiagnosticPiece *piece = I->getPtr();
FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
@@ -494,6 +559,10 @@ getLocationForCaller(const StackFrameContext *SFC,
return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
SM, CallerCtx);
}
+ case CFGElement::DeleteDtor: {
+ const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
+ return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
+ }
case CFGElement::BaseDtor:
case CFGElement::MemberDtor: {
const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
@@ -916,7 +985,7 @@ IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
if (!callEnterWithin.asLocation().isValid())
return 0;
- if (Callee->isImplicit())
+ if (Callee->isImplicit() || !Callee->hasBody())
return 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
if (MD->isDefaulted())
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 850955561ec1..5dca811722ac 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -50,7 +50,6 @@ namespace {
PathGenerationScheme getGenerationScheme() const { return Extensive; }
bool supportsLogicalOpControlFlow() const { return true; }
- bool supportsAllBlockEdges() const { return true; }
virtual bool supportsCrossFileDiagnostics() const {
return SupportsCrossFileDiagnostics;
}
@@ -215,13 +214,18 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
const SourceManager &SM,
const LangOptions &LangOpts,
unsigned indent,
- unsigned depth) {
+ unsigned depth,
+ bool isKeyEvent = false) {
Indent(o, indent) << "<dict>\n";
++indent;
Indent(o, indent) << "<key>kind</key><string>event</string>\n";
+ if (isKeyEvent) {
+ Indent(o, indent) << "<key>key_event</key><true/>\n";
+ }
+
// Output the location.
FullSourceLoc L = P.getLocation().asLocation();
@@ -270,7 +274,8 @@ static void ReportPiece(raw_ostream &o,
const LangOptions &LangOpts,
unsigned indent,
unsigned depth,
- bool includeControlFlow);
+ bool includeControlFlow,
+ bool isKeyEvent = false);
static void ReportCall(raw_ostream &o,
const PathDiagnosticCallPiece &P,
@@ -283,7 +288,8 @@ static void ReportCall(raw_ostream &o,
P.getCallEnterEvent();
if (callEnter)
- ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true);
+ ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
+ P.isLastInMainSourceFile());
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
P.getCallEnterWithinCallerEvent();
@@ -331,7 +337,8 @@ static void ReportPiece(raw_ostream &o,
const LangOptions &LangOpts,
unsigned indent,
unsigned depth,
- bool includeControlFlow) {
+ bool includeControlFlow,
+ bool isKeyEvent) {
switch (P.getKind()) {
case PathDiagnosticPiece::ControlFlow:
if (includeControlFlow)
@@ -344,7 +351,7 @@ static void ReportPiece(raw_ostream &o,
break;
case PathDiagnosticPiece::Event:
ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
- indent, depth);
+ indent, depth, isKeyEvent);
break;
case PathDiagnosticPiece::Macro:
ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
@@ -375,11 +382,10 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
- const PathPieces &path = *WorkList.back();
- WorkList.pop_back();
-
- for (PathPieces::const_iterator I = path.begin(), E = path.end();
- I!=E; ++I) {
+ const PathPieces &path = *WorkList.pop_back_val();
+
+ for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
+ ++I) {
const PathDiagnosticPiece *piece = I->getPtr();
AddFID(FM, Fids, SM, piece->getLocation().asLocation());
ArrayRef<SourceRange> Ranges = piece->getRanges();
diff --git a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
new file mode 100644
index 000000000000..ed64fcbec761
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
@@ -0,0 +1,45 @@
+//==- PrettyStackTraceLocationContext.h - show analysis backtrace --*- 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_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H
+#define LLVM_CLANG_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H
+
+#include "clang/Analysis/AnalysisContext.h"
+
+namespace clang {
+namespace ento {
+
+/// While alive, includes the current analysis stack in a crash trace.
+///
+/// Example:
+/// \code
+/// 0. Program arguments: ...
+/// 1. <eof> parser at end of file
+/// 2. While analyzing stack:
+/// #0 void inlined()
+/// #1 void test()
+/// 3. crash-trace.c:6:3: Error evaluating statement
+/// \endcode
+class PrettyStackTraceLocationContext : public llvm::PrettyStackTraceEntry {
+ const LocationContext *LCtx;
+public:
+ PrettyStackTraceLocationContext(const LocationContext *LC) : LCtx(LC) {
+ assert(LCtx);
+ }
+
+ virtual void print(raw_ostream &OS) const {
+ OS << "While analyzing stack: \n";
+ LCtx->dumpStack(OS, "\t");
+ }
+};
+
+} // end ento namespace
+} // end clang namespace
+
+#endif
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 653b69bf4860..6e2366814406 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -137,48 +137,32 @@ typedef ArrayRef<SVal> ValueList;
ProgramStateRef
ProgramState::invalidateRegions(RegionList Regions,
- const Expr *E, unsigned Count,
- const LocationContext *LCtx,
- bool CausedByPointerEscape,
- InvalidatedSymbols *IS,
- const CallEvent *Call,
- RegionList ConstRegions) const {
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ RegionAndSymbolInvalidationTraits *ITraits) const {
SmallVector<SVal, 8> Values;
for (RegionList::const_iterator I = Regions.begin(),
End = Regions.end(); I != End; ++I)
Values.push_back(loc::MemRegionVal(*I));
- SmallVector<SVal, 8> ConstValues;
- for (RegionList::const_iterator I = ConstRegions.begin(),
- End = ConstRegions.end(); I != End; ++I)
- ConstValues.push_back(loc::MemRegionVal(*I));
-
- if (!IS) {
- InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Values, E, Count, LCtx,
- CausedByPointerEscape,
- invalidated, Call, ConstValues);
- }
return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
- *IS, Call, ConstValues);
+ IS, ITraits, Call);
}
ProgramStateRef
ProgramState::invalidateRegions(ValueList Values,
- const Expr *E, unsigned Count,
- const LocationContext *LCtx,
- bool CausedByPointerEscape,
- InvalidatedSymbols *IS,
- const CallEvent *Call,
- ValueList ConstValues) const {
- if (!IS) {
- InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Values, E, Count, LCtx,
- CausedByPointerEscape,
- invalidated, Call, ConstValues);
- }
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ RegionAndSymbolInvalidationTraits *ITraits) const {
+
return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
- *IS, Call, ConstValues);
+ IS, ITraits, Call);
}
ProgramStateRef
@@ -186,49 +170,45 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
bool CausedByPointerEscape,
- InvalidatedSymbols &IS,
- const CallEvent *Call,
- ValueList ConstValues) const {
+ InvalidatedSymbols *IS,
+ RegionAndSymbolInvalidationTraits *ITraits,
+ const CallEvent *Call) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
InvalidatedSymbols ConstIS;
+ InvalidatedSymbols Invalidated;
+ if (!IS)
+ IS = &Invalidated;
+
+ RegionAndSymbolInvalidationTraits ITraitsLocal;
+ if (!ITraits)
+ ITraits = &ITraitsLocal;
+
if (Eng) {
StoreManager::InvalidatedRegions TopLevelInvalidated;
- StoreManager::InvalidatedRegions TopLevelConstInvalidated;
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
- = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
- E, Count, LCtx, Call,
- IS, ConstIS,
- &TopLevelInvalidated,
- &TopLevelConstInvalidated,
+ = Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
+ *IS, *ITraits, &TopLevelInvalidated,
&Invalidated);
ProgramStateRef newState = makeWithStore(newStore);
if (CausedByPointerEscape) {
- newState = Eng->notifyCheckersOfPointerEscape(newState, &IS,
+ newState = Eng->notifyCheckersOfPointerEscape(newState, IS,
TopLevelInvalidated,
- Invalidated, Call);
- if (!ConstValues.empty()) {
- StoreManager::InvalidatedRegions Empty;
- newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS,
- TopLevelConstInvalidated,
- Empty, Call,
- true);
- }
+ Invalidated, Call,
+ *ITraits);
}
- return Eng->processRegionChanges(newState, &IS,
- TopLevelInvalidated, Invalidated,
- Call);
+ return Eng->processRegionChanges(newState, IS, TopLevelInvalidated,
+ Invalidated, Call);
}
const StoreRef &newStore =
- Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
- E, Count, LCtx, Call,
- IS, ConstIS, NULL, NULL, NULL);
+ Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
+ *IS, *ITraits, NULL, NULL);
return makeWithStore(newStore);
}
@@ -526,6 +506,19 @@ ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key)
return getPersistentState(NewState);
}
+bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {
+ bool wasVisited = !visited.insert(val.getCVData()).second;
+ if (wasVisited)
+ return true;
+
+ StoreManager &StoreMgr = state->getStateManager().getStoreManager();
+ // FIXME: We don't really want to use getBaseRegion() here because pointer
+ // arithmetic doesn't apply, but scanReachableSymbols only accepts base
+ // regions right now.
+ const MemRegion *R = val.getRegion()->getBaseRegion();
+ return StoreMgr.scanReachableSymbols(val.getStore(), R, *this);
+}
+
bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
if (!scan(*I))
@@ -535,10 +528,9 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
}
bool ScanReachableSymbols::scan(const SymExpr *sym) {
- unsigned &isVisited = visited[sym];
- if (isVisited)
+ bool wasVisited = !visited.insert(sym).second;
+ if (wasVisited)
return true;
- isVisited = 1;
if (!visitor.VisitSymbol(sym))
return false;
@@ -570,16 +562,8 @@ bool ScanReachableSymbols::scan(SVal val) {
return scan(X->getRegion());
if (Optional<nonloc::LazyCompoundVal> X =
- val.getAs<nonloc::LazyCompoundVal>()) {
- StoreManager &StoreMgr = state->getStateManager().getStoreManager();
- // FIXME: We don't really want to use getBaseRegion() here because pointer
- // arithmetic doesn't apply, but scanReachableSymbols only accepts base
- // regions right now.
- if (!StoreMgr.scanReachableSymbols(X->getStore(),
- X->getRegion()->getBaseRegion(),
- *this))
- return false;
- }
+ val.getAs<nonloc::LazyCompoundVal>())
+ return scan(*X);
if (Optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
return scan(X->getLoc());
@@ -600,11 +584,9 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
if (isa<MemSpaceRegion>(R))
return true;
- unsigned &isVisited = visited[R];
- if (isVisited)
+ bool wasVisited = !visited.insert(R).second;
+ if (wasVisited)
return true;
- isVisited = 1;
-
if (!visitor.VisitMemRegion(R))
return false;
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 88c4eee4bb2b..0b519768aa04 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -349,7 +349,6 @@ private:
/// regions.
void populateWorkList(invalidateRegionsWorker &W,
ArrayRef<SVal> Values,
- bool IsArrayOfConstRegions,
InvalidatedRegions *TopLevelRegions);
public:
@@ -377,7 +376,7 @@ public:
/// version of that lvalue (i.e., a pointer to the first element of
/// the array). This is called by ExprEngine when evaluating
/// casts from arrays to pointers.
- SVal ArrayToPointer(Loc Array);
+ SVal ArrayToPointer(Loc Array, QualType ElementTy);
StoreRef getInitialStore(const LocationContext *InitLoc) {
return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
@@ -395,15 +394,13 @@ public:
StoreRef invalidateRegions(Store store,
ArrayRef<SVal> Values,
- ArrayRef<SVal> ConstValues,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
const CallEvent *Call,
InvalidatedSymbols &IS,
- InvalidatedSymbols &ConstIS,
+ RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *Invalidated,
- InvalidatedRegions *InvalidatedTopLevel,
- InvalidatedRegions *InvalidatedTopLevelConst);
+ InvalidatedRegions *InvalidatedTopLevel);
bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks);
@@ -422,11 +419,20 @@ 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) {
RegionBindingsRef B = getRegionBindings(store);
- assert(!B.lookup(R, BindingKey::Default));
assert(!B.lookup(R, BindingKey::Direct));
- return StoreRef(B.addBinding(R, BindingKey::Default, V)
- .asImmutableMap()
- .getRootWithoutRetain(), *this);
+
+ BindingKey Key = BindingKey::Make(R, BindingKey::Default);
+ if (B.lookup(Key)) {
+ const SubRegion *SR = cast<SubRegion>(R);
+ assert(SR->getAsOffset().getOffset() ==
+ SR->getSuperRegion()->getAsOffset().getOffset() &&
+ "A default value must come from a super-region");
+ B = removeSubRegionBindings(B, SR);
+ } else {
+ B = B.addBinding(Key, V);
+ }
+
+ return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this);
}
/// Attempt to extract the fields of \p LCV and bind them to the struct region
@@ -639,7 +645,7 @@ template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
- typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+ typedef const MemRegion * WorkListElement;
typedef SmallVector<WorkListElement, 10> WorkList;
llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -711,18 +717,17 @@ public:
return true;
}
- bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+ bool AddToWorkList(const MemRegion *R) {
const MemRegion *BaseR = R->getBaseRegion();
- return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
+ return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
}
void RunWorkList() {
while (!WL.empty()) {
WorkListElement E = WL.pop_back_val();
- const MemRegion *BaseR = E.getPointer();
+ const MemRegion *BaseR = E;
- static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
- E.getInt());
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR));
}
}
@@ -942,7 +947,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
unsigned Count;
const LocationContext *LCtx;
InvalidatedSymbols &IS;
- InvalidatedSymbols &ConstIS;
+ RegionAndSymbolInvalidationTraits &ITraits;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
@@ -951,16 +956,13 @@ public:
const Expr *ex, unsigned count,
const LocationContext *lctx,
InvalidatedSymbols &is,
- InvalidatedSymbols &inConstIS,
+ RegionAndSymbolInvalidationTraits &ITraitsIn,
StoreManager::InvalidatedRegions *r,
GlobalsFilterKind GFK)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK),
- Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
+ Ex(ex), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r){}
- /// \param IsConst Specifies if the region we are invalidating is constant.
- /// If it is, we invalidate all subregions, but not the base region itself.
- void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
- bool IsConst);
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
void VisitBinding(SVal V);
};
}
@@ -991,14 +993,18 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
}
void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
- const ClusterBindings *C,
- bool IsConst) {
+ const ClusterBindings *C) {
+
+ bool PreserveRegionsContents =
+ ITraits.hasTrait(baseR,
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+
if (C) {
for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
VisitBinding(I.getData());
- // Invalidate the contents of a non-const base region.
- if (!IsConst)
+ // Invalidate regions contents.
+ if (!PreserveRegionsContents)
B = B.remove(baseR);
}
@@ -1030,18 +1036,11 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
}
// Symbolic region?
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) {
- SymbolRef RegionSym = SR->getSymbol();
-
- // Mark that symbol touched by the invalidation.
- if (IsConst)
- ConstIS.insert(RegionSym);
- else
- IS.insert(RegionSym);
- }
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ IS.insert(SR->getSymbol());
- // Nothing else should be done for a const region.
- if (IsConst)
+ // Nothing else should be done in the case when we preserve regions context.
+ if (PreserveRegionsContents)
return;
// Otherwise, we have a normal data region. Record that we touched the region.
@@ -1050,7 +1049,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
// Invalidate the region by setting its default value to
- // conjured symbol. The type of the symbol is irrelavant.
+ // conjured symbol. The type of the symbol is irrelevant.
DefinedOrUnknownSVal V =
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
B = B.addBinding(baseR, BindingKey::Default, V);
@@ -1072,7 +1071,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
if (T->isStructureOrClassType()) {
// Invalidate the region by setting its default value to
- // conjured symbol. The type of the symbol is irrelavant.
+ // conjured symbol. The type of the symbol is irrelevant.
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
Ctx.IntTy, Count);
B = B.addBinding(baseR, BindingKey::Default, V);
@@ -1121,7 +1120,6 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
ArrayRef<SVal> Values,
- bool IsArrayOfConstRegions,
InvalidatedRegions *TopLevelRegions) {
for (ArrayRef<SVal>::iterator I = Values.begin(),
E = Values.end(); I != E; ++I) {
@@ -1136,7 +1134,7 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
// Note: the last argument is false here because these are
// non-top-level regions.
if (const MemRegion *R = (*I).getAsRegion())
- W.AddToWorkList(R, /*IsConst=*/ false);
+ W.AddToWorkList(R);
}
continue;
}
@@ -1144,7 +1142,7 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
if (const MemRegion *R = V.getAsRegion()) {
if (TopLevelRegions)
TopLevelRegions->push_back(R);
- W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions);
+ W.AddToWorkList(R);
continue;
}
}
@@ -1152,16 +1150,14 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
StoreRef
RegionStoreManager::invalidateRegions(Store store,
- ArrayRef<SVal> Values,
- ArrayRef<SVal> ConstValues,
- const Expr *Ex, unsigned Count,
- const LocationContext *LCtx,
- const CallEvent *Call,
- InvalidatedSymbols &IS,
- InvalidatedSymbols &ConstIS,
- InvalidatedRegions *TopLevelRegions,
- InvalidatedRegions *TopLevelConstRegions,
- InvalidatedRegions *Invalidated) {
+ ArrayRef<SVal> Values,
+ const Expr *Ex, unsigned Count,
+ const LocationContext *LCtx,
+ const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ RegionAndSymbolInvalidationTraits &ITraits,
+ InvalidatedRegions *TopLevelRegions,
+ InvalidatedRegions *Invalidated) {
GlobalsFilterKind GlobalsFilter;
if (Call) {
if (Call->isInSystemHeader())
@@ -1173,17 +1169,14 @@ RegionStoreManager::invalidateRegions(Store store,
}
RegionBindingsRef B = getRegionBindings(store);
- invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
+ invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ITraits,
Invalidated, GlobalsFilter);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
// Add the regions to the worklist.
- populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false,
- TopLevelRegions);
- populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true,
- TopLevelConstRegions);
+ populateWorkList(W, Values, TopLevelRegions);
W.RunWorkList();
@@ -1250,23 +1243,13 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state,
/// version of that lvalue (i.e., a pointer to the first element of
/// the array). This is called by ExprEngine when evaluating casts
/// from arrays to pointers.
-SVal RegionStoreManager::ArrayToPointer(Loc Array) {
+SVal RegionStoreManager::ArrayToPointer(Loc Array, QualType T) {
if (!Array.getAs<loc::MemRegionVal>())
return UnknownVal();
const MemRegion* R = Array.castAs<loc::MemRegionVal>().getRegion();
- const TypedValueRegion* ArrayR = dyn_cast<TypedValueRegion>(R);
-
- if (!ArrayR)
- return UnknownVal();
-
- // Strip off typedefs from the ArrayRegion's ValueType.
- QualType T = ArrayR->getValueType().getDesugaredType(Ctx);
- const ArrayType *AT = cast<ArrayType>(T);
- T = AT->getElementType();
-
NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
- return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx));
+ return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, R, Ctx));
}
//===----------------------------------------------------------------------===//
@@ -1329,7 +1312,7 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
// FIXME: Handle unions.
if (RTy->isUnionType())
- return UnknownVal();
+ return createLazyBinding(B, R);
if (RTy->isArrayType()) {
if (RTy->isConstantArrayType())
@@ -1507,7 +1490,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
// FIXME: Handle loads from strings where the literal is treated as
// an integer, e.g., *((unsigned int*)"hello")
QualType T = Ctx.getAsArrayType(StrR->getValueType())->getElementType();
- if (T != Ctx.getCanonicalType(R->getElementType()))
+ if (!Ctx.hasSameUnqualifiedType(T, R->getElementType()))
return UnknownVal();
const StringLiteral *Str = StrR->getStringLiteral();
@@ -1842,10 +1825,18 @@ NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
+static bool isRecordEmpty(const RecordDecl *RD) {
+ if (!RD->field_empty())
+ return false;
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD))
+ return CRD->getNumBases() == 0;
+ return true;
+}
+
SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
const TypedValueRegion *R) {
const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl();
- if (RD->field_empty())
+ if (!RD->getDefinition() || isRecordEmpty(RD))
return UnknownVal();
return createLazyBinding(B, R);
@@ -1915,6 +1906,8 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
return bindStruct(B, TR, V);
if (Ty->isVectorType())
return bindVector(B, TR, V);
+ if (Ty->isUnionType())
+ return bindAggregate(B, TR, V);
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 9d77a3ef58fb..adc54659911a 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -202,10 +202,12 @@ DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
CanQualType locTy,
- const LocationContext *locContext) {
+ const LocationContext *locContext,
+ unsigned blockCount) {
const BlockTextRegion *BC =
MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisDeclContext());
- const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext);
+ const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext,
+ blockCount);
return loc::MemRegionVal(BD);
}
@@ -266,6 +268,17 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
case Stmt::CXXNullPtrLiteralExprClass:
return makeNull();
+ case Stmt::ImplicitCastExprClass: {
+ const CastExpr *CE = cast<CastExpr>(E);
+ if (CE->getCastKind() == CK_ArrayToPointerDecay) {
+ Optional<SVal> ArrayVal = getConstantVal(CE->getSubExpr());
+ if (!ArrayVal)
+ return None;
+ return evalCast(*ArrayVal, CE->getType(), CE->getSubExpr()->getType());
+ }
+ // FALLTHROUGH
+ }
+
// If we don't have a special case, fall back to the AST's constant evaluator.
default: {
// Don't try to come up with a value for materialized temporaries.
@@ -394,15 +407,22 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
return val;
if (val.isConstant())
return makeTruthVal(!val.isZeroConstant(), castTy);
- if (SymbolRef Sym = val.getAsSymbol()) {
+ if (!Loc::isLocType(originalTy) &&
+ !originalTy->isIntegralOrEnumerationType() &&
+ !originalTy->isMemberPointerType())
+ return UnknownVal();
+ if (SymbolRef Sym = val.getAsSymbol(true)) {
BasicValueFactory &BVF = getBasicValueFactory();
// FIXME: If we had a state here, we could see if the symbol is known to
// be zero, but we don't.
return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy);
}
+ // Loc values are not always true, they could be weakly linked functions.
+ if (Optional<Loc> L = val.getAs<Loc>())
+ return evalCastFromLoc(*L, castTy);
- assert(val.getAs<Loc>());
- return makeTruthVal(true, castTy);
+ Loc L = val.castAs<nonloc::LocAsInteger>().getLoc();
+ return evalCastFromLoc(L, castTy);
}
// For const casts, casts to void, just propagate the value.
@@ -435,9 +455,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
}
// Check for casts from array type to another type.
- if (originalTy->isArrayType()) {
+ if (const ArrayType *arrayT =
+ dyn_cast<ArrayType>(originalTy.getCanonicalType())) {
// We will always decay to a pointer.
- val = StateMgr.ArrayToPointer(val.castAs<Loc>());
+ QualType elemTy = arrayT->getElementType();
+ val = StateMgr.ArrayToPointer(val.castAs<Loc>(), elemTy);
// Are we casting from an array to a pointer? If so just pass on
// the decayed value.
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index a06268dd331f..e6653ae6e4b5 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -68,51 +68,20 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) {
- if (Optional<NonLoc> NV = Cond.getAs<NonLoc>())
- return assume(state, *NV, Assumption);
- return assume(state, Cond.castAs<Loc>(), Assumption);
-}
-
-ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
- bool assumption) {
- state = assumeAux(state, cond, assumption);
- if (NotifyAssumeClients && SU)
- return SU->processAssume(state, cond, assumption);
- return state;
-}
-
-ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
- Loc Cond, bool Assumption) {
- switch (Cond.getSubKind()) {
- default:
- assert (false && "'Assume' not implemented for this Loc.");
- return state;
-
- case loc::MemRegionKind: {
- // FIXME: Should this go into the storemanager?
- const MemRegion *R = Cond.castAs<loc::MemRegionVal>().getRegion();
-
- // FIXME: now we only find the first symbolic region.
- if (const SymbolicRegion *SymR = R->getSymbolicBase()) {
- const llvm::APSInt &zero = getBasicVals().getZeroWithPtrWidth();
- if (Assumption)
- return assumeSymNE(state, SymR->getSymbol(), zero, zero);
- else
- return assumeSymEQ(state, SymR->getSymbol(), zero, zero);
- }
-
- // FALL-THROUGH.
+ // If we have a Loc value, cast it to a bool NonLoc first.
+ if (Optional<Loc> LV = Cond.getAs<Loc>()) {
+ SValBuilder &SVB = state->getStateManager().getSValBuilder();
+ QualType T;
+ const MemRegion *MR = LV->getAsRegion();
+ if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
+ T = TR->getLocationType();
+ else
+ T = SVB.getContext().VoidPtrTy;
+
+ Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
}
- case loc::GotoLabelKind:
- return Assumption ? state : NULL;
-
- case loc::ConcreteIntKind: {
- bool b = Cond.castAs<loc::ConcreteInt>().getValue() != 0;
- bool isFeasible = b ? Assumption : !Assumption;
- return isFeasible ? state : NULL;
- }
- } // end switch
+ return assume(state, Cond.castAs<NonLoc>(), Assumption);
}
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
@@ -216,8 +185,8 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
}
case nonloc::LocAsIntegerKind:
- return assumeAux(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
- Assumption);
+ return assume(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
+ Assumption);
} // end switch
}
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 10ddef1341c5..28a9a4ded9de 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -36,8 +36,6 @@ public:
ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond,
bool Assumption);
- ProgramStateRef assume(ProgramStateRef state, Loc Cond, bool Assumption);
-
ProgramStateRef assume(ProgramStateRef state, NonLoc Cond, bool Assumption);
ProgramStateRef assumeSymRel(ProgramStateRef state,
@@ -87,10 +85,6 @@ protected:
bool canReasonAbout(SVal X) const;
ProgramStateRef assumeAux(ProgramStateRef state,
- Loc Cond,
- bool Assumption);
-
- ProgramStateRef assumeAux(ProgramStateRef state,
NonLoc Cond,
bool Assumption);
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index ee627f2baa35..cc0ee0b5c7a9 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -137,6 +137,32 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
if (castTy->isUnionType())
return UnknownVal();
+ // Casting a Loc to a bool will almost always be true,
+ // unless this is a weak function or a symbolic region.
+ if (castTy->isBooleanType()) {
+ switch (val.getSubKind()) {
+ case loc::MemRegionKind: {
+ const MemRegion *R = val.castAs<loc::MemRegionVal>().getRegion();
+ if (const FunctionTextRegion *FTR = dyn_cast<FunctionTextRegion>(R))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl()))
+ if (FD->isWeak())
+ // FIXME: Currently we are using an extent symbol here,
+ // because there are no generic region address metadata
+ // symbols to use, only content metadata.
+ return nonloc::SymbolVal(SymMgr.getExtentSymbol(FTR));
+
+ if (const SymbolicRegion *SymR = R->getSymbolicBase())
+ return nonloc::SymbolVal(SymR->getSymbol());
+
+ // FALL-THROUGH
+ }
+
+ case loc::GotoLabelKind:
+ // Labels and non symbolic memory regions are always true.
+ return makeTruthVal(true, castTy);
+ }
+ }
+
if (castTy->isIntegralOrEnumerationType()) {
unsigned BitWidth = Context.getTypeSize(castTy);
@@ -507,6 +533,53 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
}
+static SVal evalBinOpFieldRegionFieldRegion(const FieldRegion *LeftFR,
+ const FieldRegion *RightFR,
+ BinaryOperator::Opcode op,
+ QualType resultTy,
+ SimpleSValBuilder &SVB) {
+ // Only comparisons are meaningful here!
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
+
+ // Next, see if the two FRs have the same super-region.
+ // FIXME: This doesn't handle casts yet, and simply stripping the casts
+ // doesn't help.
+ if (LeftFR->getSuperRegion() != RightFR->getSuperRegion())
+ return UnknownVal();
+
+ const FieldDecl *LeftFD = LeftFR->getDecl();
+ const FieldDecl *RightFD = RightFR->getDecl();
+ const RecordDecl *RD = LeftFD->getParent();
+
+ // Make sure the two FRs are from the same kind of record. Just in case!
+ // FIXME: This is probably where inheritance would be a problem.
+ if (RD != RightFD->getParent())
+ return UnknownVal();
+
+ // We know for sure that the two fields are not the same, since that
+ // would have given us the same SVal.
+ if (op == BO_EQ)
+ return SVB.makeTruthVal(false, resultTy);
+ if (op == BO_NE)
+ return SVB.makeTruthVal(true, resultTy);
+
+ // Iterate through the fields and see which one comes first.
+ // [C99 6.7.2.1.13] "Within a structure object, the non-bit-field
+ // members and the units in which bit-fields reside have addresses that
+ // increase in the order in which they are declared."
+ bool leftFirst = (op == BO_LT || op == BO_LE);
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I!=E; ++I) {
+ if (*I == LeftFD)
+ return SVB.makeTruthVal(leftFirst, resultTy);
+ if (*I == RightFD)
+ return SVB.makeTruthVal(!leftFirst, resultTy);
+ }
+
+ llvm_unreachable("Fields not found in parent record's definition");
+}
+
// FIXME: all this logic will change if/when we have MemRegion::getLocation().
SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
BinaryOperator::Opcode op,
@@ -621,7 +694,7 @@ 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())
+ if (SymbolRef lSym = lhs.getAsLocSymbol(true))
return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);
// Special case comparisons to NULL.
@@ -629,19 +702,14 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// build constraints. The address of any non-symbolic region is guaranteed
// to be non-NULL.
if (rInt->isZeroConstant()) {
- switch (op) {
- default:
- break;
- case BO_Sub:
+ if (op == BO_Sub)
return evalCastFromLoc(lhs, resultTy);
- case BO_EQ:
- case BO_LT:
- case BO_LE:
- return makeTruthVal(false, resultTy);
- case BO_NE:
- case BO_GT:
- case BO_GE:
- return makeTruthVal(true, resultTy);
+
+ if (BinaryOperator::isComparisonOp(op)) {
+ QualType boolType = getContext().BoolTy;
+ NonLoc l = evalCastFromLoc(lhs, boolType).castAs<NonLoc>();
+ NonLoc r = makeTruthVal(false, boolType).castAs<NonLoc>();
+ return evalBinOpNN(state, op, l, r, resultTy);
}
}
@@ -699,14 +767,10 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
}
- // FIXME: If/when there is a getAsRawOffset() for FieldRegions, this
- // ElementRegion path and the FieldRegion path below should be unified.
- if (const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR)) {
- // First see if the right region is also an ElementRegion.
- const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
- if (!RightER)
- return UnknownVal();
-
+ // Handle special cases for when both regions are element regions.
+ const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
+ const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR);
+ if (RightER && LeftER) {
// Next, see if the two ERs have the same super-region and matching types.
// FIXME: This should do something useful even if the types don't match,
// though if both indexes are constant the RegionRawOffset path will
@@ -738,17 +802,29 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// evalBinOpNN expects the two indexes to already be the right type.
return evalBinOpNN(state, op, *LeftIndex, *RightIndex, resultTy);
}
+ }
+
+ // Special handling of the FieldRegions, even with symbolic offsets.
+ const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR);
+ const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR);
+ if (RightFR && LeftFR) {
+ SVal R = evalBinOpFieldRegionFieldRegion(LeftFR, RightFR, op, resultTy,
+ *this);
+ if (!R.isUnknown())
+ return R;
+ }
- // If the element indexes aren't comparable, see if the raw offsets are.
- RegionRawOffset LeftOffset = LeftER->getAsArrayOffset();
- RegionRawOffset RightOffset = RightER->getAsArrayOffset();
+ // Compare the regions using the raw offsets.
+ RegionOffset LeftOffset = LeftMR->getAsOffset();
+ RegionOffset RightOffset = RightMR->getAsOffset();
- if (LeftOffset.getRegion() != NULL &&
- LeftOffset.getRegion() == RightOffset.getRegion()) {
- CharUnits left = LeftOffset.getOffset();
- CharUnits right = RightOffset.getOffset();
+ if (LeftOffset.getRegion() != NULL &&
+ LeftOffset.getRegion() == RightOffset.getRegion() &&
+ !LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) {
+ int64_t left = LeftOffset.getOffset();
+ int64_t right = RightOffset.getOffset();
- switch (op) {
+ switch (op) {
default:
return UnknownVal();
case BO_LT:
@@ -763,60 +839,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
return makeTruthVal(left == right, resultTy);
case BO_NE:
return makeTruthVal(left != right, resultTy);
- }
}
-
- // If we get here, we have no way of comparing the ElementRegions.
- }
-
- // See if both regions are fields of the same structure.
- // FIXME: This doesn't handle nesting, inheritance, or Objective-C ivars.
- if (const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR)) {
- // Only comparisons are meaningful here!
- if (!BinaryOperator::isComparisonOp(op))
- return UnknownVal();
-
- // First see if the right region is also a FieldRegion.
- const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR);
- if (!RightFR)
- return UnknownVal();
-
- // Next, see if the two FRs have the same super-region.
- // FIXME: This doesn't handle casts yet, and simply stripping the casts
- // doesn't help.
- if (LeftFR->getSuperRegion() != RightFR->getSuperRegion())
- return UnknownVal();
-
- const FieldDecl *LeftFD = LeftFR->getDecl();
- const FieldDecl *RightFD = RightFR->getDecl();
- const RecordDecl *RD = LeftFD->getParent();
-
- // Make sure the two FRs are from the same kind of record. Just in case!
- // FIXME: This is probably where inheritance would be a problem.
- if (RD != RightFD->getParent())
- return UnknownVal();
-
- // We know for sure that the two fields are not the same, since that
- // would have given us the same SVal.
- if (op == BO_EQ)
- return makeTruthVal(false, resultTy);
- if (op == BO_NE)
- return makeTruthVal(true, resultTy);
-
- // Iterate through the fields and see which one comes first.
- // [C99 6.7.2.1.13] "Within a structure object, the non-bit-field
- // members and the units in which bit-fields reside have addresses that
- // increase in the order in which they are declared."
- bool leftFirst = (op == BO_LT || op == BO_LE);
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I!=E; ++I) {
- if (*I == LeftFD)
- return makeTruthVal(leftFirst, resultTy);
- if (*I == RightFD)
- return makeTruthVal(!leftFirst, resultTy);
- }
-
- llvm_unreachable("Fields not found in parent record's definition");
}
// At this point we're not going to get a good answer, but we can try
@@ -835,32 +858,13 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) {
-
+ assert(!BinaryOperator::isComparisonOp(op) &&
+ "arguments to comparison ops must be of the same type");
+
// Special case: rhs is a zero constant.
if (rhs.isZeroConstant())
return lhs;
- // Special case: 'rhs' is an integer that has the same width as a pointer and
- // we are using the integer location in a comparison. Normally this cannot be
- // triggered, but transfer functions like those for OSCompareAndSwapBarrier32
- // can generate comparisons that trigger this code.
- // FIXME: Are all locations guaranteed to have pointer width?
- if (BinaryOperator::isComparisonOp(op)) {
- if (Optional<nonloc::ConcreteInt> rhsInt =
- rhs.getAs<nonloc::ConcreteInt>()) {
- const llvm::APSInt *x = &rhsInt->getValue();
- ASTContext &ctx = Context;
- if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
- // Convert the signedness of the integer (if necessary).
- if (x->isSigned())
- x = &getBasicValueFactory().getValue(*x, true);
-
- return evalBinOpLL(state, op, lhs, loc::ConcreteInt(*x), resultTy);
- }
- }
- return UnknownVal();
- }
-
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 690ed08ffc78..0beb9dbbc5be 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -325,7 +325,10 @@ SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType,
if (MRClass == TargetClass)
return loc::MemRegionVal(MR);
- if (!TargetType->isVoidType()) {
+ // We skip over incomplete types. They must be the result of an earlier
+ // reinterpret_cast, as one can only dynamic_cast between types in the same
+ // class hierarchy.
+ if (!TargetType->isVoidType() && MRClass->hasDefinition()) {
// Static upcasts are marked as DerivedToBase casts by Sema, so this will
// only happen when multiple or virtual inheritance is involved.
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 7c75b6c3d2fd..1b56f82dc60f 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -112,8 +112,7 @@ SymbolRef SymExpr::symbol_iterator::operator*() {
}
void SymExpr::symbol_iterator::expand() {
- const SymExpr *SE = itr.back();
- itr.pop_back();
+ const SymExpr *SE = itr.pop_back_val();
switch (SE->getKind()) {
case SymExpr::RegionValueKind:
@@ -436,6 +435,9 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
if (isa<MemSpaceRegion>(MR))
return true;
+ if (isa<CodeTextRegion>(MR))
+ return true;
+
return false;
}
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
deleted file mode 100644
index d5706d6dbbe8..000000000000
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//===--- TextPathDiagnostics.cpp - Text Diagnostics for Paths ---*- 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 TextPathDiagnostics object.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-using namespace ento;
-using namespace llvm;
-
-namespace {
-
-/// \brief Simple path diagnostic client used for outputting as diagnostic notes
-/// the sequence of events.
-class TextPathDiagnostics : public PathDiagnosticConsumer {
- const std::string OutputFile;
- DiagnosticsEngine &Diag;
-
-public:
- TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag)
- : OutputFile(output), Diag(diag) {}
-
- void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
- FilesMade *filesMade);
-
- virtual StringRef getName() const {
- return "TextPathDiagnostics";
- }
-
- PathGenerationScheme getGenerationScheme() const { return Minimal; }
- bool supportsLogicalOpControlFlow() const { return true; }
- bool supportsAllBlockEdges() const { return true; }
- virtual bool supportsCrossFileDiagnostics() const { return true; }
-};
-
-} // end anonymous namespace
-
-void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string& out,
- const Preprocessor &PP) {
- C.push_back(new TextPathDiagnostics(out, PP.getDiagnostics()));
-}
-
-void TextPathDiagnostics::FlushDiagnosticsImpl(
- std::vector<const PathDiagnostic *> &Diags,
- FilesMade *) {
- for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
- et = Diags.end(); it != et; ++it) {
- const PathDiagnostic *D = *it;
-
- PathPieces FlatPath = D->path.flatten(/*ShouldFlattenMacros=*/true);
- for (PathPieces::const_iterator I = FlatPath.begin(), E = FlatPath.end();
- I != E; ++I) {
- unsigned diagID =
- Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
- (*I)->getString());
- Diag.Report((*I)->getLocation().asLocation(), diagID);
- }
- }
-}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index d71e528848b0..9efe99767e4c 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -40,6 +40,7 @@
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
@@ -65,23 +66,52 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
-static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string &prefix,
- const Preprocessor &PP) {
+void ento::createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
+ const std::string &prefix,
+ const Preprocessor &PP) {
createHTMLDiagnosticConsumer(AnalyzerOpts, C,
llvm::sys::path::parent_path(prefix), PP);
createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
}
+void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
+ const std::string &Prefix,
+ const clang::Preprocessor &PP) {
+ llvm_unreachable("'text' consumer should be enabled on ClangDiags");
+}
+
namespace {
class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
DiagnosticsEngine &Diag;
+ bool IncludePath;
public:
- ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {}
+ ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag)
+ : Diag(Diag), IncludePath(false) {}
virtual ~ClangDiagPathDiagConsumer() {}
virtual StringRef getName() const { return "ClangDiags"; }
- virtual PathGenerationScheme getGenerationScheme() const { return None; }
+
+ virtual bool supportsLogicalOpControlFlow() const { return true; }
+ virtual bool supportsCrossFileDiagnostics() const { return true; }
+
+ virtual PathGenerationScheme getGenerationScheme() const {
+ return IncludePath ? Minimal : None;
+ }
+
+ void enablePaths() {
+ IncludePath = true;
+ }
+
+ void emitDiag(SourceLocation L, unsigned DiagID,
+ ArrayRef<SourceRange> Ranges) {
+ DiagnosticBuilder DiagBuilder = Diag.Report(L, DiagID);
+
+ for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I) {
+ DiagBuilder << *I;
+ }
+ }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) {
@@ -101,14 +131,20 @@ public:
unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning,
TmpStr);
SourceLocation L = PD->getLocation().asLocation();
- DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag);
+ emitDiag(L, ErrorDiag, PD->path.back()->getRanges());
+
+ if (!IncludePath)
+ continue;
- // Get the ranges from the last point in the path.
- ArrayRef<SourceRange> Ranges = PD->path.back()->getRanges();
+ PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true);
+ for (PathPieces::const_iterator PI = FlatPath.begin(),
+ PE = FlatPath.end();
+ PI != PE; ++PI) {
+ unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note,
+ (*PI)->getString());
- for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end(); I != E; ++I) {
- diagBuilder << *I;
+ SourceLocation NoteLoc = (*PI)->getLocation().asLocation();
+ emitDiag(NoteLoc, NoteID, (*PI)->getRanges());
}
}
}
@@ -185,20 +221,21 @@ public:
void DigestAnalyzerOptions() {
// Create the PathDiagnosticConsumer.
- PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics()));
+ ClangDiagPathDiagConsumer *clangDiags =
+ new ClangDiagPathDiagConsumer(PP.getDiagnostics());
+ PathConsumers.push_back(clangDiags);
+
+ if (Opts->AnalysisDiagOpt == PD_TEXT) {
+ clangDiags->enablePaths();
- if (!OutDir.empty()) {
+ } else if (!OutDir.empty()) {
switch (Opts->AnalysisDiagOpt) {
default:
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\
break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
- } else if (Opts->AnalysisDiagOpt == PD_TEXT) {
- // Create the text client even without a specified output file since
- // it just uses diagnostic notes.
- createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP);
}
// Create the analyzer component creators.
@@ -559,7 +596,7 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
// - System headers: don't run any checks.
SourceManager &SM = Ctx->getSourceManager();
SourceLocation SL = SM.getExpansionLoc(D->getLocation());
- if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) {
+ if (!Opts->AnalyzeAll && !SM.isInMainFile(SL)) {
if (SL.isInvalid() || SM.isInSystemHeader(SL))
return AM_None;
return Mode & ~AM_Path;
@@ -680,15 +717,14 @@ namespace {
class UbigraphViz : public ExplodedNode::Auditor {
OwningPtr<raw_ostream> Out;
- llvm::sys::Path Dir, Filename;
+ std::string Filename;
unsigned Cntr;
typedef llvm::DenseMap<void*,unsigned> VMap;
VMap M;
public:
- UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
- llvm::sys::Path& filename);
+ UbigraphViz(raw_ostream *Out, StringRef Filename);
~UbigraphViz();
@@ -698,28 +734,15 @@ public:
} // end anonymous namespace
static ExplodedNode::Auditor* CreateUbiViz() {
- std::string ErrMsg;
-
- llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
- if (!ErrMsg.empty())
- return 0;
-
- llvm::sys::Path Filename = Dir;
- Filename.appendComponent("llvm_ubi");
- Filename.makeUnique(true,&ErrMsg);
-
- if (!ErrMsg.empty())
- return 0;
-
- llvm::errs() << "Writing '" << Filename.str() << "'.\n";
+ SmallString<128> P;
+ int FD;
+ llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P);
+ llvm::errs() << "Writing '" << P.str() << "'.\n";
OwningPtr<llvm::raw_fd_ostream> Stream;
- Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
-
- if (!ErrMsg.empty())
- return 0;
+ Stream.reset(new llvm::raw_fd_ostream(FD, true));
- return new UbigraphViz(Stream.take(), Dir, Filename);
+ return new UbigraphViz(Stream.take(), P);
}
void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
@@ -756,9 +779,8 @@ void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
<< ", ('arrow','true'), ('oriented', 'true'))\n";
}
-UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
- llvm::sys::Path& filename)
- : Out(out), Dir(dir), Filename(filename), Cntr(0) {
+UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename)
+ : Out(Out), Filename(Filename), Cntr(0) {
*Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
*Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
@@ -769,16 +791,16 @@ UbigraphViz::~UbigraphViz() {
Out.reset(0);
llvm::errs() << "Running 'ubiviz' program... ";
std::string ErrMsg;
- llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
+ std::string Ubiviz = llvm::sys::FindProgramByName("ubiviz");
std::vector<const char*> args;
args.push_back(Ubiviz.c_str());
args.push_back(Filename.c_str());
args.push_back(0);
- if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
+ if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], 0, 0, 0, 0, &ErrMsg)) {
llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
}
- // Delete the directory.
- Dir.eraseFromDisk(true);
+ // Delete the file.
+ llvm::sys::fs::remove(Filename);
}
diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp
index 31dd46599587..a69971e006eb 100644
--- a/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/lib/Tooling/ArgumentsAdjusters.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
namespace tooling {
@@ -23,12 +25,35 @@ void ArgumentsAdjuster::anchor() {
/// Add -fsyntax-only option to the commnand line arguments.
CommandLineArguments
ClangSyntaxOnlyAdjuster::Adjust(const CommandLineArguments &Args) {
- CommandLineArguments AdjustedArgs = Args;
- // FIXME: Remove options that generate output.
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ StringRef Arg = Args[i];
+ // FIXME: Remove options that generate output.
+ if (!Arg.startswith("-fcolor-diagnostics") &&
+ !Arg.startswith("-fdiagnostics-color"))
+ AdjustedArgs.push_back(Args[i]);
+ }
AdjustedArgs.push_back("-fsyntax-only");
return AdjustedArgs;
}
+CommandLineArguments
+ClangStripOutputAdjuster::Adjust(const CommandLineArguments &Args) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ if(!Arg.startswith("-o"))
+ AdjustedArgs.push_back(Args[i]);
+
+ if(Arg == "-o") {
+ // Output is specified as -o foo. Skip the next argument also.
+ ++i;
+ }
+ // Else, the output is specified as -ofoo. Just do nothing.
+ }
+ return AdjustedArgs;
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 99aff9f4e973..cce4816aa675 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -53,7 +53,8 @@ const char *const CommonOptionsParser::HelpMessage =
"\tsuffix of a path in the compile command database.\n"
"\n";
-CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) {
+CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
+ const char *Overview) {
static cl::opt<std::string> BuildPath(
"p", cl::desc("Build path"), cl::Optional);
@@ -62,7 +63,7 @@ CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) {
Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
argv));
- cl::ParseCommandLineOptions(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv, Overview);
SourcePathList = SourcePaths;
if (!Compilations) {
std::string ErrorMessage;
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index b5b99cb7c63e..c962055de795 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -20,6 +20,16 @@
#include "llvm/Support/system_error.h"
#include <sstream>
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Option/Arg.h"
+
namespace clang {
namespace tooling {
@@ -100,6 +110,173 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
+// Helper for recursively searching through a chain of actions and collecting
+// all inputs, direct and indirect, of compile jobs.
+struct CompileJobAnalyzer {
+ void run(const driver::Action *A) {
+ runImpl(A, false);
+ }
+
+ SmallVector<std::string, 2> Inputs;
+
+private:
+
+ void runImpl(const driver::Action *A, bool Collect) {
+ bool CollectChildren = Collect;
+ switch (A->getKind()) {
+ case driver::Action::CompileJobClass:
+ CollectChildren = true;
+ break;
+
+ case driver::Action::InputClass: {
+ if (Collect) {
+ const driver::InputAction *IA = cast<driver::InputAction>(A);
+ Inputs.push_back(IA->getInputArg().getSpelling());
+ }
+ } break;
+
+ default:
+ // Don't care about others
+ ;
+ }
+
+ for (driver::ActionList::const_iterator I = A->begin(), E = A->end();
+ I != E; ++I)
+ runImpl(*I, CollectChildren);
+ }
+};
+
+// Special DiagnosticConsumer that looks for warn_drv_input_file_unused
+// diagnostics from the driver and collects the option strings for those unused
+// options.
+class UnusedInputDiagConsumer : public DiagnosticConsumer {
+public:
+ UnusedInputDiagConsumer() : Other(0) {}
+
+ // Useful for debugging, chain diagnostics to another consumer after
+ // recording for our own purposes.
+ UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) LLVM_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));
+ }
+ if (Other)
+ Other->HandleDiagnostic(DiagLevel, Info);
+ }
+
+ DiagnosticConsumer *Other;
+ SmallVector<std::string, 2> UnusedInputs;
+};
+
+// Unary functor for asking "Given a StringRef S1, does there exist a string
+// S2 in Arr where S1 == S2?"
+struct MatchesAny {
+ MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
+ bool operator() (StringRef S) {
+ for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
+ if (*I == S)
+ return true;
+ return false;
+ }
+private:
+ ArrayRef<std::string> Arr;
+};
+
+/// \brief Strips any positional args and possible argv[0] from a command-line
+/// provided by the user to construct a FixedCompilationDatabase.
+///
+/// FixedCompilationDatabase requires a command line to be in this format as it
+/// constructs the command line for each file by appending the name of the file
+/// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
+/// start of the command line although its value is not important as it's just
+/// ignored by the Driver invoked by the ClangTool using the
+/// FixedCompilationDatabase.
+///
+/// FIXME: This functionality should probably be made available by
+/// clang::driver::Driver although what the interface should look like is not
+/// clear.
+///
+/// \param[in] Args Args as provided by the user.
+/// \return Resulting stripped command line.
+/// \li true if successful.
+/// \li false if \c Args cannot be used for compilation jobs (e.g.
+/// contains an option like -E or -version).
+bool stripPositionalArgs(std::vector<const char *> Args,
+ std::vector<std::string> &Result) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ UnusedInputDiagConsumer DiagClient;
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagClient, false);
+
+ // Neither clang executable nor default image name are required since the
+ // jobs the driver builds will not be executed.
+ OwningPtr<driver::Driver> NewDriver(new driver::Driver(
+ /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
+ /* DefaultImageName= */ "", Diagnostics));
+ NewDriver->setCheckInputsExist(false);
+
+ // This becomes the new argv[0]. The value is actually not important as it
+ // isn't used for invoking Tools.
+ Args.insert(Args.begin(), "clang-tool");
+
+ // By adding -c, we force the driver to treat compilation as the last phase.
+ // It will then issue warnings via Diagnostics about un-used options that
+ // would have been used for linking. If the user provided a compiler name as
+ // the original argv[0], this will be treated as a linker input thanks to
+ // insertng a new argv[0] above. All un-used options get collected by
+ // UnusedInputdiagConsumer and get stripped out later.
+ Args.push_back("-c");
+
+ // Put a dummy C++ file on to ensure there's at least one compile job for the
+ // driver to construct. If the user specified some other argument that
+ // prevents compilation, e.g. -E or something like -version, we may still end
+ // up with no jobs but then this is the user's fault.
+ Args.push_back("placeholder.cpp");
+
+ const OwningPtr<driver::Compilation> Compilation(
+ NewDriver->BuildCompilation(Args));
+
+ const driver::JobList &Jobs = Compilation->getJobs();
+
+ CompileJobAnalyzer CompileAnalyzer;
+
+ for (driver::JobList::const_iterator I = Jobs.begin(), E = Jobs.end(); I != E;
+ ++I) {
+ if ((*I)->getKind() == driver::Job::CommandClass) {
+ const driver::Command *Cmd = cast<driver::Command>(*I);
+ // 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)
+ CompileAnalyzer.run(&Cmd->getSource());
+ }
+ }
+
+ if (CompileAnalyzer.Inputs.empty()) {
+ // No compile jobs found.
+ // FIXME: Emit a warning of some kind?
+ return false;
+ }
+
+ // Remove all compilation input files from the command line. This is
+ // necessary so that getCompileCommands() can construct a command line for
+ // each file.
+ std::vector<const char *>::iterator End = std::remove_if(
+ Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
+
+ // Remove all inputs deemed unused for compilation.
+ End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
+
+ // Remove the -c add above as well. It will be at the end right now.
+ --End;
+
+ Result = std::vector<std::string>(Args.begin() + 1, End);
+ return true;
+}
+
FixedCompilationDatabase *
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
const char **Argv,
@@ -107,9 +284,13 @@ FixedCompilationDatabase::loadFromCommandLine(int &Argc,
const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
return NULL;
- std::vector<std::string> CommandLine(DoubleDash + 1, Argv + Argc);
+ std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
Argc = DoubleDash - Argv;
- return new FixedCompilationDatabase(Directory, CommandLine);
+
+ std::vector<std::string> StrippedArgs;
+ if (!stripPositionalArgs(CommandLine, StrippedArgs))
+ return 0;
+ return new FixedCompilationDatabase(Directory, StrippedArgs);
}
FixedCompilationDatabase::
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index 5eb4bb9e49d6..89979a84f940 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -14,7 +14,7 @@
#include "clang/Tooling/FileMatchTrie.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 254b069952da..1e33b418af4e 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -117,8 +117,6 @@ std::vector<std::string> unescapeCommandLine(
return parser.parse();
}
-} // end namespace
-
class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
virtual CompilationDatabase *loadFromDirectory(
StringRef Directory, std::string &ErrorMessage) {
@@ -132,6 +130,8 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
}
};
+} // end namespace
+
// Register the JSONCompilationDatabasePlugin with the
// CompilationDatabasePluginRegistry using this statically initialized variable.
static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index d8440d639d06..e165c12e0009 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -19,6 +19,8 @@
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace tooling {
@@ -26,12 +28,12 @@ namespace tooling {
static const char * const InvalidLocation = "";
Replacement::Replacement()
- : FilePath(InvalidLocation), Offset(0), Length(0) {}
+ : FilePath(InvalidLocation) {}
-Replacement::Replacement(StringRef FilePath, unsigned Offset,
- unsigned Length, StringRef ReplacementText)
- : FilePath(FilePath), Offset(Offset),
- Length(Length), ReplacementText(ReplacementText) {}
+Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
+ StringRef ReplacementText)
+ : FilePath(FilePath), ReplacementRange(Offset, Length),
+ ReplacementText(ReplacementText) {}
Replacement::Replacement(SourceManager &Sources, SourceLocation Start,
unsigned Length, StringRef ReplacementText) {
@@ -62,11 +64,12 @@ bool Replacement::apply(Rewriter &Rewrite) const {
// the remapping API is not public in the RewriteBuffer.
const SourceLocation Start =
SM.getLocForStartOfFile(ID).
- getLocWithOffset(Offset);
+ getLocWithOffset(ReplacementRange.getOffset());
// ReplaceText returns false on success.
// ReplaceText only fails if the source location is not a file location, in
// which case we already returned false earlier.
- bool RewriteSucceeded = !Rewrite.ReplaceText(Start, Length, ReplacementText);
+ bool RewriteSucceeded = !Rewrite.ReplaceText(
+ Start, ReplacementRange.getLength(), ReplacementText);
assert(RewriteSucceeded);
return RewriteSucceeded;
}
@@ -74,17 +77,26 @@ bool Replacement::apply(Rewriter &Rewrite) const {
std::string Replacement::toString() const {
std::string result;
llvm::raw_string_ostream stream(result);
- stream << FilePath << ": " << Offset << ":+" << Length
- << ":\"" << ReplacementText << "\"";
+ stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
+ << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
return result;
}
-bool Replacement::Less::operator()(const Replacement &R1,
- const Replacement &R2) const {
- if (R1.FilePath != R2.FilePath) return R1.FilePath < R2.FilePath;
- if (R1.Offset != R2.Offset) return R1.Offset < R2.Offset;
- if (R1.Length != R2.Length) return R1.Length < R2.Length;
- return R1.ReplacementText < R2.ReplacementText;
+bool operator<(const Replacement &LHS, const Replacement &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+ if (LHS.getLength() != RHS.getLength())
+ return LHS.getLength() < RHS.getLength();
+ if (LHS.getFilePath() != RHS.getFilePath())
+ return LHS.getFilePath() < RHS.getFilePath();
+ return LHS.getReplacementText() < RHS.getReplacementText();
+}
+
+bool operator==(const Replacement &LHS, const Replacement &RHS) {
+ return LHS.getOffset() == RHS.getOffset() &&
+ LHS.getLength() == RHS.getLength() &&
+ LHS.getFilePath() == RHS.getFilePath() &&
+ LHS.getReplacementText() == RHS.getReplacementText();
}
void Replacement::setFromSourceLocation(SourceManager &Sources,
@@ -93,9 +105,16 @@ void Replacement::setFromSourceLocation(SourceManager &Sources,
const std::pair<FileID, unsigned> DecomposedLocation =
Sources.getDecomposedLoc(Start);
const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
- this->FilePath = Entry != NULL ? Entry->getName() : InvalidLocation;
- this->Offset = DecomposedLocation.second;
- this->Length = Length;
+ if (Entry != NULL) {
+ // Make FilePath absolute so replacements can be applied correctly when
+ // relative paths for files are used.
+ llvm::SmallString<256> FilePath(Entry->getName());
+ llvm::error_code EC = llvm::sys::fs::make_absolute(FilePath);
+ this->FilePath = EC ? FilePath.c_str() : Entry->getName();
+ } else {
+ this->FilePath = InvalidLocation;
+ }
+ this->ReplacementRange = Range(DecomposedLocation.second, Length);
this->ReplacementText = ReplacementText;
}
@@ -121,7 +140,7 @@ void Replacement::setFromSourceRange(SourceManager &Sources,
getRangeSize(Sources, Range), ReplacementText);
}
-bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite) {
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
bool Result = true;
for (Replacements::const_iterator I = Replaces.begin(),
E = Replaces.end();
@@ -135,6 +154,121 @@ bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite) {
return Result;
}
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+ Rewriter &Rewrite) {
+ bool Result = true;
+ for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->isApplicable()) {
+ Result = I->apply(Rewrite) && Result;
+ } else {
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ Diagnostics.setClient(new TextDiagnosticPrinter(
+ llvm::outs(), &Diagnostics.getDiagnosticOptions()));
+ SourceManager SourceMgr(Diagnostics, Files);
+ Rewriter Rewrite(SourceMgr, LangOptions());
+ llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
+ const clang::FileEntry *Entry =
+ Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(Entry, Buf);
+ FileID ID =
+ SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+ for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
+ I != E; ++I) {
+ Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+ I->getReplacementText());
+ if (!Replace.apply(Rewrite))
+ return "";
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+}
+
+unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
+ unsigned NewPosition = Position;
+ for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+ ++I) {
+ if (I->getOffset() >= Position)
+ break;
+ if (I->getOffset() + I->getLength() > Position)
+ NewPosition += I->getOffset() + I->getLength() - Position;
+ NewPosition += I->getReplacementText().size() - I->getLength();
+ }
+ return NewPosition;
+}
+
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+ unsigned Position) {
+ unsigned NewPosition = Position;
+ for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->getOffset() >= Position)
+ break;
+ if (I->getOffset() + I->getLength() > Position)
+ NewPosition += I->getOffset() + I->getLength() - Position;
+ NewPosition += I->getReplacementText().size() - I->getLength();
+ }
+ return NewPosition;
+}
+
+void deduplicate(std::vector<Replacement> &Replaces,
+ std::vector<Range> &Conflicts) {
+ if (Replaces.empty())
+ return;
+
+ // Deduplicate
+ std::sort(Replaces.begin(), Replaces.end());
+ std::vector<Replacement>::iterator End =
+ std::unique(Replaces.begin(), Replaces.end());
+ Replaces.erase(End, Replaces.end());
+
+ // Detect conflicts
+ Range ConflictRange(Replaces.front().getOffset(),
+ Replaces.front().getLength());
+ unsigned ConflictStart = 0;
+ unsigned ConflictLength = 1;
+ for (unsigned i = 1; i < Replaces.size(); ++i) {
+ Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
+ if (ConflictRange.overlapsWith(Current)) {
+ // Extend conflicted range
+ ConflictRange = Range(ConflictRange.getOffset(),
+ std::max(ConflictRange.getLength(),
+ Current.getOffset() + Current.getLength() -
+ ConflictRange.getOffset()));
+ ++ConflictLength;
+ } else {
+ if (ConflictLength > 1)
+ Conflicts.push_back(Range(ConflictStart, ConflictLength));
+ ConflictRange = Current;
+ ConflictStart = i;
+ ConflictLength = 1;
+ }
+ }
+
+ if (ConflictLength > 1)
+ Conflicts.push_back(Range(ConflictStart, ConflictLength));
+}
+
+
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
: ClangTool(Compilations, SourcePaths) {}
@@ -167,23 +301,7 @@ bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
}
int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
- for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
- E = Rewrite.buffer_end();
- I != E; ++I) {
- // FIXME: This code is copied from the FixItRewriter.cpp - I think it should
- // go into directly into Rewriter (there we also have the Diagnostics to
- // handle the error cases better).
- const FileEntry *Entry =
- Rewrite.getSourceMgr().getFileEntryForID(I->first);
- std::string ErrorInfo;
- llvm::raw_fd_ostream FileStream(
- Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
- if (!ErrorInfo.empty())
- return 1;
- I->second.write(FileStream);
- FileStream.flush();
- }
- return 0;
+ return Rewrite.overwriteChangedFiles() ? 1 : 0;
}
} // end namespace tooling
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 52855f657f64..a58854d1af30 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -13,15 +13,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Tooling.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
@@ -37,6 +40,8 @@
namespace clang {
namespace tooling {
+ToolAction::~ToolAction() {}
+
FrontendActionFactory::~FrontendActionFactory() {}
// FIXME: This file contains structural duplication with other parts of the
@@ -57,7 +62,7 @@ static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
///
/// Returns NULL on error.
-static const clang::driver::ArgStringList *getCC1Arguments(
+static const llvm::opt::ArgStringList *getCC1Arguments(
clang::DiagnosticsEngine *Diagnostics,
clang::driver::Compilation *Compilation) {
// We expect to get back exactly one Command job, if we didn't something
@@ -66,7 +71,7 @@ static const clang::driver::ArgStringList *getCC1Arguments(
if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
SmallString<256> error_msg;
llvm::raw_svector_ostream error_stream(error_msg);
- Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
+ Jobs.Print(error_stream, "; ", true);
Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
<< error_stream.str();
return NULL;
@@ -86,13 +91,14 @@ static const clang::driver::ArgStringList *getCC1Arguments(
/// \brief Returns a clang build invocation initialized from the CC1 flags.
static clang::CompilerInvocation *newInvocation(
clang::DiagnosticsEngine *Diagnostics,
- const clang::driver::ArgStringList &CC1Args) {
+ const llvm::opt::ArgStringList &CC1Args) {
assert(!CC1Args.empty() && "Must at least contain the program name!");
clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
clang::CompilerInvocation::CreateFromArgs(
*Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
*Diagnostics);
Invocation->getFrontendOpts().DisableFree = false;
+ Invocation->getCodeGenOpts().DisableFree = false;
return Invocation;
}
@@ -102,18 +108,26 @@ bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
ToolAction, Code, std::vector<std::string>(), FileName);
}
+static std::vector<std::string>
+getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs,
+ StringRef FileName) {
+ std::vector<std::string> Args;
+ Args.push_back("clang-tool");
+ Args.push_back("-fsyntax-only");
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ Args.push_back(FileName.str());
+ return Args;
+}
+
bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
const std::vector<std::string> &Args,
const Twine &FileName) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
- std::vector<std::string> Commands;
- Commands.push_back("clang-tool");
- Commands.push_back("-fsyntax-only");
- Commands.insert(Commands.end(), Args.begin(), Args.end());
- Commands.push_back(FileNameRef.data());
- FileManager Files((FileSystemOptions()));
- ToolInvocation Invocation(Commands, ToolAction, &Files);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions()));
+ ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,
+ Files.getPtr());
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
@@ -122,31 +136,56 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
}
std::string getAbsolutePath(StringRef File) {
- SmallString<1024> BaseDirectory;
- if (const char *PWD = ::getenv("PWD"))
- BaseDirectory = PWD;
- else
- llvm::sys::fs::current_path(BaseDirectory);
- SmallString<1024> PathStorage;
- if (llvm::sys::path::is_absolute(File)) {
- llvm::sys::path::native(File, PathStorage);
- return PathStorage.str();
- }
StringRef RelativePath(File);
// FIXME: Should '.\\' be accepted on Win32?
if (RelativePath.startswith("./")) {
RelativePath = RelativePath.substr(strlen("./"));
}
- SmallString<1024> AbsolutePath(BaseDirectory);
- llvm::sys::path::append(AbsolutePath, RelativePath);
- llvm::sys::path::native(Twine(AbsolutePath), PathStorage);
- return PathStorage.str();
+
+ SmallString<1024> AbsolutePath = RelativePath;
+ llvm::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
+ assert(!EC);
+ (void)EC;
+ llvm::sys::path::native(AbsolutePath);
+ return AbsolutePath.str();
}
-ToolInvocation::ToolInvocation(
- ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,
- FileManager *Files)
- : CommandLine(CommandLine.vec()), ToolAction(ToolAction), Files(Files) {
+namespace {
+
+class SingleFrontendActionFactory : public FrontendActionFactory {
+ FrontendAction *Action;
+
+public:
+ SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}
+
+ FrontendAction *create() { return Action; }
+};
+
+}
+
+ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,
+ ToolAction *Action, FileManager *Files)
+ : CommandLine(CommandLine.vec()),
+ Action(Action),
+ OwnsAction(false),
+ Files(Files),
+ DiagConsumer(NULL) {}
+
+ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,
+ FrontendAction *FAction, FileManager *Files)
+ : CommandLine(CommandLine.vec()),
+ Action(new SingleFrontendActionFactory(FAction)),
+ OwnsAction(true),
+ Files(Files),
+ DiagConsumer(NULL) {}
+
+ToolInvocation::~ToolInvocation() {
+ if (OwnsAction)
+ delete Action;
+}
+
+void ToolInvocation::setDiagnosticConsumer(DiagnosticConsumer *D) {
+ DiagConsumer = D;
}
void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
@@ -164,8 +203,8 @@ bool ToolInvocation::run() {
TextDiagnosticPrinter DiagnosticPrinter(
llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
- &*DiagOpts, &DiagnosticPrinter, false);
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
const OwningPtr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));
@@ -173,13 +212,21 @@ bool ToolInvocation::run() {
Driver->setCheckInputsExist(false);
const OwningPtr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
- const clang::driver::ArgStringList *const CC1Args = getCC1Arguments(
+ const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
if (CC1Args == NULL) {
return false;
}
OwningPtr<clang::CompilerInvocation> Invocation(
newInvocation(&Diagnostics, *CC1Args));
+ for (llvm::StringMap<StringRef>::const_iterator
+ It = MappedFileContents.begin(), End = MappedFileContents.end();
+ It != End; ++It) {
+ // Inject the code as the given file name into the preprocessor options.
+ const llvm::MemoryBuffer *Input =
+ llvm::MemoryBuffer::getMemBuffer(It->getValue());
+ Invocation->getPreprocessorOpts().addRemappedFile(It->getKey(), Input);
+ }
return runInvocation(BinaryName, Compilation.get(), Invocation.take());
}
@@ -190,54 +237,44 @@ bool ToolInvocation::runInvocation(
// Show the invocation, with -v.
if (Invocation->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang Invocation:\n";
- Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
+ Compilation->getJobs().Print(llvm::errs(), "\n", true);
llvm::errs() << "\n";
}
+ return Action->runInvocation(Invocation, Files, DiagConsumer);
+}
+
+bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
+ FileManager *Files,
+ DiagnosticConsumer *DiagConsumer) {
// Create a compiler instance to handle the actual work.
clang::CompilerInstance Compiler;
Compiler.setInvocation(Invocation);
Compiler.setFileManager(Files);
- // FIXME: What about LangOpts?
- // ToolAction can have lifetime requirements for Compiler or its members, and
- // we need to ensure it's deleted earlier than Compiler. So we pass it to an
- // OwningPtr declared after the Compiler variable.
- OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());
+ // The FrontendAction can have lifetime requirements for Compiler or its
+ // members, and we need to ensure it's deleted earlier than Compiler. So we
+ // pass it to an OwningPtr declared after the Compiler variable.
+ OwningPtr<FrontendAction> ScopedToolAction(create());
// Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics();
+ Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
if (!Compiler.hasDiagnostics())
return false;
Compiler.createSourceManager(*Files);
- addFileMappingsTo(Compiler.getSourceManager());
const bool Success = Compiler.ExecuteAction(*ScopedToolAction);
- Compiler.resetAndLeakFileManager();
Files->clearStatCaches();
return Success;
}
-void ToolInvocation::addFileMappingsTo(SourceManager &Sources) {
- for (llvm::StringMap<StringRef>::const_iterator
- It = MappedFileContents.begin(), End = MappedFileContents.end();
- It != End; ++It) {
- // Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer *Input =
- llvm::MemoryBuffer::getMemBuffer(It->getValue());
- // FIXME: figure out what '0' stands for.
- const FileEntry *FromFile = Files->getVirtualFile(
- It->getKey(), Input->getBufferSize(), 0);
- Sources.overrideFileContents(FromFile, Input);
- }
-}
-
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
- : Files((FileSystemOptions())),
- ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) {
+ : Files(new FileManager(FileSystemOptions())), DiagConsumer(NULL) {
+ ArgsAdjusters.push_back(new ClangStripOutputAdjuster());
+ ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster());
for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
@@ -259,15 +296,30 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
}
}
+void ClangTool::setDiagnosticConsumer(DiagnosticConsumer *D) {
+ DiagConsumer = D;
+}
+
void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
MappedFileContents.push_back(std::make_pair(FilePath, Content));
}
void ClangTool::setArgumentsAdjuster(ArgumentsAdjuster *Adjuster) {
- ArgsAdjuster.reset(Adjuster);
+ clearArgumentsAdjusters();
+ appendArgumentsAdjuster(Adjuster);
+}
+
+void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster *Adjuster) {
+ ArgsAdjusters.push_back(Adjuster);
+}
+
+void ClangTool::clearArgumentsAdjusters() {
+ for (unsigned I = 0, E = ArgsAdjusters.size(); I != E; ++I)
+ delete ArgsAdjusters[I];
+ ArgsAdjusters.clear();
}
-int ClangTool::run(FrontendActionFactory *ActionFactory) {
+int ClangTool::run(ToolAction *Action) {
// Exists solely for the purpose of lookup of the resource path.
// This just needs to be some symbol in the binary.
static int StaticSymbol;
@@ -277,7 +329,7 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
// first argument, thus allowing ClangTool and runToolOnCode to just
// pass in made-up names here. Make sure this works on other platforms.
std::string MainExecutable =
- llvm::sys::Path::GetMainExecutable("clang_tool", &StaticSymbol).str();
+ llvm::sys::fs::getMainExecutable("clang_tool", &StaticSymbol);
bool ProcessingFailed = false;
for (unsigned I = 0; I < CompileCommands.size(); ++I) {
@@ -292,8 +344,9 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
if (chdir(CompileCommands[I].second.Directory.c_str()))
llvm::report_fatal_error("Cannot chdir into \"" +
CompileCommands[I].second.Directory + "\n!");
- std::vector<std::string> CommandLine =
- ArgsAdjuster->Adjust(CompileCommands[I].second.CommandLine);
+ std::vector<std::string> CommandLine = CompileCommands[I].second.CommandLine;
+ for (unsigned I = 0, E = ArgsAdjusters.size(); I != E; ++I)
+ CommandLine = ArgsAdjusters[I]->Adjust(CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
// FIXME: We need a callback mechanism for the tool writer to output a
@@ -301,7 +354,8 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
DEBUG({
llvm::dbgs() << "Processing: " << File << ".\n";
});
- ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files);
+ ToolInvocation Invocation(CommandLine, Action, Files.getPtr());
+ Invocation.setDiagnosticConsumer(DiagConsumer);
for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {
Invocation.mapVirtualFile(MappedFileContents[I].first,
MappedFileContents[I].second);
@@ -315,5 +369,59 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
return ProcessingFailed ? 1 : 0;
}
+namespace {
+
+class ASTBuilderAction : public ToolAction {
+ std::vector<ASTUnit *> &ASTs;
+
+public:
+ ASTBuilderAction(std::vector<ASTUnit *> &ASTs) : ASTs(ASTs) {}
+
+ bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
+ DiagnosticConsumer *DiagConsumer) {
+ // FIXME: This should use the provided FileManager.
+ ASTUnit *AST = ASTUnit::LoadFromCompilerInvocation(
+ Invocation, CompilerInstance::createDiagnostics(
+ &Invocation->getDiagnosticOpts(), DiagConsumer,
+ /*ShouldOwnClient=*/false));
+ if (!AST)
+ return false;
+
+ ASTs.push_back(AST);
+ return true;
+ }
+};
+
+}
+
+int ClangTool::buildASTs(std::vector<ASTUnit *> &ASTs) {
+ ASTBuilderAction Action(ASTs);
+ return run(&Action);
+}
+
+ASTUnit *buildASTFromCode(const Twine &Code, const Twine &FileName) {
+ return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName);
+}
+
+ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName) {
+ SmallString<16> FileNameStorage;
+ StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
+
+ std::vector<ASTUnit *> ASTs;
+ ASTBuilderAction Action(ASTs);
+ ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action, 0);
+
+ SmallString<1024> CodeStorage;
+ Invocation.mapVirtualFile(FileNameRef,
+ Code.toNullTerminatedStringRef(CodeStorage));
+ if (!Invocation.run())
+ return 0;
+
+ assert(ASTs.size() == 1);
+ return ASTs[0];
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index e946de21a1dc..c6f38b2fc352 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -23,7 +23,13 @@ ResourceDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/$(CLANG_VERSION)
PROJ_resources := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)
ResourceLibDir := $(ResourceDir)/lib
+ResourceIncludeDir := $(ResourceDir)/include
PROJ_resources_lib := $(PROJ_resources)/lib
+PROJ_resources_include := $(PROJ_resources)/include
+
+# Initialize a variable to use for extra flags to pass to the
+# compiler-rt make process.
+COMPILERRT_MAKE_FLAGS :=
# Expect compiler-rt to be in llvm/projects/compiler-rt
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
@@ -72,12 +78,29 @@ ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
# support.
RuntimeDirs :=
ifeq ($(OS),Darwin)
-RuntimeDirs += darwin
+RuntimeDirs += darwin darwin_embedded
RuntimeLibrary.darwin.Configs := \
eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \
- asan_osx.a asan_osx_dynamic.dylib \
+ asan_osx_dynamic.dylib \
profile_osx.a profile_ios.a \
ubsan_osx.a
+RuntimeLibrary.darwin_embedded.Configs := \
+ soft_static.a hard_static.a soft_pic.a hard_pic.a
+
+# Support building compiler-rt with relocatable SDKs.
+#
+# This will cause make to put SDKROOT in the environment, and since we
+# are using the built Clang to build compiler-rt, it to pick up that
+# location as the default value for the include system root.
+ACTIVE_SDK_PATH := $(shell xcrun --show-sdk-path 2> /dev/null)
+ifneq ($(ACTIVE_SDK_PATH),)
+COMPILERRT_MAKE_FLAGS := SDKROOT=$(ACTIVE_SDK_PATH)
+endif
+IOSSIM_SDK_PATH := $(shell xcrun --show-sdk-path -sdk iphonesimulator 2> /dev/null)
+ifneq ($(IOSSIM_SDK_PATH),)
+RuntimeLibrary.darwin.Configs += asan_iossim_dynamic.dylib
+endif
+
endif
# On Linux, include a library which has all the runtime functions.
@@ -96,17 +119,21 @@ TryCompile = \
$(1) $$cflags $(2) -o /dev/null > /dev/null 2> /dev/null ; \
echo $$?)
-# We currently only try to generate runtime libraries on x86.
-ifeq ($(ARCH),x86)
-RuntimeLibrary.linux.Configs += \
+# We try to build 32-bit runtimes both on 32-bit hosts and 64-bit hosts.
+Runtime32BitConfigs = \
full-i386.a profile-i386.a san-i386.a asan-i386.a ubsan-i386.a \
ubsan_cxx-i386.a
+
+# We currently only try to generate runtime libraries on x86.
+ifeq ($(ARCH),x86)
+RuntimeLibrary.linux.Configs += $(Runtime32BitConfigs)
endif
ifeq ($(ARCH),x86_64)
RuntimeLibrary.linux.Configs += \
full-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \
- tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a
+ tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a \
+ dfsan-x86_64.a lsan-x86_64.a
# We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them
# to the list of runtime libraries to make
# "clang -fsanitize=(address|undefined) -m32" work.
@@ -114,8 +141,7 @@ RuntimeLibrary.linux.Configs += \
# executable.
test_source = $(LLVM_SRC_ROOT)/tools/clang/runtime/compiler-rt/clang_linux_test_input.c
ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-m32),0)
-RuntimeLibrary.linux.Configs += san-i386.a asan-i386.a ubsan-i386.a \
- ubsan_cxx-i386.a
+RuntimeLibrary.linux.Configs += $(Runtime32BitConfigs)
endif
ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
RuntimeLibrary.linux.Configs += asan-arm-android.so
@@ -139,18 +165,28 @@ BuildRuntimeLibraries:
ProjObjRoot=$(PROJ_OBJ_DIR) \
CC="$(ToolDir)/clang" \
LLVM_ANDROID_TOOLCHAIN_DIR="$(LLVM_ANDROID_TOOLCHAIN_DIR)" \
+ $(COMPILERRT_MAKE_FLAGS) \
$(RuntimeDirs:%=clang_%)
.PHONY: BuildRuntimeLibraries
CleanRuntimeLibraries:
$(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
ProjObjRoot=$(PROJ_OBJ_DIR) \
+ $(COMPILERRT_MAKE_FLAGS) \
clean
.PHONY: CleanRuntimeLibraries
+RuntimeHeader: $(ResourceIncludeDir)/sanitizer
$(PROJ_resources_lib):
$(Verb) $(MKDIR) $@
+$(ResourceIncludeDir):
+ $(Verb) $(MKDIR) $@
+
+$(ResourceIncludeDir)/sanitizer: $(ResourceIncludeDir)
+ $(Verb) $(MKDIR) $@
+ $(Verb) cp $(COMPILERRT_SRC_ROOT)/include/sanitizer/*.h $@
+
# Expand rules for copying/installing each individual library. We can't use
# implicit rules here because we need to match against multiple things.
define RuntimeLibraryTemplate
@@ -207,9 +243,21 @@ RuntimeLibraryInstall.$1: \
endef
$(foreach lib,$(RuntimeDirs), $(eval $(call RuntimeLibraryTemplate,$(lib))))
+$(PROJ_resources_include):
+ $(Verb) $(MKDIR) $@
+
+$(PROJ_resources_include)/sanitizer: $(ResourceIncludeDir)/sanitizer $(PROJ_resources_include)
+ $(Verb) $(MKDIR) $@
+ $(Echo) Installing compiler runtime headers
+ $(Verb) $(DataInstall) $(ResourceIncludeDir)/sanitizer/* \
+ $(PROJ_resources_include)/sanitizer
+
+RuntimeHeaderInstall: $(PROJ_resources_include)/sanitizer
+.PHONY: RuntimeHeaderInstall
+
# Hook into the standard Makefile rules.
-all-local:: $(RuntimeDirs:%=RuntimeLibrary.%)
-install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
+all-local:: $(RuntimeDirs:%=RuntimeLibrary.%) RuntimeHeader
+install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%) RuntimeHeaderInstall
clean-local:: CleanRuntimeLibraries
endif
diff --git a/runtime/libcxx/Makefile b/runtime/libcxx/Makefile
index 42322dc8a3ad..a7df868305cb 100644
--- a/runtime/libcxx/Makefile
+++ b/runtime/libcxx/Makefile
@@ -15,7 +15,7 @@
CLANG_LEVEL := ../..
include $(CLANG_LEVEL)/Makefile
-PROJ_libcxx_hdrs := $(DESTDIR)$(PROJ_prefix)/lib
+PROJ_libcxx_hdrs := $(DESTDIR)$(PROJ_prefix)/include
# Expect libcxx to be in llvm/projects/libcxx
LIBCXX_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/libcxx
diff --git a/test/.clang-format b/test/.clang-format
new file mode 100644
index 000000000000..4799b66f3e9a
--- /dev/null
+++ b/test/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+ColumnLimit: 0
diff --git a/test/ARCMT/Inputs/test1.m.in b/test/ARCMT/Inputs/test1.m.in
index 8416a8896569..44a3c4cf3d93 100644
--- a/test/ARCMT/Inputs/test1.m.in
+++ b/test/ARCMT/Inputs/test1.m.in
@@ -4,3 +4,13 @@
void test1(id p) {
[p release];
}
+
+@interface Test2
+@property (strong) id prop;
+@end
+
+@implementation Test2
+-(id)init {
+ _prop = 0;
+}
+@end
diff --git a/test/ARCMT/Inputs/test1.m.in.result b/test/ARCMT/Inputs/test1.m.in.result
index f351fe6c8355..1db9bf7ad65c 100644
--- a/test/ARCMT/Inputs/test1.m.in.result
+++ b/test/ARCMT/Inputs/test1.m.in.result
@@ -3,3 +3,13 @@
void test1(id p) {
}
+
+@interface Test2
+@property (strong) id prop;
+@end
+
+@implementation Test2
+-(id)init {
+ _prop = 0;
+}
+@end
diff --git a/test/ARCMT/checking-in-arc.m b/test/ARCMT/checking-in-arc.m
new file mode 100644
index 000000000000..40d9b1684576
--- /dev/null
+++ b/test/ARCMT/checking-in-arc.m
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -arcmt-check -fobjc-arc -fobjc-runtime=macosx-10.8.0 -triple x86_64-apple-darwin12 -fblocks -Werror %s
+// DISABLE: mingw32
+
+#if __has_feature(objc_arc)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
+
+typedef int BOOL;
+typedef unsigned NSUInteger;
+
+@protocol NSObject
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+@end
+
+@interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+@end
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+@class NSString;
+
+@interface Test : NSObject
+@property (weak) NSString *weakProperty;
+@end
+
+@implementation Test
+@end
+
+#if ! __has_feature(objc_arc)
+#error This file must be compiled with ARC (set -fobjc_arc flag on file)
+#endif
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
index b06f4a731dc7..a550633171d1 100644
--- a/test/ARCMT/checking.m
+++ b/test/ARCMT/checking.m
@@ -333,7 +333,9 @@ void rdar9504750(id p) {
}
@end
-@interface Test10 : NSObject
+@interface Test10 : NSObject {
+ CFStringRef cfstr;
+}
@property (retain) id prop;
-(void)foo;
@end
@@ -342,3 +344,13 @@ void test(Test10 *x) {
x.prop = ^{ [x foo]; }; // expected-warning {{likely to lead to a retain cycle}} \
// expected-note {{retained by the captured object}}
}
+
+@implementation Test10
+-(void)foo {
+ ^{
+ NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+ };
+}
+@end
diff --git a/test/ARCMT/driver-migrate.m b/test/ARCMT/driver-migrate.m
index a912ad95b156..b1e419ae6fb3 100644
--- a/test/ARCMT/driver-migrate.m
+++ b/test/ARCMT/driver-migrate.m
@@ -10,3 +10,6 @@
// LINK-NOT: {{ld(.exe)?"}}
// LINK: {{touch(.exe)?"}}
+
+// RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only -fno-objc-arc %s 2>&1 | FileCheck -check-prefix=CHECK-NOARC %s
+// CHECK-NOARC-NOT: argument unused during compilation
diff --git a/test/ARCMT/lit.local.cfg b/test/ARCMT/lit.local.cfg
new file mode 100644
index 000000000000..4b28d6dff8a3
--- /dev/null
+++ b/test/ARCMT/lit.local.cfg
@@ -0,0 +1,2 @@
+if config.root.clang_arcmt == 0:
+ config.unsupported = True
diff --git a/test/ARCMT/objcmt-arc-cf-annotations.m b/test/ARCMT/objcmt-arc-cf-annotations.m
new file mode 100644
index 000000000000..9772825b2934
--- /dev/null
+++ b/test/ARCMT/objcmt-arc-cf-annotations.m
@@ -0,0 +1,2047 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-annotation -objcmt-migrate-instancetype -objcmt-migrate-readwrite-property -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+
+#ifndef CF_IMPLICIT_BRIDGING_ENABLED
+#if __has_feature(arc_cf_code_audited)
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+#else
+#define CF_IMPLICIT_BRIDGING_ENABLED
+#endif
+#endif
+
+#ifndef CF_IMPLICIT_BRIDGING_DISABLED
+#if __has_feature(arc_cf_code_audited)
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+#else
+#define CF_IMPLICIT_BRIDGING_DISABLED
+#endif
+#endif
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+// #include <IOKit/IOKitLib.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef CFIndex CFByteOrder;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+extern CFTypeRef CFMakeCollectable(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+enum {
+kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+- (NSString *)description;
+- (id)init;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
++ (id)new;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end
+@interface NSNumber : NSValue
+- (char)charValue;
+- (id)initWithInt:(int)value;
++ (NSNumber *)numberWithInt:(int)value;
+@end
+@class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithArray:(NSArray *)array;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
+@end typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
+typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator );
+io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing );
+kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); // expected-note {{'IOServiceAddNotification' declared here}}
+kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification );
+CFMutableDictionaryRef IOServiceMatching( const char * name );
+CFMutableDictionaryRef IOServiceNameMatching( const char * name );
+CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID );
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+@interface NSTask : NSObject - (id)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+@end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end enum {
+ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+ space, const CGFloat components[], const CGFloat locations[], size_t count);
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+ CFArrayRef colors, const CGFloat locations[]);
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+ CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+ CGGradientDrawingOptions options);
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
+@interface NSMutableArray : NSObject
+- (void)addObject:(id)object;
++ (id)array;
+@end
+
+// This is how NSMakeCollectable is declared in the OS X 10.8 headers.
+id NSMakeCollectable(CFTypeRef __attribute__((cf_consumed))) __attribute__((ns_returns_retained));
+
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern
+void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryUUID, CFUUIDRef typeUUID);
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+CFAbsoluteTime f1() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
+ return t;
+}
+
+CFAbsoluteTime f2() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
+ return t;
+}
+
+
+NSDate* global_x;
+
+// Test to see if we supresss an error when we store the pointer
+// to a global.
+
+CFAbsoluteTime f3() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ global_x = (NSDate*) date;
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ return t;
+}
+
+//---------------------------------------------------------------------------
+// Test case 'f4' differs for region store and basic store. See
+// retain-release-region-store.m and retain-release-basic-store.m.
+//---------------------------------------------------------------------------
+
+// Test a leak.
+
+CFAbsoluteTime f5(int x) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // expected-warning{{leak}}
+
+ if (x)
+ CFRelease(date);
+
+ return t;
+}
+
+// Test a leak involving the return.
+
+CFDateRef f6(int x) {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
+ CFRetain(date);
+ date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning {{leak}}
+ return date;
+}
+
+// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and
+// has the word create.
+CFDateRef MyDateCreate();
+
+CFDateRef f8() {
+ CFDateRef date = MyDateCreate(); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+__attribute__((cf_returns_retained)) CFDateRef f9() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // no-warning
+ int *p = 0;
+ // When allocations fail, CFDateCreate can return null.
+ if (!date) *p = 1; // expected-warning{{null}}
+ return date;
+}
+
+// Handle DiskArbitration API:
+//
+// http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/DiscArbitrationFramework/
+//
+void f10(io_service_t media, DADiskRef d, CFStringRef s) {
+ DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, 0, "hello"); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, 0, media); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ CFDictionaryRef dict = DADiskCopyDescription(d); // expected-warning{{leak}}
+ if (dict) NSLog(@"ok");
+
+ disk = DADiskCopyWholeDisk(d); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault, // expected-warning{{leak}}
+ kDAReturnSuccess, s);
+ if (dissenter) NSLog(@"ok");
+
+ DASessionRef session = DASessionCreate(kCFAllocatorDefault); // expected-warning{{leak}}
+ if (session) NSLog(@"ok");
+}
+
+// Test retain/release checker with CFString and CFMutableArray.
+void f11() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+
+ // Create a string.
+ CFStringRef s1 = CFStringCreateWithCString(0, "hello world",
+ kCFStringEncodingUTF8);
+
+ // Add the string to the array.
+ CFArrayAppendValue(A, s1);
+
+ // Decrement the reference count.
+ CFRelease(s1); // no-warning
+
+ // Get the string. We don't own it.
+ s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0);
+
+ // Release the array.
+ CFRelease(A); // no-warning
+
+ // Release the string. This is a bug.
+ CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3337: Handle functions declared using typedefs.
+typedef CFTypeRef CREATEFUN();
+CFTypeRef MyCreateFun();
+
+void f12() {
+ CFTypeRef o = MyCreateFun(); // expected-warning {{leak}}
+}
+
+void f13_autorelease() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+ [(id) A autorelease]; // no-warning
+}
+
+void f13_autorelease_b() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+} // expected-warning{{Object autoreleased too many times}}
+
+CFMutableArrayRef f13_autorelease_c() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ return A; // expected-warning{{Object autoreleased too many times}}
+}
+
+CFMutableArrayRef f13_autorelease_d() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ CFMutableArrayRef B = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Object autoreleased too many times}}
+ CFRelease(B); // no-warning
+ while (1) {}
+}
+
+
+// This case exercises the logic where the leak site is the same as the allocation site.
+void f14_leakimmediately() {
+ CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}}
+}
+
+// Test that we track an allocated object beyond the point where the *name*
+// of the variable storing the reference is no longer live.
+void f15() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ CFMutableArrayRef *B = &A;
+ // At this point, the name 'A' is no longer live.
+ CFRelease(*B); // no-warning
+}
+
+// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
+void f16(int x, CFTypeRef p) {
+ if (p)
+ return;
+
+ if (x > 0) {
+ CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
+ }
+ else if (x < 0) {
+ CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
+ }
+ else {
+ CFMakeCollectable(p); // expected-warning{{Null pointer argument in call to CFMakeCollectable}}
+ }
+}
+
+// Test that an object is non-null after being CFRetained/CFReleased.
+void f17(int x, CFTypeRef p) {
+ if (x > 0) {
+ CFRelease(p);
+ if (!p)
+ CFRelease(0); // no-warning
+ }
+ else if (x < 0) {
+ CFRetain(p);
+ if (!p)
+ CFRetain(0); // no-warning
+ }
+ else {
+ CFMakeCollectable(p);
+ if (!p)
+ CFMakeCollectable(0); // no-warning
+ }
+}
+
+// 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.
+@interface SelfIvarTest : NSObject {
+ id myObj;
+}
+- (void)test_self_tracking;
+@end
+
+@implementation SelfIvarTest
+- (void)test_self_tracking {
+ myObj = (id) CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+@end
+
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+@interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+@end
+
+@implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"];
+ return s; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+@end
+
+// <rdar://problem/6659160>
+int isFoo(char c);
+
+static void rdar_6659160(char *inkind, char *inname)
+{
+ // We currently expect that [NSObject alloc] cannot fail. This
+ // will be a toggled flag in the future. It can indeed return null, but
+ // Cocoa programmers generally aren't expected to reason about out-of-memory
+ // conditions.
+ NSString *kind = [[NSString alloc] initWithUTF8String:inkind]; // expected-warning{{leak}}
+
+ // We do allow stringWithUTF8String to fail. This isn't really correct, as
+ // far as returning 0. In most error conditions it will throw an exception.
+ // If allocation fails it could return 0, but again this
+ // isn't expected.
+ NSString *name = [NSString stringWithUTF8String:inname];
+ if(!name)
+ return;
+
+ const char *kindC = 0;
+ const char *nameC = 0;
+
+ // In both cases, we cannot reach a point down below where we
+ // dereference kindC or nameC with either being null. This is because
+ // we assume that [NSObject alloc] doesn't fail and that we have the guard
+ // up above.
+
+ if(kind)
+ kindC = [kind UTF8String];
+ if(name)
+ nameC = [name UTF8String];
+ if(!isFoo(kindC[0])) // expected-warning{{null}}
+ return;
+ if(!isFoo(nameC[0])) // no-warning
+ return;
+
+ [kind release];
+ [name release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3677 - 'allocWithZone' should be treated as following the Cocoa naming
+// conventions with respect to 'return'ing ownership.
+@interface PR3677: NSObject @end
+@implementation PR3677
++ (id)allocWithZone:(NSZone *)inZone {
+ return [super allocWithZone:inZone]; // no-warning
+}
+@end
+
+// PR 3820 - Reason about calls to -dealloc
+void pr3820_DeallocInsteadOfRelease(void)
+{
+ id foo = [[NSString alloc] init]; // no-warning
+ [foo dealloc];
+ // foo is not leaked, since it has been deallocated.
+}
+
+void pr3820_ReleaseAfterDealloc(void)
+{
+ id foo = [[NSString alloc] init];
+ [foo dealloc];
+ [foo release]; // expected-warning{{used after it is release}}
+ // NSInternalInconsistencyException: message sent to deallocated object
+}
+
+void pr3820_DeallocAfterRelease(void)
+{
+ NSLog(@"\n\n[%s]", __FUNCTION__);
+ id foo = [[NSString alloc] init];
+ [foo release];
+ [foo dealloc]; // expected-warning{{used after it is released}}
+ // message sent to released object
+}
+
+// From <rdar://problem/6704930>. The problem here is that 'length' binds to
+// '($0 - 1)' after '--length', but SimpleConstraintManager doesn't know how to
+// reason about '($0 - 1) > constant'. As a temporary hack, we drop the value
+// of '($0 - 1)' and conjure a new symbol.
+void rdar6704930(unsigned char *s, unsigned int length) {
+ NSString* name = 0;
+ if (s != 0) {
+ if (length > 0) {
+ while (length > 0) {
+ if (*s == ':') {
+ ++s;
+ --length;
+ name = [[NSString alloc] init]; // no-warning
+ break;
+ }
+ ++s;
+ --length;
+ }
+ if ((length == 0) && (name != 0)) {
+ [name release];
+ name = 0;
+ }
+ if (length == 0) { // no ':' found -> use it all as name
+ name = [[NSString alloc] init]; // no-warning
+ }
+ }
+ }
+
+ if (name != 0) {
+ [name release];
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6833332>
+// One build of the analyzer accidentally stopped tracking the allocated
+// object after the 'retain'.
+//===----------------------------------------------------------------------===//
+
+@interface rdar_6833332 : NSObject <NSApplicationDelegate> {
+ NSWindow *window;
+}
+@property (nonatomic, retain) NSWindow *window;
+@end
+
+@implementation rdar_6833332
+@synthesize window;
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+
+ [dict setObject:@"foo" forKey:@"bar"];
+
+ NSLog(@"%@", dict);
+}
+- (void)dealloc {
+ [window release];
+ [super dealloc];
+}
+
+- (void)radar10102244 {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+ if (window)
+ NSLog(@"%@", window);
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6257780> clang checker fails to catch use-after-release
+//===----------------------------------------------------------------------===//
+
+int rdar_6257780_Case1() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSArray *array = [NSArray array];
+ [array release]; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+ [pool drain];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/10640253> Analyzer is confused about NSAutoreleasePool -allocWithZone:.
+//===----------------------------------------------------------------------===//
+
+void rdar_10640253_autorelease_allocWithZone() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:(NSZone*)0] init];
+ (void) pool;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6866843> Checker should understand new/setObject:/release constructs
+//===----------------------------------------------------------------------===//
+
+void rdar_6866843() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSMutableDictionary* dictionary = [[NSMutableDictionary alloc] init];
+ NSArray* array = [[NSArray alloc] init];
+ [dictionary setObject:array forKey:@"key"];
+ [array release];
+ // Using 'array' here should be fine
+ NSLog(@"array = %@\n", array); // no-warning
+ // Now the array is released
+ [dictionary release];
+ [pool drain];
+}
+
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6877235> Classes typedef-ed to CF objects should get the same treatment as CF objects
+//===----------------------------------------------------------------------===//
+
+typedef CFTypeRef OtherRef;
+
+@interface RDar6877235 : NSObject {}
+- (CFTypeRef)_copyCFTypeRef;
+- (OtherRef)_copyOtherRef;
+@end
+
+@implementation RDar6877235
+- (CFTypeRef)_copyCFTypeRef {
+ return [[NSString alloc] init]; // no-warning
+}
+- (OtherRef)_copyOtherRef {
+ return [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6320065> false positive - init method returns an object
+// owned by caller
+//===----------------------------------------------------------------------===//
+
+@interface RDar6320065 : NSObject {
+ NSString *_foo;
+}
+- (id)initReturningNewClass;
+- (id)_initReturningNewClassBad;
+- (id)initReturningNewClassBad2;
+@end
+
+@interface RDar6320065Subclass : RDar6320065
+@end
+
+@implementation RDar6320065
+- (id)initReturningNewClass {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init]; // no-warning
+ return self;
+}
+- (id)_initReturningNewClassBad {
+ [self release];
+ [[RDar6320065Subclass alloc] init]; // expected-warning {{leak}}
+ return self;
+}
+- (id)initReturningNewClassBad2 {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init];
+ return [self autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+@end
+
+@implementation RDar6320065Subclass
+@end
+
+int RDar6320065_test() {
+ RDar6320065 *test = [[RDar6320065 alloc] init]; // no-warning
+ [test release];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7129086> -awakeAfterUsingCoder: returns an owned object
+// and claims the receiver
+//===----------------------------------------------------------------------===//
+
+@interface RDar7129086 : NSObject {} @end
+@implementation RDar7129086
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder {
+ [self release]; // no-warning
+ return [NSString alloc]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a
+// retained object
+//===----------------------------------------------------------------------===//
+
+@interface RDar6859457 : NSObject {}
+- (NSString*) NoCopyString;
+- (NSString*) noCopyString;
+@end
+
+@implementation RDar6859457
+- (NSString*) NoCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}}
+- (NSString*) noCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}}
+@end
+
+void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) {
+ [x NoCopyString]; // expected-warning{{leak}}
+ [x noCopyString]; // expected-warning{{leak}}
+ [NSData dataWithBytesNoCopy:bytes length:dataLength]; // no-warning
+ [NSData dataWithBytesNoCopy:bytes length:dataLength freeWhenDone:1]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// PR 4230 - an autorelease pool is not necessarily leaked during a premature
+// return
+//===----------------------------------------------------------------------===//
+
+static void PR4230(void)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
+static void PR4230_new(void)
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
+//===----------------------------------------------------------------------===//
+// Method name that has a null IdentifierInfo* for its first selector slot.
+// This test just makes sure that we handle it.
+//===----------------------------------------------------------------------===//
+
+@interface TestNullIdentifier
+@end
+
+@implementation TestNullIdentifier
++ (id):(int)x, ... {
+ return [[NSString alloc] init]; // expected-warning{{leak}}
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6893565> don't flag leaks for return types that cannot be
+// determined to be CF types
+//===----------------------------------------------------------------------===//
+
+// We don't know if 'struct s6893565' represents a Core Foundation type, so
+// we shouldn't emit an error here.
+typedef struct s6893565* TD6893565;
+
+@interface RDar6893565 {}
+-(TD6893565)newThing;
+@end
+
+@implementation RDar6893565
+-(TD6893565)newThing {
+ return (TD6893565) [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6902710> clang: false positives w/QC and CoreImage methods
+//===----------------------------------------------------------------------===//
+
+void rdar6902710(QCView *view, QCRenderer *renderer, CIContext *context,
+ NSString *str, CIImage *img, CGRect rect,
+ CIFormat form, CGColorSpaceRef cs) {
+ [view createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [renderer createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6945561> -[CIContext createCGLayerWithSize:info:]
+// misinterpreted by clang scan-build
+//===----------------------------------------------------------------------===//
+
+void rdar6945561(CIContext *context, CGSize size, CFDictionaryRef d) {
+ [context createCGLayerWithSize:size info:d]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6961230> add knowledge of IOKit functions to retain/release
+// checker
+//===----------------------------------------------------------------------===//
+
+void IOBSDNameMatching_wrapper(mach_port_t masterPort, uint32_t options, const char * bsdName) {
+ IOBSDNameMatching(masterPort, options, bsdName); // expected-warning{{leak}}
+}
+
+void IOServiceMatching_wrapper(const char * name) {
+ IOServiceMatching(name); // expected-warning{{leak}}
+}
+
+void IOServiceNameMatching_wrapper(const char * name) {
+ IOServiceNameMatching(name); // expected-warning{{leak}}
+}
+
+CF_RETURNS_RETAINED CFDictionaryRef CreateDict();
+
+void IOServiceAddNotification_wrapper(mach_port_t masterPort, const io_name_t notificationType,
+ mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) {
+
+ CFDictionaryRef matching = CreateDict();
+ CFRelease(matching);
+ IOServiceAddNotification(masterPort, notificationType, matching, // expected-warning{{used after it is released}} expected-warning{{deprecated}}
+ wakePort, reference, notification);
+}
+
+void IORegistryEntryIDMatching_wrapper(uint64_t entryID ) {
+ IORegistryEntryIDMatching(entryID); // expected-warning{{leak}}
+}
+
+void IOOpenFirmwarePathMatching_wrapper(mach_port_t masterPort, uint32_t options,
+ const char * path) {
+ IOOpenFirmwarePathMatching(masterPort, options, path); // expected-warning{{leak}}
+}
+
+void IOServiceGetMatchingService_wrapper(mach_port_t masterPort) {
+ CFDictionaryRef matching = CreateDict();
+ IOServiceGetMatchingService(masterPort, matching);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+void IOServiceGetMatchingServices_wrapper(mach_port_t masterPort, io_iterator_t *existing) {
+ CFDictionaryRef matching = CreateDict();
+ IOServiceGetMatchingServices(masterPort, matching, existing);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort, const io_name_t notificationType,
+ IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification) {
+
+ CFDictionaryRef matching = CreateDict();
+ IOServiceAddMatchingNotification(notifyPort, notificationType, matching, callback, refCon, notification);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+//===----------------------------------------------------------------------===//
+// Test of handling objects whose references "escape" to containers.
+//===----------------------------------------------------------------------===//
+
+void CFDictionaryAddValue(CFMutableDictionaryRef, void *, void *);
+
+// <rdar://problem/6539791>
+void rdar_6539791(CFMutableDictionaryRef y, void* key, void* val_key) {
+ CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryAddValue(y, key, x);
+ CFRelease(x); // the dictionary keeps a reference, so the object isn't deallocated yet
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ if (value) {
+ CFDictionaryAddValue(x, val_key, (void*)value); // no-warning
+ CFRelease(value);
+ CFDictionaryAddValue(y, val_key, (void*)value); // no-warning
+ }
+}
+
+// <rdar://problem/6560661>
+// Same issue, except with "AppendValue" functions.
+void rdar_6560661(CFMutableArrayRef x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ // CFArrayAppendValue keeps a reference to value.
+ CFArrayAppendValue(x, value);
+ CFRelease(value);
+ CFRetain(value);
+ CFRelease(value); // no-warning
+}
+
+// <rdar://problem/7152619>
+// Same issue, excwept with "CFAttributeStringSetAttribute".
+void rdar_7152619(CFStringRef str) {
+ CFAttributedStringRef string = CFAttributedStringCreate(kCFAllocatorDefault, str, 0);
+ CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 100, string);
+ CFRelease(string);
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+ CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 1), str, number);
+ [number release];
+ [number retain];
+ CFRelease(attrString);
+}
+
+//===----------------------------------------------------------------------===//
+// Test of handling CGGradientXXX functions.
+//===----------------------------------------------------------------------===//
+
+void rdar_7184450(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), // expected-warning{{leak}}
+ components, locations, num_locations);
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+ CGGradientRelease(myGradient);
+}
+
+void rdar_7184450_pos(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), components, locations, num_locations); // expected-warning 2 {{leak}}
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7299394> clang false positive: retained instance passed to
+// thread in pthread_create marked as leak
+//
+// Until we have full IPA, the analyzer should stop tracking the reference
+// count of objects passed to pthread_create.
+//
+//===----------------------------------------------------------------------===//
+
+struct _opaque_pthread_t {};
+struct _opaque_pthread_attr_t {};
+typedef struct _opaque_pthread_t *__darwin_pthread_t;
+typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
+typedef __darwin_pthread_t pthread_t;
+typedef __darwin_pthread_attr_t pthread_attr_t;
+typedef unsigned long __darwin_pthread_key_t;
+typedef __darwin_pthread_key_t pthread_key_t;
+
+int pthread_create(pthread_t *, const pthread_attr_t *,
+ void *(*)(void *), void *);
+
+int pthread_setspecific(pthread_key_t key, const void *value);
+
+void *rdar_7299394_start_routine(void *p) {
+ [((id) p) release];
+ return 0;
+}
+void rdar_7299394(pthread_attr_t *attr, pthread_t *thread, void *args) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ pthread_create(thread, attr, rdar_7299394_start_routine, number);
+}
+void rdar_7299394_positive(pthread_attr_t *attr, pthread_t *thread) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/11282706> false positive with not understanding thread
+// local storage
+//===----------------------------------------------------------------------===//
+
+void rdar11282706(pthread_key_t key) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ pthread_setspecific(key, (void*) number);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7283567> False leak associated with call to
+// CVPixelBufferCreateWithBytes ()
+//
+// According to the Core Video Reference (ADC), CVPixelBufferCreateWithBytes and
+// CVPixelBufferCreateWithPlanarBytes can release (via a callback) the
+// pixel buffer object. These test cases show how the analyzer stops tracking
+// the reference count for the objects passed for this argument. This
+// could be made smarter.
+//===----------------------------------------------------------------------===//
+
+typedef int int32_t;
+typedef UInt32 FourCharCode;
+typedef FourCharCode OSType;
+typedef uint64_t CVOptionFlags;
+typedef int32_t CVReturn;
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVImageBufferRef;
+typedef CVImageBufferRef CVPixelBufferRef;
+typedef void (*CVPixelBufferReleaseBytesCallback)( void *releaseRefCon, const void *baseAddress );
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+typedef void (*CVPixelBufferReleasePlanarBytesCallback)( void *releaseRefCon, const void *dataPtr, size_t dataSize, size_t numberOfPlanes, const void *planeAddresses[] );
+
+extern CVReturn CVPixelBufferCreateWithPlanarBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *dataPtr,
+ size_t dataSize,
+ size_t numberOfPlanes,
+ void *planeBaseAddress[],
+ size_t planeWidth[],
+ size_t planeHeight[],
+ size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+CVReturn rdar_7283567(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithBytes(allocator, width, height, pixelFormatType,
+ baseAddress, bytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *dataPtr, size_t dataSize,
+ size_t numberOfPlanes, void *planeBaseAddress[],
+ size_t planeWidth[], size_t planeHeight[], size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithPlanarBytes(allocator,
+ width, height, pixelFormatType, dataPtr, dataSize,
+ numberOfPlanes, planeBaseAddress, planeWidth,
+ planeHeight, planeBytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7358899> False leak associated with
+// CGBitmapContextCreateWithData
+//===----------------------------------------------------------------------===//
+typedef uint32_t CGBitmapInfo;
+typedef void (*CGBitmapContextReleaseDataCallback)(void *releaseInfo, void *data);
+
+CGContextRef CGBitmapContextCreateWithData(void *data,
+ size_t width, size_t height, size_t bitsPerComponent,
+ size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo,
+ CGBitmapContextReleaseDataCallback releaseCallback, void *releaseInfo);
+
+void rdar_7358899(void *data,
+ size_t width, size_t height, size_t bitsPerComponent,
+ size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo,
+ CGBitmapContextReleaseDataCallback releaseCallback) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, // expected-warning{{leak}}
+ bytesPerRow, space, bitmapInfo, releaseCallback, number);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7265711> allow 'new', 'copy', 'alloc', 'init' prefix to
+// start before '_' when determining Cocoa fundamental rule
+//
+// Previously the retain/release checker just skipped prefixes before the
+// first '_' entirely. Now the checker honors the prefix if it results in a
+// recognizable naming convention (e.g., 'new', 'init').
+//===----------------------------------------------------------------------===//
+
+@interface RDar7265711 {}
+- (id) new_stuff;
+@end
+
+void rdar7265711_a(RDar7265711 *x) {
+ id y = [x new_stuff]; // expected-warning{{leak}}
+}
+
+void rdar7265711_b(RDar7265711 *x) {
+ id y = [x new_stuff]; // no-warning
+ [y release];
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7306898> clang thinks [NSCursor dragCopyCursor] returns a
+// retained reference
+//===----------------------------------------------------------------------===//
+
+@interface NSCursor : NSObject
++ (NSCursor *)dragCopyCursor;
+@end
+
+void rdar7306898(void) {
+ // 'dragCopyCursor' does not follow Cocoa's fundamental rule. It is a noun, not an sentence
+ // implying a 'copy' of something.
+ NSCursor *c = [NSCursor dragCopyCursor]; // no-warning
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7252064> sending 'release', 'retain', etc. to a Class
+// directly is not likely what the user intended
+//===----------------------------------------------------------------------===//
+
+@interface RDar7252064 : NSObject @end
+void rdar7252064(void) {
+ [RDar7252064 release]; // expected-warning{{The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [RDar7252064 retain]; // expected-warning{{The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [RDar7252064 autorelease]; // expected-warning{{The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [NSAutoreleasePool drain]; // expected-warning{{method '+drain' not found}} expected-warning{{The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly}}
+}
+
+//===----------------------------------------------------------------------===//
+// Tests of ownership attributes.
+//===----------------------------------------------------------------------===//
+
+typedef NSString* MyStringTy;
+
+@protocol FooP;
+
+@interface TestOwnershipAttr : NSObject
+- (NSString*) returnsAnOwnedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) returnsAnOwnedCFString CF_RETURNS_RETAINED; // no-warning
+- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+- (NSString*) newString_auto NS_RETURNS_AUTORELEASED; // no-warning
+- (NSString*) newStringNoAttr;
+- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
+- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
++ (void) consume:(id) NS_CONSUMED x;
++ (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}}
+
+void test_attr_1(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
+}
+
+void test_attr_1b(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}}
+}
+
+void test_attr1c(TestOwnershipAttr *X) {
+ NSString *str = [X newString]; // no-warning
+ NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}}
+ NSString *str3 = [X newString_auto]; // no-warning
+ NSString *str4 = [[X newString_auto] retain]; // expected-warning {{leak}}
+}
+
+void testattr2_a() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // expected-warning{{leak}}
+}
+
+void testattr2_b() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // expected-warning{{leak}}
+}
+
+void testattr2_b_11358224_self_assign_looses_the_leak() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit];// expected-warning{{leak}}
+ x = x;
+}
+
+void testattr2_c() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // no-warning
+ [x release];
+}
+
+void testattr3() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+ [TestOwnershipAttr consume:x];
+ TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+ [TestOwnershipAttr consume2:y];
+}
+
+void consume_ns(id NS_CONSUMED x);
+void consume_cf(id CF_CONSUMED x);
+
+void testattr4() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+ consume_ns(x);
+ TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+ consume_cf(y);
+}
+
+@interface TestOwnershipAttr2 : NSObject
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+@end
+
+@implementation TestOwnershipAttr2
+- (NSString*) newString {
+ return [NSString alloc]; // expected-warning {{Potential leak of an object}}
+}
+@end
+
+@interface MyClassTestCFAttr : NSObject {}
+- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
+- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
+- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
+- (CFDateRef) newCFRetainedAsCFNoAttr;
+- (NSDate*) alsoReturnsRetained;
+- (CFDateRef) alsoReturnsRetainedAsCF;
+- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
+@end
+
+CF_RETURNS_RETAINED
+CFDateRef returnsRetainedCFDate() {
+ return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+}
+
+@implementation MyClassTestCFAttr
+- (NSDate*) returnsCFRetained {
+ return (NSDate*) returnsRetainedCFDate(); // No leak.
+}
+
+- (CFDateRef) returnsCFRetainedAsCF {
+ return returnsRetainedCFDate(); // No leak.
+}
+
+- (CFDateRef) newCFRetainedAsCF {
+ return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease];
+}
+
+- (CFDateRef) newCFRetainedAsCFNoAttr {
+ return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+- (NSDate*) alsoReturnsRetained {
+ return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}}
+}
+
+- (CFDateRef) alsoReturnsRetainedAsCF {
+ return returnsRetainedCFDate(); // expected-warning{{leak}}
+}
+
+
+- (NSDate*) returnsNSRetained {
+ return (NSDate*) returnsRetainedCFDate(); // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// Test that leaks post-dominated by "panic" functions are not reported.
+//
+// <rdar://problem/5905851> do not report a leak when post-dominated by a call
+// to a noreturn or panic function
+//===----------------------------------------------------------------------===//
+
+void panic() __attribute__((noreturn));
+void panic_not_in_hardcoded_list() __attribute__((noreturn));
+
+void test_panic_negative() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+}
+
+void test_panic_positive() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ panic();
+}
+
+void test_panic_neg_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+ if (x)
+ panic();
+}
+
+void test_panic_pos_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ if (x)
+ panic();
+ if (!x) {
+ // This showed up in <rdar://problem/7796563>, where we silently missed checking
+ // the function type for noreturn. "panic()" is a hard-coded known panic function
+ // that isn't always noreturn.
+ panic_not_in_hardcoded_list();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test uses of blocks (closures)
+//===----------------------------------------------------------------------===//
+
+void test_blocks_1_pos(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+ ^{}();
+}
+
+void test_blocks_1_indirect_release(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^{ [number release]; }();
+}
+
+void test_blocks_1_indirect_retain(void) {
+ // Eventually this should be reported as a leak.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^{ [number retain]; }();
+}
+
+void test_blocks_1_indirect_release_via_call(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^(NSObject *o){ [o release]; }(number);
+}
+
+void test_blocks_1_indirect_retain_via_call(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning {{leak}}
+ ^(NSObject *o){ [o retain]; }(number);
+}
+
+//===--------------------------------------------------------------------===//
+// Test sending message to super that returns an object alias. Previously
+// this caused a crash in the analyzer.
+//===--------------------------------------------------------------------===//
+
+@interface Rdar8015556 : NSObject {} @end
+@implementation Rdar8015556
+- (id)retain {
+ return [super retain];
+}
+@end
+
+// <rdar://problem/8272168> - Correcly handle Class<...> in Cocoa Conventions
+// detector.
+
+@protocol Prot_R8272168 @end
+Class <Prot_R8272168> GetAClassThatImplementsProt_R8272168();
+void r8272168() {
+ GetAClassThatImplementsProt_R8272168();
+}
+
+// Test case for <rdar://problem/8356342>, which in the past triggered
+// a false positive.
+@interface RDar8356342
+- (NSDate*) rdar8356342:(NSDate *)inValue;
+@end
+
+@implementation RDar8356342
+- (NSDate*) rdar8356342:(NSDate*)inValue {
+ NSDate *outValue = inValue;
+ if (outValue == 0)
+ outValue = [[NSDate alloc] init]; // no-warning
+
+ if (outValue != inValue)
+ [outValue autorelease];
+
+ return outValue;
+}
+@end
+
+// <rdar://problem/8724287> - This test case previously crashed because
+// of a bug in BugReporter.
+extern const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key);
+typedef struct __CFError * CFErrorRef;
+extern const CFStringRef kCFErrorUnderlyingErrorKey;
+extern CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err);
+static void rdar_8724287(CFErrorRef error)
+{
+ CFErrorRef error_to_dump;
+
+ error_to_dump = error;
+ while (error_to_dump != ((void*)0)) {
+ CFDictionaryRef info;
+
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object}}
+
+ if (info != ((void*)0)) {
+ }
+
+ error_to_dump = (CFErrorRef) CFDictionaryGetValue(info, kCFErrorUnderlyingErrorKey);
+ }
+}
+
+// <rdar://problem/9234108> - Make sure the model applies cf_consumed
+// correctly in argument positions besides the first.
+extern void *CFStringCreate(void);
+extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value);
+void rdar_9234108() {
+ rdar_9234108_helper(0, CFStringCreate());
+}
+
+// <rdar://problem/9726279> - Make sure that objc_method_family works
+// to override naming conventions.
+struct TwoDoubles {
+ double one;
+ double two;
+};
+typedef struct TwoDoubles TwoDoubles;
+
+@interface NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles __attribute__((objc_method_family(init)));
+@end
+
+@implementation NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles
+{
+ return [self init];
+}
+@end
+
+void rdar9726279() {
+ TwoDoubles twoDoubles = { 0.0, 0.0 };
+ NSValue *value = [[NSValue alloc] _prefix_initWithTwoDoubles:twoDoubles];
+ [value release];
+}
+
+// <rdar://problem/9732321>
+// Test camelcase support for CF conventions. While Core Foundation APIs
+// don't use camel casing, other code is allowed to use it.
+CFArrayRef camelcase_create_1() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_createno() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camelcase_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_copying() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __createCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_create() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+
+CFArrayRef camel_creat() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camel_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copyMachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copymachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+// rdar://problem/8024350
+@protocol F18P
+- (id) clone;
+@end
+@interface F18 : NSObject<F18P> @end
+@interface F18(Cat)
+- (id) clone NS_RETURNS_RETAINED;
+@end
+
+@implementation F18
+- (id) clone {
+ return [F18 alloc];
+}
+@end
+
+// Radar 6582778.
+void rdar6582778(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFTypeRef vals[] = { CFDateCreate(0, t) }; // expected-warning {{leak}}
+}
+
+CFTypeRef global;
+
+void rdar6582778_2(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ global = CFDateCreate(0, t); // no-warning
+}
+
+// <rdar://problem/10232019> - Test that objects passed to containers
+// are marked "escaped".
+
+void rdar10232019() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [array addObject:string];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // no-warning
+ NSLog(@"%@", otherString);
+}
+
+void rdar10232019_positive() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // expected-warning {{Reference-counted object is used after it is release}}
+ NSLog(@"%@", otherString);
+}
+
+// RetainCountChecker support for XPC.
+// <rdar://problem/9658496>
+typedef void * xpc_object_t;
+xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef cf);
+void xpc_release(xpc_object_t object);
+
+void rdar9658496() {
+ CFStringRef cf;
+ xpc_object_t xpc;
+ cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ xpc = _CFXPCCreateXPCObjectFromCFObject( cf );
+ CFRelease(cf);
+ xpc_release(xpc);
+}
+
+// Support annotations with method families.
+@interface RDar10824732 : NSObject
+- (id)initWithObj:(id CF_CONSUMED)obj;
+@end
+
+@implementation RDar10824732
+- (id)initWithObj:(id)obj {
+ [obj release];
+ return [super init];
+}
+@end
+
+void rdar_10824732() {
+ @autoreleasepool {
+ NSString *obj = @"test";
+ RDar10824732 *foo = [[RDar10824732 alloc] initWithObj:obj]; // no-warning
+ [foo release];
+ }
+}
+
+// Stop tracking objects passed to functions, which take callbacks as parameters.
+// radar://10973977
+typedef int (*CloseCallback) (void *);
+void ReaderForIO(CloseCallback ioclose, void *ioctx);
+int IOClose(void *context);
+
+@protocol SInS <NSObject>
+@end
+
+@interface radar10973977 : NSObject
+- (id<SInS>)inputS;
+- (void)reader;
+@end
+
+@implementation radar10973977
+- (void)reader
+{
+ id<SInS> inputS = [[self inputS] retain];
+ ReaderForIO(IOClose, inputS);
+}
+- (id<SInS>)inputS
+{
+ return 0;
+}
+@end
+
+// Object escapes through a selector callback: radar://11398514
+extern id NSApp;
+@interface MySheetController
+- (id<SInS>)inputS;
+- (void)showDoSomethingSheetAction:(id)action;
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+
+@implementation MySheetController
+- (id<SInS>)inputS {
+ return 0;
+}
+- (void)showDoSomethingSheetAction:(id)action {
+ id<SInS> inputS = [[self inputS] retain];
+ [NSApp beginSheet:0
+ modalForWindow:0
+ modalDelegate:0
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:(void *)inputS]; // no - warning
+}
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
+
+ id contextObject = (id)contextInfo;
+ [contextObject release];
+}
+
+- (id)copyAutoreleaseRadar13081402 {
+ id x = [[[NSString alloc] initWithUTF8String:"foo"] autorelease];
+ [x retain];
+ return x; // no warning
+}
+
+@end
+//===----------------------------------------------------------------------===//
+// Test returning allocated memory in a struct.
+//
+// We currently don't have a general way to track pointers that "escape".
+// Here we test that RetainCountChecker doesn't get excited about returning
+// allocated CF objects in struct fields.
+//===----------------------------------------------------------------------===//
+void *malloc(size_t);
+struct rdar11104566 { CFStringRef myStr; };
+struct rdar11104566 test_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 V;
+ V.myStr = cf;
+ return V; // no-warning
+}
+
+struct rdar11104566 *test_2_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 *V = (struct rdar11104566 *) malloc(sizeof(*V));
+ V->myStr = cf;
+ return V; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// ObjC literals support.
+//===----------------------------------------------------------------------===//
+
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; // expected-warning {{leak}}
+ [o release];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1]; // expected-warning {{leak}}
+ [o release];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = [@[o] retain]; // expected-warning {{leak}}
+ [o release];
+ [a3 description];
+ [o description];
+ }
+
+ { // CASE FOUR -- OBJECT IN ARRAY CREATED BY DUPING @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithArray:@[o]]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+
+ { // CASE FIVE -- OBJECT IN RETAINED @{}
+ NSValue *o = [[NSValue alloc] init];
+ NSDictionary *a = [@{o : o} retain]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+}
+
+void test_objc_integer_literals() {
+ id value = [@1 retain]; // expected-warning {{leak}}
+ [value description];
+}
+
+void test_objc_boxed_expressions(int x, const char *y) {
+ id value = [@(x) retain]; // expected-warning {{leak}}
+ [value description];
+
+ value = [@(y) retain]; // expected-warning {{leak}}
+ [value description];
+}
+
+// Test NSLog doesn't escape tracked objects.
+void rdar11400885(int y)
+{
+ @autoreleasepool {
+ NSString *printString;
+ if(y > 2)
+ printString = [[NSString alloc] init];
+ else
+ printString = [[NSString alloc] init];
+ NSLog(@"Once %@", printString);
+ [printString release];
+ NSLog(@"Again: %@", printString); // expected-warning {{Reference-counted object is used after it is released}}
+ }
+}
+
+id makeCollectableNonLeak() {
+ extern CFTypeRef CFCreateSomething();
+
+ CFTypeRef object = CFCreateSomething(); // +1
+ CFRetain(object); // +2
+ id objCObject = NSMakeCollectable(object); // +2
+ [objCObject release]; // +1
+ return [objCObject autorelease]; // +0
+}
+
+
+void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void));
+void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void));
+
+void testConsumeAndStopTracking() {
+ id retained = [@[] retain]; // +1
+ consumeAndStopTracking(retained, ^{}); // no-warning
+
+ id doubleRetained = [[@[] retain] retain]; // +2
+ consumeAndStopTracking(doubleRetained, ^{
+ [doubleRetained release];
+ }); // no-warning
+
+ id unretained = @[]; // +0
+ consumeAndStopTracking(unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFConsumeAndStopTracking() {
+ id retained = [@[] retain]; // +1
+ CFConsumeAndStopTracking((CFTypeRef)retained, ^{}); // no-warning
+
+ id doubleRetained = [[@[] retain] retain]; // +2
+ CFConsumeAndStopTracking((CFTypeRef)doubleRetained, ^{
+ [doubleRetained release];
+ }); // no-warning
+
+ id unretained = @[]; // +0
+ CFConsumeAndStopTracking((CFTypeRef)unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+//===----------------------------------------------------------------------===//
+// Test 'pragma clang arc_cf_code_audited' support.
+//===----------------------------------------------------------------------===//
+
+typedef void *MyCFType;
+#pragma clang arc_cf_code_audited begin
+MyCFType CreateMyCFType();
+#pragma clang arc_cf_code_audited end
+
+void test_custom_cf() {
+ MyCFType x = CreateMyCFType(); // expected-warning {{leak of an object stored into 'x'}}
+}
+
+//===----------------------------------------------------------------------===//
+// Test calling CFPlugInInstanceCreate, which appears in CF but doesn't
+// return a CF object.
+//===----------------------------------------------------------------------===//
+
+void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
+ CFPlugInInstanceCreate(kCFAllocatorDefault, factoryUUID, typeUUID); // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// PR14927: -drain only has retain-count semantics on NSAutoreleasePool.
+//===----------------------------------------------------------------------===//
+
+@interface PR14927 : NSObject
+- (void)drain;
+@end
+
+void test_drain() {
+ PR14927 *obj = [[PR14927 alloc] init];
+ [obj drain];
+ [obj release]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Allow cf_returns_retained and cf_returns_not_retained to mark a return
+// value as tracked, even if the object isn't a known CF type.
+//===----------------------------------------------------------------------===//
+
+MyCFType getCustom() __attribute__((cf_returns_not_retained));
+MyCFType makeCustom() __attribute__((cf_returns_retained));
+
+void testCustomReturnsRetained() {
+ MyCFType obj = makeCustom(); // expected-warning {{leak of an object stored into 'obj'}}
+}
+
+void testCustomReturnsNotRetained() {
+ CFRelease(getCustom()); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+//===----------------------------------------------------------------------===//
+// Don't print variables which are out of the current scope.
+//===----------------------------------------------------------------------===//
+@interface MyObj12706177 : NSObject
+-(id)initX;
++(void)test12706177;
+@end
+static int Cond;
+@implementation MyObj12706177
+-(id)initX {
+ if (Cond)
+ return 0;
+ self = [super init];
+ return self;
+}
++(void)test12706177 {
+ id x = [[MyObj12706177 alloc] initX]; //expected-warning {{Potential leak of an object}}
+ [x release];
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/13783514> xpc_connection_set_finalizer_f
+//===----------------------------------------------------------------------===//
+
+typedef xpc_object_t xpc_connection_t;
+typedef void (*xpc_finalizer_t)(void *value);
+void xpc_connection_set_context(xpc_connection_t connection, void *ctx);
+void xpc_connection_set_finalizer_f(xpc_connection_t connection,
+ xpc_finalizer_t finalizer);
+void releaseAfterXPC(void *context) {
+ [(NSArray *)context release];
+}
+
+void rdar13783514(xpc_connection_t connection) {
+ xpc_connection_set_context(connection, [[NSMutableArray alloc] init]);
+ xpc_connection_set_finalizer_f(connection, releaseAfterXPC);
+} // no-warning
+
+CFAttributedStringRef CFAttributedCreate(void *CFObj CF_CONSUMED) CF_RETURNS_RETAINED;
+
+@interface Action
+- (SEL)action;
+- (void)setAction:(SEL)aSelector;
+- (id) target;
+- (void)setTarget:(id)aTarget;
+@end
diff --git a/test/ARCMT/objcmt-arc-cf-annotations.m.result b/test/ARCMT/objcmt-arc-cf-annotations.m.result
new file mode 100644
index 000000000000..7e0a9042f5e6
--- /dev/null
+++ b/test/ARCMT/objcmt-arc-cf-annotations.m.result
@@ -0,0 +1,2093 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-annotation -objcmt-migrate-instancetype -objcmt-migrate-readwrite-property -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+
+#ifndef CF_IMPLICIT_BRIDGING_ENABLED
+#if __has_feature(arc_cf_code_audited)
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+#else
+#define CF_IMPLICIT_BRIDGING_ENABLED
+#endif
+#endif
+
+#ifndef CF_IMPLICIT_BRIDGING_DISABLED
+#if __has_feature(arc_cf_code_audited)
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+#else
+#define CF_IMPLICIT_BRIDGING_DISABLED
+#endif
+#endif
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+// #include <IOKit/IOKitLib.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef CFIndex CFByteOrder;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+extern void CFRelease(CFTypeRef cf);
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+extern CFTypeRef CFMakeCollectable(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) CF_RETURNS_RETAINED;
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx) CF_RETURNS_NOT_RETAINED;
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) CF_RETURNS_RETAINED;
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding) CF_RETURNS_RETAINED;
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) CF_RETURNS_RETAINED;
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+enum {
+kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr) CF_RETURNS_RETAINED;
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) CF_RETURNS_RETAINED ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) CF_RETURNS_RETAINED ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+- (NSString *)description;
+- (instancetype)init;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
++ (id)new;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end
+@interface NSNumber : NSValue
+- (char)charValue;
+- (instancetype)initWithInt:(int)value;
++ (NSNumber *)numberWithInt:(int)value;
+@end
+@class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (instancetype)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (instancetype)arrayWithObject:(id)anObject;
++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (instancetype)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (instancetype)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (instancetype)initWithArray:(NSArray *)array;
+@end @interface NSArray (NSArrayCreation) + (instancetype)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- ( const char *)UTF8String;
+- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
++ (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
++ (instancetype)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
++ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+@end typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
+typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator );
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing );
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); // expected-note {{'IOServiceAddNotification' declared here}}
+kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef CF_CONSUMED matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification );
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+CFMutableDictionaryRef IOServiceMatching( const char * name );
+CFMutableDictionaryRef IOServiceNameMatching( const char * name );
+CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID );
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator ) CF_RETURNS_RETAINED;
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name ) CF_RETURNS_RETAINED;
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media ) CF_RETURNS_RETAINED;
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk ) CF_RETURNS_RETAINED;
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk ) CF_RETURNS_RETAINED;
+@interface NSTask : NSObject - (instancetype)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+@end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ) CF_RETURNS_RETAINED;
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r CF_RETURNS_RETAINED;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs CF_RETURNS_RETAINED;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d CF_RETURNS_RETAINED;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end enum {
+ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+ space, const CGFloat components[], const CGFloat locations[], size_t count) CF_RETURNS_RETAINED;
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+ CFArrayRef colors, const CGFloat locations[]) CF_RETURNS_RETAINED;
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+extern void CGGradientRelease(CGGradientRef gradient);
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+ CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+ CGGradientDrawingOptions options);
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+
+@interface NSMutableArray : NSObject
+- (void)addObject:(id)object;
++ (instancetype)array;
+@end
+
+// This is how NSMakeCollectable is declared in the OS X 10.8 headers.
+id NSMakeCollectable(CFTypeRef __attribute__((cf_consumed))) __attribute__((ns_returns_retained));
+
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern
+void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryUUID, CFUUIDRef typeUUID);
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+CFAbsoluteTime f1() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
+ return t;
+}
+
+CFAbsoluteTime f2() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
+ return t;
+}
+
+
+NSDate* global_x;
+
+// Test to see if we supresss an error when we store the pointer
+// to a global.
+
+CFAbsoluteTime f3() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ global_x = (NSDate*) date;
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ return t;
+}
+
+//---------------------------------------------------------------------------
+// Test case 'f4' differs for region store and basic store. See
+// retain-release-region-store.m and retain-release-basic-store.m.
+//---------------------------------------------------------------------------
+
+// Test a leak.
+
+CFAbsoluteTime f5(int x) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // expected-warning{{leak}}
+
+ if (x)
+ CFRelease(date);
+
+ return t;
+}
+
+// Test a leak involving the return.
+
+CFDateRef f6(int x) {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
+ CFRetain(date);
+ date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning {{leak}}
+ return date;
+}
+
+// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and
+// has the word create.
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+CFDateRef MyDateCreate();
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+
+CFDateRef f8() {
+ CFDateRef date = MyDateCreate(); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+__attribute__((cf_returns_retained)) CFDateRef f9() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // no-warning
+ int *p = 0;
+ // When allocations fail, CFDateCreate can return null.
+ if (!date) *p = 1; // expected-warning{{null}}
+ return date;
+}
+
+// Handle DiskArbitration API:
+//
+// http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/DiscArbitrationFramework/
+//
+void f10(io_service_t media, DADiskRef d, CFStringRef s) {
+ DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, 0, "hello"); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, 0, media); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ CFDictionaryRef dict = DADiskCopyDescription(d); // expected-warning{{leak}}
+ if (dict) NSLog(@"ok");
+
+ disk = DADiskCopyWholeDisk(d); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault, // expected-warning{{leak}}
+ kDAReturnSuccess, s);
+ if (dissenter) NSLog(@"ok");
+
+ DASessionRef session = DASessionCreate(kCFAllocatorDefault); // expected-warning{{leak}}
+ if (session) NSLog(@"ok");
+}
+
+// Test retain/release checker with CFString and CFMutableArray.
+void f11() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+
+ // Create a string.
+ CFStringRef s1 = CFStringCreateWithCString(0, "hello world",
+ kCFStringEncodingUTF8);
+
+ // Add the string to the array.
+ CFArrayAppendValue(A, s1);
+
+ // Decrement the reference count.
+ CFRelease(s1); // no-warning
+
+ // Get the string. We don't own it.
+ s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0);
+
+ // Release the array.
+ CFRelease(A); // no-warning
+
+ // Release the string. This is a bug.
+ CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3337: Handle functions declared using typedefs.
+typedef CFTypeRef CREATEFUN();
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+CFTypeRef MyCreateFun();
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+
+void f12() {
+ CFTypeRef o = MyCreateFun(); // expected-warning {{leak}}
+}
+
+void f13_autorelease() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+ [(id) A autorelease]; // no-warning
+}
+
+void f13_autorelease_b() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+} // expected-warning{{Object autoreleased too many times}}
+
+CFMutableArrayRef f13_autorelease_c() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ return A; // expected-warning{{Object autoreleased too many times}}
+}
+
+CFMutableArrayRef f13_autorelease_d() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ CFMutableArrayRef B = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Object autoreleased too many times}}
+ CFRelease(B); // no-warning
+ while (1) {}
+}
+
+
+// This case exercises the logic where the leak site is the same as the allocation site.
+void f14_leakimmediately() {
+ CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}}
+}
+
+// Test that we track an allocated object beyond the point where the *name*
+// of the variable storing the reference is no longer live.
+void f15() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ CFMutableArrayRef *B = &A;
+ // At this point, the name 'A' is no longer live.
+ CFRelease(*B); // no-warning
+}
+
+// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
+void f16(int x, CFTypeRef p) {
+ if (p)
+ return;
+
+ if (x > 0) {
+ CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
+ }
+ else if (x < 0) {
+ CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
+ }
+ else {
+ CFMakeCollectable(p); // expected-warning{{Null pointer argument in call to CFMakeCollectable}}
+ }
+}
+
+// Test that an object is non-null after being CFRetained/CFReleased.
+void f17(int x, CFTypeRef p) {
+ if (x > 0) {
+ CFRelease(p);
+ if (!p)
+ CFRelease(0); // no-warning
+ }
+ else if (x < 0) {
+ CFRetain(p);
+ if (!p)
+ CFRetain(0); // no-warning
+ }
+ else {
+ CFMakeCollectable(p);
+ if (!p)
+ CFMakeCollectable(0); // no-warning
+ }
+}
+
+// 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.
+@interface SelfIvarTest : NSObject {
+ id myObj;
+}
+- (void)test_self_tracking;
+@end
+
+@implementation SelfIvarTest
+- (void)test_self_tracking {
+ myObj = (id) CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+@end
+
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+@interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+@end
+
+@implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"];
+ return s; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+@end
+
+// <rdar://problem/6659160>
+int isFoo(char c);
+
+static void rdar_6659160(char *inkind, char *inname)
+{
+ // We currently expect that [NSObject alloc] cannot fail. This
+ // will be a toggled flag in the future. It can indeed return null, but
+ // Cocoa programmers generally aren't expected to reason about out-of-memory
+ // conditions.
+ NSString *kind = [[NSString alloc] initWithUTF8String:inkind]; // expected-warning{{leak}}
+
+ // We do allow stringWithUTF8String to fail. This isn't really correct, as
+ // far as returning 0. In most error conditions it will throw an exception.
+ // If allocation fails it could return 0, but again this
+ // isn't expected.
+ NSString *name = [NSString stringWithUTF8String:inname];
+ if(!name)
+ return;
+
+ const char *kindC = 0;
+ const char *nameC = 0;
+
+ // In both cases, we cannot reach a point down below where we
+ // dereference kindC or nameC with either being null. This is because
+ // we assume that [NSObject alloc] doesn't fail and that we have the guard
+ // up above.
+
+ if(kind)
+ kindC = [kind UTF8String];
+ if(name)
+ nameC = [name UTF8String];
+ if(!isFoo(kindC[0])) // expected-warning{{null}}
+ return;
+ if(!isFoo(nameC[0])) // no-warning
+ return;
+
+ [kind release];
+ [name release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3677 - 'allocWithZone' should be treated as following the Cocoa naming
+// conventions with respect to 'return'ing ownership.
+@interface PR3677: NSObject @end
+@implementation PR3677
++ (id)allocWithZone:(NSZone *)inZone {
+ return [super allocWithZone:inZone]; // no-warning
+}
+@end
+
+// PR 3820 - Reason about calls to -dealloc
+void pr3820_DeallocInsteadOfRelease(void)
+{
+ id foo = [[NSString alloc] init]; // no-warning
+ [foo dealloc];
+ // foo is not leaked, since it has been deallocated.
+}
+
+void pr3820_ReleaseAfterDealloc(void)
+{
+ id foo = [[NSString alloc] init];
+ [foo dealloc];
+ [foo release]; // expected-warning{{used after it is release}}
+ // NSInternalInconsistencyException: message sent to deallocated object
+}
+
+void pr3820_DeallocAfterRelease(void)
+{
+ NSLog(@"\n\n[%s]", __FUNCTION__);
+ id foo = [[NSString alloc] init];
+ [foo release];
+ [foo dealloc]; // expected-warning{{used after it is released}}
+ // message sent to released object
+}
+
+// From <rdar://problem/6704930>. The problem here is that 'length' binds to
+// '($0 - 1)' after '--length', but SimpleConstraintManager doesn't know how to
+// reason about '($0 - 1) > constant'. As a temporary hack, we drop the value
+// of '($0 - 1)' and conjure a new symbol.
+void rdar6704930(unsigned char *s, unsigned int length) {
+ NSString* name = 0;
+ if (s != 0) {
+ if (length > 0) {
+ while (length > 0) {
+ if (*s == ':') {
+ ++s;
+ --length;
+ name = [[NSString alloc] init]; // no-warning
+ break;
+ }
+ ++s;
+ --length;
+ }
+ if ((length == 0) && (name != 0)) {
+ [name release];
+ name = 0;
+ }
+ if (length == 0) { // no ':' found -> use it all as name
+ name = [[NSString alloc] init]; // no-warning
+ }
+ }
+ }
+
+ if (name != 0) {
+ [name release];
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6833332>
+// One build of the analyzer accidentally stopped tracking the allocated
+// object after the 'retain'.
+//===----------------------------------------------------------------------===//
+
+@interface rdar_6833332 : NSObject <NSApplicationDelegate> {
+ NSWindow *window;
+}
+@property (nonatomic, retain) NSWindow *window;
+@end
+
+@implementation rdar_6833332
+@synthesize window;
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+
+ [dict setObject:@"foo" forKey:@"bar"];
+
+ NSLog(@"%@", dict);
+}
+- (void)dealloc {
+ [window release];
+ [super dealloc];
+}
+
+- (void)radar10102244 {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+ if (window)
+ NSLog(@"%@", window);
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6257780> clang checker fails to catch use-after-release
+//===----------------------------------------------------------------------===//
+
+int rdar_6257780_Case1() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSArray *array = [NSArray array];
+ [array release]; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+ [pool drain];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/10640253> Analyzer is confused about NSAutoreleasePool -allocWithZone:.
+//===----------------------------------------------------------------------===//
+
+void rdar_10640253_autorelease_allocWithZone() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:(NSZone*)0] init];
+ (void) pool;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6866843> Checker should understand new/setObject:/release constructs
+//===----------------------------------------------------------------------===//
+
+void rdar_6866843() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSMutableDictionary* dictionary = [[NSMutableDictionary alloc] init];
+ NSArray* array = [[NSArray alloc] init];
+ [dictionary setObject:array forKey:@"key"];
+ [array release];
+ // Using 'array' here should be fine
+ NSLog(@"array = %@\n", array); // no-warning
+ // Now the array is released
+ [dictionary release];
+ [pool drain];
+}
+
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6877235> Classes typedef-ed to CF objects should get the same treatment as CF objects
+//===----------------------------------------------------------------------===//
+
+typedef CFTypeRef OtherRef;
+
+@interface RDar6877235 : NSObject {}
+- (CFTypeRef)_copyCFTypeRef CF_RETURNS_RETAINED;
+- (OtherRef)_copyOtherRef CF_RETURNS_RETAINED;
+@end
+
+@implementation RDar6877235
+- (CFTypeRef)_copyCFTypeRef {
+ return [[NSString alloc] init]; // no-warning
+}
+- (OtherRef)_copyOtherRef {
+ return [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6320065> false positive - init method returns an object
+// owned by caller
+//===----------------------------------------------------------------------===//
+
+@interface RDar6320065 : NSObject {
+ NSString *_foo;
+}
+- (instancetype)initReturningNewClass;
+- (id)_initReturningNewClassBad;
+- (instancetype)initReturningNewClassBad2;
+@end
+
+@interface RDar6320065Subclass : RDar6320065
+@end
+
+@implementation RDar6320065
+- (instancetype)initReturningNewClass {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init]; // no-warning
+ return self;
+}
+- (id)_initReturningNewClassBad {
+ [self release];
+ [[RDar6320065Subclass alloc] init]; // expected-warning {{leak}}
+ return self;
+}
+- (instancetype)initReturningNewClassBad2 {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init];
+ return [self autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+@end
+
+@implementation RDar6320065Subclass
+@end
+
+int RDar6320065_test() {
+ RDar6320065 *test = [[RDar6320065 alloc] init]; // no-warning
+ [test release];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7129086> -awakeAfterUsingCoder: returns an owned object
+// and claims the receiver
+//===----------------------------------------------------------------------===//
+
+@interface RDar7129086 : NSObject {} @end
+@implementation RDar7129086
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder {
+ [self release]; // no-warning
+ return [NSString alloc]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a
+// retained object
+//===----------------------------------------------------------------------===//
+
+@interface RDar6859457 : NSObject {}
+- (NSString*) NoCopyString;
+- (NSString*) noCopyString;
+@end
+
+@implementation RDar6859457
+- (NSString*) NoCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}}
+- (NSString*) noCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}}
+@end
+
+void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) {
+ [x NoCopyString]; // expected-warning{{leak}}
+ [x noCopyString]; // expected-warning{{leak}}
+ [NSData dataWithBytesNoCopy:bytes length:dataLength]; // no-warning
+ [NSData dataWithBytesNoCopy:bytes length:dataLength freeWhenDone:1]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// PR 4230 - an autorelease pool is not necessarily leaked during a premature
+// return
+//===----------------------------------------------------------------------===//
+
+static void PR4230(void)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
+static void PR4230_new(void)
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
+//===----------------------------------------------------------------------===//
+// Method name that has a null IdentifierInfo* for its first selector slot.
+// This test just makes sure that we handle it.
+//===----------------------------------------------------------------------===//
+
+@interface TestNullIdentifier
+@end
+
+@implementation TestNullIdentifier
++ (id):(int)x, ... {
+ return [[NSString alloc] init]; // expected-warning{{leak}}
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6893565> don't flag leaks for return types that cannot be
+// determined to be CF types
+//===----------------------------------------------------------------------===//
+
+// We don't know if 'struct s6893565' represents a Core Foundation type, so
+// we shouldn't emit an error here.
+typedef struct s6893565* TD6893565;
+
+@interface RDar6893565 {}
+-(TD6893565)newThing;
+@end
+
+@implementation RDar6893565
+-(TD6893565)newThing {
+ return (TD6893565) [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6902710> clang: false positives w/QC and CoreImage methods
+//===----------------------------------------------------------------------===//
+
+void rdar6902710(QCView *view, QCRenderer *renderer, CIContext *context,
+ NSString *str, CIImage *img, CGRect rect,
+ CIFormat form, CGColorSpaceRef cs) {
+ [view createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [renderer createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6945561> -[CIContext createCGLayerWithSize:info:]
+// misinterpreted by clang scan-build
+//===----------------------------------------------------------------------===//
+
+void rdar6945561(CIContext *context, CGSize size, CFDictionaryRef d) {
+ [context createCGLayerWithSize:size info:d]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6961230> add knowledge of IOKit functions to retain/release
+// checker
+//===----------------------------------------------------------------------===//
+
+void IOBSDNameMatching_wrapper(mach_port_t masterPort, uint32_t options, const char * bsdName) {
+ IOBSDNameMatching(masterPort, options, bsdName); // expected-warning{{leak}}
+}
+
+void IOServiceMatching_wrapper(const char * name) {
+ IOServiceMatching(name); // expected-warning{{leak}}
+}
+
+void IOServiceNameMatching_wrapper(const char * name) {
+ IOServiceNameMatching(name); // expected-warning{{leak}}
+}
+
+CF_RETURNS_RETAINED CFDictionaryRef CreateDict();
+
+void IOServiceAddNotification_wrapper(mach_port_t masterPort, const io_name_t notificationType,
+ mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) {
+
+ CFDictionaryRef matching = CreateDict();
+ CFRelease(matching);
+ IOServiceAddNotification(masterPort, notificationType, matching, // expected-warning{{used after it is released}} expected-warning{{deprecated}}
+ wakePort, reference, notification);
+}
+
+void IORegistryEntryIDMatching_wrapper(uint64_t entryID ) {
+ IORegistryEntryIDMatching(entryID); // expected-warning{{leak}}
+}
+
+void IOOpenFirmwarePathMatching_wrapper(mach_port_t masterPort, uint32_t options,
+ const char * path) {
+ IOOpenFirmwarePathMatching(masterPort, options, path); // expected-warning{{leak}}
+}
+
+void IOServiceGetMatchingService_wrapper(mach_port_t masterPort) {
+ CFDictionaryRef matching = CreateDict();
+ IOServiceGetMatchingService(masterPort, matching);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+void IOServiceGetMatchingServices_wrapper(mach_port_t masterPort, io_iterator_t *existing) {
+ CFDictionaryRef matching = CreateDict();
+ IOServiceGetMatchingServices(masterPort, matching, existing);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort, const io_name_t notificationType,
+ IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification) {
+
+ CFDictionaryRef matching = CreateDict();
+ IOServiceAddMatchingNotification(notifyPort, notificationType, matching, callback, refCon, notification);
+ CFRelease(matching); // expected-warning{{used after it is released}}
+}
+
+//===----------------------------------------------------------------------===//
+// Test of handling objects whose references "escape" to containers.
+//===----------------------------------------------------------------------===//
+
+void CFDictionaryAddValue(CFMutableDictionaryRef, void *, void *);
+
+// <rdar://problem/6539791>
+void rdar_6539791(CFMutableDictionaryRef y, void* key, void* val_key) {
+ CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryAddValue(y, key, x);
+ CFRelease(x); // the dictionary keeps a reference, so the object isn't deallocated yet
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ if (value) {
+ CFDictionaryAddValue(x, val_key, (void*)value); // no-warning
+ CFRelease(value);
+ CFDictionaryAddValue(y, val_key, (void*)value); // no-warning
+ }
+}
+
+// <rdar://problem/6560661>
+// Same issue, except with "AppendValue" functions.
+void rdar_6560661(CFMutableArrayRef x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ // CFArrayAppendValue keeps a reference to value.
+ CFArrayAppendValue(x, value);
+ CFRelease(value);
+ CFRetain(value);
+ CFRelease(value); // no-warning
+}
+
+// <rdar://problem/7152619>
+// Same issue, excwept with "CFAttributeStringSetAttribute".
+void rdar_7152619(CFStringRef str) {
+ CFAttributedStringRef string = CFAttributedStringCreate(kCFAllocatorDefault, str, 0);
+ CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 100, string);
+ CFRelease(string);
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+ CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 1), str, number);
+ [number release];
+ [number retain];
+ CFRelease(attrString);
+}
+
+//===----------------------------------------------------------------------===//
+// Test of handling CGGradientXXX functions.
+//===----------------------------------------------------------------------===//
+
+void rdar_7184450(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), // expected-warning{{leak}}
+ components, locations, num_locations);
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+ CGGradientRelease(myGradient);
+}
+
+void rdar_7184450_pos(CGContextRef myContext, CGFloat x, CGPoint myStartPoint,
+ CGPoint myEndPoint) {
+ size_t num_locations = 6;
+ CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 };
+ CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0,
+ x, // Start color
+ 207.0/255.0, 39.0/255.0, 39.0/255.0, x,
+ 147.0/255.0, 21.0/255.0, 22.0/255.0, x,
+ 175.0/255.0, 175.0/255.0, 175.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x,
+ 255.0/255.0,255.0/255.0, 255.0/255.0, x
+ }; // End color
+
+ CGGradientRef myGradient =
+ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), components, locations, num_locations); // expected-warning 2 {{leak}}
+
+ CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint,
+ 0);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7299394> clang false positive: retained instance passed to
+// thread in pthread_create marked as leak
+//
+// Until we have full IPA, the analyzer should stop tracking the reference
+// count of objects passed to pthread_create.
+//
+//===----------------------------------------------------------------------===//
+
+struct _opaque_pthread_t {};
+struct _opaque_pthread_attr_t {};
+typedef struct _opaque_pthread_t *__darwin_pthread_t;
+typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
+typedef __darwin_pthread_t pthread_t;
+typedef __darwin_pthread_attr_t pthread_attr_t;
+typedef unsigned long __darwin_pthread_key_t;
+typedef __darwin_pthread_key_t pthread_key_t;
+
+int pthread_create(pthread_t *, const pthread_attr_t *,
+ void *(*)(void *), void *);
+
+int pthread_setspecific(pthread_key_t key, const void *value);
+
+void *rdar_7299394_start_routine(void *p) {
+ [((id) p) release];
+ return 0;
+}
+void rdar_7299394(pthread_attr_t *attr, pthread_t *thread, void *args) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ pthread_create(thread, attr, rdar_7299394_start_routine, number);
+}
+void rdar_7299394_positive(pthread_attr_t *attr, pthread_t *thread) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/11282706> false positive with not understanding thread
+// local storage
+//===----------------------------------------------------------------------===//
+
+void rdar11282706(pthread_key_t key) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ pthread_setspecific(key, (void*) number);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7283567> False leak associated with call to
+// CVPixelBufferCreateWithBytes ()
+//
+// According to the Core Video Reference (ADC), CVPixelBufferCreateWithBytes and
+// CVPixelBufferCreateWithPlanarBytes can release (via a callback) the
+// pixel buffer object. These test cases show how the analyzer stops tracking
+// the reference count for the objects passed for this argument. This
+// could be made smarter.
+//===----------------------------------------------------------------------===//
+
+typedef int int32_t;
+typedef UInt32 FourCharCode;
+typedef FourCharCode OSType;
+typedef uint64_t CVOptionFlags;
+typedef int32_t CVReturn;
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVImageBufferRef;
+typedef CVImageBufferRef CVPixelBufferRef;
+typedef void (*CVPixelBufferReleaseBytesCallback)( void *releaseRefCon, const void *baseAddress );
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+typedef void (*CVPixelBufferReleasePlanarBytesCallback)( void *releaseRefCon, const void *dataPtr, size_t dataSize, size_t numberOfPlanes, const void *planeAddresses[] );
+
+extern CVReturn CVPixelBufferCreateWithPlanarBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *dataPtr,
+ size_t dataSize,
+ size_t numberOfPlanes,
+ void *planeBaseAddress[],
+ size_t planeWidth[],
+ size_t planeHeight[],
+ size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator,
+ size_t width,
+ size_t height,
+ OSType pixelFormatType,
+ void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ void *releaseRefCon,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) ;
+
+CVReturn rdar_7283567(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *baseAddress,
+ size_t bytesPerRow,
+ CVPixelBufferReleaseBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithBytes(allocator, width, height, pixelFormatType,
+ baseAddress, bytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height,
+ OSType pixelFormatType, void *dataPtr, size_t dataSize,
+ size_t numberOfPlanes, void *planeBaseAddress[],
+ size_t planeWidth[], size_t planeHeight[], size_t planeBytesPerRow[],
+ CVPixelBufferReleasePlanarBytesCallback releaseCallback,
+ CFDictionaryRef pixelBufferAttributes,
+ CVPixelBufferRef *pixelBufferOut) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ return CVPixelBufferCreateWithPlanarBytes(allocator,
+ width, height, pixelFormatType, dataPtr, dataSize,
+ numberOfPlanes, planeBaseAddress, planeWidth,
+ planeHeight, planeBytesPerRow, releaseCallback,
+ number, // potentially released by callback
+ pixelBufferAttributes, pixelBufferOut) ;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7358899> False leak associated with
+// CGBitmapContextCreateWithData
+//===----------------------------------------------------------------------===//
+typedef uint32_t CGBitmapInfo;
+typedef void (*CGBitmapContextReleaseDataCallback)(void *releaseInfo, void *data);
+
+CGContextRef CGBitmapContextCreateWithData(void *data,
+ size_t width, size_t height, size_t bitsPerComponent,
+ size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo,
+ CGBitmapContextReleaseDataCallback releaseCallback, void *releaseInfo) CF_RETURNS_RETAINED;
+
+void rdar_7358899(void *data,
+ size_t width, size_t height, size_t bitsPerComponent,
+ size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo,
+ CGBitmapContextReleaseDataCallback releaseCallback) {
+
+ // For the allocated object, it doesn't really matter what type it is
+ // for the purpose of this test. All we want to show is that
+ // this is freed later by the callback.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+
+ CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, // expected-warning{{leak}}
+ bytesPerRow, space, bitmapInfo, releaseCallback, number);
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7265711> allow 'new', 'copy', 'alloc', 'init' prefix to
+// start before '_' when determining Cocoa fundamental rule
+//
+// Previously the retain/release checker just skipped prefixes before the
+// first '_' entirely. Now the checker honors the prefix if it results in a
+// recognizable naming convention (e.g., 'new', 'init').
+//===----------------------------------------------------------------------===//
+
+@interface RDar7265711 {}
+- (id) new_stuff;
+@end
+
+void rdar7265711_a(RDar7265711 *x) {
+ id y = [x new_stuff]; // expected-warning{{leak}}
+}
+
+void rdar7265711_b(RDar7265711 *x) {
+ id y = [x new_stuff]; // no-warning
+ [y release];
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7306898> clang thinks [NSCursor dragCopyCursor] returns a
+// retained reference
+//===----------------------------------------------------------------------===//
+
+@interface NSCursor : NSObject
++ (NSCursor *)dragCopyCursor;
+@end
+
+void rdar7306898(void) {
+ // 'dragCopyCursor' does not follow Cocoa's fundamental rule. It is a noun, not an sentence
+ // implying a 'copy' of something.
+ NSCursor *c = [NSCursor dragCopyCursor]; // no-warning
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7252064> sending 'release', 'retain', etc. to a Class
+// directly is not likely what the user intended
+//===----------------------------------------------------------------------===//
+
+@interface RDar7252064 : NSObject @end
+void rdar7252064(void) {
+ [RDar7252064 release]; // expected-warning{{The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [RDar7252064 retain]; // expected-warning{{The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [RDar7252064 autorelease]; // expected-warning{{The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly}}
+ [NSAutoreleasePool drain]; // expected-warning{{method '+drain' not found}} expected-warning{{The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly}}
+}
+
+//===----------------------------------------------------------------------===//
+// Tests of ownership attributes.
+//===----------------------------------------------------------------------===//
+
+typedef NSString* MyStringTy;
+
+@protocol FooP;
+
+@interface TestOwnershipAttr : NSObject
+- (NSString*) returnsAnOwnedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) returnsAnOwnedCFString CF_RETURNS_RETAINED; // no-warning
+- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+- (NSString*) newString_auto NS_RETURNS_AUTORELEASED; // no-warning
+- (NSString*) newStringNoAttr;
+- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
+- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
++ (void) consume:(id) NS_CONSUMED x;
++ (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}}
+
+void test_attr_1(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
+}
+
+void test_attr_1b(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}}
+}
+
+void test_attr1c(TestOwnershipAttr *X) {
+ NSString *str = [X newString]; // no-warning
+ NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}}
+ NSString *str3 = [X newString_auto]; // no-warning
+ NSString *str4 = [[X newString_auto] retain]; // expected-warning {{leak}}
+}
+
+void testattr2_a() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // expected-warning{{leak}}
+}
+
+void testattr2_b() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // expected-warning{{leak}}
+}
+
+void testattr2_b_11358224_self_assign_looses_the_leak() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit];// expected-warning{{leak}}
+ x = x;
+}
+
+void testattr2_c() {
+ TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // no-warning
+ [x release];
+}
+
+void testattr3() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+ [TestOwnershipAttr consume:x];
+ TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+ [TestOwnershipAttr consume2:y];
+}
+
+void consume_ns(id NS_CONSUMED x);
+void consume_cf(id CF_CONSUMED x);
+
+void testattr4() {
+ TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+ consume_ns(x);
+ TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+ consume_cf(y);
+}
+
+@interface TestOwnershipAttr2 : NSObject
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+@end
+
+@implementation TestOwnershipAttr2
+- (NSString*) newString {
+ return [NSString alloc]; // expected-warning {{Potential leak of an object}}
+}
+@end
+
+@interface MyClassTestCFAttr : NSObject {}
+- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
+- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
+- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
+- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED;
+- (NSDate*) alsoReturnsRetained;
+- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED;
+- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
+@end
+
+CF_RETURNS_RETAINED
+CFDateRef returnsRetainedCFDate() {
+ return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+}
+
+@implementation MyClassTestCFAttr
+- (NSDate*) returnsCFRetained {
+ return (NSDate*) returnsRetainedCFDate(); // No leak.
+}
+
+- (CFDateRef) returnsCFRetainedAsCF {
+ return returnsRetainedCFDate(); // No leak.
+}
+
+- (CFDateRef) newCFRetainedAsCF {
+ return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease];
+}
+
+- (CFDateRef) newCFRetainedAsCFNoAttr {
+ return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+- (NSDate*) alsoReturnsRetained {
+ return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}}
+}
+
+- (CFDateRef) alsoReturnsRetainedAsCF {
+ return returnsRetainedCFDate(); // expected-warning{{leak}}
+}
+
+
+- (NSDate*) returnsNSRetained {
+ return (NSDate*) returnsRetainedCFDate(); // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// Test that leaks post-dominated by "panic" functions are not reported.
+//
+// <rdar://problem/5905851> do not report a leak when post-dominated by a call
+// to a noreturn or panic function
+//===----------------------------------------------------------------------===//
+
+void panic() __attribute__((noreturn));
+void panic_not_in_hardcoded_list() __attribute__((noreturn));
+
+void test_panic_negative() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+}
+
+void test_panic_positive() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ panic();
+}
+
+void test_panic_neg_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+ if (x)
+ panic();
+}
+
+void test_panic_pos_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ if (x)
+ panic();
+ if (!x) {
+ // This showed up in <rdar://problem/7796563>, where we silently missed checking
+ // the function type for noreturn. "panic()" is a hard-coded known panic function
+ // that isn't always noreturn.
+ panic_not_in_hardcoded_list();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test uses of blocks (closures)
+//===----------------------------------------------------------------------===//
+
+void test_blocks_1_pos(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}}
+ ^{}();
+}
+
+void test_blocks_1_indirect_release(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^{ [number release]; }();
+}
+
+void test_blocks_1_indirect_retain(void) {
+ // Eventually this should be reported as a leak.
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^{ [number retain]; }();
+}
+
+void test_blocks_1_indirect_release_via_call(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
+ ^(NSObject *o){ [o release]; }(number);
+}
+
+void test_blocks_1_indirect_retain_via_call(void) {
+ NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning {{leak}}
+ ^(NSObject *o){ [o retain]; }(number);
+}
+
+//===--------------------------------------------------------------------===//
+// Test sending message to super that returns an object alias. Previously
+// this caused a crash in the analyzer.
+//===--------------------------------------------------------------------===//
+
+@interface Rdar8015556 : NSObject {} @end
+@implementation Rdar8015556
+- (id)retain {
+ return [super retain];
+}
+@end
+
+// <rdar://problem/8272168> - Correcly handle Class<...> in Cocoa Conventions
+// detector.
+
+@protocol Prot_R8272168 @end
+Class <Prot_R8272168> GetAClassThatImplementsProt_R8272168();
+void r8272168() {
+ GetAClassThatImplementsProt_R8272168();
+}
+
+// Test case for <rdar://problem/8356342>, which in the past triggered
+// a false positive.
+@interface RDar8356342
+- (NSDate*) rdar8356342:(NSDate *)inValue;
+@end
+
+@implementation RDar8356342
+- (NSDate*) rdar8356342:(NSDate*)inValue {
+ NSDate *outValue = inValue;
+ if (outValue == 0)
+ outValue = [[NSDate alloc] init]; // no-warning
+
+ if (outValue != inValue)
+ [outValue autorelease];
+
+ return outValue;
+}
+@end
+
+// <rdar://problem/8724287> - This test case previously crashed because
+// of a bug in BugReporter.
+extern const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key) CF_RETURNS_NOT_RETAINED;
+typedef struct __CFError * CFErrorRef;
+extern const CFStringRef kCFErrorUnderlyingErrorKey;
+extern CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) CF_RETURNS_RETAINED;
+static void rdar_8724287(CFErrorRef error)
+{
+ CFErrorRef error_to_dump;
+
+ error_to_dump = error;
+ while (error_to_dump != ((void*)0)) {
+ CFDictionaryRef info;
+
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object}}
+
+ if (info != ((void*)0)) {
+ }
+
+ error_to_dump = (CFErrorRef) CFDictionaryGetValue(info, kCFErrorUnderlyingErrorKey);
+ }
+}
+
+// <rdar://problem/9234108> - Make sure the model applies cf_consumed
+// correctly in argument positions besides the first.
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+extern void *CFStringCreate(void);
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value);
+void rdar_9234108() {
+ rdar_9234108_helper(0, CFStringCreate());
+}
+
+// <rdar://problem/9726279> - Make sure that objc_method_family works
+// to override naming conventions.
+struct TwoDoubles {
+ double one;
+ double two;
+};
+typedef struct TwoDoubles TwoDoubles;
+
+@interface NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles __attribute__((objc_method_family(init)));
+@end
+
+@implementation NSValue (Mine)
+- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles
+{
+ return [self init];
+}
+@end
+
+void rdar9726279() {
+ TwoDoubles twoDoubles = { 0.0, 0.0 };
+ NSValue *value = [[NSValue alloc] _prefix_initWithTwoDoubles:twoDoubles];
+ [value release];
+}
+
+// <rdar://problem/9732321>
+// Test camelcase support for CF conventions. While Core Foundation APIs
+// don't use camel casing, other code is allowed to use it.
+CFArrayRef camelcase_create_1() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_createno() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camelcase_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camelcase_copying() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __copyCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef __createCamelCase() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_create() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+
+CFArrayRef camel_creat() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+CFArrayRef camel_copy() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copyMachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+
+CFArrayRef camel_copymachine() {
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
+}
+
+// rdar://problem/8024350
+@protocol F18P
+- (id) clone;
+@end
+@interface F18 : NSObject<F18P> @end
+@interface F18(Cat)
+- (id) clone NS_RETURNS_RETAINED;
+@end
+
+@implementation F18
+- (id) clone {
+ return [F18 alloc];
+}
+@end
+
+// Radar 6582778.
+void rdar6582778(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFTypeRef vals[] = { CFDateCreate(0, t) }; // expected-warning {{leak}}
+}
+
+CFTypeRef global;
+
+void rdar6582778_2(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ global = CFDateCreate(0, t); // no-warning
+}
+
+// <rdar://problem/10232019> - Test that objects passed to containers
+// are marked "escaped".
+
+void rdar10232019() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [array addObject:string];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // no-warning
+ NSLog(@"%@", otherString);
+}
+
+void rdar10232019_positive() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // expected-warning {{Reference-counted object is used after it is release}}
+ NSLog(@"%@", otherString);
+}
+
+// RetainCountChecker support for XPC.
+// <rdar://problem/9658496>
+typedef void * xpc_object_t;
+xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef cf);
+void xpc_release(xpc_object_t object);
+
+void rdar9658496() {
+ CFStringRef cf;
+ xpc_object_t xpc;
+ cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ xpc = _CFXPCCreateXPCObjectFromCFObject( cf );
+ CFRelease(cf);
+ xpc_release(xpc);
+}
+
+// Support annotations with method families.
+@interface RDar10824732 : NSObject
+- (instancetype)initWithObj:(id CF_CONSUMED)obj;
+@end
+
+@implementation RDar10824732
+- (instancetype)initWithObj:(id)obj {
+ [obj release];
+ return [super init];
+}
+@end
+
+void rdar_10824732() {
+ @autoreleasepool {
+ NSString *obj = @"test";
+ RDar10824732 *foo = [[RDar10824732 alloc] initWithObj:obj]; // no-warning
+ [foo release];
+ }
+}
+
+// Stop tracking objects passed to functions, which take callbacks as parameters.
+// radar://10973977
+typedef int (*CloseCallback) (void *);
+void ReaderForIO(CloseCallback ioclose, void *ioctx);
+int IOClose(void *context);
+
+@protocol SInS <NSObject>
+@end
+
+@interface radar10973977 : NSObject
+- (id<SInS>)inputS;
+- (void)reader;
+@end
+
+@implementation radar10973977
+- (void)reader
+{
+ id<SInS> inputS = [[self inputS] retain];
+ ReaderForIO(IOClose, inputS);
+}
+- (id<SInS>)inputS
+{
+ return 0;
+}
+@end
+
+// Object escapes through a selector callback: radar://11398514
+extern id NSApp;
+@interface MySheetController
+- (id<SInS>)inputS;
+- (void)showDoSomethingSheetAction:(id)action;
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+
+@implementation MySheetController
+- (id<SInS>)inputS {
+ return 0;
+}
+- (void)showDoSomethingSheetAction:(id)action {
+ id<SInS> inputS = [[self inputS] retain];
+ [NSApp beginSheet:0
+ modalForWindow:0
+ modalDelegate:0
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:(void *)inputS]; // no - warning
+}
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
+
+ id contextObject = (id)contextInfo;
+ [contextObject release];
+}
+
+- (id)copyAutoreleaseRadar13081402 {
+ id x = [[[NSString alloc] initWithUTF8String:"foo"] autorelease];
+ [x retain];
+ return x; // no warning
+}
+
+@end
+//===----------------------------------------------------------------------===//
+// Test returning allocated memory in a struct.
+//
+// We currently don't have a general way to track pointers that "escape".
+// Here we test that RetainCountChecker doesn't get excited about returning
+// allocated CF objects in struct fields.
+//===----------------------------------------------------------------------===//
+void *malloc(size_t);
+struct rdar11104566 { CFStringRef myStr; };
+struct rdar11104566 test_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 V;
+ V.myStr = cf;
+ return V; // no-warning
+}
+
+struct rdar11104566 *test_2_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 *V = (struct rdar11104566 *) malloc(sizeof(*V));
+ V->myStr = cf;
+ return V; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// ObjC literals support.
+//===----------------------------------------------------------------------===//
+
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; // expected-warning {{leak}}
+ [o release];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1]; // expected-warning {{leak}}
+ [o release];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = [@[o] retain]; // expected-warning {{leak}}
+ [o release];
+ [a3 description];
+ [o description];
+ }
+
+ { // CASE FOUR -- OBJECT IN ARRAY CREATED BY DUPING @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithArray:@[o]]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+
+ { // CASE FIVE -- OBJECT IN RETAINED @{}
+ NSValue *o = [[NSValue alloc] init];
+ NSDictionary *a = [@{o : o} retain]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+}
+
+void test_objc_integer_literals() {
+ id value = [@1 retain]; // expected-warning {{leak}}
+ [value description];
+}
+
+void test_objc_boxed_expressions(int x, const char *y) {
+ id value = [@(x) retain]; // expected-warning {{leak}}
+ [value description];
+
+ value = [@(y) retain]; // expected-warning {{leak}}
+ [value description];
+}
+
+// Test NSLog doesn't escape tracked objects.
+void rdar11400885(int y)
+{
+ @autoreleasepool {
+ NSString *printString;
+ if(y > 2)
+ printString = [[NSString alloc] init];
+ else
+ printString = [[NSString alloc] init];
+ NSLog(@"Once %@", printString);
+ [printString release];
+ NSLog(@"Again: %@", printString); // expected-warning {{Reference-counted object is used after it is released}}
+ }
+}
+
+id makeCollectableNonLeak() {
+ extern CFTypeRef CFCreateSomething();
+
+ CFTypeRef object = CFCreateSomething(); // +1
+ CFRetain(object); // +2
+ id objCObject = NSMakeCollectable(object); // +2
+ [objCObject release]; // +1
+ return [objCObject autorelease]; // +0
+}
+
+
+void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void));
+void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void));
+
+void testConsumeAndStopTracking() {
+ id retained = [@[] retain]; // +1
+ consumeAndStopTracking(retained, ^{}); // no-warning
+
+ id doubleRetained = [[@[] retain] retain]; // +2
+ consumeAndStopTracking(doubleRetained, ^{
+ [doubleRetained release];
+ }); // no-warning
+
+ id unretained = @[]; // +0
+ consumeAndStopTracking(unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFConsumeAndStopTracking() {
+ id retained = [@[] retain]; // +1
+ CFConsumeAndStopTracking((CFTypeRef)retained, ^{}); // no-warning
+
+ id doubleRetained = [[@[] retain] retain]; // +2
+ CFConsumeAndStopTracking((CFTypeRef)doubleRetained, ^{
+ [doubleRetained release];
+ }); // no-warning
+
+ id unretained = @[]; // +0
+ CFConsumeAndStopTracking((CFTypeRef)unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+//===----------------------------------------------------------------------===//
+// Test 'pragma clang arc_cf_code_audited' support.
+//===----------------------------------------------------------------------===//
+
+typedef void *MyCFType;
+#pragma clang arc_cf_code_audited begin
+MyCFType CreateMyCFType();
+#pragma clang arc_cf_code_audited end
+
+void test_custom_cf() {
+ MyCFType x = CreateMyCFType(); // expected-warning {{leak of an object stored into 'x'}}
+}
+
+//===----------------------------------------------------------------------===//
+// Test calling CFPlugInInstanceCreate, which appears in CF but doesn't
+// return a CF object.
+//===----------------------------------------------------------------------===//
+
+void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
+ CFPlugInInstanceCreate(kCFAllocatorDefault, factoryUUID, typeUUID); // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// PR14927: -drain only has retain-count semantics on NSAutoreleasePool.
+//===----------------------------------------------------------------------===//
+
+@interface PR14927 : NSObject
+- (void)drain;
+@end
+
+void test_drain() {
+ PR14927 *obj = [[PR14927 alloc] init];
+ [obj drain];
+ [obj release]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Allow cf_returns_retained and cf_returns_not_retained to mark a return
+// value as tracked, even if the object isn't a known CF type.
+//===----------------------------------------------------------------------===//
+
+MyCFType getCustom() __attribute__((cf_returns_not_retained));
+MyCFType makeCustom() __attribute__((cf_returns_retained));
+
+void testCustomReturnsRetained() {
+ MyCFType obj = makeCustom(); // expected-warning {{leak of an object stored into 'obj'}}
+}
+
+void testCustomReturnsNotRetained() {
+ CFRelease(getCustom()); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+//===----------------------------------------------------------------------===//
+// Don't print variables which are out of the current scope.
+//===----------------------------------------------------------------------===//
+@interface MyObj12706177 : NSObject
+-(instancetype)initX;
++(void)test12706177;
+@end
+static int Cond;
+@implementation MyObj12706177
+-(instancetype)initX {
+ if (Cond)
+ return 0;
+ self = [super init];
+ return self;
+}
++(void)test12706177 {
+ id x = [[MyObj12706177 alloc] initX]; //expected-warning {{Potential leak of an object}}
+ [x release];
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/13783514> xpc_connection_set_finalizer_f
+//===----------------------------------------------------------------------===//
+
+typedef xpc_object_t xpc_connection_t;
+typedef void (*xpc_finalizer_t)(void *value);
+void xpc_connection_set_context(xpc_connection_t connection, void *ctx);
+void xpc_connection_set_finalizer_f(xpc_connection_t connection,
+ xpc_finalizer_t finalizer);
+void releaseAfterXPC(void *context) {
+ [(NSArray *)context release];
+}
+
+void rdar13783514(xpc_connection_t connection) {
+ xpc_connection_set_context(connection, [[NSMutableArray alloc] init]);
+ xpc_connection_set_finalizer_f(connection, releaseAfterXPC);
+} // no-warning
+
+CFAttributedStringRef CFAttributedCreate(void *CFObj CF_CONSUMED) CF_RETURNS_RETAINED;
+
+@interface Action
+@property (nonatomic) SEL action;
+@property (nonatomic, assign) id target;
+@end
diff --git a/test/ARCMT/objcmt-atomic-property.m b/test/ARCMT/objcmt-atomic-property.m
new file mode 100644
index 000000000000..78ab3ec71596
--- /dev/null
+++ b/test/ARCMT/objcmt-atomic-property.m
@@ -0,0 +1,229 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -objcmt-atomic-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+- (void) setWeakProp : (NSString *__weak)Val;
+- (NSString *__weak) WeakProp;
+
+- (NSString *) StrongProp;
+- (void) setStrongProp : (NSString *)Val;
+
+- (NSString *) UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+- (NSString *) UnavailProp1 __attribute__((unavailable));
+- (void) setUnavailProp1 : (NSString *)Val __attribute__((unavailable));
+
+- (NSString *) UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+- (NSDictionary*) undoAction;
+- (void) setUndoAction: (NSDictionary*)Arg;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+- (void)setNames1:(NSArray *)names;
+- (void)setNames4:(__strong NSArray *)names;
+- (void)setNames3:(__strong NSArray *)names;
+- (void)setNames2:(NSArray *)names;
+- (NSArray *) names2;
+- (NSArray *)names3;
+- (__strong NSArray *)names4;
+- (NSArray *) names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+- (void *)JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+- (BOOL)isIgnoringInteractionEvents;
+
+- (NSString *)getStringValue;
+- (BOOL)getCounterValue;
+- (void)setStringValue:(NSString *)stringValue AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER;
+- (NSDictionary *)getns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+
+@interface NSInvocation(CAT)
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+- (NSURL *)appStoreReceiptURLX NS_AVAILABLE;
+- (void) setAppStoreReceiptURLX : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+- (id)OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+- (id)method1 ALIGNED NS_AVAILABLE;
+- (void) setMethod1 : (id) object NS_AVAILABLE ALIGNED;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+- (BOOL)isClass; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+- (id (^)(id, NSArray *, NSMutableDictionary *)) expressionBlock;
+- (id (^)(id, NSArray *, NSMutableDictionary *)) MyBlock;
+- (void) setMyBlock : (id (^)(id, NSArray *, NSMutableDictionary *)) bl;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) expressionFuncptr;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) MyFuncptr;
+- (void) setMyFuncptr : (id (*)(id, NSArray *, NSMutableDictionary *)) bl;
+@end
diff --git a/test/ARCMT/objcmt-atomic-property.m.result b/test/ARCMT/objcmt-atomic-property.m.result
new file mode 100644
index 000000000000..1650cd23e3bd
--- /dev/null
+++ b/test/ARCMT/objcmt-atomic-property.m.result
@@ -0,0 +1,202 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -objcmt-atomic-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+@property (weak) NSString *WeakProp;
+
+@property (retain) NSString *StrongProp;
+
+@property (retain) NSString *UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+@property (retain) NSString *UnavailProp1 __attribute__((unavailable));
+
+@property (retain) NSString *UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+@property (copy) NSDictionary *undoAction;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+@property (retain) NSArray *names2;
+@property (retain) NSArray *names3;
+@property (retain) NSArray *names4;
+@property (retain) NSArray *names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+@property (assign) id target;
+
+@property (assign) id dataSource;
+
+@property (assign) id xxxdelegateYYY;
+
+
+@property (retain) id MYtarget;
+
+@property (retain) id targetX;
+
+@property int value;
+
+@property (getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (readonly) int Length;
+@property (readonly, retain) id object;
++ (double) D;
+@property (readonly) void *JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+@property (getter=isIgnoringInteractionEvents, readonly) BOOL ignoringInteractionEvents;
+
+@property (getter=getStringValue, retain) NSString *stringValue;
+@property (getter=getCounterValue, readonly) BOOL counterValue;
+@property (getter=getns_dixtionary, readonly, retain) NSDictionary *ns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (getter=getM, readonly) BOOL m;
+@property (getter=getMA, readonly) BOOL MA;
+@property (getter=getALL, readonly) BOOL ALL;
+@property (getter=getMANY, readonly) BOOL MANY;
+@property (getter=getSome, readonly) BOOL some;
+@end
+
+
+@interface NSInvocation(CAT)
+@property (assign) id target;
+
+@property (assign) id dataSource;
+
+@property (assign) id xxxdelegateYYY;
+
+
+@property (retain) id MYtarget;
+
+@property (retain) id targetX;
+
+@property int value;
+
+@property (getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (readonly) int Length;
+@property (readonly, retain) id object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (getter=getM, readonly) BOOL m;
+@property (getter=getMA, readonly) BOOL MA;
+@property (getter=getALL, readonly) BOOL ALL;
+@property (getter=getMANY, readonly) BOOL MANY;
+@property (getter=getSome, readonly) BOOL some;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+@property (retain) NSURL *appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+@property (retain) NSURL *appStoreReceiptURLX NS_AVAILABLE;
+
+// Do not infer a property.
+@property (retain) NSURL *appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+@property (readonly, retain) id OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+@property (retain) NSURL *appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+@property (retain) id method1 ALIGNED NS_AVAILABLE;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+@property (getter=isClass, readonly) BOOL class; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+@property (readonly, copy) id (^expressionBlock)(id, NSArray *, NSMutableDictionary *);
+@property (copy) id (^MyBlock)(id, NSArray *, NSMutableDictionary *);
+@property (readonly) id (*expressionFuncptr)(id, NSArray *, NSMutableDictionary *);
+@property id (*MyFuncptr)(id, NSArray *, NSMutableDictionary *);
+@end
diff --git a/test/ARCMT/objcmt-deprecated-category.m b/test/ARCMT/objcmt-deprecated-category.m
new file mode 100644
index 000000000000..5939e5a50ada
--- /dev/null
+++ b/test/ARCMT/objcmt-deprecated-category.m
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-annotation -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+// rdar://15337661
+
+#define DEPRECATED __attribute__((deprecated))
+
+@interface NSArray
+- (int)one;
+@end
+
+@interface NSArray (NSDraggingSourceDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)getObjects:(id __unsafe_unretained [])objects;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+
+@end
+
+@interface NSArray (NSDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+- (void)getObjects:(id __unsafe_unretained [])objects;
+@property int P1;
+@property int P2 DEPRECATED;
+@end
+
+@interface NSArray (DraggingSourceDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)getObjects:(id __unsafe_unretained [])objects;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+@property int P1;
+@property int P2 DEPRECATED;
+
+@end
+
+@interface NSArray (Deprecated)
+- (void)getObjects:(id __unsafe_unretained [])objects;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+@property int P1;
+@property int P2 DEPRECATED;
+@end
diff --git a/test/ARCMT/objcmt-deprecated-category.m.result b/test/ARCMT/objcmt-deprecated-category.m.result
new file mode 100644
index 000000000000..3cb100044e46
--- /dev/null
+++ b/test/ARCMT/objcmt-deprecated-category.m.result
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-annotation -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+// rdar://15337661
+
+#define DEPRECATED __attribute__((deprecated))
+
+@interface NSArray
+- (int)one;
+@end
+
+@interface NSArray (NSDraggingSourceDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)getObjects:(id __unsafe_unretained [])objects DEPRECATED;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+
+@end
+
+@interface NSArray (NSDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+- (void)getObjects:(id __unsafe_unretained [])objects DEPRECATED;
+@property int P1 DEPRECATED;
+@property int P2 DEPRECATED;
+@end
+
+@interface NSArray (DraggingSourceDeprecated)
+
+/* This method is unsafe because it could potentially cause buffer overruns. You should use -getObjects:range: instead.
+*/
+- (void)getObjects:(id __unsafe_unretained [])objects DEPRECATED;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+@property int P1 DEPRECATED;
+@property int P2 DEPRECATED;
+
+@end
+
+@interface NSArray (Deprecated)
+- (void)getObjects:(id __unsafe_unretained [])objects DEPRECATED;
+- (void)dep_getObjects:(id __unsafe_unretained [])dep_objects DEPRECATED;
+@property int P1 DEPRECATED;
+@property int P2 DEPRECATED;
+@end
diff --git a/test/ARCMT/objcmt-instancetype-2.m b/test/ARCMT/objcmt-instancetype-2.m
new file mode 100644
index 000000000000..fb59265c4be3
--- /dev/null
+++ b/test/ARCMT/objcmt-instancetype-2.m
@@ -0,0 +1,103 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-instancetype -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef unsigned int NSUInteger;
+typedef int NSInteger;
+typedef char BOOL;
+@class NSData, NSError, NSProtocolChecker, NSObject;
+@class NSPortNameServer, NSTimeZone;
+
+@interface NSMutableString
+@end
+
+@interface NSString @end
+
+@class NSString, NSURL;
+@interface NSString (NSStringDeprecated)
++ (id)stringWithContentsOfFile:(NSString *)path __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (id)stringWithContentsOfURL:(NSURL *)url __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (id)stringWithCString:(const char *)bytes length:(NSUInteger)length __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (id)stringWithCString:(const char *)bytes __attribute__((availability(macosx,introduced=10.0 ,message="" )));
+@end
+
+
+typedef enum NSURLBookmarkResolutionOptions {
+ Bookmark
+} NSURLBookmarkResolutionOptions;
+
+@interface NSURL
++ (id)URLWithString:(NSString *)URLString;
++ (id)URLWithString:(NSString *)URLString relativeToURL:(NSURL *)baseURL;
++ (id)URLByResolvingBookmarkData:(NSData *)bookmarkData options:(NSURLBookmarkResolutionOptions)options relativeToURL:(NSURL *)relativeURL bookmarkDataIsStale:(BOOL *)isStale error:(NSError **)error __attribute__((availability(macosx,introduced=10.6)));
+@end
+
+@class NSDictionary;
+@interface NSError
++ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;
+@end
+
+
+@interface NSMutableString (NSMutableStringExtensionMethods)
++ (id)stringWithCapacity:(NSUInteger)capacity;
+@end
+
+@interface NSMutableData
++ (id)dataWithCapacity:(NSUInteger)aNumItems;
++ (id)dataWithLength:(NSUInteger)length;
+@end
+
+@interface NSMutableDictionary @end
+
+@interface NSMutableDictionary (NSSharedKeySetDictionary)
++ (id )dictionaryWithSharedKeySet:(id)keyset __attribute__((availability(macosx,introduced=10.8)));
+@end
+
+@interface NSProtocolChecker
++ (id)protocolCheckerWithTarget:(NSObject *)anObject protocol:(Protocol *)aProtocol;
+@end
+
+@interface NSConnection
++ (id)connectionWithRegisteredName:(NSString *)name host:(NSString *)hostName;
++ (id)connectionWithRegisteredName:(NSString *)name host:(NSString *)hostName usingNameServer:(NSPortNameServer *)server;
+@end
+
+@interface NSDate
++ (id)dateWithString:(NSString *)aString __attribute__((availability(macosx,introduced=10.4)));
+@end
+
+@interface NSCalendarDate : NSDate
++ (id)calendarDate __attribute__((availability(macosx,introduced=10.4)));
++ (id)dateWithString:(NSString *)description calendarFormat:(NSString *)format locale:(id)locale __attribute__((availability(macosx,introduced=10.4)));
++ (id)dateWithString:(NSString *)description calendarFormat:(NSString *)format __attribute__((availability(macosx,introduced=10.4)));
++ (id)dateWithYear:(NSInteger)year month:(NSUInteger)month day:(NSUInteger)day hour:(NSUInteger)hour minute:(NSUInteger)minute second:(NSUInteger)second timeZone:(NSTimeZone *)aTimeZone __attribute__((availability(macosx,introduced=10.4)));
+@end
+
+@interface NSUserDefaults
++ (id) standardUserDefaults;
+@end
+
+@interface NSNotificationCenter
++ (id) defaultCenter;
++ sharedCenter;
+@end
+
+@interface UIApplication
++ (id)sharedApplication;
++ defaultApplication;
+@end
+
+//===----------------------------------------------------------------------===//
+// Method name that has a null IdentifierInfo* for its first selector slot.
+// This test just makes sure that we handle it.
+//===----------------------------------------------------------------------===//
+@interface TestNullIdentifier
+@end
+
+@implementation TestNullIdentifier
++ (id):(int)x, ... {
+ return 0;
+}
+@end
+
diff --git a/test/ARCMT/objcmt-instancetype-2.m.result b/test/ARCMT/objcmt-instancetype-2.m.result
new file mode 100644
index 000000000000..8837e971ad27
--- /dev/null
+++ b/test/ARCMT/objcmt-instancetype-2.m.result
@@ -0,0 +1,103 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-instancetype -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef unsigned int NSUInteger;
+typedef int NSInteger;
+typedef char BOOL;
+@class NSData, NSError, NSProtocolChecker, NSObject;
+@class NSPortNameServer, NSTimeZone;
+
+@interface NSMutableString
+@end
+
+@interface NSString @end
+
+@class NSString, NSURL;
+@interface NSString (NSStringDeprecated)
++ (instancetype)stringWithContentsOfFile:(NSString *)path __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (instancetype)stringWithContentsOfURL:(NSURL *)url __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (instancetype)stringWithCString:(const char *)bytes length:(NSUInteger)length __attribute__((availability(macosx,introduced=10.0 ,message="" )));
++ (instancetype)stringWithCString:(const char *)bytes __attribute__((availability(macosx,introduced=10.0 ,message="" )));
+@end
+
+
+typedef enum NSURLBookmarkResolutionOptions {
+ Bookmark
+} NSURLBookmarkResolutionOptions;
+
+@interface NSURL
++ (instancetype)URLWithString:(NSString *)URLString;
++ (instancetype)URLWithString:(NSString *)URLString relativeToURL:(NSURL *)baseURL;
++ (instancetype)URLByResolvingBookmarkData:(NSData *)bookmarkData options:(NSURLBookmarkResolutionOptions)options relativeToURL:(NSURL *)relativeURL bookmarkDataIsStale:(BOOL *)isStale error:(NSError **)error __attribute__((availability(macosx,introduced=10.6)));
+@end
+
+@class NSDictionary;
+@interface NSError
++ (instancetype)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;
+@end
+
+
+@interface NSMutableString (NSMutableStringExtensionMethods)
++ (instancetype)stringWithCapacity:(NSUInteger)capacity;
+@end
+
+@interface NSMutableData
++ (instancetype)dataWithCapacity:(NSUInteger)aNumItems;
++ (instancetype)dataWithLength:(NSUInteger)length;
+@end
+
+@interface NSMutableDictionary @end
+
+@interface NSMutableDictionary (NSSharedKeySetDictionary)
++ (instancetype )dictionaryWithSharedKeySet:(id)keyset __attribute__((availability(macosx,introduced=10.8)));
+@end
+
+@interface NSProtocolChecker
++ (instancetype)protocolCheckerWithTarget:(NSObject *)anObject protocol:(Protocol *)aProtocol;
+@end
+
+@interface NSConnection
++ (instancetype)connectionWithRegisteredName:(NSString *)name host:(NSString *)hostName;
++ (instancetype)connectionWithRegisteredName:(NSString *)name host:(NSString *)hostName usingNameServer:(NSPortNameServer *)server;
+@end
+
+@interface NSDate
++ (instancetype)dateWithString:(NSString *)aString __attribute__((availability(macosx,introduced=10.4)));
+@end
+
+@interface NSCalendarDate : NSDate
++ (instancetype)calendarDate __attribute__((availability(macosx,introduced=10.4)));
++ (instancetype)dateWithString:(NSString *)description calendarFormat:(NSString *)format locale:(id)locale __attribute__((availability(macosx,introduced=10.4)));
++ (instancetype)dateWithString:(NSString *)description calendarFormat:(NSString *)format __attribute__((availability(macosx,introduced=10.4)));
++ (instancetype)dateWithYear:(NSInteger)year month:(NSUInteger)month day:(NSUInteger)day hour:(NSUInteger)hour minute:(NSUInteger)minute second:(NSUInteger)second timeZone:(NSTimeZone *)aTimeZone __attribute__((availability(macosx,introduced=10.4)));
+@end
+
+@interface NSUserDefaults
++ (instancetype) standardUserDefaults;
+@end
+
+@interface NSNotificationCenter
++ (NSNotificationCenter*) defaultCenter;
++ (NSNotificationCenter*) sharedCenter;
+@end
+
+@interface UIApplication
++ (UIApplication*)sharedApplication;
++ (UIApplication*) defaultApplication;
+@end
+
+//===----------------------------------------------------------------------===//
+// Method name that has a null IdentifierInfo* for its first selector slot.
+// This test just makes sure that we handle it.
+//===----------------------------------------------------------------------===//
+@interface TestNullIdentifier
+@end
+
+@implementation TestNullIdentifier
++ (id):(int)x, ... {
+ return 0;
+}
+@end
+
diff --git a/test/ARCMT/objcmt-instancetype.m b/test/ARCMT/objcmt-instancetype.m
new file mode 100644
index 000000000000..47dbd7aeed5a
--- /dev/null
+++ b/test/ARCMT/objcmt-instancetype.m
@@ -0,0 +1,111 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-instancetype -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@implementation NSString : NSObject
++ (id)stringWithString:(NSString *)string { return 0; };
+- (instancetype)initWithString:(NSString *)aString { return 0; };
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@implementation NSArray (NSArrayCreation)
++ (id)array { return 0; }
++ (id)arrayWithObject:(id)anObject {
+ return anObject;
+}
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt { return 0; }
++ (id)arrayWithObjects:(id)firstObj, ... {
+ return 0; }
++ arrayWithArray:(NSArray *)array {
+ return 0;
+}
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt { return 0; }
+- (id)initWithObjects:(id)firstObj, ... { return 0; }
+- (id)initWithArray:(NSArray *)array { return 0; }
+
+- (id)objectAtIndex:(unsigned long)index { return 0; }
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@implementation NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value { return 0; }
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+void foo() {
+ NSString *str = M([NSString stringWithString:@"foo"]); // expected-warning {{redundant}}
+ str = [[NSString alloc] initWithString:@"foo"]; // expected-warning {{redundant}}
+ NSArray *arr = [NSArray arrayWithArray:@[str]]; // expected-warning {{redundant}}
+ NSDictionary *dict = [NSDictionary dictionaryWithDictionary:@{str: arr}]; // expected-warning {{redundant}}
+}
diff --git a/test/ARCMT/objcmt-instancetype.m.result b/test/ARCMT/objcmt-instancetype.m.result
new file mode 100644
index 000000000000..ce51678708dd
--- /dev/null
+++ b/test/ARCMT/objcmt-instancetype.m.result
@@ -0,0 +1,111 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-instancetype -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (instancetype)stringWithString:(NSString *)string;
+- (instancetype)initWithString:(NSString *)aString;
+@end
+
+@implementation NSString : NSObject
++ (instancetype)stringWithString:(NSString *)string { return 0; };
+- (instancetype)initWithString:(NSString *)aString { return 0; };
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (instancetype)array;
++ (instancetype)arrayWithObject:(id)anObject;
++ (instancetype)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (instancetype)arrayWithObjects:(id)firstObj, ...;
++ (instancetype) arrayWithArray:(NSArray *)array;
+
+- (instancetype)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (instancetype)initWithObjects:(id)firstObj, ...;
+- (instancetype)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@implementation NSArray (NSArrayCreation)
++ (instancetype)array { return 0; }
++ (instancetype)arrayWithObject:(id)anObject {
+ return anObject;
+}
++ (instancetype)arrayWithObjects:(const id [])objects count:(unsigned long)cnt { return 0; }
++ (instancetype)arrayWithObjects:(id)firstObj, ... {
+ return 0; }
++ (instancetype) arrayWithArray:(NSArray *)array {
+ return 0;
+}
+
+- (instancetype)initWithObjects:(const id [])objects count:(unsigned long)cnt { return 0; }
+- (instancetype)initWithObjects:(id)firstObj, ... { return 0; }
+- (instancetype)initWithArray:(NSArray *)array { return 0; }
+
+- (id)objectAtIndex:(unsigned long)index { return 0; }
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object forKey:(id)key;
++ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (instancetype) dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (instancetype)dictionaryWithDictionary:(NSDictionary *)dict;
++ (instancetype)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (instancetype)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (instancetype)initWithObjectsAndKeys:(id)firstObject, ...;
+- (instancetype)initWithDictionary:(NSDictionary *)otherDictionary;
+- (instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@implementation NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value { return 0; }
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+void foo() {
+ NSString *str = M([NSString stringWithString:@"foo"]); // expected-warning {{redundant}}
+ str = [[NSString alloc] initWithString:@"foo"]; // expected-warning {{redundant}}
+ NSArray *arr = [NSArray arrayWithArray:@[str]]; // expected-warning {{redundant}}
+ NSDictionary *dict = [NSDictionary dictionaryWithDictionary:@{str: arr}]; // expected-warning {{redundant}}
+}
diff --git a/test/ARCMT/objcmt-migrate-all.m b/test/ARCMT/objcmt-migrate-all.m
new file mode 100644
index 000000000000..7ae898cf9cba
--- /dev/null
+++ b/test/ARCMT/objcmt-migrate-all.m
@@ -0,0 +1,135 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-all -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+// rdar://15396636
+
+#ifndef NS_RETURNS_INNER_POINTER // defined in iOS 6 for sure
+#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))
+#endif
+
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+typedef unsigned long CFTypeID;
+typedef unsigned long CFOptionFlags;
+typedef unsigned long CFHashCode;
+
+typedef signed long CFIndex; /*AnyObj*/
+typedef const struct __CFArray * CFArrayRef;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+
+typedef void (*CFArrayApplierFunction)(const void *value, void *context);
+
+typedef enum CFComparisonResult : CFIndex CFComparisonResult; enum CFComparisonResult : CFIndex {
+ kCFCompareLessThan = -1L,
+ kCFCompareEqualTo = 0,
+ kCFCompareGreaterThan = 1
+};
+
+
+typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context);
+
+typedef struct __CFArray * CFMutableArrayRef;
+
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+
+typedef struct CGImage *CGImageRef;
+
+typedef struct OpaqueJSValue* JSObjectRef;
+
+typedef JSObjectRef TTJSObjectRef;
+typedef unsigned int NSUInteger;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+@interface I
+- (void*) ReturnsInnerPointer;
+- (int*) AlreadyReturnsInnerPointer NS_RETURNS_INNER_POINTER;
+@end
+
+@interface UIImage
+- (CGImageRef)CGImage;
+@end
+
+@interface NSData
+- (void *)bytes;
+- (void **) ptr_bytes __attribute__((availability(macosx,unavailable)));
+@end
+
+@interface NSMutableData
+- (void *)mutableBytes __attribute__((deprecated)) __attribute__((unavailable));
+@end
+
+@interface JS
+- (JSObjectRef)JSObject;
+- (TTJSObjectRef)JSObject1;
+- (JSObjectRef*)JSObject2;
+@end
+
+// rdar://15044991
+typedef void *SecTrustRef;
+
+@interface NSURLProtectionSpace
+@property (readonly) SecTrustRef serverTrust NS_AVAILABLE;
+- (void *) FOO NS_AVAILABLE;
+@property (readonly) void * mitTrust NS_AVAILABLE;
+
+@property (readonly) void * mittiTrust;
+
+@property (readonly) SecTrustRef XserverTrust;
+
+- (SecTrustRef) FOO1 NS_AVAILABLE;
+
++ (const NSURLProtectionSpace *)ProtectionSpace;
+
+// pointer personality functions
+@property NSUInteger (*hashFunction)(const void *item, NSUInteger (*size)(const void *item));
+@end
+
+@interface MustNotMigrateToInnerPointer
+- (void*) nono;
+- (void) setNono : (void*) val;
+@end
diff --git a/test/ARCMT/objcmt-migrate-all.m.result b/test/ARCMT/objcmt-migrate-all.m.result
new file mode 100644
index 000000000000..d2ee4090b28c
--- /dev/null
+++ b/test/ARCMT/objcmt-migrate-all.m.result
@@ -0,0 +1,134 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-all -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+// rdar://15396636
+
+#ifndef NS_RETURNS_INNER_POINTER // defined in iOS 6 for sure
+#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))
+#endif
+
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+typedef unsigned long CFTypeID;
+typedef unsigned long CFOptionFlags;
+typedef unsigned long CFHashCode;
+
+typedef signed long CFIndex; /*AnyObj*/
+typedef const struct __CFArray * CFArrayRef;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+
+typedef void (*CFArrayApplierFunction)(const void *value, void *context);
+
+typedef enum CFComparisonResult : CFIndex CFComparisonResult; enum CFComparisonResult : CFIndex {
+ kCFCompareLessThan = -1L,
+ kCFCompareEqualTo = 0,
+ kCFCompareGreaterThan = 1
+};
+
+
+typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context);
+
+typedef struct __CFArray * CFMutableArrayRef;
+
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+
+typedef struct CGImage *CGImageRef;
+
+typedef struct OpaqueJSValue* JSObjectRef;
+
+typedef JSObjectRef TTJSObjectRef;
+typedef unsigned int NSUInteger;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+@interface I
+@property (nonatomic, readonly) void *ReturnsInnerPointer;
+@property (nonatomic, readonly) int *AlreadyReturnsInnerPointer NS_RETURNS_INNER_POINTER;
+@end
+
+@interface UIImage
+@property (nonatomic, readonly) CGImageRef CGImage CF_RETURNS_NOT_RETAINED;
+@end
+
+@interface NSData
+@property (nonatomic, readonly) void *bytes;
+@property (nonatomic, readonly) void **ptr_bytes __attribute__((availability(macosx,unavailable)));
+@end
+
+@interface NSMutableData
+@property (nonatomic, readonly) void *mutableBytes __attribute__((deprecated)) __attribute__((unavailable));
+@end
+
+@interface JS
+@property (nonatomic, readonly) JSObjectRef JSObject;
+@property (nonatomic, readonly) TTJSObjectRef JSObject1;
+@property (nonatomic, readonly) JSObjectRef *JSObject2;
+@end
+
+// rdar://15044991
+typedef void *SecTrustRef;
+
+@interface NSURLProtectionSpace
+@property (readonly) SecTrustRef serverTrust NS_AVAILABLE;
+@property (nonatomic, readonly) void *FOO NS_AVAILABLE;
+@property (readonly) void * mitTrust NS_AVAILABLE;
+
+@property (readonly) void * mittiTrust;
+
+@property (readonly) SecTrustRef XserverTrust;
+
+@property (nonatomic, readonly) SecTrustRef FOO1 NS_AVAILABLE;
+
++ (const NSURLProtectionSpace *)ProtectionSpace;
+
+// pointer personality functions
+@property NSUInteger (*hashFunction)(const void *item, NSUInteger (*size)(const void *item));
+@end
+
+@interface MustNotMigrateToInnerPointer
+@property (nonatomic) void *nono;
+@end
diff --git a/test/ARCMT/objcmt-ns-macros.m b/test/ARCMT/objcmt-ns-macros.m
new file mode 100644
index 000000000000..1bf55d8ed46b
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-macros.m
@@ -0,0 +1,296 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-ns-macros -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+
+#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
+#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
+#define DEPRECATED __attribute__((deprecated))
+
+enum {
+ blah,
+ blarg
+};
+typedef NSInteger wibble;
+
+enum {
+ UIViewAutoresizingNone = 0,
+ UIViewAutoresizingFlexibleLeftMargin,
+ UIViewAutoresizingFlexibleWidth,
+ UIViewAutoresizingFlexibleRightMargin,
+ UIViewAutoresizingFlexibleTopMargin,
+ UIViewAutoresizingFlexibleHeight,
+ UIViewAutoresizingFlexibleBottomMargin
+};
+typedef NSUInteger UITableViewCellStyle;
+
+typedef enum {
+ UIViewAnimationTransitionNone,
+ UIViewAnimationTransitionFlipFromLeft,
+ UIViewAnimationTransitionFlipFromRight,
+ UIViewAnimationTransitionCurlUp,
+ UIViewAnimationTransitionCurlDown,
+} UIViewAnimationTransition;
+
+typedef enum {
+ UIViewOne = 0,
+ UIViewTwo = 1 << 0,
+ UIViewThree = 1 << 1,
+ UIViewFour = 1 << 2,
+ UIViewFive = 1 << 3,
+ UIViewSix = 1 << 4,
+ UIViewSeven = 1 << 5
+} UITableView;
+
+enum {
+ UIOne = 0,
+ UITwo = 0x1,
+ UIthree = 0x8,
+ UIFour = 0x100
+};
+typedef NSInteger UI;
+
+typedef enum {
+ UIP2One = 0,
+ UIP2Two = 0x1,
+ UIP2three = 0x8,
+ UIP2Four = 0x100
+} UIPOWER2;
+
+enum {
+ UNOne,
+ UNTwo
+};
+
+// Should use NS_ENUM even though it is all power of 2.
+enum {
+ UIKOne = 1,
+ UIKTwo = 2,
+};
+typedef NSInteger UIK;
+
+typedef enum {
+ NSTickMarkBelow = 0,
+ NSTickMarkAbove = 1,
+ NSTickMarkLeft = NSTickMarkAbove,
+ NSTickMarkRight = NSTickMarkBelow
+} NSTickMarkPosition;
+
+enum {
+ UIViewNone = 0x0,
+ UIViewMargin = 0x1,
+ UIViewWidth = 0x2,
+ UIViewRightMargin = 0x3,
+ UIViewBottomMargin = 0xbadbeef
+};
+typedef NSInteger UITableStyle;
+
+enum {
+ UIView0 = 0,
+ UIView1 = 0XBADBEEF
+};
+typedef NSInteger UIStyle;
+
+enum {
+ NSTIFFFileType,
+ NSBMPFileType,
+ NSGIFFileType,
+ NSJPEGFileType,
+ NSPNGFileType,
+ NSJPEG2000FileType
+};
+typedef NSUInteger NSBitmapImageFileType;
+
+enum {
+ NSWarningAlertStyle = 0,
+ NSInformationalAlertStyle = 1,
+ NSCriticalAlertStyle = 2
+};
+typedef NSUInteger NSAlertStyle;
+
+enum {
+ D_NSTIFFFileType,
+ D_NSBMPFileType,
+ D_NSGIFFileType,
+ D_NSJPEGFileType,
+ D_NSPNGFileType,
+ D_NSJPEG2000FileType
+};
+typedef NSUInteger D_NSBitmapImageFileType DEPRECATED;
+
+typedef enum {
+ D_NSTickMarkBelow = 0,
+ D_NSTickMarkAbove = 1
+} D_NSTickMarkPosition DEPRECATED;
+
+
+#define NS_ENUM_AVAILABLE(X,Y)
+
+enum {
+ NSFStrongMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 0),
+ NSFOpaqueMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 0),
+ NSFMallocMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 0),
+ NSFMachVirtualMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 0),
+ NSFWeakMemory NS_ENUM_AVAILABLE(10_8, 6_0) = (5UL << 0),
+
+ NSFObjectPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 8),
+ NSFOpaquePersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 8),
+ NSFObjectPointerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 8),
+ NSFCStringPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 8),
+ NSFStructPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 8),
+ NSFIntegerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (5UL << 8),
+ NSFCopyIn NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 16),
+};
+
+typedef NSUInteger NSFOptions;
+
+typedef enum {
+ UIP0One = 0,
+ UIP0Two = 1,
+ UIP0Three = 2,
+ UIP0Four = 10,
+ UIP0Last = 0x100
+} UIP;
+
+typedef enum {
+ UIPZero = 0x0,
+ UIPOne = 0x1,
+ UIPTwo = 0x2,
+ UIP10 = 0x10,
+ UIPHundred = 0x100
+} UIP_3;
+
+typedef enum {
+ UIP4Zero = 0x0,
+ UIP4One = 0x1,
+ UIP4Two = 0x2,
+ UIP410 = 0x10,
+ UIP4Hundred = 100
+} UIP4_3;
+
+typedef enum {
+ UIP5Zero = 0x0,
+ UIP5Two = 0x2,
+ UIP510 = 0x3,
+ UIP5Hundred = 0x4
+} UIP5_3;
+
+typedef enum {
+ UIP6Zero = 0x0,
+ UIP6One = 0x1,
+ UIP6Two = 0x2,
+ UIP610 = 10,
+ UIP6Hundred = 0x100
+} UIP6_3;
+
+typedef enum {
+ UIP7Zero = 0x0,
+ UIP7One = 1,
+ UIP7Two = 0x2,
+ UIP710 = 10,
+ UIP7Hundred = 100
+} UIP7_3;
+
+
+typedef enum {
+ Random = 0,
+ Random1 = 2,
+ Random2 = 4,
+ Random3 = 0x12345,
+ Random4 = 0x3444444,
+ Random5 = 0xbadbeef,
+ Random6
+} UIP8_3;
+
+// rdar://15200602
+#define NS_AVAILABLE_MAC(X) __attribute__((availability(macosx,introduced=X)))
+#define NS_ENUM_AVAILABLE_MAC(X) __attribute__((availability(macosx,introduced=X)))
+
+enum {
+ NSModalResponseStop = (-1000), // Also used as the default response for sheets
+ NSModalResponseAbort = (-1001),
+ NSModalResponseContinue = (-1002),
+} NS_ENUM_AVAILABLE_MAC(10.9);
+typedef NSInteger NSModalResponse NS_AVAILABLE_MAC(10.9);
+
+// rdar://15201056
+typedef NSUInteger FarFarAwayOptions;
+
+// rdar://15200915
+typedef NSUInteger FarAwayOptions;
+enum {
+ NSWorkspaceLaunchAndPrint = 0x00000002,
+ NSWorkspaceLaunchWithErrorPresentation = 0x00000040,
+ NSWorkspaceLaunchInhibitingBackgroundOnly = 0x00000080,
+ NSWorkspaceLaunchWithoutAddingToRecents = 0x00000100,
+ NSWorkspaceLaunchWithoutActivation = 0x00000200,
+ NSWorkspaceLaunchAsync = 0x00010000,
+ NSWorkspaceLaunchAllowingClassicStartup = 0x00020000,
+ NSWorkspaceLaunchPreferringClassic = 0x00040000,
+ NSWorkspaceLaunchNewInstance = 0x00080000,
+ NSWorkspaceLaunchAndHide = 0x00100000,
+ NSWorkspaceLaunchAndHideOthers = 0x00200000,
+ NSWorkspaceLaunchDefault = NSWorkspaceLaunchAsync |
+ NSWorkspaceLaunchAllowingClassicStartup
+};
+typedef NSUInteger NSWorkspaceLaunchOptions;
+
+enum {
+ NSExcludeQuickDrawElementsIconCreationOption = 1 << 1,
+ NSExclude10_4ElementsIconCreationOption = 1 << 2
+};
+typedef NSUInteger NSExcludeOptions;
+
+enum {
+ NSExcludeQuickDrawElementsCreationOption = 1 << 1,
+ NSExclude10_4ElementsCreationOption = 1 << 2
+};
+typedef NSUInteger NSExcludeCreationOption;
+
+enum {
+ FarAway1 = 1 << 1,
+ FarAway2 = 1 << 2
+};
+
+enum {
+ NSExcludeQuickDrawElementsIconOption = 1 << 1,
+ NSExclude10_4ElementsIconOption = 1 << 2
+};
+typedef NSUInteger NSExcludeIconOptions;
+
+@interface INTF {
+ NSExcludeIconOptions I1;
+ NSExcludeIconOptions I2;
+}
+@end
+
+enum {
+ FarFarAway1 = 1 << 1,
+ FarFarAway2 = 1 << 2
+};
+
+// rdar://15200915
+typedef NS_OPTIONS(NSUInteger, NSWindowOcclusionState) {
+ NSWindowOcclusionStateVisible = 1UL << 1,
+};
+
+typedef NSUInteger NSWindowNumberListOptions;
+
+enum {
+ NSDirectSelection = 0,
+ NSSelectingNext,
+ NSSelectingPrevious
+};
+typedef NSUInteger NSSelectionDirection;
+
+// standard window buttons
+enum {
+ NSWindowCloseButton,
+ NSWindowMiniaturizeButton,
+ NSWindowZoomButton,
+ NSWindowToolbarButton,
+ NSWindowDocumentIconButton
+};
diff --git a/test/ARCMT/objcmt-ns-macros.m.result b/test/ARCMT/objcmt-ns-macros.m.result
new file mode 100644
index 000000000000..0b640ac35676
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-macros.m.result
@@ -0,0 +1,279 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-ns-macros -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+
+#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
+#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
+#define DEPRECATED __attribute__((deprecated))
+
+typedef NS_ENUM(NSInteger, wibble) {
+ blah,
+ blarg
+};
+
+typedef NS_ENUM(NSUInteger, UITableViewCellStyle) {
+ UIViewAutoresizingNone = 0,
+ UIViewAutoresizingFlexibleLeftMargin,
+ UIViewAutoresizingFlexibleWidth,
+ UIViewAutoresizingFlexibleRightMargin,
+ UIViewAutoresizingFlexibleTopMargin,
+ UIViewAutoresizingFlexibleHeight,
+ UIViewAutoresizingFlexibleBottomMargin
+};
+
+typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
+ UIViewAnimationTransitionNone,
+ UIViewAnimationTransitionFlipFromLeft,
+ UIViewAnimationTransitionFlipFromRight,
+ UIViewAnimationTransitionCurlUp,
+ UIViewAnimationTransitionCurlDown,
+} ;
+
+typedef NS_OPTIONS(NSUInteger, UITableView) {
+ UIViewOne = 0,
+ UIViewTwo = 1 << 0,
+ UIViewThree = 1 << 1,
+ UIViewFour = 1 << 2,
+ UIViewFive = 1 << 3,
+ UIViewSix = 1 << 4,
+ UIViewSeven = 1 << 5
+} ;
+
+typedef NS_OPTIONS(NSUInteger, UI) {
+ UIOne = 0,
+ UITwo = 0x1,
+ UIthree = 0x8,
+ UIFour = 0x100
+};
+
+typedef NS_OPTIONS(NSUInteger, UIPOWER2) {
+ UIP2One = 0,
+ UIP2Two = 0x1,
+ UIP2three = 0x8,
+ UIP2Four = 0x100
+} ;
+
+enum {
+ UNOne,
+ UNTwo
+};
+
+// Should use NS_ENUM even though it is all power of 2.
+typedef NS_ENUM(NSInteger, UIK) {
+ UIKOne = 1,
+ UIKTwo = 2,
+};
+
+typedef NS_ENUM(NSInteger, NSTickMarkPosition) {
+ NSTickMarkBelow = 0,
+ NSTickMarkAbove = 1,
+ NSTickMarkLeft = NSTickMarkAbove,
+ NSTickMarkRight = NSTickMarkBelow
+} ;
+
+typedef NS_OPTIONS(NSUInteger, UITableStyle) {
+ UIViewNone = 0x0,
+ UIViewMargin = 0x1,
+ UIViewWidth = 0x2,
+ UIViewRightMargin = 0x3,
+ UIViewBottomMargin = 0xbadbeef
+};
+
+typedef NS_OPTIONS(NSUInteger, UIStyle) {
+ UIView0 = 0,
+ UIView1 = 0XBADBEEF
+};
+
+typedef NS_ENUM(NSUInteger, NSBitmapImageFileType) {
+ NSTIFFFileType,
+ NSBMPFileType,
+ NSGIFFileType,
+ NSJPEGFileType,
+ NSPNGFileType,
+ NSJPEG2000FileType
+};
+
+typedef NS_ENUM(NSUInteger, NSAlertStyle) {
+ NSWarningAlertStyle = 0,
+ NSInformationalAlertStyle = 1,
+ NSCriticalAlertStyle = 2
+};
+
+enum {
+ D_NSTIFFFileType,
+ D_NSBMPFileType,
+ D_NSGIFFileType,
+ D_NSJPEGFileType,
+ D_NSPNGFileType,
+ D_NSJPEG2000FileType
+};
+typedef NSUInteger D_NSBitmapImageFileType DEPRECATED;
+
+typedef enum {
+ D_NSTickMarkBelow = 0,
+ D_NSTickMarkAbove = 1
+} D_NSTickMarkPosition DEPRECATED;
+
+
+#define NS_ENUM_AVAILABLE(X,Y)
+
+
+typedef NS_OPTIONS(NSUInteger, NSFOptions) {
+ NSFStrongMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 0),
+ NSFOpaqueMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 0),
+ NSFMallocMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 0),
+ NSFMachVirtualMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 0),
+ NSFWeakMemory NS_ENUM_AVAILABLE(10_8, 6_0) = (5UL << 0),
+
+ NSFObjectPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 8),
+ NSFOpaquePersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 8),
+ NSFObjectPointerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 8),
+ NSFCStringPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 8),
+ NSFStructPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 8),
+ NSFIntegerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (5UL << 8),
+ NSFCopyIn NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 16),
+};
+
+typedef NS_ENUM(NSInteger, UIP) {
+ UIP0One = 0,
+ UIP0Two = 1,
+ UIP0Three = 2,
+ UIP0Four = 10,
+ UIP0Last = 0x100
+} ;
+
+typedef NS_OPTIONS(NSUInteger, UIP_3) {
+ UIPZero = 0x0,
+ UIPOne = 0x1,
+ UIPTwo = 0x2,
+ UIP10 = 0x10,
+ UIPHundred = 0x100
+} ;
+
+typedef NS_ENUM(NSInteger, UIP4_3) {
+ UIP4Zero = 0x0,
+ UIP4One = 0x1,
+ UIP4Two = 0x2,
+ UIP410 = 0x10,
+ UIP4Hundred = 100
+} ;
+
+typedef NS_OPTIONS(NSUInteger, UIP5_3) {
+ UIP5Zero = 0x0,
+ UIP5Two = 0x2,
+ UIP510 = 0x3,
+ UIP5Hundred = 0x4
+} ;
+
+typedef NS_ENUM(NSInteger, UIP6_3) {
+ UIP6Zero = 0x0,
+ UIP6One = 0x1,
+ UIP6Two = 0x2,
+ UIP610 = 10,
+ UIP6Hundred = 0x100
+} ;
+
+typedef NS_ENUM(NSInteger, UIP7_3) {
+ UIP7Zero = 0x0,
+ UIP7One = 1,
+ UIP7Two = 0x2,
+ UIP710 = 10,
+ UIP7Hundred = 100
+} ;
+
+
+typedef NS_ENUM(NSInteger, UIP8_3) {
+ Random = 0,
+ Random1 = 2,
+ Random2 = 4,
+ Random3 = 0x12345,
+ Random4 = 0x3444444,
+ Random5 = 0xbadbeef,
+ Random6
+} ;
+
+// rdar://15200602
+#define NS_AVAILABLE_MAC(X) __attribute__((availability(macosx,introduced=X)))
+#define NS_ENUM_AVAILABLE_MAC(X) __attribute__((availability(macosx,introduced=X)))
+
+typedef NS_ENUM(NSInteger, NSModalResponse) {
+ NSModalResponseStop = (-1000), // Also used as the default response for sheets
+ NSModalResponseAbort = (-1001),
+ NSModalResponseContinue = (-1002),
+} NS_ENUM_AVAILABLE_MAC(10.9);
+
+// rdar://15201056
+typedef NSUInteger FarFarAwayOptions;
+
+// rdar://15200915
+typedef NS_OPTIONS(NSUInteger, FarAwayOptions) {
+ FarAway1 = 1 << 1,
+ FarAway2 = 1 << 2
+};
+typedef NS_OPTIONS(NSUInteger, NSWorkspaceLaunchOptions) {
+ NSWorkspaceLaunchAndPrint = 0x00000002,
+ NSWorkspaceLaunchWithErrorPresentation = 0x00000040,
+ NSWorkspaceLaunchInhibitingBackgroundOnly = 0x00000080,
+ NSWorkspaceLaunchWithoutAddingToRecents = 0x00000100,
+ NSWorkspaceLaunchWithoutActivation = 0x00000200,
+ NSWorkspaceLaunchAsync = 0x00010000,
+ NSWorkspaceLaunchAllowingClassicStartup = 0x00020000,
+ NSWorkspaceLaunchPreferringClassic = 0x00040000,
+ NSWorkspaceLaunchNewInstance = 0x00080000,
+ NSWorkspaceLaunchAndHide = 0x00100000,
+ NSWorkspaceLaunchAndHideOthers = 0x00200000,
+ NSWorkspaceLaunchDefault = NSWorkspaceLaunchAsync |
+ NSWorkspaceLaunchAllowingClassicStartup
+};
+
+typedef NS_OPTIONS(NSUInteger, NSExcludeOptions) {
+ NSExcludeQuickDrawElementsIconCreationOption = 1 << 1,
+ NSExclude10_4ElementsIconCreationOption = 1 << 2
+};
+
+typedef NS_OPTIONS(NSUInteger, NSExcludeCreationOption) {
+ NSExcludeQuickDrawElementsCreationOption = 1 << 1,
+ NSExclude10_4ElementsCreationOption = 1 << 2
+};
+
+
+typedef NS_OPTIONS(NSUInteger, NSExcludeIconOptions) {
+ NSExcludeQuickDrawElementsIconOption = 1 << 1,
+ NSExclude10_4ElementsIconOption = 1 << 2
+};
+
+@interface INTF {
+ NSExcludeIconOptions I1;
+ NSExcludeIconOptions I2;
+}
+@end
+
+enum {
+ FarFarAway1 = 1 << 1,
+ FarFarAway2 = 1 << 2
+};
+
+// rdar://15200915
+typedef NS_OPTIONS(NSUInteger, NSWindowOcclusionState) {
+ NSWindowOcclusionStateVisible = 1UL << 1,
+};
+
+typedef NS_ENUM(NSUInteger, NSWindowNumberListOptions) {
+ NSWindowCloseButton,
+ NSWindowMiniaturizeButton,
+ NSWindowZoomButton,
+ NSWindowToolbarButton,
+ NSWindowDocumentIconButton
+};
+
+typedef NS_ENUM(NSUInteger, NSSelectionDirection) {
+ NSDirectSelection = 0,
+ NSSelectingNext,
+ NSSelectingPrevious
+};
+
+// standard window buttons
diff --git a/test/ARCMT/objcmt-ns-nonatomic-iosonly.m b/test/ARCMT/objcmt-ns-nonatomic-iosonly.m
new file mode 100644
index 000000000000..57b20415f969
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-nonatomic-iosonly.m
@@ -0,0 +1,236 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-ns-nonatomic-iosonly -objcmt-migrate-readonly-property -objcmt-atomic-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+// rdar://15442742
+#if TARGET_OS_IPHONE
+ #define NS_NONATOMIC_IOSONLY nonatomic
+#else
+ #define NS_NONATOMIC_IOSONLY atomic
+#endif
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+- (void) setWeakProp : (NSString *__weak)Val;
+- (NSString *__weak) WeakProp;
+
+- (NSString *) StrongProp;
+- (void) setStrongProp : (NSString *)Val;
+
+- (NSString *) UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+- (NSString *) UnavailProp1 __attribute__((unavailable));
+- (void) setUnavailProp1 : (NSString *)Val __attribute__((unavailable));
+
+- (NSString *) UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+- (NSDictionary*) undoAction;
+- (void) setUndoAction: (NSDictionary*)Arg;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+- (void)setNames1:(NSArray *)names;
+- (void)setNames4:(__strong NSArray *)names;
+- (void)setNames3:(__strong NSArray *)names;
+- (void)setNames2:(NSArray *)names;
+- (NSArray *) names2;
+- (NSArray *)names3;
+- (__strong NSArray *)names4;
+- (NSArray *) names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+- (void *)JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+- (BOOL)isIgnoringInteractionEvents;
+
+- (NSString *)getStringValue;
+- (BOOL)getCounterValue;
+- (void)setStringValue:(NSString *)stringValue AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER;
+- (NSDictionary *)getns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+
+@interface NSInvocation(CAT)
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+- (NSURL *)appStoreReceiptURLX NS_AVAILABLE;
+- (void) setAppStoreReceiptURLX : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+- (id)OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+- (id)method1 ALIGNED NS_AVAILABLE;
+- (void) setMethod1 : (id) object NS_AVAILABLE ALIGNED;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+- (BOOL)isClass; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+- (id (^)(id, NSArray *, NSMutableDictionary *)) expressionBlock;
+- (id (^)(id, NSArray *, NSMutableDictionary *)) MyBlock;
+- (void) setMyBlock : (id (^)(id, NSArray *, NSMutableDictionary *)) bl;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) expressionFuncptr;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) MyFuncptr;
+- (void) setMyFuncptr : (id (*)(id, NSArray *, NSMutableDictionary *)) bl;
+@end
diff --git a/test/ARCMT/objcmt-ns-nonatomic-iosonly.m.result b/test/ARCMT/objcmt-ns-nonatomic-iosonly.m.result
new file mode 100644
index 000000000000..804142ee3280
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-nonatomic-iosonly.m.result
@@ -0,0 +1,209 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-ns-nonatomic-iosonly -objcmt-migrate-readonly-property -objcmt-atomic-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+// rdar://15442742
+#if TARGET_OS_IPHONE
+ #define NS_NONATOMIC_IOSONLY nonatomic
+#else
+ #define NS_NONATOMIC_IOSONLY atomic
+#endif
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+@property (NS_NONATOMIC_IOSONLY, weak) NSString *WeakProp;
+
+@property (NS_NONATOMIC_IOSONLY, retain) NSString *StrongProp;
+
+@property (NS_NONATOMIC_IOSONLY, retain) NSString *UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+@property (NS_NONATOMIC_IOSONLY, retain) NSString *UnavailProp1 __attribute__((unavailable));
+
+@property (NS_NONATOMIC_IOSONLY, retain) NSString *UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+@property (NS_NONATOMIC_IOSONLY, copy) NSDictionary *undoAction;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+@property (NS_NONATOMIC_IOSONLY, retain) NSArray *names2;
+@property (NS_NONATOMIC_IOSONLY, retain) NSArray *names3;
+@property (NS_NONATOMIC_IOSONLY, retain) NSArray *names4;
+@property (NS_NONATOMIC_IOSONLY, retain) NSArray *names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+@property (NS_NONATOMIC_IOSONLY, assign) id target;
+
+@property (NS_NONATOMIC_IOSONLY, assign) id dataSource;
+
+@property (NS_NONATOMIC_IOSONLY, assign) id xxxdelegateYYY;
+
+
+@property (NS_NONATOMIC_IOSONLY, retain) id MYtarget;
+
+@property (NS_NONATOMIC_IOSONLY, retain) id targetX;
+
+@property (NS_NONATOMIC_IOSONLY) int value;
+
+@property (NS_NONATOMIC_IOSONLY, getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (NS_NONATOMIC_IOSONLY, getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (NS_NONATOMIC_IOSONLY, readonly) int Length;
+@property (NS_NONATOMIC_IOSONLY, readonly, retain) id object;
++ (double) D;
+@property (NS_NONATOMIC_IOSONLY, readonly) void *JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+@property (NS_NONATOMIC_IOSONLY, getter=isIgnoringInteractionEvents, readonly) BOOL ignoringInteractionEvents;
+
+@property (NS_NONATOMIC_IOSONLY, getter=getStringValue, retain) NSString *stringValue;
+@property (NS_NONATOMIC_IOSONLY, getter=getCounterValue, readonly) BOOL counterValue;
+@property (NS_NONATOMIC_IOSONLY, getter=getns_dixtionary, readonly, retain) NSDictionary *ns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (NS_NONATOMIC_IOSONLY, getter=getM, readonly) BOOL m;
+@property (NS_NONATOMIC_IOSONLY, getter=getMA, readonly) BOOL MA;
+@property (NS_NONATOMIC_IOSONLY, getter=getALL, readonly) BOOL ALL;
+@property (NS_NONATOMIC_IOSONLY, getter=getMANY, readonly) BOOL MANY;
+@property (NS_NONATOMIC_IOSONLY, getter=getSome, readonly) BOOL some;
+@end
+
+
+@interface NSInvocation(CAT)
+@property (NS_NONATOMIC_IOSONLY, assign) id target;
+
+@property (NS_NONATOMIC_IOSONLY, assign) id dataSource;
+
+@property (NS_NONATOMIC_IOSONLY, assign) id xxxdelegateYYY;
+
+
+@property (NS_NONATOMIC_IOSONLY, retain) id MYtarget;
+
+@property (NS_NONATOMIC_IOSONLY, retain) id targetX;
+
+@property (NS_NONATOMIC_IOSONLY) int value;
+
+@property (NS_NONATOMIC_IOSONLY, getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (NS_NONATOMIC_IOSONLY, getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (NS_NONATOMIC_IOSONLY, readonly) int Length;
+@property (NS_NONATOMIC_IOSONLY, readonly, retain) id object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (NS_NONATOMIC_IOSONLY, getter=getM, readonly) BOOL m;
+@property (NS_NONATOMIC_IOSONLY, getter=getMA, readonly) BOOL MA;
+@property (NS_NONATOMIC_IOSONLY, getter=getALL, readonly) BOOL ALL;
+@property (NS_NONATOMIC_IOSONLY, getter=getMANY, readonly) BOOL MANY;
+@property (NS_NONATOMIC_IOSONLY, getter=getSome, readonly) BOOL some;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+@property (NS_NONATOMIC_IOSONLY, retain) NSURL *appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+@property (NS_NONATOMIC_IOSONLY, retain) NSURL *appStoreReceiptURLX NS_AVAILABLE;
+
+// Do not infer a property.
+@property (NS_NONATOMIC_IOSONLY, retain) NSURL *appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+@property (NS_NONATOMIC_IOSONLY, readonly, retain) id OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+@property (NS_NONATOMIC_IOSONLY, retain) NSURL *appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+@property (NS_NONATOMIC_IOSONLY, retain) id method1 ALIGNED NS_AVAILABLE;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+@property (NS_NONATOMIC_IOSONLY, getter=isClass, readonly) BOOL class; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+@property (NS_NONATOMIC_IOSONLY, readonly, copy) id (^expressionBlock)(id, NSArray *, NSMutableDictionary *);
+@property (NS_NONATOMIC_IOSONLY, copy) id (^MyBlock)(id, NSArray *, NSMutableDictionary *);
+@property (NS_NONATOMIC_IOSONLY, readonly) id (*expressionFuncptr)(id, NSArray *, NSMutableDictionary *);
+@property (NS_NONATOMIC_IOSONLY) id (*MyFuncptr)(id, NSArray *, NSMutableDictionary *);
+@end
diff --git a/test/ARCMT/objcmt-ns-returns-inner-pointer.m b/test/ARCMT/objcmt-ns-returns-inner-pointer.m
new file mode 100644
index 000000000000..bff7d80b9414
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-returns-inner-pointer.m
@@ -0,0 +1,129 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-returns-innerpointer-property -objcmt-migrate-annotation -objcmt-migrate-readwrite-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#ifndef NS_RETURNS_INNER_POINTER // defined in iOS 6 for sure
+#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))
+#endif
+
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+typedef unsigned long CFTypeID;
+typedef unsigned long CFOptionFlags;
+typedef unsigned long CFHashCode;
+
+typedef signed long CFIndex; /*AnyObj*/
+typedef const struct __CFArray * CFArrayRef;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+
+typedef void (*CFArrayApplierFunction)(const void *value, void *context);
+
+typedef enum CFComparisonResult : CFIndex CFComparisonResult; enum CFComparisonResult : CFIndex {
+ kCFCompareLessThan = -1L,
+ kCFCompareEqualTo = 0,
+ kCFCompareGreaterThan = 1
+};
+
+
+typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context);
+
+typedef struct __CFArray * CFMutableArrayRef;
+
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+
+typedef struct CGImage *CGImageRef;
+
+typedef struct OpaqueJSValue* JSObjectRef;
+
+typedef JSObjectRef TTJSObjectRef;
+typedef unsigned int NSUInteger;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+@interface I
+- (void*) ReturnsInnerPointer;
+- (int*) AlreadyReturnsInnerPointer NS_RETURNS_INNER_POINTER;
+@end
+
+@interface UIImage
+- (CGImageRef)CGImage;
+@end
+
+@interface NSData
+- (void *)bytes;
+- (void **) ptr_bytes __attribute__((availability(macosx,unavailable)));
+@end
+
+@interface NSMutableData
+- (void *)mutableBytes __attribute__((deprecated)) __attribute__((unavailable));
+@end
+
+@interface JS
+- (JSObjectRef)JSObject;
+- (TTJSObjectRef)JSObject1;
+- (JSObjectRef*)JSObject2;
+@end
+
+// rdar://15044991
+typedef void *SecTrustRef;
+
+@interface NSURLProtectionSpace
+@property (readonly) SecTrustRef serverTrust NS_AVAILABLE;
+- (void *) FOO NS_AVAILABLE;
+@property (readonly) void * mitTrust NS_AVAILABLE;
+
+@property (readonly) void * mittiTrust;
+
+@property (readonly) SecTrustRef XserverTrust;
+
+- (SecTrustRef) FOO1 NS_AVAILABLE;
+
++ (const NSURLProtectionSpace *)ProtectionSpace;
+
+// pointer personality functions
+@property NSUInteger (*hashFunction)(const void *item, NSUInteger (*size)(const void *item));
+@end
diff --git a/test/ARCMT/objcmt-ns-returns-inner-pointer.m.result b/test/ARCMT/objcmt-ns-returns-inner-pointer.m.result
new file mode 100644
index 000000000000..8048e06748aa
--- /dev/null
+++ b/test/ARCMT/objcmt-ns-returns-inner-pointer.m.result
@@ -0,0 +1,129 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-returns-innerpointer-property -objcmt-migrate-annotation -objcmt-migrate-readwrite-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#ifndef NS_RETURNS_INNER_POINTER // defined in iOS 6 for sure
+#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))
+#endif
+
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
+
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+typedef unsigned long CFTypeID;
+typedef unsigned long CFOptionFlags;
+typedef unsigned long CFHashCode;
+
+typedef signed long CFIndex; /*AnyObj*/
+typedef const struct __CFArray * CFArrayRef;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+
+typedef void (*CFArrayApplierFunction)(const void *value, void *context);
+
+typedef enum CFComparisonResult : CFIndex CFComparisonResult; enum CFComparisonResult : CFIndex {
+ kCFCompareLessThan = -1L,
+ kCFCompareEqualTo = 0,
+ kCFCompareGreaterThan = 1
+};
+
+
+typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context);
+
+typedef struct __CFArray * CFMutableArrayRef;
+
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+
+typedef struct CGImage *CGImageRef;
+
+typedef struct OpaqueJSValue* JSObjectRef;
+
+typedef JSObjectRef TTJSObjectRef;
+typedef unsigned int NSUInteger;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
+@interface I
+- (void*) ReturnsInnerPointer NS_RETURNS_INNER_POINTER;
+- (int*) AlreadyReturnsInnerPointer NS_RETURNS_INNER_POINTER;
+@end
+
+@interface UIImage
+- (CGImageRef)CGImage CF_RETURNS_NOT_RETAINED;
+@end
+
+@interface NSData
+- (void *)bytes NS_RETURNS_INNER_POINTER;
+- (void **) ptr_bytes __attribute__((availability(macosx,unavailable))) NS_RETURNS_INNER_POINTER;
+@end
+
+@interface NSMutableData
+- (void *)mutableBytes __attribute__((deprecated)) __attribute__((unavailable)) NS_RETURNS_INNER_POINTER;
+@end
+
+@interface JS
+- (JSObjectRef)JSObject;
+- (TTJSObjectRef)JSObject1;
+- (JSObjectRef*)JSObject2 NS_RETURNS_INNER_POINTER;
+@end
+
+// rdar://15044991
+typedef void *SecTrustRef;
+
+@interface NSURLProtectionSpace
+@property (readonly) SecTrustRef NS_RETURNS_INNER_POINTER serverTrust NS_AVAILABLE;
+- (void *) FOO NS_AVAILABLE NS_RETURNS_INNER_POINTER;
+@property (readonly) void * NS_RETURNS_INNER_POINTER mitTrust NS_AVAILABLE;
+
+@property (readonly) void * NS_RETURNS_INNER_POINTER mittiTrust;
+
+@property (readonly) SecTrustRef NS_RETURNS_INNER_POINTER XserverTrust;
+
+- (SecTrustRef) FOO1 NS_AVAILABLE NS_RETURNS_INNER_POINTER;
+
++ (const NSURLProtectionSpace *)ProtectionSpace;
+
+// pointer personality functions
+@property NSUInteger (*hashFunction)(const void *item, NSUInteger (*size)(const void *item));
+@end
diff --git a/test/ARCMT/objcmt-property-availability.m b/test/ARCMT/objcmt-property-availability.m
new file mode 100644
index 000000000000..d499221a74cd
--- /dev/null
+++ b/test/ARCMT/objcmt-property-availability.m
@@ -0,0 +1,46 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+// rdar://15300059
+
+
+#define __NSi_7_0 introduced=7.0
+#define __NSi_6_0 introduced=6.0
+
+#define CF_AVAILABLE(_mac, _ios) __attribute__((availability(ios,__NSi_##_ios)))
+#define CF_AVAILABLE_MAC(_mac) __attribute__((availability(macosx,__NSi_##_mac)))
+#define CF_AVAILABLE_IOS(_ios) __attribute__((availability(macosx,unavailable)))
+
+#define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios)
+#define NS_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac)
+#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)
+
+#define UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+
+@interface MKMapItem
+- (MKMapItem *)source NS_AVAILABLE(10_9, 6_0);
+- (void)setSource:(MKMapItem *)source NS_AVAILABLE(10_9, 7_0);
+
+- (void)setDest:(MKMapItem *)source NS_AVAILABLE(10_9, 6_0);
+- (MKMapItem *)dest NS_AVAILABLE(10_9, 6_0);
+
+- (MKMapItem *)final;
+- (void)setFinal:(MKMapItem *)source;
+
+- (MKMapItem *)total NS_AVAILABLE(10_9, 6_0);
+- (void)setTotal:(MKMapItem *)source;
+
+- (MKMapItem *)comp NS_AVAILABLE(10_9, 6_0);
+- (void)setComp:(MKMapItem *)source UNAVAILABLE;
+
+- (MKMapItem *)tally UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+- (void)setTally:(MKMapItem *)source UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+
+- (MKMapItem *)itally NS_AVAILABLE(10_9, 6_0);
+- (void)setItally:(MKMapItem *)source UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+
+- (MKMapItem *)normal UNAVAILABLE;
+- (void)setNormal:(MKMapItem *)source UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+@end
+
diff --git a/test/ARCMT/objcmt-property-availability.m.result b/test/ARCMT/objcmt-property-availability.m.result
new file mode 100644
index 000000000000..681f9a99bf55
--- /dev/null
+++ b/test/ARCMT/objcmt-property-availability.m.result
@@ -0,0 +1,43 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+// rdar://15300059
+
+
+#define __NSi_7_0 introduced=7.0
+#define __NSi_6_0 introduced=6.0
+
+#define CF_AVAILABLE(_mac, _ios) __attribute__((availability(ios,__NSi_##_ios)))
+#define CF_AVAILABLE_MAC(_mac) __attribute__((availability(macosx,__NSi_##_mac)))
+#define CF_AVAILABLE_IOS(_ios) __attribute__((availability(macosx,unavailable)))
+
+#define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios)
+#define NS_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac)
+#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)
+
+#define UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+
+@interface MKMapItem
+@property (nonatomic, retain) MKMapItem *source NS_AVAILABLE(10_9, 6_0);
+- (void)setSource:(MKMapItem *)source NS_AVAILABLE(10_9, 7_0);
+
+@property (nonatomic, retain) MKMapItem *dest NS_AVAILABLE(10_9, 6_0);
+
+@property (nonatomic, retain) MKMapItem *final;
+
+@property (nonatomic, retain) MKMapItem *total NS_AVAILABLE(10_9, 6_0);
+- (void)setTotal:(MKMapItem *)source;
+
+- (MKMapItem *)comp NS_AVAILABLE(10_9, 6_0);
+- (void)setComp:(MKMapItem *)source UNAVAILABLE;
+
+@property (nonatomic, retain) MKMapItem *tally UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+
+- (MKMapItem *)itally NS_AVAILABLE(10_9, 6_0);
+- (void)setItally:(MKMapItem *)source UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+
+- (MKMapItem *)normal UNAVAILABLE;
+- (void)setNormal:(MKMapItem *)source UNAVAILABLE NS_AVAILABLE(10_9, 6_0);
+@end
+
diff --git a/test/ARCMT/objcmt-property.m b/test/ARCMT/objcmt-property.m
new file mode 100644
index 000000000000..3b77aadb892b
--- /dev/null
+++ b/test/ARCMT/objcmt-property.m
@@ -0,0 +1,237 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+- (void) setWeakProp : (NSString *__weak)Val;
+- (NSString *__weak) WeakProp;
+
+- (NSString *) StrongProp;
+- (void) setStrongProp : (NSString *)Val;
+
+- (NSString *) UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+- (NSString *) UnavailProp1 __attribute__((unavailable));
+- (void) setUnavailProp1 : (NSString *)Val __attribute__((unavailable));
+
+- (NSString *) UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+- (NSDictionary*) undoAction;
+- (void) setUndoAction: (NSDictionary*)Arg;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+- (void)setNames1:(NSArray *)names;
+- (void)setNames4:(__strong NSArray *)names;
+- (void)setNames3:(__strong NSArray *)names;
+- (void)setNames2:(NSArray *)names;
+- (NSArray *) names2;
+- (NSArray *)names3;
+- (__strong NSArray *)names4;
+- (NSArray *) names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+- (void *)JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+- (BOOL)isIgnoringInteractionEvents;
+
+- (NSString *)getStringValue;
+- (BOOL)getCounterValue;
+- (void)setStringValue:(NSString *)stringValue AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER;
+- (NSDictionary *)getns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+
+@interface NSInvocation(CAT)
+- (id)target;
+- (void)setTarget:(id)target;
+
+- (id) dataSource;
+
+- (id)xxxdelegateYYY;
+- (void)setXxxdelegateYYY:(id)delegate;
+
+- (void)setDataSource:(id)source;
+
+- (id)MYtarget;
+- (void)setMYtarget: (id)target;
+
+- (id)targetX;
+- (void)setTargetX: (id)t;
+
+- (int)value;
+- (void)setValue: (int)val;
+
+-(BOOL) isContinuous;
+-(void) setContinuous:(BOOL)value;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+- (int) Length;
+- (id) object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+- (BOOL) getM;
+- (BOOL) getMA;
+- (BOOL) getALL;
+- (BOOL) getMANY;
+- (BOOL) getSome;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+- (NSURL *)appStoreReceiptURLX NS_AVAILABLE;
+- (void) setAppStoreReceiptURLX : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+- (id)OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+- (NSURL *)appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+- (id)method1 ALIGNED NS_AVAILABLE;
+- (void) setMethod1 : (id) object NS_AVAILABLE ALIGNED;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+- (BOOL)isClass; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+- (id (^)(id, NSArray *, NSMutableDictionary *)) expressionBlock;
+- (id (^)(id, NSArray *, NSMutableDictionary *)) MyBlock;
+- (void) setMyBlock : (id (^)(id, NSArray *, NSMutableDictionary *)) bl;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) expressionFuncptr;
+- (id (*)(id, NSArray *, NSMutableDictionary *)) MyFuncptr;
+- (void) setMyFuncptr : (id (*)(id, NSArray *, NSMutableDictionary *)) bl;
+@end
+
+// rdar://15231241
+@interface rdar15231241
+@property (nonatomic, readonly) double Ddelegate;
+@property (nonatomic, readonly) float Fdelegate;
+@property (nonatomic, readonly) int Idelegate;
+@property (nonatomic, readonly) BOOL Bdelegate;
+@end
diff --git a/test/ARCMT/objcmt-property.m.result b/test/ARCMT/objcmt-property.m.result
new file mode 100644
index 000000000000..c6380c80523f
--- /dev/null
+++ b/test/ARCMT/objcmt-property.m.result
@@ -0,0 +1,210 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fblocks -objcmt-migrate-readwrite-property -objcmt-migrate-readonly-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
+#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
+#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
+#define DEPRECATED __attribute__((deprecated))
+
+typedef char BOOL;
+@class NSString;
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
+
+@interface I : NSObject {
+ int ivarVal;
+}
+@property (nonatomic, weak) NSString *WeakProp;
+
+@property (nonatomic, retain) NSString *StrongProp;
+
+@property (nonatomic, retain) NSString *UnavailProp __attribute__((unavailable));
+- (void) setUnavailProp : (NSString *)Val;
+
+@property (nonatomic, retain) NSString *UnavailProp1 __attribute__((unavailable));
+
+@property (nonatomic, retain) NSString *UnavailProp2;
+- (void) setUnavailProp2 : (NSString *)Val __attribute__((unavailable));
+
+@property (nonatomic, copy) NSDictionary *undoAction;
+@end
+
+@implementation I
+@end
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+@property (nonatomic, retain) NSArray *names2;
+@property (nonatomic, retain) NSArray *names3;
+@property (nonatomic, retain) NSArray *names4;
+@property (nonatomic, retain) NSArray *names1;
+@end
+
+// Properties that contain the name "delegate" or "dataSource",
+// or have exact name "target" have unsafe_unretained attribute.
+@interface NSInvocation
+@property (nonatomic, assign) id target;
+
+@property (nonatomic, assign) id dataSource;
+
+@property (nonatomic, assign) id xxxdelegateYYY;
+
+
+@property (nonatomic, retain) id MYtarget;
+
+@property (nonatomic, retain) id targetX;
+
+@property (nonatomic) int value;
+
+@property (nonatomic, getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (nonatomic, getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (nonatomic, readonly) int Length;
+@property (nonatomic, readonly, retain) id object;
++ (double) D;
+@property (nonatomic, readonly) void *JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
+@property (nonatomic, getter=isIgnoringInteractionEvents, readonly) BOOL ignoringInteractionEvents;
+
+@property (nonatomic, getter=getStringValue, retain) NSString *stringValue;
+@property (nonatomic, getter=getCounterValue, readonly) BOOL counterValue;
+@property (nonatomic, getter=getns_dixtionary, readonly, retain) NSDictionary *ns_dixtionary;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (nonatomic, getter=getM, readonly) BOOL m;
+@property (nonatomic, getter=getMA, readonly) BOOL MA;
+@property (nonatomic, getter=getALL, readonly) BOOL ALL;
+@property (nonatomic, getter=getMANY, readonly) BOOL MANY;
+@property (nonatomic, getter=getSome, readonly) BOOL some;
+@end
+
+
+@interface NSInvocation(CAT)
+@property (nonatomic, assign) id target;
+
+@property (nonatomic, assign) id dataSource;
+
+@property (nonatomic, assign) id xxxdelegateYYY;
+
+
+@property (nonatomic, retain) id MYtarget;
+
+@property (nonatomic, retain) id targetX;
+
+@property (nonatomic) int value;
+
+@property (nonatomic, getter=isContinuous) BOOL continuous;
+
+- (id) isAnObject;
+- (void)setAnObject : (id) object;
+
+@property (nonatomic, getter=isinValid, readonly) BOOL inValid;
+- (void) setInValid : (BOOL) arg;
+
+- (void) Nothing;
+@property (nonatomic, readonly) int Length;
+@property (nonatomic, readonly, retain) id object;
++ (double) D;
+
+- (BOOL)is3bar; // watch out
+- (NSString *)get3foo; // watch out
+
+@property (nonatomic, getter=getM, readonly) BOOL m;
+@property (nonatomic, getter=getMA, readonly) BOOL MA;
+@property (nonatomic, getter=getALL, readonly) BOOL ALL;
+@property (nonatomic, getter=getMANY, readonly) BOOL MANY;
+@property (nonatomic, getter=getSome, readonly) BOOL some;
+@end
+
+DEPRECATED
+@interface I_DEP
+- (BOOL) isinValid;
+- (void) setInValid : (BOOL) arg;
+@end
+
+@interface AnotherOne
+- (BOOL) isinValid DEPRECATED;
+- (void) setInValid : (BOOL) arg;
+- (id)MYtarget;
+- (void)setMYtarget: (id)target DEPRECATED;
+- (BOOL) getM DEPRECATED;
+
+- (id)xxxdelegateYYY DEPRECATED;
+- (void)setXxxdelegateYYY:(id)delegate DEPRECATED;
+@end
+
+// rdar://14987909
+#define NS_AVAILABLE __attribute__((availability(macosx,introduced=10.0)))
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED __attribute__((aligned(16)))
+
+@interface NSURL
+// Do not infer a property.
+@property (nonatomic, retain) NSURL *appStoreReceiptURL NS_AVAILABLE;
+- (void) setAppStoreReceiptURL : (NSURL *)object;
+
+@property (nonatomic, retain) NSURL *appStoreReceiptURLX NS_AVAILABLE;
+
+// Do not infer a property.
+@property (nonatomic, retain) NSURL *appStoreReceiptURLY ;
+- (void) setAppStoreReceiptURLY : (NSURL *)object NS_AVAILABLE;
+
+@property (nonatomic, readonly, retain) id OkToInfer NS_AVAILABLE;
+
+// Do not infer a property.
+@property (nonatomic, retain) NSURL *appStoreReceiptURLZ ;
+- (void) setAppStoreReceiptURLZ : (NSURL *)object NS_AVAILABLE;
+
+// Do not infer a property.
+- (id) t1 NORETURN NS_AVAILABLE;
+- (void) setT1 : (id) arg NS_AVAILABLE;
+
+@property (nonatomic, retain) id method1 ALIGNED NS_AVAILABLE;
+
+- (NSURL *)init; // No Change
++ (id)alloc; // No Change
+
+- (BOOL)is1stClass; // Not a valid property
+@property (nonatomic, getter=isClass, readonly) BOOL class; // This is a valid property 'class' is not a keyword in ObjC
+- (BOOL)isDouble; // Not a valid property
+
+@end
+
+// rdar://15082818
+@class NSMutableDictionary;
+
+@interface NSArray
+@property (nonatomic, readonly, copy) id (^expressionBlock)(id, NSArray *, NSMutableDictionary *);
+@property (nonatomic, copy) id (^MyBlock)(id, NSArray *, NSMutableDictionary *);
+@property (nonatomic, readonly) id (*expressionFuncptr)(id, NSArray *, NSMutableDictionary *);
+@property (nonatomic) id (*MyFuncptr)(id, NSArray *, NSMutableDictionary *);
+@end
+
+// rdar://15231241
+@interface rdar15231241
+@property (nonatomic, readonly) double Ddelegate;
+@property (nonatomic, readonly) float Fdelegate;
+@property (nonatomic, readonly) int Idelegate;
+@property (nonatomic, readonly) BOOL Bdelegate;
+@end
diff --git a/test/ARCMT/objcmt-protocol-conformance.m b/test/ARCMT/objcmt-protocol-conformance.m
new file mode 100644
index 000000000000..7bc7d938177f
--- /dev/null
+++ b/test/ARCMT/objcmt-protocol-conformance.m
@@ -0,0 +1,114 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-protocol-conformance -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+@interface NSObject @end
+
+@protocol P
+- (id) Meth1: (double) arg;
+@end
+
+@interface Test1 // Test for no super class and no protocol list
+@end
+
+@implementation Test1
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@protocol P1 @end
+@protocol P2 @end
+
+@interface Test2 <P1, P2> // Test for no super class and with protocol list
+{
+ id IVAR1;
+ id IVAR2;
+}
+@end
+
+@implementation Test2
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@interface Test3 : NSObject { // Test for Super class and no protocol list
+ id IV1;
+}
+@end
+
+@implementation Test3
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@interface Test4 : NSObject <P1, P2> // Test for Super class and protocol list
+@end
+
+@implementation Test4
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+// Test5 - conforms to P3 because it implement's P3's property.
+@protocol P3
+@property (copy) id Prop;
+@end
+
+@protocol P4
+@property (copy) id Prop;
+@end
+
+@interface Test5 : NSObject<P3>
+@end
+
+@implementation Test5
+@synthesize Prop=_XXX;
+@end
+
+@protocol P5 <P3, P4>
+@property (copy) id Prop;
+@end
+
+@protocol P6 <P3, P4, P5>
+@property (copy) id Prop;
+@end
+
+@interface Test6 : NSObject // Test for minimal listing of conforming protocols
+@property (copy) id Prop;
+@end
+
+@implementation Test6
+@end
+
+@class UIDynamicAnimator, UIWindow;
+@interface UIResponder : NSObject
+@end
+
+@protocol EmptyProtocol
+@end
+
+@protocol OptionalMethodsOnly
+@optional
+- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator;
+- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;
+@end
+
+@protocol OptionalPropertiesOnly
+@optional
+@property (strong, nonatomic) id OptionalProperty;
+@end
+
+@protocol OptionalEvrything
+@optional
+- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator;
+@property (strong, nonatomic) id OptionalProperty;
+- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;
+@end
+
+@protocol UIApplicationDelegate
+@end
+
+@interface Test7 : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+@implementation Test7
+@end
+
diff --git a/test/ARCMT/objcmt-protocol-conformance.m.result b/test/ARCMT/objcmt-protocol-conformance.m.result
new file mode 100644
index 000000000000..dc0874c88f22
--- /dev/null
+++ b/test/ARCMT/objcmt-protocol-conformance.m.result
@@ -0,0 +1,114 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-protocol-conformance -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+@interface NSObject @end
+
+@protocol P
+- (id) Meth1: (double) arg;
+@end
+
+@interface Test1<P> // Test for no super class and no protocol list
+@end
+
+@implementation Test1
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@protocol P1 @end
+@protocol P2 @end
+
+@interface Test2 <P1, P2, P> // Test for no super class and with protocol list
+{
+ id IVAR1;
+ id IVAR2;
+}
+@end
+
+@implementation Test2
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@interface Test3 : NSObject<P> { // Test for Super class and no protocol list
+ id IV1;
+}
+@end
+
+@implementation Test3
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+@interface Test4 : NSObject <P1, P2, P> // Test for Super class and protocol list
+@end
+
+@implementation Test4
+- (id) Meth1: (double) arg { return 0; }
+@end
+
+// Test5 - conforms to P3 because it implement's P3's property.
+@protocol P3
+@property (copy) id Prop;
+@end
+
+@protocol P4
+@property (copy) id Prop;
+@end
+
+@interface Test5 : NSObject<P3, P4>
+@end
+
+@implementation Test5
+@synthesize Prop=_XXX;
+@end
+
+@protocol P5 <P3, P4>
+@property (copy) id Prop;
+@end
+
+@protocol P6 <P3, P4, P5>
+@property (copy) id Prop;
+@end
+
+@interface Test6 : NSObject<P6> // Test for minimal listing of conforming protocols
+@property (copy) id Prop;
+@end
+
+@implementation Test6
+@end
+
+@class UIDynamicAnimator, UIWindow;
+@interface UIResponder : NSObject
+@end
+
+@protocol EmptyProtocol
+@end
+
+@protocol OptionalMethodsOnly
+@optional
+- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator;
+- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;
+@end
+
+@protocol OptionalPropertiesOnly
+@optional
+@property (strong, nonatomic) id OptionalProperty;
+@end
+
+@protocol OptionalEvrything
+@optional
+- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator;
+@property (strong, nonatomic) id OptionalProperty;
+- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;
+@end
+
+@protocol UIApplicationDelegate
+@end
+
+@interface Test7 : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+@implementation Test7
+@end
+
diff --git a/test/ARCMT/verify.m b/test/ARCMT/verify.m
index bfb3b4b8ab55..02f7fccc6899 100644
--- a/test/ARCMT/verify.m
+++ b/test/ARCMT/verify.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -arcmt-check -verify %s
-// RUN: %clang_cc1 -arcmt-check -verify %t.invalid 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -arcmt-check -verify %t.invalid 2>&1 | FileCheck %s
#if 0
// expected-error {{should be ignored}}
diff --git a/test/ARCMT/whitelisted/Inputs/header1.h b/test/ARCMT/whitelisted/Inputs/header1.h
new file mode 100644
index 000000000000..44430f3b77e3
--- /dev/null
+++ b/test/ARCMT/whitelisted/Inputs/header1.h
@@ -0,0 +1 @@
+// the contents are not important
diff --git a/test/ARCMT/whitelisted/header1.h b/test/ARCMT/whitelisted/header1.h
new file mode 100644
index 000000000000..a3014eb5b653
--- /dev/null
+++ b/test/ARCMT/whitelisted/header1.h
@@ -0,0 +1,5 @@
+
+@interface I1 : NSObject
+-(int)prop;
+-(void)setProp:(int)p;
+@end
diff --git a/test/ARCMT/whitelisted/header1.h.result b/test/ARCMT/whitelisted/header1.h.result
new file mode 100644
index 000000000000..7808fc8a6a3f
--- /dev/null
+++ b/test/ARCMT/whitelisted/header1.h.result
@@ -0,0 +1,4 @@
+
+@interface I1 : NSObject
+@property (nonatomic) int prop;
+@end
diff --git a/test/ARCMT/whitelisted/header2.h b/test/ARCMT/whitelisted/header2.h
new file mode 100644
index 000000000000..c7577ede4a49
--- /dev/null
+++ b/test/ARCMT/whitelisted/header2.h
@@ -0,0 +1,5 @@
+
+@interface I2 : NSObject
+-(int)prop;
+-(void)setProp:(int)p;
+@end
diff --git a/test/ARCMT/whitelisted/header2.h.result b/test/ARCMT/whitelisted/header2.h.result
new file mode 100644
index 000000000000..b1b52707118e
--- /dev/null
+++ b/test/ARCMT/whitelisted/header2.h.result
@@ -0,0 +1,4 @@
+
+@interface I2 : NSObject
+@property (nonatomic) int prop;
+@end
diff --git a/test/ARCMT/whitelisted/objcmt-with-whitelist.m b/test/ARCMT/whitelisted/objcmt-with-whitelist.m
new file mode 100644
index 000000000000..1b44c9a6d9fe
--- /dev/null
+++ b/test/ARCMT/whitelisted/objcmt-with-whitelist.m
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-readwrite-property %s -triple x86_64-apple-darwin11 -migrate -o %t.remap
+// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %S/header1.h.result %S/header2.h.result
+// RUN: %clang_cc1 -objcmt-migrate-readwrite-property -objcmt-white-list-dir-path=%S/Inputs %s -triple x86_64-apple-darwin11 -migrate -o %t.remap
+// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %S/header1.h.result
+
+@interface NSObject
++ (id)alloc;
+@end
+
+#include "header1.h"
+#include "header2.h"
diff --git a/test/ARCMT/with-arc-mode-check.m b/test/ARCMT/with-arc-mode-check.m
deleted file mode 100644
index 33f31f522a58..000000000000
--- a/test/ARCMT/with-arc-mode-check.m
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -arcmt-check -fsyntax-only -fobjc-arc -x objective-c %s
-
-@protocol NSObject
-- (oneway void)release;
-@end
-
-void test1(id p) {
- [p release];
-}
diff --git a/test/ARCMT/with-arc-mode-migrate.m b/test/ARCMT/with-arc-mode-migrate.m
deleted file mode 100644
index 468859478eb0..000000000000
--- a/test/ARCMT/with-arc-mode-migrate.m
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: rm -rf %t
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
-// RUN: rm -rf %t
-
-@protocol NSObject
-- (oneway void)release;
-@end
-
-void test1(id p) {
- [p release];
-}
diff --git a/test/ARCMT/with-arc-mode-migrate.m.result b/test/ARCMT/with-arc-mode-migrate.m.result
deleted file mode 100644
index dd34b9990878..000000000000
--- a/test/ARCMT/with-arc-mode-migrate.m.result
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: rm -rf %t
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
-// RUN: rm -rf %t
-
-@protocol NSObject
-- (oneway void)release;
-@end
-
-void test1(id p) {
-}
diff --git a/test/ASTMerge/Inputs/lit.local.cfg b/test/ASTMerge/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/ASTMerge/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/ASTMerge/category.m b/test/ASTMerge/category.m
index 54a12408c480..c7d524816494 100644
--- a/test/ASTMerge/category.m
+++ b/test/ASTMerge/category.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/category1.m
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/category2.m
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: category2.m:18:1: error: instance method 'method2' has incompatible result types in different translation units ('float' vs. 'int')
// CHECK: category1.m:16:1: note: instance method 'method2' also declared here
diff --git a/test/ASTMerge/class-template.cpp b/test/ASTMerge/class-template.cpp
index eea31b1c2feb..0ab5443db7f6 100644
--- a/test/ASTMerge/class-template.cpp
+++ b/test/ASTMerge/class-template.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: class-template1.cpp:7:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long')
// CHECK: class-template2.cpp:7:15: note: declared here with type 'long'
diff --git a/test/ASTMerge/class.cpp b/test/ASTMerge/class.cpp
index 885b65e983a0..7b31187c469e 100644
--- a/test/ASTMerge/class.cpp
+++ b/test/ASTMerge/class.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class1.cpp
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class2.cpp
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 -Wno-odr | count 0
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 -Wno-odr -Werror
// CHECK: class1.cpp:5:8: warning: type 'B' has incompatible definitions in different translation units
// CHECK: class1.cpp:6:9: note: field 'y' has type 'float' here
diff --git a/test/ASTMerge/enum.c b/test/ASTMerge/enum.c
index 4380d192f1bd..7240bcced99e 100644
--- a/test/ASTMerge/enum.c
+++ b/test/ASTMerge/enum.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/enum1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/enum2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: enum1.c:9:6: warning: type 'enum E2' has incompatible definitions in different translation units
// CHECK: enum1.c:11:3: note: enumerator 'E2Enumerator2' with value 3 here
diff --git a/test/ASTMerge/function.c b/test/ASTMerge/function.c
index 8a8a03051452..89e1c699c3aa 100644
--- a/test/ASTMerge/function.c
+++ b/test/ASTMerge/function.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/function1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/function2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' vs. 'void (int, float)')
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
index 747ef38223ec..8ba5d73753a3 100644
--- a/test/ASTMerge/interface.m
+++ b/test/ASTMerge/interface.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/interface1.m
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/interface2.m
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: interface2.m:16:9: error: instance variable 'ivar2' declared with incompatible types in different translation units ('float' vs. 'int')
// CHECK: interface1.m:16:7: note: declared here with type 'int'
diff --git a/test/ASTMerge/namespace.cpp b/test/ASTMerge/namespace.cpp
index 6c46f0aa1d98..8cc0fa2a6d97 100644
--- a/test/ASTMerge/namespace.cpp
+++ b/test/ASTMerge/namespace.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/namespace1.cpp
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/namespace2.cpp
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: namespace2.cpp:16:17: error: external variable 'z' declared with incompatible types in different translation units ('double' vs. 'float')
// CHECK: namespace1.cpp:16:16: note: declared here with type 'float'
diff --git a/test/ASTMerge/property.m b/test/ASTMerge/property.m
index a8dd7c420c89..494802347696 100644
--- a/test/ASTMerge/property.m
+++ b/test/ASTMerge/property.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/property1.m
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/property2.m
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: property2.m:12:26: error: property 'Prop1' declared with incompatible types in different translation units ('int' vs. 'float')
// CHECK: property1.m:10:28: note: declared here with type 'float'
diff --git a/test/ASTMerge/struct.c b/test/ASTMerge/struct.c
index 7217222ae5c1..4f41cea26b18 100644
--- a/test/ASTMerge/struct.c
+++ b/test/ASTMerge/struct.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/struct1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/struct2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: struct1.c:13:8: warning: type 'struct S1' has incompatible definitions in different translation units
// CHECK: struct1.c:15:7: note: field 'field2' has type 'int' here
diff --git a/test/ASTMerge/typedef.c b/test/ASTMerge/typedef.c
index 6f911295b96c..79e472311874 100644
--- a/test/ASTMerge/typedef.c
+++ b/test/ASTMerge/typedef.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/typedef1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/typedef2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: typedef2.c:4:10: error: external variable 'x2' declared with incompatible types in different translation units ('Typedef2' (aka 'double') vs. 'Typedef2' (aka 'int'))
// CHECK: typedef1.c:4:10: note: declared here with type 'Typedef2' (aka 'int')
diff --git a/test/ASTMerge/var.c b/test/ASTMerge/var.c
index e1dde6abd2ac..e14dc37edac7 100644
--- a/test/ASTMerge/var.c
+++ b/test/ASTMerge/var.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/var1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/var2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s
// CHECK: var2.c:2:9: error: external variable 'x1' declared with incompatible types in different translation units ('double *' vs. 'float **')
// CHECK: var1.c:2:9: note: declared here with type 'float **'
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index 6e434a04b23d..9bb8ec48923d 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -5,6 +5,8 @@
// suppressed.
#pragma clang system_header
+typedef unsigned char uint8_t;
+
namespace std {
template <class T1, class T2>
struct pair {
@@ -74,6 +76,34 @@ namespace std {
extern const nothrow_t nothrow;
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(0), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+
template<class InputIter, class OutputIter>
OutputIter copy(InputIter II, InputIter IE, OutputIter OI) {
while (II != IE)
@@ -86,6 +116,65 @@ namespace std {
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 _Tp>
+ class allocator {
+ public:
+ void deallocate(void *p) {
+ ::delete p;
+ }
+ };
+
+ template <class _Alloc>
+ class allocator_traits {
+ public:
+ static void deallocate(void *p) {
+ _Alloc().deallocate(p);
+ }
+ };
+
+ template <class _Tp, class _Alloc>
+ class __list_imp
+ {};
+
+ template <class _Tp, class _Alloc = allocator<_Tp> >
+ class list
+ : private __list_imp<_Tp, _Alloc>
+ {
+ public:
+ void pop_front() {
+ // Fake use-after-free.
+ // No warning is expected as we are suppressing warning comming
+ // out of std::list.
+ int z = 0;
+ z = 5/z;
+ }
+ bool empty() const;
+ };
+
+ // basic_string
+ template<class _CharT, class _Alloc = allocator<_CharT> >
+ class __attribute__ ((__type_visibility__("default"))) basic_string {
+ _CharT localStorage[4];
+
+ typedef allocator_traits<_Alloc> __alloc_traits;
+
+ public:
+ void push_back(int c) {
+ // Fake error trigger.
+ // No warning is expected as we are suppressing warning comming
+ // out of std::basic_string.
+ int z = 0;
+ z = 5/z;
+ }
+
+ basic_string &operator +=(int c) {
+ // Fake deallocate stack-based storage.
+ // No warning is expected as we are suppressing warnings within
+ // allocators being used by std::basic_string.
+ __alloc_traits::deallocate(&localStorage);
+ }
+ };
}
void* operator new(std::size_t, const std::nothrow_t&) throw();
diff --git a/test/Analysis/Inputs/system-header-simulator-objc.h b/test/Analysis/Inputs/system-header-simulator-objc.h
index ecc99e17c495..3e1d9555bbde 100644
--- a/test/Analysis/Inputs/system-header-simulator-objc.h
+++ b/test/Analysis/Inputs/system-header-simulator-objc.h
@@ -102,6 +102,7 @@ typedef double NSTimeInterval;
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+- (id)initWithBytes:(void *)bytes length:(NSUInteger) length;
@end
typedef struct {
diff --git a/test/Analysis/Inputs/system-header-simulator.h b/test/Analysis/Inputs/system-header-simulator.h
index dd1cd4942f85..8b8c9c4fe17b 100644
--- a/test/Analysis/Inputs/system-header-simulator.h
+++ b/test/Analysis/Inputs/system-header-simulator.h
@@ -32,6 +32,7 @@ typedef __typeof(sizeof(int)) size_t;
size_t strlen(const char *);
char *strcpy(char *restrict, const char *restrict);
+void *memcpy(void *dst, const void *src, size_t n);
typedef unsigned long __darwin_pthread_key_t;
typedef __darwin_pthread_key_t pthread_key_t;
@@ -77,8 +78,9 @@ void xpc_connection_set_context(xpc_connection_t connection, void *context);
void xpc_connection_set_finalizer_f(xpc_connection_t connection, xpc_finalizer_t finalizer);
void xpc_connection_resume(xpc_connection_t connection);
-//The following is a fake system header function
+//The following are fake system header functions for generic testing.
void fakeSystemHeaderCallInt(int *);
+void fakeSystemHeaderCallIntPtr(int **);
typedef struct __SomeStruct {
char * p;
diff --git a/test/Analysis/MismatchedDeallocator-checker-test.mm b/test/Analysis/MismatchedDeallocator-checker-test.mm
index 56d46d99b0b9..0df5db5191f5 100644
--- a/test/Analysis/MismatchedDeallocator-checker-test.mm
+++ b/test/Analysis/MismatchedDeallocator-checker-test.mm
@@ -112,8 +112,7 @@ void testNew10() {
void testNew11(NSUInteger dataLength) {
int *p = new int;
- NSData *d = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not +dataWithBytesNoCopy:length:freeWhenDone:}}
- // FIXME: should be "+dataWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'."
+ NSData *d = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{+dataWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'}}
}
//-------------------------------------------------------
diff --git a/test/Analysis/MismatchedDeallocator-path-notes.cpp b/test/Analysis/MismatchedDeallocator-path-notes.cpp
index 369d8f69756a..61ab4f1eeb5a 100644
--- a/test/Analysis/MismatchedDeallocator-path-notes.cpp
+++ b/test/Analysis/MismatchedDeallocator-path-notes.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=plist %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void changePointee(int *p);
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index 540c7a4eabdd..a9e76fbbcaba 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops -verify -Wno-objc-root-class %s
typedef unsigned long NSUInteger;
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@@ -14,8 +14,6 @@ typedef struct _NSZone NSZone;
@protocol NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder;
@end
-@protocol NSFastEnumeration
-@end
@protocol NSSecureCoding <NSCoding>
@required
+ (BOOL)supportsSecureCoding;
@@ -24,11 +22,20 @@ typedef struct _NSZone NSZone;
- (id)init;
+ (id)alloc;
@end
-@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
+typedef struct {
+ unsigned long state;
+ id *itemsPtr;
+ unsigned long *mutationsPtr;
+ unsigned long extra[5];
+} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len;
+@end
+
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index;
-
@end
@interface NSArray (NSExtendedArray)
@@ -36,6 +43,10 @@ typedef struct _NSZone NSZone;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8)));
@end
+@interface NSArray (NSArrayCreation)
++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
@interface NSMutableArray : NSArray
- (void)addObject:(id)anObject;
@@ -58,6 +69,8 @@ typedef struct _NSZone NSZone;
+ (id)dictionary;
+ (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key;
++ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+
@end
@interface NSMutableDictionary : NSDictionary
@@ -77,10 +90,20 @@ typedef struct _NSZone NSZone;
@end
+@interface NSOrderedSet : NSObject <NSFastEnumeration>
+@end
+@interface NSOrderedSet (NSOrderedSetCreation)
+- (NSUInteger)count;
+@end
+
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
@end
+@interface NSNull : NSObject <NSCopying, NSSecureCoding>
++ (NSNull *)null;
+@end
+
// NSMutableArray API
void testNilArgNSMutableArray1() {
NSMutableArray *marray = [[NSMutableArray alloc] init];
@@ -143,6 +166,33 @@ NSDictionary *testNilArgNSDictionary2(NSObject *obj) {
return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}}
}
+id testCreateDictionaryLiteralKey(id value, id nilKey) {
+ if (nilKey)
+ ;
+ return @{@"abc":value, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}}
+}
+
+id testCreateDictionaryLiteralValue(id nilValue) {
+ if (nilValue)
+ ;
+ return @{@"abc":nilValue}; // expected-warning {{Dictionary value cannot be nil}}
+}
+
+id testCreateDictionaryLiteral(id nilValue, id nilKey) {
+ if (nilValue)
+ ;
+ if (nilKey)
+ ;
+ return @{@"abc":nilValue, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}}
+ // expected-warning@-1 {{Dictionary value cannot be nil}}
+}
+
+id testCreateArrayLiteral(id myNil) {
+ if (myNil)
+ ;
+ return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}}
+}
+
// Test inline defensive checks suppression.
void idc(id x) {
if (x)
@@ -197,4 +247,32 @@ void testNilReceiverRetNil2(NSMutableDictionary *D, Foo *FooPtrIn, id value) {
[D setObject: value forKey: key]; // no-warning
}
+void testAssumeNSNullNullReturnsNonNil(NSMutableDictionary *Table, id Object,
+ id InValue) {
+ id Value = Object ? [Table objectForKey:Object] : [NSNull null];
+ if (!Value) {
+ Value = InValue;
+ [Table setObject:Value forKey:Object]; // no warning
+ }
+}
+
+void testCollectionIsNotEmptyWhenCountIsGreaterThanZero(NSMutableDictionary *D){
+ if ([D count] > 0) { // Count is greater than zero.
+ NSString *s = 0;
+ for (NSString *key in D) {
+ s = key; // Loop is always entered.
+ }
+ [D removeObjectForKey:s]; // no warning
+ }
+}
+
+void testCountAwareNSOrderedSet(NSOrderedSet *containers, int *validptr) {
+ int *x = 0;
+ NSUInteger containerCount = [containers count];
+ if (containerCount > 0)
+ x = validptr;
+ for (id c in containers) {
+ *x = 1; // no warning
+ }
+}
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index 5d134bc36e23..cc9725128bc8 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -4,6 +4,7 @@
typedef __typeof__(sizeof(int)) size_t;
extern "C" void *malloc(size_t);
+extern "C" void free (void* ptr);
int *global;
//------------------
@@ -206,3 +207,154 @@ void testConstEscapePlacementNew() {
void *y = new (x) int;
escapeVoidPtr(y);
} // no-warning
+
+//============== Test Uninitialized delete delete[]========================
+void testUninitDelete() {
+ int *x;
+ int * y = new int;
+ delete y;
+ delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
+}
+
+void testUninitDeleteArray() {
+ int *x;
+ int * y = new int[5];
+ delete[] y;
+ delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
+}
+
+void testUninitFree() {
+ int *x;
+ free(x); // expected-warning{{Function call argument is an uninitialized value}}
+}
+
+void testUninitDeleteSink() {
+ int *x;
+ delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
+ (*(volatile int *)0 = 1); // no warn
+}
+
+void testUninitDeleteArraySink() {
+ int *x;
+ delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
+ (*(volatile int *)0 = 1); // no warn
+}
+
+namespace reference_count {
+ class control_block {
+ unsigned count;
+ public:
+ control_block() : count(0) {}
+ void retain() { ++count; }
+ int release() { return --count; }
+ };
+
+ template <typename T>
+ class shared_ptr {
+ T *p;
+ control_block *control;
+
+ public:
+ shared_ptr() : p(0), control(0) {}
+ explicit shared_ptr(T *p) : p(p), control(new control_block) {
+ control->retain();
+ }
+ shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
+ if (control)
+ control->retain();
+ }
+ ~shared_ptr() {
+ if (control && control->release() == 0) {
+ delete p;
+ delete control;
+ }
+ };
+
+ T &operator *() {
+ return *p;
+ };
+
+ void swap(shared_ptr &other) {
+ T *tmp = p;
+ p = other.p;
+ other.p = tmp;
+
+ control_block *ctrlTmp = control;
+ control = other.control;
+ other.control = ctrlTmp;
+ }
+ };
+
+ void testSingle() {
+ shared_ptr<int> a(new int);
+ *a = 1;
+ }
+
+ void testDouble() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b = a;
+ *a = 1;
+ }
+
+ void testInvalidated() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b = a;
+ *a = 1;
+
+ extern void use(shared_ptr<int> &);
+ use(b);
+ }
+
+ void testNestedScope() {
+ shared_ptr<int> a(new int);
+ {
+ shared_ptr<int> b = a;
+ }
+ *a = 1;
+ }
+
+ void testSwap() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b;
+ shared_ptr<int> c = a;
+ shared_ptr<int>(c).swap(b);
+ }
+
+ void testUseAfterFree() {
+ int *p = new int;
+ {
+ shared_ptr<int> a(p);
+ shared_ptr<int> b = a;
+ }
+
+ // FIXME: We should get a warning here, but we don't because we've
+ // conservatively modeled ~shared_ptr.
+ *p = 1;
+ }
+}
+
+// Test double delete
+class DerefClass{
+public:
+ int *x;
+ DerefClass() {}
+ ~DerefClass() {*x = 1;} //expected-warning {{Use of memory after it is freed}}
+};
+
+void testDoubleDeleteClassInstance() {
+ DerefClass *foo = new DerefClass();
+ delete foo;
+ delete foo; // FIXME: We should ideally report warning here instead of inside the destructor.
+}
+
+class EmptyClass{
+public:
+ EmptyClass() {}
+ ~EmptyClass() {}
+};
+
+void testDoubleDeleteEmptyClass() {
+ EmptyClass *foo = new EmptyClass();
+ delete foo;
+ delete foo; //expected-warning {{Attempt to free released memory}}
+}
diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp
index 85b71be68ce2..b420551c3e9a 100644
--- a/test/Analysis/NewDelete-path-notes.cpp
+++ b/test/Analysis/NewDelete-path-notes.cpp
@@ -1,13 +1,12 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=plist %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void test() {
int *p = new int;
// expected-note@-1 {{Memory is allocated}}
if (p)
- // expected-note@-1 {{Assuming 'p' is non-null}}
- // expected-note@-2 {{Taking true branch}}
+ // expected-note@-1 {{Taking true branch}}
delete p;
// expected-note@-1 {{Memory is released}}
@@ -151,75 +150,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>8</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>8</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>8</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>8</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>8</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>Assuming &apos;p&apos; is non-null</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is non-null</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>8</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>8</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: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// 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>
@@ -231,7 +167,7 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -239,12 +175,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -264,12 +200,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// 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>
@@ -277,12 +213,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>13</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>14</integer>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -294,7 +230,7 @@ void test(Odd *odd) {
// 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>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -302,12 +238,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>13</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>14</integer>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -325,10 +261,10 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>type</key><string>Double free</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test</string>
-// CHECK-NEXT: <key>issue_hash</key><string>9</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -340,7 +276,7 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -348,12 +284,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -369,7 +305,7 @@ void test(Odd *odd) {
// 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>line</key><integer>18</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -387,12 +323,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>18</integer>
// CHECK-NEXT: <key>col</key><integer>2</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>line</key><integer>18</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -400,12 +336,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// 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>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -417,7 +353,7 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// 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>
@@ -425,12 +361,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// 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>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -446,7 +382,7 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -454,12 +390,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -479,12 +415,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -492,12 +428,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>2</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>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -509,7 +445,7 @@ void test(Odd *odd) {
// 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>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -517,12 +453,12 @@ void test(Odd *odd) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>2</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>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -543,7 +479,7 @@ void test(Odd *odd) {
// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index a58efdd02948..c74d54eae528 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -123,3 +123,11 @@ void PR11959(int *p) {
*p = 0xDEADBEEF; // no-warning
}
+// Test that hard-coded Microsoft _wassert name is recognized as a noreturn
+#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(#_Expression, __FILE__, __LINE__), 0) )
+extern void _wassert(const char * _Message, const char *_File, unsigned _Line);
+void test_wassert() {
+ assert(0);
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index bf18a5eb3e71..521344a5119a 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -13,6 +13,7 @@ public:
// CHECK: [config]
// CHECK-NEXT: c++-container-inlining = false
// CHECK-NEXT: c++-inlining = destructors
+// CHECK-NEXT: c++-shared_ptr-inlining = false
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-template-inlining = true
// CHECK-NEXT: cfg-conditional-static-initializers = true
@@ -28,4 +29,4 @@ public:
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 16
+// CHECK-NEXT: num-entries = 17
diff --git a/test/Analysis/array-struct-region.cpp b/test/Analysis/array-struct-region.cpp
index 12ae5d3eba6e..47776863d6a2 100644
--- a/test/Analysis/array-struct-region.cpp
+++ b/test/Analysis/array-struct-region.cpp
@@ -21,7 +21,7 @@ struct S {
#if __cplusplus
const struct S *operator -(const struct S &s) { return &s; }
-bool operator ~(const struct S &s) { return &s != &s; }
+bool operator ~(const struct S &s) { return (&s) != &s; }
#endif
@@ -173,4 +173,27 @@ void testImmediateUseOp() {
clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
}
+namespace EmptyClass {
+ struct Base {
+ int& x;
+
+ Base(int& x) : x(x) {}
+ };
+
+ struct Derived : public Base {
+ Derived(int& x) : Base(x) {}
+
+ void operator=(int a) { x = a; }
+ };
+
+ Derived ref(int& a) { return Derived(a); }
+
+ // There used to be a warning here, because analyzer treated Derived as empty.
+ int test() {
+ int a;
+ ref(a) = 42;
+ return a; // no warning
+ }
+}
+
#endif
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 0fc651739119..0dbbfb592f71 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -3,24 +3,93 @@
class A {
public:
+// CHECK: [B1 (ENTRY)]
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
A() {}
+
+// CHECK: [B1 (ENTRY)]
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
~A() {}
+
+// 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; }
};
extern const bool UV;
+// 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: 10: const A &c = A();
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// 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];
+// CHECK-NEXT: 5: [B1.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 8: [B1.4].~A() (Implicit destructor)
+// CHECK-NEXT: 9: (CXXConstructExpr, class A)
+// CHECK: 10: A b;
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// 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;
@@ -29,6 +98,34 @@ void test_scope() {
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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B3.4].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B3.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B3.4].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B3.2].~A() (Implicit destructor)
+// 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;
@@ -36,6 +133,59 @@ void test_return() {
A c;
}
+// CHECK: [B8 (ENTRY)]
+// CHECK-NEXT: Succs (1): B7
+// CHECK: [B1]
+// CHECK: l1:
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B6.2].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B7.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A b;
+// CHECK-NEXT: 3: [B2.2].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT: T: goto l1;
+// CHECK: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B4]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B4.2]
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK-NEXT: 1: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B6.2].~A() (Implicit destructor)
+// CHECK-NEXT: T: goto l0;
+// CHECK: Preds (1): B6
+// CHECK-NEXT: Succs (1): B6
+// CHECK: [B6]
+// CHECK: l0:
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A b;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A a;
+// CHECK-NEXT: 5: UV
+// CHECK-NEXT: 6: [B6.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B6.6]
+// CHECK-NEXT: Preds (2): B7 B5
+// CHECK-NEXT: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B6
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
void test_goto() {
A a;
l0:
@@ -49,6 +199,43 @@ l1:
A c;
}
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.6].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B4.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// 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: 10: [B4.9]()
+// CHECK: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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)
@@ -56,6 +243,78 @@ void test_if_implicit_scope() {
else A c;
}
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B8.6].~A() (Implicit destructor)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B8.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B4.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B4.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B8.6].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B8.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B7.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B6]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B7.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B8.6].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B8.2].~A() (Implicit destructor)
+// 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: 10: [B8.9]()
+// CHECK: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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) {
@@ -70,12 +329,130 @@ void test_if_jumps() {
A e;
}
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B5.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B4.4].~A() (Implicit destructor)
+// 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.7]()
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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].~A() (Implicit destructor)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B10.4].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B10.4].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B10.4].~A() (Implicit destructor)
+// CHECK-NEXT: T: continue;
+// CHECK: 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].~A() (Implicit destructor)
+// CHECK-NEXT: T: break;
+// CHECK: 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.7]()
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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) {
@@ -88,11 +465,98 @@ void test_while_jumps() {
A e;
}
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B1]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: do ... while [B1.2]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (2): B3 B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: [B2.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (2): B3 B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: Preds (1): B1
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
void test_do_implicit_scope() {
do A a;
while (UV);
}
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: T: continue;
+// CHECK: 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].~A() (Implicit destructor)
+// CHECK-NEXT: T: break;
+// CHECK: 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 {
@@ -105,12 +569,107 @@ void test_do_jumps() {
A d;
}
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B2.6].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B2.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (2): B3 B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: T: switch [B2.11]
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
void test_switch_implicit_scope() {
A a;
switch (A b = a)
A c;
}
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B2.6].~A() (Implicit destructor)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A g;
+// CHECK-NEXT: 4: [B1.3].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B2.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (3): B3 B7 B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: T: switch [B2.11]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (3): B3 B8 B1
+// CHECK: [B3]
+// CHECK: case 1:
+// CHECK-NEXT: T: break;
+// CHECK: Preds (2): B2 B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B4]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A f;
+// CHECK-NEXT: 3: [B4.2].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B8.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B5]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B8.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B2.6].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B2.2].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B6]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B6.2]
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK-NEXT: 1: [B8.2].~A() (Implicit destructor)
+// CHECK-NEXT: T: break;
+// CHECK: Preds (1): B8
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B8]
+// CHECK: case 0:
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B8.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B8.4]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (2): B7 B6
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B5
void test_switch_jumps() {
A a;
switch (A b = a) {
@@ -126,11 +685,132 @@ void test_switch_jumps() {
A g;
}
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B5.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B4.4].~A() (Implicit destructor)
+// 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.7]()
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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].~A() (Implicit destructor)
+// CHECK-NEXT: 2: [B11.4].~A() (Implicit destructor)
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A f;
+// CHECK-NEXT: 5: [B1.4].~A() (Implicit destructor)
+// CHECK-NEXT: 6: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B10.4].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2].~A() (Implicit destructor)
+// CHECK-NEXT: 3: [B10.4].~A() (Implicit destructor)
+// CHECK-NEXT: 4: [B11.4].~A() (Implicit destructor)
+// CHECK-NEXT: 5: [B11.2].~A() (Implicit destructor)
+// 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].~A() (Implicit destructor)
+// CHECK-NEXT: T: continue;
+// CHECK: 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].~A() (Implicit destructor)
+// CHECK-NEXT: T: break;
+// CHECK: 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.7]()
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 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; ) {
@@ -143,722 +823,41 @@ void test_for_jumps() {
A f;
}
+// CHECK: [B3 (ENTRY)]
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B1]
+// CHECK-NEXT: T: try ...
+// CHECK-NEXT: Succs (2): B2 B0
+// CHECK: [B2]
+// CHECK-NEXT: catch (const A &e):
+// CHECK-NEXT: 1: catch (const A &e) {
+// CHECK-NEXT: }
+// CHECK-NEXT: Preds (1): B1
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (3): B2 B1 B3
void test_catch_const_ref() {
try {
} catch (const A& e) {
}
}
+// CHECK: [B3 (ENTRY)]
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B1]
+// CHECK-NEXT: T: try ...
+// CHECK-NEXT: Succs (2): B2 B0
+// CHECK: [B2]
+// CHECK-NEXT: catch (A e):
+// CHECK-NEXT: 1: catch (A e) {
+// CHECK-NEXT: }
+// CHECK-NEXT: 2: [B2.1].~A() (Implicit destructor)
+// CHECK-NEXT: Preds (1): B1
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (3): B2 B1 B3
void test_catch_copy() {
try {
} catch (A e) {
}
}
-
-// CHECK: [B1 (ENTRY)]
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B1 (ENTRY)]
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B2 (ENTRY)]
-// CHECK: Succs (1): B1
-// CHECK: [B1]
-// CHECK: 1: 1
-// CHECK: 2: return [B1.1];
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B2 (ENTRY)]
-// CHECK: Succs (1): B1
-// CHECK: [B1]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 5: const A &b = a;
-// CHECK: 6: A() (CXXConstructExpr, class A)
-// CHECK: 7: [B1.6] (BindTemporary)
-// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B1.8]
-// CHECK: 10: const A &c = A();
-// CHECK: 11: [B1.10].~A() (Implicit destructor)
-// CHECK: 12: [B1.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B2 (ENTRY)]
-// CHECK: Succs (1): B1
-// CHECK: [B1]
-// CHECK: 1: (CXXConstructExpr, class A [2])
-// CHECK: 2: A a[2];
-// CHECK: 3: (CXXConstructExpr, class A [0])
-// CHECK: 4: A b[0];
-// CHECK: 5: [B1.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B2 (ENTRY)]
-// CHECK: Succs (1): B1
-// CHECK: [B1]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: (CXXConstructExpr, class A)
-// CHECK: 4: A c;
-// CHECK: 5: (CXXConstructExpr, class A)
-// CHECK: 6: A d;
-// CHECK: 7: [B1.6].~A() (Implicit destructor)
-// CHECK: 8: [B1.4].~A() (Implicit destructor)
-// CHECK: 9: (CXXConstructExpr, class A)
-// CHECK: 10: A b;
-// CHECK: 11: [B1.10].~A() (Implicit destructor)
-// CHECK: 12: [B1.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B4 (ENTRY)]
-// CHECK: Succs (1): B3
-// CHECK: [B1]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B3.4].~A() (Implicit destructor)
-// CHECK: 5: [B3.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B3
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: return;
-// CHECK: 2: [B3.4].~A() (Implicit destructor)
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B3
-// CHECK: Succs (1): B0
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: (CXXConstructExpr, class A)
-// CHECK: 4: A b;
-// CHECK: 5: UV
-// CHECK: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B3.6]
-// CHECK: Preds (1): B4
-// CHECK: Succs (2): B2 B1
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (2): B1 B2
-// CHECK: [B8 (ENTRY)]
-// CHECK: Succs (1): B7
-// CHECK: [B1]
-// CHECK: l1:
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.2].~A() (Implicit destructor)
-// CHECK: 5: [B7.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B2 B3
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A b;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.4].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B3]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: T: goto l1;
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B4]
-// CHECK: 1: UV
-// CHECK: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B4.2]
-// CHECK: Preds (1): B6
-// CHECK: Succs (2): B3 B2
-// CHECK: [B5]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: 2: [B6.2].~A() (Implicit destructor)
-// CHECK: T: goto l0;
-// CHECK: Preds (1): B6
-// CHECK: Succs (1): B6
-// CHECK: [B6]
-// CHECK: l0:
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A b;
-// CHECK: 3: (CXXConstructExpr, class A)
-// CHECK: 4: A a;
-// CHECK: 5: UV
-// CHECK: 6: [B6.5] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B6.6]
-// CHECK: Preds (2): B7 B5
-// CHECK: Succs (2): B5 B4
-// CHECK: [B7]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: Preds (1): B8
-// CHECK: Succs (1): B6
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B5 (ENTRY)]
-// CHECK: Succs (1): B4
-// CHECK: [B1]
-// CHECK: 1: [B4.6].~A() (Implicit destructor)
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B2 B3
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B4]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 5: [B4.4] (CXXConstructExpr, class A)
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B4.8].operator int
-// CHECK: 10: [B4.9]()
-// CHECK: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: if [B4.12]
-// CHECK: Preds (1): B5
-// CHECK: Succs (2): B3 B2
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B9 (ENTRY)]
-// CHECK: Succs (1): B8
-// CHECK: [B1]
-// CHECK: 1: [B8.6].~A() (Implicit destructor)
-// CHECK: 2: (CXXConstructExpr, class A)
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B8.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B2 B5
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A d;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B4.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B3]
-// CHECK: 1: return;
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.6].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B0
-// CHECK: [B4]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B4.4]
-// CHECK: Preds (1): B8
-// CHECK: Succs (2): B3 B2
-// CHECK: [B5]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A d;
-// CHECK: 3: [B5.2].~A() (Implicit destructor)
-// CHECK: 4: [B7.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B7
-// CHECK: Succs (1): B1
-// CHECK: [B6]
-// CHECK: 1: return;
-// CHECK: 2: [B7.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.6].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B7
-// CHECK: Succs (1): B0
-// CHECK: [B7]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B7.4]
-// CHECK: Preds (1): B8
-// CHECK: Succs (2): B6 B5
-// CHECK: [B8]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 5: [B8.4] (CXXConstructExpr, class A)
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B8.8].operator int
-// CHECK: 10: [B8.9]()
-// CHECK: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: if [B8.12]
-// CHECK: Preds (1): B9
-// CHECK: Succs (2): B7 B4
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (3): B1 B3 B6
-// CHECK: [B6 (ENTRY)]
-// CHECK: Succs (1): B5
-// CHECK: [B1]
-// CHECK: 1: [B4.4].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: Preds (1): B3
-// CHECK: Succs (1): B4
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B4.4].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B2
-// CHECK: [B4]
-// CHECK: 1: a
-// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 3: [B4.2] (CXXConstructExpr, class A)
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 7: [B4.6].operator int
-// CHECK: 8: [B4.7]()
-// CHECK: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: while [B4.10]
-// CHECK: Preds (2): B2 B5
-// CHECK: Succs (2): B3 B1
-// CHECK: [B5]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: Preds (1): B6
-// CHECK: Succs (1): B4
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B12 (ENTRY)]
-// CHECK: Succs (1): B11
-// CHECK: [B1]
-// CHECK: 1: [B10.4].~A() (Implicit destructor)
-// CHECK: 2: (CXXConstructExpr, class A)
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B8 B10
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: Preds (2): B3 B6
-// CHECK: Succs (1): B10
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A d;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B9.2].~A() (Implicit destructor)
-// CHECK: 5: [B10.4].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B2
-// CHECK: [B4]
-// CHECK: 1: return;
-// CHECK: 2: [B9.2].~A() (Implicit destructor)
-// CHECK: 3: [B10.4].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B0
-// CHECK: [B5]
-// CHECK: 1: UV
-// CHECK: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B5.2]
-// CHECK: Preds (1): B7
-// CHECK: Succs (2): B4 B3
-// CHECK: [B6]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: 2: [B10.4].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Preds (1): B7
-// CHECK: Succs (1): B2
-// CHECK: [B7]
-// CHECK: 1: UV
-// CHECK: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B7.2]
-// CHECK: Preds (1): B9
-// CHECK: Succs (2): B6 B5
-// CHECK: [B8]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Preds (1): B9
-// CHECK: Succs (1): B1
-// CHECK: [B9]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B9.4]
-// CHECK: Preds (1): B10
-// CHECK: Succs (2): B8 B7
-// CHECK: [B10]
-// CHECK: 1: a
-// CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 3: [B10.2] (CXXConstructExpr, class A)
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 7: [B10.6].operator int
-// CHECK: 8: [B10.7]()
-// CHECK: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: while [B10.10]
-// CHECK: Preds (2): B2 B11
-// CHECK: Succs (2): B9 B1
-// CHECK: [B11]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: Preds (1): B12
-// CHECK: Succs (1): B10
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (2): B1 B4
-// CHECK: [B4 (ENTRY)]
-// CHECK: Succs (1): B2
-// CHECK: [B1]
-// CHECK: 1: UV
-// CHECK: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: do ... while [B1.2]
-// CHECK: Preds (1): B2
-// CHECK: Succs (2): B3 B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B3 B4
-// CHECK: Succs (1): B1
-// CHECK: [B3]
-// CHECK: Preds (1): B1
-// CHECK: Succs (1): B2
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B12 (ENTRY)]
-// CHECK: Succs (1): B11
-// CHECK: [B1]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A d;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B8 B2
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: UV
-// CHECK: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: do ... while [B2.2]
-// CHECK: Preds (2): B3 B6
-// CHECK: Succs (2): B10 B1
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B9.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B2
-// CHECK: [B4]
-// CHECK: 1: return;
-// CHECK: 2: [B9.2].~A() (Implicit destructor)
-// CHECK: 3: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B0
-// CHECK: [B5]
-// CHECK: 1: UV
-// CHECK: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B5.2]
-// CHECK: Preds (1): B7
-// CHECK: Succs (2): B4 B3
-// CHECK: [B6]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Preds (1): B7
-// CHECK: Succs (1): B2
-// CHECK: [B7]
-// CHECK: 1: UV
-// CHECK: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B7.2]
-// CHECK: Preds (1): B9
-// CHECK: Succs (2): B6 B5
-// CHECK: [B8]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Preds (1): B9
-// CHECK: Succs (1): B1
-// CHECK: [B9]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A b;
-// CHECK: 3: UV
-// CHECK: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B9.4]
-// CHECK: Preds (2): B10 B11
-// CHECK: Succs (2): B8 B7
-// CHECK: [B10]
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B9
-// CHECK: [B11]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: Preds (1): B12
-// CHECK: Succs (1): B9
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (2): B1 B4
-// CHECK: [B4 (ENTRY)]
-// CHECK: Succs (1): B2
-// CHECK: [B1]
-// CHECK: 1: [B2.6].~A() (Implicit destructor)
-// CHECK: 2: [B2.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B3 B2
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 5: [B2.4] (CXXConstructExpr, class A)
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B2.8].operator int
-// CHECK: 10: [B2.9]()
-// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: T: switch [B2.11]
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B1
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Succs (1): B1
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B9 (ENTRY)]
-// CHECK: Succs (1): B2
-// CHECK: [B1]
-// CHECK: 1: [B2.6].~A() (Implicit destructor)
-// CHECK: 2: (CXXConstructExpr, class A)
-// CHECK: 3: A g;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B2.2].~A() (Implicit destructor)
-// CHECK: Preds (3): B3 B7 B2
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 5: [B2.4] (CXXConstructExpr, class A)
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B2.8].operator int
-// CHECK: 10: [B2.9]()
-// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: T: switch [B2.11]
-// CHECK: Preds (1): B9
-// CHECK: Succs (3): B3 B8
-// CHECK: B1
-// CHECK: [B3]
-// CHECK: case 1:
-// CHECK: T: break;
-// CHECK: Preds (2): B2 B4
-// CHECK: Succs (1): B1
-// CHECK: [B4]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A f;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B6
-// CHECK: Succs (1): B3
-// CHECK: [B5]
-// CHECK: 1: return;
-// CHECK: 2: [B8.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.6].~A() (Implicit destructor)
-// CHECK: 4: [B2.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B6
-// CHECK: Succs (1): B0
-// CHECK: [B6]
-// CHECK: 1: UV
-// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B6.2]
-// CHECK: Preds (1): B8
-// CHECK: Succs (2): B5 B4
-// CHECK: [B7]
-// CHECK: 1: [B8.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Preds (1): B8
-// CHECK: Succs (1): B1
-// CHECK: [B8]
-// CHECK: case 0:
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B8.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B8.4]
-// CHECK: Preds (1): B2
-// CHECK: Succs (2): B7 B6
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (2): B1 B5
-// CHECK: [B6 (ENTRY)]
-// CHECK: Succs (1): B5
-// CHECK: [B1]
-// CHECK: 1: [B4.4].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: Preds (1): B3
-// CHECK: Succs (1): B4
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B4.4].~A() (Implicit destructor)
-// CHECK: Preds (1): B4
-// CHECK: Succs (1): B2
-// CHECK: [B4]
-// CHECK: 1: a
-// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 3: [B4.2] (CXXConstructExpr, class A)
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 7: [B4.6].operator int
-// CHECK: 8: [B4.7]()
-// CHECK: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: for (...; [B4.10]; )
-// CHECK: Preds (2): B2 B5
-// CHECK: Succs (2): B3 B1
-// CHECK: [B5]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: Preds (1): B6
-// CHECK: Succs (1): B4
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
-// CHECK: [B12 (ENTRY)]
-// CHECK: Succs (1): B11
-// CHECK: [B1]
-// CHECK: 1: [B10.4].~A() (Implicit destructor)
-// CHECK: 2: [B11.4].~A() (Implicit destructor)
-// CHECK: 3: (CXXConstructExpr, class A)
-// CHECK: 4: A f;
-// CHECK: 5: [B1.4].~A() (Implicit destructor)
-// CHECK: 6: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (2): B8 B10
-// CHECK: Succs (1): B0
-// CHECK: [B2]
-// CHECK: Preds (2): B3 B6
-// CHECK: Succs (1): B10
-// CHECK: [B3]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A e;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B9.2].~A() (Implicit destructor)
-// CHECK: 5: [B10.4].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B2
-// CHECK: [B4]
-// CHECK: 1: return;
-// CHECK: 2: [B9.2].~A() (Implicit destructor)
-// CHECK: 3: [B10.4].~A() (Implicit destructor)
-// CHECK: 4: [B11.4].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Preds (1): B5
-// CHECK: Succs (1): B0
-// CHECK: [B5]
-// CHECK: 1: UV
-// CHECK: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B5.2]
-// CHECK: Preds (1): B7
-// CHECK: Succs (2): B4 B3
-// CHECK: [B6]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Preds (1): B7
-// CHECK: Succs (1): B2
-// CHECK: [B7]
-// CHECK: 1: UV
-// CHECK: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B7.2]
-// CHECK: Preds (1): B9
-// CHECK: Succs (2): B6 B5
-// CHECK: [B8]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Preds (1): B9
-// CHECK: Succs (1): B1
-// CHECK: [B9]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A d;
-// CHECK: 3: UV
-// CHECK: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK: T: if [B9.4]
-// CHECK: Preds (1): B10
-// CHECK: Succs (2): B8 B7
-// CHECK: [B10]
-// CHECK: 1: b
-// CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 3: [B10.2] (CXXConstructExpr, class A)
-// CHECK: 4: A c = b;
-// CHECK: 5: c
-// CHECK: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 7: [B10.6].operator int
-// CHECK: 8: [B10.7]()
-// CHECK: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
-// CHECK: T: for (...; [B10.10]; )
-// CHECK: Preds (2): B2 B11
-// CHECK: Succs (2): B9 B1
-// CHECK: [B11]
-// CHECK: 1: (CXXConstructExpr, class A)
-// CHECK: 2: A a;
-// CHECK: 3: (CXXConstructExpr, class A)
-// CHECK: 4: A b;
-// CHECK: Preds (1): B12
-// CHECK: Succs (1): B10
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (2): B1 B4
-// CHECK: [B3 (ENTRY)]
-// CHECK: Succs (1): B0
-// CHECK: [B1]
-// CHECK: T: try ...
-// CHECK: Succs (2): B2 B0
-// CHECK: [B2]
-// CHECK: catch (const A &e):
-// CHECK: 1: catch (const A &e) {
-// CHECK: }
-// CHECK: Preds (1): B1
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (3): B2 B1 B3
-// CHECK: [B3 (ENTRY)]
-// CHECK: Succs (1): B0
-// CHECK: [B1]
-// CHECK: T: try ...
-// CHECK: Succs (2): B2 B0
-// CHECK: [B2]
-// CHECK: catch (A e):
-// CHECK: 1: catch (A e) {
-// CHECK: }
-// CHECK: 2: [B2.1].~A() (Implicit destructor)
-// CHECK: Preds (1): B1
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (3): B2 B1 B3
-
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index 2fa5a8e1a8a9..62d53607b533 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -13,6 +14,10 @@ void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
__attribute__((visibility("default"))) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__nothrow__)) dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
typedef long dispatch_once_t;
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
+dispatch_queue_t
+dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
+
+
typedef signed char BOOL;
typedef unsigned long NSUInteger;
typedef struct _NSZone NSZone;
@@ -56,8 +61,8 @@ void test1(NSString *format, ...) {
do {
if (__builtin_expect(*(&pred), ~0l) != ~0l)
dispatch_once(&pred, ^{
- logQueue = dispatch_queue_create("com.mycompany.myproduct.asl", ((void*)0));
- client = asl_open(((void*)0), "com.mycompany.myproduct", 0);
+ logQueue = dispatch_queue_create("com.mycompany.myproduct.asl", 0);
+ client = asl_open(((char*)0), "com.mycompany.myproduct", 0);
});
} while (0);
@@ -65,7 +70,7 @@ void test1(NSString *format, ...) {
__builtin_va_start(args, format);
NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
- dispatch_async(logQueue, ^{ asl_log(client, ((void*)0), 4, "%s", [str UTF8String]); });
+ dispatch_async(logQueue, ^{ asl_log(client, ((aslmsg)0), 4, "%s", [str UTF8String]); });
[str release];
__builtin_va_end(args);
@@ -123,3 +128,37 @@ void testMessaging() {
});
}
@end
+
+void testReturnVariousSignatures() {
+ (void)^int(){
+ return 42;
+ }();
+
+ (void)^int{
+ return 42;
+ }();
+
+ (void)^(){
+ return 42;
+ }();
+
+ (void)^{
+ return 42;
+ }();
+}
+
+// This test used to cause infinite loop in the region invalidation.
+void blockCapturesItselfInTheLoop(int x, int m) {
+ void (^assignData)(int) = ^(int x){
+ x++;
+ };
+ while (m < 0) {
+ void (^loop)(int);
+ loop = ^(int x) {
+ assignData(x);
+ };
+ assignData = loop;
+ m++;
+ }
+ assignData(x);
+}
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
new file mode 100644
index 000000000000..72d5ad23b16e
--- /dev/null
+++ b/test/Analysis/builtin-functions.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
+
+void clang_analyzer_eval(bool);
+
+void testAddressof(int x) {
+ clang_analyzer_eval(&x == __builtin_addressof(x)); // expected-warning{{TRUE}}
+}
+
+void testSize() {
+ struct {
+ int x;
+ int y;
+ char z;
+ } object;
+ clang_analyzer_eval(__builtin_object_size(&object.y, 0) == sizeof(object) - sizeof(int)); // expected-warning{{TRUE}}
+
+ // Clang can't actually evaluate these builtin "calls", but importantly they don't actually evaluate the argument expression either.
+ int i = 0;
+ char buf[10];
+ clang_analyzer_eval(__builtin_object_size(&buf[i++], 0) == sizeof(buf)); // expected-warning{{FALSE}}
+ clang_analyzer_eval(__builtin_object_size(&buf[++i], 0) == sizeof(buf) - 1); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(i == 0); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/casts.cpp b/test/Analysis/casts.cpp
new file mode 100644
index 000000000000..339539189ed7
--- /dev/null
+++ b/test/Analysis/casts.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// expected-no-diagnostics
+
+bool PR14634(int x) {
+ double y = (double)x;
+ return !y;
+}
+
+bool PR14634_implicit(int x) {
+ double y = (double)x;
+ return y;
+}
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index 1a78940eee25..895c8119c180 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,9 +1,7 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
-// Test function pointer casts. Currently we track function addresses using
-// loc::FunctionVal. Because casts can be arbitrary, do we need to model
-// functions with regions?
+// Test function pointer casts.
typedef void* (*MyFuncTest1)(void);
MyFuncTest1 test1_aux(void);
@@ -14,8 +12,7 @@ void test1(void) {
if (p != ((void*) 0)) x = (*p)();
}
-// Test casts from void* to function pointers. Same issue as above:
-// should we eventually model function pointers using regions?
+// Test casts from void* to function pointers.
void* test2(void *p) {
MyFuncTest1 fp = (MyFuncTest1) p;
return (*fp)();
@@ -41,3 +38,9 @@ adium_media_ready_cb(RDR10087620 *InObj)
{
InObj.elem |= EEOne;
}
+
+
+// PR16690
+_Bool testLocAsIntegerToBool() {
+ return (long long)&testLocAsIntegerToBool;
+}
diff --git a/test/Analysis/cfg.cpp b/test/Analysis/cfg.cpp
index 8c1c7653db13..660d1f264694 100644
--- a/test/Analysis/cfg.cpp
+++ b/test/Analysis/cfg.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
-// Check the wrapping behavior when dumping the CFG.
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 %s 2>&1 | FileCheck %s
// CHECK: ENTRY
// CHECK-NEXT: Succs (1): B1
@@ -11,7 +10,7 @@
// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
// CHECK-NEXT: B20 B21 B1
-void test(int i) {
+void checkWrap(int i) {
switch(i) {
case 0: break;
case 1: break;
@@ -35,3 +34,150 @@ void test(int i) {
case 19: break;
}
}
+
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: 2: int j;
+// CHECK-NEXT: 3: 1
+// CHECK-NEXT: 4: int k = 1;
+// CHECK-NEXT: 5: int l;
+// CHECK-NEXT: 6: 2
+// CHECK-NEXT: 7: int m = 2;
+// CHECK-NEXT: CXXConstructExpr
+// CHECK-NEXT: 9: struct standalone myStandalone;
+// CHECK-NEXT: CXXConstructExpr
+// CHECK-NEXT: 11: struct <anonymous struct at {{.*}}> myAnon;
+// CHECK-NEXT: CXXConstructExpr
+// CHECK-NEXT: 13: struct named myNamed;
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+void checkDeclStmts() {
+ int i, j;
+ int k = 1, l, m = 2;
+
+ struct standalone { int x, y; };
+ struct standalone myStandalone;
+
+ struct { int x, y; } myAnon;
+
+ struct named { int x, y; } myNamed;
+
+ static_assert(1, "abc");
+}
+
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: e
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, enum EmptyE)
+// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, IntegralCast, int)
+// CHECK-NEXT: T: switch [B1.3]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+enum EmptyE {};
+void F(EmptyE e) {
+ switch (e) {}
+}
+
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: __builtin_object_size
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, BuiltinFnToFnPtr, unsigned long (*)(const void *, int))
+// CHECK-NEXT: 3: [B1.2](dummy(), 0)
+// CHECK-NEXT: 4: (void)[B1.3] (CStyleCastExpr, ToVoid, void)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void testBuiltinSize() {
+ extern int *dummy();
+ (void)__builtin_object_size(dummy(), 0);
+}
+
+
+class A {
+public:
+ A() {}
+ ~A() {}
+};
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: new A([B1.1])
+// CHECK-NEXT: 3: A *a = new A();
+// CHECK-NEXT: 4: a
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT: 6: [B1.5]->~A() (Implicit destructor)
+// CHECK-NEXT: 7: delete [B1.5]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_deletedtor() {
+ A *a = new A();
+ delete a;
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: 5
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: new A {{\[\[}}B1.1]]
+// CHECK-NEXT: 4: A *a = new A [5];
+// CHECK-NEXT: 5: a
+// CHECK-NEXT: 6: [B1.5] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT: 7: [B1.6]->~A() (Implicit destructor)
+// CHECK-NEXT: 8: delete [] [B1.6]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_deleteArraydtor() {
+ A *a = new A[5];
+ delete[] a;
+}
+
+
+namespace NoReturnSingleSuccessor {
+ struct A {
+ A();
+ ~A();
+ };
+
+ struct B : public A {
+ B();
+ ~B() __attribute__((noreturn));
+ };
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: ~B() (Implicit destructor)
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test1(int *x) {
+ B b;
+ if (x)
+ return 1;
+ }
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: destructor
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test2(int *x) {
+ const A& a = B();
+ if (x)
+ return 1;
+ }
+}
diff --git a/test/Analysis/conditional-operator.cpp b/test/Analysis/conditional-operator.cpp
index 5a3c325b91d4..137dc3987755 100644
--- a/test/Analysis/conditional-operator.cpp
+++ b/test/Analysis/conditional-operator.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -analyzer-output=text -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -analyzer-output=text -verify
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/conditional-operator-path-notes.c b/test/Analysis/conditional-path-notes.c
index a8af394a26d4..23784970e1f4 100644
--- a/test/Analysis/conditional-operator-path-notes.c
+++ b/test/Analysis/conditional-path-notes.c
@@ -1,5 +1,5 @@
// RUN: %clang --analyze %s -Xanalyzer -analyzer-output=text -Xclang -verify
-// RUN: %clang --analyze %s -o %t
+// RUN: %clang --analyze %s -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t
// RUN: FileCheck --input-file=%t %s
void testCondOp(int *p) {
@@ -55,6 +55,32 @@ void testBinaryLHSProblem(int *p) {
(void)x;
}
+void testDiagnosableBranch(int a) {
+ if (a) {
+ // expected-note@-1 {{Assuming 'a' is not equal to 0}}
+ // expected-note@-2 {{Taking true branch}}
+ *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+ }
+}
+
+void testNonDiagnosableBranchLogical(int a, int b) {
+ if (a && b) {
+ // expected-note@-1 {{Left side of '&&' is true}}
+ // expected-note@-2 {{Taking true branch}}
+ *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+ }
+}
+
+void testNonDiagnosableBranchArithmetic(int a, int b) {
+ if (a - b) {
+ // expected-note@-1 {{Taking true branch}}
+ *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+ }
+}
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -1080,4 +1106,477 @@ void testBinaryLHSProblem(int *p) {
// 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>59</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>59</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</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>59</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>59</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>59</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>59</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>Assuming &apos;a&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is not equal to 0</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>59</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>59</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</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>62</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</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>62</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testDiagnosableBranch</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>4</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>7</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>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>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>68</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>68</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>12</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>68</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testNonDiagnosableBranchLogical</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>77</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>77</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>79</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</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>79</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</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>79</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testNonDiagnosableBranchArithmetic</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/crash-trace.c b/test/Analysis/crash-trace.c
new file mode 100644
index 000000000000..a2f318d86579
--- /dev/null
+++ b/test/Analysis/crash-trace.c
@@ -0,0 +1,19 @@
+// RUN: not --crash %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
+// REQUIRES: crash-recovery
+
+void clang_analyzer_crash(void);
+
+void inlined() {
+ clang_analyzer_crash();
+}
+
+void test() {
+ inlined();
+}
+
+// CHECK: 0. Program arguments: {{.*}}clang
+// CHECK-NEXT: 1. <eof> parser at end of file
+// CHECK-NEXT: 2. While analyzing stack:
+// CHECK-NEXT: #0 void inlined()
+// CHECK-NEXT: #1 void test()
+// CHECK-NEXT: 3. {{.*}}crash-trace.c:{{[0-9]+}}:3: Error evaluating statement
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor.mm
index 8cdb005968c3..77c87905e1f7 100644
--- a/test/Analysis/ctor-inlining.mm
+++ b/test/Analysis/ctor.mm
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
+
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
@@ -500,3 +502,175 @@ namespace ArrayMembers {
clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
}
};
+
+namespace VirtualInheritance {
+ int counter;
+
+ struct base {
+ base() {
+ ++counter;
+ }
+ };
+
+ struct virtual_subclass : public virtual base {
+ virtual_subclass() {}
+ };
+
+ struct double_subclass : public virtual_subclass {
+ double_subclass() {}
+ };
+
+ void test() {
+ counter = 0;
+ double_subclass obj;
+ clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
+ }
+
+ struct double_virtual_subclass : public virtual virtual_subclass {
+ double_virtual_subclass() {}
+ };
+
+ void testVirtual() {
+ counter = 0;
+ double_virtual_subclass obj;
+ clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
+ }
+}
+
+namespace ZeroInitialization {
+ struct raw_pair {
+ int p1;
+ int p2;
+ };
+
+ void testVarDecl() {
+ raw_pair p{};
+ clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
+ }
+
+ void testTemporary() {
+ clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}}
+ }
+
+ void testArray() {
+ raw_pair p[2] = {};
+ clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}}
+ }
+
+ void testNew() {
+ // FIXME: Pending proper implementation of constructors for 'new'.
+ raw_pair *pp = new raw_pair();
+ clang_analyzer_eval(pp->p1 == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(pp->p2 == 0); // expected-warning{{UNKNOWN}}
+ }
+
+ void testArrayNew() {
+ // FIXME: Pending proper implementation of constructors for 'new[]'.
+ raw_pair *p = new raw_pair[2]();
+ clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}}
+ }
+
+ struct initializing_pair {
+ public:
+ int x;
+ raw_pair y;
+ initializing_pair() : x(), y() {}
+ };
+
+ void testFieldInitializers() {
+ initializing_pair p;
+ clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}}
+ }
+
+ struct subclass : public raw_pair {
+ subclass() = default;
+ };
+
+ void testSubclass() {
+ subclass p;
+ clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}}
+ }
+
+ struct initializing_subclass : public raw_pair {
+ initializing_subclass() : raw_pair() {}
+ };
+
+ void testInitializingSubclass() {
+ initializing_subclass p;
+ clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
+ }
+
+ struct pair_wrapper {
+ pair_wrapper() : p() {}
+ raw_pair p;
+ };
+
+ struct virtual_subclass : public virtual pair_wrapper {
+ virtual_subclass() {}
+ };
+
+ struct double_virtual_subclass : public virtual_subclass {
+ double_virtual_subclass() {
+ // This previously caused a crash because the pair_wrapper subobject was
+ // initialized twice.
+ }
+ };
+
+ class Empty {
+ public:
+ Empty();
+ };
+
+ class PairContainer : public Empty {
+ raw_pair p;
+ public:
+ PairContainer() : Empty(), p() {
+ // This previously caused a crash because the empty base class looked
+ // like an initialization of 'p'.
+ }
+ PairContainer(int) : Empty(), p() {
+ // Test inlining something else here.
+ }
+ };
+
+ class PairContainerContainer {
+ int padding;
+ PairContainer pc;
+ public:
+ PairContainerContainer() : pc(1) {}
+ };
+}
+
+namespace InitializerList {
+ struct List {
+ bool usedInitializerList;
+
+ List() : usedInitializerList(false) {}
+ List(std::initializer_list<int>) : usedInitializerList(true) {}
+ };
+
+ void testStatic() {
+ List defaultCtor;
+ clang_analyzer_eval(!defaultCtor.usedInitializerList); // expected-warning{{TRUE}}
+
+ List list{1, 2};
+ clang_analyzer_eval(list.usedInitializerList); // expected-warning{{TRUE}}
+ }
+
+ void testDynamic() {
+ List *list = new List{1, 2};
+ // FIXME: When we handle constructors with 'new', this will be TRUE.
+ clang_analyzer_eval(list->usedInitializerList); // expected-warning{{UNKNOWN}}
+ }
+}
diff --git a/test/Analysis/cxx-for-range.cpp b/test/Analysis/cxx-for-range.cpp
new file mode 100644
index 000000000000..fe73e51410a8
--- /dev/null
+++ b/test/Analysis/cxx-for-range.cpp
@@ -0,0 +1,1668 @@
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist -verify %s
+// RUN: FileCheck --input-file=%t.plist %s
+
+extern void work();
+
+void testLoop() {
+ int z[] = {1,2};
+ for (int y : z) {
+ work();
+ work();
+ if (y == 2)
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ work();
+ work();
+ (void)y;
+ }
+
+ *(volatile int *)0 = 1; // no-warning
+}
+
+class MagicVector {
+public:
+ MagicVector();
+
+ using iterator = int *;
+
+ iterator begin() const;
+ iterator end() const;
+};
+
+MagicVector get(bool fail = false) {
+ if (fail)
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ return MagicVector{};
+}
+
+void testLoopOpaqueCollection() {
+ for (int y : get()) {
+ work();
+ work();
+ if (y == 2)
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ work();
+ work();
+ (void)y;
+ }
+
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+}
+
+
+class MagicVector2 {
+public:
+ MagicVector2();
+
+ class iterator {
+ public:
+ int operator*() const;
+ iterator &operator++();
+ bool operator==(const iterator &);
+ bool operator!=(const iterator &);
+ };
+
+ iterator begin() const;
+ iterator end() const;
+};
+
+MagicVector2 get2() {
+ return MagicVector2{};
+}
+
+void testLoopOpaqueIterator() {
+ for (int y : get2()) {
+ work();
+ work();
+ if (y == 2)
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ work();
+ work();
+ (void)y;
+ }
+
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+}
+
+
+void testLoopErrorInRange() {
+ for (int y : get(true)) { // error inside get()
+ work();
+ work();
+ if (y == 2)
+ *(volatile int *)0 = 1; // no-warning
+ work();
+ work();
+ (void)y;
+ }
+
+ *(volatile int *)0 = 1; // no-warning
+}
+// 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>7</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>7</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>8</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>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</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>8</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>8</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>8</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>8</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>9</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</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>9</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</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>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</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>15</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>15</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>15</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>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>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>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>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>8</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>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</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>8</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>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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>8</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>8</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>8</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>8</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>8</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>9</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</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>9</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>12</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>12</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>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>12</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>12</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</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>12</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>12</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>12</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>12</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testLoop</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</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>88</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>88</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>88</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>88</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>88</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>88</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>88</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>Calling &apos;get&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;get&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>31</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;testLoopErrorInRange&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testLoopErrorInRange&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>31</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>31</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</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>32</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>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>3</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>4</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>get</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>38</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>38</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>39</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>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>39</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>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>41</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>41</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>41</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>41</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>41</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>41</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>41</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>Assuming &apos;y&apos; is equal to 2</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is equal to 2</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>41</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>41</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: <key>end</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>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>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>7</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>26</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>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>42</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>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>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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testLoopOpaqueCollection</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>42</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>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>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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>38</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>38</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>48</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>48</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>48</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>48</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>48</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>48</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>48</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>48</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>48</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testLoopOpaqueCollection</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>48</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: <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>73</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>73</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>73</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>73</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>73</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>74</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>74</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>74</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>74</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>76</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>76</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>76</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>76</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>76</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>76</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>76</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>Assuming &apos;y&apos; is equal to 2</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is equal to 2</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>76</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>76</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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>77</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>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>77</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>77</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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>77</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>77</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>77</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>77</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testLoopOpaqueIterator</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</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>73</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>73</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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>73</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>73</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>83</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>83</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>83</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>83</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>83</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>83</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>83</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>83</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>83</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testLoopOpaqueIterator</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</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: </array>
diff --git a/test/Analysis/cxx11-crashes.cpp b/test/Analysis/cxx11-crashes.cpp
index d0b9222b6a66..3c33de33558f 100644
--- a/test/Analysis/cxx11-crashes.cpp
+++ b/test/Analysis/cxx11-crashes.cpp
@@ -65,3 +65,32 @@ bool begin(double *it) {
bool *a = reinterpret_cast<type &>(*( reinterpret_cast<char *>( it )));
return *a;
}
+
+// radar://14164698 Don't crash on "assuming" a ComoundVal.
+class JSONWireProtocolInputStream {
+public:
+ virtual ~JSONWireProtocolInputStream();
+};
+class JSONWireProtocolReader {
+public:
+ JSONWireProtocolReader(JSONWireProtocolInputStream& istream)
+ : _istream{istream} {} // On evaluating a bind here,
+ // the dereference checker issues an assume on a CompoundVal.
+~JSONWireProtocolReader();
+private:
+JSONWireProtocolInputStream& _istream;
+};
+class SocketWireProtocolStream : public JSONWireProtocolInputStream {
+};
+void test() {
+ SocketWireProtocolStream stream{};
+ JSONWireProtocolReader reader{stream};
+}
+
+// This crashed because the analyzer did not understand AttributedStmts.
+void fallthrough() {
+ switch (1) {
+ case 1:
+ [[clang::fallthrough]];
+ }
+}
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index 0664189a9564..e9c7ca8f731f 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -450,3 +450,28 @@ namespace PR15394 {
}
};
+namespace Bug16309 {
+ struct Incomplete;
+
+ struct Base { virtual ~Base(); };
+
+ struct Derived : public Base { int x; };
+
+ void* f(Incomplete *i) {
+ Base *b = reinterpret_cast<Base *>(i);
+ // This used to crash because of the reinterpret_cast above.
+ Derived *d = dynamic_cast<Derived *>(b);
+ return d;
+ }
+
+ // And check that reinterpret+dynamic casts work correctly after the fix.
+ void g() {
+ Derived d;
+ d.x = 47;
+ Base *b = &d;
+ Incomplete *i = reinterpret_cast<Incomplete *>(b);
+ Base *b2 = reinterpret_cast<Base *>(i);
+ Derived *d2 = dynamic_cast<Derived *>(b2);
+ clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/diagnostics/Inputs/include/report-issues-within-main-file.h b/test/Analysis/diagnostics/Inputs/include/report-issues-within-main-file.h
new file mode 100644
index 000000000000..9ecef343f5ee
--- /dev/null
+++ b/test/Analysis/diagnostics/Inputs/include/report-issues-within-main-file.h
@@ -0,0 +1,43 @@
+template<typename _Tp>
+class auto_ptr {
+private:
+ _Tp* _M_ptr;
+public:
+ auto_ptr(_Tp* __p = 0) throw() : _M_ptr(__p) { }
+ ~auto_ptr() { delete _M_ptr; }
+};
+
+void cause_div_by_zero_in_header(int in) {
+ int h = 0;
+ h = in/h;
+ h++;
+}
+
+void do_something (int in) {
+ in++;
+ in++;
+}
+
+void cause_div_by_zero_in_header2(int in) {
+ int h2 = 0;
+ h2 = in/h2;
+ h2++;
+}
+
+# define CALLS_BUGGY_FUNCTION2 cause_div_by_zero_in_header2(5);
+
+void cause_div_by_zero_in_header3(int in) {
+ int h3 = 0;
+ h3 = in/h3;
+ h3++;
+}
+
+# define CALLS_BUGGY_FUNCTION3 cause_div_by_zero_in_header3(5);
+
+void cause_div_by_zero_in_header4(int in) {
+ int h4 = 0;
+ h4 = in/h4;
+ h4++;
+}
+
+# define TAKE_CALL_AS_ARG(c) c;
diff --git a/test/Analysis/diagnostics/Inputs/include/sys/queue.h b/test/Analysis/diagnostics/Inputs/include/sys/queue.h
index e5698ed443b7..2740e174f257 100644
--- a/test/Analysis/diagnostics/Inputs/include/sys/queue.h
+++ b/test/Analysis/diagnostics/Inputs/include/sys/queue.h
@@ -1,4 +1,3 @@
-#pragma clang system_header
void free(void *);
#define FREE_POINTER(x) free(x)
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.c b/test/Analysis/diagnostics/deref-track-symbolic-region.c
index 03716de9ffec..36d56f1f144f 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.c
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
struct S {
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
index 57d2d16f89cc..78067573e322 100644
--- a/test/Analysis/diagnostics/explicit-suppression.cpp
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -12,6 +12,6 @@ void clang_analyzer_eval(bool);
void testCopyNull(int *I, int *E) {
std::copy(I, E, (int *)0);
#ifndef SUPPRESSED
- // expected-warning@../Inputs/system-header-simulator-cxx.h:80 {{Dereference of null pointer}}
+ // expected-warning@../Inputs/system-header-simulator-cxx.h:110 {{Dereference of null pointer}}
#endif
}
diff --git a/test/Analysis/diagnostics/report-issues-within-main-file.cpp b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
new file mode 100644
index 000000000000..ec8106f6000a
--- /dev/null
+++ b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
@@ -0,0 +1,1756 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-output=plist-multi-file -analyzer-config report-in-main-source-file=true -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+#include "Inputs/include/report-issues-within-main-file.h"
+
+void mainPlusHeader() {
+ auto_ptr<int> B (new int[5]);
+}
+
+void auxInMain() {
+ int j = 0;
+ j++;
+ cause_div_by_zero_in_header(j);
+ j--;
+}
+void mainPlusMainPlusHeader() {
+ int i = 0;
+ i++;
+ auxInMain();
+ i++;
+}
+
+void causeDivByZeroInMain(int in) {
+ int m = 0;
+ m = in/m;
+ m++;
+}
+void mainPlusMain() {
+ int i = 0;
+ i++;
+ causeDivByZeroInMain(i);
+ i++;
+}
+
+void causeDivByZeroInMain2(int in) {
+ int m2 = 0;
+ m2 = in/m2;
+ m2++;
+}
+
+void mainPlustHeaderCallAndReturnPlusMain() {
+ int i = 0;
+ i++;
+ do_something(i);
+ causeDivByZeroInMain2(i);
+ i++;
+}
+
+void callInMacro() {
+ int j = 0;
+ j++;
+ CALLS_BUGGY_FUNCTION2;
+ j--;
+}
+
+void callInMacro3() {
+ int j = 0;
+ j++;
+ CALLS_BUGGY_FUNCTION3;
+ j--;
+}
+
+void callCallInMacro3() {
+ callInMacro3();
+}
+
+void callInMacroArg() {
+ int j = 0;
+ j++;
+ TAKE_CALL_AS_ARG(cause_div_by_zero_in_header4(5));
+ j--;
+}
+
+// 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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>51</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>51</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>51</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 &apos;cause_div_by_zero_in_header2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;cause_div_by_zero_in_header2&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>21</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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;callInMacro&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callInMacro&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>21</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>&apos;h2&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;h2&apos; initialized to 0</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>22</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>23</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>cause_div_by_zero_in_header2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>63</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>63</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>63</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>Calling &apos;callInMacro3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;callInMacro3&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>55</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;callCallInMacro3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callCallInMacro3&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>55</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>55</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: <key>end</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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;cause_div_by_zero_in_header3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;cause_div_by_zero_in_header3&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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callInMacro3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callInMacro3&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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>30</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;h3&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;h3&apos; initialized to 0</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>30</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>31</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>cause_div_by_zero_in_header3</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>69</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>69</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>69</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>Calling &apos;cause_div_by_zero_in_header4&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;cause_div_by_zero_in_header4&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>37</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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;callInMacroArg&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callInMacroArg&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>37</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>&apos;h4&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;h4&apos; initialized to 0</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>38</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>39</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>cause_div_by_zero_in_header4</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>6</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>6</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>29</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>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>6</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>7</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>7</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>key_event</key><true/>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;~auto_ptr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~auto_ptr&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>7</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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;mainPlusHeader&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;mainPlusHeader&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>7</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>7</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
+// 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>type</key><string>Bad deallocator</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>mainPlusHeader</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</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: <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>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>18</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>18</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>18</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>18</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>18</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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;auxInMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;auxInMain&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>9</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;mainPlusMainPlusHeader&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;mainPlusMainPlusHeader&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>9</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>9</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: <key>end</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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>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>12</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>12</integer>
+// CHECK-NEXT: <key>col</key><integer>29</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>key_event</key><true/>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</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>12</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>12</integer>
+// CHECK-NEXT: <key>col</key><integer>32</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>Calling &apos;cause_div_by_zero_in_header&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;cause_div_by_zero_in_header&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>10</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;auxInMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;auxInMain&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>10</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;h&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;h&apos; initialized to 0</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>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>1</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>12</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>1</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero (within a call to &apos;cause_div_by_zero_in_header&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>auxInMain</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</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>28</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>28</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>30</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>30</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>30</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>30</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>30</integer>
+// CHECK-NEXT: <key>col</key><integer>25</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;causeDivByZeroInMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;causeDivByZeroInMain&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>22</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;mainPlusMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;mainPlusMain&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>22</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>22</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</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>23</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</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>23</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>23</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;m&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;m&apos; initialized to 0</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>23</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>23</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>24</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>24</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>24</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>24</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>24</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>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>causeDivByZeroInMain</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</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>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>41</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>41</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>43</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>43</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>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>43</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>43</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</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>44</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: </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>44</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>44</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>44</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;causeDivByZeroInMain2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;causeDivByZeroInMain2&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>34</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;mainPlustHeaderCallAndReturnPlusMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;mainPlustHeaderCallAndReturnPlusMain&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>34</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>34</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</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>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</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>35</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>35</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;m2&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;m2&apos; initialized to 0</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>35</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>35</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>36</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>36</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>36</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>36</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>36</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>causeDivByZeroInMain2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</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: </array>
diff --git a/test/Analysis/diagnostics/text-diagnostics.c b/test/Analysis/diagnostics/text-diagnostics.c
new file mode 100644
index 000000000000..592521672ff4
--- /dev/null
+++ b/test/Analysis/diagnostics/text-diagnostics.c
@@ -0,0 +1,21 @@
+// RUN: %clang --analyze -Xanalyzer -analyzer-output=text -fno-caret-diagnostics %s 2>&1 | FileCheck %s
+
+void testA() {
+ int *p = 0;
+ *p = 1;
+
+ // CHECK-LABEL: text-diagnostics.c:{{.*}}:6: warning: Dereference of null pointer (loaded from variable 'p')
+ // CHECK-NEXT: text-diagnostics.c:[[@LINE-4]]:3: note: 'p' initialized to a null pointer value
+ // CHECK-NEXT: text-diagnostics.c:[[@LINE-4]]:6: note: Dereference of null pointer (loaded from variable 'p')
+}
+
+void testB(int *q) {
+ if (q)
+ return;
+ *q = 1;
+
+ // CHECK-LABEL: text-diagnostics.c:{{.*}}:6: warning: Dereference of null pointer (loaded from variable 'q')
+ // CHECK-NEXT: text-diagnostics.c:[[@LINE-5]]:7: note: Assuming 'q' is null
+ // CHECK-NEXT: text-diagnostics.c:[[@LINE-6]]:3: note: Taking false branch
+ // CHECK-NEXT: text-diagnostics.c:[[@LINE-5]]:6: note: Dereference of null pointer (loaded from variable 'q')
+}
diff --git a/test/Analysis/diagnostics/undef-value-caller.c b/test/Analysis/diagnostics/undef-value-caller.c
index adfdd4362568..da3a13c2b121 100644
--- a/test/Analysis/diagnostics/undef-value-caller.c
+++ b/test/Analysis/diagnostics/undef-value-caller.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist -o %t %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck --input-file %t %s
#include "undef-value-callee.h"
diff --git a/test/Analysis/diagnostics/undef-value-param.c b/test/Analysis/diagnostics/undef-value-param.c
index 5855f507f9f6..dec0a5ada776 100644
--- a/test/Analysis/diagnostics/undef-value-param.c
+++ b/test/Analysis/diagnostics/undef-value-param.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void foo_irrelevant(int c) {
diff --git a/test/Analysis/diagnostics/undef-value-param.m b/test/Analysis/diagnostics/undef-value-param.m
index 4de83bfb9c82..e977acb70fd9 100644
--- a/test/Analysis/diagnostics/undef-value-param.m
+++ b/test/Analysis/diagnostics/undef-value-param.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef signed char BOOL;
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index 18cd9853f661..11ce0d57ef4f 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -401,3 +401,38 @@ namespace LifetimeExtension {
clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
}
}
+
+namespace NoReturn {
+ struct NR {
+ ~NR() __attribute__((noreturn));
+ };
+
+ void f(int **x) {
+ NR nr;
+ }
+
+ void g() {
+ int *x;
+ f(&x);
+ *x = 47; // no warning
+ }
+}
+
+namespace PseudoDtor {
+ template <typename T>
+ void destroy(T &obj) {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ obj.~T();
+ }
+
+ void test() {
+ int i;
+ destroy(i);
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+ }
+}
+
+namespace Incomplete {
+ class Foo; // expected-note{{forward declaration}}
+ void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
+}
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
new file mode 100644
index 000000000000..8019c15c1b26
--- /dev/null
+++ b/test/Analysis/edges-new.mm
@@ -0,0 +1,19628 @@
+// RUN: %clang -target x86_64-apple-darwin10 --analyze -Xclang -analyzer-config -Xclang path-diagnostics-alternate=true -Xclang -analyzer-output=plist -o %t %s
+// RUN: FileCheck --input-file %t %s
+
+//===----------------------------------------------------------------------===//
+// Forward declarations (from headers).
+//===----------------------------------------------------------------------===//
+
+typedef const struct __CFNumber * CFNumberRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef signed long CFIndex;
+enum {
+ kCFNumberSInt8Type = 1,
+ kCFNumberSInt16Type = 2,
+ kCFNumberSInt32Type = 3,
+ kCFNumberSInt64Type = 4,
+ kCFNumberFloat32Type = 5,
+ kCFNumberFloat64Type = 6,
+ kCFNumberCharType = 7,
+ kCFNumberShortType = 8,
+ kCFNumberIntType = 9,
+ kCFNumberLongType = 10,
+ kCFNumberLongLongType = 11,
+ kCFNumberFloatType = 12,
+ kCFNumberDoubleType = 13,
+ kCFNumberCFIndexType = 14,
+ kCFNumberNSIntegerType = 15,
+ kCFNumberCGFloatType = 16,
+ kCFNumberMaxType = 16
+};
+typedef CFIndex CFNumberType;
+CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+
+#define nil ((id)0)
+
+__attribute__((objc_root_class))
+@interface NSObject
++ (instancetype) alloc;
+- (instancetype) init;
+- (instancetype)retain;
+- (void)release;
+@end
+
+@interface NSArray : NSObject
+@end
+
+//===----------------------------------------------------------------------===//
+// Basic tracking of null and tests for null.
+//===----------------------------------------------------------------------===//
+
+void test_null_init(void) {
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+void test_null_assign(void) {
+ int *p;
+ p = 0;
+ *p = 0xDEADBEEF;
+}
+
+void test_null_assign_transitive(void) {
+ int *p;
+ p = 0;
+ int *q = p;
+ *q = 0xDEADBEEF;
+}
+
+void test_null_cond(int *p) {
+ if (!p) {
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_null_cond_transitive(int *q) {
+ if (!q) {
+ int *p = q;
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_null_field(void) {
+ struct s { int *p; } x;
+ x.p = 0;
+ *(x.p) = 0xDEADBEEF;
+}
+
+void test_assumptions(int a, int b)
+{
+ if (a == 0) {
+ return;
+ }
+ if (b != 0) {
+ return;
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+int *bar_cond_assign();
+int test_cond_assign() {
+ int *p;
+ if ((p = bar_cond_assign()))
+ return 1;
+ return *p;
+}
+
+//===----------------------------------------------------------------------===//
+// Diagnostics for leaks and "noreturn" paths.
+//===----------------------------------------------------------------------===//
+
+
+// <rdar://problem/8331641> leak reports should not show paths that end with exit() (but ones that don't end with exit())
+
+void stop() __attribute__((noreturn));
+
+void rdar8331641(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+ if (x)
+ stop();
+ (void) value;
+}
+
+//===----------------------------------------------------------------------===//
+// Test loops and control-flow.
+//===----------------------------------------------------------------------===//
+
+void test_objc_fast_enumeration(NSArray *x) {
+ id obj;
+ for (obj in x)
+ *(volatile int *)0 = 0;
+}
+
+void test_objc_fast_enumeration_2(id arr) {
+ int x;
+ for (id obj in arr) {
+ x = 1;
+ }
+ x += 1;
+}
+
+// Test that loops are documented in the path.
+void rdar12280665() {
+ for (unsigned i = 0; i < 2; ++i) {
+ if (i == 1) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{dereference}}
+ }
+ }
+}
+
+// Test for a "loop executed 0 times" diagnostic.
+int *radar12322528_bar();
+
+void radar12322528_for(int x) {
+ int z;
+ int *p = 0;
+ for (unsigned i = 0; i < x; ++i) {
+ p = radar12322528_bar();
+ }
+ *p = 0xDEADBEEF;
+}
+
+void radar12322528_while(int x) {
+ int *p = 0;
+ unsigned i = 0;
+ for ( ; i < x ; ) {
+ ++i;
+ p = radar12322528_bar();
+ }
+ *p = 0xDEADBEEF;
+}
+
+void radar12322528_foo_2() {
+ int *p = 0;
+ for (unsigned i = 0; i < 2; ++i) {
+ if (i == 0)
+ continue;
+
+ if (i == 1) {
+
+ break;
+ }
+ }
+ *p = 0xDEADBEEF;
+}
+
+void test_loop_diagnostics() {
+ int *p = 0;
+ for (int i = 0; i < 2; ++i) { p = 0; }
+ *p = 1;
+}
+
+void test_loop_diagnostics_2() {
+ int *p = 0;
+
+ for (int i = 0; i < 2; ) {
+
+ ++i;
+
+ p = 0;
+
+ }
+
+ *p = 1;
+}
+
+void test_loop_diagnostics_3() {
+ int z;
+ int y;
+ int k;
+ int *p = 0;
+ int i = 0;
+ while (i < 2) {
+ ++i;
+ p = 0;
+ }
+ * p = 1;
+}
+
+void test_do_while() {
+ unsigned i = 0;
+
+ int *p;
+
+ do {
+
+ ++i;
+ p = 0;
+
+ } while (i< 2);
+
+ *p = 0xDEADBEEF;
+}
+
+
+void test_logical_and() {
+ int *p = 0;
+ if (1 && 2) {
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_logical_or() {
+ int *p = 0;
+ if (0 || 2) {
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_logical_or_call() {
+ extern int call(int);
+ int *p = 0;
+ if (call(0 || 2)) {
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_nested_logicals(int coin) {
+ int *p = 0;
+
+ if ((0 || 0) || coin) {
+ *p = 0xDEADBEEF;
+ }
+
+ if (0 || (0 || !coin)) {
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_deeply_nested_logicals() {
+ extern int call(int);
+ int *p = 0;
+
+ if ((0 || (5 && 0)) ? 0 : ((0 || 4) ? call(1 && 5) : 0)) {
+
+ *p = 0xDEADBEEF;
+ }
+}
+
+void test_ternary(int x, int *y) {
+ int z = x ? 0 : 1;
+
+ int *p = z ? y : 0;
+
+ *p = 0xDEADBEEF;
+}
+
+void testUseless(int *y) {
+ if (y) {
+
+ }
+ if (y) {
+
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+//===----------------------------------------------------------------------===//
+// Interprocedural tests.
+//===----------------------------------------------------------------------===//
+
+@interface IPA_Foo
+- (int *) returnsPointer;
+@end
+
+int testFoo(IPA_Foo *x) {
+ if (x)
+ return 1;
+ return *[x returnsPointer];
+}
+
+@interface IPA_X : NSObject
+- (int *)getPointer;
+@end
+
+void test1_IPA_X() {
+ IPA_X *x = nil;
+ *[x getPointer] = 1; // here
+}
+
+
+@interface IPA_Y : NSObject
+- (IPA_Y *)opaque;
+- (IPA_X *)getX;
+@end
+
+@implementation IPA_Y
+- (IPA_X *)getX {
+ return nil;
+}
+@end
+
+void test_IPA_Y(IPA_Y *y) {
+ if (y)
+ return;
+
+ IPA_X *x = [[y opaque] getX]; // here
+ *[x getPointer] = 1;
+}
+
+// From diagnostics/report-issues-within-main-file.cpp:
+void causeDivByZeroInMain(int in) {
+ int m = 0;
+ m = in/m;
+ m++;
+}
+
+void mainPlusMain() {
+ int i = 0;
+ i++;
+ causeDivByZeroInMain(i);
+ i++;
+}
+
+// From inlining/path-notes.c:
+int *getZero() {
+ int *p = 0;
+ return p;
+}
+
+void usePointer(int *p) {
+ *p = 1;
+}
+
+void testUseOfNullPointer() {
+ // Test the case where an argument expression is itself a call.
+ usePointer(getZero());
+}
+
+
+//===----------------------------------------------------------------------===//
+// Misc. tests.
+//===----------------------------------------------------------------------===//
+
+// Test for tracking null state of ivars.
+@interface RDar12114812 : NSObject { char *p; }
+@end
+@implementation RDar12114812
+- (void)test {
+ p = 0;
+ *p = 1;
+}
+@end
+
+// Test diagnostics for initialization of structs.
+void RDar13295437_f(void *i) __attribute__((__nonnull__));
+struct RDar13295437_S { int *i; };
+int RDar13295437() {
+ struct RDar13295437_S s = {0};
+ struct RDar13295437_S *sp = &s;
+ RDar13295437_f(sp->i);
+ return 0;
+}
+
+
+void testCast(int coin) {
+ if (coin) {
+ (void)(1+2);
+ (void)(2+3);
+ (void)(3+4);
+ *(volatile int *)0 = 1;
+ }
+}
+
+// The following previously crashed when generating extensive diagnostics.
+// <rdar://problem/10797980>
+@interface RDar10797980_help
+@property (readonly) int x;
+@end
+@interface RDar10797980 : NSObject {
+ RDar10797980_help *y;
+}
+- (void) test;
+@end
+@implementation RDar10797980
+- (void) test {
+ if (y.x == 1) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{deference}}
+ }
+}
+
+// The original source for the above Radar contains another problem:
+// if the end-of-path node is an implicit statement, it may not have a valid
+// source location. <rdar://problem/12446776>
+- (void)test2 {
+ if (bar_cond_assign()) {
+ id foo = [[RDar10797980 alloc] init]; // leak
+ }
+ (void)y; // first statement after the 'if' is an implicit 'self' DeclRefExpr
+}
+
+@end
+
+void variousLoops(id input) {
+ extern int a();
+ extern int b();
+ extern int c();
+
+ extern int work();
+
+ while (a()) {
+ work();
+ work();
+ work();
+ *(volatile int *)0 = 1;
+ }
+
+ int first = 1;
+ do {
+ work();
+ work();
+ work();
+ if (!first)
+ *(volatile int *)0 = 1;
+ first = 0;
+ } while (a());
+
+ for (int i = 0; i != b(); ++i) {
+ work();
+ *(volatile int *)0 = 1;
+ }
+
+ for (id x in input) {
+ work();
+ work();
+ work();
+ (void)x;
+ *(volatile int *)0 = 1;
+ }
+
+ int z[] = {1,2};
+ for (int y : z) {
+ work();
+ work();
+ work();
+ (void)y;
+ }
+
+ int empty[] = {};
+ for (int y : empty) {
+ work();
+ work();
+ work();
+ (void)y;
+ }
+
+ for (int i = 0; ; ++i) {
+ work();
+ if (i == b())
+ break;
+ }
+
+ int i;
+ for (i = 0; i != b(); ++i) {
+ work();
+ *(volatile int *)0 = 1;
+ }
+
+ for (; i != b(); ++i) {
+ work();
+ *(volatile int *)0 = 1;
+ }
+
+ for (; i != b(); ) {
+ work();
+ if (i == b())
+ break;
+ *(volatile int *)0 = 1;
+ }
+
+ for (;;) {
+ work();
+ if (i == b())
+ break;
+ }
+
+ *(volatile int *)0 = 1;
+}
+
+void *malloc(unsigned long);
+void *realloc(void *, unsigned long);
+void free(void *);
+
+void reallocDiagnostics() {
+ char * buf = (char*)malloc(100);
+ char * tmp;
+ tmp = (char*)realloc(buf, 0x1000000);
+ if (!tmp) {
+ return;// expected-warning {{leak}}
+ }
+ buf = tmp;
+ free(buf);
+}
+
+template <typename T>
+class unique_ptr {
+ T *ptr;
+public:
+ explicit unique_ptr(T *p) : ptr(p) {}
+ ~unique_ptr() { delete ptr; }
+};
+
+void test() {
+ int i = 0;
+ ++i;
+
+ unique_ptr<int> p(new int[4]);
+ {
+ ++i;
+ }
+}
+
+void longLines() {
+ id foo = [[NSObject alloc] init]; // leak
+ id bar =
+ [foo retain];
+ [bar release];
+ id baz = [foo
+ retain];
+ [baz release];
+ // This next line is intentionally longer than 80 characters.
+ id garply = [foo retain];
+ [garply release];
+}
+
+#define POINTER(T) T*
+POINTER(void) testMacroInFunctionDecl(void *q) {
+ int *p = 0;
+ *p = 1;
+ return q;
+}
+
+namespace rdar14960554 {
+ class Foo {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+
+ Foo() :
+ a(0),
+ c(3) {
+ // Check that we don't have an edge to the in-class initializer for 'b'.
+ if (b == 2)
+ *(volatile int *)0 = 1;
+ }
+ };
+}
+
+// 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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>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>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>53</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>53</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>53</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>53</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>53</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>53</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>53</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>53</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>53</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_init</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</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>57</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>57</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>58</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: </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>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>58</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>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>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>58</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</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>59</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>59</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>59</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>59</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>59</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>59</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>59</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>59</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_assign</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</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>63</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>63</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>64</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>64</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>64</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>64</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>64</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>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>64</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>64</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>65</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>65</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>65</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>65</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>65</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</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>65</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>65</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>66</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>66</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>66</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>66</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>66</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>66</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>66</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>66</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>66</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_assign_transitive</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>66</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>70</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>70</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>70</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>70</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>70</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>70</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>70</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</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>70</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>70</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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>71</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>71</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>71</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>71</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>71</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_cond</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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: <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>76</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>76</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</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>76</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>76</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>76</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>76</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;q&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;q&apos; is null</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>76</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>76</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>78</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</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>78</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>78</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>78</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>78</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>78</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_cond_transitive</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</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: <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>83</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</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>84</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>84</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>84</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>84</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>84</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>Null pointer value stored to &apos;x.p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;x.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>84</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>84</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>85</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>85</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>85</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>85</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>85</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>85</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>85</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>85</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>85</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>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_null_field</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>85</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>90</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>90</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>90</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>90</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>90</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>90</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>90</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is not equal to 0</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>90</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>90</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>93</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>93</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>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>93</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>93</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>93</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>93</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>93</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>93</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>93</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;b&apos; is equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;b&apos; is equal to 0</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>93</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>93</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>96</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>96</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>96</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>96</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>96</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>96</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>96</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>97</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>97</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>97</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>97</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>97</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>97</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>97</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>97</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>97</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_assumptions</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>97</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>102</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>102</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>103</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>103</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>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>103</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>103</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>103</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>103</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>103</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>103</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>103</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>Value assigned to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value assigned to &apos;p&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>103</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>103</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>103</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</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>103</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>103</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>103</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming pointer value is null</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>103</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>103</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</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>105</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>105</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>105</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>105</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>105</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>105</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>105</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>105</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_cond_assign</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</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>118</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>118</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>119</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>23</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>col</key><integer>82</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>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</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>119</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>120</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>120</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>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>120</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>120</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</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>120</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>120</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>120</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>120</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>Assuming &apos;x&apos; is 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is 0</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>120</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>120</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>122</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>122</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>122</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>122</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>123</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>123</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: </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>123</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;value&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar8331641</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>123</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: <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>130</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>130</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>131</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>131</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>131</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>131</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>131</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>131</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>131</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>132</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>132</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</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>132</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</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>132</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_objc_fast_enumeration</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>140</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>140</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>140</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead increment</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_objc_fast_enumeration_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>140</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>136</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>136</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>136</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>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</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>136</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>136</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>137</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>137</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>137</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>137</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>137</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>Loop body skipped when collection is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when collection is empty</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>137</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>137</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>140</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>140</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>140</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>140</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>140</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>140</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>140</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>140</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>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Assigned value is garbage or undefined</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_objc_fast_enumeration_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>145</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>145</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>145</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>146</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>146</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>146</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>146</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>146</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>146</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>146</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>150</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>150</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>150</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>150</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>145</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>145</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>145</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>145</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>145</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>145</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>145</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>146</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>146</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>146</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>147</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>147</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>147</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>147</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>147</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>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>147</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>147</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>148</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</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>148</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>148</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>148</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>148</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>148</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar12280665</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</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: <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>157</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>157</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>158</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>158</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>158</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>158</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>158</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>158</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>158</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>159</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>159</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>159</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>159</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>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</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>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>28</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</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>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>159</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</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>162</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>162</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>162</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>162</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>162</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>162</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>162</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>162</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_for</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</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>166</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>166</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>166</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>166</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>168</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>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>168</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>168</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>168</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>168</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>168</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>168</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>168</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</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>168</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>168</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>168</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>168</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</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>172</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>172</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>172</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>172</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>172</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>172</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>172</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>172</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_while</string>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>176</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>176</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>176</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>176</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>176</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>177</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>177</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>177</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>177</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>178</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>178</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>178</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>178</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>179</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>179</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>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>179</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>179</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>185</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>185</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>185</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>185</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>177</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>177</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</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>177</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>177</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>177</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>177</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>177</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>177</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>178</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>178</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>178</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>178</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>181</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>181</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>183</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>183</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>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>183</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>183</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>186</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>186</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>186</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>186</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>186</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>186</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>186</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>186</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>186</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_foo_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>186</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>190</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>190</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>191</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>191</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>191</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>191</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</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>191</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>191</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>191</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>191</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>37</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>191</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>191</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</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>191</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>191</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>191</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>191</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>192</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>192</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>192</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>192</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>192</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>192</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>192</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>192</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>192</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>192</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>196</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>196</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>198</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>198</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>198</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>198</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>198</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</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>204</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>204</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>204</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>204</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>198</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>198</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>198</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>198</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>198</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>198</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>198</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</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>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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</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>204</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>204</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>204</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>204</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>198</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>198</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>198</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>198</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>198</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>198</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>198</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>206</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>206</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>206</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>206</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>206</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>206</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>206</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>206</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>206</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>206</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>210</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>210</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>215</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>215</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>215</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>215</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>215</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>215</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>215</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>216</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</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>218</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>218</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>218</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>218</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>215</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>215</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>215</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>215</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>215</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>215</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>215</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>215</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>215</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>215</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>216</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</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>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>217</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>217</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>218</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>218</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>218</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>218</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>215</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>215</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>215</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>215</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>215</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>215</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>215</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>219</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>219</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>219</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>219</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>219</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>219</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>219</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>219</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>219</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics_3</string>
+// CHECK-NEXT: <key>issue_hash</key><string>10</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>219</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>223</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>223</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>225</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>225</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>225</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>225</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>229</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>229</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>229</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>229</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</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>232</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>232</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: </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>232</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>232</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>227</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>227</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>227</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>227</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>227</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>227</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>227</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>229</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>229</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>229</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>229</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</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>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>230</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</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>232</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>232</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: </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>232</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>232</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>234</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>234</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>234</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>234</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>234</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>234</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>234</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>234</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>234</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_do_while</string>
+// CHECK-NEXT: <key>issue_hash</key><string>12</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>234</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>239</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>239</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>239</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>239</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>239</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>240</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>240</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>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>240</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>240</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>240</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>240</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>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>240</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>240</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>240</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>240</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: </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>240</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>240</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>241</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>241</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>241</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>241</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>241</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>241</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>241</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>241</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>241</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_logical_and</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>241</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: <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>246</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>246</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>246</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>246</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>246</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>247</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>247</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>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>247</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>247</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>247</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>247</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>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>247</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>247</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>247</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>247</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: </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>247</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>247</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>248</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>248</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>248</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>248</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>248</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>248</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>248</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>248</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>248</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_logical_or</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>248</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: <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>254</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>254</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>254</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>254</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>254</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>255</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>255</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>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>255</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>255</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</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: </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>255</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</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>255</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>255</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>255</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>255</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>255</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>255</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>256</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>256</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>256</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>256</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>256</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>256</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>256</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>256</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>256</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_logical_or_call</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>256</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: <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>261</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>261</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>261</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>261</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>261</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>263</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>263</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>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>263</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>263</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>263</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>263</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>263</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>264</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>264</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>264</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>264</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>264</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>264</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>264</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>264</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>264</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_nested_logicals</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>264</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: <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>261</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>261</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>261</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>261</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>261</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>263</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>263</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>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>263</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>263</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>263</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>263</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>263</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>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>263</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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>267</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>267</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>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>267</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>267</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>267</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>267</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>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>267</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>267</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>267</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>267</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>267</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>267</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>267</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>267</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>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>267</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>267</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>268</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>268</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>268</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>268</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>268</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>268</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>268</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>268</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>268</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_nested_logicals</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>268</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: <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>274</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>274</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>274</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>274</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>274</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>276</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>276</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>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>276</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>276</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</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>276</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>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>276</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>276</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>276</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>276</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>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>276</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>276</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>30</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>31</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>36</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>36</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>46</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>46</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>46</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>46</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>51</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>51</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>51</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>51</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>41</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>44</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>276</integer>
+// CHECK-NEXT: <key>col</key><integer>41</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>276</integer>
+// CHECK-NEXT: <key>col</key><integer>44</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>276</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>276</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>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>276</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>276</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>278</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>278</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>278</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>278</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>278</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>278</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>278</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>278</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>278</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_deeply_nested_logicals</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>278</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: <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>283</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>283</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>283</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>283</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>283</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>283</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>283</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>Assuming &apos;x&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is not equal to 0</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>283</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>283</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>283</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>283</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>283</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>283</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>283</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>283</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>283</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>283</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>285</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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>285</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>285</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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>285</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: </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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>285</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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>285</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>285</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>285</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>285</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>285</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>285</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>285</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>285</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>285</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>287</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>287</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>287</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>287</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>287</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>287</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>287</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>287</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>287</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ternary</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>287</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>291</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>291</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>291</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>291</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>291</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>291</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>291</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>Assuming &apos;y&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is null</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>291</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>291</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>294</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>294</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>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>294</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>294</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>297</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>297</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>297</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>297</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>297</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>297</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>297</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>298</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>298</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>298</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>298</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>298</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>298</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>298</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>298</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>298</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testUseless</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>298</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>310</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>310</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>310</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>310</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>310</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>310</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>310</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>Assuming &apos;x&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is nil</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>310</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>310</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>312</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>312</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>312</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>312</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>312</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>312</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: </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>312</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>312</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>312</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;returnsPointer&apos; not called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;returnsPointer&apos; not called because the receiver is nil</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>312</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>312</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>312</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testFoo</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>312</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>320</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>320</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>320</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>&apos;x&apos; initialized to nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to nil</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>320</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>320</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>321</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>321</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>321</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>321</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>321</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>&apos;getPointer&apos; not called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;getPointer&apos; not called because the receiver is nil</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>321</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>321</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>321</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>321</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>321</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>321</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test1_IPA_X</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>337</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>337</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>337</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>337</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>337</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>337</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>337</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>Assuming &apos;y&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is nil</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>337</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>337</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>340</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>340</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>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>340</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>340</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>340</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>340</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>340</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>340</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>340</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>&apos;opaque&apos; not called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;opaque&apos; not called because the receiver is nil</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>340</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>340</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>340</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>&apos;getX&apos; not called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;getX&apos; not called because the receiver is nil</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>340</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>340</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>340</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>340</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>340</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>340</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>&apos;x&apos; initialized to nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to nil</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>340</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>340</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>341</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>341</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>341</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>341</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>341</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>&apos;getPointer&apos; not called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;getPointer&apos; not called because the receiver is nil</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>341</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>341</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>341</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>341</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>341</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>341</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_IPA_Y</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>352</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>352</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>354</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>354</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>354</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>354</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>354</integer>
+// CHECK-NEXT: <key>col</key><integer>25</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;causeDivByZeroInMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;causeDivByZeroInMain&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>345</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;mainPlusMain&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;mainPlusMain&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>345</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>345</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>346</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>346</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>346</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>346</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>346</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;m&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;m&apos; initialized to 0</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>346</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>346</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>347</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>347</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>347</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>347</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>347</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>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>causeDivByZeroInMain</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>347</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>383</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>383</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>383</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>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>383</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>383</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>384</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>384</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>384</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>384</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>384</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>384</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>384</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>384</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>384</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>384</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>392</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>392</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>392</integer>
+// CHECK-NEXT: <key>col</key><integer>25</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>&apos;s.i&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;s.i&apos; initialized to a null pointer value</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>392</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>392</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>394</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>394</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>394</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>394</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>394</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: <key>category</key><string>API</string>
+// CHECK-NEXT: <key>type</key><string>Argument with &apos;nonnull&apos; attribute passed null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>RDar13295437</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>394</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>400</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>400</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>400</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>400</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>400</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>400</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>400</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>Assuming &apos;coin&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;coin&apos; is not equal to 0</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>400</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>400</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>401</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>401</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>401</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>401</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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testCast</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>420</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>420</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>421</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>421</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>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>421</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>422</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>422</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>422</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>422</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>422</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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>422</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: <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>431</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>431</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>431</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>431</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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>Value stored to &apos;foo&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;foo&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;foo&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>431</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: <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>430</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>430</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>431</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>431</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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>433</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>433</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>433</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>433</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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>446</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>446</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>446</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>446</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>449</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>449</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</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>449</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</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>449</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>449</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>453</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>453</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>453</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>453</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>453</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>453</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>453</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>458</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>458</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>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>458</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>458</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>458</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>458</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>458</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>458</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>458</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>20</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>458</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>462</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>462</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>463</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>463</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>463</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>463</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>464</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>464</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</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>464</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</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>464</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>26</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>464</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>462</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>462</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>467</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>467</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>467</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>467</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>467</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>467</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>467</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>468</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>468</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>468</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>468</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>472</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>472</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</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>472</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</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>472</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>34</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>472</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>462</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>462</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>467</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>467</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>467</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>467</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>467</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>Loop body skipped when collection is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when collection is empty</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>467</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>467</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>475</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>475</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>475</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>475</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>484</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>484</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>484</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>484</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>484</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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>484</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>484</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>491</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>491</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>491</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>491</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>491</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>491</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>491</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>494</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>494</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>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>494</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>494</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>497</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>497</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>497</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>497</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>498</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>498</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>498</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>499</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>499</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>499</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>499</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>500</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>500</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</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>500</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</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>500</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>62</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>500</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>462</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>462</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>467</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>467</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>467</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>467</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>467</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>Loop body skipped when collection is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when collection is empty</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>467</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>467</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>475</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>475</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>475</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>475</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>484</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>484</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>484</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>484</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>484</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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>484</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>484</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>491</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>491</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>491</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>491</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>491</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>491</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>491</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>494</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>494</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>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>494</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>494</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>497</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>497</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>497</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>497</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>498</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>498</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>498</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>503</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>503</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>503</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>504</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>504</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>504</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>504</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>505</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>505</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</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>505</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</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>505</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>67</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>505</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>462</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>462</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>467</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>467</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>467</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>467</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>467</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>Loop body skipped when collection is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when collection is empty</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>467</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>467</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>475</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>475</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>475</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>475</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>484</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>484</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>484</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>484</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>484</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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>484</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>484</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>491</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>491</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>491</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>491</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>491</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>491</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>491</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>494</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>494</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>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>494</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>494</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>497</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>497</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>497</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>497</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>498</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>498</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>498</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>503</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>503</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>503</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>508</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>508</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>508</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>508</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>508</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>508</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>508</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>509</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>509</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>509</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>509</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>510</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>510</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>510</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>510</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>512</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>512</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</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>512</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</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>512</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>74</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>512</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>445</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>445</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>445</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>445</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>445</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>452</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>452</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>452</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>452</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>454</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>454</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>457</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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>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>459</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>459</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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: </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>460</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>460</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>462</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>462</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>462</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>462</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>462</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>467</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>467</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>467</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>467</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>467</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>Loop body skipped when collection is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when collection is empty</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>467</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>467</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>475</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>475</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>475</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>475</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>476</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>476</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>476</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>481</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>481</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>481</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>481</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>476</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>476</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>476</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>476</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>481</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>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</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>476</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>476</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>484</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>484</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>484</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>484</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>484</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>Loop body skipped when range is empty</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body skipped when range is empty</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>484</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>484</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>491</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>491</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>491</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>491</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>491</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>491</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>491</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>492</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>492</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>493</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>494</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>494</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>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>494</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>494</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>497</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>497</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>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>497</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>497</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>498</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>498</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>498</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>498</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>498</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>503</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>503</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>503</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>503</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>503</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>508</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>508</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>508</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>508</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>508</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</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>508</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>508</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>515</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>515</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>515</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>515</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>515</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>Entering loop body</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entering loop body</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>515</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>515</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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>516</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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>516</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>517</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>517</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>517</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>517</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>518</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>518</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>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>518</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>518</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</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>521</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>521</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>521</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>521</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>521</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>521</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>521</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>521</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>variousLoops</string>
+// CHECK-NEXT: <key>issue_hash</key><string>83</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</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: <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>529</integer>
+// CHECK-NEXT: <key>col</key><integer>23</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>529</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>529</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</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>529</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>529</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>531</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>531</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>531</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>531</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>531</integer>
+// CHECK-NEXT: <key>col</key><integer>38</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>Attempt to reallocate memory</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Attempt to reallocate memory</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>531</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>531</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>532</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>532</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>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>532</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>532</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>532</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>532</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>532</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>532</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>532</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>Assuming &apos;tmp&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</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>532</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>532</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>532</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>Reallocation failed</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reallocation failed</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>532</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>532</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>533</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>533</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>533</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Potential leak of memory pointed to by &apos;buf&apos;</string>
+// 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>type</key><string>Memory leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>reallocDiagnostics</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>533</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>548</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>548</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>551</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>551</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: </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>551</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>551</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>551</integer>
+// CHECK-NEXT: <key>col</key><integer>30</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>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</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>551</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>551</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>553</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>553</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>553</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>553</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>555</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>555</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: </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>555</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;~unique_ptr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~unique_ptr&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>544</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;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&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>544</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>544</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>544</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>544</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>544</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>544</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>544</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
+// 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>type</key><string>Bad deallocator</string>
+// CHECK-NEXT: <key>issue_hash</key><string>0</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>544</integer>
+// CHECK-NEXT: <key>col</key><integer>19</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>558</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>558</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>558</integer>
+// CHECK-NEXT: <key>col</key><integer>34</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>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</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>558</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>558</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>559</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>559</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>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>559</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>559</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</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: </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>560</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>560</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +2 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +2 retain count</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>560</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>560</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>561</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>561</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>561</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>561</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>561</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>561</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>561</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Reference count decremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count decremented. The object now has a +1 retain count</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>561</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>561</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>562</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>562</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>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>562</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>562</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>562</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: </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>562</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>562</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>563</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +2 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +2 retain count</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>562</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>562</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>562</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>562</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>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>562</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>562</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>564</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>564</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>564</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>564</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>564</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>564</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>564</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Reference count decremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count decremented. The object now has a +1 retain count</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>564</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>564</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>566</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>566</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>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>566</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>566</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</integer>
+// CHECK-NEXT: <key>col</key><integer>87</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</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>566</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>Reference count incremented. The object now has a +2 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +2 retain count</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>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>566</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>566</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>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>566</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>566</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>567</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>567</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>567</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>567</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>567</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>567</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>567</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>Reference count decremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count decremented. The object now has a +1 retain count</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>567</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>567</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>568</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>568</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: </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>568</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>longLines</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>568</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: <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>572</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>572</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>572</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>572</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>572</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>573</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>573</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>573</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>573</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>573</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>573</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>573</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>573</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>573</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testMacroInFunctionDecl</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>573</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>584</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>584</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>585</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>585</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>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>585</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>585</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>587</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>587</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>587</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>587</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>588</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>588</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>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>588</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>588</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>588</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>588</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>588</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>588</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>588</integer>
+// CHECK-NEXT: <key>col</key><integer>30</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>588</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: </array>
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index 9abb560e7583..78afb45da696 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
void f(void) {
void (*p)(void);
@@ -25,3 +26,16 @@ void f3(void (*f)(void), void (*g)(void)) {
(*g)();
clang_analyzer_eval(!g); // expected-warning{{FALSE}}
}
+
+void nullFunctionPointerConstant() {
+ void (*f)(void) = 0;
+ f(); // expected-warning{{Called function pointer is null}}
+ clang_analyzer_warnIfReached(); // no-warning
+}
+
+void nullFunctionPointerConstraint(void (*f)(void)) {
+ if (f)
+ return;
+ f(); // expected-warning{{Called function pointer is null}}
+ clang_analyzer_warnIfReached(); // no-warning
+}
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
index 6e89faefc5bd..bb769283bba9 100644
--- a/test/Analysis/html-diags-multifile.c
+++ b/test/Analysis/html-diags-multifile.c
@@ -1,6 +1,6 @@
// RUN: mkdir -p %t.dir
-// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir
-// RUN: ls %t.dir | grep report | count 0
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir %s
+// RUN: ls %t.dir | not grep report
// RUN: rm -fR %t.dir
// This tests that we do not currently emit HTML diagnostics for reports that
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
index 1ec4d18884ad..1b01783d5d24 100644
--- a/test/Analysis/html-diags.c
+++ b/test/Analysis/html-diags.c
@@ -1,6 +1,14 @@
// RUN: rm -fR %T/dir
// RUN: mkdir %T/dir
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %T/dir %s
+// RUN: ls %T/dir | grep report
+
+// PR16547: Test relative paths
+// RUN: cd %T/dir
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o testrelative %s
+// RUN: ls %T/dir/testrelative | grep report
+
+// REQUIRES: shell
// 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/identical-expressions.cpp b/test/Analysis/identical-expressions.cpp
new file mode 100644
index 000000000000..50f341d39335
--- /dev/null
+++ b/test/Analysis/identical-expressions.cpp
@@ -0,0 +1,942 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -verify %s
+
+/* Only one expected warning per function allowed at the very end. */
+
+/* '!=' operator*/
+
+/* '!=' with float */
+int checkNotEqualFloatLiteralCompare1(void) {
+ return (5.14F != 5.14F); // no warning
+}
+
+int checkNotEqualFloatLiteralCompare2(void) {
+ return (6.14F != 7.14F); // no warning
+}
+
+int checkNotEqualFloatDeclCompare1(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f != g); // no warning
+}
+
+int checkNotEqualFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return (f != f); // no warning
+}
+
+int checkNotEqualFloatDeclCompare3(void) {
+ float f = 7.1F;
+ return (f != 7.1F); // no warning
+}
+
+int checkNotEqualFloatDeclCompare4(void) {
+ float f = 7.1F;
+ return (7.1F != f); // no warning
+}
+
+int checkNotEqualFloatDeclCompare5(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (t != f); // no warning
+}
+
+int checkNotEqualFloatDeclCompare6(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (f != t); // no warning
+}
+
+
+
+int checkNotEqualCastFloatDeclCompare11(void) {
+ float f = 7.1F;
+ return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkNotEqualCastFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return ((char)f != (int)f); // no warning
+}
+int checkNotEqualBinaryOpFloatCompare1(void) {
+ int res;
+ float f= 3.14F;
+ res = (f + 3.14F != f + 3.14F); // no warning
+ return (0);
+}
+int checkNotEqualBinaryOpFloatCompare2(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f + 3.14F != g + 3.14F); // no warning
+}
+int checkNotEqualBinaryOpFloatCompare3(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F != (int)f + 3.14F); // no warning
+ return (0);
+}
+int checkNotEqualBinaryOpFloatCompare4(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F != (char)f + 3.14F); // no warning
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpFloatCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (3.14F - u)*t) != ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpFloatCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) != ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpFloatCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) != ((int)f + (3.14F - u)*(f + t != f + t))); // no warning
+ return (0);
+}
+
+
+
+
+/* end '!=' with float*/
+
+/* '!=' with int*/
+
+int checkNotEqualIntLiteralCompare1(void) {
+ return (5 != 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkNotEqualIntLiteralCompare2(void) {
+ return (6 != 7); // no warning
+}
+
+int checkNotEqualIntDeclCompare1(void) {
+ int f = 7;
+ int g = 7;
+ return (f != g); // no warning
+}
+
+int checkNotEqualIntDeclCompare3(void) {
+ int f = 7;
+ return (f != 7); // no warning
+}
+
+int checkNotEqualIntDeclCompare4(void) {
+ int f = 7;
+ return (7 != f); // no warning
+}
+
+int checkNotEqualCastIntDeclCompare11(void) {
+ int f = 7;
+ return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkNotEqualCastIntDeclCompare12(void) {
+ int f = 7;
+ return ((char)f != (int)f); // no warning
+}
+int checkNotEqualBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkNotEqualBinaryOpIntCompare2(void) {
+ int f = 7;
+ int g = 7;
+ return (f + 4 != g + 4); // no warning
+}
+
+
+int checkNotEqualBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = ((int)f + 4 != (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkNotEqualBinaryOpIntCompare4(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = ((int)f + 4 != (char)f + 4); // no warning
+ return (0);
+}
+int checkNotEqualBinaryOpIntCompare5(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ res = (u + t != u + t); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (3 - u)*t) != ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpIntCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*t)); // no warning
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*(t + 1 != t + 1))); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+/* end '!=' int */
+
+
+
+/* '!=' with int pointer */
+
+int checkNotEqualIntPointerLiteralCompare1(void) {
+ int* p = 0;
+ return (p != 0); // no warning
+}
+
+int checkNotEqualIntPointerLiteralCompare2(void) {
+ return (6 != 7); // no warning
+}
+
+int checkNotEqualIntPointerDeclCompare1(void) {
+ int k = 3;
+ int* f = &k;
+ int* g = &k;
+ return (f != g); // no warning
+}
+
+int checkNotEqualCastIntPointerDeclCompare11(void) {
+ int k = 7;
+ int* f = &k;
+ return ((int*)f != (int*)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkNotEqualCastIntPointerDeclCompare12(void) {
+ int k = 7;
+ int* f = &k;
+ return ((int*)((char*)f) != (int*)f); // no warning
+}
+int checkNotEqualBinaryOpIntPointerCompare1(void) {
+ int k = 7;
+ int res;
+ int* f= &k;
+ res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkNotEqualBinaryOpIntPointerCompare2(void) {
+ int k = 7;
+ int* f = &k;
+ int* g = &k;
+ return (f + 4 != g + 4); // no warning
+}
+
+
+int checkNotEqualBinaryOpIntPointerCompare3(void) {
+ int k = 7;
+ int res;
+ int* f= &k;
+ res = ((int*)f + 4 != (int*)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkNotEqualBinaryOpIntPointerCompare4(void) {
+ int k = 7;
+ int res;
+ int* f= &k;
+ res = ((int*)f + 4 != (int*)((char*)f) + 4); // no warning
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpIntPointerCompare1(void) {
+ int res;
+ int k = 7;
+ int t= 1;
+ int* u= &k+2;
+ int* f= &k+3;
+ res = ((f + (3)*t) != (f + (3)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+int checkNotEqualNestedBinaryOpIntPointerCompare2(void) {
+ int res;
+ int k = 7;
+ int t= 1;
+ int* u= &k+2;
+ int* f= &k+3;
+ res = (((3)*t + f) != (f + (3)*t)); // no warning
+ return (0);
+}
+/* end '!=' int* */
+
+/* end '!=' */
+
+
+
+/* EQ operator */
+
+int checkEqualIntPointerDeclCompare(void) {
+ int k = 3;
+ int* f = &k;
+ int* g = &k;
+ return (f == g); // no warning
+}
+
+int checkEqualIntPointerDeclCompare0(void) {
+ int k = 3;
+ int* f = &k;
+ return (f+1 == f+1); // expected-warning {{comparison of identical expressions always evaluates to true}}
+}
+
+/* EQ with float*/
+
+int checkEqualFloatLiteralCompare1(void) {
+ return (5.14F == 5.14F); // no warning
+}
+
+int checkEqualFloatLiteralCompare2(void) {
+ return (6.14F == 7.14F); // no warning
+}
+
+int checkEqualFloatDeclCompare1(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f == g); // no warning
+}
+
+int checkEqualFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return (f == f); // no warning
+}
+
+
+int checkEqualFloatDeclCompare3(void) {
+ float f = 7.1F;
+ return (f == 7.1F); // no warning
+}
+
+int checkEqualFloatDeclCompare4(void) {
+ float f = 7.1F;
+ return (7.1F == f); // no warning
+}
+
+int checkEqualFloatDeclCompare5(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (t == f); // no warning
+}
+
+int checkEqualFloatDeclCompare6(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (f == t); // no warning
+}
+
+
+
+
+int checkEqualCastFloatDeclCompare11(void) {
+ float f = 7.1F;
+ return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}}
+}
+int checkEqualCastFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return ((char)f == (int)f); // no warning
+}
+int checkEqualBinaryOpFloatCompare1(void) {
+ int res;
+ float f= 3.14F;
+ res = (f + 3.14F == f + 3.14F); // no warning
+ return (0);
+}
+int checkEqualBinaryOpFloatCompare2(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f + 3.14F == g + 3.14F); // no warning
+}
+int checkEqualBinaryOpFloatCompare3(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F == (int)f + 3.14F); // no warning
+ return (0);
+}
+int checkEqualBinaryOpFloatCompare4(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F == (char)f + 3.14F); // no warning
+ return (0);
+}
+
+int checkEqualNestedBinaryOpFloatCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (3.14F - u)*t) == ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkEqualNestedBinaryOpFloatCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) == ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkEqualNestedBinaryOpFloatCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) == ((int)f + (3.14F - u)*(f + t == f + t))); // no warning
+ return (0);
+}
+
+
+
+
+
+/* Equal with int*/
+
+int checkEqualIntLiteralCompare1(void) {
+ return (5 == 5); // expected-warning {{comparison of identical expressions always evaluates to true}}
+}
+
+int checkEqualIntLiteralCompare2(void) {
+ return (6 == 7); // no warning
+}
+
+int checkEqualIntDeclCompare1(void) {
+ int f = 7;
+ int g = 7;
+ return (f == g); // no warning
+}
+
+int checkEqualCastIntDeclCompare11(void) {
+ int f = 7;
+ return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}}
+}
+int checkEqualCastIntDeclCompare12(void) {
+ int f = 7;
+ return ((char)f == (int)f); // no warning
+}
+
+int checkEqualIntDeclCompare3(void) {
+ int f = 7;
+ return (f == 7); // no warning
+}
+
+int checkEqualIntDeclCompare4(void) {
+ int f = 7;
+ return (7 == f); // no warning
+}
+
+int checkEqualBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = (f + 4 == f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}}
+ return (0);
+}
+int checkEqualBinaryOpIntCompare2(void) {
+ int f = 7;
+ int g = 7;
+ return (f + 4 == g + 4); // no warning
+}
+
+
+int checkEqualBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = ((int)f + 4 == (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}}
+ return (0);
+
+}
+int checkEqualBinaryOpIntCompare4(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 4;
+ res = ((int)f + 4 == (char)f + 4); // no warning
+ return (0);
+}
+int checkEqualBinaryOpIntCompare5(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ res = (u + t == u + t); // expected-warning {{comparison of identical expressions always evaluates to true}}
+ return (0);
+}
+
+int checkEqualNestedBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (3 - u)*t) == ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to true}}
+ return (0);
+}
+
+int checkEqualNestedBinaryOpIntCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*t)); // no warning
+ return (0);
+}
+
+int checkEqualNestedBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*(t + 1 == t + 1))); // expected-warning {{comparison of identical expressions always evaluates to true}}
+ return (0);
+}
+
+
+/* end EQ int */
+
+/* end EQ */
+
+
+/* LT */
+
+/* LT with float */
+
+int checkLessThanFloatLiteralCompare1(void) {
+ return (5.14F < 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkLessThanFloatLiteralCompare2(void) {
+ return (6.14F < 7.14F); // no warning
+}
+
+int checkLessThanFloatDeclCompare1(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f < g); // no warning
+}
+
+int checkLessThanFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return (f < f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkLessThanFloatDeclCompare3(void) {
+ float f = 7.1F;
+ return (f < 7.1F); // no warning
+}
+
+int checkLessThanFloatDeclCompare4(void) {
+ float f = 7.1F;
+ return (7.1F < f); // no warning
+}
+
+int checkLessThanFloatDeclCompare5(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (t < f); // no warning
+}
+
+int checkLessThanFloatDeclCompare6(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (f < t); // no warning
+}
+
+
+int checkLessThanCastFloatDeclCompare11(void) {
+ float f = 7.1F;
+ return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkLessThanCastFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return ((char)f < (int)f); // no warning
+}
+int checkLessThanBinaryOpFloatCompare1(void) {
+ int res;
+ float f= 3.14F;
+ res = (f + 3.14F < f + 3.14F); // no warning
+ return (0);
+}
+int checkLessThanBinaryOpFloatCompare2(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f + 3.14F < g + 3.14F); // no warning
+}
+int checkLessThanBinaryOpFloatCompare3(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F < (int)f + 3.14F); // no warning
+ return (0);
+}
+int checkLessThanBinaryOpFloatCompare4(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F < (char)f + 3.14F); // no warning
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpFloatCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (3.14F - u)*t) < ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpFloatCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) < ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpFloatCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) < ((int)f + (3.14F - u)*(f + t < f + t))); // no warning
+ return (0);
+}
+
+/* end LT with float */
+
+/* LT with int */
+
+
+int checkLessThanIntLiteralCompare1(void) {
+ return (5 < 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkLessThanIntLiteralCompare2(void) {
+ return (6 < 7); // no warning
+}
+
+int checkLessThanIntDeclCompare1(void) {
+ int f = 7;
+ int g = 7;
+ return (f < g); // no warning
+}
+
+int checkLessThanIntDeclCompare3(void) {
+ int f = 7;
+ return (f < 7); // no warning
+}
+
+int checkLessThanIntDeclCompare4(void) {
+ int f = 7;
+ return (7 < f); // no warning
+}
+
+int checkLessThanIntDeclCompare5(void) {
+ int f = 7;
+ int t = 7;
+ return (t < f); // no warning
+}
+
+int checkLessThanIntDeclCompare6(void) {
+ int f = 7;
+ int t = 7;
+ return (f < t); // no warning
+}
+
+int checkLessThanCastIntDeclCompare11(void) {
+ int f = 7;
+ return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkLessThanCastIntDeclCompare12(void) {
+ int f = 7;
+ return ((char)f < (int)f); // no warning
+}
+int checkLessThanBinaryOpIntCompare1(void) {
+ int res;
+ int f= 3;
+ res = (f + 3 < f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkLessThanBinaryOpIntCompare2(void) {
+ int f = 7;
+ int g = 7;
+ return (f + 3 < g + 3); // no warning
+}
+int checkLessThanBinaryOpIntCompare3(void) {
+ int res;
+ int f= 3;
+ res = ((int)f + 3 < (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkLessThanBinaryOpIntCompare4(void) {
+ int res;
+ int f= 3;
+ res = ((int)f + 3 < (char)f + 3); // no warning
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (3 - u)*t) < ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpIntCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*t)); // no warning
+ return (0);
+}
+
+int checkLessThanNestedBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*(t + u < t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+/* end LT with int */
+
+/* end LT */
+
+
+/* GT */
+
+/* GT with float */
+
+int checkGreaterThanFloatLiteralCompare1(void) {
+ return (5.14F > 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkGreaterThanFloatLiteralCompare2(void) {
+ return (6.14F > 7.14F); // no warning
+}
+
+int checkGreaterThanFloatDeclCompare1(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+
+ return (f > g); // no warning
+}
+
+int checkGreaterThanFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return (f > f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+
+int checkGreaterThanFloatDeclCompare3(void) {
+ float f = 7.1F;
+ return (f > 7.1F); // no warning
+}
+
+int checkGreaterThanFloatDeclCompare4(void) {
+ float f = 7.1F;
+ return (7.1F > f); // no warning
+}
+
+int checkGreaterThanFloatDeclCompare5(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (t > f); // no warning
+}
+
+int checkGreaterThanFloatDeclCompare6(void) {
+ float f = 7.1F;
+ int t = 7;
+ return (f > t); // no warning
+}
+
+int checkGreaterThanCastFloatDeclCompare11(void) {
+ float f = 7.1F;
+ return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkGreaterThanCastFloatDeclCompare12(void) {
+ float f = 7.1F;
+ return ((char)f > (int)f); // no warning
+}
+int checkGreaterThanBinaryOpFloatCompare1(void) {
+ int res;
+ float f= 3.14F;
+ res = (f + 3.14F > f + 3.14F); // no warning
+ return (0);
+}
+int checkGreaterThanBinaryOpFloatCompare2(void) {
+ float f = 7.1F;
+ float g = 7.1F;
+ return (f + 3.14F > g + 3.14F); // no warning
+}
+int checkGreaterThanBinaryOpFloatCompare3(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F > (int)f + 3.14F); // no warning
+ return (0);
+}
+int checkGreaterThanBinaryOpFloatCompare4(void) {
+ int res;
+ float f= 3.14F;
+ res = ((int)f + 3.14F > (char)f + 3.14F); // no warning
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpFloatCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (3.14F - u)*t) > ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpFloatCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) > ((int)f + (3.14F - u)*t)); // no warning
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpFloatCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ float f= 3.14F;
+ res = (((int)f + (u - 3.14F)*t) > ((int)f + (3.14F - u)*(f + t > f + t))); // no warning
+ return (0);
+}
+
+/* end GT with float */
+
+/* GT with int */
+
+
+int checkGreaterThanIntLiteralCompare1(void) {
+ return (5 > 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+
+int checkGreaterThanIntLiteralCompare2(void) {
+ return (6 > 7); // no warning
+}
+
+int checkGreaterThanIntDeclCompare1(void) {
+ int f = 7;
+ int g = 7;
+
+ return (f > g); // no warning
+}
+
+int checkGreaterThanIntDeclCompare3(void) {
+ int f = 7;
+ return (f > 7); // no warning
+}
+
+int checkGreaterThanIntDeclCompare4(void) {
+ int f = 7;
+ return (7 > f); // no warning
+}
+
+int checkGreaterThanCastIntDeclCompare11(void) {
+ int f = 7;
+ return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+}
+int checkGreaterThanCastIntDeclCompare12(void) {
+ int f = 7;
+ return ((char)f > (int)f); // no warning
+}
+int checkGreaterThanBinaryOpIntCompare1(void) {
+ int res;
+ int f= 3;
+ res = (f + 3 > f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkGreaterThanBinaryOpIntCompare2(void) {
+ int f = 7;
+ int g = 7;
+ return (f + 3 > g + 3); // no warning
+}
+int checkGreaterThanBinaryOpIntCompare3(void) {
+ int res;
+ int f= 3;
+ res = ((int)f + 3 > (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+int checkGreaterThanBinaryOpIntCompare4(void) {
+ int res;
+ int f= 3;
+ res = ((int)f + 3 > (char)f + 3); // no warning
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpIntCompare1(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (3 - u)*t) > ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpIntCompare2(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*t)); // no warning
+ return (0);
+}
+
+int checkGreaterThanNestedBinaryOpIntCompare3(void) {
+ int res;
+ int t= 1;
+ int u= 2;
+ int f= 3;
+ res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*(t + u > t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ return (0);
+}
+
+/* end GT with int */
+
+/* end GT */
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index 3f7802c56d29..a71e35dc63c6 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -109,3 +109,37 @@ namespace DefaultConstructorWithCleanups {
return w.arr[0].value; // no-warning
}
}
+
+namespace DefaultMemberInitializers {
+ struct Wrapper {
+ int value = 42;
+
+ Wrapper() {}
+ Wrapper(int x) : value(x) {}
+ Wrapper(bool) {}
+ };
+
+ void test() {
+ Wrapper w1;
+ clang_analyzer_eval(w1.value == 42); // expected-warning{{TRUE}}
+
+ Wrapper w2(50);
+ clang_analyzer_eval(w2.value == 50); // expected-warning{{TRUE}}
+
+ Wrapper w3(false);
+ clang_analyzer_eval(w3.value == 42); // expected-warning{{TRUE}}
+ }
+
+ struct StringWrapper {
+ const char s[4] = "abc";
+ const char *p = "xyz";
+
+ StringWrapper(bool) {}
+ };
+
+ void testString() {
+ StringWrapper w(true);
+ clang_analyzer_eval(w.s[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.p[1] == 'y'); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp
index b62d979d5bf0..db3c0fb99000 100644
--- a/test/Analysis/initializers-cfg-output.cpp
+++ b/test/Analysis/initializers-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
class A {
public:
@@ -43,6 +43,13 @@ TestControlFlow::TestControlFlow(bool b)
int v;
}
+class TestDelegating {
+ int x, z;
+ public:
+ TestDelegating() : TestDelegating(2, 3) {}
+ TestDelegating(int x, int z) : x(x), z(z) {}
+};
+
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -95,3 +102,14 @@ TestControlFlow::TestControlFlow(bool b)
// CHECK: Succs (2): B2 B3
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: 2
+// CHECK: 2: 3
+// CHECK: 3: [B1.1], [B1.2] (CXXConstructExpr, class TestDelegating)
+// CHECK: 4: TestDelegating([B1.3]) (Delegating initializer)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index dcdd23f74bb3..bcf15b343ae1 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -1,5 +1,5 @@
// RUN: %clang --analyze %s -fblocks -Xanalyzer -analyzer-output=text -Xanalyzer -analyzer-config -Xanalyzer suppress-null-return-paths=false -Xclang -verify %s
-// RUN: %clang --analyze %s -fblocks -Xanalyzer -analyzer-config -Xanalyzer suppress-null-return-paths=false -o %t
+// RUN: %clang --analyze %s -fblocks -Xanalyzer -analyzer-config -Xanalyzer suppress-null-return-paths=false -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t
// RUN: FileCheck -input-file %t %s
// <rdar://problem/10967815>
diff --git a/test/Analysis/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
index 5c42135b0490..9f33bd4652f7 100644
--- a/test/Analysis/inline-unique-reports.c
+++ b/test/Analysis/inline-unique-reports.c
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -o %t > /dev/null 2>&1
+// RUN: %clang --analyze %s -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t > /dev/null 2>&1
// RUN: FileCheck -input-file %t %s
static inline bug(int *p) {
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index 8cba63f17e0d..9ecdce33a36d 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -110,3 +110,9 @@ void never_called_by_anyone() {
clang_analyzer_checkInlined(0); // no-warning
}
+
+void knr_one_argument(a) int a; { }
+
+void call_with_less_arguments() {
+ knr_one_argument(); // expected-warning{{too few arguments}} expected-warning{{Function taking 1 argument}}
+}
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 909e18017b34..ca126ddf7f38 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -290,6 +290,15 @@ namespace DefaultArgs {
clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}}
}
+
+ char defaultString(const char *s = "abc") {
+ return s[1];
+ }
+
+ void testString() {
+ clang_analyzer_eval(defaultString("xyz") == 'y'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(defaultString() == 'b'); // expected-warning{{TRUE}}
+ }
}
namespace OperatorNew {
@@ -420,3 +429,10 @@ namespace rdar12409977 {
clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
}
}
+
+namespace bug16307 {
+ void one_argument(int a) { }
+ void call_with_less() {
+ reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}}
+ }
+}
diff --git a/test/Analysis/inlining/DynDispatchBifurcate.m b/test/Analysis/inlining/DynDispatchBifurcate.m
index ab1dfc5ec14b..0ce079654e98 100644
--- a/test/Analysis/inlining/DynDispatchBifurcate.m
+++ b/test/Analysis/inlining/DynDispatchBifurcate.m
@@ -181,11 +181,11 @@ int testPropertySynthesized(PublicClass *p) {
}
// Test definition not available edge case.
-@interface DefNotAvailClass : NSObject
+@interface DefNotAvailClass : NSObject // expected-note {{receiver is instance of class declared here}}
@end
id testDefNotAvailableInlined(DefNotAvailClass *C) {
return [C mem]; // expected-warning {{instance method '-mem' not found}}
}
id testDefNotAvailable(DefNotAvailClass *C) {
return testDefNotAvailableInlined(C);
-} \ No newline at end of file
+}
diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m
index 90ce3c051bab..6efcb894fecd 100644
--- a/test/Analysis/inlining/InlineObjCClassMethod.m
+++ b/test/Analysis/inlining/InlineObjCClassMethod.m
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
+
+void clang_analyzer_checkInlined(int);
// Test inlining of ObjC class methods.
@@ -209,3 +211,26 @@ int checkSelfUsedInparentClassMethod() {
return 5/[SelfUsedInParentChild fooA];
}
+
+@interface Rdar15037033 : NSObject
+@end
+
+void rdar15037033() {
+ [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}}
+ [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}}
+}
+
+@implementation Rdar15037033
+
++ (void)forwardDeclaredMethod {
+ clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}
+}
+
++ (void)forwardDeclaredVariadicMethod:(int)x, ... {
+ clang_analyzer_checkInlined(0); // no-warning
+}
+
+@end
+
+
+
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.c b/test/Analysis/inlining/eager-reclamation-path-notes.c
index 65613658fcb8..d14aba3d989e 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.c
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void use(int *ptr, int val) {
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
index 05411bbc7778..672b3b8b3efb 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.cpp
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef struct {
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
index c5c6bb875ea2..e1c8f67614e1 100644
--- a/test/Analysis/inlining/false-positive-suppression.c
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -84,6 +84,14 @@ void testMultipleStore(void *p) {
#endif
}
+// Test that div by zero does not get suppressed. This is a policy choice.
+int retZero() {
+ return 0;
+}
+int triggerDivZero () {
+ int y = retZero();
+ return 5/y; // expected-warning {{Division by zero}}
+}
// --------------------------
// "Suppression suppression"
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
index aa7f70030c06..4ce783c852fe 100644
--- a/test/Analysis/inlining/inline-defensive-checks.c
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -110,3 +110,32 @@ void testConstantOffset(char *value) {
cursor++;
}
}
+
+// Ensure idc works for integer zero values (ex: suppressed div by zero).
+void idcZero(int assume) {
+ if (assume)
+ ;
+}
+
+int idcTriggerZeroValue(int m) {
+ idcZero(m);
+ return 5/m; // no-warning
+}
+
+int idcTriggerZeroValueThroughCall(int i) {
+ return 5/i; // no-warning
+}
+void idcTrackZeroValueThroughCall(int x) {
+ idcZero(x);
+ idcTriggerZeroValueThroughCall(x);
+}
+
+int idcTriggerZeroThroughDoubleAssignemnt(int i) {
+ return 5/i; // no-warning
+}
+void idcTrackZeroThroughDoubleAssignemnt(int x) {
+ idcZero(x);
+ int y = x;
+ int z = y;
+ idcTriggerZeroValueThroughCall(z);
+}
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
index 660988535b34..deb2efe1d803 100644
--- a/test/Analysis/inlining/path-notes.c
+++ b/test/Analysis/inlining/path-notes.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void zero(int **p) {
diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp
index e0c83cbe3296..a354e14df9ed 100644
--- a/test/Analysis/inlining/path-notes.cpp
+++ b/test/Analysis/inlining/path-notes.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
class Foo {
@@ -264,6 +264,40 @@ const A& testDeclRefExprToReferenceInGetDerefExpr(const A *ptr) {
return val;
}
+
+int generateNoteOnDefaultArgument(int one, int two = 0) {
+ return one/two; // expected-warning {{Division by zero}}
+ // expected-note@-1 {{Division by zero}}
+}
+int callGenerateNoteOnDefaultArgument(int o) {
+ return generateNoteOnDefaultArgument(o); //expected-note{{Calling 'generateNoteOnDefaultArgument'}}
+ //expected-note@-1 {{Passing the value 0 via 2nd parameter 'two'}}
+}
+
+namespace PR17746 {
+ class Inner {
+ public:
+ ~Inner() {
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+ }
+ };
+
+ class Outer {
+ public:
+ Inner *inner;
+ ~Outer() {
+ delete inner;
+ // expected-note@-1 {{Calling '~Inner'}}
+ }
+ };
+
+ void test(Outer *outer) {
+ delete outer;
+ // expected-note@-1 {{Calling '~Outer'}}
+ }
+}
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -4743,4 +4777,456 @@ const A& testDeclRefExprToReferenceInGetDerefExpr(const A *ptr) {
// 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>273</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>273</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>273</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>273</integer>
+// CHECK-NEXT: <key>col</key><integer>38</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>273</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>273</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>273</integer>
+// CHECK-NEXT: <key>col</key><integer>41</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>Passing the value 0 via 2nd parameter &apos;two&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing the value 0 via 2nd parameter &apos;two&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>273</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>273</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>273</integer>
+// CHECK-NEXT: <key>col</key><integer>41</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;generateNoteOnDefaultArgument&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;generateNoteOnDefaultArgument&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>268</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;callGenerateNoteOnDefaultArgument&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;callGenerateNoteOnDefaultArgument&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>268</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>268</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>269</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>269</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>269</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>269</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>269</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>269</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>269</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>269</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>269</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>generateNoteOnDefaultArgument</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>269</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>296</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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>296</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>296</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>Calling &apos;~Outer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~Outer&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>289</integer>
+// CHECK-NEXT: <key>col</key><integer>5</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;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&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>289</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>289</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>290</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>290</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: </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>290</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>290</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>290</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>Calling &apos;~Inner&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~Inner&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>280</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;~Outer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;~Outer&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>280</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>280</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>281</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>281</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>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>281</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>281</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>281</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>281</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>281</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>281</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>281</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>281</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: </array>
diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m
index 74f088a382bd..23040386e4dd 100644
--- a/test/Analysis/inlining/path-notes.m
+++ b/test/Analysis/inlining/path-notes.m
@@ -1,16 +1,74 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false -fblocks %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef struct dispatch_queue_s *dispatch_queue_t;
typedef void (^dispatch_block_t)(void);
void dispatch_sync(dispatch_queue_t, dispatch_block_t);
+typedef long dispatch_once_t;
+// Note: The real dispatch_once has all parameters marked nonnull.
+// We don't do that here so that we can trigger a null dereference inside
+// the synthesized body.
+void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
+
@interface Test
@property int *p;
@end
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@protocol NSFastEnumeration
+@end
+@protocol NSSecureCoding <NSCoding>
+@required
++ (BOOL)supportsSecureCoding;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+- (id)autorelease;
+@end
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
+
+- (NSUInteger)count;
+- (id)objectAtIndex:(NSUInteger)index;
+
+@end
+
+@interface NSArray (NSExtendedArray)
+- (NSArray *)arrayByAddingObject:(id)anObject;
+- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8)));
+@end
+
+@interface NSArray (NSArrayCreation)
++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
+@interface NSMutableArray : NSArray
+
+- (void)addObject:(id)anObject;
+- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
+- (void)removeLastObject;
+- (void)removeObjectAtIndex:(NSUInteger)index;
+- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
+
+@end
+
int *getZeroIfNil(Test *x) {
return x.p;
// expected-note@-1 {{'p' not called because the receiver is nil}}
@@ -34,10 +92,10 @@ int testDispatchSyncInlining() {
// expected-note@+2 {{Calling 'dispatch_sync'}}
// expected-note@+1 {{Returning from 'dispatch_sync'}}
dispatch_sync(globalQueue, ^{
- // expected-note@7 {{Calling anonymous block}}
+ // expected-note@-1 {{Calling anonymous block}}
+ // expected-note@-2 {{Returning to caller}}
x = 0;
// expected-note@-1 {{The value 0 is assigned to 'x'}}
- // expected-note@7 {{Returning to caller}}
});
return 1 / x; // expected-warning{{Division by zero}}
@@ -54,7 +112,7 @@ int testDispatchSyncInliningNoPruning(int coin) {
// expected-note@+1 {{Calling 'dispatch_sync'}}
dispatch_sync(globalQueue, ^{
- // expected-note@7 {{Calling anonymous block}}
+ // expected-note@-1 {{Calling anonymous block}}
int x;
// expected-note@-1 {{'x' declared without an initial value}}
^{ y = x; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}}
@@ -89,6 +147,32 @@ void testNilReceiver(id *x) {
// expected-note@-3 {{Calling 'testNilReceiverHelper'}}
}
+id testCreateArrayLiteral(id myNil) {
+ if (myNil) // expected-note {{Assuming 'myNil' is nil}}
+ ; // expected-note@-1 {{Taking false branch}}
+ return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}}
+ //expected-note@-1 {{Array element cannot be nil}}
+}
+
+// <rdar://problem/14611722>
+id testAutoreleaseTakesEffectInDispatch() {
+ static dispatch_once_t token = 0;
+ dispatch_once(&token, ^{});
+
+ id x = [[[[NSObject alloc] init] autorelease] autorelease];
+ // expected-note@-1 {{Method returns an Objective-C object with a +1 retain count}}
+ // expected-note@-2 {{Object autoreleased}}
+ // expected-note@-3 {{Object autoreleased}}
+
+ dispatch_once(&token, ^{}); // don't crash, don't warn here
+
+ return x; // expected-warning{{Object autoreleased too many times}}
+ // expected-note@-1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
+}
+
+void testNullDereferenceInDispatch() {
+ dispatch_once(0, ^{}); // no-warning, don't crash
+}
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
@@ -103,12 +187,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -116,12 +200,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -133,7 +217,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -141,12 +225,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -166,12 +250,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -179,12 +263,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -196,7 +280,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -204,12 +288,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -225,7 +309,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -243,12 +327,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>72</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>14</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -256,12 +340,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -277,12 +361,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -290,12 +374,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -307,7 +391,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -315,12 +399,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -340,12 +424,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -353,12 +437,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -370,7 +454,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -378,12 +462,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>15</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -399,7 +483,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -407,12 +491,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -432,12 +516,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -445,12 +529,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -462,7 +546,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -470,12 +554,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -496,7 +580,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -512,12 +596,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>88</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>30</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -525,12 +609,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -542,7 +626,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -550,12 +634,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>41</integer>
+// CHECK-NEXT: <key>line</key><integer>99</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -571,24 +655,25 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>7</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;testDispatchSyncInlining&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInlining&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>7</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>94</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>99</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: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
@@ -599,7 +684,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -617,12 +702,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -630,12 +715,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -647,7 +732,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -655,12 +740,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -676,10 +761,25 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>7</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>94</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>99</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: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returning to caller</string>
@@ -690,7 +790,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -698,12 +798,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>41</integer>
+// CHECK-NEXT: <key>line</key><integer>99</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -723,12 +823,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</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>36</integer>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -736,12 +836,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -753,7 +853,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -761,12 +861,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</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>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -787,7 +887,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>issue_hash</key><string>14</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -803,12 +903,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>line</key><integer>109</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>51</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -816,12 +916,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -833,7 +933,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -841,12 +941,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>62</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -862,24 +962,25 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>7</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;testDispatchSyncInliningNoPruning&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInliningNoPruning&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>7</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>114</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>120</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: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
@@ -890,7 +991,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -908,12 +1009,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>30</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>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -921,12 +1022,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -938,7 +1039,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -946,12 +1047,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -971,12 +1072,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>116</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -984,12 +1085,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>5</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>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1001,7 +1102,7 @@ void testNilReceiver(id *x) {
// 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>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1009,12 +1110,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>12</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>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1032,7 +1133,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>type</key><string>uninitialized variable captured by block</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1048,12 +1149,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>140</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>82</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1061,12 +1162,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1082,12 +1183,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1095,12 +1196,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1112,7 +1213,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1120,12 +1221,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1145,12 +1246,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1158,12 +1259,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1175,7 +1276,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1183,12 +1284,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1204,7 +1305,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1212,12 +1313,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</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>86</integer>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1233,7 +1334,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1251,12 +1352,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>134</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>76</integer>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1264,12 +1365,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1285,12 +1386,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1298,12 +1399,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1315,7 +1416,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1323,12 +1424,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1349,9 +1450,581 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>151</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>151</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</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>151</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>151</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>151</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>151</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>Assuming &apos;myNil&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;myNil&apos; is nil</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>151</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>151</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</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>153</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>153</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>153</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>153</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>153</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>153</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>153</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</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>Array element cannot be nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Array element cannot be nil</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Array element cannot be nil</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>nil argument</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testCreateArrayLiteral</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</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>159</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>159</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>160</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>160</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>160</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>160</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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>162</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>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>162</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>162</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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: </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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</integer>
+// CHECK-NEXT: <key>col</key><integer>34</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>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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>162</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>162</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>162</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>162</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>47</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</integer>
+// CHECK-NEXT: <key>col</key><integer>34</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>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>162</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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>162</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>162</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>162</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>60</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>162</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>162</integer>
+// CHECK-NEXT: <key>col</key><integer>47</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>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>162</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>162</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>167</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>167</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>167</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>167</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>169</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>169</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>169</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>169</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>169</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>Object was autoreleased 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testAutoreleaseTakesEffectInDispatch</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>169</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/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
index 6053daaf3a21..c153174d27ad 100644
--- a/test/Analysis/inlining/stl.cpp
+++ b/test/Analysis/inlining/stl.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -DINLINE=1 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -DINLINE=1 -verify %s
#include "../Inputs/system-header-simulator-cxx.h"
@@ -27,3 +27,18 @@ void testException(std::exception e) {
// expected-warning@-4 {{UNKNOWN}}
#endif
}
+
+void testList_pop_front(std::list<int> list) {
+ while(!list.empty())
+ list.pop_front(); // no-warning
+}
+
+void testBasicStringSuppression() {
+ std::basic_string<uint8_t> v;
+ v.push_back(1); // no-warning
+}
+
+void testBasicStringSuppression_append() {
+ std::basic_string<char32_t> v;
+ v += 'c'; // no-warning
+}
diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp
index 77b36c42cfa8..33e216b57ecc 100644
--- a/test/Analysis/lambdas.cpp
+++ b/test/Analysis/lambdas.cpp
@@ -10,7 +10,7 @@ void f(X x) { (void) [x]{}; }
// CHECK: 1: x
// CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
// CHECK: 3: [B1.2] (CXXConstructExpr, struct X)
-// CHECK: 4: [=x] {
+// CHECK: 4: [x] {
// CHECK: }
// CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
// CHECK: Preds (1): B2
diff --git a/test/Analysis/lit.local.cfg b/test/Analysis/lit.local.cfg
new file mode 100644
index 000000000000..da2a68b378cc
--- /dev/null
+++ b/test/Analysis/lit.local.cfg
@@ -0,0 +1,2 @@
+if config.root.clang_staticanalyzer == 0:
+ config.unsupported = True
diff --git a/test/Analysis/live-variables.cpp b/test/Analysis/live-variables.cpp
new file mode 100644
index 000000000000..0cfaa1b41f52
--- /dev/null
+++ b/test/Analysis/live-variables.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
+class B {
+public:
+ bool m;
+ ~B() {} // The destructor ensures that the binary logical operator below is wrapped in the ExprWithCleanups.
+};
+B foo();
+int getBool();
+int *getPtr();
+int test() {
+ int r = 0;
+ for (int x = 0; x< 10; x++) {
+ int *p = getPtr();
+ // Liveness info is not computed correctly due to the following expression.
+ // This happens due to CFG being special cased for short circuit operators.
+ // PR18159
+ if (p != 0 && getBool() && foo().m && getBool()) {
+ r = *p; // no warning
+ }
+ }
+ return r;
+}
diff --git a/test/Analysis/live-variables.m b/test/Analysis/live-variables.m
new file mode 100644
index 000000000000..eefd292bf79b
--- /dev/null
+++ b/test/Analysis/live-variables.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -fobjc-arc -verify %s
+// expected-no-diagnostics
+@interface NSObject
+@end
+@interface NSString : NSObject
+- (id)lastPathComponent;
+@end
+int getBool();
+int *getPtr();
+int foo() {
+ int r = 0;
+ NSString *filename = @"filename";
+ for (int x = 0; x< 10; x++) {
+ int *p = getPtr();
+ // Liveness info is not computed correctly due to the following expression.
+ // This happens due to CFG being special cased for short circuit operators.
+ // Note, due to ObjC method call, the outermost logical operator is wrapped in ExprWithCleanups.
+ // PR18159
+ if ((p != 0) && (getBool()) && ([filename lastPathComponent]) && (getBool())) {
+ r = *p; // no-warning
+ }
+ }
+ return r;
+} \ No newline at end of file
diff --git a/test/Analysis/logical-ops.c b/test/Analysis/logical-ops.c
index a1223b39fa89..afaa2f107780 100644
--- a/test/Analysis/logical-ops.c
+++ b/test/Analysis/logical-ops.c
@@ -25,3 +25,15 @@ int testTypeIsInt(int i, void *p) {
return 1;
return 0;
}
+
+// These crashed the analyzer at some point.
+int between(char *x) {
+ extern char start[];
+ extern char end[];
+ return x >= start && x < end;
+}
+
+int undef(void) {} // expected-warning{{control reaches end of non-void function}}
+void useUndef(void) { 0 || undef(); }
+
+void testPointer(void) { (void) (1 && testPointer && 0); }
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index 41bb8b5793ce..0cbf9725b683 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o %t %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck -input-file %t %s
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 6071d1d43582..58d40a31a835 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -627,8 +627,49 @@ void doNotInvalidateWhenPassedToSystemCalls(char *s) {
char *p = malloc(12);
strlen(p);
strcpy(p, s);
+ strcpy(s, p);
+ strcpy(p, p);
+ memcpy(p, s, 1);
+ memcpy(s, p, 1);
+ memcpy(p, p, 1);
} // expected-warning {{leak}}
+// Treat source buffer contents as escaped.
+void escapeSourceContents(char *s) {
+ char *p = malloc(12);
+ memcpy(s, &p, 12); // no warning
+
+ void *p1 = malloc(7);
+ char *a;
+ memcpy(&a, &p1, sizeof a);
+ // FIXME: No warning due to limitations imposed by current modelling of
+ // 'memcpy' (regions metadata is not copied).
+
+ int *ptrs[2];
+ int *allocated = (int *)malloc(4);
+ memcpy(&ptrs[0], &allocated, sizeof(int *));
+ // FIXME: No warning due to limitations imposed by current modelling of
+ // 'memcpy' (regions metadata is not copied).
+}
+
+void invalidateDestinationContents() {
+ int *null = 0;
+ int *p = (int *)malloc(4);
+ memcpy(&p, &null, sizeof(int *));
+
+ int *ptrs1[2]; // expected-warning {{Potential leak of memory pointed to by}}
+ ptrs1[0] = (int *)malloc(4);
+ memcpy(ptrs1, &null, sizeof(int *));
+
+ int *ptrs2[2]; // expected-warning {{Potential memory leak}}
+ ptrs2[0] = (int *)malloc(4);
+ memcpy(&ptrs2[1], &null, sizeof(int *));
+
+ int *ptrs3[2]; // expected-warning {{Potential memory leak}}
+ ptrs3[0] = (int *)malloc(4);
+ memcpy(&ptrs3[0], &null, sizeof(int *));
+} // expected-warning {{Potential memory leak}}
+
// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p.
void symbolLostWithStrcpy(char *s) {
char *p = malloc(12);
@@ -1057,12 +1098,6 @@ void testPassConstPointerIndirectly() {
return; // expected-warning {{leak}}
}
-void testPassToSystemHeaderFunctionIndirectly() {
- int *p = malloc(4);
- p++;
- fakeSystemHeaderCallInt(p);
-} // expected-warning {{leak}}
-
void testPassConstPointerIndirectlyStruct() {
struct HasPtr hp;
hp.p = malloc(10);
@@ -1073,8 +1108,32 @@ void testPassConstPointerIndirectlyStruct() {
void testPassToSystemHeaderFunctionIndirectlyStruct() {
SomeStruct ss;
ss.p = malloc(1);
- fakeSystemHeaderCall(&ss);
-} // expected-warning {{Potential leak of memory pointed to by 'ss.p'}}
+ fakeSystemHeaderCall(&ss); // invalidates ss, making ss.p unreachable
+ // Technically a false negative here -- we know the system function won't free
+ // ss.p, but nothing else will either!
+} // no-warning
+
+void testPassToSystemHeaderFunctionIndirectlyStructFree() {
+ SomeStruct ss;
+ ss.p = malloc(1);
+ fakeSystemHeaderCall(&ss); // invalidates ss, making ss.p unreachable
+ free(ss.p);
+} // no-warning
+
+void testPassToSystemHeaderFunctionIndirectlyArray() {
+ int *p[1];
+ p[0] = malloc(sizeof(int));
+ fakeSystemHeaderCallIntPtr(p); // invalidates p, making p[0] unreachable
+ // Technically a false negative here -- we know the system function won't free
+ // p[0], but nothing else will either!
+} // no-warning
+
+void testPassToSystemHeaderFunctionIndirectlyArrayFree() {
+ int *p[1];
+ p[0] = malloc(sizeof(int));
+ fakeSystemHeaderCallIntPtr(p); // invalidates p, making p[0] unreachable
+ free(p[0]);
+} // no-warning
int *testOffsetAllocate(size_t size) {
int *memoryBlock = (int *)malloc(size + sizeof(int));
@@ -1189,6 +1248,54 @@ void freeMemory() {
}
}
+// PR16730
+void testReallocEscaped(void **memory) {
+ *memory = malloc(47);
+ char *new_memory = realloc(*memory, 47);
+ if (new_memory != 0) {
+ *memory = new_memory;
+ }
+}
+
+// PR16558
+void *smallocNoWarn(size_t size) {
+ if (size == 0) {
+ return malloc(1); // this branch is never called
+ }
+ else {
+ return malloc(size);
+ }
+}
+
+char *dupstrNoWarn(const char *s) {
+ const int len = strlen(s);
+ char *p = (char*) smallocNoWarn(len + 1);
+ strcpy(p, s); // no-warning
+ return p;
+}
+
+void *smallocWarn(size_t size) {
+ if (size == 2) {
+ return malloc(1);
+ }
+ else {
+ return malloc(size);
+ }
+}
+
+char *dupstrWarn(const char *s) {
+ const int len = strlen(s);
+ char *p = (char*) smallocWarn(len + 1);
+ strcpy(p, s); // expected-warning{{String copy function overflows destination buffer}}
+ return p;
+}
+
+int *radar15580979() {
+ int *data = (int *)malloc(32);
+ int *p = data ?: (int*)malloc(32); // no warning
+ return p;
+}
+
// ----------------------------------------------------------------------------
// False negatives.
@@ -1200,3 +1307,11 @@ void testMallocWithParam(int **p) {
void testMallocWithParam_2(int **p) {
*p = (int*) malloc(sizeof(int)); // no-warning
}
+
+void testPassToSystemHeaderFunctionIndirectly() {
+ int *p = malloc(4);
+ p++;
+ fakeSystemHeaderCallInt(p);
+ // FIXME: This is a leak: if we think a system function won't free p, it
+ // won't free (p-1) either.
+}
diff --git a/test/Analysis/malloc.m b/test/Analysis/malloc.m
index 21d2dafa38b6..ad16db52dff9 100644
--- a/test/Analysis/malloc.m
+++ b/test/Analysis/malloc.m
@@ -35,3 +35,18 @@ void rdar10579586(char x);
}
@end
+@interface MyArray : NSObject {
+ id * objects;
+}
+@end
+
+void _ArrayCreate() {
+ MyArray *array = (MyArray *)malloc(12);
+ array = [array init];
+ free(array); // no-warning
+}
+
+void testNSDataTruePositiveLeak() {
+ char *b = (char *)malloc(12);
+ NSData *d = [[NSData alloc] initWithBytes: b length: 12]; // expected-warning {{Potential leak of memory pointed to by 'b'}}
+} \ No newline at end of file
diff --git a/test/Analysis/method-call-path-notes.cpp b/test/Analysis/method-call-path-notes.cpp
index f946b327d0c2..20348d588936 100644
--- a/test/Analysis/method-call-path-notes.cpp
+++ b/test/Analysis/method-call-path-notes.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// Test warning about null or uninitialized pointer values used as instance member
diff --git a/test/Analysis/misc-ps-arm.m b/test/Analysis/misc-ps-arm.m
index 1ff0f17cea5f..a9ea3274ae4b 100644
--- a/test/Analysis/misc-ps-arm.m
+++ b/test/Analysis/misc-ps-arm.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv7-apple-ios0.0.0 -analyze -analyzer-checker=core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple thumbv7-apple-ios0.0.0 -target-feature +neon -analyze -analyzer-checker=core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
// expected-no-diagnostics
// <rdar://problem/11405978> - Handle casts of vectors to structs, and loading
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 902a5e527113..6a873f01b3d3 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
+
+void clang_analyzer_warnIfReached();
// Test basic handling of references.
char &test1_aux();
@@ -54,9 +56,7 @@ int test_init_in_condition_switch() {
if (x == 2)
return 0;
else {
- // Unreachable.
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // unreachable
}
default:
break;
@@ -74,8 +74,7 @@ int test_init_in_condition_while() {
if (z == 2)
return 0;
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // unreachable
return 0;
}
@@ -89,8 +88,7 @@ int test_init_in_condition_for() {
if (z == 1)
return 0;
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // unreachable
return 0;
}
@@ -117,8 +115,7 @@ int TestHandleThis::null_deref_negative() {
if (x == 10) {
return 1;
}
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // unreachable
return 0;
}
@@ -127,8 +124,7 @@ int TestHandleThis::null_deref_positive() {
if (x == 9) {
return 1;
}
- int *p = 0;
- *p = 0xDEADBEEF; // expected-warning{{null pointer}}
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
return 0;
}
@@ -143,9 +139,9 @@ void pr7675_test() {
pr7675(10);
pr7675('c');
pr7675_i(4.0i);
- // Add null deref to ensure we are analyzing the code up to this point.
- int *p = 0;
- *p = 0xDEADBEEF; // expected-warning{{null pointer}}
+
+ // Add check to ensure we are analyzing the code up to this point.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
// <rdar://problem/8375510> - CFGBuilder should handle temporaries.
@@ -328,26 +324,23 @@ class RDar9267815 {
};
void RDar9267815::test_pos() {
- int *p = 0;
if (x == 42)
return;
- *p = 0xDEADBEEF; // expected-warning {{null}}
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
void RDar9267815::test() {
- int *p = 0;
if (x == 42)
return;
if (x == 42)
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
}
void RDar9267815::test2() {
- int *p = 0;
if (x == 42)
return;
invalidate();
if (x == 42)
- *p = 0xDEADBEEF; // expected-warning {{null}}
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
// Test reference parameters.
@@ -440,8 +433,7 @@ int rdar9948787_negative() {
unsigned value = classWithStatic.value;
if (value == 1)
return 1;
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
return 0;
}
@@ -450,8 +442,7 @@ int rdar9948787_positive() {
unsigned value = classWithStatic.value;
if (value == 0)
return 1;
- int *p = 0;
- *p = 0xDEADBEEF; // expected-warning {{null}}
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
return 0;
}
@@ -467,8 +458,7 @@ void rdar10202899_test1() {
void rdar10202899_test2() {
if (val == rdar10202899_ValTA)
return;
- int *p = 0;
- *p = 0xDEADBEEF;
+ clang_analyzer_warnIfReached(); // no-warning
}
void rdar10202899_test3() {
@@ -476,8 +466,7 @@ void rdar10202899_test3() {
case rdar10202899_ValTA: return;
default: ;
};
- int *p = 0;
- *p = 0xDEADBEEF;
+ clang_analyzer_warnIfReached(); // no-warning
}
// This used to crash the analyzer because of the unnamed bitfield.
@@ -489,13 +478,12 @@ void PR11249()
char f2[1];
char f3;
} V = { 1, {2}, 3 };
- int *p = 0;
if (V.f1 != 1)
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
if (V.f2[0] != 2)
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
if (V.f3 != 3)
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
}
// Handle doing a load from the memory associated with the code for
@@ -599,12 +587,10 @@ void rdar10924675(unsigned short x[], int index, int index2) {
void rdar11401827() {
int x = int();
if (!x) {
- int *p = 0;
- *p = 0xDEADBEEF; // expected-warning {{null pointer}}
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
else {
- int *p = 0;
- *p = 0xDEADBEEF;
+ clang_analyzer_warnIfReached(); // no-warning
}
}
@@ -701,8 +687,7 @@ const Rdar12755044_foo *radar12755044() {
void rdar12759044() {
int flag = 512;
if (!(flag & 512)) {
- int *p = 0;
- *p = 0xDEADBEEF; // no-warning
+ clang_analyzer_warnIfReached(); // no-warning
}
}
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
index b302860a2f97..01cad1549cda 100644
--- a/test/Analysis/misc-ps.c
+++ b/test/Analysis/misc-ps.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
int size_rdar9373039 = 1;
int foo_rdar9373039(const char *);
@@ -175,3 +177,17 @@ void sinkAfterRegularNode(struct PR15684 *context) {
context->callback(uninitialized); // expected-warning {{uninitialized}}
}
+
+// PR16131: C permits variables to be declared extern void.
+static void PR16131(int x) {
+ extern void v;
+
+ int *ip = (int *)&v;
+ char *cp = (char *)&v;
+ clang_analyzer_eval(ip == cp); // expected-warning{{TRUE}}
+ // expected-warning@-1 {{comparison of distinct pointer types}}
+
+ *ip = 42;
+ clang_analyzer_eval(*ip == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(*(int *)&v == 42); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/new-with-exceptions.cpp b/test/Analysis/new-with-exceptions.cpp
index d909f1fb8b6b..84d77c22302c 100644
--- a/test/Analysis/new-with-exceptions.cpp
+++ b/test/Analysis/new-with-exceptions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify -DEXCEPTIONS %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
void clang_analyzer_eval(bool);
@@ -32,33 +32,15 @@ void testNew() {
clang_analyzer_eval(new NoThrow); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(new NoExcept); // expected-warning{{UNKNOWN}}
- clang_analyzer_eval(new DefaultThrow);
- clang_analyzer_eval(new ExplicitThrow);
-#ifdef EXCEPTIONS
- // expected-warning@-3 {{TRUE}}
- // expected-warning@-3 {{TRUE}}
-#else
- // expected-warning@-6 {{UNKNOWN}}
- // expected-warning@-6 {{UNKNOWN}}
-#endif
+ clang_analyzer_eval(new DefaultThrow); // expected-warning{{TRUE}}
+ clang_analyzer_eval(new ExplicitThrow); // expected-warning{{TRUE}}
}
void testNewArray() {
- clang_analyzer_eval(new NoThrow[2]);
- clang_analyzer_eval(new NoExcept[2]);
- clang_analyzer_eval(new DefaultThrow[2]);
- clang_analyzer_eval(new ExplicitThrow[2]);
-#ifdef EXCEPTIONS
- // expected-warning@-5 {{TRUE}}
- // expected-warning@-5 {{TRUE}}
- // expected-warning@-5 {{TRUE}}
- // expected-warning@-5 {{TRUE}}
-#else
- // expected-warning@-10 {{UNKNOWN}}
- // expected-warning@-10 {{UNKNOWN}}
- // expected-warning@-10 {{UNKNOWN}}
- // expected-warning@-10 {{UNKNOWN}}
-#endif
+ clang_analyzer_eval(new NoThrow[2]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(new NoExcept[2]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(new DefaultThrow[2]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(new ExplicitThrow[2]); // expected-warning{{TRUE}}
}
extern void *operator new[](size_t, int) noexcept;
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index 8d3eee9baa6a..105a973ccc92 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -170,6 +170,16 @@ void testUsingThisAfterDelete() {
c->f(0); // no-warning
}
+void testAggregateNew() {
+ struct Point { int x, y; };
+ new Point{1, 2}; // no crash
+
+ Point p;
+ new (&p) Point{1, 2}; // no crash
+ clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}
+}
+
//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------
@@ -196,3 +206,148 @@ int testNoInitializationPlacement() {
}
return 1;
}
+
+// Test modelling destructor call on call to delete
+class IntPair{
+public:
+ int x;
+ int y;
+ IntPair() {};
+ ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}
+};
+
+void testCallToDestructor() {
+ IntPair *b = new IntPair();
+ b->x = 1;
+ b->y = 0;
+ delete b; // This results in divide by zero in destructor
+}
+
+// Test Deleting a value that's passed as an argument.
+class DerefClass{
+public:
+ int *x;
+ DerefClass() {};
+ ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}
+};
+
+void testDestCall(DerefClass *arg) {
+ delete arg;
+}
+
+void test_delete_dtor_Arg() {
+ DerefClass *pair = new DerefClass();
+ pair->x = 0;
+ testDestCall(pair);
+}
+
+//Deleting the address of a local variable, null pointer
+void abort(void) __attribute__((noreturn));
+
+class NoReturnDtor {
+public:
+ NoReturnDtor() {}
+ ~NoReturnDtor() {abort();}
+};
+
+void test_delete_dtor_LocalVar() {
+ NoReturnDtor test;
+ delete &test; // no warn or crash
+}
+
+class DerivedNoReturn:public NoReturnDtor {
+public:
+ DerivedNoReturn() {};
+ ~DerivedNoReturn() {};
+};
+
+void testNullDtorDerived() {
+ DerivedNoReturn *p = new DerivedNoReturn();
+ delete p; // Calls the base destructor which aborts, checked below
+ clang_analyzer_eval(true); // no warn
+}
+
+//Deleting a non class pointer should not crash/warn
+void test_var_delete() {
+ int *v = new int;
+ delete v; // no crash/warn
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+void testDeleteNull() {
+ NoReturnDtor *foo = 0;
+ delete foo; // should not call destructor, checked below
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+void testNullAssigneddtor() {
+ NoReturnDtor *p = 0;
+ NoReturnDtor *s = p;
+ delete s; // should not call destructor, checked below
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+void deleteArg(NoReturnDtor *test) {
+ delete test;
+}
+
+void testNulldtorArg() {
+ NoReturnDtor *p = 0;
+ deleteArg(p);
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+void testDeleteUnknown(NoReturnDtor *foo) {
+ delete foo; // should assume non-null and call noreturn destructor
+ clang_analyzer_eval(true); // no-warning
+}
+
+void testArrayNull() {
+ NoReturnDtor *fooArray = 0;
+ delete[] fooArray; // should not call destructor, checked below
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+void testArrayDestr() {
+ NoReturnDtor *p = new NoReturnDtor[2];
+ delete[] p; // Calls the base destructor which aborts, checked below
+ //TODO: clang_analyzer_eval should not be called
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+}
+
+// Invalidate Region even in case of default destructor
+class InvalidateDestTest {
+public:
+ int x;
+ int *y;
+ ~InvalidateDestTest();
+};
+
+int test_member_invalidation() {
+
+ //test invalidation of member variable
+ InvalidateDestTest *test = new InvalidateDestTest();
+ test->x = 5;
+ int *k = &(test->x);
+ clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}}
+ delete test;
+ clang_analyzer_eval(*k == 5); // expected-warning{{UNKNOWN}}
+
+ //test invalidation of member pointer
+ int localVar = 5;
+ test = new InvalidateDestTest();
+ test->y = &localVar;
+ delete test;
+ clang_analyzer_eval(localVar == 5); // expected-warning{{UNKNOWN}}
+
+ // Test aray elements are invalidated.
+ int Var1 = 5;
+ int Var2 = 5;
+ InvalidateDestTest *a = new InvalidateDestTest[2];
+ a[0].y = &Var1;
+ a[1].y = &Var2;
+ delete[] a;
+ clang_analyzer_eval(Var1 == 5); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(Var2 == 5); // expected-warning{{UNKNOWN}}
+ return 0;
+}
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index 86e8911f4659..43a527be1907 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,alpha.core -analyzer-constraints=range -analyzer-store=region -Wno-objc-root-class %s > %t.1 2>&1
-// RUN: FileCheck -input-file=%t.1 -check-prefix=darwin8 %s
+// RUN: FileCheck -input-file=%t.1 -check-prefix=CHECK-darwin8 %s
// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-constraints=range -analyzer-store=region -Wno-objc-root-class %s > %t.2 2>&1
-// RUN: FileCheck -input-file=%t.2 -check-prefix=darwin9 %s
+// RUN: FileCheck -input-file=%t.2 -check-prefix=CHECK-darwin9 %s
// RUN: %clang_cc1 -triple thumbv6-apple-ios4.0 -analyze -analyzer-checker=core,alpha.core -analyzer-constraints=range -analyzer-store=region -Wno-objc-root-class %s > %t.3 2>&1
-// RUN: FileCheck -input-file=%t.3 -check-prefix=darwin9 %s
+// RUN: FileCheck -input-file=%t.3 -check-prefix=CHECK-darwin9 %s
@interface MyClass {}
- (void *)voidPtrM;
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
index e22d520f8884..605769483619 100644
--- a/test/Analysis/null-deref-path-notes.m
+++ b/test/Analysis/null-deref-path-notes.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=text -fblocks -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=plist-multi-file -fblocks -Wno-objc-root-class %s -o %t
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false -fblocks -Wno-objc-root-class %s -o %t
// RUN: FileCheck --input-file=%t %s
@interface Root {
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index 050c3f8dc56a..56151dc6b650 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -81,3 +81,9 @@ int materializeTempExpr() {
const S &s = S(*n); // expected-warning{{Dereference of null pointer}}
return s.a;
}
+
+typedef decltype(nullptr) nullptr_t;
+void testMaterializeTemporaryExprWithNullPtr() {
+ // Create MaterializeTemporaryExpr with a nullptr inside.
+ const nullptr_t &r = nullptr;
+}
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
index e6c6ab546132..ba590d614e8d 100644
--- a/test/Analysis/objc-arc.m
+++ b/test/Analysis/objc-arc.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist %s
+// RUN: FileCheck --input-file=%t.plist %s
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@@ -218,3 +219,1874 @@ void rdar11059275_negative() {
(void) o;
}
+__attribute__((ns_returns_retained)) id rdar14061675_helper() {
+ return [[NSObject alloc] init];
+}
+
+id rdar14061675() {
+ // ARC produces an implicit cast here. We need to make sure the combination
+ // of that and the inlined call don't produce a spurious edge cycle.
+ id result = rdar14061675_helper();
+ *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}}
+ return result;
+}
+
+// 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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</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>53</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>53</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</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>53</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>53</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>54</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>54</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>54</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>54</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>54</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>54</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>54</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>54</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>54</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_working</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>54</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>93</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>93</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>94</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>94</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>94</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>94</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>94</integer>
+// CHECK-NEXT: <key>col</key><integer>37</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>Call to function &apos;CFDateCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFDateCreate&apos; returns a Core Foundation object with a +1 retain count</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>94</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>94</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>95</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>95</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>95</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>95</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>96</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>96</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: </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>96</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;date&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;date&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;date&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_cf_leak</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>96</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: <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>119</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>119</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>119</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>119</integer>
+// CHECK-NEXT: <key>col</key><integer>25</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>Value stored to &apos;x&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;x&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;x&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar9424882</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>119</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>139</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>139</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>139</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>col</key><integer>53</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>Value stored to &apos;obj1&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;obj1&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;obj1&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>139</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</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>144</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>144</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>45</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>Value stored to &apos;obj4&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;obj4&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;obj4&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>145</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>145</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>44</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>Value stored to &apos;obj5&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;obj5&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;obj5&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</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>146</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>146</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>48</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>Value stored to &apos;obj6&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;obj6&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;obj6&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</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>139</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>139</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</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>145</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>145</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>145</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>145</integer>
+// CHECK-NEXT: <key>col</key><integer>44</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>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</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>145</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>145</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</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>146</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>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>146</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>146</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>46</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>48</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>Object leaked: object allocated and stored into &apos;obj5&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;obj5&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;obj5&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>139</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>139</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</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>146</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>146</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>146</integer>
+// CHECK-NEXT: <key>col</key><integer>48</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>Call to function &apos;CFCreateString&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFCreateString&apos; returns a Core Foundation object with a +1 retain count</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>146</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>146</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>147</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>147</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: </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>147</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;obj6&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;obj6&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;obj6&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>from_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>147</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: <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>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>64</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>Value stored to &apos;cf1&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;cf1&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;cf1&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>to_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>151</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>151</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</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>151</integer>
+// CHECK-NEXT: <key>col</key><integer>67</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>Value stored to &apos;cf2&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;cf2&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;cf2&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>to_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>152</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>152</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>55</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>Value stored to &apos;cf3&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;cf3&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;cf3&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>to_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>153</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>153</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</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>153</integer>
+// CHECK-NEXT: <key>col</key><integer>58</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>Value stored to &apos;cf4&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;cf4&apos; during its initialization is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;cf4&apos; during its initialization is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>to_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>15</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>164</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>164</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>165</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>165</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>165</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>165</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>37</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>Call to function &apos;CFDateCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFDateCreate&apos; returns a Core Foundation object with a +1 retain count</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>165</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>165</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</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>166</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>166</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>166</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>166</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>Object leaked: object allocated and stored into &apos;date&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;date&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;date&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_objc_unretainedObject</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</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>178</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>178</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>181</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>181</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>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>181</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>181</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>185</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>185</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>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>185</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>185</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>189</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>189</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>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>189</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>189</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>193</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>193</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>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>193</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>193</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>196</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>196</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>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>196</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>196</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>200</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>200</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>200</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFCreateString&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFCreateString&apos; returns a Core Foundation object with a +1 retain count</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>200</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>202</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>202</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: </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>202</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><string>24</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</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: <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>214</integer>
+// CHECK-NEXT: <key>col</key><integer>17</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>214</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>col</key><integer>39</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>Method returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +0 retain count</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>214</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>214</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>215</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>215</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>215</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>215</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>215</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
+// CHECK-NEXT: <key>col</key><integer>20</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>Reference count incremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</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>215</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>215</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</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>216</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: </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>216</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;o&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;o&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;o&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar11059275_positive</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>216</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: <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>229</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>229</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</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>230</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>230</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>230</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>230</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>230</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>230</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>230</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>230</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>Dereference of null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar14061675</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>230</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: </array>
diff --git a/test/Analysis/objc-for.m b/test/Analysis/objc-for.m
index ef149c4b14aa..2f14b8ad1aae 100644
--- a/test/Analysis/objc-for.m
+++ b/test/Analysis/objc-for.m
@@ -4,8 +4,10 @@ void clang_analyzer_eval(int);
#define nil ((id)0)
+typedef unsigned long NSUInteger;
@protocol NSFastEnumeration
- (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count;
+- (void)protocolMethod;
@end
@interface NSObject
@@ -16,21 +18,37 @@ void clang_analyzer_eval(int);
@end
@interface NSArray : NSObject <NSFastEnumeration>
+- (NSUInteger)count;
- (NSEnumerator *)objectEnumerator;
@end
@interface NSDictionary : NSObject <NSFastEnumeration>
+- (NSUInteger)count;
+- (id)objectForKey:(id)key;
+@end
+
+@interface NSDictionary (SomeCategory)
+- (void)categoryMethodOnNSDictionary;
@end
@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)obj forKey:(id)key;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)addObject:(id)obj;
@end
@interface NSSet : NSObject <NSFastEnumeration>
+- (NSUInteger)count;
@end
@interface NSPointerArray : NSObject <NSFastEnumeration>
@end
+@interface NSString : NSObject
+@end
+
void test() {
id x;
for (x in [NSArray testObject])
@@ -68,3 +86,241 @@ void testNonNil(id a, id b) {
clang_analyzer_eval(b != nil); // expected-warning{{FALSE}}
}
+void collectionIsEmpty(NSMutableDictionary *D){
+ if ([D count] == 0) { // Count is zero.
+ NSString *s = 0;
+ for (NSString *key in D) {
+ s = key; // Loop is never entered.
+ }
+ clang_analyzer_eval(s == 0); //expected-warning{{TRUE}}
+ }
+}
+
+void processCollection(NSMutableDictionary *D);
+void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){
+ if ([D count] == 0) { // Count is zero.
+ NSString *s = 0;
+ processCollection(D); // However, the collection has changed.
+ for (NSString *key in D) {
+ s = key; // Loop might be entered.
+ }
+ clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}}
+ }
+}
+
+int collectionIsEmptyNSSet(NSSet *S){
+ if ([S count] == 2) { // Count is non zero.
+ int tapCounts[2];
+ int i = 0;
+ for (NSString *elem in S) {
+ tapCounts[i]= 1; // Loop is entered.
+ i++;
+ }
+ return (tapCounts[0]); //no warning
+ }
+ return 0;
+}
+
+int collectionIsNotEmptyNSArray(NSArray *A) {
+ int count = [A count];
+ if (count > 0) {
+ int i;
+ int j;
+ for (NSString *a in A) {
+ i = 1;
+ j++;
+ }
+ clang_analyzer_eval(i == 1); // expected-warning {{TRUE}}
+ }
+ return 0;
+}
+
+void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) {
+ if (D.count > 0) {
+ int *x;
+ int i;
+ for (NSString *key in D) {
+ x = 0;
+ i++;
+ }
+ // Test that this is reachable.
+ int y = *x; // expected-warning {{Dereference of null pointer}}
+ y++;
+ }
+}
+
+void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) {
+ if (D.count > 0) {
+ int *x;
+ int i;
+ for (NSString *key in D) {
+ x = 0;
+ i++;
+ continue;
+ }
+ // Test that this is reachable.
+ int y = *x; // expected-warning {{Dereference of null pointer}}
+ y++;
+ }
+}
+
+int* getPtr();
+void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) {
+ if (D.count > 0) {
+ int *x;
+ int i;
+ for (NSString *key in D) {
+ x = 0;
+ break;
+ x = getPtr();
+ i++;
+ }
+ int y = *x; // expected-warning {{Dereference of null pointer}}
+ y++;
+ }
+}
+
+int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D,
+ int shouldUseCount) {
+ // Test with or without an initial count.
+ int count;
+ if (shouldUseCount)
+ count = [D count];
+
+ int i;
+ int j = 0;
+ for (NSString *key in D) {
+ i = 5;
+ j++;
+ }
+ for (NSString *key in D) {
+ return i; // no-warning
+ }
+ return 0;
+}
+
+int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D,
+ int shouldUseCount) {
+ int count;
+ if (shouldUseCount)
+ count = [D count];
+
+ int i = 8;
+ int j = 1;
+ for (NSString *key in D) {
+ i = 0;
+ j++;
+ }
+ for (NSString *key in D) {
+ i = 5;
+ j++;
+ }
+ return 5/i;
+}
+
+int consistencyCountThenLoop(NSArray *array) {
+ if ([array count] == 0)
+ return 0;
+
+ int x;
+ for (id y in array)
+ x = 0;
+ return x; // no-warning
+}
+
+int consistencyLoopThenCount(NSArray *array) {
+ int x;
+ for (id y in array)
+ x = 0;
+
+ if ([array count] == 0)
+ return 0;
+
+ return x; // no-warning
+}
+
+void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict,
+ NSMutableArray *other) {
+ if ([dict count])
+ return;
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // no-warning
+
+ (void)[dict objectForKey:@""];
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // no-warning
+
+ [dict categoryMethodOnNSDictionary];
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // no-warning
+
+ [dict setObject:@"" forKey:@""];
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // expected-warning{{FALSE}}
+
+ // Reset.
+ if ([dict count])
+ return;
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // no-warning
+
+ [other addObject:dict];
+
+ for (id key in dict)
+ clang_analyzer_eval(0); // expected-warning{{FALSE}}
+}
+
+void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array,
+ NSMutableArray *other) {
+ if ([array count])
+ return;
+
+ for (id key in array)
+ clang_analyzer_eval(0); // no-warning
+
+ (void)[array objectEnumerator];
+
+ for (id key in array)
+ clang_analyzer_eval(0); // no-warning
+
+ [array addObject:@""];
+
+ for (id key in array)
+ clang_analyzer_eval(0); // expected-warning{{FALSE}}
+
+ // Reset.
+ if ([array count])
+ return;
+
+ for (id key in array)
+ clang_analyzer_eval(0); // no-warning
+
+ [other addObject:array];
+
+ for (id key in array)
+ clang_analyzer_eval(0); // expected-warning{{FALSE}}
+}
+
+void protocolMethods(NSMutableArray *array) {
+ if ([array count])
+ return;
+
+ for (id key in array)
+ clang_analyzer_eval(0); // no-warning
+
+ NSArray *immutableArray = array;
+ [immutableArray protocolMethod];
+
+ for (id key in array)
+ clang_analyzer_eval(0); // no-warning
+
+ [array protocolMethod];
+
+ for (id key in array)
+ clang_analyzer_eval(0); // expected-warning{{FALSE}}
+}
diff --git a/test/Analysis/objc-properties.m b/test/Analysis/objc-properties.m
index 87ab7f716395..323f41af54ce 100644
--- a/test/Analysis/objc-properties.m
+++ b/test/Analysis/objc-properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignment -fobjc-default-synthesize-properties -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignment -verify -fblocks %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
index f44978656998..f1ecd548eb3e 100644
--- a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
+++ b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -fobjc-default-synthesize-properties -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -verify -fblocks %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
index 6919feaccfc7..cd66444f4010 100644
--- a/test/Analysis/objc_invalidation.m
+++ b/test/Analysis/objc_invalidation.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -fobjc-default-synthesize-properties -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s
extern void __assert_fail (__const char *__assertion, __const char *__file,
unsigned int __line, __const char *__function)
__attribute__ ((__noreturn__));
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index 7461d75f673b..4bd7c12fad32 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
struct X0 { };
@@ -85,3 +85,48 @@ namespace RValues {
clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}}
}
}
+
+namespace SynthesizedAssignment {
+ struct A {
+ int a;
+ A& operator=(A& other) { a = -other.a; return *this; }
+ A& operator=(A&& other) { a = other.a+1; return *this; }
+ };
+
+ struct B {
+ int x;
+ A a[3];
+ B& operator=(B&) = default;
+ B& operator=(B&&) = default;
+ };
+
+ // This used to produce a warning about the iteration variable in the
+ // synthesized assignment operator being undefined.
+ void testNoWarning() {
+ B v, u;
+ u = v;
+ }
+
+ void testNoWarningMove() {
+ B v, u;
+ u = static_cast<B &&>(v);
+ }
+
+ void testConsistency() {
+ B v, u;
+ v.a[1].a = 47;
+ v.a[2].a = 42;
+ u = v;
+ clang_analyzer_eval(u.a[1].a == -47); // expected-warning{{TRUE}}
+ clang_analyzer_eval(u.a[2].a == -42); // expected-warning{{TRUE}}
+ }
+
+ void testConsistencyMove() {
+ B v, u;
+ v.a[1].a = 47;
+ v.a[2].a = 42;
+ u = static_cast<B &&>(v);
+ clang_analyzer_eval(u.a[1].a == 48); // expected-warning{{TRUE}}
+ clang_analyzer_eval(u.a[2].a == 43); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index dd593c5f26c0..d89a23961903 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -154,3 +154,15 @@ void test_index_below_symboloc() {
buf[-1] = 0; // no-warning;
}
+void test_incomplete_struct() {
+ extern struct incomplete incomplete;
+ int *p = (int *)&incomplete;
+ p[1] = 42; // no-warning
+}
+
+void test_extern_void() {
+ extern void v;
+ int *p = (int *)&v;
+ p[1] = 42; // no-warning
+}
+
diff --git a/test/Analysis/plist-macros.cpp b/test/Analysis/plist-macros.cpp
new file mode 100644
index 000000000000..0e8518a6f59c
--- /dev/null
+++ b/test/Analysis/plist-macros.cpp
@@ -0,0 +1,1597 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-eagerly-assume -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-eagerly-assume -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=ture %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+#define mallocmemory int *x = (int*)malloc(12);
+void noteOnMacro(int y) {
+ y++;
+ y--;
+ mallocmemory
+ y++;
+ y++;
+ delete x; // expected-warning {{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void macroIsFirstInFunction(int y) {
+ mallocmemory
+ y++; // expected-warning {{Potential leak of memory pointed to by 'x'}}
+}
+
+#define checkmacro p==0
+void macroInExpressionAux(bool b);
+int macroInExpression(int *p, int y) {;
+ y++;
+ macroInExpressionAux(checkmacro);
+
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+#define noPathNoteMacro y+y
+int macroInExpressionNoNote(int *p, int y) {;
+ y++;
+ if (5 + noPathNoteMacro)
+ if (p)
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+#define macroWithArg(mp) mp==0
+int macroWithArgInExpression(int *p, int y) {;
+ y++;
+ if (macroWithArg(p))
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+#define multiNoteMacroWithError \
+ if (p) \
+ ;\
+ *p = 5;
+int useMultiNoteMacroWithError(int *p, int y) {;
+ y++;
+ multiNoteMacroWithError // expected-warning {{Dereference of null pointer}}
+
+ return *p;
+}
+
+#define multiNoteMacro \
+if (p) \
+ ;\
+if (y) \
+ ;
+int useMultiNote(int *p, int y) {;
+ y++;
+ multiNoteMacro
+
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+#define CALL_FN(a) null_deref(a)
+
+void null_deref(int *a) {
+ if (a)
+ return;
+ *a = 1; // expected-warning {{Dereference of null pointer}}
+}
+
+void test1() {
+ CALL_FN(0);
+}
+
+void test2(int *p) {
+ CALL_FN(p);
+}
+// 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>11</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>11</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>13</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>13</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>13</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>13</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>13</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>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</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>13</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>13</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: <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>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>16</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>16</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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory allocated by malloc() should be deallocated by free(), not &apos;delete&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory allocated by malloc() should be deallocated by free(), not &apos;delete&apos;</string>
+// 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>type</key><string>Bad deallocator</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>noteOnMacro</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>20</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>20</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>20</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>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</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>20</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>20</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>21</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>21</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>21</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Potential leak of memory pointed to by &apos;x&apos;</string>
+// 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>type</key><string>Memory leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>macroIsFirstInFunction</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>21</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>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>28</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>28</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>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>28</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>28</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>28</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>28</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is equal to null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is equal to null</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>28</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>33</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>28</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>28</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>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>28</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>28</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>30</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>30</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>30</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>30</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>30</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>30</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>30</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>30</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>30</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>macroInExpression</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</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>35</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>35</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>36</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>36</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>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>36</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>36</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>37</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>37</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>37</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>37</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>37</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>37</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>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</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>37</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>37</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</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>39</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>39</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>39</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>39</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>39</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>39</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>39</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>39</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>macroInExpressionNoNote</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</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>44</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>44</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>45</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>45</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>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>45</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>45</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>45</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>45</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>45</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>45</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>45</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>Assuming &apos;p&apos; is equal to null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is equal to null</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>45</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>45</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</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>47</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>47</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>47</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>47</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>47</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>47</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>47</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>47</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>macroWithArgInExpression</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</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>55</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>55</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>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>25</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>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>56</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</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>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>25</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>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>25</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>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>56</integer>
+// CHECK-NEXT: <key>col</key><integer>25</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>useMultiNoteMacroWithError</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</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>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>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>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>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>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</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>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>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>Assuming &apos;y&apos; is 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is 0</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>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>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>70</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>70</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>70</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>70</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>70</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>70</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>70</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>70</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>70</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>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>useMultiNote</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>70</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>82</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>82</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>82</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>Passing null pointer value via 1st parameter &apos;a&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;a&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>82</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>82</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>82</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>Calling &apos;null_deref&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;null_deref&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>75</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;test1&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test1&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>75</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>75</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</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>76</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>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>76</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>76</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</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>78</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>78</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>78</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>78</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>78</integer>
+// CHECK-NEXT: <key>col</key><integer>6</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>78</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>78</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>78</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>null_deref</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</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: </array>
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 93d0421d665e..ea5ace636373 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o %t %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -fblocks -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck --input-file %t %s
void test_null_init(void) {
@@ -925,12 +925,12 @@ void rdar8331641(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -946,12 +946,12 @@ void rdar8331641(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index 3dfd6be2e713..f2823a060560 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -Xanalyzer -analyzer-checker=osx.cocoa.RetainCount -o %t.plist
+// RUN: %clang --analyze %s -Xanalyzer -analyzer-checker=osx.cocoa.RetainCount -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void test_null_init(void) {
@@ -1062,12 +1062,12 @@ int testFoo(Foo *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -1083,12 +1083,12 @@ int testFoo(Foo *x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>36</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/pointer-to-member.cpp b/test/Analysis/pointer-to-member.cpp
index c9150e8ca594..37d04399b7b7 100644
--- a/test/Analysis/pointer-to-member.cpp
+++ b/test/Analysis/pointer-to-member.cpp
@@ -33,6 +33,7 @@ void testConditionalUse() {
void testComparison() {
clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
// FIXME: Should be TRUE.
clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 35faff4a1709..4a15bc24b906 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -280,3 +280,19 @@ void canonical_equal(int *lhs, int *rhs) {
// FIXME: Should be FALSE.
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
}
+
+void compare_element_region_and_base(int *p) {
+ int *q = p - 1;
+ clang_analyzer_eval(p == q); // expected-warning{{FALSE}}
+}
+
+struct Point {
+ int x;
+ int y;
+};
+void symbolicFieldRegion(struct Point *points, int i, int j) {
+ clang_analyzer_eval(&points[i].x == &points[j].x);// expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(&points[i].x == &points[i].y);// expected-warning{{FALSE}}
+ clang_analyzer_eval(&points[i].x < &points[i].y);// expected-warning{{TRUE}}
+}
+
diff --git a/test/Analysis/ptr-arith.cpp b/test/Analysis/ptr-arith.cpp
new file mode 100644
index 000000000000..5f0951857b13
--- /dev/null
+++ b/test/Analysis/ptr-arith.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// expected-no-diagnostics
+struct X {
+ int *p;
+ int zero;
+ void foo () {
+ reset(p - 1);
+ }
+ void reset(int *in) {
+ while (in != p) // Loop must be entered.
+ zero = 1;
+ }
+};
+
+int test (int *in) {
+ X littleX;
+ littleX.zero = 0;
+ littleX.p = in;
+ littleX.foo();
+ return 5/littleX.zero; // no-warning
+}
+
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index 7070709e57dd..e928710b387d 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -9,13 +9,13 @@ typedef struct _NSZone NSZone;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@interface NSObject <NSObject> {} @end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
-@class NSArray;
+@class NSArray; // expected-note {{receiver is instance of class declared here}}
@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; // expected-note{{forward declaration of class here}}
@interface FooBazController : NSObject {}
@end
typedef struct {} TazVersion;
@class TazNode;
-@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end
+@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end // expected-note {{receiver is instance of class declared here}}
@interface FooBaz : NSObject {}
@property (nonatomic) BugsBunnyType matchType;
@property (nonatomic, retain) NSArray *papyrus; @end
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index 1dabe7bc1a3d..bd5eaaa30909 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -75,6 +75,13 @@ namespace PR13440 {
int (&x)[1];
int *m() { return x; }
+
+ void testArrayToPointerDecayWithNonTypedValueRegion() {
+ int *p = x;
+ int *q = x;
+ clang_analyzer_eval(p[0] == q[0]); // expected-warning{{TRUE}}
+ }
+
};
void test() {
diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp
index 59e6a539a11f..cb7cbfd325d8 100644
--- a/test/Analysis/reinterpret-cast.cpp
+++ b/test/Analysis/reinterpret-cast.cpp
@@ -86,3 +86,20 @@ namespace PR15345 {
clang_analyzer_eval(p->x == 42); // expected-warning{{TRUE}}
};
}
+
+int trackpointer_std_addressof() {
+ int x;
+ int *p = (int*)&reinterpret_cast<const volatile char&>(x);
+ *p = 6;
+ return x; // no warning
+}
+
+void set_x1(int *&);
+void set_x2(void *&);
+int radar_13146953(void) {
+ int *x = 0, *y = 0;
+
+ set_x1(x);
+ set_x2((void *&)y);
+ return *x + *y; // no warning
+} \ No newline at end of file
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index f74d61fa9adc..40592f008b4b 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
/***
@@ -40,17 +40,17 @@ CFTypeRef CFGetSomething();
void creationViaCFCreate () {
- CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void makeCollectable () {
- CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1}}
NSMakeCollectable(leaked); // expected-note{{In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector}}
CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void retainReleaseIgnored () {
@@ -63,13 +63,13 @@ void retainReleaseIgnored () {
@implementation Foo (FundamentalRuleUnderGC)
- (id)getViolation {
- id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
- return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
+ id object = (id) CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
}
- (id)copyViolation {
- id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
- return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
+ id object = (id) CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
+ return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
}
@end
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index a3c681ae3750..4b16c714e902 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file %s -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t
// RUN: FileCheck --input-file=%t %s
/***
@@ -34,6 +34,7 @@ GC-specific notes should go in retain-release-path-notes-gc.m.
typedef struct CFType *CFTypeRef;
CFTypeRef CFRetain(CFTypeRef);
void CFRelease(CFTypeRef);
+CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)));
id NSMakeCollectable(CFTypeRef);
CFTypeRef CFMakeCollectable(CFTypeRef);
@@ -43,33 +44,33 @@ CFTypeRef CFGetSomething();
void creationViaAlloc () {
- id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ id leaked = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void creationViaCFCreate () {
- CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void acquisitionViaMethod (Foo *foo) {
- id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}}
+ id leaked = [foo methodWithValue]; // expected-note{{Method returns an Objective-C object with a +0 retain count}}
[leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
[leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
[leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void acquisitionViaProperty (Foo *foo) {
- id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}}
+ id leaked = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
[leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void acquisitionViaCFFunction () {
- CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
+ CFTypeRef leaked = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
void explicitDealloc () {
@@ -98,10 +99,10 @@ void autoreleaseUnowned (Foo *foo) {
}
void makeCollectableIgnored () {
- CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}}
NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}}
- return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
+ return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
CFTypeRef CFCopyRuleViolation () {
@@ -110,8 +111,8 @@ CFTypeRef CFCopyRuleViolation () {
}
CFTypeRef CFGetRuleViolation () {
- CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
- return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}}
+ CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}}
}
@implementation Foo (FundamentalMemoryManagementRules)
@@ -131,8 +132,8 @@ CFTypeRef CFGetRuleViolation () {
}
- (id)getViolation {
- id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
- return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
+ id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ return result; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
}
- (id)copyAutorelease {
@@ -228,12 +229,12 @@ static int Cond;
// expected-note@-3 {{Returning from 'initX'}}
// expected-note@-4 {{Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1}}
// initI is inlined because the allocation happens within initY
- id y = [[MyObj alloc] initY]; // expected-warning {{Potential leak of an object}}
+ id y = [[MyObj alloc] initY];
// expected-note@-1 {{Calling 'initY'}}
// expected-note@-2 {{Returning from 'initY'}}
// initZ is not inlined
- id z = [[MyObj alloc] initZ];
+ id z = [[MyObj alloc] initZ]; // expected-warning {{Potential leak of an object}}
// expected-note@-1 {{Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1}}
[x release];
@@ -241,6 +242,28 @@ static int Cond;
}
@end
+
+void CFOverAutorelease() {
+ CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ CFAutorelease(object); // expected-note{{Object autoreleased}}
+ CFAutorelease(object); // expected-note{{Object autoreleased}}
+ return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +1 retain count}}
+}
+
+void CFAutoreleaseUnowned() {
+ CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
+ CFAutorelease(object); // expected-note{{Object autoreleased}}
+ return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased but has a +0 retain count}}
+}
+
+void CFAutoreleaseUnownedMixed() {
+ CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
+ CFAutorelease(object); // expected-note{{Object autoreleased}}
+ [(id)object autorelease]; // expected-note{{Object autoreleased}}
+ return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +0 retain count}}
+}
+
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -254,12 +277,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>line</key><integer>47</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>46</integer>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -267,12 +290,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -284,7 +307,7 @@ static int Cond;
// 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>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -292,12 +315,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -317,12 +340,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>47</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -330,12 +353,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</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>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -347,7 +370,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -355,12 +378,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</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>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -381,7 +404,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>line</key><integer>48</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -397,12 +420,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// 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>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -410,12 +433,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</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>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -427,7 +450,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -435,12 +458,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</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>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -460,12 +483,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</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>51</integer>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -473,12 +496,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>53</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>line</key><integer>53</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -490,7 +513,7 @@ static int Cond;
// 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>line</key><integer>53</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -498,12 +521,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>53</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>line</key><integer>53</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -524,7 +547,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>53</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -540,12 +563,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>57</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>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -553,12 +576,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -570,7 +593,7 @@ static int Cond;
// 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>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -578,12 +601,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -603,12 +626,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</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>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -616,12 +639,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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>
@@ -633,7 +656,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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>
@@ -641,24 +664,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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>57</integer>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -678,12 +701,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// 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>
@@ -691,12 +714,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>59</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>line</key><integer>59</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -708,7 +731,7 @@ static int Cond;
// 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>line</key><integer>59</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -716,24 +739,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>59</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>line</key><integer>59</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>59</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>line</key><integer>59</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -753,12 +776,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>line</key><integer>59</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>line</key><integer>59</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -766,12 +789,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</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>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -783,7 +806,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -791,24 +814,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</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>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</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>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -828,12 +851,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</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>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -841,12 +864,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// 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>60</integer>
+// 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>
@@ -858,7 +881,7 @@ static int Cond;
// 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>line</key><integer>61</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -866,12 +889,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// 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>60</integer>
+// 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>
@@ -892,7 +915,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// 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>
@@ -908,12 +931,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</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>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -921,12 +944,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -938,7 +961,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -946,12 +969,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -971,12 +994,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -984,12 +1007,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</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>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1001,7 +1024,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1009,24 +1032,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</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>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</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>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1046,12 +1069,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</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>65</integer>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1059,12 +1082,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>66</integer>
+// 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>66</integer>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1076,7 +1099,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>66</integer>
+// 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>
@@ -1084,12 +1107,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>66</integer>
+// 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>66</integer>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1110,7 +1133,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>66</integer>
+// 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>
@@ -1126,12 +1149,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</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>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1139,12 +1162,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</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>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1156,7 +1179,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1164,12 +1187,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</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>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1189,12 +1212,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</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>70</integer>
+// CHECK-NEXT: <key>line</key><integer>71</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1202,12 +1225,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</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>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1219,7 +1242,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1227,24 +1250,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</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>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1264,12 +1287,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</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>71</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1277,12 +1300,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1294,7 +1317,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1302,12 +1325,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</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>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1328,7 +1351,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1344,12 +1367,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</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>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1357,12 +1380,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1374,7 +1397,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1382,12 +1405,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1407,12 +1430,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1420,12 +1443,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1437,7 +1460,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1445,24 +1468,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1482,12 +1505,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</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>77</integer>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1495,12 +1518,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1512,7 +1535,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1520,12 +1543,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</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>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1546,7 +1569,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1562,12 +1585,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</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>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1575,12 +1598,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1592,7 +1615,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1600,12 +1623,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1625,12 +1648,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1638,12 +1661,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</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>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1655,7 +1678,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1663,24 +1686,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</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>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</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>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1700,12 +1723,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</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>83</integer>
+// CHECK-NEXT: <key>line</key><integer>84</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1713,12 +1736,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</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>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1730,7 +1753,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1738,12 +1761,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</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>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1764,7 +1787,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>84</integer>
+// CHECK-NEXT: <key>line</key><integer>85</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1780,12 +1803,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</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>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1793,12 +1816,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1810,7 +1833,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1818,12 +1841,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1843,12 +1866,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>line</key><integer>89</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1856,12 +1879,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</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>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1873,7 +1896,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1881,24 +1904,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</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>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</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>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1918,12 +1941,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</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>89</integer>
+// CHECK-NEXT: <key>line</key><integer>90</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1931,12 +1954,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</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>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1948,7 +1971,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1956,24 +1979,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</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>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</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>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1993,12 +2016,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</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>90</integer>
+// CHECK-NEXT: <key>line</key><integer>91</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2006,12 +2029,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</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>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2023,7 +2046,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2031,12 +2054,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</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>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2057,7 +2080,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>91</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2073,12 +2096,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</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>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2086,12 +2109,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2103,7 +2126,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2111,12 +2134,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2136,12 +2159,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>95</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2149,12 +2172,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</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>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2166,7 +2189,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2174,24 +2197,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</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>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</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>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2211,12 +2234,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</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>96</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2224,12 +2247,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</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>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2241,7 +2264,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2249,12 +2272,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</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>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2275,7 +2298,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>97</integer>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2291,12 +2314,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</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>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2304,12 +2327,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</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>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2321,7 +2344,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2329,12 +2352,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</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>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2354,12 +2377,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</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>101</integer>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2367,12 +2390,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</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>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2384,7 +2407,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2392,24 +2415,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</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>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</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>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2429,12 +2452,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</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>102</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2442,12 +2465,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</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>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2459,7 +2482,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2467,24 +2490,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</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>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</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>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2504,12 +2527,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</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>103</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2517,12 +2540,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</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>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2534,7 +2557,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2542,12 +2565,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</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>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2568,7 +2591,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2584,12 +2607,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2597,12 +2620,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</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>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2614,7 +2637,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2622,12 +2645,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</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>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2647,12 +2670,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</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>108</integer>
+// CHECK-NEXT: <key>line</key><integer>109</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2660,12 +2683,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</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>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2677,7 +2700,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2685,24 +2708,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</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>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</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>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2718,7 +2741,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2726,12 +2749,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</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>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2752,7 +2775,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>109</integer>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2768,12 +2791,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2781,12 +2804,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2798,7 +2821,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2806,12 +2829,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2831,12 +2854,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</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>113</integer>
+// CHECK-NEXT: <key>line</key><integer>114</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2844,12 +2867,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</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>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2861,7 +2884,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2869,24 +2892,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</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>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</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>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2902,7 +2925,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2910,12 +2933,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</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>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2936,7 +2959,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>114</integer>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2952,12 +2975,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</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>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2965,12 +2988,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2982,7 +3005,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2990,12 +3013,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3015,12 +3038,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>119</integer>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3028,12 +3051,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</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>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3045,7 +3068,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3053,24 +3076,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</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>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</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>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3086,7 +3109,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3094,12 +3117,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</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>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3120,7 +3143,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3136,12 +3159,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</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>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3149,12 +3172,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3166,7 +3189,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3174,12 +3197,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3199,12 +3222,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>124</integer>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3212,12 +3235,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</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>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3229,7 +3252,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3237,24 +3260,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</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>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</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>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3270,7 +3293,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3278,12 +3301,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</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>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3304,7 +3327,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3320,12 +3343,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</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>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3333,12 +3356,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3350,7 +3373,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3358,12 +3381,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3383,12 +3406,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3396,12 +3419,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</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>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3413,7 +3436,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3421,24 +3444,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</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>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</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>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3454,7 +3477,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3462,12 +3485,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</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>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3488,7 +3511,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>line</key><integer>131</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3504,12 +3527,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</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>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3517,12 +3540,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3534,7 +3557,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3542,12 +3565,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3567,12 +3590,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3580,12 +3603,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</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>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3597,7 +3620,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3605,24 +3628,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</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>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</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>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3638,7 +3661,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3646,12 +3669,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</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>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3672,7 +3695,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3688,12 +3711,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</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>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3701,12 +3724,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3718,7 +3741,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3726,12 +3749,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3751,12 +3774,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>139</integer>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3764,12 +3787,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</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>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3781,7 +3804,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3789,24 +3812,24 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</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>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</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: <dict>
-// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</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>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3826,12 +3849,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</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>140</integer>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3839,12 +3862,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</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>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3856,7 +3879,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3864,12 +3887,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</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>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3890,7 +3913,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3906,12 +3929,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</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>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3919,12 +3942,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3936,7 +3959,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3944,12 +3967,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3969,12 +3992,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>169</integer>
+// CHECK-NEXT: <key>line</key><integer>170</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3982,12 +4005,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</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>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3999,7 +4022,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4007,12 +4030,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</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>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4033,7 +4056,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>170</integer>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4049,12 +4072,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</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>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4062,12 +4085,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4079,7 +4102,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4087,12 +4110,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4112,12 +4135,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>174</integer>
+// CHECK-NEXT: <key>line</key><integer>175</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4125,12 +4148,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</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>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4142,7 +4165,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4150,12 +4173,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</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>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4176,7 +4199,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>175</integer>
+// CHECK-NEXT: <key>line</key><integer>176</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4192,12 +4215,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</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>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4205,12 +4228,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4222,7 +4245,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4230,12 +4253,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4255,12 +4278,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>179</integer>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4268,12 +4291,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</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>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4285,7 +4308,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4293,12 +4316,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</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>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4319,7 +4342,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>line</key><integer>181</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4335,12 +4358,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</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>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4348,12 +4371,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4365,7 +4388,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4373,12 +4396,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4398,12 +4421,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>line</key><integer>185</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4411,12 +4434,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</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>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4428,7 +4451,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4436,12 +4459,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</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>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4462,7 +4485,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>185</integer>
+// CHECK-NEXT: <key>line</key><integer>186</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4478,12 +4501,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</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>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4491,12 +4514,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4508,7 +4531,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4516,12 +4539,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4541,12 +4564,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4554,12 +4577,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</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>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4571,7 +4594,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4579,12 +4602,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</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>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4605,7 +4628,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4621,12 +4644,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4634,12 +4657,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4651,7 +4674,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4659,12 +4682,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4684,12 +4707,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4697,12 +4720,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4714,7 +4737,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4722,12 +4745,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4743,7 +4766,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>line</key><integer>206</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4761,12 +4784,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>line</key><integer>206</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>205</integer>
+// CHECK-NEXT: <key>line</key><integer>206</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4774,12 +4797,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</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>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4795,12 +4818,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</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>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4808,12 +4831,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</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>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4825,7 +4848,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4833,12 +4856,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</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>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4858,12 +4881,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</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>206</integer>
+// CHECK-NEXT: <key>line</key><integer>207</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4871,12 +4894,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>208</integer>
+// CHECK-NEXT: <key>line</key><integer>209</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>208</integer>
+// CHECK-NEXT: <key>line</key><integer>209</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4888,7 +4911,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4896,12 +4919,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4921,12 +4944,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4934,12 +4957,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4951,7 +4974,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4959,12 +4982,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4985,7 +5008,7 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5001,12 +5024,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5014,12 +5037,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5035,12 +5058,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</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>225</integer>
+// CHECK-NEXT: <key>line</key><integer>226</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5048,12 +5071,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</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>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5065,7 +5088,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5073,12 +5096,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</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>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5094,7 +5117,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>213</integer>
+// CHECK-NEXT: <key>line</key><integer>214</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5112,12 +5135,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>213</integer>
+// CHECK-NEXT: <key>line</key><integer>214</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>213</integer>
+// CHECK-NEXT: <key>line</key><integer>214</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5125,12 +5148,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</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>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5146,12 +5169,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</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>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5159,12 +5182,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</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>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5176,7 +5199,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5184,12 +5207,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</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>214</integer>
+// CHECK-NEXT: <key>line</key><integer>215</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5205,7 +5228,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5213,12 +5236,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</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>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5238,12 +5261,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</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>231</integer>
+// CHECK-NEXT: <key>line</key><integer>232</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5251,12 +5274,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</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>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5272,12 +5295,12 @@ static int Cond;
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</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>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5285,12 +5308,12 @@ static int Cond;
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</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>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5302,7 +5325,7 @@ static int Cond;
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5310,12 +5333,12 @@ static int Cond;
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</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>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5336,9 +5359,813 @@ static int Cond;
// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>236</integer>
+// CHECK-NEXT: <key>line</key><integer>237</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>247</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>247</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>247</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>247</integer>
+// CHECK-NEXT: <key>col</key><integer>38</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>247</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>247</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>247</integer>
+// CHECK-NEXT: <key>col</key><integer>40</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>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</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>247</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>247</integer>
+// CHECK-NEXT: <key>col</key><integer>38</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>248</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>248</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>248</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>248</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>248</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>248</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>248</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>248</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>248</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>249</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>249</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>249</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>249</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>249</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>249</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>249</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>249</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>249</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>250</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>250</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>250</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>250</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>250</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>CFOverAutorelease</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>250</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>254</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>254</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>254</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>254</integer>
+// CHECK-NEXT: <key>col</key><integer>35</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>254</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>254</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>254</integer>
+// CHECK-NEXT: <key>col</key><integer>37</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>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</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>254</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>254</integer>
+// CHECK-NEXT: <key>col</key><integer>35</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>255</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>255</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>255</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>255</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>255</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>255</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>255</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>255</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>256</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>256</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>256</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>256</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>256</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object was autoreleased but has a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object was autoreleased but has a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>CFAutoreleaseUnowned</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>256</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>260</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>260</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>260</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>260</integer>
+// CHECK-NEXT: <key>col</key><integer>35</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>260</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>260</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>260</integer>
+// CHECK-NEXT: <key>col</key><integer>37</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>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</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>260</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>260</integer>
+// CHECK-NEXT: <key>col</key><integer>35</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>261</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>261</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>261</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>261</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>261</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>261</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>261</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>261</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>261</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>262</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>262</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>262</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>262</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>262</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: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>262</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>262</integer>
+// CHECK-NEXT: <key>col</key><integer>13</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>Object autoreleased</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object autoreleased</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>262</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>262</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>263</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>263</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>263</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>263</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>263</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>CFAutoreleaseUnownedMixed</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>263</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/retain-release.m b/test/Analysis/retain-release.m
index bb4a1d169d24..aafd94e97bdc 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -63,9 +63,12 @@ typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
extern const CFAllocatorRef kCFAllocatorDefault;
+
extern CFTypeRef CFRetain(CFTypeRef cf);
extern void CFRelease(CFTypeRef cf);
extern CFTypeRef CFMakeCollectable(CFTypeRef cf);
+extern CFTypeRef CFAutorelease(CFTypeRef CF_CONSUMED cf);
+
typedef struct {
}
CFArrayCallBacks;
@@ -2005,6 +2008,87 @@ static int Cond;
@end
//===----------------------------------------------------------------------===//
+// CFAutorelease
+//===----------------------------------------------------------------------===//
+
+CFTypeRef getAutoreleasedCFType() {
+ extern CFTypeRef CFCreateSomething();
+ return CFAutorelease(CFCreateSomething()); // no-warning
+}
+
+CFTypeRef getIncorrectlyAutoreleasedCFType() {
+ extern CFTypeRef CFGetSomething();
+ return CFAutorelease(CFGetSomething()); // expected-warning{{Object autoreleased too many times}}
+}
+
+CFTypeRef createIncorrectlyAutoreleasedCFType() {
+ extern CFTypeRef CFCreateSomething();
+ return CFAutorelease(CFCreateSomething()); // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+void useAfterAutorelease() {
+ extern CFTypeRef CFCreateSomething();
+ CFTypeRef obj = CFCreateSomething();
+ CFAutorelease(obj);
+
+ extern void useCF(CFTypeRef);
+ useCF(obj); // no-warning
+}
+
+void useAfterRelease() {
+ // Sanity check that the previous example would have warned with CFRelease.
+ extern CFTypeRef CFCreateSomething();
+ CFTypeRef obj = CFCreateSomething();
+ CFRelease(obj);
+
+ extern void useCF(CFTypeRef);
+ useCF(obj); // expected-warning{{Reference-counted object is used after it is released}}
+}
+
+void testAutoreleaseReturnsInput() {
+ extern CFTypeRef CFCreateSomething();
+ CFTypeRef obj = CFCreateSomething(); // expected-warning{{Potential leak of an object stored into 'obj'}}
+ CFTypeRef second = CFAutorelease(obj);
+ CFRetain(second);
+}
+
+CFTypeRef testAutoreleaseReturnsInputSilent() {
+ extern CFTypeRef CFCreateSomething();
+ CFTypeRef obj = CFCreateSomething();
+ CFTypeRef alias = CFAutorelease(obj);
+ CFRetain(alias);
+ CFRelease(obj);
+ return obj; // no-warning
+}
+
+void autoreleaseTypedObject() {
+ CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ CFAutorelease((CFTypeRef)arr); // no-warning
+}
+
+void autoreleaseReturningTypedObject() {
+ CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Potential leak of an object stored into 'arr'}}
+ CFArrayRef alias = (CFArrayRef)CFAutorelease((CFTypeRef)arr);
+ CFRetain(alias);
+}
+
+CFArrayRef autoreleaseReturningTypedObjectSilent() {
+ CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ CFArrayRef alias = (CFArrayRef)CFAutorelease((CFTypeRef)arr);
+ CFRetain(alias);
+ CFRelease(arr);
+ return alias; // no-warning
+}
+
+void autoreleaseObjC() {
+ id obj = [@1 retain];
+ CFAutorelease(obj); // no-warning
+
+ id anotherObj = @1;
+ CFAutorelease(anotherObj);
+} // expected-warning{{Object autoreleased too many times}}
+
+//===----------------------------------------------------------------------===//
// <rdar://problem/13783514> xpc_connection_set_finalizer_f
//===----------------------------------------------------------------------===//
@@ -2022,6 +2106,20 @@ void rdar13783514(xpc_connection_t connection) {
xpc_connection_set_finalizer_f(connection, releaseAfterXPC);
} // no-warning
+// Do not report leaks when object is cleaned up with __attribute__((cleanup ..)).
+inline static void cleanupFunction(void *tp) {
+ CFTypeRef x = *(CFTypeRef *)tp;
+ if (x) {
+ CFRelease(x);
+ }
+}
+#define ADDCLEANUP __attribute__((cleanup(cleanupFunction)))
+void foo() {
+ ADDCLEANUP CFStringRef myString;
+ myString = CFStringCreateWithCString(0, "hello world", kCFStringEncodingUTF8);
+ ADDCLEANUP CFStringRef myString2 =
+ CFStringCreateWithCString(0, "hello world", kCFStringEncodingUTF8);
+}
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index 1df8a408a697..4ffd9a0b4907 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -82,10 +82,11 @@ void test_setuid()
}
// <rdar://problem/6337100> CWE-338: Use of cryptographically weak prng
+typedef unsigned short *ushort_ptr_t; // Test that sugar doesn't confuse the warning.
int rand(void);
double drand48(void);
double erand48(unsigned short[3]);
-long jrand48(unsigned short[3]);
+long jrand48(ushort_ptr_t);
void lcong48(unsigned short[7]);
long lrand48(void);
long mrand48(void);
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index 5a4354f49ad2..d1fb88de5410 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -analyzer-config ipa=dynamic -fno-builtin %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -fno-builtin %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -analyzer-config ipa=dynamic -fno-builtin %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fno-builtin %s -verify
@class NSZone, NSCoder;
@protocol NSObject
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
index ce57fa7ac34e..2f725745a5ba 100644
--- a/test/Analysis/simple-stream-checks.c
+++ b/test/Analysis/simple-stream-checks.c
@@ -87,5 +87,5 @@ void testPassConstPointer() {
void testPassToSystemHeaderFunctionIndirectly() {
FileStruct fs;
fs.p = fopen("myfile.txt", "w");
- fakeSystemHeaderCall(&fs);
-} // expected-warning {{Opened file is never closed; potential resource leak}}
+ fakeSystemHeaderCall(&fs); // invalidates fs, making fs.p unreachable
+} // no-warning
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
index 65d757154c87..a39f9c7dc726 100644
--- a/test/Analysis/stack-addr-ps.cpp
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -20,6 +20,10 @@ const int& g3() {
return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
}
+void g4() {
+ static const int &x = 3; // no warning
+}
+
int get_value();
const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index 6cf52f7a557b..9fd3efb5c2d7 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -430,11 +430,12 @@ void strcat_unknown_src_length(char *src, int offset) {
// length for the "before" strlen, we won't be able to set one for "after".
void strcat_too_big(char *dst, char *src) {
+ // We assume this can never actually happen, so we don't get a warning.
if (strlen(dst) != (((size_t)0) - 2))
return;
if (strlen(src) != 2)
return;
- strcat(dst, src); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}}
+ strcat(dst, src);
}
@@ -653,11 +654,12 @@ void strncat_unknown_limit(float limit) {
}
void strncat_too_big(char *dst, char *src) {
+ // We assume this will never actually happen, so we don't get a warning.
if (strlen(dst) != (((size_t)0) - 2))
return;
if (strlen(src) != 2)
return;
- strncat(dst, src, 2); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}}
+ strncat(dst, src, 2);
}
void strncat_zero(char *src) {
diff --git a/test/Analysis/taint-tester.cpp b/test/Analysis/taint-tester.cpp
index f97eefb950e3..ca7b729f2691 100644
--- a/test/Analysis/taint-tester.cpp
+++ b/test/Analysis/taint-tester.cpp
@@ -6,7 +6,8 @@ typedef __typeof(sizeof(int)) size_t;
extern FILE *stdin;
typedef long ssize_t;
ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
-int printf(const char * __restrict, ...);
+int printf(const char * __restrict, ...);
+int snprintf(char *, size_t, const char *, ...);
void free(void *ptr);
struct GetLineTestStruct {
@@ -25,3 +26,10 @@ void getlineTest(void) {
}
free(line);
}
+
+class opaque;
+void testOpaqueClass(opaque *obj) {
+ char buf[20];
+ snprintf(buf, 20, "%p", obj); // don't crash trying to load *obj
+}
+
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 1ddccb704b13..ff68a876e910 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -108,6 +108,24 @@ TestCtorInits::TestCtorInits()
: a(int(A()) + int(B()))
, b() {}
+class NoReturn {
+public:
+ ~NoReturn() __attribute__((noreturn));
+ void f();
+};
+
+void test_noreturn1() {
+ int a;
+ NoReturn().f();
+ int b;
+}
+
+void test_noreturn2() {
+ int a;
+ NoReturn(), 47;
+ int b;
+}
+
// CHECK: [B1 (ENTRY)]
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
@@ -846,3 +864,36 @@ TestCtorInits::TestCtorInits()
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
+// CHECK: [B3 (ENTRY)]
+// CHECK: Succs (1): B2
+// CHECK: [B1]
+// CHECK: 1: int b;
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: int a;
+// CHECK: 2: NoReturn() (CXXConstructExpr, class NoReturn)
+// CHECK: 3: [B2.2] (BindTemporary)
+// CHECK: 4: [B2.3].f
+// CHECK: 5: [B2.4]()
+// CHECK: 6: ~NoReturn() (Temporary object destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B2
+
+// CHECK: [B3 (ENTRY)]
+// CHECK: Succs (1): B2
+// CHECK: [B1]
+// CHECK: 1: int b;
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: int a;
+// CHECK: 2: NoReturn() (CXXConstructExpr, class NoReturn)
+// CHECK: 3: [B2.2] (BindTemporary)
+// CHECK: 4: 47
+// CHECK: 5: ... , [B2.4]
+// CHECK: 6: ~NoReturn() (Temporary object destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B2
diff --git a/test/Analysis/templates.cpp b/test/Analysis/templates.cpp
index faa5c1a76209..131794a7c931 100644
--- a/test/Analysis/templates.cpp
+++ b/test/Analysis/templates.cpp
@@ -48,3 +48,25 @@ void testNonTypeTemplateInstantiation() {
#endif
}
+namespace rdar13954714 {
+ template <bool VALUE>
+ bool blockInTemplate() {
+ return (^() {
+ return VALUE;
+ })();
+ }
+
+ // force instantiation
+ template bool blockInTemplate<true>();
+
+ template <bool VALUE>
+ void blockWithStatic() {
+ (void)^() {
+ static int x;
+ return ++x;
+ };
+ }
+
+ // force instantiation
+ template void blockWithStatic<true>();
+}
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index efc0825470cd..6b49fcbddd41 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s
extern bool clang_analyzer_eval(bool);
@@ -109,3 +110,148 @@ namespace compound_literals {
}
}
+namespace destructors {
+ void testPR16664andPR18159Crash() {
+ struct Dtor {
+ ~Dtor();
+ };
+ extern bool coin();
+ extern bool check(const Dtor &);
+
+#ifndef TEMPORARY_DTORS
+ // FIXME: Don't crash here when tmp dtros are enabled.
+ // PR16664 and PR18159
+ if (coin() && (coin() || coin() || check(Dtor()))) {
+ Dtor();
+ }
+#endif
+ }
+
+#ifdef TEMPORARY_DTORS
+ struct NoReturnDtor {
+ ~NoReturnDtor() __attribute__((noreturn));
+ };
+
+ void noReturnTemp(int *x) {
+ if (! x) NoReturnDtor();
+ *x = 47; // no warning
+ }
+
+ void noReturnInline(int **x) {
+ NoReturnDtor();
+ }
+
+ void callNoReturn() {
+ int *x;
+ noReturnInline(&x);
+ *x = 47; // no warning
+ }
+
+ extern bool check(const NoReturnDtor &);
+
+ void testConsistencyIf(int i) {
+ if (i != 5)
+ return;
+ if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+
+ void testConsistencyTernary(int i) {
+ (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
+
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+
+ if (i != 5)
+ return;
+
+ (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
+
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+
+
+/*
+ // PR16664 and PR18159
+ FIXME: Don't crash here.
+ void testConsistencyNested(int i) {
+ extern bool compute(bool);
+
+ if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
+ clang_analyzer_eval(true); // expected TRUE
+
+ if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
+ clang_analyzer_eval(true); // expected TRUE
+
+ if (i != 5)
+ return;
+
+ if (compute(i == 5 &&
+ (i == 4 || compute(true) ||
+ compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
+ i != 4) {
+ clang_analyzer_eval(true); // expected TRUE
+ }
+
+ if (compute(i == 5 &&
+ (i == 4 || i == 4 ||
+ compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
+ i != 4) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }*/
+
+#endif // TEMPORARY_DTORS
+}
+
+void testStaticMaterializeTemporaryExpr() {
+ static const Trivial &ref = getTrivial();
+ clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
+
+ static const Trivial &directRef = Trivial(42);
+ clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
+
+#if __has_feature(cxx_thread_local)
+ thread_local static const Trivial &threadRef = getTrivial();
+ clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
+
+ thread_local static const Trivial &threadDirectRef = Trivial(42);
+ clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
+#endif
+}
+
+namespace PR16629 {
+ struct A {
+ explicit A(int* p_) : p(p_) {}
+ int* p;
+ };
+
+ extern void escape(const A*[]);
+ extern void check(int);
+
+ void callEscape(const A& a) {
+ const A* args[] = { &a };
+ escape(args);
+ }
+
+ void testNoWarning() {
+ int x;
+ callEscape(A(&x));
+ check(x); // Analyzer used to give a "x is uninitialized warning" here
+ }
+
+ void set(const A*a[]) {
+ *a[0]->p = 47;
+ }
+
+ void callSet(const A& a) {
+ const A* args[] = { &a };
+ set(args);
+ }
+
+ void testConsistency() {
+ int x;
+ callSet(A(&x));
+ clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/uninit-sometimes.cpp b/test/Analysis/uninit-sometimes.cpp
index 015b675d9b86..425d3048c4e0 100644
--- a/test/Analysis/uninit-sometimes.cpp
+++ b/test/Analysis/uninit-sometimes.cpp
@@ -145,13 +145,13 @@ int test_for_range_false(int k) {
int test_for_range_true(int k) {
int arr[3] = { 1, 2, 3 };
- int x;
- for (int &a : arr) { // no-warning
+ int x; // expected-note {{variable}}
+ for (int &a : arr) { // expected-warning {{variable 'x' is used uninitialized whenever 'for' loop is entered}}
goto label;
}
x = 0;
label:
- return x;
+ return x; // expected-note {{uninitialized use}}
}
@@ -356,14 +356,14 @@ int test_no_false_positive_2() {
}
-// FIXME: In this case, the variable is used uninitialized whenever the
-// function's entry block is reached. Produce a diagnostic saying that
-// the variable is uninitialized the first time it is used.
+
+
+
void test_null_pred_succ() {
- int x;
+ int x; // expected-note {{variable}} expected-warning {{used uninitialized whenever function 'test_null_pred_succ' is called}}
if (0)
foo: x = 0;
- if (x)
+ if (x) // expected-note {{use}}
goto foo;
}
@@ -385,3 +385,45 @@ int PR13360(bool b) {
// CHECK: fix-it:"{{.*}}":{376:3-380:10}:""
// CHECK: fix-it:"{{.*}}":{375:8-375:8}:" = 0"
+
+void test_jump_init() {
+goto later;
+ int x; // expected-note {{variable}} expected-warning {{used uninitialized whenever function 'test_jump_init'}}
+later:
+ while (x) x = 0; // expected-note {{use}}
+}
+
+void PR16054() {
+ int x; // expected-note {{variable}} expected-warning {{used uninitialized whenever function 'PR16054}}
+ while (x != 0) { // expected-note {{use}}
+ (void)&x;
+ }
+}
+
+void test_loop_uninit() {
+ for (int n = 0; n < 10; ++n) {
+ int k; // expected-warning {{variable 'k' is used uninitialized whenever its declaration is reached}} expected-note {{variable}}
+ do {
+ k = k + 1; // expected-note {{use}}
+ } while (k != 5);
+ }
+}
+
+// FIXME: We should warn here, because the variable is used uninitialized
+// the first time we encounter the use.
+void test_loop_with_assignment() {
+ double d;
+ for (int n = 0; n < 10; ++n) {
+ d = d + n;
+ }
+}
+
+// FIXME: We should warn here, because the variable is used uninitialized
+// the first time we encounter the use.
+void test_loop_with_ref_bind() {
+ double d;
+ for (int n = 0; n < 10; ++n) {
+ d += n;
+ const double &r = d;
+ }
+}
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 614ce2fc3354..a4aa5a114aeb 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -76,3 +76,18 @@ void PR10163 (void) {
test_PR10163(x[1]); // expected-warning{{uninitialized value}}
}
+struct MyStr {
+ int x;
+ int y;
+};
+void swap(struct MyStr *To, struct MyStr *From) {
+ // This is not really a swap but close enough for our test.
+ To->x = From->x;
+ To->y = From->y; // no warning
+}
+int test_undefined_member_assignment_in_swap(struct MyStr *s2) {
+ struct MyStr s1;
+ s1.x = 5;
+ swap(s2, &s1);
+ return s2->y; // expected-warning{{Undefined or garbage value returned to caller}}
+}
diff --git a/test/Analysis/unions.cpp b/test/Analysis/unions.cpp
index 2bffe78b41c2..f363ab81ae72 100644
--- a/test/Analysis/unions.cpp
+++ b/test/Analysis/unions.cpp
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core %s -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -verify
+
+extern void clang_analyzer_eval(bool);
+extern "C" char *strdup(const char *s);
namespace PR14054_reduced {
struct Definition;
@@ -49,3 +51,58 @@ namespace PR14054_original {
x = pn->pn_u.name.lexdef->pn_u.name.lexdef;
}
}
+
+namespace PR17596 {
+ union IntOrString {
+ int i;
+ char *s;
+ };
+
+ extern void process(IntOrString);
+
+ void test() {
+ IntOrString uu;
+ uu.s = strdup("");
+ process(uu);
+ }
+
+ void testPositive() {
+ IntOrString uu;
+ uu.s = strdup("");
+ } // expected-warning{{leak}}
+
+ void testCopy() {
+ IntOrString uu;
+ uu.i = 4;
+ clang_analyzer_eval(uu.i == 4); // expected-warning{{TRUE}}
+
+ IntOrString vv;
+ vv.i = 5;
+ uu = vv;
+ // FIXME: Should be true.
+ clang_analyzer_eval(uu.i == 5); // expected-warning{{UNKNOWN}}
+ }
+
+ void testInvalidation() {
+ IntOrString uu;
+ uu.s = strdup("");
+
+ IntOrString vv;
+ char str[] = "abc";
+ vv.s = str;
+
+ // FIXME: This is a leak of uu.s.
+ uu = vv;
+ }
+
+ void testIndirectInvalidation() {
+ IntOrString uu;
+ char str[] = "abc";
+ uu.s = str;
+
+ clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{TRUE}}
+
+ process(uu);
+ clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{UNKNOWN}}
+ }
+}
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index 46c10136ede2..dad03fac70b8 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,6 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -analyzer-config path-diagnostics-alternate=false -fblocks -verify -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
-
+// RUN: mkdir -p %t.dir
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API,osx.API -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
+// RUN: rm -fR %t.dir
struct _opaque_pthread_once_t {
long __sig;
char __opaque[8];
@@ -16,7 +18,6 @@ void *realloc(void *, size_t);
void *reallocf(void *, size_t);
void *alloca(size_t);
void *valloc(size_t);
-
typedef union {
struct _os_object_s *_os_obj;
struct dispatch_object_s *_do;
@@ -32,7 +33,6 @@ typedef union {
struct dispatch_operation_s *_doperation;
struct dispatch_disk_s *_ddisk;
} dispatch_object_t __attribute__((__transparent_union__));
-
typedef void (^dispatch_block_t)(void);
typedef long dispatch_once_t;
typedef struct dispatch_queue_s *dispatch_queue_t;
@@ -1418,6 +1418,40 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>190</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>190</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>190</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>190</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1492,24 +1526,25 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</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;test_dispatch_sync&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;test_dispatch_sync&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>40</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>190</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>190</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>194</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: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
@@ -1974,24 +2009,25 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</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>2</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;_dispatch_once&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;_dispatch_once&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>39</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>177</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>177</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>177</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>2</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index 61a4fd490e94..08019d9cbe31 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -139,3 +139,22 @@ void test11(enum foobar fb) {
error(); // expected-warning {{never executed}}
}
}
+
+void inlined(int condition) {
+ if (condition) {
+ foo(5); // no-warning
+ } else {
+ foo(6);
+ }
+}
+
+void testInlined() {
+ extern int coin();
+ int cond = coin();
+ if (!cond) {
+ inlined(0);
+ if (cond) {
+ foo(5); // expected-warning {{never executed}}
+ }
+ }
+}
diff --git a/test/Analysis/weak-functions.c b/test/Analysis/weak-functions.c
new file mode 100644
index 000000000000..96e3b44d03b8
--- /dev/null
+++ b/test/Analysis/weak-functions.c
@@ -0,0 +1,117 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection,unix.Malloc,unix.cstring,alpha.unix.cstring,unix.API,osx.API,osx.cocoa.RetainCount -Wno-null-dereference -analyzer-store=region -fblocks -verify %s
+#define NULL 0
+void clang_analyzer_eval(int);
+void myFunc();
+void myWeakFunc() __attribute__((weak_import));
+
+void testWeakFuncIsNull()
+{
+ clang_analyzer_eval(myFunc == NULL); // expected-warning{{FALSE}}
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}}
+ if (myWeakFunc == NULL) {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}}
+ } else {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}}
+ }
+}
+
+void testWeakFuncIsNot()
+{
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}}
+ if (!myWeakFunc) {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}}
+ } else {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}}
+ }
+}
+
+void testWeakFuncIsTrue()
+{
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}}
+ if (myWeakFunc) {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}}
+ } else {
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}}
+ }
+}
+
+//===----------------------------------------------------------------------===
+// func.c
+//===----------------------------------------------------------------------===
+void f(void) __attribute__((weak_import));
+void g(void (*fp)(void)) __attribute__((weak_import));
+
+void f(void) {
+ void (*p)(void);
+ p = f;
+ p = &f;
+ p();
+ (*p)();
+}
+
+void g(void (*fp)(void));
+
+void f2() {
+ g(f);
+}
+
+void f3(void (*f)(void), void (*g)(void)) {
+ clang_analyzer_eval(!f); // expected-warning{{UNKNOWN}}
+ f();
+ clang_analyzer_eval(!f); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(!g); // expected-warning{{UNKNOWN}}
+ (*g)();
+ clang_analyzer_eval(!g); // expected-warning{{FALSE}}
+}
+
+//===----------------------------------------------------------------------===
+// free.c
+//===----------------------------------------------------------------------===
+void free(void *) __attribute__((weak_import));
+
+void t10 () {
+ free((void*)&t10); // expected-warning {{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}}
+}
+
+//===----------------------------------------------------------------------===
+// string.c : strnlen()
+//===----------------------------------------------------------------------===
+typedef typeof(sizeof(int)) size_t;
+size_t strlen(const char *s) __attribute__((weak_import));
+
+size_t strlen_fn() {
+ return strlen((char*)&strlen_fn); // expected-warning{{Argument to string length function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+}
+
+//===----------------------------------------------------------------------===
+// unix-fns.c : dispatch_once
+//===----------------------------------------------------------------------===
+typedef void (^dispatch_block_t)(void);
+typedef long dispatch_once_t;
+void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) __attribute__((weak_import));
+
+void test_dispatch_once() {
+ dispatch_once_t pred = 0;
+ do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // expected-warning{{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}}
+}
+void test_dispatch_once_neg() {
+ static dispatch_once_t pred = 0;
+ do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// retain-release-path-notes.m
+//===----------------------------------------------------------------------===
+typedef struct CFType *CFTypeRef;
+CFTypeRef CFCreateSomething() __attribute__((weak_import));
+CFTypeRef CFGetSomething() __attribute__((weak_import));
+
+CFTypeRef CFCopyRuleViolation () {
+ CFTypeRef object = CFGetSomething();
+ return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+CFTypeRef CFGetRuleViolation () {
+ CFTypeRef object = CFCreateSomething(); // expected-warning{{Potential leak of an object stored into 'object'}}
+ return object; }
diff --git a/test/CXX/basic/basic.link/p6.cpp b/test/CXX/basic/basic.link/p6.cpp
index 8faec76fb3f1..ac6dc2f1f1a3 100644
--- a/test/CXX/basic/basic.link/p6.cpp
+++ b/test/CXX/basic/basic.link/p6.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s
+
+// expected-no-diagnostics
// C++11 [basic.link]p6:
// The name of a function declared in block scope and the name
@@ -9,35 +11,34 @@
// block scope declaration declares that same entity and
// receives the linkage of the previous declaration.
-// rdar://13535367
-namespace test0 {
- extern "C" int test0_array[];
- void declare() { extern int test0_array[100]; }
- extern "C" int test0_array[];
- int value = sizeof(test0_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
-}
-
-namespace test1 {
- extern "C" int test1_array[];
- void test() {
- { extern int test1_array[100]; }
- extern int test1_array[];
- int x = sizeof(test1_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+extern int same_entity;
+constexpr int *get1() {
+ int same_entity = 0; // not the same entity
+ {
+ extern int same_entity;
+ return &same_entity;
}
}
+static_assert(get1() == &same_entity, "failed to find previous decl");
-namespace test2 {
- void declare() { extern int test2_array[100]; }
- extern int test2_array[];
- int value = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+static int same_entity_2[3];
+constexpr int *get2() {
+ // This is a redeclaration of the same entity, even though it doesn't
+ // inherit the type of the prior declaration.
+ extern int same_entity_2[];
+ return same_entity_2;
}
+static_assert(get2() == same_entity_2, "failed to find previous decl");
-namespace test3 {
- void test() {
- { extern int test3_array[100]; }
- extern int test3_array[];
- int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+static int different_entities;
+constexpr int *get3() {
+ int different_entities = 0;
+ {
+ // FIXME: This is not a redeclaration of the prior entity, because
+ // it is not visible here. Under DR426, this is ill-formed, and without
+ // it, the static_assert below should fail.
+ extern int different_entities;
+ return &different_entities;
}
}
-
-
+static_assert(get3() == &different_entities, "failed to find previous decl");
diff --git a/test/CXX/basic/basic.link/p7.cpp b/test/CXX/basic/basic.link/p7.cpp
new file mode 100644
index 000000000000..9a85eacdda4f
--- /dev/null
+++ b/test/CXX/basic/basic.link/p7.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -std=c++1y %s
+
+// Example from the standard.
+namespace X {
+ void p() {
+ q(); // expected-error {{undeclared}}
+ extern void q();
+ }
+ void middle() {
+ q(); // expected-error {{undeclared}}
+ }
+ void q() { /*...*/ }
+ void bottom() {
+ q();
+ }
+}
+int q();
+
+namespace Test1 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(); // expected-error {{differ only in their return type}}
+}
+
+namespace Test2 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ void h() {
+ extern double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(void); // expected-error {{differ only in their return type}}
+ }
+}
+
+namespace Test3 {
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ constexpr void (*g())() {
+ void h();
+ return &h;
+ }
+ static_assert(f() == g(), "");
+}
+
+namespace Test4 {
+ template<typename T>
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ static_assert(f<int>() == f<char>(), "");
+ void h();
+ static_assert(f<int>() == &h, "");
+}
+
+namespace Test5 {
+ constexpr auto f() -> void (*)() {
+ void g();
+ struct X {
+ friend void g();
+ static constexpr auto h() -> void (*)() { return g; }
+ };
+ return X::h();
+ }
+ void g();
+ static_assert(f() == g, "");
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
index df9a2cd14cd4..e352bbe83c6b 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -5,7 +5,7 @@ namespace N {
X operator+(X, X);
- void f(X);
+ void f(X); // expected-note 2 {{'N::f' declared here}}
void g(X); // expected-note{{candidate function}}
void test_multiadd(X x) {
@@ -17,7 +17,7 @@ namespace M {
struct Y : N::X { };
}
-void f(); // expected-note 2 {{'f' declared here}}
+void f();
void test_operator_adl(N::X x, M::Y y) {
(void)(x + x);
@@ -27,8 +27,8 @@ void test_operator_adl(N::X x, M::Y y) {
void test_func_adl(N::X x, M::Y y) {
f(x);
f(y);
- (f)(x); // expected-error{{too many arguments to function call}}
- ::f(x); // expected-error{{too many arguments to function call}}
+ (f)(x); // expected-error{{too many arguments to function call, expected 0, have 1; did you mean 'N::f'?}}
+ ::f(x); // expected-error{{too many arguments to function call, expected 0, have 1; did you mean 'N::f'?}}
}
namespace N {
@@ -72,7 +72,7 @@ namespace O {
}
extern "C" {
- struct L { };
+ struct L { int x; };
}
void h(L); // expected-note{{candidate function}}
diff --git a/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp b/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
index 911df989530f..1d2b525da4c2 100644
--- a/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
+++ b/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
@@ -22,3 +22,48 @@ void f() {
Y(1); // okay
}
+namespace PR17731 {
+ void f() {
+ struct S { S() {} };
+ int S(void);
+ int a = S();
+ struct S b;
+ {
+ int S(void);
+ int a = S();
+ struct S c = b;
+ }
+ {
+ struct S { S() {} }; // expected-note {{candidate}}
+ int a = S(); // expected-error {{no viable conversion from 'S'}}
+ struct S c = b; // expected-error {{no viable conversion from 'struct S'}}
+ }
+ }
+ void g() {
+ int S(void);
+ struct S { S() {} };
+ int a = S();
+ struct S b;
+ {
+ int S(void);
+ int a = S();
+ struct S c = b;
+ }
+ {
+ struct S { S() {} }; // expected-note {{candidate}}
+ int a = S(); // expected-error {{no viable conversion from 'S'}}
+ struct S c = b; // expected-error {{no viable conversion from 'struct S'}}
+ }
+ }
+
+ struct A {
+ struct B;
+ void f();
+ int B;
+ };
+ struct A::B {};
+ void A::f() {
+ B = 123;
+ struct B b;
+ }
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2.cpp b/test/CXX/basic/basic.start/basic.start.main/p2.cpp
index a5386f1b9257..5c7d60c1df4c 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2.cpp
@@ -15,6 +15,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST10
// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST11
// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST12
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST13
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST14
#if TEST1
@@ -94,6 +96,20 @@ int main(int, charT* const *) {}
typedef char charT;
int main(int, const charT* const *) {}
+#elif TEST13
+
+int main(void) {}
+
+template <typename T>
+int main(void); // expected-error{{'main' cannot be a template}}
+
+#elif TEST14
+
+template <typename T>
+int main(void); // expected-error{{'main' cannot be a template}}
+
+int main(void) {}
+
#else
#error Unknown test mode
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 19d94cfdd5f6..4a681629eeae 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -7,8 +7,8 @@
// special access rights to the friends, but they do not make the nominated
// friends members of the befriending class.
-struct S { static void f(); };
-S* g() { return 0; }
+struct S { static void f(); }; // expected-note 2 {{'S' declared here}}
+S* g() { return 0; } // expected-note 2 {{'g' declared here}}
struct X {
friend struct S;
@@ -19,8 +19,8 @@ void test1() {
S s;
g()->f();
S::f();
- X::g(); // expected-error{{no member named 'g' in 'X'}}
- X::S x_s; // expected-error{{no type named 'S' in 'X'}}
+ X::g(); // expected-error{{no member named 'g' in 'X'; did you mean simply 'g'?}}
+ X::S x_s; // expected-error{{no type named 'S' in 'X'; did you mean simply 'S'?}}
X x;
x.g(); // expected-error{{no member named 'g' in 'X'}}
}
@@ -36,24 +36,24 @@ namespace N {
friend struct S2* g2();
};
- struct S2 { static void f2(); };
- S2* g2() { return 0; }
+ struct S2 { static void f2(); }; // expected-note 2 {{'S2' declared here}}
+ S2* g2() { return 0; } // expected-note 2 {{'g2' declared here}}
void test() {
g()->f();
S s;
S::f();
- X::g(); // expected-error{{no member named 'g' in 'N::X'}}
- X::S x_s; // expected-error{{no type named 'S' in 'N::X'}}
+ X::g(); // expected-error{{no member named 'g' in 'N::X'; did you mean simply 'g'?}}
+ X::S x_s; // expected-error{{no type named 'S' in 'N::X'; did you mean simply 'S'?}}
X x;
x.g(); // expected-error{{no member named 'g' in 'N::X'}}
g2();
S2 s2;
- ::g2(); // expected-error{{no member named 'g2' in the global namespace}}
- ::S2 g_s2; // expected-error{{no type named 'S2' in the global namespace}}
- X::g2(); // expected-error{{no member named 'g2' in 'N::X'}}
- X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'}}
+ ::g2(); // expected-error{{no member named 'g2' in the global namespace; did you mean simply 'g2'?}}
+ ::S2 g_s2; // expected-error{{no type named 'S2' in the global namespace; did you mean simply 'S2'?}}
+ X::g2(); // expected-error{{no member named 'g2' in 'N::X'; did you mean simply 'g2'?}}
+ X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'; did you mean simply 'S2'?}}
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
}
}
@@ -287,22 +287,22 @@ namespace test9 {
// PR7230
namespace test10 {
- extern "C" void f(void);
- extern "C" void g(void);
+ extern "C" void test10_f(void);
+ extern "C" void test10_g(void);
namespace NS {
class C {
void foo(void); // expected-note {{declared private here}}
- friend void test10::f(void);
+ friend void test10::test10_f(void);
};
static C* bar;
}
- void f(void) {
+ void test10_f(void) {
NS::bar->foo();
}
- void g(void) {
+ void test10_g(void) {
NS::bar->foo(); // expected-error {{private member}}
}
}
diff --git a/test/CXX/class.access/class.friend/p11.cpp b/test/CXX/class.access/class.friend/p11.cpp
index a05b2d28751e..ba44a0d49245 100644
--- a/test/CXX/class.access/class.friend/p11.cpp
+++ b/test/CXX/class.access/class.friend/p11.cpp
@@ -17,3 +17,83 @@ namespace test1 {
};
}
}
+
+namespace test2 {
+ void bar(); // expected-note {{'::test2::bar' declared here}}
+
+ void foo() { // expected-note {{'::test2::foo' declared here}}
+ struct S1 {
+ friend void foo(); // expected-error {{no matching function 'foo' found in local scope; did you mean '::test2::foo'?}}
+ };
+
+ void foo(); // expected-note {{local declaration nearly matches}}
+ struct S2 {
+ friend void foo();
+ };
+
+ {
+ struct S2 {
+ friend void foo(); // expected-error {{no matching function found in local scope}}
+ };
+ }
+
+ {
+ int foo;
+ struct S3 {
+ friend void foo(); // expected-error {{no matching function found in local scope}}
+ };
+ }
+
+ struct S4 {
+ friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
+ };
+
+ { void bar(); }
+ struct S5 {
+ friend void bar(); // expected-error {{no matching function found in local scope}}
+ };
+
+ {
+ void bar();
+ struct S6 {
+ friend void bar();
+ };
+ }
+
+ struct S7 {
+ void bar() { Inner::f(); }
+ struct Inner {
+ friend void bar();
+ static void f() {}
+ };
+ };
+
+ void bar(); // expected-note {{'bar' declared here}}
+ struct S8 {
+ struct Inner {
+ friend void bar();
+ };
+ };
+
+ struct S9 {
+ struct Inner {
+ friend void baz(); // expected-error {{no matching function 'baz' found in local scope; did you mean 'bar'?}}
+ };
+ };
+
+ struct S10 {
+ void quux() {}
+ void foo() {
+ struct Inner1 {
+ friend void bar(); // expected-error {{no matching function found in local scope}}
+ friend void quux(); // expected-error {{no matching function found in local scope}}
+ };
+
+ void bar();
+ struct Inner2 {
+ friend void bar();
+ };
+ }
+ };
+ }
+}
diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index ea9d2ce697c5..5a1ab49321d0 100644
--- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -36,10 +36,17 @@ class A {
public:
class foo {};
static int y;
- template <typename S> friend class B<S>::ty;
+ template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>::' for friend class declaration is not supported}}
};
-template <typename T> class B { typedef int ty; };
+template<typename T> class B { typedef int ty; };
+
+template<> class B<int> {
+ class ty {
+ static int f(A<int> &a) { return a.y; } // ok, befriended
+ };
+};
+int f(A<char> &a) { return a.y; } // FIXME: should be an error
struct {
// Ill-formed
@@ -56,7 +63,7 @@ struct {
friend
float;
- template<typename T> friend class A<T>::foo;
+ template<typename T> friend class A<T>::foo; // expected-warning {{not supported}}
} a;
void testA() { (void)sizeof(A<int>); }
diff --git a/test/CXX/class.access/class.friend/p6.cpp b/test/CXX/class.access/class.friend/p6.cpp
index 7f7d90990328..2fe20fe77fc8 100644
--- a/test/CXX/class.access/class.friend/p6.cpp
+++ b/test/CXX/class.access/class.friend/p6.cpp
@@ -11,6 +11,10 @@ struct Y {
friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
};
+template <typename T> struct Z {
+ friend void T::f() {} // expected-error{{friend function definition cannot be qualified with 'T::'}}
+};
+
void local() {
void f();
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 5ad738bebf9c..0564a52b6d0d 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -151,7 +151,7 @@ namespace test3 {
virtual Base3
{};
Derived3 d3; // expected-note {{implicit default constructor}}\
- // expected-note{{implicit default destructor}}}
+ // expected-note{{implicit destructor}}}
}
// Conversion functions.
@@ -207,13 +207,13 @@ namespace test5 {
class Test1 { A a; }; // expected-error {{private member}}
void test1() {
Test1 a;
- a = Test1(); // expected-note{{implicit default copy}}
+ a = Test1(); // expected-note{{implicit copy}}
}
class Test2 : A {}; // expected-error {{private member}}
void test2() {
Test2 a;
- a = Test2(); // expected-note{{implicit default copy}}
+ a = Test2(); // expected-note{{implicit copy}}
}
}
@@ -226,12 +226,12 @@ namespace test6 {
class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}}
void test1(const Test1 &t) {
- Test1 a = t; // expected-note{{implicit default copy}}
+ Test1 a = t; // expected-note{{implicit copy}}
}
class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}}
void test2(const Test2 &t) {
- Test2 a = t; // expected-note{{implicit default copy}}
+ Test2 a = t; // expected-note{{implicit copy}}
}
}
diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp
index fbdc87b24e26..6a93658fc78d 100644
--- a/test/CXX/class.access/p6.cpp
+++ b/test/CXX/class.access/p6.cpp
@@ -92,7 +92,7 @@ namespace test3 {
template <class T> class Outer::A<T, typename T::nature> {
public:
- static void foo();
+ static void foo(); // expected-note {{'Outer::A<B, Green>::foo' declared here}}
};
class B {
@@ -102,7 +102,7 @@ namespace test3 {
void test() {
Outer::A<B, Green>::foo();
- Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo'}}
+ Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<B, Green>::foo'?}}
}
}
diff --git a/test/CXX/class.derived/class.abstract/p16.cpp b/test/CXX/class.derived/class.abstract/p16.cpp
index c237ed90446f..2053218ca5b5 100644
--- a/test/CXX/class.derived/class.abstract/p16.cpp
+++ b/test/CXX/class.derived/class.abstract/p16.cpp
@@ -22,7 +22,7 @@ struct H;
struct D {
virtual E &operator=(const E &); // expected-note {{here}}
virtual F &operator=(const F &);
- virtual G &operator=(G&&);
+ virtual G &operator=(G&&); // expected-note {{here}}
virtual H &operator=(H&&); // expected-note {{here}}
friend struct F;
@@ -34,8 +34,8 @@ private:
struct E : D {}; // expected-error {{deleted function '~E' cannot override a non-deleted function}} \
// expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
struct F : D {};
-// No move ctor here, because it would be deleted.
struct G : D {}; // expected-error {{deleted function '~G' cannot override a non-deleted function}}
+ // expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}
struct H : D {
H &operator=(H&&) = default; // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
~H();
diff --git a/test/CXX/class.derived/class.member.lookup/p7.cpp b/test/CXX/class.derived/class.member.lookup/p7.cpp
new file mode 100644
index 000000000000..a785e0f90e57
--- /dev/null
+++ b/test/CXX/class.derived/class.member.lookup/p7.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -verify %s
+
+// expected-no-diagnostics
+
+struct A { int n; };
+struct B { float n; };
+struct C : A, B {};
+struct D : virtual C {};
+struct E : virtual C { char n; };
+struct F : D, E {} f;
+char &k = f.n;
diff --git a/test/CXX/class.derived/class.virtual/p3-0x.cpp b/test/CXX/class.derived/class.virtual/p3-0x.cpp
index 6a02a8673186..41a5954bf863 100644
--- a/test/CXX/class.derived/class.virtual/p3-0x.cpp
+++ b/test/CXX/class.derived/class.virtual/p3-0x.cpp
@@ -130,3 +130,23 @@ namespace MemberOfUnknownSpecialization {
// expected-note@+1 {{in instantiation of}}
A<double>::C c3;
}
+
+namespace DiagnosticsQOI {
+ struct X {
+ virtual ~X();
+ virtual void foo(int x); // expected-note {{hidden overloaded virtual function}}
+ virtual void bar(int x); // expected-note 2 {{hidden overloaded virtual function}}
+ virtual void bar(float x); // expected-note 2 {{hidden overloaded virtual function}}
+ };
+
+ struct Y : X {
+ void foo(int x, int y) override; // expected-error {{non-virtual member function marked 'override' hides virtual member function}}
+ void bar(double) override; // expected-error {{non-virtual member function marked 'override' hides virtual member functions}}
+ void bar(long double) final; // expected-error {{non-virtual member function marked 'final' hides virtual member functions}}
+ };
+
+ template<typename T>
+ struct Z : T {
+ static void foo() override; // expected-error {{only virtual member functions can be marked 'override'}}
+ };
+}
diff --git a/test/CXX/class/class.friend/p6.cpp b/test/CXX/class/class.friend/p6.cpp
index 82ca50e485d6..e4c59f781e3d 100644
--- a/test/CXX/class/class.friend/p6.cpp
+++ b/test/CXX/class/class.friend/p6.cpp
@@ -4,7 +4,11 @@
class A {
friend static class B; // expected-error {{'static' is invalid in friend declarations}}
friend extern class C; // expected-error {{'extern' is invalid in friend declarations}}
+#if __cplusplus < 201103L
+ friend register class E; // expected-error {{'register' is invalid in friend declarations}}
+#else
friend register class E; // expected-error {{'register' is invalid in friend declarations}}
+#endif
friend mutable class F; // expected-error {{'mutable' is invalid in friend declarations}}
friend typedef class G; // expected-error {{'typedef' is invalid in friend declarations}}
friend __thread class G; // expected-error {{'__thread' is invalid in friend declarations}}
diff --git a/test/CXX/class/class.nested.type/p1.cpp b/test/CXX/class/class.nested.type/p1.cpp
index 4a04a448595c..929565441230 100644
--- a/test/CXX/class/class.nested.type/p1.cpp
+++ b/test/CXX/class/class.nested.type/p1.cpp
@@ -2,12 +2,12 @@
class X {
public:
- typedef int I;
- class Y { };
+ typedef int I; // expected-note{{'X::I' declared here}}
+ class Y { }; // expected-note{{'X::Y' declared here}}
I a;
};
-I b; // expected-error{{unknown type name 'I'}}
-Y c; // expected-error{{unknown type name 'Y'}}
+I b; // expected-error{{unknown type name 'I'; did you mean 'X::I'?}}
+Y c; // expected-error{{unknown type name 'Y'; did you mean 'X::Y'?}}
X::Y d;
X::I e;
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
index 3bc485601ca5..96a0df4a03f0 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
@@ -3,7 +3,7 @@
// Fun things you can do with inline namespaces:
inline namespace X {
- void f1();
+ void f1(); // expected-note {{'f1' declared here}}
inline namespace Y {
void f2();
@@ -21,7 +21,7 @@ void foo1() {
f1();
::f1();
X::f1();
- Y::f1(); // expected-error {{no member named 'f1' in namespace 'X::Y'}}
+ Y::f1(); // expected-error {{no member named 'f1' in namespace 'X::Y'; did you mean simply 'f1'?}}
f2();
::f2();
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
index 93b1c6461a43..81e2ca5f1e4d 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
@@ -14,3 +14,7 @@ template<typename T, typename A, int N> struct Y {
static_assert(alignof(Y<char, int, sizeof(int)>) == alignof(int), "");
static_assert(alignof(Y<int, char, 1>) == alignof(int), ""); // expected-note {{in instantiation of}}
+
+void pr16992 () {
+ int x = alignof int; // expected-error {{expected parentheses around type name in alignof expression}}
+}
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
new file mode 100644
index 000000000000..21119398b2f4
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+class [[deprecated]] C {}; // expected-note {{declared here}}
+C c; // expected-warning {{'C' is deprecated}}
+
+typedef int t [[deprecated]]; // expected-note {{declared here}}
+t x = 42; // expected-warning {{'t' is deprecated}}
+
+[[deprecated]] int old = 42; // expected-note {{declared here}}
+int use = old; // expected-warning {{'old' is deprecated}}
+
+struct S { [[deprecated]] int member = 42; } s; // expected-note {{declared here}}
+int use2 = s.member; // expected-warning {{'member' is deprecated}}
+
+[[deprecated]] int f() { return 42; } // expected-note {{declared here}}
+int use3 = f(); // expected-warning {{'f' is deprecated}}
+
+enum [[deprecated]] e { E }; // expected-note {{declared here}}
+e my_enum; // expected-warning {{'e' is deprecated}}
+
+template <typename T> class X {};
+template <> class [[deprecated]] X<int> {}; // expected-note {{declared here}}
+X<char> x1;
+// FIXME: The diagnostic here could be much better by mentioning X<int>.
+X<int> x2; // expected-warning {{'X' is deprecated}}
+
+template <typename T> class [[deprecated]] X2 {};
+template <> class X2<int> {};
+X2<char> x3; // FIXME: no warning!
+X2<int> x4;
diff --git a/test/CXX/dcl.dcl/dcl.link/p7-2.cpp b/test/CXX/dcl.dcl/dcl.link/p7-2.cpp
index 40f61c6445ac..1e8f39338c24 100644
--- a/test/CXX/dcl.dcl/dcl.link/p7-2.cpp
+++ b/test/CXX/dcl.dcl/dcl.link/p7-2.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -ast-print -o - %s | FileCheck %s
-extern "C" void f(void);
-// CHECK: extern "C" void f()
+extern "C" int f(void);
+// CHECK: extern "C" int f()
-extern "C" void v;
-// CHECK: extern "C" void v
+extern "C" int v;
+// CHECK: extern "C" int v
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index 122a400d9b4e..cf422972a280 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -72,7 +72,8 @@ template <typename T> constexpr T ft(T t) { return t; }
template <typename T> T gt(T t) { return t; }
struct S {
template<typename T> constexpr T f(); // expected-warning {{C++1y}}
- template<typename T> T g() const;
+ template <typename T>
+ T g() const; // expected-note {{candidate template ignored: could not match 'T () const' against 'char ()'}}
};
// explicit specialization can differ in constepxr
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 4393727c193b..780a420959d6 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -63,8 +63,20 @@ struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-li
#ifndef CXX1Y
// expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
// expected-warning@-3 {{C++1y}}
+#else
+ // expected-error@-5 {{defaulted definition of copy assignment operator is not constexpr}}
#endif
};
+#ifdef CXX1Y
+struct T2 {
+ int n = 0;
+ constexpr T2 &operator=(const T2&) = default; // ok
+};
+struct T3 {
+ constexpr T3 &operator=(const T3&) const = default;
+ // expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
+};
+#endif
struct U {
constexpr U SelfReturn() const;
constexpr int SelfParam(U) const;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index 8a4fa42f0023..708c259d5b61 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -314,3 +314,23 @@ namespace CtorLookup {
constexpr C::C(const C&) = default;
constexpr C::C(C&) = default; // expected-error {{not constexpr}}
}
+
+namespace PR14503 {
+ template<typename> struct V {
+ union {
+ int n;
+ struct {
+ int x,
+ y;
+ };
+ };
+ constexpr V() : x(0) {}
+ };
+
+ // The constructor is still 'constexpr' here, but the result is not intended
+ // to be a constant expression. The standard is not clear on how this should
+ // work.
+ constexpr V<int> v; // expected-error {{constant expression}} expected-note {{subobject of type 'int' is not initialized}}
+
+ constexpr int k = V<int>().x; // FIXME: ok?
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp
new file mode 100644
index 000000000000..ff2abf9dfafc
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+template<typename T> struct S { typedef int type; };
+
+template<typename T> void f() {
+ auto x = [] { return 0; } ();
+ // FIXME: We should be able to produce a 'missing typename' diagnostic here.
+ S<decltype(x)>::type n; // expected-error 2{{}}
+}
+
+#if __cplusplus > 201103L
+template<typename T> void g() {
+ auto x = [] () -> auto { return 0; } ();
+ S<decltype(x)>::type n; // expected-error 2{{}}
+}
+#endif
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
new file mode 100644
index 000000000000..65b085bcec13
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+//FIXME: These tests were written when return type deduction had not been implemented
+// for generic lambdas, hence
+template<class T> T id(T t);
+template<class ... Ts> int vfoo(Ts&& ... ts);
+auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+auto GL3 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+auto GL4 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+
+void foo() {
+ auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+ auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+}
+
+int main()
+{
+ auto l1 = [](auto a) -> int { return a + 5; };
+ auto l2 = [](auto *p) -> int { return p + 5; };
+
+ struct A { int i; char f(int) { return 'c'; } };
+ auto l3 = [](auto &&ur,
+ auto &lr,
+ auto v,
+ int i,
+ auto* p,
+ auto A::*memvar,
+ auto (A::*memfun)(int),
+ char c,
+ decltype (v)* pv
+ , auto (&array)[5]
+ ) -> int { return v + i + c
+ + array[0];
+ };
+ int arr[5] = {0, 1, 2, 3, 4 };
+ int lval = 0;
+ double d = 3.14;
+ l3(3, lval, d, lval, &lval, &A::i, &A::f, 'c', &d, arr);
+ auto l4 = [](decltype(auto) a) -> int { return 0; }; //expected-error{{decltype(auto)}}
+ {
+ struct Local {
+ static int ifi(int i) { return i; }
+ static char cfi(int) { return 'a'; }
+ static double dfi(int i) { return i + 3.14; }
+ static Local localfi(int) { return Local{}; }
+ };
+ auto l4 = [](auto (*fp)(int)) -> int { return fp(3); }; //expected-error{{no viable conversion from 'Local' to 'int'}}
+ l4(&Local::ifi);
+ l4(&Local::cfi);
+ l4(&Local::dfi);
+ l4(&Local::localfi); //expected-note{{in instantiation of function template specialization}}
+ }
+ {
+ auto unnamed_parameter = [](auto, auto) -> void { };
+ unnamed_parameter(3, '4');
+ }
+ {
+ auto l = [](auto
+ (*)(auto)) { }; //expected-error{{'auto' not allowed}}
+ //FIXME: These diagnostics might need some work.
+ auto l2 = [](char auto::*pm) { }; //expected-error{{cannot combine with previous}}\
+ expected-error{{'pm' does not point into a class}}
+ auto l3 = [](char (auto::*pmf)()) { }; //expected-error{{'auto' not allowed}}\
+ expected-error{{'pmf' does not point into a class}}\
+ expected-error{{function cannot return function type 'char ()'}}
+ }
+}
+
+
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index e566d2a8f1d2..84f9f9b82983 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -35,7 +35,7 @@ class X {
};
struct S {
- static const auto a; // expected-error {{declaration of variable 'a' with type 'auto const' requires an initializer}}
+ static const auto a; // expected-error {{declaration of variable 'a' with type 'const auto' requires an initializer}}
static const auto b = 0;
static const int c;
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
index d327efcc20df..1711aaa8aef9 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -55,7 +55,7 @@ void f() {
auto *fail1 = 0; // expected-error {{variable 'fail1' with type 'auto *' has incompatible initializer of type 'int'}}
int **p;
- const auto **fail2(p); // expected-error {{variable 'fail2' with type 'auto const **' has incompatible initializer of type 'int **'}}
+ const auto **fail2(p); // expected-error {{variable 'fail2' with type 'const auto **' has incompatible initializer of type 'int **'}}
}
struct S {
@@ -85,8 +85,8 @@ struct S {
namespace PR10939 {
struct X {
- int method(int);
- int method(float);
+ int method(int); // expected-note{{possible target for call}}
+ int method(float); // expected-note{{possible target for call}}
};
template<typename T> T g(T);
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
index 66085eda3d73..f7b3e8e7be63 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
@@ -8,9 +8,6 @@ namespace std {
};
}
-// FIXME: This may not be p6 in C++1y; N3638 isn't very clear whether paragraphs
-// were added. It might be p8?
-
int i;
int &&f();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
index 9c1d397a1fbc..8d789bdd5ad3 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
@@ -29,4 +29,17 @@ void g() {
(*e)() -> void,
#endif
f = 0.0;
+
+#if __has_feature(cxx_decltype)
+ auto g = 0ull, h = decltype(g)(0);
+#endif
+}
+
+template<typename T> void h() {
+ auto a = T(), *b = &a;
+#if __has_feature(cxx_decltype)
+ auto c = T(), d = decltype(c)(0);
+#endif
}
+template void h<int>();
+template void h<unsigned long>();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index 8d5849880232..40e754082b48 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -14,7 +14,7 @@ class A1 {
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
- friend enum E; // expected-warning {{cannot be a friend}}
+ friend enum E; // expected-warning {{befriending enumeration type 'enum E' is a C++11 extension}}
};
template <class T> struct B { // expected-note {{previous use is here}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
index d1fbe766d527..22667ac14bb5 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y %s -verify
+// RUN: %clang_cc1 -Wno-uninitialized -std=c++1y %s -verify
// expected-no-diagnostics
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
index d61f6e3d1982..58d038366c81 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
@@ -4,7 +4,7 @@ namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E>
- struct initializer_list
+ struct initializer_list // expected-note 2{{candidate}}
{
const E *p;
size_t n;
@@ -113,10 +113,14 @@ namespace bullet8 {
namespace rdar13395022 {
struct MoveOnly {
- MoveOnly(MoveOnly&&); // expected-note{{copy constructor is implicitly deleted because 'MoveOnly' has a user-declared move constructor}}
+ MoveOnly(MoveOnly&&);
};
void test(MoveOnly mo) {
- auto &&list = {mo}; // expected-error{{call to implicitly-deleted copy constructor of 'rdar13395022::MoveOnly'}}
+ // FIXME: These diagnostics are poor.
+ auto &&list1 = {mo}; // expected-error{{no viable conversion}}
+ MoveOnly (&&list2)[1] = {mo}; // expected-error{{no viable conversion}}
+ std::initializer_list<MoveOnly> &&list3 = {};
+ MoveOnly (&&list4)[1] = {}; // expected-error{{uninitialized}}
}
}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
new file mode 100644
index 000000000000..e040d5b2642b
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
@@ -0,0 +1,209 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y -triple x86_64-linux-gnu %s
+
+// If there is a preceding declaration of the entity *in the same scope* in
+// which the bound was specified, an omitted array bound is taken to be the
+// same as in that earlier declaration
+
+// rdar://13535367
+namespace test0 {
+ extern "C" int array[];
+ void declare() { extern int array[100]; }
+ int value1 = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ extern "C" int array[];
+ int value2 = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test1 {
+ extern "C" int array[];
+ void test() {
+ { extern int array[100]; }
+ extern int array[];
+ int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+namespace test2 {
+ void declare() { extern int array[100]; }
+ extern int array[];
+ int value = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test3 {
+ void test() {
+ { extern int array[100]; }
+ extern int array[];
+ int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+namespace test4 {
+ extern int array[];
+ void test() {
+ extern int array[100];
+ int x = sizeof(array);
+ }
+ int y = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test5 {
+ void test() {
+ extern int array[100];
+ extern int array[];
+ int x = sizeof(array);
+ }
+}
+
+namespace test6 {
+ void test() {
+ extern int array[100];
+ {
+ extern int array[];
+ int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+ int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
+ }
+}
+
+namespace test7 {
+ extern int array[100];
+ void test() {
+ extern int array[];
+ int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+ int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
+}
+
+namespace test8 {
+ extern int array[];
+ void test() {
+ extern int array[100];
+ int x = sizeof(array);
+ }
+ int y = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ extern int array[];
+ int z = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace dependent {
+ template<typename T> void f() {
+ extern int arr1[];
+ extern T arr1;
+ extern T arr2;
+ extern int arr2[];
+ static_assert(sizeof(arr1) == 12, "");
+ static_assert(sizeof(arr2) == 12, "");
+
+ // Use a failing test to ensure the type isn't considered dependent.
+ static_assert(sizeof(arr2) == 13, ""); // expected-error {{failed}}
+ }
+
+ void g() { f<int[3]>(); } // expected-note {{in instantiation of}}
+
+ template<typename T> void h1() {
+ extern T arr3;
+ {
+ int arr3;
+ {
+ extern int arr3[];
+ // Detected in template definition.
+ (void)sizeof(arr3); // expected-error {{incomplete}}
+ }
+ }
+ }
+
+ template<typename T> void h2() {
+ extern int arr4[3];
+ {
+ int arr4;
+ {
+ extern T arr4;
+ // Detected in template instantiation.
+ (void)sizeof(arr4); // expected-error {{incomplete}}
+ }
+ }
+ }
+
+ void i() {
+ h1<int[3]>();
+ h2<int[]>(); // expected-note {{in instantiation of}}
+ }
+
+ int arr5[3];
+ template<typename T> void j() {
+ extern T arr5;
+ extern T arr6;
+ (void)sizeof(arr5); // expected-error {{incomplete}}
+ (void)sizeof(arr6); // expected-error {{incomplete}}
+ }
+ int arr6[3];
+
+ void k() { j<int[]>(); } // expected-note {{in instantiation of}}
+
+ template<typename T, typename U> void l() {
+ extern T arrX; // expected-note {{previous}}
+ extern U arrX; // expected-error {{different type: 'int [4]' vs 'int [3]'}}
+ (void)sizeof(arrX); // expected-error {{incomplete}}
+ }
+
+ void m() {
+ l<int[], int[3]>(); // ok
+ l<int[3], int[]>(); // ok
+ l<int[3], int[3]>(); // ok
+ l<int[3], int[4]>(); // expected-note {{in instantiation of}}
+ l<int[], int[]>(); // expected-note {{in instantiation of}}
+ }
+
+ template<typename T> void n() {
+ extern T n_var; // expected-error {{redefinition of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}}
+ extern T n_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} expected-note {{previous}}
+ }
+ template void n<int>();
+ template void n<double>(); // expected-note {{in instantiation of}}
+
+ template<typename T> void o() {
+ extern T o_var; // expected-note {{previous}}
+ extern T o_fn(); // expected-note {{previous}}
+ }
+ template void o<int>();
+ float o_var; // expected-error {{redefinition of 'o_var' with a different type: 'float' vs 'int'}}
+ float o_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+ int p_var;
+ int p_fn();
+ template<typename T> void p() {
+ extern T p_var;
+ extern T p_fn();
+ }
+}
+
+namespace use_outside_ns {
+ namespace A {
+ extern int a[3];
+ extern int b[];
+ extern int c[3];
+ void f() {
+ extern int a[];
+ extern int b[3];
+ }
+ template<typename T> void x() {
+ extern T c;
+ extern T d;
+ }
+ extern int d[3];
+ template void x<int[]>();
+ }
+ int w = sizeof(A::a);
+ int x = sizeof(A::b); // expected-error {{incomplete}}
+ int y = sizeof(A::c);
+ int z = sizeof(A::d);
+ namespace A {
+ int g() { return sizeof(a); }
+ int h() { return sizeof(b); } // expected-error {{incomplete}}
+ int i() { return sizeof(c); }
+ int j() { return sizeof(d); }
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
index 385e45dadfae..27ebb8e036f0 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A {
- virtual void f(int a = 7);
+ virtual void f(int a = 7); // expected-note{{'A::f' declared here}}
};
struct B : public A {
- void f(int a); // expected-note{{'f' declared here}}
+ void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
- pb->f(); // expected-error{{too few arguments}}
+ pb->f(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean 'A::f'?}}
}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
index 6b1f3e438d8f..ce9072886160 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
auto a() -> int; // ok
-const auto b() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto const'}}
+const auto b() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'const auto'}}
auto *c() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto *'}}
auto (d() -> int); // expected-error {{trailing return type may not be nested within parentheses}}
auto e() -> auto (*)() -> auto (*)() -> void; // ok: same as void (*(*e())())();
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
new file mode 100644
index 000000000000..265a52d9261a
--- /dev/null
+++ b/test/CXX/drs/dr0xx.cpp
@@ -0,0 +1,1040 @@
+// 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
+// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr1 { // dr1: no
+ namespace X { extern "C" void dr1_f(int a = 1); }
+ namespace Y { extern "C" void dr1_f(int a = 2); }
+ using X::dr1_f; using Y::dr1_f;
+ void g() {
+ dr1_f(0);
+ // FIXME: This should be rejected, due to the ambiguous default argument.
+ dr1_f();
+ }
+ namespace X {
+ using Y::dr1_f;
+ void h() {
+ dr1_f(0);
+ // FIXME: This should be rejected, due to the ambiguous default argument.
+ dr1_f();
+ }
+ }
+
+ namespace X {
+ void z(int);
+ }
+ void X::z(int = 1) {} // expected-note {{previous}}
+ namespace X {
+ void z(int = 2); // expected-error {{redefinition of default argument}}
+ }
+}
+
+namespace dr3 { // dr3: yes
+ template<typename T> struct A {};
+ template<typename T> void f(T) { A<T> a; } // expected-note {{implicit instantiation}}
+ template void f(int);
+ template<> struct A<int> {}; // expected-error {{explicit specialization of 'dr3::A<int>' after instantiation}}
+}
+
+namespace dr4 { // dr4: yes
+ extern "C" {
+ static void dr4_f(int) {}
+ static void dr4_f(float) {}
+ void dr4_g(int) {} // expected-note {{previous}}
+ void dr4_g(float) {} // expected-error {{conflicting types}}
+ }
+}
+
+namespace dr5 { // dr5: yes
+ struct A {} a;
+ struct B {
+ B(const A&);
+ B(const B&);
+ };
+ const volatile B b = a;
+
+ struct C { C(C&); };
+ struct D : C {};
+ struct E { operator D&(); } e;
+ const C c = e;
+}
+
+namespace dr7 { // dr7: yes
+ class A { public: ~A(); };
+ class B : virtual private A {}; // expected-note 2 {{declared private here}}
+ class C : public B {} c; // expected-error 2 {{inherited virtual base class 'dr7::A' has private destructor}} \
+ // expected-note {{implicit default constructor for 'dr7::C' first required here}} \
+ // expected-note {{implicit destructor for 'dr7::C' first required here}}
+ class VeryDerivedC : public B, virtual public A {} vdc;
+
+ class X { ~X(); }; // expected-note {{here}}
+ class Y : X { ~Y() {} }; // expected-error {{private destructor}}
+
+ namespace PR16370 { // This regressed the first time DR7 was fixed.
+ struct S1 { virtual ~S1(); };
+ struct S2 : S1 {};
+ struct S3 : S2 {};
+ struct S4 : virtual S2 {};
+ struct S5 : S3, S4 {
+ S5();
+ ~S5();
+ };
+ S5::S5() {}
+ }
+}
+
+namespace dr8 { // dr8: dup 45
+ class A {
+ struct U;
+ static const int k = 5;
+ void f();
+ template<typename, int, void (A::*)()> struct T;
+
+ T<U, k, &A::f> *g();
+ };
+ A::T<A::U, A::k, &A::f> *A::g() { return 0; }
+}
+
+namespace dr9 { // dr9: yes
+ struct B {
+ protected:
+ int m; // expected-note {{here}}
+ friend int R1();
+ };
+ struct N : protected B { // expected-note 2{{protected}}
+ friend int R2();
+ } n;
+ int R1() { return n.m; } // expected-error {{protected base class}} expected-error {{protected member}}
+ int R2() { return n.m; }
+}
+
+namespace dr10 { // dr10: dup 45
+ class A {
+ struct B {
+ A::B *p;
+ };
+ };
+}
+
+namespace dr11 { // dr11: yes
+ template<typename T> struct A : T {
+ using typename T::U;
+ U u;
+ };
+ template<typename T> struct B : T {
+ using T::V;
+ V v; // expected-error {{unknown type name}}
+ };
+ struct X { typedef int U; };
+ A<X> ax;
+}
+
+namespace dr12 { // dr12: sup 239
+ enum E { e };
+ E &f(E, E = e);
+ void g() {
+ int &f(int, E = e);
+ // Under DR12, these call two different functions.
+ // Under DR239, they call the same function.
+ int &b = f(e);
+ int &c = f(1);
+ }
+}
+
+namespace dr14 { // dr14: yes
+ namespace X { extern "C" int dr14_f(); }
+ namespace Y { extern "C" int dr14_f(); }
+ using namespace X;
+ using namespace Y;
+ int k = dr14_f();
+
+ class C {
+ int k;
+ friend int Y::dr14_f();
+ } c;
+ namespace Z {
+ extern "C" int dr14_f() { return c.k; }
+ }
+
+ namespace X { typedef int T; typedef int U; } // expected-note {{candidate}}
+ namespace Y { typedef int T; typedef long U; } // expected-note {{candidate}}
+ T t; // ok, same type both times
+ U u; // expected-error {{ambiguous}}
+}
+
+namespace dr15 { // dr15: yes
+ template<typename T> void f(int); // expected-note {{previous}}
+ template<typename T> void f(int = 0); // expected-error {{default arguments cannot be added}}
+}
+
+namespace dr16 { // dr16: yes
+ class A { // expected-note {{here}}
+ void f(); // expected-note {{here}}
+ friend class C;
+ };
+ class B : A {}; // expected-note 4{{here}}
+ class C : B {
+ void g() {
+ f(); // expected-error {{private member}} expected-error {{private base}}
+ A::f(); // expected-error {{private member}} expected-error {{private base}}
+ }
+ };
+}
+
+namespace dr17 { // dr17: yes
+ class A {
+ int n;
+ int f();
+ struct C;
+ };
+ struct B : A {} b;
+ int A::f() { return b.n; }
+ struct A::C : A {
+ int g() { return n; }
+ };
+}
+
+namespace dr18 { // dr18: yes
+ typedef void Void;
+ void f(Void); // expected-error {{empty parameter list defined with a typedef of 'void'}}
+}
+
+namespace dr19 { // dr19: yes
+ struct A {
+ int n; // expected-note {{here}}
+ };
+ struct B : protected A { // expected-note {{here}}
+ };
+ struct C : B {} c;
+ struct D : B {
+ int get1() { return c.n; } // expected-error {{protected member}}
+ int get2() { return ((A&)c).n; } // ok, A is an accessible base of B from here
+ };
+}
+
+namespace dr20 { // dr20: yes
+ class X {
+ public:
+ X();
+ private:
+ X(const X&); // expected-note {{here}}
+ };
+ X f();
+ X x = f(); // expected-error {{private}}
+}
+
+namespace dr21 { // dr21: yes
+ template<typename T> struct A;
+ struct X {
+ template<typename T = int> friend struct A; // expected-error {{default template argument not permitted on a friend template}}
+ template<typename T = int> friend struct B; // expected-error {{default template argument not permitted on a friend template}}
+ };
+}
+
+namespace dr22 { // dr22: sup 481
+ template<typename dr22_T = dr22_T> struct X; // expected-error {{unknown type name 'dr22_T'}}
+ typedef int T;
+ template<typename T = T> struct Y;
+}
+
+namespace dr23 { // dr23: yes
+ template<typename T> void f(T, T); // expected-note {{candidate}}
+ template<typename T> void f(T, int); // expected-note {{candidate}}
+ void g() { f(0, 0); } // expected-error {{ambiguous}}
+}
+
+// dr24: na
+
+namespace dr25 { // dr25: yes
+ struct A {
+ void f() throw(int);
+ };
+ void (A::*f)() throw (int);
+ void (A::*g)() throw () = f; // expected-error {{is not superset of source}}
+ void (A::*g2)() throw () = 0;
+ void (A::*h)() throw (int, char) = f;
+ void (A::*i)() throw () = &A::f; // expected-error {{is not superset of source}}
+ void (A::*i2)() throw () = 0;
+ void (A::*j)() throw (int, char) = &A::f;
+ void x() {
+ // FIXME: Don't produce the second error here.
+ g2 = f; // expected-error {{is not superset}} expected-error {{incompatible}}
+ h = f;
+ i2 = &A::f; // expected-error {{is not superset}} expected-error {{incompatible}}
+ j = &A::f;
+ }
+}
+
+namespace dr26 { // dr26: yes
+ struct A { A(A, const A & = A()); }; // expected-error {{must pass its first argument by reference}}
+ struct B {
+ B(); // expected-note {{candidate}}
+ B(const B &, B = B()); // expected-error {{no matching constructor}} expected-note {{candidate}} expected-note {{here}}
+ };
+}
+
+namespace dr27 { // dr27: yes
+ enum E { e } n;
+ E &m = true ? n : n;
+}
+
+// dr28: na
+
+namespace dr29 { // dr29: 3.4
+ void dr29_f0(); // expected-note {{here}}
+ void g0() { void dr29_f0(); }
+ extern "C++" void g0_cxx() { void dr29_f0(); }
+ extern "C" void g0_c() { void dr29_f0(); } // expected-error {{different language linkage}}
+
+ extern "C" void dr29_f1(); // expected-note {{here}}
+ void g1() { void dr29_f1(); }
+ extern "C" void g1_c() { void dr29_f1(); }
+ extern "C++" void g1_cxx() { void dr29_f1(); } // expected-error {{different language linkage}}
+
+ void g2() { void dr29_f2(); } // expected-note {{here}}
+ extern "C" void dr29_f2(); // expected-error {{different language linkage}}
+
+ extern "C" void g3() { void dr29_f3(); } // expected-note {{here}}
+ extern "C++" void dr29_f3(); // expected-error {{different language linkage}}
+
+ extern "C++" void g4() { void dr29_f4(); } // expected-note {{here}}
+ extern "C" void dr29_f4(); // expected-error {{different language linkage}}
+
+ extern "C" void g5();
+ extern "C++" void dr29_f5();
+ void g5() {
+ void dr29_f5(); // ok, g5 is extern "C" but we're not inside the linkage-specification here.
+ }
+
+ extern "C++" void g6();
+ extern "C" void dr29_f6();
+ void g6() {
+ void dr29_f6(); // ok, g6 is extern "C" but we're not inside the linkage-specification here.
+ }
+
+ extern "C" void g7();
+ extern "C++" void dr29_f7(); // expected-note {{here}}
+ extern "C" void g7() {
+ void dr29_f7(); // expected-error {{different language linkage}}
+ }
+
+ extern "C++" void g8();
+ extern "C" void dr29_f8(); // expected-note {{here}}
+ extern "C++" void g8() {
+ void dr29_f8(); // expected-error {{different language linkage}}
+ }
+}
+
+namespace dr30 { // dr30: sup 468 c++11
+ struct A {
+ template<int> static int f();
+ } a, *p = &a;
+ int x = A::template f<0>();
+ int y = a.template f<0>();
+ int z = p->template f<0>();
+#if __cplusplus < 201103L
+ // FIXME: It's not clear whether DR468 applies to C++98 too.
+ // expected-error@-5 {{'template' keyword outside of a template}}
+ // expected-error@-5 {{'template' keyword outside of a template}}
+ // expected-error@-5 {{'template' keyword outside of a template}}
+#endif
+}
+
+namespace dr31 { // dr31: yes
+ class X {
+ private:
+ void operator delete(void*); // expected-note {{here}}
+ };
+ // We would call X::operator delete if X() threw (even though it can't,
+ // and even though we allocated the X using ::operator delete).
+ X *p = new X; // expected-error {{private}}
+}
+
+// dr32: na
+
+namespace dr33 { // dr33: yes
+ namespace X { struct S; void f(void (*)(S)); } // expected-note {{candidate}}
+ namespace Y { struct T; void f(void (*)(T)); } // expected-note {{candidate}}
+ void g(X::S);
+ template<typename Z> Z g(Y::T);
+ void h() { f(&g); } // expected-error {{ambiguous}}
+}
+
+// dr34: na
+// dr35: dup 178
+// dr37: sup 475
+
+namespace dr38 { // dr38: yes
+ template<typename T> struct X {};
+ template<typename T> X<T> operator+(X<T> a, X<T> b) { return a; }
+ template X<int> operator+<int>(X<int>, X<int>);
+}
+
+namespace dr39 { // dr39: no
+ namespace example1 {
+ struct A { int &f(int); };
+ struct B : A {
+ using A::f;
+ float &f(float);
+ } b;
+ int &r = b.f(0);
+ }
+
+ namespace example2 {
+ struct A {
+ int &x(int); // expected-note {{found}}
+ static int &y(int); // expected-note {{found}}
+ };
+ struct V {
+ int &z(int);
+ };
+ struct B : A, virtual V {
+ using A::x; // expected-note {{found}}
+ float &x(float);
+ using A::y; // expected-note {{found}}
+ static float &y(float);
+ using V::z;
+ float &z(float);
+ };
+ struct C : A, B, virtual V {} c;
+ int &x = c.x(0); // expected-error {{found in multiple base classes}}
+ // FIXME: This is valid, because we find the same static data member either way.
+ int &y = c.y(0); // expected-error {{found in multiple base classes}}
+ int &z = c.z(0);
+ }
+
+ namespace example3 {
+ struct A { static int f(); };
+ struct B : virtual A { using A::f; };
+ struct C : virtual A { using A::f; };
+ struct D : B, C {} d;
+ int k = d.f();
+ }
+
+ namespace example4 {
+ struct A { int n; }; // expected-note {{found}}
+ struct B : A {};
+ struct C : A {};
+ struct D : B, C { int f() { return n; } }; // expected-error {{found in multiple base-class}}
+ }
+
+ namespace PR5916 {
+ // FIXME: This is valid.
+ struct A { int n; }; // expected-note +{{found}}
+ struct B : A {};
+ struct C : A {};
+ struct D : B, C {};
+ int k = sizeof(D::n); // expected-error {{found in multiple base}} expected-error {{unknown type name}}
+#if __cplusplus >= 201103L
+ decltype(D::n) n; // expected-error {{found in multiple base}}
+#endif
+ }
+}
+
+// dr40: na
+
+namespace dr41 { // dr41: yes
+ struct S f(S);
+}
+
+namespace dr42 { // dr42: yes
+ struct A { static const int k = 0; };
+ struct B : A { static const int k = A::k; };
+}
+
+// dr43: na
+
+namespace dr44 { // dr44: yes
+ struct A {
+ template<int> void f();
+ template<> void f<0>(); // expected-error {{explicit specialization of 'f' in class scope}}
+ };
+}
+
+namespace dr45 { // dr45: yes
+ class A {
+ class B {};
+ class C : B {};
+ C c;
+ };
+}
+
+namespace dr46 { // dr46: yes
+ template<typename> struct A { template<typename> struct B {}; };
+ template template struct A<int>::B<int>; // expected-error {{expected unqualified-id}}
+}
+
+namespace dr47 { // dr47: no
+ template<typename T> struct A {
+ friend void f() { T t; }
+ };
+ A<int> a;
+ A<float> b;
+#if __cplusplus < 201103L
+ // expected-error@-5 {{redefinition}} expected-note@-5 {{previous}}
+ // expected-note@-3 {{instantiation of}}
+#else
+ void f();
+ // FIXME: We should produce some kind of error here. C++11 [temp.friend]p4
+ // says we instantiate 'f' when it's odr-used, but that doesn't imply that
+ // this is valid; we still have multiple definitions of 'f' even if we never
+ // instantiate any of them.
+ void g() { f(); }
+#endif
+}
+
+namespace dr48 { // dr48: yes
+ namespace {
+ struct S {
+ static const int m = 0;
+ static const int n = 0;
+ static const int o = 0;
+ };
+ }
+ int a = S::m;
+ // FIXME: We should produce a 'has internal linkage but is not defined'
+ // diagnostic for 'S::n'.
+ const int &b = S::n;
+ const int S::o;
+ const int &c = S::o;
+}
+
+namespace dr49 { // dr49: yes
+ template<int*> struct A {}; // expected-note {{here}}
+ int k;
+#if __has_feature(cxx_constexpr)
+ constexpr
+#endif
+ int *const p = &k;
+ A<&k> a;
+ A<p> b; // expected-error {{must have its address taken}}
+#if __cplusplus < 201103L
+ // expected-error@-2 {{internal linkage}}
+ // expected-note@-5 {{here}}
+#endif
+}
+
+namespace dr50 { // dr50: yes
+ struct X; // expected-note {{forward}}
+ extern X *p;
+ X *q = (X*)p;
+ X *r = static_cast<X*>(p);
+ X *s = const_cast<X*>(p);
+ X *t = reinterpret_cast<X*>(p);
+ X *u = dynamic_cast<X*>(p); // expected-error {{incomplete}}
+}
+
+namespace dr51 { // dr51: yes
+ struct A {};
+ struct B : A {};
+ struct S {
+ operator A&();
+ operator B&();
+ } s;
+ A &a = s;
+}
+
+namespace dr52 { // dr52: yes
+ struct A { int n; }; // expected-note {{here}}
+ struct B : private A {} b; // expected-note 2{{private}}
+ // FIXME: This first diagnostic is very strangely worded, and seems to be bogus.
+ int k = b.A::n; // expected-error {{'A' is a private member of 'dr52::A'}}
+ // expected-error@-1 {{cannot cast 'struct B' to its private base}}
+}
+
+namespace dr53 { // dr53: yes
+ int n = 0;
+ enum E { e } x = static_cast<E>(n);
+}
+
+namespace dr54 { // dr54: yes
+ struct A { int a; } a;
+ struct V { int v; } v;
+ struct B : private A, virtual V { int b; } b; // expected-note 6{{private here}}
+
+ A &sab = static_cast<A&>(b); // expected-error {{private base}}
+ A *spab = static_cast<A*>(&b); // expected-error {{private base}}
+ int A::*smab = static_cast<int A::*>(&B::b); // expected-error {{private base}}
+ B &sba = static_cast<B&>(a); // expected-error {{private base}}
+ B *spba = static_cast<B*>(&a); // expected-error {{private base}}
+ int B::*smba = static_cast<int B::*>(&A::a); // expected-error {{private base}}
+
+ V &svb = static_cast<V&>(b);
+ V *spvb = static_cast<V*>(&b);
+ int V::*smvb = static_cast<int V::*>(&B::b); // expected-error {{virtual base}}
+ B &sbv = static_cast<B&>(v); // expected-error {{virtual base}}
+ B *spbv = static_cast<B*>(&v); // expected-error {{virtual base}}
+ int B::*smbv = static_cast<int B::*>(&V::v); // expected-error {{virtual base}}
+
+ A &cab = (A&)(b);
+ A *cpab = (A*)(&b);
+ int A::*cmab = (int A::*)(&B::b);
+ B &cba = (B&)(a);
+ B *cpba = (B*)(&a);
+ int B::*cmba = (int B::*)(&A::a);
+
+ V &cvb = (V&)(b);
+ V *cpvb = (V*)(&b);
+ int V::*cmvb = (int V::*)(&B::b); // expected-error {{virtual base}}
+ B &cbv = (B&)(v); // expected-error {{virtual base}}
+ B *cpbv = (B*)(&v); // expected-error {{virtual base}}
+ int B::*cmbv = (int B::*)(&V::v); // expected-error {{virtual base}}
+}
+
+namespace dr55 { // dr55: yes
+ enum E { e = 5 };
+ int test[(e + 1 == 6) ? 1 : -1];
+}
+
+namespace dr56 { // dr56: yes
+ struct A {
+ typedef int T; // expected-note {{previous}}
+ typedef int T; // expected-error {{redefinition}}
+ };
+ struct B {
+ struct X;
+ typedef X X; // expected-note {{previous}}
+ typedef X X; // expected-error {{redefinition}}
+ };
+}
+
+namespace dr58 { // dr58: yes
+ // FIXME: Ideally, we should have a CodeGen test for this.
+#if __cplusplus >= 201103L
+ enum E1 { E1_0 = 0, E1_1 = 1 };
+ enum E2 { E2_0 = 0, E2_m1 = -1 };
+ struct X { E1 e1 : 1; E2 e2 : 1; };
+ static_assert(X{E1_1, E2_m1}.e1 == 1, "");
+ static_assert(X{E1_1, E2_m1}.e2 == -1, "");
+#endif
+}
+
+namespace dr59 { // dr59: yes
+ template<typename T> struct convert_to { operator T() const; };
+ struct A {}; // expected-note 2{{volatile qualifier}}
+ struct B : A {}; // expected-note 2{{volatile qualifier}}
+#if __cplusplus >= 201103L // move constructors
+ // expected-note@-3 2{{volatile qualifier}}
+ // expected-note@-3 2{{volatile qualifier}}
+#endif
+
+ A a1 = convert_to<A>();
+ A a2 = convert_to<A&>();
+ A a3 = convert_to<const A>();
+ A a4 = convert_to<const volatile A>(); // expected-error {{no viable}}
+ A a5 = convert_to<const volatile A&>(); // expected-error {{no viable}}
+
+ B b1 = convert_to<B>();
+ B b2 = convert_to<B&>();
+ B b3 = convert_to<const B>();
+ B b4 = convert_to<const volatile B>(); // expected-error {{no viable}}
+ B b5 = convert_to<const volatile B&>(); // expected-error {{no viable}}
+
+ int n1 = convert_to<int>();
+ int n2 = convert_to<int&>();
+ int n3 = convert_to<const int>();
+ int n4 = convert_to<const volatile int>();
+ int n5 = convert_to<const volatile int&>();
+}
+
+namespace dr60 { // dr60: yes
+ void f(int &);
+ int &f(...);
+ const int k = 0;
+ int &n = f(k);
+}
+
+namespace dr61 { // dr61: yes
+ struct X {
+ static void f();
+ } x;
+ struct Y {
+ static void f();
+ static void f(int);
+ } y;
+ // This is (presumably) valid, because x.f does not refer to an overloaded
+ // function name.
+ void (*p)() = &x.f;
+ void (*q)() = &y.f; // expected-error {{cannot create a non-constant pointer to member function}}
+ void (*r)() = y.f; // expected-error {{cannot create a non-constant pointer to member function}}
+}
+
+namespace dr62 { // dr62: yes
+ struct A {
+ struct { int n; } b;
+ };
+ template<typename T> struct X {};
+ template<typename T> T get() { return get<T>(); }
+ template<typename T> int take(T) { return 0; }
+
+ X<A> x1;
+ A a = get<A>();
+
+ typedef struct { } *NoNameForLinkagePtr;
+#if __cplusplus < 201103L
+ // expected-note@-2 5{{here}}
+#endif
+ NoNameForLinkagePtr noNameForLinkagePtr;
+
+ struct Danger {
+ NoNameForLinkagePtr p;
+ };
+
+ X<NoNameForLinkagePtr> x2;
+ X<const NoNameForLinkagePtr> x3;
+ NoNameForLinkagePtr p1 = get<NoNameForLinkagePtr>();
+ NoNameForLinkagePtr p2 = get<const NoNameForLinkagePtr>();
+ int n1 = take(noNameForLinkagePtr);
+#if __cplusplus < 201103L
+ // expected-error@-6 {{uses unnamed type}}
+ // expected-error@-6 {{uses unnamed type}}
+ // expected-error@-6 {{uses unnamed type}}
+ // expected-error@-6 {{uses unnamed type}}
+ // expected-error@-6 {{uses unnamed type}}
+#endif
+
+ X<Danger> x4;
+
+ void f() {
+ struct NoLinkage {};
+ X<NoLinkage> a;
+ X<const NoLinkage> b;
+ get<NoLinkage>();
+ get<const NoLinkage>();
+ X<void (*)(NoLinkage A::*)> c;
+ X<int NoLinkage::*> d;
+#if __cplusplus < 201103L
+ // expected-error@-7 {{uses local type}}
+ // expected-error@-7 {{uses local type}}
+ // expected-error@-7 {{uses local type}}
+ // expected-error@-7 {{uses local type}}
+ // expected-error@-7 {{uses local type}}
+ // expected-error@-7 {{uses local type}}
+#endif
+ }
+}
+
+namespace dr63 { // dr63: yes
+ template<typename T> struct S { typename T::error e; };
+ extern S<int> *p;
+ void *q = p;
+}
+
+namespace dr64 { // dr64: yes
+ template<class T> void f(T);
+ template<class T> void f(T*);
+ template<> void f(int*);
+ template<> void f<int>(int*);
+ template<> void f(int);
+}
+
+// dr65: na
+
+namespace dr66 { // dr66: no
+ namespace X {
+ int f(int n); // expected-note 2{{candidate}}
+ }
+ using X::f;
+ namespace X {
+ int f(int n = 0);
+ int f(int, int);
+ }
+ // FIXME: The first two calls here should be accepted.
+ int a = f(); // expected-error {{no matching function}}
+ int b = f(1);
+ int c = f(1, 2); // expected-error {{no matching function}}
+}
+
+// dr67: na
+
+namespace dr68 { // dr68: yes
+ template<typename T> struct X {};
+ struct ::dr68::X<int> x1;
+ struct ::dr68::template X<int> x2;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{'template' keyword outside of a template}}
+#endif
+ struct Y {
+ friend struct X<int>;
+ friend struct ::dr68::X<char>;
+ friend struct ::dr68::template X<double>;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{'template' keyword outside of a template}}
+#endif
+ };
+ template<typename>
+ struct Z {
+ friend struct ::dr68::template X<double>;
+ friend typename ::dr68::X<double>;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{C++11 extension}}
+#endif
+ };
+}
+
+namespace dr69 { // dr69: yes
+ template<typename T> static void f() {}
+ // FIXME: Should we warn here?
+ inline void g() { f<int>(); }
+ // FIXME: This should be rejected, per [temp.explicit]p11.
+ extern template void f<char>();
+#if __cplusplus < 201103L
+ // expected-error@-2 {{C++11 extension}}
+#endif
+ template<void(*)()> struct Q {};
+ Q<&f<int> > q;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{internal linkage}} expected-note@-11 {{here}}
+#endif
+}
+
+namespace dr70 { // dr70: yes
+ template<int> struct A {};
+ template<int I, int J> int f(int (&)[I + J], A<I>, A<J>);
+ int arr[7];
+ int k = f(arr, A<3>(), A<4>());
+}
+
+// dr71: na
+// dr72: dup 69
+
+#if __cplusplus >= 201103L
+namespace dr73 { // dr73: no
+ // The resolution to dr73 is unworkable. Consider:
+ int a, b;
+ static_assert(&a + 1 != &b, "");
+}
+#endif
+
+namespace dr74 { // dr74: yes
+ enum E { k = 5 };
+ int (*p)[k] = new int[k][k];
+}
+
+namespace dr75 { // dr75: yes
+ struct S {
+ static int n = 0; // expected-error {{non-const}}
+ };
+}
+
+namespace dr76 { // dr76: yes
+ const volatile int n = 1;
+ int arr[n]; // expected-error +{{variable length array}}
+}
+
+namespace dr77 { // dr77: yes
+ struct A {
+ struct B {};
+ friend struct B;
+ };
+}
+
+namespace dr78 { // dr78: sup ????
+ // Under DR78, this is valid, because 'k' has static storage duration, so is
+ // zero-initialized.
+ const int k; // expected-error {{default initialization of an object of const}}
+}
+
+// dr79: na
+
+namespace dr80 { // dr80: yes
+ struct A {
+ int A;
+ };
+ struct B {
+ static int B; // expected-error {{same name as its class}}
+ };
+ struct C {
+ int C; // expected-note {{hidden by}}
+ // FIXME: These diagnostics aren't very good.
+ C(); // expected-error {{must use 'struct' tag to refer to}} expected-error {{expected member name}}
+ };
+ struct D {
+ D();
+ int D; // expected-error {{same name as its class}}
+ };
+}
+
+// dr81: na
+// dr82: dup 48
+
+namespace dr83 { // dr83: yes
+ int &f(const char*);
+ char &f(char *);
+ int &k = f("foo");
+}
+
+namespace dr84 { // dr84: yes
+ struct B;
+ struct A { operator B() const; };
+ struct C {};
+ struct B {
+ B(B&); // expected-note {{candidate}}
+ B(C);
+ operator C() const;
+ };
+ A a;
+ // Cannot use B(C) / operator C() pair to construct the B from the B temporary
+ // here.
+ B b = a; // expected-error {{no viable}}
+}
+
+namespace dr85 { // dr85: yes
+ struct A {
+ struct B;
+ struct B {}; // expected-note{{previous declaration is here}}
+ struct B; // expected-error{{class member cannot be redeclared}}
+
+ union U;
+ union U {}; // expected-note{{previous declaration is here}}
+ union U; // expected-error{{class member cannot be redeclared}}
+
+#if __cplusplus >= 201103L
+ enum E1 : int;
+ enum E1 : int { e1 }; // expected-note{{previous declaration is here}}
+ enum E1 : int; // expected-error{{class member cannot be redeclared}}
+
+ enum class E2;
+ enum class E2 { e2 }; // expected-note{{previous declaration is here}}
+ enum class E2; // expected-error{{class member cannot be redeclared}}
+#endif
+ };
+
+ template <typename T>
+ struct C {
+ struct B {}; // expected-note{{previous declaration is here}}
+ struct B; // expected-error{{class member cannot be redeclared}}
+ };
+}
+
+// dr86: dup 446
+
+namespace dr87 { // dr87: no
+ template<typename T> struct X {};
+ // FIXME: This is invalid.
+ X<void() throw()> x;
+ // ... but this is valid.
+ X<void(void() throw())> y;
+}
+
+namespace dr88 { // dr88: yes
+ template<typename T> struct S {
+ static const int a = 1;
+ static const int b;
+ };
+ // FIXME: This diagnostic is pretty bad.
+ template<> const int S<int>::a = 4; // expected-error {{redefinition}} expected-note {{previous}}
+ template<> const int S<int>::b = 4;
+}
+
+// dr89: na
+
+namespace dr90 { // dr90: yes
+ struct A {
+ template<typename T> friend void dr90_f(T);
+ };
+ struct B : A {
+ template<typename T> friend void dr90_g(T);
+ struct C {};
+ union D {};
+ };
+ struct E : B {};
+ struct F : B::C {};
+
+ void test() {
+ dr90_f(A());
+ dr90_f(B());
+ dr90_f(B::C()); // expected-error {{undeclared identifier}}
+ dr90_f(B::D()); // expected-error {{undeclared identifier}}
+ dr90_f(E());
+ dr90_f(F()); // expected-error {{undeclared identifier}}
+
+ dr90_g(A()); // expected-error {{undeclared identifier}}
+ dr90_g(B());
+ dr90_g(B::C());
+ dr90_g(B::D());
+ dr90_g(E());
+ dr90_g(F()); // expected-error {{undeclared identifier}}
+ }
+}
+
+namespace dr91 { // dr91: yes
+ union U { friend int f(U); };
+ int k = f(U());
+}
+
+// dr93: na
+
+namespace dr94 { // dr94: yes
+ struct A { static const int n = 5; };
+ int arr[A::n];
+}
+
+namespace dr95 { // dr95: yes
+ struct A;
+ struct B;
+ namespace N {
+ class C {
+ friend struct A;
+ friend struct B;
+ static void f(); // expected-note {{here}}
+ };
+ struct A *p; // dr95::A, not dr95::N::A.
+ }
+ A *q = N::p; // ok, same type
+ struct B { void f() { N::C::f(); } }; // expected-error {{private}}
+}
+
+namespace dr96 { // dr96: no
+ struct A {
+ void f(int);
+ template<typename T> int f(T);
+ template<typename T> struct S {};
+ } a;
+ template<template<typename> class X> struct B {};
+
+ template<typename T>
+ void test() {
+ int k1 = a.template f<int>(0);
+ // FIXME: This is ill-formed, because 'f' is not a template-id and does not
+ // name a class template.
+ // FIXME: What about alias templates?
+ int k2 = a.template f(1);
+ A::template S<int> s;
+ B<A::template S> b;
+ }
+}
+
+namespace dr97 { // dr97: yes
+ struct A {
+ static const int a = false;
+ static const int b = !a;
+ };
+}
+
+namespace dr98 { // dr98: yes
+ void test(int n) {
+ switch (n) {
+ try { // expected-note 2{{bypasses}}
+ case 0: // expected-error {{protected}}
+ x:
+ throw n;
+ } catch (...) { // expected-note 2{{bypasses}}
+ case 1: // expected-error {{protected}}
+ y:
+ throw n;
+ }
+ case 2:
+ goto x; // expected-error {{protected}}
+ case 3:
+ goto y; // expected-error {{protected}}
+ }
+ }
+}
+
+namespace dr99 { // dr99: sup 214
+ template<typename T> void f(T&);
+ template<typename T> int &f(const T&);
+ const int n = 0;
+ int &r = f(n);
+}
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
new file mode 100644
index 000000000000..7045148034fb
--- /dev/null
+++ b/test/CXX/drs/dr1xx.cpp
@@ -0,0 +1,1011 @@
+// 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++1y -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr100 { // dr100: yes
+ template<const char *> struct A {}; // expected-note {{declared here}}
+ template<const char (&)[4]> struct B {}; // expected-note {{declared here}}
+ A<"foo"> a; // expected-error {{does not refer to any declaration}}
+ B<"bar"> b; // expected-error {{does not refer to any declaration}}
+}
+
+namespace dr101 { // dr101: yes
+ extern "C" void dr101_f();
+ typedef unsigned size_t;
+ namespace X {
+ extern "C" void dr101_f();
+ typedef unsigned size_t;
+ }
+ using X::dr101_f;
+ using X::size_t;
+}
+
+namespace dr102 { // dr102: yes
+ namespace A {
+ template<typename T> T f(T a, T b) { return a + b; } // expected-error {{neither visible in the template definition nor found by argument-dependent lookup}}
+ }
+ namespace B {
+ struct S {};
+ }
+ B::S operator+(B::S, B::S); // expected-note {{should be declared prior to the call site or in namespace 'dr102::B'}}
+ template B::S A::f(B::S, B::S); // expected-note {{in instantiation of}}
+}
+
+// dr103: na
+// dr104 FIXME: add codegen test
+// dr105: na
+
+namespace dr106 { // dr106: sup 540
+ typedef int &r1;
+ typedef r1 &r1;
+ typedef const r1 r1;
+ typedef const r1 &r1;
+
+ typedef const int &r2;
+ typedef r2 &r2;
+ typedef const r2 r2;
+ typedef const r2 &r2;
+}
+
+namespace dr107 { // dr107: yes
+ struct S {};
+ extern "C" S operator+(S, S) { return S(); }
+}
+
+namespace dr108 { // dr108: yes
+ template<typename T> struct A {
+ struct B { typedef int X; };
+ B::X x; // expected-error {{missing 'typename'}}
+ struct C : B { X x; }; // expected-error {{unknown type name}}
+ };
+ template<> struct A<int>::B { int X; };
+}
+
+namespace dr109 { // dr109: yes
+ struct A { template<typename T> void f(T); };
+ template<typename T> struct B : T {
+ using T::template f; // expected-error {{using declaration can not refer to a template}}
+ void g() { this->f<int>(123); } // expected-error {{use 'template'}}
+ };
+}
+
+namespace dr111 { // dr111: dup 535
+ struct A { A(); A(volatile A&, int = 0); A(A&, const char * = "foo"); };
+ struct B : A { B(); }; // expected-note +{{would lose const qualifier}} expected-note {{requires 0 arguments}}
+ const B b1;
+ B b2(b1); // expected-error {{no matching constructor}}
+}
+
+namespace dr112 { // dr112: yes
+ struct T { int n; };
+ typedef T Arr[1];
+
+ const T a1[1] = {};
+ volatile T a2[1] = {};
+ const Arr a3 = {};
+ volatile Arr a4 = {};
+ template<const volatile T*> struct X {};
+ X<a1> x1;
+ X<a2> x2;
+ X<a3> x3;
+ X<a4> x4;
+#if __cplusplus < 201103L
+ // expected-error@-5 {{internal linkage}} expected-note@-10 {{here}}
+ // expected-error@-4 {{internal linkage}} expected-note@-9 {{here}}
+#else
+ // FIXME: Test this somehow.
+#endif
+}
+
+namespace dr113 { // dr113: yes
+ extern void (*p)();
+ void f() {
+ no_such_function(); // expected-error {{undeclared}}
+ p();
+ }
+ void g();
+ void (*p)() = &g;
+}
+
+namespace dr114 { // dr114: yes
+ struct A {
+ virtual void f(int) = 0; // expected-note {{unimplemented}}
+ };
+ struct B : A {
+ template<typename T> void f(T);
+ void g() { f(0); }
+ } b; // expected-error {{abstract}}
+}
+
+namespace dr115 { // dr115: yes
+ template<typename T> int f(T); // expected-note +{{}}
+ template<typename T> int g(T); // expected-note +{{}}
+ template<typename T> int g(T, int); // expected-note +{{}}
+
+ int k1 = f(&f); // expected-error {{no match}}
+ int k2 = f(&f<int>);
+ int k3 = f(&g<int>); // expected-error {{no match}}
+
+ void h() {
+ (void)&f; // expected-error {{address of overloaded function 'f' cannot be cast to type 'void'}}
+ (void)&f<int>;
+ (void)&g<int>; // expected-error {{address of overloaded function 'g' cannot be cast to type 'void'}}
+
+ &f; // expected-error {{reference to overloaded function could not be resolved}}
+ &f<int>; // expected-warning {{unused}}
+ &g<int>; // expected-error {{reference to overloaded function could not be resolved}}
+ }
+
+ struct S {
+ template<typename T> static int f(T);
+ template<typename T> static int g(T);
+ template<typename T> static int g(T, int);
+ } s;
+
+ int k4 = f(&s.f); // expected-error {{non-constant pointer to member}}
+ int k5 = f(&s.f<int>);
+ int k6 = f(&s.g<int>); // expected-error {{non-constant pointer to member}}
+
+ void i() {
+ (void)&s.f; // expected-error {{non-constant pointer to member}}
+ (void)&s.f<int>;
+ (void)&s.g<int>; // expected-error {{non-constant pointer to member}}
+
+ &s.f; // expected-error {{non-constant pointer to member}}
+ &s.f<int>; // expected-warning {{unused}}
+ &s.g<int>; // expected-error {{non-constant pointer to member}}
+ }
+
+ struct T {
+ template<typename T> int f(T);
+ template<typename T> int g(T);
+ template<typename T> int g(T, int);
+ } t;
+
+ int k7 = f(&s.f); // expected-error {{non-constant pointer to member}}
+ int k8 = f(&s.f<int>);
+ int k9 = f(&s.g<int>); // expected-error {{non-constant pointer to member}}
+
+ void j() {
+ (void)&s.f; // expected-error {{non-constant pointer to member}}
+ (void)&s.f<int>;
+ (void)&s.g<int>; // expected-error {{non-constant pointer to member}}
+
+ &s.f; // expected-error {{non-constant pointer to member}}
+ &s.f<int>; // expected-warning {{unused}}
+ &s.g<int>; // expected-error {{non-constant pointer to member}}
+ }
+
+#if __cplusplus >= 201103L
+ // Special case kicks in only if a template argument list is specified.
+ template<typename T=int> void with_default(); // expected-note +{{}}
+ int k10 = f(&with_default); // expected-error {{no matching function}}
+ int k11 = f(&with_default<>);
+ void k() {
+ (void)&with_default; // expected-error {{overloaded function}}
+ (void)&with_default<>;
+ &with_default; // expected-error {{overloaded function}}
+ &with_default<>; // expected-warning {{unused}}
+ }
+#endif
+}
+
+namespace dr116 { // dr116: yes
+ template<int> struct A {};
+ template<int N> void f(A<N>) {} // expected-note {{previous}}
+ template<int M> void f(A<M>) {} // expected-error {{redefinition}}
+ template<typename T> void f(A<sizeof(T)>) {} // expected-note {{previous}}
+ template<typename U> void f(A<sizeof(U)>) {} // expected-error {{redefinition}}
+}
+
+// dr117: na
+// dr118 FIXME: add codegen test
+// dr119: na
+// dr120: na
+
+namespace dr121 { // dr121: yes
+ struct X {
+ template<typename T> struct Y {};
+ };
+ template<typename T> struct Z {
+ X::Y<T> x;
+ T::Y<T> y; // expected-error +{{}}
+ };
+ Z<X> z;
+}
+
+namespace dr122 { // dr122: yes
+ template<typename T> void f();
+ void g() { f<int>(); }
+}
+
+// dr123: na
+// dr124: dup 201
+
+// dr125: yes
+struct dr125_A { struct dr125_B {}; }; // expected-note {{here}}
+dr125_A::dr125_B dr125_C();
+namespace dr125_B { dr125_A dr125_C(); }
+namespace dr125 {
+ struct X {
+ friend dr125_A::dr125_B (::dr125_C)(); // ok
+ friend dr125_A (::dr125_B::dr125_C)(); // ok
+ friend dr125_A::dr125_B::dr125_C(); // expected-error {{did you mean the constructor name 'dr125_B'?}}
+ // expected-warning@-1 {{missing exception specification}}
+#if __cplusplus >= 201103L
+ // expected-error@-3 {{follows constexpr declaration}} expected-note@-10 {{here}}
+#endif
+ };
+}
+
+namespace dr126 { // dr126: no
+ struct C {};
+ struct D : C {};
+ struct E : private C { friend class A; friend class B; };
+ struct F : protected C {};
+ struct G : C {};
+ struct H : D, G {};
+
+ struct A {
+ virtual void cp() throw(C*);
+ virtual void dp() throw(C*);
+ virtual void ep() throw(C*); // expected-note {{overridden}}
+ virtual void fp() throw(C*); // expected-note {{overridden}}
+ virtual void gp() throw(C*);
+ virtual void hp() throw(C*); // expected-note {{overridden}}
+
+ virtual void cr() throw(C&);
+ virtual void dr() throw(C&);
+ virtual void er() throw(C&); // expected-note {{overridden}}
+ virtual void fr() throw(C&); // expected-note {{overridden}}
+ virtual void gr() throw(C&);
+ virtual void hr() throw(C&); // expected-note {{overridden}}
+
+ virtual void pv() throw(void*); // expected-note {{overridden}}
+
+#if __cplusplus >= 201103L
+ virtual void np() throw(C*); // expected-note {{overridden}}
+ virtual void npm() throw(int C::*); // expected-note {{overridden}}
+ virtual void nr() throw(C&); // expected-note {{overridden}}
+#endif
+
+ virtual void ref1() throw(C *const&);
+ virtual void ref2() throw(C *);
+
+ virtual void v() throw(int);
+ virtual void w() throw(const int);
+ virtual void x() throw(int*);
+ virtual void y() throw(const int*);
+ virtual void z() throw(int); // expected-note {{overridden}}
+ };
+ struct B : A {
+ virtual void cp() throw(C*);
+ virtual void dp() throw(D*);
+ virtual void ep() throw(E*); // expected-error {{more lax}}
+ virtual void fp() throw(F*); // expected-error {{more lax}}
+ virtual void gp() throw(G*);
+ virtual void hp() throw(H*); // expected-error {{more lax}}
+
+ virtual void cr() throw(C&);
+ virtual void dr() throw(D&);
+ virtual void er() throw(E&); // expected-error {{more lax}}
+ virtual void fr() throw(F&); // expected-error {{more lax}}
+ virtual void gr() throw(G&);
+ virtual void hr() throw(H&); // expected-error {{more lax}}
+
+ virtual void pv() throw(C*); // expected-error {{more lax}} FIXME: This is valid.
+
+#if __cplusplus >= 201103L
+ using nullptr_t = decltype(nullptr);
+ virtual void np() throw(nullptr_t*); // expected-error {{more lax}} FIXME: This is valid.
+ virtual void npm() throw(nullptr_t*); // expected-error {{more lax}} FIXME: This is valid.
+ virtual void nr() throw(nullptr_t&); // expected-error {{more lax}} This is not.
+#endif
+
+ virtual void ref1() throw(D *const &);
+ virtual void ref2() throw(D *);
+
+ virtual void v() throw(const int);
+ virtual void w() throw(int);
+ virtual void x() throw(const int*); // FIXME: 'const int*' is not allowed by A::h.
+ virtual void y() throw(int*); // ok
+ virtual void z() throw(long); // expected-error {{more lax}}
+ };
+}
+
+namespace dr127 { // dr127: yes
+ __extension__ typedef __decltype(sizeof(0)) size_t;
+ template<typename T> struct A {
+ A() throw(int);
+ void *operator new(size_t, const char * = 0);
+ void operator delete(void *, const char *) { T::error; } // expected-error 2{{no members}}
+ void operator delete(void *) { T::error; }
+ };
+ A<void> *p = new A<void>; // expected-note {{instantiat}}
+ A<int> *q = new ("") A<int>; // expected-note {{instantiat}}
+}
+
+namespace dr128 { // dr128: yes
+ enum E1 { e1 } x = e1;
+ enum E2 { e2 } y = static_cast<E2>(x), z = static_cast<E2>(e1);
+}
+
+// dr129: dup 616
+// dr130: na
+
+namespace dr131 { // dr131: yes
+ const char *a_with_\u0e8c = "\u0e8c";
+ const char *b_with_\u0e8d = "\u0e8d";
+ const char *c_with_\u0e8e = "\u0e8e";
+#if __cplusplus < 201103L
+ // expected-error@-4 {{expected ';'}} expected-error@-2 {{expected ';'}}
+#endif
+}
+
+namespace dr132 { // dr132: no
+ void f() {
+ extern struct {} x; // ok
+ extern struct S {} y; // FIXME: This is invalid.
+ }
+ static enum { E } e;
+}
+
+// dr133: dup 87
+// dr134: na
+
+namespace dr135 { // dr135: yes
+ struct A {
+ A f(A a) { return a; }
+ friend A g(A a) { return a; }
+ static A h(A a) { return a; }
+ };
+}
+
+namespace dr136 { // dr136: 3.4
+ void f(int, int, int = 0); // expected-note {{previous declaration is here}}
+ void g(int, int, int); // expected-note {{previous declaration is here}}
+ struct A {
+ friend void f(int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ friend void g(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ friend void h(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}}
+ friend void i(int, int, int = 0) {} // expected-note {{previous declaration is here}}
+ friend void j(int, int, int = 0) {}
+ operator int();
+ };
+ void i(int, int, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ void q() {
+ j(A(), A()); // ok, has default argument
+ }
+ extern "C" void k(int, int, int, int); // expected-note {{previous declaration is here}}
+ namespace NSA {
+ struct A {
+ friend void dr136::k(int, int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}} \
+ // expected-note {{previous declaration is here}}
+ };
+ }
+ namespace NSB {
+ struct A {
+ friend void dr136::k(int, int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ };
+ }
+ struct B {
+ void f(int); // expected-note {{previous declaration is here}}
+ };
+ struct C {
+ friend void B::f(int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
+ };
+}
+
+namespace dr137 { // dr137: yes
+ extern void *p;
+ extern const void *cp;
+ extern volatile void *vp;
+ extern const volatile void *cvp;
+ int *q = static_cast<int*>(p);
+ int *qc = static_cast<int*>(cp); // expected-error {{casts away qualifiers}}
+ int *qv = static_cast<int*>(vp); // expected-error {{casts away qualifiers}}
+ int *qcv = static_cast<int*>(cvp); // expected-error {{casts away qualifiers}}
+ const int *cq = static_cast<const int*>(p);
+ const int *cqc = static_cast<const int*>(cp);
+ const int *cqv = static_cast<const int*>(vp); // expected-error {{casts away qualifiers}}
+ const int *cqcv = static_cast<const int*>(cvp); // expected-error {{casts away qualifiers}}
+ const volatile int *cvq = static_cast<const volatile int*>(p);
+ const volatile int *cvqc = static_cast<const volatile int*>(cp);
+ const volatile int *cvqv = static_cast<const volatile int*>(vp);
+ const volatile int *cvqcv = static_cast<const volatile int*>(cvp);
+}
+
+namespace dr139 { // dr139: yes
+ namespace example1 {
+ typedef int f; // expected-note {{previous}}
+ struct A {
+ friend void f(A &); // expected-error {{different kind of symbol}}
+ };
+ }
+
+ namespace example2 {
+ typedef int f;
+ namespace N {
+ struct A {
+ friend void f(A &);
+ operator int();
+ void g(A a) { int i = f(a); } // ok, f is typedef not friend function
+ };
+ }
+ }
+}
+
+namespace dr140 { // dr140: yes
+ void f(int *const) {} // expected-note {{previous}}
+ void f(int[3]) {} // expected-error {{redefinition}}
+ void g(const int);
+ void g(int n) { n = 2; }
+}
+
+namespace dr141 { // dr141: yes
+ template<typename T> void f();
+ template<typename T> struct S { int n; };
+ struct A : S<int> {
+ template<typename T> void f();
+ template<typename T> struct S {};
+ } a;
+ struct B : S<int> {} b;
+ void g() {
+ a.f<int>();
+ (void)a.S<int>::n; // expected-error {{no member named 'n'}}
+#if __cplusplus < 201103L
+ // expected-error@-2 {{ambiguous}}
+ // expected-note@-11 {{lookup from the current scope}}
+ // expected-note@-9 {{lookup in the object type}}
+#endif
+ b.f<int>(); // expected-error {{no member}} expected-error +{{}}
+ (void)b.S<int>::n;
+ }
+ template<typename T> struct C {
+ T t;
+ void g() {
+ t.f<int>(); // expected-error {{use 'template'}}
+ }
+ void h() {
+ (void)t.S<int>::n; // ok
+ }
+ void i() {
+ (void)t.S<int>(); // ok!
+ }
+ };
+ void h() { C<B>().h(); } // ok
+ struct X {
+ template<typename T> void S();
+ };
+ void i() { C<X>().i(); } // ok!!
+}
+
+namespace dr142 { // dr142: yes
+ class B { // expected-note +{{here}}
+ public:
+ int mi; // expected-note +{{here}}
+ static int si; // expected-note +{{here}}
+ };
+ class D : private B { // expected-note +{{here}}
+ };
+ class DD : public D {
+ void f();
+ };
+ void DD::f() {
+ mi = 3; // expected-error {{private base class}} expected-error {{private member}}
+ si = 3; // expected-error {{private member}}
+ B b_old; // expected-error {{private member}}
+ dr142::B b;
+ b.mi = 3;
+ b.si = 3;
+ B::si = 3; // expected-error {{private member}}
+ dr142::B::si = 3;
+ B *bp1_old = this; // expected-error {{private member}} expected-error {{private base class}}
+ dr142::B *bp1 = this; // expected-error {{private base class}}
+ B *bp2_old = (B*)this; // expected-error 2{{private member}}
+ dr142::B *bp2 = (dr142::B*)this;
+ bp2->mi = 3;
+ }
+}
+
+namespace dr143 { // dr143: yes
+ namespace A { struct X; }
+ namespace B { void f(A::X); }
+ namespace A {
+ struct X { friend void B::f(X); };
+ }
+ void g(A::X x) {
+ f(x); // expected-error {{undeclared identifier 'f'}}
+ }
+}
+
+namespace dr145 { // dr145: yes
+ void f(bool b) {
+ ++b; // expected-warning {{deprecated}}
+ b++; // expected-warning {{deprecated}}
+ }
+}
+
+namespace dr147 { // dr147: no
+ namespace example1 {
+ template<typename> struct A {
+ template<typename T> A(T);
+ };
+ // FIXME: This appears to be valid, and EDG and G++ accept.
+ template<> template<> A<int>::A<int>(int) {} // expected-error {{out-of-line constructor for 'A' cannot have template arguments}}
+ }
+ namespace example2 {
+ struct A { A(); };
+ struct B : A { B(); };
+ A::A a1; // expected-error {{is a constructor}}
+ B::A a2;
+ }
+ namespace example3 {
+ template<typename> struct A {
+ template<typename T> A(T);
+ static A a;
+ };
+ template<> A<int>::A<int>(A<int>::a); // expected-error {{is a constructor}}
+ }
+}
+
+namespace dr148 { // dr148: yes
+ struct A { int A::*p; };
+ int check1[__is_pod(int(A::*)) ? 1 : -1];
+ int check2[__is_pod(A) ? 1 : -1];
+}
+
+// dr149: na
+
+namespace dr151 { // dr151: yes
+ struct X {};
+ typedef int X::*p;
+#if __cplusplus < 201103L
+#define fold(x) (__builtin_constant_p(0) ? (x) : (x))
+#else
+#define fold
+#endif
+ int check[fold(p() == 0) ? 1 : -1];
+#undef fold
+}
+
+namespace dr152 { // dr152: yes
+ struct A {
+ A(); // expected-note {{not viable}}
+ explicit A(const A&);
+ };
+ A a1 = A(); // expected-error {{no matching constructor}}
+ A a2((A()));
+}
+
+// dr153: na
+
+namespace dr154 { // dr154: yes
+ union { int a; }; // expected-error {{must be declared 'static'}}
+ namespace {
+ union { int b; };
+ }
+ static union { int c; };
+}
+
+namespace dr155 { // dr155: dup 632
+ struct S { int n; } s = { { 1 } }; // expected-warning {{braces around scalar initializer}}
+}
+
+namespace dr159 { // dr159: no
+ namespace X { void f(); }
+ void f();
+ // FIXME: This should be accepted.
+ void dr159::f() {} // expected-error {{extra qualification}}
+ void dr159::X::f() {}
+}
+
+// dr160: na
+
+namespace dr161 { // dr161: yes
+ class A {
+ protected:
+ struct B { int n; } b; // expected-note 2{{here}}
+ static B bs;
+ void f(); // expected-note {{here}}
+ static void sf();
+ };
+ struct C : A {};
+ struct D : A {
+ void g(C c) {
+ (void)b.n;
+ B b1;
+ C::B b2; // ok, accessible as a member of A
+ (void)&C::b; // expected-error {{protected}}
+ (void)&C::bs;
+ (void)c.b; // expected-error {{protected}}
+ (void)c.bs;
+ f();
+ sf();
+ c.f(); // expected-error {{protected}}
+ c.sf();
+ A::f();
+ D::f();
+ A::sf();
+ C::sf();
+ D::sf();
+ }
+ };
+}
+
+namespace dr162 { // dr162: no
+ struct A {
+ char &f(char);
+ static int &f(int);
+
+ void g() {
+ int &a = (&A::f)(0); // FIXME: expected-error {{could not be resolved}}
+ char &b = (&A::f)('0'); // expected-error {{could not be resolved}}
+ }
+ };
+
+ int &c = (&A::f)(0); // FIXME: expected-error {{could not be resolved}}
+ char &d = (&A::f)('0'); // expected-error {{could not be resolved}}
+}
+
+// dr163: na
+
+namespace dr164 { // dr164: yes
+ void f(int);
+ template <class T> int g(T t) { return f(t); }
+
+ enum E { e };
+ int f(E);
+
+ int k = g(e);
+}
+
+namespace dr165 { // dr165: no
+ namespace N {
+ struct A { friend struct B; };
+ void f() { void g(); }
+ }
+ // FIXME: dr1477 says this is ok, dr165 says it's ill-formed
+ struct N::B {};
+ // FIXME: dr165 says this is ill-formed, but the argument in dr1477 says it's ok
+ void N::g() {}
+}
+
+namespace dr166 { // dr166: yes
+ namespace A { class X; }
+
+ template<typename T> int f(T t) { return t.n; }
+ int g(A::X);
+ template<typename T> int h(T t) { return t.n; } // expected-error {{private}}
+ int i(A::X);
+
+ namespace A {
+ class X {
+ friend int f<X>(X);
+ friend int dr166::g(X);
+ friend int h(X);
+ friend int i(X);
+ int n; // expected-note 2{{here}}
+ };
+
+ int h(X x) { return x.n; }
+ int i(X x) { return x.n; }
+ }
+
+ template int f(A::X);
+ int g(A::X x) { return x.n; }
+ template int h(A::X); // expected-note {{instantiation}}
+ int i(A::X x) { return x.n; } // expected-error {{private}}
+}
+
+// dr167: sup 1012
+
+namespace dr168 { // dr168: no
+ extern "C" typedef int (*p)();
+ extern "C++" typedef int (*q)();
+ struct S {
+ static int f();
+ };
+ p a = &S::f; // FIXME: this should fail.
+ q b = &S::f;
+}
+
+namespace dr169 { // dr169: yes
+ template<typename> struct A { int n; };
+ struct B {
+ template<typename> struct C;
+ template<typename> void f();
+ template<typename> static int n; // expected-error 0-1{{extension}}
+ };
+ struct D : A<int>, B {
+ using A<int>::n;
+ using B::C<int>; // expected-error {{using declaration can not refer to a template specialization}}
+ using B::f<int>; // expected-error {{using declaration can not refer to a template specialization}}
+ using B::n<int>; // expected-error {{using declaration can not refer to a template specialization}}
+ };
+}
+
+namespace { // dr171: yes
+ int dr171a;
+}
+int dr171b; // expected-note {{here}}
+namespace dr171 {
+ extern "C" void dr171a();
+ extern "C" void dr171b(); // expected-error {{conflicts}}
+}
+
+namespace dr172 { // dr172: yes
+ enum { zero };
+ int check1[-1 < zero ? 1 : -1];
+
+ enum { x = -1, y = (unsigned int)-1 };
+ int check2[sizeof(x) > sizeof(int) ? 1 : -1];
+
+ enum { a = (unsigned int)-1 / 2 };
+ int check3a[sizeof(a) == sizeof(int) ? 1 : -1];
+ int check3b[-a < 0 ? 1 : -1];
+
+ enum { b = (unsigned int)-1 / 2 + 1 };
+ int check4a[sizeof(b) == sizeof(unsigned int) ? 1 : -1];
+ int check4b[-b > 0 ? 1 : -1];
+
+ enum { c = (unsigned long)-1 / 2 };
+ int check5a[sizeof(c) == sizeof(long) ? 1 : -1];
+ int check5b[-c < 0 ? 1 : -1];
+
+ enum { d = (unsigned long)-1 / 2 + 1 };
+ int check6a[sizeof(d) == sizeof(unsigned long) ? 1 : -1];
+ int check6b[-d > 0 ? 1 : -1];
+
+ enum { e = (unsigned long long)-1 / 2 }; // expected-error 0-1{{extension}}
+ int check7a[sizeof(e) == sizeof(long) ? 1 : -1]; // expected-error 0-1{{extension}}
+ int check7b[-e < 0 ? 1 : -1];
+
+ enum { f = (unsigned long long)-1 / 2 + 1 }; // expected-error 0-1{{extension}}
+ int check8a[sizeof(f) == sizeof(unsigned long) ? 1 : -1]; // expected-error 0-1{{extension}}
+ int check8b[-f > 0 ? 1 : -1];
+}
+
+namespace dr173 { // dr173: yes
+ int check[('0' + 1 == '1' && '0' + 2 == '2' && '0' + 3 == '3' &&
+ '0' + 4 == '4' && '0' + 5 == '5' && '0' + 6 == '6' &&
+ '0' + 7 == '7' && '0' + 8 == '8' && '0' + 9 == '9') ? 1 : -1];
+}
+
+// dr174: sup 1012
+
+namespace dr175 { // dr175: yes
+ struct A {}; // expected-note {{here}}
+ struct B : private A {}; // expected-note {{constrained by private inheritance}}
+ struct C : B {
+ A a; // expected-error {{private}}
+ dr175::A b;
+ };
+}
+
+namespace dr176 { // dr176: yes
+ template<typename T> class Y;
+ template<> class Y<int> {
+ void f() {
+ typedef Y A; // expected-note {{here}}
+ typedef Y<char> A; // expected-error {{different types ('Y<char>' vs 'Y<int>')}}
+ }
+ };
+
+ template<typename T> struct Base {}; // expected-note 2{{found}}
+ template<typename T> struct Derived : public Base<T> {
+ void f() {
+ typedef typename Derived::template Base<T> A;
+ typedef typename Derived::Base A;
+ }
+ };
+ template struct Derived<int>;
+
+ template<typename T> struct Derived2 : Base<int>, Base<char> {
+ typename Derived2::Base b; // expected-error {{found in multiple base classes}}
+ typename Derived2::Base<double> d;
+ };
+
+ template<typename T> class X { // expected-note {{here}}
+ X *p1;
+ X<T> *p2;
+ X<int> *p3;
+ dr176::X *p4; // expected-error {{requires template arguments}}
+ };
+}
+
+namespace dr177 { // dr177: yes
+ struct B {};
+ struct A {
+ A(A &); // expected-note {{not viable: expects an l-value}}
+ A(const B &);
+ };
+ B b;
+ A a = b; // expected-error {{no viable constructor copying variable}}
+}
+
+namespace dr178 { // dr178: yes
+ int check[int() == 0 ? 1 : -1];
+#if __cplusplus >= 201103L
+ static_assert(int{} == 0, "");
+ struct S { int a, b; };
+ static_assert(S{1}.b == 0, "");
+ struct T { constexpr T() : n() {} int n; };
+ static_assert(T().n == 0, "");
+ struct U : S { constexpr U() : S() {} };
+ static_assert(U().b == 0, "");
+#endif
+}
+
+namespace dr179 { // dr179: yes
+ void f();
+ int n = &f - &f; // expected-error {{arithmetic on pointers to the function type 'void ()'}}
+}
+
+namespace dr180 { // dr180: yes
+ template<typename T> struct X : T, T::some_base {
+ X() : T::some_type_that_might_be_T(), T::some_base() {}
+ friend class T::some_class;
+ void f() {
+ enum T::some_enum e;
+ }
+ };
+}
+
+namespace dr181 { // dr181: yes
+ namespace X {
+ template <template X<class T> > struct A { }; // expected-error +{{}}
+ template <template X<class T> > void f(A<X>) { } // expected-error +{{}}
+ }
+
+ namespace Y {
+ template <template <class T> class X> struct A { };
+ template <template <class T> class X> void f(A<X>) { }
+ }
+}
+
+namespace dr182 { // dr182: yes
+ template <class T> struct C {
+ void f();
+ void g();
+ };
+
+ template <class T> void C<T>::f() {}
+ template <class T> void C<T>::g() {}
+
+ class A {
+ class B {}; // expected-note {{here}}
+ void f();
+ };
+
+ template void C<A::B>::f();
+ template <> void C<A::B>::g(); // expected-error {{private}}
+
+ void A::f() {
+ C<B> cb;
+ cb.f();
+ }
+}
+
+namespace dr183 { // dr183: sup 382
+ template<typename T> struct A {};
+ template<typename T> struct B {
+ typedef int X;
+ };
+ template<> struct A<int> {
+ typename B<int>::X x;
+ };
+}
+
+namespace dr184 { // dr184: yes
+ template<typename T = float> struct B {};
+
+ template<template<typename TT = float> class T> struct A {
+ void f();
+ void g();
+ };
+
+ template<template<typename TT> class T> void A<T>::f() { // expected-note {{here}}
+ T<> t; // expected-error {{too few template arguments}}
+ }
+
+ template<template<typename TT = char> class T> void A<T>::g() {
+ T<> t;
+ typedef T<> X;
+ typedef T<char> X;
+ }
+
+ void h() { A<B>().g(); }
+}
+
+// dr185 FIXME: add codegen test
+
+namespace dr187 { // dr187: sup 481
+ const int Z = 1;
+ template<int X = Z, int Z = X> struct A;
+ typedef A<> T;
+ typedef A<1, 1> T;
+}
+
+namespace dr188 { // dr188: yes
+ char c[10];
+ int check[sizeof(0, c) == 10 ? 1 : -1];
+}
+
+// dr190 FIXME: add codegen test for tbaa
+
+// dr193 FIXME: add codegen test
+
+namespace dr194 { // dr194: yes
+ struct A {
+ A();
+ void A(); // expected-error {{has the same name as its class}} expected-error {{constructor cannot have a return type}}
+ };
+ struct B {
+ void B(); // expected-error {{has the same name as its class}} expected-error {{constructor cannot have a return type}}
+ B();
+ };
+ struct C {
+ inline explicit C(int) {}
+ };
+}
+
+namespace dr195 { // dr195: yes
+ void f();
+ int *p = (int*)&f; // expected-error 0-1{{extension}}
+ void (*q)() = (void(*)())&p; // expected-error 0-1{{extension}}
+}
+
+namespace dr197 { // dr197: yes
+ char &f(char);
+
+ template <class T> void g(T t) {
+ char &a = f(1);
+ char &b = f(T(1)); // expected-error {{unrelated type 'int'}}
+ char &c = f(t); // expected-error {{unrelated type 'int'}}
+ }
+
+ void f(int);
+
+ enum E { e };
+ int &f(E);
+
+ void h() {
+ g('a');
+ g(2);
+ g(e); // expected-note {{in instantiation of}}
+ }
+}
+
+namespace dr198 { // dr198: yes
+ struct A {
+ int n;
+ struct B {
+ int m[sizeof(n)];
+#if __cplusplus < 201103L
+ // expected-error@-2 {{invalid use of non-static data member}}
+#endif
+ int f() { return n; }
+ // expected-error@-1 {{use of non-static data member 'n' of 'A' from nested type 'B'}}
+ };
+ struct C;
+ struct D;
+ };
+ struct A::C {
+ int m[sizeof(n)];
+#if __cplusplus < 201103L
+ // expected-error@-2 {{invalid use of non-static data member}}
+#endif
+ int f() { return n; }
+ // expected-error@-1 {{use of non-static data member 'n' of 'A' from nested type 'C'}}
+ };
+ struct A::D : A {
+ int m[sizeof(n)];
+#if __cplusplus < 201103L
+ // expected-error@-2 {{invalid use of non-static data member}}
+#endif
+ int f() { return n; }
+ };
+}
+
+// dr199 FIXME: add codegen test
diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp
new file mode 100644
index 000000000000..2c32a9e503f9
--- /dev/null
+++ b/test/CXX/drs/dr2xx.cpp
@@ -0,0 +1,726 @@
+// 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++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+// PR13819 -- __SIZE_TYPE__ is incompatible.
+// REQUIRES: LP64
+
+#if __cplusplus < 201103L
+#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
+#else
+#define fold
+#endif
+
+namespace dr200 { // dr200: dup 214
+ template <class T> T f(int);
+ template <class T, class U> T f(U) = delete; // expected-error 0-1{{extension}}
+
+ void g() {
+ f<int>(1);
+ }
+}
+
+// dr201 FIXME: write codegen test
+
+namespace dr202 { // dr202: yes
+ template<typename T> T f();
+ template<int (*g)()> struct X {
+ int arr[fold(g == &f<int>) ? 1 : -1];
+ };
+ template struct X<f>;
+}
+
+// FIXME (export) dr204: no
+
+namespace dr206 { // dr206: yes
+ struct S; // expected-note 2{{declaration}}
+ template<typename T> struct Q { S s; }; // expected-error {{incomplete}}
+ template<typename T> void f() { S s; } // expected-error {{incomplete}}
+}
+
+namespace dr207 { // dr207: yes
+ class A {
+ protected:
+ static void f() {}
+ };
+ class B : A {
+ public:
+ using A::f;
+ void g() {
+ A::f();
+ f();
+ }
+ };
+}
+
+// dr208 FIXME: write codegen test
+
+namespace dr209 { // dr209: yes
+ class A {
+ void f(); // expected-note {{here}}
+ };
+ class B {
+ friend void A::f(); // expected-error {{private}}
+ };
+}
+
+// dr210 FIXME: write codegen test
+
+namespace dr211 { // dr211: yes
+ struct A {
+ A() try {
+ throw 0;
+ } catch (...) {
+ return; // expected-error {{return in the catch of a function try block of a constructor}}
+ }
+ };
+}
+
+namespace dr213 { // dr213: yes
+ template <class T> struct A : T {
+ void h(T t) {
+ char &r1 = f(t);
+ int &r2 = g(t); // expected-error {{undeclared}}
+ }
+ };
+ struct B {
+ int &f(B);
+ int &g(B); // expected-note {{in dependent base class}}
+ };
+ char &f(B);
+
+ template void A<B>::h(B); // expected-note {{instantiation}}
+}
+
+namespace dr214 { // dr214: yes
+ template<typename T, typename U> T checked_cast(U from) { U::error; }
+ template<typename T, typename U> T checked_cast(U *from);
+ class C {};
+ void foo(int *arg) { checked_cast<const C *>(arg); }
+
+ template<typename T> T f(int);
+ template<typename T, typename U> T f(U) { T::error; }
+ void g() {
+ f<int>(1);
+ }
+}
+
+namespace dr215 { // dr215: yes
+ template<typename T> class X {
+ friend void T::foo();
+ int n;
+ };
+ struct Y {
+ void foo() { (void)+X<Y>().n; }
+ };
+}
+
+namespace dr216 { // dr216: no
+ // FIXME: Should reject this: 'f' has linkage but its type does not,
+ // and 'f' is odr-used but not defined in this TU.
+ typedef enum { e } *E;
+ void f(E);
+ void g(E e) { f(e); }
+
+ struct S {
+ // FIXME: Should reject this: 'f' has linkage but its type does not,
+ // and 'f' is odr-used but not defined in this TU.
+ typedef enum { e } *E;
+ void f(E);
+ };
+ void g(S s, S::E e) { s.f(e); }
+}
+
+namespace dr217 { // dr217: yes
+ template<typename T> struct S {
+ void f(int);
+ };
+ template<typename T> void S<T>::f(int = 0) {} // expected-error {{default arguments cannot be added}}
+}
+
+namespace dr218 { // dr218: yes
+ namespace A {
+ struct S {};
+ void f(S);
+ }
+ namespace B {
+ struct S {};
+ void f(S);
+ }
+
+ struct C {
+ int f;
+ void test1(A::S as) { f(as); } // expected-error {{called object type 'int'}}
+ void test2(A::S as) { void f(); f(as); } // expected-error {{too many arguments}} expected-note {{}}
+ void test3(A::S as) { using A::f; f(as); } // ok
+ void test4(A::S as) { using B::f; f(as); } // ok
+ void test5(A::S as) { int f; f(as); } // expected-error {{called object type 'int'}}
+ void test6(A::S as) { struct f {}; (void) f(as); } // expected-error {{no matching conversion}} expected-note +{{}}
+ };
+
+ namespace D {
+ struct S {};
+ struct X { void operator()(S); } f;
+ }
+ void testD(D::S ds) { f(ds); } // expected-error {{undeclared identifier}}
+
+ namespace E {
+ struct S {};
+ struct f { f(S); };
+ }
+ void testE(E::S es) { f(es); } // expected-error {{undeclared identifier}}
+
+ namespace F {
+ struct S {
+ template<typename T> friend void f(S, T) {}
+ };
+ }
+ void testF(F::S fs) { f(fs, 0); }
+
+ namespace G {
+ namespace X {
+ int f;
+ struct A {};
+ }
+ namespace Y {
+ template<typename T> void f(T);
+ struct B {};
+ }
+ template<typename A, typename B> struct C {};
+ }
+ void testG(G::C<G::X::A, G::Y::B> gc) { f(gc); }
+}
+
+// dr219: na
+// dr220: na
+
+namespace dr221 { // dr221: yes
+ struct A {
+ A &operator=(int&);
+ A &operator+=(int&);
+ static A &operator=(A&, double&); // expected-error {{cannot be a static member}}
+ static A &operator+=(A&, double&); // expected-error {{cannot be a static member}}
+ friend A &operator=(A&, char&); // expected-error {{must be a non-static member function}}
+ friend A &operator+=(A&, char&);
+ };
+ A &operator=(A&, float&); // expected-error {{must be a non-static member function}}
+ A &operator+=(A&, float&);
+
+ void test(A a, int n, char c, float f) {
+ a = n;
+ a += n;
+ a = c;
+ a += c;
+ a = f;
+ a += f;
+ }
+}
+
+// dr222 is a mystery -- it lists no changes to the standard, and yet was
+// apparently both voted into the WP and acted upon by the editor.
+
+// dr223: na
+
+namespace dr224 { // dr224: no
+ namespace example1 {
+ template <class T> class A {
+ typedef int type;
+ A::type a;
+ A<T>::type b;
+ A<T*>::type c; // expected-error {{missing 'typename'}}
+ ::dr224::example1::A<T>::type d;
+
+ class B {
+ typedef int type;
+
+ A::type a;
+ A<T>::type b;
+ A<T*>::type c; // expected-error {{missing 'typename'}}
+ ::dr224::example1::A<T>::type d;
+
+ B::type e;
+ A<T>::B::type f;
+ A<T*>::B::type g; // expected-error {{missing 'typename'}}
+ typename A<T*>::B::type h;
+ };
+ };
+
+ template <class T> class A<T*> {
+ typedef int type;
+ A<T*>::type a;
+ A<T>::type b; // expected-error {{missing 'typename'}}
+ };
+
+ template <class T1, class T2, int I> struct B {
+ typedef int type;
+ B<T1, T2, I>::type b1;
+ B<T2, T1, I>::type b2; // expected-error {{missing 'typename'}}
+
+ typedef T1 my_T1;
+ static const int my_I = I;
+ static const int my_I2 = I+0;
+ static const int my_I3 = my_I;
+ B<my_T1, T2, my_I>::type b3; // FIXME: expected-error {{missing 'typename'}}
+ B<my_T1, T2, my_I2>::type b4; // expected-error {{missing 'typename'}}
+ B<my_T1, T2, my_I3>::type b5; // FIXME: expected-error {{missing 'typename'}}
+ };
+ }
+
+ namespace example2 {
+ template <int, typename T> struct X { typedef T type; };
+ template <class T> class A {
+ static const int i = 5;
+ X<i, int>::type w; // FIXME: expected-error {{missing 'typename'}}
+ X<A::i, char>::type x; // FIXME: expected-error {{missing 'typename'}}
+ X<A<T>::i, double>::type y; // FIXME: expected-error {{missing 'typename'}}
+ X<A<T*>::i, long>::type z; // expected-error {{missing 'typename'}}
+ int f();
+ };
+ template <class T> int A<T>::f() {
+ return i;
+ }
+ }
+}
+
+// dr225: yes
+template<typename T> void dr225_f(T t) { dr225_g(t); } // expected-error {{call to function 'dr225_g' that is neither visible in the template definition nor found by argument-dependent lookup}}
+void dr225_g(int); // expected-note {{should be declared prior to the call site}}
+template void dr225_f(int); // expected-note {{in instantiation of}}
+
+namespace dr226 { // dr226: no
+ template<typename T = void> void f() {}
+#if __cplusplus < 201103L
+ // expected-error@-2 {{extension}}
+ // FIXME: This appears to be wrong: default arguments for function templates
+ // are listed as a defect (in c++98) not an extension. EDG accepts them in
+ // strict c++98 mode.
+#endif
+ template<typename T> struct S {
+ template<typename U = void> void g();
+#if __cplusplus < 201103L
+ // expected-error@-2 {{extension}}
+#endif
+ template<typename U> struct X;
+ template<typename U> void h();
+ };
+ template<typename T> template<typename U> void S<T>::g() {}
+ template<typename T> template<typename U = void> struct S<T>::X {}; // expected-error {{cannot add a default template arg}}
+ template<typename T> template<typename U = void> void S<T>::h() {} // expected-error {{cannot add a default template arg}}
+
+ template<typename> void friend_h();
+ struct A {
+ // FIXME: This is ill-formed.
+ template<typename=void> struct friend_B;
+ // FIXME: f, h, and i are ill-formed.
+ // f is ill-formed because it is not a definition.
+ // h and i are ill-formed because they are not the only declarations of the
+ // function in the translation unit.
+ template<typename=void> void friend_f();
+ template<typename=void> void friend_g() {}
+ template<typename=void> void friend_h() {}
+ template<typename=void> void friend_i() {}
+#if __cplusplus < 201103L
+ // expected-error@-5 {{extension}} expected-error@-4 {{extension}}
+ // expected-error@-4 {{extension}} expected-error@-3 {{extension}}
+#endif
+ };
+ template<typename> void friend_i();
+
+ template<typename=void, typename X> void foo(X) {}
+ template<typename=void, typename X> struct Foo {}; // expected-error {{missing a default argument}} expected-note {{here}}
+#if __cplusplus < 201103L
+ // expected-error@-3 {{extension}}
+#endif
+
+ template<typename=void, typename X, typename, typename Y> int foo(X, Y);
+ template<typename, typename X, typename=void, typename Y> int foo(X, Y);
+ int x = foo(0, 0);
+#if __cplusplus < 201103L
+ // expected-error@-4 {{extension}}
+ // expected-error@-4 {{extension}}
+#endif
+}
+
+void dr227(bool b) { // dr227: yes
+ if (b)
+ int n;
+ else
+ int n;
+}
+
+namespace dr228 { // dr228: yes
+ template <class T> struct X {
+ void f();
+ };
+ template <class T> struct Y {
+ void g(X<T> x) { x.template X<T>::f(); }
+ };
+}
+
+namespace dr229 { // dr229: yes
+ template<typename T> void f();
+ template<typename T> void f<T*>() {} // expected-error {{function template partial specialization}}
+ template<> void f<int>() {}
+}
+
+namespace dr231 { // dr231: yes
+ namespace outer {
+ namespace inner {
+ int i; // expected-note {{here}}
+ }
+ void f() { using namespace inner; }
+ int j = i; // expected-error {{undeclared identifier 'i'; did you mean 'inner::i'?}}
+ }
+}
+
+// dr234: na
+// dr235: na
+
+namespace dr236 { // dr236: yes
+ void *p = int();
+#if __cplusplus < 201103L
+ // expected-warning@-2 {{null pointer}}
+#else
+ // expected-error@-4 {{cannot initialize}}
+#endif
+}
+
+namespace dr237 { // dr237: dup 470
+ template<typename T> struct A { void f() { T::error; } };
+ template<typename T> struct B : A<T> {};
+ template struct B<int>; // ok
+}
+
+namespace dr239 { // dr239: yes
+ namespace NS {
+ class T {};
+ void f(T);
+ float &g(T, int);
+ }
+ NS::T parm;
+ int &g(NS::T, float);
+ int main() {
+ f(parm);
+ float &r = g(parm, 1);
+ extern int &g(NS::T, float);
+ int &s = g(parm, 1);
+ }
+}
+
+// dr240: dup 616
+
+namespace dr241 { // dr241: yes
+ namespace A {
+ struct B {};
+ template <int X> void f(); // expected-note 2{{candidate}}
+ template <int X> void g(B);
+ }
+ namespace C {
+ template <class T> void f(T t); // expected-note 2{{candidate}}
+ template <class T> void g(T t); // expected-note {{candidate}}
+ }
+ void h(A::B b) {
+ f<3>(b); // expected-error {{undeclared identifier}}
+ g<3>(b); // expected-error {{undeclared identifier}}
+ A::f<3>(b); // expected-error {{no matching}}
+ A::g<3>(b);
+ C::f<3>(b); // expected-error {{no matching}}
+ C::g<3>(b); // expected-error {{no matching}}
+ using C::f;
+ using C::g;
+ f<3>(b); // expected-error {{no matching}}
+ g<3>(b);
+ }
+}
+
+namespace dr243 { // dr243: yes
+ struct B;
+ struct A {
+ A(B); // expected-note {{candidate}}
+ };
+ struct B {
+ operator A() = delete; // expected-error 0-1{{extension}} expected-note {{candidate}}
+ } b;
+ A a1(b);
+ A a2 = b; // expected-error {{ambiguous}}
+}
+
+namespace dr244 { // dr244: no
+ struct B {}; struct D : B {}; // expected-note {{here}}
+
+ D D_object;
+ typedef B B_alias;
+ B* B_ptr = &D_object;
+
+ void f() {
+ D_object.~B(); // expected-error {{expression does not match the type}}
+ D_object.B::~B();
+ B_ptr->~B();
+ B_ptr->~B_alias();
+ B_ptr->B_alias::~B();
+ // This is valid under DR244.
+ B_ptr->B_alias::~B_alias(); // FIXME: expected-error {{expected the class name after '~' to name a destructor}}
+ B_ptr->dr244::~B(); // expected-error {{refers to a member in namespace}}
+ B_ptr->dr244::~B_alias(); // expected-error {{refers to a member in namespace}}
+ }
+}
+
+namespace dr245 { // dr245: yes
+ struct S {
+ enum E {}; // expected-note {{here}}
+ class E *p; // expected-error {{does not match previous declaration}}
+ };
+}
+
+namespace dr246 { // dr246: yes
+ struct S {
+ S() try { // expected-note {{try block}}
+ throw 0;
+X: ;
+ } catch (int) {
+ goto X; // expected-error {{protected scope}}
+ }
+ };
+}
+
+namespace dr247 { // dr247: yes
+ struct A {};
+ struct B : A {
+ void f();
+ void f(int);
+ };
+ void (A::*f)() = (void (A::*)())&B::f;
+
+ struct C {
+ void f();
+ void f(int);
+ };
+ struct D : C {};
+ void (C::*g)() = &D::f;
+ void (D::*h)() = &D::f;
+
+ struct E {
+ void f();
+ };
+ struct F : E {
+ using E::f;
+ void f(int);
+ };
+ void (F::*i)() = &F::f;
+}
+
+namespace dr248 { // dr248: yes c++11
+ // FIXME: Should this also apply to c++98 mode? This was a DR against C++98.
+ int \u040d\u040e = 0;
+#if __cplusplus < 201103L
+ // FIXME: expected-error@-2 {{expected ';'}}
+#endif
+}
+
+namespace dr249 { // dr249: yes
+ template<typename T> struct X { void f(); };
+ template<typename T> void X<T>::f() {}
+}
+
+namespace dr250 { // dr250: yes
+ typedef void (*FPtr)(double x[]);
+
+ template<int I> void f(double x[]);
+ FPtr fp = &f<3>;
+
+ template<int I = 3> void g(double x[]); // expected-error 0-1{{extension}}
+ FPtr gp = &g<>;
+}
+
+namespace dr252 { // dr252: yes
+ struct A {
+ void operator delete(void*); // expected-note {{found}}
+ };
+ struct B {
+ void operator delete(void*); // expected-note {{found}}
+ };
+ struct C : A, B {
+ virtual ~C();
+ };
+ C::~C() {} // expected-error {{'operator delete' found in multiple base classes}}
+
+ struct D {
+ void operator delete(void*, int); // expected-note {{here}}
+ virtual ~D();
+ };
+ D::~D() {} // expected-error {{no suitable member 'operator delete'}}
+
+ struct E {
+ void operator delete(void*, int);
+ void operator delete(void*) = delete; // expected-error 0-1{{extension}} expected-note {{here}}
+ virtual ~E();
+ };
+ E::~E() {} // expected-error {{deleted}}
+
+ struct F {
+ // If both functions are available, the first one is a placement delete.
+ void operator delete(void*, __SIZE_TYPE__);
+ void operator delete(void*) = delete; // expected-error 0-1{{extension}} expected-note {{here}}
+ virtual ~F();
+ };
+ F::~F() {} // expected-error {{deleted}}
+
+ struct G {
+ void operator delete(void*, __SIZE_TYPE__);
+ virtual ~G();
+ };
+ G::~G() {}
+}
+
+namespace dr254 { // dr254: yes
+ template<typename T> struct A {
+ typedef typename T::type type; // ok even if this is a typedef-name, because
+ // it's not an elaborated-type-specifier
+ typedef struct T::type foo; // expected-error {{elaborated type refers to a typedef}}
+ };
+ struct B { struct type {}; };
+ struct C { typedef struct {} type; }; // expected-note {{here}}
+ A<B>::type n;
+ A<C>::type n; // expected-note {{instantiation of}}
+}
+
+// dr256: dup 624
+
+namespace dr257 { // dr257: yes
+ struct A { A(int); }; // expected-note {{here}}
+ struct B : virtual A {
+ B() {}
+ virtual void f() = 0;
+ };
+ struct C : B {
+ C() {}
+ };
+ struct D : B {
+ D() {} // expected-error {{must explicitly initialize the base class 'dr257::A'}}
+ void f();
+ };
+}
+
+namespace dr258 { // dr258: yes
+ struct A {
+ void f(const int);
+ template<typename> void g(int);
+ float &h() const;
+ };
+ struct B : A {
+ using A::f;
+ using A::g;
+ using A::h;
+ int &f(int);
+ template<int> int &g(int); // expected-note {{candidate}}
+ int &h();
+ } b;
+ int &w = b.f(0);
+ int &x = b.g<int>(0); // expected-error {{no match}}
+ int &y = b.h();
+ float &z = const_cast<const B&>(b).h();
+
+ struct C {
+ virtual void f(const int) = 0;
+ };
+ struct D : C {
+ void f(int);
+ } d;
+
+ struct E {
+ virtual void f() = 0; // expected-note {{unimplemented}}
+ };
+ struct F : E {
+ void f() const {}
+ } f; // expected-error {{abstract}}
+}
+
+namespace dr259 { // dr259: yes c++11
+ template<typename T> struct A {};
+ template struct A<int>; // expected-note {{previous}}
+ template struct A<int>; // expected-error {{duplicate explicit instantiation}}
+
+ // FIXME: We only apply this DR in C++11 mode.
+ template<> struct A<float>;
+ template struct A<float>;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{extension}} expected-note@-3 {{here}}
+#endif
+
+ template struct A<char>; // expected-note {{here}}
+ template<> struct A<char>; // expected-error {{explicit specialization of 'dr259::A<char>' after instantiation}}
+
+ template<> struct A<double>;
+ template<> struct A<double>;
+ template<> struct A<double> {}; // expected-note {{here}}
+ template<> struct A<double> {}; // expected-error {{redefinition}}
+
+ template<typename T> struct B; // expected-note {{here}}
+ template struct B<int>; // expected-error {{undefined}}
+
+ template<> struct B<float>;
+ template struct B<float>;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{extension}} expected-note@-3 {{here}}
+#endif
+}
+
+namespace dr261 { // dr261: no
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wused-but-marked-unused"
+
+ // FIXME: This is ill-formed, with a diagnostic required, because operator new
+ // and operator delete are inline and odr-used, but not defined in this
+ // translation unit.
+ // We're also missing the -Wused-but-marked-unused diagnostic here.
+ struct A {
+ inline void *operator new(__SIZE_TYPE__) __attribute__((unused));
+ inline void operator delete(void*) __attribute__((unused));
+ A() {}
+ };
+
+ // FIXME: These are ill-formed, with a required diagnostic, for the same
+ // reason.
+ struct B {
+ inline void operator delete(void*) __attribute__((unused));
+ ~B() {}
+ };
+ struct C {
+ inline void operator delete(void*) __attribute__((unused));
+ virtual ~C() {}
+ };
+
+ struct D {
+ inline void operator delete(void*) __attribute__((unused));
+ };
+ void h() { C::operator delete(0); } // expected-warning {{marked unused but was used}}
+
+#pragma clang diagnostic pop
+}
+
+namespace dr262 { // dr262: yes
+ int f(int = 0, ...);
+ int k = f();
+ int l = f(0);
+ int m = f(0, 0);
+}
+
+namespace dr263 { // dr263: yes
+ struct X {};
+ struct Y {
+#if __cplusplus < 201103L
+ friend X::X() throw();
+ friend X::~X() throw();
+#else
+ friend constexpr X::X() noexcept;
+ friend X::~X();
+#endif
+ Y::Y(); // expected-error {{extra qualification}}
+ Y::~Y(); // expected-error {{extra qualification}}
+ };
+}
+
+// dr265: dup 353
+// dr266: na
+// dr269: na
+// dr270: na
diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp
new file mode 100644
index 000000000000..1d3b94064cdd
--- /dev/null
+++ b/test/CXX/drs/dr4xx.cpp
@@ -0,0 +1,32 @@
+// 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
+// expected-no-diagnostics
+
+namespace dr408 { // dr408: 3.4
+ template<int N> void g() { int arr[N != 1 ? 1 : -1]; }
+ template<> void g<2>() { }
+
+ template<typename T> struct S {
+ static int i[];
+ void f();
+ };
+ template<typename T> int S<T>::i[] = { 1 };
+
+ template<typename T> void S<T>::f() {
+ g<sizeof (i) / sizeof (int)>();
+ }
+ template<> int S<int>::i[] = { 1, 2 };
+ template void S<int>::f(); // uses g<2>(), not g<1>().
+
+
+ template<typename T> struct R {
+ static int arr[];
+ void f();
+ };
+ template<typename T> int R<T>::arr[1];
+ template<typename T> void R<T>::f() {
+ int arr[sizeof(arr) != sizeof(int) ? 1 : -1];
+ }
+ template<> int R<int>::arr[2];
+ template void R<int>::f();
+}
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index dda69e9aad60..945a767584fe 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -44,8 +44,8 @@ namespace PR13381 {
struct NoThrowMove {
NoThrowMove(const NoThrowMove &);
NoThrowMove(NoThrowMove &&) noexcept;
- NoThrowMove &operator=(const NoThrowMove &);
- NoThrowMove &operator=(NoThrowMove &&) noexcept;
+ NoThrowMove &operator=(const NoThrowMove &) const;
+ NoThrowMove &operator=(NoThrowMove &&) const noexcept;
};
struct NoThrowMoveOnly {
NoThrowMoveOnly(NoThrowMoveOnly &&) noexcept;
diff --git a/test/CXX/except/except.spec/p4.cpp b/test/CXX/except/except.spec/p4.cpp
index 1bf70188031f..8d1b75fbdd6d 100644
--- a/test/CXX/except/except.spec/p4.cpp
+++ b/test/CXX/except/except.spec/p4.cpp
@@ -34,3 +34,8 @@ template<typename T> struct U {
template<typename T> U<T>::~U() noexcept(true) {} // expected-error {{exception specification in declaration does not match previous declaration}}
template<typename T> void U<T>::operator delete(void*) noexcept(false) {} // expected-error {{exception specification in declaration does not match previous declaration}}
+
+
+// Make sure this restriction interacts properly with __attribute__((noreturn))
+void __attribute__ ((__noreturn__)) PR17110(int status) throw();
+void PR17110(int status) throw();
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 634dee3782fc..f0b53c7d3b5c 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -275,9 +275,7 @@ namespace UndefinedBehavior {
// - a lambda-expression (5.1.2);
struct Lambda {
- // FIXME: clang crashes when trying to parse this! Revisit this check once
- // lambdas are fully implemented.
- //int n : []{ return 1; }();
+ int n : []{ return 1; }(); // expected-error {{constant expression}} expected-error {{integral constant expression}}
};
// - an lvalue-to-rvalue conversion (4.1) unless it is applied to
@@ -322,7 +320,7 @@ namespace LValueToRValue {
// constant expression;
constexpr volatile S f() { return S(); }
static_assert(f().i, ""); // ok! there's no lvalue-to-rvalue conversion here!
- static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}}
+ static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
}
// DR1312: The proposed wording for this defect has issues, so we ignore this
@@ -481,17 +479,19 @@ namespace UnspecifiedRelations {
public:
constexpr A() : a(0), b(0) {}
int a;
- constexpr bool cmp() const { return &a < &b; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}}
+ constexpr bool cmp() const { return &a < &b; } // expected-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}}
private:
int b;
};
+ static_assert(A().cmp(), ""); // expected-error {{constant expression}} expected-note {{in call}}
class B {
public:
A a;
- constexpr bool cmp() const { return &a.a < &b.a; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}}
+ constexpr bool cmp() const { return &a.a < &b.a; } // expected-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}}
protected:
A b;
};
+ static_assert(B().cmp(), ""); // expected-error {{constant expression}} expected-note {{in call}}
// If two pointers point to different base sub-objects of the same object, or
// one points to a base subobject and the other points to a member, the result
diff --git a/test/CXX/expr/expr.const/p3-0x.cpp b/test/CXX/expr/expr.const/p3-0x.cpp
index 047e238190f8..e3e32dfe0900 100644
--- a/test/CXX/expr/expr.const/p3-0x.cpp
+++ b/test/CXX/expr/expr.const/p3-0x.cpp
@@ -93,7 +93,7 @@ void c() {
break;
}
}
-template<bool B> int f() { return B; }
+template <bool B> int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}}
template int f<&S::operator int>(); // expected-error {{does not refer to a function template}}
template int f<(bool)&S::operator int>();
diff --git a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
index 018609d9a07d..fbb685c5a448 100644
--- a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
@@ -20,11 +20,16 @@ struct X4 {
void vararg(...);
+void g();
+
void f(X1 x1, X2 x2, X3 x3, X4 x4) {
vararg(x1); // OK
vararg(x2); // expected-error{{cannot pass object of non-trivial type 'X2' through variadic function; call will abort at runtime}}
vararg(x3); // OK
vararg(x4); // expected-error{{cannot pass object of non-trivial type 'X4' through variadic function; call will abort at runtime}}
+
+ vararg(g()); // expected-error{{cannot pass expression of type 'void' to variadic function}}
+ vararg({1, 2, 3}); // expected-error{{cannot pass initializer list to variadic function}}
}
@@ -33,7 +38,7 @@ namespace PR11131 {
S &getS();
- void f(...);
+ int f(...);
void g() {
(void)sizeof(f(getS()));
diff --git a/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp b/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
index 76ea96fe14ae..f4c0f1ae1229 100644
--- a/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
@@ -6,14 +6,26 @@
unsigned int f(int);
+struct X {};
+
template<typename T> T& lvalue();
template<typename T> T&& xvalue();
template<typename T> T prvalue();
-void test_classification(const int *ptr) {
- int *ptr0 = const_cast<int *&&>(ptr);
- int *ptr1 = const_cast<int *&&>(xvalue<const int*>());
- int *ptr2 = const_cast<int *&&>(prvalue<const int*>());
+void test_classification(const int *ptr, X x) {
+ int *&&ptr0 = const_cast<int *&&>(ptr);
+ int *&&ptr1 = const_cast<int *&&>(xvalue<const int*>());
+ int *&&ptr2 = const_cast<int *&&>(prvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&&'}}
+ X &&ptr3 = const_cast<X&&>(x);
+ X &&ptr4 = const_cast<X&&>(xvalue<X>());
+ X &&ptr5 = const_cast<X&&>(prvalue<X>());
+
+ int *&ptr6 = const_cast<int *&>(ptr);
+ int *&ptr7 = const_cast<int *&>(xvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&'}}
+ int *&ptr8 = const_cast<int *&>(prvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&'}}
+ X &ptr9 = const_cast<X&>(x);
+ X &ptrA = const_cast<X&>(xvalue<X>()); // expected-error {{const_cast from rvalue to reference type 'X &'}}
+ X &ptrB = const_cast<X&>(prvalue<X>()); // expected-error {{const_cast from rvalue to reference type 'X &'}}
}
struct A {
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
index 66579915c7b0..fd90482ae8d2 100644
--- a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
@@ -30,16 +30,44 @@ struct C {
float &f(T*) const noexcept;
T* ptr;
- auto g1() noexcept(noexcept(f(ptr))) -> decltype(f((*this).ptr));
+ auto g1() noexcept(noexcept(f(ptr))) -> decltype(f(ptr));
auto g2() const noexcept(noexcept(f(((this))->ptr))) -> decltype(f(ptr));
+ auto g3() noexcept(noexcept(f(this->ptr))) -> decltype(f((*this).ptr));
+ auto g4() const noexcept(noexcept(f(((this))->ptr))) -> decltype(f(this->ptr));
+ auto g5() noexcept(noexcept(this->f(ptr))) -> decltype(this->f(ptr));
+ auto g6() const noexcept(noexcept(this->f(((this))->ptr))) -> decltype(this->f(ptr));
+ auto g7() noexcept(noexcept(this->f(this->ptr))) -> decltype(this->f((*this).ptr));
+ auto g8() const noexcept(noexcept(this->f(((this))->ptr))) -> decltype(this->f(this->ptr));
};
void test_C(C<int> ci) {
- int *p = 0;
int &ir = ci.g1();
float &fr = ci.g2();
+ int &ir2 = ci.g3();
+ float &fr2 = ci.g4();
+ int &ir3 = ci.g5();
+ float &fr3 = ci.g6();
+ int &ir4 = ci.g7();
+ float &fr4 = ci.g8();
static_assert(!noexcept(ci.g1()), "exception-specification failure");
static_assert(noexcept(ci.g2()), "exception-specification failure");
+ static_assert(!noexcept(ci.g3()), "exception-specification failure");
+ static_assert(noexcept(ci.g4()), "exception-specification failure");
+ static_assert(!noexcept(ci.g5()), "exception-specification failure");
+ static_assert(noexcept(ci.g6()), "exception-specification failure");
+ static_assert(!noexcept(ci.g7()), "exception-specification failure");
+ static_assert(noexcept(ci.g8()), "exception-specification failure");
+}
+
+namespace PR14263 {
+ template<typename T> struct X {
+ void f();
+ T f() const;
+
+ auto g() -> decltype(this->f()) { return f(); }
+ auto g() const -> decltype(this->f()) { return f(); }
+ };
+ template struct X<int>;
}
namespace PR10036 {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm
index 9f9867106930..24ce2cd6c198 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm
@@ -14,7 +14,7 @@ namespace PR12746 {
}
// CHECK: define internal zeroext i1 @___ZN7PR127462f1EPi_block_invoke
- // CHECK: call zeroext i1 @"_ZNK7PR127462f132___ZN7PR127462f1EPi_block_invoke3$_0clEv"
+ // CHECK: call zeroext i1 @"_ZZZN7PR127462f1EPiEUb_ENK3$_0clEv"
bool f2(int *x) {
auto outer = [&]() -> bool {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
new file mode 100644
index 000000000000..7f42c396ee22
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
+//expected-no-diagnostics
+namespace lambda_capturing {
+// FIXME: Once return type deduction is implemented for generic lambdas
+// this will need to be updated.
+void test() {
+ int i = 10;
+ {
+ auto L = [=](auto a) -> int {
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i](auto a) -> int {
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i=i](auto a) -> int {
+ return i + a;
+ };
+ L(3);
+ }
+
+
+}
+
+}
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
new file mode 100644
index 000000000000..6be200dd54e5
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++1y %s -verify
+
+const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}}
+
+double f;
+auto with_float = [f(1.0f)] {
+ using T = decltype(f);
+ using T = float;
+};
+auto with_float_2 = [&f(f)] { // ok, refers to outer f
+ using T = decltype(f);
+ using T = double&;
+};
+
+// Within the lambda-expression's compound-statement,
+// the identifier in the init-capture hides any declaration
+// of the same name in scopes enclosing the lambda-expression.
+void hiding() {
+ char c;
+ (void) [c("foo")] {
+ static_assert(sizeof(c) == sizeof(const char*), "");
+ };
+ (void) [c("bar")] () -> decltype(c) { // outer c, not init-capture
+ return "baz"; // expected-error {{cannot initialize}}
+ };
+}
+
+struct ExplicitCopy {
+ ExplicitCopy(); // expected-note 2{{not viable}}
+ explicit ExplicitCopy(const ExplicitCopy&);
+};
+auto init_kind_1 = [ec(ExplicitCopy())] {};
+auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}}
+
+template<typename T> void init_kind_template() {
+ auto init_kind_1 = [ec(T())] {};
+ auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}}
+}
+template void init_kind_template<int>();
+template void init_kind_template<ExplicitCopy>(); // expected-note {{instantiation of}}
+
+void void_fn();
+int overload_fn();
+int overload_fn(int);
+
+auto bad_init_1 = [a()] {}; // expected-error {{expected expression}}
+auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}}
+auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
+auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
+auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type '<overloaded function}}
+auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}}
+
+template<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
+template void pack_1<>(); // expected-note {{instantiation of}}
+
+// FIXME: Might need lifetime extension for the temporary here.
+// See DR1695.
+auto a = [a(4), b = 5, &c = static_cast<const int&&>(0)] {
+ static_assert(sizeof(a) == sizeof(int), "");
+ static_assert(sizeof(b) == sizeof(int), "");
+ using T = decltype(c);
+ using T = const int &;
+};
+auto b = [a{0}] {}; // expected-error {{include <initializer_list>}}
+
+struct S { S(); S(S&&); };
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+template<typename T> decltype(auto) move(T &&t) { return static_cast<typename remove_reference<T>::type&&>(t); }
+auto s = [s(move(S()))] {};
+
+template<typename T> T instantiate_test(T t) {
+ [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}}
+ return t;
+}
+int instantiate_test_1 = instantiate_test(0);
+const char *instantiate_test_2 = instantiate_test("foo"); // expected-note {{here}}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
index 6358215a5559..2ddcf18409e9 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
@@ -88,3 +88,15 @@ struct CaptureArrayAndThis {
}
};
+namespace rdar14468891 {
+ class X {
+ public:
+ virtual ~X() = 0; // expected-note{{unimplemented pure virtual method '~X' in 'X'}}
+ };
+
+ class Y : public X { };
+
+ void capture(X &x) {
+ [x]() {}(); // expected-error{{by-copy capture of value of abstract type 'rdar14468891::X'}}
+ }
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
new file mode 100644
index 000000000000..d41c4507a850
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+// prvalue
+void prvalue() {
+ auto&& x = [](auto a)->void { };
+ auto& y = [](auto *a)->void { }; // expected-error{{cannot bind to a temporary of type}}
+}
+
+namespace std {
+ class type_info;
+}
+
+struct P {
+ virtual ~P();
+};
+
+void unevaluated_operand(P &p, int i) { //expected-note{{declared here}}
+ // FIXME: this should only emit one error.
+ int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
+ // expected-error{{invalid application of 'sizeof'}}
+ const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));
+ const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\
+ // expected-error{{cannot be implicitly captured}}\
+ // expected-note{{begins here}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
index c6ed308d79a1..1fbe28722a41 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
@@ -15,7 +15,7 @@ struct P {
};
void unevaluated_operand(P &p, int i) {
- int i2 = sizeof([]()->void{}()); // expected-error{{lambda expression in an unevaluated operand}}
+ int i2 = sizeof([] ()->int { return 0; }()); // expected-error{{lambda expression in an unevaluated operand}}
const std::type_info &ti1 = typeid([&]() -> P& { return p; }());
const std::type_info &ti2 = typeid([&]() -> int { return i; }()); // expected-error{{lambda expression in an unevaluated operand}}
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
index 82fc04a48fb6..4ae34dec3e34 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wno-c++1y-extensions
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
void print();
@@ -56,3 +57,25 @@ void variadic_lambda(Args... args) {
}
template void variadic_lambda(int*, float*, double*);
+
+template<typename ...Args>
+void init_capture_pack_err(Args ...args) {
+ [as(args)...] {} (); // expected-error {{expected ','}}
+ [as...(args)]{} (); // expected-error {{expected ','}}
+}
+
+template<typename ...Args>
+void init_capture_pack_multi(Args ...args) {
+ [as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}}
+}
+template void init_capture_pack_multi(); // expected-note {{instantiation}}
+template void init_capture_pack_multi(int);
+template void init_capture_pack_multi(int, int); // expected-note {{instantiation}}
+
+template<typename ...Args>
+void init_capture_pack_outer(Args ...args) {
+ print([as(args)] { return sizeof(as); } () ...);
+}
+template void init_capture_pack_outer();
+template void init_capture_pack_outer(int);
+template void init_capture_pack_outer(int, int);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
new file mode 100644
index 000000000000..f8461335b768
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
+
+int a;
+int &b = [] (int &r) -> decltype(auto) { return r; } (a);
+int &c = [] (int &r) -> decltype(auto) { return (r); } (a);
+int &d = [] (int &r) -> auto & { return r; } (a);
+int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}}
+int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}}
+int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}}
+
+
+int test_explicit_auto_return()
+{
+ struct X {};
+ auto L = [](auto F, auto a) { return F(a); };
+ auto M = [](auto a) -> auto { return a; }; // OK
+ auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}}
+ auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}}
+ auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast<decltype(d)>(d); }; //OK
+ M(3);
+
+ auto &&x = MDeclType(X{});
+ auto &&x1 = M(X{});
+ auto &&x2 = MRef(X{});//expected-note{{in instantiation of}}
+ auto &&x3 = MPtr(X{}); //expected-note{{in instantiation of}}
+ return 0;
+}
+
+int test_implicit_auto_return()
+{
+ {
+ auto M = [](auto a) { return a; };
+ struct X {};
+ X x = M(X{});
+
+ }
+}
+
+int test_multiple_returns() {
+ auto M = [](auto a) {
+ bool k;
+ if (k)
+ return a;
+ else
+ return 5; //expected-error{{deduced as 'int' here}}
+ };
+ M(3); // OK
+ M('a'); //expected-note{{in instantiation of}}
+ return 0;
+}
+int test_no_parameter_list()
+{
+ static int si = 0;
+ auto M = [] { return 5; }; // OK
+ auto M2 = [] -> auto&& { return si; }; // expected-error{{lambda requires '()'}}
+ M();
+}
+
+int test_conditional_in_return() {
+ auto Fac = [](auto f, auto n) {
+ return n <= 0 ? n : f(f, n - 1) * n;
+ };
+ // FIXME: this test causes a recursive limit - need to error more gracefully.
+ //Fac(Fac, 3);
+
+} \ No newline at end of file
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index f580e7e4c46f..1016cb1d3056 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -DCPP1Y
void missing_lambda_declarator() {
[](){}();
@@ -17,7 +18,7 @@ void infer_void_return_type(int i) {
switch (x) {
case 0: return get<void>();
case 1: return;
- case 2: return { 1, 2.0 }; // expected-error{{cannot deduce lambda return type from initializer list}}
+ case 2: return { 1, 2.0 }; //expected-error{{cannot deduce}}
}
}(7);
}
@@ -38,7 +39,10 @@ X infer_X_return_type_fail(X x) {
if (y > 0)
return X();
else
- return x; // expected-error{{return type 'const X' must match previous return type 'X' when lambda expression has unspecified explicit return type}}
+ return x;
+#if __cplusplus <= 201103L
+ // expected-error@-2 {{return type 'const X' must match previous return type 'X' when lambda expression has unspecified explicit return type}}
+#endif
}(5);
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
index 0126e23a74ab..92c62904d57b 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
@@ -4,5 +4,5 @@
@end
void test_result_type() {
- auto l1 = [] () -> A { }; // expected-error{{non-pointer Objective-C class type 'A' in lambda expression result}}
+ auto l1 = [] () -> A { }; // expected-error{{interface type 'A' cannot be returned by value; did you forget * in 'A'?}}
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
new file mode 100644
index 000000000000..c5d3bf6d1bcf
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+namespace test_factorial {
+
+auto Fact = [](auto Self, unsigned n) -> unsigned {
+ return !n ? 1 : Self(Self, n - 1) * n;
+};
+
+auto six = Fact(Fact, 3);
+
+}
+
+namespace overload_generic_lambda {
+ template <class F1, class F2> struct overload : F1, F2 {
+ using F1::operator();
+ using F2::operator();
+ overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
+ };
+
+ auto NumParams = [](auto Self, auto h, auto ... rest) -> unsigned {
+ return 1 + Self(Self, rest...);
+ };
+ auto Base = [](auto Self, auto h) -> unsigned {
+ return 1;
+ };
+ overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);
+ int num_params = O(O, 5, 3, "abc", 3.14, 'a');
+}
+
+
+namespace overload_generic_lambda_return_type_deduction {
+ template <class F1, class F2> struct overload : F1, F2 {
+ using F1::operator();
+ using F2::operator();
+ overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
+ };
+
+ auto NumParams = [](auto Self, auto h, auto ... rest) {
+ return 1 + Self(Self, rest...);
+ };
+ auto Base = [](auto Self, auto h) {
+ return 1;
+ };
+ overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);
+ int num_params = O(O, 5, 3, "abc", 3.14, 'a');
+}
+
+namespace test_standard_p5 {
+// FIXME: This test should eventually compile without an explicit trailing return type
+auto glambda = [](auto a, auto&& b) ->bool { return a < b; };
+bool b = glambda(3, 3.14); // OK
+
+}
+namespace test_deduction_failure {
+ int test() {
+ auto g = [](auto *a) { //expected-note{{candidate template ignored}}
+ return a;
+ };
+ struct X { };
+ X *x;
+ g(x);
+ g(3); //expected-error{{no matching function}}
+ return 0;
+ }
+
+}
+
+namespace test_instantiation_or_sfinae_failure {
+int test2() {
+ {
+ auto L = [](auto *a) {
+ return (*a)(a); }; //expected-error{{called object type 'double' is not a function}}
+ double d;
+ L(&d); //expected-note{{in instantiation of}}
+ auto M = [](auto b) { return b; };
+ L(&M); // ok
+ }
+ {
+ auto L = [](auto *a) ->decltype (a->foo()) { //expected-note2{{candidate template ignored:}}
+ return (*a)(a); };
+ double d;
+ L(&d); //expected-error{{no matching function for call}}
+ auto M = [](auto b) { return b; };
+ L(&M); //expected-error{{no matching function for call}}
+
+ }
+ return 0;
+}
+
+
+}
+
+namespace test_misc {
+auto GL = [](auto a, decltype(a) b) //expected-note{{candidate function}}
+ -> int { return a + b; };
+
+void test() {
+ struct X { };
+ GL(3, X{}); //expected-error{{no matching function}}
+}
+
+void test2() {
+ auto l = [](auto *a) -> int {
+ (*a)(a); return 0; }; //expected-error{{called object type 'double' is not a function}}
+ l(&l);
+ double d;
+ l(&d); //expected-note{{in instantiation of}}
+}
+
+}
+
+namespace nested_lambdas {
+ int test() {
+ auto L = [](auto a) {
+ return [=](auto b) {
+ return a + b;
+ };
+ };
+ }
+ auto get_lambda() {
+ return [](auto a) {
+ return a;
+ };
+ };
+
+ int test2() {
+ auto L = get_lambda();
+ L(3);
+ }
+}
+
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 d1384f19dd14..b9b8cd76c011 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -verify
+// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-c++1y-extensions
class X0 {
void explicit_capture() {
@@ -26,4 +26,7 @@ void S2::f(int i) {
(void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}}
(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}}
+ (void)[i, i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}}
+ (void)[i(0), i]{ }; // expected-error{{'i' can appear only once in a capture list}}
}
diff --git a/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp b/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
index 4ebbfce289ea..2e99b525b443 100644
--- a/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
@@ -11,7 +11,7 @@ void f() {
only<double*> q = new (auto) (0.0);
new auto; // expected-error{{new expression for type 'auto' requires a constructor argument}}
- new (const auto)(); // expected-error{{new expression for type 'auto const' requires a constructor argument}}
+ new (const auto)(); // expected-error{{new expression for type 'const auto' requires a constructor argument}}
new (auto) (1,2,3); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
}
diff --git a/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp b/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp
index 6a59e3d7ae52..aa76b3a73462 100644
--- a/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp
+++ b/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp
@@ -18,3 +18,31 @@ void test(A *a) {
x = sizeof(a->bitX = 3); // expected-error {{invalid application of 'sizeof' to bit-field}}
x = sizeof(a->bitY += 3); // expected-error {{invalid application of 'sizeof' to bit-field}}
}
+
+void test2() {
+ int x;
+ x = sizeof(void); // expected-error {{invalid application of 'sizeof' to an incomplete type 'void'}}
+ x = sizeof(int()); // expected-error {{invalid application of 'sizeof' to a function type}}
+ x = sizeof(test2()); // expected-error {{invalid application of 'sizeof' to an incomplete type 'void'}}
+ x = sizeof(test2); // expected-error {{invalid application of 'sizeof' to a function type}}
+}
+
+namespace pr16992 {
+
+template<typename T> struct ABC {
+ int func () {
+ return sizeof T; // expected-error {{expected parentheses around type name in sizeof expression}}
+ }
+};
+
+ABC<int> qq;
+
+template<typename T> struct ABC2 {
+ int func () {
+ return sizeof T::A;
+ }
+};
+
+struct QQ { int A; };
+ABC2<QQ> qq2;
+}
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
index 1f5969d49327..427e8c5007f2 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions -Wno-delete-incomplete %s
// expected-no-diagnostics
#define P(e) static_assert(noexcept(e), "expected nothrow")
@@ -39,6 +39,9 @@ void (*pallspec)() throw(...);
void (*pintspec)() throw(int);
void (*pemptyspec)() throw();
+typedef void (*funcptr)();
+funcptr returnsptr() throw();
+
void callptr() {
N(pnospec());
N((*pnospec)());
@@ -48,6 +51,7 @@ void callptr() {
N((*pintspec)());
P(pemptyspec());
P((*pemptyspec)());
+ N(returnsptr()());
}
struct S1 {
@@ -91,6 +95,8 @@ struct S2 {
void *operator new(__typeof__(sizeof(int)) sz, int) throw();
+struct IncompleteStruct;
+
struct Bad1 {
~Bad1() throw(int);
};
@@ -104,6 +110,7 @@ void implicits() {
N(new int);
P(new (0) int);
P(delete (int*)0);
+ P(delete (IncompleteStruct*)0);
N(delete (Bad1*)0);
N(delete (Bad2*)0);
N(S2());
diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
index 06cc61074026..cd55cc2441a2 100644
--- a/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
@@ -38,6 +38,8 @@ namespace test2 {
};
void A::test() {
- int (A::*ptr)(int) = &(A::foo); // expected-error {{can't form member pointer of type 'int (test2::A::*)(int)' without '&' and class name}}
+ // FIXME: The error message in this case is less than clear, we can do
+ // better.
+ int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot create a non-constant pointer to member function}}
}
}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p11.cpp b/test/CXX/lex/lex.literal/lex.ext/p11.cpp
new file mode 100644
index 000000000000..8b5fcf4b609b
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p11.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+
+template<typename T, typename U> struct same_type;
+template<typename T> struct same_type<T, T> {};
+template<typename T> using X = T;
+template<typename CharT, X<CharT>...>
+int operator "" _x(); // expected-warning {{string literal operator templates are a GNU extension}}
+template<char...>
+double operator "" _x();
+
+auto a="string"_x;
+auto b=42_x;
+same_type<decltype(a), int> test_a;
+same_type<decltype(b), double> test_b;
+
+char operator "" _x(const char *begin, size_t size);
+auto c="string"_x;
+auto d=L"string"_x;
+same_type<decltype(c), char> test_c;
+same_type<decltype(d), int> test_d;
diff --git a/test/CXX/lex/lex.literal/lex.ext/p12.cpp b/test/CXX/lex/lex.literal/lex.ext/p12.cpp
new file mode 100644
index 000000000000..dad468093984
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p12.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=gnu++11 -verify %s
+
+template<typename T, T... cs> struct check; // expected-note {{template is declared here}} expected-note {{template is declared here}}
+template<>
+struct check<char, 34, -47, -126, -48, -75, -47, -127, -47, -126, 32, -16, -112, -128, -128>{};
+template<>
+struct check<char16_t, 34, 1090, 1077, 1089, 1090, 32, 55296, 56320>{};
+template<>
+struct check<char32_t, 34, 1090, 1077, 1089, 1090, 32, 65536>{};
+template<typename T, T... str> int operator""_x() { // #1 expected-warning {{string literal operator templates are a GNU extension}}
+ check<T, str...> chars; // expected-error {{implicit instantiation of undefined template 'check<char, 't', 'e', 's', 't'>'}} expected-error {{implicit instantiation of undefined template 'check<char32_t, 34, 1090, 1077, 1089, 1090, 95, 65536>'}}
+ return 1;
+}
+void *operator""_x(const char*); // #2
+void *a = 123_x; // ok, calls #2
+int b = u8"\"теÑÑ‚ ð€€"_x; // ok, calls #1
+int c = u8R"("теÑÑ‚ ð€€)"_x; // ok, calls #1
+int d = "test"_x; // expected-note {{in instantiation of function template specialization 'operator "" _x<char, 't', 'e', 's', 't'>' requested here}}
+int e = uR"("теÑÑ‚ ð€€)"_x;
+int f = UR"("теÑÑ‚ ð€€)"_x;
+int g = UR"("теÑÑ‚_ð€€)"_x; // expected-note {{in instantiation of function template specialization 'operator "" _x<char32_t, 34, 1090, 1077, 1089, 1090, 95, 65536>' requested here}}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p3.cpp b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
index 43f3468e96d3..e812ddddd8a4 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p3.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
@@ -9,7 +9,7 @@ int &i2 = 45_x1;
template<char...> char &operator "" _x1 ();
int &i3 = 0377_x1;
-int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-warning {{integer constant is too large}}
+int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-error {{integer constant is larger than the largest unsigned integer type}}
double &operator "" _x2 (const char *);
double &i5 = 123123123123123123123123123123123123123123123_x2;
diff --git a/test/CXX/lex/lex.literal/lex.ext/p5.cpp b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
index 06c091d8acae..d364a37c6cf1 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p5.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -triple=x86_64-linux-gnu
using size_t = decltype(sizeof(int));
@@ -6,7 +6,7 @@ int &operator "" _x1 (const char *);
double &operator "" _x1 (const char *, size_t);
double &i1 = "foo"_x1;
double &i2 = u8"foo"_x1;
-double &i3 = L"foo"_x1; // expected-error {{no matching literal operator}}
+double &i3 = L"foo"_x1; // expected-error {{no matching literal operator for call to 'operator "" _x1' with arguments of types 'const wchar_t *' and 'unsigned long'}}
char &operator "" _x1(const wchar_t *, size_t);
char &i4 = L"foo"_x1; // ok
diff --git a/test/CXX/lex/lex.literal/lex.ext/p7.cpp b/test/CXX/lex/lex.literal/lex.ext/p7.cpp
index 79c9394a96ba..be97f0cb922f 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p7.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p7.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -triple=x86_64-linux-gnu
using size_t = decltype(sizeof(int));
namespace std {
@@ -17,7 +17,7 @@ int main() {
auto v1 = 1.2_w; // calls operator "" _w(1.2L)
auto v2 = u"one"_w; // calls operator "" _w(u"one", 3)
auto v3 = 12_w; // calls operator "" _w("12")
- "two"_w; // expected-error {{no matching literal operator}}
+ "two"_w; // expected-error {{no matching literal operator for call to 'operator "" _w' with arguments of types 'const char *' and 'unsigned long'}}
same_type<decltype(v1), long double> test1;
same_type<decltype(v2), std::string> test2;
diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
index e0217112d91b..b1c819a93b42 100644
--- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -125,7 +125,7 @@ int main()
namespace member_pointers {
struct S {
- template <typename T> bool f(T) { return false; }
+ template <typename T> bool f(T) { return false; } // expected-note 4 {{possible target for call}}
template <typename T> static bool g(T) { return false; }
template <typename T> bool h(T) { return false; } // expected-note 3 {{possible target for call}}
diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp
index 3e8d0f1d8cdd..d03b84a2d15b 100644
--- a/test/CXX/over/over.over/p2.cpp
+++ b/test/CXX/over/over.over/p2.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<typename T> T f0(T, T); //expected-note{{candidate}}
+template <typename T>
+T f0(T, T); // expected-note{{deduced conflicting types for parameter 'T' ('int' vs. 'float')}}
void test_f0() {
int (*f0a)(int, int) = f0;
diff --git a/test/CXX/special/class.copy/implicit-move-def.cpp b/test/CXX/special/class.copy/implicit-move-def.cpp
index 5c54aea12443..5696d1f57982 100644
--- a/test/CXX/special/class.copy/implicit-move-def.cpp
+++ b/test/CXX/special/class.copy/implicit-move-def.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-ASSIGN %s
+// FIXME: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK %s
// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-ASSIGN %s
// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-CTOR %s
diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp
index 33374129f718..23ecf2e7d95a 100644
--- a/test/CXX/special/class.copy/implicit-move.cpp
+++ b/test/CXX/special/class.copy/implicit-move.cpp
@@ -190,49 +190,114 @@ namespace DR1402 {
NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default;
};
- // A non-movable, non-trivially-copyable class type as a subobject inhibits
- // the declaration of a move operation.
- struct NoMove1 { NonTrivialCopyCtor ntcc; }; // expected-note 2{{'const DR1402::NoMove1 &'}}
- struct NoMove2 { NonTrivialCopyAssign ntcc; }; // expected-note 2{{'const DR1402::NoMove2 &'}}
- struct NoMove3 : NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove3 &'}}
- struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove4 &'}}
- struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove5 &'}}
- struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove6 &'}}
- struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'const DR1402::NoMove7 &'}}
- struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'const DR1402::NoMove8 &'}}
-
- // A non-trivially-move-assignable virtual base class inhibits the declaration
- // of a move assignment (which might move-assign the base class multiple
- // times).
+ // DR1402: A non-movable, non-trivially-copyable class type as a subobject no
+ // longer inhibits the declaration of a move operation.
+ struct NoMove1 { NonTrivialCopyCtor ntcc; };
+ struct NoMove2 { NonTrivialCopyAssign ntcc; };
+ struct NoMove3 : NonTrivialCopyCtor {};
+ struct NoMove4 : NonTrivialCopyAssign {};
+ struct NoMove5 : virtual NonTrivialCopyCtor {};
+ struct NoMove6 : virtual NonTrivialCopyAssign {};
+ struct NoMove7 : NonTrivialCopyCtorVBase {};
+ struct NoMove8 : NonTrivialCopyAssignVBase {};
+
+ // DR1402: A non-trivially-move-assignable virtual base class no longer
+ // inhibits the declaration of a move assignment (even though it might
+ // move-assign the base class multiple times).
struct NoMove9 : NonTrivialMoveAssign {};
- struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'const DR1402::NoMove10 &'}}
- struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'const DR1402::NoMove11 &'}}
-
- struct Test {
- friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{no matching function}}
- friend NoMove2::NoMove2(NoMove2 &&); // expected-error {{no matching function}}
- friend NoMove3::NoMove3(NoMove3 &&); // expected-error {{no matching function}}
- friend NoMove4::NoMove4(NoMove4 &&); // expected-error {{no matching function}}
- friend NoMove5::NoMove5(NoMove5 &&); // expected-error {{no matching function}}
- friend NoMove6::NoMove6(NoMove6 &&); // expected-error {{no matching function}}
- friend NoMove7::NoMove7(NoMove7 &&); // expected-error {{no matching function}}
- friend NoMove8::NoMove8(NoMove8 &&); // expected-error {{no matching function}}
- friend NoMove9::NoMove9(NoMove9 &&);
- friend NoMove10::NoMove10(NoMove10 &&);
- friend NoMove11::NoMove11(NoMove11 &&);
-
- friend NoMove1 &NoMove1::operator=(NoMove1 &&); // expected-error {{no matching function}}
- friend NoMove2 &NoMove2::operator=(NoMove2 &&); // expected-error {{no matching function}}
- friend NoMove3 &NoMove3::operator=(NoMove3 &&); // expected-error {{no matching function}}
- friend NoMove4 &NoMove4::operator=(NoMove4 &&); // expected-error {{no matching function}}
- friend NoMove5 &NoMove5::operator=(NoMove5 &&); // expected-error {{no matching function}}
- friend NoMove6 &NoMove6::operator=(NoMove6 &&); // expected-error {{no matching function}}
- friend NoMove7 &NoMove7::operator=(NoMove7 &&); // expected-error {{no matching function}}
- friend NoMove8 &NoMove8::operator=(NoMove8 &&); // expected-error {{no matching function}}
- friend NoMove9 &NoMove9::operator=(NoMove9 &&);
- friend NoMove10 &NoMove10::operator=(NoMove10 &&); // expected-error {{no matching function}}
- friend NoMove11 &NoMove11::operator=(NoMove11 &&); // expected-error {{no matching function}}
+ struct NoMove10 : virtual NonTrivialMoveAssign {};
+ struct NoMove11 : NonTrivialMoveAssignVBase {};
+
+ template<typename T> void test(T t) {
+ (void)T(static_cast<T&&>(t)); // ok
+ t = static_cast<T&&>(t); // ok
+ }
+ template void test(NoMove1);
+ template void test(NoMove2);
+ template void test(NoMove3);
+ template void test(NoMove4);
+ template void test(NoMove5);
+ template void test(NoMove6);
+ template void test(NoMove7);
+ template void test(NoMove8);
+ template void test(NoMove9);
+ template void test(NoMove10);
+ template void test(NoMove11);
+
+ struct CopyOnly {
+ CopyOnly(const CopyOnly&);
+ CopyOnly &operator=(const CopyOnly&);
};
+ struct MoveOnly {
+ MoveOnly(MoveOnly&&); // expected-note {{user-declared move}}
+ MoveOnly &operator=(MoveOnly&&);
+ };
+ template void test(CopyOnly); // ok, copies
+ template void test(MoveOnly); // ok, moves
+ struct CopyAndMove { // expected-note {{implicitly deleted}}
+ CopyOnly co;
+ MoveOnly mo; // expected-note {{deleted copy}}
+ };
+ template void test(CopyAndMove); // ok, copies co, moves mo
+ void test2(CopyAndMove cm) {
+ (void)CopyAndMove(cm); // expected-error {{deleted}}
+ cm = cm; // expected-error {{deleted}}
+ }
+
+ namespace VbaseMove {
+ struct A {};
+ struct B { B &operator=(B&&); };
+ struct C { C &operator=(const C&); };
+ struct D { B b; };
+
+ template<typename T, unsigned I, bool NonTrivialMove = false>
+ struct E : virtual T {};
+
+ template<typename T, unsigned I>
+ struct E<T, I, true> : virtual T { E &operator=(E&&); };
+
+ template<typename T>
+ struct F :
+ E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
+ E<T, 1> {}; // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
+
+ template<typename T>
+ struct G : E<T, 0, true>, E<T, 0> {};
+
+ template<typename T>
+ struct H : E<T, 0, true>, E<T, 1, true> {};
+
+ template<typename T>
+ struct I : E<T, 0>, T {};
+
+ template<typename T>
+ struct J :
+ E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
+ virtual T {}; // expected-note-re 2{{virtual base class '[BD]' declared here}}
+
+ template<typename T> void move(T t) { t = static_cast<T&&>(t); }
+ // expected-warning-re@-1 4{{defaulted move assignment operator of .* will move assign virtual base class '[BD]' multiple times}}
+ template void move(F<A>);
+ template void move(F<B>); // expected-note {{in instantiation of}}
+ template void move(F<C>);
+ template void move(F<D>); // expected-note {{in instantiation of}}
+ template void move(G<A>);
+ template void move(G<B>);
+ template void move(G<C>);
+ template void move(G<D>);
+ template void move(H<A>);
+ template void move(H<B>);
+ template void move(H<C>);
+ template void move(H<D>);
+ template void move(I<A>);
+ template void move(I<B>);
+ template void move(I<C>);
+ template void move(I<D>);
+ template void move(J<A>);
+ template void move(J<B>); // expected-note {{in instantiation of}}
+ template void move(J<C>);
+ template void move(J<D>); // expected-note {{in instantiation of}}
+ }
}
namespace PR12625 {
diff --git a/test/CXX/special/class.copy/p11.0x.copy.cpp b/test/CXX/special/class.copy/p11.0x.copy.cpp
index fab3b9dd7bf1..a334c50e9fda 100644
--- a/test/CXX/special/class.copy/p11.0x.copy.cpp
+++ b/test/CXX/special/class.copy/p11.0x.copy.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+struct Trivial {};
struct NonTrivial {
NonTrivial(const NonTrivial&);
};
@@ -69,6 +70,12 @@ struct Deleted {
Deleted Da;
Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}}
+// It's implied (but not stated) that this also applies in the case where
+// overload resolution would fail.
+struct VolatileMember {
+ volatile Trivial vm; // expected-note {{has no copy}}
+} vm1, vm2(vm1); // expected-error {{deleted}}
+
// -- a direct or virtual base class B that cannot be copied because overload
// resolution results in an ambiguity or a function that is deleted or
// inaccessible
@@ -116,6 +123,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
// -- a non-static data member of rvalue reference type
struct RValue {
int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+ // expected-warning@-1{{binding reference member 'ri' to a temporary}} expected-note@-1 {{here}}
};
RValue RVa;
RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
diff --git a/test/CXX/special/class.copy/p11.0x.move.cpp b/test/CXX/special/class.copy/p11.0x.move.cpp
index ff9478be8b49..1dce27a83290 100644
--- a/test/CXX/special/class.copy/p11.0x.move.cpp
+++ b/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+struct Trivial {};
struct NonTrivial {
NonTrivial(NonTrivial&&);
};
@@ -61,6 +62,24 @@ struct Deleted {
};
Deleted::Deleted(Deleted&&) = default; // expected-error{{would delete}}
+// It's implied (but not stated) that this should also happen if overload
+// resolution fails.
+struct ConstMember {
+ const Trivial ct;
+ ConstMember(ConstMember&&);
+};
+ConstMember::ConstMember(ConstMember&&) = default; // ok, calls copy ctor
+struct ConstMoveOnlyMember {
+ const NonTrivial cnt;
+ ConstMoveOnlyMember(ConstMoveOnlyMember&&);
+};
+ConstMoveOnlyMember::ConstMoveOnlyMember(ConstMoveOnlyMember&&) = default; // expected-error{{would delete}}
+struct VolatileMember {
+ volatile Trivial vt;
+ VolatileMember(VolatileMember&&);
+};
+VolatileMember::VolatileMember(VolatileMember&&) = default; // expected-error{{would delete}}
+
// -- a direct or virtual base class B that cannot be moved because overload
// resolution results in an ambiguity or a function that is deleted or
// inaccessible
@@ -108,7 +127,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
// The restriction on rvalue reference members applies to only the copy
// constructor.
struct RValue {
- int &&ri = 1;
+ int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
RValue(RValue&&);
};
RValue::RValue(RValue&&) = default;
diff --git a/test/CXX/special/class.copy/p12-0x.cpp b/test/CXX/special/class.copy/p12-0x.cpp
index 17b3191d1dc5..1b23b5a4b179 100644
--- a/test/CXX/special/class.copy/p12-0x.cpp
+++ b/test/CXX/special/class.copy/p12-0x.cpp
@@ -157,8 +157,8 @@ namespace TrivialityDependsOnImplicitDeletion {
struct NoAccess {
PrivateMove pm;
- // NoAccess's move would be deleted, so is suppressed,
- // so moves of it use PrivateMove's copy ctor, which is trivial.
+ // NoAccess's move is deleted, so moves of it use PrivateMove's copy ctor,
+ // which is trivial.
};
static_assert(__is_trivially_constructible(NoAccess, const NoAccess &), "");
static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), "");
diff --git a/test/CXX/special/class.copy/p23-cxx11.cpp b/test/CXX/special/class.copy/p23-cxx11.cpp
index 90945c5803a1..de071f050f01 100644
--- a/test/CXX/special/class.copy/p23-cxx11.cpp
+++ b/test/CXX/special/class.copy/p23-cxx11.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -verify %s -std=c++11
+struct Trivial {};
+
template<typename T> struct CopyAssign {
static T t;
void test() {
@@ -9,7 +11,15 @@ template<typename T> struct CopyAssign {
template<typename T> struct MoveAssign {
static T t;
void test() {
- t = static_cast<T&&>(t); // expected-error +{{deleted}}
+ // Overload resolution will ignore a defaulted, deleted move assignment,
+ // so check for it in a different way.
+ T &(T::*f)(T&&) = &T::operator=; // expected-error +{{deleted}}
+ }
+};
+template<typename T> struct MoveOrCopyAssign {
+ static T t;
+ void test() {
+ t = static_cast<T&&>(t); // expected-error +{{copy assignment operator is implicitly deleted}}
}
};
@@ -39,6 +49,9 @@ class InaccessibleCopyAssign {
class InaccessibleMoveAssign {
InaccessibleMoveAssign &operator=(InaccessibleMoveAssign &&);
};
+class NonConstCopyAssign {
+ NonConstCopyAssign &operator=(NonConstCopyAssign &);
+};
// A defaulted copy/move assignment operator for class X is defined as deleted
// if X has:
@@ -89,29 +102,44 @@ struct D1 {
AmbiguousCopyAssign a; // expected-note {{field 'a' has multiple copy}}
};
struct D2 {
- D2 &operator=(D2 &&) = default; // expected-note {{here}}
+ D2 &operator=(D2 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
AmbiguousMoveAssign a; // expected-note {{field 'a' has multiple move}}
};
struct D3 {
DeletedCopyAssign a; // expected-note {{field 'a' has a deleted copy}}
};
struct D4 {
- D4 &operator=(D4 &&) = default; // expected-note {{here}}
+ D4 &operator=(D4 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
DeletedMoveAssign a; // expected-note {{field 'a' has a deleted move}}
};
struct D5 {
InaccessibleCopyAssign a; // expected-note {{field 'a' has an inaccessible copy}}
};
struct D6 {
- D6 &operator=(D6 &&) = default; // expected-note {{here}}
+ D6 &operator=(D6 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
InaccessibleMoveAssign a; // expected-note {{field 'a' has an inaccessible move}}
};
+struct D7 {
+ const Trivial a; // expected-note 3{{field 'a' has no }}
+};
+struct D8 {
+ volatile Trivial a; // expected-note 3{{field 'a' has no }}
+};
template struct CopyAssign<D1>; // expected-note {{here}}
template struct MoveAssign<D2>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D2>; // expected-note {{here}}
template struct CopyAssign<D3>; // expected-note {{here}}
template struct MoveAssign<D4>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D4>; // expected-note {{here}}
template struct CopyAssign<D5>; // expected-note {{here}}
template struct MoveAssign<D6>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D6>; // expected-note {{here}}
+template struct CopyAssign<D7>; // expected-note {{here}}
+template struct MoveAssign<D7>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D7>; // expected-note {{here}}
+template struct CopyAssign<D8>; // expected-note {{here}}
+template struct MoveAssign<D8>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D8>; // expected-note {{here}}
// -- a direct or virtual base that cannot be copied/moved
struct E1 : AmbiguousCopyAssign {}; // expected-note {{base class 'AmbiguousCopyAssign' has multiple copy}}
@@ -136,7 +164,7 @@ template struct MoveAssign<E6>; // expected-note {{here}}
namespace PR13381 {
struct S {
S &operator=(const S&);
- S &operator=(const volatile S&) = delete; // expected-note{{deleted here}}
+ S &operator=(const volatile S&) volatile = delete; // expected-note{{deleted here}}
};
struct T {
volatile S s; // expected-note{{field 's' has a deleted copy assignment}}
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index 0f4add8c9742..2360345a4846 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -43,7 +43,7 @@ class NotDeleted2a { int &a = n; };
NotDeleted2a nd2a;
class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
NotDeleted2b nd2b;
-class NotDeleted2c { int &&a = 0; };
+class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
NotDeleted2c nd2c;
// - any non-variant non-static data member of const qualified type (or array
diff --git a/test/CXX/special/class.inhctor/p1.cpp b/test/CXX/special/class.inhctor/p1.cpp
index 8721dec1b405..fa0416e11765 100644
--- a/test/CXX/special/class.inhctor/p1.cpp
+++ b/test/CXX/special/class.inhctor/p1.cpp
@@ -2,31 +2,30 @@
// Per a core issue (no number yet), an ellipsis is always dropped.
struct A {
A(...); // expected-note {{here}}
- A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}}
+ A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}} expected-note 2{{constructor cannot be inherited}}
A(int = 0, int = 0, ...); // expected-note {{here}}
template<typename T> A(T, int = 0, ...); // expected-note 5{{here}}
- template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}}
+ template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}} expected-note {{constructor cannot be inherited}}
template<typename T, int N> A(const T (&)[N], int = 0); // expected-note 2{{here}}
};
struct B : A { // expected-note 6{{candidate}}
- using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted}}
+ using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted constructor was inherited here}}
};
struct C {} c;
B b0{};
-// expected-error@-1 {{call to implicitly-deleted default constructor}}
+// expected-error@-1 {{call to implicitly-deleted default constructor of 'B'}}
// expected-note@-8 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}}
B b1{1};
-// FIXME: explain why the inheriting constructor was deleted
-// expected-error@-2 {{call to implicitly-deleted function of 'B'}}
+// expected-error@-1 {{call to deleted constructor of 'B'}}
B b2{1,2};
-// expected-error@-1 {{call to implicitly-deleted function of 'B'}}
+// expected-error@-1 {{call to deleted constructor of 'B'}}
B b3{1,2,3};
// ok
diff --git a/test/CXX/special/class.inhctor/p4.cpp b/test/CXX/special/class.inhctor/p4.cpp
index 512705e4dd94..356cdef687fb 100644
--- a/test/CXX/special/class.inhctor/p4.cpp
+++ b/test/CXX/special/class.inhctor/p4.cpp
@@ -43,13 +43,13 @@ FA fa2{X<2>{}}; // expected-error {{calling a private constructor}}
// It is deleted if the corresponding constructor [...] is deleted.
struct G {
- G(int) = delete;
- template<typename T> G(T*) = delete;
+ G(int) = delete; // expected-note {{function has been explicitly marked deleted here}}
+ template<typename T> G(T*) = delete; // expected-note {{function has been explicitly marked deleted here}}
};
struct H : G {
- using G::G; // expected-note 2{{marked deleted here}}
+ using G::G; // expected-note 2{{deleted constructor was inherited here}}
};
-H h1(5); // expected-error {{call to implicitly-deleted function of 'H'}}
+H h1(5); // expected-error {{call to deleted constructor of 'H'}}
H h2("foo"); // expected-error {{call to deleted constructor of 'H'}}
@@ -58,15 +58,14 @@ H h2("foo"); // expected-error {{call to deleted constructor of 'H'}}
namespace DRnnnn {
struct A {
constexpr A(int, float = 0) {}
- explicit A(int, int = 0) {}
+ explicit A(int, int = 0) {} // expected-note {{constructor cannot be inherited}}
A(int, int, int = 0) = delete;
};
struct B : A {
- // FIXME: produce notes indicating why it was deleted
using A::A; // expected-note {{here}}
};
constexpr B b0(0, 0.0f); // ok, constexpr
- B b1(0, 1); // expected-error {{call to implicitly-deleted}}
+ B b1(0, 1); // expected-error {{call to deleted constructor of 'DRnnnn::B'}}
}
diff --git a/test/CXX/special/class.inhctor/p8.cpp b/test/CXX/special/class.inhctor/p8.cpp
index 0c857382e38c..effc2c3bca24 100644
--- a/test/CXX/special/class.inhctor/p8.cpp
+++ b/test/CXX/special/class.inhctor/p8.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
-// expected-no-diagnostics
struct A {
constexpr A(const int&) : rval(false) {}
constexpr A(const int&&) : rval(true) {}
@@ -28,3 +27,6 @@ struct D : C {
using C::C;
};
static_assert(D(123).v == 123, "");
+
+// FIXME: This diagnostic sucks.
+template<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{definition of implicitly declared function}}
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 b159a15b8d40..c23cd28f3137 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -117,7 +117,7 @@ void g() {
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
- for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
+ for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}} expected-warning {{deprecated}}
for (constexpr int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'constexpr'}}
for (auto u : X::NoBeginADL()) { // expected-error {{invalid range expression of type 'X::NoBeginADL'; no viable 'begin' function available}}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index c4db0027052c..3f70ca7c81ab 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -27,7 +27,7 @@ namespace non_type_tmpl_param {
// omitted if the name refers to a function or array and shall be omitted
// if the corresopnding template-parameter is a reference; or
namespace addr_of_obj_or_func {
- template <int* p> struct X0 { }; // expected-note 4{{here}}
+ template <int* p> struct X0 { }; // expected-note 5{{here}}
template <int (*fp)(int)> struct X1 { };
template <int &p> struct X2 { }; // expected-note 4{{here}}
template <const int &p> struct X2k { }; // expected-note {{here}}
@@ -40,6 +40,7 @@ namespace addr_of_obj_or_func {
__thread int ti = 100; // expected-note 2{{here}}
static int f_internal(int); // expected-note 4{{here}}
template <typename T> T f_tmpl(T t);
+ struct S { union { int NonStaticMember; }; };
void test() {
X0<i> x0a; // expected-error {{must have its address taken}}
@@ -78,6 +79,7 @@ namespace addr_of_obj_or_func {
X0<&n> x0_no_linkage; // expected-error {{non-type template argument refers to object 'n' that does not have linkage}}
struct Local { static int f() {} }; // expected-note {{here}}
X1<&Local::f> x1_no_linkage; // expected-error {{non-type template argument refers to function 'f' that does not have linkage}}
+ X0<&S::NonStaticMember> x0_non_static; // expected-error {{non-static data member}}
}
}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
index afd9b4b0de30..2d46502e1d9b 100644
--- a/test/CXX/temp/temp.decls/temp.alias/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
@@ -9,5 +9,9 @@ template<class T> struct A {
B<short> b;
template<typename T> using U = int;
+
+template<typename ...T> void f(U<T> ...xs);
+void g() { f<void,void,void>(1, 2, 3); }
+
// FIXME: This is illegal, but probably only because CWG1044 missed this paragraph.
template<typename T> using U = U<T>;
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
new file mode 100644
index 000000000000..a49db5166a45
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s
+
+// -- The argument list of the specialization shall not be identical
+// to the implicit argument list of the primary template.
+
+template<typename T, int N, template<typename> class X> int v1;
+template<typename T, int N, template<typename> class X> int v1<T, N, X>;
+// expected-error@-1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename...T> int v2;
+template<typename...T> int v2<T...>;
+// expected-error@-1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<int...N> int v3;
+template<int...N> int v3<N...>;
+// expected-error@-1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<template<typename> class...X> int v4;
+template<template<typename> class...X> int v4<X...>;
+// expected-error@-1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename Outer> struct X {
+ template<typename Inner> static int y;
+ template<typename Inner> static int y<Outer>; // expected-warning {{can not be deduced}} expected-note {{'Inner'}}
+ template<typename Inner> static int y<Inner>; // expected-error {{does not specialize}}
+};
+template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-warning {{can not be deduced}} expected-note {{'Inner'}}
+template<typename Outer> template<typename Inner> int X<Outer>::y<Inner>; // expected-error {{does not specialize}}
+
+// FIXME: Merging this with the above class causes an assertion failure when
+// instantiating one of the bogus partial specializations.
+template<typename Outer> struct Y {
+ template<typename Inner> static int y;
+};
+template<> template<typename Inner> int Y<int>::y<Inner>; // expected-error {{does not specialize}}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
index f8cc00947480..2884be146c7c 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
@@ -12,7 +12,7 @@ A<int> a;
A<int>::E a0 = A<int>().v;
int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
-template<typename T> enum A<T>::E : T { e1, e2 };
+template<typename T> enum A<T>::E : T { e1, e2 }; // expected-note 2 {{declared here}}
// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
// into the already-instantiated class A<T>. This seems like a really bad idea,
@@ -20,7 +20,7 @@ template<typename T> enum A<T>::E : T { e1, e2 };
//
// Either do as the standard says, or only include enumerators lexically defined
// within the class in its scope.
-A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}
+A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'; did you mean simply 'e1'?}}
A<char>::E a2 = A<char>::e2;
@@ -94,7 +94,7 @@ D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
template<> enum class D<int>::E { e2 };
D<int>::E d2 = D<int>::E::e2;
D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
-D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
+D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2' in 'D<char>::E'; did you mean simply 'e2'?}}
template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
template<> enum class D<short>::E;
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index 2eae1125c0db..8a3168e5f806 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -23,4 +23,4 @@ X2& get_X2() {
return X0<X2>::value; // expected-note{{instantiation}}
}
-template<typename T> T x; // expected-error{{variable 'x' declared as a template}}
+template<typename T> T x; // expected-warning{{variable templates are a C++1y extension}}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
index 6d22f8809365..60c60cb0b28d 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
@@ -43,3 +43,10 @@ namespace OrderWithStaticMember {
a.g(p);
}
}
+
+namespace PR17075 {
+ template <typename T> struct V {};
+ struct S { template<typename T> S &operator>>(T &t) = delete; };
+ template<typename T> S &operator>>(S &s, V<T> &v);
+ void f(S s, V<int> v) { s >> v; }
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
index e036cef32b28..8571a141201b 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
@@ -26,3 +26,20 @@ void g() {
X2<float> xf;
f(xf);
}
+
+template<typename T>
+struct X3 {
+ operator int();
+
+ friend void h(int x);
+};
+
+int array2[sizeof(X3<int>)];
+int array3[sizeof(X3<float>)];
+
+void i() {
+ X3<int> xi;
+ h(xi);
+ X3<float> xf;
+ h(xf);
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index 4b899e4e5211..b26abb64f838 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
namespace test0 {
template <class T> class A {
@@ -7,7 +6,8 @@ namespace test0 {
};
class B {
- template <class T> friend class A<T>::Member;
+ template <class T> friend class A<T>::Member; // expected-warning {{not supported}}
+ int n;
};
A<int> a;
@@ -68,7 +68,7 @@ namespace test3 {
template <class U> class C {
int i;
- template <class T> friend struct A<T>::Inner;
+ template <class T> friend struct A<T>::Inner; // expected-warning {{not supported}}
};
template <class T> int A<T>::Inner::foo() {
@@ -96,7 +96,7 @@ namespace test4 {
namespace test5 {
template<template <class> class T> struct A {
- template<template <class> class T> friend void A<T>::foo();
+ template<template <class> class U> friend void A<U>::foo();
};
template <class> struct B {};
diff --git a/test/CXX/temp/temp.decls/temp.mem/p2.cpp b/test/CXX/temp/temp.decls/temp.mem/p2.cpp
new file mode 100644
index 000000000000..c24d5a9b50de
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.mem/p2.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template <typename>
+void quux();
+
+void fun() {
+ struct foo {
+ template <typename> struct bar {}; // expected-error{{templates cannot be declared inside of a local class}}
+ template <typename> void baz() {} // expected-error{{templates cannot be declared inside of a local class}}
+ template <typename> void qux(); // expected-error{{templates cannot be declared inside of a local class}}
+ };
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p2.cpp b/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
index ce19582c2282..e7a62366a9be 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
@@ -12,7 +12,7 @@ void test() {
template<typename Head, typename ...Tail>
void recurse_until_fail(const Head &, const Tail &...tail) { // expected-note{{candidate function template not viable: requires at least 1 argument, but 0 were provided}}
recurse_until_fail(tail...); // expected-error{{no matching function for call to 'recurse_until_fail'}} \
- // expected-note{{in instantiation of function template specialization 'recurse_until_fail<char [7], >' requested here}} \
+ // expected-note{{in instantiation of function template specialization 'recurse_until_fail<char [7]>' requested here}} \
// expected-note{{in instantiation of function template specialization 'recurse_until_fail<double, char [7]>' requested here}}
}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 945379872f78..3681d7757e94 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -165,6 +165,7 @@ template<typename T, typename... Types>
struct alignas(Types) TestUnexpandedDecls : T{ // expected-error{{expression contains unexpanded parameter pack 'Types'}}
void member_function(Types); // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
void member_function () throw(Types); // expected-error{{exception type contains unexpanded parameter pack 'Types'}}
+ void member_function2() noexcept(Types()); // expected-error{{expression contains unexpanded parameter pack 'Types'}}
operator Types() const; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
Types data_member; // expected-error{{data member type contains unexpanded parameter pack 'Types'}}
static Types static_data_member; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
@@ -410,3 +411,14 @@ namespace WorkingPaperExample {
f(h(args ...) + args ...);
}
}
+
+namespace PR16303 {
+ template<int> struct A { A(int); };
+ template<int...N> struct B {
+ template<int...M> struct C : A<N>... {
+ C() : A<N>(M)... {} // expected-error{{pack expansion contains parameter packs 'N' and 'M' that have different lengths (2 vs. 3)}} expected-error{{pack expansion contains parameter packs 'N' and 'M' that have different lengths (4 vs. 3)}}
+ };
+ };
+ B<1,2>::C<4,5,6> c1; // expected-note{{in instantiation of}}
+ B<1,2,3,4>::C<4,5,6> c2; // expected-note{{in instantiation of}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp b/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
new file mode 100644
index 000000000000..4960a2bac20a
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
@@ -0,0 +1,203 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+namespace pr12262 {
+
+template<typename T, typename... Ts>
+void abc1(int (*xxx)[sizeof ... (Ts) + 1]);
+
+void qq1 () {
+ abc1<int>(0);
+ abc1<int,double>(0);
+}
+
+
+template <unsigned N> class array {};
+
+
+template<typename T, typename... Types>
+array<sizeof...(Types)> make_array1(Types&&... args);
+
+void qq2 () {
+ array<1> arr = make_array1<int>(1);
+ array<3> arr2 = make_array1<int>(1,array<5>(),0.1);
+}
+
+
+template<typename T, typename... Types>
+int make_array(array<sizeof...(Types)>&, Types... args);
+
+void qq3 () {
+ array<1> a1;
+ int aa1 = make_array<int>(a1,1);
+ array<2> a2;
+ int aa2 = make_array<int>(a2, 0L, "abc");
+}
+
+
+template<typename ... Ts>
+struct AAA {
+ template<typename T, typename... Types>
+ static array<sizeof...(Types)> make_array(Types ... args);
+};
+
+void qq4 () {
+ array<2> arr2 = AAA<int, int>::make_array<int>(1,2);
+}
+
+}
+
+
+namespace pr12439 {
+
+template<class... Members>
+struct X {
+ template<int Idx>
+ using get_t = decltype(sizeof...(Members));
+
+ template<int i>
+ get_t<i> get();
+};
+
+template<class... Members>
+template<int i>
+X<Members...>::get_t<i> X<Members...>::get()
+{
+ return 0;
+}
+
+}
+
+
+namespace pr13272 {
+
+template<bool B, class T = void>
+struct enable_if { };
+
+template<class T> struct enable_if<true, T> {
+ typedef T type;
+};
+
+class Exception {};
+
+template<class Ex, typename... Args>
+void cxx_throw(typename enable_if<(sizeof...(Args) > 0), const char *>::type fmt, Args&&... args) {
+ return;
+}
+
+void test() {
+ cxx_throw<Exception>("Youpi",1);
+}
+
+}
+
+
+namespace pr13817 {
+
+template <unsigned>
+struct zod;
+
+template <>
+struct zod<1> {};
+
+template <typename T, typename ... Ts>
+zod<sizeof...(Ts)> make_zod(Ts ...) {
+ return zod<sizeof...(Ts)>();
+}
+
+int main(int argc, char *argv[])
+{
+ make_zod<int>(1);
+ return 0;
+}
+
+}
+
+
+namespace pr14273 {
+
+template<typename T, int i>
+struct myType
+{ };
+
+template<typename T, typename... Args>
+struct Counter
+{
+ static const int count = 1 + Counter<Args...>::count;
+};
+
+template<typename T>
+struct Counter<T>
+{
+ static const int count = 1;
+};
+
+template<typename Arg, typename... Args>
+myType<Arg, sizeof...(Args)>* make_array_with_type(const Args&... args)
+{
+ return 0;
+}
+
+void func(void)
+{
+ make_array_with_type<char>(1,2,3);
+}
+
+}
+
+
+namespace pr15112
+{
+ template<bool, typename _Tp = void>
+ struct enable_if
+ { };
+ template<typename _Tp>
+ struct enable_if<true,_Tp>
+ { typedef _Tp type; };
+
+ typedef __typeof__(sizeof(int)) size_t;
+
+ template <size_t n, typename T, typename... Args>
+ struct is_array_of { static const bool value = true; };
+
+ struct cpu { using value_type = void; };
+
+ template <size_t Order, typename T>
+ struct coords_alias { typedef T type; };
+
+ template <size_t Order, typename MemoryTag>
+ using coords = typename coords_alias<Order, MemoryTag>::type;
+
+ template <typename MemTag, typename... Args>
+ typename enable_if<is_array_of<sizeof...(Args), size_t, Args...>::value,
+ coords<sizeof...(Args), MemTag>>::type
+ mkcoords(Args... args);
+
+ auto c1 = mkcoords<cpu>(0ul, 0ul, 0ul);
+}
+
+
+namespace pr12699 {
+
+template<bool B>
+struct bool_constant
+{
+ static const bool value = B;
+};
+
+template<typename... A>
+struct F
+{
+ template<typename... B>
+ using SameSize = bool_constant<sizeof...(A) == sizeof...(B)>;
+
+ template<typename... B, typename = SameSize<B...>>
+ F(B...) { }
+};
+
+void func()
+{
+ F<int> f1(3);
+}
+
+}
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
index 67efc4e48162..c25868267e49 100644
--- a/test/CXX/temp/temp.param/p5.cpp
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -1,14 +1,13 @@
// RUN: %clang_cc1 -verify %s -std=c++11
-// expected-no-diagnostics
template<const int I> struct S {
decltype(I) n;
- int &&r = I;
+ int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
};
-S<5> s;
+S<5> s; // expected-note {{instantiation}}
template<typename T, T v> struct U {
decltype(v) n;
- int &&r = v;
+ int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
};
-U<const int, 6> u;
+U<const int, 6> u; // expected-note {{instantiation}}
diff --git a/test/CXX/temp/temp.res/temp.local/p6.cpp b/test/CXX/temp/temp.res/temp.local/p6.cpp
new file mode 100644
index 000000000000..eccbb8993213
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p6.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y
+
+template<typename T, // expected-note {{declared here}}
+ typename T> struct X {}; // expected-error {{declaration of 'T' shadows template parameter}}
+
+template<typename T> struct Y { // expected-note 15{{declared here}}
+ template<typename T> struct A {}; // expected-error {{declaration of 'T' shadows template parameter}}
+
+ struct B {
+ template<typename> struct T {}; // FIXME: desired-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct C {
+ template<typename> void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct D {
+ struct T {}; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct E {
+ typedef int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct F {
+ using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct G {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct H {
+ static int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct I {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct J {
+ enum T { e }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct K {
+ enum E { T }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+
+ void a() {
+ extern int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void b() {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void c() {
+ try {}
+ catch (int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void d() {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+
+ friend struct T; // expected-error {{declaration of 'T' shadows template parameter}}
+};
+
+template<typename T> // expected-note {{declared here}}
+void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
+
+// FIXME: These are ill-formed: a template-parameter shall not have the same name as the template name.
+namespace A {
+ template<typename T> struct T {};
+}
+namespace B {
+ template<typename T> void T() {}
+}
+namespace C {
+ template<typename T> int T;
+}
diff --git a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
new file mode 100644
index 000000000000..93f8ff1697bf
--- /dev/null
+++ b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 --std=c++1y -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 --std=c++1y -x c++ -fixit %t -DFIXING
+// RUN: %clang_cc1 --std=c++1y -x c++ %t -DFIXING
+
+template<typename T>
+T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+template int pi<int>;
+
+#ifndef FIXING
+template float pi<>; // expected-error {{too few template arguments for template 'pi'}}
+template double pi_var0; // expected-error {{explicit instantiation of 'pi_var0' does not refer to a function template, variable template, member function, member class, or static data member}}
+#endif
+
+// Should recover as if definition
+template double pi_var = 5; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}}
+#ifndef FIXING
+template<typename T>
+T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
+
+template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
+ expected-error{{redefinition of 'pi0' as different kind of symbol}}
+#endif
+
+template<typename T>
+T pi1 = T(3.1415926535897932385);
+
+// Should recover as if specialization
+template float pi1<float> = 1.0; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}}
+#ifndef FIXING
+namespace expected_global {
+ template<> double pi1<double> = 1.5; // expected-error {{no variable template matches specialization}}
+ template int pi1<int> = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
+ expected-error {{no variable template matches specialization}}
+}
+#endif
diff --git a/test/CXX/temp/temp.spec/no-body.cpp b/test/CXX/temp/temp.spec/no-body.cpp
new file mode 100644
index 000000000000..a4d7914d9eb6
--- /dev/null
+++ b/test/CXX/temp/temp.spec/no-body.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x c++ -fixit %t -DFIXING
+// RUN: %clang_cc1 -x c++ %t -DFIXING
+
+template<typename T> void f(T) { }
+template<typename T> void g(T) { }
+template<typename T> struct x { };
+template<typename T> struct y { }; // expected-note {{declared here}}
+
+namespace good {
+ template void f<int>(int);
+ template void g(int);
+ template struct x<int>;
+}
+
+namespace unsupported {
+#ifndef FIXING
+ template struct y; // expected-error {{elaborated type refers to a template}}
+#endif
+}
+
+template<typename T> void f0(T) { }
+template<typename T> void g0(T) { }
+template<typename T> struct x0 { }; // expected-note {{explicitly specialized declaration is here}}
+template<typename T> struct y0 { };
+
+// Should recover as if definition
+namespace noargs_body {
+#ifndef FIXING
+ template void g0(int) { } // expected-error {{function cannot be defined in an explicit instantiation; if this declaration is meant to be a function definition, remove the 'template' keyword}}
+#endif
+ template struct y0 { }; // expected-error {{class cannot be defined in an explicit instantiation; if this declaration is meant to be a class definition, remove the 'template' keyword}}
+}
+
+// Explicit specializations expected in global scope
+namespace exp_spec {
+#ifndef FIXING
+ template<> void f0<int>(int) { } // expected-error {{no function template matches function template specialization 'f0'}}
+ template<> struct x0<int> { }; // expected-error {{class template specialization of 'x0' must originally be declared in the global scope}}
+#endif
+}
+
+template<typename T> void f1(T) { }
+template<typename T> struct x1 { }; // expected-note {{explicitly specialized declaration is here}}
+
+// Should recover as if specializations,
+// thus also complain about not being in global scope.
+namespace args_bad {
+#ifndef FIXING
+ template void f1<int>(int) { } // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
+ expected-error {{no function template matches function template specialization 'f1'}}
+ template struct x1<int> { }; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
+ expected-error {{class template specialization of 'x1' must originally be declared in the global scope}}
+#endif
+}
+
+template<typename T> void f2(T) { }
+template<typename T> struct x2 { };
+
+// Should recover as if specializations
+template void f2<int>(int) { } // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}}
+template struct x2<int> { }; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
index aecbfb5649f3..d12feeff0bbc 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
@@ -163,7 +163,7 @@ namespace PR9877 {
template<> struct X<1>::Y { static const int Z = 1; };
const int X<0>::Y::Z;
- template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
+ template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
}
namespace PR9913 {
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
index ff24ad997dfd..38dc367b227e 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -emit-llvm -std=c++11 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-optzns -emit-llvm -std=c++11 -o - %s | FileCheck %s
template<typename T>
struct X0 {
diff --git a/test/CXX/temp/temp.spec/temp.inst/p1.cpp b/test/CXX/temp/temp.spec/temp.inst/p1.cpp
index 8684fc4dabd9..adf812b714d1 100644
--- a/test/CXX/temp/temp.spec/temp.inst/p1.cpp
+++ b/test/CXX/temp/temp.spec/temp.inst/p1.cpp
@@ -33,24 +33,23 @@ namespace ScopedEnum {
ScopedEnum1<double>::E e1; // ok
ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}}
- // The behavior for enums defined within function templates is not clearly
- // specified by the standard. We follow the rules for enums defined within
- // class templates.
+ // DR1484 specifies that enumerations cannot be separately instantiated,
+ // they will be instantiated with the rest of the template declaration.
template<typename T>
int f() {
enum class E {
- e = T::error
+ e = T::error // expected-error {{has no members}}
};
return (int)E();
}
- int test1 = f<int>();
+ int test1 = f<int>(); // expected-note {{here}}
template<typename T>
int g() {
enum class E {
e = T::error // expected-error {{has no members}}
};
- return E::e; // expected-note {{here}}
+ return E::e;
}
int test2 = g<int>(); // expected-note {{here}}
}
diff --git a/test/CodeCompletion/call.c b/test/CodeCompletion/call.c
index 8581414bf8c3..fe8644595f67 100644
--- a/test/CodeCompletion/call.c
+++ b/test/CodeCompletion/call.c
@@ -6,10 +6,10 @@ void test() {
f0(0, 0);
g0(0, 0);
f1(0, 0);
- // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: f0(<#float x#>, float y)
- // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CC2 %s
+ // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: f0(float x, <#float y#>)
- // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CC3 %s
+ // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: f1()
}
diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp
index f06470f4cbe7..40a72ba83602 100644
--- a/test/CodeCompletion/call.cpp
+++ b/test/CodeCompletion/call.cpp
@@ -17,12 +17,12 @@ void f();
void test() {
f(Y(), 0, 0);
- // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
// CHECK-CC1: f(N::Y y, <#int ZZ#>)
// CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
// CHECK-CC1-NEXT: f(float x, <#float y#>)
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CC2 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2-NOT: f(N::Y y, int ZZ)
// CHECK-CC2: f(int i, int j, <#int k#>)
}
diff --git a/test/CodeCompletion/documentation.cpp b/test/CodeCompletion/documentation.cpp
index c049ae3733b5..d7dec9af6c08 100644
--- a/test/CodeCompletion/documentation.cpp
+++ b/test/CodeCompletion/documentation.cpp
@@ -23,11 +23,11 @@ void test() {
t2.
}
-// RUN: %clang_cc1 -fsyntax-only -code-completion-brief-comments -code-completion-at=%s:21:1 %s -o - | FileCheck -check-prefix=CC1 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-brief-comments -code-completion-at=%s:21:1 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: COMPLETION: T1 : [#void#]T1(<#float x#>, <#float y#>) : Aaa.
// CHECK-CC1: COMPLETION: T2 : T2 : Bbb.
// CHECK-CC1: COMPLETION: T5 : T5:: : Eee.
-// RUN: %clang_cc1 -fsyntax-only -code-completion-brief-comments -code-completion-at=%s:23:6 %s -o - | FileCheck -check-prefix=CC2 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-brief-comments -code-completion-at=%s:23:6 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: COMPLETION: T3 : [#void#]T3() : Ccc.
// CHECK-CC2: COMPLETION: T4 : [#int#]T4 : Ddd.
diff --git a/test/CodeCompletion/enum-switch-case-qualified.cpp b/test/CodeCompletion/enum-switch-case-qualified.cpp
index e74ec9b5fe67..0f256716bc0d 100644
--- a/test/CodeCompletion/enum-switch-case-qualified.cpp
+++ b/test/CodeCompletion/enum-switch-case-qualified.cpp
@@ -21,7 +21,7 @@ namespace M {
void test(enum N::C::Color color) {
switch (color) {
case
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:8 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: Blue : [#M::N::C::Color#]N::C::Blue
// CHECK-CC1-NEXT: Green : [#M::N::C::Color#]N::C::Green
// CHECK-CC1-NEXT: Indigo : [#M::N::C::Color#]N::C::Indigo
diff --git a/test/CodeCompletion/enum-switch-case.c b/test/CodeCompletion/enum-switch-case.c
index b83bd7f6474c..264f46a0a360 100644
--- a/test/CodeCompletion/enum-switch-case.c
+++ b/test/CodeCompletion/enum-switch-case.c
@@ -25,14 +25,14 @@ void test(enum Color color) {
case
}
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:10 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: Blue
// CHECK-CC1-NEXT: Green
// CHECK-CC1-NEXT: Indigo
// CHECK-CC1-NEXT: Orange
// CHECK-CC1-NEXT: Violet
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:25:10 %s -o - | FileCheck -check-prefix=CC2 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:25:10 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: COMPLETION: Blue : [#enum Color#]Blue
// CHECK-CC2-NEXT: COMPLETION: c2 : [#unsigned int#]c2
// CHECK-CC2-NEXT: COMPLETION: color : [#enum Color#]color
diff --git a/test/CodeCompletion/enum-switch-case.cpp b/test/CodeCompletion/enum-switch-case.cpp
index 2677f33f98f2..997845afe584 100644
--- a/test/CodeCompletion/enum-switch-case.cpp
+++ b/test/CodeCompletion/enum-switch-case.cpp
@@ -19,7 +19,7 @@ void test(enum N::Color color) {
break;
case
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:21:8 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:21:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: Blue : [#N::Color#]N::Blue
// CHECK-CC1-NEXT: Green : [#N::Color#]N::Green
// CHECK-CC1-NEXT: Indigo : [#N::Color#]N::Indigo
diff --git a/test/CodeCompletion/functions.cpp b/test/CodeCompletion/functions.cpp
index fcab3dcbe120..036ed29e4a85 100644
--- a/test/CodeCompletion/functions.cpp
+++ b/test/CodeCompletion/functions.cpp
@@ -3,6 +3,6 @@ void f(float x, float y...);
void test() {
::
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:5 %s -o - | FileCheck -check-prefix=CC1 %s
+ // 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(<#float x#>, <#float y, ...#>)
diff --git a/test/CodeCompletion/member-access.c b/test/CodeCompletion/member-access.c
index f41c509c8809..226e182ab15f 100644
--- a/test/CodeCompletion/member-access.c
+++ b/test/CodeCompletion/member-access.c
@@ -6,7 +6,7 @@ struct Point {
void test(struct Point *p) {
p->
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: x
// CHECK-CC1: y
// CHECK-CC1: z
diff --git a/test/CodeCompletion/namespace-alias.cpp b/test/CodeCompletion/namespace-alias.cpp
index efbf99637285..bd4aef413799 100644
--- a/test/CodeCompletion/namespace-alias.cpp
+++ b/test/CodeCompletion/namespace-alias.cpp
@@ -11,7 +11,7 @@ namespace N2 {
namespace I1 { }
namespace New =
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:13:18 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:13:18 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: I1
// CHECK-CC1: I4
// CHECK-CC1: I5
diff --git a/test/CodeCompletion/namespace.cpp b/test/CodeCompletion/namespace.cpp
index ecd848039a87..8d3908a17889 100644
--- a/test/CodeCompletion/namespace.cpp
+++ b/test/CodeCompletion/namespace.cpp
@@ -8,7 +8,7 @@ namespace N2 {
namespace I1 { }
namespace
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: I1
// CHECK-CC1-NEXT: I5
diff --git a/test/CodeCompletion/nested-name-specifier.cpp b/test/CodeCompletion/nested-name-specifier.cpp
index e09a14b4cb46..8789635bd598 100644
--- a/test/CodeCompletion/nested-name-specifier.cpp
+++ b/test/CodeCompletion/nested-name-specifier.cpp
@@ -10,7 +10,7 @@ namespace N {
}
N::
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:12:4 %s -o - | FileCheck -check-prefix=CC1 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:12:4 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: A
// CHECK-CC1: B
// CHECK-CC1: M
diff --git a/test/CodeCompletion/objc-expr.m b/test/CodeCompletion/objc-expr.m
index d3c95a6e6ff1..4296cc9a8c29 100644
--- a/test/CodeCompletion/objc-expr.m
+++ b/test/CodeCompletion/objc-expr.m
@@ -4,7 +4,7 @@ id testCompleteAfterAtSign() {
return @"";
}
-// RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:11 %s -fno-const-strings -o - | FileCheck -check-prefix=AT %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:11 %s -fno-const-strings -o - | FileCheck -check-prefix=CHECK-AT %s
// CHECK-AT: COMPLETION: Pattern : [#NSString *#]"<#string#>"
// CHECK-AT: COMPLETION: Pattern : [#id#](<#expression#>)
// CHECK-AT: COMPLETION: Pattern : [#NSArray *#][<#objects, ...#>]
@@ -13,5 +13,5 @@ id testCompleteAfterAtSign() {
// CHECK-AT: COMPLETION: Pattern : [#SEL#]selector(<#selector#>)
// CHECK-AT: COMPLETION: Pattern : [#NSDictionary *#]{<#key#>: <#object, ...#>}
-// RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:11 %s -fconst-strings -o - | FileCheck -check-prefix=CONST-STRINGS %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:11 %s -fconst-strings -o - | FileCheck -check-prefix=CHECK-CONST-STRINGS %s
// CHECK-CONST-STRINGS: COMPLETION: Pattern : [#const char[]#]encode(<#type-name#>)
diff --git a/test/CodeCompletion/operator.cpp b/test/CodeCompletion/operator.cpp
index 05cd7684ad2c..e0a21860bbc7 100644
--- a/test/CodeCompletion/operator.cpp
+++ b/test/CodeCompletion/operator.cpp
@@ -8,7 +8,7 @@ void f() {
typedef float Float;
operator
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: +
// CHECK-CC1: Float
// CHECK-CC1: Integer
diff --git a/test/CodeCompletion/stdin.c b/test/CodeCompletion/stdin.c
index 46495b2cd3ad..dd7f0adab791 100644
--- a/test/CodeCompletion/stdin.c
+++ b/test/CodeCompletion/stdin.c
@@ -2,6 +2,6 @@ enum X { x };
enum Y { y };
enum
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=-:4:6 < %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=-:4:6 < %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: X
// CHECK-CC1: Y
diff --git a/test/CodeCompletion/tag.c b/test/CodeCompletion/tag.c
index 6ad29880666e..d49fb0423618 100644
--- a/test/CodeCompletion/tag.c
+++ b/test/CodeCompletion/tag.c
@@ -7,6 +7,6 @@ void X();
void test() {
enum X { x };
enum
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: X
// CHECK-CC1: Y
diff --git a/test/CodeCompletion/tag.cpp b/test/CodeCompletion/tag.cpp
index 03fc0fda2ec5..c5ba6d31c47b 100644
--- a/test/CodeCompletion/tag.cpp
+++ b/test/CodeCompletion/tag.cpp
@@ -15,7 +15,7 @@ namespace N {
void test() {
class
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// FIXME: the redundant Y is really annoying... it needs qualification to
// actually be useful. Here, it just looks redundant :(
// CHECK-CC1: A
diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c
index 473e85847e56..b6c41de024f1 100644
--- a/test/CodeCompletion/truncation.c
+++ b/test/CodeCompletion/truncation.c
@@ -4,10 +4,10 @@
struct
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: X
// CHECK-CC1-NEXT: Y
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 -o - %s | FileCheck -check-prefix=CC2 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 -o - %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: X
// CHECK-CC2: Xa
// CHECK-CC2: Y
diff --git a/test/CodeCompletion/using-namespace.cpp b/test/CodeCompletion/using-namespace.cpp
index eb1c2bd50e67..63cb5898ee9a 100644
--- a/test/CodeCompletion/using-namespace.cpp
+++ b/test/CodeCompletion/using-namespace.cpp
@@ -12,7 +12,7 @@ namespace N2 {
void foo() {
using namespace
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: I1
// CHECK-CC1: I4
// CHECK-CC1: I5
diff --git a/test/CodeCompletion/using.cpp b/test/CodeCompletion/using.cpp
index b84aa26be95b..13ebb4b2d8d0 100644
--- a/test/CodeCompletion/using.cpp
+++ b/test/CodeCompletion/using.cpp
@@ -14,7 +14,7 @@ namespace N2 {
int N3;
using
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: I1
// CHECK-CC1: I4
// CHECK-CC1: I5
diff --git a/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c b/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
index 12bce268cfac..3aa5c003973f 100644
--- a/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
+++ b/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
@@ -1,9 +1,10 @@
-/* RUN: %clang_cc1 %s -emit-llvm -o - | not grep __builtin_
+/* RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
*
- * __builtin_longjmp/setjmp should get transformed into llvm.setjmp/longjmp
- * just like explicit setjmp/longjmp calls are.
+ * __builtin_longjmp/setjmp should get transformed into intrinsics.
*/
+// CHECK-NOT: builtin_longjmp
+
void jumpaway(int *ptr) {
__builtin_longjmp(ptr,1);
}
diff --git a/test/CodeGen/2004-11-27-InvalidConstantExpr.c b/test/CodeGen/2004-11-27-InvalidConstantExpr.c
deleted file mode 100644
index 431dccffc1a1..000000000000
--- a/test/CodeGen/2004-11-27-InvalidConstantExpr.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | not grep {foo\\* sub}
-// This should not produce a subtrace constantexpr of a pointer
-struct foo {
- int Y;
- char X[100];
-} F;
-
-int test(char *Y) {
- return Y - F.X;
-}
diff --git a/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c b/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c
index 55efa86865de..9ceee4c99127 100644
--- a/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c
+++ b/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c
@@ -1,12 +1,14 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | \
-// RUN: opt -std-compile-opts -emit-llvm | not grep {declare i32.*func}
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
// There should not be an unresolved reference to func here. Believe it or not,
-// the "expected result" is a function named 'func' which is internal and
+// the "expected result" is a function named 'func' which is internal and
// referenced by bar().
// This is PR244
+// CHECK-LABEL: define void @bar(
+// CHECK: call {{.*}} @func
+// CHECK: define internal {{.*}}i32 @func(
static int func();
void bar() {
int func();
diff --git a/test/CodeGen/2007-02-25-C-DotDotDot.c b/test/CodeGen/2007-02-25-C-DotDotDot.c
index abc46683cee9..1c3a3df57094 100644
--- a/test/CodeGen/2007-02-25-C-DotDotDot.c
+++ b/test/CodeGen/2007-02-25-C-DotDotDot.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O0 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
// Make sure the call to foo is compiled as:
// call float @foo()
diff --git a/test/CodeGen/2007-03-05-DataLayout.c b/test/CodeGen/2007-03-05-DataLayout.c
deleted file mode 100644
index 751962457379..000000000000
--- a/test/CodeGen/2007-03-05-DataLayout.c
+++ /dev/null
@@ -1,55 +0,0 @@
-// Testcase for PR1242
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep datalayout | \
-// RUN: not grep {"\[Ee\]-p:\[36\]\[24\]:\[36\]\[24\]"}
-// END.
-
-typedef __SIZE_TYPE__ size_t;
-void * malloc(size_t size);
-#define NDIM 3
-#define BODY 01
-typedef double vector[NDIM];
-typedef struct bnode* bodyptr;
-// { i16, double, [3 x double], i32, i32, [3 x double], [3 x double], [3 x
-// double], double, \2 *, \2 * }
-struct bnode {
- short int type;
- double mass;
- vector pos;
- int proc;
- int new_proc;
- vector vel;
- vector acc;
- vector new_acc;
- double phi;
- bodyptr next;
- bodyptr proc_next;
-} body;
-
-#define Type(x) ((x)->type)
-#define Mass(x) ((x)->mass)
-#define Pos(x) ((x)->pos)
-#define Proc(x) ((x)->proc)
-#define New_Proc(x) ((x)->new_proc)
-#define Vel(x) ((x)->vel)
-#define Acc(x) ((x)->acc)
-#define New_Acc(x) ((x)->new_acc)
-#define Phi(x) ((x)->phi)
-#define Next(x) ((x)->next)
-#define Proc_Next(x) ((x)->proc_next)
-
-bodyptr ubody_alloc(int p)
-{
- register bodyptr tmp;
- tmp = (bodyptr)malloc(sizeof(body));
-
- Type(tmp) = BODY;
- Proc(tmp) = p;
- Proc_Next(tmp) = NULL;
- New_Proc(tmp) = p;
- return tmp;
-}
-
-int main(int argc, char** argv) {
- bodyptr b = ubody_alloc(17);
- return 0;
-}
diff --git a/test/CodeGen/2007-04-14-FNoBuiltin.c b/test/CodeGen/2007-04-14-FNoBuiltin.c
index a5fda6306f28..25ae01c5dcc0 100644
--- a/test/CodeGen/2007-04-14-FNoBuiltin.c
+++ b/test/CodeGen/2007-04-14-FNoBuiltin.c
@@ -1,7 +1,10 @@
-// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin -o - | grep call.*printf
+// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin -o - | FileCheck %s
// Check that -fno-builtin is honored.
extern int printf(const char*, ...);
+
+// CHECK: define void {{.*}}foo(
void foo(const char *msg) {
- printf("%s\n",msg);
+ // CHECK: call {{.*}}printf
+ printf("%s\n",msg);
}
diff --git a/test/CodeGen/2007-05-07-PaddingElements.c b/test/CodeGen/2007-05-07-PaddingElements.c
index 574a37760a38..f8ec2483a8d6 100644
--- a/test/CodeGen/2007-05-07-PaddingElements.c
+++ b/test/CodeGen/2007-05-07-PaddingElements.c
@@ -1,6 +1,6 @@
// PR 1278
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep {struct.s} | not grep "4 x i8] zeroinitializer"
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | not grep "i32 0, i32 2"
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep struct.s | not grep "4 x i8] zeroinitializer"
+// RUN: %clang_cc1 %s -emit-llvm -o - | not grep "i32 0, i32 2"
struct s {
double d1;
int s1;
diff --git a/test/CodeGen/2008-01-11-ChainConsistency.c b/test/CodeGen/2008-01-11-ChainConsistency.c
deleted file mode 100644
index 9ae021f6da58..000000000000
--- a/test/CodeGen/2008-01-11-ChainConsistency.c
+++ /dev/null
@@ -1,3 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -fnested-functions | not grep nest
-
-void n1(void) { void a(void) { a(); } a(); }
diff --git a/test/CodeGen/2008-01-25-ByValReadNone.c b/test/CodeGen/2008-01-25-ByValReadNone.c
index ca21f6c443a0..bb5a5887483e 100644
--- a/test/CodeGen/2008-01-25-ByValReadNone.c
+++ b/test/CodeGen/2008-01-25-ByValReadNone.c
@@ -1,7 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-
-// XFAIL: mips
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// It could hit in @llvm.memcpy with "-triple x86_64-(mingw32|win32)".
// CHECK-NOT: readonly
// CHECK-NOT: readnone
diff --git a/test/CodeGen/2008-03-05-syncPtr.c b/test/CodeGen/2008-03-05-syncPtr.c
index 93f328a57949..4df94829f572 100644
--- a/test/CodeGen/2008-03-05-syncPtr.c
+++ b/test/CodeGen/2008-03-05-syncPtr.c
@@ -3,38 +3,38 @@
int* foo(int** a, int* b, int* c) {
return __sync_val_compare_and_swap (a, b, c);
}
-// CHECK: define i32* @foo
+// CHECK-LABEL: define i32* @foo
// CHECK: cmpxchg
int foo2(int** a, int* b, int* c) {
return __sync_bool_compare_and_swap (a, b, c);
}
-// CHECK: define i32 @foo2
+// CHECK-LABEL: define i32 @foo2
// CHECK: cmpxchg
int* foo3(int** a, int b) {
return __sync_fetch_and_add (a, b);
}
-// CHECK: define i32* @foo3
+// CHECK-LABEL: define i32* @foo3
// CHECK: atomicrmw add
int* foo4(int** a, int b) {
return __sync_fetch_and_sub (a, b);
}
-// CHECK: define i32* @foo4
+// CHECK-LABEL: define i32* @foo4
// CHECK: atomicrmw sub
int* foo5(int** a, int* b) {
return __sync_lock_test_and_set (a, b);
}
-// CHECK: define i32* @foo5
+// CHECK-LABEL: define i32* @foo5
// CHECK: atomicrmw xchg
int* foo6(int** a, int*** b) {
return __sync_lock_test_and_set (a, b);
}
-// CHECK: define i32* @foo6
+// CHECK-LABEL: define i32* @foo6
// CHECK: atomicrmw xchg
diff --git a/test/CodeGen/2008-03-24-BitField-And-Alloca.c b/test/CodeGen/2008-03-24-BitField-And-Alloca.c
index cb80d76e0596..b0ccdec1116d 100644
--- a/test/CodeGen/2008-03-24-BitField-And-Alloca.c
+++ b/test/CodeGen/2008-03-24-BitField-And-Alloca.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | not grep alloca
-// RUN: %clang_cc1 -m32 -O2 -emit-llvm %s -o - | not grep {store }
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -O2 -emit-llvm %s -o - | not grep store
enum {
PP_C,
diff --git a/test/CodeGen/2008-05-19-AlwaysInline.c b/test/CodeGen/2008-05-19-AlwaysInline.c
index 73a7691aed76..419951b1594f 100644
--- a/test/CodeGen/2008-05-19-AlwaysInline.c
+++ b/test/CodeGen/2008-05-19-AlwaysInline.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -fno-unit-at-a-time -O0 -o - | not grep sabrina
-// RUN: %clang_cc1 %s -emit-llvm -funit-at-a-time -O0 -o - | not grep sabrina
+// RUN: %clang_cc1 %s -emit-llvm -o - | not grep sabrina
static inline int sabrina (void) __attribute__((always_inline));
static inline int sabrina (void)
diff --git a/test/CodeGen/2008-07-30-implicit-initialization.c b/test/CodeGen/2008-07-30-implicit-initialization.c
index e5162596d712..e77c70a140f9 100644
--- a/test/CodeGen/2008-07-30-implicit-initialization.c
+++ b/test/CodeGen/2008-07-30-implicit-initialization.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -O1 -emit-llvm -o - %s | FileCheck %s
-// CHECK: define i32 @f0()
+// CHECK-LABEL: define i32 @f0()
// CHECK: ret i32 0
-// CHECK: define i32 @f1()
+// CHECK-LABEL: define i32 @f1()
// CHECK: ret i32 0
-// CHECK: define i32 @f2()
+// CHECK-LABEL: define i32 @f2()
// CHECK: ret i32 0
// <rdar://problem/6113085>
diff --git a/test/CodeGen/2008-07-31-asm-labels.c b/test/CodeGen/2008-07-31-asm-labels.c
index 130ad6ba46cc..733742bd85ed 100644
--- a/test/CodeGen/2008-07-31-asm-labels.c
+++ b/test/CodeGen/2008-07-31-asm-labels.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: grep "@pipe()" %t | count 0
+// RUN: not grep "@pipe()" %t
// RUN: grep '_thisIsNotAPipe' %t | count 3
-// RUN: grep 'g0' %t | count 0
+// RUN: not grep 'g0' %t
// RUN: grep '_renamed' %t | count 2
// RUN: %clang_cc1 -DUSE_DEF -emit-llvm -o %t %s
-// RUN: grep "@pipe()" %t | count 0
+// RUN: not grep "@pipe()" %t
// RUN: grep '_thisIsNotAPipe' %t | count 3
// <rdr://6116729>
diff --git a/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
index 429fb1fcc27b..f348b2b6fda6 100644
--- a/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
+++ b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -O1 -emit-llvm -o - %s | FileCheck %s
-// CHECK: define i32 @f0
+// CHECK-LABEL: define i32 @f0
// CHECK: ret i32 1
-// CHECK: define i32 @f1
+// CHECK-LABEL: define i32 @f1
// CHECK: ret i32 1
-// CHECK: define i32 @f2
+// CHECK-LABEL: define i32 @f2
// CHECK: ret i32 1
// <rdr://6115726>
diff --git a/test/CodeGen/2008-08-07-AlignPadding2.c b/test/CodeGen/2008-08-07-AlignPadding2.c
index ecf28dd72de0..cef71a30940d 100644
--- a/test/CodeGen/2008-08-07-AlignPadding2.c
+++ b/test/CodeGen/2008-08-07-AlignPadding2.c
@@ -1,4 +1,4 @@
-/* RUN: %clang_cc1 %s -emit-llvm -o - -O0 | grep zeroinitializer | count 1
+/* RUN: %clang_cc1 %s -emit-llvm -o - | grep zeroinitializer | count 1
The FE must not generate padding here between array elements. PR 2533. */
diff --git a/test/CodeGen/2010-01-18-Inlined-Debug.c b/test/CodeGen/2010-01-18-Inlined-Debug.c
index cf00be7752cf..bdc6fc5267e7 100644
--- a/test/CodeGen/2010-01-18-Inlined-Debug.c
+++ b/test/CodeGen/2010-01-18-Inlined-Debug.c
@@ -1,5 +1,5 @@
// PR: 6058
-// RUN: %clang_cc1 -g -emit-llvm %s -O0 -o /dev/null
+// RUN: %clang_cc1 -g -emit-llvm %s -o /dev/null
static inline int foo(double) __attribute__ ((always_inline));
static inline int foo(double __x) { return __x; }
diff --git a/test/CodeGen/2010-03-5-LexicalScope.c b/test/CodeGen/2010-03-5-LexicalScope.c
index e0e41dd2379b..8dc68d70557f 100644
--- a/test/CodeGen/2010-03-5-LexicalScope.c
+++ b/test/CodeGen/2010-03-5-LexicalScope.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
// CHECK: DW_TAG_lexical_block
// CHECK: DW_TAG_lexical_block
int foo(int i) {
diff --git a/test/CodeGen/2010-07-08-DeclDebugLineNo.c b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
index 1637a4936747..5e9edd9acd99 100644
--- a/test/CodeGen/2010-07-08-DeclDebugLineNo.c
+++ b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
// Insure that dbg.declare lines for locals refer to correct line number records.
// Radar 8152866.
void foo() {
diff --git a/test/CodeGen/2010-08-12-asm-aggr-arg.c b/test/CodeGen/2010-08-12-asm-aggr-arg.c
index 5ddc4122d60f..dcd507d81953 100644
--- a/test/CodeGen/2010-08-12-asm-aggr-arg.c
+++ b/test/CodeGen/2010-08-12-asm-aggr-arg.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
// Radar 8288710: A small aggregate can be passed as an integer. Make sure
// we don't get an error with "input constraint with a matching output
// constraint of incompatible type!"
diff --git a/test/CodeGen/3dnow-builtins.c b/test/CodeGen/3dnow-builtins.c
index 294fbc0579eb..f53b85c931df 100644
--- a/test/CodeGen/3dnow-builtins.c
+++ b/test/CodeGen/3dnow-builtins.c
@@ -6,151 +6,151 @@
#include <x86intrin.h>
__m64 test_m_pavgusb(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pavgusb
+ // CHECK-LABEL: define i64 @test_m_pavgusb
// CHECK: @llvm.x86.3dnow.pavgusb
return _m_pavgusb(m1, m2);
}
__m64 test_m_pf2id(__m64 m) {
- // CHECK: define i64 @test_m_pf2id
+ // CHECK-LABEL: define i64 @test_m_pf2id
// CHECK: @llvm.x86.3dnow.pf2id
return _m_pf2id(m);
}
__m64 test_m_pfacc(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfacc
+ // CHECK-LABEL: define i64 @test_m_pfacc
// CHECK: @llvm.x86.3dnow.pfacc
return _m_pfacc(m1, m2);
}
__m64 test_m_pfadd(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfadd
+ // CHECK-LABEL: define i64 @test_m_pfadd
// CHECK: @llvm.x86.3dnow.pfadd
return _m_pfadd(m1, m2);
}
__m64 test_m_pfcmpeq(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfcmpeq
+ // CHECK-LABEL: define i64 @test_m_pfcmpeq
// CHECK: @llvm.x86.3dnow.pfcmpeq
return _m_pfcmpeq(m1, m2);
}
__m64 test_m_pfcmpge(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfcmpge
+ // CHECK-LABEL: define i64 @test_m_pfcmpge
// CHECK: @llvm.x86.3dnow.pfcmpge
return _m_pfcmpge(m1, m2);
}
__m64 test_m_pfcmpgt(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfcmpgt
+ // CHECK-LABEL: define i64 @test_m_pfcmpgt
// CHECK: @llvm.x86.3dnow.pfcmpgt
return _m_pfcmpgt(m1, m2);
}
__m64 test_m_pfmax(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfmax
+ // CHECK-LABEL: define i64 @test_m_pfmax
// CHECK: @llvm.x86.3dnow.pfmax
return _m_pfmax(m1, m2);
}
__m64 test_m_pfmin(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfmin
+ // CHECK-LABEL: define i64 @test_m_pfmin
// CHECK: @llvm.x86.3dnow.pfmin
return _m_pfmin(m1, m2);
}
__m64 test_m_pfmul(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfmul
+ // CHECK-LABEL: define i64 @test_m_pfmul
// CHECK: @llvm.x86.3dnow.pfmul
return _m_pfmul(m1, m2);
}
__m64 test_m_pfrcp(__m64 m) {
- // CHECK: define i64 @test_m_pfrcp
+ // CHECK-LABEL: define i64 @test_m_pfrcp
// CHECK: @llvm.x86.3dnow.pfrcp
return _m_pfrcp(m);
}
__m64 test_m_pfrcpit1(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfrcpit1
+ // CHECK-LABEL: define i64 @test_m_pfrcpit1
// CHECK: @llvm.x86.3dnow.pfrcpit1
return _m_pfrcpit1(m1, m2);
}
__m64 test_m_pfrcpit2(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfrcpit2
+ // CHECK-LABEL: define i64 @test_m_pfrcpit2
// CHECK: @llvm.x86.3dnow.pfrcpit2
return _m_pfrcpit2(m1, m2);
}
__m64 test_m_pfrsqrt(__m64 m) {
- // CHECK: define i64 @test_m_pfrsqrt
+ // CHECK-LABEL: define i64 @test_m_pfrsqrt
// CHECK: @llvm.x86.3dnow.pfrsqrt
return _m_pfrsqrt(m);
}
__m64 test_m_pfrsqrtit1(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfrsqrtit1
+ // CHECK-LABEL: define i64 @test_m_pfrsqrtit1
// CHECK: @llvm.x86.3dnow.pfrsqit1
return _m_pfrsqrtit1(m1, m2);
}
__m64 test_m_pfsub(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfsub
+ // CHECK-LABEL: define i64 @test_m_pfsub
// CHECK: @llvm.x86.3dnow.pfsub
return _m_pfsub(m1, m2);
}
__m64 test_m_pfsubr(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfsubr
+ // CHECK-LABEL: define i64 @test_m_pfsubr
// CHECK: @llvm.x86.3dnow.pfsubr
return _m_pfsubr(m1, m2);
}
__m64 test_m_pi2fd(__m64 m) {
- // CHECK: define i64 @test_m_pi2fd
+ // CHECK-LABEL: define i64 @test_m_pi2fd
// CHECK: @llvm.x86.3dnow.pi2fd
return _m_pi2fd(m);
}
__m64 test_m_pmulhrw(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pmulhrw
+ // CHECK-LABEL: define i64 @test_m_pmulhrw
// CHECK: @llvm.x86.3dnow.pmulhrw
return _m_pmulhrw(m1, m2);
}
__m64 test_m_pf2iw(__m64 m) {
- // CHECK: define i64 @test_m_pf2iw
+ // CHECK-LABEL: define i64 @test_m_pf2iw
// CHECK: @llvm.x86.3dnowa.pf2iw
return _m_pf2iw(m);
}
__m64 test_m_pfnacc(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfnacc
+ // CHECK-LABEL: define i64 @test_m_pfnacc
// CHECK: @llvm.x86.3dnowa.pfnacc
return _m_pfnacc(m1, m2);
}
__m64 test_m_pfpnacc(__m64 m1, __m64 m2) {
- // CHECK: define i64 @test_m_pfpnacc
+ // CHECK-LABEL: define i64 @test_m_pfpnacc
// CHECK: @llvm.x86.3dnowa.pfpnacc
return _m_pfpnacc(m1, m2);
}
__m64 test_m_pi2fw(__m64 m) {
- // CHECK: define i64 @test_m_pi2fw
+ // CHECK-LABEL: define i64 @test_m_pi2fw
// CHECK: @llvm.x86.3dnowa.pi2fw
return _m_pi2fw(m);
}
__m64 test_m_pswapdsf(__m64 m) {
- // CHECK: define i64 @test_m_pswapdsf
+ // CHECK-LABEL: define i64 @test_m_pswapdsf
// CHECK: @llvm.x86.3dnowa.pswapd
return _m_pswapdsf(m);
}
__m64 test_m_pswapdsi(__m64 m) {
- // CHECK: define i64 @test_m_pswapdsi
+ // CHECK-LABEL: define i64 @test_m_pswapdsi
// CHECK: @llvm.x86.3dnowa.pswapd
return _m_pswapdsi(m);
}
diff --git a/test/CodeGen/Atomics.c b/test/CodeGen/Atomics.c
index 2bb38fd749c2..5798dfff46b1 100644
--- a/test/CodeGen/Atomics.c
+++ b/test/CodeGen/Atomics.c
@@ -11,7 +11,7 @@ unsigned int ui;
signed long long sll;
unsigned long long ull;
-void test_op_ignore (void) // CHECK: define void @test_op_ignore
+void test_op_ignore (void) // CHECK-LABEL: define void @test_op_ignore
{
(void) __sync_fetch_and_add (&sc, 1); // CHECK: atomicrmw add i8
(void) __sync_fetch_and_add (&uc, 1); // CHECK: atomicrmw add i8
@@ -60,7 +60,7 @@ void test_op_ignore (void) // CHECK: define void @test_op_ignore
}
-void test_fetch_and_op (void) // CHECK: define void @test_fetch_and_op
+void test_fetch_and_op (void) // CHECK-LABEL: define void @test_fetch_and_op
{
sc = __sync_fetch_and_add (&sc, 11); // CHECK: atomicrmw add
uc = __sync_fetch_and_add (&uc, 11); // CHECK: atomicrmw add
diff --git a/test/CodeGen/PR15826.c b/test/CodeGen/PR15826.c
new file mode 100644
index 000000000000..28d7445647ef
--- /dev/null
+++ b/test/CodeGen/PR15826.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -verify -emit-llvm-only %s -o %t
+
+/* Testcase for PR15826 - clang hits assert in clang::ASTContext::getASTRecordLayout */
+struct sysctl_req {
+ struct aiocblist *p_aio;
+};
+
+struct sysctl_oid {
+ int (*oid_handler)(struct sysctl_req *req);
+};
+
+static struct sysctl_oid sysctl___kern_features_aio;
+
+static void const *const __set_sysctl_set_sym_sysctl___kern_features_aio
+ __attribute__((__used__)) = &sysctl___kern_features_aio;
+
+struct aiocblist {
+ struct aiocb uaiocb; // expected-error {{field has incomplete type}} expected-note {{forward declaration}}
+};
diff --git a/test/CodeGen/PR3589-freestanding-libcalls.c b/test/CodeGen/PR3589-freestanding-libcalls.c
index 40e5fb11214b..5216e820411a 100644
--- a/test/CodeGen/PR3589-freestanding-libcalls.c
+++ b/test/CodeGen/PR3589-freestanding-libcalls.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | grep 'declare i32 @printf' | count 1
// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 1
-// RUN: %clang_cc1 -triple i386-unknown-unknown -ffreestanding -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 0
+// RUN: %clang_cc1 -triple i386-unknown-unknown -ffreestanding -O2 -emit-llvm %s -o - | not grep 'declare i32 @puts'
int printf(const char *, ...);
diff --git a/test/CodeGen/PR5060-align.c b/test/CodeGen/PR5060-align.c
index efd852055398..34293a933aa9 100644
--- a/test/CodeGen/PR5060-align.c
+++ b/test/CodeGen/PR5060-align.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -verify | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
// CHECK: @foo.p = internal global i8 0, align 32
char *foo(void) {
diff --git a/test/CodeGen/_Bool-conversion.c b/test/CodeGen/_Bool-conversion.c
index 9e5e89450314..a51cd8ecf535 100644
--- a/test/CodeGen/_Bool-conversion.c
+++ b/test/CodeGen/_Bool-conversion.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386 -emit-llvm -O2 -o - %s | FileCheck %s
-// CHECK: define i32 @f0()
+// CHECK-LABEL: define i32 @f0()
// CHECK: ret i32 1
// CHECK: }
diff --git a/test/CodeGen/aarch64-arguments.c b/test/CodeGen/aarch64-arguments.c
index 901e7342ddac..a70dfb1e3d4d 100644
--- a/test/CodeGen/aarch64-arguments.c
+++ b/test/CodeGen/aarch64-arguments.c
@@ -3,7 +3,7 @@
// Sign extension is performed by the callee on AArch64, which means
// that we *shouldn't* tag arguments and returns with their extension.
-// PCS: define i8 @f0(i16 %a)
+// PCS-LABEL: define i8 @f0(i16 %a)
char f0(short a) {
return a;
}
@@ -32,11 +32,11 @@ struct s5 f5(void) {}
struct s6 { int f0[1]; };
struct s6 f6(void) {}
-// PCS: define void @f7()
+// PCS-LABEL: define void @f7()
struct s7 { struct { int : 0; } f0; };
struct s7 f7(void) {}
-// PCS: define void @f8()
+// PCS-LABEL: define void @f8()
struct s8 { struct { int : 0; } f0[1]; };
struct s8 f8(void) {}
@@ -56,18 +56,18 @@ struct s11 f11(void) {}
union u12 { char f0; short f1; int f2; long f3; };
union u12 f12(void) {}
-// PCS: define %struct.s13 @f13()
+// PCS-LABEL: define %struct.s13 @f13()
struct s13 { float f0; };
struct s13 f13(void) {}
-// PCS: define %union.u14 @f14()
+// PCS-LABEL: define %union.u14 @f14()
union u14 { float f0; };
union u14 f14(void) {}
-// PCS: define void @f15()
+// PCS-LABEL: define void @f15()
void f15(struct s7 a0) {}
-// PCS: define void @f16()
+// PCS-LABEL: define void @f16()
void f16(struct s8 a0) {}
// PCS: define [1 x i64] @f17()
@@ -111,14 +111,14 @@ struct s26 f26() {}
struct s27 { _Complex long f0; };
struct s27 f27() {}
-// PCS: define void @f28(i8 %a, i16 %b, i32 %c, i64 %d, float %e, double %f)
+// PCS-LABEL: define void @f28(i8 %a, i16 %b, i32 %c, i64 %d, float %e, double %f)
void f28(char a, short b, int c, long d, float e, double f) {}
// PCS: define void @f29([2 x i64] %a
struct s29 { int arr[4]; };
void f29(struct s29 a) {}
-// PCS: define void @f30(%struct.s30* %a)
+// PCS-LABEL: define void @f30(%struct.s30* %a)
struct s30 { int arr[4]; char c;};
void f30(struct s30 a) {}
@@ -126,7 +126,7 @@ void f30(struct s30 a) {}
struct s31 { double arr[4]; };
void f31(struct s31 a) {}
-// PCS: define void @f32(%struct.s32* %a)
+// PCS-LABEL: define void @f32(%struct.s32* %a)
struct s32 { float arr[5]; };
void f32(struct s32 a) {}
@@ -135,11 +135,11 @@ void f32(struct s32 a) {}
struct s33 { float arr[3]; float a; };
void f33(struct s33 a) {}
-// PCS: define void @f34(%struct.s34* noalias sret
+// PCS-LABEL: define void @f34(%struct.s34* noalias sret
struct s34 { int a[4]; char b };
struct s34 f34(void) {}
-// PCS: define void @f35()
+// PCS-LABEL: define void @f35()
struct s35 {};
void f35(struct s35 a) {}
diff --git a/test/CodeGen/aarch64-neon-2velem.c b/test/CodeGen/aarch64-neon-2velem.c
new file mode 100644
index 000000000000..03f7df715c53
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-2velem.c
@@ -0,0 +1,1698 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int16x4_t test_vmla_lane_s16(int16x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmla_lane_s16
+ return vmla_lane_s16(a, b, v, 3);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int16x8_t test_vmlaq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlaq_lane_s16
+ return vmlaq_lane_s16(a, b, v, 3);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vmla_lane_s32(int32x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmla_lane_s32
+ return vmla_lane_s32(a, b, v, 1);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlaq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlaq_lane_s32
+ return vmlaq_lane_s32(a, b, v, 1);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int16x4_t test_vmla_laneq_s16(int16x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmla_laneq_s16
+ return vmla_laneq_s16(a, b, v, 7);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int16x8_t test_vmlaq_laneq_s16(int16x8_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlaq_laneq_s16
+ return vmlaq_laneq_s16(a, b, v, 7);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int32x2_t test_vmla_laneq_s32(int32x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmla_laneq_s32
+ return vmla_laneq_s32(a, b, v, 3);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlaq_laneq_s32(int32x4_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlaq_laneq_s32
+ return vmlaq_laneq_s32(a, b, v, 3);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int16x4_t test_vmls_lane_s16(int16x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmls_lane_s16
+ return vmls_lane_s16(a, b, v, 3);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int16x8_t test_vmlsq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsq_lane_s16
+ return vmlsq_lane_s16(a, b, v, 3);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vmls_lane_s32(int32x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmls_lane_s32
+ return vmls_lane_s32(a, b, v, 1);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlsq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsq_lane_s32
+ return vmlsq_lane_s32(a, b, v, 1);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int16x4_t test_vmls_laneq_s16(int16x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmls_laneq_s16
+ return vmls_laneq_s16(a, b, v, 7);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int16x8_t test_vmlsq_laneq_s16(int16x8_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsq_laneq_s16
+ return vmlsq_laneq_s16(a, b, v, 7);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int32x2_t test_vmls_laneq_s32(int32x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmls_laneq_s32
+ return vmls_laneq_s32(a, b, v, 3);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlsq_laneq_s32(int32x4_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsq_laneq_s32
+ return vmlsq_laneq_s32(a, b, v, 3);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int16x4_t test_vmul_lane_s16(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vmul_lane_s16
+ return vmul_lane_s16(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int16x8_t test_vmulq_lane_s16(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vmulq_lane_s16
+ return vmulq_lane_s16(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vmul_lane_s32(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vmul_lane_s32
+ return vmul_lane_s32(a, v, 1);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmulq_lane_s32(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vmulq_lane_s32
+ return vmulq_lane_s32(a, v, 1);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+uint16x4_t test_vmul_lane_u16(uint16x4_t a, uint16x4_t v) {
+ // CHECK: test_vmul_lane_u16
+ return vmul_lane_u16(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+uint16x8_t test_vmulq_lane_u16(uint16x8_t a, uint16x4_t v) {
+ // CHECK: test_vmulq_lane_u16
+ return vmulq_lane_u16(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+uint32x2_t test_vmul_lane_u32(uint32x2_t a, uint32x2_t v) {
+ // CHECK: test_vmul_lane_u32
+ return vmul_lane_u32(a, v, 1);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vmulq_lane_u32(uint32x4_t a, uint32x2_t v) {
+ // CHECK: test_vmulq_lane_u32
+ return vmulq_lane_u32(a, v, 1);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int16x4_t test_vmul_laneq_s16(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vmul_laneq_s16
+ return vmul_laneq_s16(a, v, 7);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int16x8_t test_vmulq_laneq_s16(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vmulq_laneq_s16
+ return vmulq_laneq_s16(a, v, 7);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int32x2_t test_vmul_laneq_s32(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vmul_laneq_s32
+ return vmul_laneq_s32(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmulq_laneq_s32(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vmulq_laneq_s32
+ return vmulq_laneq_s32(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+uint16x4_t test_vmul_laneq_u16(uint16x4_t a, uint16x8_t v) {
+ // CHECK: test_vmul_laneq_u16
+ return vmul_laneq_u16(a, v, 7);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+uint16x8_t test_vmulq_laneq_u16(uint16x8_t a, uint16x8_t v) {
+ // CHECK: test_vmulq_laneq_u16
+ return vmulq_laneq_u16(a, v, 7);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+uint32x2_t test_vmul_laneq_u32(uint32x2_t a, uint32x4_t v) {
+ // CHECK: test_vmul_laneq_u32
+ return vmul_laneq_u32(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+uint32x4_t test_vmulq_laneq_u32(uint32x4_t a, uint32x4_t v) {
+ // CHECK: test_vmulq_laneq_u32
+ return vmulq_laneq_u32(a, v, 3);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+float32x2_t test_vfma_lane_f32(float32x2_t a, float32x2_t b, float32x2_t v) {
+ // CHECK: test_vfma_lane_f32
+ return vfma_lane_f32(a, b, v, 1);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vfmaq_lane_f32(float32x4_t a, float32x4_t b, float32x2_t v) {
+ // CHECK: test_vfmaq_lane_f32
+ return vfmaq_lane_f32(a, b, v, 1);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float32x2_t test_vfma_laneq_f32(float32x2_t a, float32x2_t b, float32x4_t v) {
+ // CHECK: test_vfma_laneq_f32
+ return vfma_laneq_f32(a, b, v, 3);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+float32x4_t test_vfmaq_laneq_f32(float32x4_t a, float32x4_t b, float32x4_t v) {
+ // CHECK: test_vfmaq_laneq_f32
+ return vfmaq_laneq_f32(a, b, v, 3);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+float32x2_t test_vfms_lane_f32(float32x2_t a, float32x2_t b, float32x2_t v) {
+ // CHECK: test_vfms_lane_f32
+ return vfms_lane_f32(a, b, v, 1);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vfmsq_lane_f32(float32x4_t a, float32x4_t b, float32x2_t v) {
+ // CHECK: test_vfmsq_lane_f32
+ return vfmsq_lane_f32(a, b, v, 1);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float32x2_t test_vfms_laneq_f32(float32x2_t a, float32x2_t b, float32x4_t v) {
+ // CHECK: test_vfms_laneq_f32
+ return vfms_laneq_f32(a, b, v, 3);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+float32x4_t test_vfmsq_laneq_f32(float32x4_t a, float32x4_t b, float32x4_t v) {
+ // CHECK: test_vfmsq_laneq_f32
+ return vfmsq_laneq_f32(a, b, v, 3);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+float64x2_t test_vfmaq_lane_f64(float64x2_t a, float64x2_t b, float64x1_t v) {
+ // CHECK: test_vfmaq_lane_f64
+ return vfmaq_lane_f64(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float64x2_t test_vfmaq_laneq_f64(float64x2_t a, float64x2_t b, float64x2_t v) {
+ // CHECK: test_vfmaq_laneq_f64
+ return vfmaq_laneq_f64(a, b, v, 1);
+ // CHECK: fmla {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[1]
+}
+
+float64x2_t test_vfmsq_lane_f64(float64x2_t a, float64x2_t b, float64x1_t v) {
+ // CHECK: test_vfmsq_lane_f64
+ return vfmsq_lane_f64(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float64x2_t test_vfmsq_laneq_f64(float64x2_t a, float64x2_t b, float64x2_t v) {
+ // CHECK: test_vfmsq_laneq_f64
+ return vfmsq_laneq_f64(a, b, v, 1);
+ // CHECK: fmls {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[1]
+}
+
+int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlal_lane_s16
+ return vmlal_lane_s16(a, b, v, 3);
+ // CHECK: smlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlal_lane_s32
+ return vmlal_lane_s32(a, b, v, 1);
+ // CHECK: smlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlal_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlal_laneq_s16
+ return vmlal_laneq_s16(a, b, v, 7);
+ // CHECK: smlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlal_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlal_laneq_s32
+ return vmlal_laneq_s32(a, b, v, 3);
+ // CHECK: smlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlal_high_lane_s16
+ return vmlal_high_lane_s16(a, b, v, 3);
+ // CHECK: smlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlal_high_lane_s32
+ return vmlal_high_lane_s32(a, b, v, 1);
+ // CHECK: smlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlal_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlal_high_laneq_s16
+ return vmlal_high_laneq_s16(a, b, v, 7);
+ // CHECK: smlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlal_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlal_high_laneq_s32
+ return vmlal_high_laneq_s32(a, b, v, 3);
+ // CHECK: smlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_lane_s16
+ return vmlsl_lane_s16(a, b, v, 3);
+ // CHECK: smlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_lane_s32
+ return vmlsl_lane_s32(a, b, v, 1);
+ // CHECK: smlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlsl_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_laneq_s16
+ return vmlsl_laneq_s16(a, b, v, 7);
+ // CHECK: smlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlsl_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_laneq_s32
+ return vmlsl_laneq_s32(a, b, v, 3);
+ // CHECK: smlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_high_lane_s16
+ return vmlsl_high_lane_s16(a, b, v, 3);
+ // CHECK: smlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_high_lane_s32
+ return vmlsl_high_lane_s32(a, b, v, 1);
+ // CHECK: smlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlsl_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_high_laneq_s16
+ return vmlsl_high_laneq_s16(a, b, v, 7);
+ // CHECK: smlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlsl_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_high_laneq_s32
+ return vmlsl_high_laneq_s32(a, b, v, 3);
+ // CHECK: smlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlal_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlal_lane_u16
+ return vmlal_lane_u16(a, b, v, 3);
+ // CHECK: umlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlal_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlal_lane_u32
+ return vmlal_lane_u32(a, b, v, 1);
+ // CHECK: umlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlal_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlal_laneq_u16
+ return vmlal_laneq_u16(a, b, v, 7);
+ // CHECK: umlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlal_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlal_laneq_u32
+ return vmlal_laneq_u32(a, b, v, 3);
+ // CHECK: umlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlal_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlal_high_lane_u16
+ return vmlal_high_lane_u16(a, b, v, 3);
+ // CHECK: umlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlal_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlal_high_lane_u32
+ return vmlal_high_lane_u32(a, b, v, 1);
+ // CHECK: umlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlal_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlal_high_laneq_u16
+ return vmlal_high_laneq_u16(a, b, v, 7);
+ // CHECK: umlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlal_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlal_high_laneq_u32
+ return vmlal_high_laneq_u32(a, b, v, 3);
+ // CHECK: umlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlsl_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_lane_u16
+ return vmlsl_lane_u16(a, b, v, 3);
+ // CHECK: umlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlsl_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_lane_u32
+ return vmlsl_lane_u32(a, b, v, 1);
+ // CHECK: umlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlsl_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_laneq_u16
+ return vmlsl_laneq_u16(a, b, v, 7);
+ // CHECK: umlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlsl_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_laneq_u32
+ return vmlsl_laneq_u32(a, b, v, 3);
+ // CHECK: umlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmlsl_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_high_lane_u16
+ return vmlsl_high_lane_u16(a, b, v, 3);
+ // CHECK: umlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmlsl_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_high_lane_u32
+ return vmlsl_high_lane_u32(a, b, v, 1);
+ // CHECK: umlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmlsl_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_high_laneq_u16
+ return vmlsl_high_laneq_u16(a, b, v, 7);
+ // CHECK: umlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmlsl_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_high_laneq_u32
+ return vmlsl_high_laneq_u32(a, b, v, 3);
+ // CHECK: umlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vmull_lane_s16
+ return vmull_lane_s16(a, v, 3);
+ // CHECK: smull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vmull_lane_s32
+ return vmull_lane_s32(a, v, 1);
+ // CHECK: smull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t v) {
+ // CHECK: test_vmull_lane_u16
+ return vmull_lane_u16(a, v, 3);
+ // CHECK: umull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t v) {
+ // CHECK: test_vmull_lane_u32
+ return vmull_lane_u32(a, v, 1);
+ // CHECK: umull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmull_high_lane_s16(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vmull_high_lane_s16
+ return vmull_high_lane_s16(a, v, 3);
+ // CHECK: smull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vmull_high_lane_s32(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vmull_high_lane_s32
+ return vmull_high_lane_s32(a, v, 1);
+ // CHECK: smull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vmull_high_lane_u16(uint16x8_t a, uint16x4_t v) {
+ // CHECK: test_vmull_high_lane_u16
+ return vmull_high_lane_u16(a, v, 3);
+ // CHECK: umull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+uint64x2_t test_vmull_high_lane_u32(uint32x4_t a, uint32x2_t v) {
+ // CHECK: test_vmull_high_lane_u32
+ return vmull_high_lane_u32(a, v, 1);
+ // CHECK: umull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vmull_laneq_s16(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vmull_laneq_s16
+ return vmull_laneq_s16(a, v, 7);
+ // CHECK: smull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmull_laneq_s32(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vmull_laneq_s32
+ return vmull_laneq_s32(a, v, 3);
+ // CHECK: smull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+uint32x4_t test_vmull_laneq_u16(uint16x4_t a, uint16x8_t v) {
+ // CHECK: test_vmull_laneq_u16
+ return vmull_laneq_u16(a, v, 7);
+ // CHECK: umull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[7]
+}
+
+uint64x2_t test_vmull_laneq_u32(uint32x2_t a, uint32x4_t v) {
+ // CHECK: test_vmull_laneq_u32
+ return vmull_laneq_u32(a, v, 3);
+ // CHECK: umull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vmull_high_laneq_s16
+ return vmull_high_laneq_s16(a, v, 7);
+ // CHECK: smull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vmull_high_laneq_s32
+ return vmull_high_laneq_s32(a, v, 3);
+ // CHECK: smull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+uint32x4_t test_vmull_high_laneq_u16(uint16x8_t a, uint16x8_t v) {
+ // CHECK: test_vmull_high_laneq_u16
+ return vmull_high_laneq_u16(a, v, 7);
+ // CHECK: umull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+uint64x2_t test_vmull_high_laneq_u32(uint32x4_t a, uint32x4_t v) {
+ // CHECK: test_vmull_high_laneq_u32
+ return vmull_high_laneq_u32(a, v, 3);
+ // CHECK: umull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vqdmlal_lane_s16
+ return vqdmlal_lane_s16(a, b, v, 3);
+ // CHECK: sqdmlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vqdmlal_lane_s32
+ return vqdmlal_lane_s32(a, b, v, 1);
+ // CHECK: sqdmlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vqdmlal_high_lane_s16
+ return vqdmlal_high_lane_s16(a, b, v, 3);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vqdmlal_high_lane_s32
+ return vqdmlal_high_lane_s32(a, b, v, 1);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vqdmlsl_lane_s16
+ return vqdmlsl_lane_s16(a, b, v, 3);
+ // CHECK: sqdmlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vqdmlsl_lane_s32
+ return vqdmlsl_lane_s32(a, b, v, 1);
+ // CHECK: sqdmlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vqdmlsl_high_lane_s16
+ return vqdmlsl_high_lane_s16(a, b, v, 3);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vqdmlsl_high_lane_s32
+ return vqdmlsl_high_lane_s32(a, b, v, 1);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqdmull_lane_s16
+ return vqdmull_lane_s16(a, v, 3);
+ // CHECK: sqdmull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqdmull_lane_s32
+ return vqdmull_lane_s32(a, v, 1);
+ // CHECK: sqdmull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmull_laneq_s16(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vqdmull_laneq_s16
+ return vqdmull_laneq_s16(a, v, 3);
+ // CHECK: sqdmull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmull_laneq_s32(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vqdmull_laneq_s32
+ return vqdmull_laneq_s32(a, v, 3);
+ // CHECK: sqdmull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+int32x4_t test_vqdmull_high_lane_s16(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqdmull_high_lane_s16
+ return vqdmull_high_lane_s16(a, v, 3);
+ // CHECK: sqdmull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int64x2_t test_vqdmull_high_lane_s32(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqdmull_high_lane_s32
+ return vqdmull_high_lane_s32(a, v, 1);
+ // CHECK: sqdmull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vqdmull_high_laneq_s16
+ return vqdmull_high_laneq_s16(a, v, 7);
+ // CHECK: sqdmull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[7]
+}
+
+int64x2_t test_vqdmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vqdmull_high_laneq_s32
+ return vqdmull_high_laneq_s32(a, v, 3);
+ // CHECK: sqdmull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqdmulh_lane_s16
+ return vqdmulh_lane_s16(a, v, 3);
+ // CHECK: sqdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqdmulhq_lane_s16
+ return vqdmulhq_lane_s16(a, v, 3);
+ // CHECK: sqdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqdmulh_lane_s32
+ return vqdmulh_lane_s32(a, v, 1);
+ // CHECK: sqdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqdmulhq_lane_s32
+ return vqdmulhq_lane_s32(a, v, 1);
+ // CHECK: sqdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqrdmulh_lane_s16
+ return vqrdmulh_lane_s16(a, v, 3);
+ // CHECK: sqrdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[3]
+}
+
+int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqrdmulhq_lane_s16
+ return vqrdmulhq_lane_s16(a, v, 3);
+ // CHECK: sqrdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqrdmulh_lane_s32
+ return vqrdmulh_lane_s32(a, v, 1);
+ // CHECK: sqrdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vqrdmulhq_lane_s32(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqrdmulhq_lane_s32
+ return vqrdmulhq_lane_s32(a, v, 1);
+ // CHECK: sqrdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float32x2_t test_vmul_lane_f32(float32x2_t a, float32x2_t v) {
+ // CHECK: test_vmul_lane_f32
+ return vmul_lane_f32(a, v, 1);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+
+float64x1_t test_vmul_lane_f64(float64x1_t a, float64x1_t v) {
+ // CHECK: test_vmul_lane_f64
+ return vmul_lane_f64(a, v, 0);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+
+float32x4_t test_vmulq_lane_f32(float32x4_t a, float32x2_t v) {
+ // CHECK: test_vmulq_lane_f32
+ return vmulq_lane_f32(a, v, 1);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float64x2_t test_vmulq_lane_f64(float64x2_t a, float64x1_t v) {
+ // CHECK: test_vmulq_lane_f64
+ return vmulq_lane_f64(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vmul_laneq_f32(float32x2_t a, float32x4_t v) {
+ // CHECK: test_vmul_laneq_f32
+ return vmul_laneq_f32(a, v, 3);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+float64x1_t test_vmul_laneq_f64(float64x1_t a, float64x2_t v) {
+ // CHECK: test_vmul_laneq_f64
+ return vmul_laneq_f64(a, v, 1);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+
+float32x4_t test_vmulq_laneq_f32(float32x4_t a, float32x4_t v) {
+ // CHECK: test_vmulq_laneq_f32
+ return vmulq_laneq_f32(a, v, 3);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+float64x2_t test_vmulq_laneq_f64(float64x2_t a, float64x2_t v) {
+ // CHECK: test_vmulq_laneq_f64
+ return vmulq_laneq_f64(a, v, 1);
+ // CHECK: fmul {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[1]
+}
+
+float32x2_t test_vmulx_lane_f32(float32x2_t a, float32x2_t v) {
+ // CHECK: test_vmulx_lane_f32
+ return vmulx_lane_f32(a, v, 1);
+ // CHECK: fmulx {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vmulxq_lane_f32(float32x4_t a, float32x2_t v) {
+ // CHECK: test_vmulxq_lane_f32
+ return vmulxq_lane_f32(a, v, 1);
+ // CHECK: fmulx {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float64x2_t test_vmulxq_lane_f64(float64x2_t a, float64x1_t v) {
+ // CHECK: test_vmulxq_lane_f64
+ return vmulxq_lane_f64(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vmulx_laneq_f32(float32x2_t a, float32x4_t v) {
+ // CHECK: test_vmulx_laneq_f32
+ return vmulx_laneq_f32(a, v, 3);
+ // CHECK: fmulx {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[3]
+}
+
+float32x4_t test_vmulxq_laneq_f32(float32x4_t a, float32x4_t v) {
+ // CHECK: test_vmulxq_laneq_f32
+ return vmulxq_laneq_f32(a, v, 3);
+ // CHECK: fmulx {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[3]
+}
+
+float64x2_t test_vmulxq_laneq_f64(float64x2_t a, float64x2_t v) {
+ // CHECK: test_vmulxq_laneq_f64
+ return vmulxq_laneq_f64(a, v, 1);
+ // CHECK: fmulx {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[1]
+}
+
+int16x4_t test_vmla_lane_s16_0(int16x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmla_lane_s16_0
+ return vmla_lane_s16(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmlaq_lane_s16_0(int16x8_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlaq_lane_s16_0
+ return vmlaq_lane_s16(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmla_lane_s32_0(int32x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmla_lane_s32_0
+ return vmla_lane_s32(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlaq_lane_s32_0(int32x4_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlaq_lane_s32_0
+ return vmlaq_lane_s32(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vmla_laneq_s16_0(int16x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmla_laneq_s16_0
+ return vmla_laneq_s16(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmlaq_laneq_s16_0(int16x8_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlaq_laneq_s16_0
+ return vmlaq_laneq_s16(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmla_laneq_s32_0(int32x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmla_laneq_s32_0
+ return vmla_laneq_s32(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlaq_laneq_s32_0(int32x4_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlaq_laneq_s32_0
+ return vmlaq_laneq_s32(a, b, v, 0);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vmls_lane_s16_0(int16x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmls_lane_s16_0
+ return vmls_lane_s16(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmlsq_lane_s16_0(int16x8_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsq_lane_s16_0
+ return vmlsq_lane_s16(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmls_lane_s32_0(int32x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmls_lane_s32_0
+ return vmls_lane_s32(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsq_lane_s32_0(int32x4_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsq_lane_s32_0
+ return vmlsq_lane_s32(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vmls_laneq_s16_0(int16x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmls_laneq_s16_0
+ return vmls_laneq_s16(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmlsq_laneq_s16_0(int16x8_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsq_laneq_s16_0
+ return vmlsq_laneq_s16(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmls_laneq_s32_0(int32x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmls_laneq_s32_0
+ return vmls_laneq_s32(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsq_laneq_s32_0(int32x4_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsq_laneq_s32_0
+ return vmlsq_laneq_s32(a, b, v, 0);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vmul_lane_s16_0(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vmul_lane_s16_0
+ return vmul_lane_s16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmulq_lane_s16_0(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vmulq_lane_s16_0
+ return vmulq_lane_s16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmul_lane_s32_0(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vmul_lane_s32_0
+ return vmul_lane_s32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmulq_lane_s32_0(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vmulq_lane_s32_0
+ return vmulq_lane_s32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint16x4_t test_vmul_lane_u16_0(uint16x4_t a, uint16x4_t v) {
+ // CHECK: test_vmul_lane_u16_0
+ return vmul_lane_u16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+uint16x8_t test_vmulq_lane_u16_0(uint16x8_t a, uint16x4_t v) {
+ // CHECK: test_vmulq_lane_u16_0
+ return vmulq_lane_u16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint32x2_t test_vmul_lane_u32_0(uint32x2_t a, uint32x2_t v) {
+ // CHECK: test_vmul_lane_u32_0
+ return vmul_lane_u32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmulq_lane_u32_0(uint32x4_t a, uint32x2_t v) {
+ // CHECK: test_vmulq_lane_u32_0
+ return vmulq_lane_u32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vmul_laneq_s16_0(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vmul_laneq_s16_0
+ return vmul_laneq_s16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vmulq_laneq_s16_0(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vmulq_laneq_s16_0
+ return vmulq_laneq_s16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vmul_laneq_s32_0(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vmul_laneq_s32_0
+ return vmul_laneq_s32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmulq_laneq_s32_0(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vmulq_laneq_s32_0
+ return vmulq_laneq_s32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint16x4_t test_vmul_laneq_u16_0(uint16x4_t a, uint16x8_t v) {
+ // CHECK: test_vmul_laneq_u16_0
+ return vmul_laneq_u16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+uint16x8_t test_vmulq_laneq_u16_0(uint16x8_t a, uint16x8_t v) {
+ // CHECK: test_vmulq_laneq_u16_0
+ return vmulq_laneq_u16(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint32x2_t test_vmul_laneq_u32_0(uint32x2_t a, uint32x4_t v) {
+ // CHECK: test_vmul_laneq_u32_0
+ return vmul_laneq_u32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmulq_laneq_u32_0(uint32x4_t a, uint32x4_t v) {
+ // CHECK: test_vmulq_laneq_u32_0
+ return vmulq_laneq_u32(a, v, 0);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vfma_lane_f32_0(float32x2_t a, float32x2_t b, float32x2_t v) {
+ // CHECK: test_vfma_lane_f32_0
+ return vfma_lane_f32(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmaq_lane_f32_0(float32x4_t a, float32x4_t b, float32x2_t v) {
+ // CHECK: test_vfmaq_lane_f32_0
+ return vfmaq_lane_f32(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vfma_laneq_f32_0(float32x2_t a, float32x2_t b, float32x4_t v) {
+ // CHECK: test_vfma_laneq_f32_0
+ return vfma_laneq_f32(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmaq_laneq_f32_0(float32x4_t a, float32x4_t b, float32x4_t v) {
+ // CHECK: test_vfmaq_laneq_f32_0
+ return vfmaq_laneq_f32(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vfms_lane_f32_0(float32x2_t a, float32x2_t b, float32x2_t v) {
+ // CHECK: test_vfms_lane_f32_0
+ return vfms_lane_f32(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmsq_lane_f32_0(float32x4_t a, float32x4_t b, float32x2_t v) {
+ // CHECK: test_vfmsq_lane_f32_0
+ return vfmsq_lane_f32(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vfms_laneq_f32_0(float32x2_t a, float32x2_t b, float32x4_t v) {
+ // CHECK: test_vfms_laneq_f32_0
+ return vfms_laneq_f32(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmsq_laneq_f32_0(float32x4_t a, float32x4_t b, float32x4_t v) {
+ // CHECK: test_vfmsq_laneq_f32_0
+ return vfmsq_laneq_f32(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vfmaq_laneq_f64_0(float64x2_t a, float64x2_t b, float64x2_t v) {
+ // CHECK: test_vfmaq_laneq_f64_0
+ return vfmaq_laneq_f64(a, b, v, 0);
+ // CHECK: fmla {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float64x2_t test_vfmsq_laneq_f64_0(float64x2_t a, float64x2_t b, float64x2_t v) {
+ // CHECK: test_vfmsq_laneq_f64_0
+ return vfmsq_laneq_f64(a, b, v, 0);
+ // CHECK: fmls {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+int32x4_t test_vmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlal_lane_s16_0
+ return vmlal_lane_s16(a, b, v, 0);
+ // CHECK: smlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlal_lane_s32_0
+ return vmlal_lane_s32(a, b, v, 0);
+ // CHECK: smlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlal_laneq_s16_0
+ return vmlal_laneq_s16(a, b, v, 0);
+ // CHECK: smlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlal_laneq_s32_0
+ return vmlal_laneq_s32(a, b, v, 0);
+ // CHECK: smlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlal_high_lane_s16_0
+ return vmlal_high_lane_s16(a, b, v, 0);
+ // CHECK: smlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlal_high_lane_s32_0
+ return vmlal_high_lane_s32(a, b, v, 0);
+ // CHECK: smlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlal_high_laneq_s16_0
+ return vmlal_high_laneq_s16(a, b, v, 0);
+ // CHECK: smlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlal_high_laneq_s32_0
+ return vmlal_high_laneq_s32(a, b, v, 0);
+ // CHECK: smlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_lane_s16_0
+ return vmlsl_lane_s16(a, b, v, 0);
+ // CHECK: smlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_lane_s32_0
+ return vmlsl_lane_s32(a, b, v, 0);
+ // CHECK: smlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_laneq_s16_0
+ return vmlsl_laneq_s16(a, b, v, 0);
+ // CHECK: smlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_laneq_s32_0
+ return vmlsl_laneq_s32(a, b, v, 0);
+ // CHECK: smlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_high_lane_s16_0
+ return vmlsl_high_lane_s16(a, b, v, 0);
+ // CHECK: smlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_high_lane_s32_0
+ return vmlsl_high_lane_s32(a, b, v, 0);
+ // CHECK: smlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_high_laneq_s16_0
+ return vmlsl_high_laneq_s16(a, b, v, 0);
+ // CHECK: smlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_high_laneq_s32_0
+ return vmlsl_high_laneq_s32(a, b, v, 0);
+ // CHECK: smlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlal_lane_u16_0
+ return vmlal_lane_u16(a, b, v, 0);
+ // CHECK: umlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlal_lane_u32_0
+ return vmlal_lane_u32(a, b, v, 0);
+ // CHECK: umlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlal_laneq_u16_0
+ return vmlal_laneq_u16(a, b, v, 0);
+ // CHECK: umlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlal_laneq_u32_0
+ return vmlal_laneq_u32(a, b, v, 0);
+ // CHECK: umlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlal_high_lane_u16_0
+ return vmlal_high_lane_u16(a, b, v, 0);
+ // CHECK: umlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlal_high_lane_u32_0
+ return vmlal_high_lane_u32(a, b, v, 0);
+ // CHECK: umlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlal_high_laneq_u16_0
+ return vmlal_high_laneq_u16(a, b, v, 0);
+ // CHECK: umlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlal_high_laneq_u32_0
+ return vmlal_high_laneq_u32(a, b, v, 0);
+ // CHECK: umlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_lane_u16_0
+ return vmlsl_lane_u16(a, b, v, 0);
+ // CHECK: umlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_lane_u32_0
+ return vmlsl_lane_u32(a, b, v, 0);
+ // CHECK: umlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_laneq_u16_0
+ return vmlsl_laneq_u16(a, b, v, 0);
+ // CHECK: umlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_laneq_u32_0
+ return vmlsl_laneq_u32(a, b, v, 0);
+ // CHECK: umlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vmlsl_high_lane_u16_0
+ return vmlsl_high_lane_u16(a, b, v, 0);
+ // CHECK: umlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vmlsl_high_lane_u32_0
+ return vmlsl_high_lane_u32(a, b, v, 0);
+ // CHECK: umlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
+ // CHECK: test_vmlsl_high_laneq_u16_0
+ return vmlsl_high_laneq_u16(a, b, v, 0);
+ // CHECK: umlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
+ // CHECK: test_vmlsl_high_laneq_u32_0
+ return vmlsl_high_laneq_u32(a, b, v, 0);
+ // CHECK: umlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmull_lane_s16_0(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vmull_lane_s16_0
+ return vmull_lane_s16(a, v, 0);
+ // CHECK: smull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmull_lane_s32_0(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vmull_lane_s32_0
+ return vmull_lane_s32(a, v, 0);
+ // CHECK: smull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmull_lane_u16_0(uint16x4_t a, uint16x4_t v) {
+ // CHECK: test_vmull_lane_u16_0
+ return vmull_lane_u16(a, v, 0);
+ // CHECK: umull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmull_lane_u32_0(uint32x2_t a, uint32x2_t v) {
+ // CHECK: test_vmull_lane_u32_0
+ return vmull_lane_u32(a, v, 0);
+ // CHECK: umull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vmull_high_lane_s16_0
+ return vmull_high_lane_s16(a, v, 0);
+ // CHECK: smull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vmull_high_lane_s32_0
+ return vmull_high_lane_s32(a, v, 0);
+ // CHECK: smull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmull_high_lane_u16_0(uint16x8_t a, uint16x4_t v) {
+ // CHECK: test_vmull_high_lane_u16_0
+ return vmull_high_lane_u16(a, v, 0);
+ // CHECK: umull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmull_high_lane_u32_0(uint32x4_t a, uint32x2_t v) {
+ // CHECK: test_vmull_high_lane_u32_0
+ return vmull_high_lane_u32(a, v, 0);
+ // CHECK: umull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vmull_laneq_s16_0
+ return vmull_laneq_s16(a, v, 0);
+ // CHECK: smull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vmull_laneq_s32_0
+ return vmull_laneq_s32(a, v, 0);
+ // CHECK: smull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmull_laneq_u16_0(uint16x4_t a, uint16x8_t v) {
+ // CHECK: test_vmull_laneq_u16_0
+ return vmull_laneq_u16(a, v, 0);
+ // CHECK: umull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmull_laneq_u32_0(uint32x2_t a, uint32x4_t v) {
+ // CHECK: test_vmull_laneq_u32_0
+ return vmull_laneq_u32(a, v, 0);
+ // CHECK: umull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vmull_high_laneq_s16_0
+ return vmull_high_laneq_s16(a, v, 0);
+ // CHECK: smull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vmull_high_laneq_s32_0
+ return vmull_high_laneq_s32(a, v, 0);
+ // CHECK: smull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmull_high_laneq_u16_0(uint16x8_t a, uint16x8_t v) {
+ // CHECK: test_vmull_high_laneq_u16_0
+ return vmull_high_laneq_u16(a, v, 0);
+ // CHECK: umull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmull_high_laneq_u32_0(uint32x4_t a, uint32x4_t v) {
+ // CHECK: test_vmull_high_laneq_u32_0
+ return vmull_high_laneq_u32(a, v, 0);
+ // CHECK: umull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vqdmlal_lane_s16_0
+ return vqdmlal_lane_s16(a, b, v, 0);
+ // CHECK: sqdmlal {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vqdmlal_lane_s32_0
+ return vqdmlal_lane_s32(a, b, v, 0);
+ // CHECK: sqdmlal {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vqdmlal_high_lane_s16_0
+ return vqdmlal_high_lane_s16(a, b, v, 0);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vqdmlal_high_lane_s32_0
+ return vqdmlal_high_lane_s32(a, b, v, 0);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
+ // CHECK: test_vqdmlsl_lane_s16_0
+ return vqdmlsl_lane_s16(a, b, v, 0);
+ // CHECK: sqdmlsl {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
+ // CHECK: test_vqdmlsl_lane_s32_0
+ return vqdmlsl_lane_s32(a, b, v, 0);
+ // CHECK: sqdmlsl {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
+ // CHECK: test_vqdmlsl_high_lane_s16_0
+ return vqdmlsl_high_lane_s16(a, b, v, 0);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
+ // CHECK: test_vqdmlsl_high_lane_s32_0
+ return vqdmlsl_high_lane_s32(a, b, v, 0);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmull_lane_s16_0(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqdmull_lane_s16_0
+ return vqdmull_lane_s16(a, v, 0);
+ // CHECK: sqdmull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmull_lane_s32_0(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqdmull_lane_s32_0
+ return vqdmull_lane_s32(a, v, 0);
+ // CHECK: sqdmull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
+ // CHECK: test_vqdmull_laneq_s16_0
+ return vqdmull_laneq_s16(a, v, 0);
+ // CHECK: sqdmull {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
+ // CHECK: test_vqdmull_laneq_s32_0
+ return vqdmull_laneq_s32(a, v, 0);
+ // CHECK: sqdmull {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqdmull_high_lane_s16_0
+ return vqdmull_high_lane_s16(a, v, 0);
+ // CHECK: sqdmull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqdmull_high_lane_s32_0
+ return vqdmull_high_lane_s32(a, v, 0);
+ // CHECK: sqdmull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
+ // CHECK: test_vqdmull_high_laneq_s16_0
+ return vqdmull_high_laneq_s16(a, v, 0);
+ // CHECK: sqdmull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
+ // CHECK: test_vqdmull_high_laneq_s32_0
+ return vqdmull_high_laneq_s32(a, v, 0);
+ // CHECK: sqdmull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vqdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqdmulh_lane_s16_0
+ return vqdmulh_lane_s16(a, v, 0);
+ // CHECK: sqdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vqdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqdmulhq_lane_s16_0
+ return vqdmulhq_lane_s16(a, v, 0);
+ // CHECK: sqdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vqdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqdmulh_lane_s32_0
+ return vqdmulh_lane_s32(a, v, 0);
+ // CHECK: sqdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmulhq_lane_s32_0(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqdmulhq_lane_s32_0
+ return vqdmulhq_lane_s32(a, v, 0);
+ // CHECK: sqdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int16x4_t test_vqrdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
+ // CHECK: test_vqrdmulh_lane_s16_0
+ return vqrdmulh_lane_s16(a, v, 0);
+ // CHECK: sqrdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.h[0]
+}
+
+int16x8_t test_vqrdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
+ // CHECK: test_vqrdmulhq_lane_s16_0
+ return vqrdmulhq_lane_s16(a, v, 0);
+ // CHECK: sqrdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int32x2_t test_vqrdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
+ // CHECK: test_vqrdmulh_lane_s32_0
+ return vqrdmulh_lane_s32(a, v, 0);
+ // CHECK: sqrdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqrdmulhq_lane_s32_0(int32x4_t a, int32x2_t v) {
+ // CHECK: test_vqrdmulhq_lane_s32_0
+ return vqrdmulhq_lane_s32(a, v, 0);
+ // CHECK: sqrdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vmul_lane_f32_0(float32x2_t a, float32x2_t v) {
+ // CHECK: test_vmul_lane_f32_0
+ return vmul_lane_f32(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vmulq_lane_f32_0(float32x4_t a, float32x2_t v) {
+ // CHECK: test_vmulq_lane_f32_0
+ return vmulq_lane_f32(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vmul_laneq_f32_0(float32x2_t a, float32x4_t v) {
+ // CHECK: test_vmul_laneq_f32_0
+ return vmul_laneq_f32(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float64x1_t test_vmul_laneq_f64_0(float64x1_t a, float64x2_t v) {
+ // CHECK: test_vmul_laneq_f64_0
+ return vmul_laneq_f64(a, v, 0);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+float32x4_t test_vmulq_laneq_f32_0(float32x4_t a, float32x4_t v) {
+ // CHECK: test_vmulq_laneq_f32_0
+ return vmulq_laneq_f32(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vmulq_laneq_f64_0(float64x2_t a, float64x2_t v) {
+ // CHECK: test_vmulq_laneq_f64_0
+ return vmulq_laneq_f64(a, v, 0);
+ // CHECK: fmul {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vmulx_lane_f32_0(float32x2_t a, float32x2_t v) {
+ // CHECK: test_vmulx_lane_f32_0
+ return vmulx_lane_f32(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vmulxq_lane_f32_0(float32x4_t a, float32x2_t v) {
+ // CHECK: test_vmulxq_lane_f32_0
+ return vmulxq_lane_f32(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vmulxq_lane_f64_0(float64x2_t a, float64x1_t v) {
+ // CHECK: test_vmulxq_lane_f64_0
+ return vmulxq_lane_f64(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vmulx_laneq_f32_0(float32x2_t a, float32x4_t v) {
+ // CHECK: test_vmulx_laneq_f32_0
+ return vmulx_laneq_f32(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vmulxq_laneq_f32_0(float32x4_t a, float32x4_t v) {
+ // CHECK: test_vmulxq_laneq_f32_0
+ return vmulxq_laneq_f32(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vmulxq_laneq_f64_0(float64x2_t a, float64x2_t v) {
+ // CHECK: test_vmulxq_laneq_f64_0
+ return vmulxq_laneq_f64(a, v, 0);
+ // CHECK: fmulx {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+int32x4_t test_vmull_high_n_s16(int16x8_t a, int16_t b) {
+ // CHECK: test_vmull_high_n_s16
+ return vmull_high_n_s16(a, b);
+ // CHECK: smull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmull_high_n_s32(int32x4_t a, int32_t b) {
+ // CHECK: test_vmull_high_n_s32
+ return vmull_high_n_s32(a, b);
+ // CHECK: smull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmull_high_n_u16(uint16x8_t a, uint16_t b) {
+ // CHECK: test_vmull_high_n_u16
+ return vmull_high_n_u16(a, b);
+ // CHECK: umull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmull_high_n_u32(uint32x4_t a, uint32_t b) {
+ // CHECK: test_vmull_high_n_u32
+ return vmull_high_n_u32(a, b);
+ // CHECK: umull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmull_high_n_s16(int16x8_t a, int16_t b) {
+ // CHECK: test_vqdmull_high_n_s16
+ return vqdmull_high_n_s16(a, b);
+ // CHECK: sqdmull2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmull_high_n_s32(int32x4_t a, int32_t b) {
+ // CHECK: test_vqdmull_high_n_s32
+ return vqdmull_high_n_s32(a, b);
+ // CHECK: sqdmull2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
+ // CHECK: test_vmlal_high_n_s16
+ return vmlal_high_n_s16(a, b, c);
+ // CHECK: smlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
+ // CHECK: test_vmlal_high_n_s32
+ return vmlal_high_n_s32(a, b, c);
+ // CHECK: smlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmlal_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
+ // CHECK: test_vmlal_high_n_u16
+ return vmlal_high_n_u16(a, b, c);
+ // CHECK: umlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmlal_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
+ // CHECK: test_vmlal_high_n_u32
+ return vmlal_high_n_u32(a, b, c);
+ // CHECK: umlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
+ // CHECK: test_vqdmlal_high_n_s16
+ return vqdmlal_high_n_s16(a, b, c);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
+ // CHECK: test_vqdmlal_high_n_s32
+ return vqdmlal_high_n_s32(a, b, c);
+ // CHECK: sqdmlal2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
+ // CHECK: test_vmlsl_high_n_s16
+ return vmlsl_high_n_s16(a, b, c);
+ // CHECK: smlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vmlsl_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
+ // CHECK: test_vmlsl_high_n_s32
+ return vmlsl_high_n_s32(a, b, c);
+ // CHECK: smlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vmlsl_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
+ // CHECK: test_vmlsl_high_n_u16
+ return vmlsl_high_n_u16(a, b, c);
+ // CHECK: umlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+uint64x2_t test_vmlsl_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
+ // CHECK: test_vmlsl_high_n_u32
+ return vmlsl_high_n_u32(a, b, c);
+ // CHECK: umlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vqdmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
+ // CHECK: test_vqdmlsl_high_n_s16
+ return vqdmlsl_high_n_s16(a, b, c);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, {{v[0-9]+}}.h[0]
+}
+
+int64x2_t test_vqdmlsl_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
+ // CHECK: test_vqdmlsl_high_n_s32
+ return vqdmlsl_high_n_s32(a, b, c);
+ // CHECK: sqdmlsl2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vmul_n_f32(float32x2_t a, float32_t b) {
+ // CHECK: test_vmul_n_f32
+ return vmul_n_f32(a, b);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vmulq_n_f32(float32x4_t a, float32_t b) {
+ // CHECK: test_vmulq_n_f32
+ return vmulq_n_f32(a, b);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vmulq_n_f64(float64x2_t a, float64_t b) {
+ // CHECK: test_vmulq_n_f64
+ return vmulq_n_f64(a, b);
+ // CHECK: fmul {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vfma_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
+ // CHECK: test_vfma_n_f32
+ return vfma_n_f32(a, b, n);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmaq_n_f32(float32x4_t a, float32x4_t b, float32_t n) {
+ // CHECK: test_vfmaq_n_f32
+ return vfmaq_n_f32(a, b, n);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float32x2_t test_vfms_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
+ // CHECK: test_vfms_n_f32
+ return vfms_n_f32(a, b, n);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vfmsq_n_f32(float32x4_t a, float32x4_t b, float32_t n) {
+ // CHECK: test_vfmsq_n_f32
+ return vfmsq_n_f32(a, b, n);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
diff --git a/test/CodeGen/aarch64-neon-across.c b/test/CodeGen/aarch64-neon-across.c
new file mode 100644
index 000000000000..257b839e2248
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-across.c
@@ -0,0 +1,271 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int16_t test_vaddlv_s8(int8x8_t a) {
+ // CHECK: test_vaddlv_s8
+ return vaddlv_s8(a);
+ // CHECK: saddlv {{h[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+int32_t test_vaddlv_s16(int16x4_t a) {
+ // CHECK: test_vaddlv_s16
+ return vaddlv_s16(a);
+ // CHECK: saddlv {{s[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+uint16_t test_vaddlv_u8(uint8x8_t a) {
+ // CHECK: test_vaddlv_u8
+ return vaddlv_u8(a);
+ // CHECK: uaddlv {{h[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+uint32_t test_vaddlv_u16(uint16x4_t a) {
+ // CHECK: test_vaddlv_u16
+ return vaddlv_u16(a);
+ // CHECK: uaddlv {{s[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+int16_t test_vaddlvq_s8(int8x16_t a) {
+ // CHECK: test_vaddlvq_s8
+ return vaddlvq_s8(a);
+ // CHECK: saddlv {{h[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+int32_t test_vaddlvq_s16(int16x8_t a) {
+ // CHECK: test_vaddlvq_s16
+ return vaddlvq_s16(a);
+ // CHECK: saddlv {{s[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+int64_t test_vaddlvq_s32(int32x4_t a) {
+ // CHECK: test_vaddlvq_s32
+ return vaddlvq_s32(a);
+ // CHECK: saddlv {{d[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint16_t test_vaddlvq_u8(uint8x16_t a) {
+ // CHECK: test_vaddlvq_u8
+ return vaddlvq_u8(a);
+ // CHECK: uaddlv {{h[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+uint32_t test_vaddlvq_u16(uint16x8_t a) {
+ // CHECK: test_vaddlvq_u16
+ return vaddlvq_u16(a);
+ // CHECK: uaddlv {{s[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+uint64_t test_vaddlvq_u32(uint32x4_t a) {
+ // CHECK: test_vaddlvq_u32
+ return vaddlvq_u32(a);
+ // CHECK: uaddlv {{d[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+int8_t test_vmaxv_s8(int8x8_t a) {
+ // CHECK: test_vmaxv_s8
+ return vmaxv_s8(a);
+ // CHECK: smaxv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+int16_t test_vmaxv_s16(int16x4_t a) {
+ // CHECK: test_vmaxv_s16
+ return vmaxv_s16(a);
+ // CHECK: smaxv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+uint8_t test_vmaxv_u8(uint8x8_t a) {
+ // CHECK: test_vmaxv_u8
+ return vmaxv_u8(a);
+ // CHECK: umaxv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+uint16_t test_vmaxv_u16(uint16x4_t a) {
+ // CHECK: test_vmaxv_u16
+ return vmaxv_u16(a);
+ // CHECK: umaxv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+int8_t test_vmaxvq_s8(int8x16_t a) {
+ // CHECK: test_vmaxvq_s8
+ return vmaxvq_s8(a);
+ // CHECK: smaxv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+int16_t test_vmaxvq_s16(int16x8_t a) {
+ // CHECK: test_vmaxvq_s16
+ return vmaxvq_s16(a);
+ // CHECK: smaxv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+int32_t test_vmaxvq_s32(int32x4_t a) {
+ // CHECK: test_vmaxvq_s32
+ return vmaxvq_s32(a);
+ // CHECK: smaxv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint8_t test_vmaxvq_u8(uint8x16_t a) {
+ // CHECK: test_vmaxvq_u8
+ return vmaxvq_u8(a);
+ // CHECK: umaxv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+uint16_t test_vmaxvq_u16(uint16x8_t a) {
+ // CHECK: test_vmaxvq_u16
+ return vmaxvq_u16(a);
+ // CHECK: umaxv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+uint32_t test_vmaxvq_u32(uint32x4_t a) {
+ // CHECK: test_vmaxvq_u32
+ return vmaxvq_u32(a);
+ // CHECK: umaxv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+int8_t test_vminv_s8(int8x8_t a) {
+ // CHECK: test_vminv_s8
+ return vminv_s8(a);
+ // CHECK: sminv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+int16_t test_vminv_s16(int16x4_t a) {
+ // CHECK: test_vminv_s16
+ return vminv_s16(a);
+ // CHECK: sminv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+uint8_t test_vminv_u8(uint8x8_t a) {
+ // CHECK: test_vminv_u8
+ return vminv_u8(a);
+ // CHECK: uminv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+uint16_t test_vminv_u16(uint16x4_t a) {
+ // CHECK: test_vminv_u16
+ return vminv_u16(a);
+ // CHECK: uminv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+int8_t test_vminvq_s8(int8x16_t a) {
+ // CHECK: test_vminvq_s8
+ return vminvq_s8(a);
+ // CHECK: sminv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+int16_t test_vminvq_s16(int16x8_t a) {
+ // CHECK: test_vminvq_s16
+ return vminvq_s16(a);
+ // CHECK: sminv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+int32_t test_vminvq_s32(int32x4_t a) {
+ // CHECK: test_vminvq_s32
+ return vminvq_s32(a);
+ // CHECK: sminv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint8_t test_vminvq_u8(uint8x16_t a) {
+ // CHECK: test_vminvq_u8
+ return vminvq_u8(a);
+ // CHECK: uminv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+uint16_t test_vminvq_u16(uint16x8_t a) {
+ // CHECK: test_vminvq_u16
+ return vminvq_u16(a);
+ // CHECK: uminv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+uint32_t test_vminvq_u32(uint32x4_t a) {
+ // CHECK: test_vminvq_u32
+ return vminvq_u32(a);
+ // CHECK: uminv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+int8_t test_vaddv_s8(int8x8_t a) {
+ // CHECK: test_vaddv_s8
+ return vaddv_s8(a);
+ // CHECK: addv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+int16_t test_vaddv_s16(int16x4_t a) {
+ // CHECK: test_vaddv_s16
+ return vaddv_s16(a);
+ // CHECK: addv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+uint8_t test_vaddv_u8(uint8x8_t a) {
+ // CHECK: test_vaddv_u8
+ return vaddv_u8(a);
+ // CHECK: addv {{b[0-9]+}}, {{v[0-9]+}}.8b
+}
+
+uint16_t test_vaddv_u16(uint16x4_t a) {
+ // CHECK: test_vaddv_u16
+ return vaddv_u16(a);
+ // CHECK: addv {{h[0-9]+}}, {{v[0-9]+}}.4h
+}
+
+int8_t test_vaddvq_s8(int8x16_t a) {
+ // CHECK: test_vaddvq_s8
+ return vaddvq_s8(a);
+ // CHECK: addv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+int16_t test_vaddvq_s16(int16x8_t a) {
+ // CHECK: test_vaddvq_s16
+ return vaddvq_s16(a);
+ // CHECK: addv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+int32_t test_vaddvq_s32(int32x4_t a) {
+ // CHECK: test_vaddvq_s32
+ return vaddvq_s32(a);
+ // CHECK: addv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint8_t test_vaddvq_u8(uint8x16_t a) {
+ // CHECK: test_vaddvq_u8
+ return vaddvq_u8(a);
+ // CHECK: addv {{b[0-9]+}}, {{v[0-9]+}}.16b
+}
+
+uint16_t test_vaddvq_u16(uint16x8_t a) {
+ // CHECK: test_vaddvq_u16
+ return vaddvq_u16(a);
+ // CHECK: addv {{h[0-9]+}}, {{v[0-9]+}}.8h
+}
+
+uint32_t test_vaddvq_u32(uint32x4_t a) {
+ // CHECK: test_vaddvq_u32
+ return vaddvq_u32(a);
+ // CHECK: addv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+float32_t test_vmaxvq_f32(float32x4_t a) {
+ // CHECK: test_vmaxvq_f32
+ return vmaxvq_f32(a);
+ // CHECK: fmaxv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+float32_t test_vminvq_f32(float32x4_t a) {
+ // CHECK: test_vminvq_f32
+ return vminvq_f32(a);
+ // CHECK: fminv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+float32_t test_vmaxnmvq_f32(float32x4_t a) {
+ // CHECK: test_vmaxnmvq_f32
+ return vmaxnmvq_f32(a);
+ // CHECK: fmaxnmv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+float32_t test_vminnmvq_f32(float32x4_t a) {
+ // CHECK: test_vminnmvq_f32
+ return vminnmvq_f32(a);
+ // CHECK: fminnmv {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
diff --git a/test/CodeGen/aarch64-neon-copy.c b/test/CodeGen/aarch64-neon-copy.c
new file mode 100644
index 000000000000..eb91bf9b5a5c
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-copy.c
@@ -0,0 +1,1319 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+uint8x8_t test_vset_lane_u8(uint8_t v1, uint8x8_t v2) {
+ // CHECK: test_vset_lane_u8
+ return vset_lane_u8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+uint16x4_t test_vset_lane_u16(uint16_t v1, uint16x4_t v2) {
+ // CHECK: test_vset_lane_u16
+ return vset_lane_u16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+uint32x2_t test_vset_lane_u32(uint32_t v1, uint32x2_t v2) {
+ // CHECK: test_vset_lane_u32
+ return vset_lane_u32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{w[0-9]+}}
+}
+uint64x1_t test_vset_lane_u64(uint64_t v1, uint64x1_t v2) {
+ // CHECK: test_vset_lane_u64
+ return vset_lane_u64(v1, v2, 0);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int8x8_t test_vset_lane_s8(int8_t v1, int8x8_t v2) {
+ // CHECK: test_vset_lane_s8
+ return vset_lane_s8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+int16x4_t test_vset_lane_s16(int16_t v1, int16x4_t v2) {
+ // CHECK: test_vset_lane_s16
+ return vset_lane_s16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+int32x2_t test_vset_lane_s32(int32_t v1, int32x2_t v2) {
+ // CHECK: test_vset_lane_s32
+ return vset_lane_s32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{w[0-9]+}}
+}
+
+ int64x1_t test_vset_lane_s64(int64_t v1, int64x1_t v2) {
+ // CHECK: test_vset_lane_s64
+ return vset_lane_s64(v1, v2, 0);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint8x16_t test_vsetq_lane_u8(uint8_t v1, uint8x16_t v2) {
+ // CHECK: test_vsetq_lane_u8
+ return vsetq_lane_u8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+uint16x8_t test_vsetq_lane_u16(uint16_t v1, uint16x8_t v2) {
+ // CHECK: test_vsetq_lane_u16
+ return vsetq_lane_u16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+uint32x4_t test_vsetq_lane_u32(uint32_t v1, uint32x4_t v2) {
+ // CHECK: test_vsetq_lane_u32
+ return vsetq_lane_u32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{w[0-9]+}}
+}
+
+ uint64x2_t test_vsetq_lane_u64(uint64_t v1, uint64x2_t v2) {
+ // CHECK: test_vsetq_lane_u64
+ return vsetq_lane_u64(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{x[0-9]+}}
+}
+
+int8x16_t test_vsetq_lane_s8(int8_t v1, int8x16_t v2) {
+ // CHECK: test_vsetq_lane_s8
+ return vsetq_lane_s8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+int16x8_t test_vsetq_lane_s16(int16_t v1, int16x8_t v2) {
+ // CHECK: test_vsetq_lane_s16
+ return vsetq_lane_s16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+int32x4_t test_vsetq_lane_s32(int32_t v1, int32x4_t v2) {
+ // CHECK: test_vsetq_lane_s32
+ return vsetq_lane_s32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{w[0-9]+}}
+}
+
+int64x2_t test_vsetq_lane_s64(int64_t v1, int64x2_t v2) {
+ // CHECK: test_vsetq_lane_s64
+ return vsetq_lane_s64(v1, v2, 0);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{x[0-9]+}}
+}
+
+poly8x8_t test_vset_lane_p8(poly8_t v1, poly8x8_t v2) {
+ // CHECK: test_vset_lane_p8
+ return vset_lane_p8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+poly16x4_t test_vset_lane_p16(poly16_t v1, poly16x4_t v2) {
+ // CHECK: test_vset_lane_p16
+ return vset_lane_p16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+poly8x16_t test_vsetq_lane_p8(poly8_t v1, poly8x16_t v2) {
+ // CHECK: test_vsetq_lane_p8
+ return vsetq_lane_p8(v1, v2, 6);
+ // CHECK: ins {{v[0-9]+}}.b[6], {{w[0-9]+}}
+}
+
+poly16x8_t test_vsetq_lane_p16(poly16_t v1, poly16x8_t v2) {
+ // CHECK: test_vsetq_lane_p16
+ return vsetq_lane_p16(v1, v2, 2);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{w[0-9]+}}
+}
+
+float32x2_t test_vset_lane_f32(float32_t v1, float32x2_t v2) {
+ // CHECK: test_vset_lane_f32
+ return vset_lane_f32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vsetq_lane_f32(float32_t v1, float32x4_t v2) {
+ // CHECK: test_vsetq_lane_f32
+ return vsetq_lane_f32(v1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+float64x1_t test_vset_lane_f64(float64_t v1, float64x1_t v2) {
+ // CHECK: test_vset_lane_f64
+ return vset_lane_f64(v1, v2, 0);
+ // CHECK: ret
+}
+
+float64x2_t test_vsetq_lane_f64(float64_t v1, float64x2_t v2) {
+ // CHECK: test_vsetq_lane_f64
+ return vsetq_lane_f64(v1, v2, 0);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[0]
+}
+
+uint8_t test_vget_lane_u8(uint8x8_t v1) {
+ // CHECK: test_vget_lane_u8
+ return vget_lane_u8(v1, 7);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+uint16_t test_vget_lane_u16(uint16x4_t v1) {
+ // CHECK: test_vget_lane_u16
+ return vget_lane_u16(v1, 3);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+uint32_t test_vget_lane_u32(uint32x2_t v1) {
+ // CHECK: test_vget_lane_u32
+ return vget_lane_u32(v1, 1);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+uint64_t test_vget_lane_u64(uint64x1_t v1) {
+ // CHECK: test_vget_lane_u64
+ return vget_lane_u64(v1, 0);
+ // CHECK: fmov {{x[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8_t test_vgetq_lane_u8(uint8x16_t v1) {
+ // CHECK: test_vgetq_lane_u8
+ return vgetq_lane_u8(v1, 15);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[15]
+}
+
+uint16_t test_vgetq_lane_u16(uint16x8_t v1) {
+ // CHECK: test_vgetq_lane_u16
+ return vgetq_lane_u16(v1, 6);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[6]
+}
+
+uint32_t test_vgetq_lane_u32(uint32x4_t v1) {
+ // CHECK: test_vgetq_lane_u32
+ return vgetq_lane_u32(v1, 2);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[2]
+}
+
+uint64_t test_vgetq_lane_u64(uint64x2_t v1) {
+ // CHECK: test_vgetq_lane_u64
+ return vgetq_lane_u64(v1, 1);
+ // CHECK: umov {{x[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+poly8_t test_vget_lane_p8(poly8x8_t v1) {
+ // CHECK: test_vget_lane_p8
+ return vget_lane_p8(v1, 7);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+poly16_t test_vget_lane_p16(poly16x4_t v1) {
+ // CHECK: test_vget_lane_p16
+ return vget_lane_p16(v1, 3);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+poly8_t test_vgetq_lane_p8(poly8x16_t v1) {
+ // CHECK: test_vgetq_lane_p8
+ return vgetq_lane_p8(v1, 14);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[14]
+}
+
+poly16_t test_vgetq_lane_p16(poly16x8_t v1) {
+ // CHECK: test_vgetq_lane_p16
+ return vgetq_lane_p16(v1, 6);
+ // CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[6]
+}
+
+int32_t test_vget_lane_s8(int8x8_t v1) {
+ // CHECK: test_vget_lane_s8
+ return vget_lane_s8(v1, 7)+1;
+ // CHECK: smov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+int32_t test_vget_lane_s16(int16x4_t v1) {
+ // CHECK: test_vget_lane_s16
+ return vget_lane_s16(v1, 3)+1;
+ // CHECK: smov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+int64_t test_vget_lane_s32(int32x2_t v1) {
+ // CHECK: test_vget_lane_s32
+ return vget_lane_s32(v1, 1);
+ // CHECK: smov {{x[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+int64_t test_vget_lane_s64(int64x1_t v1) {
+ // CHECK: test_vget_lane_s64
+ return vget_lane_s64(v1, 0);
+ // CHECK: fmov {{x[0-9]+}}, {{d[0-9]+}}
+}
+
+int32_t test_vgetq_lane_s8(int8x16_t v1) {
+ // CHECK: test_vgetq_lane_s8
+ return vgetq_lane_s8(v1, 15)+1;
+ // CHECK: smov {{w[0-9]+}}, {{v[0-9]+}}.b[15]
+}
+
+int32_t test_vgetq_lane_s16(int16x8_t v1) {
+ // CHECK: test_vgetq_lane_s16
+ return vgetq_lane_s16(v1, 6)+1;
+ // CHECK: smov {{w[0-9]+}}, {{v[0-9]+}}.h[6]
+}
+
+int64_t test_vgetq_lane_s32(int32x4_t v1) {
+ // CHECK: test_vgetq_lane_s32
+ return vgetq_lane_s32(v1, 2);
+ // CHECK: smov {{x[0-9]+}}, {{v[0-9]+}}.s[2]
+}
+
+int64_t test_vgetq_lane_s64(int64x2_t v1) {
+ // CHECK: test_vgetq_lane_s64
+ return vgetq_lane_s64(v1, 1);
+ // CHECK: umov {{x[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+int8x8_t test_vcopy_lane_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vcopy_lane_s8
+ return vcopy_lane_s8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+int16x4_t test_vcopy_lane_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vcopy_lane_s16
+ return vcopy_lane_s16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+poly8x8_t test_vcopy_lane_p8(poly8x8_t v1, poly8x8_t v2) {
+ // CHECK: test_vcopy_lane_p8
+ return vcopy_lane_p8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+poly16x4_t test_vcopy_lane_p16(poly16x4_t v1, poly16x4_t v2) {
+ // CHECK: test_vcopy_lane_p16
+ return vcopy_lane_p16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vcopy_lane_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vcopy_lane_s32
+ return vcopy_lane_s32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x2_t test_vcopy_lane_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcopy_lane_f32
+ return vcopy_lane_f32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint8x8_t test_vcopy_lane_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vcopy_lane_u8
+ return vcopy_lane_u8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+uint16x4_t test_vcopy_lane_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vcopy_lane_u16
+ return vcopy_lane_u16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+uint32x2_t test_vcopy_lane_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vcopy_lane_u32
+ return vcopy_lane_u32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int8x8_t test_vcopy_laneq_s8(int8x8_t v1, int8x16_t v2) {
+ // CHECK: test_vcopy_laneq_s8
+ return vcopy_laneq_s8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+int16x4_t test_vcopy_laneq_s16(int16x4_t v1, int16x8_t v2) {
+ // CHECK: test_vcopy_laneq_s16
+ return vcopy_laneq_s16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+poly8x8_t test_vcopy_laneq_p8(poly8x8_t v1, poly8x16_t v2) {
+ // CHECK: test_vcopy_laneq_p8
+ return vcopy_laneq_p8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+poly16x4_t test_vcopy_laneq_p16(poly16x4_t v1, poly16x8_t v2) {
+ // CHECK: test_vcopy_laneq_p16
+ return vcopy_laneq_p16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+int32x2_t test_vcopy_laneq_s32(int32x2_t v1, int32x4_t v2) {
+ // CHECK: test_vcopy_laneq_s32
+ return vcopy_laneq_s32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x2_t test_vcopy_laneq_f32(float32x2_t v1, float32x4_t v2) {
+ // CHECK: test_vcopy_laneq_f32
+ return vcopy_laneq_f32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint8x8_t test_vcopy_laneq_u8(uint8x8_t v1, uint8x16_t v2) {
+ // CHECK: test_vcopy_laneq_u8
+ return vcopy_laneq_u8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+uint16x4_t test_vcopy_laneq_u16(uint16x4_t v1, uint16x8_t v2) {
+ // CHECK: test_vcopy_laneq_u16
+ return vcopy_laneq_u16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+uint32x2_t test_vcopy_laneq_u32(uint32x2_t v1, uint32x4_t v2) {
+ // CHECK: test_vcopy_laneq_u32
+ return vcopy_laneq_u32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int8x16_t test_vcopyq_lane_s8(int8x16_t v1, int8x8_t v2) {
+ // CHECK: test_vcopyq_lane_s8
+ return vcopyq_lane_s8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+int16x8_t test_vcopyq_lane_s16(int16x8_t v1, int16x4_t v2) {
+ // CHECK: test_vcopyq_lane_s16
+ return vcopyq_lane_s16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+poly8x16_t test_vcopyq_lane_p8(poly8x16_t v1, poly8x8_t v2) {
+ // CHECK: test_vcopyq_lane_p8
+ return vcopyq_lane_p8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+poly16x8_t test_vcopyq_lane_p16(poly16x8_t v1, poly16x4_t v2) {
+ // CHECK: test_vcopyq_lane_p16
+ return vcopyq_lane_p16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+int32x4_t test_vcopyq_lane_s32(int32x4_t v1, int32x2_t v2) {
+ // CHECK: test_vcopyq_lane_s32
+ return vcopyq_lane_s32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int64x2_t test_vcopyq_lane_s64(int64x2_t v1, int64x1_t v2) {
+ // CHECK: test_vcopyq_lane_s64
+ return vcopyq_lane_s64(v1, 1, v2, 0);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+float32x4_t test_vcopyq_lane_f32(float32x4_t v1, float32x2_t v2) {
+ // CHECK: test_vcopyq_lane_f32
+ return vcopyq_lane_f32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float64x2_t test_vcopyq_lane_f64(float64x2_t v1, float64x1_t v2) {
+ // CHECK: test_vcopyq_lane_f64
+ return vcopyq_lane_f64(v1, 1, v2, 0);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+uint8x16_t test_vcopyq_lane_u8(uint8x16_t v1, uint8x8_t v2) {
+ // CHECK: test_vcopyq_lane_u8
+ return vcopyq_lane_u8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+uint16x8_t test_vcopyq_lane_u16(uint16x8_t v1, uint16x4_t v2) {
+ // CHECK: test_vcopyq_lane_u16
+ return vcopyq_lane_u16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+uint32x4_t test_vcopyq_lane_u32(uint32x4_t v1, uint32x2_t v2) {
+ // CHECK: test_vcopyq_lane_u32
+ return vcopyq_lane_u32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint64x2_t test_vcopyq_lane_u64(uint64x2_t v1, uint64x1_t v2) {
+ // CHECK: test_vcopyq_lane_u64
+ return vcopyq_lane_u64(v1, 1, v2, 0);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+int8x16_t test_vcopyq_laneq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vcopyq_laneq_s8
+ return vcopyq_laneq_s8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+int16x8_t test_vcopyq_laneq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vcopyq_laneq_s16
+ return vcopyq_laneq_s16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+poly8x16_t test_vcopyq_laneq_p8(poly8x16_t v1, poly8x16_t v2) {
+ // CHECK: test_vcopyq_laneq_p8
+ return vcopyq_laneq_p8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+poly16x8_t test_vcopyq_laneq_p16(poly16x8_t v1, poly16x8_t v2) {
+ // CHECK: test_vcopyq_laneq_p16
+ return vcopyq_laneq_p16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+int32x4_t test_vcopyq_laneq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vcopyq_laneq_s32
+ return vcopyq_laneq_s32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vcopyq_laneq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcopyq_laneq_f32
+ return vcopyq_laneq_f32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int64x2_t test_vcopyq_laneq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vcopyq_laneq_s64
+ return vcopyq_laneq_s64(v1, 1, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[1]
+}
+
+uint8x16_t test_vcopyq_laneq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vcopyq_laneq_u8
+ return vcopyq_laneq_u8(v1, 5, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.b[5], {{v[0-9]+}}.b[3]
+}
+
+uint16x8_t test_vcopyq_laneq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vcopyq_laneq_u16
+ return vcopyq_laneq_u16(v1, 2, v2, 3);
+ // CHECK: ins {{v[0-9]+}}.h[2], {{v[0-9]+}}.h[3]
+}
+
+uint32x4_t test_vcopyq_laneq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vcopyq_laneq_u32
+ return vcopyq_laneq_u32(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint64x2_t test_vcopyq_laneq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vcopyq_laneq_u64
+ return vcopyq_laneq_u64(v1, 0, v2, 1);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+int8x8_t test_vcreate_s8(uint64_t v1) {
+ // CHECK: test_vcreate_s8
+ return vcreate_s8(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int16x4_t test_vcreate_s16(uint64_t v1) {
+ // CHECK: test_vcreate_s16
+ return vcreate_s16(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int32x2_t test_vcreate_s32(uint64_t v1) {
+ // CHECK: test_vcreate_s32
+ return vcreate_s32(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int64x1_t test_vcreate_s64(uint64_t v1) {
+ // CHECK: test_vcreate_s64
+ return vcreate_s64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint8x8_t test_vcreate_u8(uint64_t v1) {
+ // CHECK: test_vcreate_u8
+ return vcreate_u8(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint16x4_t test_vcreate_u16(uint64_t v1) {
+ // CHECK: test_vcreate_u16
+ return vcreate_u16(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint32x2_t test_vcreate_u32(uint64_t v1) {
+ // CHECK: test_vcreate_u32
+ return vcreate_u32(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint64x1_t test_vcreate_u64(uint64_t v1) {
+ // CHECK: test_vcreate_u64
+ return vcreate_u64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+poly8x8_t test_vcreate_p8(uint64_t v1) {
+ // CHECK: test_vcreate_p8
+ return vcreate_p8(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+poly16x4_t test_vcreate_p16(uint64_t v1) {
+ // CHECK: test_vcreate_p16
+ return vcreate_p16(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+float16x4_t test_vcreate_f16(uint64_t v1) {
+ // CHECK: test_vcreate_f16
+ return vcreate_f16(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+float32x2_t test_vcreate_f32(uint64_t v1) {
+ // CHECK: test_vcreate_f32
+ return vcreate_f32(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+float64x1_t test_vcreate_f64(uint64_t v1) {
+ // CHECK: test_vcreate_f64
+ return vcreate_f64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint8x8_t test_vdup_n_u8(uint8_t v1) {
+ // CHECK: test_vdup_n_u8
+ return vdup_n_u8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+uint16x4_t test_vdup_n_u16(uint16_t v1) {
+ // CHECK: test_vdup_n_u16
+ return vdup_n_u16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+uint32x2_t test_vdup_n_u32(uint32_t v1) {
+ // CHECK: test_vdup_n_u32
+ return vdup_n_u32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{w[0-9]+}}
+}
+
+uint64x1_t test_vdup_n_u64(uint64_t v1) {
+ // CHECK: test_vdup_n_u64
+ return vdup_n_u64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint8x16_t test_vdupq_n_u8(uint8_t v1) {
+ // CHECK: test_vdupq_n_u8
+ return vdupq_n_u8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+uint16x8_t test_vdupq_n_u16(uint16_t v1) {
+ // CHECK: test_vdupq_n_u16
+ return vdupq_n_u16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+uint32x4_t test_vdupq_n_u32(uint32_t v1) {
+ // CHECK: test_vdupq_n_u32
+ return vdupq_n_u32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{w[0-9]+}}
+}
+
+uint64x2_t test_vdupq_n_u64(uint64_t v1) {
+ // CHECK: test_vdupq_n_u64
+ return vdupq_n_u64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
+int8x8_t test_vdup_n_s8(int8_t v1) {
+ // CHECK: test_vdup_n_s8
+ return vdup_n_s8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+int16x4_t test_vdup_n_s16(int16_t v1) {
+ // CHECK: test_vdup_n_s16
+ return vdup_n_s16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+int32x2_t test_vdup_n_s32(int32_t v1) {
+ // CHECK: test_vdup_n_s32
+ return vdup_n_s32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{w[0-9]+}}
+}
+
+int64x1_t test_vdup_n_s64(int64_t v1) {
+ // CHECK: test_vdup_n_s64
+ return vdup_n_s64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int8x16_t test_vdupq_n_s8(int8_t v1) {
+ // CHECK: test_vdupq_n_s8
+ return vdupq_n_s8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+int16x8_t test_vdupq_n_s16(int16_t v1) {
+ // CHECK: test_vdupq_n_s16
+ return vdupq_n_s16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+int32x4_t test_vdupq_n_s32(int32_t v1) {
+ // CHECK: test_vdupq_n_s32
+ return vdupq_n_s32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{w[0-9]+}}
+}
+
+int64x2_t test_vdupq_n_s64(int64_t v1) {
+ // CHECK: test_vdupq_n_s64
+ return vdupq_n_s64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
+poly8x8_t test_vdup_n_p8(poly8_t v1) {
+ // CHECK: test_vdup_n_p8
+ return vdup_n_p8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+poly16x4_t test_vdup_n_p16(poly16_t v1) {
+ // CHECK: test_vdup_n_p16
+ return vdup_n_p16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+poly8x16_t test_vdupq_n_p8(poly8_t v1) {
+ // CHECK: test_vdupq_n_p8
+ return vdupq_n_p8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+poly16x8_t test_vdupq_n_p16(poly16_t v1) {
+ // CHECK: test_vdupq_n_p16
+ return vdupq_n_p16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+float32x2_t test_vdup_n_f32(float32_t v1) {
+ // CHECK: test_vdup_n_f32
+ return vdup_n_f32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float64x1_t test_vdup_n_f64(float64_t v1) {
+ // CHECK: test_vdup_n_f64
+ return vdup_n_f64(v1);
+ // CHECK: ret
+}
+
+float32x4_t test_vdupq_n_f32(float32_t v1) {
+ // CHECK: test_vdupq_n_f32
+ return vdupq_n_f32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vdupq_n_f64(float64_t v1) {
+ // CHECK: test_vdupq_n_f64
+ return vdupq_n_f64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+int8x8_t test_vdup_lane_s8(int8x8_t v1) {
+ // CHECK: test_vdup_lane_s8
+ return vdup_lane_s8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+int16x4_t test_vdup_lane_s16(int16x4_t v1) {
+ // CHECK: test_vdup_lane_s16
+ return vdup_lane_s16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+int32x2_t test_vdup_lane_s32(int32x2_t v1) {
+ // CHECK: test_vdup_lane_s32
+ return vdup_lane_s32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int64x1_t test_vdup_lane_s64(int64x1_t v1) {
+ // CHECK: test_vdup_lane_s64
+ return vdup_lane_s64(v1, 0);
+ // CHECK: ret
+}
+
+int8x16_t test_vdupq_lane_s8(int8x8_t v1) {
+ // CHECK: test_vdupq_lane_s8
+ return vdupq_lane_s8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+int16x8_t test_vdupq_lane_s16(int16x4_t v1) {
+ // CHECK: test_vdupq_lane_s16
+ return vdupq_lane_s16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+int32x4_t test_vdupq_lane_s32(int32x2_t v1) {
+ // CHECK: test_vdupq_lane_s32
+ return vdupq_lane_s32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int64x2_t test_vdupq_lane_s64(int64x1_t v1) {
+ // CHECK: test_vdupq_lane_s64
+ return vdupq_lane_s64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+uint8x8_t test_vdup_lane_u8(uint8x8_t v1) {
+ // CHECK: test_vdup_lane_u8
+ return vdup_lane_u8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+uint16x4_t test_vdup_lane_u16(uint16x4_t v1) {
+ // CHECK: test_vdup_lane_u16
+ return vdup_lane_u16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+uint32x2_t test_vdup_lane_u32(uint32x2_t v1) {
+ // CHECK: test_vdup_lane_u32
+ return vdup_lane_u32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+uint64x1_t test_vdup_lane_u64(uint64x1_t v1) {
+ // CHECK: test_vdup_lane_u64
+ return vdup_lane_u64(v1, 0);
+ // CHECK: ret
+}
+
+uint8x16_t test_vdupq_lane_u8(uint8x8_t v1) {
+ // CHECK: test_vdupq_lane_u8
+ return vdupq_lane_u8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+uint16x8_t test_vdupq_lane_u16(uint16x4_t v1) {
+ // CHECK: test_vdupq_lane_u16
+ return vdupq_lane_u16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+uint32x4_t test_vdupq_lane_u32(uint32x2_t v1) {
+ // CHECK: test_vdupq_lane_u32
+ return vdupq_lane_u32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+uint64x2_t test_vdupq_lane_u64(uint64x1_t v1) {
+ // CHECK: test_vdupq_lane_u64
+ return vdupq_lane_u64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+int8x8_t test_vdup_laneq_s8(int8x16_t v1) {
+ // CHECK: test_vdup_laneq_s8
+ return vdup_laneq_s8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+int16x4_t test_vdup_laneq_s16(int16x8_t v1) {
+ // CHECK: test_vdup_laneq_s16
+ return vdup_laneq_s16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+int32x2_t test_vdup_laneq_s32(int32x4_t v1) {
+ // CHECK: test_vdup_laneq_s32
+ return vdup_laneq_s32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+int64x1_t test_vdup_laneq_s64(int64x2_t v1) {
+ // CHECK: test_vdup_laneq_s64
+ return vdup_laneq_s64(v1, 0);
+ // CHECK: ret
+}
+
+int8x16_t test_vdupq_laneq_s8(int8x16_t v1) {
+ // CHECK: test_vdupq_laneq_s8
+ return vdupq_laneq_s8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+int16x8_t test_vdupq_laneq_s16(int16x8_t v1) {
+ // CHECK: test_vdupq_laneq_s16
+ return vdupq_laneq_s16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+int32x4_t test_vdupq_laneq_s32(int32x4_t v1) {
+ // CHECK: test_vdupq_laneq_s32
+ return vdupq_laneq_s32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+int64x2_t test_vdupq_laneq_s64(int64x2_t v1) {
+ // CHECK: test_vdupq_laneq_s64
+ return vdupq_laneq_s64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+uint8x8_t test_vdup_laneq_u8(uint8x16_t v1) {
+ // CHECK: test_vdup_laneq_u8
+ return vdup_laneq_u8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+uint16x4_t test_vdup_laneq_u16(uint16x8_t v1) {
+ // CHECK: test_vdup_laneq_u16
+ return vdup_laneq_u16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+uint32x2_t test_vdup_laneq_u32(uint32x4_t v1) {
+ // CHECK: test_vdup_laneq_u32
+ return vdup_laneq_u32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+uint64x1_t test_vdup_laneq_u64(uint64x2_t v1) {
+ // CHECK: test_vdup_laneq_u64
+ return vdup_laneq_u64(v1, 0);
+ // CHECK: ret
+}
+
+uint8x16_t test_vdupq_laneq_u8(uint8x16_t v1) {
+ // CHECK: test_vdupq_laneq_u8
+ return vdupq_laneq_u8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+uint16x8_t test_vdupq_laneq_u16(uint16x8_t v1) {
+ // CHECK: test_vdupq_laneq_u16
+ return vdupq_laneq_u16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+uint32x4_t test_vdupq_laneq_u32(uint32x4_t v1) {
+ // CHECK: test_vdupq_laneq_u32
+ return vdupq_laneq_u32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+uint64x2_t test_vdupq_laneq_u64(uint64x2_t v1) {
+ // CHECK: test_vdupq_laneq_u64
+ return vdupq_laneq_u64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+poly8x8_t test_vdup_lane_p8(poly8x8_t v1) {
+ // CHECK: test_vdup_lane_p8
+ return vdup_lane_p8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+poly16x4_t test_vdup_lane_p16(poly16x4_t v1) {
+ // CHECK: test_vdup_lane_p16
+ return vdup_lane_p16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+poly8x16_t test_vdupq_lane_p8(poly8x8_t v1) {
+ // CHECK: test_vdupq_lane_p8
+ return vdupq_lane_p8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+poly16x8_t test_vdupq_lane_p16(poly16x4_t v1) {
+ // CHECK: test_vdupq_lane_p16
+ return vdupq_lane_p16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+poly8x8_t test_vdup_laneq_p8(poly8x16_t v1) {
+ // CHECK: test_vdup_laneq_p8
+ return vdup_laneq_p8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.8b, {{v[0-9]+}}.b[5]
+}
+
+poly16x4_t test_vdup_laneq_p16(poly16x8_t v1) {
+ // CHECK: test_vdup_laneq_p16
+ return vdup_laneq_p16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+poly8x16_t test_vdupq_laneq_p8(poly8x16_t v1) {
+ // CHECK: test_vdupq_laneq_p8
+ return vdupq_laneq_p8(v1, 5);
+ // CHECK: dup {{v[0-9]+}}.16b, {{v[0-9]+}}.b[5]
+}
+
+poly16x8_t test_vdupq_laneq_p16(poly16x8_t v1) {
+ // CHECK: test_vdupq_laneq_p16
+ return vdupq_laneq_p16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+float16x4_t test_vdup_lane_f16(float16x4_t v1) {
+ // CHECK: test_vdup_lane_f16
+ return vdup_lane_f16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+float32x2_t test_vdup_lane_f32(float32x2_t v1) {
+ // CHECK: test_vdup_lane_f32
+ return vdup_lane_f32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+float64x1_t test_vdup_lane_f64(float64x1_t v1) {
+ // CHECK: test_vdup_lane_f64
+ return vdup_lane_f64(v1, 0);
+ // CHECK: ret
+}
+
+float16x4_t test_vdup_laneq_f16(float16x8_t v1) {
+ // CHECK: test_vdup_laneq_f16
+ return vdup_laneq_f16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.4h, {{v[0-9]+}}.h[2]
+}
+
+float32x2_t test_vdup_laneq_f32(float32x4_t v1) {
+ // CHECK: test_vdup_laneq_f32
+ return vdup_laneq_f32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[1]
+}
+
+float64x1_t test_vdup_laneq_f64(float64x2_t v1) {
+ // CHECK: test_vdup_laneq_f64
+ return vdup_laneq_f64(v1, 0);
+ // CHECK: ret
+}
+
+float16x8_t test_vdupq_lane_f16(float16x4_t v1) {
+ // CHECK: test_vdupq_lane_f16
+ return vdupq_lane_f16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+float32x4_t test_vdupq_lane_f32(float32x2_t v1) {
+ // CHECK: test_vdupq_lane_f32
+ return vdupq_lane_f32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float64x2_t test_vdupq_lane_f64(float64x1_t v1) {
+ // CHECK: test_vdupq_lane_f64
+ return vdupq_lane_f64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+float16x8_t test_vdupq_laneq_f16(float16x8_t v1) {
+ // CHECK: test_vdupq_laneq_f16
+ return vdupq_laneq_f16(v1, 2);
+ // CHECK: dup {{v[0-9]+}}.8h, {{v[0-9]+}}.h[2]
+}
+
+float32x4_t test_vdupq_laneq_f32(float32x4_t v1) {
+ // CHECK: test_vdupq_laneq_f32
+ return vdupq_laneq_f32(v1, 1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[1]
+}
+
+float64x2_t test_vdupq_laneq_f64(float64x2_t v1) {
+ // CHECK: test_vdupq_laneq_f64
+ return vdupq_laneq_f64(v1, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+int8x8_t test_vmov_n_s8(int8_t v1) {
+ // CHECK: test_vmov_n_s8
+ return vmov_n_s8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+int16x4_t test_vmov_n_s16(int16_t v1) {
+ // CHECK: test_vmov_n_s16
+ return vmov_n_s16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+int32x2_t test_vmov_n_s32(int32_t v1) {
+ // CHECK: test_vmov_n_s32
+ return vmov_n_s32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{w[0-9]+}}
+}
+
+int64x1_t test_vmov_n_s64(int64_t v1) {
+ // CHECK: test_vmov_n_s64
+ return vmov_n_s64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+int8x16_t test_vmovq_n_s8(int8_t v1) {
+ // CHECK: test_vmovq_n_s8
+ return vmovq_n_s8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+int16x8_t test_vmovq_n_s16(int16_t v1) {
+ // CHECK: test_vmovq_n_s16
+ return vmovq_n_s16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+int32x4_t test_vmovq_n_s32(int32_t v1) {
+ // CHECK: test_vmovq_n_s32
+ return vmovq_n_s32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{w[0-9]+}}
+}
+
+int64x2_t test_vmovq_n_s64(int64_t v1) {
+ // CHECK: test_vmovq_n_s64
+ return vmovq_n_s64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
+uint8x8_t test_vmov_n_u8(uint8_t v1) {
+ // CHECK: test_vmov_n_u8
+ return vmov_n_u8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+uint16x4_t test_vmov_n_u16(uint16_t v1) {
+ // CHECK: test_vmov_n_u16
+ return vmov_n_u16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+uint32x2_t test_vmov_n_u32(uint32_t v1) {
+ // CHECK: test_vmov_n_u32
+ return vmov_n_u32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{w[0-9]+}}
+}
+
+uint64x1_t test_vmov_n_u64(uint64_t v1) {
+ // CHECK: test_vmov_n_u64
+ return vmov_n_u64(v1);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+uint8x16_t test_vmovq_n_u8(uint8_t v1) {
+ // CHECK: test_vmovq_n_u8
+ return vmovq_n_u8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+uint16x8_t test_vmovq_n_u16(uint16_t v1) {
+ // CHECK: test_vmovq_n_u16
+ return vmovq_n_u16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+uint32x4_t test_vmovq_n_u32(uint32_t v1) {
+ // CHECK: test_vmovq_n_u32
+ return vmovq_n_u32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{w[0-9]+}}
+}
+
+uint64x2_t test_vmovq_n_u64(uint64_t v1) {
+ // CHECK: test_vmovq_n_u64
+ return vmovq_n_u64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
+poly8x8_t test_vmov_n_p8(poly8_t v1) {
+ // CHECK: test_vmov_n_p8
+ return vmov_n_p8(v1);
+ // CHECK: dup {{v[0-9]+}}.8b, {{w[0-9]+}}
+}
+
+poly16x4_t test_vmov_n_p16(poly16_t v1) {
+ // CHECK: test_vmov_n_p16
+ return vmov_n_p16(v1);
+ // CHECK: dup {{v[0-9]+}}.4h, {{w[0-9]+}}
+}
+
+poly8x16_t test_vmovq_n_p8(poly8_t v1) {
+ // CHECK: test_vmovq_n_p8
+ return vmovq_n_p8(v1);
+ // CHECK: dup {{v[0-9]+}}.16b, {{w[0-9]+}}
+}
+
+poly16x8_t test_vmovq_n_p16(poly16_t v1) {
+ // CHECK: test_vmovq_n_p16
+ return vmovq_n_p16(v1);
+ // CHECK: dup {{v[0-9]+}}.8h, {{w[0-9]+}}
+}
+
+float32x2_t test_vmov_n_f32(float32_t v1) {
+ // CHECK: test_vmov_n_f32
+ return vmov_n_f32(v1);
+ // CHECK: dup {{v[0-9]+}}.2s, {{v[0-9]+}}.s[0]
+}
+
+float64x1_t test_vmov_n_f64(float64_t v1) {
+ // CHECK: test_vmov_n_f64
+ return vmov_n_f64(v1);
+ // CHECK: ret
+}
+
+float32x4_t test_vmovq_n_f32(float32_t v1) {
+ // CHECK: test_vmovq_n_f32
+ return vmovq_n_f32(v1);
+ // CHECK: dup {{v[0-9]+}}.4s, {{v[0-9]+}}.s[0]
+}
+
+float64x2_t test_vmovq_n_f64(float64_t v1) {
+ // CHECK: test_vmovq_n_f64
+ return vmovq_n_f64(v1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vcopy_lane_s64
+int64x1_t test_vcopy_lane_s64(int64x1_t a, int64x1_t c) {
+ return vcopy_lane_s64(a, 0, c, 0);
+// CHECK: fmov {{d[0-9]+}}, {{d[0-9]+}}
+// CHECK-NOT: dup {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vcopy_lane_u64
+uint64x1_t test_vcopy_lane_u64(uint64x1_t a, uint64x1_t c) {
+ return vcopy_lane_u64(a, 0, c, 0);
+// CHECK: fmov {{d[0-9]+}}, {{d[0-9]+}}
+// CHECK-NOT: dup {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vcopy_lane_f64
+float64x1_t test_vcopy_lane_f64(float64x1_t a, float64x1_t c) {
+ return vcopy_lane_f64(a, 0, c, 0);
+// CHECK: fmov {{d[0-9]+}}, {{d[0-9]+}}
+// CHECK-NOT: dup {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vcopy_laneq_s64
+int64x1_t test_vcopy_laneq_s64(int64x1_t a, int64x2_t c) {
+ return vcopy_laneq_s64(a, 0, c, 1);
+// CHECK: dup {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vcopy_laneq_u64
+uint64x1_t test_vcopy_laneq_u64(uint64x1_t a, uint64x2_t c) {
+ return vcopy_laneq_u64(a, 0, c, 1);
+// CHECK: dup {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vcopy_laneq_f64
+float64x1_t test_vcopy_laneq_f64(float64x1_t a, float64x2_t c) {
+ return vcopy_laneq_f64(a, 0, c, 1);
+// CHECK: dup {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vcopy_laneq_p64
+poly64x1_t test_vcopy_laneq_p64(poly64x1_t a, poly64x2_t c) {
+ return vcopy_laneq_p64(a, 0, c, 1);
+// CHECK: dup {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vcopyq_laneq_f64
+float64x2_t test_vcopyq_laneq_f64(float64x2_t a, float64x2_t c) {
+// CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[1]
+ return vcopyq_laneq_f64(a, 1, c, 1);
+}
+
+// CHECK: test_vget_lane_f16
+int test_vget_lane_f16(float16x4_t v1) {
+ float16_t a = vget_lane_f16(v1, 3);
+ return (int)a;
+// CHECK: dup {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vgetq_lane_f16
+int test_vgetq_lane_f16(float16x8_t v1) {
+ float16_t a = vgetq_lane_f16(v1, 7);
+ return (int)a;
+// CHECK: dup {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+// CHECK: test_vget_lane_f16_2
+float test_vget_lane_f16_2(float16x4_t v1) {
+ float16_t a = vget_lane_f16(v1, 3);
+ return (float)a;
+// CHECK: dup {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vgetq_lane_f16_2
+float test_vgetq_lane_f16_2(float16x8_t v1) {
+ float16_t a = vgetq_lane_f16(v1, 7);
+ return (float)a;
+// CHECK: dup {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+// CHECK: test_vset_lane_f16
+float16x4_t test_vset_lane_f16(float16x4_t v1) {
+ float16_t a;
+ return vset_lane_f16(a, v1, 3);
+// CHECK: fmov {{s[0-9]+}}, wzr
+// CHECK-NEXT: ins {{v[0-9]+}}.h[3], {{v[0-9]+}}.h[0]
+}
+
+// CHECK: test_vsetq_lane_f16
+float16x8_t test_vsetq_lane_f16(float16x8_t v1) {
+ float16_t a;
+ return vsetq_lane_f16(a, v1, 7);
+// CHECK: fmov {{s[0-9]+}}, wzr
+// CHECK-NEXT: ins {{v[0-9]+}}.h[7], {{v[0-9]+}}.h[0]
+}
+
+// CHECK: test_vset_lane_f16_2
+float16x4_t test_vset_lane_f16_2(float16x4_t v1) {
+ float16_t a = vget_lane_f16(v1, 0);
+ return vset_lane_f16(a, v1, 3);
+// CHECK: ins {{v[0-9]+}}.h[3], {{v[0-9]+}}.h[0]
+}
+
+// CHECK: test_vsetq_lane_f16_2
+float16x8_t test_vsetq_lane_f16_2(float16x8_t v1) {
+ float16_t a = vgetq_lane_f16(v1, 0);
+ return vsetq_lane_f16(a, v1, 7);
+// CHECK: ins {{v[0-9]+}}.h[7], {{v[0-9]+}}.h[0]
+}
+
+
+// CHECK: test_vsetq_lane_f16_3
+float16x8_t test_vsetq_lane_f16_3(float16x8_t v1, float b, float c) {
+ float16_t a = (float16_t)b;
+ return vsetq_lane_f16(a, v1, 7);
+// CHECK: ins {{v[0-9]+}}.h[7], {{w[0-9]+}}
+}
+
+// CHECK: test_vsetq_lane_f16_4
+float16x8_t test_vsetq_lane_f16_4(float16x8_t v1, float b, float c) {
+ float16_t a = (float16_t)b + 1.0;
+ return vsetq_lane_f16(a, v1, 7);
+// CHECK: ins {{v[0-9]+}}.h[7], {{w[0-9]+}}
+}
+
diff --git a/test/CodeGen/aarch64-neon-crypto.c b/test/CodeGen/aarch64-neon-crypto.c
new file mode 100644
index 000000000000..240f3794b965
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-crypto.c
@@ -0,0 +1,94 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -target-feature +crypto -S -O3 -o - %s | FileCheck %s
+// RUN: not %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -S -O3 -o - %s 2>&1 | FileCheck --check-prefix=CHECK-NO-CRYPTO %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+uint8x16_t test_vaeseq_u8(uint8x16_t data, uint8x16_t key) {
+ // CHECK: test_vaeseq_u8
+ // CHECK-NO-CRYPTO: warning: implicit declaration of function 'vaeseq_u8' is invalid in C99
+ return vaeseq_u8(data, key);
+ // CHECK: aese {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vaesdq_u8(uint8x16_t data, uint8x16_t key) {
+ // CHECK: test_vaesdq_u8
+ return vaesdq_u8(data, key);
+ // CHECK: aesd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vaesmcq_u8(uint8x16_t data) {
+ // CHECK: test_vaesmcq_u8
+ return vaesmcq_u8(data);
+ // CHECK: aesmc {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vaesimcq_u8(uint8x16_t data) {
+ // CHECK: test_vaesimcq_u8
+ return vaesimcq_u8(data);
+ // CHECK: aesimc {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint32_t test_vsha1h_u32(uint32_t hash_e) {
+ // CHECK: test_vsha1h_u32
+ return vsha1h_u32(hash_e);
+ // CHECK: sha1h {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+uint32x4_t test_vsha1su1q_u32(uint32x4_t tw0_3, uint32x4_t w12_15) {
+ // CHECK: test_vsha1su1q_u32
+ return vsha1su1q_u32(tw0_3, w12_15);
+ // CHECK: sha1su1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha256su0q_u32(uint32x4_t w0_3, uint32x4_t w4_7) {
+ // CHECK: test_vsha256su0q_u32
+ return vsha256su0q_u32(w0_3, w4_7);
+ // CHECK: sha256su0 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha1cq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
+ // CHECK: test_vsha1cq_u32
+ return vsha1cq_u32(hash_abcd, hash_e, wk);
+ // CHECK: sha1c {{q[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha1pq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
+ // CHECK: test_vsha1pq_u32
+ return vsha1pq_u32(hash_abcd, hash_e, wk);
+ // CHECK: sha1p {{q[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha1mq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
+ // CHECK: test_vsha1mq_u32
+ return vsha1mq_u32(hash_abcd, hash_e, wk);
+ // CHECK: sha1m {{q[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha1su0q_u32(uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11) {
+ // CHECK: test_vsha1su0q_u32
+ return vsha1su0q_u32(w0_3, w4_7, w8_11);
+ // CHECK: sha1su0 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha256hq_u32(uint32x4_t hash_abcd, uint32x4_t hash_efgh, uint32x4_t wk) {
+ // CHECK: test_vsha256hq_u32
+ return vsha256hq_u32(hash_abcd, hash_efgh, wk);
+ // CHECK: sha256h {{q[0-9]+}}, {{q[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha256h2q_u32(uint32x4_t hash_efgh, uint32x4_t hash_abcd, uint32x4_t wk) {
+ // CHECK: test_vsha256h2q_u32
+ return vsha256h2q_u32(hash_efgh, hash_abcd, wk);
+ // CHECK: sha256h2 {{q[0-9]+}}, {{q[0-9]+}}, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vsha256su1q_u32(uint32x4_t tw0_3, uint32x4_t w8_11, uint32x4_t w12_15) {
+ // CHECK: test_vsha256su1q_u32
+ return vsha256su1q_u32(tw0_3, w8_11, w12_15);
+ // CHECK: sha256su1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
diff --git a/test/CodeGen/aarch64-neon-extract.c b/test/CodeGen/aarch64-neon-extract.c
new file mode 100644
index 000000000000..faf35afad6f7
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-extract.c
@@ -0,0 +1,148 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x8_t test_vext_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vext_s8
+ return vext_s8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x2
+}
+
+int16x4_t test_vext_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vext_s16
+ return vext_s16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x6
+}
+
+int32x2_t test_vext_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vext_s32
+ return vext_s32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x4
+}
+
+int64x1_t test_vext_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vext_s64
+ return vext_s64(a, b, 0);
+}
+
+int8x16_t test_vextq_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vextq_s8
+ return vextq_s8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x2
+}
+
+int16x8_t test_vextq_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vextq_s16
+ return vextq_s16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x6
+}
+
+int32x4_t test_vextq_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vextq_s32
+ return vextq_s32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x4
+}
+
+int64x2_t test_vextq_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vextq_s64
+ return vextq_s64(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x8
+}
+
+uint8x8_t test_vext_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vext_u8
+ return vext_u8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x2
+}
+
+uint16x4_t test_vext_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vext_u16
+ return vext_u16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x6
+}
+
+uint32x2_t test_vext_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vext_u32
+ return vext_u32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x4
+}
+
+uint64x1_t test_vext_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vext_u64
+ return vext_u64(a, b, 0);
+}
+
+uint8x16_t test_vextq_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vextq_u8
+ return vextq_u8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x2
+}
+
+uint16x8_t test_vextq_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vextq_u16
+ return vextq_u16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x6
+}
+
+uint32x4_t test_vextq_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vextq_u32
+ return vextq_u32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x4
+}
+
+uint64x2_t test_vextq_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vextq_u64
+ return vextq_u64(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x8
+}
+
+float32x2_t test_vext_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vext_f32
+ return vext_f32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x4
+}
+
+float64x1_t test_vext_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vext_f64
+ return vext_f64(a, b, 0);
+}
+
+float32x4_t test_vextq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vextq_f32
+ return vextq_f32(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x4
+}
+
+float64x2_t test_vextq_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vextq_f64
+ return vextq_f64(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x8
+}
+
+poly8x8_t test_vext_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vext_p8
+ return vext_p8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x2
+}
+
+poly16x4_t test_vext_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vext_p16
+ return vext_p16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x6
+}
+
+poly8x16_t test_vextq_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vextq_p8
+ return vextq_p8(a, b, 2);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x2
+}
+
+poly16x8_t test_vextq_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vextq_p16
+ return vextq_p16(a, b, 3);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x6
+}
diff --git a/test/CodeGen/aarch64-neon-fcvt-intrinsics.c b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
new file mode 100644
index 000000000000..98f1389be4ea
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
@@ -0,0 +1,133 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+float32_t test_vcvtxd_f32_f64(float64_t a) {
+// CHECK: test_vcvtxd_f32_f64
+// CHECK: fcvtxn {{s[0-9]+}}, {{d[0-9]+}}
+ return (float32_t)vcvtxd_f32_f64(a);
+}
+
+int32_t test_vcvtas_s32_f32(float32_t a) {
+// CHECK: test_vcvtas_s32_f32
+// CHECK: fcvtas {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vcvtas_s32_f32(a);
+}
+
+int64_t test_test_vcvtad_s64_f64(float64_t a) {
+// CHECK: test_test_vcvtad_s64_f64
+// CHECK: fcvtas {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcvtad_s64_f64(a);
+}
+
+uint32_t test_vcvtas_u32_f32(float32_t a) {
+// CHECK: test_vcvtas_u32_f32
+// CHECK: fcvtau {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcvtas_u32_f32(a);
+}
+
+uint64_t test_vcvtad_u64_f64(float64_t a) {
+// CHECK: test_vcvtad_u64_f64
+// CHECK: fcvtau {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcvtad_u64_f64(a);
+}
+
+int32_t test_vcvtms_s32_f32(float32_t a) {
+// CHECK: test_vcvtms_s32_f32
+// CHECK: fcvtms {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vcvtms_s32_f32(a);
+}
+
+int64_t test_vcvtmd_s64_f64(float64_t a) {
+// CHECK: test_vcvtmd_s64_f64
+// CHECK: fcvtms {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcvtmd_s64_f64(a);
+}
+
+uint32_t test_vcvtms_u32_f32(float32_t a) {
+// CHECK: test_vcvtms_u32_f32
+// CHECK: fcvtmu {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcvtms_u32_f32(a);
+}
+
+uint64_t test_vcvtmd_u64_f64(float64_t a) {
+// CHECK: test_vcvtmd_u64_f64
+// CHECK: fcvtmu {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcvtmd_u64_f64(a);
+}
+
+int32_t test_vcvtns_s32_f32(float32_t a) {
+// CHECK: test_vcvtns_s32_f32
+// CHECK: fcvtns {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vcvtns_s32_f32(a);
+}
+
+int64_t test_vcvtnd_s64_f64(float64_t a) {
+// CHECK: test_vcvtnd_s64_f64
+// CHECK: fcvtns {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcvtnd_s64_f64(a);
+}
+
+uint32_t test_vcvtns_u32_f32(float32_t a) {
+// CHECK: test_vcvtns_u32_f32
+// CHECK: fcvtnu {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcvtns_u32_f32(a);
+}
+
+uint64_t test_vcvtnd_u64_f64(float64_t a) {
+// CHECK: test_vcvtnd_u64_f64
+// CHECK: fcvtnu {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcvtnd_u64_f64(a);
+}
+
+int32_t test_vcvtps_s32_f32(float32_t a) {
+// CHECK: test_vcvtps_s32_f32
+// CHECK: fcvtps {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vcvtps_s32_f32(a);
+}
+
+int64_t test_vcvtpd_s64_f64(float64_t a) {
+// CHECK: test_vcvtpd_s64_f64
+// CHECK: fcvtps {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcvtpd_s64_f64(a);
+}
+
+uint32_t test_vcvtps_u32_f32(float32_t a) {
+// CHECK: test_vcvtps_u32_f32
+// CHECK: fcvtpu {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcvtps_u32_f32(a);
+}
+
+uint64_t test_vcvtpd_u64_f64(float64_t a) {
+// CHECK: test_vcvtpd_u64_f64
+// CHECK: fcvtpu {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcvtpd_u64_f64(a);
+}
+
+int32_t test_vcvts_s32_f32(float32_t a) {
+// CHECK: test_vcvts_s32_f32
+// CHECK: fcvtzs {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vcvts_s32_f32(a);
+}
+
+int64_t test_vcvtd_s64_f64(float64_t a) {
+// CHECK: test_vcvtd_s64_f64
+// CHECK: fcvtzs {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcvtd_s64_f64(a);
+}
+
+uint32_t test_vcvts_u32_f32(float32_t a) {
+// CHECK: test_vcvts_u32_f32
+// CHECK: fcvtzu {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcvts_u32_f32(a);
+}
+
+uint64_t test_vcvtd_u64_f64(float64_t a) {
+// CHECK: test_vcvtd_u64_f64
+// CHECK: fcvtzu {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcvtd_u64_f64(a);
+}
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
new file mode 100644
index 000000000000..6e9b7f10b362
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-intrinsics.c
@@ -0,0 +1,11725 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x8_t test_vadd_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vadd_s8
+ return vadd_s8(v1, v2);
+ // CHECK: add {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vadd_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vadd_s16
+ return vadd_s16(v1, v2);
+ // CHECK: add {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vadd_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vadd_s32
+ return vadd_s32(v1, v2);
+ // CHECK: add {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vadd_s64(int64x1_t v1, int64x1_t v2) {
+ // CHECK: test_vadd_s64
+ return vadd_s64(v1, v2);
+ // CHECK: add {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+float32x2_t test_vadd_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vadd_f32
+ return vadd_f32(v1, v2);
+ // CHECK: fadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vadd_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vadd_u8
+ return vadd_u8(v1, v2);
+ // CHECK: add {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vadd_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vadd_u16
+ return vadd_u16(v1, v2);
+ // CHECK: add {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vadd_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vadd_u32
+ return vadd_u32(v1, v2);
+ // CHECK: add {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vadd_u64(uint64x1_t v1, uint64x1_t v2) {
+ // CHECK: test_vadd_u64
+ return vadd_u64(v1, v2);
+ // CHECK: add {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vaddq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vaddq_s8
+ return vaddq_s8(v1, v2);
+ // CHECK: add {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vaddq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vaddq_s16
+ return vaddq_s16(v1, v2);
+ // CHECK: add {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vaddq_s32(int32x4_t v1,int32x4_t v2) {
+ // CHECK: test_vaddq_s32
+ return vaddq_s32(v1, v2);
+ // CHECK: add {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vaddq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vaddq_s64
+ return vaddq_s64(v1, v2);
+ // CHECK: add {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x4_t test_vaddq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vaddq_f32
+ return vaddq_f32(v1, v2);
+ // CHECK: fadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vaddq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vaddq_f64
+ return vaddq_f64(v1, v2);
+ // CHECK: fadd {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vaddq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vaddq_u8
+ return vaddq_u8(v1, v2);
+ // CHECK: add {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vaddq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vaddq_u16
+ return vaddq_u16(v1, v2);
+ // CHECK: add {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vaddq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: vaddq_u32
+ return vaddq_u32(v1, v2);
+ // CHECK: add {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vaddq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vaddq_u64
+ return vaddq_u64(v1, v2);
+ // CHECK: add {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vsub_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vsub_s8
+ return vsub_s8(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+int16x4_t test_vsub_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vsub_s16
+ return vsub_s16(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int32x2_t test_vsub_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vsub_s32
+ return vsub_s32(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vsub_s64(int64x1_t v1, int64x1_t v2) {
+ // CHECK: test_vsub_s64
+ return vsub_s64(v1, v2);
+ // CHECK: sub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+float32x2_t test_vsub_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vsub_f32
+ return vsub_f32(v1, v2);
+ // CHECK: fsub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vsub_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vsub_u8
+ return vsub_u8(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vsub_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vsub_u16
+ return vsub_u16(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vsub_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vsub_u32
+ return vsub_u32(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vsub_u64(uint64x1_t v1, uint64x1_t v2) {
+ // CHECK: test_vsub_u64
+ return vsub_u64(v1, v2);
+ // CHECK: sub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vsubq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vsubq_s8
+ return vsubq_s8(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vsubq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vsubq_s16
+ return vsubq_s16(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vsubq_s32(int32x4_t v1,int32x4_t v2) {
+ // CHECK: test_vsubq_s32
+ return vsubq_s32(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vsubq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vsubq_s64
+ return vsubq_s64(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x4_t test_vsubq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vsubq_f32
+ return vsubq_f32(v1, v2);
+ // CHECK: fsub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vsubq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vsubq_f64
+ return vsubq_f64(v1, v2);
+ // CHECK: fsub {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vsubq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vsubq_u8
+ return vsubq_u8(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vsubq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vsubq_u16
+ return vsubq_u16(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vsubq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: vsubq_u32
+ return vsubq_u32(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vsubq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vsubq_u64
+ return vsubq_u64(v1, v2);
+ // CHECK: sub {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vmul_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vmul_s8
+ return vmul_s8(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vmul_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vmul_s16
+ return vmul_s16(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vmul_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vmul_s32
+ return vmul_s32(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vmul_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vmul_f32
+ return vmul_f32(v1, v2);
+ // CHECK: fmul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+
+uint8x8_t test_vmul_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vmul_u8
+ return vmul_u8(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vmul_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vmul_u16
+ return vmul_u16(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vmul_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vmul_u32
+ return vmul_u32(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vmulq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vmulq_s8
+ return vmulq_s8(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vmulq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vmulq_s16
+ return vmulq_s16(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vmulq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vmulq_s32
+ return vmulq_s32(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vmulq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vmulq_u8
+ return vmulq_u8(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vmulq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vmulq_u16
+ return vmulq_u16(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vmulq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vmulq_u32
+ return vmulq_u32(v1, v2);
+ // CHECK: mul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vmulq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vmulq_f32
+ return vmulq_f32(v1, v2);
+ // CHECK: fmul {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmulq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vmulq_f64
+ return vmulq_f64(v1, v2);
+ // CHECK: fmul {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+poly8x8_t test_vmul_p8(poly8x8_t v1, poly8x8_t v2) {
+ // test_vmul_p8
+ return vmul_p8(v1, v2);
+ // pmul {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vmulq_p8(poly8x16_t v1, poly8x16_t v2) {
+ // test_vmulq_p8
+ return vmulq_p8(v1, v2);
+ // pmul {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+
+int8x8_t test_vmla_s8(int8x8_t v1, int8x8_t v2, int8x8_t v3) {
+ // CHECK: test_vmla_s8
+ return vmla_s8(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vmla_s16(int16x4_t v1, int16x4_t v2, int16x4_t v3) {
+ // CHECK: test_vmla_s16
+ return vmla_s16(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vmla_s32(int32x2_t v1, int32x2_t v2, int32x2_t v3) {
+ // CHECK: test_vmla_s32
+ return vmla_s32(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vmla_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
+ // CHECK: test_vmla_f32
+ return vmla_f32(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vmla_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
+ // CHECK: test_vmla_u8
+ return vmla_u8(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vmla_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
+ // CHECK: test_vmla_u16
+ return vmla_u16(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vmla_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
+ // CHECK: test_vmla_u32
+ return vmla_u32(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vmlaq_s8(int8x16_t v1, int8x16_t v2, int8x16_t v3) {
+ // CHECK: test_vmlaq_s8
+ return vmlaq_s8(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vmlaq_s16(int16x8_t v1, int16x8_t v2, int16x8_t v3) {
+ // CHECK: test_vmlaq_s16
+ return vmlaq_s16(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vmlaq_s32(int32x4_t v1, int32x4_t v2, int32x4_t v3) {
+ // CHECK: test_vmlaq_s32
+ return vmlaq_s32(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vmlaq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
+ // CHECK: test_vmlaq_f32
+ return vmlaq_f32(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vmlaq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
+ // CHECK: test_vmlaq_u8
+ return vmlaq_u8(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vmlaq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
+ // CHECK: test_vmlaq_u16
+ return vmlaq_u16(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vmlaq_u32(uint32x4_t v1, uint32x4_t v2, uint32x4_t v3) {
+ // CHECK: test_vmlaq_u32
+ return vmlaq_u32(v1, v2, v3);
+ // CHECK: mla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmlaq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
+ // CHECK: test_vmlaq_f64
+ return vmlaq_f64(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vmls_s8(int8x8_t v1, int8x8_t v2, int8x8_t v3) {
+ // CHECK: test_vmls_s8
+ return vmls_s8(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vmls_s16(int16x4_t v1, int16x4_t v2, int16x4_t v3) {
+ // CHECK: test_vmls_s16
+ return vmls_s16(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vmls_s32(int32x2_t v1, int32x2_t v2, int32x2_t v3) {
+ // CHECK: test_vmls_s32
+ return vmls_s32(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vmls_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
+ // CHECK: test_vmls_f32
+ return vmls_f32(v1, v2, v3);
+ // CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vmls_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
+ // CHECK: test_vmls_u8
+ return vmls_u8(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vmls_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
+ // CHECK: test_vmls_u16
+ return vmls_u16(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vmls_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
+ // CHECK: test_vmls_u32
+ return vmls_u32(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+int8x16_t test_vmlsq_s8(int8x16_t v1, int8x16_t v2, int8x16_t v3) {
+ // CHECK: test_vmlsq_s8
+ return vmlsq_s8(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vmlsq_s16(int16x8_t v1, int16x8_t v2, int16x8_t v3) {
+ // CHECK: test_vmlsq_s16
+ return vmlsq_s16(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vmlsq_s32(int32x4_t v1, int32x4_t v2, int32x4_t v3) {
+ // CHECK: test_vmlsq_s32
+ return vmlsq_s32(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vmlsq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
+ // CHECK: test_vmlsq_f32
+ return vmlsq_f32(v1, v2, v3);
+ // CHECK: fmls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+uint8x16_t test_vmlsq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
+ // CHECK: test_vmlsq_u8
+ return vmlsq_u8(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vmlsq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
+ // CHECK: test_vmlsq_u16
+ return vmlsq_u16(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vmlsq_u32(uint32x4_t v1, uint32x4_t v2, uint32x4_t v3) {
+ // CHECK: test_vmlsq_u32
+ return vmlsq_u32(v1, v2, v3);
+ // CHECK: mls {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmlsq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
+ // CHECK: test_vmlsq_f64
+ return vmlsq_f64(v1, v2, v3);
+ // CHECK: fmls {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+float32x2_t test_vfma_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
+ // CHECK: test_vfma_f32
+ return vfma_f32(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vfmaq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
+ // CHECK: test_vfmaq_f32
+ return vfmaq_f32(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vfmaq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
+ // CHECK: test_vfmaq_f64
+ return vfmaq_f64(v1, v2, v3);
+ // CHECK: fmla {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+float32x2_t test_vfms_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
+ // CHECK: test_vfms_f32
+ return vfms_f32(v1, v2, v3);
+ // CHECK: fmls v0.2s, v1.2s, v2.2s
+}
+
+float32x4_t test_vfmsq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
+ // CHECK: test_vfmsq_f32
+ return vfmsq_f32(v1, v2, v3);
+ // CHECK: fmls v0.4s, v1.4s, v2.4s
+}
+
+float64x2_t test_vfmsq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
+ // CHECK: vfmsq_f64
+ return vfmsq_f64(v1, v2, v3);
+ // CHECK: fmls v0.2d, v1.2d, v2.2d
+}
+
+float64x2_t test_vdivq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vdivq_f64
+ return vdivq_f64(v1, v2);
+ // CHECK: fdiv {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x4_t test_vdivq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vdivq_f32
+ return vdivq_f32(v1, v2);
+ // CHECK: fdiv {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x2_t test_vdiv_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vdiv_f32
+ return vdiv_f32(v1, v2);
+ // CHECK: fdiv {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x8_t test_vaba_s8(int8x8_t v1, int8x8_t v2, int8x8_t v3) {
+ // CHECK: test_vaba_s8
+ return vaba_s8(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vaba_s16(int16x4_t v1, int16x4_t v2, int16x4_t v3) {
+ // CHECK: test_vaba_s16
+ return vaba_s16(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vaba_s32(int32x2_t v1, int32x2_t v2, int32x2_t v3) {
+ // CHECK: test_vaba_s32
+ return vaba_s32(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vaba_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
+ // CHECK: test_vaba_u8
+ return vaba_u8(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vaba_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
+ // CHECK: test_vaba_u16
+ return vaba_u16(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vaba_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
+ // CHECK: test_vaba_u32
+ return vaba_u32(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vabaq_s8(int8x16_t v1, int8x16_t v2, int8x16_t v3) {
+ // CHECK: test_vabaq_s8
+ return vabaq_s8(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vabaq_s16(int16x8_t v1, int16x8_t v2, int16x8_t v3) {
+ // CHECK: test_vabaq_s16
+ return vabaq_s16(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vabaq_s32(int32x4_t v1, int32x4_t v2, int32x4_t v3) {
+ // CHECK: test_vabaq_s32
+ return vabaq_s32(v1, v2, v3);
+ // CHECK: saba {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vabaq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
+ // CHECK: test_vabaq_u8
+ return vabaq_u8(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vabaq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
+ // CHECK: test_vabaq_u16
+ return vabaq_u16(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vabaq_u32(uint32x4_t v1, uint32x4_t v2, uint32x4_t v3) {
+ // CHECK: test_vabaq_u32
+ return vabaq_u32(v1, v2, v3);
+ // CHECK: uaba {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int8x8_t test_vabd_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vabd_s8
+ return vabd_s8(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vabd_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vabd_s16
+ return vabd_s16(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vabd_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vabd_s32
+ return vabd_s32(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vabd_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vabd_u8
+ return vabd_u8(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vabd_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vabd_u16
+ return vabd_u16(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vabd_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vabd_u32
+ return vabd_u32(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vabd_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vabd_f32
+ return vabd_f32(v1, v2);
+ // CHECK: fabd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vabdq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vabdq_s8
+ return vabdq_s8(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vabdq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vabdq_s16
+ return vabdq_s16(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vabdq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vabdq_s32
+ return vabdq_s32(v1, v2);
+ // CHECK: sabd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vabdq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vabdq_u8
+ return vabdq_u8(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vabdq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vabdq_u16
+ return vabdq_u16(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vabdq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vabdq_u32
+ return vabdq_u32(v1, v2);
+ // CHECK: uabd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vabdq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vabdq_f32
+ return vabdq_f32(v1, v2);
+ // CHECK: fabd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vabdq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vabdq_f64
+ return vabdq_f64(v1, v2);
+ // CHECK: fabd {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vbsl_s8(uint8x8_t v1, int8x8_t v2, int8x8_t v3) {
+ // CHECK: test_vbsl_s8
+ return vbsl_s8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vbsl_s16(uint16x4_t v1, int16x4_t v2, int16x4_t v3) {
+ // CHECK: test_vbsl_s16
+ return vbsl_s16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int32x2_t test_vbsl_s32(uint32x2_t v1, int32x2_t v2, int32x2_t v3) {
+ // CHECK: test_vbsl_s32
+ return vbsl_s32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint64x1_t test_vbsl_s64(uint64x1_t v1, uint64x1_t v2, uint64x1_t v3) {
+ // CHECK: test_vbsl_s64
+ return vbsl_s64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vbsl_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
+ // CHECK: test_vbsl_u8
+ return vbsl_u8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vbsl_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
+ // CHECK: test_vbsl_u16
+ return vbsl_u16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint32x2_t test_vbsl_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
+ // CHECK: test_vbsl_u32
+ return vbsl_u32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint64x1_t test_vbsl_u64(uint64x1_t v1, uint64x1_t v2, uint64x1_t v3) {
+ // CHECK: test_vbsl_u64
+ return vbsl_u64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+float32x2_t test_vbsl_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
+ // CHECK: test_vbsl_f32
+ return vbsl_f32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+float64x1_t test_vbsl_f64(uint64x1_t v1, float64x1_t v2, float64x1_t v3) {
+ // CHECK: test_vbsl_f64
+ return vbsl_f64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vbsl_p8(uint8x8_t v1, poly8x8_t v2, poly8x8_t v3) {
+ // CHECK: test_vbsl_p8
+ return vbsl_p8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly16x4_t test_vbsl_p16(uint16x4_t v1, poly16x4_t v2, poly16x4_t v3) {
+ // CHECK: test_vbsl_p16
+ return vbsl_p16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vbslq_s8(uint8x16_t v1, int8x16_t v2, int8x16_t v3) {
+ // CHECK: test_vbslq_s8
+ return vbslq_s8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vbslq_s16(uint16x8_t v1, int16x8_t v2, int16x8_t v3) {
+ // CHECK: test_vbslq_s16
+ return vbslq_s16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int32x4_t test_vbslq_s32(uint32x4_t v1, int32x4_t v2, int32x4_t v3) {
+ // CHECK: test_vbslq_s32
+ return vbslq_s32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int64x2_t test_vbslq_s64(uint64x2_t v1, int64x2_t v2, int64x2_t v3) {
+ // CHECK: test_vbslq_s64
+ return vbslq_s64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vbslq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
+ // CHECK: test_vbslq_u8
+ return vbslq_u8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vbslq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
+ // CHECK: test_vbslq_u16
+ return vbslq_u16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int32x4_t test_vbslq_u32(uint32x4_t v1, int32x4_t v2, int32x4_t v3) {
+ // CHECK: test_vbslq_u32
+ return vbslq_s32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint64x2_t test_vbslq_u64(uint64x2_t v1, uint64x2_t v2, uint64x2_t v3) {
+ // CHECK: test_vbslq_u64
+ return vbslq_u64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+float32x4_t test_vbslq_f32(uint32x4_t v1, float32x4_t v2, float32x4_t v3) {
+ // CHECK: test_vbslq_f32
+ return vbslq_f32(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vbslq_p8(uint8x16_t v1, poly8x16_t v2, poly8x16_t v3) {
+ // CHECK: test_vbslq_p8
+ return vbslq_p8(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x8_t test_vbslq_p16(uint16x8_t v1, poly16x8_t v2, poly16x8_t v3) {
+ // CHECK: test_vbslq_p16
+ return vbslq_p16(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+float64x2_t test_vbslq_f64(uint64x2_t v1, float64x2_t v2, float64x2_t v3) {
+ // CHECK: test_vbslq_f64
+ return vbslq_f64(v1, v2, v3);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+float32x2_t test_vrecps_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vrecps_f32
+ return vrecps_f32(v1, v2);
+ // CHECK: frecps {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vrecpsq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vrecpsq_f32
+ return vrecpsq_f32(v1, v2);
+ // CHECK: frecps {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vrecpsq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vrecpsq_f64
+ return vrecpsq_f64(v1, v2);
+ // CHECK: frecps {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x2_t test_vrsqrts_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vrsqrts_f32
+ return vrsqrts_f32(v1, v2);
+ // CHECK: frsqrts {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vrsqrtsq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vrsqrtsq_f32
+ return vrsqrtsq_f32(v1, v2);
+ // CHECK: frsqrts {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vrsqrtsq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vrsqrtsq_f64
+ return vrsqrtsq_f64(v1, v2);
+ // CHECK: frsqrts {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint32x2_t test_vcage_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcage_f32
+ return vcage_f32(v1, v2);
+ // CHECK: facge {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcage_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcage_f64
+ return vcage_f64(a, b);
+ // CHECK: facge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x4_t test_vcageq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcageq_f32
+ return vcageq_f32(v1, v2);
+ // CHECK: facge {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vcageq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcageq_f64
+ return vcageq_f64(v1, v2);
+ // CHECK: facge {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint32x2_t test_vcagt_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcagt_f32
+ return vcagt_f32(v1, v2);
+ // CHECK: facgt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcagt_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcagt_f64
+ return vcagt_f64(a, b);
+ // CHECK: facgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x4_t test_vcagtq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcagtq_f32
+ return vcagtq_f32(v1, v2);
+ // CHECK: facgt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vcagtq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcagtq_f64
+ return vcagtq_f64(v1, v2);
+ // CHECK: facgt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint32x2_t test_vcale_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcale_f32
+ return vcale_f32(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facge {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vcale_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcale_f64
+ return vcale_f64(a, b);
+ // CHECK: facge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x4_t test_vcaleq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcaleq_f32
+ return vcaleq_f32(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facge {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint64x2_t test_vcaleq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcaleq_f64
+ return vcaleq_f64(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facge {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint32x2_t test_vcalt_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcalt_f32
+ return vcalt_f32(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facgt {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vcalt_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcalt_f64
+ return vcalt_f64(a, b);
+ // CHECK: facgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x4_t test_vcaltq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcaltq_f32
+ return vcaltq_f32(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facgt {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint64x2_t test_vcaltq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcaltq_f64
+ return vcaltq_f64(v1, v2);
+ // Using registers other than v0, v1 are possible, but would be odd.
+ // CHECK: facgt {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint8x8_t test_vtst_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vtst_s8
+ return vtst_s8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vtst_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vtst_s16
+ return vtst_s16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vtst_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vtst_s32
+ return vtst_s32(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vtst_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vtst_u8
+ return vtst_u8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vtst_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vtst_u16
+ return vtst_u16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vtst_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vtst_u32
+ return vtst_u32(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x16_t test_vtstq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vtstq_s8
+ return vtstq_s8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vtstq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vtstq_s16
+ return vtstq_s16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vtstq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vtstq_s32
+ return vtstq_s32(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vtstq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vtstq_u8
+ return vtstq_u8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vtstq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vtstq_u16
+ return vtstq_u16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vtstq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vtstq_u32
+ return vtstq_u32(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vtstq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vtstq_s64
+ return vtstq_s64(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vtstq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vtstq_u64
+ return vtstq_u64(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x8_t test_vtst_p8(poly8x8_t v1, poly8x8_t v2) {
+ // CHECK: test_vtst_p8
+ return vtst_p8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vtst_p16(poly16x4_t v1, poly16x4_t v2) {
+ // CHECK: test_vtst_p16
+ return vtst_p16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint8x16_t test_vtstq_p8(poly8x16_t v1, poly8x16_t v2) {
+ // CHECK: test_vtstq_p8
+ return vtstq_p8(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vtstq_p16(poly16x8_t v1, poly16x8_t v2) {
+ // CHECK: test_vtstq_p16
+ return vtstq_p16(v1, v2);
+ // CHECK: cmtst {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+
+uint8x8_t test_vceq_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vceq_s8
+ return vceq_s8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vceq_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vceq_s16
+ return vceq_s16(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vceq_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vceq_s32
+ return vceq_s32(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vceq_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vceq_s64
+ return vceq_s64(a, b);
+ // CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x1_t test_vceq_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vceq_u64
+ return vceq_u64(a, b);
+ // CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x2_t test_vceq_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vceq_f32
+ return vceq_f32(v1, v2);
+ // CHECK: fcmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vceq_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vceq_f64
+ return vceq_f64(a, b);
+ // CHECK: fcmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vceq_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vceq_u8
+ return vceq_u8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vceq_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vceq_u16
+ return vceq_u16(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vceq_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vceq_u32
+ return vceq_u32(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vceq_p8(poly8x8_t v1, poly8x8_t v2) {
+ // CHECK: test_vceq_p8
+ return vceq_p8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vceqq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vceqq_s8
+ return vceqq_s8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vceqq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vceqq_s16
+ return vceqq_s16(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vceqq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vceqq_s32
+ return vceqq_s32(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vceqq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vceqq_f32
+ return vceqq_f32(v1, v2);
+ // CHECK: fcmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vceqq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vceqq_u8
+ return vceqq_u8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vceqq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vceqq_u16
+ return vceqq_u16(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vceqq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vceqq_u32
+ return vceqq_u32(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vceqq_p8(poly8x16_t v1, poly8x16_t v2) {
+ // CHECK: test_vceqq_p8
+ return vceqq_p8(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+
+uint64x2_t test_vceqq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vceqq_s64
+ return vceqq_s64(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vceqq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vceqq_u64
+ return vceqq_u64(v1, v2);
+ // CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vceqq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vceqq_f64
+ return vceqq_f64(v1, v2);
+ // CHECK: fcmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+uint8x8_t test_vcge_s8(int8x8_t v1, int8x8_t v2) {
+// CHECK: test_vcge_s8
+ return vcge_s8(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vcge_s16(int16x4_t v1, int16x4_t v2) {
+// CHECK: test_vcge_s16
+ return vcge_s16(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vcge_s32(int32x2_t v1, int32x2_t v2) {
+// CHECK: test_vcge_s32
+ return vcge_s32(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcge_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vcge_s64
+ return vcge_s64(a, b);
+ // CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x1_t test_vcge_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vcge_u64
+ return vcge_u64(a, b);
+ // CHECK: cmhs {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x2_t test_vcge_f32(float32x2_t v1, float32x2_t v2) {
+// CHECK: test_vcge_f32
+ return vcge_f32(v1, v2);
+// CHECK: fcmge {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcge_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcge_f64
+ return vcge_f64(a, b);
+ // CHECK: fcmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vcge_u8(uint8x8_t v1, uint8x8_t v2) {
+// CHECK: test_vcge_u8
+ return vcge_u8(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vcge_u16(uint16x4_t v1, uint16x4_t v2) {
+// CHECK: test_vcge_u16
+ return vcge_u16(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vcge_u32(uint32x2_t v1, uint32x2_t v2) {
+// CHECK: test_vcge_u32
+ return vcge_u32(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x16_t test_vcgeq_s8(int8x16_t v1, int8x16_t v2) {
+// CHECK: test_vcgeq_s8
+ return vcgeq_s8(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vcgeq_s16(int16x8_t v1, int16x8_t v2) {
+// CHECK: test_vcgeq_s16
+ return vcgeq_s16(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vcgeq_s32(int32x4_t v1, int32x4_t v2) {
+// CHECK: test_vcgeq_s32
+ return vcgeq_s32(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vcgeq_f32(float32x4_t v1, float32x4_t v2) {
+// CHECK: test_vcgeq_f32
+ return vcgeq_f32(v1, v2);
+// CHECK: fcmge {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vcgeq_u8(uint8x16_t v1, uint8x16_t v2) {
+// CHECK: test_vcgeq_u8
+ return vcgeq_u8(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vcgeq_u16(uint16x8_t v1, uint16x8_t v2) {
+// CHECK: test_vcgeq_u16
+ return vcgeq_u16(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vcgeq_u32(uint32x4_t v1, uint32x4_t v2) {
+// CHECK: test_vcgeq_u32
+ return vcgeq_u32(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vcgeq_s64(int64x2_t v1, int64x2_t v2) {
+// CHECK: test_vcgeq_s64
+ return vcgeq_s64(v1, v2);
+// CHECK: cmge {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vcgeq_u64(uint64x2_t v1, uint64x2_t v2) {
+// CHECK: test_vcgeq_u64
+ return vcgeq_u64(v1, v2);
+// CHECK: cmhs {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vcgeq_f64(float64x2_t v1, float64x2_t v2) {
+// CHECK: test_vcgeq_f64
+ return vcgeq_f64(v1, v2);
+// CHECK: fcmge {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+// Notes about vcle:
+// LE condition predicate implemented as GE, so check reversed operands.
+// Using registers other than v0, v1 are possible, but would be odd.
+uint8x8_t test_vcle_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vcle_s8
+ return vcle_s8(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.8b, v1.8b, v0.8b
+}
+
+uint16x4_t test_vcle_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vcle_s16
+ return vcle_s16(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.4h, v1.4h, v0.4h
+}
+
+uint32x2_t test_vcle_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vcle_s32
+ return vcle_s32(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vcle_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vcle_s64
+ return vcle_s64(a, b);
+ // CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x1_t test_vcle_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vcle_u64
+ return vcle_u64(a, b);
+ // CHECK: cmhs {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x2_t test_vcle_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcle_f32
+ return vcle_f32(v1, v2);
+ // CHECK: fcmge {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vcle_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcle_f64
+ return vcle_f64(a, b);
+ // CHECK: fcmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vcle_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vcle_u8
+ return vcle_u8(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.8b, v1.8b, v0.8b
+}
+
+uint16x4_t test_vcle_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vcle_u16
+ return vcle_u16(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.4h, v1.4h, v0.4h
+}
+
+uint32x2_t test_vcle_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vcle_u32
+ return vcle_u32(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint8x16_t test_vcleq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vcleq_s8
+ return vcleq_s8(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.16b, v1.16b, v0.16b
+}
+
+uint16x8_t test_vcleq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vcleq_s16
+ return vcleq_s16(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.8h, v1.8h, v0.8h
+}
+
+uint32x4_t test_vcleq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vcleq_s32
+ return vcleq_s32(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint32x4_t test_vcleq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcleq_f32
+ return vcleq_f32(v1, v2);
+ // CHECK: fcmge {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint8x16_t test_vcleq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vcleq_u8
+ return vcleq_u8(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.16b, v1.16b, v0.16b
+}
+
+uint16x8_t test_vcleq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vcleq_u16
+ return vcleq_u16(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.8h, v1.8h, v0.8h
+}
+
+uint32x4_t test_vcleq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vcleq_u32
+ return vcleq_u32(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint64x2_t test_vcleq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vcleq_s64
+ return vcleq_s64(v1, v2);
+ // CHECK: cmge {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint64x2_t test_vcleq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vcleq_u64
+ return vcleq_u64(v1, v2);
+ // CHECK: cmhs {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint64x2_t test_vcleq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcleq_f64
+ return vcleq_f64(v1, v2);
+ // CHECK: fcmge {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+
+uint8x8_t test_vcgt_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vcgt_s8
+ return vcgt_s8(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vcgt_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vcgt_s16
+ return vcgt_s16(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vcgt_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vcgt_s32
+ return vcgt_s32(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcgt_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vcgt_s64
+ return vcgt_s64(a, b);
+ // CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x1_t test_vcgt_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vcgt_u64
+ return vcgt_u64(a, b);
+ // CHECK: cmhi {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x2_t test_vcgt_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vcgt_f32
+ return vcgt_f32(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vcgt_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vcgt_f64
+ return vcgt_f64(a, b);
+ // CHECK: fcmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vcgt_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vcgt_u8
+ return vcgt_u8(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vcgt_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vcgt_u16
+ return vcgt_u16(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vcgt_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vcgt_u32
+ return vcgt_u32(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x16_t test_vcgtq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vcgtq_s8
+ return vcgtq_s8(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vcgtq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vcgtq_s16
+ return vcgtq_s16(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vcgtq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vcgtq_s32
+ return vcgtq_s32(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint32x4_t test_vcgtq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcgtq_f32
+ return vcgtq_f32(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vcgtq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vcgtq_u8
+ return vcgtq_u8(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vcgtq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vcgtq_u16
+ return vcgtq_u16(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vcgtq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vcgtq_u32
+ return vcgtq_u32(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vcgtq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vcgtq_s64
+ return vcgtq_s64(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vcgtq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vcgtq_u64
+ return vcgtq_u64(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vcgtq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcgtq_f64
+ return vcgtq_f64(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+// Notes about vclt:
+// LT condition predicate implemented as GT, so check reversed operands.
+// Using registers other than v0, v1 are possible, but would be odd.
+
+uint8x8_t test_vclt_s8(int8x8_t v1, int8x8_t v2) {
+ // CHECK: test_vclt_s8
+ return vclt_s8(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.8b, v1.8b, v0.8b
+}
+
+uint16x4_t test_vclt_s16(int16x4_t v1, int16x4_t v2) {
+ // CHECK: test_vclt_s16
+ return vclt_s16(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.4h, v1.4h, v0.4h
+}
+
+uint32x2_t test_vclt_s32(int32x2_t v1, int32x2_t v2) {
+ // CHECK: test_vclt_s32
+ return vclt_s32(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vclt_s64(int64x1_t a, int64x1_t b) {
+ // CHECK: test_vclt_s64
+ return vclt_s64(a, b);
+ // CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x1_t test_vclt_u64(uint64x1_t a, uint64x1_t b) {
+ // CHECK: test_vclt_u64
+ return vclt_u64(a, b);
+ // CHECK: cmhi {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint32x2_t test_vclt_f32(float32x2_t v1, float32x2_t v2) {
+ // CHECK: test_vclt_f32
+ return vclt_f32(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint64x1_t test_vclt_f64(float64x1_t a, float64x1_t b) {
+ // CHECK: test_vclt_f64
+ return vclt_f64(a, b);
+ // CHECK: fcmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vclt_u8(uint8x8_t v1, uint8x8_t v2) {
+ // CHECK: test_vclt_u8
+ return vclt_u8(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.8b, v1.8b, v0.8b
+}
+
+uint16x4_t test_vclt_u16(uint16x4_t v1, uint16x4_t v2) {
+ // CHECK: test_vclt_u16
+ return vclt_u16(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.4h, v1.4h, v0.4h
+}
+
+uint32x2_t test_vclt_u32(uint32x2_t v1, uint32x2_t v2) {
+ // CHECK: test_vclt_u32
+ return vclt_u32(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.2s, v1.2s, v0.2s
+}
+
+uint8x16_t test_vcltq_s8(int8x16_t v1, int8x16_t v2) {
+ // CHECK: test_vcltq_s8
+ return vcltq_s8(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.16b, v1.16b, v0.16b
+}
+
+uint16x8_t test_vcltq_s16(int16x8_t v1, int16x8_t v2) {
+ // CHECK: test_vcltq_s16
+ return vcltq_s16(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.8h, v1.8h, v0.8h
+}
+
+uint32x4_t test_vcltq_s32(int32x4_t v1, int32x4_t v2) {
+ // CHECK: test_vcltq_s32
+ return vcltq_s32(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint32x4_t test_vcltq_f32(float32x4_t v1, float32x4_t v2) {
+ // CHECK: test_vcltq_f32
+ return vcltq_f32(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint8x16_t test_vcltq_u8(uint8x16_t v1, uint8x16_t v2) {
+ // CHECK: test_vcltq_u8
+ return vcltq_u8(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.16b, v1.16b, v0.16b
+}
+
+uint16x8_t test_vcltq_u16(uint16x8_t v1, uint16x8_t v2) {
+ // CHECK: test_vcltq_u16
+ return vcltq_u16(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.8h, v1.8h, v0.8h
+}
+
+uint32x4_t test_vcltq_u32(uint32x4_t v1, uint32x4_t v2) {
+ // CHECK: test_vcltq_u32
+ return vcltq_u32(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.4s, v1.4s, v0.4s
+}
+
+uint64x2_t test_vcltq_s64(int64x2_t v1, int64x2_t v2) {
+ // CHECK: test_vcltq_s64
+ return vcltq_s64(v1, v2);
+ // CHECK: cmgt {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint64x2_t test_vcltq_u64(uint64x2_t v1, uint64x2_t v2) {
+ // CHECK: test_vcltq_u64
+ return vcltq_u64(v1, v2);
+ // CHECK: cmhi {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+uint64x2_t test_vcltq_f64(float64x2_t v1, float64x2_t v2) {
+ // CHECK: test_vcltq_f64
+ return vcltq_f64(v1, v2);
+ // CHECK: fcmgt {{v[0-9]+}}.2d, v1.2d, v0.2d
+}
+
+
+int8x8_t test_vhadd_s8(int8x8_t v1, int8x8_t v2) {
+// CHECK: test_vhadd_s8
+ return vhadd_s8(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vhadd_s16(int16x4_t v1, int16x4_t v2) {
+// CHECK: test_vhadd_s16
+ return vhadd_s16(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vhadd_s32(int32x2_t v1, int32x2_t v2) {
+// CHECK: test_vhadd_s32
+ return vhadd_s32(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vhadd_u8(uint8x8_t v1, uint8x8_t v2) {
+// CHECK: test_vhadd_u8
+ return vhadd_u8(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vhadd_u16(uint16x4_t v1, uint16x4_t v2) {
+// CHECK: test_vhadd_u16
+ return vhadd_u16(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vhadd_u32(uint32x2_t v1, uint32x2_t v2) {
+// CHECK: test_vhadd_u32
+ return vhadd_u32(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vhaddq_s8(int8x16_t v1, int8x16_t v2) {
+// CHECK: test_vhaddq_s8
+ return vhaddq_s8(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vhaddq_s16(int16x8_t v1, int16x8_t v2) {
+// CHECK: test_vhaddq_s16
+ return vhaddq_s16(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vhaddq_s32(int32x4_t v1, int32x4_t v2) {
+// CHECK: test_vhaddq_s32
+ return vhaddq_s32(v1, v2);
+ // CHECK: shadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
+// CHECK: test_vhaddq_u8
+ return vhaddq_u8(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
+// CHECK: test_vhaddq_u16
+ return vhaddq_u16(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
+// CHECK: test_vhaddq_u32
+ return vhaddq_u32(v1, v2);
+ // CHECK: uhadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+
+int8x8_t test_vhsub_s8(int8x8_t v1, int8x8_t v2) {
+// CHECK: test_vhsub_s8
+ return vhsub_s8(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vhsub_s16(int16x4_t v1, int16x4_t v2) {
+// CHECK: test_vhsub_s16
+ return vhsub_s16(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vhsub_s32(int32x2_t v1, int32x2_t v2) {
+// CHECK: test_vhsub_s32
+ return vhsub_s32(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vhsub_u8(uint8x8_t v1, uint8x8_t v2) {
+// CHECK: test_vhsub_u8
+ return vhsub_u8(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vhsub_u16(uint16x4_t v1, uint16x4_t v2) {
+// CHECK: test_vhsub_u16
+ return vhsub_u16(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vhsub_u32(uint32x2_t v1, uint32x2_t v2) {
+// CHECK: test_vhsub_u32
+ return vhsub_u32(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vhsubq_s8(int8x16_t v1, int8x16_t v2) {
+// CHECK: test_vhsubq_s8
+ return vhsubq_s8(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vhsubq_s16(int16x8_t v1, int16x8_t v2) {
+// CHECK: test_vhsubq_s16
+ return vhsubq_s16(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vhsubq_s32(int32x4_t v1, int32x4_t v2) {
+// CHECK: test_vhsubq_s32
+ return vhsubq_s32(v1, v2);
+ // CHECK: shsub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vhsubq_u8(uint8x16_t v1, uint8x16_t v2) {
+// CHECK: test_vhsubq_u8
+ return vhsubq_u8(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vhsubq_u16(uint16x8_t v1, uint16x8_t v2) {
+// CHECK: test_vhsubq_u16
+ return vhsubq_u16(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vhsubq_u32(uint32x4_t v1, uint32x4_t v2) {
+// CHECK: test_vhsubq_u32
+ return vhsubq_u32(v1, v2);
+ // CHECK: uhsub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+
+int8x8_t test_vrhadd_s8(int8x8_t v1, int8x8_t v2) {
+// CHECK: test_vrhadd_s8
+ return vrhadd_s8(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vrhadd_s16(int16x4_t v1, int16x4_t v2) {
+// CHECK: test_vrhadd_s16
+ return vrhadd_s16(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vrhadd_s32(int32x2_t v1, int32x2_t v2) {
+// CHECK: test_vrhadd_s32
+ return vrhadd_s32(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vrhadd_u8(uint8x8_t v1, uint8x8_t v2) {
+// CHECK: test_vrhadd_u8
+ return vrhadd_u8(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vrhadd_u16(uint16x4_t v1, uint16x4_t v2) {
+// CHECK: test_vrhadd_u16
+ return vrhadd_u16(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vrhadd_u32(uint32x2_t v1, uint32x2_t v2) {
+// CHECK: test_vrhadd_u32
+ return vrhadd_u32(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vrhaddq_s8(int8x16_t v1, int8x16_t v2) {
+// CHECK: test_vrhaddq_s8
+ return vrhaddq_s8(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vrhaddq_s16(int16x8_t v1, int16x8_t v2) {
+// CHECK: test_vrhaddq_s16
+ return vrhaddq_s16(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vrhaddq_s32(int32x4_t v1, int32x4_t v2) {
+// CHECK: test_vrhaddq_s32
+ return vrhaddq_s32(v1, v2);
+// CHECK: srhadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vrhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
+// CHECK: test_vrhaddq_u8
+ return vrhaddq_u8(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vrhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
+// CHECK: test_vrhaddq_u16
+ return vrhaddq_u16(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vrhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
+// CHECK: test_vrhaddq_u32
+ return vrhaddq_u32(v1, v2);
+// CHECK: urhadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vqadd_s8
+ return vqadd_s8(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqadd_s16
+ return vqadd_s16(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqadd_s32
+ return vqadd_s32(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vqadd_s64
+ return vqadd_s64(a, b);
+// CHECK: sqadd {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vqadd_u8
+ return vqadd_u8(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vqadd_u16
+ return vqadd_u16(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vqadd_u32
+ return vqadd_u32(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vqadd_u64
+ return vqadd_u64(a, b);
+// CHECK: uqadd {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vqaddq_s8
+ return vqaddq_s8(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqaddq_s16
+ return vqaddq_s16(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqaddq_s32
+ return vqaddq_s32(a, b);
+ // CHECK: sqadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vqaddq_s64
+ return vqaddq_s64(a, b);
+// CHECK: sqadd {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vqaddq_u8
+ return vqaddq_u8(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vqaddq_u16
+ return vqaddq_u16(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vqaddq_u32
+ return vqaddq_u32(a, b);
+ // CHECK: uqadd {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
+// CHECK: test_vqaddq_u64
+ return vqaddq_u64(a, b);
+// CHECK: uqadd {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vqsub_s8
+ return vqsub_s8(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqsub_s16
+ return vqsub_s16(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqsub_s32
+ return vqsub_s32(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vqsub_s64
+ return vqsub_s64(a, b);
+// CHECK: sqsub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vqsub_u8
+ return vqsub_u8(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vqsub_u16
+ return vqsub_u16(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vqsub_u32
+ return vqsub_u32(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vqsub_u64
+ return vqsub_u64(a, b);
+// CHECK: uqsub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vqsubq_s8
+ return vqsubq_s8(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqsubq_s16
+ return vqsubq_s16(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqsubq_s32
+ return vqsubq_s32(a, b);
+ // CHECK: sqsub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vqsubq_s64
+ return vqsubq_s64(a, b);
+// CHECK: sqsub {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vqsubq_u8
+ return vqsubq_u8(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vqsubq_u16
+ return vqsubq_u16(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vqsubq_u32
+ return vqsubq_u32(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
+// CHECK: test_vqsubq_u64
+ return vqsubq_u64(a, b);
+ // CHECK: uqsub {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vshl_s8
+ return vshl_s8(a, b);
+// CHECK: sshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vshl_s16
+ return vshl_s16(a, b);
+// CHECK: sshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vshl_s32
+ return vshl_s32(a, b);
+// CHECK: sshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vshl_s64
+ return vshl_s64(a, b);
+// CHECK: sshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
+// CHECK: test_vshl_u8
+ return vshl_u8(a, b);
+// CHECK: ushl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
+// CHECK: test_vshl_u16
+ return vshl_u16(a, b);
+// CHECK: ushl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
+// CHECK: test_vshl_u32
+ return vshl_u32(a, b);
+// CHECK: ushl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
+// CHECK: test_vshl_u64
+ return vshl_u64(a, b);
+// CHECK: ushl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vshlq_s8
+ return vshlq_s8(a, b);
+// CHECK: sshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vshlq_s16
+ return vshlq_s16(a, b);
+// CHECK: sshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vshlq_s32
+ return vshlq_s32(a, b);
+// CHECK: sshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vshlq_s64
+ return vshlq_s64(a, b);
+// CHECK: sshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
+// CHECK: test_vshlq_u8
+ return vshlq_u8(a, b);
+// CHECK: ushl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
+// CHECK: test_vshlq_u16
+ return vshlq_u16(a, b);
+// CHECK: ushl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
+// CHECK: test_vshlq_u32
+ return vshlq_u32(a, b);
+// CHECK: ushl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vshlq_u64(uint64x2_t a, int64x2_t b) {
+// CHECK: test_vshlq_u64
+ return vshlq_u64(a, b);
+// CHECK: ushl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vqshl_s8
+ return vqshl_s8(a, b);
+// CHECK: sqshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqshl_s16
+ return vqshl_s16(a, b);
+// CHECK: sqshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqshl_s32
+ return vqshl_s32(a, b);
+// CHECK: sqshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vqshl_s64
+ return vqshl_s64(a, b);
+// CHECK: sqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
+// CHECK: test_vqshl_u8
+ return vqshl_u8(a, b);
+// CHECK: uqshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
+// CHECK: test_vqshl_u16
+ return vqshl_u16(a, b);
+// CHECK: uqshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
+// CHECK: test_vqshl_u32
+ return vqshl_u32(a, b);
+// CHECK: uqshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
+// CHECK: test_vqshl_u64
+ return vqshl_u64(a, b);
+// CHECK: uqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vqshlq_s8
+ return vqshlq_s8(a, b);
+// CHECK: sqshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqshlq_s16
+ return vqshlq_s16(a, b);
+// CHECK: sqshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqshlq_s32
+ return vqshlq_s32(a, b);
+// CHECK: sqshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vqshlq_s64
+ return vqshlq_s64(a, b);
+// CHECK: sqshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
+// CHECK: test_vqshlq_u8
+ return vqshlq_u8(a, b);
+// CHECK: uqshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
+// CHECK: test_vqshlq_u16
+ return vqshlq_u16(a, b);
+// CHECK: uqshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
+// CHECK: test_vqshlq_u32
+ return vqshlq_u32(a, b);
+// CHECK: uqshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vqshlq_u64(uint64x2_t a, int64x2_t b) {
+// CHECK: test_vqshlq_u32
+ return vqshlq_u64(a, b);
+// CHECK: uqshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vrshl_s8
+ return vrshl_s8(a, b);
+// CHECK: srshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vrshl_s16
+ return vrshl_s16(a, b);
+// CHECK: srshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vrshl_s32
+ return vrshl_s32(a, b);
+// CHECK: srshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vrshl_s64
+ return vrshl_s64(a, b);
+// CHECK: srshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
+// CHECK: test_vrshl_u8
+ return vrshl_u8(a, b);
+// CHECK: urshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
+// CHECK: test_vrshl_u16
+ return vrshl_u16(a, b);
+// CHECK: urshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
+// CHECK: test_vrshl_u32
+ return vrshl_u32(a, b);
+// CHECK: urshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
+// CHECK: test_vrshl_u64
+ return vrshl_u64(a, b);
+// CHECK: urshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vrshlq_s8
+ return vrshlq_s8(a, b);
+// CHECK: srshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vrshlq_s16
+ return vrshlq_s16(a, b);
+// CHECK: srshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vrshlq_s32
+ return vrshlq_s32(a, b);
+// CHECK: srshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vrshlq_s64
+ return vrshlq_s64(a, b);
+// CHECK: srshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
+// CHECK: test_vrshlq_u8
+ return vrshlq_u8(a, b);
+// CHECK: urshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
+// CHECK: test_vrshlq_u16
+ return vrshlq_u16(a, b);
+// CHECK: urshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
+// CHECK: test_vrshlq_u32
+ return vrshlq_u32(a, b);
+// CHECK: urshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) {
+// CHECK: test_vrshlq_u64
+ return vrshlq_u64(a, b);
+// CHECK: urshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vqrshl_s8
+ return vqrshl_s8(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqrshl_s16
+ return vqrshl_s16(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqrshl_s32
+ return vqrshl_s32(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vqrshl_s64
+ return vqrshl_s64(a, b);
+// CHECK: sqrshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
+// CHECK: test_vqrshl_u8
+ return vqrshl_u8(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
+// CHECK: test_vqrshl_u16
+ return vqrshl_u16(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
+// CHECK: test_vqrshl_u32
+ return vqrshl_u32(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
+// CHECK: test_vqrshl_u64
+ return vqrshl_u64(a, b);
+// CHECK: uqrshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vqrshlq_s8
+ return vqrshlq_s8(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqrshlq_s16
+ return vqrshlq_s16(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqrshlq_s32
+ return vqrshlq_s32(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
+// CHECK: test_vqrshlq_s64
+ return vqrshlq_s64(a, b);
+// CHECK: sqrshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vqrshlq_u8
+uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
+ return vqrshlq_u8(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
+// CHECK: test_vqrshlq_u16
+ return vqrshlq_u16(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
+// CHECK: test_vqrshlq_u32
+ return vqrshlq_u32(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vqrshlq_u64(uint64x2_t a, int64x2_t b) {
+// CHECK: test_vqrshlq_u64
+ return vqrshlq_u64(a, b);
+// CHECK: uqrshl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vmax_s8
+ return vmax_s8(a, b);
+// CHECK: smax {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vmax_s16
+ return vmax_s16(a, b);
+// CHECK: smax {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vmax_s32
+ return vmax_s32(a, b);
+// CHECK: smax {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vmax_u8
+ return vmax_u8(a, b);
+// CHECK: umax {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vmax_u16
+ return vmax_u16(a, b);
+// CHECK: umax {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vmax_u32
+ return vmax_u32(a, b);
+// CHECK: umax {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vmax_f32
+ return vmax_f32(a, b);
+// CHECK: fmax {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vmaxq_s8
+ return vmaxq_s8(a, b);
+// CHECK: smax {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vmaxq_s16
+ return vmaxq_s16(a, b);
+// CHECK: smax {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vmaxq_s32
+ return vmaxq_s32(a, b);
+// CHECK: smax {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vmaxq_u8
+ return vmaxq_u8(a, b);
+// CHECK: umax {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vmaxq_u16
+ return vmaxq_u16(a, b);
+// CHECK: umax {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vmaxq_u32
+ return vmaxq_u32(a, b);
+// CHECK: umax {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vmaxq_f32
+ return vmaxq_f32(a, b);
+// CHECK: fmax {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmaxq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vmaxq_f64
+ return vmaxq_f64(a, b);
+// CHECK: fmax {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+
+int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vmin_s8
+ return vmin_s8(a, b);
+// CHECK: smin {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vmin_s16
+ return vmin_s16(a, b);
+// CHECK: smin {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vmin_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vmin_s32
+ return vmin_s32(a, b);
+// CHECK: smin {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vmin_u8
+ return vmin_u8(a, b);
+// CHECK: umin {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vmin_u16
+ return vmin_u16(a, b);
+// CHECK: umin {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vmin_u32
+ return vmin_u32(a, b);
+// CHECK: umin {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vmin_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vmin_f32
+ return vmin_f32(a, b);
+// CHECK: fmin {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vminq_s8
+ return vminq_s8(a, b);
+// CHECK: smin {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vminq_s16
+ return vminq_s16(a, b);
+// CHECK: smin {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vminq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vminq_s32
+ return vminq_s32(a, b);
+// CHECK: smin {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vminq_u8
+ return vminq_u8(a, b);
+// CHECK: umin {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vminq_u16
+ return vminq_u16(a, b);
+// CHECK: umin {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vminq_u32
+ return vminq_u32(a, b);
+// CHECK: umin {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vminq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vminq_f32
+ return vminq_f32(a, b);
+// CHECK: fmin {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vminq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vminq_f64
+ return vminq_f64(a, b);
+// CHECK: fmin {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x2_t test_vmaxnm_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vmaxnm_f32
+ return vmaxnm_f32(a, b);
+// CHECK: fmaxnm {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vmaxnmq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vmaxnmq_f32
+ return vmaxnmq_f32(a, b);
+// CHECK: fmaxnm {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmaxnmq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vmaxnmq_f64
+ return vmaxnmq_f64(a, b);
+// CHECK: fmaxnm {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x2_t test_vminnm_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vminnm_f32
+ return vminnm_f32(a, b);
+// CHECK: fminnm {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vminnmq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vminnmq_f32
+ return vminnmq_f32(a, b);
+// CHECK: fminnm {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vminnmq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vminnmq_f64
+ return vminnmq_f64(a, b);
+// CHECK: fminnm {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vpmax_s8
+ return vpmax_s8(a, b);
+// CHECK: smaxp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vpmax_s16
+ return vpmax_s16(a, b);
+// CHECK: smaxp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vpmax_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vpmax_s32
+ return vpmax_s32(a, b);
+// CHECK: smaxp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vpmax_u8
+ return vpmax_u8(a, b);
+// CHECK: umaxp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vpmax_u16
+ return vpmax_u16(a, b);
+// CHECK: umaxp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vpmax_u32
+ return vpmax_u32(a, b);
+// CHECK: umaxp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vpmax_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vpmax_f32
+ return vpmax_f32(a, b);
+// CHECK: fmaxp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vpmaxq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vpmaxq_s8
+ return vpmaxq_s8(a, b);
+// CHECK: smaxp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vpmaxq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vpmaxq_s16
+ return vpmaxq_s16(a, b);
+// CHECK: smaxp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vpmaxq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vpmaxq_s32
+ return vpmaxq_s32(a, b);
+// CHECK: smaxp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vpmaxq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vpmaxq_u8
+ return vpmaxq_u8(a, b);
+// CHECK: umaxp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vpmaxq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vpmaxq_u16
+ return vpmaxq_u16(a, b);
+// CHECK: umaxp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vpmaxq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vpmaxq_u32
+ return vpmaxq_u32(a, b);
+// CHECK: umaxp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vpmaxq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vpmaxq_f32
+ return vpmaxq_f32(a, b);
+// CHECK: fmaxp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vpmaxq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vpmaxq_f64
+ return vpmaxq_f64(a, b);
+// CHECK: fmaxp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vpmin_s8
+ return vpmin_s8(a, b);
+// CHECK: sminp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vpmin_s16
+ return vpmin_s16(a, b);
+// CHECK: sminp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vpmin_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vpmin_s32
+ return vpmin_s32(a, b);
+// CHECK: sminp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vpmin_u8
+ return vpmin_u8(a, b);
+// CHECK: uminp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vpmin_u16
+ return vpmin_u16(a, b);
+// CHECK: uminp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vpmin_u32
+ return vpmin_u32(a, b);
+// CHECK: uminp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vpmin_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vpmin_f32
+ return vpmin_f32(a, b);
+// CHECK: fminp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vpminq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vpminq_s8
+ return vpminq_s8(a, b);
+// CHECK: sminp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vpminq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vpminq_s16
+ return vpminq_s16(a, b);
+// CHECK: sminp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vpminq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vpminq_s32
+ return vpminq_s32(a, b);
+// CHECK: sminp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vpminq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vpminq_u8
+ return vpminq_u8(a, b);
+// CHECK: uminp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vpminq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vpminq_u16
+ return vpminq_u16(a, b);
+// CHECK: uminp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vpminq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vpminq_u32
+ return vpminq_u32(a, b);
+// CHECK: uminp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vpminq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vpminq_f32
+ return vpminq_f32(a, b);
+// CHECK: fminp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vpminq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vpminq_f64
+ return vpminq_f64(a, b);
+// CHECK: fminp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x2_t test_vpmaxnm_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vpmaxnm_f32
+ return vpmaxnm_f32(a, b);
+// CHECK: fmaxnmp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vpmaxnmq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vpmaxnmq_f32
+ return vpmaxnmq_f32(a, b);
+// CHECK: fmaxnmp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vpmaxnmq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vpmaxnmq_f64
+ return vpmaxnmq_f64(a, b);
+// CHECK: fmaxnmp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+float32x2_t test_vpminnm_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vpminnm_f32
+ return vpminnm_f32(a, b);
+// CHECK: fminnmp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vpminnmq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vpminnmq_f32
+ return vpminnmq_f32(a, b);
+// CHECK: fminnmp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vpminnmq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vpminnmq_f64
+ return vpminnmq_f64(a, b);
+// CHECK: fminnmp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
+// CHECK: test_vpadd_s8
+ return vpadd_s8(a, b);
+// CHECK: addp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vpadd_s16
+ return vpadd_s16(a, b);
+// CHECK: addp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vpadd_s32
+ return vpadd_s32(a, b);
+// CHECK: addp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
+// CHECK: test_vpadd_u8
+ return vpadd_u8(a, b);
+// CHECK: addp {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
+// CHECK: test_vpadd_u16
+ return vpadd_u16(a, b);
+// CHECK: addp {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
+// CHECK: test_vpadd_u32
+ return vpadd_u32(a, b);
+// CHECK: addp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vpadd_f32
+ return vpadd_f32(a, b);
+// CHECK: faddp {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int8x16_t test_vpaddq_s8(int8x16_t a, int8x16_t b) {
+// CHECK: test_vpaddq_s8
+ return vpaddq_s8(a, b);
+// CHECK: addp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x8_t test_vpaddq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vpaddq_s16
+ return vpaddq_s16(a, b);
+// CHECK: addp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vpaddq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vpaddq_s32
+ return vpaddq_s32(a, b);
+// CHECK: addp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint8x16_t test_vpaddq_u8(uint8x16_t a, uint8x16_t b) {
+// CHECK: test_vpaddq_u8
+ return vpaddq_u8(a, b);
+// CHECK: addp {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x8_t test_vpaddq_u16(uint16x8_t a, uint16x8_t b) {
+// CHECK: test_vpaddq_u16
+ return vpaddq_u16(a, b);
+// CHECK: addp {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x4_t test_vpaddq_u32(uint32x4_t a, uint32x4_t b) {
+// CHECK: test_vpaddq_u32
+ return vpaddq_u32(a, b);
+// CHECK: addp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float32x4_t test_vpaddq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vpaddq_f32
+ return vpaddq_f32(a, b);
+// CHECK: faddp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vpaddq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vpaddq_f64
+ return vpaddq_f64(a, b);
+// CHECK: faddp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqdmulh_s16
+ return vqdmulh_s16(a, b);
+// CHECK: sqdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqdmulh_s32
+ return vqdmulh_s32(a, b);
+// CHECK: sqdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqdmulhq_s16
+ return vqdmulhq_s16(a, b);
+// CHECK: sqdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqdmulhq_s32
+ return vqdmulhq_s32(a, b);
+// CHECK: sqdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
+// CHECK: test_vqrdmulh_s16
+ return vqrdmulh_s16(a, b);
+// CHECK: sqrdmulh {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
+// CHECK: test_vqrdmulh_s32
+ return vqrdmulh_s32(a, b);
+// CHECK: sqrdmulh {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
+// CHECK: test_vqrdmulhq_s16
+ return vqrdmulhq_s16(a, b);
+// CHECK: sqrdmulh {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
+// CHECK: test_vqrdmulhq_s32
+ return vqrdmulhq_s32(a, b);
+// CHECK: sqrdmulh {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+
+float32x2_t test_vmulx_f32(float32x2_t a, float32x2_t b) {
+// CHECK: test_vmulx_f32
+ return vmulx_f32(a, b);
+// CHECK: fmulx {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+}
+
+float32x4_t test_vmulxq_f32(float32x4_t a, float32x4_t b) {
+// CHECK: test_vmulxq_f32
+ return vmulxq_f32(a, b);
+// CHECK: fmulx {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vmulxq_f64(float64x2_t a, float64x2_t b) {
+// CHECK: test_vmulxq_f64
+ return vmulxq_f64(a, b);
+// CHECK: fmulx {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+int8x8_t test_vshl_n_s8(int8x8_t a) {
+// CHECK: test_vshl_n_s8
+ return vshl_n_s8(a, 3);
+// CHECK: shl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vshl_n_s16(int16x4_t a) {
+// CHECK: test_vshl_n_s16
+ return vshl_n_s16(a, 3);
+// CHECK: shl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vshl_n_s32(int32x2_t a) {
+// CHECK: test_vshl_n_s32
+ return vshl_n_s32(a, 3);
+// CHECK: shl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vshlq_n_s8(int8x16_t a) {
+// CHECK: test_vshlq_n_s8
+ return vshlq_n_s8(a, 3);
+// CHECK: shl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vshlq_n_s16(int16x8_t a) {
+// CHECK: test_vshlq_n_s16
+ return vshlq_n_s16(a, 3);
+// CHECK: shl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vshlq_n_s32(int32x4_t a) {
+// CHECK: test_vshlq_n_s32
+ return vshlq_n_s32(a, 3);
+// CHECK: shl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vshlq_n_s64(int64x2_t a) {
+// CHECK: test_vshlq_n_s64
+ return vshlq_n_s64(a, 3);
+// CHECK: shl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vshl_n_u8(int8x8_t a) {
+// CHECK: test_vshl_n_u8
+ return vshl_n_u8(a, 3);
+// CHECK: shl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vshl_n_u16(int16x4_t a) {
+// CHECK: test_vshl_n_u16
+ return vshl_n_u16(a, 3);
+// CHECK: shl {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vshl_n_u32(int32x2_t a) {
+// CHECK: test_vshl_n_u32
+ return vshl_n_u32(a, 3);
+// CHECK: shl {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vshlq_n_u8(int8x16_t a) {
+// CHECK: test_vshlq_n_u8
+ return vshlq_n_u8(a, 3);
+// CHECK: shl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vshlq_n_u16(int16x8_t a) {
+// CHECK: test_vshlq_n_u16
+ return vshlq_n_u16(a, 3);
+// CHECK: shl {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vshlq_n_u32(int32x4_t a) {
+// CHECK: test_vshlq_n_u32
+ return vshlq_n_u32(a, 3);
+// CHECK: shl {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vshlq_n_u64(int64x2_t a) {
+// CHECK: test_vshlq_n_u64
+ return vshlq_n_u64(a, 3);
+// CHECK: shl {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vshr_n_s8(int8x8_t a) {
+ // CHECK: test_vshr_n_s8
+ return vshr_n_s8(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vshr_n_s16(int16x4_t a) {
+ // CHECK: test_vshr_n_s16
+ return vshr_n_s16(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vshr_n_s32(int32x2_t a) {
+ // CHECK: test_vshr_n_s32
+ return vshr_n_s32(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vshrq_n_s8(int8x16_t a) {
+ // CHECK: test_vshrq_n_s8
+ return vshrq_n_s8(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vshrq_n_s16(int16x8_t a) {
+ // CHECK: test_vshrq_n_s16
+ return vshrq_n_s16(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vshrq_n_s32(int32x4_t a) {
+ // CHECK: test_vshrq_n_s32
+ return vshrq_n_s32(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vshrq_n_s64(int64x2_t a) {
+ // CHECK: test_vshrq_n_s64
+ return vshrq_n_s64(a, 3);
+ // CHECK: sshr {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vshr_n_u8(int8x8_t a) {
+ // CHECK: test_vshr_n_u8
+ return vshr_n_u8(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vshr_n_u16(int16x4_t a) {
+ // CHECK: test_vshr_n_u16
+ return vshr_n_u16(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vshr_n_u32(int32x2_t a) {
+ // CHECK: test_vshr_n_u32
+ return vshr_n_u32(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vshrq_n_u8(int8x16_t a) {
+ // CHECK: test_vshrq_n_u8
+ return vshrq_n_u8(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vshrq_n_u16(int16x8_t a) {
+ // CHECK: test_vshrq_n_u16
+ return vshrq_n_u16(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vshrq_n_u32(int32x4_t a) {
+ // CHECK: test_vshrq_n_u32
+ return vshrq_n_u32(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vshrq_n_u64(int64x2_t a) {
+ // CHECK: test_vshrq_n_u64
+ return vshrq_n_u64(a, 3);
+ // CHECK: ushr {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vsra_n_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsra_n_s8
+ return vsra_n_s8(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vsra_n_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsra_n_s16
+ return vsra_n_s16(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vsra_n_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsra_n_s32
+ return vsra_n_s32(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vsraq_n_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsraq_n_s8
+ return vsraq_n_s8(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vsraq_n_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsraq_n_s16
+ return vsraq_n_s16(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vsraq_n_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsraq_n_s32
+ return vsraq_n_s32(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vsraq_n_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsraq_n_s64
+ return vsraq_n_s64(a, b, 3);
+ // CHECK: ssra {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vsra_n_u8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsra_n_u8
+ return vsra_n_u8(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vsra_n_u16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsra_n_u16
+ return vsra_n_u16(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vsra_n_u32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsra_n_u32
+ return vsra_n_u32(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vsraq_n_u8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsraq_n_u8
+ return vsraq_n_u8(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vsraq_n_u16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsraq_n_u16
+ return vsraq_n_u16(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vsraq_n_u32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsraq_n_u32
+ return vsraq_n_u32(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vsraq_n_u64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsraq_n_u64
+ return vsraq_n_u64(a, b, 3);
+ // CHECK: usra {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vrshr_n_s8(int8x8_t a) {
+ // CHECK: test_vrshr_n_s8
+ return vrshr_n_s8(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vrshr_n_s16(int16x4_t a) {
+ // CHECK: test_vrshr_n_s16
+ return vrshr_n_s16(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vrshr_n_s32(int32x2_t a) {
+ // CHECK: test_vrshr_n_s32
+ return vrshr_n_s32(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vrshrq_n_s8(int8x16_t a) {
+ // CHECK: test_vrshrq_n_s8
+ return vrshrq_n_s8(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vrshrq_n_s16(int16x8_t a) {
+ // CHECK: test_vrshrq_n_s16
+ return vrshrq_n_s16(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vrshrq_n_s32(int32x4_t a) {
+ // CHECK: test_vrshrq_n_s32
+ return vrshrq_n_s32(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vrshrq_n_s64(int64x2_t a) {
+ // CHECK: test_vrshrq_n_s64
+ return vrshrq_n_s64(a, 3);
+ // CHECK: srshr {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vrshr_n_u8(int8x8_t a) {
+ // CHECK: test_vrshr_n_u8
+ return vrshr_n_u8(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vrshr_n_u16(int16x4_t a) {
+ // CHECK: test_vrshr_n_u16
+ return vrshr_n_u16(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vrshr_n_u32(int32x2_t a) {
+ // CHECK: test_vrshr_n_u32
+ return vrshr_n_u32(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vrshrq_n_u8(int8x16_t a) {
+ // CHECK: test_vrshrq_n_u8
+ return vrshrq_n_u8(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vrshrq_n_u16(int16x8_t a) {
+ // CHECK: test_vrshrq_n_u16
+ return vrshrq_n_u16(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vrshrq_n_u32(int32x4_t a) {
+ // CHECK: test_vrshrq_n_u32
+ return vrshrq_n_u32(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vrshrq_n_u64(int64x2_t a) {
+ // CHECK: test_vrshrq_n_u64
+ return vrshrq_n_u64(a, 3);
+ // CHECK: urshr {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vrsra_n_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vrsra_n_s8
+ return vrsra_n_s8(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vrsra_n_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vrsra_n_s16
+ return vrsra_n_s16(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vrsra_n_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vrsra_n_s32
+ return vrsra_n_s32(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vrsraq_n_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vrsraq_n_s8
+ return vrsraq_n_s8(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vrsraq_n_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vrsraq_n_s16
+ return vrsraq_n_s16(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vrsraq_n_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vrsraq_n_s32
+ return vrsraq_n_s32(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vrsraq_n_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vrsraq_n_s64
+ return vrsraq_n_s64(a, b, 3);
+ // CHECK: srsra {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vrsra_n_u8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vrsra_n_u8
+ return vrsra_n_u8(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vrsra_n_u16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vrsra_n_u16
+ return vrsra_n_u16(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vrsra_n_u32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vrsra_n_u32
+ return vrsra_n_u32(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vrsraq_n_u8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vrsraq_n_u8
+ return vrsraq_n_u8(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vrsraq_n_u16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vrsraq_n_u16
+ return vrsraq_n_u16(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vrsraq_n_u32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vrsraq_n_u32
+ return vrsraq_n_u32(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vrsraq_n_u64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vrsraq_n_u64
+ return vrsraq_n_u64(a, b, 3);
+ // CHECK: ursra {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vsri_n_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsri_n_s8
+ return vsri_n_s8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vsri_n_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsri_n_s16
+ return vsri_n_s16(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vsri_n_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsri_n_s32
+ return vsri_n_s32(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vsriq_n_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsriq_n_s8
+ return vsriq_n_s8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vsriq_n_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsriq_n_s16
+ return vsriq_n_s16(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vsriq_n_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsriq_n_s32
+ return vsriq_n_s32(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vsriq_n_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsriq_n_s64
+ return vsriq_n_s64(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vsri_n_u8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsri_n_u8
+ return vsri_n_u8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vsri_n_u16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsri_n_u16
+ return vsri_n_u16(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vsri_n_u32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsri_n_u32
+ return vsri_n_u32(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vsriq_n_u8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsriq_n_u8
+ return vsriq_n_u8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vsriq_n_u16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsriq_n_u16
+ return vsriq_n_u16(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vsriq_n_u32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsriq_n_u32
+ return vsriq_n_u32(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vsriq_n_u64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsriq_n_u64
+ return vsriq_n_u64(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+poly8x8_t test_vsri_n_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vsri_n_p8
+ return vsri_n_p8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+poly16x4_t test_vsri_n_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vsri_n_p16
+ return vsri_n_p16(a, b, 15);
+ // CHECK: sri {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #15
+}
+
+poly8x16_t test_vsriq_n_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vsriq_n_p8
+ return vsriq_n_p8(a, b, 3);
+ // CHECK: sri {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+poly16x8_t test_vsriq_n_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vsriq_n_p16
+ return vsriq_n_p16(a, b, 15);
+ // CHECK: sri {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #15
+}
+
+int8x8_t test_vsli_n_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsli_n_s8
+ return vsli_n_s8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vsli_n_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsli_n_s16
+ return vsli_n_s16(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vsli_n_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsli_n_s32
+ return vsli_n_s32(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vsliq_n_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsliq_n_s8
+ return vsliq_n_s8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vsliq_n_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsliq_n_s16
+ return vsliq_n_s16(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vsliq_n_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsliq_n_s32
+ return vsliq_n_s32(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vsliq_n_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsliq_n_s64
+ return vsliq_n_s64(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+uint8x8_t test_vsli_n_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vsli_n_u8
+ return vsli_n_u8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+uint16x4_t test_vsli_n_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vsli_n_u16
+ return vsli_n_u16(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+uint32x2_t test_vsli_n_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vsli_n_u32
+ return vsli_n_u32(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+uint8x16_t test_vsliq_n_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vsliq_n_u8
+ return vsliq_n_u8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+uint16x8_t test_vsliq_n_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vsliq_n_u16
+ return vsliq_n_u16(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+uint32x4_t test_vsliq_n_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vsliq_n_u32
+ return vsliq_n_u32(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+uint64x2_t test_vsliq_n_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vsliq_n_u64
+ return vsliq_n_u64(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+poly8x8_t test_vsli_n_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vsli_n_p8
+ return vsli_n_p8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+poly16x4_t test_vsli_n_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vsli_n_p16
+ return vsli_n_p16(a, b, 15);
+ // CHECK: sli {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #15
+}
+
+poly8x16_t test_vsliq_n_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vsliq_n_p8
+ return vsliq_n_p8(a, b, 3);
+ // CHECK: sli {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+poly16x8_t test_vsliq_n_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vsliq_n_p16
+ return vsliq_n_p16(a, b, 15);
+ // CHECK: sli {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #15
+}
+
+int8x8_t test_vqshlu_n_s8(int8x8_t a) {
+ // CHECK: test_vqshlu_n_s8
+ return vqshlu_n_s8(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #3
+}
+
+int16x4_t test_vqshlu_n_s16(int16x4_t a) {
+ // CHECK: test_vqshlu_n_s16
+ return vqshlu_n_s16(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #3
+}
+
+int32x2_t test_vqshlu_n_s32(int32x2_t a) {
+ // CHECK: test_vqshlu_n_s32
+ return vqshlu_n_s32(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #3
+}
+
+int8x16_t test_vqshluq_n_s8(int8x16_t a) {
+ // CHECK: test_vqshluq_n_s8
+ return vqshluq_n_s8(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #3
+}
+
+int16x8_t test_vqshluq_n_s16(int16x8_t a) {
+ // CHECK: test_vqshluq_n_s16
+ return vqshluq_n_s16(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #3
+}
+
+int32x4_t test_vqshluq_n_s32(int32x4_t a) {
+ // CHECK: test_vqshluq_n_s32
+ return vqshluq_n_s32(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #3
+}
+
+int64x2_t test_vqshluq_n_s64(int64x2_t a) {
+ // CHECK: test_vqshluq_n_s64
+ return vqshluq_n_s64(a, 3);
+ // CHECK: sqshlu {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #3
+}
+
+int8x8_t test_vshrn_n_s16(int16x8_t a) {
+ // CHECK: test_vshrn_n_s16
+ return vshrn_n_s16(a, 3);
+ // CHECK: shrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vshrn_n_s32(int32x4_t a) {
+ // CHECK: test_vshrn_n_s32
+ return vshrn_n_s32(a, 9);
+ // CHECK: shrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vshrn_n_s64(int64x2_t a) {
+ // CHECK: test_vshrn_n_s64
+ return vshrn_n_s64(a, 19);
+ // CHECK: shrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x8_t test_vshrn_n_u16(uint16x8_t a) {
+ // CHECK: test_vshrn_n_u16
+ return vshrn_n_u16(a, 3);
+ // CHECK: shrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x4_t test_vshrn_n_u32(uint32x4_t a) {
+ // CHECK: test_vshrn_n_u32
+ return vshrn_n_u32(a, 9);
+ // CHECK: shrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x2_t test_vshrn_n_u64(uint64x2_t a) {
+ // CHECK: test_vshrn_n_u64
+ return vshrn_n_u64(a, 19);
+ // CHECK: shrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vshrn_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vshrn_high_n_s16
+ return vshrn_high_n_s16(a, b, 3);
+ // CHECK: shrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vshrn_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vshrn_high_n_s32
+ return vshrn_high_n_s32(a, b, 9);
+ // CHECK: shrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vshrn_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vshrn_high_n_s64
+ return vshrn_high_n_s64(a, b, 19);
+ // CHECK: shrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x16_t test_vshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
+ // CHECK: test_vshrn_high_n_u16
+ return vshrn_high_n_u16(a, b, 3);
+ // CHECK: shrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x8_t test_vshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
+ // CHECK: test_vshrn_high_n_u32
+ return vshrn_high_n_u32(a, b, 9);
+ // CHECK: shrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x4_t test_vshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
+ // CHECK: test_vshrn_high_n_u64
+ return vshrn_high_n_u64(a, b, 19);
+ // CHECK: shrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int8x8_t test_vqshrun_n_s16(int16x8_t a) {
+ // CHECK: test_vqshrun_n_s16
+ return vqshrun_n_s16(a, 3);
+ // CHECK: sqshrun {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vqshrun_n_s32(int32x4_t a) {
+ // CHECK: test_vqshrun_n_s32
+ return vqshrun_n_s32(a, 9);
+ // CHECK: sqshrun {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vqshrun_n_s64(int64x2_t a) {
+ // CHECK: test_vqshrun_n_s64
+ return vqshrun_n_s64(a, 19);
+ // CHECK: sqshrun {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vqshrun_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqshrun_high_n_s16
+ return vqshrun_high_n_s16(a, b, 3);
+ // CHECK: sqshrun2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vqshrun_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqshrun_high_n_s32
+ return vqshrun_high_n_s32(a, b, 9);
+ // CHECK: sqshrun2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vqshrun_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqshrun_high_n_s64
+ return vqshrun_high_n_s64(a, b, 19);
+ // CHECK: sqshrun2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int8x8_t test_vrshrn_n_s16(int16x8_t a) {
+ // CHECK: test_vrshrn_n_s16
+ return vrshrn_n_s16(a, 3);
+ // CHECK: rshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vrshrn_n_s32(int32x4_t a) {
+ // CHECK: test_vrshrn_n_s32
+ return vrshrn_n_s32(a, 9);
+ // CHECK: rshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vrshrn_n_s64(int64x2_t a) {
+ // CHECK: test_vrshrn_n_s64
+ return vrshrn_n_s64(a, 19);
+ // CHECK: rshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x8_t test_vrshrn_n_u16(uint16x8_t a) {
+ // CHECK: test_vrshrn_n_u16
+ return vrshrn_n_u16(a, 3);
+ // CHECK: rshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x4_t test_vrshrn_n_u32(uint32x4_t a) {
+ // CHECK: test_vrshrn_n_u32
+ return vrshrn_n_u32(a, 9);
+ // CHECK: rshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x2_t test_vrshrn_n_u64(uint64x2_t a) {
+ // CHECK: test_vrshrn_n_u64
+ return vrshrn_n_u64(a, 19);
+ // CHECK: rshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vrshrn_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vrshrn_high_n_s16
+ return vrshrn_high_n_s16(a, b, 3);
+ // CHECK: rshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vrshrn_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vrshrn_high_n_s32
+ return vrshrn_high_n_s32(a, b, 9);
+ // CHECK: rshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vrshrn_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vrshrn_high_n_s64
+ return vrshrn_high_n_s64(a, b, 19);
+ // CHECK: rshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x16_t test_vrshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
+ // CHECK: test_vrshrn_high_n_u16
+ return vrshrn_high_n_u16(a, b, 3);
+ // CHECK: rshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x8_t test_vrshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
+ // CHECK: test_vrshrn_high_n_u32
+ return vrshrn_high_n_u32(a, b, 9);
+ // CHECK: rshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x4_t test_vrshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
+ // CHECK: test_vrshrn_high_n_u64
+ return vrshrn_high_n_u64(a, b, 19);
+ // CHECK: rshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int8x8_t test_vqrshrun_n_s16(int16x8_t a) {
+ // CHECK: test_vqrshrun_n_s16
+ return vqrshrun_n_s16(a, 3);
+ // CHECK: sqrshrun {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vqrshrun_n_s32(int32x4_t a) {
+ // CHECK: test_vqrshrun_n_s32
+ return vqrshrun_n_s32(a, 9);
+ // CHECK: sqrshrun {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vqrshrun_n_s64(int64x2_t a) {
+ // CHECK: test_vqrshrun_n_s64
+ return vqrshrun_n_s64(a, 19);
+ // CHECK: sqrshrun {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vqrshrun_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqrshrun_high_n_s16
+ return vqrshrun_high_n_s16(a, b, 3);
+ // CHECK: sqrshrun2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vqrshrun_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqrshrun_high_n_s32
+ return vqrshrun_high_n_s32(a, b, 9);
+ // CHECK: sqrshrun2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vqrshrun_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqrshrun_high_n_s64
+ return vqrshrun_high_n_s64(a, b, 19);
+ // CHECK: sqrshrun2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int8x8_t test_vqshrn_n_s16(int16x8_t a) {
+ // CHECK: test_vqshrn_n_s16
+ return vqshrn_n_s16(a, 3);
+ // CHECK: sqshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vqshrn_n_s32(int32x4_t a) {
+ // CHECK: test_vqshrn_n_s32
+ return vqshrn_n_s32(a, 9);
+ // CHECK: sqshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vqshrn_n_s64(int64x2_t a) {
+ // CHECK: test_vqshrn_n_s64
+ return vqshrn_n_s64(a, 19);
+ // CHECK: sqshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x8_t test_vqshrn_n_u16(uint16x8_t a) {
+ // CHECK: test_vqshrn_n_u16
+ return vqshrn_n_u16(a, 3);
+ // CHECK: uqshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x4_t test_vqshrn_n_u32(uint32x4_t a) {
+ // CHECK: test_vqshrn_n_u32
+ return vqshrn_n_u32(a, 9);
+ // CHECK: uqshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x2_t test_vqshrn_n_u64(uint64x2_t a) {
+ // CHECK: test_vqshrn_n_u64
+ return vqshrn_n_u64(a, 19);
+ // CHECK: uqshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vqshrn_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqshrn_high_n_s16
+ return vqshrn_high_n_s16(a, b, 3);
+ // CHECK: sqshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vqshrn_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqshrn_high_n_s32
+ return vqshrn_high_n_s32(a, b, 9);
+ // CHECK: sqshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vqshrn_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqshrn_high_n_s64
+ return vqshrn_high_n_s64(a, b, 19);
+ // CHECK: sqshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x16_t test_vqshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
+ // CHECK: test_vqshrn_high_n_u16
+ return vqshrn_high_n_u16(a, b, 3);
+ // CHECK: uqshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x8_t test_vqshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
+ // CHECK: test_vqshrn_high_n_u32
+ return vqshrn_high_n_u32(a, b, 9);
+ // CHECK: uqshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x4_t test_vqshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
+ // CHECK: test_vqshrn_high_n_u64
+ return vqshrn_high_n_u64(a, b, 19);
+ // CHECK: uqshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int8x8_t test_vqrshrn_n_s16(int16x8_t a) {
+ // CHECK: test_vqrshrn_n_s16
+ return vqrshrn_n_s16(a, 3);
+ // CHECK: sqrshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+int16x4_t test_vqrshrn_n_s32(int32x4_t a) {
+ // CHECK: test_vqrshrn_n_s32
+ return vqrshrn_n_s32(a, 9);
+ // CHECK: sqrshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+int32x2_t test_vqrshrn_n_s64(int64x2_t a) {
+ // CHECK: test_vqrshrn_n_s64
+ return vqrshrn_n_s64(a, 19);
+ // CHECK: sqrshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x8_t test_vqrshrn_n_u16(uint16x8_t a) {
+ // CHECK: test_vqrshrn_n_u16
+ return vqrshrn_n_u16(a, 3);
+ // CHECK: uqrshrn {{v[0-9]+}}.8b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x4_t test_vqrshrn_n_u32(uint32x4_t a) {
+ // CHECK: test_vqrshrn_n_u32
+ return vqrshrn_n_u32(a, 9);
+ // CHECK: uqrshrn {{v[0-9]+}}.4h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x2_t test_vqrshrn_n_u64(uint64x2_t a) {
+ // CHECK: test_vqrshrn_n_u64
+ return vqrshrn_n_u64(a, 19);
+ // CHECK: uqrshrn {{v[0-9]+}}.2s, {{v[0-9]+}}.2d, #19
+}
+
+int8x16_t test_vqrshrn_high_n_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqrshrn_high_n_s16
+ return vqrshrn_high_n_s16(a, b, 3);
+ // CHECK: sqrshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+int16x8_t test_vqrshrn_high_n_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqrshrn_high_n_s32
+ return vqrshrn_high_n_s32(a, b, 9);
+ // CHECK: sqrshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+int32x4_t test_vqrshrn_high_n_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqrshrn_high_n_s64
+ return vqrshrn_high_n_s64(a, b, 19);
+ // CHECK: sqrshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+uint8x16_t test_vqrshrn_high_n_u16(uint8x8_t a, uint16x8_t b) {
+ // CHECK: test_vqrshrn_high_n_u16
+ return vqrshrn_high_n_u16(a, b, 3);
+ // CHECK: uqrshrn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.8h, #3
+}
+
+uint16x8_t test_vqrshrn_high_n_u32(uint16x4_t a, uint32x4_t b) {
+ // CHECK: test_vqrshrn_high_n_u32
+ return vqrshrn_high_n_u32(a, b, 9);
+ // CHECK: uqrshrn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.4s, #9
+}
+
+uint32x4_t test_vqrshrn_high_n_u64(uint32x2_t a, uint64x2_t b) {
+ // CHECK: test_vqrshrn_high_n_u64
+ return vqrshrn_high_n_u64(a, b, 19);
+ // CHECK: uqrshrn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.2d, #19
+}
+
+int16x8_t test_vshll_n_s8(int8x8_t a) {
+// CHECK: test_vshll_n_s8
+ return vshll_n_s8(a, 3);
+// CHECK: sshll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #3
+}
+
+int32x4_t test_vshll_n_s16(int16x4_t a) {
+// CHECK: test_vshll_n_s16
+ return vshll_n_s16(a, 9);
+// CHECK: sshll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #9
+}
+
+int64x2_t test_vshll_n_s32(int32x2_t a) {
+// CHECK: test_vshll_n_s32
+ return vshll_n_s32(a, 19);
+// CHECK: sshll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #19
+}
+
+uint16x8_t test_vshll_n_u8(uint8x8_t a) {
+// CHECK: test_vshll_n_u8
+ return vshll_n_u8(a, 3);
+// CHECK: ushll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #3
+}
+
+uint32x4_t test_vshll_n_u16(uint16x4_t a) {
+// CHECK: test_vshll_n_u16
+ return vshll_n_u16(a, 9);
+// CHECK: ushll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #9
+}
+
+uint64x2_t test_vshll_n_u32(uint32x2_t a) {
+// CHECK: test_vshll_n_u32
+ return vshll_n_u32(a, 19);
+// CHECK: ushll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #19
+}
+
+int16x8_t test_vshll_high_n_s8(int8x16_t a) {
+// CHECK: test_vshll_high_n_s8
+ return vshll_high_n_s8(a, 3);
+// CHECK: sshll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #3
+}
+
+int32x4_t test_vshll_high_n_s16(int16x8_t a) {
+// CHECK: test_vshll_high_n_s16
+ return vshll_high_n_s16(a, 9);
+// CHECK: sshll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #9
+}
+
+int64x2_t test_vshll_high_n_s32(int32x4_t a) {
+// CHECK: test_vshll_high_n_s32
+ return vshll_high_n_s32(a, 19);
+// CHECK: sshll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #19
+}
+
+uint16x8_t test_vshll_high_n_u8(uint8x16_t a) {
+// CHECK: test_vshll_high_n_u8
+ return vshll_high_n_u8(a, 3);
+// CHECK: ushll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #3
+}
+
+uint32x4_t test_vshll_high_n_u16(uint16x8_t a) {
+// CHECK: test_vshll_high_n_u16
+ return vshll_high_n_u16(a, 9);
+// CHECK: ushll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #9
+}
+
+uint64x2_t test_vshll_high_n_u32(uint32x4_t a) {
+// CHECK: test_vshll_high_n_u32
+ return vshll_high_n_u32(a, 19);
+// CHECK: ushll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #19
+}
+
+int16x8_t test_vmovl_s8(int8x8_t a) {
+// CHECK: test_vmovl_s8
+ return vmovl_s8(a);
+// CHECK: sshll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #0
+}
+
+int32x4_t test_vmovl_s16(int16x4_t a) {
+// CHECK: test_vmovl_s16
+ return vmovl_s16(a);
+// CHECK: sshll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #0
+}
+
+int64x2_t test_vmovl_s32(int32x2_t a) {
+// CHECK: test_vmovl_s32
+ return vmovl_s32(a);
+// CHECK: sshll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #0
+}
+
+uint16x8_t test_vmovl_u8(uint8x8_t a) {
+// CHECK: test_vmovl_u8
+ return vmovl_u8(a);
+// CHECK: ushll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #0
+}
+
+uint32x4_t test_vmovl_u16(uint16x4_t a) {
+// CHECK: test_vmovl_u16
+ return vmovl_u16(a);
+// CHECK: ushll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #0
+}
+
+uint64x2_t test_vmovl_u32(uint32x2_t a) {
+// CHECK: test_vmovl_u32
+ return vmovl_u32(a);
+// CHECK: ushll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #0
+}
+
+int16x8_t test_vmovl_high_s8(int8x16_t a) {
+// CHECK: test_vmovl_high_s8
+ return vmovl_high_s8(a);
+// CHECK: sshll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #0
+}
+
+int32x4_t test_vmovl_high_s16(int16x8_t a) {
+// CHECK: test_vmovl_high_s16
+ return vmovl_high_s16(a);
+// CHECK: sshll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #0
+}
+
+int64x2_t test_vmovl_high_s32(int32x4_t a) {
+// CHECK: test_vmovl_high_s32
+ return vmovl_high_s32(a);
+// CHECK: sshll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #0
+}
+
+uint16x8_t test_vmovl_high_u8(uint8x16_t a) {
+// CHECK: test_vmovl_high_u8
+ return vmovl_high_u8(a);
+// CHECK: ushll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #0
+}
+
+uint32x4_t test_vmovl_high_u16(uint16x8_t a) {
+// CHECK: test_vmovl_high_u16
+ return vmovl_high_u16(a);
+// CHECK: ushll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #0
+}
+
+uint64x2_t test_vmovl_high_u32(uint32x4_t a) {
+// CHECK: test_vmovl_high_u32
+ return vmovl_high_u32(a);
+// CHECK: ushll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #0
+}
+
+float32x2_t test_vcvt_n_f32_s32(int32x2_t a) {
+ // CHECK: test_vcvt_n_f32_s32
+ return vcvt_n_f32_s32(a, 31);
+ // CHECK: scvtf {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #31
+}
+
+float32x4_t test_vcvtq_n_f32_s32(int32x4_t a) {
+ // CHECK: test_vcvtq_n_f32_s32
+ return vcvtq_n_f32_s32(a, 31);
+ // CHECK: scvtf {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #31
+}
+
+float64x2_t test_vcvtq_n_f64_s64(int64x2_t a) {
+ // CHECK: test_vcvtq_n_f64_s64
+ return vcvtq_n_f64_s64(a, 50);
+ // CHECK: scvtf {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #50
+}
+
+float32x2_t test_vcvt_n_f32_u32(uint32x2_t a) {
+ // CHECK: test_vcvt_n_f32_u32
+ return vcvt_n_f32_u32(a, 31);
+ // CHECK: ucvtf {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #31
+}
+
+float32x4_t test_vcvtq_n_f32_u32(uint32x4_t a) {
+ // CHECK: test_vcvtq_n_f32_u32
+ return vcvtq_n_f32_u32(a, 31);
+ // CHECK: ucvtf {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #31
+}
+
+float64x2_t test_vcvtq_n_f64_u64(uint64x2_t a) {
+ // CHECK: test_vcvtq_n_f64_u64
+ return vcvtq_n_f64_u64(a, 50);
+ // CHECK: ucvtf {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #50
+}
+
+int32x2_t test_vcvt_n_s32_f32(float32x2_t a) {
+ // CHECK: test_vcvt_n_s32_f32
+ return vcvt_n_s32_f32(a, 31);
+ // CHECK: fcvtzs {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #31
+}
+
+int32x4_t test_vcvtq_n_s32_f32(float32x4_t a) {
+ // CHECK: test_vcvtq_n_s32_f32
+ return vcvtq_n_s32_f32(a, 31);
+ // CHECK: fcvtzs {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #31
+}
+
+int64x2_t test_vcvtq_n_s64_f64(float64x2_t a) {
+ // CHECK: test_vcvtq_n_s64_f64
+ return vcvtq_n_s64_f64(a, 50);
+ // CHECK: fcvtzs {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #50
+}
+
+uint32x2_t test_vcvt_n_u32_f32(float32x2_t a) {
+ // CHECK: test_vcvt_n_u32_f32
+ return vcvt_n_u32_f32(a, 31);
+ // CHECK: fcvtzu {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #31
+}
+
+uint32x4_t test_vcvtq_n_u32_f32(float32x4_t a) {
+ // CHECK: test_vcvt_n_u32_f32
+ return vcvtq_n_u32_f32(a, 31);
+ // CHECK: fcvtzu {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #31
+}
+
+uint64x2_t test_vcvtq_n_u64_f64(float64x2_t a) {
+ // CHECK: test_vcvtq_n_u64_f64
+ return vcvtq_n_u64_f64(a, 50);
+ // CHECK: fcvtzu {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #50
+}
+
+int16x8_t test_vaddl_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vaddl_s8
+ return vaddl_s8(a, b);
+ // CHECK: saddl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+
+int32x4_t test_vaddl_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vaddl_s16
+ return vaddl_s16(a, b);
+ // CHECK: saddl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vaddl_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vaddl_s32
+ return vaddl_s32(a, b);
+ // CHECK: saddl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+uint16x8_t test_vaddl_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vaddl_u8
+ return vaddl_u8(a, b);
+ // CHECK: uaddl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+
+uint32x4_t test_vaddl_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vaddl_u16
+ return vaddl_u16(a, b);
+ // CHECK: uaddl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+uint64x2_t test_vaddl_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vaddl_u32
+ return vaddl_u32(a, b);
+ // CHECK: uaddl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vaddl_high_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vaddl_high_s8
+ return vaddl_high_s8(a, b);
+ // CHECK: saddl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+
+int32x4_t test_vaddl_high_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vaddl_high_s16
+ return vaddl_high_s16(a, b);
+ // CHECK: saddl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vaddl_high_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vaddl_high_s32
+ return vaddl_high_s32(a, b);
+ // CHECK: saddl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint16x8_t test_vaddl_high_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vaddl_high_u8
+ return vaddl_high_u8(a, b);
+ // CHECK: uaddl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+
+uint32x4_t test_vaddl_high_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vaddl_high_u16
+ return vaddl_high_u16(a, b);
+ // CHECK: uaddl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint64x2_t test_vaddl_high_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vaddl_high_u32
+ return vaddl_high_u32(a, b);
+ // CHECK: uaddl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vaddw_s8(int16x8_t a, int8x8_t b) {
+ // CHECK: test_vaddw_s8
+ return vaddw_s8(a, b);
+ // CHECK: saddw {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.8b
+}
+
+int32x4_t test_vaddw_s16(int32x4_t a, int16x4_t b) {
+ // CHECK: test_vaddw_s16
+ return vaddw_s16(a, b);
+ // CHECK: saddw {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vaddw_s32(int64x2_t a, int32x2_t b) {
+ // CHECK: test_vaddw_s32
+ return vaddw_s32(a, b);
+ // CHECK: saddw {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.2s
+}
+
+uint16x8_t test_vaddw_u8(uint16x8_t a, uint8x8_t b) {
+ // CHECK: test_vaddw_u8
+ return vaddw_u8(a, b);
+ // CHECK: uaddw {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.8b
+}
+
+uint32x4_t test_vaddw_u16(uint32x4_t a, uint16x4_t b) {
+ // CHECK: test_vaddw_u16
+ return vaddw_u16(a, b);
+ // CHECK: uaddw {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.4h
+}
+
+uint64x2_t test_vaddw_u32(uint64x2_t a, uint32x2_t b) {
+ // CHECK: test_vaddw_u32
+ return vaddw_u32(a, b);
+ // CHECK: uaddw {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vaddw_high_s8(int16x8_t a, int8x16_t b) {
+ // CHECK: test_vaddw_high_s8
+ return vaddw_high_s8(a, b);
+ // CHECK: saddw2 {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.16b
+}
+
+int32x4_t test_vaddw_high_s16(int32x4_t a, int16x8_t b) {
+ // CHECK: test_vaddw_high_s16
+ return vaddw_high_s16(a, b);
+ // CHECK: saddw2 {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vaddw_high_s32(int64x2_t a, int32x4_t b) {
+ // CHECK: test_vaddw_high_s32
+ return vaddw_high_s32(a, b);
+ // CHECK: saddw2 {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.4s
+}
+
+uint16x8_t test_vaddw_high_u8(uint16x8_t a, uint8x16_t b) {
+ // CHECK: test_vaddw_high_u8
+ return vaddw_high_u8(a, b);
+ // CHECK: uaddw2 {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.16b
+}
+
+uint32x4_t test_vaddw_high_u16(uint32x4_t a, uint16x8_t b) {
+ // CHECK: test_vaddw_high_u16
+ return vaddw_high_u16(a, b);
+ // CHECK: uaddw2 {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.8h
+}
+
+uint64x2_t test_vaddw_high_u32(uint64x2_t a, uint32x4_t b) {
+ // CHECK: test_vaddw_high_u32
+ return vaddw_high_u32(a, b);
+ // CHECK: uaddw2 {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vsubl_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vsubl_s8
+ return vsubl_s8(a, b);
+ // CHECK: ssubl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+
+int32x4_t test_vsubl_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vsubl_s16
+ return vsubl_s16(a, b);
+ // CHECK: ssubl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vsubl_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vsubl_s32
+ return vsubl_s32(a, b);
+ // CHECK: ssubl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+uint16x8_t test_vsubl_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vsubl_u8
+ return vsubl_u8(a, b);
+ // CHECK: usubl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+
+uint32x4_t test_vsubl_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vsubl_u16
+ return vsubl_u16(a, b);
+ // CHECK: usubl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+uint64x2_t test_vsubl_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vsubl_u32
+ return vsubl_u32(a, b);
+ // CHECK: usubl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vsubl_high_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vsubl_high_s8
+ return vsubl_high_s8(a, b);
+ // CHECK: ssubl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+
+int32x4_t test_vsubl_high_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsubl_high_s16
+ return vsubl_high_s16(a, b);
+ // CHECK: ssubl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vsubl_high_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsubl_high_s32
+ return vsubl_high_s32(a, b);
+ // CHECK: ssubl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint16x8_t test_vsubl_high_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vsubl_high_u8
+ return vsubl_high_u8(a, b);
+ // CHECK: usubl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+
+uint32x4_t test_vsubl_high_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vsubl_high_u16
+ return vsubl_high_u16(a, b);
+ // CHECK: usubl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint64x2_t test_vsubl_high_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vsubl_high_u32
+ return vsubl_high_u32(a, b);
+ // CHECK: usubl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vsubw_s8(int16x8_t a, int8x8_t b) {
+ // CHECK: test_vsubw_s8
+ return vsubw_s8(a, b);
+ // CHECK: ssubw {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.8b
+}
+
+int32x4_t test_vsubw_s16(int32x4_t a, int16x4_t b) {
+ // CHECK: test_vsubw_s16
+ return vsubw_s16(a, b);
+ // CHECK: ssubw {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vsubw_s32(int64x2_t a, int32x2_t b) {
+ // CHECK: test_vsubw_s32
+ return vsubw_s32(a, b);
+ // CHECK: ssubw {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.2s
+}
+
+uint16x8_t test_vsubw_u8(uint16x8_t a, uint8x8_t b) {
+ // CHECK: test_vsubw_u8
+ return vsubw_u8(a, b);
+ // CHECK: usubw {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.8b
+}
+
+uint32x4_t test_vsubw_u16(uint32x4_t a, uint16x4_t b) {
+ // CHECK: test_vsubw_u16
+ return vsubw_u16(a, b);
+ // CHECK: usubw {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.4h
+}
+
+uint64x2_t test_vsubw_u32(uint64x2_t a, uint32x2_t b) {
+ // CHECK: test_vsubw_u32
+ return vsubw_u32(a, b);
+ // CHECK: usubw {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vsubw_high_s8(int16x8_t a, int8x16_t b) {
+ // CHECK: test_vsubw_high_s8
+ return vsubw_high_s8(a, b);
+ // CHECK: ssubw2 {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.16b
+}
+
+int32x4_t test_vsubw_high_s16(int32x4_t a, int16x8_t b) {
+ // CHECK: test_vsubw_high_s16
+ return vsubw_high_s16(a, b);
+ // CHECK: ssubw2 {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vsubw_high_s32(int64x2_t a, int32x4_t b) {
+ // CHECK: test_vsubw_high_s32
+ return vsubw_high_s32(a, b);
+ // CHECK: ssubw2 {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.4s
+}
+
+uint16x8_t test_vsubw_high_u8(uint16x8_t a, uint8x16_t b) {
+ // CHECK: test_vsubw_high_u8
+ return vsubw_high_u8(a, b);
+ // CHECK: usubw2 {{v[0-31]+}}.8h, {{v[0-31]+}}.8h, {{v[0-31]+}}.16b
+}
+
+uint32x4_t test_vsubw_high_u16(uint32x4_t a, uint16x8_t b) {
+ // CHECK: test_vsubw_high_u16
+ return vsubw_high_u16(a, b);
+ // CHECK: usubw2 {{v[0-31]+}}.4s, {{v[0-31]+}}.4s, {{v[0-31]+}}.8h
+}
+
+uint64x2_t test_vsubw_high_u32(uint64x2_t a, uint32x4_t b) {
+ // CHECK: test_vsubw_high_u32
+ return vsubw_high_u32(a, b);
+ // CHECK: usubw2 {{v[0-31]+}}.2d, {{v[0-31]+}}.2d, {{v[0-31]+}}.4s
+}
+
+int8x8_t test_vaddhn_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vaddhn_s16
+ return vaddhn_s16(a, b);
+ // CHECK: addhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x4_t test_vaddhn_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vaddhn_s32
+ return vaddhn_s32(a, b);
+ // CHECK: addhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x2_t test_vaddhn_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vaddhn_s64
+ return vaddhn_s64(a, b);
+ // CHECK: addhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x8_t test_vaddhn_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vaddhn_u16
+ return vaddhn_u16(a, b);
+ // CHECK: addhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x4_t test_vaddhn_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vaddhn_u32
+ return vaddhn_u32(a, b);
+ // CHECK: addhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x2_t test_vaddhn_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vaddhn_u64
+ return vaddhn_u64(a, b);
+ // CHECK: addhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x16_t test_vaddhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+ // CHECK: test_vaddhn_high_s16
+ return vaddhn_high_s16(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x8_t test_vaddhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+ // CHECK: test_vaddhn_high_s32
+ return vaddhn_high_s32(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vaddhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+ // CHECK: test_vaddhn_high_s64
+ return vaddhn_high_s64(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x16_t test_vaddhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vaddhn_high_u16
+ return vaddhn_high_u16(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x8_t test_vaddhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vaddhn_high_u32
+ return vaddhn_high_u32(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x4_t test_vaddhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vaddhn_high_u64
+ return vaddhn_high_u64(r, a, b);
+ // CHECK: addhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vraddhn_s16
+ return vraddhn_s16(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vraddhn_s32
+ return vraddhn_s32(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vraddhn_s64
+ return vraddhn_s64(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vraddhn_u16
+ return vraddhn_u16(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vraddhn_u32
+ return vraddhn_u32(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vraddhn_u64
+ return vraddhn_u64(a, b);
+ // CHECK: raddhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x16_t test_vraddhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+ // CHECK: test_vraddhn_high_s16
+ return vraddhn_high_s16(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x8_t test_vraddhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+ // CHECK: test_vraddhn_high_s32
+ return vraddhn_high_s32(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vraddhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+ // CHECK: test_vraddhn_high_s64
+ return vraddhn_high_s64(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x16_t test_vraddhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vraddhn_high_u16
+ return vraddhn_high_u16(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x8_t test_vraddhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vraddhn_high_u32
+ return vraddhn_high_u32(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x4_t test_vraddhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vraddhn_high_u64
+ return vraddhn_high_u64(r, a, b);
+ // CHECK: raddhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x8_t test_vsubhn_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsubhn_s16
+ return vsubhn_s16(a, b);
+ // CHECK: subhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x4_t test_vsubhn_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsubhn_s32
+ return vsubhn_s32(a, b);
+ // CHECK: subhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x2_t test_vsubhn_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsubhn_s64
+ return vsubhn_s64(a, b);
+ // CHECK: subhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x8_t test_vsubhn_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vsubhn_u16
+ return vsubhn_u16(a, b);
+ // CHECK: subhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x4_t test_vsubhn_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vsubhn_u32
+ return vsubhn_u32(a, b);
+ // CHECK: subhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x2_t test_vsubhn_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vsubhn_u64
+ return vsubhn_u64(a, b);
+ // CHECK: subhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x16_t test_vsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+ // CHECK: test_vsubhn_high_s16
+ return vsubhn_high_s16(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x8_t test_vsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+ // CHECK: test_vsubhn_high_s32
+ return vsubhn_high_s32(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+ // CHECK: test_vsubhn_high_s64
+ return vsubhn_high_s64(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x16_t test_vsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vsubhn_high_u16
+ return vsubhn_high_u16(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x8_t test_vsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vsubhn_high_u32
+ return vsubhn_high_u32(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x4_t test_vsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vsubhn_high_u64
+ return vsubhn_high_u64(r, a, b);
+ // CHECK: subhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vrsubhn_s16
+ return vrsubhn_s16(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vrsubhn_s32
+ return vrsubhn_s32(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vrsubhn_s64
+ return vrsubhn_s64(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vrsubhn_u16
+ return vrsubhn_u16(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.8b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vrsubhn_u32
+ return vrsubhn_u32(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.4h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vrsubhn_u64
+ return vrsubhn_u64(a, b);
+ // CHECK: rsubhn {{v[0-31]+}}.2s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int8x16_t test_vrsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
+ // CHECK: test_vrsubhn_high_s16
+ return vrsubhn_high_s16(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int16x8_t test_vrsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
+ // CHECK: test_vrsubhn_high_s32
+ return vrsubhn_high_s32(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vrsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
+ // CHECK: test_vrsubhn_high_s64
+ return vrsubhn_high_s64(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+uint8x16_t test_vrsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vrsubhn_high_u16
+ return vrsubhn_high_u16(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.16b, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+uint16x8_t test_vrsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vrsubhn_high_u32
+ return vrsubhn_high_u32(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.8h, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+uint32x4_t test_vrsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vrsubhn_high_u64
+ return vrsubhn_high_u64(r, a, b);
+ // CHECK: rsubhn2 {{v[0-31]+}}.4s, {{v[0-31]+}}.2d, {{v[0-31]+}}.2d
+}
+
+int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vabdl_s8
+ return vabdl_s8(a, b);
+ // CHECK: sabdl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+int32x4_t test_vabdl_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vabdl_s16
+ return vabdl_s16(a, b);
+ // CHECK: sabdl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vabdl_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vabdl_s32
+ return vabdl_s32(a, b);
+ // CHECK: sabdl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vabdl_u8
+ return vabdl_u8(a, b);
+ // CHECK: uabdl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+uint32x4_t test_vabdl_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vabdl_u16
+ return vabdl_u16(a, b);
+ // CHECK: uabdl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+uint64x2_t test_vabdl_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vabdl_u32
+ return vabdl_u32(a, b);
+ // CHECK: uabdl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vabal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ // CHECK: test_vabal_s8
+ return vabal_s8(a, b, c);
+ // CHECK: sabal {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+int32x4_t test_vabal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ // CHECK: test_vabal_s16
+ return vabal_s16(a, b, c);
+ // CHECK: sabal {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vabal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ // CHECK: test_vabal_s32
+ return vabal_s32(a, b, c);
+ // CHECK: sabal {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+uint16x8_t test_vabal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ // CHECK: test_vabal_u8
+ return vabal_u8(a, b, c);
+ // CHECK: uabal {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+uint32x4_t test_vabal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ // CHECK: test_vabal_u16
+ return vabal_u16(a, b, c);
+ // CHECK: uabal {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+uint64x2_t test_vabal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ // CHECK: test_vabal_u32
+ return vabal_u32(a, b, c);
+ // CHECK: uabal {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vabdl_high_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vabdl_high_s8
+ return vabdl_high_s8(a, b);
+ // CHECK: sabdl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+int32x4_t test_vabdl_high_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vabdl_high_s16
+ return vabdl_high_s16(a, b);
+ // CHECK: sabdl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vabdl_high_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vabdl_high_s32
+ return vabdl_high_s32(a, b);
+ // CHECK: sabdl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+uint16x8_t test_vabdl_high_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vabdl_high_u8
+ return vabdl_high_u8(a, b);
+ // CHECK: uabdl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+uint32x4_t test_vabdl_high_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vabdl_high_u16
+ return vabdl_high_u16(a, b);
+ // CHECK: uabdl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+uint64x2_t test_vabdl_high_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vabdl_high_u32
+ return vabdl_high_u32(a, b);
+ // CHECK: uabdl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vabal_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
+ // CHECK: test_vabal_high_s8
+ return vabal_high_s8(a, b, c);
+ // CHECK: sabal2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+int32x4_t test_vabal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
+ // CHECK: test_vabal_high_s16
+ return vabal_high_s16(a, b, c);
+ // CHECK: sabal2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vabal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
+ // CHECK: test_vabal_high_s32
+ return vabal_high_s32(a, b, c);
+ // CHECK: sabal2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+uint16x8_t test_vabal_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
+ // CHECK: test_vabal_high_u8
+ return vabal_high_u8(a, b, c);
+ // CHECK: uabal2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+uint32x4_t test_vabal_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
+ // CHECK: test_vabal_high_u16
+ return vabal_high_u16(a, b, c);
+ // CHECK: uabal2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+uint64x2_t test_vabal_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
+ // CHECK: test_vabal_high_u32
+ return vabal_high_u32(a, b, c);
+ // CHECK: uabal2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vmull_s8
+ return vmull_s8(a, b);
+ // CHECK: smull {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vmull_s16
+ return vmull_s16(a, b);
+ // CHECK: smull {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vmull_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vmull_s32
+ return vmull_s32(a, b);
+ // CHECK: smull {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vmull_u8
+ return vmull_u8(a, b);
+ // CHECK: umull {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vmull_u16
+ return vmull_u16(a, b);
+ // CHECK: umull {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+uint64x2_t test_vmull_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vmull_u32
+ return vmull_u32(a, b);
+ // CHECK: umull {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vmull_high_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vmull_high_s8
+ return vmull_high_s8(a, b);
+ // CHECK: smull2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+int32x4_t test_vmull_high_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vmull_high_s16
+ return vmull_high_s16(a, b);
+ // CHECK: smull2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vmull_high_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vmull_high_s32
+ return vmull_high_s32(a, b);
+ // CHECK: smull2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+uint16x8_t test_vmull_high_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vmull_high_u8
+ return vmull_high_u8(a, b);
+ // CHECK: umull2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+uint32x4_t test_vmull_high_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vmull_high_u16
+ return vmull_high_u16(a, b);
+ // CHECK: umull2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+uint64x2_t test_vmull_high_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vmull_high_u32
+ return vmull_high_u32(a, b);
+ // CHECK: umull2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ // CHECK: test_vmlal_s8
+ return vmlal_s8(a, b, c);
+ // CHECK: smlal {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ // CHECK: test_vmlal_s16
+ return vmlal_s16(a, b, c);
+ // CHECK: smlal {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ // CHECK: test_vmlal_s32
+ return vmlal_s32(a, b, c);
+ // CHECK: smlal {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ // CHECK: test_vmlal_u8
+ return vmlal_u8(a, b, c);
+ // CHECK: umlal {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ // CHECK: test_vmlal_u16
+ return vmlal_u16(a, b, c);
+ // CHECK: umlal {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ // CHECK: test_vmlal_u32
+ return vmlal_u32(a, b, c);
+ // CHECK: umlal {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vmlal_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
+ // CHECK: test_vmlal_high_s8
+ return vmlal_high_s8(a, b, c);
+ // CHECK: smlal2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+int32x4_t test_vmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
+ // CHECK: test_vmlal_high_s16
+ return vmlal_high_s16(a, b, c);
+ // CHECK: smlal2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
+ // CHECK: test_vmlal_high_s32
+ return vmlal_high_s32(a, b, c);
+ // CHECK: smlal2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+uint16x8_t test_vmlal_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
+ // CHECK: test_vmlal_high_u8
+ return vmlal_high_u8(a, b, c);
+ // CHECK: umlal2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+uint32x4_t test_vmlal_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
+ // CHECK: test_vmlal_high_u16
+ return vmlal_high_u16(a, b, c);
+ // CHECK: umlal2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+uint64x2_t test_vmlal_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
+ // CHECK: test_vmlal_high_u32
+ return vmlal_high_u32(a, b, c);
+ // CHECK: umlal2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ // CHECK: test_vmlsl_s8
+ return vmlsl_s8(a, b, c);
+ // CHECK: smlsl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ // CHECK: test_vmlsl_s16
+ return vmlsl_s16(a, b, c);
+ // CHECK: smlsl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ // CHECK: test_vmlsl_s32
+ return vmlsl_s32(a, b, c);
+ // CHECK: smlsl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ // CHECK: test_vmlsl_u8
+ return vmlsl_u8(a, b, c);
+ // CHECK: umlsl {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ // CHECK: test_vmlsl_u16
+ return vmlsl_u16(a, b, c);
+ // CHECK: umlsl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ // CHECK: test_vmlsl_u32
+ return vmlsl_u32(a, b, c);
+ // CHECK: umlsl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int16x8_t test_vmlsl_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
+ // CHECK: test_vmlsl_high_s8
+ return vmlsl_high_s8(a, b, c);
+ // CHECK: smlsl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+int32x4_t test_vmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
+ // CHECK: test_vmlsl_high_s16
+ return vmlsl_high_s16(a, b, c);
+ // CHECK: smlsl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vmlsl_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
+ // CHECK: test_vmlsl_high_s32
+ return vmlsl_high_s32(a, b, c);
+ // CHECK: smlsl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+uint16x8_t test_vmlsl_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
+ // CHECK: test_vmlsl_high_u8
+ return vmlsl_high_u8(a, b, c);
+ // CHECK: umlsl2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+uint32x4_t test_vmlsl_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
+ // CHECK: test_vmlsl_high_u16
+ return vmlsl_high_u16(a, b, c);
+ // CHECK: umlsl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+uint64x2_t test_vmlsl_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
+ // CHECK: test_vmlsl_high_u32
+ return vmlsl_high_u32(a, b, c);
+ // CHECK: umlsl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vqdmull_s16
+ return vqdmull_s16(a, b);
+ // CHECK: sqdmull {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vqdmull_s32
+ return vqdmull_s32(a, b);
+ // CHECK: sqdmull {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ // CHECK: test_vqdmlal_s16
+ return vqdmlal_s16(a, b, c);
+ // CHECK: sqdmlal {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ // CHECK: test_vqdmlal_s32
+ return vqdmlal_s32(a, b, c);
+ // CHECK: sqdmlal {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ // CHECK: test_vqdmlsl_s16
+ return vqdmlsl_s16(a, b, c);
+ // CHECK: sqdmlsl {{v[0-31]+}}.4s, {{v[0-31]+}}.4h, {{v[0-31]+}}.4h
+}
+
+int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ // CHECK: test_vqdmlsl_s32
+ return vqdmlsl_s32(a, b, c);
+ // CHECK: sqdmlsl {{v[0-31]+}}.2d, {{v[0-31]+}}.2s, {{v[0-31]+}}.2s
+}
+
+int32x4_t test_vqdmull_high_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vqdmull_high_s16
+ return vqdmull_high_s16(a, b);
+ // CHECK: sqdmull2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+int64x2_t test_vqdmull_high_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vqdmull_high_s32
+ return vqdmull_high_s32(a, b);
+ // CHECK: sqdmull2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vqdmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
+ // CHECK: test_vqdmlal_high_s16
+ return vqdmlal_high_s16(a, b, c);
+ // CHECK: sqdmlal2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vqdmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
+ // CHECK: test_vqdmlal_high_s32
+ return vqdmlal_high_s32(a, b, c);
+ // CHECK: sqdmlal2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+int32x4_t test_vqdmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
+ // CHECK: test_vqdmlsl_high_s16
+ return vqdmlsl_high_s16(a, b, c);
+ // CHECK: sqdmlsl2 {{v[0-31]+}}.4s, {{v[0-31]+}}.8h, {{v[0-31]+}}.8h
+}
+
+int64x2_t test_vqdmlsl_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
+ // CHECK: test_vqdmlsl_high_s32
+ return vqdmlsl_high_s32(a, b, c);
+ // CHECK: sqdmlsl2 {{v[0-31]+}}.2d, {{v[0-31]+}}.4s, {{v[0-31]+}}.4s
+}
+
+poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vmull_p8
+ return vmull_p8(a, b);
+ // CHECK: pmull {{v[0-31]+}}.8h, {{v[0-31]+}}.8b, {{v[0-31]+}}.8b
+}
+
+poly16x8_t test_vmull_high_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vmull_high_p8
+ return vmull_high_p8(a, b);
+ // CHECK: pmull2 {{v[0-31]+}}.8h, {{v[0-31]+}}.16b, {{v[0-31]+}}.16b
+}
+
+int64_t test_vaddd_s64(int64_t a, int64_t b) {
+// CHECK: test_vaddd_s64
+ return vaddd_s64(a, b);
+// CHECK: add {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64_t test_vaddd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vaddd_u64
+ return vaddd_u64(a, b);
+// CHECK: add {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int64_t test_vsubd_s64(int64_t a, int64_t b) {
+// CHECK: test_vsubd_s64
+ return vsubd_s64(a, b);
+// CHECK: sub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64_t test_vsubd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vsubd_u64
+ return vsubd_u64(a, b);
+// CHECK: sub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8_t test_vqaddb_s8(int8_t a, int8_t b) {
+// CHECK: test_vqaddb_s8
+ return vqaddb_s8(a, b);
+// CHECK: sqadd {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+int16_t test_vqaddh_s16(int16_t a, int16_t b) {
+// CHECK: test_vqaddh_s16
+ return vqaddh_s16(a, b);
+// CHECK: sqadd {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+int32_t test_vqadds_s32(int32_t a, int32_t b) {
+// CHECK: test_vqadds_s32
+ return vqadds_s32(a, b);
+// CHECK: sqadd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+int64_t test_vqaddd_s64(int64_t a, int64_t b) {
+// CHECK: test_vqaddd_s64
+ return vqaddd_s64(a, b);
+// CHECK: sqadd {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8_t test_vqaddb_u8(uint8_t a, uint8_t b) {
+// CHECK: test_vqaddb_u8
+ return vqaddb_u8(a, b);
+// CHECK: uqadd {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+uint16_t test_vqaddh_u16(uint16_t a, uint16_t b) {
+// CHECK: test_vqaddh_u16
+ return vqaddh_u16(a, b);
+// CHECK: uqadd {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+uint32_t test_vqadds_u32(uint32_t a, uint32_t b) {
+// CHECK: test_vqadds_u32
+ return vqadds_u32(a, b);
+// CHECK: uqadd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+uint64_t test_vqaddd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vqaddd_u64
+ return vqaddd_u64(a, b);
+// CHECK: uqadd {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int8_t test_vqsubb_s8(int8_t a, int8_t b) {
+// CHECK: test_vqsubb_s8
+ return vqsubb_s8(a, b);
+// CHECK: sqsub {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+int16_t test_vqsubh_s16(int16_t a, int16_t b) {
+// CHECK: test_vqsubh_s16
+ return vqsubh_s16(a, b);
+// CHECK: sqsub {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+int32_t test_vqsubs_s32(int32_t a, int32_t b) {
+ // CHECK: test_vqsubs_s32
+ return vqsubs_s32(a, b);
+// CHECK: sqsub {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+int64_t test_vqsubd_s64(int64_t a, int64_t b) {
+// CHECK: test_vqsubd_s64
+ return vqsubd_s64(a, b);
+// CHECK: sqsub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint8_t test_vqsubb_u8(uint8_t a, uint8_t b) {
+// CHECK: test_vqsubb_u8
+ return vqsubb_u8(a, b);
+// CHECK: uqsub {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+uint16_t test_vqsubh_u16(uint16_t a, uint16_t b) {
+// CHECK: test_vqsubh_u16
+ return vqsubh_u16(a, b);
+// CHECK: uqsub {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+uint32_t test_vqsubs_u32(uint32_t a, uint32_t b) {
+// CHECK: test_vqsubs_u32
+ return vqsubs_u32(a, b);
+// CHECK: uqsub {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+uint64_t test_vqsubd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vqsubd_u64
+ return vqsubd_u64(a, b);
+// CHECK: uqsub {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+int64_t test_vshld_s64(int64_t a, int64_t b) {
+// CHECK: test_vshld_s64
+ return vshld_s64(a, b);
+// CHECK: sshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64_t test_vshld_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vshld_u64
+ return vshld_u64(a, b);
+// CHECK: ushl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vqshlb_s8
+int8_t test_vqshlb_s8(int8_t a, int8_t b) {
+ return vqshlb_s8(a, b);
+// CHECK: sqshl {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+// CHECK: test_vqshlh_s16
+int16_t test_vqshlh_s16(int16_t a, int16_t b) {
+ return vqshlh_s16(a, b);
+// CHECK: sqshl {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+// CHECK: test_vqshls_s32
+int32_t test_vqshls_s32(int32_t a, int32_t b) {
+ return vqshls_s32(a, b);
+// CHECK: sqshl {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+// CHECK: test_vqshld_s64
+int64_t test_vqshld_s64(int64_t a, int64_t b) {
+ return vqshld_s64(a, b);
+// CHECK: sqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vqshlb_u8
+uint8_t test_vqshlb_u8(uint8_t a, uint8_t b) {
+ return vqshlb_u8(a, b);
+// CHECK: uqshl {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+// CHECK: test_vqshlh_u16
+uint16_t test_vqshlh_u16(uint16_t a, uint16_t b) {
+ return vqshlh_u16(a, b);
+// CHECK: uqshl {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+// CHECK: test_vqshls_u32
+uint32_t test_vqshls_u32(uint32_t a, uint32_t b) {
+ return vqshls_u32(a, b);
+// CHECK: uqshl {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+// CHECK: test_vqshld_u64
+uint64_t test_vqshld_u64(uint64_t a, uint64_t b) {
+ return vqshld_u64(a, b);
+// CHECK: uqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vrshld_s64
+int64_t test_vrshld_s64(int64_t a, int64_t b) {
+ return vrshld_s64(a, b);
+// CHECK: srshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+
+// CHECK: test_vrshld_u64
+uint64_t test_vrshld_u64(uint64_t a, uint64_t b) {
+ return vrshld_u64(a, b);
+// CHECK: urshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vqrshlb_s8
+int8_t test_vqrshlb_s8(int8_t a, int8_t b) {
+ return vqrshlb_s8(a, b);
+// CHECK: sqrshl {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+// CHECK: test_vqrshlh_s16
+int16_t test_vqrshlh_s16(int16_t a, int16_t b) {
+ return vqrshlh_s16(a, b);
+// CHECK: sqrshl {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+// CHECK: test_vqrshls_s32
+int32_t test_vqrshls_s32(int32_t a, int32_t b) {
+ return vqrshls_s32(a, b);
+// CHECK: sqrshl {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+// CHECK: test_vqrshld_s64
+int64_t test_vqrshld_s64(int64_t a, int64_t b) {
+ return vqrshld_s64(a, b);
+// CHECK: sqrshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vqrshlb_u8
+uint8_t test_vqrshlb_u8(uint8_t a, uint8_t b) {
+ return vqrshlb_u8(a, b);
+// CHECK: uqrshl {{b[0-9]+}}, {{b[0-9]+}}, {{b[0-9]+}}
+}
+
+// CHECK: test_vqrshlh_u16
+uint16_t test_vqrshlh_u16(uint16_t a, uint16_t b) {
+ return vqrshlh_u16(a, b);
+// CHECK: uqrshl {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+// CHECK: test_vqrshls_u32
+uint32_t test_vqrshls_u32(uint32_t a, uint32_t b) {
+ return vqrshls_u32(a, b);
+// CHECK: uqrshl {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+// CHECK: test_vqrshld_u64
+uint64_t test_vqrshld_u64(uint64_t a, uint64_t b) {
+ return vqrshld_u64(a, b);
+// CHECK: uqrshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vpaddd_s64
+int64_t test_vpaddd_s64(int64x2_t a) {
+ return vpaddd_s64(a);
+// CHECK: addp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vpadds_f32
+float32_t test_vpadds_f32(float32x2_t a) {
+ return vpadds_f32(a);
+// CHECK: faddp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+// CHECK: test_vpaddd_f64
+float64_t test_vpaddd_f64(float64x2_t a) {
+ return vpaddd_f64(a);
+// CHECK: faddp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vpmaxnms_f32
+float32_t test_vpmaxnms_f32(float32x2_t a) {
+ return vpmaxnms_f32(a);
+// CHECK: fmaxnmp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+// CHECK: test_vpmaxnmqd_f64
+float64_t test_vpmaxnmqd_f64(float64x2_t a) {
+ return vpmaxnmqd_f64(a);
+// CHECK: fmaxnmp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vpmaxs_f32
+float32_t test_vpmaxs_f32(float32x2_t a) {
+ return vpmaxs_f32(a);
+// CHECK: fmaxp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+// CHECK: test_vpmaxqd_f64
+float64_t test_vpmaxqd_f64(float64x2_t a) {
+ return vpmaxqd_f64(a);
+// CHECK: fmaxp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vpminnms_f32
+float32_t test_vpminnms_f32(float32x2_t a) {
+ return vpminnms_f32(a);
+// CHECK: fminnmp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+// CHECK: test_vpminnmqd_f64
+float64_t test_vpminnmqd_f64(float64x2_t a) {
+ return vpminnmqd_f64(a);
+// CHECK: fminnmp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+// CHECK: test_vpmins_f32
+float32_t test_vpmins_f32(float32x2_t a) {
+ return vpmins_f32(a);
+// CHECK: fminp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+// CHECK: test_vpminqd_f64
+float64_t test_vpminqd_f64(float64x2_t a) {
+ return vpminqd_f64(a);
+// CHECK: fminp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+int16_t test_vqdmulhh_s16(int16_t a, int16_t b) {
+// CHECK: test_vqdmulhh_s16
+ return vqdmulhh_s16(a, b);
+// CHECK: sqdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+int32_t test_vqdmulhs_s32(int32_t a, int32_t b) {
+// CHECK: test_vqdmulhs_s32
+ return vqdmulhs_s32(a, b);
+// CHECK: sqdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+int16_t test_vqrdmulhh_s16(int16_t a, int16_t b) {
+// CHECK: test_vqrdmulhh_s16
+ return vqrdmulhh_s16(a, b);
+// CHECK: sqrdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+}
+
+int32_t test_vqrdmulhs_s32(int32_t a, int32_t b) {
+// CHECK: test_vqrdmulhs_s32
+ return vqrdmulhs_s32(a, b);
+// CHECK: sqrdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+float32_t test_vmulxs_f32(float32_t a, float32_t b) {
+// CHECK: test_vmulxs_f32
+ return vmulxs_f32(a, b);
+// CHECK: fmulx {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+float64_t test_vmulxd_f64(float64_t a, float64_t b) {
+// CHECK: test_vmulxd_f64
+ return vmulxd_f64(a, b);
+// CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+float32_t test_vrecpss_f32(float32_t a, float32_t b) {
+// CHECK: test_vrecpss_f32
+ return vrecpss_f32(a, b);
+// CHECK: frecps {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+float64_t test_vrecpsd_f64(float64_t a, float64_t b) {
+// CHECK: test_vrecpsd_f64
+ return vrecpsd_f64(a, b);
+// CHECK: frecps {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+float32_t test_vrsqrtss_f32(float32_t a, float32_t b) {
+// CHECK: test_vrsqrtss_f32
+ return vrsqrtss_f32(a, b);
+// CHECK: frsqrts {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+}
+
+float64_t test_vrsqrtsd_f64(float64_t a, float64_t b) {
+// CHECK: test_vrsqrtsd_f64
+ return vrsqrtsd_f64(a, b);
+// CHECK: frsqrts {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+float32_t test_vcvts_f32_s32(int32_t a) {
+// CHECK: test_vcvts_f32_s32
+// CHECK: scvtf {{s[0-9]+}}, {{s[0-9]+}}
+ return vcvts_f32_s32(a);
+}
+
+float64_t test_vcvtd_f64_s64(int64_t a) {
+// CHECK: test_vcvtd_f64_s64
+// CHECK: scvtf {{d[0-9]+}}, {{d[0-9]+}}
+ return vcvtd_f64_s64(a);
+}
+
+float32_t test_vcvts_f32_u32(uint32_t a) {
+// CHECK: test_vcvts_f32_u32
+// CHECK: ucvtf {{s[0-9]+}}, {{s[0-9]+}}
+ return vcvts_f32_u32(a);
+}
+
+float64_t test_vcvtd_f64_u64(uint64_t a) {
+// CHECK: test_vcvtd_f64_u64
+// CHECK: ucvtf {{d[0-9]+}}, {{d[0-9]+}}
+ return vcvtd_f64_u64(a);
+}
+
+float32_t test_vrecpes_f32(float32_t a) {
+// CHECK: test_vrecpes_f32
+// CHECK: frecpe {{s[0-9]+}}, {{s[0-9]+}}
+ return vrecpes_f32(a);
+}
+
+float64_t test_vrecped_f64(float64_t a) {
+// CHECK: test_vrecped_f64
+// CHECK: frecpe {{d[0-9]+}}, {{d[0-9]+}}
+ return vrecped_f64(a);
+}
+
+float32_t test_vrecpxs_f32(float32_t a) {
+// CHECK: test_vrecpxs_f32
+// CHECK: frecpx {{s[0-9]+}}, {{s[0-9]+}}
+ return vrecpxs_f32(a);
+ }
+
+float64_t test_vrecpxd_f64(float64_t a) {
+// CHECK: test_vrecpxd_f64
+// CHECK: frecpx {{d[0-9]+}}, {{d[0-9]+}}
+ return vrecpxd_f64(a);
+}
+
+float32_t test_vrsqrtes_f32(float32_t a) {
+// CHECK: vrsqrtes_f32
+// CHECK: frsqrte {{s[0-9]+}}, {{s[0-9]+}}
+ return vrsqrtes_f32(a);
+}
+
+float64_t test_vrsqrted_f64(float64_t a) {
+// CHECK: vrsqrted_f64
+// CHECK: frsqrte {{d[0-9]+}}, {{d[0-9]+}}
+ return vrsqrted_f64(a);
+}
+
+uint8x16_t test_vld1q_u8(uint8_t const *a) {
+ // CHECK: test_vld1q_u8
+ return vld1q_u8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8_t test_vld1q_u16(uint16_t const *a) {
+ // CHECK: test_vld1q_u16
+ return vld1q_u16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4_t test_vld1q_u32(uint32_t const *a) {
+ // CHECK: test_vld1q_u32
+ return vld1q_u32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2_t test_vld1q_u64(uint64_t const *a) {
+ // CHECK: test_vld1q_u64
+ return vld1q_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16_t test_vld1q_s8(int8_t const *a) {
+ // CHECK: test_vld1q_s8
+ return vld1q_s8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8_t test_vld1q_s16(int16_t const *a) {
+ // CHECK: test_vld1q_s16
+ return vld1q_s16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4_t test_vld1q_s32(int32_t const *a) {
+ // CHECK: test_vld1q_s32
+ return vld1q_s32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2_t test_vld1q_s64(int64_t const *a) {
+ // CHECK: test_vld1q_s64
+ return vld1q_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8_t test_vld1q_f16(float16_t const *a) {
+ // CHECK: test_vld1q_f16
+ return vld1q_f16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4_t test_vld1q_f32(float32_t const *a) {
+ // CHECK: test_vld1q_f32
+ return vld1q_f32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2_t test_vld1q_f64(float64_t const *a) {
+ // CHECK: test_vld1q_f64
+ return vld1q_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16_t test_vld1q_p8(poly8_t const *a) {
+ // CHECK: test_vld1q_p8
+ return vld1q_p8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8_t test_vld1q_p16(poly16_t const *a) {
+ // CHECK: test_vld1q_p16
+ return vld1q_p16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8_t test_vld1_u8(uint8_t const *a) {
+ // CHECK: test_vld1_u8
+ return vld1_u8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4_t test_vld1_u16(uint16_t const *a) {
+ // CHECK: test_vld1_u16
+ return vld1_u16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2_t test_vld1_u32(uint32_t const *a) {
+ // CHECK: test_vld1_u32
+ return vld1_u32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1_t test_vld1_u64(uint64_t const *a) {
+ // CHECK: test_vld1_u64
+ return vld1_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8_t test_vld1_s8(int8_t const *a) {
+ // CHECK: test_vld1_s8
+ return vld1_s8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4_t test_vld1_s16(int16_t const *a) {
+ // CHECK: test_vld1_s16
+ return vld1_s16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2_t test_vld1_s32(int32_t const *a) {
+ // CHECK: test_vld1_s32
+ return vld1_s32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1_t test_vld1_s64(int64_t const *a) {
+ // CHECK: test_vld1_s64
+ return vld1_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4_t test_vld1_f16(float16_t const *a) {
+ // CHECK: test_vld1_f16
+ return vld1_f16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2_t test_vld1_f32(float32_t const *a) {
+ // CHECK: test_vld1_f32
+ return vld1_f32(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1_t test_vld1_f64(float64_t const *a) {
+ // CHECK: test_vld1_f64
+ return vld1_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8_t test_vld1_p8(poly8_t const *a) {
+ // CHECK: test_vld1_p8
+ return vld1_p8(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4_t test_vld1_p16(poly16_t const *a) {
+ // CHECK: test_vld1_p16
+ return vld1_p16(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x2_t test_vld2q_u8(uint8_t const *a) {
+ // CHECK: test_vld2q_u8
+ return vld2q_u8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x2_t test_vld2q_u16(uint16_t const *a) {
+ // CHECK: test_vld2q_u16
+ return vld2q_u16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x2_t test_vld2q_u32(uint32_t const *a) {
+ // CHECK: test_vld2q_u32
+ return vld2q_u32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x2_t test_vld2q_u64(uint64_t const *a) {
+ // CHECK: test_vld2q_u64
+ return vld2q_u64(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x2_t test_vld2q_s8(int8_t const *a) {
+ // CHECK: test_vld2q_s8
+ return vld2q_s8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x2_t test_vld2q_s16(int16_t const *a) {
+ // CHECK: test_vld2q_s16
+ return vld2q_s16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x2_t test_vld2q_s32(int32_t const *a) {
+ // CHECK: test_vld2q_s32
+ return vld2q_s32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x2_t test_vld2q_s64(int64_t const *a) {
+ // CHECK: test_vld2q_s64
+ return vld2q_s64(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x2_t test_vld2q_f16(float16_t const *a) {
+ // CHECK: test_vld2q_f16
+ return vld2q_f16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x2_t test_vld2q_f32(float32_t const *a) {
+ // CHECK: test_vld2q_f32
+ return vld2q_f32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x2_t test_vld2q_f64(float64_t const *a) {
+ // CHECK: test_vld2q_f64
+ return vld2q_f64(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x2_t test_vld2q_p8(poly8_t const *a) {
+ // CHECK: test_vld2q_p8
+ return vld2q_p8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x2_t test_vld2q_p16(poly16_t const *a) {
+ // CHECK: test_vld2q_p16
+ return vld2q_p16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x2_t test_vld2_u8(uint8_t const *a) {
+ // CHECK: test_vld2_u8
+ return vld2_u8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x2_t test_vld2_u16(uint16_t const *a) {
+ // CHECK: test_vld2_u16
+ return vld2_u16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x2_t test_vld2_u32(uint32_t const *a) {
+ // CHECK: test_vld2_u32
+ return vld2_u32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x2_t test_vld2_u64(uint64_t const *a) {
+ // CHECK: test_vld2_u64
+ return vld2_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x2_t test_vld2_s8(int8_t const *a) {
+ // CHECK: test_vld2_s8
+ return vld2_s8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x2_t test_vld2_s16(int16_t const *a) {
+ // CHECK: test_vld2_s16
+ return vld2_s16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x2_t test_vld2_s32(int32_t const *a) {
+ // CHECK: test_vld2_s32
+ return vld2_s32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x2_t test_vld2_s64(int64_t const *a) {
+ // CHECK: test_vld2_s64
+ return vld2_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x2_t test_vld2_f16(float16_t const *a) {
+ // CHECK: test_vld2_f16
+ return vld2_f16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x2_t test_vld2_f32(float32_t const *a) {
+ // CHECK: test_vld2_f32
+ return vld2_f32(a);
+ // CHECK: ld2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x2_t test_vld2_f64(float64_t const *a) {
+ // CHECK: test_vld2_f64
+ return vld2_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x2_t test_vld2_p8(poly8_t const *a) {
+ // CHECK: test_vld2_p8
+ return vld2_p8(a);
+ // CHECK: ld2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x2_t test_vld2_p16(poly16_t const *a) {
+ // CHECK: test_vld2_p16
+ return vld2_p16(a);
+ // CHECK: ld2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x3_t test_vld3q_u8(uint8_t const *a) {
+ // CHECK: test_vld3q_u8
+ return vld3q_u8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x8x3_t test_vld3q_u16(uint16_t const *a) {
+ // CHECK: test_vld3q_u16
+ return vld3q_u16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x4x3_t test_vld3q_u32(uint32_t const *a) {
+ // CHECK: test_vld3q_u32
+ return vld3q_u32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x2x3_t test_vld3q_u64(uint64_t const *a) {
+ // CHECK: test_vld3q_u64
+ return vld3q_u64(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x16x3_t test_vld3q_s8(int8_t const *a) {
+ // CHECK: test_vld3q_s8
+ return vld3q_s8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x8x3_t test_vld3q_s16(int16_t const *a) {
+ // CHECK: test_vld3q_s16
+ return vld3q_s16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x4x3_t test_vld3q_s32(int32_t const *a) {
+ // CHECK: test_vld3q_s32
+ return vld3q_s32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x2x3_t test_vld3q_s64(int64_t const *a) {
+ // CHECK: test_vld3q_s64
+ return vld3q_s64(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x8x3_t test_vld3q_f16(float16_t const *a) {
+ // CHECK: test_vld3q_f16
+ return vld3q_f16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x4x3_t test_vld3q_f32(float32_t const *a) {
+ // CHECK: test_vld3q_f32
+ return vld3q_f32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x2x3_t test_vld3q_f64(float64_t const *a) {
+ // CHECK: test_vld3q_f64
+ return vld3q_f64(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x16x3_t test_vld3q_p8(poly8_t const *a) {
+ // CHECK: test_vld3q_p8
+ return vld3q_p8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x8x3_t test_vld3q_p16(poly16_t const *a) {
+ // CHECK: test_vld3q_p16
+ return vld3q_p16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x8x3_t test_vld3_u8(uint8_t const *a) {
+ // CHECK: test_vld3_u8
+ return vld3_u8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x4x3_t test_vld3_u16(uint16_t const *a) {
+ // CHECK: test_vld3_u16
+ return vld3_u16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x2x3_t test_vld3_u32(uint32_t const *a) {
+ // CHECK: test_vld3_u32
+ return vld3_u32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x1x3_t test_vld3_u64(uint64_t const *a) {
+ // CHECK: test_vld3_u64
+ return vld3_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x8x3_t test_vld3_s8(int8_t const *a) {
+ // CHECK: test_vld3_s8
+ return vld3_s8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x4x3_t test_vld3_s16(int16_t const *a) {
+ // CHECK: test_vld3_s16
+ return vld3_s16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x2x3_t test_vld3_s32(int32_t const *a) {
+ // CHECK: test_vld3_s32
+ return vld3_s32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x1x3_t test_vld3_s64(int64_t const *a) {
+ // CHECK: test_vld3_s64
+ return vld3_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x4x3_t test_vld3_f16(float16_t const *a) {
+ // CHECK: test_vld3_f16
+ return vld3_f16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x2x3_t test_vld3_f32(float32_t const *a) {
+ // CHECK: test_vld3_f32
+ return vld3_f32(a);
+ // CHECK: ld3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x1x3_t test_vld3_f64(float64_t const *a) {
+ // CHECK: test_vld3_f64
+ return vld3_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x8x3_t test_vld3_p8(poly8_t const *a) {
+ // CHECK: test_vld3_p8
+ return vld3_p8(a);
+ // CHECK: ld3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x4x3_t test_vld3_p16(poly16_t const *a) {
+ // CHECK: test_vld3_p16
+ return vld3_p16(a);
+ // CHECK: ld3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x16x4_t test_vld4q_u8(uint8_t const *a) {
+ // CHECK: test_vld4q_u8
+ return vld4q_u8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x4_t test_vld4q_u16(uint16_t const *a) {
+ // CHECK: test_vld4q_u16
+ return vld4q_u16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x4_t test_vld4q_u32(uint32_t const *a) {
+ // CHECK: test_vld4q_u32
+ return vld4q_u32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x4_t test_vld4q_u64(uint64_t const *a) {
+ // CHECK: test_vld4q_u64
+ return vld4q_u64(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x4_t test_vld4q_s8(int8_t const *a) {
+ // CHECK: test_vld4q_s8
+ return vld4q_s8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x4_t test_vld4q_s16(int16_t const *a) {
+ // CHECK: test_vld4q_s16
+ return vld4q_s16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x4_t test_vld4q_s32(int32_t const *a) {
+ // CHECK: test_vld4q_s32
+ return vld4q_s32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x4_t test_vld4q_s64(int64_t const *a) {
+ // CHECK: test_vld4q_s64
+ return vld4q_s64(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x4_t test_vld4q_f16(float16_t const *a) {
+ // CHECK: test_vld4q_f16
+ return vld4q_f16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x4_t test_vld4q_f32(float32_t const *a) {
+ // CHECK: test_vld4q_f32
+ return vld4q_f32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x4_t test_vld4q_f64(float64_t const *a) {
+ // CHECK: test_vld4q_f64
+ return vld4q_f64(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x4_t test_vld4q_p8(poly8_t const *a) {
+ // CHECK: test_vld4q_p8
+ return vld4q_p8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x4_t test_vld4q_p16(poly16_t const *a) {
+ // CHECK: test_vld4q_p16
+ return vld4q_p16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x4_t test_vld4_u8(uint8_t const *a) {
+ // CHECK: test_vld4_u8
+ return vld4_u8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x4_t test_vld4_u16(uint16_t const *a) {
+ // CHECK: test_vld4_u16
+ return vld4_u16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x4_t test_vld4_u32(uint32_t const *a) {
+ // CHECK: test_vld4_u32
+ return vld4_u32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x4_t test_vld4_u64(uint64_t const *a) {
+ // CHECK: test_vld4_u64
+ return vld4_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x4_t test_vld4_s8(int8_t const *a) {
+ // CHECK: test_vld4_s8
+ return vld4_s8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x4_t test_vld4_s16(int16_t const *a) {
+ // CHECK: test_vld4_s16
+ return vld4_s16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x4_t test_vld4_s32(int32_t const *a) {
+ // CHECK: test_vld4_s32
+ return vld4_s32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x4_t test_vld4_s64(int64_t const *a) {
+ // CHECK: test_vld4_s64
+ return vld4_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x4_t test_vld4_f16(float16_t const *a) {
+ // CHECK: test_vld4_f16
+ return vld4_f16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x4_t test_vld4_f32(float32_t const *a) {
+ // CHECK: test_vld4_f32
+ return vld4_f32(a);
+ // CHECK: ld4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x4_t test_vld4_f64(float64_t const *a) {
+ // CHECK: test_vld4_f64
+ return vld4_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x4_t test_vld4_p8(poly8_t const *a) {
+ // CHECK: test_vld4_p8
+ return vld4_p8(a);
+ // CHECK: ld4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x4_t test_vld4_p16(poly16_t const *a) {
+ // CHECK: test_vld4_p16
+ return vld4_p16(a);
+ // CHECK: ld4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u8(uint8_t *a, uint8x16_t b) {
+ // CHECK: test_vst1q_u8
+ vst1q_u8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u16(uint16_t *a, uint16x8_t b) {
+ // CHECK: test_vst1q_u16
+ vst1q_u16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u32(uint32_t *a, uint32x4_t b) {
+ // CHECK: test_vst1q_u32
+ vst1q_u32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u64(uint64_t *a, uint64x2_t b) {
+ // CHECK: test_vst1q_u64
+ vst1q_u64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s8(int8_t *a, int8x16_t b) {
+ // CHECK: test_vst1q_s8
+ vst1q_s8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s16(int16_t *a, int16x8_t b) {
+ // CHECK: test_vst1q_s16
+ vst1q_s16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s32(int32_t *a, int32x4_t b) {
+ // CHECK: test_vst1q_s32
+ vst1q_s32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s64(int64_t *a, int64x2_t b) {
+ // CHECK: test_vst1q_s64
+ vst1q_s64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f16(float16_t *a, float16x8_t b) {
+ // CHECK: test_vst1q_f16
+ vst1q_f16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f32(float32_t *a, float32x4_t b) {
+ // CHECK: test_vst1q_f32
+ vst1q_f32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f64(float64_t *a, float64x2_t b) {
+ // CHECK: test_vst1q_f64
+ vst1q_f64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p8(poly8_t *a, poly8x16_t b) {
+ // CHECK: test_vst1q_p8
+ vst1q_p8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p16(poly16_t *a, poly16x8_t b) {
+ // CHECK: test_vst1q_p16
+ vst1q_p16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u8(uint8_t *a, uint8x8_t b) {
+ // CHECK: test_vst1_u8
+ vst1_u8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u16(uint16_t *a, uint16x4_t b) {
+ // CHECK: test_vst1_u16
+ vst1_u16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u32(uint32_t *a, uint32x2_t b) {
+ // CHECK: test_vst1_u32
+ vst1_u32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u64(uint64_t *a, uint64x1_t b) {
+ // CHECK: test_vst1_u64
+ vst1_u64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s8(int8_t *a, int8x8_t b) {
+ // CHECK: test_vst1_s8
+ vst1_s8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s16(int16_t *a, int16x4_t b) {
+ // CHECK: test_vst1_s16
+ vst1_s16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s32(int32_t *a, int32x2_t b) {
+ // CHECK: test_vst1_s32
+ vst1_s32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s64(int64_t *a, int64x1_t b) {
+ // CHECK: test_vst1_s64
+ vst1_s64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f16(float16_t *a, float16x4_t b) {
+ // CHECK: test_vst1_f16
+ vst1_f16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f32(float32_t *a, float32x2_t b) {
+ // CHECK: test_vst1_f32
+ vst1_f32(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f64(float64_t *a, float64x1_t b) {
+ // CHECK: test_vst1_f64
+ vst1_f64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p8(poly8_t *a, poly8x8_t b) {
+ // CHECK: test_vst1_p8
+ vst1_p8(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p16(poly16_t *a, poly16x4_t b) {
+ // CHECK: test_vst1_p16
+ vst1_p16(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_u8(uint8_t *a, uint8x16x2_t b) {
+ // CHECK: test_vst2q_u8
+ vst2q_u8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_u16(uint16_t *a, uint16x8x2_t b) {
+ // CHECK: test_vst2q_u16
+ vst2q_u16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_u32(uint32_t *a, uint32x4x2_t b) {
+ // CHECK: test_vst2q_u32
+ vst2q_u32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_u64(uint64_t *a, uint64x2x2_t b) {
+ // CHECK: test_vst2q_u64
+ vst2q_u64(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_s8(int8_t *a, int8x16x2_t b) {
+ // CHECK: test_vst2q_s8
+ vst2q_s8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_s16(int16_t *a, int16x8x2_t b) {
+ // CHECK: test_vst2q_s16
+ vst2q_s16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_s32(int32_t *a, int32x4x2_t b) {
+ // CHECK: test_vst2q_s32
+ vst2q_s32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_s64(int64_t *a, int64x2x2_t b) {
+ // CHECK: test_vst2q_s64
+ vst2q_s64(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_f16(float16_t *a, float16x8x2_t b) {
+ // CHECK: test_vst2q_f16
+ vst2q_f16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_f32(float32_t *a, float32x4x2_t b) {
+ // CHECK: test_vst2q_f32
+ vst2q_f32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_f64(float64_t *a, float64x2x2_t b) {
+ // CHECK: test_vst2q_f64
+ vst2q_f64(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_p8(poly8_t *a, poly8x16x2_t b) {
+ // CHECK: test_vst2q_p8
+ vst2q_p8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_p16(poly16_t *a, poly16x8x2_t b) {
+ // CHECK: test_vst2q_p16
+ vst2q_p16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_u8(uint8_t *a, uint8x8x2_t b) {
+ // CHECK: test_vst2_u8
+ vst2_u8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_u16(uint16_t *a, uint16x4x2_t b) {
+ // CHECK: test_vst2_u16
+ vst2_u16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_u32(uint32_t *a, uint32x2x2_t b) {
+ // CHECK: test_vst2_u32
+ vst2_u32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_u64(uint64_t *a, uint64x1x2_t b) {
+ // CHECK: test_vst2_u64
+ vst2_u64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_s8(int8_t *a, int8x8x2_t b) {
+ // CHECK: test_vst2_s8
+ vst2_s8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_s16(int16_t *a, int16x4x2_t b) {
+ // CHECK: test_vst2_s16
+ vst2_s16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_s32(int32_t *a, int32x2x2_t b) {
+ // CHECK: test_vst2_s32
+ vst2_s32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_s64(int64_t *a, int64x1x2_t b) {
+ // CHECK: test_vst2_s64
+ vst2_s64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_f16(float16_t *a, float16x4x2_t b) {
+ // CHECK: test_vst2_f16
+ vst2_f16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_f32(float32_t *a, float32x2x2_t b) {
+ // CHECK: test_vst2_f32
+ vst2_f32(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_f64(float64_t *a, float64x1x2_t b) {
+ // CHECK: test_vst2_f64
+ vst2_f64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_p8(poly8_t *a, poly8x8x2_t b) {
+ // CHECK: test_vst2_p8
+ vst2_p8(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_p16(poly16_t *a, poly16x4x2_t b) {
+ // CHECK: test_vst2_p16
+ vst2_p16(a, b);
+ // CHECK: st2 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_u8(uint8_t *a, uint8x16x3_t b) {
+ // CHECK: test_vst3q_u8
+ vst3q_u8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_u16(uint16_t *a, uint16x8x3_t b) {
+ // CHECK: test_vst3q_u16
+ vst3q_u16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_u32(uint32_t *a, uint32x4x3_t b) {
+ // CHECK: test_vst3q_u32
+ vst3q_u32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_u64(uint64_t *a, uint64x2x3_t b) {
+ // CHECK: test_vst3q_u64
+ vst3q_u64(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_s8(int8_t *a, int8x16x3_t b) {
+ // CHECK: test_vst3q_s8
+ vst3q_s8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_s16(int16_t *a, int16x8x3_t b) {
+ // CHECK: test_vst3q_s16
+ vst3q_s16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_s32(int32_t *a, int32x4x3_t b) {
+ // CHECK: test_vst3q_s32
+ vst3q_s32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_s64(int64_t *a, int64x2x3_t b) {
+ // CHECK: test_vst3q_s64
+ vst3q_s64(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_f16(float16_t *a, float16x8x3_t b) {
+ // CHECK: test_vst3q_f16
+ vst3q_f16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_f32(float32_t *a, float32x4x3_t b) {
+ // CHECK: test_vst3q_f32
+ vst3q_f32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_f64(float64_t *a, float64x2x3_t b) {
+ // CHECK: test_vst3q_f64
+ vst3q_f64(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_p8(poly8_t *a, poly8x16x3_t b) {
+ // CHECK: test_vst3q_p8
+ vst3q_p8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_p16(poly16_t *a, poly16x8x3_t b) {
+ // CHECK: test_vst3q_p16
+ vst3q_p16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_u8(uint8_t *a, uint8x8x3_t b) {
+ // CHECK: test_vst3_u8
+ vst3_u8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_u16(uint16_t *a, uint16x4x3_t b) {
+ // CHECK: test_vst3_u16
+ vst3_u16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_u32(uint32_t *a, uint32x2x3_t b) {
+ // CHECK: test_vst3_u32
+ vst3_u32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_u64(uint64_t *a, uint64x1x3_t b) {
+ // CHECK: test_vst3_u64
+ vst3_u64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_s8(int8_t *a, int8x8x3_t b) {
+ // CHECK: test_vst3_s8
+ vst3_s8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_s16(int16_t *a, int16x4x3_t b) {
+ // CHECK: test_vst3_s16
+ vst3_s16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_s32(int32_t *a, int32x2x3_t b) {
+ // CHECK: test_vst3_s32
+ vst3_s32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_s64(int64_t *a, int64x1x3_t b) {
+ // CHECK: test_vst3_s64
+ vst3_s64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_f16(float16_t *a, float16x4x3_t b) {
+ // CHECK: test_vst3_f16
+ vst3_f16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_f32(float32_t *a, float32x2x3_t b) {
+ // CHECK: test_vst3_f32
+ vst3_f32(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_f64(float64_t *a, float64x1x3_t b) {
+ // CHECK: test_vst3_f64
+ vst3_f64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_p8(poly8_t *a, poly8x8x3_t b) {
+ // CHECK: test_vst3_p8
+ vst3_p8(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_p16(poly16_t *a, poly16x4x3_t b) {
+ // CHECK: test_vst3_p16
+ vst3_p16(a, b);
+ // CHECK: st3 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_u8(uint8_t *a, uint8x16x4_t b) {
+ // CHECK: test_vst4q_u8
+ vst4q_u8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_u16(uint16_t *a, uint16x8x4_t b) {
+ // CHECK: test_vst4q_u16
+ vst4q_u16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_u32(uint32_t *a, uint32x4x4_t b) {
+ // CHECK: test_vst4q_u32
+ vst4q_u32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_u64(uint64_t *a, uint64x2x4_t b) {
+ // CHECK: test_vst4q_u64
+ vst4q_u64(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_s8(int8_t *a, int8x16x4_t b) {
+ // CHECK: test_vst4q_s8
+ vst4q_s8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_s16(int16_t *a, int16x8x4_t b) {
+ // CHECK: test_vst4q_s16
+ vst4q_s16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_s32(int32_t *a, int32x4x4_t b) {
+ // CHECK: test_vst4q_s32
+ vst4q_s32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_s64(int64_t *a, int64x2x4_t b) {
+ // CHECK: test_vst4q_s64
+ vst4q_s64(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_f16(float16_t *a, float16x8x4_t b) {
+ // CHECK: test_vst4q_f16
+ vst4q_f16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_f32(float32_t *a, float32x4x4_t b) {
+ // CHECK: test_vst4q_f32
+ vst4q_f32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_f64(float64_t *a, float64x2x4_t b) {
+ // CHECK: test_vst4q_f64
+ vst4q_f64(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_p8(poly8_t *a, poly8x16x4_t b) {
+ // CHECK: test_vst4q_p8
+ vst4q_p8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_p16(poly16_t *a, poly16x8x4_t b) {
+ // CHECK: test_vst4q_p16
+ vst4q_p16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_u8(uint8_t *a, uint8x8x4_t b) {
+ // CHECK: test_vst4_u8
+ vst4_u8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_u16(uint16_t *a, uint16x4x4_t b) {
+ // CHECK: test_vst4_u16
+ vst4_u16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_u32(uint32_t *a, uint32x2x4_t b) {
+ // CHECK: test_vst4_u32
+ vst4_u32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_u64(uint64_t *a, uint64x1x4_t b) {
+ // CHECK: test_vst4_u64
+ vst4_u64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_s8(int8_t *a, int8x8x4_t b) {
+ // CHECK: test_vst4_s8
+ vst4_s8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_s16(int16_t *a, int16x4x4_t b) {
+ // CHECK: test_vst4_s16
+ vst4_s16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_s32(int32_t *a, int32x2x4_t b) {
+ // CHECK: test_vst4_s32
+ vst4_s32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_s64(int64_t *a, int64x1x4_t b) {
+ // CHECK: test_vst4_s64
+ vst4_s64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_f16(float16_t *a, float16x4x4_t b) {
+ // CHECK: test_vst4_f16
+ vst4_f16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_f32(float32_t *a, float32x2x4_t b) {
+ // CHECK: test_vst4_f32
+ vst4_f32(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_f64(float64_t *a, float64x1x4_t b) {
+ // CHECK: test_vst4_f64
+ vst4_f64(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_p8(poly8_t *a, poly8x8x4_t b) {
+ // CHECK: test_vst4_p8
+ vst4_p8(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_p16(poly16_t *a, poly16x4x4_t b) {
+ // CHECK: test_vst4_p16
+ vst4_p16(a, b);
+ // CHECK: st4 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x2_t test_vld1q_u8_x2(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1q_u8_x2
+ return vld1q_u8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x2_t test_vld1q_u16_x2(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1q_u16_x2
+ return vld1q_u16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x2_t test_vld1q_u32_x2(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1q_u32_x2
+ return vld1q_u32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x2_t test_vld1q_u64_x2(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1q_u64_x2
+ return vld1q_u64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x2_t test_vld1q_s8_x2(int8_t const *a) {
+ // CHECK-LABEL: test_vld1q_s8_x2
+ return vld1q_s8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x2_t test_vld1q_s16_x2(int16_t const *a) {
+ // CHECK-LABEL: test_vld1q_s16_x2
+ return vld1q_s16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x2_t test_vld1q_s32_x2(int32_t const *a) {
+ // CHECK-LABEL: test_vld1q_s32_x2
+ return vld1q_s32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x2_t test_vld1q_s64_x2(int64_t const *a) {
+ // CHECK-LABEL: test_vld1q_s64_x2
+ return vld1q_s64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x2_t test_vld1q_f16_x2(float16_t const *a) {
+ // CHECK-LABEL: test_vld1q_f16_x2
+ return vld1q_f16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x2_t test_vld1q_f32_x2(float32_t const *a) {
+ // CHECK-LABEL: test_vld1q_f32_x2
+ return vld1q_f32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x2_t test_vld1q_f64_x2(float64_t const *a) {
+ // CHECK-LABEL: test_vld1q_f64_x2
+ return vld1q_f64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x2_t test_vld1q_p8_x2(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1q_p8_x2
+ return vld1q_p8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x2_t test_vld1q_p16_x2(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1q_p16_x2
+ return vld1q_p16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x2_t test_vld1q_p64_x2(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1q_p64_x2
+ return vld1q_p64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x2_t test_vld1_u8_x2(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1_u8_x2
+ return vld1_u8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x2_t test_vld1_u16_x2(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1_u16_x2
+ return vld1_u16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x2_t test_vld1_u32_x2(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1_u32_x2
+ return vld1_u32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x2_t test_vld1_u64_x2(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1_u64_x2
+ return vld1_u64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x2_t test_vld1_s8_x2(int8_t const *a) {
+ // CHECK-LABEL: test_vld1_s8_x2
+ return vld1_s8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x2_t test_vld1_s16_x2(int16_t const *a) {
+ // CHECK-LABEL: test_vld1_s16_x2
+ return vld1_s16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x2_t test_vld1_s32_x2(int32_t const *a) {
+ // CHECK-LABEL: test_vld1_s32_x2
+ return vld1_s32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x2_t test_vld1_s64_x2(int64_t const *a) {
+ // CHECK-LABEL: test_vld1_s64_x2
+ return vld1_s64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x2_t test_vld1_f16_x2(float16_t const *a) {
+ // CHECK-LABEL: test_vld1_f16_x2
+ return vld1_f16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x2_t test_vld1_f32_x2(float32_t const *a) {
+ // CHECK-LABEL: test_vld1_f32_x2
+ return vld1_f32_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x2_t test_vld1_f64_x2(float64_t const *a) {
+ // CHECK-LABEL: test_vld1_f64_x2
+ return vld1_f64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x2_t test_vld1_p8_x2(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1_p8_x2
+ return vld1_p8_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x2_t test_vld1_p16_x2(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1_p16_x2
+ return vld1_p16_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x2_t test_vld1_p64_x2(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1_p64_x2
+ return vld1_p64_x2(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x3_t test_vld1q_u8_x3(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1q_u8_x3
+ return vld1q_u8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x8x3_t test_vld1q_u16_x3(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1q_u16_x3
+ return vld1q_u16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x4x3_t test_vld1q_u32_x3(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1q_u32_x3
+ return vld1q_u32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x2x3_t test_vld1q_u64_x3(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1q_u64_x3
+ return vld1q_u64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x16x3_t test_vld1q_s8_x3(int8_t const *a) {
+ // CHECK-LABEL: test_vld1q_s8_x3
+ return vld1q_s8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x8x3_t test_vld1q_s16_x3(int16_t const *a) {
+ // CHECK-LABEL: test_vld1q_s16_x3
+ return vld1q_s16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x4x3_t test_vld1q_s32_x3(int32_t const *a) {
+ // CHECK-LABEL: test_vld1q_s32_x3
+ return vld1q_s32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x2x3_t test_vld1q_s64_x3(int64_t const *a) {
+ // CHECK-LABEL: test_vld1q_s64_x3
+ return vld1q_s64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x8x3_t test_vld1q_f16_x3(float16_t const *a) {
+ // CHECK-LABEL: test_vld1q_f16_x3
+ return vld1q_f16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x4x3_t test_vld1q_f32_x3(float32_t const *a) {
+ // CHECK-LABEL: test_vld1q_f32_x3
+ return vld1q_f32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x2x3_t test_vld1q_f64_x3(float64_t const *a) {
+ // CHECK-LABEL: test_vld1q_f64_x3
+ return vld1q_f64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x16x3_t test_vld1q_p8_x3(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1q_p8_x3
+ return vld1q_p8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x8x3_t test_vld1q_p16_x3(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1q_p16_x3
+ return vld1q_p16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly64x2x3_t test_vld1q_p64_x3(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1q_p64_x3
+ return vld1q_p64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x8x3_t test_vld1_u8_x3(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1_u8_x3
+ return vld1_u8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x4x3_t test_vld1_u16_x3(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1_u16_x3
+ return vld1_u16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x2x3_t test_vld1_u32_x3(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1_u32_x3
+ return vld1_u32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x1x3_t test_vld1_u64_x3(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1_u64_x3
+ return vld1_u64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x8x3_t test_vld1_s8_x3(int8_t const *a) {
+ // CHECK-LABEL: test_vld1_s8_x3
+ return vld1_s8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x4x3_t test_vld1_s16_x3(int16_t const *a) {
+ // CHECK-LABEL: test_vld1_s16_x3
+ return vld1_s16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x2x3_t test_vld1_s32_x3(int32_t const *a) {
+ // CHECK-LABEL: test_vld1_s32_x3
+ return vld1_s32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x1x3_t test_vld1_s64_x3(int64_t const *a) {
+ // CHECK-LABEL: test_vld1_s64_x3
+ return vld1_s64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x4x3_t test_vld1_f16_x3(float16_t const *a) {
+ // CHECK-LABEL: test_vld1_f16_x3
+ return vld1_f16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x2x3_t test_vld1_f32_x3(float32_t const *a) {
+ // CHECK-LABEL: test_vld1_f32_x3
+ return vld1_f32_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x1x3_t test_vld1_f64_x3(float64_t const *a) {
+ // CHECK-LABEL: test_vld1_f64_x3
+ return vld1_f64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x8x3_t test_vld1_p8_x3(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1_p8_x3
+ return vld1_p8_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x4x3_t test_vld1_p16_x3(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1_p16_x3
+ return vld1_p16_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly64x1x3_t test_vld1_p64_x3(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1_p64_x3
+ return vld1_p64_x3(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x16x4_t test_vld1q_u8_x4(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1q_u8_x4
+ return vld1q_u8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x4_t test_vld1q_u16_x4(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1q_u16_x4
+ return vld1q_u16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x4_t test_vld1q_u32_x4(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1q_u32_x4
+ return vld1q_u32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x4_t test_vld1q_u64_x4(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1q_u64_x4
+ return vld1q_u64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x4_t test_vld1q_s8_x4(int8_t const *a) {
+ // CHECK-LABEL: test_vld1q_s8_x4
+ return vld1q_s8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x4_t test_vld1q_s16_x4(int16_t const *a) {
+ // CHECK-LABEL: test_vld1q_s16_x4
+ return vld1q_s16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x4_t test_vld1q_s32_x4(int32_t const *a) {
+ // CHECK-LABEL: test_vld1q_s32_x4
+ return vld1q_s32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x4_t test_vld1q_s64_x4(int64_t const *a) {
+ // CHECK-LABEL: test_vld1q_s64_x4
+ return vld1q_s64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x4_t test_vld1q_f16_x4(float16_t const *a) {
+ // CHECK-LABEL: test_vld1q_f16_x4
+ return vld1q_f16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x4_t test_vld1q_f32_x4(float32_t const *a) {
+ // CHECK-LABEL: test_vld1q_f32_x4
+ return vld1q_f32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x4_t test_vld1q_f64_x4(float64_t const *a) {
+ // CHECK-LABEL: test_vld1q_f64_x4
+ return vld1q_f64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x4_t test_vld1q_p8_x4(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1q_p8_x4
+ return vld1q_p8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x4_t test_vld1q_p16_x4(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1q_p16_x4
+ return vld1q_p16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x4_t test_vld1q_p64_x4(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1q_p64_x4
+ return vld1q_p64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x4_t test_vld1_u8_x4(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1_u8_x4
+ return vld1_u8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x4_t test_vld1_u16_x4(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1_u16_x4
+ return vld1_u16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x4_t test_vld1_u32_x4(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1_u32_x4
+ return vld1_u32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x4_t test_vld1_u64_x4(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1_u64_x4
+ return vld1_u64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x4_t test_vld1_s8_x4(int8_t const *a) {
+ // CHECK-LABEL: test_vld1_s8_x4
+ return vld1_s8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x4_t test_vld1_s16_x4(int16_t const *a) {
+ // CHECK-LABEL: test_vld1_s16_x4
+ return vld1_s16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x4_t test_vld1_s32_x4(int32_t const *a) {
+ // CHECK-LABEL: test_vld1_s32_x4
+ return vld1_s32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x4_t test_vld1_s64_x4(int64_t const *a) {
+ // CHECK-LABEL: test_vld1_s64_x4
+ return vld1_s64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x4_t test_vld1_f16_x4(float16_t const *a) {
+ // CHECK-LABEL: test_vld1_f16_x4
+ return vld1_f16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x4_t test_vld1_f32_x4(float32_t const *a) {
+ // CHECK-LABEL: test_vld1_f32_x4
+ return vld1_f32_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x4_t test_vld1_f64_x4(float64_t const *a) {
+ // CHECK-LABEL: test_vld1_f64_x4
+ return vld1_f64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x4_t test_vld1_p8_x4(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1_p8_x4
+ return vld1_p8_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x4_t test_vld1_p16_x4(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1_p16_x4
+ return vld1_p16_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x4_t test_vld1_p64_x4(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1_p64_x4
+ return vld1_p64_x4(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u8_x2(uint8_t *a, uint8x16x2_t b) {
+ // CHECK: test_vst1q_u8_x2
+ vst1q_u8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u16_x2(uint16_t *a, uint16x8x2_t b) {
+ // CHECK: test_vst1q_u16_x2
+ vst1q_u16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u32_x2(uint32_t *a, uint32x4x2_t b) {
+ // CHECK: test_vst1q_u32_x2
+ vst1q_u32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u64_x2(uint64_t *a, uint64x2x2_t b) {
+ // CHECK: test_vst1q_u64_x2
+ vst1q_u64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s8_x2(int8_t *a, int8x16x2_t b) {
+ // CHECK: test_vst1q_s8_x2
+ vst1q_s8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s16_x2(int16_t *a, int16x8x2_t b) {
+ // CHECK: test_vst1q_s16_x2
+ vst1q_s16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s32_x2(int32_t *a, int32x4x2_t b) {
+ // CHECK: test_vst1q_s32_x2
+ vst1q_s32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s64_x2(int64_t *a, int64x2x2_t b) {
+ // CHECK: test_vst1q_s64_x2
+ vst1q_s64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f16_x2(float16_t *a, float16x8x2_t b) {
+ // CHECK: test_vst1q_f16_x2
+ vst1q_f16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f32_x2(float32_t *a, float32x4x2_t b) {
+ // CHECK: test_vst1q_f32_x2
+ vst1q_f32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f64_x2(float64_t *a, float64x2x2_t b) {
+ // CHECK: test_vst1q_f64_x2
+ vst1q_f64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p8_x2(poly8_t *a, poly8x16x2_t b) {
+ // CHECK: test_vst1q_p8_x2
+ vst1q_p8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p16_x2(poly16_t *a, poly16x8x2_t b) {
+ // CHECK: test_vst1q_p16_x2
+ vst1q_p16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p64_x2(poly64_t *a, poly64x2x2_t b) {
+ // CHECK: test_vst1q_p64_x2
+ vst1q_p64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u8_x2(uint8_t *a, uint8x8x2_t b) {
+ // CHECK: test_vst1_u8_x2
+ vst1_u8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u16_x2(uint16_t *a, uint16x4x2_t b) {
+ // CHECK: test_vst1_u16_x2
+ vst1_u16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u32_x2(uint32_t *a, uint32x2x2_t b) {
+ // CHECK: test_vst1_u32_x2
+ vst1_u32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u64_x2(uint64_t *a, uint64x1x2_t b) {
+ // CHECK: test_vst1_u64_x2
+ vst1_u64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s8_x2(int8_t *a, int8x8x2_t b) {
+ // CHECK: test_vst1_s8_x2
+ vst1_s8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s16_x2(int16_t *a, int16x4x2_t b) {
+ // CHECK: test_vst1_s16_x2
+ vst1_s16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s32_x2(int32_t *a, int32x2x2_t b) {
+ // CHECK: test_vst1_s32_x2
+ vst1_s32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s64_x2(int64_t *a, int64x1x2_t b) {
+ // CHECK: test_vst1_s64_x2
+ vst1_s64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f16_x2(float16_t *a, float16x4x2_t b) {
+ // CHECK: test_vst1_f16_x2
+ vst1_f16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f32_x2(float32_t *a, float32x2x2_t b) {
+ // CHECK: test_vst1_f32_x2
+ vst1_f32_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f64_x2(float64_t *a, float64x1x2_t b) {
+ // CHECK: test_vst1_f64_x2
+ vst1_f64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p8_x2(poly8_t *a, poly8x8x2_t b) {
+ // CHECK: test_vst1_p8_x2
+ vst1_p8_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p16_x2(poly16_t *a, poly16x4x2_t b) {
+ // CHECK: test_vst1_p16_x2
+ vst1_p16_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p64_x2(poly64_t *a, poly64x1x2_t b) {
+ // CHECK: test_vst1_p64_x2
+ vst1_p64_x2(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u8_x3(uint8_t *a, uint8x16x3_t b) {
+ // CHECK: test_vst1q_u8_x3
+ vst1q_u8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u16_x3(uint16_t *a, uint16x8x3_t b) {
+ // CHECK: test_vst1q_u16_x3
+ vst1q_u16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u32_x3(uint32_t *a, uint32x4x3_t b) {
+ // CHECK: test_vst1q_u32_x3
+ vst1q_u32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u64_x3(uint64_t *a, uint64x2x3_t b) {
+ // CHECK: test_vst1q_u64_x3
+ vst1q_u64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s8_x3(int8_t *a, int8x16x3_t b) {
+ // CHECK: test_vst1q_s8_x3
+ vst1q_s8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s16_x3(int16_t *a, int16x8x3_t b) {
+ // CHECK: test_vst1q_s16_x3
+ vst1q_s16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s32_x3(int32_t *a, int32x4x3_t b) {
+ // CHECK: test_vst1q_s32_x3
+ vst1q_s32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s64_x3(int64_t *a, int64x2x3_t b) {
+ // CHECK: test_vst1q_s64_x3
+ vst1q_s64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f16_x3(float16_t *a, float16x8x3_t b) {
+ // CHECK: test_vst1q_f16_x3
+ vst1q_f16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f32_x3(float32_t *a, float32x4x3_t b) {
+ // CHECK: test_vst1q_f32_x3
+ vst1q_f32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f64_x3(float64_t *a, float64x2x3_t b) {
+ // CHECK: test_vst1q_f64_x3
+ vst1q_f64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p8_x3(poly8_t *a, poly8x16x3_t b) {
+ // CHECK: test_vst1q_p8_x3
+ vst1q_p8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p16_x3(poly16_t *a, poly16x8x3_t b) {
+ // CHECK: test_vst1q_p16_x3
+ vst1q_p16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p64_x3(poly64_t *a, poly64x2x3_t b) {
+ // CHECK: test_vst1q_p64_x3
+ vst1q_p64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u8_x3(uint8_t *a, uint8x8x3_t b) {
+ // CHECK: test_vst1_u8_x3
+ vst1_u8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u16_x3(uint16_t *a, uint16x4x3_t b) {
+ // CHECK: test_vst1_u16_x3
+ vst1_u16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u32_x3(uint32_t *a, uint32x2x3_t b) {
+ // CHECK: test_vst1_u32_x3
+ vst1_u32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u64_x3(uint64_t *a, uint64x1x3_t b) {
+ // CHECK: test_vst1_u64_x3
+ vst1_u64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s8_x3(int8_t *a, int8x8x3_t b) {
+ // CHECK: test_vst1_s8_x3
+ vst1_s8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s16_x3(int16_t *a, int16x4x3_t b) {
+ // CHECK: test_vst1_s16_x3
+ vst1_s16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s32_x3(int32_t *a, int32x2x3_t b) {
+ // CHECK: test_vst1_s32_x3
+ vst1_s32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s64_x3(int64_t *a, int64x1x3_t b) {
+ // CHECK: test_vst1_s64_x3
+ vst1_s64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f16_x3(float16_t *a, float16x4x3_t b) {
+ // CHECK: test_vst1_f16_x3
+ vst1_f16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f32_x3(float32_t *a, float32x2x3_t b) {
+ // CHECK: test_vst1_f32_x3
+ vst1_f32_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f64_x3(float64_t *a, float64x1x3_t b) {
+ // CHECK: test_vst1_f64_x3
+ vst1_f64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p8_x3(poly8_t *a, poly8x8x3_t b) {
+ // CHECK: test_vst1_p8_x3
+ vst1_p8_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p16_x3(poly16_t *a, poly16x4x3_t b) {
+ // CHECK: test_vst1_p16_x3
+ vst1_p16_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p64_x3(poly64_t *a, poly64x1x3_t b) {
+ // CHECK: test_vst1_p64_x3
+ vst1_p64_x3(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u8_x4(uint8_t *a, uint8x16x4_t b) {
+ // CHECK: test_vst1q_u8_x4
+ vst1q_u8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u16_x4(uint16_t *a, uint16x8x4_t b) {
+ // CHECK: test_vst1q_u16_x4
+ vst1q_u16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u32_x4(uint32_t *a, uint32x4x4_t b) {
+ // CHECK: test_vst1q_u32_x4
+ vst1q_u32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_u64_x4(uint64_t *a, uint64x2x4_t b) {
+ // CHECK: test_vst1q_u64_x4
+ vst1q_u64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s8_x4(int8_t *a, int8x16x4_t b) {
+ // CHECK: test_vst1q_s8_x4
+ vst1q_s8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s16_x4(int16_t *a, int16x8x4_t b) {
+ // CHECK: test_vst1q_s16_x4
+ vst1q_s16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s32_x4(int32_t *a, int32x4x4_t b) {
+ // CHECK: test_vst1q_s32_x4
+ vst1q_s32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_s64_x4(int64_t *a, int64x2x4_t b) {
+ // CHECK: test_vst1q_s64_x4
+ vst1q_s64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f16_x4(float16_t *a, float16x8x4_t b) {
+ // CHECK: test_vst1q_f16_x4
+ vst1q_f16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f32_x4(float32_t *a, float32x4x4_t b) {
+ // CHECK: test_vst1q_f32_x4
+ vst1q_f32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_f64_x4(float64_t *a, float64x2x4_t b) {
+ // CHECK: test_vst1q_f64_x4
+ vst1q_f64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p8_x4(poly8_t *a, poly8x16x4_t b) {
+ // CHECK: test_vst1q_p8_x4
+ vst1q_p8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p16_x4(poly16_t *a, poly16x8x4_t b) {
+ // CHECK: test_vst1q_p16_x4
+ vst1q_p16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p64_x4(poly64_t *a, poly64x2x4_t b) {
+ // CHECK: test_vst1q_p64_x4
+ vst1q_p64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u8_x4(uint8_t *a, uint8x8x4_t b) {
+ // CHECK: test_vst1_u8_x4
+ vst1_u8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u16_x4(uint16_t *a, uint16x4x4_t b) {
+ // CHECK: test_vst1_u16_x4
+ vst1_u16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u32_x4(uint32_t *a, uint32x2x4_t b) {
+ // CHECK: test_vst1_u32_x4
+ vst1_u32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_u64_x4(uint64_t *a, uint64x1x4_t b) {
+ // CHECK: test_vst1_u64_x4
+ vst1_u64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s8_x4(int8_t *a, int8x8x4_t b) {
+ // CHECK: test_vst1_s8_x4
+ vst1_s8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s16_x4(int16_t *a, int16x4x4_t b) {
+ // CHECK: test_vst1_s16_x4
+ vst1_s16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s32_x4(int32_t *a, int32x2x4_t b) {
+ // CHECK: test_vst1_s32_x4
+ vst1_s32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_s64_x4(int64_t *a, int64x1x4_t b) {
+ // CHECK: test_vst1_s64_x4
+ vst1_s64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f16_x4(float16_t *a, float16x4x4_t b) {
+ // CHECK: test_vst1_f16_x4
+ vst1_f16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f32_x4(float32_t *a, float32x2x4_t b) {
+ // CHECK: test_vst1_f32_x4
+ vst1_f32_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_f64_x4(float64_t *a, float64x1x4_t b) {
+ // CHECK: test_vst1_f64_x4
+ vst1_f64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p8_x4(poly8_t *a, poly8x8x4_t b) {
+ // CHECK: test_vst1_p8_x4
+ vst1_p8_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p16_x4(poly16_t *a, poly16x4x4_t b) {
+ // CHECK: test_vst1_p16_x4
+ vst1_p16_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p64_x4(poly64_t *a, poly64x1x4_t b) {
+ // CHECK: test_vst1_p64_x4
+ vst1_p64_x4(a, b);
+ // CHECK: st1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int64_t test_vceqd_s64(int64_t a, int64_t b) {
+// CHECK: test_vceqd_s64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vceqd_s64(a, b);
+}
+
+uint64_t test_vceqd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vceqd_u64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vceqd_u64(a, b);
+}
+
+int64_t test_vceqzd_s64(int64_t a) {
+// CHECK: test_vceqzd_s64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vceqzd_s64(a);
+}
+
+int64_t test_vceqzd_u64(int64_t a) {
+// CHECK: test_vceqzd_u64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vceqzd_u64(a);
+}
+
+int64_t test_vcged_s64(int64_t a, int64_t b) {
+// CHECK: test_vcged_s64
+// CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcged_s64(a, b);
+}
+
+uint64_t test_vcged_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vcged_u64
+// CHECK: cmhs {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcged_u64(a, b);
+}
+
+int64_t test_vcgezd_s64(int64_t a) {
+// CHECK: test_vcgezd_s64
+// CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vcgezd_s64(a);
+}
+
+int64_t test_vcgtd_s64(int64_t a, int64_t b) {
+// CHECK: test_vcgtd_s64
+// CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcgtd_s64(a, b);
+}
+
+uint64_t test_vcgtd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vcgtd_u64
+// CHECK: cmhi {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcgtd_u64(a, b);
+}
+
+int64_t test_vcgtzd_s64(int64_t a) {
+// CHECK: test_vcgtzd_s64
+// CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vcgtzd_s64(a);
+}
+
+int64_t test_vcled_s64(int64_t a, int64_t b) {
+// CHECK: test_vcled_s64
+// CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcled_s64(a, b);
+}
+
+uint64_t test_vcled_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vcled_u64
+// CHECK: cmhs {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcled_u64(a, 0);
+}
+
+int64_t test_vclezd_s64(int64_t a) {
+// CHECK: test_vclezd_s64
+// CHECK: cmle {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vclezd_s64(a);
+}
+
+int64_t test_vcltd_s64(int64_t a, int64_t b) {
+// CHECK: test_vcltd_s64
+// CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vcltd_s64(a, b);
+}
+
+uint64_t test_vcltd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vcltd_u64
+// CHECK: cmhi {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcltd_u64(a, b);
+}
+
+int64_t test_vcltzd_s64(int64_t a) {
+// CHECK: test_vcltzd_s64
+// CHECK: cmlt {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+ return (int64_t)vcltzd_s64(a);
+}
+
+int64_t test_vtstd_s64(int64_t a, int64_t b) {
+// CHECK: test_vtstd_s64
+// CHECK: cmtst {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vtstd_s64(a, b);
+}
+
+uint64_t test_vtstd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vtstd_u64
+// CHECK: cmtst {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vtstd_u64(a, b);
+}
+
+int64_t test_vabsd_s64(int64_t a) {
+// CHECK: test_vabsd_s64
+// CHECK: abs {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vabsd_s64(a);
+}
+
+int8_t test_vqabsb_s8(int8_t a) {
+// CHECK: test_vqabsb_s8
+// CHECK: sqabs {{b[0-9]+}}, {{b[0-9]+}}
+ return (int8_t)vqabsb_s8(a);
+}
+
+int16_t test_vqabsh_s16(int16_t a) {
+// CHECK: test_vqabsh_s16
+// CHECK: sqabs {{h[0-9]+}}, {{h[0-9]+}}
+ return (int16_t)vqabsh_s16(a);
+}
+
+int32_t test_vqabss_s32(int32_t a) {
+// CHECK: test_vqabss_s32
+// CHECK: sqabs {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vqabss_s32(a);
+}
+
+int64_t test_vqabsd_s64(int64_t a) {
+// CHECK: test_vqabsd_s64
+// CHECK: sqabs {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vqabsd_s64(a);
+}
+
+int64_t test_vnegd_s64(int64_t a) {
+// CHECK: test_vnegd_s64
+// CHECK: neg {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vnegd_s64(a);
+}
+
+int8_t test_vqnegb_s8(int8_t a) {
+// CHECK: test_vqnegb_s8
+// CHECK: sqneg {{b[0-9]+}}, {{b[0-9]+}}
+ return (int8_t)vqnegb_s8(a);
+}
+
+int16_t test_vqnegh_s16(int16_t a) {
+// CHECK: test_vqnegh_s16
+// CHECK: sqneg {{h[0-9]+}}, {{h[0-9]+}}
+ return (int16_t)vqnegh_s16(a);
+}
+
+int32_t test_vqnegs_s32(int32_t a) {
+// CHECK: test_vqnegs_s32
+// CHECK: sqneg {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vqnegs_s32(a);
+}
+
+int64_t test_vqnegd_s64(int64_t a) {
+// CHECK: test_vqnegd_s64
+// CHECK: sqneg {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vqnegd_s64(a);
+}
+
+int8_t test_vuqaddb_s8(int8_t a, int8_t b) {
+// CHECK: test_vuqaddb_s8
+// CHECK: suqadd {{b[0-9]+}}, {{b[0-9]+}}
+ return (int8_t)vuqaddb_s8(a, b);
+}
+
+int16_t test_vuqaddh_s16(int16_t a, int16_t b) {
+// CHECK: test_vuqaddh_s16
+// CHECK: suqadd {{h[0-9]+}}, {{h[0-9]+}}
+ return (int16_t)vuqaddh_s16(a, b);
+}
+
+int32_t test_vuqadds_s32(int32_t a, int32_t b) {
+// CHECK: test_vuqadds_s32
+// CHECK: suqadd {{s[0-9]+}}, {{s[0-9]+}}
+ return (int32_t)vuqadds_s32(a, b);
+}
+
+int64_t test_vuqaddd_s64(int64_t a, int64_t b) {
+// CHECK: test_vuqaddd_s64
+// CHECK: suqadd {{d[0-9]+}}, {{d[0-9]+}}
+ return (int64_t)vuqaddd_s64(a, b);
+}
+
+uint8_t test_vsqaddb_u8(uint8_t a, uint8_t b) {
+// CHECK: test_vsqaddb_u8
+// CHECK: usqadd {{b[0-9]+}}, {{b[0-9]+}}
+ return (uint8_t)vsqaddb_u8(a, b);
+}
+
+uint16_t test_vsqaddh_u16(uint16_t a, uint16_t b) {
+// CHECK: test_vsqaddh_u16
+// CHECK: usqadd {{h[0-9]+}}, {{h[0-9]+}}
+ return (uint16_t)vsqaddh_u16(a, b);
+}
+
+uint32_t test_vsqadds_u32(uint32_t a, uint32_t b) {
+// CHECK: test_vsqadds_u32
+// CHECK: usqadd {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vsqadds_u32(a, b);
+}
+
+uint64_t test_vsqaddd_u64(uint64_t a, uint64_t b) {
+// CHECK: test_vsqaddd_u64
+// CHECK: usqadd {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vsqaddd_u64(a, b);
+}
+
+int32_t test_vqdmlalh_s16(int32_t a, int16_t b, int16_t c) {
+// CHECK: test_vqdmlalh_s16
+// CHECK: sqdmlal {{s[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+ return (int32_t)vqdmlalh_s16(a, b, c);
+}
+
+int64_t test_vqdmlals_s32(int64_t a, int32_t b, int32_t c) {
+// CHECK: test_vqdmlals_s32
+// CHECK: sqdmlal {{d[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (int64_t)vqdmlals_s32(a, b, c);
+}
+
+int32_t test_vqdmlslh_s16(int32_t a, int16_t b, int16_t c) {
+// CHECK: test_vqdmlslh_s16
+// CHECK: sqdmlsl {{s[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+ return (int32_t)vqdmlslh_s16(a, b, c);
+}
+
+int64_t test_vqdmlsls_s32(int64_t a, int32_t b, int32_t c) {
+// CHECK: test_vqdmlsls_s32
+// CHECK: sqdmlsl {{d[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (int64_t)vqdmlsls_s32(a, b, c);
+}
+
+int32_t test_vqdmullh_s16(int16_t a, int16_t b) {
+// CHECK: test_vqdmullh_s16
+// CHECK: sqdmull {{s[0-9]+}}, {{h[0-9]+}}, {{h[0-9]+}}
+ return (int32_t)vqdmullh_s16(a, b);
+}
+
+int64_t test_vqdmulls_s32(int32_t a, int32_t b) {
+// CHECK: test_vqdmulls_s32
+// CHECK: sqdmull {{d[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (int64_t)vqdmulls_s32(a, b);
+}
+
+int8_t test_vqmovunh_s16(int16_t a) {
+// CHECK: test_vqmovunh_s16
+// CHECK: sqxtun {{b[0-9]+}}, {{h[0-9]+}}
+ return (int8_t)vqmovunh_s16(a);
+}
+
+int16_t test_vqmovuns_s32(int32_t a) {
+// CHECK: test_vqmovuns_s32
+// CHECK: sqxtun {{h[0-9]+}}, {{s[0-9]+}}
+ return (int16_t)vqmovuns_s32(a);
+}
+
+int32_t test_vqmovund_s64(int64_t a) {
+// CHECK: test_vqmovund_s64
+// CHECK: sqxtun {{s[0-9]+}}, {{d[0-9]+}}
+ return (int32_t)vqmovund_s64(a);
+}
+
+int8_t test_vqmovnh_s16(int16_t a) {
+// CHECK: test_vqmovnh_s16
+// CHECK: sqxtn {{b[0-9]+}}, {{h[0-9]+}}
+ return (int8_t)vqmovnh_s16(a);
+}
+
+int16_t test_vqmovns_s32(int32_t a) {
+// CHECK: test_vqmovns_s32
+// CHECK: sqxtn {{h[0-9]+}}, {{s[0-9]+}}
+ return (int16_t)vqmovns_s32(a);
+}
+
+int32_t test_vqmovnd_s64(int64_t a) {
+// CHECK: test_vqmovnd_s64
+// CHECK: sqxtn {{s[0-9]+}}, {{d[0-9]+}}
+ return (int32_t)vqmovnd_s64(a);
+}
+
+int8_t test_vqmovnh_u16(int16_t a) {
+// CHECK: test_vqmovnh_u16
+// CHECK: uqxtn {{b[0-9]+}}, {{h[0-9]+}}
+ return (int8_t)vqmovnh_u16(a);
+}
+
+int16_t test_vqmovns_u32(int32_t a) {
+// CHECK: test_vqmovns_u32
+// CHECK: uqxtn {{h[0-9]+}}, {{s[0-9]+}}
+ return (int16_t)vqmovns_u32(a);
+}
+
+int32_t test_vqmovnd_u64(int64_t a) {
+// CHECK: test_vqmovnd_u64
+// CHECK: uqxtn {{s[0-9]+}}, {{d[0-9]+}}
+ return (int32_t)vqmovnd_u64(a);
+}
+
+uint32_t test_vceqs_f32(float32_t a, float32_t b) {
+// CHECK: test_vceqs_f32
+// CHECK: fcmeq {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vceqs_f32(a, b);
+}
+
+uint64_t test_vceqd_f64(float64_t a, float64_t b) {
+// CHECK: test_vceqd_f64
+// CHECK: fcmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vceqd_f64(a, b);
+}
+
+uint32_t test_vceqzs_f32(float32_t a) {
+// CHECK: test_vceqzs_f32
+// CHECK: fcmeq {{s[0-9]+}}, {{s[0-9]+}}, #0.0
+ return (uint32_t)vceqzs_f32(a);
+}
+
+uint64_t test_vceqzd_f64(float64_t a) {
+// CHECK: test_vceqzd_f64
+// CHECK: fcmeq {{d[0-9]+}}, {{d[0-9]+}}, #0.0
+ return (uint64_t)vceqzd_f64(a);
+}
+
+uint32_t test_vcges_f32(float32_t a, float32_t b) {
+// CHECK: test_vcges_f32
+// CHECK: fcmge {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcges_f32(a, b);
+}
+
+uint64_t test_vcged_f64(float64_t a, float64_t b) {
+// CHECK: test_vcged_f64
+// CHECK: fcmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcged_f64(a, b);
+}
+
+uint32_t test_vcgezs_f32(float32_t a) {
+// CHECK: test_vcgezs_f32
+// CHECK: fcmge {{s[0-9]+}}, {{s[0-9]+}}, #0.0
+ return (uint32_t)vcgezs_f32(a);
+}
+
+uint64_t test_vcgezd_f64(float64_t a) {
+// CHECK: test_vcgezd_f64
+// CHECK: fcmge {{d[0-9]+}}, {{d[0-9]+}}, #0.0
+ return (uint64_t)vcgezd_f64(a);
+}
+
+uint32_t test_vcgts_f32(float32_t a, float32_t b) {
+// CHECK: test_vcgts_f32
+// CHECK: fcmgt {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcgts_f32(a, b);
+}
+
+uint64_t test_vcgtd_f64(float64_t a, float64_t b) {
+// CHECK: test_vcgtd_f64
+// CHECK: fcmgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcgtd_f64(a, b);
+}
+
+uint32_t test_vcgtzs_f32(float32_t a) {
+// CHECK: test_vcgtzs_f32
+// CHECK: fcmgt {{s[0-9]+}}, {{s[0-9]+}}, #0.0
+ return (uint32_t)vcgtzs_f32(a);
+}
+
+uint64_t test_vcgtzd_f64(float64_t a) {
+// CHECK: test_vcgtzd_f64
+// CHECK: fcmgt {{d[0-9]+}}, {{d[0-9]+}}, #0.0
+ return (uint64_t)vcgtzd_f64(a);
+}
+
+uint32_t test_vcles_f32(float32_t a, float32_t b) {
+// CHECK: test_vcles_f32
+// CHECK: fcmge {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcles_f32(a, b);
+}
+
+uint64_t test_vcled_f64(float64_t a, float64_t b) {
+// CHECK: test_vcled_f64
+// CHECK: fcmge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcled_f64(a, b);
+}
+
+uint32_t test_vclezs_f32(float32_t a) {
+// CHECK: test_vclezs_f32
+// CHECK: fcmle {{s[0-9]+}}, {{s[0-9]+}}, #0.0
+ return (uint32_t)vclezs_f32(a);
+}
+
+uint64_t test_vclezd_f64(float64_t a) {
+// CHECK: test_vclezd_f64
+// CHECK: fcmle {{d[0-9]+}}, {{d[0-9]+}}, #0.0
+ return (uint64_t)vclezd_f64(a);
+}
+
+uint32_t test_vclts_f32(float32_t a, float32_t b) {
+// CHECK: test_vclts_f32
+// CHECK: fcmgt {{s[0-9]+}}, s1, s0
+ return (uint32_t)vclts_f32(a, b);
+}
+
+uint64_t test_vcltd_f64(float64_t a, float64_t b) {
+// CHECK: test_vcltd_f64
+// CHECK: fcmgt {{d[0-9]+}}, d1, d0
+ return (uint64_t)vcltd_f64(a, b);
+}
+
+uint32_t test_vcltzs_f32(float32_t a) {
+// CHECK: test_vcltzs_f32
+// CHECK: fcmlt {{s[0-9]+}}, {{s[0-9]+}}, #0.0
+ return (uint32_t)vcltzs_f32(a);
+}
+
+uint64_t test_vcltzd_f64(float64_t a) {
+// CHECK: test_vcltzd_f64
+// CHECK: fcmlt {{d[0-9]+}}, {{d[0-9]+}}, #0.0
+ return (uint64_t)vcltzd_f64(a);
+}
+
+uint32_t test_vcages_f32(float32_t a, float32_t b) {
+// CHECK: test_vcages_f32
+// CHECK: facge {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcages_f32(a, b);
+}
+
+uint64_t test_vcaged_f64(float64_t a, float64_t b) {
+// CHECK: test_vcaged_f64
+// CHECK: facge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcaged_f64(a, b);
+}
+
+uint32_t test_vcagts_f32(float32_t a, float32_t b) {
+// CHECK: test_vcagts_f32
+// CHECK: facgt {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcagts_f32(a, b);
+}
+
+uint64_t test_vcagtd_f64(float64_t a, float64_t b) {
+// CHECK: test_vcagtd_f64
+// CHECK: facgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcagtd_f64(a, b);
+}
+
+uint32_t test_vcales_f32(float32_t a, float32_t b) {
+// CHECK: test_vcales_f32
+// CHECK: facge {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcales_f32(a, b);
+}
+
+uint64_t test_vcaled_f64(float64_t a, float64_t b) {
+// CHECK: test_vcaled_f64
+// CHECK: facge {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcaled_f64(a, b);
+}
+
+uint32_t test_vcalts_f32(float32_t a, float32_t b) {
+// CHECK: test_vcalts_f32
+// CHECK: facgt {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return (uint32_t)vcalts_f32(a, b);
+}
+
+uint64_t test_vcaltd_f64(float64_t a, float64_t b) {
+// CHECK: test_vcaltd_f64
+// CHECK: facgt {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return (uint64_t)vcaltd_f64(a, b);
+}
+
+int64_t test_vshrd_n_s64(int64_t a) {
+// CHECK-LABEL: test_vshrd_n_s64
+// CHECK: sshr {{d[0-9]+}}, {{d[0-9]+}}, #1
+ return (int64_t)vshrd_n_s64(a, 1);
+}
+
+int64x1_t test_vshr_n_s64(int64x1_t a) {
+// CHECK-LABEL: test_vshr_n_s64
+// CHECK: sshr {{d[0-9]+}}, {{d[0-9]+}}, #1
+ return vshr_n_s64(a, 1);
+}
+
+uint64_t test_vshrd_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vshrd_n_u64
+// CHECK: ushr {{d[0-9]+}}, {{d[0-9]+}}, #64
+ return (uint64_t)vshrd_n_u64(a, 64);
+}
+
+uint64x1_t test_vshr_n_u64(uint64x1_t a) {
+// CHECK-LABEL: test_vshr_n_u64
+// CHECK: ushr {{d[0-9]+}}, {{d[0-9]+}}, #1
+ return vshr_n_u64(a, 1);
+}
+
+int64_t test_vrshrd_n_s64(int64_t a) {
+// CHECK-LABEL: test_vrshrd_n_s64
+// CHECK: srshr {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vrshrd_n_s64(a, 63);
+}
+
+int64x1_t test_vrshr_n_s64(int64x1_t a) {
+// CHECK: test_vrshr_n_s64
+// CHECK: srshr d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vrshr_n_s64(a, 1);
+}
+
+uint64_t test_vrshrd_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vrshrd_n_u64
+// CHECK: urshr {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vrshrd_n_u64(a, 63);
+}
+
+uint64x1_t test_vrshr_n_u64(uint64x1_t a) {
+// CHECK: test_vrshr_n_u64
+// CHECK: urshr d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vrshr_n_u64(a, 1);
+}
+
+int64_t test_vsrad_n_s64(int64_t a, int64_t b) {
+// CHECK-LABEL: test_vsrad_n_s64
+// CHECK: ssra {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vsrad_n_s64(a, b, 63);
+}
+
+int64x1_t test_vsra_n_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vsra_n_s64
+// CHECK: ssra d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsra_n_s64(a, b, 1);
+}
+
+uint64_t test_vsrad_n_u64(uint64_t a, uint64_t b) {
+// CHECK-LABEL: test_vsrad_n_u64
+// CHECK: usra {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vsrad_n_u64(a, b, 63);
+}
+
+uint64x1_t test_vsra_n_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vsra_n_u64
+// CHECK: usra d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsra_n_u64(a, b, 1);
+}
+
+int64_t test_vrsrad_n_s64(int64_t a, int64_t b) {
+// CHECK-LABEL: test_vrsrad_n_s64
+// CHECK: srsra {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vrsrad_n_s64(a, b, 63);
+}
+
+int64x1_t test_vrsra_n_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vrsra_n_s64
+// CHECK: srsra d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vrsra_n_s64(a, b, 1);
+}
+
+uint64_t test_vrsrad_n_u64(uint64_t a, uint64_t b) {
+// CHECK-LABEL: test_vrsrad_n_u64
+// CHECK: ursra {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vrsrad_n_u64(a, b, 63);
+}
+
+uint64x1_t test_vrsra_n_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vrsra_n_u64
+// CHECK: ursra d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vrsra_n_u64(a, b, 1);
+}
+
+int64_t test_vshld_n_s64(int64_t a) {
+// CHECK-LABEL: test_vshld_n_s64
+// CHECK: shl {{d[0-9]+}}, {{d[0-9]+}}, #0
+ return (int64_t)vshld_n_s64(a, 0);
+}
+int64x1_t test_vshl_n_s64(int64x1_t a) {
+// CHECK: test_vshl_n_s64
+// CHECK: shl d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vshl_n_s64(a, 1);
+}
+
+uint64_t test_vshld_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vshld_n_u64
+// CHECK: shl {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vshld_n_u64(a, 63);
+}
+
+uint64x1_t test_vshl_n_u64(uint64x1_t a) {
+// CHECK: test_vshl_n_u64
+// CHECK: shl d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vshl_n_u64(a, 1);
+}
+
+int8_t test_vqshlb_n_s8(int8_t a) {
+// CHECK-LABEL: test_vqshlb_n_s8
+// CHECK: sqshl {{b[0-9]+}}, {{b[0-9]+}}, #7
+ return (int8_t)vqshlb_n_s8(a, 7);
+}
+
+int16_t test_vqshlh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqshlh_n_s16
+// CHECK: sqshl {{h[0-9]+}}, {{h[0-9]+}}, #15
+ return (int16_t)vqshlh_n_s16(a, 15);
+}
+
+int32_t test_vqshls_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqshls_n_s32
+// CHECK: sqshl {{s[0-9]+}}, {{s[0-9]+}}, #31
+ return (int32_t)vqshls_n_s32(a, 31);
+}
+
+int64_t test_vqshld_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqshld_n_s64
+// CHECK: sqshl {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vqshld_n_s64(a, 63);
+}
+
+int64x1_t test_vqshl_n_s64(int64x1_t a) {
+// CHECK: test_vqshl_n_s64
+// CHECK: sqshl d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vqshl_n_s64(a, 1);
+}
+
+uint8_t test_vqshlb_n_u8(uint8_t a) {
+// CHECK-LABEL: test_vqshlb_n_u8
+// CHECK: uqshl {{b[0-9]+}}, {{b[0-9]+}}, #7
+ return (uint8_t)vqshlb_n_u8(a, 7);
+}
+
+uint16_t test_vqshlh_n_u16(uint16_t a) {
+// CHECK-LABEL: test_vqshlh_n_u16
+// CHECK: uqshl {{h[0-9]+}}, {{h[0-9]+}}, #15
+ return (uint16_t)vqshlh_n_u16(a, 15);
+}
+
+uint32_t test_vqshls_n_u32(uint32_t a) {
+// CHECK-LABEL: test_vqshls_n_u32
+// CHECK: uqshl {{s[0-9]+}}, {{s[0-9]+}}, #31
+ return (uint32_t)vqshls_n_u32(a, 31);
+}
+
+uint64_t test_vqshld_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vqshld_n_u64
+// CHECK: uqshl {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vqshld_n_u64(a, 63);
+}
+
+uint64x1_t test_vqshl_n_u64(uint64x1_t a) {
+// CHECK: test_vqshl_n_u64
+// CHECK: uqshl d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vqshl_n_u64(a, 1);
+}
+
+int8_t test_vqshlub_n_s8(int8_t a) {
+// CHECK-LABEL: test_vqshlub_n_s8
+// CHECK: sqshlu {{b[0-9]+}}, {{b[0-9]+}}, #7
+ return (int8_t)vqshlub_n_s8(a, 7);
+}
+
+int16_t test_vqshluh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqshluh_n_s16
+// CHECK: sqshlu {{h[0-9]+}}, {{h[0-9]+}}, #15
+ return (int16_t)vqshluh_n_s16(a, 15);
+}
+
+int32_t test_vqshlus_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqshlus_n_s32
+// CHECK: sqshlu {{s[0-9]+}}, {{s[0-9]+}}, #31
+ return (int32_t)vqshlus_n_s32(a, 31);
+}
+
+int64_t test_vqshlud_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqshlud_n_s64
+// CHECK: sqshlu {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vqshlud_n_s64(a, 63);
+}
+
+uint64x1_t test_vqshlu_n_s64(int64x1_t a) {
+// CHECK: test_vqshlu_n_s64
+// CHECK: sqshlu d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vqshlu_n_s64(a, 1);
+}
+
+int64_t test_vsrid_n_s64(int64_t a, int64_t b) {
+// CHECK-LABEL: test_vsrid_n_s64
+// CHECK: sri {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vsrid_n_s64(a, b, 63);
+}
+
+int64x1_t test_vsri_n_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vsri_n_s64
+// CHECK: sri d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsri_n_s64(a, b, 1);
+}
+
+uint64_t test_vsrid_n_u64(uint64_t a, uint64_t b) {
+// CHECK-LABEL: test_vsrid_n_u64
+// CHECK: sri {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vsrid_n_u64(a, b, 63);
+}
+
+uint64x1_t test_vsri_n_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vsri_n_u64
+// CHECK: sri d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsri_n_u64(a, b, 1);
+}
+
+int64_t test_vslid_n_s64(int64_t a, int64_t b) {
+// CHECK-LABEL: test_vslid_n_s64
+// CHECK: sli {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (int64_t)vslid_n_s64(a, b, 63);
+}
+
+int64x1_t test_vsli_n_s64(int64x1_t a, int64x1_t b) {
+// CHECK: test_vsli_n_s64
+// CHECK: sli d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsli_n_s64(a, b, 1);
+}
+
+uint64_t test_vslid_n_u64(uint64_t a, uint64_t b) {
+// CHECK-LABEL: test_vslid_n_u64
+// CHECK: sli {{d[0-9]+}}, {{d[0-9]+}}, #63
+ return (uint64_t)vslid_n_u64(a, b, 63);
+}
+
+uint64x1_t test_vsli_n_u64(uint64x1_t a, uint64x1_t b) {
+// CHECK: test_vsli_n_u64
+// CHECK: sli d{{[0-9]+}}, d{{[0-9]+}}, #1
+ return vsli_n_u64(a, b, 1);
+}
+
+int8_t test_vqshrnh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqshrnh_n_s16
+// CHECK: sqshrn {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (int8_t)vqshrnh_n_s16(a, 8);
+}
+
+int16_t test_vqshrns_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqshrns_n_s32
+// CHECK: sqshrn {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (int16_t)vqshrns_n_s32(a, 16);
+}
+
+int32_t test_vqshrnd_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqshrnd_n_s64
+// CHECK: sqshrn {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (int32_t)vqshrnd_n_s64(a, 32);
+}
+
+uint8_t test_vqshrnh_n_u16(uint16_t a) {
+// CHECK-LABEL: test_vqshrnh_n_u16
+// CHECK: uqshrn {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (uint8_t)vqshrnh_n_u16(a, 8);
+}
+
+uint16_t test_vqshrns_n_u32(uint32_t a) {
+// CHECK-LABEL: test_vqshrns_n_u32
+// CHECK: uqshrn {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (uint16_t)vqshrns_n_u32(a, 16);
+}
+
+uint32_t test_vqshrnd_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vqshrnd_n_u64
+// CHECK: uqshrn {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (uint32_t)vqshrnd_n_u64(a, 32);
+}
+
+int8_t test_vqrshrnh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqrshrnh_n_s16
+// CHECK: sqrshrn {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (int8_t)vqrshrnh_n_s16(a, 8);
+}
+
+int16_t test_vqrshrns_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqrshrns_n_s32
+// CHECK: sqrshrn {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (int16_t)vqrshrns_n_s32(a, 16);
+}
+
+int32_t test_vqrshrnd_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqrshrnd_n_s64
+// CHECK: sqrshrn {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (int32_t)vqrshrnd_n_s64(a, 32);
+}
+
+uint8_t test_vqrshrnh_n_u16(uint16_t a) {
+// CHECK-LABEL: test_vqrshrnh_n_u16
+// CHECK: uqrshrn {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (uint8_t)vqrshrnh_n_u16(a, 8);
+}
+
+uint16_t test_vqrshrns_n_u32(uint32_t a) {
+// CHECK-LABEL: test_vqrshrns_n_u32
+// CHECK: uqrshrn {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (uint16_t)vqrshrns_n_u32(a, 16);
+}
+
+uint32_t test_vqrshrnd_n_u64(uint64_t a) {
+// CHECK-LABEL: test_vqrshrnd_n_u64
+// CHECK: uqrshrn {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (uint32_t)vqrshrnd_n_u64(a, 32);
+}
+
+int8_t test_vqshrunh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqshrunh_n_s16
+// CHECK: sqshrun {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (int8_t)vqshrunh_n_s16(a, 8);
+}
+
+int16_t test_vqshruns_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqshruns_n_s32
+// CHECK: sqshrun {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (int16_t)vqshruns_n_s32(a, 16);
+}
+
+int32_t test_vqshrund_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqshrund_n_s64
+// CHECK: sqshrun {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (int32_t)vqshrund_n_s64(a, 32);
+}
+
+int8_t test_vqrshrunh_n_s16(int16_t a) {
+// CHECK-LABEL: test_vqrshrunh_n_s16
+// CHECK: sqrshrun {{b[0-9]+}}, {{h[0-9]+}}, #8
+ return (int8_t)vqrshrunh_n_s16(a, 8);
+}
+
+int16_t test_vqrshruns_n_s32(int32_t a) {
+// CHECK-LABEL: test_vqrshruns_n_s32
+// CHECK: sqrshrun {{h[0-9]+}}, {{s[0-9]+}}, #16
+ return (int16_t)vqrshruns_n_s32(a, 16);
+}
+
+int32_t test_vqrshrund_n_s64(int64_t a) {
+// CHECK-LABEL: test_vqrshrund_n_s64
+// CHECK: sqrshrun {{s[0-9]+}}, {{d[0-9]+}}, #32
+ return (int32_t)vqrshrund_n_s64(a, 32);
+}
+
+float32_t test_vcvts_n_f32_s32(int32_t a) {
+// CHECK: test_vcvts_n_f32_s32
+// CHECK: scvtf {{s[0-9]+}}, {{s[0-9]+}}, #1
+ return vcvts_n_f32_s32(a, 1);
+}
+
+float64_t test_vcvtd_n_f64_s64(int64_t a) {
+// CHECK: test_vcvtd_n_f64_s64
+// CHECK: scvtf {{d[0-9]+}}, {{d[0-9]+}}, #1
+ return vcvtd_n_f64_s64(a, 1);
+}
+
+float32_t test_vcvts_n_f32_u32(uint32_t a) {
+// CHECK: test_vcvts_n_f32_u32
+// CHECK: ucvtf {{s[0-9]+}}, {{s[0-9]+}}, #32
+ return vcvts_n_f32_u32(a, 32);
+}
+
+float64_t test_vcvtd_n_f64_u64(uint64_t a) {
+// CHECK: test_vcvtd_n_f64_u64
+// CHECK: ucvtf {{d[0-9]+}}, {{d[0-9]+}}, #64
+ return vcvtd_n_f64_u64(a, 64);
+}
+
+int32_t test_vcvts_n_s32_f32(float32_t a) {
+// CHECK: test_vcvts_n_s32_f32
+// CHECK: fcvtzs {{s[0-9]+}}, {{s[0-9]+}}, #1
+ return (int32_t)vcvts_n_s32_f32(a, 1);
+}
+
+int64_t test_vcvtd_n_s64_f64(float64_t a) {
+// CHECK: test_vcvtd_n_s64_f64
+// CHECK: fcvtzs {{d[0-9]+}}, {{d[0-9]+}}, #1
+ return (int64_t)vcvtd_n_s64_f64(a, 1);
+}
+
+uint32_t test_vcvts_n_u32_f32(float32_t a) {
+// CHECK: test_vcvts_n_u32_f32
+// CHECK: fcvtzu {{s[0-9]+}}, {{s[0-9]+}}, #32
+ return (uint32_t)vcvts_n_u32_f32(a, 32);
+}
+
+uint64_t test_vcvtd_n_u64_f64(float64_t a) {
+// CHECK: test_vcvtd_n_u64_f64
+// CHECK: fcvtzu {{d[0-9]+}}, {{d[0-9]+}}, #64
+ return (uint64_t)vcvtd_n_u64_f64(a, 64);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_s16
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_s16(int16x4_t a) {
+ return vreinterpret_s8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_s32
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_s32(int32x2_t a) {
+ return vreinterpret_s8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_s64
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_s64(int64x1_t a) {
+ return vreinterpret_s8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_u8
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_u8(uint8x8_t a) {
+ return vreinterpret_s8_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_u16
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_u16(uint16x4_t a) {
+ return vreinterpret_s8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_u32
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_u32(uint32x2_t a) {
+ return vreinterpret_s8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_u64
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_u64(uint64x1_t a) {
+ return vreinterpret_s8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_f16
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_f16(float16x4_t a) {
+ return vreinterpret_s8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_f32
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_f32(float32x2_t a) {
+ return vreinterpret_s8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_f64
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_f64(float64x1_t a) {
+ return vreinterpret_s8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_p8
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_p8(poly8x8_t a) {
+ return vreinterpret_s8_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_p16
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_p16(poly16x4_t a) {
+ return vreinterpret_s8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s8_p64
+// CHECK-NEXT: ret
+int8x8_t test_vreinterpret_s8_p64(poly64x1_t a) {
+ return vreinterpret_s8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_s8
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_s8(int8x8_t a) {
+ return vreinterpret_s16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_s32
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_s32(int32x2_t a) {
+ return vreinterpret_s16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_s64
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_s64(int64x1_t a) {
+ return vreinterpret_s16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_u8
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_u8(uint8x8_t a) {
+ return vreinterpret_s16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_u16
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_u16(uint16x4_t a) {
+ return vreinterpret_s16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_u32
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_u32(uint32x2_t a) {
+ return vreinterpret_s16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_u64
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_u64(uint64x1_t a) {
+ return vreinterpret_s16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_f16
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_f16(float16x4_t a) {
+ return vreinterpret_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_f32
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_f32(float32x2_t a) {
+ return vreinterpret_s16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_f64
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_f64(float64x1_t a) {
+ return vreinterpret_s16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_p8
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_p8(poly8x8_t a) {
+ return vreinterpret_s16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_p16
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_p16(poly16x4_t a) {
+ return vreinterpret_s16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s16_p64
+// CHECK-NEXT: ret
+int16x4_t test_vreinterpret_s16_p64(poly64x1_t a) {
+ return vreinterpret_s16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_s8
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_s8(int8x8_t a) {
+ return vreinterpret_s32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_s16
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_s16(int16x4_t a) {
+ return vreinterpret_s32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_s64
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_s64(int64x1_t a) {
+ return vreinterpret_s32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_u8
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_u8(uint8x8_t a) {
+ return vreinterpret_s32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_u16
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_u16(uint16x4_t a) {
+ return vreinterpret_s32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_u32
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_u32(uint32x2_t a) {
+ return vreinterpret_s32_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_u64
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_u64(uint64x1_t a) {
+ return vreinterpret_s32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_f16
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_f16(float16x4_t a) {
+ return vreinterpret_s32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_f32
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_f32(float32x2_t a) {
+ return vreinterpret_s32_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_f64
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_f64(float64x1_t a) {
+ return vreinterpret_s32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_p8
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_p8(poly8x8_t a) {
+ return vreinterpret_s32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_p16
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_p16(poly16x4_t a) {
+ return vreinterpret_s32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s32_p64
+// CHECK-NEXT: ret
+int32x2_t test_vreinterpret_s32_p64(poly64x1_t a) {
+ return vreinterpret_s32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_s8
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_s8(int8x8_t a) {
+ return vreinterpret_s64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_s16
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_s16(int16x4_t a) {
+ return vreinterpret_s64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_s32
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_s32(int32x2_t a) {
+ return vreinterpret_s64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_u8
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_u8(uint8x8_t a) {
+ return vreinterpret_s64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_u16
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_u16(uint16x4_t a) {
+ return vreinterpret_s64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_u32
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_u32(uint32x2_t a) {
+ return vreinterpret_s64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_u64
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_u64(uint64x1_t a) {
+ return vreinterpret_s64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_f16
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_f16(float16x4_t a) {
+ return vreinterpret_s64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_f32
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_f32(float32x2_t a) {
+ return vreinterpret_s64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_f64
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_f64(float64x1_t a) {
+ return vreinterpret_s64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_p8
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_p8(poly8x8_t a) {
+ return vreinterpret_s64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_p16
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_p16(poly16x4_t a) {
+ return vreinterpret_s64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_s64_p64
+// CHECK-NEXT: ret
+int64x1_t test_vreinterpret_s64_p64(poly64x1_t a) {
+ return vreinterpret_s64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_s8
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_s8(int8x8_t a) {
+ return vreinterpret_u8_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_s16
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_s16(int16x4_t a) {
+ return vreinterpret_u8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_s32
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_s32(int32x2_t a) {
+ return vreinterpret_u8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_s64
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_s64(int64x1_t a) {
+ return vreinterpret_u8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_u16
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_u16(uint16x4_t a) {
+ return vreinterpret_u8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_u32
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_u32(uint32x2_t a) {
+ return vreinterpret_u8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_u64
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_u64(uint64x1_t a) {
+ return vreinterpret_u8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_f16
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_f16(float16x4_t a) {
+ return vreinterpret_u8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_f32
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_f32(float32x2_t a) {
+ return vreinterpret_u8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_f64
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_f64(float64x1_t a) {
+ return vreinterpret_u8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_p8
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_p8(poly8x8_t a) {
+ return vreinterpret_u8_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_p16
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_p16(poly16x4_t a) {
+ return vreinterpret_u8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u8_p64
+// CHECK-NEXT: ret
+uint8x8_t test_vreinterpret_u8_p64(poly64x1_t a) {
+ return vreinterpret_u8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_s8
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_s8(int8x8_t a) {
+ return vreinterpret_u16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_s16
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_s16(int16x4_t a) {
+ return vreinterpret_u16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_s32
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_s32(int32x2_t a) {
+ return vreinterpret_u16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_s64
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_s64(int64x1_t a) {
+ return vreinterpret_u16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_u8
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_u8(uint8x8_t a) {
+ return vreinterpret_u16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_u32
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_u32(uint32x2_t a) {
+ return vreinterpret_u16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_u64
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_u64(uint64x1_t a) {
+ return vreinterpret_u16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_f16
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_f16(float16x4_t a) {
+ return vreinterpret_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_f32
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_f32(float32x2_t a) {
+ return vreinterpret_u16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_f64
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_f64(float64x1_t a) {
+ return vreinterpret_u16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_p8
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_p8(poly8x8_t a) {
+ return vreinterpret_u16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_p16
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_p16(poly16x4_t a) {
+ return vreinterpret_u16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u16_p64
+// CHECK-NEXT: ret
+uint16x4_t test_vreinterpret_u16_p64(poly64x1_t a) {
+ return vreinterpret_u16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_s8
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_s8(int8x8_t a) {
+ return vreinterpret_u32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_s16
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_s16(int16x4_t a) {
+ return vreinterpret_u32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_s32
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_s32(int32x2_t a) {
+ return vreinterpret_u32_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_s64
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_s64(int64x1_t a) {
+ return vreinterpret_u32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_u8
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_u8(uint8x8_t a) {
+ return vreinterpret_u32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_u16
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_u16(uint16x4_t a) {
+ return vreinterpret_u32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_u64
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_u64(uint64x1_t a) {
+ return vreinterpret_u32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_f16
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_f16(float16x4_t a) {
+ return vreinterpret_u32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_f32
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_f32(float32x2_t a) {
+ return vreinterpret_u32_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_f64
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_f64(float64x1_t a) {
+ return vreinterpret_u32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_p8
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_p8(poly8x8_t a) {
+ return vreinterpret_u32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_p16
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_p16(poly16x4_t a) {
+ return vreinterpret_u32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u32_p64
+// CHECK-NEXT: ret
+uint32x2_t test_vreinterpret_u32_p64(poly64x1_t a) {
+ return vreinterpret_u32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_s8
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_s8(int8x8_t a) {
+ return vreinterpret_u64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_s16
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_s16(int16x4_t a) {
+ return vreinterpret_u64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_s32
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_s32(int32x2_t a) {
+ return vreinterpret_u64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_s64
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_s64(int64x1_t a) {
+ return vreinterpret_u64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_u8
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_u8(uint8x8_t a) {
+ return vreinterpret_u64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_u16
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_u16(uint16x4_t a) {
+ return vreinterpret_u64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_u32
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_u32(uint32x2_t a) {
+ return vreinterpret_u64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_f16
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_f16(float16x4_t a) {
+ return vreinterpret_u64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_f32
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_f32(float32x2_t a) {
+ return vreinterpret_u64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_f64
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_f64(float64x1_t a) {
+ return vreinterpret_u64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_p8
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_p8(poly8x8_t a) {
+ return vreinterpret_u64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_p16
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_p16(poly16x4_t a) {
+ return vreinterpret_u64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_u64_p64
+// CHECK-NEXT: ret
+uint64x1_t test_vreinterpret_u64_p64(poly64x1_t a) {
+ return vreinterpret_u64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_s8
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_s8(int8x8_t a) {
+ return vreinterpret_f16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_s16
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_s16(int16x4_t a) {
+ return vreinterpret_f16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_s32
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_s32(int32x2_t a) {
+ return vreinterpret_f16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_s64
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_s64(int64x1_t a) {
+ return vreinterpret_f16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_u8
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_u8(uint8x8_t a) {
+ return vreinterpret_f16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_u16
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_u16(uint16x4_t a) {
+ return vreinterpret_f16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_u32
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_u32(uint32x2_t a) {
+ return vreinterpret_f16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_u64
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_u64(uint64x1_t a) {
+ return vreinterpret_f16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_f32
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_f32(float32x2_t a) {
+ return vreinterpret_f16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_f64
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_f64(float64x1_t a) {
+ return vreinterpret_f16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_p8
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_p8(poly8x8_t a) {
+ return vreinterpret_f16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_p16
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_p16(poly16x4_t a) {
+ return vreinterpret_f16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f16_p64
+// CHECK-NEXT: ret
+float16x4_t test_vreinterpret_f16_p64(poly64x1_t a) {
+ return vreinterpret_f16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_s8
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_s8(int8x8_t a) {
+ return vreinterpret_f32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_s16
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_s16(int16x4_t a) {
+ return vreinterpret_f32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_s32
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_s32(int32x2_t a) {
+ return vreinterpret_f32_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_s64
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_s64(int64x1_t a) {
+ return vreinterpret_f32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_u8
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_u8(uint8x8_t a) {
+ return vreinterpret_f32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_u16
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_u16(uint16x4_t a) {
+ return vreinterpret_f32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_u32
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_u32(uint32x2_t a) {
+ return vreinterpret_f32_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_u64
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_u64(uint64x1_t a) {
+ return vreinterpret_f32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_f16
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_f16(float16x4_t a) {
+ return vreinterpret_f32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_f64
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_f64(float64x1_t a) {
+ return vreinterpret_f32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_p8
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_p8(poly8x8_t a) {
+ return vreinterpret_f32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_p16
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_p16(poly16x4_t a) {
+ return vreinterpret_f32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f32_p64
+// CHECK-NEXT: ret
+float32x2_t test_vreinterpret_f32_p64(poly64x1_t a) {
+ return vreinterpret_f32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_s8
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_s8(int8x8_t a) {
+ return vreinterpret_f64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_s16
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_s16(int16x4_t a) {
+ return vreinterpret_f64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_s32
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_s32(int32x2_t a) {
+ return vreinterpret_f64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_s64
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_s64(int64x1_t a) {
+ return vreinterpret_f64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_u8
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_u8(uint8x8_t a) {
+ return vreinterpret_f64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_u16
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_u16(uint16x4_t a) {
+ return vreinterpret_f64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_u32
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_u32(uint32x2_t a) {
+ return vreinterpret_f64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_u64
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_u64(uint64x1_t a) {
+ return vreinterpret_f64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_f16
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_f16(float16x4_t a) {
+ return vreinterpret_f64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_f32
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_f32(float32x2_t a) {
+ return vreinterpret_f64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_p8
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_p8(poly8x8_t a) {
+ return vreinterpret_f64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_p16
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_p16(poly16x4_t a) {
+ return vreinterpret_f64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_f64_p64
+// CHECK-NEXT: ret
+float64x1_t test_vreinterpret_f64_p64(poly64x1_t a) {
+ return vreinterpret_f64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_s8
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_s8(int8x8_t a) {
+ return vreinterpret_p8_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_s16
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_s16(int16x4_t a) {
+ return vreinterpret_p8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_s32
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_s32(int32x2_t a) {
+ return vreinterpret_p8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_s64
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_s64(int64x1_t a) {
+ return vreinterpret_p8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_u8
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_u8(uint8x8_t a) {
+ return vreinterpret_p8_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_u16
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_u16(uint16x4_t a) {
+ return vreinterpret_p8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_u32
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_u32(uint32x2_t a) {
+ return vreinterpret_p8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_u64
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_u64(uint64x1_t a) {
+ return vreinterpret_p8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_f16
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_f16(float16x4_t a) {
+ return vreinterpret_p8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_f32
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_f32(float32x2_t a) {
+ return vreinterpret_p8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_f64
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_f64(float64x1_t a) {
+ return vreinterpret_p8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_p16
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_p16(poly16x4_t a) {
+ return vreinterpret_p8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p8_p64
+// CHECK-NEXT: ret
+poly8x8_t test_vreinterpret_p8_p64(poly64x1_t a) {
+ return vreinterpret_p8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_s8
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_s8(int8x8_t a) {
+ return vreinterpret_p16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_s16
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_s16(int16x4_t a) {
+ return vreinterpret_p16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_s32
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_s32(int32x2_t a) {
+ return vreinterpret_p16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_s64
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_s64(int64x1_t a) {
+ return vreinterpret_p16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_u8
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_u8(uint8x8_t a) {
+ return vreinterpret_p16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_u16
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_u16(uint16x4_t a) {
+ return vreinterpret_p16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_u32
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_u32(uint32x2_t a) {
+ return vreinterpret_p16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_u64
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_u64(uint64x1_t a) {
+ return vreinterpret_p16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_f16
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_f16(float16x4_t a) {
+ return vreinterpret_p16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_f32
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_f32(float32x2_t a) {
+ return vreinterpret_p16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_f64
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_f64(float64x1_t a) {
+ return vreinterpret_p16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_p8
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_p8(poly8x8_t a) {
+ return vreinterpret_p16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p16_p64
+// CHECK-NEXT: ret
+poly16x4_t test_vreinterpret_p16_p64(poly64x1_t a) {
+ return vreinterpret_p16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_s8
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_s8(int8x8_t a) {
+ return vreinterpret_p64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_s16
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_s16(int16x4_t a) {
+ return vreinterpret_p64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_s32
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_s32(int32x2_t a) {
+ return vreinterpret_p64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_s64
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_s64(int64x1_t a) {
+ return vreinterpret_p64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_u8
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_u8(uint8x8_t a) {
+ return vreinterpret_p64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_u16
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_u16(uint16x4_t a) {
+ return vreinterpret_p64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_u32
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_u32(uint32x2_t a) {
+ return vreinterpret_p64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_u64
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_u64(uint64x1_t a) {
+ return vreinterpret_p64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_f16
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_f16(float16x4_t a) {
+ return vreinterpret_p64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_f32
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_f32(float32x2_t a) {
+ return vreinterpret_p64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_f64
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_f64(float64x1_t a) {
+ return vreinterpret_p64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_p8
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_p8(poly8x8_t a) {
+ return vreinterpret_p64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpret_p64_p16
+// CHECK-NEXT: ret
+poly64x1_t test_vreinterpret_p64_p16(poly16x4_t a) {
+ return vreinterpret_p64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_s16
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_s16(int16x8_t a) {
+ return vreinterpretq_s8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_s32
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_s32(int32x4_t a) {
+ return vreinterpretq_s8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_s64
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_s64(int64x2_t a) {
+ return vreinterpretq_s8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_u8
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_u8(uint8x16_t a) {
+ return vreinterpretq_s8_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_u16
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_u16(uint16x8_t a) {
+ return vreinterpretq_s8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_u32
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_u32(uint32x4_t a) {
+ return vreinterpretq_s8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_u64
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_u64(uint64x2_t a) {
+ return vreinterpretq_s8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_f16
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_f16(float16x8_t a) {
+ return vreinterpretq_s8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_f32
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_f32(float32x4_t a) {
+ return vreinterpretq_s8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_f64
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_f64(float64x2_t a) {
+ return vreinterpretq_s8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_p8
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_p8(poly8x16_t a) {
+ return vreinterpretq_s8_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_p16
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_p16(poly16x8_t a) {
+ return vreinterpretq_s8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s8_p64
+// CHECK-NEXT: ret
+int8x16_t test_vreinterpretq_s8_p64(poly64x2_t a) {
+ return vreinterpretq_s8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_s8
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_s8(int8x16_t a) {
+ return vreinterpretq_s16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_s32
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_s32(int32x4_t a) {
+ return vreinterpretq_s16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_s64
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_s64(int64x2_t a) {
+ return vreinterpretq_s16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_u8
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_u8(uint8x16_t a) {
+ return vreinterpretq_s16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_u16
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_u16(uint16x8_t a) {
+ return vreinterpretq_s16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_u32
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_u32(uint32x4_t a) {
+ return vreinterpretq_s16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_u64
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_u64(uint64x2_t a) {
+ return vreinterpretq_s16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_f16
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_f16(float16x8_t a) {
+ return vreinterpretq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_f32
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_f32(float32x4_t a) {
+ return vreinterpretq_s16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_f64
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_f64(float64x2_t a) {
+ return vreinterpretq_s16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_p8
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_p8(poly8x16_t a) {
+ return vreinterpretq_s16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_p16
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_p16(poly16x8_t a) {
+ return vreinterpretq_s16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s16_p64
+// CHECK-NEXT: ret
+int16x8_t test_vreinterpretq_s16_p64(poly64x2_t a) {
+ return vreinterpretq_s16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_s8
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_s8(int8x16_t a) {
+ return vreinterpretq_s32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_s16
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_s16(int16x8_t a) {
+ return vreinterpretq_s32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_s64
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_s64(int64x2_t a) {
+ return vreinterpretq_s32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_u8
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_u8(uint8x16_t a) {
+ return vreinterpretq_s32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_u16
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_u16(uint16x8_t a) {
+ return vreinterpretq_s32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_u32
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_u32(uint32x4_t a) {
+ return vreinterpretq_s32_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_u64
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_u64(uint64x2_t a) {
+ return vreinterpretq_s32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_f16
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_f16(float16x8_t a) {
+ return vreinterpretq_s32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_f32
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_f32(float32x4_t a) {
+ return vreinterpretq_s32_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_f64
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_f64(float64x2_t a) {
+ return vreinterpretq_s32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_p8
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_p8(poly8x16_t a) {
+ return vreinterpretq_s32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_p16
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_p16(poly16x8_t a) {
+ return vreinterpretq_s32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s32_p64
+// CHECK-NEXT: ret
+int32x4_t test_vreinterpretq_s32_p64(poly64x2_t a) {
+ return vreinterpretq_s32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_s8
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_s8(int8x16_t a) {
+ return vreinterpretq_s64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_s16
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_s16(int16x8_t a) {
+ return vreinterpretq_s64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_s32
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_s32(int32x4_t a) {
+ return vreinterpretq_s64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_u8
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_u8(uint8x16_t a) {
+ return vreinterpretq_s64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_u16
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_u16(uint16x8_t a) {
+ return vreinterpretq_s64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_u32
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_u32(uint32x4_t a) {
+ return vreinterpretq_s64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_u64
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_u64(uint64x2_t a) {
+ return vreinterpretq_s64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_f16
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_f16(float16x8_t a) {
+ return vreinterpretq_s64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_f32
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_f32(float32x4_t a) {
+ return vreinterpretq_s64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_f64
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_f64(float64x2_t a) {
+ return vreinterpretq_s64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_p8
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_p8(poly8x16_t a) {
+ return vreinterpretq_s64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_p16
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_p16(poly16x8_t a) {
+ return vreinterpretq_s64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_s64_p64
+// CHECK-NEXT: ret
+int64x2_t test_vreinterpretq_s64_p64(poly64x2_t a) {
+ return vreinterpretq_s64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_s8
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_s8(int8x16_t a) {
+ return vreinterpretq_u8_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_s16
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_s16(int16x8_t a) {
+ return vreinterpretq_u8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_s32
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_s32(int32x4_t a) {
+ return vreinterpretq_u8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_s64
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_s64(int64x2_t a) {
+ return vreinterpretq_u8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_u16
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_u16(uint16x8_t a) {
+ return vreinterpretq_u8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_u32
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_u32(uint32x4_t a) {
+ return vreinterpretq_u8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_u64
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_u64(uint64x2_t a) {
+ return vreinterpretq_u8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_f16
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_f16(float16x8_t a) {
+ return vreinterpretq_u8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_f32
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_f32(float32x4_t a) {
+ return vreinterpretq_u8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_f64
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_f64(float64x2_t a) {
+ return vreinterpretq_u8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_p8
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_p8(poly8x16_t a) {
+ return vreinterpretq_u8_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_p16
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_p16(poly16x8_t a) {
+ return vreinterpretq_u8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u8_p64
+// CHECK-NEXT: ret
+uint8x16_t test_vreinterpretq_u8_p64(poly64x2_t a) {
+ return vreinterpretq_u8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_s8
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_s8(int8x16_t a) {
+ return vreinterpretq_u16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_s16
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_s16(int16x8_t a) {
+ return vreinterpretq_u16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_s32
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_s32(int32x4_t a) {
+ return vreinterpretq_u16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_s64
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_s64(int64x2_t a) {
+ return vreinterpretq_u16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_u8
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_u8(uint8x16_t a) {
+ return vreinterpretq_u16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_u32
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_u32(uint32x4_t a) {
+ return vreinterpretq_u16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_u64
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_u64(uint64x2_t a) {
+ return vreinterpretq_u16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_f16
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_f16(float16x8_t a) {
+ return vreinterpretq_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_f32
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_f32(float32x4_t a) {
+ return vreinterpretq_u16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_f64
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_f64(float64x2_t a) {
+ return vreinterpretq_u16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_p8
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_p8(poly8x16_t a) {
+ return vreinterpretq_u16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_p16
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_p16(poly16x8_t a) {
+ return vreinterpretq_u16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u16_p64
+// CHECK-NEXT: ret
+uint16x8_t test_vreinterpretq_u16_p64(poly64x2_t a) {
+ return vreinterpretq_u16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_s8
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_s8(int8x16_t a) {
+ return vreinterpretq_u32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_s16
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_s16(int16x8_t a) {
+ return vreinterpretq_u32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_s32
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_s32(int32x4_t a) {
+ return vreinterpretq_u32_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_s64
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_s64(int64x2_t a) {
+ return vreinterpretq_u32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_u8
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_u8(uint8x16_t a) {
+ return vreinterpretq_u32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_u16
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_u16(uint16x8_t a) {
+ return vreinterpretq_u32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_u64
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_u64(uint64x2_t a) {
+ return vreinterpretq_u32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_f16
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_f16(float16x8_t a) {
+ return vreinterpretq_u32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_f32
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_f32(float32x4_t a) {
+ return vreinterpretq_u32_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_f64
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_f64(float64x2_t a) {
+ return vreinterpretq_u32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_p8
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_p8(poly8x16_t a) {
+ return vreinterpretq_u32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_p16
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_p16(poly16x8_t a) {
+ return vreinterpretq_u32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u32_p64
+// CHECK-NEXT: ret
+uint32x4_t test_vreinterpretq_u32_p64(poly64x2_t a) {
+ return vreinterpretq_u32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_s8
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_s8(int8x16_t a) {
+ return vreinterpretq_u64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_s16
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_s16(int16x8_t a) {
+ return vreinterpretq_u64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_s32
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_s32(int32x4_t a) {
+ return vreinterpretq_u64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_s64
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_s64(int64x2_t a) {
+ return vreinterpretq_u64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_u8
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_u8(uint8x16_t a) {
+ return vreinterpretq_u64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_u16
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_u16(uint16x8_t a) {
+ return vreinterpretq_u64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_u32
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_u32(uint32x4_t a) {
+ return vreinterpretq_u64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_f16
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_f16(float16x8_t a) {
+ return vreinterpretq_u64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_f32
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_f32(float32x4_t a) {
+ return vreinterpretq_u64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_f64
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_f64(float64x2_t a) {
+ return vreinterpretq_u64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_p8
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_p8(poly8x16_t a) {
+ return vreinterpretq_u64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_p16
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_p16(poly16x8_t a) {
+ return vreinterpretq_u64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_u64_p64
+// CHECK-NEXT: ret
+uint64x2_t test_vreinterpretq_u64_p64(poly64x2_t a) {
+ return vreinterpretq_u64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_s8
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_s8(int8x16_t a) {
+ return vreinterpretq_f16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_s16
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_s16(int16x8_t a) {
+ return vreinterpretq_f16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_s32
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_s32(int32x4_t a) {
+ return vreinterpretq_f16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_s64
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_s64(int64x2_t a) {
+ return vreinterpretq_f16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_u8
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_u8(uint8x16_t a) {
+ return vreinterpretq_f16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_u16
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_u16(uint16x8_t a) {
+ return vreinterpretq_f16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_u32
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_u32(uint32x4_t a) {
+ return vreinterpretq_f16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_u64
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_u64(uint64x2_t a) {
+ return vreinterpretq_f16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_f32
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_f32(float32x4_t a) {
+ return vreinterpretq_f16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_f64
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_f64(float64x2_t a) {
+ return vreinterpretq_f16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_p8
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_p8(poly8x16_t a) {
+ return vreinterpretq_f16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_p16
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_p16(poly16x8_t a) {
+ return vreinterpretq_f16_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f16_p64
+// CHECK-NEXT: ret
+float16x8_t test_vreinterpretq_f16_p64(poly64x2_t a) {
+ return vreinterpretq_f16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_s8
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_s8(int8x16_t a) {
+ return vreinterpretq_f32_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_s16
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_s16(int16x8_t a) {
+ return vreinterpretq_f32_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_s32
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_s32(int32x4_t a) {
+ return vreinterpretq_f32_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_s64
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_s64(int64x2_t a) {
+ return vreinterpretq_f32_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_u8
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_u8(uint8x16_t a) {
+ return vreinterpretq_f32_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_u16
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_u16(uint16x8_t a) {
+ return vreinterpretq_f32_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_u32
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_u32(uint32x4_t a) {
+ return vreinterpretq_f32_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_u64
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_u64(uint64x2_t a) {
+ return vreinterpretq_f32_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_f16
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_f16(float16x8_t a) {
+ return vreinterpretq_f32_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_f64
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_f64(float64x2_t a) {
+ return vreinterpretq_f32_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_p8
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_p8(poly8x16_t a) {
+ return vreinterpretq_f32_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_p16
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_p16(poly16x8_t a) {
+ return vreinterpretq_f32_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f32_p64
+// CHECK-NEXT: ret
+float32x4_t test_vreinterpretq_f32_p64(poly64x2_t a) {
+ return vreinterpretq_f32_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_s8
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_s8(int8x16_t a) {
+ return vreinterpretq_f64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_s16
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_s16(int16x8_t a) {
+ return vreinterpretq_f64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_s32
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_s32(int32x4_t a) {
+ return vreinterpretq_f64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_s64
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_s64(int64x2_t a) {
+ return vreinterpretq_f64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_u8
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_u8(uint8x16_t a) {
+ return vreinterpretq_f64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_u16
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_u16(uint16x8_t a) {
+ return vreinterpretq_f64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_u32
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_u32(uint32x4_t a) {
+ return vreinterpretq_f64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_u64
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_u64(uint64x2_t a) {
+ return vreinterpretq_f64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_f16
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_f16(float16x8_t a) {
+ return vreinterpretq_f64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_f32
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_f32(float32x4_t a) {
+ return vreinterpretq_f64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_p8
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_p8(poly8x16_t a) {
+ return vreinterpretq_f64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_p16
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_p16(poly16x8_t a) {
+ return vreinterpretq_f64_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_f64_p64
+// CHECK-NEXT: ret
+float64x2_t test_vreinterpretq_f64_p64(poly64x2_t a) {
+ return vreinterpretq_f64_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_s8
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_s8(int8x16_t a) {
+ return vreinterpretq_p8_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_s16
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_s16(int16x8_t a) {
+ return vreinterpretq_p8_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_s32
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_s32(int32x4_t a) {
+ return vreinterpretq_p8_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_s64
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_s64(int64x2_t a) {
+ return vreinterpretq_p8_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_u8
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_u8(uint8x16_t a) {
+ return vreinterpretq_p8_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_u16
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_u16(uint16x8_t a) {
+ return vreinterpretq_p8_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_u32
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_u32(uint32x4_t a) {
+ return vreinterpretq_p8_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_u64
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_u64(uint64x2_t a) {
+ return vreinterpretq_p8_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_f16
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_f16(float16x8_t a) {
+ return vreinterpretq_p8_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_f32
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_f32(float32x4_t a) {
+ return vreinterpretq_p8_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_f64
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_f64(float64x2_t a) {
+ return vreinterpretq_p8_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_p16
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_p16(poly16x8_t a) {
+ return vreinterpretq_p8_p16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p8_p64
+// CHECK-NEXT: ret
+poly8x16_t test_vreinterpretq_p8_p64(poly64x2_t a) {
+ return vreinterpretq_p8_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_s8
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_s8(int8x16_t a) {
+ return vreinterpretq_p16_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_s16
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_s16(int16x8_t a) {
+ return vreinterpretq_p16_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_s32
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_s32(int32x4_t a) {
+ return vreinterpretq_p16_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_s64
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_s64(int64x2_t a) {
+ return vreinterpretq_p16_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_u8
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_u8(uint8x16_t a) {
+ return vreinterpretq_p16_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_u16
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_u16(uint16x8_t a) {
+ return vreinterpretq_p16_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_u32
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_u32(uint32x4_t a) {
+ return vreinterpretq_p16_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_u64
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_u64(uint64x2_t a) {
+ return vreinterpretq_p16_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_f16
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_f16(float16x8_t a) {
+ return vreinterpretq_p16_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_f32
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_f32(float32x4_t a) {
+ return vreinterpretq_p16_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_f64
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_f64(float64x2_t a) {
+ return vreinterpretq_p16_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_p8
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_p8(poly8x16_t a) {
+ return vreinterpretq_p16_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p16_p64
+// CHECK-NEXT: ret
+poly16x8_t test_vreinterpretq_p16_p64(poly64x2_t a) {
+ return vreinterpretq_p16_p64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_s8
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_s8(int8x16_t a) {
+ return vreinterpretq_p64_s8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_s16
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_s16(int16x8_t a) {
+ return vreinterpretq_p64_s16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_s32
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_s32(int32x4_t a) {
+ return vreinterpretq_p64_s32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_s64
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_s64(int64x2_t a) {
+ return vreinterpretq_p64_s64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_u8
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_u8(uint8x16_t a) {
+ return vreinterpretq_p64_u8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_u16
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_u16(uint16x8_t a) {
+ return vreinterpretq_p64_u16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_u32
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_u32(uint32x4_t a) {
+ return vreinterpretq_p64_u32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_u64
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_u64(uint64x2_t a) {
+ return vreinterpretq_p64_u64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_f16
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_f16(float16x8_t a) {
+ return vreinterpretq_p64_f16(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_f32
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_f32(float32x4_t a) {
+ return vreinterpretq_p64_f32(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_f64
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_f64(float64x2_t a) {
+ return vreinterpretq_p64_f64(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_p8
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_p8(poly8x16_t a) {
+ return vreinterpretq_p64_p8(a);
+}
+
+// CHECK-LABEL: test_vreinterpretq_p64_p16
+// CHECK-NEXT: ret
+poly64x2_t test_vreinterpretq_p64_p16(poly16x8_t a) {
+ return vreinterpretq_p64_p16(a);
+}
+
+float32_t test_vabds_f32(float32_t a, float32_t b) {
+// CHECK-LABEL: test_vabds_f32
+// CHECK: fabd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+ return vabds_f32(a, b);
+}
+
+float64_t test_vabdd_f64(float64_t a, float64_t b) {
+// CHECK-LABEL: test_vabdd_f64
+// CHECK: fabd {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+ return vabdd_f64(a, b);
+}
+
+int64x1_t test_vuqadd_s64(int64x1_t a, uint64x1_t b) {
+ // CHECK-LABEL: test_vuqadd_s64
+ return vuqadd_s64(a, b);
+ // CHECK: suqadd d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vsqadd_u64(uint64x1_t a, int64x1_t b) {
+ // CHECK-LABEL: test_vsqadd_u64
+ return vsqadd_u64(a, b);
+ // CHECK: usqadd d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vabs_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vabs_s64
+ return vabs_s64(a);
+ // CHECK: abs d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vqabs_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vqabs_s64
+ return vqabs_s64(a);
+ // CHECK: sqabs d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vqneg_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vqneg_s64
+ return vqneg_s64(a);
+ // CHECK: sqneg d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vneg_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vneg_s64
+ return vneg_s64(a);
+ // CHECK: neg d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float32_t test_vaddv_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vaddv_f32
+ return vaddv_f32(a);
+ // CHECK: faddp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+float32_t test_vaddvq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vaddvq_f32
+ return vaddvq_f32(a);
+ // CHECK: faddp {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: faddp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+float64_t test_vaddvq_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vaddvq_f64
+ return vaddvq_f64(a);
+ // CHECK: faddp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float32_t test_vmaxv_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vmaxv_f32
+ return vmaxv_f32(a);
+ // CHECK: fmaxp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+float64_t test_vmaxvq_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vmaxvq_f64
+ return vmaxvq_f64(a);
+ // CHECK: fmaxp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float32_t test_vminv_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vminv_f32
+ return vminv_f32(a);
+ // CHECK: fminp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+float64_t test_vminvq_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vminvq_f64
+ return vminvq_f64(a);
+ // CHECK: fminp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float64_t test_vmaxnmvq_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vmaxnmvq_f64
+ return vmaxnmvq_f64(a);
+ // CHECK: fmaxnmp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float32_t test_vmaxnmv_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vmaxnmv_f32
+ return vmaxnmv_f32(a);
+ // CHECK: fmaxnmp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+float64_t test_vminnmvq_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vminnmvq_f64
+ return vminnmvq_f64(a);
+ // CHECK: fminnmp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float32_t test_vminnmv_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vminnmv_f32
+ return vminnmv_f32(a);
+ // CHECK: fminnmp {{s[0-9]+}}, {{v[0-9]+}}.2s
+}
+
+int64x2_t test_vpaddq_s64(int64x2_t a, int64x2_t b) {
+ // CHECK-LABEL: test_vpaddq_s64
+ return vpaddq_s64(a, b);
+ // CHECK: addp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x2_t test_vpaddq_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK-LABEL: test_vpaddq_u64
+ return vpaddq_u64(a, b);
+ // CHECK: addp {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64_t test_vpaddd_u64(uint64x2_t a) {
+ // CHECK-LABEL: test_vpaddd_u64
+ return vpaddd_u64(a);
+ // CHECK: addp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+int64_t test_vaddvq_s64(int64x2_t a) {
+ // CHECK-LABEL: test_vaddvq_s64
+ return vaddvq_s64(a);
+ // CHECK: addp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+uint64_t test_vaddvq_u64(uint64x2_t a) {
+ // CHECK-LABEL: test_vaddvq_u64
+ return vaddvq_u64(a);
+ // CHECK: addp {{d[0-9]+}}, {{v[0-9]+}}.2d
+}
+
+float64x1_t test_vadd_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vadd_f64
+ return vadd_f64(a, b);
+ // CHECK: fadd d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmul_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vmul_f64
+ return vmul_f64(a, b);
+ // CHECK: fmul d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vdiv_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vdiv_f64
+ return vdiv_f64(a, b);
+ // CHECK: fdiv d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmla_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
+ // CHECK-LABEL: test_vmla_f64
+ return vmla_f64(a, b, c);
+ // CHECK: fmadd d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmls_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
+ // CHECK-LABEL: test_vmls_f64
+ return vmls_f64(a, b, c);
+ // CHECK: fmsub d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
+ // CHECK-LABEL: test_vfma_f64
+ return vfma_f64(a, b, c);
+ // CHECK: fmadd d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vfms_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
+ // CHECK-LABEL: test_vfms_f64
+ return vfms_f64(a, b, c);
+ // CHECK: fmsub d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vsub_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vsub_f64
+ return vsub_f64(a, b);
+ // CHECK: fsub d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vabd_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vabd_f64
+ return vabd_f64(a, b);
+ // CHECK: fabd d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmax_f64(float64x1_t a, float64x1_t b) {
+// CHECK-LABEL: test_vmax_f64
+ return vmax_f64(a, b);
+// CHECK: fmax d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmin_f64(float64x1_t a, float64x1_t b) {
+// CHECK-LABEL: test_vmin_f64
+ return vmin_f64(a, b);
+// CHECK: fmin d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vmaxnm_f64(float64x1_t a, float64x1_t b) {
+// CHECK-LABEL: test_vmaxnm_f64
+ return vmaxnm_f64(a, b);
+// CHECK: fmaxnm d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vminnm_f64(float64x1_t a, float64x1_t b) {
+// CHECK-LABEL: test_vminnm_f64
+ return vminnm_f64(a, b);
+// CHECK: fminnm d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vabs_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vabs_f64
+ return vabs_f64(a);
+ // CHECK: fabs d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vneg_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vneg_f64
+ return vneg_f64(a);
+ // CHECK: fneg d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvt_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvt_s64_f64
+ return vcvt_s64_f64(a);
+ // CHECK: fcvtzs d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vcvt_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvt_u64_f64
+ return vcvt_u64_f64(a);
+ // CHECK: fcvtzu d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvtn_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtn_s64_f64
+ return vcvtn_s64_f64(a);
+ // CHECK: fcvtns d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vcvtn_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtn_u64_f64
+ return vcvtn_u64_f64(a);
+ // CHECK: fcvtnu d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvtp_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtp_s64_f64
+ return vcvtp_s64_f64(a);
+ // CHECK: fcvtps d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vcvtp_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtp_u64_f64
+ return vcvtp_u64_f64(a);
+ // CHECK: fcvtpu d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvtm_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtm_s64_f64
+ return vcvtm_s64_f64(a);
+ // CHECK: fcvtms d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vcvtm_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvtm_u64_f64
+ return vcvtm_u64_f64(a);
+ // CHECK: fcvtmu d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvta_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvta_s64_f64
+ return vcvta_s64_f64(a);
+ // CHECK: fcvtas d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+uint64x1_t test_vcvta_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvta_u64_f64
+ return vcvta_u64_f64(a);
+ // CHECK: fcvtau d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vcvt_f64_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vcvt_f64_s64
+ return vcvt_f64_s64(a);
+ // CHECK: scvtf d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vcvt_f64_u64(uint64x1_t a) {
+ // CHECK-LABEL: test_vcvt_f64_u64
+ return vcvt_f64_u64(a);
+ // CHECK: ucvtf d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+int64x1_t test_vcvt_n_s64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvt_n_s64_f64
+ return vcvt_n_s64_f64(a, 64);
+ // CHECK: fcvtzs d{{[0-9]+}}, d{{[0-9]+}}, #64
+}
+
+uint64x1_t test_vcvt_n_u64_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vcvt_n_u64_f64
+ return vcvt_n_u64_f64(a, 64);
+ // CHECK: fcvtzu d{{[0-9]+}}, d{{[0-9]+}}, #64
+}
+
+float64x1_t test_vcvt_n_f64_s64(int64x1_t a) {
+ // CHECK-LABEL: test_vcvt_n_f64_s64
+ return vcvt_n_f64_s64(a, 64);
+ // CHECK: scvtf d{{[0-9]+}}, d{{[0-9]+}}, #64
+}
+
+float64x1_t test_vcvt_n_f64_u64(uint64x1_t a) {
+ // CHECK-LABEL: test_vcvt_n_f64_u64
+ return vcvt_n_f64_u64(a, 64);
+ // CHECK: ucvtf d{{[0-9]+}}, d{{[0-9]+}}, #64
+}
+
+float64x1_t test_vrndn_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrndn_f64
+ return vrndn_f64(a);
+ // CHECK: frintn d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrnda_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrnda_f64
+ return vrnda_f64(a);
+ // CHECK: frinta d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrndp_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrndp_f64
+ return vrndp_f64(a);
+ // CHECK: frintp d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrndm_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrndm_f64
+ return vrndm_f64(a);
+ // CHECK: frintm d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrndx_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrndx_f64
+ return vrndx_f64(a);
+ // CHECK: frintx d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrnd_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrnd_f64
+ return vrnd_f64(a);
+ // CHECK: frintz d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrndi_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrndi_f64
+ return vrndi_f64(a);
+ // CHECK: frinti d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrsqrte_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrsqrte_f64
+ return vrsqrte_f64(a);
+ // CHECK: frsqrte d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrecpe_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vrecpe_f64
+ return vrecpe_f64(a);
+ // CHECK: frecpe d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vsqrt_f64(float64x1_t a) {
+ // CHECK-LABEL: test_vsqrt_f64
+ return vsqrt_f64(a);
+ // CHECK: fsqrt d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrecps_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vrecps_f64
+ return vrecps_f64(a, b);
+ // CHECK: frecps d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
+
+float64x1_t test_vrsqrts_f64(float64x1_t a, float64x1_t b) {
+ // CHECK-LABEL: test_vrsqrts_f64
+ return vrsqrts_f64(a, b);
+ // CHECK: frsqrts d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+}
diff --git a/test/CodeGen/aarch64-neon-ldst-one.c b/test/CodeGen/aarch64-neon-ldst-one.c
new file mode 100644
index 000000000000..f629260dc8ee
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-ldst-one.c
@@ -0,0 +1,2047 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+uint8x16_t test_vld1q_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_u8
+ return vld1q_dup_u8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8_t test_vld1q_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_u16
+ return vld1q_dup_u16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4_t test_vld1q_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_u32
+ return vld1q_dup_u32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2_t test_vld1q_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_u64
+ return vld1q_dup_u64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16_t test_vld1q_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_s8
+ return vld1q_dup_s8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8_t test_vld1q_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_s16
+ return vld1q_dup_s16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4_t test_vld1q_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_s32
+ return vld1q_dup_s32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2_t test_vld1q_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_s64
+ return vld1q_dup_s64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8_t test_vld1q_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_f16
+ return vld1q_dup_f16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4_t test_vld1q_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_f32
+ return vld1q_dup_f32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2_t test_vld1q_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_f64
+ return vld1q_dup_f64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16_t test_vld1q_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_p8
+ return vld1q_dup_p8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8_t test_vld1q_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_p16
+ return vld1q_dup_p16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2_t test_vld1q_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1q_dup_p64
+ return vld1q_dup_p64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8_t test_vld1_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_u8
+ return vld1_dup_u8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4_t test_vld1_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_u16
+ return vld1_dup_u16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2_t test_vld1_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_u32
+ return vld1_dup_u32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1_t test_vld1_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_u64
+ return vld1_dup_u64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8_t test_vld1_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_s8
+ return vld1_dup_s8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4_t test_vld1_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_s16
+ return vld1_dup_s16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2_t test_vld1_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_s32
+ return vld1_dup_s32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1_t test_vld1_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_s64
+ return vld1_dup_s64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4_t test_vld1_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_f16
+ return vld1_dup_f16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2_t test_vld1_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_f32
+ return vld1_dup_f32(a);
+ // CHECK: ld1r {v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1_t test_vld1_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_f64
+ return vld1_dup_f64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8_t test_vld1_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_p8
+ return vld1_dup_p8(a);
+ // CHECK: ld1r {v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4_t test_vld1_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_p16
+ return vld1_dup_p16(a);
+ // CHECK: ld1r {v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1_t test_vld1_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld1_dup_p64
+ return vld1_dup_p64(a);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x2_t test_vld2q_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_u8
+ return vld2q_dup_u8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x2_t test_vld2q_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_u16
+ return vld2q_dup_u16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x2_t test_vld2q_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_u32
+ return vld2q_dup_u32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x2_t test_vld2q_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_u64
+ return vld2q_dup_u64(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x2_t test_vld2q_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_s8
+ return vld2q_dup_s8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x2_t test_vld2q_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_s16
+ return vld2q_dup_s16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x2_t test_vld2q_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_s32
+ return vld2q_dup_s32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x2_t test_vld2q_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_s64
+ return vld2q_dup_s64(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x2_t test_vld2q_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_f16
+ return vld2q_dup_f16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x2_t test_vld2q_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_f32
+ return vld2q_dup_f32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x2_t test_vld2q_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_f64
+ return vld2q_dup_f64(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x2_t test_vld2q_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_p8
+ return vld2q_dup_p8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x2_t test_vld2q_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_p16
+ return vld2q_dup_p16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x2_t test_vld2q_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld2q_dup_p64
+ return vld2q_dup_p64(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x2_t test_vld2_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_u8
+ return vld2_dup_u8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x2_t test_vld2_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_u16
+ return vld2_dup_u16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x2_t test_vld2_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_u32
+ return vld2_dup_u32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x2_t test_vld2_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_u64
+ return vld2_dup_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x2_t test_vld2_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_s8
+ return vld2_dup_s8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x2_t test_vld2_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_s16
+ return vld2_dup_s16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x2_t test_vld2_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_s32
+ return vld2_dup_s32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x2_t test_vld2_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_s64
+ return vld2_dup_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x2_t test_vld2_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_f16
+ return vld2_dup_f16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x2_t test_vld2_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_f32
+ return vld2_dup_f32(a);
+ // CHECK: ld2r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x2_t test_vld2_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_f64
+ return vld2_dup_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x2_t test_vld2_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_p8
+ return vld2_dup_p8(a);
+ // CHECK: ld2r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x2_t test_vld2_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_p16
+ return vld2_dup_p16(a);
+ // CHECK: ld2r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x2_t test_vld2_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld2_dup_p64
+ return vld2_dup_p64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16x3_t test_vld3q_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_u8
+ return vld3q_dup_u8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x8x3_t test_vld3q_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_u16
+ return vld3q_dup_u16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x4x3_t test_vld3q_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_u32
+ return vld3q_dup_u32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x2x3_t test_vld3q_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_u64
+ return vld3q_dup_u64(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x16x3_t test_vld3q_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_s8
+ return vld3q_dup_s8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x8x3_t test_vld3q_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_s16
+ return vld3q_dup_s16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x4x3_t test_vld3q_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_s32
+ return vld3q_dup_s32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x2x3_t test_vld3q_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_s64
+ return vld3q_dup_s64(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x8x3_t test_vld3q_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_f16
+ return vld3q_dup_f16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x4x3_t test_vld3q_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_f32
+ return vld3q_dup_f32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x2x3_t test_vld3q_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_f64
+ return vld3q_dup_f64(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x16x3_t test_vld3q_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_p8
+ return vld3q_dup_p8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x8x3_t test_vld3q_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_p16
+ return vld3q_dup_p16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly64x2x3_t test_vld3q_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld3q_dup_p64
+ return vld3q_dup_p64(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x8x3_t test_vld3_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_u8
+ return vld3_dup_u8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint16x4x3_t test_vld3_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_u16
+ return vld3_dup_u16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint32x2x3_t test_vld3_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_u32
+ return vld3_dup_u32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint64x1x3_t test_vld3_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_u64
+ return vld3_dup_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+int8x8x3_t test_vld3_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_s8
+ return vld3_dup_s8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+int16x4x3_t test_vld3_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_s16
+ return vld3_dup_s16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+int32x2x3_t test_vld3_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_s32
+ return vld3_dup_s32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+int64x1x3_t test_vld3_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_s64
+ return vld3_dup_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+float16x4x3_t test_vld3_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_f16
+ return vld3_dup_f16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+float32x2x3_t test_vld3_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_f32
+ return vld3_dup_f32(a);
+ // CHECK: ld3r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s},
+ // [{{x[0-9]+|sp}}]
+}
+
+float64x1x3_t test_vld3_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_f64
+ return vld3_dup_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly8x8x3_t test_vld3_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_p8
+ return vld3_dup_p8(a);
+ // CHECK: ld3r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly16x4x3_t test_vld3_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_p16
+ return vld3_dup_p16(a);
+ // CHECK: ld3r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h},
+ // [{{x[0-9]+|sp}}]
+}
+
+poly64x1x3_t test_vld3_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld3_dup_p64
+ return vld3_dup_p64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d},
+ // [{{x[0-9]+|sp}}]
+}
+
+uint8x16x4_t test_vld4q_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_u8
+ return vld4q_dup_u8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x4_t test_vld4q_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_u16
+ return vld4q_dup_u16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x4x4_t test_vld4q_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_u32
+ return vld4q_dup_u32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x2x4_t test_vld4q_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_u64
+ return vld4q_dup_u64(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+int8x16x4_t test_vld4q_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_s8
+ return vld4q_dup_s8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+int16x8x4_t test_vld4q_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_s16
+ return vld4q_dup_s16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+int32x4x4_t test_vld4q_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_s32
+ return vld4q_dup_s32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+int64x2x4_t test_vld4q_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_s64
+ return vld4q_dup_s64(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+float16x8x4_t test_vld4q_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_f16
+ return vld4q_dup_f16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+float32x4x4_t test_vld4q_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_f32
+ return vld4q_dup_f32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4s, v{{[0-9]+}}.4s, v{{[0-9]+}}.4s,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+float64x2x4_t test_vld4q_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_f64
+ return vld4q_dup_f64(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.4s}, [{{x[0-9]+|sp}}]
+}
+
+poly8x16x4_t test_vld4q_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_p8
+ return vld4q_dup_p8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.16b, v{{[0-9]+}}.16b, v{{[0-9]+}}.16b,
+ // v{{[0-9]+}}.16b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x8x4_t test_vld4q_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_p16
+ return vld4q_dup_p16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8h, v{{[0-9]+}}.8h, v{{[0-9]+}}.8h,
+ // v{{[0-9]+}}.8h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x4_t test_vld4q_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld4q_dup_p64
+ return vld4q_dup_p64(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2d, v{{[0-9]+}}.2d, v{{[0-9]+}}.2d,
+ // v{{[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x8x4_t test_vld4_dup_u8(uint8_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_u8
+ return vld4_dup_u8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+uint16x4x4_t test_vld4_dup_u16(uint16_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_u16
+ return vld4_dup_u16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+uint32x2x4_t test_vld4_dup_u32(uint32_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_u32
+ return vld4_dup_u32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+uint64x1x4_t test_vld4_dup_u64(uint64_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_u64
+ return vld4_dup_u64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8x4_t test_vld4_dup_s8(int8_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_s8
+ return vld4_dup_s8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+int16x4x4_t test_vld4_dup_s16(int16_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_s16
+ return vld4_dup_s16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+int32x2x4_t test_vld4_dup_s32(int32_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_s32
+ return vld4_dup_s32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+int64x1x4_t test_vld4_dup_s64(int64_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_s64
+ return vld4_dup_s64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4x4_t test_vld4_dup_f16(float16_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_f16
+ return vld4_dup_f16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+float32x2x4_t test_vld4_dup_f32(float32_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_f32
+ return vld4_dup_f32(a);
+ // CHECK: ld4r {v{{[0-9]+}}.2s, v{{[0-9]+}}.2s, v{{[0-9]+}}.2s,
+ // v{{[0-9]+}}.2s}, [{{x[0-9]+|sp}}]
+}
+
+float64x1x4_t test_vld4_dup_f64(float64_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_f64
+ return vld4_dup_f64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8x4_t test_vld4_dup_p8(poly8_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_p8
+ return vld4_dup_p8(a);
+ // CHECK: ld4r {v{{[0-9]+}}.8b, v{{[0-9]+}}.8b, v{{[0-9]+}}.8b,
+ // v{{[0-9]+}}.8b}, [{{x[0-9]+|sp}}]
+}
+
+poly16x4x4_t test_vld4_dup_p16(poly16_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_p16
+ return vld4_dup_p16(a);
+ // CHECK: ld4r {v{{[0-9]+}}.4h, v{{[0-9]+}}.4h, v{{[0-9]+}}.4h,
+ // v{{[0-9]+}}.4h}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x4_t test_vld4_dup_p64(poly64_t const *a) {
+ // CHECK-LABEL: test_vld4_dup_p64
+ return vld4_dup_p64(a);
+ // CHECK: ld1 {v{{[0-9]+}}.1d, v{{[0-9]+}}.1d, v{{[0-9]+}}.1d,
+ // v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+uint8x16_t test_vld1q_lane_u8(uint8_t const *a, uint8x16_t b) {
+ // CHECK-LABEL: test_vld1q_lane_u8
+ return vld1q_lane_u8(a, b, 15);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+uint16x8_t test_vld1q_lane_u16(uint16_t const *a, uint16x8_t b) {
+ // CHECK-LABEL: test_vld1q_lane_u16
+ return vld1q_lane_u16(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+uint32x4_t test_vld1q_lane_u32(uint32_t const *a, uint32x4_t b) {
+ // CHECK-LABEL: test_vld1q_lane_u32
+ return vld1q_lane_u32(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+uint64x2_t test_vld1q_lane_u64(uint64_t const *a, uint64x2_t b) {
+ // CHECK-LABEL: test_vld1q_lane_u64
+ return vld1q_lane_u64(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+int8x16_t test_vld1q_lane_s8(int8_t const *a, int8x16_t b) {
+ // CHECK-LABEL: test_vld1q_lane_s8
+ return vld1q_lane_s8(a, b, 15);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+int16x8_t test_vld1q_lane_s16(int16_t const *a, int16x8_t b) {
+ // CHECK-LABEL: test_vld1q_lane_s16
+ return vld1q_lane_s16(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+int32x4_t test_vld1q_lane_s32(int32_t const *a, int32x4_t b) {
+ // CHECK-LABEL: test_vld1q_lane_s32
+ return vld1q_lane_s32(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+int64x2_t test_vld1q_lane_s64(int64_t const *a, int64x2_t b) {
+ // CHECK-LABEL: test_vld1q_lane_s64
+ return vld1q_lane_s64(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+float16x8_t test_vld1q_lane_f16(float16_t const *a, float16x8_t b) {
+ // CHECK-LABEL: test_vld1q_lane_f16
+ return vld1q_lane_f16(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+float32x4_t test_vld1q_lane_f32(float32_t const *a, float32x4_t b) {
+ // CHECK-LABEL: test_vld1q_lane_f32
+ return vld1q_lane_f32(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+float64x2_t test_vld1q_lane_f64(float64_t const *a, float64x2_t b) {
+ // CHECK-LABEL: test_vld1q_lane_f64
+ return vld1q_lane_f64(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+poly8x16_t test_vld1q_lane_p8(poly8_t const *a, poly8x16_t b) {
+ // CHECK-LABEL: test_vld1q_lane_p8
+ return vld1q_lane_p8(a, b, 15);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+poly16x8_t test_vld1q_lane_p16(poly16_t const *a, poly16x8_t b) {
+ // CHECK-LABEL: test_vld1q_lane_p16
+ return vld1q_lane_p16(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+poly64x2_t test_vld1q_lane_p64(poly64_t const *a, poly64x2_t b) {
+ // CHECK-LABEL: test_vld1q_lane_p64
+ return vld1q_lane_p64(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+uint8x8_t test_vld1_lane_u8(uint8_t const *a, uint8x8_t b) {
+ // CHECK-LABEL: test_vld1_lane_u8
+ return vld1_lane_u8(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+uint16x4_t test_vld1_lane_u16(uint16_t const *a, uint16x4_t b) {
+ // CHECK-LABEL: test_vld1_lane_u16
+ return vld1_lane_u16(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+uint32x2_t test_vld1_lane_u32(uint32_t const *a, uint32x2_t b) {
+ // CHECK-LABEL: test_vld1_lane_u32
+ return vld1_lane_u32(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+uint64x1_t test_vld1_lane_u64(uint64_t const *a, uint64x1_t b) {
+ // CHECK-LABEL: test_vld1_lane_u64
+ return vld1_lane_u64(a, b, 0);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+int8x8_t test_vld1_lane_s8(int8_t const *a, int8x8_t b) {
+ // CHECK-LABEL: test_vld1_lane_s8
+ return vld1_lane_s8(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+int16x4_t test_vld1_lane_s16(int16_t const *a, int16x4_t b) {
+ // CHECK-LABEL: test_vld1_lane_s16
+ return vld1_lane_s16(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+int32x2_t test_vld1_lane_s32(int32_t const *a, int32x2_t b) {
+ // CHECK-LABEL: test_vld1_lane_s32
+ return vld1_lane_s32(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+int64x1_t test_vld1_lane_s64(int64_t const *a, int64x1_t b) {
+ // CHECK-LABEL: test_vld1_lane_s64
+ return vld1_lane_s64(a, b, 0);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+float16x4_t test_vld1_lane_f16(float16_t const *a, float16x4_t b) {
+ // CHECK-LABEL: test_vld1_lane_f16
+ return vld1_lane_f16(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+float32x2_t test_vld1_lane_f32(float32_t const *a, float32x2_t b) {
+ // CHECK-LABEL: test_vld1_lane_f32
+ return vld1_lane_f32(a, b, 1);
+ // CHECK: ld1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+float64x1_t test_vld1_lane_f64(float64_t const *a, float64x1_t b) {
+ // CHECK-LABEL: test_vld1_lane_f64
+ return vld1_lane_f64(a, b, 0);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly8x8_t test_vld1_lane_p8(poly8_t const *a, poly8x8_t b) {
+ // CHECK-LABEL: test_vld1_lane_p8
+ return vld1_lane_p8(a, b, 7);
+ // CHECK: ld1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+poly16x4_t test_vld1_lane_p16(poly16_t const *a, poly16x4_t b) {
+ // CHECK-LABEL: test_vld1_lane_p16
+ return vld1_lane_p16(a, b, 3);
+ // CHECK: ld1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+poly64x1_t test_vld1_lane_p64(poly64_t const *a, poly64x1_t b) {
+ // CHECK-LABEL: test_vld1_lane_p64
+ return vld1_lane_p64(a, b, 0);
+ // CHECK: ld1r {v{{[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+uint16x8x2_t test_vld2q_lane_u16(uint16_t const *a, uint16x8x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_u16
+ return vld2q_lane_u16(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+uint32x4x2_t test_vld2q_lane_u32(uint32_t const *a, uint32x4x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_u32
+ return vld2q_lane_u32(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+uint64x2x2_t test_vld2q_lane_u64(uint64_t const *a, uint64x2x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_u64
+ return vld2q_lane_u64(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+int16x8x2_t test_vld2q_lane_s16(int16_t const *a, int16x8x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_s16
+ return vld2q_lane_s16(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+int32x4x2_t test_vld2q_lane_s32(int32_t const *a, int32x4x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_s32
+ return vld2q_lane_s32(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+int64x2x2_t test_vld2q_lane_s64(int64_t const *a, int64x2x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_s64
+ return vld2q_lane_s64(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+float16x8x2_t test_vld2q_lane_f16(float16_t const *a, float16x8x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_f16
+ return vld2q_lane_f16(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+float32x4x2_t test_vld2q_lane_f32(float32_t const *a, float32x4x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_f32
+ return vld2q_lane_f32(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+float64x2x2_t test_vld2q_lane_f64(float64_t const *a, float64x2x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_f64
+ return vld2q_lane_f64(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+poly16x8x2_t test_vld2q_lane_p16(poly16_t const *a, poly16x8x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_p16
+ return vld2q_lane_p16(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+poly64x2x2_t test_vld2q_lane_p64(poly64_t const *a, poly64x2x2_t b) {
+ // CHECK-LABEL: test_vld2q_lane_p64
+ return vld2q_lane_p64(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+uint8x8x2_t test_vld2_lane_u8(uint8_t const *a, uint8x8x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_u8
+ return vld2_lane_u8(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+uint16x4x2_t test_vld2_lane_u16(uint16_t const *a, uint16x4x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_u16
+ return vld2_lane_u16(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+uint32x2x2_t test_vld2_lane_u32(uint32_t const *a, uint32x2x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_u32
+ return vld2_lane_u32(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+uint64x1x2_t test_vld2_lane_u64(uint64_t const *a, uint64x1x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_u64
+ return vld2_lane_u64(a, b, 0);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+int8x8x2_t test_vld2_lane_s8(int8_t const *a, int8x8x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_s8
+ return vld2_lane_s8(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+int16x4x2_t test_vld2_lane_s16(int16_t const *a, int16x4x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_s16
+ return vld2_lane_s16(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+int32x2x2_t test_vld2_lane_s32(int32_t const *a, int32x2x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_s32
+ return vld2_lane_s32(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+int64x1x2_t test_vld2_lane_s64(int64_t const *a, int64x1x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_s64
+ return vld2_lane_s64(a, b, 0);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+float16x4x2_t test_vld2_lane_f16(float16_t const *a, float16x4x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_f16
+ return vld2_lane_f16(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+float32x2x2_t test_vld2_lane_f32(float32_t const *a, float32x2x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_f32
+ return vld2_lane_f32(a, b, 1);
+ // CHECK: ld2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+float64x1x2_t test_vld2_lane_f64(float64_t const *a, float64x1x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_f64
+ return vld2_lane_f64(a, b, 0);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+poly8x8x2_t test_vld2_lane_p8(poly8_t const *a, poly8x8x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_p8
+ return vld2_lane_p8(a, b, 7);
+ // CHECK: ld2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+poly16x4x2_t test_vld2_lane_p16(poly16_t const *a, poly16x4x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_p16
+ return vld2_lane_p16(a, b, 3);
+ // CHECK: ld2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+poly64x1x2_t test_vld2_lane_p64(poly64_t const *a, poly64x1x2_t b) {
+ // CHECK-LABEL: test_vld2_lane_p64
+ return vld2_lane_p64(a, b, 0);
+ // CHECK: ld2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+uint16x8x3_t test_vld3q_lane_u16(uint16_t const *a, uint16x8x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_u16
+ return vld3q_lane_u16(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+uint32x4x3_t test_vld3q_lane_u32(uint32_t const *a, uint32x4x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_u32
+ return vld3q_lane_u32(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+uint64x2x3_t test_vld3q_lane_u64(uint64_t const *a, uint64x2x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_u64
+ return vld3q_lane_u64(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+int16x8x3_t test_vld3q_lane_s16(int16_t const *a, int16x8x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_s16
+ return vld3q_lane_s16(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+int32x4x3_t test_vld3q_lane_s32(int32_t const *a, int32x4x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_s32
+ return vld3q_lane_s32(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+int64x2x3_t test_vld3q_lane_s64(int64_t const *a, int64x2x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_s64
+ return vld3q_lane_s64(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+float16x8x3_t test_vld3q_lane_f16(float16_t const *a, float16x8x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_f16
+ return vld3q_lane_f16(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+float32x4x3_t test_vld3q_lane_f32(float32_t const *a, float32x4x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_f32
+ return vld3q_lane_f32(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+float64x2x3_t test_vld3q_lane_f64(float64_t const *a, float64x2x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_f64
+ return vld3q_lane_f64(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+poly8x16x3_t test_vld3q_lane_p8(poly8_t const *a, poly8x16x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_p8
+ return vld3q_lane_p8(a, b, 15);
+ // CHECK: ld3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+poly16x8x3_t test_vld3q_lane_p16(poly16_t const *a, poly16x8x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_p16
+ return vld3q_lane_p16(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+poly64x2x3_t test_vld3q_lane_p64(poly64_t const *a, poly64x2x3_t b) {
+ // CHECK-LABEL: test_vld3q_lane_p64
+ return vld3q_lane_p64(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+uint8x8x3_t test_vld3_lane_u8(uint8_t const *a, uint8x8x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_u8
+ return vld3_lane_u8(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+uint16x4x3_t test_vld3_lane_u16(uint16_t const *a, uint16x4x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_u16
+ return vld3_lane_u16(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+uint32x2x3_t test_vld3_lane_u32(uint32_t const *a, uint32x2x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_u32
+ return vld3_lane_u32(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+uint64x1x3_t test_vld3_lane_u64(uint64_t const *a, uint64x1x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_u64
+ return vld3_lane_u64(a, b, 0);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+int8x8x3_t test_vld3_lane_s8(int8_t const *a, int8x8x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_s8
+ return vld3_lane_s8(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+int16x4x3_t test_vld3_lane_s16(int16_t const *a, int16x4x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_s16
+ return vld3_lane_s16(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+int32x2x3_t test_vld3_lane_s32(int32_t const *a, int32x2x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_s32
+ return vld3_lane_s32(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+int64x1x3_t test_vld3_lane_s64(int64_t const *a, int64x1x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_s64
+ return vld3_lane_s64(a, b, 0);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+float16x4x3_t test_vld3_lane_f16(float16_t const *a, float16x4x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_f16
+ return vld3_lane_f16(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+float32x2x3_t test_vld3_lane_f32(float32_t const *a, float32x2x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_f32
+ return vld3_lane_f32(a, b, 1);
+ // CHECK: ld3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+float64x1x3_t test_vld3_lane_f64(float64_t const *a, float64x1x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_f64
+ return vld3_lane_f64(a, b, 0);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+poly8x8x3_t test_vld3_lane_p8(poly8_t const *a, poly8x8x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_p8
+ return vld3_lane_p8(a, b, 7);
+ // CHECK: ld3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+poly16x4x3_t test_vld3_lane_p16(poly16_t const *a, poly16x4x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_p16
+ return vld3_lane_p16(a, b, 3);
+ // CHECK: ld3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+poly64x1x3_t test_vld3_lane_p64(poly64_t const *a, poly64x1x3_t b) {
+ // CHECK-LABEL: test_vld3_lane_p64
+ return vld3_lane_p64(a, b, 0);
+ // CHECK: ld3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+uint8x16x4_t test_vld4q_lane_u8(uint8_t const *a, uint8x16x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_u8
+ return vld4q_lane_u8(a, b, 15);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+uint16x8x4_t test_vld4q_lane_u16(uint16_t const *a, uint16x8x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_u16
+ return vld4q_lane_u16(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+uint32x4x4_t test_vld4q_lane_u32(uint32_t const *a, uint32x4x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_u32
+ return vld4q_lane_u32(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+uint64x2x4_t test_vld4q_lane_u64(uint64_t const *a, uint64x2x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_u64
+ return vld4q_lane_u64(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+int8x16x4_t test_vld4q_lane_s8(int8_t const *a, int8x16x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_s8
+ return vld4q_lane_s8(a, b, 15);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+int16x8x4_t test_vld4q_lane_s16(int16_t const *a, int16x8x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_s16
+ return vld4q_lane_s16(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+int32x4x4_t test_vld4q_lane_s32(int32_t const *a, int32x4x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_s32
+ return vld4q_lane_s32(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+int64x2x4_t test_vld4q_lane_s64(int64_t const *a, int64x2x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_s64
+ return vld4q_lane_s64(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+float16x8x4_t test_vld4q_lane_f16(float16_t const *a, float16x8x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_f16
+ return vld4q_lane_f16(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+float32x4x4_t test_vld4q_lane_f32(float32_t const *a, float32x4x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_f32
+ return vld4q_lane_f32(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+float64x2x4_t test_vld4q_lane_f64(float64_t const *a, float64x2x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_f64
+ return vld4q_lane_f64(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+poly8x16x4_t test_vld4q_lane_p8(poly8_t const *a, poly8x16x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_p8
+ return vld4q_lane_p8(a, b, 15);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+poly16x8x4_t test_vld4q_lane_p16(poly16_t const *a, poly16x8x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_p16
+ return vld4q_lane_p16(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+poly64x2x4_t test_vld4q_lane_p64(poly64_t const *a, poly64x2x4_t b) {
+ // CHECK-LABEL: test_vld4q_lane_p64
+ return vld4q_lane_p64(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+uint8x8x4_t test_vld4_lane_u8(uint8_t const *a, uint8x8x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_u8
+ return vld4_lane_u8(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+uint16x4x4_t test_vld4_lane_u16(uint16_t const *a, uint16x4x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_u16
+ return vld4_lane_u16(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+uint32x2x4_t test_vld4_lane_u32(uint32_t const *a, uint32x2x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_u32
+ return vld4_lane_u32(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+uint64x1x4_t test_vld4_lane_u64(uint64_t const *a, uint64x1x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_u64
+ return vld4_lane_u64(a, b, 0);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+int8x8x4_t test_vld4_lane_s8(int8_t const *a, int8x8x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_s8
+ return vld4_lane_s8(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+int16x4x4_t test_vld4_lane_s16(int16_t const *a, int16x4x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_s16
+ return vld4_lane_s16(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+int32x2x4_t test_vld4_lane_s32(int32_t const *a, int32x2x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_s32
+ return vld4_lane_s32(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+int64x1x4_t test_vld4_lane_s64(int64_t const *a, int64x1x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_s64
+ return vld4_lane_s64(a, b, 0);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+float16x4x4_t test_vld4_lane_f16(float16_t const *a, float16x4x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_f16
+ return vld4_lane_f16(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+float32x2x4_t test_vld4_lane_f32(float32_t const *a, float32x2x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_f32
+ return vld4_lane_f32(a, b, 1);
+ // CHECK: ld4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+float64x1x4_t test_vld4_lane_f64(float64_t const *a, float64x1x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_f64
+ return vld4_lane_f64(a, b, 0);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+poly8x8x4_t test_vld4_lane_p8(poly8_t const *a, poly8x8x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_p8
+ return vld4_lane_p8(a, b, 7);
+ // CHECK: ld4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+poly16x4x4_t test_vld4_lane_p16(poly16_t const *a, poly16x4x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_p16
+ return vld4_lane_p16(a, b, 3);
+ // CHECK: ld4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+poly64x1x4_t test_vld4_lane_p64(poly64_t const *a, poly64x1x4_t b) {
+ // CHECK-LABEL: test_vld4_lane_p64
+ return vld4_lane_p64(a, b, 0);
+ // CHECK: ld4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_u8(uint8_t const *a, uint8x16_t b) {
+ // CHECK-LABEL: test_vst1q_lane_u8
+ vst1q_lane_u8(a, b, 15);
+ // CHECK: st1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_u16(uint16_t const *a, uint16x8_t b) {
+ // CHECK-LABEL: test_vst1q_lane_u16
+ vst1q_lane_u16(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_u32(uint32_t const *a, uint32x4_t b) {
+ // CHECK-LABEL: test_vst1q_lane_u32
+ vst1q_lane_u32(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_u64(uint64_t const *a, uint64x2_t b) {
+ // CHECK-LABEL: test_vst1q_lane_u64
+ vst1q_lane_u64(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_s8(int8_t const *a, int8x16_t b) {
+ // CHECK-LABEL: test_vst1q_lane_s8
+ vst1q_lane_s8(a, b, 15);
+ // CHECK: st1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_s16(int16_t const *a, int16x8_t b) {
+ // CHECK-LABEL: test_vst1q_lane_s16
+ vst1q_lane_s16(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_s32(int32_t const *a, int32x4_t b) {
+ // CHECK-LABEL: test_vst1q_lane_s32
+ vst1q_lane_s32(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_s64(int64_t const *a, int64x2_t b) {
+ // CHECK-LABEL: test_vst1q_lane_s64
+ vst1q_lane_s64(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_f16(float16_t const *a, float16x8_t b) {
+ // CHECK-LABEL: test_vst1q_lane_f16
+ vst1q_lane_f16(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_f32(float32_t const *a, float32x4_t b) {
+ // CHECK-LABEL: test_vst1q_lane_f32
+ vst1q_lane_f32(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_f64(float64_t const *a, float64x2_t b) {
+ // CHECK-LABEL: test_vst1q_lane_f64
+ vst1q_lane_f64(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+poly8x16_t test_vst1q_lane_p8(poly8_t const *a, poly8x16_t b) {
+ // CHECK-LABEL: test_vst1q_lane_p8
+ vst1q_lane_p8(a, b, 15);
+ // CHECK: st1 {v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_p16(poly16_t const *a, poly16x8_t b) {
+ // CHECK-LABEL: test_vst1q_lane_p16
+ vst1q_lane_p16(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_lane_p64(poly64_t const *a, poly64x2_t b) {
+ // CHECK-LABEL: test_vst1q_lane_p64
+ vst1q_lane_p64(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_u8(uint8_t const *a, uint8x8_t b) {
+ // CHECK-LABEL: test_vst1_lane_u8
+ vst1_lane_u8(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_u16(uint16_t const *a, uint16x4_t b) {
+ // CHECK-LABEL: test_vst1_lane_u16
+ vst1_lane_u16(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_u32(uint32_t const *a, uint32x2_t b) {
+ // CHECK-LABEL: test_vst1_lane_u32
+ vst1_lane_u32(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_u64(uint64_t const *a, uint64x1_t b) {
+ // CHECK-LABEL: test_vst1_lane_u64
+ vst1_lane_u64(a, b, 0);
+ // CHECK: st1 {v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_s8(int8_t const *a, int8x8_t b) {
+ // CHECK-LABEL: test_vst1_lane_s8
+ vst1_lane_s8(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_s16(int16_t const *a, int16x4_t b) {
+ // CHECK-LABEL: test_vst1_lane_s16
+ vst1_lane_s16(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_s32(int32_t const *a, int32x2_t b) {
+ // CHECK-LABEL: test_vst1_lane_s32
+ vst1_lane_s32(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_s64(int64_t const *a, int64x1_t b) {
+ // CHECK-LABEL: test_vst1_lane_s64
+ vst1_lane_s64(a, b, 0);
+ // CHECK: st1 {v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_f16(float16_t const *a, float16x4_t b) {
+ // CHECK-LABEL: test_vst1_lane_f16
+ vst1_lane_f16(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_f32(float32_t const *a, float32x2_t b) {
+ // CHECK-LABEL: test_vst1_lane_f32
+ vst1_lane_f32(a, b, 1);
+ // CHECK: st1 {v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_f64(float64_t const *a, float64x1_t b) {
+ // CHECK-LABEL: test_vst1_lane_f64
+ vst1_lane_f64(a, b, 0);
+ // CHECK: st1 {v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_p8(poly8_t const *a, poly8x8_t b) {
+ // CHECK-LABEL: test_vst1_lane_p8
+ vst1_lane_p8(a, b, 7);
+ // CHECK: st1 {v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_p16(poly16_t const *a, poly16x4_t b) {
+ // CHECK-LABEL: test_vst1_lane_p16
+ vst1_lane_p16(a, b, 3);
+ // CHECK: st1 {v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_lane_p64(poly64_t const *a, poly64x1_t b) {
+ // CHECK-LABEL: test_vst1_lane_p64
+ vst1_lane_p64(a, b, 0);
+ // CHECK: st1 {v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_u8(uint8_t const *a, uint8x16x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_u8
+ vst2q_lane_u8(a, b, 15);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_u16(uint16_t const *a, uint16x8x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_u16
+ vst2q_lane_u16(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_u32(uint32_t const *a, uint32x4x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_u32
+ vst2q_lane_u32(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_u64(uint64_t const *a, uint64x2x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_u64
+ vst2q_lane_u64(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_s8(int8_t const *a, int8x16x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_s8
+ vst2q_lane_s8(a, b, 15);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_s16(int16_t const *a, int16x8x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_s16
+ vst2q_lane_s16(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_s32(int32_t const *a, int32x4x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_s32
+ vst2q_lane_s32(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_s64(int64_t const *a, int64x2x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_s64
+ vst2q_lane_s64(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_f16(float16_t const *a, float16x8x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_f16
+ vst2q_lane_f16(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_f32(float32_t const *a, float32x4x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_f32
+ vst2q_lane_f32(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_f64(float64_t const *a, float64x2x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_f64
+ vst2q_lane_f64(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_p8(poly8_t const *a, poly8x16x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_p8
+ vst2q_lane_p8(a, b, 15);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_p16(poly16_t const *a, poly16x8x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_p16
+ vst2q_lane_p16(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_lane_p64(poly64_t const *a, poly64x2x2_t b) {
+ // CHECK-LABEL: test_vst2q_lane_p64
+ vst2q_lane_p64(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_u8(uint8_t const *a, uint8x8x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_u8
+ vst2_lane_u8(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_u16(uint16_t const *a, uint16x4x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_u16
+ vst2_lane_u16(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_u32(uint32_t const *a, uint32x2x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_u32
+ vst2_lane_u32(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_u64(uint64_t const *a, uint64x1x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_u64
+ vst2_lane_u64(a, b, 0);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_s8(int8_t const *a, int8x8x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_s8
+ vst2_lane_s8(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_s16(int16_t const *a, int16x4x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_s16
+ vst2_lane_s16(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_s32(int32_t const *a, int32x2x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_s32
+ vst2_lane_s32(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_s64(int64_t const *a, int64x1x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_s64
+ vst2_lane_s64(a, b, 0);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_f16(float16_t const *a, float16x4x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_f16
+ vst2_lane_f16(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_f32(float32_t const *a, float32x2x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_f32
+ vst2_lane_f32(a, b, 1);
+ // CHECK: st2 {v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_f64(float64_t const *a, float64x1x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_f64
+ vst2_lane_f64(a, b, 0);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_p8(poly8_t const *a, poly8x8x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_p8
+ vst2_lane_p8(a, b, 7);
+ // CHECK: st2 {v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_p16(poly16_t const *a, poly16x4x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_p16
+ vst2_lane_p16(a, b, 3);
+ // CHECK: st2 {v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_lane_p64(poly64_t const *a, poly64x1x2_t b) {
+ // CHECK-LABEL: test_vst2_lane_p64
+ vst2_lane_p64(a, b, 0);
+ // CHECK: st2 {v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_u8(uint8_t const *a, uint8x16x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_u8
+ vst3q_lane_u8(a, b, 15);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_u16(uint16_t const *a, uint16x8x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_u16
+ vst3q_lane_u16(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_u32(uint32_t const *a, uint32x4x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_u32
+ vst3q_lane_u32(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_u64(uint64_t const *a, uint64x2x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_u64
+ vst3q_lane_u64(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_s8(int8_t const *a, int8x16x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_s8
+ vst3q_lane_s8(a, b, 15);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_s16(int16_t const *a, int16x8x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_s16
+ vst3q_lane_s16(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_s32(int32_t const *a, int32x4x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_s32
+ vst3q_lane_s32(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_s64(int64_t const *a, int64x2x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_s64
+ vst3q_lane_s64(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_f16(float16_t const *a, float16x8x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_f16
+ vst3q_lane_f16(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_f32(float32_t const *a, float32x4x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_f32
+ vst3q_lane_f32(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_f64(float64_t const *a, float64x2x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_f64
+ vst3q_lane_f64(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_p8(poly8_t const *a, poly8x16x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_p8
+ vst3q_lane_p8(a, b, 15);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_p16(poly16_t const *a, poly16x8x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_p16
+ vst3q_lane_p16(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_lane_p64(poly64_t const *a, poly64x2x3_t b) {
+ // CHECK-LABEL: test_vst3q_lane_p64
+ vst3q_lane_p64(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_u8(uint8_t const *a, uint8x8x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_u8
+ vst3_lane_u8(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_u16(uint16_t const *a, uint16x4x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_u16
+ vst3_lane_u16(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_u32(uint32_t const *a, uint32x2x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_u32
+ vst3_lane_u32(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_u64(uint64_t const *a, uint64x1x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_u64
+ vst3_lane_u64(a, b, 0);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_s8(int8_t const *a, int8x8x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_s8
+ vst3_lane_s8(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_s16(int16_t const *a, int16x4x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_s16
+ vst3_lane_s16(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_s32(int32_t const *a, int32x2x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_s32
+ vst3_lane_s32(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_s64(int64_t const *a, int64x1x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_s64
+ vst3_lane_s64(a, b, 0);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_f16(float16_t const *a, float16x4x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_f16
+ vst3_lane_f16(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_f32(float32_t const *a, float32x2x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_f32
+ vst3_lane_f32(a, b, 1);
+ // CHECK: st3 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_f64(float64_t const *a, float64x1x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_f64
+ vst3_lane_f64(a, b, 0);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_p8(poly8_t const *a, poly8x8x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_p8
+ vst3_lane_p8(a, b, 7);
+ // CHECK: st3 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_p16(poly16_t const *a, poly16x4x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_p16
+ vst3_lane_p16(a, b, 3);
+ // CHECK: st3 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_lane_p64(poly64_t const *a, poly64x1x3_t b) {
+ // CHECK-LABEL: test_vst3_lane_p64
+ vst3_lane_p64(a, b, 0);
+ // CHECK: st3 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_u8(uint16_t const *a, uint8x16x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_u8
+ vst4q_lane_u8(a, b, 15);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_u16(uint16_t const *a, uint16x8x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_u16
+ vst4q_lane_u16(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_u32(uint32_t const *a, uint32x4x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_u32
+ vst4q_lane_u32(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_u64(uint64_t const *a, uint64x2x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_u64
+ vst4q_lane_u64(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_s8(int16_t const *a, int8x16x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_s8
+ vst4q_lane_s8(a, b, 15);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_s16(int16_t const *a, int16x8x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_s16
+ vst4q_lane_s16(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_s32(int32_t const *a, int32x4x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_s32
+ vst4q_lane_s32(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_s64(int64_t const *a, int64x2x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_s64
+ vst4q_lane_s64(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_f16(float16_t const *a, float16x8x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_f16
+ vst4q_lane_f16(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_f32(float32_t const *a, float32x4x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_f32
+ vst4q_lane_f32(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_f64(float64_t const *a, float64x2x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_f64
+ vst4q_lane_f64(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_p8(poly16_t const *a, poly8x16x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_p8
+ vst4q_lane_p8(a, b, 15);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[15], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_p16(poly16_t const *a, poly16x8x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_p16
+ vst4q_lane_p16(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_lane_p64(poly64_t const *a, poly64x2x4_t b) {
+ // CHECK-LABEL: test_vst4q_lane_p64
+ vst4q_lane_p64(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_u8(uint8_t const *a, uint8x8x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_u8
+ vst4_lane_u8(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_u16(uint16_t const *a, uint16x4x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_u16
+ vst4_lane_u16(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_u32(uint32_t const *a, uint32x2x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_u32
+ vst4_lane_u32(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_u64(uint64_t const *a, uint64x1x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_u64
+ vst4_lane_u64(a, b, 0);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_s8(int8_t const *a, int8x8x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_s8
+ vst4_lane_s8(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_s16(int16_t const *a, int16x4x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_s16
+ vst4_lane_s16(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_s32(int32_t const *a, int32x2x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_s32
+ vst4_lane_s32(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_s64(int64_t const *a, int64x1x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_s64
+ vst4_lane_s64(a, b, 0);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_f16(float16_t const *a, float16x4x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_f16
+ vst4_lane_f16(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_f32(float32_t const *a, float32x2x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_f32
+ vst4_lane_f32(a, b, 1);
+ // CHECK: st4 {v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s, v{{[0-9]+}}.s}[1], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_f64(float64_t const *a, float64x1x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_f64
+ vst4_lane_f64(a, b, 0);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_p8(poly8_t const *a, poly8x8x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_p8
+ vst4_lane_p8(a, b, 7);
+ // CHECK: st4 {v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b, v{{[0-9]+}}.b}[7], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_p16(poly16_t const *a, poly16x4x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_p16
+ vst4_lane_p16(a, b, 3);
+ // CHECK: st4 {v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h, v{{[0-9]+}}.h}[3], [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_lane_p64(poly64_t const *a, poly64x1x4_t b) {
+ // CHECK-LABEL: test_vst4_lane_p64
+ vst4_lane_p64(a, b, 0);
+ // CHECK: st4 {v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d, v{{[0-9]+}}.d}[0], [{{x[0-9]+|sp}}]
+}
diff --git a/test/CodeGen/aarch64-neon-misc.c b/test/CodeGen/aarch64-neon-misc.c
new file mode 100644
index 000000000000..08174d91f8be
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-misc.c
@@ -0,0 +1,2005 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+// CHECK: test_vceqz_s8
+// CHECK: cmeq {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x0
+uint8x8_t test_vceqz_s8(int8x8_t a) {
+ return vceqz_s8(a);
+}
+
+// CHECK: test_vceqz_s16
+// CHECK: cmeq {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vceqz_s16(int16x4_t a) {
+ return vceqz_s16(a);
+}
+
+// CHECK: test_vceqz_s32
+// CHECK: cmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0x0
+uint32x2_t test_vceqz_s32(int32x2_t a) {
+ return vceqz_s32(a);
+}
+
+// CHECK: test_vceqz_s64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vceqz_s64(int64x1_t a) {
+ return vceqz_s64(a);
+}
+
+// CHECK: test_vceqz_u64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vceqz_u64(uint64x1_t a) {
+ return vceqz_u64(a);
+}
+
+// CHECK: test_vceqz_p64
+// CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vceqz_p64(poly64x1_t a) {
+ return vceqz_p64(a);
+}
+
+// CHECK: test_vceqzq_s8
+// CHECK: cmeq {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x0
+uint8x16_t test_vceqzq_s8(int8x16_t a) {
+ return vceqzq_s8(a);
+}
+
+// CHECK: test_vceqzq_s16
+// CHECK: cmeq {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vceqzq_s16(int16x8_t a) {
+ return vceqzq_s16(a);
+}
+
+// CHECK: test_vceqzq_s32
+// CHECK: cmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0x0
+uint32x4_t test_vceqzq_s32(int32x4_t a) {
+ return vceqzq_s32(a);
+}
+
+// CHECK: test_vceqzq_s64
+// CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0x0
+uint64x2_t test_vceqzq_s64(int64x2_t a) {
+ return vceqzq_s64(a);
+}
+
+// CHECK: test_vceqz_u8
+// CHECK: cmeq {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x0
+uint8x8_t test_vceqz_u8(uint8x8_t a) {
+ return vceqz_u8(a);
+}
+
+// CHECK: test_vceqz_u16
+// CHECK: cmeq {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vceqz_u16(uint16x4_t a) {
+ return vceqz_u16(a);
+}
+
+// CHECK: test_vceqz_u32
+// CHECK: cmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0x0
+uint32x2_t test_vceqz_u32(uint32x2_t a) {
+ return vceqz_u32(a);
+}
+
+// CHECK: test_vceqzq_u8
+// CHECK: cmeq {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x0
+uint8x16_t test_vceqzq_u8(uint8x16_t a) {
+ return vceqzq_u8(a);
+}
+
+// CHECK: test_vceqzq_u16
+// CHECK: cmeq {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vceqzq_u16(uint16x8_t a) {
+ return vceqzq_u16(a);
+}
+
+// CHECK: test_vceqzq_u32
+// CHECK: cmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0x0
+uint32x4_t test_vceqzq_u32(uint32x4_t a) {
+ return vceqzq_u32(a);
+}
+
+// CHECK: test_vceqzq_u64
+// CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0x0
+uint64x2_t test_vceqzq_u64(uint64x2_t a) {
+ return vceqzq_u64(a);
+}
+
+// CHECK: test_vceqz_f32
+// CHECK: fcmeq {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vceqz_f32(float32x2_t a) {
+ return vceqz_f32(a);
+}
+
+// CHECK: test_vceqz_f64
+// CHECK: fcmeq {{d[0-9]+}}, {{d[0-9]+}}, #0
+uint64x1_t test_vceqz_f64(float64x1_t a) {
+ return vceqz_f64(a);
+}
+
+// CHECK: test_vceqzq_f32
+// CHECK: fcmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vceqzq_f32(float32x4_t a) {
+ return vceqzq_f32(a);
+}
+
+// CHECK: test_vceqz_p16
+// CHECK: cmeq {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vceqz_p16(poly16x4_t a) {
+ return vceqz_p16(a);
+}
+
+// CHECK: test_vceqzq_p16
+// CHECK: cmeq {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vceqzq_p16(poly16x8_t a) {
+ return vceqzq_p16(a);
+}
+
+// CHECK: test_vceqzq_f64
+// CHECK: fcmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vceqzq_f64(float64x2_t a) {
+ return vceqzq_f64(a);
+}
+
+// CHECK: test_vceqzq_p64
+// CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vceqzq_p64(poly64x2_t a) {
+ return vceqzq_p64(a);
+}
+
+// CHECK: test_vcgez_s8
+// CHECK: cmge {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x0
+uint8x8_t test_vcgez_s8(int8x8_t a) {
+ return vcgez_s8(a);
+}
+
+// CHECK: test_vcgez_s16
+// CHECK: cmge {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vcgez_s16(int16x4_t a) {
+ return vcgez_s16(a);
+}
+
+// CHECK: test_vcgez_s32
+// CHECK: cmge {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0x0
+uint32x2_t test_vcgez_s32(int32x2_t a) {
+ return vcgez_s32(a);
+}
+
+// CHECK: test_vcgez_s64
+// CHECK: cmge {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vcgez_s64(int64x1_t a) {
+ return vcgez_s64(a);
+}
+
+// CHECK: test_vcgezq_s8
+// CHECK: cmge {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x0
+uint8x16_t test_vcgezq_s8(int8x16_t a) {
+ return vcgezq_s8(a);
+}
+
+// CHECK: test_vcgezq_s16
+// CHECK: cmge {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vcgezq_s16(int16x8_t a) {
+ return vcgezq_s16(a);
+}
+
+// CHECK: test_vcgezq_s32
+// CHECK: cmge {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0x0
+uint32x4_t test_vcgezq_s32(int32x4_t a) {
+ return vcgezq_s32(a);
+}
+
+// CHECK: test_vcgezq_s64
+// CHECK: cmge {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0x0
+uint64x2_t test_vcgezq_s64(int64x2_t a) {
+ return vcgezq_s64(a);
+}
+
+// CHECK: test_vcgez_f32
+// CHECK: fcmge {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vcgez_f32(float32x2_t a) {
+ return vcgez_f32(a);
+}
+
+// CHECK: test_vcgezq_f32
+// CHECK: fcmge {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vcgezq_f32(float32x4_t a) {
+ return vcgezq_f32(a);
+}
+
+// CHECK: test_vcgezq_f64
+// CHECK: fcmge {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vcgezq_f64(float64x2_t a) {
+ return vcgezq_f64(a);
+}
+
+// CHECK: test_vclez_s8
+// CHECK: cmle {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x0
+uint8x8_t test_vclez_s8(int8x8_t a) {
+ return vclez_s8(a);
+}
+
+// CHECK: test_vclez_s16
+// CHECK: cmle {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vclez_s16(int16x4_t a) {
+ return vclez_s16(a);
+}
+
+// CHECK: test_vclez_s32
+// CHECK: cmle {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0x0
+uint32x2_t test_vclez_s32(int32x2_t a) {
+ return vclez_s32(a);
+}
+
+// CHECK: test_vclez_s64
+// CHECK: cmle {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vclez_s64(int64x1_t a) {
+ return vclez_s64(a);
+}
+
+// CHECK: test_vclezq_s8
+// CHECK: cmle {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x0
+uint8x16_t test_vclezq_s8(int8x16_t a) {
+ return vclezq_s8(a);
+}
+
+// CHECK: test_vclezq_s16
+// CHECK: cmle {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vclezq_s16(int16x8_t a) {
+ return vclezq_s16(a);
+}
+
+// CHECK: test_vclezq_s32
+// CHECK: cmle {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0x0
+uint32x4_t test_vclezq_s32(int32x4_t a) {
+ return vclezq_s32(a);
+}
+
+// CHECK: test_vclezq_s64
+// CHECK: cmle {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0x0
+uint64x2_t test_vclezq_s64(int64x2_t a) {
+ return vclezq_s64(a);
+}
+
+// CHECK: test_vclez_f32
+// CHECK: fcmle {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vclez_f32(float32x2_t a) {
+ return vclez_f32(a);
+}
+
+// CHECK: test_vclezq_f32
+// CHECK: fcmle {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vclezq_f32(float32x4_t a) {
+ return vclezq_f32(a);
+}
+
+// CHECK: test_vclezq_f64
+// CHECK: fcmle {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vclezq_f64(float64x2_t a) {
+ return vclezq_f64(a);
+}
+
+// CHECK: test_vcgtz_s8
+// CHECK: cmgt {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0x0
+uint8x8_t test_vcgtz_s8(int8x8_t a) {
+ return vcgtz_s8(a);
+}
+
+// CHECK: test_vcgtz_s16
+// CHECK: cmgt {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0x0
+uint16x4_t test_vcgtz_s16(int16x4_t a) {
+ return vcgtz_s16(a);
+}
+
+// CHECK: test_vcgtz_s32
+// CHECK: cmgt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0x0
+uint32x2_t test_vcgtz_s32(int32x2_t a) {
+ return vcgtz_s32(a);
+}
+
+// CHECK: test_vcgtz_s64
+// CHECK: cmgt {{d[0-9]+}}, {{d[0-9]+}}, #0x0
+uint64x1_t test_vcgtz_s64(int64x1_t a) {
+ return vcgtz_s64(a);
+}
+
+// CHECK: test_vcgtzq_s8
+// CHECK: cmgt {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x0
+uint8x16_t test_vcgtzq_s8(int8x16_t a) {
+ return vcgtzq_s8(a);
+}
+
+// CHECK: test_vcgtzq_s16
+// CHECK: cmgt {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0x0
+uint16x8_t test_vcgtzq_s16(int16x8_t a) {
+ return vcgtzq_s16(a);
+}
+
+// CHECK: test_vcgtzq_s32
+// CHECK: cmgt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0x0
+uint32x4_t test_vcgtzq_s32(int32x4_t a) {
+ return vcgtzq_s32(a);
+}
+
+// CHECK: test_vcgtzq_s64
+// CHECK: cmgt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0x0
+uint64x2_t test_vcgtzq_s64(int64x2_t a) {
+ return vcgtzq_s64(a);
+}
+
+// CHECK: test_vcgtz_f32
+// CHECK: fcmgt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vcgtz_f32(float32x2_t a) {
+ return vcgtz_f32(a);
+}
+
+// CHECK: test_vcgtzq_f32
+// CHECK: fcmgt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vcgtzq_f32(float32x4_t a) {
+ return vcgtzq_f32(a);
+}
+
+// CHECK: test_vcgtzq_f64
+// CHECK: fcmgt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vcgtzq_f64(float64x2_t a) {
+ return vcgtzq_f64(a);
+}
+
+// CHECK: test_vcltz_s8
+// CHECK: cmlt {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, #0
+uint8x8_t test_vcltz_s8(int8x8_t a) {
+ return vcltz_s8(a);
+}
+
+// CHECK: test_vcltz_s16
+// CHECK: cmlt {{v[0-9]+}}.4h, {{v[0-9]+}}.4h, #0
+uint16x4_t test_vcltz_s16(int16x4_t a) {
+ return vcltz_s16(a);
+}
+
+// CHECK: test_vcltz_s32
+// CHECK: cmlt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vcltz_s32(int32x2_t a) {
+ return vcltz_s32(a);
+}
+
+// CHECK: test_vcltz_s64
+// CHECK: cmlt {{d[0-9]+}}, {{d[0-9]+}}, #0
+uint64x1_t test_vcltz_s64(int64x1_t a) {
+ return vcltz_s64(a);
+}
+
+// CHECK: test_vcltzq_s8
+// CHECK: cmlt {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0
+uint8x16_t test_vcltzq_s8(int8x16_t a) {
+ return vcltzq_s8(a);
+}
+
+// CHECK: test_vcltzq_s16
+// CHECK: cmlt {{v[0-9]+}}.8h, {{v[0-9]+}}.8h, #0
+uint16x8_t test_vcltzq_s16(int16x8_t a) {
+ return vcltzq_s16(a);
+}
+
+// CHECK: test_vcltzq_s32
+// CHECK: cmlt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vcltzq_s32(int32x4_t a) {
+ return vcltzq_s32(a);
+}
+
+// CHECK: test_vcltzq_s64
+// CHECK: cmlt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vcltzq_s64(int64x2_t a) {
+ return vcltzq_s64(a);
+}
+
+// CHECK: test_vcltz_f32
+// CHECK: fcmlt {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, #0
+uint32x2_t test_vcltz_f32(float32x2_t a) {
+ return vcltz_f32(a);
+}
+
+// CHECK: test_vcltzq_f32
+// CHECK: fcmlt {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0
+uint32x4_t test_vcltzq_f32(float32x4_t a) {
+ return vcltzq_f32(a);
+}
+
+// CHECK: test_vcltzq_f64
+// CHECK: fcmlt {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
+uint64x2_t test_vcltzq_f64(float64x2_t a) {
+ return vcltzq_f64(a);
+}
+
+// CHECK: test_vrev16_s8
+// CHECK: rev16 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+int8x8_t test_vrev16_s8(int8x8_t a) {
+ return vrev16_s8(a);
+}
+
+// CHECK: test_vrev16_u8
+// CHECK: rev16 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+uint8x8_t test_vrev16_u8(uint8x8_t a) {
+ return vrev16_u8(a);
+}
+
+// CHECK: test_vrev16_p8
+// CHECK: rev16 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+poly8x8_t test_vrev16_p8(poly8x8_t a) {
+ return vrev16_p8(a);
+}
+
+// CHECK: test_vrev16q_s8
+// CHECK: rev16 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+int8x16_t test_vrev16q_s8(int8x16_t a) {
+ return vrev16q_s8(a);
+}
+
+// CHECK: test_vrev16q_u8
+// CHECK: rev16 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+uint8x16_t test_vrev16q_u8(uint8x16_t a) {
+ return vrev16q_u8(a);
+}
+
+// CHECK: test_vrev16q_p8
+// CHECK: rev16 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+poly8x16_t test_vrev16q_p8(poly8x16_t a) {
+ return vrev16q_p8(a);
+}
+
+// CHECK: test_vrev32_s8
+// CHECK: rev32 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+int8x8_t test_vrev32_s8(int8x8_t a) {
+ return vrev32_s8(a);
+}
+
+// CHECK: test_vrev32_s16
+// CHECK: rev32 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+int16x4_t test_vrev32_s16(int16x4_t a) {
+ return vrev32_s16(a);
+}
+
+// CHECK: test_vrev32_u8
+// CHECK: rev32 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+uint8x8_t test_vrev32_u8(uint8x8_t a) {
+ return vrev32_u8(a);
+}
+
+// CHECK: test_vrev32_u16
+// CHECK: rev32 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+uint16x4_t test_vrev32_u16(uint16x4_t a) {
+ return vrev32_u16(a);
+}
+
+// CHECK: test_vrev32_p8
+// CHECK: rev32 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+poly8x8_t test_vrev32_p8(poly8x8_t a) {
+ return vrev32_p8(a);
+}
+
+// CHECK: test_vrev32_p16
+// CHECK: rev32 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+poly16x4_t test_vrev32_p16(poly16x4_t a) {
+ return vrev32_p16(a);
+}
+
+// CHECK: test_vrev32q_s8
+// CHECK: rev32 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+int8x16_t test_vrev32q_s8(int8x16_t a) {
+ return vrev32q_s8(a);
+}
+
+// CHECK: test_vrev32q_s16
+// CHECK: rev32 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+int16x8_t test_vrev32q_s16(int16x8_t a) {
+ return vrev32q_s16(a);
+}
+
+// CHECK: test_vrev32q_u8
+// CHECK: rev32 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+uint8x16_t test_vrev32q_u8(uint8x16_t a) {
+ return vrev32q_u8(a);
+}
+
+// CHECK: test_vrev32q_u16
+// CHECK: rev32 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+uint16x8_t test_vrev32q_u16(uint16x8_t a) {
+ return vrev32q_u16(a);
+}
+
+// CHECK: test_vrev32q_p8
+// CHECK: rev32 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+poly8x16_t test_vrev32q_p8(poly8x16_t a) {
+ return vrev32q_p8(a);
+}
+
+// CHECK: test_vrev32q_p16
+// CHECK: rev32 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+poly16x8_t test_vrev32q_p16(poly16x8_t a) {
+ return vrev32q_p16(a);
+}
+
+// CHECK: test_vrev64_s8
+// CHECK: rev64 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+int8x8_t test_vrev64_s8(int8x8_t a) {
+ return vrev64_s8(a);
+}
+
+// CHECK: test_vrev64_s16
+// CHECK: rev64 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+int16x4_t test_vrev64_s16(int16x4_t a) {
+ return vrev64_s16(a);
+}
+
+// CHECK: test_vrev64_s32
+// CHECK: rev64 v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+int32x2_t test_vrev64_s32(int32x2_t a) {
+ return vrev64_s32(a);
+}
+
+// CHECK: test_vrev64_u8
+// CHECK: rev64 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+uint8x8_t test_vrev64_u8(uint8x8_t a) {
+ return vrev64_u8(a);
+}
+
+// CHECK: test_vrev64_u16
+// CHECK: rev64 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+uint16x4_t test_vrev64_u16(uint16x4_t a) {
+ return vrev64_u16(a);
+}
+
+// CHECK: test_vrev64_u32
+// CHECK: rev64 v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+uint32x2_t test_vrev64_u32(uint32x2_t a) {
+ return vrev64_u32(a);
+}
+
+// CHECK: test_vrev64_p8
+// CHECK: rev64 v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+poly8x8_t test_vrev64_p8(poly8x8_t a) {
+ return vrev64_p8(a);
+}
+
+// CHECK: test_vrev64_p16
+// CHECK: rev64 v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+poly16x4_t test_vrev64_p16(poly16x4_t a) {
+ return vrev64_p16(a);
+}
+
+// CHECK: test_vrev64_f32
+// CHECK: rev64 v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+float32x2_t test_vrev64_f32(float32x2_t a) {
+ return vrev64_f32(a);
+}
+
+// CHECK: test_vrev64q_s8
+// CHECK: rev64 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+int8x16_t test_vrev64q_s8(int8x16_t a) {
+ return vrev64q_s8(a);
+}
+
+// CHECK: test_vrev64q_s16
+// CHECK: rev64 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+int16x8_t test_vrev64q_s16(int16x8_t a) {
+ return vrev64q_s16(a);
+}
+
+// CHECK: test_vrev64q_s32
+// CHECK: rev64 v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+int32x4_t test_vrev64q_s32(int32x4_t a) {
+ return vrev64q_s32(a);
+}
+
+// CHECK: test_vrev64q_u8
+// CHECK: rev64 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+uint8x16_t test_vrev64q_u8(uint8x16_t a) {
+ return vrev64q_u8(a);
+}
+
+// CHECK: test_vrev64q_u16
+// CHECK: rev64 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+uint16x8_t test_vrev64q_u16(uint16x8_t a) {
+ return vrev64q_u16(a);
+}
+
+// CHECK: test_vrev64q_u32
+// CHECK: rev64 v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+uint32x4_t test_vrev64q_u32(uint32x4_t a) {
+ return vrev64q_u32(a);
+}
+
+// CHECK: test_vrev64q_p8
+// CHECK: rev64 v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+poly8x16_t test_vrev64q_p8(poly8x16_t a) {
+ return vrev64q_p8(a);
+}
+
+// CHECK: test_vrev64q_p16
+// CHECK: rev64 v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+poly16x8_t test_vrev64q_p16(poly16x8_t a) {
+ return vrev64q_p16(a);
+}
+
+// CHECK: test_vrev64q_f32
+// CHECK: rev64 v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+float32x4_t test_vrev64q_f32(float32x4_t a) {
+ return vrev64q_f32(a);
+}
+
+int16x4_t test_vpaddl_s8(int8x8_t a) {
+ // CHECK: test_vpaddl_s8
+ return vpaddl_s8(a);
+ // CHECK: saddlp v{{[0-9]+}}.4h, v{{[0-9]+}}.8b
+}
+
+int32x2_t test_vpaddl_s16(int16x4_t a) {
+ // CHECK: test_vpaddl_s16
+ return vpaddl_s16(a);
+ // CHECK: saddlp v{{[0-9]+}}.2s, v{{[0-9]+}}.4h
+}
+
+int64x1_t test_vpaddl_s32(int32x2_t a) {
+ // CHECK: test_vpaddl_s32
+ return vpaddl_s32(a);
+ // CHECK: saddlp v{{[0-9]+}}.1d, v{{[0-9]+}}.2s
+}
+
+uint16x4_t test_vpaddl_u8(uint8x8_t a) {
+ // CHECK: test_vpaddl_u8
+ return vpaddl_u8(a);
+ // CHECK: uaddlp v{{[0-9]+}}.4h, v{{[0-9]+}}.8b
+}
+
+uint32x2_t test_vpaddl_u16(uint16x4_t a) {
+ // CHECK: test_vpaddl_u16
+ return vpaddl_u16(a);
+ // CHECK: uaddlp v{{[0-9]+}}.2s, v{{[0-9]+}}.4h
+}
+
+uint64x1_t test_vpaddl_u32(uint32x2_t a) {
+ // CHECK: test_vpaddl_u32
+ return vpaddl_u32(a);
+ // CHECK: uaddlp v{{[0-9]+}}.1d, v{{[0-9]+}}.2s
+}
+
+int16x8_t test_vpaddlq_s8(int8x16_t a) {
+ // CHECK: test_vpaddlq_s8
+ return vpaddlq_s8(a);
+ // CHECK: saddlp v{{[0-9]+}}.8h, v{{[0-9]+}}.16b
+}
+
+int32x4_t test_vpaddlq_s16(int16x8_t a) {
+ // CHECK: test_vpaddlq_s16
+ return vpaddlq_s16(a);
+ // CHECK: saddlp v{{[0-9]+}}.4s, v{{[0-9]+}}.8h
+}
+
+int64x2_t test_vpaddlq_s32(int32x4_t a) {
+ // CHECK: test_vpaddlq_s32
+ return vpaddlq_s32(a);
+ // CHECK: saddlp v{{[0-9]+}}.2d, v{{[0-9]+}}.4s
+}
+
+uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
+ // CHECK: test_vpaddlq_u8
+ return vpaddlq_u8(a);
+ // CHECK: uaddlp v{{[0-9]+}}.8h, v{{[0-9]+}}.16b
+}
+
+uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
+ // CHECK: test_vpaddlq_u16
+ return vpaddlq_u16(a);
+ // CHECK: uaddlp v{{[0-9]+}}.4s, v{{[0-9]+}}.8h
+}
+
+uint64x2_t test_vpaddlq_u32(uint32x4_t a) {
+ // CHECK: test_vpaddlq_u32
+ return vpaddlq_u32(a);
+ // CHECK: uaddlp v{{[0-9]+}}.2d, v{{[0-9]+}}.4s
+}
+
+int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
+ // CHECK: test_vpadal_s8
+ return vpadal_s8(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.4h, v{{[0-9]+}}.8b
+}
+
+int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
+ // CHECK: test_vpadal_s16
+ return vpadal_s16(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.2s, v{{[0-9]+}}.4h
+}
+
+int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
+ // CHECK: test_vpadal_s32
+ return vpadal_s32(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.1d, v{{[0-9]+}}.2s
+}
+
+uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
+ // CHECK: test_vpadal_u8
+ return vpadal_u8(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.4h, v{{[0-9]+}}.8b
+}
+
+uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
+ // CHECK: test_vpadal_u16
+ return vpadal_u16(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.2s, v{{[0-9]+}}.4h
+}
+
+uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
+ // CHECK: test_vpadal_u32
+ return vpadal_u32(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.1d, v{{[0-9]+}}.2s
+}
+
+int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
+ // CHECK: test_vpadalq_s8
+ return vpadalq_s8(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.8h, v{{[0-9]+}}.16b
+}
+
+int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
+ // CHECK: test_vpadalq_s16
+ return vpadalq_s16(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.4s, v{{[0-9]+}}.8h
+}
+
+int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
+ // CHECK: test_vpadalq_s32
+ return vpadalq_s32(a, b);
+ // CHECK: sadalp v{{[0-9]+}}.2d, v{{[0-9]+}}.4s
+}
+
+uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
+ // CHECK: test_vpadalq_u8
+ return vpadalq_u8(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.8h, v{{[0-9]+}}.16b
+}
+
+uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
+ // CHECK: test_vpadalq_u16
+ return vpadalq_u16(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.4s, v{{[0-9]+}}.8h
+}
+
+uint64x2_t test_vpadalq_u32(uint64x2_t a, uint32x4_t b) {
+ // CHECK: test_vpadalq_u32
+ return vpadalq_u32(a, b);
+ // CHECK: uadalp v{{[0-9]+}}.2d, v{{[0-9]+}}.4s
+}
+
+int8x8_t test_vqabs_s8(int8x8_t a) {
+ // CHECK: test_vqabs_s8
+ return vqabs_s8(a);
+ // CHECK: sqabs v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vqabsq_s8(int8x16_t a) {
+ // CHECK: test_vqabsq_s8
+ return vqabsq_s8(a);
+ // CHECK: sqabs v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vqabs_s16(int16x4_t a) {
+ // CHECK: test_vqabs_s16
+ return vqabs_s16(a);
+ // CHECK: sqabs v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vqabsq_s16(int16x8_t a) {
+ // CHECK: test_vqabsq_s16
+ return vqabsq_s16(a);
+ // CHECK: sqabs v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vqabs_s32(int32x2_t a) {
+ // CHECK: test_vqabs_s32
+ return vqabs_s32(a);
+ // CHECK: sqabs v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vqabsq_s32(int32x4_t a) {
+ // CHECK: test_vqabsq_s32
+ return vqabsq_s32(a);
+ // CHECK: sqabs v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vqabsq_s64(int64x2_t a) {
+ // CHECK: test_vqabsq_s64
+ return vqabsq_s64(a);
+ // CHECK: sqabs v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vqneg_s8(int8x8_t a) {
+ // CHECK: test_vqneg_s8
+ return vqneg_s8(a);
+ // CHECK: sqneg v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vqnegq_s8(int8x16_t a) {
+ // CHECK: test_vqnegq_s8
+ return vqnegq_s8(a);
+ // CHECK: sqneg v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vqneg_s16(int16x4_t a) {
+ // CHECK: test_vqneg_s16
+ return vqneg_s16(a);
+ // CHECK: sqneg v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vqnegq_s16(int16x8_t a) {
+ // CHECK: test_vqnegq_s16
+ return vqnegq_s16(a);
+ // CHECK: sqneg v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vqneg_s32(int32x2_t a) {
+ // CHECK: test_vqneg_s32
+ return vqneg_s32(a);
+ // CHECK: sqneg v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vqnegq_s32(int32x4_t a) {
+ // CHECK: test_vqnegq_s32
+ return vqnegq_s32(a);
+ // CHECK: sqneg v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vqnegq_s64(int64x2_t a) {
+ // CHECK: test_vqnegq_s64
+ return vqnegq_s64(a);
+ // CHECK: sqneg v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vneg_s8(int8x8_t a) {
+ // CHECK: test_vneg_s8
+ return vneg_s8(a);
+ // CHECK: neg v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vnegq_s8(int8x16_t a) {
+ // CHECK: test_vnegq_s8
+ return vnegq_s8(a);
+ // CHECK: neg v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vneg_s16(int16x4_t a) {
+ // CHECK: test_vneg_s16
+ return vneg_s16(a);
+ // CHECK: neg v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vnegq_s16(int16x8_t a) {
+ // CHECK: test_vnegq_s16
+ return vnegq_s16(a);
+ // CHECK: neg v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vneg_s32(int32x2_t a) {
+ // CHECK: test_vneg_s32
+ return vneg_s32(a);
+ // CHECK: neg v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vnegq_s32(int32x4_t a) {
+ // CHECK: test_vnegq_s32
+ return vnegq_s32(a);
+ // CHECK: neg v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vnegq_s64(int64x2_t a) {
+ // CHECK: test_vnegq_s64
+ return vnegq_s64(a);
+ // CHECK: neg v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vneg_f32(float32x2_t a) {
+ // CHECK: test_vneg_f32
+ return vneg_f32(a);
+ // CHECK: fneg v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vnegq_f32(float32x4_t a) {
+ // CHECK: test_vnegq_f32
+ return vnegq_f32(a);
+ // CHECK: fneg v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vnegq_f64(float64x2_t a) {
+ // CHECK: test_vnegq_f64
+ return vnegq_f64(a);
+ // CHECK: fneg v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vabs_s8(int8x8_t a) {
+ // CHECK: test_vabs_s8
+ return vabs_s8(a);
+ // CHECK: abs v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vabsq_s8(int8x16_t a) {
+ // CHECK: test_vabsq_s8
+ return vabsq_s8(a);
+ // CHECK: abs v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vabs_s16(int16x4_t a) {
+ // CHECK: test_vabs_s16
+ return vabs_s16(a);
+ // CHECK: abs v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vabsq_s16(int16x8_t a) {
+ // CHECK: test_vabsq_s16
+ return vabsq_s16(a);
+ // CHECK: abs v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vabs_s32(int32x2_t a) {
+ // CHECK: test_vabs_s32
+ return vabs_s32(a);
+ // CHECK: abs v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vabsq_s32(int32x4_t a) {
+ // CHECK: test_vabsq_s32
+ return vabsq_s32(a);
+ // CHECK: abs v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vabsq_s64(int64x2_t a) {
+ // CHECK: test_vabsq_s64
+ return vabsq_s64(a);
+ // CHECK: abs v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vabs_f32(float32x2_t a) {
+ // CHECK: test_vabs_f32
+ return vabs_f32(a);
+ // CHECK: fabs v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vabsq_f32(float32x4_t a) {
+ // CHECK: test_vabsq_f32
+ return vabsq_f32(a);
+ // CHECK: fabs v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vabsq_f64(float64x2_t a) {
+ // CHECK: test_vabsq_f64
+ return vabsq_f64(a);
+ // CHECK: fabs v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vuqadd_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vuqadd_s8
+ return vuqadd_s8(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vuqaddq_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vuqaddq_s8
+ return vuqaddq_s8(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vuqadd_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vuqadd_s16
+ return vuqadd_s16(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vuqaddq_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vuqaddq_s16
+ return vuqaddq_s16(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vuqadd_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vuqadd_s32
+ return vuqadd_s32(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vuqaddq_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vuqaddq_s32
+ return vuqaddq_s32(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vuqaddq_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vuqaddq_s64
+ return vuqaddq_s64(a, b);
+ // CHECK: suqadd v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vcls_s8(int8x8_t a) {
+ // CHECK: test_vcls_s8
+ return vcls_s8(a);
+ // CHECK: cls v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vclsq_s8(int8x16_t a) {
+ // CHECK: test_vclsq_s8
+ return vclsq_s8(a);
+ // CHECK: cls v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vcls_s16(int16x4_t a) {
+ // CHECK: test_vcls_s16
+ return vcls_s16(a);
+ // CHECK: cls v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vclsq_s16(int16x8_t a) {
+ // CHECK: test_vclsq_s16
+ return vclsq_s16(a);
+ // CHECK: cls v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vcls_s32(int32x2_t a) {
+ // CHECK: test_vcls_s32
+ return vcls_s32(a);
+ // CHECK: cls v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vclsq_s32(int32x4_t a) {
+ // CHECK: test_vclsq_s32
+ return vclsq_s32(a);
+ // CHECK: cls v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int8x8_t test_vclz_s8(int8x8_t a) {
+ // CHECK: test_vclz_s8
+ return vclz_s8(a);
+ // CHECK: clz v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vclzq_s8(int8x16_t a) {
+ // CHECK: test_vclzq_s8
+ return vclzq_s8(a);
+ // CHECK: clz v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vclz_s16(int16x4_t a) {
+ // CHECK: test_vclz_s16
+ return vclz_s16(a);
+ // CHECK: clz v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+int16x8_t test_vclzq_s16(int16x8_t a) {
+ // CHECK: test_vclzq_s16
+ return vclzq_s16(a);
+ // CHECK: clz v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+int32x2_t test_vclz_s32(int32x2_t a) {
+ // CHECK: test_vclz_s32
+ return vclz_s32(a);
+ // CHECK: clz v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vclzq_s32(int32x4_t a) {
+ // CHECK: test_vclzq_s32
+ return vclzq_s32(a);
+ // CHECK: clz v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint8x8_t test_vclz_u8(uint8x8_t a) {
+ // CHECK: test_vclz_u8
+ return vclz_u8(a);
+ // CHECK: clz v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint8x16_t test_vclzq_u8(uint8x16_t a) {
+ // CHECK: test_vclzq_u8
+ return vclzq_u8(a);
+ // CHECK: clz v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint16x4_t test_vclz_u16(uint16x4_t a) {
+ // CHECK: test_vclz_u16
+ return vclz_u16(a);
+ // CHECK: clz v{{[0-9]+}}.4h, v{{[0-9]+}}.4h
+}
+
+uint16x8_t test_vclzq_u16(uint16x8_t a) {
+ // CHECK: test_vclzq_u16
+ return vclzq_u16(a);
+ // CHECK: clz v{{[0-9]+}}.8h, v{{[0-9]+}}.8h
+}
+
+uint32x2_t test_vclz_u32(uint32x2_t a) {
+ // CHECK: test_vclz_u32
+ return vclz_u32(a);
+ // CHECK: clz v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vclzq_u32(uint32x4_t a) {
+ // CHECK: test_vclzq_u32
+ return vclzq_u32(a);
+ // CHECK: clz v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int8x8_t test_vcnt_s8(int8x8_t a) {
+ // CHECK: test_vcnt_s8
+ return vcnt_s8(a);
+ // CHECK: cnt v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vcntq_s8(int8x16_t a) {
+ // CHECK: test_vcntq_s8
+ return vcntq_s8(a);
+ // CHECK: cnt v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint8x8_t test_vcnt_u8(uint8x8_t a) {
+ // CHECK: test_vcnt_u8
+ return vcnt_u8(a);
+ // CHECK: cnt v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint8x16_t test_vcntq_u8(uint8x16_t a) {
+ // CHECK: test_vcntq_u8
+ return vcntq_u8(a);
+ // CHECK: cnt v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+poly8x8_t test_vcnt_p8(poly8x8_t a) {
+ // CHECK: test_vcnt_p8
+ return vcnt_p8(a);
+ // CHECK: cnt v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+poly8x16_t test_vcntq_p8(poly8x16_t a) {
+ // CHECK: test_vcntq_p8
+ return vcntq_p8(a);
+ // CHECK: cnt v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int8x8_t test_vmvn_s8(int8x8_t a) {
+ // CHECK: test_vmvn_s8
+ return vmvn_s8(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vmvnq_s8(int8x16_t a) {
+ // CHECK: test_vmvnq_s8
+ return vmvnq_s8(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int16x4_t test_vmvn_s16(int16x4_t a) {
+ // CHECK: test_vmvn_s16
+ return vmvn_s16(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int16x8_t test_vmvnq_s16(int16x8_t a) {
+ // CHECK: test_vmvnq_s16
+ return vmvnq_s16(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int32x2_t test_vmvn_s32(int32x2_t a) {
+ // CHECK: test_vmvn_s32
+ return vmvn_s32(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int32x4_t test_vmvnq_s32(int32x4_t a) {
+ // CHECK: test_vmvnq_s32
+ return vmvnq_s32(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint8x8_t test_vmvn_u8(uint8x8_t a) {
+ // CHECK: test_vmvn_u8
+ return vmvn_u8(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint8x16_t test_vmvnq_u8(uint8x16_t a) {
+ // CHECK: test_vmvnq_u8
+ return vmvnq_u8(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint16x4_t test_vmvn_u16(uint16x4_t a) {
+ // CHECK: test_vmvn_u16
+ return vmvn_u16(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint16x8_t test_vmvnq_u16(uint16x8_t a) {
+ // CHECK: test_vmvnq_u16
+ return vmvnq_u16(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint32x2_t test_vmvn_u32(uint32x2_t a) {
+ // CHECK: test_vmvn_u32
+ return vmvn_u32(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint32x4_t test_vmvnq_u32(uint32x4_t a) {
+ // CHECK: test_vmvnq_u32
+ return vmvnq_u32(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+poly8x8_t test_vmvn_p8(poly8x8_t a) {
+ // CHECK: test_vmvn_p8
+ return vmvn_p8(a);
+ // CHECK: not v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+poly8x16_t test_vmvnq_p8(poly8x16_t a) {
+ // CHECK: test_vmvnq_p8
+ return vmvnq_p8(a);
+ // CHECK: not v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int8x8_t test_vrbit_s8(int8x8_t a) {
+ // CHECK: test_vrbit_s8
+ return vrbit_s8(a);
+ // CHECK: rbit v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+int8x16_t test_vrbitq_s8(int8x16_t a) {
+ // CHECK: test_vrbitq_s8
+ return vrbitq_s8(a);
+ // CHECK: rbit v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+uint8x8_t test_vrbit_u8(uint8x8_t a) {
+ // CHECK: test_vrbit_u8
+ return vrbit_u8(a);
+ // CHECK: rbit v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+uint8x16_t test_vrbitq_u8(uint8x16_t a) {
+ // CHECK: test_vrbitq_u8
+ return vrbitq_u8(a);
+ // CHECK: rbit v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+poly8x8_t test_vrbit_p8(poly8x8_t a) {
+ // CHECK: test_vrbit_p8
+ return vrbit_p8(a);
+ // CHECK: rbit v{{[0-9]+}}.8b, v{{[0-9]+}}.8b
+}
+
+poly8x16_t test_vrbitq_p8(poly8x16_t a) {
+ // CHECK: test_vrbitq_p8
+ return vrbitq_p8(a);
+ // CHECK: rbit v{{[0-9]+}}.16b, v{{[0-9]+}}.16b
+}
+
+int8x8_t test_vmovn_s16(int16x8_t a) {
+ // CHECK: test_vmovn_s16
+ return vmovn_s16(a);
+ // CHECK: xtn v{{[0-9]+}}.8b, v{{[0-9]+}}.8h
+}
+
+int16x4_t test_vmovn_s32(int32x4_t a) {
+ // CHECK: test_vmovn_s32
+ return vmovn_s32(a);
+ // CHECK: xtn v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+int32x2_t test_vmovn_s64(int64x2_t a) {
+ // CHECK: test_vmovn_s64
+ return vmovn_s64(a);
+ // CHECK: xtn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+uint8x8_t test_vmovn_u16(uint16x8_t a) {
+ // CHECK: test_vmovn_u16
+ return vmovn_u16(a);
+ // CHECK: xtn v{{[0-9]+}}.8b, v{{[0-9]+}}.8h
+}
+
+uint16x4_t test_vmovn_u32(uint32x4_t a) {
+ // CHECK: test_vmovn_u32
+ return vmovn_u32(a);
+ // CHECK: xtn v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+uint32x2_t test_vmovn_u64(uint64x2_t a) {
+ // CHECK: test_vmovn_u64
+ return vmovn_u64(a);
+ // CHECK: xtn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+int8x16_t test_vmovn_high_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vmovn_high_s16
+ return vmovn_high_s16(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.16b, v{{[0-9]+}}.8h
+}
+
+int16x8_t test_vmovn_high_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vmovn_high_s32
+ return vmovn_high_s32(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+int32x4_t test_vmovn_high_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vmovn_high_s64
+ return vmovn_high_s64(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+int8x16_t test_vmovn_high_u16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vmovn_high_u16
+ return vmovn_high_u16(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.16b, v{{[0-9]+}}.8h
+}
+
+int16x8_t test_vmovn_high_u32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vmovn_high_u32
+ return vmovn_high_u32(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+int32x4_t test_vmovn_high_u64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vmovn_high_u64
+ return vmovn_high_u64(a, b);
+ // CHECK: xtn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vqmovun_s16(int16x8_t a) {
+ // CHECK: test_vqmovun_s16
+ return vqmovun_s16(a);
+ // CHECK: sqxtun v{{[0-9]+}}.8b, v{{[0-9]+}}.8h
+}
+
+int16x4_t test_vqmovun_s32(int32x4_t a) {
+ // CHECK: test_vqmovun_s32
+ return vqmovun_s32(a);
+ // CHECK: sqxtun v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+int32x2_t test_vqmovun_s64(int64x2_t a) {
+ // CHECK: test_vqmovun_s64
+ return vqmovun_s64(a);
+ // CHECK: sqxtun v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+int8x16_t test_vqmovun_high_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqmovun_high_s16
+ return vqmovun_high_s16(a, b);
+ // CHECK: sqxtun2 v{{[0-9]+}}.16b, v{{[0-9]+}}.8h
+}
+
+int16x8_t test_vqmovun_high_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqmovun_high_s32
+ return vqmovun_high_s32(a, b);
+ // CHECK: sqxtun2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+int32x4_t test_vqmovun_high_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqmovun_high_s64
+ return vqmovun_high_s64(a, b);
+ // CHECK: sqxtun2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+int8x8_t test_vqmovn_s16(int16x8_t a) {
+ // CHECK: test_vqmovn_s16
+ return vqmovn_s16(a);
+ // CHECK: sqxtn v{{[0-9]+}}.8b, v{{[0-9]+}}.8h
+}
+
+int16x4_t test_vqmovn_s32(int32x4_t a) {
+ // CHECK: test_vqmovn_s32
+ return vqmovn_s32(a);
+ // CHECK: sqxtn v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+int32x2_t test_vqmovn_s64(int64x2_t a) {
+ // CHECK: test_vqmovn_s64
+ return vqmovn_s64(a);
+ // CHECK: sqxtn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+int8x16_t test_vqmovn_high_s16(int8x8_t a, int16x8_t b) {
+ // CHECK: test_vqmovn_high_s16
+ return vqmovn_high_s16(a, b);
+ // CHECK: sqxtn2 v{{[0-9]+}}.16b, v{{[0-9]+}}.8h
+}
+
+int16x8_t test_vqmovn_high_s32(int16x4_t a, int32x4_t b) {
+ // CHECK: test_vqmovn_high_s32
+ return vqmovn_high_s32(a, b);
+ // CHECK: sqxtn2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+int32x4_t test_vqmovn_high_s64(int32x2_t a, int64x2_t b) {
+ // CHECK: test_vqmovn_high_s64
+ return vqmovn_high_s64(a, b);
+ // CHECK: sqxtn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+uint8x8_t test_vqmovn_u16(uint16x8_t a) {
+ // CHECK: test_vqmovn_u16
+ return vqmovn_u16(a);
+ // CHECK: uqxtn v{{[0-9]+}}.8b, v{{[0-9]+}}.8h
+}
+
+uint16x4_t test_vqmovn_u32(uint32x4_t a) {
+ // CHECK: test_vqmovn_u32
+ return vqmovn_u32(a);
+ // CHECK: uqxtn v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+uint32x2_t test_vqmovn_u64(uint64x2_t a) {
+ // CHECK: test_vqmovn_u64
+ return vqmovn_u64(a);
+ // CHECK: uqxtn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+uint8x16_t test_vqmovn_high_u16(uint8x8_t a, uint16x8_t b) {
+ // CHECK: test_vqmovn_high_u16
+ return vqmovn_high_u16(a, b);
+ // CHECK: uqxtn2 v{{[0-9]+}}.16b, v{{[0-9]+}}.8h
+}
+
+uint16x8_t test_vqmovn_high_u32(uint16x4_t a, uint32x4_t b) {
+ // CHECK: test_vqmovn_high_u32
+ return vqmovn_high_u32(a, b);
+ // CHECK: uqxtn2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+uint32x4_t test_vqmovn_high_u64(uint32x2_t a, uint64x2_t b) {
+ // CHECK: test_vqmovn_high_u64
+ return vqmovn_high_u64(a, b);
+ // CHECK: uqxtn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+int16x8_t test_vshll_n_s8(int8x8_t a) {
+ // CHECK: test_vshll_n_s8
+ return vshll_n_s8(a, 8);
+ // CHECK: shll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #8
+}
+
+int32x4_t test_vshll_n_s16(int16x4_t a) {
+ // CHECK: test_vshll_n_s16
+ return vshll_n_s16(a, 16);
+ // CHECK: shll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #16
+}
+
+int64x2_t test_vshll_n_s32(int32x2_t a) {
+ // CHECK: test_vshll_n_s32
+ return vshll_n_s32(a, 32);
+ // CHECK: shll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #32
+}
+
+uint16x8_t test_vshll_n_u8(uint8x8_t a) {
+ // CHECK: test_vshll_n_u8
+ return vshll_n_u8(a, 8);
+ // CHECK: shll {{v[0-9]+}}.8h, {{v[0-9]+}}.8b, #8
+}
+
+uint32x4_t test_vshll_n_u16(uint16x4_t a) {
+ // CHECK: test_vshll_n_u16
+ return vshll_n_u16(a, 16);
+ // CHECK: shll {{v[0-9]+}}.4s, {{v[0-9]+}}.4h, #16
+}
+
+uint64x2_t test_vshll_n_u32(uint32x2_t a) {
+ // CHECK: test_vshll_n_u32
+ return vshll_n_u32(a, 32);
+ // CHECK: shll {{v[0-9]+}}.2d, {{v[0-9]+}}.2s, #32
+}
+
+int16x8_t test_vshll_high_n_s8(int8x16_t a) {
+ // CHECK: test_vshll_high_n_s8
+ return vshll_high_n_s8(a, 8);
+ // CHECK: shll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #8
+}
+
+int32x4_t test_vshll_high_n_s16(int16x8_t a) {
+ // CHECK: test_vshll_high_n_s16
+ return vshll_high_n_s16(a, 16);
+ // CHECK: shll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #16
+}
+
+int64x2_t test_vshll_high_n_s32(int32x4_t a) {
+ // CHECK: test_vshll_high_n_s32
+ return vshll_high_n_s32(a, 32);
+ // CHECK: shll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #32
+}
+
+uint16x8_t test_vshll_high_n_u8(uint8x16_t a) {
+ // CHECK: test_vshll_high_n_u8
+ return vshll_high_n_u8(a, 8);
+ // CHECK: shll2 {{v[0-9]+}}.8h, {{v[0-9]+}}.16b, #8
+}
+
+uint32x4_t test_vshll_high_n_u16(uint16x8_t a) {
+ // CHECK: test_vshll_high_n_u16
+ return vshll_high_n_u16(a, 16);
+ // CHECK: shll2 {{v[0-9]+}}.4s, {{v[0-9]+}}.8h, #16
+}
+
+uint64x2_t test_vshll_high_n_u32(uint32x4_t a) {
+ // CHECK: test_vshll_high_n_u32
+ return vshll_high_n_u32(a, 32);
+ // CHECK: shll2 {{v[0-9]+}}.2d, {{v[0-9]+}}.4s, #32
+}
+
+float16x4_t test_vcvt_f16_f32(float32x4_t a) {
+ //CHECK: test_vcvt_f16_f32
+ return vcvt_f16_f32(a);
+ // CHECK: fcvtn v{{[0-9]+}}.4h, v{{[0-9]+}}.4s
+}
+
+float16x8_t test_vcvt_high_f16_f32(float16x4_t a, float32x4_t b) {
+ //CHECK: test_vcvt_high_f16_f32
+ return vcvt_high_f16_f32(a, b);
+ // CHECK: fcvtn2 v{{[0-9]+}}.8h, v{{[0-9]+}}.4s
+}
+
+float32x2_t test_vcvt_f32_f64(float64x2_t a) {
+ //CHECK: test_vcvt_f32_f64
+ return vcvt_f32_f64(a);
+ // CHECK: fcvtn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+float32x4_t test_vcvt_high_f32_f64(float32x2_t a, float64x2_t b) {
+ //CHECK: test_vcvt_high_f32_f64
+ return vcvt_high_f32_f64(a, b);
+ // CHECK: fcvtn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vcvtx_f32_f64(float64x2_t a) {
+ //CHECK: test_vcvtx_f32_f64
+ return vcvtx_f32_f64(a);
+ // CHECK: fcvtxn v{{[0-9]+}}.2s, v{{[0-9]+}}.2d
+}
+
+float32x4_t test_vcvtx_high_f32_f64(float32x2_t a, float64x2_t b) {
+ //CHECK: test_vcvtx_high_f32_f64
+ return vcvtx_high_f32_f64(a, b);
+ // CHECK: fcvtxn2 v{{[0-9]+}}.4s, v{{[0-9]+}}.2d
+}
+
+float32x4_t test_vcvt_f32_f16(float16x4_t a) {
+ //CHECK: test_vcvt_f32_f16
+ return vcvt_f32_f16(a);
+ // CHECK: fcvtl v{{[0-9]+}}.4s, v{{[0-9]+}}.4h
+}
+
+float32x4_t test_vcvt_high_f32_f16(float16x8_t a) {
+ //CHECK: test_vcvt_high_f32_f16
+ return vcvt_high_f32_f16(a);
+ // CHECK: fcvtl2 v{{[0-9]+}}.4s, v{{[0-9]+}}.8h
+}
+
+float64x2_t test_vcvt_f64_f32(float32x2_t a) {
+ //CHECK: test_vcvt_f64_f32
+ return vcvt_f64_f32(a);
+ // CHECK: fcvtl v{{[0-9]+}}.2d, v{{[0-9]+}}.2s
+}
+
+float64x2_t test_vcvt_high_f64_f32(float32x4_t a) {
+ //CHECK: test_vcvt_high_f64_f32
+ return vcvt_high_f64_f32(a);
+ // CHECK: fcvtl2 v{{[0-9]+}}.2d, v{{[0-9]+}}.4s
+}
+
+float32x2_t test_vrndn_f32(float32x2_t a) {
+ //CHECK: test_vrndn_f32
+ return vrndn_f32(a);
+ // CHECK: frintn v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndnq_f32(float32x4_t a) {
+ //CHECK: test_vrndnq_f32
+ return vrndnq_f32(a);
+ // CHECK: frintn v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndnq_f64(float64x2_t a) {
+ //CHECK: test_vrndnq_f64
+ return vrndnq_f64(a);
+ // CHECK: frintn v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrnda_f32(float32x2_t a) {
+ //CHECK: test_vrnda_f32
+ return vrnda_f32(a);
+ // CHECK: frinta v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndaq_f32(float32x4_t a) {
+ //CHECK: test_vrndaq_f32
+ return vrndaq_f32(a);
+ // CHECK: frinta v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndaq_f64(float64x2_t a) {
+ //CHECK: test_vrndaq_f64
+ return vrndaq_f64(a);
+ // CHECK: frinta v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrndp_f32(float32x2_t a) {
+ //CHECK: test_vrndp_f32
+ return vrndp_f32(a);
+ // CHECK: frintp v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndpq_f32(float32x4_t a) {
+ //CHECK: test_vrndpq_f32
+ return vrndpq_f32(a);
+ // CHECK: frintp v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndpq_f64(float64x2_t a) {
+ //CHECK: test_vrndpq_f64
+ return vrndpq_f64(a);
+ // CHECK: frintp v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrndm_f32(float32x2_t a) {
+ //CHECK: test_vrndm_f32
+ return vrndm_f32(a);
+ // CHECK: frintm v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndmq_f32(float32x4_t a) {
+ //CHECK: test_vrndmq_f32
+ return vrndmq_f32(a);
+ // CHECK: frintm v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndmq_f64(float64x2_t a) {
+ //CHECK: test_vrndmq_f64
+ return vrndmq_f64(a);
+ // CHECK: frintm v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrndx_f32(float32x2_t a) {
+ //CHECK: test_vrndx_f32
+ return vrndx_f32(a);
+ // CHECK: frintx v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndxq_f32(float32x4_t a) {
+ //CHECK: test_vrndxq_f32
+ return vrndxq_f32(a);
+ // CHECK: frintx v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndxq_f64(float64x2_t a) {
+ //CHECK: test_vrndxq_f64
+ return vrndxq_f64(a);
+ // CHECK: frintx v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrnd_f32(float32x2_t a) {
+ //CHECK: test_vrnd_f32
+ return vrnd_f32(a);
+ // CHECK: frintz v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndq_f32(float32x4_t a) {
+ //CHECK: test_vrndq_f32
+ return vrndq_f32(a);
+ // CHECK: frintz v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndq_f64(float64x2_t a) {
+ //CHECK: test_vrndq_f64
+ return vrndq_f64(a);
+ // CHECK: frintz v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrndi_f32(float32x2_t a) {
+ //CHECK: test_vrndi_f32
+ return vrndi_f32(a);
+ // CHECK: frinti v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrndiq_f32(float32x4_t a) {
+ //CHECK: test_vrndiq_f32
+ return vrndiq_f32(a);
+ // CHECK: frinti v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrndiq_f64(float64x2_t a) {
+ //CHECK: test_vrndiq_f64
+ return vrndiq_f64(a);
+ // CHECK: frinti v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int32x2_t test_vcvt_s32_f32(float32x2_t a) {
+ //CHECK: test_vcvt_s32_f32
+ return vcvt_s32_f32(a);
+ // CHECK: fcvtzs v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vcvtq_s32_f32(float32x4_t a) {
+ //CHECK: test_vcvtq_s32_f32
+ return vcvtq_s32_f32(a);
+ // CHECK: fcvtzs v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vcvtq_s64_f64(float64x2_t a) {
+ //CHECK: test_vcvtq_s64_f64
+ return vcvtq_s64_f64(a);
+ // CHECK: fcvtzs v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vcvt_u32_f32(float32x2_t a) {
+ //CHECK: test_vcvt_u32_f32
+ return vcvt_u32_f32(a);
+ // CHECK: fcvtzu v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vcvtq_u32_f32(float32x4_t a) {
+ //CHECK: test_vcvtq_u32_f32
+ return vcvtq_u32_f32(a);
+ // CHECK: fcvtzu v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint64x2_t test_vcvtq_u64_f64(float64x2_t a) {
+ //CHECK: test_vcvtq_u64_f64
+ return vcvtq_u64_f64(a);
+ // CHECK: fcvtzu v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int32x2_t test_vcvtn_s32_f32(float32x2_t a) {
+ //CHECK: test_vcvtn_s32_f32
+ return vcvtn_s32_f32(a);
+ // CHECK: fcvtns v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vcvtnq_s32_f32(float32x4_t a) {
+ //CHECK: test_vcvtnq_s32_f32
+ return vcvtnq_s32_f32(a);
+ // CHECK: fcvtns v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vcvtnq_s64_f64(float64x2_t a) {
+ //CHECK: test_vcvtnq_s64_f64
+ return vcvtnq_s64_f64(a);
+ // CHECK: fcvtns v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vcvtn_u32_f32(float32x2_t a) {
+ //CHECK: test_vcvtn_u32_f32
+ return vcvtn_u32_f32(a);
+ // CHECK: fcvtnu v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vcvtnq_u32_f32(float32x4_t a) {
+ //CHECK: test_vcvtnq_u32_f32
+ return vcvtnq_u32_f32(a);
+ // CHECK: fcvtnu v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint64x2_t test_vcvtnq_u64_f64(float64x2_t a) {
+ //CHECK: test_vcvtnq_u64_f64
+ return vcvtnq_u64_f64(a);
+ // CHECK: fcvtnu v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int32x2_t test_vcvtp_s32_f32(float32x2_t a) {
+ //CHECK: test_vcvtp_s32_f32
+ return vcvtp_s32_f32(a);
+ // CHECK: fcvtps v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vcvtpq_s32_f32(float32x4_t a) {
+ //CHECK: test_vcvtpq_s32_f32
+ return vcvtpq_s32_f32(a);
+ // CHECK: fcvtps v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vcvtpq_s64_f64(float64x2_t a) {
+ //CHECK: test_vcvtpq_s64_f64
+ return vcvtpq_s64_f64(a);
+ // CHECK: fcvtps v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vcvtp_u32_f32(float32x2_t a) {
+ //CHECK: test_vcvtp_u32_f32
+ return vcvtp_u32_f32(a);
+ // CHECK: fcvtpu v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vcvtpq_u32_f32(float32x4_t a) {
+ //CHECK: test_vcvtpq_u32_f32
+ return vcvtpq_u32_f32(a);
+ // CHECK: fcvtpu v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint64x2_t test_vcvtpq_u64_f64(float64x2_t a) {
+ //CHECK: test_vcvtpq_u64_f64
+ return vcvtpq_u64_f64(a);
+ // CHECK: fcvtpu v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int32x2_t test_vcvtm_s32_f32(float32x2_t a) {
+ //CHECK: test_vcvtm_s32_f32
+ return vcvtm_s32_f32(a);
+ // CHECK: fcvtms v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vcvtmq_s32_f32(float32x4_t a) {
+ //CHECK: test_vcvtmq_s32_f32
+ return vcvtmq_s32_f32(a);
+ // CHECK: fcvtms v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vcvtmq_s64_f64(float64x2_t a) {
+ //CHECK: test_vcvtmq_s64_f64
+ return vcvtmq_s64_f64(a);
+ // CHECK: fcvtms v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vcvtm_u32_f32(float32x2_t a) {
+ //CHECK: test_vcvtm_u32_f32
+ return vcvtm_u32_f32(a);
+ // CHECK: fcvtmu v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vcvtmq_u32_f32(float32x4_t a) {
+ //CHECK: test_vcvtmq_u32_f32
+ return vcvtmq_u32_f32(a);
+ // CHECK: fcvtmu v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint64x2_t test_vcvtmq_u64_f64(float64x2_t a) {
+ //CHECK: test_vcvtmq_u64_f64
+ return vcvtmq_u64_f64(a);
+ // CHECK: fcvtmu v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+int32x2_t test_vcvta_s32_f32(float32x2_t a) {
+ //CHECK: test_vcvta_s32_f32
+ return vcvta_s32_f32(a);
+ // CHECK: fcvtas v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+int32x4_t test_vcvtaq_s32_f32(float32x4_t a) {
+ //CHECK: test_vcvtaq_s32_f32
+ return vcvtaq_s32_f32(a);
+ // CHECK: fcvtas v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+int64x2_t test_vcvtaq_s64_f64(float64x2_t a) {
+ //CHECK: test_vcvtaq_s64_f64
+ return vcvtaq_s64_f64(a);
+ // CHECK: fcvtas v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vcvta_u32_f32(float32x2_t a) {
+ //CHECK: test_vcvta_u32_f32
+ return vcvta_u32_f32(a);
+ // CHECK: fcvtau v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vcvtaq_u32_f32(float32x4_t a) {
+ //CHECK: test_vcvtaq_u32_f32
+ return vcvtaq_u32_f32(a);
+ // CHECK: fcvtau v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+uint64x2_t test_vcvtaq_u64_f64(float64x2_t a) {
+ //CHECK: test_vcvtaq_u64_f64
+ return vcvtaq_u64_f64(a);
+ // CHECK: fcvtau v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrsqrte_f32(float32x2_t a) {
+ //CHECK: test_vrsqrte_f32
+ return vrsqrte_f32(a);
+ // CHECK: frsqrte v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrsqrteq_f32(float32x4_t a) {
+ //CHECK: test_vrsqrteq_f32
+ return vrsqrteq_f32(a);
+ // CHECK: frsqrte v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrsqrteq_f64(float64x2_t a) {
+ //CHECK: test_vrsqrteq_f64
+ return vrsqrteq_f64(a);
+ // CHECK: frsqrte v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vrecpe_f32(float32x2_t a) {
+ //CHECK: test_vrecpe_f32
+ return vrecpe_f32(a);
+ // CHECK: frecpe v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vrecpeq_f32(float32x4_t a) {
+ //CHECK: test_vrecpeq_f32
+ return vrecpeq_f32(a);
+ // CHECK: frecpe v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vrecpeq_f64(float64x2_t a) {
+ //CHECK: test_vrecpeq_f64
+ return vrecpeq_f64(a);
+ // CHECK: frecpe v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+uint32x2_t test_vrecpe_u32(uint32x2_t a) {
+ //CHECK: test_vrecpe_u32
+ return vrecpe_u32(a);
+ // CHECK: urecpe v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
+ //CHECK: test_vrecpeq_u32
+ return vrecpeq_u32(a);
+ // CHECK: urecpe v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float32x2_t test_vsqrt_f32(float32x2_t a) {
+ //CHECK: test_vsqrt_f32
+ return vsqrt_f32(a);
+ // CHECK: fsqrt v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vsqrtq_f32(float32x4_t a) {
+ //CHECK: test_vsqrtq_f32
+ return vsqrtq_f32(a);
+ // CHECK: fsqrt v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vsqrtq_f64(float64x2_t a) {
+ //CHECK: test_vsqrtq_f64
+ return vsqrtq_f64(a);
+ // CHECK: fsqrt v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float32x2_t test_vcvt_f32_s32(int32x2_t a) {
+ //CHECK: test_vcvt_f32_s32
+ return vcvt_f32_s32(a);
+ //CHECK: scvtf v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x2_t test_vcvt_f32_u32(uint32x2_t a) {
+ //CHECK: test_vcvt_f32_u32
+ return vcvt_f32_u32(a);
+ //CHECK: ucvtf v{{[0-9]+}}.2s, v{{[0-9]+}}.2s
+}
+
+float32x4_t test_vcvtq_f32_s32(int32x4_t a) {
+ //CHECK: test_vcvtq_f32_s32
+ return vcvtq_f32_s32(a);
+ //CHECK: scvtf v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float32x4_t test_vcvtq_f32_u32(uint32x4_t a) {
+ //CHECK: test_vcvtq_f32_u32
+ return vcvtq_f32_u32(a);
+ //CHECK: ucvtf v{{[0-9]+}}.4s, v{{[0-9]+}}.4s
+}
+
+float64x2_t test_vcvtq_f64_s64(int64x2_t a) {
+ //CHECK: test_vcvtq_f64_s64
+ return vcvtq_f64_s64(a);
+ //CHECK: scvtf v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
+
+float64x2_t test_vcvtq_f64_u64(uint64x2_t a) {
+ //CHECK: test_vcvtq_f64_u64
+ return vcvtq_f64_u64(a);
+ //CHECK: ucvtf v{{[0-9]+}}.2d, v{{[0-9]+}}.2d
+}
diff --git a/test/CodeGen/aarch64-neon-perm.c b/test/CodeGen/aarch64-neon-perm.c
new file mode 100644
index 000000000000..903570b9954a
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-perm.c
@@ -0,0 +1,1093 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x8_t test_vuzp1_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vuzp1_s8
+ return vuzp1_s8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vuzp1q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vuzp1q_s8
+ return vuzp1q_s8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vuzp1_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vuzp1_s16
+ return vuzp1_s16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vuzp1q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vuzp1q_s16
+ return vuzp1q_s16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vuzp1_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vuzp1_s32
+ return vuzp1_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vuzp1q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vuzp1q_s32
+ return vuzp1q_s32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vuzp1q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vuzp1q_s64
+ return vuzp1q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+uint8x8_t test_vuzp1_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vuzp1_u8
+ return vuzp1_u8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vuzp1q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vuzp1q_u8
+ return vuzp1q_u8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vuzp1_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vuzp1_u16
+ return vuzp1_u16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vuzp1q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vuzp1q_u16
+ return vuzp1q_u16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vuzp1_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vuzp1_u32
+ return vuzp1_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vuzp1q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vuzp1q_u32
+ return vuzp1q_u32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vuzp1q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vuzp1q_u64
+ return vuzp1q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vuzp1_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vuzp1_f32
+ return vuzp1_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vuzp1q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vuzp1q_f32
+ return vuzp1q_f32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vuzp1q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vuzp1q_f64
+ return vuzp1q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly8x8_t test_vuzp1_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vuzp1_p8
+ return vuzp1_p8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vuzp1q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vuzp1q_p8
+ return vuzp1q_p8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vuzp1_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vuzp1_p16
+ return vuzp1_p16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vuzp1q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vuzp1q_p16
+ return vuzp1q_p16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8_t test_vuzp2_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vuzp2_s8
+ return vuzp2_s8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vuzp2q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vuzp2q_s8
+ return vuzp2q_s8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vuzp2_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vuzp2_s16
+ return vuzp2_s16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vuzp2q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vuzp2q_s16
+ return vuzp2q_s16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vuzp2_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vuzp2_s32
+ return vuzp2_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vuzp2q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vuzp2q_s32
+ return vuzp2q_s32(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vuzp2q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vuzp2q_s64
+ return vuzp2q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+uint8x8_t test_vuzp2_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vuzp2_u8
+ return vuzp2_u8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vuzp2q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vuzp2q_u8
+ return vuzp2q_u8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vuzp2_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vuzp2_u16
+ return vuzp2_u16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vuzp2q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vuzp2q_u16
+ return vuzp2q_u16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vuzp2_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vuzp2_u32
+ return vuzp2_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vuzp2q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vuzp2q_u32
+ return vuzp2q_u32(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vuzp2q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vuzp2q_u64
+ return vuzp2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+float32x2_t test_vuzp2_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vuzp2_f32
+ return vuzp2_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vuzp2q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vuzp2q_f32
+ return vuzp2q_f32(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vuzp2q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vuzp2q_f64
+ return vuzp2q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly8x8_t test_vuzp2_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vuzp2_p8
+ return vuzp2_p8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vuzp2q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vuzp2q_p8
+ return vuzp2q_p8(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vuzp2_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vuzp2_p16
+ return vuzp2_p16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vuzp2q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vuzp2q_p16
+ return vuzp2q_p16(a, b);
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8_t test_vzip1_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vzip1_s8
+ return vzip1_s8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vzip1q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vzip1q_s8
+ return vzip1q_s8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vzip1_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vzip1_s16
+ return vzip1_s16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vzip1q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vzip1q_s16
+ return vzip1q_s16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vzip1_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vzip1_s32
+ return vzip1_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vzip1q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vzip1q_s32
+ return vzip1q_s32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vzip1q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vzip1q_s64
+ return vzip1q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+uint8x8_t test_vzip1_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vzip1_u8
+ return vzip1_u8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vzip1q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vzip1q_u8
+ return vzip1q_u8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vzip1_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vzip1_u16
+ return vzip1_u16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vzip1q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vzip1q_u16
+ return vzip1q_u16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vzip1_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vzip1_u32
+ return vzip1_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vzip1q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vzip1q_u32
+ return vzip1q_u32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vzip1q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vzip1q_u64
+ return vzip1q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vzip1_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vzip1_f32
+ return vzip1_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vzip1q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vzip1q_f32
+ return vzip1q_f32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vzip1q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vzip1q_f64
+ return vzip1q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly8x8_t test_vzip1_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vzip1_p8
+ return vzip1_p8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vzip1q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vzip1q_p8
+ return vzip1q_p8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vzip1_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vzip1_p16
+ return vzip1_p16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vzip1q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vzip1q_p16
+ return vzip1q_p16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8_t test_vzip2_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vzip2_s8
+ return vzip2_s8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vzip2q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vzip2q_s8
+ return vzip2q_s8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vzip2_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vzip2_s16
+ return vzip2_s16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vzip2q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vzip2q_s16
+ return vzip2q_s16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vzip2_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vzip2_s32
+ return vzip2_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vzip2q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vzip2q_s32
+ return vzip2q_s32(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vzip2q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vzip2q_s64
+ return vzip2q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+uint8x8_t test_vzip2_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vzip2_u8
+ return vzip2_u8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vzip2q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vzip2q_u8
+ return vzip2q_u8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vzip2_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vzip2_u16
+ return vzip2_u16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vzip2q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vzip2q_u16
+ return vzip2q_u16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vzip2_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vzip2_u32
+ return vzip2_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vzip2q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vzip2q_u32
+ return vzip2q_u32(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vzip2q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vzip2q_u64
+ return vzip2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+float32x2_t test_vzip2_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vzip2_f32
+ return vzip2_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vzip2q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vzip2q_f32
+ return vzip2q_f32(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vzip2q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vzip2q_f64
+ return vzip2q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly8x8_t test_vzip2_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vzip2_p8
+ return vzip2_p8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vzip2q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vzip2q_p8
+ return vzip2q_p8(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vzip2_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vzip2_p16
+ return vzip2_p16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vzip2q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vzip2q_p16
+ return vzip2q_p16(a, b);
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8_t test_vtrn1_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vtrn1_s8
+ return vtrn1_s8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vtrn1q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vtrn1q_s8
+ return vtrn1q_s8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vtrn1_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vtrn1_s16
+ return vtrn1_s16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vtrn1q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vtrn1q_s16
+ return vtrn1q_s16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vtrn1_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vtrn1_s32
+ return vtrn1_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+int32x4_t test_vtrn1q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vtrn1q_s32
+ return vtrn1q_s32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vtrn1q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vtrn1q_s64
+ return vtrn1q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+uint8x8_t test_vtrn1_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vtrn1_u8
+ return vtrn1_u8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vtrn1q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vtrn1q_u8
+ return vtrn1q_u8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vtrn1_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vtrn1_u16
+ return vtrn1_u16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vtrn1q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vtrn1q_u16
+ return vtrn1q_u16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vtrn1_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vtrn1_u32
+ return vtrn1_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+uint32x4_t test_vtrn1q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vtrn1q_u32
+ return vtrn1q_u32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vtrn1q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vtrn1q_u64
+ return vtrn1q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+float32x2_t test_vtrn1_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vtrn1_f32
+ return vtrn1_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+}
+
+float32x4_t test_vtrn1q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vtrn1q_f32
+ return vtrn1q_f32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vtrn1q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vtrn1q_f64
+ return vtrn1q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly8x8_t test_vtrn1_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vtrn1_p8
+ return vtrn1_p8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vtrn1q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vtrn1q_p8
+ return vtrn1q_p8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vtrn1_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vtrn1_p16
+ return vtrn1_p16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vtrn1q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vtrn1q_p16
+ return vtrn1q_p16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8_t test_vtrn2_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vtrn2_s8
+ return vtrn2_s8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vtrn2q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vtrn2q_s8
+ return vtrn2q_s8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+int16x4_t test_vtrn2_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vtrn2_s16
+ return vtrn2_s16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+int16x8_t test_vtrn2q_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vtrn2q_s16
+ return vtrn2q_s16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int32x2_t test_vtrn2_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vtrn2_s32
+ return vtrn2_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+int32x4_t test_vtrn2q_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vtrn2q_s32
+ return vtrn2q_s32(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+int64x2_t test_vtrn2q_s64(int64x2_t a, int64x2_t b) {
+ // CHECK: test_vtrn2q_s64
+ return vtrn2q_s64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+uint8x8_t test_vtrn2_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vtrn2_u8
+ return vtrn2_u8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vtrn2q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vtrn2q_u8
+ return vtrn2q_u8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+uint16x4_t test_vtrn2_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vtrn2_u16
+ return vtrn2_u16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+uint16x8_t test_vtrn2q_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vtrn2q_u16
+ return vtrn2q_u16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+uint32x2_t test_vtrn2_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vtrn2_u32
+ return vtrn2_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+uint32x4_t test_vtrn2q_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vtrn2q_u32
+ return vtrn2q_u32(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+uint64x2_t test_vtrn2q_u64(uint64x2_t a, uint64x2_t b) {
+ // CHECK: test_vtrn2q_u64
+ return vtrn2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+float32x2_t test_vtrn2_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vtrn2_f32
+ return vtrn2_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+
+float32x4_t test_vtrn2q_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vtrn2q_f32
+ return vtrn2q_f32(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+
+float64x2_t test_vtrn2q_f64(float64x2_t a, float64x2_t b) {
+ // CHECK: test_vtrn2q_f64
+ return vtrn2q_f64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly8x8_t test_vtrn2_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vtrn2_p8
+ return vtrn2_p8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vtrn2q_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vtrn2q_p8
+ return vtrn2q_p8(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly16x4_t test_vtrn2_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vtrn2_p16
+ return vtrn2_p16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+
+poly16x8_t test_vtrn2q_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vtrn2q_p16
+ return vtrn2q_p16(a, b);
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vuzp_s8
+ return vuzp_s8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vuzp_s16
+ return vuzp_s16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vuzp_s32
+ return vuzp_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vuzp_u8
+ return vuzp_u8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vuzp_u16
+ return vuzp_u16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vuzp_u32
+ return vuzp_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vuzp_f32
+ return vuzp_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vuzp_p8
+ return vuzp_p8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: uzp2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vuzp_p16
+ return vuzp_p16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: uzp2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vuzpq_s8
+ return vuzpq_s8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vuzpq_s16
+ return vuzpq_s16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vuzpq_s32
+ return vuzpq_s32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vuzpq_u8
+ return vuzpq_u8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vuzpq_u16
+ return vuzpq_u16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vuzpq_u32
+ return vuzpq_u32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vuzpq_f32
+ return vuzpq_f32(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: uzp2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vuzpq_p8
+ return vuzpq_p8(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: uzp2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vuzpq_p16
+ return vuzpq_p16(a, b);
+ // CHECK: uzp1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: uzp2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vzip_s8
+ return vzip_s8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vzip_s16
+ return vzip_s16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vzip_s32
+ return vzip_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vzip_u8
+ return vzip_u8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vzip_u16
+ return vzip_u16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vzip_u32
+ return vzip_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vzip_f32
+ return vzip_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vzip_p8
+ return vzip_p8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: zip2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vzip_p16
+ return vzip_p16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: zip2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vzipq_s8
+ return vzipq_s8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vzipq_s16
+ return vzipq_s16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vzipq_s32
+ return vzipq_s32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vzipq_u8
+ return vzipq_u8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vzipq_u16
+ return vzipq_u16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vzipq_u32
+ return vzipq_u32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vzipq_f32
+ return vzipq_f32(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vzipq_p8
+ return vzipq_p8(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: zip2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+poly16x8x2_t test_vzipq_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vzipq_p16
+ return vzipq_p16(a, b);
+ // CHECK: zip1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: zip2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+
+int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vtrn_s8
+ return vtrn_s8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) {
+ // CHECK: test_vtrn_s16
+ return vtrn_s16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) {
+ // CHECK: test_vtrn_s32
+ return vtrn_s32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vtrn_u8
+ return vtrn_u8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) {
+ // CHECK: test_vtrn_u16
+ return vtrn_u16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) {
+ // CHECK: test_vtrn_u32
+ return vtrn_u32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) {
+ // CHECK: test_vtrn_f32
+ return vtrn_f32(a, b);
+ // CHECK: ins {{v[0-9]+}}.s[1], {{v[0-9]+}}.s[0]
+ // CHECK: ins {{v[0-9]+}}.s[0], {{v[0-9]+}}.s[1]
+}
+poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) {
+ // CHECK: test_vtrn_p8
+ return vtrn_p8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: trn2 {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) {
+ // CHECK: test_vtrn_p16
+ return vtrn_p16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+ // CHECK: trn2 {{v[0-9]+}}.4h, {{v[0-9]+}}.4h
+}
+int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vtrnq_s8
+ return vtrnq_s8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) {
+ // CHECK: test_vtrnq_s16
+ return vtrnq_s16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) {
+ // CHECK: test_vtrnq_s32
+ return vtrnq_s32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vtrnq_u8
+ return vtrnq_u8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) {
+ // CHECK: test_vtrnq_u16
+ return vtrnq_u16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
+uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) {
+ // CHECK: test_vtrnq_u32
+ return vtrnq_u32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK: test_vtrnq_f32
+ return vtrnq_f32(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+ // CHECK: trn2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s
+}
+poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) {
+ // CHECK: test_vtrnq_p8
+ return vtrnq_p8(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+ // CHECK: trn2 {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+poly16x8x2_t test_vtrnq_p16(poly16x8_t a, poly16x8_t b) {
+ // CHECK: test_vtrnq_p16
+ return vtrnq_p16(a, b);
+ // CHECK: trn1 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+ // CHECK: trn2 {{v[0-9]+}}.8h, {{v[0-9]+}}.8h
+}
diff --git a/test/CodeGen/aarch64-neon-scalar-copy.c b/test/CodeGen/aarch64-neon-scalar-copy.c
new file mode 100644
index 000000000000..33e97c792fb1
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-scalar-copy.c
@@ -0,0 +1,173 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+
+#include <arm_neon.h>
+
+// CHECK: test_vdups_lane_f32
+float32_t test_vdups_lane_f32(float32x2_t a) {
+ return vdups_lane_f32(a, 1);
+// CHECK: ret
+// CHECK-NOT: dup {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+
+// CHECK: test_vdupd_lane_f64
+float64_t test_vdupd_lane_f64(float64x1_t a) {
+ return vdupd_lane_f64(a, 0);
+// CHECK: ret
+// CHECK-NOT: dup {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+
+// CHECK: test_vdups_laneq_f32
+float32_t test_vdups_laneq_f32(float32x4_t a) {
+ return vdups_laneq_f32(a, 3);
+// CHECK: ret
+// CHECK-NOT: dup {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+
+// CHECK: test_vdupd_laneq_f64
+float64_t test_vdupd_laneq_f64(float64x2_t a) {
+ return vdupd_laneq_f64(a, 1);
+// CHECK: ret
+// CHECK-NOT: dup {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+
+// CHECK: test_vdupb_lane_s8
+int8_t test_vdupb_lane_s8(int8x8_t a) {
+ return vdupb_lane_s8(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+
+// CHECK: test_vduph_lane_s16
+int16_t test_vduph_lane_s16(int16x4_t a) {
+ return vduph_lane_s16(a, 3);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+
+// CHECK: test_vdups_lane_s32
+int32_t test_vdups_lane_s32(int32x2_t a) {
+ return vdups_lane_s32(a, 1);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+
+// CHECK: test_vdupd_lane_s64
+int64_t test_vdupd_lane_s64(int64x1_t a) {
+ return vdupd_lane_s64(a, 0);
+// CHECK: fmov {{x[0-9]+}}, {{d[0-9]+}}
+}
+
+
+// CHECK: test_vdupb_lane_u8
+uint8_t test_vdupb_lane_u8(uint8x8_t a) {
+ return vdupb_lane_u8(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+
+// CHECK: test_vduph_lane_u16
+uint16_t test_vduph_lane_u16(uint16x4_t a) {
+ return vduph_lane_u16(a, 3);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+
+// CHECK: test_vdups_lane_u32
+uint32_t test_vdups_lane_u32(uint32x2_t a) {
+ return vdups_lane_u32(a, 1);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+
+// CHECK: test_vdupd_lane_u64
+uint64_t test_vdupd_lane_u64(uint64x1_t a) {
+ return vdupd_lane_u64(a, 0);
+// CHECK: fmov {{x[0-9]+}}, {{d[0-9]+}}
+}
+
+// CHECK: test_vdupb_laneq_s8
+int8_t test_vdupb_laneq_s8(int8x16_t a) {
+ return vdupb_laneq_s8(a, 15);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[15]
+}
+
+
+// CHECK: test_vduph_laneq_s16
+int16_t test_vduph_laneq_s16(int16x8_t a) {
+ return vduph_laneq_s16(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+
+// CHECK: test_vdups_laneq_s32
+int32_t test_vdups_laneq_s32(int32x4_t a) {
+ return vdups_laneq_s32(a, 3);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+
+// CHECK: test_vdupd_laneq_s64
+int64_t test_vdupd_laneq_s64(int64x2_t a) {
+ return vdupd_laneq_s64(a, 1);
+// CHECK: umov {{x[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+
+// CHECK: test_vdupb_laneq_u8
+uint8_t test_vdupb_laneq_u8(uint8x16_t a) {
+ return vdupb_laneq_u8(a, 15);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[15]
+}
+
+
+// CHECK: test_vduph_laneq_u16
+uint16_t test_vduph_laneq_u16(uint16x8_t a) {
+ return vduph_laneq_u16(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+
+// CHECK: test_vdups_laneq_u32
+uint32_t test_vdups_laneq_u32(uint32x4_t a) {
+ return vdups_laneq_u32(a, 3);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+
+// CHECK: test_vdupd_laneq_u64
+uint64_t test_vdupd_laneq_u64(uint64x2_t a) {
+ return vdupd_laneq_u64(a, 1);
+// CHECK: umov {{x[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vdupb_lane_p8
+poly8_t test_vdupb_lane_p8(poly8x8_t a) {
+ return vdupb_lane_p8(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[7]
+}
+
+// CHECK: test_vduph_lane_p16
+poly16_t test_vduph_lane_p16(poly16x4_t a) {
+ return vduph_lane_p16(a, 3);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vdupb_laneq_p8
+poly8_t test_vdupb_laneq_p8(poly8x16_t a) {
+ return vdupb_laneq_p8(a, 15);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.b[15]
+}
+
+// CHECK: test_vduph_laneq_p16
+poly16_t test_vduph_laneq_p16(poly16x8_t a) {
+ return vduph_laneq_p16(a, 7);
+// CHECK: umov {{w[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
diff --git a/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
new file mode 100644
index 000000000000..4f0771ad276e
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
@@ -0,0 +1,255 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+
+float32_t test_vmuls_lane_f32(float32_t a, float32x2_t b) {
+ // CHECK: test_vmuls_lane_f32
+ return vmuls_lane_f32(a, b, 1);
+ // CHECK: fmul {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+float64_t test_vmuld_lane_f64(float64_t a, float64x1_t b) {
+ // CHECK: test_vmuld_lane_f64
+ return vmuld_lane_f64(a, b, 0);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+float32_t test_vmuls_laneq_f32(float32_t a, float32x4_t b) {
+ // CHECK: test_vmuls_laneq_f32
+ return vmuls_laneq_f32(a, b, 3);
+ // CHECK: fmul {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+float64_t test_vmuld_laneq_f64(float64_t a, float64x2_t b) {
+ // CHECK: test_vmuld_laneq_f64
+ return vmuld_laneq_f64(a, b, 1);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+float64x1_t test_vmul_n_f64(float64x1_t a, float64_t b) {
+ // CHECK: test_vmul_n_f64
+ return vmul_n_f64(a, b);
+ // CHECK: fmul {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+float32_t test_vmulxs_lane_f32(float32_t a, float32x2_t b) {
+// CHECK: test_vmulxs_lane_f32
+ return vmulxs_lane_f32(a, b, 1);
+// CHECK: fmulx {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+float32_t test_vmulxs_laneq_f32(float32_t a, float32x4_t b) {
+// CHECK: test_vmulxs_laneq_f32
+ return vmulxs_laneq_f32(a, b, 3);
+// CHECK: fmulx {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+float64_t test_vmulxd_lane_f64(float64_t a, float64x1_t b) {
+// CHECK: test_vmulxd_lane_f64
+ return vmulxd_lane_f64(a, b, 0);
+// CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+float64_t test_vmulxd_laneq_f64(float64_t a, float64x2_t b) {
+// CHECK: test_vmulxd_laneq_f64
+ return vmulxd_laneq_f64(a, b, 1);
+// CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vmulx_lane_f64
+float64x1_t test_vmulx_lane_f64(float64x1_t a, float64x1_t b) {
+ return vmulx_lane_f64(a, b, 0);
+ // CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+
+// CHECK: test_vmulx_laneq_f64_0
+float64x1_t test_vmulx_laneq_f64_0(float64x1_t a, float64x2_t b) {
+ return vmulx_laneq_f64(a, b, 0);
+ // CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vmulx_laneq_f64_1
+float64x1_t test_vmulx_laneq_f64_1(float64x1_t a, float64x2_t b) {
+ return vmulx_laneq_f64(a, b, 1);
+ // CHECK: fmulx {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+
+// CHECK: test_vfmas_lane_f32
+float32_t test_vfmas_lane_f32(float32_t a, float32_t b, float32x2_t c) {
+ return vfmas_lane_f32(a, b, c, 1);
+ // CHECK: fmla {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+// CHECK: test_vfmad_lane_f64
+float64_t test_vfmad_lane_f64(float64_t a, float64_t b, float64x1_t c) {
+ return vfmad_lane_f64(a, b, c, 0);
+ // CHECK: fmla {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vfmad_laneq_f64
+float64_t test_vfmad_laneq_f64(float64_t a, float64_t b, float64x2_t c) {
+ return vfmad_laneq_f64(a, b, c, 1);
+ // CHECK: fmla {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+// CHECK: test_vfmss_lane_f32
+float32_t test_vfmss_lane_f32(float32_t a, float32_t b, float32x2_t c) {
+ return vfmss_lane_f32(a, b, c, 1);
+ // CHECK: fmls {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+// CHECK: test_vfma_lane_f64
+float64x1_t test_vfma_lane_f64(float64x1_t a, float64x1_t b, float64x1_t v) {
+ return vfma_lane_f64(a, b, v, 0);
+ // CHECK: fmla {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vfms_lane_f64
+float64x1_t test_vfms_lane_f64(float64x1_t a, float64x1_t b, float64x1_t v) {
+ return vfms_lane_f64(a, b, v, 0);
+ // CHECK: fmls {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vfma_laneq_f64
+float64x1_t test_vfma_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) {
+ return vfma_laneq_f64(a, b, v, 0);
+ // CHECK: fmla {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vfms_laneq_f64
+float64x1_t test_vfms_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) {
+ return vfms_laneq_f64(a, b, v, 0);
+ // CHECK: fmls {{d[0-9]+}}, {{d[0-9]+}}, {{v[0-9]+}}.d[0]
+}
+
+// CHECK: test_vqdmullh_lane_s16
+int32_t test_vqdmullh_lane_s16(int16_t a, int16x4_t b) {
+ return vqdmullh_lane_s16(a, b, 3);
+ // CHECK: sqdmull {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vqdmulls_lane_s32
+int64_t test_vqdmulls_lane_s32(int32_t a, int32x2_t b) {
+ return vqdmulls_lane_s32(a, b, 1);
+ // CHECK: sqdmull {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+// CHECK: test_vqdmullh_laneq_s16
+int32_t test_vqdmullh_laneq_s16(int16_t a, int16x8_t b) {
+ return vqdmullh_laneq_s16(a, b, 7);
+ // CHECK: sqdmull {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+// CHECK: test_vqdmulls_laneq_s32
+int64_t test_vqdmulls_laneq_s32(int32_t a, int32x4_t b) {
+ return vqdmulls_laneq_s32(a, b, 3);
+ // CHECK: sqdmull {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+// CHECK: test_vqdmulhh_lane_s16
+int16_t test_vqdmulhh_lane_s16(int16_t a, int16x4_t b) {
+ return vqdmulhh_lane_s16(a, b, 3);
+// CHECK: sqdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vqdmulhs_lane_s32
+int32_t test_vqdmulhs_lane_s32(int32_t a, int32x2_t b) {
+ return vqdmulhs_lane_s32(a, b, 1);
+// CHECK: sqdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+
+// CHECK: test_vqdmulhh_laneq_s16
+int16_t test_vqdmulhh_laneq_s16(int16_t a, int16x8_t b) {
+ return vqdmulhh_laneq_s16(a, b, 7);
+// CHECK: sqdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+
+// CHECK: test_vqdmulhs_laneq_s32
+int32_t test_vqdmulhs_laneq_s32(int32_t a, int32x4_t b) {
+ return vqdmulhs_laneq_s32(a, b, 3);
+// CHECK: sqdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+// CHECK: test_vqrdmulhh_lane_s16
+int16_t test_vqrdmulhh_lane_s16(int16_t a, int16x4_t b) {
+ return vqrdmulhh_lane_s16(a, b, 3);
+// CHECK: sqrdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vqrdmulhs_lane_s32
+int32_t test_vqrdmulhs_lane_s32(int32_t a, int32x2_t b) {
+ return vqrdmulhs_lane_s32(a, b, 1);
+// CHECK: sqrdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+
+// CHECK: test_vqrdmulhh_laneq_s16
+int16_t test_vqrdmulhh_laneq_s16(int16_t a, int16x8_t b) {
+ return vqrdmulhh_laneq_s16(a, b, 7);
+// CHECK: sqrdmulh {{h[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+
+// CHECK: test_vqrdmulhs_laneq_s32
+int32_t test_vqrdmulhs_laneq_s32(int32_t a, int32x4_t b) {
+ return vqrdmulhs_laneq_s32(a, b, 3);
+// CHECK: sqrdmulh {{s[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+// CHECK: test_vqdmlalh_lane_s16
+int32_t test_vqdmlalh_lane_s16(int32_t a, int16_t b, int16x4_t c) {
+ return vqdmlalh_lane_s16(a, b, c, 3);
+// CHECK: sqdmlal {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vqdmlals_lane_s32
+int64_t test_vqdmlals_lane_s32(int64_t a, int32_t b, int32x2_t c) {
+ return vqdmlals_lane_s32(a, b, c, 1);
+// CHECK: sqdmlal {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+// CHECK: test_vqdmlalh_laneq_s16
+int32_t test_vqdmlalh_laneq_s16(int32_t a, int16_t b, int16x8_t c) {
+ return vqdmlalh_laneq_s16(a, b, c, 7);
+// CHECK: sqdmlal {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+// CHECK: test_vqdmlals_laneq_s32
+int64_t test_vqdmlals_laneq_s32(int64_t a, int32_t b, int32x4_t c) {
+ return vqdmlals_laneq_s32(a, b, c, 3);
+// CHECK: sqdmlal {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
+// CHECK: test_vqdmlslh_lane_s16
+int32_t test_vqdmlslh_lane_s16(int32_t a, int16_t b, int16x4_t c) {
+ return vqdmlslh_lane_s16(a, b, c, 3);
+// CHECK: sqdmlsl {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[3]
+}
+
+// CHECK: test_vqdmlsls_lane_s32
+int64_t test_vqdmlsls_lane_s32(int64_t a, int32_t b, int32x2_t c) {
+ return vqdmlsls_lane_s32(a, b, c, 1);
+// CHECK: sqdmlsl {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[1]
+}
+
+// CHECK: test_vqdmlslh_laneq_s16
+int32_t test_vqdmlslh_laneq_s16(int32_t a, int16_t b, int16x8_t c) {
+ return vqdmlslh_laneq_s16(a, b, c, 7);
+// CHECK: sqdmlsl {{s[0-9]+}}, {{h[0-9]+}}, {{v[0-9]+}}.h[7]
+}
+
+// CHECK: test_vqdmlsls_laneq_s32
+int64_t test_vqdmlsls_laneq_s32(int64_t a, int32_t b, int32x4_t c) {
+ return vqdmlsls_laneq_s32(a, b, c, 3);
+// CHECK: sqdmlsl {{d[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}.s[3]
+}
+
diff --git a/test/CodeGen/aarch64-neon-shifts.c b/test/CodeGen/aarch64-neon-shifts.c
new file mode 100644
index 000000000000..4777f18aae7f
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-shifts.c
@@ -0,0 +1,43 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -emit-llvm -O1 -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+uint8x8_t test_shift_vshr(uint8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr
+ // CHECK: %{{.*}} = lshr <8 x i8> %a, <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+ return vshr_n_u8(a, 5);
+}
+
+int8x8_t test_shift_vshr_smax(int8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr_smax
+ // CHECK: %{{.*}} = ashr <8 x i8> %a, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ return vshr_n_s8(a, 8);
+}
+
+uint8x8_t test_shift_vshr_umax(uint8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr_umax
+ // CHECK: ret <8 x i8> zeroinitializer
+ return vshr_n_u8(a, 8);
+}
+
+uint8x8_t test_shift_vsra(uint8x8_t a, uint8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra
+ // CHECK: %[[SHR:.*]] = lshr <8 x i8> %b, <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+ // CHECK: %{{.*}} = add <8 x i8> %[[SHR]], %a
+ return vsra_n_u8(a, b, 5);
+}
+
+int8x8_t test_shift_vsra_smax(int8x8_t a, int8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra_smax
+ // CHECK: %[[SHR:.*]] = ashr <8 x i8> %b, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ // CHECK: %{{.*}} = add <8 x i8> %[[SHR]], %a
+ return vsra_n_s8(a, b, 8);
+}
+
+uint8x8_t test_shift_vsra_umax(uint8x8_t a, uint8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra_umax
+ // CHECK: ret <8 x i8> %a
+ return vsra_n_u8(a, b, 8);
+}
diff --git a/test/CodeGen/aarch64-neon-tbl.c b/test/CodeGen/aarch64-neon-tbl.c
new file mode 100644
index 000000000000..db78a7aa7037
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-tbl.c
@@ -0,0 +1,463 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x8_t test_vtbl1_s8(int8x8_t a, int8x8_t b) {
+ // CHECK: test_vtbl1_s8
+ return vtbl1_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbl1_s8(int8x16_t a, int8x8_t b) {
+ // CHECK: test_vqtbl1_s8
+ return vqtbl1_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbl2_s8(int8x8x2_t a, int8x8_t b) {
+ // CHECK: test_vtbl2_s8
+ return vtbl2_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbl2_s8(int8x16x2_t a, int8x8_t b) {
+ // CHECK: test_vqtbl2_s8
+ return vqtbl2_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbl3_s8(int8x8x3_t a, int8x8_t b) {
+ // CHECK: test_vtbl3_s8
+ return vtbl3_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbl3_s8(int8x16x3_t a, int8x8_t b) {
+ // CHECK: test_vqtbl3_s8
+ return vqtbl3_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbl4_s8(int8x8x4_t a, int8x8_t b) {
+ // CHECK: test_vtbl4_s8
+ return vtbl4_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbl4_s8(int8x16x4_t a, int8x8_t b) {
+ // CHECK: test_vqtbl4_s8
+ return vqtbl4_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vqtbl1q_s8(int8x16_t a, int8x16_t b) {
+ // CHECK: test_vqtbl1q_s8
+ return vqtbl1q_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbl2q_s8(int8x16x2_t a, int8x16_t b) {
+ // CHECK: test_vqtbl2q_s8
+ return vqtbl2q_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbl3q_s8(int8x16x3_t a, int8x16_t b) {
+ // CHECK: test_vqtbl3q_s8
+ return vqtbl3q_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbl4q_s8(int8x16x4_t a, int8x16_t b) {
+ // CHECK: test_vqtbl4q_s8
+ return vqtbl4q_s8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x8_t test_vtbx1_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
+ // CHECK: test_vtbx1_s8
+ return vtbx1_s8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbx2_s8(int8x8_t a, int8x8x2_t b, int8x8_t c) {
+ // CHECK: test_vtbx2_s8
+ return vtbx2_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbx3_s8(int8x8_t a, int8x8x3_t b, int8x8_t c) {
+ // CHECK: test_vtbx3_s8
+ return vtbx3_s8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vtbx4_s8(int8x8_t a, int8x8x4_t b, int8x8_t c) {
+ // CHECK: test_vtbx4_s8
+ return vtbx4_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbx1_s8(int8x8_t a, int8x16_t b, int8x8_t c) {
+ // CHECK: test_vqtbx1_s8
+ return vqtbx1_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbx2_s8(int8x8_t a, int8x16x2_t b, int8x8_t c) {
+ // CHECK: test_vqtbx2_s8
+ return vqtbx2_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbx3_s8(int8x8_t a, int8x16x3_t b, int8x8_t c) {
+ // CHECK: test_vqtbx3_s8
+ return vqtbx3_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x8_t test_vqtbx4_s8(int8x8_t a, int8x16x4_t b, int8x8_t c) {
+ // CHECK: test_vqtbx4_s8
+ return vqtbx4_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+int8x16_t test_vqtbx1q_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
+ // CHECK: test_vqtbx1q_s8
+ return vqtbx1q_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbx2q_s8(int8x16_t a, int8x16x2_t b, int8x16_t c) {
+ // CHECK: test_vqtbx2q_s8
+ return vqtbx2q_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbx3q_s8(int8x16_t a, int8x16x3_t b, int8x16_t c) {
+ // CHECK: test_vqtbx3q_s8
+ return vqtbx3q_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+int8x16_t test_vqtbx4q_s8(int8x16_t a, int8x16x4_t b, int8x16_t c) {
+ // CHECK: test_vqtbx4q_s8
+ return vqtbx4q_s8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x8_t test_vtbl1_u8(uint8x8_t a, uint8x8_t b) {
+ // CHECK: test_vtbl1_u8
+ return vtbl1_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbl1_u8(uint8x16_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl1_u8
+ return vqtbl1_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbl2_u8(uint8x8x2_t a, uint8x8_t b) {
+ // CHECK: test_vtbl2_u8
+ return vtbl2_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbl2_u8(uint8x16x2_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl2_u8
+ return vqtbl2_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbl3_u8(uint8x8x3_t a, uint8x8_t b) {
+ // CHECK: test_vtbl3_u8
+ return vtbl3_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbl3_u8(uint8x16x3_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl3_u8
+ return vqtbl3_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbl4_u8(uint8x8x4_t a, uint8x8_t b) {
+ // CHECK: test_vtbl4_u8
+ return vtbl4_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbl4_u8(uint8x16x4_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl4_u8
+ return vqtbl4_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vqtbl1q_u8(uint8x16_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl1q_u8
+ return vqtbl1q_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbl2q_u8(uint8x16x2_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl2q_u8
+ return vqtbl2q_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbl3q_u8(uint8x16x3_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl3q_u8
+ return vqtbl3q_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbl4q_u8(uint8x16x4_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl4q_u8
+ return vqtbl4q_u8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x8_t test_vtbx1_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ // CHECK: test_vtbx1_u8
+ return vtbx1_u8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbx2_u8(uint8x8_t a, uint8x8x2_t b, uint8x8_t c) {
+ // CHECK: test_vtbx2_u8
+ return vtbx2_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbx3_u8(uint8x8_t a, uint8x8x3_t b, uint8x8_t c) {
+ // CHECK: test_vtbx3_u8
+ return vtbx3_u8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vtbx4_u8(uint8x8_t a, uint8x8x4_t b, uint8x8_t c) {
+ // CHECK: test_vtbx4_u8
+ return vtbx4_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbx1_u8(uint8x8_t a, uint8x16_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx1_u8
+ return vqtbx1_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbx2_u8(uint8x8_t a, uint8x16x2_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx2_u8
+ return vqtbx2_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbx3_u8(uint8x8_t a, uint8x16x3_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx3_u8
+ return vqtbx3_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x8_t test_vqtbx4_u8(uint8x8_t a, uint8x16x4_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx4_u8
+ return vqtbx4_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+uint8x16_t test_vqtbx1q_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx1q_u8
+ return vqtbx1q_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbx2q_u8(uint8x16_t a, uint8x16x2_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx2q_u8
+ return vqtbx2q_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbx3q_u8(uint8x16_t a, uint8x16x3_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx3q_u8
+ return vqtbx3q_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+uint8x16_t test_vqtbx4q_u8(uint8x16_t a, uint8x16x4_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx4q_u8
+ return vqtbx4q_u8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x8_t test_vtbl1_p8(poly8x8_t a, uint8x8_t b) {
+ // CHECK: test_vtbl1_p8
+ return vtbl1_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbl1_p8(poly8x16_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl1_p8
+ return vqtbl1_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbl2_p8(poly8x8x2_t a, uint8x8_t b) {
+ // CHECK: test_vtbl2_p8
+ return vtbl2_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbl2_p8(poly8x16x2_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl2_p8
+ return vqtbl2_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbl3_p8(poly8x8x3_t a, uint8x8_t b) {
+ // CHECK: test_vtbl3_p8
+ return vtbl3_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbl3_p8(poly8x16x3_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl3_p8
+ return vqtbl3_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbl4_p8(poly8x8x4_t a, uint8x8_t b) {
+ // CHECK: test_vtbl4_p8
+ return vtbl4_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbl4_p8(poly8x16x4_t a, uint8x8_t b) {
+ // CHECK: test_vqtbl4_p8
+ return vqtbl4_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vqtbl1q_p8(poly8x16_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl1q_p8
+ return vqtbl1q_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbl2q_p8(poly8x16x2_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl2q_p8
+ return vqtbl2q_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbl3q_p8(poly8x16x3_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl3q_p8
+ return vqtbl3q_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbl4q_p8(poly8x16x4_t a, uint8x16_t b) {
+ // CHECK: test_vqtbl4q_p8
+ return vqtbl4q_p8(a, b);
+ // CHECK: tbl {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x8_t test_vtbx1_p8(poly8x8_t a, poly8x8_t b, uint8x8_t c) {
+ // CHECK: test_vtbx1_p8
+ return vtbx1_p8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbx2_p8(poly8x8_t a, poly8x8x2_t b, uint8x8_t c) {
+ // CHECK: test_vtbx2_p8
+ return vtbx2_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbx3_p8(poly8x8_t a, poly8x8x3_t b, uint8x8_t c) {
+ // CHECK: test_vtbx3_p8
+ return vtbx3_p8(a, b, c);
+ // CHECK: movi {{v[0-9]+}}.8b, #0
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: tbl {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+ // CHECK: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) {
+ // CHECK: test_vtbx4_p8
+ return vtbx4_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbx1_p8(poly8x8_t a, uint8x16_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx1_p8
+ return vqtbx1_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbx2_p8(poly8x8_t a, poly8x16x2_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx2_p8
+ return vqtbx2_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbx3_p8(poly8x8_t a, poly8x16x3_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx3_p8
+ return vqtbx3_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x8_t test_vqtbx4_p8(poly8x8_t a, poly8x16x4_t b, uint8x8_t c) {
+ // CHECK: test_vqtbx4_p8
+ return vqtbx4_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.8b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.8b
+}
+
+poly8x16_t test_vqtbx1q_p8(poly8x16_t a, uint8x16_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx1q_p8
+ return vqtbx1q_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbx2q_p8(poly8x16_t a, poly8x16x2_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx2q_p8
+ return vqtbx2q_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbx3q_p8(poly8x16_t a, poly8x16x3_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx3q_p8
+ return vqtbx3q_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
+
+poly8x16_t test_vqtbx4q_p8(poly8x16_t a, poly8x16x4_t b, uint8x16_t c) {
+ // CHECK: test_vqtbx4q_p8
+ return vqtbx4q_p8(a, b, c);
+ // CHECK: tbx {{v[0-9]+}}.16b, {{{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b}, {{v[0-9]+}}.16b
+}
diff --git a/test/CodeGen/aarch64-neon-vcombine.c b/test/CodeGen/aarch64-neon-vcombine.c
new file mode 100644
index 000000000000..3e170c8c4c9f
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-vcombine.c
@@ -0,0 +1,91 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x16_t test_vcombine_s8(int8x8_t low, int8x8_t high) {
+ // CHECK-LABEL: test_vcombine_s8:
+ return vcombine_s8(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+int16x8_t test_vcombine_s16(int16x4_t low, int16x4_t high) {
+ // CHECK-LABEL: test_vcombine_s16:
+ return vcombine_s16(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+int32x4_t test_vcombine_s32(int32x2_t low, int32x2_t high) {
+ // CHECK-LABEL: test_vcombine_s32:
+ return vcombine_s32(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+int64x2_t test_vcombine_s64(int64x1_t low, int64x1_t high) {
+ // CHECK-LABEL: test_vcombine_s64:
+ return vcombine_s64(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+uint8x16_t test_vcombine_u8(uint8x8_t low, uint8x8_t high) {
+ // CHECK-LABEL: test_vcombine_u8:
+ return vcombine_u8(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+uint16x8_t test_vcombine_u16(uint16x4_t low, uint16x4_t high) {
+ // CHECK-LABEL: test_vcombine_u16:
+ return vcombine_u16(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+uint32x4_t test_vcombine_u32(uint32x2_t low, uint32x2_t high) {
+ // CHECK-LABEL: test_vcombine_u32:
+ return vcombine_u32(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+uint64x2_t test_vcombine_u64(uint64x1_t low, uint64x1_t high) {
+ // CHECK-LABEL: test_vcombine_u64:
+ return vcombine_u64(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+poly64x2_t test_vcombine_p64(poly64x1_t low, poly64x1_t high) {
+ // CHECK-LABEL: test_vcombine_p64:
+ return vcombine_p64(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+float16x8_t test_vcombine_f16(float16x4_t low, float16x4_t high) {
+ // CHECK-LABEL: test_vcombine_f16:
+ return vcombine_f16(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+float32x4_t test_vcombine_f32(float32x2_t low, float32x2_t high) {
+ // CHECK-LABEL: test_vcombine_f32:
+ return vcombine_f32(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+poly8x16_t test_vcombine_p8(poly8x8_t low, poly8x8_t high) {
+ // CHECK-LABEL: test_vcombine_p8:
+ return vcombine_p8(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+poly16x8_t test_vcombine_p16(poly16x4_t low, poly16x4_t high) {
+ // CHECK-LABEL: test_vcombine_p16:
+ return vcombine_p16(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
+
+float64x2_t test_vcombine_f64(float64x1_t low, float64x1_t high) {
+ // CHECK-LABEL: test_vcombine_f64:
+ return vcombine_f64(low, high);
+ // CHECK: ins v0.d[1], v1.d[0]
+}
diff --git a/test/CodeGen/aarch64-neon-vget-hilo.c b/test/CodeGen/aarch64-neon-vget-hilo.c
new file mode 100644
index 000000000000..012b0bbb964a
--- /dev/null
+++ b/test/CodeGen/aarch64-neon-vget-hilo.c
@@ -0,0 +1,176 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics and types
+
+#include <arm_neon.h>
+
+int8x8_t test_vget_high_s8(int8x16_t a) {
+ // CHECK-LABEL: test_vget_high_s8:
+ return vget_high_s8(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+int16x4_t test_vget_high_s16(int16x8_t a) {
+ // CHECK-LABEL: test_vget_high_s16:
+ return vget_high_s16(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+int32x2_t test_vget_high_s32(int32x4_t a) {
+ // CHECK-LABEL: test_vget_high_s32:
+ return vget_high_s32(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+int64x1_t test_vget_high_s64(int64x2_t a) {
+ // CHECK-LABEL: test_vget_high_s64:
+ return vget_high_s64(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+uint8x8_t test_vget_high_u8(uint8x16_t a) {
+ // CHECK-LABEL: test_vget_high_u8:
+ return vget_high_u8(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+uint16x4_t test_vget_high_u16(uint16x8_t a) {
+ // CHECK-LABEL: test_vget_high_u16:
+ return vget_high_u16(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+uint32x2_t test_vget_high_u32(uint32x4_t a) {
+ // CHECK-LABEL: test_vget_high_u32:
+ return vget_high_u32(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+uint64x1_t test_vget_high_u64(uint64x2_t a) {
+ // CHECK-LABEL: test_vget_high_u64:
+ return vget_high_u64(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+poly64x1_t test_vget_high_p64(poly64x2_t a) {
+ // CHECK-LABEL: test_vget_high_p64:
+ return vget_high_p64(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+float16x4_t test_vget_high_f16(float16x8_t a) {
+ // CHECK-LABEL: test_vget_high_f16:
+ return vget_high_f16(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+float32x2_t test_vget_high_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vget_high_f32:
+ return vget_high_f32(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+poly8x8_t test_vget_high_p8(poly8x16_t a) {
+ // CHECK-LABEL: test_vget_high_p8:
+ return vget_high_p8(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+poly16x4_t test_vget_high_p16(poly16x8_t a) {
+ // CHECK-LABEL: test_vget_high_p16
+ return vget_high_p16(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+float64x1_t test_vget_high_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vget_high_f64
+ return vget_high_f64(a);
+ // CHECK: dup d0, {{v[0-9]+}}.d[1]
+}
+
+int8x8_t test_vget_low_s8(int8x16_t a) {
+ // CHECK-LABEL: test_vget_low_s8:
+ return vget_low_s8(a);
+ // CHECK-NEXT: ret
+}
+
+int16x4_t test_vget_low_s16(int16x8_t a) {
+ // CHECK-LABEL: test_vget_low_s16:
+ return vget_low_s16(a);
+ // CHECK-NEXT: ret
+}
+
+int32x2_t test_vget_low_s32(int32x4_t a) {
+ // CHECK-LABEL: test_vget_low_s32:
+ return vget_low_s32(a);
+ // CHECK-NEXT: ret
+}
+
+int64x1_t test_vget_low_s64(int64x2_t a) {
+ // CHECK-LABEL: test_vget_low_s64:
+ return vget_low_s64(a);
+ // CHECK-NEXT: ret
+}
+
+uint8x8_t test_vget_low_u8(uint8x16_t a) {
+ // CHECK-LABEL: test_vget_low_u8:
+ return vget_low_u8(a);
+ // CHECK-NEXT: ret
+}
+
+uint16x4_t test_vget_low_u16(uint16x8_t a) {
+ // CHECK-LABEL: test_vget_low_u16:
+ return vget_low_u16(a);
+ // CHECK-NEXT: ret
+}
+
+uint32x2_t test_vget_low_u32(uint32x4_t a) {
+ // CHECK-LABEL: test_vget_low_u32:
+ return vget_low_u32(a);
+ // CHECK-NEXT: ret
+}
+
+uint64x1_t test_vget_low_u64(uint64x2_t a) {
+ // CHECK-LABEL: test_vget_low_u64:
+ return vget_low_u64(a);
+ // CHECK-NEXT: ret
+}
+
+poly64x1_t test_vget_low_p64(poly64x2_t a) {
+ // CHECK-LABEL: test_vget_low_p64:
+ return vget_low_p64(a);
+ // CHECK-NEXT: ret
+}
+
+float16x4_t test_vget_low_f16(float16x8_t a) {
+ // CHECK-LABEL: test_vget_low_f16:
+ return vget_low_f16(a);
+ // CHECK-NEXT: ret
+}
+
+float32x2_t test_vget_low_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vget_low_f32:
+ return vget_low_f32(a);
+ // CHECK-NEXT: ret
+}
+
+poly8x8_t test_vget_low_p8(poly8x16_t a) {
+ // CHECK-LABEL: test_vget_low_p8:
+ return vget_low_p8(a);
+ // CHECK-NEXT: ret
+}
+
+poly16x4_t test_vget_low_p16(poly16x8_t a) {
+ // CHECK-LABEL: test_vget_low_p16:
+ return vget_low_p16(a);
+ // CHECK-NEXT: ret
+}
+
+float64x1_t test_vget_low_f64(float64x2_t a) {
+ // CHECK-LABEL: test_vget_low_f64:
+ return vget_low_f64(a);
+ // CHECK-NEXT: ret
+}
+
diff --git a/test/CodeGen/aarch64-poly64.c b/test/CodeGen/aarch64-poly64.c
new file mode 100644
index 000000000000..3e195019cd0a
--- /dev/null
+++ b/test/CodeGen/aarch64-poly64.c
@@ -0,0 +1,283 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test new aarch64 intrinsics with poly64
+
+#include <arm_neon.h>
+
+uint64x1_t test_vceq_p64(poly64x1_t a, poly64x1_t b) {
+ // CHECK: test_vceq_p64
+ return vceq_p64(a, b);
+ // CHECK: cmeq {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x2_t test_vceqq_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vceqq_p64
+ return vceqq_p64(a, b);
+ // CHECK: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+uint64x1_t test_vtst_p64(poly64x1_t a, poly64x1_t b) {
+ // CHECK: test_vtst_p64
+ return vtst_p64(a, b);
+ // CHECK: cmtst {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+uint64x2_t test_vtstq_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vtstq_p64
+ return vtstq_p64(a, b);
+ // CHECK: cmtst {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+}
+
+poly64x1_t test_vbsl_p64(poly64x1_t a, poly64x1_t b, poly64x1_t c) {
+ // CHECK: test_vbsl_p64
+ return vbsl_p64(a, b, c);
+ // CHECK: bsl {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
+}
+
+poly64x2_t test_vbslq_p64(poly64x2_t a, poly64x2_t b, poly64x2_t c) {
+ // CHECK: test_vbslq_p64
+ return vbslq_p64(a, b, c);
+ // CHECK: bsl {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
+}
+
+poly64_t test_vget_lane_p64(poly64x1_t v) {
+ // CHECK: test_vget_lane_p64
+ return vget_lane_p64(v, 0);
+ // CHECK: fmov {{x[0-9]+}}, {{d[0-9]+}}
+}
+
+poly64_t test_vgetq_lane_p64(poly64x2_t v) {
+ // CHECK: test_vgetq_lane_p64
+ return vgetq_lane_p64(v, 1);
+ // CHECK: umov {{x[0-9]+}}, {{v[0-9]+}}.d[1]
+}
+
+poly64x1_t test_vset_lane_p64(poly64_t a, poly64x1_t v) {
+ // CHECK: test_vset_lane_p64
+ return vset_lane_p64(a, v, 0);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+poly64x2_t test_vsetq_lane_p64(poly64_t a, poly64x2_t v) {
+ // CHECK: test_vsetq_lane_p64
+ return vsetq_lane_p64(a, v, 1);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{x[0-9]+}}
+}
+
+poly64x1_t test_vcopy_lane_p64(poly64x1_t a, poly64x1_t b) {
+ // CHECK: test_vcopy_lane_p64
+ return vcopy_lane_p64(a, 0, b, 0);
+ // CHECK: fmov {{d[0-9]+}}, {{d[0-9]+}}
+}
+
+poly64x2_t test_vcopyq_lane_p64(poly64x2_t a, poly64x1_t b) {
+ // CHECK: test_vcopyq_lane_p64
+ return vcopyq_lane_p64(a, 1, b, 0);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly64x2_t test_vcopyq_laneq_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vcopyq_laneq_p64
+ return vcopyq_laneq_p64(a, 1, b, 1);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[1]
+}
+
+poly64x1_t test_vcreate_p64(uint64_t a) {
+ // CHECK: test_vcreate_p64
+ return vcreate_p64(a);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+poly64x1_t test_vdup_n_p64(poly64_t a) {
+ // CHECK: test_vdup_n_p64
+ return vdup_n_p64(a);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+poly64x2_t test_vdupq_n_p64(poly64_t a) {
+ // CHECK: test_vdup_n_p64
+ return vdupq_n_p64(a);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
+poly64x1_t test_vdup_lane_p64(poly64x1_t vec) {
+ // CHECK: test_vdup_lane_p64
+ return vdup_lane_p64(vec, 0);
+ // CHECK: ret
+}
+
+poly64x2_t test_vdupq_lane_p64(poly64x1_t vec) {
+ // CHECK: test_vdupq_lane_p64
+ return vdupq_lane_p64(vec, 0);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[0]
+}
+
+poly64x2_t test_vdupq_laneq_p64(poly64x2_t vec) {
+ // CHECK: test_vdupq_laneq_p64
+ return vdupq_laneq_p64(vec, 1);
+ // CHECK: dup {{v[0-9]+}}.2d, {{v[0-9]+}}.d[1]
+}
+
+poly64x2_t test_vcombine_p64(poly64x1_t low, poly64x1_t high) {
+ // CHECK: test_vcombine_p64
+ return vcombine_p64(low, high);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly64x1_t test_vld1_p64(poly64_t const * ptr) {
+ // CHECK: test_vld1_p64
+ return vld1_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2_t test_vld1q_p64(poly64_t const * ptr) {
+ // CHECK: test_vld1q_p64
+ return vld1q_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1_p64(poly64_t * ptr, poly64x1_t val) {
+ // CHECK: test_vst1_p64
+ return vst1_p64(ptr, val);
+ // CHECK: st1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst1q_p64(poly64_t * ptr, poly64x2_t val) {
+ // CHECK: test_vst1q_p64
+ return vst1q_p64(ptr, val);
+ // CHECK: st1 {{{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x2_t test_vld2_p64(poly64_t const * ptr) {
+ // CHECK: test_vld2_p64
+ return vld2_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x2_t test_vld2q_p64(poly64_t const * ptr) {
+ // CHECK: test_vld2q_p64
+ return vld2q_p64(ptr);
+ // CHECK: ld2 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x3_t test_vld3_p64(poly64_t const * ptr) {
+ // CHECK: test_vld3_p64
+ return vld3_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x3_t test_vld3q_p64(poly64_t const * ptr) {
+ // CHECK: test_vld3q_p64
+ return vld3q_p64(ptr);
+ // CHECK: ld3 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1x4_t test_vld4_p64(poly64_t const * ptr) {
+ // CHECK: test_vld4_p64
+ return vld4_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x2x4_t test_vld4q_p64(poly64_t const * ptr) {
+ // CHECK: test_vld4q_p64
+ return vld4q_p64(ptr);
+ // CHECK: ld4 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2_p64(poly64_t * ptr, poly64x1x2_t val) {
+ // CHECK: test_vst2_p64
+ return vst2_p64(ptr, val);
+ // CHECK: st1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst2q_p64(poly64_t * ptr, poly64x2x2_t val) {
+ // CHECK: test_vst2q_p64
+ return vst2q_p64(ptr, val);
+ // CHECK: st2 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst3_p64(poly64_t * ptr, poly64x1x3_t val) {
+ // CHECK: test_vst3_p64
+ return vst3_p64(ptr, val);
+ // CHECK: st1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst3q_p64(poly64_t * ptr, poly64x2x3_t val) {
+ // CHECK: test_vst3q_p64
+ return vst3q_p64(ptr, val);
+ // CHECK: st3 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4_p64(poly64_t * ptr, poly64x1x4_t val) {
+ // CHECK: test_vst4_p64
+ return vst4_p64(ptr, val);
+ // CHECK: st1 {{{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d, {{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
+
+void test_vst4q_p64(poly64_t * ptr, poly64x2x4_t val) {
+ // CHECK: test_vst4q_p64
+ return vst4q_p64(ptr, val);
+ // CHECK: st4 {{{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+}
+
+poly64x1_t test_vext_p64(poly64x1_t a, poly64x1_t b) {
+ // CHECK: test_vext_p64
+ return vext_u64(a, b, 0);
+
+}
+
+poly64x2_t test_vextq_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vextq_p64
+ return vextq_p64(a, b, 1);
+ // CHECK: ext {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, #0x8
+}
+
+poly64x2_t test_vzip1q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vzip1q_p64
+ return vzip1q_p64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly64x2_t test_vzip2q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vzip2q_p64
+ return vzip2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly64x2_t test_vuzp1q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vuzp1q_p64
+ return vuzp1q_p64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly64x2_t test_vuzp2q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vuzp2q_p64
+ return vuzp2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly64x2_t test_vtrn1q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vtrn1q_p64
+ return vtrn1q_p64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+}
+
+poly64x2_t test_vtrn2q_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vtrn2q_p64
+ return vtrn2q_u64(a, b);
+ // CHECK: ins {{v[0-9]+}}.d[0], {{v[0-9]+}}.d[1]
+}
+
+poly64x1_t test_vsri_n_p64(poly64x1_t a, poly64x1_t b) {
+ // CHECK: test_vsri_n_p64
+ return vsri_n_p64(a, b, 33);
+ // CHECK: sri {{d[0-9]+}}, {{d[0-9]+}}, #33
+}
+
+poly64x2_t test_vsriq_n_p64(poly64x2_t a, poly64x2_t b) {
+ // CHECK: test_vsriq_n_p64
+ return vsriq_n_p64(a, b, 64);
+ // CHECK: sri {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #64
+}
+
diff --git a/test/CodeGen/aarch64-varargs.c b/test/CodeGen/aarch64-varargs.c
index 324a0708271f..3d9cd866e872 100644
--- a/test/CodeGen/aarch64-varargs.c
+++ b/test/CodeGen/aarch64-varargs.c
@@ -7,7 +7,7 @@
va_list the_list;
int simple_int(void) {
-// CHECK: define i32 @simple_int
+// CHECK-LABEL: define i32 @simple_int
return va_arg(the_list, int);
// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
@@ -39,7 +39,7 @@ int simple_int(void) {
}
__int128 aligned_int(void) {
-// CHECK: define i128 @aligned_int
+// CHECK-LABEL: define i128 @aligned_int
return va_arg(the_list, __int128);
// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
@@ -81,7 +81,7 @@ struct bigstruct {
};
struct bigstruct simple_indirect(void) {
-// CHECK: define void @simple_indirect
+// CHECK-LABEL: define void @simple_indirect
return va_arg(the_list, struct bigstruct);
// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
@@ -119,7 +119,7 @@ struct aligned_bigstruct {
};
struct aligned_bigstruct simple_aligned_indirect(void) {
-// CHECK: define void @simple_aligned_indirect
+// CHECK-LABEL: define void @simple_aligned_indirect
return va_arg(the_list, struct aligned_bigstruct);
// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
@@ -150,7 +150,7 @@ struct aligned_bigstruct simple_aligned_indirect(void) {
}
double simple_double(void) {
-// CHECK: define double @simple_double
+// CHECK-LABEL: define double @simple_double
return va_arg(the_list, double);
// CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
@@ -186,7 +186,7 @@ struct hfa {
};
struct hfa simple_hfa(void) {
-// CHECK: define %struct.hfa @simple_hfa
+// CHECK-LABEL: define %struct.hfa @simple_hfa
return va_arg(the_list, struct hfa);
// CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
@@ -226,7 +226,7 @@ struct hfa simple_hfa(void) {
}
void check_start(int n, ...) {
-// CHECK: define void @check_start(i32 %n, ...)
+// CHECK-LABEL: define void @check_start(i32 %n, ...)
va_list the_list;
va_start(the_list, n);
diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c
index 9de0670b1024..3e865fd3b775 100644
--- a/test/CodeGen/address-space.c
+++ b/test/CodeGen/address-space.c
@@ -9,11 +9,11 @@ int foo __attribute__((address_space(1)));
// CHECK: @ban = common addrspace(1) global
int ban[10] __attribute__((address_space(1)));
-// CHECK: define i32 @test1()
+// CHECK-LABEL: define i32 @test1()
// CHECK: load i32 addrspace(1)* @foo
int test1() { return foo; }
-// CHECK: define i32 @test2(i32 %i)
+// CHECK-LABEL: define i32 @test2(i32 %i)
// CHECK: load i32 addrspace(1)*
// CHECK-NEXT: ret i32
int test2(int i) { return ban[i]; }
@@ -21,7 +21,7 @@ int test2(int i) { return ban[i]; }
// Both A and B point into addrspace(2).
__attribute__((address_space(2))) int *A, *B;
-// CHECK: define void @test3()
+// CHECK-LABEL: define void @test3()
// CHECK: load i32 addrspace(2)** @B
// CHECK: load i32 addrspace(2)*
// CHECK: load i32 addrspace(2)** @A
@@ -35,7 +35,7 @@ typedef struct {
float aData[1];
} MyStruct;
-// CHECK: define void @test4(
+// CHECK-LABEL: define void @test4(
// CHECK: call void @llvm.memcpy.p0i8.p2i8
// CHECK: call void @llvm.memcpy.p2i8.p0i8
void test4(MyStruct __attribute__((address_space(2))) *pPtr) {
diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
index a8380a37c583..efa94b340bbd 100644
--- a/test/CodeGen/alias.c
+++ b/test/CodeGen/alias.c
@@ -8,18 +8,18 @@ static int bar1 = 42;
extern int g1;
extern int g1 __attribute((alias("g0")));
-// CHECKBASIC: @g1 = alias i32* @g0
+// CHECKBASIC-DAG: @g1 = alias i32* @g0
void f0(void) { }
extern void f1(void);
extern void f1(void) __attribute((alias("f0")));
-// CHECKBASIC: @f1 = alias void ()* @f0
+// CHECKBASIC-DAG: @f1 = alias void ()* @f0
// CHECKBASIC: define void @f0() [[NUW:#[0-9]+]] {
// Make sure that aliases cause referenced values to be emitted.
// PR3200
static inline int foo1() { return 0; }
-// CHECKBASIC: define internal i32 @foo1()
+// CHECKBASIC-LABEL: define internal i32 @foo1()
int foo() __attribute__((alias("foo1")));
int bar() __attribute__((alias("bar1")));
diff --git a/test/CodeGen/align-param.c b/test/CodeGen/align-param.c
index 8907f66409a1..78e57b5b1f8c 100644
--- a/test/CodeGen/align-param.c
+++ b/test/CodeGen/align-param.c
@@ -5,7 +5,7 @@
int test (long long x) {
return (int)x;
}
-// CHECK: define i32 @test
+// CHECK-LABEL: define i32 @test
// CHECK: alloca i64, align 8
@@ -14,5 +14,5 @@ struct X { int x,y,z,a; };
int test2(struct X x __attribute((aligned(16)))) {
return x.z;
}
-// CHECK: define i32 @test2
+// CHECK-LABEL: define i32 @test2
// CHECK: alloca %struct.X, align 16
diff --git a/test/CodeGen/align-x68_64.c b/test/CodeGen/align-x68_64.c
new file mode 100644
index 000000000000..cf128b43433e
--- /dev/null
+++ b/test/CodeGen/align-x68_64.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// PR5599
+
+void test1_f(void *);
+
+void test1_g(void) {
+ float x[4];
+ test1_f(x);
+}
+// CHECK: @test1_g
+// CHECK: alloca [4 x float], align 16
diff --git a/test/CodeGen/alignment.c b/test/CodeGen/alignment.c
index 98ea01be0920..04d6aaccc219 100644
--- a/test/CodeGen/alignment.c
+++ b/test/CodeGen/alignment.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
__attribute((aligned(16))) float a[128];
union {int a[4]; __attribute((aligned(16))) float b[4];} b;
@@ -6,7 +6,8 @@ union {int a[4]; __attribute((aligned(16))) float b[4];} b;
// CHECK: @a = {{.*}}zeroinitializer, align 16
// CHECK: @b = {{.*}}zeroinitializer, align 16
-
+long long int test5[1024];
+// CHECK-DAG: @test5 = common global [1024 x i64] zeroinitializer, align 8
// PR5279 - Reduced alignment on typedef.
typedef int myint __attribute__((aligned(1)));
diff --git a/test/CodeGen/annotations-var.c b/test/CodeGen/annotations-var.c
index b8ada9fc0f3e..da9e0b63eca3 100644
--- a/test/CodeGen/annotations-var.c
+++ b/test/CodeGen/annotations-var.c
@@ -31,7 +31,7 @@ int foo(int v __attribute__((annotate("param_ann_0"))) __attribute__((annotate("
void local(void) {
int localvar __attribute__((annotate("localvar_ann_0"))) __attribute__((annotate("localvar_ann_1"))) = 3;
-// LOCAL: define void @local()
+// LOCAL-LABEL: define void @local()
// LOCAL: [[LOCALVAR:%.*]] = alloca i32,
// LOCAL-NEXT: [[T0:%.*]] = bitcast i32* [[LOCALVAR]] to i8*
// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33)
@@ -41,7 +41,7 @@ void local(void) {
void undef(void) {
int undefvar __attribute__((annotate("undefvar_ann_0")));
-// UNDEF: define void @undef()
+// UNDEF-LABEL: define void @undef()
// UNDEF: [[UNDEFVAR:%.*]] = alloca i32,
// UNDEF-NEXT: [[T0:%.*]] = bitcast i32* [[UNDEFVAR]] to i8*
// UNDEF-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 43)
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index 7210229f377b..0e102f35ed05 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -95,6 +95,6 @@ void test_neon(struct neon_struct arg) {
neon_callee(arg);
}
-// CHECK: define arm_aapcs_vfpcc void @f33(%struct.s33* byval %s)
+// CHECK-LABEL: define arm_aapcs_vfpcc void @f33(%struct.s33* byval %s)
struct s33 { char buf[32*32]; };
void f33(struct s33 s) { }
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 63ecd4c5990b..b6bac9ac44af 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -1,78 +1,78 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -triple armv7-apple-darwin9 -target-abi apcs-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=APCS-GNU %s
-// RUN: %clang_cc1 -triple armv7-apple-darwin9 -target-abi aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=AAPCS %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -target-feature +neon -target-abi apcs-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=APCS-GNU %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -target-feature +neon -target-abi aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=AAPCS %s
-// APCS-GNU: define signext i8 @f0()
-// AAPCS: define arm_aapcscc signext i8 @f0()
+// APCS-GNU-LABEL: define signext i8 @f0()
+// AAPCS-LABEL: define arm_aapcscc signext i8 @f0()
char f0(void) {
return 0;
}
-// APCS-GNU: define i8 @f1()
-// AAPCS: define arm_aapcscc i8 @f1()
+// APCS-GNU-LABEL: define i8 @f1()
+// AAPCS-LABEL: define arm_aapcscc i8 @f1()
struct s1 { char f0; };
struct s1 f1(void) {}
-// APCS-GNU: define i16 @f2()
-// AAPCS: define arm_aapcscc i16 @f2()
+// APCS-GNU-LABEL: define i16 @f2()
+// AAPCS-LABEL: define arm_aapcscc i16 @f2()
struct s2 { short f0; };
struct s2 f2(void) {}
-// APCS-GNU: define i32 @f3()
-// AAPCS: define arm_aapcscc i32 @f3()
+// APCS-GNU-LABEL: define i32 @f3()
+// AAPCS-LABEL: define arm_aapcscc i32 @f3()
struct s3 { int f0; };
struct s3 f3(void) {}
-// APCS-GNU: define i32 @f4()
-// AAPCS: define arm_aapcscc i32 @f4()
+// APCS-GNU-LABEL: define i32 @f4()
+// AAPCS-LABEL: define arm_aapcscc i32 @f4()
struct s4 { struct s4_0 { int f0; } f0; };
struct s4 f4(void) {}
-// APCS-GNU: define void @f5(
+// APCS-GNU-LABEL: define void @f5(
// APCS-GNU: struct.s5* noalias sret
-// AAPCS: define arm_aapcscc i32 @f5()
+// AAPCS-LABEL: define arm_aapcscc i32 @f5()
struct s5 { struct { } f0; int f1; };
struct s5 f5(void) {}
-// APCS-GNU: define void @f6(
+// APCS-GNU-LABEL: define void @f6(
// APCS-GNU: struct.s6* noalias sret
-// AAPCS: define arm_aapcscc i32 @f6()
+// AAPCS-LABEL: define arm_aapcscc i32 @f6()
struct s6 { int f0[1]; };
struct s6 f6(void) {}
-// APCS-GNU: define void @f7()
-// AAPCS: define arm_aapcscc void @f7()
+// APCS-GNU-LABEL: define void @f7()
+// AAPCS-LABEL: define arm_aapcscc void @f7()
struct s7 { struct { int : 0; } f0; };
struct s7 f7(void) {}
-// APCS-GNU: define void @f8(
+// APCS-GNU-LABEL: define void @f8(
// APCS-GNU: struct.s8* noalias sret
-// AAPCS: define arm_aapcscc void @f8()
+// AAPCS-LABEL: define arm_aapcscc void @f8()
struct s8 { struct { int : 0; } f0[1]; };
struct s8 f8(void) {}
-// APCS-GNU: define i32 @f9()
-// AAPCS: define arm_aapcscc i32 @f9()
+// APCS-GNU-LABEL: define i32 @f9()
+// AAPCS-LABEL: define arm_aapcscc i32 @f9()
struct s9 { int f0; int : 0; };
struct s9 f9(void) {}
-// APCS-GNU: define i32 @f10()
-// AAPCS: define arm_aapcscc i32 @f10()
+// APCS-GNU-LABEL: define i32 @f10()
+// AAPCS-LABEL: define arm_aapcscc i32 @f10()
struct s10 { int f0; int : 0; int : 0; };
struct s10 f10(void) {}
-// APCS-GNU: define void @f11(
+// APCS-GNU-LABEL: define void @f11(
// APCS-GNU: struct.s11* noalias sret
-// AAPCS: define arm_aapcscc i32 @f11()
+// AAPCS-LABEL: define arm_aapcscc i32 @f11()
struct s11 { int : 0; int f0; };
struct s11 f11(void) {}
-// APCS-GNU: define i32 @f12()
-// AAPCS: define arm_aapcscc i32 @f12()
+// APCS-GNU-LABEL: define i32 @f12()
+// AAPCS-LABEL: define arm_aapcscc i32 @f12()
union u12 { char f0; short f1; int f2; };
union u12 f12(void) {}
-// APCS-GNU: define void @f13(
+// APCS-GNU-LABEL: define void @f13(
// APCS-GNU: struct.s13* noalias sret
// FIXME: This should return a float.
@@ -80,55 +80,55 @@ union u12 f12(void) {}
struct s13 { float f0; };
struct s13 f13(void) {}
-// APCS-GNU: define void @f14(
+// APCS-GNU-LABEL: define void @f14(
// APCS-GNU: union.u14* noalias sret
-// AAPCS: define arm_aapcscc i32 @f14()
+// AAPCS-LABEL: define arm_aapcscc i32 @f14()
union u14 { float f0; };
union u14 f14(void) {}
-// APCS-GNU: define void @f15()
-// AAPCS: define arm_aapcscc void @f15()
+// APCS-GNU-LABEL: define void @f15()
+// AAPCS-LABEL: define arm_aapcscc void @f15()
void f15(struct s7 a0) {}
-// APCS-GNU: define void @f16()
-// AAPCS: define arm_aapcscc void @f16()
+// APCS-GNU-LABEL: define void @f16()
+// AAPCS-LABEL: define arm_aapcscc void @f16()
void f16(struct s8 a0) {}
-// APCS-GNU: define i32 @f17()
-// AAPCS: define arm_aapcscc i32 @f17()
+// APCS-GNU-LABEL: define i32 @f17()
+// AAPCS-LABEL: define arm_aapcscc i32 @f17()
struct s17 { short f0 : 13; char f1 : 4; };
struct s17 f17(void) {}
-// APCS-GNU: define i32 @f18()
-// AAPCS: define arm_aapcscc i32 @f18()
+// APCS-GNU-LABEL: define i32 @f18()
+// AAPCS-LABEL: define arm_aapcscc i32 @f18()
struct s18 { short f0; char f1 : 4; };
struct s18 f18(void) {}
-// APCS-GNU: define void @f19(
+// APCS-GNU-LABEL: define void @f19(
// APCS-GNU: struct.s19* noalias sret
-// AAPCS: define arm_aapcscc i32 @f19()
+// AAPCS-LABEL: define arm_aapcscc i32 @f19()
struct s19 { int f0; struct s8 f1; };
struct s19 f19(void) {}
-// APCS-GNU: define void @f20(
+// APCS-GNU-LABEL: define void @f20(
// APCS-GNU: struct.s20* noalias sret
-// AAPCS: define arm_aapcscc i32 @f20()
+// AAPCS-LABEL: define arm_aapcscc i32 @f20()
struct s20 { struct s8 f1; int f0; };
struct s20 f20(void) {}
-// APCS-GNU: define i8 @f21()
-// AAPCS: define arm_aapcscc i32 @f21()
+// APCS-GNU-LABEL: define i8 @f21()
+// AAPCS-LABEL: define arm_aapcscc i32 @f21()
struct s21 { struct {} f1; int f0 : 4; };
struct s21 f21(void) {}
-// APCS-GNU: define i16 @f22()
-// APCS-GNU: define i32 @f23()
-// APCS-GNU: define i64 @f24()
-// APCS-GNU: define i128 @f25()
-// APCS-GNU: define i64 @f26()
-// APCS-GNU: define i128 @f27()
-// AAPCS: define arm_aapcscc i16 @f22()
-// AAPCS: define arm_aapcscc i32 @f23()
+// APCS-GNU-LABEL: define i16 @f22()
+// APCS-GNU-LABEL: define i32 @f23()
+// APCS-GNU-LABEL: define i64 @f24()
+// APCS-GNU-LABEL: define i128 @f25()
+// APCS-GNU-LABEL: define i64 @f26()
+// APCS-GNU-LABEL: define i128 @f27()
+// AAPCS-LABEL: define arm_aapcscc i16 @f22()
+// AAPCS-LABEL: define arm_aapcscc i32 @f23()
// AAPCS: define arm_aapcscc void @f24({{.*}} noalias sret
// AAPCS: define arm_aapcscc void @f25({{.*}} noalias sret
// AAPCS: define arm_aapcscc void @f26({{.*}} noalias sret
@@ -140,13 +140,13 @@ _Complex long long f25(void) {}
_Complex float f26(void) {}
_Complex double f27(void) {}
-// APCS-GNU: define i16 @f28()
-// AAPCS: define arm_aapcscc i16 @f28()
+// APCS-GNU-LABEL: define i16 @f28()
+// AAPCS-LABEL: define arm_aapcscc i16 @f28()
struct s28 { _Complex char f0; };
struct s28 f28() {}
-// APCS-GNU: define i32 @f29()
-// AAPCS: define arm_aapcscc i32 @f29()
+// APCS-GNU-LABEL: define i32 @f29()
+// AAPCS-LABEL: define arm_aapcscc i32 @f29()
struct s29 { _Complex short f0; };
struct s29 f29() {}
@@ -176,8 +176,8 @@ void f32(struct s32 s) { }
// PR13350
struct s33 { char buf[32*32]; };
void f33(struct s33 s) { }
-// APCS-GNU: define void @f33(%struct.s33* byval %s)
-// AAPCS: define arm_aapcscc void @f33(%struct.s33* byval %s)
+// APCS-GNU-LABEL: define void @f33(%struct.s33* byval %s)
+// AAPCS-LABEL: define arm_aapcscc void @f33(%struct.s33* byval %s)
// PR14048
struct s34 { char c; };
@@ -209,14 +209,14 @@ float32x4_t f35(int i, s35_with_align s1, s35_with_align s2) {
*(float32x4_t *)&s2);
return v;
}
-// APCS-GNU: define <4 x float> @f35(i32 %i, %struct.s35* byval, %struct.s35* byval)
+// APCS-GNU-LABEL: define <4 x float> @f35(i32 %i, %struct.s35* byval, %struct.s35* byval)
// APCS-GNU: %[[a:.*]] = alloca %struct.s35, align 16
// APCS-GNU: %[[b:.*]] = bitcast %struct.s35* %[[a]] to i8*
// APCS-GNU: %[[c:.*]] = bitcast %struct.s35* %0 to i8*
// APCS-GNU: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %[[b]], i8* %[[c]]
// APCS-GNU: %[[d:.*]] = bitcast %struct.s35* %[[a]] to <4 x float>*
// APCS-GNU: load <4 x float>* %[[d]], align 16
-// AAPCS: define arm_aapcscc <4 x float> @f35(i32 %i, %struct.s35* byval, %struct.s35* byval)
+// AAPCS-LABEL: define arm_aapcscc <4 x float> @f35(i32 %i, %struct.s35* byval, %struct.s35* byval)
// AAPCS: %[[a:.*]] = alloca %struct.s35, align 16
// AAPCS: %[[b:.*]] = bitcast %struct.s35* %[[a]] to i8*
// AAPCS: %[[c:.*]] = bitcast %struct.s35* %0 to i8*
diff --git a/test/CodeGen/arm-asm-diag.c b/test/CodeGen/arm-asm-diag.c
index eea7920b1062..944a271e6cba 100644
--- a/test/CodeGen/arm-asm-diag.c
+++ b/test/CodeGen/arm-asm-diag.c
@@ -1,5 +1,5 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -triple armv7 %s -S -o /dev/null 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple armv7 -target-feature +neon %s -S -o /dev/null 2>&1 | FileCheck %s
// rdar://13446483
typedef __attribute__((neon_vector_type(2))) long long int64x2_t;
@@ -9,10 +9,10 @@ typedef struct int64x2x4_t {
int64x2x4_t t1(const long long a[]) {
int64x2x4_t r;
__asm__("vldm %[a], { %q[r0], %q[r1], %q[r2], %q[r3] }"
- : [r0] "=r"(r.val[0]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r1] "=r"(r.val[1]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r2] "=r"(r.val[2]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r3] "=r"(r.val[3]) // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
+ : [r0] "=r"(r.val[0]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r1] "=r"(r.val[1]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r2] "=r"(r.val[2]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r3] "=r"(r.val[3]) // expected-warning {{value size does not match register size specified by the constraint and modifier}}
: [a] "r"(a));
return r;
}
diff --git a/test/CodeGen/arm-asm-warn.c b/test/CodeGen/arm-asm-warn.c
index 9b52dd695a51..a580700661e4 100644
--- a/test/CodeGen/arm-asm-warn.c
+++ b/test/CodeGen/arm-asm-warn.c
@@ -1,5 +1,5 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -triple armv7 %s -emit-llvm -o /dev/null
+// RUN: %clang_cc1 -triple armv7 -target-feature +neon %s -emit-llvm -o /dev/null
char bar();
@@ -12,6 +12,7 @@ void t1(int x, char y) {
: "+r" (x),
"+r" (y)
:);
+ __asm__ volatile("ldrb %0, [%1]" : "=r" (y) : "r" (x)); // no warning
}
// <rdar://problem/12284092>
@@ -22,10 +23,10 @@ typedef struct int64x2x4_t {
int64x2x4_t t2(const long long a[]) {
int64x2x4_t r;
__asm__("vldm %[a], { %q[r0], %q[r1], %q[r2], %q[r3] }"
- : [r0] "=r"(r.val[0]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r1] "=r"(r.val[1]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r2] "=r"(r.val[2]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
- [r3] "=r"(r.val[3]) // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
+ : [r0] "=r"(r.val[0]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r1] "=r"(r.val[1]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r2] "=r"(r.val[2]), // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ [r3] "=r"(r.val[3]) // expected-warning {{value size does not match register size specified by the constraint and modifier}}
: [a] "r"(a));
return r;
}
diff --git a/test/CodeGen/arm-cc.c b/test/CodeGen/arm-cc.c
index 80ebe687c11b..8e6aae78b66d 100644
--- a/test/CodeGen/arm-cc.c
+++ b/test/CodeGen/arm-cc.c
@@ -5,13 +5,13 @@
// RUN: %clang_cc1 -triple arm-none-linux-gnueabi -target-abi aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=LINUX-AAPCS %s
-// DARWIN-APCS: define void @f()
+// DARWIN-APCS-LABEL: define void @f()
// DARWIN-APCS: call void @g
-// DARWIN-AAPCS: define arm_aapcscc void @f()
+// DARWIN-AAPCS-LABEL: define arm_aapcscc void @f()
// DARWIN-AAPCS: call arm_aapcscc void @g
-// LINUX-APCS: define arm_apcscc void @f()
+// LINUX-APCS-LABEL: define arm_apcscc void @f()
// LINUX-APCS: call arm_apcscc void @g
-// LINUX-AAPCS: define void @f()
+// LINUX-AAPCS-LABEL: define void @f()
// LINUX-AAPCS: call void @g
void g(void);
void f(void) {
diff --git a/test/CodeGen/arm-clear.c b/test/CodeGen/arm-clear.c
index 51506dfed10d..8ef3675641f8 100644
--- a/test/CodeGen/arm-clear.c
+++ b/test/CodeGen/arm-clear.c
@@ -1,21 +1,8 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
-void clear0(void *ptr) {
- // CHECK: clear0
- // CHECK-NOT: load i8**
- __clear_cache();
-}
-
-void clear1(void *ptr) {
- // CHECK: clear1
- // CHECK: load i8**
- // CHECK-NOT: load i8**
- __clear_cache(ptr);
-}
-
-void clear2(void *ptr, void *ptr2) {
- // CHECK: clear2
+void clear(void *ptr, void *ptr2) {
+ // CHECK: clear
// CHECK: load i8**
// CHECK: load i8**
__clear_cache(ptr, ptr2);
diff --git a/test/CodeGen/arm-crc32.c b/test/CodeGen/arm-crc32.c
new file mode 100644
index 000000000000..d49f20eac74c
--- /dev/null
+++ b/test/CodeGen/arm-crc32.c
@@ -0,0 +1,63 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple armv8-none-linux-gnueabi \
+// RUN: -O3 -S -emit-llvm -o - %s | FileCheck %s
+
+int crc32b(int a, char b)
+{
+ return __builtin_arm_crc32b(a,b);
+// CHECK: [[T0:%[0-9]+]] = zext i8 %b to i32
+// CHECK: call i32 @llvm.arm.crc32b(i32 %a, i32 [[T0]])
+}
+
+int crc32cb(int a, char b)
+{
+ return __builtin_arm_crc32cb(a,b);
+// CHECK: [[T0:%[0-9]+]] = zext i8 %b to i32
+// CHECK: call i32 @llvm.arm.crc32cb(i32 %a, i32 [[T0]])
+}
+
+int crc32h(int a, short b)
+{
+ return __builtin_arm_crc32h(a,b);
+// CHECK: [[T0:%[0-9]+]] = zext i16 %b to i32
+// CHECK: call i32 @llvm.arm.crc32h(i32 %a, i32 [[T0]])
+}
+
+int crc32ch(int a, short b)
+{
+ return __builtin_arm_crc32ch(a,b);
+// CHECK: [[T0:%[0-9]+]] = zext i16 %b to i32
+// CHECK: call i32 @llvm.arm.crc32ch(i32 %a, i32 [[T0]])
+}
+
+int crc32w(int a, int b)
+{
+ return __builtin_arm_crc32w(a,b);
+// CHECK: call i32 @llvm.arm.crc32w(i32 %a, i32 %b)
+}
+
+int crc32cw(int a, int b)
+{
+ return __builtin_arm_crc32cw(a,b);
+// CHECK: call i32 @llvm.arm.crc32cw(i32 %a, i32 %b)
+}
+
+int crc32d(int a, long long b)
+{
+ return __builtin_arm_crc32d(a,b);
+// CHECK: [[T0:%[0-9]+]] = trunc i64 %b to i32
+// CHECK: [[T1:%[0-9]+]] = lshr i64 %b, 32
+// CHECK: [[T2:%[0-9]+]] = trunc i64 [[T1]] to i32
+// CHECK: [[T3:%[0-9]+]] = tail call i32 @llvm.arm.crc32w(i32 %a, i32 [[T0]])
+// CHECK: call i32 @llvm.arm.crc32w(i32 [[T3]], i32 [[T2]])
+}
+
+int crc32cd(int a, long long b)
+{
+ return __builtin_arm_crc32cd(a,b);
+// CHECK: [[T0:%[0-9]+]] = trunc i64 %b to i32
+// CHECK: [[T1:%[0-9]+]] = lshr i64 %b, 32
+// CHECK: [[T2:%[0-9]+]] = trunc i64 [[T1]] to i32
+// CHECK: [[T3:%[0-9]+]] = tail call i32 @llvm.arm.crc32cw(i32 %a, i32 [[T0]])
+// CHECK: call i32 @llvm.arm.crc32cw(i32 [[T3]], i32 [[T2]])
+}
diff --git a/test/CodeGen/arm-interrupt-attr.c b/test/CodeGen/arm-interrupt-attr.c
new file mode 100644
index 000000000000..73f1cfee0502
--- /dev/null
+++ b/test/CodeGen/arm-interrupt-attr.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple thumb-apple-darwin -target-abi aapcs -target-cpu cortex-m3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm-apple-darwin -target-abi apcs-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-APCS
+
+__attribute__((interrupt)) void test_generic_interrupt() {
+ // CHECK: define arm_aapcscc void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
+
+ // CHECK-APCS: define void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("IRQ"))) void test_irq_interrupt() {
+ // CHECK: define arm_aapcscc void @test_irq_interrupt() [[IRQ_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("FIQ"))) void test_fiq_interrupt() {
+ // CHECK: define arm_aapcscc void @test_fiq_interrupt() [[FIQ_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("SWI"))) void test_swi_interrupt() {
+ // CHECK: define arm_aapcscc void @test_swi_interrupt() [[SWI_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("ABORT"))) void test_abort_interrupt() {
+ // CHECK: define arm_aapcscc void @test_abort_interrupt() [[ABORT_ATTR:#[0-9]+]]
+}
+
+
+__attribute__((interrupt("UNDEF"))) void test_undef_interrupt() {
+ // CHECK: define arm_aapcscc void @test_undef_interrupt() [[UNDEF_ATTR:#[0-9]+]]
+}
+
+// CHECK: attributes [[GENERIC_ATTR]] = { nounwind alignstack=8 {{"interrupt"[^=]}}
+// CHECK: attributes [[IRQ_ATTR]] = { nounwind alignstack=8 "interrupt"="IRQ"
+// CHECK: attributes [[FIQ_ATTR]] = { nounwind alignstack=8 "interrupt"="FIQ"
+// CHECK: attributes [[SWI_ATTR]] = { nounwind alignstack=8 "interrupt"="SWI"
+// CHECK: attributes [[ABORT_ATTR]] = { nounwind alignstack=8 "interrupt"="ABORT"
+// CHECK: attributes [[UNDEF_ATTR]] = { nounwind alignstack=8 "interrupt"="UNDEF"
+
+// CHECK-APCS: attributes [[GENERIC_ATTR]] = { nounwind "interrupt"
diff --git a/test/CodeGen/arm-neon-shifts.c b/test/CodeGen/arm-neon-shifts.c
new file mode 100644
index 000000000000..7acfb894e976
--- /dev/null
+++ b/test/CodeGen/arm-neon-shifts.c
@@ -0,0 +1,45 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple thumbv7-apple-darwin \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -ffreestanding \
+// RUN: -emit-llvm -w -O1 -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+uint8x8_t test_shift_vshr(uint8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr
+ // CHECK: %{{.*}} = lshr <8 x i8> %a, <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+ return vshr_n_u8(a, 5);
+}
+
+int8x8_t test_shift_vshr_smax(int8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr_smax
+ // CHECK: %{{.*}} = ashr <8 x i8> %a, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ return vshr_n_s8(a, 8);
+}
+
+uint8x8_t test_shift_vshr_umax(uint8x8_t a) {
+ // CHECK-LABEL: test_shift_vshr_umax
+ // CHECK: ret <8 x i8> zeroinitializer
+ return vshr_n_u8(a, 8);
+}
+
+uint8x8_t test_shift_vsra(uint8x8_t a, uint8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra
+ // CHECK: %[[SHR:.*]] = lshr <8 x i8> %b, <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+ // CHECK: %{{.*}} = add <8 x i8> %[[SHR]], %a
+ return vsra_n_u8(a, b, 5);
+}
+
+int8x8_t test_shift_vsra_smax(int8x8_t a, int8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra_smax
+ // CHECK: %[[SHR:.*]] = ashr <8 x i8> %b, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ // CHECK: %{{.*}} = add <8 x i8> %[[SHR]], %a
+ return vsra_n_s8(a, b, 8);
+}
+
+uint8x8_t test_shift_vsra_umax(uint8x8_t a, uint8x8_t b) {
+ // CHECK-LABEL: test_shift_vsra_umax
+ // CHECK: ret <8 x i8> %a
+ return vsra_n_u8(a, b, 8);
+}
diff --git a/test/CodeGen/arm-neon-vget.c b/test/CodeGen/arm-neon-vget.c
new file mode 100644
index 000000000000..4a710a2ad8e4
--- /dev/null
+++ b/test/CodeGen/arm-neon-vget.c
@@ -0,0 +1,124 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple thumbv7-apple-darwin \
+// RUN: -target-abi apcs-gnu \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -mfloat-abi soft \
+// RUN: -target-feature +soft-float-abi \
+// RUN: -ffreestanding \
+// RUN: -emit-llvm -w -O1 -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+// Check that the vget_low/vget_high intrinsics generate a single shuffle
+// without any bitcasting.
+int8x8_t low_s8(int8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return vget_low_s8(a);
+}
+
+uint8x8_t low_u8 (uint8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return vget_low_u8(a);
+}
+
+int16x4_t low_s16( int16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ return vget_low_s16(a);
+}
+
+uint16x4_t low_u16(uint16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ return vget_low_u16(a);
+}
+
+int32x2_t low_s32( int32x4_t a) {
+// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 0, i32 1>
+ return vget_low_s32(a);
+}
+
+uint32x2_t low_u32(uint32x4_t a) {
+// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 0, i32 1>
+ return vget_low_u32(a);
+}
+
+int64x1_t low_s64( int64x2_t a) {
+// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> zeroinitializer
+ return vget_low_s64(a);
+}
+
+uint64x1_t low_u64(uint64x2_t a) {
+// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> zeroinitializer
+ return vget_low_u64(a);
+}
+
+poly8x8_t low_p8 (poly8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return vget_low_p8(a);
+}
+
+poly16x4_t low_p16(poly16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ return vget_low_p16(a);
+}
+
+float32x2_t low_f32(float32x4_t a) {
+// CHECK: shufflevector <4 x float> %a, <4 x float> undef, <2 x i32> <i32 0, i32 1>
+ return vget_low_f32(a);
+}
+
+
+int8x8_t high_s8(int8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ return vget_high_s8(a);
+}
+
+uint8x8_t high_u8 (uint8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ return vget_high_u8(a);
+}
+
+int16x4_t high_s16( int16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ return vget_high_s16(a);
+}
+
+uint16x4_t high_u16(uint16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ return vget_high_u16(a);
+}
+
+int32x2_t high_s32( int32x4_t a) {
+// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 2, i32 3>
+ return vget_high_s32(a);
+}
+
+uint32x2_t high_u32(uint32x4_t a) {
+// CHECK: shufflevector <4 x i32> %a, <4 x i32> undef, <2 x i32> <i32 2, i32 3>
+ return vget_high_u32(a);
+}
+
+int64x1_t high_s64( int64x2_t a) {
+// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> <i32 1>
+ return vget_high_s64(a);
+}
+
+uint64x1_t high_u64(uint64x2_t a) {
+// CHECK: shufflevector <2 x i64> %a, <2 x i64> undef, <1 x i32> <i32 1>
+ return vget_high_u64(a);
+}
+
+poly8x8_t high_p8 (poly8x16_t a) {
+// CHECK: shufflevector <16 x i8> %a, <16 x i8> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ return vget_high_p8(a);
+}
+
+poly16x4_t high_p16(poly16x8_t a) {
+// CHECK: shufflevector <8 x i16> %a, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ return vget_high_p16(a);
+}
+
+float32x2_t high_f32(float32x4_t a) {
+// CHECK: shufflevector <4 x float> %a, <4 x float> undef, <2 x i32> <i32 2, i32 3>
+ return vget_high_f32(a);
+}
+
diff --git a/test/CodeGen/arm-pcs.c b/test/CodeGen/arm-pcs.c
index fc658c3bef6f..269f01e77de1 100644
--- a/test/CodeGen/arm-pcs.c
+++ b/test/CodeGen/arm-pcs.c
@@ -6,7 +6,7 @@ typedef int __attribute__((pcs("aapcs-vfp"))) (*aapcs_vfp_fn)(void);
aapcs_fn bar;
int foo(aapcs_vfp_fn baz) {
-// CHECK: define i32 @foo
+// CHECK-LABEL: define i32 @foo
// CHECK: call arm_aapcscc
// CHECK: call arm_aapcs_vfpcc
return bar() + baz();
diff --git a/test/CodeGen/arm-pnaclcall.c b/test/CodeGen/arm-pnaclcall.c
index 50259957eb15..2faac1c676b9 100644
--- a/test/CodeGen/arm-pnaclcall.c
+++ b/test/CodeGen/arm-pnaclcall.c
@@ -9,10 +9,10 @@ typedef struct {
int a;
int b;
} s1;
-// CHECK: define i32 @f48(%struct.s1* byval %s)
+// CHECK-LABEL: define i32 @f48(%struct.s1* byval %s)
int __attribute__((pnaclcall)) f48(s1 s) { return s.a; }
-// CHECK: define void @f49(%struct.s1* noalias sret %agg.result)
+// CHECK-LABEL: define void @f49(%struct.s1* noalias sret %agg.result)
s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
union simple_union {
@@ -20,7 +20,7 @@ union simple_union {
char b;
};
// Unions should be passed as byval structs
-// CHECK: define void @f50(%union.simple_union* byval %s)
+// CHECK-LABEL: define void @f50(%union.simple_union* byval %s)
void __attribute__((pnaclcall)) f50(union simple_union s) {}
typedef struct {
@@ -29,5 +29,5 @@ typedef struct {
int b8 : 8;
} bitfield1;
// Bitfields should be passed as byval structs
-// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+// CHECK-LABEL: define void @f51(%struct.bitfield1* byval %bf1)
void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
diff --git a/test/CodeGen/arm_neon_intrinsics.c b/test/CodeGen/arm_neon_intrinsics.c
new file mode 100644
index 000000000000..1d76e8a57546
--- /dev/null
+++ b/test/CodeGen/arm_neon_intrinsics.c
@@ -0,0 +1,11636 @@
+// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi apcs-gnu\
+// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\
+// RUN: | FileCheck %s
+
+// REQUIRES: long_tests
+
+#include <arm_neon.h>
+
+// CHECK: test_vaba_s8
+// CHECK: vaba.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vaba_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
+ return vaba_s8(a, b, c);
+}
+
+// CHECK: test_vaba_s16
+// CHECK: vaba.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vaba_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+ return vaba_s16(a, b, c);
+}
+
+// CHECK: test_vaba_s32
+// CHECK: vaba.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vaba_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+ return vaba_s32(a, b, c);
+}
+
+// CHECK: test_vaba_u8
+// CHECK: vaba.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vaba_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vaba_u8(a, b, c);
+}
+
+// CHECK: test_vaba_u16
+// CHECK: vaba.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vaba_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vaba_u16(a, b, c);
+}
+
+// CHECK: test_vaba_u32
+// CHECK: vaba.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vaba_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vaba_u32(a, b, c);
+}
+
+// CHECK: test_vabaq_s8
+// CHECK: vaba.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vabaq_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
+ return vabaq_s8(a, b, c);
+}
+
+// CHECK: test_vabaq_s16
+// CHECK: vaba.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vabaq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
+ return vabaq_s16(a, b, c);
+}
+
+// CHECK: test_vabaq_s32
+// CHECK: vaba.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vabaq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
+ return vabaq_s32(a, b, c);
+}
+
+// CHECK: test_vabaq_u8
+// CHECK: vaba.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vabaq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
+ return vabaq_u8(a, b, c);
+}
+
+// CHECK: test_vabaq_u16
+// CHECK: vaba.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vabaq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
+ return vabaq_u16(a, b, c);
+}
+
+// CHECK: test_vabaq_u32
+// CHECK: vaba.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vabaq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
+ return vabaq_u32(a, b, c);
+}
+
+
+// CHECK: test_vabal_s8
+// CHECK: vabal.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vabal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ return vabal_s8(a, b, c);
+}
+
+// CHECK: test_vabal_s16
+// CHECK: vabal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vabal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vabal_s16(a, b, c);
+}
+
+// CHECK: test_vabal_s32
+// CHECK: vabal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vabal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vabal_s32(a, b, c);
+}
+
+// CHECK: test_vabal_u8
+// CHECK: vabal.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vabal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vabal_u8(a, b, c);
+}
+
+// CHECK: test_vabal_u16
+// CHECK: vabal.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vabal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vabal_u16(a, b, c);
+}
+
+// CHECK: test_vabal_u32
+// CHECK: vabal.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vabal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vabal_u32(a, b, c);
+}
+
+
+// CHECK: test_vabd_s8
+// CHECK: vabd.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vabd_s8(int8x8_t a, int8x8_t b) {
+ return vabd_s8(a, b);
+}
+
+// CHECK: test_vabd_s16
+// CHECK: vabd.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vabd_s16(int16x4_t a, int16x4_t b) {
+ return vabd_s16(a, b);
+}
+
+// CHECK: test_vabd_s32
+// CHECK: vabd.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vabd_s32(int32x2_t a, int32x2_t b) {
+ return vabd_s32(a, b);
+}
+
+// CHECK: test_vabd_u8
+// CHECK: vabd.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vabd_u8(uint8x8_t a, uint8x8_t b) {
+ return vabd_u8(a, b);
+}
+
+// CHECK: test_vabd_u16
+// CHECK: vabd.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vabd_u16(uint16x4_t a, uint16x4_t b) {
+ return vabd_u16(a, b);
+}
+
+// CHECK: test_vabd_u32
+// CHECK: vabd.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vabd_u32(uint32x2_t a, uint32x2_t b) {
+ return vabd_u32(a, b);
+}
+
+// CHECK: test_vabd_f32
+// CHECK: vabd.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vabd_f32(float32x2_t a, float32x2_t b) {
+ return vabd_f32(a, b);
+}
+
+// CHECK: test_vabdq_s8
+// CHECK: vabd.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vabdq_s8(int8x16_t a, int8x16_t b) {
+ return vabdq_s8(a, b);
+}
+
+// CHECK: test_vabdq_s16
+// CHECK: vabd.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vabdq_s16(int16x8_t a, int16x8_t b) {
+ return vabdq_s16(a, b);
+}
+
+// CHECK: test_vabdq_s32
+// CHECK: vabd.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vabdq_s32(int32x4_t a, int32x4_t b) {
+ return vabdq_s32(a, b);
+}
+
+// CHECK: test_vabdq_u8
+// CHECK: vabd.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vabdq_u8(uint8x16_t a, uint8x16_t b) {
+ return vabdq_u8(a, b);
+}
+
+// CHECK: test_vabdq_u16
+// CHECK: vabd.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vabdq_u16(uint16x8_t a, uint16x8_t b) {
+ return vabdq_u16(a, b);
+}
+
+// CHECK: test_vabdq_u32
+// CHECK: vabd.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vabdq_u32(uint32x4_t a, uint32x4_t b) {
+ return vabdq_u32(a, b);
+}
+
+// CHECK: test_vabdq_f32
+// CHECK: vabd.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vabdq_f32(float32x4_t a, float32x4_t b) {
+ return vabdq_f32(a, b);
+}
+
+
+// CHECK: test_vabdl_s8
+// CHECK: vabdl.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
+ return vabdl_s8(a, b);
+}
+
+// CHECK: test_vabdl_s16
+// CHECK: vabdl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vabdl_s16(int16x4_t a, int16x4_t b) {
+ return vabdl_s16(a, b);
+}
+
+// CHECK: test_vabdl_s32
+// CHECK: vabdl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vabdl_s32(int32x2_t a, int32x2_t b) {
+ return vabdl_s32(a, b);
+}
+
+// CHECK: test_vabdl_u8
+// CHECK: vabdl.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
+ return vabdl_u8(a, b);
+}
+
+// CHECK: test_vabdl_u16
+// CHECK: vabdl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vabdl_u16(uint16x4_t a, uint16x4_t b) {
+ return vabdl_u16(a, b);
+}
+
+// CHECK: test_vabdl_u32
+// CHECK: vabdl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vabdl_u32(uint32x2_t a, uint32x2_t b) {
+ return vabdl_u32(a, b);
+}
+
+
+// CHECK: test_vabs_s8
+// CHECK: vabs.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vabs_s8(int8x8_t a) {
+ return vabs_s8(a);
+}
+
+// CHECK: test_vabs_s16
+// CHECK: vabs.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vabs_s16(int16x4_t a) {
+ return vabs_s16(a);
+}
+
+// CHECK: test_vabs_s32
+// CHECK: vabs.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vabs_s32(int32x2_t a) {
+ return vabs_s32(a);
+}
+
+// CHECK: test_vabs_f32
+// CHECK: vabs.f32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vabs_f32(float32x2_t a) {
+ return vabs_f32(a);
+}
+
+// CHECK: test_vabsq_s8
+// CHECK: vabs.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vabsq_s8(int8x16_t a) {
+ return vabsq_s8(a);
+}
+
+// CHECK: test_vabsq_s16
+// CHECK: vabs.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vabsq_s16(int16x8_t a) {
+ return vabsq_s16(a);
+}
+
+// CHECK: test_vabsq_s32
+// CHECK: vabs.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vabsq_s32(int32x4_t a) {
+ return vabsq_s32(a);
+}
+
+// CHECK: test_vabsq_f32
+// CHECK: vabs.f32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vabsq_f32(float32x4_t a) {
+ return vabsq_f32(a);
+}
+
+
+// CHECK: test_vadd_s8
+// CHECK: vadd.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vadd_s8(int8x8_t a, int8x8_t b) {
+ return vadd_s8(a, b);
+}
+
+// CHECK: test_vadd_s16
+// CHECK: vadd.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vadd_s16(int16x4_t a, int16x4_t b) {
+ return vadd_s16(a, b);
+}
+
+// CHECK: test_vadd_s32
+// CHECK: vadd.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vadd_s32(int32x2_t a, int32x2_t b) {
+ return vadd_s32(a, b);
+}
+
+// CHECK: test_vadd_s64
+// CHECK: vadd.i64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vadd_s64(int64x1_t a, int64x1_t b) {
+ return vadd_s64(a, b);
+}
+
+// CHECK: test_vadd_f32
+// CHECK: vadd.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vadd_f32(float32x2_t a, float32x2_t b) {
+ return vadd_f32(a, b);
+}
+
+// CHECK: test_vadd_u8
+// CHECK: vadd.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vadd_u8(uint8x8_t a, uint8x8_t b) {
+ return vadd_u8(a, b);
+}
+
+// CHECK: test_vadd_u16
+// CHECK: vadd.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vadd_u16(uint16x4_t a, uint16x4_t b) {
+ return vadd_u16(a, b);
+}
+
+// CHECK: test_vadd_u32
+// CHECK: vadd.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vadd_u32(uint32x2_t a, uint32x2_t b) {
+ return vadd_u32(a, b);
+}
+
+// CHECK: test_vadd_u64
+// CHECK: vadd.i64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vadd_u64(uint64x1_t a, uint64x1_t b) {
+ return vadd_u64(a, b);
+}
+
+// CHECK: test_vaddq_s8
+// CHECK: vadd.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vaddq_s8(int8x16_t a, int8x16_t b) {
+ return vaddq_s8(a, b);
+}
+
+// CHECK: test_vaddq_s16
+// CHECK: vadd.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vaddq_s16(int16x8_t a, int16x8_t b) {
+ return vaddq_s16(a, b);
+}
+
+// CHECK: test_vaddq_s32
+// CHECK: vadd.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vaddq_s32(int32x4_t a, int32x4_t b) {
+ return vaddq_s32(a, b);
+}
+
+// CHECK: test_vaddq_s64
+// CHECK: vadd.i64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vaddq_s64(int64x2_t a, int64x2_t b) {
+ return vaddq_s64(a, b);
+}
+
+// CHECK: test_vaddq_f32
+// CHECK: vadd.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vaddq_f32(float32x4_t a, float32x4_t b) {
+ return vaddq_f32(a, b);
+}
+
+// CHECK: test_vaddq_u8
+// CHECK: vadd.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vaddq_u8(uint8x16_t a, uint8x16_t b) {
+ return vaddq_u8(a, b);
+}
+
+// CHECK: test_vaddq_u16
+// CHECK: vadd.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vaddq_u16(uint16x8_t a, uint16x8_t b) {
+ return vaddq_u16(a, b);
+}
+
+// CHECK: test_vaddq_u32
+// CHECK: vadd.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vaddq_u32(uint32x4_t a, uint32x4_t b) {
+ return vaddq_u32(a, b);
+}
+
+// CHECK: test_vaddq_u64
+// CHECK: vadd.i64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vaddq_u64(uint64x2_t a, uint64x2_t b) {
+ return vaddq_u64(a, b);
+}
+
+
+// CHECK: test_vaddhn_s16
+// CHECK: vaddhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vaddhn_s16(int16x8_t a, int16x8_t b) {
+ return vaddhn_s16(a, b);
+}
+
+// CHECK: test_vaddhn_s32
+// CHECK: vaddhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vaddhn_s32(int32x4_t a, int32x4_t b) {
+ return vaddhn_s32(a, b);
+}
+
+// CHECK: test_vaddhn_s64
+// CHECK: vaddhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vaddhn_s64(int64x2_t a, int64x2_t b) {
+ return vaddhn_s64(a, b);
+}
+
+// CHECK: test_vaddhn_u16
+// CHECK: vaddhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vaddhn_u16(uint16x8_t a, uint16x8_t b) {
+ return vaddhn_u16(a, b);
+}
+
+// CHECK: test_vaddhn_u32
+// CHECK: vaddhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vaddhn_u32(uint32x4_t a, uint32x4_t b) {
+ return vaddhn_u32(a, b);
+}
+
+// CHECK: test_vaddhn_u64
+// CHECK: vaddhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vaddhn_u64(uint64x2_t a, uint64x2_t b) {
+ return vaddhn_u64(a, b);
+}
+
+
+// CHECK: test_vaddl_s8
+// CHECK: vaddl.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vaddl_s8(int8x8_t a, int8x8_t b) {
+ return vaddl_s8(a, b);
+}
+
+// CHECK: test_vaddl_s16
+// CHECK: vaddl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vaddl_s16(int16x4_t a, int16x4_t b) {
+ return vaddl_s16(a, b);
+}
+
+// CHECK: test_vaddl_s32
+// CHECK: vaddl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vaddl_s32(int32x2_t a, int32x2_t b) {
+ return vaddl_s32(a, b);
+}
+
+// CHECK: test_vaddl_u8
+// CHECK: vaddl.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vaddl_u8(uint8x8_t a, uint8x8_t b) {
+ return vaddl_u8(a, b);
+}
+
+// CHECK: test_vaddl_u16
+// CHECK: vaddl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vaddl_u16(uint16x4_t a, uint16x4_t b) {
+ return vaddl_u16(a, b);
+}
+
+// CHECK: test_vaddl_u32
+// CHECK: vaddl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vaddl_u32(uint32x2_t a, uint32x2_t b) {
+ return vaddl_u32(a, b);
+}
+
+
+// CHECK: test_vaddw_s8
+// CHECK: vaddw.s8 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vaddw_s8(int16x8_t a, int8x8_t b) {
+ return vaddw_s8(a, b);
+}
+
+// CHECK: test_vaddw_s16
+// CHECK: vaddw.s16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vaddw_s16(int32x4_t a, int16x4_t b) {
+ return vaddw_s16(a, b);
+}
+
+// CHECK: test_vaddw_s32
+// CHECK: vaddw.s32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vaddw_s32(int64x2_t a, int32x2_t b) {
+ return vaddw_s32(a, b);
+}
+
+// CHECK: test_vaddw_u8
+// CHECK: vaddw.u8 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vaddw_u8(uint16x8_t a, uint8x8_t b) {
+ return vaddw_u8(a, b);
+}
+
+// CHECK: test_vaddw_u16
+// CHECK: vaddw.u16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vaddw_u16(uint32x4_t a, uint16x4_t b) {
+ return vaddw_u16(a, b);
+}
+
+// CHECK: test_vaddw_u32
+// CHECK: vaddw.u32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vaddw_u32(uint64x2_t a, uint32x2_t b) {
+ return vaddw_u32(a, b);
+}
+
+
+// CHECK: test_vand_s8
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vand_s8(int8x8_t a, int8x8_t b) {
+ return vand_s8(a, b);
+}
+
+// CHECK: test_vand_s16
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vand_s16(int16x4_t a, int16x4_t b) {
+ return vand_s16(a, b);
+}
+
+// CHECK: test_vand_s32
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vand_s32(int32x2_t a, int32x2_t b) {
+ return vand_s32(a, b);
+}
+
+// CHECK: test_vand_s64
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vand_s64(int64x1_t a, int64x1_t b) {
+ return vand_s64(a, b);
+}
+
+// CHECK: test_vand_u8
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vand_u8(uint8x8_t a, uint8x8_t b) {
+ return vand_u8(a, b);
+}
+
+// CHECK: test_vand_u16
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vand_u16(uint16x4_t a, uint16x4_t b) {
+ return vand_u16(a, b);
+}
+
+// CHECK: test_vand_u32
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vand_u32(uint32x2_t a, uint32x2_t b) {
+ return vand_u32(a, b);
+}
+
+// CHECK: test_vand_u64
+// CHECK: vand d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vand_u64(uint64x1_t a, uint64x1_t b) {
+ return vand_u64(a, b);
+}
+
+// CHECK: test_vandq_s8
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vandq_s8(int8x16_t a, int8x16_t b) {
+ return vandq_s8(a, b);
+}
+
+// CHECK: test_vandq_s16
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vandq_s16(int16x8_t a, int16x8_t b) {
+ return vandq_s16(a, b);
+}
+
+// CHECK: test_vandq_s32
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vandq_s32(int32x4_t a, int32x4_t b) {
+ return vandq_s32(a, b);
+}
+
+// CHECK: test_vandq_s64
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vandq_s64(int64x2_t a, int64x2_t b) {
+ return vandq_s64(a, b);
+}
+
+// CHECK: test_vandq_u8
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vandq_u8(uint8x16_t a, uint8x16_t b) {
+ return vandq_u8(a, b);
+}
+
+// CHECK: test_vandq_u16
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vandq_u16(uint16x8_t a, uint16x8_t b) {
+ return vandq_u16(a, b);
+}
+
+// CHECK: test_vandq_u32
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vandq_u32(uint32x4_t a, uint32x4_t b) {
+ return vandq_u32(a, b);
+}
+
+// CHECK: test_vandq_u64
+// CHECK: vand q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vandq_u64(uint64x2_t a, uint64x2_t b) {
+ return vandq_u64(a, b);
+}
+
+
+// CHECK: test_vbic_s8
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vbic_s8(int8x8_t a, int8x8_t b) {
+ return vbic_s8(a, b);
+}
+
+// CHECK: test_vbic_s16
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vbic_s16(int16x4_t a, int16x4_t b) {
+ return vbic_s16(a, b);
+}
+
+// CHECK: test_vbic_s32
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vbic_s32(int32x2_t a, int32x2_t b) {
+ return vbic_s32(a, b);
+}
+
+// CHECK: test_vbic_s64
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vbic_s64(int64x1_t a, int64x1_t b) {
+ return vbic_s64(a, b);
+}
+
+// CHECK: test_vbic_u8
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vbic_u8(uint8x8_t a, uint8x8_t b) {
+ return vbic_u8(a, b);
+}
+
+// CHECK: test_vbic_u16
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vbic_u16(uint16x4_t a, uint16x4_t b) {
+ return vbic_u16(a, b);
+}
+
+// CHECK: test_vbic_u32
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vbic_u32(uint32x2_t a, uint32x2_t b) {
+ return vbic_u32(a, b);
+}
+
+// CHECK: test_vbic_u64
+// CHECK: vbic d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vbic_u64(uint64x1_t a, uint64x1_t b) {
+ return vbic_u64(a, b);
+}
+
+// CHECK: test_vbicq_s8
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vbicq_s8(int8x16_t a, int8x16_t b) {
+ return vbicq_s8(a, b);
+}
+
+// CHECK: test_vbicq_s16
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vbicq_s16(int16x8_t a, int16x8_t b) {
+ return vbicq_s16(a, b);
+}
+
+// CHECK: test_vbicq_s32
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vbicq_s32(int32x4_t a, int32x4_t b) {
+ return vbicq_s32(a, b);
+}
+
+// CHECK: test_vbicq_s64
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vbicq_s64(int64x2_t a, int64x2_t b) {
+ return vbicq_s64(a, b);
+}
+
+// CHECK: test_vbicq_u8
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vbicq_u8(uint8x16_t a, uint8x16_t b) {
+ return vbicq_u8(a, b);
+}
+
+// CHECK: test_vbicq_u16
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vbicq_u16(uint16x8_t a, uint16x8_t b) {
+ return vbicq_u16(a, b);
+}
+
+// CHECK: test_vbicq_u32
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vbicq_u32(uint32x4_t a, uint32x4_t b) {
+ return vbicq_u32(a, b);
+}
+
+// CHECK: test_vbicq_u64
+// CHECK: vbic q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vbicq_u64(uint64x2_t a, uint64x2_t b) {
+ return vbicq_u64(a, b);
+}
+
+
+// CHECK: test_vbsl_s8
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vbsl_s8(uint8x8_t a, int8x8_t b, int8x8_t c) {
+ return vbsl_s8(a, b, c);
+}
+
+// CHECK: test_vbsl_s16
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vbsl_s16(uint16x4_t a, int16x4_t b, int16x4_t c) {
+ return vbsl_s16(a, b, c);
+}
+
+// CHECK: test_vbsl_s32
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vbsl_s32(uint32x2_t a, int32x2_t b, int32x2_t c) {
+ return vbsl_s32(a, b, c);
+}
+
+// CHECK: test_vbsl_s64
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vbsl_s64(uint64x1_t a, int64x1_t b, int64x1_t c) {
+ return vbsl_s64(a, b, c);
+}
+
+// CHECK: test_vbsl_u8
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vbsl_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vbsl_u8(a, b, c);
+}
+
+// CHECK: test_vbsl_u16
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vbsl_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vbsl_u16(a, b, c);
+}
+
+// CHECK: test_vbsl_u32
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vbsl_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vbsl_u32(a, b, c);
+}
+
+// CHECK: test_vbsl_u64
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vbsl_u64(uint64x1_t a, uint64x1_t b, uint64x1_t c) {
+ return vbsl_u64(a, b, c);
+}
+
+// CHECK: test_vbsl_f32
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vbsl_f32(uint32x2_t a, float32x2_t b, float32x2_t c) {
+ return vbsl_f32(a, b, c);
+}
+
+// CHECK: test_vbsl_p8
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vbsl_p8(uint8x8_t a, poly8x8_t b, poly8x8_t c) {
+ return vbsl_p8(a, b, c);
+}
+
+// CHECK: test_vbsl_p16
+// CHECK: vbsl d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4_t test_vbsl_p16(uint16x4_t a, poly16x4_t b, poly16x4_t c) {
+ return vbsl_p16(a, b, c);
+}
+
+// CHECK: test_vbslq_s8
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vbslq_s8(uint8x16_t a, int8x16_t b, int8x16_t c) {
+ return vbslq_s8(a, b, c);
+}
+
+// CHECK: test_vbslq_s16
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vbslq_s16(uint16x8_t a, int16x8_t b, int16x8_t c) {
+ return vbslq_s16(a, b, c);
+}
+
+// CHECK: test_vbslq_s32
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vbslq_s32(uint32x4_t a, int32x4_t b, int32x4_t c) {
+ return vbslq_s32(a, b, c);
+}
+
+// CHECK: test_vbslq_s64
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vbslq_s64(uint64x2_t a, int64x2_t b, int64x2_t c) {
+ return vbslq_s64(a, b, c);
+}
+
+// CHECK: test_vbslq_u8
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vbslq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
+ return vbslq_u8(a, b, c);
+}
+
+// CHECK: test_vbslq_u16
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vbslq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
+ return vbslq_u16(a, b, c);
+}
+
+// CHECK: test_vbslq_u32
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vbslq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
+ return vbslq_u32(a, b, c);
+}
+
+// CHECK: test_vbslq_u64
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vbslq_u64(uint64x2_t a, uint64x2_t b, uint64x2_t c) {
+ return vbslq_u64(a, b, c);
+}
+
+// CHECK: test_vbslq_f32
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vbslq_f32(uint32x4_t a, float32x4_t b, float32x4_t c) {
+ return vbslq_f32(a, b, c);
+}
+
+// CHECK: test_vbslq_p8
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vbslq_p8(uint8x16_t a, poly8x16_t b, poly8x16_t c) {
+ return vbslq_p8(a, b, c);
+}
+
+// CHECK: test_vbslq_p16
+// CHECK: vbsl q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8_t test_vbslq_p16(uint16x8_t a, poly16x8_t b, poly16x8_t c) {
+ return vbslq_p16(a, b, c);
+}
+
+
+// CHECK: test_vcage_f32
+// CHECK: vacge.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcage_f32(float32x2_t a, float32x2_t b) {
+ return vcage_f32(a, b);
+}
+
+// CHECK: test_vcageq_f32
+// CHECK: vacge.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcageq_f32(float32x4_t a, float32x4_t b) {
+ return vcageq_f32(a, b);
+}
+
+
+// CHECK: test_vcagt_f32
+// CHECK: vacgt.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcagt_f32(float32x2_t a, float32x2_t b) {
+ return vcagt_f32(a, b);
+}
+
+// CHECK: test_vcagtq_f32
+// CHECK: vacgt.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcagtq_f32(float32x4_t a, float32x4_t b) {
+ return vcagtq_f32(a, b);
+}
+
+
+// CHECK: test_vcale_f32
+// CHECK: vacge.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcale_f32(float32x2_t a, float32x2_t b) {
+ return vcale_f32(a, b);
+}
+
+// CHECK: test_vcaleq_f32
+// CHECK: vacge.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcaleq_f32(float32x4_t a, float32x4_t b) {
+ return vcaleq_f32(a, b);
+}
+
+
+// CHECK: test_vcalt_f32
+// CHECK: vacgt.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcalt_f32(float32x2_t a, float32x2_t b) {
+ return vcalt_f32(a, b);
+}
+
+// CHECK: test_vcaltq_f32
+// CHECK: vacgt.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcaltq_f32(float32x4_t a, float32x4_t b) {
+ return vcaltq_f32(a, b);
+}
+
+
+// CHECK: test_vceq_s8
+// CHECK: vceq.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vceq_s8(int8x8_t a, int8x8_t b) {
+ return vceq_s8(a, b);
+}
+
+// CHECK: test_vceq_s16
+// CHECK: vceq.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vceq_s16(int16x4_t a, int16x4_t b) {
+ return vceq_s16(a, b);
+}
+
+// CHECK: test_vceq_s32
+// CHECK: vceq.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vceq_s32(int32x2_t a, int32x2_t b) {
+ return vceq_s32(a, b);
+}
+
+// CHECK: test_vceq_f32
+// CHECK: vceq.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vceq_f32(float32x2_t a, float32x2_t b) {
+ return vceq_f32(a, b);
+}
+
+// CHECK: test_vceq_u8
+// CHECK: vceq.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vceq_u8(uint8x8_t a, uint8x8_t b) {
+ return vceq_u8(a, b);
+}
+
+// CHECK: test_vceq_u16
+// CHECK: vceq.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vceq_u16(uint16x4_t a, uint16x4_t b) {
+ return vceq_u16(a, b);
+}
+
+// CHECK: test_vceq_u32
+// CHECK: vceq.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vceq_u32(uint32x2_t a, uint32x2_t b) {
+ return vceq_u32(a, b);
+}
+
+// CHECK: test_vceq_p8
+// CHECK: vceq.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vceq_p8(poly8x8_t a, poly8x8_t b) {
+ return vceq_p8(a, b);
+}
+
+// CHECK: test_vceqq_s8
+// CHECK: vceq.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vceqq_s8(int8x16_t a, int8x16_t b) {
+ return vceqq_s8(a, b);
+}
+
+// CHECK: test_vceqq_s16
+// CHECK: vceq.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vceqq_s16(int16x8_t a, int16x8_t b) {
+ return vceqq_s16(a, b);
+}
+
+// CHECK: test_vceqq_s32
+// CHECK: vceq.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vceqq_s32(int32x4_t a, int32x4_t b) {
+ return vceqq_s32(a, b);
+}
+
+// CHECK: test_vceqq_f32
+// CHECK: vceq.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vceqq_f32(float32x4_t a, float32x4_t b) {
+ return vceqq_f32(a, b);
+}
+
+// CHECK: test_vceqq_u8
+// CHECK: vceq.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vceqq_u8(uint8x16_t a, uint8x16_t b) {
+ return vceqq_u8(a, b);
+}
+
+// CHECK: test_vceqq_u16
+// CHECK: vceq.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vceqq_u16(uint16x8_t a, uint16x8_t b) {
+ return vceqq_u16(a, b);
+}
+
+// CHECK: test_vceqq_u32
+// CHECK: vceq.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vceqq_u32(uint32x4_t a, uint32x4_t b) {
+ return vceqq_u32(a, b);
+}
+
+// CHECK: test_vceqq_p8
+// CHECK: vceq.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vceqq_p8(poly8x16_t a, poly8x16_t b) {
+ return vceqq_p8(a, b);
+}
+
+
+// CHECK: test_vcge_s8
+// CHECK: vcge.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcge_s8(int8x8_t a, int8x8_t b) {
+ return vcge_s8(a, b);
+}
+
+// CHECK: test_vcge_s16
+// CHECK: vcge.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcge_s16(int16x4_t a, int16x4_t b) {
+ return vcge_s16(a, b);
+}
+
+// CHECK: test_vcge_s32
+// CHECK: vcge.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcge_s32(int32x2_t a, int32x2_t b) {
+ return vcge_s32(a, b);
+}
+
+// CHECK: test_vcge_f32
+// CHECK: vcge.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcge_f32(float32x2_t a, float32x2_t b) {
+ return vcge_f32(a, b);
+}
+
+// CHECK: test_vcge_u8
+// CHECK: vcge.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcge_u8(uint8x8_t a, uint8x8_t b) {
+ return vcge_u8(a, b);
+}
+
+// CHECK: test_vcge_u16
+// CHECK: vcge.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcge_u16(uint16x4_t a, uint16x4_t b) {
+ return vcge_u16(a, b);
+}
+
+// CHECK: test_vcge_u32
+// CHECK: vcge.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcge_u32(uint32x2_t a, uint32x2_t b) {
+ return vcge_u32(a, b);
+}
+
+// CHECK: test_vcgeq_s8
+// CHECK: vcge.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcgeq_s8(int8x16_t a, int8x16_t b) {
+ return vcgeq_s8(a, b);
+}
+
+// CHECK: test_vcgeq_s16
+// CHECK: vcge.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcgeq_s16(int16x8_t a, int16x8_t b) {
+ return vcgeq_s16(a, b);
+}
+
+// CHECK: test_vcgeq_s32
+// CHECK: vcge.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgeq_s32(int32x4_t a, int32x4_t b) {
+ return vcgeq_s32(a, b);
+}
+
+// CHECK: test_vcgeq_f32
+// CHECK: vcge.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgeq_f32(float32x4_t a, float32x4_t b) {
+ return vcgeq_f32(a, b);
+}
+
+// CHECK: test_vcgeq_u8
+// CHECK: vcge.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcgeq_u8(uint8x16_t a, uint8x16_t b) {
+ return vcgeq_u8(a, b);
+}
+
+// CHECK: test_vcgeq_u16
+// CHECK: vcge.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcgeq_u16(uint16x8_t a, uint16x8_t b) {
+ return vcgeq_u16(a, b);
+}
+
+// CHECK: test_vcgeq_u32
+// CHECK: vcge.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgeq_u32(uint32x4_t a, uint32x4_t b) {
+ return vcgeq_u32(a, b);
+}
+
+
+// CHECK: test_vcgt_s8
+// CHECK: vcgt.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcgt_s8(int8x8_t a, int8x8_t b) {
+ return vcgt_s8(a, b);
+}
+
+// CHECK: test_vcgt_s16
+// CHECK: vcgt.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcgt_s16(int16x4_t a, int16x4_t b) {
+ return vcgt_s16(a, b);
+}
+
+// CHECK: test_vcgt_s32
+// CHECK: vcgt.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcgt_s32(int32x2_t a, int32x2_t b) {
+ return vcgt_s32(a, b);
+}
+
+// CHECK: test_vcgt_f32
+// CHECK: vcgt.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcgt_f32(float32x2_t a, float32x2_t b) {
+ return vcgt_f32(a, b);
+}
+
+// CHECK: test_vcgt_u8
+// CHECK: vcgt.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcgt_u8(uint8x8_t a, uint8x8_t b) {
+ return vcgt_u8(a, b);
+}
+
+// CHECK: test_vcgt_u16
+// CHECK: vcgt.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcgt_u16(uint16x4_t a, uint16x4_t b) {
+ return vcgt_u16(a, b);
+}
+
+// CHECK: test_vcgt_u32
+// CHECK: vcgt.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcgt_u32(uint32x2_t a, uint32x2_t b) {
+ return vcgt_u32(a, b);
+}
+
+// CHECK: test_vcgtq_s8
+// CHECK: vcgt.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcgtq_s8(int8x16_t a, int8x16_t b) {
+ return vcgtq_s8(a, b);
+}
+
+// CHECK: test_vcgtq_s16
+// CHECK: vcgt.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcgtq_s16(int16x8_t a, int16x8_t b) {
+ return vcgtq_s16(a, b);
+}
+
+// CHECK: test_vcgtq_s32
+// CHECK: vcgt.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgtq_s32(int32x4_t a, int32x4_t b) {
+ return vcgtq_s32(a, b);
+}
+
+// CHECK: test_vcgtq_f32
+// CHECK: vcgt.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgtq_f32(float32x4_t a, float32x4_t b) {
+ return vcgtq_f32(a, b);
+}
+
+// CHECK: test_vcgtq_u8
+// CHECK: vcgt.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcgtq_u8(uint8x16_t a, uint8x16_t b) {
+ return vcgtq_u8(a, b);
+}
+
+// CHECK: test_vcgtq_u16
+// CHECK: vcgt.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcgtq_u16(uint16x8_t a, uint16x8_t b) {
+ return vcgtq_u16(a, b);
+}
+
+// CHECK: test_vcgtq_u32
+// CHECK: vcgt.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcgtq_u32(uint32x4_t a, uint32x4_t b) {
+ return vcgtq_u32(a, b);
+}
+
+
+// CHECK: test_vcle_s8
+// CHECK: vcge.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcle_s8(int8x8_t a, int8x8_t b) {
+ return vcle_s8(a, b);
+}
+
+// CHECK: test_vcle_s16
+// CHECK: vcge.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcle_s16(int16x4_t a, int16x4_t b) {
+ return vcle_s16(a, b);
+}
+
+// CHECK: test_vcle_s32
+// CHECK: vcge.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcle_s32(int32x2_t a, int32x2_t b) {
+ return vcle_s32(a, b);
+}
+
+// CHECK: test_vcle_f32
+// CHECK: vcge.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcle_f32(float32x2_t a, float32x2_t b) {
+ return vcle_f32(a, b);
+}
+
+// CHECK: test_vcle_u8
+// CHECK: vcge.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcle_u8(uint8x8_t a, uint8x8_t b) {
+ return vcle_u8(a, b);
+}
+
+// CHECK: test_vcle_u16
+// CHECK: vcge.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vcle_u16(uint16x4_t a, uint16x4_t b) {
+ return vcle_u16(a, b);
+}
+
+// CHECK: test_vcle_u32
+// CHECK: vcge.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcle_u32(uint32x2_t a, uint32x2_t b) {
+ return vcle_u32(a, b);
+}
+
+// CHECK: test_vcleq_s8
+// CHECK: vcge.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcleq_s8(int8x16_t a, int8x16_t b) {
+ return vcleq_s8(a, b);
+}
+
+// CHECK: test_vcleq_s16
+// CHECK: vcge.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcleq_s16(int16x8_t a, int16x8_t b) {
+ return vcleq_s16(a, b);
+}
+
+// CHECK: test_vcleq_s32
+// CHECK: vcge.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcleq_s32(int32x4_t a, int32x4_t b) {
+ return vcleq_s32(a, b);
+}
+
+// CHECK: test_vcleq_f32
+// CHECK: vcge.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcleq_f32(float32x4_t a, float32x4_t b) {
+ return vcleq_f32(a, b);
+}
+
+// CHECK: test_vcleq_u8
+// CHECK: vcge.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcleq_u8(uint8x16_t a, uint8x16_t b) {
+ return vcleq_u8(a, b);
+}
+
+// CHECK: test_vcleq_u16
+// CHECK: vcge.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcleq_u16(uint16x8_t a, uint16x8_t b) {
+ return vcleq_u16(a, b);
+}
+
+// CHECK: test_vcleq_u32
+// CHECK: vcge.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcleq_u32(uint32x4_t a, uint32x4_t b) {
+ return vcleq_u32(a, b);
+}
+
+
+// CHECK: test_vcls_s8
+// CHECK: vcls.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vcls_s8(int8x8_t a) {
+ return vcls_s8(a);
+}
+
+// CHECK: test_vcls_s16
+// CHECK: vcls.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vcls_s16(int16x4_t a) {
+ return vcls_s16(a);
+}
+
+// CHECK: test_vcls_s32
+// CHECK: vcls.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vcls_s32(int32x2_t a) {
+ return vcls_s32(a);
+}
+
+// CHECK: test_vclsq_s8
+// CHECK: vcls.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vclsq_s8(int8x16_t a) {
+ return vclsq_s8(a);
+}
+
+// CHECK: test_vclsq_s16
+// CHECK: vcls.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vclsq_s16(int16x8_t a) {
+ return vclsq_s16(a);
+}
+
+// CHECK: test_vclsq_s32
+// CHECK: vcls.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vclsq_s32(int32x4_t a) {
+ return vclsq_s32(a);
+}
+
+
+// CHECK: test_vclt_s8
+// CHECK: vcgt.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vclt_s8(int8x8_t a, int8x8_t b) {
+ return vclt_s8(a, b);
+}
+
+// CHECK: test_vclt_s16
+// CHECK: vcgt.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vclt_s16(int16x4_t a, int16x4_t b) {
+ return vclt_s16(a, b);
+}
+
+// CHECK: test_vclt_s32
+// CHECK: vcgt.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vclt_s32(int32x2_t a, int32x2_t b) {
+ return vclt_s32(a, b);
+}
+
+// CHECK: test_vclt_f32
+// CHECK: vcgt.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vclt_f32(float32x2_t a, float32x2_t b) {
+ return vclt_f32(a, b);
+}
+
+// CHECK: test_vclt_u8
+// CHECK: vcgt.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vclt_u8(uint8x8_t a, uint8x8_t b) {
+ return vclt_u8(a, b);
+}
+
+// CHECK: test_vclt_u16
+// CHECK: vcgt.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vclt_u16(uint16x4_t a, uint16x4_t b) {
+ return vclt_u16(a, b);
+}
+
+// CHECK: test_vclt_u32
+// CHECK: vcgt.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vclt_u32(uint32x2_t a, uint32x2_t b) {
+ return vclt_u32(a, b);
+}
+
+// CHECK: test_vcltq_s8
+// CHECK: vcgt.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcltq_s8(int8x16_t a, int8x16_t b) {
+ return vcltq_s8(a, b);
+}
+
+// CHECK: test_vcltq_s16
+// CHECK: vcgt.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcltq_s16(int16x8_t a, int16x8_t b) {
+ return vcltq_s16(a, b);
+}
+
+// CHECK: test_vcltq_s32
+// CHECK: vcgt.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcltq_s32(int32x4_t a, int32x4_t b) {
+ return vcltq_s32(a, b);
+}
+
+// CHECK: test_vcltq_f32
+// CHECK: vcgt.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcltq_f32(float32x4_t a, float32x4_t b) {
+ return vcltq_f32(a, b);
+}
+
+// CHECK: test_vcltq_u8
+// CHECK: vcgt.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcltq_u8(uint8x16_t a, uint8x16_t b) {
+ return vcltq_u8(a, b);
+}
+
+// CHECK: test_vcltq_u16
+// CHECK: vcgt.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vcltq_u16(uint16x8_t a, uint16x8_t b) {
+ return vcltq_u16(a, b);
+}
+
+// CHECK: test_vcltq_u32
+// CHECK: vcgt.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcltq_u32(uint32x4_t a, uint32x4_t b) {
+ return vcltq_u32(a, b);
+}
+
+
+// CHECK: test_vclz_s8
+// CHECK: vclz.i8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vclz_s8(int8x8_t a) {
+ return vclz_s8(a);
+}
+
+// CHECK: test_vclz_s16
+// CHECK: vclz.i16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vclz_s16(int16x4_t a) {
+ return vclz_s16(a);
+}
+
+// CHECK: test_vclz_s32
+// CHECK: vclz.i32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vclz_s32(int32x2_t a) {
+ return vclz_s32(a);
+}
+
+// CHECK: test_vclz_u8
+// CHECK: vclz.i8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vclz_u8(uint8x8_t a) {
+ return vclz_u8(a);
+}
+
+// CHECK: test_vclz_u16
+// CHECK: vclz.i16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vclz_u16(uint16x4_t a) {
+ return vclz_u16(a);
+}
+
+// CHECK: test_vclz_u32
+// CHECK: vclz.i32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vclz_u32(uint32x2_t a) {
+ return vclz_u32(a);
+}
+
+// CHECK: test_vclzq_s8
+// CHECK: vclz.i8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vclzq_s8(int8x16_t a) {
+ return vclzq_s8(a);
+}
+
+// CHECK: test_vclzq_s16
+// CHECK: vclz.i16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vclzq_s16(int16x8_t a) {
+ return vclzq_s16(a);
+}
+
+// CHECK: test_vclzq_s32
+// CHECK: vclz.i32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vclzq_s32(int32x4_t a) {
+ return vclzq_s32(a);
+}
+
+// CHECK: test_vclzq_u8
+// CHECK: vclz.i8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vclzq_u8(uint8x16_t a) {
+ return vclzq_u8(a);
+}
+
+// CHECK: test_vclzq_u16
+// CHECK: vclz.i16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vclzq_u16(uint16x8_t a) {
+ return vclzq_u16(a);
+}
+
+// CHECK: test_vclzq_u32
+// CHECK: vclz.i32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vclzq_u32(uint32x4_t a) {
+ return vclzq_u32(a);
+}
+
+
+// CHECK: test_vcnt_u8
+// CHECK: vcnt.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vcnt_u8(uint8x8_t a) {
+ return vcnt_u8(a);
+}
+
+// CHECK: test_vcnt_s8
+// CHECK: vcnt.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vcnt_s8(int8x8_t a) {
+ return vcnt_s8(a);
+}
+
+// CHECK: test_vcnt_p8
+// CHECK: vcnt.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vcnt_p8(poly8x8_t a) {
+ return vcnt_p8(a);
+}
+
+// CHECK: test_vcntq_u8
+// CHECK: vcnt.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vcntq_u8(uint8x16_t a) {
+ return vcntq_u8(a);
+}
+
+// CHECK: test_vcntq_s8
+// CHECK: vcnt.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vcntq_s8(int8x16_t a) {
+ return vcntq_s8(a);
+}
+
+// CHECK: test_vcntq_p8
+// CHECK: vcnt.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vcntq_p8(poly8x16_t a) {
+ return vcntq_p8(a);
+}
+
+
+// CHECK: test_vcombine_s8
+int8x16_t test_vcombine_s8(int8x8_t a, int8x8_t b) {
+ return vcombine_s8(a, b);
+}
+
+// CHECK: test_vcombine_s16
+int16x8_t test_vcombine_s16(int16x4_t a, int16x4_t b) {
+ return vcombine_s16(a, b);
+}
+
+// CHECK: test_vcombine_s32
+int32x4_t test_vcombine_s32(int32x2_t a, int32x2_t b) {
+ return vcombine_s32(a, b);
+}
+
+// CHECK: test_vcombine_s64
+int64x2_t test_vcombine_s64(int64x1_t a, int64x1_t b) {
+ return vcombine_s64(a, b);
+}
+
+// CHECK: test_vcombine_f16
+float16x8_t test_vcombine_f16(float16x4_t a, float16x4_t b) {
+ return vcombine_f16(a, b);
+}
+
+// CHECK: test_vcombine_f32
+float32x4_t test_vcombine_f32(float32x2_t a, float32x2_t b) {
+ return vcombine_f32(a, b);
+}
+
+// CHECK: test_vcombine_u8
+uint8x16_t test_vcombine_u8(uint8x8_t a, uint8x8_t b) {
+ return vcombine_u8(a, b);
+}
+
+// CHECK: test_vcombine_u16
+uint16x8_t test_vcombine_u16(uint16x4_t a, uint16x4_t b) {
+ return vcombine_u16(a, b);
+}
+
+// CHECK: test_vcombine_u32
+uint32x4_t test_vcombine_u32(uint32x2_t a, uint32x2_t b) {
+ return vcombine_u32(a, b);
+}
+
+// CHECK: test_vcombine_u64
+uint64x2_t test_vcombine_u64(uint64x1_t a, uint64x1_t b) {
+ return vcombine_u64(a, b);
+}
+
+// CHECK: test_vcombine_p8
+poly8x16_t test_vcombine_p8(poly8x8_t a, poly8x8_t b) {
+ return vcombine_p8(a, b);
+}
+
+// CHECK: test_vcombine_p16
+poly16x8_t test_vcombine_p16(poly16x4_t a, poly16x4_t b) {
+ return vcombine_p16(a, b);
+}
+
+
+// CHECK: test_vcreate_s8
+int8x8_t test_vcreate_s8(uint64_t a) {
+ return vcreate_s8(a);
+}
+
+// CHECK: test_vcreate_s16
+int16x4_t test_vcreate_s16(uint64_t a) {
+ return vcreate_s16(a);
+}
+
+// CHECK: test_vcreate_s32
+int32x2_t test_vcreate_s32(uint64_t a) {
+ return vcreate_s32(a);
+}
+
+// CHECK: test_vcreate_f16
+float16x4_t test_vcreate_f16(uint64_t a) {
+ return vcreate_f16(a);
+}
+
+// CHECK: test_vcreate_f32
+float32x2_t test_vcreate_f32(uint64_t a) {
+ return vcreate_f32(a);
+}
+
+// CHECK: test_vcreate_u8
+uint8x8_t test_vcreate_u8(uint64_t a) {
+ return vcreate_u8(a);
+}
+
+// CHECK: test_vcreate_u16
+uint16x4_t test_vcreate_u16(uint64_t a) {
+ return vcreate_u16(a);
+}
+
+// CHECK: test_vcreate_u32
+uint32x2_t test_vcreate_u32(uint64_t a) {
+ return vcreate_u32(a);
+}
+
+// CHECK: test_vcreate_u64
+uint64x1_t test_vcreate_u64(uint64_t a) {
+ return vcreate_u64(a);
+}
+
+// CHECK: test_vcreate_p8
+poly8x8_t test_vcreate_p8(uint64_t a) {
+ return vcreate_p8(a);
+}
+
+// CHECK: test_vcreate_p16
+poly16x4_t test_vcreate_p16(uint64_t a) {
+ return vcreate_p16(a);
+}
+
+// CHECK: test_vcreate_s64
+int64x1_t test_vcreate_s64(uint64_t a) {
+ return vcreate_s64(a);
+}
+
+
+// CHECK: test_vcvt_f16_f32
+// CHECK: vcvt.f16.f32 d{{[0-9]+}}, q{{[0-9]+}}
+float16x4_t test_vcvt_f16_f32(float32x4_t a) {
+ return vcvt_f16_f32(a);
+}
+
+
+// CHECK: test_vcvt_f32_s32
+// CHECK: vcvt.f32.s32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vcvt_f32_s32(int32x2_t a) {
+ return vcvt_f32_s32(a);
+}
+
+// CHECK: test_vcvt_f32_u32
+// CHECK: vcvt.f32.u32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vcvt_f32_u32(uint32x2_t a) {
+ return vcvt_f32_u32(a);
+}
+
+// CHECK: test_vcvtq_f32_s32
+// CHECK: vcvt.f32.s32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vcvtq_f32_s32(int32x4_t a) {
+ return vcvtq_f32_s32(a);
+}
+
+// CHECK: test_vcvtq_f32_u32
+// CHECK: vcvt.f32.u32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vcvtq_f32_u32(uint32x4_t a) {
+ return vcvtq_f32_u32(a);
+}
+
+
+// CHECK: test_vcvt_f32_f16
+// CHECK: vcvt.f32.f16
+float32x4_t test_vcvt_f32_f16(float16x4_t a) {
+ return vcvt_f32_f16(a);
+}
+
+
+// CHECK: test_vcvt_n_f32_s32
+// CHECK: vcvt.f32.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+float32x2_t test_vcvt_n_f32_s32(int32x2_t a) {
+ return vcvt_n_f32_s32(a, 1);
+}
+
+// CHECK: test_vcvt_n_f32_u32
+// CHECK: vcvt.f32.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+float32x2_t test_vcvt_n_f32_u32(uint32x2_t a) {
+ return vcvt_n_f32_u32(a, 1);
+}
+
+// CHECK: test_vcvtq_n_f32_s32
+// CHECK: vcvt.f32.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+float32x4_t test_vcvtq_n_f32_s32(int32x4_t a) {
+ return vcvtq_n_f32_s32(a, 3);
+}
+
+// CHECK: test_vcvtq_n_f32_u32
+// CHECK: vcvt.f32.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+float32x4_t test_vcvtq_n_f32_u32(uint32x4_t a) {
+ return vcvtq_n_f32_u32(a, 3);
+}
+
+
+// CHECK: test_vcvt_n_s32_f32
+// CHECK: vcvt.s32.f32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vcvt_n_s32_f32(float32x2_t a) {
+ return vcvt_n_s32_f32(a, 1);
+}
+
+// CHECK: test_vcvtq_n_s32_f32
+// CHECK: vcvt.s32.f32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vcvtq_n_s32_f32(float32x4_t a) {
+ return vcvtq_n_s32_f32(a, 3);
+}
+
+
+// CHECK: test_vcvt_n_u32_f32
+// CHECK: vcvt.u32.f32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vcvt_n_u32_f32(float32x2_t a) {
+ return vcvt_n_u32_f32(a, 1);
+}
+
+// CHECK: test_vcvtq_n_u32_f32
+// CHECK: vcvt.u32.f32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vcvtq_n_u32_f32(float32x4_t a) {
+ return vcvtq_n_u32_f32(a, 3);
+}
+
+
+// CHECK: test_vcvt_s32_f32
+// CHECK: vcvt.s32.f32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vcvt_s32_f32(float32x2_t a) {
+ return vcvt_s32_f32(a);
+}
+
+// CHECK: test_vcvtq_s32_f32
+// CHECK: vcvt.s32.f32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vcvtq_s32_f32(float32x4_t a) {
+ return vcvtq_s32_f32(a);
+}
+
+
+// CHECK: test_vcvt_u32_f32
+// CHECK: vcvt.u32.f32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vcvt_u32_f32(float32x2_t a) {
+ return vcvt_u32_f32(a);
+}
+
+// CHECK: test_vcvtq_u32_f32
+// CHECK: vcvt.u32.f32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vcvtq_u32_f32(float32x4_t a) {
+ return vcvtq_u32_f32(a);
+}
+
+
+// CHECK: test_vdup_lane_u8
+// CHECK: vdup.8 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint8x8_t test_vdup_lane_u8(uint8x8_t a) {
+ return vdup_lane_u8(a, 7);
+}
+
+// CHECK: test_vdup_lane_u16
+// CHECK: vdup.16 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x4_t test_vdup_lane_u16(uint16x4_t a) {
+ return vdup_lane_u16(a, 3);
+}
+
+// CHECK: test_vdup_lane_u32
+// CHECK: vdup.32 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x2_t test_vdup_lane_u32(uint32x2_t a) {
+ return vdup_lane_u32(a, 1);
+}
+
+// CHECK: test_vdup_lane_s8
+// CHECK: vdup.8 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int8x8_t test_vdup_lane_s8(int8x8_t a) {
+ return vdup_lane_s8(a, 7);
+}
+
+// CHECK: test_vdup_lane_s16
+// CHECK: vdup.16 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vdup_lane_s16(int16x4_t a) {
+ return vdup_lane_s16(a, 3);
+}
+
+// CHECK: test_vdup_lane_s32
+// CHECK: vdup.32 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vdup_lane_s32(int32x2_t a) {
+ return vdup_lane_s32(a, 1);
+}
+
+// CHECK: test_vdup_lane_p8
+// CHECK: vdup.8 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+poly8x8_t test_vdup_lane_p8(poly8x8_t a) {
+ return vdup_lane_p8(a, 7);
+}
+
+// CHECK: test_vdup_lane_p16
+// CHECK: vdup.16 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+poly16x4_t test_vdup_lane_p16(poly16x4_t a) {
+ return vdup_lane_p16(a, 3);
+}
+
+// CHECK: test_vdup_lane_f32
+// CHECK: vdup.32 d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+float32x2_t test_vdup_lane_f32(float32x2_t a) {
+ return vdup_lane_f32(a, 1);
+}
+
+// CHECK: test_vdupq_lane_u8
+// CHECK: vdup.8 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint8x16_t test_vdupq_lane_u8(uint8x8_t a) {
+ return vdupq_lane_u8(a, 7);
+}
+
+// CHECK: test_vdupq_lane_u16
+// CHECK: vdup.16 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x8_t test_vdupq_lane_u16(uint16x4_t a) {
+ return vdupq_lane_u16(a, 3);
+}
+
+// CHECK: test_vdupq_lane_u32
+// CHECK: vdup.32 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vdupq_lane_u32(uint32x2_t a) {
+ return vdupq_lane_u32(a, 1);
+}
+
+// CHECK: test_vdupq_lane_s8
+// CHECK: vdup.8 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int8x16_t test_vdupq_lane_s8(int8x8_t a) {
+ return vdupq_lane_s8(a, 7);
+}
+
+// CHECK: test_vdupq_lane_s16
+// CHECK: vdup.16 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vdupq_lane_s16(int16x4_t a) {
+ return vdupq_lane_s16(a, 3);
+}
+
+// CHECK: test_vdupq_lane_s32
+// CHECK: vdup.32 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vdupq_lane_s32(int32x2_t a) {
+ return vdupq_lane_s32(a, 1);
+}
+
+// CHECK: test_vdupq_lane_p8
+// CHECK: vdup.8 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+poly8x16_t test_vdupq_lane_p8(poly8x8_t a) {
+ return vdupq_lane_p8(a, 7);
+}
+
+// CHECK: test_vdupq_lane_p16
+// CHECK: vdup.16 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+poly16x8_t test_vdupq_lane_p16(poly16x4_t a) {
+ return vdupq_lane_p16(a, 3);
+}
+
+// CHECK: test_vdupq_lane_f32
+// CHECK: vdup.32 q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+float32x4_t test_vdupq_lane_f32(float32x2_t a) {
+ return vdupq_lane_f32(a, 1);
+}
+
+// CHECK: test_vdup_lane_s64
+int64x1_t test_vdup_lane_s64(int64x1_t a) {
+ return vdup_lane_s64(a, 0);
+}
+
+// CHECK: test_vdup_lane_u64
+uint64x1_t test_vdup_lane_u64(uint64x1_t a) {
+ return vdup_lane_u64(a, 0);
+}
+
+// CHECK: test_vdupq_lane_s64
+// CHECK: {{vmov|vdup}}
+int64x2_t test_vdupq_lane_s64(int64x1_t a) {
+ return vdupq_lane_s64(a, 0);
+}
+
+// CHECK: test_vdupq_lane_u64
+// CHECK: {{vmov|vdup}}
+uint64x2_t test_vdupq_lane_u64(uint64x1_t a) {
+ return vdupq_lane_u64(a, 0);
+}
+
+
+// CHECK: test_vdup_n_u8
+// CHECK: vmov
+uint8x8_t test_vdup_n_u8(uint8_t a) {
+ return vdup_n_u8(a);
+}
+
+// CHECK: test_vdup_n_u16
+// CHECK: vmov
+uint16x4_t test_vdup_n_u16(uint16_t a) {
+ return vdup_n_u16(a);
+}
+
+// CHECK: test_vdup_n_u32
+// CHECK: vmov
+uint32x2_t test_vdup_n_u32(uint32_t a) {
+ return vdup_n_u32(a);
+}
+
+// CHECK: test_vdup_n_s8
+// CHECK: vmov
+int8x8_t test_vdup_n_s8(int8_t a) {
+ return vdup_n_s8(a);
+}
+
+// CHECK: test_vdup_n_s16
+// CHECK: vmov
+int16x4_t test_vdup_n_s16(int16_t a) {
+ return vdup_n_s16(a);
+}
+
+// CHECK: test_vdup_n_s32
+// CHECK: vmov
+int32x2_t test_vdup_n_s32(int32_t a) {
+ return vdup_n_s32(a);
+}
+
+// CHECK: test_vdup_n_p8
+// CHECK: vmov
+poly8x8_t test_vdup_n_p8(poly8_t a) {
+ return vdup_n_p8(a);
+}
+
+// CHECK: test_vdup_n_p16
+// CHECK: vmov
+poly16x4_t test_vdup_n_p16(poly16_t a) {
+ return vdup_n_p16(a);
+}
+
+// CHECK: test_vdup_n_f32
+// CHECK: vmov
+float32x2_t test_vdup_n_f32(float32_t a) {
+ return vdup_n_f32(a);
+}
+
+// CHECK: test_vdupq_n_u8
+// CHECK: vmov
+uint8x16_t test_vdupq_n_u8(uint8_t a) {
+ return vdupq_n_u8(a);
+}
+
+// CHECK: test_vdupq_n_u16
+// CHECK: vmov
+uint16x8_t test_vdupq_n_u16(uint16_t a) {
+ return vdupq_n_u16(a);
+}
+
+// CHECK: test_vdupq_n_u32
+// CHECK: vmov
+uint32x4_t test_vdupq_n_u32(uint32_t a) {
+ return vdupq_n_u32(a);
+}
+
+// CHECK: test_vdupq_n_s8
+// CHECK: vmov
+int8x16_t test_vdupq_n_s8(int8_t a) {
+ return vdupq_n_s8(a);
+}
+
+// CHECK: test_vdupq_n_s16
+// CHECK: vmov
+int16x8_t test_vdupq_n_s16(int16_t a) {
+ return vdupq_n_s16(a);
+}
+
+// CHECK: test_vdupq_n_s32
+// CHECK: vmov
+int32x4_t test_vdupq_n_s32(int32_t a) {
+ return vdupq_n_s32(a);
+}
+
+// CHECK: test_vdupq_n_p8
+// CHECK: vmov
+poly8x16_t test_vdupq_n_p8(poly8_t a) {
+ return vdupq_n_p8(a);
+}
+
+// CHECK: test_vdupq_n_p16
+// CHECK: vmov
+poly16x8_t test_vdupq_n_p16(poly16_t a) {
+ return vdupq_n_p16(a);
+}
+
+// CHECK: test_vdupq_n_f32
+// CHECK: vmov
+float32x4_t test_vdupq_n_f32(float32_t a) {
+ return vdupq_n_f32(a);
+}
+
+// CHECK: test_vdup_n_s64
+// CHECK: vmov
+int64x1_t test_vdup_n_s64(int64_t a) {
+ return vdup_n_s64(a);
+}
+
+// CHECK: test_vdup_n_u64
+// CHECK: vmov
+uint64x1_t test_vdup_n_u64(uint64_t a) {
+ return vdup_n_u64(a);
+}
+
+// CHECK: test_vdupq_n_s64
+// CHECK: vmov
+int64x2_t test_vdupq_n_s64(int64_t a) {
+ return vdupq_n_s64(a);
+}
+
+// CHECK: test_vdupq_n_u64
+// CHECK: vmov
+uint64x2_t test_vdupq_n_u64(uint64_t a) {
+ return vdupq_n_u64(a);
+}
+
+
+// CHECK: test_veor_s8
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_veor_s8(int8x8_t a, int8x8_t b) {
+ return veor_s8(a, b);
+}
+
+// CHECK: test_veor_s16
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_veor_s16(int16x4_t a, int16x4_t b) {
+ return veor_s16(a, b);
+}
+
+// CHECK: test_veor_s32
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_veor_s32(int32x2_t a, int32x2_t b) {
+ return veor_s32(a, b);
+}
+
+// CHECK: test_veor_s64
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_veor_s64(int64x1_t a, int64x1_t b) {
+ return veor_s64(a, b);
+}
+
+// CHECK: test_veor_u8
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_veor_u8(uint8x8_t a, uint8x8_t b) {
+ return veor_u8(a, b);
+}
+
+// CHECK: test_veor_u16
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_veor_u16(uint16x4_t a, uint16x4_t b) {
+ return veor_u16(a, b);
+}
+
+// CHECK: test_veor_u32
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_veor_u32(uint32x2_t a, uint32x2_t b) {
+ return veor_u32(a, b);
+}
+
+// CHECK: test_veor_u64
+// CHECK: veor d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_veor_u64(uint64x1_t a, uint64x1_t b) {
+ return veor_u64(a, b);
+}
+
+// CHECK: test_veorq_s8
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_veorq_s8(int8x16_t a, int8x16_t b) {
+ return veorq_s8(a, b);
+}
+
+// CHECK: test_veorq_s16
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_veorq_s16(int16x8_t a, int16x8_t b) {
+ return veorq_s16(a, b);
+}
+
+// CHECK: test_veorq_s32
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_veorq_s32(int32x4_t a, int32x4_t b) {
+ return veorq_s32(a, b);
+}
+
+// CHECK: test_veorq_s64
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_veorq_s64(int64x2_t a, int64x2_t b) {
+ return veorq_s64(a, b);
+}
+
+// CHECK: test_veorq_u8
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_veorq_u8(uint8x16_t a, uint8x16_t b) {
+ return veorq_u8(a, b);
+}
+
+// CHECK: test_veorq_u16
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_veorq_u16(uint16x8_t a, uint16x8_t b) {
+ return veorq_u16(a, b);
+}
+
+// CHECK: test_veorq_u32
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_veorq_u32(uint32x4_t a, uint32x4_t b) {
+ return veorq_u32(a, b);
+}
+
+// CHECK: test_veorq_u64
+// CHECK: veor q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_veorq_u64(uint64x2_t a, uint64x2_t b) {
+ return veorq_u64(a, b);
+}
+
+
+// CHECK: test_vext_s8
+// CHECK: vext.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vext_s8(int8x8_t a, int8x8_t b) {
+ return vext_s8(a, b, 7);
+}
+
+// CHECK: test_vext_u8
+// CHECK: vext.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vext_u8(uint8x8_t a, uint8x8_t b) {
+ return vext_u8(a, b, 7);
+}
+
+// CHECK: test_vext_p8
+// CHECK: vext.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly8x8_t test_vext_p8(poly8x8_t a, poly8x8_t b) {
+ return vext_p8(a, b, 7);
+}
+
+// CHECK: test_vext_s16
+// CHECK: vext.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vext_s16(int16x4_t a, int16x4_t b) {
+ return vext_s16(a, b, 3);
+}
+
+// CHECK: test_vext_u16
+// CHECK: vext.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vext_u16(uint16x4_t a, uint16x4_t b) {
+ return vext_u16(a, b, 3);
+}
+
+// CHECK: test_vext_p16
+// CHECK: vext.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly16x4_t test_vext_p16(poly16x4_t a, poly16x4_t b) {
+ return vext_p16(a, b, 3);
+}
+
+// CHECK: test_vext_s32
+// CHECK: vext.32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vext_s32(int32x2_t a, int32x2_t b) {
+ return vext_s32(a, b, 1);
+}
+
+// CHECK: test_vext_u32
+// CHECK: vext.32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vext_u32(uint32x2_t a, uint32x2_t b) {
+ return vext_u32(a, b, 1);
+}
+
+// CHECK: test_vext_s64
+int64x1_t test_vext_s64(int64x1_t a, int64x1_t b) {
+ return vext_s64(a, b, 0);
+}
+
+// CHECK: test_vext_u64
+uint64x1_t test_vext_u64(uint64x1_t a, uint64x1_t b) {
+ return vext_u64(a, b, 0);
+}
+
+// CHECK: test_vext_f32
+// CHECK: vext.32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+float32x2_t test_vext_f32(float32x2_t a, float32x2_t b) {
+ return vext_f32(a, b, 1);
+}
+
+// CHECK: test_vextq_s8
+// CHECK: vext.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vextq_s8(int8x16_t a, int8x16_t b) {
+ return vextq_s8(a, b, 15);
+}
+
+// CHECK: test_vextq_u8
+// CHECK: vext.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vextq_u8(uint8x16_t a, uint8x16_t b) {
+ return vextq_u8(a, b, 15);
+}
+
+// CHECK: test_vextq_p8
+// CHECK: vext.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly8x16_t test_vextq_p8(poly8x16_t a, poly8x16_t b) {
+ return vextq_p8(a, b, 15);
+}
+
+// CHECK: test_vextq_s16
+// CHECK: vext.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vextq_s16(int16x8_t a, int16x8_t b) {
+ return vextq_s16(a, b, 7);
+}
+
+// CHECK: test_vextq_u16
+// CHECK: vext.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vextq_u16(uint16x8_t a, uint16x8_t b) {
+ return vextq_u16(a, b, 7);
+}
+
+// CHECK: test_vextq_p16
+// CHECK: vext.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly16x8_t test_vextq_p16(poly16x8_t a, poly16x8_t b) {
+ return vextq_p16(a, b, 7);
+}
+
+// CHECK: test_vextq_s32
+// CHECK: vext.32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vextq_s32(int32x4_t a, int32x4_t b) {
+ return vextq_s32(a, b, 3);
+}
+
+// CHECK: test_vextq_u32
+// CHECK: vext.32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vextq_u32(uint32x4_t a, uint32x4_t b) {
+ return vextq_u32(a, b, 3);
+}
+
+// CHECK: test_vextq_s64
+// CHECK: {{vmov|vdup}}
+int64x2_t test_vextq_s64(int64x2_t a, int64x2_t b) {
+ return vextq_s64(a, b, 1);
+}
+
+// CHECK: test_vextq_u64
+// CHECK: {{vmov|vdup}}
+uint64x2_t test_vextq_u64(uint64x2_t a, uint64x2_t b) {
+ return vextq_u64(a, b, 1);
+}
+
+// CHECK: test_vextq_f32
+// CHECK: vext.32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+float32x4_t test_vextq_f32(float32x4_t a, float32x4_t b) {
+ return vextq_f32(a, b, 3);
+}
+
+
+// CHECK: test_vfma_f32
+// CHECK: vfma.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
+ return vfma_f32(a, b, c);
+}
+
+// CHECK: test_vfmaq_f32
+// CHECK: vfma.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vfmaq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
+ return vfmaq_f32(a, b, c);
+}
+
+
+// CHECK: test_vget_high_s8
+int8x8_t test_vget_high_s8(int8x16_t a) {
+ return vget_high_s8(a);
+}
+
+// CHECK: test_vget_high_s16
+int16x4_t test_vget_high_s16(int16x8_t a) {
+ return vget_high_s16(a);
+}
+
+// CHECK: test_vget_high_s32
+int32x2_t test_vget_high_s32(int32x4_t a) {
+ return vget_high_s32(a);
+}
+
+// CHECK: test_vget_high_s64
+int64x1_t test_vget_high_s64(int64x2_t a) {
+ return vget_high_s64(a);
+}
+
+// CHECK: test_vget_high_f16
+float16x4_t test_vget_high_f16(float16x8_t a) {
+ return vget_high_f16(a);
+}
+
+// CHECK: test_vget_high_f32
+float32x2_t test_vget_high_f32(float32x4_t a) {
+ return vget_high_f32(a);
+}
+
+// CHECK: test_vget_high_u8
+uint8x8_t test_vget_high_u8(uint8x16_t a) {
+ return vget_high_u8(a);
+}
+
+// CHECK: test_vget_high_u16
+uint16x4_t test_vget_high_u16(uint16x8_t a) {
+ return vget_high_u16(a);
+}
+
+// CHECK: test_vget_high_u32
+uint32x2_t test_vget_high_u32(uint32x4_t a) {
+ return vget_high_u32(a);
+}
+
+// CHECK: test_vget_high_u64
+uint64x1_t test_vget_high_u64(uint64x2_t a) {
+ return vget_high_u64(a);
+}
+
+// CHECK: test_vget_high_p8
+poly8x8_t test_vget_high_p8(poly8x16_t a) {
+ return vget_high_p8(a);
+}
+
+// CHECK: test_vget_high_p16
+poly16x4_t test_vget_high_p16(poly16x8_t a) {
+ return vget_high_p16(a);
+}
+
+
+// CHECK: test_vget_lane_u8
+// CHECK: vmov
+uint8_t test_vget_lane_u8(uint8x8_t a) {
+ return vget_lane_u8(a, 7);
+}
+
+// CHECK: test_vget_lane_u16
+// CHECK: vmov
+uint16_t test_vget_lane_u16(uint16x4_t a) {
+ return vget_lane_u16(a, 3);
+}
+
+// CHECK: test_vget_lane_u32
+// CHECK: vmov
+uint32_t test_vget_lane_u32(uint32x2_t a) {
+ return vget_lane_u32(a, 1);
+}
+
+// CHECK: test_vget_lane_s8
+// CHECK: vmov
+int8_t test_vget_lane_s8(int8x8_t a) {
+ return vget_lane_s8(a, 7);
+}
+
+// CHECK: test_vget_lane_s16
+// CHECK: vmov
+int16_t test_vget_lane_s16(int16x4_t a) {
+ return vget_lane_s16(a, 3);
+}
+
+// CHECK: test_vget_lane_s32
+// CHECK: vmov
+int32_t test_vget_lane_s32(int32x2_t a) {
+ return vget_lane_s32(a, 1);
+}
+
+// CHECK: test_vget_lane_p8
+// CHECK: vmov
+poly8_t test_vget_lane_p8(poly8x8_t a) {
+ return vget_lane_p8(a, 7);
+}
+
+// CHECK: test_vget_lane_p16
+// CHECK: vmov
+poly16_t test_vget_lane_p16(poly16x4_t a) {
+ return vget_lane_p16(a, 3);
+}
+
+// CHECK: test_vget_lane_f32
+// CHECK: vmov
+float32_t test_vget_lane_f32(float32x2_t a) {
+ return vget_lane_f32(a, 1);
+}
+
+// CHECK: test_vgetq_lane_u8
+// CHECK: vmov
+uint8_t test_vgetq_lane_u8(uint8x16_t a) {
+ return vgetq_lane_u8(a, 15);
+}
+
+// CHECK: test_vgetq_lane_u16
+// CHECK: vmov
+uint16_t test_vgetq_lane_u16(uint16x8_t a) {
+ return vgetq_lane_u16(a, 7);
+}
+
+// CHECK: test_vgetq_lane_u32
+// CHECK: vmov
+uint32_t test_vgetq_lane_u32(uint32x4_t a) {
+ return vgetq_lane_u32(a, 3);
+}
+
+// CHECK: test_vgetq_lane_s8
+// CHECK: vmov
+int8_t test_vgetq_lane_s8(int8x16_t a) {
+ return vgetq_lane_s8(a, 15);
+}
+
+// CHECK: test_vgetq_lane_s16
+// CHECK: vmov
+int16_t test_vgetq_lane_s16(int16x8_t a) {
+ return vgetq_lane_s16(a, 7);
+}
+
+// CHECK: test_vgetq_lane_s32
+// CHECK: vmov
+int32_t test_vgetq_lane_s32(int32x4_t a) {
+ return vgetq_lane_s32(a, 3);
+}
+
+// CHECK: test_vgetq_lane_p8
+// CHECK: vmov
+poly8_t test_vgetq_lane_p8(poly8x16_t a) {
+ return vgetq_lane_p8(a, 15);
+}
+
+// CHECK: test_vgetq_lane_p16
+// CHECK: vmov
+poly16_t test_vgetq_lane_p16(poly16x8_t a) {
+ return vgetq_lane_p16(a, 7);
+}
+
+// CHECK: test_vgetq_lane_f32
+// CHECK: vmov
+float32_t test_vgetq_lane_f32(float32x4_t a) {
+ return vgetq_lane_f32(a, 3);
+}
+
+// CHECK: test_vget_lane_s64
+// CHECK: vmov
+int64_t test_vget_lane_s64(int64x1_t a) {
+ return vget_lane_s64(a, 0);
+}
+
+// CHECK: test_vget_lane_u64
+// CHECK: vmov
+uint64_t test_vget_lane_u64(uint64x1_t a) {
+ return vget_lane_u64(a, 0);
+}
+
+// CHECK: test_vgetq_lane_s64
+// CHECK: vmov
+int64_t test_vgetq_lane_s64(int64x2_t a) {
+ return vgetq_lane_s64(a, 1);
+}
+
+// CHECK: test_vgetq_lane_u64
+// CHECK: vmov
+uint64_t test_vgetq_lane_u64(uint64x2_t a) {
+ return vgetq_lane_u64(a, 1);
+}
+
+
+// CHECK: test_vget_low_s8
+int8x8_t test_vget_low_s8(int8x16_t a) {
+ return vget_low_s8(a);
+}
+
+// CHECK: test_vget_low_s16
+int16x4_t test_vget_low_s16(int16x8_t a) {
+ return vget_low_s16(a);
+}
+
+// CHECK: test_vget_low_s32
+int32x2_t test_vget_low_s32(int32x4_t a) {
+ return vget_low_s32(a);
+}
+
+// CHECK: test_vget_low_s64
+int64x1_t test_vget_low_s64(int64x2_t a) {
+ return vget_low_s64(a);
+}
+
+// CHECK: test_vget_low_f16
+float16x4_t test_vget_low_f16(float16x8_t a) {
+ return vget_low_f16(a);
+}
+
+// CHECK: test_vget_low_f32
+float32x2_t test_vget_low_f32(float32x4_t a) {
+ return vget_low_f32(a);
+}
+
+// CHECK: test_vget_low_u8
+uint8x8_t test_vget_low_u8(uint8x16_t a) {
+ return vget_low_u8(a);
+}
+
+// CHECK: test_vget_low_u16
+uint16x4_t test_vget_low_u16(uint16x8_t a) {
+ return vget_low_u16(a);
+}
+
+// CHECK: test_vget_low_u32
+uint32x2_t test_vget_low_u32(uint32x4_t a) {
+ return vget_low_u32(a);
+}
+
+// CHECK: test_vget_low_u64
+uint64x1_t test_vget_low_u64(uint64x2_t a) {
+ return vget_low_u64(a);
+}
+
+// CHECK: test_vget_low_p8
+poly8x8_t test_vget_low_p8(poly8x16_t a) {
+ return vget_low_p8(a);
+}
+
+// CHECK: test_vget_low_p16
+poly16x4_t test_vget_low_p16(poly16x8_t a) {
+ return vget_low_p16(a);
+}
+
+
+// CHECK: test_vhadd_s8
+// CHECK: vhadd.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vhadd_s8(int8x8_t a, int8x8_t b) {
+ return vhadd_s8(a, b);
+}
+
+// CHECK: test_vhadd_s16
+// CHECK: vhadd.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vhadd_s16(int16x4_t a, int16x4_t b) {
+ return vhadd_s16(a, b);
+}
+
+// CHECK: test_vhadd_s32
+// CHECK: vhadd.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vhadd_s32(int32x2_t a, int32x2_t b) {
+ return vhadd_s32(a, b);
+}
+
+// CHECK: test_vhadd_u8
+// CHECK: vhadd.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vhadd_u8(uint8x8_t a, uint8x8_t b) {
+ return vhadd_u8(a, b);
+}
+
+// CHECK: test_vhadd_u16
+// CHECK: vhadd.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vhadd_u16(uint16x4_t a, uint16x4_t b) {
+ return vhadd_u16(a, b);
+}
+
+// CHECK: test_vhadd_u32
+// CHECK: vhadd.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vhadd_u32(uint32x2_t a, uint32x2_t b) {
+ return vhadd_u32(a, b);
+}
+
+// CHECK: test_vhaddq_s8
+// CHECK: vhadd.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vhaddq_s8(int8x16_t a, int8x16_t b) {
+ return vhaddq_s8(a, b);
+}
+
+// CHECK: test_vhaddq_s16
+// CHECK: vhadd.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vhaddq_s16(int16x8_t a, int16x8_t b) {
+ return vhaddq_s16(a, b);
+}
+
+// CHECK: test_vhaddq_s32
+// CHECK: vhadd.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vhaddq_s32(int32x4_t a, int32x4_t b) {
+ return vhaddq_s32(a, b);
+}
+
+// CHECK: test_vhaddq_u8
+// CHECK: vhadd.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vhaddq_u8(uint8x16_t a, uint8x16_t b) {
+ return vhaddq_u8(a, b);
+}
+
+// CHECK: test_vhaddq_u16
+// CHECK: vhadd.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vhaddq_u16(uint16x8_t a, uint16x8_t b) {
+ return vhaddq_u16(a, b);
+}
+
+// CHECK: test_vhaddq_u32
+// CHECK: vhadd.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vhaddq_u32(uint32x4_t a, uint32x4_t b) {
+ return vhaddq_u32(a, b);
+}
+
+
+// CHECK: test_vhsub_s8
+// CHECK: vhsub.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vhsub_s8(int8x8_t a, int8x8_t b) {
+ return vhsub_s8(a, b);
+}
+
+// CHECK: test_vhsub_s16
+// CHECK: vhsub.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vhsub_s16(int16x4_t a, int16x4_t b) {
+ return vhsub_s16(a, b);
+}
+
+// CHECK: test_vhsub_s32
+// CHECK: vhsub.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vhsub_s32(int32x2_t a, int32x2_t b) {
+ return vhsub_s32(a, b);
+}
+
+// CHECK: test_vhsub_u8
+// CHECK: vhsub.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vhsub_u8(uint8x8_t a, uint8x8_t b) {
+ return vhsub_u8(a, b);
+}
+
+// CHECK: test_vhsub_u16
+// CHECK: vhsub.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vhsub_u16(uint16x4_t a, uint16x4_t b) {
+ return vhsub_u16(a, b);
+}
+
+// CHECK: test_vhsub_u32
+// CHECK: vhsub.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vhsub_u32(uint32x2_t a, uint32x2_t b) {
+ return vhsub_u32(a, b);
+}
+
+// CHECK: test_vhsubq_s8
+// CHECK: vhsub.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vhsubq_s8(int8x16_t a, int8x16_t b) {
+ return vhsubq_s8(a, b);
+}
+
+// CHECK: test_vhsubq_s16
+// CHECK: vhsub.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vhsubq_s16(int16x8_t a, int16x8_t b) {
+ return vhsubq_s16(a, b);
+}
+
+// CHECK: test_vhsubq_s32
+// CHECK: vhsub.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vhsubq_s32(int32x4_t a, int32x4_t b) {
+ return vhsubq_s32(a, b);
+}
+
+// CHECK: test_vhsubq_u8
+// CHECK: vhsub.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vhsubq_u8(uint8x16_t a, uint8x16_t b) {
+ return vhsubq_u8(a, b);
+}
+
+// CHECK: test_vhsubq_u16
+// CHECK: vhsub.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vhsubq_u16(uint16x8_t a, uint16x8_t b) {
+ return vhsubq_u16(a, b);
+}
+
+// CHECK: test_vhsubq_u32
+// CHECK: vhsub.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vhsubq_u32(uint32x4_t a, uint32x4_t b) {
+ return vhsubq_u32(a, b);
+}
+
+
+// CHECK: test_vld1q_u8
+// CHECK: vld1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x16_t test_vld1q_u8(uint8_t const * a) {
+ return vld1q_u8(a);
+}
+
+// CHECK: test_vld1q_u16
+// CHECK: vld1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x8_t test_vld1q_u16(uint16_t const * a) {
+ return vld1q_u16(a);
+}
+
+// CHECK: test_vld1q_u32
+// CHECK: vld1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x4_t test_vld1q_u32(uint32_t const * a) {
+ return vld1q_u32(a);
+}
+
+// CHECK: test_vld1q_u64
+// CHECK: vld1.64 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint64x2_t test_vld1q_u64(uint64_t const * a) {
+ return vld1q_u64(a);
+}
+
+// CHECK: test_vld1q_s8
+// CHECK: vld1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x16_t test_vld1q_s8(int8_t const * a) {
+ return vld1q_s8(a);
+}
+
+// CHECK: test_vld1q_s16
+// CHECK: vld1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x8_t test_vld1q_s16(int16_t const * a) {
+ return vld1q_s16(a);
+}
+
+// CHECK: test_vld1q_s32
+// CHECK: vld1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x4_t test_vld1q_s32(int32_t const * a) {
+ return vld1q_s32(a);
+}
+
+// CHECK: test_vld1q_s64
+// CHECK: vld1.64 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int64x2_t test_vld1q_s64(int64_t const * a) {
+ return vld1q_s64(a);
+}
+
+// CHECK: test_vld1q_f16
+// CHECK: vld1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x8_t test_vld1q_f16(float16_t const * a) {
+ return vld1q_f16(a);
+}
+
+// CHECK: test_vld1q_f32
+// CHECK: vld1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x4_t test_vld1q_f32(float32_t const * a) {
+ return vld1q_f32(a);
+}
+
+// CHECK: test_vld1q_p8
+// CHECK: vld1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x16_t test_vld1q_p8(poly8_t const * a) {
+ return vld1q_p8(a);
+}
+
+// CHECK: test_vld1q_p16
+// CHECK: vld1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x8_t test_vld1q_p16(poly16_t const * a) {
+ return vld1q_p16(a);
+}
+
+// CHECK: test_vld1_u8
+// CHECK: vld1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x8_t test_vld1_u8(uint8_t const * a) {
+ return vld1_u8(a);
+}
+
+// CHECK: test_vld1_u16
+// CHECK: vld1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x4_t test_vld1_u16(uint16_t const * a) {
+ return vld1_u16(a);
+}
+
+// CHECK: test_vld1_u32
+// CHECK: vld1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x2_t test_vld1_u32(uint32_t const * a) {
+ return vld1_u32(a);
+}
+
+// CHECK: test_vld1_u64
+// CHECK: vld1.64 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint64x1_t test_vld1_u64(uint64_t const * a) {
+ return vld1_u64(a);
+}
+
+// CHECK: test_vld1_s8
+// CHECK: vld1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x8_t test_vld1_s8(int8_t const * a) {
+ return vld1_s8(a);
+}
+
+// CHECK: test_vld1_s16
+// CHECK: vld1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x4_t test_vld1_s16(int16_t const * a) {
+ return vld1_s16(a);
+}
+
+// CHECK: test_vld1_s32
+// CHECK: vld1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x2_t test_vld1_s32(int32_t const * a) {
+ return vld1_s32(a);
+}
+
+// CHECK: test_vld1_s64
+// CHECK: vld1.64 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+int64x1_t test_vld1_s64(int64_t const * a) {
+ return vld1_s64(a);
+}
+
+// CHECK: test_vld1_f16
+// CHECK: vld1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x4_t test_vld1_f16(float16_t const * a) {
+ return vld1_f16(a);
+}
+
+// CHECK: test_vld1_f32
+// CHECK: vld1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x2_t test_vld1_f32(float32_t const * a) {
+ return vld1_f32(a);
+}
+
+// CHECK: test_vld1_p8
+// CHECK: vld1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x8_t test_vld1_p8(poly8_t const * a) {
+ return vld1_p8(a);
+}
+
+// CHECK: test_vld1_p16
+// CHECK: vld1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x4_t test_vld1_p16(poly16_t const * a) {
+ return vld1_p16(a);
+}
+
+
+// CHECK: test_vld1q_dup_u8
+// CHECK: vld1.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint8x16_t test_vld1q_dup_u8(uint8_t const * a) {
+ return vld1q_dup_u8(a);
+}
+
+// CHECK: test_vld1q_dup_u16
+// CHECK: vld1.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+uint16x8_t test_vld1q_dup_u16(uint16_t const * a) {
+ return vld1q_dup_u16(a);
+}
+
+// CHECK: test_vld1q_dup_u32
+// CHECK: vld1.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+uint32x4_t test_vld1q_dup_u32(uint32_t const * a) {
+ return vld1q_dup_u32(a);
+}
+
+// CHECK: test_vld1q_dup_u64
+// CHECK: {{ldr|vldr|vmov}}
+uint64x2_t test_vld1q_dup_u64(uint64_t const * a) {
+ return vld1q_dup_u64(a);
+}
+
+// CHECK: test_vld1q_dup_s8
+// CHECK: vld1.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int8x16_t test_vld1q_dup_s8(int8_t const * a) {
+ return vld1q_dup_s8(a);
+}
+
+// CHECK: test_vld1q_dup_s16
+// CHECK: vld1.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+int16x8_t test_vld1q_dup_s16(int16_t const * a) {
+ return vld1q_dup_s16(a);
+}
+
+// CHECK: test_vld1q_dup_s32
+// CHECK: vld1.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+int32x4_t test_vld1q_dup_s32(int32_t const * a) {
+ return vld1q_dup_s32(a);
+}
+
+// CHECK: test_vld1q_dup_s64
+// CHECK: {{ldr|vldr|vmov}}
+int64x2_t test_vld1q_dup_s64(int64_t const * a) {
+ return vld1q_dup_s64(a);
+}
+
+// CHECK: test_vld1q_dup_f16
+// CHECK: vld1.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+float16x8_t test_vld1q_dup_f16(float16_t const * a) {
+ return vld1q_dup_f16(a);
+}
+
+// CHECK: test_vld1q_dup_f32
+// CHECK: vld1.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+float32x4_t test_vld1q_dup_f32(float32_t const * a) {
+ return vld1q_dup_f32(a);
+}
+
+// CHECK: test_vld1q_dup_p8
+// CHECK: vld1.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly8x16_t test_vld1q_dup_p8(poly8_t const * a) {
+ return vld1q_dup_p8(a);
+}
+
+// CHECK: test_vld1q_dup_p16
+// CHECK: vld1.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+poly16x8_t test_vld1q_dup_p16(poly16_t const * a) {
+ return vld1q_dup_p16(a);
+}
+
+// CHECK: test_vld1_dup_u8
+// CHECK: vld1.8 {d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint8x8_t test_vld1_dup_u8(uint8_t const * a) {
+ return vld1_dup_u8(a);
+}
+
+// CHECK: test_vld1_dup_u16
+// CHECK: vld1.16 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+uint16x4_t test_vld1_dup_u16(uint16_t const * a) {
+ return vld1_dup_u16(a);
+}
+
+// CHECK: test_vld1_dup_u32
+// CHECK: vld1.32 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+uint32x2_t test_vld1_dup_u32(uint32_t const * a) {
+ return vld1_dup_u32(a);
+}
+
+// CHECK: test_vld1_dup_u64
+// CHECK: {{ldr|vldr|vmov}}
+uint64x1_t test_vld1_dup_u64(uint64_t const * a) {
+ return vld1_dup_u64(a);
+}
+
+// CHECK: test_vld1_dup_s8
+// CHECK: vld1.8 {d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int8x8_t test_vld1_dup_s8(int8_t const * a) {
+ return vld1_dup_s8(a);
+}
+
+// CHECK: test_vld1_dup_s16
+// CHECK: vld1.16 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+int16x4_t test_vld1_dup_s16(int16_t const * a) {
+ return vld1_dup_s16(a);
+}
+
+// CHECK: test_vld1_dup_s32
+// CHECK: vld1.32 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+int32x2_t test_vld1_dup_s32(int32_t const * a) {
+ return vld1_dup_s32(a);
+}
+
+// CHECK: test_vld1_dup_s64
+// CHECK: {{ldr|vldr|vmov}}
+int64x1_t test_vld1_dup_s64(int64_t const * a) {
+ return vld1_dup_s64(a);
+}
+
+// CHECK: test_vld1_dup_f16
+// CHECK: vld1.16 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+float16x4_t test_vld1_dup_f16(float16_t const * a) {
+ return vld1_dup_f16(a);
+}
+
+// CHECK: test_vld1_dup_f32
+// CHECK: vld1.32 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:32]
+float32x2_t test_vld1_dup_f32(float32_t const * a) {
+ return vld1_dup_f32(a);
+}
+
+// CHECK: test_vld1_dup_p8
+// CHECK: vld1.8 {d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly8x8_t test_vld1_dup_p8(poly8_t const * a) {
+ return vld1_dup_p8(a);
+}
+
+// CHECK: test_vld1_dup_p16
+// CHECK: vld1.16 {d{{[0-9]+}}[]}, [r{{[0-9]+}}:16]
+poly16x4_t test_vld1_dup_p16(poly16_t const * a) {
+ return vld1_dup_p16(a);
+}
+
+
+// CHECK: test_vld1q_lane_u8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint8x16_t test_vld1q_lane_u8(uint8_t const * a, uint8x16_t b) {
+ return vld1q_lane_u8(a, b, 15);
+}
+
+// CHECK: test_vld1q_lane_u16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+uint16x8_t test_vld1q_lane_u16(uint16_t const * a, uint16x8_t b) {
+ return vld1q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vld1q_lane_u32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+uint32x4_t test_vld1q_lane_u32(uint32_t const * a, uint32x4_t b) {
+ return vld1q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vld1q_lane_u64
+// CHECK: {{ldr|vldr|vmov}}
+uint64x2_t test_vld1q_lane_u64(uint64_t const * a, uint64x2_t b) {
+ return vld1q_lane_u64(a, b, 1);
+}
+
+// CHECK: test_vld1q_lane_s8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int8x16_t test_vld1q_lane_s8(int8_t const * a, int8x16_t b) {
+ return vld1q_lane_s8(a, b, 15);
+}
+
+// CHECK: test_vld1q_lane_s16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+int16x8_t test_vld1q_lane_s16(int16_t const * a, int16x8_t b) {
+ return vld1q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vld1q_lane_s32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+int32x4_t test_vld1q_lane_s32(int32_t const * a, int32x4_t b) {
+ return vld1q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vld1q_lane_s64
+// CHECK: {{ldr|vldr|vmov}}
+int64x2_t test_vld1q_lane_s64(int64_t const * a, int64x2_t b) {
+ return vld1q_lane_s64(a, b, 1);
+}
+
+// CHECK: test_vld1q_lane_f16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+float16x8_t test_vld1q_lane_f16(float16_t const * a, float16x8_t b) {
+ return vld1q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vld1q_lane_f32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+float32x4_t test_vld1q_lane_f32(float32_t const * a, float32x4_t b) {
+ return vld1q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vld1q_lane_p8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly8x16_t test_vld1q_lane_p8(poly8_t const * a, poly8x16_t b) {
+ return vld1q_lane_p8(a, b, 15);
+}
+
+// CHECK: test_vld1q_lane_p16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+poly16x8_t test_vld1q_lane_p16(poly16_t const * a, poly16x8_t b) {
+ return vld1q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vld1_lane_u8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint8x8_t test_vld1_lane_u8(uint8_t const * a, uint8x8_t b) {
+ return vld1_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vld1_lane_u16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+uint16x4_t test_vld1_lane_u16(uint16_t const * a, uint16x4_t b) {
+ return vld1_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vld1_lane_u32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+uint32x2_t test_vld1_lane_u32(uint32_t const * a, uint32x2_t b) {
+ return vld1_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vld1_lane_u64
+// CHECK: {{ldr|vldr|vmov}}
+uint64x1_t test_vld1_lane_u64(uint64_t const * a, uint64x1_t b) {
+ return vld1_lane_u64(a, b, 0);
+}
+
+// CHECK: test_vld1_lane_s8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int8x8_t test_vld1_lane_s8(int8_t const * a, int8x8_t b) {
+ return vld1_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vld1_lane_s16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+int16x4_t test_vld1_lane_s16(int16_t const * a, int16x4_t b) {
+ return vld1_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vld1_lane_s32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+int32x2_t test_vld1_lane_s32(int32_t const * a, int32x2_t b) {
+ return vld1_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vld1_lane_s64
+// CHECK: {{ldr|vldr|vmov}}
+int64x1_t test_vld1_lane_s64(int64_t const * a, int64x1_t b) {
+ return vld1_lane_s64(a, b, 0);
+}
+
+// CHECK: test_vld1_lane_f16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+float16x4_t test_vld1_lane_f16(float16_t const * a, float16x4_t b) {
+ return vld1_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vld1_lane_f32
+// CHECK: vld1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+float32x2_t test_vld1_lane_f32(float32_t const * a, float32x2_t b) {
+ return vld1_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vld1_lane_p8
+// CHECK: vld1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly8x8_t test_vld1_lane_p8(poly8_t const * a, poly8x8_t b) {
+ return vld1_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vld1_lane_p16
+// CHECK: vld1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+poly16x4_t test_vld1_lane_p16(poly16_t const * a, poly16x4_t b) {
+ return vld1_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vld2q_u8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x16x2_t test_vld2q_u8(uint8_t const * a) {
+ return vld2q_u8(a);
+}
+
+// CHECK: test_vld2q_u16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x8x2_t test_vld2q_u16(uint16_t const * a) {
+ return vld2q_u16(a);
+}
+
+// CHECK: test_vld2q_u32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x4x2_t test_vld2q_u32(uint32_t const * a) {
+ return vld2q_u32(a);
+}
+
+// CHECK: test_vld2q_s8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x16x2_t test_vld2q_s8(int8_t const * a) {
+ return vld2q_s8(a);
+}
+
+// CHECK: test_vld2q_s16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x8x2_t test_vld2q_s16(int16_t const * a) {
+ return vld2q_s16(a);
+}
+
+// CHECK: test_vld2q_s32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x4x2_t test_vld2q_s32(int32_t const * a) {
+ return vld2q_s32(a);
+}
+
+// CHECK: test_vld2q_f16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x8x2_t test_vld2q_f16(float16_t const * a) {
+ return vld2q_f16(a);
+}
+
+// CHECK: test_vld2q_f32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x4x2_t test_vld2q_f32(float32_t const * a) {
+ return vld2q_f32(a);
+}
+
+// CHECK: test_vld2q_p8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x16x2_t test_vld2q_p8(poly8_t const * a) {
+ return vld2q_p8(a);
+}
+
+// CHECK: test_vld2q_p16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x8x2_t test_vld2q_p16(poly16_t const * a) {
+ return vld2q_p16(a);
+}
+
+// CHECK: test_vld2_u8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x8x2_t test_vld2_u8(uint8_t const * a) {
+ return vld2_u8(a);
+}
+
+// CHECK: test_vld2_u16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x4x2_t test_vld2_u16(uint16_t const * a) {
+ return vld2_u16(a);
+}
+
+// CHECK: test_vld2_u32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x2x2_t test_vld2_u32(uint32_t const * a) {
+ return vld2_u32(a);
+}
+
+// CHECK: test_vld2_u64
+// CHECK: vld1.64
+uint64x1x2_t test_vld2_u64(uint64_t const * a) {
+ return vld2_u64(a);
+}
+
+// CHECK: test_vld2_s8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x8x2_t test_vld2_s8(int8_t const * a) {
+ return vld2_s8(a);
+}
+
+// CHECK: test_vld2_s16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x4x2_t test_vld2_s16(int16_t const * a) {
+ return vld2_s16(a);
+}
+
+// CHECK: test_vld2_s32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x2x2_t test_vld2_s32(int32_t const * a) {
+ return vld2_s32(a);
+}
+
+// CHECK: test_vld2_s64
+// CHECK: vld1.64
+int64x1x2_t test_vld2_s64(int64_t const * a) {
+ return vld2_s64(a);
+}
+
+// CHECK: test_vld2_f16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x4x2_t test_vld2_f16(float16_t const * a) {
+ return vld2_f16(a);
+}
+
+// CHECK: test_vld2_f32
+// CHECK: vld2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x2x2_t test_vld2_f32(float32_t const * a) {
+ return vld2_f32(a);
+}
+
+// CHECK: test_vld2_p8
+// CHECK: vld2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x8x2_t test_vld2_p8(poly8_t const * a) {
+ return vld2_p8(a);
+}
+
+// CHECK: test_vld2_p16
+// CHECK: vld2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x4x2_t test_vld2_p16(poly16_t const * a) {
+ return vld2_p16(a);
+}
+
+
+// CHECK: test_vld2_dup_u8
+// CHECK: vld2.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint8x8x2_t test_vld2_dup_u8(uint8_t const * a) {
+ return vld2_dup_u8(a);
+}
+
+// CHECK: test_vld2_dup_u16
+// CHECK: vld2.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint16x4x2_t test_vld2_dup_u16(uint16_t const * a) {
+ return vld2_dup_u16(a);
+}
+
+// CHECK: test_vld2_dup_u32
+// CHECK: vld2.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint32x2x2_t test_vld2_dup_u32(uint32_t const * a) {
+ return vld2_dup_u32(a);
+}
+
+// CHECK: test_vld2_dup_u64
+// CHECK: vld1.64
+uint64x1x2_t test_vld2_dup_u64(uint64_t const * a) {
+ return vld2_dup_u64(a);
+}
+
+// CHECK: test_vld2_dup_s8
+// CHECK: vld2.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int8x8x2_t test_vld2_dup_s8(int8_t const * a) {
+ return vld2_dup_s8(a);
+}
+
+// CHECK: test_vld2_dup_s16
+// CHECK: vld2.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int16x4x2_t test_vld2_dup_s16(int16_t const * a) {
+ return vld2_dup_s16(a);
+}
+
+// CHECK: test_vld2_dup_s32
+// CHECK: vld2.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int32x2x2_t test_vld2_dup_s32(int32_t const * a) {
+ return vld2_dup_s32(a);
+}
+
+// CHECK: test_vld2_dup_s64
+// CHECK: vld1.64
+int64x1x2_t test_vld2_dup_s64(int64_t const * a) {
+ return vld2_dup_s64(a);
+}
+
+// CHECK: test_vld2_dup_f16
+// CHECK: vld2.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float16x4x2_t test_vld2_dup_f16(float16_t const * a) {
+ return vld2_dup_f16(a);
+}
+
+// CHECK: test_vld2_dup_f32
+// CHECK: vld2.32 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float32x2x2_t test_vld2_dup_f32(float32_t const * a) {
+ return vld2_dup_f32(a);
+}
+
+// CHECK: test_vld2_dup_p8
+// CHECK: vld2.8 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly8x8x2_t test_vld2_dup_p8(poly8_t const * a) {
+ return vld2_dup_p8(a);
+}
+
+// CHECK: test_vld2_dup_p16
+// CHECK: vld2.16 {d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly16x4x2_t test_vld2_dup_p16(poly16_t const * a) {
+ return vld2_dup_p16(a);
+}
+
+
+// CHECK: test_vld2q_lane_u16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint16x8x2_t test_vld2q_lane_u16(uint16_t const * a, uint16x8x2_t b) {
+ return vld2q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vld2q_lane_u32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint32x4x2_t test_vld2q_lane_u32(uint32_t const * a, uint32x4x2_t b) {
+ return vld2q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vld2q_lane_s16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int16x8x2_t test_vld2q_lane_s16(int16_t const * a, int16x8x2_t b) {
+ return vld2q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vld2q_lane_s32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int32x4x2_t test_vld2q_lane_s32(int32_t const * a, int32x4x2_t b) {
+ return vld2q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vld2q_lane_f16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float16x8x2_t test_vld2q_lane_f16(float16_t const * a, float16x8x2_t b) {
+ return vld2q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vld2q_lane_f32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float32x4x2_t test_vld2q_lane_f32(float32_t const * a, float32x4x2_t b) {
+ return vld2q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vld2q_lane_p16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly16x8x2_t test_vld2q_lane_p16(poly16_t const * a, poly16x8x2_t b) {
+ return vld2q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vld2_lane_u8
+// CHECK: vld2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint8x8x2_t test_vld2_lane_u8(uint8_t const * a, uint8x8x2_t b) {
+ return vld2_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vld2_lane_u16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint16x4x2_t test_vld2_lane_u16(uint16_t const * a, uint16x4x2_t b) {
+ return vld2_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vld2_lane_u32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint32x2x2_t test_vld2_lane_u32(uint32_t const * a, uint32x2x2_t b) {
+ return vld2_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vld2_lane_s8
+// CHECK: vld2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int8x8x2_t test_vld2_lane_s8(int8_t const * a, int8x8x2_t b) {
+ return vld2_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vld2_lane_s16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int16x4x2_t test_vld2_lane_s16(int16_t const * a, int16x4x2_t b) {
+ return vld2_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vld2_lane_s32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int32x2x2_t test_vld2_lane_s32(int32_t const * a, int32x2x2_t b) {
+ return vld2_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vld2_lane_f16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float16x4x2_t test_vld2_lane_f16(float16_t const * a, float16x4x2_t b) {
+ return vld2_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vld2_lane_f32
+// CHECK: vld2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float32x2x2_t test_vld2_lane_f32(float32_t const * a, float32x2x2_t b) {
+ return vld2_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vld2_lane_p8
+// CHECK: vld2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly8x8x2_t test_vld2_lane_p8(poly8_t const * a, poly8x8x2_t b) {
+ return vld2_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vld2_lane_p16
+// CHECK: vld2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly16x4x2_t test_vld2_lane_p16(poly16_t const * a, poly16x4x2_t b) {
+ return vld2_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vld3q_u8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint8x16x3_t test_vld3q_u8(uint8_t const * a) {
+ return vld3q_u8(a);
+}
+
+// CHECK: test_vld3q_u16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint16x8x3_t test_vld3q_u16(uint16_t const * a) {
+ return vld3q_u16(a);
+}
+
+// CHECK: test_vld3q_u32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint32x4x3_t test_vld3q_u32(uint32_t const * a) {
+ return vld3q_u32(a);
+}
+
+// CHECK: test_vld3q_s8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int8x16x3_t test_vld3q_s8(int8_t const * a) {
+ return vld3q_s8(a);
+}
+
+// CHECK: test_vld3q_s16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int16x8x3_t test_vld3q_s16(int16_t const * a) {
+ return vld3q_s16(a);
+}
+
+// CHECK: test_vld3q_s32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int32x4x3_t test_vld3q_s32(int32_t const * a) {
+ return vld3q_s32(a);
+}
+
+// CHECK: test_vld3q_f16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+float16x8x3_t test_vld3q_f16(float16_t const * a) {
+ return vld3q_f16(a);
+}
+
+// CHECK: test_vld3q_f32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+float32x4x3_t test_vld3q_f32(float32_t const * a) {
+ return vld3q_f32(a);
+}
+
+// CHECK: test_vld3q_p8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+poly8x16x3_t test_vld3q_p8(poly8_t const * a) {
+ return vld3q_p8(a);
+}
+
+// CHECK: test_vld3q_p16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+poly16x8x3_t test_vld3q_p16(poly16_t const * a) {
+ return vld3q_p16(a);
+}
+
+// CHECK: test_vld3_u8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x8x3_t test_vld3_u8(uint8_t const * a) {
+ return vld3_u8(a);
+}
+
+// CHECK: test_vld3_u16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x4x3_t test_vld3_u16(uint16_t const * a) {
+ return vld3_u16(a);
+}
+
+// CHECK: test_vld3_u32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x2x3_t test_vld3_u32(uint32_t const * a) {
+ return vld3_u32(a);
+}
+
+// CHECK: test_vld3_u64
+// CHECK: vld1.64
+uint64x1x3_t test_vld3_u64(uint64_t const * a) {
+ return vld3_u64(a);
+}
+
+// CHECK: test_vld3_s8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x8x3_t test_vld3_s8(int8_t const * a) {
+ return vld3_s8(a);
+}
+
+// CHECK: test_vld3_s16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x4x3_t test_vld3_s16(int16_t const * a) {
+ return vld3_s16(a);
+}
+
+// CHECK: test_vld3_s32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x2x3_t test_vld3_s32(int32_t const * a) {
+ return vld3_s32(a);
+}
+
+// CHECK: test_vld3_s64
+// CHECK: vld1.64
+int64x1x3_t test_vld3_s64(int64_t const * a) {
+ return vld3_s64(a);
+}
+
+// CHECK: test_vld3_f16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x4x3_t test_vld3_f16(float16_t const * a) {
+ return vld3_f16(a);
+}
+
+// CHECK: test_vld3_f32
+// CHECK: vld3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x2x3_t test_vld3_f32(float32_t const * a) {
+ return vld3_f32(a);
+}
+
+// CHECK: test_vld3_p8
+// CHECK: vld3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x8x3_t test_vld3_p8(poly8_t const * a) {
+ return vld3_p8(a);
+}
+
+// CHECK: test_vld3_p16
+// CHECK: vld3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x4x3_t test_vld3_p16(poly16_t const * a) {
+ return vld3_p16(a);
+}
+
+
+// CHECK: test_vld3_dup_u8
+// CHECK: vld3.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint8x8x3_t test_vld3_dup_u8(uint8_t const * a) {
+ return vld3_dup_u8(a);
+}
+
+// CHECK: test_vld3_dup_u16
+// CHECK: vld3.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint16x4x3_t test_vld3_dup_u16(uint16_t const * a) {
+ return vld3_dup_u16(a);
+}
+
+// CHECK: test_vld3_dup_u32
+// CHECK: vld3.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint32x2x3_t test_vld3_dup_u32(uint32_t const * a) {
+ return vld3_dup_u32(a);
+}
+
+// CHECK: test_vld3_dup_u64
+// CHECK: vld1.64
+uint64x1x3_t test_vld3_dup_u64(uint64_t const * a) {
+ return vld3_dup_u64(a);
+}
+
+// CHECK: test_vld3_dup_s8
+// CHECK: vld3.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int8x8x3_t test_vld3_dup_s8(int8_t const * a) {
+ return vld3_dup_s8(a);
+}
+
+// CHECK: test_vld3_dup_s16
+// CHECK: vld3.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int16x4x3_t test_vld3_dup_s16(int16_t const * a) {
+ return vld3_dup_s16(a);
+}
+
+// CHECK: test_vld3_dup_s32
+// CHECK: vld3.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int32x2x3_t test_vld3_dup_s32(int32_t const * a) {
+ return vld3_dup_s32(a);
+}
+
+// CHECK: test_vld3_dup_s64
+// CHECK: vld1.64
+int64x1x3_t test_vld3_dup_s64(int64_t const * a) {
+ return vld3_dup_s64(a);
+}
+
+// CHECK: test_vld3_dup_f16
+// CHECK: vld3.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float16x4x3_t test_vld3_dup_f16(float16_t const * a) {
+ return vld3_dup_f16(a);
+}
+
+// CHECK: test_vld3_dup_f32
+// CHECK: vld3.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float32x2x3_t test_vld3_dup_f32(float32_t const * a) {
+ return vld3_dup_f32(a);
+}
+
+// CHECK: test_vld3_dup_p8
+// CHECK: vld3.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly8x8x3_t test_vld3_dup_p8(poly8_t const * a) {
+ return vld3_dup_p8(a);
+}
+
+// CHECK: test_vld3_dup_p16
+// CHECK: vld3.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly16x4x3_t test_vld3_dup_p16(poly16_t const * a) {
+ return vld3_dup_p16(a);
+}
+
+
+// CHECK: test_vld3q_lane_u16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+uint16x8x3_t test_vld3q_lane_u16(uint16_t const * a, uint16x8x3_t b) {
+ return vld3q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vld3q_lane_u32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+uint32x4x3_t test_vld3q_lane_u32(uint32_t const * a, uint32x4x3_t b) {
+ return vld3q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vld3q_lane_s16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+int16x8x3_t test_vld3q_lane_s16(int16_t const * a, int16x8x3_t b) {
+ return vld3q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vld3q_lane_s32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+int32x4x3_t test_vld3q_lane_s32(int32_t const * a, int32x4x3_t b) {
+ return vld3q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vld3q_lane_f16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+float16x8x3_t test_vld3q_lane_f16(float16_t const * a, float16x8x3_t b) {
+ return vld3q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vld3q_lane_f32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+float32x4x3_t test_vld3q_lane_f32(float32_t const * a, float32x4x3_t b) {
+ return vld3q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vld3q_lane_p16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+poly16x8x3_t test_vld3q_lane_p16(poly16_t const * a, poly16x8x3_t b) {
+ return vld3q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vld3_lane_u8
+// CHECK: vld3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint8x8x3_t test_vld3_lane_u8(uint8_t const * a, uint8x8x3_t b) {
+ return vld3_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vld3_lane_u16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint16x4x3_t test_vld3_lane_u16(uint16_t const * a, uint16x4x3_t b) {
+ return vld3_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vld3_lane_u32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint32x2x3_t test_vld3_lane_u32(uint32_t const * a, uint32x2x3_t b) {
+ return vld3_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vld3_lane_s8
+// CHECK: vld3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int8x8x3_t test_vld3_lane_s8(int8_t const * a, int8x8x3_t b) {
+ return vld3_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vld3_lane_s16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int16x4x3_t test_vld3_lane_s16(int16_t const * a, int16x4x3_t b) {
+ return vld3_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vld3_lane_s32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int32x2x3_t test_vld3_lane_s32(int32_t const * a, int32x2x3_t b) {
+ return vld3_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vld3_lane_f16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float16x4x3_t test_vld3_lane_f16(float16_t const * a, float16x4x3_t b) {
+ return vld3_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vld3_lane_f32
+// CHECK: vld3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float32x2x3_t test_vld3_lane_f32(float32_t const * a, float32x2x3_t b) {
+ return vld3_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vld3_lane_p8
+// CHECK: vld3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly8x8x3_t test_vld3_lane_p8(poly8_t const * a, poly8x8x3_t b) {
+ return vld3_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vld3_lane_p16
+// CHECK: vld3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly16x4x3_t test_vld3_lane_p16(poly16_t const * a, poly16x4x3_t b) {
+ return vld3_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vld4q_u8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint8x16x4_t test_vld4q_u8(uint8_t const * a) {
+ return vld4q_u8(a);
+}
+
+// CHECK: test_vld4q_u16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint16x8x4_t test_vld4q_u16(uint16_t const * a) {
+ return vld4q_u16(a);
+}
+
+// CHECK: test_vld4q_u32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+uint32x4x4_t test_vld4q_u32(uint32_t const * a) {
+ return vld4q_u32(a);
+}
+
+// CHECK: test_vld4q_s8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int8x16x4_t test_vld4q_s8(int8_t const * a) {
+ return vld4q_s8(a);
+}
+
+// CHECK: test_vld4q_s16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int16x8x4_t test_vld4q_s16(int16_t const * a) {
+ return vld4q_s16(a);
+}
+
+// CHECK: test_vld4q_s32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+int32x4x4_t test_vld4q_s32(int32_t const * a) {
+ return vld4q_s32(a);
+}
+
+// CHECK: test_vld4q_f16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+float16x8x4_t test_vld4q_f16(float16_t const * a) {
+ return vld4q_f16(a);
+}
+
+// CHECK: test_vld4q_f32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+float32x4x4_t test_vld4q_f32(float32_t const * a) {
+ return vld4q_f32(a);
+}
+
+// CHECK: test_vld4q_p8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+poly8x16x4_t test_vld4q_p8(poly8_t const * a) {
+ return vld4q_p8(a);
+}
+
+// CHECK: test_vld4q_p16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+poly16x8x4_t test_vld4q_p16(poly16_t const * a) {
+ return vld4q_p16(a);
+}
+
+// CHECK: test_vld4_u8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint8x8x4_t test_vld4_u8(uint8_t const * a) {
+ return vld4_u8(a);
+}
+
+// CHECK: test_vld4_u16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint16x4x4_t test_vld4_u16(uint16_t const * a) {
+ return vld4_u16(a);
+}
+
+// CHECK: test_vld4_u32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+uint32x2x4_t test_vld4_u32(uint32_t const * a) {
+ return vld4_u32(a);
+}
+
+// CHECK: test_vld4_u64
+// CHECK: vld1.64
+uint64x1x4_t test_vld4_u64(uint64_t const * a) {
+ return vld4_u64(a);
+}
+
+// CHECK: test_vld4_s8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int8x8x4_t test_vld4_s8(int8_t const * a) {
+ return vld4_s8(a);
+}
+
+// CHECK: test_vld4_s16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int16x4x4_t test_vld4_s16(int16_t const * a) {
+ return vld4_s16(a);
+}
+
+// CHECK: test_vld4_s32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+int32x2x4_t test_vld4_s32(int32_t const * a) {
+ return vld4_s32(a);
+}
+
+// CHECK: test_vld4_s64
+// CHECK: vld1.64
+int64x1x4_t test_vld4_s64(int64_t const * a) {
+ return vld4_s64(a);
+}
+
+// CHECK: test_vld4_f16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float16x4x4_t test_vld4_f16(float16_t const * a) {
+ return vld4_f16(a);
+}
+
+// CHECK: test_vld4_f32
+// CHECK: vld4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+float32x2x4_t test_vld4_f32(float32_t const * a) {
+ return vld4_f32(a);
+}
+
+// CHECK: test_vld4_p8
+// CHECK: vld4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly8x8x4_t test_vld4_p8(poly8_t const * a) {
+ return vld4_p8(a);
+}
+
+// CHECK: test_vld4_p16
+// CHECK: vld4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+poly16x4x4_t test_vld4_p16(poly16_t const * a) {
+ return vld4_p16(a);
+}
+
+
+// CHECK: test_vld4_dup_u8
+// CHECK: vld4.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint8x8x4_t test_vld4_dup_u8(uint8_t const * a) {
+ return vld4_dup_u8(a);
+}
+
+// CHECK: test_vld4_dup_u16
+// CHECK: vld4.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint16x4x4_t test_vld4_dup_u16(uint16_t const * a) {
+ return vld4_dup_u16(a);
+}
+
+// CHECK: test_vld4_dup_u32
+// CHECK: vld4.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+uint32x2x4_t test_vld4_dup_u32(uint32_t const * a) {
+ return vld4_dup_u32(a);
+}
+
+// CHECK: test_vld4_dup_u64
+// CHECK: vld1.64
+uint64x1x4_t test_vld4_dup_u64(uint64_t const * a) {
+ return vld4_dup_u64(a);
+}
+
+// CHECK: test_vld4_dup_s8
+// CHECK: vld4.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int8x8x4_t test_vld4_dup_s8(int8_t const * a) {
+ return vld4_dup_s8(a);
+}
+
+// CHECK: test_vld4_dup_s16
+// CHECK: vld4.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int16x4x4_t test_vld4_dup_s16(int16_t const * a) {
+ return vld4_dup_s16(a);
+}
+
+// CHECK: test_vld4_dup_s32
+// CHECK: vld4.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+int32x2x4_t test_vld4_dup_s32(int32_t const * a) {
+ return vld4_dup_s32(a);
+}
+
+// CHECK: test_vld4_dup_s64
+// CHECK: vld1.64
+int64x1x4_t test_vld4_dup_s64(int64_t const * a) {
+ return vld4_dup_s64(a);
+}
+
+// CHECK: test_vld4_dup_f16
+// CHECK: vld4.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float16x4x4_t test_vld4_dup_f16(float16_t const * a) {
+ return vld4_dup_f16(a);
+}
+
+// CHECK: test_vld4_dup_f32
+// CHECK: vld4.32 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+float32x2x4_t test_vld4_dup_f32(float32_t const * a) {
+ return vld4_dup_f32(a);
+}
+
+// CHECK: test_vld4_dup_p8
+// CHECK: vld4.8 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly8x8x4_t test_vld4_dup_p8(poly8_t const * a) {
+ return vld4_dup_p8(a);
+}
+
+// CHECK: test_vld4_dup_p16
+// CHECK: vld4.16 {d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[], d{{[0-9]+}}[]}, [r{{[0-9]+}}]
+poly16x4x4_t test_vld4_dup_p16(poly16_t const * a) {
+ return vld4_dup_p16(a);
+}
+
+
+// CHECK: test_vld4q_lane_u16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+uint16x8x4_t test_vld4q_lane_u16(uint16_t const * a, uint16x8x4_t b) {
+ return vld4q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vld4q_lane_u32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+uint32x4x4_t test_vld4q_lane_u32(uint32_t const * a, uint32x4x4_t b) {
+ return vld4q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vld4q_lane_s16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+int16x8x4_t test_vld4q_lane_s16(int16_t const * a, int16x8x4_t b) {
+ return vld4q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vld4q_lane_s32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+int32x4x4_t test_vld4q_lane_s32(int32_t const * a, int32x4x4_t b) {
+ return vld4q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vld4q_lane_f16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+float16x8x4_t test_vld4q_lane_f16(float16_t const * a, float16x8x4_t b) {
+ return vld4q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vld4q_lane_f32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+float32x4x4_t test_vld4q_lane_f32(float32_t const * a, float32x4x4_t b) {
+ return vld4q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vld4q_lane_p16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+poly16x8x4_t test_vld4q_lane_p16(poly16_t const * a, poly16x8x4_t b) {
+ return vld4q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vld4_lane_u8
+// CHECK: vld4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint8x8x4_t test_vld4_lane_u8(uint8_t const * a, uint8x8x4_t b) {
+ return vld4_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vld4_lane_u16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint16x4x4_t test_vld4_lane_u16(uint16_t const * a, uint16x4x4_t b) {
+ return vld4_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vld4_lane_u32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+uint32x2x4_t test_vld4_lane_u32(uint32_t const * a, uint32x2x4_t b) {
+ return vld4_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vld4_lane_s8
+// CHECK: vld4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int8x8x4_t test_vld4_lane_s8(int8_t const * a, int8x8x4_t b) {
+ return vld4_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vld4_lane_s16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int16x4x4_t test_vld4_lane_s16(int16_t const * a, int16x4x4_t b) {
+ return vld4_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vld4_lane_s32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+int32x2x4_t test_vld4_lane_s32(int32_t const * a, int32x2x4_t b) {
+ return vld4_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vld4_lane_f16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float16x4x4_t test_vld4_lane_f16(float16_t const * a, float16x4x4_t b) {
+ return vld4_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vld4_lane_f32
+// CHECK: vld4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+float32x2x4_t test_vld4_lane_f32(float32_t const * a, float32x2x4_t b) {
+ return vld4_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vld4_lane_p8
+// CHECK: vld4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly8x8x4_t test_vld4_lane_p8(poly8_t const * a, poly8x8x4_t b) {
+ return vld4_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vld4_lane_p16
+// CHECK: vld4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+poly16x4x4_t test_vld4_lane_p16(poly16_t const * a, poly16x4x4_t b) {
+ return vld4_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vmax_s8
+// CHECK: vmax.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
+ return vmax_s8(a, b);
+}
+
+// CHECK: test_vmax_s16
+// CHECK: vmax.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
+ return vmax_s16(a, b);
+}
+
+// CHECK: test_vmax_s32
+// CHECK: vmax.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) {
+ return vmax_s32(a, b);
+}
+
+// CHECK: test_vmax_u8
+// CHECK: vmax.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
+ return vmax_u8(a, b);
+}
+
+// CHECK: test_vmax_u16
+// CHECK: vmax.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
+ return vmax_u16(a, b);
+}
+
+// CHECK: test_vmax_u32
+// CHECK: vmax.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
+ return vmax_u32(a, b);
+}
+
+// CHECK: test_vmax_f32
+// CHECK: vmax.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) {
+ return vmax_f32(a, b);
+}
+
+// CHECK: test_vmaxq_s8
+// CHECK: vmax.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
+ return vmaxq_s8(a, b);
+}
+
+// CHECK: test_vmaxq_s16
+// CHECK: vmax.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
+ return vmaxq_s16(a, b);
+}
+
+// CHECK: test_vmaxq_s32
+// CHECK: vmax.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) {
+ return vmaxq_s32(a, b);
+}
+
+// CHECK: test_vmaxq_u8
+// CHECK: vmax.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
+ return vmaxq_u8(a, b);
+}
+
+// CHECK: test_vmaxq_u16
+// CHECK: vmax.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
+ return vmaxq_u16(a, b);
+}
+
+// CHECK: test_vmaxq_u32
+// CHECK: vmax.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
+ return vmaxq_u32(a, b);
+}
+
+// CHECK: test_vmaxq_f32
+// CHECK: vmax.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
+ return vmaxq_f32(a, b);
+}
+
+
+// CHECK: test_vmin_s8
+// CHECK: vmin.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
+ return vmin_s8(a, b);
+}
+
+// CHECK: test_vmin_s16
+// CHECK: vmin.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
+ return vmin_s16(a, b);
+}
+
+// CHECK: test_vmin_s32
+// CHECK: vmin.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmin_s32(int32x2_t a, int32x2_t b) {
+ return vmin_s32(a, b);
+}
+
+// CHECK: test_vmin_u8
+// CHECK: vmin.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
+ return vmin_u8(a, b);
+}
+
+// CHECK: test_vmin_u16
+// CHECK: vmin.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
+ return vmin_u16(a, b);
+}
+
+// CHECK: test_vmin_u32
+// CHECK: vmin.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
+ return vmin_u32(a, b);
+}
+
+// CHECK: test_vmin_f32
+// CHECK: vmin.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vmin_f32(float32x2_t a, float32x2_t b) {
+ return vmin_f32(a, b);
+}
+
+// CHECK: test_vminq_s8
+// CHECK: vmin.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
+ return vminq_s8(a, b);
+}
+
+// CHECK: test_vminq_s16
+// CHECK: vmin.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
+ return vminq_s16(a, b);
+}
+
+// CHECK: test_vminq_s32
+// CHECK: vmin.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vminq_s32(int32x4_t a, int32x4_t b) {
+ return vminq_s32(a, b);
+}
+
+// CHECK: test_vminq_u8
+// CHECK: vmin.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
+ return vminq_u8(a, b);
+}
+
+// CHECK: test_vminq_u16
+// CHECK: vmin.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
+ return vminq_u16(a, b);
+}
+
+// CHECK: test_vminq_u32
+// CHECK: vmin.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
+ return vminq_u32(a, b);
+}
+
+// CHECK: test_vminq_f32
+// CHECK: vmin.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vminq_f32(float32x4_t a, float32x4_t b) {
+ return vminq_f32(a, b);
+}
+
+
+// CHECK: test_vmla_s8
+// CHECK: vmla.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmla_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
+ return vmla_s8(a, b, c);
+}
+
+// CHECK: test_vmla_s16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmla_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+ return vmla_s16(a, b, c);
+}
+
+// CHECK: test_vmla_s32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmla_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+ return vmla_s32(a, b, c);
+}
+
+// CHECK: test_vmla_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+// CHECK: vadd.f32
+float32x2_t test_vmla_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
+ return vmla_f32(a, b, c);
+}
+
+// CHECK: test_vmla_u8
+// CHECK: vmla.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmla_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vmla_u8(a, b, c);
+}
+
+// CHECK: test_vmla_u16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmla_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmla_u16(a, b, c);
+}
+
+// CHECK: test_vmla_u32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmla_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmla_u32(a, b, c);
+}
+
+// CHECK: test_vmlaq_s8
+// CHECK: vmla.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vmlaq_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
+ return vmlaq_s8(a, b, c);
+}
+
+// CHECK: test_vmlaq_s16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmlaq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
+ return vmlaq_s16(a, b, c);
+}
+
+// CHECK: test_vmlaq_s32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmlaq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
+ return vmlaq_s32(a, b, c);
+}
+
+// CHECK: test_vmlaq_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+// CHECK: vadd.f32
+float32x4_t test_vmlaq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
+ return vmlaq_f32(a, b, c);
+}
+
+// CHECK: test_vmlaq_u8
+// CHECK: vmla.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vmlaq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
+ return vmlaq_u8(a, b, c);
+}
+
+// CHECK: test_vmlaq_u16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmlaq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
+ return vmlaq_u16(a, b, c);
+}
+
+// CHECK: test_vmlaq_u32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmlaq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
+ return vmlaq_u32(a, b, c);
+}
+
+
+// CHECK: test_vmlal_s8
+// CHECK: vmlal.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ return vmlal_s8(a, b, c);
+}
+
+// CHECK: test_vmlal_s16
+// CHECK: vmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vmlal_s16(a, b, c);
+}
+
+// CHECK: test_vmlal_s32
+// CHECK: vmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vmlal_s32(a, b, c);
+}
+
+// CHECK: test_vmlal_u8
+// CHECK: vmlal.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vmlal_u8(a, b, c);
+}
+
+// CHECK: test_vmlal_u16
+// CHECK: vmlal.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmlal_u16(a, b, c);
+}
+
+// CHECK: test_vmlal_u32
+// CHECK: vmlal.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmlal_u32(a, b, c);
+}
+
+
+// CHECK: test_vmlal_lane_s16
+// CHECK: vmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vmlal_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmlal_lane_s32
+// CHECK: vmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vmlal_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmlal_lane_u16
+// CHECK: vmlal.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmlal_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmlal_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmlal_lane_u32
+// CHECK: vmlal.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint64x2_t test_vmlal_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmlal_lane_u32(a, b, c, 1);
+}
+
+
+// CHECK: test_vmlal_n_s16
+// CHECK: vmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
+ return vmlal_n_s16(a, b, c);
+}
+
+// CHECK: test_vmlal_n_s32
+// CHECK: vmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
+ return vmlal_n_s32(a, b, c);
+}
+
+// CHECK: test_vmlal_n_u16
+// CHECK: vmlal.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmlal_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
+ return vmlal_n_u16(a, b, c);
+}
+
+// CHECK: test_vmlal_n_u32
+// CHECK: vmlal.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmlal_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
+ return vmlal_n_u32(a, b, c);
+}
+
+
+// CHECK: test_vmla_lane_s16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vmla_lane_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+ return vmla_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmla_lane_s32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vmla_lane_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+ return vmla_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmla_lane_u16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x4_t test_vmla_lane_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmla_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmla_lane_u32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x2_t test_vmla_lane_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmla_lane_u32(a, b, c, 1);
+}
+
+// CHECK: test_vmla_lane_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+// CHECK: vadd.f32
+float32x2_t test_vmla_lane_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
+ return vmla_lane_f32(a, b, c, 1);
+}
+
+// CHECK: test_vmlaq_lane_s16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vmlaq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t c) {
+ return vmlaq_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmlaq_lane_s32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmlaq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t c) {
+ return vmlaq_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmlaq_lane_u16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x8_t test_vmlaq_lane_u16(uint16x8_t a, uint16x8_t b, uint16x4_t c) {
+ return vmlaq_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmlaq_lane_u32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmlaq_lane_u32(uint32x4_t a, uint32x4_t b, uint32x2_t c) {
+ return vmlaq_lane_u32(a, b, c, 1);
+}
+
+// CHECK: test_vmlaq_lane_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+// CHECK: vadd.f32
+float32x4_t test_vmlaq_lane_f32(float32x4_t a, float32x4_t b, float32x2_t c) {
+ return vmlaq_lane_f32(a, b, c, 1);
+}
+
+
+// CHECK: test_vmla_n_s16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmla_n_s16(int16x4_t a, int16x4_t b, int16_t c) {
+ return vmla_n_s16(a, b, c);
+}
+
+// CHECK: test_vmla_n_s32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmla_n_s32(int32x2_t a, int32x2_t b, int32_t c) {
+ return vmla_n_s32(a, b, c);
+}
+
+// CHECK: test_vmla_n_u16
+// CHECK: vmla.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmla_n_u16(uint16x4_t a, uint16x4_t b, uint16_t c) {
+ return vmla_n_u16(a, b, c);
+}
+
+// CHECK: test_vmla_n_u32
+// CHECK: vmla.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmla_n_u32(uint32x2_t a, uint32x2_t b, uint32_t c) {
+ return vmla_n_u32(a, b, c);
+}
+
+// CHECK: test_vmla_n_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+// CHECK: vadd.f32
+float32x2_t test_vmla_n_f32(float32x2_t a, float32x2_t b, float32_t c) {
+ return vmla_n_f32(a, b, c);
+}
+
+// CHECK: test_vmlaq_n_s16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmlaq_n_s16(int16x8_t a, int16x8_t b, int16_t c) {
+ return vmlaq_n_s16(a, b, c);
+}
+
+// CHECK: test_vmlaq_n_s32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmlaq_n_s32(int32x4_t a, int32x4_t b, int32_t c) {
+ return vmlaq_n_s32(a, b, c);
+}
+
+// CHECK: test_vmlaq_n_u16
+// CHECK: vmla.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmlaq_n_u16(uint16x8_t a, uint16x8_t b, uint16_t c) {
+ return vmlaq_n_u16(a, b, c);
+}
+
+// CHECK: test_vmlaq_n_u32
+// CHECK: vmla.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmlaq_n_u32(uint32x4_t a, uint32x4_t b, uint32_t c) {
+ return vmlaq_n_u32(a, b, c);
+}
+
+// CHECK: test_vmlaq_n_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[0]
+// CHECK: vadd.f32
+float32x4_t test_vmlaq_n_f32(float32x4_t a, float32x4_t b, float32_t c) {
+ return vmlaq_n_f32(a, b, c);
+}
+
+
+// CHECK: test_vmls_s8
+// CHECK: vmls.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmls_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
+ return vmls_s8(a, b, c);
+}
+
+// CHECK: test_vmls_s16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmls_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+ return vmls_s16(a, b, c);
+}
+
+// CHECK: test_vmls_s32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmls_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+ return vmls_s32(a, b, c);
+}
+
+// CHECK: test_vmls_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+// CHECK: vsub.f32
+float32x2_t test_vmls_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
+ return vmls_f32(a, b, c);
+}
+
+// CHECK: test_vmls_u8
+// CHECK: vmls.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmls_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vmls_u8(a, b, c);
+}
+
+// CHECK: test_vmls_u16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmls_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmls_u16(a, b, c);
+}
+
+// CHECK: test_vmls_u32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmls_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmls_u32(a, b, c);
+}
+
+// CHECK: test_vmlsq_s8
+// CHECK: vmls.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vmlsq_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
+ return vmlsq_s8(a, b, c);
+}
+
+// CHECK: test_vmlsq_s16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmlsq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
+ return vmlsq_s16(a, b, c);
+}
+
+// CHECK: test_vmlsq_s32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmlsq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
+ return vmlsq_s32(a, b, c);
+}
+
+// CHECK: test_vmlsq_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+// CHECK: vsub.f32
+float32x4_t test_vmlsq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
+ return vmlsq_f32(a, b, c);
+}
+
+// CHECK: test_vmlsq_u8
+// CHECK: vmls.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vmlsq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
+ return vmlsq_u8(a, b, c);
+}
+
+// CHECK: test_vmlsq_u16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmlsq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
+ return vmlsq_u16(a, b, c);
+}
+
+// CHECK: test_vmlsq_u32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmlsq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
+ return vmlsq_u32(a, b, c);
+}
+
+
+// CHECK: test_vmlsl_s8
+// CHECK: vmlsl.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
+ return vmlsl_s8(a, b, c);
+}
+
+// CHECK: test_vmlsl_s16
+// CHECK: vmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vmlsl_s16(a, b, c);
+}
+
+// CHECK: test_vmlsl_s32
+// CHECK: vmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vmlsl_s32(a, b, c);
+}
+
+// CHECK: test_vmlsl_u8
+// CHECK: vmlsl.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vmlsl_u8(a, b, c);
+}
+
+// CHECK: test_vmlsl_u16
+// CHECK: vmlsl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmlsl_u16(a, b, c);
+}
+
+// CHECK: test_vmlsl_u32
+// CHECK: vmlsl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmlsl_u32(a, b, c);
+}
+
+
+// CHECK: test_vmlsl_lane_s16
+// CHECK: vmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vmlsl_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmlsl_lane_s32
+// CHECK: vmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vmlsl_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmlsl_lane_u16
+// CHECK: vmlsl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmlsl_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmlsl_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmlsl_lane_u32
+// CHECK: vmlsl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint64x2_t test_vmlsl_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmlsl_lane_u32(a, b, c, 1);
+}
+
+
+// CHECK: test_vmlsl_n_s16
+// CHECK: vmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
+ return vmlsl_n_s16(a, b, c);
+}
+
+// CHECK: test_vmlsl_n_s32
+// CHECK: vmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
+ return vmlsl_n_s32(a, b, c);
+}
+
+// CHECK: test_vmlsl_n_u16
+// CHECK: vmlsl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmlsl_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
+ return vmlsl_n_u16(a, b, c);
+}
+
+// CHECK: test_vmlsl_n_u32
+// CHECK: vmlsl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmlsl_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
+ return vmlsl_n_u32(a, b, c);
+}
+
+
+// CHECK: test_vmls_lane_s16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vmls_lane_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+ return vmls_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmls_lane_s32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vmls_lane_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+ return vmls_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmls_lane_u16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x4_t test_vmls_lane_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
+ return vmls_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmls_lane_u32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x2_t test_vmls_lane_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
+ return vmls_lane_u32(a, b, c, 1);
+}
+
+// CHECK: test_vmls_lane_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+// CHECK: vsub.f32
+float32x2_t test_vmls_lane_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
+ return vmls_lane_f32(a, b, c, 1);
+}
+
+// CHECK: test_vmlsq_lane_s16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vmlsq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t c) {
+ return vmlsq_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vmlsq_lane_s32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmlsq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t c) {
+ return vmlsq_lane_s32(a, b, c, 1);
+}
+
+// CHECK: test_vmlsq_lane_u16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x8_t test_vmlsq_lane_u16(uint16x8_t a, uint16x8_t b, uint16x4_t c) {
+ return vmlsq_lane_u16(a, b, c, 3);
+}
+
+// CHECK: test_vmlsq_lane_u32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmlsq_lane_u32(uint32x4_t a, uint32x4_t b, uint32x2_t c) {
+ return vmlsq_lane_u32(a, b, c, 1);
+}
+
+// CHECK: test_vmlsq_lane_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+// CHECK: vsub.f32
+float32x4_t test_vmlsq_lane_f32(float32x4_t a, float32x4_t b, float32x2_t c) {
+ return vmlsq_lane_f32(a, b, c, 1);
+}
+
+
+// CHECK: test_vmls_n_s16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmls_n_s16(int16x4_t a, int16x4_t b, int16_t c) {
+ return vmls_n_s16(a, b, c);
+}
+
+// CHECK: test_vmls_n_s32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmls_n_s32(int32x2_t a, int32x2_t b, int32_t c) {
+ return vmls_n_s32(a, b, c);
+}
+
+// CHECK: test_vmls_n_u16
+// CHECK: vmls.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmls_n_u16(uint16x4_t a, uint16x4_t b, uint16_t c) {
+ return vmls_n_u16(a, b, c);
+}
+
+// CHECK: test_vmls_n_u32
+// CHECK: vmls.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmls_n_u32(uint32x2_t a, uint32x2_t b, uint32_t c) {
+ return vmls_n_u32(a, b, c);
+}
+
+// CHECK: test_vmls_n_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+// CHECK: vsub.f32
+float32x2_t test_vmls_n_f32(float32x2_t a, float32x2_t b, float32_t c) {
+ return vmls_n_f32(a, b, c);
+}
+
+// CHECK: test_vmlsq_n_s16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmlsq_n_s16(int16x8_t a, int16x8_t b, int16_t c) {
+ return vmlsq_n_s16(a, b, c);
+}
+
+// CHECK: test_vmlsq_n_s32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmlsq_n_s32(int32x4_t a, int32x4_t b, int32_t c) {
+ return vmlsq_n_s32(a, b, c);
+}
+
+// CHECK: test_vmlsq_n_u16
+// CHECK: vmls.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmlsq_n_u16(uint16x8_t a, uint16x8_t b, uint16_t c) {
+ return vmlsq_n_u16(a, b, c);
+}
+
+// CHECK: test_vmlsq_n_u32
+// CHECK: vmls.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmlsq_n_u32(uint32x4_t a, uint32x4_t b, uint32_t c) {
+ return vmlsq_n_u32(a, b, c);
+}
+
+// CHECK: test_vmlsq_n_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[0]
+// CHECK: vsub.f32
+float32x4_t test_vmlsq_n_f32(float32x4_t a, float32x4_t b, float32_t c) {
+ return vmlsq_n_f32(a, b, c);
+}
+
+
+// CHECK: test_vmovl_s8
+// CHECK: vmovl.s8 q{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vmovl_s8(int8x8_t a) {
+ return vmovl_s8(a);
+}
+
+// CHECK: test_vmovl_s16
+// CHECK: vmovl.s16 q{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmovl_s16(int16x4_t a) {
+ return vmovl_s16(a);
+}
+
+// CHECK: test_vmovl_s32
+// CHECK: vmovl.s32 q{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmovl_s32(int32x2_t a) {
+ return vmovl_s32(a);
+}
+
+// CHECK: test_vmovl_u8
+// CHECK: vmovl.u8 q{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vmovl_u8(uint8x8_t a) {
+ return vmovl_u8(a);
+}
+
+// CHECK: test_vmovl_u16
+// CHECK: vmovl.u16 q{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmovl_u16(uint16x4_t a) {
+ return vmovl_u16(a);
+}
+
+// CHECK: test_vmovl_u32
+// CHECK: vmovl.u32 q{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmovl_u32(uint32x2_t a) {
+ return vmovl_u32(a);
+}
+
+
+// CHECK: test_vmovn_s16
+// CHECK: vmovn.i16 d{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vmovn_s16(int16x8_t a) {
+ return vmovn_s16(a);
+}
+
+// CHECK: test_vmovn_s32
+// CHECK: vmovn.i32 d{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vmovn_s32(int32x4_t a) {
+ return vmovn_s32(a);
+}
+
+// CHECK: test_vmovn_s64
+// CHECK: vmovn.i64 d{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vmovn_s64(int64x2_t a) {
+ return vmovn_s64(a);
+}
+
+// CHECK: test_vmovn_u16
+// CHECK: vmovn.i16 d{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vmovn_u16(uint16x8_t a) {
+ return vmovn_u16(a);
+}
+
+// CHECK: test_vmovn_u32
+// CHECK: vmovn.i32 d{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vmovn_u32(uint32x4_t a) {
+ return vmovn_u32(a);
+}
+
+// CHECK: test_vmovn_u64
+// CHECK: vmovn.i64 d{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vmovn_u64(uint64x2_t a) {
+ return vmovn_u64(a);
+}
+
+
+// CHECK: test_vmov_n_u8
+// CHECK: vmov
+uint8x8_t test_vmov_n_u8(uint8_t a) {
+ return vmov_n_u8(a);
+}
+
+// CHECK: test_vmov_n_u16
+// CHECK: vmov
+uint16x4_t test_vmov_n_u16(uint16_t a) {
+ return vmov_n_u16(a);
+}
+
+// CHECK: test_vmov_n_u32
+// CHECK: vmov
+uint32x2_t test_vmov_n_u32(uint32_t a) {
+ return vmov_n_u32(a);
+}
+
+// CHECK: test_vmov_n_s8
+// CHECK: vmov
+int8x8_t test_vmov_n_s8(int8_t a) {
+ return vmov_n_s8(a);
+}
+
+// CHECK: test_vmov_n_s16
+// CHECK: vmov
+int16x4_t test_vmov_n_s16(int16_t a) {
+ return vmov_n_s16(a);
+}
+
+// CHECK: test_vmov_n_s32
+// CHECK: vmov
+int32x2_t test_vmov_n_s32(int32_t a) {
+ return vmov_n_s32(a);
+}
+
+// CHECK: test_vmov_n_p8
+// CHECK: vmov
+poly8x8_t test_vmov_n_p8(poly8_t a) {
+ return vmov_n_p8(a);
+}
+
+// CHECK: test_vmov_n_p16
+// CHECK: vmov
+poly16x4_t test_vmov_n_p16(poly16_t a) {
+ return vmov_n_p16(a);
+}
+
+// CHECK: test_vmov_n_f32
+// CHECK: vmov
+float32x2_t test_vmov_n_f32(float32_t a) {
+ return vmov_n_f32(a);
+}
+
+// CHECK: test_vmovq_n_u8
+// CHECK: vmov
+uint8x16_t test_vmovq_n_u8(uint8_t a) {
+ return vmovq_n_u8(a);
+}
+
+// CHECK: test_vmovq_n_u16
+// CHECK: vmov
+uint16x8_t test_vmovq_n_u16(uint16_t a) {
+ return vmovq_n_u16(a);
+}
+
+// CHECK: test_vmovq_n_u32
+// CHECK: vmov
+uint32x4_t test_vmovq_n_u32(uint32_t a) {
+ return vmovq_n_u32(a);
+}
+
+// CHECK: test_vmovq_n_s8
+// CHECK: vmov
+int8x16_t test_vmovq_n_s8(int8_t a) {
+ return vmovq_n_s8(a);
+}
+
+// CHECK: test_vmovq_n_s16
+// CHECK: vmov
+int16x8_t test_vmovq_n_s16(int16_t a) {
+ return vmovq_n_s16(a);
+}
+
+// CHECK: test_vmovq_n_s32
+// CHECK: vmov
+int32x4_t test_vmovq_n_s32(int32_t a) {
+ return vmovq_n_s32(a);
+}
+
+// CHECK: test_vmovq_n_p8
+// CHECK: vmov
+poly8x16_t test_vmovq_n_p8(poly8_t a) {
+ return vmovq_n_p8(a);
+}
+
+// CHECK: test_vmovq_n_p16
+// CHECK: vmov
+poly16x8_t test_vmovq_n_p16(poly16_t a) {
+ return vmovq_n_p16(a);
+}
+
+// CHECK: test_vmovq_n_f32
+// CHECK: vmov
+float32x4_t test_vmovq_n_f32(float32_t a) {
+ return vmovq_n_f32(a);
+}
+
+// CHECK: test_vmov_n_s64
+// CHECK: vmov
+int64x1_t test_vmov_n_s64(int64_t a) {
+ return vmov_n_s64(a);
+}
+
+// CHECK: test_vmov_n_u64
+// CHECK: vmov
+uint64x1_t test_vmov_n_u64(uint64_t a) {
+ return vmov_n_u64(a);
+}
+
+// CHECK: test_vmovq_n_s64
+// CHECK: vmov
+int64x2_t test_vmovq_n_s64(int64_t a) {
+ return vmovq_n_s64(a);
+}
+
+// CHECK: test_vmovq_n_u64
+// CHECK: vmov
+uint64x2_t test_vmovq_n_u64(uint64_t a) {
+ return vmovq_n_u64(a);
+}
+
+
+// CHECK: test_vmul_s8
+// CHECK: vmul.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmul_s8(int8x8_t a, int8x8_t b) {
+ return vmul_s8(a, b);
+}
+
+// CHECK: test_vmul_s16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmul_s16(int16x4_t a, int16x4_t b) {
+ return vmul_s16(a, b);
+}
+
+// CHECK: test_vmul_s32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmul_s32(int32x2_t a, int32x2_t b) {
+ return vmul_s32(a, b);
+}
+
+// CHECK: test_vmul_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vmul_f32(float32x2_t a, float32x2_t b) {
+ return vmul_f32(a, b);
+}
+
+// CHECK: test_vmul_u8
+// CHECK: vmul.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmul_u8(uint8x8_t a, uint8x8_t b) {
+ return vmul_u8(a, b);
+}
+
+// CHECK: test_vmul_u16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmul_u16(uint16x4_t a, uint16x4_t b) {
+ return vmul_u16(a, b);
+}
+
+// CHECK: test_vmul_u32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmul_u32(uint32x2_t a, uint32x2_t b) {
+ return vmul_u32(a, b);
+}
+
+// CHECK: test_vmulq_s8
+// CHECK: vmul.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vmulq_s8(int8x16_t a, int8x16_t b) {
+ return vmulq_s8(a, b);
+}
+
+// CHECK: test_vmulq_s16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmulq_s16(int16x8_t a, int16x8_t b) {
+ return vmulq_s16(a, b);
+}
+
+// CHECK: test_vmulq_s32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmulq_s32(int32x4_t a, int32x4_t b) {
+ return vmulq_s32(a, b);
+}
+
+// CHECK: test_vmulq_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vmulq_f32(float32x4_t a, float32x4_t b) {
+ return vmulq_f32(a, b);
+}
+
+// CHECK: test_vmulq_u8
+// CHECK: vmul.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vmulq_u8(uint8x16_t a, uint8x16_t b) {
+ return vmulq_u8(a, b);
+}
+
+// CHECK: test_vmulq_u16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmulq_u16(uint16x8_t a, uint16x8_t b) {
+ return vmulq_u16(a, b);
+}
+
+// CHECK: test_vmulq_u32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmulq_u32(uint32x4_t a, uint32x4_t b) {
+ return vmulq_u32(a, b);
+}
+
+
+// CHECK: test_vmull_s8
+// CHECK: vmull.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
+ return vmull_s8(a, b);
+}
+
+// CHECK: test_vmull_s16
+// CHECK: vmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
+ return vmull_s16(a, b);
+}
+
+// CHECK: test_vmull_s32
+// CHECK: vmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmull_s32(int32x2_t a, int32x2_t b) {
+ return vmull_s32(a, b);
+}
+
+// CHECK: test_vmull_u8
+// CHECK: vmull.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
+ return vmull_u8(a, b);
+}
+
+// CHECK: test_vmull_u16
+// CHECK: vmull.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
+ return vmull_u16(a, b);
+}
+
+// CHECK: test_vmull_u32
+// CHECK: vmull.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmull_u32(uint32x2_t a, uint32x2_t b) {
+ return vmull_u32(a, b);
+}
+
+// CHECK: test_vmull_p8
+// CHECK: vmull.p8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
+ return vmull_p8(a, b);
+}
+
+
+// CHECK: test_vmull_lane_s16
+// CHECK: vmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t b) {
+ return vmull_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vmull_lane_s32
+// CHECK: vmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t b) {
+ return vmull_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vmull_lane_u16
+// CHECK: vmull.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t b) {
+ return vmull_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vmull_lane_u32
+// CHECK: vmull.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t b) {
+ return vmull_lane_u32(a, b, 1);
+}
+
+
+// CHECK: test_vmull_n_s16
+// CHECK: vmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vmull_n_s16(int16x4_t a, int16_t b) {
+ return vmull_n_s16(a, b);
+}
+
+// CHECK: test_vmull_n_s32
+// CHECK: vmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vmull_n_s32(int32x2_t a, int32_t b) {
+ return vmull_n_s32(a, b);
+}
+
+// CHECK: test_vmull_n_u16
+// CHECK: vmull.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vmull_n_u16(uint16x4_t a, uint16_t b) {
+ return vmull_n_u16(a, b);
+}
+
+// CHECK: test_vmull_n_u32
+// CHECK: vmull.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vmull_n_u32(uint32x2_t a, uint32_t b) {
+ return vmull_n_u32(a, b);
+}
+
+
+// CHECK: test_vmul_p8
+// CHECK: vmul.p8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vmul_p8(poly8x8_t a, poly8x8_t b) {
+ return vmul_p8(a, b);
+}
+
+// CHECK: test_vmulq_p8
+// CHECK: vmul.p8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vmulq_p8(poly8x16_t a, poly8x16_t b) {
+ return vmulq_p8(a, b);
+}
+
+
+// CHECK: test_vmul_lane_s16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vmul_lane_s16(int16x4_t a, int16x4_t b) {
+ return vmul_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vmul_lane_s32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vmul_lane_s32(int32x2_t a, int32x2_t b) {
+ return vmul_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vmul_lane_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+float32x2_t test_vmul_lane_f32(float32x2_t a, float32x2_t b) {
+ return vmul_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vmul_lane_u16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x4_t test_vmul_lane_u16(uint16x4_t a, uint16x4_t b) {
+ return vmul_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vmul_lane_u32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x2_t test_vmul_lane_u32(uint32x2_t a, uint32x2_t b) {
+ return vmul_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vmulq_lane_s16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vmulq_lane_s16(int16x8_t a, int16x4_t b) {
+ return vmulq_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vmulq_lane_s32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vmulq_lane_s32(int32x4_t a, int32x2_t b) {
+ return vmulq_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vmulq_lane_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+float32x4_t test_vmulq_lane_f32(float32x4_t a, float32x2_t b) {
+ return vmulq_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vmulq_lane_u16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint16x8_t test_vmulq_lane_u16(uint16x8_t a, uint16x4_t b) {
+ return vmulq_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vmulq_lane_u32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+uint32x4_t test_vmulq_lane_u32(uint32x4_t a, uint32x2_t b) {
+ return vmulq_lane_u32(a, b, 1);
+}
+
+
+// CHECK: test_vmul_n_s16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmul_n_s16(int16x4_t a, int16_t b) {
+ return vmul_n_s16(a, b);
+}
+
+// CHECK: test_vmul_n_s32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmul_n_s32(int32x2_t a, int32_t b) {
+ return vmul_n_s32(a, b);
+}
+
+// CHECK: test_vmul_n_f32
+// CHECK: vmul.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vmul_n_f32(float32x2_t a, float32_t b) {
+ return vmul_n_f32(a, b);
+}
+
+// CHECK: test_vmul_n_u16
+// CHECK: vmul.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmul_n_u16(uint16x4_t a, uint16_t b) {
+ return vmul_n_u16(a, b);
+}
+
+// CHECK: test_vmul_n_u32
+// CHECK: vmul.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmul_n_u32(uint32x2_t a, uint32_t b) {
+ return vmul_n_u32(a, b);
+}
+
+// CHECK: test_vmulq_n_s16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmulq_n_s16(int16x8_t a, int16_t b) {
+ return vmulq_n_s16(a, b);
+}
+
+// CHECK: test_vmulq_n_s32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmulq_n_s32(int32x4_t a, int32_t b) {
+ return vmulq_n_s32(a, b);
+}
+
+// CHECK: test_vmulq_n_f32
+// CHECK: vmul.f32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[0]
+float32x4_t test_vmulq_n_f32(float32x4_t a, float32_t b) {
+ return vmulq_n_f32(a, b);
+}
+
+// CHECK: test_vmulq_n_u16
+// CHECK: vmul.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmulq_n_u16(uint16x8_t a, uint16_t b) {
+ return vmulq_n_u16(a, b);
+}
+
+// CHECK: test_vmulq_n_u32
+// CHECK: vmul.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmulq_n_u32(uint32x4_t a, uint32_t b) {
+ return vmulq_n_u32(a, b);
+}
+
+
+// CHECK: test_vmvn_s8
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vmvn_s8(int8x8_t a) {
+ return vmvn_s8(a);
+}
+
+// CHECK: test_vmvn_s16
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vmvn_s16(int16x4_t a) {
+ return vmvn_s16(a);
+}
+
+// CHECK: test_vmvn_s32
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vmvn_s32(int32x2_t a) {
+ return vmvn_s32(a);
+}
+
+// CHECK: test_vmvn_u8
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vmvn_u8(uint8x8_t a) {
+ return vmvn_u8(a);
+}
+
+// CHECK: test_vmvn_u16
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vmvn_u16(uint16x4_t a) {
+ return vmvn_u16(a);
+}
+
+// CHECK: test_vmvn_u32
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vmvn_u32(uint32x2_t a) {
+ return vmvn_u32(a);
+}
+
+// CHECK: test_vmvn_p8
+// CHECK: vmvn d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vmvn_p8(poly8x8_t a) {
+ return vmvn_p8(a);
+}
+
+// CHECK: test_vmvnq_s8
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vmvnq_s8(int8x16_t a) {
+ return vmvnq_s8(a);
+}
+
+// CHECK: test_vmvnq_s16
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vmvnq_s16(int16x8_t a) {
+ return vmvnq_s16(a);
+}
+
+// CHECK: test_vmvnq_s32
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vmvnq_s32(int32x4_t a) {
+ return vmvnq_s32(a);
+}
+
+// CHECK: test_vmvnq_u8
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vmvnq_u8(uint8x16_t a) {
+ return vmvnq_u8(a);
+}
+
+// CHECK: test_vmvnq_u16
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vmvnq_u16(uint16x8_t a) {
+ return vmvnq_u16(a);
+}
+
+// CHECK: test_vmvnq_u32
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vmvnq_u32(uint32x4_t a) {
+ return vmvnq_u32(a);
+}
+
+// CHECK: test_vmvnq_p8
+// CHECK: vmvn q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vmvnq_p8(poly8x16_t a) {
+ return vmvnq_p8(a);
+}
+
+
+// CHECK: test_vneg_s8
+// CHECK: vneg.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vneg_s8(int8x8_t a) {
+ return vneg_s8(a);
+}
+
+// CHECK: test_vneg_s16
+// CHECK: vneg.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vneg_s16(int16x4_t a) {
+ return vneg_s16(a);
+}
+
+// CHECK: test_vneg_s32
+// CHECK: vneg.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vneg_s32(int32x2_t a) {
+ return vneg_s32(a);
+}
+
+// CHECK: test_vneg_f32
+// CHECK: vneg.f32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vneg_f32(float32x2_t a) {
+ return vneg_f32(a);
+}
+
+// CHECK: test_vnegq_s8
+// CHECK: vneg.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vnegq_s8(int8x16_t a) {
+ return vnegq_s8(a);
+}
+
+// CHECK: test_vnegq_s16
+// CHECK: vneg.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vnegq_s16(int16x8_t a) {
+ return vnegq_s16(a);
+}
+
+// CHECK: test_vnegq_s32
+// CHECK: vneg.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vnegq_s32(int32x4_t a) {
+ return vnegq_s32(a);
+}
+
+// CHECK: test_vnegq_f32
+// CHECK: vneg.f32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vnegq_f32(float32x4_t a) {
+ return vnegq_f32(a);
+}
+
+
+// CHECK: test_vorn_s8
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vorn_s8(int8x8_t a, int8x8_t b) {
+ return vorn_s8(a, b);
+}
+
+// CHECK: test_vorn_s16
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vorn_s16(int16x4_t a, int16x4_t b) {
+ return vorn_s16(a, b);
+}
+
+// CHECK: test_vorn_s32
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vorn_s32(int32x2_t a, int32x2_t b) {
+ return vorn_s32(a, b);
+}
+
+// CHECK: test_vorn_s64
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vorn_s64(int64x1_t a, int64x1_t b) {
+ return vorn_s64(a, b);
+}
+
+// CHECK: test_vorn_u8
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vorn_u8(uint8x8_t a, uint8x8_t b) {
+ return vorn_u8(a, b);
+}
+
+// CHECK: test_vorn_u16
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vorn_u16(uint16x4_t a, uint16x4_t b) {
+ return vorn_u16(a, b);
+}
+
+// CHECK: test_vorn_u32
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vorn_u32(uint32x2_t a, uint32x2_t b) {
+ return vorn_u32(a, b);
+}
+
+// CHECK: test_vorn_u64
+// CHECK: vorn d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vorn_u64(uint64x1_t a, uint64x1_t b) {
+ return vorn_u64(a, b);
+}
+
+// CHECK: test_vornq_s8
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vornq_s8(int8x16_t a, int8x16_t b) {
+ return vornq_s8(a, b);
+}
+
+// CHECK: test_vornq_s16
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vornq_s16(int16x8_t a, int16x8_t b) {
+ return vornq_s16(a, b);
+}
+
+// CHECK: test_vornq_s32
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vornq_s32(int32x4_t a, int32x4_t b) {
+ return vornq_s32(a, b);
+}
+
+// CHECK: test_vornq_s64
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vornq_s64(int64x2_t a, int64x2_t b) {
+ return vornq_s64(a, b);
+}
+
+// CHECK: test_vornq_u8
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vornq_u8(uint8x16_t a, uint8x16_t b) {
+ return vornq_u8(a, b);
+}
+
+// CHECK: test_vornq_u16
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vornq_u16(uint16x8_t a, uint16x8_t b) {
+ return vornq_u16(a, b);
+}
+
+// CHECK: test_vornq_u32
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vornq_u32(uint32x4_t a, uint32x4_t b) {
+ return vornq_u32(a, b);
+}
+
+// CHECK: test_vornq_u64
+// CHECK: vorn q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vornq_u64(uint64x2_t a, uint64x2_t b) {
+ return vornq_u64(a, b);
+}
+
+
+// CHECK: test_vorr_s8
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vorr_s8(int8x8_t a, int8x8_t b) {
+ return vorr_s8(a, b);
+}
+
+// CHECK: test_vorr_s16
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vorr_s16(int16x4_t a, int16x4_t b) {
+ return vorr_s16(a, b);
+}
+
+// CHECK: test_vorr_s32
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vorr_s32(int32x2_t a, int32x2_t b) {
+ return vorr_s32(a, b);
+}
+
+// CHECK: test_vorr_s64
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vorr_s64(int64x1_t a, int64x1_t b) {
+ return vorr_s64(a, b);
+}
+
+// CHECK: test_vorr_u8
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vorr_u8(uint8x8_t a, uint8x8_t b) {
+ return vorr_u8(a, b);
+}
+
+// CHECK: test_vorr_u16
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vorr_u16(uint16x4_t a, uint16x4_t b) {
+ return vorr_u16(a, b);
+}
+
+// CHECK: test_vorr_u32
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vorr_u32(uint32x2_t a, uint32x2_t b) {
+ return vorr_u32(a, b);
+}
+
+// CHECK: test_vorr_u64
+// CHECK: vorr d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vorr_u64(uint64x1_t a, uint64x1_t b) {
+ return vorr_u64(a, b);
+}
+
+// CHECK: test_vorrq_s8
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vorrq_s8(int8x16_t a, int8x16_t b) {
+ return vorrq_s8(a, b);
+}
+
+// CHECK: test_vorrq_s16
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vorrq_s16(int16x8_t a, int16x8_t b) {
+ return vorrq_s16(a, b);
+}
+
+// CHECK: test_vorrq_s32
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vorrq_s32(int32x4_t a, int32x4_t b) {
+ return vorrq_s32(a, b);
+}
+
+// CHECK: test_vorrq_s64
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vorrq_s64(int64x2_t a, int64x2_t b) {
+ return vorrq_s64(a, b);
+}
+
+// CHECK: test_vorrq_u8
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vorrq_u8(uint8x16_t a, uint8x16_t b) {
+ return vorrq_u8(a, b);
+}
+
+// CHECK: test_vorrq_u16
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vorrq_u16(uint16x8_t a, uint16x8_t b) {
+ return vorrq_u16(a, b);
+}
+
+// CHECK: test_vorrq_u32
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vorrq_u32(uint32x4_t a, uint32x4_t b) {
+ return vorrq_u32(a, b);
+}
+
+// CHECK: test_vorrq_u64
+// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vorrq_u64(uint64x2_t a, uint64x2_t b) {
+ return vorrq_u64(a, b);
+}
+
+
+// CHECK: test_vpadal_s8
+// CHECK: vpadal.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
+ return vpadal_s8(a, b);
+}
+
+// CHECK: test_vpadal_s16
+// CHECK: vpadal.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
+ return vpadal_s16(a, b);
+}
+
+// CHECK: test_vpadal_s32
+// CHECK: vpadal.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
+ return vpadal_s32(a, b);
+}
+
+// CHECK: test_vpadal_u8
+// CHECK: vpadal.u8 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
+ return vpadal_u8(a, b);
+}
+
+// CHECK: test_vpadal_u16
+// CHECK: vpadal.u16 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
+ return vpadal_u16(a, b);
+}
+
+// CHECK: test_vpadal_u32
+// CHECK: vpadal.u32 d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
+ return vpadal_u32(a, b);
+}
+
+// CHECK: test_vpadalq_s8
+// CHECK: vpadal.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
+ return vpadalq_s8(a, b);
+}
+
+// CHECK: test_vpadalq_s16
+// CHECK: vpadal.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
+ return vpadalq_s16(a, b);
+}
+
+// CHECK: test_vpadalq_s32
+// CHECK: vpadal.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
+ return vpadalq_s32(a, b);
+}
+
+// CHECK: test_vpadalq_u8
+// CHECK: vpadal.u8 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
+ return vpadalq_u8(a, b);
+}
+
+// CHECK: test_vpadalq_u16
+// CHECK: vpadal.u16 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
+ return vpadalq_u16(a, b);
+}
+
+// CHECK: test_vpadalq_u32
+// CHECK: vpadal.u32 q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vpadalq_u32(uint64x2_t a, uint32x4_t b) {
+ return vpadalq_u32(a, b);
+}
+
+
+// CHECK: test_vpadd_s8
+// CHECK: vpadd.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
+ return vpadd_s8(a, b);
+}
+
+// CHECK: test_vpadd_s16
+// CHECK: vpadd.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
+ return vpadd_s16(a, b);
+}
+
+// CHECK: test_vpadd_s32
+// CHECK: vpadd.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
+ return vpadd_s32(a, b);
+}
+
+// CHECK: test_vpadd_u8
+// CHECK: vpadd.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
+ return vpadd_u8(a, b);
+}
+
+// CHECK: test_vpadd_u16
+// CHECK: vpadd.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
+ return vpadd_u16(a, b);
+}
+
+// CHECK: test_vpadd_u32
+// CHECK: vpadd.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
+ return vpadd_u32(a, b);
+}
+
+// CHECK: test_vpadd_f32
+// CHECK: vpadd.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
+ return vpadd_f32(a, b);
+}
+
+
+// CHECK: test_vpaddl_s8
+// CHECK: vpaddl.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vpaddl_s8(int8x8_t a) {
+ return vpaddl_s8(a);
+}
+
+// CHECK: test_vpaddl_s16
+// CHECK: vpaddl.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vpaddl_s16(int16x4_t a) {
+ return vpaddl_s16(a);
+}
+
+// CHECK: test_vpaddl_s32
+// CHECK: vpaddl.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vpaddl_s32(int32x2_t a) {
+ return vpaddl_s32(a);
+}
+
+// CHECK: test_vpaddl_u8
+// CHECK: vpaddl.u8 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vpaddl_u8(uint8x8_t a) {
+ return vpaddl_u8(a);
+}
+
+// CHECK: test_vpaddl_u16
+// CHECK: vpaddl.u16 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vpaddl_u16(uint16x4_t a) {
+ return vpaddl_u16(a);
+}
+
+// CHECK: test_vpaddl_u32
+// CHECK: vpaddl.u32 d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vpaddl_u32(uint32x2_t a) {
+ return vpaddl_u32(a);
+}
+
+// CHECK: test_vpaddlq_s8
+// CHECK: vpaddl.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vpaddlq_s8(int8x16_t a) {
+ return vpaddlq_s8(a);
+}
+
+// CHECK: test_vpaddlq_s16
+// CHECK: vpaddl.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vpaddlq_s16(int16x8_t a) {
+ return vpaddlq_s16(a);
+}
+
+// CHECK: test_vpaddlq_s32
+// CHECK: vpaddl.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vpaddlq_s32(int32x4_t a) {
+ return vpaddlq_s32(a);
+}
+
+// CHECK: test_vpaddlq_u8
+// CHECK: vpaddl.u8 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
+ return vpaddlq_u8(a);
+}
+
+// CHECK: test_vpaddlq_u16
+// CHECK: vpaddl.u16 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
+ return vpaddlq_u16(a);
+}
+
+// CHECK: test_vpaddlq_u32
+// CHECK: vpaddl.u32 q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vpaddlq_u32(uint32x4_t a) {
+ return vpaddlq_u32(a);
+}
+
+
+// CHECK: test_vpmax_s8
+// CHECK: vpmax.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
+ return vpmax_s8(a, b);
+}
+
+// CHECK: test_vpmax_s16
+// CHECK: vpmax.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
+ return vpmax_s16(a, b);
+}
+
+// CHECK: test_vpmax_s32
+// CHECK: vpmax.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vpmax_s32(int32x2_t a, int32x2_t b) {
+ return vpmax_s32(a, b);
+}
+
+// CHECK: test_vpmax_u8
+// CHECK: vpmax.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
+ return vpmax_u8(a, b);
+}
+
+// CHECK: test_vpmax_u16
+// CHECK: vpmax.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
+ return vpmax_u16(a, b);
+}
+
+// CHECK: test_vpmax_u32
+// CHECK: vpmax.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
+ return vpmax_u32(a, b);
+}
+
+// CHECK: test_vpmax_f32
+// CHECK: vpmax.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vpmax_f32(float32x2_t a, float32x2_t b) {
+ return vpmax_f32(a, b);
+}
+
+
+// CHECK: test_vpmin_s8
+// CHECK: vpmin.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
+ return vpmin_s8(a, b);
+}
+
+// CHECK: test_vpmin_s16
+// CHECK: vpmin.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
+ return vpmin_s16(a, b);
+}
+
+// CHECK: test_vpmin_s32
+// CHECK: vpmin.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vpmin_s32(int32x2_t a, int32x2_t b) {
+ return vpmin_s32(a, b);
+}
+
+// CHECK: test_vpmin_u8
+// CHECK: vpmin.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
+ return vpmin_u8(a, b);
+}
+
+// CHECK: test_vpmin_u16
+// CHECK: vpmin.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
+ return vpmin_u16(a, b);
+}
+
+// CHECK: test_vpmin_u32
+// CHECK: vpmin.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
+ return vpmin_u32(a, b);
+}
+
+// CHECK: test_vpmin_f32
+// CHECK: vpmin.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vpmin_f32(float32x2_t a, float32x2_t b) {
+ return vpmin_f32(a, b);
+}
+
+
+// CHECK: test_vqabs_s8
+// CHECK: vqabs.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqabs_s8(int8x8_t a) {
+ return vqabs_s8(a);
+}
+
+// CHECK: test_vqabs_s16
+// CHECK: vqabs.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqabs_s16(int16x4_t a) {
+ return vqabs_s16(a);
+}
+
+// CHECK: test_vqabs_s32
+// CHECK: vqabs.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqabs_s32(int32x2_t a) {
+ return vqabs_s32(a);
+}
+
+// CHECK: test_vqabsq_s8
+// CHECK: vqabs.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqabsq_s8(int8x16_t a) {
+ return vqabsq_s8(a);
+}
+
+// CHECK: test_vqabsq_s16
+// CHECK: vqabs.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqabsq_s16(int16x8_t a) {
+ return vqabsq_s16(a);
+}
+
+// CHECK: test_vqabsq_s32
+// CHECK: vqabs.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqabsq_s32(int32x4_t a) {
+ return vqabsq_s32(a);
+}
+
+
+// CHECK: test_vqadd_s8
+// CHECK: vqadd.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
+ return vqadd_s8(a, b);
+}
+
+// CHECK: test_vqadd_s16
+// CHECK: vqadd.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
+ return vqadd_s16(a, b);
+}
+
+// CHECK: test_vqadd_s32
+// CHECK: vqadd.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
+ return vqadd_s32(a, b);
+}
+
+// CHECK: test_vqadd_s64
+// CHECK: vqadd.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
+ return vqadd_s64(a, b);
+}
+
+// CHECK: test_vqadd_u8
+// CHECK: vqadd.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
+ return vqadd_u8(a, b);
+}
+
+// CHECK: test_vqadd_u16
+// CHECK: vqadd.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
+ return vqadd_u16(a, b);
+}
+
+// CHECK: test_vqadd_u32
+// CHECK: vqadd.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
+ return vqadd_u32(a, b);
+}
+
+// CHECK: test_vqadd_u64
+// CHECK: vqadd.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
+ return vqadd_u64(a, b);
+}
+
+// CHECK: test_vqaddq_s8
+// CHECK: vqadd.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
+ return vqaddq_s8(a, b);
+}
+
+// CHECK: test_vqaddq_s16
+// CHECK: vqadd.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
+ return vqaddq_s16(a, b);
+}
+
+// CHECK: test_vqaddq_s32
+// CHECK: vqadd.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
+ return vqaddq_s32(a, b);
+}
+
+// CHECK: test_vqaddq_s64
+// CHECK: vqadd.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
+ return vqaddq_s64(a, b);
+}
+
+// CHECK: test_vqaddq_u8
+// CHECK: vqadd.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
+ return vqaddq_u8(a, b);
+}
+
+// CHECK: test_vqaddq_u16
+// CHECK: vqadd.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
+ return vqaddq_u16(a, b);
+}
+
+// CHECK: test_vqaddq_u32
+// CHECK: vqadd.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
+ return vqaddq_u32(a, b);
+}
+
+// CHECK: test_vqaddq_u64
+// CHECK: vqadd.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
+ return vqaddq_u64(a, b);
+}
+
+
+// CHECK: test_vqdmlal_s16
+// CHECK: vqdmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vqdmlal_s16(a, b, c);
+}
+
+// CHECK: test_vqdmlal_s32
+// CHECK: vqdmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vqdmlal_s32(a, b, c);
+}
+
+
+// CHECK: test_vqdmlal_lane_s16
+// CHECK: vqdmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vqdmlal_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vqdmlal_lane_s32
+// CHECK: vqdmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vqdmlal_lane_s32(a, b, c, 1);
+}
+
+
+// CHECK: test_vqdmlal_n_s16
+// CHECK: vqdmlal.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
+ return vqdmlal_n_s16(a, b, c);
+}
+
+// CHECK: test_vqdmlal_n_s32
+// CHECK: vqdmlal.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
+ return vqdmlal_n_s32(a, b, c);
+}
+
+
+// CHECK: test_vqdmlsl_s16
+// CHECK: vqdmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vqdmlsl_s16(a, b, c);
+}
+
+// CHECK: test_vqdmlsl_s32
+// CHECK: vqdmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vqdmlsl_s32(a, b, c);
+}
+
+
+// CHECK: test_vqdmlsl_lane_s16
+// CHECK: vqdmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
+ return vqdmlsl_lane_s16(a, b, c, 3);
+}
+
+// CHECK: test_vqdmlsl_lane_s32
+// CHECK: vqdmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
+ return vqdmlsl_lane_s32(a, b, c, 1);
+}
+
+
+// CHECK: test_vqdmlsl_n_s16
+// CHECK: vqdmlsl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
+ return vqdmlsl_n_s16(a, b, c);
+}
+
+// CHECK: test_vqdmlsl_n_s32
+// CHECK: vqdmlsl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
+ return vqdmlsl_n_s32(a, b, c);
+}
+
+
+// CHECK: test_vqdmulh_s16
+// CHECK: vqdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
+ return vqdmulh_s16(a, b);
+}
+
+// CHECK: test_vqdmulh_s32
+// CHECK: vqdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
+ return vqdmulh_s32(a, b);
+}
+
+// CHECK: test_vqdmulhq_s16
+// CHECK: vqdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
+ return vqdmulhq_s16(a, b);
+}
+
+// CHECK: test_vqdmulhq_s32
+// CHECK: vqdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
+ return vqdmulhq_s32(a, b);
+}
+
+
+// CHECK: test_vqdmulh_lane_s16
+// CHECK: vqdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t b) {
+ return vqdmulh_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vqdmulh_lane_s32
+// CHECK: vqdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t b) {
+ return vqdmulh_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vqdmulhq_lane_s16
+// CHECK: vqdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
+ return vqdmulhq_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vqdmulhq_lane_s32
+// CHECK: vqdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
+ return vqdmulhq_lane_s32(a, b, 1);
+}
+
+
+// CHECK: test_vqdmulh_n_s16
+// CHECK: vqdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqdmulh_n_s16(int16x4_t a, int16_t b) {
+ return vqdmulh_n_s16(a, b);
+}
+
+// CHECK: test_vqdmulh_n_s32
+// CHECK: vqdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqdmulh_n_s32(int32x2_t a, int32_t b) {
+ return vqdmulh_n_s32(a, b);
+}
+
+// CHECK: test_vqdmulhq_n_s16
+// CHECK: vqdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqdmulhq_n_s16(int16x8_t a, int16_t b) {
+ return vqdmulhq_n_s16(a, b);
+}
+
+// CHECK: test_vqdmulhq_n_s32
+// CHECK: vqdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqdmulhq_n_s32(int32x4_t a, int32_t b) {
+ return vqdmulhq_n_s32(a, b);
+}
+
+
+// CHECK: test_vqdmull_s16
+// CHECK: vqdmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
+ return vqdmull_s16(a, b);
+}
+
+// CHECK: test_vqdmull_s32
+// CHECK: vqdmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
+ return vqdmull_s32(a, b);
+}
+
+
+// CHECK: test_vqdmull_lane_s16
+// CHECK: vqdmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t b) {
+ return vqdmull_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vqdmull_lane_s32
+// CHECK: vqdmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t b) {
+ return vqdmull_lane_s32(a, b, 1);
+}
+
+
+// CHECK: test_vqdmull_n_s16
+// CHECK: vqdmull.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vqdmull_n_s16(int16x4_t a, int16_t b) {
+ return vqdmull_n_s16(a, b);
+}
+
+// CHECK: test_vqdmull_n_s32
+// CHECK: vqdmull.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vqdmull_n_s32(int32x2_t a, int32_t b) {
+ return vqdmull_n_s32(a, b);
+}
+
+
+// CHECK: test_vqmovn_s16
+// CHECK: vqmovn.s16 d{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vqmovn_s16(int16x8_t a) {
+ return vqmovn_s16(a);
+}
+
+// CHECK: test_vqmovn_s32
+// CHECK: vqmovn.s32 d{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vqmovn_s32(int32x4_t a) {
+ return vqmovn_s32(a);
+}
+
+// CHECK: test_vqmovn_s64
+// CHECK: vqmovn.s64 d{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vqmovn_s64(int64x2_t a) {
+ return vqmovn_s64(a);
+}
+
+// CHECK: test_vqmovn_u16
+// CHECK: vqmovn.u16 d{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vqmovn_u16(uint16x8_t a) {
+ return vqmovn_u16(a);
+}
+
+// CHECK: test_vqmovn_u32
+// CHECK: vqmovn.u32 d{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vqmovn_u32(uint32x4_t a) {
+ return vqmovn_u32(a);
+}
+
+// CHECK: test_vqmovn_u64
+// CHECK: vqmovn.u64 d{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vqmovn_u64(uint64x2_t a) {
+ return vqmovn_u64(a);
+}
+
+
+// CHECK: test_vqmovun_s16
+// CHECK: vqmovun.s16 d{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vqmovun_s16(int16x8_t a) {
+ return vqmovun_s16(a);
+}
+
+// CHECK: test_vqmovun_s32
+// CHECK: vqmovun.s32 d{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vqmovun_s32(int32x4_t a) {
+ return vqmovun_s32(a);
+}
+
+// CHECK: test_vqmovun_s64
+// CHECK: vqmovun.s64 d{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vqmovun_s64(int64x2_t a) {
+ return vqmovun_s64(a);
+}
+
+
+// CHECK: test_vqneg_s8
+// CHECK: vqneg.s8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqneg_s8(int8x8_t a) {
+ return vqneg_s8(a);
+}
+
+// CHECK: test_vqneg_s16
+// CHECK: vqneg.s16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqneg_s16(int16x4_t a) {
+ return vqneg_s16(a);
+}
+
+// CHECK: test_vqneg_s32
+// CHECK: vqneg.s32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqneg_s32(int32x2_t a) {
+ return vqneg_s32(a);
+}
+
+// CHECK: test_vqnegq_s8
+// CHECK: vqneg.s8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqnegq_s8(int8x16_t a) {
+ return vqnegq_s8(a);
+}
+
+// CHECK: test_vqnegq_s16
+// CHECK: vqneg.s16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqnegq_s16(int16x8_t a) {
+ return vqnegq_s16(a);
+}
+
+// CHECK: test_vqnegq_s32
+// CHECK: vqneg.s32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqnegq_s32(int32x4_t a) {
+ return vqnegq_s32(a);
+}
+
+
+// CHECK: test_vqrdmulh_s16
+// CHECK: vqrdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
+ return vqrdmulh_s16(a, b);
+}
+
+// CHECK: test_vqrdmulh_s32
+// CHECK: vqrdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
+ return vqrdmulh_s32(a, b);
+}
+
+// CHECK: test_vqrdmulhq_s16
+// CHECK: vqrdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
+ return vqrdmulhq_s16(a, b);
+}
+
+// CHECK: test_vqrdmulhq_s32
+// CHECK: vqrdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
+ return vqrdmulhq_s32(a, b);
+}
+
+
+// CHECK: test_vqrdmulh_lane_s16
+// CHECK: vqrdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t b) {
+ return vqrdmulh_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vqrdmulh_lane_s32
+// CHECK: vqrdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t b) {
+ return vqrdmulh_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vqrdmulhq_lane_s16
+// CHECK: vqrdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
+ return vqrdmulhq_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vqrdmulhq_lane_s32
+// CHECK: vqrdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}[{{[0-9]}}]
+int32x4_t test_vqrdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
+ return vqrdmulhq_lane_s32(a, b, 1);
+}
+
+
+// CHECK: test_vqrdmulh_n_s16
+// CHECK: vqrdmulh.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqrdmulh_n_s16(int16x4_t a, int16_t b) {
+ return vqrdmulh_n_s16(a, b);
+}
+
+// CHECK: test_vqrdmulh_n_s32
+// CHECK: vqrdmulh.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqrdmulh_n_s32(int32x2_t a, int32_t b) {
+ return vqrdmulh_n_s32(a, b);
+}
+
+// CHECK: test_vqrdmulhq_n_s16
+// CHECK: vqrdmulh.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqrdmulhq_n_s16(int16x8_t a, int16_t b) {
+ return vqrdmulhq_n_s16(a, b);
+}
+
+// CHECK: test_vqrdmulhq_n_s32
+// CHECK: vqrdmulh.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqrdmulhq_n_s32(int32x4_t a, int32_t b) {
+ return vqrdmulhq_n_s32(a, b);
+}
+
+
+// CHECK: test_vqrshl_s8
+// CHECK: vqrshl.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
+ return vqrshl_s8(a, b);
+}
+
+// CHECK: test_vqrshl_s16
+// CHECK: vqrshl.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
+ return vqrshl_s16(a, b);
+}
+
+// CHECK: test_vqrshl_s32
+// CHECK: vqrshl.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
+ return vqrshl_s32(a, b);
+}
+
+// CHECK: test_vqrshl_s64
+// CHECK: vqrshl.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
+ return vqrshl_s64(a, b);
+}
+
+// CHECK: test_vqrshl_u8
+// CHECK: vqrshl.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
+ return vqrshl_u8(a, b);
+}
+
+// CHECK: test_vqrshl_u16
+// CHECK: vqrshl.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
+ return vqrshl_u16(a, b);
+}
+
+// CHECK: test_vqrshl_u32
+// CHECK: vqrshl.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
+ return vqrshl_u32(a, b);
+}
+
+// CHECK: test_vqrshl_u64
+// CHECK: vqrshl.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
+ return vqrshl_u64(a, b);
+}
+
+// CHECK: test_vqrshlq_s8
+// CHECK: vqrshl.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
+ return vqrshlq_s8(a, b);
+}
+
+// CHECK: test_vqrshlq_s16
+// CHECK: vqrshl.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
+ return vqrshlq_s16(a, b);
+}
+
+// CHECK: test_vqrshlq_s32
+// CHECK: vqrshl.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
+ return vqrshlq_s32(a, b);
+}
+
+// CHECK: test_vqrshlq_s64
+// CHECK: vqrshl.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
+ return vqrshlq_s64(a, b);
+}
+
+// CHECK: test_vqrshlq_u8
+// CHECK: vqrshl.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
+ return vqrshlq_u8(a, b);
+}
+
+// CHECK: test_vqrshlq_u16
+// CHECK: vqrshl.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
+ return vqrshlq_u16(a, b);
+}
+
+// CHECK: test_vqrshlq_u32
+// CHECK: vqrshl.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
+ return vqrshlq_u32(a, b);
+}
+
+// CHECK: test_vqrshlq_u64
+// CHECK: vqrshl.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vqrshlq_u64(uint64x2_t a, int64x2_t b) {
+ return vqrshlq_u64(a, b);
+}
+
+
+// CHECK: test_vqrshrn_n_s16
+// CHECK: vqrshrn.s16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vqrshrn_n_s16(int16x8_t a) {
+ return vqrshrn_n_s16(a, 1);
+}
+
+// CHECK: test_vqrshrn_n_s32
+// CHECK: vqrshrn.s32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vqrshrn_n_s32(int32x4_t a) {
+ return vqrshrn_n_s32(a, 1);
+}
+
+// CHECK: test_vqrshrn_n_s64
+// CHECK: vqrshrn.s64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vqrshrn_n_s64(int64x2_t a) {
+ return vqrshrn_n_s64(a, 1);
+}
+
+// CHECK: test_vqrshrn_n_u16
+// CHECK: vqrshrn.u16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqrshrn_n_u16(uint16x8_t a) {
+ return vqrshrn_n_u16(a, 1);
+}
+
+// CHECK: test_vqrshrn_n_u32
+// CHECK: vqrshrn.u32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqrshrn_n_u32(uint32x4_t a) {
+ return vqrshrn_n_u32(a, 1);
+}
+
+// CHECK: test_vqrshrn_n_u64
+// CHECK: vqrshrn.u64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqrshrn_n_u64(uint64x2_t a) {
+ return vqrshrn_n_u64(a, 1);
+}
+
+
+// CHECK: test_vqrshrun_n_s16
+// CHECK: vqrshrun.s16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqrshrun_n_s16(int16x8_t a) {
+ return vqrshrun_n_s16(a, 1);
+}
+
+// CHECK: test_vqrshrun_n_s32
+// CHECK: vqrshrun.s32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqrshrun_n_s32(int32x4_t a) {
+ return vqrshrun_n_s32(a, 1);
+}
+
+// CHECK: test_vqrshrun_n_s64
+// CHECK: vqrshrun.s64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqrshrun_n_s64(int64x2_t a) {
+ return vqrshrun_n_s64(a, 1);
+}
+
+
+// CHECK: test_vqshl_s8
+// CHECK: vqshl.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
+ return vqshl_s8(a, b);
+}
+
+// CHECK: test_vqshl_s16
+// CHECK: vqshl.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
+ return vqshl_s16(a, b);
+}
+
+// CHECK: test_vqshl_s32
+// CHECK: vqshl.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
+ return vqshl_s32(a, b);
+}
+
+// CHECK: test_vqshl_s64
+// CHECK: vqshl.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
+ return vqshl_s64(a, b);
+}
+
+// CHECK: test_vqshl_u8
+// CHECK: vqshl.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
+ return vqshl_u8(a, b);
+}
+
+// CHECK: test_vqshl_u16
+// CHECK: vqshl.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
+ return vqshl_u16(a, b);
+}
+
+// CHECK: test_vqshl_u32
+// CHECK: vqshl.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
+ return vqshl_u32(a, b);
+}
+
+// CHECK: test_vqshl_u64
+// CHECK: vqshl.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
+ return vqshl_u64(a, b);
+}
+
+// CHECK: test_vqshlq_s8
+// CHECK: vqshl.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
+ return vqshlq_s8(a, b);
+}
+
+// CHECK: test_vqshlq_s16
+// CHECK: vqshl.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
+ return vqshlq_s16(a, b);
+}
+
+// CHECK: test_vqshlq_s32
+// CHECK: vqshl.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
+ return vqshlq_s32(a, b);
+}
+
+// CHECK: test_vqshlq_s64
+// CHECK: vqshl.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
+ return vqshlq_s64(a, b);
+}
+
+// CHECK: test_vqshlq_u8
+// CHECK: vqshl.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
+ return vqshlq_u8(a, b);
+}
+
+// CHECK: test_vqshlq_u16
+// CHECK: vqshl.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
+ return vqshlq_u16(a, b);
+}
+
+// CHECK: test_vqshlq_u32
+// CHECK: vqshl.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
+ return vqshlq_u32(a, b);
+}
+
+// CHECK: test_vqshlq_u64
+// CHECK: vqshl.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vqshlq_u64(uint64x2_t a, int64x2_t b) {
+ return vqshlq_u64(a, b);
+}
+
+
+// CHECK: test_vqshlu_n_s8
+// CHECK: vqshlu.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqshlu_n_s8(int8x8_t a) {
+ return vqshlu_n_s8(a, 1);
+}
+
+// CHECK: test_vqshlu_n_s16
+// CHECK: vqshlu.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqshlu_n_s16(int16x4_t a) {
+ return vqshlu_n_s16(a, 1);
+}
+
+// CHECK: test_vqshlu_n_s32
+// CHECK: vqshlu.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqshlu_n_s32(int32x2_t a) {
+ return vqshlu_n_s32(a, 1);
+}
+
+// CHECK: test_vqshlu_n_s64
+// CHECK: vqshlu.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vqshlu_n_s64(int64x1_t a) {
+ return vqshlu_n_s64(a, 1);
+}
+
+// CHECK: test_vqshluq_n_s8
+// CHECK: vqshlu.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vqshluq_n_s8(int8x16_t a) {
+ return vqshluq_n_s8(a, 1);
+}
+
+// CHECK: test_vqshluq_n_s16
+// CHECK: vqshlu.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vqshluq_n_s16(int16x8_t a) {
+ return vqshluq_n_s16(a, 1);
+}
+
+// CHECK: test_vqshluq_n_s32
+// CHECK: vqshlu.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vqshluq_n_s32(int32x4_t a) {
+ return vqshluq_n_s32(a, 1);
+}
+
+// CHECK: test_vqshluq_n_s64
+// CHECK: vqshlu.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vqshluq_n_s64(int64x2_t a) {
+ return vqshluq_n_s64(a, 1);
+}
+
+
+// CHECK: test_vqshl_n_s8
+// CHECK: vqshl.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vqshl_n_s8(int8x8_t a) {
+ return vqshl_n_s8(a, 1);
+}
+
+// CHECK: test_vqshl_n_s16
+// CHECK: vqshl.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vqshl_n_s16(int16x4_t a) {
+ return vqshl_n_s16(a, 1);
+}
+
+// CHECK: test_vqshl_n_s32
+// CHECK: vqshl.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vqshl_n_s32(int32x2_t a) {
+ return vqshl_n_s32(a, 1);
+}
+
+// CHECK: test_vqshl_n_s64
+// CHECK: vqshl.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vqshl_n_s64(int64x1_t a) {
+ return vqshl_n_s64(a, 1);
+}
+
+// CHECK: test_vqshl_n_u8
+// CHECK: vqshl.u8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqshl_n_u8(uint8x8_t a) {
+ return vqshl_n_u8(a, 1);
+}
+
+// CHECK: test_vqshl_n_u16
+// CHECK: vqshl.u16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqshl_n_u16(uint16x4_t a) {
+ return vqshl_n_u16(a, 1);
+}
+
+// CHECK: test_vqshl_n_u32
+// CHECK: vqshl.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqshl_n_u32(uint32x2_t a) {
+ return vqshl_n_u32(a, 1);
+}
+
+// CHECK: test_vqshl_n_u64
+// CHECK: vqshl.u64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vqshl_n_u64(uint64x1_t a) {
+ return vqshl_n_u64(a, 1);
+}
+
+// CHECK: test_vqshlq_n_s8
+// CHECK: vqshl.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vqshlq_n_s8(int8x16_t a) {
+ return vqshlq_n_s8(a, 1);
+}
+
+// CHECK: test_vqshlq_n_s16
+// CHECK: vqshl.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vqshlq_n_s16(int16x8_t a) {
+ return vqshlq_n_s16(a, 1);
+}
+
+// CHECK: test_vqshlq_n_s32
+// CHECK: vqshl.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vqshlq_n_s32(int32x4_t a) {
+ return vqshlq_n_s32(a, 1);
+}
+
+// CHECK: test_vqshlq_n_s64
+// CHECK: vqshl.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vqshlq_n_s64(int64x2_t a) {
+ return vqshlq_n_s64(a, 1);
+}
+
+// CHECK: test_vqshlq_n_u8
+// CHECK: vqshl.u8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vqshlq_n_u8(uint8x16_t a) {
+ return vqshlq_n_u8(a, 1);
+}
+
+// CHECK: test_vqshlq_n_u16
+// CHECK: vqshl.u16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vqshlq_n_u16(uint16x8_t a) {
+ return vqshlq_n_u16(a, 1);
+}
+
+// CHECK: test_vqshlq_n_u32
+// CHECK: vqshl.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vqshlq_n_u32(uint32x4_t a) {
+ return vqshlq_n_u32(a, 1);
+}
+
+// CHECK: test_vqshlq_n_u64
+// CHECK: vqshl.u64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vqshlq_n_u64(uint64x2_t a) {
+ return vqshlq_n_u64(a, 1);
+}
+
+
+// CHECK: test_vqshrn_n_s16
+// CHECK: vqshrn.s16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vqshrn_n_s16(int16x8_t a) {
+ return vqshrn_n_s16(a, 1);
+}
+
+// CHECK: test_vqshrn_n_s32
+// CHECK: vqshrn.s32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vqshrn_n_s32(int32x4_t a) {
+ return vqshrn_n_s32(a, 1);
+}
+
+// CHECK: test_vqshrn_n_s64
+// CHECK: vqshrn.s64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vqshrn_n_s64(int64x2_t a) {
+ return vqshrn_n_s64(a, 1);
+}
+
+// CHECK: test_vqshrn_n_u16
+// CHECK: vqshrn.u16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqshrn_n_u16(uint16x8_t a) {
+ return vqshrn_n_u16(a, 1);
+}
+
+// CHECK: test_vqshrn_n_u32
+// CHECK: vqshrn.u32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqshrn_n_u32(uint32x4_t a) {
+ return vqshrn_n_u32(a, 1);
+}
+
+// CHECK: test_vqshrn_n_u64
+// CHECK: vqshrn.u64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqshrn_n_u64(uint64x2_t a) {
+ return vqshrn_n_u64(a, 1);
+}
+
+
+// CHECK: test_vqshrun_n_s16
+// CHECK: vqshrun.s16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vqshrun_n_s16(int16x8_t a) {
+ return vqshrun_n_s16(a, 1);
+}
+
+// CHECK: test_vqshrun_n_s32
+// CHECK: vqshrun.s32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vqshrun_n_s32(int32x4_t a) {
+ return vqshrun_n_s32(a, 1);
+}
+
+// CHECK: test_vqshrun_n_s64
+// CHECK: vqshrun.s64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vqshrun_n_s64(int64x2_t a) {
+ return vqshrun_n_s64(a, 1);
+}
+
+
+// CHECK: test_vqsub_s8
+// CHECK: vqsub.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
+ return vqsub_s8(a, b);
+}
+
+// CHECK: test_vqsub_s16
+// CHECK: vqsub.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
+ return vqsub_s16(a, b);
+}
+
+// CHECK: test_vqsub_s32
+// CHECK: vqsub.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
+ return vqsub_s32(a, b);
+}
+
+// CHECK: test_vqsub_s64
+// CHECK: vqsub.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
+ return vqsub_s64(a, b);
+}
+
+// CHECK: test_vqsub_u8
+// CHECK: vqsub.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
+ return vqsub_u8(a, b);
+}
+
+// CHECK: test_vqsub_u16
+// CHECK: vqsub.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
+ return vqsub_u16(a, b);
+}
+
+// CHECK: test_vqsub_u32
+// CHECK: vqsub.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
+ return vqsub_u32(a, b);
+}
+
+// CHECK: test_vqsub_u64
+// CHECK: vqsub.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
+ return vqsub_u64(a, b);
+}
+
+// CHECK: test_vqsubq_s8
+// CHECK: vqsub.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
+ return vqsubq_s8(a, b);
+}
+
+// CHECK: test_vqsubq_s16
+// CHECK: vqsub.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
+ return vqsubq_s16(a, b);
+}
+
+// CHECK: test_vqsubq_s32
+// CHECK: vqsub.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
+ return vqsubq_s32(a, b);
+}
+
+// CHECK: test_vqsubq_s64
+// CHECK: vqsub.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
+ return vqsubq_s64(a, b);
+}
+
+// CHECK: test_vqsubq_u8
+// CHECK: vqsub.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
+ return vqsubq_u8(a, b);
+}
+
+// CHECK: test_vqsubq_u16
+// CHECK: vqsub.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
+ return vqsubq_u16(a, b);
+}
+
+// CHECK: test_vqsubq_u32
+// CHECK: vqsub.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
+ return vqsubq_u32(a, b);
+}
+
+// CHECK: test_vqsubq_u64
+// CHECK: vqsub.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
+ return vqsubq_u64(a, b);
+}
+
+
+// CHECK: test_vraddhn_s16
+// CHECK: vraddhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
+ return vraddhn_s16(a, b);
+}
+
+// CHECK: test_vraddhn_s32
+// CHECK: vraddhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
+ return vraddhn_s32(a, b);
+}
+
+// CHECK: test_vraddhn_s64
+// CHECK: vraddhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
+ return vraddhn_s64(a, b);
+}
+
+// CHECK: test_vraddhn_u16
+// CHECK: vraddhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
+ return vraddhn_u16(a, b);
+}
+
+// CHECK: test_vraddhn_u32
+// CHECK: vraddhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
+ return vraddhn_u32(a, b);
+}
+
+// CHECK: test_vraddhn_u64
+// CHECK: vraddhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
+ return vraddhn_u64(a, b);
+}
+
+
+// CHECK: test_vrecpe_f32
+// CHECK: vrecpe.f32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vrecpe_f32(float32x2_t a) {
+ return vrecpe_f32(a);
+}
+
+// CHECK: test_vrecpe_u32
+// CHECK: vrecpe.u32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vrecpe_u32(uint32x2_t a) {
+ return vrecpe_u32(a);
+}
+
+// CHECK: test_vrecpeq_f32
+// CHECK: vrecpe.f32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vrecpeq_f32(float32x4_t a) {
+ return vrecpeq_f32(a);
+}
+
+// CHECK: test_vrecpeq_u32
+// CHECK: vrecpe.u32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
+ return vrecpeq_u32(a);
+}
+
+
+// CHECK: test_vrecps_f32
+// CHECK: vrecps.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vrecps_f32(float32x2_t a, float32x2_t b) {
+ return vrecps_f32(a, b);
+}
+
+// CHECK: test_vrecpsq_f32
+// CHECK: vrecps.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vrecpsq_f32(float32x4_t a, float32x4_t b) {
+ return vrecpsq_f32(a, b);
+}
+
+
+// CHECK: test_vreinterpret_s8_s16
+int8x8_t test_vreinterpret_s8_s16(int16x4_t a) {
+ return vreinterpret_s8_s16(a);
+}
+
+// CHECK: test_vreinterpret_s8_s32
+int8x8_t test_vreinterpret_s8_s32(int32x2_t a) {
+ return vreinterpret_s8_s32(a);
+}
+
+// CHECK: test_vreinterpret_s8_s64
+int8x8_t test_vreinterpret_s8_s64(int64x1_t a) {
+ return vreinterpret_s8_s64(a);
+}
+
+// CHECK: test_vreinterpret_s8_u8
+int8x8_t test_vreinterpret_s8_u8(uint8x8_t a) {
+ return vreinterpret_s8_u8(a);
+}
+
+// CHECK: test_vreinterpret_s8_u16
+int8x8_t test_vreinterpret_s8_u16(uint16x4_t a) {
+ return vreinterpret_s8_u16(a);
+}
+
+// CHECK: test_vreinterpret_s8_u32
+int8x8_t test_vreinterpret_s8_u32(uint32x2_t a) {
+ return vreinterpret_s8_u32(a);
+}
+
+// CHECK: test_vreinterpret_s8_u64
+int8x8_t test_vreinterpret_s8_u64(uint64x1_t a) {
+ return vreinterpret_s8_u64(a);
+}
+
+// CHECK: test_vreinterpret_s8_f16
+int8x8_t test_vreinterpret_s8_f16(float16x4_t a) {
+ return vreinterpret_s8_f16(a);
+}
+
+// CHECK: test_vreinterpret_s8_f32
+int8x8_t test_vreinterpret_s8_f32(float32x2_t a) {
+ return vreinterpret_s8_f32(a);
+}
+
+// CHECK: test_vreinterpret_s8_p8
+int8x8_t test_vreinterpret_s8_p8(poly8x8_t a) {
+ return vreinterpret_s8_p8(a);
+}
+
+// CHECK: test_vreinterpret_s8_p16
+int8x8_t test_vreinterpret_s8_p16(poly16x4_t a) {
+ return vreinterpret_s8_p16(a);
+}
+
+// CHECK: test_vreinterpret_s16_s8
+int16x4_t test_vreinterpret_s16_s8(int8x8_t a) {
+ return vreinterpret_s16_s8(a);
+}
+
+// CHECK: test_vreinterpret_s16_s32
+int16x4_t test_vreinterpret_s16_s32(int32x2_t a) {
+ return vreinterpret_s16_s32(a);
+}
+
+// CHECK: test_vreinterpret_s16_s64
+int16x4_t test_vreinterpret_s16_s64(int64x1_t a) {
+ return vreinterpret_s16_s64(a);
+}
+
+// CHECK: test_vreinterpret_s16_u8
+int16x4_t test_vreinterpret_s16_u8(uint8x8_t a) {
+ return vreinterpret_s16_u8(a);
+}
+
+// CHECK: test_vreinterpret_s16_u16
+int16x4_t test_vreinterpret_s16_u16(uint16x4_t a) {
+ return vreinterpret_s16_u16(a);
+}
+
+// CHECK: test_vreinterpret_s16_u32
+int16x4_t test_vreinterpret_s16_u32(uint32x2_t a) {
+ return vreinterpret_s16_u32(a);
+}
+
+// CHECK: test_vreinterpret_s16_u64
+int16x4_t test_vreinterpret_s16_u64(uint64x1_t a) {
+ return vreinterpret_s16_u64(a);
+}
+
+// CHECK: test_vreinterpret_s16_f16
+int16x4_t test_vreinterpret_s16_f16(float16x4_t a) {
+ return vreinterpret_s16_f16(a);
+}
+
+// CHECK: test_vreinterpret_s16_f32
+int16x4_t test_vreinterpret_s16_f32(float32x2_t a) {
+ return vreinterpret_s16_f32(a);
+}
+
+// CHECK: test_vreinterpret_s16_p8
+int16x4_t test_vreinterpret_s16_p8(poly8x8_t a) {
+ return vreinterpret_s16_p8(a);
+}
+
+// CHECK: test_vreinterpret_s16_p16
+int16x4_t test_vreinterpret_s16_p16(poly16x4_t a) {
+ return vreinterpret_s16_p16(a);
+}
+
+// CHECK: test_vreinterpret_s32_s8
+int32x2_t test_vreinterpret_s32_s8(int8x8_t a) {
+ return vreinterpret_s32_s8(a);
+}
+
+// CHECK: test_vreinterpret_s32_s16
+int32x2_t test_vreinterpret_s32_s16(int16x4_t a) {
+ return vreinterpret_s32_s16(a);
+}
+
+// CHECK: test_vreinterpret_s32_s64
+int32x2_t test_vreinterpret_s32_s64(int64x1_t a) {
+ return vreinterpret_s32_s64(a);
+}
+
+// CHECK: test_vreinterpret_s32_u8
+int32x2_t test_vreinterpret_s32_u8(uint8x8_t a) {
+ return vreinterpret_s32_u8(a);
+}
+
+// CHECK: test_vreinterpret_s32_u16
+int32x2_t test_vreinterpret_s32_u16(uint16x4_t a) {
+ return vreinterpret_s32_u16(a);
+}
+
+// CHECK: test_vreinterpret_s32_u32
+int32x2_t test_vreinterpret_s32_u32(uint32x2_t a) {
+ return vreinterpret_s32_u32(a);
+}
+
+// CHECK: test_vreinterpret_s32_u64
+int32x2_t test_vreinterpret_s32_u64(uint64x1_t a) {
+ return vreinterpret_s32_u64(a);
+}
+
+// CHECK: test_vreinterpret_s32_f16
+int32x2_t test_vreinterpret_s32_f16(float16x4_t a) {
+ return vreinterpret_s32_f16(a);
+}
+
+// CHECK: test_vreinterpret_s32_f32
+int32x2_t test_vreinterpret_s32_f32(float32x2_t a) {
+ return vreinterpret_s32_f32(a);
+}
+
+// CHECK: test_vreinterpret_s32_p8
+int32x2_t test_vreinterpret_s32_p8(poly8x8_t a) {
+ return vreinterpret_s32_p8(a);
+}
+
+// CHECK: test_vreinterpret_s32_p16
+int32x2_t test_vreinterpret_s32_p16(poly16x4_t a) {
+ return vreinterpret_s32_p16(a);
+}
+
+// CHECK: test_vreinterpret_s64_s8
+int64x1_t test_vreinterpret_s64_s8(int8x8_t a) {
+ return vreinterpret_s64_s8(a);
+}
+
+// CHECK: test_vreinterpret_s64_s16
+int64x1_t test_vreinterpret_s64_s16(int16x4_t a) {
+ return vreinterpret_s64_s16(a);
+}
+
+// CHECK: test_vreinterpret_s64_s32
+int64x1_t test_vreinterpret_s64_s32(int32x2_t a) {
+ return vreinterpret_s64_s32(a);
+}
+
+// CHECK: test_vreinterpret_s64_u8
+int64x1_t test_vreinterpret_s64_u8(uint8x8_t a) {
+ return vreinterpret_s64_u8(a);
+}
+
+// CHECK: test_vreinterpret_s64_u16
+int64x1_t test_vreinterpret_s64_u16(uint16x4_t a) {
+ return vreinterpret_s64_u16(a);
+}
+
+// CHECK: test_vreinterpret_s64_u32
+int64x1_t test_vreinterpret_s64_u32(uint32x2_t a) {
+ return vreinterpret_s64_u32(a);
+}
+
+// CHECK: test_vreinterpret_s64_u64
+int64x1_t test_vreinterpret_s64_u64(uint64x1_t a) {
+ return vreinterpret_s64_u64(a);
+}
+
+// CHECK: test_vreinterpret_s64_f16
+int64x1_t test_vreinterpret_s64_f16(float16x4_t a) {
+ return vreinterpret_s64_f16(a);
+}
+
+// CHECK: test_vreinterpret_s64_f32
+int64x1_t test_vreinterpret_s64_f32(float32x2_t a) {
+ return vreinterpret_s64_f32(a);
+}
+
+// CHECK: test_vreinterpret_s64_p8
+int64x1_t test_vreinterpret_s64_p8(poly8x8_t a) {
+ return vreinterpret_s64_p8(a);
+}
+
+// CHECK: test_vreinterpret_s64_p16
+int64x1_t test_vreinterpret_s64_p16(poly16x4_t a) {
+ return vreinterpret_s64_p16(a);
+}
+
+// CHECK: test_vreinterpret_u8_s8
+uint8x8_t test_vreinterpret_u8_s8(int8x8_t a) {
+ return vreinterpret_u8_s8(a);
+}
+
+// CHECK: test_vreinterpret_u8_s16
+uint8x8_t test_vreinterpret_u8_s16(int16x4_t a) {
+ return vreinterpret_u8_s16(a);
+}
+
+// CHECK: test_vreinterpret_u8_s32
+uint8x8_t test_vreinterpret_u8_s32(int32x2_t a) {
+ return vreinterpret_u8_s32(a);
+}
+
+// CHECK: test_vreinterpret_u8_s64
+uint8x8_t test_vreinterpret_u8_s64(int64x1_t a) {
+ return vreinterpret_u8_s64(a);
+}
+
+// CHECK: test_vreinterpret_u8_u16
+uint8x8_t test_vreinterpret_u8_u16(uint16x4_t a) {
+ return vreinterpret_u8_u16(a);
+}
+
+// CHECK: test_vreinterpret_u8_u32
+uint8x8_t test_vreinterpret_u8_u32(uint32x2_t a) {
+ return vreinterpret_u8_u32(a);
+}
+
+// CHECK: test_vreinterpret_u8_u64
+uint8x8_t test_vreinterpret_u8_u64(uint64x1_t a) {
+ return vreinterpret_u8_u64(a);
+}
+
+// CHECK: test_vreinterpret_u8_f16
+uint8x8_t test_vreinterpret_u8_f16(float16x4_t a) {
+ return vreinterpret_u8_f16(a);
+}
+
+// CHECK: test_vreinterpret_u8_f32
+uint8x8_t test_vreinterpret_u8_f32(float32x2_t a) {
+ return vreinterpret_u8_f32(a);
+}
+
+// CHECK: test_vreinterpret_u8_p8
+uint8x8_t test_vreinterpret_u8_p8(poly8x8_t a) {
+ return vreinterpret_u8_p8(a);
+}
+
+// CHECK: test_vreinterpret_u8_p16
+uint8x8_t test_vreinterpret_u8_p16(poly16x4_t a) {
+ return vreinterpret_u8_p16(a);
+}
+
+// CHECK: test_vreinterpret_u16_s8
+uint16x4_t test_vreinterpret_u16_s8(int8x8_t a) {
+ return vreinterpret_u16_s8(a);
+}
+
+// CHECK: test_vreinterpret_u16_s16
+uint16x4_t test_vreinterpret_u16_s16(int16x4_t a) {
+ return vreinterpret_u16_s16(a);
+}
+
+// CHECK: test_vreinterpret_u16_s32
+uint16x4_t test_vreinterpret_u16_s32(int32x2_t a) {
+ return vreinterpret_u16_s32(a);
+}
+
+// CHECK: test_vreinterpret_u16_s64
+uint16x4_t test_vreinterpret_u16_s64(int64x1_t a) {
+ return vreinterpret_u16_s64(a);
+}
+
+// CHECK: test_vreinterpret_u16_u8
+uint16x4_t test_vreinterpret_u16_u8(uint8x8_t a) {
+ return vreinterpret_u16_u8(a);
+}
+
+// CHECK: test_vreinterpret_u16_u32
+uint16x4_t test_vreinterpret_u16_u32(uint32x2_t a) {
+ return vreinterpret_u16_u32(a);
+}
+
+// CHECK: test_vreinterpret_u16_u64
+uint16x4_t test_vreinterpret_u16_u64(uint64x1_t a) {
+ return vreinterpret_u16_u64(a);
+}
+
+// CHECK: test_vreinterpret_u16_f16
+uint16x4_t test_vreinterpret_u16_f16(float16x4_t a) {
+ return vreinterpret_u16_f16(a);
+}
+
+// CHECK: test_vreinterpret_u16_f32
+uint16x4_t test_vreinterpret_u16_f32(float32x2_t a) {
+ return vreinterpret_u16_f32(a);
+}
+
+// CHECK: test_vreinterpret_u16_p8
+uint16x4_t test_vreinterpret_u16_p8(poly8x8_t a) {
+ return vreinterpret_u16_p8(a);
+}
+
+// CHECK: test_vreinterpret_u16_p16
+uint16x4_t test_vreinterpret_u16_p16(poly16x4_t a) {
+ return vreinterpret_u16_p16(a);
+}
+
+// CHECK: test_vreinterpret_u32_s8
+uint32x2_t test_vreinterpret_u32_s8(int8x8_t a) {
+ return vreinterpret_u32_s8(a);
+}
+
+// CHECK: test_vreinterpret_u32_s16
+uint32x2_t test_vreinterpret_u32_s16(int16x4_t a) {
+ return vreinterpret_u32_s16(a);
+}
+
+// CHECK: test_vreinterpret_u32_s32
+uint32x2_t test_vreinterpret_u32_s32(int32x2_t a) {
+ return vreinterpret_u32_s32(a);
+}
+
+// CHECK: test_vreinterpret_u32_s64
+uint32x2_t test_vreinterpret_u32_s64(int64x1_t a) {
+ return vreinterpret_u32_s64(a);
+}
+
+// CHECK: test_vreinterpret_u32_u8
+uint32x2_t test_vreinterpret_u32_u8(uint8x8_t a) {
+ return vreinterpret_u32_u8(a);
+}
+
+// CHECK: test_vreinterpret_u32_u16
+uint32x2_t test_vreinterpret_u32_u16(uint16x4_t a) {
+ return vreinterpret_u32_u16(a);
+}
+
+// CHECK: test_vreinterpret_u32_u64
+uint32x2_t test_vreinterpret_u32_u64(uint64x1_t a) {
+ return vreinterpret_u32_u64(a);
+}
+
+// CHECK: test_vreinterpret_u32_f16
+uint32x2_t test_vreinterpret_u32_f16(float16x4_t a) {
+ return vreinterpret_u32_f16(a);
+}
+
+// CHECK: test_vreinterpret_u32_f32
+uint32x2_t test_vreinterpret_u32_f32(float32x2_t a) {
+ return vreinterpret_u32_f32(a);
+}
+
+// CHECK: test_vreinterpret_u32_p8
+uint32x2_t test_vreinterpret_u32_p8(poly8x8_t a) {
+ return vreinterpret_u32_p8(a);
+}
+
+// CHECK: test_vreinterpret_u32_p16
+uint32x2_t test_vreinterpret_u32_p16(poly16x4_t a) {
+ return vreinterpret_u32_p16(a);
+}
+
+// CHECK: test_vreinterpret_u64_s8
+uint64x1_t test_vreinterpret_u64_s8(int8x8_t a) {
+ return vreinterpret_u64_s8(a);
+}
+
+// CHECK: test_vreinterpret_u64_s16
+uint64x1_t test_vreinterpret_u64_s16(int16x4_t a) {
+ return vreinterpret_u64_s16(a);
+}
+
+// CHECK: test_vreinterpret_u64_s32
+uint64x1_t test_vreinterpret_u64_s32(int32x2_t a) {
+ return vreinterpret_u64_s32(a);
+}
+
+// CHECK: test_vreinterpret_u64_s64
+uint64x1_t test_vreinterpret_u64_s64(int64x1_t a) {
+ return vreinterpret_u64_s64(a);
+}
+
+// CHECK: test_vreinterpret_u64_u8
+uint64x1_t test_vreinterpret_u64_u8(uint8x8_t a) {
+ return vreinterpret_u64_u8(a);
+}
+
+// CHECK: test_vreinterpret_u64_u16
+uint64x1_t test_vreinterpret_u64_u16(uint16x4_t a) {
+ return vreinterpret_u64_u16(a);
+}
+
+// CHECK: test_vreinterpret_u64_u32
+uint64x1_t test_vreinterpret_u64_u32(uint32x2_t a) {
+ return vreinterpret_u64_u32(a);
+}
+
+// CHECK: test_vreinterpret_u64_f16
+uint64x1_t test_vreinterpret_u64_f16(float16x4_t a) {
+ return vreinterpret_u64_f16(a);
+}
+
+// CHECK: test_vreinterpret_u64_f32
+uint64x1_t test_vreinterpret_u64_f32(float32x2_t a) {
+ return vreinterpret_u64_f32(a);
+}
+
+// CHECK: test_vreinterpret_u64_p8
+uint64x1_t test_vreinterpret_u64_p8(poly8x8_t a) {
+ return vreinterpret_u64_p8(a);
+}
+
+// CHECK: test_vreinterpret_u64_p16
+uint64x1_t test_vreinterpret_u64_p16(poly16x4_t a) {
+ return vreinterpret_u64_p16(a);
+}
+
+// CHECK: test_vreinterpret_f16_s8
+float16x4_t test_vreinterpret_f16_s8(int8x8_t a) {
+ return vreinterpret_f16_s8(a);
+}
+
+// CHECK: test_vreinterpret_f16_s16
+float16x4_t test_vreinterpret_f16_s16(int16x4_t a) {
+ return vreinterpret_f16_s16(a);
+}
+
+// CHECK: test_vreinterpret_f16_s32
+float16x4_t test_vreinterpret_f16_s32(int32x2_t a) {
+ return vreinterpret_f16_s32(a);
+}
+
+// CHECK: test_vreinterpret_f16_s64
+float16x4_t test_vreinterpret_f16_s64(int64x1_t a) {
+ return vreinterpret_f16_s64(a);
+}
+
+// CHECK: test_vreinterpret_f16_u8
+float16x4_t test_vreinterpret_f16_u8(uint8x8_t a) {
+ return vreinterpret_f16_u8(a);
+}
+
+// CHECK: test_vreinterpret_f16_u16
+float16x4_t test_vreinterpret_f16_u16(uint16x4_t a) {
+ return vreinterpret_f16_u16(a);
+}
+
+// CHECK: test_vreinterpret_f16_u32
+float16x4_t test_vreinterpret_f16_u32(uint32x2_t a) {
+ return vreinterpret_f16_u32(a);
+}
+
+// CHECK: test_vreinterpret_f16_u64
+float16x4_t test_vreinterpret_f16_u64(uint64x1_t a) {
+ return vreinterpret_f16_u64(a);
+}
+
+// CHECK: test_vreinterpret_f16_f32
+float16x4_t test_vreinterpret_f16_f32(float32x2_t a) {
+ return vreinterpret_f16_f32(a);
+}
+
+// CHECK: test_vreinterpret_f16_p8
+float16x4_t test_vreinterpret_f16_p8(poly8x8_t a) {
+ return vreinterpret_f16_p8(a);
+}
+
+// CHECK: test_vreinterpret_f16_p16
+float16x4_t test_vreinterpret_f16_p16(poly16x4_t a) {
+ return vreinterpret_f16_p16(a);
+}
+
+// CHECK: test_vreinterpret_f32_s8
+float32x2_t test_vreinterpret_f32_s8(int8x8_t a) {
+ return vreinterpret_f32_s8(a);
+}
+
+// CHECK: test_vreinterpret_f32_s16
+float32x2_t test_vreinterpret_f32_s16(int16x4_t a) {
+ return vreinterpret_f32_s16(a);
+}
+
+// CHECK: test_vreinterpret_f32_s32
+float32x2_t test_vreinterpret_f32_s32(int32x2_t a) {
+ return vreinterpret_f32_s32(a);
+}
+
+// CHECK: test_vreinterpret_f32_s64
+float32x2_t test_vreinterpret_f32_s64(int64x1_t a) {
+ return vreinterpret_f32_s64(a);
+}
+
+// CHECK: test_vreinterpret_f32_u8
+float32x2_t test_vreinterpret_f32_u8(uint8x8_t a) {
+ return vreinterpret_f32_u8(a);
+}
+
+// CHECK: test_vreinterpret_f32_u16
+float32x2_t test_vreinterpret_f32_u16(uint16x4_t a) {
+ return vreinterpret_f32_u16(a);
+}
+
+// CHECK: test_vreinterpret_f32_u32
+float32x2_t test_vreinterpret_f32_u32(uint32x2_t a) {
+ return vreinterpret_f32_u32(a);
+}
+
+// CHECK: test_vreinterpret_f32_u64
+float32x2_t test_vreinterpret_f32_u64(uint64x1_t a) {
+ return vreinterpret_f32_u64(a);
+}
+
+// CHECK: test_vreinterpret_f32_f16
+float32x2_t test_vreinterpret_f32_f16(float16x4_t a) {
+ return vreinterpret_f32_f16(a);
+}
+
+// CHECK: test_vreinterpret_f32_p8
+float32x2_t test_vreinterpret_f32_p8(poly8x8_t a) {
+ return vreinterpret_f32_p8(a);
+}
+
+// CHECK: test_vreinterpret_f32_p16
+float32x2_t test_vreinterpret_f32_p16(poly16x4_t a) {
+ return vreinterpret_f32_p16(a);
+}
+
+// CHECK: test_vreinterpret_p8_s8
+poly8x8_t test_vreinterpret_p8_s8(int8x8_t a) {
+ return vreinterpret_p8_s8(a);
+}
+
+// CHECK: test_vreinterpret_p8_s16
+poly8x8_t test_vreinterpret_p8_s16(int16x4_t a) {
+ return vreinterpret_p8_s16(a);
+}
+
+// CHECK: test_vreinterpret_p8_s32
+poly8x8_t test_vreinterpret_p8_s32(int32x2_t a) {
+ return vreinterpret_p8_s32(a);
+}
+
+// CHECK: test_vreinterpret_p8_s64
+poly8x8_t test_vreinterpret_p8_s64(int64x1_t a) {
+ return vreinterpret_p8_s64(a);
+}
+
+// CHECK: test_vreinterpret_p8_u8
+poly8x8_t test_vreinterpret_p8_u8(uint8x8_t a) {
+ return vreinterpret_p8_u8(a);
+}
+
+// CHECK: test_vreinterpret_p8_u16
+poly8x8_t test_vreinterpret_p8_u16(uint16x4_t a) {
+ return vreinterpret_p8_u16(a);
+}
+
+// CHECK: test_vreinterpret_p8_u32
+poly8x8_t test_vreinterpret_p8_u32(uint32x2_t a) {
+ return vreinterpret_p8_u32(a);
+}
+
+// CHECK: test_vreinterpret_p8_u64
+poly8x8_t test_vreinterpret_p8_u64(uint64x1_t a) {
+ return vreinterpret_p8_u64(a);
+}
+
+// CHECK: test_vreinterpret_p8_f16
+poly8x8_t test_vreinterpret_p8_f16(float16x4_t a) {
+ return vreinterpret_p8_f16(a);
+}
+
+// CHECK: test_vreinterpret_p8_f32
+poly8x8_t test_vreinterpret_p8_f32(float32x2_t a) {
+ return vreinterpret_p8_f32(a);
+}
+
+// CHECK: test_vreinterpret_p8_p16
+poly8x8_t test_vreinterpret_p8_p16(poly16x4_t a) {
+ return vreinterpret_p8_p16(a);
+}
+
+// CHECK: test_vreinterpret_p16_s8
+poly16x4_t test_vreinterpret_p16_s8(int8x8_t a) {
+ return vreinterpret_p16_s8(a);
+}
+
+// CHECK: test_vreinterpret_p16_s16
+poly16x4_t test_vreinterpret_p16_s16(int16x4_t a) {
+ return vreinterpret_p16_s16(a);
+}
+
+// CHECK: test_vreinterpret_p16_s32
+poly16x4_t test_vreinterpret_p16_s32(int32x2_t a) {
+ return vreinterpret_p16_s32(a);
+}
+
+// CHECK: test_vreinterpret_p16_s64
+poly16x4_t test_vreinterpret_p16_s64(int64x1_t a) {
+ return vreinterpret_p16_s64(a);
+}
+
+// CHECK: test_vreinterpret_p16_u8
+poly16x4_t test_vreinterpret_p16_u8(uint8x8_t a) {
+ return vreinterpret_p16_u8(a);
+}
+
+// CHECK: test_vreinterpret_p16_u16
+poly16x4_t test_vreinterpret_p16_u16(uint16x4_t a) {
+ return vreinterpret_p16_u16(a);
+}
+
+// CHECK: test_vreinterpret_p16_u32
+poly16x4_t test_vreinterpret_p16_u32(uint32x2_t a) {
+ return vreinterpret_p16_u32(a);
+}
+
+// CHECK: test_vreinterpret_p16_u64
+poly16x4_t test_vreinterpret_p16_u64(uint64x1_t a) {
+ return vreinterpret_p16_u64(a);
+}
+
+// CHECK: test_vreinterpret_p16_f16
+poly16x4_t test_vreinterpret_p16_f16(float16x4_t a) {
+ return vreinterpret_p16_f16(a);
+}
+
+// CHECK: test_vreinterpret_p16_f32
+poly16x4_t test_vreinterpret_p16_f32(float32x2_t a) {
+ return vreinterpret_p16_f32(a);
+}
+
+// CHECK: test_vreinterpret_p16_p8
+poly16x4_t test_vreinterpret_p16_p8(poly8x8_t a) {
+ return vreinterpret_p16_p8(a);
+}
+
+// CHECK: test_vreinterpretq_s8_s16
+int8x16_t test_vreinterpretq_s8_s16(int16x8_t a) {
+ return vreinterpretq_s8_s16(a);
+}
+
+// CHECK: test_vreinterpretq_s8_s32
+int8x16_t test_vreinterpretq_s8_s32(int32x4_t a) {
+ return vreinterpretq_s8_s32(a);
+}
+
+// CHECK: test_vreinterpretq_s8_s64
+int8x16_t test_vreinterpretq_s8_s64(int64x2_t a) {
+ return vreinterpretq_s8_s64(a);
+}
+
+// CHECK: test_vreinterpretq_s8_u8
+int8x16_t test_vreinterpretq_s8_u8(uint8x16_t a) {
+ return vreinterpretq_s8_u8(a);
+}
+
+// CHECK: test_vreinterpretq_s8_u16
+int8x16_t test_vreinterpretq_s8_u16(uint16x8_t a) {
+ return vreinterpretq_s8_u16(a);
+}
+
+// CHECK: test_vreinterpretq_s8_u32
+int8x16_t test_vreinterpretq_s8_u32(uint32x4_t a) {
+ return vreinterpretq_s8_u32(a);
+}
+
+// CHECK: test_vreinterpretq_s8_u64
+int8x16_t test_vreinterpretq_s8_u64(uint64x2_t a) {
+ return vreinterpretq_s8_u64(a);
+}
+
+// CHECK: test_vreinterpretq_s8_f16
+int8x16_t test_vreinterpretq_s8_f16(float16x8_t a) {
+ return vreinterpretq_s8_f16(a);
+}
+
+// CHECK: test_vreinterpretq_s8_f32
+int8x16_t test_vreinterpretq_s8_f32(float32x4_t a) {
+ return vreinterpretq_s8_f32(a);
+}
+
+// CHECK: test_vreinterpretq_s8_p8
+int8x16_t test_vreinterpretq_s8_p8(poly8x16_t a) {
+ return vreinterpretq_s8_p8(a);
+}
+
+// CHECK: test_vreinterpretq_s8_p16
+int8x16_t test_vreinterpretq_s8_p16(poly16x8_t a) {
+ return vreinterpretq_s8_p16(a);
+}
+
+// CHECK: test_vreinterpretq_s16_s8
+int16x8_t test_vreinterpretq_s16_s8(int8x16_t a) {
+ return vreinterpretq_s16_s8(a);
+}
+
+// CHECK: test_vreinterpretq_s16_s32
+int16x8_t test_vreinterpretq_s16_s32(int32x4_t a) {
+ return vreinterpretq_s16_s32(a);
+}
+
+// CHECK: test_vreinterpretq_s16_s64
+int16x8_t test_vreinterpretq_s16_s64(int64x2_t a) {
+ return vreinterpretq_s16_s64(a);
+}
+
+// CHECK: test_vreinterpretq_s16_u8
+int16x8_t test_vreinterpretq_s16_u8(uint8x16_t a) {
+ return vreinterpretq_s16_u8(a);
+}
+
+// CHECK: test_vreinterpretq_s16_u16
+int16x8_t test_vreinterpretq_s16_u16(uint16x8_t a) {
+ return vreinterpretq_s16_u16(a);
+}
+
+// CHECK: test_vreinterpretq_s16_u32
+int16x8_t test_vreinterpretq_s16_u32(uint32x4_t a) {
+ return vreinterpretq_s16_u32(a);
+}
+
+// CHECK: test_vreinterpretq_s16_u64
+int16x8_t test_vreinterpretq_s16_u64(uint64x2_t a) {
+ return vreinterpretq_s16_u64(a);
+}
+
+// CHECK: test_vreinterpretq_s16_f16
+int16x8_t test_vreinterpretq_s16_f16(float16x8_t a) {
+ return vreinterpretq_s16_f16(a);
+}
+
+// CHECK: test_vreinterpretq_s16_f32
+int16x8_t test_vreinterpretq_s16_f32(float32x4_t a) {
+ return vreinterpretq_s16_f32(a);
+}
+
+// CHECK: test_vreinterpretq_s16_p8
+int16x8_t test_vreinterpretq_s16_p8(poly8x16_t a) {
+ return vreinterpretq_s16_p8(a);
+}
+
+// CHECK: test_vreinterpretq_s16_p16
+int16x8_t test_vreinterpretq_s16_p16(poly16x8_t a) {
+ return vreinterpretq_s16_p16(a);
+}
+
+// CHECK: test_vreinterpretq_s32_s8
+int32x4_t test_vreinterpretq_s32_s8(int8x16_t a) {
+ return vreinterpretq_s32_s8(a);
+}
+
+// CHECK: test_vreinterpretq_s32_s16
+int32x4_t test_vreinterpretq_s32_s16(int16x8_t a) {
+ return vreinterpretq_s32_s16(a);
+}
+
+// CHECK: test_vreinterpretq_s32_s64
+int32x4_t test_vreinterpretq_s32_s64(int64x2_t a) {
+ return vreinterpretq_s32_s64(a);
+}
+
+// CHECK: test_vreinterpretq_s32_u8
+int32x4_t test_vreinterpretq_s32_u8(uint8x16_t a) {
+ return vreinterpretq_s32_u8(a);
+}
+
+// CHECK: test_vreinterpretq_s32_u16
+int32x4_t test_vreinterpretq_s32_u16(uint16x8_t a) {
+ return vreinterpretq_s32_u16(a);
+}
+
+// CHECK: test_vreinterpretq_s32_u32
+int32x4_t test_vreinterpretq_s32_u32(uint32x4_t a) {
+ return vreinterpretq_s32_u32(a);
+}
+
+// CHECK: test_vreinterpretq_s32_u64
+int32x4_t test_vreinterpretq_s32_u64(uint64x2_t a) {
+ return vreinterpretq_s32_u64(a);
+}
+
+// CHECK: test_vreinterpretq_s32_f16
+int32x4_t test_vreinterpretq_s32_f16(float16x8_t a) {
+ return vreinterpretq_s32_f16(a);
+}
+
+// CHECK: test_vreinterpretq_s32_f32
+int32x4_t test_vreinterpretq_s32_f32(float32x4_t a) {
+ return vreinterpretq_s32_f32(a);
+}
+
+// CHECK: test_vreinterpretq_s32_p8
+int32x4_t test_vreinterpretq_s32_p8(poly8x16_t a) {
+ return vreinterpretq_s32_p8(a);
+}
+
+// CHECK: test_vreinterpretq_s32_p16
+int32x4_t test_vreinterpretq_s32_p16(poly16x8_t a) {
+ return vreinterpretq_s32_p16(a);
+}
+
+// CHECK: test_vreinterpretq_s64_s8
+int64x2_t test_vreinterpretq_s64_s8(int8x16_t a) {
+ return vreinterpretq_s64_s8(a);
+}
+
+// CHECK: test_vreinterpretq_s64_s16
+int64x2_t test_vreinterpretq_s64_s16(int16x8_t a) {
+ return vreinterpretq_s64_s16(a);
+}
+
+// CHECK: test_vreinterpretq_s64_s32
+int64x2_t test_vreinterpretq_s64_s32(int32x4_t a) {
+ return vreinterpretq_s64_s32(a);
+}
+
+// CHECK: test_vreinterpretq_s64_u8
+int64x2_t test_vreinterpretq_s64_u8(uint8x16_t a) {
+ return vreinterpretq_s64_u8(a);
+}
+
+// CHECK: test_vreinterpretq_s64_u16
+int64x2_t test_vreinterpretq_s64_u16(uint16x8_t a) {
+ return vreinterpretq_s64_u16(a);
+}
+
+// CHECK: test_vreinterpretq_s64_u32
+int64x2_t test_vreinterpretq_s64_u32(uint32x4_t a) {
+ return vreinterpretq_s64_u32(a);
+}
+
+// CHECK: test_vreinterpretq_s64_u64
+int64x2_t test_vreinterpretq_s64_u64(uint64x2_t a) {
+ return vreinterpretq_s64_u64(a);
+}
+
+// CHECK: test_vreinterpretq_s64_f16
+int64x2_t test_vreinterpretq_s64_f16(float16x8_t a) {
+ return vreinterpretq_s64_f16(a);
+}
+
+// CHECK: test_vreinterpretq_s64_f32
+int64x2_t test_vreinterpretq_s64_f32(float32x4_t a) {
+ return vreinterpretq_s64_f32(a);
+}
+
+// CHECK: test_vreinterpretq_s64_p8
+int64x2_t test_vreinterpretq_s64_p8(poly8x16_t a) {
+ return vreinterpretq_s64_p8(a);
+}
+
+// CHECK: test_vreinterpretq_s64_p16
+int64x2_t test_vreinterpretq_s64_p16(poly16x8_t a) {
+ return vreinterpretq_s64_p16(a);
+}
+
+// CHECK: test_vreinterpretq_u8_s8
+uint8x16_t test_vreinterpretq_u8_s8(int8x16_t a) {
+ return vreinterpretq_u8_s8(a);
+}
+
+// CHECK: test_vreinterpretq_u8_s16
+uint8x16_t test_vreinterpretq_u8_s16(int16x8_t a) {
+ return vreinterpretq_u8_s16(a);
+}
+
+// CHECK: test_vreinterpretq_u8_s32
+uint8x16_t test_vreinterpretq_u8_s32(int32x4_t a) {
+ return vreinterpretq_u8_s32(a);
+}
+
+// CHECK: test_vreinterpretq_u8_s64
+uint8x16_t test_vreinterpretq_u8_s64(int64x2_t a) {
+ return vreinterpretq_u8_s64(a);
+}
+
+// CHECK: test_vreinterpretq_u8_u16
+uint8x16_t test_vreinterpretq_u8_u16(uint16x8_t a) {
+ return vreinterpretq_u8_u16(a);
+}
+
+// CHECK: test_vreinterpretq_u8_u32
+uint8x16_t test_vreinterpretq_u8_u32(uint32x4_t a) {
+ return vreinterpretq_u8_u32(a);
+}
+
+// CHECK: test_vreinterpretq_u8_u64
+uint8x16_t test_vreinterpretq_u8_u64(uint64x2_t a) {
+ return vreinterpretq_u8_u64(a);
+}
+
+// CHECK: test_vreinterpretq_u8_f16
+uint8x16_t test_vreinterpretq_u8_f16(float16x8_t a) {
+ return vreinterpretq_u8_f16(a);
+}
+
+// CHECK: test_vreinterpretq_u8_f32
+uint8x16_t test_vreinterpretq_u8_f32(float32x4_t a) {
+ return vreinterpretq_u8_f32(a);
+}
+
+// CHECK: test_vreinterpretq_u8_p8
+uint8x16_t test_vreinterpretq_u8_p8(poly8x16_t a) {
+ return vreinterpretq_u8_p8(a);
+}
+
+// CHECK: test_vreinterpretq_u8_p16
+uint8x16_t test_vreinterpretq_u8_p16(poly16x8_t a) {
+ return vreinterpretq_u8_p16(a);
+}
+
+// CHECK: test_vreinterpretq_u16_s8
+uint16x8_t test_vreinterpretq_u16_s8(int8x16_t a) {
+ return vreinterpretq_u16_s8(a);
+}
+
+// CHECK: test_vreinterpretq_u16_s16
+uint16x8_t test_vreinterpretq_u16_s16(int16x8_t a) {
+ return vreinterpretq_u16_s16(a);
+}
+
+// CHECK: test_vreinterpretq_u16_s32
+uint16x8_t test_vreinterpretq_u16_s32(int32x4_t a) {
+ return vreinterpretq_u16_s32(a);
+}
+
+// CHECK: test_vreinterpretq_u16_s64
+uint16x8_t test_vreinterpretq_u16_s64(int64x2_t a) {
+ return vreinterpretq_u16_s64(a);
+}
+
+// CHECK: test_vreinterpretq_u16_u8
+uint16x8_t test_vreinterpretq_u16_u8(uint8x16_t a) {
+ return vreinterpretq_u16_u8(a);
+}
+
+// CHECK: test_vreinterpretq_u16_u32
+uint16x8_t test_vreinterpretq_u16_u32(uint32x4_t a) {
+ return vreinterpretq_u16_u32(a);
+}
+
+// CHECK: test_vreinterpretq_u16_u64
+uint16x8_t test_vreinterpretq_u16_u64(uint64x2_t a) {
+ return vreinterpretq_u16_u64(a);
+}
+
+// CHECK: test_vreinterpretq_u16_f16
+uint16x8_t test_vreinterpretq_u16_f16(float16x8_t a) {
+ return vreinterpretq_u16_f16(a);
+}
+
+// CHECK: test_vreinterpretq_u16_f32
+uint16x8_t test_vreinterpretq_u16_f32(float32x4_t a) {
+ return vreinterpretq_u16_f32(a);
+}
+
+// CHECK: test_vreinterpretq_u16_p8
+uint16x8_t test_vreinterpretq_u16_p8(poly8x16_t a) {
+ return vreinterpretq_u16_p8(a);
+}
+
+// CHECK: test_vreinterpretq_u16_p16
+uint16x8_t test_vreinterpretq_u16_p16(poly16x8_t a) {
+ return vreinterpretq_u16_p16(a);
+}
+
+// CHECK: test_vreinterpretq_u32_s8
+uint32x4_t test_vreinterpretq_u32_s8(int8x16_t a) {
+ return vreinterpretq_u32_s8(a);
+}
+
+// CHECK: test_vreinterpretq_u32_s16
+uint32x4_t test_vreinterpretq_u32_s16(int16x8_t a) {
+ return vreinterpretq_u32_s16(a);
+}
+
+// CHECK: test_vreinterpretq_u32_s32
+uint32x4_t test_vreinterpretq_u32_s32(int32x4_t a) {
+ return vreinterpretq_u32_s32(a);
+}
+
+// CHECK: test_vreinterpretq_u32_s64
+uint32x4_t test_vreinterpretq_u32_s64(int64x2_t a) {
+ return vreinterpretq_u32_s64(a);
+}
+
+// CHECK: test_vreinterpretq_u32_u8
+uint32x4_t test_vreinterpretq_u32_u8(uint8x16_t a) {
+ return vreinterpretq_u32_u8(a);
+}
+
+// CHECK: test_vreinterpretq_u32_u16
+uint32x4_t test_vreinterpretq_u32_u16(uint16x8_t a) {
+ return vreinterpretq_u32_u16(a);
+}
+
+// CHECK: test_vreinterpretq_u32_u64
+uint32x4_t test_vreinterpretq_u32_u64(uint64x2_t a) {
+ return vreinterpretq_u32_u64(a);
+}
+
+// CHECK: test_vreinterpretq_u32_f16
+uint32x4_t test_vreinterpretq_u32_f16(float16x8_t a) {
+ return vreinterpretq_u32_f16(a);
+}
+
+// CHECK: test_vreinterpretq_u32_f32
+uint32x4_t test_vreinterpretq_u32_f32(float32x4_t a) {
+ return vreinterpretq_u32_f32(a);
+}
+
+// CHECK: test_vreinterpretq_u32_p8
+uint32x4_t test_vreinterpretq_u32_p8(poly8x16_t a) {
+ return vreinterpretq_u32_p8(a);
+}
+
+// CHECK: test_vreinterpretq_u32_p16
+uint32x4_t test_vreinterpretq_u32_p16(poly16x8_t a) {
+ return vreinterpretq_u32_p16(a);
+}
+
+// CHECK: test_vreinterpretq_u64_s8
+uint64x2_t test_vreinterpretq_u64_s8(int8x16_t a) {
+ return vreinterpretq_u64_s8(a);
+}
+
+// CHECK: test_vreinterpretq_u64_s16
+uint64x2_t test_vreinterpretq_u64_s16(int16x8_t a) {
+ return vreinterpretq_u64_s16(a);
+}
+
+// CHECK: test_vreinterpretq_u64_s32
+uint64x2_t test_vreinterpretq_u64_s32(int32x4_t a) {
+ return vreinterpretq_u64_s32(a);
+}
+
+// CHECK: test_vreinterpretq_u64_s64
+uint64x2_t test_vreinterpretq_u64_s64(int64x2_t a) {
+ return vreinterpretq_u64_s64(a);
+}
+
+// CHECK: test_vreinterpretq_u64_u8
+uint64x2_t test_vreinterpretq_u64_u8(uint8x16_t a) {
+ return vreinterpretq_u64_u8(a);
+}
+
+// CHECK: test_vreinterpretq_u64_u16
+uint64x2_t test_vreinterpretq_u64_u16(uint16x8_t a) {
+ return vreinterpretq_u64_u16(a);
+}
+
+// CHECK: test_vreinterpretq_u64_u32
+uint64x2_t test_vreinterpretq_u64_u32(uint32x4_t a) {
+ return vreinterpretq_u64_u32(a);
+}
+
+// CHECK: test_vreinterpretq_u64_f16
+uint64x2_t test_vreinterpretq_u64_f16(float16x8_t a) {
+ return vreinterpretq_u64_f16(a);
+}
+
+// CHECK: test_vreinterpretq_u64_f32
+uint64x2_t test_vreinterpretq_u64_f32(float32x4_t a) {
+ return vreinterpretq_u64_f32(a);
+}
+
+// CHECK: test_vreinterpretq_u64_p8
+uint64x2_t test_vreinterpretq_u64_p8(poly8x16_t a) {
+ return vreinterpretq_u64_p8(a);
+}
+
+// CHECK: test_vreinterpretq_u64_p16
+uint64x2_t test_vreinterpretq_u64_p16(poly16x8_t a) {
+ return vreinterpretq_u64_p16(a);
+}
+
+// CHECK: test_vreinterpretq_f16_s8
+float16x8_t test_vreinterpretq_f16_s8(int8x16_t a) {
+ return vreinterpretq_f16_s8(a);
+}
+
+// CHECK: test_vreinterpretq_f16_s16
+float16x8_t test_vreinterpretq_f16_s16(int16x8_t a) {
+ return vreinterpretq_f16_s16(a);
+}
+
+// CHECK: test_vreinterpretq_f16_s32
+float16x8_t test_vreinterpretq_f16_s32(int32x4_t a) {
+ return vreinterpretq_f16_s32(a);
+}
+
+// CHECK: test_vreinterpretq_f16_s64
+float16x8_t test_vreinterpretq_f16_s64(int64x2_t a) {
+ return vreinterpretq_f16_s64(a);
+}
+
+// CHECK: test_vreinterpretq_f16_u8
+float16x8_t test_vreinterpretq_f16_u8(uint8x16_t a) {
+ return vreinterpretq_f16_u8(a);
+}
+
+// CHECK: test_vreinterpretq_f16_u16
+float16x8_t test_vreinterpretq_f16_u16(uint16x8_t a) {
+ return vreinterpretq_f16_u16(a);
+}
+
+// CHECK: test_vreinterpretq_f16_u32
+float16x8_t test_vreinterpretq_f16_u32(uint32x4_t a) {
+ return vreinterpretq_f16_u32(a);
+}
+
+// CHECK: test_vreinterpretq_f16_u64
+float16x8_t test_vreinterpretq_f16_u64(uint64x2_t a) {
+ return vreinterpretq_f16_u64(a);
+}
+
+// CHECK: test_vreinterpretq_f16_f32
+float16x8_t test_vreinterpretq_f16_f32(float32x4_t a) {
+ return vreinterpretq_f16_f32(a);
+}
+
+// CHECK: test_vreinterpretq_f16_p8
+float16x8_t test_vreinterpretq_f16_p8(poly8x16_t a) {
+ return vreinterpretq_f16_p8(a);
+}
+
+// CHECK: test_vreinterpretq_f16_p16
+float16x8_t test_vreinterpretq_f16_p16(poly16x8_t a) {
+ return vreinterpretq_f16_p16(a);
+}
+
+// CHECK: test_vreinterpretq_f32_s8
+float32x4_t test_vreinterpretq_f32_s8(int8x16_t a) {
+ return vreinterpretq_f32_s8(a);
+}
+
+// CHECK: test_vreinterpretq_f32_s16
+float32x4_t test_vreinterpretq_f32_s16(int16x8_t a) {
+ return vreinterpretq_f32_s16(a);
+}
+
+// CHECK: test_vreinterpretq_f32_s32
+float32x4_t test_vreinterpretq_f32_s32(int32x4_t a) {
+ return vreinterpretq_f32_s32(a);
+}
+
+// CHECK: test_vreinterpretq_f32_s64
+float32x4_t test_vreinterpretq_f32_s64(int64x2_t a) {
+ return vreinterpretq_f32_s64(a);
+}
+
+// CHECK: test_vreinterpretq_f32_u8
+float32x4_t test_vreinterpretq_f32_u8(uint8x16_t a) {
+ return vreinterpretq_f32_u8(a);
+}
+
+// CHECK: test_vreinterpretq_f32_u16
+float32x4_t test_vreinterpretq_f32_u16(uint16x8_t a) {
+ return vreinterpretq_f32_u16(a);
+}
+
+// CHECK: test_vreinterpretq_f32_u32
+float32x4_t test_vreinterpretq_f32_u32(uint32x4_t a) {
+ return vreinterpretq_f32_u32(a);
+}
+
+// CHECK: test_vreinterpretq_f32_u64
+float32x4_t test_vreinterpretq_f32_u64(uint64x2_t a) {
+ return vreinterpretq_f32_u64(a);
+}
+
+// CHECK: test_vreinterpretq_f32_f16
+float32x4_t test_vreinterpretq_f32_f16(float16x8_t a) {
+ return vreinterpretq_f32_f16(a);
+}
+
+// CHECK: test_vreinterpretq_f32_p8
+float32x4_t test_vreinterpretq_f32_p8(poly8x16_t a) {
+ return vreinterpretq_f32_p8(a);
+}
+
+// CHECK: test_vreinterpretq_f32_p16
+float32x4_t test_vreinterpretq_f32_p16(poly16x8_t a) {
+ return vreinterpretq_f32_p16(a);
+}
+
+// CHECK: test_vreinterpretq_p8_s8
+poly8x16_t test_vreinterpretq_p8_s8(int8x16_t a) {
+ return vreinterpretq_p8_s8(a);
+}
+
+// CHECK: test_vreinterpretq_p8_s16
+poly8x16_t test_vreinterpretq_p8_s16(int16x8_t a) {
+ return vreinterpretq_p8_s16(a);
+}
+
+// CHECK: test_vreinterpretq_p8_s32
+poly8x16_t test_vreinterpretq_p8_s32(int32x4_t a) {
+ return vreinterpretq_p8_s32(a);
+}
+
+// CHECK: test_vreinterpretq_p8_s64
+poly8x16_t test_vreinterpretq_p8_s64(int64x2_t a) {
+ return vreinterpretq_p8_s64(a);
+}
+
+// CHECK: test_vreinterpretq_p8_u8
+poly8x16_t test_vreinterpretq_p8_u8(uint8x16_t a) {
+ return vreinterpretq_p8_u8(a);
+}
+
+// CHECK: test_vreinterpretq_p8_u16
+poly8x16_t test_vreinterpretq_p8_u16(uint16x8_t a) {
+ return vreinterpretq_p8_u16(a);
+}
+
+// CHECK: test_vreinterpretq_p8_u32
+poly8x16_t test_vreinterpretq_p8_u32(uint32x4_t a) {
+ return vreinterpretq_p8_u32(a);
+}
+
+// CHECK: test_vreinterpretq_p8_u64
+poly8x16_t test_vreinterpretq_p8_u64(uint64x2_t a) {
+ return vreinterpretq_p8_u64(a);
+}
+
+// CHECK: test_vreinterpretq_p8_f16
+poly8x16_t test_vreinterpretq_p8_f16(float16x8_t a) {
+ return vreinterpretq_p8_f16(a);
+}
+
+// CHECK: test_vreinterpretq_p8_f32
+poly8x16_t test_vreinterpretq_p8_f32(float32x4_t a) {
+ return vreinterpretq_p8_f32(a);
+}
+
+// CHECK: test_vreinterpretq_p8_p16
+poly8x16_t test_vreinterpretq_p8_p16(poly16x8_t a) {
+ return vreinterpretq_p8_p16(a);
+}
+
+// CHECK: test_vreinterpretq_p16_s8
+poly16x8_t test_vreinterpretq_p16_s8(int8x16_t a) {
+ return vreinterpretq_p16_s8(a);
+}
+
+// CHECK: test_vreinterpretq_p16_s16
+poly16x8_t test_vreinterpretq_p16_s16(int16x8_t a) {
+ return vreinterpretq_p16_s16(a);
+}
+
+// CHECK: test_vreinterpretq_p16_s32
+poly16x8_t test_vreinterpretq_p16_s32(int32x4_t a) {
+ return vreinterpretq_p16_s32(a);
+}
+
+// CHECK: test_vreinterpretq_p16_s64
+poly16x8_t test_vreinterpretq_p16_s64(int64x2_t a) {
+ return vreinterpretq_p16_s64(a);
+}
+
+// CHECK: test_vreinterpretq_p16_u8
+poly16x8_t test_vreinterpretq_p16_u8(uint8x16_t a) {
+ return vreinterpretq_p16_u8(a);
+}
+
+// CHECK: test_vreinterpretq_p16_u16
+poly16x8_t test_vreinterpretq_p16_u16(uint16x8_t a) {
+ return vreinterpretq_p16_u16(a);
+}
+
+// CHECK: test_vreinterpretq_p16_u32
+poly16x8_t test_vreinterpretq_p16_u32(uint32x4_t a) {
+ return vreinterpretq_p16_u32(a);
+}
+
+// CHECK: test_vreinterpretq_p16_u64
+poly16x8_t test_vreinterpretq_p16_u64(uint64x2_t a) {
+ return vreinterpretq_p16_u64(a);
+}
+
+// CHECK: test_vreinterpretq_p16_f16
+poly16x8_t test_vreinterpretq_p16_f16(float16x8_t a) {
+ return vreinterpretq_p16_f16(a);
+}
+
+// CHECK: test_vreinterpretq_p16_f32
+poly16x8_t test_vreinterpretq_p16_f32(float32x4_t a) {
+ return vreinterpretq_p16_f32(a);
+}
+
+// CHECK: test_vreinterpretq_p16_p8
+poly16x8_t test_vreinterpretq_p16_p8(poly8x16_t a) {
+ return vreinterpretq_p16_p8(a);
+}
+
+
+// CHECK: test_vrev16_s8
+// CHECK: vrev16.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vrev16_s8(int8x8_t a) {
+ return vrev16_s8(a);
+}
+
+// CHECK: test_vrev16_u8
+// CHECK: vrev16.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vrev16_u8(uint8x8_t a) {
+ return vrev16_u8(a);
+}
+
+// CHECK: test_vrev16_p8
+// CHECK: vrev16.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vrev16_p8(poly8x8_t a) {
+ return vrev16_p8(a);
+}
+
+// CHECK: test_vrev16q_s8
+// CHECK: vrev16.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vrev16q_s8(int8x16_t a) {
+ return vrev16q_s8(a);
+}
+
+// CHECK: test_vrev16q_u8
+// CHECK: vrev16.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vrev16q_u8(uint8x16_t a) {
+ return vrev16q_u8(a);
+}
+
+// CHECK: test_vrev16q_p8
+// CHECK: vrev16.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vrev16q_p8(poly8x16_t a) {
+ return vrev16q_p8(a);
+}
+
+
+// CHECK: test_vrev32_s8
+// CHECK: vrev32.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vrev32_s8(int8x8_t a) {
+ return vrev32_s8(a);
+}
+
+// CHECK: test_vrev32_s16
+// CHECK: vrev32.16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vrev32_s16(int16x4_t a) {
+ return vrev32_s16(a);
+}
+
+// CHECK: test_vrev32_u8
+// CHECK: vrev32.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vrev32_u8(uint8x8_t a) {
+ return vrev32_u8(a);
+}
+
+// CHECK: test_vrev32_u16
+// CHECK: vrev32.16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vrev32_u16(uint16x4_t a) {
+ return vrev32_u16(a);
+}
+
+// CHECK: test_vrev32_p8
+// CHECK: vrev32.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vrev32_p8(poly8x8_t a) {
+ return vrev32_p8(a);
+}
+
+// CHECK: test_vrev32_p16
+// CHECK: vrev32.16 d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4_t test_vrev32_p16(poly16x4_t a) {
+ return vrev32_p16(a);
+}
+
+// CHECK: test_vrev32q_s8
+// CHECK: vrev32.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vrev32q_s8(int8x16_t a) {
+ return vrev32q_s8(a);
+}
+
+// CHECK: test_vrev32q_s16
+// CHECK: vrev32.16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vrev32q_s16(int16x8_t a) {
+ return vrev32q_s16(a);
+}
+
+// CHECK: test_vrev32q_u8
+// CHECK: vrev32.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vrev32q_u8(uint8x16_t a) {
+ return vrev32q_u8(a);
+}
+
+// CHECK: test_vrev32q_u16
+// CHECK: vrev32.16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vrev32q_u16(uint16x8_t a) {
+ return vrev32q_u16(a);
+}
+
+// CHECK: test_vrev32q_p8
+// CHECK: vrev32.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vrev32q_p8(poly8x16_t a) {
+ return vrev32q_p8(a);
+}
+
+// CHECK: test_vrev32q_p16
+// CHECK: vrev32.16 q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8_t test_vrev32q_p16(poly16x8_t a) {
+ return vrev32q_p16(a);
+}
+
+
+// CHECK: test_vrev64_s8
+// CHECK: vrev64.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vrev64_s8(int8x8_t a) {
+ return vrev64_s8(a);
+}
+
+// CHECK: test_vrev64_s16
+// CHECK: vrev64.16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vrev64_s16(int16x4_t a) {
+ return vrev64_s16(a);
+}
+
+// CHECK: test_vrev64_s32
+// CHECK: vrev64.32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vrev64_s32(int32x2_t a) {
+ return vrev64_s32(a);
+}
+
+// CHECK: test_vrev64_u8
+// CHECK: vrev64.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vrev64_u8(uint8x8_t a) {
+ return vrev64_u8(a);
+}
+
+// CHECK: test_vrev64_u16
+// CHECK: vrev64.16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vrev64_u16(uint16x4_t a) {
+ return vrev64_u16(a);
+}
+
+// CHECK: test_vrev64_u32
+// CHECK: vrev64.32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vrev64_u32(uint32x2_t a) {
+ return vrev64_u32(a);
+}
+
+// CHECK: test_vrev64_p8
+// CHECK: vrev64.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8_t test_vrev64_p8(poly8x8_t a) {
+ return vrev64_p8(a);
+}
+
+// CHECK: test_vrev64_p16
+// CHECK: vrev64.16 d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4_t test_vrev64_p16(poly16x4_t a) {
+ return vrev64_p16(a);
+}
+
+// CHECK: test_vrev64_f32
+// CHECK: vrev64.32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vrev64_f32(float32x2_t a) {
+ return vrev64_f32(a);
+}
+
+// CHECK: test_vrev64q_s8
+// CHECK: vrev64.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vrev64q_s8(int8x16_t a) {
+ return vrev64q_s8(a);
+}
+
+// CHECK: test_vrev64q_s16
+// CHECK: vrev64.16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vrev64q_s16(int16x8_t a) {
+ return vrev64q_s16(a);
+}
+
+// CHECK: test_vrev64q_s32
+// CHECK: vrev64.32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vrev64q_s32(int32x4_t a) {
+ return vrev64q_s32(a);
+}
+
+// CHECK: test_vrev64q_u8
+// CHECK: vrev64.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vrev64q_u8(uint8x16_t a) {
+ return vrev64q_u8(a);
+}
+
+// CHECK: test_vrev64q_u16
+// CHECK: vrev64.16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vrev64q_u16(uint16x8_t a) {
+ return vrev64q_u16(a);
+}
+
+// CHECK: test_vrev64q_u32
+// CHECK: vrev64.32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vrev64q_u32(uint32x4_t a) {
+ return vrev64q_u32(a);
+}
+
+// CHECK: test_vrev64q_p8
+// CHECK: vrev64.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16_t test_vrev64q_p8(poly8x16_t a) {
+ return vrev64q_p8(a);
+}
+
+// CHECK: test_vrev64q_p16
+// CHECK: vrev64.16 q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8_t test_vrev64q_p16(poly16x8_t a) {
+ return vrev64q_p16(a);
+}
+
+// CHECK: test_vrev64q_f32
+// CHECK: vrev64.32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vrev64q_f32(float32x4_t a) {
+ return vrev64q_f32(a);
+}
+
+
+// CHECK: test_vrhadd_s8
+// CHECK: vrhadd.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vrhadd_s8(int8x8_t a, int8x8_t b) {
+ return vrhadd_s8(a, b);
+}
+
+// CHECK: test_vrhadd_s16
+// CHECK: vrhadd.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vrhadd_s16(int16x4_t a, int16x4_t b) {
+ return vrhadd_s16(a, b);
+}
+
+// CHECK: test_vrhadd_s32
+// CHECK: vrhadd.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vrhadd_s32(int32x2_t a, int32x2_t b) {
+ return vrhadd_s32(a, b);
+}
+
+// CHECK: test_vrhadd_u8
+// CHECK: vrhadd.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vrhadd_u8(uint8x8_t a, uint8x8_t b) {
+ return vrhadd_u8(a, b);
+}
+
+// CHECK: test_vrhadd_u16
+// CHECK: vrhadd.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vrhadd_u16(uint16x4_t a, uint16x4_t b) {
+ return vrhadd_u16(a, b);
+}
+
+// CHECK: test_vrhadd_u32
+// CHECK: vrhadd.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vrhadd_u32(uint32x2_t a, uint32x2_t b) {
+ return vrhadd_u32(a, b);
+}
+
+// CHECK: test_vrhaddq_s8
+// CHECK: vrhadd.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vrhaddq_s8(int8x16_t a, int8x16_t b) {
+ return vrhaddq_s8(a, b);
+}
+
+// CHECK: test_vrhaddq_s16
+// CHECK: vrhadd.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vrhaddq_s16(int16x8_t a, int16x8_t b) {
+ return vrhaddq_s16(a, b);
+}
+
+// CHECK: test_vrhaddq_s32
+// CHECK: vrhadd.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vrhaddq_s32(int32x4_t a, int32x4_t b) {
+ return vrhaddq_s32(a, b);
+}
+
+// CHECK: test_vrhaddq_u8
+// CHECK: vrhadd.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vrhaddq_u8(uint8x16_t a, uint8x16_t b) {
+ return vrhaddq_u8(a, b);
+}
+
+// CHECK: test_vrhaddq_u16
+// CHECK: vrhadd.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vrhaddq_u16(uint16x8_t a, uint16x8_t b) {
+ return vrhaddq_u16(a, b);
+}
+
+// CHECK: test_vrhaddq_u32
+// CHECK: vrhadd.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vrhaddq_u32(uint32x4_t a, uint32x4_t b) {
+ return vrhaddq_u32(a, b);
+}
+
+
+// CHECK: test_vrshl_s8
+// CHECK: vrshl.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
+ return vrshl_s8(a, b);
+}
+
+// CHECK: test_vrshl_s16
+// CHECK: vrshl.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
+ return vrshl_s16(a, b);
+}
+
+// CHECK: test_vrshl_s32
+// CHECK: vrshl.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
+ return vrshl_s32(a, b);
+}
+
+// CHECK: test_vrshl_s64
+// CHECK: vrshl.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
+ return vrshl_s64(a, b);
+}
+
+// CHECK: test_vrshl_u8
+// CHECK: vrshl.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
+ return vrshl_u8(a, b);
+}
+
+// CHECK: test_vrshl_u16
+// CHECK: vrshl.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
+ return vrshl_u16(a, b);
+}
+
+// CHECK: test_vrshl_u32
+// CHECK: vrshl.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
+ return vrshl_u32(a, b);
+}
+
+// CHECK: test_vrshl_u64
+// CHECK: vrshl.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
+ return vrshl_u64(a, b);
+}
+
+// CHECK: test_vrshlq_s8
+// CHECK: vrshl.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
+ return vrshlq_s8(a, b);
+}
+
+// CHECK: test_vrshlq_s16
+// CHECK: vrshl.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
+ return vrshlq_s16(a, b);
+}
+
+// CHECK: test_vrshlq_s32
+// CHECK: vrshl.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
+ return vrshlq_s32(a, b);
+}
+
+// CHECK: test_vrshlq_s64
+// CHECK: vrshl.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
+ return vrshlq_s64(a, b);
+}
+
+// CHECK: test_vrshlq_u8
+// CHECK: vrshl.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
+ return vrshlq_u8(a, b);
+}
+
+// CHECK: test_vrshlq_u16
+// CHECK: vrshl.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
+ return vrshlq_u16(a, b);
+}
+
+// CHECK: test_vrshlq_u32
+// CHECK: vrshl.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
+ return vrshlq_u32(a, b);
+}
+
+// CHECK: test_vrshlq_u64
+// CHECK: vrshl.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) {
+ return vrshlq_u64(a, b);
+}
+
+
+// CHECK: test_vrshrn_n_s16
+// CHECK: vrshrn.i16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vrshrn_n_s16(int16x8_t a) {
+ return vrshrn_n_s16(a, 1);
+}
+
+// CHECK: test_vrshrn_n_s32
+// CHECK: vrshrn.i32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vrshrn_n_s32(int32x4_t a) {
+ return vrshrn_n_s32(a, 1);
+}
+
+// CHECK: test_vrshrn_n_s64
+// CHECK: vrshrn.i64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vrshrn_n_s64(int64x2_t a) {
+ return vrshrn_n_s64(a, 1);
+}
+
+// CHECK: test_vrshrn_n_u16
+// CHECK: vrshrn.i16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vrshrn_n_u16(uint16x8_t a) {
+ return vrshrn_n_u16(a, 1);
+}
+
+// CHECK: test_vrshrn_n_u32
+// CHECK: vrshrn.i32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vrshrn_n_u32(uint32x4_t a) {
+ return vrshrn_n_u32(a, 1);
+}
+
+// CHECK: test_vrshrn_n_u64
+// CHECK: vrshrn.i64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vrshrn_n_u64(uint64x2_t a) {
+ return vrshrn_n_u64(a, 1);
+}
+
+
+// CHECK: test_vrshr_n_s8
+// CHECK: vrshr.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vrshr_n_s8(int8x8_t a) {
+ return vrshr_n_s8(a, 1);
+}
+
+// CHECK: test_vrshr_n_s16
+// CHECK: vrshr.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vrshr_n_s16(int16x4_t a) {
+ return vrshr_n_s16(a, 1);
+}
+
+// CHECK: test_vrshr_n_s32
+// CHECK: vrshr.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vrshr_n_s32(int32x2_t a) {
+ return vrshr_n_s32(a, 1);
+}
+
+// CHECK: test_vrshr_n_s64
+// CHECK: vrshr.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vrshr_n_s64(int64x1_t a) {
+ return vrshr_n_s64(a, 1);
+}
+
+// CHECK: test_vrshr_n_u8
+// CHECK: vrshr.u8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vrshr_n_u8(uint8x8_t a) {
+ return vrshr_n_u8(a, 1);
+}
+
+// CHECK: test_vrshr_n_u16
+// CHECK: vrshr.u16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vrshr_n_u16(uint16x4_t a) {
+ return vrshr_n_u16(a, 1);
+}
+
+// CHECK: test_vrshr_n_u32
+// CHECK: vrshr.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vrshr_n_u32(uint32x2_t a) {
+ return vrshr_n_u32(a, 1);
+}
+
+// CHECK: test_vrshr_n_u64
+// CHECK: vrshr.u64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vrshr_n_u64(uint64x1_t a) {
+ return vrshr_n_u64(a, 1);
+}
+
+// CHECK: test_vrshrq_n_s8
+// CHECK: vrshr.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vrshrq_n_s8(int8x16_t a) {
+ return vrshrq_n_s8(a, 1);
+}
+
+// CHECK: test_vrshrq_n_s16
+// CHECK: vrshr.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vrshrq_n_s16(int16x8_t a) {
+ return vrshrq_n_s16(a, 1);
+}
+
+// CHECK: test_vrshrq_n_s32
+// CHECK: vrshr.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vrshrq_n_s32(int32x4_t a) {
+ return vrshrq_n_s32(a, 1);
+}
+
+// CHECK: test_vrshrq_n_s64
+// CHECK: vrshr.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vrshrq_n_s64(int64x2_t a) {
+ return vrshrq_n_s64(a, 1);
+}
+
+// CHECK: test_vrshrq_n_u8
+// CHECK: vrshr.u8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vrshrq_n_u8(uint8x16_t a) {
+ return vrshrq_n_u8(a, 1);
+}
+
+// CHECK: test_vrshrq_n_u16
+// CHECK: vrshr.u16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vrshrq_n_u16(uint16x8_t a) {
+ return vrshrq_n_u16(a, 1);
+}
+
+// CHECK: test_vrshrq_n_u32
+// CHECK: vrshr.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vrshrq_n_u32(uint32x4_t a) {
+ return vrshrq_n_u32(a, 1);
+}
+
+// CHECK: test_vrshrq_n_u64
+// CHECK: vrshr.u64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vrshrq_n_u64(uint64x2_t a) {
+ return vrshrq_n_u64(a, 1);
+}
+
+
+// CHECK: test_vrsqrte_f32
+// CHECK: vrsqrte.f32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vrsqrte_f32(float32x2_t a) {
+ return vrsqrte_f32(a);
+}
+
+// CHECK: test_vrsqrte_u32
+// CHECK: vrsqrte.u32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vrsqrte_u32(uint32x2_t a) {
+ return vrsqrte_u32(a);
+}
+
+// CHECK: test_vrsqrteq_f32
+// CHECK: vrsqrte.f32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vrsqrteq_f32(float32x4_t a) {
+ return vrsqrteq_f32(a);
+}
+
+// CHECK: test_vrsqrteq_u32
+// CHECK: vrsqrte.u32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vrsqrteq_u32(uint32x4_t a) {
+ return vrsqrteq_u32(a);
+}
+
+
+// CHECK: test_vrsqrts_f32
+// CHECK: vrsqrts.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vrsqrts_f32(float32x2_t a, float32x2_t b) {
+ return vrsqrts_f32(a, b);
+}
+
+// CHECK: test_vrsqrtsq_f32
+// CHECK: vrsqrts.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vrsqrtsq_f32(float32x4_t a, float32x4_t b) {
+ return vrsqrtsq_f32(a, b);
+}
+
+
+// CHECK: test_vrsra_n_s8
+// CHECK: vrsra.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vrsra_n_s8(int8x8_t a, int8x8_t b) {
+ return vrsra_n_s8(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_s16
+// CHECK: vrsra.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vrsra_n_s16(int16x4_t a, int16x4_t b) {
+ return vrsra_n_s16(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_s32
+// CHECK: vrsra.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vrsra_n_s32(int32x2_t a, int32x2_t b) {
+ return vrsra_n_s32(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_s64
+// CHECK: vrsra.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vrsra_n_s64(int64x1_t a, int64x1_t b) {
+ return vrsra_n_s64(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_u8
+// CHECK: vrsra.u8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vrsra_n_u8(uint8x8_t a, uint8x8_t b) {
+ return vrsra_n_u8(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_u16
+// CHECK: vrsra.u16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vrsra_n_u16(uint16x4_t a, uint16x4_t b) {
+ return vrsra_n_u16(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_u32
+// CHECK: vrsra.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vrsra_n_u32(uint32x2_t a, uint32x2_t b) {
+ return vrsra_n_u32(a, b, 1);
+}
+
+// CHECK: test_vrsra_n_u64
+// CHECK: vrsra.u64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vrsra_n_u64(uint64x1_t a, uint64x1_t b) {
+ return vrsra_n_u64(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_s8
+// CHECK: vrsra.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vrsraq_n_s8(int8x16_t a, int8x16_t b) {
+ return vrsraq_n_s8(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_s16
+// CHECK: vrsra.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vrsraq_n_s16(int16x8_t a, int16x8_t b) {
+ return vrsraq_n_s16(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_s32
+// CHECK: vrsra.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vrsraq_n_s32(int32x4_t a, int32x4_t b) {
+ return vrsraq_n_s32(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_s64
+// CHECK: vrsra.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vrsraq_n_s64(int64x2_t a, int64x2_t b) {
+ return vrsraq_n_s64(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_u8
+// CHECK: vrsra.u8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vrsraq_n_u8(uint8x16_t a, uint8x16_t b) {
+ return vrsraq_n_u8(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_u16
+// CHECK: vrsra.u16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vrsraq_n_u16(uint16x8_t a, uint16x8_t b) {
+ return vrsraq_n_u16(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_u32
+// CHECK: vrsra.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vrsraq_n_u32(uint32x4_t a, uint32x4_t b) {
+ return vrsraq_n_u32(a, b, 1);
+}
+
+// CHECK: test_vrsraq_n_u64
+// CHECK: vrsra.u64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vrsraq_n_u64(uint64x2_t a, uint64x2_t b) {
+ return vrsraq_n_u64(a, b, 1);
+}
+
+
+// CHECK: test_vrsubhn_s16
+// CHECK: vrsubhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
+ return vrsubhn_s16(a, b);
+}
+
+// CHECK: test_vrsubhn_s32
+// CHECK: vrsubhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
+ return vrsubhn_s32(a, b);
+}
+
+// CHECK: test_vrsubhn_s64
+// CHECK: vrsubhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
+ return vrsubhn_s64(a, b);
+}
+
+// CHECK: test_vrsubhn_u16
+// CHECK: vrsubhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
+ return vrsubhn_u16(a, b);
+}
+
+// CHECK: test_vrsubhn_u32
+// CHECK: vrsubhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
+ return vrsubhn_u32(a, b);
+}
+
+// CHECK: test_vrsubhn_u64
+// CHECK: vrsubhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
+ return vrsubhn_u64(a, b);
+}
+
+
+// CHECK: test_vset_lane_u8
+// CHECK: vmov
+uint8x8_t test_vset_lane_u8(uint8_t a, uint8x8_t b) {
+ return vset_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vset_lane_u16
+// CHECK: vmov
+uint16x4_t test_vset_lane_u16(uint16_t a, uint16x4_t b) {
+ return vset_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vset_lane_u32
+// CHECK: vmov
+uint32x2_t test_vset_lane_u32(uint32_t a, uint32x2_t b) {
+ return vset_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vset_lane_s8
+// CHECK: vmov
+int8x8_t test_vset_lane_s8(int8_t a, int8x8_t b) {
+ return vset_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vset_lane_s16
+// CHECK: vmov
+int16x4_t test_vset_lane_s16(int16_t a, int16x4_t b) {
+ return vset_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vset_lane_s32
+// CHECK: vmov
+int32x2_t test_vset_lane_s32(int32_t a, int32x2_t b) {
+ return vset_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vset_lane_p8
+// CHECK: vmov
+poly8x8_t test_vset_lane_p8(poly8_t a, poly8x8_t b) {
+ return vset_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vset_lane_p16
+// CHECK: vmov
+poly16x4_t test_vset_lane_p16(poly16_t a, poly16x4_t b) {
+ return vset_lane_p16(a, b, 3);
+}
+
+// CHECK: test_vset_lane_f32
+// CHECK: vmov
+float32x2_t test_vset_lane_f32(float32_t a, float32x2_t b) {
+ return vset_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vsetq_lane_u8
+// CHECK: vmov
+uint8x16_t test_vsetq_lane_u8(uint8_t a, uint8x16_t b) {
+ return vsetq_lane_u8(a, b, 15);
+}
+
+// CHECK: test_vsetq_lane_u16
+// CHECK: vmov
+uint16x8_t test_vsetq_lane_u16(uint16_t a, uint16x8_t b) {
+ return vsetq_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vsetq_lane_u32
+// CHECK: vmov
+uint32x4_t test_vsetq_lane_u32(uint32_t a, uint32x4_t b) {
+ return vsetq_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vsetq_lane_s8
+// CHECK: vmov
+int8x16_t test_vsetq_lane_s8(int8_t a, int8x16_t b) {
+ return vsetq_lane_s8(a, b, 15);
+}
+
+// CHECK: test_vsetq_lane_s16
+// CHECK: vmov
+int16x8_t test_vsetq_lane_s16(int16_t a, int16x8_t b) {
+ return vsetq_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vsetq_lane_s32
+// CHECK: vmov
+int32x4_t test_vsetq_lane_s32(int32_t a, int32x4_t b) {
+ return vsetq_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vsetq_lane_p8
+// CHECK: vmov
+poly8x16_t test_vsetq_lane_p8(poly8_t a, poly8x16_t b) {
+ return vsetq_lane_p8(a, b, 15);
+}
+
+// CHECK: test_vsetq_lane_p16
+// CHECK: vmov
+poly16x8_t test_vsetq_lane_p16(poly16_t a, poly16x8_t b) {
+ return vsetq_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vsetq_lane_f32
+// CHECK: vmov
+float32x4_t test_vsetq_lane_f32(float32_t a, float32x4_t b) {
+ return vsetq_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vset_lane_s64
+// CHECK: vmov
+int64x1_t test_vset_lane_s64(int64_t a, int64x1_t b) {
+ return vset_lane_s64(a, b, 0);
+}
+
+// CHECK: test_vset_lane_u64
+// CHECK: vmov
+uint64x1_t test_vset_lane_u64(uint64_t a, uint64x1_t b) {
+ return vset_lane_u64(a, b, 0);
+}
+
+// CHECK: test_vsetq_lane_s64
+// CHECK: vmov
+int64x2_t test_vsetq_lane_s64(int64_t a, int64x2_t b) {
+ return vsetq_lane_s64(a, b, 1);
+}
+
+// CHECK: test_vsetq_lane_u64
+// CHECK: vmov
+uint64x2_t test_vsetq_lane_u64(uint64_t a, uint64x2_t b) {
+ return vsetq_lane_u64(a, b, 1);
+}
+
+
+// CHECK: test_vshl_s8
+// CHECK: vshl.s8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
+ return vshl_s8(a, b);
+}
+
+// CHECK: test_vshl_s16
+// CHECK: vshl.s16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
+ return vshl_s16(a, b);
+}
+
+// CHECK: test_vshl_s32
+// CHECK: vshl.s32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
+ return vshl_s32(a, b);
+}
+
+// CHECK: test_vshl_s64
+// CHECK: vshl.s64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
+ return vshl_s64(a, b);
+}
+
+// CHECK: test_vshl_u8
+// CHECK: vshl.u8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
+ return vshl_u8(a, b);
+}
+
+// CHECK: test_vshl_u16
+// CHECK: vshl.u16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
+ return vshl_u16(a, b);
+}
+
+// CHECK: test_vshl_u32
+// CHECK: vshl.u32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
+ return vshl_u32(a, b);
+}
+
+// CHECK: test_vshl_u64
+// CHECK: vshl.u64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
+ return vshl_u64(a, b);
+}
+
+// CHECK: test_vshlq_s8
+// CHECK: vshl.s8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
+ return vshlq_s8(a, b);
+}
+
+// CHECK: test_vshlq_s16
+// CHECK: vshl.s16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
+ return vshlq_s16(a, b);
+}
+
+// CHECK: test_vshlq_s32
+// CHECK: vshl.s32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
+ return vshlq_s32(a, b);
+}
+
+// CHECK: test_vshlq_s64
+// CHECK: vshl.s64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
+ return vshlq_s64(a, b);
+}
+
+// CHECK: test_vshlq_u8
+// CHECK: vshl.u8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
+ return vshlq_u8(a, b);
+}
+
+// CHECK: test_vshlq_u16
+// CHECK: vshl.u16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
+ return vshlq_u16(a, b);
+}
+
+// CHECK: test_vshlq_u32
+// CHECK: vshl.u32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
+ return vshlq_u32(a, b);
+}
+
+// CHECK: test_vshlq_u64
+// CHECK: vshl.u64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vshlq_u64(uint64x2_t a, int64x2_t b) {
+ return vshlq_u64(a, b);
+}
+
+
+// CHECK: test_vshll_n_s8
+// CHECK: vshll.s8 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vshll_n_s8(int8x8_t a) {
+ return vshll_n_s8(a, 1);
+}
+
+// CHECK: test_vshll_n_s16
+// CHECK: vshll.s16 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vshll_n_s16(int16x4_t a) {
+ return vshll_n_s16(a, 1);
+}
+
+// CHECK: test_vshll_n_s32
+// CHECK: vshll.s32 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vshll_n_s32(int32x2_t a) {
+ return vshll_n_s32(a, 1);
+}
+
+// CHECK: test_vshll_n_u8
+// CHECK: vshll.u8 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vshll_n_u8(uint8x8_t a) {
+ return vshll_n_u8(a, 1);
+}
+
+// CHECK: test_vshll_n_u16
+// CHECK: vshll.u16 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vshll_n_u16(uint16x4_t a) {
+ return vshll_n_u16(a, 1);
+}
+
+// CHECK: test_vshll_n_u32
+// CHECK: vshll.u32 q{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vshll_n_u32(uint32x2_t a) {
+ return vshll_n_u32(a, 1);
+}
+
+
+// CHECK: test_vshl_n_s8
+// CHECK: vshl.i8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vshl_n_s8(int8x8_t a) {
+ return vshl_n_s8(a, 1);
+}
+
+// CHECK: test_vshl_n_s16
+// CHECK: vshl.i16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vshl_n_s16(int16x4_t a) {
+ return vshl_n_s16(a, 1);
+}
+
+// CHECK: test_vshl_n_s32
+// CHECK: vshl.i32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vshl_n_s32(int32x2_t a) {
+ return vshl_n_s32(a, 1);
+}
+
+// CHECK: test_vshl_n_s64
+// CHECK: vshl.i64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vshl_n_s64(int64x1_t a) {
+ return vshl_n_s64(a, 1);
+}
+
+// CHECK: test_vshl_n_u8
+// CHECK: vshl.i8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vshl_n_u8(uint8x8_t a) {
+ return vshl_n_u8(a, 1);
+}
+
+// CHECK: test_vshl_n_u16
+// CHECK: vshl.i16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vshl_n_u16(uint16x4_t a) {
+ return vshl_n_u16(a, 1);
+}
+
+// CHECK: test_vshl_n_u32
+// CHECK: vshl.i32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vshl_n_u32(uint32x2_t a) {
+ return vshl_n_u32(a, 1);
+}
+
+// CHECK: test_vshl_n_u64
+// CHECK: vshl.i64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vshl_n_u64(uint64x1_t a) {
+ return vshl_n_u64(a, 1);
+}
+
+// CHECK: test_vshlq_n_s8
+// CHECK: vshl.i8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vshlq_n_s8(int8x16_t a) {
+ return vshlq_n_s8(a, 1);
+}
+
+// CHECK: test_vshlq_n_s16
+// CHECK: vshl.i16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vshlq_n_s16(int16x8_t a) {
+ return vshlq_n_s16(a, 1);
+}
+
+// CHECK: test_vshlq_n_s32
+// CHECK: vshl.i32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vshlq_n_s32(int32x4_t a) {
+ return vshlq_n_s32(a, 1);
+}
+
+// CHECK: test_vshlq_n_s64
+// CHECK: vshl.i64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vshlq_n_s64(int64x2_t a) {
+ return vshlq_n_s64(a, 1);
+}
+
+// CHECK: test_vshlq_n_u8
+// CHECK: vshl.i8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vshlq_n_u8(uint8x16_t a) {
+ return vshlq_n_u8(a, 1);
+}
+
+// CHECK: test_vshlq_n_u16
+// CHECK: vshl.i16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vshlq_n_u16(uint16x8_t a) {
+ return vshlq_n_u16(a, 1);
+}
+
+// CHECK: test_vshlq_n_u32
+// CHECK: vshl.i32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vshlq_n_u32(uint32x4_t a) {
+ return vshlq_n_u32(a, 1);
+}
+
+// CHECK: test_vshlq_n_u64
+// CHECK: vshl.i64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vshlq_n_u64(uint64x2_t a) {
+ return vshlq_n_u64(a, 1);
+}
+
+
+// CHECK: test_vshrn_n_s16
+// CHECK: vshrn.i16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vshrn_n_s16(int16x8_t a) {
+ return vshrn_n_s16(a, 1);
+}
+
+// CHECK: test_vshrn_n_s32
+// CHECK: vshrn.i32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vshrn_n_s32(int32x4_t a) {
+ return vshrn_n_s32(a, 1);
+}
+
+// CHECK: test_vshrn_n_s64
+// CHECK: vshrn.i64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vshrn_n_s64(int64x2_t a) {
+ return vshrn_n_s64(a, 1);
+}
+
+// CHECK: test_vshrn_n_u16
+// CHECK: vshrn.i16 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vshrn_n_u16(uint16x8_t a) {
+ return vshrn_n_u16(a, 1);
+}
+
+// CHECK: test_vshrn_n_u32
+// CHECK: vshrn.i32 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vshrn_n_u32(uint32x4_t a) {
+ return vshrn_n_u32(a, 1);
+}
+
+// CHECK: test_vshrn_n_u64
+// CHECK: vshrn.i64 d{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vshrn_n_u64(uint64x2_t a) {
+ return vshrn_n_u64(a, 1);
+}
+
+
+// CHECK: test_vshr_n_s8
+// CHECK: vshr.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vshr_n_s8(int8x8_t a) {
+ return vshr_n_s8(a, 1);
+}
+
+// CHECK: test_vshr_n_s16
+// CHECK: vshr.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vshr_n_s16(int16x4_t a) {
+ return vshr_n_s16(a, 1);
+}
+
+// CHECK: test_vshr_n_s32
+// CHECK: vshr.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vshr_n_s32(int32x2_t a) {
+ return vshr_n_s32(a, 1);
+}
+
+// CHECK: test_vshr_n_s64
+// CHECK: vshr.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vshr_n_s64(int64x1_t a) {
+ return vshr_n_s64(a, 1);
+}
+
+// CHECK: test_vshr_n_u8
+// CHECK: vshr.u8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vshr_n_u8(uint8x8_t a) {
+ return vshr_n_u8(a, 1);
+}
+
+// CHECK: test_vshr_n_u16
+// CHECK: vshr.u16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vshr_n_u16(uint16x4_t a) {
+ return vshr_n_u16(a, 1);
+}
+
+// CHECK: test_vshr_n_u32
+// CHECK: vshr.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vshr_n_u32(uint32x2_t a) {
+ return vshr_n_u32(a, 1);
+}
+
+// CHECK: test_vshr_n_u64
+// CHECK: vshr.u64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vshr_n_u64(uint64x1_t a) {
+ return vshr_n_u64(a, 1);
+}
+
+// CHECK: test_vshrq_n_s8
+// CHECK: vshr.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vshrq_n_s8(int8x16_t a) {
+ return vshrq_n_s8(a, 1);
+}
+
+// CHECK: test_vshrq_n_s16
+// CHECK: vshr.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vshrq_n_s16(int16x8_t a) {
+ return vshrq_n_s16(a, 1);
+}
+
+// CHECK: test_vshrq_n_s32
+// CHECK: vshr.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vshrq_n_s32(int32x4_t a) {
+ return vshrq_n_s32(a, 1);
+}
+
+// CHECK: test_vshrq_n_s64
+// CHECK: vshr.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vshrq_n_s64(int64x2_t a) {
+ return vshrq_n_s64(a, 1);
+}
+
+// CHECK: test_vshrq_n_u8
+// CHECK: vshr.u8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vshrq_n_u8(uint8x16_t a) {
+ return vshrq_n_u8(a, 1);
+}
+
+// CHECK: test_vshrq_n_u16
+// CHECK: vshr.u16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vshrq_n_u16(uint16x8_t a) {
+ return vshrq_n_u16(a, 1);
+}
+
+// CHECK: test_vshrq_n_u32
+// CHECK: vshr.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vshrq_n_u32(uint32x4_t a) {
+ return vshrq_n_u32(a, 1);
+}
+
+// CHECK: test_vshrq_n_u64
+// CHECK: vshr.u64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vshrq_n_u64(uint64x2_t a) {
+ return vshrq_n_u64(a, 1);
+}
+
+
+// CHECK: test_vsli_n_s8
+// CHECK: vsli.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vsli_n_s8(int8x8_t a, int8x8_t b) {
+ return vsli_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsli_n_s16
+// CHECK: vsli.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vsli_n_s16(int16x4_t a, int16x4_t b) {
+ return vsli_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsli_n_s32
+// CHECK: vsli.32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vsli_n_s32(int32x2_t a, int32x2_t b) {
+ return vsli_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsli_n_s64
+// CHECK: vsli.64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vsli_n_s64(int64x1_t a, int64x1_t b) {
+ return vsli_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsli_n_u8
+// CHECK: vsli.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vsli_n_u8(uint8x8_t a, uint8x8_t b) {
+ return vsli_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsli_n_u16
+// CHECK: vsli.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vsli_n_u16(uint16x4_t a, uint16x4_t b) {
+ return vsli_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsli_n_u32
+// CHECK: vsli.32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vsli_n_u32(uint32x2_t a, uint32x2_t b) {
+ return vsli_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsli_n_u64
+// CHECK: vsli.64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vsli_n_u64(uint64x1_t a, uint64x1_t b) {
+ return vsli_n_u64(a, b, 1);
+}
+
+// CHECK: test_vsli_n_p8
+// CHECK: vsli.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly8x8_t test_vsli_n_p8(poly8x8_t a, poly8x8_t b) {
+ return vsli_n_p8(a, b, 1);
+}
+
+// CHECK: test_vsli_n_p16
+// CHECK: vsli.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly16x4_t test_vsli_n_p16(poly16x4_t a, poly16x4_t b) {
+ return vsli_n_p16(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_s8
+// CHECK: vsli.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vsliq_n_s8(int8x16_t a, int8x16_t b) {
+ return vsliq_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_s16
+// CHECK: vsli.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vsliq_n_s16(int16x8_t a, int16x8_t b) {
+ return vsliq_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_s32
+// CHECK: vsli.32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vsliq_n_s32(int32x4_t a, int32x4_t b) {
+ return vsliq_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_s64
+// CHECK: vsli.64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vsliq_n_s64(int64x2_t a, int64x2_t b) {
+ return vsliq_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_u8
+// CHECK: vsli.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vsliq_n_u8(uint8x16_t a, uint8x16_t b) {
+ return vsliq_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_u16
+// CHECK: vsli.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vsliq_n_u16(uint16x8_t a, uint16x8_t b) {
+ return vsliq_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_u32
+// CHECK: vsli.32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vsliq_n_u32(uint32x4_t a, uint32x4_t b) {
+ return vsliq_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_u64
+// CHECK: vsli.64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vsliq_n_u64(uint64x2_t a, uint64x2_t b) {
+ return vsliq_n_u64(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_p8
+// CHECK: vsli.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly8x16_t test_vsliq_n_p8(poly8x16_t a, poly8x16_t b) {
+ return vsliq_n_p8(a, b, 1);
+}
+
+// CHECK: test_vsliq_n_p16
+// CHECK: vsli.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly16x8_t test_vsliq_n_p16(poly16x8_t a, poly16x8_t b) {
+ return vsliq_n_p16(a, b, 1);
+}
+
+
+// CHECK: test_vsra_n_s8
+// CHECK: vsra.s8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vsra_n_s8(int8x8_t a, int8x8_t b) {
+ return vsra_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsra_n_s16
+// CHECK: vsra.s16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vsra_n_s16(int16x4_t a, int16x4_t b) {
+ return vsra_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsra_n_s32
+// CHECK: vsra.s32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vsra_n_s32(int32x2_t a, int32x2_t b) {
+ return vsra_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsra_n_s64
+// CHECK: vsra.s64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vsra_n_s64(int64x1_t a, int64x1_t b) {
+ return vsra_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsra_n_u8
+// CHECK: vsra.u8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vsra_n_u8(uint8x8_t a, uint8x8_t b) {
+ return vsra_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsra_n_u16
+// CHECK: vsra.u16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vsra_n_u16(uint16x4_t a, uint16x4_t b) {
+ return vsra_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsra_n_u32
+// CHECK: vsra.u32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vsra_n_u32(uint32x2_t a, uint32x2_t b) {
+ return vsra_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsra_n_u64
+// CHECK: vsra.u64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vsra_n_u64(uint64x1_t a, uint64x1_t b) {
+ return vsra_n_u64(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_s8
+// CHECK: vsra.s8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vsraq_n_s8(int8x16_t a, int8x16_t b) {
+ return vsraq_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_s16
+// CHECK: vsra.s16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vsraq_n_s16(int16x8_t a, int16x8_t b) {
+ return vsraq_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_s32
+// CHECK: vsra.s32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vsraq_n_s32(int32x4_t a, int32x4_t b) {
+ return vsraq_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_s64
+// CHECK: vsra.s64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vsraq_n_s64(int64x2_t a, int64x2_t b) {
+ return vsraq_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_u8
+// CHECK: vsra.u8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vsraq_n_u8(uint8x16_t a, uint8x16_t b) {
+ return vsraq_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_u16
+// CHECK: vsra.u16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vsraq_n_u16(uint16x8_t a, uint16x8_t b) {
+ return vsraq_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_u32
+// CHECK: vsra.u32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vsraq_n_u32(uint32x4_t a, uint32x4_t b) {
+ return vsraq_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsraq_n_u64
+// CHECK: vsra.u64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vsraq_n_u64(uint64x2_t a, uint64x2_t b) {
+ return vsraq_n_u64(a, b, 1);
+}
+
+
+// CHECK: test_vsri_n_s8
+// CHECK: vsri.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int8x8_t test_vsri_n_s8(int8x8_t a, int8x8_t b) {
+ return vsri_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsri_n_s16
+// CHECK: vsri.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int16x4_t test_vsri_n_s16(int16x4_t a, int16x4_t b) {
+ return vsri_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsri_n_s32
+// CHECK: vsri.32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int32x2_t test_vsri_n_s32(int32x2_t a, int32x2_t b) {
+ return vsri_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsri_n_s64
+// CHECK: vsri.64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+int64x1_t test_vsri_n_s64(int64x1_t a, int64x1_t b) {
+ return vsri_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsri_n_u8
+// CHECK: vsri.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint8x8_t test_vsri_n_u8(uint8x8_t a, uint8x8_t b) {
+ return vsri_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsri_n_u16
+// CHECK: vsri.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint16x4_t test_vsri_n_u16(uint16x4_t a, uint16x4_t b) {
+ return vsri_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsri_n_u32
+// CHECK: vsri.32 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint32x2_t test_vsri_n_u32(uint32x2_t a, uint32x2_t b) {
+ return vsri_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsri_n_u64
+// CHECK: vsri.64 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+uint64x1_t test_vsri_n_u64(uint64x1_t a, uint64x1_t b) {
+ return vsri_n_u64(a, b, 1);
+}
+
+// CHECK: test_vsri_n_p8
+// CHECK: vsri.8 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly8x8_t test_vsri_n_p8(poly8x8_t a, poly8x8_t b) {
+ return vsri_n_p8(a, b, 1);
+}
+
+// CHECK: test_vsri_n_p16
+// CHECK: vsri.16 d{{[0-9]+}}, d{{[0-9]+}}, #{{[0-9]+}}
+poly16x4_t test_vsri_n_p16(poly16x4_t a, poly16x4_t b) {
+ return vsri_n_p16(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_s8
+// CHECK: vsri.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int8x16_t test_vsriq_n_s8(int8x16_t a, int8x16_t b) {
+ return vsriq_n_s8(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_s16
+// CHECK: vsri.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int16x8_t test_vsriq_n_s16(int16x8_t a, int16x8_t b) {
+ return vsriq_n_s16(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_s32
+// CHECK: vsri.32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int32x4_t test_vsriq_n_s32(int32x4_t a, int32x4_t b) {
+ return vsriq_n_s32(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_s64
+// CHECK: vsri.64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+int64x2_t test_vsriq_n_s64(int64x2_t a, int64x2_t b) {
+ return vsriq_n_s64(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_u8
+// CHECK: vsri.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint8x16_t test_vsriq_n_u8(uint8x16_t a, uint8x16_t b) {
+ return vsriq_n_u8(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_u16
+// CHECK: vsri.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint16x8_t test_vsriq_n_u16(uint16x8_t a, uint16x8_t b) {
+ return vsriq_n_u16(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_u32
+// CHECK: vsri.32 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint32x4_t test_vsriq_n_u32(uint32x4_t a, uint32x4_t b) {
+ return vsriq_n_u32(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_u64
+// CHECK: vsri.64 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+uint64x2_t test_vsriq_n_u64(uint64x2_t a, uint64x2_t b) {
+ return vsriq_n_u64(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_p8
+// CHECK: vsri.8 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly8x16_t test_vsriq_n_p8(poly8x16_t a, poly8x16_t b) {
+ return vsriq_n_p8(a, b, 1);
+}
+
+// CHECK: test_vsriq_n_p16
+// CHECK: vsri.16 q{{[0-9]+}}, q{{[0-9]+}}, #{{[0-9]+}}
+poly16x8_t test_vsriq_n_p16(poly16x8_t a, poly16x8_t b) {
+ return vsriq_n_p16(a, b, 1);
+}
+
+
+// CHECK: test_vst1q_u8
+// CHECK: vst1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_u8(uint8_t * a, uint8x16_t b) {
+ vst1q_u8(a, b);
+}
+
+// CHECK: test_vst1q_u16
+// CHECK: vst1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_u16(uint16_t * a, uint16x8_t b) {
+ vst1q_u16(a, b);
+}
+
+// CHECK: test_vst1q_u32
+// CHECK: vst1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_u32(uint32_t * a, uint32x4_t b) {
+ vst1q_u32(a, b);
+}
+
+// CHECK: test_vst1q_u64
+// CHECK: vst1.64 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_u64(uint64_t * a, uint64x2_t b) {
+ vst1q_u64(a, b);
+}
+
+// CHECK: test_vst1q_s8
+// CHECK: vst1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_s8(int8_t * a, int8x16_t b) {
+ vst1q_s8(a, b);
+}
+
+// CHECK: test_vst1q_s16
+// CHECK: vst1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_s16(int16_t * a, int16x8_t b) {
+ vst1q_s16(a, b);
+}
+
+// CHECK: test_vst1q_s32
+// CHECK: vst1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_s32(int32_t * a, int32x4_t b) {
+ vst1q_s32(a, b);
+}
+
+// CHECK: test_vst1q_s64
+// CHECK: vst1.64 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_s64(int64_t * a, int64x2_t b) {
+ vst1q_s64(a, b);
+}
+
+// CHECK: test_vst1q_f16
+// CHECK: vst1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_f16(float16_t * a, float16x8_t b) {
+ vst1q_f16(a, b);
+}
+
+// CHECK: test_vst1q_f32
+// CHECK: vst1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_f32(float32_t * a, float32x4_t b) {
+ vst1q_f32(a, b);
+}
+
+// CHECK: test_vst1q_p8
+// CHECK: vst1.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_p8(poly8_t * a, poly8x16_t b) {
+ vst1q_p8(a, b);
+}
+
+// CHECK: test_vst1q_p16
+// CHECK: vst1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1q_p16(poly16_t * a, poly16x8_t b) {
+ vst1q_p16(a, b);
+}
+
+// CHECK: test_vst1_u8
+// CHECK: vst1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_u8(uint8_t * a, uint8x8_t b) {
+ vst1_u8(a, b);
+}
+
+// CHECK: test_vst1_u16
+// CHECK: vst1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_u16(uint16_t * a, uint16x4_t b) {
+ vst1_u16(a, b);
+}
+
+// CHECK: test_vst1_u32
+// CHECK: vst1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_u32(uint32_t * a, uint32x2_t b) {
+ vst1_u32(a, b);
+}
+
+// CHECK: test_vst1_u64
+// CHECK: vst1.64 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_u64(uint64_t * a, uint64x1_t b) {
+ vst1_u64(a, b);
+}
+
+// CHECK: test_vst1_s8
+// CHECK: vst1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_s8(int8_t * a, int8x8_t b) {
+ vst1_s8(a, b);
+}
+
+// CHECK: test_vst1_s16
+// CHECK: vst1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_s16(int16_t * a, int16x4_t b) {
+ vst1_s16(a, b);
+}
+
+// CHECK: test_vst1_s32
+// CHECK: vst1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_s32(int32_t * a, int32x2_t b) {
+ vst1_s32(a, b);
+}
+
+// CHECK: test_vst1_s64
+// CHECK: vst1.64 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_s64(int64_t * a, int64x1_t b) {
+ vst1_s64(a, b);
+}
+
+// CHECK: test_vst1_f16
+// CHECK: vst1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_f16(float16_t * a, float16x4_t b) {
+ vst1_f16(a, b);
+}
+
+// CHECK: test_vst1_f32
+// CHECK: vst1.32 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_f32(float32_t * a, float32x2_t b) {
+ vst1_f32(a, b);
+}
+
+// CHECK: test_vst1_p8
+// CHECK: vst1.8 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_p8(poly8_t * a, poly8x8_t b) {
+ vst1_p8(a, b);
+}
+
+// CHECK: test_vst1_p16
+// CHECK: vst1.16 {d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst1_p16(poly16_t * a, poly16x4_t b) {
+ vst1_p16(a, b);
+}
+
+
+// CHECK: test_vst1q_lane_u8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1q_lane_u8(uint8_t * a, uint8x16_t b) {
+ vst1q_lane_u8(a, b, 15);
+}
+
+// CHECK: test_vst1q_lane_u16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1q_lane_u16(uint16_t * a, uint16x8_t b) {
+ vst1q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vst1q_lane_u32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1q_lane_u32(uint32_t * a, uint32x4_t b) {
+ vst1q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vst1q_lane_u64
+// CHECK: {{str|vstr|vmov}}
+void test_vst1q_lane_u64(uint64_t * a, uint64x2_t b) {
+ vst1q_lane_u64(a, b, 1);
+}
+
+// CHECK: test_vst1q_lane_s8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1q_lane_s8(int8_t * a, int8x16_t b) {
+ vst1q_lane_s8(a, b, 15);
+}
+
+// CHECK: test_vst1q_lane_s16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1q_lane_s16(int16_t * a, int16x8_t b) {
+ vst1q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vst1q_lane_s32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1q_lane_s32(int32_t * a, int32x4_t b) {
+ vst1q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vst1q_lane_s64
+// CHECK: {{str|vstr|vmov}}
+void test_vst1q_lane_s64(int64_t * a, int64x2_t b) {
+ vst1q_lane_s64(a, b, 1);
+}
+
+// CHECK: test_vst1q_lane_f16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1q_lane_f16(float16_t * a, float16x8_t b) {
+ vst1q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vst1q_lane_f32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1q_lane_f32(float32_t * a, float32x4_t b) {
+ vst1q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vst1q_lane_p8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1q_lane_p8(poly8_t * a, poly8x16_t b) {
+ vst1q_lane_p8(a, b, 15);
+}
+
+// CHECK: test_vst1q_lane_p16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1q_lane_p16(poly16_t * a, poly16x8_t b) {
+ vst1q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vst1_lane_u8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1_lane_u8(uint8_t * a, uint8x8_t b) {
+ vst1_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vst1_lane_u16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1_lane_u16(uint16_t * a, uint16x4_t b) {
+ vst1_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vst1_lane_u32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1_lane_u32(uint32_t * a, uint32x2_t b) {
+ vst1_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vst1_lane_u64
+// CHECK: {{str|vstr|vmov}}
+void test_vst1_lane_u64(uint64_t * a, uint64x1_t b) {
+ vst1_lane_u64(a, b, 0);
+}
+
+// CHECK: test_vst1_lane_s8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1_lane_s8(int8_t * a, int8x8_t b) {
+ vst1_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vst1_lane_s16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1_lane_s16(int16_t * a, int16x4_t b) {
+ vst1_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vst1_lane_s32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1_lane_s32(int32_t * a, int32x2_t b) {
+ vst1_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vst1_lane_s64
+// CHECK: {{str|vstr|vmov}}
+void test_vst1_lane_s64(int64_t * a, int64x1_t b) {
+ vst1_lane_s64(a, b, 0);
+}
+
+// CHECK: test_vst1_lane_f16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1_lane_f16(float16_t * a, float16x4_t b) {
+ vst1_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vst1_lane_f32
+// CHECK: vst1.32 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:32]
+void test_vst1_lane_f32(float32_t * a, float32x2_t b) {
+ vst1_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vst1_lane_p8
+// CHECK: vst1.8 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst1_lane_p8(poly8_t * a, poly8x8_t b) {
+ vst1_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vst1_lane_p16
+// CHECK: vst1.16 {d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}:16]
+void test_vst1_lane_p16(poly16_t * a, poly16x4_t b) {
+ vst1_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vst2q_u8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_u8(uint8_t * a, uint8x16x2_t b) {
+ vst2q_u8(a, b);
+}
+
+// CHECK: test_vst2q_u16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_u16(uint16_t * a, uint16x8x2_t b) {
+ vst2q_u16(a, b);
+}
+
+// CHECK: test_vst2q_u32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_u32(uint32_t * a, uint32x4x2_t b) {
+ vst2q_u32(a, b);
+}
+
+// CHECK: test_vst2q_s8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_s8(int8_t * a, int8x16x2_t b) {
+ vst2q_s8(a, b);
+}
+
+// CHECK: test_vst2q_s16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_s16(int16_t * a, int16x8x2_t b) {
+ vst2q_s16(a, b);
+}
+
+// CHECK: test_vst2q_s32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_s32(int32_t * a, int32x4x2_t b) {
+ vst2q_s32(a, b);
+}
+
+// CHECK: test_vst2q_f16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_f16(float16_t * a, float16x8x2_t b) {
+ vst2q_f16(a, b);
+}
+
+// CHECK: test_vst2q_f32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_f32(float32_t * a, float32x4x2_t b) {
+ vst2q_f32(a, b);
+}
+
+// CHECK: test_vst2q_p8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_p8(poly8_t * a, poly8x16x2_t b) {
+ vst2q_p8(a, b);
+}
+
+// CHECK: test_vst2q_p16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2q_p16(poly16_t * a, poly16x8x2_t b) {
+ vst2q_p16(a, b);
+}
+
+// CHECK: test_vst2_u8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_u8(uint8_t * a, uint8x8x2_t b) {
+ vst2_u8(a, b);
+}
+
+// CHECK: test_vst2_u16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_u16(uint16_t * a, uint16x4x2_t b) {
+ vst2_u16(a, b);
+}
+
+// CHECK: test_vst2_u32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_u32(uint32_t * a, uint32x2x2_t b) {
+ vst2_u32(a, b);
+}
+
+// CHECK: test_vst2_u64
+// CHECK: vst1.64
+void test_vst2_u64(uint64_t * a, uint64x1x2_t b) {
+ vst2_u64(a, b);
+}
+
+// CHECK: test_vst2_s8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_s8(int8_t * a, int8x8x2_t b) {
+ vst2_s8(a, b);
+}
+
+// CHECK: test_vst2_s16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_s16(int16_t * a, int16x4x2_t b) {
+ vst2_s16(a, b);
+}
+
+// CHECK: test_vst2_s32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_s32(int32_t * a, int32x2x2_t b) {
+ vst2_s32(a, b);
+}
+
+// CHECK: test_vst2_s64
+// CHECK: vst1.64
+void test_vst2_s64(int64_t * a, int64x1x2_t b) {
+ vst2_s64(a, b);
+}
+
+// CHECK: test_vst2_f16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_f16(float16_t * a, float16x4x2_t b) {
+ vst2_f16(a, b);
+}
+
+// CHECK: test_vst2_f32
+// CHECK: vst2.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_f32(float32_t * a, float32x2x2_t b) {
+ vst2_f32(a, b);
+}
+
+// CHECK: test_vst2_p8
+// CHECK: vst2.8 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_p8(poly8_t * a, poly8x8x2_t b) {
+ vst2_p8(a, b);
+}
+
+// CHECK: test_vst2_p16
+// CHECK: vst2.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst2_p16(poly16_t * a, poly16x4x2_t b) {
+ vst2_p16(a, b);
+}
+
+
+// CHECK: test_vst2q_lane_u16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_u16(uint16_t * a, uint16x8x2_t b) {
+ vst2q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vst2q_lane_u32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_u32(uint32_t * a, uint32x4x2_t b) {
+ vst2q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vst2q_lane_s16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_s16(int16_t * a, int16x8x2_t b) {
+ vst2q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vst2q_lane_s32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_s32(int32_t * a, int32x4x2_t b) {
+ vst2q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vst2q_lane_f16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_f16(float16_t * a, float16x8x2_t b) {
+ vst2q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vst2q_lane_f32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_f32(float32_t * a, float32x4x2_t b) {
+ vst2q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vst2q_lane_p16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2q_lane_p16(poly16_t * a, poly16x8x2_t b) {
+ vst2q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vst2_lane_u8
+// CHECK: vst2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_u8(uint8_t * a, uint8x8x2_t b) {
+ vst2_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vst2_lane_u16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_u16(uint16_t * a, uint16x4x2_t b) {
+ vst2_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vst2_lane_u32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_u32(uint32_t * a, uint32x2x2_t b) {
+ vst2_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vst2_lane_s8
+// CHECK: vst2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_s8(int8_t * a, int8x8x2_t b) {
+ vst2_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vst2_lane_s16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_s16(int16_t * a, int16x4x2_t b) {
+ vst2_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vst2_lane_s32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_s32(int32_t * a, int32x2x2_t b) {
+ vst2_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vst2_lane_f16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_f16(float16_t * a, float16x4x2_t b) {
+ vst2_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vst2_lane_f32
+// CHECK: vst2.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_f32(float32_t * a, float32x2x2_t b) {
+ vst2_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vst2_lane_p8
+// CHECK: vst2.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_p8(poly8_t * a, poly8x8x2_t b) {
+ vst2_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vst2_lane_p16
+// CHECK: vst2.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst2_lane_p16(poly16_t * a, poly16x4x2_t b) {
+ vst2_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vst3q_u8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_u8(uint8_t * a, uint8x16x3_t b) {
+ vst3q_u8(a, b);
+}
+
+// CHECK: test_vst3q_u16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_u16(uint16_t * a, uint16x8x3_t b) {
+ vst3q_u16(a, b);
+}
+
+// CHECK: test_vst3q_u32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_u32(uint32_t * a, uint32x4x3_t b) {
+ vst3q_u32(a, b);
+}
+
+// CHECK: test_vst3q_s8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_s8(int8_t * a, int8x16x3_t b) {
+ vst3q_s8(a, b);
+}
+
+// CHECK: test_vst3q_s16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_s16(int16_t * a, int16x8x3_t b) {
+ vst3q_s16(a, b);
+}
+
+// CHECK: test_vst3q_s32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_s32(int32_t * a, int32x4x3_t b) {
+ vst3q_s32(a, b);
+}
+
+// CHECK: test_vst3q_f16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_f16(float16_t * a, float16x8x3_t b) {
+ vst3q_f16(a, b);
+}
+
+// CHECK: test_vst3q_f32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_f32(float32_t * a, float32x4x3_t b) {
+ vst3q_f32(a, b);
+}
+
+// CHECK: test_vst3q_p8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_p8(poly8_t * a, poly8x16x3_t b) {
+ vst3q_p8(a, b);
+}
+
+// CHECK: test_vst3q_p16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst3q_p16(poly16_t * a, poly16x8x3_t b) {
+ vst3q_p16(a, b);
+}
+
+// CHECK: test_vst3_u8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_u8(uint8_t * a, uint8x8x3_t b) {
+ vst3_u8(a, b);
+}
+
+// CHECK: test_vst3_u16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_u16(uint16_t * a, uint16x4x3_t b) {
+ vst3_u16(a, b);
+}
+
+// CHECK: test_vst3_u32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_u32(uint32_t * a, uint32x2x3_t b) {
+ vst3_u32(a, b);
+}
+
+// CHECK: test_vst3_u64
+// CHECK: vst1.64
+void test_vst3_u64(uint64_t * a, uint64x1x3_t b) {
+ vst3_u64(a, b);
+}
+
+// CHECK: test_vst3_s8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_s8(int8_t * a, int8x8x3_t b) {
+ vst3_s8(a, b);
+}
+
+// CHECK: test_vst3_s16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_s16(int16_t * a, int16x4x3_t b) {
+ vst3_s16(a, b);
+}
+
+// CHECK: test_vst3_s32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_s32(int32_t * a, int32x2x3_t b) {
+ vst3_s32(a, b);
+}
+
+// CHECK: test_vst3_s64
+// CHECK: vst1.64
+void test_vst3_s64(int64_t * a, int64x1x3_t b) {
+ vst3_s64(a, b);
+}
+
+// CHECK: test_vst3_f16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_f16(float16_t * a, float16x4x3_t b) {
+ vst3_f16(a, b);
+}
+
+// CHECK: test_vst3_f32
+// CHECK: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_f32(float32_t * a, float32x2x3_t b) {
+ vst3_f32(a, b);
+}
+
+// CHECK: test_vst3_p8
+// CHECK: vst3.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_p8(poly8_t * a, poly8x8x3_t b) {
+ vst3_p8(a, b);
+}
+
+// CHECK: test_vst3_p16
+// CHECK: vst3.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst3_p16(poly16_t * a, poly16x4x3_t b) {
+ vst3_p16(a, b);
+}
+
+
+// CHECK: test_vst3q_lane_u16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_u16(uint16_t * a, uint16x8x3_t b) {
+ vst3q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vst3q_lane_u32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_u32(uint32_t * a, uint32x4x3_t b) {
+ vst3q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vst3q_lane_s16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_s16(int16_t * a, int16x8x3_t b) {
+ vst3q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vst3q_lane_s32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_s32(int32_t * a, int32x4x3_t b) {
+ vst3q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vst3q_lane_f16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_f16(float16_t * a, float16x8x3_t b) {
+ vst3q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vst3q_lane_f32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_f32(float32_t * a, float32x4x3_t b) {
+ vst3q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vst3q_lane_p16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst3q_lane_p16(poly16_t * a, poly16x8x3_t b) {
+ vst3q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vst3_lane_u8
+// CHECK: vst3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_u8(uint8_t * a, uint8x8x3_t b) {
+ vst3_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vst3_lane_u16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_u16(uint16_t * a, uint16x4x3_t b) {
+ vst3_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vst3_lane_u32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_u32(uint32_t * a, uint32x2x3_t b) {
+ vst3_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vst3_lane_s8
+// CHECK: vst3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_s8(int8_t * a, int8x8x3_t b) {
+ vst3_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vst3_lane_s16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_s16(int16_t * a, int16x4x3_t b) {
+ vst3_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vst3_lane_s32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_s32(int32_t * a, int32x2x3_t b) {
+ vst3_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vst3_lane_f16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_f16(float16_t * a, float16x4x3_t b) {
+ vst3_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vst3_lane_f32
+// CHECK: vst3.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_f32(float32_t * a, float32x2x3_t b) {
+ vst3_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vst3_lane_p8
+// CHECK: vst3.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_p8(poly8_t * a, poly8x8x3_t b) {
+ vst3_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vst3_lane_p16
+// CHECK: vst3.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst3_lane_p16(poly16_t * a, poly16x4x3_t b) {
+ vst3_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vst4q_u8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_u8(uint8_t * a, uint8x16x4_t b) {
+ vst4q_u8(a, b);
+}
+
+// CHECK: test_vst4q_u16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_u16(uint16_t * a, uint16x8x4_t b) {
+ vst4q_u16(a, b);
+}
+
+// CHECK: test_vst4q_u32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_u32(uint32_t * a, uint32x4x4_t b) {
+ vst4q_u32(a, b);
+}
+
+// CHECK: test_vst4q_s8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_s8(int8_t * a, int8x16x4_t b) {
+ vst4q_s8(a, b);
+}
+
+// CHECK: test_vst4q_s16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_s16(int16_t * a, int16x8x4_t b) {
+ vst4q_s16(a, b);
+}
+
+// CHECK: test_vst4q_s32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_s32(int32_t * a, int32x4x4_t b) {
+ vst4q_s32(a, b);
+}
+
+// CHECK: test_vst4q_f16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_f16(float16_t * a, float16x8x4_t b) {
+ vst4q_f16(a, b);
+}
+
+// CHECK: test_vst4q_f32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_f32(float32_t * a, float32x4x4_t b) {
+ vst4q_f32(a, b);
+}
+
+// CHECK: test_vst4q_p8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_p8(poly8_t * a, poly8x16x4_t b) {
+ vst4q_p8(a, b);
+}
+
+// CHECK: test_vst4q_p16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}
+void test_vst4q_p16(poly16_t * a, poly16x8x4_t b) {
+ vst4q_p16(a, b);
+}
+
+// CHECK: test_vst4_u8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_u8(uint8_t * a, uint8x8x4_t b) {
+ vst4_u8(a, b);
+}
+
+// CHECK: test_vst4_u16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_u16(uint16_t * a, uint16x4x4_t b) {
+ vst4_u16(a, b);
+}
+
+// CHECK: test_vst4_u32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_u32(uint32_t * a, uint32x2x4_t b) {
+ vst4_u32(a, b);
+}
+
+// CHECK: test_vst4_u64
+// CHECK: vst1.64
+void test_vst4_u64(uint64_t * a, uint64x1x4_t b) {
+ vst4_u64(a, b);
+}
+
+// CHECK: test_vst4_s8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_s8(int8_t * a, int8x8x4_t b) {
+ vst4_s8(a, b);
+}
+
+// CHECK: test_vst4_s16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_s16(int16_t * a, int16x4x4_t b) {
+ vst4_s16(a, b);
+}
+
+// CHECK: test_vst4_s32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_s32(int32_t * a, int32x2x4_t b) {
+ vst4_s32(a, b);
+}
+
+// CHECK: test_vst4_s64
+// CHECK: vst1.64
+void test_vst4_s64(int64_t * a, int64x1x4_t b) {
+ vst4_s64(a, b);
+}
+
+// CHECK: test_vst4_f16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_f16(float16_t * a, float16x4x4_t b) {
+ vst4_f16(a, b);
+}
+
+// CHECK: test_vst4_f32
+// CHECK: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_f32(float32_t * a, float32x2x4_t b) {
+ vst4_f32(a, b);
+}
+
+// CHECK: test_vst4_p8
+// CHECK: vst4.8 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_p8(poly8_t * a, poly8x8x4_t b) {
+ vst4_p8(a, b);
+}
+
+// CHECK: test_vst4_p16
+// CHECK: vst4.16 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r{{[0-9]+}}]
+void test_vst4_p16(poly16_t * a, poly16x4x4_t b) {
+ vst4_p16(a, b);
+}
+
+
+// CHECK: test_vst4q_lane_u16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_u16(uint16_t * a, uint16x8x4_t b) {
+ vst4q_lane_u16(a, b, 7);
+}
+
+// CHECK: test_vst4q_lane_u32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_u32(uint32_t * a, uint32x4x4_t b) {
+ vst4q_lane_u32(a, b, 3);
+}
+
+// CHECK: test_vst4q_lane_s16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_s16(int16_t * a, int16x8x4_t b) {
+ vst4q_lane_s16(a, b, 7);
+}
+
+// CHECK: test_vst4q_lane_s32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_s32(int32_t * a, int32x4x4_t b) {
+ vst4q_lane_s32(a, b, 3);
+}
+
+// CHECK: test_vst4q_lane_f16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_f16(float16_t * a, float16x8x4_t b) {
+ vst4q_lane_f16(a, b, 7);
+}
+
+// CHECK: test_vst4q_lane_f32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_f32(float32_t * a, float32x4x4_t b) {
+ vst4q_lane_f32(a, b, 3);
+}
+
+// CHECK: test_vst4q_lane_p16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}
+void test_vst4q_lane_p16(poly16_t * a, poly16x8x4_t b) {
+ vst4q_lane_p16(a, b, 7);
+}
+
+// CHECK: test_vst4_lane_u8
+// CHECK: vst4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_u8(uint8_t * a, uint8x8x4_t b) {
+ vst4_lane_u8(a, b, 7);
+}
+
+// CHECK: test_vst4_lane_u16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_u16(uint16_t * a, uint16x4x4_t b) {
+ vst4_lane_u16(a, b, 3);
+}
+
+// CHECK: test_vst4_lane_u32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_u32(uint32_t * a, uint32x2x4_t b) {
+ vst4_lane_u32(a, b, 1);
+}
+
+// CHECK: test_vst4_lane_s8
+// CHECK: vst4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_s8(int8_t * a, int8x8x4_t b) {
+ vst4_lane_s8(a, b, 7);
+}
+
+// CHECK: test_vst4_lane_s16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_s16(int16_t * a, int16x4x4_t b) {
+ vst4_lane_s16(a, b, 3);
+}
+
+// CHECK: test_vst4_lane_s32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_s32(int32_t * a, int32x2x4_t b) {
+ vst4_lane_s32(a, b, 1);
+}
+
+// CHECK: test_vst4_lane_f16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_f16(float16_t * a, float16x4x4_t b) {
+ vst4_lane_f16(a, b, 3);
+}
+
+// CHECK: test_vst4_lane_f32
+// CHECK: vst4.32 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_f32(float32_t * a, float32x2x4_t b) {
+ vst4_lane_f32(a, b, 1);
+}
+
+// CHECK: test_vst4_lane_p8
+// CHECK: vst4.8 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_p8(poly8_t * a, poly8x8x4_t b) {
+ vst4_lane_p8(a, b, 7);
+}
+
+// CHECK: test_vst4_lane_p16
+// CHECK: vst4.16 {d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}], d{{[0-9]+}}[{{[0-9]+}}]}, [r{{[0-9]+}}]
+void test_vst4_lane_p16(poly16_t * a, poly16x4x4_t b) {
+ vst4_lane_p16(a, b, 3);
+}
+
+
+// CHECK: test_vsub_s8
+// CHECK: vsub.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int8x8_t test_vsub_s8(int8x8_t a, int8x8_t b) {
+ return vsub_s8(a, b);
+}
+
+// CHECK: test_vsub_s16
+// CHECK: vsub.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x4_t test_vsub_s16(int16x4_t a, int16x4_t b) {
+ return vsub_s16(a, b);
+}
+
+// CHECK: test_vsub_s32
+// CHECK: vsub.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x2_t test_vsub_s32(int32x2_t a, int32x2_t b) {
+ return vsub_s32(a, b);
+}
+
+// CHECK: test_vsub_s64
+// CHECK: vsub.i64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x1_t test_vsub_s64(int64x1_t a, int64x1_t b) {
+ return vsub_s64(a, b);
+}
+
+// CHECK: test_vsub_f32
+// CHECK: vsub.f32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+float32x2_t test_vsub_f32(float32x2_t a, float32x2_t b) {
+ return vsub_f32(a, b);
+}
+
+// CHECK: test_vsub_u8
+// CHECK: vsub.i8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vsub_u8(uint8x8_t a, uint8x8_t b) {
+ return vsub_u8(a, b);
+}
+
+// CHECK: test_vsub_u16
+// CHECK: vsub.i16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vsub_u16(uint16x4_t a, uint16x4_t b) {
+ return vsub_u16(a, b);
+}
+
+// CHECK: test_vsub_u32
+// CHECK: vsub.i32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vsub_u32(uint32x2_t a, uint32x2_t b) {
+ return vsub_u32(a, b);
+}
+
+// CHECK: test_vsub_u64
+// CHECK: vsub.i64 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x1_t test_vsub_u64(uint64x1_t a, uint64x1_t b) {
+ return vsub_u64(a, b);
+}
+
+// CHECK: test_vsubq_s8
+// CHECK: vsub.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x16_t test_vsubq_s8(int8x16_t a, int8x16_t b) {
+ return vsubq_s8(a, b);
+}
+
+// CHECK: test_vsubq_s16
+// CHECK: vsub.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x8_t test_vsubq_s16(int16x8_t a, int16x8_t b) {
+ return vsubq_s16(a, b);
+}
+
+// CHECK: test_vsubq_s32
+// CHECK: vsub.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x4_t test_vsubq_s32(int32x4_t a, int32x4_t b) {
+ return vsubq_s32(a, b);
+}
+
+// CHECK: test_vsubq_s64
+// CHECK: vsub.i64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int64x2_t test_vsubq_s64(int64x2_t a, int64x2_t b) {
+ return vsubq_s64(a, b);
+}
+
+// CHECK: test_vsubq_f32
+// CHECK: vsub.f32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+float32x4_t test_vsubq_f32(float32x4_t a, float32x4_t b) {
+ return vsubq_f32(a, b);
+}
+
+// CHECK: test_vsubq_u8
+// CHECK: vsub.i8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vsubq_u8(uint8x16_t a, uint8x16_t b) {
+ return vsubq_u8(a, b);
+}
+
+// CHECK: test_vsubq_u16
+// CHECK: vsub.i16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vsubq_u16(uint16x8_t a, uint16x8_t b) {
+ return vsubq_u16(a, b);
+}
+
+// CHECK: test_vsubq_u32
+// CHECK: vsub.i32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vsubq_u32(uint32x4_t a, uint32x4_t b) {
+ return vsubq_u32(a, b);
+}
+
+// CHECK: test_vsubq_u64
+// CHECK: vsub.i64 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint64x2_t test_vsubq_u64(uint64x2_t a, uint64x2_t b) {
+ return vsubq_u64(a, b);
+}
+
+
+// CHECK: test_vsubhn_s16
+// CHECK: vsubhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int8x8_t test_vsubhn_s16(int16x8_t a, int16x8_t b) {
+ return vsubhn_s16(a, b);
+}
+
+// CHECK: test_vsubhn_s32
+// CHECK: vsubhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int16x4_t test_vsubhn_s32(int32x4_t a, int32x4_t b) {
+ return vsubhn_s32(a, b);
+}
+
+// CHECK: test_vsubhn_s64
+// CHECK: vsubhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+int32x2_t test_vsubhn_s64(int64x2_t a, int64x2_t b) {
+ return vsubhn_s64(a, b);
+}
+
+// CHECK: test_vsubhn_u16
+// CHECK: vsubhn.i16 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x8_t test_vsubhn_u16(uint16x8_t a, uint16x8_t b) {
+ return vsubhn_u16(a, b);
+}
+
+// CHECK: test_vsubhn_u32
+// CHECK: vsubhn.i32 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x4_t test_vsubhn_u32(uint32x4_t a, uint32x4_t b) {
+ return vsubhn_u32(a, b);
+}
+
+// CHECK: test_vsubhn_u64
+// CHECK: vsubhn.i64 d{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x2_t test_vsubhn_u64(uint64x2_t a, uint64x2_t b) {
+ return vsubhn_u64(a, b);
+}
+
+
+// CHECK: test_vsubl_s8
+// CHECK: vsubl.s8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vsubl_s8(int8x8_t a, int8x8_t b) {
+ return vsubl_s8(a, b);
+}
+
+// CHECK: test_vsubl_s16
+// CHECK: vsubl.s16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vsubl_s16(int16x4_t a, int16x4_t b) {
+ return vsubl_s16(a, b);
+}
+
+// CHECK: test_vsubl_s32
+// CHECK: vsubl.s32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vsubl_s32(int32x2_t a, int32x2_t b) {
+ return vsubl_s32(a, b);
+}
+
+// CHECK: test_vsubl_u8
+// CHECK: vsubl.u8 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vsubl_u8(uint8x8_t a, uint8x8_t b) {
+ return vsubl_u8(a, b);
+}
+
+// CHECK: test_vsubl_u16
+// CHECK: vsubl.u16 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vsubl_u16(uint16x4_t a, uint16x4_t b) {
+ return vsubl_u16(a, b);
+}
+
+// CHECK: test_vsubl_u32
+// CHECK: vsubl.u32 q{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vsubl_u32(uint32x2_t a, uint32x2_t b) {
+ return vsubl_u32(a, b);
+}
+
+
+// CHECK: test_vsubw_s8
+// CHECK: vsubw.s8 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int16x8_t test_vsubw_s8(int16x8_t a, int8x8_t b) {
+ return vsubw_s8(a, b);
+}
+
+// CHECK: test_vsubw_s16
+// CHECK: vsubw.s16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int32x4_t test_vsubw_s16(int32x4_t a, int16x4_t b) {
+ return vsubw_s16(a, b);
+}
+
+// CHECK: test_vsubw_s32
+// CHECK: vsubw.s32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+int64x2_t test_vsubw_s32(int64x2_t a, int32x2_t b) {
+ return vsubw_s32(a, b);
+}
+
+// CHECK: test_vsubw_u8
+// CHECK: vsubw.u8 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint16x8_t test_vsubw_u8(uint16x8_t a, uint8x8_t b) {
+ return vsubw_u8(a, b);
+}
+
+// CHECK: test_vsubw_u16
+// CHECK: vsubw.u16 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint32x4_t test_vsubw_u16(uint32x4_t a, uint16x4_t b) {
+ return vsubw_u16(a, b);
+}
+
+// CHECK: test_vsubw_u32
+// CHECK: vsubw.u32 q{{[0-9]+}}, q{{[0-9]+}}, d{{[0-9]+}}
+uint64x2_t test_vsubw_u32(uint64x2_t a, uint32x2_t b) {
+ return vsubw_u32(a, b);
+}
+
+
+// CHECK: test_vtbl1_u8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbl1_u8(uint8x8_t a, uint8x8_t b) {
+ return vtbl1_u8(a, b);
+}
+
+// CHECK: test_vtbl1_s8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbl1_s8(int8x8_t a, int8x8_t b) {
+ return vtbl1_s8(a, b);
+}
+
+// CHECK: test_vtbl1_p8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbl1_p8(poly8x8_t a, uint8x8_t b) {
+ return vtbl1_p8(a, b);
+}
+
+
+// CHECK: test_vtbl2_u8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbl2_u8(uint8x8x2_t a, uint8x8_t b) {
+ return vtbl2_u8(a, b);
+}
+
+// CHECK: test_vtbl2_s8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbl2_s8(int8x8x2_t a, int8x8_t b) {
+ return vtbl2_s8(a, b);
+}
+
+// CHECK: test_vtbl2_p8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbl2_p8(poly8x8x2_t a, uint8x8_t b) {
+ return vtbl2_p8(a, b);
+}
+
+
+// CHECK: test_vtbl3_u8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbl3_u8(uint8x8x3_t a, uint8x8_t b) {
+ return vtbl3_u8(a, b);
+}
+
+// CHECK: test_vtbl3_s8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbl3_s8(int8x8x3_t a, int8x8_t b) {
+ return vtbl3_s8(a, b);
+}
+
+// CHECK: test_vtbl3_p8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbl3_p8(poly8x8x3_t a, uint8x8_t b) {
+ return vtbl3_p8(a, b);
+}
+
+
+// CHECK: test_vtbl4_u8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbl4_u8(uint8x8x4_t a, uint8x8_t b) {
+ return vtbl4_u8(a, b);
+}
+
+// CHECK: test_vtbl4_s8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbl4_s8(int8x8x4_t a, int8x8_t b) {
+ return vtbl4_s8(a, b);
+}
+
+// CHECK: test_vtbl4_p8
+// CHECK: vtbl.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbl4_p8(poly8x8x4_t a, uint8x8_t b) {
+ return vtbl4_p8(a, b);
+}
+
+
+// CHECK: test_vtbx1_u8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbx1_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
+ return vtbx1_u8(a, b, c);
+}
+
+// CHECK: test_vtbx1_s8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbx1_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
+ return vtbx1_s8(a, b, c);
+}
+
+// CHECK: test_vtbx1_p8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbx1_p8(poly8x8_t a, poly8x8_t b, uint8x8_t c) {
+ return vtbx1_p8(a, b, c);
+}
+
+
+// CHECK: test_vtbx2_u8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbx2_u8(uint8x8_t a, uint8x8x2_t b, uint8x8_t c) {
+ return vtbx2_u8(a, b, c);
+}
+
+// CHECK: test_vtbx2_s8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbx2_s8(int8x8_t a, int8x8x2_t b, int8x8_t c) {
+ return vtbx2_s8(a, b, c);
+}
+
+// CHECK: test_vtbx2_p8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbx2_p8(poly8x8_t a, poly8x8x2_t b, uint8x8_t c) {
+ return vtbx2_p8(a, b, c);
+}
+
+
+// CHECK: test_vtbx3_u8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbx3_u8(uint8x8_t a, uint8x8x3_t b, uint8x8_t c) {
+ return vtbx3_u8(a, b, c);
+}
+
+// CHECK: test_vtbx3_s8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbx3_s8(int8x8_t a, int8x8x3_t b, int8x8_t c) {
+ return vtbx3_s8(a, b, c);
+}
+
+// CHECK: test_vtbx3_p8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbx3_p8(poly8x8_t a, poly8x8x3_t b, uint8x8_t c) {
+ return vtbx3_p8(a, b, c);
+}
+
+
+// CHECK: test_vtbx4_u8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+uint8x8_t test_vtbx4_u8(uint8x8_t a, uint8x8x4_t b, uint8x8_t c) {
+ return vtbx4_u8(a, b, c);
+}
+
+// CHECK: test_vtbx4_s8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+int8x8_t test_vtbx4_s8(int8x8_t a, int8x8x4_t b, int8x8_t c) {
+ return vtbx4_s8(a, b, c);
+}
+
+// CHECK: test_vtbx4_p8
+// CHECK: vtbx.8 d{{[0-9]+}}, {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, d{{[0-9]+}}
+poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) {
+ return vtbx4_p8(a, b, c);
+}
+
+
+// CHECK: test_vtrn_s8
+// CHECK: vtrn.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) {
+ return vtrn_s8(a, b);
+}
+
+// CHECK: test_vtrn_s16
+// CHECK: vtrn.16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) {
+ return vtrn_s16(a, b);
+}
+
+// CHECK: test_vtrn_s32
+// CHECK: vtrn.32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) {
+ return vtrn_s32(a, b);
+}
+
+// CHECK: test_vtrn_u8
+// CHECK: vtrn.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) {
+ return vtrn_u8(a, b);
+}
+
+// CHECK: test_vtrn_u16
+// CHECK: vtrn.16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) {
+ return vtrn_u16(a, b);
+}
+
+// CHECK: test_vtrn_u32
+// CHECK: vtrn.32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) {
+ return vtrn_u32(a, b);
+}
+
+// CHECK: test_vtrn_f32
+// CHECK: vtrn.32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) {
+ return vtrn_f32(a, b);
+}
+
+// CHECK: test_vtrn_p8
+// CHECK: vtrn.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) {
+ return vtrn_p8(a, b);
+}
+
+// CHECK: test_vtrn_p16
+// CHECK: vtrn.16 d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) {
+ return vtrn_p16(a, b);
+}
+
+// CHECK: test_vtrnq_s8
+// CHECK: vtrn.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) {
+ return vtrnq_s8(a, b);
+}
+
+// CHECK: test_vtrnq_s16
+// CHECK: vtrn.16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) {
+ return vtrnq_s16(a, b);
+}
+
+// CHECK: test_vtrnq_s32
+// CHECK: vtrn.32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) {
+ return vtrnq_s32(a, b);
+}
+
+// CHECK: test_vtrnq_u8
+// CHECK: vtrn.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) {
+ return vtrnq_u8(a, b);
+}
+
+// CHECK: test_vtrnq_u16
+// CHECK: vtrn.16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) {
+ return vtrnq_u16(a, b);
+}
+
+// CHECK: test_vtrnq_u32
+// CHECK: vtrn.32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) {
+ return vtrnq_u32(a, b);
+}
+
+// CHECK: test_vtrnq_f32
+// CHECK: vtrn.32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) {
+ return vtrnq_f32(a, b);
+}
+
+// CHECK: test_vtrnq_p8
+// CHECK: vtrn.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) {
+ return vtrnq_p8(a, b);
+}
+
+// CHECK: test_vtrnq_p16
+// CHECK: vtrn.16 q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8x2_t test_vtrnq_p16(poly16x8_t a, poly16x8_t b) {
+ return vtrnq_p16(a, b);
+}
+
+
+// CHECK: test_vtst_s8
+// CHECK: vtst.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vtst_s8(int8x8_t a, int8x8_t b) {
+ return vtst_s8(a, b);
+}
+
+// CHECK: test_vtst_s16
+// CHECK: vtst.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vtst_s16(int16x4_t a, int16x4_t b) {
+ return vtst_s16(a, b);
+}
+
+// CHECK: test_vtst_s32
+// CHECK: vtst.32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vtst_s32(int32x2_t a, int32x2_t b) {
+ return vtst_s32(a, b);
+}
+
+// CHECK: test_vtst_u8
+// CHECK: vtst.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vtst_u8(uint8x8_t a, uint8x8_t b) {
+ return vtst_u8(a, b);
+}
+
+// CHECK: test_vtst_u16
+// CHECK: vtst.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vtst_u16(uint16x4_t a, uint16x4_t b) {
+ return vtst_u16(a, b);
+}
+
+// CHECK: test_vtst_u32
+// CHECK: vtst.32 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2_t test_vtst_u32(uint32x2_t a, uint32x2_t b) {
+ return vtst_u32(a, b);
+}
+
+// CHECK: test_vtst_p8
+// CHECK: vtst.8 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8_t test_vtst_p8(poly8x8_t a, poly8x8_t b) {
+ return vtst_p8(a, b);
+}
+
+// CHECK: test_vtst_p16
+// CHECK: vtst.16 d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4_t test_vtst_p16(poly16x4_t a, poly16x4_t b) {
+ return vtst_p16(a, b);
+}
+
+// CHECK: test_vtstq_s8
+// CHECK: vtst.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vtstq_s8(int8x16_t a, int8x16_t b) {
+ return vtstq_s8(a, b);
+}
+
+// CHECK: test_vtstq_s16
+// CHECK: vtst.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vtstq_s16(int16x8_t a, int16x8_t b) {
+ return vtstq_s16(a, b);
+}
+
+// CHECK: test_vtstq_s32
+// CHECK: vtst.32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vtstq_s32(int32x4_t a, int32x4_t b) {
+ return vtstq_s32(a, b);
+}
+
+// CHECK: test_vtstq_u8
+// CHECK: vtst.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vtstq_u8(uint8x16_t a, uint8x16_t b) {
+ return vtstq_u8(a, b);
+}
+
+// CHECK: test_vtstq_u16
+// CHECK: vtst.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vtstq_u16(uint16x8_t a, uint16x8_t b) {
+ return vtstq_u16(a, b);
+}
+
+// CHECK: test_vtstq_u32
+// CHECK: vtst.32 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4_t test_vtstq_u32(uint32x4_t a, uint32x4_t b) {
+ return vtstq_u32(a, b);
+}
+
+// CHECK: test_vtstq_p8
+// CHECK: vtst.8 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16_t test_vtstq_p8(poly8x16_t a, poly8x16_t b) {
+ return vtstq_p8(a, b);
+}
+
+// CHECK: test_vtstq_p16
+// CHECK: vtst.16 q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8_t test_vtstq_p16(poly16x8_t a, poly16x8_t b) {
+ return vtstq_p16(a, b);
+}
+
+
+// CHECK: test_vuzp_s8
+// CHECK: vuzp.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) {
+ return vuzp_s8(a, b);
+}
+
+// CHECK: test_vuzp_s16
+// CHECK: vuzp.16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) {
+ return vuzp_s16(a, b);
+}
+
+// CHECK: test_vuzp_s32
+// CHECK: {{vtrn|vuzp}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) {
+ return vuzp_s32(a, b);
+}
+
+// CHECK: test_vuzp_u8
+// CHECK: vuzp.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) {
+ return vuzp_u8(a, b);
+}
+
+// CHECK: test_vuzp_u16
+// CHECK: vuzp.16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) {
+ return vuzp_u16(a, b);
+}
+
+// CHECK: test_vuzp_u32
+// CHECK: {{vtrn|vuzp}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) {
+ return vuzp_u32(a, b);
+}
+
+// CHECK: test_vuzp_f32
+// CHECK: {{vtrn|vuzp}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) {
+ return vuzp_f32(a, b);
+}
+
+// CHECK: test_vuzp_p8
+// CHECK: vuzp.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) {
+ return vuzp_p8(a, b);
+}
+
+// CHECK: test_vuzp_p16
+// CHECK: vuzp.16 d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) {
+ return vuzp_p16(a, b);
+}
+
+// CHECK: test_vuzpq_s8
+// CHECK: vuzp.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) {
+ return vuzpq_s8(a, b);
+}
+
+// CHECK: test_vuzpq_s16
+// CHECK: vuzp.16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) {
+ return vuzpq_s16(a, b);
+}
+
+// CHECK: test_vuzpq_s32
+// CHECK: {{vtrn|vuzp}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) {
+ return vuzpq_s32(a, b);
+}
+
+// CHECK: test_vuzpq_u8
+// CHECK: vuzp.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) {
+ return vuzpq_u8(a, b);
+}
+
+// CHECK: test_vuzpq_u16
+// CHECK: vuzp.16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) {
+ return vuzpq_u16(a, b);
+}
+
+// CHECK: test_vuzpq_u32
+// CHECK: {{vtrn|vuzp}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) {
+ return vuzpq_u32(a, b);
+}
+
+// CHECK: test_vuzpq_f32
+// CHECK: {{vtrn|vuzp}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) {
+ return vuzpq_f32(a, b);
+}
+
+// CHECK: test_vuzpq_p8
+// CHECK: vuzp.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) {
+ return vuzpq_p8(a, b);
+}
+
+// CHECK: test_vuzpq_p16
+// CHECK: vuzp.16 q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) {
+ return vuzpq_p16(a, b);
+}
+
+
+// CHECK: test_vzip_s8
+// CHECK: vzip.8 d{{[0-9]+}}, d{{[0-9]+}}
+int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) {
+ return vzip_s8(a, b);
+}
+
+// CHECK: test_vzip_s16
+// CHECK: vzip.16 d{{[0-9]+}}, d{{[0-9]+}}
+int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) {
+ return vzip_s16(a, b);
+}
+
+// CHECK: test_vzip_s32
+// CHECK: {{vtrn|vzip}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) {
+ return vzip_s32(a, b);
+}
+
+// CHECK: test_vzip_u8
+// CHECK: vzip.8 d{{[0-9]+}}, d{{[0-9]+}}
+uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) {
+ return vzip_u8(a, b);
+}
+
+// CHECK: test_vzip_u16
+// CHECK: vzip.16 d{{[0-9]+}}, d{{[0-9]+}}
+uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) {
+ return vzip_u16(a, b);
+}
+
+// CHECK: test_vzip_u32
+// CHECK: {{vtrn|vzip}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) {
+ return vzip_u32(a, b);
+}
+
+// CHECK: test_vzip_f32
+// CHECK: {{vtrn|vzip}}.32 d{{[0-9]+}}, d{{[0-9]+}}
+float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) {
+ return vzip_f32(a, b);
+}
+
+// CHECK: test_vzip_p8
+// CHECK: vzip.8 d{{[0-9]+}}, d{{[0-9]+}}
+poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) {
+ return vzip_p8(a, b);
+}
+
+// CHECK: test_vzip_p16
+// CHECK: vzip.16 d{{[0-9]+}}, d{{[0-9]+}}
+poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) {
+ return vzip_p16(a, b);
+}
+
+// CHECK: test_vzipq_s8
+// CHECK: vzip.8 q{{[0-9]+}}, q{{[0-9]+}}
+int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) {
+ return vzipq_s8(a, b);
+}
+
+// CHECK: test_vzipq_s16
+// CHECK: vzip.16 q{{[0-9]+}}, q{{[0-9]+}}
+int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) {
+ return vzipq_s16(a, b);
+}
+
+// CHECK: test_vzipq_s32
+// CHECK: {{vtrn|vzip}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) {
+ return vzipq_s32(a, b);
+}
+
+// CHECK: test_vzipq_u8
+// CHECK: vzip.8 q{{[0-9]+}}, q{{[0-9]+}}
+uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) {
+ return vzipq_u8(a, b);
+}
+
+// CHECK: test_vzipq_u16
+// CHECK: vzip.16 q{{[0-9]+}}, q{{[0-9]+}}
+uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) {
+ return vzipq_u16(a, b);
+}
+
+// CHECK: test_vzipq_u32
+// CHECK: {{vtrn|vzip}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) {
+ return vzipq_u32(a, b);
+}
+
+// CHECK: test_vzipq_f32
+// CHECK: {{vtrn|vzip}}.32 q{{[0-9]+}}, q{{[0-9]+}}
+float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) {
+ return vzipq_f32(a, b);
+}
+
+// CHECK: test_vzipq_p8
+// CHECK: vzip.8 q{{[0-9]+}}, q{{[0-9]+}}
+poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) {
+ return vzipq_p8(a, b);
+}
+
+// CHECK: test_vzipq_p16
+// CHECK: vzip.16 q{{[0-9]+}}, q{{[0-9]+}}
+poly16x8x2_t test_vzipq_p16(poly16x8_t a, poly16x8_t b) {
+ return vzipq_p16(a, b);
+}
+
+
diff --git a/test/CodeGen/asm-label.c b/test/CodeGen/asm-label.c
index c06f11fd2d24..f944d368f8b3 100644
--- a/test/CodeGen/asm-label.c
+++ b/test/CodeGen/asm-label.c
@@ -17,3 +17,15 @@ int *test(void) {
// DARWIN: @"\01bar" = internal global i32 0
// DARWIN: @"\01foo" = common global i32 0
// DARWIN: declare i8* @"\01alias"(i32)
+
+// PR7887
+int pr7887_1 asm("");
+extern int pr7887_2 asm("");
+int pr7887_3 () asm("");
+
+int pt7887_4 () {
+ static int y asm("");
+ y = pr7887_3();
+ pr7887_2 = 1;
+ return pr7887_1;
+}
diff --git a/test/CodeGen/assign.c b/test/CodeGen/assign.c
index fc008963c317..b2702f096601 100644
--- a/test/CodeGen/assign.c
+++ b/test/CodeGen/assign.c
@@ -2,7 +2,7 @@
// Check that we don't generate unnecessary reloads.
//
-// CHECK: define void @f0()
+// CHECK-LABEL: define void @f0()
// CHECK: [[x_0:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[y_0:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 1, i32* [[x_0]]
@@ -18,7 +18,7 @@ void f0() {
// This used to test that we generate reloads for volatile access,
// but that does not appear to be correct behavior for C.
//
-// CHECK: define void @f1()
+// CHECK-LABEL: define void @f1()
// CHECK: [[x_1:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[y_1:%.*]] = alloca i32, align 4
// CHECK-NEXT: store volatile i32 1, i32* [[x_1]]
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
index d79f40522344..830f21a569aa 100644
--- a/test/CodeGen/atomic-ops.c
+++ b/test/CodeGen/atomic-ops.c
@@ -246,9 +246,6 @@ _Atomic(struct foo) bigAtomic;
void structAtomicStore() {
// CHECK: @structAtomicStore
struct foo f = {0};
- __c11_atomic_store(&bigAtomic, f, 5);
- // CHECK: call void @__atomic_store(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
-
struct bar b = {0};
__atomic_store(&smallThing, &b, 5);
// CHECK: call void @__atomic_store(i32 3, i8* {{.*}} @smallThing
@@ -258,13 +255,11 @@ void structAtomicStore() {
}
void structAtomicLoad() {
// CHECK: @structAtomicLoad
- struct foo f = __c11_atomic_load(&bigAtomic, 5);
- // CHECK: call void @__atomic_load(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
-
struct bar b;
__atomic_load(&smallThing, &b, 5);
// CHECK: call void @__atomic_load(i32 3, i8* {{.*}} @smallThing
+ struct foo f = {0};
__atomic_load(&bigThing, &f, 5);
// CHECK: call void @__atomic_load(i32 512, i8* {{.*}} @bigThing
}
diff --git a/test/CodeGen/atomics-inlining.c b/test/CodeGen/atomics-inlining.c
index 9b0d4135fc14..6456e74a94ec 100644
--- a/test/CodeGen/atomics-inlining.c
+++ b/test/CodeGen/atomics-inlining.c
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -triple arm-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=ARM
// RUN: %clang_cc1 -triple powerpc-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC32
// RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC64
// RUN: %clang_cc1 -triple mipsel-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=MIPS32
@@ -7,6 +8,7 @@ unsigned char c1, c2;
unsigned short s1, s2;
unsigned int i1, i2;
unsigned long long ll1, ll2;
+unsigned char a1[100], a2[100];
enum memory_order {
memory_order_relaxed,
@@ -19,31 +21,73 @@ enum memory_order {
void test1(void) {
(void)__atomic_load(&c1, &c2, memory_order_seq_cst);
+ (void)__atomic_store(&c1, &c2, memory_order_seq_cst);
(void)__atomic_load(&s1, &s2, memory_order_seq_cst);
+ (void)__atomic_store(&s1, &s2, memory_order_seq_cst);
(void)__atomic_load(&i1, &i2, memory_order_seq_cst);
+ (void)__atomic_store(&i1, &i2, memory_order_seq_cst);
(void)__atomic_load(&ll1, &ll2, memory_order_seq_cst);
+ (void)__atomic_store(&ll1, &ll2, memory_order_seq_cst);
+ (void)__atomic_load(&a1, &a2, memory_order_seq_cst);
+ (void)__atomic_store(&a1, &a2, memory_order_seq_cst);
-// PPC32: define void @test1
-// PPC32: load atomic i8* @c1 seq_cst
-// PPC32: load atomic i16* @s1 seq_cst
-// PPC32: load atomic i32* @i1 seq_cst
-// PPC32: call void @__atomic_load(i32 8, i8* bitcast (i64* @ll1 to i8*)
-
-// PPC64: define void @test1
-// PPC64: load atomic i8* @c1 seq_cst
-// PPC64: load atomic i16* @s1 seq_cst
-// PPC64: load atomic i32* @i1 seq_cst
-// PPC64: load atomic i64* @ll1 seq_cst
-
-// MIPS32: define void @test1
-// MIPS32: load atomic i8* @c1 seq_cst
-// MIPS32: load atomic i16* @s1 seq_cst
-// MIPS32: load atomic i32* @i1 seq_cst
-// MIPS32: call void @__atomic_load(i32 8, i8* bitcast (i64* @ll1 to i8*)
-
-// MIPS64: define void @test1
-// MIPS64: load atomic i8* @c1 seq_cst
-// MIPS64: load atomic i16* @s1 seq_cst
-// MIPS64: load atomic i32* @i1 seq_cst
-// MIPS64: load atomic i64* @ll1 seq_cst
+// ARM-LABEL: define arm_aapcscc void @test1
+// ARM: = call arm_aapcscc zeroext i8 @__atomic_load_1(i8* @c1
+// ARM: call arm_aapcscc void @__atomic_store_1(i8* @c1, i8 zeroext
+// ARM: = call arm_aapcscc zeroext i16 @__atomic_load_2(i8* bitcast (i16* @s1 to i8*)
+// ARM: call arm_aapcscc void @__atomic_store_2(i8* bitcast (i16* @s1 to i8*), i16 zeroext
+// ARM: = call arm_aapcscc i32 @__atomic_load_4(i8* bitcast (i32* @i1 to i8*)
+// ARM: call arm_aapcscc void @__atomic_store_4(i8* bitcast (i32* @i1 to i8*), i32
+// ARM: = call arm_aapcscc i64 @__atomic_load_8(i8* bitcast (i64* @ll1 to i8*)
+// ARM: call arm_aapcscc void @__atomic_store_8(i8* bitcast (i64* @ll1 to i8*), i64
+// ARM: call arm_aapcscc void @__atomic_load(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// ARM: call arm_aapcscc void @__atomic_store(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+
+// PPC32-LABEL: define void @test1
+// PPC32: = load atomic i8* @c1 seq_cst
+// PPC32: store atomic i8 {{.*}}, i8* @c1 seq_cst
+// PPC32: = load atomic i16* @s1 seq_cst
+// PPC32: store atomic i16 {{.*}}, i16* @s1 seq_cst
+// PPC32: = load atomic i32* @i1 seq_cst
+// PPC32: store atomic i32 {{.*}}, i32* @i1 seq_cst
+// PPC32: = call i64 @__atomic_load_8(i8* bitcast (i64* @ll1 to i8*)
+// PPC32: call void @__atomic_store_8(i8* bitcast (i64* @ll1 to i8*), i64
+// PPC32: call void @__atomic_load(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// PPC32: call void @__atomic_store(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+
+// PPC64-LABEL: define void @test1
+// PPC64: = load atomic i8* @c1 seq_cst
+// PPC64: store atomic i8 {{.*}}, i8* @c1 seq_cst
+// PPC64: = load atomic i16* @s1 seq_cst
+// PPC64: store atomic i16 {{.*}}, i16* @s1 seq_cst
+// PPC64: = load atomic i32* @i1 seq_cst
+// PPC64: store atomic i32 {{.*}}, i32* @i1 seq_cst
+// PPC64: = load atomic i64* @ll1 seq_cst
+// PPC64: store atomic i64 {{.*}}, i64* @ll1 seq_cst
+// PPC64: call void @__atomic_load(i64 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// PPC64: call void @__atomic_store(i64 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+
+// MIPS32-LABEL: define void @test1
+// MIPS32: = load atomic i8* @c1 seq_cst
+// MIPS32: store atomic i8 {{.*}}, i8* @c1 seq_cst
+// MIPS32: = load atomic i16* @s1 seq_cst
+// MIPS32: store atomic i16 {{.*}}, i16* @s1 seq_cst
+// MIPS32: = load atomic i32* @i1 seq_cst
+// MIPS32: store atomic i32 {{.*}}, i32* @i1 seq_cst
+// MIPS32: call i64 @__atomic_load_8(i8* bitcast (i64* @ll1 to i8*)
+// MIPS32: call void @__atomic_store_8(i8* bitcast (i64* @ll1 to i8*), i64
+// MIPS32: call void @__atomic_load(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// MIPS32: call void @__atomic_store(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+
+// MIPS64-LABEL: define void @test1
+// MIPS64: = load atomic i8* @c1 seq_cst
+// MIPS64: store atomic i8 {{.*}}, i8* @c1 seq_cst
+// MIPS64: = load atomic i16* @s1 seq_cst
+// MIPS64: store atomic i16 {{.*}}, i16* @s1 seq_cst
+// MIPS64: = load atomic i32* @i1 seq_cst
+// MIPS64: store atomic i32 {{.*}}, i32* @i1 seq_cst
+// MIPS64: = load atomic i64* @ll1 seq_cst
+// MIPS64: store atomic i64 {{.*}}, i64* @ll1 seq_cst
+// MIPS64: call void @__atomic_load(i64 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0)
+// MIPS64: call void @__atomic_store(i64 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
}
diff --git a/test/CodeGen/attr-availability.c b/test/CodeGen/attr-availability.c
index 6f9c045a3f17..ccbbb62f8c1f 100644
--- a/test/CodeGen/attr-availability.c
+++ b/test/CodeGen/attr-availability.c
@@ -2,15 +2,15 @@
// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin9.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_5 %s
// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin10.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_6 %s
-// CHECK-10_4: define hidden void @f2
-// CHECK-10_5: define hidden void @f2
-// CHECK-10_6: define hidden void @f2
+// CHECK-10_4-LABEL: define hidden void @f2
+// CHECK-10_5-LABEL: define hidden void @f2
+// CHECK-10_6-LABEL: define hidden void @f2
void f2();
void f2() { }
-// CHECK-10_4: define void @f3
-// CHECK-10_5: define void @f3
-// CHECK-10_6: define void @f3
+// CHECK-10_4-LABEL: define void @f3
+// CHECK-10_5-LABEL: define void @f3
+// CHECK-10_6-LABEL: define 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 a27711970842..ec54edde9d77 100644
--- a/test/CodeGen/attr-coldhot.c
+++ b/test/CodeGen/attr-coldhot.c
@@ -8,4 +8,4 @@ int test1() __attribute__((__cold__)) {
// CHECK: ret
}
-// CHECK: attributes [[ATTR]] = { {{.*}}optsize{{.*}} }
+// CHECK: attributes [[ATTR]] = { {{.*}}cold{{.*}}optsize{{.*}} }
diff --git a/test/CodeGen/attr-minsize.cpp b/test/CodeGen/attr-minsize.cpp
index 997194df7f90..0f07725fe8d8 100644
--- a/test/CodeGen/attr-minsize.cpp
+++ b/test/CodeGen/attr-minsize.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -Oz -emit-llvm %s -o - | FileCheck %s -check-prefix=Oz
-// RUN: %clang_cc1 -O0 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O3 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
diff --git a/test/CodeGen/attr-weakref.c b/test/CodeGen/attr-weakref.c
index 560d39141ca9..248860d5bcd3 100644
--- a/test/CodeGen/attr-weakref.c
+++ b/test/CodeGen/attr-weakref.c
@@ -8,7 +8,7 @@ void test1_h(void) {
test1_g();
}
-// CHECK: define void @test2_f()
+// CHECK-LABEL: define void @test2_f()
void test2_f(void) {}
static void test2_g(void) __attribute__((weakref("test2_f")));
void test2_h(void) {
@@ -25,7 +25,7 @@ void test3_h(void) {
test3_g();
}
-// CHECK: define void @test4_f()
+// CHECK-LABEL: define void @test4_f()
void test4_f(void);
static void test4_g(void) __attribute__((weakref("test4_f")));
void test4_h(void) {
diff --git a/test/CodeGen/available-externally-suppress.c b/test/CodeGen/available-externally-suppress.c
index 46b6e742f35e..390d2017884a 100644
--- a/test/CodeGen/available-externally-suppress.c
+++ b/test/CodeGen/available-externally-suppress.c
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -emit-llvm -o - -O0 -triple x86_64-apple-darwin10 %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-apple-darwin10 %s | FileCheck %s
// Ensure that we don't emit available_externally functions at -O0.
int x;
inline void f0(int y) { x = y; }
-// CHECK: define void @test()
+// CHECK-LABEL: define void @test()
// CHECK: declare void @f0(i32)
void test() {
f0(17);
diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c
index 0e5a741bcf67..c88946fe8567 100644
--- a/test/CodeGen/avx-builtins.c
+++ b/test/CodeGen/avx-builtins.c
@@ -93,3 +93,21 @@ int test_mm_cmpistrz(__m128i A, __m128i B) {
// CHECK: @llvm.x86.sse42.pcmpistriz128
return _mm_cmpistrz(A, B, 7);
}
+
+int test_extract_epi32(__m256i __a) {
+ // CHECK-LABEL: @test_extract_epi32
+ // CHECK: extractelement <8 x i32> %{{.*}}, i32 0
+ return _mm256_extract_epi32(__a, 8);
+}
+
+int test_extract_epi16(__m256i __a) {
+ // CHECK-LABEL: @test_extract_epi16
+ // CHECK: extractelement <16 x i16> %{{.*}}, i32 0
+ return _mm256_extract_epi16(__a, 16);
+}
+
+int test_extract_epi8(__m256i __a) {
+ // CHECK-LABEL: @test_extract_epi8
+ // CHECK: extractelement <32 x i8> %{{.*}}, i32 0
+ return _mm256_extract_epi8(__a, 32);
+}
diff --git a/test/CodeGen/avx-cmp-builtins.c b/test/CodeGen/avx-cmp-builtins.c
index 1ac1c31e2ad0..5b205d79d0c6 100644
--- a/test/CodeGen/avx-cmp-builtins.c
+++ b/test/CodeGen/avx-cmp-builtins.c
@@ -44,3 +44,51 @@ __m128d test_cmp_ss(__m128 a, __m128 b) {
// CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 13)
return _mm_cmp_ss(a, b, _CMP_GE_OS);
}
+
+__m128 test_cmpgt_ss(__m128 a, __m128 b) {
+ // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 1)
+ // CHECK: shufflevector <{{.*}}, <4 x i32> <i32 4, i32 1, i32 2, i32 3>
+ return _mm_cmpgt_ss(a, b);
+}
+
+__m128 test_cmpge_ss(__m128 a, __m128 b) {
+ // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 2)
+ // CHECK: shufflevector <{{.*}}, <4 x i32> <i32 4, i32 1, i32 2, i32 3>
+ return _mm_cmpge_ss(a, b);
+}
+
+__m128 test_cmpngt_ss(__m128 a, __m128 b) {
+ // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 5)
+ // CHECK: shufflevector <{{.*}}, <4 x i32> <i32 4, i32 1, i32 2, i32 3>
+ return _mm_cmpngt_ss(a, b);
+}
+
+__m128 test_cmpnge_ss(__m128 a, __m128 b) {
+ // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 6)
+ // CHECK: shufflevector <{{.*}}, <4 x i32> <i32 4, i32 1, i32 2, i32 3>
+ return _mm_cmpnge_ss(a, b);
+}
+
+__m128d test_cmpgt_sd(__m128d a, __m128d b) {
+ // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 1)
+ // CHECK: shufflevector <{{.*}}, <2 x i32> <i32 0, i32 3>
+ return _mm_cmpgt_sd(a, b);
+}
+
+__m128d test_cmpge_sd(__m128d a, __m128d b) {
+ // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 2)
+ // CHECK: shufflevector <{{.*}}, <2 x i32> <i32 0, i32 3>
+ return _mm_cmpge_sd(a, b);
+}
+
+__m128d test_cmpngt_sd(__m128d a, __m128d b) {
+ // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 5)
+ // CHECK: shufflevector <{{.*}}, <2 x i32> <i32 0, i32 3>
+ return _mm_cmpngt_sd(a, b);
+}
+
+__m128d test_cmpnge_sd(__m128d a, __m128d b) {
+ // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 6)
+ // CHECK: shufflevector <{{.*}}, <2 x i32> <i32 0, i32 3>
+ return _mm_cmpnge_sd(a, b);
+}
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index b5bc60503173..5024d94e7185 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Werror | FileCheck %s
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -606,9 +606,9 @@ __m256d test_mm256_broadcastsd_pd(__m128d a) {
return _mm256_broadcastsd_pd(a);
}
-__m256i test_mm_broadcastsi128_si256(__m128i *a) {
+__m256i test_mm256_broadcastsi128_si256(__m128i a) {
// CHECK: @llvm.x86.avx2.vbroadcasti128
- return _mm_broadcastsi128_si256(a);
+ return _mm256_broadcastsi128_si256(a);
}
__m128i test_mm_blend_epi32(__m128i a, __m128i b) {
@@ -850,22 +850,22 @@ __m128i test_mm256_mask_i64gather_epi32(__m128i a, int const *b, __m256i c,
return _mm256_mask_i64gather_epi32(a, b, c, d, 2);
}
-__m128i test_mm_mask_i32gather_epi64(__m128i a, int const *b, __m128i c,
+__m128i test_mm_mask_i32gather_epi64(__m128i a, long long const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.d.q
return _mm_mask_i32gather_epi64(a, b, c, d, 2);
}
-__m256i test_mm256_mask_i32gather_epi64(__m256i a, int const *b, __m128i c,
+__m256i test_mm256_mask_i32gather_epi64(__m256i a, long long const *b, __m128i c,
__m256i d) {
// CHECK: @llvm.x86.avx2.gather.d.q.256
return _mm256_mask_i32gather_epi64(a, b, c, d, 2);
}
-__m128i test_mm_mask_i64gather_epi64(__m128i a, int const *b, __m128i c,
+__m128i test_mm_mask_i64gather_epi64(__m128i a, long long const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.q.q
return _mm_mask_i64gather_epi64(a, b, c, d, 2);
}
-__m256i test_mm256_mask_i64gather_epi64(__m256i a, int const *b, __m256i c,
+__m256i test_mm256_mask_i64gather_epi64(__m256i a, long long const *b, __m256i c,
__m256i d) {
// CHECK: @llvm.x86.avx2.gather.q.q.256
return _mm256_mask_i64gather_epi64(a, b, c, d, 2);
@@ -920,19 +920,19 @@ __m128i test_mm256_i64gather_epi32(int const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.d.256
return _mm256_i64gather_epi32(b, c, 2);
}
-__m128i test_mm_i32gather_epi64(int const *b, __m128i c) {
+__m128i test_mm_i32gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.q
return _mm_i32gather_epi64(b, c, 2);
}
-__m256i test_mm256_i32gather_epi64(int const *b, __m128i c) {
+__m256i test_mm256_i32gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.q.256
return _mm256_i32gather_epi64(b, c, 2);
}
-__m128i test_mm_i64gather_epi64(int const *b, __m128i c) {
+__m128i test_mm_i64gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.q.q
return _mm_i64gather_epi64(b, c, 2);
}
-__m256i test_mm256_i64gather_epi64(int const *b, __m256i c) {
+__m256i test_mm256_i64gather_epi64(long long const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.q.256
return _mm256_i64gather_epi64(b, c, 2);
}
diff --git a/test/CodeGen/big-atomic-ops.c b/test/CodeGen/big-atomic-ops.c
new file mode 100644
index 000000000000..b09aededcdea
--- /dev/null
+++ b/test/CodeGen/big-atomic-ops.c
@@ -0,0 +1,323 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-macosx10.9.0 | FileCheck %s
+
+// Also test serialization of atomic operations here, to avoid duplicating the
+// test.
+// RUN: %clang_cc1 %s -emit-pch -o %t -triple=x86_64-apple-macosx10.9.0
+// RUN: %clang_cc1 %s -include-pch %t -triple=x86_64-apple-macosx10.9.0 -emit-llvm -o - | FileCheck %s
+#ifndef ALREADY_INCLUDED
+#define ALREADY_INCLUDED
+
+// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
+
+typedef enum memory_order {
+ memory_order_relaxed, memory_order_consume, memory_order_acquire,
+ memory_order_release, memory_order_acq_rel, memory_order_seq_cst
+} memory_order;
+
+int fi1(_Atomic(int) *i) {
+ // CHECK: @fi1
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return __c11_atomic_load(i, memory_order_seq_cst);
+}
+
+int fi1a(int *i) {
+ // CHECK: @fi1a
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ int v;
+ __atomic_load(i, &v, memory_order_seq_cst);
+ return v;
+}
+
+int fi1b(int *i) {
+ // CHECK: @fi1b
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return __atomic_load_n(i, memory_order_seq_cst);
+}
+
+void fi2(_Atomic(int) *i) {
+ // CHECK: @fi2
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ __c11_atomic_store(i, 1, memory_order_seq_cst);
+}
+
+void fi2a(int *i) {
+ // CHECK: @fi2a
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ int v = 1;
+ __atomic_store(i, &v, memory_order_seq_cst);
+}
+
+void fi2b(int *i) {
+ // CHECK: @fi2b
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ __atomic_store_n(i, 1, memory_order_seq_cst);
+}
+
+int fi3(_Atomic(int) *i) {
+ // CHECK: @fi3
+ // CHECK: atomicrmw and
+ // CHECK-NOT: and
+ return __c11_atomic_fetch_and(i, 1, memory_order_seq_cst);
+}
+
+int fi3a(int *i) {
+ // CHECK: @fi3a
+ // CHECK: atomicrmw xor
+ // CHECK-NOT: xor
+ return __atomic_fetch_xor(i, 1, memory_order_seq_cst);
+}
+
+int fi3b(int *i) {
+ // CHECK: @fi3b
+ // CHECK: atomicrmw add
+ // CHECK: add
+ return __atomic_add_fetch(i, 1, memory_order_seq_cst);
+}
+
+int fi3c(int *i) {
+ // CHECK: @fi3c
+ // CHECK: atomicrmw nand
+ // CHECK-NOT: and
+ return __atomic_fetch_nand(i, 1, memory_order_seq_cst);
+}
+
+int fi3d(int *i) {
+ // CHECK: @fi3d
+ // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ return __atomic_nand_fetch(i, 1, memory_order_seq_cst);
+}
+
+_Bool fi4(_Atomic(int) *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ return __c11_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire);
+}
+
+_Bool fi4a(int *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ int desired = 1;
+ return __atomic_compare_exchange(i, &cmp, &desired, 0, memory_order_acquire, memory_order_acquire);
+}
+
+_Bool fi4b(int *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire, memory_order_acquire);
+}
+
+float ff1(_Atomic(float) *d) {
+ // CHECK: @ff1
+ // CHECK: load atomic i32* {{.*}} monotonic
+ return __c11_atomic_load(d, memory_order_relaxed);
+}
+
+void ff2(_Atomic(float) *d) {
+ // CHECK: @ff2
+ // CHECK: store atomic i32 {{.*}} release
+ __c11_atomic_store(d, 1, memory_order_release);
+}
+
+float ff3(_Atomic(float) *d) {
+ return __c11_atomic_exchange(d, 2, memory_order_seq_cst);
+}
+
+int* fp1(_Atomic(int*) *p) {
+ // CHECK: @fp1
+ // CHECK: load atomic i64* {{.*}} seq_cst
+ return __c11_atomic_load(p, memory_order_seq_cst);
+}
+
+int* fp2(_Atomic(int*) *p) {
+ // CHECK: @fp2
+ // CHECK: store i64 4
+ // CHECK: atomicrmw add {{.*}} monotonic
+ return __c11_atomic_fetch_add(p, 1, memory_order_relaxed);
+}
+
+int *fp2a(int **p) {
+ // CHECK: @fp2a
+ // CHECK: store i64 4
+ // CHECK: atomicrmw sub {{.*}} monotonic
+ // Note, the GNU builtins do not multiply by sizeof(T)!
+ return __atomic_fetch_sub(p, 4, memory_order_relaxed);
+}
+
+_Complex float fc(_Atomic(_Complex float) *c) {
+ // CHECK: @fc
+ // CHECK: atomicrmw xchg i64*
+ return __c11_atomic_exchange(c, 2, memory_order_seq_cst);
+}
+
+typedef struct X { int x; } X;
+X fs(_Atomic(X) *c) {
+ // CHECK: @fs
+ // CHECK: atomicrmw xchg i32*
+ return __c11_atomic_exchange(c, (X){2}, memory_order_seq_cst);
+}
+
+X fsa(X *c, X *d) {
+ // CHECK: @fsa
+ // CHECK: atomicrmw xchg i32*
+ X ret;
+ __atomic_exchange(c, d, &ret, memory_order_seq_cst);
+ return ret;
+}
+
+_Bool fsb(_Bool *c) {
+ // CHECK: @fsb
+ // CHECK: atomicrmw xchg i8*
+ return __atomic_exchange_n(c, 1, memory_order_seq_cst);
+}
+
+char flag1;
+volatile char flag2;
+void test_and_set() {
+ // CHECK: atomicrmw xchg i8* @flag1, i8 1 seq_cst
+ __atomic_test_and_set(&flag1, memory_order_seq_cst);
+ // CHECK: atomicrmw volatile xchg i8* @flag2, i8 1 acquire
+ __atomic_test_and_set(&flag2, memory_order_acquire);
+ // CHECK: store atomic volatile i8 0, i8* @flag2 release
+ __atomic_clear(&flag2, memory_order_release);
+ // CHECK: store atomic i8 0, i8* @flag1 seq_cst
+ __atomic_clear(&flag1, memory_order_seq_cst);
+}
+
+struct Sixteen {
+ char c[16];
+} sixteen;
+struct Seventeen {
+ char c[17];
+} seventeen;
+
+int lock_free(struct Incomplete *incomplete) {
+ // CHECK: @lock_free
+
+ // CHECK: call i32 @__atomic_is_lock_free(i64 3, i8* null)
+ __c11_atomic_is_lock_free(3);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i64 16, i8* {{.*}}@sixteen{{.*}})
+ __atomic_is_lock_free(16, &sixteen);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i64 17, i8* {{.*}}@seventeen{{.*}})
+ __atomic_is_lock_free(17, &seventeen);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i64 4, {{.*}})
+ __atomic_is_lock_free(4, incomplete);
+
+ char cs[20];
+ // CHECK: call i32 @__atomic_is_lock_free(i64 4, {{.*}})
+ __atomic_is_lock_free(4, cs+1);
+
+ // CHECK-NOT: call
+ __atomic_always_lock_free(3, 0);
+ __atomic_always_lock_free(16, 0);
+ __atomic_always_lock_free(17, 0);
+ __atomic_always_lock_free(16, &sixteen);
+ __atomic_always_lock_free(17, &seventeen);
+
+ int n;
+ __atomic_is_lock_free(4, &n);
+
+ // CHECK: ret i32 1
+ return __c11_atomic_is_lock_free(sizeof(_Atomic(int)));
+}
+
+// Tests for atomic operations on big values. These should call the functions
+// defined here:
+// http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary#The_Library_interface
+
+struct foo {
+ int big[128];
+};
+struct bar {
+ char c[3];
+};
+
+struct bar smallThing, thing1, thing2;
+struct foo bigThing;
+_Atomic(struct foo) bigAtomic;
+
+void structAtomicStore() {
+ // CHECK: @structAtomicStore
+ struct foo f = {0};
+ __c11_atomic_store(&bigAtomic, f, 5);
+ // CHECK: call void @__atomic_store(i64 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+
+ struct bar b = {0};
+ __atomic_store(&smallThing, &b, 5);
+ // CHECK: call void @__atomic_store(i64 3, i8* {{.*}} @smallThing
+
+ __atomic_store(&bigThing, &f, 5);
+ // CHECK: call void @__atomic_store(i64 512, i8* {{.*}} @bigThing
+}
+void structAtomicLoad() {
+ // CHECK: @structAtomicLoad
+ struct foo f = __c11_atomic_load(&bigAtomic, 5);
+ // CHECK: call void @__atomic_load(i64 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+
+ struct bar b;
+ __atomic_load(&smallThing, &b, 5);
+ // CHECK: call void @__atomic_load(i64 3, i8* {{.*}} @smallThing
+
+ __atomic_load(&bigThing, &f, 5);
+ // CHECK: call void @__atomic_load(i64 512, i8* {{.*}} @bigThing
+}
+struct foo structAtomicExchange() {
+ // CHECK: @structAtomicExchange
+ struct foo f = {0};
+ struct foo old;
+ __atomic_exchange(&f, &bigThing, &old, 5);
+ // CHECK: call void @__atomic_exchange(i64 512, {{.*}}, i8* bitcast ({{.*}} @bigThing to i8*),
+
+ return __c11_atomic_exchange(&bigAtomic, f, 5);
+ // CHECK: call void @__atomic_exchange(i64 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+}
+int structAtomicCmpExchange() {
+ // CHECK: @structAtomicCmpExchange
+ _Bool x = __atomic_compare_exchange(&smallThing, &thing1, &thing2, 1, 5, 5);
+ // CHECK: call zeroext i1 @__atomic_compare_exchange(i64 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+
+ struct foo f = {0};
+ struct foo g = {0};
+ g.big[12] = 12;
+ return x & __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5);
+ // CHECK: call zeroext i1 @__atomic_compare_exchange(i64 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+}
+
+// Check that no atomic operations are used in any initialisation of _Atomic
+// types.
+_Atomic(int) atomic_init_i = 42;
+
+// CHECK: @atomic_init_foo
+void atomic_init_foo()
+{
+ // CHECK-NOT: }
+ // CHECK-NOT: atomic
+ // CHECK: store
+ _Atomic(int) j = 12;
+
+ // CHECK-NOT: }
+ // CHECK-NOT: atomic
+ // CHECK: store
+ __c11_atomic_init(&j, 42);
+
+ // CHECK-NOT: atomic
+ // CHECK: }
+}
+
+// CHECK: @invalid_atomic
+void invalid_atomic(_Atomic(int) *i) {
+ __c11_atomic_store(i, 1, memory_order_consume);
+ __c11_atomic_store(i, 1, memory_order_acquire);
+ __c11_atomic_store(i, 1, memory_order_acq_rel);
+ __c11_atomic_load(i, memory_order_release);
+ __c11_atomic_load(i, memory_order_acq_rel);
+}
+
+#endif
diff --git a/test/CodeGen/bitfield-2.c b/test/CodeGen/bitfield-2.c
index bec55ffa7512..58b17f17f02a 100644
--- a/test/CodeGen/bitfield-2.c
+++ b/test/CodeGen/bitfield-2.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -O3 -o %t.opt.ll %s \
-// RUN: -fdump-record-layouts 2> %t.dump.txt
+// RUN: -fdump-record-layouts > %t.dump.txt
// RUN: FileCheck -check-prefix=CHECK-RECORD < %t.dump.txt %s
// RUN: FileCheck -check-prefix=CHECK-OPT < %t.opt.ll %s
@@ -32,7 +32,7 @@ int f0_reload(struct s0 *a0) {
return (a0->f0 += 1);
}
-// CHECK-OPT: define i64 @test_0()
+// CHECK-OPT-LABEL: define i64 @test_0()
// CHECK-OPT: ret i64 1
// CHECK-OPT: }
unsigned long long test_0() {
@@ -78,7 +78,7 @@ int f1_reload(struct s1 *a0) {
return (a0->f1 += 1234);
}
-// CHECK-OPT: define i64 @test_1()
+// CHECK-OPT-LABEL: define i64 @test_1()
// CHECK-OPT: ret i64 210
// CHECK-OPT: }
unsigned long long test_1() {
@@ -120,7 +120,7 @@ int f2_reload(union u2 *a0) {
return (a0->f0 += 1234);
}
-// CHECK-OPT: define i64 @test_2()
+// CHECK-OPT-LABEL: define i64 @test_2()
// CHECK-OPT: ret i64 2
// CHECK-OPT: }
unsigned long long test_2() {
@@ -156,7 +156,7 @@ int f3_reload(struct s3 *a0) {
return (a0->f0 += 1234);
}
-// CHECK-OPT: define i64 @test_3()
+// CHECK-OPT-LABEL: define i64 @test_3()
// CHECK-OPT: ret i64 -559039940
// CHECK-OPT: }
unsigned long long test_3() {
@@ -190,7 +190,7 @@ int f4_reload(struct s4 *a0) {
return (a0->f0 += 1234) ^ (a0->f1 += 5678);
}
-// CHECK-OPT: define i64 @test_4()
+// CHECK-OPT-LABEL: define i64 @test_4()
// CHECK-OPT: ret i64 4860
// CHECK-OPT: }
unsigned long long test_4() {
@@ -222,7 +222,7 @@ int f5_reload(struct s5 *a0) {
return (a0->f0 += 0xF) ^ (a0->f1 += 0xF) ^ (a0->f2 += 0xF);
}
-// CHECK-OPT: define i64 @test_5()
+// CHECK-OPT-LABEL: define i64 @test_5()
// CHECK-OPT: ret i64 2
// CHECK-OPT: }
unsigned long long test_5() {
@@ -252,7 +252,7 @@ int f6_reload(struct s6 *a0) {
return (a0->f0 += 0xF);
}
-// CHECK-OPT: define zeroext i1 @test_6()
+// CHECK-OPT-LABEL: define zeroext i1 @test_6()
// CHECK-OPT: ret i1 true
// CHECK-OPT: }
_Bool test_6() {
@@ -310,7 +310,7 @@ int f8_reload(struct s8 *a0) {
return (a0->f0 += 0xFD) ^ (a0->f2 += 0xFD) ^ (a0->f3 += 0xFD);
}
-// CHECK-OPT: define i32 @test_8()
+// CHECK-OPT-LABEL: define i32 @test_8()
// CHECK-OPT: ret i32 -3
// CHECK-OPT: }
unsigned test_8() {
diff --git a/test/CodeGen/bitfield-assign.c b/test/CodeGen/bitfield-assign.c
index b8ab61339cf6..270f44de52f3 100644
--- a/test/CodeGen/bitfield-assign.c
+++ b/test/CodeGen/bitfield-assign.c
@@ -4,14 +4,14 @@
/* Check that we get one load for each simple assign and two for the
compound assign (load the old value before the add then load again
to store back). Also check that our g0 pattern is good. */
-// RUN: %clang_cc1 -triple i386-unknown-unknown -O0 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o %t %s
// RUN: grep 'load ' %t | count 5
// RUN: grep "@g0" %t | count 4
// Check that we got the right value.
// RUN: %clang_cc1 -triple i386-unknown-unknown -O3 -emit-llvm -o %t %s
-// RUN: grep 'load ' %t | count 0
-// RUN: grep "@g0" %t | count 0
+// RUN: not grep 'load ' %t
+// RUN: not grep "@g0" %t
struct s0 {
int f0 : 2;
diff --git a/test/CodeGen/bitfield.c b/test/CodeGen/bitfield.c
index dea5e43e0f1c..c624d0045d33 100644
--- a/test/CodeGen/bitfield.c
+++ b/test/CodeGen/bitfield.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o %t -O3
-// RUN: grep "ret i32" %t | count 4
-// RUN: grep "ret i32 1" %t | count 4
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - -O3 -no-struct-path-tbaa | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - -O3 | FileCheck %s --check-prefix=PATH
static int f0(int n) {
struct s0 {
@@ -17,6 +16,10 @@ static int f0(int n) {
}
int g0(void) {
+// CHECK-LABEL: @g0()
+// CHECK: ret i32 1
+// PATH-LABEL: @g0()
+// PATH: ret i32 1
return f0(-1) + 44335655;
}
@@ -35,6 +38,10 @@ static int f1(void) {
}
int g1(void) {
+// CHECK-LABEL: @g1()
+// CHECK: ret i32 1
+// PATH-LABEL: @g1()
+// PATH: ret i32 1
return f1() + 16;
}
@@ -51,6 +58,10 @@ static int f2(void) {
}
int g2(void) {
+// CHECK-LABEL: @g2()
+// CHECK: ret i32 1
+// PATH-LABEL: @g2()
+// PATH: ret i32 1
return f2() - 9;
}
@@ -70,5 +81,9 @@ static int f3(int n) {
}
int g3(void) {
+// CHECK-LABEL: @g3()
+// CHECK: ret i32 1
+// PATH-LABEL: @g3()
+// PATH: ret i32 1
return f3(20) + 130725747;
}
diff --git a/test/CodeGen/block-byref-aggr.c b/test/CodeGen/block-byref-aggr.c
index eb342b856e4f..eed023956cd3 100644
--- a/test/CodeGen/block-byref-aggr.c
+++ b/test/CodeGen/block-byref-aggr.c
@@ -12,7 +12,7 @@ void test0() {
a = makeAgg();
}
-// CHECK: define void @test0()
+// CHECK-LABEL: define void @test0()
// CHECK: [[A:%.*]] = alloca [[BYREF:%.*]], align 8
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
// CHECK: [[RESULT:%.*]] = call i32 @makeAgg()
@@ -37,7 +37,7 @@ void test1() {
__block Agg a, b;
a = b = makeAgg();
}
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
// CHECK: [[A:%.*]] = alloca [[A_BYREF:%.*]], align 8
// CHECK-NEXT: [[B:%.*]] = alloca [[B_BYREF:%.*]], align 8
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
diff --git a/test/CodeGen/blocks-2.c b/test/CodeGen/blocks-2.c
deleted file mode 100644
index 4e574dafec52..000000000000
--- a/test/CodeGen/blocks-2.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// RUN: %clang_cc1 -g %s -emit-llvm -o %t -fblocks
-// RUN: grep "func.start" %t | count 4
-// RUN: %clang_cc1 -g %s -triple i386-unknown-unknown -emit-llvm -o %t -fblocks -fblock-introspection
-// RUN: grep "v8@?0i4" %t | count 1
-// RUN: %clang_cc1 -g %s -triple i386-unknown-unknown -emit-llvm -o %t -fblocks
-// RUN: grep "v8@?0i4" %t | count 0
-// 1 declaration, 1 bar, 1 test_block_dbg and 1 for the block.
-// XFAIL: *
-
-static __inline__ __attribute__((always_inline)) int bar(int va, int vb) { return (va == vb); }
-
-int test_block_dbg() {
- extern int g;
- static int i = 1;
- ^(int j){ i = bar(3,4); }(0);
- return i + g;
-}
-
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
index 71f7171c7181..5871e8c2429c 100644
--- a/test/CodeGen/blocks.c
+++ b/test/CodeGen/blocks.c
@@ -45,7 +45,7 @@ void f3() {
// The bool can fill in between the header and the long long.
// Add the appropriate amount of padding between them.
void f4_helper(long long (^)(void));
-// CHECK: define void @f4()
+// CHECK-LABEL: define void @f4()
void f4(void) {
_Bool b = 0;
long long ll = 0;
@@ -60,9 +60,21 @@ struct F5 {
char buffer[32] __attribute((aligned));
};
void f5_helper(void (^)(struct F5 *));
-// CHECK: define void @f5()
+// CHECK-LABEL: define void @f5()
void f5(void) {
struct F5 value;
// CHECK: alloca <{ i8*, i32, i32, i8*, {{%.*}}*, [12 x i8], [[F5:%.*]] }>, align 16
f5_helper(^(struct F5 *slot) { *slot = value; });
}
+
+// rdar://14085217
+void (^b)() = ^{};
+int main() {
+ (b?: ^{})();
+}
+// CHECK: [[ZERO:%.*]] = load void (...)** @b
+// CHECK-NEXT: [[TB:%.*]] = icmp ne void (...)* [[ZERO]], null
+// CHECK-NEXT: br i1 [[TB]], label [[CT:%.*]], label [[CF:%.*]]
+// CHECK: [[ONE:%.*]] = bitcast void (...)* [[ZERO]] to void ()*
+// CHECK-NEXT: br label [[CE:%.*]]
+
diff --git a/test/CodeGen/bool_test.c b/test/CodeGen/bool_test.c
index 83d833077151..a4aa669f16c3 100644
--- a/test/CodeGen/bool_test.c
+++ b/test/CodeGen/bool_test.c
@@ -8,7 +8,7 @@ void f(_Bool *x, _Bool *y) {
*x = *y;
}
-// CHECK: define void @f(
+// CHECK-LABEL: define void @f(
// CHECK: [[FROMMEM:%.*]] = load i32* %
// CHECK: [[BOOLVAL:%.*]] = trunc i32 [[FROMMEM]] to i1
// CHECK: [[TOMEM:%.*]] = zext i1 [[BOOLVAL]] to i32
diff --git a/test/CodeGen/bounds-checking.c b/test/CodeGen/bounds-checking.c
index fa7541f8141e..d93cd3ede7d6 100644
--- a/test/CodeGen/bounds-checking.c
+++ b/test/CodeGen/bounds-checking.c
@@ -1,26 +1,29 @@
-// RUN: %clang_cc1 -fsanitize=bounds -emit-llvm -triple x86_64-apple-darwin10 < %s | FileCheck %s
+// RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-undefined-trap-on-error -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s
-// CHECK: @f
+// CHECK-LABEL: @f
double f(int b, int i) {
double a[b];
- // CHECK: trap
+ // CHECK: call {{.*}} @llvm.trap
return a[i];
}
-// CHECK: @f2
+// CHECK-LABEL: @f2
void f2() {
// everything is constant; no trap possible
- // CHECK-NOT: trap
+ // CHECK-NOT: call {{.*}} @llvm.trap
int a[2];
a[1] = 42;
-
+
+#ifndef NO_DYNAMIC
short *b = malloc(64);
b[5] = *a + a[1] + 2;
+#endif
}
-// CHECK: @f3
+// CHECK-LABEL: @f3
void f3() {
int a[1];
- // CHECK: trap
+ // CHECK: call {{.*}} @llvm.trap
a[2] = 1;
}
diff --git a/test/CodeGen/branch-on-bool.c b/test/CodeGen/branch-on-bool.c
new file mode 100644
index 000000000000..78dae1b1fd78
--- /dev/null
+++ b/test/CodeGen/branch-on-bool.c
@@ -0,0 +1,22 @@
+// RUN: %clang %s -O0 -emit-llvm -S -o - | FileCheck %s
+
+void foo();
+void bar();
+
+void fold_if(int a, int b) {
+ // CHECK: define {{.*}} @fold_if(
+ // CHECK-NOT: = phi
+ // CHECK: }
+ if (a && b)
+ foo();
+ else
+ bar();
+}
+
+void fold_for(int a, int b) {
+ // CHECK: define {{.*}} @fold_for(
+ // CHECK-NOT: = phi
+ // CHECK: }
+ for (int i = 0; a && i < b; ++i) foo();
+ for (int i = 0; a || i < b; ++i) bar();
+}
diff --git a/test/CodeGen/builtin-ms-noop.cpp b/test/CodeGen/builtin-ms-noop.cpp
index 42c25016b138..7c5068dd61b0 100644
--- a/test/CodeGen/builtin-ms-noop.cpp
+++ b/test/CodeGen/builtin-ms-noop.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-win32 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions -triple i686-pc-win32 -emit-llvm %s -o - | FileCheck %s
class A {
public:
diff --git a/test/CodeGen/builtins-arm-exclusive.c b/test/CodeGen/builtins-arm-exclusive.c
new file mode 100644
index 000000000000..7eccb9e27bb5
--- /dev/null
+++ b/test/CodeGen/builtins-arm-exclusive.c
@@ -0,0 +1,112 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -Wall -Werror -triple thumbv7-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s
+
+// Make sure the canonical use works before going into smaller details:
+int atomic_inc(int *addr) {
+ int Failure, OldVal;
+ do {
+ OldVal = __builtin_arm_ldrex(addr);
+ Failure = __builtin_arm_strex(OldVal + 1, addr);
+ } while (Failure);
+
+ return OldVal;
+}
+
+// CHECK: @atomic_inc
+// CHECK: [[OLDVAL:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* %addr)
+// CHECK: [[INC:%.*]] = add nsw i32 [[OLDVAL]], 1
+// CHECK: [[FAILURE:%.*]] = tail call i32 @llvm.arm.strex.p0i32(i32 [[INC]], i32* %addr)
+// CHECK: [[TST:%.*]] = icmp eq i32 [[FAILURE]], 0
+// CHECK: br i1 [[TST]], label {{%[a-zA-Z0-9.]+}}, label {{%[a-zA-Z0-9.]+}}
+
+struct Simple {
+ char a, b;
+};
+
+int test_ldrex(char *addr, long long *addr64, float *addrfloat) {
+// CHECK: @test_ldrex
+ int sum = 0;
+ sum += __builtin_arm_ldrex(addr);
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
+// CHECK: and i32 [[INTRES]], 255
+
+ sum += __builtin_arm_ldrex((short *)addr);
+// CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i16(i16* [[ADDR16]])
+// CHECK: [[TMPSEXT:%.*]] = shl i32 [[INTRES]], 16
+// CHECK: ashr exact i32 [[TMPSEXT]], 16
+
+ sum += __builtin_arm_ldrex((int *)addr);
+// CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK: call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
+
+ sum += __builtin_arm_ldrex((long long *)addr);
+// CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* %addr)
+
+ sum += __builtin_arm_ldrex(addr64);
+// CHECK: [[ADDR64_AS8:%.*]] = bitcast i64* %addr64 to i8*
+// CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* [[ADDR64_AS8]])
+
+ sum += __builtin_arm_ldrex(addrfloat);
+// CHECK: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[INTADDR]])
+// CHECK: bitcast i32 [[INTRES]] to float
+
+ sum += __builtin_arm_ldrex((double *)addr);
+// CHECK: [[STRUCTRES:%.*]] = tail call { i32, i32 } @llvm.arm.ldrexd(i8* %addr)
+// CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
+// CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
+// CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
+// CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
+// CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
+// CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
+// CHECK: bitcast i64 [[INTRES]] to double
+
+ sum += *__builtin_arm_ldrex((int **)addr);
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
+// CHECK: inttoptr i32 [[INTRES]] to i32*
+
+ sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
+// CHECK: inttoptr i32 [[INTRES]] to %struct.Simple*
+
+ return sum;
+}
+
+int test_strex(char *addr) {
+// CHECK: @test_strex
+ int res = 0;
+ struct Simple var = {0};
+ res |= __builtin_arm_strex(4, addr);
+// CHECK: call i32 @llvm.arm.strex.p0i8(i32 4, i8* %addr)
+
+ res |= __builtin_arm_strex(42, (short *)addr);
+// CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK: call i32 @llvm.arm.strex.p0i16(i32 42, i16* [[ADDR16]])
+
+ res |= __builtin_arm_strex(42, (int *)addr);
+// CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK: call i32 @llvm.arm.strex.p0i32(i32 42, i32* [[ADDR32]])
+
+ res |= __builtin_arm_strex(42, (long long *)addr);
+// CHECK: call i32 @llvm.arm.strexd(i32 42, i32 0, i8* %addr)
+
+ res |= __builtin_arm_strex(2.71828f, (float *)addr);
+// CHECK: call i32 @llvm.arm.strex.p0i32(i32 1076754509, i32* [[ADDR32]])
+
+ res |= __builtin_arm_strex(3.14159, (double *)addr);
+// CHECK: call i32 @llvm.arm.strexd(i32 -266631570, i32 1074340345, i8* %addr)
+
+ res |= __builtin_arm_strex(&var, (struct Simple **)addr);
+// CHECK: [[INTVAL:%.*]] = ptrtoint i16* %var to i32
+// CHECK: call i32 @llvm.arm.strex.p0i32(i32 [[INTVAL]], i32* [[ADDR32]])
+
+ return res;
+}
+
+void test_clrex() {
+// CHECK: @test_clrex
+
+ __builtin_arm_clrex();
+// CHECK: call void @llvm.arm.clrex()
+}
diff --git a/test/CodeGen/builtins-arm.c b/test/CodeGen/builtins-arm.c
index e6c7cede1fdc..937e1d962594 100644
--- a/test/CodeGen/builtins-arm.c
+++ b/test/CodeGen/builtins-arm.c
@@ -18,3 +18,13 @@ void test_eh_return_data_regno()
res = __builtin_eh_return_data_regno(0); // CHECK: store volatile i32 0
res = __builtin_eh_return_data_regno(1); // CHECK: store volatile i32 1
}
+
+void sevl() {
+ __builtin_arm_sevl();
+}
+// CHECK: call {{.*}} @llvm.arm.sevl
+
+void test_barrier() {
+ __builtin_arm_dmb(1); //CHECK: call {{.*}} @llvm.arm.dmb(i32 1)
+ __builtin_arm_dsb(2); //CHECK: call {{.*}} @llvm.arm.dsb(i32 2)
+}
diff --git a/test/CodeGen/builtins-mips-msa.c b/test/CodeGen/builtins-mips-msa.c
new file mode 100644
index 000000000000..69cb8e22a194
--- /dev/null
+++ b/test/CodeGen/builtins-mips-msa.c
@@ -0,0 +1,829 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang_cc1 -triple mips-unknown-linux-gnu -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+typedef signed char v16i8 __attribute__ ((vector_size(16)));
+typedef signed short v8i16 __attribute__ ((vector_size(16)));
+typedef signed int v4i32 __attribute__ ((vector_size(16)));
+typedef signed long long v2i64 __attribute__ ((vector_size(16)));
+typedef unsigned char v16u8 __attribute__ ((vector_size(16)));
+typedef unsigned short v8u16 __attribute__ ((vector_size(16)));
+typedef unsigned int v4u32 __attribute__ ((vector_size(16)));
+typedef unsigned long long v2u64 __attribute__ ((vector_size(16)));
+typedef __fp16 v8f16 __attribute__ ((vector_size(16)));
+typedef float v4f32 __attribute__ ((vector_size(16)));
+typedef double v2f64 __attribute__ ((vector_size(16)));
+
+void test(void) {
+ v16i8 v16i8_a = (v16i8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ v16i8 v16i8_b = (v16i8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ v16i8 v16i8_r;
+ v8i16 v8i16_a = (v8i16) {0, 1, 2, 3, 4, 5, 6, 7};
+ v8i16 v8i16_b = (v8i16) {1, 2, 3, 4, 5, 6, 7, 8};
+ v8i16 v8i16_r;
+ v4i32 v4i32_a = (v4i32) {0, 1, 2, 3};
+ v4i32 v4i32_b = (v4i32) {1, 2, 3, 4};
+ v4i32 v4i32_r;
+ v2i64 v2i64_a = (v2i64) {0, 1};
+ v2i64 v2i64_b = (v2i64) {1, 2};
+ v2i64 v2i64_r;
+
+ v16u8 v16u8_a = (v16u8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ v16u8 v16u8_b = (v16u8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ v16u8 v16u8_r;
+ v8u16 v8u16_a = (v8u16) {0, 1, 2, 3, 4, 5, 6, 7};
+ v8u16 v8u16_b = (v8u16) {1, 2, 3, 4, 5, 6, 7, 8};
+ v8u16 v8u16_r;
+ v4u32 v4u32_a = (v4u32) {0, 1, 2, 3};
+ v4u32 v4u32_b = (v4u32) {1, 2, 3, 4};
+ v4u32 v4u32_r;
+ v2u64 v2u64_a = (v2u64) {0, 1};
+ v2u64 v2u64_b = (v2u64) {1, 2};
+ v2u64 v2u64_r;
+
+ v8f16 v8f16_a = (v8f16) {0.5, 1, 2, 3, 4, 5, 6, 7};
+ v8f16 v8f16_b = (v8f16) {1.5, 2, 3, 4, 5, 6, 7, 8};
+ v8f16 v8f16_r;
+ v4f32 v4f32_a = (v4f32) {0.5, 1, 2, 3};
+ v4f32 v4f32_b = (v4f32) {1.5, 2, 3, 4};
+ v4f32 v4f32_r;
+ v2f64 v2f64_a = (v2f64) {0.5, 1};
+ v2f64 v2f64_b = (v2f64) {1.5, 2};
+ v2f64 v2f64_r;
+
+ int int_r;
+ long long ll_r;
+ int int_a = 0;
+
+ v16i8_r = __builtin_msa_add_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.add.a.b(
+ v8i16_r = __builtin_msa_add_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.add.a.h(
+ v4i32_r = __builtin_msa_add_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.add.a.w(
+ v2i64_r = __builtin_msa_add_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.add.a.d(
+
+ v16i8_r = __builtin_msa_adds_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.a.b(
+ v8i16_r = __builtin_msa_adds_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.a.h(
+ v4i32_r = __builtin_msa_adds_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.a.w(
+ v2i64_r = __builtin_msa_adds_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.a.d(
+
+ v16i8_r = __builtin_msa_adds_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.s.b(
+ v8i16_r = __builtin_msa_adds_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.s.h(
+ v4i32_r = __builtin_msa_adds_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.s.w(
+ v2i64_r = __builtin_msa_adds_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.s.d(
+
+ v16u8_r = __builtin_msa_adds_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.adds.u.b(
+ v8u16_r = __builtin_msa_adds_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.adds.u.h(
+ v4u32_r = __builtin_msa_adds_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.adds.u.w(
+ v2u64_r = __builtin_msa_adds_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.adds.u.d(
+
+ v16i8_r = __builtin_msa_addv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b(
+ v8i16_r = __builtin_msa_addv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h(
+ v4i32_r = __builtin_msa_addv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w(
+ v2i64_r = __builtin_msa_addv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d(
+
+ v16u8_r = __builtin_msa_addv_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b(
+ v8u16_r = __builtin_msa_addv_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h(
+ v4u32_r = __builtin_msa_addv_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w(
+ v2u64_r = __builtin_msa_addv_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d(
+
+ v16i8_r = __builtin_msa_addvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b(
+ v8i16_r = __builtin_msa_addvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h(
+ v4i32_r = __builtin_msa_addvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w(
+ v2i64_r = __builtin_msa_addvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d(
+
+ v16u8_r = __builtin_msa_addvi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b(
+ v8u16_r = __builtin_msa_addvi_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h(
+ v4u32_r = __builtin_msa_addvi_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w(
+ v2u64_r = __builtin_msa_addvi_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d(
+
+ v16i8_r = __builtin_msa_and_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.and.v(
+ v8i16_r = __builtin_msa_and_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.and.v(
+ v4i32_r = __builtin_msa_and_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.and.v(
+ v2i64_r = __builtin_msa_and_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.and.v(
+
+ v16i8_r = __builtin_msa_andi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v8i16_r = __builtin_msa_andi_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v4i32_r = __builtin_msa_andi_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v2i64_r = __builtin_msa_andi_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+
+ v16u8_r = __builtin_msa_andi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v8u16_r = __builtin_msa_andi_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v4u32_r = __builtin_msa_andi_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+ v2u64_r = __builtin_msa_andi_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b(
+
+ v16i8_r = __builtin_msa_asub_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.asub.s.b(
+ v8i16_r = __builtin_msa_asub_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.asub.s.h(
+ v4i32_r = __builtin_msa_asub_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.asub.s.w(
+ v2i64_r = __builtin_msa_asub_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.asub.s.d(
+
+ v16u8_r = __builtin_msa_asub_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.asub.u.b(
+ v8u16_r = __builtin_msa_asub_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.asub.u.h(
+ v4u32_r = __builtin_msa_asub_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.asub.u.w(
+ v2u64_r = __builtin_msa_asub_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.asub.u.d(
+
+ v16i8_r = __builtin_msa_ave_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ave.s.b(
+ v8i16_r = __builtin_msa_ave_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ave.s.h(
+ v4i32_r = __builtin_msa_ave_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ave.s.w(
+ v2i64_r = __builtin_msa_ave_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ave.s.d(
+
+ v16u8_r = __builtin_msa_ave_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.ave.u.b(
+ v8u16_r = __builtin_msa_ave_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.ave.u.h(
+ v4u32_r = __builtin_msa_ave_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.ave.u.w(
+ v2u64_r = __builtin_msa_ave_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.ave.u.d(
+
+ v16i8_r = __builtin_msa_aver_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.aver.s.b(
+ v8i16_r = __builtin_msa_aver_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.aver.s.h(
+ v4i32_r = __builtin_msa_aver_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.aver.s.w(
+ v2i64_r = __builtin_msa_aver_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.aver.s.d(
+
+ v16u8_r = __builtin_msa_aver_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.aver.u.b(
+ v8u16_r = __builtin_msa_aver_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.aver.u.h(
+ v4u32_r = __builtin_msa_aver_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.aver.u.w(
+ v2u64_r = __builtin_msa_aver_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.aver.u.d(
+
+ v16i8_r = __builtin_msa_bclr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bclr.b(
+ v8i16_r = __builtin_msa_bclr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bclr.h(
+ v4i32_r = __builtin_msa_bclr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bclr.w(
+ v2i64_r = __builtin_msa_bclr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bclr.d(
+
+ v16i8_r = __builtin_msa_bclri_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bclri.b(
+ v8i16_r = __builtin_msa_bclri_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bclri.h(
+ v4i32_r = __builtin_msa_bclri_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bclri.w(
+ v2i64_r = __builtin_msa_bclri_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bclri.d(
+
+ v16i8_r = __builtin_msa_binsl_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsl.b(
+ v8i16_r = __builtin_msa_binsl_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsl.h(
+ v4i32_r = __builtin_msa_binsl_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsl.w(
+ v2i64_r = __builtin_msa_binsl_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsl.d(
+
+ v16i8_r = __builtin_msa_binsli_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.binsli.b(
+ v8i16_r = __builtin_msa_binsli_h(v8i16_r, v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.binsli.h(
+ v4i32_r = __builtin_msa_binsli_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsli.w(
+ v2i64_r = __builtin_msa_binsli_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsli.d(
+
+ v16i8_r = __builtin_msa_binsr_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsr.b(
+ v8i16_r = __builtin_msa_binsr_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsr.h(
+ v4i32_r = __builtin_msa_binsr_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsr.w(
+ v2i64_r = __builtin_msa_binsr_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsr.d(
+
+ v16i8_r = __builtin_msa_binsri_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.binsri.b(
+ v8i16_r = __builtin_msa_binsri_h(v8i16_r, v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.binsri.h(
+ v4i32_r = __builtin_msa_binsri_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsri.w(
+ v2i64_r = __builtin_msa_binsri_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsri.d(
+
+ v16i8_r = __builtin_msa_bmnz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v(
+ v8i16_r = __builtin_msa_bmnz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v(
+ v4i32_r = __builtin_msa_bmnz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v(
+ v2i64_r = __builtin_msa_bmnz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v(
+
+ v16i8_r = __builtin_msa_bmnzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmnzi.b(
+
+ v16i8_r = __builtin_msa_bmz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v(
+ v8i16_r = __builtin_msa_bmz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v(
+ v4i32_r = __builtin_msa_bmz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v(
+ v2i64_r = __builtin_msa_bmz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v(
+
+ v16i8_r = __builtin_msa_bmzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmzi.b(
+
+ v16i8_r = __builtin_msa_bneg_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bneg.b(
+ v8i16_r = __builtin_msa_bneg_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bneg.h(
+ v4i32_r = __builtin_msa_bneg_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bneg.w(
+ v2i64_r = __builtin_msa_bneg_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bneg.d(
+
+ v16i8_r = __builtin_msa_bnegi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bnegi.b(
+ v8i16_r = __builtin_msa_bnegi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bnegi.h(
+ v4i32_r = __builtin_msa_bnegi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bnegi.w(
+ v2i64_r = __builtin_msa_bnegi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bnegi.d(
+
+ int_r = __builtin_msa_bnz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.b(
+ int_r = __builtin_msa_bnz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.h(
+ int_r = __builtin_msa_bnz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.w(
+ int_r = __builtin_msa_bnz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.d(
+
+ int_r = __builtin_msa_bnz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.v(
+
+ v16i8_r = __builtin_msa_bsel_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v(
+ v8i16_r = __builtin_msa_bsel_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v(
+ v4i32_r = __builtin_msa_bsel_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v(
+ v2i64_r = __builtin_msa_bsel_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v(
+
+ v16i8_r = __builtin_msa_bseli_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bseli.b(
+
+ v16i8_r = __builtin_msa_bset_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bset.b(
+ v8i16_r = __builtin_msa_bset_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bset.h(
+ v4i32_r = __builtin_msa_bset_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bset.w(
+ v2i64_r = __builtin_msa_bset_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bset.d(
+
+ v16i8_r = __builtin_msa_bseti_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bseti.b(
+ v8i16_r = __builtin_msa_bseti_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bseti.h(
+ v4i32_r = __builtin_msa_bseti_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bseti.w(
+ v2i64_r = __builtin_msa_bseti_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bseti.d(
+
+ int_r = __builtin_msa_bz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bz.b(
+ int_r = __builtin_msa_bz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bz.h(
+ int_r = __builtin_msa_bz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bz.w(
+ int_r = __builtin_msa_bz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bz.d(
+
+ int_r = __builtin_msa_bz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bz.v(
+
+ v16i8_r = __builtin_msa_ceq_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ceq.b(
+ v8i16_r = __builtin_msa_ceq_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ceq.h(
+ v4i32_r = __builtin_msa_ceq_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ceq.w(
+ v2i64_r = __builtin_msa_ceq_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ceq.d(
+
+ v16i8_r = __builtin_msa_ceqi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ceqi.b(
+ v8i16_r = __builtin_msa_ceqi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.ceqi.h(
+ v4i32_r = __builtin_msa_ceqi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.ceqi.w(
+ v2i64_r = __builtin_msa_ceqi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.ceqi.d(
+
+ int_r = __builtin_msa_cfcmsa(1); // CHECK: call i32 @llvm.mips.cfcmsa(
+
+ v16i8_r = __builtin_msa_cle_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.cle.s.b(
+ v8i16_r = __builtin_msa_cle_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.cle.s.h(
+ v4i32_r = __builtin_msa_cle_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.cle.s.w(
+ v2i64_r = __builtin_msa_cle_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.cle.s.d(
+
+ v16u8_r = __builtin_msa_cle_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.cle.u.b(
+ v8u16_r = __builtin_msa_cle_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.cle.u.h(
+ v4u32_r = __builtin_msa_cle_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.cle.u.w(
+ v2u64_r = __builtin_msa_cle_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.cle.u.d(
+
+ v16i8_r = __builtin_msa_clei_s_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clei.s.b(
+ v8i16_r = __builtin_msa_clei_s_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clei.s.h(
+ v4i32_r = __builtin_msa_clei_s_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clei.s.w(
+ v2i64_r = __builtin_msa_clei_s_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clei.s.d(
+
+ v16u8_r = __builtin_msa_clei_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clei.u.b(
+ v8u16_r = __builtin_msa_clei_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clei.u.h(
+ v4u32_r = __builtin_msa_clei_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clei.u.w(
+ v2u64_r = __builtin_msa_clei_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clei.u.d(
+
+ v16i8_r = __builtin_msa_clt_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.clt.s.b(
+ v8i16_r = __builtin_msa_clt_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.clt.s.h(
+ v4i32_r = __builtin_msa_clt_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.clt.s.w(
+ v2i64_r = __builtin_msa_clt_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.clt.s.d(
+
+ v16u8_r = __builtin_msa_clt_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.clt.u.b(
+ v8u16_r = __builtin_msa_clt_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.clt.u.h(
+ v4u32_r = __builtin_msa_clt_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.clt.u.w(
+ v2u64_r = __builtin_msa_clt_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.clt.u.d(
+
+ v16i8_r = __builtin_msa_clti_s_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clti.s.b(
+ v8i16_r = __builtin_msa_clti_s_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clti.s.h(
+ v4i32_r = __builtin_msa_clti_s_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clti.s.w(
+ v2i64_r = __builtin_msa_clti_s_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clti.s.d(
+
+ v16u8_r = __builtin_msa_clti_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clti.u.b(
+ v8u16_r = __builtin_msa_clti_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clti.u.h(
+ v4u32_r = __builtin_msa_clti_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clti.u.w(
+ v2u64_r = __builtin_msa_clti_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clti.u.d(
+
+ int_r = __builtin_msa_copy_s_b(v16i8_a, 1); // CHECK: call i32 @llvm.mips.copy.s.b(
+ int_r = __builtin_msa_copy_s_h(v8i16_a, 1); // CHECK: call i32 @llvm.mips.copy.s.h(
+ int_r = __builtin_msa_copy_s_w(v4i32_a, 1); // CHECK: call i32 @llvm.mips.copy.s.w(
+ ll_r = __builtin_msa_copy_s_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.s.d(
+
+ int_r = __builtin_msa_copy_u_b(v16u8_a, 1); // CHECK: call i32 @llvm.mips.copy.u.b(
+ int_r = __builtin_msa_copy_u_h(v8u16_a, 1); // CHECK: call i32 @llvm.mips.copy.u.h(
+ int_r = __builtin_msa_copy_u_w(v4u32_a, 1); // CHECK: call i32 @llvm.mips.copy.u.w(
+ ll_r = __builtin_msa_copy_u_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.u.d(
+
+ __builtin_msa_ctcmsa(1, int_a); // CHECK: call void @llvm.mips.ctcmsa(
+
+ v16i8_r = __builtin_msa_div_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.div.s.b(
+ v8i16_r = __builtin_msa_div_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.div.s.h(
+ v4i32_r = __builtin_msa_div_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.div.s.w(
+ v2i64_r = __builtin_msa_div_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.div.s.d(
+
+ v16u8_r = __builtin_msa_div_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.div.u.b(
+ v8u16_r = __builtin_msa_div_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.div.u.h(
+ v4u32_r = __builtin_msa_div_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.div.u.w(
+ v2u64_r = __builtin_msa_div_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.div.u.d(
+
+ v8i16_r = __builtin_msa_dotp_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.s.h(
+ v4i32_r = __builtin_msa_dotp_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.s.w(
+ v2i64_r = __builtin_msa_dotp_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.s.d(
+
+ v8u16_r = __builtin_msa_dotp_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.u.h(
+ v4u32_r = __builtin_msa_dotp_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.u.w(
+ v2u64_r = __builtin_msa_dotp_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.u.d(
+
+ v8i16_r = __builtin_msa_dpadd_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.s.h(
+ v4i32_r = __builtin_msa_dpadd_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.s.w(
+ v2i64_r = __builtin_msa_dpadd_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.s.d(
+
+ v8u16_r = __builtin_msa_dpadd_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.u.h(
+ v4u32_r = __builtin_msa_dpadd_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.u.w(
+ v2u64_r = __builtin_msa_dpadd_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.u.d(
+
+ v8i16_r = __builtin_msa_dpsub_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.s.h(
+ v4i32_r = __builtin_msa_dpsub_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.s.w(
+ v2i64_r = __builtin_msa_dpsub_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.s.d(
+
+ v8u16_r = __builtin_msa_dpsub_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.u.h(
+ v4u32_r = __builtin_msa_dpsub_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.u.w(
+ v2u64_r = __builtin_msa_dpsub_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.u.d(
+
+ v4f32_r = __builtin_msa_fadd_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fadd.w(
+ v2f64_r = __builtin_msa_fadd_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fadd.d(
+
+ v4i32_r = __builtin_msa_fcaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcaf.w(
+ v2i64_r = __builtin_msa_fcaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcaf.d(
+
+ v4i32_r = __builtin_msa_fceq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fceq.w(
+ v2i64_r = __builtin_msa_fceq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fceq.d(
+
+ v4i32_r = __builtin_msa_fclass_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.fclass.w(
+ v2i64_r = __builtin_msa_fclass_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.fclass.d(
+
+ v4i32_r = __builtin_msa_fcle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcle.w(
+ v2i64_r = __builtin_msa_fcle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcle.d(
+
+ v4i32_r = __builtin_msa_fclt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fclt.w(
+ v2i64_r = __builtin_msa_fclt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fclt.d(
+
+ v4i32_r = __builtin_msa_fcne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcne.w(
+ v2i64_r = __builtin_msa_fcne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcne.d(
+
+ v4i32_r = __builtin_msa_fcor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcor.w(
+ v2i64_r = __builtin_msa_fcor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcor.d(
+
+ v4i32_r = __builtin_msa_fcueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcueq.w(
+ v2i64_r = __builtin_msa_fcueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcueq.d(
+
+ v4i32_r = __builtin_msa_fcule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcule.w(
+ v2i64_r = __builtin_msa_fcule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcule.d(
+
+ v4i32_r = __builtin_msa_fcult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcult.w(
+ v2i64_r = __builtin_msa_fcult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcult.d(
+
+ v4i32_r = __builtin_msa_fcun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcun.w(
+ v2i64_r = __builtin_msa_fcun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcun.d(
+
+ v4i32_r = __builtin_msa_fcune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcune.w(
+ v2i64_r = __builtin_msa_fcune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcune.d(
+
+ v4f32_r = __builtin_msa_fdiv_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fdiv.w(
+ v2f64_r = __builtin_msa_fdiv_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fdiv.d(
+
+ v8f16_r = __builtin_msa_fexdo_h(v4f32_a, v4f32_b); // CHECK: call <8 x half> @llvm.mips.fexdo.h(
+ v4f32_r = __builtin_msa_fexdo_w(v2f64_a, v2f64_b); // CHECK: call <4 x float> @llvm.mips.fexdo.w(
+
+ v4f32_r = __builtin_msa_fexp2_w(v4f32_a, v4i32_b); // CHECK: call <4 x float> @llvm.mips.fexp2.w(
+ v2f64_r = __builtin_msa_fexp2_d(v2f64_a, v2i64_b); // CHECK: call <2 x double> @llvm.mips.fexp2.d(
+
+ v4f32_r = __builtin_msa_fexupl_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupl.w(
+ v2f64_r = __builtin_msa_fexupl_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupl.d(
+
+ v4f32_r = __builtin_msa_fexupr_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupr.w(
+ v2f64_r = __builtin_msa_fexupr_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupr.d(
+
+ v4f32_r = __builtin_msa_ffint_s_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.s.w(
+ v2f64_r = __builtin_msa_ffint_s_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.s.d(
+
+ v4f32_r = __builtin_msa_ffint_u_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.u.w(
+ v2f64_r = __builtin_msa_ffint_u_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.u.d(
+
+ v4f32_r = __builtin_msa_ffql_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffql.w(
+ v2f64_r = __builtin_msa_ffql_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffql.d(
+
+ v4f32_r = __builtin_msa_ffqr_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffqr.w(
+ v2f64_r = __builtin_msa_ffqr_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffqr.d(
+
+ v16i8_r = __builtin_msa_fill_b(3); // CHECK: call <16 x i8> @llvm.mips.fill.b(
+ v8i16_r = __builtin_msa_fill_h(3); // CHECK: call <8 x i16> @llvm.mips.fill.h(
+ v4i32_r = __builtin_msa_fill_w(3); // CHECK: call <4 x i32> @llvm.mips.fill.w(
+ v2i64_r = __builtin_msa_fill_d(3); // CHECK: call <2 x i64> @llvm.mips.fill.d(
+
+ v4f32_r = __builtin_msa_flog2_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.flog2.w(
+ v2f64_r = __builtin_msa_flog2_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.flog2.d(
+
+ v4f32_r = __builtin_msa_fmadd_w(v8f16_r, v8f16_a, v8f16_b); // CHECK: call <4 x float> @llvm.mips.fmadd.w(
+ v2f64_r = __builtin_msa_fmadd_d(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <2 x double> @llvm.mips.fmadd.d(
+
+ v4f32_r = __builtin_msa_fmax_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.w(
+ v2f64_r = __builtin_msa_fmax_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.d(
+
+ v4f32_r = __builtin_msa_fmax_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.a.w(
+ v2f64_r = __builtin_msa_fmax_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.a.d(
+
+ v4f32_r = __builtin_msa_fmin_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.w(
+ v2f64_r = __builtin_msa_fmin_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.d(
+
+ v4f32_r = __builtin_msa_fmin_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.a.w(
+ v2f64_r = __builtin_msa_fmin_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.a.d(
+
+ v4f32_r = __builtin_msa_fmsub_w(v8f16_r, v8f16_a, v8f16_b); // CHECK: call <4 x float> @llvm.mips.fmsub.w(
+ v2f64_r = __builtin_msa_fmsub_d(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <2 x double> @llvm.mips.fmsub.d(
+
+ v4f32_r = __builtin_msa_fmul_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmul.w(
+ v2f64_r = __builtin_msa_fmul_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmul.d(
+
+ v4f32_r = __builtin_msa_frint_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frint.w(
+ v2f64_r = __builtin_msa_frint_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frint.d(
+
+ v4f32_r = __builtin_msa_frcp_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frcp.w(
+ v2f64_r = __builtin_msa_frcp_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frcp.d(
+
+ v4f32_r = __builtin_msa_frsqrt_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frsqrt.w(
+ v2f64_r = __builtin_msa_frsqrt_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frsqrt.d(
+
+ v4i32_r = __builtin_msa_fseq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fseq.w(
+ v2i64_r = __builtin_msa_fseq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fseq.d(
+
+ v4i32_r = __builtin_msa_fsaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsaf.w(
+ v2i64_r = __builtin_msa_fsaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsaf.d(
+
+ v4i32_r = __builtin_msa_fsle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsle.w(
+ v2i64_r = __builtin_msa_fsle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsle.d(
+
+ v4i32_r = __builtin_msa_fslt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fslt.w(
+ v2i64_r = __builtin_msa_fslt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fslt.d(
+
+ v4i32_r = __builtin_msa_fsne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsne.w(
+ v2i64_r = __builtin_msa_fsne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsne.d(
+
+ v4i32_r = __builtin_msa_fsor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsor.w(
+ v2i64_r = __builtin_msa_fsor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsor.d(
+
+ v4f32_r = __builtin_msa_fsqrt_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fsqrt.w(
+ v2f64_r = __builtin_msa_fsqrt_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fsqrt.d(
+
+ v4f32_r = __builtin_msa_fsub_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fsub.w(
+ v2f64_r = __builtin_msa_fsub_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fsub.d(
+
+ v4i32_r = __builtin_msa_fsueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsueq.w(
+ v2i64_r = __builtin_msa_fsueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsueq.d(
+
+ v4i32_r = __builtin_msa_fsule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsule.w(
+ v2i64_r = __builtin_msa_fsule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsule.d(
+
+ v4i32_r = __builtin_msa_fsult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsult.w(
+ v2i64_r = __builtin_msa_fsult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsult.d(
+
+ v4i32_r = __builtin_msa_fsun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsun.w(
+ v2i64_r = __builtin_msa_fsun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsun.d(
+
+ v4i32_r = __builtin_msa_fsune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsune.w(
+ v2i64_r = __builtin_msa_fsune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsune.d(
+
+ v4i32_r = __builtin_msa_ftint_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.s.w(
+ v2i64_r = __builtin_msa_ftint_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.s.d(
+
+ v4i32_r = __builtin_msa_ftint_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.u.w(
+ v2i64_r = __builtin_msa_ftint_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.u.d(
+
+ v8i16_r = __builtin_msa_ftq_h(v4f32_a, v4f32_b); // CHECK: call <8 x i16> @llvm.mips.ftq.h(
+ v4i32_r = __builtin_msa_ftq_w(v2f64_a, v2f64_b); // CHECK: call <4 x i32> @llvm.mips.ftq.w(
+
+ v4i32_r = __builtin_msa_ftrunc_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.s.w(
+ v2i64_r = __builtin_msa_ftrunc_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.s.d(
+
+ v4i32_r = __builtin_msa_ftrunc_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.u.w(
+ v2i64_r = __builtin_msa_ftrunc_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.u.d(
+
+ v8i16_r = __builtin_msa_hadd_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.s.h(
+ v4i32_r = __builtin_msa_hadd_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.s.w(
+ v2i64_r = __builtin_msa_hadd_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.s.d(
+
+ v8u16_r = __builtin_msa_hadd_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.u.h(
+ v4u32_r = __builtin_msa_hadd_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.u.w(
+ v2u64_r = __builtin_msa_hadd_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.u.d(
+
+ v8i16_r = __builtin_msa_hsub_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.s.h(
+ v4i32_r = __builtin_msa_hsub_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.s.w(
+ v2i64_r = __builtin_msa_hsub_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.s.d(
+
+ v8u16_r = __builtin_msa_hsub_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.u.h(
+ v4u32_r = __builtin_msa_hsub_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.u.w(
+ v2u64_r = __builtin_msa_hsub_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.u.d(
+
+ v16i8_r = __builtin_msa_ilvev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvev.b(
+ v8i16_r = __builtin_msa_ilvev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvev.h(
+ v4i32_r = __builtin_msa_ilvev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvev.w(
+ v2i64_r = __builtin_msa_ilvev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvev.d(
+
+ v16i8_r = __builtin_msa_ilvl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvl.b(
+ v8i16_r = __builtin_msa_ilvl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvl.h(
+ v4i32_r = __builtin_msa_ilvl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvl.w(
+ v2i64_r = __builtin_msa_ilvl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvl.d(
+
+ v16i8_r = __builtin_msa_ilvod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvod.b(
+ v8i16_r = __builtin_msa_ilvod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvod.h(
+ v4i32_r = __builtin_msa_ilvod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvod.w(
+ v2i64_r = __builtin_msa_ilvod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvod.d(
+
+ v16i8_r = __builtin_msa_ilvr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvr.b(
+ v8i16_r = __builtin_msa_ilvr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvr.h(
+ v4i32_r = __builtin_msa_ilvr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvr.w(
+ v2i64_r = __builtin_msa_ilvr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvr.d(
+
+ v16i8_r = __builtin_msa_insert_b(v16i8_r, 1, 25); // CHECK: call <16 x i8> @llvm.mips.insert.b(
+ v8i16_r = __builtin_msa_insert_h(v8i16_r, 1, 25); // CHECK: call <8 x i16> @llvm.mips.insert.h(
+ v4i32_r = __builtin_msa_insert_w(v4i32_r, 1, 25); // CHECK: call <4 x i32> @llvm.mips.insert.w(
+ v2i64_r = __builtin_msa_insert_d(v2i64_r, 1, 25); // CHECK: call <2 x i64> @llvm.mips.insert.d(
+
+ v16i8_r = __builtin_msa_insve_b(v16i8_r, 1, v16i8_a); // CHECK: call <16 x i8> @llvm.mips.insve.b(
+ v8i16_r = __builtin_msa_insve_h(v8i16_r, 1, v8i16_a); // CHECK: call <8 x i16> @llvm.mips.insve.h(
+ v4i32_r = __builtin_msa_insve_w(v4i32_r, 1, v4i32_a); // CHECK: call <4 x i32> @llvm.mips.insve.w(
+ v2i64_r = __builtin_msa_insve_d(v2i64_r, 1, v2i64_a); // CHECK: call <2 x i64> @llvm.mips.insve.d(
+
+ v16i8_r = __builtin_msa_ld_b(&v16i8_a, 1); // CHECK: call <16 x i8> @llvm.mips.ld.b(
+ v8i16_r = __builtin_msa_ld_h(&v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.ld.h(
+ v4i32_r = __builtin_msa_ld_w(&v4i32_a, 4); // CHECK: call <4 x i32> @llvm.mips.ld.w(
+ v2i64_r = __builtin_msa_ld_d(&v2i64_a, 8); // CHECK: call <2 x i64> @llvm.mips.ld.d(
+
+ v16i8_r = __builtin_msa_ldi_b(3); // CHECK: call <16 x i8> @llvm.mips.ldi.b(
+ v8i16_r = __builtin_msa_ldi_h(3); // CHECK: call <8 x i16> @llvm.mips.ldi.h(
+ v4i32_r = __builtin_msa_ldi_w(3); // CHECK: call <4 x i32> @llvm.mips.ldi.w(
+ v2i64_r = __builtin_msa_ldi_d(3); // CHECK: call <2 x i64> @llvm.mips.ldi.d(
+
+ v8i16_r = __builtin_msa_madd_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.madd.q.h(
+ v4i32_r = __builtin_msa_madd_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.madd.q.w(
+
+ v8i16_r = __builtin_msa_maddr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddr.q.h(
+ v4i32_r = __builtin_msa_maddr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddr.q.w(
+
+ v16i8_r = __builtin_msa_maddv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.maddv.b(
+ v8i16_r = __builtin_msa_maddv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddv.h(
+ v4i32_r = __builtin_msa_maddv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddv.w(
+ v2i64_r = __builtin_msa_maddv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.maddv.d(
+
+ v16i8_r = __builtin_msa_max_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.a.b(
+ v8i16_r = __builtin_msa_max_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.a.h(
+ v4i32_r = __builtin_msa_max_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.a.w(
+ v2i64_r = __builtin_msa_max_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.a.d(
+
+ v16i8_r = __builtin_msa_max_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.s.b(
+ v8i16_r = __builtin_msa_max_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.s.h(
+ v4i32_r = __builtin_msa_max_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.s.w(
+ v2i64_r = __builtin_msa_max_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.s.d(
+
+ v16u8_r = __builtin_msa_max_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.max.u.b(
+ v8u16_r = __builtin_msa_max_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.max.u.h(
+ v4u32_r = __builtin_msa_max_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.max.u.w(
+ v2u64_r = __builtin_msa_max_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.max.u.d(
+
+ v16i8_r = __builtin_msa_maxi_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.s.b(
+ v8i16_r = __builtin_msa_maxi_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.s.h(
+ v4i32_r = __builtin_msa_maxi_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.s.w(
+ v2i64_r = __builtin_msa_maxi_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.s.d(
+
+ v16u8_r = __builtin_msa_maxi_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.u.b(
+ v8u16_r = __builtin_msa_maxi_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.u.h(
+ v4u32_r = __builtin_msa_maxi_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.u.w(
+ v2u64_r = __builtin_msa_maxi_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.u.d(
+
+ v16i8_r = __builtin_msa_min_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.a.b(
+ v8i16_r = __builtin_msa_min_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.a.h(
+ v4i32_r = __builtin_msa_min_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.a.w(
+ v2i64_r = __builtin_msa_min_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.a.d(
+
+ v16i8_r = __builtin_msa_min_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.s.b(
+ v8i16_r = __builtin_msa_min_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.s.h(
+ v4i32_r = __builtin_msa_min_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.s.w(
+ v2i64_r = __builtin_msa_min_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.s.d(
+
+ v16u8_r = __builtin_msa_min_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.min.u.b(
+ v8u16_r = __builtin_msa_min_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.min.u.h(
+ v4u32_r = __builtin_msa_min_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.min.u.w(
+ v2u64_r = __builtin_msa_min_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.min.u.d(
+
+ v16i8_r = __builtin_msa_mini_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.s.b(
+ v8i16_r = __builtin_msa_mini_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.s.h(
+ v4i32_r = __builtin_msa_mini_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.s.w(
+ v2i64_r = __builtin_msa_mini_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.s.d(
+
+ v16u8_r = __builtin_msa_mini_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.u.b(
+ v8u16_r = __builtin_msa_mini_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.u.h(
+ v4u32_r = __builtin_msa_mini_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.u.w(
+ v2u64_r = __builtin_msa_mini_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.u.d(
+
+ v16i8_r = __builtin_msa_mod_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mod.s.b(
+ v8i16_r = __builtin_msa_mod_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mod.s.h(
+ v4i32_r = __builtin_msa_mod_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mod.s.w(
+ v2i64_r = __builtin_msa_mod_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mod.s.d(
+
+ v16u8_r = __builtin_msa_mod_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.mod.u.b(
+ v8u16_r = __builtin_msa_mod_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.mod.u.h(
+ v4u32_r = __builtin_msa_mod_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.mod.u.w(
+ v2u64_r = __builtin_msa_mod_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.mod.u.d(
+
+ v16i8_r = __builtin_msa_move_v(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.move.v(
+
+ v8i16_r = __builtin_msa_msub_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msub.q.h(
+ v4i32_r = __builtin_msa_msub_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msub.q.w(
+
+ v8i16_r = __builtin_msa_msubr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubr.q.h(
+ v4i32_r = __builtin_msa_msubr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubr.q.w(
+
+ v16i8_r = __builtin_msa_msubv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.msubv.b(
+ v8i16_r = __builtin_msa_msubv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubv.h(
+ v4i32_r = __builtin_msa_msubv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubv.w(
+ v2i64_r = __builtin_msa_msubv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.msubv.d(
+
+ v8i16_r = __builtin_msa_mul_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mul.q.h(
+ v4i32_r = __builtin_msa_mul_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mul.q.w(
+
+ v8i16_r = __builtin_msa_mulr_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulr.q.h(
+ v4i32_r = __builtin_msa_mulr_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulr.q.w(
+
+ v16i8_r = __builtin_msa_mulv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mulv.b(
+ v8i16_r = __builtin_msa_mulv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulv.h(
+ v4i32_r = __builtin_msa_mulv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulv.w(
+ v2i64_r = __builtin_msa_mulv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mulv.d(
+
+ v16i8_r = __builtin_msa_nloc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nloc.b(
+ v8i16_r = __builtin_msa_nloc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nloc.h(
+ v4i32_r = __builtin_msa_nloc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nloc.w(
+ v2i64_r = __builtin_msa_nloc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nloc.d(
+
+ v16i8_r = __builtin_msa_nlzc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nlzc.b(
+ v8i16_r = __builtin_msa_nlzc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nlzc.h(
+ v4i32_r = __builtin_msa_nlzc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nlzc.w(
+ v2i64_r = __builtin_msa_nlzc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nlzc.d(
+
+ v16i8_r = __builtin_msa_nor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.nor.v(
+ v8i16_r = __builtin_msa_nor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.nor.v(
+ v4i32_r = __builtin_msa_nor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.nor.v(
+ v2i64_r = __builtin_msa_nor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.nor.v(
+
+ v16i8_r = __builtin_msa_nori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v8i16_r = __builtin_msa_nori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v4i32_r = __builtin_msa_nori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v2i64_r = __builtin_msa_nori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+
+ v16u8_r = __builtin_msa_nori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v8u16_r = __builtin_msa_nori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v4u32_r = __builtin_msa_nori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+ v2u64_r = __builtin_msa_nori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b(
+
+ v16i8_r = __builtin_msa_or_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.or.v(
+ v8i16_r = __builtin_msa_or_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.or.v(
+ v4i32_r = __builtin_msa_or_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.or.v(
+ v2i64_r = __builtin_msa_or_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.or.v(
+
+ v16i8_r = __builtin_msa_ori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v8i16_r = __builtin_msa_ori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v4i32_r = __builtin_msa_ori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v2i64_r = __builtin_msa_ori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+
+ v16u8_r = __builtin_msa_ori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v8u16_r = __builtin_msa_ori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v4u32_r = __builtin_msa_ori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+ v2u64_r = __builtin_msa_ori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b(
+
+ v16i8_r = __builtin_msa_pckev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckev.b(
+ v8i16_r = __builtin_msa_pckev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckev.h(
+ v4i32_r = __builtin_msa_pckev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckev.w(
+ v2i64_r = __builtin_msa_pckev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckev.d(
+
+ v16i8_r = __builtin_msa_pckod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckod.b(
+ v8i16_r = __builtin_msa_pckod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckod.h(
+ v4i32_r = __builtin_msa_pckod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckod.w(
+ v2i64_r = __builtin_msa_pckod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckod.d(
+
+ v16i8_r = __builtin_msa_pcnt_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.pcnt.b(
+ v8i16_r = __builtin_msa_pcnt_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.pcnt.h(
+ v4i32_r = __builtin_msa_pcnt_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.pcnt.w(
+ v2i64_r = __builtin_msa_pcnt_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.pcnt.d(
+
+ v16i8_r = __builtin_msa_sat_s_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.s.b(
+ v8i16_r = __builtin_msa_sat_s_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.s.h(
+ v4i32_r = __builtin_msa_sat_s_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.s.w(
+ v2i64_r = __builtin_msa_sat_s_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.s.d(
+
+ v16i8_r = __builtin_msa_sat_u_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.u.b(
+ v8i16_r = __builtin_msa_sat_u_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.u.h(
+ v4i32_r = __builtin_msa_sat_u_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.u.w(
+ v2i64_r = __builtin_msa_sat_u_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.u.d(
+
+ v16i8_r = __builtin_msa_shf_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.shf.b(
+ v8i16_r = __builtin_msa_shf_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.shf.h(
+ v4i32_r = __builtin_msa_shf_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.shf.w(
+
+ v16i8_r = __builtin_msa_sld_b(v16i8_a, 10); // CHECK: call <16 x i8> @llvm.mips.sld.b(
+ v8i16_r = __builtin_msa_sld_h(v8i16_a, 10); // CHECK: call <8 x i16> @llvm.mips.sld.h(
+ v4i32_r = __builtin_msa_sld_w(v4i32_a, 10); // CHECK: call <4 x i32> @llvm.mips.sld.w(
+ v2i64_r = __builtin_msa_sld_d(v2i64_a, 10); // CHECK: call <2 x i64> @llvm.mips.sld.d(
+
+ v16i8_r = __builtin_msa_sldi_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sldi.b(
+ v8i16_r = __builtin_msa_sldi_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sldi.h(
+ v4i32_r = __builtin_msa_sldi_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sldi.w(
+ v2i64_r = __builtin_msa_sldi_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sldi.d(
+
+ v16i8_r = __builtin_msa_sll_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sll.b(
+ v8i16_r = __builtin_msa_sll_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sll.h(
+ v4i32_r = __builtin_msa_sll_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sll.w(
+ v2i64_r = __builtin_msa_sll_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sll.d(
+
+ v16i8_r = __builtin_msa_slli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.slli.b(
+ v8i16_r = __builtin_msa_slli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.slli.h(
+ v4i32_r = __builtin_msa_slli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.slli.w(
+ v2i64_r = __builtin_msa_slli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.slli.d(
+
+ v16i8_r = __builtin_msa_splat_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splat.b(
+ v8i16_r = __builtin_msa_splat_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splat.h(
+ v4i32_r = __builtin_msa_splat_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splat.w(
+ v2i64_r = __builtin_msa_splat_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.splat.d(
+
+ v16i8_r = __builtin_msa_splati_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splati.b(
+ v8i16_r = __builtin_msa_splati_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splati.h(
+ v4i32_r = __builtin_msa_splati_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splati.w(
+ v2i64_r = __builtin_msa_splati_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.splati.d(
+
+ v16i8_r = __builtin_msa_sra_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sra.b(
+ v8i16_r = __builtin_msa_sra_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sra.h(
+ v4i32_r = __builtin_msa_sra_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sra.w(
+ v2i64_r = __builtin_msa_sra_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sra.d(
+
+ v16i8_r = __builtin_msa_srai_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srai.b(
+ v8i16_r = __builtin_msa_srai_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srai.h(
+ v4i32_r = __builtin_msa_srai_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srai.w(
+ v2i64_r = __builtin_msa_srai_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srai.d(
+
+ v16i8_r = __builtin_msa_srar_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srar.b(
+ v8i16_r = __builtin_msa_srar_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srar.h(
+ v4i32_r = __builtin_msa_srar_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srar.w(
+ v2i64_r = __builtin_msa_srar_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srar.d(
+
+ v16i8_r = __builtin_msa_srari_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srari.b(
+ v8i16_r = __builtin_msa_srari_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srari.h(
+ v4i32_r = __builtin_msa_srari_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srari.w(
+ v2i64_r = __builtin_msa_srari_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srari.d(
+
+ v16i8_r = __builtin_msa_srl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srl.b(
+ v8i16_r = __builtin_msa_srl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srl.h(
+ v4i32_r = __builtin_msa_srl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srl.w(
+ v2i64_r = __builtin_msa_srl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srl.d(
+
+ v16i8_r = __builtin_msa_srli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srli.b(
+ v8i16_r = __builtin_msa_srli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srli.h(
+ v4i32_r = __builtin_msa_srli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srli.w(
+ v2i64_r = __builtin_msa_srli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srli.d(
+
+ v16i8_r = __builtin_msa_srlr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srlr.b(
+ v8i16_r = __builtin_msa_srlr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srlr.h(
+ v4i32_r = __builtin_msa_srlr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srlr.w(
+ v2i64_r = __builtin_msa_srlr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srlr.d(
+
+ v16i8_r = __builtin_msa_srlri_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srlri.b(
+ v8i16_r = __builtin_msa_srlri_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srlri.h(
+ v4i32_r = __builtin_msa_srlri_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srlri.w(
+ v2i64_r = __builtin_msa_srlri_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srlri.d(
+
+ __builtin_msa_st_b(v16i8_b, &v16i8_a, 1); // CHECK: call void @llvm.mips.st.b(
+ __builtin_msa_st_h(v8i16_b, &v8i16_a, 2); // CHECK: call void @llvm.mips.st.h(
+ __builtin_msa_st_w(v4i32_b, &v4i32_a, 4); // CHECK: call void @llvm.mips.st.w(
+ __builtin_msa_st_d(v2i64_b, &v2i64_a, 8); // CHECK: call void @llvm.mips.st.d(
+
+ v16i8_r = __builtin_msa_subs_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subs.s.b(
+ v8i16_r = __builtin_msa_subs_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subs.s.h(
+ v4i32_r = __builtin_msa_subs_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subs.s.w(
+ v2i64_r = __builtin_msa_subs_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subs.s.d(
+
+ v16u8_r = __builtin_msa_subs_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subs.u.b(
+ v8u16_r = __builtin_msa_subs_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subs.u.h(
+ v4u32_r = __builtin_msa_subs_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subs.u.w(
+ v2u64_r = __builtin_msa_subs_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subs.u.d(
+
+ v16u8_r = __builtin_msa_subsus_u_b(v16u8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subsus.u.b(
+ v8u16_r = __builtin_msa_subsus_u_h(v8u16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subsus.u.h(
+ v4u32_r = __builtin_msa_subsus_u_w(v4u32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subsus.u.w(
+ v2u64_r = __builtin_msa_subsus_u_d(v2u64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subsus.u.d(
+
+ v16i8_r = __builtin_msa_subsuu_s_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subsuu.s.b(
+ v8i16_r = __builtin_msa_subsuu_s_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subsuu.s.h(
+ v4i32_r = __builtin_msa_subsuu_s_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subsuu.s.w(
+ v2i64_r = __builtin_msa_subsuu_s_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subsuu.s.d(
+
+ v16i8_r = __builtin_msa_subv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subv.b(
+ v8i16_r = __builtin_msa_subv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subv.h(
+ v4i32_r = __builtin_msa_subv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subv.w(
+ v2i64_r = __builtin_msa_subv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subv.d(
+
+ v16i8_r = __builtin_msa_subvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.subvi.b(
+ v8i16_r = __builtin_msa_subvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.subvi.h(
+ v4i32_r = __builtin_msa_subvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.subvi.w(
+ v2i64_r = __builtin_msa_subvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.subvi.d(
+
+ v16i8_r = __builtin_msa_vshf_b(v16i8_a, v16i8_b, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.vshf.b(
+ v8i16_r = __builtin_msa_vshf_h(v8i16_a, v8i16_b, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.vshf.h(
+ v4i32_r = __builtin_msa_vshf_w(v4i32_a, v4i32_b, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.vshf.w(
+ v2i64_r = __builtin_msa_vshf_d(v2i64_a, v2i64_b, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.vshf.d(
+
+ v16i8_r = __builtin_msa_xor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.xor.v(
+ v8i16_r = __builtin_msa_xor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.xor.v(
+ v4i32_r = __builtin_msa_xor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.xor.v(
+ v2i64_r = __builtin_msa_xor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.xor.v(
+
+ v16i8_r = __builtin_msa_xori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v8i16_r = __builtin_msa_xori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v4i32_r = __builtin_msa_xori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v2i64_r = __builtin_msa_xori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+
+ v16u8_r = __builtin_msa_xori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v8u16_r = __builtin_msa_xori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v4u32_r = __builtin_msa_xori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+ v2u64_r = __builtin_msa_xori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b(
+
+}
diff --git a/test/CodeGen/builtins-ms.c b/test/CodeGen/builtins-ms.c
new file mode 100644
index 000000000000..0676e9df7a7d
--- /dev/null
+++ b/test/CodeGen/builtins-ms.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fms-extensions -triple i686-pc-win32 | FileCheck %s
+
+// CHECK-LABEL: define void @test_alloca
+void capture(void *);
+void test_alloca(int n) {
+ capture(_alloca(n));
+ // CHECK: %[[arg:.*]] = alloca i8, i32 %
+ // CHECK: call void @capture(i8* %[[arg]])
+}
diff --git a/test/CodeGen/builtins-multiprecision.c b/test/CodeGen/builtins-multiprecision.c
index 172f683de3b8..4d196088d3d8 100644
--- a/test/CodeGen/builtins-multiprecision.c
+++ b/test/CodeGen/builtins-multiprecision.c
@@ -2,6 +2,25 @@
// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - -O3 | FileCheck %s
// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - -O3 | FileCheck %s
+unsigned char test_addcb(unsigned char x, unsigned char y,
+ unsigned char carryin, unsigned char *z) {
+ // CHECK: @test_addcb
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %x, i8 %y)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %{{.+}}, i8 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i8
+ // CHECK: store i8 %{{.+}}, i8* %z, align 1
+
+ unsigned char carryout;
+ *z = __builtin_addcb(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
unsigned short test_addcs(unsigned short x, unsigned short y,
unsigned short carryin, unsigned short *z) {
// CHECK: @test_addcs
@@ -76,6 +95,25 @@ unsigned long long test_addcll(unsigned long long x, unsigned long long y,
return carryout;
}
+unsigned char test_subcb(unsigned char x, unsigned char y,
+ unsigned char carryin, unsigned char *z) {
+ // CHECK: @test_subcb
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %{{.+}}, i8 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i8
+ // CHECK: store i8 %{{.+}}, i8* %z, align 1
+
+ unsigned char carryout;
+ *z = __builtin_subcb(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
unsigned short test_subcs(unsigned short x, unsigned short y,
unsigned short carryin, unsigned short *z) {
// CHECK: @test_subcs
diff --git a/test/CodeGen/builtins-nvptx.c b/test/CodeGen/builtins-nvptx.c
index 2c7e0c136769..7deee8ef48eb 100644
--- a/test/CodeGen/builtins-nvptx.c
+++ b/test/CodeGen/builtins-nvptx.c
@@ -165,4 +165,13 @@ void nvvm_math(float f1, float f2, double d1, double d2) {
double td3 = __nvvm_sqrt_rn_d(d1);
// CHECK: call double @llvm.nvvm.rcp.rn.d
double td4 = __nvvm_rcp_rn_d(d2);
+
+// CHECK: call void @llvm.nvvm.membar.cta()
+ __nvvm_membar_cta();
+// CHECK: call void @llvm.nvvm.membar.gl()
+ __nvvm_membar_gl();
+// CHECK: call void @llvm.nvvm.membar.sys()
+ __nvvm_membar_sys();
+// CHECK: call void @llvm.nvvm.barrier0()
+ __nvvm_bar0();
}
diff --git a/test/CodeGen/builtins-overflow.c b/test/CodeGen/builtins-overflow.c
new file mode 100644
index 000000000000..5c5500d5684a
--- /dev/null
+++ b/test/CodeGen/builtins-overflow.c
@@ -0,0 +1,175 @@
+// Test CodeGen for Security Check Overflow Builtins.
+// rdar://13421498
+
+// RUN: %clang_cc1 -triple "i686-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - | FileCheck %s
+
+extern unsigned UnsignedErrorCode;
+extern unsigned long UnsignedLongErrorCode;
+extern unsigned long long UnsignedLongLongErrorCode;
+extern int IntErrorCode;
+extern long LongErrorCode;
+extern long long LongLongErrorCode;
+
+unsigned test_uadd_overflow(unsigned x, unsigned y) {
+// CHECK: @test_uadd_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ unsigned result;
+ if (__builtin_uadd_overflow(x, y, &result))
+ return UnsignedErrorCode;
+ return result;
+}
+
+unsigned long test_uaddl_overflow(unsigned long x, unsigned long y) {
+// CHECK: @test_uaddl_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.uadd.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ unsigned long result;
+ if (__builtin_uaddl_overflow(x, y, &result))
+ return UnsignedLongErrorCode;
+ return result;
+}
+
+unsigned long long test_uaddll_overflow(unsigned long long x, unsigned long long y) {
+// CHECK: @test_uaddll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ unsigned long long result;
+ if (__builtin_uaddll_overflow(x, y, &result))
+ return UnsignedLongLongErrorCode;
+ return result;
+}
+
+unsigned test_usub_overflow(unsigned x, unsigned y) {
+// CHECK: @test_usub_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ unsigned result;
+ if (__builtin_usub_overflow(x, y, &result))
+ return UnsignedErrorCode;
+ return result;
+}
+
+unsigned long test_usubl_overflow(unsigned long x, unsigned long y) {
+// CHECK: @test_usubl_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.usub.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ unsigned long result;
+ if (__builtin_usubl_overflow(x, y, &result))
+ return UnsignedLongErrorCode;
+ return result;
+}
+
+unsigned long long test_usubll_overflow(unsigned long long x, unsigned long long y) {
+// CHECK: @test_usubll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ unsigned long long result;
+ if (__builtin_usubll_overflow(x, y, &result))
+ return UnsignedLongLongErrorCode;
+ return result;
+}
+
+unsigned test_umul_overflow(unsigned x, unsigned y) {
+// CHECK: @test_umul_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ unsigned result;
+ if (__builtin_umul_overflow(x, y, &result))
+ return UnsignedErrorCode;
+ return result;
+}
+
+unsigned long test_umull_overflow(unsigned long x, unsigned long y) {
+// CHECK: @test_umull_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.umul.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ unsigned long result;
+ if (__builtin_umull_overflow(x, y, &result))
+ return UnsignedLongErrorCode;
+ return result;
+}
+
+unsigned long long test_umulll_overflow(unsigned long long x, unsigned long long y) {
+// CHECK: @test_umulll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ unsigned long long result;
+ if (__builtin_umulll_overflow(x, y, &result))
+ return UnsignedLongLongErrorCode;
+ return result;
+}
+
+int test_sadd_overflow(int x, int y) {
+// CHECK: @test_sadd_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ int result;
+ if (__builtin_sadd_overflow(x, y, &result))
+ return IntErrorCode;
+ return result;
+}
+
+long test_saddl_overflow(long x, long y) {
+// CHECK: @test_saddl_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.sadd.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ long result;
+ if (__builtin_saddl_overflow(x, y, &result))
+ return LongErrorCode;
+ return result;
+}
+
+long long test_saddll_overflow(long long x, long long y) {
+// CHECK: @test_saddll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ long long result;
+ if (__builtin_saddll_overflow(x, y, &result))
+ return LongLongErrorCode;
+ return result;
+}
+
+int test_ssub_overflow(int x, int y) {
+// CHECK: @test_ssub_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ int result;
+ if (__builtin_ssub_overflow(x, y, &result))
+ return IntErrorCode;
+ return result;
+}
+
+long test_ssubl_overflow(long x, long y) {
+// CHECK: @test_ssubl_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.ssub.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ long result;
+ if (__builtin_ssubl_overflow(x, y, &result))
+ return LongErrorCode;
+ return result;
+}
+
+long long test_ssubll_overflow(long long x, long long y) {
+// CHECK: @test_ssubll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ long long result;
+ if (__builtin_ssubll_overflow(x, y, &result))
+ return LongLongErrorCode;
+ return result;
+}
+
+int test_smul_overflow(int x, int y) {
+// CHECK: @test_smul_overflow
+// CHECK: %{{.+}} = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
+ int result;
+ if (__builtin_smul_overflow(x, y, &result))
+ return IntErrorCode;
+ return result;
+}
+
+long test_smull_overflow(long x, long y) {
+// CHECK: @test_smull_overflow([[UL:i32|i64]] %x
+// CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.smul.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}})
+ long result;
+ if (__builtin_smull_overflow(x, y, &result))
+ return LongErrorCode;
+ return result;
+}
+
+long long test_smulll_overflow(long long x, long long y) {
+// CHECK: @test_smulll_overflow
+// CHECK: %{{.+}} = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}})
+ long long result;
+ if (__builtin_smulll_overflow(x, y, &result))
+ return LongLongErrorCode;
+ return result;
+}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index 9427a8a57cdf..47a198f2aeda 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -41,7 +41,7 @@ int res_i;
int res_ui;
int res_f;
-// CHECK: define void @test1
+// CHECK-LABEL: define void @test1
void test1() {
/* vec_abs */
@@ -333,7 +333,7 @@ void test1() {
}
-// CHECK: define void @test2
+// CHECK-LABEL: define void @test2
void test2() {
/* vec_avg */
res_vsc = vec_avg(vsc, vsc); // CHECK: @llvm.ppc.altivec.vavgsb
@@ -371,7 +371,7 @@ void test2() {
res_vbi = vec_vcmpgefp(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp
}
-// CHECK: define void @test5
+// CHECK-LABEL: define void @test5
void test5() {
/* vec_cmpgt */
@@ -394,7 +394,7 @@ void test5() {
res_vbi = vec_cmple(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp
}
-// CHECK: define void @test6
+// CHECK-LABEL: define void @test6
void test6() {
/* vec_cmplt */
res_vbc = vec_cmplt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb
@@ -3055,7 +3055,7 @@ void test6() {
}
/* ------------------------------ Relational Operators ------------------------------ */
-// CHECK: define void @test7
+// CHECK-LABEL: define void @test7
void test7() {
vector signed char vsc1 = (vector signed char)(-1);
vector signed char vsc2 = (vector signed char)(-2);
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index fcf1512ca16e..261bf2f5d8b3 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -55,6 +55,7 @@ void f0() {
const float* tmp_fCp;
double* tmp_dp;
const double* tmp_dCp;
+ long long* tmp_LLip;
#define imm_i 32
#define imm_i_0_2 0
@@ -288,6 +289,9 @@ void f0() {
tmp_i = __builtin_ia32_movmskpd(tmp_V2d);
tmp_i = __builtin_ia32_pmovmskb128(tmp_V16c);
(void) __builtin_ia32_movnti(tmp_ip, tmp_i);
+#ifdef USE_64
+ (void) __builtin_ia32_movnti64(tmp_LLip, tmp_LLi);
+#endif
(void) __builtin_ia32_movntpd(tmp_dp, tmp_V2d);
(void) __builtin_ia32_movntdq(tmp_V2LLip, tmp_V2LLi);
tmp_V2LLi = __builtin_ia32_psadbw128(tmp_V16c, tmp_V16c);
@@ -491,5 +495,13 @@ void f0() {
tmp_V2f = __builtin_ia32_pi2fw(tmp_V2i);
tmp_V2f = __builtin_ia32_pswapdsf(tmp_V2f);
tmp_V2i = __builtin_ia32_pswapdsi(tmp_V2i);
+
+ tmp_V4i = __builtin_ia32_sha1rnds4(tmp_V4i, tmp_V4i, imm_i);
+ tmp_V4i = __builtin_ia32_sha1nexte(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_sha1msg1(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_sha1msg2(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_sha256rnds2(tmp_V4i, tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_sha256msg1(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_sha256msg2(tmp_V4i, tmp_V4i);
#endif
}
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index 9ba12bbf2fec..39bd84c5a5a4 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -131,7 +131,7 @@ void foo() {
__builtin_strcat(0, 0);
}
-// CHECK: define void @bar(
+// CHECK-LABEL: define void @bar(
void bar() {
float f;
double d;
@@ -167,7 +167,7 @@ void bar() {
// CHECK: }
-// CHECK: define void @test_float_builtins
+// CHECK-LABEL: define void @test_float_builtins
void test_float_builtins(float F, double D, long double LD) {
volatile int res;
res = __builtin_isinf(F);
@@ -197,7 +197,7 @@ void test_float_builtins(float F, double D, long double LD) {
// CHECK: and i1
}
-// CHECK: define void @test_builtin_longjmp
+// CHECK-LABEL: define void @test_builtin_longjmp
void test_builtin_longjmp(void **buffer) {
// CHECK: [[BITCAST:%.*]] = bitcast
// CHECK-NEXT: call void @llvm.eh.sjlj.longjmp(i8* [[BITCAST]])
@@ -205,7 +205,7 @@ void test_builtin_longjmp(void **buffer) {
// CHECK-NEXT: unreachable
}
-// CHECK: define i64 @test_builtin_readcyclecounter
+// CHECK-LABEL: define i64 @test_builtin_readcyclecounter
long long test_builtin_readcyclecounter() {
// CHECK: call i64 @llvm.readcyclecounter()
return __builtin_readcyclecounter();
diff --git a/test/CodeGen/builtinshufflevector2.c b/test/CodeGen/builtinshufflevector2.c
index ac0e07a41907..04405b5cd159 100644
--- a/test/CodeGen/builtinshufflevector2.c
+++ b/test/CodeGen/builtinshufflevector2.c
@@ -3,7 +3,7 @@
typedef float float4 __attribute__((ext_vector_type(4)));
typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
-// CHECK: define void @clang_shufflevector_v_v(
+// CHECK-LABEL: define void @clang_shufflevector_v_v(
void clang_shufflevector_v_v( float4* A, float4 x, uint4 mask ) {
// CHECK: [[MASK:%.*]] = and <4 x i32> {{%.*}}, <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 0
@@ -27,9 +27,16 @@ void clang_shufflevector_v_v( float4* A, float4 x, uint4 mask ) {
*A = __builtin_shufflevector( x, mask );
}
-// CHECK: define void @clang_shufflevector_v_v_c(
-void clang_shufflevector_v_v_c( float4* A, float4 x, float4 y, uint4 mask ) {
+// CHECK-LABEL: define void @clang_shufflevector_v_v_c(
+void clang_shufflevector_v_v_c( float4* A, float4 x, float4 y) {
// CHECK: [[V:%.*]] = shufflevector <4 x float> {{%.*}}, <4 x float> {{%.*}}, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
// CHECK: store <4 x float> [[V]], <4 x float>* {{%.*}}
*A = __builtin_shufflevector( x, y, 0, 4, 1, 5 );
}
+
+// CHECK-LABEL: define void @clang_shufflevector_v_v_undef(
+void clang_shufflevector_v_v_undef( float4* A, float4 x, float4 y) {
+// CHECK: [[V:%.*]] = shufflevector <4 x float> {{%.*}}, <4 x float> {{%.*}}, <4 x i32> <i32 0, i32 4, i32 undef, i32 5>
+// CHECK: store <4 x float> [[V]], <4 x float>* {{%.*}}
+ *A = __builtin_shufflevector( x, y, 0, 4, -1, 5 );
+}
diff --git a/test/CodeGen/byval-memcpy-elim.c b/test/CodeGen/byval-memcpy-elim.c
index 76cdafb5e8c5..d4b751a48bd9 100644
--- a/test/CodeGen/byval-memcpy-elim.c
+++ b/test/CodeGen/byval-memcpy-elim.c
@@ -12,7 +12,7 @@ struct Test2S {
// Make sure we don't generate extra memcpy for lvalues
void test1a(struct Test1S, struct Test2S);
-// CHECK: define void @test1(
+// CHECK-LABEL: define void @test1(
// CHECK-NOT: memcpy
// CHECK: call void @test1a
void test1(struct Test1S *A, struct Test2S *B) {
@@ -28,7 +28,7 @@ struct Test3S {
int a,b,c,d,e,f,g,h,i,j,k,l;
};
void test2a(struct Test3S q);
-// CHECK: define void @test2(
+// CHECK-LABEL: define void @test2(
// CHECK: alloca %struct.Test3S, align 8
// CHECK: memcpy
// CHECK: call void @test2a
@@ -38,7 +38,7 @@ void test2(struct Test3S *q) {
// But make sure we don't generate a memcpy when we can guarantee alignment.
void fooey(void);
-// CHECK: define void @test3(
+// CHECK-LABEL: define void @test3(
// CHECK: alloca %struct.Test3S, align 8
// CHECK: call void @fooey
// CHECK-NOT: memcpy
diff --git a/test/CodeGen/c-strings.c b/test/CodeGen/c-strings.c
index 60a6b019129b..ff86619117ad 100644
--- a/test/CodeGen/c-strings.c
+++ b/test/CodeGen/c-strings.c
@@ -19,13 +19,13 @@ unsigned char align = 1;
void bar(const char *);
-// CHECK: define void @f0()
+// CHECK-LABEL: define void @f0()
void f0() {
bar("hello");
// CHECK: call void @bar({{.*}} @.str
}
-// CHECK: define void @f1()
+// CHECK-LABEL: define void @f1()
void f1() {
static char *x = "hello";
bar(x);
@@ -33,14 +33,14 @@ void f1() {
// CHECK: call void @bar(i8* [[T1:%.*]])
}
-// CHECK: define void @f2()
+// CHECK-LABEL: define void @f2()
void f2() {
static char x[] = "hello";
bar(x);
// CHECK: call void @bar({{.*}} @f2.x
}
-// CHECK: define void @f3()
+// CHECK-LABEL: define void @f3()
void f3() {
static char x[8] = "hello";
bar(x);
@@ -49,7 +49,7 @@ void f3() {
void gaz(void *);
-// CHECK: define void @f4()
+// CHECK-LABEL: define void @f4()
void f4() {
static struct s {
char *name;
diff --git a/test/CodeGen/c11atomics-ios.c b/test/CodeGen/c11atomics-ios.c
index d1c9b143306f..ad004fa4b2f3 100644
--- a/test/CodeGen/c11atomics-ios.c
+++ b/test/CodeGen/c11atomics-ios.c
@@ -6,7 +6,7 @@
// This work was done in pursuit of <rdar://13338582>.
-// CHECK: define arm_aapcscc void @testFloat(float*
+// CHECK-LABEL: define arm_aapcscc void @testFloat(float*
void testFloat(_Atomic(float) *fp) {
// CHECK: [[FP:%.*]] = alloca float*
// CHECK-NEXT: [[X:%.*]] = alloca float
@@ -102,8 +102,6 @@ void testStruct(_Atomic(S) *fp) {
// CHECK-NEXT: store [[S]]*
// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
-// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
@@ -114,8 +112,6 @@ void testStruct(_Atomic(S) *fp) {
// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
__c11_atomic_init(fp, (S){1,2,3,4});
-// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
@@ -169,7 +165,7 @@ void testPromotedStruct(_Atomic(PS) *fp) {
__c11_atomic_init(fp, (PS){1,2,3});
// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[T0]], i8 0, i32 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
@@ -183,7 +179,7 @@ void testPromotedStruct(_Atomic(PS) *fp) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i64*
// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
// CHECK-NEXT: [[T3:%.*]] = bitcast [[APS]]* [[TMP0]] to i64*
-// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 8
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 2
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP0]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8*
@@ -191,6 +187,8 @@ void testPromotedStruct(_Atomic(PS) *fp) {
PS f = *fp;
// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[TMP1]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[T1]], i8 0, i32 8, i32 8, i1 false)
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
diff --git a/test/CodeGen/c11atomics.c b/test/CodeGen/c11atomics.c
index 8d298af01919..5c761b137498 100644
--- a/test/CodeGen/c11atomics.c
+++ b/test/CodeGen/c11atomics.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-freebsd -std=c11 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv5-unknown-freebsd -std=c11 | FileCheck %s
// Test that we are generating atomicrmw instructions, rather than
// compare-exchange loops for common atomic ops. This makes a big difference
@@ -135,7 +135,7 @@ void testandeq(void)
s &= 42;
}
-// CHECK: define arm_aapcscc void @testFloat(float*
+// CHECK-LABEL: define arm_aapcscc void @testFloat(float*
void testFloat(_Atomic(float) *fp) {
// CHECK: [[FP:%.*]] = alloca float*
// CHECK-NEXT: [[X:%.*]] = alloca float
@@ -233,8 +233,6 @@ void testStruct(_Atomic(S) *fp) {
// CHECK-NEXT: store [[S]]*
// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
-// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
@@ -245,8 +243,6 @@ void testStruct(_Atomic(S) *fp) {
// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
__c11_atomic_init(fp, (S){1,2,3,4});
-// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
@@ -283,6 +279,9 @@ void testPromotedStruct(_Atomic(PS) *fp) {
// CHECK-NEXT: [[F:%.*]] = alloca [[PS:%.*]], align 2
// CHECK-NEXT: [[TMP0:%.*]] = alloca [[APS]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TMP2:%.*]] = alloca %struct.PS, align 2
+// CHECK-NEXT: [[TMP3:%.*]] = alloca [[APS]], align 8
// CHECK-NEXT: store [[APS]]*
// CHECK-NEXT: [[P:%.*]] = load [[APS]]** [[FP]]
@@ -298,7 +297,7 @@ void testPromotedStruct(_Atomic(PS) *fp) {
__c11_atomic_init(fp, (PS){1,2,3});
// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[T0]], i8 0, i32 8, i32 8, i1 false)
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
@@ -319,6 +318,8 @@ void testPromotedStruct(_Atomic(PS) *fp) {
PS f = *fp;
// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[TMP1]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[T1]], i8 0, i32 8, i32 8, i1 false)
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
@@ -328,6 +329,20 @@ void testPromotedStruct(_Atomic(PS) *fp) {
// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T4]], i8* [[T5]], i32 5)
*fp = f;
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]], align 4
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[APS]]* [[TMP3]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP3]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = bitcast %struct.PS* [[TMP2]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast %struct.PS* [[T0]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 6, i32 2, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds %struct.PS* [[TMP2]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = load i16* [[T0]], align 2
+// CHECK-NEXT: [[T2:%.*]] = sext i16 [[T1]] to i32
+// CHECK-NEXT: store i32 [[T2]], i32* [[A]], align 4
+ int a = ((PS)*fp).x;
+
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGen/capture-complex-expr-in-block.c b/test/CodeGen/capture-complex-expr-in-block.c
index 86c93d0252bc..83695a8b734d 100644
--- a/test/CodeGen/capture-complex-expr-in-block.c
+++ b/test/CodeGen/capture-complex-expr-in-block.c
@@ -12,7 +12,7 @@ int main ()
b();
}
-// CHECK: define internal void @__main_block_invoke
+// CHECK-LABEL: define internal void @__main_block_invoke
// CHECK: [[C1:%.*]] = alloca { double, double }, align 8
// CHECK: [[RP:%.*]] = getelementptr inbounds { double, double }* [[C1]], i32 0, i32 0
// CHECK-NEXT: [[R:%.*]] = load double* [[RP]]
diff --git a/test/CodeGen/captured-statements-nested.c b/test/CodeGen/captured-statements-nested.c
new file mode 100644
index 000000000000..d8ec74692adf
--- /dev/null
+++ b/test/CodeGen/captured-statements-nested.c
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o %t
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK1
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK2
+
+struct A {
+ int a;
+ float b;
+ char c;
+};
+
+void test_nest_captured_stmt(int param) {
+ int w;
+ // CHECK1: %struct.anon{{.*}} = type { i32*, i32* }
+ // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32* }
+ // CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32* }
+ #pragma clang __debug captured
+ {
+ int x;
+ int *y = &w;
+ #pragma clang __debug captured
+ {
+ struct A z;
+ #pragma clang __debug captured
+ {
+ w = x = z.a = 1;
+ *y = param;
+ z.b = 0.1f;
+ z.c = 'c';
+
+ // CHECK1: define internal void @__captured_stmt{{.*}}([[T]]
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1-NEXT: load %struct.A**
+ // CHECK1-NEXT: getelementptr inbounds %struct.A*
+ // CHECK1-NEXT: store i32 1
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 1
+ // CHECK1-NEXT: load i32**
+ // CHECK1-NEXT: store i32 1
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 0
+ // CHECK1-NEXT: load i32**
+ // CHECK1-NEXT: store i32 1
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 4
+ // CHECK1-NEXT: load i32**
+ // CHECK1-NEXT: load i32*
+ // CHECK1-NEXT: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 3
+ // CHECK1-NEXT: load i32***
+ // CHECK1-NEXT: load i32**
+ // CHECK1-NEXT: store i32
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1-NEXT: load %struct.A**
+ // CHECK1-NEXT: getelementptr inbounds %struct.A*
+ // CHECK1-NEXT: store float
+ //
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1-NEXT: load %struct.A**
+ // CHECK1-NEXT: getelementptr inbounds %struct.A*
+ // CHECK1-NEXT: store i8 99
+ }
+ }
+ }
+}
+
+void test_nest_block() {
+ __block int x;
+ int y;
+ ^{
+ int z;
+ x = z;
+ #pragma clang __debug captured
+ {
+ z = y; // OK
+ }
+ }();
+
+ // CHECK2: define internal void @{{.*}}test_nest_block_block_invoke
+ //
+ // CHECK2: [[Z:%[0-9a-z_]*]] = alloca i32
+ // CHECK2: alloca %struct.anon{{.*}}
+ //
+ // CHECK2: store i32
+ // CHECK2: store i32* [[Z]]
+ //
+ // CHECK2: getelementptr inbounds %struct.anon
+ // CHECK2-NEXT: getelementptr inbounds
+ // CHECK2-NEXT: store i32*
+ //
+ // CHECK2: call void @__captured_stmt
+
+ int a;
+ #pragma clang __debug captured
+ {
+ __block int b;
+ int c;
+ __block int d;
+ ^{
+ b = a;
+ b = c;
+ b = d;
+ }();
+ }
+
+ // CHECK2: alloca %struct.__block_byref_b
+ // CHECK2-NEXT: [[C:%[0-9a-z_]*]] = alloca i32
+ // CHECK2-NEXT: alloca %struct.__block_byref_d
+ //
+ // CHECK2: bitcast %struct.__block_byref_b*
+ // CHECK2-NEXT: store i8*
+ //
+ // CHECK2: [[CapA:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 7
+ //
+ // CHECK2: getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
+ // CHECK2: load i32**
+ // CHECK2: load i32*
+ // CHECK2: store i32 {{.*}}, i32* [[CapA]]
+ //
+ // CHECK2: [[CapC:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 8
+ // CHECK2-NEXT: [[Val:%[0-9a-z_]*]] = load i32* [[C]]
+ // CHECK2-NEXT: store i32 [[Val]], i32* [[CapC]]
+ //
+ // CHECK2: bitcast %struct.__block_byref_d*
+ // CHECK2-NEXT: store i8*
+}
diff --git a/test/CodeGen/captured-statements.c b/test/CodeGen/captured-statements.c
new file mode 100644
index 000000000000..c87c1873506b
--- /dev/null
+++ b/test/CodeGen/captured-statements.c
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -emit-llvm %s -o %t
+// 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
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
+
+int foo();
+int global;
+
+// Single statement
+void test1() {
+ int i = 0;
+ #pragma clang __debug captured
+ {
+ i++;
+ }
+ // CHECK-1: %struct.anon = type { i32* }
+ //
+ // CHECK-1: test1
+ // CHECK-1: alloca %struct.anon
+ // CHECK-1: getelementptr inbounds %struct.anon*
+ // CHECK-1: store i32* %i
+ // CHECK-1: call void @[[HelperName:__captured_stmt[0-9]+]]
+}
+
+// CHECK-1: define internal void @[[HelperName]](%struct.anon
+// CHECK-1: getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
+// CHECK-1: load i32**
+// CHECK-1: load i32*
+// CHECK-1: add nsw i32
+// CHECK-1: store i32
+
+// Compound statement with local variable
+void test2(int x) {
+ #pragma clang __debug captured
+ {
+ int i;
+ for (i = 0; i < x; i++)
+ foo();
+ }
+ // CHECK-2: test2
+ // CHECK-2-NOT: %i
+ // CHECK-2: call void @[[HelperName:__captured_stmt[0-9]+]]
+}
+
+// CHECK-2: define internal void @[[HelperName]]
+// CHECK-2-NOT: }
+// CHECK-2: %i = alloca i32
+
+// Capture array
+void test3() {
+ int arr[] = {1, 2, 3, 4, 5};
+ #pragma clang __debug captured
+ {
+ arr[2] = arr[1];
+ }
+ // CHECK-3: test3
+ // CHECK-3: alloca [5 x i32]
+ // CHECK-3: call void @__captured_stmt
+}
+
+void dont_capture_global() {
+ static int s;
+ extern int e;
+ #pragma clang __debug captured
+ {
+ global++;
+ s++;
+ e++;
+ }
+
+ // CHECK-GLOBALS: %[[Capture:struct\.anon[\.0-9]*]] = type {}
+ // CHECK-GLOBALS: call void @__captured_stmt[[HelperName:[0-9]+]](%[[Capture]]
+}
+
+// CHECK-GLOBALS: define internal void @__captured_stmt[[HelperName]]
+// CHECK-GLOBALS-NOT: ret
+// CHECK-GLOBALS: load i32* @global
+// CHECK-GLOBALS: load i32* @
+// CHECK-GLOBALS: load i32* @e
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index ebe39feea434..9be261467d2f 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -31,12 +31,12 @@ void foo() {
// CHECK-TRAP: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
// CHECK: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
- // CHECK-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(i8* %[[I8PTR]], i1 false)
+ // CHECK-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
// CHECK-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
// CHECK-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
// CHECK-TRAP: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
- // CHECK-TRAP-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(i8* %[[I8PTR]], i1 false)
+ // CHECK-TRAP-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
// CHECK-TRAP-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
// CHECK-TRAP-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
diff --git a/test/CodeGen/char-literal.c b/test/CodeGen/char-literal.c
index 237d4b2010ee..6fdf8b7c02b1 100644
--- a/test/CodeGen/char-literal.c
+++ b/test/CodeGen/char-literal.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CPP0X %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-CPP0X %s
#include <stddef.h>
diff --git a/test/CodeGen/complex-convert.c b/test/CodeGen/complex-convert.c
index aaa57a023a2f..e35be9c14917 100644
--- a/test/CodeGen/complex-convert.c
+++ b/test/CodeGen/complex-convert.c
@@ -21,7 +21,7 @@ void foo(signed char sc, unsigned char uc, signed long long sll,
_Complex unsigned char cuc1;
_Complex signed long long csll1;
_Complex unsigned long long cull1;
- // CHECK: define void @foo(
+ // CHECK-LABEL: define void @foo(
// CHECK: alloca i[[CHSIZE:[0-9]+]], align [[CHALIGN:[0-9]+]]
// CHECK-NEXT: alloca i[[CHSIZE]], align [[CHALIGN]]
// CHECK-NEXT: alloca i[[LLSIZE:[0-9]+]], align [[LLALIGN:[0-9]+]]
diff --git a/test/CodeGen/complex-indirect.c b/test/CodeGen/complex-indirect.c
index 0daa970e760a..cb84f7f49725 100644
--- a/test/CodeGen/complex-indirect.c
+++ b/test/CodeGen/complex-indirect.c
@@ -7,6 +7,6 @@
void a(int,int,int,int,int,int,__complex__ char);
void b(__complex__ char *y) { a(0,0,0,0,0,0,*y); }
-// CHECK: define void @b
+// CHECK-LABEL: define void @b
// CHECK: alloca { i8, i8 }*, align 8
// CHECK: call void @a(i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i16 {{.*}})
diff --git a/test/CodeGen/complex-init-list.c b/test/CodeGen/complex-init-list.c
index 99c1c62b5884..bc38e2caf21f 100644
--- a/test/CodeGen/complex-init-list.c
+++ b/test/CodeGen/complex-init-list.c
@@ -8,11 +8,11 @@ _Complex float x = { 1.0f, 1.0f/0.0f };
// CHECK: @x = global { float, float } { float 1.000000e+00, float 0x7FF0000000000000 }, align 4
_Complex float f(float x, float y) { _Complex float z = { x, y }; return z; }
-// CHECK: define <2 x float> @f
+// CHECK-LABEL: define <2 x float> @f
// CHECK: alloca { float, float }
// CHECK: alloca { float, float }
_Complex float f2(float x, float y) { return (_Complex float){ x, y }; }
-// CHECK: define <2 x float> @f2
+// CHECK-LABEL: define <2 x float> @f2
// CHECK: alloca { float, float }
// CHECK: alloca { float, float }
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
index 1212660e878d..206db253caa4 100644
--- a/test/CodeGen/complex.c
+++ b/test/CodeGen/complex.c
@@ -32,8 +32,7 @@ void test3() {
double Gr = __real g1;
cf += D;
- // FIXME: Currently unsupported!
- //D += cf;
+ D += cf;
cf /= g1;
g1 = g1 + D;
g1 = D + g1;
@@ -51,8 +50,7 @@ void test3int() {
i = __real ci1;
cs += i;
- // FIXME: Currently unsupported!
- //D += cf;
+ D += cf;
cs /= ci1;
ci1 = ci1 + i;
ci1 = i + ci1;
@@ -97,3 +95,6 @@ double t7(double _Complex c) {
void t8() {
__complex__ int *x = &(__complex__ int){1};
}
+
+const _Complex double test9const = 0;
+_Complex double test9func() { return test9const; }
diff --git a/test/CodeGen/compound-assign-overflow.c b/test/CodeGen/compound-assign-overflow.c
index e82061bdb7b3..15334294d47e 100644
--- a/test/CodeGen/compound-assign-overflow.c
+++ b/test/CodeGen/compound-assign-overflow.c
@@ -7,8 +7,7 @@
// CHECK: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}} @[[INT]]
// CHECK: @[[UINT:.*]] = private unnamed_addr constant { i16, i16, [15 x i8] } { i16 0, i16 10, [15 x i8] c"'unsigned int'\00" }
// CHECK: @[[LINE_200:.*]] = private unnamed_addr global {{.*}}, i32 200, i32 5 {{.*}} @[[UINT]]
-// CHECK: @[[DIVINT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
-// CHECK: @[[LINE_300:.*]] = private unnamed_addr global {{.*}}, i32 300, i32 5 {{.*}} @[[DIVINT]]
+// CHECK: @[[LINE_300:.*]] = private unnamed_addr global {{.*}}, i32 300, i32 5 {{.*}} @[[INT]]
int32_t x;
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
index e4bf962e12ad..458a78e1984b 100644
--- a/test/CodeGen/compound-literal.c
+++ b/test/CodeGen/compound-literal.c
@@ -12,7 +12,7 @@ struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
_Complex double * x = &(_Complex double){1.0f};
}
-// CHECK: define void @f()
+// CHECK-LABEL: define void @f()
void f() {
typedef struct S { int x,y; } S;
// CHECK: [[S:%[a-zA-Z0-9.]+]] = alloca [[STRUCT:%[a-zA-Z0-9.]+]],
@@ -33,7 +33,7 @@ void f() {
// CHECK-NEXT: ret void
}
-// CHECK: define i48 @g(
+// CHECK-LABEL: define i48 @g(
struct G { short x, y, z; };
struct G g(int x, int y, int z) {
// CHECK: [[RESULT:%.*]] = alloca [[G:%.*]], align 2
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 5f729b8df428..7d7ccae370dd 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -156,6 +156,6 @@ void g29() {
// CHECK: @g29.b = internal global [1 x i32] [i32 ptrtoint ([5 x i8]* @.str to i32)], align 4
// CHECK: @g29.c = internal global [1 x i32] [i32 97], align 4
static DCC_SRVR_NM a = { {"@"} };
- static int b[1] = { "asdf" };
+ static int b[1] = { "asdf" }; // expected-warning {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [5]'}}
static int c[1] = { L"a" };
}
diff --git a/test/CodeGen/convertvector.c b/test/CodeGen/convertvector.c
new file mode 100644
index 000000000000..2b23dd96e1b8
--- /dev/null
+++ b/test/CodeGen/convertvector.c
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm -x c++ %s -o - | FileCheck %s
+
+typedef double vector8double __attribute__((__vector_size__(64)));
+typedef float vector8float __attribute__((__vector_size__(32)));
+typedef long vector8long __attribute__((__vector_size__(64)));
+typedef short vector8short __attribute__((__vector_size__(16)));
+typedef unsigned long vector8ulong __attribute__((__vector_size__(64)));
+typedef unsigned short vector8ushort __attribute__((__vector_size__(16)));
+
+#ifdef __cplusplus
+#define BOOL bool
+#else
+#define BOOL _Bool
+#endif
+
+typedef BOOL vector8bool __attribute__((__ext_vector_type__(8)));
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+vector8float flt_trunc(vector8double x) {
+ return __builtin_convertvector(x, vector8float);
+ // CHECK-LABEL: @flt_trunc
+ // CHECK: fptrunc <8 x double> %{{[^ ]}} to <8 x float>
+}
+
+vector8double flt_ext(vector8float x) {
+ return __builtin_convertvector(x, vector8double);
+ // CHECK-LABEL: @flt_ext
+ // CHECK: fpext <8 x float> %{{[^ ]}} to <8 x double>
+}
+
+vector8bool flt_tobool(vector8float x) {
+ return __builtin_convertvector(x, vector8bool);
+ // CHECK-LABEL: @flt_tobool
+ // CHECK-NOT: fptoui <8 x float> %{{[^ ]}} to <8 x i1>
+ // CHECK: fcmp une <8 x float> %{{[^ ]}}, zeroinitializer
+}
+
+vector8long flt_tosi(vector8float x) {
+ return __builtin_convertvector(x, vector8long);
+ // CHECK-LABEL: @flt_tosi
+ // CHECK: fptosi <8 x float> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong flt_toui(vector8float x) {
+ return __builtin_convertvector(x, vector8ulong);
+ // CHECK-LABEL: @flt_toui
+ // CHECK: fptoui <8 x float> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong fltd_toui(vector8double x) {
+ return __builtin_convertvector(x, vector8ulong);
+ // CHECK-LABEL: @fltd_toui
+ // CHECK: fptoui <8 x double> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong int_zext(vector8ushort x) {
+ return __builtin_convertvector(x, vector8ulong);
+ // CHECK-LABEL: @int_zext
+ // CHECK: zext <8 x i16> %{{[^ ]}} to <8 x i64>
+}
+
+vector8long int_sext(vector8short x) {
+ return __builtin_convertvector(x, vector8long);
+ // CHECK-LABEL: @int_sext
+ // CHECK: sext <8 x i16> %{{[^ ]}} to <8 x i64>
+}
+
+vector8bool int_tobool(vector8short x) {
+ return __builtin_convertvector(x, vector8bool);
+ // CHECK-LABEL: @int_tobool
+ // CHECK-NOT: trunc <8 x i16> %{{[^ ]}} to <8 x i1>
+ // CHECK: icmp ne <8 x i16> %{{[^ ]}}, zeroinitializer
+}
+
+vector8float int_tofp(vector8short x) {
+ return __builtin_convertvector(x, vector8float);
+ // CHECK-LABEL: @int_tofp
+ // CHECK: sitofp <8 x i16> %{{[^ ]}} to <8 x float>
+}
+
+vector8float uint_tofp(vector8ushort x) {
+ return __builtin_convertvector(x, vector8float);
+ // CHECK-LABEL: @uint_tofp
+ // CHECK: uitofp <8 x i16> %{{[^ ]}} to <8 x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+template<typename T>
+T int_toT(vector8long x) {
+ return __builtin_convertvector(x, T);
+}
+
+extern "C" {
+ vector8double int_toT_fp(vector8long x) {
+ // CHECK-LABEL: @int_toT_fp
+ // CHECK: sitofp <8 x i64> %{{[^ ]}} to <8 x double>
+ return int_toT<vector8double>(x);
+ }
+}
+#else
+vector8double int_toT_fp(vector8long x) {
+ return __builtin_convertvector(x, vector8double);
+}
+#endif
+
diff --git a/test/CodeGen/cxx-default-arg.cpp b/test/CodeGen/cxx-default-arg.cpp
index 25b7c10ad10f..12e266640818 100644
--- a/test/CodeGen/cxx-default-arg.cpp
+++ b/test/CodeGen/cxx-default-arg.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm %s -o %t
-// Note: define CLANG_GENERATE_KNOWN_GOOD and compile to generate code
+// Note-LABEL: define CLANG_GENERATE_KNOWN_GOOD and compile to generate code
// that makes all of the defaulted arguments explicit. The resulting
// byte code should be identical to the compilation without
// CLANG_GENERATE_KNOWN_GOOD.
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
index 968386a90e98..c7d9ff916000 100644
--- a/test/CodeGen/darwin-string-literals.c
+++ b/test/CodeGen/darwin-string-literals.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix LSB %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LSB %s
// CHECK-LSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
// CHECK-LSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
@@ -6,7 +6,7 @@
// CHECK-LSB: @.str4 = internal unnamed_addr constant [6 x i16] [i16 116, i16 101, i16 115, i16 116, i16 8482, i16 0], align 2
-// RUN: %clang_cc1 -triple powerpc-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix MSB %s
+// RUN: %clang_cc1 -triple powerpc-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-MSB %s
// CHECK-MSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
// CHECK-MSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
diff --git a/test/CodeGen/debug-info-args.c b/test/CodeGen/debug-info-args.c
index 3312952a06cf..50b85411adb9 100644
--- a/test/CodeGen/debug-info-args.c
+++ b/test/CodeGen/debug-info-args.c
@@ -2,7 +2,7 @@
int somefunc(char *x, int y, double z) {
- // CHECK: metadata ![[NUM:[^,]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type
+ // CHECK: metadata ![[NUM:[^,]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type
// CHECK: ![[NUM]] = {{metadata !{metadata ![^,]*, metadata ![^,]*, metadata ![^,]*, metadata ![^,]*}}}
return y;
diff --git a/test/CodeGen/debug-info-block-decl.c b/test/CodeGen/debug-info-block-decl.c
new file mode 100644
index 000000000000..06c0e1ad3192
--- /dev/null
+++ b/test/CodeGen/debug-info-block-decl.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fblocks -emit-llvm -o - %s | FileCheck %s
+// Assignment and block entry should point to the same line.
+// rdar://problem/14039866
+
+// CHECK: define{{.*}}@main()
+// CHECK: store{{.*}}bitcast{{.*}}, !dbg ![[ASSIGNMENT:[0-9]+]]
+// CHECK: define {{.*}} @__main_block_invoke
+// CHECK: dbg ![[BLOCK_ENTRY:[0-9]+]]
+
+int main()
+{
+// CHECK: [[ASSIGNMENT]] = metadata !{i32 [[@LINE+2]],
+// CHECK: [[BLOCK_ENTRY]] = metadata !{i32 [[@LINE+1]],
+ int (^blockptr)(void) = ^(void) {
+ return 0;
+ };
+ return blockptr();
+}
+
diff --git a/test/CodeGen/debug-info-enum.c b/test/CodeGen/debug-info-enum.c
deleted file mode 100644
index b4a1ce0d3a22..000000000000
--- a/test/CodeGen/debug-info-enum.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -g %s -o %t
-// RUN: grep DW_TAG_enumeration_type %t
-// Radar 8195980
-
-enum vtag {
- VT_ONE
-};
-
-int foo(int i) {
- return i == VT_ONE;
-}
diff --git a/test/CodeGen/debug-info-limited.c b/test/CodeGen/debug-info-limited.c
new file mode 100644
index 000000000000..7333452ee568
--- /dev/null
+++ b/test/CodeGen/debug-info-limited.c
@@ -0,0 +1,11 @@
+// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s
+
+// Ensure we emit the full definition of 'foo' even though only its declaration
+// is needed, since C has no ODR to ensure that the definition will be the same
+// in whatever TU actually uses/requires the definition of 'foo'.
+// CHECK: ; [ DW_TAG_structure_type ] [foo] {{.*}} [def]
+
+struct foo {
+};
+
+struct foo *f;
diff --git a/test/CodeGen/debug-info-version.c b/test/CodeGen/debug-info-version.c
new file mode 100644
index 000000000000..3a74876de59b
--- /dev/null
+++ b/test/CodeGen/debug-info-version.c
@@ -0,0 +1,8 @@
+// RUN: %clang -g -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang -S -emit-llvm -o - %s | FileCheck %s --check-prefix=NO_DEBUG
+int main (void) {
+ return 0;
+}
+
+// CHECK: metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+// NO_DEBUG-NOT: metadata !"Debug Info Version"
diff --git a/test/CodeGen/debug-info-vla.c b/test/CodeGen/debug-info-vla.c
index 20fb6aace41f..7a8da960db47 100644
--- a/test/CodeGen/debug-info-vla.c
+++ b/test/CodeGen/debug-info-vla.c
@@ -1,9 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
-// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"vla", metadata {{.*}}, i32 7, metadata {{.*}}, i32 0, i32 0, i64 2} ; [ DW_TAG_auto_variable ]
-
void testVLAwithSize(int s)
{
+// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"vla", metadata {{.*}}, i32 [[@LINE+1]], metadata {{.*}}, i32 8192, i32 0} ; [ DW_TAG_auto_variable ] [vla] [line [[@LINE+1]]]
int vla[s];
int i;
for (i = 0; i < s; i++) {
diff --git a/test/CodeGen/decl-in-prototype.c b/test/CodeGen/decl-in-prototype.c
index 2c0fc4fc3b17..15efa6551bc3 100644
--- a/test/CodeGen/decl-in-prototype.c
+++ b/test/CodeGen/decl-in-prototype.c
@@ -2,13 +2,13 @@
const int AA = 5;
-// CHECK: define i32 @f1
+// CHECK-LABEL: define i32 @f1
int f1(enum {AA,BB} E) {
// CHECK: ret i32 1
return BB;
}
-// CHECK: define i32 @f2
+// CHECK-LABEL: define i32 @f2
int f2(enum {AA=7,BB} E) {
// CHECK: ret i32 7
return AA;
diff --git a/test/CodeGen/dependent-lib.c b/test/CodeGen/dependent-lib.c
new file mode 100644
index 000000000000..df4aaf073060
--- /dev/null
+++ b/test/CodeGen/dependent-lib.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
+// 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 = !{!0}
+// CHECK: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]]}
+// CHECK: ![[msvcrt]] = metadata !{metadata !"/DEFAULTLIB:msvcrt.lib"}
+
+// LINUX: !llvm.module.flags = !{!0}
+// LINUX: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
+// LINUX: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]]}
+// LINUX: ![[msvcrt]] = metadata !{metadata !"-lmsvcrt"}
+
+int f();
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
index 6561ce56d823..b11c67a45421 100644
--- a/test/CodeGen/designated-initializers.c
+++ b/test/CodeGen/designated-initializers.c
@@ -52,6 +52,93 @@ struct ds ds7 = {
.b = 3
};
+
+// <rdar://problem/10465114>
+struct overwrite_string_struct1 {
+ __typeof(L"foo"[0]) L[6];
+ int M;
+} overwrite_string1[] = { { { L"foo" }, 1 }, [0].L[2] = L'x'};
+// CHECK: [6 x i32] [i32 102, i32 111, i32 120, i32 0, i32 0, i32 0], i32 1
+struct overwrite_string_struct2 {
+ char L[6];
+ int M;
+} overwrite_string2[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [6 x i8] c"fox\00\00\00", i32 1
+struct overwrite_string_struct3 {
+ char L[3];
+ int M;
+} overwrite_string3[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [3 x i8] c"fox", i32 1
+struct overwrite_string_struct4 {
+ char L[3];
+ int M;
+} overwrite_string4[] = { { { "foobar" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [3 x i8] c"fox", i32 1
+struct overwrite_string_struct5 {
+ char L[6];
+ int M;
+} overwrite_string5[] = { { { "foo" }, 1 }, [0].L[4] = 'y'};
+// CHECK: [6 x i8] c"foo\00y\00", i32 1
+
+
+// CHECK: @u1 = {{.*}} { i32 65535 }
+union u_FFFF { char c; long l; } u1 = { .l = 0xFFFF };
+
+
+/// PR16644
+typedef union u_16644 {
+ struct s_16644 {
+ int zero;
+ int one;
+ int two;
+ int three;
+ } a;
+ int b[4];
+} union_16644_t;
+
+// CHECK: @union_16644_instance_0 = {{.*}} { i32 0, i32 0, i32 0, i32 3 } }
+union_16644_t union_16644_instance_0 =
+{
+ .b[0] = 0,
+ .a.one = 1,
+ .b[2] = 2,
+ .a.three = 3,
+};
+
+// CHECK: @union_16644_instance_1 = {{.*}} [i32 10, i32 0, i32 0, i32 0]
+union_16644_t union_16644_instance_1 =
+{
+ .a.three = 13,
+ .b[2] = 12,
+ .a.one = 11,
+ .b[0] = 10,
+};
+
+// CHECK: @union_16644_instance_2 = {{.*}} [i32 0, i32 20, i32 0, i32 0]
+union_16644_t union_16644_instance_2 =
+{
+ .a.one = 21,
+ .b[1] = 20,
+};
+
+// CHECK: @union_16644_instance_3 = {{.*}} { i32 0, i32 31, i32 0, i32 0 }
+union_16644_t union_16644_instance_3 =
+{
+ .b[1] = 30,
+ .a = {
+ .one = 31
+ }
+};
+
+// CHECK: @union_16644_instance_4 = {{.*}} { i32 5, i32 2, i32 0, i32 0 } {{.*}} [i32 0, i32 4, i32 0, i32 0]
+union_16644_t union_16644_instance_4[2] =
+{
+ [0].a.one = 2,
+ [1].a.zero = 3,
+ [0].a.zero = 5,
+ [1].b[1] = 4
+};
+
void test1(int argc, char **argv)
{
// CHECK: internal global %struct.foo { i8* null, i32 1024 }
diff --git a/test/CodeGen/dllimport-dllexport.c b/test/CodeGen/dllimport-dllexport.c
index c187503c5cfa..e70ac03f04c7 100644
--- a/test/CodeGen/dllimport-dllexport.c
+++ b/test/CodeGen/dllimport-dllexport.c
@@ -2,11 +2,11 @@
void __attribute__((dllimport)) foo1();
void __attribute__((dllexport)) foo1(){}
-// CHECK: define dllexport void @foo1
+// CHECK-LABEL: define dllexport void @foo1
void __attribute__((dllexport)) foo2();
// PR6269
__declspec(dllimport) void foo3();
__declspec(dllexport) void foo3(){}
-// CHECK: define dllexport void @foo3
+// CHECK-LABEL: define dllexport void @foo3
__declspec(dllexport) void foo4();
diff --git a/test/CodeGen/dwarf-version.c b/test/CodeGen/dwarf-version.c
new file mode 100644
index 000000000000..6c0f097a3b88
--- /dev/null
+++ b/test/CodeGen/dwarf-version.c
@@ -0,0 +1,14 @@
+// RUN: %clang -target x86_64-linux-gnu -gdwarf-2 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang -target x86_64-linux-gnu -gdwarf-3 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER3
+// RUN: %clang -target x86_64-linux-gnu -gdwarf-4 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
+// RUN: %clang -target x86_64-linux-gnu -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX
+// RUN: %clang -target x86_64-apple-darwin -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=DARWIN
+int main (void) {
+ return 0;
+}
+
+// CHECK: metadata !{i32 2, metadata !"Dwarf Version", i32 2}
+// VER3: metadata !{i32 2, metadata !"Dwarf Version", i32 3}
+// VER4: metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+// LINUX: metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+// DARWIN: metadata !{i32 2, metadata !"Dwarf Version", i32 2}
diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c
new file mode 100644
index 000000000000..eadbe15cfff0
--- /dev/null
+++ b/test/CodeGen/exceptions-seh.c
@@ -0,0 +1,18 @@
+// RUN: not %clang_cc1 -triple i686-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
+
+// This is a codegen test because we only emit the diagnostic when we start
+// generating code.
+
+int SaveDiv(int numerator, int denominator, int *res) {
+ int myres = 0;
+ __try {
+ myres = numerator / denominator;
+ } __except (1) {
+ return 0;
+ }
+ *res = myres;
+ return 1;
+}
+// CHECK-NOT error
+// CHECK: error: cannot compile this SEH __try yet
+// CHECK-NOT error
diff --git a/test/CodeGen/exceptions.c b/test/CodeGen/exceptions.c
index 311bc84e6a16..ae0af4dd9d84 100644
--- a/test/CodeGen/exceptions.c
+++ b/test/CodeGen/exceptions.c
@@ -5,8 +5,8 @@
void test1() {
extern void test1_helper(void (^)(int));
- // CHECK: define void @test1()
- // CHECK-ARM: define arm_aapcscc void @test1()
+ // CHECK-LABEL: define void @test1()
+ // CHECK-ARM-LABEL: define arm_aapcscc void @test1()
__block int x = 10;
diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c
index f8f28330ab77..2a2216946b25 100644
--- a/test/CodeGen/exprs.c
+++ b/test/CodeGen/exprs.c
@@ -121,7 +121,7 @@ void f10() {
}
// rdar://7530813
-// CHECK: define i32 @f11
+// CHECK-LABEL: define i32 @f11
int f11(long X) {
int A[100];
return A[X];
@@ -134,14 +134,14 @@ int f11(long X) {
int f12() {
// PR3150
- // CHECK: define i32 @f12
+ // CHECK-LABEL: define i32 @f12
// CHECK: ret i32 1
return 1||1;
}
// Make sure negate of fp uses -0.0 for proper -0 handling.
double f13(double X) {
- // CHECK: define double @f13
+ // CHECK-LABEL: define double @f13
// CHECK: fsub double -0.0
return -X;
}
@@ -151,7 +151,7 @@ void f14(struct s14 *a) {
(void) &*a;
}
-// CHECK: define void @f15
+// CHECK-LABEL: define void @f15
void f15() {
extern void f15_start(void);
f15_start();
@@ -168,7 +168,7 @@ void f15() {
}
// PR8967: this was crashing
-// CHECK: define void @f16()
+// CHECK-LABEL: define void @f16()
void f16() {
__extension__({ goto lbl; });
lbl:
@@ -176,7 +176,7 @@ void f16() {
}
// PR13704: negative increment in i128 is not preserved.
-// CHECK: define void @f17()
+// CHECK-LABEL: define void @f17()
void f17() {
extern void extfunc(__int128);
__int128 x = 2;
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index a9fa1511758b..0b78e97fbb36 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -286,3 +286,18 @@ int4 test15(uint4 V0) {
V = V || V;
return V;
}
+
+// CHECK: @test16
+void test16(float2 a, float2 b) {
+ float2 t0 = (a + b) / 2;
+}
+
+typedef char char16 __attribute__((ext_vector_type(16)));
+
+// CHECK: @test17
+void test17(void) {
+ char16 valA;
+ char valB;
+ char valC;
+ char16 destVal = valC ? valA : valB;
+}
diff --git a/test/CodeGen/fast-math.c b/test/CodeGen/fast-math.c
index 76cfbbd36548..4a513589ef4c 100644
--- a/test/CodeGen/fast-math.c
+++ b/test/CodeGen/fast-math.c
@@ -2,7 +2,7 @@
float f0, f1, f2;
void foo(void) {
- // CHECK: define void @foo()
+ // CHECK-LABEL: define void @foo()
// CHECK: fadd fast
f0 = f1 + f2;
diff --git a/test/CodeGen/finite-math.c b/test/CodeGen/finite-math.c
index bf39cea42cea..b0ee15759a5d 100644
--- a/test/CodeGen/finite-math.c
+++ b/test/CodeGen/finite-math.c
@@ -2,7 +2,7 @@
float f0, f1, f2;
void foo(void) {
- // CHECK: define void @foo()
+ // CHECK-LABEL: define void @foo()
// CHECK: fadd nnan ninf
f0 = f1 + f2;
diff --git a/test/CodeGen/fp16-ops.c b/test/CodeGen/fp16-ops.c
index e50651330670..a848ed16bd8a 100644
--- a/test/CodeGen/fp16-ops.c
+++ b/test/CodeGen/fp16-ops.c
@@ -7,7 +7,7 @@ volatile __fp16 h0 = 0.0, h1 = 1.0, h2;
volatile float f0, f1, f2;
void foo(void) {
- // CHECK: define void @foo()
+ // CHECK-LABEL: define void @foo()
// Check unary ops
diff --git a/test/CodeGen/func-return-member.c b/test/CodeGen/func-return-member.c
index 14ecac5d6bbb..efc30034e002 100644
--- a/test/CodeGen/func-return-member.c
+++ b/test/CodeGen/func-return-member.c
@@ -10,17 +10,17 @@ int X;
struct frk F;
float _Complex C;
-// CHECK: define void @bar
+// CHECK-LABEL: define void @bar
void bar(void) {
X = foo().f.f.x;
}
-// CHECK: define void @bun
+// CHECK-LABEL: define void @bun
void bun(void) {
F = foo().f.f;
}
-// CHECK: define void @ban
+// CHECK-LABEL: define void @ban
void ban(void) {
C = foo().f.f.c;
}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 25ca9163a191..47a056835571 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -24,7 +24,7 @@ void f6(signed short x) { }
void f7(unsigned short x) { }
-// CHECK: define void @f8()
+// CHECK-LABEL: define void @f8()
// CHECK: [[AI:#[0-9]+]]
// CHECK: {
void __attribute__((always_inline)) f8(void) { }
@@ -61,7 +61,7 @@ void f13(void){}
// Ensure that these get inlined: rdar://6853279
-// CHECK: define void @f14
+// CHECK-LABEL: define void @f14
// CHECK-NOT: @ai_
// CHECK: call void @f14_end
static __inline__ __attribute__((always_inline))
@@ -81,21 +81,21 @@ void f14(int a) {
}
// <rdar://problem/7102668> [irgen] clang isn't setting the optsize bit on functions
-// CHECK: define void @f15
+// CHECK-LABEL: define void @f15
// CHECK: [[NUW]]
// CHECK: {
void f15(void) {
}
// PR5254
-// CHECK: define void @f16
+// CHECK-LABEL: define void @f16
// CHECK: [[ALIGN:#[0-9]+]]
// CHECK: {
void __attribute__((force_align_arg_pointer)) f16(void) {
}
// PR11038
-// CHECK: define void @f18()
+// CHECK-LABEL: define void @f18()
// CHECK: [[RT:#[0-9]+]]
// CHECK: {
// CHECK: call void @f17()
@@ -106,7 +106,7 @@ __attribute__ ((returns_twice)) void f18(void) {
f17();
}
-// CHECK: define void @f19()
+// CHECK-LABEL: define void @f19()
// CHECK: {
// CHECK: call i32 @setjmp(i32* null)
// CHECK: [[RT_CALL]]
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index 8241a3d1674a..55f2d5f35ce3 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -20,14 +20,14 @@ int a(int);
int a() {return 1;}
void f0() {}
-// CHECK: define void @f0()
+// CHECK-LABEL: define void @f0()
void f1();
void f2(void) {
// CHECK: call void @f1()
f1(1, 2, 3);
}
-// CHECK: define void @f1()
+// CHECK-LABEL: define void @f1()
void f1() {}
// CHECK: define {{.*}} @f3{{\(\)|\(.*sret.*\)}}
@@ -54,7 +54,7 @@ void f8_callback(struct Incomplete);
void f8_user(void (*callback)(struct Incomplete));
void f8_test() {
f8_user(&f8_callback);
-// CHECK: define void @f8_test()
+// CHECK-LABEL: define void @f8_test()
// CHECK: call void @f8_user({{.*}}* bitcast (void ()* @f8_callback to {{.*}}*))
// CHECK: declare void @f8_user({{.*}}*)
// CHECK: declare void @f8_callback()
diff --git a/test/CodeGen/implicit-arg.c b/test/CodeGen/implicit-arg.c
index 52ab58ec9801..c25f034a1a38 100644
--- a/test/CodeGen/implicit-arg.c
+++ b/test/CodeGen/implicit-arg.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o -
+// RUN: %clang_cc1 %s -emit-llvm -o -
// RUN: %clang_cc1 %s -emit-llvm -O1 -o -
// rdar://6518089
diff --git a/test/CodeGen/incomplete-function-type.c b/test/CodeGen/incomplete-function-type.c
index b6309472a5bc..fc216dae4a71 100644
--- a/test/CodeGen/incomplete-function-type.c
+++ b/test/CodeGen/incomplete-function-type.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
// CHECK: ModuleID
// CHECK-NOT: opaque
-// CHECK: define void @f0
+// CHECK-LABEL: define void @f0
enum teste1 test1f(void), (*test1)(void) = test1f;
struct tests2 test2f(), (*test2)() = test2f;
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 442b38000b3c..70ab696b64ee 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -1,55 +1,64 @@
// RUN: echo "GNU89 tests:"
-// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=gnu89 | FileCheck %s --check-prefix=CHECK1
-// CHECK1: define i32 @foo()
-// CHECK1: define i32 @bar()
-// CHECK1: define void @unreferenced1()
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=gnu89 | FileCheck %s --check-prefix=CHECK1
+// CHECK1-LABEL: define i32 @foo()
+// CHECK1-LABEL: define i32 @bar()
+// CHECK1-LABEL: define void @unreferenced1()
// CHECK1-NOT: unreferenced2
-// CHECK1: define void @gnu_inline()
-// CHECK1: define i32 @test1
-// CHECK1: define i32 @test2
-// CHECK1: define void @test3()
-// CHECK1: define available_externally i32 @test4
-// CHECK1: define available_externally i32 @test5
-// CHECK1: define i32 @test6
-// CHECK1: define void @test7
+// CHECK1-LABEL: define void @gnu_inline()
+// CHECK1-LABEL: define i32 @test1
+// CHECK1-LABEL: define i32 @test2
+// CHECK1-LABEL: define void @test3()
+// CHECK1-LABEL: define available_externally i32 @test4
+// CHECK1-LABEL: define available_externally i32 @test5
+// CHECK1-LABEL: define i32 @test6
+// CHECK1-LABEL: define void @test7
// CHECK1: define i{{..}} @strlcpy
// CHECK1-NOT: test9
-// CHECK1: define void @testA
-// CHECK1: define void @testB
-// CHECK1: define void @testC
-// CHECK1: define available_externally void @gnu_ei_inline()
-// CHECK1: define available_externally i32 @ei()
+// CHECK1-LABEL: define void @testA
+// CHECK1-LABEL: define void @testB
+// CHECK1-LABEL: define void @testC
+// CHECK1-LABEL: define available_externally void @gnu_ei_inline()
+// CHECK1-LABEL: define available_externally i32 @ei()
// RUN: echo "C99 tests:"
-// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=gnu99 | FileCheck %s --check-prefix=CHECK2
-// CHECK2: define i32 @ei()
-// CHECK2: define i32 @bar()
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=gnu99 | FileCheck %s --check-prefix=CHECK2
+// CHECK2-LABEL: define i32 @ei()
+// CHECK2-LABEL: define i32 @bar()
// CHECK2-NOT: unreferenced1
-// CHECK2: define void @unreferenced2()
-// CHECK2: define void @gnu_inline()
-// CHECK2: define i32 @test1
-// CHECK2: define i32 @test2
-// CHECK2: define void @test3
-// CHECK2: define available_externally i32 @test4
-// CHECK2: define available_externally i32 @test5
-// CHECK2: define i32 @test6
-// CHECK2: define void @test7
+// CHECK2-LABEL: define void @unreferenced2()
+// CHECK2-LABEL: define void @gnu_inline()
+// CHECK2-LABEL: define i32 @test1
+// CHECK2-LABEL: define i32 @test2
+// CHECK2-LABEL: define void @test3
+// CHECK2-LABEL: define available_externally i32 @test4
+// CHECK2-LABEL: define available_externally i32 @test5
+// CHECK2-LABEL: define i32 @test6
+// CHECK2-LABEL: define void @test7
// CHECK2: define available_externally i{{..}} @strlcpy
-// CHECK2: define void @test9
-// CHECK2: define void @testA
-// CHECK2: define void @testB
-// CHECK2: define void @testC
-// CHECK2: define available_externally void @gnu_ei_inline()
-// CHECK2: define available_externally i32 @foo()
+// CHECK2-LABEL: define void @test9
+// CHECK2-LABEL: define void @testA
+// CHECK2-LABEL: define void @testB
+// CHECK2-LABEL: define void @testC
+// CHECK2-LABEL: define available_externally void @gnu_ei_inline()
+// CHECK2-LABEL: define available_externally i32 @foo()
// RUN: echo "C++ tests:"
-// RUN: %clang -x c++ %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=c++98 | FileCheck %s --check-prefix=CHECK3
-// CHECK3: define i32 @_Z3barv()
-// CHECK3: define linkonce_odr i32 @_Z3foov()
+// RUN: %clang_cc1 -x c++ %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=c++98 | FileCheck %s --check-prefix=CHECK3
+// CHECK3-LABEL: define i32 @_Z3barv()
+// CHECK3-LABEL: define linkonce_odr i32 @_Z3foov()
// CHECK3-NOT: unreferenced
-// CHECK3: define void @_Z10gnu_inlinev()
-// CHECK3: define available_externally void @_Z13gnu_ei_inlinev()
-// CHECK3: define linkonce_odr i32 @_Z2eiv()
+// CHECK3-LABEL: define void @_Z10gnu_inlinev()
+// CHECK3-LABEL: define available_externally void @_Z13gnu_ei_inlinev()
+// CHECK3-LABEL: define linkonce_odr i32 @_Z2eiv()
+
+// RUN: echo "MS C Mode tests:"
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=c99 -fms-compatibility | FileCheck %s --check-prefix=CHECK4
+// CHECK4-LABEL: define i32 @bar()
+// CHECK4-LABEL: define void @gnu_inline()
+// CHECK4-LABEL: define available_externally void @gnu_ei_inline()
+// CHECK4-LABEL: define linkonce_odr i32 @foo()
+// CHECK4-NOT: unreferenced
+// CHECK4-LABEL: define linkonce_odr i32 @ei()
extern __inline int ei() { return 123; }
diff --git a/test/CodeGen/inline2.c b/test/CodeGen/inline2.c
index fca4fff7ca8d..670ae201f9ba 100644
--- a/test/CodeGen/inline2.c
+++ b/test/CodeGen/inline2.c
@@ -1,60 +1,60 @@
-// RUN: %clang_cc1 -O1 -std=gnu89 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix GNU89 %s
-// RUN: %clang_cc1 -O1 -std=c99 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix C99 %s
+// RUN: %clang_cc1 -O1 -std=gnu89 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-GNU89 %s
+// RUN: %clang_cc1 -O1 -std=c99 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-C99 %s
-// CHECK-GNU89: define i32 @f0()
-// CHECK-C99: define i32 @f0()
+// CHECK-GNU89-LABEL: define i32 @f0()
+// CHECK-C99-LABEL: define i32 @f0()
int f0(void);
int f0(void) { return 0; }
-// CHECK-GNU89: define i32 @f1()
-// CHECK-C99: define i32 @f1()
+// CHECK-GNU89-LABEL: define i32 @f1()
+// CHECK-C99-LABEL: define i32 @f1()
inline int f1(void);
int f1(void) { return 0; }
-// CHECK-GNU89: define i32 @f2()
-// CHECK-C99: define i32 @f2()
+// CHECK-GNU89-LABEL: define i32 @f2()
+// CHECK-C99-LABEL: define i32 @f2()
int f2(void);
inline int f2(void) { return 0; }
-// CHECK-GNU89: define i32 @f3()
-// CHECK-C99: define i32 @f3()
+// CHECK-GNU89-LABEL: define i32 @f3()
+// CHECK-C99-LABEL: define i32 @f3()
extern inline int f3(void);
int f3(void) { return 0; }
-// CHECK-GNU89: define i32 @f5()
-// CHECK-C99: define i32 @f5()
+// CHECK-GNU89-LABEL: define i32 @f5()
+// CHECK-C99-LABEL: define i32 @f5()
extern inline int f5(void);
inline int f5(void) { return 0; }
-// CHECK-GNU89: define i32 @f6()
-// CHECK-C99: define i32 @f6()
+// CHECK-GNU89-LABEL: define i32 @f6()
+// CHECK-C99-LABEL: define i32 @f6()
inline int f6(void);
extern inline int f6(void) { return 0; }
-// CHECK-GNU89: define i32 @f7()
-// CHECK-C99: define i32 @f7()
+// CHECK-GNU89-LABEL: define i32 @f7()
+// CHECK-C99-LABEL: define i32 @f7()
extern inline int f7(void);
extern int f7(void) { return 0; }
-// CHECK-GNU89: define i32 @fA()
+// CHECK-GNU89-LABEL: define i32 @fA()
inline int fA(void) { return 0; }
-// CHECK-GNU89: define available_externally i32 @f4()
-// CHECK-C99: define i32 @f4()
+// CHECK-GNU89-LABEL: define available_externally i32 @f4()
+// CHECK-C99-LABEL: define i32 @f4()
int f4(void);
extern inline int f4(void) { return 0; }
-// CHECK-GNU89: define available_externally i32 @f8()
-// CHECK-C99: define i32 @f8()
+// CHECK-GNU89-LABEL: define available_externally i32 @f8()
+// CHECK-C99-LABEL: define i32 @f8()
extern int f8(void);
extern inline int f8(void) { return 0; }
-// CHECK-GNU89: define available_externally i32 @f9()
-// CHECK-C99: define i32 @f9()
+// CHECK-GNU89-LABEL: define available_externally i32 @f9()
+// CHECK-C99-LABEL: define i32 @f9()
extern inline int f9(void);
extern inline int f9(void) { return 0; }
-// CHECK-C99: define available_externally i32 @fA()
+// CHECK-C99-LABEL: define available_externally i32 @fA()
int test_all() {
return f0() + f1() + f2() + f3() + f4() + f5() + f6() + f7() + f8() + f9()
diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c
index ed2dede7814c..a007960dec83 100644
--- a/test/CodeGen/integer-overflow.c
+++ b/test/CodeGen/integer-overflow.c
@@ -8,9 +8,9 @@
// Tests for signed integer overflow stuff.
// rdar://7432000 rdar://7221421
void test1() {
- // DEFAULT: define void @test1
- // WRAPV: define void @test1
- // TRAPV: define void @test1
+ // DEFAULT-LABEL: define void @test1
+ // WRAPV-LABEL: define void @test1
+ // TRAPV-LABEL: define void @test1
extern volatile int f11G, a, b;
// DEFAULT: add nsw i32
diff --git a/test/CodeGen/le32-arguments.c b/test/CodeGen/le32-arguments.c
index 2cbbc0fbea45..d26640e6927a 100644
--- a/test/CodeGen/le32-arguments.c
+++ b/test/CodeGen/le32-arguments.c
@@ -2,7 +2,7 @@
// Basic argument/attribute tests for le32/PNaCl
-// CHECK: define void @f0(i32 %i, i32 %j, double %k)
+// CHECK-LABEL: define void @f0(i32 %i, i32 %j, double %k)
void f0(int i, long j, double k) {}
typedef struct {
@@ -10,27 +10,27 @@ typedef struct {
int bb;
} s1;
// Structs should be passed byval and not split up
-// CHECK: define void @f1(%struct.s1* byval %i)
+// CHECK-LABEL: define void @f1(%struct.s1* byval %i)
void f1(s1 i) {}
typedef struct {
int cc;
} s2;
// Structs should be returned sret and not simplified by the frontend
-// CHECK: define void @f2(%struct.s2* noalias sret %agg.result)
+// CHECK-LABEL: define void @f2(%struct.s2* noalias sret %agg.result)
s2 f2() {
s2 foo;
return foo;
}
-// CHECK: define void @f3(i64 %i)
+// CHECK-LABEL: define void @f3(i64 %i)
void f3(long long i) {}
// i8/i16 should be signext, i32 and higher should not
-// CHECK: define void @f4(i8 signext %a, i16 signext %b)
+// CHECK-LABEL: define void @f4(i8 signext %a, i16 signext %b)
void f4(char a, short b) {}
-// CHECK: define void @f5(i8 zeroext %a, i16 zeroext %b)
+// CHECK-LABEL: define void @f5(i8 zeroext %a, i16 zeroext %b)
void f5(unsigned char a, unsigned short b) {}
@@ -40,7 +40,7 @@ enum my_enum {
ENUM3,
};
// Enums should be treated as the underlying i32
-// CHECK: define void @f6(i32 %a)
+// CHECK-LABEL: define void @f6(i32 %a)
void f6(enum my_enum a) {}
union simple_union {
@@ -48,7 +48,7 @@ union simple_union {
char b;
};
// Unions should be passed as byval structs
-// CHECK: define void @f7(%union.simple_union* byval %s)
+// CHECK-LABEL: define void @f7(%union.simple_union* byval %s)
void f7(union simple_union s) {}
typedef struct {
@@ -57,5 +57,5 @@ typedef struct {
int b8 : 8;
} bitfield1;
// Bitfields should be passed as byval structs
-// CHECK: define void @f8(%struct.bitfield1* byval %bf1)
+// CHECK-LABEL: define void @f8(%struct.bitfield1* byval %bf1)
void f8(bitfield1 bf1) {}
diff --git a/test/CodeGen/le32-libcall-pow.c b/test/CodeGen/le32-libcall-pow.c
new file mode 100644
index 000000000000..1b8a7a33a562
--- /dev/null
+++ b/test/CodeGen/le32-libcall-pow.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fno-math-builtin -fmath-errno -emit-llvm -o - %s -triple le32-unknown-nacl | FileCheck %s
+// RUN: %clang_cc1 -fno-math-builtin -emit-llvm -o - %s -triple le32-unknown-nacl | FileCheck %s
+
+// le32 (PNaCl) never generates intrinsics for pow calls, with or without
+// errno, when the -fno-math-builtin flag is passed to -cc1. A separate test
+// makes sure this flag is indeed passed for le32.
+
+float powf(float, float);
+double pow(double, double);
+long double powl(long double, long double);
+
+// CHECK-LABEL: define void @test_pow
+void test_pow(float a0, double a1, long double a2) {
+ // CHECK: call float @powf
+ float l0 = powf(a0, a0);
+
+ // CHECK: call double @pow
+ double l1 = pow(a1, a1);
+
+ // CHECK: call double @powl
+ long double l2 = powl(a2, a2);
+}
+
+// CHECK: declare float @powf(float, float)
+// CHECK: declare double @pow(double, double)
+// CHECK: declare double @powl(double, double)
+
diff --git a/test/CodeGen/libcall-declarations.c b/test/CodeGen/libcall-declarations.c
index d07590ff1171..6442e29bd86e 100644
--- a/test/CodeGen/libcall-declarations.c
+++ b/test/CodeGen/libcall-declarations.c
@@ -1,194 +1,596 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=CHECK-NOERRNO
// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -o - -emit-llvm -fmath-errno %s | FileCheck %s -check-prefix=CHECK-ERRNO
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -S -o - -emit-llvm -x c++ %s | FileCheck %s -check-prefix=CHECK-NOERRNO
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -o - -emit-llvm -x c++ -fmath-errno %s | FileCheck %s -check-prefix=CHECK-ERRNO
// Prototypes.
+#ifdef __cplusplus
+extern "C" {
+#endif
+double atan2(double, double);
+float atan2f(float, float);
+long double atan2l(long double, long double);
+int abs(int);
+long int labs(long int);
+long long int llabs(long long int);
+double copysign(double, double);
+float copysignf(float, float);
+long double copysignl(long double, long double);
+double fabs(double);
+float fabsf(float);
+long double fabsl(long double);
+double fmod(double, double);
+float fmodf(float, float);
+long double fmodl(long double, long double);
+double frexp(double, int *);
+float frexpf(float, int *);
+long double frexpl(long double, int *);
+double ldexp(double, int);
+float ldexpf(float, int);
+long double ldexpl(long double, int);
+double modf(double, double *);
+float modff(float, float *);
+long double modfl(long double, long double *);
+double nan(const char *);
+float nanf(const char *);
+long double nanl(const char *);
+double pow(double, double);
+float powf(float, float);
+long double powl(long double, long double);
double acos(double);
-long double acosl(long double);
float acosf(float);
+long double acosl(long double);
+double acosh(double);
+float acoshf(float);
+long double acoshl(long double);
double asin(double);
-long double asinl(long double);
float asinf(float);
+long double asinl(long double);
+double asinh(double);
+float asinhf(float);
+long double asinhl(long double);
double atan(double);
-long double atanl(long double);
float atanf(float);
-double atan2(double, double);
-long double atan2l(long double, long double);
-float atan2f(float, float);
+long double atanl( long double);
+double atanh(double);
+float atanhf(float);
+long double atanhl(long double);
+double cbrt(double);
+float cbrtf(float);
+long double cbrtl(long double);
double ceil(double);
-long double ceill(long double);
float ceilf(float);
-double copysign(double, double);
-long double copysignl(long double, long double);
-float copysignf(float, float);
+long double ceill(long double);
double cos(double);
-long double cosl(long double);
float cosf(float);
+long double cosl(long double);
+double cosh(double);
+float coshf(float);
+long double coshl(long double);
+double erf(double);
+float erff(float);
+long double erfl(long double);
+double erfc(double);
+float erfcf(float);
+long double erfcl(long double);
double exp(double);
-long double expl(long double);
float expf(float);
+long double expl(long double);
double exp2(double);
-long double exp2l(long double);
float exp2f(float);
-double fabs(double);
-long double fabsl(long double);
-float fabsf(float);
+long double exp2l(long double);
+double expm1(double);
+float expm1f(float);
+long double expm1l(long double);
+double fdim(double, double);
+float fdimf(float, float);
+long double fdiml(long double, long double);
double floor(double);
-long double floorl(long double);
float floorf(float);
+long double floorl(long double);
double fma(double, double, double);
-long double fmal(long double, long double, long double);
float fmaf(float, float, float);
+long double fmal(long double, long double, long double);
double fmax(double, double);
-long double fmaxl(long double, long double);
float fmaxf(float, float);
+long double fmaxl(long double, long double);
double fmin(double, double);
-long double fminl(long double, long double);
float fminf(float, float);
+long double fminl(long double, long double);
+double hypot(double, double);
+float hypotf(float, float);
+long double hypotl(long double, long double);
+int ilogb(double);
+int ilogbf(float);
+int ilogbl(long double);
+double lgamma(double);
+float lgammaf(float);
+long double lgammal(long double);
+long long int llrint(double);
+long long int llrintf(float);
+long long int llrintl(long double);
+long long int llround(double);
+long long int llroundf(float);
+long long int llroundl(long double);
double log(double);
-long double logl(long double);
float logf(float);
+long double logl(long double);
+double log10(double);
+float log10f(float);
+long double log10l(long double);
+double log1p(double);
+float log1pf(float);
+long double log1pl(long double);
double log2(double);
-long double log2l(long double);
float log2f(float);
+long double log2l(long double);
+double logb(double);
+float logbf(float);
+long double logbl(long double);
+long int lrint(double);
+long int lrintf(float);
+long int lrintl(long double);
+long int lround(double);
+long int lroundf(float);
+long int lroundl(long double);
double nearbyint(double);
-long double nearbyintl(long double);
float nearbyintf(float);
-double pow(double, double);
-long double powl(long double, long double);
-float powf(float, float);
+long double nearbyintl(long double);
+double nextafter(double, double);
+float nextafterf(float, float);
+long double nextafterl(long double, long double);
+double nexttoward(double, long double);
+float nexttowardf(float, long double);
+long double nexttowardl(long double, long double);
+double remainder(double, double);
+float remainderf(float, float);
+long double remainderl(long double, long double);
double rint(double);
-long double rintl(long double);
float rintf(float);
+long double rintl(long double);
double round(double);
-long double roundl(long double);
float roundf(float);
+long double roundl(long double);
+double scalbln(double, long int exp);
+float scalblnf(float, long int exp);
+long double scalblnl(long double, long int exp);
+double scalbn(double, int exp);
+float scalbnf(float, int exp);
+long double scalbnl(long double, int exp);
double sin(double);
-long double sinl(long double);
float sinf(float);
+long double sinl(long double);
+double sinh(double);
+float sinhf(float);
+long double sinhl(long double);
double sqrt(double);
-long double sqrtl(long double);
float sqrtf(float);
+long double sqrtl(long double);
double tan(double);
-long double tanl(long double);
float tanf(float);
+long double tanl(long double);
+double tanh(double);
+float tanhf(float);
+long double tanhl(long double);
+double tgamma(double);
+float tgammaf(float);
+long double tgammal(long double);
double trunc(double);
-long double truncl(long double);
float truncf(float);
+long double truncl(long double);
+double cabs(double _Complex);
+float cabsf(float _Complex);
+long double cabsl(long double _Complex);
+double _Complex cacos(double _Complex);
+float _Complex cacosf(float _Complex);
+long double _Complex cacosl(long double _Complex);
+double _Complex cacosh(double _Complex);
+float _Complex cacoshf(float _Complex);
+long double _Complex cacoshl(long double _Complex);
+double carg(double _Complex);
+float cargf(float _Complex);
+long double cargl(long double _Complex);
+double _Complex casin(double _Complex);
+float _Complex casinf(float _Complex);
+long double _Complex casinl(long double _Complex);
+double _Complex casinh(double _Complex);
+float _Complex casinhf(float _Complex);
+long double _Complex casinhl(long double _Complex);
+double _Complex catan(double _Complex);
+float _Complex catanf(float _Complex);
+long double _Complex catanl(long double _Complex);
+double _Complex catanh(double _Complex);
+float _Complex catanhf(float _Complex);
+long double _Complex catanhl(long double _Complex);
+double _Complex ccos(double _Complex);
+float _Complex ccosf(float _Complex);
+long double _Complex ccosl(long double _Complex);
+double _Complex ccosh(double _Complex);
+float _Complex ccoshf(float _Complex);
+long double _Complex ccoshl(long double _Complex);
+double _Complex cexp(double _Complex);
+float _Complex cexpf(float _Complex);
+long double _Complex cexpl(long double _Complex);
+double cimag(double _Complex);
+float cimagf(float _Complex);
+long double cimagl(long double _Complex);
+double _Complex conj(double _Complex);
+float _Complex conjf(float _Complex);
+long double _Complex conjl(long double _Complex);
+double _Complex clog(double _Complex);
+float _Complex clogf(float _Complex);
+long double _Complex clogl(long double _Complex);
+double _Complex cproj(double _Complex);
+float _Complex cprojf(float _Complex);
+long double _Complex cprojl(long double _Complex);
+double _Complex cpow(double _Complex, _Complex double);
+float _Complex cpowf(float _Complex, _Complex float);
+long double _Complex cpowl(long double _Complex, _Complex long double);
+double creal(double _Complex);
+float crealf(float _Complex);
+long double creall(long double _Complex);
+double _Complex csin(double _Complex);
+float _Complex csinf(float _Complex);
+long double _Complex csinl(long double _Complex);
+double _Complex csinh(double _Complex);
+float _Complex csinhf(float _Complex);
+long double _Complex csinhl(long double _Complex);
+double _Complex csqrt(double _Complex);
+float _Complex csqrtf(float _Complex);
+long double _Complex csqrtl(long double _Complex);
+double _Complex ctan(double _Complex);
+float _Complex ctanf(float _Complex);
+long double _Complex ctanl(long double _Complex);
+double _Complex ctanh(double _Complex);
+float _Complex ctanhf(float _Complex);
+long double _Complex ctanhl(long double _Complex);
+#ifdef __cplusplus
+}
+#endif
// Force emission of the declare statements.
+#define F(x) ((void*)x)
void *use[] = {
- acos, acosl, acosf, asin, asinl, asinf, atan, atanl, atanf, atan2, atan2l,
- atan2f, ceil, ceill, ceilf, copysign, copysignl, copysignf, cos, cosl, cosf,
- exp, expl, expf, exp2, exp2l, exp2f, fabs, fabsl, fabsf, floor, floorl,
- floorf, fma, fmal, fmaf, fmax, fmaxl, fmaxf, fmin, fminl, fminf, log, logl,
- logf, log2, log2l, log2f, nearbyint, nearbyintl, nearbyintf, pow, powl, powf,
- rint, rintl, rintf, round, roundl, roundf, sin, sinl, sinf, sqrt, sqrtl,
- sqrtf, tan, tanl, tanf, trunc, truncl, truncf
+ F(atan2), F(atan2f), F(atan2l), F(abs), F(labs),
+ F(llabs), F(copysign), F(copysignf), F(copysignl), F(fabs),
+ F(fabsf), F(fabsl), F(fmod), F(fmodf), F(fmodl),
+ F(frexp), F(frexpf), F(frexpl), F(ldexp), F(ldexpf),
+ F(ldexpl), F(modf), F(modff), F(modfl), F(nan),
+ F(nanf), F(nanl), F(pow), F(powf), F(powl),
+ F(acos), F(acosf), F(acosl), F(acosh), F(acoshf),
+ F(acoshl), F(asin), F(asinf), F(asinl), F(asinh),
+ F(asinhf), F(asinhl), F(atan), F(atanf), F(atanl),
+ F(atanh), F(atanhf), F(atanhl), F(cbrt), F(cbrtf),
+ F(cbrtl), F(ceil), F(ceilf), F(ceill), F(cos),
+ F(cosf), F(cosl), F(cosh), F(coshf), F(coshl),
+ F(erf), F(erff), F(erfl), F(erfc), F(erfcf),
+ F(erfcl), F(exp), F(expf), F(expl), F(exp2),
+ F(exp2f), F(exp2l), F(expm1), F(expm1f), F(expm1l),
+ F(fdim), F(fdimf), F(fdiml), F(floor), F(floorf),
+ F(floorl), F(fma), F(fmaf), F(fmal), F(fmax),
+ F(fmaxf), F(fmaxl), F(fmin), F(fminf), F(fminl),
+ F(hypot), F(hypotf), F(hypotl), F(ilogb), F(ilogbf),
+ F(ilogbl), F(lgamma), F(lgammaf), F(lgammal), F(llrint),
+ F(llrintf), F(llrintl), F(llround), F(llroundf), F(llroundl),
+ F(log), F(logf), F(logl), F(log10), F(log10f),
+ F(log10l), F(log1p), F(log1pf), F(log1pl), F(log2),
+ F(log2f), F(log2l), F(logb), F(logbf), F(logbl),
+ F(lrint), F(lrintf), F(lrintl), F(lround), F(lroundf),
+ F(lroundl), F(nearbyint), F(nearbyintf), F(nearbyintl), F(nextafter),
+ F(nextafterf), F(nextafterl), F(nexttoward), F(nexttowardf), F(nexttowardl),
+ F(remainder), F(remainderf), F(remainderl), F(rint), F(rintf),
+ F(rintl), F(round), F(roundf), F(roundl), F(scalbln),
+ F(scalblnf), F(scalblnl), F(scalbn), F(scalbnf), F(scalbnl),
+ F(sin), F(sinf), F(sinl), F(sinh), F(sinhf),
+ F(sinhl), F(sqrt), F(sqrtf), F(sqrtl), F(tan),
+ F(tanf), F(tanl), F(tanh), F(tanhf), F(tanhl),
+ F(tgamma), F(tgammaf), F(tgammal), F(trunc), F(truncf),
+ F(truncl), F(cabs), F(cabsf), F(cabsl), F(cacos),
+ F(cacosf), F(cacosl), F(cacosh), F(cacoshf), F(cacoshl),
+ F(carg), F(cargf), F(cargl), F(casin), F(casinf),
+ F(casinl), F(casinh), F(casinhf), F(casinhl), F(catan),
+ F(catanf), F(catanl), F(catanh), F(catanhf), F(catanhl),
+ F(ccos), F(ccosf), F(ccosl), F(ccosh), F(ccoshf),
+ F(ccoshl), F(cexp), F(cexpf), F(cexpl), F(cimag),
+ F(cimagf), F(cimagl), F(conj), F(conjf), F(conjl),
+ F(clog), F(clogf), F(clogl), F(cproj), F(cprojf),
+ F(cprojl), F(cpow), F(cpowf), F(cpowl), F(creal),
+ F(crealf), F(creall), F(csin), F(csinf), F(csinl),
+ F(csinh), F(csinhf), F(csinhl), F(csqrt), F(csqrtf),
+ F(csqrtl), F(ctan), F(ctanf), F(ctanl), F(ctanh),
+ F(ctanhf), F(ctanhl)
};
-// CHECK-NOERRNO: declare double @acos(double) [[NUW:#[0-9]+]]
-// CHECK-NOERRNO: declare x86_fp80 @acosl(x86_fp80) [[NUW]]
+// 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 x86_fp80 @asinl(x86_fp80) [[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 x86_fp80 @atanl(x86_fp80) [[NUW]]
// CHECK-NOERRNO: declare float @atanf(float) [[NUW]]
-// CHECK-NOERRNO: declare double @atan2(double, double) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare float @atan2f(float, 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 x86_fp80 @ceill(x86_fp80) [[NUW]]
// CHECK-NOERRNO: declare float @ceilf(float) [[NUW]]
-// CHECK-NOERRNO: declare double @copysign(double, double) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare float @copysignf(float, float) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
// CHECK-NOERRNO: declare double @cos(double) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @cosl(x86_fp80) [[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 x86_fp80 @expl(x86_fp80) [[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 x86_fp80 @exp2l(x86_fp80) [[NUW]]
// CHECK-NOERRNO: declare float @exp2f(float) [[NUW]]
-// CHECK-NOERRNO: declare double @fabs(double) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare float @fabsf(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 x86_fp80 @floorl(x86_fp80) [[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 x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[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 x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[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 x86_fp80 @fminl(x86_fp80, x86_fp80) [[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 @lgamma(double) [[NUW]]
+// CHECK-NOERRNO: declare float @lgammaf(float) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @lgammal(x86_fp80) [[NUW]]
+// 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 x86_fp80 @logl(x86_fp80) [[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 x86_fp80 @log2l(x86_fp80) [[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 x86_fp80 @nearbyintl(x86_fp80) [[NUW]]
// CHECK-NOERRNO: declare float @nearbyintf(float) [[NUW]]
-// CHECK-NOERRNO: declare double @pow(double, double) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @powl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare float @powf(float, 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 x86_fp80 @rintl(x86_fp80) [[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 x86_fp80 @roundl(x86_fp80) [[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 x86_fp80 @sinl(x86_fp80) [[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 x86_fp80 @sqrtl(x86_fp80) [[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 x86_fp80 @tanl(x86_fp80) [[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 x86_fp80 @truncl(x86_fp80) [[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-ERRNO: declare double @ceil(double) [[NUW:#[0-9]+]]
-// CHECK-ERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare float @ceilf(float) [[NUW]]
+// 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 x86_fp80 @copysignl(x86_fp80, x86_fp80) [[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 x86_fp80 @fabsl(x86_fp80) [[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 x86_fp80 @floorl(x86_fp80) [[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 x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[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 x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
// CHECK-ERRNO: declare float @fminf(float, float) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
// CHECK-ERRNO: declare double @nearbyint(double) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[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 x86_fp80 @rintl(x86_fp80) [[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 x86_fp80 @roundl(x86_fp80) [[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 x86_fp80 @truncl(x86_fp80) [[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-NOERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGen/libcalls-complex.c b/test/CodeGen/libcalls-complex.c
index 7bcfa605ae8b..22c97b6a7b3f 100644
--- a/test/CodeGen/libcalls-complex.c
+++ b/test/CodeGen/libcalls-complex.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fno-builtin -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix YES %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix NO %s
+// RUN: %clang_cc1 -fno-builtin -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-NO %s
extern float crealf(float _Complex);
extern double creal(double _Complex);
diff --git a/test/CodeGen/libcalls-d.c b/test/CodeGen/libcalls-d.c
index b375f2bb83a6..3d88eb1a305e 100644
--- a/test/CodeGen/libcalls-d.c
+++ b/test/CodeGen/libcalls-d.c
@@ -1,8 +1,8 @@
// llvm-gcc -O1+ should run simplify libcalls, O0 shouldn't
// and -fno-builtins shouldn't.
// -fno-math-errno should emit an llvm intrinsic, -fmath-errno should not.
-// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -O0 -o - | grep {call.*exp2\\.f64}
-// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -O0 -o - | grep {call.*exp2}
+// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -o - | grep {call.*exp2\\.f64}
+// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -o - | grep {call.*exp2}
// RUN: %clang_cc1 %s -emit-llvm -O1 -o - | grep {call.*ldexp}
// RUN: %clang_cc1 %s -emit-llvm -O3 -fno-builtin -o - | grep {call.*exp2}
diff --git a/test/CodeGen/libcalls-ld.c b/test/CodeGen/libcalls-ld.c
index 2758761b5ee1..dfa7835d6b73 100644
--- a/test/CodeGen/libcalls-ld.c
+++ b/test/CodeGen/libcalls-ld.c
@@ -1,8 +1,8 @@
// llvm-gcc -O1+ should run simplify libcalls, O0 shouldn't
// and -fno-builtins shouldn't.
// -fno-math-errno should emit an llvm intrinsic, -fmath-errno should not.
-// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -O0 -o - | grep {call.*exp2\\..*f}
-// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -O0 -o - | grep {call.*exp2l}
+// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -o - | grep {call.*exp2\\..*f}
+// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -o - | grep {call.*exp2l}
// RUN: %clang_cc1 %s -emit-llvm -O1 -o - | grep {call.*ldexp}
// RUN: %clang_cc1 %s -emit-llvm -O3 -fno-builtin -o - | grep {call.*exp2l}
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index 8f8e18226a35..3112c8757343 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -fmath-errno -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix YES %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix NO %s
+// RUN: %clang_cc1 -fmath-errno -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-NO %s
+// RUN: %clang_cc1 -menable-unsafe-fp-math -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-FAST %s
-// CHECK-YES: define void @test_sqrt
-// CHECK-NO: define void @test_sqrt
+// CHECK-YES-LABEL: define void @test_sqrt
+// 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
@@ -27,9 +29,12 @@ void test_sqrt(float a0, double a1, long double a2) {
// 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-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)
-// CHECK-YES: define void @test_pow
-// CHECK-NO: define void @test_pow
+// CHECK-YES-LABEL: define void @test_pow
+// CHECK-NO-LABEL: define void @test_pow
void test_pow(float a0, double a1, long double a2) {
// CHECK-YES: call float @powf
// CHECK-NO: call float @llvm.pow.f32
@@ -51,8 +56,8 @@ void test_pow(float a0, double a1, long double a2) {
// CHECK-NO: declare double @llvm.pow.f64(double, double) [[NUW_RO]]
// CHECK-NO: declare x86_fp80 @llvm.pow.f80(x86_fp80, x86_fp80) [[NUW_RO]]
-// CHECK-YES: define void @test_fma
-// CHECK-NO: define void @test_fma
+// CHECK-YES-LABEL: define void @test_fma
+// CHECK-NO-LABEL: define void @test_fma
void test_fma(float a0, double a1, long double a2) {
// CHECK-YES: call float @llvm.fma.f32
// CHECK-NO: call float @llvm.fma.f32
diff --git a/test/CodeGen/link-bitcode-file.c b/test/CodeGen/link-bitcode-file.c
index 77404062ecdd..cf9493f988ae 100644
--- a/test/CodeGen/link-bitcode-file.c
+++ b/test/CodeGen/link-bitcode-file.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -emit-llvm-bc -o %t.bc %s
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO-BC %s
-// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s 2>&1 | FileCheck -check-prefix=CHECK-BC %s
+// RUN: not %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s 2>&1 | FileCheck -check-prefix=CHECK-BC %s
int f(void);
@@ -13,12 +13,12 @@ int f(void) {
#else
-// CHECK-NO-BC: define i32 @g
+// CHECK-NO-BC-LABEL: define i32 @g
// CHECK-NO-BC: ret i32 42
int g(void) {
return f();
}
-// CHECK-NO-BC: define i32 @f
+// CHECK-NO-BC-LABEL: define i32 @f
#endif
diff --git a/test/CodeGen/linkage-redecl.c b/test/CodeGen/linkage-redecl.c
index 14112fe3a0a8..58993f349f81 100644
--- a/test/CodeGen/linkage-redecl.c
+++ b/test/CodeGen/linkage-redecl.c
@@ -16,4 +16,4 @@ void g0() {
}
extern void f(int x) { } // still has internal linkage
-// CHECK: define internal void @f
+// CHECK-LABEL: define internal void @f
diff --git a/test/CodeGen/linux-arm-atomic.c b/test/CodeGen/linux-arm-atomic.c
index c7ce1d228bb5..116925a585b6 100644
--- a/test/CodeGen/linux-arm-atomic.c
+++ b/test/CodeGen/linux-arm-atomic.c
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-linux | FileCheck %s
// 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-double-x86-nacl.c b/test/CodeGen/long-double-x86-nacl.c
index 175129cb6a2a..cec381a06b9b 100644
--- a/test/CodeGen/long-double-x86-nacl.c
+++ b/test/CodeGen/long-double-x86-nacl.c
@@ -3,5 +3,5 @@
long double x = 0;
int checksize[sizeof(x) == 8 ? 1 : -1];
-// CHECK: define void @s1(double %a)
+// CHECK-LABEL: define void @s1(double %a)
void s1(long double a) {}
diff --git a/test/CodeGen/mangle-windows-rtd.c b/test/CodeGen/mangle-windows-rtd.c
new file mode 100644
index 000000000000..fc6f309eaf58
--- /dev/null
+++ b/test/CodeGen/mangle-windows-rtd.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -mrtd %s -o - -triple=i386-mingw32 | FileCheck %s
+
+void f1(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f1@0"
+
+void __stdcall f2(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f2@0"
+
+void __fastcall f3(void) {}
+// CHECK: define x86_fastcallcc void @"\01@f3@0"
diff --git a/test/CodeGen/mangle-windows.c b/test/CodeGen/mangle-windows.c
new file mode 100644
index 000000000000..670649216ddf
--- /dev/null
+++ b/test/CodeGen/mangle-windows.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft \
+// RUN: -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | FileCheck %s
+
+void __stdcall f1(void) {}
+// CHECK: define x86_stdcallcc void @"\01_f1@0"
+
+void __fastcall f2(void) {}
+// CHECK: define x86_fastcallcc void @"\01@f2@0"
+
+void __stdcall f3() {}
+// CHECK: define x86_stdcallcc void @"\01_f3@0"
+
+void __fastcall f4(char a) {}
+// CHECK: define x86_fastcallcc void @"\01@f4@4"
+
+void __fastcall f5(short a) {}
+// CHECK: define x86_fastcallcc void @"\01@f5@4"
+
+void __fastcall f6(int a) {}
+// CHECK: define x86_fastcallcc void @"\01@f6@4"
+
+void __fastcall f7(long a) {}
+// CHECK: define x86_fastcallcc void @"\01@f7@4"
+
+void __fastcall f8(long long a) {}
+// CHECK: define x86_fastcallcc void @"\01@f8@8"
+
+void __fastcall f9(long long a, char b, char c, short d) {}
+// CHECK: define x86_fastcallcc void @"\01@f9@20"(i64 %a, i8 signext %b, i8
+// signext %c, i16 signext %d)
+
+void f12(void) {}
+// CHECK: define void @f12(
diff --git a/test/CodeGen/may-alias.c b/test/CodeGen/may-alias.c
index c76724444bf2..4d6f721f6abb 100644
--- a/test/CodeGen/may-alias.c
+++ b/test/CodeGen/may-alias.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -O1 -disable-llvm-optzns -o - %s | FileCheck %s
-// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -O1 -struct-path-tbaa -disable-llvm-optzns -o - %s | FileCheck %s -check-prefix=PATH
+// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -O1 -no-struct-path-tbaa -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -O1 -disable-llvm-optzns -o - %s | FileCheck %s -check-prefix=PATH
// Types with the may_alias attribute should be considered equivalent
// to char for aliasing.
@@ -8,10 +8,10 @@ typedef int __attribute__((may_alias)) aliasing_int;
void test0(aliasing_int *ai, int *i)
{
-// CHECK: store i32 0, i32* %{{.*}}, !tbaa !1
+// CHECK: store i32 0, i32* %{{.*}}, !tbaa [[TAG_CHAR:!.*]]
// PATH: store i32 0, i32* %{{.*}}, !tbaa [[TAG_CHAR:!.*]]
*ai = 0;
-// CHECK: store i32 1, i32* %{{.*}}, !tbaa !3
+// CHECK: store i32 1, i32* %{{.*}}, !tbaa [[TAG_INT:!.*]]
// PATH: store i32 1, i32* %{{.*}}, !tbaa [[TAG_INT:!.*]]
*i = 1;
}
@@ -20,22 +20,23 @@ void test0(aliasing_int *ai, int *i)
struct Test1 { int x; };
struct Test1MA { int x; } __attribute__((may_alias));
void test1(struct Test1MA *p1, struct Test1 *p2) {
- // CHECK: store i32 2, i32* {{%.*}}, !tbaa !1
+ // CHECK: store i32 2, i32* {{%.*}}, !tbaa [[TAG_CHAR]]
// PATH: store i32 2, i32* {{%.*}}, !tbaa [[TAG_CHAR]]
p1->x = 2;
- // CHECK: store i32 3, i32* {{%.*}}, !tbaa !3
+ // CHECK: store i32 3, i32* {{%.*}}, !tbaa [[TAG_INT]]
// PATH: store i32 3, i32* {{%.*}}, !tbaa [[TAG_test1_x:!.*]]
p2->x = 3;
}
-
-// CHECK: !0 = metadata !{metadata !"any pointer", metadata !1}
-// CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2}
-// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: !3 = metadata !{metadata !"int", metadata !1}
+// CHECK: metadata !{metadata !"any pointer", metadata [[TYPE_CHAR:!.*]],
+// CHECK: [[TYPE_CHAR]] = metadata !{metadata !"omnipotent char", metadata [[TAG_CXX_TBAA:!.*]],
+// CHECK: [[TAG_CXX_TBAA]] = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: [[TAG_CHAR]] = metadata !{metadata [[TYPE_CHAR]], metadata [[TYPE_CHAR]], i64 0}
+// CHECK: [[TAG_INT]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !{{.*}}
// PATH: [[TAG_CHAR]] = metadata !{metadata [[TYPE_CHAR]], metadata [[TYPE_CHAR]], i64 0}
// PATH: [[TAG_INT]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
// PATH: [[TAG_test1_x]] = metadata !{metadata [[TYPE_test1:!.*]], metadata [[TYPE_INT]], i64 0}
-// PATH: [[TYPE_test1]] = metadata !{metadata !"_ZTS5Test1", metadata [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_test1]] = metadata !{metadata !"Test1", metadata [[TYPE_INT]], i64 0}
diff --git a/test/CodeGen/microsoft-call-conv-x64.c b/test/CodeGen/microsoft-call-conv-x64.c
index 97a1d99d6b6d..6475dfa2936d 100644
--- a/test/CodeGen/microsoft-call-conv-x64.c
+++ b/test/CodeGen/microsoft-call-conv-x64.c
@@ -3,12 +3,12 @@
void __fastcall f1(void);
void __stdcall f2(void);
void __fastcall f4(void) {
-// CHECK: define void @f4()
+// CHECK-LABEL: define void @f4()
f1();
// CHECK: call void @f1()
}
void __stdcall f5(void) {
-// CHECK: define void @f5()
+// CHECK-LABEL: define void @f5()
f2();
// CHECK: call void @f2()
}
diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c
index 64d10fb4f4ff..b80c58dfd1f2 100644
--- a/test/CodeGen/microsoft-call-conv.c
+++ b/test/CodeGen/microsoft-call-conv.c
@@ -1,20 +1,22 @@
// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm -mrtd < %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm -fms-compatibility < %s
void __fastcall f1(void);
void __stdcall f2(void);
void __thiscall f3(void);
void __fastcall f4(void) {
-// CHECK: define x86_fastcallcc void @f4()
+// CHECK-LABEL: define x86_fastcallcc void @f4()
f1();
// CHECK: call x86_fastcallcc void @f1()
}
void __stdcall f5(void) {
-// CHECK: define x86_stdcallcc void @f5()
+// CHECK-LABEL: define x86_stdcallcc void @f5()
f2();
// CHECK: call x86_stdcallcc void @f2()
}
void __thiscall f6(void) {
-// CHECK: define x86_thiscallcc void @f6()
+// CHECK-LABEL: define x86_thiscallcc void @f6()
f3();
// CHECK: call x86_thiscallcc void @f3()
}
@@ -48,3 +50,11 @@ void f8(void) {
f7(0);
// CHECK: call x86_stdcallcc void @f7(i32 0)
}
+
+// PR12535
+void __fastcall f9(int x, int y) {};
+// WIN: define x86_fastcallcc void @f9({{.*}})
+void __fastcall f10(int x, ...) {};
+// WIN: define void @f10({{.*}})
+void __stdcall f11(int x, ...) {};
+// WIN: define void @f11({{.*}})
diff --git a/test/CodeGen/mips-byval-arg.c b/test/CodeGen/mips-byval-arg.c
index 41ccd60e8f3e..589e85ef9dd1 100644
--- a/test/CodeGen/mips-byval-arg.c
+++ b/test/CodeGen/mips-byval-arg.c
@@ -7,8 +7,8 @@ typedef struct {
extern void foo2(S0);
-// O32: define void @foo1(i32 %a0.coerce0, i32 %a0.coerce1, i32 %a0.coerce2)
-// N64: define void @foo1(i64 %a0.coerce0, i32 %a0.coerce1)
+// O32-LABEL: define void @foo1(i32 %a0.coerce0, i32 %a0.coerce1, i32 %a0.coerce2)
+// N64-LABEL: define void @foo1(i64 %a0.coerce0, i32 %a0.coerce1)
void foo1(S0 a0) {
foo2(a0);
diff --git a/test/CodeGen/mips-clobber-reg.c b/test/CodeGen/mips-clobber-reg.c
index be18353af820..a87a3e7b2e66 100644
--- a/test/CodeGen/mips-clobber-reg.c
+++ b/test/CodeGen/mips-clobber-reg.c
@@ -1,80 +1,150 @@
-// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s
+// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s
/*
This checks that the frontend will accept both
- enumerated and symbolic Mips GPR register names.
-
+ enumerated and symbolic Mips register names.
+
+ Includes:
+ - GPR
+ - FPU
+ - MSA
+
Any bad names will make the frontend choke.
*/
main()
{
- __asm__ __volatile__ (".set noat \n\t addi $7,$at,77":::"at");
- __asm__ __volatile__ ("addi $7,$v0,77":::"v0");
- __asm__ __volatile__ ("addi $7,$v1,77":::"v1");
- __asm__ __volatile__ ("addi $7,$a0,77":::"a0");
- __asm__ __volatile__ ("addi $7,$a1,77":::"a1");
- __asm__ __volatile__ ("addi $7,$a2,77":::"a2");
- __asm__ __volatile__ ("addi $7,$a3,77":::"a3");
- __asm__ __volatile__ ("addi $7,$t0,77":::"t0");
- __asm__ __volatile__ ("addi $7,$t1,77":::"t1");
- __asm__ __volatile__ ("addi $7,$t2,77":::"t2");
- __asm__ __volatile__ ("addi $7,$t3,77":::"t3");
- __asm__ __volatile__ ("addi $7,$t4,77":::"t4");
- __asm__ __volatile__ ("addi $7,$t5,77":::"t5");
- __asm__ __volatile__ ("addi $7,$t6,77":::"t6");
- __asm__ __volatile__ ("addi $7,$t7,77":::"t7");
- __asm__ __volatile__ ("addi $7,$s0,77":::"s0");
- __asm__ __volatile__ ("addi $7,$s1,77":::"s1");
- __asm__ __volatile__ ("addi $7,$s2,77":::"s2");
- __asm__ __volatile__ ("addi $7,$s3,77":::"s3");
- __asm__ __volatile__ ("addi $7,$s4,77":::"s4");
- __asm__ __volatile__ ("addi $7,$s5,77":::"s5");
- __asm__ __volatile__ ("addi $7,$s6,77":::"s6");
- __asm__ __volatile__ ("addi $7,$s7,77":::"s7");
- __asm__ __volatile__ ("addi $7,$t8,77":::"t8");
- __asm__ __volatile__ ("addi $7,$t9,77":::"t9");
- __asm__ __volatile__ ("addi $7,$k0,77":::"k0");
- __asm__ __volatile__ ("addi $7,$k1,77":::"k1");
- __asm__ __volatile__ ("addi $7,$gp,77":::"gp");
- __asm__ __volatile__ ("addi $7,$sp,77":::"sp");
- __asm__ __volatile__ ("addi $7,$fp,77":::"fp");
- __asm__ __volatile__ ("addi $7,$sp,77":::"$sp");
- __asm__ __volatile__ ("addi $7,$fp,77":::"$fp");
- __asm__ __volatile__ ("addi $7,$ra,77":::"ra");
+ __asm__ __volatile__ (".set noat \n\t addi $7,$at,77":::"at");
+ __asm__ __volatile__ ("addi $7,$v0,77":::"v0");
+ __asm__ __volatile__ ("addi $7,$v1,77":::"v1");
+ __asm__ __volatile__ ("addi $7,$a0,77":::"a0");
+ __asm__ __volatile__ ("addi $7,$a1,77":::"a1");
+ __asm__ __volatile__ ("addi $7,$a2,77":::"a2");
+ __asm__ __volatile__ ("addi $7,$a3,77":::"a3");
+ __asm__ __volatile__ ("addi $7,$t0,77":::"t0");
+ __asm__ __volatile__ ("addi $7,$t1,77":::"t1");
+ __asm__ __volatile__ ("addi $7,$t2,77":::"t2");
+ __asm__ __volatile__ ("addi $7,$t3,77":::"t3");
+ __asm__ __volatile__ ("addi $7,$t4,77":::"t4");
+ __asm__ __volatile__ ("addi $7,$t5,77":::"t5");
+ __asm__ __volatile__ ("addi $7,$t6,77":::"t6");
+ __asm__ __volatile__ ("addi $7,$t7,77":::"t7");
+ __asm__ __volatile__ ("addi $7,$s0,77":::"s0");
+ __asm__ __volatile__ ("addi $7,$s1,77":::"s1");
+ __asm__ __volatile__ ("addi $7,$s2,77":::"s2");
+ __asm__ __volatile__ ("addi $7,$s3,77":::"s3");
+ __asm__ __volatile__ ("addi $7,$s4,77":::"s4");
+ __asm__ __volatile__ ("addi $7,$s5,77":::"s5");
+ __asm__ __volatile__ ("addi $7,$s6,77":::"s6");
+ __asm__ __volatile__ ("addi $7,$s7,77":::"s7");
+ __asm__ __volatile__ ("addi $7,$t8,77":::"t8");
+ __asm__ __volatile__ ("addi $7,$t9,77":::"t9");
+ __asm__ __volatile__ ("addi $7,$k0,77":::"k0");
+ __asm__ __volatile__ ("addi $7,$k1,77":::"k1");
+ __asm__ __volatile__ ("addi $7,$gp,77":::"gp");
+ __asm__ __volatile__ ("addi $7,$sp,77":::"sp");
+ __asm__ __volatile__ ("addi $7,$fp,77":::"fp");
+ __asm__ __volatile__ ("addi $7,$sp,77":::"$sp");
+ __asm__ __volatile__ ("addi $7,$fp,77":::"$fp");
+ __asm__ __volatile__ ("addi $7,$ra,77":::"ra");
+
+ __asm__ __volatile__ ("addi $7,$0,77":::"$0");
+ __asm__ __volatile__ (".set noat \n\t addi $7,$1,77":::"$1");
+ __asm__ __volatile__ ("addi $7,$2,77":::"$2");
+ __asm__ __volatile__ ("addi $7,$3,77":::"$3");
+ __asm__ __volatile__ ("addi $7,$4,77":::"$4");
+ __asm__ __volatile__ ("addi $7,$5,77":::"$5");
+ __asm__ __volatile__ ("addi $7,$6,77":::"$6");
+ __asm__ __volatile__ ("addi $7,$7,77":::"$7");
+ __asm__ __volatile__ ("addi $7,$8,77":::"$8");
+ __asm__ __volatile__ ("addi $7,$9,77":::"$9");
+ __asm__ __volatile__ ("addi $7,$10,77":::"$10");
+ __asm__ __volatile__ ("addi $7,$11,77":::"$11");
+ __asm__ __volatile__ ("addi $7,$12,77":::"$12");
+ __asm__ __volatile__ ("addi $7,$13,77":::"$13");
+ __asm__ __volatile__ ("addi $7,$14,77":::"$14");
+ __asm__ __volatile__ ("addi $7,$15,77":::"$15");
+ __asm__ __volatile__ ("addi $7,$16,77":::"$16");
+ __asm__ __volatile__ ("addi $7,$17,77":::"$17");
+ __asm__ __volatile__ ("addi $7,$18,77":::"$18");
+ __asm__ __volatile__ ("addi $7,$19,77":::"$19");
+ __asm__ __volatile__ ("addi $7,$20,77":::"$20");
+ __asm__ __volatile__ ("addi $7,$21,77":::"$21");
+ __asm__ __volatile__ ("addi $7,$22,77":::"$22");
+ __asm__ __volatile__ ("addi $7,$23,77":::"$23");
+ __asm__ __volatile__ ("addi $7,$24,77":::"$24");
+ __asm__ __volatile__ ("addi $7,$25,77":::"$25");
+ __asm__ __volatile__ ("addi $7,$26,77":::"$26");
+ __asm__ __volatile__ ("addi $7,$27,77":::"$27");
+ __asm__ __volatile__ ("addi $7,$28,77":::"$28");
+ __asm__ __volatile__ ("addi $7,$29,77":::"$29");
+ __asm__ __volatile__ ("addi $7,$30,77":::"$30");
+ __asm__ __volatile__ ("addi $7,$31,77":::"$31");
- __asm__ __volatile__ ("addi $7,$0,77":::"$0");
- __asm__ __volatile__ (".set noat \n\t addi $7,$1,77":::"$1");
- __asm__ __volatile__ ("addi $7,$2,77":::"$2");
- __asm__ __volatile__ ("addi $7,$3,77":::"$3");
- __asm__ __volatile__ ("addi $7,$4,77":::"$4");
- __asm__ __volatile__ ("addi $7,$5,77":::"$5");
- __asm__ __volatile__ ("addi $7,$6,77":::"$6");
- __asm__ __volatile__ ("addi $7,$7,77":::"$7");
- __asm__ __volatile__ ("addi $7,$8,77":::"$8");
- __asm__ __volatile__ ("addi $7,$9,77":::"$9");
- __asm__ __volatile__ ("addi $7,$10,77":::"$10");
- __asm__ __volatile__ ("addi $7,$11,77":::"$10");
- __asm__ __volatile__ ("addi $7,$12,77":::"$12");
- __asm__ __volatile__ ("addi $7,$13,77":::"$13");
- __asm__ __volatile__ ("addi $7,$14,77":::"$14");
- __asm__ __volatile__ ("addi $7,$15,77":::"$15");
- __asm__ __volatile__ ("addi $7,$16,77":::"$16");
- __asm__ __volatile__ ("addi $7,$17,77":::"$17");
- __asm__ __volatile__ ("addi $7,$18,77":::"$18");
- __asm__ __volatile__ ("addi $7,$19,77":::"$19");
- __asm__ __volatile__ ("addi $7,$20,77":::"$20");
- __asm__ __volatile__ ("addi $7,$21,77":::"$21");
- __asm__ __volatile__ ("addi $7,$22,77":::"$22");
- __asm__ __volatile__ ("addi $7,$23,77":::"$23");
- __asm__ __volatile__ ("addi $7,$24,77":::"$24");
- __asm__ __volatile__ ("addi $7,$25,77":::"$25");
- __asm__ __volatile__ ("addi $7,$26,77":::"$26");
- __asm__ __volatile__ ("addi $7,$27,77":::"$27");
- __asm__ __volatile__ ("addi $7,$28,77":::"$28");
- __asm__ __volatile__ ("addi $7,$29,77":::"$29");
- __asm__ __volatile__ ("addi $7,$30,77":::"$30");
- __asm__ __volatile__ ("addi $7,$31,77":::"$31");
+ __asm__ __volatile__ ("fadd.s $f0,77":::"$f0");
+ __asm__ __volatile__ ("fadd.s $f1,77":::"$f1");
+ __asm__ __volatile__ ("fadd.s $f2,77":::"$f2");
+ __asm__ __volatile__ ("fadd.s $f3,77":::"$f3");
+ __asm__ __volatile__ ("fadd.s $f4,77":::"$f4");
+ __asm__ __volatile__ ("fadd.s $f5,77":::"$f5");
+ __asm__ __volatile__ ("fadd.s $f6,77":::"$f6");
+ __asm__ __volatile__ ("fadd.s $f7,77":::"$f7");
+ __asm__ __volatile__ ("fadd.s $f8,77":::"$f8");
+ __asm__ __volatile__ ("fadd.s $f9,77":::"$f9");
+ __asm__ __volatile__ ("fadd.s $f10,77":::"$f10");
+ __asm__ __volatile__ ("fadd.s $f11,77":::"$f11");
+ __asm__ __volatile__ ("fadd.s $f12,77":::"$f12");
+ __asm__ __volatile__ ("fadd.s $f13,77":::"$f13");
+ __asm__ __volatile__ ("fadd.s $f14,77":::"$f14");
+ __asm__ __volatile__ ("fadd.s $f15,77":::"$f15");
+ __asm__ __volatile__ ("fadd.s $f16,77":::"$f16");
+ __asm__ __volatile__ ("fadd.s $f17,77":::"$f17");
+ __asm__ __volatile__ ("fadd.s $f18,77":::"$f18");
+ __asm__ __volatile__ ("fadd.s $f19,77":::"$f19");
+ __asm__ __volatile__ ("fadd.s $f20,77":::"$f20");
+ __asm__ __volatile__ ("fadd.s $f21,77":::"$f21");
+ __asm__ __volatile__ ("fadd.s $f22,77":::"$f22");
+ __asm__ __volatile__ ("fadd.s $f23,77":::"$f23");
+ __asm__ __volatile__ ("fadd.s $f24,77":::"$f24");
+ __asm__ __volatile__ ("fadd.s $f25,77":::"$f25");
+ __asm__ __volatile__ ("fadd.s $f26,77":::"$f26");
+ __asm__ __volatile__ ("fadd.s $f27,77":::"$f27");
+ __asm__ __volatile__ ("fadd.s $f28,77":::"$f28");
+ __asm__ __volatile__ ("fadd.s $f29,77":::"$f29");
+ __asm__ __volatile__ ("fadd.s $f30,77":::"$f30");
+ __asm__ __volatile__ ("fadd.s $f31,77":::"$f31");
+ __asm__ __volatile__ ("ldi.w $w0,77":::"$w0");
+ __asm__ __volatile__ ("ldi.w $w1,77":::"$w1");
+ __asm__ __volatile__ ("ldi.w $w2,77":::"$w2");
+ __asm__ __volatile__ ("ldi.w $w3,77":::"$w3");
+ __asm__ __volatile__ ("ldi.w $w4,77":::"$w4");
+ __asm__ __volatile__ ("ldi.w $w5,77":::"$w5");
+ __asm__ __volatile__ ("ldi.w $w6,77":::"$w6");
+ __asm__ __volatile__ ("ldi.w $w7,77":::"$w7");
+ __asm__ __volatile__ ("ldi.w $w8,77":::"$w8");
+ __asm__ __volatile__ ("ldi.w $w9,77":::"$w9");
+ __asm__ __volatile__ ("ldi.w $w10,77":::"$w10");
+ __asm__ __volatile__ ("ldi.w $w11,77":::"$w10");
+ __asm__ __volatile__ ("ldi.w $w12,77":::"$w12");
+ __asm__ __volatile__ ("ldi.w $w13,77":::"$w13");
+ __asm__ __volatile__ ("ldi.w $w14,77":::"$w14");
+ __asm__ __volatile__ ("ldi.w $w15,77":::"$w15");
+ __asm__ __volatile__ ("ldi.w $w16,77":::"$w16");
+ __asm__ __volatile__ ("ldi.w $w17,77":::"$w17");
+ __asm__ __volatile__ ("ldi.w $w18,77":::"$w18");
+ __asm__ __volatile__ ("ldi.w $w19,77":::"$w19");
+ __asm__ __volatile__ ("ldi.w $w20,77":::"$w20");
+ __asm__ __volatile__ ("ldi.w $w21,77":::"$w21");
+ __asm__ __volatile__ ("ldi.w $w22,77":::"$w22");
+ __asm__ __volatile__ ("ldi.w $w23,77":::"$w23");
+ __asm__ __volatile__ ("ldi.w $w24,77":::"$w24");
+ __asm__ __volatile__ ("ldi.w $w25,77":::"$w25");
+ __asm__ __volatile__ ("ldi.w $w26,77":::"$w26");
+ __asm__ __volatile__ ("ldi.w $w27,77":::"$w27");
+ __asm__ __volatile__ ("ldi.w $w28,77":::"$w28");
+ __asm__ __volatile__ ("ldi.w $w29,77":::"$w29");
+ __asm__ __volatile__ ("ldi.w $w30,77":::"$w30");
+ __asm__ __volatile__ ("ldi.w $w31,77":::"$w31");
}
diff --git a/test/CodeGen/mips-constraints-mem.c b/test/CodeGen/mips-constraints-mem.c
index ea6bcaff9730..2c3c01ac11e2 100644
--- a/test/CodeGen/mips-constraints-mem.c
+++ b/test/CodeGen/mips-constraints-mem.c
@@ -9,7 +9,7 @@ int foo()
// 'R': An address that can be used in a non-macro load or stor'
// This test will result in the higher and lower nibbles being
// switched due to the lwl/lwr instruction pairs.
- // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R"(i32* %{{[0-9,a-f]+}}) #1, !srcloc !0
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R"(i32* %{{[0-9,a-f]+}}) #1,
int c = 0xffbbccdd;
diff --git a/test/CodeGen/mips-inline-asm-modifiers.c b/test/CodeGen/mips-inline-asm-modifiers.c
index 7c4ca2ce1446..9d697e8b228e 100644
--- a/test/CodeGen/mips-inline-asm-modifiers.c
+++ b/test/CodeGen/mips-inline-asm-modifiers.c
@@ -5,12 +5,16 @@
int printf(const char*, ...);
- // CHECK: %{{[0-9]+}} = call i32 asm ".set noreorder;\0Alw $0,$1;\0A.set reorder;\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2, !srcloc !0
- // CHECK: %{{[0-9]+}} = call i32 asm "lw $0,${1:D};\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2, !srcloc !1
+typedef int v4i32 __attribute__((vector_size(16)));
+
+ // CHECK: %{{[0-9]+}} = call i32 asm ".set noreorder;\0Alw $0,$1;\0A.set reorder;\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
+ // CHECK: %{{[0-9]+}} = call i32 asm "lw $0,${1:D};\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
+ // CHECK: %{{[0-9]+}} = call <4 x i32> asm "ldi.w ${0:w},1", "=f"
int b[8] = {0,1,2,3,4,5,6,7};
int main()
{
int i;
+ v4i32 v4i32_r;
// The first word. Notice, no 'D'
{asm (
@@ -29,6 +33,9 @@ int main()
: "m" (*(b+4))
);}
+ // MSA registers
+ {asm ("ldi.w %w0,1" : "=f" (v4i32_r));}
+
printf("%d\n",i);
return 1;
diff --git a/test/CodeGen/mips-target-data.c b/test/CodeGen/mips-target-data.c
index 88eadcb13d6b..6475ccb4d273 100644
--- a/test/CodeGen/mips-target-data.c
+++ b/test/CodeGen/mips-target-data.c
@@ -6,6 +6,8 @@
// RUN: FileCheck %s -check-prefix=64EL
// RUN: %clang -target mips64-linux-gnu -o - -emit-llvm -S %s |\
// RUN: FileCheck %s -check-prefix=64EB
+// RUN: %clang -target mipsel-linux-gnu -o - -emit-llvm -S -mfp64 %s |\
+// RUN: FileCheck %s -check-prefix=32EL
// 32EL: e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64
// 32EB: E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64
diff --git a/test/CodeGen/mips-vector-return.c b/test/CodeGen/mips-vector-return.c
index 0bff96969000..a7c8ce157c84 100644
--- a/test/CodeGen/mips-vector-return.c
+++ b/test/CodeGen/mips-vector-return.c
@@ -8,14 +8,14 @@ typedef float v4sf __attribute__ ((__vector_size__ (16)));
typedef double v4df __attribute__ ((__vector_size__ (32)));
typedef int v4i32 __attribute__ ((__vector_size__ (16)));
-// O32: define void @test_v4sf(<4 x float>* noalias nocapture sret
+// O32-LABEL: define void @test_v4sf(<4 x float>* noalias nocapture sret
// N64: define { i64, i64 } @test_v4sf
v4sf test_v4sf(float a) {
return (v4sf){0.0f, a, 0.0f, 0.0f};
}
-// O32: define void @test_v4df(<4 x double>* noalias nocapture sret
-// N64: define void @test_v4df(<4 x double>* noalias nocapture sret
+// O32-LABEL: define void @test_v4df(<4 x double>* noalias nocapture sret
+// N64-LABEL: define void @test_v4df(<4 x double>* noalias nocapture sret
v4df test_v4df(double a) {
return (v4df){0.0, a, 0.0, 0.0};
}
diff --git a/test/CodeGen/mips64-class-return.cpp b/test/CodeGen/mips64-class-return.cpp
index 2a786df3effa..a473c1319550 100644
--- a/test/CodeGen/mips64-class-return.cpp
+++ b/test/CodeGen/mips64-class-return.cpp
@@ -34,12 +34,12 @@ D1 foo2(void) {
return gd1;
}
-// CHECK: define void @_Z4foo32D2(i64 %a0.coerce0, double %a0.coerce1)
+// CHECK-LABEL: define void @_Z4foo32D2(i64 %a0.coerce0, double %a0.coerce1)
void foo3(D2 a0) {
gd2 = a0;
}
-// CHECK: define void @_Z4foo42D0(i64 %a0.coerce0, i64 %a0.coerce1)
+// CHECK-LABEL: define void @_Z4foo42D0(i64 %a0.coerce0, i64 %a0.coerce1)
void foo4(D0 a0) {
gd0 = a0;
}
diff --git a/test/CodeGen/mips64-padding-arg.c b/test/CodeGen/mips64-padding-arg.c
index 85dc00c90590..49a29c1efb31 100644
--- a/test/CodeGen/mips64-padding-arg.c
+++ b/test/CodeGen/mips64-padding-arg.c
@@ -1,5 +1,6 @@
// RUN: %clang -target mipsel-unknown-linux -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64
+// RUN: %clang -target mipsel-unknown-linux -mfp64 -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
typedef struct {
double d;
@@ -8,7 +9,7 @@ typedef struct {
// Insert padding to ensure arguments of type S0 are aligned to 16-byte boundaries.
-// N64: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// N64-LABEL: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
// N64: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
// N64: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64)
@@ -20,7 +21,7 @@ void foo1(int a0, S0 a1, S0 a2, int b, S0 a3) {
// Insert padding before long double argument.
//
-// N64: define void @foo3(i32 %a0, i64, fp128 %a1)
+// N64-LABEL: define void @foo3(i32 %a0, i64, fp128 %a1)
// N64: tail call void @foo4(i32 1, i32 2, i32 %a0, i64 undef, fp128 %a1)
// N64: declare void @foo4(i32, i32, i32, i64, fp128)
@@ -32,7 +33,7 @@ void foo3(int a0, long double a1) {
// Insert padding after hidden argument.
//
-// N64: define void @foo5(%struct.S0* noalias sret %agg.result, i64, fp128 %a0)
+// N64-LABEL: define void @foo5(%struct.S0* noalias sret %agg.result, i64, fp128 %a0)
// N64: call void @foo6(%struct.S0* sret %agg.result, i32 1, i32 2, i64 undef, fp128 %a0)
// N64: declare void @foo6(%struct.S0* sret, i32, i32, i64, fp128)
@@ -44,7 +45,7 @@ S0 foo5(long double a0) {
// Do not insert padding if ABI is O32.
//
-// O32: define void @foo7(float %a0, double %a1)
+// O32-LABEL: define void @foo7(float %a0, double %a1)
// O32: declare void @foo8(float, double)
extern void foo8(float, double);
@@ -53,3 +54,18 @@ void foo7(float a0, double a1) {
foo8(a0 + 1.0f, a1 + 2.0);
}
+// O32-LABEL: define void @foo9()
+// O32: declare void @foo10(i32, i32
+
+typedef struct __attribute__((aligned(16))) {
+ int a;
+} S16;
+
+S16 s16;
+
+void foo10(int, S16);
+
+void foo9(void) {
+ foo10(1, s16);
+}
+
diff --git a/test/CodeGen/mmx-inline-asm-error.c b/test/CodeGen/mmx-inline-asm-error.c
new file mode 100644
index 000000000000..a6393682ced1
--- /dev/null
+++ b/test/CodeGen/mmx-inline-asm-error.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -verify -triple x86_64-unknown-unknown -emit-llvm-only %s
+typedef int vec256 __attribute__((ext_vector_type(8)));
+
+vec256 foo(vec256 in) {
+ vec256 out;
+
+ asm("something %0" : : "y"(in)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
+ asm("something %0" : "=y"(out)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
+ asm("something %0, %0" : "+y"(out)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
+
+ return out;
+}
+
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
index a40a59ac0fcc..8fa7cf02cead 100644
--- a/test/CodeGen/mrtd.c
+++ b/test/CodeGen/mrtd.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -mrtd -triple i386-unknown-freebsd9.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s | FileCheck %s
void baz(int arg);
@@ -14,4 +14,13 @@ void foo(int arg) {
// CHECK: declare x86_stdcallcc void @baz(i32)
+void qux(int arg, ...) { }
+// CHECK: define void @qux(i32 %arg, ...)
+
+void quux(int a1, int a2, int a3) {
+ qux(a1, a2, a3);
+}
+// CHECK-LABEL: define x86_stdcallcc void @quux
+// CHECK: call void (i32, ...)* @qux
+
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index 26bdc58ebb7f..5dc7787b8fb9 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
+__declspec(selectany) int x1 = 1;
+const __declspec(selectany) int x2 = 2;
+// CHECK: @x1 = weak_odr global i32 1, align 4
+// CHECK: @x2 = weak_odr constant i32 2, align 4
+
struct __declspec(align(16)) S {
char x;
};
diff --git a/test/CodeGen/ms-inline-asm-64.c b/test/CodeGen/ms-inline-asm-64.c
index dd7b9b3349eb..f667708c6591 100644
--- a/test/CodeGen/ms-inline-asm-64.c
+++ b/test/CodeGen/ms-inline-asm-64.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fasm-blocks -emit-llvm -o - | FileCheck %s
void t1() {
int var = 10;
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index c71a8df0ec7a..c4486f6f332f 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -fasm-blocks -emit-llvm -o - | FileCheck %s
void t1() {
// CHECK: @t1
diff --git a/test/CodeGen/ms-inline-asm.cpp b/test/CodeGen/ms-inline-asm.cpp
index 8f824f9947b6..64b8558b483a 100644
--- a/test/CodeGen/ms-inline-asm.cpp
+++ b/test/CodeGen/ms-inline-asm.cpp
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -x c++ %s -triple i386-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -x c++ %s -triple i386-apple-darwin10 -fasm-blocks -emit-llvm -o - | FileCheck %s
// rdar://13645930
@@ -39,7 +39,7 @@ void t2() {
// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3Bar3ptrE)
}
-// CHECK: define void @_Z2t3v()
+// CHECK-LABEL: define void @_Z2t3v()
void t3() {
__asm mov eax, LENGTH Foo::ptr
// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
@@ -76,7 +76,7 @@ struct T4 {
void test();
};
-// CHECK: define void @_ZN2T44testEv(
+// CHECK-LABEL: define void @_ZN2T44testEv(
void T4::test() {
// CHECK: [[T0:%.*]] = alloca [[T4:%.*]]*,
// CHECK: [[THIS:%.*]] = load [[T4]]** [[T0]]
@@ -91,7 +91,7 @@ template <class T> struct T5 {
template <class U> static T create(U);
void run();
};
-// CHECK: define void @_Z5test5v()
+// CHECK-LABEL: define void @_Z5test5v()
void test5() {
// CHECK: [[X:%.*]] = alloca i32
// CHECK: [[Y:%.*]] = alloca i32
@@ -103,3 +103,11 @@ void test5() {
__asm mov x, eax
// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, eax", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[X]])
}
+
+// Just verify this doesn't emit an error.
+void test6() {
+ __asm {
+ a:
+ jmp a
+ }
+}
diff --git a/test/CodeGen/ms_abi.c b/test/CodeGen/ms_abi.c
new file mode 100644
index 000000000000..7c5c26fc41c2
--- /dev/null
+++ b/test/CodeGen/ms_abi.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 -emit-llvm < %s | FileCheck -check-prefix=FREEBSD %s
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s
+
+void __attribute__((ms_abi)) f1(void);
+void __attribute__((sysv_abi)) f2(void);
+void f3(void) {
+// FREEBSD: define void @f3()
+// WIN64: define void @f3()
+ f1();
+// FREEBSD: call x86_64_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 void @f2()
+// WIN64: declare void @f1()
+// WIN64: declare x86_64_sysvcc void @f2()
+
diff --git a/test/CodeGen/mult-alt-generic.c b/test/CodeGen/mult-alt-generic.c
index 111679e3a980..6c9d789e412b 100644
--- a/test/CodeGen/mult-alt-generic.c
+++ b/test/CodeGen/mult-alt-generic.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -triple i686 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple mblaze %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mips %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mipsel %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple powerpc %s -emit-llvm -o - | FileCheck %s
diff --git a/test/CodeGen/no-opt-volatile-memcpy.c b/test/CodeGen/no-opt-volatile-memcpy.c
index 0fab3632805f..718d704a3338 100644
--- a/test/CodeGen/no-opt-volatile-memcpy.c
+++ b/test/CodeGen/no-opt-volatile-memcpy.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
// rdar://11861085
struct s {
@@ -14,7 +14,7 @@ void foo (void) {
gs = gs;
ls = gs;
}
-// CHECK: define void @foo()
+// CHECK-LABEL: define void @foo()
// CHECK: %[[LS:.*]] = alloca %struct.s, align 4
// CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8*
// CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8*
@@ -34,7 +34,7 @@ void fee (void) {
s = s;
s.y = gs;
}
-// CHECK: define void @fee()
+// CHECK-LABEL: define void @fee()
// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
diff --git a/test/CodeGen/nomathbuiltin.c b/test/CodeGen/nomathbuiltin.c
new file mode 100644
index 000000000000..f80cd91de9d4
--- /dev/null
+++ b/test/CodeGen/nomathbuiltin.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fno-math-builtin -emit-llvm -o - %s | FileCheck %s
+
+// Check that the -fno-math-builtin option for -cc1 is working properly.
+
+
+double pow(double, double);
+
+double foo(double a, double b) {
+ return pow(a, b);
+// CHECK: call double @pow
+}
+
diff --git a/test/CodeGen/nvptx-abi.c b/test/CodeGen/nvptx-abi.c
new file mode 100644
index 000000000000..f846def2de52
--- /dev/null
+++ b/test/CodeGen/nvptx-abi.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -S -o - %s -emit-llvm | FileCheck %s
+// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -S -o - %s -emit-llvm | FileCheck %s
+
+typedef struct float4_s {
+ float x, y, z, w;
+} float4_t;
+
+float4_t my_function(void);
+
+// CHECK-DAG: declare %struct.float4_s @my_function
+
+float bar(void) {
+ float4_t ret;
+// CHECK-DAG: call %struct.float4_s @my_function
+ ret = my_function();
+ return ret.x;
+}
diff --git a/test/CodeGen/nvptx-inlineasm-ptx.c b/test/CodeGen/nvptx-inlineasm-ptx.c
new file mode 100644
index 000000000000..0a19123ee074
--- /dev/null
+++ b/test/CodeGen/nvptx-inlineasm-ptx.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -O3 -S -o - %s -emit-llvm | FileCheck %s
+// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -O3 -S -o - %s -emit-llvm | FileCheck %s
+
+void constraints() {
+ char c;
+ unsigned char uc;
+ short s;
+ unsigned short us;
+ int i;
+ unsigned int ui;
+ long l;
+ unsigned long ul;
+ float f;
+ double d;
+
+ // CHECK: i8 asm sideeffect "mov.b8 $0, $1;", "=c,c"
+ asm volatile ("mov.b8 %0, %1;" : "=c"(c) : "c"(c));
+ // CHECK: i8 asm sideeffect "mov.b8 $0, $1;", "=c,c"
+ asm volatile ("mov.b8 %0, %1;" : "=c"(uc) : "c"(uc));
+
+ // CHECK: i16 asm sideeffect "mov.b16 $0, $1;", "=h,h"
+ asm volatile ("mov.b16 %0, %1;" : "=h"(s) : "h"(s));
+ // CHECK: i16 asm sideeffect "mov.b16 $0, $1;", "=h,h"
+ asm volatile ("mov.b16 %0, %1;" : "=h"(us) : "h"(us));
+
+ // CHECK: i32 asm sideeffect "mov.b32 $0, $1;", "=r,r"
+ asm volatile ("mov.b32 %0, %1;" : "=r"(i) : "r"(i));
+ // CHECK: i32 asm sideeffect "mov.b32 $0, $1;", "=r,r"
+ asm volatile ("mov.b32 %0, %1;" : "=r"(ui) : "r"(ui));
+
+ // CHECK: i64 asm sideeffect "mov.b64 $0, $1;", "=l,l"
+ asm volatile ("mov.b64 %0, %1;" : "=l"(l) : "l"(l));
+ // CHECK: i64 asm sideeffect "mov.b64 $0, $1;", "=l,l"
+ asm volatile ("mov.b64 %0, %1;" : "=l"(ul) : "l"(ul));
+
+ // CHECK: float asm sideeffect "mov.b32 $0, $1;", "=f,f"
+ asm volatile ("mov.b32 %0, %1;" : "=f"(f) : "f"(f));
+ // CHECK: double asm sideeffect "mov.b64 $0, $1;", "=d,d"
+ asm volatile ("mov.b64 %0, %1;" : "=d"(d) : "d"(d));
+}
diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c
index f6c7db835bf3..5a4dc99f3658 100644
--- a/test/CodeGen/object-size.c
+++ b/test/CodeGen/object-size.c
@@ -13,38 +13,38 @@ char gbuf[63];
char *gp;
int gi, gj;
-// CHECK: define void @test1
+// CHECK-LABEL: define void @test1
void test1() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 4), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 59)
strcpy(&gbuf[4], "Hi there");
}
-// CHECK: define void @test2
+// CHECK-LABEL: define void @test2
void test2() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 63)
strcpy(gbuf, "Hi there");
}
-// CHECK: define void @test3
+// CHECK-LABEL: define void @test3
void test3() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i64 1, i64 37), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy(&gbuf[100], "Hi there");
}
-// CHECK: define void @test4
+// CHECK-LABEL: define void @test4
void test4() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 -1), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy((char*)(void*)&gbuf[-1], "Hi there");
}
-// CHECK: define void @test5
+// CHECK-LABEL: define void @test5
void test5() {
// CHECK: = load i8** @gp
- // CHECK-NEXT:= call i64 @llvm.objectsize.i64(i8* %{{.*}}, i1 false)
+ // CHECK-NEXT:= call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
strcpy(gp, "Hi there");
}
-// CHECK: define void @test6
+// CHECK-LABEL: define void @test6
void test6() {
char buf[57];
@@ -52,7 +52,7 @@ void test6() {
strcpy(&buf[4], "Hi there");
}
-// CHECK: define void @test7
+// CHECK-LABEL: define void @test7
void test7() {
int i;
// Ensure we only evaluate the side-effect once.
@@ -62,7 +62,7 @@ void test7() {
strcpy((++i, gbuf), "Hi there");
}
-// CHECK: define void @test8
+// CHECK-LABEL: define void @test8
void test8() {
char *buf[50];
// CHECK-NOT: __strcpy_chk
@@ -70,14 +70,14 @@ void test8() {
strcpy(buf[++gi], "Hi there");
}
-// CHECK: define void @test9
+// CHECK-LABEL: define void @test9
void test9() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy((char *)((++gi) + gj), "Hi there");
}
-// CHECK: define void @test10
+// CHECK-LABEL: define void @test10
char **p;
void test10() {
// CHECK-NOT: __strcpy_chk
@@ -85,42 +85,42 @@ void test10() {
strcpy(*(++p), "Hi there");
}
-// CHECK: define void @test11
+// CHECK-LABEL: define void @test11
void test11() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp = gbuf, "Hi there");
}
-// CHECK: define void @test12
+// CHECK-LABEL: define void @test12
void test12() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(++gp, "Hi there");
}
-// CHECK: define void @test13
+// CHECK-LABEL: define void @test13
void test13() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp++, "Hi there");
}
-// CHECK: define void @test14
+// CHECK-LABEL: define void @test14
void test14() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(--gp, "Hi there");
}
-// CHECK: define void @test15
+// CHECK-LABEL: define void @test15
void test15() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{..*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp--, "Hi there");
}
-// CHECK: define void @test16
+// CHECK-LABEL: define void @test16
void test16() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
diff --git a/test/CodeGen/override-layout.c b/test/CodeGen/override-layout.c
index 99c2cd656ec0..57de8b525dcf 100644
--- a/test/CodeGen/override-layout.c
+++ b/test/CodeGen/override-layout.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -w -fdump-record-layouts %s 2> %t.layouts
-// RUN: %clang_cc1 -w -fdump-record-layouts-simple %s > %t.before 2>&1
-// RUN: %clang_cc1 -w -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: %clang_cc1 -w -fdump-record-layouts %s > %t.layouts
+// RUN: %clang_cc1 -w -fdump-record-layouts-simple %s > %t.before
+// RUN: %clang_cc1 -w -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after
// RUN: diff %t.before %t.after
// RUN: FileCheck %s < %t.after
@@ -19,24 +19,32 @@ struct X0 {
int x[6] PACKED;
};
+void use_X0() { struct X0 x0; x0.x[5] = sizeof(struct X0); };
+
// CHECK: Type: struct X1
struct X1 {
char x[13];
struct X0 y;
} PACKED;
+void use_X1() { struct X1 x1; x1.x[5] = sizeof(struct X1); };
+
// CHECK: Type: struct X2
struct PACKED X2 {
short x;
int y;
};
+void use_X2() { struct X2 x2; x2.y = sizeof(struct X2); };
+
// CHECK: Type: struct X3
struct X3 {
short x PACKED;
int y;
};
+void use_X3() { struct X3 x3; x3.y = sizeof(struct X3); };
+
#pragma pack(push,2)
// CHECK: Type: struct X4
struct X4 {
@@ -45,18 +53,26 @@ struct X4 {
};
#pragma pack(pop)
+void use_X4() { struct X4 x4; x4.y = sizeof(struct X4); };
+
// CHECK: Type: struct X5
struct PACKED X5 { double a[19]; signed char b; };
+void use_X5() { struct X5 x5; x5.b = sizeof(struct X5); };
+
// CHECK: Type: struct X6
struct PACKED X6 { long double a; char b; };
+void use_X6() { struct X6 x6; x6.b = sizeof(struct X6); };
+
// CHECK: Type: struct X7
struct X7 {
unsigned x;
unsigned char y;
} PACKED;
+void use_X7() { struct X7 x7; x7.y = x7.x = sizeof(struct X7); }
+
// CHECK: Type: union X8
union X8 {
struct X7 x;
@@ -114,32 +130,6 @@ struct ALIGNED16 X16 {
};
void use_structs() {
- struct X0 x0;
- x0.x[5] = sizeof(struct X0);
-
- struct X1 x1;
- x1.x[5] = sizeof(struct X1);
-
- struct X2 x2;
- x2.y = sizeof(struct X2);
-
- struct X3 x3;
- x3.y = sizeof(struct X3);
-
- struct X4 x4;
- x4.y = sizeof(struct X4);
-
- struct X5 x5;
- x5.b = sizeof(struct X5);
-
- struct X6 x6;
- x6.b = sizeof(struct X6);
-
- struct X7 x7;
- typedef int X7array[sizeof(struct X7)];
- x7.x = sizeof(struct X7);
- x7.y = x7.x;
-
union X8 x8;
typedef int X8array[sizeof(union X8)];
x8.y = sizeof(union X8);
diff --git a/test/CodeGen/packed-arrays.c b/test/CodeGen/packed-arrays.c
index 0c8bb6c7bd4f..8e748dfcfce7 100644
--- a/test/CodeGen/packed-arrays.c
+++ b/test/CodeGen/packed-arrays.c
@@ -51,10 +51,10 @@ int align2_x0 = __alignof(((struct s2*) 0)->x[0]);
// CHECK: @align3_x0 = global i32 4
int align3_x0 = __alignof(((struct s3*) 0)->x[0]);
-// CHECK: define i32 @f0_a
+// CHECK-LABEL: define i32 @f0_a
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f0_b
+// CHECK-LABEL: define i32 @f0_b
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
int f0_a(struct s0 *a) {
@@ -66,19 +66,19 @@ int f0_b(struct s0 *a) {
// Note that we are incompatible with GCC on this example.
//
-// CHECK: define i32 @f1_a
+// CHECK-LABEL: define i32 @f1_a
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f1_b
+// CHECK-LABEL: define i32 @f1_b
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
// Note that we are incompatible with GCC on this example.
//
-// CHECK: define i32 @f1_c
+// CHECK-LABEL: define i32 @f1_c
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
-// CHECK: define i32 @f1_d
+// CHECK-LABEL: define i32 @f1_d
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
int f1_a(struct s1 *a) {
@@ -94,16 +94,16 @@ int f1_d(struct s1 *a) {
return a->z;
}
-// CHECK: define i32 @f2_a
+// CHECK-LABEL: define i32 @f2_a
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f2_b
+// CHECK-LABEL: define i32 @f2_b
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
-// CHECK: define i32 @f2_c
+// CHECK-LABEL: define i32 @f2_c
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f2_d
+// CHECK-LABEL: define i32 @f2_d
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
int f2_a(struct s2 *a) {
@@ -119,16 +119,16 @@ int f2_d(struct s2 *a) {
return a->z;
}
-// CHECK: define i32 @f3_a
+// CHECK-LABEL: define i32 @f3_a
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f3_b
+// CHECK-LABEL: define i32 @f3_b
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
-// CHECK: define i32 @f3_c
+// CHECK-LABEL: define i32 @f3_c
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
-// CHECK: define i32 @f3_d
+// CHECK-LABEL: define i32 @f3_d
// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
int f3_a(struct s3 *a) {
@@ -146,7 +146,7 @@ int f3_d(struct s3 *a) {
// Verify we don't claim things are overaligned.
//
-// CHECK: define double @f4
+// CHECK-LABEL: define double @f4
// CHECK: load double* {{.*}}, align 8
// CHECK: }
extern double g4[5] __attribute__((aligned(16)));
diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c
index 7f486c99987d..393174196f4e 100644
--- a/test/CodeGen/packed-nest-unpacked.c
+++ b/test/CodeGen/packed-nest-unpacked.c
@@ -28,7 +28,7 @@ void test3(struct X a) {
// <rdar://problem/10530444>
void test4() {
// CHECK: @test4
- // FIXME: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i64 24, i32 1, i1 false)
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i64 24, i32 1, i1 false)
f(g.y);
}
diff --git a/test/CodeGen/packed-structure.c b/test/CodeGen/packed-structure.c
index ffd98dbfcf36..a915a544b9eb 100644
--- a/test/CodeGen/packed-structure.c
+++ b/test/CodeGen/packed-structure.c
@@ -16,7 +16,7 @@ int s0_align_x = __alignof(((struct s0*)0)->x);
int s0_align_y = __alignof(((struct s0*)0)->y);
int s0_align = __alignof(struct s0);
-// CHECK-FUNCTIONS: define i32 @s0_load_x
+// CHECK-FUNCTIONS-LABEL: define i32 @s0_load_x
// CHECK-FUNCTIONS: [[s0_load_x:%.*]] = load i32* {{.*}}, align 4
// CHECK-FUNCTIONS: ret i32 [[s0_load_x]]
int s0_load_x(struct s0 *a) { return a->x; }
@@ -24,11 +24,11 @@ int s0_load_x(struct s0 *a) { return a->x; }
// has changed in llvm-gcc recently, previously both x and y would be loaded
// with align 1 (in 2363.1 at least).
//
-// CHECK-FUNCTIONS: define i32 @s0_load_y
+// CHECK-FUNCTIONS-LABEL: define i32 @s0_load_y
// CHECK-FUNCTIONS: [[s0_load_y:%.*]] = load i32* {{.*}}, align 1
// CHECK-FUNCTIONS: ret i32 [[s0_load_y]]
int s0_load_y(struct s0 *a) { return a->y; }
-// CHECK-FUNCTIONS: define void @s0_copy
+// CHECK-FUNCTIONS-LABEL: define void @s0_copy
// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 4, i1 false)
void s0_copy(struct s0 *a, struct s0 *b) { *b = *a; }
@@ -46,15 +46,15 @@ int s1_align_x = __alignof(((struct s1*)0)->x);
int s1_align_y = __alignof(((struct s1*)0)->y);
int s1_align = __alignof(struct s1);
-// CHECK-FUNCTIONS: define i32 @s1_load_x
+// CHECK-FUNCTIONS-LABEL: define i32 @s1_load_x
// CHECK-FUNCTIONS: [[s1_load_x:%.*]] = load i32* {{.*}}, align 1
// CHECK-FUNCTIONS: ret i32 [[s1_load_x]]
int s1_load_x(struct s1 *a) { return a->x; }
-// CHECK-FUNCTIONS: define i32 @s1_load_y
+// CHECK-FUNCTIONS-LABEL: define i32 @s1_load_y
// CHECK-FUNCTIONS: [[s1_load_y:%.*]] = load i32* {{.*}}, align 1
// CHECK-FUNCTIONS: ret i32 [[s1_load_y]]
int s1_load_y(struct s1 *a) { return a->y; }
-// CHECK-FUNCTIONS: define void @s1_copy
+// CHECK-FUNCTIONS-LABEL: define void @s1_copy
// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 1, i1 false)
void s1_copy(struct s1 *a, struct s1 *b) { *b = *a; }
@@ -74,15 +74,15 @@ int s2_align_x = __alignof(((struct s2*)0)->x);
int s2_align_y = __alignof(((struct s2*)0)->y);
int s2_align = __alignof(struct s2);
-// CHECK-FUNCTIONS: define i32 @s2_load_x
+// CHECK-FUNCTIONS-LABEL: define i32 @s2_load_x
// CHECK-FUNCTIONS: [[s2_load_y:%.*]] = load i32* {{.*}}, align 2
// CHECK-FUNCTIONS: ret i32 [[s2_load_y]]
int s2_load_x(struct s2 *a) { return a->x; }
-// CHECK-FUNCTIONS: define i32 @s2_load_y
+// CHECK-FUNCTIONS-LABEL: define i32 @s2_load_y
// CHECK-FUNCTIONS: [[s2_load_y:%.*]] = load i32* {{.*}}, align 2
// CHECK-FUNCTIONS: ret i32 [[s2_load_y]]
int s2_load_y(struct s2 *a) { return a->y; }
-// CHECK-FUNCTIONS: define void @s2_copy
+// CHECK-FUNCTIONS-LABEL: define void @s2_copy
// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 2, i1 false)
void s2_copy(struct s2 *a, struct s2 *b) { *b = *a; }
@@ -92,7 +92,7 @@ struct __attribute__((packed, aligned)) s3 {
};
// CHECK-GLOBAL: @s3_1 = global i32 1
int s3_1 = __alignof(((struct s3*) 0)->anInt);
-// CHECK-FUNCTIONS: define i32 @test3(
+// CHECK-FUNCTIONS-LABEL: define i32 @test3(
int test3(struct s3 *ptr) {
// CHECK-FUNCTIONS: [[PTR:%.*]] = getelementptr inbounds {{%.*}}* {{%.*}}, i32 0, i32 1
// CHECK-FUNCTIONS-NEXT: load i32* [[PTR]], align 1
diff --git a/test/CodeGen/ppc64-extend.c b/test/CodeGen/ppc64-extend.c
index 68d28c79b526..d46b65104392 100644
--- a/test/CodeGen/ppc64-extend.c
+++ b/test/CodeGen/ppc64-extend.c
@@ -1,5 +1,5 @@
// REQUIRES: ppc64-registered-target
-// RUN: %clang_cc1 -O0 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
void f1(int x) { return; }
// CHECK: define void @f1(i32 signext %x) [[NUW:#[0-9]+]]
diff --git a/test/CodeGen/ppc64-struct-onefloat.c b/test/CodeGen/ppc64-struct-onefloat.c
index 4f9e1949cea3..e26987f44a0e 100644
--- a/test/CodeGen/ppc64-struct-onefloat.c
+++ b/test/CodeGen/ppc64-struct-onefloat.c
@@ -1,5 +1,5 @@
// REQUIRES: ppc64-registered-target
-// RUN: %clang_cc1 -O0 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
typedef struct s1 { float f; } Sf;
typedef struct s2 { double d; } Sd;
@@ -8,7 +8,7 @@ typedef struct s5 { Sd ds; } SSd;
void bar(Sf a, Sd b, SSf d, SSd e) {}
-// CHECK: define void @bar
+// CHECK-LABEL: define void @bar
// CHECK: %a = alloca %struct.s1, align 4
// CHECK: %b = alloca %struct.s2, align 8
// CHECK: %d = alloca %struct.s4, align 4
@@ -34,7 +34,7 @@ void foo(void)
bar(p1, p2, p4, p5);
}
-// CHECK: define void @foo
+// CHECK-LABEL: define void @foo
// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1* %p1, i32 0, i32 0
// CHECK: %{{[0-9]+}} = load float* %{{[a-zA-Z0-9.]+}}, align 1
// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2* %p2, i32 0, i32 0
diff --git a/test/CodeGen/ppc64-struct-onevect.c b/test/CodeGen/ppc64-struct-onevect.c
new file mode 100644
index 000000000000..a5a1232ffa89
--- /dev/null
+++ b/test/CodeGen/ppc64-struct-onevect.c
@@ -0,0 +1,13 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -O2 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+typedef float v4sf __attribute__ ((vector_size (16)));
+
+struct s { v4sf v; };
+
+v4sf foo (struct s a) {
+ return a.v;
+}
+
+// CHECK-LABEL: define <4 x float> @foo(<4 x float> inreg %a.coerce)
+// CHECK: ret <4 x float> %a.coerce
diff --git a/test/CodeGen/pr12251.c b/test/CodeGen/pr12251.c
index b01713122141..ea74cc6a594d 100644
--- a/test/CodeGen/pr12251.c
+++ b/test/CodeGen/pr12251.c
@@ -5,7 +5,7 @@ enum e1 g1(enum e1 *x) {
return *x;
}
-// CHECK: define i32 @g1
+// CHECK-LABEL: define i32 @g1
// CHECK: load i32* %x, align 4
// CHECK-NOT: range
// CHECK: ret
diff --git a/test/CodeGen/pr2394.c b/test/CodeGen/pr2394.c
index f1091ec2fba3..c92e364dedac 100644
--- a/test/CodeGen/pr2394.c
+++ b/test/CodeGen/pr2394.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
struct __attribute((packed)) x {int a : 24;};
int a(struct x* g) {
// CHECK: load i24
diff --git a/test/CodeGen/pr3518.c b/test/CodeGen/pr3518.c
index f96a5aa65f19..ff8d75e7b90c 100644
--- a/test/CodeGen/pr3518.c
+++ b/test/CodeGen/pr3518.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
// PR 3518
// Some of the objects were coming out as unintialized (external) before 3518
// was fixed. Internal names are different between llvm-gcc and clang so they
diff --git a/test/CodeGen/pr4349.c b/test/CodeGen/pr4349.c
index 94b4fbd5db46..016995871a49 100644
--- a/test/CodeGen/pr4349.c
+++ b/test/CodeGen/pr4349.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
// PR 4349
union reg
diff --git a/test/CodeGen/pr9614.c b/test/CodeGen/pr9614.c
index 8fdb2f299ce0..53abef1801d9 100644
--- a/test/CodeGen/pr9614.c
+++ b/test/CodeGen/pr9614.c
@@ -18,7 +18,7 @@ void f(void) {
strrchr_foo("", '.');
}
-// CHECK: define void @f()
+// CHECK-LABEL: define void @f()
// CHECK: call void @foo()
// CHECK-NEXT: call void @bar()
// CHECK-NEXT: call i8* @strrchr(
diff --git a/test/CodeGen/pragma-comment.c b/test/CodeGen/pragma-comment.c
new file mode 100644
index 000000000000..30bf7b7d4e5b
--- /dev/null
+++ b/test/CodeGen/pragma-comment.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i686-pc-linux -fms-extensions -emit-llvm -o - | FileCheck -check-prefix LINUX %s
+
+#pragma comment(lib, "msvcrt.lib")
+#pragma comment(lib, "kernel32")
+#pragma comment(lib, "USER32.LIB")
+
+#define BAR "2"
+#pragma comment(linker," /bar=" BAR)
+
+// CHECK: !llvm.module.flags = !{!0}
+// CHECK: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]], metadata ![[kernel32:[0-9]+]], metadata ![[USER32:[0-9]+]], metadata ![[bar:[0-9]+]]}
+// CHECK: ![[msvcrt]] = metadata !{metadata !"/DEFAULTLIB:msvcrt.lib"}
+// CHECK: ![[kernel32]] = metadata !{metadata !"/DEFAULTLIB:kernel32.lib"}
+// CHECK: ![[USER32]] = metadata !{metadata !"/DEFAULTLIB:USER32.LIB"}
+// CHECK: ![[bar]] = metadata !{metadata !" /bar=2"}
+
+// LINUX: metadata !{metadata !"-lmsvcrt.lib"}
+// LINUX: metadata !{metadata !"-lkernel32"}
+// LINUX: metadata !{metadata !"-lUSER32.LIB"}
+// LINUX: metadata !{metadata !" /bar=2"}
diff --git a/test/CodeGen/pragma-detect_mismatch.c b/test/CodeGen/pragma-detect_mismatch.c
new file mode 100644
index 000000000000..86cc6d8586f8
--- /dev/null
+++ b/test/CodeGen/pragma-detect_mismatch.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+
+#pragma detect_mismatch("test", "1")
+
+#define BAR "2"
+#pragma detect_mismatch("test2", BAR)
+
+// CHECK: !llvm.module.flags = !{!0}
+// CHECK: !0 = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = metadata !{metadata ![[test:[0-9]+]], metadata ![[test2:[0-9]+]]}
+// CHECK: ![[test]] = metadata !{metadata !"/FAILIFMISMATCH:\22test=1\22"}
+// CHECK: ![[test2]] = metadata !{metadata !"/FAILIFMISMATCH:\22test2=2\22"}
diff --git a/test/CodeGen/pragma-pack-2.c b/test/CodeGen/pragma-pack-2.c
index bfb34d7c688d..1ca3bdf32a28 100644
--- a/test/CodeGen/pragma-pack-2.c
+++ b/test/CodeGen/pragma-pack-2.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X32 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix CHECK-X32 %s
// CHECK-X32: %struct.s0 = type { i64, i64, i32, [12 x i32] }
// CHECK-X32: %struct.s1 = type { [15 x i32], %struct.s0 }
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix CHECK-X64 %s
// CHECK-X64: %struct.s0 = type <{ i64, i64, i32, [12 x i32] }>
// CHECK-X64: %struct.s1 = type <{ [15 x i32], %struct.s0 }>
diff --git a/test/CodeGen/pragma-pack-3.c b/test/CodeGen/pragma-pack-3.c
index 04b636e9c774..586317430744 100644
--- a/test/CodeGen/pragma-pack-3.c
+++ b/test/CodeGen/pragma-pack-3.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X32 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix CHECK-X32 %s
// CHECK-X32: %union.command = type <{ i8*, [2 x i8] }>
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix X64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix CHECK-X64 %s
// CHECK-X64: %union.command = type <{ i8*, [2 x i8] }>
// <rdar://problem/7184250>
diff --git a/test/CodeGen/pragma-visibility.c b/test/CodeGen/pragma-visibility.c
index a7fceb3d1ac1..56e73f301aee 100644
--- a/test/CodeGen/pragma-visibility.c
+++ b/test/CodeGen/pragma-visibility.c
@@ -17,8 +17,8 @@ int z = 0;
#pragma GCC visibility push(hidden)
void f() {}
-// CHECK: define hidden void @f
+// CHECK-LABEL: define hidden void @f
__attribute((visibility("default"))) void g();
void g() {}
-// CHECK: define void @g
+// CHECK-LABEL: define void @g
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index d4b1b9f93f62..b5d186324bf6 100644
--- a/test/CodeGen/pragma-weak.c
+++ b/test/CodeGen/pragma-weak.c
@@ -5,24 +5,22 @@
// CHECK: @correct_linkage = weak global
-// CHECK: @both = alias void ()* @__both
-// CHECK: @both2 = alias void ()* @__both2
-// CHECK: @both3 = alias weak void ()* @__both3
-// CHECK: @a3 = alias weak void ()* @__a3
-// CHECK: @weakvar_alias = alias weak i32* @__weakvar_alias
-// CHECK: @foo = alias weak void ()* @__foo
-// CHECK: @foo2 = alias weak void ()* @__foo2
-// CHECK: @stutter = alias weak void ()* @__stutter
-// CHECK: @stutter2 = alias weak void ()* @__stutter2
-// CHECK: @declfirst = alias weak void ()* @__declfirst
-// CHECK: @declfirstattr = alias weak void ()* @__declfirstattr
-// CHECK: @mix2 = alias weak void ()* @__mix2
-// CHECK: @a1 = alias weak void ()* @__a1
-// CHECK: @xxx = alias weak void ()* @__xxx
+// CHECK-DAG: @both = alias void ()* @__both
+// CHECK-DAG: @both2 = alias void ()* @__both2
+// CHECK-DAG: @weakvar_alias = alias weak i32* @__weakvar_alias
+// CHECK-DAG: @foo = alias weak void ()* @__foo
+// CHECK-DAG: @foo2 = alias weak void ()* @__foo2
+// CHECK-DAG: @stutter = alias weak void ()* @__stutter
+// CHECK-DAG: @stutter2 = alias weak void ()* @__stutter2
+// CHECK-DAG: @declfirst = alias weak void ()* @__declfirst
+// CHECK-DAG: @declfirstattr = alias weak void ()* @__declfirstattr
+// CHECK-DAG: @mix2 = alias weak void ()* @__mix2
+// CHECK-DAG: @a1 = alias weak void ()* @__a1
+// CHECK-DAG: @xxx = alias weak void ()* @__xxx
-// CHECK: define weak void @weakdef()
+// CHECK-LABEL: define weak void @weakdef()
#pragma weak weakvar
@@ -42,12 +40,12 @@ int __weakvar_alias;
#pragma weak foo = __foo
void __foo(void) {}
-// CHECK: define void @__foo()
+// CHECK-LABEL: define void @__foo()
void __foo2(void) {}
#pragma weak foo2 = __foo2
-// CHECK: define void @__foo2()
+// CHECK-LABEL: define void @__foo2()
///// test errors
@@ -69,12 +67,12 @@ typedef int __td2;
#pragma weak stutter = __stutter
#pragma weak stutter = __stutter
void __stutter(void) {}
-// CHECK: define void @__stutter()
+// CHECK-LABEL: define void @__stutter()
void __stutter2(void) {}
#pragma weak stutter2 = __stutter2
#pragma weak stutter2 = __stutter2
-// CHECK: define void @__stutter2()
+// CHECK-LABEL: define void @__stutter2()
// test decl/pragma weak order
@@ -82,12 +80,12 @@ void __stutter2(void) {}
void __declfirst(void);
#pragma weak declfirst = __declfirst
void __declfirst(void) {}
-// CHECK: define void @__declfirst()
+// CHECK-LABEL: define void @__declfirst()
void __declfirstattr(void) __attribute((noinline));
#pragma weak declfirstattr = __declfirstattr
void __declfirstattr(void) {}
-// CHECK: define void @__declfirstattr()
+// CHECK-LABEL: define void @__declfirstattr()
//// test that other attributes are preserved
@@ -96,7 +94,7 @@ void __declfirstattr(void) {}
void mix(void);
#pragma weak mix
__attribute((weak)) void mix(void) { }
-// CHECK: define weak void @mix()
+// CHECK-LABEL: define weak void @mix()
// ensure following __attributes are preserved and that only a single
// alias is generated
@@ -104,7 +102,7 @@ __attribute((weak)) void mix(void) { }
void __mix2(void) __attribute((noinline));
void __mix2(void) __attribute((noinline));
void __mix2(void) {}
-// CHECK: define void @__mix2()
+// CHECK-LABEL: define void @__mix2()
////////////// test #pragma weak/__attribute combinations
@@ -113,7 +111,7 @@ void __mix2(void) {}
void both(void) __attribute((alias("__both")));
#pragma weak both = __both
void __both(void) {}
-// CHECK: define void @__both()
+// CHECK-LABEL: define void @__both()
// if the TARGET is previously declared then whichever aliasing method
// comes first applies and subsequent aliases are discarded.
@@ -123,13 +121,7 @@ void __both2(void);
void both2(void) __attribute((alias("__both2"))); // first, wins
#pragma weak both2 = __both2
void __both2(void) {}
-// CHECK: define void @__both2()
-
-void __both3(void);
-#pragma weak both3 = __both3 // first, wins
-void both3(void) __attribute((alias("__both3")));
-void __both3(void) {}
-// CHECK: define void @__both3()
+// CHECK-LABEL: define void @__both2()
///////////// ensure that #pragma weak does not alter existing __attributes()
@@ -138,16 +130,8 @@ void __a1(void) __attribute((noinline));
void __a1(void) {}
// CHECK: define void @__a1() [[NI:#[0-9]+]]
-// attributes introduced BEFORE a combination of #pragma weak and alias()
-// hold...
-void __a3(void) __attribute((noinline));
-#pragma weak a3 = __a3
-void a3(void) __attribute((alias("__a3")));
-void __a3(void) {}
-// CHECK: define void @__a3() [[NI]]
-
#pragma weak xxx = __xxx
-__attribute((pure,noinline,const,fastcall)) void __xxx(void) { }
+__attribute((pure,noinline,const)) void __xxx(void) { }
// CHECK: void @__xxx() [[RN:#[0-9]+]]
///////////// PR10878: Make sure we can call a weak alias
@@ -165,6 +149,28 @@ void PR14046f() {
}
// CHECK: declare extern_weak i32 @PR14046e()
+// Parse #pragma weak after a label or case statement
+extern int PR16705a(void);
+extern int PR16705b(void);
+extern int PR16705c(void);
+void PR16705f(int a) {
+ switch(a) {
+ case 1:
+#pragma weak PR16705a
+ PR16705a();
+ default:
+#pragma weak PR16705b
+ PR16705b();
+ }
+label:
+ #pragma weak PR16705c
+ PR16705c();
+}
+
+// CHECK: declare extern_weak i32 @PR16705a()
+// CHECK: declare extern_weak i32 @PR16705b()
+// CHECK: declare extern_weak i32 @PR16705c()
+
///////////// TODO: stuff that still doesn't work
@@ -176,7 +182,7 @@ void yyy(void){}
void zzz(void){}
#pragma weak yyy
// NOTE: weak doesn't apply, not before or in same TopLevelDec(!)
-// CHECK: define void @yyy()
+// CHECK-LABEL: define void @yyy()
int correct_linkage;
diff --git a/test/CodeGen/predefined-expr.c b/test/CodeGen/predefined-expr.c
index e2826b68d7df..3471dcdaa2a4 100644
--- a/test/CodeGen/predefined-expr.c
+++ b/test/CodeGen/predefined-expr.c
@@ -6,6 +6,8 @@
// CHECK: @__PRETTY_FUNCTION__.externFunction = private unnamed_addr constant [22 x i8] c"void externFunction()\00"
// CHECK: @__func__.privateExternFunction = private unnamed_addr constant [22 x i8] c"privateExternFunction\00"
// CHECK: @__PRETTY_FUNCTION__.privateExternFunction = private unnamed_addr constant [29 x i8] c"void privateExternFunction()\00"
+// CHECK: @__func__.__captured_stmt = private unnamed_addr constant [25 x i8] c"functionWithCapturedStmt\00"
+// CHECK: @__PRETTY_FUNCTION__.__captured_stmt = private unnamed_addr constant [32 x i8] c"void functionWithCapturedStmt()\00"
// CHECK: @__func__.staticFunction = private unnamed_addr constant [15 x i8] c"staticFunction\00"
// CHECK: @__PRETTY_FUNCTION__.staticFunction = private unnamed_addr constant [22 x i8] c"void staticFunction()\00"
@@ -29,6 +31,15 @@ __private_extern__ void privateExternFunction() {
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
}
+void functionWithCapturedStmt() {
+ #pragma clang __debug captured
+ {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+}
+
static void staticFunction() {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
@@ -39,6 +50,7 @@ int main() {
plainFunction();
externFunction();
privateExternFunction();
+ functionWithCapturedStmt();
staticFunction();
return 0;
diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c
index 4c3752c56a13..151c58f958bd 100644
--- a/test/CodeGen/regparm.c
+++ b/test/CodeGen/regparm.c
@@ -15,7 +15,7 @@ extern void FASTCALL reduced(char b, double c, foo* d, double e, int f);
// PR7025
void FASTCALL f1(int i, int j, int k);
-// CHECK: define void @f1(i32 inreg %i, i32 inreg %j, i32 %k)
+// CHECK-LABEL: define void @f1(i32 inreg %i, i32 inreg %j, i32 %k)
void f1(int i, int j, int k) { }
int
diff --git a/test/CodeGen/sections.c b/test/CodeGen/sections.c
new file mode 100644
index 000000000000..7994acf4dcac
--- /dev/null
+++ b/test/CodeGen/sections.c
@@ -0,0 +1,28 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+
+// 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
+
+const int hello = 123;
+void world() {}
+
+// PLAIN-NOT: section
+// PLAIN: world:
+// PLAIN: section .rodata,
+// PLAIN: hello:
+
+// FUNC_SECT: section .text.world,
+// FUNC_SECT: world:
+// FUNC_SECT: section .rodata,
+// FUNC_SECT: hello:
+
+// DATA_SECT-NOT: section
+// DATA_SECT: world:
+// DATA_SECT: .section .rodata.hello,
+// DATA_SECT: hello:
diff --git a/test/CodeGen/sha-builtins.c b/test/CodeGen/sha-builtins.c
new file mode 100644
index 000000000000..181dba15b539
--- /dev/null
+++ b/test/CodeGen/sha-builtins.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-unknown-unknown -target-feature +sha -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+__m128i test_sha1rnds4(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha1rnds4
+ return _mm_sha1rnds4_epu32(a, b, 8);
+}
+__m128i test_sha1nexte(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha1nexte
+ return _mm_sha1nexte_epu32(a, b);
+}
+__m128i test_sha1msg1(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha1msg1
+ return _mm_sha1msg1_epu32(a, b);
+}
+__m128i test_sha1msg2(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha1msg2
+ return _mm_sha1msg2_epu32(a, b);
+}
+__m128i test_sha256rnds2(__m128i a, __m128i b, __m128i c) {
+ // CHECK: call <4 x i32> @llvm.x86.sha256rnds2
+ return _mm_sha256rnds2_epu32(a, b, c);
+}
+__m128i test_sha256msg1(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha256msg1
+ return _mm_sha256msg1_epu32(a, b);
+}
+__m128i test_sha256msg2(__m128i a, __m128i b) {
+ // CHECK: call <4 x i32> @llvm.x86.sha256msg2
+ return _mm_sha256msg2_epu32(a, b);
+}
diff --git a/test/CodeGen/sparcv9-abi.c b/test/CodeGen/sparcv9-abi.c
new file mode 100644
index 000000000000..4ba4be852fe8
--- /dev/null
+++ b/test/CodeGen/sparcv9-abi.c
@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+#include <stdarg.h>
+
+// CHECK-LABEL: define void @f_void()
+void f_void(void) {}
+
+// Arguments and return values smaller than the word size are extended.
+
+// CHECK-LABEL: define signext i32 @f_int_1(i32 signext %x)
+int f_int_1(int x) { return x; }
+
+// CHECK-LABEL: define zeroext i32 @f_int_2(i32 zeroext %x)
+unsigned f_int_2(unsigned x) { return x; }
+
+// CHECK-LABEL: define i64 @f_int_3(i64 %x)
+long long f_int_3(long long x) { return x; }
+
+// CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x)
+char f_int_4(char x) { return x; }
+
+// Small structs are passed in registers.
+struct small {
+ int *a, *b;
+};
+
+// CHECK-LABEL: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
+struct small f_small(struct small x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// Medium-sized structs are passed indirectly, but can be returned in registers.
+struct medium {
+ int *a, *b;
+ int *c, *d;
+};
+
+// CHECK-LABEL: define %struct.medium @f_medium(%struct.medium* %x)
+struct medium f_medium(struct medium x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// Large structs are also returned indirectly.
+struct large {
+ int *a, *b;
+ int *c, *d;
+ int x;
+};
+
+// CHECK-LABEL: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x)
+struct large f_large(struct large x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// A 64-bit struct fits in a register.
+struct reg {
+ int a, b;
+};
+
+// CHECK-LABEL: define i64 @f_reg(i64 %x.coerce)
+struct reg f_reg(struct reg x) {
+ x.a += x.b;
+ return x;
+}
+
+// Structs with mixed int and float parts require the inreg attribute.
+struct mixed {
+ int a;
+ float b;
+};
+
+// CHECK-LABEL: define inreg %struct.mixed @f_mixed(i32 inreg %x.coerce0, float inreg %x.coerce1)
+struct mixed f_mixed(struct mixed x) {
+ x.a += 1;
+ return x;
+}
+
+// Struct with padding.
+struct mixed2 {
+ int a;
+ double b;
+};
+
+// CHECK: define { i64, double } @f_mixed2(i64 %x.coerce0, double %x.coerce1)
+// CHECK: store i64 %x.coerce0
+// CHECK: store double %x.coerce1
+struct mixed2 f_mixed2(struct mixed2 x) {
+ x.a += 1;
+ return x;
+}
+
+// Struct with single element and padding in passed in the high bits of a
+// register.
+struct tiny {
+ char a;
+};
+
+// CHECK-LABEL: define i64 @f_tiny(i64 %x.coerce)
+// CHECK: %[[HB:[^ ]+]] = lshr i64 %x.coerce, 56
+// CHECK: = trunc i64 %[[HB]] to i8
+struct tiny f_tiny(struct tiny x) {
+ x.a += 1;
+ return x;
+}
+
+// CHECK-LABEL: define void @call_tiny()
+// CHECK: %[[XV:[^ ]+]] = zext i8 %{{[^ ]+}} to i64
+// CHECK: %[[HB:[^ ]+]] = shl i64 %[[XV]], 56
+// CHECK: = call i64 @f_tiny(i64 %[[HB]])
+void call_tiny() {
+ struct tiny x = { 1 };
+ f_tiny(x);
+}
+
+// CHECK-LABEL: define signext i32 @f_variable(i8* %f, ...)
+// CHECK: %ap = alloca i8*
+// CHECK: call void @llvm.va_start
+//
+int f_variable(char *f, ...) {
+ int s = 0;
+ char c;
+ va_list ap;
+ va_start(ap, f);
+ while ((c = *f++)) switch (c) {
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[EXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 4
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[EXT]] to i32*
+// CHECK-DAG: load i32* %[[ADR]]
+// CHECK: br
+ case 'i':
+ s += va_arg(ap, int);
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to i64*
+// CHECK-DAG: load i64* %[[ADR]]
+// CHECK: br
+ case 'l':
+ s += va_arg(ap, long);
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.tiny*
+// CHECK: br
+ case 't':
+ s += va_arg(ap, struct tiny).a;
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 16
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.small*
+// CHECK: br
+ case 's':
+ s += *va_arg(ap, struct small).a;
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[IND:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.medium**
+// CHECK-DAG: %[[ADR:[^ ]+]] = load %struct.medium** %[[IND]]
+// CHECK: br
+ case 'm':
+ s += *va_arg(ap, struct medium).a;
+ break;
+ }
+ return s;
+}
diff --git a/test/CodeGen/sret.c b/test/CodeGen/sret.c
index ed1f9a44ef14..828bf9b42d61 100644
--- a/test/CodeGen/sret.c
+++ b/test/CodeGen/sret.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 5
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep sret | count 5
struct abc {
long a;
diff --git a/test/CodeGen/sret2.c b/test/CodeGen/sret2.c
index c96ce4d5c4e0..375746251163 100644
--- a/test/CodeGen/sret2.c
+++ b/test/CodeGen/sret2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 2
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep sret | count 2
struct abc {
long a;
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 400209fca291..1f5cb8e9e107 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ffreestanding -triple i386-apple-darwin9 -target-cpu pentium4 -target-feature +sse4.1 -g -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-apple-macosx10.8.0 -target-feature +sse4.1 -g -emit-llvm %s -o - | FileCheck %s
#include <xmmintrin.h>
#include <emmintrin.h>
@@ -63,7 +63,7 @@ __m128 test_load1_ps(void* y) {
}
void test_store_ss(__m128 x, void* y) {
- // CHECK: define void @test_store_ss
+ // CHECK-LABEL: define void @test_store_ss
// CHECK: store {{.*}} float* {{.*}}, align 1,
_mm_store_ss(y, x);
}
@@ -99,32 +99,32 @@ __m128d test_loadl_pd(__m128d x, void* y) {
}
void test_store_sd(__m128d x, void* y) {
- // CHECK: define void @test_store_sd
+ // CHECK-LABEL: define void @test_store_sd
// CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
_mm_store_sd(y, x);
}
void test_store1_pd(__m128d x, void* y) {
- // CHECK: define void @test_store1_pd
+ // CHECK-LABEL: define void @test_store1_pd
// CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
// CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
_mm_store1_pd(y, x);
}
void test_storer_pd(__m128d x, void* y) {
- // CHECK: define void @test_storer_pd
+ // CHECK-LABEL: define void @test_storer_pd
// CHECK: store {{.*}} <2 x double>* {{.*}}, align 16{{$}}
_mm_storer_pd(y, x);
}
void test_storeh_pd(__m128d x, void* y) {
- // CHECK: define void @test_storeh_pd
+ // CHECK-LABEL: define void @test_storeh_pd
// CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
_mm_storeh_pd(y, x);
}
void test_storel_pd(__m128d x, void* y) {
- // CHECK: define void @test_storel_pd
+ // CHECK-LABEL: define void @test_storel_pd
// CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
_mm_storel_pd(y, x);
}
@@ -184,7 +184,56 @@ __m128d test_mm_round_sd(__m128d x, __m128d y) {
}
void test_storel_epi64(__m128i x, void* y) {
- // CHECK: define void @test_storel_epi64
+ // CHECK-LABEL: define void @test_storel_epi64
// CHECK: store {{.*}} i64* {{.*}}, align 1{{$}}
_mm_storel_epi64(y, x);
}
+
+void test_stream_si32(int x, void *y) {
+ // CHECK-LABEL: define void @test_stream_si32
+ // CHECK: store {{.*}} i32* {{.*}}, align 1, !nontemporal
+ _mm_stream_si32(y, x);
+}
+
+void test_stream_si64(long long x, void *y) {
+ // CHECK-LABEL: define void @test_stream_si64
+ // CHECK: store {{.*}} i64* {{.*}}, align 1, !nontemporal
+ _mm_stream_si64(y, x);
+}
+
+void test_stream_si128(__m128i x, void *y) {
+ // CHECK-LABEL: define void @test_stream_si128
+ // CHECK: store {{.*}} <2 x i64>* {{.*}}, align 16, !nontemporal
+ _mm_stream_si128(y, x);
+}
+
+void test_extract_epi16(__m128i __a) {
+ // CHECK-LABEL: define void @test_extract_epi16
+ // CHECK: [[x:%.*]] = and i32 %{{.*}}, 7
+ // CHECK: extractelement <8 x i16> %{{.*}}, i32 [[x]]
+ _mm_extract_epi16(__a, 8);
+}
+
+int test_extract_ps(__m128i __a) {
+ // CHECK-LABEL: @test_extract_ps
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 0
+ return _mm_extract_ps(__a, 4);
+}
+
+int test_extract_epi8(__m128i __a) {
+ // CHECK-LABEL: @test_extract_epi8
+ // CHECK: extractelement <16 x i8> %{{.*}}, i32 0
+ return _mm_extract_epi8(__a, 16);
+}
+
+int test_extract_epi32(__m128i __a) {
+ // CHECK-LABEL: @test_extract_epi32
+ // CHECK: extractelement <4 x i32> %{{.*}}, i32 0
+ return _mm_extract_epi32(__a, 4);
+}
+
+void test_insert_epi32(__m128i __a, int b) {
+ // CHECK-LABEL: @test_insert_epi32
+ // CHECK: insertelement <4 x i32> %{{.*}}, i32 %{{.*}}, i32 0
+ _mm_insert_epi32(__a, b, 4);
+}
diff --git a/test/CodeGen/statements.c b/test/CodeGen/statements.c
index 5affb9a83513..ad5cb6278134 100644
--- a/test/CodeGen/statements.c
+++ b/test/CodeGen/statements.c
@@ -1,13 +1,6 @@
// RUN: %clang_cc1 -Wno-error=return-type %s -emit-llvm-only
// REQUIRES: LP64
-void test1(int x) {
-switch (x) {
-case 111111111111111111111111111111111111111:
-bar();
-}
-}
-
// Mismatched type between return and function result.
int test2() { return; }
void test3() { return 4; }
diff --git a/test/CodeGen/static-order.c b/test/CodeGen/static-order.c
index e7f9814261cc..58aabbebd57e 100644
--- a/test/CodeGen/static-order.c
+++ b/test/CodeGen/static-order.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
// CHECK: ModuleID
// CHECK-NOT: zeroinitializer
-// CHECK: define i8* @f
+// CHECK-LABEL: define i8* @f
struct s {
int a;
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index d51817882283..b6217ac1cf3c 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -4,17 +4,17 @@ void __attribute__((fastcall)) f1(void);
void __attribute__((stdcall)) f2(void);
void __attribute__((thiscall)) f3(void);
void __attribute__((fastcall)) f4(void) {
-// CHECK: define x86_fastcallcc void @f4()
+// CHECK-LABEL: define x86_fastcallcc void @f4()
f1();
// CHECK: call x86_fastcallcc void @f1()
}
void __attribute__((stdcall)) f5(void) {
-// CHECK: define x86_stdcallcc void @f5()
+// CHECK-LABEL: define x86_stdcallcc void @f5()
f2();
// CHECK: call x86_stdcallcc void @f2()
}
void __attribute__((thiscall)) f6(void) {
-// CHECK: define x86_thiscallcc void @f6()
+// CHECK-LABEL: define x86_thiscallcc void @f6()
f3();
// CHECK: call x86_thiscallcc void @f3()
}
@@ -51,7 +51,7 @@ void f8(void) {
void __attribute__((fastcall)) foo1(int y);
void bar1(int y) {
- // CHECK: define void @bar1
+ // CHECK-LABEL: define void @bar1
// CHECK: call x86_fastcallcc void @foo1(i32 inreg %
foo1(y);
}
@@ -61,14 +61,14 @@ struct S1 {
};
void __attribute__((fastcall)) foo2(struct S1 y);
void bar2(struct S1 y) {
- // CHECK: define void @bar2
+ // CHECK-LABEL: define void @bar2
// CHECK: call x86_fastcallcc void @foo2(i32 inreg undef, i32 %
foo2(y);
}
void __attribute__((fastcall)) foo3(int *y);
void bar3(int *y) {
- // CHECK: define void @bar3
+ // CHECK-LABEL: define void @bar3
// CHECK: call x86_fastcallcc void @foo3(i32* inreg %
foo3(y);
}
@@ -76,7 +76,7 @@ void bar3(int *y) {
enum Enum {Eval};
void __attribute__((fastcall)) foo4(enum Enum y);
void bar4(enum Enum y) {
- // CHECK: define void @bar4
+ // CHECK-LABEL: define void @bar4
// CHECK: call x86_fastcallcc void @foo4(i32 inreg %
foo4(y);
}
@@ -88,49 +88,49 @@ struct S2 {
};
void __attribute__((fastcall)) foo5(struct S2 y);
void bar5(struct S2 y) {
- // CHECK: define void @bar5
+ // CHECK-LABEL: define void @bar5
// CHECK: call x86_fastcallcc void @foo5(%struct.S2* byval align 4 %
foo5(y);
}
void __attribute__((fastcall)) foo6(long long y);
void bar6(long long y) {
- // CHECK: define void @bar6
+ // CHECK-LABEL: define void @bar6
// CHECK: call x86_fastcallcc void @foo6(i64 %
foo6(y);
}
void __attribute__((fastcall)) foo7(int a, struct S1 b, int c);
void bar7(int a, struct S1 b, int c) {
- // CHECK: define void @bar7
+ // CHECK-LABEL: define void @bar7
// CHECK: call x86_fastcallcc void @foo7(i32 inreg %{{.*}}, i32 %{{.*}}, i32 %{{.*}}
foo7(a, b, c);
}
void __attribute__((fastcall)) foo8(struct S1 a, int b);
void bar8(struct S1 a, int b) {
- // CHECK: define void @bar8
+ // CHECK-LABEL: define void @bar8
// CHECK: call x86_fastcallcc void @foo8(i32 inreg undef, i32 %{{.*}}, i32 inreg %
foo8(a, b);
}
void __attribute__((fastcall)) foo9(struct S2 a, int b);
void bar9(struct S2 a, int b) {
- // CHECK: define void @bar9
+ // CHECK-LABEL: define void @bar9
// CHECK: call x86_fastcallcc void @foo9(%struct.S2* byval align 4 %{{.*}}, i32 %
foo9(a, b);
}
void __attribute__((fastcall)) foo10(float y, int x);
void bar10(float y, int x) {
- // CHECK: define void @bar10
+ // CHECK-LABEL: define void @bar10
// CHECK: call x86_fastcallcc void @foo10(float %{{.*}}, i32 inreg %
foo10(y, x);
}
void __attribute__((fastcall)) foo11(double y, int x);
void bar11(double y, int x) {
- // CHECK: define void @bar11
+ // CHECK-LABEL: define void @bar11
// CHECK: call x86_fastcallcc void @foo11(double %{{.*}}, i32 inreg %
foo11(y, x);
}
@@ -140,7 +140,7 @@ struct S3 {
};
void __attribute__((fastcall)) foo12(struct S3 y, int x);
void bar12(struct S3 y, int x) {
- // CHECK: define void @bar12
+ // CHECK-LABEL: define void @bar12
// CHECK: call x86_fastcallcc void @foo12(float %{{.*}}, i32 inreg %
foo12(y, x);
}
diff --git a/test/CodeGen/string-literal-unicode-conversion.c b/test/CodeGen/string-literal-unicode-conversion.c
index 3e5b7fb04112..23205b80b027 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=C %s
-// RUN: %clang_cc1 -x c++ -std=c++0x -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CPP0X %s
-// RUN: %clang_cc1 -x c++ -std=c++0x -fshort-wchar -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=SHORTWCHAR %s
+// 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
// 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
@@ -31,10 +31,11 @@ void f() {
wchar_t const *b = L"Кошка";
// CHECK-C: private unnamed_addr constant [4 x i32] [i32 20320, i32 22909, i32 66304, i32 0], align 4
- // CHECK-SHORTWCHAR: private unnamed_addr constant [4 x i16] [i16 20320, i16 22909, i16 768, i16 0], align 2
// CHECK-CPP0X: private unnamed_addr constant [4 x i32] [i32 20320, i32 22909, i32 66304, i32 0], align 4
+#if __WCHAR_MAX__ == 2147483647
wchar_t const *b2 = L"\x4f60\x597d\x10300";
-
+#endif
+
#if __cplusplus >= 201103L
// CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"1\D0\9A\D0\BE\D1\88\D0\BA\D0\B0\00", align 1
diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c
index 5273138e4e5e..30834acec736 100644
--- a/test/CodeGen/struct-init.c
+++ b/test/CodeGen/struct-init.c
@@ -1,5 +1,5 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -S -triple armv7-apple-darwin %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -S -triple armv7-apple-darwin -target-feature +neon %s -emit-llvm -o - | FileCheck %s
typedef struct _zend_ini_entry zend_ini_entry;
struct _zend_ini_entry {
diff --git a/test/CodeGen/struct-matching-constraint.c b/test/CodeGen/struct-matching-constraint.c
index bdd11c8b9000..dfc3014c5d9a 100644
--- a/test/CodeGen/struct-matching-constraint.c
+++ b/test/CodeGen/struct-matching-constraint.c
@@ -1,5 +1,5 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -S -emit-llvm -triple armv7a-apple-darwin %s -o /dev/null
+// RUN: %clang_cc1 -S -emit-llvm -triple armv7a-apple-darwin -target-feature +neon %s -o /dev/null
typedef unsigned short uint16_t;
typedef __attribute__((neon_vector_type(8))) uint16_t uint16x8_t;
diff --git a/test/CodeGen/switch-dce.c b/test/CodeGen/switch-dce.c
index a18d3bc89e7d..5a68ff26c6f5 100644
--- a/test/CodeGen/switch-dce.c
+++ b/test/CodeGen/switch-dce.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -O0 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
// PR9322 and rdar://6970405
diff --git a/test/CodeGen/switch.c b/test/CodeGen/switch.c
index 8b94a0976e6e..2417a870f166 100644
--- a/test/CodeGen/switch.c
+++ b/test/CodeGen/switch.c
@@ -63,7 +63,7 @@ static int foo4(int i) {
return j;
}
-// CHECK: define i32 @foo4t()
+// CHECK-LABEL: define i32 @foo4t()
// CHECK: ret i32 376
// CHECK: }
int foo4t() {
@@ -71,7 +71,7 @@ int foo4t() {
return foo4(111) + foo4(99) + foo4(222) + foo4(601);
}
-// CHECK: define void @foo5()
+// CHECK-LABEL: define void @foo5()
// CHECK-NOT: switch
// CHECK: }
void foo5(){
@@ -83,7 +83,7 @@ void foo5(){
}
}
-// CHECK: define void @foo6()
+// CHECK-LABEL: define void @foo6()
// CHECK-NOT: switch
// CHECK: }
void foo6(){
@@ -91,7 +91,7 @@ void foo6(){
}
}
-// CHECK: define void @foo7()
+// CHECK-LABEL: define void @foo7()
// CHECK-NOT: switch
// CHECK: }
void foo7(){
@@ -101,7 +101,7 @@ void foo7(){
}
-// CHECK: define i32 @f8(
+// CHECK-LABEL: define i32 @f8(
// CHECK: ret i32 3
// CHECK: }
int f8(unsigned x) {
@@ -115,7 +115,7 @@ int f8(unsigned x) {
// Ensure that default after a case range is not ignored.
//
-// CHECK: define i32 @f9()
+// CHECK-LABEL: define i32 @f9()
// CHECK: ret i32 10
// CHECK: }
static int f9_0(unsigned x) {
@@ -134,7 +134,7 @@ int f9() {
// miscompilation of fallthrough from default to a (tested) case
// range.
//
-// CHECK: define i32 @f10()
+// CHECK-LABEL: define i32 @f10()
// CHECK: ret i32 10
// CHECK: }
static int f10_0(unsigned x) {
@@ -153,7 +153,7 @@ int f10() {
// This generated incorrect code because of poor switch chaining.
//
-// CHECK: define i32 @f11(
+// CHECK-LABEL: define i32 @f11(
// CHECK: ret i32 3
// CHECK: }
int f11(int x) {
@@ -167,7 +167,7 @@ int f11(int x) {
// This just asserted because of the way case ranges were calculated.
//
-// CHECK: define i32 @f12(
+// CHECK-LABEL: define i32 @f12(
// CHECK: ret i32 3
// CHECK: }
int f12(int x) {
@@ -181,7 +181,7 @@ int f12(int x) {
// Make sure return is not constant (if empty range is skipped or miscompiled)
//
-// CHECK: define i32 @f13(
+// CHECK-LABEL: define i32 @f13(
// CHECK: ret i32 %
// CHECK: }
int f13(unsigned x) {
diff --git a/test/CodeGen/systemz-inline-asm.c b/test/CodeGen/systemz-inline-asm.c
index 8e5854f1bb6c..c9372333b1f2 100644
--- a/test/CodeGen/systemz-inline-asm.c
+++ b/test/CodeGen/systemz-inline-asm.c
@@ -5,31 +5,31 @@ unsigned long gl;
void test_store_m(unsigned int i) {
asm("st %1, %0" : "=m" (gi) : "r" (i));
-// CHECK: define void @test_store_m(i32 zeroext %i)
+// CHECK-LABEL: define void @test_store_m(i32 zeroext %i)
// CHECK: call void asm "st $1, $0", "=*m,r"(i32* @gi, i32 %i)
}
void test_store_Q(unsigned int i) {
asm("st %1, %0" : "=Q" (gi) : "r" (i));
-// CHECK: define void @test_store_Q(i32 zeroext %i)
+// CHECK-LABEL: define void @test_store_Q(i32 zeroext %i)
// CHECK: call void asm "st $1, $0", "=*Q,r"(i32* @gi, i32 %i)
}
void test_store_R(unsigned int i) {
asm("st %1, %0" : "=R" (gi) : "r" (i));
-// CHECK: define void @test_store_R(i32 zeroext %i)
+// CHECK-LABEL: define void @test_store_R(i32 zeroext %i)
// CHECK: call void asm "st $1, $0", "=*R,r"(i32* @gi, i32 %i)
}
void test_store_S(unsigned int i) {
asm("st %1, %0" : "=S" (gi) : "r" (i));
-// CHECK: define void @test_store_S(i32 zeroext %i)
+// CHECK-LABEL: define void @test_store_S(i32 zeroext %i)
// CHECK: call void asm "st $1, $0", "=*S,r"(i32* @gi, i32 %i)
}
void test_store_T(unsigned int i) {
asm("st %1, %0" : "=T" (gi) : "r" (i));
-// CHECK: define void @test_store_T(i32 zeroext %i)
+// CHECK-LABEL: define void @test_store_T(i32 zeroext %i)
// CHECK: call void asm "st $1, $0", "=*T,r"(i32* @gi, i32 %i)
}
@@ -37,7 +37,7 @@ int test_load_m() {
unsigned int i;
asm("l %0, %1" : "=r" (i) : "m" (gi));
return i;
-// CHECK: define signext i32 @test_load_m()
+// CHECK-LABEL: define signext i32 @test_load_m()
// CHECK: call i32 asm "l $0, $1", "=r,*m"(i32* @gi)
}
@@ -45,7 +45,7 @@ int test_load_Q() {
unsigned int i;
asm("l %0, %1" : "=r" (i) : "Q" (gi));
return i;
-// CHECK: define signext i32 @test_load_Q()
+// CHECK-LABEL: define signext i32 @test_load_Q()
// CHECK: call i32 asm "l $0, $1", "=r,*Q"(i32* @gi)
}
@@ -53,7 +53,7 @@ int test_load_R() {
unsigned int i;
asm("l %0, %1" : "=r" (i) : "R" (gi));
return i;
-// CHECK: define signext i32 @test_load_R()
+// CHECK-LABEL: define signext i32 @test_load_R()
// CHECK: call i32 asm "l $0, $1", "=r,*R"(i32* @gi)
}
@@ -61,7 +61,7 @@ int test_load_S() {
unsigned int i;
asm("l %0, %1" : "=r" (i) : "S" (gi));
return i;
-// CHECK: define signext i32 @test_load_S()
+// CHECK-LABEL: define signext i32 @test_load_S()
// CHECK: call i32 asm "l $0, $1", "=r,*S"(i32* @gi)
}
@@ -69,61 +69,61 @@ int test_load_T() {
unsigned int i;
asm("l %0, %1" : "=r" (i) : "T" (gi));
return i;
-// CHECK: define signext i32 @test_load_T()
+// CHECK-LABEL: define signext i32 @test_load_T()
// CHECK: call i32 asm "l $0, $1", "=r,*T"(i32* @gi)
}
void test_mI(unsigned char *c) {
asm volatile("cli %0, %1" :: "Q" (*c), "I" (100));
-// CHECK: define void @test_mI(i8* %c)
+// CHECK-LABEL: define void @test_mI(i8* %c)
// CHECK: call void asm sideeffect "cli $0, $1", "*Q,I"(i8* %c, i32 100)
}
unsigned int test_dJa(unsigned int i, unsigned int j) {
asm("sll %0, %2(%3)" : "=d" (i) : "0" (i), "J" (1000), "a" (j));
return i;
-// CHECK: define zeroext i32 @test_dJa(i32 zeroext %i, i32 zeroext %j)
+// CHECK-LABEL: define zeroext i32 @test_dJa(i32 zeroext %i, i32 zeroext %j)
// CHECK: call i32 asm "sll $0, $2($3)", "=d,0,J,a"(i32 %i, i32 1000, i32 %j)
}
unsigned long test_rK(unsigned long i) {
asm("aghi %0, %2" : "=r" (i) : "0" (i), "K" (-30000));
return i;
-// CHECK: define i64 @test_rK(i64 %i)
+// CHECK-LABEL: define i64 @test_rK(i64 %i)
// CHECK: call i64 asm "aghi $0, $2", "=r,0,K"(i64 %i, i32 -30000)
}
unsigned long test_rL(unsigned long i) {
asm("sllg %0, %1, %2" : "=r" (i) : "r" (i), "L" (500000));
return i;
-// CHECK: define i64 @test_rL(i64 %i)
+// CHECK-LABEL: define i64 @test_rL(i64 %i)
// CHECK: call i64 asm "sllg $0, $1, $2", "=r,r,L"(i64 %i, i32 500000)
}
void test_M() {
asm volatile("#FOO %0" :: "M"(0x7fffffff));
-// CHECK: define void @test_M()
+// CHECK-LABEL: define void @test_M()
// CHECK: call void asm sideeffect "#FOO $0", "M"(i32 2147483647)
}
float test_f32(float f, float g) {
asm("aebr %0, %2" : "=f" (f) : "0" (f), "f" (g));
return f;
-// CHECK: define float @test_f32(float %f, float %g)
+// CHECK-LABEL: define float @test_f32(float %f, float %g)
// CHECK: call float asm "aebr $0, $2", "=f,0,f"(float %f, float %g)
}
double test_f64(double f, double g) {
asm("adbr %0, %2" : "=f" (f) : "0" (f), "f" (g));
return f;
-// CHECK: define double @test_f64(double %f, double %g)
+// CHECK-LABEL: define double @test_f64(double %f, double %g)
// CHECK: call double asm "adbr $0, $2", "=f,0,f"(double %f, double %g)
}
long double test_f128(long double f, long double g) {
asm("axbr %0, %2" : "=f" (f) : "0" (f), "f" (g));
return f;
-// CHECK: define void @test_f128(fp128* noalias nocapture sret [[DEST:%.*]], fp128* byval nocapture, fp128* byval nocapture)
+// CHECK: define void @test_f128(fp128* noalias nocapture sret [[DEST:%.*]], fp128* nocapture readonly, fp128* nocapture readonly)
// CHECK: %f = load fp128* %0
// CHECK: %g = load fp128* %1
// CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g)
diff --git a/test/CodeGen/tbaa-class.cpp b/test/CodeGen/tbaa-class.cpp
index 967ba19a04da..bdd155d450a9 100644
--- a/test/CodeGen/tbaa-class.cpp
+++ b/test/CodeGen/tbaa-class.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -no-struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
// Test TBAA metadata generated by front-end.
typedef unsigned char uint8_t;
@@ -52,8 +52,8 @@ public:
uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32:!.*]]
@@ -64,8 +64,8 @@ uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16:!.*]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_A_f16:!.*]]
@@ -76,8 +76,8 @@ uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
uint32_t g3(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32:!.*]]
@@ -88,8 +88,8 @@ uint32_t g3(StructA *A, StructB *B, uint64_t count) {
uint32_t g4(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_B_a_f16:!.*]]
@@ -100,8 +100,8 @@ uint32_t g4(StructA *A, StructB *B, uint64_t count) {
uint32_t g5(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_f32:!.*]]
@@ -112,8 +112,8 @@ uint32_t g5(StructA *A, StructB *B, uint64_t count) {
uint32_t g6(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32_2:!.*]]
@@ -124,8 +124,8 @@ uint32_t g6(StructA *A, StructB *B, uint64_t count) {
uint32_t g7(StructA *A, StructS *S, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32:!.*]]
@@ -136,8 +136,8 @@ uint32_t g7(StructA *A, StructS *S, uint64_t count) {
uint32_t g8(StructA *A, StructS *S, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_S_f16:!.*]]
@@ -148,8 +148,8 @@ uint32_t g8(StructA *A, StructS *S, uint64_t count) {
uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32:!.*]]
@@ -160,8 +160,8 @@ uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S2_f32_2:!.*]]
@@ -172,8 +172,8 @@ uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
uint32_t g11(StructC *C, StructD *D, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_C_b_a_f32:!.*]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_D_b_a_f32:!.*]]
@@ -184,8 +184,8 @@ uint32_t g11(StructC *C, StructD *D, uint64_t count) {
uint32_t g12(StructC *C, StructD *D, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// TODO: differentiate the two accesses.
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32]]
@@ -198,12 +198,14 @@ uint32_t g12(StructC *C, StructD *D, uint64_t count) {
return b1->a.f32;
}
-// CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2}
-// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: !4 = metadata !{metadata !"int", metadata !1}
-// CHECK: !5 = metadata !{metadata !"short", metadata !1}
+// CHECK: [[TYPE_char:!.*]] = metadata !{metadata !"omnipotent char", metadata [[TAG_cxx_tbaa:!.*]],
+// CHECK: [[TAG_cxx_tbaa]] = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: [[TAG_i32]] = metadata !{metadata [[TYPE_i32:!.*]], metadata [[TYPE_i32]], i64 0}
+// CHECK: [[TYPE_i32]] = metadata !{metadata !"int", metadata [[TYPE_char]],
+// CHECK: [[TAG_i16]] = metadata !{metadata [[TYPE_i16:!.*]], metadata [[TYPE_i16]], i64 0}
+// CHECK: [[TYPE_i16]] = metadata !{metadata !"short", metadata [[TYPE_char]],
-// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !3
+// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
// PATH: [[TAG_i32]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
// PATH: [[TAG_A_f32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 4}
diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp
index 93690361906b..7ba058bffe66 100644
--- a/test/CodeGen/tbaa-for-vptr.cpp
+++ b/test/CodeGen/tbaa-for-vptr.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -emit-llvm -o - -O0 -fsanitize=thread %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -fsanitize=thread %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -o - -O1 %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -o - -O1 -relaxed-aliasing -fsanitize=thread %s | FileCheck %s
//
-// RUN: %clang_cc1 -emit-llvm -o - -O0 %s | FileCheck %s --check-prefix=NOTBAA
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s --check-prefix=NOTBAA
// RUN: %clang_cc1 -emit-llvm -o - -O2 -relaxed-aliasing %s | FileCheck %s --check-prefix=NOTBAA
//
// Check that we generate TBAA for vtable pointer loads and stores.
@@ -23,5 +23,6 @@ void CallFoo(A *a) {
// CHECK: %{{.*}} = load {{.*}} !tbaa ![[NUM:[0-9]+]]
// CHECK: store {{.*}} !tbaa ![[NUM]]
-// CHECK: [[NUM]] = metadata !{metadata !"vtable pointer", metadata !{{.*}}}
+// CHECK: [[NUM]] = metadata !{metadata [[TYPE:!.*]], metadata [[TYPE]], i64 0}
+// CHECK: [[TYPE]] = metadata !{metadata !"vtable pointer", metadata !{{.*}}
// NOTBAA-NOT: = metadata !{metadata !"Simple C/C++ TBAA"}
diff --git a/test/CodeGen/tbaa-ms-abi.cpp b/test/CodeGen/tbaa-ms-abi.cpp
new file mode 100644
index 000000000000..67390b1a8a54
--- /dev/null
+++ b/test/CodeGen/tbaa-ms-abi.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -cxx-abi microsoft -triple i686-pc-win32 -disable-llvm-optzns -emit-llvm -o - -O1 %s | FileCheck %s
+//
+// Test that TBAA works in the Microsoft C++ ABI. We used to error out while
+// attempting to mangle RTTI.
+
+struct StructA {
+ int a;
+};
+
+struct StructB : virtual StructA {
+ StructB();
+};
+
+StructB::StructB() {
+ a = 42;
+// CHECK: store i32 42, i32* {{.*}}, !tbaa [[TAG_A_i32:!.*]]
+}
+
+// CHECK: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
+// CHECK: [[TYPE_INT:!.*]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]], i64 0}
+// CHECK: [[TAG_A_i32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_A]] = metadata !{metadata !"?AUStructA@@", metadata [[TYPE_INT]], i64 0}
diff --git a/test/CodeGen/tbaa-struct.cpp b/test/CodeGen/tbaa-struct.cpp
index 6d593a3c1b24..f8bd1245ceef 100644
--- a/test/CodeGen/tbaa-struct.cpp
+++ b/test/CodeGen/tbaa-struct.cpp
@@ -65,10 +65,12 @@ void copy5(struct six *a, struct six *b) {
// CHECK: [[TS]] = metadata !{i64 0, i64 2, metadata !{{.*}}, i64 4, i64 4, metadata !{{.*}}, i64 8, i64 1, metadata !{{.*}}, i64 12, i64 4, metadata !{{.*}}}
// CHECK: [[CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !{{.*}}}
-// CHECK: [[INT:!.*]] = metadata !{metadata !"int", metadata [[CHAR]]}
+// CHECK: [[TAG_INT:!.*]] = metadata !{metadata [[INT:!.*]], metadata [[INT]], i64 0}
+// CHECK: [[INT]] = metadata !{metadata !"int", metadata [[CHAR]]
+// CHECK: [[TAG_CHAR:!.*]] = metadata !{metadata [[CHAR]], metadata [[CHAR]], i64 0}
// (offset, size) = (0,1) char; (4,2) short; (8,4) int; (12,1) char; (16,4) int; (20,4) int
// CHECK: [[TS2]] = metadata !{i64 0, i64 1, metadata !{{.*}}, i64 4, i64 2, metadata !{{.*}}, i64 8, i64 4, metadata !{{.*}}, i64 12, i64 1, metadata !{{.*}}, i64 16, i64 4, metadata {{.*}}, i64 20, i64 4, metadata {{.*}}}
// (offset, size) = (0,8) char; (0,2) char; (4,8) char
// CHECK: [[TS3]] = metadata !{i64 0, i64 8, metadata !{{.*}}, i64 0, i64 2, metadata !{{.*}}, i64 4, i64 8, metadata !{{.*}}}
-// CHECK: [[TS4]] = metadata !{i64 0, i64 1, metadata [[CHAR]], i64 1, i64 1, metadata [[CHAR]], i64 2, i64 1, metadata [[CHAR]]}
-// CHECK: [[TS5]] = metadata !{i64 0, i64 1, metadata [[CHAR]], i64 4, i64 4, metadata [[INT]], i64 4, i64 1, metadata [[CHAR]], i64 5, i64 1, metadata [[CHAR]]}
+// CHECK: [[TS4]] = metadata !{i64 0, i64 1, metadata [[TAG_CHAR]], i64 1, i64 4, metadata [[TAG_INT]], i64 1, i64 1, metadata [[TAG_CHAR]], i64 2, i64 1, metadata [[TAG_CHAR]]}
+// CHECK: [[TS5]] = metadata !{i64 0, i64 1, metadata [[TAG_CHAR]], i64 4, i64 4, metadata [[TAG_INT]], i64 4, i64 1, metadata [[TAG_CHAR]], i64 5, i64 1, metadata [[TAG_CHAR]]}
diff --git a/test/CodeGen/tbaa-thread-sanitizer.cpp b/test/CodeGen/tbaa-thread-sanitizer.cpp
new file mode 100644
index 000000000000..abffae3a8fab
--- /dev/null
+++ b/test/CodeGen/tbaa-thread-sanitizer.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread -relaxed-aliasing -O1 | FileCheck %s
+
+// Make sure we do not crash when relaxed-aliasing is on.
+// CHECK-NOT: !tbaa
+struct iterator { void *node; };
+
+struct pair {
+ iterator first;
+ pair(const iterator &a) : first(a) {}
+};
+
+void equal_range() {
+ (void)pair(iterator());
+}
diff --git a/test/CodeGen/tbaa.cpp b/test/CodeGen/tbaa.cpp
index afb8893d3e6a..92d31e5ae293 100644
--- a/test/CodeGen/tbaa.cpp
+++ b/test/CodeGen/tbaa.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -no-struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
// Test TBAA metadata generated by front-end.
typedef unsigned char uint8_t;
@@ -46,8 +46,8 @@ typedef struct
uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32:!.*]]
@@ -58,8 +58,8 @@ uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16:!.*]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_A_f16:!.*]]
@@ -70,8 +70,8 @@ uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
uint32_t g3(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32:!.*]]
@@ -82,8 +82,8 @@ uint32_t g3(StructA *A, StructB *B, uint64_t count) {
uint32_t g4(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_B_a_f16:!.*]]
@@ -94,8 +94,8 @@ uint32_t g4(StructA *A, StructB *B, uint64_t count) {
uint32_t g5(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_f32:!.*]]
@@ -106,8 +106,8 @@ uint32_t g5(StructA *A, StructB *B, uint64_t count) {
uint32_t g6(StructA *A, StructB *B, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32_2:!.*]]
@@ -118,8 +118,8 @@ uint32_t g6(StructA *A, StructB *B, uint64_t count) {
uint32_t g7(StructA *A, StructS *S, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32:!.*]]
@@ -130,8 +130,8 @@ uint32_t g7(StructA *A, StructS *S, uint64_t count) {
uint32_t g8(StructA *A, StructS *S, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_A_f32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_S_f16:!.*]]
@@ -142,8 +142,8 @@ uint32_t g8(StructA *A, StructS *S, uint64_t count) {
uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S2_f32:!.*]]
@@ -154,8 +154,8 @@ uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_i16]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa [[TAG_S2_f16:!.*]]
@@ -166,8 +166,8 @@ uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
uint32_t g11(StructC *C, StructD *D, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_C_b_a_f32:!.*]]
// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_D_b_a_f32:!.*]]
@@ -178,8 +178,8 @@ uint32_t g11(StructC *C, StructD *D, uint64_t count) {
uint32_t g12(StructC *C, StructD *D, uint64_t count) {
// CHECK: define i32 @{{.*}}(
-// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
-// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
// TODO: differentiate the two accesses.
// PATH: define i32 @{{.*}}(
// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_B_a_f32]]
@@ -203,7 +203,7 @@ struct five {
char g13(struct five *a, struct five *b) {
return a->b;
// CHECK: define signext i8 @{{.*}}(
-// CHECK: load i8* %{{.*}}, align 1, !tbaa !1
+// CHECK: load i8* %{{.*}}, align 1, !tbaa [[TAG_char:!.*]]
// PATH: define signext i8 @{{.*}}(
// PATH: load i8* %{{.*}}, align 1, !tbaa [[TAG_five_b:!.*]]
}
@@ -216,18 +216,35 @@ struct six {
};
char g14(struct six *a, struct six *b) {
// CHECK: define signext i8 @{{.*}}(
-// CHECK: load i8* %{{.*}}, align 1, !tbaa !1
+// CHECK: load i8* %{{.*}}, align 1, !tbaa [[TAG_char]]
// PATH: define signext i8 @{{.*}}(
// PATH: load i8* %{{.*}}, align 1, !tbaa [[TAG_six_b:!.*]]
return a->b;
}
-// CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2}
-// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: !4 = metadata !{metadata !"int", metadata !1}
-// CHECK: !5 = metadata !{metadata !"short", metadata !1}
+// Types that differ only by name may alias.
+typedef StructS StructS3;
+uint32_t g15(StructS *S, StructS3 *S3, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_i32]]
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa [[TAG_S_f32]]
+ S->f32 = 1;
+ S3->f32 = 4;
+ return S->f32;
+}
+
+// CHECK: [[TYPE_char:!.*]] = metadata !{metadata !"omnipotent char", metadata [[TAG_cxx_tbaa:!.*]],
+// CHECK: [[TAG_cxx_tbaa]] = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: [[TAG_i32]] = metadata !{metadata [[TYPE_i32:!.*]], metadata [[TYPE_i32]], i64 0}
+// CHECK: [[TYPE_i32]] = metadata !{metadata !"int", metadata [[TYPE_char]],
+// CHECK: [[TAG_i16]] = metadata !{metadata [[TYPE_i16:!.*]], metadata [[TYPE_i16]], i64 0}
+// CHECK: [[TYPE_i16]] = metadata !{metadata !"short", metadata [[TYPE_char]],
+// CHECK: [[TAG_char]] = metadata !{metadata [[TYPE_char]], metadata [[TYPE_char]], i64 0}
-// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !3
+// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
// PATH: [[TAG_i32]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
// PATH: [[TAG_A_f32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 4}
@@ -250,6 +267,6 @@ char g14(struct six *a, struct six *b) {
// PATH: [[TAG_D_b_a_f32]] = metadata !{metadata [[TYPE_D:!.*]], metadata [[TYPE_INT]], i64 12}
// PATH: [[TYPE_D]] = metadata !{metadata !"_ZTS7StructD", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_B]], i64 4, metadata [[TYPE_INT]], i64 28, metadata [[TYPE_CHAR]], i64 32}
// PATH: [[TAG_five_b]] = metadata !{metadata [[TYPE_five:!.*]], metadata [[TYPE_CHAR]], i64 1}
-// PATH: [[TYPE_five]] = metadata !{metadata !"_ZTS4five", metadata [[TYPE_CHAR]], i64 0, metadata [[TYPE_CHAR]], i64 1, metadata [[TYPE_CHAR]], i64 2}
+// PATH: [[TYPE_five]] = metadata !{metadata !"_ZTS4five", metadata [[TYPE_CHAR]], i64 0, metadata [[TYPE_INT]], i64 1, metadata [[TYPE_CHAR]], i64 1, metadata [[TYPE_CHAR]], i64 2}
// PATH: [[TAG_six_b]] = metadata !{metadata [[TYPE_six:!.*]], metadata [[TYPE_CHAR]], i64 4}
// PATH: [[TYPE_six]] = metadata !{metadata !"_ZTS3six", metadata [[TYPE_CHAR]], i64 0, metadata [[TYPE_INT]], i64 4, metadata [[TYPE_CHAR]], i64 4, metadata [[TYPE_CHAR]], i64 5}
diff --git a/test/CodeGen/tbm-builtins.c b/test/CodeGen/tbm-builtins.c
new file mode 100644
index 000000000000..e3a702161ecc
--- /dev/null
+++ b/test/CodeGen/tbm-builtins.c
@@ -0,0 +1,137 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned int test__bextri_u32(unsigned int a) {
+ // CHECK: call i32 @llvm.x86.tbm.bextri.u32
+ return __bextri_u32(a, 1);
+}
+
+unsigned long long test__bextri_u64(unsigned long long a) {
+ // CHECK: call i64 @llvm.x86.tbm.bextri.u64
+ return __bextri_u64(a, 2);
+}
+
+unsigned long long test__bextri_u64_bigint(unsigned long long a) {
+ // CHECK: call i64 @llvm.x86.tbm.bextri.u64
+ return __bextri_u64(a, 0x7fffffffffLL);
+}
+
+unsigned int test__blcfill_u32(unsigned int a) {
+ // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
+ // CHECK-NEXT: %{{.*}} = and i32 [[TMP]], [[SRC]]
+ return __blcfill_u32(a);
+}
+
+unsigned long long test__blcfill_u64(unsigned long long a) {
+ // CHECK: [[TMPT:%.*]] = add i64 [[SRC:%.*]], 1
+ // CHECK-NEXT: %{{.*}} = and i64 [[TMP]], [[SRC]]
+ return __blcfill_u64(a);
+}
+
+unsigned int test__blci_u32(unsigned int a) {
+ // CHECK: [[TMP:%.*]] = sub i32 -2, [[SRC:%.*]]
+ // CHECK-NEXT: %{{.*}} = or i32 [[TMP]], [[SRC]]
+ return __blci_u32(a);
+}
+
+unsigned long long test__blci_u64(unsigned long long a) {
+ // CHECK: [[TMP:%.*]] = sub i64 -2, [[SRC:%.*]]
+ // CHECK-NEXT: %{{.*}} = or i64 [[TMP]], [[SRC]]
+ return __blci_u64(a);
+}
+
+unsigned int test__blcic_u32(unsigned int a) {
+ // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC]], 1
+ // CHECK-NEXT: {{.*}} = and i32 [[TMP2]], [[TMP1]]
+ return __blcic_u32(a);
+}
+
+unsigned long long test__blcic_u64(unsigned long long a) {
+ // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC]], 1
+ // CHECK-NEXT: {{.*}} = and i64 [[TMP2]], [[TMP1]]
+ return __blcic_u64(a);
+}
+
+unsigned int test__blcmsk_u32(unsigned int a) {
+ // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = xor i32 [[TMP]], [[SRC]]
+ return __blcmsk_u32(a);
+}
+
+unsigned long long test__blcmsk_u64(unsigned long long a) {
+ // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = xor i64 [[TMP]], [[SRC]]
+ return __blcmsk_u64(a);
+}
+
+unsigned int test__blcs_u32(unsigned int a) {
+ // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP]], [[SRC]]
+ return __blcs_u32(a);
+}
+
+unsigned long long test__blcs_u64(unsigned long long a) {
+ // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP]], [[SRC]]
+ return __blcs_u64(a);
+}
+
+unsigned int test__blsfill_u32(unsigned int a) {
+ // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP]], [[SRC]]
+ return __blsfill_u32(a);
+}
+
+unsigned long long test__blsfill_u64(unsigned long long a) {
+ // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP]], [[SRC]]
+ return __blsfill_u64(a);
+}
+
+unsigned int test__blsic_u32(unsigned int a) {
+ // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP2]], [[TMP1]]
+ return __blsic_u32(a);
+}
+
+unsigned long long test__blsic_u64(unsigned long long a) {
+ // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP2]], [[TMP1]]
+ return __blsic_u64(a);
+}
+
+unsigned int test__t1mskc_u32(unsigned int a) {
+ // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP2]], [[TMP1]]
+ return __t1mskc_u32(a);
+}
+
+unsigned long long test__t1mskc_u64(unsigned long long a) {
+ // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], 1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP2]], [[TMP1]]
+ return __t1mskc_u64(a);
+}
+
+unsigned int test__tzmsk_u32(unsigned int a) {
+ // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = and i32 [[TMP2]], [[TMP1]]
+ return __tzmsk_u32(a);
+}
+
+unsigned long long test__tzmsk_u64(unsigned long long a) {
+ // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: {{.*}} = and i64 [[TMP2]], [[TMP1]]
+ return __tzmsk_u64(a);
+}
diff --git a/test/CodeGen/transparent-union.c b/test/CodeGen/transparent-union.c
index afdb3d6090b0..21040e4da05b 100644
--- a/test/CodeGen/transparent-union.c
+++ b/test/CodeGen/transparent-union.c
@@ -10,7 +10,7 @@ typedef union {
void f0(transp_t0 obj);
-// CHECK: define void @f1_0(i32* %a0)
+// CHECK-LABEL: define void @f1_0(i32* %a0)
// CHECK: call void @f0(%union.transp_t0* byval align 4 %{{.*}})
// CHECK: call void %{{.*}}(i8* %{{[a-z0-9]*}})
// CHECK: }
diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c
index bc8bc700636c..51034108ee43 100644
--- a/test/CodeGen/trapv.c
+++ b/test/CodeGen/trapv.c
@@ -3,7 +3,7 @@
unsigned int ui, uj, uk;
int i, j, k;
-// CHECK: define void @test0()
+// CHECK-LABEL: define void @test0()
void test0() {
// -ftrapv doesn't affect unsigned arithmetic.
// CHECK: [[T1:%.*]] = load i32* @uj
@@ -23,7 +23,7 @@ void test0() {
i = j + k;
}
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
void test1() {
extern void opaque(int);
opaque(i++);
@@ -37,7 +37,7 @@ void test1() {
// CHECK: call void @llvm.trap()
}
-// CHECK: define void @test2()
+// CHECK-LABEL: define void @test2()
void test2() {
extern void opaque(int);
opaque(++i);
@@ -51,7 +51,7 @@ void test2() {
// CHECK: call void @llvm.trap()
}
-// CHECK: define void @test3(
+// CHECK-LABEL: define void @test3(
void test3(int a, int b, float c, float d) {
// CHECK-NOT: @llvm.trap
(void)(a / b);
diff --git a/test/CodeGen/unsigned-overflow.c b/test/CodeGen/unsigned-overflow.c
index 341ea355636b..01ed0bf8cb5e 100644
--- a/test/CodeGen/unsigned-overflow.c
+++ b/test/CodeGen/unsigned-overflow.c
@@ -8,7 +8,7 @@ unsigned int ii, ij, ik;
extern void opaquelong(unsigned long);
extern void opaqueint(unsigned int);
-// CHECK: define void @testlongadd()
+// CHECK-LABEL: define void @testlongadd()
void testlongadd() {
// CHECK: [[T1:%.*]] = load i64* @lj
@@ -20,7 +20,7 @@ void testlongadd() {
li = lj + lk;
}
-// CHECK: define void @testlongsub()
+// CHECK-LABEL: define void @testlongsub()
void testlongsub() {
// CHECK: [[T1:%.*]] = load i64* @lj
@@ -32,7 +32,7 @@ void testlongsub() {
li = lj - lk;
}
-// CHECK: define void @testlongmul()
+// CHECK-LABEL: define void @testlongmul()
void testlongmul() {
// CHECK: [[T1:%.*]] = load i64* @lj
@@ -44,7 +44,7 @@ void testlongmul() {
li = lj * lk;
}
-// CHECK: define void @testlongpostinc()
+// CHECK-LABEL: define void @testlongpostinc()
void testlongpostinc() {
opaquelong(li++);
@@ -55,7 +55,7 @@ void testlongpostinc() {
// CHECK: call void @__ubsan_handle_add_overflow
}
-// CHECK: define void @testlongpreinc()
+// CHECK-LABEL: define void @testlongpreinc()
void testlongpreinc() {
opaquelong(++li);
@@ -66,7 +66,7 @@ void testlongpreinc() {
// CHECK: call void @__ubsan_handle_add_overflow
}
-// CHECK: define void @testintadd()
+// CHECK-LABEL: define void @testintadd()
void testintadd() {
// CHECK: [[T1:%.*]] = load i32* @ij
@@ -78,7 +78,7 @@ void testintadd() {
ii = ij + ik;
}
-// CHECK: define void @testintsub()
+// CHECK-LABEL: define void @testintsub()
void testintsub() {
// CHECK: [[T1:%.*]] = load i32* @ij
@@ -90,7 +90,7 @@ void testintsub() {
ii = ij - ik;
}
-// CHECK: define void @testintmul()
+// CHECK-LABEL: define void @testintmul()
void testintmul() {
// CHECK: [[T1:%.*]] = load i32* @ij
@@ -102,7 +102,7 @@ void testintmul() {
ii = ij * ik;
}
-// CHECK: define void @testintpostinc()
+// CHECK-LABEL: define void @testintpostinc()
void testintpostinc() {
opaqueint(ii++);
@@ -113,7 +113,7 @@ void testintpostinc() {
// CHECK: call void @__ubsan_handle_add_overflow
}
-// CHECK: define void @testintpreinc()
+// CHECK-LABEL: define void @testintpreinc()
void testintpreinc() {
opaqueint(++ii);
diff --git a/test/CodeGen/unsigned-promotion.c b/test/CodeGen/unsigned-promotion.c
index c263c0c946b0..2c3415201ce7 100644
--- a/test/CodeGen/unsigned-promotion.c
+++ b/test/CodeGen/unsigned-promotion.c
@@ -12,8 +12,8 @@ unsigned char ci, cj, ck;
extern void opaqueshort(unsigned short);
extern void opaquechar(unsigned char);
-// CHECKS: define void @testshortadd()
-// CHECKU: define void @testshortadd()
+// CHECKS-LABEL: define void @testshortadd()
+// CHECKU-LABEL: define void @testshortadd()
void testshortadd() {
// CHECKS: load i16* @sj
// CHECKS: load i16* @sk
@@ -33,8 +33,8 @@ void testshortadd() {
si = sj + sk;
}
-// CHECKS: define void @testshortsub()
-// CHECKU: define void @testshortsub()
+// CHECKS-LABEL: define void @testshortsub()
+// CHECKU-LABEL: define void @testshortsub()
void testshortsub() {
// CHECKS: load i16* @sj
@@ -55,8 +55,8 @@ void testshortsub() {
si = sj - sk;
}
-// CHECKS: define void @testshortmul()
-// CHECKU: define void @testshortmul()
+// CHECKS-LABEL: define void @testshortmul()
+// CHECKU-LABEL: define void @testshortmul()
void testshortmul() {
// CHECKS: load i16* @sj
@@ -76,8 +76,8 @@ void testshortmul() {
si = sj * sk;
}
-// CHECKS: define void @testcharadd()
-// CHECKU: define void @testcharadd()
+// CHECKS-LABEL: define void @testcharadd()
+// CHECKU-LABEL: define void @testcharadd()
void testcharadd() {
// CHECKS: load i8* @cj
@@ -98,8 +98,8 @@ void testcharadd() {
ci = cj + ck;
}
-// CHECKS: define void @testcharsub()
-// CHECKU: define void @testcharsub()
+// CHECKS-LABEL: define void @testcharsub()
+// CHECKU-LABEL: define void @testcharsub()
void testcharsub() {
// CHECKS: load i8* @cj
@@ -120,8 +120,8 @@ void testcharsub() {
ci = cj - ck;
}
-// CHECKS: define void @testcharmul()
-// CHECKU: define void @testcharmul()
+// CHECKS-LABEL: define void @testcharmul()
+// CHECKU-LABEL: define void @testcharmul()
void testcharmul() {
// CHECKS: load i8* @cj
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index e505a6e9e277..527237578ee4 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -fexceptions -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix NOEXC %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix CHECK-NOEXC %s
int opaque();
diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c
index 3fa5f1441d2f..6c14b7fa79eb 100644
--- a/test/CodeGen/vector.c
+++ b/test/CodeGen/vector.c
@@ -55,3 +55,10 @@ unsigned long test_epi16(__m128i x) { return _mm_extract_epi16(x, 3); }
// CHECK: @test_epi16
// CHECK: extractelement <8 x i16> {{.*}}, i32 3
// CHECK: zext i16 {{.*}} to i32
+
+void extractinttypes() {
+ extern int check_extract_result_int;
+ extern __typeof(_mm_extract_epi8(_mm_setzero_si128(), 3)) check_result_int;
+ extern __typeof(_mm_extract_epi16(_mm_setzero_si128(), 3)) check_result_int;
+ extern __typeof(_mm_extract_epi32(_mm_setzero_si128(), 3)) check_result_int;
+}
diff --git a/test/CodeGen/visibility.c b/test/CodeGen/visibility.c
index 3082b7b6ea6f..8e153b893a3f 100644
--- a/test/CodeGen/visibility.c
+++ b/test/CodeGen/visibility.c
@@ -23,15 +23,15 @@ static char g_deferred[] = "hello";
// CHECK-PROTECTED: @test4 = hidden global i32 10
// CHECK-HIDDEN: @test4 = hidden global i32 10
-// CHECK-DEFAULT: define i32 @f_def()
+// CHECK-DEFAULT-LABEL: define i32 @f_def()
// CHECK-DEFAULT: declare void @f_ext()
-// CHECK-DEFAULT: define internal void @f_deferred()
-// CHECK-PROTECTED: define protected i32 @f_def()
+// CHECK-DEFAULT-LABEL: define internal void @f_deferred()
+// CHECK-PROTECTED-LABEL: define protected i32 @f_def()
// CHECK-PROTECTED: declare void @f_ext()
-// CHECK-PROTECTED: define internal void @f_deferred()
-// CHECK-HIDDEN: define hidden i32 @f_def()
+// CHECK-PROTECTED-LABEL: define internal void @f_deferred()
+// CHECK-HIDDEN-LABEL: define hidden i32 @f_def()
// CHECK-HIDDEN: declare void @f_ext()
-// CHECK-HIDDEN: define internal void @f_deferred()
+// CHECK-HIDDEN-LABEL: define internal void @f_deferred()
extern void f_ext(void);
@@ -45,22 +45,22 @@ int f_def(void) {
}
// PR8457
-// CHECK-DEFAULT: define void @test1(
-// CHECK-PROTECTED: define void @test1(
-// CHECK-HIDDEN: define void @test1(
+// CHECK-DEFAULT-LABEL: define void @test1(
+// CHECK-PROTECTED-LABEL: define void @test1(
+// CHECK-HIDDEN-LABEL: define void @test1(
struct Test1 { int field; };
void __attribute__((visibility("default"))) test1(struct Test1 *v) { }
// rdar://problem/8595231
-// CHECK-DEFAULT: define void @test2()
-// CHECK-PROTECTED: define void @test2()
-// CHECK-HIDDEN: define void @test2()
+// CHECK-DEFAULT-LABEL: define void @test2()
+// CHECK-PROTECTED-LABEL: define void @test2()
+// CHECK-HIDDEN-LABEL: define void @test2()
void test2(void);
void __attribute__((visibility("default"))) test2(void) {}
-// CHECK-DEFAULT: define hidden void @test3()
-// CHECK-PROTECTED: define hidden void @test3()
-// CHECK-HIDDEN: define hidden void @test3()
+// CHECK-DEFAULT-LABEL: define hidden void @test3()
+// CHECK-PROTECTED-LABEL: define hidden void @test3()
+// CHECK-HIDDEN-LABEL: define hidden void @test3()
extern void test3(void);
__private_extern__ void test3(void) {}
@@ -69,8 +69,8 @@ extern int test4;
__private_extern__ int test4 = 10;
// rdar://12399248
-// CHECK-DEFAULT: define hidden void @test5()
-// CHECK-PROTECTED: define hidden void @test5()
-// CHECK-HIDDEN: define hidden void @test5()
+// CHECK-DEFAULT-LABEL: define hidden void @test5()
+// CHECK-PROTECTED-LABEL: define hidden void @test5()
+// CHECK-HIDDEN-LABEL: define hidden void @test5()
__attribute__((availability(macosx,introduced=10.5,deprecated=10.6)))
__private_extern__ void test5(void) {}
diff --git a/test/CodeGen/vla.c b/test/CodeGen/vla.c
index f63796b39dc2..1757ef778794 100644
--- a/test/CodeGen/vla.c
+++ b/test/CodeGen/vla.c
@@ -37,7 +37,7 @@ void g(int count) {
}
// rdar://8403108
-// CHECK: define void @f_8403108
+// CHECK-LABEL: define void @f_8403108
void f_8403108(unsigned x) {
// CHECK: call i8* @llvm.stacksave()
char s1[x];
@@ -86,7 +86,7 @@ int test2(int n)
}
// http://llvm.org/PR8567
-// CHECK: define double @test_PR8567
+// CHECK-LABEL: define double @test_PR8567
double test_PR8567(int n, double (*p)[n][5]) {
// CHECK: [[NV:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[PV:%.*]] = alloca [5 x double]*, align 4
@@ -104,7 +104,7 @@ double test_PR8567(int n, double (*p)[n][5]) {
}
int test4(unsigned n, char (*p)[n][n+1][6]) {
- // CHECK: define i32 @test4(
+ // CHECK-LABEL: define i32 @test4(
// CHECK: [[N:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[P:%.*]] = alloca [6 x i8]*, align 4
// CHECK-NEXT: [[P2:%.*]] = alloca [6 x i8]*, align 4
@@ -146,7 +146,7 @@ int test4(unsigned n, char (*p)[n][n+1][6]) {
// rdar://11485774
void test5(void)
{
- // CHECK: define void @test5(
+ // CHECK-LABEL: define void @test5(
int a[5], i = 0;
// CHECK: [[A:%.*]] = alloca [5 x i32], align 4
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
@@ -169,7 +169,7 @@ void test5(void)
void test6(void)
{
- // CHECK: define void @test6(
+ // CHECK-LABEL: define void @test6(
int n = 20, **a, i=0;
// CHECK: [[N:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[A:%.*]] = alloca i32**, align 4
@@ -192,6 +192,6 @@ void test6(void)
// Follow gcc's behavior for VLAs in parameter lists. PR9559.
void test7(int a[b(0)]) {
- // CHECK: define void @test7(
+ // CHECK-LABEL: define void @test7(
// CHECK: call i32 @b(i8* null)
}
diff --git a/test/CodeGen/vld_dup.c b/test/CodeGen/vld_dup.c
index 2bc251989b6a..95904124c596 100644
--- a/test/CodeGen/vld_dup.c
+++ b/test/CodeGen/vld_dup.c
@@ -1,7 +1,7 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple armv7a-linux-gnueabi \
// RUN: -target-cpu cortex-a8 \
-// RUN: -emit-llvm -O0 -o - %s | FileCheck %s
+// RUN: -emit-llvm -o - %s | FileCheck %s
#include <arm_neon.h>
int main(){
int32_t v0[3];
diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c
index 65511593d32a..d1861d545899 100644
--- a/test/CodeGen/volatile-1.c
+++ b/test/CodeGen/volatile-1.c
@@ -22,49 +22,49 @@ int printf(const char *, ...);
// that do implicit lvalue-to-rvalue conversion are substantially
// reduced.
-// CHECK: define void @test()
+// CHECK-LABEL: define void @test()
void test() {
// CHECK: load volatile [[INT]]* @i
i;
- // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: sitofp [[INT]]
(float)(ci);
- // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
(void)ci;
// CHECK-NEXT: bitcast
// CHECK-NEXT: memcpy
(void)a;
- // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
(void)(ci=ci);
// CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* @j
// CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i
(void)(i=j);
- // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
// Not sure why they're ordered this way.
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
ci+=ci;
- // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
// These additions can be elided
// CHECK-NEXT: add [[INT]] [[R]], [[R2]]
// CHECK-NEXT: add [[INT]] [[I]], [[I2]]
@@ -303,7 +303,7 @@ void test() {
}
extern volatile enum X x;
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
void test1() {
extern void test1_helper(void);
test1_helper();
@@ -313,3 +313,15 @@ void test1() {
(void) x;
return x;
}
+
+// CHECK: define {{.*}} @test2()
+int test2() {
+ // CHECK: load volatile i32*
+ // CHECK-NEXT: load volatile i32*
+ // CHECK-NEXT: load volatile i32*
+ // CHECK-NEXT: add i32
+ // CHECK-NEXT: add i32
+ // CHECK-NEXT: store volatile i32
+ // CHECK-NEXT: ret i32
+ return i += ci;
+}
diff --git a/test/CodeGen/volatile-2.c b/test/CodeGen/volatile-2.c
index 3d342de69005..18d0d318ef82 100644
--- a/test/CodeGen/volatile-2.c
+++ b/test/CodeGen/volatile-2.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
void test0() {
- // CHECK: define void @test0()
+ // CHECK-LABEL: define void @test0()
// CHECK: [[F:%.*]] = alloca float
- // CHECK-NEXT: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @test0_v, i32 0, i32 0)
- // CHECK-NEXT: load volatile float* getelementptr inbounds ({{.*}} @test0_v, i32 0, i32 1)
+ // CHECK-NEXT: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @test0_v, i32 0, i32 0), align 4
+ // CHECK-NEXT: load volatile float* getelementptr inbounds ({{.*}} @test0_v, i32 0, i32 1), align 4
// CHECK-NEXT: store float [[REAL]], float* [[F]], align 4
// CHECK-NEXT: ret void
extern volatile _Complex float test0_v;
@@ -12,11 +12,11 @@ void test0() {
}
void test1() {
- // CHECK: define void @test1()
- // CHECK: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: [[IMAG:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
- // CHECK-NEXT: store volatile float [[REAL]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: store volatile float [[IMAG]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
+ // CHECK-LABEL: define void @test1()
+ // CHECK: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[IMAG:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1), align 4
+ // CHECK-NEXT: store volatile float [[REAL]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0), align 4
+ // CHECK-NEXT: store volatile float [[IMAG]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1), align 4
// CHECK-NEXT: ret void
extern volatile _Complex float test1_v;
test1_v = test1_v;
diff --git a/test/CodeGen/volatile-complex.c b/test/CodeGen/volatile-complex.c
new file mode 100644
index 000000000000..71e5db6f5cf8
--- /dev/null
+++ b/test/CodeGen/volatile-complex.c
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+// Validate that volatile _Complex loads and stores are generated
+// properly, including their alignment (even when overaligned).
+//
+// This test assumes that floats are 32-bit aligned and doubles are
+// 64-bit aligned, and uses x86-64 as a target that should have this
+// datalayout.
+
+// CHECK: target datalayout = "{{.*}}f32:32:32-f64:64:64{{.*}}"
+
+volatile _Complex float cf;
+volatile _Complex double cd;
+volatile _Complex float cf32 __attribute__((aligned(32)));
+volatile _Complex double cd32 __attribute__((aligned(32)));
+
+// CHECK-LABEL-LABEL: define void @test_cf()
+void test_cf() {
+ // CHECK: load volatile float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 0), align 4
+ // CHECK-NEXT: load volatile float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 1), align 4
+ (void)(cf);
+ // CHECK-NEXT: [[R:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 0), align 4
+ // CHECK-NEXT: [[I:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 1), align 4
+ // CHECK-NEXT: store volatile float [[R]], float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 0), align 4
+ // CHECK-NEXT: store volatile float [[I]], float* getelementptr inbounds ({ float, float }* @cf, i32 0, i32 1), align 4
+ (void)(cf=cf);
+ // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL-LABEL: define void @test_cd()
+void test_cd() {
+ // CHECK: load volatile double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 0), align 8
+ // CHECK-NEXT: load volatile double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 1), align 8
+ (void)(cd);
+ // CHECK-NEXT: [[R:%.*]] = load volatile double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 0), align 8
+ // CHECK-NEXT: [[I:%.*]] = load volatile double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 1), align 8
+ // CHECK-NEXT: store volatile double [[R]], double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 0), align 8
+ // CHECK-NEXT: store volatile double [[I]], double* getelementptr inbounds ({ double, double }* @cd, i32 0, i32 1), align 8
+ (void)(cd=cd);
+ // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL-LABEL: define void @test_cf32()
+void test_cf32() {
+ // CHECK: load volatile float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 0), align 32
+ // CHECK-NEXT: load volatile float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 1), align 4
+ (void)(cf32);
+ // CHECK-NEXT: [[R:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 0), align 32
+ // CHECK-NEXT: [[I:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 1), align 4
+ // CHECK-NEXT: store volatile float [[R]], float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 0), align 32
+ // CHECK-NEXT: store volatile float [[I]], float* getelementptr inbounds ({ float, float }* @cf32, i32 0, i32 1), align 4
+ (void)(cf32=cf32);
+ // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL-LABEL: define void @test_cd32()
+void test_cd32() {
+ // CHECK: load volatile double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 0), align 32
+ // CHECK-NEXT: load volatile double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 1), align 8
+ (void)(cd32);
+ // CHECK-NEXT: [[R:%.*]] = load volatile double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 0), align 32
+ // CHECK-NEXT: [[I:%.*]] = load volatile double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 1), align 8
+ // CHECK-NEXT: store volatile double [[R]], double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 0), align 32
+ // CHECK-NEXT: store volatile double [[I]], double* getelementptr inbounds ({ double, double }* @cd32, i32 0, i32 1), align 8
+ (void)(cd32=cd32);
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGen/wchar-const.c b/test/CodeGen/wchar-const.c
index a9e7e523f96d..2e9af53a14de 100644
--- a/test/CodeGen/wchar-const.c
+++ b/test/CodeGen/wchar-const.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple i386-pc-win32 | FileCheck %s --check-prefix=WIN
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-apple-darwin | FileCheck %s --check-prefix=DAR
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple i386-pc-win32 | FileCheck %s --check-prefix=CHECK-WIN
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-apple-darwin | FileCheck %s --check-prefix=CHECK-DAR
// This should pass for any endianness combination of host and target.
// This bit is taken from Sema/wchar.c so we can avoid the wchar.h include.
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 4aa4295ffda2..422e030537e0 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -1,44 +1,44 @@
// RUN: %clang_cc1 -w -fblocks -triple i386-apple-darwin9 -target-cpu yonah -emit-llvm -o - %s | FileCheck %s
-// CHECK: define signext i8 @f0()
+// CHECK-LABEL: define signext i8 @f0()
char f0(void) {
return 0;
}
-// CHECK: define signext i16 @f1()
+// CHECK-LABEL: define signext i16 @f1()
short f1(void) {
return 0;
}
-// CHECK: define i32 @f2()
+// CHECK-LABEL: define i32 @f2()
int f2(void) {
return 0;
}
-// CHECK: define float @f3()
+// CHECK-LABEL: define float @f3()
float f3(void) {
return 0;
}
-// CHECK: define double @f4()
+// CHECK-LABEL: define double @f4()
double f4(void) {
return 0;
}
-// CHECK: define x86_fp80 @f5()
+// CHECK-LABEL: define x86_fp80 @f5()
long double f5(void) {
return 0;
}
-// CHECK: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
+// CHECK-LABEL: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
void f6(char a0, short a1, int a2, long long a3, void *a4) {}
-// CHECK: define void @f7(i32 %a0)
+// CHECK-LABEL: define void @f7(i32 %a0)
typedef enum { A, B, C } e7;
void f7(e7 a0) {}
-// CHECK: define i64 @f8_1()
-// CHECK: define void @f8_2(i32 %a0.0, i32 %a0.1)
+// CHECK-LABEL: define i64 @f8_1()
+// CHECK-LABEL: define void @f8_2(i32 %a0.0, i32 %a0.1)
struct s8 {
int a;
int b;
@@ -48,11 +48,11 @@ void f8_2(struct s8 a0) {}
// This should be passed just as s8.
-// CHECK: define i64 @f9_1()
+// CHECK-LABEL: define i64 @f9_1()
// FIXME: llvm-gcc expands this, this may have some value for the
// backend in terms of optimization but doesn't change the ABI.
-// CHECK: define void @f9_2(%struct.s9* byval align 4 %a0)
+// CHECK-LABEL: define void @f9_2(%struct.s9* byval align 4 %a0)
struct s9 {
int a : 17;
int b;
@@ -123,91 +123,91 @@ struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { whi
// CHECK: void @f28(%struct.s28* noalias sret %agg.result)
struct s28 { int a; int b[]; } f28(void) { while (1) {} }
-// CHECK: define i16 @f29()
+// CHECK-LABEL: define i16 @f29()
struct s29 { struct { } a[1]; char b; char c; } f29(void) { while (1) {} }
-// CHECK: define i16 @f30()
+// CHECK-LABEL: define i16 @f30()
struct s30 { char a; char b : 4; } f30(void) { while (1) {} }
-// CHECK: define float @f31()
+// CHECK-LABEL: define float @f31()
struct s31 { char : 0; float b; char : 0; } f31(void) { while (1) {} }
-// CHECK: define i32 @f32()
+// CHECK-LABEL: define i32 @f32()
struct s32 { char a; unsigned : 0; } f32(void) { while (1) {} }
-// CHECK: define float @f33()
+// CHECK-LABEL: define float @f33()
struct s33 { float a; long long : 0; } f33(void) { while (1) {} }
-// CHECK: define float @f34()
+// CHECK-LABEL: define float @f34()
struct s34 { struct { int : 0; } a; float b; } f34(void) { while (1) {} }
-// CHECK: define i16 @f35()
+// CHECK-LABEL: define i16 @f35()
struct s35 { struct { int : 0; } a; char b; char c; } f35(void) { while (1) {} }
-// CHECK: define i16 @f36()
+// CHECK-LABEL: define i16 @f36()
struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while (1) {} }
-// CHECK: define float @f37()
+// CHECK-LABEL: define float @f37()
struct s37 { float c[1][1]; } f37(void) { while (1) {} }
-// CHECK: define void @f38(%struct.s38* noalias sret %agg.result)
+// CHECK-LABEL: define void @f38(%struct.s38* noalias sret %agg.result)
struct s38 { char a[3]; short b; } f38(void) { while (1) {} }
-// CHECK: define void @f39(%struct.s39* byval align 16 %x)
+// CHECK-LABEL: define void @f39(%struct.s39* byval align 16 %x)
typedef int v39 __attribute((vector_size(16)));
struct s39 { v39 x; };
void f39(struct s39 x) {}
// <rdar://problem/7247671>
-// CHECK: define i32 @f40()
+// CHECK-LABEL: define i32 @f40()
enum e40 { ec0 = 0 };
enum e40 f40(void) { }
-// CHECK: define void ()* @f41()
+// CHECK-LABEL: define void ()* @f41()
typedef void (^vvbp)(void);
vvbp f41(void) { }
-// CHECK: define i32 @f42()
+// CHECK-LABEL: define i32 @f42()
struct s42 { enum e40 f0; } f42(void) { }
-// CHECK: define i64 @f43()
+// CHECK-LABEL: define i64 @f43()
struct s43 { enum e40 f0; int f1; } f43(void) { }
-// CHECK: define void ()* @f44()
+// CHECK-LABEL: define void ()* @f44()
struct s44 { vvbp f0; } f44(void) { }
-// CHECK: define i64 @f45()
+// CHECK-LABEL: define i64 @f45()
struct s45 { vvbp f0; int f1; } f45(void) { }
-// CHECK: define void @f46(i32 %a0)
+// CHECK-LABEL: define void @f46(i32 %a0)
void f46(enum e40 a0) { }
-// CHECK: define void @f47(void ()* %a1)
+// CHECK-LABEL: define void @f47(void ()* %a1)
void f47(vvbp a1) { }
-// CHECK: define void @f48(i32 %a0.0)
+// CHECK-LABEL: define void @f48(i32 %a0.0)
struct s48 { enum e40 f0; };
void f48(struct s48 a0) { }
-// CHECK: define void @f49(i32 %a0.0, i32 %a0.1)
+// CHECK-LABEL: define void @f49(i32 %a0.0, i32 %a0.1)
struct s49 { enum e40 f0; int f1; };
void f49(struct s49 a0) { }
-// CHECK: define void @f50(void ()* %a0.0)
+// CHECK-LABEL: define void @f50(void ()* %a0.0)
struct s50 { vvbp f0; };
void f50(struct s50 a0) { }
-// CHECK: define void @f51(void ()* %a0.0, i32 %a0.1)
+// CHECK-LABEL: define void @f51(void ()* %a0.0, i32 %a0.1)
struct s51 { vvbp f0; int f1; };
void f51(struct s51 a0) { }
-// CHECK: define void @f52(%struct.s52* byval align 4)
+// CHECK-LABEL: define void @f52(%struct.s52* byval align 4)
struct s52 {
long double a;
};
void f52(struct s52 x) {}
-// CHECK: define void @f53(%struct.s53* byval align 4)
+// CHECK-LABEL: define void @f53(%struct.s53* byval align 4)
struct __attribute__((aligned(32))) s53 {
int x;
int y;
@@ -216,18 +216,18 @@ void f53(struct s53 x) {}
typedef unsigned short v2i16 __attribute__((__vector_size__(4)));
-// CHECK: define i32 @f54(i32 %arg.coerce)
+// CHECK-LABEL: define i32 @f54(i32 %arg.coerce)
// rdar://8359483
v2i16 f54(v2i16 arg) { return arg+arg; }
typedef int v4i32 __attribute__((__vector_size__(16)));
-// CHECK: define <2 x i64> @f55(<4 x i32> %arg)
+// CHECK-LABEL: define <2 x i64> @f55(<4 x i32> %arg)
// PR8029
v4i32 f55(v4i32 arg) { return arg+arg; }
-// CHECK: define void @f56(
+// CHECK-LABEL: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
// CHECK: i64 %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: i64 %a4.coerce, %struct.s56_2* byval align 4,
@@ -276,34 +276,34 @@ void f56(char a0, struct s56_0 a1,
a10, a11, a12, a13);
}
-// CHECK: define void @f57(i32 %x.0, i32 %x.1)
+// CHECK-LABEL: define void @f57(i32 %x.0, i32 %x.1)
// CHECK: call void @f57(
struct s57 { _Complex int x; };
void f57(struct s57 x) {} void f57a(void) { f57((struct s57){1}); }
-// CHECK: define void @f58()
+// CHECK-LABEL: define void @f58()
union u58 {};
void f58(union u58 x) {}
-// CHECK: define i64 @f59()
+// CHECK-LABEL: define i64 @f59()
struct s59 { float x __attribute((aligned(8))); };
struct s59 f59() { while (1) {} }
-// CHECK: define void @f60(%struct.s60* byval align 4, i32 %y)
+// CHECK-LABEL: define void @f60(%struct.s60* byval align 4, i32 %y)
struct s60 { int x __attribute((aligned(8))); };
void f60(struct s60 x, int y) {}
-// CHECK: define void @f61(i32 %x, %struct.s61* byval align 16 %y)
+// CHECK-LABEL: define void @f61(i32 %x, %struct.s61* byval align 16 %y)
typedef int T61 __attribute((vector_size(16)));
struct s61 { T61 x; int y; };
void f61(int x, struct s61 y) {}
-// CHECK: define void @f62(i32 %x, %struct.s62* byval align 4)
+// CHECK-LABEL: define void @f62(i32 %x, %struct.s62* byval align 4)
typedef int T62 __attribute((vector_size(16)));
struct s62 { T62 x; int y; } __attribute((packed, aligned(8)));
void f62(int x, struct s62 y) {}
-// CHECK: define i32 @f63
+// CHECK-LABEL: define i32 @f63
// CHECK: ptrtoint
// CHECK: and {{.*}}, -16
// CHECK: inttoptr
@@ -317,15 +317,15 @@ int f63(int i, ...) {
return s.y;
}
-// CHECK: define void @f64(%struct.s64* byval align 4 %x)
+// CHECK-LABEL: define void @f64(%struct.s64* byval align 4 %x)
struct s64 { signed char a[0]; signed char b[]; };
void f64(struct s64 x) {}
-// CHECK: define float @f65()
+// CHECK-LABEL: define float @f65()
struct s65 { signed char a[0]; float b; };
struct s65 f65() { return (struct s65){{},2}; }
-// CHECK: define <2 x i64> @f66
+// CHECK-LABEL: define <2 x i64> @f66
// CHECK: ptrtoint
// CHECK: and {{.*}}, -16
// CHECK: inttoptr
@@ -341,4 +341,4 @@ T66 f66(int i, ...) {
// PR14453
struct s67 { _Complex unsigned short int a; };
void f67(struct s67 x) {}
-// CHECK: define void @f67(%struct.s67* byval align 4 %x)
+// CHECK-LABEL: define void @f67(%struct.s67* byval align 4 %x)
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index e93f9dccbf05..1a8c6001292b 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -w -fblocks -triple i386-pc-linux-gnu -target-cpu pentium4 -emit-llvm -o %t %s
// RUN: FileCheck < %t %s
-// CHECK: define void @f56(
+// CHECK-LABEL: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
// CHECK: i64 %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: <1 x double> %a4, %struct.s56_2* byval align 4,
diff --git a/test/CodeGen/x86_32-arguments-nommx.c b/test/CodeGen/x86_32-arguments-nommx.c
index 40362f796f6c..ce68e3a8916c 100644
--- a/test/CodeGen/x86_32-arguments-nommx.c
+++ b/test/CodeGen/x86_32-arguments-nommx.c
@@ -3,9 +3,9 @@
// no-mmx should put mmx into memory
typedef int __attribute__((vector_size (8))) i32v2;
int a(i32v2 x) { return x[0]; }
-// CHECK: define i32 @a(i64 %x.coerce)
+// CHECK-LABEL: define i32 @a(i64 %x.coerce)
// but SSE2 vectors should still go into an SSE2 register
typedef int __attribute__((vector_size (16))) i32v4;
int b(i32v4 x) { return x[0]; }
-// CHECK: define i32 @b(<4 x i32> %x)
+// CHECK-LABEL: define i32 @b(<4 x i32> %x)
diff --git a/test/CodeGen/x86_32-arguments-realign.c b/test/CodeGen/x86_32-arguments-realign.c
index b08862ee43e4..768e1cc4690f 100644
--- a/test/CodeGen/x86_32-arguments-realign.c
+++ b/test/CodeGen/x86_32-arguments-realign.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -w -fblocks -triple i386-apple-darwin9 -emit-llvm -o %t %s
// RUN: FileCheck < %t %s
-// CHECK: define void @f0(%struct.s0* byval align 4)
+// CHECK-LABEL: define void @f0(%struct.s0* byval align 4)
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 16, i32 4, i1 false)
// CHECK: }
struct s0 { long double a; };
diff --git a/test/CodeGen/x86_32-arguments-win32.c b/test/CodeGen/x86_32-arguments-win32.c
index 77ff9e2ff3dd..f8b09957b36e 100644
--- a/test/CodeGen/x86_32-arguments-win32.c
+++ b/test/CodeGen/x86_32-arguments-win32.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -w -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s
-// CHECK: define i64 @f1_1()
-// CHECK: define void @f1_2(%struct.s1* byval align 4 %a0)
+// CHECK-LABEL: define i64 @f1_1()
+// CHECK-LABEL: define void @f1_2(%struct.s1* byval align 4 %a0)
struct s1 {
int a;
int b;
@@ -9,37 +9,37 @@ struct s1 {
struct s1 f1_1(void) { while (1) {} }
void f1_2(struct s1 a0) {}
-// CHECK: define i32 @f2_1()
+// CHECK-LABEL: define i32 @f2_1()
struct s2 {
short a;
short b;
};
struct s2 f2_1(void) { while (1) {} }
-// CHECK: define i16 @f3_1()
+// CHECK-LABEL: define i16 @f3_1()
struct s3 {
char a;
char b;
};
struct s3 f3_1(void) { while (1) {} }
-// CHECK: define i8 @f4_1()
+// CHECK-LABEL: define i8 @f4_1()
struct s4 {
char a:4;
char b:4;
};
struct s4 f4_1(void) { while (1) {} }
-// CHECK: define i64 @f5_1()
-// CHECK: define void @f5_2(%struct.s5* byval align 4)
+// CHECK-LABEL: define i64 @f5_1()
+// CHECK-LABEL: define void @f5_2(%struct.s5* byval align 4)
struct s5 {
double a;
};
struct s5 f5_1(void) { while (1) {} }
void f5_2(struct s5 a0) {}
-// CHECK: define i32 @f6_1()
-// CHECK: define void @f6_2(%struct.s6* byval align 4 %a0)
+// CHECK-LABEL: define i32 @f6_1()
+// CHECK-LABEL: define void @f6_2(%struct.s6* byval align 4 %a0)
struct s6 {
float a;
};
diff --git a/test/CodeGen/x86_32-fpcc-struct-return.c b/test/CodeGen/x86_32-fpcc-struct-return.c
new file mode 100644
index 000000000000..9f61599fc695
--- /dev/null
+++ b/test/CodeGen/x86_32-fpcc-struct-return.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-REG
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PCC
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-REG
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PCC
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PCC
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-REG
+// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-REG
+// RUN: %clang_cc1 -triple i386-pc-win32 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PCC
+// RUN: %clang_cc1 -triple i386-pc-win32 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-REG
+
+typedef struct { int a,b,c,d; } Big;
+typedef struct { int i; } Small;
+typedef struct { short s; } Short;
+typedef struct { } ZeroSized;
+
+// CHECK-LABEL: define void @returnBig
+// CHECK: ret void
+Big returnBig(Big x) { return x; }
+
+// CHECK-PCC-LABEL: define void @returnSmall
+// CHECK-PCC: ret void
+// CHECK-REG-LABEL: define i32 @returnSmall
+// CHECK-REG: ret i32
+Small returnSmall(Small x) { return x; }
+
+// CHECK-PCC-LABEL: define void @returnShort
+// CHECK-PCC: ret void
+// CHECK-REG-LABEL: define i16 @returnShort
+// CHECK-REG: ret i16
+Short returnShort(Short x) { return x; }
+
+// CHECK-LABEL: define void @returnZero()
+// CHECK: ret void
+ZeroSized returnZero(ZeroSized x) { return x; }
diff --git a/test/CodeGen/x86_64-arguments-nacl.c b/test/CodeGen/x86_64-arguments-nacl.c
index 8f756caba757..1c3f5b0c4a2f 100644
--- a/test/CodeGen/x86_64-arguments-nacl.c
+++ b/test/CodeGen/x86_64-arguments-nacl.c
@@ -21,21 +21,21 @@ struct PP_Var f0() {
return result;
}
-// CHECK: define void @f1(i64 %p1.coerce0, i64 %p1.coerce1)
+// CHECK-LABEL: define void @f1(i64 %p1.coerce0, i64 %p1.coerce1)
void f1(struct PP_Var p1) { while(1) {} }
// long doubles are 64 bits on NaCl
-// CHECK: define double @f5()
+// CHECK-LABEL: define double @f5()
long double f5(void) {
return 0;
}
-// CHECK: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
+// CHECK-LABEL: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
void f6(char a0, short a1, int a2, long long a3, void *a4) {
}
-// CHECK: define i64 @f8_1()
-// CHECK: define void @f8_2(i64 %a0.coerce)
+// CHECK-LABEL: define i64 @f8_1()
+// CHECK-LABEL: define void @f8_2(i64 %a0.coerce)
union u8 {
long double a;
int b;
@@ -43,18 +43,18 @@ union u8 {
union u8 f8_1() { while (1) {} }
void f8_2(union u8 a0) {}
-// CHECK: define i64 @f9()
+// CHECK-LABEL: define i64 @f9()
struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
-// CHECK: define void @f10(i64 %a0.coerce)
+// CHECK-LABEL: define void @f10(i64 %a0.coerce)
struct s10 { int a; int b; int : 0; };
void f10(struct s10 a0) {}
-// CHECK: define double @f11()
+// CHECK-LABEL: define double @f11()
union { long double a; float b; } f11() { while (1) {} }
-// CHECK: define i32 @f12_0()
-// CHECK: define void @f12_1(i32 %a0.coerce)
+// CHECK-LABEL: define i32 @f12_0()
+// CHECK-LABEL: define void @f12_1(i32 %a0.coerce)
struct s12 { int a __attribute__((aligned(16))); };
struct s12 f12_0(void) { while (1) {} }
void f12_1(struct s12 a0) {}
@@ -68,7 +68,7 @@ struct s13_1 { long long f0[2]; };
struct s13_0 f13(int a, int b, int c, int d,
struct s13_1 e, int f) { while (1) {} }
-// CHECK: define void @f20(%struct.s20* byval align 32 %x)
+// CHECK-LABEL: define void @f20(%struct.s20* byval align 32 %x)
struct __attribute__((aligned(32))) s20 {
int x;
int y;
@@ -96,10 +96,10 @@ typedef struct {
int a;
int b;
} s1;
-// CHECK: define i32 @f48(%struct.s1* byval %s)
+// CHECK-LABEL: define i32 @f48(%struct.s1* byval %s)
int __attribute__((pnaclcall)) f48(s1 s) { return s.a; }
-// CHECK: define void @f49(%struct.s1* noalias sret %agg.result)
+// CHECK-LABEL: define void @f49(%struct.s1* noalias sret %agg.result)
s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
union simple_union {
@@ -107,7 +107,7 @@ union simple_union {
char b;
};
// Unions should be passed as byval structs
-// CHECK: define void @f50(%union.simple_union* byval %s)
+// CHECK-LABEL: define void @f50(%union.simple_union* byval %s)
void __attribute__((pnaclcall)) f50(union simple_union s) {}
typedef struct {
@@ -116,5 +116,5 @@ typedef struct {
int b8 : 8;
} bitfield1;
// Bitfields should be passed as byval structs
-// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+// CHECK-LABEL: define void @f51(%struct.bitfield1* byval %bf1)
void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 518ee843308d..5d01d3bf69ed 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -2,49 +2,49 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -target-feature +avx | FileCheck %s -check-prefix=AVX
#include <stdarg.h>
-// CHECK: define signext i8 @f0()
+// CHECK-LABEL: define signext i8 @f0()
char f0(void) {
return 0;
}
-// CHECK: define signext i16 @f1()
+// CHECK-LABEL: define signext i16 @f1()
short f1(void) {
return 0;
}
-// CHECK: define i32 @f2()
+// CHECK-LABEL: define i32 @f2()
int f2(void) {
return 0;
}
-// CHECK: define float @f3()
+// CHECK-LABEL: define float @f3()
float f3(void) {
return 0;
}
-// CHECK: define double @f4()
+// CHECK-LABEL: define double @f4()
double f4(void) {
return 0;
}
-// CHECK: define x86_fp80 @f5()
+// CHECK-LABEL: define x86_fp80 @f5()
long double f5(void) {
return 0;
}
-// CHECK: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
+// CHECK-LABEL: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
void f6(char a0, short a1, int a2, long long a3, void *a4) {
}
-// CHECK: define void @f7(i32 %a0)
+// CHECK-LABEL: define void @f7(i32 %a0)
typedef enum { A, B, C } e7;
void f7(e7 a0) {
}
// Test merging/passing of upper eightbyte with X87 class.
//
-// CHECK: define void @f8_1(%union.u8* noalias sret %agg.result)
-// CHECK: define void @f8_2(%union.u8* byval align 16 %a0)
+// CHECK-LABEL: define void @f8_1(%union.u8* noalias sret %agg.result)
+// CHECK-LABEL: define void @f8_2(%union.u8* byval align 16 %a0)
union u8 {
long double a;
int b;
@@ -52,18 +52,18 @@ union u8 {
union u8 f8_1() { while (1) {} }
void f8_2(union u8 a0) {}
-// CHECK: define i64 @f9()
+// CHECK-LABEL: define i64 @f9()
struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
-// CHECK: define void @f10(i64 %a0.coerce)
+// CHECK-LABEL: define void @f10(i64 %a0.coerce)
struct s10 { int a; int b; int : 0; };
void f10(struct s10 a0) {}
-// CHECK: define void @f11(%union.anon* noalias sret %agg.result)
+// CHECK-LABEL: define void @f11(%union.anon* noalias sret %agg.result)
union { long double a; float b; } f11() { while (1) {} }
-// CHECK: define i32 @f12_0()
-// CHECK: define void @f12_1(i32 %a0.coerce)
+// CHECK-LABEL: define i32 @f12_0()
+// CHECK-LABEL: define void @f12_1(i32 %a0.coerce)
struct s12 { int a __attribute__((aligned(16))); };
struct s12 f12_0(void) { while (1) {} }
void f12_1(struct s12 a0) {}
@@ -94,19 +94,19 @@ void f17(float a, float b, float c, float d, float e, float f, float g, float h,
// Check for valid coercion. The struct should be passed/returned as i32, not
// as i64 for better code quality.
// rdar://8135035
-// CHECK: define void @f18(i32 %a, i32 %f18_arg1.coerce)
+// CHECK-LABEL: define void @f18(i32 %a, i32 %f18_arg1.coerce)
struct f18_s0 { int f0; };
void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }
// Check byval alignment.
-// CHECK: define void @f19(%struct.s19* byval align 16 %x)
+// CHECK-LABEL: define void @f19(%struct.s19* byval align 16 %x)
struct s19 {
long double a;
};
void f19(struct s19 x) {}
-// CHECK: define void @f20(%struct.s20* byval align 32 %x)
+// CHECK-LABEL: define void @f20(%struct.s20* byval align 32 %x)
struct __attribute__((aligned(32))) s20 {
int x;
int y;
@@ -119,7 +119,7 @@ struct StringRef {
};
// rdar://7375902
-// CHECK: define i8* @f21(i64 %S.coerce0, i8* %S.coerce1)
+// CHECK-LABEL: define i8* @f21(i64 %S.coerce0, i8* %S.coerce1)
const char *f21(struct StringRef S) { return S.x+S.Ptr; }
// PR7567
@@ -140,7 +140,7 @@ struct f23S {
void f23(int A, struct f23S B) {
- // CHECK: define void @f23(i32 %A, i64 %B.coerce0, i32 %B.coerce1)
+ // CHECK-LABEL: define void @f23(i32 %A, i64 %B.coerce0, i32 %B.coerce1)
}
struct f24s { long a; int b; };
@@ -154,7 +154,7 @@ struct f23S f24(struct f23S *X, struct f24s *P2) {
// rdar://8248065
typedef float v4f32 __attribute__((__vector_size__(16)));
v4f32 f25(v4f32 X) {
- // CHECK: define <4 x float> @f25(<4 x float> %X)
+ // CHECK-LABEL: define <4 x float> @f25(<4 x float> %X)
// CHECK-NOT: alloca
// CHECK: alloca <4 x float>
// CHECK-NOT: alloca
@@ -180,7 +180,7 @@ struct v4f32wrapper {
};
struct v4f32wrapper f27(struct v4f32wrapper X) {
- // CHECK: define <4 x float> @f27(<4 x float> %X.coerce)
+ // CHECK-LABEL: define <4 x float> @f27(<4 x float> %X.coerce)
return X;
}
@@ -190,7 +190,7 @@ struct f28c {
int y;
};
void f28(struct f28c C) {
- // CHECK: define void @f28(double %C.coerce0, i32 %C.coerce1)
+ // CHECK-LABEL: define void @f28(double %C.coerce0, i32 %C.coerce1)
}
struct f29a {
@@ -201,26 +201,26 @@ struct f29a {
};
void f29a(struct f29a A) {
- // CHECK: define void @f29a(double %A.coerce0, i32 %A.coerce1)
+ // CHECK-LABEL: define void @f29a(double %A.coerce0, i32 %A.coerce1)
}
// rdar://8249586
struct S0 { char f0[8]; char f2; char f3; char f4; };
void f30(struct S0 p_4) {
- // CHECK: define void @f30(i64 %p_4.coerce0, i24 %p_4.coerce1)
+ // CHECK-LABEL: define void @f30(i64 %p_4.coerce0, i24 %p_4.coerce1)
}
// Pass the third element as a float when followed by tail padding.
// rdar://8251384
struct f31foo { float a, b, c; };
float f31(struct f31foo X) {
- // CHECK: define float @f31(<2 x float> %X.coerce0, float %X.coerce1)
+ // CHECK-LABEL: define float @f31(<2 x float> %X.coerce0, float %X.coerce1)
return X.c;
}
_Complex float f32(_Complex float A, _Complex float B) {
// rdar://6379669
- // CHECK: define <2 x float> @f32(<2 x float> %A.coerce, <2 x float> %B.coerce)
+ // CHECK-LABEL: define <2 x float> @f32(<2 x float> %A.coerce, <2 x float> %B.coerce)
return A+B;
}
@@ -235,12 +235,12 @@ void f33(va_list X) {
typedef unsigned long long v1i64 __attribute__((__vector_size__(8)));
// rdar://8359248
-// CHECK: define i64 @f34(i64 %arg.coerce)
+// CHECK-LABEL: define i64 @f34(i64 %arg.coerce)
v1i64 f34(v1i64 arg) { return arg; }
// rdar://8358475
-// CHECK: define i64 @f35(i64 %arg.coerce)
+// CHECK-LABEL: define i64 @f35(i64 %arg.coerce)
typedef unsigned long v1i64_2 __attribute__((__vector_size__(8)));
v1i64_2 f35(v1i64_2 arg) { return arg+arg; }
@@ -260,7 +260,7 @@ void f9122143()
func(ss);
}
-// CHECK: define double @f36(double %arg.coerce)
+// CHECK-LABEL: define double @f36(double %arg.coerce)
typedef unsigned v2i32 __attribute((__vector_size__(8)));
v2i32 f36(v2i32 arg) { return arg; }
@@ -308,7 +308,7 @@ void func43(SA s) {
func42(s);
}
-// CHECK: define i32 @f44
+// CHECK-LABEL: define i32 @f44
// CHECK: ptrtoint
// CHECK-NEXT: and {{.*}}, -32
// CHECK-NEXT: inttoptr
@@ -323,7 +323,7 @@ int f44(int i, ...) {
}
// Text that vec3 returns the correct LLVM IR type.
-// AVX: define i32 @foo(<3 x i64> %X)
+// AVX-LABEL: define i32 @foo(<3 x i64> %X)
typedef long long3 __attribute((ext_vector_type(3)));
int foo(long3 X)
{
@@ -379,7 +379,7 @@ void test49_helper(double, ...);
void test49(double d, double e) {
test49_helper(d, e);
}
-// CHECK: define void @test49(
+// CHECK-LABEL: define void @test49(
// CHECK: [[T0:%.*]] = load double*
// CHECK-NEXT: [[T1:%.*]] = load double*
// CHECK-NEXT: call void (double, ...)* @test49_helper(double [[T0]], double [[T1]])
@@ -388,7 +388,49 @@ void test50_helper();
void test50(double d, double e) {
test50_helper(d, e);
}
-// CHECK: define void @test50(
+// CHECK-LABEL: define void @test50(
// CHECK: [[T0:%.*]] = load double*
// CHECK-NEXT: [[T1:%.*]] = load double*
// CHECK-NEXT: call void (double, double, ...)* bitcast (void (...)* @test50_helper to void (double, double, ...)*)(double [[T0]], double [[T1]])
+
+struct test51_s { __uint128_t intval; };
+void test51(struct test51_s *s, __builtin_va_list argList) {
+ *s = __builtin_va_arg(argList, struct test51_s);
+}
+
+// CHECK-LABEL: define void @test51
+// CHECK: [[TMP_ADDR:%.*]] = alloca [[STRUCT_TEST51:%.*]], align 16
+// CHECK: br i1
+// CHECK: [[REG_SAVE_AREA_PTR:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 3
+// CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load i8** [[REG_SAVE_AREA_PTR]]
+// CHECK-NEXT: [[VALUE_ADDR:%.*]] = getelementptr i8* [[REG_SAVE_AREA]], i32 {{.*}}
+// CHECK-NEXT: [[CASTED_VALUE_ADDR:%.*]] = bitcast i8* [[VALUE_ADDR]] to [[STRUCT_TEST51]]
+// CHECK-NEXT: [[CASTED_TMP_ADDR:%.*]] = bitcast [[STRUCT_TEST51]]* [[TMP_ADDR]] to i8*
+// CHECK-NEXT: [[RECASTED_VALUE_ADDR:%.*]] = bitcast [[STRUCT_TEST51]]* [[CASTED_VALUE_ADDR]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[CASTED_TMP_ADDR]], i8* [[RECASTED_VALUE_ADDR]], i64 16, i32 8, i1 false)
+// CHECK-NEXT: add i32 {{.*}}, 16
+// CHECK-NEXT: store i32 {{.*}}, i32* {{.*}}
+// CHECK-NEXT: br label
+
+void test52_helper(int, ...);
+__m256 x52;
+void test52() {
+ test52_helper(0, x52, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
+}
+// AVX: @test52_helper(i32 0, <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 {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
+
+void test53(__m256 *m, __builtin_va_list argList) {
+ *m = __builtin_va_arg(argList, __m256);
+}
+// AVX-LABEL: define void @test53
+// AVX-NOT: br i1
+// AVX: ret void
+
+void test54_helper(__m256, ...);
+__m256 x54;
+void test54() {
+ test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
+ 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]+}})
diff --git a/test/CodeGen/xcore-abi.c b/test/CodeGen/xcore-abi.c
new file mode 100644
index 000000000000..10881de7cec2
--- /dev/null
+++ b/test/CodeGen/xcore-abi.c
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -triple xcore -verify %s
+_Static_assert(sizeof(long long) == 8, "sizeof long long is wrong");
+_Static_assert(_Alignof(long long) == 4, "alignof long long is wrong");
+
+_Static_assert(sizeof(double) == 8, "sizeof double is wrong");
+_Static_assert(_Alignof(double) == 4, "alignof double is wrong");
+
+// RUN: %clang_cc1 -triple xcore-unknown-unknown -fno-signed-char -fno-common -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: target datalayout = "e-p:32:32:32-a0:0:32-n32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f16:16:32-f32:32:32-f64:32:32"
+// CHECK: target triple = "xcore-unknown-unknown"
+
+// CHECK: @g1 = global i32 0, align 4
+int g1;
+
+#include <stdarg.h>
+struct x { int a[5]; };
+void f(void*);
+void testva (int n, ...) {
+ // CHECK-LABEL: testva
+ va_list ap;
+ va_start(ap,n);
+ // CHECK: [[AP:%[a-z0-9]+]] = alloca i8*, align 4
+ // CHECK: [[AP1:%[a-z0-9]+]] = bitcast i8** [[AP]] to i8*
+ // CHECK: call void @llvm.va_start(i8* [[AP1]])
+
+ char* v1 = va_arg (ap, char*);
+ f(v1);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[P:%[a-z0-9]+]] = bitcast i8* [[I]] to i8**
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 4
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = load i8** [[P]]
+ // CHECK: store i8* [[V1]], i8** [[V:%[a-z0-9]+]], align 4
+ // CHECK: [[V2:%[a-z0-9]+]] = load i8** [[V]], align 4
+ // CHECK: call void @f(i8* [[V2]])
+
+ char v2 = va_arg (ap, char); // expected-warning{{second argument to 'va_arg' is of promotable type 'char'}}
+ f(&v2);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 4
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = load i8* [[I]]
+ // CHECK: store i8 [[V1]], i8* [[V:%[a-z0-9]+]], align 1
+ // CHECK: call void @f(i8* [[V]])
+
+ int v3 = va_arg (ap, int);
+ f(&v3);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[P:%[a-z0-9]+]] = bitcast i8* [[I]] to i32*
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 4
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = load i32* [[P]]
+ // CHECK: store i32 [[V1]], i32* [[V:%[a-z0-9]+]], align 4
+ // CHECK: [[V2:%[a-z0-9]+]] = bitcast i32* [[V]] to i8*
+ // CHECK: call void @f(i8* [[V2]])
+
+ long long int v4 = va_arg (ap, long long int);
+ f(&v4);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[P:%[a-z0-9]+]] = bitcast i8* [[I]] to i64*
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 8
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = load i64* [[P]]
+ // CHECK: store i64 [[V1]], i64* [[V:%[a-z0-9]+]], align 4
+ // CHECK:[[V2:%[a-z0-9]+]] = bitcast i64* [[V]] to i8*
+ // CHECK: call void @f(i8* [[V2]])
+
+ struct x v5 = va_arg (ap, struct x); // typical agregate type
+ f(&v5);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[I2:%[a-z0-9]+]] = bitcast i8* [[I]] to %struct.x**
+ // CHECK: [[P:%[a-z0-9]+]] = load %struct.x** [[I2]]
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 4
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = bitcast %struct.x* [[V:%[a-z0-9]+]] to i8*
+ // CHECK: [[P1:%[a-z0-9]+]] = bitcast %struct.x* [[P]] to i8*
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[V1]], i8* [[P1]], i32 20, i32 4, i1 false)
+ // CHECK: [[V2:%[a-z0-9]+]] = bitcast %struct.x* [[V]] to i8*
+ // CHECK: call void @f(i8* [[V2]])
+
+ int* v6 = va_arg (ap, int[4]); // an unusual agregate type
+ f(v6);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[I2:%[a-z0-9]+]] = bitcast i8* [[I]] to [4 x i32]**
+ // CHECK: [[P:%[a-z0-9]+]] = load [4 x i32]** [[I2]]
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 4
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = bitcast [4 x i32]* [[V0:%[a-z0-9]+]] to i8*
+ // CHECK: [[P1:%[a-z0-9]+]] = bitcast [4 x i32]* [[P]] to i8*
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[V1]], i8* [[P1]], i32 16, i32 4, i1 false)
+ // CHECK: [[V2:%[a-z0-9]+]] = getelementptr inbounds [4 x i32]* [[V0]], i32 0, i32 0
+ // CHECK: store i32* [[V2]], i32** [[V:%[a-z0-9]+]], align 4
+ // CHECK: [[V3:%[a-z0-9]+]] = load i32** [[V]], align 4
+ // CHECK: [[V4:%[a-z0-9]+]] = bitcast i32* [[V3]] to i8*
+ // CHECK: call void @f(i8* [[V4]])
+
+ double v7 = va_arg (ap, double);
+ f(&v7);
+ // CHECK: [[I:%[a-z0-9]+]] = load i8** [[AP]]
+ // CHECK: [[P:%[a-z0-9]+]] = bitcast i8* [[I]] to double*
+ // CHECK: [[IN:%[a-z0-9]+]] = getelementptr i8* [[I]], i32 8
+ // CHECK: store i8* [[IN]], i8** [[AP]]
+ // CHECK: [[V1:%[a-z0-9]+]] = load double* [[P]]
+ // CHECK: store double [[V1]], double* [[V:%[a-z0-9]+]], align 4
+ // CHECK: [[V2:%[a-z0-9]+]] = bitcast double* [[V]] to i8*
+ // CHECK: call void @f(i8* [[V2]])
+}
+
+void testbuiltin (void) {
+ // CHECK-LABEL: testbuiltin
+ // CHECK: call i32 @llvm.xcore.getid()
+ // CHECK: call i32 @llvm.xcore.getps(i32 {{%[a-z0-9]+}})
+ // CHECK: call i32 @llvm.xcore.bitrev(i32 {{%[a-z0-9]+}})
+ // CHECK: call void @llvm.xcore.setps(i32 {{%[a-z0-9]+}}, i32 {{%[a-z0-9]+}})
+ int i = __builtin_getid();
+ unsigned int ui = __builtin_getps(i);
+ ui = __builtin_bitrev(ui);
+ __builtin_setps(i,ui);
+}
+
+// CHECK-LABEL: define zeroext i8 @testchar()
+// CHECK: ret i8 -1
+char testchar (void) {
+ return (char)-1;
+}
+
+// CHECK: "no-frame-pointer-elim"="false"
+// CHECK-NOT: "no-frame-pointer-elim-non-leaf"
diff --git a/test/CodeGenCUDA/address-spaces.cu b/test/CodeGenCUDA/address-spaces.cu
index 9df7e3f4d262..04344526f40e 100644
--- a/test/CodeGenCUDA/address-spaces.cu
+++ b/test/CodeGenCUDA/address-spaces.cu
@@ -12,13 +12,13 @@ __constant__ int j;
__shared__ int k;
__device__ void foo() {
- // CHECK: load i32* bitcast (i32 addrspace(1)* @i to i32*)
+ // CHECK: load i32* addrspacecast (i32 addrspace(1)* @i to i32*)
i++;
- // CHECK: load i32* bitcast (i32 addrspace(4)* @j to i32*)
+ // CHECK: load i32* addrspacecast (i32 addrspace(4)* @j to i32*)
j++;
- // CHECK: load i32* bitcast (i32 addrspace(3)* @k to i32*)
+ // CHECK: load i32* addrspacecast (i32 addrspace(3)* @k to i32*)
k++;
static int li;
diff --git a/test/CodeGenCUDA/ptx-kernels.cu b/test/CodeGenCUDA/ptx-kernels.cu
index 8d34f4f3a654..211692fcc7c0 100644
--- a/test/CodeGenCUDA/ptx-kernels.cu
+++ b/test/CodeGenCUDA/ptx-kernels.cu
@@ -2,11 +2,11 @@
#include "../SemaCUDA/cuda.h"
-// CHECK: define void @device_function
+// CHECK-LABEL: define void @device_function
extern "C"
__device__ void device_function() {}
-// CHECK: define void @global_function
+// CHECK-LABEL: define void @global_function
extern "C"
__global__ void global_function() {
// CHECK: call void @device_function
diff --git a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp
index 3bfecd54b780..c478e7dcae1d 100644
--- a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp
+++ b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp
@@ -4,6 +4,6 @@
namespace nm {
struct str {
- friend int foo(int arg = 0);
+ friend void foo(int arg = 0) {};
};
}
diff --git a/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp b/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp
deleted file mode 100644
index c37f5dce32b2..000000000000
--- a/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
-
-// CHECK-NOT: i32 6
-struct QVectorTypedData {
- int size;
- unsigned int sharable : 1;
- unsigned short array[1];
-};
-
-void foo(QVectorTypedData *X) {
- X->array[0] = 123;
-}
diff --git a/test/CodeGenCXX/2007-05-03-VectorInit.cpp b/test/CodeGenCXX/2007-05-03-VectorInit.cpp
index 5bc196f30fe2..b22b52a26615 100644
--- a/test/CodeGenCXX/2007-05-03-VectorInit.cpp
+++ b/test/CodeGenCXX/2007-05-03-VectorInit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -O0 -o -
+// RUN: %clang_cc1 -emit-llvm %s -o -
// PR1378
typedef float v4sf __attribute__((vector_size(16)));
diff --git a/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp
index 7c05535b3587..802f4c3d67f7 100644
--- a/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp
+++ b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o /dev/null
+// RUN: %clang_cc1 -emit-llvm -g %s -o /dev/null
// PR 7104
struct A {
diff --git a/test/CodeGenCXX/DynArrayInit.cpp b/test/CodeGenCXX/DynArrayInit.cpp
index 4b4c2ecf1d3e..fb865e35af4e 100644
--- a/test/CodeGenCXX/DynArrayInit.cpp
+++ b/test/CodeGenCXX/DynArrayInit.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -O3 -emit-llvm -o - %s | FileCheck %s
// PR7490
-// CHECK: define signext i8 @_Z2f0v
+// CHECK-LABEL: define signext i8 @_Z2f0v
// CHECK: ret i8 0
// CHECK: }
inline void* operator new[](unsigned long, void* __p) { return __p; }
diff --git a/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
index c50dafbbab20..a1b05ebc70b1 100644
--- a/test/CodeGenCXX/PR5050-constructor-conversion.cpp
+++ b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
struct A { A(const A&, int i1 = 1); };
diff --git a/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp b/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp
new file mode 100644
index 000000000000..2514704f1d88
--- /dev/null
+++ b/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp
@@ -0,0 +1,85 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon %s -emit-llvm -o - | FileCheck %s
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+typedef unsigned char poly8_t;
+typedef unsigned short poly16_t;
+typedef __fp16 float16_t;
+typedef float float32_t;
+typedef double float64_t;
+
+typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t;
+typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t;
+typedef __attribute__((neon_vector_type(4))) int16_t int16x4_t;
+typedef __attribute__((neon_vector_type(8))) int16_t int16x8_t;
+typedef __attribute__((neon_vector_type(2))) int int32x2_t;
+typedef __attribute__((neon_vector_type(4))) int int32x4_t;
+typedef __attribute__((neon_vector_type(2))) int64_t int64x2_t;
+typedef __attribute__((neon_vector_type(8))) uint8_t uint8x8_t;
+typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t;
+typedef __attribute__((neon_vector_type(4))) uint16_t uint16x4_t;
+typedef __attribute__((neon_vector_type(8))) uint16_t uint16x8_t;
+typedef __attribute__((neon_vector_type(2))) unsigned int uint32x2_t;
+typedef __attribute__((neon_vector_type(4))) unsigned int uint32x4_t;
+typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t;
+typedef __attribute__((neon_vector_type(4))) float16_t float16x4_t;
+typedef __attribute__((neon_vector_type(8))) float16_t float16x8_t;
+typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t;
+typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
+typedef __attribute__((neon_vector_type(2))) float64_t float64x2_t;
+typedef __attribute__((neon_polyvector_type(8))) poly8_t poly8x8_t;
+typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
+typedef __attribute__((neon_polyvector_type(4))) poly16_t poly16x4_t;
+typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
+
+// CHECK: 10__Int8x8_t
+void f1(int8x8_t) {}
+// CHECK: 11__Int16x4_t
+void f2(int16x4_t) {}
+// CHECK: 11__Int32x2_t
+void f3(int32x2_t) {}
+// CHECK: 11__Uint8x8_t
+void f4(uint8x8_t) {}
+// CHECK: 12__Uint16x4_t
+void f5(uint16x4_t) {}
+// CHECK: 13__Float16x4_t
+void f6(float16x4_t) {}
+// CHECK: 13__Float16x8_t
+void f7(float16x8_t) {}
+// CHECK: 12__Uint32x2_t
+void f8(uint32x2_t) {}
+// CHECK: 13__Float32x2_t
+void f9(float32x2_t) {}
+// CHECK: 13__Float32x4_t
+void f10(float32x4_t) {}
+// CHECK: 11__Poly8x8_t
+void f11(poly8x8_t v) {}
+// CHECK: 12__Poly16x4_t
+void f12(poly16x4_t v) {}
+// CHECK:12__Poly8x16_t
+void f13(poly8x16_t v) {}
+// CHECK:12__Poly16x8_t
+void f14(poly16x8_t v) {}
+// CHECK: 11__Int8x16_t
+void f15(int8x16_t) {}
+// CHECK: 11__Int16x8_t
+void f16(int16x8_t) {}
+// CHECK:11__Int32x4_t
+void f17(int32x4_t) {}
+// CHECK: 12__Uint8x16_t
+void f18(uint8x16_t) {}
+// CHECK: 12__Uint16x8_t
+void f19(uint16x8_t) {}
+// CHECK: 12__Uint32x4_t
+void f20(uint32x4_t) {}
+// CHECK: 11__Int64x2_t
+void f21(int64x2_t) {}
+// CHECK: 12__Uint64x2_t
+void f22(uint64x2_t) {}
+// CHECK: 13__Float64x2_t
+void f23(float64x2_t) {}
diff --git a/test/CodeGenCXX/aarch64-neon.cpp b/test/CodeGenCXX/aarch64-neon.cpp
new file mode 100644
index 000000000000..5d2a00bebe73
--- /dev/null
+++ b/test/CodeGenCXX/aarch64-neon.cpp
@@ -0,0 +1,13 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
+
+// Test whether arm_neon.h can be used in .cpp file.
+
+#include "arm_neon.h"
+
+poly64x1_t test_vld1_p64(poly64_t const * ptr) {
+ // CHECK: test_vld1_p64
+ return vld1_p64(ptr);
+ // CHECK: ld1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+}
diff --git a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
index 012c2231551d..793bbde05021 100644
--- a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
+++ b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
@@ -7,10 +7,10 @@ struct A {
~A();
};
-// CHECK-NOT: define void @_ZN1AC1Ev
-// CHECK: define void @_ZN1AC2Ev
-// CHECK: define void @_ZN1AD1Ev
-// CHECK: define void @_ZN1AD2Ev
+// CHECK-NOT-LABEL: define void @_ZN1AC1Ev
+// CHECK-LABEL: define void @_ZN1AC2Ev
+// CHECK-LABEL: define void @_ZN1AD1Ev
+// CHECK-LABEL: define void @_ZN1AD2Ev
A::A() { }
A::~A() { }
diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp
index 162c6e5754f3..71794520f0a0 100644
--- a/test/CodeGenCXX/address-of-fntemplate.cpp
+++ b/test/CodeGenCXX/address-of-fntemplate.cpp
@@ -9,8 +9,8 @@ void test() {
// CHECK: @_Z1fIiEvv
void (*p2)() = f<int>;
}
-// CHECK: define linkonce_odr void @_Z1fIiEvT_
-// CHECK: define linkonce_odr void @_Z1fIiEvv
+// CHECK-LABEL: define linkonce_odr void @_Z1fIiEvT_
+// CHECK-LABEL: define linkonce_odr void @_Z1fIiEvv
namespace PR6973 {
template<typename T>
diff --git a/test/CodeGenCXX/alloca-align.cpp b/test/CodeGenCXX/alloca-align.cpp
index 99d6ab5845f2..079b55d2b03a 100644
--- a/test/CodeGenCXX/alloca-align.cpp
+++ b/test/CodeGenCXX/alloca-align.cpp
@@ -6,19 +6,19 @@ struct s0 {
int TheStores __attribute__((aligned(16)));
};
-// CHECK: define void @f0
+// CHECK-LABEL: define void @f0
// CHECK: alloca %struct.s0, align 16
extern "C" void f0() {
(void) s0();
}
-// CHECK: define void @f1
+// CHECK-LABEL: define void @f1
// CHECK: alloca %struct.s0, align 16
extern "C" void f1() {
(void) (struct s0) { 0, 0, 0, 0 };
}
-// CHECK: define i32 @f2
+// CHECK-LABEL: define i32 @f2
// CHECK: alloca %struct.s1, align 2
struct s1 { short x; short y; };
extern "C" struct s1 f2(int a, struct s1 *x, struct s1 *y) {
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
index 32e17a35ff2d..abc700fef6c2 100644
--- a/test/CodeGenCXX/anonymous-namespaces.cpp
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-llvm %s -o - > %t
-// RUN: FileCheck %s -check-prefix=1 < %t
-// RUN: FileCheck %s -check-prefix=2 < %t
+// RUN: FileCheck %s -check-prefix=CHECK-1 < %t
+// RUN: FileCheck %s -check-prefix=CHECK-2 < %t
int f();
@@ -28,12 +28,12 @@ namespace {
struct E : public virtual EBase { virtual ~E() {} };
};
- // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_13fooEv()
+ // CHECK-1-LABEL: define internal i32 @_ZN12_GLOBAL__N_13fooEv()
int foo() {
return 32;
}
- // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv()
+ // CHECK-1-LABEL: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv()
namespace A {
int foo() {
return 45;
@@ -58,11 +58,20 @@ namespace test2 {
struct C;
}
- // CHECK-2: define void @_ZN5test24testEv()
+ // CHECK-2-LABEL: define void @_ZN5test24testEv()
// CHECK-2: call void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv()
void test() {
A::B<C>::foo();
}
- // CHECK-2: define internal void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv()
+ // CHECK-2-LABEL: define internal void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv()
}
+
+namespace {
+
+int bar() {
+ extern int a;
+ return a;
+}
+
+} // namespace
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index 8dc4f4721dd0..98e982ddf695 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -31,7 +31,7 @@ namespace PR7021 {
union { long l; };
};
- // CHECK: define void @_ZN6PR70211fENS_1XES0_
+ // CHECK-LABEL: define void @_ZN6PR70211fENS_1XES0_
void f(X x, X z) {
X x1;
@@ -61,7 +61,7 @@ namespace test2 {
};
A::A() : b(10) { }
- // CHECK: define void @_ZN5test21AC2Ev(
+ // CHECK-LABEL: define void @_ZN5test21AC2Ev(
// CHECK-NOT: }
// CHECK: store i32 10
// CHECK: }
@@ -79,14 +79,14 @@ namespace PR10512 {
};
};
- // CHECK: define void @_ZN7PR105121AC2Ev
+ // 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]]** [[THISADDR]]
// CHECK-NEXT: ret void
A::A() {}
- // CHECK: define void @_ZN7PR105121AC2Ei
+ // 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]]
@@ -100,7 +100,7 @@ namespace PR10512 {
// CHECK-NEXT: ret void
A::A(int x) : x(x) { }
- // CHECK: define void @_ZN7PR105121AC2El
+ // 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]]
@@ -130,7 +130,7 @@ namespace test3 {
};
A::A() : callback(0), callback_value(0) {}
- // CHECK: define void @_ZN5test31AC2Ev(
+ // CHECK-LABEL: define void @_ZN5test31AC2Ev(
// CHECK: [[THIS:%.*]] = load
// CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
// CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to
diff --git a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
index bd275f1c4da2..7ac5b5839e8c 100644
--- a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
+++ b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s
-// CHECK: define void @_ZN2B1D0Ev
+// CHECK-LABEL: define void @_ZN2B1D0Ev
// CHECK: [[T1:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2)
// CHECK-NEXT: call void [[T1]](%struct.B1* [[T2:%.*]])
-// CHECK: define void @_Z6DELETEP2B1
+// CHECK-LABEL: define void @_Z6DELETEP2B1
// CHECK: [[T3:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2)
// CHECK-NEXT: call void [[T3]](%struct.B1* [[T4:%.*]])
diff --git a/test/CodeGenCXX/apple-kext-linkage.C b/test/CodeGenCXX/apple-kext-linkage.C
index 59d228e2300c..e66b0389fcc3 100644
--- a/test/CodeGenCXX/apple-kext-linkage.C
+++ b/test/CodeGenCXX/apple-kext-linkage.C
@@ -13,21 +13,21 @@ void foo() {
Derived d1; // ok
}
-// CHECK: define internal i32 @_Z1fj(
+// CHECK-LABEL: define internal i32 @_Z1fj(
inline unsigned f(unsigned n) { return n == 0 ? 0 : n + f(n-1); }
unsigned g(unsigned n) { return f(n); }
// rdar://problem/10133200: give explicit instantiations external linkage in kernel mode
-// CHECK: define void @_Z3barIiEvv()
+// CHECK-LABEL: define void @_Z3barIiEvv()
template <typename T> void bar() {}
template void bar<int>();
-// CHECK: define internal i32 @_Z5identIiET_S0_(
+// CHECK-LABEL: define internal i32 @_Z5identIiET_S0_(
template <typename X> X ident(X x) { return x; }
int foo(int n) { return ident(n); }
-// CHECK: define internal void @_ZN7DerivedD1Ev(
-// CHECK: define internal void @_ZN7DerivedD0Ev(
-// CHECK: define internal void @_ZN7DeriveddlEPv(
+// CHECK-LABEL: define internal void @_ZN7DerivedD1Ev(
+// CHECK-LABEL: define internal void @_ZN7DerivedD0Ev(
+// CHECK-LABEL: define internal void @_ZN7DeriveddlEPv(
diff --git a/test/CodeGenCXX/arm-vaarg.cpp b/test/CodeGenCXX/arm-vaarg.cpp
new file mode 100644
index 000000000000..9850fb342faf
--- /dev/null
+++ b/test/CodeGenCXX/arm-vaarg.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple armv7-apple-ios -emit-llvm -o - %s | FileCheck %s
+struct Empty {};
+
+Empty emptyvar;
+
+int take_args(int a, ...) {
+ __builtin_va_list l;
+ __builtin_va_start(l, a);
+// CHECK: call void @llvm.va_start
+
+ emptyvar = __builtin_va_arg(l, Empty);
+// CHECK: load i8**
+// CHECK-NOT: getelementptr
+// CHECK: [[EMPTY_PTR:%[a-zA-Z0-9._]+]] = bitcast i8* {{%[a-zA-Z0-9._]+}} to %struct.Empty*
+
+ // It's conceivable that EMPTY_PTR may not actually be a valid pointer
+ // (e.g. it's at the very bottom of the stack and the next page is
+ // invalid). This doesn't matter provided it's never loaded (there's no
+ // well-defined way to tell), but it becomes a problem if we do try to use it.
+// CHECK-NOT: load %struct.Empty* [[EMPTY_PTR]]
+
+ int i = __builtin_va_arg(l, int);
+// CHECK: load i32*
+
+ __builtin_va_end(l);
+ return i;
+}
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 48f2f0084015..2fb9c49bb707 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -28,7 +28,7 @@ bar baz;
// CHECK: call [[BAR:%.*]]* @_ZN3barC1Ev(
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_baz)
-// CHECK: define internal void @__dtor_baz()
+// CHECK-LABEL: define internal void @__dtor_baz()
// CHECK: call [[BAR]]* @_ZN3barD1Ev([[BAR]]* @baz)
// Destructors and constructors must return this.
@@ -41,7 +41,7 @@ namespace test1 {
void bar() { foo(); }
};
- // CHECK: define void @_ZN5test14testEv()
+ // CHECK-LABEL: define void @_ZN5test14testEv()
void test() {
// CHECK: [[AV:%.*]] = alloca [[A:%.*]], align 1
// CHECK: call [[A]]* @_ZN5test11AC1Ei([[A]]* [[AV]], i32 10)
@@ -52,19 +52,19 @@ namespace test1 {
a.bar();
}
- // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr
+ // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei(
+ // CHECK: ret [[A]]* [[THIS1]]
- // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
+ // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev(
+ // CHECK: ret [[A]]* [[THIS1]]
}
// Awkward virtual cases.
@@ -107,7 +107,7 @@ namespace test3 {
};
void a() {
- // CHECK: define void @_ZN5test31aEv()
+ // CHECK-LABEL: define void @_ZN5test31aEv()
// CHECK: call noalias i8* @_Znam(i32 48)
// CHECK: store i32 4
// CHECK: store i32 10
@@ -115,7 +115,7 @@ namespace test3 {
}
void b(int n) {
- // CHECK: define void @_ZN5test31bEi(
+ // CHECK-LABEL: define void @_ZN5test31bEi(
// CHECK: [[N:%.*]] = load i32*
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
// CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
@@ -128,7 +128,7 @@ namespace test3 {
}
void c() {
- // CHECK: define void @_ZN5test31cEv()
+ // CHECK-LABEL: define void @_ZN5test31cEv()
// CHECK: call noalias i8* @_Znam(i32 808)
// CHECK: store i32 4
// CHECK: store i32 200
@@ -136,7 +136,7 @@ namespace test3 {
}
void d(int n) {
- // CHECK: define void @_ZN5test31dEi(
+ // CHECK-LABEL: define void @_ZN5test31dEi(
// CHECK: [[N:%.*]] = load i32*
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
// CHECK: [[NE:%.*]] = mul i32 [[N]], 20
@@ -149,7 +149,7 @@ namespace test3 {
}
void e(A *x) {
- // CHECK: define void @_ZN5test31eEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN5test31eEPNS_1AE(
// CHECK: icmp eq {{.*}}, null
// CHECK: getelementptr {{.*}}, i64 -8
// CHECK: getelementptr {{.*}}, i64 4
@@ -161,7 +161,7 @@ namespace test3 {
}
void f(A (*x)[20]) {
- // CHECK: define void @_ZN5test31fEPA20_NS_1AE(
+ // CHECK-LABEL: define void @_ZN5test31fEPA20_NS_1AE(
// CHECK: icmp eq {{.*}}, null
// CHECK: getelementptr {{.*}}, i64 -8
// CHECK: getelementptr {{.*}}, i64 4
@@ -180,7 +180,7 @@ namespace test4 {
};
void a() {
- // CHECK: define void @_ZN5test41aEv()
+ // CHECK-LABEL: define void @_ZN5test41aEv()
// CHECK: call noalias i8* @_Znam(i32 48)
// CHECK: store i32 4
// CHECK: store i32 10
@@ -188,7 +188,7 @@ namespace test4 {
}
void b(int n) {
- // CHECK: define void @_ZN5test41bEi(
+ // CHECK-LABEL: define void @_ZN5test41bEi(
// CHECK: [[N:%.*]] = load i32*
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
// CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
@@ -200,7 +200,7 @@ namespace test4 {
}
void c() {
- // CHECK: define void @_ZN5test41cEv()
+ // CHECK-LABEL: define void @_ZN5test41cEv()
// CHECK: call noalias i8* @_Znam(i32 808)
// CHECK: store i32 4
// CHECK: store i32 200
@@ -208,7 +208,7 @@ namespace test4 {
}
void d(int n) {
- // CHECK: define void @_ZN5test41dEi(
+ // CHECK-LABEL: define void @_ZN5test41dEi(
// CHECK: [[N:%.*]] = load i32*
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
// CHECK: [[NE:%.*]] = mul i32 [[N]], 20
@@ -221,7 +221,7 @@ namespace test4 {
}
void e(A *x) {
- // CHECK: define void @_ZN5test41eEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN5test41eEPNS_1AE(
// CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
// CHECK: getelementptr inbounds {{.*}}, i64 4
// CHECK: bitcast
@@ -233,7 +233,7 @@ namespace test4 {
}
void f(A (*x)[20]) {
- // CHECK: define void @_ZN5test41fEPA20_NS_1AE(
+ // CHECK-LABEL: define void @_ZN5test41fEPA20_NS_1AE(
// CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
// CHECK: getelementptr inbounds {{.*}}, i64 4
// CHECK: bitcast
@@ -251,7 +251,7 @@ namespace test5 {
~A();
};
- // CHECK: define void @_ZN5test54testEPNS_1AE
+ // CHECK-LABEL: define void @_ZN5test54testEPNS_1AE
void test(A *a) {
// CHECK: [[PTR:%.*]] = alloca [[A:%.*]]*, align 4
// CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[PTR]], align 4
@@ -267,7 +267,7 @@ namespace test6 {
virtual ~A();
};
- // CHECK: define void @_ZN5test64testEPNS_1AE
+ // CHECK-LABEL: define void @_ZN5test64testEPNS_1AE
void test(A *a) {
// CHECK: [[AVAR:%.*]] = alloca [[A:%.*]]*, align 4
// CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[AVAR]], align 4
@@ -290,7 +290,7 @@ namespace test7 {
// Static and guard tested at top of file
- // CHECK: define void @_ZN5test74testEv()
+ // CHECK-LABEL: define void @_ZN5test74testEv()
void test() {
// CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test74testEvE1x
// CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1
@@ -325,7 +325,7 @@ namespace test8 {
// Static and guard tested at top of file
- // CHECK: define void @_ZN5test84testEv()
+ // CHECK-LABEL: define void @_ZN5test84testEv()
void test() {
// CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test84testEvE1x
// CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1
@@ -394,7 +394,7 @@ namespace test9 {
void testDelete(A *array) {
delete[] array;
}
-// CHECK: define void @_ZN5test910testDeleteEPNS_1AE(
+// CHECK-LABEL: define void @_ZN5test910testDeleteEPNS_1AE(
// CHECK: [[BEGIN:%.*]] = load [[TEST9]]**
// CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], null
// CHECK-NEXT: br i1 [[T0]],
@@ -413,7 +413,7 @@ namespace test9 {
// CHECK: call [[C]]* @_ZN5test21CD1Ev(
// CHECK: ret [[C]]* undef
- // CHECK: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev(
+ // CHECK-LABEL: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev(
// CHECK: call void @_ZN5test21CD0Ev(
// CHECK: ret void
diff --git a/test/CodeGenCXX/array-construction.cpp b/test/CodeGenCXX/array-construction.cpp
index 7b565a490c11..645ad1d787df 100644
--- a/test/CodeGenCXX/array-construction.cpp
+++ b/test/CodeGenCXX/array-construction.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/array-operator-delete-call.cpp b/test/CodeGenCXX/array-operator-delete-call.cpp
index 1b23c4d137aa..8d6f50fdfab1 100644
--- a/test/CodeGenCXX/array-operator-delete-call.cpp
+++ b/test/CodeGenCXX/array-operator-delete-call.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/atomic.cpp b/test/CodeGenCXX/atomic.cpp
index 36bb4ef5608e..653f16d26309 100644
--- a/test/CodeGenCXX/atomic.cpp
+++ b/test/CodeGenCXX/atomic.cpp
@@ -5,7 +5,7 @@ namespace PR11411 {
void f();
};
- // CHECK: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv
+ // CHECK-LABEL: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv
// CHECK-NOT: ret
template<typename _Tp> inline void Ptr<_Tp>::f() {
int* _refcount;
diff --git a/test/CodeGenCXX/atomicinit.cpp b/test/CodeGenCXX/atomicinit.cpp
index 38d012e6a9a1..ee2e9e4cf244 100644
--- a/test/CodeGenCXX/atomicinit.cpp
+++ b/test/CodeGenCXX/atomicinit.cpp
@@ -18,7 +18,7 @@ struct B {
_Atomic(B) b;
-// CHECK: define void @_Z11atomic_initR1Ai
+// CHECK-LABEL: define void @_Z11atomic_initR1Ai
void atomic_init(A& a, int i) {
// CHECK-NOT: atomic
// CHECK: tail call void @_ZN1BC1Ei
@@ -26,7 +26,7 @@ void atomic_init(A& a, int i) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z16atomic_init_boolPU7_Atomicbb
+// CHECK-LABEL: define void @_Z16atomic_init_boolPU7_Atomicbb
void atomic_init_bool(_Atomic(bool) *ab, bool b) {
// CHECK-NOT: atomic
// CHECK: {{zext i1.*to i8}}
@@ -40,7 +40,7 @@ struct AtomicBoolMember {
AtomicBoolMember(bool b);
};
-// CHECK: define void @_ZN16AtomicBoolMemberC2Eb
+// CHECK-LABEL: define void @_ZN16AtomicBoolMemberC2Eb
// CHECK: {{zext i1.*to i8}}
// CHECK-NEXT: store i8
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/attr-cleanup.cpp b/test/CodeGenCXX/attr-cleanup.cpp
new file mode 100644
index 000000000000..ff15b03de57c
--- /dev/null
+++ b/test/CodeGenCXX/attr-cleanup.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+namespace N {
+ void free(void *i) {}
+}
+
+int main(void) {
+ // CHECK: call void @_ZN1N4freeEPv
+ void *fp __attribute__((cleanup(N::free)));
+ return 0;
+}
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 4748cda8cc47..8bcff363c723 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -26,7 +26,7 @@ void C::bar3() { }
void C::bar4() { }
// PR6635
-// CHECK: define i32 @_Z5test1v()
+// CHECK-LABEL: define i32 @_Z5test1v()
int test1() { return 10; }
// CHECK at top of file
extern "C" int test2() __attribute__((alias("_Z5test1v")));
diff --git a/test/CodeGenCXX/bitfield-layout.cpp b/test/CodeGenCXX/bitfield-layout.cpp
index 15f33d27658d..646300a7d1cb 100644
--- a/test/CodeGenCXX/bitfield-layout.cpp
+++ b/test/CodeGenCXX/bitfield-layout.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP32 %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix CHECK-LP64 %s
+// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix CHECK-LP32 %s
// CHECK-LP64: %union.Test1 = type { i32, [4 x i8] }
union Test1 {
diff --git a/test/CodeGenCXX/bitfield.cpp b/test/CodeGenCXX/bitfield.cpp
index 1814aa2d534c..2c454b0c072c 100644
--- a/test/CodeGenCXX/bitfield.cpp
+++ b/test/CodeGenCXX/bitfield.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm -o - %s \
// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
//
// Tests for bitfield access patterns in C++ with special attention to
@@ -20,13 +20,13 @@ namespace N0 {
unsigned b71 : 2;
};
unsigned read00(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read00
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read00
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 16383
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read00
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read00
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 50
@@ -35,14 +35,14 @@ namespace N0 {
return s->b00;
}
unsigned read01(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read01
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read01
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 14
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read01
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read01
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 48
@@ -52,14 +52,14 @@ namespace N0 {
return s->b01;
}
unsigned read20(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read20
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read20
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 16
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read20
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read20
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 42
@@ -69,14 +69,14 @@ namespace N0 {
return s->b20;
}
unsigned read21(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read21
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read21
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 22
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read21
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read21
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 40
@@ -86,14 +86,14 @@ namespace N0 {
return s->b21;
}
unsigned read30(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read30
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read30
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read30
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read30
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10
@@ -103,14 +103,14 @@ namespace N0 {
return s->b30;
}
unsigned read31(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read31
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read31
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read31
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read31
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8
@@ -120,14 +120,14 @@ namespace N0 {
return s->b31;
}
unsigned read70(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read70
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read70
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56
// CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read70
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read70
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2
@@ -137,13 +137,13 @@ namespace N0 {
return s->b70;
}
unsigned read71(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N06read71
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N06read71
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62
// CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32
// CHECK-X86-64: ret i32 %[[trunc]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N06read71
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read71
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
// CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
// CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3
@@ -166,13 +166,13 @@ namespace N1 {
char c;
};
unsigned read(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N14read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N14read
// CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-X86-64: %[[val:.*]] = load i8* %[[ptr]]
// CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1
// CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32
// CHECK-X86-64: ret i32 %[[ext]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N14read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N14read
// CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-PPC64: %[[val:.*]] = load i8* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7
@@ -181,7 +181,7 @@ namespace N1 {
return s->b;
}
void write(S* s, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N15write
+ // CHECK-X86-64-LABEL: define void @_ZN2N15write
// CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
// CHECK-X86-64: %[[old:.*]] = load i8* %[[ptr]]
@@ -189,7 +189,7 @@ namespace N1 {
// CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2
// CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]]
// CHECK-X86-64: store i8 %[[new]], i8* %[[ptr]]
- // CHECK-PPC64: define void @_ZN2N15write
+ // CHECK-PPC64-LABEL: define void @_ZN2N15write
// CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
// CHECK-PPC64: %[[old:.*]] = load i8* %[[ptr]]
@@ -210,12 +210,12 @@ namespace N2 {
void *p;
};
unsigned read(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N24read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N24read
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
// CHECK-X86-64: ret i32 %[[and]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N24read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N24read
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
@@ -223,14 +223,14 @@ namespace N2 {
return s->b;
}
void write(S* s, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N25write
+ // CHECK-X86-64-LABEL: define void @_ZN2N25write
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
// CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
// CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
// CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
- // CHECK-PPC64: define void @_ZN2N25write
+ // CHECK-PPC64-LABEL: define void @_ZN2N25write
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
@@ -249,12 +249,12 @@ namespace N3 {
unsigned b : 24;
};
unsigned read(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N34read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N34read
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
// CHECK-X86-64: ret i32 %[[and]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N34read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N34read
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
@@ -262,14 +262,14 @@ namespace N3 {
return s->b;
}
void write(S* s, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N35write
+ // CHECK-X86-64-LABEL: define void @_ZN2N35write
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
// CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
// CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
// CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
- // CHECK-PPC64: define void @_ZN2N35write
+ // CHECK-PPC64-LABEL: define void @_ZN2N35write
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
@@ -300,13 +300,13 @@ namespace N4 {
// FIXME: We should widen this load as long as the function isn't being
// instrumented by thread-sanitizer.
//
- // CHECK-X86-64: define i32 @_ZN2N44read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N44read
// CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
// CHECK-X86-64: %[[val:.*]] = load i24* %[[ptr]]
// CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
// CHECK-X86-64: ret i32 %[[ext]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N44read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N44read
// CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
// CHECK-PPC64: %[[val:.*]] = load i24* %[[ptr]]
@@ -315,12 +315,12 @@ namespace N4 {
return s->b;
}
void write(Base* s, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N45write
+ // CHECK-X86-64-LABEL: define void @_ZN2N45write
// CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
// CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24
// CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]]
- // CHECK-PPC64: define void @_ZN2N45write
+ // CHECK-PPC64-LABEL: define void @_ZN2N45write
// CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
// CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24
@@ -342,12 +342,12 @@ namespace N5 {
struct Y { unsigned b : 24; } y;
};
unsigned read(U* u) {
- // CHECK-X86-64: define i32 @_ZN2N54read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N54read
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
// CHECK-X86-64: ret i32 %[[and]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N54read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N54read
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
@@ -355,14 +355,14 @@ namespace N5 {
return u->y.b;
}
void write(U* u, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N55write
+ // CHECK-X86-64-LABEL: define void @_ZN2N55write
// CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
// CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
// CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
// CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
- // CHECK-PPC64: define void @_ZN2N55write
+ // CHECK-PPC64-LABEL: define void @_ZN2N55write
// CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
// CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
// CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
@@ -387,7 +387,7 @@ namespace N6 {
unsigned char b2 : 8;
};
unsigned read(S* s) {
- // CHECK-X86-64: define i32 @_ZN2N64read
+ // CHECK-X86-64-LABEL: define i32 @_ZN2N64read
// CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
// CHECK-X86-64: %[[val1:.*]] = load i24* %[[ptr1]]
// CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
@@ -396,7 +396,7 @@ namespace N6 {
// CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
// CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
// CHECK-X86-64: ret i32 %[[add]]
- // CHECK-PPC64: define zeroext i32 @_ZN2N64read
+ // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N64read
// CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
// CHECK-PPC64: %[[val1:.*]] = load i24* %[[ptr1]]
// CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
@@ -408,14 +408,14 @@ namespace N6 {
return s->b1 + s->b2;
}
void write(S* s, unsigned x) {
- // CHECK-X86-64: define void @_ZN2N65write
+ // CHECK-X86-64-LABEL: define void @_ZN2N65write
// CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
// CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
// CHECK-X86-64: store i24 %[[new1]], i24* %[[ptr1]]
// CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
// CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
// CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]]
- // CHECK-PPC64: define void @_ZN2N65write
+ // CHECK-PPC64-LABEL: define void @_ZN2N65write
// CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
// CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
// CHECK-PPC64: store i24 %[[new1]], i24* %[[ptr1]]
diff --git a/test/CodeGenCXX/block-byref-cxx-objc.cpp b/test/CodeGenCXX/block-byref-cxx-objc.cpp
index 30f1f074b9b3..616fd67ccc38 100644
--- a/test/CodeGenCXX/block-byref-cxx-objc.cpp
+++ b/test/CodeGenCXX/block-byref-cxx-objc.cpp
@@ -15,13 +15,13 @@ int main()
return 0;
}
-// CHECK: define internal void @__Block_byref_object_copy_
+// CHECK-LABEL: define internal void @__Block_byref_object_copy_
// CHECK: call {{.*}} @_ZN1AC1ERKS_
-// CHECK: define internal void @__Block_byref_object_dispose_
+// CHECK-LABEL: define internal void @__Block_byref_object_dispose_
// CHECK: call {{.*}} @_ZN1AD1Ev
-// CHECK: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @__copy_helper_block_
// CHECK: call void @_Block_object_assign
-// CHECK: define internal void @__destroy_helper_block_
+// CHECK-LABEL: define internal void @__destroy_helper_block_
// CHECK: call void @_Block_object_dispose
// rdar://problem/11135650
diff --git a/test/CodeGenCXX/block-in-ctor-dtor.cpp b/test/CodeGenCXX/block-in-ctor-dtor.cpp
index 4ee6b1c10eb1..bd37d4418d4f 100644
--- a/test/CodeGenCXX/block-in-ctor-dtor.cpp
+++ b/test/CodeGenCXX/block-in-ctor-dtor.cpp
@@ -36,13 +36,13 @@ X::~X() {
};
-// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke
-// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_
-// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke
-// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_
-// CHECK: define internal void @___ZN1XC1Ev_block_invoke
-// CHECK: define internal void @___ZN1XC1Ev_block_invoke_
-// CHECK: define internal void @___ZN1XC2Ev_block_invoke
-// CHECK: define internal void @___ZN1XC2Ev_block_invoke_
-// CHECK: define internal void @___ZN1XD2Ev_block_invoke
-// CHECK: define internal void @___ZN1XD2Ev_block_invoke_
+// CHECK-LABEL: define internal void @___ZN4ZoneC2Ev_block_invoke
+// CHECK-LABEL: define internal void @___ZN4ZoneC2Ev_block_invoke_
+// CHECK-LABEL: define internal void @___ZN4ZoneD2Ev_block_invoke
+// CHECK-LABEL: define internal void @___ZN4ZoneD2Ev_block_invoke_
+// CHECK-LABEL: define internal void @___ZN1XC1Ev_block_invoke
+// CHECK-LABEL: define internal void @___ZN1XC1Ev_block_invoke_
+// CHECK-LABEL: define internal void @___ZN1XC2Ev_block_invoke
+// CHECK-LABEL: define internal void @___ZN1XC2Ev_block_invoke_
+// CHECK-LABEL: define internal void @___ZN1XD2Ev_block_invoke
+// CHECK-LABEL: define internal void @___ZN1XD2Ev_block_invoke_
diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp
index 3f0380abbd37..9ff5826ec5f1 100644
--- a/test/CodeGenCXX/blocks-cxx11.cpp
+++ b/test/CodeGenCXX/blocks-cxx11.cpp
@@ -46,7 +46,7 @@ namespace test_complex_int {
void test() {
constexpr _Complex int x = 500;
takeABlock(^{ takeItByValue(x); });
- // CHECK: store i32 500,
+ // CHECK: store { i32, i32 } { i32 500, i32 0 },
// CHECK: store i32 500,
// CHECK-NEXT: store i32 0,
@@ -100,7 +100,7 @@ namespace test_block_in_lambda {
};
lambda(); // make sure we emit the invocation function
}
- // CHECK: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"(
+ // CHECK-LABEL: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"(
// CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
// CHECK: [[THIS:%.*]] = load [[LAMBDA_T:%.*]]**
// CHECK: [[TO_DESTROY:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index 81eef0e02822..8a6fdacf8d1f 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
namespace test0 {
- // CHECK: define void @_ZN5test04testEi(
+ // CHECK-LABEL: define void @_ZN5test04testEi(
// CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(
// CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}(
void test(int x) {
@@ -13,7 +13,7 @@ extern void (^out)();
namespace test1 {
// Capturing const objects doesn't require a local block.
- // CHECK: define void @_ZN5test15test1Ev()
+ // CHECK-LABEL: define void @_ZN5test15test1Ev()
// CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
void test1() {
const int NumHorsemen = 4;
@@ -21,7 +21,7 @@ namespace test1 {
}
// That applies to structs too...
- // CHECK: define void @_ZN5test15test2Ev()
+ // CHECK-LABEL: define void @_ZN5test15test2Ev()
// CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
struct loc { double x, y; };
void test2() {
@@ -30,7 +30,7 @@ namespace test1 {
}
// ...unless they have mutable fields...
- // CHECK: define void @_ZN5test15test3Ev()
+ // CHECK-LABEL: define void @_ZN5test15test3Ev()
// CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
// CHECK: store void ()* [[T0]], void ()** @out
@@ -41,7 +41,7 @@ namespace test1 {
}
// ...or non-trivial destructors...
- // CHECK: define void @_ZN5test15test4Ev()
+ // CHECK-LABEL: define void @_ZN5test15test4Ev()
// CHECK: [[OBJ:%.*]] = alloca
// CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
@@ -69,22 +69,22 @@ namespace test2 {
~B();
};
- // CHECK: define void @_ZN5test24testEv()
+ // CHECK-LABEL: define void @_ZN5test24testEv()
void test() {
__block A a;
__block B b;
}
- // CHECK: define internal void @__Block_byref_object_copy
+ // CHECK-LABEL: define internal void @__Block_byref_object_copy
// CHECK: call void @_ZN5test21AC1ERKS0_(
- // CHECK: define internal void @__Block_byref_object_dispose
+ // CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: call void @_ZN5test21AD1Ev(
- // CHECK: define internal void @__Block_byref_object_copy
+ // CHECK-LABEL: define internal void @__Block_byref_object_copy
// CHECK: call void @_ZN5test21BC1ERKS0_(
- // CHECK: define internal void @__Block_byref_object_dispose
+ // CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: call void @_ZN5test21BD1Ev(
}
@@ -118,8 +118,8 @@ namespace test4 {
extern void consume(void(^)());
consume(^{ return foo(A()); });
}
- // CHECK: define void @_ZN5test44testEv()
- // CHECK: define internal void @___ZN5test44testEv_block_invoke
+ // CHECK-LABEL: define void @_ZN5test44testEv()
+ // 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*
@@ -147,7 +147,7 @@ namespace test5 {
doWithBlock(b);
}
- // CHECK: define void @_ZN5test54testEb(
+ // CHECK-LABEL: define void @_ZN5test54testEb(
// CHECK: [[COND:%.*]] = alloca i8
// CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4
// CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
@@ -197,7 +197,7 @@ namespace test6 {
bar();
}
- // CHECK: define void @_ZN5test64testEv()
+ // CHECK-LABEL: define void @_ZN5test64testEv()
// CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1
// CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]])
// CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(
diff --git a/test/CodeGenCXX/bool-bitfield.cpp b/test/CodeGenCXX/bool-bitfield.cpp
index 06bdf2bd0df3..a5a344ffb6ee 100644
--- a/test/CodeGenCXX/bool-bitfield.cpp
+++ b/test/CodeGenCXX/bool-bitfield.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
// RUN: | FileCheck %s
// PR14638; make sure this doesn't crash.
@@ -9,6 +9,6 @@ void func1(bool b, A& a1)
{
if ((a1.m_sorted = b)) {}
}
-// CHECK: define void @_Z5func1bR1A
+// CHECK-LABEL: define void @_Z5func1bR1A
// CHECK: br i1
// CHECK: ret void
diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp
index c9b0bff0f2e2..98e2d1a8271c 100644
--- a/test/CodeGenCXX/builtins.cpp
+++ b/test/CodeGenCXX/builtins.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
// PR8839
extern "C" char memmove();
@@ -7,3 +7,22 @@ int main() {
// CHECK: call {{signext i8|i8}} @memmove()
return memmove();
}
+
+struct S;
+// CHECK: define {{.*}} @_Z9addressofbR1SS0_(
+S *addressof(bool b, S &s, S &t) {
+ // CHECK: %[[LVALUE:.*]] = phi
+ // CHECK: ret {{.*}}* %[[LVALUE]]
+ return __builtin_addressof(b ? s : t);
+}
+
+extern "C" int __builtin_abs(int); // #1
+long __builtin_abs(long); // #2
+extern "C" int __builtin_abs(int); // #3
+
+int x = __builtin_abs(-2);
+// CHECK: store i32 2, i32* @x, align 4
+
+long y = __builtin_abs(-2l);
+// CHECK: [[Y:%.+]] = call i64 @_Z13__builtin_absl(i64 -2)
+// CHECK: store i64 [[Y]], i64* @y, align 8
diff --git a/test/CodeGenCXX/c-linkage.cpp b/test/CodeGenCXX/c-linkage.cpp
index f6e64d9e7415..1607623c6fea 100644
--- a/test/CodeGenCXX/c-linkage.cpp
+++ b/test/CodeGenCXX/c-linkage.cpp
@@ -10,15 +10,15 @@ extern "C" {
}
}
-// CHECK: define void @_ZN1N1X1fEv
+// CHECK-LABEL: define void @_ZN1N1X1fEv
extern "C" {
static void test2_f() {
}
- // CHECK: define internal void @_Z7test2_fv
+ // CHECK-LABEL: define internal void @_Z7test2_fv
static void test2_f(int x) {
}
- // CHECK: define internal void @_Z7test2_fi
+ // CHECK-LABEL: define internal void @_Z7test2_fi
void test2_use() {
test2_f();
test2_f(42);
diff --git a/test/CodeGenCXX/c99-variable-length-array.cpp b/test/CodeGenCXX/c99-variable-length-array.cpp
index d486f9b01826..2cd8e114b1ec 100644
--- a/test/CodeGenCXX/c99-variable-length-array.cpp
+++ b/test/CodeGenCXX/c99-variable-length-array.cpp
@@ -9,7 +9,7 @@ struct Y {
~Y();
};
-// CHECK: define void @_Z1fiPPKc(
+// CHECK-LABEL: define void @_Z1fiPPKc(
void f(int argc, const char* argv[]) {
// CHECK: call void @_ZN1XC1Ev
X x;
diff --git a/test/CodeGenCXX/call-arg-zero-temp.cpp b/test/CodeGenCXX/call-arg-zero-temp.cpp
index 101e81f8ef79..14238f214515 100644
--- a/test/CodeGenCXX/call-arg-zero-temp.cpp
+++ b/test/CodeGenCXX/call-arg-zero-temp.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/captured-statements.cpp b/test/CodeGenCXX/captured-statements.cpp
new file mode 100644
index 000000000000..2843c2b69c95
--- /dev/null
+++ b/test/CodeGenCXX/captured-statements.cpp
@@ -0,0 +1,189 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t
+// 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
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-4
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-5
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-6
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-7
+
+struct Foo {
+ int x;
+ float y;
+ ~Foo() {}
+};
+
+struct TestClass {
+ int x;
+
+ TestClass() : x(0) {};
+ void MemberFunc() {
+ Foo f;
+ #pragma clang __debug captured
+ {
+ f.y = x;
+ }
+ }
+};
+
+void test1() {
+ TestClass c;
+ c.MemberFunc();
+ // CHECK-1: %[[Capture:struct\.anon[\.0-9]*]] = type { %struct.Foo*, %struct.TestClass* }
+
+ // CHECK-1: define {{.*}} void @_ZN9TestClass10MemberFuncEv
+ // CHECK-1: alloca %struct.anon
+ // CHECK-1: getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 0
+ // CHECK-1: store %struct.Foo* %f, %struct.Foo**
+ // CHECK-1: getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 1
+ // CHECK-1: call void @[[HelperName:[A-Za-z0-9_]+]](%[[Capture]]*
+ // CHECK-1: call {{.*}}FooD1Ev
+ // CHECK-1: ret
+}
+
+// CHECK-1: define internal void @[[HelperName]]
+// CHECK-1: getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 1
+// CHECK-1: getelementptr inbounds %struct.TestClass* {{[^,]*}}, i32 0, i32 0
+// CHECK-1: getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 0
+
+void test2(int x) {
+ int y = [&]() {
+ #pragma clang __debug captured
+ {
+ x++;
+ }
+ return x;
+ }();
+
+ // CHECK-2-LABEL: define void @_Z5test2i
+ // CHECK-2: call {{.*}} @[[Lambda:["$\w]+]]
+ //
+ // CHECK-2: define internal {{.*}} @[[Lambda]]
+ // CHECK-2: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
+ //
+ // CHECK-2: define internal void @[[HelperName]]
+ // CHECK-2: getelementptr inbounds %[[Capture]]*
+ // CHECK-2: load i32**
+ // CHECK-2: load i32*
+}
+
+void test3(int x) {
+ #pragma clang __debug captured
+ {
+ x = [=]() { return x + 1; } ();
+ }
+
+ // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }
+
+ // CHECK-3-LABEL: define void @_Z5test3i
+ // CHECK-3: store i32*
+ // CHECK-3: call void @{{.*}}__captured_stmt
+ // CHECK-3: ret void
+}
+
+void test4() {
+ #pragma clang __debug captured
+ {
+ Foo f;
+ f.x = 5;
+ }
+ // CHECK-4-LABEL: define void @_Z5test4v
+ // CHECK-4: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
+ // CHECK-4: ret void
+ //
+ // CHECK-4: define internal void @[[HelperName]]
+ // CHECK-4: store i32 5, i32*
+ // CHECK-4: call {{.*}}FooD1Ev
+}
+
+template <typename T, int id>
+void touch(const T &) {}
+
+template <typename T, unsigned id>
+void template_capture_var() {
+ T x;
+ #pragma clang __debug captured
+ {
+ touch<T, id>(x);
+ }
+}
+
+template <typename T, int id>
+class Val {
+ T v;
+public:
+ void set() {
+ #pragma clang __debug captured
+ {
+ touch<T, id>(v);
+ }
+ }
+
+ template <typename U, int id2>
+ void foo(U u) {
+ #pragma clang __debug captured
+ {
+ touch<U, id + id2>(u);
+ }
+ }
+};
+
+void test_capture_var() {
+ // CHECK-5: define {{.*}} void @_Z20template_capture_varIiLj201EEvv
+ // CHECK-5-NOT: }
+ // CHECK-5: store i32*
+ // CHECK-5: call void @__captured_stmt
+ // CHECK-5-NEXT: ret void
+ template_capture_var<int, 201>();
+
+ // CHECK-5: define {{.*}} void @_ZN3ValIfLi202EE3setEv
+ // CHECK-5-NOT: }
+ // CHECK-5: store %class.Val*
+ // CHECK-5: call void @__captured_stmt
+ // CHECK-5-NEXT: ret void
+ Val<float, 202> Obj;
+ Obj.set();
+
+ // CHECK-5: define {{.*}} void @_ZN3ValIfLi202EE3fooIdLi203EEEvT_
+ // CHECK-5-NOT: }
+ // CHECK-5: store %class.Val*
+ // CHECK-5: store double
+ // CHECK-5: call void @__captured_stmt
+ // CHECK-5-NEXT: ret void
+ Obj.foo<double, 203>(1.0);
+}
+
+template <typename T>
+void template_capture_lambda() {
+ T x, y;
+ [=, &y]() {
+ #pragma clang __debug captured
+ {
+ y += x;
+ }
+ }();
+}
+
+void test_capture_lambda() {
+ // CHECK-6: define {{.*}} void @_ZZ23template_capture_lambdaIiEvvENKUlvE_clEv
+ // CHECK-6-NOT: }
+ // CHECK-6: store i32*
+ // CHECK-6: store i32*
+ // CHECK-6: call void @__captured_stmt
+ // CHECK-6-NEXT: ret void
+ template_capture_lambda<int>();
+}
+
+inline int test_captured_linkage() {
+ // CHECK-7: @_ZZ21test_captured_linkagevE1i = linkonce_odr global i32 0
+ int j;
+ #pragma clang __debug captured
+ {
+ static int i = 0;
+ j = ++i;
+ }
+ return j;
+}
+void call_test_captured_linkage() {
+ test_captured_linkage();
+}
diff --git a/test/CodeGenCXX/cast-conversion.cpp b/test/CodeGenCXX/cast-conversion.cpp
index d023b9abfee0..5565f6548437 100644
--- a/test/CodeGenCXX/cast-conversion.cpp
+++ b/test/CodeGenCXX/cast-conversion.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
struct A {
A(int);
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index d6d0edfa1edb..338da57f0c7b 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
struct S {
double d;
@@ -186,7 +186,7 @@ void bad_downcast_pointer(S *p) {
// CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
// CHECK: br i1 %[[NONNULL]],
- // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(
// CHECK: %[[E1:.*]] = icmp uge i64 %[[SIZE]], 24
// CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
// CHECK: %[[E2:.*]] = icmp eq i64 %[[MISALIGN]], 0
@@ -207,7 +207,7 @@ void bad_downcast_pointer(S *p) {
void bad_downcast_reference(S &p) {
// CHECK: %[[E1:.*]] = icmp ne {{.*}}, null
// CHECK-NOT: br i1
- // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(
// CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24
// CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
// CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
@@ -321,4 +321,156 @@ char string_index(int n) {
return "Hello"[n];
}
+class A // align=4
+{
+ int a1, a2, a3;
+};
+
+class B // align=8
+{
+ long b1, b2;
+};
+
+class C : public A, public B // align=16
+{
+ alignas(16) int c1;
+};
+
+// Make sure we check the alignment of the pointer after subtracting any
+// offset. The pointer before subtraction doesn't need to be aligned for
+// the destination type.
+
+// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b)
+void downcast_pointer(B *b) {
+ (void) static_cast<C*>(b);
+ // Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...)
+ // CHECK: [[SUB:%[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16
+ // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C*
+ // null check goes here
+ // CHECK: [[FROM_PHI:%[0-9]*]] = phi %class.C* [ [[C]], {{.*}} ], {{.*}}
+ // Objectsize check goes here
+ // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[FROM_PHI]] to i64
+ // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15
+ // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0
+ // AND the alignment test with the objectsize test.
+ // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
+ // CHECK-NEXT: br i1 [[AND]]
+}
+
+// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b)
+void downcast_reference(B &b) {
+ (void) static_cast<C&>(b);
+ // Alignment check from EmitTypeCheck(TCK_DowncastReference, ...)
+ // CHECK: [[SUB:%[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16
+ // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C*
+ // Objectsize check goes here
+ // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[C]] to i64
+ // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15
+ // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0
+ // AND the alignment test with the objectsize test.
+ // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
+ // CHECK-NEXT: br i1 [[AND]]
+}
+
+// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prefix <{ i32, i8* }> <{ i32 1413876459, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
+void indirect_function_call(void (*p)(int)) {
+ // CHECK: [[PTR:%[0-9]*]] = bitcast void (i32)* {{.*}} to <{ i32, i8* }>*
+
+ // Signature check
+ // CHECK-NEXT: [[SIGPTR:%[0-9]*]] = getelementptr <{ i32, i8* }>* [[PTR]], i32 0, i32 0
+ // CHECK-NEXT: [[SIG:%[0-9]*]] = load i32* [[SIGPTR]]
+ // CHECK-NEXT: [[SIGCMP:%[0-9]*]] = icmp eq i32 [[SIG]], 1413876459
+ // CHECK-NEXT: br i1 [[SIGCMP]]
+
+ // RTTI pointer check
+ // CHECK: [[RTTIPTR:%[0-9]*]] = getelementptr <{ i32, i8* }>* [[PTR]], i32 0, i32 1
+ // CHECK-NEXT: [[RTTI:%[0-9]*]] = load i8** [[RTTIPTR]]
+ // CHECK-NEXT: [[RTTICMP:%[0-9]*]] = icmp eq i8* [[RTTI]], bitcast ({ i8*, i8* }* @_ZTIFviE to i8*)
+ // CHECK-NEXT: br i1 [[RTTICMP]]
+ p(42);
+}
+
+namespace CopyValueRepresentation {
+ // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_
+ // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
+ // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S4aSEOS0_
+ // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
+ // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S5C2ERKS0_
+ // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value
+ // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S2C2ERKS0_
+ // CHECK: __ubsan_handle_load_invalid_value
+ // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S1C2ERKS0_
+ // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value
+
+ struct CustomCopy { CustomCopy(); CustomCopy(const CustomCopy&); };
+ struct S1 {
+ CustomCopy CC;
+ bool b;
+ };
+ void callee1(S1);
+ void test1() {
+ S1 s11;
+ callee1(s11);
+ S1 s12;
+ s12 = s11;
+ }
+
+ static bool some_global_bool;
+ struct ExprCopy {
+ ExprCopy();
+ ExprCopy(const ExprCopy&, bool b = some_global_bool);
+ };
+ struct S2 {
+ ExprCopy EC;
+ bool b;
+ };
+ void callee2(S2);
+ void test2(void) {
+ S2 s21;
+ callee2(s21);
+ S2 s22;
+ s22 = s21;
+ }
+
+ struct CustomAssign { CustomAssign &operator=(const CustomAssign&); };
+ struct S3 {
+ CustomAssign CA;
+ bool b;
+ };
+ void test3() {
+ S3 x, y;
+ x = y;
+ }
+
+ struct CustomMove {
+ CustomMove();
+ CustomMove(const CustomMove&&);
+ CustomMove &operator=(const CustomMove&&);
+ };
+ struct S4 {
+ CustomMove CM;
+ bool b;
+ };
+ void test4() {
+ S4 x, y;
+ x = static_cast<S4&&>(y);
+ }
+
+ struct EnumCustomCopy {
+ EnumCustomCopy();
+ EnumCustomCopy(const EnumCustomCopy&);
+ };
+ struct S5 {
+ EnumCustomCopy ECC;
+ bool b;
+ };
+ void callee5(S5);
+ void test5() {
+ S5 s51;
+ callee5(s51);
+ S5 s52;
+ s52 = s51;
+ }
+}
+
// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGenCXX/catch-undef-behavior2.cpp b/test/CodeGenCXX/catch-undef-behavior2.cpp
new file mode 100644
index 000000000000..b8b31ca23f55
--- /dev/null
+++ b/test/CodeGenCXX/catch-undef-behavior2.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+bool GetOptionalBool(bool *value);
+bool GetBool(bool default_value) {
+ // CHECK-LABEL: @_Z7GetBoolb
+ // CHECK-NOT: select
+ bool value;
+ return GetOptionalBool(&value) ? value : default_value;
+}
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
index 5df0ea587667..f1d88027c4fa 100644
--- a/test/CodeGenCXX/compound-literals.cpp
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -12,7 +12,7 @@ struct Y {
X x;
};
-// CHECK: define i32 @_Z1fv()
+// CHECK-LABEL: define i32 @_Z1fv()
int f() {
// CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca
// CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0
@@ -26,7 +26,7 @@ int f() {
return ((Y){17, "seventeen"}).i;
}
-// CHECK: define i32 @_Z1gv()
+// CHECK-LABEL: define i32 @_Z1gv()
int g() {
// CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]]
const int (&v)[2] = (int [2]) {1,2};
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
index cc2eaf5bd6a5..452f1c3c9b7e 100644
--- a/test/CodeGenCXX/condition.cpp
+++ b/test/CodeGenCXX/condition.cpp
@@ -26,7 +26,7 @@ struct Y {
X getX();
-// CHECK: define void @_Z11if_destructi(
+// CHECK-LABEL: define void @_Z11if_destructi(
void if_destruct(int z) {
// Verify that the condition variable is destroyed at the end of the
// "if" statement.
@@ -95,7 +95,7 @@ void switch_destruct(int z) {
int foo();
-// CHECK: define void @_Z14while_destructi
+// CHECK-LABEL: define void @_Z14while_destructi
void while_destruct(int z) {
// CHECK: [[Z:%.*]] = alloca i32
// CHECK: [[CLEANUPDEST:%.*]] = alloca i32
@@ -135,7 +135,7 @@ void while_destruct(int z) {
// CHECK: ret
}
-// CHECK: define void @_Z12for_destructi(
+// CHECK-LABEL: define void @_Z12for_destructi(
void for_destruct(int z) {
// CHECK: [[Z:%.*]] = alloca i32
// CHECK: [[CLEANUPDEST:%.*]] = alloca i32
@@ -224,7 +224,7 @@ void for_destruct(int z) {
}
void do_destruct(int z) {
- // CHECK: define void @_Z11do_destruct
+ // CHECK-LABEL: define void @_Z11do_destruct
do {
// CHECK: store i32 77
z = 77;
diff --git a/test/CodeGenCXX/conditional-gnu-ext.cpp b/test/CodeGenCXX/conditional-gnu-ext.cpp
index 104a91d27356..44ebf9808e4a 100644
--- a/test/CodeGenCXX/conditional-gnu-ext.cpp
+++ b/test/CodeGenCXX/conditional-gnu-ext.cpp
@@ -77,7 +77,7 @@ namespace test3 {
};
B test0(B &x) {
- // CHECK: define void @_ZN5test35test0ERNS_1BE(
+ // CHECK-LABEL: define void @_ZN5test35test0ERNS_1BE(
// CHECK: [[X:%.*]] = alloca [[B:%.*]]*,
// CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]]
// CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]]
@@ -92,7 +92,7 @@ namespace test3 {
}
B test1() {
- // CHECK: define void @_ZN5test35test1Ev(
+ // CHECK-LABEL: define void @_ZN5test35test1Ev(
// CHECK: [[TEMP:%.*]] = alloca [[B]],
// CHECK-NEXT: call void @_ZN5test312test1_helperEv([[B]]* sret [[TEMP]])
// CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]])
@@ -109,7 +109,7 @@ namespace test3 {
A test2(B &x) {
- // CHECK: define void @_ZN5test35test2ERNS_1BE(
+ // CHECK-LABEL: define void @_ZN5test35test2ERNS_1BE(
// CHECK: [[X:%.*]] = alloca [[B]]*,
// CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]]
// CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]]
@@ -124,7 +124,7 @@ namespace test3 {
}
A test3() {
- // CHECK: define void @_ZN5test35test3Ev(
+ // CHECK-LABEL: define void @_ZN5test35test3Ev(
// CHECK: [[TEMP:%.*]] = alloca [[B]],
// CHECK-NEXT: call void @_ZN5test312test3_helperEv([[B]]* sret [[TEMP]])
// CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]])
diff --git a/test/CodeGenCXX/conditional-temporaries.cpp b/test/CodeGenCXX/conditional-temporaries.cpp
index d5382872f9d9..a3cc2fef1e8f 100644
--- a/test/CodeGenCXX/conditional-temporaries.cpp
+++ b/test/CodeGenCXX/conditional-temporaries.cpp
@@ -36,19 +36,19 @@ Checker c;
}
-// CHECK: define i32 @_Z12getCtorCallsv()
+// CHECK-LABEL: define i32 @_Z12getCtorCallsv()
int getCtorCalls() {
// CHECK: ret i32 5
return ctorcalls;
}
-// CHECK: define i32 @_Z12getDtorCallsv()
+// CHECK-LABEL: define i32 @_Z12getDtorCallsv()
int getDtorCalls() {
// CHECK: ret i32 5
return dtorcalls;
}
-// CHECK: define zeroext i1 @_Z7successv()
+// CHECK-LABEL: define zeroext i1 @_Z7successv()
bool success() {
// CHECK: ret i1 true
return ctorcalls == dtorcalls;
diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp
index 833adba8bae7..d21e91178e40 100644
--- a/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/test/CodeGenCXX/const-init-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s
+// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s
// FIXME: The padding in all these objects should be zero-initialized.
namespace StructUnion {
@@ -224,12 +224,50 @@ namespace LiteralReference {
constexpr Lit() : n(5) {}
int n;
};
- // FIXME: This should have static initialization, but we do not implement
- // that yet. For now, just check that we don't set the (pointer) value of
- // the reference to 5!
- //
- // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null
+
+ // This creates a non-const temporary and binds a reference to it.
+ // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 5 }, align 4
+ // CHECK: @_ZN16LiteralReference3litE = constant {{.*}} @[[TEMP]], align 8
const Lit &lit = Lit();
+
+ // This creates a const temporary as part of the reference initialization.
+ // CHECK: @[[TEMP:.*]] = private constant {{.*}} { i32 5 }, align 4
+ // CHECK: @_ZN16LiteralReference4lit2E = constant {{.*}} @[[TEMP]], align 8
+ const Lit &lit2 = {};
+
+ struct A { int &&r1; const int &&r2; };
+ struct B { A &&a1; const A &&a2; };
+ B b = { { 0, 1 }, { 2, 3 } };
+ // CHECK: @[[TEMP0:.*]] = private global i32 0, align 4
+ // CHECK: @[[TEMP1:.*]] = private constant i32 1, align 4
+ // CHECK: @[[TEMPA1:.*]] = private global {{.*}} { i32* @[[TEMP0]], i32* @[[TEMP1]] }, align 8
+ // CHECK: @[[TEMP2:.*]] = private global i32 2, align 4
+ // CHECK: @[[TEMP3:.*]] = private constant i32 3, align 4
+ // CHECK: @[[TEMPA2:.*]] = private constant {{.*}} { i32* @[[TEMP2]], i32* @[[TEMP3]] }, align 8
+ // CHECK: @_ZN16LiteralReference1bE = global {{.*}} { {{.*}}* @[[TEMPA1]], {{.*}}* @[[TEMPA2]] }, align 8
+
+ struct Subobj {
+ int a, b, c;
+ };
+ // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 1, i32 2, i32 3 }, align 4
+ // CHECK: @_ZN16LiteralReference2soE = constant {{.*}} (i8* getelementptr {{.*}} @[[TEMP]]{{.*}}, i64 4)
+ constexpr int &&so = Subobj{ 1, 2, 3 }.b;
+
+ struct Dummy { int padding; };
+ struct Derived : Dummy, Subobj {
+ constexpr Derived() : Dummy{200}, Subobj{4, 5, 6} {}
+ };
+ using ConstDerived = const Derived;
+ // CHECK: @[[TEMPCOMMA:.*]] = private constant {{.*}} { i32 200, i32 4, i32 5, i32 6 }
+ // CHECK: @_ZN16LiteralReference5commaE = constant {{.*}} getelementptr {{.*}} @[[TEMPCOMMA]]{{.*}}, i64 8)
+ constexpr const int &comma = (1, (2, ConstDerived{}).b);
+
+ // CHECK: @[[TEMPDERIVED:.*]] = private global {{.*}} { i32 200, i32 4, i32 5, i32 6 }
+ // CHECK: @_ZN16LiteralReference4baseE = constant {{.*}} getelementptr {{.*}} @[[TEMPDERIVED]]{{.*}}, i64 4)
+ constexpr Subobj &&base = Derived{};
+
+ // CHECK: @_ZN16LiteralReference7derivedE = constant {{.*}} @[[TEMPDERIVED]]
+ constexpr Derived &derived = static_cast<Derived&>(base);
}
namespace NonLiteralConstexpr {
@@ -330,6 +368,32 @@ namespace PR13273 {
extern const S s {};
}
+namespace ArrayTemporary {
+ struct A { const int (&x)[3]; };
+ struct B { const A (&x)[2]; };
+ // CHECK: @[[A1:_ZGRN14ArrayTemporary1bE.*]] = private constant [3 x i32] [i32 1, i32 2, i32 3]
+ // CHECK: @[[A2:_ZGRN14ArrayTemporary1bE.*]] = private constant [3 x i32] [i32 4, i32 5, i32 6]
+ // CHECK: @[[ARR:_ZGRN14ArrayTemporary1bE.*]] = private constant [2 x {{.*}}] [{{.*}} { [3 x i32]* @[[A1]] }, {{.*}} { [3 x i32]* @[[A2]] }]
+ // CHECK: @[[B:_ZGRN14ArrayTemporary1bE.*]] = private global {{.*}} { [2 x {{.*}}]* @[[ARR]] }
+ // CHECK: @_ZN14ArrayTemporary1bE = constant {{.*}}* @[[B]]
+ B &&b = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } };
+}
+
+namespace UnemittedTemporaryDecl {
+ constexpr int &&ref = 0;
+ extern constexpr int &ref2 = ref;
+ // CHECK: @_ZGRN22UnemittedTemporaryDecl3refE = private global i32 0
+
+ // FIXME: This declaration should not be emitted -- it isn't odr-used.
+ // CHECK: @_ZN22UnemittedTemporaryDecl3refE
+
+ // CHECK: @_ZN22UnemittedTemporaryDecl4ref2E = constant i32* @_ZGRN22UnemittedTemporaryDecl3refE
+}
+
+// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
+// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102
+// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103
+
// Constant initialization tests go before this point,
// dynamic initialization tests go after.
@@ -356,6 +420,40 @@ namespace PR13273 {
// CHECK-NOT: }
// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev
+// PR12848: Don't emit dynamic initializers for local constexpr variables.
+namespace LocalVarInit {
+ constexpr int f(int n) { return n; }
+ struct Agg { int k; };
+ struct Ctor { constexpr Ctor(int n) : k(n) {} int k; };
+ struct Mutable { constexpr Mutable(int n) : k(n) {} mutable int k; };
+
+ // CHECK: define {{.*}} @_ZN12LocalVarInit6scalarEv
+ // CHECK-NOT: call
+ // CHECK: store i32 100,
+ // CHECK-NOT: call
+ // CHECK: ret i32 100
+ int scalar() { constexpr int a = { f(100) }; return a; }
+
+ // CHECK: define {{.*}} @_ZN12LocalVarInit3aggEv
+ // CHECK-NOT: call
+ // CHECK: ret i32 101
+ int agg() { constexpr Agg a = { f(101) }; return a.k; }
+
+ // CHECK: define {{.*}} @_ZN12LocalVarInit4ctorEv
+ // CHECK-NOT: call
+ // CHECK: ret i32 102
+ int ctor() { constexpr Ctor a = { f(102) }; return a.k; }
+
+ // CHECK: define {{.*}} @_ZN12LocalVarInit8mutable_Ev
+ // CHECK-NOT: call
+ // CHECK: call {{.*}}memcpy{{.*}} @_ZZN12LocalVarInit8mutable_EvE1a
+ // CHECK-NOT: call
+ // Can't fold return value due to 'mutable'.
+ // CHECK-NOT: ret i32 103
+ // CHECK: }
+ int mutable_() { constexpr Mutable a = { f(103) }; return a.k; }
+}
+
namespace CrossFuncLabelDiff {
// Make sure we refuse to constant-fold the variable b.
constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }
diff --git a/test/CodeGenCXX/const-init-cxx1y.cpp b/test/CodeGenCXX/const-init-cxx1y.cpp
new file mode 100644
index 000000000000..978c428e078a
--- /dev/null
+++ b/test/CodeGenCXX/const-init-cxx1y.cpp
@@ -0,0 +1,48 @@
+// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++1y | FileCheck %s
+
+struct A {
+ constexpr A() : n(1) {}
+ ~A();
+ int n;
+};
+struct B : A {
+ A a[3];
+ constexpr B() {
+ ++a[0].n;
+ a[1].n += 2;
+ a[2].n = n + a[1].n;
+ }
+};
+B b;
+
+// CHECK: @b = global {{.*}} i32 1, {{.*}} { i32 2 }, {{.*}} { i32 3 }, {{.*}} { i32 4 }
+// CHECK-NOT: _ZN1BC
+
+namespace ModifyStaticTemporary {
+ struct A { int &&temporary; int x; };
+ constexpr int f(int &r) { r *= 9; return r - 12; }
+ A a = { 6, f(a.temporary) };
+ // CHECK: @_ZGRN21ModifyStaticTemporary1aE = private global i32 54
+ // CHECK: @_ZN21ModifyStaticTemporary1aE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1aE, i32 42
+
+ A b = { 7, ++b.temporary };
+ // CHECK: @_ZGRN21ModifyStaticTemporary1bE = private global i32 8
+ // CHECK: @_ZN21ModifyStaticTemporary1bE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1bE, i32 8
+
+ // Can't emit all of 'c' as a constant here, so emit the initial value of
+ // 'c.temporary', not the value as modified by the partial evaluation within
+ // the initialization of 'c.x'.
+ A c = { 10, (++c.temporary, b.x) };
+ // CHECK: @_ZGRN21ModifyStaticTemporary1cE = private global i32 10
+ // CHECK: @_ZN21ModifyStaticTemporary1cE = global {{.*}} zeroinitializer
+}
+
+// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
+
+// CHECK: define
+// CHECK-NOT: @_ZGRN21ModifyStaticTemporary1cE
+// CHECK: store {{.*}} @_ZGRN21ModifyStaticTemporary1cE, {{.*}} @_ZN21ModifyStaticTemporary1cE
+// CHECK: add
+// CHECK: store
+// CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE
+// CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
index 201ce8f0c64c..05896ff7db00 100644
--- a/test/CodeGenCXX/const-init.cpp
+++ b/test/CodeGenCXX/const-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
// CHECK: @a = global i32 10
int a = 10;
diff --git a/test/CodeGenCXX/constructor-attr.cpp b/test/CodeGenCXX/constructor-attr.cpp
index 691795f77619..4f6d635e95d1 100644
--- a/test/CodeGenCXX/constructor-attr.cpp
+++ b/test/CodeGenCXX/constructor-attr.cpp
@@ -5,7 +5,7 @@
// PR6521
void bar();
struct Foo {
- // CHECK: define linkonce_odr void @_ZN3Foo3fooEv
+ // CHECK-LABEL: define linkonce_odr void @_ZN3Foo3fooEv
static void foo() __attribute__((constructor)) {
bar();
}
diff --git a/test/CodeGenCXX/constructor-conversion.cpp b/test/CodeGenCXX/constructor-conversion.cpp
index f50346328500..ebb414da960b 100644
--- a/test/CodeGenCXX/constructor-conversion.cpp
+++ b/test/CodeGenCXX/constructor-conversion.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-default-arg.cpp b/test/CodeGenCXX/constructor-default-arg.cpp
index 32086c1ad37c..c2cf44ce810c 100644
--- a/test/CodeGenCXX/constructor-default-arg.cpp
+++ b/test/CodeGenCXX/constructor-default-arg.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp
index 1ff922de60f3..ea2ea45a3273 100644
--- a/test/CodeGenCXX/constructor-destructor-return-this.cpp
+++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp
@@ -1,60 +1,116 @@
-//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-pc-win32 -cxx-abi microsoft -fno-rtti | FileCheck --check-prefix=CHECKMS %s
+// FIXME: these tests crash on the bots when run with -triple=x86_64-pc-win32
-// For constructors/desctructors that return 'this', if there exists a callsite
-// that returns 'this' and is immediately before the return instruction, make
-// sure we are using the return value from the callsite.
-// rdar://12818789
+// Make sure we attach the 'returned' attribute to the 'this' parameter of
+// constructors and destructors which return this (and only these cases)
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
-// CHECK-NEXT: ret [[A]] [[THIS1]]
+class A {
+public:
+ A();
+ ~A();
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
-// CHECK-NEXT: ret [[A]] [[THIS1]]
+private:
+ int x_;
+};
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
-// CHECK-NEXT: ret [[A]] [[THIS1]]
+class B : public A {
+public:
+ B(int *i);
+ ~B();
+
+private:
+ int *i_;
+};
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
-// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
-// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
-// CHECK-NEXT: ret [[A]] [[THIS2]]
+B::B(int *i) : i_(i) { }
+B::~B() { }
-class TimerBase {
+// CHECKGEN-LABEL: define void @_ZN1BC1EPi(%class.B* %this, i32* %i)
+// CHECKGEN-LABEL: define void @_ZN1BC2EPi(%class.B* %this, i32* %i)
+// CHECKGEN-LABEL: define void @_ZN1BD1Ev(%class.B* %this)
+// CHECKGEN-LABEL: define void @_ZN1BD2Ev(%class.B* %this)
+
+// CHECKARM-LABEL: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i)
+// CHECKARM-LABEL: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i)
+// CHECKARM-LABEL: define %class.B* @_ZN1BD1Ev(%class.B* returned %this)
+// CHECKARM-LABEL: define %class.B* @_ZN1BD2Ev(%class.B* returned %this)
+
+// CHECKMS-LABEL: define x86_thiscallcc %class.B* @"\01??0B@@QAE@PAH@Z"(%class.B* returned %this, i32* %i)
+// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1B@@QAE@XZ"(%class.B* %this)
+
+class C : public A, public B {
public:
- TimerBase();
- virtual ~TimerBase();
+ C(int *i, char *c);
+ virtual ~C();
+private:
+ char *c_;
};
-template <typename TimerFiredClass> class Timer : public TimerBase {
-public:
- typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
+C::C(int *i, char *c) : B(i), c_(c) { }
+C::~C() { }
- Timer(TimerFiredClass* o, TimerFiredFunction f)
- : m_object(o), m_function(f) { }
+// CHECKGEN-LABEL: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)
+// CHECKGEN-LABEL: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c)
+// CHECKGEN-LABEL: define void @_ZN1CD0Ev(%class.C* %this)
+// CHECKGEN-LABEL: define void @_ZN1CD1Ev(%class.C* %this)
+// CHECKGEN-LABEL: define void @_ZN1CD2Ev(%class.C* %this)
-private:
- virtual void fired() { (m_object->*m_function)(this); }
+// CHECKARM-LABEL: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c)
+// CHECKARM-LABEL: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c)
+// CHECKARM-LABEL: define void @_ZN1CD0Ev(%class.C* %this)
+// CHECKARM-LABEL: define %class.C* @_ZN1CD1Ev(%class.C* returned %this)
+// CHECKARM-LABEL: define %class.C* @_ZN1CD2Ev(%class.C* returned %this)
- TimerFiredClass* m_object;
- TimerFiredFunction m_function;
-};
+// CHECKMS-LABEL: define x86_thiscallcc %class.C* @"\01??0C@@QAE@PAHPAD@Z"(%class.C* returned %this, i32* %i, i8* %c)
+// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1C@@UAE@XZ"(%class.C* %this)
-class ObjectCache {
+class D : public virtual A {
public:
- explicit ObjectCache();
- ~ObjectCache();
+ D();
+ ~D();
+};
-private:
- Timer<ObjectCache> m_notificationPostTimer;
+D::D() { }
+D::~D() { }
+
+// CHECKGEN-LABEL: define void @_ZN1DC1Ev(%class.D* %this)
+// CHECKGEN-LABEL: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt)
+// CHECKGEN-LABEL: define void @_ZN1DD1Ev(%class.D* %this)
+// CHECKGEN-LABEL: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt)
+
+// CHECKARM-LABEL: define %class.D* @_ZN1DC1Ev(%class.D* returned %this)
+// CHECKARM-LABEL: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt)
+// CHECKARM-LABEL: define %class.D* @_ZN1DD1Ev(%class.D* returned %this)
+// CHECKARM-LABEL: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt)
+
+// CHECKMS-LABEL: define x86_thiscallcc %class.D* @"\01??0D@@QAE@XZ"(%class.D* returned %this, i32 %is_most_derived)
+// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1D@@QAE@XZ"(%class.D* %this)
+
+class E {
+public:
+ E();
+ virtual ~E();
};
-inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
-inline ObjectCache::~ObjectCache() { }
+E* gete();
-ObjectCache *test() {
- ObjectCache *dd = new ObjectCache();
- return dd;
+void test_destructor() {
+ const E& e1 = E();
+ E* e2 = gete();
+ e2->~E();
}
+
+// CHECKARM-LABEL: define void @_Z15test_destructorv()
+
+// Verify that virtual calls to destructors are not marked with a 'returned'
+// this parameter at the call site...
+// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)**
+// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]]
+// CHECKARM: call %class.E* [[THUNK]](%class.E* %
+
+// ...but static calls create declarations with 'returned' this
+// CHECKARM: {{%.*}} = call %class.E* @_ZN1ED1Ev(%class.E* %
+
+// CHECKARM: declare %class.E* @_ZN1ED1Ev(%class.E* returned)
diff --git a/test/CodeGenCXX/constructor-for-array-members.cpp b/test/CodeGenCXX/constructor-for-array-members.cpp
index 7a365cd26da4..7842d9c725e5 100644
--- a/test/CodeGenCXX/constructor-for-array-members.cpp
+++ b/test/CodeGenCXX/constructor-for-array-members.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index b33184e3966e..477a439f337a 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -70,7 +70,7 @@ template <class T> struct A {
operator int() {return 0;}
};
-// CHECK: define void @_Z1fv()
+// CHECK-LABEL: define void @_Z1fv()
void f() {
// CHECK: call void @_ZN1AIsEC1Ei
A<short> a4 = 97;
@@ -93,7 +93,7 @@ namespace InitVTable {
B(int);
};
- // CHECK: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr
// CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i8***
// CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]]
// CHECK: [[VTBL:%.*]] = load i32 ([[B]]*)*** {{%.*}}
@@ -106,7 +106,7 @@ namespace InitVTable {
// CHECK-NEXT: ret void
B::B() : A(foo()) {}
- // CHECK: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr
+ // CHECK-LABEL: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr
// CHECK: [[ARG:%.*]] = add nsw i32 {{%.*}}, 5
// CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]])
// CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i8***
@@ -120,7 +120,7 @@ namespace rdar9694300 {
int x;
};
- // CHECK: define void @_ZN11rdar96943001fEv
+ // CHECK-LABEL: define void @_ZN11rdar96943001fEv
void f() {
// CHECK: alloca
X x;
@@ -163,7 +163,7 @@ template<typename T> struct X;
// Make sure that the instantiated constructor initializes start and
// end properly.
-// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr
// CHECK: {{store.*null}}
// CHECK: {{store.*null}}
// CHECK: ret
@@ -200,7 +200,7 @@ namespace PR10720 {
// CHECK-PR10720: ret
pair2 &operator=(pair2&&) = default;
- // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_
+ // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_
// CHECK-PR10720-NOT: ret
// CHECK-PR10720: load
// CHECK-PR10720: icmp ult
@@ -210,7 +210,7 @@ namespace PR10720 {
// CHECK-PR10720: ret void
pair2(pair2&&) = default;
- // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_
+ // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_
// CHECK-PR10720-NOT: ret
// CHECK-PR10720: load
// CHECK-PR10720: icmp ult
@@ -223,7 +223,7 @@ namespace PR10720 {
struct pair : X { // Make the copy constructor non-trivial, so we actually generate it.
int second[4];
- // CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_
+ // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_
// CHECK-PR10720-NOT: ret
// CHECK-PR10720: call void @llvm.memcpy
// CHECK-PR10720-NEXT: ret void
diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp
index fe4687c1b303..0d38d10c1382 100644
--- a/test/CodeGenCXX/constructor-template.cpp
+++ b/test/CodeGenCXX/constructor-template.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
// PR4826
struct A {
diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp
index 9e2da31f046a..f730b9ef491a 100644
--- a/test/CodeGenCXX/constructors.cpp
+++ b/test/CodeGenCXX/constructors.cpp
@@ -21,18 +21,18 @@ struct A {
A::A(struct Undeclared &ref) : mem(0) {}
// Check that delegation works.
-// CHECK: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
// CHECK: call void @_ZN1AC2ER10Undeclared(
-// CHECK: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
// CHECK: call void @_ZN6MemberC1Ei(
A::A(ValueClass v) : mem(v.y - v.x) {}
-// CHECK: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr
// CHECK: call void @_ZN1AC2E10ValueClass(
-// CHECK: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr
// CHECK: call void @_ZN6MemberC1Ei(
@@ -44,10 +44,10 @@ struct B : A {
B::B(struct Undeclared &ref) : A(ref), mem(1) {}
-// CHECK: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
// CHECK: call void @_ZN1BC2ER10Undeclared(
-// CHECK: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
// CHECK: call void @_ZN1AC2ER10Undeclared(
// CHECK: call void @_ZN6MemberC1Ei(
@@ -64,12 +64,12 @@ struct C : virtual A {
};
C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {}
-// CHECK: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
-// CHECK: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr
// CHECK: call void @_ZN6MemberC1Ei(
@@ -83,12 +83,12 @@ struct D : A {
D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {}
-// CHECK: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
+// CHECK-LABEL: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
-// CHECK: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
+// CHECK-LABEL: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
@@ -109,7 +109,7 @@ namespace test1 {
struct A { A(); void *ptr; };
struct B { B(); int x; A a[0]; };
B::B() {}
- // CHECK: define void @_ZN5test11BC2Ev(
+ // CHECK-LABEL: define void @_ZN5test11BC2Ev(
// CHECK: [[THIS:%.*]] = load [[B:%.*]]**
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenCXX/conversion-function.cpp b/test/CodeGenCXX/conversion-function.cpp
index 76d9e027d997..ec098d078d28 100644
--- a/test/CodeGenCXX/conversion-function.cpp
+++ b/test/CodeGenCXX/conversion-function.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
// XFAIL: *
extern "C" int printf(...);
struct S {
diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp
index 425f79de5067..e497acf33dc4 100644
--- a/test/CodeGenCXX/convert-to-fptr.cpp
+++ b/test/CodeGenCXX/convert-to-fptr.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
index 5d09b5430a10..2ffc7bcb7c8d 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-1.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - | \
+// RUN: FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -emit-llvm %s -o - | \
+// RUN: FileCheck %s
extern "C" int printf(...);
@@ -93,11 +93,5 @@ int main() {
dstY.pr();
}
-// CHECK-LP64: .globl __ZN1XaSERKS_
-// CHECK-LP64: .weak_definition __ZN1XaSERKS_
-// CHECK-LP64: __ZN1XaSERKS_:
-
-// CHECK-LP32: .globl __ZN1XaSERKS_
-// CHECK-LP32: .weak_definition __ZN1XaSERKS_
-// CHECK-LP32: __ZN1XaSERKS_:
+// CHECK: define linkonce_odr %struct.X* @_ZN1XaSERKS_
diff --git a/test/CodeGenCXX/copy-assign-synthesis-2.cpp b/test/CodeGenCXX/copy-assign-synthesis-2.cpp
index c25e0467fad5..18e92f98ebde 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-2.cpp
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
struct A {};
A& (A::*x)(const A&) = &A::operator=;
-// CHECK: define linkonce_odr %struct.A* @_ZN1AaSERKS_
+// CHECK-LABEL: define linkonce_odr %struct.A* @_ZN1AaSERKS_
diff --git a/test/CodeGenCXX/copy-assign-synthesis.cpp b/test/CodeGenCXX/copy-assign-synthesis.cpp
index e9fc0c337c10..9c8ae8879540 100644
--- a/test/CodeGenCXX/copy-assign-synthesis.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: grep "_ZN1XaSERK1X" %t | count 0
+// RUN: not grep "_ZN1XaSERK1X" %t
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp
index 4ff877516b09..727af1ba7cd3 100644
--- a/test/CodeGenCXX/copy-constructor-elim-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp
@@ -2,7 +2,7 @@
struct A { int x; A(int); ~A(); };
A f() { return A(0); }
-// CHECK: define void @_Z1fv
+// CHECK-LABEL: define void @_Z1fv
// CHECK: call {{.*}} @_ZN1AC1Ei
// CHECK-NEXT: ret void
@@ -21,7 +21,7 @@ namespace no_elide_base {
Derived(const Other &O);
};
- // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
+ // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
Derived::Derived(const Other &O)
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_
@@ -63,7 +63,7 @@ namespace PR12139 {
static A makeA() { A a; a.value = 2; return a; }
};
- // CHECK: define i32 @_ZN7PR121394testEv
+ // CHECK-LABEL: define i32 @_ZN7PR121394testEv
int test() {
// CHECK: call void @_ZN7PR121391A5makeAEv
// CHECK-NEXT: call %"struct.PR12139::A"* @_ZN7PR121391AC1ERKS0_i
diff --git a/test/CodeGenCXX/copy-constructor-elim.cpp b/test/CodeGenCXX/copy-constructor-elim.cpp
index c883584fe02f..ad3a87b9d5f8 100644
--- a/test/CodeGenCXX/copy-constructor-elim.cpp
+++ b/test/CodeGenCXX/copy-constructor-elim.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: grep "_ZN1CC1ERK1C" %t | count 0
-// RUN: grep "_ZN1SC1ERK1S" %t | count 0
+// RUN: not grep "_ZN1CC1ERK1C" %t
+// RUN: not grep "_ZN1SC1ERK1S" %t
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
index d028a28fdd67..03c66339947d 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
@@ -3,5 +3,5 @@
struct A { virtual void a(); };
A x(A& y) { return y; }
-// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A*) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
index 68f680574b75..c8b265ca2d12 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -21,7 +21,7 @@ struct P {
};
-// CHECK: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr
struct X : M, N, P { // ...
X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd),
au_i1(1234), au1_4("MASKED") {}
@@ -136,7 +136,33 @@ void f(B b1) {
B b2 = b1;
}
-// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr
+// CHECK: define linkonce_odr [[A:%.*]]* @_ZN12rdar138169401AaSERKS0_(
+// CHECK: [[THIS:%.*]] = load [[A]]**
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
+// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16*
+// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]**
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1
+// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16*
+// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8*
+// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false)
+// CHECK-NEXT: ret [[A]]* [[THIS]]
+
+// CHECK-LABEL: define linkonce_odr void @_ZN12rdar138169401AC2ERKS0_(
+// CHECK: [[THIS:%.*]] = load [[A]]**
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i8***
+// CHECK-NEXT: store i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2), i8*** [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
+// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16*
+// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]**
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1
+// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16*
+// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8*
+// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false)
+// CHECK-NEXT: ret void
+
+// CHECK-LABEL: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr
// CHECK: call void @_ZN6PR66281TC1Ev
// CHECK: call void @_ZN6PR66281TC1Ev
// CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_
@@ -154,3 +180,18 @@ void f(B b1) {
// CHECK: call void @_ZN6PR66281TD1Ev
}
+// rdar://13816940
+// Test above because things get weirdly re-ordered.
+namespace rdar13816940 {
+ struct A {
+ virtual ~A();
+ unsigned short a : 1;
+ unsigned short : 15;
+ unsigned other;
+ };
+
+ void test(A &a) {
+ A x = a; // force copy constructor into existence
+ x = a; // also force the copy assignment operator
+ }
+}
diff --git a/test/CodeGenCXX/copy-initialization.cpp b/test/CodeGenCXX/copy-initialization.cpp
index aecd64ec1aac..1a16013a81a9 100644
--- a/test/CodeGenCXX/copy-initialization.cpp
+++ b/test/CodeGenCXX/copy-initialization.cpp
@@ -12,7 +12,7 @@ struct Bar {
void f(Foo);
-// CHECK: define void @_Z1g3Foo(%struct.Foo* %foo)
+// CHECK-LABEL: define void @_Z1g3Foo(%struct.Foo* %foo)
void g(Foo foo) {
// CHECK: call void @_ZN3BarC1Ev
// CHECK: @_ZNK3BarcvRK3FooEv
diff --git a/test/CodeGenCXX/crash.cpp b/test/CodeGenCXX/crash.cpp
new file mode 100644
index 000000000000..073542dd15b0
--- /dev/null
+++ b/test/CodeGenCXX/crash.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
+// CHECK that we don't crash.
+
+// PR11676's example is ill-formed:
+/*
+union _XEvent {
+};
+void ProcessEvent() {
+ _XEvent pluginEvent = _XEvent();
+}
+*/
+
+// Example from PR11665:
+void f() {
+ union U { int field; } u = U();
+ (void)U().field;
+}
+
+namespace PR17476 {
+struct string {
+ string(const char *__s);
+ string &operator+=(const string &__str);
+};
+
+template <class ELFT> void finalizeDefaultAtomValues() {
+ auto startEnd = [&](const char * sym)->void {
+ string start("__");
+ start += sym;
+ }
+ ;
+ startEnd("preinit_array");
+}
+
+void f() { finalizeDefaultAtomValues<int>(); }
+}
diff --git a/test/CodeGenCXX/ctor-dtor-alias.cpp b/test/CodeGenCXX/ctor-dtor-alias.cpp
new file mode 100644
index 000000000000..235d1650dec9
--- /dev/null
+++ b/test/CodeGenCXX/ctor-dtor-alias.cpp
@@ -0,0 +1,163 @@
+// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s
+
+// RUN: %clang_cc1 -cc1 -triple x86_64--netbsd -emit-llvm \
+// RUN: -mconstructor-aliases -O2 %s -o - | FileCheck --check-prefix=CHECK-RAUW %s
+
+namespace test1 {
+// test that we don't produce an alias when the destructor is weak_odr. The
+// reason to avoid it that another TU might have no explicit template
+// instantiation definition or declaration, causing it to to output only
+// one of the destructors as linkonce_odr, producing a different comdat.
+
+// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC2Ev
+// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC1Ev
+
+template <typename T> struct foobar {
+ foobar() {}
+};
+
+template struct foobar<void>;
+}
+
+namespace test2 {
+// test that when the destrucor is linkonce_odr we just replace every use of
+// C1 with C2.
+
+// CHECK-DAG: define linkonce_odr void @_ZN5test26foobarIvEC2Ev(
+// CHECK-DAG: call void @_ZN5test26foobarIvEC2Ev
+void g();
+template <typename T> struct foobar {
+ foobar() { g(); }
+};
+foobar<void> x;
+}
+
+namespace test3 {
+// test that instead of an internal alias we just use the other destructor
+// directly.
+
+// CHECK-DAG: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev(
+// CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev
+namespace {
+struct A {
+ ~A() {}
+};
+
+struct B : public A {};
+}
+
+B x;
+}
+
+namespace test4 {
+ // Test that we don't produce aliases from B to A. We cannot because we cannot
+ // guarantee that they will be present in every TU. Instead, we just call
+ // A's destructor directly.
+
+ // CHECK-DAG: define linkonce_odr void @_ZN5test41AD2Ev(
+ // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev
+
+ // test that we don't do this optimization at -O0 so that the debugger can
+ // see both destructors.
+ // NOOPT-DAG: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev
+ // NOOOPT-DAG: define linkonce_odr void @_ZN5test41BD2Ev
+ struct A {
+ virtual ~A() {}
+ };
+ struct B : public A{
+ ~B() {}
+ };
+ B X;
+}
+
+namespace test5 {
+ // similar to test4, but with an internal B.
+
+ // CHECK-DAG: define linkonce_odr void @_ZN5test51AD2Ev(
+ // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev
+ struct A {
+ virtual ~A() {}
+ };
+ namespace {
+ struct B : public A{
+ ~B() {}
+ };
+ }
+ B X;
+}
+
+namespace test6 {
+ // Test that we use ~A directly, even when ~A is not defined. The symbol for
+ // ~B would have been internal and still contain a reference to ~A.
+ struct A {
+ virtual ~A();
+ };
+ namespace {
+ struct B : public A {
+ ~B() {}
+ };
+ }
+ B X;
+ // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev
+}
+
+namespace test7 {
+ // Test that we don't produce an alias from ~B to ~A<int> (or crash figuring
+ // out if we should).
+ // pr17875.
+ // CHECK-DAG: define void @_ZN5test71BD2Ev
+ template <typename> struct A {
+ ~A() {}
+ };
+ class B : A<int> {
+ ~B();
+ };
+ template class A<int>;
+ B::~B() {}
+}
+
+namespace test8 {
+ // Test that we replace ~zed with ~bar which is an alias to ~foo.
+ // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev
+ // CHECK-DAG: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev
+ struct foo {
+ ~foo();
+ };
+ foo::~foo() {}
+ struct bar : public foo {
+ ~bar();
+ };
+ bar::~bar() {}
+ struct zed : public bar {};
+ zed foo;
+}
+
+// CHECK-RAUW: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}]
+// r194296 replaced C::~C with B::~B without emitting the later.
+
+class A {
+public:
+ A(int);
+ virtual ~A();
+};
+
+template <class>
+class B : A {
+public:
+ B()
+ : A(0) {
+ }
+ __attribute__((always_inline)) ~B() {
+ }
+};
+
+extern template class B<char>;
+
+class C : B<char> {
+};
+
+void
+fn1() {
+ new C;
+}
diff --git a/test/CodeGenCXX/cxx-block-objects.cpp b/test/CodeGenCXX/cxx-block-objects.cpp
index b98906599603..ff868fcdd06f 100644
--- a/test/CodeGenCXX/cxx-block-objects.cpp
+++ b/test/CodeGenCXX/cxx-block-objects.cpp
@@ -25,9 +25,9 @@ main()
return 0;
}
-// CHECK: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @__copy_helper_block_
// CHECK: call void @_ZN1AC1ERKS_
-// CHECK:define internal void @__destroy_helper_block_
+// CHECK-LABEL:define internal void @__destroy_helper_block_
// CHECK: call void @_ZN1AD1Ev
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index e909f0320454..c48e61fd14e0 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -87,7 +87,7 @@ namespace PR14588 {
virtual void squawk() { other(); }
};
- // CHECK: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"*
+ // CHECK-LABEL: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"*
// CHECK: call void @_ZN7PR145883FooC1EPKv(
// CHECK: invoke void @_ZN7PR145885otherEv()
// CHECK: call void @_ZN7PR145883FooD1Ev
diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp
index 3144e941ef42..49bc86fadc78 100644
--- a/test/CodeGenCXX/cxx0x-initializer-array.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp
@@ -6,7 +6,7 @@ struct A { int a[1]; };
typedef A x[];
int f() {
x{{{1}}};
- // CHECK: define i32 @_Z1fv
+ // CHECK-LABEL: define i32 @_Z1fv
// CHECK: store i32 1
// (It's okay if the output changes here, as long as we don't crash.)
return 0;
@@ -33,7 +33,7 @@ namespace ValueInitArrayOfMemPtr {
S1();
};
- // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1fEi
+ // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1fEi
void f(int n) {
Agg1 a = { n };
// CHECK: store i32 -1,
@@ -42,7 +42,7 @@ namespace ValueInitArrayOfMemPtr {
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* bitcast ([3 x i32]* @[[THREE_NULL_MEMPTRS]] to i8*), i32 12, i32 4, i1 false)
}
- // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1gEv
+ // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEv
void g() {
// CHECK: store i32 -1,
f(a{});
@@ -54,7 +54,7 @@ namespace array_dtor {
using T = S[3];
void f(const T &);
void f(T *);
- // CHECK: define void @_ZN10array_dtor1gEv(
+ // CHECK-LABEL: define void @_ZN10array_dtor1gEv(
void g() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
@@ -73,7 +73,7 @@ namespace array_dtor {
// CHECK: ret void
}
- // CHECK: define void @_ZN10array_dtor1hEv(
+ // CHECK-LABEL: define void @_ZN10array_dtor1hEv(
void h() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
@@ -91,7 +91,7 @@ namespace array_dtor {
// CHECK: ret void
}
- // CHECK: define void @_ZN10array_dtor1iEv(
+ // CHECK-LABEL: define void @_ZN10array_dtor1iEv(
void i() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
diff --git a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
index be5b44df1fec..f60536e92094 100644
--- a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
@@ -6,21 +6,21 @@ struct S {
};
void fn1() {
- // CHECK: define void @_Z3fn1v
+ // CHECK-LABEL: define void @_Z3fn1v
S s { 1 };
// CHECK: alloca %struct.S, align 1
// CHECK: call void @_ZN1SC1Ei(%struct.S* %s, i32 1)
}
void fn2() {
- // CHECK: define void @_Z3fn2v
+ // CHECK-LABEL: define void @_Z3fn2v
S s { 1, 2.0, 3.0 };
// CHECK: alloca %struct.S, align 1
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %s, i32 1, double 2.000000e+00, double 3.000000e+00)
}
void fn3() {
- // CHECK: define void @_Z3fn3v
+ // CHECK-LABEL: define void @_Z3fn3v
S sa[] { { 1 }, { 2 }, { 3 } };
// CHECK: alloca [3 x %struct.S], align 1
// CHECK: call void @_ZN1SC1Ei(%struct.S* %{{.+}}, i32 1)
@@ -29,9 +29,25 @@ void fn3() {
}
void fn4() {
- // CHECK: define void @_Z3fn4v
+ // CHECK-LABEL: define void @_Z3fn4v
S sa[] { { 1, 2.0, 3.0 }, { 4, 5.0, 6.0 } };
// CHECK: alloca [2 x %struct.S], align 1
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %{{.+}}, i32 1, double 2.000000e+00, double 3.000000e+00)
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %{{.+}}, i32 4, double 5.000000e+00, double 6.000000e+00)
}
+
+namespace TreeTransformBracedInit {
+ struct S {};
+ struct T { T(const S &); T(const T&); ~T(); };
+ void x(const T &);
+ template<typename> void foo(const S &s) {
+ // Instantiation of this expression used to lose the CXXBindTemporaryExpr
+ // node and thus not destroy the temporary.
+ x({s});
+ }
+ template void foo<void>(const S&);
+ // CHECK: define {{.*}} void @_ZN23TreeTransformBracedInit3fooIvEEvRKNS_1SE(
+ // CHECK: call void @_ZN23TreeTransformBracedInit1TC1ERKNS_1SE(
+ // CHECK-NEXT: call void @_ZN23TreeTransformBracedInit1xERKNS_1TE(
+ // CHECK-NEXT: call void @_ZN23TreeTransformBracedInit1TD1Ev(
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
index 14d2f7729184..091d7b70117c 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
@@ -1,18 +1,28 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-STATIC-BL
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BL
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END | FileCheck %s --check-prefix=CHECK-STATIC-BE
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BE
namespace std {
typedef decltype(sizeof(int)) size_t;
- // libc++'s implementation
template <class _E>
class initializer_list
{
const _E* __begin_;
+#ifdef USE_END
+ const _E* __end_;
+#else
size_t __size_;
+#endif
- initializer_list(const _E* __b, size_t __s)
+ constexpr initializer_list(const _E* __b, size_t __s)
: __begin_(__b),
+#ifdef USE_END
+ __end_(__b + __s)
+#else
__size_(__s)
+#endif
{}
public:
@@ -24,14 +34,99 @@ namespace std {
typedef const _E* iterator;
typedef const _E* const_iterator;
- initializer_list() : __begin_(nullptr), __size_(0) {}
+#ifdef USE_END
+ constexpr initializer_list() : __begin_(nullptr), __end_(nullptr) {}
+
+ size_t size() const {return __end_ - __begin_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __end_;}
+#else
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
size_t size() const {return __size_;}
const _E* begin() const {return __begin_;}
const _E* end() const {return __begin_ + __size_;}
+#endif
};
}
-std::initializer_list<std::initializer_list<int>> pleasefail = {
- {1, 2}, {3, 4}, {5, 6} // expected-error {{cannot compile}}
+constexpr int a = 2, b = 4, c = 6;
+std::initializer_list<std::initializer_list<int>> nested = {
+ {1, a}, {3, b}, {5, c}
};
+
+// CHECK-STATIC-BL: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4
+// CHECK-STATIC-BL: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4
+// CHECK-STATIC-BL: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4
+// CHECK-STATIC-BL: @_ZGR6nested3 = private constant [3 x {{.*}}] [
+// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0), i64 2 },
+// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0), i64 2 },
+// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0), i64 2 }
+// CHECK-STATIC-BL: ], align 8
+// CHECK-STATIC-BL: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0), i64 3 }, align 8
+
+// CHECK-DYNAMIC-BL: @nested = global
+// CHECK-DYNAMIC-BL: @_ZGR6nested = private global [3 x
+// CHECK-DYNAMIC-BL: @_ZGR6nested1 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BL: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BL: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BL: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
+// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
+// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
+// CHECK-DYMAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
+// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
+// CHECK-DYNAMIC-BL: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
+// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
+// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
+// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
+// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
+// CHECK-DYNAMIC-BL: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
+// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
+// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
+// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
+// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8
+// CHECK-DYNAMIC-BL: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0),
+// CHECK-DYNAMIC-BL: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8
+// CHECK-DYNAMIC-BL: store i64 3, i64* getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8
+
+// CHECK-STATIC-BE: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4
+// CHECK-STATIC-BE: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4
+// CHECK-STATIC-BE: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4
+// CHECK-STATIC-BE: @_ZGR6nested3 = private constant [3 x {{.*}}] [
+// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0),
+// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested to i8*), i64 8) to i32*) }
+// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0),
+// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested1 to i8*), i64 8) to i32*) }
+// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0),
+// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested2 to i8*), i64 8) to i32*) }
+// CHECK-STATIC-BE: ], align 8
+// CHECK-STATIC-BE: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0),
+// CHECK-STATIC-BE: {{.*}} bitcast ({{.*}}* getelementptr (i8* bitcast ([3 x {{.*}}]* @_ZGR6nested3 to i8*), i64 48) to {{.*}}*) }
+
+// CHECK-DYNAMIC-BE: @nested = global
+// CHECK-DYNAMIC-BE: @_ZGR6nested = private global [3 x
+// CHECK-DYNAMIC-BE: @_ZGR6nested1 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BE: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BE: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
+// CHECK-DYNAMIC-BE: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
+// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
+// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 1, i64 0),
+// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
+// CHECK-DYNAMIC-BE: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
+// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
+// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 1, i64 0),
+// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
+// CHECK-DYNAMIC-BE: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
+// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
+// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
+// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 1, i64 0),
+// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8
+// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0),
+// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8
+// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 1, i64 0),
+// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
index 209ee6513855..8e0d161bc0f4 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
@@ -32,12 +32,12 @@ namespace std {
};
}
-// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
-// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, {{[^)]*}}), i32*
+// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, {{[^)]*}}), i32*
std::initializer_list<int> globalInitList1 = {1, 2, 3};
void fn1(int i) {
- // CHECK: define void @_Z3fn1i
+ // CHECK-LABEL: define void @_Z3fn1i
// temporary array
// CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
// CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
@@ -66,7 +66,7 @@ struct destroyme2 {
void fn2() {
- // CHECK: define void @_Z3fn2v
+ // CHECK-LABEL: define void @_Z3fn2v
void target(std::initializer_list<destroyme1>);
// objects should be destroyed before dm2, after call returns
target({ destroyme1(), destroyme1() });
@@ -76,7 +76,7 @@ void fn2() {
}
void fn3() {
- // CHECK: define void @_Z3fn3v
+ // CHECK-LABEL: define void @_Z3fn3v
// objects should be destroyed after dm2
auto list = { destroyme1(), destroyme1() };
destroyme2 dm2;
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index d683493a83d8..164cbce027ef 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -47,23 +47,48 @@ struct wantslist1 {
~wantslist1();
};
-// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
-// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 }
+// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, i32 0, i32 0), i{{32|64}} 3 }
std::initializer_list<int> globalInitList1 = {1, 2, 3};
namespace thread_local_global_array {
- // CHECK: @_ZN25thread_local_global_arrayL11x__initlistE = internal thread_local global [4 x i32] [i32 1, i32 2, i32 3, i32 4]
- // CHECK: @_ZN25thread_local_global_array1xE = thread_local global {{.*}} @_ZN25thread_local_global_arrayL11x__initlistE, {{.*}} i64 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).
+ //
+ // CHECK: @_ZN25thread_local_global_array1xE = thread_local global
+ // CHECK: @_ZGRN25thread_local_global_array1xE = private 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: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer
-// CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x
+// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
+// CHECK: @_ZGR15globalInitList2 = private 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.*]] = private global {{.*}} zeroinitializer, align 8
+// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = private global [3 x {{.*}}] zeroinitializer, align 8
+// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = private global [2 x i32] zeroinitializer, align 4
+// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = private constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
+
// CHECK: appending global
-// CHECK: define internal void
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 0
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 1
+
+
+// thread_local initializer:
+// CHECK-LABEL: define internal void
+// CHECK: store i32* getelementptr inbounds ([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]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 0
+// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 1
// CHECK: __cxa_atexit
+// CHECK: store %[[WITHARG]]* getelementptr inbounds ([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
// CHECK: call void @_ZN10destroyme1D1Ev
std::initializer_list<witharg1> globalInitList2 = {
@@ -71,7 +96,7 @@ std::initializer_list<witharg1> globalInitList2 = {
};
void fn1(int i) {
- // CHECK: define void @_Z3fn1i
+ // CHECK-LABEL: define void @_Z3fn1i
// temporary array
// CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
// CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
@@ -91,7 +116,7 @@ void fn1(int i) {
}
void fn2() {
- // CHECK: define void @_Z3fn2v
+ // CHECK-LABEL: define void @_Z3fn2v
void target(std::initializer_list<destroyme1>);
// objects should be destroyed before dm2, after call returns
// CHECK: call void @_Z6targetSt16initializer_listI10destroyme1E
@@ -102,7 +127,7 @@ void fn2() {
}
void fn3() {
- // CHECK: define void @_Z3fn3v
+ // CHECK-LABEL: define void @_Z3fn3v
// objects should be destroyed after dm2
auto list = { destroyme1(), destroyme1() };
destroyme2 dm2;
@@ -111,7 +136,7 @@ void fn3() {
}
void fn4() {
- // CHECK: define void @_Z3fn4v
+ // CHECK-LABEL: define void @_Z3fn4v
void target(std::initializer_list<witharg1>);
// objects should be destroyed before dm2, after call returns
// CHECK: call void @_ZN8witharg1C1ERK10destroyme1
@@ -124,7 +149,7 @@ void fn4() {
}
void fn5() {
- // CHECK: define void @_Z3fn5v
+ // CHECK-LABEL: define void @_Z3fn5v
// temps should be destroyed before dm2
// objects should be destroyed after dm2
// CHECK: call void @_ZN8witharg1C1ERK10destroyme1
@@ -136,7 +161,7 @@ void fn5() {
}
void fn6() {
- // CHECK: define void @_Z3fn6v
+ // CHECK-LABEL: define void @_Z3fn6v
void target(const wantslist1&);
// objects should be destroyed before dm2, after call returns
// CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
@@ -149,7 +174,7 @@ void fn6() {
}
void fn7() {
- // CHECK: define void @_Z3fn7v
+ // CHECK-LABEL: define void @_Z3fn7v
// temps should be destroyed before dm2
// object should be destroyed after dm2
// CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
@@ -161,7 +186,7 @@ void fn7() {
}
void fn8() {
- // CHECK: define void @_Z3fn8v
+ // CHECK-LABEL: define void @_Z3fn8v
void target(std::initializer_list<std::initializer_list<destroyme1>>);
// objects should be destroyed before dm2, after call returns
// CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE
@@ -175,7 +200,7 @@ void fn8() {
}
void fn9() {
- // CHECK: define void @_Z3fn9v
+ // CHECK-LABEL: define void @_Z3fn9v
// objects should be destroyed after dm2
std::initializer_list<destroyme1> inner;
std::initializer_list<std::initializer_list<destroyme1>> list =
@@ -193,7 +218,7 @@ struct haslist1 {
haslist1();
};
-// CHECK: define void @_ZN8haslist1C2Ev
+// CHECK-LABEL: define void @_ZN8haslist1C2Ev
haslist1::haslist1()
// CHECK: alloca [3 x i32]
// CHECK: store i32 1
@@ -210,7 +235,7 @@ struct haslist2 {
haslist2();
};
-// CHECK: define void @_ZN8haslist2C2Ev
+// CHECK-LABEL: define void @_ZN8haslist2C2Ev
haslist2::haslist2()
: il{destroyme1(), destroyme1()}
{
@@ -220,7 +245,7 @@ haslist2::haslist2()
}
void fn10() {
- // CHECK: define void @_Z4fn10v
+ // CHECK-LABEL: define void @_Z4fn10v
// CHECK: alloca [3 x i32]
// CHECK: call noalias i8* @_Znw{{[jm]}}
// CHECK: store i32 1
@@ -232,7 +257,7 @@ void fn10() {
}
void fn11() {
- // CHECK: define void @_Z4fn11v
+ // CHECK-LABEL: define void @_Z4fn11v
(void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()};
// CHECK: call void @_ZN10destroyme1D1Ev
destroyme2 dm2;
@@ -260,7 +285,7 @@ namespace PR12178 {
namespace rdar13325066 {
struct X { ~X(); };
- // CHECK: define void @_ZN12rdar133250664loopERNS_1XES1_
+ // CHECK-LABEL: define void @_ZN12rdar133250664loopERNS_1XES1_
void loop(X &x1, X &x2) {
// CHECK: br label
// CHECK: br i1
@@ -275,3 +300,134 @@ namespace rdar13325066 {
for (X x : { x1, x2 }) { }
}
}
+
+namespace dtors {
+ struct S {
+ S();
+ ~S();
+ };
+ void z();
+
+ // CHECK-LABEL: define void @_ZN5dtors1fEv(
+ void f() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ std::initializer_list<S>{ S(), S() };
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
+ }
+
+ // CHECK-LABEL: define void @_ZN5dtors1gEv(
+ void g() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ auto x = std::initializer_list<S>{ S(), S() };
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
+ }
+
+ // CHECK-LABEL: define void @_ZN5dtors1hEv(
+ void h() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ // CHECK: call void @_ZN5dtors1SC1Ev(
+ std::initializer_list<S> x = { S(), S() };
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
+ }
+}
+
+namespace partly_constant {
+ int k;
+ 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-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* @_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)
+ //
+ // 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-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)
+ //
+ // 'il' reference.
+ // CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8
+}
+
+namespace nested {
+ struct A { A(); ~A(); };
+ struct B { const A &a; ~B(); };
+ struct C { std::initializer_list<B> b; ~C(); };
+ void f();
+ // CHECK-LABEL: define void @_ZN6nested1gEv(
+ void g() {
+ // CHECK: call void @_ZN6nested1AC1Ev(
+ // CHECK-NOT: call
+ // CHECK: call void @_ZN6nested1AC1Ev(
+ // CHECK-NOT: call
+ const C &c { { { A() }, { A() } } };
+
+ // CHECK: call void @_ZN6nested1fEv(
+ // CHECK-NOT: call
+ f();
+
+ // CHECK: call void @_ZN6nested1CD1Ev(
+ // CHECK-NOT: call
+
+ // Destroy B[2] array.
+ // FIXME: This isn't technically correct: reverse construction order would
+ // destroy the second B then the second A then the first B then the first A.
+ // CHECK: call void @_ZN6nested1BD1Ev(
+ // CHECK-NOT: call
+ // CHECK: br
+
+ // CHECK-NOT: call
+ // CHECK: call void @_ZN6nested1AD1Ev(
+ // CHECK-NOT: call
+ // CHECK: call void @_ZN6nested1AD1Ev(
+ // CHECK-NOT: call
+ // CHECK: }
+ }
+}
diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp
index 49ca8610f28f..96ea1d7f00ed 100644
--- a/test/CodeGenCXX/cxx11-exception-spec.cpp
+++ b/test/CodeGenCXX/cxx11-exception-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s
+// RUN: not %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s
void h();
diff --git a/test/CodeGenCXX/cxx11-initializer-array-new.cpp b/test/CodeGenCXX/cxx11-initializer-array-new.cpp
new file mode 100644
index 000000000000..23577bec661a
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-initializer-array-new.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -emit-llvm -o - | FileCheck %s
+
+// PR10878
+
+struct S { S(); S(int); ~S(); int n; };
+
+void *p = new S[2][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
+
+// CHECK-LABEL: define
+// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 32)
+// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
+// CHECK: store i64 6, i64* %[[COOKIE]]
+// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
+// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S:.*]]*
+//
+// Explicit initializers:
+//
+// { 1, 2, 3 }
+//
+// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
+//
+// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
+// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
+// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
+//
+// { 4, 5, 6 }
+//
+// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
+//
+// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
+// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
+// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
+//
+// CHECK-NOT: br i1
+// CHECK-NOT: call
+// CHECK: }
+
+int n;
+void *q = new S[n][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
+
+// CHECK-LABEL: define
+//
+// CHECK: load i32* @n
+// CHECK: call {{.*}} @llvm.umul.with.overflow.i64(i64 %[[N:.*]], i64 12)
+// CHECK: %[[ELTS:.*]] = mul i64 %[[N]], 3
+// CHECK: call {{.*}} @llvm.uadd.with.overflow.i64(i64 %{{.*}}, i64 8)
+// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 %{{.*}})
+//
+// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
+// CHECK: store i64 %[[ELTS]], i64* %[[COOKIE]]
+// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
+// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S]]*
+// CHECK: %[[END_AS_S:.*]] = getelementptr inbounds %[[S]]* %[[START_AS_S]], i64 %[[ELTS]]
+//
+// Explicit initializers:
+//
+// { 1, 2, 3 }
+//
+// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
+//
+// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
+// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
+// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
+//
+// { 4, 5, 6 }
+//
+// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
+//
+// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
+// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
+// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
+//
+// CHECK: %[[S_2:.*]] = getelementptr [3 x %[[S]]]* %[[S_1]], i32 1
+// CHECK: %[[S_2_AS_S:.*]] = bitcast [3 x %[[S]]]* %[[S_2]] to %[[S]]*
+// CHECK: icmp eq %[[S]]* %[[S_2_AS_S]], %[[END_AS_S]]
+// CHECK: br i1
+//
+// S[n-2][3] initialization loop:
+//
+// CHECK: %[[END_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 3
+// CHECK: br label
+//
+// S[3] initialization loop:
+//
+// CHECK: call void @_ZN1SC1Ev(%[[S]]*
+// CHECK: %[[NEXT_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 1
+// CHECK: icmp eq %[[S]]* %[[NEXT_INNER]], %[[END_INNER]]
+// CHECK: br i1
+//
+// CHECK: %[[NEXT_OUTER:.*]] = getelementptr %[[S]]* %{{.*}}, i32 1
+// CHECK: icmp eq %[[S]]* %[[NEXT_OUTER]], %[[END_AS_S]]
+// CHECK: br i1
+//
+// CHECK: }
diff --git a/test/CodeGenCXX/cxx11-thread-local-reference.cpp b/test/CodeGenCXX/cxx11-thread-local-reference.cpp
index 2ea9acda4815..7759d41b0f92 100644
--- a/test/CodeGenCXX/cxx11-thread-local-reference.cpp
+++ b/test/CodeGenCXX/cxx11-thread-local-reference.cpp
@@ -13,7 +13,7 @@ int &g() { return r; }
// CHECK: call i32* @_Z1fv()
// CHECK: store i32* %{{.*}}, i32** @r, align 8
-// CHECK: define i32* @_Z1gv()
+// CHECK-LABEL: define i32* @_Z1gv()
// CHECK: call i32* @_ZTW1r()
// CHECK: ret i32* %{{.*}}
@@ -22,5 +22,5 @@ int &g() { return r; }
// CHECK: load i32** @r, align 8
// CHECK: ret i32* %{{.*}}
-// CHECK: define internal void @__tls_init()
+// CHECK-LABEL: define internal void @__tls_init()
// CHECK: call void @[[R_INIT]]()
diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp
index a7141d133bbe..509562dd8fc1 100644
--- a/test/CodeGenCXX/cxx11-thread-local.cpp
+++ b/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -35,7 +35,7 @@ int e = V<int>::m;
// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global
// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
-// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global
+// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global
// CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0
@@ -55,7 +55,7 @@ int e = V<int>::m;
// CHECK: call i32 @_Z1fv()
// CHECK-NEXT: store i32 {{.*}}, i32* @a, align 4
-// CHECK: define i32 @_Z1fv()
+// CHECK-LABEL: define i32 @_Z1fv()
int f() {
// CHECK: %[[GUARD:.*]] = load i8* @_ZGVZ1fvE1n, align 1
// CHECK: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD]], 0
@@ -76,7 +76,7 @@ int f() {
// CHECK-NEXT: load i32* %{{.*}}, align 4
// CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4
-// CHECK: define weak_odr hidden i32* @_ZTW1b()
+// CHECK-LABEL: define weak_odr hidden i32* @_ZTW1b()
// CHECK: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
// not null:
// CHECK: call void @_ZTH1b()
@@ -97,7 +97,7 @@ int f() {
// CHECK-NEXT: load i32* %{{.*}}, align 4
// CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4
-// CHECK: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
+// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
// CHECK: call void @_ZTHN1VIiE1mE()
// CHECK: ret i32* @_ZN1VIiE1mE
@@ -105,7 +105,7 @@ int f() {
struct S { S(); ~S(); };
struct T { ~T(); };
-// CHECK: define void @_Z8tls_dtorv()
+// CHECK-LABEL: define void @_Z8tls_dtorv()
void tls_dtor() {
// CHECK: load i8* @_ZGVZ8tls_dtorvE1s
// CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZZ8tls_dtorvE1s)
@@ -128,6 +128,13 @@ void tls_dtor() {
// CHECK: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
+// CHECK: define {{.*}} @_Z7PR15991v(
+int PR15991() {
+ thread_local int n;
+ auto l = [] { return n; };
+ return l();
+}
+
// CHECK: define {{.*}} @[[V_M_INIT:.*]]()
// CHECK: load i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
// CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0
@@ -164,10 +171,10 @@ void tls_dtor() {
// CHECK: declare extern_weak void @_ZTH1b()
-// CHECK: define internal hidden i32* @_ZTWL1d()
+// CHECK-LABEL: define internal hidden i32* @_ZTWL1d()
// CHECK: call void @_ZTHL1d()
// CHECK: ret i32* @_ZL1d
-// CHECK: define weak_odr hidden i32* @_ZTWN1U1mE()
+// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
// CHECK: call void @_ZTHN1U1mE()
// CHECK: ret i32* @_ZN1U1mE
diff --git a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
new file mode 100644
index 000000000000..6d15a2246df0
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @x = global {{.*}} zeroinitializer
+
+// CHECK: define {{.*}} @_Z1fv
+inline auto f() {
+ int n = 0;
+ // CHECK: load i32
+ // CHECK: store i32
+ // CHECK: ret
+ return [=] () mutable { return ++n; };
+}
+
+auto x = f();
+
+template<typename T> auto *g(T t) { return t; }
+template<typename T> decltype(auto) h(T t) { return t; }
+
+// CHECK: define {{.*}} @_Z1zv
+void z() {
+ // CHECK: call {{.*}} @_Z1gIPZ1fvEUlvE_EPDaT_(
+ // CHECK: call {{.*}} @_Z1hIPZ1fvEUlvE_EDcT_(
+ g(&x);
+ h(&x);
+}
+
+auto i() { return [] {}; }
+// CHECK: define {{.*}} @_Z1jv
+auto j() {
+ // CHECK: call {{.*}} @"_Z1hIZ1ivE3$_0EDcT_"()
+ h(i());
+}
diff --git a/test/CodeGenCXX/cxx1y-init-captures.cpp b/test/CodeGenCXX/cxx1y-init-captures.cpp
new file mode 100644
index 000000000000..a60269f3b185
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-init-captures.cpp
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct S {
+ S();
+ S(S &&);
+ ~S();
+};
+
+void f() {
+ (void) [s(S{})] {};
+}
+
+// CHECK-LABEL: define void @_Z1fv(
+// CHECK: call void @_ZN1SC1Ev(
+// CHECK: call void @"_ZZ1fvEN3$_0D1Ev"(
+
+// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D1Ev"(
+// CHECK: @"_ZZ1fvEN3$_0D2Ev"(
+
+// D2 at end of file.
+
+void g() {
+ [a(1), b(2)] { return a + b; } ();
+}
+
+// CHECK-LABEL: define void @_Z1gv(
+// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0
+// CHECK: store i32 1, i32*
+// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1
+// CHECK: store i32 2, i32*
+// CHECK: call i32 @"_ZZ1gvENK3$_1clEv"(
+
+// CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_1clEv"(
+// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0
+// CHECK: load i32*
+// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1
+// CHECK: load i32*
+// CHECK: add nsw i32
+
+int h(int a) {
+ // CHECK-LABEL: define i32 @_Z1hi(
+ // CHECK: %[[A_ADDR:.*]] = alloca i32,
+ // CHECK: %[[OUTER:.*]] = alloca
+ // CHECK: store i32 {{.*}}, i32* %[[A_ADDR]],
+ //
+ // Initialize init-capture 'b(a)' by reference.
+ // CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0
+ // CHECK: store i32* %[[A_ADDR]], i32** {{.*}},
+ //
+ // Initialize init-capture 'c(a)' by copy.
+ // CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1
+ // CHECK: load i32* %[[A_ADDR]],
+ // CHECK: store i32
+ //
+ // CHECK: call i32 @"_ZZ1hiENK3$_2clEv"({{.*}}* %[[OUTER]])
+ return [&b(a), c(a)] {
+ // CHECK-LABEL: define internal i32 @"_ZZ1hiENK3$_2clEv"(
+ // CHECK: %[[OUTER_ADDR:.*]] = alloca
+ // CHECK: %[[INNER:.*]] = alloca
+ // CHECK: store {{.*}}, {{.*}}** %[[OUTER_ADDR]],
+ //
+ // Capture outer 'c' by reference.
+ // CHECK: %[[OUTER:.*]] = load {{.*}}** %[[OUTER_ADDR]]
+ // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0
+ // CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1
+ // CHECK-NEXT: store i32* %
+ //
+ // Capture outer 'b' by copy.
+ // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1
+ // CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0
+ // CHECK-NEXT: load i32** %
+ // CHECK-NEXT: load i32* %
+ // CHECK-NEXT: store i32
+ //
+ // CHECK: call i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"({{.*}}* %[[INNER]])
+ return [=, &c] {
+ // CHECK-LABEL: define internal i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"(
+ // CHECK: %[[INNER_ADDR:.*]] = alloca
+ // CHECK: store {{.*}}, {{.*}}** %[[INNER_ADDR]],
+ // CHECK: %[[INNER:.*]] = load {{.*}}** %[[INNER_ADDR]]
+ //
+ // Load capture of 'b'
+ // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1
+ // CHECK: load i32* %
+ //
+ // Load capture of 'c'
+ // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0
+ // CHECK: load i32** %
+ // CHECK: load i32* %
+ //
+ // CHECK: add nsw i32
+ return b + c;
+ } ();
+ } ();
+}
+
+// Ensure we can emit code for init-captures in global lambdas too.
+auto global_lambda = [a = 0] () mutable { return ++a; };
+int get_incremented() { return global_lambda(); }
+
+// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D2Ev"(
+// CHECK: call void @_ZN1SD1Ev(
diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
index ef78c434e35e..ae49a047f624 100644
--- a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
+++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
@@ -25,7 +25,11 @@ A b { 4, "bazquux", .x = 42, .c = 9 };
A c { 1, 0, 'A', f(), { 3 } };
// CHECK: @[[STR_A:.*]] = {{.*}} [7 x i8] c"foobar\00"
+// CHECK: @a = global {{.*}} zeroinitializer
+
+// @b has a constant initializer
// CHECK: @[[STR_B:.*]] = {{.*}} [8 x i8] c"bazquux\00"
+// CHECK: @b = global {{.*}} i32 4, {{.*}} @[[STR_B]], {{.*}} i8 117, i32 42, {{.*}} i8 9
B x;
B y {};
@@ -44,18 +48,9 @@ B z { 1 };
// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3)
// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4))
-// Initialization of 'b':
+// No dynamic initialization of 'b':
-// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0)
-// CHECK: store i8* {{.*}} @[[STR_B]]{{.*}}, i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1)
-// CHECK: load i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0)
-// CHECK: load i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1)
-// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}}
-// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @b, i32 0, i32 2)
-// CHECK-NOT: @_ZN1A1fEv
-// CHECK: store i32 42, i32* getelementptr inbounds ({{.*}}* @b, i32 0, i32 3)
-// CHECK-NOT: C1Ev
-// CHECK: store i8 9, i8* {{.*}} @b, i32 0, i32 4)
+// CHECK-NOT: @b
// Initialization of 'c':
diff --git a/test/CodeGenCXX/cxx1y-sized-deallocation.cpp b/test/CodeGenCXX/cxx1y-sized-deallocation.cpp
new file mode 100644
index 000000000000..7fd3ece3e02c
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-sized-deallocation.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -std=c++1y %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED
+
+// CHECK-UNSIZED-NOT: _ZdlPvm
+// CHECK-UNSIZED-NOT: _ZdaPvm
+
+typedef decltype(sizeof(0)) size_t;
+
+typedef int A;
+struct B { int n; };
+struct C { ~C() {} };
+struct D { D(); virtual ~D() {} };
+struct E {
+ void *operator new(size_t);
+ void *operator new[](size_t);
+ void operator delete(void *) noexcept;
+ void operator delete[](void *) noexcept;
+};
+struct F {
+ void *operator new(size_t);
+ void *operator new[](size_t);
+ void operator delete(void *, size_t) noexcept;
+ void operator delete[](void *, size_t) noexcept;
+};
+
+template<typename T> T get();
+
+template<typename T>
+void del() {
+ ::delete get<T*>();
+ ::delete[] get<T*>();
+ delete get<T*>();
+ delete[] get<T*>();
+}
+
+template void del<A>();
+template void del<B>();
+template void del<C>();
+template void del<D>();
+template void del<E>();
+template void del<F>();
+
+D::D() {}
+
+// CHECK-LABEL: define weak_odr void @_Z3delIiEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+//
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define linkonce void @_ZdlPvm(i8*
+// CHECK: call void @_ZdlPv(i8* %0)
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1BEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+//
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1CEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+//
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+// CHECK-LABEL: define linkonce void @_ZdaPvm(i8*
+// CHECK: call void @_ZdaPv(i8* %0)
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1DEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
+// CHECK: mul i64 8, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+//
+// CHECK-NOT: Zdl
+// CHECK: call void %{{.*}}
+// CHECK-NOT: Zdl
+// CHECK: mul i64 8, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1EEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+//
+// CHECK: call void @_ZN1EdlEPv(i8* %{{[^ ]*}})
+// CHECK: call void @_ZN1EdaEPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1FEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+//
+// CHECK: call void @_ZN1FdlEPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZN1FdaEPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+
+// CHECK-LABEL: define linkonce_odr void @_ZN1DD0Ev(%{{[^ ]*}}* %this)
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
diff --git a/test/CodeGenCXX/cxx1y-variable-template.cpp b/test/CodeGenCXX/cxx1y-variable-template.cpp
new file mode 100644
index 000000000000..d1e70603e280
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-variable-template.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Check that we keep the 'extern' when we instantiate the definition of this
+// variable template specialization.
+template<typename T> extern const int extern_redecl;
+template<typename T> const int extern_redecl = 5;
+template const int extern_redecl<int>;
+
+// CHECK: @_Z13extern_redeclIiE = weak_odr constant
+
+template<typename T> struct Outer {
+ template<typename U> struct Inner {
+ template<typename V> static int arr[];
+ };
+};
+Outer<char[100]> outer_int;
+int init_arr();
+template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
+int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
+
+// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global [123 x i32] zeroinitializer
+// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global
+
+// CHECK: call {{.*}}@_Z8init_arrv
diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp
index ff0f6638f615..84f496f54c37 100644
--- a/test/CodeGenCXX/debug-info-artificial-arg.cpp
+++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp
@@ -22,8 +22,8 @@ int main(int argc, char **argv) {
A reallyA (500);
}
-// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from A]
-// CHECK: ![[CLASSTYPE:.*]] = {{.*}} ; [ DW_TAG_class_type ] [A]
-// CHECK: metadata ![[CLASSTYPE]], {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A]
-// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: ![[CLASSTYPE:.*]] = {{.*}}, metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
+// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A]
+// CHECK: metadata !"_ZTS1A", {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A]
+// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
// CHECK: [[FUNCTYPE]] = metadata !{null, metadata ![[ARTARG]], metadata !{{.*}}, metadata !{{.*}}}
diff --git a/test/CodeGenCXX/debug-info-class-limited.cpp b/test/CodeGenCXX/debug-info-class-limited.cpp
new file mode 100644
index 000000000000..a4b9f46ec653
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-class-limited.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+
+namespace PR16214_1 {
+// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
+struct foo {
+ int i;
+};
+
+typedef foo bar;
+
+bar *a;
+bar b;
+}
+
+namespace PR14467 {
+// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
+struct foo {
+};
+
+foo *bar(foo *a) {
+ foo *b = new foo(*a);
+ return b;
+}
+}
+
+namespace test1 {
+// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [decl]
+struct foo {
+};
+
+extern int bar(foo *a);
+int baz(foo *a) {
+ return bar(a);
+}
+}
+
+namespace test2 {
+// FIXME: if we were a bit fancier, we could realize that the 'foo' type is only
+// required because of the 'bar' type which is not required at all (or might
+// only be required to be declared)
+// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
+struct foo {
+};
+
+struct bar {
+ foo f;
+};
+
+void func() {
+ foo *f;
+}
+}
diff --git a/test/CodeGenCXX/debug-info-class-nolimit.cpp b/test/CodeGenCXX/debug-info-class-nolimit.cpp
new file mode 100644
index 000000000000..ce72bd347cab
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-class-nolimit.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -fno-limit-debug-info -o - -emit-llvm -g %s | FileCheck %s
+
+namespace rdar14101097_1 { // see also PR16214
+// Check that we emit debug info for the definition of a struct if the
+// definition is available, even if it's used via a pointer wrapped in a
+// typedef.
+// CHECK: [ DW_TAG_structure_type ] [foo] {{.*}}[def]
+struct foo {
+};
+
+typedef foo *foop;
+
+void bar() {
+ foop f;
+}
+}
+
+namespace rdar14101097_2 {
+// As above, except trickier because we first encounter only a declaration of
+// the type and no debug-info related use after we see the definition of the
+// type.
+// CHECK: [ DW_TAG_structure_type ] [foo] {{.*}}[def]
+struct foo;
+void bar() {
+ foo *f;
+}
+struct foo {
+};
+}
+
diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp
index df2492603e36..e1402c96f043 100644
--- a/test/CodeGenCXX/debug-info-class.cpp
+++ b/test/CodeGenCXX/debug-info-class.cpp
@@ -12,6 +12,51 @@ class B {
public:
virtual ~B();
};
+
+B::~B() {
+}
+
+struct C {
+ static int s;
+ virtual ~C();
+};
+
+C::~C() {
+}
+
+struct D {
+ D();
+ virtual ~D();
+ void func() {
+ }
+};
+
+struct E {
+ E();
+ virtual ~E();
+ virtual void func() {
+ }
+};
+
+struct F {
+ struct inner {
+ };
+ static const int i = 2;
+ virtual ~F();
+};
+
+struct G {
+ virtual void func();
+ struct inner {
+ int j;
+ };
+};
+
+struct H {};
+struct I : virtual H {};
+struct J : I {};
+J j;
+
struct A {
int one;
static const int HdrSize = 52;
@@ -21,9 +66,17 @@ struct A {
}
};
+void f1() {
+ D x;
+ x.func();
+ E y;
+ int i = F::i;
+ F::inner z;
+}
int main(int argc, char **argv) {
B b;
+ G::inner c_i;
if (argc) {
A a;
}
@@ -40,9 +93,33 @@ int main(int argc, char **argv) {
// CHECK: DW_TAG_structure_type ] [foo]
// CHECK: DW_TAG_class_type ] [bar]
// CHECK: DW_TAG_union_type ] [baz]
-// CHECK: DW_TAG_structure_type ] [A]
-// CHECK: HdrSize
-// CHECK: DW_TAG_class_type ] [B]
+// CHECK: DW_TAG_class_type ] [B] {{.*}} [def]
// CHECK: metadata !"_vptr$B", {{.*}}, i32 64, metadata !{{.*}}} ; [ DW_TAG_member ]
-// CHECK: ![[EXCEPTLOC]] = metadata !{i32 31,
-// CHECK: ![[RETLOC]] = metadata !{i32 30,
+
+// CHECK: [[C:![0-9]*]] = {{.*}} metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS1C", null, metadata !"_ZTS1C"} ; [ DW_TAG_structure_type ] [C] {{.*}} [def]
+// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_S:![0-9]*]], metadata [[C_DTOR:![0-9]*]]}
+// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$C] {{.*}} [artificial]
+// CHECK: [[C_S]] = {{.*}} ; [ DW_TAG_member ] [s] {{.*}} [static] [from int]
+// CHECK: [[C_DTOR]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [~C]
+
+// CHECK: metadata [[D_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS1D"} ; [ DW_TAG_structure_type ] [D] {{.*}} [decl]
+// CHECK: [[D_MEM]] = metadata !{metadata [[D_FUNC:![0-9]*]]}
+// CHECK: [[D_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]
+// CHECK: null, i32 0, null, null, metadata !"_ZTS1E"} ; [ DW_TAG_structure_type ] [E] {{.*}} [decl]
+// CHECK: [[F:![0-9]*]] = {{.*}} metadata [[F_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS1F"} ; [ DW_TAG_structure_type ] [F] {{.*}} [decl]
+// CHECK: [[F_MEM]] = metadata !{metadata [[F_I:![0-9]*]]}
+// CHECK: [[F_I]] = {{.*}} ; [ DW_TAG_member ] [i]
+
+// CHECK: null, i32 0, null, null, metadata !"_ZTS1G"} ; [ DW_TAG_structure_type ] [G] {{.*}} [decl]
+// CHECK: metadata [[G_INNER_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN1G5innerE"} ; [ DW_TAG_structure_type ] [inner] [line 50, {{.*}} [def]
+// CHECK: [[G_INNER_MEM]] = metadata !{metadata [[G_INNER_I:![0-9]*]]}
+// CHECK: [[G_INNER_I]] = {{.*}} ; [ DW_TAG_member ] [j] {{.*}} [from int]
+
+// CHECK: ; [ DW_TAG_structure_type ] [A]
+// CHECK: HdrSize
+// CHECK: ; [ DW_TAG_structure_type ] [I] {{.*}} [def]
+
+// CHECK: [[F_I_DEF:![0-9]*]] = {{.*}}, metadata [[F_I]]} ; [ DW_TAG_variable ] [i]
+
+// CHECK: ![[EXCEPTLOC]] = metadata !{i32 84,
+// CHECK: ![[RETLOC]] = metadata !{i32 83,
diff --git a/test/CodeGenCXX/debug-info-cxx1y.cpp b/test/CodeGenCXX/debug-info-cxx1y.cpp
new file mode 100644
index 000000000000..3cb7e45e6985
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-cxx1y.cpp
@@ -0,0 +1,7 @@
+// RUN: not %clang_cc1 -emit-llvm-only -std=c++1y -g %s 2>&1 | FileCheck %s
+
+struct foo {
+ auto func(); // CHECK: error: debug information for auto is not yet supported
+};
+
+foo f;
diff --git a/test/CodeGenCXX/debug-info-decl-nested.cpp b/test/CodeGenCXX/debug-info-decl-nested.cpp
new file mode 100644
index 000000000000..f79a8e9fe32d
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-decl-nested.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -std=c++11 -g -emit-llvm -g -triple x86_64-apple-darwin %s -o %t
+// RUN: cat %t | FileCheck %s -check-prefix=CHECK0
+// RUN: cat %t | FileCheck %s -check-prefix=CHECK1
+// RUN: cat %t | FileCheck %s -check-prefix=CHECK2
+//
+// This test ensures that we associate a declaration with the
+// definition of the constructor for OuterClass. The declaration is
+// necessary so the backend can emit the DW_AT_specification attribute
+// for the definition.
+//
+// rdar://problem/13116508
+
+class Foo;
+class OuterClass
+{
+ static class InnerClass {
+ public:
+ InnerClass(); // Here createContextChain() generates a limited type for OuterClass.
+ } theInnerClass;
+// CHECK0: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [OuterClass]
+ OuterClass(const Foo *); // line 10
+};
+OuterClass::InnerClass OuterClass::theInnerClass; // This toplevel decl causes InnerClass to be generated.
+// CHECK0: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [OuterClass]
+OuterClass::OuterClass(const Foo *meta) { } // line 13
+
+
+
+
+
+class Foo1;
+class OuterClass1
+{
+ static class InnerClass1 {
+ public:
+ InnerClass1();
+ } theInnerClass1;
+// CHECK1: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+2]]] [private] [Bar]
+// CHECK1: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+4]]} ; [ DW_TAG_subprogram ] [line [[@LINE+4]]] [def] [Bar]
+ void Bar(const Foo1 *);
+};
+OuterClass1::InnerClass1 OuterClass1::theInnerClass1;
+void OuterClass1::Bar(const Foo1 *meta) { }
+
+
+
+
+
+class Foo2;
+class OuterClass2
+{
+ static class InnerClass2 {
+ public:
+ InnerClass2();
+ } theInnerClass2;
+// CHECK2: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [~OuterClass2]
+ ~OuterClass2(); // line 10
+};
+OuterClass2::InnerClass2 OuterClass2::theInnerClass2;
+// CHECK2: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [~OuterClass2]
+OuterClass2::~OuterClass2() { }
diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp
index 929327b79829..0f4b09afb5dd 100644
--- a/test/CodeGenCXX/debug-info-enum-class.cpp
+++ b/test/CodeGenCXX/debug-info-enum-class.cpp
@@ -9,10 +9,10 @@ B b;
C c;
D d;
-// CHECK: ; [ DW_TAG_enumeration_type ] [A] [line 3, size 32, align 32, offset 0] [from int]
-// CHECK: ; [ DW_TAG_enumeration_type ] [B] [line 4, size 64, align 64, offset 0] [from long unsigned int]
-// CHECK: ; [ DW_TAG_enumeration_type ] [C] [line 5, size 32, align 32, offset 0] [from ]
-// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [fwd] [from ]
+// CHECK: ; [ DW_TAG_enumeration_type ] [A] [line 3, size 32, align 32, offset 0] [def] [from int]
+// CHECK: ; [ DW_TAG_enumeration_type ] [B] [line 4, size 64, align 64, offset 0] [def] [from long unsigned int]
+// CHECK: ; [ DW_TAG_enumeration_type ] [C] [line 5, size 32, align 32, offset 0] [def] [from ]
+// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [decl] [from ]
namespace PR14029 {
// Make sure this doesn't crash/assert.
diff --git a/test/CodeGenCXX/debug-info-enum.cpp b/test/CodeGenCXX/debug-info-enum.cpp
index c08fc35af5b9..f0e2608db856 100644
--- a/test/CodeGenCXX/debug-info-enum.cpp
+++ b/test/CodeGenCXX/debug-info-enum.cpp
@@ -1,8 +1,36 @@
-// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_enumeration_type
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
-int v;
-enum index { MAX };
-void foo(void)
-{
- v = MAX;
+// CHECK: [[ENUMS:![0-9]*]], {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}} ; [ DW_TAG_compile_unit ]
+// CHECK: [[ENUMS]] = metadata !{metadata [[E1:![0-9]*]], metadata [[E2:![0-9]*]], metadata [[E3:![0-9]*]]}
+
+namespace test1 {
+// CHECK: [[E1]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST1:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test11eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[TEST1]] = {{.*}} ; [ DW_TAG_namespace ] [test1]
+// CHECK: [[TEST1_ENUMS]] = metadata !{metadata [[TEST1_E:![0-9]*]]}
+// CHECK: [[TEST1_E]] = {{.*}}, metadata !"E", i64 0} ; [ DW_TAG_enumerator ] [E :: 0]
+enum e { E };
+void foo() {
+ int v = E;
+}
+}
+
+namespace test2 {
+// rdar://8195980
+// CHECK: [[E2]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST2:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS]], {{[^,]*}}, null, null, metadata !"_ZTSN5test21eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[TEST2]] = {{.*}} ; [ DW_TAG_namespace ] [test2]
+enum e { E };
+bool func(int i) {
+ return i == E;
+}
+}
+
+namespace test3 {
+// CHECK: [[E3]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST3:![0-9]*]], {{.*}}, metadata [[TEST3_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test31eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[TEST3]] = {{.*}} ; [ DW_TAG_namespace ] [test3]
+// CHECK: [[TEST3_ENUMS]] = metadata !{metadata [[TEST3_E:![0-9]*]]}
+// CHECK: [[TEST3_E]] = {{.*}}, metadata !"E", i64 -1} ; [ DW_TAG_enumerator ] [E :: -1]
+enum e { E = -1 };
+void func() {
+ e x;
+}
}
diff --git a/test/CodeGenCXX/debug-info-friend.cpp b/test/CodeGenCXX/debug-info-friend.cpp
index c50f281a3b8f..b103b142a2ae 100644
--- a/test/CodeGenCXX/debug-info-friend.cpp
+++ b/test/CodeGenCXX/debug-info-friend.cpp
@@ -1,11 +1,20 @@
-// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_friend
+// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s
class MyFriend;
-class SomeClass
-{
- friend class MyFriend;
+class SomeClass {
+ friend class MyFriend;
+ typedef int SomeType;
};
-SomeClass sc;
+SomeClass *x;
+struct MyFriend {
+ static void func(SomeClass::SomeType) {
+ }
+};
+
+// Emitting debug info for friends unnecessarily bloats debug info without any
+// known benefit or debugger feature that requires it. Re-enable this is a
+// use-case appears.
+// CHECK-NOT: DW_TAG_friend
diff --git a/test/CodeGenCXX/debug-info-function-context.cpp b/test/CodeGenCXX/debug-info-function-context.cpp
new file mode 100644
index 000000000000..4ca1c8d1eced
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-function-context.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-pc-linux-gnu %s -o - | FileCheck %s
+
+struct C {
+ void member_function();
+ static int static_member_function();
+ static int static_member_variable;
+};
+
+int C::static_member_variable = 0;
+
+void C::member_function() { static_member_variable = 0; }
+
+int C::static_member_function() { return static_member_variable; }
+
+C global_variable;
+
+int global_function() { return -1; }
+
+namespace ns {
+void global_namespace_function() { global_variable.member_function(); }
+int global_namespace_variable = 1;
+}
+
+// Check that the functions that belong to C have C as a context and the
+// functions that belong to the namespace have it as a context, and the global
+// function has the file as a context.
+
+// CHECK: metadata !"_ZTS1C", metadata !"member_function"{{.*}} [ DW_TAG_subprogram ] [line 11] [def] [member_function]
+
+// CHECK: metadata !"_ZTS1C", metadata !"static_member_function"{{.*}} [ DW_TAG_subprogram ] [line 13] [def] [static_member_function]
+
+// CHECK: metadata !22, metadata !"global_function"{{.*}} [ DW_TAG_subprogram ] [line 17] [def] [global_function]
+// CHECK: !22 = {{.*}} [ DW_TAG_file_type ]
+
+// CHECK: metadata !24, metadata !"global_namespace_function"{{.*}} [ DW_TAG_subprogram ] [line 20] [def] [global_namespace_function]
+// CHECK: !24 = {{.*}} [ DW_TAG_namespace ] [ns] [line 19]
diff --git a/test/CodeGenCXX/debug-info-gline-tables-only.cpp b/test/CodeGenCXX/debug-info-gline-tables-only.cpp
index 8d2e63d67778..7ecdeb2ec22e 100644
--- a/test/CodeGenCXX/debug-info-gline-tables-only.cpp
+++ b/test/CodeGenCXX/debug-info-gline-tables-only.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -O0 -gline-tables-only -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -gline-tables-only -S -emit-llvm -o - | FileCheck %s
// Checks that clang with "-gline-tables-only" doesn't emit debug info
// for variables and types.
@@ -13,9 +13,17 @@ class E : public C {
// CHECK-NOT: DW_TAG_reference type
void x(const D& d);
};
+struct F {
+ enum X { };
+ void func(X);
+ virtual ~F();
+};
+F::~F() {
+}
}
// CHECK-NOT: DW_TAG_variable
NS::C c;
NS::D d;
NS::E e;
+NS::F f;
diff --git a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
index bdaf58c82703..afa77077a25d 100644
--- a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
+++ b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
@@ -20,8 +20,8 @@ void foo() {
// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 12] [local] [def] [__dtor_glob]
// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_var_init1]
// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_array_dtor]
-// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_]
+// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_array]
// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 16] [local] [def] [__dtor__ZZ3foovE4stat]
-// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__I_a]
+// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}}
-// CHECK-KEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__D_a]
+// CHECK-KEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}}
diff --git a/test/CodeGenCXX/debug-info-globalinit.cpp b/test/CodeGenCXX/debug-info-globalinit.cpp
index b3891c148e3e..30c8bfc680eb 100644
--- a/test/CodeGenCXX/debug-info-globalinit.cpp
+++ b/test/CodeGenCXX/debug-info-globalinit.cpp
@@ -12,19 +12,27 @@ int test() {
static int i = test();
__attribute__((nodebug)) static int j = test();
+static int k = test();
int main(void) {}
-// CHECK: define internal void @__cxx_global_var_init()
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
// CHECK-NOT: __cxx_global_var_init
// CHECK: %[[C0:.+]] = call i32 @_Z4testv(), !dbg ![[LINE:.*]]
// CHECK-NOT: __cxx_global_var_init
// CHECK: store i32 %[[C0]], i32* @_ZL1i, align 4, !dbg
//
-// CHECK: define internal void @__cxx_global_var_init1()
+// CHECK-LABEL: define internal void @__cxx_global_var_init1()
// CHECK-NOT: dbg
// CHECK: %[[C1:.+]] = call i32 @_Z4testv()
// CHECK-NOT: dbg
// CHECK: store i32 %[[C1]], i32* @_ZL1j, align 4
+//
+// CHECK-LABEL: define internal void @__cxx_global_var_init2()
+// CHECK-NOT: __cxx_global_var_init
+// CHECK: %[[C2:.+]] = call i32 @_Z4testv(), !dbg ![[LINE2:.*]]
+// CHECK-NOT: __cxx_global_var_init
+// CHECK: store i32 %[[C2]], i32* @_ZL1k, align 4, !dbg
//
// CHECK: ![[LINE]] = metadata !{i32 13, i32
+// CHECK: ![[LINE2]] = metadata !{i32 15, i32
diff --git a/test/CodeGenCXX/debug-info-limit-type.cpp b/test/CodeGenCXX/debug-info-limit-type.cpp
deleted file mode 100644
index e03024fb3cd9..000000000000
--- a/test/CodeGenCXX/debug-info-limit-type.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
-// XFAIL: *
-
-class B {
-public:
- int bb;
- void fn2() {}
-};
-
-class A {
-public:
- int aa;
- void fn1(B b) { b.fn2(); }
-};
-
-void foo(A *aptr) {
-}
-
-void bar() {
- A a;
-}
-
-// B should only be emitted as a forward reference (i32 4).
-// CHECK: metadata !"B", metadata !6, i32 3, i32 0, i32 0, i32 0, i32 4} ; [ DW_TAG_class_type ]
diff --git a/test/CodeGenCXX/debug-info-limit.cpp b/test/CodeGenCXX/debug-info-limit.cpp
deleted file mode 100644
index bca887b4db87..000000000000
--- a/test/CodeGenCXX/debug-info-limit.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
-
-// TAG_member is used to encode debug info for class constructor.
-// CHECK: TAG_member
-class A {
-public:
- int z;
-};
-
-A *foo (A* x) {
- A *a = new A(*x);
- return a;
-}
-
diff --git a/test/CodeGenCXX/debug-info-limited.cpp b/test/CodeGenCXX/debug-info-limited.cpp
new file mode 100644
index 000000000000..54a2424fddd9
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-limited.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s
+
+// CHECK: ; [ DW_TAG_class_type ] [A] {{.*}} [def]
+class A {
+public:
+ int z;
+};
+
+A *foo (A* x) {
+ A *a = new A(*x);
+ return a;
+}
+
+// Verify that we're not emitting a full definition of B in limit debug mode.
+// CHECK: ; [ DW_TAG_class_type ] [B] {{.*}} [decl]
+
+class B {
+public:
+ int y;
+};
+
+extern int bar(B *b);
+int baz(B *b) {
+ return bar(b);
+}
+
+
+// CHECK: ; [ DW_TAG_structure_type ] [C] {{.*}} [decl]
+
+struct C {
+};
+
+C (*x)(C);
diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp
index 3ee4d9b08f46..50b3f66354e0 100644
--- a/test/CodeGenCXX/debug-info-method.cpp
+++ b/test/CodeGenCXX/debug-info-method.cpp
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o - | FileCheck %s
-// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from A]
+// CHECK: metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
// CHECK: metadata !"_ZN1A3fooEiS_3$_0", {{.*}} [protected]
+// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from _ZTS1A]
// CHECK: DW_TAG_ptr_to_member_type
// CHECK: {{.*}}metadata ![[MEMFUNTYPE:[0-9]+]], metadata !{{.*}}} ; [ DW_TAG_ptr_to_member_type ] {{.*}} [from ]
-// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] {{.*}} [from ]
+// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] {{.*}} [from ]
// CHECK: ![[MEMFUNARGS]] = {{.*}}, metadata ![[THISTYPE]],
// CHECK: ""{{.*}}DW_TAG_arg_variable
// CHECK: ""{{.*}}DW_TAG_arg_variable
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 13a7914b7be0..a2d7ede1643e 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -1,14 +1,24 @@
-// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang -g -gline-tables-only -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-GMLT %s
+// RUN: %clang -g -fno-limit-debug-info -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-NOLIMIT %s
namespace A {
#line 1 "foo.cpp"
namespace B {
int i;
+void f1() { }
+void f1(int) { }
+struct foo;
+struct bar { };
+typedef bar baz;
}
+}
+namespace A {
using namespace B;
}
using namespace A;
+namespace E = A;
int func(bool b) {
if (b) {
@@ -16,22 +26,52 @@ int func(bool b) {
return i;
}
using namespace A;
- return B::i;
+ using B::foo;
+ using B::bar;
+ using B::f1;
+ using B::i;
+ using B::baz;
+ namespace X = A;
+ namespace Y = X;
+ return i + X::B::i + Y::B::i;
}
+// This should work even if 'i' and 'func' were declarations & not definitions,
+// but it doesn't yet.
+
// CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ]
// CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp"
-// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 9] [def] [func]
-// CHECK: [[FILE2:![0-9]*]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
-// CHECK: [[VAR:![0-9]*]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i]
-// CHECK: [[NS]] = {{.*}}, metadata [[FILE2]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1]
-// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3]
-// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]]}
-// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 4} ; [ DW_TAG_imported_module ]
-// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 7} ; [ DW_TAG_imported_module ]
-// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ]
-// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 10, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
-// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 14} ; [ DW_TAG_imported_module ]
+// CHECK: [[FOO:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [foo] [line 5, size 0, align 0, offset 0] [decl] [from ]
+// CHECK: [[FOOCPP:![0-9]*]] = metadata !{metadata !"foo.cpp", {{.*}}
+// CHECK: [[NS:![0-9]*]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1]
+// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 5]
+// CHECK: [[BAR:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [decl] [from ]
+// CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1]
+// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
+// CHECK: [[I:![0-9]*]] = {{.*}}, metadata [[NS]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i]
+// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]]}
+// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ]
+// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ]
+// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 15, metadata !"E"} ; [ DW_TAG_imported_module ]
+// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX2:![0-9]*]], metadata [[NS]], i32 19} ; [ DW_TAG_imported_module ]
+// CHECK: [[LEX2]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[LEX1:![0-9]+]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
+// CHECK: [[LEX1]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
+// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ]
+// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 23} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M10]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}}, metadata !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE]
+// CHECK: [[M11]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}, metadata !"X"} ; [ DW_TAG_imported_module ]
+// CHECK: [[M12]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[M11]], i32 {{[0-9]*}}, metadata !"Y"} ; [ DW_TAG_imported_module ]
+
+// CHECK-GMLT: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ]
+// CHECK-GMLT: [[MODULES]] = metadata !{i32 0}
+
+// CHECK-NOLIMIT: ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [def] [from ]
// FIXME: It is confused on win32 to generate file entry when dosish filename is given.
// REQUIRES: shell
+// REQUIRES: shell-preserves-root
diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp
index 42e9741d1967..ef9b618fdb34 100644
--- a/test/CodeGenCXX/debug-info-nullptr.cpp
+++ b/test/CodeGenCXX/debug-info-nullptr.cpp
@@ -4,4 +4,4 @@ void foo() {
decltype(nullptr) t = 0;
}
-// CHECK: [ DW_TAG_unspecified_type ] [nullptr_t]
+// CHECK: [ DW_TAG_unspecified_type ] [decltype(nullptr)]
diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp
index 6ca3da8674f3..6393cddeef67 100644
--- a/test/CodeGenCXX/debug-info-pubtypes.cpp
+++ b/test/CodeGenCXX/debug-info-pubtypes.cpp
@@ -1,6 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S %s -o %t
-// RUN: FileCheck %s < %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S -mllvm -generate-dwarf-pub-sections=Enable %s -o - | FileCheck %s
// FIXME: This testcase shouldn't rely on assembly emission.
//CHECK: Lpubtypes_begin[[SECNUM:[0-9]:]]
@@ -10,7 +9,7 @@
class G {
public:
- void foo();
+ void foo();
};
void G::foo() {
diff --git a/test/CodeGenCXX/debug-info-same-line.cpp b/test/CodeGenCXX/debug-info-same-line.cpp
index ad245031abf0..519e9eeb87a4 100644
--- a/test/CodeGenCXX/debug-info-same-line.cpp
+++ b/test/CodeGenCXX/debug-info-same-line.cpp
@@ -83,6 +83,21 @@ main(int argc, char const *argv[])
// result
// CHECK: call void @llvm.dbg.declare
+// We want to see a distinct !dbg node.
+// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg ![[A_DI]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg !{{.*}}
+// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg ![[B_DI]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg !{{.*}}
+// result
+// CHECK: call void @llvm.dbg.declare
+
+// Again: we want to see a distinct !dbg node.
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[X_MD:[0-9]+]]), !dbg ![[X_DI:[0-9]+]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[Y_MD:[0-9]+]]), !dbg ![[Y_DI:[0-9]+]]
+// result
+// CHECK: call void @llvm.dbg.declare
+
+
// CHECK: define {{.*}} @main
// CHECK: call {{.*}} @_Z3fooii
// CHECK: call {{.*}} @_Z3fooii
@@ -96,3 +111,13 @@ main(int argc, char const *argv[])
// CHECK: load {{.*}} !dbg ![[DBG]]
// CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]]
// CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]]
+
+
+// Verify that product() has its own inlined_at location at column 15.
+// CHECK-DAG: ![[A_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [a]
+// CHECK-DAG: ![[B_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [b]
+// CHECK-DAG: ![[X_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [x]
+// CHECK-DAG: ![[Y_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [y]
+// CHECK-DAG: ![[X_DI]] = metadata !{i32 {{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata ![[PRODUCT:[0-9]+]]}
+// CHECK-DAG: [[PRODUCT]] = metadata !{i32 {{.*}}, i32 16, metadata !{{.*}}, null}
+// CHECK-DAG: ![[Y_DI]] = metadata !{i32 {{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata ![[PRODUCT]]}
diff --git a/test/CodeGenCXX/debug-info-scope.cpp b/test/CodeGenCXX/debug-info-scope.cpp
new file mode 100644
index 000000000000..557ee3178354
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-scope.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -g -emit-llvm %s -o -| FileCheck %s
+//
+// Two variables with the same name in subsequent if staments need to be in separate scopes.
+//
+// rdar://problem/14024005
+//
+
+int printf(const char*, ...);
+
+char *return_char (int input)
+{
+ if (input%2 == 0)
+ return "I am even.\n";
+ else
+ return "I am odd.\n";
+}
+
+int main2() {
+// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]]
+// CHECK metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ]
+ if (char *ptr = return_char(1)) {
+ printf ("%s", ptr);
+ }
+// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]]
+// CHECK metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ]
+ if (char *ptr = return_char(2)) {
+ printf ("%s", ptr);
+ }
+ else printf ("%s", ptr);
+
+ return 0;
+}
diff --git a/test/CodeGenCXX/debug-info-static-member.cpp b/test/CodeGenCXX/debug-info-static-member.cpp
index 774f7b1727c3..1ac235c50f8e 100644
--- a/test/CodeGenCXX/debug-info-static-member.cpp
+++ b/test/CodeGenCXX/debug-info-static-member.cpp
@@ -1,7 +1,9 @@
-// RUN: %clangxx -target x86_64-unknown-unknown -g -O0 %s -emit-llvm -S -o - | FileCheck %s
+// RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck %s
// PR14471
-
+enum X {
+ Y
+};
class C
{
static int a;
@@ -13,6 +15,7 @@ public:
static int c;
const static int const_c = 18;
int d;
+ static X x_a;
};
int C::a = 4;
@@ -30,12 +33,15 @@ int main()
// why the definition of "a" comes before the declarations while
// "b" and "c" come after.
-// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A:[0-9]+]]} ; [ DW_TAG_variable ] [a] {{.*}} [def]
-// CHECK: ![[DECL_A]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
+// CHECK: metadata !"_ZTS1X"} ; [ DW_TAG_enumeration_type ] [X]
+// CHECK: metadata !"_ZTS1C"} ; [ DW_TAG_class_type ] [C]
+// CHECK: ![[DECL_A:[0-9]+]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
// CHECK: metadata !"const_a", {{.*}}, i1 true} ; [ DW_TAG_member ] [const_a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
// CHECK: ![[DECL_B:[0-9]+]] {{.*}} metadata !"b", {{.*}} [ DW_TAG_member ] [b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
// CHECK: metadata !"const_b", {{.*}}, float 0x{{.*}}} ; [ DW_TAG_member ] [const_b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
// CHECK: ![[DECL_C:[0-9]+]] {{.*}} metadata !"c", {{.*}} [ DW_TAG_member ] [c] [line {{.*}}, size 0, align 0, offset 0] [static]
// CHECK: metadata !"const_c", {{.*}} [ DW_TAG_member ] [const_c] [line {{.*}}, size 0, align 0, offset 0] [static]
+// CHECK: metadata !"x_a", {{.*}} [ DW_TAG_member ] [x_a] {{.*}} [static]
+// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A]]} ; [ DW_TAG_variable ] [a] {{.*}} [def]
// CHECK: metadata !"b", {{.*}} @_ZN1C1bE, metadata ![[DECL_B]]} ; [ DW_TAG_variable ] [b] {{.*}} [def]
// CHECK: metadata !"c", {{.*}} @_ZN1C1cE, metadata ![[DECL_C]]} ; [ DW_TAG_variable ] [c] {{.*}} [def]
diff --git a/test/CodeGenCXX/debug-info-template-limit.cpp b/test/CodeGenCXX/debug-info-template-limit.cpp
index afad31b14efa..c3e241ecc806 100644
--- a/test/CodeGenCXX/debug-info-template-limit.cpp
+++ b/test/CodeGenCXX/debug-info-template-limit.cpp
@@ -1,8 +1,8 @@
// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s
// Check that this pointer type is TC<int>
-// CHECK: ![[LINE:[0-9]+]]} ; [ DW_TAG_pointer_type ]{{.*}}[from TC<int>]
-// CHECK-NEXT: ![[LINE]] ={{.*}}"TC<int>"
+// CHECK: ![[LINE:[0-9]+]] = {{.*}}"TC<int>", {{.*}} metadata !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ]
+// CHECK: metadata !"_ZTS2TCIiE"} ; [ DW_TAG_pointer_type ]{{.*}}[from _ZTS2TCIiE]
template<typename T>
class TC {
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
index 6be7f9bd2495..9ac1befc1019 100644
--- a/test/CodeGenCXX/debug-info-template-member.cpp
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -1,21 +1,78 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
-class MyClass
-{
-public:
- int add2(int j)
- {
- return add<2>(j);
- }
-private:
- template <int i> int add(int j)
- {
- return i + j;
- }
+struct MyClass {
+ template <int i> int add(int j) {
+ return i + j;
+ }
+ virtual void func() {
+ }
};
-MyClass m;
+int add2(int x) {
+ return MyClass().add<2>(x);
+}
+
+inline int add3(int x) {
+ return MyClass().add<3>(x); // even though add<3> is ODR used, don't emit it since we don't codegen it
+}
+
+// CHECK: [[FOO_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: [[FOO_MEM]] = metadata !{metadata [[FOO_FUNC:![0-9]*]]}
+// CHECK: [[FOO_FUNC]] = {{.*}}, metadata !"_ZN3foo4funcEN5outerIS_E5innerE", i32 {{[0-9]*}}, metadata [[FOO_FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]
+// CHECK: [[FOO_FUNC_TYPE]] = {{.*}}, metadata [[FOO_FUNC_PARAMS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FOO_FUNC_PARAMS]] = metadata !{null, metadata !{{[0-9]*}}, metadata [[OUTER_FOO_INNER:![0-9]*]]}
+// CHECK: [[OUTER_FOO_INNER]] = {{.*}} ; [ DW_TAG_structure_type ] [inner]
+
+// CHECK: metadata [[VIRT_MEM:![0-9]*]], i32 0, metadata !"_ZTS4virtI4elemE", metadata [[VIRT_TEMP_PARAM:![0-9]*]], metadata !"_ZTS4virtI4elemE"} ; [ DW_TAG_structure_type ] [virt<elem>] {{.*}} [def]
+// CHECK: [[VIRT_TEMP_PARAM]] = metadata !{metadata [[VIRT_T:![0-9]*]]}
+// CHECK: [[VIRT_T]] = {{.*}}, metadata !"T", metadata !"_ZTS4elem", {{.*}} ; [ DW_TAG_template_type_parameter ]
+
+// CHECK: [[C:![0-9]*]] = {{.*}}, metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS7MyClass", null, metadata !"_ZTS7MyClass"} ; [ DW_TAG_structure_type ] [MyClass]
+// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_ADD:![0-9]*]], metadata [[C_FUNC:![0-9]*]], metadata [[C_CTOR:![0-9]*]]}
+// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$MyClass]
+
+// CHECK: [[C_ADD]] = {{.*}} ; [ DW_TAG_subprogram ] [line 4] [add<2>]
+// CHECK: [[C_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] [line 7] [func]
+// CHECK: [[C_CTOR]] = {{.*}} ; [ DW_TAG_subprogram ] [line 0] [MyClass]
+
+// CHECK: [[ELEM:![0-9]*]] = {{.*}}, metadata [[ELEM_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS4elem"} ; [ DW_TAG_structure_type ] [elem] {{.*}} [def]
+// CHECK: [[ELEM_MEM]] = metadata !{metadata [[ELEM_X:![0-9]*]]}
+// CHECK: [[ELEM_X]] = {{.*}} ; [ DW_TAG_member ] [x] {{.*}} [static] [from _ZTS4virtI4elemE]
+
+template<typename T>
+struct outer {
+ struct inner {
+ int i;
+ };
+};
+
+struct foo {
+ void func(outer<foo>::inner);
+};
+
+inline void func() {
+ // require 'foo' to be complete before the emission of 'inner' so that, when
+ // constructing the context chain for 'x' we emit the full definition of
+ // 'foo', which requires the definition of 'inner' again
+ foo f;
+}
+
+outer<foo>::inner x;
+
+// CHECK: metadata [[OUTER_FOO_INNER]], i32 {{[0-9]*}}, i32 {{[0-9]*}}, %"struct.outer<foo>::inner"* @x, {{.*}} ; [ DW_TAG_variable ] [x]
+
+template <typename T>
+struct virt {
+ T* values;
+ virtual ~virt();
+};
+struct elem {
+ static virt<elem> x; // ensure that completing 'elem' will require/completing 'virt<elem>'
+};
+inline void f1() {
+ elem e; // ensure 'elem' is required to be complete when it is emitted as a template argument for 'virt<elem>'
+};
+void f2() {
+ virt<elem> d; // emit 'virt<elem>'
+}
-// CHECK: metadata [[C_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [MyClass]
-// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:![0-9]*]], metadata {{.*}}}
-// CHECK: [[C_TEMP]] = {{.*}} ; [ DW_TAG_subprogram ] [line 11] [private] [add<2>]
diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp
index 335c8abb11e4..740f7bfa5ce5 100644
--- a/test/CodeGenCXX/debug-info-template-quals.cpp
+++ b/test/CodeGenCXX/debug-info-template-quals.cpp
@@ -15,13 +15,13 @@ void foo (const char *c) {
str.assign(c, str);
}
-// CHECK: [[P:.*]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [def] [from ]
+// CHECK: [[TYPE:![0-9]*]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P:![0-9]*]], metadata [[R:.*]]}
+// CHECK: [[P]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
// CHECK: [[CON]] = {{.*}}, metadata [[CH:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char]
// CHECK: [[CH]] = {{.*}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char]
-// CHECK: {{.*}} metadata [[TYPE:![0-9]*]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
-// CHECK: [[TYPE]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P]], metadata [[R:.*]]}
-// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [from ]
// CHECK: [[R]] = {{.*}}, metadata [[CON2:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ]
-// CHECK: [[CON2]] = {{.*}}, metadata [[BS]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from basic_string<char>]
+// CHECK: [[CON2]] = {{.*}}, metadata !"_ZTS12basic_stringIcE"} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _ZTS12basic_stringIcE]
+// CHECK: {{.*}} metadata [[TYPE]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp
index 9d52159bed84..f58973bcceae 100644
--- a/test/CodeGenCXX/debug-info-template.cpp
+++ b/test/CodeGenCXX/debug-info-template.cpp
@@ -1,46 +1,116 @@
-// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+// RUN: %clang -S -emit-llvm -target x86_64-unknown_unknown -g %s -o - -std=c++11 | FileCheck %s
-//CHECK: TC<int>
-//CHECK: DW_TAG_template_type_parameter
+// CHECK: {{.*}}, i1 false, metadata !"", i32 0, metadata !{{[0-9]]*}}, metadata [[RETAIN:![0-9]*]], {{.*}} ; [ DW_TAG_compile_unit ]
+// CHECK: [[EMPTY:![0-9]*]] = metadata !{i32 0}
+// CHECK: [[RETAIN]] = metadata !{metadata !{{[0-9]]*}}, metadata [[FOO:![0-9]*]],
-template<typename T>
-class TC {
-public:
- TC(const TC &) {}
- TC() {}
-};
-TC<int> tci;
+// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>]
+// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]], metadata [[TCARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCARG8:![0-9]*]]}
+//
+// We seem to be missing file/line/col info on template value parameters -
+// metadata supports it but it's not populated. GCC doesn't emit it either,
+// perhaps we should just drop it from the metadata.
+//
+// CHECK: [[TCARG1]] = {{.*}}metadata !"T", metadata [[UINT:![0-9]*]], {{.*}} ; [ DW_TAG_template_type_parameter ]
+// CHECK: [[UINT:![0-9]*]] = {{.*}} ; [ DW_TAG_base_type ] [unsigned int]
+// CHECK: [[TCARG2]] = {{.*}}metadata !"", metadata [[UINT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG3]] = {{.*}}metadata !"x", metadata [[INTPTR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[INTPTR]] = {{.*}}, metadata [[INT:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from int]
+// CHECK: [[INT]] = {{.*}} ; [ DW_TAG_base_type ] [int]
+// CHECK: [[TCARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR:![0-9]*]], i64 8, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[MEMINTPTR]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ] {{.*}}[from int]
+//
+// Currently Clang emits the pointer-to-member-function value, but LLVM doesn't
+// use it (GCC doesn't emit a value for pointers to member functions either - so
+// it's not clear what, if any, format would be acceptable to GDB)
+//
+// CHECK: [[TCARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[MEMFUNPTR]] = {{.*}}, metadata [[FTYPE:![0-9]*]], metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ]
+// CHECK: [[FTYPE]] = {{.*}}, metadata [[FARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FARGS]] = metadata !{null, metadata [[FARG1:![0-9]*]]}
+// CHECK: [[FARG1]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS3foo]
+//
+// CHECK: [[TCARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR:![0-9]*]], void ()* @_Z4funcv, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[FUNPTR]] = {{.*}}, metadata [[FUNTYPE:![0-9]*]]} ; [ DW_TAG_pointer_type ]
+// CHECK: [[FUNTYPE]] = {{.*}}, metadata [[FUNARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FUNARGS]] = metadata !{null}
+// CHECK: [[TCARG7]] = {{.*}}metadata !"tmpl", null, metadata !"tmpl_impl", {{.*}} ; [ DW_TAG_GNU_template_template_param ]
+// CHECK: [[TCARG8]] = {{.*}}metadata !"Is", null, metadata [[TCARG8_VALS:![0-9]*]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ]
+// CHECK: [[TCARG8_VALS]] = metadata !{metadata [[TCARG8_1:![0-9]*]], metadata [[TCARG8_2:![0-9]*]], metadata [[TCARG8_3:![0-9]*]]}
+// CHECK: [[TCARG8_1]] = {{.*}}metadata !"", metadata [[INT]], i32 1, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG8_2]] = {{.*}}metadata !"", metadata [[INT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG8_3]] = {{.*}}metadata !"", metadata [[INT]], i32 3, {{.*}} ; [ DW_TAG_template_value_parameter ]
+//
+// We could just emit a declaration of 'foo' here, rather than the entire
+// definition (same goes for any time we emit a member (function or data)
+// pointer type)
+// CHECK: [[FOO]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: metadata !"f", metadata !"_ZN3foo1fEv", i32 {{[0-9]*}}, metadata [[FTYPE:![0-9]*]],
+//
+
+
+// CHECK: [[TCNESTED:![0-9]*]] = metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"_ZTS2TCIjLj2EXadL_Z3glbEEXadL_ZN3foo1eEEEXadL_ZNS0_1fEvEEXadL_Z4funcvEE9tmpl_implJLi1ELi2ELi3EEE", {{.*}} ; [ DW_TAG_structure_type ] [nested]
+// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl>]
+// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]], metadata [[TCNARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCNARG8:![0-9]*]]}
+// CHECK: [[TCNARG1]] = {{.*}}metadata !"T", metadata [[INT]], {{.*}} ; [ DW_TAG_template_type_parameter ]
+// CHECK: [[TCNARG2]] = {{.*}}metadata !"", metadata [[INT]], i32 -3, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG3]] = {{.*}}metadata !"x", metadata [[INTPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+
+// The interesting null pointer: -1 for member data pointers (since they are
+// just an offset in an object, they can be zero and non-null for the first
+// member)
+
+// CHECK: [[TCNARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR]], i64 -1, {{.*}} ; [ DW_TAG_template_value_parameter ]
+//
+// In some future iteration we could possibly emit the value of a null member
+// function pointer as '{ i64, i64 } zeroinitializer' as it may be handled
+// naturally from the LLVM CodeGen side once we decide how to handle non-null
+// member function pointers. For now, it's simpler just to emit the 'i8 0'.
+//
+// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG8]] = {{.*}}metadata !"Is", null, metadata [[EMPTY]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ]
+
+// CHECK: metadata [[PTOARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [PaddingAtEndTemplate<&PaddedObj>]
+// CHECK: [[PTOARGS]] = metadata !{metadata [[PTOARG1:![0-9]*]]}
+// CHECK: [[PTOARG1]] = {{.*}}metadata !"", metadata [[CONST_PADDINGATEND_PTR:![0-9]*]], { i32, i8, [3 x i8] }* @PaddedObj, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[CONST_PADDINGATEND_PTR]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from _ZTS12PaddingAtEnd]
-//CHECK: TU<2>
-//CHECK: DW_TAG_template_value_parameter
-template<unsigned >
-class TU {
- int b;
+// CHECK: metadata [[TCNESTED]], i32 0, i32 1, %"struct.TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested"* @tci, null} ; [ DW_TAG_variable ] [tci]
+
+// CHECK: metadata [[TCNT:![0-9]*]], i32 0, i32 1, %struct.TC* @tcn, null} ; [ DW_TAG_variable ] [tcn]
+struct foo {
+ char pad[8]; // make the member pointer to 'e' a bit more interesting (nonzero)
+ int e;
+ void f();
+};
+
+template<typename T, T, int *x, int foo::*a, void (foo::*b)(), void (*f)(), template<typename> class tmpl, int ...Is>
+struct TC {
+ struct nested {
+ };
};
-TU<2> u2;
+int glb;
+void func();
-// PR9600
-template<typename T> class vector {};
-class Foo;
-typedef vector<Foo*> FooVector[3];
-struct Test {
- virtual void foo(FooVector *);
+template<typename>
+struct tmpl_impl {
};
-static Test test;
-// PR9608
-template <int i> struct TheTemplate {
- struct Empty2 {};
- typedef const Empty2 DependentType[i];
- TheTemplate() {}
-};
+TC<unsigned, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested tci;
+TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl> tcn;
-class TheTemplateTest : public TheTemplate<42> {
- TheTemplateTest();
- void method(const TheTemplate<42>::DependentType *) {}
-};
+struct PaddingAtEnd {
+ int i;
+ char c;
+};
+
+PaddingAtEnd PaddedObj = {};
-TheTemplateTest::TheTemplateTest() : TheTemplate<42>() {}
+template <const PaddingAtEnd *>
+struct PaddingAtEndTemplate {
+};
+PaddingAtEndTemplate<&PaddedObj> PaddedTemplateObj;
diff --git a/test/CodeGenCXX/debug-info-thunk.cpp b/test/CodeGenCXX/debug-info-thunk.cpp
index 394ebd829188..2a5089572534 100644
--- a/test/CodeGenCXX/debug-info-thunk.cpp
+++ b/test/CodeGenCXX/debug-info-thunk.cpp
@@ -14,4 +14,4 @@ struct C : A, B {
void C::f() { }
-// CHECK: [ DW_TAG_subprogram ] [line 15] [def] [_ZThn{{4|8}}_N1C1fEv]
+// CHECK: metadata !"_ZThn{{4|8}}_N1C1fEv", i32 15, {{.*}} ; [ DW_TAG_subprogram ] [line 15] [def]{{$}}
diff --git a/test/CodeGenCXX/debug-info-union-template.cpp b/test/CodeGenCXX/debug-info-union-template.cpp
index f5e6e14a71d1..570520d03d9e 100644
--- a/test/CodeGenCXX/debug-info-union-template.cpp
+++ b/test/CodeGenCXX/debug-info-union-template.cpp
@@ -10,6 +10,6 @@ namespace PR15637 {
Value<float> f;
}
-// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]]} ; [ DW_TAG_union_type ] [Value<float>]
+// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]], metadata !"_ZTSN7PR156375ValueIfEE"} ; [ DW_TAG_union_type ] [Value<float>]
// CHECK: [[TTPARAM]] = metadata !{metadata [[PARAMS:.*]]}
// CHECK: [[PARAMS]] = metadata !{{{.*}}metadata !"T",{{.*}}} ; [ DW_TAG_template_type_parameter ]
diff --git a/test/CodeGenCXX/debug-info-uuid.cpp b/test/CodeGenCXX/debug-info-uuid.cpp
new file mode 100644
index 000000000000..a57e2f0a84ae
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-uuid.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-pc-win32 -cxx-abi microsoft -g %s -o - -std=c++11 | FileCheck %s
+// RUN: not %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-unknown-unknown -g %s -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-ITANIUM
+
+// CHECK: metadata [[TGIARGS:![0-9]*]], null} ; [ DW_TAG_structure_type ] [tmpl_guid<&__uuidof(uuid)>]
+// CHECK: [[TGIARGS]] = metadata !{metadata [[TGIARG1:![0-9]*]]}
+// CHECK: [[TGIARG1]] = {{.*}}metadata !"", metadata [[CONST_GUID_PTR:![0-9]*]], { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[CONST_GUID_PTR]] = {{.*}}, metadata [[CONST_GUID:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+// CHECK: [[CONST_GUID]] = {{.*}}, metadata [[GUID:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _GUID]
+// CHECK: [[GUID]] = {{.*}} ; [ DW_TAG_structure_type ] [_GUID]
+
+// CHECK-ITANIUM: error: cannot yet mangle expression type CXXUuidofExpr
+
+struct _GUID;
+template <const _GUID *>
+struct tmpl_guid {
+};
+
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ab}")) uuid;
+tmpl_guid<&__uuidof(uuid)> tgi;
diff --git a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
index fb47022b646f..101796509da3 100644
--- a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
+++ b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
@@ -7,6 +7,6 @@ class A {
A a;
// CHECK: metadata [[ARRAY_TYPE:![0-9]*]]} ; [ DW_TAG_member ] [x]
-// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int]
+// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int]
// CHECK: [[ELEM_TYPE]] = metadata !{metadata [[SUBRANGE:.*]]}
// CHECK: [[SUBRANGE]] = metadata !{i32 786465, i64 0, i64 -1} ; [ DW_TAG_subrange_type ] [unbounded]
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index 33b52789caf2..93a4fe3f466a 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only -g %s
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -g %s -o - | FileCheck %s
template<typename T> struct Identity {
typedef T Type;
};
@@ -67,3 +67,54 @@ class Cls {
Cls obj;
}
+
+namespace pr14763 {
+struct foo {
+ foo(const foo&);
+};
+
+foo func(foo f) {
+ return f; // reference 'f' for now because otherwise we hit another bug
+}
+
+// CHECK: [[FOO:![0-9]*]] = metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata [[PR14763:![0-9]*]], {{.*}} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: [[PR14763]] = {{.*}} ; [ DW_TAG_namespace ] [pr14763]
+// CHECK: [[INCTYPE:![0-9]*]] = {{.*}} ; [ DW_TAG_structure_type ] [incomplete]{{.*}} [decl]
+// CHECK: metadata [[A_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN7pr162141aE"} ; [ DW_TAG_structure_type ] [a]
+// CHECK: [[A_MEM]] = metadata !{metadata [[A_I:![0-9]*]]}
+// CHECK: [[A_I]] = {{.*}} ; [ DW_TAG_member ] [i] {{.*}} [from int]
+// CHECK: ; [ DW_TAG_structure_type ] [b] {{.*}}[decl]
+
+// CHECK: [[FUNC:![0-9]*]] = {{.*}} metadata !"_ZN7pr147634funcENS_3fooE", i32 {{[0-9]*}}, metadata [[FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+}
+
+namespace pr9608 { // also pr9600
+struct incomplete;
+incomplete (*x)[3];
+// CHECK: metadata [[INCARRAYPTR:![0-9]*]], i32 0, i32 1, [3 x i8]** @_ZN6pr96081xE, null} ; [ DW_TAG_variable ] [x]
+// CHECK: [[INCARRAYPTR]] = {{.*}}metadata [[INCARRAY:![0-9]*]]} ; [ DW_TAG_pointer_type ]
+// CHECK: [[INCARRAY]] = {{.*}}metadata !"_ZTSN6pr960810incompleteE", metadata {{![0-9]*}}, i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 0, offset 0] [from _ZTSN6pr960810incompleteE]
+}
+
+// For some reason the argument for PR14763 ended up all the way down here
+// CHECK: = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], {{.*}}, metadata [[FOO]], i32 8192, i32 0} ; [ DW_TAG_arg_variable ] [f]
+
+namespace pr16214 {
+struct a {
+ int i;
+};
+
+typedef a at;
+
+struct b {
+};
+
+typedef b bt;
+
+void func() {
+ at a_inst;
+ bt *b_ptr_inst;
+ const bt *b_cnst_ptr_inst;
+}
+
+}
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
index 39c9a445c4ee..0b087360f9d5 100644
--- a/test/CodeGenCXX/debug-lambda-expressions.cpp
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -12,7 +12,7 @@ int b(int x) { return [x]{return x;}(); }
int c(int x) { return [&x]{return x;}(); }
struct D { D(); D(const D&); int x; };
-int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
+int d(int x) { D y[10]; return [x,y] { return y[x].x; }(); }
// Randomness for file. -- 6
// CHECK: [[FILE:.*]] = {{.*}} [ DW_TAG_file_type ] [{{.*}}debug-lambda-expressions.cpp]
@@ -30,42 +30,38 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// CHECK: [[D_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE:.*]]] [def] [d]
// Back to D. -- 24
-// CHECK: [[LAM_D:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]],
-// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]}
+// CHECK: [[LAM_D:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]],
+// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]}
// CHECK: [[CAP_D_X]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [x] [line [[D_LINE]],
// CHECK: [[CAP_D_Y]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [y] [line [[D_LINE]],
// CHECK: [[CON_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [operator()]
-// CHECK: [[DES_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [~]
// Back to C. -- 55
-// CHECK: [[LAM_C:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]],
-// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]}
+// CHECK: [[LAM_C:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]],
+// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]]}
// Ignoring the member type for now.
// CHECK: [[CAP_C]] = {{.*}}, metadata [[LAM_C]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[C_LINE]],
// CHECK: [[CON_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [operator()]
-// CHECK: [[DES_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [~]
// Back to B. -- 67
-// CHECK: [[LAM_B:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]],
-// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]}
+// CHECK: [[LAM_B:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]],
+// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]]}
// CHECK: [[CAP_B]] = {{.*}}, metadata [[LAM_B]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[B_LINE]],
// CHECK: [[CON_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [operator()]
-// CHECK: [[DES_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [~]
// Back to A. -- 78
-// CHECK: [[LAM_A:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]],
-// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]}
+// CHECK: [[LAM_A:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]],
+// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]]}
// CHECK: [[CON_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [operator()]
-// CHECK: [[DES_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [~]
// CVAR:
// CHECK: {{.*}} metadata [[CVAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [cvar] [line [[CVAR_LINE:[0-9]*]]]
-// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]],
-// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
+// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]],
+// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}}
// VAR:
// CHECK: {{.*}} metadata [[VAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [var] [line [[VAR_LINE:[0-9]*]]]
-// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]],
-// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
+// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]],
+// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}}
diff --git a/test/CodeGenCXX/decl-ref-init.cpp b/test/CodeGenCXX/decl-ref-init.cpp
index a066fbb3f3ea..1a82ee2b485b 100644
--- a/test/CodeGenCXX/decl-ref-init.cpp
+++ b/test/CodeGenCXX/decl-ref-init.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
struct A {};
diff --git a/test/CodeGenCXX/default-arg-temps.cpp b/test/CodeGenCXX/default-arg-temps.cpp
index 3d741d502834..43756006f209 100644
--- a/test/CodeGenCXX/default-arg-temps.cpp
+++ b/test/CodeGenCXX/default-arg-temps.cpp
@@ -13,7 +13,7 @@ public:
X(const X&, const T& t = T());
};
-// CHECK: define void @_Z1gv()
+// CHECK-LABEL: define void @_Z1gv()
void g() {
// CHECK: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG1:%.*]])
// CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG1]])
@@ -41,7 +41,7 @@ void g() {
class obj{ int a; float b; double d; };
-// CHECK: define void @_Z1hv()
+// CHECK-LABEL: define void @_Z1hv()
void h() {
// CHECK: call void @llvm.memset.p0i8.i64(
obj o = obj();
@@ -61,7 +61,7 @@ namespace test1 {
C c;
A a;
- // CHECK: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr
// CHECK: call void @_ZN5test11BC1Ev(
// CHECK-NEXT: call void @_ZN5test11CC1ERKNS_1BE(
// CHECK-NEXT: call void @_ZN5test11BD1Ev(
diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp
index 206d4d6c8860..83cae3afd561 100644
--- a/test/CodeGenCXX/default-arguments.cpp
+++ b/test/CodeGenCXX/default-arguments.cpp
@@ -26,7 +26,7 @@ struct B {
B(const A1& = A1(), const A2& = A2());
};
-// CHECK: define void @_Z2f1v()
+// CHECK-LABEL: define void @_Z2f1v()
void f1() {
// CHECK: call void @_ZN2A1C1Ev(
@@ -42,10 +42,10 @@ struct C {
C();
};
-// CHECK: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr
// CHECK: call void @_ZN1CC2Ev(
-// CHECK: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr
// CHECK: call void @_ZN2A1C1Ev(
// CHECK: call void @_ZN2A2C1Ev(
// CHECK: call void @_ZN1BC1ERK2A1RK2A2(
@@ -53,7 +53,7 @@ struct C {
// CHECK: call void @_ZN2A1D1Ev
C::C() { }
-// CHECK: define void @_Z2f3v()
+// CHECK-LABEL: define void @_Z2f3v()
void f3() {
// CHECK: call void @_ZN2A1C1Ev(
// CHECK: call void @_ZN2A2C1Ev(
diff --git a/test/CodeGenCXX/default-constructor-for-members.cpp b/test/CodeGenCXX/default-constructor-for-members.cpp
index 714811f37b14..6065b49ac158 100644
--- a/test/CodeGenCXX/default-constructor-for-members.cpp
+++ b/test/CodeGenCXX/default-constructor-for-members.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/default-constructor-template-member.cpp b/test/CodeGenCXX/default-constructor-template-member.cpp
index 0dd64dfcb4c9..215696405a4f 100644
--- a/test/CodeGenCXX/default-constructor-template-member.cpp
+++ b/test/CodeGenCXX/default-constructor-template-member.cpp
@@ -5,6 +5,7 @@ struct B { A<int> x; };
void a() {
B b;
}
+
// CHECK: call {{.*}} @_ZN1BC1Ev
-// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* {{.*}}%this) unnamed_addr
// CHECK: call {{.*}} @_ZN1AIiEC1Ev
diff --git a/test/CodeGenCXX/deferred-global-init.cpp b/test/CodeGenCXX/deferred-global-init.cpp
index 24c8c675b006..deb458f55c7d 100644
--- a/test/CodeGenCXX/deferred-global-init.cpp
+++ b/test/CodeGenCXX/deferred-global-init.cpp
@@ -7,10 +7,10 @@ void* bar() { return a; }
// CHECK: @_ZL1a = internal global i8* null
-// CHECK: define internal void @__cxx_global_var_init
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: load i8** @foo
// CHECK: ret void
-// CHECK: define internal void @_GLOBAL__I_a
+// CHECK-LABEL: define internal void @_GLOBAL__I_a
// CHECK: call void @__cxx_global_var_init()
// CHECK: ret void
diff --git a/test/CodeGenCXX/delayed-template-parsing.cpp b/test/CodeGenCXX/delayed-template-parsing.cpp
new file mode 100644
index 000000000000..fa177d456255
--- /dev/null
+++ b/test/CodeGenCXX/delayed-template-parsing.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
+
+namespace ClassScopeSpecialization {
+ struct Type {
+ template <int i>
+ void Foo() {}
+ template <>
+ void Foo<0>() {}
+ };
+
+ void call() {
+ Type T;
+// CHECK: call {{.*}} @"\01??$Foo@$0A@@Type@ClassScopeSpecialization@@QAEXXZ"
+// X64: call {{.*}} @"\01??$Foo@$0A@@Type@ClassScopeSpecialization@@QEAAXXZ"
+ T.Foo<0>();
+ }
+}
diff --git a/test/CodeGenCXX/delete-two-arg.cpp b/test/CodeGenCXX/delete-two-arg.cpp
index b82e9ba63ddc..f8e6bff29580 100644
--- a/test/CodeGenCXX/delete-two-arg.cpp
+++ b/test/CodeGenCXX/delete-two-arg.cpp
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s
+// RUN: not %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s
typedef __typeof(sizeof(int)) size_t;
namespace test1 {
struct A { void operator delete(void*,size_t); int x; };
- // CHECK: define void @_ZN5test11aEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN5test11aEPNS_1AE(
void a(A *x) {
// CHECK: load
// CHECK-NEXT: icmp eq {{.*}}, null
@@ -35,7 +35,7 @@ namespace test2 {
return ::new A[10];
}
- // CHECK: define void @_ZN5test24testEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN5test24testEPNS_1AE(
void test(A *p) {
// CHECK: [[P:%.*]] = alloca [[A]]*, align 4
// CHECK-NEXT: store [[A]]* {{%.*}}, [[A]]** [[P]], align 4
@@ -60,7 +60,7 @@ namespace test3 {
};
struct B : A {};
- // CHECK: define void @_ZN5test34testEv()
+ // CHECK-LABEL: define void @_ZN5test34testEv()
void test() {
// CHECK: call noalias i8* @_Znaj(i32 24)
// CHECK-NEXT: bitcast
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 1299b29a03a8..cdd5a89963e4 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -19,7 +19,7 @@ struct T {
int a;
};
-// CHECK: define void @_Z2t4P1T
+// CHECK-LABEL: define void @_Z2t4P1T
void t4(T *t) {
// CHECK: call void @_ZN1TD1Ev
// CHECK-NEXT: bitcast
@@ -46,7 +46,7 @@ namespace test0 {
~A() {}
};
- // CHECK: define void @_ZN5test04testEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN5test04testEPNS_1AE(
void test(A *a) {
// CHECK: call void @_ZN5test01AD1Ev
// CHECK-NEXT: bitcast
@@ -54,8 +54,8 @@ namespace test0 {
delete a;
}
- // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr
- // CHECK: define linkonce_odr void @_ZN5test01AdlEPv
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01AdlEPv
}
namespace test1 {
@@ -64,7 +64,7 @@ namespace test1 {
~A();
};
- // CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE(
+ // CHECK-LABEL: define void @_ZN5test14testEPA10_A20_NS_1AE(
void test(A (*arr)[10][20]) {
delete [] arr;
// CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null
@@ -88,7 +88,7 @@ namespace test1 {
}
namespace test2 {
- // CHECK: define void @_ZN5test21fEPb
+ // CHECK-LABEL: define void @_ZN5test21fEPb
void f(bool *b) {
// CHECK: call void @_ZdlPv(i8*
delete b;
@@ -111,7 +111,7 @@ namespace test4 {
void operator delete (void *);
};
- // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE
+ // CHECK-LABEL: define void @_ZN5test421global_delete_virtualEPNS_1XE
void global_delete_virtual(X *xp) {
// Load the offset-to-top from the vtable and apply it.
// This has to be done first because the dtor can mess it up.
@@ -136,7 +136,7 @@ namespace test4 {
namespace test5 {
struct Incomplete;
- // CHECK: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_
+ // CHECK-LABEL: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_
void array_delete_incomplete(Incomplete *p1, Incomplete *p2) {
// CHECK: call void @_ZdlPv
delete p1;
@@ -145,4 +145,4 @@ namespace test5 {
}
}
-// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp
index 9b15c6804dfc..675c50c42328 100644
--- a/test/CodeGenCXX/derived-to-base-conv.cpp
+++ b/test/CodeGenCXX/derived-to-base-conv.cpp
@@ -31,7 +31,7 @@ struct X {
void test0_helper(A);
void test0(X x) {
test0_helper(x);
- // CHECK: define void @_Z5test01X(
+ // CHECK-LABEL: define void @_Z5test01X(
// CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align
// CHECK-NEXT: [[T0:%.*]] = call [[B:%.*]]* @_ZN1XcvR1BEv(
// CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]* [[T0]] to [[A]]*
@@ -60,7 +60,7 @@ struct Derived : Base {
void test1_helper(Base);
void test1(Derived bb) {
- // CHECK: define void @_Z5test17Derived(
+ // CHECK-LABEL: define void @_Z5test17Derived(
// CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv(
// CHECK: call void @_ZN4BaseC1ERKS_(
// CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv(
@@ -75,7 +75,7 @@ class Test2a {};
class Test2b final : public virtual Test2a {};
void test2(Test2b &x) {
Test2a &y = x;
- // CHECK: define void @_Z5test2R6Test2b(
+ // CHECK-LABEL: define void @_Z5test2R6Test2b(
// CHECK: [[X:%.*]] = alloca [[B:%.*]]*, align 8
// CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]]*, align 8
// CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]], align 8
diff --git a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
index 0e153022439b..f2ecfc1d38cc 100644
--- a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
+++ b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
@@ -9,7 +9,7 @@ struct D final : virtual C {
virtual void f();
};
-// CHECK: define %struct.B* @_Z1fR1D
+// CHECK-LABEL: define %struct.B* @_Z1fR1D
B &f(D &d) {
// CHECK-NOT: load i8**
return d;
diff --git a/test/CodeGenCXX/destructor-exception-spec.cpp b/test/CodeGenCXX/destructor-exception-spec.cpp
index 579daef8541f..e111ba0ba8e5 100644
--- a/test/CodeGenCXX/destructor-exception-spec.cpp
+++ b/test/CodeGenCXX/destructor-exception-spec.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -emit-llvm-only %s -std=c++11
+// RUN: %clang_cc1 -emit-llvm-only -fno-use-cxa-atexit %s -std=c++11
+// RUN: %clang_cc1 -cxx-abi microsoft -fno-rtti -emit-llvm-only %s -std=c++11
// PR13479: don't crash with -fno-exceptions.
namespace {
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index 7dc188ba94b5..799cca28b4a4 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -1,14 +1,10 @@
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-optzns | FileCheck %s
-// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
-// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
-
-// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
-// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
-// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+// CHECK-DAG: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
+// CHECK-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
struct A {
int a;
@@ -40,13 +36,13 @@ namespace PR7526 {
struct allocator_derived : allocator { };
- // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN6PR75263fooEv()
+ // CHECK: call void {{.*}} @_ZN6PR75269allocatorD2Ev
+
+ // CHECK-LABEL: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr
// CHECK: call void @__cxa_call_unexpected
allocator::~allocator() throw() { foo(); }
- // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr
- // CHECK-NOT: call void @__cxa_call_unexpected
- // CHECK: }
void foo() {
allocator_derived ad;
}
@@ -93,7 +89,7 @@ namespace test0 {
// complete destructor alias tested above
-// CHECK: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test06MemberD1Ev
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
// CHECK: invoke void @_ZN5test04BaseD2Ev
@@ -106,7 +102,7 @@ namespace test0 {
B::~B() try { } catch (int i) {}
// It will suppress the delegation optimization here, though.
-// CHECK: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test06MemberD1Ev
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
// CHECK: invoke void @_ZN5test04BaseD2Ev
@@ -114,7 +110,7 @@ namespace test0 {
// CHECK: invoke void @_ZN5test05VBaseD2Ev
// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]]
-// CHECK: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr
+// CHECK-LABEL: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr
// CHECK: invoke void @_ZN5test06MemberD1Ev
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
// CHECK: invoke void @_ZN5test04BaseD2Ev
@@ -142,24 +138,24 @@ namespace test1 {
O::~O() {} // alias tested above
struct P : NonEmpty, A { ~P(); };
- P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr
+ P::~P() {} // CHECK-LABEL: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr
struct Q : A, B { ~Q(); };
- Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr
+ Q::~Q() {} // CHECK-LABEL: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr
struct R : A { ~R(); };
- R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr
+ R::~R() { A a; } // CHECK-LABEL: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr
struct S : A { ~S(); int x; };
S::~S() {} // alias tested above
struct T : A { ~T(); B x; };
- T::~T() {} // CHECK: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr
+ T::~T() {} // CHECK-LABEL: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr
// The VTT parameter prevents this. We could still make this work
// for calling conventions that are safe against extra parameters.
struct U : A, virtual B { ~U(); };
- U::~U() {} // CHECK: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr
+ U::~U() {} // CHECK-LABEL: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr
}
// PR6471
@@ -168,7 +164,7 @@ namespace test2 {
struct B : A { ~B(); };
B::~B() {}
- // CHECK: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr
// CHECK: call void @_ZN5test21AD2Ev
}
@@ -184,18 +180,12 @@ namespace test3 {
void test() {
new D; // Force emission of D's vtable
}
-
- // Checked at top of file:
- // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
-
- // More checks at end of file.
-
}
namespace test4 {
struct A { ~A(); };
- // CHECK: define void @_ZN5test43fooEv()
+ // CHECK-LABEL: define void @_ZN5test43fooEv()
// CHECK: call void @_ZN5test41AD1Ev
// CHECK: ret void
void foo() {
@@ -208,7 +198,7 @@ namespace test4 {
return;
}
- // CHECK: define void @_ZN5test43barEi(
+ // CHECK-LABEL: define void @_ZN5test43barEi(
// CHECK: [[X:%.*]] = alloca i32
// CHECK-NEXT: [[A:%.*]] = alloca
// CHECK: br label
@@ -233,7 +223,7 @@ namespace test4 {
namespace test5 {
struct A { ~A(); };
- // CHECK: define void @_ZN5test53fooEv()
+ // CHECK-LABEL: define void @_ZN5test53fooEv()
// CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
// CHECK-NEXT: [[SEL:%.*]] = alloca i32
@@ -272,7 +262,7 @@ namespace test6 {
};
C::C() { opaque(); }
- // CHECK: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr
// CHECK: call void @_ZN5test61BILj2EEC2Ev
// CHECK: invoke void @_ZN5test61BILj3EEC2Ev
// CHECK: invoke void @_ZN5test61BILj0EEC2Ev
@@ -282,7 +272,7 @@ namespace test6 {
// FIXME: way too much EH cleanup code follows
C::~C() { opaque(); }
- // CHECK: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test61CD2Ev
// CHECK: invoke void @_ZN5test61BILj3EED2Ev
// CHECK: call void @_ZN5test61BILj2EED2Ev
@@ -290,7 +280,7 @@ namespace test6 {
// CHECK: invoke void @_ZN5test61BILj3EED2Ev
// CHECK: invoke void @_ZN5test61BILj2EED2Ev
- // CHECK: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr
// CHECK: invoke void @_ZN5test66opaqueEv
// CHECK: invoke void @_ZN5test61AD1Ev
// CHECK: invoke void @_ZN5test61AD1Ev
@@ -318,7 +308,7 @@ namespace test7 {
};
// Verify that this doesn't get emitted as an alias
- // CHECK: define void @_ZN5test71BD2Ev(
+ // CHECK-LABEL: define void @_ZN5test71BD2Ev(
// CHECK: invoke void @_ZN5test71DD1Ev(
// CHECK: call void @_ZN5test71AD2Ev(
B::~B() {}
@@ -338,7 +328,7 @@ namespace test8 {
l: die();
}
- // CHECK: define void @_ZN5test84testEv()
+ // CHECK-LABEL: define void @_ZN5test84testEv()
// CHECK: [[X:%.*]] = alloca [[A:%.*]], align 1
// CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1
// CHECK: call void @_ZN5test81AC1Ev([[A]]* [[X]])
@@ -366,10 +356,26 @@ namespace test9 {
// CHECK: call void @_ZN5test92f2Ev()
}
+namespace test10 {
+ // We used to crash trying to replace _ZN6test106OptionD1Ev with
+ // _ZN6test106OptionD2Ev twice.
+ struct Option {
+ virtual ~Option() {}
+ };
+ template <class DataType> class opt : public Option {};
+ template class opt<int>;
+ // CHECK-LABEL: define zeroext i1 @_ZN6test1016handleOccurrenceEv(
+ bool handleOccurrence() {
+ // CHECK: call void @_ZN6test106OptionD2Ev(
+ Option x;
+ return true;
+ }
+}
+
// Checks from test3:
- // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr
- // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev(
+ // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr
+ // CHECK: invoke void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
// CHECK: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]]
// CHECK: ret void
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
@@ -377,21 +383,22 @@ namespace test9 {
// CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: resume { i8*, i32 }
- // Checked at top of file:
- // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
- // @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
-
- // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
+ // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev(
+ // CHECK: call void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
// CHECK: ret void
- // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
+ // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
// CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev(
// CHECK: ret void
- // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr
+ // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11CD2Ev(
+ // CHECK: ret void
+
+ // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test31BD2Ev(
// CHECK: call void @_ZN5test31AD2Ev(
// CHECK: ret void
@@ -399,8 +406,8 @@ namespace test9 {
// CHECK: declare void @_ZN5test31BD2Ev(
// CHECK: declare void @_ZN5test31AD2Ev(
- // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr
- // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev(
+ // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr
+ // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev(
// CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: ret void
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
@@ -408,14 +415,9 @@ namespace test9 {
// CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: resume { i8*, i32 }
- // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
- // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev(
- // CHECK: ret void
-
- // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
+ // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
// CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
// CHECK: ret void
- // CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+ // CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
index 40f3cada7d46..11026e8df3e7 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -5,7 +5,7 @@ namespace Test1 {
virtual int f() final;
};
- // CHECK: define i32 @_ZN5Test11fEPNS_1AE
+ // CHECK-LABEL: define i32 @_ZN5Test11fEPNS_1AE
int f(A *a) {
// CHECK: call i32 @_ZN5Test11A1fEv
return a->f();
@@ -17,7 +17,7 @@ namespace Test2 {
virtual int f();
};
- // CHECK: define i32 @_ZN5Test21fEPNS_1AE
+ // CHECK-LABEL: define i32 @_ZN5Test21fEPNS_1AE
int f(A *a) {
// CHECK: call i32 @_ZN5Test21A1fEv
return a->f();
@@ -31,19 +31,19 @@ namespace Test3 {
struct B final : A { };
- // CHECK: define i32 @_ZN5Test31fEPNS_1BE
+ // CHECK-LABEL: define i32 @_ZN5Test31fEPNS_1BE
int f(B *b) {
// CHECK: call i32 @_ZN5Test31A1fEv
return b->f();
}
- // CHECK: define i32 @_ZN5Test31fERNS_1BE
+ // CHECK-LABEL: define i32 @_ZN5Test31fERNS_1BE
int f(B &b) {
// CHECK: call i32 @_ZN5Test31A1fEv
return b.f();
}
- // CHECK: define i32 @_ZN5Test31fEPv
+ // CHECK-LABEL: define i32 @_ZN5Test31fEPv
int f(void *v) {
// CHECK: call i32 @_ZN5Test31A1fEv
return static_cast<B*>(v)->f();
@@ -59,7 +59,7 @@ namespace Test4 {
virtual void f();
};
- // CHECK: define void @_ZN5Test41fEPNS_1BE
+ // CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE
void f(B* d) {
// CHECK: call void @_ZN5Test41B1fEv
static_cast<A*>(d)->f();
@@ -78,7 +78,7 @@ namespace Test5 {
struct C final : B {
};
- // CHECK: define void @_ZN5Test51fEPNS_1CE
+ // CHECK-LABEL: define void @_ZN5Test51fEPNS_1CE
void f(C* d) {
// FIXME: It should be possible to devirtualize this case, but that is
// not implemented yet.
@@ -105,7 +105,7 @@ namespace Test6 {
struct D final : public C, public B {
};
- // CHECK: define void @_ZN5Test61fEPNS_1DE
+ // CHECK-LABEL: define void @_ZN5Test61fEPNS_1DE
void f(D* d) {
// CHECK: call void @_ZN5Test61DD1Ev
static_cast<A*>(d)->~A();
@@ -126,7 +126,7 @@ namespace Test7 {
virtual int f() {return z;}
};
- // CHECK: define i32 @_ZN5Test71fEPNS_3zedE
+ // CHECK-LABEL: define i32 @_ZN5Test71fEPNS_3zedE
int f(zed *z) {
// CHECK: alloca
// CHECK-NEXT: store
@@ -144,7 +144,7 @@ namespace Test8 {
virtual int foo() { return b; }
};
struct C final : A, B { };
- // CHECK: define i32 @_ZN5Test84testEPNS_1CE
+ // CHECK-LABEL: define i32 @_ZN5Test84testEPNS_1CE
int test(C *c) {
// CHECK: %[[THIS:.*]] = phi
// CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]])
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index 52f1cd3fa236..911ddeedd236 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -79,7 +79,7 @@ namespace test3 {
struct D : public B {
};
void f(D d) {
- // CHECK: define void @_ZN5test31fENS_1DE
+ // CHECK-LABEL: define void @_ZN5test31fENS_1DE
d.B::~B();
}
}
diff --git a/test/CodeGenCXX/dynamic_cast-no-rtti.cpp b/test/CodeGenCXX/dynamic_cast-no-rtti.cpp
new file mode 100644
index 000000000000..0e26de5bcf8b
--- /dev/null
+++ b/test/CodeGenCXX/dynamic_cast-no-rtti.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm %s -verify -fno-rtti -o - | FileCheck %s
+// expected-no-diagnostics
+
+struct A {
+ virtual ~A(){};
+};
+
+struct B : public A {
+ B() : A() {}
+};
+
+// An upcast can be resolved statically and can be used with -fno-rtti, iff it
+// does not use runtime support.
+A *upcast(B *b) {
+ return dynamic_cast<A *>(b);
+// CHECK-LABEL: define %struct.A* @_Z6upcastP1B
+// CHECK-NOT: call i8* @__dynamic_cast
+}
+
+// A NoOp dynamic_cast can be used with -fno-rtti iff it does not use
+// runtime support.
+B *samecast(B *b) {
+ return dynamic_cast<B *>(b);
+// CHECK-LABEL: define %struct.B* @_Z8samecastP1B
+// CHECK-NOT: call i8* @__dynamic_cast
+}
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 70887f7718d0..2a61e61bb818 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -9,7 +9,7 @@ void test1() {
throw d1;
}
-// CHECK: define void @_Z5test1v()
+// CHECK-LABEL: define void @_Z5test1v()
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
@@ -29,7 +29,7 @@ void test2() {
throw d2;
}
-// CHECK: define void @_Z5test2v()
+// CHECK-LABEL: define void @_Z5test2v()
// CHECK: [[EXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
@@ -51,7 +51,7 @@ void test3() {
throw (volatile test3_D *)0;
}
-// CHECK: define void @_Z5test3v()
+// CHECK-LABEL: define void @_Z5test3v()
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]**
// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]]
@@ -63,7 +63,7 @@ void test4() {
throw;
}
-// CHECK: define void @_Z5test4v()
+// CHECK-LABEL: define void @_Z5test4v()
// CHECK: call void @__cxa_rethrow() [[NR]]
// CHECK-NEXT: unreachable
@@ -79,7 +79,7 @@ namespace test5 {
void test() {
try { throw A(); } catch (A &x) {}
}
-// CHECK: define void @_ZN5test54testEv()
+// CHECK-LABEL: define void @_ZN5test54testEv()
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1)
// CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]*
// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]])
@@ -101,7 +101,7 @@ namespace test6 {
// PR7127
namespace test7 {
-// CHECK: define i32 @_ZN5test73fooEv()
+// CHECK-LABEL: define i32 @_ZN5test73fooEv()
int foo() {
// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
@@ -160,7 +160,7 @@ namespace test8 {
struct A { A(const A&); ~A(); };
void bar();
- // CHECK: define void @_ZN5test83fooEv()
+ // CHECK-LABEL: define void @_ZN5test83fooEv()
void foo() {
try {
// CHECK: invoke void @_ZN5test83barEv()
@@ -184,11 +184,11 @@ namespace test9 {
struct A { A(); };
- // CHECK: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr
// CHECK: call void @_ZN5test91AC2Ev
// CHECK-NEXT: ret void
- // CHECK: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr
A::A() try {
// CHECK: invoke void @_ZN5test96opaqueEv()
opaque();
@@ -210,7 +210,7 @@ namespace test10 {
struct A { ~A(); };
struct B { int x; };
- // CHECK: define void @_ZN6test103fooEv()
+ // CHECK-LABEL: define void @_ZN6test103fooEv()
void foo() {
A a; // force a cleanup context
@@ -244,7 +244,7 @@ namespace test10 {
namespace test11 {
void opaque();
- // CHECK: define void @_ZN6test113fooEv()
+ // CHECK-LABEL: define void @_ZN6test113fooEv()
void foo() {
try {
// CHECK: invoke void @_ZN6test116opaqueEv()
@@ -261,7 +261,7 @@ namespace test11 {
struct A {};
- // CHECK: define void @_ZN6test113barEv()
+ // CHECK-LABEL: define void @_ZN6test113barEv()
void bar() {
try {
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
@@ -286,7 +286,7 @@ namespace test12 {
struct A { ~A() noexcept(false); };
bool opaque(const A&);
- // CHECK: define void @_ZN6test124testEv()
+ // CHECK-LABEL: define void @_ZN6test124testEv()
void test() {
// CHECK: [[X:%.*]] = alloca [[A:%.*]],
// CHECK: [[EHCLEANUPDEST:%.*]] = alloca i32
@@ -371,7 +371,7 @@ namespace test15 {
bool opaque(int);
- // CHECK: define void @_ZN6test153fooEv()
+ // CHECK-LABEL: define void @_ZN6test153fooEv()
void foo() {
A a;
@@ -405,7 +405,7 @@ namespace test16 {
void foo();
bool cond();
- // CHECK: define void @_ZN6test163barEv()
+ // CHECK-LABEL: define void @_ZN6test163barEv()
void bar() {
// CHECK: [[EXN_SAVE:%.*]] = alloca i8*
// CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1
diff --git a/test/CodeGenCXX/empty-classes.cpp b/test/CodeGenCXX/empty-classes.cpp
index 1ce1dad40ffa..8491480bcf54 100644
--- a/test/CodeGenCXX/empty-classes.cpp
+++ b/test/CodeGenCXX/empty-classes.cpp
@@ -29,7 +29,7 @@ struct D : A, Empty {
#define CHECK(x) if (!(x)) return __LINE__
// PR7012
-// CHECK: define i32 @_Z1fv()
+// CHECK-LABEL: define i32 @_Z1fv()
int f() {
B b1;
diff --git a/test/CodeGenCXX/empty-nontrivially-copyable.cpp b/test/CodeGenCXX/empty-nontrivially-copyable.cpp
new file mode 100644
index 000000000000..9ee3281505ec
--- /dev/null
+++ b/test/CodeGenCXX/empty-nontrivially-copyable.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple armv7-apple-ios -x c++ -emit-llvm -o - %s | FileCheck %s
+
+// According to the Itanium ABI (3.1.1), types with non-trivial copy
+// constructors passed by value should be passed indirectly, with the caller
+// creating a temporary.
+
+struct Empty;
+
+struct Empty {
+ Empty(const Empty &e);
+ bool check();
+};
+
+bool foo(Empty e) {
+// CHECK: @_Z3foo5Empty(%struct.Empty* %e)
+// CHECK: call {{.*}} @_ZN5Empty5checkEv(%struct.Empty* %e)
+ return e.check();
+}
+
+void caller(Empty &e) {
+// CHECK: @_Z6callerR5Empty(%struct.Empty* %e)
+// CHECK: call {{.*}} @_ZN5EmptyC1ERKS_(%struct.Empty* [[NEWTMP:%.*]], %struct.Empty*
+// CHECK: call {{.*}} @_Z3foo5Empty(%struct.Empty* [[NEWTMP]])
+ foo(e);
+}
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index f6f5079791ab..d37e6109db4a 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -269,7 +269,7 @@ namespace test5 {
void foo();
- // CHECK: define void @_ZN5test54testEv()
+ // CHECK-LABEL: define void @_ZN5test54testEv()
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
// CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1
@@ -403,7 +403,7 @@ namespace test8 {
void test() {
throw makeA();
}
- // CHECK: define void @_ZN5test84testEv
+ // CHECK-LABEL: define void @_ZN5test84testEv
}
// Make sure we generate the correct code for the delete[] call which
@@ -432,14 +432,14 @@ namespace test10 {
struct A { ~A(); };
A::~A() try { cleanup(); } catch (...) { return; }
- // CHECK: define void @_ZN6test101AD1Ev(
+ // CHECK-LABEL: define void @_ZN6test101AD1Ev(
// CHECK: invoke void @_ZN6test107cleanupEv()
// CHECK-NOT: rethrow
// CHECK: ret void
struct B { ~B(); };
B::~B() try { cleanup(); } catch (...) {}
- // CHECK: define void @_ZN6test101BD1Ev(
+ // CHECK-LABEL: define void @_ZN6test101BD1Ev(
// CHECK: invoke void @_ZN6test107cleanupEv()
// CHECK: call i8* @__cxa_begin_catch
// CHECK-NEXT: invoke void @__cxa_rethrow()
@@ -447,7 +447,7 @@ namespace test10 {
struct C { ~C(); };
C::~C() try { cleanup(); } catch (...) { if (suppress) return; }
- // CHECK: define void @_ZN6test101CD1Ev(
+ // CHECK-LABEL: define void @_ZN6test101CD1Ev(
// CHECK: invoke void @_ZN6test107cleanupEv()
// CHECK: call i8* @__cxa_begin_catch
// CHECK-NEXT: load i8* @_ZN6test108suppressE, align 1
@@ -477,7 +477,7 @@ namespace test11 {
C::C() {
throw 0;
}
- // CHECK: define void @_ZN6test111CC2Ev(
+ // CHECK-LABEL: define void @_ZN6test111CC2Ev(
// CHECK: [[THIS:%.*]] = load [[C:%.*]]** {{%.*}}
// Construct single.
// CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 0
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index 8daf3c680006..6a4fd822122f 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -13,7 +13,7 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
return t + u;
}
-// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
+// CHECK-LABEL: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
template struct plus<int, long, long>;
// Check that we emit definitions from explicit instantiations even when they
@@ -27,16 +27,16 @@ template <typename T> struct S {
};
};
-// CHECK: define weak_odr void @_ZN1SIiE1fEv
+// CHECK-LABEL: define weak_odr void @_ZN1SIiE1fEv
template void S<int>::f();
-// CHECK: define weak_odr void @_ZN1SIiE1gEv
+// CHECK-LABEL: define weak_odr void @_ZN1SIiE1gEv
template void S<int>::g();
// See the check line at the top of the file.
template int S<int>::i;
-// CHECK: define weak_odr void @_ZN1SIiE2S21hEv
+// CHECK-LABEL: define weak_odr void @_ZN1SIiE2S21hEv
template void S<int>::S2::h();
template <typename T> void S<T>::f() {}
diff --git a/test/CodeGenCXX/fastcall.cpp b/test/CodeGenCXX/fastcall.cpp
index c0a910667274..0326ce53bc4a 100644
--- a/test/CodeGenCXX/fastcall.cpp
+++ b/test/CodeGenCXX/fastcall.cpp
@@ -2,7 +2,7 @@
void __attribute__((fastcall)) foo1(int &y);
void bar1(int &y) {
- // CHECK: define void @_Z4bar1Ri
+ // CHECK-LABEL: define void @_Z4bar1Ri
// CHECK: call x86_fastcallcc void @_Z4foo1Ri(i32* inreg %
foo1(y);
}
@@ -14,7 +14,7 @@ struct S1 {
void __attribute__((fastcall)) foo2(S1 a, int b);
void bar2(S1 a, int b) {
- // CHECK: define void @_Z4bar22S1i
+ // CHECK-LABEL: define void @_Z4bar22S1i
// CHECK: call x86_fastcallcc void @_Z4foo22S1i(%struct.S1* inreg %{{.*}}, i32 inreg %
foo2(a, b);
}
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
index 926fe445a5ba..8124129713f0 100644
--- a/test/CodeGenCXX/for-range.cpp
+++ b/test/CodeGenCXX/for-range.cpp
@@ -32,7 +32,7 @@ B *end(C&);
extern B array[5];
-// CHECK: define void @_Z9for_arrayv(
+// CHECK-LABEL: define void @_Z9for_arrayv(
void for_array() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
@@ -40,7 +40,7 @@ void for_array() {
// CHECK-NOT: 5begin
// CHECK-NOT: 3end
// CHECK: getelementptr {{.*}}, i32 0
- // CHECK: getelementptr {{.*}}, i64 1, i64 0
+ // CHECK: getelementptr {{.*}}, i64 5
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
@@ -61,7 +61,7 @@ void for_array() {
// CHECK: ret void
}
-// CHECK: define void @_Z9for_rangev(
+// CHECK-LABEL: define void @_Z9for_rangev(
void for_range() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
@@ -93,7 +93,7 @@ void for_range() {
// CHECK: ret void
}
-// CHECK: define void @_Z16for_member_rangev(
+// CHECK-LABEL: define void @_Z16for_member_rangev(
void for_member_range() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
diff --git a/test/CodeGenCXX/forward-enum.cpp b/test/CodeGenCXX/forward-enum.cpp
index c1169e013994..685e4f31cc61 100644
--- a/test/CodeGenCXX/forward-enum.cpp
+++ b/test/CodeGenCXX/forward-enum.cpp
@@ -3,7 +3,7 @@
enum MyEnum : char;
void bar(MyEnum value) { }
-// CHECK: define void @_Z3foo6MyEnum
+// CHECK-LABEL: define void @_Z3foo6MyEnum
void foo(MyEnum value)
{
// CHECK: call void @_Z3bar6MyEnum(i8 signext
diff --git a/test/CodeGenCXX/fp16-mangle.cpp b/test/CodeGenCXX/fp16-mangle.cpp
index 4a056d6c6bbb..bd5a3194112c 100644
--- a/test/CodeGenCXX/fp16-mangle.cpp
+++ b/test/CodeGenCXX/fp16-mangle.cpp
@@ -4,9 +4,9 @@
template <typename T, typename U> struct S { static int i; };
template <> int S<__fp16, __fp16>::i = 3;
-// CHECK: define void @_Z1fPDh(i16* %x)
+// CHECK-LABEL: define void @_Z1fPDh(i16* %x)
void f (__fp16 *x) { }
-// CHECK: define void @_Z1gPDhS_(i16* %x, i16* %y)
+// CHECK-LABEL: define void @_Z1gPDhS_(i16* %x, i16* %y)
void g (__fp16 *x, __fp16 *y) { }
diff --git a/test/CodeGenCXX/function-template-explicit-specialization.cpp b/test/CodeGenCXX/function-template-explicit-specialization.cpp
index 21f0127ab489..5d26dcd61cf0 100644
--- a/test/CodeGenCXX/function-template-explicit-specialization.cpp
+++ b/test/CodeGenCXX/function-template-explicit-specialization.cpp
@@ -3,11 +3,11 @@
template<typename T> void a(T);
template<> void a(int) {}
-// CHECK: define void @_Z1aIiEvT_
+// CHECK-LABEL: define void @_Z1aIiEvT_
namespace X {
template<typename T> void b(T);
template<> void b(int) {}
}
-// CHECK: define void @_ZN1X1bIiEEvT_
+// CHECK-LABEL: define void @_ZN1X1bIiEEvT_
diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp
index 087d655f0a27..6ebc13953f67 100644
--- a/test/CodeGenCXX/global-array-destruction.cpp
+++ b/test/CodeGenCXX/global-array-destruction.cpp
@@ -56,7 +56,7 @@ using U = T[2][3];
U &&u = U{ {{1.0, 2}, {3.0, 4}, {5.0, 6}}, {{7.0, 8}, {9.0, 10}, {11.0, 12}} };
// CHECK: call {{.*}} @__cxa_atexit
-// CHECK: getelementptr inbounds ([2 x [3 x {{.*}}]]* @_ZGR1u, i64 1, i64 0, i64 0)
+// CHECK: getelementptr inbounds ({{.*}}* getelementptr inbounds ([2 x [3 x {{.*}}]]* @_ZGR1u, i32 0, i32 0, i32 0), i64 6)
// CHECK: call void @_ZN1TD1Ev
// CHECK: icmp eq {{.*}} @_ZGR1u
// CHECK: br i1 {{.*}}
diff --git a/test/CodeGenCXX/global-block-literal-helpers.cpp b/test/CodeGenCXX/global-block-literal-helpers.cpp
index 350ea548662c..762b5d9910df 100644
--- a/test/CodeGenCXX/global-block-literal-helpers.cpp
+++ b/test/CodeGenCXX/global-block-literal-helpers.cpp
@@ -5,23 +5,23 @@ namespace N {
typedef void (^BL)();
int func(BL, BL, BL);
-// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke(
-// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_2(
-// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_3
+// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke(
+// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke_2(
+// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke_3
BL ArrBlock [] = { ^{}, ^{}, ^{} };
-// CHECK: define internal void @_ZN1N4ivalE_block_invoke_4(
-// CHECK: define internal void @_ZN1N4ivalE_block_invoke_5(
-// CHECK: define internal void @_ZN1N4ivalE_block_invoke_6(
+// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_4(
+// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_5(
+// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_6(
int ival = func(^{}, ^{}, ^{});
-// CHECK: define internal void @_ZN1N9gvarlobalE_block_invoke_7(
+// CHECK-LABEL: define internal void @_ZN1N9gvarlobalE_block_invoke_7(
void (^gvarlobal)(void) = ^{};
struct S {
BL field = ^{};
};
-// CHECK: define internal void @_ZN1N3blfE_block_invoke_8(
+// CHECK-LABEL: define internal void @_ZN1N3blfE_block_invoke_8(
S blf;
};
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
index 7c4b6aa1e05f..9d35e848e3ca 100644
--- a/test/CodeGenCXX/global-dtor-no-atexit.cpp
+++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -22,7 +22,7 @@ public:
A a, b;
// PR9593
-// CHECK: define void @_Z4funcv()
+// CHECK-LABEL: define void @_Z4funcv()
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a1)
// CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a1)
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a1)
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 426cf9c10e3a..69631c278905 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - |FileCheck %s
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck -check-prefix NOEXC %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck -check-prefix CHECK-NOEXC %s
struct A {
A();
@@ -45,7 +45,7 @@ namespace test1 {
const int y = x - 1; // This gets deferred.
const int z = ~y; // This also gets deferred, but gets "undeferred" before y.
int test() { return z; }
-// CHECK: define i32 @_ZN5test14testEv()
+// CHECK-LABEL: define i32 @_ZN5test14testEv()
// All of these initializers end up delayed, so we check them later.
}
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index 77b6166aff41..904f95fb22be 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -5,7 +5,7 @@ namespace test0 {
struct A { A(); ~A(); };
struct V { V(const A &a = A()); ~V(); };
- // CHECK: define linkonce_odr i32 @_ZN5test04testILi0EEEii
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN5test04testILi0EEEii
template<int X> int test(int x) {
// CHECK: [[RET:%.*]] = alloca i32
// CHECK-NEXT: [[X:%.*]] = alloca i32
diff --git a/test/CodeGenCXX/implicit-copy-assign-operator.cpp b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
index 79586fba9af1..267402122f82 100644
--- a/test/CodeGenCXX/implicit-copy-assign-operator.cpp
+++ b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
@@ -40,7 +40,7 @@ void test_D(D d1, D d2) {
d1 = d2;
}
-// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_
+// CHECK-LABEL: define linkonce_odr %struct.D* @_ZN1DaSERS_
// CHECK: {{call.*_ZN1AaSERS_}}
// CHECK: {{call.*_ZN1BaSERS_}}
// CHECK: {{call.*_ZN1CaSERKS_}}
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
index 24e84d57b13d..bb04318e7307 100644
--- a/test/CodeGenCXX/implicit-copy-constructor.cpp
+++ b/test/CodeGenCXX/implicit-copy-constructor.cpp
@@ -40,7 +40,7 @@ void f(D d) {
D d2(d);
}
-// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr
// CHECK: call void @_ZN1AC1Ev
// CHECK: call void @_ZN1CC2ERS_1A
// CHECK: call void @_ZN1AD1Ev
diff --git a/test/CodeGenCXX/implicit-instantiation-1.cpp b/test/CodeGenCXX/implicit-instantiation-1.cpp
index 0c826e4b20d1..bf6a14150892 100644
--- a/test/CodeGenCXX/implicit-instantiation-1.cpp
+++ b/test/CodeGenCXX/implicit-instantiation-1.cpp
@@ -20,7 +20,7 @@ void foo(X<int> &xi, X<float> *xfp, int i, float f) {
// RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1
xfp->f(f);
- // RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0
+ // RUN: not grep "linkonce_odr.*_ZN1XIfE1hEf" %t
}
diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp
index 0f3978492976..c99a20c730e4 100644
--- a/test/CodeGenCXX/inheriting-constructor.cpp
+++ b/test/CodeGenCXX/inheriting-constructor.cpp
@@ -11,18 +11,18 @@ struct C { template<typename T> C(T); };
struct D : C { using C::C; };
D d(123);
-// CHECK: define void @_ZN1BD0Ev
-// CHECK: define void @_ZN1BD1Ev
-// CHECK: define void @_ZN1BD2Ev
+// CHECK-LABEL: define void @_ZN1BD0Ev
+// CHECK-LABEL: define void @_ZN1BD1Ev
+// CHECK-LABEL: define void @_ZN1BD2Ev
-// CHECK: define linkonce_odr void @_ZN1BC1Ei(
+// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ei(
// CHECK: call void @_ZN1BC2Ei(
-// CHECK: define linkonce_odr void @_ZN1DC1IiEET_(
+// CHECK-LABEL: define linkonce_odr void @_ZN1DC1IiEET_(
// CHECK: call void @_ZN1DC2IiEET_(
-// CHECK: define linkonce_odr void @_ZN1DC2IiEET_(
+// CHECK-LABEL: define linkonce_odr void @_ZN1DC2IiEET_(
// CHECK: call void @_ZN1CC2IiEET_(
-// CHECK: define linkonce_odr void @_ZN1BC2Ei(
+// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ei(
// CHECK: call void @_ZN1AC2Ei(
diff --git a/test/CodeGenCXX/init-invariant.cpp b/test/CodeGenCXX/init-invariant.cpp
index 9eb19896b6bb..45816b28fb65 100644
--- a/test/CodeGenCXX/init-invariant.cpp
+++ b/test/CodeGenCXX/init-invariant.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O0 -o - | FileCheck %s --check-prefix=CHECK-O0
+// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-O0
// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O1 -o - | FileCheck %s
// Check that we add an llvm.invariant.start to mark when a global becomes
@@ -54,7 +54,7 @@ void e() {
// CHECK: store {{.*}}, i32* @d
// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @d to i8*))
-// CHECK: define void @_Z1ev(
+// CHECK-LABEL: define void @_Z1ev(
// CHECK: call void @_ZN1AC1Ev(%struct.A* @_ZZ1evE1a)
// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @_ZZ1evE1a to i8*))
// CHECK-NOT: llvm.invariant.end
diff --git a/test/CodeGenCXX/inline-functions.cpp b/test/CodeGenCXX/inline-functions.cpp
index 8c011de28a02..9f8e536a3b0c 100644
--- a/test/CodeGenCXX/inline-functions.cpp
+++ b/test/CodeGenCXX/inline-functions.cpp
@@ -5,7 +5,7 @@ struct A {
inline void f();
};
-// CHECK-NOT: define void @_ZN1A1fEv
+// CHECK-NOT-LABEL: define void @_ZN1A1fEv
void A::f() { }
template<typename> struct B { };
@@ -19,13 +19,13 @@ void B<char>::f() { }
// We need a final CHECK line here.
-// CHECK: define void @_Z1fv
+// CHECK-LABEL: define void @_Z1fv
void f() { }
// <rdar://problem/8740363>
inline void f1(int);
-// CHECK: define linkonce_odr void @_Z2f1i
+// CHECK-LABEL: define linkonce_odr void @_Z2f1i
void f1(int) { }
void test_f1() { f1(17); }
@@ -38,7 +38,7 @@ namespace test1 {
void g() {}
};
- // CHECK: define linkonce_odr void @_ZN5test11C4funcEv(
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test11C4funcEv(
class C {
public:
@@ -65,5 +65,5 @@ namespace test2 {
A a;
f(a);
}
- // CHECK: define linkonce_odr void @_ZN5test21fERKNS_1AE
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test21fERKNS_1AE
}
diff --git a/test/CodeGenCXX/instantiate-temporaries.cpp b/test/CodeGenCXX/instantiate-temporaries.cpp
index 29cfc07e92d8..c08ea781b8cb 100644
--- a/test/CodeGenCXX/instantiate-temporaries.cpp
+++ b/test/CodeGenCXX/instantiate-temporaries.cpp
@@ -18,7 +18,7 @@ void call() {
Y().get();
}
-// CHECK: define weak_odr void @_Z4callIiEvv
+// CHECK-LABEL: define weak_odr void @_Z4callIiEvv
// CHECK: call void @_ZN1Y3getEv
// CHECK-NEXT: call void @_ZN1XD1Ev
// CHECK-NEXT: ret void
@@ -29,7 +29,7 @@ void compound_literal() {
(X2){};
}
-// CHECK: define weak_odr void @_Z16compound_literalIiEvv
+// CHECK-LABEL: define weak_odr void @_Z16compound_literalIiEvv
// CHECK: call void @_ZN1XC1Ev
// CHECK-NEXT: call void @_ZN2X2D1Ev
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/invalid.cpp b/test/CodeGenCXX/invalid.cpp
new file mode 100644
index 000000000000..d3462465809d
--- /dev/null
+++ b/test/CodeGenCXX/invalid.cpp
@@ -0,0 +1,11 @@
+// RUN: not %clang_cc1 -g -emit-llvm %s
+
+// Don't attempt to codegen invalid code that would lead to a crash
+
+// PR16933
+struct A;
+A *x;
+struct A {
+ B y;
+};
+A y;
diff --git a/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp b/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp
new file mode 100644
index 000000000000..0083f0826ecc
--- /dev/null
+++ b/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++1y | FileCheck %s
+
+// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv
+// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"(%class.anon
+// CHECK-LABEL: define internal signext i8 @"_ZZZN19non_inline_function3fooEvENK3$_0clEiENKUlcE_clEc"(%class.anon
+// CHECK-LABEL: define linkonce_odr void @_ZN19non_inline_function4foo2IiEEDav()
+namespace non_inline_function {
+auto foo() {
+ auto L = [](int a) {
+ return [](char b) {
+ return b;
+ };
+ };
+ L(3)('a');
+ return L;
+}
+
+template<typename T>
+auto foo2() {
+ return [](const T&) { return 42; };
+}
+
+auto use = foo2<int>();
+
+}
+//CHECK-LABEL: define linkonce_odr void @_ZN22inline_member_function1X3fooEv(%"struct.inline_member_function::X"* %this)
+//CHECK-LABEL: define linkonce_odr void @_ZZN22inline_member_function1X3fooEvENKUliE_clEi(%class.anon
+//CHECK-LABEL: define linkonce_odr signext i8 @_ZZZN22inline_member_function1X3fooEvENKUliE_clEiENKUlcE_clEc(%class.anon
+
+namespace inline_member_function {
+struct X {
+auto foo() {
+ auto L = [](int a) {
+ return [](char b) {
+ return b;
+ };
+ };
+ return L;
+}
+};
+
+auto run1 = X{}.foo()(3)('a');
+
+template<typename S>
+struct A {
+ template<typename T> static auto default_lambda() {
+ return [](const T&) { return 42; };
+ }
+
+ template<class U = decltype(default_lambda<S>())>
+ U func(U u = default_lambda<S>()) { return u; }
+
+ template<class T> auto foo() { return [](const T&) { return 42; }; }
+};
+//CHECK-LABEL: define linkonce_odr i32 @_ZZN22inline_member_function1AIdE14default_lambdaIdEEDavENKUlRKdE_clES5_(%class.anon
+int run2 = A<double>{}.func()(3.14);
+
+//CHECK-LABEL: define linkonce_odr i32 @_ZZN22inline_member_function1AIcE14default_lambdaIcEEDavENKUlRKcE_clES5_(%class.anon
+int run3 = A<char>{}.func()('a');
+} // end inline_member_function
+
+
+// CHECK-LABEL: define linkonce_odr void @_ZN15inline_function3fooEv()
+// CHECK: define linkonce_odr void @_ZZN15inline_function3fooEvENKUliE_clEi(%class.anon
+// CHECK: define linkonce_odr signext i8 @_ZZZN15inline_function3fooEvENKUliE_clEiENKUlcE_clEc(%class.anon
+namespace inline_function {
+inline auto foo() {
+ auto L = [](int a) {
+ return [](char b) {
+ return b;
+ };
+ };
+ return L;
+}
+auto use = foo()(3)('a');
+}
+
diff --git a/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp b/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp
new file mode 100644
index 000000000000..accc5d2c4c38
--- /dev/null
+++ b/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
+
+// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv()
+// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"(%class.anon
+// CHECK-LABEL: define internal signext i8 @"_ZZZN19non_inline_function3fooEvENK3$_0clEiENKUlcE_clEc"(%class.anon
+namespace non_inline_function {
+void foo() {
+ auto L = [](int a) {
+ return [](char b) {
+ return b;
+ };
+ };
+ L(3)('a');
+}
+}
+
+namespace non_template {
+ struct L {
+ int t = ([](int a) { return [](int b) { return b; };})(2)(3);
+ };
+ L l;
+}
+
+namespace lambdas_in_NSDMIs_template_class {
+template<class T>
+struct L {
+ T t2 = ([](int a) { return [](int b) { return b; };})(T{})(T{});
+};
+L<int> l;
+}
+
+// CHECK-LABEL: define linkonce_odr i32 @_ZN15inline_function3fooEv
+// CHECK: define linkonce_odr void @_ZZN15inline_function3fooEvENKUliE_clEi
+// CHECK: define linkonce_odr signext i8 @_ZZZN15inline_function3fooEvENKUliE_clEiENKUlcE_clEc
+namespace inline_function {
+inline int foo() {
+ auto L = [](int a) {
+ return [](char b) {
+ return b;
+ };
+ };
+ L(3)('a');
+}
+int use = foo();
+}
+// CHECK: define linkonce_odr void @_ZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEi(%class.anon
+// CHECK: define linkonce_odr i32 @_ZZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEiENKUliE_clEi(%class.anon
+
+// CHECK: define linkonce_odr void @_ZNK12non_template1L1tMUliE_clEi(%class.anon
+// CHECK: define linkonce_odr i32 @_ZZNK12non_template1L1tMUliE_clEiENKUliE_clEi(%class.anon
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index 68ae68fadbbb..2f9a4f2d4f55 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -11,27 +11,27 @@ void *use = &used;
extern "C" auto cvar = []{};
int a() { return []{ return 1; }(); }
-// CHECK: define i32 @_Z1av
+// CHECK-LABEL: define i32 @_Z1av
// CHECK: call i32 @"_ZZ1avENK3$_0clEv"
-// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_0clEv"
// CHECK: ret i32 1
int b(int x) { return [x]{return x;}(); }
-// CHECK: define i32 @_Z1bi
+// CHECK-LABEL: define i32 @_Z1bi
// CHECK: store i32
// CHECK: load i32*
// CHECK: store i32
// CHECK: call i32 @"_ZZ1biENK3$_1clEv"
-// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_1clEv"
// CHECK: load i32*
// CHECK: ret i32
int c(int x) { return [&x]{return x;}(); }
-// CHECK: define i32 @_Z1ci
+// CHECK-LABEL: define i32 @_Z1ci
// CHECK: store i32
// CHECK: store i32*
// CHECK: call i32 @"_ZZ1ciENK3$_2clEv"
-// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_2clEv"
// CHECK: load i32**
// CHECK: load i32*
// CHECK: ret i32
@@ -39,32 +39,32 @@ int c(int x) { return [&x]{return x;}(); }
struct D { D(); D(const D&); int x; };
int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
-// CHECK: define i32 @_Z1di
+// CHECK-LABEL: define i32 @_Z1di
// CHECK: call void @_ZN1DC1Ev
// CHECK: icmp ult i64 %{{.*}}, 10
// CHECK: call void @_ZN1DC1ERKS_
// CHECK: call i32 @"_ZZ1diENK3$_3clEv"
-// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_3clEv"
// CHECK: load i32*
// CHECK: load i32*
// CHECK: ret i32
struct E { E(); E(const E&); ~E(); int x; };
int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); }
-// CHECK: define i32 @_Z1e1ES_b
+// CHECK-LABEL: define i32 @_Z1e1ES_b
// CHECK: call void @_ZN1EC1ERKS_
// CHECK: invoke void @_ZN1EC1ERKS_
// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv"
// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
-// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
// CHECK: trunc i8
// CHECK: load i32*
// CHECK: ret i32
void f() {
- // CHECK: define void @_Z1fv()
+ // CHECK-LABEL: define void @_Z1fv()
// CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv"
// CHECK-NEXT: store i32 (i32, i32)*
// CHECK-NEXT: ret void
@@ -74,7 +74,7 @@ void f() {
static int k;
int g() {
int &r = k;
- // CHECK: define internal i32 @"_ZZ1gvENK3$_6clEv"(
+ // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_6clEv"(
// CHECK-NOT: }
// CHECK: load i32* @_ZL1k,
return [] { return r; } ();
@@ -100,7 +100,7 @@ void h() {
A (*h)() = [] { return A(); };
}
-// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
+// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
// CHECK-NEXT: load i32*
@@ -108,7 +108,7 @@ void h() {
// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii"
// CHECK-NEXT: ret i32
-// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
+// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
// <rdar://problem/12778708>
struct XXX {};
diff --git a/test/CodeGenCXX/linetable-cleanup.cpp b/test/CodeGenCXX/linetable-cleanup.cpp
index 4077af6d8e01..96b857225267 100644
--- a/test/CodeGenCXX/linetable-cleanup.cpp
+++ b/test/CodeGenCXX/linetable-cleanup.cpp
@@ -1,12 +1,18 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
-// Check the line numbers for cleanup code with EH in combinatin with
+// Check the line numbers for cleanup code with EH in combination with
// simple return expressions.
// CHECK: define {{.*}}foo
// CHECK: call void @_ZN1CD1Ev(%class.C* {{.*}}), !dbg ![[CLEANUP:[0-9]+]]
// CHECK: ret i32 0, !dbg ![[RET:[0-9]+]]
+// CHECK: define {{.*}}bar
+// CHECK: ret void, !dbg ![[RETBAR:[0-9]+]]
+
+// CHECK: define {{.*}}baz
+// CHECK: ret void, !dbg ![[RETBAZ:[0-9]+]]
+
class C {
public:
~C() {}
@@ -22,3 +28,31 @@ int foo()
return 0;
// CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
}
+
+void bar()
+{
+ if (!foo())
+ // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ return;
+
+ if (foo()) {
+ C c;
+ c.i = foo();
+ }
+ // Clang creates only a single ret instruction. Make sure it is at a useful line.
+ // CHECK: ![[RETBAR]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+
+void baz()
+{
+ if (!foo())
+ // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ return;
+
+ if (foo()) {
+ // no cleanup
+ // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ return;
+ }
+ // CHECK: ![[RETBAZ]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
diff --git a/test/CodeGenCXX/linkage.cpp b/test/CodeGenCXX/linkage.cpp
new file mode 100644
index 000000000000..19f1b20773c0
--- /dev/null
+++ b/test/CodeGenCXX/linkage.cpp
@@ -0,0 +1,222 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -O1 -disable-llvm-optzns %s -o - | FileCheck %s
+
+namespace test1 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test11fIZNS_1gEvE1SEEvT_(
+ template <typename T> void f(T) {}
+ inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test2 {
+ // CHECK-DAG-LABEL: define internal void @_ZN5test21fIZNS_L1gEvE1SEEvT_(
+ template <typename T> void f(T) {}
+ static inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test3 {
+ // CHECK-DAG-LABEL: define internal void @_ZN5test31fIZNS_1gEvE1SEEvT_(
+ template <typename T> void f(T) {}
+ void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test4 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test41fIZNS_1gILi1EEEPvvE1SEEvT_(
+ template <typename T> void f(T) {}
+ template <int N> inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ extern template void *g<1>();
+ template void *g<1>();
+}
+
+namespace test5 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test51fIZNS_1gILi1EEEPvvE1SEEvT_(
+ template <typename T> void f(T) {}
+ template <int N> inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ extern template void *g<1>();
+ void *h() { return g<1>(); }
+}
+
+namespace test6 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test61fIZZNS_1gEvEN1S1hEvE1TEEvv(
+ template <typename T> void f() {}
+
+ inline void *g() {
+ struct S {
+ void *h() {
+ struct T {
+ };
+ return (void *)f<T>;
+ }
+ } s;
+ return s.h();
+ }
+
+ void *h() { return g(); }
+}
+
+namespace test7 {
+ // CHECK-DAG-LABEL: define internal void @_ZN5test71fIZZNS_1gEvEN1S1hEvE1TEEvv(
+ template <typename T> void f() {}
+
+ void *g() {
+ struct S {
+ void *h() {
+ struct T {
+ };
+ return (void *)f<T>;
+ }
+ } s;
+ return s.h();
+ }
+
+ void *h() { return g(); }
+}
+
+namespace test8 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test81fIZNS_1gEvE1SEEvT_(
+ template <typename T> void f(T) {}
+ inline void *g() {
+ enum S {
+ };
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test9 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test91fIPZNS_1gEvE1SEEvT_(
+ template <typename T> void f(T) {}
+ inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S*>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test10 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test101fIPFZNS_1gEvE1SvEEEvT_(
+ template <typename T> void f(T) {}
+ inline void *g() {
+ struct S {
+ } s;
+ typedef S(*ftype)();
+ return reinterpret_cast<void *>(f<ftype>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test11 {
+ // CHECK-DAG-LABEL: define internal void @_ZN6test111fIPFZNS_1gEvE1SPNS_12_GLOBAL__N_11IEEEEvT_(
+ namespace {
+ struct I {
+ };
+ }
+
+ template <typename T> void f(T) {}
+ inline void *g() {
+ struct S {
+ };
+ typedef S(*ftype)(I * x);
+ return reinterpret_cast<void *>(f<ftype>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test12 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test123fooIZNS_3barIZNS_3zedEvE2S2EEPvvE2S1EEvv
+ template <typename T> void foo() {}
+ template <typename T> inline void *bar() {
+ enum S1 {
+ };
+ return reinterpret_cast<void *>(foo<S1>);
+ }
+ inline void *zed() {
+ enum S2 {
+ };
+ return reinterpret_cast<void *>(bar<S2>);
+ }
+ void *h() { return zed(); }
+}
+
+namespace test13 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZZN6test133fooEvEN1S3barEv(
+ inline void *foo() {
+ struct S {
+ static void bar() {}
+ };
+ return (void *)S::bar;
+ }
+ void *zed() { return foo(); }
+}
+
+namespace test14 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test143fooIZNS_1fEvE1SE3barILPS1_0EEEvv(
+ template <typename T> struct foo {
+ template <T *P> static void bar() {}
+ static void *g() { return (void *)bar<nullptr>; }
+ };
+ inline void *f() {
+ struct S {
+ };
+ return foo<S>::g();
+ }
+ void h() { f(); }
+}
+
+namespace test15 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test153zedIZNS_3fooIiEEPvvE3barEEvv(
+ template <class T> void zed() {}
+ template <class T> void *foo() {
+ class bar {
+ };
+ return reinterpret_cast<void *>(zed<bar>);
+ }
+ void test() { foo<int>(); }
+}
+
+namespace test16 {
+ // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test163zedIZNS_3fooIiE3barEvE1SEEvv(
+ template <class T> void zed() {}
+ template <class T> struct foo {
+ static void *bar();
+ };
+ template <class T> void *foo<T>::bar() {
+ class S {
+ };
+ return reinterpret_cast<void *>(zed<S>);
+ }
+ void *test() { return foo<int>::bar(); }
+}
+
+namespace test17 {
+ // CHECK-DAG: @_ZZN6test173fooILi42EEEPivE3bar = linkonce_odr
+ // CHECK-DAG-LABEL: define weak_odr i32* @_ZN6test173fooILi42EEEPiv(
+ template<int I>
+ int *foo() {
+ static int bar;
+ return &bar;
+ }
+ template int *foo<42>();
+}
diff --git a/test/CodeGenCXX/lpad-linetable.cpp b/test/CodeGenCXX/lpad-linetable.cpp
new file mode 100644
index 000000000000..dba2ad63b2dd
--- /dev/null
+++ b/test/CodeGenCXX/lpad-linetable.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// The landing pad should have the line number of the closing brace of the function.
+// rdar://problem/13888152
+// CHECK: ret i32
+// CHECK: landingpad {{.*}}
+// CHECK-NEXT: !dbg ![[LPAD:[0-9]+]]
+// CHECK: ![[LPAD]] = metadata !{i32 24, i32 0, metadata !{{.*}}, null}
+
+# 1 "/usr/include/c++/4.2.1/vector" 1 3
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+namespace std {
+ template<typename _Tp>
+ class allocator
+ {
+ public:
+ template<typename _Tp1>
+ struct rebind
+ { typedef allocator<_Tp1> other; };
+ ~allocator() throw() { }
+ };
+ template<typename _Tp, typename _Alloc>
+ struct _Vector_base
+ {
+ typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
+ struct _Vector_impl
+ {
+ _Vector_impl(_Tp_alloc_type const& __a) { }
+ };
+ typedef _Alloc allocator_type;
+ _Vector_base(const allocator_type& __a)
+ : _M_impl(__a)
+ { }
+ ~_Vector_base() { }
+ _Vector_impl _M_impl;
+ };
+ template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
+ class vector
+ : protected _Vector_base<_Tp, _Alloc>
+ {
+ typedef _Vector_base<_Tp, _Alloc> _Base;
+ public:
+ typedef _Tp value_type;
+ typedef size_t size_type;
+ typedef _Alloc allocator_type;
+ vector(const allocator_type& __a = allocator_type())
+ : _Base(__a)
+ { }
+ size_type
+ push_back(const value_type& __x)
+ {}
+ };
+}
+# 10 "main.cpp" 2
+
+
+
+
+int main (int argc, char const *argv[], char const *envp[])
+{ // 15
+ std::vector<long> longs;
+ std::vector<short> shorts;
+ for (int i=0; i<12; i++)
+ {
+ longs.push_back(i);
+ shorts.push_back(i);
+ }
+ return 0; // 23
+} // 24
diff --git a/test/CodeGenCXX/lvalue-bitcasts.cpp b/test/CodeGenCXX/lvalue-bitcasts.cpp
index 8c5fa4ad44bb..86355b27abbf 100644
--- a/test/CodeGenCXX/lvalue-bitcasts.cpp
+++ b/test/CodeGenCXX/lvalue-bitcasts.cpp
@@ -3,7 +3,7 @@
struct X { int i; float f; };
struct Y { X x; };
-// CHECK: define void @_Z21reinterpret_cast_testRiRfR1X
+// CHECK-LABEL: define void @_Z21reinterpret_cast_testRiRfR1X
void reinterpret_cast_test(int &ir, float &fr, X &xr) {
// CHECK: load float**
// CHECK: bitcast float*
@@ -48,7 +48,7 @@ void reinterpret_cast_test(int &ir, float &fr, X &xr) {
// CHECK: ret void
}
-// CHECK: define void @_Z6c_castRiRfR1X
+// CHECK-LABEL: define void @_Z6c_castRiRfR1X
void c_cast(int &ir, float &fr, X &xr) {
// CHECK: load float**
// CHECK: bitcast float*
@@ -93,7 +93,7 @@ void c_cast(int &ir, float &fr, X &xr) {
// CHECK: ret void
}
-// CHECK: define void @_Z15functional_castRiRfR1X
+// CHECK-LABEL: define void @_Z15functional_castRiRfR1X
void functional_cast(int &ir, float &fr, X &xr) {
typedef int &intref;
typedef float &floatref;
diff --git a/test/CodeGenCXX/mangle-98.cpp b/test/CodeGenCXX/mangle-98.cpp
index a9ab6ca42370..a329caf1d29d 100644
--- a/test/CodeGenCXX/mangle-98.cpp
+++ b/test/CodeGenCXX/mangle-98.cpp
@@ -2,11 +2,11 @@
template <bool B> struct S3 {};
-// CHECK: define void @_Z1f2S3ILb1EE
+// CHECK-LABEL: define void @_Z1f2S3ILb1EE
void f(S3<true>) {}
-// CHECK: define void @_Z1f2S3ILb0EE
+// CHECK-LABEL: define void @_Z1f2S3ILb0EE
void f(S3<false>) {}
-// CHECK: define void @_Z2f22S3ILb1EE
+// CHECK-LABEL: define void @_Z2f22S3ILb1EE
void f2(S3<100>) {}
diff --git a/test/CodeGenCXX/mangle-address-space.cpp b/test/CodeGenCXX/mangle-address-space.cpp
index ff23c206911c..4a4a1f3f56e9 100644
--- a/test/CodeGenCXX/mangle-address-space.cpp
+++ b/test/CodeGenCXX/mangle-address-space.cpp
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-// CHECK: define void @_Z2f0Pc
+// CHECK-LABEL: define void @_Z2f0Pc
void f0(char *p) { }
-// CHECK: define void @_Z2f0PU3AS1c
+// CHECK-LABEL: define void @_Z2f0PU3AS1c
void f0(char __attribute__((address_space(1))) *p) { }
struct OpaqueType;
typedef OpaqueType __attribute__((address_space(100))) * OpaqueTypePtr;
-// CHECK: define void @_Z2f0PU5AS10010OpaqueType
+// CHECK-LABEL: define void @_Z2f0PU5AS10010OpaqueType
void f0(OpaqueTypePtr) { }
diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp
index 5ace0b01cc2e..b6719c545233 100644
--- a/test/CodeGenCXX/mangle-alias-template.cpp
+++ b/test/CodeGenCXX/mangle-alias-template.cpp
@@ -15,7 +15,7 @@ template<typename,typename,typename> struct S {};
template<typename T, typename U> using U = S<T, int, U>;
template<typename...Ts> void h(U<Ts...>, Ts...);
-// CHECK: define void @_Z1zv(
+// CHECK-LABEL: define void @_Z1zv(
void z() {
vector<int> VI;
f(VI);
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index 2d7a883526db..e935f51a46b2 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -70,22 +70,22 @@ namespace Casts {
template <int N> T<N> f() { return T<N>(); }
- // CHECK: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
template void implicit<4>(void*);
- // CHECK: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void cstyle<4>(void*);
- // CHECK: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void functional<4>(void*);
- // CHECK: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void static_<4>(void*);
- // CHECK: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
template T<6> f<6>();
- // CHECK: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE(
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE(
template void auto_<int>(int*);
- // CHECK: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE(
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE(
template void scalar_<int>(int);
}
@@ -93,10 +93,10 @@ namespace test1 {
short foo(short);
int foo(int);
- // CHECK: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_(
+ // CHECK-LABEL: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_(
template <class T> auto a(T t) -> decltype(foo(T())) { return foo(t); }
- // CHECK: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_(
+ // CHECK-LABEL: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_(
template <class T> auto b(T t) -> decltype((foo)(T())) { return (foo)(t); }
void test(short s) {
@@ -124,7 +124,7 @@ namespace test2 {
float baz(float(*)());
void fred(float(*)(), float);
- // CHECK: define void @_ZN5test211instantiateEv
+ // CHECK-LABEL: define void @_ZN5test211instantiateEv
void instantiate() {
// CHECK: call void @_ZN5test21aIPFfvEEEvT_DTclfL0p_EE(
a(foo, 0.0f);
@@ -156,7 +156,7 @@ namespace test3 {
int *member;
};
- // CHECK: define void @_ZN5test311instantiateEv
+ // CHECK-LABEL: define void @_ZN5test311instantiateEv
void instantiate() {
X x;
int *ip;
diff --git a/test/CodeGenCXX/mangle-extreme.cpp b/test/CodeGenCXX/mangle-extreme.cpp
index ef2d466e416c..9fa678a6f7d4 100644
--- a/test/CodeGenCXX/mangle-extreme.cpp
+++ b/test/CodeGenCXX/mangle-extreme.cpp
@@ -2,7 +2,7 @@
struct X { };
-// CHECK: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_(
+// CHECK-LABEL: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_(
void f(X****************************************,
X****************************************,
X***************************************,
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
index 0bd5ad2a02ca..659b437a0ef3 100644
--- a/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s
// CHECK: @_ZZNK7PR12917IJiiEE1nMUlvE_clEvE1n = linkonce_odr global i32 0
-// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd_N1nE = linkonce_odr global i32 0
-// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd0_N1nE = linkonce_odr global i32 0
-// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd1_N1nE = linkonce_odr global i32 0
+// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd_NKUlvE_clEvE1n = linkonce_odr global i32 0
+// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd0_NKUlvE_clEvE1n = linkonce_odr global i32 0
+// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd1_NKUlvE_clEvE1n = linkonce_odr global i32 0
-// CHECK: define linkonce_odr void @_Z11inline_funci
+// CHECK-LABEL: define linkonce_odr void @_Z11inline_funci
inline void inline_func(int n) {
// CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv
int i = []{ return 1; }();
@@ -41,7 +41,7 @@ struct S {
void S::g(int i = []{return 1;}(),
int j = []{return 2; }()) {}
-// CHECK: define void @_Z6test_S1S
+// CHECK-LABEL: define void @_Z6test_S1S
void test_S(S s) {
// CHECK: call i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv
// CHECK-NEXT: call i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv
@@ -63,15 +63,15 @@ void test_S(S s) {
}
// Check the linkage of the lambda call operators used in test_S.
-// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv
// CHECK: ret i32 1
-// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv
// CHECK: ret i32 2
-// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv
// CHECK: ret i32 3
-// CHECK: define internal i32 @"_ZNK1S3$_0clEv"
+// CHECK-LABEL: define internal i32 @"_ZNK1S3$_0clEv"
// CHECK: ret i32 1
-// CHECK: define internal i32 @"_ZNK1S3$_1clEv"
+// CHECK-LABEL: define internal i32 @"_ZNK1S3$_1clEv"
// CHECK: ret i32 2
template<typename T>
@@ -81,7 +81,7 @@ struct ST {
T = []{return T(3);}());
};
-// CHECK: define void @_Z7test_ST2STIdE
+// CHECK-LABEL: define void @_Z7test_ST2STIdE
void test_ST(ST<double> st) {
// CHECK: call double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv
// CHECK-NEXT: call double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv
@@ -94,11 +94,11 @@ void test_ST(ST<double> st) {
}
// Check the linkage of the lambda call operators used in test_ST.
-// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv
// CHECK: ret double 1
-// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv
+// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv
// CHECK: ret double 2
-// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd_NKUlvE_clEv
// CHECK: ret double 3
template<typename T>
@@ -106,6 +106,7 @@ struct StaticMembers {
static T x;
static T y;
static T z;
+ static int (*f)();
};
template<typename T> int accept_lambda(T);
@@ -119,39 +120,47 @@ T StaticMembers<T>::y = []{return 3;}();
template<typename T>
T StaticMembers<T>::z = accept_lambda([]{return 4;});
-// CHECK: define internal void @__cxx_global_var_init()
+template<typename T>
+int (*StaticMembers<T>::f)() = []{return 5;};
+
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
// CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
// CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
// CHECK-NEXT: add nsw
-// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
// CHECK: ret i32 1
-// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
// CHECK: ret i32 2
template float StaticMembers<float>::x;
-// CHECK: define internal void @__cxx_global_var_init1()
+// CHECK-LABEL: define internal void @__cxx_global_var_init1()
// CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
-// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
// CHECK: ret i32 3
template float StaticMembers<float>::y;
-// CHECK: define internal void @__cxx_global_var_init2()
+// CHECK-LABEL: define internal void @__cxx_global_var_init2()
// CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_
// CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_()
template float StaticMembers<float>::z;
-// CHECK: define internal void @__cxx_global_var_init3
+// CHECK-LABEL: define internal void @__cxx_global_var_init3()
+// 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_init4
// CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv"
-// CHECK: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv"
+// CHECK-LABEL: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv"
// CHECK: ret i32 42
template<> double StaticMembers<double>::z = []{return 42; }();
template<typename T>
void func_template(T = []{ return T(); }());
-// CHECK: define void @_Z17use_func_templatev()
+// CHECK-LABEL: define void @_Z17use_func_templatev()
void use_func_template() {
- // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv"
+ // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENK3$_3clEv"
func_template<int>();
}
@@ -183,7 +192,7 @@ namespace PR12123 {
};
void B::h() { f(); }
}
-// CHECK: define linkonce_odr %"struct.PR12123::A"* @_ZZN7PR121231B1fERKSt9type_infoEd_NKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr %"struct.PR12123::A"* @_ZZN7PR121231B1fERKSt9type_infoEd_NKUlvE_clEv
namespace PR12808 {
template <typename> struct B {
@@ -196,11 +205,11 @@ namespace PR12808 {
void f() {
b<int>(1);
}
- // CHECK: define linkonce_odr void @_ZZN7PR128081bIiEEviENKS0_IiEUlvE_clEv
- // CHECK: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKS0_IiEUlvE_clEvENKUlvE_clEv
+ // CHECK-LABEL: define linkonce_odr void @_ZZN7PR128081bIiEEviENKUlvE_clEv
+ // CHECK-LABEL: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKUlvE_clEvENKUlvE_clEv
}
-// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
+// CHECK-LABEL: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
struct Members {
int x = [] { return 1; }() + [] { return 2; }();
@@ -208,7 +217,7 @@ struct Members {
};
void test_Members() {
- // CHECK: define linkonce_odr void @_ZN7MembersC2Ev
+ // CHECK-LABEL: define linkonce_odr void @_ZN7MembersC2Ev
// CHECK: call i32 @_ZNK7Members1xMUlvE_clEv
// CHECK-NEXT: call i32 @_ZNK7Members1xMUlvE0_clE
// CHECK-NEXT: add nsw i32
@@ -232,21 +241,21 @@ void test_NestedInstantiation() {
}
// Check the linkage of the lambdas used in test_Members.
-// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv
// CHECK: ret i32 1
-// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv
// CHECK: ret i32 2
-// CHECK: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv
// CHECK: ret i32 3
// Check linkage of the various lambdas.
-// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv
// CHECK: ret i32 1
-// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv
// CHECK: ret i32
-// CHECK: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv
+// CHECK-LABEL: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv
// CHECK: ret double
-// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi
+// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi
// CHECK: ret i32
-// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv
// CHECK: ret i32 17
diff --git a/test/CodeGenCXX/mangle-local-class-names.cpp b/test/CodeGenCXX/mangle-local-class-names.cpp
index 332146076ae5..8b950fcd1776 100644
--- a/test/CodeGenCXX/mangle-local-class-names.cpp
+++ b/test/CodeGenCXX/mangle-local-class-names.cpp
@@ -55,3 +55,33 @@ void GORF (float IVAR1)
}
}
+// CHECK: @_ZZ12OmittingCodefEN4SSSSC1E_0RKf
+inline void OmittingCode(float x) {
+ if (0) {
+ struct SSSS {
+ float bv;
+ SSSS(const float& from): bv(from) { }
+ };
+
+ SSSS VAR1(x);
+ }
+
+ struct SSSS {
+ float bv;
+ SSSS(const float& from): bv(from) { }
+ };
+
+ SSSS VAR2(x);
+}
+void CallOmittingCode() { OmittingCode(1); }
+
+// CHECK: @_ZZ15LocalAnonStructvENUt0_1gEv
+inline void LocalAnonStruct() {
+ if (0) {
+ struct { void f() {} } x;
+ x.f();
+ }
+ struct { void g() {} } y;
+ y.g();
+}
+void CallLocalAnonStruct() { LocalAnonStruct(); }
diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
index d03ba5264975..50a238340e18 100644
--- a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
+++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
@@ -1,123 +1,240 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix=X64 %s
void foo(const unsigned int) {}
// CHECK: "\01?foo@@YAXI@Z"
+// X64: "\01?foo@@YAXI@Z"
void foo(const double) {}
// CHECK: "\01?foo@@YAXN@Z"
+// X64: "\01?foo@@YAXN@Z"
void bar(const volatile double) {}
// CHECK: "\01?bar@@YAXN@Z"
+// X64: "\01?bar@@YAXN@Z"
void foo_pad(char * x) {}
// CHECK: "\01?foo_pad@@YAXPAD@Z"
+// X64: "\01?foo_pad@@YAXPEAD@Z"
void foo_pbd(const char * x) {}
// CHECK: "\01?foo_pbd@@YAXPBD@Z"
+// X64: "\01?foo_pbd@@YAXPEBD@Z"
void foo_pcd(volatile char * x) {}
// CHECK: "\01?foo_pcd@@YAXPCD@Z"
+// X64: "\01?foo_pcd@@YAXPECD@Z"
void foo_qad(char * const x) {}
// CHECK: "\01?foo_qad@@YAXQAD@Z"
+// X64: "\01?foo_qad@@YAXQEAD@Z"
void foo_rad(char * volatile x) {}
// CHECK: "\01?foo_rad@@YAXRAD@Z"
+// X64: "\01?foo_rad@@YAXREAD@Z"
void foo_sad(char * const volatile x) {}
// CHECK: "\01?foo_sad@@YAXSAD@Z"
+// X64: "\01?foo_sad@@YAXSEAD@Z"
void foo_papad(char ** x) {}
// CHECK: "\01?foo_papad@@YAXPAPAD@Z"
+// X64: "\01?foo_papad@@YAXPEAPEAD@Z"
void foo_papbd(char const ** x) {}
// CHECK: "\01?foo_papbd@@YAXPAPBD@Z"
+// X64: "\01?foo_papbd@@YAXPEAPEBD@Z"
void foo_papcd(char volatile ** x) {}
// CHECK: "\01?foo_papcd@@YAXPAPCD@Z"
+// X64: "\01?foo_papcd@@YAXPEAPECD@Z"
void foo_pbqad(char * const* x) {}
// CHECK: "\01?foo_pbqad@@YAXPBQAD@Z"
+// X64: "\01?foo_pbqad@@YAXPEBQEAD@Z"
void foo_pcrad(char * volatile* x) {}
// CHECK: "\01?foo_pcrad@@YAXPCRAD@Z"
+// X64: "\01?foo_pcrad@@YAXPECREAD@Z"
void foo_qapad(char ** const x) {}
// CHECK: "\01?foo_qapad@@YAXQAPAD@Z"
+// X64: "\01?foo_qapad@@YAXQEAPEAD@Z"
void foo_rapad(char ** volatile x) {}
// CHECK: "\01?foo_rapad@@YAXRAPAD@Z"
+// X64: "\01?foo_rapad@@YAXREAPEAD@Z"
void foo_pbqbd(const char * const* x) {}
// CHECK: "\01?foo_pbqbd@@YAXPBQBD@Z"
+// X64: "\01?foo_pbqbd@@YAXPEBQEBD@Z"
void foo_pbqcd(volatile char * const* x) {}
// CHECK: "\01?foo_pbqcd@@YAXPBQCD@Z"
+// X64: "\01?foo_pbqcd@@YAXPEBQECD@Z"
void foo_pcrbd(const char * volatile* x) {}
// CHECK: "\01?foo_pcrbd@@YAXPCRBD@Z"
+// X64: "\01?foo_pcrbd@@YAXPECREBD@Z"
void foo_pcrcd(volatile char * volatile* x) {}
// CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z"
+// X64: "\01?foo_pcrcd@@YAXPECRECD@Z"
void foo_aad(char &x) {}
// CHECK: "\01?foo_aad@@YAXAAD@Z"
+// X64: "\01?foo_aad@@YAXAEAD@Z"
void foo_abd(const char &x) {}
// CHECK: "\01?foo_abd@@YAXABD@Z"
+// X64: "\01?foo_abd@@YAXAEBD@Z"
void foo_aapad(char *&x) {}
// CHECK: "\01?foo_aapad@@YAXAAPAD@Z"
+// X64: "\01?foo_aapad@@YAXAEAPEAD@Z"
void foo_aapbd(const char *&x) {}
// CHECK: "\01?foo_aapbd@@YAXAAPBD@Z"
+// X64: "\01?foo_aapbd@@YAXAEAPEBD@Z"
void foo_abqad(char * const &x) {}
// CHECK: "\01?foo_abqad@@YAXABQAD@Z"
+// X64: "\01?foo_abqad@@YAXAEBQEAD@Z"
void foo_abqbd(const char * const &x) {}
// CHECK: "\01?foo_abqbd@@YAXABQBD@Z"
+// X64: "\01?foo_abqbd@@YAXAEBQEBD@Z"
void foo_aay144h(int (&x)[5][5]) {}
// CHECK: "\01?foo_aay144h@@YAXAAY144H@Z"
+// X64: "\01?foo_aay144h@@YAXAEAY144H@Z"
void foo_aay144cbh(const int (&x)[5][5]) {}
// CHECK: "\01?foo_aay144cbh@@YAXAAY144$$CBH@Z"
+// X64: "\01?foo_aay144cbh@@YAXAEAY144$$CBH@Z"
void foo_qay144h(int (&&x)[5][5]) {}
// CHECK: "\01?foo_qay144h@@YAX$$QAY144H@Z"
+// X64: "\01?foo_qay144h@@YAX$$QEAY144H@Z"
void foo_qay144cbh(const int (&&x)[5][5]) {}
// CHECK: "\01?foo_qay144cbh@@YAX$$QAY144$$CBH@Z"
+// X64: "\01?foo_qay144cbh@@YAX$$QEAY144$$CBH@Z"
void foo_p6ahxz(int x()) {}
// CHECK: "\01?foo_p6ahxz@@YAXP6AHXZ@Z"
+// X64: "\01?foo_p6ahxz@@YAXP6AHXZ@Z"
void foo_a6ahxz(int (&x)()) {}
// CHECK: "\01?foo_a6ahxz@@YAXA6AHXZ@Z"
+// X64: "\01?foo_a6ahxz@@YAXA6AHXZ@Z"
void foo_q6ahxz(int (&&x)()) {}
// CHECK: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z"
+// X64: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z"
void foo_qay04h(int x[5][5]) {}
// CHECK: "\01?foo_qay04h@@YAXQAY04H@Z"
+// X64: "\01?foo_qay04h@@YAXQEAY04H@Z"
void foo_qay04cbh(const int x[5][5]) {}
// CHECK: "\01?foo_qay04cbh@@YAXQAY04$$CBH@Z"
+// X64: "\01?foo_qay04cbh@@YAXQEAY04$$CBH@Z"
typedef double Vector[3];
void foo(Vector*) {}
// CHECK: "\01?foo@@YAXPAY02N@Z"
+// X64: "\01?foo@@YAXPEAY02N@Z"
void foo(Vector) {}
// CHECK: "\01?foo@@YAXQAN@Z"
+// X64: "\01?foo@@YAXQEAN@Z"
void foo_const(const Vector) {}
// CHECK: "\01?foo_const@@YAXQBN@Z"
+// X64: "\01?foo_const@@YAXQEBN@Z"
void foo_volatile(volatile Vector) {}
// CHECK: "\01?foo_volatile@@YAXQCN@Z"
+// X64: "\01?foo_volatile@@YAXQECN@Z"
void foo(Vector*, const Vector, const double) {}
// CHECK: "\01?foo@@YAXPAY02NQBNN@Z"
+// X64: "\01?foo@@YAXPEAY02NQEBNN@Z"
+
+typedef void (*ConstFunPtr)(int *const d);
+void foo_fnptrconst(ConstFunPtr f) { }
+// CHECK: "\01?foo_fnptrconst@@YAXP6AXQAH@Z@Z"
+// X64: "\01?foo_fnptrconst@@YAXP6AXQEAH@Z@Z"
+
+typedef void (*ArrayFunPtr)(int d[1]);
+void foo_fnptrarray(ArrayFunPtr f) { }
+// CHECK: "\01?foo_fnptrarray@@YAXP6AXQAH@Z@Z"
+// X64: "\01?foo_fnptrarray@@YAXP6AXQEAH@Z@Z"
+
+void foo_fnptrbackref1(ArrayFunPtr f1, ArrayFunPtr f2) { }
+// CHECK: "\01?foo_fnptrbackref1@@YAXP6AXQAH@Z1@Z"
+// X64: "\01?foo_fnptrbackref1@@YAXP6AXQEAH@Z1@Z"
+
+void foo_fnptrbackref2(ArrayFunPtr f1, ConstFunPtr f2) { }
+// CHECK: "\01?foo_fnptrbackref2@@YAXP6AXQAH@Z1@Z"
+// X64: "\01?foo_fnptrbackref2@@YAXP6AXQEAH@Z1@Z"
+
+typedef void (*NormalFunPtr)(int *d);
+void foo_fnptrbackref3(ArrayFunPtr f1, NormalFunPtr f2) { }
+// CHECK: "\01?foo_fnptrbackref3@@YAXP6AXQAH@Z1@Z"
+// X64: "\01?foo_fnptrbackref3@@YAXP6AXQEAH@Z1@Z"
+
+void foo_fnptrbackref4(NormalFunPtr f1, ArrayFunPtr f2) { }
+// CHECK: "\01?foo_fnptrbackref4@@YAXP6AXPAH@Z1@Z"
+// X64: "\01?foo_fnptrbackref4@@YAXP6AXPEAH@Z1@Z"
+
+ArrayFunPtr ret_fnptrarray() { return 0; }
+// CHECK: "\01?ret_fnptrarray@@YAP6AXQAH@ZXZ"
+// X64: "\01?ret_fnptrarray@@YAP6AXQEAH@ZXZ"
+
+// Test that we mangle the forward decl when we have a redeclaration with a
+// slightly different type.
+void mangle_fwd(char * const x);
+void mangle_fwd(char * x) {}
+// CHECK: "\01?mangle_fwd@@YAXQAD@Z"
+// X64: "\01?mangle_fwd@@YAXQEAD@Z"
+
+void mangle_no_fwd(char * x) {}
+// CHECK: "\01?mangle_no_fwd@@YAXPAD@Z"
+// X64: "\01?mangle_no_fwd@@YAXPEAD@Z"
+
+// The first argument gets mangled as-if it were written "int *const"
+// The second arg should not form a backref because it isn't qualified
+void mangle_no_backref0(int[], int *) {}
+// CHECK: "\01?mangle_no_backref0@@YAXQAHPAH@Z"
+// X64: "\01?mangle_no_backref0@@YAXQEAHPEAH@Z"
+
+void mangle_no_backref1(int[], int *const) {}
+// CHECK: "\01?mangle_no_backref1@@YAXQAHQAH@Z"
+// X64: "\01?mangle_no_backref1@@YAXQEAHQEAH@Z"
+
+typedef void fun_type(void);
+typedef void (*ptr_to_fun_type)(void);
+
+// Pointer to function types don't backref with function types
+void mangle_no_backref2(fun_type, ptr_to_fun_type) {}
+// CHECK: "\01?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z"
+// X64: "\01?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z"
+
+void mangle_yes_backref0(int[], int []) {}
+// CHECK: "\01?mangle_yes_backref0@@YAXQAH0@Z"
+// X64: "\01?mangle_yes_backref0@@YAXQEAH0@Z"
+
+void mangle_yes_backref1(int *const, int *const) {}
+// CHECK: "\01?mangle_yes_backref1@@YAXQAH0@Z"
+// X64: "\01?mangle_yes_backref1@@YAXQEAH0@Z"
+
+void mangle_yes_backref2(fun_type *const[], ptr_to_fun_type const[]) {}
+// CHECK: "\01?mangle_yes_backref2@@YAXQBQ6AXXZ0@Z"
+// X64: "\01?mangle_yes_backref2@@YAXQEBQ6AXXZ0@Z"
+
+void mangle_yes_backref3(ptr_to_fun_type *const, void (**const)(void)) {}
+// CHECK: "\01?mangle_yes_backref3@@YAXQAP6AXXZ0@Z"
+// X64: "\01?mangle_yes_backref3@@YAXQEAP6AXXZ0@Z"
diff --git a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
index fbc64923486b..e10cc8e32986 100644
--- a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
+++ b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
@@ -107,7 +107,7 @@ void call_l_foo(L* l) { l->foo(I<A>()); }
void foo(I<A> x) {}
// CHECK: "\01?foo@PR13207@@YAXV?$I@VA@PR13207@@@1@@Z"
void foo2(I<A> x, I<A> y) { }
-// CHECK "\01?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z"
+// CHECK: "\01?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z"
void bar(J<A,B> x) {}
// CHECK: "\01?bar@PR13207@@YAXV?$J@VA@PR13207@@VB@2@@1@@Z"
void spam(K<A,B,C> x) {}
@@ -163,3 +163,31 @@ void foobar(NC::Y<NB::Y<NA::Y<NA::X> > > x) {}
// CHECK: "\01?foobar@NC@PR13207@@YAXV?$Y@V?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@NB@PR13207@@@12@@Z"
}
}
+
+// Function template names are not considered for backreferencing, but normal
+// function names are.
+namespace fn_space {
+struct RetVal { int hash; };
+template <typename T>
+RetVal fun_tmpl(const T &t) { return RetVal(); }
+RetVal fun_normal(int t) { return RetVal(); }
+void fun_instantiate() {
+ fun_normal(1);
+ fun_tmpl(1);
+}
+// CHECK: "\01?fun_normal@fn_space@@YA?AURetVal@1@H@Z"
+// CHECK: "\01??$fun_tmpl@H@fn_space@@YA?AURetVal@0@ABH@Z"
+
+template <typename T, RetVal (*F)(T)>
+RetVal fun_tmpl_recurse(T t) {
+ if (!t)
+ return RetVal();
+ return F(t - 1);
+}
+RetVal ident(int x) { return RetVal(); }
+void fun_instantiate2() {
+ fun_tmpl_recurse<int, fun_tmpl_recurse<int, ident> >(10);
+}
+// CHECK: "\01??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z"
+// CHECK: "\01??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z"
+}
diff --git a/test/CodeGenCXX/mangle-ms-back-references.cpp b/test/CodeGenCXX/mangle-ms-back-references.cpp
index 5f93590cf2a2..4f1732688833 100644
--- a/test/CodeGenCXX/mangle-ms-back-references.cpp
+++ b/test/CodeGenCXX/mangle-ms-back-references.cpp
@@ -61,3 +61,8 @@ void h2(void (*f_ptr)(void *), void *arg) {}
PInt3Func h3(PInt3Func x, PInt3Func y, int* z) { return 0; }
// CHECK: "\01?h3@@YAP6APAHPAH0@ZP6APAH00@Z10@Z"
+
+namespace foo {
+void foo() { }
+// CHECK: "\01?foo@0@YAXXZ"
+}
diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp
index 10e68248dc18..514f5739ffd5 100644
--- a/test/CodeGenCXX/mangle-ms-templates.cpp
+++ b/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
template<typename T>
class Class {
@@ -23,6 +24,18 @@ class IntTemplate {
IntTemplate() {}
};
+template<long long param>
+class LongLongTemplate {
+ public:
+ LongLongTemplate() {}
+};
+
+template<unsigned long long param>
+class UnsignedLongLongTemplate {
+ public:
+ UnsignedLongLongTemplate() {}
+};
+
template<>
class BoolTemplate<true> {
public:
@@ -33,65 +46,113 @@ class BoolTemplate<true> {
void template_mangling() {
Class<Typename> c1;
// CHECK: call {{.*}} @"\01??0?$Class@VTypename@@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@VTypename@@@@QEAA@XZ"
Class<const Typename> c1_const;
// CHECK: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QEAA@XZ"
Class<volatile Typename> c1_volatile;
// CHECK: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QEAA@XZ"
Class<const volatile Typename> c1_cv;
// CHECK: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QEAA@XZ"
Class<Nested<Typename> > c2;
// CHECK: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QEAA@XZ"
Class<int * const> c_intpc;
// CHECK: call {{.*}} @"\01??0?$Class@QAH@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@QEAH@@QEAA@XZ"
Class<int()> c_ft;
// CHECK: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QEAA@XZ"
Class<int[]> c_inti;
// CHECK: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QEAA@XZ"
Class<int[5]> c_int5;
// CHECK: call {{.*}} @"\01??0?$Class@$$BY04H@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$BY04H@@QEAA@XZ"
Class<const int[5]> c_intc5;
// CHECK: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QEAA@XZ"
Class<int * const[5]> c_intpc5;
// CHECK: call {{.*}} @"\01??0?$Class@$$BY04QAH@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$Class@$$BY04QEAH@@QEAA@XZ"
BoolTemplate<false> _false;
// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QEAA@XZ"
BoolTemplate<true> _true;
// PR13158
_true.Foo(1);
// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$BoolTemplate@$00@@QEAA@XZ"
// CHECK: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z"
+// X64: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QEAAXH@Z"
IntTemplate<0> zero;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QEAA@XZ"
IntTemplate<5> five;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$04@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$04@@QEAA@XZ"
IntTemplate<11> eleven;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QEAA@XZ"
IntTemplate<256> _256;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QEAA@XZ"
IntTemplate<513> _513;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QEAA@XZ"
IntTemplate<1026> _1026;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QEAA@XZ"
IntTemplate<65535> ffff;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QEAA@XZ"
+
+ IntTemplate<-1> neg_1;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?0@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0?0@@QEAA@XZ"
+ IntTemplate<-9> neg_9;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?8@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0?8@@QEAA@XZ"
+ IntTemplate<-10> neg_10;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?9@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0?9@@QEAA@XZ"
+ IntTemplate<-11> neg_11;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QEAA@XZ"
+
+ LongLongTemplate<-9223372036854775807LL-1LL> int64_min;
+// CHECK: call {{.*}} @"\01??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QEAA@XZ"
+ LongLongTemplate<9223372036854775807LL> int64_max;
+// CHECK: call {{.*}} @"\01??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QEAA@XZ"
+ UnsignedLongLongTemplate<18446744073709551615ULL> uint64_max;
+// CHECK: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ"
+ UnsignedLongLongTemplate<(unsigned long long)-1> uint64_neg_1;
+// CHECK: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ"
}
namespace space {
template<class T> const T& foo(const T& l) { return l; }
}
// CHECK: "\01??$foo@H@space@@YAABHABH@Z"
+// X64: "\01??$foo@H@space@@YAAEBHAEBH@Z"
void use() {
space::foo(42);
@@ -108,4 +169,96 @@ void FunctionPointerTemplate() {
void spam() {
FunctionPointerTemplate<spam>();
// CHECK: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ"
+// X64: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ"
+}
+
+// Unlike Itanium, there is no character code to indicate an argument pack.
+// Tested with MSVC 2013, the first version which supports variadic templates.
+
+template <typename ...Ts> void variadic_fn_template(const Ts &...args) { }
+void variadic_fn_instantiate() {
+ variadic_fn_template(0, 1, 3, 4);
+ variadic_fn_template(0, 1, 'a', "b");
+}
+// CHECK: "\01??$variadic_fn_template@HHHH@@YAXABH000@Z"
+// CHECK: "\01??$variadic_fn_template@HHD$$BY01D@@YAXABH0ABDAAY01$$CBD@Z"
+
+template <typename ...Ts>
+struct VariadicClass {
+ VariadicClass() { }
+ int x;
+};
+void variadic_class_instantiate() {
+ VariadicClass<int, char, bool> a;
+ VariadicClass<bool, char, int> b;
+}
+// CHECK: call {{.*}} @"\01??0?$VariadicClass@HD_N@@QAE@XZ"
+// CHECK: call {{.*}} @"\01??0?$VariadicClass@_NDH@@QAE@XZ"
+
+template <typename T>
+struct Second {};
+
+template <typename T, template <class> class>
+struct Type {};
+
+template <template <class> class T>
+struct Type2 {};
+
+template <template <class> class T, bool B>
+struct Thing;
+
+template <template <class> class T>
+struct Thing<T, false> { };
+
+template <template <class> class T>
+struct Thing<T, true> { };
+
+void template_template_fun(Type<Thing<Second, true>, Second>) { }
+// CHECK: "\01?template_template_fun@@YAXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z"
+
+template <typename T>
+void template_template_specialization();
+
+template <>
+void template_template_specialization<void (Type<Thing<Second, true>, Second>)>() {
+}
+// CHECK: "\01??$template_template_specialization@$$A6AXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z@@YAXXZ"
+
+// PR16788
+template <decltype(nullptr)> struct S1 {};
+void f(S1<nullptr>) {}
+// CHECK: "\01?f@@YAXU?$S1@$0A@@@@Z"
+
+struct record {
+ int first;
+ int second;
+};
+template <const record &>
+struct type1 {
+};
+extern const record inst;
+void recref(type1<inst>) {}
+// CHECK: "\01?recref@@YAXU?$type1@$E?inst@@3Urecord@@B@@@Z"
+
+struct _GUID {};
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
+
+template <typename T, const _GUID *G = &__uuidof(T)>
+struct UUIDType1 {};
+
+template <typename T, const _GUID &G = __uuidof(T)>
+struct UUIDType2 {};
+
+void fun(UUIDType1<uuid> a) {}
+// CHECK: "\01?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z"
+void fun(UUIDType2<uuid> b) {}
+// CHECK: "\01?fun@@YAXU?$UUIDType2@Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z"
+
+template <typename T> struct TypeWithFriendDefinition {
+ friend void FunctionDefinedWithInjectedName(TypeWithFriendDefinition<T>) {}
+};
+// CHECK: call {{.*}} @"\01?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z"
+void CallFunctionDefinedWithInjectedName() {
+ FunctionDefinedWithInjectedName(TypeWithFriendDefinition<int>());
}
+// CHECK: @"\01?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z"
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index 1b98a84823f4..68ec2b3baf68 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -1,57 +1,51 @@
-// RUN: %clang_cc1 -fms-extensions -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
-// RUN: %clang_cc1 -fms-compatibility -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
-
-// CHECK: @"\01?a@@3HA"
-// CHECK: @"\01?b@N@@3HA"
-// CHECK: @"\01?anonymous@?A@N@@3HA"
-// CHECK: @c
-// CHECK: @"\01?d@foo@@0FB"
-// CHECK: @"\01?e@foo@@1JC"
-// CHECK: @"\01?f@foo@@2DD"
-// CHECK: @"\01?g@bar@@2HA"
-// CHECK: @"\01?h1@@3QAHA"
-// CHECK: @"\01?h2@@3QBHB"
-// CHECK: @"\01?i@@3PAY0BE@HA"
-// CHECK: @"\01?j@@3P6GHCE@ZA"
-// CHECK: @"\01?k@@3PTfoo@@DA"
-// CHECK: @"\01?l@@3P8foo@@AEHH@ZA"
-// CHECK: @"\01?color1@@3PANA"
-// CHECK: @"\01?color2@@3QBNB"
-// CHECK: @"\01?color3@@3QAY02$$CBNA"
-// CHECK: @"\01?color4@@3QAY02$$CBNA"
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -std=c++11 | FileCheck %s
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 -std=c++11| FileCheck -check-prefix X64 %s
int a;
+// CHECK-DAG: @"\01?a@@3HA"
namespace N {
int b;
+// CHECK-DAG: @"\01?b@N@@3HA"
namespace {
int anonymous;
+// CHECK-DAG: @"\01?anonymous@?A@N@@3HA"
}
}
static int c;
+// CHECK-DAG: @c
+
int _c(void) {return N::anonymous + c;}
-// CHECK: @"\01?_c@@YAHXZ"
+// CHECK-DAG: @"\01?_c@@YAHXZ"
+// X64-DAG: @"\01?_c@@YAHXZ"
class foo {
static const short d;
+// CHECK-DAG: @"\01?d@foo@@0FB"
protected:
static volatile long e;
+// CHECK-DAG: @"\01?e@foo@@1JC"
public:
static const volatile char f;
+// CHECK-DAG: @"\01?f@foo@@2DD"
int operator+(int a);
foo(){}
-//CHECK: @"\01??0foo@@QAE@XZ"
+// CHECK-DAG: @"\01??0foo@@QAE@XZ"
+// X64-DAG: @"\01??0foo@@QEAA@XZ"
~foo(){}
-//CHECK: @"\01??1foo@@QAE@XZ"
+// CHECK-DAG: @"\01??1foo@@QAE@XZ"
+// X64-DAG: @"\01??1foo@@QEAA@XZ
foo(int i){}
-//CHECK: @"\01??0foo@@QAE@H@Z"
+// CHECK-DAG: @"\01??0foo@@QAE@H@Z"
+// X64-DAG: @"\01??0foo@@QEAA@H@Z"
foo(char *q){}
-//CHECK: @"\01??0foo@@QAE@PAD@Z"
+// CHECK-DAG: @"\01??0foo@@QAE@PAD@Z"
+// X64-DAG: @"\01??0foo@@QEAA@PEAD@Z"
static foo* static_method() { return 0; }
@@ -76,13 +70,16 @@ enum quux {
};
foo bar() { return foo(); }
-//CHECK: @"\01?bar@@YA?AVfoo@@XZ"
+// CHECK-DAG: @"\01?bar@@YA?AVfoo@@XZ"
+// X64-DAG: @"\01?bar@@YA?AVfoo@@XZ"
int foo::operator+(int a) {
-//CHECK: @"\01??Hfoo@@QAEHH@Z"
+// CHECK-DAG: @"\01??Hfoo@@QAEHH@Z"
+// X64-DAG: @"\01??Hfoo@@QEAAHH@Z"
foo::static_method();
-//CHECK: @"\01?static_method@foo@@SAPAV1@XZ"
+// CHECK-DAG: @"\01?static_method@foo@@SAPAV1@XZ"
+// X64-DAG: @"\01?static_method@foo@@SAPEAV1@XZ"
bar();
return a;
}
@@ -92,106 +89,278 @@ volatile long foo::e;
const volatile char foo::f = 'C';
int bar::g;
+// CHECK-DAG: @"\01?g@bar@@2HA"
extern int * const h1 = &a;
+// CHECK-DAG: @"\01?h1@@3QAHA"
extern const int * const h2 = &a;
+// CHECK-DAG: @"\01?h2@@3QBHB"
int i[10][20];
+// CHECK-DAG: @"\01?i@@3PAY0BE@HA"
int (__stdcall *j)(signed char, unsigned char);
+// CHECK-DAG: @"\01?j@@3P6GHCE@ZA"
const volatile char foo2::*k;
+// CHECK-DAG: @"\01?k@@3PTfoo@@DT1@"
+// X64-DAG: @"\01?k@@3PETfoo@@DET1@"
int (foo2::*l)(int);
+// CHECK-DAG: @"\01?l@@3P8foo@@AEHH@ZQ1@"
// Static functions are mangled, too.
// Also make sure calling conventions, arglists, and throw specs work.
static void __stdcall alpha(float a, double b) throw() {}
bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) {
-// CHECK: @"\01?beta@@YI_N_J_W@Z"
+// CHECK-DAG: @"\01?beta@@YI_N_J_W@Z"
+// X64-DAG: @"\01?beta@@YA_N_J_W@Z"
alpha(0.f, 0.0);
return false;
}
-// CHECK: @"\01?alpha@@YGXMN@Z"
-// X64: @"\01?alpha@@YAXMN@Z"
+// CHECK-DAG: @"\01?alpha@@YGXMN@Z"
+// X64-DAG: @"\01?alpha@@YAXMN@Z"
// Make sure tag-type mangling works.
void gamma(class foo, struct bar, union baz, enum quux) {}
-// CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"
+// CHECK-DAG: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"
+// X64-DAG: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"
// Make sure pointer/reference-type mangling works.
void delta(int * const a, const long &) {}
-// CHECK: @"\01?delta@@YAXQAHABJ@Z"
+// CHECK-DAG: @"\01?delta@@YAXQAHABJ@Z"
+// X64-DAG: @"\01?delta@@YAXQEAHAEBJ@Z"
// Array mangling.
void epsilon(int a[][10][20]) {}
-// CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z"
+// CHECK-DAG: @"\01?epsilon@@YAXQAY19BE@H@Z"
+// X64-DAG: @"\01?epsilon@@YAXQEAY19BE@H@Z"
void zeta(int (*)(int, int)) {}
-// CHECK: @"\01?zeta@@YAXP6AHHH@Z@Z"
+// CHECK-DAG: @"\01?zeta@@YAXP6AHHH@Z@Z"
+// X64-DAG: @"\01?zeta@@YAXP6AHHH@Z@Z"
// Blocks mangling (Clang extension). A block should be mangled slightly
// differently from a similar function pointer.
void eta(int (^)(int, int)) {}
-// CHECK: @"\01?eta@@YAXP_EAHHH@Z@Z"
+// CHECK-DAG: @"\01?eta@@YAXP_EAHHH@Z@Z"
typedef int theta_arg(int,int);
void theta(theta_arg^ block) {}
-// CHECK: @"\01?theta@@YAXP_EAHHH@Z@Z"
+// CHECK-DAG: @"\01?theta@@YAXP_EAHHH@Z@Z"
void operator_new_delete() {
char *ptr = new char;
-// CHECK: @"\01??2@YAPAXI@Z"
+// CHECK-DAG: @"\01??2@YAPAXI@Z"
delete ptr;
-// CHECK: @"\01??3@YAXPAX@Z"
+// CHECK-DAG: @"\01??3@YAXPAX@Z"
char *array = new char[42];
-// CHECK: @"\01??_U@YAPAXI@Z"
+// CHECK-DAG: @"\01??_U@YAPAXI@Z"
delete [] array;
-// CHECK: @"\01??_V@YAXPAX@Z"
+// CHECK-DAG: @"\01??_V@YAXPAX@Z"
}
// PR13022
void (redundant_parens)();
void redundant_parens_use() { redundant_parens(); }
-// CHECK: @"\01?redundant_parens@@YAXXZ"
+// CHECK-DAG: @"\01?redundant_parens@@YAXXZ"
+// X64-DAG: @"\01?redundant_parens@@YAXXZ"
// PR13047
typedef double RGB[3];
RGB color1;
+// CHECK-DAG: @"\01?color1@@3PANA"
extern const RGB color2 = {};
+// CHECK-DAG: @"\01?color2@@3QBNB"
extern RGB const color3[5] = {};
+// CHECK-DAG: @"\01?color3@@3QAY02$$CBNA"
extern RGB const ((color4)[5]) = {};
+// CHECK-DAG: @"\01?color4@@3QAY02$$CBNA"
+
+struct B;
+volatile int B::* volatile memptr1;
+// X64-DAG: @"\01?memptr1@@3RESB@@HES1@"
+volatile int B::* memptr2;
+// X64-DAG: @"\01?memptr2@@3PESB@@HES1@"
+int B::* volatile memptr3;
+// X64-DAG: @"\01?memptr3@@3REQB@@HEQ1@"
+typedef int (*fun)();
+volatile fun B::* volatile funmemptr1;
+// X64-DAG: @"\01?funmemptr1@@3RESB@@R6AHXZES1@"
+volatile fun B::* funmemptr2;
+// X64-DAG: @"\01?funmemptr2@@3PESB@@R6AHXZES1@"
+fun B::* volatile funmemptr3;
+// X64-DAG: @"\01?funmemptr3@@3REQB@@P6AHXZEQ1@"
+void (B::* volatile memptrtofun1)();
+// X64-DAG: @"\01?memptrtofun1@@3R8B@@EAAXXZEQ1@"
+const void (B::* memptrtofun2)();
+// X64-DAG: @"\01?memptrtofun2@@3P8B@@EAAXXZEQ1@"
+volatile void (B::* memptrtofun3)();
+// X64-DAG: @"\01?memptrtofun3@@3P8B@@EAAXXZEQ1@"
+int (B::* volatile memptrtofun4)();
+// X64-DAG: @"\01?memptrtofun4@@3R8B@@EAAHXZEQ1@"
+volatile int (B::* memptrtofun5)();
+// X64-DAG: @"\01?memptrtofun5@@3P8B@@EAA?CHXZEQ1@"
+const int (B::* memptrtofun6)();
+// X64-DAG: @"\01?memptrtofun6@@3P8B@@EAA?BHXZEQ1@"
+fun (B::* volatile memptrtofun7)();
+// X64-DAG: @"\01?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@"
+volatile fun (B::* memptrtofun8)();
+// X64-DAG: @"\01?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@"
+const fun (B::* memptrtofun9)();
+// X64-DAG: @"\01?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@"
// PR12603
enum E {};
-// CHECK: "\01?fooE@@YA?AW4E@@XZ"
+// CHECK-DAG: "\01?fooE@@YA?AW4E@@XZ"
+// X64-DAG: "\01?fooE@@YA?AW4E@@XZ"
E fooE() { return E(); }
class X {};
-// CHECK: "\01?fooX@@YA?AVX@@XZ"
+// CHECK-DAG: "\01?fooX@@YA?AVX@@XZ"
+// X64-DAG: "\01?fooX@@YA?AVX@@XZ"
X fooX() { return X(); }
namespace PR13182 {
extern char s0[];
- // CHECK: @"\01?s0@PR13182@@3PADA"
+ // CHECK-DAG: @"\01?s0@PR13182@@3PADA"
extern char s1[42];
- // CHECK: @"\01?s1@PR13182@@3PADA"
+ // CHECK-DAG: @"\01?s1@PR13182@@3PADA"
extern const char s2[];
- // CHECK: @"\01?s2@PR13182@@3QBDB"
+ // CHECK-DAG: @"\01?s2@PR13182@@3QBDB"
extern const char s3[42];
- // CHECK: @"\01?s3@PR13182@@3QBDB"
+ // CHECK-DAG: @"\01?s3@PR13182@@3QBDB"
extern volatile char s4[];
- // CHECK: @"\01?s4@PR13182@@3RCDC"
+ // CHECK-DAG: @"\01?s4@PR13182@@3RCDC"
extern const volatile char s5[];
- // CHECK: @"\01?s5@PR13182@@3SDDD"
+ // CHECK-DAG: @"\01?s5@PR13182@@3SDDD"
extern const char* const* s6;
- // CHECK: @"\01?s6@PR13182@@3PBQBDB"
+ // CHECK-DAG: @"\01?s6@PR13182@@3PBQBDB"
char foo() {
return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0];
}
}
+
+extern "C" inline void extern_c_func() {
+ static int local;
+// CHECK-DAG: @"\01?local@?1??extern_c_func@@9@4HA"
+// X64-DAG: @"\01?local@?1??extern_c_func@@9@4HA"
+}
+
+void call_extern_c_func() {
+ extern_c_func();
+}
+
+int main() { return 0; }
+// CHECK-DAG: @main
+// X64-DAG: @main
+
+int wmain() { return 0; }
+// CHECK-DAG: @wmain
+// X64-DAG: @wmain
+
+int WinMain() { return 0; }
+// CHECK-DAG: @WinMain
+// X64-DAG: @WinMain
+
+int wWinMain() { return 0; }
+// CHECK-DAG: @wWinMain
+// X64-DAG: @wWinMain
+
+int DllMain() { return 0; }
+// CHECK-DAG: @DllMain
+// X64-DAG: @DllMain
+
+inline int inline_function_with_local_type() {
+ static struct {
+ int a_field;
+ } static_variable_in_inline_function = { 20 }, second_static = { 40 };
+ // CHECK: @"\01?static_variable_in_inline_function@?1??inline_function_with_local_type@@YAHXZ@4U<unnamed-type-static_variable_in_inline_function>@?1??1@YAHXZ@A"
+
+ return static_variable_in_inline_function.a_field + second_static.a_field;
+}
+
+int call_inline_function_with_local_type() {
+ return inline_function_with_local_type();
+}
+
+template <typename T>
+inline int templated_inline_function_with_local_type() {
+ static struct {
+ int a_field;
+ } static_variable_in_templated_inline_function = { 20 },
+ second_static = { 40 };
+ // CHECK: @"\01?static_variable_in_templated_inline_function@?1???$templated_inline_function_with_local_type@H@@YAHXZ@4U<unnamed-type-static_variable_in_templated_inline_function>@?1???$templated_inline_function_with_local_type@H@@YAHXZ@A"
+
+ return static_variable_in_templated_inline_function.a_field +
+ second_static.a_field;
+}
+
+int call_templated_inline_function_with_local_type() {
+ return templated_inline_function_with_local_type<int>();
+}
+
+// PR17371
+struct OverloadedNewDelete {
+ // __cdecl
+ void *operator new(__SIZE_TYPE__);
+ void *operator new[](__SIZE_TYPE__);
+ void operator delete(void *);
+ void operator delete[](void *);
+ // __thiscall
+ int operator+(int);
+};
+
+void *OverloadedNewDelete::operator new(__SIZE_TYPE__ s) { return 0; }
+void *OverloadedNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; }
+void OverloadedNewDelete::operator delete(void *) { }
+void OverloadedNewDelete::operator delete[](void *) { }
+int OverloadedNewDelete::operator+(int x) { return x; };
+
+// CHECK-DAG: ??2OverloadedNewDelete@@SAPAXI@Z
+// CHECK-DAG: ??_UOverloadedNewDelete@@SAPAXI@Z
+// CHECK-DAG: ??3OverloadedNewDelete@@SAXPAX@Z
+// CHECK-DAG: ??_VOverloadedNewDelete@@SAXPAX@Z
+// CHECK-DAG: ??HOverloadedNewDelete@@QAEHH@Z
+
+// X64-DAG: ??2OverloadedNewDelete@@SAPEAX_K@Z
+// X64-DAG: ??_UOverloadedNewDelete@@SAPEAX_K@Z
+// X64-DAG: ??3OverloadedNewDelete@@SAXPEAX@Z
+// X64-DAG: ??_VOverloadedNewDelete@@SAXPEAX@Z
+// X64-DAG: ??HOverloadedNewDelete@@QEAAHH@Z
+
+// Indirecting the function type through a typedef will require a calling
+// convention adjustment before building the method decl.
+
+typedef void *__thiscall OperatorNewType(__SIZE_TYPE__);
+typedef void __thiscall OperatorDeleteType(void *);
+
+struct TypedefNewDelete {
+ OperatorNewType operator new;
+ OperatorNewType operator new[];
+ OperatorDeleteType operator delete;
+ OperatorDeleteType operator delete[];
+};
+
+void *TypedefNewDelete::operator new(__SIZE_TYPE__ s) { return 0; }
+void *TypedefNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; }
+void TypedefNewDelete::operator delete(void *) { }
+void TypedefNewDelete::operator delete[](void *) { }
+
+// CHECK-DAG: ??2TypedefNewDelete@@SAPAXI@Z
+// CHECK-DAG: ??_UTypedefNewDelete@@SAPAXI@Z
+// CHECK-DAG: ??3TypedefNewDelete@@SAXPAX@Z
+// CHECK-DAG: ??_VTypedefNewDelete@@SAXPAX@Z
+
+namespace PR18022 {
+
+struct { } a;
+decltype(a) fun(decltype(a) x, decltype(a)) { return x; }
+// CHECK-DAG: ?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z
+
+}
diff --git a/test/CodeGenCXX/mangle-neon-vectors.cpp b/test/CodeGenCXX/mangle-neon-vectors.cpp
index 3723deb19219..249ec2e99b69 100644
--- a/test/CodeGenCXX/mangle-neon-vectors.cpp
+++ b/test/CodeGenCXX/mangle-neon-vectors.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm-none-linux-gnueabi -target-feature +neon %s -emit-llvm -o - | FileCheck %s
typedef float float32_t;
+typedef __fp16 float16_t;
typedef signed char poly8_t;
typedef short poly16_t;
typedef unsigned long long uint64_t;
@@ -11,8 +12,10 @@ typedef __attribute__((neon_vector_type(1))) uint64_t uint64x1_t;
typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t;
typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t;
typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
-typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
-typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
+typedef __attribute__((neon_vector_type(4))) float16_t float16x4_t;
+typedef __attribute__((neon_vector_type(8))) float16_t float16x8_t;
+typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
+typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
// CHECK: 16__simd64_int32_t
void f1(int32x2_t v) { }
@@ -26,7 +29,11 @@ void f4(uint64x2_t v) { }
void f5(float32x2_t v) { }
// CHECK: 19__simd128_float32_t
void f6(float32x4_t v) { }
+// CHECK: 18__simd64_float16_t
+void f7(float16x4_t v) {}
+// CHECK: 19__simd128_float16_t
+void f8(float16x8_t v) {}
// CHECK: 17__simd128_poly8_t
-void f7(poly8x16_t v) { }
+void f9(poly8x16_t v) {}
// CHECK: 18__simd128_poly16_t
-void f8(poly16x8_t v) { }
+void f10(poly16x8_t v) {}
diff --git a/test/CodeGenCXX/mangle-nullptr-arg.cpp b/test/CodeGenCXX/mangle-nullptr-arg.cpp
index 07bf52fc9067..b55ea6dd2dd4 100644
--- a/test/CodeGenCXX/mangle-nullptr-arg.cpp
+++ b/test/CodeGenCXX/mangle-nullptr-arg.cpp
@@ -2,15 +2,15 @@
template<int *ip> struct IP {};
-// CHECK: define void @_Z5test12IPILPi0EE
+// CHECK-LABEL: define void @_Z5test12IPILPi0EE
void test1(IP<nullptr>) {}
struct X{ };
template<int X::*pm> struct PM {};
-// CHECK: define void @_Z5test22PMILM1Xi0EE
+// CHECK-LABEL: define void @_Z5test22PMILM1Xi0EE
void test2(PM<nullptr>) { }
-// CHECK: define void @_Z5test316DependentTypePtrIPiLS0_0EE
+// CHECK-LABEL: define void @_Z5test316DependentTypePtrIPiLS0_0EE
template<typename T, T x> struct DependentTypePtr {};
void test3(DependentTypePtr<int*,nullptr>) { }
diff --git a/test/CodeGenCXX/mangle-ref-qualifiers.cpp b/test/CodeGenCXX/mangle-ref-qualifiers.cpp
index ce2af502e482..4552c93ea686 100644
--- a/test/CodeGenCXX/mangle-ref-qualifiers.cpp
+++ b/test/CodeGenCXX/mangle-ref-qualifiers.cpp
@@ -5,17 +5,17 @@ struct X {
int h() const &&;
};
-// CHECK: define i32 @_ZNR1X1fEv
+// CHECK-LABEL: define i32 @_ZNR1X1fEv
int X::f() & { return 0; }
-// CHECK: define i32 @_ZNO1X1gEv
+// CHECK-LABEL: define i32 @_ZNO1X1gEv
int X::g() && { return 0; }
-// CHECK: define i32 @_ZNKO1X1hEv
+// CHECK-LABEL: define i32 @_ZNKO1X1hEv
int X::h() const && { return 0; }
-// CHECK: define void @_Z1fM1XFivREMS_FivOEMS_KFivOE
+// CHECK-LABEL: define void @_Z1fM1XFivREMS_FivOEMS_KFivOE
void f(int (X::*)() &, int (X::*)() &&, int (X::*)() const&&) { }
-// CHECK: define void @_Z1g1AIFivEES_IFivREES_IFivOEES_IKFivEES_IKFivREES_IKFivOEES_IVKFivEES_IVKFivREES_IVKFivOEE()
+// CHECK-LABEL: define void @_Z1g1AIFivEES_IFivREES_IFivOEES_IKFivEES_IKFivREES_IKFivOEES_IVKFivEES_IVKFivREES_IVKFivOEE()
template <class T> struct A {};
void g(A<int()>, A<int()&>, A<int()&&>,
A<int() const>, A<int() const &>, A<int() const &&>,
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index 04e3e84304e8..6277c7af21c4 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -15,8 +15,8 @@
namespace std {
struct A { A(); };
- // CHECK: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr
- // CHECK: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr
+ // CHECK-LABEL: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr
A::A() { }
};
@@ -24,14 +24,14 @@ namespace std {
template<typename> struct allocator { };
}
-// CHECK: define void @_Z1fSaIcESaIiE
+// CHECK-LABEL: define void @_Z1fSaIcESaIiE
void f(std::allocator<char>, std::allocator<int>) { }
namespace std {
template<typename, typename, typename> struct basic_string { };
}
-// CHECK: define void @_Z1fSbIcciE
+// CHECK-LABEL: define void @_Z1fSbIcciE
void f(std::basic_string<char, char, int>) { }
namespace std {
@@ -90,7 +90,7 @@ namespace std
}
// Make sure we don't treat the following like std::string
-// CHECK: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE
+// CHECK-LABEL: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE
template<typename, typename, typename> struct basic_string { };
typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string;
void f(not_string) { }
@@ -106,7 +106,7 @@ namespace N {
namespace std {
struct A { void f(); };
- // CHECK: define void @_ZN1N3std1A1fEv
+ // CHECK-LABEL: define void @_ZN1N3std1A1fEv
void A::f() { }
}
}
diff --git a/test/CodeGenCXX/mangle-subst.cpp b/test/CodeGenCXX/mangle-subst.cpp
index d83a081dd76a..30360aeae317 100644
--- a/test/CodeGenCXX/mangle-subst.cpp
+++ b/test/CodeGenCXX/mangle-subst.cpp
@@ -2,19 +2,19 @@
struct X {};
-// CHECK: define void @_Z1f1XS_(
+// CHECK-LABEL: define void @_Z1f1XS_(
void f(X, X) { }
-// CHECK: define void @_Z1fR1XS0_(
+// CHECK-LABEL: define void @_Z1fR1XS0_(
void f(X&, X&) { }
-// CHECK: define void @_Z1fRK1XS1_(
+// CHECK-LABEL: define void @_Z1fRK1XS1_(
void f(const X&, const X&) { }
typedef void T();
struct S {};
-// CHECK: define void @_Z1fPFvvEM1SFvvE(
+// CHECK-LABEL: define void @_Z1fPFvvEM1SFvvE(
void f(T*, T (S::*)) {}
namespace A {
@@ -22,14 +22,14 @@ namespace A {
struct B { };
};
-// CHECK: define void @_Z1fN1A1AENS_1BE(
+// CHECK-LABEL: define void @_Z1fN1A1AENS_1BE(
void f(A::A a, A::B b) { }
struct C {
struct D { };
};
-// CHECK: define void @_Z1fN1C1DERS_PS_S1_(
+// CHECK-LABEL: define void @_Z1fN1C1DERS_PS_S1_(
void f(C::D, C&, C*, C&) { }
template<typename T>
diff --git a/test/CodeGenCXX/mangle-system-header.cpp b/test/CodeGenCXX/mangle-system-header.cpp
index 6716b58926d7..3ab5f96f6239 100644
--- a/test/CodeGenCXX/mangle-system-header.cpp
+++ b/test/CodeGenCXX/mangle-system-header.cpp
@@ -3,9 +3,9 @@
// PR5420
# 1 "fake_system_header.h" 1 3 4
-// CHECK: define void @_ZdlPvS_(
+// CHECK-LABEL: define void @_ZdlPvS_(
void operator delete (void*, void*) {}
// PR6217
-// CHECK: define void @_Z3barv()
+// CHECK-LABEL: define void @_Z3barv()
void bar() { }
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index 15a85c7bd2e5..3b7f3027f6c2 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -82,7 +82,7 @@ namespace test7 {
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
};
- // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr
+ // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(
template X<int>::X(double*, float*);
}
@@ -101,7 +101,7 @@ namespace test8 {
template<typename T>
void f(int_c<meta<T>::type::value>) { }
- // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE
+ // CHECK-LABEL: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE(
template void f<int>(int_c<sizeof(int)>);
}
@@ -160,13 +160,13 @@ namespace test12 {
const int n = 10;
template<typename T, T v> void test() {}
void use() {
- // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
+ // CHECK-LABEL: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
test<int(), &f>();
- // CHECK: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv(
+ // CHECK-LABEL: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv(
test<int(&)(), f>();
- // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
+ // CHECK-LABEL: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
test<const int*, &n>();
- // CHECK: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv(
+ // CHECK-LABEL: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv(
test<const int&, n>();
}
}
diff --git a/test/CodeGenCXX/mangle-unnamed.cpp b/test/CodeGenCXX/mangle-unnamed.cpp
index 53f381c3a011..a62bdd5393c4 100644
--- a/test/CodeGenCXX/mangle-unnamed.cpp
+++ b/test/CodeGenCXX/mangle-unnamed.cpp
@@ -80,7 +80,7 @@ template <class T> struct Test8 {
template <class T> void make_test8(T value) { Test8<T> t(value); }
void test8() { make_test8(T8); }
-// CHECK: define internal void @"_ZNV3$_35test9Ev"(
+// CHECK-LABEL: define internal void @"_ZNV3$_35test9Ev"(
typedef volatile struct {
void test9() volatile {}
} Test9;
@@ -89,4 +89,4 @@ void test9() {
a.test9();
}
-// CHECK: define internal void @"_ZN5Test8I3$_2EC1ES0_"(
+// CHECK-LABEL: define internal void @"_ZN5Test8I3$_2EC1ES0_"(
diff --git a/test/CodeGenCXX/mangle-valist.cpp b/test/CodeGenCXX/mangle-valist.cpp
index 73fd58e75e8a..0fcc1db73108 100644
--- a/test/CodeGenCXX/mangle-valist.cpp
+++ b/test/CodeGenCXX/mangle-valist.cpp
@@ -15,30 +15,30 @@ void Test2::test2(const char *fmt, va_list ap) {
// RUN: %clang_cc1 %s -emit-llvm -o - \
// RUN: -triple armv7-unknown-linux \
-// RUN: | FileCheck -check-prefix=MANGLE-ARM-AAPCS %s
+// RUN: | FileCheck -check-prefix=CHECK-MANGLE-ARM-AAPCS %s
// CHECK-MANGLE-ARM-AAPCS: @_ZN5test15test1EPKcSt9__va_list
// CHECK-MANGLE-ARM-AAPCS: @_ZN5Test25test2EPKcSt9__va_list
// RUN: %clang_cc1 %s -emit-llvm -o - \
// RUN: -triple armv7-unknown-linux -target-abi apcs-gnu \
-// RUN: | FileCheck -check-prefix=MANGLE-ARM-APCS %s
+// RUN: | FileCheck -check-prefix=CHECK-MANGLE-ARM-APCS %s
// CHECK-MANGLE-ARM-APCS: @_ZN5test15test1EPKcPv
// CHECK-MANGLE-ARM-APCS: @_ZN5Test25test2EPKcPv
// RUN: %clang_cc1 %s -emit-llvm -o - \
// RUN: -triple mipsel-unknown-linux \
-// RUN: | FileCheck -check-prefix=MANGLE-MIPSEL %s
+// RUN: | FileCheck -check-prefix=CHECK-MANGLE-MIPSEL %s
// CHECK-MANGLE-MIPSEL: @_ZN5test15test1EPKcPv
// CHECK-MANGLE-MIPSEL: @_ZN5Test25test2EPKcPv
// RUN: %clang_cc1 %s -emit-llvm -o - \
// RUN: -triple i686-unknown-linux \
-// RUN: | FileCheck -check-prefix=MANGLE-X86 %s
+// RUN: | FileCheck -check-prefix=CHECK-MANGLE-X86 %s
// CHECK-MANGLE-X86: @_ZN5test15test1EPKcPc
// CHECK-MANGLE-X86: @_ZN5Test25test2EPKcPc
// RUN: %clang_cc1 %s -emit-llvm -o - \
// RUN: -triple x86_64-unknown-linux \
-// RUN: | FileCheck -check-prefix=MANGLE-X86-64 %s
+// RUN: | FileCheck -check-prefix=CHECK-MANGLE-X86-64 %s
// CHECK-MANGLE-X86-64: @_ZN5test15test1EPKcP13__va_list_tag
// CHECK-MANGLE-X86-64: @_ZN5Test25test2EPKcP13__va_list_tag
diff --git a/test/CodeGenCXX/mangle-variadic-templates.cpp b/test/CodeGenCXX/mangle-variadic-templates.cpp
index b5bdae234445..264cc113cd57 100644
--- a/test/CodeGenCXX/mangle-variadic-templates.cpp
+++ b/test/CodeGenCXX/mangle-variadic-templates.cpp
@@ -9,59 +9,59 @@ template<typename ...Types> struct tuple { };
template<int ...Values> struct int_tuple { };
template<template<typename> class ...Templates> struct template_tuple { };
-// CHECK: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE
+// CHECK-LABEL: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE
template<typename ...Types>
void f0(X<sizeof...(Types), Types&...>) { }
template void f0(X<0>);
-// CHECK: define weak_odr void @_Z2f0IJifdEEv1XIXsZT_EJDpRT_EE
+// CHECK-LABEL: define weak_odr void @_Z2f0IJifdEEv1XIXsZT_EJDpRT_EE
template void f0<int, float, double>(X<3, int&, float&, double&>);
// Mangling for template argument packs
template<typename ...Types> void f1() {}
-// CHECK: define weak_odr void @_Z2f1IJEEvv
+// CHECK-LABEL: define weak_odr void @_Z2f1IJEEvv
template void f1<>();
-// CHECK: define weak_odr void @_Z2f1IJiEEvv
+// CHECK-LABEL: define weak_odr void @_Z2f1IJiEEvv
template void f1<int>();
-// CHECK: define weak_odr void @_Z2f1IJifEEvv
+// CHECK-LABEL: define weak_odr void @_Z2f1IJifEEvv
template void f1<int, float>();
// Mangling function parameter packs
template<typename ...Types> void f2(Types...) {}
-// CHECK: define weak_odr void @_Z2f2IJEEvDpT_
+// CHECK-LABEL: define weak_odr void @_Z2f2IJEEvDpT_
template void f2<>();
-// CHECK: define weak_odr void @_Z2f2IJiEEvDpT_
+// CHECK-LABEL: define weak_odr void @_Z2f2IJiEEvDpT_
template void f2<int>(int);
-// CHECK: define weak_odr void @_Z2f2IJifEEvDpT_
+// CHECK-LABEL: define weak_odr void @_Z2f2IJifEEvDpT_
template void f2<int, float>(int, float);
// Mangling non-trivial function parameter packs
template<typename ...Types> void f3(const Types *...) {}
-// CHECK: define weak_odr void @_Z2f3IJEEvDpPKT_
+// CHECK-LABEL: define weak_odr void @_Z2f3IJEEvDpPKT_
template void f3<>();
-// CHECK: define weak_odr void @_Z2f3IJiEEvDpPKT_
+// CHECK-LABEL: define weak_odr void @_Z2f3IJiEEvDpPKT_
template void f3<int>(const int*);
-// CHECK: define weak_odr void @_Z2f3IJifEEvDpPKT_
+// CHECK-LABEL: define weak_odr void @_Z2f3IJifEEvDpPKT_
template void f3<int, float>(const int*, const float*);
// Mangling of type pack expansions in a template argument
template<typename ...Types> tuple<Types...> f4() {}
-// CHECK: define weak_odr void @_Z2f4IJifdEE5tupleIJDpT_EEv
+// CHECK-LABEL: define weak_odr void @_Z2f4IJifdEE5tupleIJDpT_EEv
template tuple<int, float, double> f4();
// Mangling of type pack expansions in a function type
template<typename R, typename ...ArgTypes> identity<R(ArgTypes...)> f5() {}
-// CHECK: define weak_odr void @_Z2f5IiJifdEE8identityIFT_DpT0_EEv
+// CHECK-LABEL: define weak_odr void @_Z2f5IiJifdEE8identityIFT_DpT0_EEv
template identity<int(int, float, double)> f5();
// Mangling of non-type template argument expansions
template<int ...Values> int_tuple<Values...> f6() {}
-// CHECK: define weak_odr void @_Z2f6IJLi1ELi2ELi3EEE9int_tupleIJXspT_EEEv
+// CHECK-LABEL: define weak_odr void @_Z2f6IJLi1ELi2ELi3EEE9int_tupleIJXspT_EEEv
template int_tuple<1, 2, 3> f6();
// Mangling of template template argument expansions
template<template<typename> class ...Templates>
template_tuple<Templates...> f7() {}
-// CHECK: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv
+// CHECK-LABEL: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv
template template_tuple<identity, add_reference> f7();
diff --git a/test/CodeGenCXX/mangle-windows.cpp b/test/CodeGenCXX/mangle-windows.cpp
new file mode 100644
index 000000000000..c087616875c7
--- /dev/null
+++ b/test/CodeGenCXX/mangle-windows.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft \
+// RUN: -triple=i386-pc-win32 | FileCheck --check-prefix=WIN %s
+//
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | \
+// RUN: FileCheck --check-prefix=ITANIUM %s
+
+void __stdcall f1(void) {}
+// WIN: define x86_stdcallcc void @"\01?f1@@YGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__Z2f1v@0"
+
+void __fastcall f2(void) {}
+// WIN: define x86_fastcallcc void @"\01?f2@@YIXXZ"
+// ITANIUM: define x86_fastcallcc void @"\01@_Z2f2v@0"
+
+extern "C" void __stdcall f3(void) {}
+// WIN: define x86_stdcallcc void @"\01_f3@0"
+// ITANIUM: define x86_stdcallcc void @"\01_f3@0"
+
+extern "C" void __fastcall f4(void) {}
+// WIN: define x86_fastcallcc void @"\01@f4@0"
+// ITANIUM: define x86_fastcallcc void @"\01@f4@0"
+
+struct Foo {
+ void __stdcall foo();
+ static void __stdcall bar();
+};
+
+void Foo::foo() {}
+// WIN: define x86_stdcallcc void @"\01?foo@Foo@@QAGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3fooEv@4"
+
+void Foo::bar() {}
+// WIN: define x86_stdcallcc void @"\01?bar@Foo@@SGXXZ"
+// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3barEv@0"
+
+// Mostly a test that we don't crash and that the names start with a \01.
+// gcc on mingw produces __Zpp@4
+// cl produces _++@4
+extern "C" void __stdcall operator++(Foo &x) {
+}
+// WIN: define x86_stdcallcc void @"\01??E@YGXAAUFoo@@@Z"
+// ITANIUM: define x86_stdcallcc void @"\01__ZppR3Foo@4"
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index e7955a8ed910..d836f36c1818 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -9,37 +9,37 @@ struct Y { };
// CHECK: @_ZGVZN1N1gEvE1a = internal global
//CHECK: @pr5966_i = external global
-//CHECK: @_ZL8pr5966_i = internal global
+//CHECK: @_ZL8pr5966_j = internal global
-// CHECK: define zeroext i1 @_ZplRK1YRA100_P1X
+// CHECK-LABEL: define zeroext i1 @_ZplRK1YRA100_P1X
bool operator+(const Y&, X* (&xs)[100]) { return false; }
-// CHECK: define void @_Z1f1s
+// CHECK-LABEL: define void @_Z1f1s
typedef struct { int a; } s;
void f(s) { }
-// CHECK: define void @_Z1f1e
+// CHECK-LABEL: define void @_Z1f1e
typedef enum { foo } e;
void f(e) { }
-// CHECK: define void @_Z1f1u
+// CHECK-LABEL: define void @_Z1f1u
typedef union { int a; } u;
void f(u) { }
-// CHECK: define void @_Z1f1x
+// CHECK-LABEL: define void @_Z1f1x
typedef struct { int a; } x,y;
void f(y) { }
-// CHECK: define void @_Z1fv
+// CHECK-LABEL: define void @_Z1fv
void f() { }
-// CHECK: define void @_ZN1N1fEv
+// CHECK-LABEL: define void @_ZN1N1fEv
namespace N { void f() { } }
-// CHECK: define void @_ZN1N1N1fEv
+// CHECK-LABEL: define void @_ZN1N1N1fEv
namespace N { namespace N { void f() { } } }
-// CHECK: define void @unmangled_function
+// CHECK-LABEL: define void @unmangled_function
extern "C" { namespace N { void unmangled_function() { } } }
extern "C" { namespace N { int unmangled_variable = 10; } }
@@ -50,41 +50,41 @@ namespace N { int f(int, int) { static int b; return b; } }
namespace N { int h(); void g() { static int a = h(); } }
-// CHECK: define void @_Z1fno
+// CHECK-LABEL: define void @_Z1fno
void f(__int128_t, __uint128_t) { }
template <typename T> struct S1 {};
-// CHECK: define void @_Z1f2S1IiE
+// CHECK-LABEL: define void @_Z1f2S1IiE
void f(S1<int>) {}
-// CHECK: define void @_Z1f2S1IdE
+// CHECK-LABEL: define void @_Z1f2S1IdE
void f(S1<double>) {}
template <int N> struct S2 {};
-// CHECK: define void @_Z1f2S2ILi100EE
+// CHECK-LABEL: define void @_Z1f2S2ILi100EE
void f(S2<100>) {}
-// CHECK: define void @_Z1f2S2ILin100EE
+// CHECK-LABEL: define void @_Z1f2S2ILin100EE
void f(S2<-100>) {}
template <bool B> struct S3 {};
-// CHECK: define void @_Z1f2S3ILb1EE
+// CHECK-LABEL: define void @_Z1f2S3ILb1EE
void f(S3<true>) {}
-// CHECK: define void @_Z1f2S3ILb0EE
+// CHECK-LABEL: define void @_Z1f2S3ILb0EE
void f(S3<false>) {}
struct S;
-// CHECK: define void @_Z1fM1SKFvvE
+// CHECK-LABEL: define void @_Z1fM1SKFvvE
void f(void (S::*)() const) {}
-// CHECK: define void @_Z1fM1SFvvE
+// CHECK-LABEL: define void @_Z1fM1SFvvE
void f(void (S::*)()) {}
-// CHECK: define void @_Z1fi
+// CHECK-LABEL: define void @_Z1fi
void f(const int) { }
template<typename T, typename U> void ft1(U u, T t) { }
@@ -238,7 +238,7 @@ template<bool, typename> struct __enable_if {};
template<typename T> struct __enable_if<true, T> { typedef T __type; };
template<typename T>
-// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
+// CHECK-LABEL: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv
typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { };
void f() { __fill_a<int>(); }
@@ -247,26 +247,26 @@ void f() { __fill_a<int>(); }
namespace Expressions {
// Unary operators.
-// CHECK: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i
+// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i
template <int i> void f1(int (*)[(-i) + 2]) { };
template void f1<1>(int (*)[1]);
-// CHECK: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i
+// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i
template <int i> void f2(int (*)[+i]) { };
template void f2<1>(int (*)[1]);
// Binary operators.
-// CHECK: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i
+// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i
template <int i> void f3(int (*)[i+i]) { };
template void f3<1>(int (*)[2]);
-// CHECK: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i
+// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i
template <int i> void f4(int (*)[2 + i+i]) { };
template void f4<1>(int (*)[4]);
// The ternary operator.
-// CHECK: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i
+// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i
template <bool b> void f4(int (*)[b ? 1 : 2]) { };
template void f4<true>(int (*)[1]);
}
@@ -280,13 +280,13 @@ struct Ops {
void *v;
};
-// CHECK: define %struct.Ops* @_ZN3OpsplERKS_
+// CHECK-LABEL: define %struct.Ops* @_ZN3OpsplERKS_
Ops& Ops::operator+(const Ops&) { return *this; }
-// CHECK: define %struct.Ops* @_ZN3OpsmiERKS_
+// CHECK-LABEL: define %struct.Ops* @_ZN3OpsmiERKS_
Ops& Ops::operator-(const Ops&) { return *this; }
-// CHECK: define %struct.Ops* @_ZN3OpsanERKS_
+// CHECK-LABEL: define %struct.Ops* @_ZN3OpsanERKS_
Ops& Ops::operator&(const Ops&) { return *this; }
-// CHECK: define %struct.Ops* @_ZN3OpsmlERKS_
+// CHECK-LABEL: define %struct.Ops* @_ZN3OpsmlERKS_
Ops& Ops::operator*(const Ops&) { return *this; }
// PR5861
@@ -302,11 +302,11 @@ template<typename T, typename = Policy<P, true> > class Alloc
T *allocate(int, const void*) { return 0; }
};
-// CHECK: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv
+// CHECK-LABEL: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv
template class Alloc<char>;
}
-// CHECK: define void @_Z1fU13block_pointerFiiiE
+// CHECK-LABEL: define void @_Z1fU13block_pointerFiiiE
void f(int (^)(int, int)) { }
void pr5966_foo() {
@@ -314,10 +314,10 @@ void pr5966_foo() {
pr5966_i = 0;
}
-static int pr5966_i;
+static int pr5966_j;
void pr5966_bar() {
- pr5966_i = 0;
+ pr5966_j = 0;
}
namespace test0 {
@@ -330,29 +330,29 @@ namespace test0 {
char buffer[1];
f(0.0, buffer);
}
- // CHECK: define void @_ZN5test05test0Ev()
- // CHECK: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c(
+ // CHECK-LABEL: define void @_ZN5test05test0Ev()
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c(
void test1() {
char buffer[sizeof(int)];
f(1, buffer);
}
- // CHECK: define void @_ZN5test05test1Ev()
- // CHECK: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c(
+ // CHECK-LABEL: define void @_ZN5test05test1Ev()
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c(
template <class T> void g(char (&buffer)[sizeof(T() + 5.0f)]) {}
void test2() {
char buffer[sizeof(float)];
g<float>(buffer);
}
- // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c(
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c(
template <class T> void h(char (&buffer)[sizeof(T() + 5.0)]) {}
void test3() {
char buffer[sizeof(double)];
h<float>(buffer);
}
- // CHECK: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c(
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c(
template <class T> void j(char (&buffer)[sizeof(T().buffer)]) {}
struct A { double buffer[128]; };
@@ -360,25 +360,25 @@ namespace test0 {
char buffer[1024];
j<A>(buffer);
}
- // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c(
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c(
template <class T> void k(char (&buffer)[sizeof(T() + 0.0f)]) {}
void test5() {
char buffer[sizeof(float)];
k<float>(buffer);
}
- // CHECK: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c(
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c(
}
namespace test1 {
template<typename T> struct X { };
template<template<class> class Y, typename T> void f(Y<T>) { }
- // CHECK: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E
+ // CHECK-LABEL: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E
template void f(X<int>);
}
-// CHECK: define internal void @_ZL27functionWithInternalLinkagev()
+// CHECK-LABEL: define internal void @_ZL27functionWithInternalLinkagev()
static void functionWithInternalLinkage() { }
void g() { functionWithInternalLinkage(); }
@@ -392,7 +392,7 @@ namespace test2 {
return read_member(obj);
}
- // CHECK: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_(
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_(
}
// rdar://problem/9280586
@@ -402,16 +402,16 @@ namespace test3 {
struct Path2 : AmbiguousBase { double p; };
struct Derived : Path1, Path2 { };
- // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_(
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_(
template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; }
- // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_(
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_(
template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; }
- // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_(
+ // CHECK-LABEL: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_(
template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; }
- // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_(
+ // CHECK-LABEL: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_(
template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; }
Derived obj;
@@ -423,7 +423,7 @@ namespace test3 {
}
}
-// CHECK: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
+// CHECK-LABEL: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
namespace test4 {
struct foo { int bar; };
template <int (foo::*)>
@@ -431,7 +431,7 @@ namespace test4 {
void g(zed<&foo::bar>*)
{}
}
-// CHECK: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
+// CHECK-LABEL: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE
namespace test5 {
struct foo { static int bar; };
template <int *>
@@ -439,7 +439,7 @@ namespace test5 {
void g(zed<&foo::bar>*)
{}
}
-// CHECK: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
+// CHECK-LABEL: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
namespace test6 {
struct foo { int bar(); };
template <int (foo::*)()>
@@ -447,7 +447,7 @@ namespace test6 {
void g(zed<&foo::bar>*)
{}
}
-// CHECK: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
+// CHECK-LABEL: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE
namespace test7 {
struct foo { static int bar(); };
template <int (*f)()>
@@ -455,7 +455,7 @@ namespace test7 {
void g(zed<&foo::bar>*)
{}
}
-// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv
+// CHECK-LABEL: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv
namespace test8 {
template <int &counter> class A { void inc() { counter++; } };
class B { public: static int value; };
@@ -482,7 +482,7 @@ namespace test10 {
template <char P1> struct S {};
template <char P2> void f(struct S<false ? 'a' : P2> ) {}
- // CHECK: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE(
template void f<(char) 3>(struct S<3>);
}
@@ -512,7 +512,7 @@ namespace test13 {
template <template<class> class T> void foo(const A<T> &a) {}
- // CHECK: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE(
template void foo(const A<B> &a);
}
@@ -521,7 +521,7 @@ namespace test14 {
struct S {
static int a(), x;
};
- // CHECK: define i32 @_ZN6test141S1aEv
+ // CHECK-LABEL: define i32 @_ZN6test141S1aEv
// CHECK: load i32* @_ZN6test141S1xE
int S::a() { return S::x; }
}
@@ -534,7 +534,7 @@ namespace test15 {
template <int I> void f(S<I + e>) {}
- // CHECK: define weak_odr void @_ZN6test151fILi7EEEvNS_1SIXplT_LNS_1EE3EEEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test151fILi7EEEvNS_1SIXplT_LNS_1EE3EEEE(
template void f<7>(S<7 + e>);
}
@@ -548,7 +548,7 @@ namespace test17 {
template <class T> A<sizeof(T::foo())> func(void);
- // CHECK: define void @_ZN6test174testEv()
+ // CHECK-LABEL: define void @_ZN6test174testEv()
// CHECK: call {{.*}} @_ZN6test174funcINS_1BEEENS_1AIXszclsrT_3fooEEEEv()
void test() {
func<B>();
@@ -577,10 +577,10 @@ namespace test18 {
template <typename T> void f(S<&T::operator&>) {}
template void f<A>(S<&A::operator&>);
- // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_plEEE
- // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_miEEE
- // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_mlEEE
- // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_anEEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_plEEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_miEEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_mlEEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_anEEE
}
// rdar://problem/8332117
@@ -599,13 +599,13 @@ namespace test19 {
template <typename T> void g (S<&T::operator int>) {}
template <typename T> void g (S<&T::template operator- <double> >) {}
- // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_1fIiEEEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_1fIiEEEE(
template void g<A>(S<&A::f<int> >);
- // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_plEEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_plEEE(
template void g<A>(S<&A::operator+>);
- // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_cviEEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_cviEEE(
template void g<A>(S<&A::operator int>);
- // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_miIdEEEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_miIdEEEE(
template void g<A>(S<&A::operator-<double> >);
}
@@ -613,23 +613,23 @@ namespace test20 {
template <class T> T *f(const T&);
template <class T> T *f(T*);
- // CHECK: define weak_odr void @_ZN6test205test0IiEEvDTcl1fIPT_ELi0EEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test205test0IiEEvDTcl1fIPT_ELi0EEE(
template <class T> void test0(decltype(f<T*>(0))) {}
template void test0<int>(decltype(f<int*>(0)));
- // CHECK: define weak_odr void @_ZN6test205test1IiEEvDTcl1fIEcvT__EEE(
+ // CHECK-LABEL: define weak_odr void @_ZN6test205test1IiEEvDTcl1fIEcvT__EEE(
template <class T> void test1(decltype(f<>(T()))) {}
template void test1<int>(decltype(f<>(int())));
}
// rdar:// 8620510
namespace test21 {
- // CHECK: define void @_ZN6test2112vla_arg_funcEiPA_i(
+ // CHECK-LABEL: define void @_ZN6test2112vla_arg_funcEiPA_i(
void vla_arg_func(int X, int a[X][X]) {}
}
namespace test22 {
- // CHECK: define void @_ZN6test221fEDn(
+ // CHECK-LABEL: define void @_ZN6test221fEDn(
void f(decltype(nullptr)) { }
}
@@ -637,12 +637,12 @@ namespace test22 {
namespace test23 {
typedef void * const vpc;
- // CHECK: define void @_ZN6test231fERA10_KPv(
+ // CHECK-LABEL: define void @_ZN6test231fERA10_KPv(
void f(vpc (&)[10]) {}
typedef vpc vpca5[5];
void f(vpca5 volatile (&)[10]) {}
- // CHECK: define void @_ZN6test231fERA10_A5_VKPv(
+ // CHECK-LABEL: define void @_ZN6test231fERA10_A5_VKPv(
}
namespace test24 {
@@ -652,10 +652,10 @@ namespace test24 {
foo();
}
- static char foo() {}
+ static char bar() {}
void test1() {
- // CHECK: call signext i8 @_ZN6test24L3fooEv()
- foo();
+ // CHECK: call signext i8 @_ZN6test24L3barEv()
+ bar();
}
}
@@ -757,11 +757,11 @@ namespace test31 { // instantiation-dependent mangling of decltype
void g(int);
template<class T> auto f3(T p)->decltype(g(p)) {}
- // CHECK: define weak_odr i32 @_ZN6test312f1IiEEiT_(
+ // CHECK-LABEL: define weak_odr i32 @_ZN6test312f1IiEEiT_(
template int f1(int);
- // CHECK: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_
+ // CHECK-LABEL: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_
template int f2(int);
- // CHECK: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_
+ // CHECK-LABEL: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_
template void f3(int);
}
@@ -802,14 +802,14 @@ namespace test34 {
template<typename T>
void f(decltype(sizeof(decltype(T() + T())))) {}
- // CHECK: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE
template void f<int>(decltype(sizeof(1)));
// Mangling for non-instantiation-dependent sizeof expressions.
template<unsigned N>
void f2(int (&)[N + sizeof(int*)]) {}
- // CHECK: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i
+ // CHECK-LABEL: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i
template void f2<4>(int (&)[4 + sizeof(int*)]);
// Mangling for non-instantiation-dependent sizeof expressions
@@ -817,7 +817,7 @@ namespace test34 {
template<unsigned long long N>
void f3(int (&)[N + sizeof(int*)]) {}
- // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i
+ // CHECK-LABEL: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i
template void f3<4>(int (&)[4 + sizeof(int*)]);
// Mangling for instantiation-dependent sizeof() expressions as
@@ -826,7 +826,7 @@ namespace test34 {
template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { }
- // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE
template void f4<int>(A<sizeof(sizeof(int))>);
}
@@ -839,7 +839,7 @@ namespace test35 {
template<typename T>
void f1(decltype(sizeof(&T::template operator+<int>))) {}
- // CHECK: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE
+ // CHECK-LABEL: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE
template void f1<A>(__SIZE_TYPE__);
}
@@ -864,14 +864,90 @@ namespace test37 {
};
template<typename T> void func(T) { }
void test() {
- // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_
func(foo().a);
- // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_
func(*foo::c());
- // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_
func(foo().d);
}
}
-// CHECK: define void @_Z6ASfuncPU3AS3i
+// CHECK-LABEL: define void @_Z6ASfuncPU3AS3i
void ASfunc(__attribute__((address_space(3))) int* x) {}
+
+namespace test38 {
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test384funcINS_3fooUt_EEEvT_
+ typedef struct {
+ struct {
+ } a;
+ } foo;
+
+ template <typename T> void func(T) {}
+ void test() { func(foo().a); }
+}
+
+namespace test39 {
+ // CHECK-LABEL: define internal void @"_ZN6test394funcINS_3$_03$_1EEEvT_"
+ typedef struct {
+ struct {} a;
+ } *foo;
+ template<typename T> void func(T) {}
+ void test(foo x) {
+ func(x->a);
+ }
+}
+
+namespace test40 {
+ // CHECK: i32* @_ZZN6test401fEvE1a_0
+ void h(int&);
+ inline void f() {
+ if (0) {
+ static int a;
+ }
+ static int a;
+ h(a);
+ };
+ void g() { f(); }
+}
+
+namespace test41 {
+ // CHECK: define linkonce_odr void @_ZN6test414funcINS_1XEEEvNS_3fooILi20ES1_EE
+ template <int i, class T> struct foo {
+ template <class T2 = T> friend void func(foo x) {}
+ };
+
+ struct X {};
+
+ void g() { func(foo<20, X>()); }
+}
+
+namespace test42 {
+ // CHECK: define linkonce_odr void @_ZN6test424funcINS_1XEEEvNS_3fooILi20ES1_EE
+ template <int i, template <class> class T> struct foo {
+ template <template <class> class T2 = T> friend void func(foo x) {}
+ };
+
+ template <class V> struct X {
+ };
+
+ void g() { func(foo<20, X>()); }
+}
+
+namespace test43 {
+ // CHECK-LABEL: define void @_ZN6test431gEPNS_3zedIXadL_ZNS_3fooUt_3barEEEEE
+ struct foo { union { int bar; }; };
+ template <int (foo::*)>
+ struct zed {};
+ void g(zed<&foo::bar>*)
+ {}
+}
+
+namespace test44 {
+ struct foo { void bar() __restrict { }; } obj;
+
+ void f() {
+ obj.bar();
+ }
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test443foo3barEv(%"struct.test44::foo"* %this)
+}
diff --git a/test/CodeGenCXX/member-expressions.cpp b/test/CodeGenCXX/member-expressions.cpp
index d9fb3940b05b..48502727be7f 100644
--- a/test/CodeGenCXX/member-expressions.cpp
+++ b/test/CodeGenCXX/member-expressions.cpp
@@ -58,7 +58,7 @@ namespace test4 {
extern C *c_ptr;
- // CHECK: define i32 @_ZN5test44testEv()
+ // CHECK-LABEL: define i32 @_ZN5test44testEv()
int test() {
// CHECK: load {{.*}} @_ZN5test45c_ptrE
// CHECK-NEXT: bitcast
diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp
index f8960aac52ef..99162ebd5863 100644
--- a/test/CodeGenCXX/member-function-pointer-calls.cpp
+++ b/test/CodeGenCXX/member-function-pointer-calls.cpp
@@ -8,14 +8,14 @@ int f(A* a, int (A::*fp)()) {
return (a->*fp)();
}
-// CHECK: define i32 @_Z2g1v()
+// CHECK-LABEL: define i32 @_Z2g1v()
// CHECK: ret i32 1
int g1() {
A a;
return f(&a, &A::vf1);
}
-// CHECK: define i32 @_Z2g2v()
+// CHECK-LABEL: define i32 @_Z2g2v()
// CHECK: ret i32 2
int g2() {
A a;
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 84b54b67d315..fb06fa77039d 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -4,6 +4,9 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-unknown-unknown | FileCheck -check-prefix GLOBAL-LP32 %s
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix GLOBAL-ARM %s
+// PNaCl uses the same representation of method pointers as ARM.
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=le32-unknown-nacl | FileCheck -check-prefix GLOBAL-ARM %s
+
struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
struct B { int b; virtual void g(); };
struct C : B, A { };
@@ -226,7 +229,7 @@ namespace test9 {
fooptr p;
};
- // CODE-LP64: define void @_ZN5test94testEv(
+ // CODE-LP64-LABEL: define void @_ZN5test94testEv(
// CODE-LP64: alloca i32
// CODE-LP64-NEXT: ret void
void test() {
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
index 75b354cd0f93..1773c67fc863 100644
--- a/test/CodeGenCXX/member-functions.cpp
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -5,11 +5,11 @@ struct C {
void g(int, ...);
};
-// CHECK: define void @_ZN1C1fEv
+// CHECK-LABEL: define void @_ZN1C1fEv
void C::f() {
}
-// CHECK: define void @_Z5test1v
+// CHECK-LABEL: define void @_Z5test1v
void test1() {
C c;
@@ -34,7 +34,7 @@ struct S {
virtual void v() {}
};
-// CHECK: define void @_ZN1S1fEv
+// CHECK-LABEL: define void @_ZN1S1fEv
void S::f() {
}
@@ -51,13 +51,13 @@ void test2() {
// CHECK: define linkonce_odr void @_ZN1SC1Ev{{.*}} unnamed_addr
// S::f_inline1()
-// CHECK: define linkonce_odr void @_ZN1S9f_inline1Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN1S9f_inline1Ev
// S::f_inline2()
-// CHECK: define linkonce_odr void @_ZN1S9f_inline2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN1S9f_inline2Ev
// S::g()
-// CHECK: define linkonce_odr void @_ZN1S1gEv
+// CHECK-LABEL: define linkonce_odr void @_ZN1S1gEv
// S::~S()
// CHECK: define linkonce_odr void @_ZN1SD1Ev{{.*}} unnamed_addr
@@ -66,7 +66,7 @@ struct T {
T operator+(const T&);
};
-// CHECK: define void @_Z5test3v
+// CHECK-LABEL: define void @_Z5test3v
void test3() {
T t1, t2;
diff --git a/test/CodeGenCXX/member-init-anon-union.cpp b/test/CodeGenCXX/member-init-anon-union.cpp
index 4db31f0b83fd..bfe1667c8c6c 100644
--- a/test/CodeGenCXX/member-init-anon-union.cpp
+++ b/test/CodeGenCXX/member-init-anon-union.cpp
@@ -11,7 +11,7 @@ static union {
int f() { return a; }
-// CHECK: define internal void @__cxx_global_var_init
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK-NOT: }
// CHECK: call {{.*}}@"[[CONSTRUCT_GLOBAL:.*]]C1Ev"
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
index c22b99d60627..c98e6bf92362 100644
--- a/test/CodeGenCXX/member-initializers.cpp
+++ b/test/CodeGenCXX/member-initializers.cpp
@@ -12,7 +12,7 @@ struct B : A {
int i;
};
-// CHECK: define i32 @_Z1fv() #0
+// CHECK-LABEL: define i32 @_Z1fv() #0
int f() {
B b;
diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp
index 7e4bdca77f38..c72dd6e5f528 100644
--- a/test/CodeGenCXX/member-templates.cpp
+++ b/test/CodeGenCXX/member-templates.cpp
@@ -15,8 +15,8 @@ struct B {
template<typename T> B::B(T) {}
-// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr
-// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr
+// CHECK-LABEL: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr
+// CHECK-LABEL: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr
template B::B(int);
template<typename T>
diff --git a/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp b/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp
new file mode 100644
index 000000000000..7407efed2f9d
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i686-pc-win32 -o - %s 2>/dev/null | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 -o - %s 2>/dev/null | FileCheck %s -check-prefix CHECK-X64
+
+struct B { char a; };
+struct A : virtual B {} a;
+
+// The <> indicate that the pointer is packed, which is required to support
+// microsoft layout in 32 bit mode, but not 64 bit mode.
+// CHECK: %struct.A = type <{ i32*, %struct.B }>
+// CHECK-X64: %struct.A = type { i32*, %struct.B }
diff --git a/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp
new file mode 100644
index 000000000000..92db9a789b3c
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct A {
+ constexpr A(int x) : x(x) {}
+ virtual void f();
+ int x;
+};
+
+A a(42);
+// CHECK: @"\01?a@@3UA@@A" = global { [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7A@@6B@", i32 42 }, align 4
+
+struct B {
+ constexpr B(int y) : y(y) {}
+ virtual void g();
+ int y;
+};
+
+struct C : A, B {
+ constexpr C() : A(777), B(13) {}
+};
+
+C c;
+// CHECK: @"\01?c@@3UC@@A" = global { [1 x i8*]*, i32, [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7C@@6BA@@@", i32 777, [1 x i8*]* @"\01??_7C@@6BB@@@", i32 13 }
diff --git a/test/CodeGenCXX/microsoft-abi-default-cc.cpp b/test/CodeGenCXX/microsoft-abi-default-cc.cpp
index 7f2fc0a89d7a..d7fba9911e1b 100644
--- a/test/CodeGenCXX/microsoft-abi-default-cc.cpp
+++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp
@@ -12,13 +12,13 @@
void foo();
void __cdecl foo();
void __cdecl foo() {}
-// GCABI: define void @_Z3foov()
+// GCABI-LABEL: define void @_Z3foov()
// MSABI: define void @"\01?foo@@YAXXZ"
void __cdecl bar();
void bar();
void bar() {}
-// GCABI: define void @_Z3barv()
+// GCABI-LABEL: define void @_Z3barv()
// MSABI: define void @"\01?bar@@YAXXZ"
// Test that it's OK to mark either the method declaration or method definition
@@ -33,15 +33,15 @@ public:
};
void METHOD_CC A::baz() {}
-// GCABI: define void @_ZN1A3bazEv
+// GCABI-LABEL: define void @_ZN1A3bazEv
// MSABI: define x86_thiscallcc void @"\01?baz@A@@QAEXXZ"
void A::qux() {}
-// GCABI: define void @_ZN1A3quxEv
+// GCABI-LABEL: define void @_ZN1A3quxEv
// MSABI: define x86_thiscallcc void @"\01?qux@A@@QAEXXZ"
void __cdecl static_baz() {}
-// GCABI: define void @_Z10static_bazv
+// GCABI-LABEL: define void @_Z10static_bazv
// MSABI: define void @"\01?static_baz@@YAXXZ"
void static_qux() {}
-// GCABI: define void @_Z10static_quxv
+// GCABI-LABEL: define void @_Z10static_quxv
// MSABI: define void @"\01?static_qux@@YAXXZ"
diff --git a/test/CodeGenCXX/microsoft-abi-exceptions.cpp b/test/CodeGenCXX/microsoft-abi-exceptions.cpp
new file mode 100644
index 000000000000..7757ea004359
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-exceptions.cpp
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
+
+struct A {
+ A();
+ ~A();
+ int a;
+};
+
+A getA();
+
+int TakesTwo(A a, A b);
+void HasEHCleanup() {
+ TakesTwo(getA(), getA());
+}
+
+// With exceptions, we need to clean up at least one of these temporaries.
+// WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
+// First one doesn't have any cleanups, no need for invoke.
+// WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
+// If this call throws, we have to cleanup the first temporary.
+// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
+// If this call throws, we already popped our cleanups
+// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// WIN32: ret void
+//
+// There should be one dtor call for unwinding from the second getA.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: }
+
+void TakeRef(const A &a);
+int HasDeactivatedCleanups() {
+ return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
+}
+
+// WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
+// WIN32: %[[isactive:.*]] = alloca i1
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]])
+// WIN32: store i1 true, i1* %[[isactive]]
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 false, i1* %[[isactive]]
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// Destroy the two const ref temporaries.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: ret i32
+//
+// Conditionally destroy arg1.
+// WIN32: %[[cond:.*]] = load i1* %[[isactive]]
+// WIN32: br i1 %[[cond]]
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
+
+// Test putting the cleanups inside a conditional.
+int CouldThrow();
+int HasConditionalCleanup(bool cond) {
+ return (cond ? TakesTwo(A(), A()) : CouldThrow());
+}
+
+// WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} {
+// WIN32: store i1 false
+// WIN32: br i1
+// No cleanups, so we call and then activate a cleanup if it succeeds.
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]])
+// WIN32: store i1 true
+// Now we have a cleanup for the first aggregate, so we invoke.
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
+// Now we have no cleanups because TakeTwo will destruct both args.
+// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// Still no cleanups, so call.
+// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()
+// Somewhere in the landing pad for our single invoke, call the dtor.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
+
+// Now test both.
+int HasConditionalDeactivatedCleanups(bool cond) {
+ return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
+}
+
+// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {
+// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4
+// WIN32: alloca i1
+// WIN32: %[[arg1_cond:.*]] = alloca i1
+// Start all four cleanups as deactivated.
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: br i1
+// True condition.
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: store i1 true, i1* %[[arg1_cond]]
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: store i1 false, i1* %[[arg1_cond]]
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// False condition.
+// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
+// Two normal cleanups for TakeRef args.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: ret i32
+//
+// Somewhere in the landing pad soup, we conditionally destroy arg1.
+// WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]]
+// WIN32: br i1 %[[isactive]]
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
+
+namespace crash_on_partial_destroy {
+struct A {
+ virtual ~A();
+};
+
+struct B : virtual A {
+ // Has an implicit destructor.
+};
+
+struct C : B {
+ C();
+};
+
+void foo();
+// We used to crash when emitting this.
+C::C() { foo(); }
+
+// Verify that we don't bother with a vbtable lookup when adjusting the this
+// pointer to call a base destructor from a constructor while unwinding.
+// WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} {
+// WIN32: landingpad
+//
+// We shouldn't do any vbptr loads, just constant GEPs.
+// WIN32-NOT: load
+// WIN32: getelementptr i8* %{{.*}}, i32 4
+// WIN32-NOT: load
+// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"*
+// WIN32: invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"
+//
+// WIN32-NOT: load
+// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8*
+// WIN32-NOT: load
+// WIN32: getelementptr inbounds i8* %{{.*}}, i64 4
+// WIN32-NOT: load
+// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*
+// WIN32: invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"
+// WIN32: }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 3fffc9d72cb1..c0dcd3cf8316 100755
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -1,16 +1,20 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// FIXME: Test x86_64 member pointers when codegen no longer asserts on records
+// with virtual bases.
struct B1 {
void foo();
int b;
};
struct B2 {
+ int b2;
void foo();
};
struct Single : B1 {
void foo();
};
struct Multiple : B1, B2 {
+ int m;
void foo();
};
struct Virtual : virtual B1 {
@@ -34,9 +38,11 @@ struct Polymorphic {
// offset.
struct NonZeroVBPtr : POD, Virtual {
int n;
+ void foo();
};
struct Unspecified;
+struct UnspecSingle;
// Check that we can lower the LLVM types and get the null initializers right.
int Single ::*s_d_memptr;
@@ -45,29 +51,95 @@ int Multiple ::*m_d_memptr;
int Virtual ::*v_d_memptr;
int NonZeroVBPtr::*n_d_memptr;
int Unspecified::*u_d_memptr;
-// CHECK: @"\01?s_d_memptr@@3PQSingle@@HA" = global i32 -1, align 4
-// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HA" = global i32 0, align 4
-// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HA" = global i32 -1, align 4
-// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HA" = global { i32, i32 }
+int UnspecSingle::*us_d_memptr;
+// CHECK: @"\01?s_d_memptr@@3PQSingle@@HQ1@" = global i32 -1, align 4
+// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HQ1@" = global i32 0, align 4
+// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HQ1@" = global i32 -1, align 4
+// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HQ1@" = global { i32, i32 }
// CHECK: { i32 0, i32 -1 }, align 4
-// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HA" = global { i32, i32 }
+// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HQ1@" = global { i32, i32 }
// CHECK: { i32 0, i32 -1 }, align 4
-// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HA" = global { i32, i32, i32 }
+// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HQ1@" = global { i32, i32, i32 }
+// CHECK: { i32 0, i32 0, i32 -1 }, align 4
+// CHECK: @"\01?us_d_memptr@@3PQUnspecSingle@@HQ1@" = global { i32, i32, i32 }
// CHECK: { i32 0, i32 0, i32 -1 }, align 4
void (Single ::*s_f_memptr)();
void (Multiple::*m_f_memptr)();
void (Virtual ::*v_f_memptr)();
-// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZA" = global i8* null, align 4
-// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4
-// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4
+// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZQ1@" = global i8* null, align 4
+// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4
+// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4
// We can define Unspecified after locking in the inheritance model.
-struct Unspecified : Virtual {
+struct Unspecified : Multiple, Virtual {
void foo();
int u;
};
+struct UnspecSingle {
+ void foo();
+};
+
+// Test memptr emission in a constant expression.
+namespace Const {
+void (Single ::*s_f_mp)() = &Single::foo;
+void (Multiple ::*m_f_mp)() = &B2::foo;
+void (Virtual ::*v_f_mp)() = &Virtual::foo;
+void (Unspecified::*u_f_mp)() = &Unspecified::foo;
+void (UnspecSingle::*us_f_mp)() = &UnspecSingle::foo;
+// CHECK: @"\01?s_f_mp@Const@@3P8Single@@AEXXZQ2@" =
+// CHECK: global i8* bitcast ({{.*}} @"\01?foo@Single@@QAEXXZ" to i8*), align 4
+// CHECK: @"\01?m_f_mp@Const@@3P8Multiple@@AEXXZQ2@" =
+// CHECK: global { i8*, i32 } { i8* bitcast ({{.*}} @"\01?foo@B2@@QAEXXZ" to i8*), i32 4 }, align 4
+// CHECK: @"\01?v_f_mp@Const@@3P8Virtual@@AEXXZQ2@" =
+// CHECK: global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 4
+// CHECK: @"\01?u_f_mp@Const@@3P8Unspecified@@AEXXZQ2@" =
+// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, align 4
+// CHECK: @"\01?us_f_mp@Const@@3P8UnspecSingle@@AEXXZQ2@" =
+// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@UnspecSingle@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 4
+}
+
+namespace CastParam {
+// This exercises ConstExprEmitter instead of ValueDecl::evaluateValue. The
+// extra reinterpret_cast for the parameter type requires more careful folding.
+// FIXME: Or does it? If reinterpret_casts are no-ops, we should be able to
+// strip them in evaluateValue() and just proceed as normal with an APValue.
+struct A {
+ int a;
+ void foo(A *p);
+};
+struct B { int b; };
+struct C : B, A { int c; };
+
+void (A::*ptr1)(void *) = (void (A::*)(void *)) &A::foo;
+// CHECK: @"\01?ptr1@CastParam@@3P8A@1@AEXPAX@ZQ21@" =
+// CHECK: global i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), align 4
+
+// Try a reinterpret_cast followed by a memptr conversion.
+void (C::*ptr2)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) &A::foo;
+// CHECK: @"\01?ptr2@CastParam@@3P8C@1@AEXPAX@ZQ21@" =
+// CHECK: global { i8*, i32 } { i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), i32 4 }, align 4
+
+void (C::*ptr3)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) (void (A::*)(A *)) 0;
+// CHECK: @"\01?ptr3@CastParam@@3P8C@1@AEXPAX@ZQ21@" =
+// CHECK: global { i8*, i32 } zeroinitializer, align 4
+
+struct D : C {
+ virtual void isPolymorphic();
+ int d;
+};
+
+// Try a cast that changes the inheritance model. Null for D is 0, but null for
+// C is -1. We need the cast to long in order to hit the non-APValue path.
+int C::*ptr4 = (int C::*) (int D::*) (long D::*) 0;
+// CHECK: @"\01?ptr4@CastParam@@3PQC@1@HQ21@" = global i32 -1, align 4
+
+// MSVC rejects this but we accept it.
+int C::*ptr5 = (int C::*) (long D::*) 0;
+// CHECK: @"\01?ptr5@CastParam@@3PQC@1@HQ21@" = global i32 -1, align 4
+}
+
struct UnspecWithVBPtr;
int UnspecWithVBPtr::*forceUnspecWithVBPtr;
struct UnspecWithVBPtr : B1, virtual B2 {
@@ -82,7 +154,7 @@ void EmitNonVirtualMemberPointers() {
void (Virtual ::*v_f_memptr)() = &Virtual::foo;
void (Unspecified::*u_f_memptr)() = &Unspecified::foo;
void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;
-// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 {
+// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() {{.*}} {
// CHECK: alloca i8*, align 4
// CHECK: alloca { i8*, i32 }, align 4
// CHECK: alloca { i8*, i32, i32 }, align 4
@@ -95,7 +167,7 @@ void EmitNonVirtualMemberPointers() {
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 },
// CHECK: { i8*, i32, i32 }* %{{.*}}, align 4
// CHECK: store { i8*, i32, i32, i32 }
-// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 },
+// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 },
// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4
// CHECK: store { i8*, i32, i32, i32 }
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*),
@@ -112,7 +184,7 @@ void podMemPtrs() {
if (memptr)
memptr = 0;
// Check that member pointers use the right offsets and that null is -1.
-// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() #0 {
+// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() {{.*}} {
// CHECK: %[[memptr:.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 0, i32* %[[memptr]], align 4
// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4
@@ -132,7 +204,7 @@ void polymorphicMemPtrs() {
memptr = 0;
// Member pointers for polymorphic classes include the vtable slot in their
// offset and use 0 to represent null.
-// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() #0 {
+// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() {{.*}} {
// CHECK: %[[memptr:.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4
// CHECK-NEXT: store i32 8, i32* %[[memptr]], align 4
@@ -233,7 +305,7 @@ int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {
(o->*memptr)();
// Just look for an indirect thiscall.
-// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} {{.*}} {
// CHECK: call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}})
// CHECK: ret void
// CHECK: }
@@ -241,7 +313,7 @@ void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {
void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) {
(o->*memptr)();
-// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} {
// CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0
// CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1
// CHECK: %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]]
@@ -255,7 +327,7 @@ void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) {
void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) {
(o->*memptr)();
// This shares a lot with virtual data member pointers.
-// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} {
// CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0
// CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1
// CHECK: %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2
@@ -361,3 +433,107 @@ bool unspecDataMemptrEq(int Unspecified::*l, int Unspecified::*r) {
// CHECK: ret i1
// CHECK: }
}
+
+void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() {
+ return mp;
+// CHECK: define i64 @"\01?convertB2FuncToMultiple@@YAP8Multiple@@AEXXZP8B2@@AEXXZ@Z"{{.*}} {
+// CHECK: store
+// CHECK: %[[mp:.*]] = load i8** %{{.*}}, align 4
+// CHECK: icmp ne i8* %[[mp]], null
+// CHECK: br i1 %{{.*}} label %{{.*}}, label %{{.*}}
+//
+// memptr.convert: ; preds = %entry
+// CHECK: insertvalue { i8*, i32 } undef, i8* %[[mp]], 0
+// CHECK: insertvalue { i8*, i32 } %{{.*}}, i32 4, 1
+// CHECK: br label
+//
+// memptr.converted: ; preds = %memptr.convert, %entry
+// CHECK: phi { i8*, i32 } [ zeroinitializer, %{{.*}} ], [ {{.*}} ]
+// CHECK: }
+}
+
+void (B2::*convertMultipleFuncToB2(void (Multiple::*mp)()))() {
+// FIXME: cl emits warning C4407 on this code because of the representation
+// change. We might want to do the same.
+ return static_cast<void (B2::*)()>(mp);
+// FIXME: We should return i8* instead of i32 here. The ptrtoint cast prevents
+// LLVM from optimizing away the branch. This is likely a bug in
+// lib/CodeGen/TargetInfo.cpp with how we classify memptr types for returns.
+//
+// CHECK: define i32 @"\01?convertMultipleFuncToB2@@YAP8B2@@AEXXZP8Multiple@@AEXXZ@Z"{{.*}} {
+// CHECK: store
+// CHECK: %[[src:.*]] = load { i8*, i32 }* %{{.*}}, align 4
+// CHECK: extractvalue { i8*, i32 } %[[src]], 0
+// CHECK: icmp ne i8* %{{.*}}, null
+// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+//
+// memptr.convert: ; preds = %entry
+// CHECK: %[[fp:.*]] = extractvalue { i8*, i32 } %[[src]], 0
+// CHECK: br label
+//
+// memptr.converted: ; preds = %memptr.convert, %entry
+// CHECK: phi i8* [ null, %{{.*}} ], [ %[[fp]], %{{.*}} ]
+// CHECK: }
+}
+
+namespace Test1 {
+
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+
+void (D::*convertCToD(void (C::*mp)()))() {
+ return mp;
+// CHECK: define void @"\01?convertCToD@Test1@@YAP8D@1@AEXXZP8C@1@AEXXZ@Z"{{.*}} {
+// CHECK: store
+// CHECK: load { i8*, i32, i32 }* %{{.*}}, align 4
+// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK: icmp ne i8* %{{.*}}, null
+// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+//
+// memptr.convert: ; preds = %entry
+// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 1
+// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 2
+// CHECK: %[[adj:.*]] = add nsw i32 %{{.*}}, 4
+// CHECK: insertvalue { i8*, i32, i32 } undef, i8* {{.*}}, 0
+// CHECK: insertvalue { i8*, i32, i32 } {{.*}}, i32 %[[adj]], 1
+// CHECK: insertvalue { i8*, i32, i32 } {{.*}}, i32 {{.*}}, 2
+// CHECK: br label
+//
+// memptr.converted: ; preds = %memptr.convert, %entry
+// CHECK: phi { i8*, i32, i32 } [ { i8* null, i32 0, i32 -1 }, {{.*}} ], [ {{.*}} ]
+// CHECK: }
+}
+
+}
+
+namespace Test2 {
+// Test that we dynamically convert between different null reps.
+
+struct A { int a; };
+struct B : A { int b; };
+struct C : A {
+ int c;
+ virtual void hasVfPtr();
+};
+
+int A::*reinterpret(int B::*mp) {
+ return reinterpret_cast<int A::*>(mp);
+// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQB@1@H@Z"{{.*}} {
+// CHECK-NOT: select
+// CHECK: ret i32
+// CHECK: }
+}
+
+int A::*reinterpret(int C::*mp) {
+ return reinterpret_cast<int A::*>(mp);
+// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQC@1@H@Z"{{.*}} {
+// CHECK: %[[mp:.*]] = load i32*
+// CHECK: %[[cmp:.*]] = icmp ne i32 %[[mp]], 0
+// CHECK: select i1 %[[cmp]], i32 %[[mp]], i32 -1
+// CHECK: }
+}
+
+}
diff --git a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
new file mode 100644
index 000000000000..802f0ca24175
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
@@ -0,0 +1,201 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct Left {
+ virtual void left();
+};
+
+struct Right {
+ virtual void right();
+};
+
+struct ChildNoOverride : Left, Right {
+};
+
+struct ChildOverride : Left, Right {
+ virtual void left();
+ virtual void right();
+};
+
+extern "C" void foo(void *);
+
+void call_left_no_override(ChildNoOverride *child) {
+// CHECK: define void @"\01?call_left_no_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride
+
+ child->left();
+// Only need to cast 'this' to Left*.
+// CHECK: %[[LEFT:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to %struct.Left*
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.Left* %[[LEFT]] to void (%struct.Left*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.Left*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Left*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Left*)** %[[VFUN]]
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Left* %[[LEFT]])
+// CHECK: ret
+}
+
+void ChildOverride::left() {
+// CHECK: define x86_thiscallcc void @"\01?left@ChildOverride@@UAEXXZ"(%struct.ChildOverride* %[[THIS:.*]])
+//
+// No need to adjust 'this' as the ChildOverride's layout begins with Left.
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4
+// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_i8]])
+// CHECK: ret
+}
+
+void call_left_override(ChildOverride *child) {
+// CHECK: define void @"\01?call_left_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride
+
+ child->left();
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to void (%struct.ChildOverride*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.ChildOverride*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.ChildOverride*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.ChildOverride*)** %[[VFUN]]
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.ChildOverride* %[[CHILD]])
+// CHECK: ret
+}
+
+void call_right_no_override(ChildNoOverride *child) {
+// CHECK: define void @"\01?call_right_no_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride
+
+ child->right();
+// When calling a right base's virtual method, one needs to adjust 'this' at
+// the caller site.
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to i8*
+// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4
+// CHECK: %[[RIGHT:.*]] = bitcast i8* %[[RIGHT_i8]] to %struct.Right*
+//
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.Right* %[[RIGHT]] to void (%struct.Right*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.Right*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Right*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Right*)** %[[VFUN]]
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Right* %[[RIGHT]])
+// CHECK: ret
+}
+
+void ChildOverride::right() {
+// CHECK: define x86_thiscallcc void @"\01?right@ChildOverride@@UAEXXZ"(i8*
+//
+// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we
+// need to adjust 'this' before use.
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -4
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.ChildOverride*
+// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_PARAM]])
+// CHECK: ret
+}
+
+void call_right_override(ChildOverride *child) {
+// CHECK: define void @"\01?call_right_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride
+
+ child->right();
+// When calling a right child's virtual method, one needs to adjust 'this' at
+// the caller site.
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8*
+//
+// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to void (i8*)***
+// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]]
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8*
+// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[RIGHT]])
+// CHECK: ret
+}
+
+struct GrandchildOverride : ChildOverride {
+ virtual void right();
+};
+
+void GrandchildOverride::right() {
+// CHECK: define x86_thiscallcc void @"\01?right@GrandchildOverride@@UAEXXZ"(i8*
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.GrandchildOverride*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -4
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.GrandchildOverride*
+// CHECK: store %struct.GrandchildOverride* %[[THIS]], %struct.GrandchildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_PARAM]])
+// CHECK: ret
+}
+
+void call_grandchild_right(GrandchildOverride *obj) {
+ // Just make sure we don't crash.
+ obj->right();
+}
+
+void emit_ctors() {
+ Left l;
+ // CHECK: define {{.*}} @"\01??0Left@@QAE@XZ"
+ // CHECK-NOT: getelementptr
+ // CHECK: store [1 x i8*]* @"\01??_7Left@@6B@"
+ // CHECK: ret
+
+ Right r;
+ // CHECK: define {{.*}} @"\01??0Right@@QAE@XZ"
+ // CHECK-NOT: getelementptr
+ // CHECK: store [1 x i8*]* @"\01??_7Right@@6B@"
+ // CHECK: ret
+
+ ChildOverride co;
+ // CHECK: define {{.*}} @"\01??0ChildOverride@@QAE@XZ"
+ // CHECK: %[[THIS:.*]] = load %struct.ChildOverride**
+ // CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to [1 x i8*]**
+ // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
+ // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]**
+ // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: ret
+
+ GrandchildOverride gc;
+ // CHECK: define {{.*}} @"\01??0GrandchildOverride@@QAE@XZ"
+ // CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride**
+ // CHECK: %[[VFPTR:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to [1 x i8*]**
+ // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8*
+ // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]**
+ // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: ret
+}
+
+struct LeftWithNonVirtualDtor {
+ virtual void left();
+ ~LeftWithNonVirtualDtor();
+};
+
+struct AsymmetricChild : LeftWithNonVirtualDtor, Right {
+ virtual ~AsymmetricChild();
+};
+
+void call_asymmetric_child_complete_dtor() {
+ // CHECK-LABEL: define void @"\01?call_asymmetric_child_complete_dtor@@YAXXZ"
+ AsymmetricChild obj;
+ // CHECK: call x86_thiscallcc %struct.AsymmetricChild* @"\01??0AsymmetricChild@@QAE@XZ"(%struct.AsymmetricChild* %[[OBJ:.*]])
+ // CHECK-NOT: getelementptr
+ // CHECK: call x86_thiscallcc void @"\01??1AsymmetricChild@@UAE@XZ"(%struct.AsymmetricChild* %[[OBJ]])
+ // CHECK: ret
+}
diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
index 060c1728586c..d0750e6ebe91 100644
--- a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
+++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux | FileCheck -check-prefix LINUX %s
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN32 %s
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN64 %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN32 %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN64 %s
struct Empty {};
@@ -22,6 +22,12 @@ struct SmallWithCtor {
int x;
};
+struct SmallWithDtor {
+ SmallWithDtor();
+ ~SmallWithDtor();
+ int x;
+};
+
struct SmallWithVftable {
int x;
virtual void foo();
@@ -43,70 +49,108 @@ struct Big {
// Returning structs that fit into a register.
Small small_return() { return Small(); }
-// LINUX: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result)
// WIN32: define i32 @"\01?small_return@@YA?AUSmall@@XZ"()
// WIN64: define i32 @"\01?small_return@@YA?AUSmall@@XZ"()
Medium medium_return() { return Medium(); }
-// LINUX: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result)
// WIN32: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"()
// WIN64: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"()
// Returning structs that fit into a register but are not POD.
SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); }
-// LINUX: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
// WIN32: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
// WIN64: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); }
-// LINUX: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result)
// WIN32: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result)
// WIN64: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result)
SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); }
-// LINUX: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result)
// WIN32: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result)
// WIN64: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result)
MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); }
-// LINUX: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result)
// WIN32: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result)
// WIN64: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result)
// Returning a large struct that doesn't fit into a register.
Big big_return() { return Big(); }
-// LINUX: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result)
+// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result)
// WIN32: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result)
// WIN64: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result)
void small_arg(Small s) {}
-// LINUX: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s)
+// LINUX-LABEL: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s)
// WIN32: define void @"\01?small_arg@@YAXUSmall@@@Z"(%struct.Small* byval align 4 %s)
// WIN64: define void @"\01?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce)
void medium_arg(Medium s) {}
-// LINUX: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s)
+// LINUX-LABEL: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s)
// WIN32: define void @"\01?medium_arg@@YAXUMedium@@@Z"(%struct.Medium* byval align 4 %s)
// WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce)
void small_arg_with_ctor(SmallWithCtor s) {}
-// LINUX: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s)
+// LINUX-LABEL: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s)
// WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(%struct.SmallWithCtor* byval align 4 %s)
// WIN64: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce)
+// Test that dtors are invoked in the callee.
+void small_arg_with_dtor(SmallWithDtor s) {}
+// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %s)
+// WIN32: }
+// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} {
+// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s)
+// WIN64: }
+
+// Test that references aren't destroyed in the callee.
+void ref_small_arg_with_dtor(const SmallWithDtor &s) { }
+// WIN32: define void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} {
+// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
+// Test that temporaries passed by reference are destroyed in the caller.
+void temporary_ref_with_dtor() {
+ ref_small_arg_with_dtor(SmallWithDtor());
+}
+// WIN32: define void @"\01?temporary_ref_with_dtor@@YAXXZ"() {{.*}} {
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"
+// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
+void takes_two_by_val_with_dtor(SmallWithDtor a, SmallWithDtor b);
+void eh_cleanup_arg_with_dtor() {
+ takes_two_by_val_with_dtor(SmallWithDtor(), SmallWithDtor());
+}
+// When exceptions are off, we don't have any cleanups. See
+// microsoft-abi-exceptions.cpp for these cleanups.
+// WIN32: define void @"\01?eh_cleanup_arg_with_dtor@@YAXXZ"() {{.*}} {
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call void @"\01?takes_two_by_val_with_dtor@@YAXUSmallWithDtor@@0@Z"
+// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
void small_arg_with_vftable(SmallWithVftable s) {}
-// LINUX: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
+// LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s)
// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s)
void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {}
-// LINUX: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s)
+// LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s)
// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s)
// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s)
void big_arg(Big s) {}
-// LINUX: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s)
+// LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s)
// WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s)
// WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s)
@@ -167,3 +211,19 @@ void use_class() {
c.thiscall_method_arg(SmallWithCtor());
c.thiscall_method_arg(Big());
}
+
+struct X {
+ X();
+ ~X();
+};
+void g(X) {
+}
+// WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* %0)
+// WIN32: }
+void f() {
+ g(X());
+}
+// WIN32: define void @"\01?f@@YAXXZ"() {{.*}} {
+// WIN32-NOT: call {{.*}} @"\01??1X@@QAE@XZ"
+// WIN32: }
diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index 35e343bc4d3c..c0b972212357 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -1,19 +1,85 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }]
+// CHECK: [{ i32, void ()* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@YAXXZ" },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
struct S {
- S() {}
- ~S() {}
-} s;
+ S();
+ ~S();
+};
-// CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]]
+S s;
+
+// CHECK: define internal void @"\01??__Es@@YAXXZ"() [[NUW:#[0-9]+]]
// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
-// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A")
+// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ")
// CHECK: ret void
-// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] {
+// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] {
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
// CHECK: ret void
+void StaticLocal() {
+ static S TheS;
+}
+// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"()
+// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
+// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
+// CHECK: ret
+
+void MultipleStatics() {
+ static S S1;
+ static S S2;
+ static S S3;
+ static S S4;
+ static S S5;
+ static S S6;
+ static S S7;
+ static S S8;
+ static S S9;
+ static S S10;
+ static S S11;
+ static S S12;
+ static S S13;
+ static S S14;
+ static S S15;
+ static S S16;
+ static S S17;
+ static S S18;
+ static S S19;
+ static S S20;
+ static S S21;
+ static S S22;
+ static S S23;
+ static S S24;
+ static S S25;
+ static S S26;
+ static S S27;
+ static S S28;
+ static S S29;
+ static S S30;
+ static S S31;
+ static S S32;
+ static S S33;
+ static S S34;
+ static S S35;
+}
+// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"()
+// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA"
+// CHECK: and i32 {{.*}}, 1
+// CHECK: and i32 {{.*}}, 2
+// CHECK: and i32 {{.*}}, 4
+// CHECK: and i32 {{.*}}, 8
+// CHECK: and i32 {{.*}}, 16
+// ...
+// CHECK: and i32 {{.*}}, -2147483648
+// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1"
+// CHECK: and i32 {{.*}}, 1
+// CHECK: and i32 {{.*}}, 2
+// CHECK: and i32 {{.*}}, 4
+// CHECK: ret
+
// Force WeakODRLinkage by using templates
class A {
public:
@@ -29,26 +95,60 @@ class B {
template<typename T> A B<T>::foo;
+inline S &UnreachableStatic() {
+ if (0) {
+ static S s; // bit 1
+ return s;
+ }
+ static S s; // bit 2
+ return s;
+}
+
+// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"()
+// CHECK: and i32 {{.*}}, 2
+// CHECK: or i32 {{.*}}, 2
+// CHECK: ret
+
+inline S &getS() {
+ static S TheS;
+ return TheS;
+}
+
+// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?getS@@YAAAUS@@XZ"
+// CHECK: load i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51"
+// CHECK: and i32 {{.*}}, 1
+// CHECK: icmp ne i32 {{.*}}, 0
+// CHECK: br i1
+// init:
+// CHECK: or i32 {{.*}}, 1
+// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51"
+// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A")
+// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ")
+// CHECK: br label
+// init.end:
+// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A"
+
void force_usage() {
+ UnreachableStatic();
+ getS();
(void)B<int>::foo; // (void) - force usage
}
-// CHECK: define internal void [[INIT_foo:@.*global_var.*]] [[NUW]]
+// CHECK: define internal void @"\01??__Efoo@?$B@H@@YAXXZ"() [[NUW]]
// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
-// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
+// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@YAXXZ")
// CHECK: ret void
// CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ"
-// CHECK: define internal void [[FOO_DTOR]]
+// CHECK: define internal void @"\01??__Ffoo@?$B@H@@YAXXZ"
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo
// CHECK: ret void
// CHECK: define internal void @_GLOBAL__I_a() [[NUW]] {
-// CHECK: call void [[INIT_s]]
-// CHECK: call void [[INIT_foo]]
+// CHECK: call void @"\01??__Es@@YAXXZ"()
// CHECK: ret void
// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/microsoft-abi-structors-alias.cpp b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp
new file mode 100644
index 000000000000..d54520fab72c
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti -mconstructor-aliases | FileCheck %s
+
+namespace test1 {
+template <typename T> class A {
+ ~A() {}
+};
+template class A<char>;
+// CHECK: define weak_odr x86_thiscallcc void @"\01??1?$A@D@test1@@AAE@XZ"
+}
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 864540d425ef..c2f1395f47df 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -1,27 +1,31 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1
+// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t
// RUN: FileCheck %s < %t
-// Using a different check prefix as the inline destructors might be placed
-// anywhere in the output.
-// RUN: FileCheck --check-prefix=DTORS %s < %t
+// vftables are emitted very late, so do another pass to try to keep the checks
+// in source order.
+// RUN: FileCheck --check-prefix DTORS %s < %t
+//
+// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s
namespace basic {
class A {
public:
A() { }
- ~A() { }
+ ~A();
};
void no_constructor_destructor_infinite_recursion() {
A a;
-// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this)
+// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this)
// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
// CHECK-NEXT: ret %"class.basic::A"* [[T1]]
// CHECK-NEXT: }
+}
+A::~A() {
// Make sure that the destructor doesn't call itself:
// CHECK: define {{.*}} @"\01??1A@basic@@QAE@XZ"
// CHECK-NOT: call void @"\01??1A@basic@@QAE@XZ"
@@ -34,33 +38,29 @@ struct B {
// Tests that we can define constructors outside the class (PR12784).
B::B() {
- // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this)
+ // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this)
// CHECK: ret
}
struct C {
virtual ~C() {
-// Complete destructor first:
-// DTORS: define {{.*}} x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %this)
-
-// Then, the scalar deleting destructor (used in the vtable):
-// FIXME: add a test that verifies that the out-of-line scalar deleting
-// destructor is linkonce_odr too.
-// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i1 zeroext %should_call_delete)
-// DTORS: %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8
-// DTORS-NEXT: store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1
-// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i8* %[[SHOULD_DELETE_VAR]]
+// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i32 %should_call_delete)
+// DTORS: store i32 %should_call_delete, i32* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4
+// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32* %[[SHOULD_DELETE_VAR]]
// DTORS: call x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]])
-// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i8 %[[SHOULD_DELETE_VALUE]], 0
+// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[SHOULD_DELETE_VALUE]], 0
// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]
//
// DTORS: [[CALL_DELETE_LABEL]]
// DTORS-NEXT: %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %"struct.basic::C"* %[[THIS]] to i8*
-// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) [[NUW:#[0-9]+]]
+// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]])
// DTORS-NEXT: br label %[[CONTINUE_LABEL]]
//
// DTORS: [[CONTINUE_LABEL]]
// DTORS-NEXT: ret void
+
+// Check that we do the mangling correctly on x64.
+// DTORS-X64: @"\01??_GC@basic@@UEAAPEAXI@Z"
}
virtual void foo();
};
@@ -71,19 +71,19 @@ void C::foo() {}
void check_vftable_offset() {
C c;
// The vftable pointer should point at the beginning of the vftable.
-// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i8***
-// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7C@basic@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
+// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to [2 x i8*]**
+// CHECK: store [2 x i8*]* @"\01??_7C@basic@@6B@", [2 x i8*]** [[THIS_PTR]]
}
void call_complete_dtor(C *obj_ptr) {
// CHECK: define void @"\01?call_complete_dtor@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr)
obj_ptr->~C();
// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext false)
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
// CHECK-NEXT: ret void
}
@@ -94,11 +94,11 @@ void call_deleting_dtor(C *obj_ptr) {
// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
// CHECK: [[DELETE_NOTNULL]]
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext true)
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1)
// CHECK: ret void
}
@@ -119,8 +119,6 @@ struct D {
void use_D() { D c; }
-// DTORS: attributes [[NUW]] = { nounwind{{.*}} }
-
} // end namespace basic
@@ -136,7 +134,7 @@ struct B : A {
};
B::B() {
- // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this)
+ // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this)
// CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK: ret
}
@@ -146,7 +144,7 @@ struct C : virtual A {
};
C::C() {
- // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)
+ // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived)
// TODO: make sure this works in the Release build too;
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
@@ -154,12 +152,19 @@ C::C() {
// CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
//
// CHECK: [[INIT_VBASES]]
- // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::C"* %{{.*}} to i8*
+ // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+ // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
+ // CHECK-NEXT: store [2 x i32]* @"\01??_8C@constructors@@7B@", [2 x i32]** %[[vbptr]]
+ // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to i8*
+ // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
+ // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
// CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK-NEXT: br label %[[SKIP_VBASES]]
//
// CHECK: [[SKIP_VBASES]]
- // CHECK: @"\01??_7C@constructors@@6B@"
+ // Class C does not define or override methods, so shouldn't change the vfptr.
+ // CHECK-NOT: @"\01??_7C@constructors@@6B@"
// CHECK: ret
}
@@ -175,14 +180,20 @@ struct D : C {
};
D::D() {
- // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr
+ // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
// CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
//
// CHECK: [[INIT_VBASES]]
- // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::D"* %{{.*}} to i8*
+ // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+ // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
+ // CHECK-NEXT: store [2 x i32]* @"\01??_8D@constructors@@7B@", [2 x i32]** %[[vbptr]]
+ // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to i8*
+ // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
+ // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
// CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK-NEXT: br label %[[SKIP_VBASES]]
//
@@ -196,14 +207,23 @@ struct E : virtual C {
};
E::E() {
- // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr
+ // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
// CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
//
// CHECK: [[INIT_VBASES]]
- // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::E"* %{{.*}} to i8*
+ // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+ // CHECK-NEXT: %[[vbptr_E:.*]] = bitcast i8* %[[offs]] to [3 x i32]**
+ // CHECK-NEXT: store [3 x i32]* @"\01??_8E@constructors@@7B01@@", [3 x i32]** %[[vbptr_E]]
+ // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 4
+ // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to [2 x i32]**
+ // CHECK-NEXT: store [2 x i32]* @"\01??_8E@constructors@@7BC@1@@", [2 x i32]** %[[vbptr_C]]
+ // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to i8*
+ // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
+ // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
// CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
// CHECK-NEXT: br label %[[SKIP_VBASES]]
@@ -212,4 +232,70 @@ E::E() {
// CHECK: ret
}
+// PR16735 - even abstract classes should have a constructor emitted.
+struct F {
+ F();
+ virtual void f() = 0;
+};
+
+F::F() {}
+// CHECK: define x86_thiscallcc %"struct.constructors::F"* @"\01??0F@constructors@@QAE@XZ"
+
} // end namespace constructors
+
+namespace dtors {
+
+struct A {
+ ~A();
+};
+
+void call_nv_complete(A *a) {
+ a->~A();
+// CHECK: define void @"\01?call_nv_complete@dtors@@YAXPAUA@1@@Z"
+// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ"
+// CHECK: ret
+}
+
+// CHECK: declare x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ"
+
+// Now try some virtual bases, where we need the complete dtor.
+
+struct B : virtual A { ~B(); };
+struct C : virtual A { ~C(); };
+struct D : B, C { ~D(); };
+
+void call_vbase_complete(D *d) {
+ d->~D();
+// CHECK: define void @"\01?call_vbase_complete@dtors@@YAXPAUD@1@@Z"
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: ret
+}
+
+// The complete dtor should call the base dtors for D and the vbase A (once).
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"
+// CHECK-NOT: call
+// CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ"
+// CHECK-NOT: call
+// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ"
+// CHECK-NOT: call
+// CHECK: ret
+
+void destroy_d_complete() {
+ D d;
+// CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ"
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: ret
+}
+
+// FIXME: Clang manually inlines the deletion, so we don't get a call to the
+// deleting dtor (_G). The only way to call deleting dtors currently is through
+// a vftable.
+void call_nv_deleting_dtor(D *d) {
+ delete d;
+// CHECK: define void @"\01?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z"
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: call void @"\01??3@YAXPAX@Z"
+// CHECK: ret
+}
+
+}
diff --git a/test/CodeGenCXX/microsoft-abi-thunks.cpp b/test/CodeGenCXX/microsoft-abi-thunks.cpp
new file mode 100644
index 000000000000..f1bc385fdff2
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-thunks.cpp
@@ -0,0 +1,154 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1
+// RUN: FileCheck --check-prefix=MANGLING %s < %t
+// RUN: FileCheck --check-prefix=XMANGLING %s < %t
+// RUN: FileCheck --check-prefix=CODEGEN %s < %t
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 2>&1 | FileCheck --check-prefix=MANGLING-X64 %s
+
+void foo(void *);
+
+struct A {
+ virtual ~A();
+ virtual void public_f();
+ // Make sure we don't emit unneeded thunks:
+ // XMANGLING-NOT: @"\01?public_f@A@@QAEXXZ"
+ protected:
+ virtual void protected_f();
+ private:
+ virtual void private_f();
+};
+
+struct B {
+ virtual ~B();
+ virtual void public_f();
+ protected:
+ virtual void protected_f();
+ private:
+ virtual void private_f();
+};
+
+
+struct C : A, B {
+ C();
+
+ virtual ~C();
+ // MANGLING-DAG: @"\01??1C@@UAE@XZ"
+ // MANGLING-DAG: @"\01??_GC@@UAEPAXI@Z"
+ // MANGLING-DAG: @"\01??_EC@@W3AEPAXI@Z"
+ // MANGLING-X64-DAG: @"\01??1C@@UEAA@XZ"
+ // MANGLING-X64-DAG: @"\01??_GC@@UEAAPEAXI@Z"
+ // MANGLING-X64-DAG: @"\01??_EC@@W7EAAPEAXI@Z"
+
+ // Overrides public_f() of two subobjects with distinct vfptrs, thus needs a thunk.
+ virtual void public_f();
+ // MANGLING-DAG: @"\01?public_f@C@@UAEXXZ"
+ // MANGLING-DAG: @"\01?public_f@C@@W3AEXXZ"
+ // MANGLING-X64-DAG: @"\01?public_f@C@@UEAAXXZ"
+ // MANGLING-X64-DAG: @"\01?public_f@C@@W7EAAXXZ"
+ protected:
+ virtual void protected_f();
+ // MANGLING-DAG: @"\01?protected_f@C@@MAEXXZ"
+ // MANGLING-DAG: @"\01?protected_f@C@@O3AEXXZ"
+ // MANGLING-X64-DAG: @"\01?protected_f@C@@MEAAXXZ"
+ // MANGLING-X64-DAG: @"\01?protected_f@C@@O7EAAXXZ"
+
+ private:
+ virtual void private_f();
+ // MANGLING-DAG: @"\01?private_f@C@@EAEXXZ"
+ // MANGLING-DAG: @"\01?private_f@C@@G3AEXXZ"
+ // MANGLING-X64-DAG: @"\01?private_f@C@@EEAAXXZ"
+ // MANGLING-X64-DAG: @"\01?private_f@C@@G7EAAXXZ"
+};
+
+C::C() {} // Emits vftable and forces thunk generation.
+
+// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
+// CODEGEN: getelementptr i8* {{.*}}, i32 -4
+// FIXME: should actually call _EC, not _GC.
+// CODEGEN: call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z"
+// CODEGEN: ret
+
+// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
+// CODEGEN: getelementptr i8* {{.*}}, i32 -4
+// CODEGEN: call x86_thiscallcc void @"\01?public_f@C@@UAEXXZ"(%struct.C*
+// CODEGEN: ret
+
+void zoo(C* obj) {
+ delete obj;
+}
+
+struct D {
+ virtual B* goo();
+};
+
+struct E : D {
+ E();
+ virtual C* goo();
+ // MANGLING-DAG: @"\01?goo@E@@UAEPAUC@@XZ"
+ // MANGLING-DAG: @"\01?goo@E@@QAEPAUB@@XZ"
+ // MANGLING-X64-DAG: @"\01?goo@E@@UEAAPEAUC@@XZ"
+ // MANGLING-X64-DAG: @"\01?goo@E@@QEAAPEAUB@@XZ"
+};
+
+E::E() {} // Emits vftable and forces thunk generation.
+
+// CODEGEN-LABEL: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
+// CODEGEN: call x86_thiscallcc %struct.C* @"\01?goo@E@@UAEPAUC@@XZ"
+// CODEGEN: getelementptr inbounds i8* {{.*}}, i32 4
+// CODEGEN: ret
+
+struct F : virtual A, virtual B {
+ virtual void own_method();
+ virtual ~F();
+};
+
+F f; // Just make sure we don't crash, e.g. mangling the complete dtor.
+
+struct G : C { };
+
+struct H : E {
+ virtual G* goo();
+ // MANGLING-DAG: @"\01?goo@H@@UAEPAUG@@XZ"
+ // MANGLING-DAG: @"\01?goo@H@@QAEPAUB@@XZ"
+ // MANGLING-DAG: @"\01?goo@H@@QAEPAUC@@XZ"
+ // MANGLING-X64-DAG: @"\01?goo@H@@UEAAPEAUG@@XZ"
+ // MANGLING-X64-DAG: @"\01?goo@H@@QEAAPEAUB@@XZ"
+ // MANGLING-X64-DAG: @"\01?goo@H@@QEAAPEAUC@@XZ"
+};
+
+H h;
+
+struct I : D {
+ I();
+ virtual F* goo();
+};
+
+I::I() {} // Emits vftable and forces thunk generation.
+
+// CODEGEN-LABEL: define weak x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ"
+// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ"
+// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
+// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4
+// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
+// CODEGEN: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
+// CODEGEN: %[[VBASE_OFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 8
+// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = bitcast i8* %[[VBASE_OFFSET_PTR_i8]] to i32*
+// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32* %[[VBASE_OFFSET_PTR]]
+// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
+// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F*
+// CODEGEN: phi %struct.F* {{.*}} %[[RES]]
+// CODEGEN: ret %struct.{{[BF]}}*
+
+namespace CrashOnThunksForAttributedType {
+// We used to crash on this because the type of foo is an AttributedType, not
+// FunctionType, and we had to look through the sugar.
+struct A {
+ virtual void __stdcall foo();
+};
+struct B {
+ virtual void __stdcall foo();
+};
+struct C : A, B {
+ virtual void __stdcall foo();
+};
+C c;
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vbtables.cpp b/test/CodeGenCXX/microsoft-abi-vbtables.cpp
new file mode 100644
index 000000000000..6de556b1d814
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vbtables.cpp
@@ -0,0 +1,479 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s
+
+// See microsoft-abi-structors.cpp for constructor codegen tests.
+
+namespace Test1 {
+// Classic diamond, fully virtual.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B, virtual C { int d; };
+D d; // Force vbtable emission.
+
+// Layout should be:
+// D: vbptr D
+// int d
+// A: int a
+// B: vbptr B
+// int b
+// C: vbptr C
+// int c
+
+// CHECK-DAG: @"\01??_8D@Test1@@7B01@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 8, i32 12, i32 20]
+// CHECK-DAG: @"\01??_8D@Test1@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// CHECK-DAG: @"\01??_8D@Test1@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -12]
+// CHECK-DAG: @"\01??_8C@Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// CHECK-DAG: @"\01??_8B@Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test2 {
+// Classic diamond, only A is virtual.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+D d; // Force vbtable emission.
+
+// Layout should be:
+// B: vbptr B
+// int b
+// C: vbptr C
+// int c
+// D: int d
+// A: int a
+
+// CHECK-DAG: @"\01??_8D@Test2@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// CHECK-DAG: @"\01??_8D@Test2@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8C@Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// CHECK-DAG: @"\01??_8B@Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test3 {
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A, virtual B { int c; };
+C c;
+
+// CHECK-DAG: @"\01??_8C@Test3@@7B@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12]
+}
+
+namespace Test4 {
+// Test reusing a vbptr from a non-virtual base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B, virtual A { int c; };
+C c; // Force vbtable emission.
+
+// CHECK-DAG: @"\01??_8C@Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8B@Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test5 {
+// Test multiple base subobjects of the same type when that type has a virtual
+// base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B, C { int d; };
+D d; // Force vbtable emission.
+
+// CHECK-DAG: @"\01??_8D@Test5@@7BB@1@@"
+// CHECK-DAG: @"\01??_8D@Test5@@7BC@1@@"
+// CHECK-DAG: @"\01??_8C@Test5@@7B@"
+// CHECK-DAG: @"\01??_8B@Test5@@7B@"
+}
+
+namespace Test6 {
+// Test that we skip unneeded base path component names.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B, C { int d; };
+struct E : D { int e; };
+struct F : E, B, C { int f; };
+struct G : F, virtual E { int g; };
+G g;
+
+// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@E@1@F@1@@" =
+// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@E@1@F@1@@" =
+// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@F@1@@" =
+// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@F@1@@" =
+// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@E@1@@" =
+// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@E@1@@" =
+// CHECK-DAG: @"\01??_8F@Test6@@7BB@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 52]
+// CHECK-DAG: @"\01??_8F@Test6@@7BC@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 44]
+// CHECK-DAG: @"\01??_8F@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// CHECK-DAG: @"\01??_8F@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 16]
+// CHECK-DAG: @"\01??_8C@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8B@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// CHECK-DAG: @"\01??_8E@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 28]
+// CHECK-DAG: @"\01??_8E@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// CHECK-DAG: @"\01??_8D@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// CHECK-DAG: @"\01??_8D@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 16]
+}
+
+namespace Test7 {
+// Test a non-virtual base which reuses the vbptr of another base.
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D : virtual A { int d; };
+struct E : B, D, virtual A, virtual C { int e; };
+E o;
+
+// CHECK-DAG: @"\01??_8E@Test7@@7B@" = {{.*}} [3 x i32] [i32 0, i32 12, i32 16]
+// CHECK-DAG: @"\01??_8D@Test7@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test8 {
+// Test a virtual base which reuses the vbptr of another base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : virtual C { int d; };
+D o;
+
+// CHECK-DAG: @"\01??_8D@Test8@@7B01@@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12]
+// CHECK-DAG: @"\01??_8D@Test8@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// CHECK-DAG: @"\01??_8C@Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8B@Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test9 {
+// D has to add to B's vbtable because D has more morally virtual bases than B.
+// D then takes B's vbptr and the vbtable is named for D, not B.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct BB : B { int bb; }; // Indirection =/
+struct D : BB, C { int d; };
+struct E : virtual D { };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test9@@7B01@@" =
+// CHECK-DAG: @"\01??_8E@Test9@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test9@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test9@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test9@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test9@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test9@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test9@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test9@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8BB@Test9@@7B@" =
+// CHECK-DAG: @"\01??_8B@Test9@@7B@" =
+}
+
+namespace Test10 {
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test10@@7B@" =
+// CHECK-DAG: @"\01??_8C@Test10@@7B@" =
+
+}
+
+namespace Test11 {
+// Typical diamond with an extra single inheritance indirection for B and C.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : B { int d; };
+struct E : C { int e; };
+struct F : D, E { int f; };
+F f;
+
+// CHECK-DAG: @"\01??_8F@Test11@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 28]
+// CHECK-DAG: @"\01??_8F@Test11@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// CHECK-DAG: @"\01??_8E@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8C@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// CHECK-DAG: @"\01??_8D@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// CHECK-DAG: @"\01??_8B@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+
+}
+
+namespace Test12 {
+// Another vbptr inside a virtual base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : C, B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test12@@7BC@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test12@@7BB@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test12@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test12@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test12@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test12@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test12@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test12@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test12@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test12@@7B@" =
+// CHECK-DAG: @"\01??_8B@Test12@@7B@" =
+}
+
+namespace Test13 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test13@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test13@@7BC@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test13@@7BB@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test13@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test13@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test13@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test13@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test13@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test13@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test13@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test13@@7B@" =
+}
+
+namespace Test14 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C { int d; };
+struct E : D, virtual C, virtual B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test14@@7B@" =
+// CHECK-DAG: @"\01??_8E@Test14@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test14@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test14@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test14@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test14@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test14@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test14@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test14@@7B@" =
+}
+
+namespace Test15 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test15@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test15@@7BB@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test15@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test15@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test15@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test15@@7B01@@" =
+// CHECK-DAG: @"\01??_8D@Test15@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test15@@7B@" =
+}
+
+namespace Test16 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; }; // ambig
+struct D : virtual C { int d; };
+struct E : virtual D { int e; }; // ambig
+struct F : E, D, C, B { int f; }; // ambig
+F f;
+
+// CHECK-DAG: @"\01??_8F@Test16@@7BE@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BD@1@E@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BC@1@E@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BB@1@E@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8F@Test16@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8E@Test16@@7B01@@" =
+// CHECK-DAG: @"\01??_8E@Test16@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test16@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test16@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test16@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test16@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test16@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test16@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test16@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test16@@7B@" =
+}
+
+namespace Test17 {
+// This test case has an interesting alternating pattern of using "vbtable of B"
+// and "vbtable of C for C". This may be the key to the underlying algorithm.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; }; // ambig
+struct D : virtual C { int d; };
+struct E : virtual D { int e; }; // ambig
+struct F : virtual E { int f; };
+struct G : virtual F { int g; }; // ambig
+struct H : virtual G { int h; };
+struct I : virtual H { int i; }; // ambig
+struct J : virtual I { int j; };
+struct K : virtual J { int k; }; // ambig
+K k;
+
+// CHECK-DAG: @"\01??_8K@Test17@@7B01@@" =
+// CHECK-DAG: @"\01??_8J@Test17@@7B@" =
+// CHECK-DAG: @"\01??_8I@Test17@@7B01@@" =
+// CHECK-DAG: @"\01??_8H@Test17@@7B@" =
+// CHECK-DAG: @"\01??_8G@Test17@@7B01@@" =
+// CHECK-DAG: @"\01??_8F@Test17@@7B@" =
+// CHECK-DAG: @"\01??_8E@Test17@@7B01@@" =
+// CHECK-DAG: @"\01??_8D@Test17@@7B@" =
+// CHECK-DAG: @"\01??_8C@Test17@@7B01@@" =
+// CHECK-DAG: @"\01??_8B@Test17@@7B@" =
+}
+
+namespace Test18 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : C, B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test18@@7BC@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test18@@7BB@1@D@1@@" =
+// CHECK-DAG: @"\01??_8E@Test18@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test18@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test18@@7B@" =
+// CHECK-DAG: @"\01??_8C@Test18@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test18@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test18@@7BB@1@@" =
+}
+
+namespace Test19 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C, virtual B { int d; };
+struct E : virtual D, virtual C, virtual B { int e; };
+E e;
+
+// CHECK-DAG: @"\01??_8E@Test19@@7B01@@" =
+// CHECK-DAG: @"\01??_8E@Test19@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test19@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test19@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8D@Test19@@7B@" =
+// CHECK-DAG: @"\01??_8D@Test19@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8D@Test19@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8C@Test19@@7B01@@" =
+// CHECK-DAG: @"\01??_8C@Test19@@7BB@1@@" =
+// CHECK-DAG: @"\01??_8B@Test19@@7B@" =
+}
+
+namespace Test20 {
+// E has no direct vbases, but it adds to C's vbtable anyway.
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B { int d; };
+struct E : C, D { int e; };
+E f;
+
+// CHECK-DAG: @"\01??_8E@Test20@@7BC@1@@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 20, i32 24]
+// CHECK-DAG: @"\01??_8E@Test20@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// CHECK-DAG: @"\01??_8D@Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// CHECK-DAG: @"\01??_8C@Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test21 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B { int d; };
+struct E : C, D { int e; };
+struct F : virtual E { int f; };
+struct G : E { int g; };
+struct H : F, G { int h; };
+H h;
+
+// CHECK-DAG: @"\01??_8H@Test21@@7B@" =
+// CHECK-DAG: @"\01??_8H@Test21@@7BC@1@F@1@@" =
+// CHECK-DAG: @"\01??_8H@Test21@@7BD@1@F@1@@" =
+// CHECK-DAG: @"\01??_8H@Test21@@7BC@1@G@1@@" =
+// CHECK-DAG: @"\01??_8H@Test21@@7BD@1@G@1@@" =
+// CHECK-DAG: @"\01??_8G@Test21@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8G@Test21@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8F@Test21@@7B@" =
+// CHECK-DAG: @"\01??_8F@Test21@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8F@Test21@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8E@Test21@@7BC@1@@" =
+// CHECK-DAG: @"\01??_8E@Test21@@7BD@1@@" =
+// CHECK-DAG: @"\01??_8D@Test21@@7B@" =
+// CHECK-DAG: @"\01??_8B@Test21@@7B@" =
+// CHECK-DAG: @"\01??_8C@Test21@@7B@" =
+}
+
+namespace Test22 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C { int c; };
+struct D : B, virtual C { int d; };
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test22@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 12, i32 16]
+// CHECK-DAG: @"\01??_8B@Test22@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test23 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C { int c; };
+// Note the unusual order of bases. It forces C to be laid out before A.
+struct D : virtual C, B { int d; };
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test23@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12]
+// CHECK-DAG: @"\01??_8B@Test23@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test24 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C { int c; };
+struct D : virtual C, B {
+ virtual void f(); // Issues a vfptr, but the vbptr is still shared with B.
+ int d;
+};
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test24@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12]
+// CHECK-DAG: @"\01??_8B@Test24@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test25 {
+struct A { int a; };
+struct B : virtual A {
+ virtual void f(); // Issues a vfptr.
+ int b;
+};
+struct C { int c; };
+struct D : virtual C, B { int d; };
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test25@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 -4, i32 16, i32 12]
+// CHECK-DAG: @"\01??_8B@Test25@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 8]
+}
+
+namespace Test26 {
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D : virtual A { int d; };
+struct E : virtual B {
+ virtual void foo(); // Issues a vfptr.
+ int e;
+};
+struct F: virtual C, D, E { int f; };
+F f;
+// F reuses the D's vbptr, even though D is laid out after E.
+// CHECK-DAG: @"\01??_8F@Test26@@7BD@1@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 16, i32 12, i32 20]
+// CHECK-DAG: @"\01??_8F@Test26@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 28]
+}
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp
new file mode 100644
index 000000000000..8e23ade658c4
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s
+
+// For now, just make sure x86_64 doesn't crash.
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {};
+
+struct D : virtual C {
+ D();
+ ~D();
+ virtual void f();
+ void g();
+ int xxx;
+};
+
+D::D() {} // Forces vftable emission.
+
+// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPM@A@AEXXZ"
+// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}}
+// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8*
+// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4
+// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32*
+// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]]
+// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]]
+// CHECK: %[[ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]]
+// CHECK: call x86_thiscallcc void @"\01?f@D@@UAEXXZ"(i8* %[[ADJUSTED_i8]])
+// CHECK: ret void
+
+// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPI@3AEXXZ"
+// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}}
+// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8*
+// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -8
+// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32*
+// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]]
+// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]]
+// CHECK: %[[VTORDISP_ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]]
+// CHECK: %[[ADJUSTED_i8:.*]] = getelementptr i8* %[[VTORDISP_ADJUSTED_i8]], i32 -4
+// CHECK: call x86_thiscallcc void @"\01?f@D@@UAEXXZ"(i8* %[[ADJUSTED_i8]])
+// CHECK: ret void
+
+struct E : virtual A {
+ virtual void f();
+ ~E();
+};
+
+struct F {
+ virtual void z();
+};
+
+struct G : virtual F, virtual E {
+ int ggg;
+ G();
+ ~G();
+};
+
+G::G() {} // Forces vftable emission.
+
+// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@E@@$R4BA@M@PPPPPPPM@7AEXXZ"(i8*)
+// CHECK: %[[ECX:.*]] = load %struct.E** %{{.*}}
+// CHECK: %[[ECX_i8:.*]] = bitcast %struct.E* %[[ECX]] to i8*
+// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4
+// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32*
+// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]]
+// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]]
+// CHECK: %[[VTORDISP_ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]]
+// CHECK: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[VTORDISP_ADJUSTED_i8]], i32 -16
+// CHECK: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
+// CHECK: %[[VBOFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 12
+// CHECK: %[[VBOFFSET_PTR:.*]] = bitcast i8* %[[VBOFFSET_PTR_i8]] to i32*
+// CHECK: %[[VBASE_OFFSET:.*]] = load i32* %[[VBOFFSET_PTR]]
+// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
+// CHECK: %[[ARG_i8:.*]] = getelementptr i8* %[[VBASE]], i32 8
+// CHECK: call x86_thiscallcc void @"\01?f@E@@UAEXXZ"(i8* %[[ARG_i8]])
+// CHECK: ret void
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
new file mode 100644
index 000000000000..7c223ca0a772
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
@@ -0,0 +1,314 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck --check-prefix=CHECK2 %s < %t
+
+// For now, just make sure x86_64 doesn't crash.
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t
+
+struct VBase {
+ virtual ~VBase();
+ virtual void foo();
+ virtual void bar();
+ int field;
+};
+
+struct B : virtual VBase {
+ B();
+ virtual ~B();
+ virtual void foo();
+ virtual void bar();
+};
+
+B::B() {
+ // CHECK-LABEL: define x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"
+ // CHECK: %[[THIS:.*]] = load %struct.B**
+ // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+
+ // Don't check the INIT_VBASES case as it's covered by the ctor tests.
+
+ // CHECK: %[[SKIP_VBASES]]
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
+ // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+
+ // Initialize vtorDisp:
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}}
+ // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]]
+ // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4
+ // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32*
+ // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]]
+
+ // CHECK: ret
+}
+
+B::~B() {
+ // CHECK-LABEL: define x86_thiscallcc void @"\01??1B@@UAE@XZ"
+ // Adjust the this parameter:
+ // CHECK: %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8*
+ // CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8]], i32 -8
+ // CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
+ // CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4
+ // CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]]
+
+ // Restore the vfptr that could have been changed by a subclass.
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
+ // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+
+ // Initialize vtorDisp:
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}}
+ // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]]
+ // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4
+ // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32*
+ // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]]
+
+ foo(); // Avoid the "trivial destructor" optimization.
+
+ // CHECK: ret
+
+ // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B*
+ // CHECK2: %[[THIS:.*]] = load %struct.B** {{.*}}
+ // CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK2: %[[B_i8:.*]] = getelementptr i8* %[[THIS_i8]], i32 8
+ // CHECK2: %[[B:.*]] = bitcast i8* %[[B_i8]] to %struct.B*
+ // CHECK2: call x86_thiscallcc void @"\01??1B@@UAE@XZ"(%struct.B* %[[B]])
+ // CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK2: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i64 8
+ // CHECK2: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase*
+ // CHECK2: call x86_thiscallcc void @"\01??1VBase@@UAE@XZ"(%struct.VBase* %[[VBASE]])
+ // CHECK2: ret
+
+ // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"
+ // CHECK2: %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8*
+ // CHECK2: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8:.*]], i32 -8
+ // CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
+ // CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4
+ // CHECK2: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]]
+ // CHECK2: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[THIS]])
+ // ...
+ // CHECK2: ret
+}
+
+void B::foo() {
+// CHECK-LABEL: define x86_thiscallcc void @"\01?foo@B@@UAEXXZ"(i8*
+//
+// B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we
+// need to adjust 'this' before use.
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.B*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -8
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
+// CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR]], align 4
+
+ field = 42;
+// CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]]
+// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase*
+// CHECK: %[[FIELD:.*]] = getelementptr inbounds %struct.VBase* %[[VBASE]], i32 0, i32 1
+// CHECK: store i32 42, i32* %[[FIELD]], align 4
+//
+// CHECK: ret void
+}
+
+void call_vbase_bar(B *obj) {
+// CHECK-LABEL: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj)
+// CHECK: %[[OBJ:.*]] = load %struct.B
+
+ obj->bar();
+// When calling a vbase's virtual method, one needs to adjust 'this'
+// at the caller site.
+//
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)***
+// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 2
+// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]]
+//
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[VBASE]])
+//
+// CHECK: ret void
+}
+
+void delete_B(B *obj) {
+// CHECK-LABEL: define void @"\01?delete_B@@YAXPAUB@@@Z"(%struct.B* %obj)
+// CHECK: %[[OBJ:.*]] = load %struct.B
+
+ delete obj;
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (%struct.B*, i32)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.B*, i32)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.B*, i32)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.B*, i32)** %[[VFUN]]
+//
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B*
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1)
+// CHECK: ret void
+}
+
+void call_complete_dtor() {
+ // CHECK-LABEL: define void @"\01?call_complete_dtor@@YAXXZ"
+ B b;
+ // CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1)
+ // CHECK-NOT: getelementptr
+ // CHECK: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[B]])
+ // CHECK: ret
+}
+
+struct C : B {
+ C();
+ // has an implicit vdtor.
+};
+
+// Used to crash on an assertion.
+C::C() {
+// CHECK-LABEL: define x86_thiscallcc %struct.C* @"\01??0C@@QAE@XZ"
+}
+
+namespace multiple_vbases {
+struct A {
+ virtual void a();
+};
+
+struct B {
+ virtual void b();
+};
+
+struct C {
+ virtual void c();
+};
+
+struct D : virtual A, virtual B, virtual C {
+ virtual void a();
+ virtual void b();
+ virtual void c();
+ D();
+};
+
+D::D() {
+ // CHECK-LABEL: define x86_thiscallcc %"struct.multiple_vbases::D"* @"\01??0D@multiple_vbases@@QAE@XZ"
+ // Just make sure we emit 3 vtordisps after initializing vfptrs.
+ // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BA@1@@", [1 x i8*]** %{{.*}}
+ // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BB@1@@", [1 x i8*]** %{{.*}}
+ // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BC@1@@", [1 x i8*]** %{{.*}}
+ // ...
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: ret
+}
+}
+
+namespace diamond {
+struct A {
+ A();
+ virtual ~A();
+};
+
+struct B : virtual A {
+ B();
+ ~B();
+};
+
+struct C : virtual A {
+ C();
+ ~C();
+ int c1, c2, c3;
+};
+
+struct Z {
+ int z;
+};
+
+struct D : virtual Z, B, C {
+ D();
+ ~D();
+} d;
+
+D::~D() {
+ // CHECK-LABEL: define x86_thiscallcc void @"\01??1D@diamond@@UAE@XZ"(%"struct.diamond::D"*)
+ // CHECK: %[[ARG_i8:.*]] = bitcast %"struct.diamond::D"* %{{.*}} to i8*
+ // CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ARG_i8]], i32 -24
+ // CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %"struct.diamond::D"*
+ // CHECK: store %"struct.diamond::D"* %[[THIS]], %"struct.diamond::D"** %[[THIS_VAL:.*]], align 4
+ // CHECK: %[[THIS:.*]] = load %"struct.diamond::D"** %[[THIS_VAL]]
+ // CHECK: %[[D_i8:.*]] = bitcast %"struct.diamond::D"* %[[THIS]] to i8*
+ // CHECK: %[[C_i8:.*]] = getelementptr inbounds i8* %[[D_i8]], i64 4
+ // CHECK: %[[C:.*]] = bitcast i8* %[[C_i8]] to %"struct.diamond::C"*
+ // CHECK: %[[C_i8:.*]] = bitcast %"struct.diamond::C"* %[[C]] to i8*
+ // CHECK: %[[ARG_i8:.*]] = getelementptr i8* %{{.*}}, i32 16
+ // FIXME: We might consider changing the dtor this parameter type to i8*.
+ // CHECK: %[[ARG:.*]] = bitcast i8* %[[ARG_i8]] to %"struct.diamond::C"*
+ // CHECK: call x86_thiscallcc void @"\01??1C@diamond@@UAE@XZ"(%"struct.diamond::C"* %[[ARG]])
+
+ // CHECK: %[[B:.*]] = bitcast %"struct.diamond::D"* %[[THIS]] to %"struct.diamond::B"*
+ // CHECK: %[[B_i8:.*]] = bitcast %"struct.diamond::B"* %[[B]] to i8*
+ // CHECK: %[[ARG_i8:.*]] = getelementptr i8* %[[B_i8]], i32 4
+ // CHECK: %[[ARG:.*]] = bitcast i8* %[[ARG_i8]] to %"struct.diamond::B"*
+ // CHECK: call x86_thiscallcc void @"\01??1B@diamond@@UAE@XZ"(%"struct.diamond::B"* %[[ARG]])
+ // CHECK: ret void
+}
+
+}
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
new file mode 100644
index 000000000000..51a04c89dcb7
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK32
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK64
+
+struct S {
+ int x, y, z;
+};
+
+struct C {
+ virtual void foo();
+ virtual int bar(int, double);
+ virtual S baz(int);
+};
+
+namespace {
+struct D {
+ virtual void foo();
+};
+}
+
+void f() {
+ void (C::*ptr)();
+ ptr = &C::foo;
+ ptr = &C::foo; // Don't crash trying to define the thunk twice :)
+
+ int (C::*ptr2)(int, double);
+ ptr2 = &C::bar;
+
+ S (C::*ptr3)(int);
+ ptr3 = &C::baz;
+
+ void (D::*ptr4)();
+ ptr4 = &D::foo;
+
+// CHECK32-LABEL: define void @"\01?f@@YAXXZ"()
+// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
+// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
+// CHECK32: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
+// CHECK32: store i8* bitcast (void (%"struct.<anonymous namespace>::D"*)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4
+// CHECK32: }
+//
+// CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
+// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
+// CHECK64: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
+// CHECK64: store i8* bitcast (void (%"struct.<anonymous namespace>::D"*)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: }
+}
+
+
+// Thunk for calling the 1st virtual function in C with no parameters.
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this) unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}})
+// CHECK32: ret void
+// CHECK32: }
+//
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this) unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
+// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}})
+// CHECK64: ret void
+// CHECK64: }
+
+// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double) unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
+// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
+// CHECK32: [[CALL:%.*]] = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
+// CHECK32: ret i32 [[CALL]]
+// CHECK32: }
+//
+// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double) unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
+// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
+// CHECK64: [[CALL:%.*]] = call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
+// CHECK64: ret i32 [[CALL]]
+// CHECK64: }
+
+// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
+// CHECK32: ret void
+// CHECK32: }
+//
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
+// CHECK64: call void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
+// CHECK64: ret void
+// CHECK64: }
+
+// Thunk for calling the virtual function in internal class D.
+// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.<anonymous namespace>::D"* %this) unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.<anonymous namespace>::D"*)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%"struct.<anonymous namespace>::D"*)** [[VPTR]]
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%"struct.<anonymous namespace>::D"* %{{.*}})
+// CHECK32: ret void
+// CHECK32: }
+//
+// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.<anonymous namespace>::D"* %this) unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.<anonymous namespace>::D"*)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%"struct.<anonymous namespace>::D"*)** [[VPTR]]
+// CHECK64: call void [[CALLEE]](%"struct.<anonymous namespace>::D"* %{{.*}})
+// CHECK64: ret void
+// CHECK64: }
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
new file mode 100644
index 000000000000..d93dee11cdee
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
@@ -0,0 +1,579 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test1 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test2 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test3 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test4 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test5 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test6 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test7 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test8 %s < %t
+// RUN: FileCheck --check-prefix=NO-THUNKS-Test9 %s < %t
+// RUN: FileCheck --check-prefix=PURE-VIRTUAL-Test1 %s < %t
+// RUN: FileCheck --check-prefix=THIS-THUNKS-Test1 %s < %t
+// RUN: FileCheck --check-prefix=THIS-THUNKS-Test2 %s < %t
+// RUN: FileCheck --check-prefix=THIS-THUNKS-Test3 %s < %t
+// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test3 %s < %t
+// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test5 %s < %t
+// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test6 %s < %t
+// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test7 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test1 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test2 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test3 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test6 %s < %t
+
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+struct Empty {
+ // Doesn't have a vftable!
+};
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ // Add an extra virtual method so it's easier to check for the absence of thunks.
+ virtual void h();
+};
+
+struct C {
+ virtual void g(); // Might "collide" with B::g if both are bases of some class.
+};
+
+
+namespace no_thunks {
+
+struct Test1: A, B {
+ // NO-THUNKS-Test1: VFTable for 'A' in 'no_thunks::Test1' (1 entries)
+ // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
+
+ // NO-THUNKS-Test1: VFTable for 'B' in 'no_thunks::Test1' (2 entries)
+ // NO-THUNKS-Test1-NEXT: 0 | void B::g()
+ // NO-THUNKS-Test1-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test1: VFTable indices for 'no_thunks::Test1' (1 entries)
+ // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
+
+ // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BB@@@"
+
+ // Overrides only the left child's method (A::f), needs no thunks.
+ virtual void f();
+};
+
+Test1 t1;
+
+struct Test2: A, B {
+ // NO-THUNKS-Test2: VFTable for 'A' in 'no_thunks::Test2' (1 entries)
+ // NO-THUNKS-Test2-NEXT: 0 | void A::f()
+
+ // NO-THUNKS-Test2: VFTable for 'B' in 'no_thunks::Test2' (2 entries)
+ // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
+ // NO-THUNKS-Test2-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test2: VFTable indices for 'no_thunks::Test2' (1 entries).
+ // NO-THUNKS-Test2-NEXT: via vfptr at offset 4
+ // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
+
+ // Overrides only the right child's method (B::g), needs this adjustment but
+ // not thunks.
+ virtual void g();
+};
+
+Test2 t2;
+
+struct Test3: A, B {
+ // NO-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test3' (2 entries)
+ // NO-THUNKS-Test3-NEXT: 0 | void A::f()
+ // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
+
+ // NO-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test3' (2 entries)
+ // NO-THUNKS-Test3-NEXT: 0 | void B::g()
+ // NO-THUNKS-Test3-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test3: VFTable indices for 'no_thunks::Test3' (1 entries).
+ // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
+
+ // Only adds a new method.
+ virtual void i();
+};
+
+Test3 t3;
+
+// Only the right base has a vftable, so it's laid out before the left one!
+struct Test4 : Empty, A {
+ // NO-THUNKS-Test4: VFTable for 'A' in 'no_thunks::Test4' (1 entries)
+ // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
+
+ // NO-THUNKS-Test4: VFTable indices for 'no_thunks::Test4' (1 entries).
+ // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
+
+ // MANGLING-DAG: @"\01??_7Test4@no_thunks@@6B@"
+
+ virtual void f();
+};
+
+Test4 t4;
+
+// 2-level structure with repeating subobject types, but no thunks needed.
+struct Test5: Test1, Test2 {
+ // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
+ // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test1::f()
+ // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
+
+ // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
+ // NO-THUNKS-Test5-NEXT: 0 | void B::g()
+ // NO-THUNKS-Test5-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test5' (1 entries)
+ // NO-THUNKS-Test5-NEXT: 0 | void A::f()
+
+ // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test5' (2 entries)
+ // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test2::g()
+ // NO-THUNKS-Test5-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test5: VFTable indices for 'no_thunks::Test5' (1 entries).
+ // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
+
+ // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test1@1@@"
+ // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test2@1@@"
+ // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test1@1@@"
+ // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test2@1@@"
+
+ virtual void z();
+};
+
+Test5 t5;
+
+struct Test6: Test1 {
+ // NO-THUNKS-Test6: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test6' (1 entries).
+ // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
+
+ // NO-THUNKS-Test6: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test6' (2 entries).
+ // NO-THUNKS-Test6-NEXT: 0 | void B::g()
+ // NO-THUNKS-Test6-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test6: VFTable indices for 'no_thunks::Test6' (1 entries).
+ // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
+
+ // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BB@@@"
+
+ // Overrides both no_thunks::Test1::f and A::f.
+ virtual void f();
+};
+
+Test6 t6;
+
+struct Test7: Test2 {
+ // NO-THUNKS-Test7: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test7' (1 entries).
+ // NO-THUNKS-Test7-NEXT: 0 | void A::f()
+
+ // NO-THUNKS-Test7: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test7' (2 entries).
+ // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
+ // NO-THUNKS-Test7-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test7: VFTable indices for 'no_thunks::Test7' (1 entries).
+ // NO-THUNKS-Test7-NEXT: via vfptr at offset 4
+ // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
+
+ // Overrides both no_thunks::Test2::g and B::g.
+ virtual void g();
+};
+
+Test7 t7;
+
+struct Test8: Test3 {
+ // NO-THUNKS-Test8: VFTable for 'A' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
+ // NO-THUNKS-Test8-NEXT: 0 | void A::f()
+ // NO-THUNKS-Test8-NEXT: 1 | void no_thunks::Test3::i()
+
+ // NO-THUNKS-Test8: VFTable for 'B' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
+ // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
+ // NO-THUNKS-Test8-NEXT: 1 | void B::h()
+
+ // NO-THUNKS-Test8: VFTable indices for 'no_thunks::Test8' (1 entries).
+ // NO-THUNKS-Test8-NEXT: via vfptr at offset 4
+ // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
+
+ // Overrides grandparent's B::g.
+ virtual void g();
+};
+
+Test8 t8;
+
+struct D : A {
+ virtual void g();
+};
+
+// Repeating subobject.
+struct Test9: A, D {
+ // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::Test9' (2 entries).
+ // NO-THUNKS-Test9-NEXT: 0 | void A::f()
+ // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
+
+ // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::D' in 'no_thunks::Test9' (2 entries).
+ // NO-THUNKS-Test9-NEXT: 0 | void A::f()
+ // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::D::g()
+
+ // NO-THUNKS-Test9: VFTable indices for 'no_thunks::Test9' (1 entries).
+ // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
+
+ // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BD@1@@"
+
+ virtual void h();
+};
+
+Test9 t9;
+}
+
+namespace pure_virtual {
+struct D {
+ virtual void g() = 0;
+ virtual void h();
+};
+
+
+struct Test1: A, D {
+ // PURE-VIRTUAL-Test1: VFTable for 'A' in 'pure_virtual::Test1' (1 entries)
+ // PURE-VIRTUAL-Test1-NEXT: 0 | void A::f()
+
+ // PURE-VIRTUAL-Test1: VFTable for 'pure_virtual::D' in 'pure_virtual::Test1' (2 entries)
+ // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
+ // PURE-VIRTUAL-Test1-NEXT: 1 | void pure_virtual::D::h()
+
+ // PURE-VIRTUAL-Test1: VFTable indices for 'pure_virtual::Test1' (1 entries).
+ // PURE-VIRTUAL-Test1-NEXT: via vfptr at offset 4
+ // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
+
+ // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BD@1@@"
+
+ // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but
+ // not thunks.
+ virtual void g();
+};
+
+Test1 t1;
+}
+
+namespace this_adjustment {
+
+// Overrides methods of two bases at the same time, thus needing thunks.
+struct Test1 : B, C {
+ // THIS-THUNKS-Test1: VFTable for 'B' in 'this_adjustment::Test1' (2 entries).
+ // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
+ // THIS-THUNKS-Test1-NEXT: 1 | void B::h()
+
+ // THIS-THUNKS-Test1: VFTable for 'C' in 'this_adjustment::Test1' (1 entries).
+ // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
+ // THIS-THUNKS-Test1-NEXT: [this adjustment: -4 non-virtual]
+
+ // THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
+ // THIS-THUNKS-Test1-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries).
+ // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
+
+ // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BB@@@"
+ // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BC@@@"
+
+ virtual void g();
+};
+
+Test1 t1;
+
+struct Test2 : A, B, C {
+ // THIS-THUNKS-Test2: VFTable for 'A' in 'this_adjustment::Test2' (1 entries).
+ // THIS-THUNKS-Test2-NEXT: 0 | void A::f()
+
+ // THIS-THUNKS-Test2: VFTable for 'B' in 'this_adjustment::Test2' (2 entries).
+ // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
+ // THIS-THUNKS-Test2-NEXT: 1 | void B::h()
+
+ // THIS-THUNKS-Test2: VFTable for 'C' in 'this_adjustment::Test2' (1 entries).
+ // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
+ // THIS-THUNKS-Test2-NEXT: [this adjustment: -4 non-virtual]
+
+ // THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
+ // THIS-THUNKS-Test2-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // THIS-THUNKS-Test2: VFTable indices for 'this_adjustment::Test2' (1 entries).
+ // THIS-THUNKS-Test2-NEXT: via vfptr at offset 4
+ // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
+
+ // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BB@@@"
+ // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BC@@@"
+
+ virtual void g();
+};
+
+Test2 t2;
+
+// Overrides methods of two bases at the same time, thus needing thunks.
+struct Test3: no_thunks::Test1, no_thunks::Test2 {
+ // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test1' in 'this_adjustment::Test3' (1 entries).
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
+
+ // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test1' in 'this_adjustment::Test3' (2 entries).
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
+ // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
+
+ // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries).
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
+ // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
+
+ // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
+ // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
+ // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
+ // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
+
+ // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
+ // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // THIS-THUNKS-Test3: VFTable indices for 'this_adjustment::Test3' (2 entries).
+ // THIS-THUNKS-Test3-NEXT: via vfptr at offset 0
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
+ // THIS-THUNKS-Test3-NEXT: via vfptr at offset 4
+ // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
+
+ virtual void f();
+ virtual void g();
+};
+
+Test3 t3;
+}
+
+namespace vdtor {
+struct Test1 {
+ virtual ~Test1();
+ virtual void z1();
+};
+
+struct Test2 {
+ virtual ~Test2();
+};
+
+struct Test3 : Test1, Test2 {
+ // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test1' in 'vdtor::Test3' (2 entries).
+ // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
+ // VDTOR-THUNKS-Test3-NEXT: 1 | void vdtor::Test1::z1()
+
+ // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test2' in 'vdtor::Test3' (1 entries).
+ // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
+ // VDTOR-THUNKS-Test3-NEXT: [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test3: Thunks for 'vdtor::Test3::~Test3()' (1 entry).
+ // VDTOR-THUNKS-Test3-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test3: VFTable indices for 'vdtor::Test3' (1 entries).
+ // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
+ virtual ~Test3();
+};
+
+Test3 t3;
+
+struct Test4 {
+ // No virtual destructor here!
+ virtual void z4();
+};
+
+struct Test5 : Test4, Test2 {
+ // Implicit virtual dtor here!
+
+ // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test4' in 'vdtor::Test5' (1 entries).
+ // VDTOR-THUNKS-Test5-NEXT: 0 | void vdtor::Test4::z4()
+
+ // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test2' in 'vdtor::Test5' (1 entries).
+ // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
+ // VDTOR-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test5: Thunks for 'vdtor::Test5::~Test5()' (1 entry).
+ // VDTOR-THUNKS-Test5-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test5: VFTable indices for 'vdtor::Test5' (1 entries).
+ // VDTOR-THUNKS-Test5-NEXT: -- accessible via vfptr at offset 4 --
+ // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
+};
+
+Test5 t5;
+
+struct Test6 : Test4, Test2 {
+ // Implicit virtual dtor here!
+
+ // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test4' in 'vdtor::Test6' (1 entries).
+ // VDTOR-THUNKS-Test6-NEXT: 0 | void vdtor::Test4::z4()
+
+ // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test2' in 'vdtor::Test6' (1 entries).
+ // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
+ // VDTOR-THUNKS-Test6-NEXT: [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test6: Thunks for 'vdtor::Test6::~Test6()' (1 entry).
+ // VDTOR-THUNKS-Test6-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test6: VFTable indices for 'vdtor::Test6' (1 entries).
+ // VDTOR-THUNKS-Test6-NEXT: -- accessible via vfptr at offset 4 --
+ // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
+};
+
+Test6 t6;
+
+struct Test7 : Test5 {
+ // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test4' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries).
+ // VDTOR-THUNKS-Test7-NEXT: 0 | void vdtor::Test4::z4()
+
+ // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test2' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries).
+ // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
+ // VDTOR-THUNKS-Test7-NEXT: [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test7: Thunks for 'vdtor::Test7::~Test7()' (1 entry).
+ // VDTOR-THUNKS-Test7-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTOR-THUNKS-Test7: VFTable indices for 'vdtor::Test7' (1 entries).
+ // VDTOR-THUNKS-Test7-NEXT: -- accessible via vfptr at offset 4 --
+ // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
+ virtual ~Test7();
+};
+
+Test7 t7;
+
+}
+
+namespace return_adjustment {
+
+struct Ret1 {
+ virtual C* foo();
+ virtual void z();
+};
+
+struct Test1 : Ret1 {
+ // RET-THUNKS-Test1: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries).
+ // RET-THUNKS-Test1-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo()
+ // RET-THUNKS-Test1-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test1-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
+
+ // RET-THUNKS-Test1: VFTable indices for 'return_adjustment::Test1' (1 entries).
+ // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
+
+ // MANGLING-DAG: @"\01??_7Test1@return_adjustment@@6B@"
+
+ virtual this_adjustment::Test1* foo();
+};
+
+Test1 t1;
+
+struct Ret2 : B, this_adjustment::Test1 { };
+
+struct Test2 : Test1 {
+ // RET-THUNKS-Test2: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries).
+ // RET-THUNKS-Test2-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
+ // RET-THUNKS-Test2-NEXT: [return adjustment: 8 non-virtual]
+ // RET-THUNKS-Test2-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test2-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
+ // RET-THUNKS-Test2-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
+
+ // RET-THUNKS-Test2: VFTable indices for 'return_adjustment::Test2' (1 entries).
+ // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
+
+ virtual Ret2* foo();
+};
+
+Test2 t2;
+
+struct Test3: B, Ret1 {
+ // RET-THUNKS-Test3: VFTable for 'B' in 'return_adjustment::Test3' (2 entries).
+ // RET-THUNKS-Test3-NEXT: 0 | void B::g()
+ // RET-THUNKS-Test3-NEXT: 1 | void B::h()
+
+ // RET-THUNKS-Test3: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries).
+ // RET-THUNKS-Test3-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo()
+ // RET-THUNKS-Test3-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test3-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
+
+ // RET-THUNKS-Test3: VFTable indices for 'return_adjustment::Test3' (1 entries).
+ // RET-THUNKS-Test3-NEXT: via vfptr at offset 4
+ // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
+
+ virtual this_adjustment::Test1* foo();
+};
+
+Test3 t3;
+
+struct Test4 : Test3 {
+ // RET-THUNKS-Test4: VFTable for 'B' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (2 entries).
+ // RET-THUNKS-Test4-NEXT: 0 | void B::g()
+ // RET-THUNKS-Test4-NEXT: 1 | void B::h()
+
+ // RET-THUNKS-Test4: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries).
+ // RET-THUNKS-Test4-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
+ // RET-THUNKS-Test4-NEXT: [return adjustment: 8 non-virtual]
+ // RET-THUNKS-Test4-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test4-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
+ // RET-THUNKS-Test4-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
+
+ // RET-THUNKS-Test4: VFTable indices for 'return_adjustment::Test4' (1 entries).
+ // RET-THUNKS-Test4-NEXT: -- accessible via vfptr at offset 4 --
+ // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
+
+ virtual Ret2* foo();
+};
+
+Test4 t4;
+
+struct Test5 : Ret1, Test1 {
+ // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries).
+ // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+ // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual]
+ // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+
+ // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries).
+ // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+ // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual]
+ // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
+ // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+ // RET-THUNKS-Test5-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
+ // RET-THUNKS-Test5-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+ // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
+
+ // RET-THUNKS-Test5: VFTable indices for 'return_adjustment::Test5' (1 entries).
+ // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
+
+ virtual Ret2* foo();
+};
+
+Test5 t5;
+
+struct Ret3 : this_adjustment::Test1 { };
+
+struct Test6 : Test1 {
+ virtual Ret3* foo();
+ // RET-THUNKS-Test6: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test6' (4 entries).
+ // RET-THUNKS-Test6-NEXT: 0 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
+ // RET-THUNKS-Test6-NEXT: [return adjustment: 4 non-virtual]
+ // RET-THUNKS-Test6-NEXT: 1 | void return_adjustment::Ret1::z()
+ // RET-THUNKS-Test6-NEXT: 2 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
+ // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
+
+ // RET-THUNKS-Test6: VFTable indices for 'return_adjustment::Test6' (1 entries).
+ // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
+};
+
+Test6 t6;
+
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
index 5d430db54e2e..6fe12b0ef07b 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1
-// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t
+// RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll
+// RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll
// RUN: FileCheck --check-prefix=CHECK-A %s < %t
// RUN: FileCheck --check-prefix=CHECK-B %s < %t
// RUN: FileCheck --check-prefix=CHECK-C %s < %t
@@ -7,107 +8,245 @@
// RUN: FileCheck --check-prefix=CHECK-E %s < %t
// RUN: FileCheck --check-prefix=CHECK-F %s < %t
// RUN: FileCheck --check-prefix=CHECK-G %s < %t
+// RUN: FileCheck --check-prefix=CHECK-I %s < %t
+// RUN: FileCheck --check-prefix=CHECK-J %s < %t
+// RUN: FileCheck --check-prefix=CHECK-K %s < %t
+// RUN: FileCheck --check-prefix=CHECK-L %s < %t
+// RUN: FileCheck --check-prefix=CHECK-M %s < %t
+// RUN: FileCheck --check-prefix=CHECK-N %s < %t
struct A {
- // CHECK-A: Vtable for 'A' (3 entries)
+ // CHECK-A: VFTable for 'A' (3 entries)
// CHECK-A-NEXT: 0 | void A::f()
// CHECK-A-NEXT: 1 | void A::g()
// CHECK-A-NEXT: 2 | void A::h()
- // EMITS-VTABLE: @"\01??_7A@@6B@" = unnamed_addr constant [3 x i8*]
+ // CHECK-A: VFTable indices for 'A' (3 entries)
+ // CHECK-A-NEXT: 0 | void A::f()
+ // CHECK-A-NEXT: 1 | void A::g()
+ // CHECK-A-NEXT: 2 | void A::h()
+
virtual void f();
virtual void g();
virtual void h();
int ia;
};
-void A::f() {}
+A a;
+// EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*]
struct B : A {
- // CHECK-B: Vtable for 'B' (5 entries)
+ // CHECK-B: VFTable for 'A' in 'B' (5 entries)
// CHECK-B-NEXT: 0 | void B::f()
// CHECK-B-NEXT: 1 | void A::g()
// CHECK-B-NEXT: 2 | void A::h()
// CHECK-B-NEXT: 3 | void B::i()
// CHECK-B-NEXT: 4 | void B::j()
- // EMITS-VTABLE: @"\01??_7B@@6B@" = unnamed_addr constant [5 x i8*]
+ // CHECK-B: VFTable indices for 'B' (3 entries)
+ // CHECK-B-NEXT: 0 | void B::f()
+ // CHECK-B-NEXT: 3 | void B::i()
+ // CHECK-B-NEXT: 4 | void B::j()
+
virtual void f(); // overrides A::f()
virtual void i();
virtual void j();
};
-void B::f() {}
+B b;
+// EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
struct C {
- // CHECK-C: Vtable for 'C' (2 entries)
+ // CHECK-C: VFTable for 'C' (2 entries)
// CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
// CHECK-C-NEXT: 1 | void C::f()
- // CHECK-C: VTable indices for 'C' (2 entries).
+ // CHECK-C: VFTable indices for 'C' (2 entries).
// CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
// CHECK-C-NEXT: 1 | void C::f()
- // Never used, so doesn't emit a vtable.
- virtual ~C();
+ virtual ~C();
virtual void f();
};
void C::f() {}
+// NO-VFTABLE-NOT: @"\01??_7C@@6B@"
struct D {
- // CHECK-D: Vtable for 'D' (2 entries)
+ // CHECK-D: VFTable for 'D' (2 entries)
+ // CHECK-D-NEXT: 0 | void D::f()
+ // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
+ // CHECK-D: VFTable indices for 'D' (2 entries)
// CHECK-D-NEXT: 0 | void D::f()
// CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
- // EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*]
- virtual void f();
+ virtual void f();
virtual ~D();
};
-void D::f() {}
+D d;
+// EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*]
struct E : A {
- // CHECK-E: Vtable for 'E' (5 entries)
+ // CHECK-E: VFTable for 'A' in 'E' (5 entries)
// CHECK-E-NEXT: 0 | void A::f()
// CHECK-E-NEXT: 1 | void A::g()
// CHECK-E-NEXT: 2 | void A::h()
// CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
// CHECK-E-NEXT: 4 | void E::i()
- // CHECK-E: VTable indices for 'E' (2 entries).
+ // CHECK-E: VFTable indices for 'E' (2 entries).
// CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
// CHECK-E-NEXT: 4 | void E::i()
- // Never used, so doesn't emit a vtable.
+ // ~E would be the key method, but it isn't used, and MS ABI has no key
+ // methods.
virtual ~E();
virtual void i();
};
void E::i() {}
+// NO-VFTABLE-NOT: @"\01??_7E@@6B@"
struct F : A {
- // CHECK-F: Vtable for 'F' (5 entries)
+ // CHECK-F: VFTable for 'A' in 'F' (5 entries)
// CHECK-F-NEXT: 0 | void A::f()
// CHECK-F-NEXT: 1 | void A::g()
// CHECK-F-NEXT: 2 | void A::h()
// CHECK-F-NEXT: 3 | void F::i()
// CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
- // CHECK-F: VTable indices for 'F' (2 entries).
+ // CHECK-F: VFTable indices for 'F' (2 entries).
// CHECK-F-NEXT: 3 | void F::i()
// CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
- // EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*]
+
virtual void i();
virtual ~F();
};
-void F::i() {}
+F f;
+// EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
struct G : E {
- // CHECK-G: Vtable for 'G' (6 entries)
+ // CHECK-G: VFTable for 'A' in 'E' in 'G' (6 entries)
// CHECK-G-NEXT: 0 | void G::f()
// CHECK-G-NEXT: 1 | void A::g()
// CHECK-G-NEXT: 2 | void A::h()
// CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
// CHECK-G-NEXT: 4 | void E::i()
// CHECK-G-NEXT: 5 | void G::j()
- // CHECK-G: VTable indices for 'G' (3 entries).
+ // CHECK-G: VFTable indices for 'G' (3 entries).
// CHECK-G-NEXT: 0 | void G::f()
// CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
// CHECK-G-NEXT: 5 | void G::j()
- // Never used, so doesn't emit a vtable.
+
virtual void f(); // overrides A::f()
virtual ~G();
virtual void j();
};
void G::j() {}
+// NO-VFTABLE-NOT: @"\01??_7G@@6B@"
+
+// Test that the usual Itanium-style key method does not emit a vtable.
+struct H {
+ virtual void f();
+};
+void H::f() {}
+// NO-VFTABLE-NOT: @"\01??_7H@@6B@"
+
+struct Empty { };
+
+struct I : Empty {
+ // CHECK-I: VFTable for 'I' (2 entries)
+ // CHECK-I-NEXT: 0 | void I::f()
+ // CHECK-I-NEXT: 1 | void I::g()
+ virtual void f();
+ virtual void g();
+};
+
+I i;
+
+struct J {
+ // CHECK-J: VFTable for 'J' (6 entries)
+ // CHECK-J-NEXT: 0 | void J::foo(long)
+ // CHECK-J-NEXT: 1 | void J::foo(int)
+ // CHECK-J-NEXT: 2 | void J::foo(short)
+ // CHECK-J-NEXT: 3 | void J::bar(long)
+ // CHECK-J-NEXT: 4 | void J::bar(int)
+ // CHECK-J-NEXT: 5 | void J::bar(short)
+ virtual void foo(short);
+ virtual void bar(short);
+ virtual void foo(int);
+ virtual void bar(int);
+ virtual void foo(long);
+ virtual void bar(long);
+};
+
+J j;
+
+struct K : J {
+ // CHECK-K: VFTable for 'J' in 'K' (9 entries)
+ // CHECK-K-NEXT: 0 | void J::foo(long)
+ // CHECK-K-NEXT: 1 | void J::foo(int)
+ // CHECK-K-NEXT: 2 | void J::foo(short)
+ // CHECK-K-NEXT: 3 | void J::bar(long)
+ // CHECK-K-NEXT: 4 | void J::bar(int)
+ // CHECK-K-NEXT: 5 | void J::bar(short)
+ // CHECK-K-NEXT: 6 | void K::bar(double)
+ // CHECK-K-NEXT: 7 | void K::bar(float)
+ // CHECK-K-NEXT: 8 | void K::foo(float)
+ virtual void bar(float);
+ virtual void foo(float);
+ virtual void bar(double);
+};
+
+K k;
+
+struct L : J {
+ // CHECK-L: VFTable for 'J' in 'L' (9 entries)
+ // CHECK-L-NEXT: 0 | void J::foo(long)
+ // CHECK-L-NEXT: 1 | void L::foo(int)
+ // CHECK-L-NEXT: 2 | void J::foo(short)
+ // CHECK-L-NEXT: 3 | void J::bar(long)
+ // CHECK-L-NEXT: 4 | void J::bar(int)
+ // CHECK-L-NEXT: 5 | void J::bar(short)
+ // CHECK-L-NEXT: 6 | void L::foo(float)
+ // CHECK-L-NEXT: 7 | void L::bar(double)
+ // CHECK-L-NEXT: 8 | void L::bar(float)
+
+ // This case is interesting. Since the J::foo(int) override is the first method in
+ // the class, foo(float) precedes the bar(double) and bar(float) in the vftable.
+ virtual void foo(int);
+ virtual void bar(float);
+ virtual void foo(float);
+ virtual void bar(double);
+};
+
+L l;
+
+struct M : J {
+ // CHECK-M: VFTable for 'J' in 'M' (11 entries)
+ // CHECK-M-NEXT: 0 | void J::foo(long)
+ // CHECK-M-NEXT: 1 | void M::foo(int)
+ // CHECK-M-NEXT: 2 | void J::foo(short)
+ // CHECK-M-NEXT: 3 | void J::bar(long)
+ // CHECK-M-NEXT: 4 | void J::bar(int)
+ // CHECK-M-NEXT: 5 | void J::bar(short)
+ // CHECK-M-NEXT: 6 | void M::foo(float)
+ // CHECK-M-NEXT: 7 | void M::spam(long)
+ // CHECK-M-NEXT: 8 | void M::spam(int)
+ // CHECK-M-NEXT: 9 | void M::bar(double)
+ // CHECK-M-NEXT: 10 | void M::bar(float)
+
+ virtual void foo(int);
+ virtual void spam(int);
+ virtual void bar(float);
+ virtual void bar(double);
+ virtual void foo(float);
+ virtual void spam(long);
+};
+
+M m;
+
+struct N {
+ // CHECK-N: VFTable for 'N' (4 entries)
+ // CHECK-N-NEXT: 0 | void N::operator+(int)
+ // CHECK-N-NEXT: 1 | void N::operator+(short)
+ // CHECK-N-NEXT: 2 | void N::operator*(int)
+ // CHECK-N-NEXT: 3 | void N::operator*(short)
+ virtual void operator+(short);
+ virtual void operator*(short);
+ virtual void operator+(int);
+ virtual void operator*(int);
+};
+
+N n;
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
new file mode 100644
index 000000000000..3fef0e409349
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
@@ -0,0 +1,324 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o %t.ll -cxx-abi microsoft -triple=i386-pc-win32 >%t
+// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-A %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-B %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-C %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-A %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-B %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-C %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-E %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-F %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-G %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-H %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-PR17738-A %s < %t
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+// For now, just make sure x86_64 doesn't crash.
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -fdump-vtable-layouts %s -cxx-abi microsoft -triple=x86_64-pc-win32 >/dev/null
+
+struct V1 {
+ virtual void f();
+ virtual ~V1();
+};
+
+struct V2 {
+ virtual void f();
+ virtual ~V2();
+ int v;
+};
+
+struct Z {
+ virtual void g();
+ virtual ~Z();
+ int x;
+};
+
+struct V3 : Z, V2 {
+};
+
+struct V4 : Z, V1, V2 {
+ int y;
+};
+
+void use_somewhere_else(void*);
+
+namespace simple {
+// In case of a single-layer virtual inheritance, the "this" adjustment is done
+// staically:
+// struct A {
+// virtual void f(); // Expects "(A*)this" in ECX
+// };
+// struct B : virtual A {
+// virtual void f(); // Expects "(char*)(B*)this + 12" in ECX
+// virtual ~B(); // Might call f()
+// };
+//
+// If a class overrides a virtual function of its base and has a non-trivial
+// ctor/dtor that call(s) the virtual function (or may escape "this" to some
+// code that might call it), a virtual adjustment might be needed in case the
+// current class layout and the most derived class layout are different.
+// This is done using vtordisp thunks.
+//
+// A simple vtordisp{A,B} thunk for Method@Class is something like:
+// sub ecx, [ecx+A] // apply the vtordisp adjustment
+// sub ecx, B // apply the subobject adjustment, if needed.
+// jmp Method@Class
+
+struct A : virtual V1 {
+ // VTABLE-SIMPLE-A: VFTable for 'V1' in 'simple::A' (2 entries).
+ // VTABLE-SIMPLE-A-NEXT: 0 | void simple::A::f()
+ // VTABLE-SIMPLE-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+ // VTABLE-SIMPLE-A-NEXT: 1 | simple::A::~A() [scalar deleting]
+ // VTABLE-SIMPLE-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ virtual void f();
+ // MANGLING-DAG: @"\01?f@A@simple@@$4PPPPPPPM@A@AEXXZ"
+
+ virtual ~A();
+ // MANGLING-DAG: @"\01??_EA@simple@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+A a;
+
+struct B : virtual V3 {
+ // VTABLE-SIMPLE-B: VFTable for 'Z' in 'V3' in 'simple::B' (2 entries).
+ // VTABLE-SIMPLE-B-NEXT: 0 | void Z::g()
+ // VTABLE-SIMPLE-B-NEXT: 1 | simple::B::~B() [scalar deleting]
+ // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // VTABLE-SIMPLE-B: VFTable for 'V2' in 'V3' in 'simple::B' (2 entries).
+ // VTABLE-SIMPLE-B-NEXT: 0 | void simple::B::f()
+ // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual]
+ // VTABLE-SIMPLE-B-NEXT: 1 | simple::B::~B() [scalar deleting]
+ // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
+
+ // FIXME: The vtordisp thunk should only get emitted for a constructor
+ // if "this" leaves scope.
+ B() { use_somewhere_else(this); }
+
+ virtual void f();
+ // MANGLING-DAG: @"\01?f@B@simple@@$4PPPPPPPE@A@AEXXZ"
+
+ // Has an implicit destructor.
+ // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPE@7AEPAXI@Z"
+ // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+B b;
+
+struct C : virtual V4 {
+ // VTABLE-SIMPLE-C: VFTable for 'Z' in 'V4' in 'simple::C' (2 entries).
+ // VTABLE-SIMPLE-C-NEXT: 0 | void Z::g()
+ // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting]
+ // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // VTABLE-SIMPLE-C: VFTable for 'V1' in 'V4' in 'simple::C' (2 entries).
+ // VTABLE-SIMPLE-C-NEXT: 0 | void simple::C::f()
+ // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual]
+ // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting]
+ // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
+
+ // VTABLE-SIMPLE-C: VFTable for 'V2' in 'V4' in 'simple::C' (2 entries).
+ // VTABLE-SIMPLE-C-NEXT: 0 | void simple::C::f()
+ // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -16, -4 non-virtual]
+ // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting]
+ // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -16, -12 non-virtual]
+
+ int x;
+ virtual void f();
+ // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPA@3AEXXZ"
+ // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPE@A@AEXXZ"
+ virtual ~C();
+ // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPA@M@AEPAXI@Z"
+ // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPE@7AEPAXI@Z"
+ // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+C c;
+}
+
+namespace extended {
+// If a virtual function requires vtordisp adjustment and the final overrider
+// is defined in another vitual base of the most derived class,
+// we need to know two vbase offsets.
+// In this case, we should use the extended form of vtordisp thunks, called
+// vtordispex thunks.
+//
+// vtordispex{A,B,C,D} thunk for Method@Class is something like:
+// sub ecx, [ecx+C] // apply the vtordisp adjustment
+// sub ecx, A // jump to the vbtable of the most derived class
+// mov eax, [ecx] // load the vbtable address
+// add ecx, [eax+B] // lookup the final overrider's vbase offset
+// add ecx, D // apphy the subobject offset if needed
+// jmp Method@Class
+
+struct A : virtual simple::A {
+ // VTABLE-EXTENDED-A: VFTable for 'V1' in 'simple::A' in 'extended::A' (2 entries).
+ // VTABLE-EXTENDED-A-NEXT: 0 | void simple::A::f()
+ // VTABLE-EXTENDED-A-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
+ // VTABLE-EXTENDED-A-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
+ // VTABLE-EXTENDED-A-NEXT: 1 | extended::A::~A() [scalar deleting]
+ // VTABLE-EXTENDED-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // `vtordispex{8,8,4294967292,8}'
+ // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ"
+
+ virtual ~A();
+ // vtordisp{4294967292,0}
+ // MANGLING-DAG: @"\01??_EA@extended@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+A a;
+
+struct B : virtual simple::A {
+ // This class has an implicit dtor. Vdtors don't require vtordispex thunks
+ // as the most derived class always has an implicit dtor,
+ // which is a final overrider.
+
+ // VTABLE-EXTENDED-B: VFTable for 'V1' in 'simple::A' in 'extended::B' (2 entries).
+ // ...
+ // VTABLE-EXTENDED-B: 1 | extended::B::~B() [scalar deleting]
+ // VTABLE-EXTENDED-B-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // vtordisp{4294967292,0}
+ // MANGLING-DAG: @"\01??_EB@extended@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+B b;
+
+struct C : virtual simple::A {
+ // VTABLE-EXTENDED-C: VFTable for 'V1' in 'simple::A' in 'extended::C' (2 entries).
+ // VTABLE-EXTENDED-C-NEXT: 0 | void simple::A::f()
+ // VTABLE-EXTENDED-C-NEXT: [this adjustment: vtordisp at -4, vbptr at 12 to the left,
+ // VTABLE-EXTENDED-C-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
+
+ // `vtordispex{12,8,4294967292,8}'
+ // MANGLING-DAG: @"\01?f@A@simple@@$R4M@7PPPPPPPM@7AEXXZ"
+ int x;
+ virtual ~C();
+ // MANGLING-DAG: @"\01??_EC@extended@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+C c;
+
+struct D : virtual V2 {
+ virtual void f();
+ virtual ~D();
+ int x;
+};
+
+struct E : virtual D {
+ // VTABLE-EXTENDED-E: VFTable for 'V2' in 'extended::D' in 'extended::E' (2 entries).
+ // VTABLE-EXTENDED-E-NEXT: 0 | void extended::D::f()
+ // VTABLE-EXTENDED-E-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
+ // VTABLE-EXTENDED-E-NEXT: vboffset at 8 in the vbtable, 12 non-virtual]
+
+ // `vtordispex{8,8,4294967292,12}'
+ // MANGLING-DAG: @"\01?f@D@extended@@$R477PPPPPPPM@M@AEXXZ"
+
+ virtual ~E();
+ // MANGLING-DAG: @"\01??_EE@extended@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+E e;
+
+struct F : virtual Z, virtual D {
+ // VTABLE-EXTENDED-F: VFTable for 'V2' in 'extended::D' in 'extended::F' (2 entries).
+ // VTABLE-EXTENDED-F-NEXT: 0 | void extended::D::f()
+ // VTABLE-EXTENDED-F-NEXT: [this adjustment: vtordisp at -4, vbptr at 20 to the left,
+ // VTABLE-EXTENDED-F-NEXT: vboffset at 12 in the vbtable, 12 non-virtual]
+
+ // `vtordispex{20,12,4294967292,12}'
+ // MANGLING-DAG: @"\01?f@D@extended@@$R4BE@M@PPPPPPPM@M@AEXXZ"
+ int x;
+ virtual ~F();
+ // MANGLING-DAG: @"\01??_EF@extended@@$4PPPPPPPM@M@AEPAXI@Z"
+};
+
+F f;
+
+struct G : virtual simple::A {
+ // VTABLE-EXTENDED-G: VFTable for 'extended::G' (1 entries).
+ // VTABLE-EXTENDED-G-NEXT: 0 | void extended::G::g()
+
+ // VTABLE-EXTENDED-G: VFTable for 'V1' in 'simple::A' in 'extended::G' (2 entries).
+ // VTABLE-EXTENDED-G-NEXT: 0 | void simple::A::f()
+ // VTABLE-EXTENDED-G-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
+ // VTABLE-EXTENDED-G-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
+ // VTABLE-EXTENDED-G-NEXT: 1 | extended::G::~G() [scalar deleting]
+ // VTABLE-EXTENDED-G-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // Emits a G's own vfptr, thus moving the vbptr in the layout.
+ virtual void g();
+
+ virtual ~G();
+ // vtordisp{4294967292,0}
+ // MANGLING-DAG: @"\01??_EG@extended@@$4PPPPPPPM@A@AEPAXI@Z"
+};
+
+G g;
+
+struct H : Z, A {
+ // VTABLE-EXTENDED-H: VFTable for 'Z' in 'extended::H' (2 entries).
+ // VTABLE-EXTENDED-H-NEXT: 0 | void Z::g()
+ // VTABLE-EXTENDED-H-NEXT: 1 | extended::H::~H() [scalar deleting]
+
+ // VTABLE-EXTENDED-H: VFTable for 'V1' in 'simple::A' in 'extended::A' in 'extended::H' (2 entries).
+ // VTABLE-EXTENDED-H-NEXT: 0 | void simple::A::f()
+ // VTABLE-EXTENDED-H-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left,
+ // VTABLE-EXTENDED-H-NEXT: vboffset at 8 in the vbtable, 8 non-virtual]
+
+ // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ"
+ // MANGLING-DAG: @"\01??_EH@extended@@$4PPPPPPPM@BA@AEPAXI@Z"
+};
+
+H h;
+}
+
+namespace pr17738 {
+// These classes should have vtordispex thunks but MSVS CL miscompiles them.
+// Just do the right thing.
+
+struct A : virtual simple::B {
+ // VTABLE-PR17738-A: VFTable for 'V2' in 'V3' in 'simple::B' in 'pr17738::A' (2 entries).
+ // VTABLE-PR17738-A-NEXT: 0 | void simple::B::f()
+ // VTABLE-PR17738-A-NEXT: [this adjustment: vtordisp at -12, vbptr at 20 to the left,
+ // VTABLE-PR17738-A-NEXT: vboffset at 8 in the vbtable, 16 non-virtual]
+
+ // MANGLING-DAG: @"\01?f@B@simple@@$R4BE@7PPPPPPPE@BA@AEXXZ"
+ int a;
+ virtual ~A();
+};
+
+A a;
+}
+
+namespace access {
+struct A {
+ virtual ~A();
+protected:
+ virtual void prot();
+private:
+ virtual void priv();
+};
+
+struct B : virtual A {
+ virtual ~B();
+protected:
+ virtual void prot();
+ // MANGLING-DAG: @"\01?prot@B@access@@$2PPPPPPPM@A@AEXXZ"
+private:
+ virtual void priv();
+ // MANGLING-DAG: @"\01?priv@B@access@@$0PPPPPPPM@A@AEXXZ"
+};
+
+B b;
+
+struct C : virtual B {
+ virtual ~C();
+
+ // MANGLING-DAG: @"\01?prot@B@access@@$R277PPPPPPPM@7AEXXZ"
+ // MANGLING-DAG: @"\01?priv@B@access@@$R077PPPPPPPM@7AEXXZ"
+};
+
+C c;
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
new file mode 100644
index 000000000000..b58a0b14cdcd
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -0,0 +1,575 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -cxx-abi microsoft -triple=i386-pc-win32 >%t
+
+// RUN: FileCheck --check-prefix=VTABLE-C %s < %t
+// RUN: FileCheck --check-prefix=VTABLE-D %s < %t
+// RUN: FileCheck --check-prefix=TEST1 %s < %t
+// RUN: FileCheck --check-prefix=TEST2 %s < %t
+// RUN: FileCheck --check-prefix=TEST3 %s < %t
+// RUN: FileCheck --check-prefix=TEST4 %s < %t
+// RUN: FileCheck --check-prefix=TEST5 %s < %t
+// RUN: FileCheck --check-prefix=TEST6 %s < %t
+// RUN: FileCheck --check-prefix=TEST7 %s < %t
+// RUN: FileCheck --check-prefix=TEST8-X %s < %t
+// RUN: FileCheck --check-prefix=TEST8-Z %s < %t
+// RUN: FileCheck --check-prefix=TEST9-Y %s < %t
+// RUN: FileCheck --check-prefix=TEST9-Z %s < %t
+// RUN: FileCheck --check-prefix=TEST9-W %s < %t
+// RUN: FileCheck --check-prefix=TEST9-T %s < %t
+// RUN: FileCheck --check-prefix=TEST10 %s < %t
+// RUN: FileCheck --check-prefix=VDTORS-Y %s < %t
+// RUN: FileCheck --check-prefix=VDTORS-U %s < %t
+// RUN: FileCheck --check-prefix=VDTORS-V %s < %t
+// RUN: FileCheck --check-prefix=VDTORS-P %s < %t
+// RUN: FileCheck --check-prefix=RET-W %s < %t
+// RUN: FileCheck --check-prefix=RET-T %s < %t
+// RUN: FileCheck --check-prefix=RET-V %s < %t
+
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+struct Empty { };
+
+struct A {
+ virtual void f();
+ virtual void z(); // Useful to check there are no thunks for f() when appropriate.
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C: virtual A {
+ // VTABLE-C: VFTable for 'A' in 'C' (2 entries)
+ // VTABLE-C-NEXT: 0 | void C::f()
+ // VTABLE-C-NEXT: 1 | void A::z()
+
+ // VTABLE-C: VFTable indices for 'C' (1 entries)
+ // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0
+ // VTABLE-C-NEXT: 0 | void C::f()
+
+ // MANGLING-DAG: @"\01??_7C@@6B@"
+
+ virtual void f();
+};
+
+C c;
+
+struct D: virtual A {
+ // VTABLE-D: VFTable for 'D' (1 entries).
+ // VTABLE-D-NEXT: 0 | void D::h()
+
+ // VTABLE-D: VFTable for 'A' in 'D' (2 entries).
+ // VTABLE-D-NEXT: 0 | void D::f()
+ // VTABLE-D-NEXT: 1 | void A::z()
+
+ // VTABLE-D: VFTable indices for 'D' (2 entries).
+ // VTABLE-D-NEXT: via vfptr at offset 0
+ // VTABLE-D-NEXT: 0 | void D::h()
+ // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0
+ // VTABLE-D-NEXT: 0 | void D::f()
+
+ // MANGLING-DAG: @"\01??_7D@@6B0@@"
+ // MANGLING-DAG: @"\01??_7D@@6BA@@@"
+
+ virtual void f();
+ virtual void h();
+};
+
+void D::h() {}
+D d;
+
+namespace Test1 {
+
+struct X { int x; };
+
+// X and A get reordered in the layout since X doesn't have a vfptr while A has.
+struct Y : X, A { };
+// MANGLING-DAG: @"\01??_7Y@Test1@@6B@"
+
+struct Z : virtual Y {
+ // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
+ // TEST1-NEXT: 0 | void A::f()
+ // TEST1-NEXT: 1 | void A::z()
+
+ // TEST1-NOT: VFTable indices for 'Test1::Z'
+
+ // MANGLING-DAG: @"\01??_7Z@Test1@@6B@"
+};
+
+Z z;
+}
+
+namespace Test2 {
+
+struct X: virtual A, virtual B {
+ // TEST2: VFTable for 'Test2::X' (1 entries).
+ // TEST2-NEXT: 0 | void Test2::X::h()
+
+ // TEST2: VFTable for 'A' in 'Test2::X' (2 entries).
+ // TEST2-NEXT: 0 | void A::f()
+ // TEST2-NEXT: 1 | void A::z()
+
+ // TEST2: VFTable for 'B' in 'Test2::X' (1 entries).
+ // TEST2-NEXT: 0 | void B::g()
+
+ // TEST2: VFTable indices for 'Test2::X' (1 entries).
+ // TEST2-NEXT: 0 | void Test2::X::h()
+
+ // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@"
+ // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@"
+
+ virtual void h();
+};
+
+X x;
+}
+
+namespace Test3 {
+
+struct X : virtual A {
+ // MANGLING-DAG: @"\01??_7X@Test3@@6B@"
+};
+
+struct Y: virtual X {
+ // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
+ // TEST3-NEXT: 0 | void A::f()
+ // TEST3-NEXT: 1 | void A::z()
+
+ // TEST3-NOT: VFTable indices for 'Test3::Y'
+
+ // MANGLING-DAG: @"\01??_7Y@Test3@@6B@"
+};
+
+Y y;
+}
+
+namespace Test4 {
+
+struct X: virtual C {
+ // This one's interesting. C::f expects (A*) to be passed as 'this' and does
+ // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
+ // should pass a pointer to the end of X in order
+ // for ECX-=4 to point at the C part.
+
+ // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
+ // TEST4-NEXT: 0 | void C::f()
+ // TEST4-NEXT: [this adjustment: 8 non-virtual]
+ // TEST4-NEXT: 1 | void A::z()
+
+ // TEST4-NOT: VFTable indices for 'Test4::X'
+
+ // MANGLING-DAG: @"\01??_7X@Test4@@6B@"
+
+ // Also check the mangling of the thunk.
+ // MANGLING-DAG: define weak x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
+};
+
+X x;
+}
+
+namespace Test5 {
+
+// New methods are added to the base's vftable.
+struct X : A {
+ // MANGLING-DAG: @"\01??_7X@Test5@@6B@"
+ virtual void g();
+};
+
+struct Y : virtual X {
+ // TEST5: VFTable for 'Test5::Y' (1 entries).
+ // TEST5-NEXT: 0 | void Test5::Y::h()
+
+ // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
+ // TEST5-NEXT: 0 | void A::f()
+ // TEST5-NEXT: 1 | void A::z()
+ // TEST5-NEXT: 2 | void Test5::X::g()
+
+ // TEST5: VFTable indices for 'Test5::Y' (1 entries).
+ // TEST5-NEXT: 0 | void Test5::Y::h()
+
+ // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@"
+ // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@"
+
+ virtual void h();
+};
+
+Y y;
+}
+
+namespace Test6 {
+
+struct X : A, virtual Empty {
+ // TEST6: VFTable for 'A' in 'Test6::X' (2 entries).
+ // TEST6-NEXT: 0 | void A::f()
+ // TEST6-NEXT: 1 | void A::z()
+
+ // TEST6-NOT: VFTable indices for 'Test6::X'
+
+ // MANGLING-DAG: @"\01??_7X@Test6@@6B@"
+};
+
+X x;
+}
+
+namespace Test7 {
+
+struct X : C {
+ // MANGLING-DAG: @"\01??_7X@Test7@@6B@"
+};
+
+struct Y : virtual X {
+ // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
+ // TEST7-NEXT: 0 | void C::f()
+ // TEST7-NEXT: [this adjustment: 8 non-virtual]
+ // TEST7-NEXT: 1 | void A::z()
+
+ // TEST7: Thunks for 'void C::f()' (1 entry).
+ // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual]
+
+ // TEST7-NOT: VFTable indices for 'Test7::Y'
+
+ // MANGLING-DAG: @"\01??_7Y@Test7@@6B@"
+};
+
+Y y;
+}
+
+namespace Test8 {
+
+// This is a typical diamond inheritance with a shared 'A' vbase.
+struct X : D, C {
+ // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entries).
+ // TEST8-X-NEXT: 0 | void D::h()
+
+ // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
+ // TEST8-X-NEXT: 0 | void Test8::X::f()
+ // TEST8-X-NEXT: 1 | void A::z()
+
+ // TEST8-X: VFTable indices for 'Test8::X' (1 entries).
+ // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0
+ // TEST8-X-NEXT: 0 | void Test8::X::f()
+
+ // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@"
+
+ virtual void f();
+};
+
+X x;
+
+// Another diamond inheritance which led to AST crashes.
+struct Y : virtual A {};
+
+class Z : Y, C {
+ // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries).
+ // TEST8-Z-NEXT: 0 | void Test8::Z::f()
+ // TEST8-Z-NEXT: 1 | void A::z()
+
+ // TEST8-Z: VFTable indices for 'Test8::Z' (1 entries).
+ // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0
+ // TEST8-Z-NEXT: 0 | void Test8::Z::f()
+ virtual void f();
+};
+Z z;
+}
+
+namespace Test9 {
+
+struct X : A { };
+
+struct Y : virtual X {
+ // TEST9-Y: VFTable for 'Test9::Y' (1 entries).
+ // TEST9-Y-NEXT: 0 | void Test9::Y::h()
+
+ // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
+ // TEST9-Y-NEXT: 0 | void A::f()
+ // TEST9-Y-NEXT: 1 | void A::z()
+
+ // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries).
+ // TEST9-Y-NEXT: 0 | void Test9::Y::h()
+
+ // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@"
+ // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@"
+
+ virtual void h();
+};
+
+Y y;
+
+struct Z : Y, virtual B {
+ // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries).
+ // TEST9-Z-NEXT: 0 | void Test9::Y::h()
+
+ // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
+ // TEST9-Z-NEXT: 0 | void A::f()
+ // TEST9-Z-NEXT: 1 | void A::z()
+
+ // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries).
+ // TEST9-Z-NEXT: 0 | void B::g()
+
+ // TEST9-Z-NOT: VFTable indices for 'Test9::Z'
+
+ // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@"
+ // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@"
+
+ // FIXME this one is wrong:
+ // INCORRECT MANGLING-DAG: @"\01??_7Z@Test9@@6BB@@@"
+ // MANGLING-DAG-SHOULD-BE: @"\01??_7Z@Test9@@6B@"
+};
+
+Z z;
+
+struct W : Z, D, virtual A, virtual B {
+ // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries).
+ // TEST9-W-NEXT: 0 | void Test9::Y::h()
+
+ // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
+ // TEST9-W-NEXT: 0 | void A::f()
+ // TEST9-W-NEXT: 1 | void A::z()
+
+ // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries).
+ // TEST9-W-NEXT: 0 | void B::g()
+
+ // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries).
+ // TEST9-W-NEXT: 0 | void D::h()
+
+ // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
+ // TEST9-W-NEXT: 0 | void D::f()
+ // TEST9-W-NEXT: [this adjustment: -8 non-virtual]
+ // TEST9-W-NEXT: 1 | void A::z()
+
+ // TEST9-W: Thunks for 'void D::f()' (1 entry).
+ // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // TEST9-W-NOT: VFTable indices for 'Test9::W'
+
+ // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@"
+ // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@"
+
+ // FIXME: these two are wrong:
+ // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BB@@@"
+ // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6B@"
+ // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@Z@1@@"
+ // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6BY@1@@"
+};
+
+W w;
+
+struct T : Z, D, virtual A, virtual B {
+ // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries).
+ // TEST9-T-NEXT: 0 | void Test9::T::h()
+
+ // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
+ // TEST9-T-NEXT: 0 | void Test9::T::f()
+ // TEST9-T-NEXT: 1 | void Test9::T::z()
+
+ // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries).
+ // TEST9-T-NEXT: 0 | void Test9::T::g()
+
+ // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries).
+ // TEST9-T-NEXT: 0 | void Test9::T::h()
+ // TEST9-T-NEXT: [this adjustment: -8 non-virtual]
+
+ // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
+ // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
+ // TEST9-T-NEXT: 0 | void Test9::T::f()
+ // TEST9-T-NEXT: [this adjustment: -8 non-virtual]
+ // TEST9-T-NEXT: 1 | void Test9::T::z()
+ // TEST9-T-NEXT: [this adjustment: -8 non-virtual]
+
+ // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
+ // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
+ // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // TEST9-T: VFTable indices for 'Test9::T' (4 entries).
+ // TEST9-T-NEXT: via vfptr at offset 0
+ // TEST9-T-NEXT: 0 | void Test9::T::h()
+ // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0
+ // TEST9-T-NEXT: 0 | void Test9::T::f()
+ // TEST9-T-NEXT: 1 | void Test9::T::z()
+ // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0
+ // TEST9-T-NEXT: 0 | void Test9::T::g()
+
+ // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@"
+ // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@"
+
+ // FIXME: these two are wrong:
+ // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BB@@@"
+ // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6B@"
+ // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@Z@1@@"
+ // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6BY@1@@"
+
+ virtual void f();
+ virtual void g();
+ virtual void h();
+ virtual void z();
+};
+
+T t;
+}
+
+namespace Test10 {
+struct X : virtual C, virtual A {
+ // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
+ // TEST10-NEXT: 0 | void Test10::X::f()
+ // TEST10-NEXT: 1 | void A::z()
+
+ // TEST10: VFTable indices for 'Test10::X' (1 entries).
+ // TEST10-NEXT: via vbtable index 1, vfptr at offset 0
+ // TEST10-NEXT: 0 | void Test10::X::f()
+ virtual void f();
+};
+
+void X::f() {}
+X x;
+}
+
+namespace vdtors {
+struct X {
+ virtual ~X();
+ virtual void zzz();
+};
+
+struct Y : virtual X {
+ // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries).
+ // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting]
+ // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz()
+
+ // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()'
+ virtual ~Y();
+};
+
+Y y;
+
+struct Z {
+ virtual void z();
+};
+
+struct W : Z, X {
+ // Implicit virtual dtor.
+};
+
+struct U : virtual W {
+ // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entries).
+ // VDTORS-U-NEXT: 0 | void vdtors::Z::z()
+
+ // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries).
+ // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting]
+ // VDTORS-U-NEXT: [this adjustment: -4 non-virtual]
+ // VDTORS-U-NEXT: 1 | void vdtors::X::zzz()
+
+ // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry).
+ // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTORS-U: VFTable indices for 'vdtors::U' (1 entries).
+ // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
+ // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting]
+ virtual ~U();
+};
+
+U u;
+
+struct V : virtual W {
+ // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries).
+ // VDTORS-V-NEXT: 0 | void vdtors::Z::z()
+
+ // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries).
+ // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting]
+ // VDTORS-V-NEXT: [this adjustment: -4 non-virtual]
+ // VDTORS-V-NEXT: 1 | void vdtors::X::zzz()
+
+ // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry).
+ // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // VDTORS-V: VFTable indices for 'vdtors::V' (1 entries).
+ // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
+ // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting]
+};
+
+V v;
+
+struct T : virtual X {
+ virtual ~T();
+};
+
+struct P : T, Y {
+ // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries).
+ // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting]
+ // VDTORS-P-NEXT: 1 | void vdtors::X::zzz()
+
+ // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()'
+ virtual ~P();
+};
+
+P p;
+
+}
+
+namespace return_adjustment {
+
+struct X : virtual A {
+ virtual void f();
+};
+
+struct Y : virtual A, virtual X {
+ virtual void f();
+};
+
+struct Z {
+ virtual A* foo();
+};
+
+struct W : Z {
+ // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
+ // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
+ // RET-W-NEXT: [return adjustment: vbase #1, 0 non-virtual]
+ // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
+
+ // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
+ // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
+
+ virtual X* foo();
+};
+
+W y;
+
+struct T : W {
+ // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
+ // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
+ // RET-T-NEXT: [return adjustment: vbase #1, 0 non-virtual]
+ // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
+ // RET-T-NEXT: [return adjustment: vbase #2, 0 non-virtual]
+ // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
+
+ // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
+ // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
+
+ virtual Y* foo();
+};
+
+T t;
+
+struct U : virtual A {
+ virtual void g(); // adds a vfptr
+};
+
+struct V : Z {
+ // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).
+ // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo()
+ // RET-V-NEXT: [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual]
+ // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
+
+ // RET-V: VFTable indices for 'return_adjustment::V' (1 entries).
+ // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
+
+ virtual U* foo();
+};
+
+V v;
+}
diff --git a/test/CodeGenCXX/microsoft-interface.cpp b/test/CodeGenCXX/microsoft-interface.cpp
index 0b44bab73854..419075a86303 100644
--- a/test/CodeGenCXX/microsoft-interface.cpp
+++ b/test/CodeGenCXX/microsoft-interface.cpp
@@ -19,25 +19,25 @@ int fn() {
// CHECK: @_ZTV1S = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1S to i8*), i8* bitcast (i32 (%struct.S*)* @_ZN1S4testEv to i8*)]
-// CHECK: define i32 @_Z2fnv()
+// CHECK-LABEL: define i32 @_Z2fnv()
// CHECK: call void @_ZN1SC1Ev(%struct.S* %s)
// CHECK: %{{[.0-9A-Z_a-z]+}} = call i32 @_ZN1S4testEv(%struct.S* %s)
-// CHECK: define linkonce_odr void @_ZN1SC1Ev(%struct.S* %this)
+// CHECK-LABEL: define linkonce_odr void @_ZN1SC1Ev(%struct.S* %this)
// CHECK: call void @_ZN1SC2Ev(%struct.S* %{{[.0-9A-Z_a-z]+}})
-// CHECK: define linkonce_odr i32 @_ZN1S4testEv(%struct.S* %this)
+// CHECK-LABEL: define linkonce_odr i32 @_ZN1S4testEv(%struct.S* %this)
// CHECK: %{{[.0-9A-Z_a-z]+}} = call i32 @_ZN1I4testEv(%__interface.I* %{{[.0-9A-Z_a-z]+}})
-// CHECK: define linkonce_odr i32 @_ZN1I4testEv(%__interface.I* %this)
+// CHECK-LABEL: define linkonce_odr i32 @_ZN1I4testEv(%__interface.I* %this)
// CHECK: ret i32 1
-// CHECK: define linkonce_odr void @_ZN1SC2Ev(%struct.S* %this)
+// CHECK-LABEL: define linkonce_odr void @_ZN1SC2Ev(%struct.S* %this)
// CHECK: call void @_ZN1IC2Ev(%__interface.I* %{{[.0-9A-Z_a-z]+}})
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1S, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}}
-// CHECK: define linkonce_odr void @_ZN1IC2Ev(%__interface.I* %this)
+// CHECK-LABEL: define linkonce_odr void @_ZN1IC2Ev(%__interface.I* %this)
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1I, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}}
-// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSERKS_(%__interface.I* %this, %__interface.I*)
-// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSEOS_(%__interface.I* %this, %__interface.I*)
+// CHECK-NOT-LABEL: define linkonce_odr %__interface.I* @_ZN1IaSERKS_(%__interface.I* %this, %__interface.I*)
+// CHECK-NOT-LABEL: define linkonce_odr %__interface.I* @_ZN1IaSEOS_(%__interface.I* %this, %__interface.I*)
diff --git a/test/CodeGenCXX/microsoft-new.cpp b/test/CodeGenCXX/microsoft-new.cpp
new file mode 100644
index 000000000000..48e93d4aa0f8
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-new.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -fms-compatibility %s -emit-llvm -o - | FileCheck %s
+
+#include <stddef.h>
+
+struct arbitrary_t {} arbitrary;
+void *operator new(size_t size, arbitrary_t);
+
+struct arbitrary2_t {} arbitrary2;
+void *operator new[](size_t size, arbitrary2_t);
+
+namespace PR13164 {
+ void f() {
+ // MSVC will fall back on the non-array operator new.
+ void *a;
+ int *p = new(arbitrary) int[4];
+ // CHECK: call i8* @_Znwj11arbitrary_t(i32 16, %struct.arbitrary_t*
+ }
+
+ struct S {
+ void *operator new[](size_t size, arbitrary_t);
+ };
+
+ void g() {
+ S *s = new(arbitrary) S[2];
+ // CHECK: call i8* @_ZN7PR131641SnaEj11arbitrary_t(i32 2, %struct.arbitrary_t*
+ S *s1 = new(arbitrary) S;
+ // CHECK: call i8* @_Znwj11arbitrary_t(i32 1, %struct.arbitrary_t*
+ }
+
+ struct T {
+ void *operator new(size_t size, arbitrary2_t);
+ };
+
+ void h() {
+ // This should still call the global operator new[].
+ T *t = new(arbitrary2) T[2];
+ // CHECK: call i8* @_Znaj12arbitrary2_t(i32 2, %struct.arbitrary2_t*
+ }
+}
diff --git a/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp b/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
deleted file mode 100644
index 4f68aa34772c..000000000000
--- a/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-macosx10.8.0 -fms-extensions -verify
-
-typedef struct _GUID
-{
- unsigned long Data1;
- unsigned short Data2;
- unsigned short Data3;
- unsigned char Data4[8];
-} GUID;
-
-struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S { };
-
-GUID g = __uuidof(S); // expected-error {{__uuidof codegen is not supported on this architecture}}
diff --git a/test/CodeGenCXX/microsoft-uuidof.cpp b/test/CodeGenCXX/microsoft-uuidof.cpp
index 8eeb4490ac11..ab3d9b64c6f8 100644
--- a/test/CodeGenCXX/microsoft-uuidof.cpp
+++ b/test/CodeGenCXX/microsoft-uuidof.cpp
@@ -1,72 +1,112 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID
-typedef struct _GUID
-{
+#ifdef DEFINE_GUID
+struct _GUID {
+#ifdef WRONG_GUID
+ unsigned int SomethingWentWrong;
+#else
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
-} GUID;
+#endif
+};
+#endif
+typedef struct _GUID GUID;
-struct __declspec(uuid("12345678-1234-1234-1234-1234567890ab")) S1 { } s1;
+struct __declspec(uuid("12345678-1234-1234-1234-1234567890aB")) S1 { } s1;
struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { };
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
+
+#ifdef DEFINE_GUID
+// Make sure we can properly generate code when the UUID has curly braces on it.
+GUID thing = __uuidof(Curly);
+// CHECK-DEFINE-GUID: @thing = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-WRONG-GUID: @thing = global %struct._GUID zeroinitializer, align 4
// This gets initialized in a static initializer.
-// CHECK: @g = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-GUID: @g = global %struct._GUID zeroinitializer, align 4
+// CHECK-DEFINE-WRONG-GUID: @g = global %struct._GUID zeroinitializer, align 4
GUID g = __uuidof(S1);
+#endif
// First global use of __uuidof(S1) forces the creation of the global.
-// CHECK: @__uuid_12345678-1234-1234-1234-1234567890ab = private unnamed_addr constant %struct._GUID { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" }
-// CHECK: @gr = constant %struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab, align 4
+// CHECK: @_GUID_12345678_1234_1234_1234_1234567890ab = linkonce_odr constant { i32, i16, i16, [8 x i8] } { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" }
+// CHECK: @gr = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4
const GUID& gr = __uuidof(S1);
-// CHECK: @gp = global %struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab, align 4
+// CHECK: @gp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4
const GUID* gp = &__uuidof(S1);
+// CHECK: @cp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to %struct._GUID*), align 4
+const GUID* cp = &__uuidof(Curly);
+
// Special case: _uuidof(0)
-// CHECK: @zeroiid = constant %struct._GUID* @__uuid_00000000-0000-0000-0000-000000000000, align 4
+// CHECK: @zeroiid = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), align 4
const GUID& zeroiid = __uuidof(0);
// __uuidof(S2) hasn't been used globally yet, so it's emitted when it's used
// in a function and is emitted at the end of the globals section.
-// CHECK: @__uuid_87654321-4321-4321-4321-ba0987654321 = private unnamed_addr constant %struct._GUID { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" }
+// CHECK: @_GUID_87654321_4321_4321_4321_ba0987654321 = linkonce_odr constant { i32, i16, i16, [8 x i8] } { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" }
+
+// The static initializer for thing.
+// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 4, i32 4, i1 false)
// The static initializer for g.
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
+#ifdef DEFINE_GUID
void fun() {
- // CHECK: %s1_1 = alloca %struct._GUID, align 4
- // CHECK: %s1_2 = alloca %struct._GUID, align 4
- // CHECK: %s1_3 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-GUID: %s1_1 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-WRONG-GUID: %s1_1 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-GUID: %s1_2 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-WRONG-GUID: %s1_2 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-GUID: %s1_3 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-WRONG-GUID: %s1_3 = alloca %struct._GUID, align 4
- // CHECK: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
- // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
+ // CHECK-DEFINE-WRONG-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8*
+ // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
GUID s1_1 = __uuidof(S1);
- // CHECK: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
- // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
+ // CHECK-DEFINE-WRONG-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8*
+ // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
GUID s1_2 = __uuidof(S1);
- // CHECK: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
- // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
+ // CHECK-DEFINE-WRONG-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8*
+ // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false)
+ // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false)
GUID s1_3 = __uuidof(s1);
}
+#endif
void gun() {
- // CHECK: %s2_1 = alloca %struct._GUID, align 4
- // CHECK: %s2_2 = alloca %struct._GUID, align 4
+#ifdef DEFINE_GUID
+ // CHECK-DEFINE-GUID: %s2_1 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-WRONG-GUID: %s2_1 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-GUID: %s2_2 = alloca %struct._GUID, align 4
+ // CHECK-DEFINE-WRONG-GUID: %s2_2 = alloca %struct._GUID, align 4
+ GUID s2_1 = __uuidof(S2);
+ GUID s2_2 = __uuidof(S2);
+#endif
// CHECK: %r = alloca %struct._GUID*, align 4
// CHECK: %p = alloca %struct._GUID*, align 4
// CHECK: %zeroiid = alloca %struct._GUID*, align 4
- GUID s2_1 = __uuidof(S2);
- GUID s2_2 = __uuidof(S2);
- // CHECK: store %struct._GUID* @__uuid_87654321-4321-4321-4321-ba0987654321, %struct._GUID** %r, align 4
+ // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %r, align 4
const GUID& r = __uuidof(S2);
- // CHECK: store %struct._GUID* @__uuid_87654321-4321-4321-4321-ba0987654321, %struct._GUID** %p, align 4
+ // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %p, align 4
const GUID* p = &__uuidof(S2);
// Special case _uuidof(0), local scope version.
- // CHECK: store %struct._GUID* @__uuid_00000000-0000-0000-0000-000000000000, %struct._GUID** %zeroiid, align 4
+ // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), %struct._GUID** %zeroiid, align 4
const GUID& zeroiid = __uuidof(0);
}
diff --git a/test/CodeGenCXX/move-assignment.cpp b/test/CodeGenCXX/move-assignment.cpp
new file mode 100644
index 000000000000..3653eab6b7da
--- /dev/null
+++ b/test/CodeGenCXX/move-assignment.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -o - %s -triple x86_64-pc-linux-gnu | FileCheck %s
+
+struct A {
+ A &operator=(A&&);
+};
+
+struct B {
+ A a;
+ int i;
+ bool b;
+ char c;
+ long l;
+ float f;
+};
+
+void test1() {
+ B b1, b2;
+ b1 = static_cast<B&&>(b2);
+}
+
+// CHECK-LABEL: define {{.*}} @_ZN1BaSEOS_
+// CHECK: call {{.*}} @_ZN1AaSEOS_
+// CHECK-NOT: store
+// CHECK: call {{.*}}memcpy{{.*}}, i64 24
+// CHECK-NOT: store
+// CHECK: ret
diff --git a/test/CodeGenCXX/ms-integer-static-data-members.cpp b/test/CodeGenCXX/ms-integer-static-data-members.cpp
new file mode 100644
index 000000000000..00beaa62f190
--- /dev/null
+++ b/test/CodeGenCXX/ms-integer-static-data-members.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -DINLINE_INIT -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE
+// RUN: %clang_cc1 -DREAL_DEFINITION -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-OUTOFLINE
+// RUN: %clang_cc1 -DINLINE_INIT -DREAL_DEFINITION -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE
+
+struct S {
+ // For MS ABI, we emit a linkonce_odr definition here, even though it's really just a declaration.
+#ifdef INLINE_INIT
+ static const int x = 5;
+#else
+ static const int x;
+#endif
+};
+
+const int *f() {
+ return &S::x;
+};
+
+#ifdef REAL_DEFINITION
+#ifdef INLINE_INIT
+const int S::x;
+#else
+const int S::x = 5;
+#endif
+#endif
+
+
+// Inline initialization.
+// CHECK-INLINE: @"\01?x@S@@2HB" = linkonce_odr constant i32 5, align 4
+
+// Out-of-line initialization.
+// CHECK-OUTOFLINE: @"\01?x@S@@2HB" = constant i32 5, align 4
+
+// No initialization.
+// CHECK: @"\01?x@S@@2HB" = external constant i32
diff --git a/test/CodeGenCXX/new-alias.cpp b/test/CodeGenCXX/new-alias.cpp
new file mode 100644
index 000000000000..7ddc1f988086
--- /dev/null
+++ b/test/CodeGenCXX/new-alias.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -std=c++11 -o - %s | FileCheck %s
+
+using size_t = decltype(sizeof(0));
+
+extern "C" char *something(long long x) {
+}
+
+// CHECK: @_Znwm = alias i8* (i64)* @something
+void *operator new(size_t) __attribute__((alias("something")));
+
+// PR16715: don't assert here.
+// CHECK: call noalias i8* @_Znwm(i64 4){{$}}
+int *pr16715 = new int;
diff --git a/test/CodeGenCXX/new-array-init-exceptions.cpp b/test/CodeGenCXX/new-array-init-exceptions.cpp
index 5d9cc9fa636d..5cfb75744d54 100644
--- a/test/CodeGenCXX/new-array-init-exceptions.cpp
+++ b/test/CodeGenCXX/new-array-init-exceptions.cpp
@@ -7,7 +7,7 @@ struct Throws {
~Throws();
};
-// CHECK: define void @_Z7cleanupi
+// CHECK-LABEL: define void @_Z7cleanupi
void cleanup(int n) {
// CHECK: invoke void @_ZN6ThrowsC1Ei
// CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD:[^ ]+]]
@@ -25,7 +25,7 @@ void cleanup(int n) {
}
-// CHECK: define void @_Z7cleanupv
+// CHECK-LABEL: define void @_Z7cleanupv
void cleanup() {
// CHECK: invoke void @_ZN6ThrowsC1Ei
// CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2:[^ ]+]]
diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp
index 231df24781ae..0e925c0a67eb 100644
--- a/test/CodeGenCXX/new-array-init.cpp
+++ b/test/CodeGenCXX/new-array-init.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
-// CHECK: define void @_Z2fni
+// CHECK-LABEL: define void @_Z2fni
void fn(int n) {
// CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3
// CHECK: store i32 1
@@ -11,21 +11,21 @@ void fn(int n) {
new int[n] { 1, 2, 3 };
}
-// CHECK: define void @_Z15const_underflowv
+// CHECK-LABEL: define void @_Z15const_underflowv
void const_underflow() {
// CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
// CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1)
new int[2] { 1, 2, 3 };
}
-// CHECK: define void @_Z11const_exactv
+// CHECK-LABEL: define void @_Z11const_exactv
void const_exact() {
// CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
// CHECK-NOT: icmp eq i32*
new int[3] { 1, 2, 3 };
}
-// CHECK: define void @_Z16const_sufficientv
+// CHECK-LABEL: define void @_Z16const_sufficientv
void const_sufficient() {
// CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
new int[4] { 1, 2, 3 };
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index e0523909a3db..91da77a0838a 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -2,9 +2,24 @@
typedef __typeof__(sizeof(0)) size_t;
+// Ensure that this declaration doesn't cause operator new to lose its
+// 'noalias' attribute.
+void *operator new[](size_t);
+
void t1() {
- int* a = new int;
+ delete new int;
+ delete [] new int [3];
+}
+
+// CHECK: declare noalias i8* @_Znwm(i64) [[ATTR_NOBUILTIN:#[^ ]*]]
+// CHECK: declare void @_ZdlPv(i8*) [[ATTR_NOBUILTIN_NOUNWIND:#[^ ]*]]
+// CHECK: declare noalias i8* @_Znam(i64) [[ATTR_NOBUILTIN]]
+// CHECK: declare void @_ZdaPv(i8*) [[ATTR_NOBUILTIN_NOUNWIND]]
+
+namespace std {
+ struct nothrow_t {};
}
+std::nothrow_t nothrow;
// Declare the reserved placement operators.
void *operator new(size_t, void*) throw();
@@ -12,6 +27,13 @@ void operator delete(void*, void*) throw();
void *operator new[](size_t, void*) throw();
void operator delete[](void*, void*) throw();
+// Declare the replaceable global allocation operators.
+void *operator new(size_t, const std::nothrow_t &) throw();
+void *operator new[](size_t, const std::nothrow_t &) throw();
+void operator delete(void *, const std::nothrow_t &) throw();
+void operator delete[](void *, const std::nothrow_t &) throw();
+
+
void t2(int* a) {
int* b = new (a) int;
}
@@ -77,10 +99,6 @@ void t8(int n) {
new U[n];
}
-// noalias
-// CHECK: declare noalias i8* @_Znam
-void *operator new[](size_t);
-
void t9() {
bool b;
@@ -98,7 +116,7 @@ A* t10() {
return new(1, 2, 3.45, 100) A;
}
-// CHECK: define void @_Z3t11i
+// CHECK-LABEL: define void @_Z3t11i
struct B { int a; };
struct Bmemptr { int Bmemptr::* memptr; int a; };
@@ -122,7 +140,7 @@ void t11(int n) {
struct Empty { };
// We don't need to initialize an empty class.
-// CHECK: define void @_Z3t12v
+// CHECK-LABEL: define void @_Z3t12v
void t12() {
// CHECK: call noalias i8* @_Znam
// CHECK-NOT: br
@@ -136,7 +154,7 @@ void t12() {
}
// Zero-initialization
-// CHECK: define void @_Z3t13i
+// CHECK-LABEL: define void @_Z3t13i
void t13(int n) {
// CHECK: call noalias i8* @_Znwm
// CHECK: store i32 0, i32*
@@ -171,7 +189,7 @@ void f() {
namespace test15 {
struct A { A(); ~A(); };
- // CHECK: define void @_ZN6test155test0EPv(
+ // CHECK-LABEL: define void @_ZN6test155test0EPv(
// CHECK: [[P:%.*]] = load i8*
// CHECK-NEXT: icmp eq i8* [[P]], null
// CHECK-NEXT: br i1
@@ -181,7 +199,7 @@ namespace test15 {
new (p) A();
}
- // CHECK: define void @_ZN6test155test1EPv(
+ // CHECK-LABEL: define void @_ZN6test155test1EPv(
// CHECK: [[P:%.*]] = load i8**
// CHECK-NEXT: icmp eq i8* [[P]], null
// CHECK-NEXT: br i1
@@ -199,7 +217,7 @@ namespace test15 {
// TODO: it's okay if all these size calculations get dropped.
// FIXME: maybe we should try to throw on overflow?
- // CHECK: define void @_ZN6test155test2EPvi(
+ // CHECK-LABEL: define void @_ZN6test155test2EPvi(
// CHECK: [[N:%.*]] = load i32*
// CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64
// CHECK-NEXT: [[T1:%.*]] = icmp slt i64 [[T0]], 0
@@ -220,7 +238,7 @@ namespace test15 {
}
namespace PR10197 {
- // CHECK: define weak_odr void @_ZN7PR101971fIiEEvv()
+ // CHECK-LABEL: define weak_odr void @_ZN7PR101971fIiEEvv()
template<typename T>
void f() {
// CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm
@@ -235,7 +253,7 @@ namespace PR10197 {
namespace PR11523 {
class MyClass;
typedef int MyClass::* NewTy;
- // CHECK: define i64* @_ZN7PR115231fEv
+ // CHECK-LABEL: define i64* @_ZN7PR115231fEv
// CHECK: store i64 -1
NewTy* f() { return new NewTy[2](); }
}
@@ -254,9 +272,69 @@ namespace PR11757 {
namespace PR13380 {
struct A { A() {} };
struct B : public A { int x; };
- // CHECK: define i8* @_ZN7PR133801fEv
+ // CHECK-LABEL: define i8* @_ZN7PR133801fEv
// CHECK: call noalias i8* @_Znam(
// CHECK: call void @llvm.memset.p0i8
// CHECK-NEXT: call void @_ZN7PR133801BC1Ev
void* f() { return new B[2](); }
}
+
+struct MyPlacementType {} mpt;
+void *operator new(size_t, MyPlacementType);
+
+namespace N3664 {
+ struct S { S() throw(int); };
+
+ // CHECK-LABEL-LABEL: define void @_ZN5N36641fEv
+ void f() {
+ // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]]
+ int *p = new int;
+ // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]]
+ delete p;
+
+ // CHECK: call noalias i8* @_Znam(i64 12) [[ATTR_BUILTIN_NEW]]
+ int *q = new int[3];
+ // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_BUILTIN_DELETE]]
+ delete [] p;
+
+ // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]]
+ (void) new (nothrow) S[3];
+
+ // CHECK: call i8* @_Znwm15MyPlacementType(i64 4){{$}}
+ (void) new (mpt) int;
+ }
+
+ // FIXME: Can we mark this noalias?
+ // CHECK: declare i8* @_ZnamRKSt9nothrow_t(i64, {{.*}}) [[ATTR_NOBUILTIN_NOUNWIND]]
+
+ // CHECK-LABEL-LABEL: define void @_ZN5N36641gEv
+ void g() {
+ // It's OK for there to be attributes here, so long as we don't have a
+ // 'builtin' attribute.
+ // CHECK: call noalias i8* @_Znwm(i64 4){{$}}
+ int *p = (int*)operator new(4);
+ // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_NOUNWIND:#[^ ]*]]
+ operator delete(p);
+
+ // CHECK: call noalias i8* @_Znam(i64 12){{$}}
+ int *q = (int*)operator new[](12);
+ // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_NOUNWIND]]
+ operator delete [](p);
+
+ // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_NOUNWIND]]
+ (void) operator new[](3, nothrow);
+ }
+}
+
+// CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = {{[{].*}} nobuiltin {{.*[}]}}
+// CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOUNWIND]] = {{[{].*}} nobuiltin nounwind {{.*[}]}}
+
+// CHECK: attributes [[ATTR_NOUNWIND]] =
+// CHECK-NOT: builtin
+// CHECK-NOT: attributes
+// CHECK: nounwind
+// CHECK-NOT: builtin
+// CHECK: attributes
+
+// CHECK-DAG: attributes [[ATTR_BUILTIN_NEW]] = {{[{].*}} builtin {{.*[}]}}
+// CHECK-DAG: attributes [[ATTR_BUILTIN_DELETE]] = {{[{].*}} builtin {{.*[}]}}
diff --git a/test/CodeGenCXX/no-opt-volatile-memcpy.cpp b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp
index e542e4a9348c..d1e2e1d62190 100644
--- a/test/CodeGenCXX/no-opt-volatile-memcpy.cpp
+++ b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
// rdar://11861085
struct s {
@@ -14,7 +14,7 @@ void foo (void) {
gs = gs;
ls = gs;
}
-// CHECK: define void @_Z3foov()
+// CHECK-LABEL: define void @_Z3foov()
// CHECK: %[[LS:.*]] = alloca %struct.s, align 4
// CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8*
// CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8*
@@ -34,7 +34,7 @@ void fee (void) {
s = s;
s.y = gs;
}
-// CHECK: define void @_Z3feev()
+// CHECK-LABEL: define void @_Z3feev()
// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
@@ -46,5 +46,5 @@ d gd;
void gorf(void) {
gd = gd;
}
-// CHECK: define void @_Z4gorfv()
+// CHECK-LABEL: define void @_Z4gorfv()
// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
diff --git a/test/CodeGenCXX/noexcept.cpp b/test/CodeGenCXX/noexcept.cpp
new file mode 100644
index 000000000000..dd4cfda1d896
--- /dev/null
+++ b/test/CodeGenCXX/noexcept.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions -std=c++11 | FileCheck %s
+
+// rdar://11904428
+// Ensure that we call __cxa_begin_catch before calling
+// std::terminate in a noexcept function.
+namespace test0 {
+ void foo();
+
+ struct A {
+ A();
+ ~A();
+ };
+
+ void test() noexcept {
+ A a;
+ foo();
+ }
+}
+// CHECK-LABEL: define void @_ZN5test04testEv()
+// CHECK: [[EXN:%.*]] = alloca i8*
+// This goes to the terminate lpad.
+// CHECK: invoke void @_ZN5test01AC1Ev(
+// This goes to the cleanup-and-then-terminate lpad.
+// CHECK: invoke void @_ZN5test03fooEv()
+// Destructors don't throw by default in C++11.
+// CHECK: call void @_ZN5test01AD1Ev(
+// Cleanup lpad.
+// CHECK: [[T0:%.*]] = landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
+// CHECK-NEXT: store i8* [[T1]], i8** [[EXN]]
+// (Calling this destructor is not technically required.)
+// CHECK: call void @_ZN5test01AD1Ev(
+// CHECK-NEXT: br label
+// The terminate landing pad jumps in here for some reason.
+// CHECK: [[T0:%.*]] = landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
+// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T1]])
+// CHECK-NEXT: unreachable
+// The terminate handler chained to by the cleanup lpad.
+// CHECK: [[T0:%.*]] = load i8** [[EXN]]
+// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T0]])
+// CHECK-NEXT: unreachable
+
+// CHECK-LABEL: define linkonce_odr hidden void @__clang_call_terminate(
+// CHECK: call i8* @__cxa_begin_catch(
+// CHECK-NEXT: call void @_ZSt9terminatev()
+// CHECK-NEXT: unreachable
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 747ab6db63eb..b83dd727e0bb 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -9,8 +9,8 @@ public:
~X();
};
-// CHECK: define void @_Z5test0v
-// CHECK-EH: define void @_Z5test0v
+// CHECK-LABEL: define void @_Z5test0v
+// CHECK-EH-LABEL: define void @_Z5test0v
X test0() {
X x;
// CHECK: call {{.*}} @_ZN1XC1Ev
@@ -21,8 +21,8 @@ X test0() {
return x;
}
-// CHECK: define void @_Z5test1b(
-// CHECK-EH: define void @_Z5test1b(
+// CHECK-LABEL: define void @_Z5test1b(
+// CHECK-EH-LABEL: define void @_Z5test1b(
X test1(bool B) {
// CHECK: tail call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret void
@@ -34,8 +34,8 @@ X test1(bool B) {
// CHECK-EH-NEXT: ret void
}
-// CHECK: define void @_Z5test2b
-// CHECK-EH: define void @_Z5test2b
+// CHECK-LABEL: define void @_Z5test2b
+// CHECK-EH-LABEL: define void @_Z5test2b
X test2(bool B) {
// No NRVO.
@@ -120,7 +120,7 @@ X test3(bool B) {
extern "C" void exit(int) throw();
-// CHECK: define void @_Z5test4b
+// CHECK-LABEL: define void @_Z5test4b
X test4(bool B) {
{
// CHECK: tail call {{.*}} @_ZN1XC1Ev
@@ -135,7 +135,7 @@ X test4(bool B) {
}
#ifdef __EXCEPTIONS
-// CHECK-EH: define void @_Z5test5
+// CHECK-EH-LABEL: define void @_Z5test5
void may_throw();
X test5() {
try {
@@ -150,7 +150,7 @@ X test5() {
#endif
// rdar://problem/10430868
-// CHECK: define void @_Z5test6v
+// CHECK-LABEL: define void @_Z5test6v
X test6() {
X a __attribute__((aligned(8)));
return a;
diff --git a/test/CodeGenCXX/override-layout.cpp b/test/CodeGenCXX/override-layout.cpp
index aba4c9179a6d..418c4ffab633 100644
--- a/test/CodeGenCXX/override-layout.cpp
+++ b/test/CodeGenCXX/override-layout.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fdump-record-layouts-simple %s 2> %t.layouts
-// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1
-// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.layouts
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before
+// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after
// RUN: diff -u %t.before %t.after
// RUN: FileCheck %s < %t.after
diff --git a/test/CodeGenCXX/partial-destruction.cpp b/test/CodeGenCXX/partial-destruction.cpp
index f232a159eda5..22daebe47baa 100644
--- a/test/CodeGenCXX/partial-destruction.cpp
+++ b/test/CodeGenCXX/partial-destruction.cpp
@@ -11,7 +11,7 @@ namespace test0 {
A as[10] = { 5, 7 };
opaque();
}
- // CHECK: define void @_ZN5test04testEv()
+ // CHECK-LABEL: define void @_ZN5test04testEv()
// CHECK: [[AS:%.*]] = alloca [10 x [[A:%.*]]], align
// CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]*
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
@@ -98,7 +98,7 @@ namespace test1 {
void test() {
B v = { 5, 6, 7, 8 };
}
- // CHECK: define void @_ZN5test14testEv()
+ // CHECK-LABEL: define void @_ZN5test14testEv()
// CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
@@ -128,7 +128,7 @@ namespace test2 {
void test() {
A v[4][7];
- // CHECK: define void @_ZN5test24testEv()
+ // CHECK-LABEL: define void @_ZN5test24testEv()
// CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
diff --git a/test/CodeGenCXX/pod-member-memcpys.cpp b/test/CodeGenCXX/pod-member-memcpys.cpp
index 534d5d19e99a..5c79568c2ace 100644
--- a/test/CodeGenCXX/pod-member-memcpys.cpp
+++ b/test/CodeGenCXX/pod-member-memcpys.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++03 -fexceptions -fcxx-exceptions -O1 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -std=c++03 -O0 -o - %s | FileCheck --check-prefix=CHECK-2 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++03 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -std=c++03 -o - %s | FileCheck --check-prefix=CHECK-2 %s
struct POD {
int w, x, y, z;
@@ -108,61 +108,61 @@ CALL_AO(InnerClassMember)
CALL_AO(PackedMembers)
// Basic copy-assignment:
-// CHECK: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: ret %struct.Basic* %this
+// CHECK-LABEL: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.Basic*
// PODMember copy-assignment:
-// CHECK: define linkonce_odr %struct.PODMember* @_ZN9PODMemberaSERKS_(%struct.PODMember* %this, %struct.PODMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: ret %struct.PODMember* %this
+// CHECK-LABEL: define linkonce_odr %struct.PODMember* @_ZN9PODMemberaSERKS_(%struct.PODMember* %this, %struct.PODMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.PODMember*
// PODLikeMember copy-assignment:
-// CHECK: define linkonce_odr %struct.PODLikeMember* @_ZN13PODLikeMemberaSERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: ret %struct.PODLikeMember* %this
+// CHECK-LABEL: define linkonce_odr %struct.PODLikeMember* @_ZN13PODLikeMemberaSERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.PODLikeMember*
// ArrayMember copy-assignment:
-// CHECK: define linkonce_odr %struct.ArrayMember* @_ZN11ArrayMemberaSERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
-// CHECK: ret %struct.ArrayMember* %this
+// CHECK-LABEL: define linkonce_odr %struct.ArrayMember* @_ZN11ArrayMemberaSERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: ret %struct.ArrayMember*
// VolatileMember copy-assignment:
-// CHECK: define linkonce_odr %struct.VolatileMember* @_ZN14VolatileMemberaSERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr %struct.VolatileMember* @_ZN14VolatileMemberaSERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: load volatile i32* {{.*}}, align 4
// CHECK: store volatile i32 {{.*}}, align 4
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: ret %struct.VolatileMember* %this
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.VolatileMember*
// BitfieldMember copy-assignment:
-// CHECK: define linkonce_odr %struct.BitfieldMember* @_ZN14BitfieldMemberaSERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
-// CHECK: ret %struct.BitfieldMember* %this
+// CHECK-LABEL: define linkonce_odr %struct.BitfieldMember* @_ZN14BitfieldMemberaSERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
+// CHECK: ret %struct.BitfieldMember*
// InnerClass copy-assignment:
-// CHECK: define linkonce_odr %struct.InnerClassMember* @_ZN16InnerClassMemberaSERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: ret %struct.InnerClassMember* %this
+// CHECK-LABEL: define linkonce_odr %struct.InnerClassMember* @_ZN16InnerClassMemberaSERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.InnerClassMember*
// PackedMembers copy-assignment:
-// CHECK: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
-// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
-// CHECK: ret %struct.PackedMembers* %this
+// CHECK-LABEL: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK: ret %struct.PackedMembers*
// COPY-CONSTRUCTORS:
@@ -184,73 +184,73 @@ CALL_CC(PODMember)
CALL_CC(Basic)
// Basic copy-constructor:
-// CHECK: define linkonce_odr void @_ZN5BasicC2ERKS_(%struct.Basic* %this, %struct.Basic*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN5BasicC2ERKS_(%struct.Basic* %this, %struct.Basic*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret void
// PODMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN9PODMemberC2ERKS_(%struct.PODMember* %this, %struct.PODMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN9PODMemberC2ERKS_(%struct.PODMember* %this, %struct.PODMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret void
// PODLikeMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN13PODLikeMemberC2ERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN13PODLikeMemberC2ERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
// CHECK: invoke void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret void
// CHECK: landingpad
// CHECK: invoke void @_ZN7PODLikeD1Ev
// ArrayMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN11ArrayMemberC2ERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN11ArrayMemberC2ERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
// CHECK: ret void
// VolatileMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN14VolatileMemberC2ERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN14VolatileMemberC2ERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: load volatile i32* {{.*}}, align 4
// CHECK: store volatile i32 {{.*}}, align 4
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret void
// BitfieldMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN14BitfieldMemberC2ERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN14BitfieldMemberC2ERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
// CHECK: ret void
// InnerClass copy-constructor:
-// CHECK: define linkonce_odr void @_ZN16InnerClassMemberC2ERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN16InnerClassMemberC2ERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret void
// ReferenceMember copy-constructor:
-// CHECK: define linkonce_odr void @_ZN15ReferenceMemberC2ERKS_(%struct.ReferenceMember* %this, %struct.ReferenceMember*)
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN15ReferenceMemberC2ERKS_(%struct.ReferenceMember* %this, %struct.ReferenceMember*)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
// CHECK: ret void
// BitfieldMember2 copy-constructor:
-// CHECK-2: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2*)
+// CHECK-2-LABEL: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2*)
// CHECK-2: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4, i1 false)
// CHECK-2: call void @_ZN6NonPODC1ERKS_
// CHECK-2: ret void
// PackedMembers copy-assignment:
-// CHECK: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
-// CHECK: tail call void @_ZN6NonPODC1ERKS_
-// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK-LABEL: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: call void @_ZN6NonPODC1ERKS_
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
// CHECK: ret void
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 7335c97dd975..f0199c851dcd 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -124,7 +124,7 @@ struct A {
A();
};
-// CHECK: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr
// CHECK: store i64 -1, i64*
// CHECK: ret void
A::A() : a() {}
@@ -202,7 +202,7 @@ namespace BoolPtrToMember {
bool member;
};
- // CHECK: define i8* @_ZN15BoolPtrToMember1fERNS_1XEMS0_b
+ // CHECK-LABEL: define i8* @_ZN15BoolPtrToMember1fERNS_1XEMS0_b
bool &f(X &x, bool X::*member) {
// CHECK: {{bitcast.* to i8\*}}
// CHECK-NEXT: getelementptr inbounds i8*
@@ -249,7 +249,7 @@ namespace PR13097 {
};
A f();
X g() { return f().*&A::x; }
- // CHECK: define void @_ZN7PR130971gEv
+ // CHECK-LABEL: define void @_ZN7PR130971gEv
// CHECK: call void @_ZN7PR130971fEv
// CHECK-NOT: memcpy
// CHECK: call void @_ZN7PR130971XC1ERKS0_
diff --git a/test/CodeGenCXX/pr11676.cpp b/test/CodeGenCXX/pr11676.cpp
deleted file mode 100644
index 896751ad6e31..000000000000
--- a/test/CodeGenCXX/pr11676.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
-// CHECK that we don't crash.
-
-// PR11676's example is ill-formed:
-/*
-union _XEvent {
-};
-void ProcessEvent() {
- _XEvent pluginEvent = _XEvent();
-}
-*/
-
-// Example from PR11665:
-void f() {
- union U { int field; } u = U();
- (void)U().field;
-}
diff --git a/test/CodeGenCXX/pr11797.cpp b/test/CodeGenCXX/pr11797.cpp
index 05221acc84f3..1098372ce389 100644
--- a/test/CodeGenCXX/pr11797.cpp
+++ b/test/CodeGenCXX/pr11797.cpp
@@ -5,4 +5,4 @@ namespace std __attribute__ ((__visibility__ ("default"))) {}
void foo() {
}
#pragma GCC visibility pop
-// CHECK: define void @_Z3foov()
+// CHECK-LABEL: define void @_Z3foov()
diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp
index f3f2ec417e39..bb1c82dc8153 100644
--- a/test/CodeGenCXX/pr12251.cpp
+++ b/test/CodeGenCXX/pr12251.cpp
@@ -4,97 +4,97 @@
bool f(bool *x) {
return *x;
}
-// CHECK: define zeroext i1 @_Z1fPb
-// CHECK: load i8* %{{.*}}, align 1, !range !0
+// CHECK-LABEL: define zeroext i1 @_Z1fPb
+// CHECK: load i8* %{{[^ ]*}}, align 1, !range [[RANGE_i8_0_2:![^ ]*]]
// Only enum-tests follow. Ensure that after the bool test, no further range
// metadata shows up when strict enums are disabled.
-// NO-STRICT-ENUMS: define zeroext i1 @_Z1fPb
-// NO-STRICT-ENUMS: load i8* %{{.*}}, align 1, !range !0
+// NO-STRICT-ENUMS-LABEL: define zeroext i1 @_Z1fPb
+// NO-STRICT-ENUMS: load i8* %{{[^ ]*}}, align 1, !range
// NO-STRICT-ENUMS-NOT: !range
enum e1 { };
e1 g1(e1 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g1P2e1
-// CHECK: load i32* %x, align 4, !range !1
+// CHECK-LABEL: define i32 @_Z2g1P2e1
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1:![^ ]*]]
enum e2 { e2_a = 0 };
e2 g2(e2 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g2P2e2
-// CHECK: load i32* %x, align 4, !range !1
+// CHECK-LABEL: define i32 @_Z2g2P2e2
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1]]
enum e3 { e3_a = 16 };
e3 g3(e3 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g3P2e3
-// CHECK: load i32* %x, align 4, !range !2
+// CHECK-LABEL: define i32 @_Z2g3P2e3
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_32:![^ ]*]]
enum e4 { e4_a = -16};
e4 g4(e4 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g4P2e4
-// CHECK: load i32* %x, align 4, !range !3
+// CHECK-LABEL: define i32 @_Z2g4P2e4
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m16_16:![^ ]*]]
enum e5 { e5_a = -16, e5_b = 16};
e5 g5(e5 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g5P2e5
-// CHECK: load i32* %x, align 4, !range !4
+// CHECK-LABEL: define i32 @_Z2g5P2e5
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m32_32:![^ ]*]]
enum e6 { e6_a = -1 };
e6 g6(e6 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g6P2e6
-// CHECK: load i32* %x, align 4, !range !5
+// CHECK-LABEL: define i32 @_Z2g6P2e6
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m1_1:![^ ]*]]
enum e7 { e7_a = -16, e7_b = 2};
e7 g7(e7 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g7P2e7
-// CHECK: load i32* %x, align 4, !range !3
+// CHECK-LABEL: define i32 @_Z2g7P2e7
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m16_16]]
enum e8 { e8_a = -17};
e8 g8(e8 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g8P2e8
-// CHECK: load i32* %x, align 4, !range !4
+// CHECK-LABEL: define i32 @_Z2g8P2e8
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m32_32:![^ ]*]]
enum e9 { e9_a = 17};
e9 g9(e9 *x) {
return *x;
}
-// CHECK: define i32 @_Z2g9P2e9
-// CHECK: load i32* %x, align 4, !range !2
+// CHECK-LABEL: define i32 @_Z2g9P2e9
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_32]]
enum e10 { e10_a = -16, e10_b = 32};
e10 g10(e10 *x) {
return *x;
}
-// CHECK: define i32 @_Z3g10P3e10
-// CHECK: load i32* %x, align 4, !range !6
+// CHECK-LABEL: define i32 @_Z3g10P3e10
+// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m64_64:![^ ]*]]
enum e11 {e11_a = 4294967296 };
enum e11 g11(enum e11 *x) {
return *x;
}
-// CHECK: define i64 @_Z3g11P3e11
-// CHECK: load i64* %x, align {{[84]}}, !range !7
+// CHECK-LABEL: define i64 @_Z3g11P3e11
+// CHECK: load i64* %x, align {{[84]}}, !range [[RANGE_i64_0_2pow33:![^ ]*]]
enum e12 {e12_a = 9223372036854775808U };
enum e12 g12(enum e12 *x) {
return *x;
}
-// CHECK: define i64 @_Z3g12P3e12
+// CHECK-LABEL: define i64 @_Z3g12P3e12
// CHECK: load i64* %x, align {{[84]}}
// CHECK-NOT: range
// CHECK: ret
@@ -103,7 +103,7 @@ enum e13 : char {e13_a = -1 };
e13 g13(e13 *x) {
return *x;
}
-// CHECK: define signext i8 @_Z3g13P3e13
+// CHECK-LABEL: define signext i8 @_Z3g13P3e13
// CHECK: load i8* %x, align 1
// CHECK-NOT: range
// CHECK: ret
@@ -112,7 +112,7 @@ enum class e14 {e14_a = 1};
e14 g14(e14 *x) {
return *x;
}
-// CHECK: define i32 @_Z3g14P3e14
+// CHECK-LABEL: define i32 @_Z3g14P3e14
// CHECK: load i32* %x, align 4
// CHECK-NOT: range
// CHECK: ret
@@ -121,7 +121,7 @@ enum e15 { e15_a = 2147483648 };
e15 g15(e15 *x) {
return *x;
}
-// CHECK: define i32 @_Z3g15P3e15
+// CHECK-LABEL: define i32 @_Z3g15P3e15
// CHECK: load i32* %x, align 4
// CHECK-NOT: range
// CHECK: ret
@@ -130,17 +130,17 @@ enum e16 { e16_a = -2147483648 };
e16 g16(e16 *x) {
return *x;
}
-// CHECK: define i32 @_Z3g16P3e16
+// CHECK-LABEL: define i32 @_Z3g16P3e16
// CHECK: load i32* %x, align 4
// CHECK-NOT: range
// CHECK: ret
-// CHECK: !0 = metadata !{i8 0, i8 2}
-// CHECK: !1 = metadata !{i32 0, i32 1}
-// CHECK: !2 = metadata !{i32 0, i32 32}
-// CHECK: !3 = metadata !{i32 -16, i32 16}
-// CHECK: !4 = metadata !{i32 -32, i32 32}
-// CHECK: !5 = metadata !{i32 -1, i32 1}
-// CHECK: !6 = metadata !{i32 -64, i32 64}
-// CHECK: !7 = metadata !{i64 0, i64 8589934592}
+// CHECK: [[RANGE_i8_0_2]] = metadata !{i8 0, i8 2}
+// CHECK: [[RANGE_i32_0_1]] = metadata !{i32 0, i32 1}
+// CHECK: [[RANGE_i32_0_32]] = metadata !{i32 0, i32 32}
+// CHECK: [[RANGE_i32_m16_16]] = metadata !{i32 -16, i32 16}
+// CHECK: [[RANGE_i32_m32_32]] = metadata !{i32 -32, i32 32}
+// CHECK: [[RANGE_i32_m1_1]] = metadata !{i32 -1, i32 1}
+// CHECK: [[RANGE_i32_m64_64]] = metadata !{i32 -64, i32 64}
+// CHECK: [[RANGE_i64_0_2pow33]] = metadata !{i64 0, i64 8589934592}
diff --git a/test/CodeGenCXX/pr13396.cpp b/test/CodeGenCXX/pr13396.cpp
index 7d4e2ce74f04..3d582c51006b 100644
--- a/test/CodeGenCXX/pr13396.cpp
+++ b/test/CodeGenCXX/pr13396.cpp
@@ -7,13 +7,13 @@ struct foo {
};
foo::foo() {
- // CHECK: define void @_ZN3fooC1Ev(%struct.foo* inreg %this)
- // CHECK: define void @_ZN3fooC2Ev(%struct.foo* inreg %this)
+ // CHECK-LABEL: define void @_ZN3fooC1Ev(%struct.foo* inreg %this)
+ // CHECK-LABEL: define void @_ZN3fooC2Ev(%struct.foo* inreg %this)
}
foo::~foo() {
- // CHECK: define void @_ZN3fooD1Ev(%struct.foo* inreg %this)
- // CHECK: define void @_ZN3fooD2Ev(%struct.foo* inreg %this)
+ // CHECK-LABEL: define void @_ZN3fooD1Ev(%struct.foo* inreg %this)
+ // CHECK-LABEL: define void @_ZN3fooD2Ev(%struct.foo* inreg %this)
}
void dummy() {
@@ -21,6 +21,6 @@ void dummy() {
// older clangs accept:
// template foo::foo(int x);
foo x(10);
- // CHECK: define linkonce_odr void @_ZN3fooC1IiEET_(%struct.foo* inreg %this, i32 inreg %x)
- // CHECK: define linkonce_odr void @_ZN3fooC2IiEET_(%struct.foo* inreg %this, i32 inreg %x)
+ // CHECK-LABEL: define linkonce_odr void @_ZN3fooC1IiEET_(%struct.foo* inreg %this, i32 inreg %x)
+ // CHECK-LABEL: define linkonce_odr void @_ZN3fooC2IiEET_(%struct.foo* inreg %this, i32 inreg %x)
}
diff --git a/test/CodeGenCXX/pr9130.cpp b/test/CodeGenCXX/pr9130.cpp
index b28f3940e4e6..e726e5a80b0a 100644
--- a/test/CodeGenCXX/pr9130.cpp
+++ b/test/CodeGenCXX/pr9130.cpp
@@ -11,4 +11,4 @@ class nsVorbisState : public nsOggCodecState {
nsVorbisState::~nsVorbisState() {
}
-// CHECK: define linkonce_odr i32 @_ZN15nsOggCodecState9StartTimeEv
+// CHECK-LABEL: define linkonce_odr i32 @_ZN15nsOggCodecState9StartTimeEv
diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
index 0d267ff70372..c2d54e19215d 100644
--- a/test/CodeGenCXX/pr9965.cpp
+++ b/test/CodeGenCXX/pr9965.cpp
@@ -8,7 +8,7 @@ struct X : A // default constructor is not trivial
};
X<int> x;
-// CHECK: define internal void @__cxx_global_var_init()
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
// CHECK: call {{.*}} @_ZN1XIiEC1Ev
// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC1Ev
// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC2Ev
diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp
index 0640d4244eba..c0ba9046c8c4 100644
--- a/test/CodeGenCXX/pragma-visibility.cpp
+++ b/test/CodeGenCXX/pragma-visibility.cpp
@@ -28,8 +28,8 @@ template<> int x4<int>::y = 10;
template<int x> int f() { return x; }
extern "C" int g() { return f<3>(); }
#pragma GCC visibility pop
-// CHECK: define hidden i32 @g()
-// CHECK: define linkonce_odr hidden i32 @_Z1fILi3EEiv()
+// CHECK-LABEL: define hidden i32 @g()
+// CHECK-LABEL: define linkonce_odr hidden i32 @_Z1fILi3EEiv()
#pragma GCC visibility push(hidden)
template<class T> struct x5 {
@@ -37,19 +37,19 @@ template<class T> struct x5 {
};
#pragma GCC visibility pop
template<> void x5<int>::y() {}
-// CHECK: define hidden void @_ZN2x5IiE1yEv
+// CHECK-LABEL: define hidden void @_ZN2x5IiE1yEv
#pragma GCC visibility push(hidden)
namespace n __attribute((visibility("default"))) {
void f() {}
- // CHECK: define void @_ZN1n1fEv
+ // CHECK-LABEL: define void @_ZN1n1fEv
}
#pragma GCC visibility pop
namespace n __attribute((visibility("default"))) {
#pragma GCC visibility push(hidden)
void g() {}
- // CHECK: define hidden void @_ZN1n1gEv
+ // CHECK-LABEL: define hidden void @_ZN1n1gEv
#pragma GCC visibility pop
}
@@ -69,6 +69,6 @@ namespace test2 {
bar<foo>::f();
bar<int>::f();
}
- // CHECK: define linkonce_odr hidden void @_ZN5test23barINS_3fooEE1fEv
- // CHECK: define linkonce_odr void @_ZN5test23barIiE1fEv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test23barINS_3fooEE1fEv
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test23barIiE1fEv
}
diff --git a/test/CodeGenCXX/pragma-weak.cpp b/test/CodeGenCXX/pragma-weak.cpp
index ed537ffcd297..c03307914040 100644
--- a/test/CodeGenCXX/pragma-weak.cpp
+++ b/test/CodeGenCXX/pragma-weak.cpp
@@ -10,22 +10,22 @@ int zex;
#pragma weak foo
struct S { void foo(); };
void S::foo() {}
-// CHECK: define void @_ZN1S3fooEv(
+// CHECK-LABEL: define void @_ZN1S3fooEv(
#pragma weak zed
namespace bar { void zed() {} }
-// CHECK: define void @_ZN3bar3zedEv(
+// CHECK-LABEL: define void @_ZN3bar3zedEv(
#pragma weak bah
void bah() {}
-// CHECK: define void @_Z3bahv(
+// CHECK-LABEL: define void @_Z3bahv(
#pragma weak baz
extern "C" void baz() {}
-// CHECK: define weak void @baz(
+// CHECK-LABEL: define weak void @baz(
#pragma weak _Z3baxv
void bax() {}
// GCC produces a weak symbol for this one, but it doesn't look like a good
// idea to expose the mangling to the pragma unless we really have to.
-// CHECK: define void @_Z3baxv(
+// CHECK-LABEL: define void @_Z3baxv(
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
index 24ead8f8f478..9062ee095c3a 100644
--- a/test/CodeGenCXX/predefined-expr.cpp
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -9,6 +9,8 @@
// CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
// CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
// CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
+// CHECK: private unnamed_addr constant [51 x i8] c"void functionTemplateWithCapturedStmt(T) [T = int]\00"
+// CHECK: private unnamed_addr constant [76 x i8] c"auto functionTemplateWithLambda(int)::<anonymous class>::operator()() const\00"
// CHECK: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00"
// CHECK: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00"
@@ -376,6 +378,23 @@ void functionTemplateWithUnnamedTemplateParameter(T t)
}
template <typename T>
+void functionTemplateWithLambda(T t)
+{
+ []() {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ } ();
+}
+
+template <typename T>
+void functionTemplateWithCapturedStmt(T t)
+{
+ #pragma clang __debug captured
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+}
+
+template <typename T>
class OuterClass
{
public:
@@ -500,6 +519,9 @@ int main() {
functionTemplateExplicitSpecialization(0.0);
functionTemplateWithUnnamedTemplateParameter<int, float>(0.0f);
+ functionTemplateWithLambda<int>(0);
+ functionTemplateWithCapturedStmt<int>(0);
+
OuterClass<int *>::MiddleClass::InnerClass<float> omi;
omi.memberFunction(0, 0.0f);
diff --git a/test/CodeGenCXX/ptr-to-member-function.cpp b/test/CodeGenCXX/ptr-to-member-function.cpp
index 3989c0362889..914a90a4be1a 100644
--- a/test/CodeGenCXX/ptr-to-member-function.cpp
+++ b/test/CodeGenCXX/ptr-to-member-function.cpp
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
// 13.3.3.2 Ranking implicit conversion sequences
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/reference-cast.cpp b/test/CodeGenCXX/reference-cast.cpp
index f157ae99f9a2..60ea393af96c 100644
--- a/test/CodeGenCXX/reference-cast.cpp
+++ b/test/CodeGenCXX/reference-cast.cpp
@@ -15,7 +15,7 @@ const int &lvalue_noop_cast() {
return 17;
}
-// CHECK: define i16* @_Z20lvalue_integral_castv()
+// CHECK-LABEL: define i16* @_Z20lvalue_integral_castv()
const short &lvalue_integral_cast() {
if (i == 0)
// CHECK: store i16 17, i16*
@@ -27,7 +27,7 @@ const short &lvalue_integral_cast() {
return 17;
}
-// CHECK: define i16* @_Z29lvalue_floating_integral_castv()
+// CHECK-LABEL: define i16* @_Z29lvalue_floating_integral_castv()
const short &lvalue_floating_integral_cast() {
if (i == 0)
// CHECK: store i16 17, i16*
@@ -39,7 +39,7 @@ const short &lvalue_floating_integral_cast() {
return 17.5;
}
-// CHECK: define float* @_Z29lvalue_integral_floating_castv()
+// CHECK-LABEL: define float* @_Z29lvalue_integral_floating_castv()
const float &lvalue_integral_floating_cast() {
if (i == 0)
// CHECK: store float 1.700000e+{{0*}}1, float*
@@ -51,7 +51,7 @@ const float &lvalue_integral_floating_cast() {
return 17;
}
-// CHECK: define float* @_Z20lvalue_floating_castv()
+// CHECK-LABEL: define float* @_Z20lvalue_floating_castv()
const float &lvalue_floating_cast() {
if (i == 0)
// CHECK: store float 1.700000e+{{0*}}1, float*
@@ -65,7 +65,7 @@ const float &lvalue_floating_cast() {
int get_int();
-// CHECK: define i8* @_Z24lvalue_integer_bool_castv()
+// CHECK-LABEL: define i8* @_Z24lvalue_integer_bool_castv()
const bool &lvalue_integer_bool_cast() {
if (i == 0)
// CHECK: call i32 @_Z7get_intv()
@@ -82,7 +82,7 @@ const bool &lvalue_integer_bool_cast() {
float get_float();
-// CHECK: define i8* @_Z25lvalue_floating_bool_castv()
+// CHECK-LABEL: define i8* @_Z25lvalue_floating_bool_castv()
const bool &lvalue_floating_bool_cast() {
if (i == 0)
// CHECK: call float @_Z9get_floatv()
@@ -107,7 +107,7 @@ typedef int (X::*pmf)(int);
pm get_pointer_to_member_data();
pmf get_pointer_to_member_function();
-// CHECK: define i8* @_Z26lvalue_ptrmem_to_bool_castv()
+// CHECK-LABEL: define i8* @_Z26lvalue_ptrmem_to_bool_castv()
const bool &lvalue_ptrmem_to_bool_cast() {
if (i == 0)
// CHECK: call i64 @_Z26get_pointer_to_member_datav()
@@ -125,7 +125,7 @@ const bool &lvalue_ptrmem_to_bool_cast() {
return get_pointer_to_member_data();
}
-// CHECK: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v
+// CHECK-LABEL: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v
const bool &lvalue_ptrmem_to_bool_cast2() {
if (i == 0)
// CHECK: {{call.*_Z30get_pointer_to_member_functionv}}
@@ -169,7 +169,7 @@ const _Complex float &f1() {
return get_complex_double();
}
-// CHECK: define i32 @_Z7pr10592RKi(i32*
+// CHECK-LABEL: define i32 @_Z7pr10592RKi(i32*
unsigned pr10592(const int &v) {
// CHECK: [[VADDR:%[a-zA-Z0-9.]+]] = alloca i32*
// CHECK-NEXT: [[REFTMP:%[a-zA-Z0-9.]+]] = alloca i32
@@ -189,7 +189,7 @@ namespace PR10650 {
unsigned long long test(Helper *obj) {
return static_cast<const unsigned long long&>(obj->id());
}
- // CHECK: define i64 @_ZN7PR106504testEPNS_6HelperE
+ // CHECK-LABEL: define i64 @_ZN7PR106504testEPNS_6HelperE
// CHECK: store i64
}
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index df5a33686e0d..ec7a3d5daa8f 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s
void t1() {
- // CHECK: define void @_Z2t1v
+ // CHECK-LABEL: define void @_Z2t1v
// CHECK: [[REFLOAD:%.*]] = load i32** @a, align 8
// CHECK: load i32* [[REFLOAD]], align 4
extern int& a;
@@ -8,7 +8,7 @@ void t1() {
}
void t2(int& a) {
- // CHECK: define void @_Z2t2Ri
+ // CHECK-LABEL: define void @_Z2t2Ri
// CHECK: [[REFLOAD2:%.*]] = load i32** {{.*}}, align 8
// CHECK: load i32* [[REFLOAD2]], align 4
int b = a;
@@ -189,7 +189,7 @@ namespace N2 {
P getP();
- // CHECK: define void @_ZN2N21fEi
+ // CHECK-LABEL: define void @_ZN2N21fEi
// CHECK: call void @_ZN2N24getPEv
// CHECK: getelementptr inbounds
// CHECK: store i32 17
@@ -218,7 +218,7 @@ namespace N2 {
Z getZ();
- // CHECK: define void @_ZN2N21gEi
+ // CHECK-LABEL: define void @_ZN2N21gEi
// CHECK: call void @_ZN2N24getZEv
// CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
// CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
@@ -240,7 +240,7 @@ struct A {
~A();
};
-// CHECK: define internal void @__cxx_global_var_init
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call void @_ZN2N31AC1Ei(%"struct.N3::A"* @_ZGRN2N35sA123E, i32 123)
// CHECK: call i32 @__cxa_atexit
// CHECK: ret void
@@ -255,7 +255,7 @@ struct A {
};
void f() {
- // CHECK: define void @_ZN2N41fEv
+ // CHECK-LABEL: define void @_ZN2N41fEv
// CHECK: call void @_ZN2N41AC1Ev(%"struct.N4::A"* @_ZGRZN2N41fEvE2ar)
// CHECK: call i32 @__cxa_atexit
// CHECK: ret void
@@ -279,7 +279,7 @@ void h() {
// PR9565
namespace PR9565 {
struct a { int a : 10, b : 10; };
- // CHECK: define void @_ZN6PR95651fEv()
+ // CHECK-LABEL: define void @_ZN6PR95651fEv()
void f() {
// CHECK: call void @llvm.memcpy
a x = { 0, 0 };
@@ -306,7 +306,7 @@ namespace PR9565 {
namespace N6 {
extern struct x {char& x;}y;
int a() { return y.x; }
- // CHECK: define i32 @_ZN2N61aEv
+ // CHECK-LABEL: define i32 @_ZN2N61aEv
// CHECK: [[REFLOAD3:%.*]] = load i8** getelementptr inbounds (%"struct.N6::x"* @_ZN2N61yE, i32 0, i32 0), align 8
// CHECK: load i8* [[REFLOAD3]], align 1
}
diff --git a/test/CodeGenCXX/return.cpp b/test/CodeGenCXX/return.cpp
index 43d40ae986ee..1975055fdb74 100644
--- a/test/CodeGenCXX/return.cpp
+++ b/test/CodeGenCXX/return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -O -o - %s | FileCheck %s --check-prefix=CHECK-OPT
// CHECK: @_Z9no_return
diff --git a/test/CodeGenCXX/rtti-layout.cpp b/test/CodeGenCXX/rtti-layout.cpp
index 7128c4e4d07b..0db257731f42 100644
--- a/test/CodeGenCXX/rtti-layout.cpp
+++ b/test/CodeGenCXX/rtti-layout.cpp
@@ -101,7 +101,7 @@ struct B {
static int (B::*d)[10];
};
-// CHECK: define i32 @_Z1fv()
+// CHECK-LABEL: define i32 @_Z1fv()
int f() {
// Vectors should be treated as fundamental types.
typedef short __v4hi __attribute__ ((__vector_size__ (8)));
diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp
index 66d3f41589d1..646c61e0fd8f 100644
--- a/test/CodeGenCXX/runtimecc.cpp
+++ b/test/CodeGenCXX/runtimecc.cpp
@@ -20,7 +20,7 @@ namespace test0 {
};
A global;
-// CHECK: define internal arm_aapcscc void @__cxx_global_var_init()
+// CHECK-LABEL: define internal arm_aapcscc void @__cxx_global_var_init()
// CHECK: call arm_aapcscc [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE)
// CHECK-NEXT: call arm_aapcscc i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]]
// CHECK-NEXT: ret void
@@ -33,7 +33,7 @@ namespace test1 {
throw 0;
}
-// CHECK: define arm_aapcscc void @_ZN5test14testEv()
+// CHECK-LABEL: define arm_aapcscc void @_ZN5test14testEv()
// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]]
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32*
// CHECK-NEXT: store i32 0, i32* [[T1]]
@@ -45,7 +45,7 @@ namespace test1 {
// CHECK: declare arm_aapcscc void @__cxa_throw(i8*, i8*, i8*)
-// CHECK: define internal arm_aapcscc void @_GLOBAL__I_a()
+// CHECK-LABEL: define internal arm_aapcscc void @_GLOBAL__I_a()
// CHECK: call arm_aapcscc void @__cxx_global_var_init()
diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp
index b8d47dcfbe2f..2e0fa829ec90 100644
--- a/test/CodeGenCXX/rvalue-references.cpp
+++ b/test/CodeGenCXX/rvalue-references.cpp
@@ -7,7 +7,7 @@ struct B : Spacer, A { };
B &getB();
-// CHECK: define %struct.A* @_Z4getAv()
+// CHECK-LABEL: define %struct.A* @_Z4getAv()
// CHECK: call %struct.B* @_Z4getBv()
// CHECK-NEXT: bitcast %struct.B*
// CHECK-NEXT: getelementptr inbounds i8*
@@ -19,17 +19,17 @@ int &getIntLValue();
int &&getIntXValue();
int getIntPRValue();
-// CHECK: define i32* @_Z2f0v()
+// CHECK-LABEL: define i32* @_Z2f0v()
// CHECK: call i32* @_Z12getIntLValuev()
// CHECK-NEXT: ret i32*
int &&f0() { return static_cast<int&&>(getIntLValue()); }
-// CHECK: define i32* @_Z2f1v()
+// CHECK-LABEL: define i32* @_Z2f1v()
// CHECK: call i32* @_Z12getIntXValuev()
// CHECK-NEXT: ret i32*
int &&f1() { return static_cast<int&&>(getIntXValue()); }
-// CHECK: define i32* @_Z2f2v
+// CHECK-LABEL: define i32* @_Z2f2v
// CHECK: call i32 @_Z13getIntPRValuev()
// CHECK-NEXT: store i32 {{.*}}, i32*
// CHECK-NEXT: ret i32*
@@ -59,7 +59,7 @@ public:
C test();
-// CHECK: define void @_Z15elide_copy_initv
+// CHECK-LABEL: define void @_Z15elide_copy_initv
void elide_copy_init() {
ok = false;
// CHECK: call void @_Z4testv
@@ -68,7 +68,7 @@ void elide_copy_init() {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z16test_move_returnv
+// CHECK-LABEL: define void @_Z16test_move_returnv
C test_move_return() {
// CHECK: call void @_ZN1CC1Ei
C a1(3);
@@ -94,7 +94,7 @@ namespace test1 {
B(int i);
};
- // CHECK: define void @_ZN5test11BC2Ei(
+ // CHECK-LABEL: define void @_ZN5test11BC2Ei(
// CHECK: [[T0:%.*]] = call i32* @_ZN5test14moveERi(
// CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]]
// CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]])
diff --git a/test/CodeGenCXX/scoped-enums.cpp b/test/CodeGenCXX/scoped-enums.cpp
index c20faaaf2e96..159172d1662e 100644
--- a/test/CodeGenCXX/scoped-enums.cpp
+++ b/test/CodeGenCXX/scoped-enums.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
// PR9923
enum class Color { red, blue, green };
@@ -15,3 +15,10 @@ void h(Colour);
void i() {
h(Colour::grey);
}
+
+enum struct PR17103 : int { a = -1, b = 1 };
+bool cmp(PR17103 x, PR17103 y) { return x < y; }
+
+// CHECK-LABEL: @_Z3cmp7PR17103S_(
+// CHECK-NOT: }
+// CHECK: icmp slt
diff --git a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
index 84697be4a4cd..29926b91b795 100644
--- a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
@@ -10,7 +10,7 @@ struct A {
~A();
};
-// CHECK: define void @_ZN5Test11AD2Ev
+// CHECK-LABEL: define void @_ZN5Test11AD2Ev
// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8***
A::~A()
{
@@ -26,7 +26,7 @@ struct A {
~A();
};
-// CHECK: define void @_ZN5Test21AD2Ev
+// CHECK-LABEL: define void @_ZN5Test21AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8***
A::~A() {
f();
@@ -49,7 +49,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test31AD2Ev
+// CHECK-LABEL: define void @_ZN5Test31AD2Ev
// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8***
A::~A() {
@@ -75,7 +75,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test41AD2Ev
+// CHECK-LABEL: define void @_ZN5Test41AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8***
A::~A()
{
@@ -99,7 +99,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test51AD2Ev
+// CHECK-LABEL: define void @_ZN5Test51AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8***
A::~A()
{
@@ -127,7 +127,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test61AD2Ev
+// CHECK-LABEL: define void @_ZN5Test61AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8***
A::~A()
{
@@ -153,7 +153,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test71AD2Ev
+// CHECK-LABEL: define void @_ZN5Test71AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8***
A::~A()
{
@@ -179,7 +179,7 @@ struct A {
Field field;
};
-// CHECK: define void @_ZN5Test81AD2Ev
+// CHECK-LABEL: define void @_ZN5Test81AD2Ev
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8***
A::~A()
{
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index 4ad339db985b..eea979494843 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -42,7 +42,7 @@ namespace test2 {
template struct A<int>;
}
- // CHECK: define internal void @__cxx_global_var_init()
+ // CHECK-LABEL: define internal void @__cxx_global_var_init()
// CHECK: [[TMP:%.*]] = call i32 @_ZN5test23fooEv()
// CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test212_GLOBAL__N_11AIiE1xE, align 4
// CHECK-NEXT: ret void
@@ -60,7 +60,7 @@ namespace test3 {
template <class T> int A<T>::x = foo();
template struct A<int>;
- // CHECK: define internal void @__cxx_global_var_init1()
+ // CHECK-LABEL: define internal void @__cxx_global_var_init1()
// CHECK: [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
// CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0
// CHECK-NEXT: br i1 [[UNINITIALIZED]]
@@ -79,7 +79,7 @@ namespace test4 {
};
int f(A *a) {
- // CHECK: define i32 @_ZN5test41fEPNS_1AE
+ // CHECK-LABEL: define i32 @_ZN5test41fEPNS_1AE
// CHECK: ret i32 76
return a->n;
}
diff --git a/test/CodeGenCXX/static-init-1.cpp b/test/CodeGenCXX/static-init-1.cpp
index a926c0a2d32d..09bf7bfd5ca6 100644
--- a/test/CodeGenCXX/static-init-1.cpp
+++ b/test/CodeGenCXX/static-init-1.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t
-// RUN: grep "call i32 @_Z5func1i" %t | count 3
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-llvm %s -o - | FileCheck %s
extern "C" int printf(...);
@@ -9,15 +8,18 @@ int func2(int c) { return printf("loading the func2(%d)\n", c); };
int func1(int c) { return printf("loading the func1(%d)\n", c); }
static int loader_1 = func1(++count);
+// CHECK: call i32 @_Z5func1i
int loader_2 = func2(++count);
static int loader_3 = func1(++count);
-
+// CHECK: call i32 @_Z5func1i
int main() {}
int loader_4 = func2(++count);
static int loader_5 = func1(++count);
int loader_6 = func2(++count);
+// CHECK: call i32 @_Z5func1i
+// CHECK-NOT: call i32 @_Z5func1i
diff --git a/test/CodeGenCXX/static-init-4.cpp b/test/CodeGenCXX/static-init-4.cpp
new file mode 100644
index 000000000000..a4bb987c8d3d
--- /dev/null
+++ b/test/CodeGenCXX/static-init-4.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s -triple x86_64-linux-gnu | FileCheck %s
+
+typedef __attribute__((vector_size(4*4))) float float32x4_t;
+union QDSUnion { float32x4_t q; float s[4]; };
+constexpr float32x4_t a = {1,2,3,4};
+QDSUnion t = {{(a)}};
+// CHECK: @t = global %union.QDSUnion { <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00> }
diff --git a/test/CodeGenCXX/static-init-pnacl.cpp b/test/CodeGenCXX/static-init-pnacl.cpp
new file mode 100644
index 000000000000..de35ec3847fa
--- /dev/null
+++ b/test/CodeGenCXX/static-init-pnacl.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm -triple=le32-unknown-nacl -o - %s | FileCheck %s
+
+int f();
+
+// Test that PNaCl uses the Itanium/x86 ABI in which the static
+// variable's guard variable is tested via "load i8 and compare with
+// zero" rather than the ARM ABI which uses "load i32 and test the
+// bottom bit".
+void g() {
+ static int a = f();
+}
+// CHECK: [[LOAD:%.*]] = load atomic i8* bitcast (i64* @_ZGVZ1gvE1a to i8*) acquire
+// CHECK-NEXT: [[GUARD:%.*]] = icmp eq i8 [[LOAD]], 0
+// CHECK-NEXT: br i1 [[GUARD]]
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index 74278f7128c8..f522775c109e 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -54,7 +54,7 @@ namespace test0 {
}
namespace test1 {
- // CHECK: define internal i32 @_ZN5test1L6getvarEi(
+ // CHECK-LABEL: define internal i32 @_ZN5test1L6getvarEi(
static inline int getvar(int index) {
static const int var[] = { 1, 0, 2, 4 };
return var[index];
@@ -68,7 +68,7 @@ char base_req[] = { "foo" };
unsigned char base_req_uchar[] = { "bar" };
namespace union_static_local {
- // CHECK: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv
+ // CHECK-LABEL: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv
// CHECK: call void @_ZN18union_static_local1fEPNS_1xE(%"union.union_static_local::x"* bitcast ({ [2 x i8*] }* @_ZZN18union_static_local4testEvE3foo to %"union.union_static_local::x"*))
union x { long double y; const char *x[2]; };
void f(union x*);
@@ -103,14 +103,14 @@ namespace test2 {
B::B() {
static int x = foo();
}
- // CHECK: define void @_ZN5test21BC1Ev
+ // CHECK-LABEL: define void @_ZN5test21BC1Ev
// CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire,
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x)
// CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
// CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x,
// CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x)
- // CHECK: define void @_ZN5test21BC2Ev
+ // CHECK-LABEL: define void @_ZN5test21BC2Ev
// CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire,
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x)
// CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
@@ -122,10 +122,10 @@ namespace test2 {
B::~B() {
static int y = foo();
}
- // CHECK: define void @_ZN5test21BD1Ev(
+ // CHECK-LABEL: define void @_ZN5test21BD1Ev(
// CHECK: call void @_ZN5test21BD2Ev(
- // CHECK: define void @_ZN5test21BD2Ev(
+ // CHECK-LABEL: define void @_ZN5test21BD2Ev(
// CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire,
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y)
// CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
@@ -149,6 +149,6 @@ namespace test3 {
union U { char x; int i; };
static U u = { 'a' };
}
- // CHECK: define void @_ZN5test31BC1Ev(
- // CHECK: define void @_ZN5test31BC2Ev(
+ // CHECK-LABEL: define void @_ZN5test31BC1Ev(
+ // CHECK-LABEL: define void @_ZN5test31BC2Ev(
}
diff --git a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
index 94fd9aa12ced..50772bf647d1 100644
--- a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
+++ b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
@@ -1,6 +1,10 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: ; ModuleID
-template<typename> struct A { static int a; };
+
+extern "C" int foo();
+
+template<typename T> struct A { static int a; };
+template<typename T> int A<T>::a = foo();
// CHECK-NOT: @_ZN1AIcE1aE
template<> int A<char>::a;
@@ -8,4 +12,85 @@ template<> int A<char>::a;
// CHECK: @_ZN1AIbE1aE = global i32 10
template<> int A<bool>::a = 10;
+// CHECK: @llvm.global_ctors = appending global [7 x { i32, void ()* }]
+// CHECK: [{ i32, void ()* } { i32 65535, void ()* @[[unordered1:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered2:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered3:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered4:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered5:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered6:[^ ]*]] },
+// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
+
+template int A<short>::a; // Unordered
+int b = foo();
+int c = foo();
+int d = A<void>::a; // Unordered
+
+// An explicit specialization is ordered, and goes in __GLOBAL_I_a.
+template<> struct A<int> { static int a; };
+int A<int>::a = foo();
+
+template<typename T> struct S { static T x; static T y; };
+template<> int S<int>::x = foo();
+template<> int S<int>::y = S<int>::x;
+
+template<typename T> T x = foo();
+template short x<short>; // Unordered
+template<> int x<int> = foo();
+int e = x<char>; // Unordered
+
+namespace ns {
+template <typename T> struct a {
+ static int i;
+};
+template<typename T> int a<T>::i = foo();
+template struct a<int>;
+
+struct b {
+ template <typename T> static T i;
+};
+template<typename T> T b::i = foo();
+template int b::i<int>;
+}
+// CHECK: define internal void @[[unordered1]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_ZN1AIsE1aE
+// CHECK: ret
+
+// CHECK: define internal void @[[unordered2]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_Z1xIsE
+// CHECK: ret
+
+// CHECK: define internal void @[[unordered3]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_ZN2ns1aIiE1iE
+// CHECK: ret
+
+// CHECK: define internal void @[[unordered4]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_ZN2ns1b1iIiEE
+// CHECK: ret
+
+// CHECK: define internal void @[[unordered5]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_ZN1AIvE1aE
+// CHECK: ret
+
+// CHECK: define internal void @[[unordered6]]
+// CHECK: call i32 @foo()
+// CHECK: store {{.*}} @_Z1xIcE
+// CHECK: ret
+// CHECK: define internal void @_GLOBAL__I_a()
+// We call unique stubs for every ordered dynamic initializer in the TU.
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK: call
+// CHECK-NOT: call
+// CHECK: ret
diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp
index 1f0e4ac4bf29..5d4d6bcce458 100644
--- a/test/CodeGenCXX/stmtexpr.cpp
+++ b/test/CodeGenCXX/stmtexpr.cpp
@@ -73,3 +73,10 @@ int* foo5() {
return (({ a; }));
}
+// <rdar://problem/14074868>
+// Make sure this doesn't crash.
+int foo5(bool b) {
+ int y = 0;
+ y = ({ A a(1); if (b) goto G; a.i; });
+ G: return y;
+}
diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp
index 3df487a33f3c..f4d6549e8338 100644
--- a/test/CodeGenCXX/template-anonymous-types.cpp
+++ b/test/CodeGenCXX/template-anonymous-types.cpp
@@ -19,19 +19,19 @@ template <typename T> int f(T t) {
void test() {
// Look for two instantiations, one for FOO's
// type and one for BAR's.
- // CHECK: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t)
+ // CHECK-LABEL: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t)
(void)f(S::FOO);
- // CHECK: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t)
+ // CHECK-LABEL: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t)
(void)f(S::BAR);
// Now check for the class template instantiations. Annoyingly, they are in
// reverse order.
//
// BAR's instantiation of X:
- // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this)
- // CHECK: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this)
+ // CHECK-LABEL: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr
//
// FOO's instantiation of X:
- // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this)
- // CHECK: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this)
+ // CHECK-LABEL: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr
}
diff --git a/test/CodeGenCXX/template-dependent-bind-temporary.cpp b/test/CodeGenCXX/template-dependent-bind-temporary.cpp
index cc1ce866fe2d..ca980c3ff685 100644
--- a/test/CodeGenCXX/template-dependent-bind-temporary.cpp
+++ b/test/CodeGenCXX/template-dependent-bind-temporary.cpp
@@ -18,7 +18,7 @@ void IntToString(T a)
}
int main() {
-// CHECK: define linkonce_odr void @_Z11IntToStringIcEvT_(
+// CHECK-LABEL: define linkonce_odr void @_Z11IntToStringIcEvT_(
IntToString('a');
}
diff --git a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
index 2c62b60b1100..de86f10f6c30 100644
--- a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
+++ b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
@@ -2,8 +2,8 @@
// Verify that symbols are hidden.
// CHECK: @_ZN1CIiE5Inner6Inner26StaticE = weak_odr hidden global
-// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner1fEv
-// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv
+// CHECK-LABEL: define weak_odr hidden void @_ZN1CIiE5Inner1fEv
+// CHECK-LABEL: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv
template<typename T>
struct C {
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index b90716ba1ae6..80283a1edd04 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -13,16 +13,16 @@
// CHECK-NOT: _ZTVN5test31SIiEE
// CHECK-NOT: _ZTSN5test31SIiEE
-// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr
-// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
-// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd(
-
-// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE()
-// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE()
-// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE()
-// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE()
-// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE()
-// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
+// CHECK-LABEL: define available_externally void @_ZN5test21CIiE6zedbarEd(
+
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE()
+// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE()
// CHECK: declare void @_ZN7PR106662h1ENS_1SILi1EEE()
// CHECK: declare void @_ZN7PR106662h1ENS_1SILi2EEE()
// CHECK: declare void @_ZN7PR106662h1ENS_1SILi3EEE()
diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp
index 3acd12ef0bc5..a84affab7622 100644
--- a/test/CodeGenCXX/template-linkage.cpp
+++ b/test/CodeGenCXX/template-linkage.cpp
@@ -9,19 +9,19 @@ template<typename T> struct A {
// Explicit instantiations have external linkage.
-// CHECK: define weak_odr void @_ZN1AIiE1gEv(
+// CHECK-LABEL: define weak_odr void @_ZN1AIiE1gEv(
template void A<int>::g();
-// CHECK: define weak_odr void @_ZN1AIfE1fEf(
-// CHECK: define weak_odr void @_ZN1AIfE1gEv(
+// CHECK-LABEL: define weak_odr void @_ZN1AIfE1fEf(
+// CHECK-LABEL: define weak_odr void @_ZN1AIfE1gEv(
// FIXME: This should also emit the vtable.
template struct A<float>;
-// CHECK: define weak_odr void @_Z1fIiEvT_
+// CHECK-LABEL: define weak_odr void @_Z1fIiEvT_
template <typename T> void f(T) { }
template void f<int>(int);
-// CHECK: define weak_odr void @_Z1gIiEvT_
+// CHECK-LABEL: define weak_odr void @_Z1gIiEvT_
template <typename T> inline void g(T) { }
template void g<int>(int);
@@ -40,7 +40,7 @@ template<typename T> void X1<T>::blarg() { }
extern template struct X0<char>;
extern template struct X1<char>;
-// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr
void test_X1() {
X1<char> i1c;
}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index a369c2e36976..e8a7a1f25596 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -1,4 +1,32 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s
+
+namespace PR16263 {
+ const unsigned int n = 1234;
+ extern const int &r = (const int&)n;
+ // CHECK: @_ZGRN7PR162631rE = private constant i32 1234,
+ // CHECK: @_ZN7PR162631rE = constant i32* @_ZGRN7PR162631rE,
+
+ extern const int &s = reinterpret_cast<const int&>(n);
+ // CHECK: @_ZN7PR16263L1nE = internal constant i32 1234, align 4
+ // CHECK: @_ZN7PR162631sE = constant i32* @_ZN7PR16263L1nE, align 8
+
+ struct A { int n; };
+ struct B { int n; };
+ struct C : A, B {};
+ extern const A &&a = (A&&)(A&&)(C&&)(C{});
+ // CHECK: @_ZGRN7PR162631aE = private global {{.*}} zeroinitializer,
+ // CHECK: @_ZN7PR162631aE = constant {{.*}} bitcast ({{.*}}* @_ZGRN7PR162631aE to
+
+ extern const int &&t = ((B&&)C{}).n;
+ // CHECK: @_ZGRN7PR162631tE = private global {{.*}} zeroinitializer,
+ // CHECK: @_ZN7PR162631tE = constant i32* {{.*}}* @_ZGRN7PR162631tE {{.*}} 4
+
+ struct D { double d; C c; };
+ extern const int &&u = (123, static_cast<B&&>(0, ((D&&)D{}).*&D::c).n);
+ // CHECK: @_ZGRN7PR162631uE = private global {{.*}} zeroinitializer
+ // CHECK: @_ZN7PR162631uE = constant i32* {{.*}} @_ZGRN7PR162631uE {{.*}} 12
+}
+
struct A {
A();
~A();
@@ -226,7 +254,7 @@ namespace PR5867 {
};
void f(S, int);
- // CHECK: define void @_ZN6PR58671gEv
+ // CHECK-LABEL: define void @_ZN6PR58671gEv
void g() {
// CHECK: call void @_ZN6PR58671SC1Ev
// CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi
@@ -235,7 +263,7 @@ namespace PR5867 {
(f)(S(), 0);
}
- // CHECK: define linkonce_odr void @_ZN6PR58672g2IiEEvT_
+ // CHECK-LABEL: define linkonce_odr void @_ZN6PR58672g2IiEEvT_
template<typename T>
void g2(T) {
// CHECK: call void @_ZN6PR58671SC1Ev
@@ -256,7 +284,7 @@ namespace PR6199 {
struct B { operator A(); };
- // CHECK: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_
+ // CHECK-LABEL: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_
template<typename T> A f2(T) {
B b;
// CHECK: call void @_ZN6PR61991BcvNS_1AEEv
@@ -278,7 +306,7 @@ struct A {
int& f(int);
-// CHECK: define void @_ZN3T121gEv
+// CHECK-LABEL: define void @_ZN3T121gEv
void g() {
// CHECK: call void @_ZN3T121AC1Ev
// CHECK-NEXT: call i32 @_ZN3T121A1fEv(
@@ -325,7 +353,7 @@ namespace PR7556 {
struct A { ~A(); };
struct B { int i; ~B(); };
struct C { int C::*pm; ~C(); };
- // CHECK: define void @_ZN6PR75563fooEv()
+ // CHECK-LABEL: define void @_ZN6PR75563fooEv()
void foo() {
// CHECK: call void @_ZN6PR75561AD1Ev
A();
@@ -350,7 +378,7 @@ namespace Elision {
A fooA();
void takeA(A a);
- // CHECK: define void @_ZN7Elision5test0Ev()
+ // CHECK-LABEL: define void @_ZN7Elision5test0Ev()
void test0() {
// CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8
// CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8
@@ -378,7 +406,7 @@ namespace Elision {
}
- // CHECK: define void @_ZN7Elision5test1EbNS_1AE(
+ // CHECK-LABEL: define void @_ZN7Elision5test1EbNS_1AE(
void test1(bool c, A x) {
// CHECK: [[I:%.*]] = alloca [[A]], align 8
// CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8
@@ -417,7 +445,7 @@ namespace Elision {
// CHECK: ret void
}
- // CHECK: define void @_ZN7Elision5test4Ev()
+ // CHECK-LABEL: define void @_ZN7Elision5test4Ev()
void test4() {
// CHECK: [[X:%.*]] = alloca [[A]], align 8
// CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16
@@ -493,7 +521,7 @@ namespace Elision {
namespace PR8623 {
struct A { A(int); ~A(); };
- // CHECK: define void @_ZN6PR86233fooEb(
+ // CHECK-LABEL: define void @_ZN6PR86233fooEb(
void foo(bool b) {
// CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
// CHECK-NEXT: [[LCONS:%.*]] = alloca i1
@@ -523,7 +551,7 @@ namespace PR8623 {
namespace PR11365 {
struct A { A(); ~A(); };
- // CHECK: define void @_ZN7PR113653fooEv(
+ // CHECK-LABEL: define void @_ZN7PR113653fooEv(
void foo() {
// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [[A:%.*]]]* {{.*}}, i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 3
@@ -542,7 +570,7 @@ namespace AssignmentOp {
struct A { ~A(); };
struct B { A operator=(const B&); };
struct C : B { B b1, b2; };
- // CHECK: define void @_ZN12AssignmentOp1fE
+ // CHECK-LABEL: define void @_ZN12AssignmentOp1fE
void f(C &c1, const C &c2) {
// CHECK: call {{.*}} @_ZN12AssignmentOp1CaSERKS0_(
c1 = c2;
@@ -558,3 +586,194 @@ namespace AssignmentOp {
// CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS
// CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev(
}
+
+namespace BindToSubobject {
+ struct A {
+ A();
+ ~A();
+ int a;
+ };
+
+ void f(), g();
+
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1aE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1aE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1aE, i32 0, i32 0), i32** @_ZN15BindToSubobject1aE, align 8
+ int &&a = A().a;
+
+ // CHECK: call void @_ZN15BindToSubobject1fEv()
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1bE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1bE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1bE, i32 0, i32 0), i32** @_ZN15BindToSubobject1bE, align 8
+ int &&b = (f(), A().a);
+
+ int A::*h();
+
+ // CHECK: call void @_ZN15BindToSubobject1fEv()
+ // CHECK: call void @_ZN15BindToSubobject1gEv()
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
+ // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
+ // CHECK: getelementptr
+ // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8
+ int &&c = (f(), (g(), A().*h()));
+
+ struct B {
+ int padding;
+ A a;
+ };
+
+ // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
+ // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
+ // CHECK: getelementptr {{.*}} getelementptr
+ // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8
+ int &&d = (B().a).*h();
+}
+
+namespace Bitfield {
+ struct S { int a : 5; ~S(); };
+
+ // Do not lifetime extend the S() temporary here.
+ // CHECK: alloca
+ // CHECK: call {{.*}}memset
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE
+ // CHECK: call void @_ZN8Bitfield1SD1
+ // CHECK: store i32* @_ZGRN8Bitfield1rE, i32** @_ZN8Bitfield1rE, align 8
+ int &&r = S().a;
+}
+
+namespace Vector {
+ typedef __attribute__((vector_size(16))) int vi4a;
+ typedef __attribute__((ext_vector_type(4))) int vi4b;
+ struct S {
+ vi4a v;
+ vi4b w;
+ };
+ // CHECK: alloca
+ // CHECK: extractelement
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE
+ // CHECK: store i32* @_ZGRN6Vector1rE, i32** @_ZN6Vector1rE,
+ int &&r = S().v[1];
+
+ // CHECK: alloca
+ // CHECK: extractelement
+ // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE
+ // CHECK: store i32* @_ZGRN6Vector1sE, i32** @_ZN6Vector1sE,
+ int &&s = S().w[1];
+ // FIXME PR16204: The following code leads to an assertion in Sema.
+ //int &&s = S().w.y;
+}
+
+namespace ImplicitTemporaryCleanup {
+ struct A { A(int); ~A(); };
+ void g();
+
+ // CHECK-LABEL: define void @_ZN24ImplicitTemporaryCleanup1fEv(
+ void f() {
+ // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AC1Ei(
+ A &&a = 0;
+
+ // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1gEv(
+ g();
+
+ // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AD1Ev(
+ }
+}
+
+namespace MultipleExtension {
+ struct A { A(); ~A(); };
+ struct B { B(); ~B(); };
+ struct C { C(); ~C(); };
+ struct D { D(); ~D(); int n; C c; };
+ struct E { const A &a; B b; const C &c; ~E(); };
+
+ E &&e1 = { A(), B(), D().c };
+
+ // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]])
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
+ // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0)
+
+ // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1))
+
+ // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]])
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
+ // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2)
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]]
+ // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8
+
+ E e2 = { A(), B(), D().c };
+
+ // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]])
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
+ // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0)
+
+ // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1))
+
+ // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]])
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
+ // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2)
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]]
+
+
+ void g();
+ // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv(
+ void f() {
+ E &&e1 = { A(), B(), D().c };
+ // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0
+ // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]])
+ // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]]
+ // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1
+ // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]])
+ // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2
+ // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]])
+ // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1
+ // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]]
+ // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]]
+
+ g();
+ // CHECK: call void @[[NS]]1gEv()
+
+ E e2 = { A(), B(), D().c };
+ // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0
+ // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]])
+ // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]]
+ // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1
+ // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]])
+ // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2
+ // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]])
+ // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1
+ // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]]
+
+ g();
+ // CHECK: call void @[[NS]]1gEv()
+
+ // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]])
+ // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]])
+ // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]])
+ // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]])
+ // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]])
+ // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]])
+ }
+}
+
+namespace PR14130 {
+ struct S { S(int); };
+ struct U { S &&s; };
+ U v { { 0 } };
+ // CHECK: call void @_ZN7PR141301SC1Ei({{.*}} @_ZGRN7PR141301vE, i32 0)
+ // CHECK: store {{.*}} @_ZGRN7PR141301vE, {{.*}} @_ZN7PR141301vE
+}
+
+namespace Ctor {
+ struct A { A(); ~A(); };
+ void f();
+ struct B {
+ A &&a;
+ B() : a{} { f(); }
+ } b;
+ // CHECK: define {{.*}}void @_ZN4Ctor1BC1Ev(
+ // CHECK: call void @_ZN4Ctor1AC1Ev(
+ // CHECK: call void @_ZN4Ctor1fEv(
+ // CHECK: call void @_ZN4Ctor1AD1Ev(
+}
diff --git a/test/CodeGenCXX/thiscall-struct-return.cpp b/test/CodeGenCXX/thiscall-struct-return.cpp
index ff531255bba9..a6be5aa494e1 100644
--- a/test/CodeGenCXX/thiscall-struct-return.cpp
+++ b/test/CodeGenCXX/thiscall-struct-return.cpp
@@ -1,7 +1,7 @@
// For MSVC ABI compatibility, all structures returned by value using the
// thiscall calling convention must use the hidden parameter.
//
-// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -O0 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -emit-llvm -o - | FileCheck %s
// This structure would normally be returned via EAX
struct S {
@@ -29,7 +29,7 @@ public:
}
};
-// CHECK: define void @_Z4testv()
+// CHECK-LABEL: define void @_Z4testv()
void test( void ) {
// CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]])
C c;
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
index 769d120be323..70decc98a109 100644
--- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -7,7 +7,7 @@ struct X {
struct Y { };
-// CHECK: define void @_Z1fv
+// CHECK-LABEL: define void @_Z1fv
void f() {
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
// CHECK: invoke void @_ZN1XC1Ev
diff --git a/test/CodeGenCXX/throw-expression-cleanup.cpp b/test/CodeGenCXX/throw-expression-cleanup.cpp
index e1ecd3804679..9944e161a817 100644
--- a/test/CodeGenCXX/throw-expression-cleanup.cpp
+++ b/test/CodeGenCXX/throw-expression-cleanup.cpp
@@ -14,7 +14,7 @@ void f() {
} catch (...) { }
}
-// CHECK: define void @_Z1fv
+// CHECK-LABEL: define void @_Z1fv
// CHECK: call void @_ZN5ErrorC1ERK1X
// CHECK: invoke void @__cxa_throw
// CHECK: landingpad
diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp
index ba8a86881a63..d9bf8fdd59ea 100644
--- a/test/CodeGenCXX/throw-expressions.cpp
+++ b/test/CodeGenCXX/throw-expressions.cpp
@@ -23,7 +23,31 @@ int test4() {
int test5(bool x, bool y, int z) {
return (x ? throw 1 : y) ? z : throw 2;
}
-// CHECK: define i32 @_Z5test5bbi(
+// CHECK-LABEL: define i32 @_Z5test5bbi(
+// CHECK: br i1
+//
+// x.true:
+// CHECK: call void @__cxa_throw(
+// CHECK-NEXT: unreachable
+//
+// x.false:
+// CHECK: br i1
+//
+// y.true:
+// CHECK: load i32*
+// CHECK: br label
+//
+// y.false:
+// CHECK: call void @__cxa_throw(
+// CHECK-NEXT: unreachable
+//
+// end:
+// CHECK: ret i32
+
+int test6(bool x, bool y, int z) {
+ return (x ? throw 1 : y) ? z : (throw 2);
+}
+// CHECK-LABEL: define i32 @_Z5test6bbi(
// CHECK: br i1
//
// x.true:
diff --git a/test/CodeGenCXX/thunks-available-externally.cpp b/test/CodeGenCXX/thunks-available-externally.cpp
index dfdb786b18ee..01e494717ebf 100644
--- a/test/CodeGenCXX/thunks-available-externally.cpp
+++ b/test/CodeGenCXX/thunks-available-externally.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm-only -O3
// Check that we don't assert on this case.
namespace Test1 {
@@ -58,15 +58,6 @@ static void f(B* b) {
b->f();
}
-// CHECK: define void @_ZN5Test21fEv()
-// CHECK: call void @_ZN5Test21C1fEv
-// CHECK: ret void
-// CHECK: define available_externally void @_ZThn16_N5Test21C1fEv
-void f() {
- C c;
- f(&c);
-}
-
}
// Test that we don't assert.
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index 6e58830c6aef..defb70681d93 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - -O1 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=CHECK-HIDDEN %s
namespace Test1 {
@@ -19,7 +20,7 @@ struct C : A, B {
virtual void f();
};
-// CHECK: define void @_ZThn8_N5Test11C1fEv(
+// CHECK-LABEL: define void @_ZThn8_N5Test11C1fEv(
void C::f() { }
}
@@ -37,7 +38,7 @@ struct B : virtual A {
virtual void f();
};
-// CHECK: define void @_ZTv0_n24_N5Test21B1fEv(
+// CHECK-LABEL: define void @_ZTv0_n24_N5Test21B1fEv(
void B::f() { }
}
@@ -82,7 +83,7 @@ struct __attribute__((visibility("protected"))) C : A, B {
virtual void f();
};
-// CHECK: define protected void @_ZThn8_N5Test41C1fEv(
+// CHECK-LABEL: define protected void @_ZThn8_N5Test41C1fEv(
void C::f() { }
}
@@ -165,7 +166,7 @@ namespace Test6 {
virtual X f();
};
- // CHECK: define void @_ZThn16_N5Test66Thunks1fEv
+ // CHECK-LABEL: define void @_ZThn16_N5Test66Thunks1fEv
// CHECK-NOT: memcpy
// CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}}
// CHECK: ret void
@@ -211,7 +212,7 @@ namespace Test7 {
void D::baz(X, X&, _Complex float, Small, Small&, Large) { }
- // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE(
+ // CHECK-LABEL: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE(
// CHECK-NOT: memcpy
// CHECK: ret void
void testD() { D d; }
@@ -226,7 +227,7 @@ namespace Test8 {
// CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]*
void C::helper(NonPOD var) {}
- // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE(
+ // CHECK-LABEL: define void @_ZThn8_N5Test81C3barENS_6NonPODE(
// CHECK-NOT: load [[NONPODTYPE]]*
// CHECK-NOT: memcpy
// CHECK: ret void
@@ -250,8 +251,8 @@ namespace Test10 {
struct B { virtual void foo(); };
struct C : A, B { void foo() {} };
- // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test101C3fooEv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv
void test() {
C c;
@@ -342,10 +343,31 @@ namespace Test14 {
// CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) unnamed_addr [[NUW:#[0-9]+]]
}
+// Varargs non-covariant thunk test.
+// PR18098
+namespace Test15 {
+ struct A {
+ virtual ~A();
+ };
+ struct B {
+ virtual void f(int x, ...);
+ };
+ struct C : A, B {
+ virtual void c();
+ virtual void f(int x, ...);
+ };
+ void C::c() {}
+
+ // C::c
+ // CHECK: declare void @_ZN6Test151C1fEiz
+ // non-virtual thunk to C::f
+ // CHECK: declare void @_ZThn8_N6Test151C1fEiz
+}
+
/**** The following has to go at the end of the file ****/
// This is from Test5:
-// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
-// CHECK: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
+// CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
+// CHECK-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
// CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
diff --git a/test/CodeGenCXX/type_visibility.cpp b/test/CodeGenCXX/type_visibility.cpp
index 5c45611991ce..11e5091fd279 100644
--- a/test/CodeGenCXX/type_visibility.cpp
+++ b/test/CodeGenCXX/type_visibility.cpp
@@ -26,11 +26,11 @@ namespace temp0 {
};
template struct B<A>;
- // FUNS: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv(
+ // FUNS-LABEL: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv(
// VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
// VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant
// VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
- // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv(
+ // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv(
// VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant
// VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
@@ -43,11 +43,11 @@ namespace temp1 {
};
template struct B<A>;
- // FUNS: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv(
+ // FUNS-LABEL: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv(
// VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
// VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
// VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
- // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv(
+ // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv(
// VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
// VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
@@ -60,11 +60,11 @@ namespace temp2 {
};
template struct B<A>;
- // FUNS: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv(
+ // FUNS-LABEL: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv(
// VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
// VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant
// VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
- // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv(
+ // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv(
// VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant
// VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
@@ -77,11 +77,11 @@ namespace temp3 {
};
template struct B<A>;
- // FUNS: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // FUNS-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
// VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
// VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
- // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
// VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
// VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
@@ -94,11 +94,11 @@ namespace temp4 {
};
template struct B<A>;
- // FUNS: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv(
+ // FUNS-LABEL: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv(
// VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
// VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
- // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv(
+ // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv(
// VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
// VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
@@ -110,11 +110,11 @@ namespace type0 {
};
void A::foo() {}
- // FUNS: define void @_ZN5type01A3fooEv(
+ // FUNS-LABEL: define void @_ZN5type01A3fooEv(
// VARS: @_ZTVN5type01AE = unnamed_addr constant
// VARS: @_ZTSN5type01AE = constant
// VARS: @_ZTIN5type01AE = unnamed_addr constant
- // FUNS-HIDDEN: define hidden void @_ZN5type01A3fooEv(
+ // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type01A3fooEv(
// VARS-HIDDEN: @_ZTVN5type01AE = unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5type01AE = constant
// VARS-HIDDEN: @_ZTIN5type01AE = unnamed_addr constant
@@ -126,11 +126,11 @@ namespace type1 {
};
void A::foo() {}
- // FUNS: define hidden void @_ZN5type11A3fooEv(
+ // FUNS-LABEL: define hidden void @_ZN5type11A3fooEv(
// VARS: @_ZTVN5type11AE = unnamed_addr constant
// VARS: @_ZTSN5type11AE = constant
// VARS: @_ZTIN5type11AE = unnamed_addr constant
- // FUNS-HIDDEN: define hidden void @_ZN5type11A3fooEv(
+ // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type11A3fooEv(
// VARS-HIDDEN: @_ZTVN5type11AE = unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5type11AE = constant
// VARS-HIDDEN: @_ZTIN5type11AE = unnamed_addr constant
@@ -142,11 +142,11 @@ namespace type2 {
};
void A::foo() {}
- // FUNS: define void @_ZN5type21A3fooEv(
+ // FUNS-LABEL: define void @_ZN5type21A3fooEv(
// VARS: @_ZTVN5type21AE = hidden unnamed_addr constant
// VARS: @_ZTSN5type21AE = hidden constant
// VARS: @_ZTIN5type21AE = hidden unnamed_addr constant
- // FUNS-HIDDEN: define hidden void @_ZN5type21A3fooEv(
+ // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type21A3fooEv(
// VARS-HIDDEN: @_ZTVN5type21AE = hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5type21AE = hidden constant
// VARS-HIDDEN: @_ZTIN5type21AE = hidden unnamed_addr constant
@@ -158,11 +158,11 @@ namespace type3 {
};
void A::foo() {}
- // FUNS: define void @_ZN5type31A3fooEv(
+ // FUNS-LABEL: define void @_ZN5type31A3fooEv(
// VARS: @_ZTVN5type31AE = hidden unnamed_addr constant
// VARS: @_ZTSN5type31AE = hidden constant
// VARS: @_ZTIN5type31AE = hidden unnamed_addr constant
- // FUNS-HIDDEN: define void @_ZN5type31A3fooEv(
+ // FUNS-HIDDEN-LABEL: define void @_ZN5type31A3fooEv(
// VARS-HIDDEN: @_ZTVN5type31AE = hidden unnamed_addr constant
// VARS-HIDDEN: @_ZTSN5type31AE = hidden constant
// VARS-HIDDEN: @_ZTIN5type31AE = hidden unnamed_addr constant
diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp
index a1bc967d74d2..9d212905e614 100644
--- a/test/CodeGenCXX/typeid.cpp
+++ b/test/CodeGenCXX/typeid.cpp
@@ -27,7 +27,10 @@ extern A &a;
// CHECK: @_ZN5Test14a_tiE = global
const std::type_info &a_ti = typeid(a);
-// CHECK: define i8* @_ZN5Test11fEv
+// CHECK: @_ZN5Test18A10_c_tiE = constant %"class.std::type_info"* bitcast ({ i8*, i8* }* @_ZTIA10_c to %"class.std::type_info"*), align 8
+const std::type_info &A10_c_ti = typeid(char const[10]);
+
+// CHECK-LABEL: define i8* @_ZN5Test11fEv
const char *f() {
try {
// CHECK: br i1
diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp
index 902cc8de5c97..aacb8493ef3c 100644
--- a/test/CodeGenCXX/unknown-anytype.cpp
+++ b/test/CodeGenCXX/unknown-anytype.cpp
@@ -1,33 +1,45 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix COMMON %s < %t
+// RUN: FileCheck -check-prefix X86_64 %s < %t
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix COMMON %s < %t
+// RUN: FileCheck -check-prefix I386 %s < %t
+
+// x86-64 is the special case here because of its variadic convention.
+// We want to ensure that it always uses a variadic convention even if
+// other platforms do not.
+// rdar://13731520
int test0() {
extern __unknown_anytype test0_any;
- // CHECK: load i32* @test0_any
+ // COMMON: load i32* @test0_any
return (int) test0_any;
}
int test1() {
extern __unknown_anytype test1_any();
- // CHECK: call i32 @_Z9test1_anyv()
+ // COMMON: call i32 @_Z9test1_anyv()
return (int) test1_any();
}
extern "C" __unknown_anytype test2_any(...);
float test2() {
- // CHECK: call float (...)* @test2_any(double {{[^,]+}})
+ // X86_64: call float (double, ...)* @test2_any(double {{[^,]+}})
+ // I386: call float (double, ...)* @test2_any(double {{[^,]+}})
return (float) test2_any(0.5f);
}
extern "C" __unknown_anytype test2a_any(...);
float test2a() {
- // CHECK: call float (...)* @test2a_any(float {{[^,]+}})
+ // X86_64: call float (float, ...)* @test2a_any(float {{[^,]+}})
+ // I386: call float (float, ...)* @test2a_any(float {{[^,]+}})
return (float) test2a_any((float) 0.5f);
}
float test3() {
extern __unknown_anytype test3_any;
- // CHECK: [[FN:%.*]] = load float (i32)** @test3_any,
- // CHECK: call float [[FN]](i32 5)
+ // COMMON: [[FN:%.*]] = load float (i32)** @test3_any,
+ // COMMON: call float [[FN]](i32 5)
return ((float(*)(int)) test3_any)(5);
}
@@ -36,22 +48,22 @@ namespace test4 {
extern __unknown_anytype test4_any2;
int test() {
- // CHECK: load i32* @_ZN5test410test4_any1E
- // CHECK: load i8* @_ZN5test410test4_any2E
+ // COMMON: load i32* @_ZN5test410test4_any1E
+ // COMMON: load i8* @_ZN5test410test4_any2E
return (int) test4_any1 + (char) test4_any2;
}
}
extern "C" __unknown_anytype test5_any();
void test5() {
- // CHECK: call void @test5_any()
+ // COMMON: call void @test5_any()
return (void) test5_any();
}
extern "C" __unknown_anytype test6_any(float *);
long test6() {
- // CHECK: call i64 @test6_any(float* null)
- return (long) test6_any(0);
+ // COMMON: call i64 @test6_any(float* null)
+ return (long long) test6_any(0);
}
struct Test7 {
@@ -59,7 +71,7 @@ struct Test7 {
};
extern "C" __unknown_anytype test7_any(int);
Test7 test7() {
- // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
+ // COMMON: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
return (Test7) test7_any(5);
}
@@ -71,29 +83,35 @@ struct Test8 {
};
void Test8::test() {
float f;
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
f = (int) foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
f = (int) foo(5);
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
f = (float) this->foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
f = (float) this->foo(5);
}
void test8(Test8 *p) {
double d;
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
d = (double) p->foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
d = (double) p->foo(5);
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
d = (bool) (*p).foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
d = (bool) (*p).foo(5);
}
extern "C" __unknown_anytype test9_foo;
void *test9() {
- // CHECK: ret i8* bitcast (i32* @test9_foo to i8*)
+ // COMMON: ret i8* bitcast (i32* @test9_foo to i8*)
return (int*) &test9_foo;
}
+
+// Don't explode on this.
+extern "C" __unknown_anytype test10_any(...);
+void test10() {
+ (void) test10_any(), (void) test10_any();
+}
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index 60dca99045ff..fad459b481bf 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -74,7 +74,7 @@ namespace ptrmem {
int S::*mem2;
};
- // CHECK: define i32 @_ZN6ptrmem4testEPNS_1SE
+ // CHECK-LABEL: define i32 @_ZN6ptrmem4testEPNS_1SE
int test(S *s) {
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
// CHECK: getelementptr
@@ -99,7 +99,7 @@ struct Test2 {
struct Test3 : public Test { };
-// CHECK: define void @_ZN6PR98011fEv
+// CHECK-LABEL: define void @_ZN6PR98011fEv
void f() {
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @_ZN6PR98014TestC1Ei
@@ -131,7 +131,7 @@ void f() {
namespace zeroinit {
struct S { int i; };
- // CHECK: define i32 @_ZN8zeroinit4testEv()
+ // CHECK-LABEL: define i32 @_ZN8zeroinit4testEv()
int test() {
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK: ret i32 0
@@ -148,7 +148,7 @@ namespace zeroinit {
void f();
};
- // CHECK: define void @_ZN8zeroinit9testX0_X1Ev
+ // CHECK-LABEL: define void @_ZN8zeroinit9testX0_X1Ev
void testX0_X1() {
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X1C1Ev
@@ -169,7 +169,7 @@ namespace zeroinit {
};
- // CHECK: define void @_ZN8zeroinit9testX0_X3Ev
+ // CHECK-LABEL: define void @_ZN8zeroinit9testX0_X3Ev
void testX0_X3() {
// CHECK-NOT: call void @llvm.memset
// CHECK: call void @_ZN8zeroinit2X3IiEC1Ev
@@ -201,7 +201,7 @@ namespace test6 {
void test() {
A arr[10][20] = { 5 };
};
- // CHECK: define void @_ZN5test64testEv()
+ // CHECK-LABEL: define void @_ZN5test64testEv()
// CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]],
// CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0
@@ -243,7 +243,7 @@ namespace PR11124 {
struct B : virtual A { int b; };
struct C : B { C(); };
C::C() : A(3), B() {}
- // CHECK: define void @_ZN7PR111241CC1Ev
+ // CHECK-LABEL: define void @_ZN7PR111241CC1Ev
// CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 12, i32 8, i1 false)
// CHECK-NEXT: call void @_ZN7PR111241BC2Ev
// Make sure C::C doesn't overwrite parts of A while it is zero-initializing B
@@ -251,18 +251,18 @@ namespace PR11124 {
struct B2 : virtual A { int B::*b; };
struct C2 : B2 { C2(); };
C2::C2() : A(3), B2() {}
- // CHECK: define void @_ZN7PR111242C2C1Ev
+ // CHECK-LABEL: define void @_ZN7PR111242C2C1Ev
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* {{.*}}, i64 16, i32 8, i1 false)
// CHECK-NEXT: call void @_ZN7PR111242B2C2Ev
}
// Ensure we produce an i1 here, and don't assert.
-// CHECK: define void @_Z9r170806_bv(
+// CHECK-LABEL: define void @_Z9r170806_bv(
// CHECK: call void @_Z9r170806_ab(i1 zeroext false)
void r170806_a(bool b = bool());
void r170806_b() { r170806_a(); }
-// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/vararg-conversion-ctor.cpp b/test/CodeGenCXX/vararg-conversion-ctor.cpp
index a49b1dba9961..e496f6dcd116 100644
--- a/test/CodeGenCXX/vararg-conversion-ctor.cpp
+++ b/test/CodeGenCXX/vararg-conversion-ctor.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t-64.ll
-// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s
+// RUN: FileCheck -check-prefix CHECK-LPLL64 --input-file=%t-64.ll %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/vararg-non-pod.cpp b/test/CodeGenCXX/vararg-non-pod.cpp
index 6c6f459ce505..9497179ddf05 100644
--- a/test/CodeGenCXX/vararg-non-pod.cpp
+++ b/test/CodeGenCXX/vararg-non-pod.cpp
@@ -8,7 +8,7 @@ struct X {
void vararg(...);
-// CHECK: define void @_Z4test1X
+// CHECK-LABEL: define void @_Z4test1X
void test(X x) {
// CHECK: call void @llvm.trap()
vararg(x);
diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp
index af34336a0ae2..31bbee9863a5 100644
--- a/test/CodeGenCXX/varargs.cpp
+++ b/test/CodeGenCXX/varargs.cpp
@@ -7,7 +7,7 @@ namespace test0 {
// though there is no way to do a va_begin. Otherwise, the optimizer
// will warn about 'dropped arguments' at the call site.
- // CHECK: define i32 @_ZN5test05test1Ez(...)
+ // CHECK-LABEL: define i32 @_ZN5test05test1Ez(...)
int test1(...) {
return -1;
}
@@ -30,7 +30,7 @@ namespace test1 {
A x;
foo(x);
}
- // CHECK: define void @_ZN5test14testEv()
+ // CHECK-LABEL: define void @_ZN5test14testEv()
// CHECK: [[X:%.*]] = alloca [[A:%.*]], align 4
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 4
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i8*
diff --git a/test/CodeGenCXX/variadic-templates.cpp b/test/CodeGenCXX/variadic-templates.cpp
index c56bec33a0f8..4974b6517b89 100644
--- a/test/CodeGenCXX/variadic-templates.cpp
+++ b/test/CodeGenCXX/variadic-templates.cpp
@@ -5,7 +5,7 @@ int get_num_types(Types...) {
return sizeof...(Types);
}
-// CHECK: define weak_odr i32 @_Z13get_num_typesIJifdEEiDpT_
+// CHECK-LABEL: define weak_odr i32 @_Z13get_num_typesIJifdEEiDpT_
// CHECK: ret i32 3
template int get_num_types(int, float, double);
@@ -13,7 +13,7 @@ template int get_num_types(int, float, double);
namespace test1 {
template <class... T> void foo() {
int values[sizeof...(T)+1] = { T::value... };
- // CHECK: define linkonce_odr void @_ZN5test13fooIJEEEvv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN5test13fooIJEEEvv()
// CHECK: alloca [1 x i32], align 4
}
diff --git a/test/CodeGenCXX/virt-dtor-gen.cpp b/test/CodeGenCXX/virt-dtor-gen.cpp
index 1a6c583c34f2..78a0b8193d74 100644
--- a/test/CodeGenCXX/virt-dtor-gen.cpp
+++ b/test/CodeGenCXX/virt-dtor-gen.cpp
@@ -7,4 +7,4 @@ class Foo {
};
Foo::~Foo() {}
-// CHECK: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
index f469636b2265..40e68f672232 100644
--- a/test/CodeGenCXX/virtual-base-cast.cpp
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -cxx-abi microsoft -emit-llvm %s -o - -triple i686-pc-win32 | FileCheck -check-prefix MSVC %s
struct A { int a; virtual int aa(); };
struct B { int b; virtual int bb(); };
@@ -17,6 +18,16 @@ A* a() { return x; }
// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
// CHECK: }
+// MSVC: @"\01?a@@YAPAUA@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
+// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: add nsw i32 0, %[[offset]]
+// MSVC: }
+
B* b() { return x; }
// CHECK: @_Z1bv() [[NUW]]
// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20
@@ -24,6 +35,18 @@ B* b() { return x; }
// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
// CHECK: }
+// Same as 'a' except we use a different vbtable offset.
+// MSVC: @"\01?b@@YAPAUB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 8
+// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: add nsw i32 0, %[[offset]]
+// MSVC: }
+
+
BB* c() { return x; }
// CHECK: @_Z1cv() [[NUW]]
// CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24
@@ -32,4 +55,35 @@ BB* c() { return x; }
// CHECK: add i32 [[VBASEOFFSETC]], 8
// CHECK: }
+// Same as 'a' except we use a different vbtable offset.
+// MSVC: @"\01?c@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
+// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: add nsw i32 0, %[[offset]]
+// MSVC: }
+
+// Put the vbptr at a non-zero offset inside a non-virtual base.
+struct E { int e; };
+struct F : E, D { int f; };
+
+F* y;
+
+BB* d() { return y; }
+
+// Same as 'c' except the vbptr offset is 4, changing the initial GEP and the
+// final add.
+// MSVC: @"\01?d@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
+// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: add nsw i32 4, %[[offset]]
+// MSVC: }
+
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp
index 2424d218d6b7..5014eaf2643b 100644
--- a/test/CodeGenCXX/virtual-base-destructor-call.cpp
+++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp
@@ -18,34 +18,34 @@ int main() {
// basic_iostream's complete dtor calls its base dtor, then its
// virtual base's dtor.
-// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_iostream's base dtor calls its non-virtual base dtor.
-// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* {{.*}}%this, i8** %vtt) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
// CHECK: }
-// basic_iostream's deleting dtor calls its complete dtor, then
-// operator delete().
-// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
-// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
-// CHECK: call {{.*}} @_ZdlPv
-
// basic_istream's complete dtor calls the base dtor,
// then its virtual base's base dtor.
-// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_istream's deleting dtor calls the complete dtor, then
// operator delete().
-// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev
// CHECK: call {{.*}} @_ZdlPv
+// basic_iostream's deleting dtor calls its complete dtor, then
+// operator delete().
+// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr
+// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
+// CHECK: call {{.*}} @_ZdlPv
+
// basic_istream's base dtor is a no-op.
-// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
+// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr
// CHECK-NOT: call
// CHECK: }
diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
index c9f13f853d1b..2878e95b52cd 100644
--- a/test/CodeGenCXX/virtual-bases.cpp
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -5,23 +5,23 @@ struct A {
};
// CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev
-// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr
A::A() { }
struct B : virtual A {
B();
};
-// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
-// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr
B::B() { }
struct C : virtual A {
C(bool);
};
-// CHECK: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr
-// CHECK: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr
C::C(bool) { }
// PR6251
@@ -39,7 +39,7 @@ struct D : B, C {
D();
};
-// CHECK: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr
// CHECK: call void @_ZN6PR62511AIcEC2Ev
// CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev
// CHECK: ret void
diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp
index 7ef50b23fa7c..ae3704f36928 100644
--- a/test/CodeGenCXX/virtual-destructor-calls.cpp
+++ b/test/CodeGenCXX/virtual-destructor-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s
struct Member {
~Member();
@@ -21,12 +21,12 @@ struct B : A {
// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev
// Deleting dtor: defers to the complete dtor.
-// CHECK: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN1BD1Ev
// CHECK: call void @_ZdlPv
// Base dtor: actually calls A's base dtor.
-// CHECK: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN6MemberD1Ev
// CHECK: call void @_ZN1AD2Ev
@@ -41,7 +41,7 @@ C::~C() { }
// Complete dtor: just an alias (checked above).
// Deleting dtor: defers to the complete dtor.
-// CHECK: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr
// CHECK: call void @_ZN1CD1Ev
// CHECK: call void @_ZdlPv
diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
index afa658f7d374..624c89dcdae4 100644
--- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
+++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
@@ -9,7 +9,7 @@ struct B {
void B::f() { }
-// CHECK: define i32 @_ZN1D1gEv(%struct.D* %this)
+// CHECK-LABEL: define i32 @_ZN1D1gEv(%struct.D* %this)
// CHECK: declare void @_ZN1B1gEv()
struct C;
diff --git a/test/CodeGenCXX/visibility-hidden-extern-templates.cpp b/test/CodeGenCXX/visibility-hidden-extern-templates.cpp
index 7629b77c2cee..549e674740ff 100644
--- a/test/CodeGenCXX/visibility-hidden-extern-templates.cpp
+++ b/test/CodeGenCXX/visibility-hidden-extern-templates.cpp
@@ -14,13 +14,13 @@ extern template struct X<char>;
// <rdar://problem/8109763>
void test_X(X<int> xi, X<char> xc) {
- // CHECK: define weak_odr hidden void @_ZN1XIiE1fEv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN1XIiE1fEv
xi.f();
- // CHECK: define weak_odr hidden void @_ZN1XIiE1gEv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN1XIiE1gEv
xi.g();
// CHECK: declare void @_ZN1XIcE1fEv
xc.f();
- // CHECK: define available_externally void @_ZN1XIcE1gEv
+ // CHECK-LABEL: define available_externally void @_ZN1XIcE1gEv
xc.g();
}
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index e5bc743e4da9..7c0757b2829a 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -37,31 +37,31 @@ struct __attribute__((visibility("default"))) X2 {
extern template struct X1<float>;
void use(X0 *x0, X1<int> *x1, X2 *x2, X1<float> *x3) {
- // CHECK: define linkonce_odr void @_ZN2X02f1Ev
+ // CHECK-LABEL: define linkonce_odr void @_ZN2X02f1Ev
x0->f1();
- // CHECK: define linkonce_odr hidden void @_ZN2X02f2Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f2Ev
x0->f2();
- // CHECK: define linkonce_odr hidden void @_ZN2X02f3Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f3Ev
x0->f3();
- // CHECK: define linkonce_odr hidden void @_ZN2X02f5Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f5Ev
X0::f5();
- // CHECK: define linkonce_odr hidden void @_ZN2X02f6Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f6Ev
x0->X0::f6();
- // CHECK: define linkonce_odr void @_ZN2X1IiE2f1Ev
+ // CHECK-LABEL: define linkonce_odr void @_ZN2X1IiE2f1Ev
x1->f1();
- // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f2Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f2Ev
x1->f2();
- // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f3Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f3Ev
x1->f3();
- // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f4Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f4Ev
x1->f4();
- // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f5Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f5Ev
X1<int>::f5();
- // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f6Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f6Ev
x1->X1::f6();
- // CHECK: define linkonce_odr hidden void @_ZN2X22f2Ev
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X22f2Ev
x2->f2();
- // CHECK: define available_externally void @_ZN2X1IfE2f2Ev
+ // CHECK-LABEL: define available_externally void @_ZN2X1IfE2f2Ev
x3->f2();
}
@@ -95,7 +95,7 @@ namespace test2 {
ns::foo<arg>();
}
- // CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv()
+ // CHECK-LABEL: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv()
}
namespace PR11642 {
@@ -106,7 +106,7 @@ namespace PR11642 {
};
extern template class Foo<int>;
template class Foo<int>;
- // CHECK: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi
+ // CHECK-LABEL: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi
}
// Test that clang implements the new gcc behaviour for inline functions.
@@ -122,9 +122,9 @@ namespace test3 {
foo();
zed<int>();
}
- // CHECK: define weak_odr void @_ZN5test33zedIfEEvv
- // CHECK: define linkonce_odr hidden void @_ZN5test33fooEv
- // CHECK: define linkonce_odr hidden void @_ZN5test33zedIiEEvv
+ // CHECK-LABEL: define weak_odr void @_ZN5test33zedIfEEvv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test33fooEv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test33zedIiEEvv
}
namespace test4 {
@@ -133,7 +133,7 @@ namespace test4 {
void bar() {
foo();
}
- // CHECK: define available_externally void @_ZN5test43fooE
+ // CHECK-LABEL: define available_externally void @_ZN5test43fooE
}
namespace test5 {
diff --git a/test/CodeGenCXX/visibility-ms-compat.cpp b/test/CodeGenCXX/visibility-ms-compat.cpp
index 58a8fed62e04..25446cdf06f9 100644
--- a/test/CodeGenCXX/visibility-ms-compat.cpp
+++ b/test/CodeGenCXX/visibility-ms-compat.cpp
@@ -22,7 +22,7 @@ namespace test0 {
};
void A::foo() { bar(); }
- // CHECK: define hidden void @_ZN5test01A3fooEv()
+ // CHECK-LABEL: define hidden void @_ZN5test01A3fooEv()
// CHECK: declare void @_ZN5test01A3barEv()
const std::type_info &ti = typeid(A);
@@ -38,7 +38,7 @@ namespace test1 {
};
void A::foo() { bar(); }
- // CHECK: define hidden void @_ZN5test11A3fooEv()
+ // CHECK-LABEL: define hidden void @_ZN5test11A3fooEv()
// CHECK: declare hidden void @_ZN5test11A3barEv()
const std::type_info &ti = typeid(A);
@@ -54,7 +54,7 @@ namespace test2 {
};
void A::foo() { bar(); }
- // CHECK: define void @_ZN5test21A3fooEv()
+ // CHECK-LABEL: define void @_ZN5test21A3fooEv()
// CHECK: declare void @_ZN5test21A3barEv()
const std::type_info &ti = typeid(A);
@@ -71,7 +71,7 @@ namespace test3 {
};
template void B<A>::foo();
- // CHECK: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv()
+ // CHECK-LABEL: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv()
// CHECK: declare void @_ZN5test31BINS_1AEE3barEv()
const std::type_info &ti = typeid(B<A>);
@@ -87,7 +87,7 @@ namespace test4 {
};
template void B<A>::foo();
- // CHECK: define weak_odr void @_ZN5test41BINS_1AEE3fooEv()
+ // CHECK-LABEL: define weak_odr void @_ZN5test41BINS_1AEE3fooEv()
// CHECK: declare void @_ZN5test41BINS_1AEE3barEv()
const std::type_info &ti = typeid(B<A>);
@@ -103,7 +103,7 @@ namespace test5 {
};
template void B<A>::foo();
- // CHECK: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv()
+ // CHECK-LABEL: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv()
// CHECK: declare hidden void @_ZN5test51BINS_1AEE3barEv()
const std::type_info &ti = typeid(B<A>);
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 87add446ba7b..1c4d5bb8e7a8 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -139,12 +139,16 @@ namespace test27 {
// CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
// CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
// CHECK-HIDDEN: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr hidden global i64
+// CHECK: @_ZZN6test681fC1EvE4test = linkonce_odr global
+// CHECK: @_ZGVZN6test681fC1EvE4test = linkonce_odr global
+// CHECK-HIDDEN: @_ZZN6test681fC1EvE4test = linkonce_odr hidden global
+// CHECK-HIDDEN: @_ZGVZN6test681fC1EvE4test = linkonce_odr hidden global
// CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant
// CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant
// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant
namespace Test1 {
- // CHECK: define hidden void @_ZN5Test11fEv
+ // CHECK-LABEL: define hidden void @_ZN5Test11fEv
void HIDDEN f() { }
}
@@ -155,7 +159,7 @@ namespace Test2 {
};
// A::f is a member function of a hidden class.
- // CHECK: define hidden void @_ZN5Test21A1fEv
+ // CHECK-LABEL: define hidden void @_ZN5Test21A1fEv
void A::f() { }
}
@@ -167,7 +171,7 @@ namespace Test3 {
};
// B is a nested class where its parent class is hidden.
- // CHECK: define hidden void @_ZN5Test31A1B1fEv
+ // CHECK-LABEL: define hidden void @_ZN5Test31A1B1fEv
void A::B::f() { }
}
@@ -175,7 +179,7 @@ namespace Test4 HIDDEN {
int VariableInHiddenNamespace = 10;
// Test4::g is in a hidden namespace.
- // CHECK: define hidden void @_ZN5Test41gEv
+ // CHECK-LABEL: define hidden void @_ZN5Test41gEv
void g() { }
struct DEFAULT A {
@@ -183,7 +187,7 @@ namespace Test4 HIDDEN {
};
// A has default visibility.
- // CHECK: define void @_ZN5Test41A1fEv
+ // CHECK-LABEL: define void @_ZN5Test41A1fEv
void A::f() { }
}
@@ -191,13 +195,13 @@ namespace Test5 {
namespace NS HIDDEN {
// f is in NS which is hidden.
- // CHECK: define hidden void @_ZN5Test52NS1fEv()
+ // CHECK-LABEL: define hidden void @_ZN5Test52NS1fEv()
void f() { }
}
namespace NS {
// g is in NS, but this NS decl is not hidden.
- // CHECK: define void @_ZN5Test52NS1gEv
+ // CHECK-LABEL: define void @_ZN5Test52NS1gEv
void g() { }
}
}
@@ -231,7 +235,7 @@ namespace Test7 {
class B : public A {};
B b; // top of file
- // CHECK: define linkonce_odr hidden void @_ZN5Test74ArefILZNS_1aEEE3fooEv()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN5Test74ArefILZNS_1aEEE3fooEv()
void test() {
Aref<a>::foo();
}
@@ -240,7 +244,7 @@ namespace Test7 {
namespace Test8 {
void foo();
void bar() {}
- // CHECK-HIDDEN: define hidden void @_ZN5Test83barEv()
+ // CHECK-HIDDEN-LABEL: define hidden void @_ZN5Test83barEv()
// CHECK-HIDDEN: declare void @_ZN5Test83fooEv()
void test() {
@@ -256,8 +260,8 @@ namespace Test9 {
void DEFAULT test9_fun(struct A *a) { }
struct A DEFAULT test9_var; // above
}
- // CHECK: define void @test9_fun(
- // CHECK-HIDDEN: define void @test9_fun(
+ // CHECK-LABEL: define void @test9_fun(
+ // CHECK-HIDDEN-LABEL: define void @test9_fun(
void test() {
A a = test9_var;
@@ -273,8 +277,8 @@ namespace Test10 {
void foo(A*);
};
- // CHECK: define void @_ZN6Test101B3fooEPNS_1AE(
- // CHECK-HIDDEN: define void @_ZN6Test101B3fooEPNS_1AE(
+ // CHECK-LABEL: define void @_ZN6Test101B3fooEPNS_1AE(
+ // CHECK-HIDDEN-LABEL: define void @_ZN6Test101B3fooEPNS_1AE(
void B::foo(A*) {}
}
@@ -291,10 +295,10 @@ namespace Test11 {
a.bar();
}
- // CHECK: define linkonce_odr void @_ZN6Test111A3fooEv(
- // CHECK: define linkonce_odr void @_ZN6Test111A3barEv(
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6Test111A3fooEv(
- // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test111A3barEv(
+ // CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3fooEv(
+ // CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3barEv(
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6Test111A3fooEv(
+ // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6Test111A3barEv(
}
// Tested at top of file.
@@ -481,7 +485,7 @@ namespace Test20 {
static void test1();
};
- // CHECK: define hidden void @_ZN6Test201AILj0EE5test0Ev()
+ // CHECK-LABEL: define hidden void @_ZN6Test201AILj0EE5test0Ev()
void A<0>::test0() {}
// CHECK: declare hidden void @_ZN6Test201AILj0EE5test1Ev()
@@ -495,7 +499,7 @@ namespace Test20 {
static void test3();
};
- // CHECK: define void @_ZN6Test201AILj1EE5test2Ev()
+ // CHECK-LABEL: define void @_ZN6Test201AILj1EE5test2Ev()
void A<1>::test2() {}
// CHECK: declare void @_ZN6Test201AILj1EE5test3Ev()
@@ -511,7 +515,7 @@ namespace Test20 {
static void test5();
};
- // CHECK: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev()
void test4() {
B<A<2> >::test4();
}
@@ -529,7 +533,7 @@ namespace test21 {
DEFAULT void foo() {}
};
- // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
+ // CHECK-LABEL: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
template void A<en>::foo();
}
@@ -556,13 +560,13 @@ namespace test22 {
B<A2>::bar();
}
// CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv()
- // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
// CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv()
- // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv()
// CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv()
- // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
+ // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
// CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv()
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv()
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv()
}
namespace PR10113 {
@@ -573,14 +577,14 @@ namespace PR10113 {
};
}
template class foo::bar<char>;
- // CHECK: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
- // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
struct zed {
};
template class foo::bar<zed>;
- // CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv
}
namespace PR11690 {
@@ -589,13 +593,13 @@ namespace PR11690 {
}
};
template class DEFAULT Class<char>;
- // CHECK: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
- // CHECK-HIDDEN: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
+ // CHECK-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
template<class T> void Method() {}
template DEFAULT void Method<char>();
- // CHECK: define weak_odr void @_ZN7PR116906MethodIcEEvv
- // CHECK-HIDDEN: define weak_odr void @_ZN7PR116906MethodIcEEvv
+ // CHECK-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv
}
namespace PR11690_2 {
@@ -610,8 +614,8 @@ namespace PR11690_2 {
struct baz {
};
template class foo::zed<baz>;
- // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
+ // CHECK-LABEL: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
}
namespace test23 {
@@ -629,8 +633,8 @@ namespace test23 {
X<A> y;
y.f();
}
- // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
}
namespace PR12001 {
@@ -643,8 +647,8 @@ namespace PR12001 {
void f() {
Bind(Version());
}
- // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+ // CHECK-LABEL: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
}
namespace test24 {
@@ -659,8 +663,8 @@ namespace test24 {
S s;
s.mem<A>();
}
- // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
}
namespace test26 {
@@ -672,8 +676,8 @@ namespace test26 {
template<>
void C<int>::f() { }
- // CHECK: define void @_ZN6test261CIiE1fEv
- // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv
+ // CHECK-LABEL: define void @_ZN6test261CIiE1fEv
+ // CHECK-HIDDEN-LABEL: define void @_ZN6test261CIiE1fEv
}
namespace test31 {
@@ -697,8 +701,8 @@ namespace test32 {
};
void A::B::baz() {
}
- // CHECK: define void @_ZN6test321A1B3bazEv
- // CHECK-HIDDEN: define void @_ZN6test321A1B3bazEv
+ // CHECK-LABEL: define void @_ZN6test321A1B3bazEv
+ // CHECK-HIDDEN-LABEL: define void @_ZN6test321A1B3bazEv
}
namespace test33 {
@@ -709,8 +713,8 @@ namespace test33 {
struct HIDDEN zed {
};
template class DEFAULT foo<zed>;
- // CHECK: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
}
namespace test34 {
@@ -719,8 +723,8 @@ namespace test34 {
template<class T>
void bar() {}
template DEFAULT void bar<foo>();
- // CHECK: define weak_odr void @_ZN6test343barINS_3fooEEEvv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test343barINS_3fooEEEvv
+ // CHECK-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv
}
namespace test35 {
@@ -737,8 +741,8 @@ namespace test35 {
template class foo<zed>;
class DEFAULT zed {
};
- // CHECK: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv
}
namespace test36 {
@@ -749,8 +753,8 @@ namespace test36 {
class DEFAULT S1 {};
struct HIDDEN S2 {};
template class foo<S1, S2>;
- // CHECK: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
}
namespace test37 {
@@ -759,8 +763,8 @@ namespace test37 {
template<class T>
DEFAULT void bar() {}
template DEFAULT void bar<foo>();
- // CHECK: define weak_odr void @_ZN6test373barINS_3fooEEEvv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test373barINS_3fooEEEvv
+ // CHECK-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv
}
namespace test38 {
@@ -771,8 +775,8 @@ namespace test38 {
struct HIDDEN zed {
};
template class foo<zed>;
- // CHECK: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
}
namespace test39 {
@@ -790,19 +794,19 @@ namespace test39 {
template void A<hidden_t>::B<hidden_t>::temp<default_t>();
template void A<hidden_t>::B<hidden_t>::temp<hidden_t>();
- // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
- // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
- // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
// GCC produces a default for this one. Why?
- // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
// GCC produces a default for this one. Why?
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
}
namespace test42 {
@@ -817,8 +821,8 @@ namespace test42 {
};
void bar<foo>::zed() {
}
- // CHECK: define void @_ZN6test423barINS_3fooEE3zedEv
- // CHECK-HIDDEN: define void @_ZN6test423barINS_3fooEE3zedEv
+ // CHECK-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv
+ // CHECK-HIDDEN-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv
}
namespace test43 {
@@ -830,8 +834,8 @@ namespace test43 {
template <>
DEFAULT void bar<foo>() {
}
- // CHECK: define void @_ZN6test433barINS_3fooEEEvv
- // CHECK-HIDDEN: define void @_ZN6test433barINS_3fooEEEvv
+ // CHECK-LABEL: define void @_ZN6test433barINS_3fooEEEvv
+ // CHECK-HIDDEN-LABEL: define void @_ZN6test433barINS_3fooEEEvv
}
namespace test44 {
@@ -844,8 +848,8 @@ namespace test44 {
}
template struct DEFAULT foo<bar>;
foo<bar> x;
- // CHECK: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
- // CHECK-HIDDEN: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
+ // CHECK-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
+ // CHECK-HIDDEN-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
}
namespace test45 {
@@ -861,8 +865,8 @@ namespace test45 {
}
template struct DEFAULT foo<int>::bar<zed>;
foo<int>::bar<zed> x;
- // CHECK: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
- // CHECK-HIDDEN: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
+ // CHECK-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
+ // CHECK-HIDDEN-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
}
namespace test46 {
@@ -876,8 +880,8 @@ namespace test46 {
void zed() {
foo<bar>();
}
- // CHECK: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
- // CHECK-HIDDEN: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
+ // CHECK-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
+ // CHECK-HIDDEN-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
}
namespace test47 {
@@ -893,8 +897,8 @@ namespace test47 {
void baz() {
foo::bar<zed>();
}
- // CHECK: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
- // CHECK-HIDDEN: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
+ // CHECK-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
+ // CHECK-HIDDEN-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
}
namespace test49 {
@@ -914,8 +918,8 @@ namespace test49 {
};
template void bar::zed<&x>();
- // CHECK: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
}
namespace test50 {
@@ -932,8 +936,8 @@ namespace test50 {
}
};
template void bar<&x>::zed();
- // CHECK: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
}
namespace test51 {
@@ -948,8 +952,8 @@ namespace test51 {
void DEFAULT zed() {
}
template void zed<&x>();
- // CHECK: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv
- // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv
+ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv
}
namespace test52 {
@@ -967,8 +971,8 @@ namespace test52 {
void f() {
zed<nullptr>();
}
- // CHECK: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
- // CHECK-HIDDEN: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
+ // CHECK-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
+ // CHECK-HIDDEN-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
}
namespace test53 {
@@ -1070,8 +1074,8 @@ namespace test58 {
bar<foo>::zed();
}
#pragma GCC visibility pop
- // CHECK: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
}
namespace test59 {
@@ -1082,12 +1086,12 @@ namespace test59 {
void test() {}
void use() {
test<&g, &f>();
- // CHECK: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
test<&f, &g>();
- // CHECK: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
}
}
@@ -1100,12 +1104,12 @@ namespace test60 {
void test() {}
void use() {
test<a, b>();
- // CHECK: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
test<b, a>();
- // CHECK: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
- // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
+ // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
}
}
@@ -1167,8 +1171,8 @@ namespace test63 {
A::foo<E0>();
A::B<E0>::foo();
}
- // CHECK: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
- // CHECK: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
}
// Don't ignore the visibility of template arguments just because we
@@ -1180,7 +1184,7 @@ namespace test64 {
};
template class B<A>;
- // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
+ // CHECK-LABEL: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
}
namespace test65 {
@@ -1196,23 +1200,23 @@ namespace test65 {
static void foo() {}
};
- // CHECK: define void @_ZN6test651BINS_1AEE4funcEv()
+ // CHECK-LABEL: define void @_ZN6test651BINS_1AEE4funcEv()
template <> DEFAULT void B<A>::func() {}
- // CHECK: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
+ // CHECK-LABEL: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
template <> template <> DEFAULT void B<A>::funcT2<A>() {}
- // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
- // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
template <> template <class T> DEFAULT void B<A>::funcT1() {}
- // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
template <> struct DEFAULT B<A>::Inner {
static void foo() {}
};
- // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
- // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
template <> template <class U> struct DEFAULT B<A>::InnerT {
static void foo() {}
};
@@ -1236,8 +1240,8 @@ namespace test66 {
class foo;
class DEFAULT foo;
template struct barT<foo>;
- // CHECK: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
template <int* I>
struct DEFAULT barI {
@@ -1246,8 +1250,8 @@ namespace test66 {
extern int I;
extern int I DEFAULT;
template struct barI<&I>;
- // CHECK: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
typedef void (*fType)(void);
template<fType F>
@@ -1257,8 +1261,8 @@ namespace test66 {
void F();
void F() DEFAULT;
template struct barF<F>;
- // CHECK: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
}
namespace test67 {
@@ -1274,6 +1278,34 @@ namespace test67 {
class DEFAULT foo;
template struct bar<foo>;
- // CHECK: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
+}
+
+namespace test68 {
+ class A { public: ~A(); };
+ class f {
+ public:
+ f() {
+ static A test;
+ }
+ };
+ void g() {
+ f a;
+ }
+ // Check lines at top of file.
+}
+
+namespace test69 {
+ // PR18174
+ namespace foo {
+ void f();
+ }
+ namespace foo {
+ void f() {};
+ }
+ namespace foo __attribute__((visibility("hidden"))) {
+ }
+ // CHECK-LABEL: define void @_ZN6test693foo1fEv
+ // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv
}
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
index b523c769d541..b22f21c3faf3 100644
--- a/test/CodeGenCXX/vla.cpp
+++ b/test/CodeGenCXX/vla.cpp
@@ -16,7 +16,7 @@ int f() {
// rdar://problem/9506377
void test0(void *array, int n) {
- // CHECK: define void @_Z5test0Pvi(
+ // 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
diff --git a/test/CodeGenCXX/volatile.cpp b/test/CodeGenCXX/volatile.cpp
index 6ebb2f11fca5..38c8829347c2 100644
--- a/test/CodeGenCXX/volatile.cpp
+++ b/test/CodeGenCXX/volatile.cpp
@@ -11,7 +11,7 @@ namespace test0 {
volatile A *array;
- // CHECK: define void @_ZN5test04testENS_1AE(
+ // CHECK-LABEL: define void @_ZN5test04testENS_1AE(
void test(A t) {
// CHECK: [[ARR:%.*]] = load [[A:%.*]]** @_ZN5test05arrayE, align 8
// CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [[A]]* [[ARR]], i64 0
@@ -24,7 +24,7 @@ namespace test0 {
namespace test1 {
volatile int *x;
- // CHECK: define void @_ZN5test14testEv()
+ // CHECK-LABEL: define void @_ZN5test14testEv()
void test() {
// CHECK: [[TMP:%.*]] = load i32** @_ZN5test11xE, align 8
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp
index 693b36abe502..282bd2a172ad 100644
--- a/test/CodeGenCXX/vtable-available-externally.cpp
+++ b/test/CodeGenCXX/vtable-available-externally.cpp
@@ -1,19 +1,11 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t
// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t
// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t
// RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-TEST7 %s < %t
#include <typeinfo>
-// Test1::A's key function (f) is not defined in this translation
-// unit, but in order to devirtualize calls, we emit the v-table with
-// available_externally linkage.
-//
-// There's no real reason to do this to the RTTI, though.
-
-// CHECK-TEST1: @_ZTVN5Test11AE = available_externally
-// CHECK-TEST1: @_ZTIN5Test11AE = external constant i8*
+// CHECK-TEST1: @_ZTVN5Test11AE = external unnamed_addr constant
namespace Test1 {
struct A {
@@ -28,7 +20,7 @@ void f(A* a) {
a->f();
};
-// CHECK: define void @_ZN5Test11gEv
+// CHECK-LABEL: define void @_ZN5Test11gEv
// CHECK: call void @_ZN5Test11A1fEv
void g() {
A a;
@@ -106,7 +98,7 @@ void f() {
}
// PR9130, test that we emit a definition of A::f.
-// CHECK-TEST5: define linkonce_odr void @_ZN5Test51A1fEv
+// CHECK-TEST5-LABEL: define linkonce_odr void @_ZN5Test51A1fEv
namespace Test5 {
struct A {
@@ -159,14 +151,4 @@ struct c11 : c10, c1{
struct c28 : virtual c11{
void f6 ();
};
-
-// CHECK-TEST7: define void @_ZN5Test79check_c28Ev
-// CHECK-TEST7: call void @_ZN5Test73c282f6Ev
-// CHECK-TEST7: ret void
-void check_c28 () {
- c28 obj;
- c11 *ptr = &obj;
- ptr->f6 ();
-}
-
}
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index 1e831d2d8349..ca5384d6e031 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t
// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
// RUN: FileCheck --check-prefix=CHECK-3 %s < %t
@@ -44,6 +44,7 @@
// RUN: FileCheck --check-prefix=CHECK-43 %s < %t
// RUN: FileCheck --check-prefix=CHECK-44 %s < %t
// RUN: FileCheck --check-prefix=CHECK-45 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-46 %s < %t
// For now, just verify this doesn't crash.
namespace test0 {
@@ -61,6 +62,9 @@ namespace Test1 {
// CHECK-1-NEXT: 1 | Test1::A RTTI
// CHECK-1-NEXT: -- (Test1::A, 0) vtable address --
// CHECK-1-NEXT: 2 | void Test1::A::f()
+//
+// CHECK-1: VTable indices for 'Test1::A' (1 entries).
+// CHECK-1-NEXT: 0 | void Test1::A::f()
struct A {
virtual void f();
};
@@ -82,6 +86,15 @@ namespace Test2 {
// CHECK-2-NEXT: 6 | Test2::A::~A() [deleting]
// CHECK-2-NEXT: 7 | void Test2::A::h()
// CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(const Test2::A &)
+//
+// CHECK-2: VTable indices for 'Test2::A' (7 entries).
+// CHECK-2-NEXT: 0 | void Test2::A::f()
+// CHECK-2-NEXT: 1 | void Test2::A::f() const
+// CHECK-2-NEXT: 2 | Test2::A *Test2::A::g(int)
+// CHECK-2-NEXT: 3 | Test2::A::~A() [complete]
+// CHECK-2-NEXT: 4 | Test2::A::~A() [deleting]
+// CHECK-2-NEXT: 5 | void Test2::A::h()
+// CHECK-2-NEXT: 6 | Test2::A &Test2::A::operator=(const Test2::A &)
struct A {
virtual void f();
virtual void f() const;
@@ -103,6 +116,12 @@ void A::f() { }
// CHECK-3-NEXT: 3 | void Test2::B::g() [pure]
// CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure]
// CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure]
+//
+// CHECK-3: VTable indices for 'Test2::B' (4 entries).
+// CHECK-3-NEXT: 0 | void Test2::B::f()
+// CHECK-3-NEXT: 1 | void Test2::B::g()
+// CHECK-3-NEXT: 2 | Test2::B::~B() [complete]
+// CHECK-3-NEXT: 3 | Test2::B::~B() [deleting]
struct B {
virtual void f();
virtual void g() = 0;
@@ -123,6 +142,9 @@ namespace Test3 {
// CHECK-4-NEXT: 1 | Test3::A RTTI
// CHECK-4-NEXT: -- (Test3::A, 0) vtable address --
// CHECK-4-NEXT: 2 | void Test3::A::f()
+//
+// CHECK-4: VTable indices for 'Test3::A' (1 entries).
+// CHECK-4-NEXT: 0 | void Test3::A::f()
struct A {
virtual void f();
};
@@ -135,6 +157,10 @@ void A::f() { }
// CHECK-5-NEXT: -- (Test3::B, 0) vtable address --
// CHECK-5-NEXT: 2 | void Test3::B::f()
// CHECK-5-NEXT: 3 | void Test3::B::g()
+//
+// CHECK-5: VTable indices for 'Test3::B' (2 entries).
+// CHECK-5-NEXT: 0 | void Test3::B::f()
+// CHECK-5-NEXT: 1 | void Test3::B::g()
struct B : A {
virtual void f();
virtual void g();
@@ -149,6 +175,10 @@ void B::f() { }
// CHECK-6-NEXT: 2 | void Test3::A::f()
// CHECK-6-NEXT: 3 | void Test3::C::g()
// CHECK-6-NEXT: 4 | void Test3::C::h()
+//
+// CHECK-6: VTable indices for 'Test3::C' (2 entries).
+// CHECK-6-NEXT: 1 | void Test3::C::g()
+// CHECK-6-NEXT: 2 | void Test3::C::h()
struct C : A {
virtual void g();
virtual void h();
@@ -164,6 +194,11 @@ void C::g() { }
// CHECK-7-NEXT: 2 | void Test3::D::f()
// CHECK-7-NEXT: 3 | void Test3::D::g()
// CHECK-7-NEXT: 4 | void Test3::D::h()
+//
+// CHECK-7: VTable indices for 'Test3::D' (3 entries).
+// CHECK-7-NEXT: 0 | void Test3::D::f()
+// CHECK-7-NEXT: 1 | void Test3::D::g()
+// CHECK-7-NEXT: 2 | void Test3::D::h()
struct D : B {
virtual void f();
virtual void g();
@@ -193,7 +228,9 @@ struct A {
// CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f()
// CHECK-8-NEXT: [return adjustment: 4 non-virtual]
// CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f()
-
+//
+// CHECK-8: VTable indices for 'Test4::B' (1 entries).
+// CHECK-8-NEXT: 1 | Test4::R3 *Test4::B::f()
struct B : A {
virtual R3 *f();
};
@@ -215,6 +252,9 @@ struct C {
// CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f()
// CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
// CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f()
+//
+// CHECK-9: VTable indices for 'Test4::D' (1 entries).
+// CHECK-9-NEXT: 1 | Test4::V2 *Test4::D::f()
struct D : C {
virtual V2 *f();
};
@@ -231,7 +271,9 @@ struct V3 : virtual R3 { int r3; };
// CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f()
// CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset]
// CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f()
-
+//
+// CHECK-10: VTable indices for 'Test4::E' (1 entries).
+// CHECK-10-NEXT: 1 | Test4::V3 *Test4::E::f()
struct E : A {
virtual V3 *f();
};
@@ -247,6 +289,10 @@ V3 *E::f() { return 0;}
// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure]
// CHECK-11-NEXT: 3 | void Test4::F::g()
// CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure]
+//
+// CHECK-11: VTable indices for 'Test4::F' (2 entries).
+// CHECK-11-NEXT: 1 | void Test4::F::g()
+// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f()
struct F : A {
virtual void g();
virtual R3 *f() = 0;
@@ -289,6 +335,9 @@ struct B2 : A {
// CHECK-12-NEXT: -- (Test5::B2, 16) vtable address --
// CHECK-12-NEXT: 7 | void Test5::A::f()
// CHECK-12-NEXT: 8 | void Test5::B2::g()
+//
+// CHECK-12: VTable indices for 'Test5::C' (1 entries).
+// CHECK-12-NEXT: 2 | void Test5::C::h()
struct C : B1, B2 {
virtual void h();
};
@@ -319,6 +368,9 @@ struct A2 {
// CHECK-13-NEXT: -- (Test6::A2, 16) vtable address --
// CHECK-13-NEXT: 5 | void Test6::C::f()
// CHECK-13-NEXT: [this adjustment: -16 non-virtual]
+//
+// CHECK-13: VTable indices for 'Test6::C' (1 entries).
+// CHECK-13-NEXT: 0 | void Test6::C::f()
struct C : A1, A2 {
virtual void f();
};
@@ -360,6 +412,9 @@ struct C { virtual void c(); };
// CHECK-14-NEXT: -- (Test7::B2, 24) vtable address --
// CHECK-14-NEXT: 9 | void Test7::D::f()
// CHECK-14-NEXT: [this adjustment: -24 non-virtual]
+//
+// CHECK-14: VTable indices for 'Test7::D' (1 entries).
+// CHECK-14-NEXT: 1 | void Test7::D::f()
struct D : C, B1, B2 {
virtual void f();
};
@@ -379,7 +434,10 @@ struct A { };
// CHECK-15-NEXT: 1 | Test8::B RTTI
// CHECK-15-NEXT: -- (Test8::B, 0) vtable address --
// CHECK-15-NEXT: 2 | void Test8::B::f()
-struct B : A {
+//
+// CHECK-15: VTable indices for 'Test8::B' (1 entries).
+// CHECK-15-NEXT: 0 | void Test8::B::f()
+struct B : A {
virtual void f();
};
void B::f() { }
@@ -400,6 +458,9 @@ struct A2 { int a2; };
// CHECK-16-NEXT: 3 | Test9::B RTTI
// CHECK-16-NEXT: -- (Test9::B, 0) vtable address --
// CHECK-16-NEXT: 4 | void Test9::B::f()
+//
+// CHECK-16: VTable indices for 'Test9::B' (1 entries).
+// CHECK-16-NEXT: 0 | void Test9::B::f()
struct B : virtual A1, virtual A2 {
int b;
@@ -430,6 +491,9 @@ struct A2 { virtual void a2(); };
// CHECK-17-NEXT: 5 | Test10::C RTTI
// CHECK-17-NEXT: -- (Test10::A2, 8) vtable address --
// CHECK-17-NEXT: 6 | void Test10::A2::a2()
+//
+// CHECK-17: VTable indices for 'Test10::C' (1 entries).
+// CHECK-17-NEXT: 1 | void Test10::C::f()
struct B : A1, A2 {
int b;
};
@@ -461,6 +525,9 @@ struct B : A1, virtual A2 {
// CHECK-18-NEXT: 5 | vbase_offset (16)
// CHECK-18-NEXT: 6 | offset_to_top (-8)
// CHECK-18-NEXT: 7 | Test11::C RTTI
+//
+// CHECK-18: VTable indices for 'Test11::C' (1 entries).
+// CHECK-18-NEXT: 0 | void Test11::C::f()
struct C : virtual B {
virtual void f();
};
@@ -498,6 +565,10 @@ namespace Test12 {
// CHECK-19-NEXT: 17 | Test12::B RTTI
// CHECK-19-NEXT: -- (Test12::A3, 40) vtable address --
// CHECK-19-NEXT: 18 | void Test12::A3::a3()
+//
+// CHECK-19: VTable indices for 'Test12::B' (2 entries).
+// CHECK-19-NEXT: 0 | void Test12::B::f()
+// CHECK-19-NEXT: 1 | void Test12::B::a()
struct A1 {
virtual void a1();
int a;
@@ -548,6 +619,9 @@ struct B : virtual A {
// CHECK-20-NEXT: -- (Test13::B, 0) vtable address --
// CHECK-20-NEXT: -- (Test13::C, 0) vtable address --
// CHECK-20-NEXT: 5 | void Test13::C::f()
+//
+// CHECK-20: VTable indices for 'Test13::C' (1 entries).
+// CHECK-20-NEXT: 0 | void Test13::C::f()
struct C : virtual B, virtual A {
virtual void f();
};
@@ -577,6 +651,9 @@ struct C : virtual B { };
// CHECK-21-NEXT: -- (Test14::C, 0) vtable address --
// CHECK-21-NEXT: -- (Test14::D, 0) vtable address --
// CHECK-21-NEXT: 4 | void Test14::D::f()
+//
+// CHECK-21: VTable indices for 'Test14::D' (1 entries).
+// CHECK-21-NEXT: 0 | void Test14::D::f()
struct D : C, virtual B {
virtual void f();
};
@@ -608,6 +685,9 @@ struct C : virtual B { };
// CHECK-22-NEXT: -- (Test15::B, 8) vtable address --
// CHECK-22-NEXT: -- (Test15::C, 8) vtable address --
// CHECK-22-NEXT: 10 | void Test15::B::b()
+//
+// CHECK-22: VTable indices for 'Test15::D' (1 entries).
+// CHECK-22-NEXT: 1 | void Test15::D::f()
struct D : A, virtual B, virtual C {
virtual void f();
};
@@ -648,6 +728,11 @@ struct C : A, B { virtual ~C(); };
// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
// CHECK-23-NEXT: 14 | Test16::D::~D() [deleting]
// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
+//
+// CHECK-23: VTable indices for 'Test16::D' (3 entries).
+// CHECK-23-NEXT: 0 | void Test16::D::f()
+// CHECK-23-NEXT: 1 | Test16::D::~D() [complete]
+// CHECK-23-NEXT: 2 | Test16::D::~D() [deleting]
struct D : virtual C {
virtual void f();
};
@@ -683,6 +768,9 @@ struct D : virtual B, virtual C { virtual void f(); };
// CHECK-24-NEXT: -- (Test17::C, 8) vtable address --
// CHECK-24-NEXT: 12 | void Test17::E::f()
// CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+//
+// CHECK-24: VTable indices for 'Test17::E' (1 entries).
+// CHECK-24-NEXT: 0 | void Test17::E::f()
class E : virtual D {
virtual void f();
};
@@ -741,6 +829,10 @@ struct C : A, B {
// CHECK-25-NEXT: 22 | void Test18::D::f()
// CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
// CHECK-25-NEXT: 23 | [unused] void Test18::C::g()
+//
+// CHECK-25: VTable indices for 'Test18::D' (2 entries).
+// CHECK-25-NEXT: 0 | void Test18::D::f()
+// CHECK-25-NEXT: 2 | void Test18::D::h()
// CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries).
// CHECK-25-NEXT: 0 | vbase_offset (0)
@@ -848,6 +940,9 @@ struct C {
// CHECK-26-NEXT: -- (Test19::A, 24) vtable address --
// CHECK-26-NEXT: 12 | void Test19::D::f()
// CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+//
+// CHECK-26: VTable indices for 'Test19::D' (1 entries).
+// CHECK-26-NEXT: 1 | void Test19::D::f()
struct D : C, B, virtual A {
virtual void f();
};
@@ -880,7 +975,11 @@ struct B : A { };
// CHECK-27-NEXT: -- (Test20::B, 8) vtable address --
// CHECK-27-NEXT: 7 | void Test20::C::f() [pure]
// CHECK-27-NEXT: 8 | void Test20::A::g()
-struct C : A, B {
+//
+// CHECK-27: VTable indices for 'Test20::C' (2 entries).
+// CHECK-27-NEXT: 0 | void Test20::C::f()
+// CHECK-27-NEXT: 2 | void Test20::C::h()
+struct C : A, B {
virtual void f() = 0;
virtual void h();
};
@@ -931,6 +1030,9 @@ class E : virtual C { };
// CHECK-28-NEXT: Test21::C | -48
// CHECK-28-NEXT: Test21::D | -56
// CHECK-28-NEXT: Test21::E | -64
+//
+// CHECK-28: VTable indices for 'Test21::F' (1 entries).
+// CHECK-28-NEXT: 0 | void Test21::F::f()
class F : virtual D, virtual E {
virtual void f();
};
@@ -960,6 +1062,9 @@ struct V2 : virtual V1 {
// CHECK-29-NEXT: 6 | offset_to_top (-16)
// CHECK-29-NEXT: 7 | Test22::C RTTI
// CHECK-29-NEXT: -- (Test22::V2, 16) vtable address --
+//
+// CHECK-29: VTable indices for 'Test22::C' (1 entries).
+// CHECK-29-NEXT: 0 | void Test22::C::f()
// CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries).
// CHECK-29-NEXT: 0 | vbase_offset (-4)
@@ -1052,6 +1157,9 @@ struct C : virtual A { };
// CHECK-31-NEXT: 8 | Test24::D RTTI
// CHECK-31-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-31-NEXT: 9 | [unused] void Test24::D::f()
+//
+// CHECK-31: VTable indices for 'Test24::D' (1 entries).
+// CHECK-31-NEXT: 0 | void Test24::D::f()
// CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries).
// CHECK-31-NEXT: 0 | vbase_offset (0)
@@ -1108,6 +1216,9 @@ struct B : virtual V { };
// CHECK-32-NEXT: 9 | Test25::C RTTI
// CHECK-32-NEXT: -- (Test25::B, 8) vtable address --
// CHECK-32-NEXT: 10 | [unused] void Test25::V::f()
+//
+// CHECK-32: VTable indices for 'Test25::C' (1 entries).
+// CHECK-32-NEXT: 1 | void Test25::C::g()
// CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
// CHECK-32-NEXT: 0 | vbase_offset (0)
@@ -1174,6 +1285,9 @@ struct C : virtual A {
// CHECK-33-NEXT: -- (Test26::C, 8) vtable address --
// CHECK-33-NEXT: 13 | void Test26::A::a()
// CHECK-33-NEXT: 14 | void Test26::C::b()
+//
+// CHECK-33: VTable indices for 'Test26::D' (1 entries).
+// CHECK-33-NEXT: 1 | void Test26::D::d()
// CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries).
// CHECK-33-NEXT: 0 | vcall_offset (0)
@@ -1232,6 +1346,9 @@ struct D : A, virtual B, C {
// CHECK-34-NEXT: 11 | Test27::E RTTI
// CHECK-34-NEXT: -- (Test27::B, 16) vtable address --
// CHECK-34-NEXT: 12 | void Test27::B::b()
+//
+// CHECK-34: VTable indices for 'Test27::E' (1 entries).
+// CHECK-34-NEXT: 2 | void Test27::E::e()
// CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries).
// CHECK-34-NEXT: 0 | vbase_offset (16)
@@ -1293,6 +1410,9 @@ struct D : virtual C {
// CHECK-35-NEXT: 12 | Test28::E RTTI
// CHECK-35-NEXT: -- (Test28::B, 16) vtable address --
// CHECK-35-NEXT: 13 | void Test28::B::b()
+//
+// CHECK-35: VTable indices for 'Test28::E' (1 entries).
+// CHECK-35-NEXT : 0 | void Test28::E::e()
// CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries).
// CHECK-35-NEXT: 0 | vbase_offset (8)
@@ -1342,6 +1462,9 @@ struct A {
// CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
// CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
// CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f()
+//
+// CHECK-36: VTable indices for 'Test29::B' (1 entries).
+// CHECK-36-NEXT: 1 | Test29::V2 *Test29::B::f()
struct B : virtual A {
virtual V2 *f();
};
@@ -1403,6 +1526,9 @@ struct C : A, virtual B {
// CHECK-37-NEXT: -- (Test31::C, 8) vtable address --
// CHECK-37-NEXT: 10 | void Test31::D::f()
// CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+//
+// CHECK-37: VTable indices for 'Test31::D' (1 entries).
+// CHECK-37-NEXT: 0 | void Test31::D::f()
struct D : virtual C {
virtual void f();
};
@@ -1494,6 +1620,9 @@ struct E : A, D {
// CHECK-39-NEXT: 28 | Test33::F RTTI
// CHECK-39-NEXT: -- (Test33::B, 24) vtable address --
// CHECK-39-NEXT: 29 | void Test33::B::b()
+//
+// CHECK-39: VTable indices for 'Test33::F' (1 entries).
+// CHECK-39-NEXT: 1 | void Test33::F::f()
struct F : virtual E, A {
virtual void f();
};
@@ -1631,12 +1760,15 @@ struct G : virtual E { };
// CHECK-41-NEXT: 29 | void Test35::C::c()
// CHECK-41-NEXT: 30 | void Test35::D::d()
// CHECK-41-NEXT: 31 | void Test35::E::e()
-
+//
// CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries).
// CHECK-41-NEXT: Test35::A | -32
// CHECK-41-NEXT: Test35::B | -24
// CHECK-41-NEXT: Test35::D | -56
// CHECK-41-NEXT: Test35::E | -64
+//
+// CHECK-41: VTable indices for 'Test35::H' (1 entries).
+// CHECK-41-NEXT: 2 | void Test35::H::h()
struct H : F, G {
virtual void h();
};
@@ -1676,6 +1808,9 @@ struct C : virtual A {
// CHECK-42-NEXT: -- (Test36::B, 8) vtable address --
// CHECK-42-NEXT: 11 | void Test36::C::f()
// CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+//
+// CHECK-42: VTable indices for 'Test36::D' (1 entries).
+// CHECK-42-NEXT: 1 | void Test36::D::g()
struct D : virtual B, C {
virtual void g();
};
@@ -1721,6 +1856,10 @@ namespace Test38 {
// CHECK-44-NEXT: -- (Test38::B, 0) vtable address --
// CHECK-44-NEXT: 5 | void *Test38::B::foo()
// CHECK-44-NEXT: 6 | const void *Test38::B::foo() const
+ //
+ // CHECK-44: VTable indices for 'Test38::B' (2 entries).
+ // CHECK-44-NEXT: 0 | void *Test38::B::foo()
+ // CHECK-44-NEXT: 1 | const void *Test38::B::foo() const
class B : virtual public A {
void *foo();
const void *foo() const;
@@ -1741,6 +1880,9 @@ namespace Test39 {
// CHECK-45-NEXT: -- (Test39::B, 0) vtable address --
// CHECK-45-NEXT: 2 | void Test39::A::foo() [deleted]
// CHECK-45-NEXT: 3 | void Test39::B::foo2()
+ //
+ // CHECK-45: VTable indices for 'Test39::B' (1 entries).
+ // CHECK-45-NEXT: 1 | void Test39::B::foo2()
struct B: A {
virtual void foo2();
};
@@ -1748,3 +1890,37 @@ namespace Test39 {
void B::foo2() {
}
}
+
+namespace Test40 {
+ struct A {
+ virtual void foo() = 0;
+ };
+
+ struct B : public A {
+ virtual void foo();
+ };
+
+ struct C: public B {
+ // CHECK-46: VTable indices for 'Test40::C' (8 entries).
+ // CHECK-46-NEXT: 1 | int Test40::C::f(int)
+ // CHECK-46-NEXT: 2 | int Test40::C::f()
+ // CHECK-46-NEXT: 3 | int Test40::C::g(int)
+ // CHECK-46-NEXT: 4 | int Test40::C::g()
+ // CHECK-46-NEXT: 5 | int Test40::C::h(int)
+ // CHECK-46-NEXT: 6 | int Test40::C::h()
+ // CHECK-46-NEXT: 7 | int Test40::C::i(int)
+ // CHECK-46-NEXT: 8 | int Test40::C::i()
+ virtual int f(int);
+ virtual int f();
+ virtual int g(int);
+ virtual int g();
+ virtual int h(int);
+ virtual int h();
+ virtual int i(int);
+ virtual int i();
+ };
+
+ class D : C {};
+
+ D d;
+}
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index b945e569afb6..c17e33387e52 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -1,24 +1,9 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -disable-llvm-optzns -O3 -emit-llvm -o %t.opt
-// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-2-HIDDEN %s < %t.hidden
-// RUN: FileCheck --check-prefix=CHECK-3 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-4 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-5 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-5-HIDDEN %s < %t.hidden
-// RUN: FileCheck --check-prefix=CHECK-6 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-6-HIDDEN %s < %t.hidden
-// RUN: FileCheck --check-prefix=CHECK-7 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-8 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-9 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-9-OPT %s < %t.opt
-// RUN: FileCheck --check-prefix=CHECK-10 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-10-OPT %s < %t.opt
-// RUN: FileCheck --check-prefix=CHECK-11 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-12 %s < %t
-// RUN: FileCheck --check-prefix=CHECK-13 %s < %t
+// RUN: FileCheck --check-prefix=CHECK %s < %t
+// RUN: FileCheck --check-prefix=CHECK-HIDDEN %s < %t.hidden
+// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt
namespace {
struct A {
@@ -102,96 +87,94 @@ void use_F() {
// B has a key function that is not defined in this translation unit so its vtable
// has external linkage.
-// CHECK-1: @_ZTV1B = external unnamed_addr constant
+// CHECK-DAG: @_ZTV1B = external unnamed_addr constant
// C has no key function, so its vtable should have weak_odr linkage
// and hidden visibility (rdar://problem/7523229).
-// CHECK-2: @_ZTV1C = linkonce_odr unnamed_addr constant
-// CHECK-2: @_ZTS1C = linkonce_odr constant
-// CHECK-2: @_ZTI1C = linkonce_odr unnamed_addr constant
-// CHECK-2: @_ZTT1C = linkonce_odr unnamed_addr constant
-// CHECK-2-HIDDEN: @_ZTV1C = linkonce_odr hidden unnamed_addr constant
-// CHECK-2-HIDDEN: @_ZTS1C = linkonce_odr constant
-// CHECK-2-HIDDEN: @_ZTI1C = linkonce_odr hidden unnamed_addr constant
-// CHECK-2-HIDDEN: @_ZTT1C = linkonce_odr hidden unnamed_addr constant
+// CHECK-DAG: @_ZTV1C = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1C = linkonce_odr constant
+// CHECK-DAG: @_ZTI1C = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTT1C = linkonce_odr unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTV1C = linkonce_odr hidden unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTS1C = linkonce_odr constant
+// CHECK-HIDDEN-DAG: @_ZTI1C = linkonce_odr hidden unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTT1C = linkonce_odr hidden unnamed_addr constant
// D has a key function that is defined in this translation unit so its vtable is
// defined in the translation unit.
-// CHECK-3: @_ZTV1D = unnamed_addr constant
-// CHECK-3: @_ZTS1D = constant
-// CHECK-3: @_ZTI1D = unnamed_addr constant
+// CHECK-DAG: @_ZTV1D = unnamed_addr constant
+// CHECK-DAG: @_ZTS1D = constant
+// CHECK-DAG: @_ZTI1D = unnamed_addr constant
// E<char> is an explicit specialization with a key function defined
// in this translation unit, so its vtable should have external
// linkage.
-// CHECK-4: @_ZTV1EIcE = unnamed_addr constant
-// CHECK-4: @_ZTS1EIcE = constant
-// CHECK-4: @_ZTI1EIcE = unnamed_addr constant
+// CHECK-DAG: @_ZTV1EIcE = unnamed_addr constant
+// CHECK-DAG: @_ZTS1EIcE = constant
+// CHECK-DAG: @_ZTI1EIcE = unnamed_addr constant
// E<short> is an explicit template instantiation with a key function
// defined in this translation unit, so its vtable should have
// weak_odr linkage.
-// CHECK-5: @_ZTV1EIsE = weak_odr unnamed_addr constant
-// CHECK-5: @_ZTS1EIsE = weak_odr constant
-// CHECK-5: @_ZTI1EIsE = weak_odr unnamed_addr constant
-// CHECK-5-HIDDEN: @_ZTV1EIsE = weak_odr unnamed_addr constant
-// CHECK-5-HIDDEN: @_ZTS1EIsE = weak_odr constant
-// CHECK-5-HIDDEN: @_ZTI1EIsE = weak_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1EIsE = weak_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1EIsE = weak_odr constant
+// CHECK-DAG: @_ZTI1EIsE = weak_odr unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTV1EIsE = weak_odr unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTS1EIsE = weak_odr constant
+// CHECK-HIDDEN-DAG: @_ZTI1EIsE = weak_odr unnamed_addr constant
// F<short> is an explicit template instantiation without a key
// function, so its vtable should have weak_odr linkage
-// CHECK-6: @_ZTV1FIsE = weak_odr unnamed_addr constant
-// CHECK-6: @_ZTS1FIsE = weak_odr constant
-// CHECK-6: @_ZTI1FIsE = weak_odr unnamed_addr constant
-// CHECK-6-HIDDEN: @_ZTV1FIsE = weak_odr unnamed_addr constant
-// CHECK-6-HIDDEN: @_ZTS1FIsE = weak_odr constant
-// CHECK-6-HIDDEN: @_ZTI1FIsE = weak_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1FIsE = weak_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1FIsE = weak_odr constant
+// CHECK-DAG: @_ZTI1FIsE = weak_odr unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTV1FIsE = weak_odr unnamed_addr constant
+// CHECK-HIDDEN-DAG: @_ZTS1FIsE = weak_odr constant
+// CHECK-HIDDEN-DAG: @_ZTI1FIsE = weak_odr unnamed_addr constant
// E<long> is an implicit template instantiation with a key function
// defined in this translation unit, so its vtable should have
// linkonce_odr linkage.
-// CHECK-7: @_ZTV1EIlE = linkonce_odr unnamed_addr constant
-// CHECK-7: @_ZTS1EIlE = linkonce_odr constant
-// CHECK-7: @_ZTI1EIlE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1EIlE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1EIlE = linkonce_odr constant
+// CHECK-DAG: @_ZTI1EIlE = linkonce_odr unnamed_addr constant
// F<long> is an implicit template instantiation with no key function,
// so its vtable should have linkonce_odr linkage.
-// CHECK-8: @_ZTV1FIlE = linkonce_odr unnamed_addr constant
-// CHECK-8: @_ZTS1FIlE = linkonce_odr constant
-// CHECK-8: @_ZTI1FIlE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1FIlE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1FIlE = linkonce_odr constant
+// CHECK-DAG: @_ZTI1FIlE = linkonce_odr unnamed_addr constant
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have external linkage.
-// CHECK-9: @_ZTV1FIiE = external unnamed_addr constant
-// CHECK-9-OPT: @_ZTV1FIiE = available_externally unnamed_addr constant
+// CHECK-DAG: @_ZTV1FIiE = external unnamed_addr constant
+// CHECK-OPT-DAG: @_ZTV1FIiE = external unnamed_addr constant
// E<int> is an explicit template instantiation declaration. It has a
// key function that is not instantiated, so we should only reference
// its vtable, not define it.
-// CHECK-10: @_ZTV1EIiE = external unnamed_addr constant
-// CHECK-10-OPT: @_ZTV1EIiE = available_externally unnamed_addr constant
+// CHECK-DAG: @_ZTV1EIiE = external unnamed_addr constant
+// CHECK-OPT-DAG: @_ZTV1EIiE = external unnamed_addr constant
// The anonymous struct for e has no linkage, so the vtable should have
// internal linkage.
-// CHECK-11: @"_ZTV3$_0" = internal unnamed_addr constant
-// CHECK-11: @"_ZTS3$_0" = internal constant
-// CHECK-11: @"_ZTI3$_0" = internal unnamed_addr constant
+// CHECK-DAG: @"_ZTV3$_0" = internal unnamed_addr constant
+// CHECK-DAG: @"_ZTS3$_0" = internal constant
+// CHECK-DAG: @"_ZTI3$_0" = internal unnamed_addr constant
// The A vtable should have internal linkage since it is inside an anonymous
// namespace.
-// CHECK-12: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr constant
-// CHECK-12: @_ZTSN12_GLOBAL__N_11AE = internal constant
-// CHECK-12: @_ZTIN12_GLOBAL__N_11AE = internal unnamed_addr constant
+// CHECK-DAG: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr constant
+// CHECK-DAG: @_ZTSN12_GLOBAL__N_11AE = internal constant
+// CHECK-DAG: @_ZTIN12_GLOBAL__N_11AE = internal unnamed_addr constant
// F<char> is an explicit specialization without a key function, so
// its vtable should have linkonce_odr linkage.
-// CHECK-13: @_ZTV1FIcE = linkonce_odr unnamed_addr constant
-// CHECK-13: @_ZTS1FIcE = linkonce_odr constant
-// CHECK-13: @_ZTI1FIcE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1FIcE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTS1FIcE = linkonce_odr constant
+// CHECK-DAG: @_ZTI1FIcE = linkonce_odr unnamed_addr constant
-// RUN: FileCheck --check-prefix=CHECK-G %s < %t
-//
-// CHECK-G: @_ZTV1GIiE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1GIiE = linkonce_odr unnamed_addr constant
template <typename T>
class G {
public:
@@ -205,11 +188,9 @@ template <typename T>
void G<T>::f0() {}
void G_f0() { new G<int>(); }
-// RUN: FileCheck --check-prefix=CHECK-H %s < %t
-
// H<int> has a key function without a body but it's a template instantiation
// so its VTable must be emitted.
-// CHECK-H: @_ZTV1HIiE = linkonce_odr unnamed_addr constant
+// CHECK-DAG: @_ZTV1HIiE = linkonce_odr unnamed_addr constant
template <typename T>
class H {
public:
@@ -220,21 +201,15 @@ void use_H() {
H<int> h;
}
-// RUN: FileCheck --check-prefix=CHECK-I %s < %t
-// RUN: FileCheck --check-prefix=CHECK-I-OPT %s < %t.opt
-
// I<int> has an explicit instantiation declaration and needs a VTT and
-// construction vtables. We emit the VTT available_externally, but point it at
-// internal construction vtables because there is no way to form a reference to
-// the real construction vtables.
+// construction vtables.
-// CHECK-I: @_ZTV1IIiE = external unnamed_addr constant
-// CHECK-I: @_ZTT1IIiE = external unnamed_addr constant
-// CHECK-I-NOT: @_ZTC1IIiE
+// CHECK-DAG: @_ZTV1IIiE = external unnamed_addr constant
+// CHECK-DAG: @_ZTT1IIiE = external unnamed_addr constant
+// CHECK-NOT: @_ZTC1IIiE
//
-// CHECK-I-OPT: @_ZTV1IIiE = available_externally unnamed_addr constant
-// CHECK-I-OPT: @_ZTT1IIiE = available_externally unnamed_addr constant {{.*}} @_ZTC1IIiE0_6VBase2
-// CHECK-I-OPT: @_ZTC1IIiE0_6VBase2 = internal unnamed_addr constant
+// CHECK-OPT-DAG: @_ZTV1IIiE = external unnamed_addr constant
+// CHECK-OPT-DAG: @_ZTT1IIiE = external unnamed_addr constant
struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {};
template<typename T>
struct I : VBase2 {};
diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp
index 9b1eaa5ba775..85e08d8f0f9b 100644
--- a/test/CodeGenCXX/vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -19,14 +19,14 @@ struct A : Base {
Field field;
};
-// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr
// CHECK: call void @_ZN4BaseC2Ev(
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
// CHECK: call void @_ZN5FieldC1Ev(
// CHECK: ret void
A::A() { }
-// CHECK: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr
+// CHECK-LABEL: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
// CHECK: call void @_ZN5FieldD1Ev(
// CHECK: call void @_ZN4BaseD2Ev(
@@ -41,16 +41,16 @@ struct B : Base {
void f() { B b; }
-// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN1BC2Ev(
-// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
// CHECK: call void @_ZN5FieldD1Ev(
// CHECK: call void @_ZN4BaseD2Ev(
// CHECK: ret void
-// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN4BaseC2Ev(
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
// CHECK: call void @_ZN5FieldC1Ev
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index 4404de0f88e5..2c7234e038c9 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -6,9 +6,9 @@ struct S {
short s;
};
-// CHECK: define void @_Z1fv(%struct.S* noalias sret %
+// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret %
S f() { return S(); }
-// CHECK: define void @_Z1f1S(%struct.S*)
+// CHECK-LABEL: define void @_Z1f1S(%struct.S*)
void f(S) { }
// Non-trivial dtors, should both be passed indirectly.
@@ -18,10 +18,10 @@ public:
double c;
};
-// CHECK: define void @_Z1gv(%class.C* noalias sret %
+// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret %
C g() { return C(); }
-// CHECK: define void @_Z1f1C(%class.C*)
+// CHECK-LABEL: define void @_Z1f1C(%class.C*)
void f(C) { }
@@ -29,7 +29,7 @@ void f(C) { }
// PR7058 - Missing byval on MI thunk definition.
-// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite
+// CHECK-LABEL: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite
// ...
// CHECK: %struct.CallSite* byval align 4 %CS)
struct CallSite {
@@ -57,38 +57,38 @@ void BasicAliasAnalysis::getModRefInfo(CallSite CS) {
//
// PR7098.
-// CHECK: define i64 @_Z2f0v()
+// CHECK-LABEL: define i64 @_Z2f0v()
struct s0_0 { int x; };
struct s0_1 : s0_0 { int* y; };
s0_1 f0() { return s0_1(); }
-// CHECK: define i32 @_Z2f1v()
+// CHECK-LABEL: define i32 @_Z2f1v()
struct s1_0 { int x; };
struct s1_1 : s1_0 { };
s1_1 f1() { return s1_1(); }
-// CHECK: define double @_Z2f2v()
+// CHECK-LABEL: define double @_Z2f2v()
struct s2_0 { double x; };
struct s2_1 : s2_0 { };
s2_1 f2() { return s2_1(); }
-// CHECK: define double @_Z2f3v()
+// CHECK-LABEL: define double @_Z2f3v()
struct s3_0 { };
struct s3_1 { double x; };
struct s3_2 : s3_0, s3_1 { };
s3_2 f3() { return s3_2(); }
-// CHECK: define i64 @_Z2f4v()
+// CHECK-LABEL: define i64 @_Z2f4v()
struct s4_0 { float x; };
struct s4_1 { float x; };
struct s4_2 : s4_0, s4_1 { };
s4_2 f4() { return s4_2(); }
-// CHECK: define i32* @_Z2f5v()
+// CHECK-LABEL: define i32* @_Z2f5v()
struct s5 { s5(); int &x; };
s5 f5() { return s5(); }
-// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a)
+// CHECK-LABEL: define i32 @_Z4f6_0M2s6i(i32 %a)
// CHECK: define i64 @_Z4f6_1M2s6FivE({ i32, i32 }* byval align 4)
// FIXME: It would be nice to avoid byval on the previous case.
struct s6 {};
@@ -97,19 +97,19 @@ typedef int (s6::*s6_mfp)();
s6_mdp f6_0(s6_mdp a) { return a; }
s6_mfp f6_1(s6_mfp a) { return a; }
-// CHECK: define double @_Z2f7v()
+// CHECK-LABEL: define double @_Z2f7v()
struct s7_0 { unsigned : 0; };
struct s7_1 { double x; };
struct s7 : s7_0, s7_1 { };
s7 f7() { return s7(); }
-// CHECK: define void @_Z2f8v(%struct.s8* noalias sret %agg.result)
+// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret %agg.result)
struct s8_0 { };
struct s8_1 { double x; };
struct s8 { s8_0 a; s8_1 b; };
s8 f8() { return s8(); }
-// CHECK: define void @_Z2f9v(%struct.s9* noalias sret %agg.result)
+// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret %agg.result)
struct s9_0 { unsigned : 0; };
struct s9_1 { double x; };
struct s9 { s9_0 a; s9_1 b; };
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index 672180363fca..2172e0810d75 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -3,28 +3,28 @@
// Basic base class test.
struct f0_s0 { unsigned a; };
struct f0_s1 : public f0_s0 { void *b; };
-// CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1)
+// CHECK-LABEL: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1)
void f0(f0_s1 a0) { }
// Check with two eight-bytes in base class.
struct f1_s0 { unsigned a; unsigned b; float c; };
struct f1_s1 : public f1_s0 { float d;};
-// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1)
+// CHECK-LABEL: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1)
void f1(f1_s1 a0) { }
// Check with two eight-bytes in base class and merge.
struct f2_s0 { unsigned a; unsigned b; float c; };
struct f2_s1 : public f2_s0 { char d;};
-// CHECK: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1)
+// CHECK-LABEL: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1)
void f2(f2_s1 a0) { }
// PR5831
-// CHECK: define void @_Z2f34s3_1(i64 %x.coerce)
+// CHECK-LABEL: define void @_Z2f34s3_1(i64 %x.coerce)
struct s3_0 {};
struct s3_1 { struct s3_0 a; long b; };
void f3(struct s3_1 x) {}
-// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a)
+// CHECK-LABEL: define i64 @_Z4f4_0M2s4i(i64 %a)
// CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1)
struct s4 {};
typedef int s4::* s4_mdp;
@@ -41,7 +41,7 @@ struct StringRef {
void AddKeyword(StringRef, int x);
void foo() {
- // CHECK: define void @_ZN6PR75233fooEv()
+ // CHECK-LABEL: define void @_ZN6PR75233fooEv()
// CHECK: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(i8* {{.*}}, i32 4)
AddKeyword(StringRef(), 4);
}
@@ -54,7 +54,7 @@ namespace PR7742 { // Also rdar://8250764
struct c2 : public s2 {};
- // CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P)
+ // CHECK-LABEL: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P)
c2 foo(c2 *P) {
return c2();
}
@@ -72,7 +72,7 @@ namespace PR5179 {
B1 b1;
};
- // CHECK: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce)
+ // CHECK-LABEL: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce)
const void *bar(B2 b2) {
return b2.b1.pa;
}
@@ -114,7 +114,7 @@ namespace test6 {
int test(outer x) {
return x.x + x.f;
}
- // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1)
+ // CHECK-LABEL: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1)
}
namespace test7 {
diff --git a/test/CodeGenObjC/2010-02-09-DbgSelf.m b/test/CodeGenObjC/2010-02-09-DbgSelf.m
index e09adac161ec..9aebe3d619bc 100644
--- a/test/CodeGenObjC/2010-02-09-DbgSelf.m
+++ b/test/CodeGenObjC/2010-02-09-DbgSelf.m
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | grep "\"self\", metadata"
+// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | FileCheck %s
// Test to check that "self" argument is assigned a location.
+// CHECK: call void @llvm.dbg.declare(metadata !{%0** %{{[^}]+}}}, metadata [[SELF:![0-9]*]])
+// CHECK: [[SELF]] = {{.*}} ; [ DW_TAG_arg_variable ] [self]
@interface Foo
-(void) Bar: (int)x ;
diff --git a/test/CodeGenObjC/arc-block-copy-escape.m b/test/CodeGenObjC/arc-block-copy-escape.m
index 3ba742637515..afe7c0bdc18b 100644
--- a/test/CodeGenObjC/arc-block-copy-escape.m
+++ b/test/CodeGenObjC/arc-block-copy-escape.m
@@ -8,14 +8,14 @@ void use_int(int);
void test0(int i) {
block_t block = ^{ use_int(i); };
- // CHECK: define void @test0(
+ // CHECK-LABEL: define void @test0(
// CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]], !clang.arc.copy_on_escape
// CHECK: ret void
}
void test1(int i) {
id block = ^{ use_int(i); };
- // CHECK: define void @test1(
+ // CHECK-LABEL: define void @test1(
// CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) [[NUW]]
// CHECK-NOT: !clang.arc.copy_on_escape
// CHECK: ret void
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index c9ba2f615347..4ba3f05fd9f6 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -7,7 +7,7 @@ void test0(id (^maker)(void)) {
}
int (^test1(int x))(void) {
- // CHECK: define i32 ()* @test1(
+ // CHECK-LABEL: define i32 ()* @test1(
// CHECK: [[X:%.*]] = alloca i32,
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
@@ -23,7 +23,7 @@ int (^test1(int x))(void) {
}
void test2(id x) {
-// CHECK: define void @test2(
+// CHECK-LABEL: define void @test2(
// CHECK: [[X:%.*]] = alloca i8*,
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
@@ -43,7 +43,7 @@ void test2(id x) {
extern void test2_helper(id (^)(void));
test2_helper(^{ return x; });
-// CHECK: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @__copy_helper_block_
// CHECK: [[T0:%.*]] = load i8**
// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-NEXT: [[T0:%.*]] = load i8**
@@ -53,7 +53,7 @@ void test2(id x) {
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: ret void
-// CHECK: define internal void @__destroy_helper_block_
+// CHECK-LABEL: define internal void @__destroy_helper_block_
// CHECK: [[T0:%.*]] = load i8**
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5
@@ -66,7 +66,7 @@ void test3(void (^sink)(id*)) {
__strong id strong;
sink(&strong);
- // CHECK: define void @test3(
+ // CHECK-LABEL: define void @test3(
// CHECK: [[SINK:%.*]] = alloca void (i8**)*
// CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
@@ -108,7 +108,7 @@ void test4(void) {
__block id var = test4_source();
test4_helper(^{ var = 0; });
- // CHECK: define void @test4()
+ // CHECK-LABEL: define void @test4()
// CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
@@ -130,7 +130,7 @@ void test4(void) {
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK: ret void
- // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK-LABEL: define internal void @__Block_byref_object_copy_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
// CHECK-NEXT: load i8**
// CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
@@ -139,22 +139,22 @@ void test4(void) {
// CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
// CHECK-NEXT: store i8* null, i8** [[T1]]
- // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK-LABEL: define internal void @__Block_byref_object_dispose_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // CHECK: define internal void @__test4_block_invoke
+ // CHECK-LABEL: define internal void @__test4_block_invoke
// CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
// CHECK-NEXT: store i8* null, i8** [[SLOT]],
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: ret void
- // CHECK: define internal void @__copy_helper_block_
+ // CHECK-LABEL: define internal void @__copy_helper_block_
// CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
- // CHECK: define internal void @__destroy_helper_block_
+ // CHECK-LABEL: define internal void @__destroy_helper_block_
// CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
}
@@ -164,7 +164,7 @@ void test5(void) {
__unsafe_unretained id var = test5_source();
test5_helper(^{ (void) var; });
- // CHECK: define void @test5()
+ // CHECK-LABEL: define void @test5()
// CHECK: [[VAR:%.*]] = alloca i8*
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = call i8* @test5_source()
@@ -187,7 +187,7 @@ void test6(void) {
__block __weak id var = test6_source();
test6_helper(^{ var = 0; });
- // CHECK: define void @test6()
+ // CHECK-LABEL: define void @test6()
// CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
@@ -209,27 +209,27 @@ void test6(void) {
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
// CHECK: ret void
- // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK-LABEL: define internal void @__Block_byref_object_copy_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
// CHECK-NEXT: load i8**
// CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
// CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
- // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK-LABEL: define internal void @__Block_byref_object_dispose_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
- // CHECK: define internal void @__test6_block_invoke
+ // CHECK-LABEL: define internal void @__test6_block_invoke
// CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
// CHECK-NEXT: ret void
- // CHECK: define internal void @__copy_helper_block_
+ // CHECK-LABEL: define internal void @__copy_helper_block_
// 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
// CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
- // CHECK: define internal void @__destroy_helper_block_
+ // CHECK-LABEL: define internal void @__destroy_helper_block_
// 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
// CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
}
@@ -241,7 +241,7 @@ void test7(void) {
__weak id var = test7_source();
test7_helper(^{ test7_consume(var); });
- // CHECK: define void @test7()
+ // CHECK-LABEL: define void @test7()
// CHECK: [[VAR:%.*]] = alloca i8*,
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = call i8* @test7_source()
@@ -258,19 +258,19 @@ void test7(void) {
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
// CHECK: ret void
- // CHECK: define internal void @__test7_block_invoke
+ // CHECK-LABEL: define internal void @__test7_block_invoke
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[SLOT]])
// CHECK-NEXT: call void @test7_consume(i8* [[T0]])
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK: ret void
- // CHECK: define internal void @__copy_helper_block_
+ // CHECK-LABEL: define internal void @__copy_helper_block_
// CHECK: getelementptr
// CHECK-NEXT: getelementptr
// CHECK-NEXT: call void @objc_copyWeak(
- // CHECK: define internal void @__destroy_helper_block_
+ // CHECK-LABEL: define internal void @__destroy_helper_block_
// CHECK: getelementptr
// CHECK-NEXT: call void @objc_destroyWeak(
}
@@ -311,7 +311,7 @@ id test9(void) {
return test9_produce();
}();
-// CHECK: define i8* @test9(
+// CHECK-LABEL: define i8* @test9(
// CHECK: load i8** getelementptr
// CHECK-NEXT: bitcast i8*
// CHECK-NEXT: call i8*
@@ -328,7 +328,7 @@ id test9(void) {
// when the initialization captures the variable.
void test10a(void) {
__block void (^block)(void) = ^{ block(); };
- // CHECK: define void @test10a()
+ // CHECK-LABEL: define void @test10a()
// CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
// Zero-initialization before running the initializer.
@@ -362,7 +362,7 @@ void test10a(void) {
// We can also use _Block_object_assign/destroy with
// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.
-// CHECK: define internal void @__Block_byref_object_copy
+// CHECK-LABEL: define internal void @__Block_byref_object_copy
// CHECK: [[D0:%.*]] = load i8** {{%.*}}
// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]*
// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6
@@ -376,7 +376,7 @@ void test10a(void) {
// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8
// CHECK: ret void
-// CHECK: define internal void @__Block_byref_object_dispose
+// CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: [[T0:%.*]] = load i8** {{%.*}}
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]*
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6
@@ -391,7 +391,7 @@ void test10b(void) {
__block void (^block)(void);
block = ^{ block(); };
- // CHECK: define void @test10b()
+ // CHECK-LABEL: define void @test10b()
// CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
// Zero-initialize.
@@ -427,7 +427,7 @@ void test11a(void) {
int x;
test11_helper(^{ (void) x; });
- // CHECK: define void @test11a()
+ // CHECK-LABEL: define void @test11a()
// CHECK: [[X:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
@@ -444,7 +444,7 @@ void test11b(void) {
int x;
id b = ^{ (void) x; };
- // CHECK: define void @test11b()
+ // CHECK-LABEL: define void @test11b()
// CHECK: [[X:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
@@ -487,7 +487,7 @@ void test13(id x) {
void (^b)(void) = (x ? ^{test13_helper(x);} : 0);
test13_use(b);
- // CHECK: define void @test13(
+ // CHECK-LABEL: define void @test13(
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
@@ -547,7 +547,7 @@ void test15(int a) {
void test16() {
void (^BLKVAR)(void) = ^{ BLKVAR(); };
- // CHECK: define void @test16(
+ // CHECK-LABEL: define void @test16(
// CHECK: [[BLKVAR:%.*]] = alloca void ()*, align 8
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
@@ -567,7 +567,7 @@ id (^test17(id self, int which))(void) {
}
return (void*) 0;
}
-// CHECK: define i8* ()* @test17(
+// CHECK-LABEL: define i8* ()* @test17(
// CHECK: [[RET:%.*]] = alloca i8* ()*, align
// CHECK-NEXT: [[SELF:%.*]] = alloca i8*,
// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align
@@ -612,7 +612,7 @@ id (^test17(id self, int which))(void) {
// CHECK-NEXT: br label
void test18(id x) {
-// CHECK-UNOPT: define void @test18(
+// CHECK-UNOPT-LABEL: define void @test18(
// CHECK-UNOPT: [[X:%.*]] = alloca i8*,
// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-UNOPT-NEXT: store i8* null, i8** [[X]]
@@ -630,7 +630,7 @@ void test18(id x) {
extern void test18_helper(id (^)(void));
test18_helper(^{ return x; });
-// CHECK-UNOPT: define internal void @__copy_helper_block_
+// CHECK-UNOPT-LABEL: define internal void @__copy_helper_block_
// CHECK-UNOPT: [[T0:%.*]] = load i8**
// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8**
@@ -642,7 +642,7 @@ void test18(id x) {
// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) [[NUW]]
// CHECK-UNOPT-NEXT: ret void
-// CHECK-UNOPT: define internal void @__destroy_helper_block_
+// CHECK-UNOPT-LABEL: define internal void @__destroy_helper_block_
// CHECK-UNOPT: [[T0:%.*]] = load i8**
// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5
@@ -653,7 +653,7 @@ void test18(id x) {
// rdar://13588325
void test19_sink(void (^)(int));
void test19(void (^b)(void)) {
-// CHECK: define void @test19(
+// CHECK-LABEL: define void @test19(
// Prologue.
// CHECK: [[B:%.*]] = alloca void ()*,
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
diff --git a/test/CodeGenObjC/arc-bridged-cast.m b/test/CodeGenObjC/arc-bridged-cast.m
index eb9045d3d840..cdfe1dbfc55f 100644
--- a/test/CodeGenObjC/arc-bridged-cast.m
+++ b/test/CodeGenObjC/arc-bridged-cast.m
@@ -14,7 +14,7 @@ CFStringRef CFGetString(void);
id CreateSomething(void);
NSString *CreateNSString(void);
-// CHECK: define void @bridge_transfer_from_cf
+// CHECK-LABEL: define void @bridge_transfer_from_cf
void bridge_transfer_from_cf(int *i) {
// CHECK: store i32 7
*i = 7;
@@ -34,7 +34,7 @@ void bridge_transfer_from_cf(int *i) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @bridge_from_cf
+// CHECK-LABEL: define void @bridge_from_cf
void bridge_from_cf(int *i) {
// CHECK: store i32 7
*i = 7;
@@ -53,7 +53,7 @@ void bridge_from_cf(int *i) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @bridge_retained_of_cf
+// CHECK-LABEL: define void @bridge_retained_of_cf
void bridge_retained_of_cf(int *i) {
*i = 7;
// CHECK: call i8* @CreateSomething()
@@ -70,7 +70,7 @@ void bridge_retained_of_cf(int *i) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @bridge_of_cf
+// CHECK-LABEL: define void @bridge_of_cf
void bridge_of_cf(int *i) {
// CHECK: store i32 7
*i = 7;
diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
index 3072316963ce..6ab02a916e8b 100644
--- a/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
+++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
// RUN: FileCheck --input-file=%t-32.layout %s
// rdar://12184410
// rdar://12752901
diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
index 7ecdb4b1e9aa..45a894c38150 100644
--- a/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
+++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
// RUN: FileCheck --input-file=%t-32.layout %s
// rdar://12184410
// rdar://12752901
diff --git a/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
index 28c5bb4f5bf8..89e2b570b038 100644
--- a/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
+++ b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
// RUN: FileCheck --input-file=%t-64.layout %s
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
// RUN: FileCheck -check-prefix=CHECK-i386 --input-file=%t-32.layout %s
// rdar://12184410
diff --git a/test/CodeGenObjC/arc-captured-block-var-layout.m b/test/CodeGenObjC/arc-captured-block-var-layout.m
index bc203072e788..42e6060dcc25 100644
--- a/test/CodeGenObjC/arc-captured-block-var-layout.m
+++ b/test/CodeGenObjC/arc-captured-block-var-layout.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.layout %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.layout %s
// rdar://12184410
// rdar://12752901
diff --git a/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m
index aa3d2f3640ca..dafffd81f506 100644
--- a/test/CodeGenObjC/arc-exceptions.m
+++ b/test/CodeGenObjC/arc-exceptions.m
@@ -11,7 +11,7 @@ void test0(void) {
} @catch (Ety *e) {
}
}
-// CHECK: define void @test0()
+// CHECK-LABEL: define void @test0()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @test0_helper()
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
@@ -31,7 +31,7 @@ void test1(void) {
} @catch (__weak Ety *e) {
}
}
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @test1_helper()
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index 176b28d3a278..44561818c94f 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 -O0 -emit-llvm %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// 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
// rdar://9503326
// rdar://9606600
@@ -22,7 +22,7 @@ void test0(NSArray *array) {
}
}
-// CHECK-LP64: define void @test0(
+// CHECK-LP64-LABEL: define void @test0(
// CHECK-LP64: [[ARRAY:%.*]] = alloca [[ARRAY_T:%.*]]*,
// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
@@ -82,7 +82,7 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
// CHECK-LP64-NEXT: ret void
-// CHECK-LP64: define internal void @__test0_block_invoke
+// CHECK-LP64-LABEL: define internal void @__test0_block_invoke
// CHECK-LP64: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
// CHECK-LP64-NOT: ret
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
@@ -95,7 +95,7 @@ void test1(NSArray *array) {
}
}
-// CHECK-LP64: define void @test1(
+// CHECK-LP64-LABEL: define void @test1(
// CHECK-LP64: alloca [[ARRAY_T:%.*]]*,
// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
@@ -128,7 +128,7 @@ void test2(Test2 *a) {
}
}
-// CHECK-LP64: define void @test2(
+// CHECK-LP64-LABEL: define void @test2(
// CHECK-LP64: [[T0:%.*]] = call [[ARRAY_T]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[ARRAY_T]]* (i8*, i8*)*)(
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
@@ -160,7 +160,7 @@ void test3(NSArray *array) {
use(x);
}
- // CHECK-LP64: define void @test3(
+ // CHECK-LP64-LABEL: define void @test3(
// CHECK-LP64: [[ARRAY:%.*]] = alloca [[ARRAY_T]]*, align 8
// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*, align 8
// CHECK-LP64: [[T0:%.*]] = load i8** [[X]], align 8
diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m
index 90683149d5bb..62428f5aefc7 100644
--- a/test/CodeGenObjC/arc-ivar-layout.m
+++ b/test/CodeGenObjC/arc-ivar-layout.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// REQUIRES: x86-64-registered-target
// rdar://8991729
diff --git a/test/CodeGenObjC/arc-linetable-autorelease.m b/test/CodeGenObjC/arc-linetable-autorelease.m
new file mode 100644
index 000000000000..be05ec2fcd8e
--- /dev/null
+++ b/test/CodeGenObjC/arc-linetable-autorelease.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -emit-llvm -fobjc-arc -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// Ensure that the line info is making sense:
+// ARC cleanups should be at the closing '}'.
+@protocol NSObject
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@protocol NSCopying
+@end
+
+@protocol NSCoding
+@end
+
+typedef double CGFloat;
+struct CGRect {};
+typedef struct CGRect CGRect;
+typedef CGRect NSRect;
+NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h);
+@interface NSBezierPath : NSObject <NSCopying, NSCoding>
++ (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect xRadius:(CGFloat)xRadius yRadius:(CGFloat)yRadius;
+@end
+@implementation AppDelegate : NSObject {}
+- (NSBezierPath *)_createBezierPathWithWidth:(CGFloat)width height:(CGFloat)height radius:(CGFloat)radius lineWidth:(CGFloat)lineWidth
+{
+ NSRect rect = NSMakeRect(0, 0, width, height);
+ NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius];
+ CGFloat pattern[2];
+ // CHECK: define {{.*}}_createBezierPathWithWidth
+ // CHECK: load {{.*}} %path, align {{.*}}, !dbg ![[RET:[0-9]+]]
+ // CHECK: call void @objc_storeStrong{{.*}} !dbg ![[ARC1:[0-9]+]]
+ // CHECK: call {{.*}} @objc_autoreleaseReturnValue{{.*}} !dbg ![[ARC2:[0-9]+]]
+ // CHECK: ret {{.*}} !dbg ![[ARC2]]
+ // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ return path;
+ // CHECK: ![[ARC1]] = metadata !{i32 [[@LINE+2]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[ARC2]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+@end
diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m
index 78c5d9d23721..19a5516dc7ca 100644
--- a/test/CodeGenObjC/arc-literals.m
+++ b/test/CodeGenObjC/arc-literals.m
@@ -12,7 +12,7 @@
// CHECK: c"dictionaryWithObjects:forKeys:count:\00"
// CHECK: c"prop\00"
-// CHECK: define void @test_numeric()
+// CHECK-LABEL: define void @test_numeric()
void test_numeric() {
// CHECK: {{call.*objc_msgSend.*i32 17}}
// CHECK: call i8* @objc_retainAutoreleasedReturnValue
@@ -33,7 +33,7 @@ void test_numeric() {
// CHECK-NEXT: ret void
}
-// CHECK: define void @test_array
+// CHECK-LABEL: define void @test_array
void test_array(id a, id b) {
// CHECK: [[A:%.*]] = alloca i8*,
// CHECK: [[B:%.*]] = alloca i8*,
@@ -65,7 +65,7 @@ void test_array(id a, id b) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @test_dictionary
+// CHECK-LABEL: define void @test_dictionary
void test_dictionary(id k1, id o1, id k2, id o2) {
// CHECK: [[K1:%.*]] = alloca i8*,
// CHECK: [[O1:%.*]] = alloca i8*,
@@ -119,7 +119,7 @@ void test_dictionary(id k1, id o1, id k2, id o2) {
@property (retain) A* prop;
@end
-// CHECK: define void @test_property
+// CHECK-LABEL: define void @test_property
void test_property(B *b) {
// Retain parameter
// CHECK: call i8* @objc_retain
diff --git a/test/CodeGenObjC/arc-loadweakretained-release.m b/test/CodeGenObjC/arc-loadweakretained-release.m
index 00d25fac0db9..a84719d606de 100644
--- a/test/CodeGenObjC/arc-loadweakretained-release.m
+++ b/test/CodeGenObjC/arc-loadweakretained-release.m
@@ -42,7 +42,7 @@ void test1(int cond) {
test34_sink(cond ? &weak : 0);
}
-// CHECK: define void @test1(
+// CHECK-LABEL: define void @test1(
// CHECK: [[CONDADDR:%.*]] = alloca i32
// CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
// CHECK-NEXT: [[INCRTEMP:%.*]] = alloca i8*
diff --git a/test/CodeGenObjC/arc-no-arc-exceptions.m b/test/CodeGenObjC/arc-no-arc-exceptions.m
index 008c848987e1..681891bf7dcc 100644
--- a/test/CodeGenObjC/arc-no-arc-exceptions.m
+++ b/test/CodeGenObjC/arc-no-arc-exceptions.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O0 -disable-llvm-optzns -o - %s | FileCheck -check-prefix=NO-METADATA %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -disable-llvm-optzns -o - %s | FileCheck -check-prefix=NO-METADATA %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s -fobjc-arc-exceptions | FileCheck -check-prefix=NO-METADATA %s
// The front-end should emit clang.arc.no_objc_arc_exceptions in -fobjc-arc-exceptions
@@ -8,10 +8,10 @@
void thrower(void);
void not(void) __attribute__((nothrow));
-// CHECK: define void @test0(
+// CHECK-LABEL: define void @test0(
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
// CHECK: call void @not() [[NUW:#[0-9]+]], !clang.arc.no_objc_arc_exceptions !
-// NO-METADATA: define void @test0(
+// NO-METADATA-LABEL: define void @test0(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
void test0(void) {
@@ -19,10 +19,10 @@ void test0(void) {
not();
}
-// CHECK: define void @test1(
+// CHECK-LABEL: define void @test1(
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
// CHECK: call void @not() [[NUW]], !clang.arc.no_objc_arc_exceptions !
-// NO-METADATA: define void @test1(
+// NO-METADATA-LABEL: define void @test1(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
void test1(id x) {
@@ -33,10 +33,10 @@ void test1(id x) {
void NSLog(id, ...);
-// CHECK: define void @test2(
+// CHECK-LABEL: define void @test2(
// CHECK: invoke void (i8*, ...)* @NSLog(i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), i32* %{{.*}})
// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
-// NO-METADATA: define void @test2(
+// NO-METADATA-LABEL: define void @test2(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
void test2(void) {
@@ -46,10 +46,10 @@ void test2(void) {
}
}
-// CHECK: define void @test3(
+// CHECK-LABEL: define void @test3(
// CHECK: invoke void %{{.*}}(i8* %{{.*}})
// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
-// NO-METADATA: define void @test3(
+// NO-METADATA-LABEL: define void @test3(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
void test3(void) {
@@ -61,10 +61,10 @@ void test3(void) {
}
}
-// CHECK: define void @test4(
+// CHECK-LABEL: define void @test4(
// CHECK: invoke void %{{.*}}(i8* %{{.*}})
// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
-// NO-METADATA: define void @test4(
+// NO-METADATA-LABEL: define void @test4(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
void test4(void) {
diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m
index 595a4f9fdf26..e15d5d4835ce 100644
--- a/test/CodeGenObjC/arc-precise-lifetime.m
+++ b/test/CodeGenObjC/arc-precise-lifetime.m
@@ -25,11 +25,12 @@ void test0() {
// rdar://problem/9821110
@interface Test1
- (char*) interior __attribute__((objc_returns_inner_pointer));
-// Should we allow this on properties?
+// Should we allow this on properties? Yes! see // rdar://14990439
+@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));
@end
extern Test1 *test1_helper(void);
-// CHECK: define void @test1a()
+// CHECK-LABEL: define void @test1a()
void test1a(void) {
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
@@ -52,7 +53,7 @@ void test1a(void) {
char *c = [(ptr) interior];
}
-// CHECK: define void @test1b()
+// CHECK-LABEL: define void @test1b()
void test1b(void) {
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
@@ -73,12 +74,56 @@ void test1b(void) {
char *c = [ptr interior];
}
+void test1c(void) {
+ // 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: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+ // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
+ // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+ // CHECK-NEXT: store i8* [[T6]], i8**
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ Test1 *ptr = test1_helper();
+ char *pc = ptr.PropertyReturnsInnerPointer;
+}
+
+void test1d(void) {
+ // 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: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
+ // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
+ // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] 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: [[NINE:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[TEN]])
+ // CHECK-NEXT: ret void
+ __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
+ char *pc = ptr.PropertyReturnsInnerPointer;
+}
+
@interface Test2 {
@public
id ivar;
}
@end
-// CHECK: define void @test2(
+// CHECK-LABEL: define void @test2(
void test2(Test2 *x) {
x->ivar = 0;
// CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]*
@@ -104,7 +149,7 @@ void test2(Test2 *x) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @test3(i8*
+// CHECK-LABEL: define void @test3(i8*
void test3(PRECISE_LIFETIME id x) {
// CHECK: [[X:%.*]] = alloca i8*,
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]]
diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
index dde02d7dd710..c3c7e2bc11ec 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -7,7 +7,7 @@
void test0(Test0 *t0, id value) {
t0.value = value;
}
-// CHECK: define void @test0(
+// CHECK-LABEL: define void @test0(
// CHECK: call void @objc_storeStrong
// CHECK: call void @objc_storeStrong
// CHECK: @objc_msgSend
diff --git a/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
index e8b97012cdcc..72d287187920 100644
--- a/test/CodeGenObjC/arc-related-result-type.m
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -6,7 +6,7 @@
void test0(Test0 *val) {
Test0 *x = [val self];
-// CHECK: define void @test0(
+// CHECK-LABEL: define void @test0(
// CHECK: [[VAL:%.*]] = alloca [[TEST0:%.*]]*
// CHECK-NEXT: [[X:%.*]] = alloca [[TEST0]]*
// CHECK-NEXT: store [[TEST0]]* null
diff --git a/test/CodeGenObjC/arc-ternary-op.m b/test/CodeGenObjC/arc-ternary-op.m
index f70e8864a047..217db8019417 100644
--- a/test/CodeGenObjC/arc-ternary-op.m
+++ b/test/CodeGenObjC/arc-ternary-op.m
@@ -3,7 +3,7 @@
void test0(_Bool cond) {
id test0_helper(void) __attribute__((ns_returns_retained));
- // CHECK: define void @test0(
+ // CHECK-LABEL: define void @test0(
// CHECK: [[COND:%.*]] = alloca i8,
// CHECK-NEXT: [[X:%.*]] = alloca i8*,
// CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
@@ -40,7 +40,7 @@ void test1(int cond) {
test1_sink(cond ? &strong : 0);
test1_sink(cond ? &weak : 0);
- // CHECK: define void @test1(
+ // CHECK-LABEL: define void @test1(
// CHECK: [[COND:%.*]] = alloca i32
// CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
// CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
@@ -106,7 +106,7 @@ void test2(int cond) {
for (id obj in cond ? test2_producer() : (void*) 0) {
}
- // CHECK: define void @test2(
+ // CHECK-LABEL: define void @test2(
// CHECK: [[COND:%.*]] = alloca i32,
// CHECK: alloca i8*
// CHECK: [[CLEANUP_SAVE:%.*]] = alloca i8*
diff --git a/test/CodeGenObjC/arc-unopt.m b/test/CodeGenObjC/arc-unopt.m
index 84f5d34b196e..c0e67dfd3b0f 100644
--- a/test/CodeGenObjC/arc-unopt.m
+++ b/test/CodeGenObjC/arc-unopt.m
@@ -55,7 +55,7 @@ void test5(void) {
if ((x = y))
y = 0;
-// CHECK: define void @test5()
+// CHECK-LABEL: define void @test5()
// CHECK: [[X:%.*]] = alloca [[TEST5:%.*]]*,
// CHECK-NEXT: [[Y:%.*]] = alloca [[TEST5:%.*]]*,
// CHECK-NEXT: store [[TEST5]]* null, [[TEST5]]** [[X]],
diff --git a/test/CodeGenObjC/arc-unoptimized-byref-var.m b/test/CodeGenObjC/arc-unoptimized-byref-var.m
index d3189e15d3d1..4a30c6af7f1c 100644
--- a/test/CodeGenObjC/arc-unoptimized-byref-var.m
+++ b/test/CodeGenObjC/arc-unoptimized-byref-var.m
@@ -3,7 +3,7 @@
void test19() {
__block id x;
-// CHECK-UNOPT: define internal void @__Block_byref_object_copy
+// CHECK-UNOPT-LABEL: define internal void @__Block_byref_object_copy
// CHECK-UNOPT: [[X:%.*]] = getelementptr inbounds [[BYREF_T:%.*]]* [[VAR:%.*]], i32 0, i32 6
// CHECK-UNOPT: [[X2:%.*]] = getelementptr inbounds [[BYREF_T:%.*]]* [[VAR1:%.*]], i32 0, i32 6
// CHECK-UNOPT-NEXT: [[SIX:%.*]] = load i8** [[X2]], align 8
diff --git a/test/CodeGenObjC/arc-with-atthrow.m b/test/CodeGenObjC/arc-with-atthrow.m
index 257037679af0..e5295159ce5e 100644
--- a/test/CodeGenObjC/arc-with-atthrow.m
+++ b/test/CodeGenObjC/arc-with-atthrow.m
@@ -9,7 +9,7 @@ void test() {
// TODO: We should probably emit this specific pattern without the reclaim.
-// CHECK: define void @test()
+// CHECK-LABEL: define void @test()
// CHECK: [[T0:%.*]] = call i8* @make()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autorelease(i8* [[T1]])
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 7262dc8d7b1c..00cdb6fcc529 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -32,7 +32,7 @@
// ARC-NATIVE: declare i8* @objc_autorelease(i8*)
// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8*)
-// CHECK: define void @test0
+// CHECK-LABEL: define void @test0
void test0(id x) {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{.*}})
@@ -42,7 +42,7 @@ void test0(id x) {
// CHECK-NEXT: ret void
}
-// CHECK: define i8* @test1(i8*
+// CHECK-LABEL: define i8* @test1(i8*
id test1(id x) {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[Y:%.*]] = alloca i8*
@@ -94,7 +94,7 @@ id test1(id x) {
- (id) copy;
@end
-// CHECK: define void @test3_unelided()
+// CHECK-LABEL: define void @test3_unelided()
void test3_unelided() {
extern void test3_helper(void);
@@ -125,7 +125,7 @@ void test3_unelided() {
// CHECK-NEXT: ret void
}
-// CHECK: define void @test3()
+// CHECK-LABEL: define void @test3()
void test3() {
// CHECK: [[X:%.*]] = alloca i8*
@@ -166,7 +166,7 @@ void test3() {
// CHECK-NEXT: ret void
}
-// CHECK: define i8* @test4()
+// CHECK-LABEL: define i8* @test4()
id test4() {
// Call to +alloc.
// CHECK: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
@@ -197,7 +197,7 @@ id test4() {
}
@end
-// CHECK: define void @test5
+// CHECK-LABEL: define void @test5
void test5(Test5 *x, id y) {
// Prologue.
// CHECK: [[X:%.*]] = alloca [[TEST5:%.*]]*,
@@ -241,7 +241,7 @@ void test5(Test5 *x, id y) {
}
id test6_helper(void) __attribute__((ns_returns_retained));
-// CHECK: define void @test6()
+// CHECK-LABEL: define void @test6()
void test6() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper()
@@ -253,7 +253,7 @@ void test6() {
}
void test7_helper(id __attribute__((ns_consumed)));
-// CHECK: define void @test7()
+// CHECK-LABEL: define void @test7()
void test7() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[X]]
@@ -284,7 +284,7 @@ void test10() {
Test10 *x;
id y = x.me.me;
- // CHECK: define void @test10()
+ // CHECK-LABEL: define void @test10()
// CHECK: [[X:%.*]] = alloca [[TEST10:%.*]]*, align
// CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
// CHECK-NEXT: store [[TEST10]]* null, [[TEST10]]** [[X]]
@@ -314,7 +314,7 @@ void test10() {
}
void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
- // CHECK: define void @test11(
+ // CHECK-LABEL: define void @test11(
// CHECK: [[F:%.*]] = alloca i8* ()*, align
// CHECK-NEXT: [[X:%.*]] = alloca i8*, align
// CHECK-NEXT: store i8* ()* {{%.*}}, i8* ()** [[F]], align
@@ -330,7 +330,7 @@ void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
void test12(void) {
extern id test12_helper(void);
- // CHECK: define void @test12()
+ // CHECK-LABEL: define void @test12()
// CHECK: [[X:%.*]] = alloca i8*, align
// CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
@@ -358,7 +358,7 @@ void test12(void) {
// Indirect consuming calls.
void test13(void) {
- // CHECK: define void @test13()
+ // CHECK-LABEL: define void @test13()
// CHECK: [[X:%.*]] = alloca i8*, align
// CHECK-NEXT: store i8* null, i8** [[X]], align
id x;
@@ -458,7 +458,7 @@ void test13(void) {
@end
void test19() {
- // CHECK: define void @test19()
+ // CHECK-LABEL: define void @test19()
// CHECK: [[X:%.*]] = alloca [5 x i8*], align 16
// CHECK: call void @llvm.lifetime.start
// CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8*
@@ -490,7 +490,7 @@ void test19() {
}
void test20(unsigned n) {
- // CHECK: define void @test20
+ // CHECK-LABEL: define void @test20
// CHECK: [[N:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
// CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
@@ -531,7 +531,7 @@ void test20(unsigned n) {
}
void test21(unsigned n) {
- // CHECK: define void @test21
+ // CHECK-LABEL: define void @test21
// CHECK: [[N:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
// CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
@@ -829,7 +829,7 @@ char *helper;
@end
__attribute__((ns_returns_retained)) id test32(void) {
-// CHECK: define i8* @test32()
+// CHECK-LABEL: define i8* @test32()
// CHECK: [[CALL:%.*]] = call i8* @test32_helper()
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
// CHECK-NEXT: ret i8* [[T0]]
@@ -932,7 +932,7 @@ void test33(Test33 *ptr) {
}
-// CHECK: define void @test36
+// CHECK-LABEL: define void @test36
void test36(id x) {
// CHECK: [[X:%.*]] = alloca i8*
@@ -960,7 +960,7 @@ void test37(void) {
Test37 *var;
test37_helper(&var);
- // CHECK: define void @test37()
+ // CHECK-LABEL: define void @test37()
// CHECK: [[VAR:%.*]] = alloca [[TEST37:%.*]]*,
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
// CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]]
@@ -1037,7 +1037,7 @@ void test47(void) {
extern id test47_helper(void);
id x = x = test47_helper();
- // CHECK: define void @test47()
+ // CHECK-LABEL: define void @test47()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test47_helper()
@@ -1057,7 +1057,7 @@ void test47(void) {
void test48(void) {
extern id test48_helper(void);
__weak id x = x = test48_helper();
- // CHECK: define void @test48()
+ // CHECK-LABEL: define void @test48()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_initWeak(i8** [[X]], i8* null)
// CHECK-NEXT: [[T1:%.*]] = call i8* @test48_helper()
@@ -1072,7 +1072,7 @@ void test48(void) {
void test49(void) {
extern id test49_helper(void);
__autoreleasing id x = x = test49_helper();
- // CHECK: define void @test49()
+ // CHECK-LABEL: define void @test49()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test49_helper()
@@ -1113,13 +1113,16 @@ id test52(void) {
id test52_helper(int) __attribute__((ns_returns_retained));
return ({ int x = 5; test52_helper(x); });
-// CHECK: define i8* @test52()
+// CHECK-LABEL: define i8* @test52()
// CHECK: [[X:%.*]] = alloca i32
+// CHECK-NEXT: [[TMPALLOCA:%.*]] = alloca i8*
// CHECK-NEXT: store i32 5, i32* [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i32* [[X]],
// CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]])
-// CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]])
-// CHECK-NEXT: ret i8* [[T2]]
+// CHECK-NEXT: store i8* [[T1]], i8** [[TMPALLOCA]]
+// CHECK-NEXT: [[T2:%.*]] = load i8** [[TMPALLOCA]]
+// CHECK-NEXT: [[T3:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T2]])
+// CHECK-NEXT: ret i8* [[T3]]
}
// rdar://problem/9400644
@@ -1127,17 +1130,20 @@ void test53(void) {
id test53_helper(void);
id x = ({ id y = test53_helper(); y; });
(void) x;
-// CHECK: define void @test53()
+// CHECK-LABEL: define void @test53()
// CHECK: [[X:%.*]] = alloca i8*,
// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[TMPALLOCA:%.*]] = alloca i8*,
// CHECK-NEXT: [[T0:%.*]] = call i8* @test53_helper()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]],
// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]],
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[TMPALLOCA]]
// CHECK-NEXT: [[T2:%.*]] = load i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
-// CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+// CHECK-NEXT: [[T3:%.*]] = load i8** [[TMPALLOCA]]
+// CHECK-NEXT: store i8* [[T3]], i8** [[X]],
// CHECK-NEXT: load i8** [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
@@ -1145,7 +1151,7 @@ void test53(void) {
}
// <rdar://problem/9758798>
-// CHECK: define void @test54(i32 %first, ...)
+// CHECK-LABEL: define void @test54(i32 %first, ...)
void test54(int first, ...) {
__builtin_va_list arglist;
// CHECK: call void @llvm.va_start
@@ -1185,7 +1191,7 @@ void test54(int first, ...) {
@end
void test56_test(void) {
id x = [Test56 make];
- // CHECK: define void @test56_test()
+ // CHECK-LABEL: define void @test56_test()
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK: [[T0:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(
// CHECK-NEXT: store i8* [[T0]], i8** [[X]]
@@ -1239,7 +1245,7 @@ void test59(void) {
test59_body();
}
- // CHECK: define void @test59()
+ // CHECK-LABEL: define void @test59()
// CHECK: [[T0:%.*]] = call i8* @test59_getlock()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: call i32 @objc_sync_enter(i8* [[T1]])
@@ -1257,7 +1263,7 @@ void test59(void) {
- (id) test61_id;
@end
void test61(void) {
- // CHECK: define void @test61()
+ // CHECK-LABEL: define void @test61()
// CHECK: [[Y:%.*]] = alloca i8*, align 8
extern id test61_make(void);
@@ -1287,7 +1293,7 @@ void test61(void) {
// rdar://problem/9891815
void test62(void) {
- // CHECK: define void @test62()
+ // CHECK-LABEL: define void @test62()
// CHECK: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[CLEANUP_VALUE:%.*]] = alloca i8*
// CHECK-NEXT: [[CLEANUP_REQUIRED:%.*]] = alloca i1
@@ -1359,7 +1365,7 @@ void test66(void) {
extern id test66_arg(void);
[test66_receiver() consume: test66_arg()];
}
-// CHECK: define void @test66()
+// CHECK-LABEL: define void @test66()
// CHECK: [[T0:%.*]] = call [[TEST66:%.*]]* @test66_receiver()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST66]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
@@ -1383,7 +1389,7 @@ Class test67_helper(void);
void test67(void) {
Class cl = test67_helper();
}
-// CHECK: define void @test67()
+// CHECK-LABEL: define void @test67()
// CHECK: [[CL:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
// CHECK-NEXT: store i8* [[T0]], i8** [[CL]], align 8
@@ -1393,7 +1399,7 @@ Class test68_helper(void);
void test68(void) {
__strong Class cl = test67_helper();
}
-// CHECK: define void @test68()
+// CHECK-LABEL: define void @test68()
// CHECK: [[CL:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
@@ -1415,7 +1421,7 @@ void test68(void) {
// rdar://problem/10907547
void test70(id i) {
- // CHECK: define void @test70
+ // CHECK-LABEL: define void @test70
// CHECK: store i8* null, i8**
// CHECK: store i8* null, i8**
// CHECK: [[ID:%.*]] = call i8* @objc_retain(i8*
diff --git a/test/CodeGenObjC/assign.m b/test/CodeGenObjC/assign.m
index bdc99c635835..7d0c06f74353 100644
--- a/test/CodeGenObjC/assign.m
+++ b/test/CodeGenObjC/assign.m
@@ -12,7 +12,7 @@ struct s0 {
// Check that we get exactly the message sends we expect, and no more.
//
-// CHECK: define void @f0
+// CHECK-LABEL: define void @f0
void f0(C0 *a) {
// CHECK: objc_msgSend
int l0 = (a.x0 = 1);
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
index 878255b0fb3f..1b9cb8f8e865 100644
--- a/test/CodeGenObjC/atomic-aggregate-property.m
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP64 %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP64 %s
// rdar: // 7849824
// <rdar://problem/12547611>
diff --git a/test/CodeGenObjC/auto-property-synthesize-protocol.m b/test/CodeGenObjC/auto-property-synthesize-protocol.m
index 49a4037e2645..e0c54894849a 100644
--- a/test/CodeGenObjC/auto-property-synthesize-protocol.m
+++ b/test/CodeGenObjC/auto-property-synthesize-protocol.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fobjc-default-synthesize-properties -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s
// rdar://10907410
@protocol P
diff --git a/test/CodeGenObjC/autorelease.m b/test/CodeGenObjC/autorelease.m
index f89b81a8acb9..4b8101720123 100644
--- a/test/CodeGenObjC/autorelease.m
+++ b/test/CodeGenObjC/autorelease.m
@@ -39,7 +39,7 @@ int tryTo(int (*f)(void)) {
return 0;
}
}
-// CHECK: define i32 @tryTo(i32 ()*
+// CHECK-LABEL: define i32 @tryTo(i32 ()*
// CHECK: [[RET:%.*]] = alloca i32,
// CHECK: [[T0:%.*]] = call i8* @objc_autoreleasePoolPush()
// CHECK-NEXT: [[T1:%.*]] = load i32 ()** {{%.*}},
diff --git a/test/CodeGenObjC/bitfield-access.m b/test/CodeGenObjC/bitfield-access.m
index 597fe3567942..2b8039df9ec1 100644
--- a/test/CodeGenObjC/bitfield-access.m
+++ b/test/CodeGenObjC/bitfield-access.m
@@ -14,7 +14,7 @@
// Check that we don't try to use an i32 load here, which would reach beyond the
// end of the structure.
//
-// CHECK-I386: define i32 @f0(
+// CHECK-I386-LABEL: define i32 @f0(
// CHECK-I386: [[t0_0:%.*]] = load i8* {{.*}}, align 1
// CHECK-I386: lshr i8 [[t0_0]], 7
// CHECK-I386: }
@@ -24,7 +24,7 @@ int f0(I0 *a) {
// Check that we can handled straddled loads.
//
-// CHECK-ARM: define i32 @f1(
+// CHECK-ARM-LABEL: define i32 @f1(
// CHECK-ARM: [[t1_ptr:%.*]] = getelementptr
// CHECK-ARM: [[t1_base:%.*]] = bitcast i8* [[t1_ptr]] to i40*
// CHECK-ARM: [[t1_0:%.*]] = load i40* [[t1_base]], align 1
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
index 7a07f27d2653..f17d56af19ce 100644
--- a/test/CodeGenObjC/bitfield-ivar-offsets.m
+++ b/test/CodeGenObjC/bitfield-ivar-offsets.m
@@ -6,7 +6,7 @@
// RUN: grep -F '@"OBJC_IVAR_$_I0._b3" = global i64 4, section "__DATA, __objc_ivar", align 8' %t
// RUN: grep -F '@"OBJC_IVAR_$_I0._y" = global i64 6, section "__DATA, __objc_ivar", align 8' %t
// RUN: grep -F '@"OBJC_IVAR_$_I0._b4" = global i64 7, section "__DATA, __objc_ivar", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0." = global' %t | count 0
+// RUN: not grep -F '@"OBJC_IVAR_$_I0." = global' %t
@interface I0 {
unsigned _b0:4;
diff --git a/test/CodeGenObjC/block-6.m b/test/CodeGenObjC/block-6.m
index 57b9ea3fa6ea..b04b1893191c 100644
--- a/test/CodeGenObjC/block-6.m
+++ b/test/CodeGenObjC/block-6.m
@@ -2,7 +2,7 @@
// rdar://8893785
void MYFUNC() {
-// CHECK: define void @MYFUNC()
+// CHECK-LABEL: define void @MYFUNC()
// CHECK: [[OBSERVER_SLOT:%.*]] = alloca [[OBSERVER_T:%.*]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[OBSERVER_SLOT]], i32 0, i32 1
diff --git a/test/CodeGenObjC/block-byref-debuginfo.m b/test/CodeGenObjC/block-byref-debuginfo.m
new file mode 100644
index 000000000000..88a8d8d50c1f
--- /dev/null
+++ b/test/CodeGenObjC/block-byref-debuginfo.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -g -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s
+
+// rdar://problem/14386148
+// Test that the foo is aligned at an 8 byte boundary in the DWARF
+// expression (256) that locates it inside of the byref descriptor:
+// CHECK: metadata !"foo", i32 0, i64 {{[0-9]+}}, i64 64, i64 256, i32 0, metadata
+
+struct Foo {
+ unsigned char *data;
+};
+int func() {
+ __attribute__((__blocks__(byref))) struct Foo foo;
+ return 0;
+}
diff --git a/test/CodeGenObjC/block-byref-variable-layout.m b/test/CodeGenObjC/block-byref-variable-layout.m
index 9c8f6743be3d..a03617bce293 100644
--- a/test/CodeGenObjC/block-byref-variable-layout.m
+++ b/test/CodeGenObjC/block-byref-variable-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s
// rdar://12759433
@class NSString;
diff --git a/test/CodeGenObjC/block-var-layout.m b/test/CodeGenObjC/block-var-layout.m
index ab9523126c3d..0ad44daa0bdb 100644
--- a/test/CodeGenObjC/block-var-layout.m
+++ b/test/CodeGenObjC/block-var-layout.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.layout %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.layout %s
// rdar://12752901
struct S {
diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m
index 99a11f91e4cd..0d2c35096ae4 100644
--- a/test/CodeGenObjC/blocks-1.m
+++ b/test/CodeGenObjC/blocks-1.m
@@ -4,7 +4,7 @@
// RUN: grep "__destroy_helper_block_" %t | count 4
// RUN: grep "__Block_byref_object_copy_" %t | count 2
// RUN: grep "__Block_byref_object_dispose_" %t | count 2
-// RUN: grep "i32 135)" %t | count 0
+// RUN: not grep "i32 135)" %t
// RUN: grep "_Block_object_assign" %t | count 4
// RUN: grep "objc_read_weak" %t | count 2
// RUN: grep "objc_assign_weak" %t | count 3
@@ -14,7 +14,7 @@
// RUN: grep "__destroy_helper_block_" %t | count 4
// RUN: grep "__Block_byref_object_copy_" %t | count 2
// RUN: grep "__Block_byref_object_dispose_" %t | count 2
-// RUN: grep "i32 135)" %t | count 0
+// RUN: not grep "i32 135)" %t
// RUN: grep "_Block_object_assign" %t | count 4
// RUN: grep "objc_read_weak" %t | count 2
// RUN: grep "objc_assign_weak" %t | count 3
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 3718ad590a53..5245679dd42d 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -7,7 +7,7 @@ struct S {
@interface T
- - (int)foo: (T (^)(T*)) x;
+ - (int)foo: (T* (^)(T*)) x;
@end
void foo(T *P) {
@@ -43,7 +43,7 @@ void foo(T *P) {
@interface Test2 -(void) destroy; @end
void test2(Test2 *x) {
extern void test2_helper(void (^)(void));
- // CHECK: define void @test2(
+ // CHECK-LABEL: define void @test2(
// CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]*,
// CHECK-NEXT: [[WEAKX:%.*]] = alloca [[WEAK_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
@@ -91,7 +91,7 @@ void test2(Test2 *x) {
// rdar://problem/9124263
// In the test above, check that the use in the invocation function
// doesn't require a read barrier.
-// CHECK: define internal void @__test2_block_invoke
+// CHECK-LABEL: define internal void @__test2_block_invoke
// CHECK: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
// CHECK-NOT: bitcast
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
@@ -107,7 +107,7 @@ void test2(Test2 *x) {
void test3(void (^block)(int, ...)) {
block(0, 1, 2, 3);
}
-// CHECK: define void @test3(
+// CHECK-LABEL: define void @test3(
// CHECK: [[BLOCK:%.*]] = alloca void (i32, ...)*, align 4
// CHECK-NEXT: store void (i32, ...)*
// CHECK-NEXT: [[T0:%.*]] = load void (i32, ...)** [[BLOCK]], align 4
@@ -122,7 +122,7 @@ void test3(void (^block)(int, ...)) {
void test4(void (^block)()) {
block(0, 1, 2, 3);
}
-// CHECK: define void @test4(
+// CHECK-LABEL: define void @test4(
// CHECK: [[BLOCK:%.*]] = alloca void (...)*, align 4
// CHECK-NEXT: store void (...)*
// CHECK-NEXT: [[T0:%.*]] = load void (...)** [[BLOCK]], align 4
diff --git a/test/CodeGenObjC/builtins.m b/test/CodeGenObjC/builtins.m
index 0c5744805e6d..37d8c7a3e95d 100644
--- a/test/CodeGenObjC/builtins.m
+++ b/test/CodeGenObjC/builtins.m
@@ -3,5 +3,5 @@
void test0(id receiver, SEL sel, const char *str) {
short s = ((short (*)(id, SEL, const char*)) objc_msgSend)(receiver, sel, str);
}
-// CHECK: define void @test0(
+// CHECK-LABEL: define void @test0(
// CHECK: call signext i16 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i16 (i8*, i8*, i8*)*)(
diff --git a/test/CodeGenObjC/complex-property.m b/test/CodeGenObjC/complex-property.m
index 8c3aef9e24bd..d65d72fdd70c 100644
--- a/test/CodeGenObjC/complex-property.m
+++ b/test/CodeGenObjC/complex-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP64 %s
// rdar: // 7351147
@interface A
diff --git a/test/CodeGenObjC/debug-info-block-line.m b/test/CodeGenObjC/debug-info-block-line.m
index 2192575bb78e..1965e1d7dcdc 100644
--- a/test/CodeGenObjC/debug-info-block-line.m
+++ b/test/CodeGenObjC/debug-info-block-line.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-default-synthesize-properties -fobjc-arc -O0 -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-arc -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
// rdar://11562117
typedef unsigned int NSUInteger;
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index 3d91c9ea5cd4..63068a9ca980 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -2,16 +2,31 @@
// rdar://problem/9279956
// Test that we generate the proper debug location for a captured self.
-// The second half of this patch is in llvm/tests/DebugInfo/debug-info-blocks.ll
+// The second half of this test is in llvm/tests/DebugInfo/debug-info-blocks.ll
// CHECK: define {{.*}}_block_invoke
// CHECK: %[[BLOCK:.*]] = bitcast i8* %.block_descriptor to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>*, !dbg
// CHECK-NEXT: store <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA:.*]], align
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]]}, metadata ![[SELF:[0-9]+]])
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{%1** %d}, metadata ![[D:[0-9]+]])
-// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 51]
-// CHECK: ![[D]] = {{.*}} [d] [line 49]
+// 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.
+// 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: define {{.*}} @__destroy_helper_block_{{.*}}(i8*)
+// CHECK-NOT: ret
+// CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]]
+
+// CHECK-DAG: [[DBG_LINE]] = metadata !{i32 0, i32 0, metadata ![[COPY_SP:[0-9]+]], null}
+// CHECK-DAG: [[COPY_LINE]] = metadata !{i32 0, i32 0, metadata ![[COPY_SP:[0-9]+]], null}
+// CHECK-DAG: [[COPY_SP]] = {{.*}}[ DW_TAG_subprogram ]{{.*}}[__copy_helper_block_]
+// CHECK-DAG: [[DESTROY_LINE]] = metadata !{i32 0, i32 0, metadata ![[DESTROY_SP:[0-9]+]], null}
+// CHECK-DAG: [[DESTROY_SP]] = {{.*}}[ DW_TAG_subprogram ]{{.*}}[__destroy_helper_block_]
typedef unsigned int NSUInteger;
@protocol NSObject
@@ -46,6 +61,8 @@ static void run(void (^block)(void))
{
if ((self = [super init])) {
run(^{
+ // CHECK-DAG: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line [[@LINE+4]]]
+ // CHECK-DAG: ![[D]] = {{.*}} [d] [line [[@LINE+1]]]
NSMutableDictionary *d = [[NSMutableDictionary alloc] init];
ivar = 42 + (int)[d count];
});
diff --git a/test/CodeGenObjC/debug-info-default-synth-ivar.m b/test/CodeGenObjC/debug-info-default-synth-ivar.m
index 30d751e67d1e..e9045eca4388 100644
--- a/test/CodeGenObjC/debug-info-default-synth-ivar.m
+++ b/test/CodeGenObjC/debug-info-default-synth-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -g %s -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o %t
// RUN: grep DW_TAG_member %t | count 5
// rdar://8493239
diff --git a/test/CodeGenObjC/debug-info-fwddecl.m b/test/CodeGenObjC/debug-info-fwddecl.m
index b41c485e1922..b43d7c0eb87c 100644
--- a/test/CodeGenObjC/debug-info-fwddecl.m
+++ b/test/CodeGenObjC/debug-info-fwddecl.m
@@ -2,4 +2,4 @@
@class ForwardObjcClass;
ForwardObjcClass *ptr = 0;
-// CHECK: {{.*}} [ DW_TAG_structure_type ] [ForwardObjcClass] [line 2, size 0, align 0, offset 0] [fwd]
+// CHECK: {{.*}} [ DW_TAG_structure_type ] [ForwardObjcClass] [line 2, size 0, align 0, offset 0] [decl]
diff --git a/test/CodeGenObjC/debug-info-id-with-protocol.m b/test/CodeGenObjC/debug-info-id-with-protocol.m
index db1a3ef74547..7e96baffdeea 100644
--- a/test/CodeGenObjC/debug-info-id-with-protocol.m
+++ b/test/CodeGenObjC/debug-info-id-with-protocol.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
__attribute((objc_root_class)) @interface NSObject {
id isa;
}
@@ -36,6 +36,6 @@ int main()
}
}
// Verify that the debug type for both variables is 'id'.
-// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"bad_carrier", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[IDTYPE:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [bad_carrier] [line 21]
-// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"good_carrier", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{.*}}[[IDTYPE]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [good_carrier] [line 22]
+// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"bad_carrier", null, i32 {{[0-9]+}}, metadata ![[IDTYPE:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [bad_carrier] [line 0]
+// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"good_carrier", null, i32 {{[0-9]+}}, metadata !{{.*}}[[IDTYPE]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [good_carrier] [line 0]
// CHECK !{{.*}}[[IDTYPE]] = metadata !{i32 {{[0-9]+}}, null, metadata !"id", metadata !{{[0-9]+}}, i32 !{{[0-9]+}}, i64 0, i64 0, i64 0, i32 0, metadata !{{[0-9]+}}} ; [ DW_TAG_typedef ] [id]
diff --git a/test/CodeGenObjC/debug-info-instancetype.m b/test/CodeGenObjC/debug-info-instancetype.m
new file mode 100644
index 000000000000..1c155179a382
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-instancetype.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// rdar://problem/13359718
+// Substitute the actual type for a method returning instancetype.
+@interface NSObject
++ (id)alloc;
+- (id)init;
+- (id)retain;
+@end
+
+@interface Foo : NSObject
++ (instancetype)defaultFoo;
+@end
+
+@implementation Foo
++(instancetype)defaultFoo {return 0;}
+// CHECK: ![[FOO:[0-9]+]] = metadata {{.*}}; [ DW_TAG_structure_type ] [Foo]
+// CHECK: metadata !"+[Foo defaultFoo]", metadata !"", i32 [[@LINE-2]], metadata ![[TYPE:[0-9]+]]
+// CHECK: ![[TYPE]] = {{.*}} metadata ![[RESULT:[0-9]+]], i32 {{.*}}, null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: ![[RESULT]] = metadata {{.*}}{metadata ![[FOOPTR:[0-9]+]],
+// CHECK: ![[FOOPTR]] = {{.*}}, metadata ![[FOO]]}{{.*}}[ DW_TAG_pointer_type ] {{.*}} [from Foo]
+@end
+
+
+int main (int argc, const char *argv[])
+{
+ Foo *foo = [Foo defaultFoo];
+ return 0;
+}
diff --git a/test/CodeGenObjC/debug-info-lifetime-crash.m b/test/CodeGenObjC/debug-info-lifetime-crash.m
new file mode 100644
index 000000000000..90382010fb6d
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-lifetime-crash.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -cc1 -triple arm-apple-ios -emit-llvm -g -fblocks -fobjc-runtime=ios-7.0.0 -fobjc-arc %s -o - | FileCheck %s
+// rdar://problem/14990656
+@protocol NSObject
+- (id)copy;
+@end
+@class W;
+@interface View1
+@end
+@implementation Controller {
+ void (^Block)(void);
+}
+- (void)View:(View1 *)View foo:(W *)W
+{
+ // The debug type for these two will be identical, because we do not
+ // actually emit the ownership qualifier.
+ // CHECK-DAG: metadata !"weakSelf", metadata !{{[0-9]+}}, i32 [[@LINE+1]], metadata ![[SELFTY:[0-9]+]], i32 0, i32 0, {{.*}}} ; [ DW_TAG_auto_variable ] [weakSelf]
+ __attribute__((objc_ownership(weak))) __typeof(self) weakSelf = self;
+ Block = [^{
+ // CHECK-DAG: metadata !"strongSelf", metadata !{{[0-9]+}}, i32 [[@LINE+1]], metadata ![[SELFTY]], i32 0, i32 0} ; [ DW_TAG_auto_variable ] [strongSelf]
+ __attribute__((objc_ownership(strong))) __typeof(self) strongSelf = weakSelf;
+ } copy];
+}
+@end
diff --git a/test/CodeGenObjC/debug-info-property-accessors.m b/test/CodeGenObjC/debug-info-property-accessors.m
new file mode 100644
index 000000000000..4c7b98466a3e
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property-accessors.m
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -emit-llvm -x objective-c -g -triple x86_64-apple-macosx10.8.0 %s -o - | FileCheck %s
+//
+// rdar://problem/14035789
+//
+// Ensure we emit the names of explicit/renamed accessors even if they
+// are defined later in the implementation section.
+//
+// CHECK: metadata !{i32 {{.*}}, metadata !"blah", {{.*}} metadata !"isBlah", metadata !"", {{.*}}} ; [ DW_TAG_APPLE_property ] [blah]
+
+@class NSString;
+extern void NSLog(NSString *format, ...);
+typedef signed char BOOL;
+
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+
+typedef unsigned int NSUInteger;
+
+@protocol NSObject
+@end
+
+@interface NSObject <NSObject>
+- (id)init;
++ (id)alloc;
+@end
+
+@interface Bar : NSObject
+@property int normal_property;
+@property (getter=isBlah, setter=setBlah:) BOOL blah;
+@end
+
+@implementation Bar
+@synthesize normal_property;
+
+- (BOOL) isBlah
+{
+ return YES;
+}
+- (void) setBlah: (BOOL) newBlah
+{
+ NSLog (@"Speak up, I didn't catch that.");
+}
+@end
+
+int
+main ()
+{
+ Bar *my_bar = [[Bar alloc] init];
+
+ if (my_bar.blah)
+ NSLog (@"It was true!!!");
+
+ my_bar.blah = NO;
+
+ return 0;
+}
diff --git a/test/CodeGenObjC/debug-info-property4.m b/test/CodeGenObjC/debug-info-property4.m
index 6d9973c3e0e2..71863a6b9f3b 100644
--- a/test/CodeGenObjC/debug-info-property4.m
+++ b/test/CodeGenObjC/debug-info-property4.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK: AT_APPLE_property_name
// CHECK-NOT: AT_APPLE_property_getter
diff --git a/test/CodeGenObjC/debug-info-property5.m b/test/CodeGenObjC/debug-info-property5.m
index 35215749ecd9..272aa5de0760 100644
--- a/test/CodeGenObjC/debug-info-property5.m
+++ b/test/CodeGenObjC/debug-info-property5.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK: AT_APPLE_property_name
// CHECK: AT_APPLE_property_getter
diff --git a/test/CodeGenObjC/debug-info-self.m b/test/CodeGenObjC/debug-info-self.m
index 7803467eab9a..8cbc0292f0ae 100644
--- a/test/CodeGenObjC/debug-info-self.m
+++ b/test/CodeGenObjC/debug-info-self.m
@@ -14,10 +14,6 @@
}
@end
-// It's weird that the first two parameters are recorded as being in a
-// different, ("<unknown>") file compared to the third parameter which is 'in'
-// the actual source file. (see the metadata node after the arg name in each
-// line)
-// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR:.*]], metadata !"self", metadata ![[UNKFILE:.*]], i32 16777227, metadata !{{.*}}, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [self] [line 11]
-// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"_cmd", metadata ![[UNKFILE]], i32 33554443, metadata !{{.*}}, i32 64, i32 0} ; [ DW_TAG_arg_variable ] [_cmd] [line 11]
+// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR:.*]], metadata !"self", null, i32 16777216, metadata !{{.*}}, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [self] [line 0]
+// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"_cmd", null, i32 33554432, metadata !{{.*}}, i32 64, i32 0} ; [ DW_TAG_arg_variable ] [_cmd] [line 0]
// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"myarg", metadata !{{.*}}, i32 50331659, metadata !{{.*}}, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [myarg] [line 11]
diff --git a/test/CodeGenObjC/debuginfo-properties.m b/test/CodeGenObjC/debuginfo-properties.m
new file mode 100644
index 000000000000..9a3571458307
--- /dev/null
+++ b/test/CodeGenObjC/debuginfo-properties.m
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -g -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+// Check that we emit the correct method names for properties from a protocol.
+// rdar://problem/13798000
+@protocol NSObject
+- (id)init;
+@end
+@interface NSObject <NSObject> {}
+@end
+
+@class Selection;
+
+@protocol HasASelection <NSObject>
+@property (nonatomic, retain) Selection* selection;
+// CHECK: [ DW_TAG_subprogram ] [line [[@LINE-1]]] [local] [def] [-[MyClass selection]]
+// CHECK: [ DW_TAG_subprogram ] [line [[@LINE-2]]] [local] [def] [-[MyClass setSelection:]]
+// CHECK: [ DW_TAG_subprogram ] [line [[@LINE-3]]] [local] [def] [-[OtherClass selection]]
+// CHECK: [ DW_TAG_subprogram ] [line [[@LINE-4]]] [local] [def] [-[OtherClass setSelection:]]
+@end
+
+@interface MyClass : NSObject <HasASelection> {
+ Selection *_selection;
+}
+@end
+
+@implementation MyClass
+@synthesize selection = _selection;
+@end
+
+@interface OtherClass : NSObject <HasASelection> {
+ Selection *_selection;
+}
+@end
+@implementation OtherClass
+@synthesize selection = _selection;
+@end
diff --git a/test/CodeGenObjC/designated-initializers.m b/test/CodeGenObjC/designated-initializers.m
new file mode 100644
index 000000000000..80dfdf3602c6
--- /dev/null
+++ b/test/CodeGenObjC/designated-initializers.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+// <rdar://problem/10465114>
+struct overwrite_string_struct {
+ char L[3];
+ int M;
+} overwrite_string[] = { { { @encode(void**) }, 1 }, [0].L[1] = 'x'};
+// CHECK: [3 x i8] c"^xv", i32 1
diff --git a/test/CodeGenObjC/encode-cstyle-method.m b/test/CodeGenObjC/encode-cstyle-method.m
index f3243a31487f..309089b9b602 100644
--- a/test/CodeGenObjC/encode-cstyle-method.m
+++ b/test/CodeGenObjC/encode-cstyle-method.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP64 %s
// rdar: // 7445205
@interface Foo
diff --git a/test/CodeGenObjC/encode-test-6.m b/test/CodeGenObjC/encode-test-6.m
index b7feb14434bc..b7b37997e1fa 100644
--- a/test/CodeGenObjC/encode-test-6.m
+++ b/test/CodeGenObjC/encode-test-6.m
@@ -35,3 +35,21 @@ typedef BABugExample BABugExampleRedefinition;
@end
// CHECK: internal global [24 x i8] c"^{BABugExample=@}16
+
+// rdar://14408244
+@class SCNCamera;
+typedef SCNCamera C3DCamera;
+typedef struct
+{
+ C3DCamera *presentationInstance;
+} C3DCameraStorage;
+
+@interface SCNCamera
+@end
+
+@implementation SCNCamera
+{
+ C3DCameraStorage _storage;
+}
+@end
+// CHECK: internal global [39 x i8] c"{?=\22presentationInstance\22^{SCNCamera}}\00"
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index e8d65413740d..d6e7b6dfccad 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -159,7 +159,7 @@ struct f
int tt;
};
-// CHECK: @g10 = constant [14 x i8] c"{f=i[0{?=}]i}\00"
+// CHECK: @g10 = constant [14 x i8] c"{f=i[4{?=}]i}\00"
const char g10[] = @encode(struct f);
// rdar://9622422
diff --git a/test/CodeGenObjC/exceptions-nonfragile.m b/test/CodeGenObjC/exceptions-nonfragile.m
index 1f3892699839..212a1eedd45f 100644
--- a/test/CodeGenObjC/exceptions-nonfragile.m
+++ b/test/CodeGenObjC/exceptions-nonfragile.m
@@ -26,6 +26,6 @@ void test2(void) {
test2_helper();
}
- // CHECK: define void @test2()
+ // CHECK-LABEL: define void @test2()
// CHECK-NOT: call void @test2_helper()
}
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 408b94d385fa..92f68292fff0 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -14,7 +14,7 @@ void f0() {
}
}
-// CHECK: define void @f1()
+// CHECK-LABEL: define void @f1()
void f1() {
extern void foo(void);
@@ -40,7 +40,7 @@ void f1() {
// Test that modifications to local variables are respected under
// optimization. rdar://problem/8160285
-// CHECK: define i32 @f2()
+// CHECK-LABEL: define i32 @f2()
int f2() {
extern void foo(void);
@@ -77,7 +77,7 @@ int f2() {
// Test that the cleanup destination is saved when entering a finally
// block. rdar://problem/8293901
-// CHECK: define void @f3()
+// CHECK-LABEL: define void @f3()
void f3() {
extern void f3_helper(int, int*);
@@ -130,7 +130,7 @@ void f3() {
void f4() {
extern void f4_help(int);
- // CHECK: define void @f4()
+ // CHECK-LABEL: define void @f4()
// CHECK: [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
// CHECK: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
// CHECK: call i32 @_setjmp
diff --git a/test/CodeGenObjC/extended-block-signature-encode.m b/test/CodeGenObjC/extended-block-signature-encode.m
index a380856da5f2..3db31fafc080 100644
--- a/test/CodeGenObjC/extended-block-signature-encode.m
+++ b/test/CodeGenObjC/extended-block-signature-encode.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fencode-extended-block-signature -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s -check-prefix=BRIEF
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-BRIEF
// rdar://12109031
@class NSString, NSArray;
diff --git a/test/CodeGenObjC/fp2ret.m b/test/CodeGenObjC/fp2ret.m
index 2e65332ec974..5f7c76d6cdd8 100644
--- a/test/CodeGenObjC/fp2ret.m
+++ b/test/CodeGenObjC/fp2ret.m
@@ -12,15 +12,15 @@
@end
-// CHECK-X86_32: define void @t0()
+// CHECK-X86_32-LABEL: define void @t0()
// CHECK-X86_32: call void bitcast {{.*}} @objc_msgSend_stret to
// CHECK-X86_32: }
//
-// CHECK-X86_64: define void @t0()
+// CHECK-X86_64-LABEL: define void @t0()
// CHECK-X86_64: call { x86_fp80, x86_fp80 } bitcast {{.*}} @objc_msgSend_fp2ret to
// CHECK-X86_64: }
//
-// CHECK-ARMV7: define void @t0()
+// CHECK-ARMV7-LABEL: define void @t0()
// CHECK-ARMV7: call i128 bitcast {{.*}} @objc_msgSend to
// CHECK-ARMV7: }
void t0() {
diff --git a/test/CodeGenObjC/fpret.m b/test/CodeGenObjC/fpret.m
index cabef108df48..7fe550177d4c 100644
--- a/test/CodeGenObjC/fpret.m
+++ b/test/CodeGenObjC/fpret.m
@@ -14,19 +14,19 @@
@end
-// CHECK-X86_32: define void @t0()
+// CHECK-X86_32-LABEL: define void @t0()
// CHECK-X86_32: call float bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_32: call double bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_32: call x86_fp80 bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_32: }
//
-// CHECK-X86_64: define void @t0()
+// CHECK-X86_64-LABEL: define void @t0()
// CHECK-X86_64: call float bitcast {{.*}} @objc_msgSend to
// CHECK-X86_64: call double bitcast {{.*}} @objc_msgSend to
// CHECK-X86_64: call x86_fp80 bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_64: }
//
-// CHECK-ARMV7: define void @t0()
+// CHECK-ARMV7-LABEL: define void @t0()
// CHECK-ARMV7: call float bitcast {{.*}} @objc_msgSend to
// CHECK-ARMV7: call double bitcast {{.*}} @objc_msgSend to
// CHECK-ARMV7: call double bitcast {{.*}} @objc_msgSend to
diff --git a/test/CodeGenObjC/gc.m b/test/CodeGenObjC/gc.m
index ce2611ecf8ae..729cf107a903 100644
--- a/test/CodeGenObjC/gc.m
+++ b/test/CodeGenObjC/gc.m
@@ -4,7 +4,7 @@ void test0(void) {
extern id test0_helper(void);
__attribute__((objc_precise_lifetime)) id x = test0_helper();
test0_helper();
- // CHECK: define void @test0()
+ // CHECK-LABEL: define void @test0()
// CHECK: [[T0:%.*]] = call i8* @test0_helper()
// CHECK-NEXT: store i8* [[T0]], i8** [[X:%.*]], align 8
// CHECK-NEXT: call i8* @test0_helper()
diff --git a/test/CodeGenObjC/id-isa-codegen.m b/test/CodeGenObjC/id-isa-codegen.m
index 8717ce2d0abb..fa0f0b097a00 100644
--- a/test/CodeGenObjC/id-isa-codegen.m
+++ b/test/CodeGenObjC/id-isa-codegen.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix LP32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP64 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-LP32 %s
typedef struct objc_class *Class;
diff --git a/test/CodeGenObjC/ivar-base-as-invariant-load.m b/test/CodeGenObjC/ivar-base-as-invariant-load.m
index 8b660cf483d9..19dc6587f553 100644
--- a/test/CodeGenObjC/ivar-base-as-invariant-load.m
+++ b/test/CodeGenObjC/ivar-base-as-invariant-load.m
@@ -23,7 +23,7 @@
@end
-// CHECK: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
-// CHECK: [[T2:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
-// CHECK: [[T3:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
+// CHECK: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !5
+// CHECK: [[T2:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !5
+// CHECK: [[T3:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !5
diff --git a/test/CodeGenObjC/ivar-invariant.m b/test/CodeGenObjC/ivar-invariant.m
index 7cafee70073f..ef17ffc12f78 100644
--- a/test/CodeGenObjC/ivar-invariant.m
+++ b/test/CodeGenObjC/ivar-invariant.m
@@ -40,7 +40,7 @@ void * variant_load_1(int i) {
return ptr;
}
-// CHECK: define i8* @variant_load_1(i32 %i)
+// CHECK-LABEL: define i8* @variant_load_1(i32 %i)
// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Derived.member"{{$}}
@interface Container : Derived @end
@@ -61,7 +61,7 @@ void * variant_load_1(int i) {
}
@end
-// CHECK: define internal i8* @block_block_invoke
+// CHECK-LABEL: define internal i8* @block_block_invoke
// CHECK: load i64* @"OBJC_IVAR_$_ForBlock.foo"
id (^block)(ForBlock*) = ^(ForBlock* a) {
return a->foo;
diff --git a/test/CodeGenObjC/ivar-layout-array0-struct.m b/test/CodeGenObjC/ivar-layout-array0-struct.m
index 267f947f42b6..47373035214d 100644
--- a/test/CodeGenObjC/ivar-layout-array0-struct.m
+++ b/test/CodeGenObjC/ivar-layout-array0-struct.m
@@ -1,6 +1,6 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// rdar://8800513
@interface NSObject {
diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m
index 46a7034a2249..17b519577f97 100644
--- a/test/CodeGenObjC/ivar-layout-no-optimize.m
+++ b/test/CodeGenObjC/ivar-layout-no-optimize.m
@@ -1,8 +1,8 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
@interface NSObject {
id isa;
diff --git a/test/CodeGenObjC/local-static-block.m b/test/CodeGenObjC/local-static-block.m
index deea8bac13ea..b5b4534b8e47 100644
--- a/test/CodeGenObjC/local-static-block.m
+++ b/test/CodeGenObjC/local-static-block.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o %t-64.ll
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.ll %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.ll %s
// rdar: // 8390455
@class NSArray;
diff --git a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
index bb3a20bb291c..6ea656443a8b 100644
--- a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
+++ b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
// RUN: FileCheck --input-file=%t-64.layout %s
-// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
// RUN: FileCheck -check-prefix=CHECK-i386 --input-file=%t-32.layout %s
// rdar://12184410
// rdar://12184410
diff --git a/test/CodeGenObjC/ns_consume_null_check.m b/test/CodeGenObjC/ns_consume_null_check.m
index 6a31a808f4c8..d4502ec04263 100644
--- a/test/CodeGenObjC/ns_consume_null_check.m
+++ b/test/CodeGenObjC/ns_consume_null_check.m
@@ -16,7 +16,7 @@ void test0(void) {
id obj = [NSObject new];
[x isEqual : obj];
}
-// CHECK: define void @test0()
+// CHECK-LABEL: define void @test0()
// CHECK: [[FIVE:%.*]] = call i8* @objc_retain
// CHECK-NEXT: [[SIX:%.*]] = bitcast
// CHECK-NEXT: [[SEVEN:%.*]] = icmp eq i8* [[SIX]], null
@@ -36,7 +36,7 @@ void test1(void) {
__weak id weakObj = obj;
_Complex float result = [x asComplexWithArg: obj];
}
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
// CHECK: [[OBJ:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[WEAKOBJ:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[RESULT:%.*]] = alloca { float, float }, align 4
diff --git a/test/CodeGenObjC/null-objc-empty-vtable.m b/test/CodeGenObjC/null-objc-empty-vtable.m
new file mode 100644
index 000000000000..fe69ce1f69c1
--- /dev/null
+++ b/test/CodeGenObjC/null-objc-empty-vtable.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-OSX %s
+// RUN: %clang_cc1 -triple thumbv7-apple-ios3.0.0 -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IOS %s
+// rdar://14802916
+
+@interface I
+@end
+
+@implementation I @end
+// CHECK-OSX: %struct._class_t* null, %struct._objc_cache* @_objc_empty_cache, i8* (i8*, i8*)** null
+// CHECK-IOS: %struct._class_t* null, %struct._objc_cache* @_objc_empty_cache, i8* (i8*, i8*)** null
diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m
index 6c2baac0504b..eb11a4e1b33a 100644
--- a/test/CodeGenObjC/objc-gc-aggr-assign.m
+++ b/test/CodeGenObjC/objc-gc-aggr-assign.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix C %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CP %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CHECK-C %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CHECK-CP %s
static int count;
diff --git a/test/CodeGenObjC/objc-read-weak-byref.m b/test/CodeGenObjC/objc-read-weak-byref.m
index 94eca2899d9b..35b4de1cec2e 100644
--- a/test/CodeGenObjC/objc-read-weak-byref.m
+++ b/test/CodeGenObjC/objc-read-weak-byref.m
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
@interface NSObject
- copy;
diff --git a/test/CodeGenObjC/objc2-legacy-dispatch.m b/test/CodeGenObjC/objc2-legacy-dispatch.m
index a6b20000d802..aa944f89519f 100644
--- a/test/CodeGenObjC/objc2-legacy-dispatch.m
+++ b/test/CodeGenObjC/objc2-legacy-dispatch.m
@@ -1,15 +1,15 @@
// RUN: %clang_cc1 -fobjc-dispatch-method=mixed -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
//
-// CHECK_NEW_DISPATCH: define void @f0
+// CHECK_NEW_DISPATCH-LABEL: define void @f0
// CHECK_NEW_DISPATCH: bitcast {{.*}}objc_msgSend_fixup_alloc
-// CHECK_NEW_DISPATCH: define void @f1
+// CHECK_NEW_DISPATCH-LABEL: define void @f1
// CHECK_NEW_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
//
// RUN: %clang_cc1 -fobjc-dispatch-method=legacy -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
//
-// CHECK_OLD_DISPATCH: define void @f0
+// CHECK_OLD_DISPATCH-LABEL: define void @f0
// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
-// CHECK_OLD_DISPATCH: define void @f1
+// CHECK_OLD_DISPATCH-LABEL: define void @f1
// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
@interface A
diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m
index ece6b9d582b7..16593f128d78 100644
--- a/test/CodeGenObjC/objc2-no-write-barrier.m
+++ b/test/CodeGenObjC/objc2-no-write-barrier.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep 'objc_assign' %t | count 0
+// RUN: not grep 'objc_assign' %t
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep 'objc_assign' %t | count 0
+// RUN: not grep 'objc_assign' %t
typedef struct {
int ival;
diff --git a/test/CodeGenObjC/objc2-weak-block-call.m b/test/CodeGenObjC/objc2-weak-block-call.m
index 25434947d104..7c6881751dbe 100644
--- a/test/CodeGenObjC/objc2-weak-block-call.m
+++ b/test/CodeGenObjC/objc2-weak-block-call.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64 %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64 %s
@interface MyView
- (void)MyView_sharedInit;
diff --git a/test/CodeGenObjC/objc2-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m
index 65a71a5a1d35..44af818a320e 100644
--- a/test/CodeGenObjC/objc2-write-barrier-5.m
+++ b/test/CodeGenObjC/objc2-write-barrier-5.m
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep objc_assign_ivar %t | count 0
+// RUN: not grep objc_assign_ivar %t
// RUN: grep objc_assign_strongCast %t | count 8
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep objc_assign_ivar %t | count 0
+// RUN: not grep objc_assign_ivar %t
// RUN: grep objc_assign_strongCast %t | count 8
@interface TestUnarchiver
diff --git a/test/CodeGenObjC/objfw.m b/test/CodeGenObjC/objfw.m
index 98e3fb02652d..8e72867fcde6 100644
--- a/test/CodeGenObjC/objfw.m
+++ b/test/CodeGenObjC/objfw.m
@@ -8,7 +8,7 @@
void test0(void) {
[Test0 test];
}
-// CHECK: define void @test0()
+// CHECK-LABEL: define void @test0()
// CHECK: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (i8*, i8*)*
// CHECK-NEXT: call void [[T1]](i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index 6a438268c78f..e156270f66fe 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -54,7 +54,7 @@ int printf(const char *, ...);
@end
// Test that compound operations only compute the base once.
-// CHECK: define void @test2
+// CHECK-LABEL: define void @test2
A *test2_helper(void);
void test2() {
// CHECK: [[BASE:%.*]] = call [[A:%.*]]* @test2_helper()
@@ -94,7 +94,7 @@ void test3(test3_object *p) {
@interface Test4 {}
@property float f;
@end
-// CHECK: define void @test4
+// CHECK-LABEL: define void @test4
void test4(Test4 *t) {
extern int test4_printf(const char *, ...);
// CHECK: [[TMP:%.*]] = call float {{.*}} @objc_msgSend
diff --git a/test/CodeGenObjC/protocol-in-extended-class.m b/test/CodeGenObjC/protocol-in-extended-class.m
index b919d5fd234a..a5fb80eca4b9 100644
--- a/test/CodeGenObjC/protocol-in-extended-class.m
+++ b/test/CodeGenObjC/protocol-in-extended-class.m
@@ -1,8 +1,8 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s
@protocol MyProtocol
@end
diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m
index 642f886a088b..fba7454b9549 100644
--- a/test/CodeGenObjC/protocols-lazy.m
+++ b/test/CodeGenObjC/protocols-lazy.m
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-apple-darwin8 -fobjc-runtime=macosx-fragile-10.5 -o %t %s
// No object generated
-// RUN: grep OBJC_PROTOCOL_P0 %t | count 0
+// RUN: not grep OBJC_PROTOCOL_P0 %t
@protocol P0;
// No object generated
-// RUN: grep OBJC_PROTOCOL_P1 %t | count 0
+// RUN: not grep OBJC_PROTOCOL_P1 %t
@protocol P1 -im1; @end
// Definition triggered by protocol reference.
@@ -16,7 +16,7 @@ void f0() { id x = @protocol(P2); }
// Forward definition triggered by protocol reference.
// RUN: grep OBJC_PROTOCOL_P3 %t | count 3
-// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P3 %t | count 0
+// RUN: not grep OBJC_PROTOCOL_INSTANCE_METHODS_P3 %t
@protocol P3;
void f1() { id x = @protocol(P3); }
diff --git a/test/CodeGenObjC/related-result-type.m b/test/CodeGenObjC/related-result-type.m
index ef38661f94c0..cd7847421812 100644
--- a/test/CodeGenObjC/related-result-type.m
+++ b/test/CodeGenObjC/related-result-type.m
@@ -9,7 +9,7 @@
@interface NSString : NSObject
@end
-// CHECK: define void @test1()
+// CHECK-LABEL: define void @test1()
void test1() {
// CHECK: {{call.*@objc_msgSend}}
// CHECK: {{call.*@objc_msgSend}}
@@ -18,7 +18,7 @@ void test1() {
NSString *str1 = [[[NSString alloc] init] retain];
}
-// CHECK: define void @test2()
+// CHECK-LABEL: define void @test2()
void test2() {
// CHECK: {{call.*@objc_msgSend}}
// CHECK: {{call.*@objc_msgSend}}
diff --git a/test/CodeGenObjC/reorder-synthesized-ivars.m b/test/CodeGenObjC/reorder-synthesized-ivars.m
index 747265d15512..0f8cf6a3ea87 100644
--- a/test/CodeGenObjC/reorder-synthesized-ivars.m
+++ b/test/CodeGenObjC/reorder-synthesized-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -x objective-c %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -x objective-c %s -o - | FileCheck %s
// rdar://13192366
typedef signed char BOOL;
@interface NSObject
diff --git a/test/CodeGenObjC/stret_lookup.m b/test/CodeGenObjC/stret_lookup.m
new file mode 100644
index 000000000000..6682fac7aefe
--- /dev/null
+++ b/test/CodeGenObjC/stret_lookup.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -DSTRET -triple x86_64-pc-linux-gnu -fobjc-runtime=objfw -emit-llvm -o - %s | FileCheck -check-prefix=HASSTRET %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fobjc-runtime=gcc -emit-llvm -o - %s | FileCheck -check-prefix=NOSTRET %s
+
+// Test stret lookup
+
+struct test {
+ char test[1024];
+};
+@interface Test0
++ (struct test)test;
+@end
+void test0(void) {
+ struct test t;
+#if (defined(STRET) && defined(__OBJFW_RUNTIME_ABI__)) || \
+ (!defined(STRET) && !defined(__OBJFW_RUNTIME_ABI__))
+ t = [Test0 test];
+#endif
+ (void)t;
+}
+
+// HASSTRET-LABEL: define void @test0()
+// HASSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup_stret(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
+// HASSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (%struct.test*, i8*, i8*)*
+// HASSTRET-NEXT: call void [[T1]](%struct.test* sret {{.*}}, i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
+
+// NOSTRET-LABEL: define void @test0()
+// NOSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup(i8*
+// NOSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (%struct.test*, i8*, i8*)*
+// NOSTRET-NEXT: call void [[T1]](%struct.test* sret {{.*}}, i8* {{.*}}, i8* bitcast ([2 x { i8*, i8* }]*
diff --git a/test/CodeGenObjC/synchronized.m b/test/CodeGenObjC/synchronized.m
index e927882b3f73..015e55b8f8af 100644
--- a/test/CodeGenObjC/synchronized.m
+++ b/test/CodeGenObjC/synchronized.m
@@ -20,7 +20,7 @@
@end
-// CHECK: define void @foo(
+// CHECK-LABEL: define void @foo(
void foo(id a) {
// CHECK: [[A:%.*]] = alloca i8*
// CHECK: [[SYNC:%.*]] = alloca i8*
@@ -47,7 +47,7 @@ void foo(id a) {
}
-// CHECK: define i32 @f0(
+// CHECK-LABEL: define i32 @f0(
int f0(id a) {
// TODO: we can optimize the ret to a constant if we can figure out
// either that x isn't stored to within the synchronized block or
@@ -64,7 +64,7 @@ int f0(id a) {
return x;
}
-// CHECK: define void @f1(
+// CHECK-LABEL: define void @f1(
void f1(id a) {
// Check that the return doesn't go through the cleanup.
extern void opaque(void);
diff --git a/test/CodeGenObjC/tentative-cfconstantstring.m b/test/CodeGenObjC/tentative-cfconstantstring.m
index b7e1c4601fed..714c1a402336 100644
--- a/test/CodeGenObjC/tentative-cfconstantstring.m
+++ b/test/CodeGenObjC/tentative-cfconstantstring.m
@@ -34,7 +34,7 @@ static inline void _inlineFunction() {
// CHECK: @__CFConstantStringClassReference = common global [24 x i32] zeroinitializer, align 16
// CHECK: @_unnamed_cfstring_{{.*}} = private constant %struct.NSConstantString { i32* getelementptr inbounds ([24 x i32]* @__CFConstantStringClassReference, i32 0, i32 0)
-// CHECK: define internal void @_inlineFunction()
+// CHECK-LABEL: define internal void @_inlineFunction()
// CHECK: [[ZERO:%.*]] = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_
// CHECK-NEXT: [[ONE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
// CHECK-NEXT: [[TWO:%.*]] = bitcast %struct._class_t* [[ZERO]] to i8*
diff --git a/test/CodeGenObjC/terminate.m b/test/CodeGenObjC/terminate.m
index 8728ec4598bf..4992b998b395 100644
--- a/test/CodeGenObjC/terminate.m
+++ b/test/CodeGenObjC/terminate.m
@@ -9,7 +9,7 @@ void test0(void) {
void *ptr __attribute__((cleanup(destroy)));
test0_helper();
- // CHECK-WITH: define void @test0()
+ // CHECK-WITH-LABEL: define void @test0()
// CHECK-WITH: [[PTR:%.*]] = alloca i8*,
// CHECK-WITH: call void @destroy(i8** [[PTR]])
// CHECK-WITH-NEXT: ret void
@@ -18,7 +18,7 @@ void test0(void) {
// CHECK-WITH-NEXT: catch i8* null
// CHECK-WITH-NEXT: call void @objc_terminate()
- // CHECK-WITHOUT: define void @test0()
+ // CHECK-WITHOUT-LABEL: define void @test0()
// CHECK-WITHOUT: [[PTR:%.*]] = alloca i8*,
// CHECK-WITHOUT: call void @destroy(i8** [[PTR]])
// CHECK-WITHOUT-NEXT: ret void
diff --git a/test/CodeGenObjC/x86_64-struct-return-gc.m b/test/CodeGenObjC/x86_64-struct-return-gc.m
index dab5b15e284e..9cb4b134e67d 100644
--- a/test/CodeGenObjC/x86_64-struct-return-gc.m
+++ b/test/CodeGenObjC/x86_64-struct-return-gc.m
@@ -5,7 +5,7 @@ struct Coerce {
struct Coerce coerce_func(void);
-// CHECK: define void @Coerce_test()
+// CHECK-LABEL: define void @Coerce_test()
void Coerce_test(void) {
struct Coerce c;
@@ -21,7 +21,7 @@ struct Indirect {
struct Indirect indirect_func(void);
-// CHECK: define void @Indirect_test()
+// CHECK-LABEL: define void @Indirect_test()
void Indirect_test(void) {
struct Indirect i;
diff --git a/test/CodeGenObjCXX/arc-attrs.mm b/test/CodeGenObjCXX/arc-attrs.mm
index 57ccb6cdeae0..0f0610f1721d 100644
--- a/test/CodeGenObjCXX/arc-attrs.mm
+++ b/test/CodeGenObjCXX/arc-attrs.mm
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -O0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -o - %s | FileCheck %s
id makeObject1() __attribute__((ns_returns_retained));
id makeObject2() __attribute__((ns_returns_retained));
void releaseObject(__attribute__((ns_consumed)) id);
-// CHECK: define void @_Z10sanityTestv
+// CHECK-LABEL: define void @_Z10sanityTestv
void sanityTest() {
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z11makeObject1v()
@@ -28,7 +28,7 @@ T makeObjectT2() __attribute__((ns_returns_retained));
template <typename T>
void releaseObjectT(__attribute__((ns_consumed)) T);
-// CHECK: define void @_Z12templateTestv
+// CHECK-LABEL: define void @_Z12templateTestv
void templateTest() {
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectET_v()
diff --git a/test/CodeGenObjCXX/arc-blocks.mm b/test/CodeGenObjCXX/arc-blocks.mm
index 810c0e09cc9d..ebb9d21c61f6 100644
--- a/test/CodeGenObjCXX/arc-blocks.mm
+++ b/test/CodeGenObjCXX/arc-blocks.mm
@@ -16,7 +16,7 @@ namespace test0 {
void foo() {
__block A v;
}
- // CHECK: define void @_ZN5test03fooEv()
+ // CHECK-LABEL: define void @_ZN5test03fooEv()
// CHECK: [[V:%.*]] = alloca [[BYREF_A:%.*]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 4
// CHECK-NEXT: store i8* bitcast (void (i8*, i8*)* [[COPY_HELPER:@.*]] to i8*), i8** [[T0]]
diff --git a/test/CodeGenObjCXX/arc-exceptions.mm b/test/CodeGenObjCXX/arc-exceptions.mm
index b5ed257e9485..0bb11d52ff60 100644
--- a/test/CodeGenObjCXX/arc-exceptions.mm
+++ b/test/CodeGenObjCXX/arc-exceptions.mm
@@ -11,7 +11,7 @@ void test0(void) {
} @catch (Ety *e) {
}
}
-// CHECK: define void @_Z5test0v()
+// CHECK-LABEL: define void @_Z5test0v()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @_Z12test0_helperv()
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
@@ -31,7 +31,7 @@ void test1(void) {
} @catch (__weak Ety *e) {
}
}
-// CHECK: define void @_Z5test1v()
+// CHECK-LABEL: define void @_Z5test1v()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @_Z12test1_helperv()
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
@@ -50,7 +50,7 @@ void test2(void) {
} catch (Ety *e) {
}
}
-// CHECK: define void @_Z5test2v()
+// CHECK-LABEL: define void @_Z5test2v()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @_Z12test2_helperv()
// CHECK: [[T0:%.*]] = call i8* @__cxa_begin_catch(
@@ -70,7 +70,7 @@ void test3(void) {
} catch (Ety * __weak e) {
}
}
-// CHECK: define void @_Z5test3v()
+// CHECK-LABEL: define void @_Z5test3v()
// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
// CHECK-NEXT: invoke void @_Z12test3_helperv()
// CHECK: [[T0:%.*]] = call i8* @__cxa_begin_catch(
@@ -93,7 +93,7 @@ namespace test4 {
A::A() {
throw 0;
}
- // CHECK: define void @_ZN5test41AC2Ev(
+ // CHECK-LABEL: define void @_ZN5test41AC2Ev(
// CHECK: [[THIS:%.*]] = load [[A:%.*]]** {{%.*}}
// Construct single.
// CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 0
diff --git a/test/CodeGenObjCXX/arc-globals.mm b/test/CodeGenObjCXX/arc-globals.mm
index 958d1d872c28..84ea180bca7d 100644
--- a/test/CodeGenObjCXX/arc-globals.mm
+++ b/test/CodeGenObjCXX/arc-globals.mm
@@ -5,21 +5,21 @@
// autorelease pool.
id getObject();
-// CHECK: define internal void @__cxx_global_var_init
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i8* @_Z9getObjectv
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
// CHECK-NEXT: {{store i8*.*@global_obj}}
// CHECK-NEXT: ret void
id global_obj = getObject();
-// CHECK: define internal void @__cxx_global_var_init
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i8* @_Z9getObjectv
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
// CHECK-NEXT: {{store i8*.*@global_obj2}}
// CHECK-NEXT: ret void
id global_obj2 = getObject();
-// CHECK: define internal void @_GLOBAL__I_a
+// CHECK-LABEL: define internal void @_GLOBAL__I_a
// CHECK: call i8* @objc_autoreleasePoolPush()
// CHECK-NEXT: call void @__cxx_global_var_init
// CHECK-NEXT: call void @__cxx_global_var_init1
diff --git a/test/CodeGenObjCXX/arc-mangle.mm b/test/CodeGenObjCXX/arc-mangle.mm
index c2b5817c73b3..10c4f68451f8 100644
--- a/test/CodeGenObjCXX/arc-mangle.mm
+++ b/test/CodeGenObjCXX/arc-mangle.mm
@@ -1,25 +1,25 @@
// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
-// CHECK: define void @_Z1fPU8__strongP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPU8__strongP11objc_object(i8**)
void f(__strong id *) {}
-// CHECK: define void @_Z1fPU6__weakP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPU6__weakP11objc_object(i8**)
void f(__weak id *) {}
-// CHECK: define void @_Z1fPU15__autoreleasingP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPU15__autoreleasingP11objc_object(i8**)
void f(__autoreleasing id *) {}
-// CHECK: define void @_Z1fPP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPP11objc_object(i8**)
void f(__unsafe_unretained id *) {}
-// CHECK: define void @_Z1fPKU8__strongP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPKU8__strongP11objc_object(i8**)
void f(const __strong id *) {}
-// CHECK: define void @_Z1fPKU6__weakP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPKU6__weakP11objc_object(i8**)
void f(const __weak id *) {}
-// CHECK: define void @_Z1fPKU15__autoreleasingP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPKU15__autoreleasingP11objc_object(i8**)
void f(const __autoreleasing id *) {}
-// CHECK: define void @_Z1fPKP11objc_object(i8**)
+// CHECK-LABEL: define void @_Z1fPKP11objc_object(i8**)
void f(const __unsafe_unretained id *) {}
template<unsigned N> struct unsigned_c { };
-// CHECK: define weak_odr void @_Z1gIKvEvP10unsigned_cIXplszv1U8__bridgecvPT_v1U8__bridgecvP11objc_objectcvS3_Li0ELi1EEE
+// 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> *);
diff --git a/test/CodeGenObjCXX/arc-move.mm b/test/CodeGenObjCXX/arc-move.mm
index cf3051dd1fe6..0a8286ded438 100644
--- a/test/CodeGenObjCXX/arc-move.mm
+++ b/test/CodeGenObjCXX/arc-move.mm
@@ -31,7 +31,7 @@ typename remove_reference<T>::type&& move(T &&x) {
return static_cast<typename remove_reference<T>::type&&>(x);
}
-// CHECK: define void @_Z12library_moveRU8__strongP11objc_objectS2_
+// CHECK-LABEL: define void @_Z12library_moveRU8__strongP11objc_objectS2_
void library_move(__strong id &x, __strong id &y) {
// CHECK: call i8** @_Z4moveIRU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_
// CHECK: load i8**
@@ -44,7 +44,7 @@ void library_move(__strong id &x, __strong id &y) {
x = move(y);
}
-// CHECK: define void @_Z12library_moveRU8__strongP11objc_object
+// CHECK-LABEL: define void @_Z12library_moveRU8__strongP11objc_object
void library_move(__strong id &y) {
// CHECK: [[Y:%[a-zA-Z0-9]+]] = call i8** @_Z4moveIRU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_
// Load the object
@@ -62,7 +62,7 @@ void library_move(__strong id &y) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z10const_moveRKU8__strongP11objc_object(
+// CHECK-LABEL: define void @_Z10const_moveRKU8__strongP11objc_object(
void const_move(const __strong id &x) {
// CHECK: [[Y:%.*]] = alloca i8*,
// CHECK: [[X:%.*]] = call i8** @_Z4moveIRKU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_(
diff --git a/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
index c061e5dbdff8..9d42b03a7c4c 100644
--- a/test/CodeGenObjCXX/arc-new-delete.mm
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -3,7 +3,7 @@
typedef __strong id strong_id;
typedef __weak id weak_id;
-// CHECK: define void @_Z8test_newP11objc_object
+// CHECK-LABEL: define void @_Z8test_newP11objc_object
void test_new(id invalue) {
// CHECK: [[INVALUEADDR:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[INVALUEADDR]]
@@ -40,7 +40,7 @@ void test_new(id invalue) {
// CHECK: ret void
}
-// CHECK: define void @_Z14test_array_new
+// CHECK-LABEL: define void @_Z14test_array_new
void test_array_new() {
// CHECK: call noalias i8* @_Znam
// CHECK: store i64 17, i64*
@@ -54,7 +54,7 @@ void test_array_new() {
// CHECK: ret void
}
-// CHECK: define void @_Z11test_deletePU8__strongP11objc_objectPU6__weakS0_
+// CHECK-LABEL: define void @_Z11test_deletePU8__strongP11objc_objectPU6__weakS0_
void test_delete(__strong id *sptr, __weak id *wptr) {
// CHECK: br i1
// CHECK: load i8**
@@ -69,7 +69,7 @@ void test_delete(__strong id *sptr, __weak id *wptr) {
// CHECK: ret void
}
-// CHECK: define void @_Z17test_array_deletePU8__strongP11objc_objectPU6__weakS0_
+// CHECK-LABEL: define void @_Z17test_array_deletePU8__strongP11objc_objectPU6__weakS0_
void test_array_delete(__strong id *sptr, __weak id *wptr) {
// CHECK: icmp eq i8** [[BEGIN:%.*]], null
// CHECK: [[LEN:%.*]] = load i64* {{%.*}}
diff --git a/test/CodeGenObjCXX/arc-pseudo-destructors.mm b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
index 2f8d9e1878bb..0a69487b9e7c 100644
--- a/test/CodeGenObjCXX/arc-pseudo-destructors.mm
+++ b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
-// CHECK: define void @_Z28test_objc_object_pseudo_dtorPU8__strongP11objc_objectPU6__weakS0_
+// CHECK-LABEL: define void @_Z28test_objc_object_pseudo_dtorPU8__strongP11objc_objectPU6__weakS0_
void test_objc_object_pseudo_dtor(__strong id *ptr, __weak id *wptr) {
// CHECK: load i8***
// CHECK-NEXT: load i8**
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
index 121077435da3..10e7f64198db 100644
--- a/test/CodeGenObjCXX/arc-references.mm
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -7,7 +7,7 @@ id getObject();
void callee();
// Lifetime extension for binding a reference to an rvalue
-// CHECK: define void @_Z5test0v()
+// CHECK-LABEL: define void @_Z5test0v()
void test0() {
// CHECK: call i8* @_Z9getObjectv
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
@@ -25,7 +25,7 @@ void test0() {
}
// No lifetime extension when we're binding a reference to an lvalue.
-// CHECK: define void @_Z5test1RU8__strongP11objc_objectRU6__weakS0_
+// CHECK-LABEL: define void @_Z5test1RU8__strongP11objc_objectRU6__weakS0_
void test1(__strong id &x, __weak id &y) {
// CHECK-NOT: release
const __strong id &ref1 = x;
@@ -47,7 +47,7 @@ void test3() {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z5test4RU8__strongP11objc_object
+// CHECK-LABEL: define void @_Z5test4RU8__strongP11objc_object
void test4(__strong id &x) {
// CHECK: call i8* @objc_retain
__strong A* const &ar = x;
@@ -59,7 +59,7 @@ void test4(__strong id &x) {
void sink(__strong A* &&);
-// CHECK: define void @_Z5test5RU8__strongP11objc_object
+// CHECK-LABEL: define void @_Z5test5RU8__strongP11objc_object
void test5(__strong id &x) {
// CHECK: [[REFTMP:%.*]] = alloca {{%.*}}*, align 8
// CHECK: [[OBJ_ID:%.*]] = call i8* @objc_retain(
@@ -75,7 +75,7 @@ void test5(__strong id &x) {
// CHECK-NEXT: ret void
}
-// CHECK: define internal void @__cxx_global_var_init(
+// CHECK-LABEL: define internal void @__cxx_global_var_init(
// CHECK: call i8* @_Z9getObjectv
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
const __strong id &global_ref = getObject();
diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm
index 0b34538d13ef..49077ffec494 100644
--- a/test/CodeGenObjCXX/arc-special-member-functions.mm
+++ b/test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -12,14 +12,14 @@ struct ObjCBlockMember {
int (^bp)(int);
};
-// CHECK: define void @_Z42test_ObjCMember_default_construct_destructv(
+// CHECK-LABEL: define void @_Z42test_ObjCMember_default_construct_destructv(
void test_ObjCMember_default_construct_destruct() {
// CHECK: call void @_ZN10ObjCMemberC1Ev
// CHECK: call void @_ZN10ObjCMemberD1Ev
ObjCMember m1;
}
-// CHECK: define void @_Z39test_ObjCMember_copy_construct_destruct10ObjCMember
+// CHECK-LABEL: define void @_Z39test_ObjCMember_copy_construct_destruct10ObjCMember
void test_ObjCMember_copy_construct_destruct(ObjCMember m1) {
// CHECK: call void @_ZN10ObjCMemberC1ERKS_
// CHECK: call void @_ZN10ObjCMemberD1Ev
@@ -27,7 +27,7 @@ void test_ObjCMember_copy_construct_destruct(ObjCMember m1) {
// CHECK: ret void
}
-// CHECK: define void @_Z27test_ObjCMember_copy_assign10ObjCMemberS_
+// CHECK-LABEL: define void @_Z27test_ObjCMember_copy_assign10ObjCMemberS_
void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) {
// CHECK: {{call.*_ZN10ObjCMemberaSERKS_}}
m1 = m2;
@@ -39,7 +39,7 @@ void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) {
// CHECK: call void @objc_storeStrong
// CHECK: ret
-// CHECK: define void @_Z47test_ObjCArrayMember_default_construct_destructv
+// CHECK-LABEL: define void @_Z47test_ObjCArrayMember_default_construct_destructv
void test_ObjCArrayMember_default_construct_destruct() {
// CHECK: call void @_ZN15ObjCArrayMemberC1Ev
ObjCArrayMember m1;
@@ -47,7 +47,7 @@ void test_ObjCArrayMember_default_construct_destruct() {
// CHECK: ret void
}
-// CHECK: define void @_Z44test_ObjCArrayMember_copy_construct_destruct15ObjCArrayMember
+// CHECK-LABEL: define void @_Z44test_ObjCArrayMember_copy_construct_destruct15ObjCArrayMember
void test_ObjCArrayMember_copy_construct_destruct(ObjCArrayMember m1) {
// CHECK: call void @_ZN15ObjCArrayMemberC1ERKS_
ObjCArrayMember m2 = m1;
@@ -67,7 +67,7 @@ void test_ObjCArrayMember_copy_assign(ObjCArrayMember m1, ObjCArrayMember m2) {
// CHECK-NEXT: br label
// CHECK: ret
-// CHECK: define void @_Z47test_ObjCBlockMember_default_construct_destructv
+// CHECK-LABEL: define void @_Z47test_ObjCBlockMember_default_construct_destructv
void test_ObjCBlockMember_default_construct_destruct() {
// CHECK: call void @_ZN15ObjCBlockMemberC1Ev
ObjCBlockMember m;
@@ -75,7 +75,7 @@ void test_ObjCBlockMember_default_construct_destruct() {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z44test_ObjCBlockMember_copy_construct_destruct15ObjCBlockMember
+// CHECK-LABEL: define void @_Z44test_ObjCBlockMember_copy_construct_destruct15ObjCBlockMember
void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) {
// CHECK: call void @_ZN15ObjCBlockMemberC1ERKS_
ObjCBlockMember m2 = m1;
@@ -83,7 +83,7 @@ void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z32test_ObjCBlockMember_copy_assign15ObjCBlockMemberS_
+// CHECK-LABEL: define void @_Z32test_ObjCBlockMember_copy_assign15ObjCBlockMemberS_
void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK: {{call.*_ZN15ObjCBlockMemberaSERKS_}}
m1 = m2;
@@ -105,22 +105,22 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK-NEXT: ret
// Implicitly-generated copy constructor for ObjCBlockMember
-// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2ERKS_
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCBlockMemberC2ERKS_
// CHECK: call i8* @objc_retainBlock
// CHECK: ret
// Implicitly-generated destructor for ObjCBlockMember
-// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev
// CHECK: call void @objc_storeStrong(i8*
// CHECK: ret
// Implicitly-generated default constructor for ObjCBlockMember
-// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCBlockMemberC2Ev
// CHECK: store {{.*}} null,
// CHECK-NEXT: ret void
// Implicitly-generated copy constructor for ObjCArrayMember
-// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2ERKS_
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCArrayMemberC2ERKS_
// CHECK: br i1
// CHECK: call i8* @objc_retain
// CHECK-NEXT: store i8*
@@ -128,7 +128,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK: ret
// Implicitly-generated destructor for ObjCArrayMember
-// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [2 x [3 x i8*]]*
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 6
// CHECK-NEXT: br label
@@ -140,24 +140,24 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK: ret void
// Implicitly-generated default constructor for ObjCArrayMember
-// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN15ObjCArrayMemberC2Ev
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK: ret
// Implicitly-generated copy constructor for ObjCMember
-// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2ERKS_
+// CHECK-LABEL: define linkonce_odr void @_ZN10ObjCMemberC2ERKS_
// CHECK-NOT: objc_release
// CHECK: call i8* @objc_retain
// CHECK-NEXT: store i8*
// CHECK-NEXT: ret void
// Implicitly-generated destructor for ObjCMember
-// CHECK: define linkonce_odr void @_ZN10ObjCMemberD2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN10ObjCMemberD2Ev
// CHECK: call void @objc_storeStrong
// CHECK: ret void
// Implicitly-generated default constructor for ObjCMember
-// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZN10ObjCMemberC2Ev
// CHECK-NOT: objc_release
// CHECK: store i8* null
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index e3e86a0b0d53..e31b0943b75e 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -55,7 +55,7 @@ void test34(int cond) {
test34_sink(cond ? &strong : 0);
test34_sink(cond ? &weak : 0);
- // CHECK: define void @_Z6test34i(
+ // CHECK-LABEL: define void @_Z6test34i(
// CHECK: [[COND:%.*]] = alloca i32
// CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
// CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
@@ -118,7 +118,7 @@ struct Test35_Helper {
id makeObject4();
};
-// CHECK: define void @_Z6test3513Test35_HelperPS_
+// CHECK-LABEL: define void @_Z6test3513Test35_HelperPS_
void test35(Test35_Helper x0, Test35_Helper *x0p) {
// CHECK: call i8* @_ZN13Test35_Helper11makeObject1Ev
// CHECK-NOT: call i8* @objc_retain
@@ -146,7 +146,7 @@ void test35(Test35_Helper x0, Test35_Helper *x0p) {
// CHECK-NEXT: ret void
}
-// CHECK: define void @_Z7test35b13Test35_HelperPS_
+// CHECK-LABEL: define void @_Z7test35b13Test35_HelperPS_
void test35b(Test35_Helper x0, Test35_Helper *x0p) {
// CHECK: call i8* @_ZN13Test35_Helper11makeObject3Ev
// CHECK: call i8* @objc_retain
@@ -174,7 +174,7 @@ void test35b(Test35_Helper x0, Test35_Helper *x0p) {
}
// rdar://problem/9603128
-// CHECK: define i8* @_Z6test36P11objc_object(
+// CHECK-LABEL: define i8* @_Z6test36P11objc_object(
id test36(id z) {
// CHECK: objc_retain
// CHECK: objc_retain
@@ -196,7 +196,7 @@ template <class T> void test37(T *a) {
}
extern template void test37<Test37>(Test37 *a);
template void test37<Test37>(Test37 *a);
-// CHECK: define weak_odr void @_Z6test37I6Test37EvPT_(
+// CHECK-LABEL: define weak_odr void @_Z6test37I6Test37EvPT_(
// CHECK: [[T0:%.*]] = call [[NSARRAY]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[NSARRAY]]* (i8*, i8*)*)(
// CHECK-NEXT: [[T1:%.*]] = bitcast [[NSARRAY]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
@@ -224,7 +224,7 @@ void send_release() {
[Test37 array];
}
-// CHECK: define weak_odr void @_Z12send_releaseIiEvv(
+// CHECK-LABEL: define weak_odr void @_Z12send_releaseIiEvv(
// CHECK: call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: bitcast
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
@@ -240,7 +240,7 @@ Test37 *instantiate_init() {
return result;
}
-// CHECK: define weak_odr %2* @_Z16instantiate_initIiEP6Test37v
+// CHECK-LABEL: define weak_odr %2* @_Z16instantiate_initIiEP6Test37v
// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: call i8* @objc_retain
@@ -257,7 +257,7 @@ template <class T> class Test38 {
^{ (void) x; }, ({ x; });
}
};
-// CHECK: define weak_odr void @_ZN6Test38IiE4testEi(
+// CHECK-LABEL: define weak_odr void @_ZN6Test38IiE4testEi(
template class Test38<int>;
// rdar://problem/11964832
@@ -272,7 +272,7 @@ class Test39 : Test39_base1, Test39_base2 { // base2 is at non-zero offset
};
id Test39::bar() { return 0; }
// Note lack of autorelease.
-// CHECK: define i8* @_ZThn8_N6Test393barEv(
+// CHECK-LABEL: define i8* @_ZThn8_N6Test393barEv(
// CHECK: call i8* @_ZN6Test393barEv(
// CHECK-NEXT: ret i8*
@@ -287,7 +287,7 @@ template <class T> void test40_helper() {
[Test40 foo: &x];
};
template void test40_helper<int>();
-// CHECK: define weak_odr void @_Z13test40_helperIiEvv()
+// CHECK-LABEL: define weak_odr void @_Z13test40_helperIiEvv()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[X]]
diff --git a/test/CodeGenObjCXX/block-var-layout.mm b/test/CodeGenObjCXX/block-var-layout.mm
index 08dbc02affbd..793d4b99aad6 100644
--- a/test/CodeGenObjCXX/block-var-layout.mm
+++ b/test/CodeGenObjCXX/block-var-layout.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
// RUN: FileCheck --input-file=%t-64.layout %s
// rdar://12184410
// rdar://12752901
diff --git a/test/CodeGenObjCXX/catch-id-type.mm b/test/CodeGenObjCXX/catch-id-type.mm
index 2d6cccc0f129..0a2b940ff16e 100644
--- a/test/CodeGenObjCXX/catch-id-type.mm
+++ b/test/CodeGenObjCXX/catch-id-type.mm
@@ -31,7 +31,7 @@ id FUNC() {
catch( id error )
{
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- // CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP4INTF to i8*)
+ // CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPU11objcproto1P4INTF to i8*)
// CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP11objc_object to i8*)
// CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP10objc_class to i8*)
error = error;
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index 1b6a241fcffa..075d7909d596 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -201,3 +201,26 @@ struct Y : Empty {
// CHECK: @g8 = constant [14 x i8] c"{Y={X=[10i]}}\00"
extern const char g8[] = @encode(Y);
+
+
+class dynamic_class {
+public:
+ virtual ~dynamic_class();
+};
+@interface has_dynamic_class_ivar
+@end
+@implementation has_dynamic_class_ivar {
+ dynamic_class dynamic_class_ivar;
+}
+@end
+// CHECK: internal global [41 x i8] c"{dynamic_class=\22_vptr$dynamic_class\22^^?}\00"
+
+namespace PR17142 {
+ struct A { virtual ~A(); };
+ struct B : virtual A { int y; };
+ struct C { virtual ~C(); int z; };
+ struct D : C, B { int a; };
+ struct E : D {};
+ // CHECK: @_ZN7PR171421xE = constant [14 x i8] c"{E=^^?i^^?ii}\00"
+ extern const char x[] = @encode(E);
+}
diff --git a/test/CodeGenObjCXX/exceptions-legacy.mm b/test/CodeGenObjCXX/exceptions-legacy.mm
index a31ba36660ab..5de90bbb5611 100644
--- a/test/CodeGenObjCXX/exceptions-legacy.mm
+++ b/test/CodeGenObjCXX/exceptions-legacy.mm
@@ -12,7 +12,7 @@ void test0(id obj) {
foo();
}
}
-// CHECK: define void @_Z5test0P11objc_object(
+// CHECK-LABEL: define void @_Z5test0P11objc_object(
// Enter the @synchronized block.
// CHECK: call i32 @objc_sync_enter(i8* [[OBJ:%.*]])
// CHECK: call void @objc_exception_try_enter([[BUF_T:%.*]]* [[BUF:%.*]])
@@ -52,7 +52,7 @@ void test1(id obj, bool *failed) {
*failed = true;
}
}
-// CHECK: define void @_Z5test1P11objc_objectPb(
+// CHECK-LABEL: define void @_Z5test1P11objc_objectPb(
// Enter the @try block.
// CHECK: call void @objc_exception_try_enter([[BUF_T]]* [[BUF:%.*]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr [[BUF_T]]* [[BUF]], i32 0, i32 0, i32 0
diff --git a/test/CodeGenObjCXX/exceptions.mm b/test/CodeGenObjCXX/exceptions.mm
index 031c22204d8b..a62a82b08cbd 100644
--- a/test/CodeGenObjCXX/exceptions.mm
+++ b/test/CodeGenObjCXX/exceptions.mm
@@ -5,7 +5,7 @@ void opaque();
namespace test0 {
- // CHECK: define void @_ZN5test03fooEv
+ // CHECK-LABEL: define void @_ZN5test03fooEv
void foo() {
try {
// CHECK: invoke void @_Z6opaquev
diff --git a/test/CodeGenObjCXX/gc.mm b/test/CodeGenObjCXX/gc.mm
index a504892bcbdf..1659dbf7a445 100644
--- a/test/CodeGenObjCXX/gc.mm
+++ b/test/CodeGenObjCXX/gc.mm
@@ -9,7 +9,7 @@ namespace test0 {
};
A::A() : x(test0::x) {}
-// CHECK: define void @_ZN5test01AC2Ev(
+// CHECK-LABEL: define void @_ZN5test01AC2Ev(
// CHECK: [[THIS:%.*]] = alloca [[TEST0:%.*]]*, align 8
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[THIS]]
diff --git a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
index a5ce78960914..88837c1713ba 100644
--- a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
+++ b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
@@ -43,7 +43,7 @@ void test_D(D d1, D d2) {
d1 = d2;
}
-// CHECK-OBJ: define linkonce_odr %struct.D* @_ZN1DaSERS_
+// CHECK-OBJ-LABEL: define linkonce_odr %struct.D* @_ZN1DaSERS_
// CHECK-OBJ: {{call.*_ZN1AaSERS_}}
// CHECK-OBJ: {{call.*_ZN1BaSERS_}}
// CHECK-OBJ: {{call.*_ZN1CaSERKS_}}
diff --git a/test/CodeGenObjCXX/implicit-copy-constructor.mm b/test/CodeGenObjCXX/implicit-copy-constructor.mm
index 5cd6f42a6c42..6dbd39e15223 100644
--- a/test/CodeGenObjCXX/implicit-copy-constructor.mm
+++ b/test/CodeGenObjCXX/implicit-copy-constructor.mm
@@ -41,7 +41,7 @@ void f(D d) {
D d2(d);
}
-// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr
+// CHECK-LABEL: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr
// CHECK: call void @_ZN1AC1Ev
// CHECK: call void @_ZN1CC2ERS_1A
// CHECK: call void @_ZN1AD1Ev
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index c73e1727d637..2468eb1e71a4 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -6,16 +6,16 @@ fp f() { auto x = []{ return 3; }; return x; }
// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = internal global [5 x i8] c"copy\00"
// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = internal global [12 x i8] c"autorelease\00"
-// MRC: define i32 ()* @_Z1fv(
-// MRC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
+// MRC-LABEL: define i32 ()* @_Z1fv(
+// MRC-LABEL: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
// MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
// MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke" to i8*)
// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
// MRC: ret i32 ()*
-// ARC: define i32 ()* @_Z1fv(
-// ARC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
+// ARC-LABEL: define i32 ()* @_Z1fv(
+// ARC-LABEL: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
// ARC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
// ARC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke" to i8*)
// ARC: call i8* @objc_retainBlock
@@ -35,7 +35,7 @@ void f2() { global = []{ return 3; }; }
// ARC: store i8* bitcast (i32 (i8*)* @___Z2f2v_block_invoke to i8*),
// ARC: call i8* @objc_retainBlock
// ARC: call void @objc_release
-// ARC: define internal i32 @___Z2f2v_block_invoke
+// ARC-LABEL: define internal i32 @___Z2f2v_block_invoke
// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
template <class T> void take_lambda(T &&lambda) { lambda(); }
@@ -60,6 +60,33 @@ void take_block(void (^block)()) { block(); }
}
@end
-// ARC: attributes [[NUW]] = { nounwind{{.*}} }
+// Check lines for BlockInLambda test below
+// ARC-LABEL: define internal i32 @___ZZN13BlockInLambda1X1fEvENKUlvE_clEv_block_invoke
+// ARC: [[Y:%.*]] = getelementptr inbounds %"struct.BlockInLambda::X"* {{.*}}, i32 0, i32 1
+// ARC-NEXT: [[YVAL:%.*]] = load i32* [[Y]], align 4
+// ARC-NEXT: ret i32 [[YVAL]]
+
+typedef int (^fptr)();
+template<typename T> struct StaticMembers {
+ static fptr f;
+};
+template<typename T>
+fptr StaticMembers<T>::f = [] { auto f = []{return 5;}; return fptr(f); }();
+template fptr StaticMembers<float>::f;
+// ARC-LABEL: define linkonce_odr i32 ()* @_ZZNK13StaticMembersIfE1fMUlvE_clEvENKUlvE_cvU13block_pointerFivEEv
+
+namespace BlockInLambda {
+ struct X {
+ int x,y;
+ void f() {
+ [this]{return ^{return y;}();}();
+ };
+ };
+ void g(X& x) {
+ x.f();
+ };
+}
+
+// ARC: attributes [[NUW]] = { nounwind{{.*}} }
// MRC: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenObjCXX/literals.mm b/test/CodeGenObjCXX/literals.mm
index b8946fa3f805..f21bba75f374 100644
--- a/test/CodeGenObjCXX/literals.mm
+++ b/test/CodeGenObjCXX/literals.mm
@@ -14,7 +14,7 @@ struct Y {
operator id() const;
};
-// CHECK: define void @_Z10test_arrayv
+// CHECK-LABEL: define void @_Z10test_arrayv
void test_array() {
// CHECK: [[OBJECTS:%[a-zA-Z0-9.]+]] = alloca [2 x i8*]
@@ -60,7 +60,7 @@ void test_array() {
// CHECK: unreachable
}
-// CHECK: define weak_odr void @_Z24test_array_instantiationIiEvv
+// CHECK-LABEL: define weak_odr void @_Z24test_array_instantiationIiEvv
template<typename T>
void test_array_instantiation() {
// CHECK: [[OBJECTS:%[a-zA-Z0-9.]+]] = alloca [2 x i8*]
diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm
index 892c8afedebf..405e5282cda7 100644
--- a/test/CodeGenObjCXX/mangle-blocks.mm
+++ b/test/CodeGenObjCXX/mangle-blocks.mm
@@ -1,19 +1,22 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
-// CHECK: @_ZGVN3foo22___Z3foov_block_invoke5valueE = internal global i64 0
+// CHECK: @_ZGVZZ3foovEUb_E5value = internal global i64 0
+// CHECK: @_ZZZN26externally_visible_statics1S3fooEiEd_Ub_E1k = linkonce_odr global i32 0
+// CHECK: @_ZZ26externally_visible_statics1S1xMUb_E1j = linkonce_odr global i32 0
+// CHECK: @_ZZZN26externally_visible_statics10inlinefuncEvEUb_E1i = linkonce_odr global i32 0
int f();
void foo() {
- // CHECK: define internal i32 @___Z3foov_block_invoke
- // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo22___Z3foov_block_invoke5valueE
+ // CHECK-LABEL: define internal i32 @___Z3foov_block_invoke
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZZ3foovEUb_E5value
(void)^(int x) {
static int value = f();
return x + value;
};
}
-// CHECK: define internal i32 @i_block_invoke
+// CHECK-LABEL: define internal i32 @i_block_invoke
int i = ^(int x) { return x;}(i);
@interface A
@@ -24,7 +27,7 @@ int i = ^(int x) { return x;}(i);
- (void)method {
// CHECK: define internal signext i8 @"__11-[A method]_block_invoke"
(void)^(int x) {
- // CHECK: @"_ZN11-[A method]28__11-[A method]_block_invoke4nameE"
+ // CHECK: @"_ZZZ11-[A method]EUb0_E4name"
static const char *name = "hello";
return name[x];
};
@@ -39,12 +42,44 @@ void foo(int) {
}
namespace N {
- // CHECK: define internal signext i8 @___Z3fooi_block_invoke
+ // CHECK-LABEL: define internal signext i8 @___Z3fooi_block_invoke
void bar() {
(void)^(int x) {
- // CHECK: @_ZN1N3bar26___ZN1N3barEv_block_invoke4nameE
+ // CHECK: @_ZZZN1N3barEvEUb2_E4name
static const char *name = "hello";
return name[x];
};
}
}
+
+class C {
+ C();
+};
+C::C() {
+ (void)^(int x) {
+ // CHECK: @_ZZZN1CC1EvEUb3_E5nameb
+ static const char *nameb = "hello";
+ return nameb[x];
+ };
+}
+
+int f();
+namespace externally_visible_statics {
+ inline void inlinefunc() {
+ ^{
+ static int i = f();
+ }();
+ }
+ struct S {
+ int x = ^{
+ static int j = f();
+ return j;
+ }();
+ void foo(int y = ^{ static int k = f(); return k; }()) {}
+ };
+ void g() {
+ inlinefunc();
+ S s;
+ s.foo();
+ }
+}
diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm
index 45a93a196dcb..5b944caf1f41 100644
--- a/test/CodeGenObjCXX/mangle.mm
+++ b/test/CodeGenObjCXX/mangle.mm
@@ -78,3 +78,23 @@ void test2(Test2 *t) {
Test2Template<decltype(t.dimension)> t1;
Test2Template<decltype(t->alt_axis)> t2;
}
+
+@protocol P;
+void overload1(A<P>*) {}
+// CHECK-LABEL: define void @_Z9overload1PU11objcproto1P1A
+void overload1(const A<P>*) {}
+// CHECK-LABEL: define void @_Z9overload1PKU11objcproto1P1A
+void overload1(A<P>**) {}
+// CHECK-LABEL: define void @_Z9overload1PPU11objcproto1P1A
+void overload1(A<P>*const*) {}
+// CHECK-LABEL: define void @_Z9overload1PKPU11objcproto1P1A
+void overload1(A<P>***) {}
+// CHECK-LABEL: define void @_Z9overload1PPPU11objcproto1P1A
+void overload1(void (f)(A<P>*)) {}
+// CHECK-LABEL: define void @_Z9overload1PFvPU11objcproto1P1AE
+
+template<typename T> struct X { void f(); };
+template<> void X<A*>::f() {}
+// CHECK-LABEL: define void @_ZN1XIP1AE1fEv
+template<> void X<A<P>*>::f() {}
+// CHECK-LABEL: define void @_ZN1XIPU11objcproto1P1AE1fEv
diff --git a/test/CodeGenObjCXX/message.mm b/test/CodeGenObjCXX/message.mm
index 1268a79d63b7..af3d81f16c98 100644
--- a/test/CodeGenObjCXX/message.mm
+++ b/test/CodeGenObjCXX/message.mm
@@ -15,7 +15,7 @@ namespace test0 {
[a foo];
}
template void foo<int>();
- // CHECK: define weak_odr void @_ZN5test03fooIiEEvv()
+ // CHECK-LABEL: define weak_odr void @_ZN5test03fooIiEEvv()
// CHECK: [[T0:%.*]] = call [[TEST0:%.*]]* @_ZN5test01AcvP5Test0Ev(
// CHECK-NEXT: [[T1:%.*]] = load i8**
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
diff --git a/test/CodeGenObjCXX/nrvo.mm b/test/CodeGenObjCXX/nrvo.mm
index 47460c2fb3db..0a7dff50c5a0 100644
--- a/test/CodeGenObjCXX/nrvo.mm
+++ b/test/CodeGenObjCXX/nrvo.mm
@@ -22,7 +22,7 @@ struct X {
X blocksNRVO() {
return ^{
- // CHECK: define internal void @___Z10blocksNRVOv_block_invoke
+ // CHECK-LABEL: define internal void @___Z10blocksNRVOv_block_invoke
X x;
// CHECK: tail call void @_ZN1XC1Ev
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjCXX/objc-container-subscripting-1.mm b/test/CodeGenObjCXX/objc-container-subscripting-1.mm
index c0dd0f8bae4d..48c5f5cc2cf2 100644
--- a/test/CodeGenObjCXX/objc-container-subscripting-1.mm
+++ b/test/CodeGenObjCXX/objc-container-subscripting-1.mm
@@ -34,7 +34,7 @@ template <class T> void test2(NSMutableArray *a) {
a[10] = 0;
}
template void test2<int>(NSMutableArray*);
-// CHECK: define weak_odr void @_Z5test2IiEvP14NSMutableArray
+// CHECK-LABEL: define weak_odr void @_Z5test2IiEvP14NSMutableArray
// CHECK: @objc_msgSend
// CHECK: ret void
@@ -44,7 +44,7 @@ template <class T> void test3(NSMutableArray *a) {
}
template void test3<int>(NSMutableArray*);
-// CHECK: define weak_odr void @_Z5test3IiEvP14NSMutableArray
+// CHECK-LABEL: define weak_odr void @_Z5test3IiEvP14NSMutableArray
// CHECK: @objc_msgSend
// CHECK: ret void
diff --git a/test/CodeGenObjCXX/objc-container-subscripting.mm b/test/CodeGenObjCXX/objc-container-subscripting.mm
index dfe48e9d6dc8..d9069023b951 100644
--- a/test/CodeGenObjCXX/objc-container-subscripting.mm
+++ b/test/CodeGenObjCXX/objc-container-subscripting.mm
@@ -33,7 +33,7 @@ template <class T> void test2(NSMutableArray *a) {
a[10] = 0;
}
template void test2<int>(NSMutableArray*);
-// CHECK: define weak_odr void @_Z5test2IiEvP14NSMutableArray
+// CHECK-LABEL: define weak_odr void @_Z5test2IiEvP14NSMutableArray
// CHECK: @objc_msgSend
// CHECK: ret void
@@ -43,11 +43,11 @@ template <class T> void test3(NSMutableArray *a) {
}
template void test3<int>(NSMutableArray*);
-// CHECK: define weak_odr void @_Z5test3IiEvP14NSMutableArray
+// CHECK-LABEL: define weak_odr void @_Z5test3IiEvP14NSMutableArray
// CHECK: @objc_msgSend
// CHECK: ret void
-// CHECK: define void @_Z11static_dataP14NSMutableArray
+// CHECK-LABEL: define void @_Z11static_dataP14NSMutableArray
void static_data(NSMutableArray *array) {
// CHECK: call i32 @__cxa_guard_acquire
// CHECK: {{call i8*.*@objc_msgSend }}
diff --git a/test/CodeGenObjCXX/property-dot-reference.mm b/test/CodeGenObjCXX/property-dot-reference.mm
index e64b397cc026..be6742aef25f 100644
--- a/test/CodeGenObjCXX/property-dot-reference.mm
+++ b/test/CodeGenObjCXX/property-dot-reference.mm
@@ -50,7 +50,7 @@ void test2() {
void(obj.myProperty);
void(obj.myGetter);
}
-// CHECK: define void @_Z5test2v()
+// CHECK-LABEL: define void @_Z5test2v()
// CHECK: call i32 bitcast
// CHECK: call double bitcast
// CHECK: call i32 bitcast
diff --git a/test/CodeGenObjCXX/property-object-reference-2.mm b/test/CodeGenObjCXX/property-object-reference-2.mm
index 25bfdf848d3a..542967c48e65 100644
--- a/test/CodeGenObjCXX/property-object-reference-2.mm
+++ b/test/CodeGenObjCXX/property-object-reference-2.mm
@@ -29,7 +29,7 @@ struct TCPPObject
@synthesize MyProperty1 = _cppObject1;
@end
-// CHECK: define internal void @__copy_helper_atomic_property_(
+// CHECK-LABEL: define internal void @__copy_helper_atomic_property_(
// CHECK: [[TWO:%.*]] = load %struct.TCPPObject** [[ADDR:%.*]], align 8
// CHECK: [[THREE:%.*]] = load %struct.TCPPObject** [[ADDR1:%.*]], align 8
// CHECK: [[CALL:%.*]] = call i32 @_Z7DEFAULTv()
@@ -43,7 +43,7 @@ struct TCPPObject
// CHECK: call void @objc_copyCppObjectAtomic(i8* [[THREE]], i8* [[TWO]], i8* bitcast (void (%struct.TCPPObject*, %struct.TCPPObject*)* @__copy_helper_atomic_property_ to i8*))
// CHECK: ret void
-// CHECK: define internal void @__assign_helper_atomic_property_(
+// CHECK-LABEL: define internal void @__assign_helper_atomic_property_(
// CHECK: [[TWO:%.*]] = load %struct.TCPPObject** [[ADDR:%.*]], align 8
// CHECK: [[THREE:%.*]] = load %struct.TCPPObject** [[ADDR1:%.*]], align 8
// CHECK: [[CALL:%.*]] = call %struct.TCPPObject* @_ZN10TCPPObjectaSERKS_(%struct.TCPPObject* [[TWO]], %struct.TCPPObject* [[THREE]])
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
index a3c2ed37466e..88e992c81a4b 100644
--- a/test/CodeGenObjCXX/property-objects.mm
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -54,7 +54,7 @@ struct CGRect {
@end
-// CHECK: define i32 @main
+// CHECK-LABEL: define i32 @main
// CHECK: call void @_ZN1SC1ERKS_(%class.S* [[AGGTMP:%[a-zA-Z0-9\.]+]], %class.S* {{%[a-zA-Z0-9\.]+}})
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %class.S*)*)(i8* {{%[a-zA-Z0-9\.]+}}, i8* {{%[a-zA-Z0-9\.]+}}, %class.S* [[AGGTMP]])
// CHECK-NEXT: ret i32 0
@@ -66,7 +66,7 @@ int main() {
}
// rdar://8379892
-// CHECK: define void @_Z1fP1A
+// CHECK-LABEL: define void @_Z1fP1A
// CHECK: call void @_ZN1XC1Ev(%struct.X* [[LVTEMP:%[a-zA-Z0-9\.]+]])
// CHECK: call void @_ZN1XC1ERKS_(%struct.X* [[AGGTMP:%[a-zA-Z0-9\.]+]], %struct.X* [[LVTEMP]])
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %struct.X*)*)({{.*}} %struct.X* [[AGGTMP]])
diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm
index 0e4897b74947..a4af90010b3b 100644
--- a/test/CodeGenObjCXX/property-reference.mm
+++ b/test/CodeGenObjCXX/property-reference.mm
@@ -64,7 +64,7 @@ template <class T> void test2(Test2 *a) {
a.prop += x;
}
template void test2<int>(Test2*);
-// CHECK: define weak_odr void @_Z5test2IiEvP5Test2(
+// CHECK-LABEL: define weak_odr void @_Z5test2IiEvP5Test2(
// CHECK: [[X:%.*]] = alloca i32,
// CHECK: @objc_msgSend
// CHECK: store i32 {{%.*}}, i32* [[X]],
@@ -83,7 +83,7 @@ template <class T> void test3(Test2 *a) {
a.prop += (sizeof(T), x);
}
template void test3<int>(Test2*);
-// CHECK: define weak_odr void @_Z5test3IiEvP5Test2(
+// CHECK-LABEL: define weak_odr void @_Z5test3IiEvP5Test2(
// CHECK: [[X:%.*]] = alloca i32,
// CHECK: @objc_msgSend
// CHECK: store i32 {{%.*}}, i32* [[X]],
diff --git a/test/CodeGenObjCXX/references.mm b/test/CodeGenObjCXX/references.mm
index 6265c7be7613..39abd8a305f6 100644
--- a/test/CodeGenObjCXX/references.mm
+++ b/test/CodeGenObjCXX/references.mm
@@ -17,7 +17,7 @@ struct A { ~A(); };
@end
-// CHECK: define void @_Z1fP1B
+// CHECK-LABEL: define void @_Z1fP1B
// CHECK: objc_msgSend to
// CHECK-NOT: call void @_ZN1AD1Ev
// CHECK: ret void
diff --git a/test/CodeGenObjCXX/rtti.mm b/test/CodeGenObjCXX/rtti.mm
index 72de3ac98016..e458f090a768 100644
--- a/test/CodeGenObjCXX/rtti.mm
+++ b/test/CodeGenObjCXX/rtti.mm
@@ -38,14 +38,14 @@ int main() {
const std::type_info &t5 = typeid(c);
const std::type_info &t6 = typeid(*c);
- // CHECK: store {{.*}} @_ZTIP11objc_object
- // CHECK: store {{.*}} @_ZTI11objc_object
+ // CHECK: store {{.*}} @_ZTIPU11objcproto1P11objc_object
+ // CHECK: store {{.*}} @_ZTIU11objcproto1P11objc_object
id<P> i2 = 0;
const std::type_info &t7 = typeid(i2);
const std::type_info &t8 = typeid(*i2);
- // CHECK: store {{.*}} @_ZTIP10objc_class
- // CHECK: store {{.*}} @_ZTI10objc_class
+ // CHECK: store {{.*}} @_ZTIPU11objcproto1P10objc_class
+ // CHECK: store {{.*}} @_ZTIU11objcproto1P10objc_class
Class<P> c2 = 0;
const std::type_info &t9 = typeid(c2);
const std::type_info &t10 = typeid(*c2);
diff --git a/test/CodeGenObjCXX/unknown-anytype.mm b/test/CodeGenObjCXX/unknown-anytype.mm
index 0e146d42c9ee..4731fcc76dfe 100644
--- a/test/CodeGenObjCXX/unknown-anytype.mm
+++ b/test/CodeGenObjCXX/unknown-anytype.mm
@@ -6,7 +6,7 @@
void test0(A *a) {
(void) [a test0: (float) 2.0];
}
-// CHECK: define void @_Z5test0P1A(
+// CHECK-LABEL: define void @_Z5test0P1A(
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
@interface B
@@ -15,6 +15,6 @@ void test0(A *a) {
void test1(B *b) {
(void) [b test1: (float) 2.0];
}
-// CHECK: define void @_Z5test1P1B(
+// CHECK-LABEL: define void @_Z5test1P1B(
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
diff --git a/test/CodeGenOpenCL/address-spaces-mangling.cl b/test/CodeGenOpenCL/address-spaces-mangling.cl
new file mode 100644
index 000000000000..3c7a5183636c
--- /dev/null
+++ b/test/CodeGenOpenCL/address-spaces-mangling.cl
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=yes -emit-llvm -o - | FileCheck -check-prefix=ASMANG %s
+// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=no -emit-llvm -o - | FileCheck -check-prefix=NOASMANG %s
+
+// We can't name this f as private is equivalent to default
+// no specifier given address space so we get multiple definition
+// warnings, but we do want it for comparison purposes.
+__attribute__((overloadable))
+void ff(int *arg) { }
+// ASMANG: @_Z2ffPi
+// NOASMANG: @_Z2ffPi
+
+__attribute__((overloadable))
+void f(private int *arg) { }
+// ASMANG: @_Z1fPi
+// NOASMANG: @_Z1fPi
+
+__attribute__((overloadable))
+void f(global int *arg) { }
+// ASMANG: @_Z1fPU3AS1i
+// NOASMANG: @_Z1fPU8CLglobali
+
+__attribute__((overloadable))
+void f(local int *arg) { }
+// ASMANG: @_Z1fPU3AS2i
+// NOASMANG: @_Z1fPU7CLlocali
+
+__attribute__((overloadable))
+void f(constant int *arg) { }
+// ASMANG: @_Z1fPU3AS3i
+// NOASMANG: @_Z1fPU10CLconstanti
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index 1166f9384fa4..0825ffc0336f 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
diff --git a/test/CodeGenOpenCL/local.cl b/test/CodeGenOpenCL/local.cl
index b4bd0085dfad..b5c67d9af9c7 100644
--- a/test/CodeGenOpenCL/local.cl
+++ b/test/CodeGenOpenCL/local.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=no -emit-llvm -o - | FileCheck %s
__kernel void foo(void) {
// CHECK: @foo.i = internal addrspace(2)
@@ -6,7 +6,7 @@ __kernel void foo(void) {
++i;
}
-// CHECK: define void @_Z3barPU3AS2i
+// CHECK-LABEL: define void @_Z3barPU7CLlocali
__kernel void __attribute__((__overloadable__)) bar(local int *x) {
*x = 5;
}
diff --git a/test/CodeGenOpenCL/opencl_types.cl b/test/CodeGenOpenCL/opencl_types.cl
index b1e558db9b9c..7e99fc548ec5 100644
--- a/test/CodeGenOpenCL/opencl_types.cl
+++ b/test/CodeGenOpenCL/opencl_types.cl
@@ -22,7 +22,7 @@ void fnc3(image3d_t img) {}
// CHECK: @fnc3(%opencl.image3d_t*
void fnc4smp(sampler_t s) {}
-// CHECK: define void @fnc4smp(i32
+// CHECK-LABEL: define void @fnc4smp(i32
kernel void foo(image1d_t img) {
sampler_t smp = 5;
diff --git a/test/CodeGenOpenCL/ptx-calls.cl b/test/CodeGenOpenCL/ptx-calls.cl
index d9904513e518..00f2a0e4c042 100644
--- a/test/CodeGenOpenCL/ptx-calls.cl
+++ b/test/CodeGenOpenCL/ptx-calls.cl
@@ -2,12 +2,12 @@
void device_function() {
}
-// CHECK: define void @device_function()
+// CHECK-LABEL: define void @device_function()
__kernel void kernel_function() {
device_function();
}
-// CHECK: define void @kernel_function()
+// CHECK-LABEL: define void @kernel_function()
// CHECK: call void @device_function()
// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/ptx-kernels.cl b/test/CodeGenOpenCL/ptx-kernels.cl
index 07648e401507..49d207f023c8 100644
--- a/test/CodeGenOpenCL/ptx-kernels.cl
+++ b/test/CodeGenOpenCL/ptx-kernels.cl
@@ -2,10 +2,10 @@
void device_function() {
}
-// CHECK: define void @device_function()
+// CHECK-LABEL: define void @device_function()
__kernel void kernel_function() {
}
-// CHECK: define void @kernel_function()
+// CHECK-LABEL: define void @kernel_function()
// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/str_literals.cl b/test/CodeGenOpenCL/str_literals.cl
new file mode 100644
index 000000000000..78a93056b98d
--- /dev/null
+++ b/test/CodeGenOpenCL/str_literals.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -ffake-address-space-map | FileCheck %s
+
+__constant char * __constant x = "hello world";
+__constant char * __constant y = "hello world";
+
+// CHECK: addrspace(3) unnamed_addr constant
+// CHECK-NOT: addrspace(3) unnamed_addr constant
+// CHECK: @x = addrspace(3) global i8 addrspace(3)*
+// CHECK: @y = addrspace(3) global i8 addrspace(3)*
diff --git a/test/CodeGenOpenCL/vector_odd.cl b/test/CodeGenOpenCL/vector_odd.cl
new file mode 100644
index 000000000000..c44328bfaa71
--- /dev/null
+++ b/test/CodeGenOpenCL/vector_odd.cl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -o - | FileCheck %s
+
+typedef unsigned char __attribute__((ext_vector_type(3))) uchar3;
+
+//CHECK: {{%.*}} = shufflevector <3 x i8> {{%.*}}, <3 x i8> <i8 1, i8 1, i8 undef>, <3 x i32> <i32 0, i32 3, i32 2>
+
+kernel void test_odd_vector1 (uchar3 lhs)
+{
+ lhs.odd = 1;
+}
+
+//CHECK: {{%.*}} = shufflevector <3 x i8> {{%.*}}, <3 x i8> <i8 2, i8 2, i8 undef>, <3 x i32> <i32 0, i32 1, i32 3>
+
+kernel void test_odd_vector2 (uchar3 lhs)
+{
+ lhs.hi = 2;
+}
diff --git a/test/Coverage/codegen-next.m b/test/Coverage/codegen-next.m
index 8f6645df515a..7b907fea0e1e 100644
--- a/test/Coverage/codegen-next.m
+++ b/test/Coverage/codegen-next.m
@@ -1,4 +1,12 @@
-// RUN: %clang_cc1 -emit-llvm -fobjc-exceptions -o %t %s
-// RUN: %clang_cc1 -g -emit-llvm -fobjc-exceptions -o %t %s
+// RUN: %clang_cc1 -emit-llvm -fobjc-exceptions -triple x86_64-apple-darwin -o %t %s
+// RUN: %clang_cc1 -g -emit-llvm -fobjc-exceptions -triple x86_64-apple-darwin -o %t %s
+
+// An error could be seen for targeting x86_64-win32;
+//
+// Bitcast requires types of same width
+// %7 = bitcast i32 %6 to i64
+//
+// Then, This test should be excluded on x86_64-win32.
+// REQUIRES: LP64
#include "objc-language-features.inc"
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
index 4f1b0e3763b8..410ee2acd5fd 100644
--- a/test/Coverage/html-diagnostics.c
+++ b/test/Coverage/html-diagnostics.c
@@ -2,6 +2,9 @@
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s
// RUN: cat %t/*.html | FileCheck %s
+// Because of the glob (*.html)
+// REQUIRES: shell
+
// CHECK: <h3>Annotated Source Code</h3>
// Without tweaking expr, the expr would hit to the line below
diff --git a/test/Driver/B-opt.c b/test/Driver/B-opt.c
index a0b9a11162dd..6759353174d0 100644
--- a/test/Driver/B-opt.c
+++ b/test/Driver/B-opt.c
@@ -3,20 +3,20 @@
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir1 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-TRIPLE %s
-// CHECK-B-OPT-TRIPLE: "{{.*}}/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld"
+// CHECK-B-OPT-TRIPLE: "{{.*}}/Inputs/B_opt_tree/dir1{{/|\\}}i386-unknown-linux-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-DIR %s
-// CHECK-B-OPT-DIR: "{{.*}}/Inputs/B_opt_tree/dir2/ld"
+// CHECK-B-OPT-DIR: "{{.*}}/Inputs/B_opt_tree/dir2{{/|\\}}ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-PREFIX %s
-// CHECK-B-OPT-PREFIX: "{{.*}}/Inputs/B_opt_tree/dir3/prefix-ld"
+// CHECK-B-OPT-PREFIX: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\}}prefix-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- \
// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-MULT %s
-// CHECK-B-OPT-MULT: "{{.*}}/Inputs/B_opt_tree/dir3/prefix-ld"
+// CHECK-B-OPT-MULT: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\}}prefix-ld"
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-as b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld
new file mode 120000
index 000000000000..7e0a9cfe2ddb
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld
@@ -0,0 +1 @@
+i386-unknown-linux-gnu-ld.gold \ No newline at end of file
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.bfd b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.bfd
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.bfd
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.gold b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.gold
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/i386-unknown-linux-gnu-ld.gold
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld
new file mode 120000
index 000000000000..ce36ac093b61
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld
@@ -0,0 +1 @@
+x86_64-unknown-linux-gnu-ld.gold \ No newline at end of file
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.bfd b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.bfd
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.bfd
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.gold b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.gold
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld.gold
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/as b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld
new file mode 120000
index 000000000000..6cd03701cdda
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld
@@ -0,0 +1 @@
+ld.gold \ No newline at end of file
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.bfd b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.bfd
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.bfd
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.gold b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.gold
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/bin/ld.gold
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/lib/.keep b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/i386-unknown-linux-gnu/lib/.keep
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/crtbegin.o b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbegin.o b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbeginT.o b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbeginT.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtbeginT.o
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtfastmath.o b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtfastmath.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/crtfastmath.o
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/as b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld
new file mode 120000
index 000000000000..6cd03701cdda
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld
@@ -0,0 +1 @@
+ld.gold \ No newline at end of file
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.bfd b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.bfd
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.bfd
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.gold b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.gold
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/bin/ld.gold
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/lib/.keep b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_cross_linux_tree/usr/x86_64-unknown-linux-gnu/lib/.keep
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crt0.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crt0.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crt0.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbegin.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbegin.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbeginS.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbeginS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtbeginS.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtend.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtend.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtendS.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtendS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtendS.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtn.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/libtest.so b/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/libtest.so
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/libtest.so
diff --git a/test/Driver/Inputs/file.prof b/test/Driver/Inputs/file.prof
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/file.prof
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/crtbegin.o b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/crtbegin.o
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/.keep b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/.keep
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/x86_64-pc-linux-gnu/lib/.keep b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/x86_64-pc-linux-gnu/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.2_tree/usr/x86_64-pc-linux-gnu/lib/.keep
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/crtbegin.o b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/crtbegin.o
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/.keep b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/.keep
diff --git a/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/x86_64-pc-linux-gnu/lib/.keep b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/x86_64-pc-linux-gnu/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gentoo_linux_gcc_4.6.4_tree/usr/x86_64-pc-linux-gnu/lib/.keep
diff --git a/test/Driver/Inputs/lit.local.cfg b/test/Driver/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/Driver/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/Driver/Inputs/mips_fsf_tree/bin/.keep b/test/Driver/Inputs/mips_fsf_tree/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/bin/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include-fixed/.keep b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include-fixed/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include-fixed/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include/.keep b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/include/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/micromips/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips16/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/mips16/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips32/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/64/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/64/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/fp64/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/mips64r2/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/backward/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/backward/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/backward/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/micromips/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips16/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/mips16/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips32/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/64/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/64/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/fp64/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/fp64/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/fp64/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/mips64r2/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/inclide/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/inclide/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/inclide/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/inclide/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/inclide/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/inclide/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/inclide/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/inclide/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/inclide/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/micromips/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips16/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/mips16/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips32/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/fp64/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/mips64r2/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/as b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/as
new file mode 120000
index 000000000000..0065315cfd1d
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/as
@@ -0,0 +1 @@
+i386-unknown-linux-gnu-as \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-as b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-ld b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-ld
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/i386-unknown-linux-gnu-ld
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/ld b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/ld
new file mode 120000
index 000000000000..9e5574285c70
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/bin/ld
@@ -0,0 +1 @@
+i386-unknown-linux-gnu-ld \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/as b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/as
new file mode 120000
index 000000000000..2aa12fdef916
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/as
@@ -0,0 +1 @@
+../../bin/i386-unknown-linux-gnu-as \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/ld b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/ld
new file mode 120000
index 000000000000..5aeaff619662
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/bin/ld
@@ -0,0 +1 @@
+../../bin/i386-unknown-linux-gnu-ld \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/as b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/as
new file mode 120000
index 000000000000..477cbc9635fc
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/as
@@ -0,0 +1 @@
+x86_64-unknown-linux-gnu-as \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/ld b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/ld
new file mode 120000
index 000000000000..5343caf34d8f
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/ld
@@ -0,0 +1 @@
+x86_64-unknown-linux-gnu-ld \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-as
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld
new file mode 100755
index 000000000000..b23e55619b2f
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/bin/x86_64-unknown-linux-gnu-ld
@@ -0,0 +1 @@
+#!/bin/true
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/as b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/as
new file mode 120000
index 000000000000..84a9113f2671
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/as
@@ -0,0 +1 @@
+../../bin/x86_64-unknown-linux-gnu-as \ No newline at end of file
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/ld b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/ld
new file mode 120000
index 000000000000..c417e3afaa49
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/bin/ld
@@ -0,0 +1 @@
+../../bin/x86_64-unknown-linux-gnu-ld \ No newline at end of file
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/crtbegin.o b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/crtbegin.o
new file mode 100644
index 000000000000..c6cac69265af
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/crtbegin.o
@@ -0,0 +1 @@
+empty
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/lib/.keep b/test/Driver/Inputs/x86-64_ubuntu_13.10/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/lib/.keep
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crt1.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crt1.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crti.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crti.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crtn.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabi/lib/crtn.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crt1.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crt1.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crti.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crti.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crtn.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/arm-linux-gnueabihf/lib/crtn.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtbegin.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtbegin.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtend.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/crtend.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtbegin.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtbegin.o
diff --git a/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtend.o b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/x86-64_ubuntu_13.10/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/crtend.o
diff --git a/test/Driver/O.c b/test/Driver/O.c
new file mode 100644
index 000000000000..a7dedc860cfc
--- /dev/null
+++ b/test/Driver/O.c
@@ -0,0 +1,10 @@
+// Test that we parse and translate the -O option correctly.
+
+// RUN: %clang -O -### %s 2>&1 | FileCheck -check-prefix=CHECK-O %s
+// CHECK-O: -O2
+
+// RUN: %clang -O0 -### %s 2>&1 | FileCheck -check-prefix=CHECK-O0 %s
+// CHECK-O0: -O0
+
+// RUN: %clang -O1 -### %s 2>&1 | FileCheck -check-prefix=CHECK-O1 %s
+// CHECK-O1: -O1
diff --git a/test/Driver/Wp-args.c b/test/Driver/Wp-args.c
index 1d1af24804a1..e01e2a2651f0 100644
--- a/test/Driver/Wp-args.c
+++ b/test/Driver/Wp-args.c
@@ -1,7 +1,7 @@
// Check that we extract -MD from '-Wp,-MD,FOO', which is used by a number of
// major projects (e.g., FireFox and the Linux Kernel).
-// RUN: %clang --target i386-pc-linux-gnu -### \
+// RUN: %clang -target i386-pc-linux-gnu -### \
// RUN: -Wp,-MD,FOO.d -fsyntax-only %s 2> %t
// RUN: FileCheck < %t %s
//
@@ -12,7 +12,7 @@
//
// PR4062
-// RUN: %clang --target i386-pc-linux-gnu -### \
+// RUN: %clang -target i386-pc-linux-gnu -### \
// RUN: -Wp,-MMD -fsyntax-only %s 2> %t
// RUN: FileCheck -check-prefix MMD < %t %s
diff --git a/test/Driver/Xarch.c b/test/Driver/Xarch.c
index 2523f5acac01..34f9340dd68f 100644
--- a/test/Driver/Xarch.c
+++ b/test/Driver/Xarch.c
@@ -1,7 +1,7 @@
// RUN: %clang -target i386-apple-darwin9 -m32 -Xarch_i386 -O2 %s -S -### 2> %t.log
// RUN: grep ' "-O2" ' %t.log | count 1
// RUN: %clang -target i386-apple-darwin9 -m64 -Xarch_i386 -O2 %s -S -### 2> %t.log
-// RUN: grep ' "-O2" ' %t.log | count 0
+// RUN: not grep ' "-O2" ' %t.log
// RUN: grep "argument unused during compilation: '-Xarch_i386 -O2'" %t.log
// RUN: not %clang -target i386-apple-darwin9 -m32 -Xarch_i386 -o -Xarch_i386 -S %s -S -Xarch_i386 -o 2> %t.log
// RUN: grep "error: invalid Xarch argument: '-Xarch_i386 -o'" %t.log | count 2
diff --git a/test/Driver/Xlinker-args.c b/test/Driver/Xlinker-args.c
index d89d5bad1aaf..4285af7944b5 100644
--- a/test/Driver/Xlinker-args.c
+++ b/test/Driver/Xlinker-args.c
@@ -14,3 +14,11 @@
// DARWIN-NOT: --no-demangle
// DARWIN: "one" "two" "three" "four"
// LINUX: "--no-demangle" "one" "two" "three" "four"
+
+// Check that we forward '-Xlinker' and '-Wl,' on Windows.
+// RUN: %clang -target i686-pc-win32 -### \
+// RUN: -Xlinker one -Wl,two %s 2>&1 | \
+// RUN: FileCheck -check-prefix=WIN %s
+// WIN: link.exe
+// WIN: "one"
+// WIN: "two"
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
new file mode 100644
index 000000000000..799ce1042a0e
--- /dev/null
+++ b/test/Driver/aarch64-cpus.c
@@ -0,0 +1,10 @@
+// Check target CPUs are correctly passed.
+
+// RUN: %clang -target aarch64 -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC %s
+// GENERIC: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
+// CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
+
+// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
+// CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57"
diff --git a/test/Driver/aarch64-mfpu.c b/test/Driver/aarch64-mfpu.c
new file mode 100644
index 000000000000..234401bcb211
--- /dev/null
+++ b/test/Driver/aarch64-mfpu.c
@@ -0,0 +1,26 @@
+// Test that different values of -mfpu pick correct AArch64 FPU target-feature(s).
+
+// RUN: %clang -target aarch64-linux-eabi -mfpu=neon %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON %s
+// CHECK-NEON: "-target-feature" "+neon"
+
+// RUN: %clang -target aarch64-linux-eabi -mfpu=fp-armv8 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP-ARMV8 %s
+// CHECK-FP-ARMV8: "-target-feature" "+fp-armv8"
+
+// RUN: %clang -target aarch64-linux-eabi -mfpu=neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON-FP-ARMV8 %s
+// CHECK-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
+// CHECK-NEON-FP-ARMV8: "-target-feature" "+neon"
+
+// RUN: %clang -target aarch64-linux-eabi -mfpu=crypto-neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-CRYPTO-NEON-FP-ARMV8 %s
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+neon"
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+crypto"
+
+// RUN: %clang -target aarch64-linux-eabi -mfpu=none %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FP %s
+// CHECK-NO-FP: "-target-feature" "-fp-armv8"
+// CHECK-NO-FP: "-target-feature" "-crypto"
+// CHECK-NO-FP: "-target-feature" "-neon"
diff --git a/test/Driver/altivec-asm.S b/test/Driver/altivec-asm.S
new file mode 100644
index 000000000000..4143d520f4a8
--- /dev/null
+++ b/test/Driver/altivec-asm.S
@@ -0,0 +1,3 @@
+// RUN: %clang -target powerpc64-linux-gnu -maltivec -S %s -o - | FileCheck %s
+// Verify that assembling an empty file does not auto-include altivec.h.
+// CHECK-NOT: static vector
diff --git a/test/Driver/arc.c b/test/Driver/arc.c
index 4c99e5773acc..97d00baf4cc9 100644
--- a/test/Driver/arc.c
+++ b/test/Driver/arc.c
@@ -1,9 +1,9 @@
-// RUN: %clang -ObjC -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x objective-c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x objective-c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
-// RUN: %clang -x c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
-// RUN: %clang -x objective-c -target x86_64-apple-darwin11 -mmacosx-version-min=10.5 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix UNSUPPORTED %s
+// RUN: not %clang -ObjC -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang -x objective-c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang -x objective-c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang -x c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: not %clang -x c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: not %clang -x objective-c -target x86_64-apple-darwin11 -mmacosx-version-min=10.5 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix UNSUPPORTED %s
// Just to test clang is working.
# foo
diff --git a/test/Driver/arch.c b/test/Driver/arch.c
index df9a3e10e02e..f113c1dfa5c2 100644
--- a/test/Driver/arch.c
+++ b/test/Driver/arch.c
@@ -1,3 +1,5 @@
-// RUN: %clang -target armv7a-unknown-linux-gnueabi -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang -target armv7a-unknown-linux-gnueabi -S -emit-llvm %s -o - | FileCheck %s --check-prefix=V7
+// RUN: %clang -target armv8a-unknown-linux-gnueabi -S -emit-llvm %s -o - | FileCheck %s --check-prefix=V8
-// CHECK: target triple = "armv7-unknown-linux-gnueabi"
+// V7: target triple = "armv7-unknown-linux-gnueabi"
+// V8: target triple = "armv8-unknown-linux-gnueabi"
diff --git a/test/Driver/arm-alignment.c b/test/Driver/arm-alignment.c
new file mode 100644
index 000000000000..e3ab276212a3
--- /dev/null
+++ b/test/Driver/arm-alignment.c
@@ -0,0 +1,25 @@
+// RUN: %clang -target arm-none-gnueabi -munaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-UNALIGNED < %t %s
+
+// RUN: %clang -target arm-none-gnueabi -mstrict-align -munaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-UNALIGNED < %t %s
+
+// RUN: %clang -target arm-none-gnueabi -mno-unaligned-access -munaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-UNALIGNED < %t %s
+
+// CHECK-UNALIGNED: "-backend-option" "-arm-no-strict-align"
+
+
+// RUN: %clang -target arm-none-gnueabi -mno-unaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ALIGNED < %t %s
+
+// RUN: %clang -target arm-none-gnueabi -mstrict-align -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ALIGNED < %t %s
+
+// RUN: %clang -target arm-none-gnueabi -munaligned-access -mno-unaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ALIGNED < %t %s
+
+// RUN: %clang -target arm-none-gnueabi -munaligned-access -mstrict-align -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ALIGNED < %t %s
+
+// CHECK-ALIGNED: "-backend-option" "-arm-strict-align"
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index 6fa649aa392a..bd833cbdd009 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -1,3 +1,4 @@
+// ================== Check default Cortex CPU on each major architecture
// RUN: %clang -target armv6m-apple-darwin -arch armv6m -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6M %s
// CHECK-V6M: "-cc1"{{.*}} "-triple" "thumbv6m-{{.*}} "-target-cpu" "cortex-m0"
@@ -6,3 +7,39 @@
// RUN: %clang -target armv7em-apple-darwin -arch armv7em -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7EM %s
// CHECK-V7EM: "-cc1"{{.*}} "-triple" "thumbv7em-{{.*}} "-target-cpu" "cortex-m4"
+
+// RUN: %clang -target armv7a-linux-gnueabi -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7A %s
+// CHECK-V7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}} "-target-cpu" "cortex-a8"
+
+// RUN: %clang -target armv7r-linux-gnueabi -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7R %s
+// CHECK-V7R: "-cc1"{{.*}} "-triple" "armv7r-{{.*}} "-target-cpu" "cortex-r4"
+
+// RUN: %clang -target armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// CHECK-V8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}" "-target-cpu" "cortex-a53"
+
+// ================== Check default Architecture on each Cortex CPU
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// CHECK-CPUV7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}}
+
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m0 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6M %s
+// CHECK-CPUV6M: "-cc1"{{.*}} "-triple" "thumbv6m-{{.*}}
+
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m3 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7M %s
+// CHECK-CPUV7M: "-cc1"{{.*}} "-triple" "armv7m-{{.*}}
+
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
+// CHECK-CPUV7EM: "-cc1"{{.*}} "-triple" "armv7em-{{.*}}
+
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// CHECK-CPUV7R: "-cc1"{{.*}} "-triple" "armv7r-{{.*}}
+
+// RUN: %clang -target arm -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// CHECK-CPUV8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}
diff --git a/test/Driver/arm-fixed-r9.c b/test/Driver/arm-fixed-r9.c
new file mode 100644
index 000000000000..0a95d8779780
--- /dev/null
+++ b/test/Driver/arm-fixed-r9.c
@@ -0,0 +1,4 @@
+// RUN: %clang -target arm-none-gnueeabi -ffixed-r9 -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-FIXED-R9 < %t %s
+
+// CHECK-FIXED-R9: "-backend-option" "-arm-reserve-r9"
diff --git a/test/Driver/arm-hwdiv.c b/test/Driver/arm-hwdiv.c
new file mode 100644
index 000000000000..b3617ce53452
--- /dev/null
+++ b/test/Driver/arm-hwdiv.c
@@ -0,0 +1,39 @@
+// Test that different values of -mhwdiv pick correct ARM hwdiv target-feature(s).
+
+// RUN: %clang -### -target arm %s -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s
+// CHECK-DEFAULT-NOT: "-target-feature" "+hwdiv"
+// CHECK-DEFAULT-NOT: "-target-feature" "+hwdiv-arm"
+
+// RUN: %clang -### -target arm %s -mhwdiv=arm -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM %s
+// CHECK-ARM: "-target-feature" "+hwdiv-arm"
+// CHECK-ARM: "-target-feature" "-hwdiv"
+
+// RUN: %clang -### -target arm %s -mhwdiv=thumb -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-THUMB %s
+// CHECK-THUMB: "-target-feature" "-hwdiv-arm"
+// CHECK-THUMB: "-target-feature" "+hwdiv"
+
+// RUN: %clang -### -target arm %s -mhwdiv=arm,thumb -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM-THUMB %s
+// CHECK-ARM-THUMB: "-target-feature" "+hwdiv-arm"
+// CHECK-ARM-THUMB: "-target-feature" "+hwdiv"
+
+// RUN: %clang -### -target arm %s -mhwdiv=thumb,arm -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-THUMB-ARM %s
+// CHECK-THUMB-ARM: "-target-feature" "+hwdiv-arm"
+// CHECK-THUMB-ARM: "-target-feature" "+hwdiv"
+
+// RUN: %clang -### -target arm %s -mhwdiv=none -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NONE %s
+// CHECK-NONE: "-target-feature" "-hwdiv-arm"
+// CHECK-NONE: "-target-feature" "-hwdiv"
+
+// Also check the alternative syntax.
+
+// RUN: %clang -### -target arm %s --mhwdiv arm -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ALT %s
+// CHECK-ALT: "-target-feature" "+hwdiv-arm"
+// CHECK-ALT: "-target-feature" "-hwdiv"
+
diff --git a/test/Driver/arm-mfpmath.c b/test/Driver/arm-mfpmath.c
deleted file mode 100644
index 0421046c5bc8..000000000000
--- a/test/Driver/arm-mfpmath.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// Test different values of -mfpmath.
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP %s
-// CHECK-VFP: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp2 %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP2 %s
-// CHECK-VFP2: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp3 %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP3 %s
-// CHECK-VFP3: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp4 %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP4 %s
-// CHECK-VFP4: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=neon %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-NEON %s
-// CHECK-NEON: "-target-feature" "+neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=foo %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-ERROR %s
-// CHECK-ERROR: clang compiler does not support '-mfpmath=foo'
-
-// RUN: %clang -target arm-apple-darwin10 -mcpu=arm1136j-s -mfpmath=neon %s -### -c -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-MCPU-ERROR %s
-// CHECK-MCPU-ERROR: error: invalid feature '-mfpmath=neon' for CPU 'arm1136j-s'
diff --git a/test/Driver/arm-mfpu.c b/test/Driver/arm-mfpu.c
index f51c41ed3f8a..765b2982156a 100644
--- a/test/Driver/arm-mfpu.c
+++ b/test/Driver/arm-mfpu.c
@@ -46,3 +46,41 @@
// RUN: %clang -target arm-linux-eabi -msoft-float %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-SOFT-FLOAT %s
// CHECK-SOFT-FLOAT: "-target-feature" "-neon"
+
+// RUN: %clang -target armv8 -mfpu=fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARMV8-SOFT-FLOAT %s
+// CHECK-ARMV8-SOFT-FLOAT: "-target-feature" "+fp-armv8"
+// CHECK-ARMV8-SOFT-FLOAT: "-target-feature" "-crypto"
+// CHECK-ARMV8-SOFT-FLOAT: "-target-feature" "-neon"
+
+// RUN: %clang -target armv8-linux-gnueabihf -mfpu=fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP-ARMV8 %s
+// CHECK-FP-ARMV8-NOT: "-target-feature" "+neon"
+// CHECK-FP-ARMV8: "-target-feature" "+fp-armv8"
+// CHECK-FP-ARMV8: "-target-feature" "-neon"
+// CHECK-FP-ARMV8: "-target-feature" "-crypto"
+
+// RUN: %clang -target armv8-linux-gnueabihf -mfpu=neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON-FP-ARMV8 %s
+// CHECK-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
+// CHECK-NEON-FP-ARMV8: "-target-feature" "+neon"
+// CHECK-NEON-FP-ARMV8: "-target-feature" "-crypto"
+
+// RUN: %clang -target armv8-linux-gnueabihf -mfpu=crypto-neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-CRYPTO-NEON-FP-ARMV8 %s
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+neon"
+// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+crypto"
+
+// RUN: %clang -target armv8-linux-gnueabi -mfpu=none %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FP %s
+// CHECK-NO-FP: "-target-feature" "-vfp2"
+// CHECK-NO-FP: "-target-feature" "-vfp3"
+// CHECK-NO-FP: "-target-feature" "-vfp4"
+// CHECK-NO-FP: "-target-feature" "-fp-armv8"
+// CHECK-NO-FP: "-target-feature" "-crypto"
+// CHECK-NO-FP: "-target-feature" "-neon"
+
+// RUN: %clang -target arm-linux-gnueabihf %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-HF %s
+// CHECK-HF: "-target-cpu" "arm1136jf-s"
diff --git a/test/Driver/arm-restrict-it.c b/test/Driver/arm-restrict-it.c
new file mode 100644
index 000000000000..c2a776046b68
--- /dev/null
+++ b/test/Driver/arm-restrict-it.c
@@ -0,0 +1,15 @@
+// RUN: %clang -target arm-none-gnueabi -mrestrict-it -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-RESTRICTED < %t %s
+
+// RUN: %clang -target armv8a-none-gnueabi -mrestrict-it -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-RESTRICTED < %t %s
+
+// CHECK-RESTRICTED: "-backend-option" "-arm-restrict-it"
+
+// RUN: %clang -target arm-none-gnueabi -mno-restrict-it -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-RESTRICTED < %t %s
+
+// RUN: %clang -target armv8a-none-gnueabi -mno-restrict-it -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-RESTRICTED < %t %s
+
+// CHECK-NO-RESTRICTED: "-backend-option" "-arm-no-restrict-it"
diff --git a/test/Driver/armv8-crc.c b/test/Driver/armv8-crc.c
new file mode 100644
index 000000000000..bee75355cd79
--- /dev/null
+++ b/test/Driver/armv8-crc.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target armv8 -mcrc -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-V8-CRC < %t %s
+// CHECK-V8-CRC: "-target-feature" "+crc"
+
+// RUN: %clang -target armv8 -mnocrc -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-V8-NOCRC < %t %s
+// CHECK-V8-NOCRC: "-target-feature" "-crc"
+
diff --git a/test/Driver/at_file.c b/test/Driver/at_file.c
index 4ad2a5fde3d6..0541ece88b1f 100644
--- a/test/Driver/at_file.c
+++ b/test/Driver/at_file.c
@@ -1,5 +1,7 @@
// RUN: %clang -E %s @%s.args -o %t.log
// RUN: FileCheck --input-file=%t.log %s
+// RUN: %clang -E %s @%s.args.utf16le -o %t.log
+// RUN: FileCheck --input-file=%t.log %s
// CHECK: bar1
// CHECK-NEXT: bar2 zed2
@@ -13,6 +15,8 @@
// CHECK-NEXT: foo10"bar10"zed10
// CHECK: bar
// CHECK: zed12
+// CHECK: one\two
+// CHECK: c:\foo\bar.c
foo1
foo2
@@ -28,3 +32,5 @@ foo10
bar
#endif
foo12
+foo13
+foo14
diff --git a/test/Driver/at_file.c.args b/test/Driver/at_file.c.args
index 9a2b4ee93bd3..8739000e3c57 100644
--- a/test/Driver/at_file.c.args
+++ b/test/Driver/at_file.c.args
@@ -9,3 +9,5 @@
-Dfoo10=foo10\"bar10\"zed10
-D foo11
-Dfoo12=zed12\
+-Dfoo13='one\\two'
+-Dfoo14='c:\foo\bar.c'
diff --git a/test/Driver/at_file.c.args.utf16le b/test/Driver/at_file.c.args.utf16le
new file mode 100644
index 000000000000..c219c603a76a
--- /dev/null
+++ b/test/Driver/at_file.c.args.utf16le
Binary files differ
diff --git a/test/Driver/bounds-checking.c b/test/Driver/bounds-checking.c
index a4f97e820b4c..fdd20ca374ef 100644
--- a/test/Driver/bounds-checking.c
+++ b/test/Driver/bounds-checking.c
@@ -1,11 +1,11 @@
// RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2> %t
// RUN: FileCheck -check-prefix=CHECK < %t %s
-// CHECK: "-fsanitize=bounds"
+// CHECK: "-fsanitize=array-bounds,local-bounds"
// RUN: %clang -fbounds-checking -### -fsyntax-only %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-OLD < %t %s
-// CHECK-OLD: "-fsanitize=bounds"
+// CHECK-OLD: "-fsanitize=local-bounds"
// RUN: %clang -fbounds-checking=3 -### -fsyntax-only %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-OLD2 < %t %s
-// CHECK-OLD2: "-fsanitize=bounds"
+// CHECK-OLD2: "-fsanitize=local-bounds"
diff --git a/test/Driver/ccc-add-args.c b/test/Driver/ccc-add-args.c
deleted file mode 100644
index d9a16cbfb460..000000000000
--- a/test/Driver/ccc-add-args.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: env CCC_ADD_ARGS="-ccc-echo,-ccc-print-options,,-v" %clang -### 2>&1 | FileCheck %s
-// CHECK: Option 0 - Name: "-ccc-echo", Values: {}
-// CHECK: Option 1 - Name: "-ccc-print-options", Values: {}
-// CHECK: Option 2 - Name: "-v", Values: {}
-// CHECK: Option 3 - Name: "-###", Values: {}
diff --git a/test/Driver/ccc-as-cpp.c b/test/Driver/ccc-as-cpp.c
index feead5191db1..6c004338eda7 100644
--- a/test/Driver/ccc-as-cpp.c
+++ b/test/Driver/ccc-as-cpp.c
@@ -1,6 +1,3 @@
-// REQUIRES: shell
-// RUN: ln -sf %clang %T/clang-cpp
-
// PR13529: Don't crash.
-// RUN: %T/clang-cpp -lfoo -M %s 2>&1 | FileCheck --check-prefix=CHECK-PR13529 %s
+// RUN: %clang_cpp -lfoo -M %s 2>&1 | FileCheck --check-prefix=CHECK-PR13529 %s
// CHECK-PR13529: warning: -lfoo: 'linker' input unused in cpp mode
diff --git a/test/Driver/cl-fallback.c b/test/Driver/cl-fallback.c
new file mode 100644
index 000000000000..2433072a0250
--- /dev/null
+++ b/test/Driver/cl-fallback.c
@@ -0,0 +1,41 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// 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 /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /LD /LDd \
+// RUN: /MD /MDd /MTd /MT /FImyheader.h -### -- %s 2>&1 | FileCheck %s
+// CHECK: "-fdiagnostics-format" "msvc-fallback"
+// CHECK: ||
+// CHECK: cl.exe
+// CHECK: "/nologo"
+// CHECK: "/c"
+// CHECK: "/W0"
+// CHECK: "-D" "foo=bar"
+// CHECK: "-U" "baz"
+// CHECK: "-I" "foo"
+// CHECK: "/Ox"
+// CHECK: "/GR-"
+// CHECK: "/FImyheader.h"
+// CHECK: "/LD"
+// CHECK: "/LDd"
+// CHECK: "/MT"
+// CHECK: "/Tc" "{{.*cl-fallback.c}}"
+// CHECK: "/Fo{{.*cl-fallback.*.obj}}"
+
+// RUN: %clang_cl /fallback /Od -### -- %s 2>&1 | FileCheck -check-prefix=O0 %s
+// O0: cl.exe
+// O0: "/Od"
+// RUN: %clang_cl /fallback /O1 -### -- %s 2>&1 | FileCheck -check-prefix=O1 %s
+// O1: cl.exe
+// O1: "-O1"
+// RUN: %clang_cl /fallback /O2 -### -- %s 2>&1 | FileCheck -check-prefix=O2 %s
+// O2: cl.exe
+// O2: "-O2"
+// RUN: %clang_cl /fallback /Os -### -- %s 2>&1 | FileCheck -check-prefix=Os %s
+// Os: cl.exe
+// Os: "-Os"
+// RUN: %clang_cl /fallback /Ox -### -- %s 2>&1 | FileCheck -check-prefix=Ox %s
+// Ox: cl.exe
+// Ox: "/Ox"
diff --git a/test/Driver/cl-inputs.c b/test/Driver/cl-inputs.c
new file mode 100644
index 000000000000..d6ee520257d5
--- /dev/null
+++ b/test/Driver/cl-inputs.c
@@ -0,0 +1,35 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// 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 /TC -### -- %s 2>&1 | FileCheck -check-prefix=TC %s
+// TC: "-x" "c"
+// TC-NOT: warning
+// TC-NOT: note
+
+// RUN: %clang_cl /TP -### -- %s 2>&1 | FileCheck -check-prefix=TP %s
+// TP: "-x" "c++"
+// TP-NOT: warning
+// TP-NOT: note
+
+// RUN: %clang_cl -### /Tc%s /TP -- %s 2>&1 | FileCheck -check-prefix=Tc %s
+// RUN: %clang_cl -### /TP /Tc%s -- %s 2>&1 | FileCheck -check-prefix=Tc %s
+// Tc: "-x" "c"
+// Tc: "-x" "c++"
+// Tc-NOT: warning
+// Tc-NOT: note
+
+// RUN: %clang_cl -### /Tp%s /TC -- %s 2>&1 | FileCheck -check-prefix=Tp %s
+// RUN: %clang_cl -### /TC /Tp%s -- %s 2>&1 | FileCheck -check-prefix=Tp %s
+// Tp: "-x" "c++"
+// Tp: "-x" "c"
+// Tp-NOT: warning
+// Tp-NOT: note
+
+// RUN: %clang_cl /TP /TC /TP -### -- %s 2>&1 | FileCheck -check-prefix=WARN %s
+// WARN: warning: overriding '/TP' option with '/TC'
+// WARN: warning: overriding '/TC' option with '/TP'
+// WARN: note: The last /TC or /TP option takes precedence over earlier instances
+// WARN-NOT: note
diff --git a/test/Driver/cl-link.c b/test/Driver/cl-link.c
new file mode 100644
index 000000000000..24e0702c8ab3
--- /dev/null
+++ b/test/Driver/cl-link.c
@@ -0,0 +1,33 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: %s must be preceded by -- or bound to another option, otherwise it may
+// be interpreted as a command-line option, e.g. on Mac where %s is commonly
+// under /Users.
+
+// RUN: %clang_cl /Tc%s -### /link foo bar baz 2>&1 | FileCheck --check-prefix=LINK %s
+// LINK: link.exe
+// LINK: "foo"
+// LINK: "bar"
+// LINK: "baz"
+
+// RUN: %clang_cl /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN %s
+// ASAN: link.exe
+// ASAN: "-debug"
+// ASAN: "-incremental:no"
+// ASAN: "{{.*}}clang_rt.asan-i386.lib"
+// ASAN: "{{.*}}cl-link{{.*}}.obj"
+
+// RUN: %clang_cl /LD -### /Tc%s 2>&1 | FileCheck --check-prefix=DLL %s
+// RUN: %clang_cl /LDd -### /Tc%s 2>&1 | FileCheck --check-prefix=DLL %s
+// DLL: link.exe
+// "-dll"
+
+// RUN: %clang_cl /LD /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-DLL %s
+// RUN: %clang_cl /LDd /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-DLL %s
+// ASAN-DLL: link.exe
+// ASAN-DLL: "-dll"
+// ASAN-DLL: "-debug"
+// ASAN-DLL: "-incremental:no"
+// ASAN-DLL: "{{.*}}clang_rt.asan_dll_thunk-i386.lib"
+// ASAN-DLL: "{{.*}}cl-link{{.*}}.obj"
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
new file mode 100644
index 000000000000..01032bb38eec
--- /dev/null
+++ b/test/Driver/cl-options.c
@@ -0,0 +1,238 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// 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.
+
+
+// Alias options:
+
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=C %s
+// C: -c
+
+// RUN: %clang_cl /Dfoo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
+// RUN: %clang_cl /D foo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
+// D: "-D" "foo=bar"
+
+// RTTI is on by default; just check that we don't error.
+// RUN: %clang_cl /Zs /GR -- %s 2>&1
+
+// RUN: %clang_cl /GR- -### -- %s 2>&1 | FileCheck -check-prefix=GR_ %s
+// GR_: -fno-rtti
+
+// RUN: %clang_cl /Imyincludedir -### -- %s 2>&1 | FileCheck -check-prefix=SLASH_I %s
+// RUN: %clang_cl /I myincludedir -### -- %s 2>&1 | FileCheck -check-prefix=SLASH_I %s
+// SLASH_I: "-I" "myincludedir"
+
+// RUN: %clang_cl /J -### -- %s 2>&1 | FileCheck -check-prefix=J %s
+// J: -fno-signed-char
+
+// RUN: %clang_cl /Ofoo -### -- %s 2>&1 | FileCheck -check-prefix=O %s
+// O: -Ofoo
+
+// RUN: %clang_cl /Ob0 -### -- %s 2>&1 | FileCheck -check-prefix=Ob0 %s
+// Ob0: -fno-inline
+
+// RUN: %clang_cl /Od -### -- %s 2>&1 | FileCheck -check-prefix=Od %s
+// Od: -O0
+
+// RUN: %clang_cl /Oi- /Oi -### -- %s 2>&1 | FileCheck -check-prefix=Oi %s
+// Oi-NOT: -fno-builtin
+
+// RUN: %clang_cl /Oi- -### -- %s 2>&1 | FileCheck -check-prefix=Oi_ %s
+// Oi_: -fno-builtin
+
+// RUN: %clang_cl /Os -### -- %s 2>&1 | FileCheck -check-prefix=Os %s
+// Os: -Os
+
+// RUN: %clang_cl /Ot -### -- %s 2>&1 | FileCheck -check-prefix=Ot %s
+// Ot: -O2
+
+// RUN: %clang_cl /Ox -### -- %s 2>&1 | FileCheck -check-prefix=Ox %s
+// Ox: -O3
+
+// RUN: %clang_cl /Zs /Oy -- %s 2>&1
+
+// RUN: %clang_cl /Oy- -### -- %s 2>&1 | FileCheck -check-prefix=Oy_ %s
+// Oy_: -mdisable-fp-elim
+
+// RUN: %clang_cl /P -### -- %s 2>&1 | FileCheck -check-prefix=P %s
+// P: -E
+
+// RUN: %clang_cl /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes %s
+// showIncludes: --show-includes
+
+// RUN: %clang_cl /Umymacro -### -- %s 2>&1 | FileCheck -check-prefix=U %s
+// RUN: %clang_cl /U mymacro -### -- %s 2>&1 | FileCheck -check-prefix=U %s
+// U: "-U" "mymacro"
+
+// RUN: %clang_cl /W0 -### -- %s 2>&1 | FileCheck -check-prefix=W0 %s
+// W0: -w
+
+// RUN: %clang_cl /W1 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// RUN: %clang_cl /W2 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// RUN: %clang_cl /W3 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// RUN: %clang_cl /W4 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// RUN: %clang_cl /Wall -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// W1: -Wall
+
+// RUN: %clang_cl /WX -### -- %s 2>&1 | FileCheck -check-prefix=WX %s
+// WX: -Werror
+
+// RUN: %clang_cl /WX- -### -- %s 2>&1 | FileCheck -check-prefix=WX_ %s
+// WX_: -Wno-error
+
+// RUN: %clang_cl /w -### -- %s 2>&1 | FileCheck -check-prefix=w %s
+// w: -w
+
+// RUN: %clang_cl /Zs -### -- %s 2>&1 | FileCheck -check-prefix=Zs %s
+// Zs: -fsyntax-only
+
+// RUN: %clang_cl /FIasdf.h -### -- %s 2>&1 | FileCheck -check-prefix=FI %s
+// FI: "-include" "asdf.h"
+
+// RUN: %clang_cl /FI asdf.h -### -- %s 2>&1 | FileCheck -check-prefix=FI_ %s
+// FI_: "-include" "asdf.h"
+
+// We forward any unrecognized -W diagnostic options to cc1.
+// RUN: %clang_cl -Wunused-pragmas -### -- %s 2>&1 | FileCheck -check-prefix=WJoined %s
+// WJoined: "-cc1"
+// WJoined: "-Wunused-pragmas"
+
+
+// Ignored options. Check that we don't get "unused during compilation" errors.
+// (/Zs is for syntax-only, /WX is for -Werror)
+// RUN: %clang_cl /Zs /WX \
+// RUN: /analyze- \
+// RUN: /errorReport:foo \
+// RUN: /FS \
+// RUN: /GF \
+// RUN: /GS- \
+// RUN: /kernel- \
+// RUN: /nologo \
+// RUN: /Ob1 \
+// RUN: /Ob2 \
+// RUN: /RTC1 \
+// RUN: /sdl \
+// RUN: /sdl- \
+// RUN: /vmg \
+// RUN: /w12345 \
+// RUN: /wd1234 \
+// RUN: /Zc:forScope \
+// RUN: /Zc:wchar_t \
+// RUN: -- %s
+
+// Ignored options and compile-only options are ignored for link jobs.
+// RUN: touch %t.obj
+// RUN: %clang_cl /nologo -### -- %t.obj 2>&1 | FileCheck -check-prefix=LINKUNUSED %s
+// RUN: %clang_cl /Dfoo -### -- %t.obj 2>&1 | FileCheck -check-prefix=LINKUNUSED %s
+// RUN: %clang_cl /MD -### -- %t.obj 2>&1 | FileCheck -check-prefix=LINKUNUSED %s
+// LINKUNUSED-NOT: argument unused during compilation
+
+// Support ignoring warnings about unused arguments.
+// RUN: %clang_cl /Abracadabra -Qunused-arguments -### -- %s 2>&1 | FileCheck -check-prefix=UNUSED %s
+// UNUSED-NOT: warning
+
+// Unsupported but parsed options. Check that we don't error on them.
+// (/Zs is for syntax-only)
+// RUN: %clang_cl /Zs \
+// RUN: /AIfoo \
+// RUN: /arch:sse2 \
+// RUN: /clr:pure \
+// RUN: /docname \
+// RUN: /E \
+// RUN: /EHsc \
+// RUN: /EP \
+// RUN: /F \
+// RUN: /FA \
+// RUN: /FAc \
+// RUN: /Fafilename \
+// RUN: /FAs \
+// RUN: /FAu \
+// RUN: /favor:blend \
+// RUN: /FC \
+// RUN: /Fdfoo \
+// RUN: /Fifoo \
+// RUN: /Fmfoo \
+// RUN: /FpDebug\main.pch \
+// RUN: /fp:precise \
+// RUN: /Frfoo \
+// RUN: /FRfoo \
+// RUN: /FU foo \
+// RUN: /Fx \
+// RUN: /G1 \
+// RUN: /G2 \
+// RUN: /GA \
+// RUN: /Gd \
+// RUN: /Ge \
+// RUN: /Gh \
+// RUN: /GH \
+// RUN: /GL \
+// RUN: /GL- \
+// RUN: /Gm \
+// RUN: /Gm- \
+// RUN: /Gr \
+// RUN: /GS \
+// RUN: /Gs1000 \
+// RUN: /GT \
+// RUN: /GX \
+// RUN: /Gy \
+// RUN: /Gy- \
+// RUN: /Gz \
+// RUN: /GZ \
+// RUN: /H \
+// RUN: /homeparams \
+// RUN: /hotpatch \
+// RUN: /kernel \
+// RUN: /LN \
+// RUN: /MP \
+// RUN: /o foo.obj \
+// RUN: /ofoo.obj \
+// RUN: /openmp \
+// RUN: /Qfast_transcendentals \
+// RUN: /QIfist \
+// RUN: /Qimprecise_fwaits \
+// RUN: /Qpar \
+// RUN: /Qvec-report:2 \
+// RUN: /u \
+// RUN: /V \
+// RUN: /vd2 \
+// RUN: /vmb \
+// RUN: /vmm \
+// RUN: /vms \
+// RUN: /vmv \
+// RUN: /volatile \
+// RUN: /wfoo \
+// RUN: /WL \
+// RUN: /Wp64 \
+// RUN: /X \
+// RUN: /Y- \
+// RUN: /Yc \
+// RUN: /Ycstdafx.h \
+// RUN: /Yd \
+// RUN: /Yl- \
+// RUN: /Ylfoo \
+// RUN: /Yustdafx.h \
+// RUN: /Z7 \
+// RUN: /Za \
+// RUN: /Zc:auto \
+// RUN: /Zc:wchar_t- \
+// RUN: /Ze \
+// RUN: /Zg \
+// RUN: /Zi \
+// RUN: /ZI \
+// RUN: /Zl \
+// RUN: /Zp \
+// RUN: /ZW:nostdlib \
+// RUN: -- %s 2>&1
+
+// We support -Xclang for forwarding options to cc1.
+// RUN: %clang_cl -Xclang hellocc1 -### -- %s 2>&1 | FileCheck -check-prefix=Xclang %s
+// Xclang: "-cc1"
+// Xclang: "hellocc1"
+
+// We support -m32 and -m64.
+// RUN: %clang_cl /Zs /WX -m32 -m64 -- %s
+
+
+void f() { }
diff --git a/test/Driver/cl-outputs.c b/test/Driver/cl-outputs.c
new file mode 100644
index 000000000000..2ceaa85471b1
--- /dev/null
+++ b/test/Driver/cl-outputs.c
@@ -0,0 +1,107 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// 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 /c -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULT %s
+// DEFAULT: "-o" "cl-outputs.obj"
+
+// RUN: %clang_cl /Foa -### -- %s 2>&1 | FileCheck -check-prefix=FoNAME %s
+// FoNAME: "-o" "a.obj"
+
+// RUN: %clang_cl /Foa.ext /Fob.ext -### -- %s 2>&1 | FileCheck -check-prefix=FoNAMEEXT %s
+// FoNAMEEXT: "-o" "b.ext"
+
+// RUN: %clang_cl /Fofoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FoDIR %s
+// FoDIR: "-o" "foo.dir{{[/\\]+}}cl-outputs.obj"
+
+// RUN: %clang_cl /Fofoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FoDIRNAME %s
+// FoDIRNAME: "-o" "foo.dir{{[/\\]+}}a.obj"
+
+// RUN: %clang_cl /Fofoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FoDIRNAMEEXT %s
+// FoDIRNAMEEXT: "-o" "foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /Fo.. -### -- %s 2>&1 | FileCheck -check-prefix=FoCRAZY %s
+// FoCRAZY: "-o" "..obj"
+
+// RUN: %clang_cl /Fo -### 2>&1 | FileCheck -check-prefix=FoMISSINGARG %s
+// FoMISSINGARG: error: argument to '/Fo' is missing (expected 1 value)
+
+// RUN: %clang_cl /Foa.obj -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEERROR %s
+// CHECK-MULTIPLESOURCEERROR: error: cannot specify '/Foa.obj' when compiling multiple source files
+
+// RUN: %clang_cl /Fomydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEOK %s
+// CHECK-MULTIPLESOURCEOK: "-o" "mydir{{[/\\]+}}cl-outputs.obj"
+
+
+// RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTEXE %s
+// DEFAULTEXE: cl-outputs.exe
+
+// RUN: %clang_cl /LD -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTDLL %s
+// RUN: %clang_cl /LDd -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTDLL %s
+// DEFAULTDLL: "-out:cl-outputs.dll"
+// DEFAULTDLL: "-implib:cl-outputs.lib"
+
+// RUN: %clang_cl /Fefoo -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXT %s
+// FeNOEXT: "-out:foo.exe"
+
+// RUN: %clang_cl /Fefoo /LD -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
+// RUN: %clang_cl /Fefoo /LDd -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
+// FeNOEXTDLL: "-out:foo.dll"
+// FeNOEXTDLL: "-implib:foo.lib"
+
+// RUN: %clang_cl /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXT %s
+// FeEXT: "-out:foo.ext"
+
+// RUN: %clang_cl /LD /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXTDLL %s
+// RUN: %clang_cl /LDd /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXTDLL %s
+// FeEXTDLL: "-out:foo.ext"
+// FeEXTDLL: "-implib:foo.lib"
+
+// RUN: %clang_cl /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIR %s
+// FeDIR: "-out:foo.dir{{[/\\]+}}cl-outputs.exe"
+
+// RUN: %clang_cl /LD /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRDLL %s
+// FeDIRDLL: "-out:foo.dir{{[/\\]+}}cl-outputs.dll"
+// FeDIRDLL: "-implib:foo.dir{{[/\\]+}}cl-outputs.lib"
+
+// RUN: %clang_cl /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAME %s
+// FeDIRNAME: "-out:foo.dir{{[/\\]+}}a.exe"
+
+// RUN: %clang_cl /LD /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEDLL %s
+// FeDIRNAMEDLL: "-out:foo.dir{{[/\\]+}}a.dll"
+// FeDIRNAMEDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
+
+// RUN: %clang_cl /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXT %s
+// FeDIRNAMEEXT: "-out:foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /LD /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXTDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXTDLL %s
+// FeDIRNAMEEXTDLL: "-out:foo.dir{{[/\\]+}}a.ext"
+// FeDIRNAMEEXTDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
+
+// RUN: %clang_cl /Fe -### 2>&1 | FileCheck -check-prefix=FeMISSINGARG %s
+// FeMISSINGARG: error: argument to '/Fe' is missing (expected 1 value)
+
+// RUN: %clang_cl /Fefoo /Febar -### -- %s 2>&1 | FileCheck -check-prefix=FeOVERRIDE %s
+// FeOVERRIDE: "-out:bar.exe"
+
+
+// RUN: %clang_cl /FA -### -- %s 2>&1 | FileCheck -check-prefix=FA %s
+// FA: "-o" "cl-outputs.asm"
+// RUN: %clang_cl /FA /Fafoo -### -- %s 2>&1 | FileCheck -check-prefix=FaNAME %s
+// RUN: %clang_cl /Fafoo -### -- %s 2>&1 | FileCheck -check-prefix=FaNAME %s
+// FaNAME: "-o" "foo.asm"
+// RUN: %clang_cl /FA /Faa.ext /Fab.ext -### -- %s 2>&1 | FileCheck -check-prefix=FaNAMEEXT %s
+// FaNAMEEXT: "-o" "b.ext"
+// RUN: %clang_cl /FA /Fafoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FaDIR %s
+// FaDIR: "-o" "foo.dir{{[/\\]+}}cl-outputs.asm"
+// RUN: %clang_cl /FA /Fafoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FaDIRNAME %s
+// FaDIRNAME: "-o" "foo.dir{{[/\\]+}}a.asm"
+// RUN: %clang_cl /FA /Fafoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FaDIRNAMEEXT %s
+// FaDIRNAMEEXT: "-o" "foo.dir{{[/\\]+}}a.ext"
+// RUN: %clang_cl /Faa.asm -### -- %s %s 2>&1 | FileCheck -check-prefix=FaMULTIPLESOURCE %s
+// FaMULTIPLESOURCE: error: cannot specify '/Faa.asm' when compiling multiple source files
diff --git a/test/Driver/cl-runtime-flags.c b/test/Driver/cl-runtime-flags.c
new file mode 100644
index 000000000000..8367531f9ccb
--- /dev/null
+++ b/test/Driver/cl-runtime-flags.c
@@ -0,0 +1,89 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// 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.
+
+// First check that regular clang doesn't do any of this stuff.
+// RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=CHECK-CLANG %s
+// CHECK-CLANG-NOT: "-D_DEBUG"
+// CHECK-CLANG-NOT: "-D_MT"
+// CHECK-CLANG-NOT: "-D_DLL"
+// CHECK-CLANG-NOT: --dependent-lib
+
+// RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s
+// RUN: %clang_cl -### /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s
+// CHECK-MT-NOT: "-D_DEBUG"
+// CHECK-MT: "-D_MT"
+// CHECK-MT-NOT: "-D_DLL"
+// CHECK-MT: "--dependent-lib=libcmt"
+// CHECK-MT: "--dependent-lib=oldnames"
+
+// RUN: %clang_cl -### /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
+// RUN: %clang_cl -### /LD /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
+// CHECK-MTd: "-D_DEBUG"
+// CHECK-MTd: "-D_MT"
+// CHECK-MTd-NOT: "-D_DLL"
+// CHECK-MTd: "--dependent-lib=libcmtd"
+// CHECK-MTd: "--dependent-lib=oldnames"
+
+// RUN: %clang_cl -### /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-MD %s
+// CHECK-MD-NOT: "-D_DEBUG"
+// CHECK-MD: "-D_MT"
+// CHECK-MD: "-D_DLL"
+// CHECK-MD: "--dependent-lib=msvcrt"
+// CHECK-MD: "--dependent-lib=oldnames"
+
+// RUN: %clang_cl -### /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MDd %s
+// CHECK-MDd: "-D_DEBUG"
+// CHECK-MDd: "-D_MT"
+// CHECK-MDd: "-D_DLL"
+// CHECK-MDd: "--dependent-lib=msvcrtd"
+// CHECK-MDd: "--dependent-lib=oldnames"
+
+// RUN: %clang_cl -### /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
+// RUN: %clang_cl -### /LD /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
+// CHECK-LD-NOT: "-D_DEBUG"
+// CHECK-LD: "-D_MT"
+// CHECK-LD-NOT: "-D_DLL"
+// CHECK-LD: "--dependent-lib=libcmt"
+
+// RUN: %clang_cl -### /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
+// RUN: %clang_cl -### /LDd /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
+// CHECK-LDd: "-D_DEBUG"
+// CHECK-LDd: "-D_MT"
+// CHECK-LDd-NOT: "-D_DLL"
+// CHECK-LDd: "--dependent-lib=libcmtd"
+
+// RUN: %clang_cl -### /LDd /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
+// RUN: %clang_cl -### /MT /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
+// CHECK-LDdMT: "-D_DEBUG"
+// CHECK-LDdMT: "-D_MT"
+// CHECK-LDdMT-NOT: "-D_DLL"
+// CHECK-LDdMT: "--dependent-lib=libcmt"
+
+// RUN: %clang_cl -### /LD /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
+// RUN: %clang_cl -### /MD /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
+// CHECK-LDMD-NOT: "-D_DEBUG"
+// CHECK-LDMD: "-D_MT"
+// CHECK-LDMD: "-D_DLL"
+// CHECK-LDMD: "--dependent-lib=msvcrt"
+
+// RUN: %clang_cl -### /LDd /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
+// RUN: %clang_cl -### /MD /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
+// CHECK-LDdMD: "-D_DEBUG"
+// CHECK-LDdMD: "-D_MT"
+// CHECK-LDdMD: "-D_DLL"
+// CHECK-LDdMD: "--dependent-lib=msvcrt"
+
+// RUN: %clang_cl -### /LD /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /MDd /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /LDd /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /MDd /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// CHECK-LDMDd: "-D_DEBUG"
+// CHECK-LDMDd: "-D_MT"
+// CHECK-LDMDd: "-D_DLL"
+// CHECK-LDMDd: "--dependent-lib=msvcrtd"
+
+// RUN: %clang_cl /MD /MT -### -- %s 2>&1 | FileCheck -check-prefix=MTOVERRIDE %s
+// MTOVERRIDE: "--dependent-lib=libcmt"
diff --git a/test/Driver/cl.c b/test/Driver/cl.c
new file mode 100644
index 000000000000..4fd406439797
--- /dev/null
+++ b/test/Driver/cl.c
@@ -0,0 +1,35 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: we have to quote the /? option, otherwise some shells will try to
+// expand the ? into a one-letter filename in the root directory, and make
+// the test fail is such a file or directory exists.
+
+// 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.
+
+// Check that clang-cl options are not available by default.
+// RUN: %clang -help | FileCheck %s -check-prefix=DEFAULT
+// DEFAULT-NOT: CL.EXE COMPATIBILITY OPTIONS
+// DEFAULT-NOT: {{/[?]}}
+// DEFAULT-NOT: /help
+// RUN: not %clang "/?"
+// RUN: not %clang -?
+// RUN: not %clang /help
+
+// Check that /? and /help are available as clang-cl options.
+// RUN: %clang_cl "/?" | FileCheck %s -check-prefix=CL
+// RUN: %clang_cl /help | FileCheck %s -check-prefix=CL
+// RUN: %clang_cl -help | FileCheck %s -check-prefix=CL
+// CL: CL.EXE COMPATIBILITY OPTIONS
+// CL: {{/[?]}}
+// CL: /help
+
+// Options which are not "core" clang options nor cl.exe compatible options
+// are not available in clang-cl.
+// DEFAULT: -fapple-kext
+// CL-NOT: -fapple-kext
+
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=COMPILE %s
+// COMPILE: "-cxx-abi" "microsoft"
+// COMPILE: "-fdiagnostics-format" "msvc"
diff --git a/test/Driver/clang-g-opts.c b/test/Driver/clang-g-opts.c
index f5d09fda3dd8..9ca1fd38e407 100644
--- a/test/Driver/clang-g-opts.c
+++ b/test/Driver/clang-g-opts.c
@@ -1,9 +1,16 @@
// RUN: %clang -### -S %s 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
-// RUN: %clang -### -S %s -g 2>&1 | FileCheck --check-prefix=CHECK-WITH-G %s
+// RUN: %clang -### -S %s -g -target x86_64-linux-gnu 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WITH-G %s
+// RUN: %clang -### -S %s -g -target x86_64-apple-darwin 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WITH-G-DARWIN %s
// RUN: %clang -### -S %s -g0 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
// RUN: %clang -### -S %s -g -g0 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
-// RUN: %clang -### -S %s -g0 -g 2>&1 | FileCheck --check-prefix=CHECK-WITH-G %s
+// RUN: %clang -### -S %s -g0 -g -target x86_64-linux-gnu 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WITH-G %s
+// RUN: %clang -### -S %s -g0 -g -target x86_64-apple-darwin 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WITH-G-DARWIN %s
// CHECK-WITHOUT-G-NOT: "-g"
// CHECK-WITH-G: "-g"
+// CHECK-WITH-G-DARWIN: "-gdwarf-2"
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index 3b2b7e81f916..09303841c34b 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -19,6 +19,10 @@
// RUN: FileCheck -check-prefix=CORE2 %s
// CORE2: "-target-cpu"
// CORE2: "core2"
+// RUN: %clang -target x86_64h-apple-darwin -### -S %s -o %t.s 2>&1 | \
+// RUN: FileCheck -check-prefix=AVX2 %s
+// AVX2: "-target-cpu"
+// AVX2: "core-avx2"
// RUN: %clang -target x86_64-apple-darwin10 -### -S %s -arch armv7 2>&1 | \
// RUN: FileCheck -check-prefix=ARMV7_DEFAULT %s
@@ -33,10 +37,10 @@
// RUN: -msoft-float 2>&1 | FileCheck -check-prefix=ARMV7_SOFTFLOAT %s
// ARMV7_SOFTFLOAT: clang
// ARMV7_SOFTFLOAT: "-cc1"
-// ARMV7_SOFTFLOAT: "-msoft-float"
-// ARMV7_SOFTFLOAT: "-mfloat-abi" "soft"
// ARMV7_SOFTFLOAT: "-target-feature"
// ARMV7_SOFTFLOAT: "-neon"
+// ARMV7_SOFTFLOAT: "-msoft-float"
+// ARMV7_SOFTFLOAT: "-mfloat-abi" "soft"
// ARMV7_SOFTFLOAT: "-x" "c"
// RUN: %clang -target x86_64-apple-darwin10 -### -S %s -arch armv7 \
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 5451945515a4..8bf53e5e6dc3 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -15,11 +15,11 @@
// CHECK-OPTIONS2: -fno-show-source-location
// RUN: %clang -### -S -Wwrite-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS1 %s
+// RUN: %clang -### -S -Weverything %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS1 %s
// WRITE-STRINGS1: -fconst-strings
// RUN: %clang -### -S -Wwrite-strings -Wno-write-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS2 %s
+// RUN: %clang -### -S -Wwrite-strings -w %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS2 %s
// WRITE-STRINGS2-NOT: -fconst-strings
-// RUN: %clang -### -S -Wwrite-strings -w %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS3 %s
-// WRITE-STRINGS3: -fconst-strings
// RUN: %clang -### -x c++ -c %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
// RUN: %clang -### -x c++ -c -Wdeprecated %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
@@ -37,6 +37,23 @@
// FP-CONTRACT-FAST-CHECK: -ffp-contract=fast
// FP-CONTRACT-OFF-CHECK: -ffp-contract=off
+// RUN: %clang -### -S -funroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-UNROLL-LOOPS %s
+// RUN: %clang -### -S -fno-unroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-UNROLL-LOOPS %s
+// RUN: %clang -### -S -fno-unroll-loops -funroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-UNROLL-LOOPS %s
+// RUN: %clang -### -S -funroll-loops -fno-unroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-UNROLL-LOOPS %s
+// CHECK-UNROLL-LOOPS: "-funroll-loops"
+// CHECK-NO-UNROLL-LOOPS: "-fno-unroll-loops"
+
+// RUN: %clang -### -S -freroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-REROLL-LOOPS %s
+// RUN: %clang -### -S -fno-reroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-REROLL-LOOPS %s
+// RUN: %clang -### -S -fno-reroll-loops -freroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-REROLL-LOOPS %s
+// RUN: %clang -### -S -freroll-loops -fno-reroll-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-REROLL-LOOPS %s
+// CHECK-REROLL-LOOPS: "-freroll-loops"
+// CHECK-NO-REROLL-LOOPS-NOT: "-freroll-loops"
+
+// 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 -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
// RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
// RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
@@ -45,6 +62,17 @@
// RUN: %clang -### -S -fno-tree-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
// RUN: %clang -### -S -fno-tree-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
// RUN: %clang -### -S -ftree-vectorize -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -O %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -O2 %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -Os %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -O3 %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -fno-vectorize -O3 %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -O1 -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -Ofast %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -O0 %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -O1 %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -Oz %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
// CHECK-VECTORIZE: "-vectorize-loops"
// CHECK-NO-VECTORIZE-NOT: "-vectorize-loops"
@@ -71,3 +99,49 @@
// CHECK-EXTENDED-IDENTIFIERS: "-cc1"
// CHECK-EXTENDED-IDENTIFIERS-NOT: "-fextended-identifiers"
// CHECK-NO-EXTENDED-IDENTIFIERS: error: unsupported option '-fno-extended-identifiers'
+
+// RUN: %clang -### -S -fno-pascal-strings -mpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-M-PASCAL-STRINGS %s
+// CHECK-M-PASCAL-STRINGS: "-fpascal-strings"
+
+// RUN: %clang -### -S -fpascal-strings -mno-pascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-NO-M-PASCAL-STRINGS %s
+// CHECK-NO-M-PASCAL-STRINGS-NOT: "-fpascal-strings"
+
+// RUN: %clang -### -S -O4 %s 2>&1 | FileCheck -check-prefix=CHECK-MAX-O %s
+// CHECK-MAX-O: warning: -O4 is equivalent to -O3
+// CHECK-MAX-O: -O3
+
+// RUN: %clang -S -O20 -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-O %s
+// CHECK-INVALID-O: warning: optimization level '-O20' is unsupported; using '-O3' instead
+
+// Test that we don't error on these.
+// RUN: %clang -### -S -Werror \
+// RUN: -falign-functions -falign-functions=2 -fno-align-functions \
+// RUN: -fasynchronous-unwind-tables -fno-asynchronous-unwind-tables \
+// RUN: -fbuiltin -fno-builtin \
+// RUN: -fdiagnostics-show-location=once \
+// RUN: -ffloat-store -fno-float-store \
+// RUN: -feliminate-unused-debug-types -fno-eliminate-unused-debug-types \
+// RUN: -fgcse -fno-gcse \
+// RUN: -fident -fno-ident \
+// RUN: -fimplicit-templates -fno-implicit-templates \
+// RUN: -fivopts -fno-ivopts \
+// RUN: -fnon-call-exceptions -fno-non-call-exceptions \
+// RUN: -fpermissive -fno-permissive \
+// RUN: -fprefetch-loop-arrays -fno-prefetch-loop-arrays \
+// RUN: -fprofile-correction -fno-profile-correction \
+// RUN: -fprofile-dir=bar \
+// RUN: -fprofile-use -fprofile-use=zed -fno-profile-use \
+// RUN: -fprofile-values -fno-profile-values \
+// RUN: -frounding-math -fno-rounding-math \
+// RUN: -fsee -fno-see \
+// RUN: -ftracer -fno-tracer \
+// RUN: -funroll-all-loops -fno-unroll-all-loops \
+// RUN: -fuse-ld=gold \
+// RUN: -fno-builtin-foobar \
+// RUN: -fno-builtin-strcat -fno-builtin-strcpy \
+// RUN: -fno-var-tracking \
+// RUN: -fno-unsigned-char \
+// RUN: -fno-signed-char \
+// RUN: -fstrength-reduce -fno-strength-reduce \
+// RUN: %s 2>&1 | FileCheck --check-prefix=IGNORE %s
+// IGNORE-NOT: error: unknown argument
diff --git a/test/Driver/color-diagnostics.c b/test/Driver/color-diagnostics.c
index deff5119a0f7..ebf614eeb1a3 100644
--- a/test/Driver/color-diagnostics.c
+++ b/test/Driver/color-diagnostics.c
@@ -1,53 +1,57 @@
// RUN: %clang -fcolor-diagnostics -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=CD %s
+// RUN: | FileCheck --check-prefix=CHECK-CD %s
// CHECK-CD: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fno-color-diagnostics -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=NCD %s
+// RUN: | FileCheck --check-prefix=CHECK-NCD %s
// CHECK-NCD-NOT: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fdiagnostics-color -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DC %s
+// RUN: | FileCheck --check-prefix=CHECK-DC %s
// CHECK-DC: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fno-diagnostics-color -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=NDC %s
+// RUN: | FileCheck --check-prefix=CHECK-NDC %s
// CHECK-NDC-NOT: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fdiagnostics-color=always -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DCE_A %s
+// RUN: | FileCheck --check-prefix=CHECK-DCE_A %s
// CHECK-DCE_A: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fdiagnostics-color=never -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DCE_N %s
+// RUN: | FileCheck --check-prefix=CHECK-DCE_N %s
// CHECK-DCE_N-NOT: clang{{.*}}" "-fcolor-diagnostics"
// The test doesn't run in a PTY, so "auto" defaults to off.
// RUN: %clang -fdiagnostics-color=auto -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DCE_AUTO %s
+// RUN: | FileCheck --check-prefix=CHECK-DCE_AUTO %s
// CHECK-DCE_AUTO-NOT: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fdiagnostics-color=foo -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DCE_FOO %s
+// RUN: | FileCheck --check-prefix=CHECK-DCE_FOO %s
// CHECK-DCE_FOO: error: the clang compiler does not support '-fdiagnostics-color=foo'
// Check that the last flag wins.
// RUN: %clang -fno-color-diagnostics -fdiagnostics-color -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=NCD_DC_S %s
+// RUN: | FileCheck --check-prefix=CHECK-NCD_DC_S %s
// CHECK-NCD_DC_S: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fcolor-diagnostics -fno-diagnostics-color -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=CD_NDC_S %s
+// RUN: | FileCheck --check-prefix=CHECK-CD_NDC_S %s
// CHECK-CD_NDC_S-NOT: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fdiagnostics-color -fno-color-diagnostics -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=DC_NCD_S %s
+// RUN: | FileCheck --check-prefix=CHECK-DC_NCD_S %s
// CHECK-DC_NCD_S-NOT: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fno-diagnostics-color -fcolor-diagnostics -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=NDC_CD_S %s
+// RUN: | FileCheck --check-prefix=CHECK-NDC_CD_S %s
// CHECK-NDC_CD_S: clang{{.*}}" "-fcolor-diagnostics"
// RUN: %clang -fcolor-diagnostics -fdiagnostics-color=auto -### -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=CD_DCE_AUTO_S %s
+// RUN: | FileCheck --check-prefix=CHECK-CD_DCE_AUTO_S %s
// CHECK-CD_DCE_AUTO_S-NOT: clang{{.*}}" "-fcolor-diagnostics"
+
+// RUN: %clang -fansi-escape-codes -### -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-AEC %s
+// CHECK-AEC: clang{{.*}}" "-fansi-escape-codes"
diff --git a/test/Driver/coverage-ld.c b/test/Driver/coverage-ld.c
new file mode 100644
index 000000000000..cbb7dd472410
--- /dev/null
+++ b/test/Driver/coverage-ld.c
@@ -0,0 +1,19 @@
+// Test coverage ld flags.
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux --coverage \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX-I386 %s
+//
+// CHECK-LINUX-I386: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-LINUX-I386: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-i386.a" {{.*}} "-lc"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux --coverage \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX-X86-64 %s
+//
+// CHECK-LINUX-X86-64: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-LINUX-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-x86_64.a" {{.*}} "-lc"
diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c
index 975e9a8a714f..95c57f238e0a 100644
--- a/test/Driver/crash-report.c
+++ b/test/Driver/crash-report.c
@@ -1,21 +1,29 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 %clang -fsyntax-only %s \
+// RUN: not env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 %clang -fsyntax-only %s \
// RUN: -F/tmp/ -I /tmp/ -idirafter /tmp/ -iquote /tmp/ -isystem /tmp/ \
// RUN: -iprefix /the/prefix -iwithprefix /tmp -iwithprefixbefore /tmp/ \
-// RUN: -internal-isystem /tmp/ -internal-externc-isystem /tmp/ \
+// RUN: -Xclang -internal-isystem -Xclang /tmp/ \
+// RUN: -Xclang -internal-externc-isystem -Xclang /tmp/ \
// RUN: -DFOO=BAR 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-*.c | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
// REQUIRES: crash-recovery
-// RUN: env FORCE_CLANG_DIAGNOSTICS_CRASH=1 %clang -fsyntax-only -x c /dev/null 2>&1 | FileCheck %s
+// because of the glob (*.c, *.sh)
+// REQUIRES: shell
+
+// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH=1 %clang -fsyntax-only -x c /dev/null 2>&1 | FileCheck %s
+
+// FIXME: Investigating. "fatal error: file 'nul' modified since it was first processed"
+// XFAIL: mingw32
#pragma clang __debug parser_crash
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
// CHECK-NEXT: note: diagnostic msg: {{.*}}.c
FOO
// CHECKSRC: FOO
+// CHECKSH: -cc1
// CHECKSH: -D "FOO=BAR"
// CHECKSH-NOT: -F/tmp/
// CHECKSH-NOT: -I /tmp/
diff --git a/test/Driver/cross-linux.c b/test/Driver/cross-linux.c
new file mode 100644
index 000000000000..3013d80f4c1e
--- /dev/null
+++ b/test/Driver/cross-linux.c
@@ -0,0 +1,95 @@
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
+// RUN: --target=i386-unknown-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-I386 %s
+// CHECK-I386: "-cc1" "-triple" "i386-unknown-linux-gnu"
+// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\}}as" "--32"
+// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf_i386"
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
+// RUN: --target=x86_64-unknown-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-X86-64 %s
+// CHECK-X86-64: "-cc1" "-triple" "x86_64-unknown-linux-gnu"
+// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}as" "--64"
+// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf_x86_64"
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
+// RUN: --target=x86_64-unknown-linux-gnu -m32 \
+// RUN: | FileCheck --check-prefix=CHECK-I386 %s
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
+// RUN: --target=i386-unknown-linux-gnu -m64 \
+// RUN: | FileCheck --check-prefix=CHECK-X86-64 %s
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
+// RUN: --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-MULTI32-I386 %s
+// CHECK-MULTI32-I386: "-cc1" "-triple" "i386-unknown-linux"
+// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--32"
+// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI32-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
+// CHECK-MULTI32-I386: "-m" "elf_i386"
+// CHECK-MULTI32-I386: "crti.o" "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]{{/|\\\\}}crtbegin.o"
+// CHECK-MULTI32-I386: "-L[[gcc_install]]"
+// CHECK-MULTI32-I386: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib/../lib32"
+// CHECK-MULTI32-I386: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib"
+// CHECK-MULTI32-I386: "-L[[sysroot]]/lib"
+// CHECK-MULTI32-I386: "-L[[sysroot]]/usr/lib"
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
+// RUN: --target=x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-MULTI32-X86-64 %s
+// CHECK-MULTI32-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
+// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--64"
+// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI32-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
+// CHECK-MULTI32-X86-64: "-m" "elf_x86_64"
+// CHECK-MULTI32-X86-64: "crti.o" "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]/64{{/|\\\\}}crtbegin.o"
+// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/64"
+// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib/../lib64"
+// CHECK-MULTI32-X86-64: "-L[[gcc_install]]"
+// CHECK-MULTI32-X86-64: "-L[[gcc_install]]/../../../../i386-unknown-linux/lib"
+// CHECK-MULTI32-X86-64: "-L[[sysroot]]/lib"
+// CHECK-MULTI32-X86-64: "-L[[sysroot]]/usr/lib"
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
+// RUN: --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-MULTI64-I386 %s
+// CHECK-MULTI64-I386: "-cc1" "-triple" "i386-unknown-linux"
+// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--32"
+// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI64-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
+// CHECK-MULTI64-I386: "-m" "elf_i386"
+// CHECK-MULTI64-I386: "crti.o" "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]/32{{/|\\\\}}crtbegin.o"
+// CHECK-MULTI64-I386: "-L[[gcc_install]]/32"
+// CHECK-MULTI64-I386: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib/../lib32"
+// CHECK-MULTI64-I386: "-L[[gcc_install]]"
+// CHECK-MULTI64-I386: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib"
+// CHECK-MULTI64-I386: "-L[[sysroot]]/lib"
+// CHECK-MULTI64-I386: "-L[[sysroot]]/usr/lib"
+//
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
+// RUN: --target=x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-MULTI64-X86-64 %s
+// CHECK-MULTI64-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
+// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--64"
+// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI64-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
+// CHECK-MULTI64-X86-64: "-m" "elf_x86_64"
+// CHECK-MULTI64-X86-64: "crti.o" "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]{{/|\\\\}}crtbegin.o"
+// CHECK-MULTI64-X86-64: "-L[[gcc_install]]"
+// CHECK-MULTI64-X86-64: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib/../lib64"
+// CHECK-MULTI64-X86-64: "-L[[gcc_install]]/../../../../x86_64-unknown-linux/lib"
+// CHECK-MULTI64-X86-64: "-L[[sysroot]]/lib"
+// CHECK-MULTI64-X86-64: "-L[[sysroot]]/usr/lib"
diff --git a/test/Driver/darwin-as.c b/test/Driver/darwin-as.c
index 92c76414a72b..58c850eb9b45 100644
--- a/test/Driver/darwin-as.c
+++ b/test/Driver/darwin-as.c
@@ -1,17 +1,17 @@
// RUN: %clang -target i386-apple-darwin10 -### -x assembler -c %s \
// RUN: -no-integrated-as -static -dynamic 2>%t
-// RUN: FileCheck -check-prefix=STATIC_AND_DYNAMIC-32 --input-file %t %s
+// RUN: FileCheck -check-prefix=CHECK-STATIC_AND_DYNAMIC-32 --input-file %t %s
//
-// CHECK-STATIC_AND_DYNAMIC-32: as{{(.exe)?}}" "-arch" "i386" "-force_cpusubtype_ALL" "-static" "-o"
+// CHECK-STATIC_AND_DYNAMIC-32: as{{(.exe)?}}" "-Q" "-arch" "i386" "-force_cpusubtype_ALL" "-static" "-o"
// RUN: %clang -target x86_64-apple-darwin10 -### -x assembler -c %s \
// RUN: -no-integrated-as -static 2>%t
-// RUN: FileCheck -check-prefix=STATIC-64 --input-file %t %s
+// RUN: FileCheck -check-prefix=CHECK-STATIC-64 --input-file %t %s
//
-// CHECK-STATIC-64: as{{(.exe)?}}" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o"
+// CHECK-STATIC-64: as{{(.exe)?}}" "-Q" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o"
// RUN: %clang -target x86_64-apple-darwin10 -### \
// RUN: -arch armv6 -no-integrated-as -x assembler -c %s 2>%t
-// RUN: FileCheck -check-prefix=ARMV6 --input-file %t %s
+// RUN: FileCheck -check-prefix=CHECK-ARMV6 --input-file %t %s
//
-// CHECK-ARMV6: as{{(.exe)?}}" "-arch" "armv6" "-o"
+// CHECK-ARMV6: as{{(.exe)?}}" "-Q" "-arch" "armv6" "-o"
diff --git a/test/Driver/darwin-dsymutil.c b/test/Driver/darwin-dsymutil.c
index 440986639a0a..b8c3083c9353 100644
--- a/test/Driver/darwin-dsymutil.c
+++ b/test/Driver/darwin-dsymutil.c
@@ -35,7 +35,7 @@
// RUN: touch %t.o
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -o foo %t.o -g 2> %t
-// RUN: grep "Dsymutil" %t | count 0
+// RUN: not grep "Dsymutil" %t
// Check that we put the .dSYM in the right place.
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
diff --git a/test/Driver/darwin-eabi.c b/test/Driver/darwin-eabi.c
new file mode 100644
index 000000000000..1288fa40608c
--- /dev/null
+++ b/test/Driver/darwin-eabi.c
@@ -0,0 +1,12 @@
+// RUN: %clang -arch armv7 -target thumbv7-apple-darwin-eabi -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-AAPCS
+// RUN: %clang -arch armv7s -target thumbv7-apple-ios -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-APCS
+// RUN: %clang -arch armv7s -target thumbv7-apple-darwin -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-APCS
+// RUN: %clang -arch armv6m -target thumbv7-apple-darwin -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-DARWIN-EABI
+// RUN: %clang -arch armv7m -target thumbv7-apple-darwin -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-DARWIN-EABI
+// RUN: %clang -arch armv7em -target thumbv7-apple-darwin -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-DARWIN-EABI
+
+// CHECK-DARWIN-EABI: "-triple" "{{thumbv[67]e?m}}-apple-darwin-eabi"
+// CHECK-IOS: "-triple" "thumbv7" "thumbv7-apple-ios
+
+// CHECK-AAPCS: "-target-abi" "aapcs"
+// CHECK-APCS: "-target-abi" "apcs-gnu"
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index cd511e034f13..d6c5170496ba 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -130,3 +130,17 @@
// RUN: FileCheck -check-prefix=LINK_PG %s < %t.log
// LINK_PG: -lgcrt1.o
// LINK_PG: -no_new_main
+
+// RUN: %clang -target x86_64-apple-darwin12 -rdynamic -### %t.o \
+// RUN: -mlinker-version=100 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_NO_EXPORT_DYNAMIC %s < %t.log
+// LINK_NO_EXPORT_DYNAMIC: {{ld(.exe)?"}}
+// LINK_NO_EXPORT_DYNAMIC-NOT: "-export_dynamic"
+
+// RUN: %clang -target x86_64-apple-darwin12 -rdynamic -### %t.o \
+// RUN: -mlinker-version=137 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_EXPORT_DYNAMIC %s < %t.log
+// LINK_EXPORT_DYNAMIC: {{ld(.exe)?"}}
+// LINK_EXPORT_DYNAMIC: "-export_dynamic"
+
+
diff --git a/test/Driver/darwin-objc-defaults.m b/test/Driver/darwin-objc-defaults.m
index 6265cfb41f10..1742deb1b12e 100644
--- a/test/Driver/darwin-objc-defaults.m
+++ b/test/Driver/darwin-objc-defaults.m
@@ -4,7 +4,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -mmacosx-version-min=10.5 2> %t
-// RUN: FileCheck --check-prefix CHECK-I386_OSX10_5 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-I386_OSX10_5 < %t %s
// CHECK-CHECK-I386_OSX10_5: "-cc1"
// CHECK-CHECK-I386_OSX10_5: -fobjc-runtime=macosx-fragile-10.5
@@ -13,7 +13,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -mmacosx-version-min=10.6 2> %t
-// RUN: FileCheck --check-prefix CHECK-I386_OSX10_6 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-I386_OSX10_6 < %t %s
// CHECK-CHECK-I386_OSX10_6: "-cc1"
// CHECK-CHECK-I386_OSX10_6: -fobjc-runtime=macosx-fragile-10.6
@@ -22,7 +22,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -miphoneos-version-min=3.0 2> %t
-// RUN: FileCheck --check-prefix CHECK-I386_IPHONE3_0 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-I386_IPHONE3_0 < %t %s
// CHECK-CHECK-I386_IPHONE3_0: "-cc1"
// CHECK-CHECK-I386_IPHONE3_0: -fobjc-runtime=ios-3.0
@@ -33,36 +33,33 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -mmacosx-version-min=10.5 2> %t
-// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_5 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-X86_64_OSX10_5 < %t %s
// CHECK-CHECK-X86_64_OSX10_5: "-cc1"
// CHECK-CHECK-X86_64_OSX10_5: -fobjc-runtime=macosx-10.5
-// CHECK-CHECK-X86_64_OSX10_5: -fobjc-dispatch-method=non-legacy
// CHECK-CHECK-X86_64_OSX10_5: darwin-objc-defaults
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -mmacosx-version-min=10.6 2> %t
-// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_6 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-X86_64_OSX10_6 < %t %s
// CHECK-CHECK-X86_64_OSX10_6: "-cc1"
// CHECK-CHECK-X86_64_OSX10_6: -fobjc-runtime=macosx-10.6
-// CHECK-CHECK-X86_64_OSX10_6: -fobjc-dispatch-method=mixed
// CHECK-CHECK-X86_64_OSX10_6: darwin-objc-defaults
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -miphoneos-version-min=3.0 2> %t
-// RUN: FileCheck --check-prefix CHECK-X86_64_IPHONE3_0 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-X86_64_IPHONE3_0 < %t %s
// CHECK-CHECK-X86_64_IPHONE3_0: "-cc1"
// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-runtime=ios-3.0
-// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-dispatch-method=mixed
// CHECK-CHECK-X86_64_IPHONE3_0: darwin-objc-defaults
// armv7
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -mmacosx-version-min=10.5 2> %t
-// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_5 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-ARMV7_OSX10_5 < %t %s
// CHECK-CHECK-ARMV7_OSX10_5: "-cc1"
// CHECK-CHECK-ARMV7_OSX10_5: -fobjc-runtime=macosx-10.5
@@ -71,7 +68,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -mmacosx-version-min=10.6 2> %t
-// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_6 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-ARMV7_OSX10_6 < %t %s
// CHECK-CHECK-ARMV7_OSX10_6: "-cc1"
// CHECK-CHECK-ARMV7_OSX10_6: -fobjc-runtime=macosx-10.6
@@ -80,7 +77,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -miphoneos-version-min=3.0 2> %t
-// RUN: FileCheck --check-prefix CHECK-ARMV7_IPHONE3_0 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-ARMV7_IPHONE3_0 < %t %s
// CHECK-CHECK-ARMV7_IPHONE3_0: "-cc1"
// CHECK-CHECK-ARMV7_IPHONE3_0: -fobjc-runtime=ios-3.0
diff --git a/test/Driver/darwin-objc-options.m b/test/Driver/darwin-objc-options.m
index 77501ab1b914..a90a12d733d6 100644
--- a/test/Driver/darwin-objc-options.m
+++ b/test/Driver/darwin-objc-options.m
@@ -2,7 +2,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -fobjc-abi-version=1 2> %t
-// RUN: FileCheck --check-prefix CHECK-X86_64_ABI1 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-X86_64_ABI1 < %t %s
// CHECK-CHECK-X86_64_ABI1: "-cc1"
// CHECK-CHECK-X86_64_ABI1: -fobjc-runtime=macosx-fragile-10.6.0
@@ -11,7 +11,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -fobjc-abi-version=2 2> %t
-// RUN: FileCheck --check-prefix CHECK-I386_ABI2 < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-I386_ABI2 < %t %s
// CHECK-CHECK-I386_ABI2: "-cc1"
// CHECK-CHECK-I386_ABI2: -fobjc-runtime=macosx-10.6.0
@@ -22,7 +22,7 @@
// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -fobjc-runtime=ios-5.0 2> %t
-// RUN: FileCheck --check-prefix CHECK-I386_IOS < %t %s
+// RUN: FileCheck --check-prefix CHECK-CHECK-I386_IOS < %t %s
// CHECK-CHECK-I386_IOS: "-cc1"
// CHECK-CHECK-I386_IOS: -fobjc-runtime=ios-5.0
diff --git a/test/Driver/darwin-sanitizer-ld.c b/test/Driver/darwin-sanitizer-ld.c
index 98b37e96fe2e..85cfb73c4a34 100644
--- a/test/Driver/darwin-sanitizer-ld.c
+++ b/test/Driver/darwin-sanitizer-ld.c
@@ -5,8 +5,16 @@
// RUN: | FileCheck --check-prefix=CHECK-ASAN %s
// CHECK-ASAN: "{{.*}}ld{{(.exe)?}}"
-// CHECK-ASAN: libclang_rt.asan_osx_dynamic.dylib"
// CHECK-ASAN: stdc++
+// CHECK-ASAN: libclang_rt.asan_osx_dynamic.dylib"
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fsanitize=address -mios-simulator-version-min=7.0 %s -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-IOSSIM %s
+
+// CHECK-ASAN-IOSSIM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN-IOSSIM: lc++
+// CHECK-ASAN-IOSSIM: libclang_rt.asan_iossim_dynamic.dylib"
// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
// RUN: -fPIC -shared -fsanitize=address %s -o %t.so 2>&1 \
@@ -14,10 +22,7 @@
// CHECK-DYN-ASAN: "{{.*}}ld{{(.exe)?}}"
// CHECK-DYN-ASAN: "-dylib"
-// CHECK-DYN-ASAN-NOT: libclang_rt.asan_osx_dynamic.dylib
-// CHECK-DYN-ASAN: "-undefined"
-// CHECK-DYN-ASAN: "dynamic_lookup"
-// CHECK-DYN-ASAN-NOT: libclang_rt.asan_osx_dynamic.dylib
+// CHECK-DYN-ASAN: libclang_rt.asan_osx_dynamic.dylib
// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
// RUN: -fsanitize=undefined %s -o %t.o 2>&1 \
diff --git a/test/Driver/darwin-verify-debug.c b/test/Driver/darwin-verify-debug.c
index 677419a20c5b..c419cef589d1 100644
--- a/test/Driver/darwin-verify-debug.c
+++ b/test/Driver/darwin-verify-debug.c
@@ -31,4 +31,4 @@
// RUN: touch %t.o
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -verify -o foo %t.o -g 2> %t
-// RUN: grep "Verify" %t | count 0
+// RUN: not grep "Verify" %t
diff --git a/test/Driver/debug-main-file.S b/test/Driver/debug-main-file.S
index 8c154a32df17..9127df09f3f3 100644
--- a/test/Driver/debug-main-file.S
+++ b/test/Driver/debug-main-file.S
@@ -1,4 +1,3 @@
-// REQUIRES: clang-driver
// RUN: %clang -### -c -save-temps -integrated-as -g %s 2>&1 \
// RUN: | FileCheck %s
diff --git a/test/Driver/debug-options-as.c b/test/Driver/debug-options-as.c
index 0b639b2959cb..74a544c1c4b0 100644
--- a/test/Driver/debug-options-as.c
+++ b/test/Driver/debug-options-as.c
@@ -1,6 +1,3 @@
-// cygming have not supported integrated-as yet.
-// REQUIRES: clang-driver
-//
// Check to make sure clang is somewhat picky about -g options.
// (Delived from debug-options.c)
// rdar://10383444
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index ca77abf9fd30..1f890b2e67f4 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -1,13 +1,33 @@
// Check to make sure clang is somewhat picky about -g options.
// rdar://10383444
-// RUN: %clang -### -c -g %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -g2 %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -g3 %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -ggdb %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -ggdb1 %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -ggdb3 %s 2>&1 | FileCheck -check-prefix=G %s
-// RUN: %clang -### -c -gdwarf-2 %s 2>&1 | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -g %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -g2 %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -g3 %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -ggdb %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -ggdb1 %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -ggdb3 %s -target x86_64-linux-gnu 2>&1 \
+ | FileCheck -check-prefix=G %s
+
+// RUN: %clang -### -c -g %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -g2 %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -g3 %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -ggdb %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -ggdb1 %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -ggdb3 %s -target x86_64-apple-darwin 2>&1 \
+ | FileCheck -check-prefix=G_DARWIN %s
+
+// RUN: %clang -### -c -gdwarf-2 %s 2>&1 | FileCheck -check-prefix=G_D2 %s
//
// RUN: %clang -### -c -gfoo %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -g -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
@@ -15,18 +35,29 @@
//
// RUN: %clang -### -c -gline-tables-only %s 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_ONLY %s
-// RUN: %clang -### -c -gline-tables-only -g %s 2>&1 \
+// RUN: %clang -### -c -gline-tables-only -g %s -target x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck -check-prefix=G_ONLY %s
+// RUN: %clang -### -c -gline-tables-only -g %s -target x86_64-apple-darwin 2>&1 \
+// RUN: | FileCheck -check-prefix=G_ONLY_DARWIN %s
// 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: | not grep "argument unused during compilation"
+// RUN: -gstrict-dwarf -gno-strict-dwarf -fdebug-types-section \
+// RUN: -fno-debug-types-section %s 2>&1 \
+// RUN: | FileCheck -check-prefix=GIGNORE %s
+//
+// RUN: %clang -### -c -ggnu-pubnames %s 2>&1 | FileCheck -check-prefix=GOPT %s
//
// G: "-cc1"
// G: "-g"
//
+// G_DARWIN: "-cc1"
+// G_DARWIN: "-gdwarf-2"
+//
+// G_D2: "-cc1"
+// G_D2: "-gdwarf-2"
+//
// G_NO: "-cc1"
// G_NO-NOT: "-g"
//
@@ -40,5 +71,14 @@
// G_ONLY: "-g"
// G_ONLY-NOT: "-gline-tables-only"
//
+// G_ONLY_DARWIN: "-cc1"
+// G_ONLY_DARWIN-NOT: "-gline-tables-only"
+// G_ONLY_DARWIN: "-gdwarf-2"
+// G_ONLY_DARWIN-NOT: "-gline-tables-only"
+//
// GLTO_NO: "-cc1"
// GLTO_NO-NOT: "-gline-tables-only"
+//
+// GIGNORE-NOT: "argument unused during compilation"
+//
+// GOPT: -generate-gnu-dwarf-pub-sections
diff --git a/test/Driver/debug-unsupported.c b/test/Driver/debug-unsupported.c
index acbd7673a321..1804a9cc51b5 100644
--- a/test/Driver/debug-unsupported.c
+++ b/test/Driver/debug-unsupported.c
@@ -1,13 +1,13 @@
-// RUN: %clang -c -gstabs %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gstabs+ %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gcoff %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gxcoff %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gxcoff+ %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gvms %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gstabs1 %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gcoff2 %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gxcoff3 %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gvms0 %s 2>&1 | FileCheck %s
-// RUN: %clang -c -gtoggle %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gstabs %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gstabs+ %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gcoff %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gxcoff %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gxcoff+ %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gvms %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gstabs1 %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gcoff2 %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gxcoff3 %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gvms0 %s 2>&1 | FileCheck %s
+// RUN: not %clang -c -gtoggle %s 2>&1 | FileCheck %s
//
// CHECK: error: unsupported option
diff --git a/test/Driver/dyld-prefix.c b/test/Driver/dyld-prefix.c
new file mode 100644
index 000000000000..317d64449da6
--- /dev/null
+++ b/test/Driver/dyld-prefix.c
@@ -0,0 +1,9 @@
+// REQUIRES: shell-preserves-root
+
+// RUN: touch %t.o
+
+// RUN: %clang -target i386-unknown-linux --dyld-prefix /foo -### %t.o 2>&1 | FileCheck --check-prefix=CHECK-32 %s
+// CHECK-32: "-dynamic-linker" "/foo/lib/ld-linux.so.2"
+
+// RUN: %clang -target x86_64-unknown-linux --dyld-prefix /foo -### %t.o 2>&1 | FileCheck --check-prefix=CHECK-64 %s
+// CHECK-64: "-dynamic-linker" "/foo/lib64/ld-linux-x86-64.so.2"
diff --git a/test/Driver/emit-llvm.c b/test/Driver/emit-llvm.c
deleted file mode 100644
index 76ea05926c96..000000000000
--- a/test/Driver/emit-llvm.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check that -O4 is only honored as the effective -O option.
-// <rdar://problem/7046672> clang/loader problem
-
-// RUN: %clang -ccc-print-phases -c -O4 -O0 %s 2> %t
-// RUN: FileCheck --check-prefix=O4_AND_O0 %s < %t
-
-// O4_AND_O0: 0: input, "{{.*}}", c
-// O4_AND_O0: 1: preprocessor, {0}, cpp-output
-// O4_AND_O0: 2: compiler, {1}, assembler
-// O4_AND_O0: 3: assembler, {2}, object
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index 91af2e1dce45..eba25c8fe85e 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -42,18 +42,14 @@
// CHECK-MATH-ERRNO: "-cc1"
// CHECK-MATH-ERRNO: "-fmath-errno"
//
-// RUN: %clang -### -fno-fast-math -fmath-errno -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH-MATH-ERRNO %s
-// CHECK-NO-FAST-MATH-MATH-ERRNO: "-cc1"
-// CHECK-NO-FAST-MATH-MATH-ERRNO: "-fmath-errno"
-//
-// RUN: %clang -### -fmath-errno -fno-fast-math -c %s 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO-NO-FAST-MATH %s
-// CHECK-MATH-ERRNO-NO-FAST-MATH: "-cc1"
-// CHECK-MATH-ERRNO-NO-FAST-MATH-NOT: "-fmath-errno"
-//
// RUN: %clang -### -fmath-errno -fno-math-errno -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// CHECK-NO-MATH-ERRNO: "-cc1"
+// CHECK-NO-MATH-ERRNO-NOT: "-fmath-errno"
+//
+// Target defaults for -fmath-errno (reusing the above checks).
+// RUN: %clang -### -target i686-unknown-linux -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
// RUN: %clang -### -target i686-apple-darwin -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
// RUN: %clang -### -target x86_64-unknown-freebsd -c %s 2>&1 \
@@ -64,8 +60,26 @@
// 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
-// CHECK-NO-MATH-ERRNO: "-cc1"
-// CHECK-NO-MATH-ERRNO-NOT: "-fmath-errno"
+//
+// Check that -ffast-math disables -fmath-errno, and -fno-fast-math merely
+// preserves the target default. Also check various flag set operations between
+// the two flags. (Resuses above checks.)
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// RUN: %clang -### -fmath-errno -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// RUN: %clang -### -ffast-math -fmath-errno -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
+// RUN: %clang -### -target i686-unknown-linux -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
+// RUN: %clang -### -target i686-unknown-linux -fno-math-errno -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
+// RUN: %clang -### -target i686-apple-darwin -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// RUN: %clang -### -target i686-apple-darwin -fno-math-errno -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// RUN: %clang -### -fno-fast-math -fno-math-errno -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
//
// RUN: %clang -### -fno-math-errno -fassociative-math -freciprocal-math \
// RUN: -fno-signed-zeros -fno-trapping-math -c %s 2>&1 \
diff --git a/test/Driver/fpack-struct.c b/test/Driver/fpack-struct.c
index cc75da5bc0f8..da98ae948b7b 100644
--- a/test/Driver/fpack-struct.c
+++ b/test/Driver/fpack-struct.c
@@ -1,7 +1,7 @@
// RUN: %clang -fpack-struct -### %s 2> %t
// RUN: FileCheck < %t %s
// RUN: %clang -fpack-struct=8 -### %s 2> %t
-// RUN: FileCheck < %t %s --check-prefix=EQ
+// RUN: FileCheck < %t %s --check-prefix=CHECK-EQ
// CHECK: "-cc1"
// CHECK: "-fpack-struct=1"
diff --git a/test/Driver/frame-pointer.c b/test/Driver/frame-pointer.c
index 6be395c59880..1d63f2c42920 100644
--- a/test/Driver/frame-pointer.c
+++ b/test/Driver/frame-pointer.c
@@ -11,6 +11,20 @@
// RUN: %clang -target x86_64-pc-linux -### -S -O3 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK3-64 %s
// RUN: %clang -target x86_64-pc-linux -### -S -Os %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECKs-64 %s
+// Trust the above to get the optimizations right, and just test other targets
+// that want this by default.
+// RUN: %clang -target s390x-pc-linux -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
+// RUN: %clang -target s390x-pc-linux -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+
+// RUN: %clang -target mips-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
+// RUN: %clang -target mips-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
+// RUN: %clang -target mipsel-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
+// RUN: %clang -target mipsel-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
+// RUN: %clang -target mips64-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
+// RUN: %clang -target mips64-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
+// RUN: %clang -target mips64el-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
+// RUN: %clang -target mips64el-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
+
// CHECK0-32: -mdisable-fp-elim
// CHECK1-32-NOT: -mdisable-fp-elim
// CHECK2-32-NOT: -mdisable-fp-elim
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index cc7244396176..d1d9ea8a5106 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -107,3 +107,7 @@
// CHECK-ARM-EABI-NOT: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions"
// CHECK-ARM-EABI: as{{.*}}" "-mfpu=softvfp" "-meabi=5"
// CHECK-ARM-EABI-NOT: as{{.*}}" "-matpcs"
+
+// RUN: %clang -target x86_64-pc-freebsd8 %s -### -flto -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LTO %s
+// CHECK-LTO: ld{{.*}}" "-plugin{{.*}}LLVMgold.so
diff --git a/test/Driver/freebsd.cc b/test/Driver/freebsd.cc
new file mode 100644
index 000000000000..dea3267233cc
--- /dev/null
+++ b/test/Driver/freebsd.cc
@@ -0,0 +1,6 @@
+// RUN: %clangxx %s -### -o %t.o -target amd64-unknown-freebsd10.0 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-TEN %s
+// RUN: %clangxx %s -### -o %t.o -target amd64-unknown-freebsd9.2 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NINE %s
+// CHECK-TEN: -lc++
+// CHECK-NINE: -lstdc++
diff --git a/test/Driver/fsanitize-blacklist.c b/test/Driver/fsanitize-blacklist.c
index 5327bc16a340..690bc877952a 100644
--- a/test/Driver/fsanitize-blacklist.c
+++ b/test/Driver/fsanitize-blacklist.c
@@ -1,18 +1,26 @@
// General blacklist usage.
-// RUN: %clang -fsanitize=address -fsanitize-blacklist=%s %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST
+
+// PR12920
+// REQUIRES: clang-driver, shell
+
+// RUN: echo "fun:foo" > %t.good
+// RUN: echo "badline" > %t.bad
+
+// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST
// CHECK-BLACKLIST: -fsanitize-blacklist
// Ignore -fsanitize-blacklist flag if there is no -fsanitize flag.
-// RUN: %clang -fsanitize-blacklist=%s %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE
+// RUN: %clang -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE
// CHECK-NO-SANITIZE-NOT: -fsanitize-blacklist
// Flag -fno-sanitize-blacklist wins if it is specified later.
-// RUN: %clang -fsanitize=address -fsanitize-blacklist=%s -fno-sanitize-blacklist %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-BLACKLIST
+// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.good -fno-sanitize-blacklist %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-BLACKLIST
// CHECK-NO-BLACKLIST-NOT: -fsanitize-blacklist
// Driver barks on unexisting blacklist files.
// RUN: %clang -fno-sanitize-blacklist -fsanitize-blacklist=unexisting.txt %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SUCH-FILE
// CHECK-NO-SUCH-FILE: error: no such file or directory: 'unexisting.txt'
-// PR12920
-// REQUIRES: clang-driver
+// Driver properly reports malformed blacklist files.
+// RUN: %clang -fsanitize=address -fsanitize-blacklist=%t.bad %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-BLACKLIST
+// CHECK-BAD-BLACKLIST: error: malformed sanitizer blacklist
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 0e7522b54837..2d079236f574 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -1,27 +1,33 @@
// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior %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|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|bounds|enum|bool),?){14}"}}
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool),?){14}"}}
// CHECK-UNDEFINED-TRAP: "-fsanitize-undefined-trap-on-error"
// 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|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|bounds|enum|bool),?){15}"}}
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){16}"}}
+
+// 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|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){15}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift),?){4}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -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|shift|unreachable|return|vla-bound|alignment|null|object-size|bounds),?){11}"}}
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|object-size|array-bounds),?){12}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address-full %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FULL
// CHECK-ASAN-FULL: "-fsanitize={{((address|init-order|use-after-return|use-after-scope),?){4}"}}
-// RUN: %clang -target x86_64-linux-gnu -fno-sanitize=init-order -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-IMPLIED-INIT-ORDER
-// CHECK-ASAN-IMPLIED-INIT-ORDER: "-fsanitize={{((address|init-order),?){2}"}}
+// RUN: %clang -target x86_64-linux-gnu -fno-sanitize=init-order,use-after-return -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-IMPLIED-INIT-ORDER-UAR
+// CHECK-ASAN-IMPLIED-INIT-ORDER-UAR: "-fsanitize={{((address|init-order|use-after-return),?){3}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize=init-order %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-NO-IMPLIED-INIT-ORDER
// CHECK-ASAN-NO-IMPLIED-INIT-ORDER-NOT: init-order
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize=use-after-return %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-NO-IMPLIED-UAR
+// CHECK-ASAN-NO-IMPLIED-UAR-NOT: use-after-return
+
// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fno-sanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NO-TRAP-ERROR
// CHECK-UNDEFINED-NO-TRAP-ERROR: '-fcatch-undefined-behavior' not allowed with '-fno-sanitize-undefined-trap-on-error'
@@ -50,6 +56,12 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory,thread -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANM-SANT
// CHECK-SANM-SANT: '-fsanitize=thread' not allowed with '-fsanitize=memory'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak,thread -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-SANT
+// CHECK-SANL-SANT: '-fsanitize=leak' not allowed with '-fsanitize=thread'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak,memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-SANM
+// CHECK-SANL-SANM: '-fsanitize=leak' not allowed with '-fsanitize=memory'
+
// RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
// CHECK-ASAN-TSAN: '-faddress-sanitizer' not allowed with '-fthread-sanitizer'
@@ -87,12 +99,12 @@
// OK
// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fthread-sanitizer -fno-thread-sanitizer -faddress-sanitizer -fno-address-sanitizer -fbounds-checking -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEPRECATED
-// CHECK-DEPRECATED: argument '-fcatch-undefined-behavior' is deprecated, use '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error' instead
-// CHECK-DEPRECATED: argument '-fthread-sanitizer' is deprecated, use '-fsanitize=thread' instead
-// CHECK-DEPRECATED: argument '-fno-thread-sanitizer' is deprecated, use '-fno-sanitize=thread' instead
-// CHECK-DEPRECATED: argument '-faddress-sanitizer' is deprecated, use '-fsanitize=address' instead
+// CHECK-DEPRECATED: argument '-fbounds-checking' is deprecated, use '-fsanitize=local-bounds' instead
// CHECK-DEPRECATED: argument '-fno-address-sanitizer' is deprecated, use '-fno-sanitize=address' instead
-// CHECK-DEPRECATED: argument '-fbounds-checking' is deprecated, use '-fsanitize=bounds' instead
+// CHECK-DEPRECATED: argument '-faddress-sanitizer' is deprecated, use '-fsanitize=address' instead
+// CHECK-DEPRECATED: argument '-fno-thread-sanitizer' is deprecated, use '-fno-sanitize=thread' instead
+// CHECK-DEPRECATED: argument '-fthread-sanitizer' is deprecated, use '-fsanitize=thread' instead
+// CHECK-DEPRECATED: argument '-fcatch-undefined-behavior' is deprecated, use '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error' instead
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-NO-PIE
// CHECK-TSAN-NO-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pie-level" "2"
@@ -114,6 +126,9 @@
// CHECK-ANDROID-ASAN-NO-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pie-level" "2"
// CHECK-ANDROID-ASAN-NO-PIE: "-pie"
+// RUN: %clang -target arm-linux-androideabi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-NO-ASAN
+// CHECK-ANDROID-NO-ASAN: "-mrelocation-model" "static"
+
// RUN: %clang -target arm-linux-androideabi -fsanitize=address -fsanitize-address-zero-base-shadow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-ASAN-ZERO-BASE
// CHECK-ANDROID-ASAN-ZERO-BASE-NOT: argument unused during compilation
@@ -127,3 +142,40 @@
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
// CHECK-RECOVER-NOT: sanitize-recover
// CHECK-NO-RECOVER: "-fno-sanitize-recover"
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL
+// CHECK-SANL: "-fsanitize=leak"
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA
+// CHECK-SANA-SANL-NO-SANA: "-fsanitize=leak"
+
+// RUN: %clang -target 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=zzz %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIAG1
+// CHECK-DIAG1: unsupported argument 'zzz' to option 'fsanitize='
+// CHECK-DIAG1-NOT: unsupported argument 'zzz' to option 'fsanitize='
+
+// RUN: %clang -target i686-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-X86
+// CHECK-MSAN-X86: error: unsupported option '-fsanitize=memory' for target 'i686--linux-gnu'
+
+// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-DARWIN
+// CHECK-MSAN-DARWIN: unsupported option '-fsanitize=memory' for target 'x86_64-apple-darwin10'
+
+// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=memory -fno-sanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-NOMSAN-DARWIN
+// CHECK-MSAN-NOMSAN-DARWIN-NOT: unsupported option
+
+// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=memory -fsanitize=thread,memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-TSAN-MSAN-DARWIN
+// CHECK-MSAN-TSAN-MSAN-DARWIN: unsupported option '-fsanitize=thread,memory' for target 'x86_64-apple-darwin10'
+// CHECK-MSAN-TSAN-MSAN-DARWIN-NOT: unsupported option
+
+// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=thread,memory -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-MSAN-MSAN-DARWIN
+// CHECK-TSAN-MSAN-MSAN-DARWIN: unsupported option '-fsanitize=memory' for target 'x86_64-apple-darwin10'
+// CHECK-TSAN-MSAN-MSAN-DARWIN: unsupported option '-fsanitize=thread' for target 'x86_64-apple-darwin10'
+// CHECK-TSAN-MSAN-MSAN-DARWIN-NOT: unsupported option
+
+// 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'
diff --git a/test/Driver/gcc-toolchain.cpp b/test/Driver/gcc-toolchain.cpp
index e122dac9b97d..aa0e078160ef 100644
--- a/test/Driver/gcc-toolchain.cpp
+++ b/test/Driver/gcc-toolchain.cpp
@@ -1,7 +1,13 @@
// Test that gcc-toolchain option is working correctly
//
// RUN: %clangxx -no-canonical-prefixes %s -### -o %t 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: --target=i386-unknown-linux \
+// RUN: --gcc-toolchain=%S/Inputs/ubuntu_11.04_multiarch_tree/usr \
+// RUN: | FileCheck %s
+//
+// Additionally check that the legacy spelling of the flag works.
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t 2>&1 \
+// RUN: --target=i386-unknown-linux \
// RUN: -gcc-toolchain %S/Inputs/ubuntu_11.04_multiarch_tree/usr \
// RUN: | FileCheck %s
//
@@ -18,6 +24,6 @@
// the same precise formatting of the path as the '-internal-system' flags
// above, so we just blanket wildcard match the 'crtbegin.o'.
// CHECK: "{{[^"]*}}ld{{(.exe)?}}"
-// CHECK: "{{[^"]*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK: "{{[^"]*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK: "-L[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5"
// CHECK: "-L[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../.."
diff --git a/test/Driver/gcc-version-debug.c b/test/Driver/gcc-version-debug.c
new file mode 100644
index 000000000000..ff38c2805238
--- /dev/null
+++ b/test/Driver/gcc-version-debug.c
@@ -0,0 +1,6 @@
+// RUN: %clang -v --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree 2>&1 | FileCheck %s
+
+// CHECK: Found candidate GCC installation: {{.*}}Inputs{{.}}debian_multiarch_tree{{.}}usr{{.}}lib{{.}}gcc{{.}}i686-linux-gnu{{.}}4.5
+// CHECK-NEXT: Found candidate GCC installation: {{.*}}Inputs{{.}}debian_multiarch_tree{{.}}usr{{.}}lib{{.}}gcc{{.}}x86_64-linux-gnu{{.}}4.5
+// CHECK-NEXT: Selected GCC installation: {{.*}}Inputs{{.}}debian_multiarch_tree{{.}}usr{{.}}lib{{.}}gcc{{.}}i686-linux-gnu{{.}}4.5
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index 8eead214feef..b9933d7fb376 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -1,13 +1,44 @@
// Check that we don't try to forward -Xclang or -mlinker-version to GCC.
+// PR12920 -- Check also we may not forward W_Group options to GCC.
//
// RUN: %clang -target powerpc-unknown-unknown \
-// RUN: -c %s \
+// RUN: %s \
+// RUN: -Wall -Wdocumentation \
// RUN: -Xclang foo-bar \
+// RUN: -march=x86_64 \
// RUN: -mlinker-version=10 -### 2> %t
// RUN: FileCheck < %t %s
//
-// CHECK: gcc{{.*}}"
+// clang-cc1
+// CHECK: "-Wall" "-Wdocumentation"
+// CHECK: "-o" "{{[^"]+}}.s"
+//
+// gcc-as
+// CHECK: gcc{{[^"]*}}"
+// CHECK-NOT: "-mlinker-version=10"
+// CHECK-NOT: "-Xclang"
+// CHECK-NOT: "foo-bar"
+// CHECK-NOT: "-Wall"
+// CHECK-NOT: "-Wdocumentation"
+// CHECK: -march
+// CHECK-NOT: "-mlinker-version=10"
+// CHECK-NOT: "-Xclang"
+// CHECK-NOT: "foo-bar"
+// CHECK-NOT: "-Wall"
+// CHECK-NOT: "-Wdocumentation"
+// CHECK: "-o" "{{[^"]+}}.o"
+//
+// gcc-ld
+// CHECK: gcc{{[^"]*}}"
+// CHECK-NOT: "-mlinker-version=10"
+// CHECK-NOT: "-Xclang"
+// CHECK-NOT: "foo-bar"
+// CHECK-NOT: "-Wall"
+// CHECK-NOT: "-Wdocumentation"
+// CHECK: -march
// CHECK-NOT: "-mlinker-version=10"
// CHECK-NOT: "-Xclang"
// CHECK-NOT: "foo-bar"
-// CHECK: gcc_forward
+// CHECK-NOT: "-Wall"
+// CHECK-NOT: "-Wdocumentation"
+// CHECK: "-o" "a.out"
diff --git a/test/Driver/gfortran.f90 b/test/Driver/gfortran.f90
new file mode 100644
index 000000000000..d531f59cd35b
--- /dev/null
+++ b/test/Driver/gfortran.f90
@@ -0,0 +1,244 @@
+! Test that Clang can forward all of the flags which are documented as
+! being supported by gfortran to GCC when falling back to GCC for
+! a fortran input file.
+!
+! RUN: %clang -no-canonical-prefixes -target i386-linux -### %s -o %t 2>&1 \
+! RUN: -Aquestion=answer \
+! RUN: -A-question=answer \
+! RUN: -C \
+! RUN: -CC \
+! RUN: -Dmacro \
+! RUN: -Dmacro=value \
+! RUN: -H \
+! RUN: -Isome/directory \
+! RUN: -Jsome/other/directory \
+! RUN: -P \
+! RUN: -Umacro \
+! RUN: -Waliasing \
+! RUN: -Walign-commons \
+! RUN: -Wall \
+! RUN: -Wampersand \
+! RUN: -Warray-bounds \
+! RUN: -Wc-binding-type \
+! RUN: -Wcharacter-truncation \
+! RUN: -Wconversion \
+! RUN: -Wfunction-elimination \
+! RUN: -Wimplicit-interface \
+! RUN: -Wimplicit-procedure \
+! RUN: -Wintrinsic-shadow \
+! RUN: -Wintrinsics-std \
+! RUN: -Wline-truncation \
+! RUN: -Wreal-q-constant \
+! RUN: -Wrealloc-lhs \
+! RUN: -Wsurprising \
+! RUN: -Wtabs \
+! RUN: -Wtarget-lifetime \
+! RUN: -Wunderflow \
+! RUN: -Wunused-parameter \
+! RUN: -cpp \
+! RUN: -dD \
+! RUN: -dI \
+! RUN: -dM \
+! RUN: -dN \
+! RUN: -dU \
+! RUN: -faggressive-function-elimination \
+! RUN: -falign-commons \
+! RUN: -fall-intrinsics \
+! RUN: -fautomatic \
+! RUN: -fbackslash \
+! RUN: -fbacktrace \
+! RUN: -fblas-matmul-limit=42 \
+! RUN: -fbounds-check \
+! RUN: -fcheck-array-temporaries \
+! RUN: -fcheck=all \
+! RUN: -fcoarray=none \
+! RUN: -fconvert=foobar \
+! RUN: -fcray-pointer \
+! RUN: -fd-lines-as-code \
+! RUN: -fd-lines-as-comments \
+! RUN: -fdefault-double-8 \
+! RUN: -fdefault-integer-8 \
+! RUN: -fdefault-real-8 \
+! RUN: -fdollar-ok \
+! RUN: -fdump-fortran-optimized \
+! RUN: -fdump-fortran-original \
+! RUN: -fdump-parse-tree \
+! RUN: -fexternal-blas \
+! RUN: -ff2c \
+! RUN: -ffixed-form \
+! RUN: -ffixed-line-length-42 \
+! RUN: -ffpe-trap=list \
+! RUN: -ffree-form \
+! RUN: -ffree-line-length-42 \
+! RUN: -ffrontend-optimize \
+! RUN: -fimplicit-none \
+! RUN: -finit-character=n \
+! RUN: -finit-integer=n \
+! RUN: -finit-local-zero \
+! RUN: -finit-logical=false \
+! RUN: -finit-real=zero \
+! RUN: -finteger-4-integer-8 \
+! RUN: -fintrinsic-modules-path \
+! RUN: -fmax-array-constructor=42 \
+! RUN: -fmax-errors=42 \
+! RUN: -fmax-identifier-length \
+! RUN: -fmax-stack-var-size=42 \
+! RUN: -fmax-subrecord-length=42 \
+! RUN: -fmodule-private \
+! RUN: -fopenmp \
+! RUN: -fpack-derived \
+! RUN: -fprotect-parens \
+! RUN: -frange-check \
+! RUN: -freal-4-real-10 \
+! RUN: -freal-4-real-16 \
+! RUN: -freal-4-real-8 \
+! RUN: -freal-8-real-10 \
+! RUN: -freal-8-real-16 \
+! RUN: -freal-8-real-4 \
+! RUN: -frealloc-lhs \
+! RUN: -frecord-marker=42 \
+! RUN: -frecursive \
+! RUN: -frepack-arrays \
+! RUN: -fsecond-underscore \
+! RUN: -fshort-enums \
+! RUN: -fsign-zero \
+! RUN: -fstack-arrays \
+! RUN: -fsyntax-only \
+! RUN: -funderscoring \
+! RUN: -fwhole-file \
+! RUN: -fworking-directory \
+! RUN: -imultilib \
+! RUN: -iprefix \
+! RUN: -iquote \
+! RUN: -isysroot \
+! RUN: -isystem \
+! RUN: -nocpp \
+! RUN: -nostdinc \
+! RUN: -pedantic \
+! RUN: -pedantic-errors \
+! RUN: -static-libgfortran \
+! RUN: -std=f90 \
+! RUN: -undef \
+! RUN: | FileCheck %s
+!
+! FIXME: Several of these shouldn't necessarily be rendered separately
+! when passing to GCC... Hopefully their driver handles this.
+!
+! CHECK: "-Aquestion=answer"
+! CHECK: "-A-question=answer"
+! CHECK: "-C"
+! CHECK: "-CC"
+! CHECK: "-D" "macro"
+! CHECK: "-D" "macro=value"
+! CHECK: "-H"
+! CHECK: "-I" "some/directory"
+! CHECK: "-Jsome/other/directory"
+! CHECK: "-P"
+! CHECK: "-U" "macro"
+! CHECK: "-Waliasing"
+! CHECK: "-Walign-commons"
+! CHECK: "-Wall"
+! CHECK: "-Wampersand"
+! CHECK: "-Warray-bounds"
+! CHECK: "-Wc-binding-type"
+! CHECK: "-Wcharacter-truncation"
+! CHECK: "-Wconversion"
+! CHECK: "-Wfunction-elimination"
+! CHECK: "-Wimplicit-interface"
+! CHECK: "-Wimplicit-procedure"
+! CHECK: "-Wintrinsic-shadow"
+! CHECK: "-Wintrinsics-std"
+! CHECK: "-Wline-truncation"
+! CHECK: "-Wreal-q-constant"
+! CHECK: "-Wrealloc-lhs"
+! CHECK: "-Wsurprising"
+! CHECK: "-Wtabs"
+! CHECK: "-Wtarget-lifetime"
+! CHECK: "-Wunderflow"
+! CHECK: "-Wunused-parameter"
+! CHECK: "-cpp"
+! CHECK: "-dD"
+! CHECK: "-dI"
+! CHECK: "-dM"
+! CHECK: "-dN"
+! CHECK: "-dU"
+! CHECK: "-faggressive-function-elimination"
+! CHECK: "-falign-commons"
+! CHECK: "-fall-intrinsics"
+! CHECK: "-fautomatic"
+! CHECK: "-fbackslash"
+! CHECK: "-fbacktrace"
+! CHECK: "-fblas-matmul-limit=42"
+! CHECK: "-fbounds-check"
+! CHECK: "-fcheck-array-temporaries"
+! CHECK: "-fcheck=all"
+! CHECK: "-fcoarray=none"
+! CHECK: "-fconvert=foobar"
+! CHECK: "-fcray-pointer"
+! CHECK: "-fd-lines-as-code"
+! CHECK: "-fd-lines-as-comments"
+! CHECK: "-fdefault-double-8"
+! CHECK: "-fdefault-integer-8"
+! CHECK: "-fdefault-real-8"
+! CHECK: "-fdollar-ok"
+! CHECK: "-fdump-fortran-optimized"
+! CHECK: "-fdump-fortran-original"
+! CHECK: "-fdump-parse-tree"
+! CHECK: "-fexternal-blas"
+! CHECK: "-ff2c"
+! CHECK: "-ffixed-form"
+! CHECK: "-ffixed-line-length-42"
+! CHECK: "-ffpe-trap=list"
+! CHECK: "-ffree-form"
+! CHECK: "-ffree-line-length-42"
+! CHECK: "-ffrontend-optimize"
+! CHECK: "-fimplicit-none"
+! CHECK: "-finit-character=n"
+! CHECK: "-finit-integer=n"
+! CHECK: "-finit-local-zero"
+! CHECK: "-finit-logical=false"
+! CHECK: "-finit-real=zero"
+! CHECK: "-finteger-4-integer-8"
+! CHECK: "-fintrinsic-modules-path"
+! CHECK: "-fmax-array-constructor=42"
+! CHECK: "-fmax-errors=42"
+! CHECK: "-fmax-identifier-length"
+! CHECK: "-fmax-stack-var-size=42"
+! CHECK: "-fmax-subrecord-length=42"
+! CHECK: "-fmodule-private"
+! CHECK: "-fopenmp"
+! CHECK: "-fpack-derived"
+! CHECK: "-fprotect-parens"
+! CHECK: "-frange-check"
+! CHECK: "-freal-4-real-10"
+! CHECK: "-freal-4-real-16"
+! CHECK: "-freal-4-real-8"
+! CHECK: "-freal-8-real-10"
+! CHECK: "-freal-8-real-16"
+! CHECK: "-freal-8-real-4"
+! CHECK: "-frealloc-lhs"
+! CHECK: "-frecord-marker=42"
+! CHECK: "-frecursive"
+! CHECK: "-frepack-arrays"
+! CHECK: "-fsecond-underscore"
+! CHECK: "-fshort-enums"
+! CHECK: "-fsign-zero"
+! CHECK: "-fstack-arrays"
+! CHECK: "-funderscoring"
+! CHECK: "-fwhole-file"
+! CHECK: "-fworking-directory"
+! CHECK: "-imultilib"
+! CHECK: "-iprefix"
+! CHECK: "-iquote"
+! CHECK: "-isysroot"
+! CHECK: "-isystem"
+! CHECK: "-nocpp"
+! CHECK: "-nostdinc"
+! CHECK: "-pedantic"
+! CHECK: "-pedantic-errors"
+! CHECK: "-static-libgfortran"
+! CHECK: "-std=f90"
+! CHECK: "-undef"
+!
+! Clang understands this one and orders it weirdly.
+! CHECK: "-fsyntax-only"
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 1a2650d16ebc..f60c61c9c355 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -11,17 +11,17 @@
// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK002 %s
-// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -nostdinc, -nostdlibinc, -nostdinc++
@@ -36,7 +36,7 @@
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -47,9 +47,9 @@
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
@@ -59,16 +59,16 @@
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdinc++ \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK006 %s
// CHECK006: "-cc1"
// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -march=<archname> -mcpu=<archname> -mv<number>
@@ -79,8 +79,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK007 %s
// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv3"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -88,8 +88,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK008 %s
// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv5"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -97,30 +97,30 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK009 %s
// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv2"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK010 %s
// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv4"
-// RUN: %clang -march=hexagonv2 -target hexagon-unknown-elf \
+// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: %clang -mcpu=hexagonv2 -target hexagon-unknown-elf \
+// RUN: not %clang -mcpu=hexagonv2 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: %clang -mv2 -target hexagon-unknown-elf \
+// RUN: not %clang -mv2 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
-// RUN: %clang -march=hexagonv3 -target hexagon-unknown-elf \
+// RUN: not %clang -march=hexagonv3 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: %clang -mcpu=hexagonv3 -target hexagon-unknown-elf \
+// RUN: not %clang -mcpu=hexagonv3 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: %clang -mv3 -target hexagon-unknown-elf \
+// RUN: not %clang -mv3 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
@@ -136,8 +136,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK011 %s
// CHECK011: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK011-NOT: "-static"
// CHECK011-NOT: "-shared"
// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -155,13 +155,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Defaults for C++
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK012 %s
// CHECK012: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK012-NOT: "-static"
// CHECK012-NOT: "-shared"
// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -186,8 +186,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK013 %s
// CHECK013: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
@@ -210,8 +210,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK014 %s
// CHECK014: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK014: "-static"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
@@ -231,8 +231,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK015 %s
// CHECK015: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK015: "-shared" "-call_shared"
// CHECK015-NOT: crt0_standalone.o
// CHECK015-NOT: crt0.o
@@ -261,8 +261,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK016 %s
// CHECK016: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK016: "-shared" "-call_shared" "-static"
// CHECK016-NOT: crt0_standalone.o
// CHECK016-NOT: crt0.o
@@ -287,14 +287,14 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -nostdlib, -nostartfiles, -nodefaultlibs
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdlib \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK017 %s
// CHECK017: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK017-NOT: crt0_standalone.o
// CHECK017-NOT: crt0.o
// CHECK017-NOT: init.o
@@ -313,14 +313,14 @@
// CHECK017-NOT: "--end-group"
// CHECK017-NOT: fini.o
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostartfiles \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK018 %s
// CHECK018: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK018-NOT: crt0_standalone.o
// CHECK018-NOT: crt0.o
// CHECK018-NOT: init.o
@@ -339,14 +339,14 @@
// CHECK018: "--end-group"
// CHECK018-NOT: fini.o
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nodefaultlibs \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK019 %s
// CHECK019: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
@@ -374,8 +374,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK020 %s
// CHECK020: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK020-NOT: "-static"
// CHECK020-NOT: "-shared"
// CHECK020-NOT: crt0_standalone.o
@@ -399,8 +399,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK021 %s
// CHECK021: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK021-NOT: "-static"
// CHECK021-NOT: "-shared"
// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -421,7 +421,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Other args to pass to linker
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -s \
// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
@@ -431,8 +431,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK022 %s
// CHECK022: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
@@ -459,9 +459,9 @@
// RUN: | FileCheck -check-prefix=CHECK023 %s
// CHECK023: "{{.*}}clang{{.*}}" "-cc1"
// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK023-NOT: "-G{{[0-9]+}}"
// RUN: %clang -### -target hexagon-unknown-elf \
@@ -477,16 +477,16 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -fPIC \
-// RUN: -msmall_data_threshold=8 \
+// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// CHECK024: "{{.*}}clang{{.*}}" "-cc1"
// CHECK024-NOT: "-mrelocation-model" "static"
// CHECK024: "-pic-level" "{{[12]}}"
// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK024: "-G0"
// RUN: %clang -### -target hexagon-unknown-elf \
@@ -507,9 +507,9 @@
// CHECK025: "{{.*}}clang{{.*}}" "-cc1"
// CHECK025: "-mrelocation-model" "static"
// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK025: "-G8"
// -----------------------------------------------------------------------------
@@ -521,8 +521,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK026 %s
// CHECK026: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK026: "-pie"
// RUN: %clang -### -target hexagon-unknown-elf \
@@ -531,8 +531,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK027 %s
// CHECK027: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK027-NOT: "-pie"
// -----------------------------------------------------------------------------
@@ -545,8 +545,8 @@
// CHECK028: "{{.*}}clang{{.*}}" "-cc1"
// CHECK028: "-mqdsp6-compat"
// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// -----------------------------------------------------------------------------
// Test Assembler related args
@@ -559,6 +559,6 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK029 %s
// CHECK029: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
index 3e66f354c443..f3d7e25aa9dc 100644
--- a/test/Driver/hexagon-toolchain.c
+++ b/test/Driver/hexagon-toolchain.c
@@ -11,17 +11,17 @@
// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK002 %s
-// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -nostdinc, -nostdlibinc, -nostdinc++
@@ -36,7 +36,7 @@
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -47,9 +47,9 @@
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
@@ -59,16 +59,16 @@
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdinc++ \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK006 %s
// CHECK006: "-cc1"
// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -march=<archname> -mcpu=<archname> -mv<number>
@@ -79,8 +79,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK007 %s
// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv3"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -88,8 +88,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK008 %s
// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv5"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
@@ -97,30 +97,30 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK009 %s
// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv2"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK010 %s
// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv4"
-// RUN: %clang -march=hexagonv2 -target hexagon-unknown-linux \
+// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: %clang -mcpu=hexagonv2 -target hexagon-unknown-linux \
+// RUN: not %clang -mcpu=hexagonv2 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: %clang -mv2 -target hexagon-unknown-linux \
+// RUN: not %clang -mv2 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
-// RUN: %clang -march=hexagonv3 -target hexagon-unknown-linux \
+// RUN: not %clang -march=hexagonv3 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: %clang -mcpu=hexagonv3 -target hexagon-unknown-linux \
+// RUN: not %clang -mcpu=hexagonv3 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: %clang -mv3 -target hexagon-unknown-linux \
+// RUN: not %clang -mv3 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
@@ -136,8 +136,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK011 %s
// CHECK011: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK011-NOT: "-static"
// CHECK011-NOT: "-shared"
// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -155,13 +155,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Defaults for C++
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK012 %s
// CHECK012: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK012-NOT: "-static"
// CHECK012-NOT: "-shared"
// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -186,8 +186,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK013 %s
// CHECK013: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
@@ -210,8 +210,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK014 %s
// CHECK014: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK014: "-static"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
@@ -231,8 +231,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK015 %s
// CHECK015: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK015: "-shared" "-call_shared"
// CHECK015-NOT: crt0_standalone.o
// CHECK015-NOT: crt0.o
@@ -261,8 +261,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK016 %s
// CHECK016: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK016: "-shared" "-call_shared" "-static"
// CHECK016-NOT: crt0_standalone.o
// CHECK016-NOT: crt0.o
@@ -287,14 +287,14 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -nostdlib, -nostartfiles, -nodefaultlibs
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostdlib \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK017 %s
// CHECK017: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK017-NOT: crt0_standalone.o
// CHECK017-NOT: crt0.o
// CHECK017-NOT: init.o
@@ -313,14 +313,14 @@
// CHECK017-NOT: "--end-group"
// CHECK017-NOT: fini.o
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nostartfiles \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK018 %s
// CHECK018: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK018-NOT: crt0_standalone.o
// CHECK018-NOT: crt0.o
// CHECK018-NOT: init.o
@@ -339,14 +339,14 @@
// CHECK018: "--end-group"
// CHECK018-NOT: fini.o
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -nodefaultlibs \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK019 %s
// CHECK019: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
@@ -374,8 +374,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK020 %s
// CHECK020: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK020-NOT: "-static"
// CHECK020-NOT: "-shared"
// CHECK020-NOT: crt0_standalone.o
@@ -399,8 +399,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK021 %s
// CHECK021: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK021-NOT: "-static"
// CHECK021-NOT: "-shared"
// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -421,7 +421,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Other args to pass to linker
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -s \
// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
@@ -431,8 +431,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK022 %s
// CHECK022: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
@@ -459,9 +459,9 @@
// RUN: | FileCheck -check-prefix=CHECK023 %s
// CHECK023: "{{.*}}clang{{.*}}" "-cc1"
// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK023-NOT: "-G{{[0-9]+}}"
// RUN: %clang -### -target hexagon-unknown-linux \
@@ -477,16 +477,16 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: -fPIC \
-// RUN: -msmall_data_threshold=8 \
+// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// CHECK024: "{{.*}}clang{{.*}}" "-cc1"
// CHECK024-NOT: "-mrelocation-model" "static"
// CHECK024: "-pic-level" "{{[12]}}"
// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK024: "-G0"
// RUN: %clang -### -target hexagon-unknown-linux \
@@ -507,9 +507,9 @@
// CHECK025: "{{.*}}clang{{.*}}" "-cc1"
// CHECK025: "-mrelocation-model" "static"
// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK025: "-G8"
// -----------------------------------------------------------------------------
@@ -521,8 +521,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK026 %s
// CHECK026: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK026: "-pie"
// RUN: %clang -### -target hexagon-unknown-linux \
@@ -531,8 +531,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK027 %s
// CHECK027: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// CHECK027-NOT: "-pie"
// -----------------------------------------------------------------------------
@@ -545,8 +545,8 @@
// CHECK028: "{{.*}}clang{{.*}}" "-cc1"
// CHECK028: "-mqdsp6-compat"
// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin/hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
// -----------------------------------------------------------------------------
// Test Assembler related args
@@ -559,6 +559,6 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK029 %s
// CHECK029: "{{.*}}clang{{.*}}" "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
diff --git a/test/Driver/ident_md.c b/test/Driver/ident_md.c
new file mode 100644
index 000000000000..d7da31707f04
--- /dev/null
+++ b/test/Driver/ident_md.c
@@ -0,0 +1,6 @@
+// RUN: %clang %s -emit-llvm -S -o - | FileCheck %s
+// Verify that clang version appears in the llvm.ident metadata.
+
+// CHECK: !llvm.ident = !{!0}
+// CHECK: !0 = metadata !{metadata !{{.*}}
+
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
index 2b54ecf7c150..f50ccae64217 100644
--- a/test/Driver/immediate-options.c
+++ b/test/Driver/immediate-options.c
@@ -1,6 +1,14 @@
-// RUN: %clang --help | grep isystem
-// RUN: %clang --help | not grep ast-dump
-// RUN: %clang --help | not grep ccc-cxx
-// RUN: %clang --help-hidden | grep ccc-cxx
-// RUN: %clang -dumpversion
-// RUN: %clang -print-search-dirs
+// RUN: %clang --help | FileCheck %s -check-prefix=HELP
+// HELP: isystem
+// HELP-NOT: ast-dump
+// HELP-NOT: driver-mode
+
+// RUN: %clang --help-hidden | FileCheck %s -check-prefix=HELP-HIDDEN
+// HELP-HIDDEN: driver-mode
+
+// RUN: %clang -dumpversion | FileCheck %s -check-prefix=DUMPVERSION
+// DUMPVERSION: 4.2.1
+
+// RUN: %clang -print-search-dirs | FileCheck %s -check-prefix=PRINT-SEARCH-DIRS
+// PRINT-SEARCH-DIRS: programs: ={{.*}}
+// PRINT-SEARCH-DIRS: libraries: ={{.*}}
diff --git a/test/Driver/inhibit-downstream-commands.c b/test/Driver/inhibit-downstream-commands.c
index 5e46708cfe89..ceb245e4f1c9 100644
--- a/test/Driver/inhibit-downstream-commands.c
+++ b/test/Driver/inhibit-downstream-commands.c
@@ -1,4 +1,4 @@
-// RUN: %clang -no-integrated-as %s 2>&1 | FileCheck %s
+// RUN: not %clang -no-integrated-as %s 2>&1 | FileCheck %s
// CHECK: error: unknown type name 'invalid'
// CHECK-NOT: clang: error: assembler command failed
// CHECK-NOT: clang: error: linker command failed
diff --git a/test/Driver/integrated-as.c b/test/Driver/integrated-as.c
index 2045e8b559c6..e73174e878f8 100644
--- a/test/Driver/integrated-as.c
+++ b/test/Driver/integrated-as.c
@@ -1,7 +1,4 @@
// RUN: %clang -### -c -save-temps -integrated-as %s 2>&1 | FileCheck %s
-// gcc is invoked instead of clang-cc1as with gcc-driver -save-temps.
-// REQUIRES: clang-driver
-
// CHECK: cc1as
-// CHECK: -relax-all
+// CHECK: -mrelax-all
diff --git a/test/Driver/integrated-as.s b/test/Driver/integrated-as.s
index d614418276b8..0843cf93457b 100644
--- a/test/Driver/integrated-as.s
+++ b/test/Driver/integrated-as.s
@@ -1,6 +1,33 @@
// RUN: %clang -### -c -integrated-as %s 2>&1 | FileCheck %s
-
-// REQUIRES: clang-driver
-
// CHECK: cc1as
// CHECK-NOT: -relax-all
+
+// RUN: %clang -### -c -integrated-as -Wa,-L %s 2>&1 | FileCheck --check-prefix=OPT_L %s
+// OPT_L: msave-temp-labels
+
+// RUN: not %clang -c -integrated-as -Wa,--compress-debug-sections %s 2>&1 | FileCheck --check-prefix=INVALID %s
+// INVALID: error: unsupported argument '--compress-debug-sections' to option 'Wa,'
+
+// RUN: %clang -### -target x86_64-linux-gnu -c -integrated-as %s -fsanitize=address 2>&1 %s | FileCheck --check-prefix=SANITIZE %s
+// SANITIZE: argument unused during compilation: '-fsanitize=address'
+
+// Test that -I params in -Wa, and -Xassembler args are passed to integrated assembler
+// RUN: %clang -### -c -integrated-as %s -Wa,-I,foo_dir 2>&1 %s | FileCheck --check-prefix=WA_INCLUDE1 %s
+// WA_INCLUDE1: cc1as
+// WA_INCLUDE1: "-I" "foo_dir"
+
+// RUN: %clang -### -c -integrated-as %s -Wa,-Ifoo_dir 2>&1 %s | FileCheck --check-prefix=WA_INCLUDE2 %s
+// WA_INCLUDE2: cc1as
+// WA_INCLUDE2: "-Ifoo_dir"
+
+// RUN: %clang -### -c -integrated-as %s -Wa,-I -Wa,foo_dir 2>&1 %s | FileCheck --check-prefix=WA_INCLUDE3 %s
+// WA_INCLUDE3: cc1as
+// WA_INCLUDE3: "-I" "foo_dir"
+
+// RUN: %clang -### -c -integrated-as %s -Xassembler -I -Xassembler foo_dir 2>&1 %s | FileCheck --check-prefix=XA_INCLUDE1 %s
+// XA_INCLUDE1: cc1as
+// XA_INCLUDE1: "-I" "foo_dir"
+
+// RUN: %clang -### -c -integrated-as %s -Xassembler -Ifoo_dir 2>&1 %s | FileCheck --check-prefix=XA_INCLUDE2 %s
+// XA_INCLUDE2: cc1as
+// XA_INCLUDE2: "-Ifoo_dir"
diff --git a/test/Driver/invalid-o-level.c b/test/Driver/invalid-o-level.c
deleted file mode 100644
index d5242c7ac066..000000000000
--- a/test/Driver/invalid-o-level.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: not %clang_cc1 %s -O900 2> %t.log
-// RUN: FileCheck %s -input-file=%t.log
-
-// CHECK: invalid value '900' in '-O900'
diff --git a/test/Driver/le32-toolchain.c b/test/Driver/le32-toolchain.c
new file mode 100644
index 000000000000..bab550262edd
--- /dev/null
+++ b/test/Driver/le32-toolchain.c
@@ -0,0 +1,4 @@
+// RUN: %clang -### -target le32-unknown-nacl %s 2>&1 | FileCheck -check-prefix=CHECK-DEFAULT %s
+
+// CHECK-DEFAULT: "-cc1" {{.*}} "-fno-math-builtin"
+
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
index 61388c5ca186..e029f667a192 100644
--- a/test/Driver/le32-unknown-nacl.cpp
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang -target le32-unknown-nacl -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target le32-unknown-nacl -### %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
// RUN: %clang -target le32-unknown-nacl %s -emit-llvm -S -c -o - | FileCheck %s
// RUN: %clang -target le32-unknown-nacl %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
-// ECHO: {{.*}} -cc1 {{.*}}le32-unknown-nacl.c
+// ECHO: {{.*}} "-cc1" {{.*}}le32-unknown-nacl.c
// Check platform defines
#include <stdarg.h>
diff --git a/test/Driver/linux-as.c b/test/Driver/linux-as.c
index b3265da23478..a449b7b65380 100644
--- a/test/Driver/linux-as.c
+++ b/test/Driver/linux-as.c
@@ -1,56 +1,70 @@
-// Check passing options to the assembler for ARM targets.
+// Check passing options to the assembler for various linux targets.
//
// RUN: %clang -target arm-linux -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM %s
// CHECK-ARM: as{{(.exe)?}}" "-mfloat-abi=soft"
//
// RUN: %clang -target arm-linux -mcpu=cortex-a8 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-MCPU %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-MCPU %s
// CHECK-ARM-MCPU: as{{(.exe)?}}" "-mfloat-abi=soft" "-mcpu=cortex-a8"
//
// RUN: %clang -target arm-linux -mfpu=neon -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-MFPU %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-MFPU %s
// CHECK-ARM-MFPU: as{{(.exe)?}}" "-mfloat-abi=soft" "-mfpu=neon"
//
// RUN: %clang -target arm-linux -march=armv7-a -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-MARCH %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-MARCH %s
// CHECK-ARM-MARCH: as{{(.exe)?}}" "-mfloat-abi=soft" "-march=armv7-a"
//
// RUN: %clang -target arm-linux -mcpu=cortex-a8 -mfpu=neon -march=armv7-a -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-ALL %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-ALL %s
// CHECK-ARM-ALL: as{{(.exe)?}}" "-mfloat-abi=soft" "-march=armv7-a" "-mcpu=cortex-a8" "-mfpu=neon"
//
// RUN: %clang -target armv7-linux -mcpu=cortex-a8 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-TARGET %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-TARGET %s
// CHECK-ARM-TARGET: as{{(.exe)?}}" "-mfpu=neon" "-mfloat-abi=soft" "-mcpu=cortex-a8"
//
+// RUN: %clang -target armv8-linux -mcpu=cortex-a53 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM-TARGET-V8 %s
+// CHECK-ARM-TARGET-V8: as{{(.exe)?}}" "-mfpu=crypto-neon-fp-armv8" "-mfloat-abi=soft" "-mcpu=cortex-a53"
+//
// RUN: %clang -target arm-linux -mfloat-abi=hard -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-MFLOAT-ABI %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-MFLOAT-ABI %s
// CHECK-ARM-MFLOAT-ABI: as{{(.exe)?}}" "-mfloat-abi=hard"
//
// RUN: %clang -target arm-linux-androideabi -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-ANDROID %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-ANDROID %s
// CHECK-ARM-ANDROID: as{{(.exe)?}}" "-mfloat-abi=soft"
//
// RUN: %clang -target arm-linux-androideabi -march=armv7-a -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-ANDROID-SOFTFP %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-ANDROID-SOFTFP %s
// CHECK-ARM-ANDROID-SOFTFP: as{{(.exe)?}}" "-mfloat-abi=softfp" "-march=armv7-a"
//
// RUN: %clang -target arm-linux-eabi -mhard-float -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-HARDFP %s
+// RUN: | FileCheck -check-prefix=CHECK-ARM-HARDFP %s
// CHECK-ARM-HARDFP: as{{(.exe)?}}" "-mfloat-abi=hard"
//
// RUN: %clang -target ppc-linux -mcpu=invalid-cpu -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=PPC-NO-MCPU %s
+// RUN: | FileCheck -check-prefix=CHECK-PPC-NO-MCPU %s
// CHECK-PPC-NO-MCPU-NOT: as{{.*}} "-mcpu=invalid-cpu"
+//
+// RUN: %clang -target s390x-linux -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-Z-DEFAULT-ARCH %s
+// CHECK-Z-DEFAULT-ARCH: as{{.*}} "-march=z10"
+//
+// RUN: %clang -target s390x-linux -march=z196 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-Z-ARCH-Z196 %s
+// CHECK-Z-ARCH-Z196: as{{.*}} "-march=z196"
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
index d09f5b27ae9d..8955ed71d3c2 100644
--- a/test/Driver/linux-header-search.cpp
+++ b/test/Driver/linux-header-search.cpp
@@ -12,7 +12,7 @@
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/i686-linux-gnu"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/backward"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-UBUNTU-11-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
//
@@ -26,11 +26,25 @@
// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/backward"
// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/x86_64-linux-gnu/c++/4.7"
// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-UBUNTU-13-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu"
// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target arm-linux-gnueabihf \
+// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-CROSS %s
+// CHECK-UBUNTU-13-04-CROSS: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-UBUNTU-13-04-CROSS: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/../../../../include/c++/4.7"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/../../../../include/c++/4.7/backward"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.7/../../../../include/arm-linux-gnueabihf/c++/4.7"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-UBUNTU-13-04-CROSS: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+//
// Test Ubuntu/Debian's new version of multiarch, with -m32.
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu -m32 \
@@ -55,7 +69,7 @@
// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../../include/c++/4.5/i686-linux-gnu"
// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../../include/c++/4.5/backward"
// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-DEBIAN-X86: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-X86: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/i386-linux-gnu"
// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
@@ -69,7 +83,7 @@
// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../../include/c++/4.5/x86_64-linux-gnu"
// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../../include/c++/4.5/backward"
// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-DEBIAN-X86-64: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu"
// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
@@ -83,7 +97,7 @@
// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../../include/c++/4.5/powerpc-linux-gnu"
// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../../include/c++/4.5/backward"
// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-DEBIAN-PPC: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/powerpc-linux-gnu"
// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
@@ -97,7 +111,36 @@
// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../../include/c++/4.5/powerpc64-linux-gnu"
// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../../include/c++/4.5/backward"
// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
-// CHECK-DEBIAN-PPC64: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/powerpc64-linux-gnu"
// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+//
+// Test Gentoo's weirdness both before and after they changed it in their GCC
+// 4.6.4 release.
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu \
+// RUN: --sysroot=%S/Inputs/gentoo_linux_gcc_4.6.2_tree \
+// RUN: | FileCheck --check-prefix=CHECK-GENTOO-4-6-2 %s
+// CHECK-GENTOO-4-6-2: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK-GENTOO-4-6-2: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-GENTOO-4-6-2: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4"
+// CHECK-GENTOO-4-6-2: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/x86_64-pc-linux-gnu"
+// CHECK-GENTOO-4-6-2: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4/backward"
+// CHECK-GENTOO-4-6-2: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-GENTOO-4-6-2: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
+// CHECK-GENTOO-4-6-2: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-GENTOO-4-6-2: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu \
+// RUN: --sysroot=%S/Inputs/gentoo_linux_gcc_4.6.4_tree \
+// RUN: | FileCheck --check-prefix=CHECK-GENTOO-4-6-4 %s
+// CHECK-GENTOO-4-6-4: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK-GENTOO-4-6-4: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-GENTOO-4-6-4: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6"
+// CHECK-GENTOO-4-6-4: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/x86_64-pc-linux-gnu"
+// CHECK-GENTOO-4-6-4: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.4/include/g++-v4.6/backward"
+// CHECK-GENTOO-4-6-4: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-GENTOO-4-6-4: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]}}{{/|\\\\}}include"
+// CHECK-GENTOO-4-6-4: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-GENTOO-4-6-4: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index ebac718b33b8..755fa04055e5 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -2,12 +2,12 @@
// sysroot to make these tests independent of the host system.
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
// CHECK-LD-32-NOT: warning:
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-LD-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-LD-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib"
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../.."
@@ -15,7 +15,7 @@
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: --target=x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
// CHECK-LD-64-NOT: warning:
@@ -23,7 +23,7 @@
// CHECK-LD-64: "--eh-frame-hdr"
// CHECK-LD-64: "-m" "elf_x86_64"
// CHECK-LD-64: "-dynamic-linker"
-// CHECK-LD-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-LD-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
@@ -34,7 +34,7 @@
// CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: --target=x86_64-unknown-linux \
// RUN: -static-libgcc \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s
@@ -43,7 +43,7 @@
// CHECK-LD-64-STATIC-LIBGCC: "--eh-frame-hdr"
// CHECK-LD-64-STATIC-LIBGCC: "-m" "elf_x86_64"
// CHECK-LD-64-STATIC-LIBGCC: "-dynamic-linker"
-// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
@@ -54,7 +54,7 @@
// CHECK-LD-64-STATIC-LIBGCC: "-lgcc" "-lgcc_eh"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: --target=x86_64-unknown-linux \
// RUN: -static \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
@@ -64,7 +64,7 @@
// CHECK-LD-64-STATIC: "-m" "elf_x86_64"
// CHECK-LD-64-STATIC-NOT: "-dynamic-linker"
// CHECK-LD-64-STATIC: "-static"
-// CHECK-LD-64-STATIC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o"
+// CHECK-LD-64-STATIC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbeginT.o"
// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
@@ -74,17 +74,17 @@
//
// Check that flags can be combined. The -static dominates.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: --target=x86_64-unknown-linux \
// RUN: -static-libgcc -static \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-32 %s
// CHECK-32-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-32-TO-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-32-TO-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib/../lib32"
// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../lib32"
@@ -96,11 +96,11 @@
// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m64 \
+// RUN: --target=i386-unknown-linux -m64 \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-64 %s
// CHECK-32-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-32-TO-64: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o"
+// CHECK-32-TO-64: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/64{{/|\\\\}}crtbegin.o"
// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/64"
// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib/../lib64"
// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../lib64"
@@ -113,11 +113,11 @@
// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -m64 \
+// RUN: --target=x86_64-unknown-linux -m64 \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-64 %s
// CHECK-64-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-64-TO-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-64-TO-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib64"
// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib64"
@@ -129,11 +129,11 @@
// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -m32 \
+// RUN: --target=x86_64-unknown-linux -m32 \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-32 %s
// CHECK-64-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-64-TO-32: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o"
+// CHECK-64-TO-32: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32{{/|\\\\}}crtbegin.o"
// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32"
// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib32"
// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib32"
@@ -146,12 +146,12 @@
// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -m32 \
-// RUN: -gcc-toolchain %S/Inputs/multilib_64bit_linux_tree/usr \
+// RUN: --target=x86_64-unknown-linux -m32 \
+// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-32-SYSROOT %s
// CHECK-64-TO-32-SYSROOT: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-64-TO-32-SYSROOT: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o"
+// CHECK-64-TO-32-SYSROOT: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32{{/|\\\\}}crtbegin.o"
// CHECK-64-TO-32-SYSROOT: "-L{{[^"]*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32"
// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/lib/../lib32"
// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib/../lib32"
@@ -160,67 +160,67 @@
// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-32 %s
// CHECK-INSTALL-DIR-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-INSTALL-DIR-32: "{{.*}}/Inputs/fake_install_tree/bin/../lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o"
+// CHECK-INSTALL-DIR-32: "{{.*}}/Inputs/fake_install_tree/bin/../lib/gcc/i386-unknown-linux/4.7.0{{/|\\\\}}crtbegin.o"
// CHECK-INSTALL-DIR-32: "-L{{.*}}/Inputs/fake_install_tree/bin/../lib/gcc/i386-unknown-linux/4.7.0"
//
// Check that with 64-bit builds, we don't actually use the install directory
// as its version of GCC is lower than our sysrooted version.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -m64 \
+// RUN: --target=x86_64-unknown-linux -m64 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-64 %s
// CHECK-INSTALL-DIR-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-INSTALL-DIR-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-INSTALL-DIR-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
// CHECK-INSTALL-DIR-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
//
// Check that we support unusual patch version formats, including missing that
// component.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing1/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION1 %s
// CHECK-GCC-VERSION1: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-GCC-VERSION1: "{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7/crtbegin.o"
+// CHECK-GCC-VERSION1: "{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7{{/|\\\\}}crtbegin.o"
// CHECK-GCC-VERSION1: "-L{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing2/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION2 %s
// CHECK-GCC-VERSION2: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-GCC-VERSION2: "{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o"
+// CHECK-GCC-VERSION2: "{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x{{/|\\\\}}crtbegin.o"
// CHECK-GCC-VERSION2: "-L{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing3/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION3 %s
// CHECK-GCC-VERSION3: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-GCC-VERSION3: "{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o"
+// CHECK-GCC-VERSION3: "{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5{{/|\\\\}}crtbegin.o"
// CHECK-GCC-VERSION3: "-L{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -m32 \
+// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing4/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION4 %s
// CHECK-GCC-VERSION4: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-GCC-VERSION4: "{{.*}}/Inputs/gcc_version_parsing4/bin/../lib/gcc/i386-unknown-linux/4.7.99/crtbegin.o"
+// CHECK-GCC-VERSION4: "{{.*}}/Inputs/gcc_version_parsing4/bin/../lib/gcc/i386-unknown-linux/4.7.99{{/|\\\\}}crtbegin.o"
// CHECK-GCC-VERSION4: "-L{{.*}}/Inputs/gcc_version_parsing4/bin/../lib/gcc/i386-unknown-linux/4.7.99"
//
// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
// CHECK-UBUNTU-11-04: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-UBUNTU-11-04: "{{.*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK-UBUNTU-11-04: "{{.*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5"
// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../i386-linux-gnu"
// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu"
@@ -230,60 +230,94 @@
//
// Check multi arch support on Ubuntu 12.04 LTS.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-unknown-linux-gnueabihf \
+// RUN: --target=arm-unknown-linux-gnueabihf \
// RUN: --sysroot=%S/Inputs/ubuntu_12.04_LTS_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-12-04-ARM-HF %s
// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf/crt1.o"
-// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf/crti.o"
-// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o"
+// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf{{/|\\\\}}crt1.o"
+// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf{{/|\\\\}}crti.o"
+// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3{{/|\\\\}}crtbegin.o"
// CHECK-UBUNTU-12-04-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabihf/4.6.3"
// CHECK-UBUNTU-12-04-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf"
// CHECK-UBUNTU-12-04-ARM-HF: "-L[[SYSROOT]]/lib/arm-linux-gnueabihf"
// CHECK-UBUNTU-12-04-ARM-HF: "-L[[SYSROOT]]/usr/lib/arm-linux-gnueabihf"
// CHECK-UBUNTU-12-04-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../.."
-// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o"
-// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf/crtn.o"
+// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3{{/|\\\\}}crtend.o"
+// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/../../../arm-linux-gnueabihf{{/|\\\\}}crtn.o"
+//
+// Check Ubuntu 13.10 on x86-64 targeting arm-linux-gnueabihf.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=arm-linux-gnueabihf \
+// RUN: --sysroot=%S/Inputs/x86-64_ubuntu_13.10 \
+// RUN: | FileCheck --check-prefix=CHECK-X86-64-UBUNTU-13-10-ARM-HF %s
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-dynamic-linker" "/lib/ld-linux-armhf.so.3"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8{{/|\\\\}}crtbegin.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-L[[SYSROOT]]/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-L[[SYSROOT]]/usr/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8{{/|\\\\}}crtend.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/lib/../lib{{/|\\\\}}crtn.o"
+//
+// Check Ubuntu 13.10 on x86-64 targeting arm-linux-gnueabi.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=arm-linux-gnueabi \
+// RUN: --sysroot=%S/Inputs/x86-64_ubuntu_13.10 \
+// RUN: | FileCheck --check-prefix=CHECK-X86-64-UBUNTU-13-10-ARM %s
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-dynamic-linker" "/lib/ld-linux.so.3"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/../../../../arm-linux-gnueabi/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/../../../../arm-linux-gnueabi/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabi/4.7{{/|\\\\}}crtbegin.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabi/4.7"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/../../../../arm-linux-gnueabi/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-L[[SYSROOT]]/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-L[[SYSROOT]]/usr/lib/../lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "-L[[SYSROOT]]/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/../../../../arm-linux-gnueabi/lib"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabi/4.7{{/|\\\\}}crtend.o"
+// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}/usr/lib/gcc-cross/arm-linux-gnueabi/4.7/../../../../arm-linux-gnueabi/lib/../lib{{/|\\\\}}crtn.o"
//
// Check fedora 18 on arm.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target armv7-unknown-linux-gnueabihf \
+// RUN: --target=armv7-unknown-linux-gnueabihf \
// RUN: --sysroot=%S/Inputs/fedora_18_tree \
// RUN: | FileCheck --check-prefix=CHECK-FEDORA-18-ARM-HF %s
// CHECK-FEDORA-18-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../crt1.o"
-// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../crti.o"
-// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/crtbegin.o"
+// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../../lib{{/|\\\\}}crt1.o"
+// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../../lib{{/|\\\\}}crti.o"
+// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2{{/|\\\\}}crtbegin.o"
// CHECK-FEDORA-18-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2"
-// CHECK-FEDORA-18-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../.."
-// CHECK-FEDORA-18-ARM-HF: "-L[[SYSROOT]]/lib"
-// CHECK-FEDORA-18-ARM-HF: "-L[[SYSROOT]]/usr/lib"
-// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/crtend.o"
-// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../crtn.o"
+// CHECK-FEDORA-18-ARM-HF: "-L[[SYSROOT]]/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../../lib"
+// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2{{/|\\\\}}crtend.o"
+// CHECK-FEDORA-18-ARM-HF: "{{.*}}/usr/lib/gcc/armv7hl-redhat-linux-gnueabi/4.7.2/../../../../lib{{/|\\\\}}crtn.o"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-unknown-linux-gnueabi \
+// RUN: --target=arm-unknown-linux-gnueabi \
// RUN: --sysroot=%S/Inputs/ubuntu_12.04_LTS_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-12-04-ARM %s
// CHECK-UBUNTU-12-04-ARM: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi/crt1.o"
-// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi/crti.o"
-// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o"
+// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi{{/|\\\\}}crt1.o"
+// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi{{/|\\\\}}crti.o"
+// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1{{/|\\\\}}crtbegin.o"
// CHECK-UBUNTU-12-04-ARM: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabi/4.6.1"
// CHECK-UBUNTU-12-04-ARM: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi"
// CHECK-UBUNTU-12-04-ARM: "-L[[SYSROOT]]/lib/arm-linux-gnueabi"
// CHECK-UBUNTU-12-04-ARM: "-L[[SYSROOT]]/usr/lib/arm-linux-gnueabi"
// CHECK-UBUNTU-12-04-ARM: "-L[[SYSROOT]]/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../.."
-// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o"
-// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi/crtn.o"
+// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1{{/|\\\\}}crtend.o"
+// CHECK-UBUNTU-12-04-ARM: "{{.*}}/usr/lib/gcc/arm-linux-gnueabi/4.6.1/../../../arm-linux-gnueabi{{/|\\\\}}crtn.o"
//
// Test the setup that shipped in SUSE 10.3 on ppc64.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target powerpc64-suse-linux \
+// RUN: --target=powerpc64-suse-linux \
// RUN: --sysroot=%S/Inputs/suse_10.3_ppc64_tree \
// RUN: | FileCheck --check-prefix=CHECK-SUSE-10-3-PPC64 %s
// CHECK-SUSE-10-3-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-SUSE-10-3-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o"
+// CHECK-SUSE-10-3-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64{{/|\\\\}}crtbegin.o"
// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64"
// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-suse-linux/4.1.2/../../../../lib64"
// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/lib/../lib64"
@@ -291,14 +325,14 @@
//
// Check dynamic-linker for different archs
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-gnueabi \
+// RUN: --target=arm-linux-gnueabi \
// RUN: | FileCheck --check-prefix=CHECK-ARM %s
// CHECK-ARM: "{{.*}}ld{{(.exe)?}}"
// CHECK-ARM: "-m" "armelf_linux_eabi"
// CHECK-ARM: "-dynamic-linker" "{{.*}}/lib/ld-linux.so.3"
//
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-gnueabihf \
+// RUN: --target=arm-linux-gnueabihf \
// RUN: | FileCheck --check-prefix=CHECK-ARM-HF %s
// CHECK-ARM-HF: "{{.*}}ld{{(.exe)?}}"
// CHECK-ARM-HF: "-m" "armelf_linux_eabi"
@@ -308,42 +342,42 @@
// and provide correct path to the dynamic linker and emulation mode when build
// for MIPS platforms.
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu \
+// RUN: --target=mips-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-MIPS %s
// CHECK-MIPS: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPS: "-m" "elf32btsmip"
// CHECK-MIPS: "-dynamic-linker" "{{.*}}/lib/ld.so.1"
// CHECK-MIPS-NOT: "--hash-style={{gnu|both}}"
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu \
+// RUN: --target=mipsel-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-MIPSEL %s
// CHECK-MIPSEL: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPSEL: "-m" "elf32ltsmip"
// CHECK-MIPSEL: "-dynamic-linker" "{{.*}}/lib/ld.so.1"
// CHECK-MIPSEL-NOT: "--hash-style={{gnu|both}}"
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu \
+// RUN: --target=mips64-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64 %s
// CHECK-MIPS64: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPS64: "-m" "elf64btsmip"
// CHECK-MIPS64: "-dynamic-linker" "{{.*}}/lib64/ld.so.1"
// CHECK-MIPS64-NOT: "--hash-style={{gnu|both}}"
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu \
+// RUN: --target=mips64el-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL %s
// CHECK-MIPS64EL: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPS64EL: "-m" "elf64ltsmip"
// CHECK-MIPS64EL: "-dynamic-linker" "{{.*}}/lib64/ld.so.1"
// CHECK-MIPS64EL-NOT: "--hash-style={{gnu|both}}"
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu -mabi=n32 \
+// RUN: --target=mips64-linux-gnu -mabi=n32 \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64-N32 %s
// CHECK-MIPS64-N32: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPS64-N32: "-m" "elf32btsmipn32"
// CHECK-MIPS64-N32: "-dynamic-linker" "{{.*}}/lib32/ld.so.1"
// CHECK-MIPS64-N32-NOT: "--hash-style={{gnu|both}}"
// RUN: %clang %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu -mabi=n32 \
+// RUN: --target=mips64el-linux-gnu -mabi=n32 \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL-N32 %s
// CHECK-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}"
// CHECK-MIPS64EL-N32: "-m" "elf32ltsmipn32"
@@ -352,11 +386,11 @@
//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i686-linux-gnu \
+// RUN: --target=i686-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86 %s
// CHECK-DEBIAN-X86: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-X86: "{{.*}}/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-X86: "{{.*}}/usr/lib/gcc/i686-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5"
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../i386-linux-gnu"
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu"
@@ -364,11 +398,11 @@
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-linux-gnu \
+// RUN: --target=x86_64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86-64 %s
// CHECK-DEBIAN-X86-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-X86-64: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-X86-64: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5"
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../x86_64-linux-gnu"
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu"
@@ -376,11 +410,11 @@
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target powerpc-linux-gnu \
+// RUN: --target=powerpc-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
// CHECK-DEBIAN-PPC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-PPC: "{{.*}}/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-PPC: "{{.*}}/usr/lib/gcc/powerpc-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5"
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../powerpc-linux-gnu"
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/powerpc-linux-gnu"
@@ -388,11 +422,11 @@
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target powerpc64-linux-gnu \
+// RUN: --target=powerpc64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
// CHECK-DEBIAN-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5"
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../powerpc64-linux-gnu"
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/powerpc64-linux-gnu"
@@ -400,11 +434,11 @@
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu \
+// RUN: --target=mips-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS %s
// CHECK-DEBIAN-MIPS: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPS: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-MIPS: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5"
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5/../../../mips-linux-gnu"
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/usr/lib/mips-linux-gnu"
@@ -412,11 +446,11 @@
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu \
+// RUN: --target=mipsel-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPSEL %s
// CHECK-DEBIAN-MIPSEL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5"
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5/../../../mipsel-linux-gnu"
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/usr/lib/mipsel-linux-gnu"
@@ -424,44 +458,44 @@
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu \
+// RUN: --target=mips64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64 %s
// CHECK-DEBIAN-MIPS64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPS64: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5/64/crtbegin.o"
+// CHECK-DEBIAN-MIPS64: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5/64{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5/64"
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5"
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5/../../.."
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu \
+// RUN: --target=mips64el-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64EL %s
// CHECK-DEBIAN-MIPS64EL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5/64/crtbegin.o"
+// CHECK-DEBIAN-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5/64{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5/64"
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5"
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5/../../.."
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu -mabi=n32 \
+// RUN: --target=mips64-linux-gnu -mabi=n32 \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64-N32 %s
// CHECK-DEBIAN-MIPS64-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPS64-N32: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5/n32/crtbegin.o"
+// CHECK-DEBIAN-MIPS64-N32: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.5/n32{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5/n32"
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5"
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/usr/lib/gcc/mips-linux-gnu/4.5/../../.."
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/lib"
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu -mabi=n32 \
+// RUN: --target=mips64el-linux-gnu -mabi=n32 \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64EL-N32 %s
// CHECK-DEBIAN-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5/n32/crtbegin.o"
+// CHECK-DEBIAN-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.5/n32{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5/n32"
// CHECK-DEBIAN-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5"
// CHECK-DEBIAN-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.5/../../.."
@@ -470,123 +504,123 @@
//
// Test linker invocation on Android.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi \
+// RUN: --target=arm-linux-androideabi \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-android \
+// RUN: --target=arm-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-android \
+// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-linux-android \
+// RUN: --target=i386-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-ANDROID: "{{.*}}/crtbegin_dynamic.o"
+// CHECK-ANDROID: "{{.*}}{{/|\\\\}}crtbegin_dynamic.o"
// CHECK-ANDROID: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-NOT: "gcc_s"
// CHECK-ANDROID: "-lgcc"
// CHECK-ANDROID: "-ldl"
// CHECK-ANDROID-NOT: "gcc_s"
-// CHECK-ANDROID: "{{.*}}/crtend_android.o"
+// CHECK-ANDROID: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi \
+// RUN: --target=arm-linux-androideabi \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-android \
+// RUN: --target=arm-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-android \
+// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-linux-android \
+// RUN: --target=i386-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// CHECK-ANDROID-SO: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-ANDROID-SO: "-Bsymbolic"
-// CHECK-ANDROID-SO: "{{.*}}/crtbegin_so.o"
+// CHECK-ANDROID-SO: "{{.*}}{{/|\\\\}}crtbegin_so.o"
// CHECK-ANDROID-SO: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-SO-NOT: "gcc_s"
// CHECK-ANDROID-SO: "-lgcc"
// CHECK-ANDROID-SO: "-ldl"
// CHECK-ANDROID-SO-NOT: "gcc_s"
-// CHECK-ANDROID-SO: "{{.*}}/crtend_so.o"
+// CHECK-ANDROID-SO: "{{.*}}{{/|\\\\}}crtend_so.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi \
+// RUN: --target=arm-linux-androideabi \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-android \
+// RUN: --target=arm-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-android \
+// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-linux-android \
+// RUN: --target=i386-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// CHECK-ANDROID-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-ANDROID-STATIC: "{{.*}}/crtbegin_static.o"
+// CHECK-ANDROID-STATIC: "{{.*}}{{/|\\\\}}crtbegin_static.o"
// CHECK-ANDROID-STATIC: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-STATIC-NOT: "gcc_s"
// CHECK-ANDROID-STATIC: "-lgcc"
// CHECK-ANDROID-STATIC-NOT: "-ldl"
// CHECK-ANDROID-STATIC-NOT: "gcc_s"
-// CHECK-ANDROID-STATIC: "{{.*}}/crtend_android.o"
+// CHECK-ANDROID-STATIC: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi \
+// RUN: --target=arm-linux-androideabi \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-android \
+// RUN: --target=arm-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-android \
+// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-linux-android \
+// RUN: --target=i386-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// CHECK-ANDROID-PIE: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-ANDROID-PIE: "{{.*}}/crtbegin_dynamic.o"
+// CHECK-ANDROID-PIE: "{{.*}}{{/|\\\\}}crtbegin_dynamic.o"
// CHECK-ANDROID-PIE: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-PIE-NOT: "gcc_s"
// CHECK-ANDROID-PIE: "-lgcc"
// CHECK-ANDROID-PIE-NOT: "gcc_s"
-// CHECK-ANDROID-PIE: "{{.*}}/crtend_android.o"
+// CHECK-ANDROID-PIE: "{{.*}}{{/|\\\\}}crtend_android.o"
//
// Check linker invocation on Debian 6 MIPS 32/64-bit.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu \
+// RUN: --target=mipsel-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPSEL %s
// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib/crt1.o"
-// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib/crti.o"
-// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o"
+// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib{{/|\\\\}}crt1.o"
+// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib{{/|\\\\}}crti.o"
+// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4"
// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib"
// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/lib/../lib"
@@ -596,13 +630,13 @@
// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu \
+// RUN: --target=mips64el-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64EL %s
// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib64/crt1.o"
-// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib64/crti.o"
-// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o"
+// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib64{{/|\\\\}}crt1.o"
+// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib64{{/|\\\\}}crti.o"
+// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/64{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/64"
// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib64"
// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/lib/../lib64"
@@ -612,13 +646,13 @@
// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu -mabi=n32 \
+// RUN: --target=mips64el-linux-gnu -mabi=n32 \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64EL-N32 %s
// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
-// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib32/crt1.o"
-// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib32/crti.o"
-// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib32{{/|\\\\}}crt1.o"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib32{{/|\\\\}}crti.o"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.4/n32{{/|\\\\}}crtbegin.o"
// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/n32"
// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../../../lib32"
// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/lib/../lib32"
@@ -629,41 +663,47 @@
//
// Test linker invocation for Freescale SDK (OpenEmbedded).
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target powerpc-fsl-linux \
+// RUN: --target=powerpc-fsl-linux \
// RUN: --sysroot=%S/Inputs/freescale_ppc_tree \
// RUN: | FileCheck --check-prefix=CHECK-FSL-PPC %s
// CHECK-FSL-PPC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-FSL-PPC: "-m" "elf32ppclinux"
-// CHECK-FSL-PPC: "{{.*}}/crt1.o"
-// CHECK-FSL-PPC: "{{.*}}/crtbegin.o"
+// CHECK-FSL-PPC: "{{.*}}{{/|\\\\}}crt1.o"
+// CHECK-FSL-PPC: "{{.*}}{{/|\\\\}}crtbegin.o"
// CHECK-FSL-PPC: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target powerpc64-fsl-linux \
+// RUN: --target=powerpc64-fsl-linux \
// RUN: --sysroot=%S/Inputs/freescale_ppc64_tree \
// RUN: | FileCheck --check-prefix=CHECK-FSL-PPC64 %s
// CHECK-FSL-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-FSL-PPC64: "-m" "elf64ppc"
-// CHECK-FSL-PPC64: "{{.*}}/crt1.o"
-// CHECK-FSL-PPC64: "{{.*}}/crtbegin.o"
+// CHECK-FSL-PPC64: "{{.*}}{{/|\\\\}}crt1.o"
+// CHECK-FSL-PPC64: "{{.*}}{{/|\\\\}}crtbegin.o"
// CHECK-FSL-PPC64: "-L[[SYSROOT]]/usr/lib64/powerpc64-fsl-linux/4.6.2/../.."
//
// Check that crtfastmath.o is linked with -ffast-math.
-// RUN: %clang -target x86_64-unknown-linux -### %s \
+// RUN: %clang --target=x86_64-unknown-linux -### %s \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
-// RUN: %clang -target x86_64-unknown-linux -### %s -ffast-math \
+// RUN: %clang --target=x86_64-unknown-linux -### %s -ffast-math \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
-// RUN: %clang -target x86_64-unknown-linux -### %s -funsafe-math-optimizations\
+// RUN: %clang --target=x86_64-unknown-linux -### %s -funsafe-math-optimizations\
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
-// RUN: %clang -target x86_64-unknown-linux -### %s -ffast-math -fno-fast-math \
+// RUN: %clang --target=x86_64-unknown-linux -### %s -ffast-math -fno-fast-math \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
// We don't have crtfastmath.o in the i386 tree, use it to check that file
// detection works.
-// RUN: %clang -target i386-unknown-linux -### %s -ffast-math \
+// RUN: %clang --target=i386-unknown-linux -### %s -ffast-math \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
-// CHECK-CRTFASTMATH: usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o
+// CHECK-CRTFASTMATH: usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtfastmath.o
// CHECK-NOCRTFASTMATH-NOT: crtfastmath.o
+
+// Check that we link in gcrt1.o when compiling with -pg
+// RUN: %clang -pg --target=x86_64-unknown-linux -### %s \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>& 1 \
+// RUN: | FileCheck --check-prefix=CHECK-PG %s
+// CHECK-PG: gcrt1.o
diff --git a/test/Driver/lit.local.cfg b/test/Driver/lit.local.cfg
index a62ea1a09983..d69e6ec1312c 100644
--- a/test/Driver/lit.local.cfg
+++ b/test/Driver/lit.local.cfg
@@ -1 +1,5 @@
-config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s']
+config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.f95']
+config.substitutions = list(config.substitutions)
+config.substitutions.insert(0,
+ ('%clang_cc1',
+ """*** Do not use 'clang -cc1' in Driver tests. ***""") )
diff --git a/test/Driver/lto.c b/test/Driver/lto.c
index 22b47882691d..91524bf78b1d 100644
--- a/test/Driver/lto.c
+++ b/test/Driver/lto.c
@@ -1,11 +1,8 @@
-// -emit-llvm, -flto, and -O4 all cause a switch to llvm-bc object files.
+// -flto causes a switch to llvm-bc object files.
// RUN: %clang -ccc-print-phases -c %s -flto 2> %t.log
// RUN: grep '2: compiler, {1}, lto-bc' %t.log
-// RUN: %clang -ccc-print-phases -c %s -O4 2> %t.log
-// RUN: grep '2: compiler, {1}, lto-bc' %t.log
-// and -emit-llvm doesn't alter pipeline (unfortunately?).
-// RUN: %clang -ccc-print-phases %s -emit-llvm 2> %t.log
+// RUN: %clang -ccc-print-phases %s -flto 2> %t.log
// RUN: grep '0: input, ".*lto.c", c' %t.log
// RUN: grep '1: preprocessor, {0}, cpp-output' %t.log
// RUN: grep '2: compiler, {1}, lto-bc' %t.log
@@ -13,11 +10,13 @@
// llvm-bc and llvm-ll outputs need to match regular suffixes
// (unfortunately).
-// RUN: %clang %s -emit-llvm -save-temps -### 2> %t.log
+// RUN: %clang %s -flto -save-temps -### 2> %t.log
// RUN: grep '"-o" ".*lto\.i" "-x" "c" ".*lto\.c"' %t.log
// RUN: grep '"-o" ".*lto\.o" .*".*lto\.i"' %t.log
// RUN: grep '".*a.out" .*".*lto\.o"' %t.log
-// RUN: %clang %s -emit-llvm -S -### 2> %t.log
+// RUN: %clang %s -flto -S -### 2> %t.log
// RUN: grep '"-o" ".*lto\.s" "-x" "c" ".*lto\.c"' %t.log
+// RUN: not %clang %s -emit-llvm 2>&1 | FileCheck --check-prefix=LLVM-LINK %s
+// LLVM-LINK: -emit-llvm cannot be used when linking
diff --git a/test/Driver/m_and_mm.c b/test/Driver/m_and_mm.c
index eab2a04986a9..18cf7abfa629 100644
--- a/test/Driver/m_and_mm.c
+++ b/test/Driver/m_and_mm.c
@@ -1,3 +1,3 @@
// RUN: %clang -### \
// RUN: -M -MM %s 2> %t
-// RUN: grep '"-sys-header-deps"' %t | count 0
+// RUN: not grep '"-sys-header-deps"' %t
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
index 216b65607e06..df925f1a17d4 100644
--- a/test/Driver/mips-as.c
+++ b/test/Driver/mips-as.c
@@ -115,3 +115,35 @@
// RUN: | FileCheck -check-prefix=MIPS-NDSPR2 %s
// MIPS-NDSPR2: as{{(.exe)?}}"
// MIPS-NDSPR2-NOT: "-mdspr2"
+//
+// RUN: %clang -target mips-linux-gnu -mnan=legacy -mnan=2008 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-NAN2008 %s
+// MIPS-NAN2008: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB" "-mnan=2008"
+//
+// RUN: %clang -target mips-linux-gnu -mnan=2008 -mnan=legacy -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-NAN-LEGACY %s
+// MIPS-NAN-LEGACY: as{{(.exe)?}}"
+// MIPS-NAN_LEGACY-NOT: "-mnan={{.*}}"
+//
+// RUN: %clang -target mips-linux-gnu -mfp64 -mfp32 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-MFP32 %s
+// MIPS-MFP32: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB" "-mfp32"
+//
+// RUN: %clang -target mips-linux-gnu -mfp32 -mfp64 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-MFP64 %s
+// MIPS-MFP64: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB" "-mfp64"
+//
+// RUN: %clang -target mips-linux-gnu -mno-msa -mmsa -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-MSA %s
+// MIPS-MSA: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB" "-mmsa"
+//
+// RUN: %clang -target mips-linux-gnu -mmsa -mno-msa -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-NMSA %s
+// MIPS-NMSA: as{{(.exe)?}}"
+// MIPS-NMSA-NOT: "-mmsa"
diff --git a/test/Driver/mips-cs-header-search.cpp b/test/Driver/mips-cs-header-search.cpp
index e59fadca585c..5538031670db 100644
--- a/test/Driver/mips-cs-header-search.cpp
+++ b/test/Driver/mips-cs-header-search.cpp
@@ -2,8 +2,8 @@
//
// = Big-endian, hard float
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32 %s
// CHECK-BE-HF-32: "-internal-isystem"
// CHECK-BE-HF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -18,8 +18,8 @@
//
// = Big-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-16 %s
// CHECK-BE-HF-16: "-internal-isystem"
// CHECK-BE-HF-16: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -34,8 +34,8 @@
//
// = Big-endian, hard float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-MICRO %s
// CHECK-BE-HF-MICRO: "-internal-isystem"
// CHECK-BE-HF-MICRO: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -50,8 +50,8 @@
//
// = Big-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-32 %s
// CHECK-BE-SF-32: "-internal-isystem"
// CHECK-BE-SF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -66,8 +66,8 @@
//
// = Big-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-16 %s
// CHECK-BE-SF-16: "-internal-isystem"
// CHECK-BE-SF-16: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -82,8 +82,8 @@
//
// = Big-endian, soft float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-MICRO %s
// CHECK-BE-SF-MICRO: "-internal-isystem"
// CHECK-BE-SF-MICRO: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -98,8 +98,8 @@
//
// = Big-endian, hard float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64 %s
// CHECK-BE-HF-64: "-internal-isystem"
// CHECK-BE-HF-64: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -114,8 +114,8 @@
//
// = Big-endian, soft float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64 %s
// CHECK-BE-SF-64: "-internal-isystem"
// CHECK-BE-SF-64: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -130,8 +130,8 @@
//
// = Little-endian, hard float
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mhard-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-32 %s
// CHECK-EL-HF-32: "-internal-isystem"
// CHECK-EL-HF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -146,8 +146,8 @@
//
// = Little-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-16 %s
// CHECK-EL-HF-16: "-internal-isystem"
// CHECK-EL-HF-16: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -162,8 +162,8 @@
//
// = Little-endian, hard float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-MICRO %s
// CHECK-EL-HF-MICRO: "-internal-isystem"
// CHECK-EL-HF-MICRO: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -178,8 +178,8 @@
//
// = Little-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mfloat-abi=soft \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mfloat-abi=soft \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-32 %s
// CHECK-EL-SF-32: "-internal-isystem"
// CHECK-EL-SF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -194,8 +194,8 @@
//
// = Little-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mips16 -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-16 %s
// CHECK-EL-SF-16: "-internal-isystem"
// CHECK-EL-SF-16: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -210,8 +210,8 @@
//
// = Little-endian, soft float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mmicromips -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mmicromips -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-MICRO %s
// CHECK-EL-SF-MICRO: "-internal-isystem"
// CHECK-EL-SF-MICRO: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -226,8 +226,8 @@
//
// = Little-endian, hard float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64el-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64 %s
// CHECK-EL-HF-64: "-internal-isystem"
// CHECK-EL-HF-64: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
@@ -242,8 +242,8 @@
//
// = Little-endian, soft float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -c -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64el-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64 %s
// CHECK-EL-SF-64: "-internal-isystem"
// CHECK-EL-SF-64: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
diff --git a/test/Driver/mips-cs-ld.c b/test/Driver/mips-cs-ld.c
index ac3adfd910b7..cdbd5c8c69c4 100644
--- a/test/Driver/mips-cs-ld.c
+++ b/test/Driver/mips-cs-ld.c
@@ -2,287 +2,287 @@
//
// = Big-endian, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32 %s
// CHECK-BE-HF-32: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-HF-32: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc"
-// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib/crt1.o"
-// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib/crti.o"
-// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/crtbegin.o"
+// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3{{/|\\\\}}crtbegin.o"
// CHECK-BE-HF-32: "-L[[TC]]"
// CHECK-BE-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib"
// CHECK-BE-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/lib"
// CHECK-BE-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/usr/lib"
-// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/crtend.o"
-// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib/crtn.o"
+// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-16 %s
// CHECK-BE-HF-16: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-HF-16: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/mips16"
-// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib/crt1.o"
-// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib/crti.o"
-// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/crtbegin.o"
+// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16{{/|\\\\}}crtbegin.o"
// CHECK-BE-HF-16: "-L[[TC]]/mips16"
// CHECK-BE-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/mips16"
-// CHECK-BE-HF-16: "-L[[TC]]"
-// CHECK-BE-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/lib"
-// CHECK-BE-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/usr/lib"
-// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/crtend.o"
-// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib/crtn.o"
+// CHECK-BE-HF-16-NOT: "-L[[TC]]"
+// CHECK-BE-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/lib/../lib"
+// CHECK-BE-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib"
+// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, hard float, mmicromips
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-MICRO %s
// CHECK-BE-HF-MICRO: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-HF-MICRO: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/micromips"
-// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib/crt1.o"
-// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib/crti.o"
-// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/crtbegin.o"
+// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips{{/|\\\\}}crtbegin.o"
// CHECK-BE-HF-MICRO: "-L[[TC]]/micromips"
// CHECK-BE-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/micromips"
-// CHECK-BE-HF-MICRO: "-L[[TC]]"
-// CHECK-BE-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/lib"
-// CHECK-BE-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/usr/lib"
-// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/crtend.o"
-// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib/crtn.o"
+// CHECK-BE-HF-MICRO-NOT: "-L[[TC]]"
+// CHECK-BE-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/lib/../lib"
+// CHECK-BE-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib"
+// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-32 %s
// CHECK-BE-SF-32: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-SF-32: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/soft-float"
-// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib/crt1.o"
-// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib/crti.o"
-// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/crtbegin.o"
+// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float{{/|\\\\}}crtbegin.o"
// CHECK-BE-SF-32: "-L[[TC]]/soft-float"
// CHECK-BE-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/soft-float"
-// CHECK-BE-SF-32: "-L[[TC]]"
-// CHECK-BE-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/lib"
-// CHECK-BE-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/usr/lib"
-// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/crtend.o"
-// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib/crtn.o"
+// CHECK-BE-SF-32-NOT: "-L[[TC]]"
+// CHECK-BE-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/lib/../lib"
+// CHECK-BE-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib"
+// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-16 %s
// CHECK-BE-SF-16: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-SF-16: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/mips16/soft-float"
-// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib/crt1.o"
-// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib/crti.o"
-// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/crtbegin.o"
+// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float{{/|\\\\}}crtbegin.o"
// CHECK-BE-SF-16: "-L[[TC]]/mips16/soft-float"
// CHECK-BE-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/mips16/soft-float"
-// CHECK-BE-SF-16: "-L[[TC]]"
-// CHECK-BE-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/lib"
-// CHECK-BE-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib"
-// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/crtend.o"
-// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib/crtn.o"
+// CHECK-BE-SF-16-NOT: "-L[[TC]]"
+// CHECK-BE-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/lib/../lib"
+// CHECK-BE-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib"
+// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, soft float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips-linux-gnu -msoft-float -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips-linux-gnu -msoft-float -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-MICRO %s
// CHECK-BE-SF-MICRO: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-SF-MICRO: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/micromips/soft-float"
-// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib/crt1.o"
-// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib/crti.o"
-// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/crtbegin.o"
+// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float{{/|\\\\}}crtbegin.o"
// CHECK-BE-SF-MICRO: "-L[[TC]]/micromips/soft-float"
// CHECK-BE-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/micromips/soft-float"
-// CHECK-BE-SF-MICRO: "-L[[TC]]"
-// CHECK-BE-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/lib"
-// CHECK-BE-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib"
-// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/crtend.o"
-// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib/crtn.o"
+// CHECK-BE-SF-MICRO-NOT: "-L[[TC]]"
+// CHECK-BE-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/lib/../lib"
+// CHECK-BE-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib"
+// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Big-endian, hard float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64 %s
// CHECK-BE-HF-64: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-HF-64: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc"
-// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64/crt1.o"
-// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64/crti.o"
-// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/64/crtbegin.o"
+// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64{{/|\\\\}}crti.o"
+// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/64{{/|\\\\}}crtbegin.o"
// CHECK-BE-HF-64: "-L[[TC]]/64"
// CHECK-BE-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib64"
// CHECK-BE-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/lib/../lib64"
// CHECK-BE-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/usr/lib/../lib64"
-// CHECK-BE-HF-64: "-L[[TC]]"
-// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/64/crtend.o"
-// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64/crtn.o"
+// CHECK-BE-HF-64-NOT: "-L[[TC]]"
+// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/usr/lib/../lib64{{/|\\\\}}crtn.o"
//
// = Big-endian, soft float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64 %s
// CHECK-BE-SF-64: "{{.*}}ld{{(.exe)?}}"
// CHECK-BE-SF-64: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/soft-float"
-// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64/crt1.o"
-// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64/crti.o"
-// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/64/crtbegin.o"
+// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64{{/|\\\\}}crti.o"
+// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/64{{/|\\\\}}crtbegin.o"
// CHECK-BE-SF-64: "-L[[TC]]/soft-float/64"
// CHECK-BE-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib64/soft-float"
// CHECK-BE-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/lib/../lib64"
// CHECK-BE-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64"
-// CHECK-BE-SF-64: "-L[[TC]]"
-// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/64/crtend.o"
-// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64/crtn.o"
+// CHECK-BE-SF-64-NOT: "-L[[TC]]"
+// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/64{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib64{{/|\\\\}}crtn.o"
//
// = Little-endian, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mhard-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-32 %s
// CHECK-EL-HF-32: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-HF-32: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/el"
-// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib/crti.o"
-// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/crtbegin.o"
+// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-HF-32: "-L[[TC]]/el"
// CHECK-EL-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/el"
-// CHECK-EL-HF-32: "-L[[TC]]"
-// CHECK-EL-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/lib"
-// CHECK-EL-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/usr/lib"
-// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/crtend.o"
-// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-HF-32-NOT: "-L[[TC]]"
+// CHECK-EL-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/lib/../lib"
+// CHECK-EL-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/usr/lib/../lib"
+// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mips16 \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mips16 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-16 %s
// CHECK-EL-HF-16: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-HF-16: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/mips16/el"
-// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib/crti.o"
-// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/el/crtbegin.o"
+// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-HF-16: "-L[[TC]]/mips16/el"
// CHECK-EL-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/mips16/el"
-// CHECK-EL-HF-16: "-L[[TC]]"
-// CHECK-EL-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/el/lib"
-// CHECK-EL-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/el/usr/lib"
-// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/el/crtend.o"
-// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-HF-16-NOT: "-L[[TC]]"
+// CHECK-EL-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/el/lib/../lib"
+// CHECK-EL-HF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib"
+// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, hard float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mmicromips \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mmicromips \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-MICRO %s
// CHECK-EL-HF-MICRO: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-HF-MICRO: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/micromips/el"
-// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib/crti.o"
-// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/el/crtbegin.o"
+// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-HF-MICRO: "-L[[TC]]/micromips/el"
// CHECK-EL-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/micromips/el"
-// CHECK-EL-HF-MICRO: "-L[[TC]]"
-// CHECK-EL-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/el/lib"
-// CHECK-EL-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/el/usr/lib"
-// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/el/crtend.o"
-// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-HF-MICRO-NOT: "-L[[TC]]"
+// CHECK-EL-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/el/lib/../lib"
+// CHECK-EL-HF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib"
+// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mfloat-abi=soft \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mfloat-abi=soft \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-32 %s
// CHECK-EL-SF-32: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-SF-32: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/soft-float/el"
-// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib/crti.o"
-// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/crtbegin.o"
+// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-SF-32: "-L[[TC]]/soft-float/el"
// CHECK-EL-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/soft-float/el"
-// CHECK-EL-SF-32: "-L[[TC]]"
-// CHECK-EL-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/lib"
-// CHECK-EL-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib"
-// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/crtend.o"
-// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-SF-32-NOT: "-L[[TC]]"
+// CHECK-EL-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/lib/../lib"
+// CHECK-EL-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib"
+// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-32: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mips16 -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-16 %s
// CHECK-EL-SF-16: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-SF-16: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/mips16/soft-float/el"
-// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib/crti.o"
-// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/el/crtbegin.o"
+// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-SF-16: "-L[[TC]]/mips16/soft-float/el"
// CHECK-EL-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/mips16/soft-float/el"
-// CHECK-EL-SF-16: "-L[[TC]]"
-// CHECK-EL-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/el/lib"
-// CHECK-EL-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib"
-// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/el/crtend.o"
-// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-SF-16-NOT: "-L[[TC]]"
+// CHECK-EL-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/el/lib/../lib"
+// CHECK-EL-SF-16: "-L[[TC]]/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib"
+// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/mips16/soft-float/el{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-16: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/mips16/soft-float/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, soft float, micromips
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mipsel-linux-gnu -mmicromips -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mipsel-linux-gnu -mmicromips -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-MICRO %s
// CHECK-EL-SF-MICRO: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-SF-MICRO: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/micromips/soft-float/el"
-// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib/crt1.o"
-// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib/crti.o"
-// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/el/crtbegin.o"
+// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/el{{/|\\\\}}crtbegin.o"
// CHECK-EL-SF-MICRO: "-L[[TC]]/micromips/soft-float/el"
// CHECK-EL-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/micromips/soft-float/el"
-// CHECK-EL-SF-MICRO: "-L[[TC]]"
-// CHECK-EL-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/el/lib"
-// CHECK-EL-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib"
-// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/el/crtend.o"
-// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib/crtn.o"
+// CHECK-EL-SF-MICRO-NOT: "-L[[TC]]"
+// CHECK-EL-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/el/lib/../lib"
+// CHECK-EL-SF-MICRO: "-L[[TC]]/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib"
+// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/micromips/soft-float/el{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-MICRO: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/micromips/soft-float/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
// = Little-endian, hard float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64el-linux-gnu \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64 %s
// CHECK-EL-HF-64: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-HF-64: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/el"
-// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64/crt1.o"
-// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64/crti.o"
-// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/64/crtbegin.o"
+// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64{{/|\\\\}}crti.o"
+// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/64{{/|\\\\}}crtbegin.o"
// CHECK-EL-HF-64: "-L[[TC]]/el/64"
// CHECK-EL-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib64/el"
// CHECK-EL-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/lib/../lib64"
// CHECK-EL-HF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64"
-// CHECK-EL-HF-64: "-L[[TC]]"
-// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/64/crtend.o"
-// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64/crtn.o"
+// CHECK-EL-HF-64-NOT: "-L[[TC]]"
+// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/el/64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/el/usr/lib/../lib64{{/|\\\\}}crtn.o"
//
// = Little-endian, soft float, 64-bit
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target mips64el-linux-gnu -msoft-float \
-// RUN: -gcc-toolchain %S/Inputs/mips_cs_tree \
+// RUN: --target=mips64el-linux-gnu -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64 %s
// CHECK-EL-SF-64: "{{.*}}ld{{(.exe)?}}"
// CHECK-EL-SF-64: "--sysroot=[[TC:[^"]+]]/../../../../mips-linux-gnu/libc/soft-float/el"
-// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64/crt1.o"
-// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64/crti.o"
-// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/64/crtbegin.o"
+// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64{{/|\\\\}}crti.o"
+// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/64{{/|\\\\}}crtbegin.o"
// CHECK-EL-SF-64: "-L[[TC]]/soft-float/el/64"
// CHECK-EL-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib64/soft-float/el"
// CHECK-EL-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/lib/../lib64"
// CHECK-EL-SF-64: "-L[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64"
-// CHECK-EL-SF-64: "-L[[TC]]"
-// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/64/crtend.o"
-// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64/crtn.o"
+// CHECK-EL-SF-64-NOT: "-L[[TC]]"
+// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/soft-float/el/64{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-64: "{{.*}}/lib/gcc/mips-linux-gnu/4.6.3/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib64{{/|\\\\}}crtn.o"
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index 31bf1935ea03..d663e6651e53 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -48,6 +48,30 @@
// RUN: | FileCheck --check-prefix=CHECK-NOMDSPR2 %s
// CHECK-NOMDSPR2: "-target-feature" "-dspr2"
//
+// -mmsa
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mno-msa -mmsa 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MMSA %s
+// CHECK-MMSA: "-target-feature" "+msa"
+//
+// -mno-msa
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mmsa -mno-msa 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOMMSA %s
+// CHECK-NOMMSA: "-target-feature" "-msa"
+//
+// -mfp64
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mfp32 -mfp64 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MFP64 %s
+// CHECK-MFP64: "-target-feature" "+fp64"
+//
+// -mfp32
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mfp64 -mfp32 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOMFP64 %s
+// CHECK-NOMFP64: "-target-feature" "-fp64"
+//
// -mxgot
// RUN: %clang -target mips-linux-gnu -### -c %s \
// RUN: -mno-xgot -mxgot 2>&1 \
@@ -60,6 +84,30 @@
// RUN: | FileCheck --check-prefix=CHECK-NOXGOT %s
// CHECK-NOXGOT-NOT: "-mllvm" "-mxgot"
//
+// -mldc1-sdc1
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mno-ldc1-sdc1 -mldc1-sdc1 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LDC1SDC1 %s
+// CHECK-LDC1SDC1-NOT: "-mllvm" "-mno-ldc1-sdc1"
+//
+// -mno-ldc1-sdc1
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mldc1-sdc1 -mno-ldc1-sdc1 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOLDC1SDC1 %s
+// CHECK-NOLDC1SDC1: "-mllvm" "-mno-ldc1-sdc1"
+//
+// -mcheck-zero-division
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mno-check-zero-division -mcheck-zero-division 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ZERODIV %s
+// CHECK-ZERODIV-NOT: "-mllvm" "-mno-check-zero-division"
+//
+// -mno-check-zero-division
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mcheck-zero-division -mno-check-zero-division 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOZERODIV %s
+// CHECK-NOZERODIV: "-mllvm" "-mno-check-zero-division"
+//
// -G
// RUN: %clang -target mips-linux-gnu -### -c %s \
// RUN: -G 16 2>&1 \
diff --git a/test/Driver/mips-float.c b/test/Driver/mips-float.c
index 9e62c0a95e04..ad2106a00e81 100644
--- a/test/Driver/mips-float.c
+++ b/test/Driver/mips-float.c
@@ -17,9 +17,9 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -msoft-float \
// RUN: | FileCheck --check-prefix=CHECK-SOFT %s
+// CHECK-SOFT: "-target-feature" "+soft-float"
// CHECK-SOFT: "-msoft-float"
// CHECK-SOFT: "-mfloat-abi" "soft"
-// CHECK-SOFT: "-target-feature" "+soft-float"
//
// -mfloat-abi=hard
// RUN: %clang -c %s -### -o %t.o 2>&1 \
@@ -31,9 +31,9 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mfloat-abi=soft \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SOFT %s
+// CHECK-ABI-SOFT: "-target-feature" "+soft-float"
// CHECK-ABI-SOFT: "-msoft-float"
// CHECK-ABI-SOFT: "-mfloat-abi" "soft"
-// CHECK-ABI-SOFT: "-target-feature" "+soft-float"
//
// -mdouble-float
// RUN: %clang -c %s -### -o %t.o 2>&1 \
@@ -46,15 +46,15 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mdouble-float -msingle-float \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SINGLE %s
-// CHECK-ABI-SINGLE: "-mfloat-abi" "hard"
// CHECK-ABI-SINGLE: "-target-feature" "+single-float"
+// CHECK-ABI-SINGLE: "-mfloat-abi" "hard"
//
// -msoft-float -msingle-float
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -msoft-float -msingle-float \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SOFT-SINGLE %s
-// CHECK-ABI-SOFT-SINGLE: "-mfloat-abi" "soft"
// CHECK-ABI-SOFT-SINGLE: "-target-feature" "+single-float"
+// CHECK-ABI-SOFT-SINGLE: "-mfloat-abi" "soft"
//
// Default -mips16
// RUN: %clang -c %s -### -o %t.o 2>&1 \
@@ -67,32 +67,32 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mhard-float -mips16 \
// RUN: | FileCheck --check-prefix=CHECK-HARD-MIPS16 %s
+// CHECK-HARD-MIPS16: "-target-feature" "+soft-float"
// CHECK-HARD-MIPS16: "-msoft-float"
// CHECK-HARD-MIPS16: "-mfloat-abi" "soft"
-// CHECK-HARD-MIPS16: "-target-feature" "+soft-float"
// CHECK-HARD-MIPS16: "-mllvm" "-mips16-hard-float"
//
// -msoft-float -mips16
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -msoft-float -mips16 \
// RUN: | FileCheck --check-prefix=CHECK-SOFT-MIPS16 %s
+// CHECK-SOFT-MIPS16: "-target-feature" "+soft-float"
// CHECK-SOFT-MIPS16: "-msoft-float"
// CHECK-SOFT-MIPS16: "-mfloat-abi" "soft"
-// CHECK-SOFT-MIPS16: "-target-feature" "+soft-float"
//
// -mfloat-abi=hard -mips16
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mfloat-abi=hard -mips16 \
// RUN: | FileCheck --check-prefix=CHECK-ABI-HARD-MIPS16 %s
+// CHECK-ABI-HARD-MIPS16: "-target-feature" "+soft-float"
// CHECK-ABI-HARD-MIPS16: "-msoft-float"
// CHECK-ABI-HARD-MIPS16: "-mfloat-abi" "soft"
-// CHECK-ABI-HARD-MIPS16: "-target-feature" "+soft-float"
// CHECK-ABI-HARD-MIPS16: "-mllvm" "-mips16-hard-float"
//
// -mfloat-abi=soft -mips16
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mfloat-abi=soft -mips16 \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SOFT-MIPS16 %s
+// CHECK-ABI-SOFT-MIPS16: "-target-feature" "+soft-float"
// CHECK-ABI-SOFT-MIPS16: "-msoft-float"
// CHECK-ABI-SOFT-MIPS16: "-mfloat-abi" "soft"
-// CHECK-ABI-SOFT-MIPS16: "-target-feature" "+soft-float"
diff --git a/test/Driver/mips-fsf.cpp b/test/Driver/mips-fsf.cpp
new file mode 100644
index 000000000000..b9fb11fd7c72
--- /dev/null
+++ b/test/Driver/mips-fsf.cpp
@@ -0,0 +1,2341 @@
+// Check frontend and linker invocations on FSF MIPS toolchain.
+//
+// = Big-endian, mips32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32 %s
+// CHECK-BE-HF-32: "-internal-isystem"
+// CHECK-BE-HF-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-32: "-internal-isystem"
+// CHECK-BE-HF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32"
+// CHECK-BE-HF-32: "-internal-isystem"
+// CHECK-BE-HF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-32: "-internal-externc-isystem"
+// CHECK-BE-HF-32: "[[TC]]/include"
+// CHECK-BE-HF-32: "-internal-externc-isystem"
+// CHECK-BE-HF-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32"
+// CHECK-BE-HF-32: "[[TC]]/../../../../sysroot/mips32/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-32: "[[TC]]/../../../../sysroot/mips32/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-32: "[[TC]]/mips32{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-32: "-L[[SR]]/mips32"
+// CHECK-BE-HF-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32"
+// CHECK-BE-HF-32: "-L[[SR]]/../../../../sysroot/mips32/usr/lib/../lib"
+// CHECK-BE-HF-32: "[[TC]]/mips32{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-32: "[[TC]]/../../../../sysroot/mips32/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32, hard float, fp64
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-32 %s
+// CHECK-BE-HF64-32: "-internal-isystem"
+// CHECK-BE-HF64-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-32: "-internal-isystem"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64"
+// CHECK-BE-HF64-32: "-internal-isystem"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-32: "-internal-externc-isystem"
+// CHECK-BE-HF64-32: "[[TC]]/include"
+// CHECK-BE-HF64-32: "-internal-externc-isystem"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/fp64"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../sysroot/mips32/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../sysroot/mips32/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-32: "[[TC]]/mips32/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-32: "-L[[SR]]/mips32/fp64"
+// CHECK-BE-HF64-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/fp64"
+// CHECK-BE-HF64-32: "-L[[SR]]/../../../../sysroot/mips32/fp64/usr/lib/../lib"
+// CHECK-BE-HF64-32: "[[TC]]/mips32/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-32: "[[TC]]/../../../../sysroot/mips32/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-32 %s
+// CHECK-BE-SF-32: "-internal-isystem"
+// CHECK-BE-SF-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-32: "-internal-isystem"
+// CHECK-BE-SF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/sof"
+// CHECK-BE-SF-32: "-internal-isystem"
+// CHECK-BE-SF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-32: "-internal-externc-isystem"
+// CHECK-BE-SF-32: "[[TC]]/include"
+// CHECK-BE-SF-32: "-internal-externc-isystem"
+// CHECK-BE-SF-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/sof"
+// CHECK-BE-SF-32: "[[TC]]/../../../../sysroot/mips32/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-32: "[[TC]]/../../../../sysroot/mips32/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-32: "[[TC]]/mips32/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-32: "-L[[SR]]/mips32/sof"
+// CHECK-BE-SF-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/sof"
+// CHECK-BE-SF-32: "-L[[SR]]/../../../../sysroot/mips32/sof/usr/lib/../lib"
+// CHECK-BE-SF-32: "[[TC]]/mips32/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-32: "[[TC]]/../../../../sysroot/mips32/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips16 / mips32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mips16 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-16 %s
+// CHECK-BE-HF-16: "-internal-isystem"
+// CHECK-BE-HF-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-16: "-internal-isystem"
+// CHECK-BE-HF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16"
+// CHECK-BE-HF-16: "-internal-isystem"
+// CHECK-BE-HF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-16: "-internal-externc-isystem"
+// CHECK-BE-HF-16: "[[TC]]/include"
+// CHECK-BE-HF-16: "-internal-externc-isystem"
+// CHECK-BE-HF-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16"
+// CHECK-BE-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-16: "[[TC]]/mips32/mips16{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-16: "-L[[SR]]/mips32/mips16"
+// CHECK-BE-HF-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16"
+// CHECK-BE-HF-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/usr/lib/../lib"
+// CHECK-BE-HF-16: "[[TC]]/mips32/mips16{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips16 / mips32, hard float, fp64
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mips16 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-16 %s
+// CHECK-BE-HF64-16: "-internal-isystem"
+// CHECK-BE-HF64-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-16: "-internal-isystem"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/fp64"
+// CHECK-BE-HF64-16: "-internal-isystem"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-16: "-internal-externc-isystem"
+// CHECK-BE-HF64-16: "[[TC]]/include"
+// CHECK-BE-HF64-16: "-internal-externc-isystem"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/fp64"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-16: "[[TC]]/mips32/mips16/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-16: "-L[[SR]]/mips32/mips16/fp64"
+// CHECK-BE-HF64-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/fp64"
+// CHECK-BE-HF64-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/fp64/usr/lib/../lib"
+// CHECK-BE-HF64-16: "[[TC]]/mips32/mips16/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips16 / mips32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-16 %s
+// CHECK-BE-SF-16: "-internal-isystem"
+// CHECK-BE-SF-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-16: "-internal-isystem"
+// CHECK-BE-SF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/sof"
+// CHECK-BE-SF-16: "-internal-isystem"
+// CHECK-BE-SF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-16: "-internal-externc-isystem"
+// CHECK-BE-SF-16: "[[TC]]/include"
+// CHECK-BE-SF-16: "-internal-externc-isystem"
+// CHECK-BE-SF-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/sof"
+// CHECK-BE-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-16: "[[TC]]/mips32/mips16/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-16: "-L[[SR]]/mips32/mips16/sof"
+// CHECK-BE-SF-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/sof"
+// CHECK-BE-SF-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/sof/usr/lib/../lib"
+// CHECK-BE-SF-16: "[[TC]]/mips32/mips16/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32 / mips16, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mips16 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-16 %s
+// CHECK-BE-NAN-16: "-internal-isystem"
+// CHECK-BE-NAN-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-16: "-internal-isystem"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/nan2008"
+// CHECK-BE-NAN-16: "-internal-isystem"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-16: "-internal-externc-isystem"
+// CHECK-BE-NAN-16: "[[TC]]/include"
+// CHECK-BE-NAN-16: "-internal-externc-isystem"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/nan2008"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-16: "[[TC]]/mips32/mips16/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-16: "-L[[SR]]/mips32/mips16/nan2008"
+// CHECK-BE-NAN-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/nan2008"
+// CHECK-BE-NAN-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN-16: "[[TC]]/mips32/mips16/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32 / mips16, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mips16 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-16 %s
+// CHECK-BE-NAN64-16: "-internal-isystem"
+// CHECK-BE-NAN64-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-16: "-internal-isystem"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16: "-internal-isystem"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-16: "-internal-externc-isystem"
+// CHECK-BE-NAN64-16: "[[TC]]/include"
+// CHECK-BE-NAN64-16: "-internal-externc-isystem"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-16: "[[TC]]/mips32/mips16/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-16: "-L[[SR]]/mips32/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/fp64/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN64-16: "[[TC]]/mips32/mips16/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-32 %s
+// CHECK-BE-NAN-32: "-internal-isystem"
+// CHECK-BE-NAN-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-32: "-internal-isystem"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/nan2008"
+// CHECK-BE-NAN-32: "-internal-isystem"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-32: "-internal-externc-isystem"
+// CHECK-BE-NAN-32: "[[TC]]/include"
+// CHECK-BE-NAN-32: "-internal-externc-isystem"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/nan2008"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../sysroot/mips32/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../sysroot/mips32/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-32: "[[TC]]/mips32/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-32: "-L[[SR]]/mips32/nan2008"
+// CHECK-BE-NAN-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/nan2008"
+// CHECK-BE-NAN-32: "-L[[SR]]/../../../../sysroot/mips32/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN-32: "[[TC]]/mips32/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-32: "[[TC]]/../../../../sysroot/mips32/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-32 %s
+// CHECK-BE-NAN64-32: "-internal-isystem"
+// CHECK-BE-NAN64-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-32: "-internal-isystem"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/fp64/nan2008"
+// CHECK-BE-NAN64-32: "-internal-isystem"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-32: "[[TC]]/include"
+// CHECK-BE-NAN64-32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/fp64/nan2008"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../sysroot/mips32/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../sysroot/mips32/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-32: "[[TC]]/mips32/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-32: "-L[[SR]]/mips32/fp64/nan2008"
+// CHECK-BE-NAN64-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/fp64/nan2008"
+// CHECK-BE-NAN64-32: "-L[[SR]]/../../../../sysroot/mips32/fp64/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN64-32: "[[TC]]/mips32/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-32: "[[TC]]/../../../../sysroot/mips32/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32R2 %s
+// CHECK-BE-HF-32R2: "-internal-isystem"
+// CHECK-BE-HF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-32R2: "-internal-isystem"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu"
+// CHECK-BE-HF-32R2: "-internal-isystem"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-32R2: "-internal-externc-isystem"
+// CHECK-BE-HF-32R2: "[[TC]]/include"
+// CHECK-BE-HF-32R2: "-internal-externc-isystem"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../sysroot/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../sysroot/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-32R2: "[[TC]]{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-32R2: "-L[[SR]]"
+// CHECK-BE-HF-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib"
+// CHECK-BE-HF-32R2: "-L[[SR]]/../../../../sysroot/usr/lib/../lib"
+// CHECK-BE-HF-32R2: "[[TC]]{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-32R2: "[[TC]]/../../../../sysroot/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-32R2 %s
+// CHECK-BE-HF64-32R2: "-internal-isystem"
+// CHECK-BE-HF64-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-32R2: "-internal-isystem"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64"
+// CHECK-BE-HF64-32R2: "-internal-isystem"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-32R2: "-internal-externc-isystem"
+// CHECK-BE-HF64-32R2: "[[TC]]/include"
+// CHECK-BE-HF64-32R2: "-internal-externc-isystem"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/fp64"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../sysroot/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../sysroot/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-32R2: "[[TC]]/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-32R2: "-L[[SR]]/fp64"
+// CHECK-BE-HF64-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/fp64"
+// CHECK-BE-HF64-32R2: "-L[[SR]]/../../../../sysroot/fp64/usr/lib/../lib"
+// CHECK-BE-HF64-32R2: "[[TC]]/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-32R2: "[[TC]]/../../../../sysroot/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-32R2 %s
+// CHECK-BE-SF-32R2: "-internal-isystem"
+// CHECK-BE-SF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-32R2: "-internal-isystem"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/sof"
+// CHECK-BE-SF-32R2: "-internal-isystem"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-32R2: "-internal-externc-isystem"
+// CHECK-BE-SF-32R2: "[[TC]]/include"
+// CHECK-BE-SF-32R2: "-internal-externc-isystem"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/sof"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../sysroot/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../sysroot/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-32R2: "[[TC]]/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-32R2: "-L[[SR]]/sof"
+// CHECK-BE-SF-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/sof"
+// CHECK-BE-SF-32R2: "-L[[SR]]/../../../../sysroot/sof/usr/lib/../lib"
+// CHECK-BE-SF-32R2: "[[TC]]/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-32R2: "[[TC]]/../../../../sysroot/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2 / mips16, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-16R2 %s
+// CHECK-BE-HF-16R2: "-internal-isystem"
+// CHECK-BE-HF-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-16R2: "-internal-isystem"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16"
+// CHECK-BE-HF-16R2: "-internal-isystem"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-16R2: "-internal-externc-isystem"
+// CHECK-BE-HF-16R2: "[[TC]]/include"
+// CHECK-BE-HF-16R2: "-internal-externc-isystem"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../sysroot/mips16/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../sysroot/mips16/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-16R2: "[[TC]]/mips16{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-16R2: "-L[[SR]]/mips16"
+// CHECK-BE-HF-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16"
+// CHECK-BE-HF-16R2: "-L[[SR]]/../../../../sysroot/mips16/usr/lib/../lib"
+// CHECK-BE-HF-16R2: "[[TC]]/mips16{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-16R2: "[[TC]]/../../../../sysroot/mips16/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2 / mips16, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-16R2 %s
+// CHECK-BE-HF64-16R2: "-internal-isystem"
+// CHECK-BE-HF64-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-16R2: "-internal-isystem"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64"
+// CHECK-BE-HF64-16R2: "-internal-isystem"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-16R2: "-internal-externc-isystem"
+// CHECK-BE-HF64-16R2: "[[TC]]/include"
+// CHECK-BE-HF64-16R2: "-internal-externc-isystem"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/fp64"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-16R2: "[[TC]]/mips16/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-16R2: "-L[[SR]]/mips16/fp64"
+// CHECK-BE-HF64-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/fp64"
+// CHECK-BE-HF64-16R2: "-L[[SR]]/../../../../sysroot/mips16/fp64/usr/lib/../lib"
+// CHECK-BE-HF64-16R2: "[[TC]]/mips16/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2 / mips16, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-16R2 %s
+// CHECK-BE-SF-16R2: "-internal-isystem"
+// CHECK-BE-SF-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-16R2: "-internal-isystem"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/sof"
+// CHECK-BE-SF-16R2: "-internal-isystem"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-16R2: "-internal-externc-isystem"
+// CHECK-BE-SF-16R2: "[[TC]]/include"
+// CHECK-BE-SF-16R2: "-internal-externc-isystem"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/sof"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../sysroot/mips16/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../sysroot/mips16/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-16R2: "[[TC]]/mips16/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-16R2: "-L[[SR]]/mips16/sof"
+// CHECK-BE-SF-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/sof"
+// CHECK-BE-SF-16R2: "-L[[SR]]/../../../../sysroot/mips16/sof/usr/lib/../lib"
+// CHECK-BE-SF-16R2: "[[TC]]/mips16/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-16R2: "[[TC]]/../../../../sysroot/mips16/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2 / mips16, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-16R2 %s
+// CHECK-BE-NAN-16R2: "-internal-isystem"
+// CHECK-BE-NAN-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-16R2: "-internal-isystem"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/nan2008"
+// CHECK-BE-NAN-16R2: "-internal-isystem"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-16R2: "-internal-externc-isystem"
+// CHECK-BE-NAN-16R2: "[[TC]]/include"
+// CHECK-BE-NAN-16R2: "-internal-externc-isystem"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/nan2008"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-16R2: "[[TC]]/mips16/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-16R2: "-L[[SR]]/mips16/nan2008"
+// CHECK-BE-NAN-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/nan2008"
+// CHECK-BE-NAN-16R2: "-L[[SR]]/../../../../sysroot/mips16/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN-16R2: "[[TC]]/mips16/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2 / mips16, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-16R2 %s
+// CHECK-BE-NAN64-16R2: "-internal-isystem"
+// CHECK-BE-NAN64-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-16R2: "-internal-isystem"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16R2: "-internal-isystem"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-16R2: "-internal-externc-isystem"
+// CHECK-BE-NAN64-16R2: "[[TC]]/include"
+// CHECK-BE-NAN64-16R2: "-internal-externc-isystem"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-16R2: "[[TC]]/mips16/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-16R2: "-L[[SR]]/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/fp64/nan2008"
+// CHECK-BE-NAN64-16R2: "-L[[SR]]/../../../../sysroot/mips16/fp64/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN64-16R2: "[[TC]]/mips16/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-32R2 %s
+// CHECK-BE-NAN-32R2: "-internal-isystem"
+// CHECK-BE-NAN-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-32R2: "-internal-isystem"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/nan2008"
+// CHECK-BE-NAN-32R2: "-internal-isystem"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-32R2: "-internal-externc-isystem"
+// CHECK-BE-NAN-32R2: "[[TC]]/include"
+// CHECK-BE-NAN-32R2: "-internal-externc-isystem"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/nan2008"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../sysroot/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../sysroot/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-32R2: "[[TC]]/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-32R2: "-L[[SR]]/nan2008"
+// CHECK-BE-NAN-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/nan2008"
+// CHECK-BE-NAN-32R2: "-L[[SR]]/../../../../sysroot/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN-32R2: "[[TC]]/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-32R2: "[[TC]]/../../../../sysroot/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips32r2, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-32R2 %s
+// CHECK-BE-NAN64-32R2: "-internal-isystem"
+// CHECK-BE-NAN64-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-32R2: "-internal-isystem"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/fp64/nan2008"
+// CHECK-BE-NAN64-32R2: "-internal-isystem"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-32R2: "-internal-externc-isystem"
+// CHECK-BE-NAN64-32R2: "[[TC]]/include"
+// CHECK-BE-NAN64-32R2: "-internal-externc-isystem"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/fp64/nan2008"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../sysroot/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../sysroot/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-32R2: "[[TC]]/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-32R2: "-L[[SR]]/fp64/nan2008"
+// CHECK-BE-NAN64-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/fp64/nan2008"
+// CHECK-BE-NAN64-32R2: "-L[[SR]]/../../../../sysroot/fp64/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN64-32R2: "[[TC]]/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-32R2: "[[TC]]/../../../../sysroot/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, micromips, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mmicromips -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-MM %s
+// CHECK-BE-HF-MM: "-internal-isystem"
+// CHECK-BE-HF-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-MM: "-internal-isystem"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips"
+// CHECK-BE-HF-MM: "-internal-isystem"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-MM: "-internal-externc-isystem"
+// CHECK-BE-HF-MM: "[[TC]]/include"
+// CHECK-BE-HF-MM: "-internal-externc-isystem"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../sysroot/micromips/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../sysroot/micromips/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-MM: "[[TC]]/micromips{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-MM: "-L[[SR]]/micromips"
+// CHECK-BE-HF-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips"
+// CHECK-BE-HF-MM: "-L[[SR]]/../../../../sysroot/micromips/usr/lib/../lib"
+// CHECK-BE-HF-MM: "[[TC]]/micromips{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-MM: "[[TC]]/../../../../sysroot/micromips/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, micromips, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mmicromips -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-MM %s
+// CHECK-BE-HF64-MM: "-internal-isystem"
+// CHECK-BE-HF64-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-MM: "-internal-isystem"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64"
+// CHECK-BE-HF64-MM: "-internal-isystem"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-MM: "-internal-externc-isystem"
+// CHECK-BE-HF64-MM: "[[TC]]/include"
+// CHECK-BE-HF64-MM: "-internal-externc-isystem"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/fp64"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-MM: "[[TC]]/micromips/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-MM: "-L[[SR]]/micromips/fp64"
+// CHECK-BE-HF64-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/fp64"
+// CHECK-BE-HF64-MM: "-L[[SR]]/../../../../sysroot/micromips/fp64/usr/lib/../lib"
+// CHECK-BE-HF64-MM: "[[TC]]/micromips/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, micromips, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mmicromips -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-MM %s
+// CHECK-BE-SF-MM: "-internal-isystem"
+// CHECK-BE-SF-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-MM: "-internal-isystem"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/sof"
+// CHECK-BE-SF-MM: "-internal-isystem"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-MM: "-internal-externc-isystem"
+// CHECK-BE-SF-MM: "[[TC]]/include"
+// CHECK-BE-SF-MM: "-internal-externc-isystem"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/sof"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../sysroot/micromips/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../sysroot/micromips/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-MM: "[[TC]]/micromips/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-MM: "-L[[SR]]/micromips/sof"
+// CHECK-BE-SF-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/sof"
+// CHECK-BE-SF-MM: "-L[[SR]]/../../../../sysroot/micromips/sof/usr/lib/../lib"
+// CHECK-BE-SF-MM: "[[TC]]/micromips/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-MM: "[[TC]]/../../../../sysroot/micromips/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, micromips, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mmicromips -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-MM %s
+// CHECK-BE-NAN-MM: "-internal-isystem"
+// CHECK-BE-NAN-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-MM: "-internal-isystem"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/nan2008"
+// CHECK-BE-NAN-MM: "-internal-isystem"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-MM: "-internal-externc-isystem"
+// CHECK-BE-NAN-MM: "[[TC]]/include"
+// CHECK-BE-NAN-MM: "-internal-externc-isystem"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/nan2008"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../sysroot/micromips/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../sysroot/micromips/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-MM: "[[TC]]/micromips/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-MM: "-L[[SR]]/micromips/nan2008"
+// CHECK-BE-NAN-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/nan2008"
+// CHECK-BE-NAN-MM: "-L[[SR]]/../../../../sysroot/micromips/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN-MM: "[[TC]]/micromips/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-MM: "[[TC]]/../../../../sysroot/micromips/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, micromips, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mmicromips -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-MM %s
+// CHECK-BE-NAN64-MM: "-internal-isystem"
+// CHECK-BE-NAN64-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-MM: "-internal-isystem"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/fp64/nan2008"
+// CHECK-BE-NAN64-MM: "-internal-isystem"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-MM: "-internal-externc-isystem"
+// CHECK-BE-NAN64-MM: "[[TC]]/include"
+// CHECK-BE-NAN64-MM: "-internal-externc-isystem"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/fp64/nan2008"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-MM: "[[TC]]/micromips/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-MM: "-L[[SR]]/micromips/fp64/nan2008"
+// CHECK-BE-NAN64-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/fp64/nan2008"
+// CHECK-BE-NAN64-MM: "-L[[SR]]/../../../../sysroot/micromips/fp64/nan2008/usr/lib/../lib"
+// CHECK-BE-NAN64-MM: "[[TC]]/micromips/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI n32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=n32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64-N32 %s
+// CHECK-BE-HF-64-N32: "-internal-isystem"
+// CHECK-BE-HF-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-64-N32: "-internal-isystem"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64"
+// CHECK-BE-HF-64-N32: "-internal-isystem"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-64-N32: "-internal-externc-isystem"
+// CHECK-BE-HF-64-N32: "[[TC]]/include"
+// CHECK-BE-HF-64-N32: "-internal-externc-isystem"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-64-N32: "[[TC]]/mips64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-64-N32: "-L[[SR]]/mips64"
+// CHECK-BE-HF-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64"
+// CHECK-BE-HF-64-N32: "-L[[SR]]/../../../../sysroot/mips64/usr/lib"
+// CHECK-BE-HF-64-N32: "[[TC]]/mips64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI n32, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=n32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-64-N32 %s
+// CHECK-BE-HF64-64-N32: "-internal-isystem"
+// CHECK-BE-HF64-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-64-N32: "-internal-isystem"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64"
+// CHECK-BE-HF64-64-N32: "-internal-isystem"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-64-N32: "-internal-externc-isystem"
+// CHECK-BE-HF64-64-N32: "[[TC]]/include"
+// CHECK-BE-HF64-64-N32: "-internal-externc-isystem"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/fp64"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-64-N32: "[[TC]]/mips64/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-64-N32: "-L[[SR]]/mips64/fp64"
+// CHECK-BE-HF64-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/fp64"
+// CHECK-BE-HF64-64-N32: "-L[[SR]]/../../../../sysroot/mips64/fp64/usr/lib"
+// CHECK-BE-HF64-64-N32: "[[TC]]/mips64/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI n32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=n32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64-N32 %s
+// CHECK-BE-SF-64-N32: "-internal-isystem"
+// CHECK-BE-SF-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-64-N32: "-internal-isystem"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/sof"
+// CHECK-BE-SF-64-N32: "-internal-isystem"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-64-N32: "-internal-externc-isystem"
+// CHECK-BE-SF-64-N32: "[[TC]]/include"
+// CHECK-BE-SF-64-N32: "-internal-externc-isystem"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/sof"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-64-N32: "[[TC]]/mips64/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-64-N32: "-L[[SR]]/mips64/sof"
+// CHECK-BE-SF-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/sof"
+// CHECK-BE-SF-64-N32: "-L[[SR]]/../../../../sysroot/mips64/sof/usr/lib"
+// CHECK-BE-SF-64-N32: "[[TC]]/mips64/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI n32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=n32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-64-N32 %s
+// CHECK-BE-NAN-64-N32: "-internal-isystem"
+// CHECK-BE-NAN-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-64-N32: "-internal-isystem"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/nan2008"
+// CHECK-BE-NAN-64-N32: "-internal-isystem"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-64-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN-64-N32: "[[TC]]/include"
+// CHECK-BE-NAN-64-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/nan2008"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-64-N32: "[[TC]]/mips64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-64-N32: "-L[[SR]]/mips64/nan2008"
+// CHECK-BE-NAN-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/nan2008"
+// CHECK-BE-NAN-64-N32: "-L[[SR]]/../../../../sysroot/mips64/nan2008/usr/lib"
+// CHECK-BE-NAN-64-N32: "[[TC]]/mips64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI n32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=n32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-64-N32 %s
+// CHECK-BE-NAN64-64-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-64-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/fp64/nan2008"
+// CHECK-BE-NAN64-64-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-64-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/include"
+// CHECK-BE-NAN64-64-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/fp64/nan2008"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/mips64/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-64-N32: "-L[[SR]]/mips64/fp64/nan2008"
+// CHECK-BE-NAN64-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/fp64/nan2008"
+// CHECK-BE-NAN64-64-N32: "-L[[SR]]/../../../../sysroot/mips64/fp64/nan2008/usr/lib"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/mips64/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI 64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64-64 %s
+// CHECK-BE-HF-64-64: "-internal-isystem"
+// CHECK-BE-HF-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-64-64: "-internal-isystem"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64"
+// CHECK-BE-HF-64-64: "-internal-isystem"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-64-64: "-internal-externc-isystem"
+// CHECK-BE-HF-64-64: "[[TC]]/include"
+// CHECK-BE-HF-64-64: "-internal-externc-isystem"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-64-64: "[[TC]]/mips64/64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-64-64: "-L[[SR]]/mips64/64"
+// CHECK-BE-HF-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64"
+// CHECK-BE-HF-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/usr/lib"
+// CHECK-BE-HF-64-64: "[[TC]]/mips64/64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI 64, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=64 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-64-64 %s
+// CHECK-BE-HF64-64-64: "-internal-isystem"
+// CHECK-BE-HF64-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-64-64: "-internal-isystem"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64"
+// CHECK-BE-HF64-64-64: "-internal-isystem"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-64-64: "-internal-externc-isystem"
+// CHECK-BE-HF64-64-64: "[[TC]]/include"
+// CHECK-BE-HF64-64-64: "-internal-externc-isystem"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/fp64"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-64-64: "[[TC]]/mips64/64/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-64-64: "-L[[SR]]/mips64/64/fp64"
+// CHECK-BE-HF64-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/fp64"
+// CHECK-BE-HF64-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/fp64/usr/lib"
+// CHECK-BE-HF64-64-64: "[[TC]]/mips64/64/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI 64, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=64 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64-64 %s
+// CHECK-BE-SF-64-64: "-internal-isystem"
+// CHECK-BE-SF-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-64-64: "-internal-isystem"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/sof"
+// CHECK-BE-SF-64-64: "-internal-isystem"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-64-64: "-internal-externc-isystem"
+// CHECK-BE-SF-64-64: "[[TC]]/include"
+// CHECK-BE-SF-64-64: "-internal-externc-isystem"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/sof"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-64-64: "[[TC]]/mips64/64/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-64-64: "-L[[SR]]/mips64/64/sof"
+// CHECK-BE-SF-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/sof"
+// CHECK-BE-SF-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/sof/usr/lib"
+// CHECK-BE-SF-64-64: "[[TC]]/mips64/64/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI 64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-64-64 %s
+// CHECK-BE-NAN-64-64: "-internal-isystem"
+// CHECK-BE-NAN-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-64-64: "-internal-isystem"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/nan2008"
+// CHECK-BE-NAN-64-64: "-internal-isystem"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-64-64: "-internal-externc-isystem"
+// CHECK-BE-NAN-64-64: "[[TC]]/include"
+// CHECK-BE-NAN-64-64: "-internal-externc-isystem"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/nan2008"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-64-64: "[[TC]]/mips64/64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-64-64: "-L[[SR]]/mips64/64/nan2008"
+// CHECK-BE-NAN-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/nan2008"
+// CHECK-BE-NAN-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/nan2008/usr/lib"
+// CHECK-BE-NAN-64-64: "[[TC]]/mips64/64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64, ABI 64, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64 -mabi=64 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-64-64 %s
+// CHECK-BE-NAN64-64-64: "-internal-isystem"
+// CHECK-BE-NAN64-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-64-64: "-internal-isystem"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/fp64/nan2008"
+// CHECK-BE-NAN64-64-64: "-internal-isystem"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-64-64: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64-64: "[[TC]]/include"
+// CHECK-BE-NAN64-64-64: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/fp64/nan2008"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-64-64: "[[TC]]/mips64/64/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-64-64: "-L[[SR]]/mips64/64/fp64/nan2008"
+// CHECK-BE-NAN64-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/fp64/nan2008"
+// CHECK-BE-NAN64-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/fp64/nan2008/usr/lib"
+// CHECK-BE-NAN64-64-64: "[[TC]]/mips64/64/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI n32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=n32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64R2-N32 %s
+// CHECK-BE-HF-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2"
+// CHECK-BE-HF-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/include"
+// CHECK-BE-HF-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/mips64r2{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-64R2-N32: "-L[[SR]]/mips64r2"
+// CHECK-BE-HF-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2"
+// CHECK-BE-HF-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/usr/lib"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/mips64r2{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI n32, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=n32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-64R2-N32 %s
+// CHECK-BE-HF64-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF64-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64"
+// CHECK-BE-HF64-64R2-N32: "-internal-isystem"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/include"
+// CHECK-BE-HF64-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/fp64"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/mips64r2/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-64R2-N32: "-L[[SR]]/mips64r2/fp64"
+// CHECK-BE-HF64-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/fp64"
+// CHECK-BE-HF64-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/fp64/usr/lib"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/mips64r2/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI n32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=n32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64R2-N32 %s
+// CHECK-BE-SF-64R2-N32: "-internal-isystem"
+// CHECK-BE-SF-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-64R2-N32: "-internal-isystem"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/sof"
+// CHECK-BE-SF-64R2-N32: "-internal-isystem"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/include"
+// CHECK-BE-SF-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/sof"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/mips64r2/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-64R2-N32: "-L[[SR]]/mips64r2/sof"
+// CHECK-BE-SF-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/sof"
+// CHECK-BE-SF-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/sof/usr/lib"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/mips64r2/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI n32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=n32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-64R2-N32 %s
+// CHECK-BE-NAN-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/nan2008"
+// CHECK-BE-NAN-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/include"
+// CHECK-BE-NAN-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/nan2008"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/mips64r2/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-64R2-N32: "-L[[SR]]/mips64r2/nan2008"
+// CHECK-BE-NAN-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/nan2008"
+// CHECK-BE-NAN-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/nan2008/usr/lib"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/mips64r2/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI n32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=n32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-64R2-N32 %s
+// CHECK-BE-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/include"
+// CHECK-BE-NAN64-64R2-N32: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/mips64r2/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-64R2-N32: "-L[[SR]]/mips64r2/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/fp64/nan2008/usr/lib"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/mips64r2/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI 64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-64R2-64 %s
+// CHECK-BE-HF-64R2-64: "-internal-isystem"
+// CHECK-BE-HF-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF-64R2-64: "-internal-isystem"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64"
+// CHECK-BE-HF-64R2-64: "-internal-isystem"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-HF-64R2-64: "[[TC]]/include"
+// CHECK-BE-HF-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-64R2-64: "[[TC]]/mips64r2/64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF-64R2-64: "-L[[SR]]/mips64r2/64"
+// CHECK-BE-HF-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64"
+// CHECK-BE-HF-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/usr/lib"
+// CHECK-BE-HF-64R2-64: "[[TC]]/mips64r2/64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI 64, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=64 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF64-64R2-64 %s
+// CHECK-BE-HF64-64R2-64: "-internal-isystem"
+// CHECK-BE-HF64-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-HF64-64R2-64: "-internal-isystem"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64"
+// CHECK-BE-HF64-64R2-64: "-internal-isystem"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-HF64-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/include"
+// CHECK-BE-HF64-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-HF64-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-HF64-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/fp64"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/mips64r2/64/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-BE-HF64-64R2-64: "-L[[SR]]/mips64r2/64/fp64"
+// CHECK-BE-HF64-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/fp64"
+// CHECK-BE-HF64-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/fp64/usr/lib"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/mips64r2/64/fp64{{/|\\\\}}crtend.o"
+// CHECK-BE-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI 64, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=64 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-SF-64R2-64 %s
+// CHECK-BE-SF-64R2-64: "-internal-isystem"
+// CHECK-BE-SF-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-SF-64R2-64: "-internal-isystem"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/sof"
+// CHECK-BE-SF-64R2-64: "-internal-isystem"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-SF-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-SF-64R2-64: "[[TC]]/include"
+// CHECK-BE-SF-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-SF-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-SF-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/sof"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-SF-64R2-64: "[[TC]]/mips64r2/64/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-SF-64R2-64: "-L[[SR]]/mips64r2/64/sof"
+// CHECK-BE-SF-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/sof"
+// CHECK-BE-SF-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/sof/usr/lib"
+// CHECK-BE-SF-64R2-64: "[[TC]]/mips64r2/64/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI 64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN-64R2-64 %s
+// CHECK-BE-NAN-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/nan2008"
+// CHECK-BE-NAN-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/include"
+// CHECK-BE-NAN-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/nan2008"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/mips64r2/64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN-64R2-64: "-L[[SR]]/mips64r2/64/nan2008"
+// CHECK-BE-NAN-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/nan2008"
+// CHECK-BE-NAN-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/nan2008/usr/lib"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/mips64r2/64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Big-endian, mips64r2, ABI 64, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64-linux-gnu -mips64r2 -mabi=64 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-NAN64-64R2-64 %s
+// CHECK-BE-NAN64-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-NAN64-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-64: "-internal-isystem"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-NAN64-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/include"
+// CHECK-BE-NAN64-64R2-64: "-internal-externc-isystem"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-BE-NAN64-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-NAN64-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/mips64r2/64/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-NAN64-64R2-64: "-L[[SR]]/mips64r2/64/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/fp64/nan2008"
+// CHECK-BE-NAN64-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/fp64/nan2008/usr/lib"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/mips64r2/64/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-32 %s
+// CHECK-EL-HF-32: "-internal-isystem"
+// CHECK-EL-HF-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-32: "-internal-isystem"
+// CHECK-EL-HF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el"
+// CHECK-EL-HF-32: "-internal-isystem"
+// CHECK-EL-HF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-32: "-internal-externc-isystem"
+// CHECK-EL-HF-32: "[[TC]]/include"
+// CHECK-EL-HF-32: "-internal-externc-isystem"
+// CHECK-EL-HF-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/el"
+// CHECK-EL-HF-32: "[[TC]]/../../../../sysroot/mips32/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-32: "[[TC]]/../../../../sysroot/mips32/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-32: "[[TC]]/mips32/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-32: "-L[[SR]]/mips32/el"
+// CHECK-EL-HF-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/el"
+// CHECK-EL-HF-32: "-L[[SR]]/../../../../sysroot/mips32/el/usr/lib/../lib"
+// CHECK-EL-HF-32: "[[TC]]/mips32/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-32: "[[TC]]/../../../../sysroot/mips32/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-32 %s
+// CHECK-EL-HF64-32: "-internal-isystem"
+// CHECK-EL-HF64-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-32: "-internal-isystem"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64"
+// CHECK-EL-HF64-32: "-internal-isystem"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-32: "-internal-externc-isystem"
+// CHECK-EL-HF64-32: "[[TC]]/include"
+// CHECK-EL-HF64-32: "-internal-externc-isystem"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/el/fp64"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-32: "[[TC]]/mips32/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-32: "-L[[SR]]/mips32/el/fp64"
+// CHECK-EL-HF64-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/el/fp64"
+// CHECK-EL-HF64-32: "-L[[SR]]/../../../../sysroot/mips32/el/fp64/usr/lib/../lib"
+// CHECK-EL-HF64-32: "[[TC]]/mips32/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-32 %s
+// CHECK-EL-SF-32: "-internal-isystem"
+// CHECK-EL-SF-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-32: "-internal-isystem"
+// CHECK-EL-SF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/sof"
+// CHECK-EL-SF-32: "-internal-isystem"
+// CHECK-EL-SF-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-32: "-internal-externc-isystem"
+// CHECK-EL-SF-32: "[[TC]]/include"
+// CHECK-EL-SF-32: "-internal-externc-isystem"
+// CHECK-EL-SF-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/el/sof"
+// CHECK-EL-SF-32: "[[TC]]/../../../../sysroot/mips32/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-32: "[[TC]]/../../../../sysroot/mips32/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-32: "[[TC]]/mips32/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-32: "-L[[SR]]/mips32/el/sof"
+// CHECK-EL-SF-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/el/sof"
+// CHECK-EL-SF-32: "-L[[SR]]/../../../../sysroot/mips32/el/sof/usr/lib/../lib"
+// CHECK-EL-SF-32: "[[TC]]/mips32/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-32: "[[TC]]/../../../../sysroot/mips32/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32 / mips16, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mips16 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-16 %s
+// CHECK-EL-HF-16: "-internal-isystem"
+// CHECK-EL-HF-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-16: "-internal-isystem"
+// CHECK-EL-HF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el"
+// CHECK-EL-HF-16: "-internal-isystem"
+// CHECK-EL-HF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-16: "-internal-externc-isystem"
+// CHECK-EL-HF-16: "[[TC]]/include"
+// CHECK-EL-HF-16: "-internal-externc-isystem"
+// CHECK-EL-HF-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/el"
+// CHECK-EL-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-16: "[[TC]]/mips32/mips16/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-16: "-L[[SR]]/mips32/mips16/el"
+// CHECK-EL-HF-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/el"
+// CHECK-EL-HF-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/el/usr/lib/../lib"
+// CHECK-EL-HF-16: "[[TC]]/mips32/mips16/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32 / mips16, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mips16 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-16 %s
+// CHECK-EL-HF64-16: "-internal-isystem"
+// CHECK-EL-HF64-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-16: "-internal-isystem"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/fp64"
+// CHECK-EL-HF64-16: "-internal-isystem"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-16: "-internal-externc-isystem"
+// CHECK-EL-HF64-16: "[[TC]]/include"
+// CHECK-EL-HF64-16: "-internal-externc-isystem"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/el/fp64"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-16: "[[TC]]/mips32/mips16/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-16: "-L[[SR]]/mips32/mips16/el/fp64"
+// CHECK-EL-HF64-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/el/fp64"
+// CHECK-EL-HF64-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/el/fp64/usr/lib/../lib"
+// CHECK-EL-HF64-16: "[[TC]]/mips32/mips16/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32 / mips16, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-16 %s
+// CHECK-EL-SF-16: "-internal-isystem"
+// CHECK-EL-SF-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-16: "-internal-isystem"
+// CHECK-EL-SF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/sof"
+// CHECK-EL-SF-16: "-internal-isystem"
+// CHECK-EL-SF-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-16: "-internal-externc-isystem"
+// CHECK-EL-SF-16: "[[TC]]/include"
+// CHECK-EL-SF-16: "-internal-externc-isystem"
+// CHECK-EL-SF-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/el/sof"
+// CHECK-EL-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-16: "[[TC]]/mips32/mips16/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-16: "-L[[SR]]/mips32/mips16/el/sof"
+// CHECK-EL-SF-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/el/sof"
+// CHECK-EL-SF-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/el/sof/usr/lib/../lib"
+// CHECK-EL-SF-16: "[[TC]]/mips32/mips16/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32 / mips16, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mips16 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-16 %s
+// CHECK-EL-NAN-16: "-internal-isystem"
+// CHECK-EL-NAN-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-16: "-internal-isystem"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/nan2008"
+// CHECK-EL-NAN-16: "-internal-isystem"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-16: "-internal-externc-isystem"
+// CHECK-EL-NAN-16: "[[TC]]/include"
+// CHECK-EL-NAN-16: "-internal-externc-isystem"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/el/nan2008"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-16: "[[TC]]/mips32/mips16/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-16: "-L[[SR]]/mips32/mips16/el/nan2008"
+// CHECK-EL-NAN-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/el/nan2008"
+// CHECK-EL-NAN-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/el/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN-16: "[[TC]]/mips32/mips16/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32 / mips16, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mips16 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-16 %s
+// CHECK-EL-NAN64-16: "-internal-isystem"
+// CHECK-EL-NAN64-16: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-16: "-internal-isystem"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16: "-internal-isystem"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-16: "-internal-externc-isystem"
+// CHECK-EL-NAN64-16: "[[TC]]/include"
+// CHECK-EL-NAN64-16: "-internal-externc-isystem"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-16: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-16: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-16: "[[TC]]/mips32/mips16/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-16: "-L[[SR]]/mips32/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16: "-L[[SR]]/../../../../sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN64-16: "[[TC]]/mips32/mips16/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-16: "[[TC]]/../../../../sysroot/mips32/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-32 %s
+// CHECK-EL-NAN-32: "-internal-isystem"
+// CHECK-EL-NAN-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-32: "-internal-isystem"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/nan2008"
+// CHECK-EL-NAN-32: "-internal-isystem"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-32: "-internal-externc-isystem"
+// CHECK-EL-NAN-32: "[[TC]]/include"
+// CHECK-EL-NAN-32: "-internal-externc-isystem"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/el/nan2008"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../sysroot/mips32/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../sysroot/mips32/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-32: "[[TC]]/mips32/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-32: "-L[[SR]]/mips32/el/nan2008"
+// CHECK-EL-NAN-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/el/nan2008"
+// CHECK-EL-NAN-32: "-L[[SR]]/../../../../sysroot/mips32/el/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN-32: "[[TC]]/mips32/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-32: "[[TC]]/../../../../sysroot/mips32/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-32 %s
+// CHECK-EL-NAN64-32: "-internal-isystem"
+// CHECK-EL-NAN64-32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-32: "-internal-isystem"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips32/el/fp64/nan2008"
+// CHECK-EL-NAN64-32: "-internal-isystem"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-32: "[[TC]]/include"
+// CHECK-EL-NAN64-32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips32/el/fp64/nan2008"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-32: "[[TC]]/mips32/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-32: "-L[[SR]]/mips32/el/fp64/nan2008"
+// CHECK-EL-NAN64-32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips32/el/fp64/nan2008"
+// CHECK-EL-NAN64-32: "-L[[SR]]/../../../../sysroot/mips32/el/fp64/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN64-32: "[[TC]]/mips32/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-32: "[[TC]]/../../../../sysroot/mips32/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-32R2 %s
+// CHECK-EL-HF-32R2: "-internal-isystem"
+// CHECK-EL-HF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-32R2: "-internal-isystem"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el"
+// CHECK-EL-HF-32R2: "-internal-isystem"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-32R2: "-internal-externc-isystem"
+// CHECK-EL-HF-32R2: "[[TC]]/include"
+// CHECK-EL-HF-32R2: "-internal-externc-isystem"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/el"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../sysroot/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../sysroot/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-32R2: "[[TC]]/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-32R2: "-L[[SR]]/el"
+// CHECK-EL-HF-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/el"
+// CHECK-EL-HF-32R2: "-L[[SR]]/../../../../sysroot/el/usr/lib/../lib"
+// CHECK-EL-HF-32R2: "[[TC]]/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-32R2: "[[TC]]/../../../../sysroot/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-32R2 %s
+// CHECK-EL-HF64-32R2: "-internal-isystem"
+// CHECK-EL-HF64-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-32R2: "-internal-isystem"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64"
+// CHECK-EL-HF64-32R2: "-internal-isystem"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-32R2: "-internal-externc-isystem"
+// CHECK-EL-HF64-32R2: "[[TC]]/include"
+// CHECK-EL-HF64-32R2: "-internal-externc-isystem"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/el/fp64"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../sysroot/el/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../sysroot/el/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-32R2: "[[TC]]/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-32R2: "-L[[SR]]/el/fp64"
+// CHECK-EL-HF64-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/el/fp64"
+// CHECK-EL-HF64-32R2: "-L[[SR]]/../../../../sysroot/el/fp64/usr/lib/../lib"
+// CHECK-EL-HF64-32R2: "[[TC]]/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-32R2: "[[TC]]/../../../../sysroot/el/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-32R2 %s
+// CHECK-EL-SF-32R2: "-internal-isystem"
+// CHECK-EL-SF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-32R2: "-internal-isystem"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/sof"
+// CHECK-EL-SF-32R2: "-internal-isystem"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-32R2: "-internal-externc-isystem"
+// CHECK-EL-SF-32R2: "[[TC]]/include"
+// CHECK-EL-SF-32R2: "-internal-externc-isystem"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/el/sof"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../sysroot/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../sysroot/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-32R2: "[[TC]]/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-32R2: "-L[[SR]]/el/sof"
+// CHECK-EL-SF-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/el/sof"
+// CHECK-EL-SF-32R2: "-L[[SR]]/../../../../sysroot/el/sof/usr/lib/../lib"
+// CHECK-EL-SF-32R2: "[[TC]]/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-32R2: "[[TC]]/../../../../sysroot/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2 / mips16, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-16R2 %s
+// CHECK-EL-HF-16R2: "-internal-isystem"
+// CHECK-EL-HF-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-16R2: "-internal-isystem"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el"
+// CHECK-EL-HF-16R2: "-internal-isystem"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-16R2: "-internal-externc-isystem"
+// CHECK-EL-HF-16R2: "[[TC]]/include"
+// CHECK-EL-HF-16R2: "-internal-externc-isystem"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/el"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../sysroot/mips16/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../sysroot/mips16/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-16R2: "[[TC]]/mips16/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-16R2: "-L[[SR]]/mips16/el"
+// CHECK-EL-HF-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/el"
+// CHECK-EL-HF-16R2: "-L[[SR]]/../../../../sysroot/mips16/el/usr/lib/../lib"
+// CHECK-EL-HF-16R2: "[[TC]]/mips16/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-16R2: "[[TC]]/../../../../sysroot/mips16/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2 / mips16, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-16R2 %s
+// CHECK-EL-HF64-16R2: "-internal-isystem"
+// CHECK-EL-HF64-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-16R2: "-internal-isystem"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64"
+// CHECK-EL-HF64-16R2: "-internal-isystem"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-16R2: "-internal-externc-isystem"
+// CHECK-EL-HF64-16R2: "[[TC]]/include"
+// CHECK-EL-HF64-16R2: "-internal-externc-isystem"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/el/fp64"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-16R2: "[[TC]]/mips16/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-16R2: "-L[[SR]]/mips16/el/fp64"
+// CHECK-EL-HF64-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/el/fp64"
+// CHECK-EL-HF64-16R2: "-L[[SR]]/../../../../sysroot/mips16/el/fp64/usr/lib/../lib"
+// CHECK-EL-HF64-16R2: "[[TC]]/mips16/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2 / mips16, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-16R2 %s
+// CHECK-EL-SF-16R2: "-internal-isystem"
+// CHECK-EL-SF-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-16R2: "-internal-isystem"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/sof"
+// CHECK-EL-SF-16R2: "-internal-isystem"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-16R2: "-internal-externc-isystem"
+// CHECK-EL-SF-16R2: "[[TC]]/include"
+// CHECK-EL-SF-16R2: "-internal-externc-isystem"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/el/sof"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../sysroot/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../sysroot/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-16R2: "[[TC]]/mips16/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-16R2: "-L[[SR]]/mips16/el/sof"
+// CHECK-EL-SF-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/el/sof"
+// CHECK-EL-SF-16R2: "-L[[SR]]/../../../../sysroot/mips16/el/sof/usr/lib/../lib"
+// CHECK-EL-SF-16R2: "[[TC]]/mips16/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-16R2: "[[TC]]/../../../../sysroot/mips16/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2 / mips16, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-16R2 %s
+// CHECK-EL-NAN-16R2: "-internal-isystem"
+// CHECK-EL-NAN-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-16R2: "-internal-isystem"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/nan2008"
+// CHECK-EL-NAN-16R2: "-internal-isystem"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-16R2: "-internal-externc-isystem"
+// CHECK-EL-NAN-16R2: "[[TC]]/include"
+// CHECK-EL-NAN-16R2: "-internal-externc-isystem"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/el/nan2008"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-16R2: "[[TC]]/mips16/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-16R2: "-L[[SR]]/mips16/el/nan2008"
+// CHECK-EL-NAN-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/el/nan2008"
+// CHECK-EL-NAN-16R2: "-L[[SR]]/../../../../sysroot/mips16/el/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN-16R2: "[[TC]]/mips16/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-16R2: "[[TC]]/../../../../sysroot/mips16/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2 / mips16, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-16R2 %s
+// CHECK-EL-NAN64-16R2: "-internal-isystem"
+// CHECK-EL-NAN64-16R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-16R2: "-internal-isystem"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16R2: "-internal-isystem"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-16R2: "-internal-externc-isystem"
+// CHECK-EL-NAN64-16R2: "[[TC]]/include"
+// CHECK-EL-NAN64-16R2: "-internal-externc-isystem"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-16R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-16R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-16R2: "[[TC]]/mips16/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-16R2: "-L[[SR]]/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/mips16/el/fp64/nan2008"
+// CHECK-EL-NAN64-16R2: "-L[[SR]]/../../../../sysroot/mips16/el/fp64/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN64-16R2: "[[TC]]/mips16/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-16R2: "[[TC]]/../../../../sysroot/mips16/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-32R2 %s
+// CHECK-EL-NAN-32R2: "-internal-isystem"
+// CHECK-EL-NAN-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-32R2: "-internal-isystem"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/nan2008"
+// CHECK-EL-NAN-32R2: "-internal-isystem"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-32R2: "-internal-externc-isystem"
+// CHECK-EL-NAN-32R2: "[[TC]]/include"
+// CHECK-EL-NAN-32R2: "-internal-externc-isystem"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/el/nan2008"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../sysroot/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../sysroot/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-32R2: "[[TC]]/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-32R2: "-L[[SR]]/el/nan2008"
+// CHECK-EL-NAN-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/el/nan2008"
+// CHECK-EL-NAN-32R2: "-L[[SR]]/../../../../sysroot/el/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN-32R2: "[[TC]]/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-32R2: "[[TC]]/../../../../sysroot/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips32r2, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-32R2 %s
+// CHECK-EL-NAN64-32R2: "-internal-isystem"
+// CHECK-EL-NAN64-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-32R2: "-internal-isystem"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/el/fp64/nan2008"
+// CHECK-EL-NAN64-32R2: "-internal-isystem"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-32R2: "-internal-externc-isystem"
+// CHECK-EL-NAN64-32R2: "[[TC]]/include"
+// CHECK-EL-NAN64-32R2: "-internal-externc-isystem"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-32R2: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/el/fp64/nan2008"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../sysroot/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../sysroot/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-32R2: "[[TC]]/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-32R2: "-L[[SR]]/el/fp64/nan2008"
+// CHECK-EL-NAN64-32R2: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/el/fp64/nan2008"
+// CHECK-EL-NAN64-32R2: "-L[[SR]]/../../../../sysroot/el/fp64/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN64-32R2: "[[TC]]/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-32R2: "[[TC]]/../../../../sysroot/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, micromips, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mmicromips -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-MM %s
+// CHECK-EL-HF-MM: "-internal-isystem"
+// CHECK-EL-HF-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-MM: "-internal-isystem"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el"
+// CHECK-EL-HF-MM: "-internal-isystem"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-MM: "-internal-externc-isystem"
+// CHECK-EL-HF-MM: "[[TC]]/include"
+// CHECK-EL-HF-MM: "-internal-externc-isystem"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/el"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../sysroot/micromips/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../sysroot/micromips/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-MM: "[[TC]]/micromips/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-MM: "-L[[SR]]/micromips/el"
+// CHECK-EL-HF-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/el"
+// CHECK-EL-HF-MM: "-L[[SR]]/../../../../sysroot/micromips/el/usr/lib/../lib"
+// CHECK-EL-HF-MM: "[[TC]]/micromips/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-MM: "[[TC]]/../../../../sysroot/micromips/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, micromips, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mmicromips -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-MM %s
+// CHECK-EL-HF64-MM: "-internal-isystem"
+// CHECK-EL-HF64-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-MM: "-internal-isystem"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64"
+// CHECK-EL-HF64-MM: "-internal-isystem"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-MM: "-internal-externc-isystem"
+// CHECK-EL-HF64-MM: "[[TC]]/include"
+// CHECK-EL-HF64-MM: "-internal-externc-isystem"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/el/fp64"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-MM: "[[TC]]/micromips/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-MM: "-L[[SR]]/micromips/el/fp64"
+// CHECK-EL-HF64-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/el/fp64"
+// CHECK-EL-HF64-MM: "-L[[SR]]/../../../../sysroot/micromips/el/fp64/usr/lib/../lib"
+// CHECK-EL-HF64-MM: "[[TC]]/micromips/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, micromips, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mmicromips -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-MM %s
+// CHECK-EL-SF-MM: "-internal-isystem"
+// CHECK-EL-SF-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-MM: "-internal-isystem"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/sof"
+// CHECK-EL-SF-MM: "-internal-isystem"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-MM: "-internal-externc-isystem"
+// CHECK-EL-SF-MM: "[[TC]]/include"
+// CHECK-EL-SF-MM: "-internal-externc-isystem"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/el/sof"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../sysroot/micromips/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../sysroot/micromips/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-MM: "[[TC]]/micromips/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-MM: "-L[[SR]]/micromips/el/sof"
+// CHECK-EL-SF-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/el/sof"
+// CHECK-EL-SF-MM: "-L[[SR]]/../../../../sysroot/micromips/el/sof/usr/lib/../lib"
+// CHECK-EL-SF-MM: "[[TC]]/micromips/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-MM: "[[TC]]/../../../../sysroot/micromips/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, micromips, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mmicromips -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-MM %s
+// CHECK-EL-NAN-MM: "-internal-isystem"
+// CHECK-EL-NAN-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-MM: "-internal-isystem"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/nan2008"
+// CHECK-EL-NAN-MM: "-internal-isystem"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-MM: "-internal-externc-isystem"
+// CHECK-EL-NAN-MM: "[[TC]]/include"
+// CHECK-EL-NAN-MM: "-internal-externc-isystem"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/el/nan2008"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../sysroot/micromips/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../sysroot/micromips/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-MM: "[[TC]]/micromips/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-MM: "-L[[SR]]/micromips/el/nan2008"
+// CHECK-EL-NAN-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/el/nan2008"
+// CHECK-EL-NAN-MM: "-L[[SR]]/../../../../sysroot/micromips/el/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN-MM: "[[TC]]/micromips/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-MM: "[[TC]]/../../../../sysroot/micromips/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, micromips, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mmicromips -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-MM %s
+// CHECK-EL-NAN64-MM: "-internal-isystem"
+// CHECK-EL-NAN64-MM: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-MM: "-internal-isystem"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/micromips/el/fp64/nan2008"
+// CHECK-EL-NAN64-MM: "-internal-isystem"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-MM: "-internal-externc-isystem"
+// CHECK-EL-NAN64-MM: "[[TC]]/include"
+// CHECK-EL-NAN64-MM: "-internal-externc-isystem"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-MM: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-MM: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/micromips/el/fp64/nan2008"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-MM: "[[TC]]/micromips/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-MM: "-L[[SR]]/micromips/el/fp64/nan2008"
+// CHECK-EL-NAN64-MM: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/../lib/micromips/el/fp64/nan2008"
+// CHECK-EL-NAN64-MM: "-L[[SR]]/../../../../sysroot/micromips/el/fp64/nan2008/usr/lib/../lib"
+// CHECK-EL-NAN64-MM: "[[TC]]/micromips/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-MM: "[[TC]]/../../../../sysroot/micromips/el/fp64/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI n32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=n32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64-N32 %s
+// CHECK-EL-HF-64-N32: "-internal-isystem"
+// CHECK-EL-HF-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-64-N32: "-internal-isystem"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el"
+// CHECK-EL-HF-64-N32: "-internal-isystem"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-64-N32: "-internal-externc-isystem"
+// CHECK-EL-HF-64-N32: "[[TC]]/include"
+// CHECK-EL-HF-64-N32: "-internal-externc-isystem"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/el"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-64-N32: "[[TC]]/mips64/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-64-N32: "-L[[SR]]/mips64/el"
+// CHECK-EL-HF-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/el"
+// CHECK-EL-HF-64-N32: "-L[[SR]]/../../../../sysroot/mips64/el/usr/lib"
+// CHECK-EL-HF-64-N32: "[[TC]]/mips64/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI n32, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=n32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-64-N32 %s
+// CHECK-EL-HF64-64-N32: "-internal-isystem"
+// CHECK-EL-HF64-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-64-N32: "-internal-isystem"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64"
+// CHECK-EL-HF64-64-N32: "-internal-isystem"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-64-N32: "-internal-externc-isystem"
+// CHECK-EL-HF64-64-N32: "[[TC]]/include"
+// CHECK-EL-HF64-64-N32: "-internal-externc-isystem"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/el/fp64"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-64-N32: "[[TC]]/mips64/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-64-N32: "-L[[SR]]/mips64/el/fp64"
+// CHECK-EL-HF64-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/el/fp64"
+// CHECK-EL-HF64-64-N32: "-L[[SR]]/../../../../sysroot/mips64/el/fp64/usr/lib"
+// CHECK-EL-HF64-64-N32: "[[TC]]/mips64/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI n32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=n32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64-N32 %s
+// CHECK-EL-SF-64-N32: "-internal-isystem"
+// CHECK-EL-SF-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-64-N32: "-internal-isystem"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/sof"
+// CHECK-EL-SF-64-N32: "-internal-isystem"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-64-N32: "-internal-externc-isystem"
+// CHECK-EL-SF-64-N32: "[[TC]]/include"
+// CHECK-EL-SF-64-N32: "-internal-externc-isystem"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/el/sof"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-64-N32: "[[TC]]/mips64/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-64-N32: "-L[[SR]]/mips64/el/sof"
+// CHECK-EL-SF-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/el/sof"
+// CHECK-EL-SF-64-N32: "-L[[SR]]/../../../../sysroot/mips64/el/sof/usr/lib"
+// CHECK-EL-SF-64-N32: "[[TC]]/mips64/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-64-N32: "[[TC]]/../../../../sysroot/mips64/el/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI n32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=n32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-64-N32 %s
+// CHECK-EL-NAN-64-N32: "-internal-isystem"
+// CHECK-EL-NAN-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-64-N32: "-internal-isystem"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/nan2008"
+// CHECK-EL-NAN-64-N32: "-internal-isystem"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-64-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN-64-N32: "[[TC]]/include"
+// CHECK-EL-NAN-64-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/el/nan2008"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/el/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/el/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-64-N32: "[[TC]]/mips64/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-64-N32: "-L[[SR]]/mips64/el/nan2008"
+// CHECK-EL-NAN-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/el/nan2008"
+// CHECK-EL-NAN-64-N32: "-L[[SR]]/../../../../sysroot/mips64/el/nan2008/usr/lib"
+// CHECK-EL-NAN-64-N32: "[[TC]]/mips64/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-64-N32: "[[TC]]/../../../../sysroot/mips64/el/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI n32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=n32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-64-N32 %s
+// CHECK-EL-NAN64-64-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-64-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-64-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/include"
+// CHECK-EL-NAN64-64-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-64-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-64-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/mips64/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-64-N32: "-L[[SR]]/mips64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-N32: "-L[[SR]]/../../../../sysroot/mips64/el/fp64/nan2008/usr/lib"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/mips64/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-64-N32: "[[TC]]/../../../../sysroot/mips64/el/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI 64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64-64 %s
+// CHECK-EL-HF-64-64: "-internal-isystem"
+// CHECK-EL-HF-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-64-64: "-internal-isystem"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el"
+// CHECK-EL-HF-64-64: "-internal-isystem"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-64-64: "-internal-externc-isystem"
+// CHECK-EL-HF-64-64: "[[TC]]/include"
+// CHECK-EL-HF-64-64: "-internal-externc-isystem"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/el"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-64-64: "[[TC]]/mips64/64/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-64-64: "-L[[SR]]/mips64/64/el"
+// CHECK-EL-HF-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/el"
+// CHECK-EL-HF-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/el/usr/lib"
+// CHECK-EL-HF-64-64: "[[TC]]/mips64/64/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI 64, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=64 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-64-64 %s
+// CHECK-EL-HF64-64-64: "-internal-isystem"
+// CHECK-EL-HF64-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-64-64: "-internal-isystem"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64"
+// CHECK-EL-HF64-64-64: "-internal-isystem"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-64-64: "-internal-externc-isystem"
+// CHECK-EL-HF64-64-64: "[[TC]]/include"
+// CHECK-EL-HF64-64-64: "-internal-externc-isystem"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/el/fp64"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-64-64: "[[TC]]/mips64/64/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-64-64: "-L[[SR]]/mips64/64/el/fp64"
+// CHECK-EL-HF64-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/el/fp64"
+// CHECK-EL-HF64-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/el/fp64/usr/lib"
+// CHECK-EL-HF64-64-64: "[[TC]]/mips64/64/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI 64, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=64 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64-64 %s
+// CHECK-EL-SF-64-64: "-internal-isystem"
+// CHECK-EL-SF-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-64-64: "-internal-isystem"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/sof"
+// CHECK-EL-SF-64-64: "-internal-isystem"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-64-64: "-internal-externc-isystem"
+// CHECK-EL-SF-64-64: "[[TC]]/include"
+// CHECK-EL-SF-64-64: "-internal-externc-isystem"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/el/sof"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-64-64: "[[TC]]/mips64/64/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-64-64: "-L[[SR]]/mips64/64/el/sof"
+// CHECK-EL-SF-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/el/sof"
+// CHECK-EL-SF-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/el/sof/usr/lib"
+// CHECK-EL-SF-64-64: "[[TC]]/mips64/64/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI 64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-64-64 %s
+// CHECK-EL-NAN-64-64: "-internal-isystem"
+// CHECK-EL-NAN-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-64-64: "-internal-isystem"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/nan2008"
+// CHECK-EL-NAN-64-64: "-internal-isystem"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-64-64: "-internal-externc-isystem"
+// CHECK-EL-NAN-64-64: "[[TC]]/include"
+// CHECK-EL-NAN-64-64: "-internal-externc-isystem"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/el/nan2008"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-64-64: "[[TC]]/mips64/64/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-64-64: "-L[[SR]]/mips64/64/el/nan2008"
+// CHECK-EL-NAN-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/el/nan2008"
+// CHECK-EL-NAN-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/el/nan2008/usr/lib"
+// CHECK-EL-NAN-64-64: "[[TC]]/mips64/64/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64, ABI 64, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64 -mabi=64 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-64-64 %s
+// CHECK-EL-NAN64-64-64: "-internal-isystem"
+// CHECK-EL-NAN64-64-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-64-64: "-internal-isystem"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-64: "-internal-isystem"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-64-64: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64-64: "[[TC]]/include"
+// CHECK-EL-NAN64-64-64: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-64-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-64-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-64-64: "[[TC]]/mips64/64/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-64-64: "-L[[SR]]/mips64/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64-64: "-L[[SR]]/../../../../sysroot/mips64/64/el/fp64/nan2008/usr/lib"
+// CHECK-EL-NAN64-64-64: "[[TC]]/mips64/64/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-64-64: "[[TC]]/../../../../sysroot/mips64/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI n32, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=n32 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64R2-N32 %s
+// CHECK-EL-HF-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el"
+// CHECK-EL-HF-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/include"
+// CHECK-EL-HF-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/el"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/mips64r2/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-64R2-N32: "-L[[SR]]/mips64r2/el"
+// CHECK-EL-HF-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/el"
+// CHECK-EL-HF-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/el/usr/lib"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/mips64r2/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI n32, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=n32 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-64R2-N32 %s
+// CHECK-EL-HF64-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF64-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64"
+// CHECK-EL-HF64-64R2-N32: "-internal-isystem"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/include"
+// CHECK-EL-HF64-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/el/fp64"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/mips64r2/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-64R2-N32: "-L[[SR]]/mips64r2/el/fp64"
+// CHECK-EL-HF64-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/el/fp64"
+// CHECK-EL-HF64-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/el/fp64/usr/lib"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/mips64r2/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI n32, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=n32 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64R2-N32 %s
+// CHECK-EL-SF-64R2-N32: "-internal-isystem"
+// CHECK-EL-SF-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-64R2-N32: "-internal-isystem"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/sof"
+// CHECK-EL-SF-64R2-N32: "-internal-isystem"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/include"
+// CHECK-EL-SF-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/el/sof"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/mips64r2/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-64R2-N32: "-L[[SR]]/mips64r2/el/sof"
+// CHECK-EL-SF-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/el/sof"
+// CHECK-EL-SF-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/el/sof/usr/lib"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/mips64r2/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI n32, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=n32 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-64R2-N32 %s
+// CHECK-EL-NAN-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/nan2008"
+// CHECK-EL-NAN-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/include"
+// CHECK-EL-NAN-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/el/nan2008"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/mips64r2/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-64R2-N32: "-L[[SR]]/mips64r2/el/nan2008"
+// CHECK-EL-NAN-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/el/nan2008"
+// CHECK-EL-NAN-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/el/nan2008/usr/lib"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/mips64r2/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI n32, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=n32 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-64R2-N32 %s
+// CHECK-EL-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-N32: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-N32: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/include"
+// CHECK-EL-NAN64-64R2-N32: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-64R2-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-64R2-N32: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/mips64r2/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-64R2-N32: "-L[[SR]]/mips64r2/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-N32: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-N32: "-L[[SR]]/../../../../sysroot/mips64r2/el/fp64/nan2008/usr/lib"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/mips64r2/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-64R2-N32: "[[TC]]/../../../../sysroot/mips64r2/el/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI 64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF-64R2-64 %s
+// CHECK-EL-HF-64R2-64: "-internal-isystem"
+// CHECK-EL-HF-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF-64R2-64: "-internal-isystem"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el"
+// CHECK-EL-HF-64R2-64: "-internal-isystem"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-HF-64R2-64: "[[TC]]/include"
+// CHECK-EL-HF-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/el"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF-64R2-64: "[[TC]]/mips64r2/64/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF-64R2-64: "-L[[SR]]/mips64r2/64/el"
+// CHECK-EL-HF-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/el"
+// CHECK-EL-HF-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/el/usr/lib"
+// CHECK-EL-HF-64R2-64: "[[TC]]/mips64r2/64/el{{/|\\\\}}crtend.o"
+// CHECK-EL-HF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI 64, fp64, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=64 -mfp64 -mhard-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-HF64-64R2-64 %s
+// CHECK-EL-HF64-64R2-64: "-internal-isystem"
+// CHECK-EL-HF64-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-HF64-64R2-64: "-internal-isystem"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64"
+// CHECK-EL-HF64-64R2-64: "-internal-isystem"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-HF64-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/include"
+// CHECK-EL-HF64-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-HF64-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-HF64-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/el/fp64"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/mips64r2/64/el/fp64{{/|\\\\}}crtbegin.o"
+// CHECK-EL-HF64-64R2-64: "-L[[SR]]/mips64r2/64/el/fp64"
+// CHECK-EL-HF64-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/el/fp64"
+// CHECK-EL-HF64-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/el/fp64/usr/lib"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/mips64r2/64/el/fp64{{/|\\\\}}crtend.o"
+// CHECK-EL-HF64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI 64, soft float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=64 -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-SF-64R2-64 %s
+// CHECK-EL-SF-64R2-64: "-internal-isystem"
+// CHECK-EL-SF-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-SF-64R2-64: "-internal-isystem"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/sof"
+// CHECK-EL-SF-64R2-64: "-internal-isystem"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-SF-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-SF-64R2-64: "[[TC]]/include"
+// CHECK-EL-SF-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-SF-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-SF-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/el/sof"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/sof/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/sof/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-SF-64R2-64: "[[TC]]/mips64r2/64/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-SF-64R2-64: "-L[[SR]]/mips64r2/64/el/sof"
+// CHECK-EL-SF-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/el/sof"
+// CHECK-EL-SF-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/el/sof/usr/lib"
+// CHECK-EL-SF-64R2-64: "[[TC]]/mips64r2/64/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-SF-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/sof/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI 64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN-64R2-64 %s
+// CHECK-EL-NAN-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/nan2008"
+// CHECK-EL-NAN-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/include"
+// CHECK-EL-NAN-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/el/nan2008"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/mips64r2/64/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN-64R2-64: "-L[[SR]]/mips64r2/64/el/nan2008"
+// CHECK-EL-NAN-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/el/nan2008"
+// CHECK-EL-NAN-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/el/nan2008/usr/lib"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/mips64r2/64/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/nan2008/usr/lib{{/|\\\\}}crtn.o"
+//
+// = Little-endian, mips64r2, ABI 64, fp64, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips64el-linux-gnu -mips64r2 -mabi=64 -mfp64 -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-NAN64-64R2-64 %s
+// CHECK-EL-NAN64-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-64: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-NAN64-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/mips64r2/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-64: "-internal-isystem"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-NAN64-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/include"
+// CHECK-EL-NAN64-64R2-64: "-internal-externc-isystem"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../sysroot/usr/include"
+// CHECK-EL-NAN64-64R2-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-NAN64-64R2-64: "--sysroot=[[SR:[^"]+]]/../../../../sysroot/mips64r2/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crti.o"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/mips64r2/64/el/fp64/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-NAN64-64R2-64: "-L[[SR]]/mips64r2/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-64: "-L[[SR]]/../../../../mips-mti-linux-gnu/lib/mips64r2/64/el/fp64/nan2008"
+// CHECK-EL-NAN64-64R2-64: "-L[[SR]]/../../../../sysroot/mips64r2/64/el/fp64/nan2008/usr/lib"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/mips64r2/64/el/fp64/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-NAN64-64R2-64: "[[TC]]/../../../../sysroot/mips64r2/64/el/fp64/nan2008/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/mipsel-nacl-defines.cpp b/test/Driver/mipsel-nacl-defines.cpp
new file mode 100644
index 000000000000..0f63d7659e51
--- /dev/null
+++ b/test/Driver/mipsel-nacl-defines.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang -target mipsel-unknown-nacl -### %s -emit-llvm-only -c -o %t.o 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target mipsel-unknown-nacl %s -emit-llvm -S -c -o - | FileCheck %s
+// RUN: %clang -target mipsel-unknown-nacl %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+
+// ECHO: {{.*}} "-cc1" {{.*}}mipsel-nacl-defines.c
+
+// Check platform defines
+
+// CHECK: _MIPSELdefined
+#ifdef _MIPSEL
+void _MIPSELdefined() {}
+#endif
+
+// CHECK: _mipsdefined
+#ifdef _mips
+void _mipsdefined() {}
+#endif
+
+// CHECK: __native_client__defined
+#ifdef __native_client__
+void __native_client__defined() {}
+#endif
+
+// CHECK: unixdefined
+#ifdef unix
+void unixdefined() {}
+#endif
+
+// CHECK: __ELF__defined
+#ifdef __ELF__
+void __ELF__defined() {}
+#endif
+
+// CHECK: _GNU_SOURCEdefined
+#ifdef _GNU_SOURCE
+void _GNU_SOURCEdefined() {}
+#endif
+
+// THREADS: _REENTRANTdefined
+// CHECK: _REENTRANTundefined
+#ifdef _REENTRANT
+void _REENTRANTdefined() {}
+#else
+void _REENTRANTundefined() {}
+#endif
diff --git a/test/Driver/montavista-gcc-toolchain.c b/test/Driver/montavista-gcc-toolchain.c
index b9ab729ef21c..da76e9579439 100644
--- a/test/Driver/montavista-gcc-toolchain.c
+++ b/test/Driver/montavista-gcc-toolchain.c
@@ -1,9 +1,9 @@
// Test that the montavista gcc-toolchain is correctly detected
//
// RUN: %clang -print-libgcc-file-name 2>&1 \
-// RUN: -target i686-montavista-linux \
-// RUN: -gcc-toolchain %S/Inputs/montavista_i686_tree/usr \
+// RUN: --target=i686-montavista-linux \
+// RUN: --gcc-toolchain=%S/Inputs/montavista_i686_tree/usr \
// RUN: | FileCheck %s
// Test for header search toolchain detection.
-// CHECK: montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0/libgcc.a
+// CHECK: montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0{{/|\\}}libgcc.a
diff --git a/test/Driver/netbsd.c b/test/Driver/netbsd.c
new file mode 100644
index 000000000000..09c2bd3d6e1f
--- /dev/null
+++ b/test/Driver/netbsd.c
@@ -0,0 +1,57 @@
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64 %s
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64-7 %s
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd6.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64-6 %s
+
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64 %s
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64-7 %s
+// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd6.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64-6 %s
+
+// X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
+// X86_64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd7.0.0"
+// X86_64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd6.0.0"
+// X86_64-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// X86_64-6: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
+// S-X86_64: ld{{.*}}" "-Bstatic"
+// S-X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd7.0.0"
+// S-X86_64-7: ld{{.*}}" "-Bstatic"
+// S-X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd6.0.0"
+// S-X86_64-6: ld{{.*}}" "-Bstatic"
+// S-X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-X86_64-6: "-lgcc_eh" "-lc" "-lgcc"
+// S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/netbsd.cpp b/test/Driver/netbsd.cpp
new file mode 100644
index 000000000000..1c338d3e6925
--- /dev/null
+++ b/test/Driver/netbsd.cpp
@@ -0,0 +1,57 @@
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64 %s
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd6.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64-6 %s
+
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64 %s
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd6.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-X86_64-6 %s
+
+// X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
+// X86_64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// X86_64: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd7.0.0"
+// X86_64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// X86_64-7: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd6.0.0"
+// X86_64-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// X86_64-6: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
+// S-X86_64: ld{{.*}}" "-Bstatic"
+// S-X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-X86_64: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd7.0.0"
+// S-X86_64-7: ld{{.*}}" "-Bstatic"
+// S-X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-X86_64-7: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd6.0.0"
+// S-X86_64-6: ld{{.*}}" "-Bstatic"
+// S-X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// S-X86_64-6: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/no-integrated-as-win.c b/test/Driver/no-integrated-as-win.c
index 0d6c2958e57a..8f590a090168 100644
--- a/test/Driver/no-integrated-as-win.c
+++ b/test/Driver/no-integrated-as-win.c
@@ -1,3 +1,11 @@
// RUN: %clang -target x86_64-pc-win32 -### -no-integrated-as %s -c 2>&1 | FileCheck %s
+// CHECK: there is no external assembler that can be used on this platform
-// CHECK: there is no external assembler we can use on windows
+// But there is for mingw. The source file should only be mentioned once for
+// the compile step.
+// RUN: %clang -target i686-pc-mingw32 -### -no-integrated-as %s -c 2>&1 | FileCheck -check-prefix=MINGW %s
+// MINGW: "-cc1"
+// MINGW: "-main-file-name" "no-integrated-as-win.c"
+// MINGW: "-x" "c" "{{.*}}no-integrated-as-win.c"
+// The assembler goes here, but its name depends on PATH.
+// MINGW-NOT: no-integrated-as-win.c
diff --git a/test/Driver/no-objc-default-synthesize-properties.m b/test/Driver/no-objc-default-synthesize-properties.m
index e3805140fa04..a034926a9e2f 100644
--- a/test/Driver/no-objc-default-synthesize-properties.m
+++ b/test/Driver/no-objc-default-synthesize-properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang -fsyntax-only -fno-objc-default-synthesize-properties -fobjc-default-synthesize-properties %s 2>&1 | FileCheck %s
+// RUN: not %clang -fsyntax-only -fno-objc-default-synthesize-properties -fobjc-default-synthesize-properties %s 2>&1 | FileCheck %s
@interface I
@property int P;
@@ -6,5 +6,5 @@
@implementation I
@end
-// CHECK: warning: argument unused during compilation: '-fno-objc-default-synthesize-properties'
-// CHECK: warning: argument unused during compilation: '-fobjc-default-synthesize-properties'
+// CHECK: error: unknown argument: '-fno-objc-default-synthesize-properties'
+// CHECK: error: unknown argument: '-fobjc-default-synthesize-properties'
diff --git a/test/Driver/noexecstack.c b/test/Driver/noexecstack.c
index 1f4772882654..5970713c1654 100644
--- a/test/Driver/noexecstack.c
+++ b/test/Driver/noexecstack.c
@@ -1 +1,3 @@
-// RUN: %clang -### %s -c -o tmp.o -triple i686-pc-linux-gnu -integrated-as -Wa,--noexecstack 2>&1 | grep "mnoexecstack"
+// RUN: %clang -### %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -Wa,--noexecstack 2>&1 | FileCheck %s
+
+// CHECK: "-cc1" {{.*}} "-mnoexecstack"
diff --git a/test/Driver/nostdincxx.cpp b/test/Driver/nostdincxx.cpp
index 7e00555d04bd..1e1d85f35830 100644
--- a/test/Driver/nostdincxx.cpp
+++ b/test/Driver/nostdincxx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -nostdinc++ %s 2>&1 | FileCheck %s
+// RUN: not %clangxx -nostdinc++ %s 2>&1 | FileCheck %s
// XFAIL: win32
// CHECK: file not found
#include <vector>
diff --git a/test/Driver/objc_default_synth.m b/test/Driver/objc_default_synth.m
deleted file mode 100644
index a8c7f7e546db..000000000000
--- a/test/Driver/objc_default_synth.m
+++ /dev/null
@@ -1,6 +0,0 @@
-// We should be synthesizing properties by default on all platforms now.
-// RUN: %clang -### -target armv7-unknown-freebsd %s 2>&1 | FileCheck %s
-// RUN: %clang -### -target armv7-apple-ios %s 2>&1 | FileCheck %s
-// RUN: %clang -### -target i686-apple-macosx %s 2>&1 | FileCheck %s
-// REQUIRES: clang-driver
-// CHECK: -fobjc-default-synthesize
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index 4fd5b6a41b57..ef02b07d29ef 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -17,6 +17,10 @@
// RUN: | FileCheck --check-prefix=CHECK-LD-T %s
// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -Z %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-LD-Z %s
+// RUN: %clang -no-canonical-prefixes -target mips64-unknown-openbsd %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64-LD %s
+// RUN: %clang -no-canonical-prefixes -target mips64el-unknown-openbsd %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL-LD %s
// CHECK-LD-R: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
// CHECK-LD-R: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-r" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
// CHECK-LD-S: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
@@ -25,3 +29,27 @@
// CHECK-LD-T: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-t" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
// CHECK-LD-Z: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
// CHECK-LD-Z: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-Z" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// CHECK-MIPS64-LD: clang{{.*}}" "-cc1" "-triple" "mips64-unknown-openbsd"
+// CHECK-MIPS64-LD: ld{{.*}}" "-EB" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// CHECK-MIPS64EL-LD: clang{{.*}}" "-cc1" "-triple" "mips64el-unknown-openbsd"
+// CHECK-MIPS64EL-LD: ld{{.*}}" "-EL" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+
+// Check passing options to the assembler for various OpenBSD targets
+// RUN: %clang -target amd64-pc-openbsd -m32 -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AMD64-M32 %s
+// RUN: %clang -target powerpc-unknown-openbsd -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-POWERPC %s
+// RUN: %clang -target mips64-unknown-openbsd -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64 %s
+// RUN: %clang -target mips64-unknown-openbsd -fPIC -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64-PIC %s
+// RUN: %clang -target mips64el-unknown-openbsd -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64EL %s
+// RUN: %clang -target mips64el-unknown-openbsd -fPIC -### -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64EL-PIC %s
+// CHECK-AMD64-M32: as{{.*}}" "--32"
+// CHECK-POWERPC: as{{.*}}" "-mppc" "-many"
+// CHECK-MIPS64: as{{.*}}" "-mabi" "64" "-EB"
+// CHECK-MIPS64-PIC: as{{.*}}" "-mabi" "64" "-EB" "-KPIC"
+// CHECK-MIPS64EL: as{{.*}}" "-mabi" "64" "-EL"
+// CHECK-MIPS64EL-PIC: as{{.*}}" "-mabi" "64" "-EL" "-KPIC"
diff --git a/test/Driver/option-aliases.c b/test/Driver/option-aliases.c
index 38bf4b1a5777..9cd9252a4832 100644
--- a/test/Driver/option-aliases.c
+++ b/test/Driver/option-aliases.c
@@ -1,11 +1,14 @@
-// RUN: %clang -ccc-print-options \
-// RUN: --save-temps --undefine-macro=FOO --undefine-macro FOO \
-// RUN: --param=FOO --output=FOO 2> %t
-// RUN: FileCheck --check-prefix=CHECK-OPTIONS < %t %s
+// RUN: %clang -### -S \
+// RUN: --save-temps --undefine-macro=FOO --undefine-macro BAR \
+// RUN: --param=FOO --output=FOO %s 2>&1 | \
+// RUN: FileCheck %s
-// CHECK-OPTIONS: Option 0 - Name: "-ccc-print-options", Values: {}
-// CHECK-OPTIONS: Option 1 - Name: "-save-temps", Values: {}
-// CHECK-OPTIONS: Option 2 - Name: "-U", Values: {"FOO"}
-// CHECK-OPTIONS: Option 3 - Name: "-U", Values: {"FOO"}
-// CHECK-OPTIONS: Option 4 - Name: "--param", Values: {"FOO"}
-// CHECK-OPTIONS: Option 5 - Name: "-o", Values: {"FOO"}
+// CHECK: "-cc1"
+// CHECK: "-E"
+// CHECK: "-U" "FOO"
+// CHECK: "-U" "BAR"
+// CHECK: "-o" "option-aliases.i"
+
+// CHECK-NEXT: "-cc1"
+// CHECK: "-S"
+// CHECK: "-o" "FOO"
diff --git a/test/Driver/parsing.c b/test/Driver/parsing.c
deleted file mode 100644
index eceba37d84fb..000000000000
--- a/test/Driver/parsing.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang -ccc-print-options input -Yunknown -m32 -arch ppc -djoined -A separate -Ajoined -Wp,one,two -Xarch_joined AndSeparate -sectalign 1 2 3 2> %t
-// RUN: grep 'Option 0 - Name: "-ccc-print-options", Values: {}' %t
-// RUN: grep 'Option 1 - Name: "<input>", Values: {"input"}' %t
-// RUN: grep 'Option 2 - Name: "<unknown>", Values: {"-Yunknown"}' %t
-// RUN: grep 'Option 3 - Name: "-m32", Values: {}' %t
-// RUN: grep 'Option 4 - Name: "-arch", Values: {"ppc"}' %t
-// RUN: grep 'Option 5 - Name: "-d", Values: {"joined"}' %t
-// RUN: grep 'Option 6 - Name: "-A", Values: {"separate"}' %t
-// RUN: grep 'Option 7 - Name: "-A", Values: {"joined"}' %t
-// RUN: grep 'Option 8 - Name: "-Wp,", Values: {"one", "two"}' %t
-// RUN: grep 'Option 9 - Name: "-Xarch_", Values: {"joined", "AndSeparate"}' %t
-// RUN: grep 'Option 10 - Name: "-sectalign", Values: {"1", "2", "3"}' %t
-
-// RUN: not %clang -V 2> %t
-// RUN: grep "error: argument to '-V' is missing (expected 1 value)" %t
-// RUN: not %clang -sectalign 1 2 2> %t
-// RUN: grep "error: argument to '-sectalign' is missing (expected 3 values)" %t
-
-// Verify that search continues after find the first option.
-// RUN: %clang -ccc-print-options -Wally 2> %t
-// RUN: grep 'Option 0 - Name: "-ccc-print-options", Values: {}' %t
-// RUN: grep 'Option 1 - Name: "-W", Values: {"ally"}' %t
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 3faed2d18faf..30e1005c9737 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -24,6 +24,8 @@
// CHECK-PIE-LD: "Scrt1.o" "crti.o" "crtbeginS.o"
// CHECK-PIE-LD: "crtendS.o" "crtn.o"
//
+// CHECK-NOPIE-LD: "-nopie"
+//
// CHECK-DYNAMIC-NO-PIC-32: "-mrelocation-model" "dynamic-no-pic"
// CHECK-DYNAMIC-NO-PIC-32-NOT: "-pic-level"
// CHECK-DYNAMIC-NO-PIC-32-NOT: "-pie-level"
@@ -197,3 +199,13 @@
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=6.0.0 -static -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+//
+// On OpenBSD, PIE is enabled by default, but can be disabled.
+// RUN: %clang -c %s -target i386-pc-openbsd -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i386-pc-openbsd -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+//
+// 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
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index be78e19861b3..6959c629e581 100644
--- a/test/Driver/ppc-features.cpp
+++ b/test/Driver/ppc-features.cpp
@@ -4,15 +4,15 @@
// RUN: %clang -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
// RUN: %clang -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
-// RUN: %clang -target i386-pc-win32 -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target x86_64-unknown-freebsd -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target armv6-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target armv7-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %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: invalid argument '-faltivec' only allowed with 'ppc/ppc64'
+// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64/ppc64le'
// Check that -fno-altivec and -mno-altivec correctly disable the altivec
// target feature on powerpc.
@@ -86,3 +86,9 @@
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-fprnd -mfprnd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-FPRND %s
// CHECK-FPRND: "-target-feature" "+fprnd"
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-vsx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOVSX %s
+// CHECK-NOVSX: "-target-feature" "-vsx"
+
+// 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"
+
diff --git a/test/Driver/pth.c b/test/Driver/pth.c
index 4350f46e86f6..e56c34c93bb0 100644
--- a/test/Driver/pth.c
+++ b/test/Driver/pth.c
@@ -3,10 +3,10 @@
// RUN: %clang -no-canonical-prefixes -ccc-pch-is-pth -x c-header %s -o %t.h.pth -### 2> %t.log
// RUN: FileCheck -check-prefix CHECK1 -input-file %t.log %s
-// CHECK1: "{{.*}}/clang{{.*}}" "-cc1" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c"
+// CHECK1: "{{.*[/\\]}}clang{{.*}}" "-cc1" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c"
// RUN: touch %t.h.pth
// RUN: %clang -no-canonical-prefixes -ccc-pch-is-pth -E -include %t.h %s -### 2> %t.log
// RUN: FileCheck -check-prefix CHECK2 -input-file %t.log %s
-// CHECK2: "{{.*}}/clang{{.*}}" "-cc1" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c"
+// CHECK2: "{{.*[/\\]}}clang{{.*}}" "-cc1" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c"
diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c
index f89815739b12..e5d9c95944aa 100644
--- a/test/Driver/qa_override.c
+++ b/test/Driver/qa_override.c
@@ -1,16 +1,12 @@
-// RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " %clang x -O2 b -O3 2>&1 | FileCheck %s
-// RUN: env QA_OVERRIDE_GCC3_OPTIONS="x-Werror +-mfoo" %clang -Werror %s -c 2>&1 | FileCheck %s -check-prefix=RM-WERROR
+// RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-### " %clang -target x86_64-apple-darwin %s -O2 b -O3 2>&1 | FileCheck %s
+// RUN: env QA_OVERRIDE_GCC3_OPTIONS="x-Werror +-msse" %clang -target x86_64-apple-darwin -Werror %s -c -### 2>&1 | FileCheck %s -check-prefix=RM-WERROR
-// FIXME: It seems doesn't work with gcc-driver.
-// REQUIRES: clang-driver
+// CHECK: "-cc1"
+// CHECK-NOT: "-Oignore"
+// CHECK: "-Omagic"
+// CHECK-NOT: "-Oignore"
-// CHECK-NOT: ###
-// CHECK: Option 0 - Name: "-ccc-print-options", Values: {}
-// CHECK-NEXT: Option 1 - Name: "<input>", Values: {"x"}
-// CHECK-NEXT: Option 2 - Name: "-O", Values: {"ignore"}
-// CHECK-NEXT: Option 3 - Name: "-O", Values: {"magic"}
-
-// RM-WERROR: ### QA_OVERRIDE_GCC3_OPTIONS: x-Werror +-mfoo
+// RM-WERROR: ### QA_OVERRIDE_GCC3_OPTIONS: x-Werror +-msse
// RM-WERROR-NEXT: ### Deleting argument -Werror
-// RM-WERROR-NEXT: ### Adding argument -mfoo at end
-// RM-WERROR-NEXT: warning: argument unused during compilation: '-mfoo'
+// RM-WERROR-NEXT: ### Adding argument -msse at end
+// RM-WERROR-NOT: "-Werror"
diff --git a/test/Driver/r600-mcpu.cl b/test/Driver/r600-mcpu.cl
index 1c5e76225b5e..7238ff4fbd20 100644
--- a/test/Driver/r600-mcpu.cl
+++ b/test/Driver/r600-mcpu.cl
@@ -30,6 +30,10 @@
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=bonaire %s -o - 2>&1 | FileCheck --check-prefix=BONAIRE-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=kabini %s -o - 2>&1 | FileCheck --check-prefix=KABINI-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=kaveri %s -o - 2>&1 | FileCheck --check-prefix=KAVERI-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=hawaii %s -o - 2>&1 | FileCheck --check-prefix=HAWAII-CHECK %s
// R600-CHECK: "-target-cpu" "r600"
// RS880-CHECK: "-target-cpu" "rs880"
@@ -50,3 +54,7 @@
// PITCAIRN-CHECK: "-target-cpu" "pitcairn"
// VERDE-CHECK: "-target-cpu" "verde"
// OLAND-CHECK: "-target-cpu" "oland"
+// BONAIRE-CHECK: "-target-cpu" "bonaire"
+// KABINI-CHECK: "-target-cpu" "kabini"
+// KAVERI-CHECK: "-target-cpu" "kaveri"
+// HAWAII-CHECK: "-target-cpu" "hawaii"
diff --git a/test/Driver/rewrite-legacy-objc.m b/test/Driver/rewrite-legacy-objc.m
index 2e3f4218ef2d..0c6404e323de 100644
--- a/test/Driver/rewrite-legacy-objc.m
+++ b/test/Driver/rewrite-legacy-objc.m
@@ -3,5 +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" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-default-synthesize-properties" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-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" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index fa159a625824..95db58294d2a 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" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fobjc-dispatch-method=mixed" "-fobjc-default-synthesize-properties" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index fd7e97fc20f8..691b44bba262 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -152,4 +152,37 @@
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHARED %s
// CHECK-UBSAN-LINUX-SHARED: "{{.*}}ld{{(.exe)?}}"
-// CHECK-UBSAN-LINUX-SHARED-NOT: libclang_rt.ubsan-i386.a"
+// CHECK-UBSAN-LINUX-SHARED: libclang_rt.ubsan-i386.a"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux -fsanitize=leak \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LSAN-LINUX %s
+//
+// CHECK-LSAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-LSAN-LINUX-NOT: "-lc"
+// CHECK-LSAN-LINUX: libclang_rt.lsan-x86_64.a"
+// CHECK-LSAN-LINUX: "-lpthread"
+// CHECK-LSAN-LINUX: "-ldl"
+
+// RUN: %clang -fsanitize=leak,undefined %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LSAN-UBSAN-LINUX %s
+// CHECK-LSAN-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LSAN-UBSAN-LINUX-NOT: libclang_rt.san
+// CHECK-LSAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.lsan-x86_64.a" "-no-whole-archive"
+// CHECK-LSAN-UBSAN-LINUX-NOT: libclang_rt.san
+// CHECK-LSAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-x86_64.a" "-no-whole-archive"
+// CHECK-LSAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
+// CHECK-LSAN-UBSAN-LINUX: "-lpthread"
+// CHECK-LSAN-UBSAN-LINUX-NOT: "-lstdc++"
+
+// RUN: %clang -fsanitize=leak,address %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LSAN-ASAN-LINUX %s
+// CHECK-LSAN-ASAN-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
+// CHECK-LSAN-ASAN-LINUX: libclang_rt.asan-x86_64
+// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c
index d8a9fe841e27..792abbd55259 100644
--- a/test/Driver/split-debug.c
+++ b/test/Driver/split-debug.c
@@ -23,3 +23,13 @@
// RUN: FileCheck -check-prefix=CHECK-OPTION < %t %s
//
// CHECK-OPTION: "-split-dwarf-file" "split-debug.dwo"
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -S -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-ASM < %t %s
+//
+// CHECK-ASM-NOT: objcopy
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -no-integrated-as -gsplit-dwarf -c -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-IAS < %t %s
+//
+// CHECK-IAS: objcopy
diff --git a/test/Driver/stack-protector.c b/test/Driver/stack-protector.c
index 5f3d679c1ade..2eb0f53530a7 100644
--- a/test/Driver/stack-protector.c
+++ b/test/Driver/stack-protector.c
@@ -9,3 +9,9 @@
// RUN: %clang -fstack-protector --param ssp-buffer-size=16 -### %s 2>&1 | FileCheck %s -check-prefix=SSP-BUF
// SSP-BUF: "-stack-protector" "1"
// SSP-BUF: "-stack-protector-buffer-size" "16"
+
+// RUN: %clang -target i386-pc-openbsd -### %s 2>&1 | FileCheck %s -check-prefix=OPENBSD
+// OPENBSD: "-stack-protector" "1"
+
+// RUN: %clang -target i386-pc-openbsd -fno-stack-protector -### %s 2>&1 | FileCheck %s -check-prefix=OPENBSD_OFF
+// OPENBSD_OFF-NOT: "-stack-protector"
diff --git a/test/Driver/std.cpp b/test/Driver/std.cpp
index 822658c837dc..e98fd2c6bf18 100644
--- a/test/Driver/std.cpp
+++ b/test/Driver/std.cpp
@@ -1,12 +1,12 @@
-// RUN: %clang -std=c++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
-// RUN: %clang -std=gnu++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX98 %s
-// RUN: %clang -std=c++03 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
-// RUN: %clang -std=c++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
-// RUN: %clang -std=gnu++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
-// RUN: %clang -std=c++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
-// RUN: %clang -std=gnu++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
-// RUN: %clang -std=c++1y %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX1Y %s
-// RUN: %clang -std=gnu++1y %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX1Y %s
+// RUN: not %clang -std=c++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
+// RUN: not %clang -std=gnu++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX98 %s
+// RUN: not %clang -std=c++03 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
+// RUN: not %clang -std=c++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
+// RUN: not %clang -std=gnu++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
+// RUN: not %clang -std=c++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
+// RUN: not %clang -std=gnu++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
+// RUN: not %clang -std=c++1y %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX1Y %s
+// RUN: not %clang -std=gnu++1y %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX1Y %s
void f(int n) {
typeof(n)();
diff --git a/test/Driver/systemz-march.c b/test/Driver/systemz-march.c
new file mode 100644
index 000000000000..ffc126f14fe1
--- /dev/null
+++ b/test/Driver/systemz-march.c
@@ -0,0 +1,13 @@
+// Check that -march works for all supported targets.
+
+// RUN: not %clang -target s390x -S -emit-llvm -march=z9 %s -o - 2>&1 | FileCheck --check-prefix=CHECK-Z9 %s
+// RUN: %clang -target s390x -### -S -emit-llvm -march=z10 %s 2>&1 | FileCheck --check-prefix=CHECK-Z10 %s
+// RUN: %clang -target s390x -### -S -emit-llvm -march=z196 %s 2>&1 | FileCheck --check-prefix=CHECK-Z196 %s
+// RUN: %clang -target s390x -### -S -emit-llvm -march=zEC12 %s 2>&1 | FileCheck --check-prefix=CHECK-ZEC12 %s
+
+// CHECK-Z9: error: unknown target CPU 'z9'
+// CHECK-Z10: "-target-cpu" "z10"
+// CHECK-Z196: "-target-cpu" "z196"
+// CHECK-ZEC12: "-target-cpu" "zEC12"
+
+int x;
diff --git a/test/Driver/target-as.s b/test/Driver/target-as.s
index adb3d10f14ea..4881a330b56a 100644
--- a/test/Driver/target-as.s
+++ b/test/Driver/target-as.s
@@ -1,5 +1,3 @@
-// REQUIRES: clang-driver
-
// Make sure the -march is passed down to cc1as.
// RUN: %clang -target i386-unknown-freebsd -### -c -integrated-as %s \
// RUN: -march=geode 2>&1 | FileCheck -check-prefix=TARGET %s
diff --git a/test/Driver/target.c b/test/Driver/target.c
index 59147e0fbffd..b400f990fb1b 100644
--- a/test/Driver/target.c
+++ b/test/Driver/target.c
@@ -1,4 +1,4 @@
-// RUN: %clang -no-canonical-prefixes -target unknown-unknown-unknown -c %s \
+// RUN: %clang -no-canonical-prefixes --target=unknown-unknown-unknown -c %s \
// RUN: -o %t.o -### 2>&1 | FileCheck %s
//
// Ensure we get a crazy triple here as we asked for one.
@@ -9,3 +9,7 @@
// CHECK-NOT: "-target"
// CHECK-NOT: "unknown-unknown-unknown"
// CHECK: "-x" "assembler"
+//
+// Also check that the legacy spelling works.
+// RUN: %clang -no-canonical-prefixes -target unknown-unknown-unknown -c %s \
+// RUN: -o %t.o -### 2>&1 | FileCheck %s
diff --git a/test/Driver/tsan.c b/test/Driver/tsan.c
index 18b027fbceec..82a0785c07ac 100644
--- a/test/Driver/tsan.c
+++ b/test/Driver/tsan.c
@@ -1,8 +1,8 @@
-// RUN: %clang -target i386-unknown-unknown -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O1 -target i386-unknown-unknown -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O2 -target i386-unknown-unknown -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O3 -target i386-unknown-unknown -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -target i386-unknown-unknown -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -target x86_64-unknown-linux -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O1 -target x86_64-unknown-linux -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O3 -target x86_64-unknown-linux -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -target x86_64-unknown-linux -fsanitize=thread %s -S -emit-llvm -o - | FileCheck %s
// Verify that -fsanitize=thread invokes tsan instrumentation.
int foo(int *a) { return *a; }
diff --git a/test/Driver/unknown-arg.c b/test/Driver/unknown-arg.c
index 0fab8a50b99e..f834a0e8db92 100644
--- a/test/Driver/unknown-arg.c
+++ b/test/Driver/unknown-arg.c
@@ -1,6 +1,15 @@
-// RUN: not %clang_cc1 %s -cake-is-lie -%0 -%d 2> %t.log
-// RUN: FileCheck %s -input-file=%t.log
+// 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
-// CHECK: unknown argument
-// CHECK: unknown argument
-// CHECK: unknown argument
+// CHECK: unknown argument: '-cake-is-lie'
+// CHECK: unknown argument: '-%0'
+// CHECK: unknown argument: '-%d'
+// CHECK: unknown argument: '-HHHH'
+// CHECK: unknown argument: '-munknown-to-clang-option'
+// CHECK: unknown argument: '-print-stats'
+// CHECK: unknown argument: '-funknown-to-clang-option'
+
+
+// RUN: %clang -S %s -o %t.s -Wunknown-to-clang-option 2>&1 | FileCheck --check-prefix=IGNORED %s
+
+// IGNORED: warning: unknown warning option '-Wunknown-to-clang-option'
diff --git a/test/Driver/working-directory.c b/test/Driver/working-directory.c
index 38a87a6402af..195abaca6f0c 100644
--- a/test/Driver/working-directory.c
+++ b/test/Driver/working-directory.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-print-options -working-directory "C:\Test" input 2>&1 | FileCheck %s
-// CHECK: Option 0 - Name: "-ccc-print-options", Values: {}
-// CHECK: Option 1 - Name: "-working-directory", Values: {"C:\Test"}
-// CHECK: Option 2 - Name: "<input>", Values: {"input"}
+// RUN: %clang -### -working-directory /no/such/dir/ input 2>&1 | FileCheck %s
+// REQUIRES: shell-preserves-root
+
+//CHECK: no such file or directory: '/no/such/dir/input'
diff --git a/test/Driver/x86_64-nacl-defines.cpp b/test/Driver/x86_64-nacl-defines.cpp
index b7c894036cd4..87d02d7e10f7 100644
--- a/test/Driver/x86_64-nacl-defines.cpp
+++ b/test/Driver/x86_64-nacl-defines.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang -target x86_64-unknown-nacl -ccc-echo %s -emit-llvm-only -c -o %t.o 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target x86_64-unknown-nacl -### %s -emit-llvm-only -c -o %t.o 2>&1 | FileCheck %s -check-prefix=ECHO
// RUN: %clang -target x86_64-unknown-nacl %s -emit-llvm -S -c -o - | FileCheck %s
// RUN: %clang -target x86_64-unknown-nacl %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
-// ECHO: {{.*}} -cc1 {{.*}}x86_64-nacl-defines.c
+// ECHO: {{.*}} "-cc1" {{.*}}x86_64-nacl-defines.c
// Check platform defines
diff --git a/test/Driver/x86_features.c b/test/Driver/x86_features.c
index 5c65e31ff45c..26f0bd8bcf01 100644
--- a/test/Driver/x86_features.c
+++ b/test/Driver/x86_features.c
@@ -1,3 +1,7 @@
-// RUN: %clang -target i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2> %t
-// RUN: grep '"pentium4" "-target-feature" "+sse4" "-target-feature" "-mmx" "-target-feature" "+sse"' %t
+// RUN: %clang -target i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2>&1 | FileCheck %s
+// CHECK: "pentium4" "-target-feature" "+sse4" "-target-feature" "-mmx" "-target-feature" "+sse"
// Note that we filter out all but the last -m(no)sse.
+
+// Test that we don't produce an error with -mieee-fp.
+// RUN: %clang -### %s -mieee-fp -S 2>&1 | FileCheck --check-prefix=IEEE %s
+// IEEE-NOT: error: unknown argument
diff --git a/test/Driver/xcore-opts.c b/test/Driver/xcore-opts.c
new file mode 100644
index 000000000000..10d8da172d4a
--- /dev/null
+++ b/test/Driver/xcore-opts.c
@@ -0,0 +1,13 @@
+// RUN: %clang -target xcore %s -g -Wl,L1Arg,L2Arg -Wa,A1Arg,A2Arg -### -o %t.o 2>&1 | FileCheck %s
+
+// CHECK: "-nostdsysteminc"
+// CHECK: "-momit-leaf-frame-pointer"
+// CHECK-NOT: "-mdisable-fp-elim"
+// CHECK: "-fno-signed-char"
+// CHECK: "-fno-use-cxa-atexit"
+// CHECK: "-fno-common"
+// CHECH: xcc" "-o"
+// CHECK: "-c" "-g" "A1Arg" "A2Arg"
+// CHECK: xcc" "-o"
+// CHECK: "L1Arg" "L2Arg"
+
diff --git a/test/FixIt/bridge-cast-in-arc.mm b/test/FixIt/bridge-cast-in-arc.mm
index 5cd482fabc04..d32629d7c700 100644
--- a/test/FixIt/bridge-cast-in-arc.mm
+++ b/test/FixIt/bridge-cast-in-arc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c++ -fobjc-arc %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c++ -fobjc-arc %s 2>&1 | FileCheck %s
// rdar://12788838
id obj;
diff --git a/test/FixIt/fixit-autoreleasepool.m b/test/FixIt/fixit-autoreleasepool.m
index ba1ad130f22a..06c45448fd21 100644
--- a/test/FixIt/fixit-autoreleasepool.m
+++ b/test/FixIt/fixit-autoreleasepool.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
// rdar://10723084
void f0() {
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 1f6275f933bc..bfd8c3dcfea6 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -132,3 +132,8 @@ namespace NonStaticConstexpr {
}
};
}
+
+int RegisterVariable() {
+ register int n; // expected-warning {{'register' storage class specifier is deprecated}}
+ return n;
+}
diff --git a/test/FixIt/fixit-cxx11-attributes.cpp b/test/FixIt/fixit-cxx11-attributes.cpp
index f28bdfc7cd90..30697a900026 100644
--- a/test/FixIt/fixit-cxx11-attributes.cpp
+++ b/test/FixIt/fixit-cxx11-attributes.cpp
@@ -2,7 +2,7 @@
// RUN: cp %s %t
// RUN: not %clang_cc1 -x c++ -std=c++11 -fixit %t
// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++11 %t
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
namespace ClassSpecifier {
class [[]] [[]]
diff --git a/test/FixIt/fixit-errors-1.c b/test/FixIt/fixit-errors-1.c
index b034b1973471..0dbbe198e061 100644
--- a/test/FixIt/fixit-errors-1.c
+++ b/test/FixIt/fixit-errors-1.c
@@ -1,6 +1,6 @@
// RUN: cp %s %t
// RUN: %clang_cc1 -pedantic -fixit %t
-// RUN: echo %clang_cc1 -pedantic -Werror -x c %t
+// RUN: %clang_cc1 -pedantic -Werror -x c %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-include.c b/test/FixIt/fixit-include.c
index 383c51386ab7..fd5d7a9ac142 100644
--- a/test/FixIt/fixit-include.c
+++ b/test/FixIt/fixit-include.c
@@ -3,7 +3,7 @@
// RUN: cp %S/fixit-include.h %T
// RUN: not %clang_cc1 -fsyntax-only -fixit %t
// RUN: %clang_cc1 -Wall -pedantic %t
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// 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}
diff --git a/test/FixIt/fixit-interface-as-param.m b/test/FixIt/fixit-interface-as-param.m
index 3295c82c31a1..75da5720d7f0 100644
--- a/test/FixIt/fixit-interface-as-param.m
+++ b/test/FixIt/fixit-interface-as-param.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
// rdar://11311333
@interface NSView @end
diff --git a/test/FixIt/fixit-objc-message-comma-separator.m b/test/FixIt/fixit-objc-message-comma-separator.m
index 0caa33eb0ad2..748553e73060 100644
--- a/test/FixIt/fixit-objc-message-comma-separator.m
+++ b/test/FixIt/fixit-objc-message-comma-separator.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
// rdar://11376372
@class NSObject;
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index ea57fe671b94..7c4776ae71e7 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -27,13 +27,13 @@ void g(NSString *a); // expected-note{{passing argument to parameter 'a' here}}
void h(id a); // expected-note 2{{passing argument to parameter 'a' here}}
void f(Test *t) {
- NSString *a = "Foo"; // expected-warning {{incompatible pointer types initializing 'NSString *' with an expression of type 'char [4]'}}
+ NSString *a = "Foo"; // expected-warning {{string literal must be prefixed by '@'}}
id b = "Foo"; // expected-warning {{incompatible pointer types initializing 'id' with an expression of type 'char [4]'}}
- g("Foo"); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'NSString *'}}
+ g("Foo"); // expected-warning {{string literal must be prefixed by '@'}}
h("Foo"); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'id'}}
h(("Foo")); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'id'}}
- [t test:"Foo"]; // expected-warning{{incompatible pointer types sending 'char [4]' to parameter of type 'NSString *'}}
- t.property = "Foo"; // expected-warning{{incompatible pointer types assigning to 'NSString *' from 'char [4]'}}
+ [t test:"Foo"]; // expected-warning {{string literal must be prefixed by '@'}}
+ t.property = "Foo"; // expected-warning {{string literal must be prefixed by '@'}}
// <rdar://problem/6896493>
[t test:@"Foo"]]; // expected-error{{extraneous ']' before ';'}}
diff --git a/test/FixIt/fixit-static-object-decl.m b/test/FixIt/fixit-static-object-decl.m
index e13900fa786f..5f4feada4905 100644
--- a/test/FixIt/fixit-static-object-decl.m
+++ b/test/FixIt/fixit-static-object-decl.m
@@ -5,8 +5,8 @@
// Objective-C++ recovery
// RUN: cp %s %t
-// RUN: not %clang_cc1 -fixit -x objective-c++ %t
-// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c++ %t
+// RUN: not %clang_cc1 -fixit -x objective-c++ %t -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c++ %t -std=c++11
// rdar://9603056
@interface S @end
@@ -24,6 +24,14 @@ NSArray func() {
return P;
}
+NSArray (func2)() { return 0; }
+
+#ifdef __cplusplus
+void test_result_type() {
+ auto l1 = [] () -> NSArray { return 0; };
+}
+#endif
+
int main() {
NSArray pluginNames = [NSArray arrayWithObjects];
}
diff --git a/test/FixIt/fixit-unicode-with-utf8-output.c b/test/FixIt/fixit-unicode-with-utf8-output.c
new file mode 100644
index 000000000000..aff854274324
--- /dev/null
+++ b/test/FixIt/fixit-unicode-with-utf8-output.c
@@ -0,0 +1,24 @@
+// This test is an additional set of checks for the fixit-unicode.c test for
+// systems capable of outputting Unicode characters to the standard output in
+// the UTF-8 encoding.
+// RUN: not %clang_cc1 -fsyntax-only %S/fixit-unicode.c 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: warning: format specifies type 'int' but the argument has type 'long'
+// CHECK: {{^ printf\("∆: %d", 1L\);}}
+// CHECK: {{^ ~~ \^~}}
+
+// CHECK: error: use of undeclared identifier 'à¸sss'; did you mean 'à¸ssss'?
+// CHECK: {{^ \^}}
+// CHECK: {{^ à¸ssss}}
+
+// CHECK: error: use of undeclared identifier 'ssà¸s'; did you mean 'ssà¸ss'?
+// CHECK: {{^ \^}}
+// CHECK: {{^ ssà¸ss}}
+
+// CHECK: error: use of undeclared identifier 'ss一二三'; did you mean 's一二三'?
+// CHECK: {{^ \^~~~~~~~}}
+// CHECK: {{^ s一二三}}
+
+// CHECK: error: use of undeclared identifier 'sssssssss'; did you mean 'sssssssssà¸'?
+// CHECK: {{^ \^}}
+// CHECK: {{^ sssssssssà¸}}
diff --git a/test/FixIt/fixit-unicode.c b/test/FixIt/fixit-unicode.c
index 9c0242e92e3b..360ac6957495 100644
--- a/test/FixIt/fixit-unicode.c
+++ b/test/FixIt/fixit-unicode.c
@@ -1,5 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -check-prefix=CHECK-MACHINE %s
+// This file contains code and checks, that should work on any platform.
+// There's a set of additional checks for systems with proper support of UTF-8
+// on the standard output in fixit-unicode-with-utf8-output.c.
+
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -check-prefix=CHECK-MACHINE %s
struct Foo {
int bar;
@@ -16,8 +20,8 @@ void test1() {
// CHECK: {{^ \^}}
// CHECK: {{^ ;}}
-// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-8]]:15-[[@LINE-8]]:18}:""
-// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-9]]:15-[[@LINE-9]]:15}:";"
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-8]]:15-[[@LINE-8]]:18}:""
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-9]]:15-[[@LINE-9]]:15}:";"
}
@@ -32,5 +36,30 @@ void test2() {
// because different systems will render the delta differently (either as a
// character, or as <U+2206>.) The fixit should line up with the %d regardless.
-// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-9]]:16-[[@LINE-9]]:18}:"%ld"
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-9]]:16-[[@LINE-9]]:18}:"%ld"
+}
+
+void test3() {
+ int à¸ssss = 42;
+ int a = à¸sss; // expected-error{{use of undeclared identifier 'à¸sss'; did you mean 'à¸ssss'?}}
+// CHECK: {{^ \^}}
+// CHECK: {{^ [^ ]+ssss}}
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:17}:"\340\270\201ssss"
+
+ int ssà¸ss = 42;
+ int b = ssà¸s; // expected-error{{use of undeclared identifier 'ssà¸s'; did you mean 'ssà¸ss'?}}
+// CHECK: {{^ \^}}
+// CHECK: {{^ ss.+ss}}
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:17}:"ss\340\270\201ss"
+
+ int s一二三 = 42;
+ int b一二三四五六七 = ss一二三; // expected-error{{use of undeclared identifier 'ss一二三'; did you mean 's一二三'?}}
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-1]]:32-[[@LINE-1]]:43}:"s\344\270\200\344\272\214\344\270\211"
+
+
+ int sssssssssภ= 42;
+ int c = sssssssss; // expected-error{{use of undeclared identifier 'sssssssss'; did you mean 'sssssssssà¸'?}}
+// CHECK: {{^ \^}}
+// CHECK: {{^ sssssssss.+}}
+// CHECK-MACHINE: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:20}:"sssssssss\340\270\201"
}
diff --git a/test/FixIt/fixit-uninit.c b/test/FixIt/fixit-uninit.c
new file mode 100644
index 000000000000..853041e05b07
--- /dev/null
+++ b/test/FixIt/fixit-uninit.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+_Bool test_bool_no_false() {
+ _Bool var; // expected-note {{initialize}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:12-[[@LINE-1]]:12}:" = 0"
+ return var; // expected-warning {{uninitialized}}
+}
+
+#define bool _Bool
+#define false (bool)0
+#define true (bool)1
+bool test_bool_with_false() {
+ bool var; // expected-note {{initialize}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:" = false"
+ return var; // expected-warning {{uninitialized}}
+}
+
+bool test_bool_with_false_undefined() {
+ bool
+#undef false
+ var; // expected-note {{initialize}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:10}:" = 0"
+ return var; // expected-warning {{uninitialized}}
+}
diff --git a/test/FixIt/fixit-vexing-parse.cpp b/test/FixIt/fixit-vexing-parse.cpp
index dd0f87304a53..79d8cad6bb9f 100644
--- a/test/FixIt/fixit-vexing-parse.cpp
+++ b/test/FixIt/fixit-vexing-parse.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -verify -x c++ %s
-// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
struct S {
int n;
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 00adb19e50ce..6443fe53c2a1 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -115,3 +115,5 @@ struct noSemiAfterStruct {
enum noSemiAfterEnum {
e1
} // expected-error {{expected ';' after enum}}
+
+int PR17175 __attribute__((visibility(hidden))); // expected-error {{'visibility' attribute requires a string}}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index fca596b715de..52bbb3849a8f 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ %t
@@ -307,3 +307,34 @@ namespace dtor_fixit {
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo"
};
}
+
+namespace PR5066 {
+ template<typename T> struct X {};
+ X<int *p> x; // expected-error {{type-id cannot have a name}}
+}
+
+namespace PR5898 {
+ class A {
+ public:
+ const char *str();
+ };
+ const char* foo(A &x)
+ {
+ return x.str.(); // expected-error {{unexpected '.' in function call; perhaps remove the '.'?}}
+ }
+ bool bar(A x, const char *y) {
+ return foo->(x) == y; // expected-error {{unexpected '->' in function call; perhaps remove the '->'?}}
+ }
+}
+
+namespace PR15045 {
+ class Cl0 {
+ public:
+ int a;
+ };
+
+ int f() {
+ Cl0 c;
+ return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}}
+ }
+}
diff --git a/test/FixIt/format.m b/test/FixIt/format.m
index 919212b30678..5e4636047e86 100644
--- a/test/FixIt/format.m
+++ b/test/FixIt/format.m
@@ -186,26 +186,26 @@ void test_percent_C() {
const unsigned short data = 'a';
NSLog(@"%C", data); // no-warning
- NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ NSLog(@"%C", 0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unsigned short)"
typedef unsigned short unichar;
- NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ NSLog(@"%C", 0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
- NSLog(@"%C", data ? 0x2F : 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ NSLog(@"%C", data ? 0x2F0000 : 0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)("
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:36-[[@LINE-3]]:36}:")"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:42-[[@LINE-3]]:42}:")"
NSLog(@"%C", 0.0); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'double'}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%f"
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
- NSLog(@"%C", (char)0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}}
+ NSLog(@"%C", (char)0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:"(unichar)"
diff --git a/test/FixIt/format.mm b/test/FixIt/format.mm
index 64c6c47b9b63..9d89c062faa9 100644
--- a/test/FixIt/format.mm
+++ b/test/FixIt/format.mm
@@ -11,7 +11,7 @@ void test_percent_C() {
NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'wchar_t'}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"(unsigned short)"
- NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ NSLog(@"%C", 0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unsigned short)"
@@ -20,7 +20,7 @@ void test_percent_C() {
NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'wchar_t'}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"(unichar)"
- NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ NSLog(@"%C", 0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
diff --git a/test/FixIt/lit.local.cfg b/test/FixIt/lit.local.cfg
new file mode 100644
index 000000000000..5bbc711c656d
--- /dev/null
+++ b/test/FixIt/lit.local.cfg
@@ -0,0 +1,2 @@
+if config.root.clang_rewriter == 0:
+ config.unsupported = True
diff --git a/test/FixIt/messages.cpp b/test/FixIt/messages.cpp
index b9391449ad16..eb4c09d629ed 100644
--- a/test/FixIt/messages.cpp
+++ b/test/FixIt/messages.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 2>&1 %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 2>&1 %s | FileCheck -strict-whitespace %s
struct A {
unsigned int a;
diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp
index 9da29229f041..7e8e1fbbb07b 100644
--- a/test/FixIt/no-fixit.cpp
+++ b/test/FixIt/no-fixit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
// test that the diagnostics produced by this code do not include fixit hints
diff --git a/test/FixIt/selector-fixit.m b/test/FixIt/selector-fixit.m
new file mode 100644
index 000000000000..e9d2f19df1a1
--- /dev/null
+++ b/test/FixIt/selector-fixit.m
@@ -0,0 +1,41 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x objective-c -Wundeclared-selector -fixit %t
+// RUN: %clang_cc1 -x objective-c -Wundeclared-selector -Werror %t
+// rdar://14039037
+
+@interface NSObject @end
+
+@interface LogoutController : NSObject
+- (void)close;
+- (void)closed;
+- (void) open : (id) file_id;
+@end
+
+@implementation LogoutController
+
+- (void)close { }
+- (void)closed { }
+
+- (SEL)Meth
+{
+ return @selector(cloze);
+}
+- (void) open : (id) file_id {}
+
+- (SEL)Meth1
+{
+ return @selector(ope:);
+}
+
+@end
+
+// rdar://7853549
+@interface rdar7853549 : NSObject
+- (int) bounds;
+@end
+
+@implementation rdar7853549
+- (int) bounds { return 0; }
+- (void)PrivateMeth { int bounds = [self bonds]; }
+- (void)OtherPrivateMeth : (id) p { int bounds = [p bonds]; }
+@end
diff --git a/test/FixIt/typo-crash.cpp b/test/FixIt/typo-crash.cpp
index c154e3baba4f..4ea63c542a89 100644
--- a/test/FixIt/typo-crash.cpp
+++ b/test/FixIt/typo-crash.cpp
@@ -19,11 +19,12 @@ namespace PR12297 {
namespace B {
typedef short T;
- T global(); // expected-note {{'A::B::global' declared here}}
+ T global(); // expected-note {{'::PR12297::global' declared here}}
}
}
using namespace A::B;
- T A::global(); // expected-error {{out-of-line definition of 'global' does not match any declaration in namespace 'PR12297::A'; did you mean 'A::B::global'?}}
+ // FIXME: Adding '::PR12297::' is not needed as removing 'A::' is sufficient
+ T A::global(); // expected-error {{out-of-line declaration of 'global' does not match any declaration in namespace 'PR12297::A'; did you mean '::PR12297::global'?}}
}
diff --git a/test/FixIt/typo-location-bugs.cpp b/test/FixIt/typo-location-bugs.cpp
new file mode 100644
index 000000000000..9c34a91d49c7
--- /dev/null
+++ b/test/FixIt/typo-location-bugs.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
+
+namespace dcl_fct_default_p10 {
+struct A {
+ virtual void f(int a = 7); // expected-note{{'A::f' declared here}}
+};
+
+struct B : public A {
+ void f(int a);
+};
+
+void m() {
+ B* pb = new B;
+ A* pa = pb;
+ pa->f(); // OK, calls pa->B::f(7)
+ pb->f(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean 'A::f'?}}
+}
+}
diff --git a/test/FixIt/typo-using.cpp b/test/FixIt/typo-using.cpp
new file mode 100644
index 000000000000..e676b1074f9f
--- /dev/null
+++ b/test/FixIt/typo-using.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
+// RUN: grep using_suggestion_tyname_ty_dropped_specifier %t
+
+// These tests have been separated from typo.cpp to keep the maximum typo
+// correction counter from ticking over; this causes spurious failures.
+
+namespace using_suggestion_ty {
+namespace N { class AAA {}; } // expected-note {{'AAA' declared here}}
+using N::AAB; // expected-error {{no member named 'AAB' in namespace 'using_suggestion_ty::N'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_tyname_ty {
+namespace N { class AAA {}; } // expected-note {{'AAA' declared here}}
+using typename N::AAB; // expected-error {{no member named 'AAB' in namespace 'using_suggestion_tyname_ty::N'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_val {
+namespace N { void FFF() {} } // expected-note {{'FFF' declared here}}
+using N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_val::N'; did you mean 'FFF'?}}
+}
+
+namespace using_suggestion_ty_dropped_specifier {
+class ABC {}; // expected-note {{'::using_suggestion_ty_dropped_specifier::ABC' declared here}}
+namespace N { }
+using N::ABC; // expected-error {{no member named 'ABC' in namespace 'using_suggestion_ty_dropped_specifier::N'; did you mean '::using_suggestion_ty_dropped_specifier::ABC'?}}
+}
+
+namespace using_suggestion_tyname_ty_dropped_specifier {
+class BCD {}; // expected-note {{'::using_suggestion_tyname_ty_dropped_specifier::BCD' declared here}}
+namespace N { }
+using typename N::BCD; // expected-error {{no member named 'BCD' in namespace 'using_suggestion_tyname_ty_dropped_specifier::N'; did you mean '::using_suggestion_tyname_ty_dropped_specifier::BCD'?}}
+}
+
+namespace using_suggestion_val_dropped_specifier {
+void EFG() {} // expected-note {{'::using_suggestion_val_dropped_specifier::EFG' declared here}}
+namespace N { }
+using N::EFG; // expected-error {{no member named 'EFG' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::EFG'?}}
+}
+
+namespace using_suggestion_member_ty {
+class CCC { public: typedef int AAA; }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_ty::CCC'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_member_val {
+class CCC { public: void AAA() { } }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_val::CCC'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_member_tyname_ty {
+class CCC { public: typedef int AAA; }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using typename CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_tyname_ty::CCC'; did you mean 'AAA'?}}
+}
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 8e380c94979a..4f4c67b538f2 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c %t
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index b3568a5bbf73..2a743991be41 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -5,8 +5,7 @@
// RUN: grep test_string %t
namespace std {
- template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}} \
- // expected-note {{'otherstd::basic_string' declared here}}
+ template<typename T> class basic_string { // expected-note 3{{'basic_string' declared here}}
public:
int find(const char *substr); // expected-note{{'find' declared here}}
static const int npos = -1; // expected-note{{'npos' declared here}}
@@ -84,8 +83,12 @@ namespace nonstd {
yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}}
wibble::yarn str5; // expected-error{{no type named 'yarn' in namespace 'otherstd'; did you mean 'nonstd::yarn'?}}
+namespace another {
+ template<typename T> class wide_string {}; // expected-note {{'another::wide_string' declared here}}
+}
int poit() {
- nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean 'otherstd::basic_string'?}}
+ nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean simply 'basic_string'?}}
+ nonstd::wide_string<char> str2; // expected-error{{no template named 'wide_string' in namespace 'nonstd'; did you mean 'another::wide_string'?}}
return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}}
}
@@ -124,3 +127,11 @@ void func2() {
// to replace base::i with derived::i as we would for other qualified name misspellings.
// d.base::i = 3;
}
+
+class A {
+ void bar(int);
+};
+void bar(int, int); // expected-note{{'::bar' declared here}}
+void A::bar(int x) {
+ bar(x, 5); // expected-error{{too many arguments to function call, expected 1, have 2; did you mean '::bar'?}}
+}
diff --git a/test/Format/cursor.cpp b/test/Format/cursor.cpp
new file mode 100644
index 000000000000..d9aab5acb635
--- /dev/null
+++ b/test/Format/cursor.cpp
@@ -0,0 +1,6 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t2.cpp
+// RUN: clang-format -style=LLVM %t2.cpp -cursor=6 > %t.cpp
+// RUN: FileCheck -strict-whitespace -input-file=%t.cpp %s
+// CHECK: {{^\{ "Cursor": 4 \}$}}
+// CHECK: {{^int\ \i;$}}
+ int i;
diff --git a/test/Format/diagnostic.cpp b/test/Format/diagnostic.cpp
deleted file mode 100644
index 2e930ee5b790..000000000000
--- a/test/Format/diagnostic.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: clang-format 2>&1 >/dev/null %s |FileCheck %s
-
-}
-// CHECK: diagnostic.cpp:[[@LINE-1]]:1: error: unexpected '}'
diff --git a/test/Format/line-ranges.cpp b/test/Format/line-ranges.cpp
new file mode 100644
index 000000000000..370445aed1e1
--- /dev/null
+++ b/test/Format/line-ranges.cpp
@@ -0,0 +1,11 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-format -style=LLVM -lines=1:1 -lines=5:5 -i %t.cpp
+// RUN: FileCheck -strict-whitespace -input-file=%t.cpp %s
+// CHECK: {{^int\ \*i;$}}
+ int*i;
+
+// CHECK: {{^\ \ int\ \ \*\ \ i;$}}
+ int * i;
+
+// CHECK: {{^\ \ int\ \*i;$}}
+ int * i;
diff --git a/test/Format/multiple-inputs-error.cpp b/test/Format/multiple-inputs-error.cpp
index 71f87e0b15b2..1aa9c9f3e2fa 100644
--- a/test/Format/multiple-inputs-error.cpp
+++ b/test/Format/multiple-inputs-error.cpp
@@ -1,6 +1,8 @@
// RUN: cp %s %t-1.cpp
// RUN: cp %s %t-2.cpp
-// RUN: clang-format 2>&1 >/dev/null -offset=1 -length=0 %t-1.cpp %t-2.cpp |FileCheck %s
-// CHECK: error: "-offset" and "-length" can only be used for single file.
+// RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=0 %t-1.cpp %t-2.cpp |FileCheck %s
+// RUN: not clang-format 2>&1 >/dev/null -lines=1:1 %t-1.cpp %t-2.cpp |FileCheck %s -check-prefix=CHECK-LINE
+// CHECK: error: -offset, -length and -lines can only be used for single file.
+// CHECK-LINE: error: -offset, -length and -lines can only be used for single file.
int i ;
diff --git a/test/Format/style-on-command-line.cpp b/test/Format/style-on-command-line.cpp
new file mode 100644
index 000000000000..22131a1ebe1b
--- /dev/null
+++ b/test/Format/style-on-command-line.cpp
@@ -0,0 +1,29 @@
+// RUN: grep -Ev "// *[A-Z0-9_]+:" %s > %t.cpp
+// RUN: clang-format -style="{BasedOnStyle: Google, IndentWidth: 8}" %t.cpp | FileCheck -strict-whitespace -check-prefix=CHECK1 %s
+// RUN: clang-format -style="{BasedOnStyle: LLVM, IndentWidth: 7}" %t.cpp | FileCheck -strict-whitespace -check-prefix=CHECK2 %s
+// RUN: clang-format -style="{BasedOnStyle: invalid, IndentWidth: 7}" %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK3 %s
+// RUN: clang-format -style="{lsjd}" %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK4 %s
+// RUN: [ ! -e %T/.clang-format ] || rm %T/.clang-format
+// RUN: printf "BasedOnStyle: google\nIndentWidth: 5\n" > %T/.clang-format
+// RUN: clang-format -style=file %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK5 %s
+// RUN: printf "\n" > %T/.clang-format
+// RUN: clang-format -style=file %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK6 %s
+// RUN: [ ! -e %T/.clang-format ] || rm %T/.clang-format
+// RUN: [ ! -e %T/_clang-format ] || rm %T/_clang-format
+// RUN: printf "BasedOnStyle: google\nIndentWidth: 6\n" > %T/_clang-format
+// RUN: clang-format -style=file %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK7 %s
+void f() {
+// CHECK1: {{^ int\* i;$}}
+// CHECK2: {{^ int \*i;$}}
+// CHECK3: Unknown value for BasedOnStyle: invalid
+// CHECK3: Error parsing -style: Invalid argument, using LLVM style
+// CHECK3: {{^ int \*i;$}}
+// CHECK4: Error parsing -style: Invalid argument, using LLVM style
+// CHECK4: {{^ int \*i;$}}
+// CHECK5: {{^ int\* i;$}}
+// CHECK6: {{^Error reading .*\.clang-format: Invalid argument}}
+// XCHECK6X: {{^ int \*i;$}}
+// CHECK7: {{^ int\* i;$}}
+int*i;
+int j;
+}
diff --git a/test/Frontend/Inputs/lit.local.cfg b/test/Frontend/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/Frontend/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/Frontend/Inputs/rewrite-includes-bom.h b/test/Frontend/Inputs/rewrite-includes-bom.h
new file mode 100644
index 000000000000..7ba011fc2d77
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes-bom.h
@@ -0,0 +1 @@
+// This file starts with UTF-8 BOM marker.
diff --git a/test/Frontend/cc1-return-codes.c b/test/Frontend/cc1-return-codes.c
new file mode 100644
index 000000000000..da329b934265
--- /dev/null
+++ b/test/Frontend/cc1-return-codes.c
@@ -0,0 +1,4 @@
+// cc1 immediate arguments (arguments which displays information and exits)
+// shall exit indicating success (return code 0)
+// RUN: %clang -cc1 -help
+// RUN: %clang -cc1 -version
diff --git a/test/Frontend/darwin-eabi.c b/test/Frontend/darwin-eabi.c
new file mode 100644
index 000000000000..b4b82aa842ed
--- /dev/null
+++ b/test/Frontend/darwin-eabi.c
@@ -0,0 +1,7 @@
+// RUN: %clang -arch armv6m -dM -E %s | FileCheck %s
+// RUN: %clang -arch armv7m -dM -E %s | FileCheck %s
+// RUN: %clang -arch armv7em -dM -E %s | FileCheck %s
+// RUN: %clang -arch armv7 -target thumbv7-apple-darwin-eabi -dM -E %s | FileCheck %s
+
+// CHECK-NOT: __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
+// CHECK-NOT: __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
diff --git a/test/Frontend/darwin-version.c b/test/Frontend/darwin-version.c
index f9ce54b923d3..7234ab48e3b0 100644
--- a/test/Frontend/darwin-version.c
+++ b/test/Frontend/darwin-version.c
@@ -1,23 +1,23 @@
// RUN: %clang -target armv6-apple-darwin9 -dM -E -o %t %s
-// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
+// RUN: not grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=3.0 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '30000' | count 1
-// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0
+// RUN: not grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t
// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20000' | count 1
-// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0
+// RUN: not grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t
// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20200' | count 1
// RUN: %clang -target i686-apple-darwin8 -dM -E -o %t %s
-// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
+// RUN: not grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1
// RUN: %clang -target i686-apple-darwin9 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
// RUN: %clang -target i686-apple-darwin10 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1
// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t %s
-// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
+// RUN: not grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1
// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
diff --git a/test/Frontend/invalid-o-level.c b/test/Frontend/invalid-o-level.c
new file mode 100644
index 000000000000..b9e01fcf00c0
--- /dev/null
+++ b/test/Frontend/invalid-o-level.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -O900 -o /dev/null 2> %t.log
+// RUN: FileCheck %s -input-file=%t.log
+
+// CHECK: warning: optimization level '-O900' is unsupported; using '-O3' instead
diff --git a/test/Frontend/ir-support-errors.ll b/test/Frontend/ir-support-errors.ll
index cb5913cd3af8..daf1675be51d 100644
--- a/test/Frontend/ir-support-errors.ll
+++ b/test/Frontend/ir-support-errors.ll
@@ -1,4 +1,4 @@
-; RUN: %clang_cc1 -S -o - %s 2>&1 | FileCheck %s
+; RUN: not %clang_cc1 -S -o - %s 2>&1 | FileCheck %s
target triple = "x86_64-apple-darwin10"
diff --git a/test/Frontend/mfpmath.c b/test/Frontend/mfpmath.c
new file mode 100644
index 000000000000..f650e485cb99
--- /dev/null
+++ b/test/Frontend/mfpmath.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse -mfpmath 387 %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse -mfpmath sse %s
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath xyz %s 2>&1 | FileCheck --check-prefix=CHECK-XYZ %s
+// CHECK-XYZ: error: unknown FP unit 'xyz'
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath 387 %s 2>&1 | FileCheck --check-prefix=CHECK-NO-387 %s
+// CHECK-NO-387: error: the '387' unit is not supported with this instruction set
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature -sse \
+// RUN: -mfpmath sse %s 2>&1 | FileCheck --check-prefix=CHECK-NO-SSE %s
+// CHECK-NO-SSE: error: the 'sse' unit is not supported with this instruction set
+
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp2 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp3 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp4 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -mfpmath neon %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -mfpmath foo %s 2>&1 \
+// RUN: FileCheck --check-prefix=CHECK-FOO %s
+// CHECK-FOO: unknown FP unit 'foo'
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu arm1136j-s \
+// RUN: -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -target-feature -neon -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// CHECK-NO-NEON: error: the 'neon' unit is not supported with this instruction set
diff --git a/test/Driver/mips-long-double.c b/test/Frontend/mips-long-double.c
index 09de38c6b707..09de38c6b707 100644
--- a/test/Driver/mips-long-double.c
+++ b/test/Frontend/mips-long-double.c
diff --git a/test/Frontend/print-header-includes.c b/test/Frontend/print-header-includes.c
index 7773d2069d98..aa3e3971fd1b 100644
--- a/test/Frontend/print-header-includes.c
+++ b/test/Frontend/print-header-includes.c
@@ -5,4 +5,11 @@
// CHECK: . {{.*test.h}}
// CHECK: .. {{.*test2.h}}
+// RUN: %clang_cc1 -include Inputs/test3.h -E --show-includes -o %t.out %s 2> %t.err
+// RUN: FileCheck --check-prefix=MS < %t.err %s
+// MS-NOT: test3.h
+// MS: Note: including file: {{.*test.h}}
+// MS: Note: including file: {{.*test2.h}}
+// MS-NOT: Note
+
#include "Inputs/test.h"
diff --git a/test/Frontend/rewrite-includes-bom.c b/test/Frontend/rewrite-includes-bom.c
new file mode 100644
index 000000000000..a1aa4c98f86e
--- /dev/null
+++ b/test/Frontend/rewrite-includes-bom.c
@@ -0,0 +1,4 @@
+// RUN: %clang -E -frewrite-includes -I %S/Inputs %s -o - | %clang -fsyntax-only -Xclang -verify -x c -
+// expected-no-diagnostics
+
+#include "rewrite-includes-bom.h"
diff --git a/test/Frontend/rewrite-includes-header-cmd-line.c b/test/Frontend/rewrite-includes-header-cmd-line.c
new file mode 100644
index 000000000000..dffaf28fe237
--- /dev/null
+++ b/test/Frontend/rewrite-includes-header-cmd-line.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -E -frewrite-includes -include rewrite-includes2.h -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
+
+// STARTMAIN
+
+// CHECK-NOT: {{^}}#define
+// CHECK: included_line2
+// CHECK: {{^}}// STARTMAIN{{$}}
diff --git a/test/Frontend/rewrite-includes-invalid-hasinclude.c b/test/Frontend/rewrite-includes-invalid-hasinclude.c
index e32d6ad8a3ed..334519a4b02d 100644
--- a/test/Frontend/rewrite-includes-invalid-hasinclude.c
+++ b/test/Frontend/rewrite-includes-invalid-hasinclude.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
#if __has_include bar.h
#endif
diff --git a/test/Frontend/rewrite-includes-warnings.c b/test/Frontend/rewrite-includes-warnings.c
new file mode 100644
index 000000000000..1fb98db30147
--- /dev/null
+++ b/test/Frontend/rewrite-includes-warnings.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -verify -Wall -Wextra -E -frewrite-includes %s
+// expected-no-diagnostics
+
+#pragma GCC visibility push (default)
diff --git a/test/Frontend/rewrite-includes.c b/test/Frontend/rewrite-includes.c
index bf330a60a3d6..2158dd0e8ead 100644
--- a/test/Frontend/rewrite-includes.c
+++ b/test/Frontend/rewrite-includes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -verify -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
-// RUN: %clang_cc1 -verify -E -frewrite-includes -P -DFIRST -I %S/Inputs %s -o - | FileCheck -check-prefix=CHECKNL -strict-whitespace %s
+// RUN: not %clang_cc1 -verify -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -verify -E -frewrite-includes -P -DFIRST -I %S/Inputs %s -o - | FileCheck -check-prefix=CHECKNL -strict-whitespace %s
// STARTCOMPARE
#define A(a,b) a ## b
A(1,2)
@@ -10,6 +10,7 @@ A(1,2)
#else
#include "rewrite-includes4.h"
#endif
+ // indented
#/**/include /**/ "rewrite-includes5.h" /**/ \
#include "rewrite-includes6.h" // comment
@@ -26,79 +27,86 @@ A(1,2)
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes1.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes1.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 1{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#pragma clang system_header{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs[/\\]}}rewrite-includes1.h" 3{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 3{{$}}
// CHECK-NEXT: {{^}}included_line1{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes2.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes2.h" 1 3{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes2.h" 1 3{{$}}
// CHECK-NEXT: {{^}}included_line2{{$}}
-// CHECK-NEXT: {{^}}# 4 "{{.*[/\\]Inputs[/\\]}}rewrite-includes1.h" 2 3{{$}}
+// CHECK-NEXT: {{^}}# 4 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 2 3{{$}}
// CHECK-NEXT: {{^}}# 7 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}#ifdef FIRST{{$}}
// CHECK-NEXT: {{^}}#define HEADER "rewrite-includes3.h"{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include HEADER{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes3.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes3.h" 1{{$}}
// CHECK-NEXT: {{^}}included_line3{{$}}
// CHECK-NEXT: {{^}}# 10 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}#else{{$}}
+// CHECK-NEXT: {{^}}# 11 "{{.*}}rewrite-includes.c"{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes4.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}# 12 "{{.*}}rewrite-includes.c"{{$}}
// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}# 13 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}} // indented{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}}
// CHECK-NEXT: {{^}} {{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes5.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes5.h" 1{{$}}
// CHECK-NEXT: {{^}}included_line5{{$}}
-// CHECK-NEXT: {{^}}# 15 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes6.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes6.h" 1{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#pragma once{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs[/\\]}}rewrite-includes6.h"{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes6.h"{{$}}
// CHECK-NEXT: {{^}}included_line6{{$}}
-// CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}# 17 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}} {{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" /* comment{{$}}
// CHECK-NEXT: {{^}} continues */{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 19 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}# 20 "{{.*}}rewrite-includes.c"{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes7.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes7.h" 1{{$}}
// CHECK-NEXT: {{^}}#ifndef REWRITE_INCLUDES_7{{$}}
// CHECK-NEXT: {{^}}#define REWRITE_INCLUDES_7{{$}}
// CHECK-NEXT: {{^}}included_line7{{$}}
// CHECK-NEXT: {{^}}#endif{{$}}
-// CHECK-NEXT: {{^}}# 20 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}# 5 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes7.h"{{$}}
+// CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c"{{$}}
// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes8.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes8.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h" 1{{$}}
// CHECK-NEXT: {{^}}#if (1)/*__has_include_next(<rewrite-includes8.h>)*/{{$}}
// CHECK-NEXT: {{^}}#elif (0)/*__has_include(<rewrite-includes8.hfail>)*/{{$}}
+// CHECK-NEXT: {{^}}# 3 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h"{{$}}
// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}# 4 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h"{{$}}
// CHECK-NEXT: {{^}}#if !(1)/*__has_include("rewrite-includes8.h")*/{{$}}
// CHECK-NEXT: {{^}}#endif{{$}}
-// CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}# 6 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h"{{$}}
+// CHECK-NEXT: {{^}}# 23 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}
// CHECKNL: {{^}}// STARTCOMPARE{{$}}
@@ -126,6 +134,7 @@ A(1,2)
// CHECKNL-NEXT: {{^}}#include "rewrite-includes4.h"{{$}}
// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
// CHECKNL-NEXT: {{^}}#endif{{$}}
+// CHECKNL-NEXT: {{^}} // indented{{$}}
// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECKNL-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}}
// CHECKNL-NEXT: {{^}} {{$}}
diff --git a/test/Frontend/verify-fatal.c b/test/Frontend/verify-fatal.c
index 0e74032a3afe..1a26196efa1b 100644
--- a/test/Frontend/verify-fatal.c
+++ b/test/Frontend/verify-fatal.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wfatal-errors -verify %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -Wfatal-errors -verify %s 2>&1 | FileCheck %s
#error first fatal
// expected-error@-1 {{first fatal}}
diff --git a/test/Frontend/verify.c b/test/Frontend/verify.c
index 3d71e04980c5..4bd0c90b4aea 100644
--- a/test/Frontend/verify.c
+++ b/test/Frontend/verify.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -DTEST1 -verify %s
-// RUN: %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
-// RUN: %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
-// RUN: %clang_cc1 -DTEST4 -verify %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
-// RUN: %clang_cc1 -DTEST5 -verify %s 2>&1 | FileCheck -check-prefix=CHECK5 %s
+// RUN: not %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
+// RUN: not %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
+// RUN: not %clang_cc1 -DTEST4 -verify %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
+// RUN: not %clang_cc1 -DTEST5 -verify %s 2>&1 | FileCheck -check-prefix=CHECK5 %s
// expected-warning@ malformed
// expected-error@7 1 {{missing or invalid line number}}
@@ -109,14 +109,14 @@ unexpected b; // expected-error@33 1-1 {{unknown type}}
#endif
#if 0
-// RUN: %clang_cc1 -verify %t.invalid 2>&1 | FileCheck -check-prefix=CHECK6 %s
+// RUN: not %clang_cc1 -verify %t.invalid 2>&1 | FileCheck -check-prefix=CHECK6 %s
// CHECK6: error: no expected directives found: consider use of 'expected-no-diagnostics'
// CHECK6-NEXT: error: 'error' diagnostics seen but not expected:
// CHECK6-NEXT: (frontend): error reading '{{.*}}verify.c.tmp.invalid'
// CHECK6-NEXT: 2 errors generated.
-// RUN: echo -e '//expected-error@2{{1}}\n#error 2' | %clang_cc1 -verify 2>&1 | FileCheck -check-prefix=CHECK7 %s
+// RUN: printf '//expected-error@2{{1}}\n#error 2\n' | not %clang_cc1 -verify 2>&1 | FileCheck -check-prefix=CHECK7 %s
// CHECK7: error: 'error' diagnostics expected but not seen:
// CHECK7-NEXT: Line 2 (directive at <stdin>:1): 1
@@ -126,10 +126,10 @@ unexpected b; // expected-error@33 1-1 {{unknown type}}
#endif
#ifdef TEST8
-// RUN: %clang_cc1 -DTEST8 -verify %s 2>&1 | FileCheck -check-prefix=CHECK8 %s
+// RUN: not %clang_cc1 -DTEST8 -verify %s 2>&1 | FileCheck -check-prefix=CHECK8 %s
-// expected-warning@nonexistant-file:1 {{ }}
-// expected-error@-1 {{file 'nonexistant-file' could not be located}}
+// expected-warning@nonexistent-file:1 {{ }}
+// expected-error@-1 {{file 'nonexistent-file' could not be located}}
// expected-warning@verify-directive.h: {{ }}
// expected-error@-1 {{missing or invalid line number}}
diff --git a/test/Frontend/verify2.c b/test/Frontend/verify2.c
index 04f80ad48e1a..73eda4d815de 100644
--- a/test/Frontend/verify2.c
+++ b/test/Frontend/verify2.c
@@ -1,5 +1,5 @@
#if 0
-// RUN: %clang_cc1 -verify %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -verify %s 2>&1 | FileCheck %s
// Please note that all comments are inside "#if 0" blocks so that
// VerifyDiagnosticConsumer sees no comments while processing this
diff --git a/test/Frontend/verify3.c b/test/Frontend/verify3.c
index 0705b4b7ee57..3898bfeedda0 100644
--- a/test/Frontend/verify3.c
+++ b/test/Frontend/verify3.c
@@ -2,7 +2,7 @@
// diagnostics are generated in relation to the mis-use and non-use of the
// 'expected-no-diagnostics' directive.
-// RUN: %clang_cc1 -DTEST1 -verify %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
+// RUN: not %clang_cc1 -DTEST1 -verify %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
#ifdef TEST1
// expected-no-diagnostics
// expected-note {{}}
@@ -12,7 +12,7 @@
// CHECK1-NEXT: 1 error generated.
#endif
-// RUN: %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
+// RUN: not %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
#ifdef TEST2
#warning X
// expected-warning@-1 {{X}}
@@ -23,8 +23,8 @@
// CHECK2-NEXT: 1 error generated.
#endif
-// RUN: %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
-// RUN: %clang_cc1 -verify 2>&1 | FileCheck -check-prefix=CHECK3 %s
+// RUN: not %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
+// RUN: not %clang_cc1 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
#ifdef TEST3
// no directives
diff --git a/test/Driver/x86_64-nacl-types.cpp b/test/Frontend/x86_64-nacl-types.cpp
index a994cb75ef66..a994cb75ef66 100644
--- a/test/Driver/x86_64-nacl-types.cpp
+++ b/test/Frontend/x86_64-nacl-types.cpp
diff --git a/test/Headers/Inputs/include/complex.h b/test/Headers/Inputs/include/complex.h
new file mode 100644
index 000000000000..1ed5f53092a5
--- /dev/null
+++ b/test/Headers/Inputs/include/complex.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define complex _Complex
diff --git a/test/Headers/Inputs/include/math.h b/test/Headers/Inputs/include/math.h
new file mode 100644
index 000000000000..6f70f09beec2
--- /dev/null
+++ b/test/Headers/Inputs/include/math.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/test/Headers/Inputs/include/stdint.h b/test/Headers/Inputs/include/stdint.h
index 7a1fddef82da..5bf26a7b67b0 100644
--- a/test/Headers/Inputs/include/stdint.h
+++ b/test/Headers/Inputs/include/stdint.h
@@ -10,6 +10,7 @@ typedef unsigned __INT64_TYPE__ uint64_t;
#endif
#ifdef __INTPTR_TYPE__
+typedef __INTPTR_TYPE__ intptr_t;
typedef unsigned __INTPTR_TYPE__ uintptr_t;
#else
#error Every target should have __INTPTR_TYPE__
diff --git a/test/Headers/altivec-header.c b/test/Headers/altivec-header.c
index 085e799f9599..b01cc9716d76 100644
--- a/test/Headers/altivec-header.c
+++ b/test/Headers/altivec-header.c
@@ -1,7 +1,7 @@
// REQUIRES: ppc64-registered-target
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -maltivec -ffreestanding -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -maltivec -ffreestanding -fno-lax-vector-conversions -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -maltivec -ffreestanding -x c++ -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -fno-lax-vector-conversions -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -x c++ -S -o - %s | FileCheck %s
#include <altivec.h>
diff --git a/test/Headers/c11.c b/test/Headers/c11.c
index 21f2e4f2224d..11bec1954462 100644
--- a/test/Headers/c11.c
+++ b/test/Headers/c11.c
@@ -1,6 +1,6 @@
-// RUN: %clang -fsyntax-only -Xclang -verify -std=c11 %s
-// RUN: %clang -fsyntax-only -Xclang -verify -std=c11 -fmodules %s
-// RUN: %clang -fsyntax-only -Xclang -verify -std=c11 -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -fmodules %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -ffreestanding %s
noreturn int f(); // expected-error 1+{{}}
diff --git a/test/Headers/c89.c b/test/Headers/c89.c
index acf01b40e06e..6188df5487bd 100644
--- a/test/Headers/c89.c
+++ b/test/Headers/c89.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target i386-apple-darwin10 -fsyntax-only -Xclang -verify -std=c89 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -target-cpu yonah -fsyntax-only -verify -std=c89 %s
// expected-no-diagnostics
// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
diff --git a/test/Headers/cxx11.cpp b/test/Headers/cxx11.cpp
index 54fe350ea5b2..1a4b6400e095 100644
--- a/test/Headers/cxx11.cpp
+++ b/test/Headers/cxx11.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang -fsyntax-only -std=c++11 %s
-// RUN: %clang -fsyntax-only -std=c++11 -fmodules %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 -fmodules %s
#include <stdalign.h>
diff --git a/test/Headers/limits.cpp b/test/Headers/limits.cpp
new file mode 100644
index 000000000000..a78f7fc6de6e
--- /dev/null
+++ b/test/Headers/limits.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fno-signed-char -ffreestanding -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -ffreestanding -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+#include <limits.h>
+
+_Static_assert(SCHAR_MAX == -(SCHAR_MIN+1), "");
+_Static_assert(SHRT_MAX == -(SHRT_MIN+1), "");
+_Static_assert(INT_MAX == -(INT_MIN+1), "");
+_Static_assert(LONG_MAX == -(LONG_MIN+1L), "");
+
+_Static_assert(SCHAR_MAX == UCHAR_MAX/2, "");
+_Static_assert(SHRT_MAX == USHRT_MAX/2, "");
+_Static_assert(INT_MAX == UINT_MAX/2, "");
+_Static_assert(LONG_MAX == ULONG_MAX/2, "");
+
+_Static_assert(SCHAR_MIN == -SCHAR_MAX-1, "");
+_Static_assert(SHRT_MIN == -SHRT_MAX-1, "");
+_Static_assert(INT_MIN == -INT_MAX-1, "");
+_Static_assert(LONG_MIN == -LONG_MAX-1L, "");
+
+_Static_assert(UCHAR_MAX == (unsigned char)~0ULL, "");
+_Static_assert(USHRT_MAX == (unsigned short)~0ULL, "");
+_Static_assert(UINT_MAX == (unsigned int)~0ULL, "");
+_Static_assert(ULONG_MAX == (unsigned long)~0ULL, "");
+
+_Static_assert(MB_LEN_MAX >= 1, "");
+
+_Static_assert(CHAR_BIT >= 8, "");
+
+const bool char_is_signed = (char)-1 < (char)0;
+_Static_assert(CHAR_MIN == (char_is_signed ? -CHAR_MAX-1 : 0), "");
+_Static_assert(CHAR_MAX == (char_is_signed ? -(CHAR_MIN+1) : (char)~0ULL), "");
+
+#if __STDC_VERSION__ >= 199901 || __cplusplus >= 201103L
+_Static_assert(LLONG_MAX == -(LLONG_MIN+1LL), "");
+_Static_assert(LLONG_MIN == -LLONG_MAX-1LL, "");
+_Static_assert(ULLONG_MAX == (unsigned long long)~0ULL, "");
+#else
+int LLONG_MIN, LLONG_MAX, ULLONG_MAX; // Not defined.
+#endif
diff --git a/test/Headers/ms-intrin.cpp b/test/Headers/ms-intrin.cpp
new file mode 100644
index 000000000000..1bf134e7eac6
--- /dev/null
+++ b/test/Headers/ms-intrin.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 -target-cpu pentium4 \
+// RUN: -fms-extensions -fms-compatibility -fmsc-version=1700 \
+// RUN: -ffreestanding -verify %s
+
+// Intrin.h needs size_t, but -ffreestanding prevents us from getting it from
+// stddef.h. Work around it with this typedef.
+typedef __SIZE_TYPE__ size_t;
+
+#include <Intrin.h>
+
+// Use some C++ to make sure we closed the extern "C" brackets.
+template <typename T>
+void foo(T V) {}
+
+void bar() {
+ _ReadWriteBarrier(); // expected-warning {{is deprecated: use other intrinsics or C++11 atomics instead}}
+ _ReadBarrier(); // expected-warning {{is deprecated: use other intrinsics or C++11 atomics instead}}
+ _WriteBarrier(); // expected-warning {{is deprecated: use other intrinsics or C++11 atomics instead}}
+ // FIXME: It'd be handy if we didn't have to hardcode the line number in
+ // intrin.h.
+ // expected-note@Intrin.h:754 {{declared here}}
+ // expected-note@Intrin.h:759 {{declared here}}
+ // expected-note@Intrin.h:764 {{declared here}}
+}
diff --git a/test/Headers/ms-null-ms-header-vs-stddef.cpp b/test/Headers/ms-null-ms-header-vs-stddef.cpp
index 7efa871da90e..237ed51f965e 100644
--- a/test/Headers/ms-null-ms-header-vs-stddef.cpp
+++ b/test/Headers/ms-null-ms-header-vs-stddef.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang -fsyntax-only -target i686-pc-win32 %s
-// RUN: %clang -fsyntax-only -target i386-mingw32 %s
+// RUN: %clang_cc1 -fsyntax-only -triple i686-pc-win32 -fms-compatibility -fmsc-version=1700 %s
+// RUN: %clang_cc1 -fsyntax-only -triple i386-mingw32 %s
// Something in MSVC's headers (pulled in e.g. by <crtdefs.h>) defines __null
// to something, mimick that.
diff --git a/test/Headers/ms-wchar.c b/test/Headers/ms-wchar.c
index f015fc77ee51..fee7e72bd42c 100644
--- a/test/Headers/ms-wchar.c
+++ b/test/Headers/ms-wchar.c
@@ -1,4 +1,4 @@
-// RUN: %clang -fsyntax-only -target i386-pc-win32 %s
+// RUN: %clang_cc1 -fsyntax-only -triple i386-pc-win32 -fms-compatibility %s
#if defined(_WCHAR_T_DEFINED)
#error "_WCHAR_T_DEFINED should not be defined in C99"
diff --git a/test/Headers/tgmath.c b/test/Headers/tgmath.c
new file mode 100644
index 000000000000..4235ae20719f
--- /dev/null
+++ b/test/Headers/tgmath.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -fsyntax-only -isystem %S/Inputs/include -verify %s
+// expected-no-diagnostics
+
+#include <tgmath.h>
+
+float f;
+double d;
+long double l;
+
+float complex fc;
+double complex dc;
+long double complex lc;
+
+// creal
+
+_Static_assert(sizeof(creal(f)) == sizeof(f), "");
+_Static_assert(sizeof(creal(d)) == sizeof(d), "");
+_Static_assert(sizeof(creal(l)) == sizeof(l), "");
+
+_Static_assert(sizeof(creal(fc)) == sizeof(f), "");
+_Static_assert(sizeof(creal(dc)) == sizeof(d), "");
+_Static_assert(sizeof(creal(lc)) == sizeof(l), "");
+
+// fabs
+
+_Static_assert(sizeof(fabs(f)) == sizeof(f), "");
+_Static_assert(sizeof(fabs(d)) == sizeof(d), "");
+_Static_assert(sizeof(fabs(l)) == sizeof(l), "");
+
+_Static_assert(sizeof(fabs(fc)) == sizeof(f), "");
+_Static_assert(sizeof(fabs(dc)) == sizeof(d), "");
+_Static_assert(sizeof(fabs(lc)) == sizeof(l), "");
+
+// logb
+
+_Static_assert(sizeof(logb(f)) == sizeof(f), "");
+_Static_assert(sizeof(logb(d)) == sizeof(d), "");
+_Static_assert(sizeof(logb(l)) == sizeof(l), "");
diff --git a/test/Headers/x86-intrinsics-headers.c b/test/Headers/x86-intrinsics-headers.c
index bdffddedfc7b..91c4ffaa0edb 100644
--- a/test/Headers/x86-intrinsics-headers.c
+++ b/test/Headers/x86-intrinsics-headers.c
@@ -1,6 +1,6 @@
-// RUN: %clang -fsyntax-only -ffreestanding %s
-// RUN: %clang -fsyntax-only -ffreestanding -fno-lax-vector-conversions %s
-// RUN: %clangxx -fsyntax-only -ffreestanding -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -fno-lax-vector-conversions %s
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -x c++ %s
#if defined(i386) || defined(__x86_64__)
diff --git a/test/Headers/x86intrin.c b/test/Headers/x86intrin.c
new file mode 100644
index 000000000000..d095c00674e0
--- /dev/null
+++ b/test/Headers/x86intrin.c
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding %s -verify
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -fno-lax-vector-conversions %s -verify
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -x c++ %s -verify
+// expected-no-diagnostics
+
+#if defined(i386) || defined(__x86_64__)
+
+// Pretend to enable all features.
+#ifndef __3dNOW__
+#define __3dNOW__
+#endif
+#ifndef __BMI__
+#define __BMI__
+#endif
+#ifndef __BMI2__
+#define __BMI2__
+#endif
+#ifndef __LZCNT__
+#define __LZCNT__
+#endif
+#ifndef __POPCNT__
+#define __POPCNT__
+#endif
+#ifndef __RDSEED__
+#define __RDSEED__
+#endif
+#ifndef __PRFCHW__
+#define __PRFCHW__
+#endif
+#ifndef __SSE4A__
+#define __SSE4A__
+#endif
+#ifndef __FMA4__
+#define __FMA4__
+#endif
+#ifndef __XOP__
+#define __XOP__
+#endif
+#ifndef __F16C__
+#define __F16C__
+#endif
+#ifndef __MMX__
+#define __MMX__
+#endif
+#ifndef __SSE__
+#define __SSE__
+#endif
+#ifndef __SSE2__
+#define __SSE2__
+#endif
+#ifndef __SSE3__
+#define __SSE3__
+#endif
+#ifndef __SSSE3__
+#define __SSSE3__
+#endif
+#ifndef __SSE4_1__
+#define __SSE4_1__
+#endif
+#ifndef __SSE4_2__
+#define __SSE4_2__
+#endif
+#ifndef __AES__
+#define __AES__
+#endif
+#ifndef __AVX__
+#define __AVX__
+#endif
+#ifndef __AVX2__
+#define __AVX2__
+#endif
+#ifndef __BMI__
+#define __BMI__
+#endif
+#ifndef __BMI2__
+#define __BMI2__
+#endif
+#ifndef __LZCNT__
+#define __LZCNT__
+#endif
+#ifndef __FMA__
+#define __FMA__
+#endif
+#ifndef __RDRND__
+#define __RDRND__
+#endif
+
+// Now include the metaheader that includes all x86 intrinsic headers.
+#include <x86intrin.h>
+
+#endif
diff --git a/test/Index/Inputs/CommentXML/invalid-function-13.xml b/test/Index/Inputs/CommentXML/invalid-function-13.xml
new file mode 100644
index 000000000000..14cd31bfa4ba
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/invalid-function-13.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Parameters>
+ <Parameter>
+ <Name>x1</Name>
+ <IsVarArg />
+ <Discussion><Para>Bbb</Para></Discussion>
+ </Parameter>
+</Parameters>
+</Function>
+
diff --git a/test/Index/Inputs/CommentXML/valid-function-07.xml b/test/Index/Inputs/CommentXML/valid-function-07.xml
index 89b8a0ca6fc8..b567e6b265bf 100644
--- a/test/Index/Inputs/CommentXML/valid-function-07.xml
+++ b/test/Index/Inputs/CommentXML/valid-function-07.xml
@@ -20,11 +20,24 @@
<Direction isExplicit="1">in,out</Direction>
<Discussion><Para>Ddd</Para></Discussion>
</Parameter>
+ <Parameter>
+ <Name>x4</Name>
+ <IsVarArg />
+ <Direction isExplicit="0">in</Direction>
+ <Discussion><Para>Eee</Para></Discussion>
+ </Parameter>
</Parameters>
-<ResultDiscussion><Para>Eee.</Para></ResultDiscussion>
+<Exceptions>
+ <Para>Fff.</Para>
+ <Para>Ggg</Para>
+</Exceptions>
+<ResultDiscussion>
+ <Para>Hhh.</Para>
+ <Para>Iii</Para>
+</ResultDiscussion>
<Discussion>
- <Para>Fff</Para>
- <Verbatim xml:space="preserve" kind="verbatim">Ggg</Verbatim>
+ <Para>Jjj</Para>
+ <Verbatim xml:space="preserve" kind="verbatim">Kkk</Verbatim>
</Discussion>
</Function>
diff --git a/test/Index/Inputs/empty.h b/test/Index/Inputs/empty.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Index/Inputs/empty.h
diff --git a/test/Index/Inputs/lit.local.cfg b/test/Index/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/Index/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/Index/Inputs/preamble-with-error.h b/test/Index/Inputs/preamble-with-error.h
new file mode 100644
index 000000000000..f840947369b0
--- /dev/null
+++ b/test/Index/Inputs/preamble-with-error.h
@@ -0,0 +1,3 @@
+typedef int Int;
+enum FFF
+extern Int *const www;
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index 038353b11dd6..899765eb0a2d 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -1,6 +1,6 @@
// RUN: c-index-test -write-pch %t.ast -fobjc-nonfragile-abi -fblocks -x objective-c %s
-// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=scan %s
-// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=load %s
+// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=CHECK-scan %s
+// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=CHECK-load %s
// This test checks how the @class resolves as a cursor when there is a real definition
// that follows. <rdar://problem/7383421>
diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m
index 2f32d33c7082..9696a280661d 100644
--- a/test/Index/TestClassForwardDecl.m
+++ b/test/Index/TestClassForwardDecl.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -o %t.ast
-// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=scan %s
-// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=load %s
+// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=CHECK-scan %s
+// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=CHECK-load %s
// This test checks how the @class resolves as a cursor when the @interface is implicitly defined.
// See TestClassDecl.m for the corresponding test case. (<rdar://problem/7383421>)
diff --git a/test/Index/annotate-comments-objc.m b/test/Index/annotate-comments-objc.m
new file mode 100644
index 000000000000..e778d6c65e1c
--- /dev/null
+++ b/test/Index/annotate-comments-objc.m
@@ -0,0 +1,78 @@
+// Run lines are sensitive to line numbers and come below the code.
+
+#ifndef HEADER
+#define HEADER
+
+@class NSString;
+
+//===---
+// rdar://14258334
+// Check that we attach comments to properties correctly.
+//===---
+
+@interface MyClass {
+}
+
+/// property1_isdoxy1 IS_DOXYGEN_SINGLE
+@property (nonatomic, copy, readwrite) NSString *property1_isdoxy1;
+@property (nonatomic, copy, readwrite) NSString *property1_isdoxy2; ///< property1_isdoxy2 IS_DOXYGEN_SINGLE
+@property (nonatomic, copy, readwrite) NSString *property1_isdoxy3; /**< property1_isdoxy3 IS_DOXYGEN_SINGLE */
+@property (nonatomic, copy, readwrite) NSString *property1_isdoxy4; /*!< property1_isdoxy4 IS_DOXYGEN_SINGLE */
+
+/// method1_isdoxy1 IS_DOXYGEN_SINGLE
+- (void)method1_isdoxy1;
+- (void)method1_isdoxy2; /*!< method1_isdoxy2 IS_DOXYGEN_SINGLE */
+- (void)method1_isdoxy3; /*!< method1_isdoxy3 IS_DOXYGEN_SINGLE */
+- (void)method1_isdoxy4; /*!< method1_isdoxy4 IS_DOXYGEN_SINGLE */
+@end
+
+
+#endif
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// Check that we serialize comment source locations properly.
+// RUN: %clang_cc1 -emit-pch -o %t/out.pch %s
+// RUN: %clang_cc1 -include-pch %t/out.pch -fsyntax-only %s
+
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s > %t/out.c-index-direct
+// RUN: c-index-test -test-load-tu %t/out.pch all > %t/out.c-index-pch
+
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-direct
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-pch
+
+// Declarations without Doxygen comments should not pick up some Doxygen comments.
+// WRONG-NOT: notdoxy{{.*}}Comment=
+// WRONG-NOT: test{{.*}}Comment=
+
+// Non-Doxygen comments should not be attached to anything.
+// WRONG-NOT: NOT_DOXYGEN
+
+// Some Doxygen comments are not attached to anything.
+// WRONG-NOT: IS_DOXYGEN_NOT_ATTACHED
+
+// Ensure we don't pick up extra comments.
+// WRONG-NOT: IS_DOXYGEN_START{{.*}}IS_DOXYGEN_START{{.*}}BriefComment=
+// WRONG-NOT: IS_DOXYGEN_END{{.*}}IS_DOXYGEN_END{{.*}}BriefComment=
+//
+// Ensure that XML is not invalid
+// WRONG-NOT: CommentXMLInvalid
+
+// RUN: FileCheck %s < %t/out.c-index-direct
+// RUN: FileCheck %s < %t/out.c-index-pch
+
+// These CHECK lines are not located near the code on purpose. This test
+// checks that documentation comments are attached to declarations correctly.
+// Adding a non-documentation comment with CHECK line between every two
+// documentation comments will only test a single code path.
+//
+// CHECK: annotate-comments-objc.m:17:50: ObjCPropertyDecl=property1_isdoxy1:{{.*}} property1_isdoxy1 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:18:50: ObjCPropertyDecl=property1_isdoxy2:{{.*}} property1_isdoxy2 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:19:50: ObjCPropertyDecl=property1_isdoxy3:{{.*}} property1_isdoxy3 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:20:50: ObjCPropertyDecl=property1_isdoxy4:{{.*}} property1_isdoxy4 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:23:9: ObjCInstanceMethodDecl=method1_isdoxy1:{{.*}} method1_isdoxy1 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:24:9: ObjCInstanceMethodDecl=method1_isdoxy2:{{.*}} method1_isdoxy2 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:25:9: ObjCInstanceMethodDecl=method1_isdoxy3:{{.*}} method1_isdoxy3 IS_DOXYGEN_SINGLE
+// CHECK: annotate-comments-objc.m:26:9: ObjCInstanceMethodDecl=method1_isdoxy4:{{.*}} method1_isdoxy4 IS_DOXYGEN_SINGLE
+
diff --git a/test/Index/annotate-comments-unterminated.c b/test/Index/annotate-comments-unterminated.c
index 6bba911aac93..305cf2319172 100644
--- a/test/Index/annotate-comments-unterminated.c
+++ b/test/Index/annotate-comments-unterminated.c
@@ -1,5 +1,5 @@
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=ERR %s
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
// CHECK: annotate-comments-unterminated.c:9:5: VarDecl=x:{{.*}} RawComment=[/** Aaa. */]{{.*}} BriefComment=[Aaa.]
// CHECK: annotate-comments-unterminated.c:11:5: VarDecl=y:{{.*}} RawComment=[/**< Bbb. */]{{.*}} BriefComment=[Bbb.]
diff --git a/test/Index/annotate-comments.cpp b/test/Index/annotate-comments.cpp
index 2a0b635de85c..6612a44792e6 100644
--- a/test/Index/annotate-comments.cpp
+++ b/test/Index/annotate-comments.cpp
@@ -247,6 +247,13 @@ void isdoxy52(int);
*/
void isdoxy53(int);
+#define MYMAC(x,y)
+/**
+ * Aaa. IS_DOXYGEN_START IS_DOXYGEN_END
+ */
+MYMAC(0,0)
+void isdoxy54(int);
+
#endif
// RUN: rm -rf %t
@@ -327,4 +334,5 @@ void isdoxy53(int);
// CHECK: annotate-comments.cpp:222:6: FunctionDecl=isdoxy50:{{.*}} BriefComment=[Returns ddd IS_DOXYGEN_END]
// CHECK: annotate-comments.cpp:231:6: FunctionDecl=isdoxy51:{{.*}} BriefComment=[Aaa. IS_DOXYGEN_START]
// CHECK: annotate-comments.cpp:241:6: FunctionDecl=isdoxy52:{{.*}} BriefComment=[Aaa. IS_DOXYGEN_START Bbb.]
-
+// CHECK: annotate-comments.cpp:248:6: FunctionDecl=isdoxy53:{{.*}} BriefComment=[Aaa. IS_DOXYGEN_START IS_DOXYGEN_END]
+// CHECK: annotate-comments.cpp:255:6: FunctionDecl=isdoxy54:{{.*}} BriefComment=[Aaa. IS_DOXYGEN_START IS_DOXYGEN_END]
diff --git a/test/Index/annotate-tokens-cxx0x.cpp b/test/Index/annotate-tokens-cxx0x.cpp
index 49f7efb285a1..4e6d156dfa9f 100644
--- a/test/Index/annotate-tokens-cxx0x.cpp
+++ b/test/Index/annotate-tokens-cxx0x.cpp
@@ -23,6 +23,47 @@ class S : public B {
virtual void foo(Int) override;
};
+// Need std::initializer_list
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+struct Foo {
+ Foo(std::initializer_list<int> il);
+};
+
+void test2() {
+ Foo{10};
+}
+
// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 -fno-delayed-template-parsing -std=c++11 %s | FileCheck %s
// CHECK: Identifier: "args" [3:20 - 3:24] SizeOfPackExpr=args:2:15
@@ -52,3 +93,6 @@ class S : public B {
// CHECK-WITH-OVERRIDE: Punctuation: ")" [23:23 - 23:24] ParmDecl=:23:23 (Definition)
// CHECK-WITH-OVERRIDE: Keyword: "override" [23:25 - 23:33] attribute(override)=
// CHECK-WITH-OVERRIDE: Punctuation: ";" [23:33 - 23:34] ClassDecl=S:22:7 (Definition)
+
+// RUN: c-index-test -test-annotate-tokens=%s:64:1:65:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-INITLIST %s
+// CHECK-INITLIST: Identifier: "Foo" [64:3 - 64:6] TypeRef=struct Foo:59:8
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 40c66a18b8f0..9a7e28a666bf 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -142,6 +142,17 @@ static Rdar8595462_A * Rdar8595462_staticVar;
}
@end
+@interface MyClass
+ @property int classProperty;
+@end
+@interface MyClass (abc)
+ @property int categoryProperty;
+@end
+@interface MyClass ()
+ @property int extensionProperty;
+@end
+
+
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
@@ -574,3 +585,14 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-WITH-WEAK: Identifier: "foo" [141:15 - 141:18] ObjCIvarDecl=foo:141:15 (Definition)
// CHECK-WITH-WEAK: Punctuation: ";" [141:18 - 141:19] ObjCInterfaceDecl=rdar9535717:140:12
// CHECK-WITH-WEAK: Punctuation: "}" [142:1 - 142:2] ObjCInterfaceDecl=rdar9535717:140:12
+
+// RUN: c-index-test -test-annotate-tokens=%s:145:1:153:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-PROP %s
+// CHECK-PROP: Keyword: "property" [146:4 - 146:12] ObjCPropertyDecl=classProperty:146:17
+// CHECK-PROP: Keyword: "int" [146:13 - 146:16] ObjCPropertyDecl=classProperty:146:17
+// CHECK-PROP: Identifier: "classProperty" [146:17 - 146:30] ObjCPropertyDecl=classProperty:146:17
+// CHECK-PROP: Keyword: "property" [149:4 - 149:12] ObjCPropertyDecl=categoryProperty:149:17
+// CHECK-PROP: Keyword: "int" [149:13 - 149:16] ObjCPropertyDecl=categoryProperty:149:17
+// CHECK-PROP: Identifier: "categoryProperty" [149:17 - 149:33] ObjCPropertyDecl=categoryProperty:149:17
+// CHECK-PROP: Keyword: "property" [152:4 - 152:12] ObjCPropertyDecl=extensionProperty:152:17
+// CHECK-PROP: Keyword: "int" [152:13 - 152:16] ObjCPropertyDecl=extensionProperty:152:17
+// CHECK-PROP: Identifier: "extensionProperty" [152:17 - 152:34] ObjCPropertyDecl=extensionProperty:152:17
diff --git a/test/Index/annotate-toplevel-in-objccontainer.m b/test/Index/annotate-toplevel-in-objccontainer.m
index 56b7871d9bc2..3d8948e01e8b 100644
--- a/test/Index/annotate-toplevel-in-objccontainer.m
+++ b/test/Index/annotate-toplevel-in-objccontainer.m
@@ -18,16 +18,16 @@ static int glob2;
// RUN: c-index-test -write-pch %t.h.pch -x objective-c-header %s.h
// RUN: c-index-test -test-annotate-tokens=%s:5:1:7:1 %s -include %t.h \
-// RUN: | FileCheck -check-prefix=INTER %s
+// RUN: | FileCheck -check-prefix=CHECK-INTER %s
// CHECK-INTER: Identifier: "meth1" [5:8 - 5:13] ObjCInstanceMethodDecl=meth1:5:8
// CHECK-INTER: Identifier: "meth2" [6:8 - 6:13] ObjCInstanceMethodDecl=meth2:6:8
// RUN: c-index-test -test-annotate-tokens=%s:14:1:16:1 %s -include %t.h \
-// RUN: | FileCheck -check-prefix=IMPL %s
+// RUN: | FileCheck -check-prefix=CHECK-IMPL %s
// CHECK-IMPL: Identifier: "meth1" [14:8 - 14:13] ObjCInstanceMethodDecl=meth1:14:8 (Definition)
// CHECK-IMPL: Identifier: "meth2" [15:8 - 15:13] ObjCInstanceMethodDecl=meth2:15:8 (Definition)
// RUN: c-index-test -test-annotate-tokens=%s.h:7:1:9:1 %s -include %t.h \
-// RUN: | FileCheck -check-prefix=PCH %s
+// RUN: | FileCheck -check-prefix=CHECK-PCH %s
// CHECK-PCH: Identifier: "meth1" [7:8 - 7:13] ObjCInstanceMethodDecl=meth1:7:8
// CHECK-PCH: Identifier: "meth2" [8:8 - 8:13] ObjCInstanceMethodDecl=meth2:8:8
diff --git a/test/Index/asm-attribute.c b/test/Index/asm-attribute.c
index f9524598b608..dddecfbe62d2 100644
--- a/test/Index/asm-attribute.c
+++ b/test/Index/asm-attribute.c
@@ -2,5 +2,4 @@ int foo(int x) __asm__("_foo_");
// RUN: c-index-test -test-load-source all %s | FileCheck %s
// CHECK: asm-attribute.c:1:5: FunctionDecl=foo:1:5 Extent=[1:1 - 1:32]
-// FIXME: Location below.
-// CHECK: <invalid loc>:0:0: asm label=_foo_ Extent=[1:24 - 1:31]
+// CHECK: asm-attribute.c:1:24: asm label=_foo_ Extent=[1:24 - 1:31]
diff --git a/test/Index/attributes.c b/test/Index/attributes.c
new file mode 100644
index 000000000000..3e60e6c0e495
--- /dev/null
+++ b/test/Index/attributes.c
@@ -0,0 +1,10 @@
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+
+struct __attribute__((packed)) Test2 {
+ char a;
+};
+
+// CHECK: attributes.c:3:32: StructDecl=Test2:3:32 (Definition) Extent=[3:1 - 5:2]
+// CHECK: attributes.c:3:23: attribute(packed)=packed Extent=[3:23 - 3:29]
+// CHECK: attributes.c:4:8: FieldDecl=a:4:8 (Definition) Extent=[4:3 - 4:9] [access=public]
+
diff --git a/test/Index/availability.c b/test/Index/availability.c
index e6b1273acafb..cfe0ff5bea81 100644
--- a/test/Index/availability.c
+++ b/test/Index/availability.c
@@ -2,9 +2,19 @@
void foo(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7), availability(ios,introduced=3.2,deprecated=4.1)));
+enum {
+ old_enum
+} __attribute__((deprecated));
+
+enum {
+ old_enum_plat
+} __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: (macosx, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+// CHECK-2: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
+// CHECK-2: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macosx, introduced=10.4, deprecated=10.5, obsoleted=10.7)
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 61d82a6cde5a..c75d5ac6814e 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -77,14 +77,14 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:3 - 6:40]
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[6:18 - 6:26]
+// CHECK: c-index-api-loadTU-test.m:6:18: attribute(iboutlet)= Extent=[6:18 - 6:26]
// CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31]
// CHECK: c-index-api-loadTU-test.m:8:36: ObjCInstanceMethodDecl=myMessage::8:36 Extent=[8:1 - 8:54]
-// CHECK: <invalid loc>:0:0: attribute(ibaction)= Extent=[8:25 - 8:33]
+// CHECK: c-index-api-loadTU-test.m:8:25: attribute(ibaction)= Extent=[8:25 - 8:33]
// CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53]
// CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49]
// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) (always deprecated: "") Extent=[9:1 - 9:35]
-// CHECK: <invalid loc>:0:0: UnexposedAttr= Extent=[9:22 - 9:32]
+// CHECK: c-index-api-loadTU-test.m:9:22: UnexposedAttr= Extent=[9:22 - 9:32]
// CHECK: c-index-api-loadTU-test.m:10:3: ObjCClassMethodDecl=fooC:10:3 Extent=[10:1 - 10:8]
// CHECK: c-index-api-loadTU-test.m:14:12: ObjCInterfaceDecl=Bar:14:12 Extent=[14:1 - 18:5]
// CHECK: c-index-api-loadTU-test.m:14:18: ObjCSuperClassRef=Foo:4:12 Extent=[14:18 - 14:21]
@@ -153,13 +153,13 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36]
// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5]
// CHECK: c-index-api-loadTU-test.m:63:15: ObjCIvarDecl=anOutlet:63:15 (Definition) Extent=[63:3 - 63:23]
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[63:3 - 63:11]
+// CHECK: c-index-api-loadTU-test.m:63:3: attribute(iboutlet)= Extent=[63:3 - 63:11]
// CHECK: c-index-api-loadTU-test.m:63:12: TypeRef=id:0:0 Extent=[63:12 - 63:14]
// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:3 - 64:47]
-// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer] Extent=[64:3 - 64:25]
+// CHECK: c-index-api-loadTU-test.m:64:3: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer] Extent=[64:3 - 64:25]
// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28]
// CHECK: c-index-api-loadTU-test.m:66:14: ObjCInstanceMethodDecl=actionMethod::66:14 Extent=[66:1 - 66:35]
-// CHECK: <invalid loc>:0:0: attribute(ibaction)= Extent=[66:4 - 66:12]
+// CHECK: c-index-api-loadTU-test.m:66:4: attribute(ibaction)= Extent=[66:4 - 66:12]
// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34]
// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30]
// CHECK: c-index-api-loadTU-test.m:69:16: StructDecl=X0:69:16 Extent=[69:9 - 69:18]
@@ -170,7 +170,7 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:73:12: ObjCCategoryDecl=:73:12 Extent=[73:1 - 76:5]
// CHECK: c-index-api-loadTU-test.m:73:12: ObjCClassRef=TestAttributes:62:12 Extent=[73:12 - 73:26]
// CHECK: c-index-api-loadTU-test.m:75:32: ObjCPropertyDecl=anotherOutlet:75:32 [retain,] Extent=[75:1 - 75:45]
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[75:20 - 75:28]
+// CHECK: c-index-api-loadTU-test.m:75:20: attribute(iboutlet)= Extent=[75:20 - 75:28]
// CHECK: c-index-api-loadTU-test.m:75:29: TypeRef=id:0:0 Extent=[75:29 - 75:31]
// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=anotherOutlet:75:32 Extent=[75:32 - 75:45]
// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=setAnotherOutlet::75:32 Extent=[75:32 - 75:45]
diff --git a/test/Index/c-index-unsupported-warning-test.c b/test/Index/c-index-unsupported-warning-test.c
new file mode 100644
index 000000000000..82ed06359d7e
--- /dev/null
+++ b/test/Index/c-index-unsupported-warning-test.c
@@ -0,0 +1,3 @@
+// RUN: c-index-test -code-completion-at=%s:1:1 -Wunknown-foo-bar-warning -Werror %s
+
+void f();
diff --git a/test/Index/cindex-from-source.m b/test/Index/cindex-from-source.m
index f226e4533530..504d90fd2bc9 100644
--- a/test/Index/cindex-from-source.m
+++ b/test/Index/cindex-from-source.m
@@ -1,4 +1,4 @@
-
+// REQUIRES: native
// RUN: %clang -x objective-c-header %S/Inputs/cindex-from-source.h -o %t.pfx.h.gch
// RUN: c-index-test -test-load-source local %s -include %t.pfx.h > %t
// RUN: FileCheck %s < %t
diff --git a/test/Index/comment-custom-block-command.cpp b/test/Index/comment-custom-block-command.cpp
index 80a58caa2b50..f87cef96e590 100644
--- a/test/Index/comment-custom-block-command.cpp
+++ b/test/Index/comment-custom-block-command.cpp
@@ -17,7 +17,7 @@
// RUN: FileCheck %s < %t/out.c-index-direct
// RUN: FileCheck %s < %t/out.c-index-pch
-// XFAIL: valgrind
+// XFAIL: vg_leak
#ifndef HEADER
#define HEADER
diff --git a/test/Index/comment-misc-tags.m b/test/Index/comment-misc-tags.m
index 9eae5489fc06..bb16ea97b6d6 100644
--- a/test/Index/comment-misc-tags.m
+++ b/test/Index/comment-misc-tags.m
@@ -45,7 +45,7 @@
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
// CHECK: (CXComment_BlockCommand CommandName=[seealso]
// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ //k_ref/doc/uid/XX30000905-CH204 Programming] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ //k_ref/doc/uid/XX30000905-CH204 Programming])
// rdar://12379053
/*!
@@ -108,3 +108,4 @@ struct Test {int filler;};
// CHECK: (CXComment_BlockCommand CommandName=[par]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ And this is the second paragraph.])))
+
diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp
index c770ca8d30f0..8c0ed21b2f04 100644
--- a/test/Index/comment-to-html-xml-conversion.cpp
+++ b/test/Index/comment-to-html-xml-conversion.cpp
@@ -116,7 +116,8 @@ void comment_to_html_conversion_6();
/// \return Bbb.
void comment_to_html_conversion_7();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_7:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_7</Name><USR>c:@F@comment_to_html_conversion_7#</USR><Declaration>void comment_to_html_conversion_7()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_7:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_7</Name><USR>c:@F@comment_to_html_conversion_7#</USR><Declaration>void comment_to_html_conversion_7()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -132,7 +133,7 @@ void comment_to_html_conversion_7();
/// \returns Bbb.
void comment_to_html_conversion_8();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_8:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_8</Name><USR>c:@F@comment_to_html_conversion_8#</USR><Declaration>void comment_to_html_conversion_8()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_8:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_8</Name><USR>c:@F@comment_to_html_conversion_8#</USR><Declaration>void comment_to_html_conversion_8()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -148,7 +149,7 @@ void comment_to_html_conversion_8();
/// \result Bbb.
void comment_to_html_conversion_9();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_9:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_9</Name><USR>c:@F@comment_to_html_conversion_9#</USR><Declaration>void comment_to_html_conversion_9()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_9:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_9</Name><USR>c:@F@comment_to_html_conversion_9#</USR><Declaration>void comment_to_html_conversion_9()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -163,7 +164,7 @@ void comment_to_html_conversion_9();
/// \returns Bbb.
void comment_to_html_conversion_10();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_10:{{.*}} FullCommentAsHTML=[<p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Aaa. </p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_10</Name><USR>c:@F@comment_to_html_conversion_10#</USR><Declaration>void comment_to_html_conversion_10()</Declaration><ResultDiscussion><Para> Aaa. </Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_10:{{.*}} FullCommentAsHTML=[<div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Aaa. </p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_10</Name><USR>c:@F@comment_to_html_conversion_10#</USR><Declaration>void comment_to_html_conversion_10()</Declaration><ResultDiscussion><Para> Aaa. </Para><Para> Bbb.</Para></ResultDiscussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -183,7 +184,7 @@ void comment_to_html_conversion_10();
/// \returns Ccc.
void comment_to_html_conversion_11();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_11</Name><USR>c:@F@comment_to_html_conversion_11#</USR><Declaration>void comment_to_html_conversion_11()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Ccc.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Ccc.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_11</Name><USR>c:@F@comment_to_html_conversion_11#</USR><Declaration>void comment_to_html_conversion_11()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Ccc.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -270,12 +271,29 @@ void comment_to_html_conversion_16(int x1, int x2);
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+/// \param x1 Aaa.
+/// \param ... Bbb.
+void comment_to_html_conversion_17(int x1, ...);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa. </dd><dt class="param-name-index-vararg">...</dt><dd class="param-descr-index-vararg"> Bbb.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@F@comment_to_html_conversion_17#I.#</USR><Declaration>void comment_to_html_conversion_17(int x1, ...)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa. </Para></Discussion></Parameter><Parameter><Name>...</Name><IsVarArg /><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[...] ParamIndex=4294967295
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))] Extent=[276:1 - 276:48]
+
/// \tparam
/// \param aaa Blah blah
template<typename T>
-void comment_to_html_conversion_17(T aaa);
+void comment_to_html_conversion_18(T aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_18</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_18#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_18(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -290,9 +308,9 @@ void comment_to_html_conversion_17(T aaa);
/// \tparam T
/// \param aaa Blah blah
template<typename T>
-void comment_to_html_conversion_18(T aaa);
+void comment_to_html_conversion_19(T aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_18</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_18#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_18(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_19#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_19(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -307,9 +325,9 @@ void comment_to_html_conversion_18(T aaa);
/// \tparam T2 Bbb
/// \tparam T1 Aaa
template<typename T1, typename T2>
-void comment_to_html_conversion_19(T1 aaa, T2 bbb);
+void comment_to_html_conversion_20(T1 aaa, T2 bbb);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2&gt;\nvoid comment_to_html_conversion_19(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2&gt;\nvoid comment_to_html_conversion_20(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -327,9 +345,9 @@ void comment_to_html_conversion_19(T1 aaa, T2 bbb);
/// \tparam V Ccc
/// \tparam T1 Aaa
template<typename T1, typename T2, int V>
-void comment_to_html_conversion_20(T1 aaa, T2 bbb);
+void comment_to_html_conversion_21(T1 aaa, T2 bbb);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt;\nvoid comment_to_html_conversion_20(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_21#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt;\nvoid comment_to_html_conversion_21(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -355,9 +373,9 @@ void comment_to_html_conversion_20(T1 aaa, T2 bbb);
/// \tparam T Aaa
/// \tparam TT Bbb
template<template<template<typename T> class TT, class C> class TTT>
-void comment_to_html_conversion_21();
+void comment_to_html_conversion_22();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -385,9 +403,9 @@ void comment_to_html_conversion_21();
/// \param x2 Ddd.
/// \param x1 Ccc.
/// \returns Eee.
-void comment_to_html_conversion_22(int x1, int x2);
+void comment_to_html_conversion_23(int x1, int x2);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@F@comment_to_html_conversion_22#I#I#</USR><Declaration>void comment_to_html_conversion_22(int x1, int x2)</Declaration><Abstract><Para> Aaa.</Para></Abstract><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ccc. </Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ddd. </Para></Discussion></Parameter></Parameters><ResultDiscussion><Para> Eee.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><div class="result-discussion"><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p></div>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_23</Name><USR>c:@F@comment_to_html_conversion_23#I#I#</USR><Declaration>void comment_to_html_conversion_23(int x1, int x2)</Declaration><Abstract><Para> Aaa.</Para></Abstract><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ccc. </Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ddd. </Para></Discussion></Parameter></Parameters><ResultDiscussion><Para> Eee.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -412,9 +430,9 @@ void comment_to_html_conversion_22(int x1, int x2);
// CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))]
/// <br><a href="http://example.com/">Aaa</a>
-void comment_to_html_conversion_23();
+void comment_to_html_conversion_24();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_23</Name><USR>c:@F@comment_to_html_conversion_23#</USR><Declaration>void comment_to_html_conversion_23()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -428,9 +446,9 @@ void comment_to_html_conversion_23();
/// <a href="http://example.com/">Aaa</a>
/// <a href='http://example.com/'>Aaa</a>
/// \endverbatim
-void comment_to_html_conversion_24();
+void comment_to_html_conversion_25();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<pre> &lt;a href=&quot;http:&#47;&#47;example.com&#47;&quot;&gt;Aaa&lt;&#47;a&gt;\n &lt;a href=&#39;http:&#47;&#47;example.com&#47;&#39;&gt;Aaa&lt;&#47;a&gt;</pre>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Discussion><Verbatim xml:space="preserve" kind="verbatim"> &lt;a href=&quot;http://example.com/&quot;&gt;Aaa&lt;/a&gt;\n &lt;a href=&apos;http://example.com/&apos;&gt;Aaa&lt;/a&gt;</Verbatim></Discussion></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<pre> &lt;a href=&quot;http:&#47;&#47;example.com&#47;&quot;&gt;Aaa&lt;&#47;a&gt;\n &lt;a href=&#39;http:&#47;&#47;example.com&#47;&#39;&gt;Aaa&lt;&#47;a&gt;</pre>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_25</Name><USR>c:@F@comment_to_html_conversion_25#</USR><Declaration>void comment_to_html_conversion_25()</Declaration><Discussion><Verbatim xml:space="preserve" kind="verbatim"> &lt;a href=&quot;http://example.com/&quot;&gt;Aaa&lt;/a&gt;\n &lt;a href=&apos;http://example.com/&apos;&gt;Aaa&lt;/a&gt;</Verbatim></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -439,35 +457,63 @@ void comment_to_html_conversion_24();
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href="http://example.com/">Aaa</a>])
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href='http://example.com/'>Aaa</a>])))]
-/// \function foo
-/// \class foo
-/// \method foo
-/// \interface foo
+/// \def foo_def
+/// \fn foo_fn
+/// \namespace foo_namespace
+/// \overload foo_overload
+/// \property foo_property
+/// \typedef foo_typedef
+/// \var foo_var
+/// \function foo_function
+/// \class foo_class
+/// \method foo_method
+/// \interface foo_interface
/// Blah blah.
-void comment_to_html_conversion_25();
+void comment_to_html_conversion_26();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_25</Name><USR>c:@F@comment_to_html_conversion_25#</USR><Declaration>void comment_to_html_conversion_25()</Declaration><Abstract><Para> Blah blah.</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_26</Name><USR>c:@F@comment_to_html_conversion_26#</USR><Declaration>void comment_to_html_conversion_26()</Declaration><Abstract><Para> Blah blah.</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_def])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_fn])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_namespace])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_overload])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_property])
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_typedef])
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_var])
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_function])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_class])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_method])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo_interface])
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Blah blah.])))]
/// \unknown
-void comment_to_html_conversion_26();
+void comment_to_html_conversion_27();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> </p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_26</Name><USR>c:@F@comment_to_html_conversion_26#</USR><Declaration>void comment_to_html_conversion_26()</Declaration><Abstract><Para> </Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> </p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_27</Name><USR>c:@F@comment_to_html_conversion_27#</USR><Declaration>void comment_to_html_conversion_27()</Declaration><Abstract><Para> </Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -475,9 +521,9 @@ void comment_to_html_conversion_26();
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[unknown] RenderNormal)))]
/// \b Aaa
-void comment_to_html_conversion_27();
+void comment_to_html_conversion_28();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_27</Name><USR>c:@F@comment_to_html_conversion_27#</USR><Declaration>void comment_to_html_conversion_27()</Declaration><Abstract><Para> <bold>Aaa</bold></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_28</Name><USR>c:@F@comment_to_html_conversion_28#</USR><Declaration>void comment_to_html_conversion_28()</Declaration><Abstract><Para> <bold>Aaa</bold></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -485,9 +531,9 @@ void comment_to_html_conversion_27();
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[b] RenderBold Arg[0]=Aaa)))]
/// \c Aaa \p Bbb
-void comment_to_html_conversion_28();
+void comment_to_html_conversion_29();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_28</Name><USR>c:@F@comment_to_html_conversion_28#</USR><Declaration>void comment_to_html_conversion_28()</Declaration><Abstract><Para> <monospaced>Aaa</monospaced> <monospaced>Bbb</monospaced></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_29</Name><USR>c:@F@comment_to_html_conversion_29#</USR><Declaration>void comment_to_html_conversion_29()</Declaration><Abstract><Para> <monospaced>Aaa</monospaced> <monospaced>Bbb</monospaced></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -497,9 +543,9 @@ void comment_to_html_conversion_28();
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[p] RenderMonospaced Arg[0]=Bbb)))]
/// \a Aaa \e Bbb \em Ccc
-void comment_to_html_conversion_29();
+void comment_to_html_conversion_30();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_29</Name><USR>c:@F@comment_to_html_conversion_29#</USR><Declaration>void comment_to_html_conversion_29()</Declaration><Abstract><Para> <emphasized>Aaa</emphasized> <emphasized>Bbb</emphasized> <emphasized>Ccc</emphasized></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_30</Name><USR>c:@F@comment_to_html_conversion_30#</USR><Declaration>void comment_to_html_conversion_30()</Declaration><Abstract><Para> <emphasized>Aaa</emphasized> <emphasized>Bbb</emphasized> <emphasized>Ccc</emphasized></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -511,9 +557,9 @@ void comment_to_html_conversion_29();
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=Ccc)))]
/// \a 1<2 \e 3<4 \em 5<6 \param 7<8 aaa \tparam 9<10 bbb
-void comment_to_html_conversion_30();
+void comment_to_html_conversion_31();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>1&lt;2</em> <em>3&lt;4</em> <em>5&lt;6</em> </p><dl><dt class="tparam-name-index-invalid">9&lt;10</dt><dd class="tparam-descr-index-invalid"> bbb</dd></dl><dl><dt class="param-name-index-invalid">7&lt;8</dt><dd class="param-descr-index-invalid"> aaa </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_30</Name><USR>c:@F@comment_to_html_conversion_30#</USR><Declaration>void comment_to_html_conversion_30()</Declaration><Abstract><Para> <emphasized>1&lt;2</emphasized> <emphasized>3&lt;4</emphasized> <emphasized>5&lt;6</emphasized> </Para></Abstract><TemplateParameters><Parameter><Name>9&lt;10</Name><Discussion><Para> bbb</Para></Discussion></Parameter></TemplateParameters><Parameters><Parameter><Name>7&lt;8</Name><Direction isExplicit="0">in</Direction><Discussion><Para> aaa </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>1&lt;2</em> <em>3&lt;4</em> <em>5&lt;6</em> </p><dl><dt class="tparam-name-index-invalid">9&lt;10</dt><dd class="tparam-descr-index-invalid"> bbb</dd></dl><dl><dt class="param-name-index-invalid">7&lt;8</dt><dd class="param-descr-index-invalid"> aaa </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_31</Name><USR>c:@F@comment_to_html_conversion_31#</USR><Declaration>void comment_to_html_conversion_31()</Declaration><Abstract><Para> <emphasized>1&lt;2</emphasized> <emphasized>3&lt;4</emphasized> <emphasized>5&lt;6</emphasized> </Para></Abstract><TemplateParameters><Parameter><Name>9&lt;10</Name><Discussion><Para> bbb</Para></Discussion></Parameter></TemplateParameters><Parameters><Parameter><Name>7&lt;8</Name><Direction isExplicit="0">in</Direction><Discussion><Para> aaa </Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -532,9 +578,9 @@ void comment_to_html_conversion_30();
// CHECK-NEXT: (CXComment_Text Text=[ bbb]))))]
/// \\ \@ \& \$ \# \< \> \% \" \. \::
-void comment_to_html_conversion_31();
+void comment_to_html_conversion_32();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_31</Name><USR>c:@F@comment_to_html_conversion_31#</USR><Declaration>void comment_to_html_conversion_31()</Declaration><Abstract><Para> \ @ &amp; $ # &lt; &gt; % &quot; . ::</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_32</Name><USR>c:@F@comment_to_html_conversion_32#</USR><Declaration>void comment_to_html_conversion_32()</Declaration><Abstract><Para> \ @ &amp; $ # &lt; &gt; % &quot; . ::</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -562,9 +608,9 @@ void comment_to_html_conversion_31();
// CHECK-NEXT: (CXComment_Text Text=[::])))]
/// &amp; &lt; &gt; &quot; &apos; &#109;&#101;&#111;&#119; &#x6d;&#x65;&#x6F;&#X77;
-void comment_to_html_conversion_32();
+void comment_to_html_conversion_33();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot; &#39; meow meow</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_32</Name><USR>c:@F@comment_to_html_conversion_32#</USR><Declaration>void comment_to_html_conversion_32()</Declaration><Abstract><Para> &amp; &lt; &gt; &quot; &apos; meow meow</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot; &#39; meow meow</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_33</Name><USR>c:@F@comment_to_html_conversion_33#</USR><Declaration>void comment_to_html_conversion_33()</Declaration><Abstract><Para> &amp; &lt; &gt; &quot; &apos; meow meow</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -590,9 +636,9 @@ void comment_to_html_conversion_32();
// CHECK-NEXT: (CXComment_Text Text=[w])))]
/// <em>0&lt;i</em>
-void comment_to_html_conversion_33();
+void comment_to_html_conversion_34();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_33</Name><USR>c:@F@comment_to_html_conversion_33#</USR><Declaration>void comment_to_html_conversion_33()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F@comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -610,9 +656,9 @@ void comment_to_html_conversion_33();
/// &nbsp; a non breakable space.
/// &Delta; Greek letter Delta Δ.
/// &Gamma; Greek letter Gamma Γ.
-void comment_to_html_conversion_34();
+void comment_to_html_conversion_35();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F@comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_35:{{.*}} FullCommentAsHTML=[<p class="para-brief"> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_35</Name><USR>c:@F@comment_to_html_conversion_35#</USR><Declaration>void comment_to_html_conversion_35()</Declaration><Abstract><Para> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -767,6 +813,57 @@ enum class comment_to_xml_conversion_17 {
// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Declaration>comment_to_xml_conversion_18</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
};
+//===---
+// Check that we attach comments from the base class to derived classes if they don't have a comment.
+// rdar://13647476
+//===---
+
+/// BaseToSuper1_Base
+class BaseToSuper1_Base {};
+
+class BaseToSuper1_Derived : public BaseToSuper1_Base {};
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper1_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper1_Base</Name><USR>c:@C@BaseToSuper1_Base</USR><Declaration>class BaseToSuper1_Derived : public BaseToSuper1_Base {}</Declaration><Abstract><Para> BaseToSuper1_Base</Para></Abstract></Class>]
+
+
+/// BaseToSuper2_Base
+class BaseToSuper2_Base {};
+
+/// BaseToSuper2_Derived
+class BaseToSuper2_Derived : public BaseToSuper2_Base {};
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@C@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_Derived : public BaseToSuper2_Base {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
+
+class BaseToSuper2_MoreDerived : public BaseToSuper2_Derived {};
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@C@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_MoreDerived : public BaseToSuper2_Derived {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
+
+
+/// BaseToSuper3_Base
+class BaseToSuper3_Base {};
+
+class BaseToSuper3_DerivedA : public virtual BaseToSuper3_Base {};
+
+class BaseToSuper3_DerivedB : public virtual BaseToSuper3_Base {};
+
+class BaseToSuper3_MoreDerived : public BaseToSuper3_DerivedA, public BaseToSuper3_DerivedB {};
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper3_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper3_Base</Name><USR>c:@C@BaseToSuper3_Base</USR><Declaration>class BaseToSuper3_MoreDerived : public BaseToSuper3_DerivedA,\n public BaseToSuper3_DerivedB {}</Declaration><Abstract><Para> BaseToSuper3_Base</Para></Abstract></Class>]
+
+
+// Check that we propagate comments only through public inheritance.
+
+/// BaseToSuper4_Base
+class BaseToSuper4_Base {};
+
+/// BaseToSuper4_DerivedA
+class BaseToSuper4_DerivedA : virtual BaseToSuper4_Base {};
+
+class BaseToSuper4_DerivedB : public virtual BaseToSuper4_Base {};
+
+class BaseToSuper4_MoreDerived : BaseToSuper4_DerivedA, public BaseToSuper4_DerivedB {};
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper4_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper4_Base</Name><USR>c:@C@BaseToSuper4_Base</USR><Declaration>class BaseToSuper4_MoreDerived : BaseToSuper4_DerivedA,\n public BaseToSuper4_DerivedB {}</Declaration><Abstract><Para> BaseToSuper4_Base</Para></Abstract></Class>]
+
+//===---
+// Check the representation of \todo in XML.
+//===---
+
/// Aaa.
/// \todo Bbb.
void comment_to_xml_conversion_todo_1();
@@ -793,5 +890,102 @@ void comment_to_xml_conversion_todo_3();
void comment_to_xml_conversion_todo_4();
// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_4:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_4</Name><USR>c:@F@comment_to_xml_conversion_todo_4#</USR><Declaration>void comment_to_xml_conversion_todo_4()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb. </Para><Para kind="todo"> Ccc.</Para></Discussion></Function>]
+
+//===---
+// Test the representation of exception specifications in AST and XML.
+//===---
+
+/// Aaa.
+/// \throws Bbb.
+void comment_to_xml_conversion_exceptions_1();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_1:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_1</Name><USR>c:@F@comment_to_xml_conversion_exceptions_1#</USR><Declaration>void comment_to_xml_conversion_exceptions_1()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \throw Bbb.
+void comment_to_xml_conversion_exceptions_2();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_2:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_2</Name><USR>c:@F@comment_to_xml_conversion_exceptions_2#</USR><Declaration>void comment_to_xml_conversion_exceptions_2()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throw]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \exception Bbb.
+void comment_to_xml_conversion_exceptions_3();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_3:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_3</Name><USR>c:@F@comment_to_xml_conversion_exceptions_3#</USR><Declaration>void comment_to_xml_conversion_exceptions_3()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[exception]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \throws Bbb.
+/// \throws Ccc.
+/// \throws Ddd.
+void comment_to_xml_conversion_exceptions_4();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_4:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_4</Name><USR>c:@F@comment_to_xml_conversion_exceptions_4#</USR><Declaration>void comment_to_xml_conversion_exceptions_4()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb. </Para><Para> Ccc. </Para><Para> Ddd.</Para></Exceptions></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ddd.]))))]
+
+/// Aaa.
+/// \throws Bbb.
+/// \throw Ccc.
+void comment_to_xml_conversion_exceptions_5();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_5:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_5</Name><USR>c:@F@comment_to_xml_conversion_exceptions_5#</USR><Declaration>void comment_to_xml_conversion_exceptions_5()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb. </Para><Para> Ccc.</Para></Exceptions></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[throw]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))]
+
+
+// rdar://14348912
+#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
+
+/**! Documentation comment */
+typedef NS_ENUM(int, Color) { Red, Green, Blue };
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:22: TypedefDecl=Color:[[@LINE-1]]:22
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[! Documentation comment ])))]
+
#endif
diff --git a/test/Index/comment-unqualified-objc-pointer.m b/test/Index/comment-unqualified-objc-pointer.m
index 546d4fa9f077..e9e1ceee236b 100644
--- a/test/Index/comment-unqualified-objc-pointer.m
+++ b/test/Index/comment-unqualified-objc-pointer.m
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 -fobjc-default-synthesize-properties -fobjc-arc %s > %t/out
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 -fobjc-arc %s > %t/out
// RUN: FileCheck %s < %t/out
// rdar://13757500
diff --git a/test/Index/comment-xml-schema.c b/test/Index/comment-xml-schema.c
index b8560f7e279b..2bbdfcfe9999 100644
--- a/test/Index/comment-xml-schema.c
+++ b/test/Index/comment-xml-schema.c
@@ -33,21 +33,22 @@
//
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-para-kind-01.xml
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-01.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-02.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-03.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-04.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-05.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-06.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-07.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-08.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-09.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-10.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-11.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-12.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-//
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-01.xml 2>&1 | FileCheck %s -check-prefix=INVALID
-// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-02.xml 2>&1 | FileCheck %s -check-prefix=INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-01.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-02.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-03.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-04.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-05.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-06.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-07.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-08.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-09.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-10.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-11.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-12.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-13.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+//
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-01.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
+// RUN: not xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-02.xml 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID
// CHECK-INVALID: fails to validate
diff --git a/test/Index/complete-documentation-properties.m b/test/Index/complete-documentation-properties.m
index 774a02021e74..21ddf805a9c0 100644
--- a/test/Index/complete-documentation-properties.m
+++ b/test/Index/complete-documentation-properties.m
@@ -53,22 +53,22 @@
return 0;
}
@end
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:47:16 %s | FileCheck -check-prefix=CC1 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:47:16 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText ReadonlyGetter}{{.*}}(brief comment: This is ReadonlyProperty)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:48:13 %s | FileCheck -check-prefix=CC2 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:48:13 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText GetterInClassExtension}{{.*}}(brief comment: This is PropertyInClassExtension)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:49:13 %s | FileCheck -check-prefix=CC3 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:49:13 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: {TypedText PropertyInPrimaryClass}{{.*}}(brief comment: This is PropertyInPrimaryClass)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:50:13 %s | FileCheck -check-prefix=CC4 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:50:13 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: {TypedText Record}{{.*}}(brief comment: This is Record)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:51:9 %s | FileCheck -check-prefix=CC5 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:51:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: {TypedText setThisRecord:}{Placeholder (id)}{{.*}}(brief comment: This is Record)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:52:12 %s | FileCheck -check-prefix=CC6 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:52:12 %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: {TypedText GetterInClassExtension}{{.*}}(brief comment: This is PropertyInClassExtension)
@interface AnotherAppDelegate
@@ -87,6 +87,6 @@
self.ReadonlyGetter;
}
@end
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:87:6 %s | FileCheck -check-prefix=CC7 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:87:6 %s | FileCheck -check-prefix=CHECK-CC7 %s
// CHECK-CC7: {TypedText ReadonlyGetter}{{.*}}(brief comment: This is getter = ReadonlyGetter)
diff --git a/test/Index/complete-documentation-templates.cpp b/test/Index/complete-documentation-templates.cpp
index 4cb826e1d5aa..ca24bc374d6a 100644
--- a/test/Index/complete-documentation-templates.cpp
+++ b/test/Index/complete-documentation-templates.cpp
@@ -105,20 +105,20 @@ void test_CC5_CC6_CC7() {
T100<int, long>::T105 t105;
}
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:17:1 %s | FileCheck -check-prefix=CC1 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:17:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: FunctionTemplate:{ResultType void}{TypedText T1}{{.*}}(brief comment: This is T1.)
// CHECK-CC1: FunctionTemplate:{ResultType void}{TypedText T2}{{.*}}(brief comment: This is T2.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:56:12 %s | FileCheck -check-prefix=CC2 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:56:12 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: CXXMethod:{ResultType void}{TypedText T4}{{.*}}(brief comment: This is T4.)
// CHECK-CC2: VarDecl:{ResultType int}{TypedText T5}{{.*}}(brief comment: This is T5.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:58:6 %s | FileCheck -check-prefix=CC3 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:58:6 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: FunctionTemplate:{ResultType void}{TypedText T11}{{.*}}(brief comment: This is T11.)
// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T6}{{.*}}(brief comment: This is T6.)
// CHECK-CC3: FieldDecl:{ResultType int}{TypedText T7}{{.*}}(brief comment: This is T7.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:59:12 %s | FileCheck -check-prefix=CC4 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:59:12 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: EnumConstantDecl:{ResultType T3<int>::T9}{TypedText T10}{{.*}}(brief comment: This is T10.)
// FIXME: after we implement propagating comments through typedefs, this
// typedef for implicit instantiation should pick up the documentation
@@ -128,16 +128,16 @@ void test_CC5_CC6_CC7() {
// CHECK-CC4: ClassDecl:{TypedText T8}{{.*}}(brief comment: This is T8.)
// CHECK-CC4: EnumDecl:{TypedText T9}{{.*}}(brief comment: This is T9.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:102:20 %s | FileCheck -check-prefix=CC5 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:102:20 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: CXXMethod:{ResultType void}{TypedText T101}{{.*}}(brief comment: This is T101.)
// CHECK-CC5: VarDecl:{ResultType int}{TypedText T102}{{.*}}(brief comment: This is T102.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:104:8 %s | FileCheck -check-prefix=CC6 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:104:8 %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: CXXMethod:{ResultType void}{TypedText T103}{{.*}}(brief comment: This is T103.)
// CHECK-CC6: FieldDecl:{ResultType int}{TypedText T104}{{.*}}(brief comment: This is T104.)
// CHECK-CC6: FunctionTemplate:{ResultType void}{TypedText T108}{{.*}}(brief comment: This is T108.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:105:20 %s | FileCheck -check-prefix=CC7 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:105:20 %s | FileCheck -check-prefix=CHECK-CC7 %s
// CHECK-CC7: ClassDecl:{TypedText T105}{{.*}}(brief comment: This is T105.)
// CHECK-CC7: EnumDecl:{TypedText T106}{{.*}}(brief comment: This is T106.)
// CHECK-CC7: EnumConstantDecl:{ResultType T100<int, long>::T106}{TypedText T107}{{.*}}(brief comment: This is T107.)
diff --git a/test/Index/complete-documentation.cpp b/test/Index/complete-documentation.cpp
index 49b61f03ce6c..553660a124f8 100644
--- a/test/Index/complete-documentation.cpp
+++ b/test/Index/complete-documentation.cpp
@@ -37,15 +37,15 @@ void test1() {
t6.T8();
}
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:32:1 %s | FileCheck -check-prefix=CC1 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:32:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText T1}{{.*}}(brief comment: Aaa.)
// CHECK-CC1: ClassDecl:{TypedText T2}{{.*}}(brief comment: Bbb.)
// CHECK-CC1: Namespace:{TypedText T5}{{.*}}(brief comment: Eee.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:34:6 %s | FileCheck -check-prefix=CC2 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:34:6 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: CXXMethod:{ResultType void}{TypedText T3}{{.*}}(brief comment: Ccc.)
// CHECK-CC2: FieldDecl:{ResultType int}{TypedText T4}{{.*}}(brief comment: Ddd.)
-// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:37:6 %s | FileCheck -check-prefix=CC3 %s
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:37:6 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T7}{LeftParen (}{RightParen )} (34)(brief comment: Fff.)
// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T8}{LeftParen (}{RightParen )} (34)(brief comment: Ggg.)
diff --git a/test/Index/complete-modules.m b/test/Index/complete-modules.m
index d63c4b89566c..175cf3db2c7f 100644
--- a/test/Index/complete-modules.m
+++ b/test/Index/complete-modules.m
@@ -5,12 +5,12 @@
// RUN: rm -rf %t
// RUN: c-index-test -code-completion-at=%s:4:9 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP-LEVEL %s
-// CHECK-TOP-LEVEL: NotImplemented:{TypedText Framework} (50)
-// CHECK-TOP-LEVEL: NotImplemented:{TypedText LibA} (50)
-// CHECK-TOP-LEVEL: NotImplemented:{TypedText nested} (50)
+// CHECK-TOP-LEVEL: ModuleImport:{TypedText Framework} (50)
+// CHECK-TOP-LEVEL: ModuleImport:{TypedText LibA} (50)
+// CHECK-TOP-LEVEL: ModuleImport:{TypedText nested} (50)
// RUN: c-index-test -code-completion-at=%s:4:14 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-LIBA %s
-// CHECK-LIBA: NotImplemented:{TypedText Extensions} (50)
+// CHECK-LIBA: ModuleImport:{TypedText Extensions} (50)
// RUN: c-index-test -code-completion-at=%s:4:1 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP %s
// CHECK-TOP: NotImplemented:{TypedText @import}{HorizontalSpace }{Placeholder module} (40)
diff --git a/test/Index/complete-pch.m b/test/Index/complete-pch.m
index 517d49c6351e..4c29f2796b5c 100644
--- a/test/Index/complete-pch.m
+++ b/test/Index/complete-pch.m
@@ -11,6 +11,8 @@ void msg_id(id x) {
[x instanceMethod1:5];
}
+// REQUIRES: native
+
// Build the precompiled header
// RUN: %clang -x objective-c-header -o %t.h.pch %S/Inputs/complete-pch.h
diff --git a/test/Index/complete-preamble.cpp b/test/Index/complete-preamble.cpp
index 61fb90a9db96..c57c88ab330a 100644
--- a/test/Index/complete-preamble.cpp
+++ b/test/Index/complete-preamble.cpp
@@ -3,6 +3,6 @@ void f() {
std::
}
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50)
diff --git a/test/Index/complete-qualified.cpp b/test/Index/complete-qualified.cpp
index 38a678af2422..a17ea25370c7 100644
--- a/test/Index/complete-qualified.cpp
+++ b/test/Index/complete-qualified.cpp
@@ -13,7 +13,7 @@ void foo()
{
Foo::
-// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CC1 %s
+// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// 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 )}
diff --git a/test/Index/crash-recovery-modules.m b/test/Index/crash-recovery-modules.m
index 23740ec98b3f..431c23f7dcad 100644
--- a/test/Index/crash-recovery-modules.m
+++ b/test/Index/crash-recovery-modules.m
@@ -15,6 +15,21 @@
@import Crash;
+#ifdef LIBCLANG_CRASH
+#pragma clang __debug crash
+#endif
+
void test() {
const char* error = getCrashString();
}
+
+
+// RUN: rm -rf %t
+// Check that libclang crash-recovery works; both with a module building 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 -DLIBCLANG_CRASH %s 2> %t.err
+// RUN: FileCheck < %t.err -check-prefix=CHECK-LIBCLANG-CRASH %s
+// ...and with module building successful.
+// 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 -DLIBCLANG_CRASH %s 2> %t.err
+// RUN: FileCheck < %t.err -check-prefix=CHECK-LIBCLANG-CRASH %s
+// CHECK-LIBCLANG-CRASH: libclang: crash detected during parsing
+// CHECK-LIBCLANG-CRASH: Unable to load translation unit!
diff --git a/test/Index/create-tu-fail.c b/test/Index/create-tu-fail.c
index f259cca50ff4..de3250173a3f 100644
--- a/test/Index/create-tu-fail.c
+++ b/test/Index/create-tu-fail.c
@@ -2,7 +2,7 @@
// RUN: touch %t.c
// RUN: c-index-test -write-pch %t.pch %t.c
// RUN: cp %s %t.c
-// RUN: c-index-test -test-load-tu %t.pch local 2>&1 | FileCheck %s
+// RUN: not c-index-test -test-load-tu %t.pch local 2>&1 | FileCheck %s
// rdar://11558355
// Unfortunately this would crash reliably only via valgrind.
diff --git a/test/Index/error-on-deserialized.c b/test/Index/error-on-deserialized.c
index 8ba828328e7a..bf0d59a05880 100644
--- a/test/Index/error-on-deserialized.c
+++ b/test/Index/error-on-deserialized.c
@@ -6,7 +6,7 @@
// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h
// RUN: env CINDEXTEST_FAILONERROR=1 not c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
// RUN: -Xclang -error-on-deserialized-decl=NestedVar1
-// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: env CINDEXTEST_FAILONERROR=1 not c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 2>&1 \
// RUN: | FileCheck %s
diff --git a/test/Index/file-includes.c b/test/Index/file-includes.c
index 2dfced0c0c4f..ac3d568dc53d 100644
--- a/test/Index/file-includes.c
+++ b/test/Index/file-includes.c
@@ -22,3 +22,6 @@ int LocalVar;
// TOP: inclusion directive=targeted-nested1.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-nested1.h) =[5:1 - 5:2]
// TOP: inclusion directive=targeted-fields.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-fields.h) =[16:1 - 16:2]
+
+// rdar://13803893
+// RUN: c-index-test -file-includes-in=%S/Inputs/empty.h %S/Inputs/empty.h
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
index 7eaa3a0a3c1e..f659fb1ff61c 100644
--- a/test/Index/get-cursor.m
+++ b/test/Index/get-cursor.m
@@ -99,6 +99,20 @@ void foo3(Test3 *test3) {
@synthesize prop1 = _prop1;
@end
+@protocol TestProt
+-(void)protMeth1;
+@property (retain) id propProp1;
+
+@optional
+-(void)protMeth2;
+@property (retain) id propProp2;
+
+@required
+-(void)protMeth3;
+@property (retain) id propProp3;
+@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
// CHECK-PROP: ObjCPropertyDecl=foo2:5:27
@@ -146,3 +160,13 @@ void foo3(Test3 *test3) {
// RUN: c-index-test -cursor-at=%s:86:7 -cursor-at=%s:89:7 %s | FileCheck -check-prefix=CHECK-SELECTORLOC %s
// CHECK-SELECTORLOC: 86:6 ObjCInstanceMethodDecl=meth1:86:6 (Definition) Extent=[86:1 - 88:2] Spelling=meth1 ([86:6 - 86:11]) Selector index=0
// CHECK-SELECTORLOC: 89:6 ObjCInstanceMethodDecl=meth2:89:6 (Definition) Extent=[89:1 - 91:2] Spelling=meth2 ([89:6 - 89:11]) Selector index=0
+
+// RUN: c-index-test -cursor-at=%s:103:10 -cursor-at=%s:104:10 \
+// RUN: -cursor-at=%s:107:10 -cursor-at=%s:108:10 \
+// RUN: -cursor-at=%s:111:10 -cursor-at=%s:112:10 %s | FileCheck -check-prefix=CHECK-OBJCOPTIONAL %s
+// CHECK-OBJCOPTIONAL: 103:8 ObjCInstanceMethodDecl=protMeth1:103:8 Extent=[103:1 - 103:18]
+// CHECK-OBJCOPTIONAL: 104:23 ObjCPropertyDecl=propProp1:104:23 [retain,] Extent=[104:1 - 104:32]
+// CHECK-OBJCOPTIONAL: 107:8 ObjCInstanceMethodDecl=protMeth2:107:8 (@optional) Extent=[107:1 - 107:18]
+// CHECK-OBJCOPTIONAL: 108:23 ObjCPropertyDecl=propProp2:108:23 (@optional) [retain,] Extent=[108:1 - 108:32]
+// CHECK-OBJCOPTIONAL: 111:8 ObjCInstanceMethodDecl=protMeth3:111:8 Extent=[111:1 - 111:18]
+// CHECK-OBJCOPTIONAL: 112:23 ObjCPropertyDecl=propProp3:112:23 [retain,] Extent=[112:1 - 112:32]
diff --git a/test/Index/index-decls.m b/test/Index/index-decls.m
index c6b14bb8fda5..a405abc78c88 100644
--- a/test/Index/index-decls.m
+++ b/test/Index/index-decls.m
@@ -33,6 +33,21 @@ int test1() {
return extfn();
}
+@interface I4
+@property (assign, nonatomic) id prop;
+-(id)prop;
+-(void)setProp:(id)p;
+@end
+
+@implementation I4
+@synthesize prop = _prop;
+-(id)prop {
+ return 0;
+}
+-(void)setProp:(id)p {
+}
+@end
+
// RUN: c-index-test -index-file %s -target x86_64-apple-macosx10.7 > %t
// RUN: FileCheck %s -input-file=%t
// CHECK: [indexDeclaration]: kind: objc-class | name: I | {{.*}} | loc: 1:12
@@ -54,3 +69,7 @@ int test1() {
// CHECK: [indexEntityReference]: kind: variable | name: extvar | {{.*}} | loc: 31:3
// CHECK: [indexDeclaration]: kind: function | name: extfn | {{.*}} | loc: 32:14
// CHECK: [indexEntityReference]: kind: function | name: extfn | {{.*}} | loc: 33:10
+
+// CHECK: [indexDeclaration]: kind: objc-class | name: I4 | {{.*}} | loc: 36:12
+// CHECK-NOT: [indexDeclaration]: kind: objc-instance-method {{.*}} loc: 37:
+// CHECK-NOT: [indexDeclaration]: kind: objc-instance-method {{.*}} loc: 43:
diff --git a/test/Index/index-file.cpp b/test/Index/index-file.cpp
index 7634c0db863f..37b14a2715a9 100644
--- a/test/Index/index-file.cpp
+++ b/test/Index/index-file.cpp
@@ -4,7 +4,20 @@ extern "C" {
template < typename T > *Allocate() { }
}
+// rdar://14063074
+namespace rdar14063074 {
+template <typename T>
+struct TS {};
+struct TS<int> {};
+
+template <typename T>
+void tfoo() {}
+void tfoo<int>() {}
+}
+
// RUN: c-index-test -index-file %s > %t
// RUN: FileCheck %s -input-file=%t
// CHECK: [indexDeclaration]: kind: type-alias | name: MyTypeAlias | {{.*}} | loc: 1:7
+// CHECK: [indexDeclaration]: kind: struct-template-spec | name: TS | {{.*}} | loc: 11:8
+// CHECK: [indexDeclaration]: kind: function-template-spec | name: tfoo | {{.*}} | loc: 15:6
diff --git a/test/Index/index-module.m b/test/Index/index-module.m
index 77dee98b4ac8..d6953136d863 100644
--- a/test/Index/index-module.m
+++ b/test/Index/index-module.m
@@ -21,11 +21,13 @@ int glob;
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_MODULE_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]DependsOnModule\.h]] | {{.*}} | hash loc: <invalid>
// 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
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_OTHER_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]other\.h]] | {{.*}} | hash loc: <invalid>
+// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_NOT_CXX_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]not_cxx\.h]] | {{.*}} | hash loc: <invalid>
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: <invalid>
// 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
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_PRIVATE_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]PrivateHeaders[/\\]DependsOnModulePrivate.h]] | {{.*}} | hash loc: <invalid>
// CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache{{[/\\]}}Module.pcm | loc: [[DMOD_MODULE_H]]:1:2 | name: "Module" | isImplicit: 1
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_other | {{.*}} | loc: [[DMOD_OTHER_H]]:1:5
+// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: template | {{.*}} | loc: [[DMOD_NOT_CXX_H]]:1:12
// CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache/DependsOnModule.pcm | loc: {{.*}}SubFramework.h:1:2 | name: "DependsOnModule.SubFramework.Other" | isImplicit: 1
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: sub_framework | {{.*}} | loc: [[DMOD_SUB_H]]:2:8
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: sub_framework_other | {{.*}} | loc: [[DMOD_SUB_OTHER_H]]:1:9
diff --git a/test/Index/overrides.cpp b/test/Index/overrides.cpp
index a711d82bea80..e311699f8660 100644
--- a/test/Index/overrides.cpp
+++ b/test/Index/overrides.cpp
@@ -17,7 +17,14 @@ struct D : C {
void C::g() {}
+struct E {
+ virtual void h() = 0;
+ template <typename T> void i(T);
+};
+
// RUN: c-index-test -test-load-source local %s | FileCheck %s
// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 (virtual) [Overrides @7:16] Extent=[11:3 - 11:19]
// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 (virtual) [Overrides @2:16, @6:16] Extent=[15:3 - 15:22]
// CHECK: overrides.cpp:18:9: CXXMethod=g:18:9 (Definition) (virtual) [Overrides @7:16] Extent=[18:1 - 18:15]
+// CHECK: overrides.cpp:21:16: CXXMethod=h:21:16 (virtual) (pure) Extent=[21:3 - 21:23]
+// CHECK: overrides.cpp:22:30: FunctionTemplate=i:22:30 Extent=[22:3 - 22:34]
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index 46ead4f64256..9285693396e0 100644
--- a/test/Index/overriding-method-comments.mm
+++ b/test/Index/overriding-method-comments.mm
@@ -19,7 +19,7 @@
- (void)METH:(id)AAA;
@end
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)AAA;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)AAA;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ</Para></Discussion></Parameter></Parameters></Function>]
@interface Sub : Root
@end
@@ -28,13 +28,13 @@
- (void)METH:(id)BBB;
@end
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)BBB;</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)BBB;</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ</Para></Discussion></Parameter></Parameters></Function>]
@implementation Sub(CAT)
- (void)METH:(id)III {}
@end
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)III;</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)III;</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ</Para></Discussion></Parameter></Parameters></Function>]
@interface Redec : Root
@end
@@ -48,13 +48,13 @@
- (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC;
@end
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double</Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
@implementation Redec
- (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {}
@end
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double</Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
struct Base {
/// \brief Does something.
diff --git a/test/Index/pch-with-errors.c b/test/Index/pch-with-errors.c
index 2d396134e5f2..5c94a8a8e4d3 100644
--- a/test/Index/pch-with-errors.c
+++ b/test/Index/pch-with-errors.c
@@ -37,8 +37,8 @@ void foo(void) {
// CHECK-INDEX: [indexDeclaration]: kind: function | name: foo
// CHECK-INDEX: [indexEntityReference]: kind: function | name: erroneous
-// RUN: %clang -fsyntax-only %s -include %t.h 2>&1 | FileCheck -check-prefix=PCH-ERR %s
+// RUN: not %clang -fsyntax-only %s -include %t.h 2>&1 | FileCheck -check-prefix=PCH-ERR %s
// PCH-ERR: error: PCH file contains compiler errors
-// RUN: c-index-test -write-pch %t.pch foobar.c 2>&1 | FileCheck -check-prefix=NONEXISTENT %s
+// RUN: not c-index-test -write-pch %t.pch foobar.c 2>&1 | FileCheck -check-prefix=NONEXISTENT %s
// NONEXISTENT: Unable to load translation unit
diff --git a/test/Index/pch-with-errors.m b/test/Index/pch-with-errors.m
index cc42cd308141..397f8e8e17cb 100644
--- a/test/Index/pch-with-errors.m
+++ b/test/Index/pch-with-errors.m
@@ -9,6 +9,12 @@
-(void)meth;
@end
+struct FFF1
+extern I2 *somevar1;
+
+enum FFF2
+extern I2 *somevar2;
+
#else
void foo(I2 *i) {
diff --git a/test/Index/pch-with-module.m b/test/Index/pch-with-module.m
new file mode 100644
index 000000000000..e839c811dab6
--- /dev/null
+++ b/test/Index/pch-with-module.m
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t.cache
+// RUN: c-index-test -write-pch %t.h.pch %s -target x86_64-apple-macosx10.7 -fobjc-arc -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs -Xclang -fdisable-module-hash
+// RUN: %clang -fsyntax-only %s -target x86_64-apple-macosx10.7 -include %t.h -fobjc-arc -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \
+// RUN: -Xclang -fdisable-module-hash -Xclang -detailed-preprocessing-record -Xclang -verify
+
+// expected-no-diagnostics
+
+#ifndef PCH_HEADER
+#define PCH_HEADER
+
+#include <Module/Module.h>
+
+@interface Module(PCHCat)
+-(id)PCH_meth;
+@end
+
+#else
+
+void foo(Module *m) {
+ [m PCH_meth];
+}
+
+#endif
diff --git a/test/Index/preamble-reparse-with-BOM.m b/test/Index/preamble-reparse-with-BOM.m
index a2a89c8d8e15..6727a7ee1cac 100644
--- a/test/Index/preamble-reparse-with-BOM.m
+++ b/test/Index/preamble-reparse-with-BOM.m
@@ -2,5 +2,7 @@
@interface I2
@end
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 \
-// RUN: c-index-test -test-load-source-reparse 1 local %s
+// RUN: env CINDEXTEST_EDITING=1 \
+// RUN: c-index-test -test-load-source-reparse 1 local %s | FileCheck %s
+
+// CHECK: preamble-reparse-with-BOM.m:2:12: ObjCInterfaceDecl=I2:2:12 Extent=[2:1 - 3:5]
diff --git a/test/Index/preamble.c b/test/Index/preamble.c
index 8a158e9b30ce..92a9b84546ff 100644
--- a/test/Index/preamble.c
+++ b/test/Index/preamble.c
@@ -1,5 +1,7 @@
#include "prefix.h"
#include "preamble.h"
+#include "preamble-with-error.h"
+
int wibble(int);
void f(int x) {
@@ -14,10 +16,10 @@ void f(int x) {
// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13]
// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13]
// CHECK: preamble.h:5:10: IntegerLiteral= Extent=[5:10 - 5:11]
-// CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:1 - 3:16]
-// CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]
+// CHECK: preamble.c:5:5: FunctionDecl=wibble:5:5 Extent=[5:1 - 5:16]
+// CHECK: preamble.c:5:15: ParmDecl=:5:15 (Definition) Extent=[5:12 - 5:16]
// CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:6:1 -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck -check-prefix CHECK-CC %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:8:1 -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck -check-prefix CHECK-CC %s
// CHECK-CC: FunctionDecl:{ResultType int}{TypedText bar}{LeftParen (}{Placeholder int i}{RightParen )} (50)
// CHECK-CC: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder int x}{RightParen )} (50)
// CHECK-CC: FunctionDecl:{ResultType int}{TypedText foo}{LeftParen (}{Placeholder int}{RightParen )} (50)
diff --git a/test/Index/print-type-cxx11.cpp b/test/Index/print-type-cxx11.cpp
new file mode 100644
index 000000000000..0ad547377462
--- /dev/null
+++ b/test/Index/print-type-cxx11.cpp
@@ -0,0 +1,8 @@
+struct RefQualifierTest {
+ void f() & {};
+ void f() && {};
+};
+
+// RUN: c-index-test -test-print-type -std=c++11 %s | FileCheck %s
+// CHECK: CXXMethod=f:2:8 (Definition) [type=void () &] [typekind=FunctionProto] lvalue-ref-qualifier [resulttype=void] [resulttypekind=Void] [isPOD=0]
+// CHECK: CXXMethod=f:3:8 (Definition) [type=void () &&] [typekind=FunctionProto] rvalue-ref-qualifier [resulttype=void] [resulttypekind=Void] [isPOD=0]
diff --git a/test/Index/print-type-size.cpp b/test/Index/print-type-size.cpp
index 698d96705bc9..58f2e14c33a4 100644
--- a/test/Index/print-type-size.cpp
+++ b/test/Index/print-type-size.cpp
@@ -74,13 +74,6 @@ struct Test2 {
int foobar;
};
};
- struct inner {
- struct {
-//CHECK64: FieldDecl=mybar:[[@LINE+1]]:15 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=0]
- int mybar;
- };
-//CHECK64: FieldDecl=mole:[[@LINE+1]]:7 (Definition) [type=struct inner] [typekind=Unexposed] [sizeof=4] [alignof=4] [offsetof=96]
- } mole;
};
};
@@ -91,12 +84,9 @@ namespace Incomplete {
// test that fields in incomplete named record do not crash
union named {
struct forward_decl f1;
-//CHECK64: FieldDecl=f2:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int f2;
struct x {
-//CHECK64: FieldDecl=g1:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=0]
int g1;
-//CHECK64: FieldDecl=f3:[[@LINE+1]]:5 (Definition) [type=struct x] [typekind=Unexposed] [sizeof=4] [alignof=4] [offsetof=-2]
} f3;
struct forward_decl f4;
struct x2{
@@ -107,18 +97,13 @@ union named {
// test that fields in incomplete anonymous record do not crash
union f {
-//CHECK64: FieldDecl=f1:[[@LINE+1]]:23 (Definition) [type=struct forward_decl] [typekind=Unexposed] [sizeof=-2] [alignof=-2] [offsetof=-2]
struct forward_decl f1;
-//CHECK64: FieldDecl=f2:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int f2;
struct {
-//CHECK64: FieldDecl=e1:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int e1;
struct {
-//CHECK64: FieldDecl=g1:[[@LINE+1]]:28 (Definition) [type=struct forward_decl2] [typekind=Unexposed] [sizeof=-2] [alignof=-2] [offsetof=-2]
struct forward_decl2 g1;
};
-//CHECK64: FieldDecl=e3:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int e3;
};
};
@@ -128,10 +113,8 @@ union f {
struct s1 {
struct {
struct forward_decl2 s1_g1;
-//CHECK64: FieldDecl=s1_e1:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int s1_e1;
} s1_x; // named record shows in s1->field_iterator
-//CHECK64: FieldDecl=s1_e3:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int s1_e3;
};
@@ -140,17 +123,14 @@ struct s1b {
struct {
struct forward_decl2 s1b_g1;
}; // erroneous anonymous record does not show in s1b->field_iterator
-//CHECK64: FieldDecl=s1b_e2:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=0]
int s1b_e2;
};
struct s2 {
struct {
struct forward_decl2 s2_g1;
-//CHECK64: FieldDecl=s2_e1:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-5]
int s2_e1;
}; // erroneous anonymous record does not show in s1b->field_iterator
-//CHECK64: FieldDecl=s2_e3:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=0]
int s2_e3;
};
@@ -167,7 +147,6 @@ struct s3 {
};
};
};
-//CHECK64: FieldDecl=s3_e3:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=64]
int s3_e3;
};
};
@@ -181,13 +160,11 @@ struct s4a {
struct {
struct {
struct {
-//CHECK64: FieldDecl=s4_e1:[[@LINE+1]]:17 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int s4_e1;
};
};
};
};
-//CHECK64: FieldDecl=s4_e3:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-2]
int s4_e3;
};
};
@@ -200,30 +177,32 @@ struct s4b {
struct {
struct {
struct {
-//CHECK64: FieldDecl=s4b_e1:[[@LINE+1]]:17 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-5]
int s4b_e1;
};
};
};
};
-//CHECK64: FieldDecl=s4b_e3:[[@LINE+1]]:9 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-5]
int s4b_e3;
};
};
+//named struct within anonymous struct
+struct s5 {
+ struct {
+ struct x {
+ int i;
+ };
+ };
+};
+
// CHECK64: StructDecl=As:[[@LINE+1]]:8 [type=Incomplete::As] [typekind=Record]
struct As;
// undefined class. Should not crash
// CHECK64: ClassDecl=A:[[@LINE+1]]:7 [type=Incomplete::A] [typekind=Record]
class A;
-// CHECK64: ClassDecl=B:[[@LINE+1]]:7 (Definition) [type=Incomplete::B] [typekind=Record] [sizeof=16] [alignof=8]
class B {
-// CHECK64: FieldDecl=a1:[[@LINE+2]]:6 (Definition) [type=Incomplete::A *] [typekind=Pointer] [sizeof=8] [alignof=8] [offsetof=0]
-// CHECK32: FieldDecl=a1:[[@LINE+1]]:6 (Definition) [type=Incomplete::A *] [typekind=Pointer] [sizeof=4] [alignof=4] [offsetof=0]
A* a1;
-// CHECK64: FieldDecl=a2:[[@LINE+2]]:6 (Definition) [type=Incomplete::A &] [typekind=LValueReference] [sizeof=-2] [alignof=-2] [offsetof=64]
-// CHECK32: FieldDecl=a2:[[@LINE+1]]:6 (Definition) [type=Incomplete::A &] [typekind=LValueReference] [sizeof=-2] [alignof=-2] [offsetof=32]
A& a2;
};
@@ -388,15 +367,12 @@ struct BaseStruct
namespace NotConstantSize {
void f(int i) {
-// CHECK32: VarDecl=v2:[[@LINE+1]]:8 (Definition) [type=int [i]] [typekind=Unexposed] [sizeof=-4] [alignof=4]
+// CHECK32: VarDecl=v2:[[@LINE+1]]:8 (Definition) [type=int [i]] [typekind=VariableArray] [sizeof=-4] [alignof=4]
int v2[i];
{
struct CS1 {
-// FIXME: should libclang return [offsetof=0] ?
-//CHECK32: FieldDecl=f1:[[@LINE+1]]:9 (Definition) [type=int [i]] [typekind=Unexposed] [sizeof=-4] [alignof=4] [offsetof=0]
- int f1[i];
-//CHECK32: FieldDecl=f2:[[@LINE+1]]:11 (Definition) [type=float] [typekind=Float] [sizeof=4] [alignof=4] [offsetof=0]
- float f2;
+ int f1[i];
+ float f2;
};
}
}
@@ -407,9 +383,7 @@ namespace CrashTest {
// test crash scenarios on dependent types.
template<typename T>
struct Foo {
-//CHECK32: FieldDecl=t:[[@LINE+1]]:5 (Definition) [type=T] [typekind=Unexposed] [sizeof=-3] [alignof=-3] [offsetof=-1]
T t;
-//CHECK32: FieldDecl=a:[[@LINE+1]]:7 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-1]
int a;
};
diff --git a/test/Index/print-type.c b/test/Index/print-type.c
index 4805f59f3fe0..6c7095a4e5f5 100644
--- a/test/Index/print-type.c
+++ b/test/Index/print-type.c
@@ -10,6 +10,8 @@ typedef int ArrayType[5];
int __attribute__((vector_size(16))) x;
typedef int __attribute__((vector_size(16))) int4_t;
+int f2(int incompletearray[]);
+
// RUN: c-index-test -test-print-type %s | FileCheck %s
// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int *, void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int [5]] [ConstantArray] [void (*)(int)] [Pointer]] [isPOD=0]
// CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
@@ -35,10 +37,11 @@ typedef int __attribute__((vector_size(16))) int4_t;
// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1]
// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ArraySubscriptExpr= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: DeclRefExpr=arr:3:40 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: UnexposedExpr=arr:3:40 [type=int [5]] [typekind=ConstantArray] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
// CHECK: TypedefDecl=OtherType:8:16 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
// CHECK: TypedefDecl=ArrayType:9:13 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
// CHECK: VarDecl=x:10:38 [type=__attribute__((__vector_size__(4 * sizeof(int)))) int] [typekind=Vector] [isPOD=1]
// CHECK: TypedefDecl=int4_t:11:46 (Definition) [type=int4_t] [typekind=Typedef] [canonicaltype=__attribute__((__vector_size__(4 * sizeof(int)))) int] [canonicaltypekind=Vector] [isPOD=1]
+// CHECK: ParmDecl=incompletearray:13:12 (Definition) [type=int []] [typekind=IncompleteArray] [isPOD=1]
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index 49a05fbbdbdf..6324d439a6d5 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -29,6 +29,16 @@ T tbar(int);
template <typename T>
T tbar(int[5]);
+template <typename T, int size>
+T tbar(int[size]);
+
+void foo(int i, int incomplete_array[]) { int variable_array[i]; }
+
+struct Blob {
+ int i;
+};
+int Blob::*member_pointer;
+
// RUN: c-index-test -test-print-type %s | FileCheck %s
// CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
// CHECK: ClassTemplate=Foo:4:8 (Definition) [type=] [typekind=Invalid] [isPOD=0]
@@ -64,3 +74,8 @@ T tbar(int[5]);
// CHECK: TemplateTypeParameter=T:26:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
// CHECK: FunctionTemplate=tbar:30:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
// CHECK: ParmDecl=:30:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
+// CHECK: FunctionTemplate=tbar:33:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: ParmDecl=:33:11 (Definition) [type=int [size]] [typekind=DependentSizedArray] [isPOD=0]
+// CHECK: ParmDecl=incomplete_array:35:21 (Definition) [type=int []] [typekind=IncompleteArray] [isPOD=1]
+// CHECK: VarDecl=variable_array:35:47 (Definition) [type=int [i]] [typekind=VariableArray] [isPOD=1]
+// CHECK: VarDecl=member_pointer:40:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
diff --git a/test/Index/recover-bad-code-rdar_7487294.c b/test/Index/recover-bad-code-rdar_7487294.c
index e060672b6923..c2803006ac43 100644
--- a/test/Index/recover-bad-code-rdar_7487294.c
+++ b/test/Index/recover-bad-code-rdar_7487294.c
@@ -1,4 +1,4 @@
-// RUN: %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/retain-comments-from-system-headers.c b/test/Index/retain-comments-from-system-headers.c
index a9b2e2f1ef3c..67a0fd05f5de 100644
--- a/test/Index/retain-comments-from-system-headers.c
+++ b/test/Index/retain-comments-from-system-headers.c
@@ -9,7 +9,7 @@
int user_function(int a);
// RUN: c-index-test -test-load-source all %s -I %S/Inputs | FileCheck %s
-// RUN: c-index-test -test-load-source all %s -fretain-comments-from-system-headers -I %S/Inputs | FileCheck %s -check-prefix=RETAIN
+// RUN: c-index-test -test-load-source all %s -fretain-comments-from-system-headers -I %S/Inputs | FileCheck %s -check-prefix=CHECK-RETAIN
// CHECK: retain-comments-from-system-headers.h:7:5: FunctionDecl=system_function:7:5 Extent=[7:1 - 7:27]
// CHECK: retain-comments-from-system-headers.c:9:5: FunctionDecl=user_function:9:5 RawComment=[/**\n * user_function\n * \param a Aaa.\n */] RawCommentRange=[5:1 - 8:4] BriefComment=[user_function]
diff --git a/test/Index/subclass-comment.mm b/test/Index/subclass-comment.mm
index 9682a9f71d6c..5fcb89fe632b 100644
--- a/test/Index/subclass-comment.mm
+++ b/test/Index/subclass-comment.mm
@@ -13,7 +13,7 @@
// CHECK-NEXT: (CXComment_Text Text=[ NSObject is root of all.])))]
//! An umbrella class for super classes.
-@interface SuperClass
+@interface SuperClass
@end
// CHECK: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
@@ -41,67 +41,3 @@
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ An umbrella class for super classes.])))]
-//! Something valuable to the organization.
-class Asset {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Something valuable to the organization.])))]
-
-//! An individual human or human individual.
-class Person : public Asset {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ An individual human or human individual.])))]
-
-class Student : public Person {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ An individual human or human individual.])))]
-
-//! Every thing is a part
-class Parts {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Every thing is a part])))]
-
-class Window : public virtual Parts {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Every thing is a part])))]
-
-class Door : public virtual Parts {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Every thing is a part])))]
-
-class House : public Window, Door {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Every thing is a part])))]
-
-//! Any Material
-class Material : virtual Parts {
-};
-
-class Building : Window, public Material {
-};
-// CHECK: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Any Material])))]
-
-
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index dccfb7587279..cc2e0fd4b4c2 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -118,7 +118,7 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
// CHECK: usrs.m c:usrs.m@402objc(cs)Foo(im)godzilla@a Extent=[36:3 - 36:19]
-// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:3 - 37:15]
+// CHECK: usrs.m c:@z Extent=[37:3 - 37:15]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
// CHECK: usrs.m c:usrs.m@470objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
diff --git a/test/Layout/ms-x86-aligned-tail-padding.cpp b/test/Layout/ms-x86-aligned-tail-padding.cpp
new file mode 100644
index 000000000000..b9020f386c03
--- /dev/null
+++ b/test/Layout/ms-x86-aligned-tail-padding.cpp
@@ -0,0 +1,502 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 {
+ int a;
+ B0() : a(0xf00000B0) {}
+};
+struct __declspec(align(16)) B1 {
+ int a;
+ B1() : a(0xf00000B1) {}
+};
+struct B2 {
+ __declspec(align(16)) int a;
+ B2() : a(0xf00000B2) {}
+};
+struct __declspec(align(16)) B3 {
+ long long a1;
+ int a;
+ B3() : a(0xf00000B3), a1(0xf00000B3f00000B3ll) {}
+};
+struct V {
+ char a;
+ V() : a(0X11) {}
+};
+struct __declspec(align(32)) A16 {};
+struct V1 : A16 { virtual void f() {} };
+struct V2 {
+ long long a;
+ int a1;
+ V2() : a(0xf0000011f0000011ll), a1(0xf0000011) {}
+};
+struct V3 {
+ int a;
+ V3() : a(0xf0000022) {}
+};
+struct __declspec(align(16)) A16X {
+};
+struct __declspec(align(16)) B0X {
+ int a, a1;
+ B0X() : a(0xf00000B0), a1(0xf00000B0) {}
+};
+struct B1X {
+ int a;
+ B1X() : a(0xf00000B1) {}
+};
+struct B2X {
+ int a;
+ B2X() : a(0xf00000B2) {}
+};
+struct __declspec(align(16)) B3X {
+ int a;
+ B3X() : a(0xf00000B3) {}
+ virtual void g() {}
+};
+struct B4X : A16X {
+ int a, a1;
+ B4X() : a(0xf00000B4), a1(0xf00000B4) {}
+};
+struct B5X : virtual A16X {
+ int a, a1;
+ B5X() : a(0xf00000B5), a1(0xf00000B5) {}
+};
+struct B6X {
+ int a;
+ B6X() : a(0xf00000B6) {}
+};
+
+struct A : B1, B0, B2, virtual V {
+ int a;
+ A() : a(0xf000000A) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | struct B1 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | struct B0 (base)
+// CHECK: 4 | int a
+// CHECK: 16 | struct B2 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | (A vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct V (virtual base)
+// CHECK: 64 | char a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | struct B1 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 4 | struct B0 (base)
+// CHECK-X64: 4 | int a
+// CHECK-X64: 16 | struct B2 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (A vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct V (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct B : B2, B0, B1, virtual V {
+ int a;
+ B() : a(0xf000000B) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct B2 (base)
+// CHECK: 0 | int a
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | struct B1 (base)
+// CHECK: 32 | int a
+// CHECK: 36 | (B vbtable pointer)
+// CHECK: 52 | int a
+// CHECK: 64 | struct V (virtual base)
+// CHECK: 64 | char a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | struct B2 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 16 | struct B0 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | struct B1 (base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | (B vbtable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 64 | struct V (virtual base)
+// CHECK-X64: 64 | char a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+struct C : B1, B0, virtual V {
+ int a;
+ long long a1;
+ C() : a(0xf000000C), a1(0xf000000Cf000000Cll) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | struct B1 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | struct B0 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (C vbtable pointer)
+// CHECK: 24 | int a
+// CHECK: 32 | long long a1
+// CHECK: 48 | struct V (virtual base)
+// CHECK: 48 | char a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | struct B1 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 4 | struct B0 (base)
+// CHECK-X64: 4 | int a
+// CHECK-X64: 8 | (C vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | long long a1
+// CHECK-X64: 32 | struct V (virtual base)
+// CHECK-X64: 32 | char a
+// CHECK-X64: | [sizeof=48, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct D : B2, B0, virtual V {
+ int a;
+ D() : a(0xf000000D) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct B2 (base)
+// CHECK: 0 | int a
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (D vbtable pointer)
+// CHECK: 36 | int a
+// CHECK: 48 | struct V (virtual base)
+// CHECK: 48 | char a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | struct B2 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 16 | struct B0 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | (D vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct V (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct E : B3, B0, virtual V {
+ int a;
+ E() : a(0xf000000E) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | struct B3 (base)
+// CHECK: 0 | long long a1
+// CHECK: 8 | int a
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (E vbtable pointer)
+// CHECK: 36 | int a
+// CHECK: 48 | struct V (virtual base)
+// CHECK: 48 | char a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | struct B3 (base)
+// CHECK-X64: 0 | long long a1
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | (E vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct V (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct F : B0, virtual V1 {
+ __declspec(align(16)) int a;
+ F() : a(0xf000000F) {}
+ virtual void f() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | struct B0 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (F vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 92 | (vtordisp for vbase V1)
+// CHECK: 96 | struct V1 (virtual base)
+// CHECK: 96 | (V1 vftable pointer)
+// CHECK: 128 | struct A16 (base) (empty)
+// CHECK: | [sizeof=128, align=32
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | struct B0 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (F vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 60 | (vtordisp for vbase V1)
+// CHECK-X64: 64 | struct V1 (virtual base)
+// CHECK-X64: 64 | (V1 vftable pointer)
+// CHECK-X64: 96 | struct A16 (base) (empty)
+// CHECK-X64: | [sizeof=96, align=32
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct G : virtual V2, virtual V3 {
+ int a;
+ G() : a(0xf0000001) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 0 | (G vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct V2 (virtual base)
+// CHECK: 8 | long long a
+// CHECK: 16 | int a1
+// CHECK: 24 | struct V3 (virtual base)
+// CHECK: 24 | int a
+// CHECK: | [sizeof=28, align=8
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct G
+// CHECK-X64: 0 | (G vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct V2 (virtual base)
+// CHECK-X64: 16 | long long a
+// CHECK-X64: 24 | int a1
+// CHECK-X64: 32 | struct V3 (virtual base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct H {
+ __declspec(align(16)) int a;
+ int b;
+ H() : a(0xf0000010), b(0xf0000010) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct H
+// CHECK: 0 | int a
+// CHECK: 4 | int b
+// CHECK: | [sizeof=16, align=16
+// CHECK: | nvsize=16, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct H
+// CHECK-X64: 0 | int a
+// CHECK-X64: 4 | int b
+// CHECK-X64: | [sizeof=16, align=16
+// CHECK-X64: | nvsize=16, nvalign=16]
+
+struct I {
+ B2 a;
+ int b;
+ I() : b(0xf0000010) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct I
+// CHECK: 0 | struct B2 a
+// CHECK: 0 | int a
+// CHECK: 16 | int b
+// CHECK: | [sizeof=32, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct I
+// CHECK-X64: 0 | struct B2 a
+// CHECK-X64: 0 | int a
+// CHECK-X64: 16 | int b
+// CHECK-X64: | [sizeof=32, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct AX : B0X, virtual B2X, virtual B6X, virtual B3X {
+ int a;
+ AX() : a(0xf000000A) {}
+ virtual void f() {}
+ virtual void g() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AX
+// CHECK: 0 | (AX vftable pointer)
+// CHECK: 16 | struct B0X (base)
+// CHECK: 16 | int a
+// CHECK: 20 | int a1
+// CHECK: 24 | (AX vbtable pointer)
+// CHECK: 40 | int a
+// CHECK: 48 | struct B2X (virtual base)
+// CHECK: 48 | int a
+// CHECK: 52 | struct B6X (virtual base)
+// CHECK: 52 | int a
+// CHECK: 76 | (vtordisp for vbase B3X)
+// CHECK: 80 | struct B3X (virtual base)
+// CHECK: 80 | (B3X vftable pointer)
+// CHECK: 84 | int a
+// CHECK: | [sizeof=96, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AX
+// CHECK-X64: 0 | (AX vftable pointer)
+// CHECK-X64: 16 | struct B0X (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | int a1
+// CHECK-X64: 24 | (AX vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B2X (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 52 | struct B6X (virtual base)
+// CHECK-X64: 52 | int a
+// CHECK-X64: 76 | (vtordisp for vbase B3X)
+// CHECK-X64: 80 | struct B3X (virtual base)
+// CHECK-X64: 80 | (B3X vftable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct BX : B4X, virtual B2X, virtual B6X, virtual B3X {
+ int a;
+ BX() : a(0xf000000B) {}
+ virtual void f() {}
+ virtual void g() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct BX
+// CHECK: 0 | (BX vftable pointer)
+// CHECK: 16 | struct B4X (base)
+// CHECK: 16 | struct A16X (base) (empty)
+// CHECK: 16 | int a
+// CHECK: 20 | int a1
+// CHECK: 32 | (BX vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct B2X (virtual base)
+// CHECK: 64 | int a
+// CHECK: 68 | struct B6X (virtual base)
+// CHECK: 68 | int a
+// CHECK: 92 | (vtordisp for vbase B3X)
+// CHECK: 96 | struct B3X (virtual base)
+// CHECK: 96 | (B3X vftable pointer)
+// CHECK: 100 | int a
+// CHECK: | [sizeof=112, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct BX
+// CHECK-X64: 0 | (BX vftable pointer)
+// CHECK-X64: 16 | struct B4X (base)
+// CHECK-X64: 16 | struct A16X (base) (empty)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | int a1
+// CHECK-X64: 32 | (BX vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct B2X (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 52 | struct B6X (virtual base)
+// CHECK-X64: 52 | int a
+// CHECK-X64: 76 | (vtordisp for vbase B3X)
+// CHECK-X64: 80 | struct B3X (virtual base)
+// CHECK-X64: 80 | (B3X vftable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct CX : B5X, virtual B2X, virtual B6X, virtual B3X {
+ int a;
+ CX() : a(0xf000000C) {}
+ virtual void f() {}
+ virtual void g() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct CX
+// CHECK: 0 | (CX vftable pointer)
+// CHECK: 16 | struct B5X (base)
+// CHECK: 16 | (B5X vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 24 | int a1
+// CHECK: 28 | int a
+// CHECK: 32 | struct A16X (virtual base) (empty)
+// CHECK: 32 | struct B2X (virtual base)
+// CHECK: 32 | int a
+// CHECK: 36 | struct B6X (virtual base)
+// CHECK: 36 | int a
+// CHECK: 60 | (vtordisp for vbase B3X)
+// CHECK: 64 | struct B3X (virtual base)
+// CHECK: 64 | (B3X vftable pointer)
+// CHECK: 68 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct CX
+// CHECK-X64: 0 | (CX vftable pointer)
+// CHECK-X64: 16 | struct B5X (base)
+// CHECK-X64: 16 | (B5X vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 28 | int a1
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct A16X (virtual base) (empty)
+// CHECK-X64: 48 | struct B2X (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 52 | struct B6X (virtual base)
+// CHECK-X64: 52 | int a
+// CHECK-X64: 76 | (vtordisp for vbase B3X)
+// CHECK-X64: 80 | struct B3X (virtual base)
+// CHECK-X64: 80 | (B3X vftable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct __declspec(align(16)) DX {
+ int a;
+ DX() : a(0xf000000D) {}
+ virtual void f() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct DX
+// CHECK: 0 | (DX vftable pointer)
+// CHECK: 4 | int a
+// CHECK: | [sizeof=16, align=16
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct DX
+// CHECK-X64: 0 | (DX vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: | [sizeof=16, align=16
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)+
+sizeof(H)+
+sizeof(I)+
+sizeof(AX)+
+sizeof(BX)+
+sizeof(CX)+
+sizeof(DX)];
diff --git a/test/Layout/ms-x86-basic-layout.cpp b/test/Layout/ms-x86-basic-layout.cpp
new file mode 100644
index 000000000000..86b3553b0ba0
--- /dev/null
+++ b/test/Layout/ms-x86-basic-layout.cpp
@@ -0,0 +1,775 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct A4 {
+ int a;
+ A4() : a(0xf00000a4) {}
+};
+
+struct B4 {
+ int a;
+ B4() : a(0xf00000b4) {}
+};
+
+struct C4 {
+ int a;
+ C4() : a(0xf00000c4) {}
+ virtual void f() {printf("C4");}
+};
+
+struct A16 {
+ __declspec(align(16)) int a;
+ A16() : a(0xf0000a16) {}
+};
+
+struct C16 {
+ __declspec(align(16)) int a;
+ C16() : a(0xf0000c16) {}
+ virtual void f() {printf("C16");}
+};
+
+struct TestF0 : A4, virtual B4 {
+ int a;
+ TestF0() : a(0xf00000F0) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF0
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF0 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct B4 (virtual base)
+// CHECK: 12 | int a
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF0
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF0 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B4 (virtual base)
+// CHECK-X64: 24 | int a
+// CHECK-X64: | [sizeof=32, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct TestF1 : A4, virtual A16 {
+ int a;
+ TestF1() : a(0xf00000f1) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF1
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF1 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 16 | struct A16 (virtual base)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=32, align=16
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF1
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF1 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | struct A16 (virtual base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=48, align=16
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct TestF2 : A4, virtual C4 {
+ int a;
+ TestF2() : a(0xf00000f2) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF2
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF2 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct C4 (virtual base)
+// CHECK: 12 | (C4 vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF2
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF2 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct C4 (virtual base)
+// CHECK-X64: 24 | (C4 vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct TestF3 : A4, virtual C16 {
+ int a;
+ TestF3() : a(0xf00000f3) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF3
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF3 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 16 | struct C16 (virtual base)
+// CHECK: 16 | (C16 vftable pointer)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF3
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF3 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | struct C16 (virtual base)
+// CHECK-X64: 32 | (C16 vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct TestF4 : TestF3, A4 {
+ int a;
+ TestF4() : a(0xf00000f4) {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF4
+// CHECK: 0 | struct TestF3 (base)
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF3 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct A4 (base)
+// CHECK: 12 | int a
+// CHECK: 16 | int a
+// CHECK: 32 | struct C16 (virtual base)
+// CHECK: 32 | (C16 vftable pointer)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF4
+// CHECK-X64: 0 | struct TestF3 (base)
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF3 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct A4 (base)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 28 | int a
+// CHECK-X64: 32 | struct C16 (virtual base)
+// CHECK-X64: 32 | (C16 vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct TestF5 : TestF3, A4 {
+ int a;
+ TestF5() : a(0xf00000f5) {}
+ virtual void g() {printf("F5");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF5
+// CHECK: 0 | (TestF5 vftable pointer)
+// CHECK: 16 | struct TestF3 (base)
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (TestF3 vbtable pointer)
+// CHECK: 24 | int a
+// CHECK: 28 | struct A4 (base)
+// CHECK: 28 | int a
+// CHECK: 32 | int a
+// CHECK: 48 | struct C16 (virtual base)
+// CHECK: 48 | (C16 vftable pointer)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF5
+// CHECK-X64: 0 | (TestF5 vftable pointer)
+// CHECK-X64: 16 | struct TestF3 (base)
+// CHECK-X64: 16 | struct A4 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | (TestF3 vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | struct A4 (base)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 44 | int a
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct TestF6 : TestF3, A4 {
+ int a;
+ TestF6() : a(0xf00000f6) {}
+ virtual void f() {printf("F6");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF6
+// CHECK: 0 | struct TestF3 (base)
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF3 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct A4 (base)
+// CHECK: 12 | int a
+// CHECK: 16 | int a
+// CHECK: 44 | (vtordisp for vbase C16)
+// CHECK: 48 | struct C16 (virtual base)
+// CHECK: 48 | (C16 vftable pointer)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF6
+// CHECK-X64: 0 | struct TestF3 (base)
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF3 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct A4 (base)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 28 | int a
+// CHECK-X64: 44 | (vtordisp for vbase C16)
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct TestF7 : A4, virtual C16 {
+ int a;
+ TestF7() : a(0xf00000f7) {}
+ virtual void f() {printf("F7");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF7
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF7 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 28 | (vtordisp for vbase C16)
+// CHECK: 32 | struct C16 (virtual base)
+// CHECK: 32 | (C16 vftable pointer)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF7
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF7 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 44 | (vtordisp for vbase C16)
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct TestF8 : TestF7, A4 {
+ int a;
+ TestF8() : a(0xf00000f8) {}
+ virtual void f() {printf("F8");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF8
+// CHECK: 0 | struct TestF7 (base)
+// CHECK: 0 | struct A4 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (TestF7 vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct A4 (base)
+// CHECK: 12 | int a
+// CHECK: 16 | int a
+// CHECK: 44 | (vtordisp for vbase C16)
+// CHECK: 48 | struct C16 (virtual base)
+// CHECK: 48 | (C16 vftable pointer)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF8
+// CHECK-X64: 0 | struct TestF7 (base)
+// CHECK-X64: 0 | struct A4 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (TestF7 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct A4 (base)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 28 | int a
+// CHECK-X64: 44 | (vtordisp for vbase C16)
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct TestF9 : A4, virtual C16 {
+ int a;
+ TestF9() : a(0xf00000f9) {}
+ virtual void g() {printf("F9");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestF9
+// CHECK: 0 | (TestF9 vftable pointer)
+// CHECK: 4 | struct A4 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (TestF9 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct C16 (virtual base)
+// CHECK: 16 | (C16 vftable pointer)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestF9
+// CHECK-X64: 0 | (TestF9 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (TestF9 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | struct C16 (virtual base)
+// CHECK-X64: 32 | (C16 vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=32, nvalign=8]
+
+struct TestFA : TestF9, A4 {
+ int a;
+ TestFA() : a(0xf00000fa) {}
+ virtual void g() {printf("FA");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestFA
+// CHECK: 0 | struct TestF9 (primary base)
+// CHECK: 0 | (TestF9 vftable pointer)
+// CHECK: 4 | struct A4 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (TestF9 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | int a
+// CHECK: 32 | struct C16 (virtual base)
+// CHECK: 32 | (C16 vftable pointer)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestFA
+// CHECK-X64: 0 | struct TestF9 (primary base)
+// CHECK-X64: 0 | (TestF9 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (TestF9 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | struct A4 (base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 36 | int a
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct TestFB : A16, virtual C16 {
+ int a;
+ TestFB() : a(0xf00000fb) {}
+ virtual void g() {printf("Fb");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestFB
+// CHECK: 0 | (TestFB vftable pointer)
+// CHECK: 16 | struct A16 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | (TestFB vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct C16 (virtual base)
+// CHECK: 64 | (C16 vftable pointer)
+// CHECK: 80 | int a
+// CHECK: | [sizeof=96, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestFB
+// CHECK-X64: 0 | (TestFB vftable pointer)
+// CHECK-X64: 16 | struct A16 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (TestFB vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct C16 (virtual base)
+// CHECK-X64: 48 | (C16 vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct TestFC : TestFB, A4 {
+ int a;
+ TestFC() : a(0xf00000fc) {}
+ virtual void g() {printf("FC");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct TestFC
+// CHECK: 0 | struct TestFB (primary base)
+// CHECK: 0 | (TestFB vftable pointer)
+// CHECK: 16 | struct A16 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | (TestFB vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct A4 (base)
+// CHECK: 64 | int a
+// CHECK: 68 | int a
+// CHECK: 80 | struct C16 (virtual base)
+// CHECK: 80 | (C16 vftable pointer)
+// CHECK: 96 | int a
+// CHECK: | [sizeof=112, align=16
+// CHECK: | nvsize=80, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct TestFC
+// CHECK-X64: 0 | struct TestFB (primary base)
+// CHECK-X64: 0 | (TestFB vftable pointer)
+// CHECK-X64: 16 | struct A16 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (TestFB vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct A4 (base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 52 | int a
+// CHECK-X64: 64 | struct C16 (virtual base)
+// CHECK-X64: 64 | (C16 vftable pointer)
+// CHECK-X64: 80 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+
+struct A16f {
+ __declspec(align(16)) int a;
+ A16f() : a(0xf0000a16) {}
+ virtual void f() {printf("A16f");}
+};
+
+struct Y { char y; Y() : y(0xaa) {} };
+struct X : virtual A16f {};
+
+struct B : A4, Y, X {
+ int a;
+ B() : a(0xf000000b) {}
+};
+
+struct F0 : A4, B {
+ int a;
+ F0() : a(0xf00000f0) {}
+ virtual void g() {printf("F0");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F0
+// CHECK: 0 | (F0 vftable pointer)
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | struct B (base)
+// CHECK: 32 | struct A4 (base)
+// CHECK: 32 | int a
+// CHECK: 36 | struct Y (base)
+// CHECK: 36 | char y
+// CHECK: 48 | struct X (base)
+// CHECK: 48 | (X vbtable pointer)
+// CHECK: 52 | int a
+// CHECK: 64 | int a
+// CHECK: 80 | struct A16f (virtual base)
+// CHECK: 80 | (A16f vftable pointer)
+// CHECK: 96 | int a
+// CHECK: | [sizeof=112, align=16
+// CHECK: | nvsize=80, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F0
+// CHECK-X64: 0 | (F0 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B (base)
+// CHECK-X64: 16 | struct A4 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | struct Y (base)
+// CHECK-X64: 20 | char y
+// CHECK-X64: 32 | struct X (base)
+// CHECK-X64: 32 | (X vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | int a
+// CHECK-X64: 64 | struct A16f (virtual base)
+// CHECK-X64: 64 | (A16f vftable pointer)
+// CHECK-X64: 80 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+struct F1 : B, A4 {
+ int a;
+ F1() : a(0xf00000f1) {}
+ virtual void g() {printf("F1");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F1
+// CHECK: 0 | (F1 vftable pointer)
+// CHECK: 16 | struct B (base)
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | struct Y (base)
+// CHECK: 20 | char y
+// CHECK: 32 | struct X (base)
+// CHECK: 32 | (X vbtable pointer)
+// CHECK: 36 | int a
+// CHECK: 48 | struct A4 (base)
+// CHECK: 48 | int a
+// CHECK: 52 | int a
+// CHECK: 64 | struct A16f (virtual base)
+// CHECK: 64 | (A16f vftable pointer)
+// CHECK: 80 | int a
+// CHECK: | [sizeof=96, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F1
+// CHECK-X64: 0 | (F1 vftable pointer)
+// CHECK-X64: 16 | struct B (base)
+// CHECK-X64: 16 | struct A4 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | struct Y (base)
+// CHECK-X64: 20 | char y
+// CHECK-X64: 32 | struct X (base)
+// CHECK-X64: 32 | (X vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct A4 (base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 52 | int a
+// CHECK-X64: 64 | struct A16f (virtual base)
+// CHECK-X64: 64 | (A16f vftable pointer)
+// CHECK-X64: 80 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+struct F2 : A4, virtual A16f {
+ int a;
+ F2() : a(0xf00000f2) {}
+ virtual void g() {printf("F2");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F2
+// CHECK: 0 | (F2 vftable pointer)
+// CHECK: 4 | struct A4 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (F2 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct A16f (virtual base)
+// CHECK: 16 | (A16f vftable pointer)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F2
+// CHECK-X64: 0 | (F2 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (F2 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | struct A16f (virtual base)
+// CHECK-X64: 32 | (A16f vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=32, nvalign=8]
+
+struct F3 : A4, virtual A16f {
+ __declspec(align(16)) int a;
+ F3() : a(0xf00000f3) {}
+ virtual void g() {printf("F3");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F3
+// CHECK: 0 | (F3 vftable pointer)
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (F3 vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct A16f (virtual base)
+// CHECK: 64 | (A16f vftable pointer)
+// CHECK: 80 | int a
+// CHECK: | [sizeof=96, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F3
+// CHECK-X64: 0 | (F3 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (F3 vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct A16f (virtual base)
+// CHECK-X64: 48 | (A16f vftable pointer)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct F4 : A4, B {
+ __declspec(align(16)) int a;
+ F4() : a(0xf00000f4) {}
+ virtual void g() {printf("F4");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F4
+// CHECK: 0 | (F4 vftable pointer)
+// CHECK: 16 | struct A4 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | struct B (base)
+// CHECK: 32 | struct A4 (base)
+// CHECK: 32 | int a
+// CHECK: 36 | struct Y (base)
+// CHECK: 36 | char y
+// CHECK: 48 | struct X (base)
+// CHECK: 48 | (X vbtable pointer)
+// CHECK: 52 | int a
+// CHECK: 64 | int a
+// CHECK: 80 | struct A16f (virtual base)
+// CHECK: 80 | (A16f vftable pointer)
+// CHECK: 96 | int a
+// CHECK: | [sizeof=112, align=16
+// CHECK: | nvsize=80, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F4
+// CHECK-X64: 0 | (F4 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B (base)
+// CHECK-X64: 16 | struct A4 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | struct Y (base)
+// CHECK-X64: 20 | char y
+// CHECK-X64: 32 | struct X (base)
+// CHECK-X64: 32 | (X vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | int a
+// CHECK-X64: 64 | struct A16f (virtual base)
+// CHECK-X64: 64 | (A16f vftable pointer)
+// CHECK-X64: 80 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+struct F5 : A16f, virtual A4 {
+ int a;
+ F5() : a(0xf00000f5) {}
+ virtual void g() {printf("F5");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F5
+// CHECK: 0 | struct A16f (primary base)
+// CHECK: 0 | (A16f vftable pointer)
+// CHECK: 16 | int a
+// CHECK: 32 | (F5 vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct A4 (virtual base)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F5
+// CHECK-X64: 0 | struct A16f (primary base)
+// CHECK-X64: 0 | (A16f vftable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (F5 vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct A4 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct F6 : virtual A16f, A4, virtual B {
+ int a;
+ F6() : a(0xf00000f6) {}
+ virtual void g() {printf("F6");}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F6
+// CHECK: 0 | (F6 vftable pointer)
+// CHECK: 4 | struct A4 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (F6 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct A16f (virtual base)
+// CHECK: 16 | (A16f vftable pointer)
+// CHECK: 32 | int a
+// CHECK: 48 | struct B (virtual base)
+// CHECK: 48 | struct A4 (base)
+// CHECK: 48 | int a
+// CHECK: 52 | struct Y (base)
+// CHECK: 52 | char y
+// CHECK: 64 | struct X (base)
+// CHECK: 64 | (X vbtable pointer)
+// CHECK: 68 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F6
+// CHECK-X64: 0 | (F6 vftable pointer)
+// CHECK-X64: 8 | struct A4 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (F6 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | struct A16f (virtual base)
+// CHECK-X64: 32 | (A16f vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 64 | struct B (virtual base)
+// CHECK-X64: 64 | struct A4 (base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: 68 | struct Y (base)
+// CHECK-X64: 68 | char y
+// CHECK-X64: 80 | struct X (base)
+// CHECK-X64: 80 | (X vbtable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=32, nvalign=8]
+
+int a[
+sizeof(TestF0)+
+sizeof(TestF1)+
+sizeof(TestF2)+
+sizeof(TestF3)+
+sizeof(TestF4)+
+sizeof(TestF5)+
+sizeof(TestF6)+
+sizeof(TestF7)+
+sizeof(TestF8)+
+sizeof(TestF9)+
+sizeof(TestFA)+
+sizeof(TestFB)+
+sizeof(TestFC)+
+sizeof(F0)+
+sizeof(F1)+
+sizeof(F2)+
+sizeof(F3)+
+sizeof(F4)+
+sizeof(F5)+
+sizeof(F6)];
diff --git a/test/Layout/ms-x86-bitfields-vbases.cpp b/test/Layout/ms-x86-bitfields-vbases.cpp
new file mode 100644
index 000000000000..e11ef67a6347
--- /dev/null
+++ b/test/Layout/ms-x86-bitfields-vbases.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+struct B0 { };
+
+struct A : virtual B0 { char a : 1; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 9 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=9, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 17 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct B : virtual B0 { short a : 1; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | (B vbtable pointer)
+// CHECK: 4 | short a
+// CHECK: 10 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=10, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | (B vbtable pointer)
+// CHECK-X64: 8 | short a
+// CHECK-X64: 18 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct C : virtual B0 { char a : 1; char : 0; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 5 | char
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 9 | char
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct D : virtual B0 { char a : 1; char b; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | (D vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 5 | char b
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | (D vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 9 | char b
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)];
diff --git a/test/Layout/ms-x86-empty-base-after-base-with-vbptr.cpp b/test/Layout/ms-x86-empty-base-after-base-with-vbptr.cpp
new file mode 100644
index 000000000000..293a61b96e64
--- /dev/null
+++ b/test/Layout/ms-x86-empty-base-after-base-with-vbptr.cpp
@@ -0,0 +1,216 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+
+struct U { char a; };
+struct V { };
+struct W { };
+struct X : virtual V { char a; };
+struct Y : virtual V { char a; };
+struct Z : Y { };
+
+struct A : X, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 9 | struct W (base) (empty)
+// CHECK: 9 | char a
+// CHECK: 12 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 17 | struct W (base) (empty)
+// CHECK-X64: 17 | char a
+// CHECK-X64: 24 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct B : X, U, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 8 | struct U (base)
+// CHECK: 8 | char a
+// CHECK: 9 | struct W (base) (empty)
+// CHECK: 9 | char a
+// CHECK: 12 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 16 | struct U (base)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 17 | struct W (base) (empty)
+// CHECK-X64: 17 | char a
+// CHECK-X64: 24 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct C : X, V, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 9 | struct V (base) (empty)
+// CHECK: 10 | struct W (base) (empty)
+// CHECK: 10 | char a
+// CHECK: 12 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 17 | struct V (base) (empty)
+// CHECK-X64: 18 | struct W (base) (empty)
+// CHECK-X64: 18 | char a
+// CHECK-X64: 24 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct D : X, U, V, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 8 | struct U (base)
+// CHECK: 8 | char a
+// CHECK: 9 | struct V (base) (empty)
+// CHECK: 10 | struct W (base) (empty)
+// CHECK: 10 | char a
+// CHECK: 12 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 16 | struct U (base)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 17 | struct V (base) (empty)
+// CHECK-X64: 18 | struct W (base) (empty)
+// CHECK-X64: 18 | char a
+// CHECK-X64: 24 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct E : X, U, Y, V, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 8 | struct U (base)
+// CHECK: 8 | char a
+// CHECK: 12 | struct Y (base)
+// CHECK: 12 | (Y vbtable pointer)
+// CHECK: 16 | char a
+// CHECK: 21 | struct V (base) (empty)
+// CHECK: 22 | struct W (base) (empty)
+// CHECK: 22 | char a
+// CHECK: 24 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=24, align=4
+// CHECK: | nvsize=24, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 16 | struct U (base)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct Y (base)
+// CHECK-X64: 24 | (Y vbtable pointer)
+// CHECK-X64: 32 | char a
+// CHECK-X64: 41 | struct V (base) (empty)
+// CHECK-X64: 42 | struct W (base) (empty)
+// CHECK-X64: 42 | char a
+// CHECK-X64: 48 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=8
+// CHECK-X64: | nvsize=48, nvalign=8]
+
+struct F : Z, W { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | struct Z (base)
+// CHECK: 0 | struct Y (base)
+// CHECK: 0 | (Y vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 9 | struct W (base) (empty)
+// CHECK: 9 | char a
+// CHECK: 12 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | struct Z (base)
+// CHECK-X64: 0 | struct Y (base)
+// CHECK-X64: 0 | (Y vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 17 | struct W (base) (empty)
+// CHECK-X64: 17 | char a
+// CHECK-X64: 24 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct G : X, W, Y, V { char a; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 0 | struct X (base)
+// CHECK: 0 | (X vbtable pointer)
+// CHECK: 4 | char a
+// CHECK: 9 | struct W (base) (empty)
+// CHECK: 12 | struct Y (base)
+// CHECK: 12 | (Y vbtable pointer)
+// CHECK: 16 | char a
+// CHECK: 21 | struct V (base) (empty)
+// CHECK: 21 | char a
+// CHECK: 24 | struct V (virtual base) (empty)
+// CHECK: | [sizeof=24, align=4
+// CHECK: | nvsize=24, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct G
+// CHECK-X64: 0 | struct X (base)
+// CHECK-X64: 0 | (X vbtable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 17 | struct W (base) (empty)
+// CHECK-X64: 24 | struct Y (base)
+// CHECK-X64: 24 | (Y vbtable pointer)
+// CHECK-X64: 32 | char a
+// CHECK-X64: 41 | struct V (base) (empty)
+// CHECK-X64: 41 | char a
+// CHECK-X64: 48 | struct V (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=8
+// CHECK-X64: | nvsize=48, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)];
diff --git a/test/Layout/ms-x86-empty-nonvirtual-bases.cpp b/test/Layout/ms-x86-empty-nonvirtual-bases.cpp
new file mode 100644
index 000000000000..01d10c9994f6
--- /dev/null
+++ b/test/Layout/ms-x86-empty-nonvirtual-bases.cpp
@@ -0,0 +1,174 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+
+extern "C" int printf(const char *fmt, ...);
+
+struct __declspec(align(8)) B0 { B0() {printf("B0 : %p\n", this);} };
+struct __declspec(align(8)) B1 { B1() {printf("B1 : %p\n", this);} };
+struct __declspec(align(8)) B2 { B2() {printf("B2 : %p\n", this);} };
+struct __declspec(align(8)) B3 { B3() {printf("B3 : %p\n", this);} };
+struct __declspec(align(8)) B4 { B4() {printf("B4 : %p\n", this);} };
+
+struct C0 { int a; C0() : a(0xf00000C0) {printf("C0 : %p\n", this);} };
+struct C1 { int a; C1() : a(0xf00000C1) {printf("C1 : %p\n", this);} };
+struct C2 { int a; C2() : a(0xf00000C2) {printf("C2 : %p\n", this);} };
+struct C3 { int a; C3() : a(0xf00000C3) {printf("C3 : %p\n", this);} };
+struct C4 { int a; C4() : a(0xf00000C4) {printf("C4 : %p\n", this);} };
+
+struct A : B0 {
+ int a;
+ A() : a(0xf000000A) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 0 | int a
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=8, nvalign=8]
+
+struct B : B0 {
+ B0 b0;
+ int a;
+ B() : a(0xf000000B) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 0 | struct B0 b0 (empty)
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=0, nvalign=1]
+// CHECK: 8 | int a
+// CHECK: | [sizeof=16, align=8
+// CHECK: | nvsize=16, nvalign=8]
+
+struct C : B0, B1, B2, B3, B4 {
+ int a;
+ C() : a(0xf000000C) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 8 | struct B1 (base) (empty)
+// CHECK: 16 | struct B2 (base) (empty)
+// CHECK: 24 | struct B3 (base) (empty)
+// CHECK: 32 | struct B4 (base) (empty)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=40, align=8
+// CHECK: | nvsize=40, nvalign=8]
+
+struct D {
+ B0 b0;
+ C0 c0;
+ C1 c1;
+ C2 c2;
+ B1 b1;
+ int a;
+ D() : a(0xf000000D) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct B0 b0 (empty)
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=0, nvalign=1]
+// CHECK: 8 | struct C0 c0
+// CHECK: 8 | int a
+// CHECK: | [sizeof=4, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK: 12 | struct C1 c1
+// CHECK: 12 | int a
+// CHECK: | [sizeof=4, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK: 16 | struct C2 c2
+// CHECK: 16 | int a
+// CHECK: | [sizeof=4, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK: 24 | struct B1 b1 (empty)
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=0, nvalign=1]
+// CHECK: 32 | int a
+// CHECK: | [sizeof=40, align=8
+// CHECK: | nvsize=40, nvalign=8]
+
+struct E : B0, C0, C1, C2, B1 {
+ int a;
+ E() : a(0xf000000E) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 0 | struct C0 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | struct C1 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | struct C2 (base)
+// CHECK: 8 | int a
+// CHECK: 16 | struct B1 (base) (empty)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=24, align=8
+// CHECK: | nvsize=24, nvalign=8]
+
+struct F : C0, B0, B1, C1 {
+ int a;
+ F() : a(0xf000000F) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | struct C0 (base)
+// CHECK: 0 | int a
+// CHECK: 8 | struct B0 (base) (empty)
+// CHECK: 16 | struct B1 (base) (empty)
+// CHECK: 16 | struct C1 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | int a
+// CHECK: | [sizeof=24, align=8
+// CHECK: | nvsize=24, nvalign=8]
+
+struct G : B0, B1, B2, B3, B4 {
+ __declspec(align(32)) int a;
+ G() : a(0xf0000011) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 8 | struct B1 (base) (empty)
+// CHECK: 16 | struct B2 (base) (empty)
+// CHECK: 24 | struct B3 (base) (empty)
+// CHECK: 32 | struct B4 (base) (empty)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=64, align=32
+// CHECK: | nvsize=64, nvalign=32]
+
+struct __declspec(align(32)) H : B0, B1, B2, B3, B4 {
+ int a;
+ H() : a(0xf0000011) {printf("X : %p\n", this);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct H
+// CHECK: 0 | struct B0 (base) (empty)
+// CHECK: 8 | struct B1 (base) (empty)
+// CHECK: 16 | struct B2 (base) (empty)
+// CHECK: 24 | struct B3 (base) (empty)
+// CHECK: 32 | struct B4 (base) (empty)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=64, align=32
+// CHECK: | nvsize=40, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)+
+sizeof(H)];
diff --git a/test/Layout/ms-x86-empty-virtual-base.cpp b/test/Layout/ms-x86-empty-virtual-base.cpp
new file mode 100644
index 000000000000..ef6f08175e7a
--- /dev/null
+++ b/test/Layout/ms-x86-empty-virtual-base.cpp
@@ -0,0 +1,704 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct __declspec(align(8)) B0 { B0() {printf("B0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct __declspec(align(8)) B1 { B1() {printf("B1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct __declspec(align(8)) B2 { B2() {printf("B2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct __declspec(align(8)) B3 { B3() {printf("B3 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct __declspec(align(8)) B4 { B4() {printf("B4 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+
+struct C0 { int a; C0() : a(0xf00000C0) {printf("C0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct C1 { int a; C1() : a(0xf00000C1) {printf("C1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct C2 { int a; C2() : a(0xf00000C2) {printf("C2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct C3 { int a; C3() : a(0xf00000C3) {printf("C3 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct C4 { int a; C4() : a(0xf00000C4) {printf("C4 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+
+struct __declspec(align(16)) D0 { D0() {printf("D0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} virtual void f() {} };
+struct D1 { D1() {printf("D1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+struct D2 { int a[8]; D2() {printf("D2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
+
+struct A : virtual B0 {
+ int a;
+ A() : a(0xf000000A) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct B : virtual B0 {
+ B0 b0;
+ int a;
+ B() : a(0xf000000B) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | (B vbtable pointer)
+// CHECK: 8 | struct B0 b0 (empty)
+// CHECK: | [sizeof=8, align=8
+// CHECK: | nvsize=0, nvalign=1]
+// CHECK: 16 | int a
+// CHECK: 24 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=24, align=8
+// CHECK: | nvsize=24, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | (B vbtable pointer)
+// CHECK-X64: 8 | struct B0 b0 (empty)
+// CHECK-X64: | [sizeof=8, align=8
+// CHECK-X64: | nvsize=0, nvalign=1]
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct C : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
+ int a;
+ C() : a(0xf000000C) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: 16 | struct B1 (virtual base) (empty)
+// CHECK: 24 | struct B2 (virtual base) (empty)
+// CHECK: 32 | struct B3 (virtual base) (empty)
+// CHECK: 40 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=40, align=8
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: 24 | struct B1 (virtual base) (empty)
+// CHECK-X64: 32 | struct B2 (virtual base) (empty)
+// CHECK-X64: 40 | struct B3 (virtual base) (empty)
+// CHECK-X64: 48 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct D {
+ B0 b0;
+ C0 c0;
+ C1 c1;
+ C2 c2;
+ B1 b1;
+ int a;
+ D() : a(0xf000000D) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct B0 b0 (empty)
+// CHECK: 8 | struct C0 c0
+// CHECK: 8 | int a
+// CHECK: 12 | struct C1 c1
+// CHECK: 12 | int a
+// CHECK: 16 | struct C2 c2
+// CHECK: 16 | int a
+// CHECK: 24 | struct B1 b1 (empty)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=40, align=8
+// CHECK: | nvsize=40, nvalign=8]
+// CHECK-64: *** Dumping AST Record Layout
+// CHECK-64: 0 | struct D
+// CHECK-64: 0 | struct B0 b0 (empty)
+// CHECK-64: 8 | struct C0 c0
+// CHECK-64: 8 | int a
+// CHECK-64: 12 | struct C1 c1
+// CHECK-64: 12 | int a
+// CHECK-64: 16 | struct C2 c2
+// CHECK-64: 16 | int a
+// CHECK-64: 24 | struct B1 b1 (empty)
+// CHECK-64: 32 | int a
+// CHECK-64: | [sizeof=40, align=8
+// CHECK-64: | nvsize=40, nvalign=8]
+
+struct E : virtual B0, virtual C0, virtual C1, virtual C2, virtual B1 {
+ int a;
+ E() : a(0xf000000E) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | (E vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: 8 | struct C0 (virtual base)
+// CHECK: 8 | int a
+// CHECK: 12 | struct C1 (virtual base)
+// CHECK: 12 | int a
+// CHECK: 16 | struct C2 (virtual base)
+// CHECK: 16 | int a
+// CHECK: 24 | struct B1 (virtual base) (empty)
+// CHECK: | [sizeof=24, align=8
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | (E vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: 16 | struct C0 (virtual base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | struct C1 (virtual base)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct C2 (virtual base)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | struct B1 (virtual base) (empty)
+// CHECK-X64: | [sizeof=32, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct F : virtual C0, virtual B0, virtual B1, virtual C1 {
+ int a;
+ F() : a(0xf000000F) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | (F vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct C0 (virtual base)
+// CHECK: 8 | int a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: 24 | struct B1 (virtual base) (empty)
+// CHECK: 24 | struct C1 (virtual base)
+// CHECK: 24 | int a
+// CHECK: | [sizeof=32, align=8
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | (F vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct C0 (virtual base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: 32 | struct B1 (virtual base) (empty)
+// CHECK-X64: 32 | struct C1 (virtual base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct G : virtual C0, virtual B0, virtual B1, D0, virtual C1 {
+ int a;
+ G() : a(0xf0000010) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+ virtual void f() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 0 | struct D0 (primary base)
+// CHECK: 0 | (D0 vftable pointer)
+// CHECK: 4 | (G vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 32 | struct C0 (virtual base)
+// CHECK: 32 | int a
+// CHECK: 40 | struct B0 (virtual base) (empty)
+// CHECK: 56 | struct B1 (virtual base) (empty)
+// CHECK: 56 | struct C1 (virtual base)
+// CHECK: 56 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct G
+// CHECK-X64: 0 | struct D0 (primary base)
+// CHECK-X64: 0 | (D0 vftable pointer)
+// CHECK-X64: 8 | (G vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | struct C0 (virtual base)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | struct B0 (virtual base) (empty)
+// CHECK-X64: 56 | struct B1 (virtual base) (empty)
+// CHECK-X64: 56 | struct C1 (virtual base)
+// CHECK-X64: 56 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct H : virtual C0, virtual B0, virtual B1, virtual D0, virtual C1 {
+ int a;
+ H() : a(0xf0000011) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+ virtual void f() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct H
+// CHECK: 0 | (H vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct C0 (virtual base)
+// CHECK: 8 | int a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: 24 | struct B1 (virtual base) (empty)
+// CHECK: 44 | (vtordisp for vbase D0)
+// CHECK: 48 | struct D0 (virtual base)
+// CHECK: 48 | (D0 vftable pointer)
+// CHECK: 52 | struct C1 (virtual base)
+// CHECK: 52 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct H
+// CHECK-X64: 0 | (H vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct C0 (virtual base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: 40 | struct B1 (virtual base) (empty)
+// CHECK-X64: 60 | (vtordisp for vbase D0)
+// CHECK-X64: 64 | struct D0 (virtual base)
+// CHECK-X64: 64 | (D0 vftable pointer)
+// CHECK-X64: 72 | struct C1 (virtual base)
+// CHECK-X64: 72 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct I : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ I() : a(0xf0000012) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct I
+// CHECK: 0 | (I vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B0 (virtual base) (empty)
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct I
+// CHECK-X64: 0 | (I vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B0 (virtual base) (empty)
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct __declspec(align(32)) J : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
+ int a;
+ J() : a(0xf0000012) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct J
+// CHECK: 0 | (J vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: 40 | struct B1 (virtual base) (empty)
+// CHECK: 72 | struct B2 (virtual base) (empty)
+// CHECK: 104 | struct B3 (virtual base) (empty)
+// CHECK: 136 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=160, align=32
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct J
+// CHECK-X64: 0 | (J vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: 40 | struct B1 (virtual base) (empty)
+// CHECK-X64: 72 | struct B2 (virtual base) (empty)
+// CHECK-X64: 104 | struct B3 (virtual base) (empty)
+// CHECK-X64: 136 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=160, align=32
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct K : virtual D1, virtual B1, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ K() : a(0xf0000013) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct K
+// CHECK: 0 | (K vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct D1 (virtual base) (empty)
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct K
+// CHECK-X64: 0 | (K vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct D1 (virtual base) (empty)
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct L : virtual B1, virtual D1, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ L() : a(0xf0000014) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct L
+// CHECK: 0 | (L vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B1 (virtual base) (empty)
+// CHECK: 68 | struct D1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct L
+// CHECK-X64: 0 | (L vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B1 (virtual base) (empty)
+// CHECK-X64: 68 | struct D1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct M : virtual B1, virtual B2, virtual D1, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ M() : a(0xf0000015) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct M
+// CHECK: 0 | (M vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B1 (virtual base) (empty)
+// CHECK: 72 | struct B2 (virtual base) (empty)
+// CHECK: 100 | struct D1 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct M
+// CHECK-X64: 0 | (M vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B1 (virtual base) (empty)
+// CHECK-X64: 72 | struct B2 (virtual base) (empty)
+// CHECK-X64: 100 | struct D1 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct N : virtual C0, virtual B1, virtual D1, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ N() : a(0xf0000016) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct N
+// CHECK: 0 | (N vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct C0 (virtual base)
+// CHECK: 64 | int a
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 100 | struct D1 (virtual base) (empty)
+// CHECK: 136 | struct B2 (virtual base) (empty)
+// CHECK: 168 | struct B3 (virtual base) (empty)
+// CHECK: 200 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=224, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct N
+// CHECK-X64: 0 | (N vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct C0 (virtual base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 100 | struct D1 (virtual base) (empty)
+// CHECK-X64: 136 | struct B2 (virtual base) (empty)
+// CHECK-X64: 168 | struct B3 (virtual base) (empty)
+// CHECK-X64: 200 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=224, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct O : virtual C0, virtual B1, virtual B2, virtual D1, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ O() : a(0xf0000017) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct O
+// CHECK: 0 | (O vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct C0 (virtual base)
+// CHECK: 64 | int a
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 132 | struct D1 (virtual base) (empty)
+// CHECK: 168 | struct B3 (virtual base) (empty)
+// CHECK: 200 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=224, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct O
+// CHECK-X64: 0 | (O vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct C0 (virtual base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 132 | struct D1 (virtual base) (empty)
+// CHECK-X64: 168 | struct B3 (virtual base) (empty)
+// CHECK-X64: 200 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=224, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct P : virtual B1, virtual C0, virtual D1, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ P() : a(0xf0000018) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct P
+// CHECK: 0 | (P vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B1 (virtual base) (empty)
+// CHECK: 64 | struct C0 (virtual base)
+// CHECK: 64 | int a
+// CHECK: 68 | struct D1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct P
+// CHECK-X64: 0 | (P vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B1 (virtual base) (empty)
+// CHECK-X64: 64 | struct C0 (virtual base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: 68 | struct D1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct Q : virtual B1, virtual C0, virtual B2, virtual D1, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ Q() : a(0xf0000019) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct Q
+// CHECK: 0 | (Q vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B1 (virtual base) (empty)
+// CHECK: 64 | struct C0 (virtual base)
+// CHECK: 64 | int a
+// CHECK: 72 | struct B2 (virtual base) (empty)
+// CHECK: 100 | struct D1 (virtual base) (empty)
+// CHECK: 136 | struct B3 (virtual base) (empty)
+// CHECK: 168 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=192, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct Q
+// CHECK-X64: 0 | (Q vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B1 (virtual base) (empty)
+// CHECK-X64: 64 | struct C0 (virtual base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: 72 | struct B2 (virtual base) (empty)
+// CHECK-X64: 100 | struct D1 (virtual base) (empty)
+// CHECK-X64: 136 | struct B3 (virtual base) (empty)
+// CHECK-X64: 168 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=192, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct R : virtual B0, virtual B1, virtual B2, virtual C0, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ R() : a(0xf0000020) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct R
+// CHECK: 0 | (R vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B0 (virtual base) (empty)
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 104 | struct B2 (virtual base) (empty)
+// CHECK: 104 | struct C0 (virtual base)
+// CHECK: 104 | int a
+// CHECK: 112 | struct B3 (virtual base) (empty)
+// CHECK: 136 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=160, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct R
+// CHECK-X64: 0 | (R vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B0 (virtual base) (empty)
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 104 | struct B2 (virtual base) (empty)
+// CHECK-X64: 104 | struct C0 (virtual base)
+// CHECK-X64: 104 | int a
+// CHECK-X64: 112 | struct B3 (virtual base) (empty)
+// CHECK-X64: 136 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=160, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct S : virtual B0, virtual B1, virtual C0, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(32)) int a;
+ S() : a(0xf0000021) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct S
+// CHECK: 0 | (S vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 64 | struct B0 (virtual base) (empty)
+// CHECK: 72 | struct B1 (virtual base) (empty)
+// CHECK: 72 | struct C0 (virtual base)
+// CHECK: 72 | int a
+// CHECK: 80 | struct B2 (virtual base) (empty)
+// CHECK: 104 | struct B3 (virtual base) (empty)
+// CHECK: 136 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=160, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct S
+// CHECK-X64: 0 | (S vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 64 | struct B0 (virtual base) (empty)
+// CHECK-X64: 72 | struct B1 (virtual base) (empty)
+// CHECK-X64: 72 | struct C0 (virtual base)
+// CHECK-X64: 72 | int a
+// CHECK-X64: 80 | struct B2 (virtual base) (empty)
+// CHECK-X64: 104 | struct B3 (virtual base) (empty)
+// CHECK-X64: 136 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=160, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct T : virtual B0, virtual B1, virtual C0, virtual D2, virtual B2, virtual B3, virtual B4 {
+ __declspec(align(16)) int a;
+ T() : a(0xf0000022) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct T
+// CHECK: 0 | (T vbtable pointer)
+// CHECK: 16 | int a
+// CHECK: 32 | struct B0 (virtual base) (empty)
+// CHECK: 40 | struct B1 (virtual base) (empty)
+// CHECK: 40 | struct C0 (virtual base)
+// CHECK: 40 | int a
+// CHECK: 44 | struct D2 (virtual base)
+// CHECK: 44 | int [8] a
+// CHECK: 80 | struct B2 (virtual base) (empty)
+// CHECK: 88 | struct B3 (virtual base) (empty)
+// CHECK: 104 | struct B4 (virtual base) (empty)
+// CHECK: | [sizeof=112, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct T
+// CHECK-X64: 0 | (T vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | struct B0 (virtual base) (empty)
+// CHECK-X64: 40 | struct B1 (virtual base) (empty)
+// CHECK-X64: 40 | struct C0 (virtual base)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 44 | struct D2 (virtual base)
+// CHECK-X64: 44 | int [8] a
+// CHECK-X64: 80 | struct B2 (virtual base) (empty)
+// CHECK-X64: 88 | struct B3 (virtual base) (empty)
+// CHECK-X64: 104 | struct B4 (virtual base) (empty)
+// CHECK-X64: | [sizeof=112, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct __declspec(align(32)) U : virtual B0, virtual B1 {
+ int a;
+ U() : a(0xf0000023) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct U
+// CHECK: 0 | (U vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: 40 | struct B1 (virtual base) (empty)
+// CHECK: | [sizeof=64, align=32
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct U
+// CHECK-X64: 0 | (U vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: 40 | struct B1 (virtual base) (empty)
+// CHECK-X64: | [sizeof=64, align=32
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct __declspec(align(32)) V : virtual D1 {
+ int a;
+ V() : a(0xf0000024) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct V
+// CHECK: 0 | (V vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct D1 (virtual base) (empty)
+// CHECK: | [sizeof=32, align=32
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct V
+// CHECK-X64: 0 | (V vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct D1 (virtual base) (empty)
+// CHECK-X64: | [sizeof=32, align=32
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)+
+sizeof(H)+
+sizeof(I)+
+sizeof(J)+
+sizeof(K)+
+sizeof(L)+
+sizeof(M)+
+sizeof(N)+
+sizeof(O)+
+sizeof(P)+
+sizeof(Q)+
+sizeof(R)+
+sizeof(S)+
+sizeof(T)+
+sizeof(U)+
+sizeof(V)]; \ No newline at end of file
diff --git a/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp b/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
new file mode 100644
index 000000000000..7dd3fad5bf45
--- /dev/null
+++ b/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
@@ -0,0 +1,735 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 { B0() { printf("B0 = %p\n", this); } };
+struct B1 { B1() { printf("B1 = %p\n", this); } };
+struct B2 { B2() { printf("B2 = %p\n", this); } };
+struct B3 { B3() { printf("B3 = %p\n", this); } };
+struct B4 { B4() { printf("B4 = %p\n", this); } };
+struct B5 { B5() { printf("B5 = %p\n", this); } };
+struct __declspec(align(2)) B6 { B6() { printf("B6 = %p\n", this); } };
+struct __declspec(align(16)) B7 { B7() { printf("B7 = %p\n", this); } };
+struct B8 { char c[5]; B8() { printf("B8 = %p\n", this); } };
+struct B9 { char c[6]; B9() { printf("B9 = %p\n", this); } };
+struct B10 { char c[7]; B10() { printf("B10 = %p\n", this); } };
+struct B11 { char c[8]; B11() { printf("B11 = %p\n", this); } };
+struct B0X { B0X() { printf("B0 = %p\n", this); } };
+struct B1X { B1X() { printf("B1 = %p\n", this); } };
+struct __declspec(align(16)) B2X { B2X() { printf("B2 = %p\n", this); } };
+struct __declspec(align(2)) B3X { B3X() { printf("B3 = %p\n", this); } };
+struct B4X { B4X() { printf("B4 = %p\n", this); } };
+struct B5X { B5X() { printf("B5 = %p\n", this); } };
+struct B6X { B6X() { printf("B6 = %p\n", this); } };
+struct B8X { short a; B8X() : a(0xf00000B8) { printf("B8 = %p\n", this); } };
+
+struct AA : B8, B1, virtual B0 {
+ int a;
+ AA() : a(0xf00000AA) { printf("AA = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AA
+// CHECK: 0 | struct B8 (base)
+// CHECK: 0 | char [5] c
+// CHECK: 13 | struct B1 (base) (empty)
+// CHECK: 8 | (AA vbtable pointer)
+// CHECK: 16 | int a
+// CHECK: 20 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AA
+// CHECK-X64: 0 | struct B8 (base)
+// CHECK-X64: 0 | char [5] c
+// CHECK-X64: 17 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AA vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AB : B8, B1, virtual B0 {
+ short a;
+ AB() : a(0xf00000AB) { printf("AB = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AB
+// CHECK: 0 | struct B8 (base)
+// CHECK: 0 | char [5] c
+// CHECK: 13 | struct B1 (base) (empty)
+// CHECK: 8 | (AB vbtable pointer)
+// CHECK: 14 | short a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AB
+// CHECK-X64: 0 | struct B8 (base)
+// CHECK-X64: 0 | char [5] c
+// CHECK-X64: 17 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AB vbtable pointer)
+// CHECK-X64: 18 | short a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AC : B8, B1, virtual B0 {
+ char a;
+ AC() : a(0xf00000AC) { printf("AC = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AC
+// CHECK: 0 | struct B8 (base)
+// CHECK: 0 | char [5] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AC vbtable pointer)
+// CHECK: 12 | char a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AC
+// CHECK-X64: 0 | struct B8 (base)
+// CHECK-X64: 0 | char [5] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AC vbtable pointer)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AD : B8, B1, virtual B0 {
+ AD() { printf("AD = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AD
+// CHECK: 0 | struct B8 (base)
+// CHECK: 0 | char [5] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AD vbtable pointer)
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AD
+// CHECK-X64: 0 | struct B8 (base)
+// CHECK-X64: 0 | char [5] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AD vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct AA1 : B9, B1, virtual B0 {
+ int a;
+ AA1() : a(0xf0000AA1) { printf("AA1 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AA1
+// CHECK: 0 | struct B9 (base)
+// CHECK: 0 | char [6] c
+// CHECK: 14 | struct B1 (base) (empty)
+// CHECK: 8 | (AA1 vbtable pointer)
+// CHECK: 16 | int a
+// CHECK: 20 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AA1
+// CHECK-X64: 0 | struct B9 (base)
+// CHECK-X64: 0 | char [6] c
+// CHECK-X64: 18 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AA1 vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AB1 : B9, B1, virtual B0 {
+ short a;
+ AB1() : a(0xf0000AB1) { printf("AB1 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AB1
+// CHECK: 0 | struct B9 (base)
+// CHECK: 0 | char [6] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AB1 vbtable pointer)
+// CHECK: 12 | short a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AB1
+// CHECK-X64: 0 | struct B9 (base)
+// CHECK-X64: 0 | char [6] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AB1 vbtable pointer)
+// CHECK-X64: 16 | short a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AC1 : B9, B1, virtual B0 {
+ char a;
+ AC1() : a(0xf0000AC1) { printf("AC1 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AC1
+// CHECK: 0 | struct B9 (base)
+// CHECK: 0 | char [6] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AC1 vbtable pointer)
+// CHECK: 12 | char a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AC1
+// CHECK-X64: 0 | struct B9 (base)
+// CHECK-X64: 0 | char [6] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AC1 vbtable pointer)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AD1 : B9, B1, virtual B0 {
+ AD1() { printf("AD1 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AD1
+// CHECK: 0 | struct B9 (base)
+// CHECK: 0 | char [6] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AD1 vbtable pointer)
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AD1
+// CHECK-X64: 0 | struct B9 (base)
+// CHECK-X64: 0 | char [6] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AD1 vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct AA2 : B10, B1, virtual B0 {
+ int a;
+ AA2() : a(0xf0000AA2) { printf("AA2 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AA2
+// CHECK: 0 | struct B10 (base)
+// CHECK: 0 | char [7] c
+// CHECK: 15 | struct B1 (base) (empty)
+// CHECK: 8 | (AA2 vbtable pointer)
+// CHECK: 16 | int a
+// CHECK: 20 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AA2
+// CHECK-X64: 0 | struct B10 (base)
+// CHECK-X64: 0 | char [7] c
+// CHECK-X64: 19 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AA2 vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AB2 : B10, B1, virtual B0 {
+ short a;
+ AB2() : a(0xf0000AB2) { printf("AB2 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AB2
+// CHECK: 0 | struct B10 (base)
+// CHECK: 0 | char [7] c
+// CHECK: 13 | struct B1 (base) (empty)
+// CHECK: 8 | (AB2 vbtable pointer)
+// CHECK: 14 | short a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AB2
+// CHECK-X64: 0 | struct B10 (base)
+// CHECK-X64: 0 | char [7] c
+// CHECK-X64: 17 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AB2 vbtable pointer)
+// CHECK-X64: 18 | short a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AC2 : B10, B1, virtual B0 {
+ char a;
+ AC2() : a(0xf0000AC2) { printf("AC2 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AC2
+// CHECK: 0 | struct B10 (base)
+// CHECK: 0 | char [7] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AC2 vbtable pointer)
+// CHECK: 12 | char a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AC2
+// CHECK-X64: 0 | struct B10 (base)
+// CHECK-X64: 0 | char [7] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AC2 vbtable pointer)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AD2 : B10, B1, virtual B0 {
+ AD2() { printf("AD2 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AD2
+// CHECK: 0 | struct B10 (base)
+// CHECK: 0 | char [7] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AD2 vbtable pointer)
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AD2
+// CHECK-X64: 0 | struct B10 (base)
+// CHECK-X64: 0 | char [7] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AD2 vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct AA3 : B11, B1, virtual B0 {
+ int a;
+ AA3() : a(0xf0000AA3) { printf("AA3 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AA3
+// CHECK: 0 | struct B11 (base)
+// CHECK: 0 | char [8] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AA3 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AA3
+// CHECK-X64: 0 | struct B11 (base)
+// CHECK-X64: 0 | char [8] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AA3 vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AB3 : B11, B1, virtual B0 {
+ short a;
+ AB3() : a(0xf0000AB3) { printf("AB3 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AB3
+// CHECK: 0 | struct B11 (base)
+// CHECK: 0 | char [8] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AB3 vbtable pointer)
+// CHECK: 12 | short a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AB3
+// CHECK-X64: 0 | struct B11 (base)
+// CHECK-X64: 0 | char [8] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AB3 vbtable pointer)
+// CHECK-X64: 16 | short a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AC3 : B11, B1, virtual B0 {
+ char a;
+ AC3() : a(0xf0000AC3) { printf("AC3 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AC3
+// CHECK: 0 | struct B11 (base)
+// CHECK: 0 | char [8] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AC3 vbtable pointer)
+// CHECK: 12 | char a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AC3
+// CHECK-X64: 0 | struct B11 (base)
+// CHECK-X64: 0 | char [8] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AC3 vbtable pointer)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AD3 : B11, B1, virtual B0 {
+ AD3() { printf("AD3 = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AD3
+// CHECK: 0 | struct B11 (base)
+// CHECK: 0 | char [8] c
+// CHECK: 12 | struct B1 (base) (empty)
+// CHECK: 8 | (AD3 vbtable pointer)
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AD3
+// CHECK-X64: 0 | struct B11 (base)
+// CHECK-X64: 0 | char [8] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (AD3 vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct B : B1, B2, virtual B0 {
+ B() { printf("B = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct B1 (base) (empty)
+// CHECK: 8 | struct B2 (base) (empty)
+// CHECK: 4 | (B vbtable pointer)
+// CHECK: 8 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | struct B1 (base) (empty)
+// CHECK-X64: 16 | struct B2 (base) (empty)
+// CHECK-X64: 8 | (B vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct C : B1, B2, B3, virtual B0 {
+ char a;
+ C() : a(0xf000000C) { printf("C = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | struct B1 (base) (empty)
+// CHECK: 1 | struct B2 (base) (empty)
+// CHECK: 8 | struct B3 (base) (empty)
+// CHECK: 4 | (C vbtable pointer)
+// CHECK: 8 | char a
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | struct B1 (base) (empty)
+// CHECK-X64: 1 | struct B2 (base) (empty)
+// CHECK-X64: 16 | struct B3 (base) (empty)
+// CHECK-X64: 8 | (C vbtable pointer)
+// CHECK-X64: 16 | char a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct D : B1, B2, B3, B4, B5, virtual B0 {
+ int a;
+ D() : a(0xf000000D) { printf("D = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct B1 (base) (empty)
+// CHECK: 1 | struct B2 (base) (empty)
+// CHECK: 2 | struct B3 (base) (empty)
+// CHECK: 3 | struct B4 (base) (empty)
+// CHECK: 8 | struct B5 (base) (empty)
+// CHECK: 4 | (D vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | struct B1 (base) (empty)
+// CHECK-X64: 1 | struct B2 (base) (empty)
+// CHECK-X64: 2 | struct B3 (base) (empty)
+// CHECK-X64: 3 | struct B4 (base) (empty)
+// CHECK-X64: 16 | struct B5 (base) (empty)
+// CHECK-X64: 8 | (D vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct E : B1, B6, B3, B4, B5, virtual B0 {
+ int a;
+ E() : a(0xf000000E) { printf("E = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | struct B1 (base) (empty)
+// CHECK: 2 | struct B6 (base) (empty)
+// CHECK: 3 | struct B3 (base) (empty)
+// CHECK: 4 | struct B4 (base) (empty)
+// CHECK: 13 | struct B5 (base) (empty)
+// CHECK: 8 | (E vbtable pointer)
+// CHECK: 16 | int a
+// CHECK: 20 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | struct B1 (base) (empty)
+// CHECK-X64: 2 | struct B6 (base) (empty)
+// CHECK-X64: 3 | struct B3 (base) (empty)
+// CHECK-X64: 4 | struct B4 (base) (empty)
+// CHECK-X64: 17 | struct B5 (base) (empty)
+// CHECK-X64: 8 | (E vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct F : B1, B6, B4, B8, B5, virtual B0 {
+ int a;
+ F() : a(0xf000000F) { printf("&a = %p\n", &a); printf("F = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | struct B1 (base) (empty)
+// CHECK: 2 | struct B6 (base) (empty)
+// CHECK: 3 | struct B4 (base) (empty)
+// CHECK: 3 | struct B8 (base)
+// CHECK: 3 | char [5] c
+// CHECK: 12 | struct B5 (base) (empty)
+// CHECK: 8 | (F vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | struct B1 (base) (empty)
+// CHECK-X64: 2 | struct B6 (base) (empty)
+// CHECK-X64: 3 | struct B4 (base) (empty)
+// CHECK-X64: 3 | struct B8 (base)
+// CHECK-X64: 3 | char [5] c
+// CHECK-X64: 16 | struct B5 (base) (empty)
+// CHECK-X64: 8 | (F vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct G : B8, B1, virtual B0 {
+ int a;
+ __declspec(align(16)) int a1;
+ G() : a(0xf0000010), a1(0xf0000010) { printf("G = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 0 | struct B8 (base)
+// CHECK: 0 | char [5] c
+// CHECK: 21 | struct B1 (base) (empty)
+// CHECK: 8 | (G vbtable pointer)
+// CHECK: 24 | int a
+// CHECK: 32 | int a1
+// CHECK: 48 | struct B0 (virtual base) (empty)
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct G
+// CHECK-X64: 0 | struct B8 (base)
+// CHECK-X64: 0 | char [5] c
+// CHECK-X64: 16 | struct B1 (base) (empty)
+// CHECK-X64: 8 | (G vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | int a1
+// CHECK-X64: 48 | struct B0 (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct AX : B1X, B2X, B3X, B4X, virtual B0X {
+ int a;
+ AX() : a(0xf000000A) { printf(" A = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AX
+// CHECK: 0 | struct B1X (base) (empty)
+// CHECK: 16 | struct B2X (base) (empty)
+// CHECK: 18 | struct B3X (base) (empty)
+// CHECK: 35 | struct B4X (base) (empty)
+// CHECK: 20 | (AX vbtable pointer)
+// CHECK: 36 | int a
+// CHECK: 48 | struct B0X (virtual base) (empty)
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AX
+// CHECK-X64: 0 | struct B1X (base) (empty)
+// CHECK-X64: 16 | struct B2X (base) (empty)
+// CHECK-X64: 18 | struct B3X (base) (empty)
+// CHECK-X64: 33 | struct B4X (base) (empty)
+// CHECK-X64: 24 | (AX vbtable pointer)
+// CHECK-X64: 36 | int a
+// CHECK-X64: 48 | struct B0X (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct BX : B2X, B1X, B3X, B4X, virtual B0X {
+ int a;
+ BX() : a(0xf000000B) { printf(" B = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct BX
+// CHECK: 0 | struct B2X (base) (empty)
+// CHECK: 1 | struct B1X (base) (empty)
+// CHECK: 2 | struct B3X (base) (empty)
+// CHECK: 19 | struct B4X (base) (empty)
+// CHECK: 4 | (BX vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 32 | struct B0X (virtual base) (empty)
+// CHECK: | [sizeof=32, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct BX
+// CHECK-X64: 0 | struct B2X (base) (empty)
+// CHECK-X64: 1 | struct B1X (base) (empty)
+// CHECK-X64: 2 | struct B3X (base) (empty)
+// CHECK-X64: 17 | struct B4X (base) (empty)
+// CHECK-X64: 8 | (BX vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 32 | struct B0X (virtual base) (empty)
+// CHECK-X64: | [sizeof=32, align=16
+// CHECK-X64: | nvsize=32, nvalign=16]
+
+struct CX : B1X, B3X, B2X, virtual B0X {
+ int a;
+ CX() : a(0xf000000C) { printf(" C = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct CX
+// CHECK: 0 | struct B1X (base) (empty)
+// CHECK: 2 | struct B3X (base) (empty)
+// CHECK: 32 | struct B2X (base) (empty)
+// CHECK: 4 | (CX vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 48 | struct B0X (virtual base) (empty)
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct CX
+// CHECK-X64: 0 | struct B1X (base) (empty)
+// CHECK-X64: 2 | struct B3X (base) (empty)
+// CHECK-X64: 32 | struct B2X (base) (empty)
+// CHECK-X64: 8 | (CX vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B0X (virtual base) (empty)
+// CHECK-X64: | [sizeof=48, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct DX : B8X, B1X, virtual B0X {
+ int a;
+ DX() : a(0xf000000D) { printf(" D = %p\n", this); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct DX
+// CHECK: 0 | struct B8X (base)
+// CHECK: 0 | short a
+// CHECK: 10 | struct B1X (base) (empty)
+// CHECK: 4 | (DX vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | struct B0X (virtual base) (empty)
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct DX
+// CHECK-X64: 0 | struct B8X (base)
+// CHECK-X64: 0 | short a
+// CHECK-X64: 18 | struct B1X (base) (empty)
+// CHECK-X64: 8 | (DX vbtable pointer)
+// CHECK-X64: 20 | int a
+// CHECK-X64: 24 | struct B0X (virtual base) (empty)
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+int a[
+sizeof(AA)+
+sizeof(AB)+
+sizeof(AC)+
+sizeof(AD)+
+sizeof(AA1)+
+sizeof(AB1)+
+sizeof(AC1)+
+sizeof(AD1)+
+sizeof(AA2)+
+sizeof(AB2)+
+sizeof(AC2)+
+sizeof(AD2)+
+sizeof(AA3)+
+sizeof(AB3)+
+sizeof(AC3)+
+sizeof(AD3)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)+
+sizeof(AX)+
+sizeof(BX)+
+sizeof(CX)+
+sizeof(DX)];
diff --git a/test/Layout/ms-x86-misalignedarray.cpp b/test/Layout/ms-x86-misalignedarray.cpp
new file mode 100644
index 000000000000..f6887daf15b6
--- /dev/null
+++ b/test/Layout/ms-x86-misalignedarray.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+struct T0 { char c; };
+struct T2 : virtual T0 { };
+struct T3 { T2 a[1]; char c; };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct T3
+// CHECK: 0 | struct T2 [1] a
+// CHECK: 5 | char c
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct T3
+// CHECK-X64: 0 | struct T2 [1] a
+// CHECK-X64: 16 | char c
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+int a[sizeof(T3)];
diff --git a/test/Layout/ms-x86-primary-bases.cpp b/test/Layout/ms-x86-primary-bases.cpp
new file mode 100644
index 000000000000..bc9b801d99c8
--- /dev/null
+++ b/test/Layout/ms-x86-primary-bases.cpp
@@ -0,0 +1,317 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 { int a; B0() : a(0xf00000B0) { printf("B0 = %p\n", this); } virtual void f() { printf("B0"); } };
+struct B1 { int a; B1() : a(0xf00000B1) { printf("B1 = %p\n", this); } virtual void g() { printf("B1"); } };
+struct B2 { int a; B2() : a(0xf00000B2) { printf("B1 = %p\n", this); } };
+struct B0X { int a; B0X() : a(0xf00000B0) {} };
+struct B1X { int a; B1X() : a(0xf00000B1) {} virtual void f() { printf("B0"); } };
+struct B2X : virtual B1X { int a; B2X() : a(0xf00000B2) {} };
+
+struct A : virtual B0 {
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | (B0 vftable pointer)
+// CHECK: 8 | int a
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | (B0 vftable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct B : virtual B0 {
+ virtual void f() { printf("B"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | (B vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | (B0 vftable pointer)
+// CHECK: 8 | int a
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | (B vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | (B0 vftable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct C : virtual B0 {
+ virtual void g() { printf("A"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vftable pointer)
+// CHECK: 4 | (C vbtable pointer)
+// CHECK: 8 | struct B0 (virtual base)
+// CHECK: 8 | (B0 vftable pointer)
+// CHECK: 12 | int a
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vftable pointer)
+// CHECK-X64: 8 | (C vbtable pointer)
+// CHECK-X64: 16 | struct B0 (virtual base)
+// CHECK-X64: 16 | (B0 vftable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: | [sizeof=32, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct D : virtual B2, virtual B0 {
+ virtual void f() { printf("D"); }
+ virtual void g() { printf("D"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | (D vftable pointer)
+// CHECK: 4 | (D vbtable pointer)
+// CHECK: 8 | struct B2 (virtual base)
+// CHECK: 8 | int a
+// CHECK: 12 | struct B0 (virtual base)
+// CHECK: 12 | (B0 vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | (D vftable pointer)
+// CHECK-X64: 8 | (D vbtable pointer)
+// CHECK-X64: 16 | struct B2 (virtual base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B0 (virtual base)
+// CHECK-X64: 24 | (B0 vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct E : B0, virtual B1 {
+ virtual void f() { printf("E"); }
+ virtual void g() { printf("E"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | struct B0 (primary base)
+// CHECK: 0 | (B0 vftable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | (E vbtable pointer)
+// CHECK: 12 | struct B1 (virtual base)
+// CHECK: 12 | (B1 vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | struct B0 (primary base)
+// CHECK-X64: 0 | (B0 vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (E vbtable pointer)
+// CHECK-X64: 24 | struct B1 (virtual base)
+// CHECK-X64: 24 | (B1 vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct F : virtual B0, virtual B1 {
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | (F vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | (B0 vftable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct B1 (virtual base)
+// CHECK: 12 | (B1 vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | (F vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | (B0 vftable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B1 (virtual base)
+// CHECK-X64: 24 | (B1 vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct AX : B0X, B1X { int a; AX() : a(0xf000000A) {} virtual void f() { printf("A"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct AX
+// CHECK: 8 | struct B0X (base)
+// CHECK: 8 | int a
+// CHECK: 0 | struct B1X (primary base)
+// CHECK: 0 | (B1X vftable pointer)
+// CHECK: 4 | int a
+// CHECK: 12 | int a
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct AX
+// CHECK-X64: 16 | struct B0X (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 0 | struct B1X (primary base)
+// CHECK-X64: 0 | (B1X vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 20 | int a
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct BX : B0X, B1X { int a; BX() : a(0xf000000B) {} virtual void g() { printf("B"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct BX
+// CHECK: 8 | struct B0X (base)
+// CHECK: 8 | int a
+// CHECK: 0 | struct B1X (primary base)
+// CHECK: 0 | (B1X vftable pointer)
+// CHECK: 4 | int a
+// CHECK: 12 | int a
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=16, nvalign=4]
+// CHECK-x64: *** Dumping AST Record Layout
+// CHECK-x64: 0 | struct BX
+// CHECK-x64: 16 | struct B0X (base)
+// CHECK-x64: 16 | int a
+// CHECK-x64: 0 | struct B1X (primary base)
+// CHECK-x64: 0 | (B1X vftable pointer)
+// CHECK-x64: 8 | int a
+// CHECK-x64: 24 | int a
+// CHECK-x64: | [sizeof=24, align=8
+// CHECK-x64: | nvsize=24, nvalign=8]
+
+struct CX : B0X, B2X { int a; CX() : a(0xf000000C) {} virtual void g() { printf("C"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct CX
+// CHECK: 0 | (CX vftable pointer)
+// CHECK: 4 | struct B0X (base)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B2X (base)
+// CHECK: 8 | (B2X vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | int a
+// CHECK: 20 | struct B1X (virtual base)
+// CHECK: 20 | (B1X vftable pointer)
+// CHECK: 24 | int a
+// CHECK: | [sizeof=28, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct CX
+// CHECK-X64: 0 | (CX vftable pointer)
+// CHECK-X64: 8 | struct B0X (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B2X (base)
+// CHECK-X64: 16 | (B2X vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | struct B1X (virtual base)
+// CHECK-X64: 40 | (B1X vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=56, align=8
+// CHECK-X64: | nvsize=40, nvalign=8]
+
+struct DX : virtual B1X { int a; DX() : a(0xf000000D) {} virtual void f() { printf("D"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct DX
+// CHECK: 0 | (DX vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | (vtordisp for vbase B1X)
+// CHECK: 12 | struct B1X (virtual base)
+// CHECK: 12 | (B1X vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct DX
+// CHECK-X64: 0 | (DX vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 20 | (vtordisp for vbase B1X)
+// CHECK-X64: 24 | struct B1X (virtual base)
+// CHECK-X64: 24 | (B1X vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct EX : virtual B1X { int a; EX() : a(0xf000000E) {} virtual void g() { printf("E"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct EX
+// CHECK: 0 | (EX vftable pointer)
+// CHECK: 4 | (EX vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct B1X (virtual base)
+// CHECK: 12 | (B1X vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct EX
+// CHECK-X64: 0 | (EX vftable pointer)
+// CHECK-X64: 8 | (EX vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct B1X (virtual base)
+// CHECK-X64: 24 | (B1X vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct FX : virtual B1X { int a; FX() : a(0xf000000F) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct FX
+// CHECK: 0 | (FX vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B1X (virtual base)
+// CHECK: 8 | (B1X vftable pointer)
+// CHECK: 12 | int a
+// CHECK: | [sizeof=16, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct FX
+// CHECK-X64: 0 | (FX vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B1X (virtual base)
+// CHECK-X64: 16 | (B1X vftable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: | [sizeof=32, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(AX)+
+sizeof(BX)+
+sizeof(CX)+
+sizeof(DX)+
+sizeof(EX)+
+sizeof(FX)];
diff --git a/test/Layout/ms-x86-size-alignment-fail.cpp b/test/Layout/ms-x86-size-alignment-fail.cpp
new file mode 100644
index 000000000000..f998ee12c8d1
--- /dev/null
+++ b/test/Layout/ms-x86-size-alignment-fail.cpp
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 { char a; B0() : a(0xB0) {} };
+struct __declspec(align(1)) B1 {};
+
+struct A : virtual B0 {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | char a
+// CHECK: | [sizeof=5, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | char a
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct __declspec(align(1)) B : virtual B0 {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | (B vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | char a
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | (B vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | char a
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct C : virtual B0 { int a; C() : a(0xC) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base)
+// CHECK: 8 | char a
+// CHECK: | [sizeof=9, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base)
+// CHECK-X64: 16 | char a
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct D : virtual B0 { __declspec(align(1)) int a; D() : a(0xD) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | (D vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B0 (virtual base)
+// CHECK: 8 | char a
+// CHECK: | [sizeof=12, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | (D vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B0 (virtual base)
+// CHECK-X64: 16 | char a
+// CHECK-X64: | [sizeof=24, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct E : virtual B0, virtual B1 {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | (E vbtable pointer)
+// CHECK: 4 | struct B0 (virtual base)
+// CHECK: 4 | char a
+// CHECK: 5 | struct B1 (virtual base) (empty)
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | (E vbtable pointer)
+// CHECK-X64: 8 | struct B0 (virtual base)
+// CHECK-X64: 8 | char a
+// CHECK-X64: 9 | struct B1 (virtual base) (empty)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+struct F { char a; virtual ~F(); };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | (F vftable pointer)
+// CHECK: 4 | char a
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | (F vftable pointer)
+// CHECK-X64: 8 | char a
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)];
diff --git a/test/Layout/ms-x86-vfvb-alignment.cpp b/test/Layout/ms-x86-vfvb-alignment.cpp
new file mode 100644
index 000000000000..8eea20959b0e
--- /dev/null
+++ b/test/Layout/ms-x86-vfvb-alignment.cpp
@@ -0,0 +1,376 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 { int a; B0() : a(0xf00000B0) {} };
+struct B1 { char a; B1() : a(0xB1) {} };
+struct B2 : virtual B1 { int a; B2() : a(0xf00000B2) {} };
+struct B3 { __declspec(align(16)) int a; B3() : a(0xf00000B3) {} };
+struct B4 : virtual B3 { int a; B4() : a(0xf00000B4) {} };
+struct B5 { __declspec(align(32)) int a; B5() : a(0xf00000B5) {} };
+struct B6 { int a; B6() : a(0xf00000B6) {} virtual void f() { printf("B6"); } };
+
+struct A : B0, virtual B1 { __declspec(align(16)) int a; A() : a(0xf000000A) {} virtual void f() { printf("A"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vftable pointer)
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (A vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct B1 (virtual base)
+// CHECK: 64 | char a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vftable pointer)
+// CHECK-X64: 8 | struct B0 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (A vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct B : A, B2 { int a; B() : a(0xf000000B) {} virtual void f() { printf("B"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct A (primary base)
+// CHECK: 0 | (A vftable pointer)
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (A vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct B2 (base)
+// CHECK: 64 | (B2 vbtable pointer)
+// CHECK: 68 | int a
+// CHECK: 72 | int a
+// CHECK: 80 | struct B1 (virtual base)
+// CHECK: 80 | char a
+// CHECK: | [sizeof=96, align=16
+// CHECK: | nvsize=80, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | struct A (primary base)
+// CHECK-X64: 0 | (A vftable pointer)
+// CHECK-X64: 8 | struct B0 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (A vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B2 (base)
+// CHECK-X64: 48 | (B2 vbtable pointer)
+// CHECK-X64: 56 | int a
+// CHECK-X64: 64 | int a
+// CHECK-X64: 80 | struct B1 (virtual base)
+// CHECK-X64: 80 | char a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=80, nvalign=16]
+
+struct C : B4 { int a; C() : a(0xf000000C) {} virtual void f() { printf("C"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vftable pointer)
+// CHECK: 16 | struct B4 (base)
+// CHECK: 16 | (B4 vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 24 | int a
+// CHECK: 32 | struct B3 (virtual base)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vftable pointer)
+// CHECK-X64: 16 | struct B4 (base)
+// CHECK-X64: 16 | (B4 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B3 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct D : C { int a; D() : a(0xf000000D) {} virtual void f() { printf("D"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct C (primary base)
+// CHECK: 0 | (C vftable pointer)
+// CHECK: 16 | struct B4 (base)
+// CHECK: 16 | (B4 vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 24 | int a
+// CHECK: 32 | int a
+// CHECK: 48 | struct B3 (virtual base)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | struct C (primary base)
+// CHECK-X64: 0 | (C vftable pointer)
+// CHECK-X64: 16 | struct B4 (base)
+// CHECK-X64: 16 | (B4 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | int a
+// CHECK-X64: 64 | struct B3 (virtual base)
+// CHECK-X64: 64 | int a
+// CHECK-X64: | [sizeof=80, align=16
+// CHECK-X64: | nvsize=64, nvalign=16]
+
+struct E : virtual C { int a; E() : a(0xf000000E) {} virtual void f() { printf("E"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct E
+// CHECK: 0 | (E vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 16 | struct B3 (virtual base)
+// CHECK: 16 | int a
+// CHECK: 44 | (vtordisp for vbase C)
+// CHECK: 48 | struct C (virtual base)
+// CHECK: 48 | (C vftable pointer)
+// CHECK: 64 | struct B4 (base)
+// CHECK: 64 | (B4 vbtable pointer)
+// CHECK: 68 | int a
+// CHECK: 72 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct E
+// CHECK-X64: 0 | (E vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B3 (virtual base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 44 | (vtordisp for vbase C)
+// CHECK-X64: 48 | struct C (virtual base)
+// CHECK-X64: 48 | (C vftable pointer)
+// CHECK-X64: 64 | struct B4 (base)
+// CHECK-X64: 64 | (B4 vbtable pointer)
+// CHECK-X64: 72 | int a
+// CHECK-X64: 80 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct F : B3, virtual B0 { int a; F() : a(0xf000000F) {} virtual void f() { printf("F"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct F
+// CHECK: 0 | (F vftable pointer)
+// CHECK: 16 | struct B3 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | (F vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct B0 (virtual base)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct F
+// CHECK-X64: 0 | (F vftable pointer)
+// CHECK-X64: 16 | struct B3 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (F vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 48 | struct B0 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct G : B2, B6, virtual B1 { int a; G() : a(0xf0000010) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct G
+// CHECK: 8 | struct B2 (base)
+// CHECK: 8 | (B2 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 0 | struct B6 (primary base)
+// CHECK: 0 | (B6 vftable pointer)
+// CHECK: 4 | int a
+// CHECK: 16 | int a
+// CHECK: 20 | struct B1 (virtual base)
+// CHECK: 20 | char a
+// CHECK: | [sizeof=21, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct G
+// CHECK-X64: 16 | struct B2 (base)
+// CHECK-X64: 16 | (B2 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 0 | struct B6 (primary base)
+// CHECK-X64: 0 | (B6 vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | struct B1 (virtual base)
+// CHECK-X64: 40 | char a
+// CHECK-X64: | [sizeof=48, align=8
+// CHECK-X64: | nvsize=40, nvalign=8]
+
+struct H : B6, B2, virtual B1 { int a; H() : a(0xf0000011) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct H
+// CHECK: 0 | struct B6 (primary base)
+// CHECK: 0 | (B6 vftable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | struct B2 (base)
+// CHECK: 8 | (B2 vbtable pointer)
+// CHECK: 12 | int a
+// CHECK: 16 | int a
+// CHECK: 20 | struct B1 (virtual base)
+// CHECK: 20 | char a
+// CHECK: | [sizeof=21, align=4
+// CHECK: | nvsize=20, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct H
+// CHECK-X64: 0 | struct B6 (primary base)
+// CHECK-X64: 0 | (B6 vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | struct B2 (base)
+// CHECK-X64: 16 | (B2 vbtable pointer)
+// CHECK-X64: 24 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 40 | struct B1 (virtual base)
+// CHECK-X64: 40 | char a
+// CHECK-X64: | [sizeof=48, align=8
+// CHECK-X64: | nvsize=40, nvalign=8]
+
+struct I : B0, virtual B1 { int a; int a1; __declspec(align(16)) int a2; I() : a(0xf0000011), a1(0xf0000011), a2(0xf0000011) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct I
+// CHECK: 0 | struct B0 (base)
+// CHECK: 0 | int a
+// CHECK: 4 | (I vbtable pointer)
+// CHECK: 20 | int a
+// CHECK: 24 | int a1
+// CHECK: 32 | int a2
+// CHECK: 48 | struct B1 (virtual base)
+// CHECK: 48 | char a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct I
+// CHECK-X64: 0 | struct B0 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 8 | (I vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 20 | int a1
+// CHECK-X64: 32 | int a2
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct J : B0, B3, virtual B1 { int a; int a1; J() : a(0xf0000012), a1(0xf0000012) {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct J
+// CHECK: 0 | struct B0 (base)
+// CHECK: 0 | int a
+// CHECK: 16 | struct B3 (base)
+// CHECK: 16 | int a
+// CHECK: 32 | (J vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 52 | int a1
+// CHECK: 64 | struct B1 (virtual base)
+// CHECK: 64 | char a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct J
+// CHECK-X64: 0 | struct B0 (base)
+// CHECK-X64: 0 | int a
+// CHECK-X64: 16 | struct B3 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | (J vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 44 | int a1
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | char a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct K { int a; K() : a(0xf0000013) {} virtual void f() { printf("K"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct K
+// CHECK: 0 | (K vftable pointer)
+// CHECK: 4 | int a
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct K
+// CHECK-X64: 0 | (K vftable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+struct L : virtual K { int a; L() : a(0xf0000014) {} virtual void g() { printf("L"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct L
+// CHECK: 0 | (L vftable pointer)
+// CHECK: 4 | (L vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 12 | struct K (virtual base)
+// CHECK: 12 | (K vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct L
+// CHECK-X64: 0 | (L vftable pointer)
+// CHECK-X64: 8 | (L vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 24 | struct K (virtual base)
+// CHECK-X64: 24 | (K vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct M : virtual K { int a; M() : a(0xf0000015) {} virtual void f() { printf("M"); } };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct M
+// CHECK: 0 | (M vbtable pointer)
+// CHECK: 4 | int a
+// CHECK: 8 | (vtordisp for vbase K)
+// CHECK: 12 | struct K (virtual base)
+// CHECK: 12 | (K vftable pointer)
+// CHECK: 16 | int a
+// CHECK: | [sizeof=20, align=4
+// CHECK: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct M
+// CHECK-X64: 0 | (M vbtable pointer)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 20 | (vtordisp for vbase K)
+// CHECK-X64: 24 | struct K (virtual base)
+// CHECK-X64: 24 | (K vftable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: | [sizeof=40, align=8
+// CHECK-X64: | nvsize=16, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)+
+sizeof(E)+
+sizeof(F)+
+sizeof(G)+
+sizeof(H)+
+sizeof(I)+
+sizeof(J)+
+sizeof(K)+
+sizeof(L)+
+sizeof(M)];
diff --git a/test/Layout/ms-x86-vfvb-sharing.cpp b/test/Layout/ms-x86-vfvb-sharing.cpp
new file mode 100644
index 000000000000..2b3d08e44c67
--- /dev/null
+++ b/test/Layout/ms-x86-vfvb-sharing.cpp
@@ -0,0 +1,140 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 { int a; B0() : a(0xf00000B0) { printf("B0 = %p\n", this); } };
+struct B1 { int a; B1() : a(0xf00000B1) { printf("B1 = %p\n", this); } };
+struct B2 { B2() { printf("B2 = %p\n", this); } virtual void g() { printf("B2"); } };
+struct B3 : virtual B1 { B3() { printf("B3 = %p\n", this); } };
+struct B4 : virtual B1 { B4() { printf("B4 = %p\n", this); } virtual void g() { printf("B4"); } };
+
+struct A : B0, virtual B1 {
+ __declspec(align(16)) int a;
+ A() : a(0xf000000A) { printf(" A = %p\n\n", this); }
+ virtual void f() { printf("A"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vftable pointer)
+// CHECK: 16 | struct B0 (base)
+// CHECK: 16 | int a
+// CHECK: 20 | (A vbtable pointer)
+// CHECK: 48 | int a
+// CHECK: 64 | struct B1 (virtual base)
+// CHECK: 64 | int a
+// CHECK: | [sizeof=80, align=16
+// CHECK: | nvsize=64, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vftable pointer)
+// CHECK-X64: 8 | struct B0 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (A vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct B : B2, B0, virtual B1 {
+ __declspec(align(16)) int a;
+ B() : a(0xf000000B) { printf(" B = %p\n\n", this); }
+ virtual void f() { printf("B"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct B
+// CHECK: 0 | struct B2 (primary base)
+// CHECK: 0 | (B2 vftable pointer)
+// CHECK: 4 | struct B0 (base)
+// CHECK: 4 | int a
+// CHECK: 8 | (B vbtable pointer)
+// CHECK: 32 | int a
+// CHECK: 48 | struct B1 (virtual base)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct B
+// CHECK-X64: 0 | struct B2 (primary base)
+// CHECK-X64: 0 | (B2 vftable pointer)
+// CHECK-X64: 8 | struct B0 (base)
+// CHECK-X64: 8 | int a
+// CHECK-X64: 16 | (B vbtable pointer)
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct C : B3, B0, virtual B1 {
+ __declspec(align(16)) int a;
+ C() : a(0xf000000C) { printf(" C = %p\n\n", this); }
+ virtual void f() { printf("C"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vftable pointer)
+// CHECK: 16 | struct B3 (base)
+// CHECK: 16 | (B3 vbtable pointer)
+// CHECK: 20 | struct B0 (base)
+// CHECK: 20 | int a
+// CHECK: 32 | int a
+// CHECK: 48 | struct B1 (virtual base)
+// CHECK: 48 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=48, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vftable pointer)
+// CHECK-X64: 8 | struct B3 (base)
+// CHECK-X64: 8 | (B3 vbtable pointer)
+// CHECK-X64: 16 | struct B0 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+struct D : B4, B0, virtual B1 {
+ __declspec(align(16)) int a;
+ D() : a(0xf000000D) { printf(" D = %p\n\n", this); }
+ virtual void f() { printf("D"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | struct B4 (primary base)
+// CHECK: 0 | (B4 vftable pointer)
+// CHECK: 4 | (B4 vbtable pointer)
+// CHECK: 8 | struct B0 (base)
+// CHECK: 8 | int a
+// CHECK: 16 | int a
+// CHECK: 32 | struct B1 (virtual base)
+// CHECK: 32 | int a
+// CHECK: | [sizeof=48, align=16
+// CHECK: | nvsize=32, nvalign=16]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | struct B4 (primary base)
+// CHECK-X64: 0 | (B4 vftable pointer)
+// CHECK-X64: 8 | (B4 vbtable pointer)
+// CHECK-X64: 16 | struct B0 (base)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 32 | int a
+// CHECK-X64: 48 | struct B1 (virtual base)
+// CHECK-X64: 48 | int a
+// CHECK-X64: | [sizeof=64, align=16
+// CHECK-X64: | nvsize=48, nvalign=16]
+
+int a[
+sizeof(A)+
+sizeof(B)+
+sizeof(C)+
+sizeof(D)];
diff --git a/test/Layout/ms-x86-vtordisp.cpp b/test/Layout/ms-x86-vtordisp.cpp
new file mode 100644
index 000000000000..b16f09ed704c
--- /dev/null
+++ b/test/Layout/ms-x86-vtordisp.cpp
@@ -0,0 +1,170 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
+// RUN: | FileCheck %s -check-prefix CHECK-X64
+
+extern "C" int printf(const char *fmt, ...);
+
+struct B0 {
+ int a;
+ B0() : a(0xf00000B0) {}
+ virtual void f() { printf("B0"); }
+};
+
+struct __declspec(align(16)) B1 {
+ int a;
+ B1() : a(0xf00000B1) {}
+ virtual void f() { printf("B1"); }
+};
+
+struct __declspec(align(16)) Align16 {};
+struct __declspec(align(32)) Align32 {};
+struct VAlign16 : virtual Align16 {};
+struct VAlign32 : virtual Align32 {};
+
+struct A : virtual B0, virtual B1 {
+ int a;
+ A() : a(0xf000000A) {}
+ virtual void f() { printf("A"); }
+ virtual void g() { printf("A"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct A
+// CHECK: 0 | (A vftable pointer)
+// CHECK: 4 | (A vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 16 | (vtordisp for vbase B0)
+// CHECK: 20 | struct B0 (virtual base)
+// CHECK: 20 | (B0 vftable pointer)
+// CHECK: 24 | int a
+// CHECK: 44 | (vtordisp for vbase B1)
+// CHECK: 48 | struct B1 (virtual base)
+// CHECK: 48 | (B1 vftable pointer)
+// CHECK: 52 | int a
+// CHECK: | [sizeof=64, align=16
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct A
+// CHECK-X64: 0 | (A vftable pointer)
+// CHECK-X64: 8 | (A vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 36 | (vtordisp for vbase B0)
+// CHECK-X64: 40 | struct B0 (virtual base)
+// CHECK-X64: 40 | (B0 vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 76 | (vtordisp for vbase B1)
+// CHECK-X64: 80 | struct B1 (virtual base)
+// CHECK-X64: 80 | (B1 vftable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=16
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct C : virtual B0, virtual B1, VAlign32 {
+ int a;
+ C() : a(0xf000000C) {}
+ virtual void f() { printf("C"); }
+ virtual void g() { printf("C"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct C
+// CHECK: 0 | (C vftable pointer)
+// CHECK: 32 | struct VAlign32 (base)
+// CHECK: 32 | (VAlign32 vbtable pointer)
+// CHECK: 36 | int a
+// CHECK: 64 | (vtordisp for vbase B0)
+// CHECK: 68 | struct B0 (virtual base)
+// CHECK: 68 | (B0 vftable pointer)
+// CHECK: 72 | int a
+// CHECK: 108 | (vtordisp for vbase B1)
+// CHECK: 112 | struct B1 (virtual base)
+// CHECK: 112 | (B1 vftable pointer)
+// CHECK: 116 | int a
+// CHECK: 128 | struct Align32 (virtual base) (empty)
+// CHECK: | [sizeof=128, align=32
+// CHECK: | nvsize=64, nvalign=32]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct C
+// CHECK-X64: 0 | (C vftable pointer)
+// CHECK-X64: 32 | struct VAlign32 (base)
+// CHECK-X64: 32 | (VAlign32 vbtable pointer)
+// CHECK-X64: 40 | int a
+// CHECK-X64: 68 | (vtordisp for vbase B0)
+// CHECK-X64: 72 | struct B0 (virtual base)
+// CHECK-X64: 72 | (B0 vftable pointer)
+// CHECK-X64: 80 | int a
+// CHECK-X64: 108 | (vtordisp for vbase B1)
+// CHECK-X64: 112 | struct B1 (virtual base)
+// CHECK-X64: 112 | (B1 vftable pointer)
+// CHECK-X64: 120 | int a
+// CHECK-X64: 128 | struct Align32 (virtual base) (empty)
+// CHECK-X64: | [sizeof=128, align=32
+// CHECK-X64: | nvsize=64, nvalign=32]
+
+struct __declspec(align(32)) D : virtual B0, virtual B1 {
+ int a;
+ D() : a(0xf000000D) {}
+ virtual void f() { printf("D"); }
+ virtual void g() { printf("D"); }
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct D
+// CHECK: 0 | (D vftable pointer)
+// CHECK: 4 | (D vbtable pointer)
+// CHECK: 8 | int a
+// CHECK: 32 | (vtordisp for vbase B0)
+// CHECK: 36 | struct B0 (virtual base)
+// CHECK: 36 | (B0 vftable pointer)
+// CHECK: 40 | int a
+// CHECK: 76 | (vtordisp for vbase B1)
+// CHECK: 80 | struct B1 (virtual base)
+// CHECK: 80 | (B1 vftable pointer)
+// CHECK: 84 | int a
+// CHECK: | [sizeof=96, align=32
+// CHECK: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct D
+// CHECK-X64: 0 | (D vftable pointer)
+// CHECK-X64: 8 | (D vbtable pointer)
+// CHECK-X64: 16 | int a
+// CHECK-X64: 36 | (vtordisp for vbase B0)
+// CHECK-X64: 40 | struct B0 (virtual base)
+// CHECK-X64: 40 | (B0 vftable pointer)
+// CHECK-X64: 48 | int a
+// CHECK-X64: 76 | (vtordisp for vbase B1)
+// CHECK-X64: 80 | struct B1 (virtual base)
+// CHECK-X64: 80 | (B1 vftable pointer)
+// CHECK-X64: 88 | int a
+// CHECK-X64: | [sizeof=96, align=32
+// CHECK-X64: | nvsize=24, nvalign=8]
+
+struct AT {
+ virtual ~AT(){}
+};
+struct CT : virtual AT {
+ virtual ~CT();
+};
+CT::~CT(){}
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct CT
+// CHECK: 0 | (CT vbtable pointer)
+// CHECK: 4 | struct AT (virtual base)
+// CHECK: 4 | (AT vftable pointer)
+// CHECK: | [sizeof=8, align=4
+// CHECK: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct CT
+// CHECK-X64: 0 | (CT vbtable pointer)
+// CHECK-X64: 8 | struct AT (virtual base)
+// CHECK-X64: 8 | (AT vftable pointer)
+// CHECK-X64: | [sizeof=16, align=8
+// CHECK-X64: | nvsize=8, nvalign=8]
+
+int a[
+sizeof(A)+
+sizeof(C)+
+sizeof(D)+
+sizeof(CT)];
diff --git a/test/Lexer/Inputs/bad-header-guard-defined.h b/test/Lexer/Inputs/bad-header-guard-defined.h
new file mode 100644
index 000000000000..b28f1a8873e9
--- /dev/null
+++ b/test/Lexer/Inputs/bad-header-guard-defined.h
@@ -0,0 +1,4 @@
+#if !defined(foo)
+#define goo
+int n;
+#endif
diff --git a/test/Lexer/Inputs/bad-header-guard.h b/test/Lexer/Inputs/bad-header-guard.h
new file mode 100644
index 000000000000..601da0932721
--- /dev/null
+++ b/test/Lexer/Inputs/bad-header-guard.h
@@ -0,0 +1,4 @@
+#ifndef bad_header_guard
+#define bad_guard
+
+#endif
diff --git a/test/Lexer/Inputs/different-define.h b/test/Lexer/Inputs/different-define.h
new file mode 100644
index 000000000000..f23454b7c8c4
--- /dev/null
+++ b/test/Lexer/Inputs/different-define.h
@@ -0,0 +1,4 @@
+#ifndef different_define
+#define FOO 5
+
+#endif
diff --git a/test/Lexer/Inputs/good-header-guard.h b/test/Lexer/Inputs/good-header-guard.h
new file mode 100644
index 000000000000..664a479d3914
--- /dev/null
+++ b/test/Lexer/Inputs/good-header-guard.h
@@ -0,0 +1,4 @@
+#ifndef good_header_guard
+#define good_header_guard
+
+#endif
diff --git a/test/Lexer/Inputs/multiple.h b/test/Lexer/Inputs/multiple.h
new file mode 100644
index 000000000000..5dfb327a0b2a
--- /dev/null
+++ b/test/Lexer/Inputs/multiple.h
@@ -0,0 +1,4 @@
+#ifndef multiple
+#define multi
+
+#endif
diff --git a/test/Lexer/Inputs/no-define.h b/test/Lexer/Inputs/no-define.h
new file mode 100644
index 000000000000..591a66b30c61
--- /dev/null
+++ b/test/Lexer/Inputs/no-define.h
@@ -0,0 +1,3 @@
+#ifndef no_define
+
+#endif
diff --git a/test/Lexer/Inputs/out-of-order-define.h b/test/Lexer/Inputs/out-of-order-define.h
new file mode 100644
index 000000000000..d38e93f29bb5
--- /dev/null
+++ b/test/Lexer/Inputs/out-of-order-define.h
@@ -0,0 +1,7 @@
+#ifndef out_of_order
+
+#define something_else
+
+#define out_of_order
+
+#endif
diff --git a/test/Lexer/Inputs/tokens-between-ifndef-and-define.h b/test/Lexer/Inputs/tokens-between-ifndef-and-define.h
new file mode 100644
index 000000000000..ce8d77050631
--- /dev/null
+++ b/test/Lexer/Inputs/tokens-between-ifndef-and-define.h
@@ -0,0 +1,7 @@
+#ifndef tokens_between
+
+const int pi = 3;
+
+#define pi_is_bad
+
+#endif
diff --git a/test/Lexer/Inputs/unlikely-to-be-header-guard.h b/test/Lexer/Inputs/unlikely-to-be-header-guard.h
new file mode 100644
index 000000000000..098fc3cb7a1a
--- /dev/null
+++ b/test/Lexer/Inputs/unlikely-to-be-header-guard.h
@@ -0,0 +1,5 @@
+#ifndef data_rep_h
+#define use_alternate_data_rep
+/* #include "data_rep.h" */
+#endif
+
diff --git a/test/Lexer/builtin_redef.c b/test/Lexer/builtin_redef.c
index c9351dc4a696..b0bb2a096be5 100644
--- a/test/Lexer/builtin_redef.c
+++ b/test/Lexer/builtin_redef.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-OUT
// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
-// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR
+// RUN: not %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR
// CHECK-WARN: <command line>:{{.*}} warning: redefining builtin macro
// CHECK-WARN: <command line>:{{.*}} warning: undefining builtin macro
diff --git a/test/Lexer/char-literal.cpp b/test/Lexer/char-literal.cpp
index b2fab34e4407..1cd14a9b0116 100644
--- a/test/Lexer/char-literal.cpp
+++ b/test/Lexer/char-literal.cpp
@@ -36,8 +36,4 @@ char16_t p[2] = u"\U0000FFFF";
char16_t q[2] = u"\U00010000";
#ifdef __cplusplus
// expected-error@-2 {{too long}}
-#else
-// FIXME: The above should be accepted in C11 mode.
-// expected-error@-6 {{must be an initializer list}}
-// expected-error@-6 {{must be an initializer list}}
#endif
diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c
index 290388543c0e..f0cd4d7cf29c 100644
--- a/test/Lexer/constants.c
+++ b/test/Lexer/constants.c
@@ -13,7 +13,12 @@ float Y = 08.123456;
// PR2252
#if -0x8000000000000000 // should not warn.
#endif
-
+#if -01000000000000000000000 // should not warn.
+#endif
+#if 9223372036854775808 // expected-warning {{integer constant is larger than the largest signed integer type}}
+#endif
+#if 0x10000000000000000 // expected-error {{integer constant is larger than the largest unsigned integer type}}
+#endif
int c[] = {
'df', // expected-warning {{multi-character character constant}}
diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp
new file mode 100644
index 000000000000..1202ecb18349
--- /dev/null
+++ b/test/Lexer/cxx-features.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++98 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+// expected-no-diagnostics
+
+#if __cplusplus < 201103L
+#define check(macro, cxx98, cxx11, cxx1y) cxx98 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx98
+#elif __cplusplus < 201304L
+#define check(macro, cxx98, cxx11, cxx1y) cxx11 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx11
+#else
+#define check(macro, cxx98, cxx11, cxx1y) cxx1y == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx1y
+#endif
+
+#if check(binary_literals, 0, 0, 201304)
+#error "wrong value for __cpp_binary_literals"
+#endif
+
+#if check(init_captures, 0, 0, 201304)
+#error "wrong value for __cpp_init_captures"
+#endif
+
+#if check(generic_lambdas, 0, 0, 201304)
+#error "wrong value for __cpp_generic_lambdas"
+#endif
+
+#if check(constexpr, 0, 200704, 201304)
+#error "wrong value for __cpp_constexpr"
+#endif
+
+#if check(decltype_auto, 0, 0, 201304)
+#error "wrong value for __cpp_decltype_auto"
+#endif
+
+#if check(return_type_deduction, 0, 0, 201304)
+#error "wrong value for __cpp_return_type_deduction"
+#endif
+
+#if check(runtime_arrays, 0, 0, 0)
+#error "wrong value for __cpp_runtime_arrays"
+#endif
+
+#if check(aggregate_nsdmi, 0, 0, 201304)
+#error "wrong value for __cpp_aggregate_nsdmi"
+#endif
+
+#if check(variable_templates, 0, 0, 201304)
+#error "wrong value for __cpp_variable_templates"
+#endif
+
+#if check(unicode_characters, 0, 200704, 200704)
+#error "wrong value for __cpp_unicode_characters"
+#endif
+
+#if check(raw_strings, 0, 200710, 200710)
+#error "wrong value for __cpp_raw_strings"
+#endif
+
+#if check(unicode_literals, 0, 200710, 200710)
+#error "wrong value for __cpp_unicode_literals"
+#endif
+
+#if check(user_defined_literals, 0, 200809, 200809)
+#error "wrong value for __cpp_user_defined_literals"
+#endif
+
+#if check(lambdas, 0, 200907, 200907)
+#error "wrong value for __cpp_lambdas"
+#endif
+
+#if check(static_assert, 0, 200410, 200410)
+#error "wrong value for __cpp_static_assert"
+#endif
+
+#if check(decltype, 0, 200707, 200707)
+#error "wrong value for __cpp_decltype"
+#endif
+
+#if check(attributes, 0, 200809, 200809)
+#error "wrong value for __cpp_attributes"
+#endif
+
+#if check(rvalue_references, 0, 200610, 200610)
+#error "wrong value for __cpp_rvalue_references"
+#endif
+
+#if check(variadic_templates, 0, 200704, 200704)
+#error "wrong value for __cpp_variadic_templates"
+#endif
diff --git a/test/Lexer/cxx0x_raw_string_unterminated.cpp b/test/Lexer/cxx0x_raw_string_unterminated.cpp
index dfbaaeee1e72..be134f8cb513 100644
--- a/test/Lexer/cxx0x_raw_string_unterminated.cpp
+++ b/test/Lexer/cxx0x_raw_string_unterminated.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -E %s 2>&1 | grep 'error: raw string missing terminating delimiter )foo"'
+// RUN: not %clang_cc1 -std=c++11 -E %s 2>&1 | grep 'error: raw string missing terminating delimiter )foo"'
const char *str = R"foo(abc
def)bar";
diff --git a/test/Lexer/cxx1y_binary_literal.cpp b/test/Lexer/cxx1y_binary_literal.cpp
index 96dce3dd4439..662e99d28c0b 100644
--- a/test/Lexer/cxx1y_binary_literal.cpp
+++ b/test/Lexer/cxx1y_binary_literal.cpp
@@ -17,3 +17,4 @@ int k1 = 0b1234; // expected-error {{invalid digit '2' in binary constant}}
// we'll need to rework our binary literal parsing rules.
int k2 = 0b10010f; // expected-error {{invalid digit 'f' in binary constant}}
int k3 = 0b10010g; // expected-error {{invalid suffix 'g' on integer constant}}
+int k4 = 0b; // expected-error {{invalid digit 'b' in octal constant}}
diff --git a/test/Lexer/cxx1y_digit_separators.cpp b/test/Lexer/cxx1y_digit_separators.cpp
new file mode 100644
index 000000000000..39ea3e7b8d74
--- /dev/null
+++ b/test/Lexer/cxx1y_digit_separators.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+int operator""ms(unsigned long long); // expected-warning {{reserved}}
+float operator""ms(long double); // expected-warning {{reserved}}
+
+int operator""_foo(unsigned long long);
+
+namespace integral {
+ static_assert(1'2'3 == 12'3, "");
+ static_assert(1'000'000 == 0xf'4240, "");
+ static_assert(0'004'000'000 == 0x10'0000, "");
+ static_assert(0b0101'0100 == 0x54, "");
+
+ int a = 123'; //'; // expected-error {{expected ';'}}
+ int b = 0'xff; // expected-error {{digit separator cannot appear at end of digit sequence}} expected-error {{suffix 'xff' on integer}}
+ int c = 0x'ff; // expected-error {{suffix 'x'ff' on integer}}
+ int d = 0'1234; // ok, octal
+ int e = 0'b1010; // expected-error {{digit 'b' in octal constant}}
+ int f = 0b'1010; // expected-error {{invalid digit 'b' in octal}}
+ int g = 123'ms; // expected-error {{digit separator cannot appear at end of digit sequence}}
+
+ int z = 0'123'_foo; //'; // expected-error {{cannot appear at end of digit seq}}
+}
+
+namespace floating {
+ static_assert(0'123.456'7 == 123.4567, "");
+ static_assert(1e1'0 == 10'000'000'000, "");
+
+ float a = 1'e1; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float b = 1'0e1;
+ float c = 1.'0e1; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float d = 1.0'e1; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float e = 1e'1; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float f = 1e1'ms; // expected-error {{digit separator cannot appear at end of digit sequence}}
+}
+
+#line 123'456
+static_assert(__LINE__ == 123456, "");
+
+// x has value 0 in C++11 and 34 in C++1y.
+#define M(x, ...) __VA_ARGS__
+constexpr int x = { M(1'2,3'4) };
+static_assert(x == 34, "");
diff --git a/test/Lexer/dollar-idents.c b/test/Lexer/dollar-idents.c
index e57ee865886b..a1263b4e572c 100644
--- a/test/Lexer/dollar-idents.c
+++ b/test/Lexer/dollar-idents.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -dump-tokens %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -dump-tokens -x assembler-with-cpp %s 2>&1 | FileCheck %s --check-prefix=ASM
+// RUN: %clang_cc1 -dump-tokens -x assembler-with-cpp %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASM
// PR3808
// CHECK: identifier '$A'
diff --git a/test/Lexer/gnu-flags.c b/test/Lexer/gnu-flags.c
new file mode 100644
index 000000000000..6e47547b009d
--- /dev/null
+++ b/test/Lexer/gnu-flags.c
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL \
+// RUN: -Wgnu-zero-variadic-macro-arguments \
+// RUN: -Wgnu-imaginary-constant -Wgnu-binary-literal -Wgnu-zero-line-directive
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \
+// RUN: -Wno-gnu-zero-variadic-macro-arguments \
+// RUN: -Wno-gnu-imaginary-constant -Wno-gnu-binary-literal -Wno-gnu-zero-line-directive
+// Additional disabled tests:
+// %clang_cc1 -fsyntax-only -verify %s -DZEROARGS -Wgnu-zero-variadic-macro-arguments
+// %clang_cc1 -fsyntax-only -verify %s -DIMAGINARYCONST -Wgnu-imaginary-constant
+// %clang_cc1 -fsyntax-only -verify %s -DBINARYLITERAL -Wgnu-binary-literal
+// %clang_cc1 -fsyntax-only -verify %s -DLINE0 -Wgnu-zero-line-directive
+
+#if NONE
+// expected-no-diagnostics
+#endif
+
+
+#if ALL || ZEROARGS
+// expected-warning@+9 {{must specify at least one argument for '...' parameter of variadic macro}}
+// expected-note@+4 {{macro 'efoo' defined here}}
+// expected-warning@+3 {{token pasting of ',' and __VA_ARGS__ is a GNU extension}}
+#endif
+
+#define efoo(format, args...) foo(format , ##args)
+
+void foo( const char* c )
+{
+ efoo("6");
+}
+
+
+#if ALL || IMAGINARYCONST
+// expected-warning@+3 {{imaginary constants are a GNU extension}}
+#endif
+
+float _Complex c = 1.if;
+
+
+#if ALL || BINARYLITERAL
+// expected-warning@+3 {{binary integer literals are a GNU extension}}
+#endif
+
+int b = 0b0101;
+
+
+// This case is handled differently because lit has a bug whereby #line 0 is reported to be on line 4294967295
+// http://llvm.org/bugs/show_bug.cgi?id=16952
+#if ALL || LINE0
+#line 0 // expected-warning {{#line directive with zero argument is a GNU extension}}
+#else
+#line 0
+#endif
+
+// WARNING: Do not add more tests after the #line 0 line! Add them before the LINE0 test
diff --git a/test/Lexer/has_extension_cxx.cpp b/test/Lexer/has_extension_cxx.cpp
index 68b542fb2975..d3483df94c5a 100644
--- a/test/Lexer/has_extension_cxx.cpp
+++ b/test/Lexer/has_extension_cxx.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 -E %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -E %s -o - | FileCheck %s --check-prefix=CHECK11
// CHECK: c_static_assert
#if __has_extension(c_static_assert)
@@ -40,16 +41,23 @@ int has_reference_qualified_functions();
int has_rvalue_references();
#endif
+// CHECK: has_local_type_template_args
#if __has_extension(cxx_local_type_template_args)
int has_local_type_template_args();
-#else
-int no_local_type_template_args();
#endif
-// CHECK: has_local_type_template_args
-
+// CHECK: has_binary_literals
#if __has_extension(cxx_binary_literals)
int has_binary_literals();
#endif
-// CHECK: has_binary_literals
+// CHECK: has_variable_templates
+#if __has_extension(cxx_variable_templates)
+int has_variable_templates();
+#endif
+
+// CHECK-NOT: has_init_captures
+// CHECK11: has_init_captures
+#if __has_extension(cxx_init_captures)
+int has_init_captures();
+#endif
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index 62a965caacb1..b2fe842bd678 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -346,3 +346,53 @@ int no_aggregate_nsdmi();
// CHECK-1Y: has_aggregate_nsdmi
// CHECK-11: no_aggregate_nsdmi
// CHECK-NO-11: no_aggregate_nsdmi
+
+#if __has_feature(cxx_return_type_deduction)
+int has_return_type_deduction();
+#else
+int no_return_type_deduction();
+#endif
+
+// CHECK-1Y: has_return_type_deduction
+// CHECK-11: no_return_type_deduction
+// CHECK-NO-11: no_return_type_deduction
+
+#if __has_feature(cxx_contextual_conversions)
+int has_contextual_conversions();
+#else
+int no_contextual_conversions();
+#endif
+
+// CHECK-1Y: has_contextual_conversions
+// CHECK-11: no_contextual_conversions
+// CHECK-NO-11: no_contextual_conversions
+
+#if __has_feature(cxx_relaxed_constexpr)
+int has_relaxed_constexpr();
+#else
+int no_relaxed_constexpr();
+#endif
+
+// CHECK-1Y: has_relaxed_constexpr
+// CHECK-11: no_relaxed_constexpr
+// CHECK-NO-11: no_relaxed_constexpr
+
+#if __has_feature(cxx_variable_templates)
+int has_variable_templates();
+#else
+int no_variable_templates();
+#endif
+
+// CHECK-1Y: has_variable_templates
+// CHECK-11: no_variable_templates
+// CHECK-NO-11: no_variable_templates
+
+#if __has_feature(cxx_init_captures)
+int has_init_captures();
+#else
+int no_init_captures();
+#endif
+
+// CHECK-1Y: has_init_captures
+// CHECK-11: no_init_captures
+// CHECK-NO-11: no_init_captures
diff --git a/test/Lexer/header.cpp b/test/Lexer/header.cpp
new file mode 100644
index 000000000000..f02b1e69db43
--- /dev/null
+++ b/test/Lexer/header.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-header-guard %s
+// RUN: %clang_cc1 -fsyntax-only -Wheader-guard %s 2>&1 | FileCheck %s
+
+#include "Inputs/good-header-guard.h"
+#include "Inputs/no-define.h"
+#include "Inputs/different-define.h"
+#include "Inputs/out-of-order-define.h"
+#include "Inputs/tokens-between-ifndef-and-define.h"
+#include "Inputs/unlikely-to-be-header-guard.h"
+
+#include "Inputs/bad-header-guard.h"
+// CHECK: In file included from {{.*}}header.cpp:{{[0-9]*}}:
+// CHECK: {{.*}}bad-header-guard.h:1:9: warning: 'bad_header_guard' is used as a header guard here, followed by #define of a different macro
+// CHECK: {{^}}#ifndef bad_header_guard
+// CHECK: {{^}} ^~~~~~~~~~~~~~~~
+// CHECK: {{.*}}bad-header-guard.h:2:9: note: 'bad_guard' is defined here; did you mean 'bad_header_guard'?
+// CHECK: {{^}}#define bad_guard
+// CHECK: {{^}} ^~~~~~~~~
+// CHECK: {{^}} bad_header_guard
+
+#include "Inputs/bad-header-guard-defined.h"
+// CHECK: In file included from {{.*}}header.cpp:{{[0-9]*}}:
+// CHECK: {{.*}}bad-header-guard-defined.h:1:2: warning: 'foo' is used as a header guard here, followed by #define of a different macro
+// CHECK: {{^}}#if !defined(foo)
+// CHECK: {{^}} ^~
+// CHECK: {{.*}}bad-header-guard-defined.h:2:9: note: 'goo' is defined here; did you mean 'foo'?
+// CHECK: {{^}}#define goo
+// CHECK: {{^}} ^~~
+// CHECK: {{^}} foo
+
+#include "Inputs/multiple.h"
+#include "Inputs/multiple.h"
+#include "Inputs/multiple.h"
+#include "Inputs/multiple.h"
+// CHECK: In file included from {{.*}}header.cpp:{{[0-9]*}}:
+// CHECK: {{.*}}multiple.h:1:9: warning: 'multiple' is used as a header guard here, followed by #define of a different macro
+// CHECK: {{^}}#ifndef multiple
+// CHECK: {{^}} ^~~~~~~~
+// CHECK: {{.*}}multiple.h:2:9: note: 'multi' is defined here; did you mean 'multiple'?
+// CHECK: {{^}}#define multi
+// CHECK: {{^}} ^~~~~
+// CHECK: {{^}} multiple
+
+// CHECK: 3 warnings generated.
diff --git a/test/Lexer/newline-eof-c++11.cpp b/test/Lexer/newline-eof-c++11.cpp
deleted file mode 100644
index eeabe8bb9fc3..000000000000
--- a/test/Lexer/newline-eof-c++11.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wnewline-eof -verify %s
-// expected-no-diagnostics
-
-// The following line isn't terminated, don't fix it.
-void foo() {} \ No newline at end of file
diff --git a/test/Lexer/newline-eof-c++98-compat.cpp b/test/Lexer/newline-eof-c++98-compat.cpp
index 3e5c8e226235..9af0b889537b 100644
--- a/test/Lexer/newline-eof-c++98-compat.cpp
+++ b/test/Lexer/newline-eof-c++98-compat.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wc++98-compat-pedantic -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wc++98-compat-pedantic -Wnewline-eof -std=c++11 -verify %s
// The following line isn't terminated, don't fix it.
void foo() {} // expected-warning{{C++98 requires newline at end of file}} \ No newline at end of file
diff --git a/test/Lexer/newline-eof.c b/test/Lexer/newline-eof.c
index a4a18835cf5f..340d9de8d36a 100644
--- a/test/Lexer/newline-eof.c
+++ b/test/Lexer/newline-eof.c
@@ -1,9 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -Wnewline-eof -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++03 -pedantic -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wnewline-eof %s 2>&1 | FileCheck %s
// rdar://9133072
+// In C++11 mode, this is allowed, so don't warn in pedantic mode.
+// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 -Wnewline-eof -verify %s
+// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 -Werror -pedantic %s
+
// Make sure the diagnostic shows up properly at the end of the last line.
-// CHECK: newline-eof.c:9:63
+// CHECK: newline-eof.c:[[@LINE+3]]:63
// The following line isn't terminated, don't fix it.
void foo() {} // expected-warning{{no newline at end of file}} \ No newline at end of file
diff --git a/test/Lexer/pragma-operators.cpp b/test/Lexer/pragma-operators.cpp
index 6a5a498a151f..7270f1eed203 100644
--- a/test/Lexer/pragma-operators.cpp
+++ b/test/Lexer/pragma-operators.cpp
@@ -35,3 +35,25 @@ B(foo)
// CHECK: #pragma message("\042Hello\042, world!")
// CHECK: 0;
int n = pragma_L pragma_u8 pragma_u pragma_U pragma_R pragma_UR pragma_hello 0;
+
+#pragma warning(disable : 1 2L 3U ; error : 4 5 6 ; suppress : 7 8 9)
+// CHECK: #pragma warning(disable: 1 2 3)
+// CHECK: #line [[@LINE-2]]
+// CHECK: #pragma warning(error: 4 5 6)
+// CHECK: #line [[@LINE-4]]
+// CHECK: #pragma warning(suppress: 7 8 9)
+
+#pragma warning(push)
+#pragma warning(push, 1L)
+#pragma warning(push, 4U)
+#pragma warning(push, 0x1)
+#pragma warning(push, 03)
+#pragma warning(push, 0b10)
+#pragma warning(push, 1i8)
+// CHECK: #pragma warning(push)
+// CHECK: #pragma warning(push, 1)
+// CHECK: #pragma warning(push, 4)
+// CHECK: #pragma warning(push, 1)
+// CHECK: #pragma warning(push, 3)
+// CHECK: #pragma warning(push, 2)
+// CHECK: #pragma warning(push, 1)
diff --git a/test/Lexer/string-literal-errors.cpp b/test/Lexer/string-literal-errors.cpp
index be574c2a557b..d8e29934f367 100644
--- a/test/Lexer/string-literal-errors.cpp
+++ b/test/Lexer/string-literal-errors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
void foo() {
(void)"\q \u123z \x \U \U123 \U12345 \u123 \xyzzy \777 \U"
diff --git a/test/Lexer/wchar-signedness.c b/test/Lexer/wchar-signedness.c
index fea0ecac64f5..b5d4ac8f000c 100644
--- a/test/Lexer/wchar-signedness.c
+++ b/test/Lexer/wchar-signedness.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple x86_64-none-linux-gnu | FileCheck %s --check-prefix=X86
-// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple armv7-none-eabi | FileCheck %s --check-prefix=ARM
+// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple x86_64-none-linux-gnu | FileCheck %s --check-prefix=CHECK-X86
+// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple armv7-none-eabi | FileCheck %s --check-prefix=CHECK-ARM
// CHECK-X86-NOT: #define __WCHAR_UNSIGNED__
// CHECK-X86: #define __WINT_UNSIGNED__ 1
diff --git a/test/Makefile b/test/Makefile
index 4fdafe1481b1..dbfa52177b71 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -45,6 +45,9 @@ lit.site.cfg: FORCE
@$(ECHOPATH) s=@CLANG_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
@$(ECHOPATH) s=@CLANG_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> lit.tmp
@$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
+ @$(ECHOPATH) s=@ENABLE_CLANG_ARCMT@=$(ENABLE_CLANG_ARCMT)=g >> lit.tmp
+ @$(ECHOPATH) s=@ENABLE_CLANG_REWRITER@=$(ENABLE_CLANG_REWRITER)=g >> lit.tmp
+ @$(ECHOPATH) s=@ENABLE_CLANG_STATIC_ANALYZER@=$(ENABLE_CLANG_STATIC_ANALYZER)=g >> lit.tmp
@sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
@-rm -f lit.tmp
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index 3efcd098b370..729be1f24773 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -95,3 +95,19 @@ void *TestVariadicUnsigned1(int) __attribute__((alloc_size(1)));
void *TestVariadicUnsigned2(int, int) __attribute__((alloc_size(1,2)));
// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned2
// CHECK: AllocSizeAttr{{.*}} 0 1
+
+void TestLabel() {
+L: __attribute__((unused)) int i;
+// CHECK: LabelStmt{{.*}}'L'
+// CHECK: VarDecl{{.*}}i 'int'
+// CHECK-NEXT: UnusedAttr{{.*}}
+
+M: __attribute(()) int j;
+// CHECK: LabelStmt {{.*}} 'M'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} j 'int'
+
+N: __attribute(()) ;
+// CHECK: LabelStmt {{.*}} 'N'
+// CHECK-NEXT: NullStmt
+}
diff --git a/test/Misc/ast-dump-color.cpp b/test/Misc/ast-dump-color.cpp
index 0367cc50178f..a41c0bba8cb4 100644
--- a/test/Misc/ast-dump-color.cpp
+++ b/test/Misc/ast-dump-color.cpp
@@ -58,7 +58,7 @@ int TestExpr __attribute__((guarded_by(mu1)));
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]> Text=" Comment"{{$}}
-//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> class[[CYAN]] Mutex[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> class[[CYAN]] Mutex[[RESET]] definition{{$}}
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[BLUE]]LockableAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:22[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:33[[RESET]]> class[[CYAN]] Mutex[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]>[[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}}
@@ -71,11 +71,11 @@ int TestExpr __attribute__((guarded_by(mu1)));
//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:22[[RESET]]> Text=" Another variable"{{$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:23:6[[RESET]], [[Yellow]]col:44[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:44[[RESET]]> Text=" Like the other variable, but different"{{$}}
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (void)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (void)'[[RESET]] inline{{.*$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>{{$}}
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (const class Mutex &)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (const class Mutex &)'[[RESET]] inline{{ .*$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Green]]'const class Mutex &'[[RESET]]{{$}}
-//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (class Mutex &&)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (class Mutex &&)'[[RESET]] inline{{ .*$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Green]]'class Mutex &&'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]line:25:3[[RESET]]>[[CYAN]] mu1[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp
index 31715cd15e4c..d98bdb56d5bd 100644
--- a/test/Misc/ast-dump-decl.cpp
+++ b/test/Misc/ast-dump-decl.cpp
@@ -458,3 +458,19 @@ namespace TestFriendDecl2 {
// CHECK: |-CXXRecordDecl {{.*}} struct S
// CHECK: `-FriendDecl
// CHECK: `-FunctionDecl {{.*}} parent [[TestFriendDecl2]] prev [[TestFriendDecl2_f]] <{{.*}}> f 'void (void)'
+
+namespace Comment {
+ extern int Test;
+ /// Something here.
+ extern int Test;
+ extern int Test;
+}
+
+// CHECK: VarDecl {{.*}} Test 'int' extern
+// CHECK-NOT: FullComment
+// CHECK: VarDecl {{.*}} Test 'int' extern
+// CHECK: `-FullComment
+// CHECK: `-ParagraphComment
+// CHECK: `-TextComment
+// CHECK: VarDecl {{.*}} Test 'int' extern
+// CHECK-NOT: FullComment
diff --git a/test/Misc/ast-dump-stmt.cpp b/test/Misc/ast-dump-stmt.cpp
index cf3e8bf28981..72205c130e08 100644
--- a/test/Misc/ast-dump-stmt.cpp
+++ b/test/Misc/ast-dump-stmt.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -fcxx-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
namespace n {
void function() {}
@@ -12,3 +12,29 @@ void TestFunction() {
Variable = 4;
// CHECK: DeclRefExpr{{.*}} (UsingShadow{{.*}}Variable
}
+
+// CHECK: FunctionDecl {{.*}} TestCatch1
+void TestCatch1() {
+// CHECK: CXXTryStmt
+// CHECK-NEXT: CompoundStmt
+ try {
+ }
+// CHECK-NEXT: CXXCatchStmt
+// CHECK-NEXT: VarDecl {{.*}} x
+// CHECK-NEXT: CompoundStmt
+ catch (int x) {
+ }
+}
+
+// CHECK: FunctionDecl {{.*}} TestCatch2
+void TestCatch2() {
+// CHECK: CXXTryStmt
+// CHECK-NEXT: CompoundStmt
+ try {
+ }
+// CHECK-NEXT: CXXCatchStmt
+// CHECK-NEXT: NULL
+// CHECK-NEXT: CompoundStmt
+ catch (...) {
+ }
+}
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
index 7e28da95a1f2..b7aeca8d55df 100644
--- a/test/Misc/ast-dump-templates.cpp
+++ b/test/Misc/ast-dump-templates.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -ast-print %s > %t
// RUN: FileCheck < %t %s -check-prefix=CHECK1
// RUN: FileCheck < %t %s -check-prefix=CHECK2
+// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefix=DUMP %s
template <int X, typename Y, int Z = 5>
struct foo {
@@ -37,3 +38,14 @@ void baz() {
// Template definition - bar
// CHECK1: template <int A, typename B> B bar()
// CHECK2: template <int A, typename B> B bar()
+
+namespace test2 {
+void func(int);
+void func(float);
+template<typename T>
+void tmpl() {
+ func(T());
+}
+
+// DUMP: UnresolvedLookupExpr {{.*}} <col:3> '<overloaded function type>' lvalue (ADL) = 'func'
+}
diff --git a/test/Misc/caret-diags-scratch-buffer.c b/test/Misc/caret-diags-scratch-buffer.c
index 883c68e81dce..e53e0b4277f3 100644
--- a/test/Misc/caret-diags-scratch-buffer.c
+++ b/test/Misc/caret-diags-scratch-buffer.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | not grep keyXXXX
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | not grep keyXXXX
// This should not show keyXXXX in the caret diag output. This once
// happened because the two tokens ended up in the scratch buffer and
// the caret diag from the scratch buffer included the previous token.
diff --git a/test/Misc/dev-fd-fs.c b/test/Misc/dev-fd-fs.c
index 2bc4f291a216..d1f13286aa8e 100644
--- a/test/Misc/dev-fd-fs.c
+++ b/test/Misc/dev-fd-fs.c
@@ -1,9 +1,6 @@
// Check that we can operate on files from /dev/fd.
// REQUIRES: dev-fd-fs
-// It has not been working since r169831 on freebsd.
-// XFAIL: freebsd
-
// Check reading from named pipes. We cat the input here instead of redirecting
// it to ensure that /dev/fd/0 is a named pipe, not just a redirected file.
//
diff --git a/test/Misc/diag-format.c b/test/Misc/diag-format.c
index 959177b2bd42..3dc351d4290c 100644
--- a/test/Misc/diag-format.c
+++ b/test/Misc/diag-format.c
@@ -12,7 +12,7 @@
//
// RUN: %clang -fsyntax-only -fno-show-column %s 2>&1 | FileCheck %s -check-prefix=NO_COLUMN
//
-
+// RUN: not %clang -fsyntax-only -Werror -fdiagnostics-format=msvc-fallback %s 2>&1 | FileCheck %s -check-prefix=MSVC-FALLBACK
@@ -31,4 +31,5 @@
// VI: {{.*}} +28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
// MSVC_ORIG: {{.*}}(28) : warning: extra tokens at end of #endif directive [-Wextra-tokens]
// NO_COLUMN: {{.*}}:28: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+// MSVC-FALLBACK: {{.*}}(28,7) : error(clang): extra tokens at end of #endif directive
int x;
diff --git a/test/Misc/diag-line-wrapping.cpp b/test/Misc/diag-line-wrapping.cpp
index ea119afc642d..2bcb03f9781c 100644
--- a/test/Misc/diag-line-wrapping.cpp
+++ b/test/Misc/diag-line-wrapping.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fmessage-length 60 %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only -fmessage-length 0 %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fmessage-length 60 %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fmessage-length 0 %s 2>&1 | FileCheck %s
struct B { void f(); };
struct D1 : B {};
diff --git a/test/Misc/diag-macro-backtrace.c b/test/Misc/diag-macro-backtrace.c
index 0d28d7b9114c..8d7d5726ad82 100644
--- a/test/Misc/diag-macro-backtrace.c
+++ b/test/Misc/diag-macro-backtrace.c
@@ -1,4 +1,4 @@
-// RUN: %clang -fsyntax-only -fmacro-backtrace-limit=0 %s 2>&1 | FileCheck %s
+// RUN: not %clang -fsyntax-only -fmacro-backtrace-limit=0 %s 2>&1 | FileCheck %s
#define FOO 1+"hi"
#define BAR FOO
diff --git a/test/Misc/diag-mapping.c b/test/Misc/diag-mapping.c
index 75b49ef17c98..edc137ec68fe 100644
--- a/test/Misc/diag-mapping.c
+++ b/test/Misc/diag-mapping.c
@@ -4,10 +4,10 @@
// RUN: %clang_cc1 %s -Wno-extra-tokens 2>&1 | not grep diagnostic
// -Werror can map all warnings to error.
-// RUN: %clang_cc1 %s -Werror 2>&1 | grep "error:"
+// RUN: not %clang_cc1 %s -Werror 2>&1 | grep "error:"
// -Werror can map this one warning to error.
-// RUN: %clang_cc1 %s -Werror=extra-tokens 2>&1 | grep "error:"
+// RUN: not %clang_cc1 %s -Werror=extra-tokens 2>&1 | grep "error:"
// Mapping unrelated diags to errors doesn't affect this one.
// RUN: %clang_cc1 %s -Werror=trigraphs 2>&1 | grep "warning:"
@@ -16,7 +16,7 @@
// RUN: %clang_cc1 %s -pedantic 2>&1 | grep "warning:"
// This should emit an error with -pedantic-errors.
-// RUN: %clang_cc1 %s -pedantic-errors 2>&1 | grep "error:"
+// RUN: not %clang_cc1 %s -pedantic-errors 2>&1 | grep "error:"
// This should emit a warning, because -Wfoo overrides -pedantic*.
// RUN: %clang_cc1 %s -pedantic-errors -Wextra-tokens 2>&1 | grep "warning:"
diff --git a/test/Misc/diag-mapping2.c b/test/Misc/diag-mapping2.c
index bc5a0872e7c8..c4ade074cb05 100644
--- a/test/Misc/diag-mapping2.c
+++ b/test/Misc/diag-mapping2.c
@@ -6,10 +6,10 @@
// RUN: %clang_cc1 %s -Wno-#warnings 2>&1 | not grep diagnostic
// -Werror can map all warnings to error.
-// RUN: %clang_cc1 %s -Werror 2>&1 | grep "error:"
+// RUN: not %clang_cc1 %s -Werror 2>&1 | grep "error:"
// -Werror can map this one warning to error.
-// RUN: %clang_cc1 %s -Werror=#warnings 2>&1 | grep "error:"
+// RUN: not %clang_cc1 %s -Werror=#warnings 2>&1 | grep "error:"
// -Wno-error= overrides -Werror. rdar://3158301
// RUN: %clang_cc1 %s -Werror -Wno-error=#warnings 2>&1 | grep "warning:"
diff --git a/test/Misc/diag-presumed.c b/test/Misc/diag-presumed.c
index 07b7cdfe351f..70f2f24e321c 100644
--- a/test/Misc/diag-presumed.c
+++ b/test/Misc/diag-presumed.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic-errors %s 2>&1 | FileCheck %s --check-prefix=PRESUMED
-// RUN: %clang_cc1 -fsyntax-only -pedantic-errors -fno-diagnostics-use-presumed-location %s 2>&1 | FileCheck %s --check-prefix=SPELLING
+// RUN: not %clang_cc1 -fsyntax-only -pedantic-errors %s 2>&1 | FileCheck %s --check-prefix=PRESUMED
+// RUN: not %clang_cc1 -fsyntax-only -pedantic-errors -fno-diagnostics-use-presumed-location %s 2>&1 | FileCheck %s --check-prefix=SPELLING
#line 100
#define X(y) y
diff --git a/test/Misc/diag-template-diffing-color.cpp b/test/Misc/diag-template-diffing-color.cpp
index c771857f3907..e73fc2c3973a 100644
--- a/test/Misc/diag-template-diffing-color.cpp
+++ b/test/Misc/diag-template-diffing-color.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fcolor-diagnostics %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
+// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
// REQUIRES: ansi-escape-sequences
template<typename> struct foo {};
void func(foo<int>);
diff --git a/test/Misc/diag-template-diffing-cxx98.cpp b/test/Misc/diag-template-diffing-cxx98.cpp
index a21e4cf060d9..9fa46127920c 100644
--- a/test/Misc/diag-template-diffing-cxx98.cpp
+++ b/test/Misc/diag-template-diffing-cxx98.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -std=c++98 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only %s -std=c++98 2>&1 | FileCheck %s
namespace PR14342 {
template<typename T, char a> struct X {};
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index add96efd37b6..46807070c7cc 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-NOTREE
-// RUN: %clang_cc1 -fsyntax-only %s -fno-elide-type -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-NOTREE
-// RUN: %clang_cc1 -fsyntax-only %s -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-TREE
-// RUN: %clang_cc1 -fsyntax-only %s -fno-elide-type -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-TREE
+// RUN: not %clang_cc1 -fsyntax-only %s -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-NOTREE
+// RUN: not %clang_cc1 -fsyntax-only %s -fno-elide-type -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-NOTREE
+// RUN: not %clang_cc1 -fsyntax-only %s -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-ELIDE-TREE
+// RUN: not %clang_cc1 -fsyntax-only %s -fno-elide-type -fdiagnostics-show-template-tree -std=c++11 2>&1 | FileCheck %s -check-prefix=CHECK-NOELIDE-TREE
// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"
// vector<string> refers to two different types here. Make sure the message
@@ -935,10 +935,10 @@ namespace DependentDefault {
B<int, char> b3;
b1 = b2;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
- // CHECK-ELIDE-NOTREE: no known conversion from 'B<char, (default) Trait<T>::Ty>' to 'B<int, int>'
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<char, [...]>' to 'B<int, [...]>'
b3 = b1;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
- // CHECK-ELIDE-NOTREE: no known conversion from 'B<[...], (default) Trait<T>::Ty>' to 'B<[...], char>'
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<[...], (default) int>' to 'B<[...], char>'
b2 = b3;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
// CHECK-ELIDE-NOTREE: no known conversion from 'B<int, char>' to 'B<char, int>'
@@ -1002,8 +1002,73 @@ namespace VariadicDefault {
}
}
+namespace PointerArguments {
+ template <int *p> class T {};
+ template <int* ...> class U {};
+ int a, b, c;
+ int z[5];
+ void test() {
+ T<&a> ta;
+ T<z> tz;
+ T<&b> tb(ta);
+ // CHECK-ELIDE-NOTREE: no matching constructor for initialization of 'T<&b>'
+ // CHECK-ELIDE-NOTREE: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'T<&a>' to 'const T<&b>' for 1st argument
+ T<&c> tc(tz);
+ // CHECK-ELIDE-NOTREE: no matching constructor for initialization of 'T<&c>'
+ // CHECK-ELIDE-NOTREE: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'T<z>' to 'const T<&c>' for 1st argument
+
+ U<&a, &a> uaa;
+ U<&b> ub(uaa);
+ // CHECK-ELIDE-NOTREE: no matching constructor for initialization of 'U<&b>'
+ // CHECK-ELIDE-NOTREE: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'U<&a, &a>' to 'const U<&b, (no argument)>' for 1st argument
+
+ U<&b, &b, &b> ubbb(uaa);
+ // CHECK-ELIDE-NOTREE: no matching constructor for initialization of 'U<&b, &b, &b>'
+ // CHECK-ELIDE-NOTREE: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'U<&a, &a, (no argument)>' to 'const U<&b, &b, &b>' for 1st argument
+
+ }
+}
+
+namespace DependentInt {
+ template<int Num> struct INT;
+
+ template <class CLASS, class Int_wrapper = INT<CLASS::val> >
+ struct C;
+
+ struct N {
+ static const int val = 1;
+ };
+
+ template <class M_T>
+ struct M {};
+
+ void test() {
+ using T1 = M<C<int, INT<0>>>;
+ using T2 = M<C<N>>;
+ T2 p;
+ T1 x = p;
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'M<C<struct DependentInt::N, INT<1>>>' to 'M<C<int, INT<0>>>'
+ }
+}
+
+namespace PR17510 {
+class Atom;
+
+template <typename T> class allocator;
+template <typename T, typename A> class vector;
+
+typedef vector<const Atom *, allocator<const Atom *> > AtomVector;
+
+template <typename T, typename A = allocator<const Atom *> > class vector {};
+
+void foo() {
+ vector<Atom *> v;
+ AtomVector v2(v);
+ // CHECK-ELIDE-NOTREE: no known conversion from 'vector<class PR17510::Atom *, [...]>' to 'const vector<const class PR17510::Atom *, [...]>'
+}
+}
+
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-TREE: {{[0-9]*}} errors generated.
-
diff --git a/test/Misc/diag-trailing-null-bytes.cpp b/test/Misc/diag-trailing-null-bytes.cpp
index 91b159ca257d..2786f50e65e1 100644
--- a/test/Misc/diag-trailing-null-bytes.cpp
+++ b/test/Misc/diag-trailing-null-bytes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
// CHECK: {{ERR_DNS_SERVER_REQUIRES_TCP$}}
// http://llvm.org/PR12674
diff --git a/test/Misc/diag-verify.cpp b/test/Misc/diag-verify.cpp
index 895bc3fe0303..397558c0574d 100644
--- a/test/Misc/diag-verify.cpp
+++ b/test/Misc/diag-verify.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -verify %s 2>&1 | FileCheck %s
// Test the -verify flag. Each of the "x = y;" lines will produce a
// "use of undeclared identifier 'y'" error message.
diff --git a/test/Misc/error-limit-multiple-notes.cpp b/test/Misc/error-limit-multiple-notes.cpp
index 019b4dde2633..71a39091f60c 100644
--- a/test/Misc/error-limit-multiple-notes.cpp
+++ b/test/Misc/error-limit-multiple-notes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
// error and three notes emitted
void foo(int);
diff --git a/test/Misc/error-limit.c b/test/Misc/error-limit.c
index 26f4ac1d8a5e..e4ce7aab42e8 100644
--- a/test/Misc/error-limit.c
+++ b/test/Misc/error-limit.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
// error and note emitted
struct s1{};
diff --git a/test/Misc/include-stack-for-note-flag.cpp b/test/Misc/include-stack-for-note-flag.cpp
index b41284fd607e..f9bceee968d7 100644
--- a/test/Misc/include-stack-for-note-flag.cpp
+++ b/test/Misc/include-stack-for-note-flag.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
-// RUN: %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
-// RUN: %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
+// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
#include "Inputs/include.h"
int test() {
diff --git a/test/Misc/languageOptsOpenCL.cl b/test/Misc/languageOptsOpenCL.cl
new file mode 100644
index 000000000000..c81db995808f
--- /dev/null
+++ b/test/Misc/languageOptsOpenCL.cl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -x cl %s -verify
+// expected-no-diagnostics
+
+// Test the forced language options for OpenCL are set correctly.
+
+__constant int v0[(sizeof(int) == 4) -1];
+__constant int v1[(__alignof(int) == 4) -1];
+__constant int v2[(sizeof(long) == 8) -1];
+__constant int v3[(__alignof(long) == 8) -1];
+__constant int v4[(sizeof(long long) == 16) -1];
+__constant int v5[(__alignof(long long) == 16) -1];
+__constant int v6[(sizeof(float) == 4) -1];
+__constant int v7[(__alignof(float) == 4) -1];
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+__constant int v8[(sizeof(double)==8) -1];
+__constant int v9[(__alignof(double)==8) -1];
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+__constant int v10[(sizeof(half) == 2) -1];
+__constant int v11[(__alignof(half) == 2) -1];
diff --git a/test/Misc/permissions.cpp b/test/Misc/permissions.cpp
new file mode 100644
index 000000000000..143e49d58eac
--- /dev/null
+++ b/test/Misc/permissions.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: shell
+
+// MSYS doesn't emulate umask.
+// FIXME: Could we introduce another feature for it?
+// REQUIRES: shell-preserves-root
+
+// RUN: umask 000
+// RUN: %clang_cc1 -emit-llvm-bc %s -o %t
+// RUN: ls -l %t | FileCheck --check-prefix=CHECK000 %s
+// CHECK000: rw-rw-rw-
+
+// RUN: umask 002
+// RUN: %clang_cc1 -emit-llvm-bc %s -o %t
+// RUN: ls -l %t | FileCheck --check-prefix=CHECK002 %s
+// CHECK002: rw-rw-r--
diff --git a/test/Misc/show-diag-options.c b/test/Misc/show-diag-options.c
index ef0a5a660da4..8f05fbc76b56 100644
--- a/test/Misc/show-diag-options.c
+++ b/test/Misc/show-diag-options.c
@@ -2,7 +2,7 @@
// RUN: | FileCheck %s -check-prefix=BASE
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=OPTION
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -Werror %s 2>&1 \
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-option -Werror %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=OPTION_ERROR
// RUN: %clang_cc1 -fsyntax-only -std=c89 -pedantic -fdiagnostics-show-option %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=OPTION_PEDANTIC
@@ -10,7 +10,7 @@
// RUN: | FileCheck %s -check-prefix=CATEGORY_ID
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-category name %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=CATEGORY_NAME
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -fdiagnostics-show-category name -Werror %s 2>&1 \
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-option -fdiagnostics-show-category name -Werror %s 2>&1 \
// RUN: | FileCheck %s -check-prefix=OPTION_ERROR_CATEGORY
void test(int x, int y) {
diff --git a/test/Misc/tabstop.c b/test/Misc/tabstop.c
index 7f59b6ab32b1..cb6af0cec8a1 100644
--- a/test/Misc/tabstop.c
+++ b/test/Misc/tabstop.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -ftabstop 3 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=3 -strict-whitespace %s
-// RUN: %clang_cc1 -ftabstop 4 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=4 -strict-whitespace %s
-// RUN: %clang_cc1 -ftabstop 5 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=5 -strict-whitespace %s
+// RUN: %clang_cc1 -ftabstop 3 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-3 -strict-whitespace %s
+// RUN: %clang_cc1 -ftabstop 4 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-4 -strict-whitespace %s
+// RUN: %clang_cc1 -ftabstop 5 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-5 -strict-whitespace %s
// tab
void* a = 1;
diff --git a/test/Misc/unprintable.c b/test/Misc/unprintable.c
index cd97131c8d1a..eaa4f34d8028 100644
--- a/test/Misc/unprintable.c
+++ b/test/Misc/unprintable.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fmessage-length 40 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 %s -fmessage-length 40 2>&1 | FileCheck -strict-whitespace %s
int main() {
int i;
diff --git a/test/Misc/warning-flags-tree.c b/test/Misc/warning-flags-tree.c
index a64e942f20bd..d71c9f618b42 100644
--- a/test/Misc/warning-flags-tree.c
+++ b/test/Misc/warning-flags-tree.c
@@ -36,11 +36,8 @@
// CHECK-GNU: ext_gnu_array_range
// CHECK-GNU: ext_gnu_missing_equal_designator
// CHECK-GNU: ext_gnu_old_style_field_designator
-// CHECK-GNU: -Wvla
+// CHECK-GNU: -Wvla-extension
// CHECK-GNU: ext_vla
-// CHECK-GNU: ext_array_init_copy
-// CHECK-GNU: ext_empty_struct_union
-// CHECK-GNU: ext_expr_not_ice
// 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
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index a6dc8f1352fd..e61225ad20a5 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -5,22 +5,21 @@ 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.
-
+
(2) It prevents us adding new warnings to Clang that have no -W flag. All
new warnings should have -W flags.
-
+
If you add a new warning without a flag, this test will fail. To fix
this test, simply add a warning group to that warning.
-
+
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (143):
+CHECK: Warnings without flags (134):
CHECK-NEXT: ext_delete_void_ptr_operand
-CHECK-NEXT: ext_enum_friend
CHECK-NEXT: ext_expected_semi_decl_list
CHECK-NEXT: ext_explicit_specialization_storage_class
CHECK-NEXT: ext_implicit_lib_function_decl
@@ -81,13 +80,11 @@ CHECK-NEXT: warn_fe_cc_log_diagnostics_failure
CHECK-NEXT: warn_fe_cc_print_header_failure
CHECK-NEXT: warn_fe_macro_contains_embedded_newline
CHECK-NEXT: warn_file_asm_volatile
-CHECK-NEXT: warn_hex_escape_too_large
CHECK-NEXT: warn_ignoring_ftabstop_value
CHECK-NEXT: warn_implements_nscopying
CHECK-NEXT: warn_incompatible_qualified_id
CHECK-NEXT: warn_initializer_string_for_char_array_too_long
CHECK-NEXT: warn_inline_namespace_reopened_noninline
-CHECK-NEXT: warn_integer_too_large
CHECK-NEXT: warn_integer_too_large_for_signed
CHECK-NEXT: warn_invalid_asm_cast_lvalue
CHECK-NEXT: warn_many_braces_around_scalar_init
@@ -104,7 +101,6 @@ CHECK-NEXT: warn_nonnull_pointers_only
CHECK-NEXT: warn_not_compound_assign
CHECK-NEXT: warn_objc_property_copy_missing_on_block
CHECK-NEXT: warn_objc_protocol_qualifier_missing_id
-CHECK-NEXT: warn_octal_escape_too_large
CHECK-NEXT: warn_on_superclass_use
CHECK-NEXT: warn_param_default_argument_redefinition
CHECK-NEXT: warn_partial_specs_not_deducible
@@ -136,7 +132,6 @@ CHECK-NEXT: warn_pragma_unused_expected_punc
CHECK-NEXT: warn_pragma_unused_expected_var
CHECK-NEXT: warn_pragma_unused_expected_var_arg
CHECK-NEXT: warn_pragma_unused_undeclared_var
-CHECK-NEXT: warn_previous_alias_decl
CHECK-NEXT: warn_property_attr_mismatch
CHECK-NEXT: warn_property_attribute
CHECK-NEXT: warn_property_getter_owning_mismatch
@@ -146,9 +141,6 @@ CHECK-NEXT: warn_redeclaration_without_attribute_prev_attribute_ignored
CHECK-NEXT: warn_register_objc_catch_parm
CHECK-NEXT: warn_related_result_type_compatibility_class
CHECK-NEXT: warn_related_result_type_compatibility_protocol
-CHECK-NEXT: warn_second_parameter_of_va_start_not_last_named_argument
-CHECK-NEXT: warn_second_parameter_to_va_arg_never_compatible
-CHECK-NEXT: warn_static_inline_explicit_inst_ignored
CHECK-NEXT: warn_static_non_static
CHECK-NEXT: warn_template_export_unsupported
CHECK-NEXT: warn_template_spec_extra_headers
@@ -158,11 +150,10 @@ CHECK-NEXT: warn_unavailable_fwdclass_message
CHECK-NEXT: warn_undef_interface
CHECK-NEXT: warn_undef_interface_suggest
CHECK-NEXT: warn_undef_protocolref
-CHECK-NEXT: warn_unknown_method_family
CHECK-NEXT: warn_use_out_of_scope_declaration
CHECK-NEXT: warn_weak_identifier_undeclared
CHECK-NEXT: warn_weak_import
The list of warnings in -Wpedantic should NEVER grow.
-CHECK: Number in -Wpedantic (not covered by other -W flags): 29
+CHECK: Number in -Wpedantic (not covered by other -W flags): 28
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/not_cxx.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_cxx.h
new file mode 100644
index 000000000000..c29a9219c64c
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_cxx.h
@@ -0,0 +1 @@
+extern int template;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/not_objc.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_objc.h
new file mode 100644
index 000000000000..f63975a25d16
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_objc.h
@@ -0,0 +1 @@
+int NSObject;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/module.map b/test/Modules/Inputs/DependsOnModule.framework/module.map
index 2a3dd8038bd1..5a1cacaad2a3 100644
--- a/test/Modules/Inputs/DependsOnModule.framework/module.map
+++ b/test/Modules/Inputs/DependsOnModule.framework/module.map
@@ -8,6 +8,14 @@ framework module DependsOnModule {
requires cplusplus
header "cxx_other.h"
}
+ explicit module NotCXX {
+ requires !cplusplus
+ header "not_cxx.h"
+ }
+ explicit module NotObjC {
+ requires !objc
+ header "not_objc.h"
+ }
explicit framework module SubFramework {
umbrella header "SubFramework.h"
diff --git a/test/Modules/Inputs/MethodPoolBSub.h b/test/Modules/Inputs/MethodPoolBSub.h
index 0a7899df81b7..fbfc0aa14392 100644
--- a/test/Modules/Inputs/MethodPoolBSub.h
+++ b/test/Modules/Inputs/MethodPoolBSub.h
@@ -1,4 +1,5 @@
@interface B (Sub)
- (char *)method3;
- (char*)method4;
+- (id)method6;
@end
diff --git a/test/Modules/Inputs/MethodPoolBSub2.h b/test/Modules/Inputs/MethodPoolBSub2.h
new file mode 100644
index 000000000000..8bc369f73e85
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolBSub2.h
@@ -0,0 +1,3 @@
+@interface TotallyUnrelated
+- (id)method6;
+@end
diff --git a/test/Modules/Inputs/System/usr/include/stdio.h b/test/Modules/Inputs/System/usr/include/stdio.h
index 9a7b1063032c..f41e09c35a41 100644
--- a/test/Modules/Inputs/System/usr/include/stdio.h
+++ b/test/Modules/Inputs/System/usr/include/stdio.h
@@ -1,3 +1,3 @@
typedef struct { int id; } FILE;
int fprintf(FILE*restrict, const char* restrict format, ...);
-
+extern FILE *__stderrp;
diff --git a/test/Modules/Inputs/cxx-decls-imported.h b/test/Modules/Inputs/cxx-decls-imported.h
new file mode 100644
index 000000000000..b94368614dfb
--- /dev/null
+++ b/test/Modules/Inputs/cxx-decls-imported.h
@@ -0,0 +1,5 @@
+class HasFriends {
+ friend void friend_1(HasFriends);
+ friend void friend_2(HasFriends);
+ void private_thing();
+};
diff --git a/test/Modules/Inputs/cxx-decls-unimported.h b/test/Modules/Inputs/cxx-decls-unimported.h
new file mode 100644
index 000000000000..0431e324616e
--- /dev/null
+++ b/test/Modules/Inputs/cxx-decls-unimported.h
@@ -0,0 +1 @@
+void operator delete(void*);
diff --git a/test/Modules/Inputs/cxx-templates-a.h b/test/Modules/Inputs/cxx-templates-a.h
new file mode 100644
index 000000000000..0b1614d3d9e6
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-a.h
@@ -0,0 +1,50 @@
+@import cxx_templates_common;
+
+template<typename T> T f() { return T(); }
+template<typename T> T f(T);
+namespace N {
+ template<typename T> T f() { return T(); }
+ template<typename T> T f(T);
+}
+
+template<int N> int template_param_kinds_1();
+template<template<typename T, int, int> class> int template_param_kinds_2();
+template<template<typename T, typename U, T> class> int template_param_kinds_3();
+
+template<typename T> struct SomeTemplate<T*>;
+template<typename T> struct SomeTemplate<T*> {};
+typedef SomeTemplate<int*> SomeTemplateIntPtr;
+
+template<typename T> void PerformDelayedLookup(T &t) {
+ t.f();
+ typename T::Inner inner;
+ FoundByADL(t);
+}
+
+template<typename T> void PerformDelayedLookupInDefaultArgument(T &t, int a = (FoundByADL(T()), 0)) {}
+
+template<typename T> struct RedeclaredAsFriend {};
+
+void use_some_template_a() {
+ SomeTemplate<char[2]> a;
+ SomeTemplate<char[1]> b, c;
+ b = c;
+}
+
+template<int> struct MergeTemplates;
+MergeTemplates<0> *merge_templates_a;
+
+auto enum_a_from_a = CommonTemplate<int>::a;
+const auto enum_c_from_a = CommonTemplate<int>::c;
+
+template<int> struct UseInt;
+template<typename T> void UseRedeclaredEnum(UseInt<T() + CommonTemplate<char>::a>);
+constexpr void (*UseRedeclaredEnumA)(UseInt<1>) = UseRedeclaredEnum<int>;
+
+template<typename> struct MergeSpecializations;
+template<typename T> struct MergeSpecializations<T*> {
+ typedef int partially_specialized_in_a;
+};
+template<> struct MergeSpecializations<char> {
+ typedef int explicitly_specialized_in_a;
+};
diff --git a/test/Modules/Inputs/cxx-templates-b-impl.h b/test/Modules/Inputs/cxx-templates-b-impl.h
new file mode 100644
index 000000000000..fdf4a4fbc4d4
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-b-impl.h
@@ -0,0 +1,5 @@
+struct DefinedInBImpl {
+ void f();
+ struct Inner {};
+ friend void FoundByADL(DefinedInBImpl);
+};
diff --git a/test/Modules/Inputs/cxx-templates-b.h b/test/Modules/Inputs/cxx-templates-b.h
new file mode 100644
index 000000000000..6cd83faf1a1b
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-b.h
@@ -0,0 +1,69 @@
+@import cxx_templates_common;
+
+template<typename T> T f();
+template<typename T> T f(T t) { return t; }
+namespace N {
+ template<typename T> T f();
+ template<typename T> T f(T t) { return t; }
+}
+
+template<typename> int template_param_kinds_1();
+template<template<typename, int, int...> class> int template_param_kinds_2();
+template<template<typename T, typename U, U> class> int template_param_kinds_3();
+
+template<typename T> struct SomeTemplate<T&> {};
+template<typename T> struct SomeTemplate<T&>;
+typedef SomeTemplate<int&> SomeTemplateIntRef;
+
+extern DefinedInCommon &defined_in_common;
+
+template<int> struct MergeTemplates;
+MergeTemplates<0> *merge_templates_b;
+
+@import cxx_templates_b_impl;
+
+template<typename T, typename> struct Identity { typedef T type; };
+template<typename T> void UseDefinedInBImpl() {
+ typename Identity<DefinedInBImpl, T>::type dependent;
+ FoundByADL(dependent);
+ typename Identity<DefinedInBImpl, T>::type::Inner inner;
+ dependent.f();
+}
+
+extern DefinedInBImpl &defined_in_b_impl;
+
+template<typename T>
+struct RedeclareTemplateAsFriend {
+ template<typename U>
+ friend struct RedeclaredAsFriend;
+};
+
+void use_some_template_b() {
+ SomeTemplate<char[1]> a;
+ SomeTemplate<char[2]> b, c;
+ b = c;
+}
+
+auto enum_b_from_b = CommonTemplate<int>::b;
+const auto enum_c_from_b = CommonTemplate<int>::c;
+
+template<int> struct UseInt;
+template<typename T> void UseRedeclaredEnum(UseInt<T() + CommonTemplate<char>::a>);
+constexpr void (*UseRedeclaredEnumB)(UseInt<1>) = UseRedeclaredEnum<int>;
+
+template<typename> struct MergeSpecializations;
+template<typename T> struct MergeSpecializations<T&> {
+ typedef int partially_specialized_in_b;
+};
+template<> struct MergeSpecializations<double> {
+ typedef int explicitly_specialized_in_b;
+};
+
+@import cxx_templates_a;
+template<typename T> void UseDefinedInBImplIndirectly(T &v) {
+ PerformDelayedLookup(v);
+}
+
+void TriggerInstantiation() {
+ UseDefinedInBImpl<void>();
+}
diff --git a/test/Modules/Inputs/cxx-templates-c.h b/test/Modules/Inputs/cxx-templates-c.h
new file mode 100644
index 000000000000..4c0fc8a4a825
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-c.h
@@ -0,0 +1,7 @@
+template<typename> struct MergeSpecializations;
+template<typename T> struct MergeSpecializations<T[]> {
+ typedef int partially_specialized_in_c;
+};
+template<> struct MergeSpecializations<bool> {
+ typedef int explicitly_specialized_in_c;
+};
diff --git a/test/Modules/Inputs/cxx-templates-common.h b/test/Modules/Inputs/cxx-templates-common.h
new file mode 100644
index 000000000000..40a11e20b4f0
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-common.h
@@ -0,0 +1,11 @@
+template<typename T> struct SomeTemplate {};
+
+struct DefinedInCommon {
+ void f();
+ struct Inner {};
+ friend void FoundByADL(DefinedInCommon);
+};
+
+template<typename T> struct CommonTemplate {
+ enum E { a = 1, b = 2, c = 3 };
+};
diff --git a/test/Modules/Inputs/declare-use/a.h b/test/Modules/Inputs/declare-use/a.h
new file mode 100644
index 000000000000..a36dc1b59d6f
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/a.h
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+const int a = 2;
+#endif
diff --git a/test/Modules/Inputs/declare-use/b.h b/test/Modules/Inputs/declare-use/b.h
new file mode 100644
index 000000000000..55daf7286801
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/b.h
@@ -0,0 +1,4 @@
+#ifndef B_H
+#define B_H
+const int b = 3;
+#endif
diff --git a/test/Modules/Inputs/declare-use/c.h b/test/Modules/Inputs/declare-use/c.h
new file mode 100644
index 000000000000..a24cd5ae44c0
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/c.h
@@ -0,0 +1,6 @@
+#ifndef C_H
+#define C_H
+#include "a.h"
+#include "b.h"
+const int c = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/d.h b/test/Modules/Inputs/declare-use/d.h
new file mode 100644
index 000000000000..a597b01c5d04
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/d.h
@@ -0,0 +1,6 @@
+#ifndef D_H
+#define D_H
+#include "a.h"
+#include "b.h"
+const int d = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/e.h b/test/Modules/Inputs/declare-use/e.h
new file mode 100644
index 000000000000..ed8d843f9a85
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/e.h
@@ -0,0 +1,6 @@
+#ifndef E_H
+#define E_H
+#include "a.h"
+#include "b.h"
+const int e = a*b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/f.h b/test/Modules/Inputs/declare-use/f.h
new file mode 100644
index 000000000000..1d8e2fd2881e
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/f.h
@@ -0,0 +1,6 @@
+#ifndef F_H
+#define F_H
+#include "a.h"
+#include "b.h"
+const int f = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/g.h b/test/Modules/Inputs/declare-use/g.h
new file mode 100644
index 000000000000..2a590177f8c3
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/g.h
@@ -0,0 +1,6 @@
+#ifndef G_H
+#define G_H
+#include "c.h"
+#include "g1.h"
+const int g1 = aux_g*c*7;
+#endif
diff --git a/test/Modules/Inputs/declare-use/g1.h b/test/Modules/Inputs/declare-use/g1.h
new file mode 100644
index 000000000000..78a072451f81
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/g1.h
@@ -0,0 +1 @@
+int aux_g = 11;
diff --git a/test/Modules/Inputs/declare-use/h.h b/test/Modules/Inputs/declare-use/h.h
new file mode 100644
index 000000000000..df99a6dd10ae
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/h.h
@@ -0,0 +1,7 @@
+#ifndef H_H
+#define H_H
+#include "c.h"
+#include "d.h" // expected-error {{use of a module not declared used}}
+#include "h1.h"
+const int h1 = aux_h*c*7*d;
+#endif
diff --git a/test/Modules/Inputs/declare-use/h1.h b/test/Modules/Inputs/declare-use/h1.h
new file mode 100644
index 000000000000..a9275d555c34
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/h1.h
@@ -0,0 +1 @@
+int aux_h = 13;
diff --git a/test/Modules/Inputs/declare-use/module.map b/test/Modules/Inputs/declare-use/module.map
new file mode 100644
index 000000000000..774fc37760c9
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/module.map
@@ -0,0 +1,43 @@
+module XA {
+ header "a.h"
+}
+
+module XB {
+ header "b.h"
+}
+
+module XC {
+ header "c.h"
+ use XA
+}
+
+module XD {
+ header "d.h"
+ use XA
+}
+
+module XE {
+ header "e.h"
+ use XA
+ use XB
+}
+
+module XF {
+ header "f.h"
+ use XA
+ use XB
+}
+
+module XG {
+ header "g.h"
+ header "g1.h"
+ use XC
+ use XE
+}
+
+module XH {
+ header "h.h"
+ header "h1.h"
+ use XC
+ use XE
+}
diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h
index eb7eb7e59dc1..6fa83d3eec75 100644
--- a/test/Modules/Inputs/def.h
+++ b/test/Modules/Inputs/def.h
@@ -17,4 +17,11 @@ class Def2 {
public:
void func();
};
+
+namespace Def3NS {
+ class Def3 {
+ public:
+ void func();
+ };
+}
#endif
diff --git a/test/Modules/Inputs/dummy.h b/test/Modules/Inputs/dummy.h
new file mode 100644
index 000000000000..6e1ac74e44fb
--- /dev/null
+++ b/test/Modules/Inputs/dummy.h
@@ -0,0 +1,3 @@
+// This module only exists to make local decl IDs and global decl IDs different.
+
+struct Dummy {} extern *dummy1, *dummy2, *dummy3;
diff --git a/test/Modules/Inputs/incomplete_mod.h b/test/Modules/Inputs/incomplete_mod.h
new file mode 100644
index 000000000000..f08be7244136
--- /dev/null
+++ b/test/Modules/Inputs/incomplete_mod.h
@@ -0,0 +1 @@
+#include "incomplete_mod_missing.h"
diff --git a/test/Modules/Inputs/incomplete_mod_missing.h b/test/Modules/Inputs/incomplete_mod_missing.h
new file mode 100644
index 000000000000..ffc85d5e7305
--- /dev/null
+++ b/test/Modules/Inputs/incomplete_mod_missing.h
@@ -0,0 +1,2 @@
+extern int *missing;
+
diff --git a/test/Modules/Inputs/initializer_list b/test/Modules/Inputs/initializer_list
new file mode 100644
index 000000000000..6058f803a3dd
--- /dev/null
+++ b/test/Modules/Inputs/initializer_list
@@ -0,0 +1,9 @@
+namespace std {
+ using size_t = decltype(sizeof(0));
+
+ template<typename T> struct initializer_list {
+ initializer_list(T*, size_t);
+ };
+
+ template<typename T> int min(initializer_list<T>);
+}
diff --git a/test/Modules/Inputs/modular_maps/a.h b/test/Modules/Inputs/modular_maps/a.h
new file mode 100644
index 000000000000..a36dc1b59d6f
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/a.h
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+const int a = 2;
+#endif
diff --git a/test/Modules/Inputs/modular_maps/b.h b/test/Modules/Inputs/modular_maps/b.h
new file mode 100644
index 000000000000..55daf7286801
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/b.h
@@ -0,0 +1,4 @@
+#ifndef B_H
+#define B_H
+const int b = 3;
+#endif
diff --git a/test/Modules/Inputs/modular_maps/common.h b/test/Modules/Inputs/modular_maps/common.h
new file mode 100644
index 000000000000..f690bcbd399b
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/common.h
@@ -0,0 +1,4 @@
+#ifndef COMMON_H
+#define COMMON_H
+const int c = 2;
+#endif
diff --git a/test/Modules/Inputs/modular_maps/modulea.map b/test/Modules/Inputs/modular_maps/modulea.map
new file mode 100644
index 000000000000..58c5f6464e40
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/modulea.map
@@ -0,0 +1,7 @@
+module A {
+ header "common.h"
+ header "a.h"
+}
+
+extern module B "moduleb.map"
+
diff --git a/test/Modules/Inputs/modular_maps/moduleb.map b/test/Modules/Inputs/modular_maps/moduleb.map
new file mode 100644
index 000000000000..7b35e8f91e44
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/moduleb.map
@@ -0,0 +1,4 @@
+module B {
+ header "common.h"
+ private header "b.h"
+}
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index d20521f9c764..cf8a298ccee7 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -131,6 +131,10 @@ module MethodPoolA {
module MethodPoolB {
header "MethodPoolB.h"
+ explicit module Sub2 {
+ header "MethodPoolBSub2.h"
+ }
+
explicit module Sub {
header "MethodPoolBSub.h"
}
@@ -184,6 +188,35 @@ module cxx_linkage_cache {
header "cxx-linkage-cache.h"
}
+module cxx_templates_common {
+ header "cxx-templates-common.h"
+}
+
+module cxx_templates_a {
+ header "cxx-templates-a.h"
+}
+
+module cxx_templates_b_impl {
+ header "cxx-templates-b-impl.h"
+}
+
+module cxx_templates_b {
+ header "cxx-templates-b.h"
+}
+
+module cxx_templates_c {
+ header "cxx-templates-c.h"
+}
+
+module cxx_decls {
+ module unimported {
+ header "cxx-decls-unimported.h"
+ }
+ module imported {
+ header "cxx-decls-imported.h"
+ }
+}
+
module config {
header "config.h"
config_macros [exhaustive] WANT_FOO, WANT_BAR
@@ -193,6 +226,10 @@ module diag_pragma {
header "diag_pragma.h"
}
+module dummy {
+ header "dummy.h"
+}
+
module builtin {
header "builtin.h"
explicit module sub {
@@ -209,3 +246,38 @@ module linkage_merge {
}
}
+
+module incomplete_mod {
+ header "incomplete_mod.h"
+}
+
+module warning {
+ header "warning.h"
+}
+
+module initializer_list {
+ header "initializer_list"
+}
+
+module using_decl {
+ module a { header "using-decl-a.h" export * }
+ module b { header "using-decl-b.h" export * }
+}
+
+module recursive_visibility_a1 {
+ module inner { header "recursive_visibility_a1_inner.h" }
+}
+module recursive_visibility_a2 {
+ module inner {
+ module more_inner {
+ header "recursive_visibility_a2_more_inner.h"
+ }
+ }
+}
+module recursive_visibility_b {
+ header "recursive_visibility_b.h"
+ export *
+}
+module recursive_visibility_c {
+ header "recursive_visibility_c.h"
+}
diff --git a/test/Modules/Inputs/namespaces-top.h b/test/Modules/Inputs/namespaces-top.h
index 0c607f528516..7aa8490eb7e1 100644
--- a/test/Modules/Inputs/namespaces-top.h
+++ b/test/Modules/Inputs/namespaces-top.h
@@ -12,3 +12,8 @@ namespace N3 {
namespace N12 { }
+namespace N13 {
+ void f();
+ int f(int);
+ void (*p)() = &f;
+}
diff --git a/test/Modules/Inputs/odr/a.h b/test/Modules/Inputs/odr/a.h
new file mode 100644
index 000000000000..26144b86e8d1
--- /dev/null
+++ b/test/Modules/Inputs/odr/a.h
@@ -0,0 +1,13 @@
+extern struct Y {
+ int n;
+ float f;
+} y1;
+enum E { e1 };
+
+struct X {
+ int n;
+} x1;
+
+int f() {
+ return y1.n + e1 + y1.f + x1.n;
+}
diff --git a/test/Modules/Inputs/odr/b.h b/test/Modules/Inputs/odr/b.h
new file mode 100644
index 000000000000..b4063979474f
--- /dev/null
+++ b/test/Modules/Inputs/odr/b.h
@@ -0,0 +1,9 @@
+struct Y {
+ int m;
+ double f;
+} y2;
+enum E { e2 };
+
+int g() {
+ return y2.m + e2 + y2.f;
+}
diff --git a/test/Modules/Inputs/odr/module.map b/test/Modules/Inputs/odr/module.map
new file mode 100644
index 000000000000..81f396342fac
--- /dev/null
+++ b/test/Modules/Inputs/odr/module.map
@@ -0,0 +1,6 @@
+module a {
+ header "a.h"
+}
+module b {
+ header "b.h"
+}
diff --git a/test/Modules/Inputs/pch-used.h b/test/Modules/Inputs/pch-used.h
new file mode 100644
index 000000000000..60e0097ea909
--- /dev/null
+++ b/test/Modules/Inputs/pch-used.h
@@ -0,0 +1,2 @@
+@import cstd.stdio;
+static inline void SPXTrace() { fprintf(__stderrp, ""); }
diff --git a/test/Modules/Inputs/private/common.h b/test/Modules/Inputs/private/common.h
new file mode 100644
index 000000000000..17d5444b650f
--- /dev/null
+++ b/test/Modules/Inputs/private/common.h
@@ -0,0 +1,6 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+typedef int common;
+
+#endif
diff --git a/test/Modules/Inputs/private/module.map b/test/Modules/Inputs/private/module.map
new file mode 100644
index 000000000000..9da44354be14
--- /dev/null
+++ b/test/Modules/Inputs/private/module.map
@@ -0,0 +1,9 @@
+module libPrivate1 {
+ header "public1.h"
+ private header "private1.h"
+}
+
+module libPrivate2 {
+ header "public2.h"
+ private header "private2.h"
+}
diff --git a/test/Modules/Inputs/private/private1.h b/test/Modules/Inputs/private/private1.h
new file mode 100644
index 000000000000..3f41cc0181d5
--- /dev/null
+++ b/test/Modules/Inputs/private/private1.h
@@ -0,0 +1,9 @@
+#ifndef PRIVATE1_H
+#define PRIVATE1_H
+
+#include "common.h"
+
+struct mitts_off1 { common field; };
+struct mitts_off1 hidden_variable1;
+
+#endif
diff --git a/test/Modules/Inputs/private/private2.h b/test/Modules/Inputs/private/private2.h
new file mode 100644
index 000000000000..3b6cddc4d902
--- /dev/null
+++ b/test/Modules/Inputs/private/private2.h
@@ -0,0 +1,9 @@
+#ifndef PRIVATE2_H
+#define PRIVATE2_H
+
+#include "common.h"
+
+struct mitts_off2 { common field; };
+struct mitts_off2 hidden_variable2;
+
+#endif
diff --git a/test/Modules/Inputs/private/public1.h b/test/Modules/Inputs/private/public1.h
new file mode 100644
index 000000000000..3af596a98d08
--- /dev/null
+++ b/test/Modules/Inputs/private/public1.h
@@ -0,0 +1,9 @@
+#ifndef PUBLIC1_H
+#define PUBLIC1_H
+
+#include "private1.h"
+
+struct use_this1 { struct mitts_off1 field; };
+struct use_this1 public_variable1;
+
+#endif
diff --git a/test/Modules/Inputs/private/public2.h b/test/Modules/Inputs/private/public2.h
new file mode 100644
index 000000000000..03d0a858e10e
--- /dev/null
+++ b/test/Modules/Inputs/private/public2.h
@@ -0,0 +1,9 @@
+#ifndef PUBLIC2_H
+#define PUBLIC2_H
+
+#include "private2.h"
+
+struct use_this2 { struct mitts_off2 field; };
+struct use_this2 public_variable2;
+
+#endif
diff --git a/test/Modules/Inputs/private0/common.h b/test/Modules/Inputs/private0/common.h
new file mode 100644
index 000000000000..17d5444b650f
--- /dev/null
+++ b/test/Modules/Inputs/private0/common.h
@@ -0,0 +1,6 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+typedef int common;
+
+#endif
diff --git a/test/Modules/Inputs/private1/module.map b/test/Modules/Inputs/private1/module.map
new file mode 100644
index 000000000000..0904fe68a62c
--- /dev/null
+++ b/test/Modules/Inputs/private1/module.map
@@ -0,0 +1,4 @@
+module libPrivate {
+ header "public1.h"
+ private header "private1.h"
+}
diff --git a/test/Modules/Inputs/private1/private1.h b/test/Modules/Inputs/private1/private1.h
new file mode 100644
index 000000000000..3f41cc0181d5
--- /dev/null
+++ b/test/Modules/Inputs/private1/private1.h
@@ -0,0 +1,9 @@
+#ifndef PRIVATE1_H
+#define PRIVATE1_H
+
+#include "common.h"
+
+struct mitts_off1 { common field; };
+struct mitts_off1 hidden_variable1;
+
+#endif
diff --git a/test/Modules/Inputs/private1/public1.h b/test/Modules/Inputs/private1/public1.h
new file mode 100644
index 000000000000..3af596a98d08
--- /dev/null
+++ b/test/Modules/Inputs/private1/public1.h
@@ -0,0 +1,9 @@
+#ifndef PUBLIC1_H
+#define PUBLIC1_H
+
+#include "private1.h"
+
+struct use_this1 { struct mitts_off1 field; };
+struct use_this1 public_variable1;
+
+#endif
diff --git a/test/Modules/Inputs/private2/module.map b/test/Modules/Inputs/private2/module.map
new file mode 100644
index 000000000000..3d2a5786f9b1
--- /dev/null
+++ b/test/Modules/Inputs/private2/module.map
@@ -0,0 +1,4 @@
+module libPrivateN2 {
+ header "public2.h"
+ private header "private2.h"
+}
diff --git a/test/Modules/Inputs/private2/private2.h b/test/Modules/Inputs/private2/private2.h
new file mode 100644
index 000000000000..3b6cddc4d902
--- /dev/null
+++ b/test/Modules/Inputs/private2/private2.h
@@ -0,0 +1,9 @@
+#ifndef PRIVATE2_H
+#define PRIVATE2_H
+
+#include "common.h"
+
+struct mitts_off2 { common field; };
+struct mitts_off2 hidden_variable2;
+
+#endif
diff --git a/test/Modules/Inputs/private2/public2.h b/test/Modules/Inputs/private2/public2.h
new file mode 100644
index 000000000000..03d0a858e10e
--- /dev/null
+++ b/test/Modules/Inputs/private2/public2.h
@@ -0,0 +1,9 @@
+#ifndef PUBLIC2_H
+#define PUBLIC2_H
+
+#include "private2.h"
+
+struct use_this2 { struct mitts_off2 field; };
+struct use_this2 public_variable2;
+
+#endif
diff --git a/test/Modules/Inputs/recursive_visibility_a1_inner.h b/test/Modules/Inputs/recursive_visibility_a1_inner.h
new file mode 100644
index 000000000000..0f9fdf709ba5
--- /dev/null
+++ b/test/Modules/Inputs/recursive_visibility_a1_inner.h
@@ -0,0 +1,4 @@
+namespace A1_Inner {
+ struct X {};
+ void f(X);
+}
diff --git a/test/Modules/Inputs/recursive_visibility_a2_more_inner.h b/test/Modules/Inputs/recursive_visibility_a2_more_inner.h
new file mode 100644
index 000000000000..a9ff9d90af1b
--- /dev/null
+++ b/test/Modules/Inputs/recursive_visibility_a2_more_inner.h
@@ -0,0 +1,4 @@
+namespace A2_More_Inner {
+ struct X {};
+ void f(X);
+}
diff --git a/test/Modules/Inputs/recursive_visibility_b.h b/test/Modules/Inputs/recursive_visibility_b.h
new file mode 100644
index 000000000000..2c5d4effe330
--- /dev/null
+++ b/test/Modules/Inputs/recursive_visibility_b.h
@@ -0,0 +1,2 @@
+@import recursive_visibility_a1.inner;
+@import recursive_visibility_a2;
diff --git a/test/Modules/Inputs/recursive_visibility_c.h b/test/Modules/Inputs/recursive_visibility_c.h
new file mode 100644
index 000000000000..a978a3c0a562
--- /dev/null
+++ b/test/Modules/Inputs/recursive_visibility_c.h
@@ -0,0 +1,5 @@
+@import recursive_visibility_b;
+template<template<typename T> class Y> void g() {
+ f(typename Y<A1_Inner::X>::type{});
+ f(typename Y<A2_More_Inner::X>::type{});
+}
diff --git a/test/Modules/Inputs/separate_map_tree/maps/modulea.map b/test/Modules/Inputs/separate_map_tree/maps/modulea.map
new file mode 100644
index 000000000000..736503ecaebe
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/maps/modulea.map
@@ -0,0 +1,12 @@
+module D {
+ header "../src/common.h"
+}
+
+module A {
+ header "../src/common.h"
+ use C
+}
+
+extern module B "moduleb.map"
+extern module C "modulec.map"
+
diff --git a/test/Modules/Inputs/separate_map_tree/maps/moduleb.map b/test/Modules/Inputs/separate_map_tree/maps/moduleb.map
new file mode 100644
index 000000000000..d3877965c71e
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/maps/moduleb.map
@@ -0,0 +1,4 @@
+module B {
+ header "../src/public-in-b.h"
+ private header "../src/public-in-c.h"
+}
diff --git a/test/Modules/Inputs/separate_map_tree/maps/modulec.map b/test/Modules/Inputs/separate_map_tree/maps/modulec.map
new file mode 100644
index 000000000000..91063b65f378
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/maps/modulec.map
@@ -0,0 +1,5 @@
+module C {
+ header "../src/public-in-c.h"
+ private header "../src/public-in-b.h"
+ private header "../src/private-in-c.h"
+}
diff --git a/test/Modules/Inputs/separate_map_tree/src/common.h b/test/Modules/Inputs/separate_map_tree/src/common.h
new file mode 100644
index 000000000000..1d2ecb5a194d
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/src/common.h
@@ -0,0 +1,4 @@
+#ifndef COMMON_H
+#define COMMON_H
+const int common = 2;
+#endif
diff --git a/test/Modules/Inputs/separate_map_tree/src/private-in-c.h b/test/Modules/Inputs/separate_map_tree/src/private-in-c.h
new file mode 100644
index 000000000000..bc9e2c1bb342
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/src/private-in-c.h
@@ -0,0 +1,4 @@
+#ifndef PRIVATE_IN_C_H
+#define PRIVATE_IN_C_H
+const int c_ = 2;
+#endif
diff --git a/test/Modules/Inputs/separate_map_tree/src/public-in-b.h b/test/Modules/Inputs/separate_map_tree/src/public-in-b.h
new file mode 100644
index 000000000000..9ea6c1b4410d
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/src/public-in-b.h
@@ -0,0 +1,4 @@
+#ifndef PUBLIC_IN_B_H
+#define PUBLIC_IN_B_H
+const int b = 3;
+#endif
diff --git a/test/Modules/Inputs/separate_map_tree/src/public-in-c.h b/test/Modules/Inputs/separate_map_tree/src/public-in-c.h
new file mode 100644
index 000000000000..fa3d2fd2cb73
--- /dev/null
+++ b/test/Modules/Inputs/separate_map_tree/src/public-in-c.h
@@ -0,0 +1,4 @@
+#ifndef PUBLIC_IN_C_H
+#define PUBLIC_IN_C_H
+const int c = 2;
+#endif
diff --git a/test/Modules/Inputs/submodules/import-self-a.h b/test/Modules/Inputs/submodules/import-self-a.h
new file mode 100644
index 000000000000..adb070abf362
--- /dev/null
+++ b/test/Modules/Inputs/submodules/import-self-a.h
@@ -0,0 +1 @@
+typedef int MyTypeA;
diff --git a/test/Modules/Inputs/submodules/import-self-b.h b/test/Modules/Inputs/submodules/import-self-b.h
new file mode 100644
index 000000000000..f88b56d5f082
--- /dev/null
+++ b/test/Modules/Inputs/submodules/import-self-b.h
@@ -0,0 +1,10 @@
+@import import_self.c;
+#include "import-self-d.h"
+
+// FIXME: This should not work; names from 'a' should not be visible here.
+MyTypeA import_self_test_a;
+
+// FIXME: This should work but does not; names from 'b' are not actually visible here.
+//MyTypeC import_self_test_c;
+
+MyTypeD import_self_test_d;
diff --git a/test/Modules/Inputs/submodules/import-self-c.h b/test/Modules/Inputs/submodules/import-self-c.h
new file mode 100644
index 000000000000..f4b86c5656e1
--- /dev/null
+++ b/test/Modules/Inputs/submodules/import-self-c.h
@@ -0,0 +1 @@
+typedef int MyTypeC;
diff --git a/test/Modules/Inputs/submodules/import-self-d.h b/test/Modules/Inputs/submodules/import-self-d.h
new file mode 100644
index 000000000000..e32a6f51957c
--- /dev/null
+++ b/test/Modules/Inputs/submodules/import-self-d.h
@@ -0,0 +1 @@
+typedef int MyTypeD;
diff --git a/test/Modules/Inputs/submodules/module.map b/test/Modules/Inputs/submodules/module.map
index 16cedac231e7..c91e94f47d23 100644
--- a/test/Modules/Inputs/submodules/module.map
+++ b/test/Modules/Inputs/submodules/module.map
@@ -3,3 +3,10 @@ module std {
module type_traits { header "type_traits.h" }
explicit module hash_map { header "hash_map.h" }
}
+
+module import_self {
+ module a { header "import-self-a.h" }
+ module b { header "import-self-b.h" export * }
+ module c { header "import-self-c.h" }
+ module d { header "import-self-d.h" }
+}
diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h
index 7451420c7482..e76598d6bd5c 100644
--- a/test/Modules/Inputs/templates-left.h
+++ b/test/Modules/Inputs/templates-left.h
@@ -19,6 +19,10 @@ namespace N {
};
}
+constexpr unsigned List<int>::*size_left = &List<int>::size;
+List<int> list_left = { 0, 8 };
+typedef List<int> ListInt_left;
+
template <typename T>
void pendingInstantiationEmit(T) {}
void triggerPendingInstantiation() {
@@ -27,3 +31,5 @@ void triggerPendingInstantiation() {
}
void redeclDefinitionEmit(){}
+
+typedef Outer<int>::Inner OuterIntInner_left;
diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h
index d3524d34769b..16d0a714d90e 100644
--- a/test/Modules/Inputs/templates-right.h
+++ b/test/Modules/Inputs/templates-right.h
@@ -18,6 +18,10 @@ namespace N {
};
}
+constexpr unsigned List<int>::*size_right = &List<int>::size;
+List<int> list_right = { 0, 12 };
+typedef List<int> ListInt_right;
+
template <typename T>
void pendingInstantiationEmit(T) {}
void triggerPendingInstantiationToo() {
@@ -25,3 +29,5 @@ void triggerPendingInstantiationToo() {
}
void redeclDefinitionEmit(){}
+
+typedef Outer<int>::Inner OuterIntInner_right;
diff --git a/test/Modules/Inputs/templates-top.h b/test/Modules/Inputs/templates-top.h
index 5985ee8820d6..87dcd8b7f465 100644
--- a/test/Modules/Inputs/templates-top.h
+++ b/test/Modules/Inputs/templates-top.h
@@ -3,6 +3,10 @@ template<typename T> class Vector;
template<typename T> class List {
public:
void push_back(T);
+
+ struct node {};
+ node *head;
+ unsigned size;
};
namespace A {
@@ -15,3 +19,7 @@ template <typename T> class A::WhereAmI {
public:
static void func() {}
};
+
+template<typename T> struct Outer {
+ struct Inner {};
+};
diff --git a/test/Modules/Inputs/using-decl-a.h b/test/Modules/Inputs/using-decl-a.h
new file mode 100644
index 000000000000..85a4788e7647
--- /dev/null
+++ b/test/Modules/Inputs/using-decl-a.h
@@ -0,0 +1,10 @@
+typedef int using_decl_type;
+int using_decl_var;
+
+namespace UsingDecl {
+ using ::using_decl_type;
+ using ::using_decl_var;
+
+ namespace A { typedef int inner; }
+ using A::inner;
+}
diff --git a/test/Modules/Inputs/using-decl-b.h b/test/Modules/Inputs/using-decl-b.h
new file mode 100644
index 000000000000..b82526f39ff4
--- /dev/null
+++ b/test/Modules/Inputs/using-decl-b.h
@@ -0,0 +1,11 @@
+namespace UsingDecl {
+ namespace B { typedef int inner; }
+ using B::inner;
+}
+
+#include "using-decl-a.h"
+
+namespace UsingDecl {
+ using ::using_decl_type;
+ using ::using_decl_var;
+}
diff --git a/test/Modules/Inputs/warning.h b/test/Modules/Inputs/warning.h
new file mode 100644
index 000000000000..a90c62886749
--- /dev/null
+++ b/test/Modules/Inputs/warning.h
@@ -0,0 +1 @@
+enum { bigger_than_int = 0x80000000 };
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index 735182818203..d7fb9d1f9fd6 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -1,10 +1,12 @@
// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify -DERRORS
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
+//
+// Test both with and without the declarations that refer to unimported
+// entities. For error recovery, those cases implicitly trigger an import.
#include <DependsOnModule/DependsOnModule.h> // expected-warning{{treating #include as an import of module 'DependsOnModule'}}
-// expected-note@Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h:1{{'no_umbrella_A_private' declared here}}
-
#ifdef MODULE_H_MACRO
# error MODULE_H_MACRO should have been hidden
#endif
@@ -13,15 +15,21 @@
# error DEPENDS_ON_MODULE should have been hidden
#endif
-Module *mod; // expected-error{{unknown type name 'Module'}}
-
+#ifdef ERRORS
+Module *mod; // expected-error{{declaration of 'Module' must be imported from module 'Module' before it is required}}
+// expected-note@Inputs/Module.framework/Headers/Module.h:15 {{previous}}
+#else
#import <AlsoDependsOnModule/AlsoDependsOnModule.h> // expected-warning{{treating #import as an import of module 'AlsoDependsOnModule'}}
+#endif
Module *mod2;
int getDependsOther() { return depends_on_module_other; }
void testSubframeworkOther() {
- double *sfo1 = sub_framework_other; // expected-error{{use of undeclared identifier 'sub_framework_other'}}
+#ifdef ERRORS
+ double *sfo1 = sub_framework_other; // expected-error{{declaration of 'sub_framework_other' must be imported from module 'DependsOnModule.SubFramework.Other'}}
+ // expected-note@Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h:15 {{previous}}
+#endif
}
// Test umbrella-less submodule includes
@@ -32,8 +40,10 @@ int getNoUmbrellaA() { return no_umbrella_A; }
#include <NoUmbrella/SubDir/C.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.SubDir.C'}}
int getNoUmbrellaC() { return no_umbrella_C; }
+#ifndef ERRORS
// Test header cross-subframework include pattern.
#include <DependsOnModule/../Frameworks/SubFramework.framework/Headers/Other.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.SubFramework.Other'}}
+#endif
void testSubframeworkOtherAgain() {
double *sfo1 = sub_framework_other;
@@ -61,7 +71,8 @@ int getModulePrivate() { return module_private; }
#include <NoUmbrella/A_Private.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.Private.A_Private'}}
int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
-int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}
+int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{declaration of 'no_umbrella_B_private' must be imported from module 'NoUmbrella.Private.B_Private'}}
+// expected-note@Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h:1 {{previous}}
// Test inclusion of headers that are under an umbrella directory but
// not actually part of the module.
@@ -71,3 +82,7 @@ int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-er
int getNotInModule() {
return not_in_module;
}
+
+void includeNotAtTopLevel() {
+ #include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} expected-error {{expected expression}}
+}
diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m
index 4bf9d592a8f2..077aac5374a0 100644
--- a/test/Modules/autolink.m
+++ b/test/Modules/autolink.m
@@ -35,7 +35,7 @@ int use_no_umbrella() {
// CHECK: !4 = metadata !{i32 6, metadata !"Linker Options", metadata ![[AUTOLINK_OPTIONS:[0-9]+]]}
// CHECK: ![[AUTOLINK_OPTIONS]] = metadata !{metadata ![[AUTOLINK_FRAMEWORK:[0-9]+]], metadata ![[AUTOLINK:[0-9]+]], metadata ![[DEPENDSONMODULE:[0-9]+]], metadata ![[MODULE:[0-9]+]], metadata ![[NOUMBRELLA:[0-9]+]]}
// CHECK: ![[AUTOLINK_FRAMEWORK]] = metadata !{metadata !"-framework", metadata !"autolink_framework"}
-// CHECK: ![[AUTOLINK]] = metadata !{metadata !"-lautolink"}
+// CHECK: ![[AUTOLINK]] = metadata !{metadata !"{{(-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"}
// CHECK: ![[DEPENDSONMODULE]] = metadata !{metadata !"-framework", metadata !"DependsOnModule"}
// CHECK: ![[MODULE]] = metadata !{metadata !"-framework", metadata !"Module"}
// CHECK: ![[NOUMBRELLA]] = metadata !{metadata !"-framework", metadata !"NoUmbrella"}
diff --git a/test/Modules/build-fail-notes.m b/test/Modules/build-fail-notes.m
index 8375788e817b..e27341154d79 100644
--- a/test/Modules/build-fail-notes.m
+++ b/test/Modules/build-fail-notes.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
@import DependsOnModule;
@@ -11,14 +11,14 @@
// CHECK: fatal error: could not build module 'DependsOnModule'
// CHECK-NOT: error:
-// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -fdiagnostics-show-note-include-stack 2>&1 | FileCheck -check-prefix=CHECK-REDEF %s
+// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -fdiagnostics-show-note-include-stack 2>&1 | FileCheck -check-prefix=CHECK-REDEF %s
extern int Module;
// CHECK-REDEF: In module 'DependsOnModule' imported from
// CHECK-REDEF: In module 'Module' imported from
// CHECK-REDEF: Module.h:15:12: note: previous definition is here
-// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" -serialize-diagnostic-file %t/tmp.diag %s 2>&1
+// RUN: not %clang_cc1 -Wincomplete-umbrella -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" -serialize-diagnostic-file %t/tmp.diag %s 2>&1
// RUN: c-index-test -read-diagnostics %t/tmp.diag 2>&1 | FileCheck -check-prefix=CHECK-SDIAG %s
// CHECK-SDIAG: Module.h:9:13: error: expected ';' after top level declarator
diff --git a/test/Modules/compiler_builtins_arm.m b/test/Modules/compiler_builtins_arm.m
new file mode 100644
index 000000000000..d15437cafcdb
--- /dev/null
+++ b/test/Modules/compiler_builtins_arm.m
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv7-none-linux-gnueabihf -target-abi aapcs -target-cpu cortex-a8 -mfloat-abi hard -std=c99 -fmodules -fmodules-cache-path=%t -D__need_wint_t %s -verify
+// expected-no-diagnostics
+// REQUIRES: arm-registered-target
+
+@import _Builtin_intrinsics.arm.neon;
diff --git a/test/Modules/cxx-decls.cpp b/test/Modules/cxx-decls.cpp
new file mode 100644
index 000000000000..ba3281aaec7a
--- /dev/null
+++ b/test/Modules/cxx-decls.cpp
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+// expected-no-diagnostics
+
+@import dummy;
+@import cxx_decls.imported;
+
+void test_delete(int *p) {
+ // We can call the normal global deallocation function even though it has only
+ // ever been explicitly declared in an unimported submodule.
+ delete p;
+}
+
+void friend_1(HasFriends s) {
+ s.private_thing();
+}
+void test_friends(HasFriends s) {
+ friend_1(s);
+ friend_2(s);
+}
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
new file mode 100644
index 000000000000..65f41f677be5
--- /dev/null
+++ b/test/Modules/cxx-templates.cpp
@@ -0,0 +1,125 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+@import cxx_templates_a;
+@import cxx_templates_b;
+@import cxx_templates_c;
+@import cxx_templates_common;
+
+template<typename, char> struct Tmpl_T_C {};
+template<typename, int, int> struct Tmpl_T_I_I {};
+
+template<typename A, typename B, A> struct Tmpl_T_T_A {};
+template<typename A, typename B, B> struct Tmpl_T_T_B {};
+
+template<int> struct UseInt {};
+
+void g() {
+ f(0);
+ f<double>(1.0);
+ f<int>();
+ f(); // expected-error {{no matching function}}
+ // expected-note@Inputs/cxx-templates-b.h:3 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-b.h:4 {{requires single argument}}
+
+ N::f(0);
+ N::f<double>(1.0);
+ N::f<int>();
+ N::f(); // expected-error {{no matching function}}
+ // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument 't'}}
+
+ template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
+ template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
+
+ template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function}}
+ // expected-note@Inputs/cxx-templates-a.h:11 {{invalid explicitly-specified argument}}
+ // expected-note@Inputs/cxx-templates-b.h:11 {{invalid explicitly-specified argument}}
+
+ template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}}
+ // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}}
+ // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}}
+
+ // 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.
+ PerformDelayedLookup(defined_in_common);
+
+ // Likewise, but via a default argument.
+ PerformDelayedLookupInDefaultArgument(defined_in_common);
+
+ // Trigger the instantiation of a template in 'b' that uses a type defined in
+ // 'b_impl'. That type is not visible here.
+ UseDefinedInBImpl<int>();
+
+ // Trigger the instantiation of a template in 'a' that uses a type defined in
+ // 'b_impl', via a template defined in 'b'. Since the type is visible from
+ // within 'b', the instantiation succeeds.
+ UseDefinedInBImplIndirectly(defined_in_b_impl);
+
+ // Trigger the instantiation of a template in 'a' that uses a type defined in
+ // 'b_impl'. That type is not visible here, nor in 'a'. This fails; there is
+ // no reason why DefinedInBImpl should be visible here.
+ // expected-error@Inputs/cxx-templates-a.h:19 {{definition of 'DefinedInBImpl' must be imported}}
+ // expected-note@Inputs/cxx-templates-b-impl.h:1 {{definition is here}}
+ PerformDelayedLookup(defined_in_b_impl); // expected-note {{in instantiation of}}
+
+ merge_templates_a = merge_templates_b; // ok, same type
+
+ using T = decltype(enum_a_from_a);
+ using T = decltype(enum_b_from_b);
+ T e = true ? enum_a_from_a : enum_b_from_b;
+
+ UseRedeclaredEnum<int>(UseInt<1>());
+ // FIXME: Reintroduce this once we merge function template specializations.
+ //static_assert(UseRedeclaredEnumA == UseRedeclaredEnumB, "");
+ //static_assert(UseRedeclaredEnumA == UseRedeclaredEnum<int>, "");
+ //static_assert(UseRedeclaredEnumB == UseRedeclaredEnum<int>, "");
+ static_assert(enum_c_from_a == enum_c_from_b, "");
+ CommonTemplate<int> cti;
+ CommonTemplate<int>::E eee = CommonTemplate<int>::c;
+}
+
+RedeclaredAsFriend<int> raf1;
+RedeclareTemplateAsFriend<double> rtaf;
+RedeclaredAsFriend<double> raf2;
+
+MergeSpecializations<int*>::partially_specialized_in_a spec_in_a_1;
+MergeSpecializations<int&>::partially_specialized_in_b spec_in_b_1;
+MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1;
+MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
+MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
+MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
+
+@import cxx_templates_common;
+
+typedef SomeTemplate<int*> SomeTemplateIntPtr;
+typedef SomeTemplate<int&> SomeTemplateIntRef;
+SomeTemplate<char*> some_template_char_ptr;
+SomeTemplate<char&> some_template_char_ref;
+
+void testImplicitSpecialMembers(SomeTemplate<char[1]> &a,
+ const SomeTemplate<char[1]> &b,
+ SomeTemplate<char[2]> &c,
+ const SomeTemplate<char[2]> &d) {
+ a = b;
+ c = d;
+}
+
+// CHECK-GLOBAL: DeclarationName 'f'
+// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
+
+// CHECK-NAMESPACE-N: DeclarationName 'f'
+// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
+// CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f'
diff --git a/test/Modules/cycles.c b/test/Modules/cycles.c
index 5f83092c95fd..47728d814c29 100644
--- a/test/Modules/cycles.c
+++ b/test/Modules/cycles.c
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -F %S/Inputs %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -F %S/Inputs %s 2>&1 | FileCheck %s
// FIXME: When we have a syntax for modules in C, use that.
@import MutuallyRecursive1;
diff --git a/test/Modules/declare-use1.cpp b/test/Modules/declare-use1.cpp
new file mode 100644
index 000000000000..4508017c12d2
--- /dev/null
+++ b/test/Modules/declare-use1.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify
+
+#include "g.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int g2 = g1+e+f;
diff --git a/test/Modules/declare-use2.cpp b/test/Modules/declare-use2.cpp
new file mode 100644
index 000000000000..a2ec55e5e5ca
--- /dev/null
+++ b/test/Modules/declare-use2.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XH -I %S/Inputs/declare-use %s -verify
+
+#include "h.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int h2 = h1+e+f;
diff --git a/test/Modules/decldef.m b/test/Modules/decldef.m
index 7ed82b57e9c6..efd2d7c42c83 100644
--- a/test/Modules/decldef.m
+++ b/test/Modules/decldef.m
@@ -1,13 +1,16 @@
// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
-// expected-note@Inputs/def.h:5 {{previous definition is here}}
+// expected-note@Inputs/def.h:5 {{previous}}
@class Def;
Def *def;
@import decldef;
-A *a1; // expected-error{{unknown type name 'A'}}
+#ifdef USE_EARLY
+A *a1; // expected-error{{declaration of 'A' must be imported from module 'decldef.Def' before it is required}}
+#endif
B *b1; // expected-error{{must use 'struct' tag to refer to type 'B'}}
@import decldef.Decl;
@@ -15,7 +18,10 @@ A *a2;
struct B *b;
void testA(A *a) {
- a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
+ a->ivar = 17;
+#ifndef USE_EARLY
+ // expected-error@-2{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
+#endif
}
void testB() {
diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm
index 593f53b2c6cf..35694935dfbb 100644
--- a/test/Modules/decldef.mm
+++ b/test/Modules/decldef.mm
@@ -1,27 +1,35 @@
// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
-// expected-note@Inputs/def.h:5 {{previous definition is here}}
+// expected-note@Inputs/def.h:5 {{previous}}
@class Def;
Def *def;
-class Def2;
+class Def2; // expected-note {{forward decl}}
Def2 *def2;
+namespace Def3NS { class Def3; } // expected-note {{forward decl}}
+Def3NS::Def3 *def3;
@interface Unrelated
- defMethod;
@end
@import decldef;
-A *a1; // expected-error{{unknown type name 'A'}}
-B *b1; // expected-error{{unknown type name 'B'}}
+#ifdef USE_EARLY
+A *a1; // expected-error{{declaration of 'A' must be imported from module 'decldef.Def'}}
+B *b1;
+#endif
@import decldef.Decl;
A *a2;
B *b;
void testA(A *a) {
- a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
+ a->ivar = 17;
+#ifndef USE_EARLY
+ // expected-error@-2{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
+#endif
}
void testB() {
@@ -33,5 +41,9 @@ void testDef() {
}
void testDef2() {
- def2->func();
+ // FIXME: These should both work, since we've (implicitly) imported
+ // decldef.Def here, but they don't, because nothing has triggered the lazy
+ // loading of the definitions of these classes.
+ def2->func(); // expected-error {{incomplete}}
+ def3->func(); // expected-error {{incomplete}}
}
diff --git a/test/Modules/driver.c b/test/Modules/driver.c
index 08fdaab44106..79d1bbe13c07 100644
--- a/test/Modules/driver.c
+++ b/test/Modules/driver.c
@@ -1,5 +1,5 @@
-// RUN: %clang -fmodules %s -### 2>&1 | FileCheck -check-prefix NO_MODULE_CACHE %s
-// RUN: %clang -fmodules -fmodules-cache-path=blarg %s -### 2>&1 | FileCheck -check-prefix WITH_MODULE_CACHE %s
+// RUN: %clang -fmodules %s -### 2>&1 | FileCheck -check-prefix CHECK-NO_MODULE_CACHE %s
+// RUN: %clang -fmodules -fmodules-cache-path=blarg %s -### 2>&1 | FileCheck -check-prefix CHECK-WITH_MODULE_CACHE %s
// CHECK-NO_MODULE_CACHE: {{clang.*"-fmodules-cache-path=.*ModuleCache"}}
diff --git a/test/Modules/epic-fail.m b/test/Modules/epic-fail.m
index 8969149f957a..7ce9571255f9 100644
--- a/test/Modules/epic-fail.m
+++ b/test/Modules/epic-fail.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
@import Module;
@import DependsOnModule;
diff --git a/test/Modules/fatal-module-loader-error.m b/test/Modules/fatal-module-loader-error.m
new file mode 100644
index 000000000000..6af3b4c7c370
--- /dev/null
+++ b/test/Modules/fatal-module-loader-error.m
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: touch %t/Module.pcm
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -verify
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -DIMPLICIT -verify
+
+// This tests that after a fatal module loader error, we do not continue parsing.
+
+#ifdef IMPLICIT
+
+// expected-error@+1{{does not appear to be}}
+#import <Module/Module.h>
+#pragma clang __debug crash;
+
+#else
+
+// expected-error@+1{{does not appear to be}}
+@import Module;
+#pragma clang __debug crash;
+
+#endif
+
+// Also check that libclang does not create a PCH with such an error.
+// RUN: not c-index-test -write-pch %t.pch -fmodules -fmodules-cache-path=%t \
+// RUN: %s -Xclang -fdisable-module-hash -F %S/Inputs 2>&1 | FileCheck %s
+// CHECK: Unable to write PCH file
diff --git a/test/Modules/import-decl.cpp b/test/Modules/import-decl.cpp
index 900e090c0c5f..56428b3eba65 100644
--- a/test/Modules/import-decl.cpp
+++ b/test/Modules/import-decl.cpp
@@ -8,3 +8,12 @@
int main() {
return 0;
}
+
+// <rdar://problem/15084587>
+@interface A
+-method;
+@end
+
+void testImport(A *import) {
+ [import method];
+}
diff --git a/test/Modules/incomplete-module.m b/test/Modules/incomplete-module.m
new file mode 100644
index 000000000000..8edaea983cb9
--- /dev/null
+++ b/test/Modules/incomplete-module.m
@@ -0,0 +1,5 @@
+@import incomplete_mod;
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -Wincomplete-module -fmodules -I %S/Inputs %s 2>&1 | FileCheck %s
+// CHECK: {{warning: header '.*incomplete_mod_missing.h' is included in module 'incomplete_mod' but not listed in module map}}
diff --git a/test/Modules/initializer_list.cpp b/test/Modules/initializer_list.cpp
new file mode 100644
index 000000000000..0cbcbbb70e46
--- /dev/null
+++ b/test/Modules/initializer_list.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+// expected-no-diagnostics
+@import initializer_list;
+
+int n = std::min({1, 2, 3});
diff --git a/test/Modules/load_failure.c b/test/Modules/load_failure.c
index 6f9426aa062b..6c6d812bafa3 100644
--- a/test/Modules/load_failure.c
+++ b/test/Modules/load_failure.c
@@ -8,7 +8,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fdisable-module-hash -emit-module -fmodule-name=load_failure %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
+// RUN: not %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
// CHECK-NONEXISTENT: load_failure.c:2:9: fatal error: module 'load_nonexistent' not found
// RUN: not %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -fdisable-module-hash %s -DFAILURE 2> %t.out
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
index 433e03324bce..541c95be58de 100644
--- a/test/Modules/macros.c
+++ b/test/Modules/macros.c
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros_right %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -verify -fmodules-cache-path=%t %s
-// RUN: %clang_cc1 -E -fmodules -x objective-c -fmodules-cache-path=%t %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
+// RUN: not %clang_cc1 -E -fmodules -x objective-c -fmodules-cache-path=%t %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
// FIXME: When we have a syntax for modules in C, use that.
// These notes come from headers in modules, and are bogus.
diff --git a/test/Modules/method_pool.m b/test/Modules/method_pool.m
index 6fd74b0885fd..f7d5ae700c97 100644
--- a/test/Modules/method_pool.m
+++ b/test/Modules/method_pool.m
@@ -47,6 +47,10 @@ void testMethod3Again(id object) {
char *str = [object method3]; // okay: only found in MethodPoolB.Sub
}
+void testMethod6(id object) {
+ [object method6];
+}
+
@import MethodPoolA.Sub;
void testMethod3AgainAgain(id object) {
diff --git a/test/Modules/modular_maps.cpp b/test/Modules/modular_maps.cpp
new file mode 100644
index 000000000000..9c9aba85a918
--- /dev/null
+++ b/test/Modules/modular_maps.cpp
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
+
+#include "common.h"
+#include "a.h"
+#include "b.h" // expected-error {{private header}}
+const int v = a + c;
+const int val = a + b + c; // expected-error {{undeclared identifier}}
diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp
index 426e0025f9f8..8c225e051bde 100644
--- a/test/Modules/namespaces.cpp
+++ b/test/Modules/namespaces.cpp
@@ -75,3 +75,10 @@ void testAnonymousNotMerged() {
// expected-note@Inputs/namespaces-right.h:60 {{passing argument to parameter here}}
// expected-note@Inputs/namespaces-right.h:67 {{passing argument to parameter here}}
+
+// Test that bringing in one name from an overload set does not hide the rest.
+void testPartialImportOfOverloadSet() {
+ void (*p)() = N13::p;
+ p();
+ N13::f(0);
+}
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 8155318fb310..70fed60b1295 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -24,8 +24,8 @@ int testNestedUmbrellaA() {
int testNestedUmbrellaBFail() {
return nested_umbrella_b;
- // expected-error@-1{{use of undeclared identifier 'nested_umbrella_b'; did you mean 'nested_umbrella_a'?}}
- // expected-note@Inputs/normal-module-map/nested_umbrella/a.h:1{{'nested_umbrella_a' declared here}}
+ // expected-error@-1{{declaration of 'nested_umbrella_b' must be imported from module 'nested_umbrella.b' before it is required}}
+ // expected-note@Inputs/normal-module-map/nested_umbrella/b.h:1{{previous}}
}
@import nested_umbrella.b;
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
index 81fb28bafb2a..f08b13a78ab2 100644
--- a/test/Modules/objc-categories.m
+++ b/test/Modules/objc-categories.m
@@ -10,6 +10,7 @@
// expected-note@Inputs/category_left.h:14 {{previous definition}}
// expected-warning@Inputs/category_right.h:11 {{duplicate definition of category}}
+// expected-note@Inputs/category_top.h:1 {{receiver is instance of class declared here}}
@interface Foo(Source)
-(void)source;
diff --git a/test/Modules/odr.cpp b/test/Modules/odr.cpp
new file mode 100644
index 000000000000..5ab10d2ce419
--- /dev/null
+++ b/test/Modules/odr.cpp
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs/odr %s -verify -std=c++11
+
+// expected-error@a.h:8 {{'X::n' from module 'a' is not present in definition of 'X' provided earlier}}
+struct X { // expected-note {{definition has no member 'n'}}
+};
+
+@import a;
+@import b;
+
+// Trigger the declarations from a and b to be imported.
+int x = f() + g();
+
+// expected-note@a.h:5 {{definition has no member 'e2'}}
+// expected-note@a.h:3 {{declaration of 'f' does not match}}
+// expected-note@a.h:1 {{definition has no member 'm'}}
+
+// expected-error@b.h:5 {{'E::e2' from module 'b' is not present in definition of 'E' in module 'a'}}
+// expected-error@b.h:3 {{'Y::f' from module 'b' is not present in definition of 'Y' in module 'a'}}
+// expected-error@b.h:2 {{'Y::m' from module 'b' is not present in definition of 'Y' in module 'a'}}
diff --git a/test/Modules/pch-used.m b/test/Modules/pch-used.m
new file mode 100644
index 000000000000..56961ba404cc
--- /dev/null
+++ b/test/Modules/pch-used.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -x objective-c-header -emit-pch %S/Inputs/pch-used.h -o %t/pch-used.h.pch -fmodules -fmodules-cache-path=%t/cache -O0 -isystem %S/Inputs/System/usr/include
+// RUN: %clang_cc1 %s -include-pch %t/pch-used.h.pch -fmodules -fmodules-cache-path=%t/cache -O0 -isystem %S/Inputs/System/usr/include -emit-llvm -o - | FileCheck %s
+
+void f() { SPXTrace(); }
+
+// CHECK: define internal void @SPXTrace
diff --git a/test/Modules/private.cpp b/test/Modules/private.cpp
new file mode 100644
index 000000000000..93b4b9457f44
--- /dev/null
+++ b/test/Modules/private.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/private %s -verify
+
+#include "common.h"
+@import libPrivate1;
+#include "private1.h" // expected-error {{use of private header from outside its module}}
+#include "public2.h"
+#include "private2.h" // expected-error {{use of private header from outside its module}}
+
+struct use_this1 client_variable1;
+struct use_this2 client_variable2;
+struct mitts_off1 client_variable3;
+struct mitts_off2 client_variable4;
diff --git a/test/Modules/private1.cpp b/test/Modules/private1.cpp
new file mode 100644
index 000000000000..811a2333d1db
--- /dev/null
+++ b/test/Modules/private1.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/private0 -I %S/Inputs/private1 -I %S/Inputs/private2 %s -verify
+
+#include "common.h"
+@import libPrivateN2;
+#include "private1.h" // expected-error {{use of private header from outside its module}}
+#include "public2.h"
+#include "private2.h" // expected-error {{use of private header from outside its module}}
+
+struct use_this1 client_variable1;
+struct use_this2 client_variable2;
+struct mitts_off1 client_variable3;
+struct mitts_off2 client_variable4;
diff --git a/test/Modules/recursive_visibility.mm b/test/Modules/recursive_visibility.mm
new file mode 100644
index 000000000000..f37410aa44e1
--- /dev/null
+++ b/test/Modules/recursive_visibility.mm
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+// expected-no-diagnostics
+
+@import recursive_visibility_c;
+
+template<typename T> struct Z { typedef T type; };
+template void g<Z>();
diff --git a/test/Modules/requires.m b/test/Modules/requires.m
index 83b524d3935b..b8b2c55698c4 100644
--- a/test/Modules/requires.m
+++ b/test/Modules/requires.m
@@ -2,4 +2,5 @@
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
@import DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
-
+@import DependsOnModule.NotCXX;
+@import DependsOnModule.NotObjC; // expected-error{{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}}
diff --git a/test/Modules/requires.mm b/test/Modules/requires.mm
new file mode 100644
index 000000000000..736f2fab646a
--- /dev/null
+++ b/test/Modules/requires.mm
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %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'}}
diff --git a/test/Modules/self-import-header/af.framework/Headers/a1.h b/test/Modules/self-import-header/af.framework/Headers/a1.h
new file mode 100644
index 000000000000..31ae279bde2d
--- /dev/null
+++ b/test/Modules/self-import-header/af.framework/Headers/a1.h
@@ -0,0 +1,4 @@
+@import DepBuiltin;
+
+@interface Foo
+@end
diff --git a/test/Modules/self-import-header/af.framework/Headers/a2.h b/test/Modules/self-import-header/af.framework/Headers/a2.h
new file mode 100644
index 000000000000..cc7e6e20b667
--- /dev/null
+++ b/test/Modules/self-import-header/af.framework/Headers/a2.h
@@ -0,0 +1 @@
+#import "a1.h"
diff --git a/test/Modules/self-import-header/af.framework/module.map b/test/Modules/self-import-header/af.framework/module.map
new file mode 100644
index 000000000000..87176831df2d
--- /dev/null
+++ b/test/Modules/self-import-header/af.framework/module.map
@@ -0,0 +1,4 @@
+framework module af {
+ header "a1.h"
+ header "a2.h"
+}
diff --git a/test/Modules/self-import-header/depend_builtin/h1.h b/test/Modules/self-import-header/depend_builtin/h1.h
new file mode 100644
index 000000000000..13298efce877
--- /dev/null
+++ b/test/Modules/self-import-header/depend_builtin/h1.h
@@ -0,0 +1 @@
+#include <float.h>
diff --git a/test/Modules/self-import-header/depend_builtin/module.map b/test/Modules/self-import-header/depend_builtin/module.map
new file mode 100644
index 000000000000..a736ad85c136
--- /dev/null
+++ b/test/Modules/self-import-header/depend_builtin/module.map
@@ -0,0 +1,5 @@
+module DepBuiltin {
+header "h1.h"
+ export *
+}
+
diff --git a/test/Modules/self-import-header/test.m b/test/Modules/self-import-header/test.m
new file mode 100644
index 000000000000..377c01d66eb3
--- /dev/null
+++ b/test/Modules/self-import-header/test.m
@@ -0,0 +1,8 @@
+// rdar://13840148
+
+// RUN: rm -rf %t
+// RUN: %clang -fsyntax-only -isysroot %S/../Inputs/System/usr/include -fmodules -fmodules-cache-path=%t \
+// RUN: -target x86_64-darwin \
+// RUN: -F %S -I %S %s -D__need_wint_t -Werror=implicit-function-declaration
+
+@import af;
diff --git a/test/Modules/separate_map_tree.cpp b/test/Modules/separate_map_tree.cpp
new file mode 100644
index 000000000000..5a1fff4efc70
--- /dev/null
+++ b/test/Modules/separate_map_tree.cpp
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=A -fmodule-map-file=%S/Inputs/separate_map_tree/maps/modulea.map -I %S/Inputs/separate_map_tree/src %s -verify
+
+#include "common.h"
+#include "public-in-b.h" // expected-error {{private header}}
+#include "public-in-c.h"
+#include "private-in-c.h" // expected-error {{private header}}
+const int val = common + b + c + c_; // expected-error {{undeclared identifier}}
diff --git a/test/Modules/subframeworks.m b/test/Modules/subframeworks.m
index ad70cc2b22f8..5d70bc0840d5 100644
--- a/test/Modules/subframeworks.m
+++ b/test/Modules/subframeworks.m
@@ -5,7 +5,8 @@
@import DependsOnModule;
void testSubFramework() {
- float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}}
+ float *sf1 = sub_framework; // expected-error{{declaration of 'sub_framework' must be imported from module 'DependsOnModule.SubFramework' before it is required}}
+ // expected-note@Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h:2 {{previous}}
}
@import DependsOnModule.SubFramework;
diff --git a/test/Modules/submodules.cpp b/test/Modules/submodules.cpp
index 1b4f5d886e3b..9c62389eadc0 100644
--- a/test/Modules/submodules.cpp
+++ b/test/Modules/submodules.cpp
@@ -7,8 +7,9 @@
vector<int> vi;
// Note: remove_reference is not visible yet.
-remove_reference<int&>::type *int_ptr = 0; // expected-error{{unknown type name 'remove_reference'}} \
-// expected-error{{expected unqualified-id}}
+remove_reference<int&>::type *int_ptr = 0; // expected-error{{declaration of 'remove_reference' must be imported from module 'std.type_traits' before it is required}}
+// expected-note@Inputs/submodules/type_traits.h:2{{previous}}
+// expected-note@Inputs/submodules/hash_map.h:1{{previous}}
@import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
@@ -20,10 +21,16 @@ remove_reference<int&>::type *int_ptr2 = 0;
@import std; // import everything in 'std'
// hash_map still isn't available.
-hash_map<int, float> ints_to_floats; // expected-error{{unknown type name 'hash_map'}} \
-// expected-error{{expected unqualified-id}}
+hash_map<int, float> ints_to_floats; // expected-error{{declaration of 'hash_map' must be imported from module 'std.hash_map' before it is required}}
@import std.hash_map;
hash_map<int, float> ints_to_floats2;
+@import import_self.b;
+extern MyTypeA import_self_test_a; // expected-error {{must be imported from module 'import_self.a'}}
+// expected-note@import-self-a.h:1 {{here}}
+extern MyTypeC import_self_test_c;
+// FIXME: This should be valid; import_self.b re-exports import_self.d.
+extern MyTypeD import_self_test_d; // expected-error {{must be imported from module 'import_self.d'}}
+// expected-note@import-self-d.h:1 {{here}}
diff --git a/test/Modules/system_headers.m b/test/Modules/system_headers.m
new file mode 100644
index 000000000000..39b13ca5fc4a
--- /dev/null
+++ b/test/Modules/system_headers.m
@@ -0,0 +1,8 @@
+// Test that system-headerness works for building modules.
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -isystem %S/Inputs -pedantic -Werror %s -verify
+// expected-no-diagnostics
+
+@import warning;
+int i = bigger_than_int;
diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm
index 1fef967e400f..080f9e7c665e 100644
--- a/test/Modules/templates.mm
+++ b/test/Modules/templates.mm
@@ -1,11 +1,15 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | grep Emit | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | FileCheck %s
// expected-no-diagnostics
@import templates_left;
@import templates_right;
+// CHECK: @list_left = global { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 8,
+// CHECK: @list_right = global { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 12,
+// CHECK: @_ZZ15testMixedStructvE1l = {{.*}} constant { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 1,
+// CHECK: @_ZZ15testMixedStructvE1r = {{.*}} constant { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 2,
void testTemplateClasses() {
Vector<int> vec_int;
@@ -32,5 +36,34 @@ void testRedeclDefinition() {
redeclDefinitionEmit();
}
+// These three are all the same type.
+typedef OuterIntInner_left OuterIntInner;
+typedef OuterIntInner_right OuterIntInner;
+typedef Outer<int>::Inner OuterIntInner;
+
// CHECK: call {{.*pendingInstantiation}}
// CHECK: call {{.*redeclDefinitionEmit}}
+
+static_assert(size_left == size_right, "same field both ways");
+void useListInt(List<int> &);
+
+// CHECK-LABEL: define i32 @_Z15testMixedStructv(
+unsigned testMixedStruct() {
+ // CHECK: %[[l:.*]] = alloca %[[ListInt:[^ ]*]], align 8
+ // CHECK: %[[r:.*]] = alloca %[[ListInt]], align 8
+
+ // CHECK: call {{.*}}memcpy{{.*}}(i8* %{{.*}}, i8* bitcast ({{.*}}* @_ZZ15testMixedStructvE1l to i8*), i64 16,
+ ListInt_left l{0, 1};
+
+ // CHECK: call {{.*}}memcpy{{.*}}(i8* %{{.*}}, i8* bitcast ({{.*}}* @_ZZ15testMixedStructvE1r to i8*), i64 16,
+ ListInt_right r{0, 2};
+
+ // CHECK: call void @_Z10useListIntR4ListIiE(%[[ListInt]]* %[[l]])
+ useListInt(l);
+ // CHECK: call void @_Z10useListIntR4ListIiE(%[[ListInt]]* %[[r]])
+ useListInt(r);
+
+ // CHECK: load i32* bitcast (i8* getelementptr inbounds (i8* bitcast ({{.*}}* @list_left to i8*), i64 8) to i32*)
+ // CHECK: load i32* bitcast (i8* getelementptr inbounds (i8* bitcast ({{.*}}* @list_right to i8*), i64 8) to i32*)
+ return list_left.*size_right + list_right.*size_left;
+}
diff --git a/test/Modules/using-decl.cpp b/test/Modules/using-decl.cpp
new file mode 100644
index 000000000000..4432738f060a
--- /dev/null
+++ b/test/Modules/using-decl.cpp
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify
+
+@import using_decl.a;
+
+// expected-no-diagnostics
+UsingDecl::using_decl_type x = UsingDecl::using_decl_var;
+UsingDecl::inner y = x;
diff --git a/test/OpenMP/openmp_common.c b/test/OpenMP/openmp_common.c
index ca5d89a6629b..3765f4c5dc14 100644
--- a/test/OpenMP/openmp_common.c
+++ b/test/OpenMP/openmp_common.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
#pragma omp // expected-error {{expected an OpenMP directive}}
#pragma omp unknown_directive // expected-error {{expected an OpenMP directive}}
diff --git a/test/OpenMP/parallel_ast_print.cpp b/test/OpenMP/parallel_ast_print.cpp
new file mode 100644
index 000000000000..f2fd2f7b69f9
--- /dev/null
+++ b/test/OpenMP/parallel_ast_print.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+
+template <typename T>
+T tmain(T argc, T *argv) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+#pragma omp parallel
+ a=2;
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d)
+ foo();
+ return 0;
+}
+// CHECK: template <typename T = int> int tmain(int argc, int *argv) {
+// CHECK-NEXT: int b = argc, c, d, e, f, g;
+// CHECK-NEXT: static int a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T = float> float tmain(float argc, float *argv) {
+// CHECK-NEXT: float b = argc, c, d, e, f, g;
+// CHECK-NEXT: static float a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T> T tmain(T argc, T *argv) {
+// CHECK-NEXT: T b = argc, c, d, e, f, g;
+// CHECK-NEXT: static T a;
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
+// CHECK-NEXT: foo()
+
+int main (int argc, char **argv) {
+ float x;
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp parallel
+// CHECK-NEXT: #pragma omp parallel
+ a=2;
+// CHECK-NEXT: a = 2;
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv)
+// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv)
+ foo();
+// CHECK-NEXT: foo();
+ return tmain(b, &b) + tmain(x, &x);
+}
+
+#endif
diff --git a/test/OpenMP/parallel_default_messages.cpp b/test/OpenMP/parallel_default_messages.cpp
new file mode 100644
index 000000000000..cbc6a73fe35d
--- /dev/null
+++ b/test/OpenMP/parallel_default_messages.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
+
+void foo();
+
+int main(int argc, char **argv) {
+ #pragma omp parallel default // expected-error {{expected '(' after 'default'}}
+ #pragma omp parallel default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ #pragma omp parallel default (none // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel default (shared), default(shared) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'default' clause}}
+ #pragma omp parallel default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ foo();
+
+ #pragma omp parallel default(none)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ #pragma omp parallel default(none)
+ #pragma omp parallel default(shared)
+ ++argc;
+ return 0;
+}
diff --git a/test/OpenMP/parallel_firstprivate_messages.cpp b/test/OpenMP/parallel_firstprivate_messages.cpp
new file mode 100644
index 000000000000..780059e282bf
--- /dev/null
+++ b/test/OpenMP/parallel_firstprivate_messages.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ S2(S2 &s2):a(s2.a) { }
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+ S3(S3 &s3):a(s3.a) { }
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5():a(0) {}
+ S5(const S5 &s5):a(s5.a) { }
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = { 0 };
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ #pragma omp parallel firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel firstprivate () // expected-error {{expected expression}}
+ #pragma omp parallel firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ #pragma omp parallel firstprivate (argc)
+ #pragma omp parallel firstprivate (S1) // expected-error {{'S1' does not refer to a value}}
+ #pragma omp parallel firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ #pragma omp parallel firstprivate (argv[1]) // expected-error {{expected variable name}}
+ #pragma omp parallel firstprivate(ba)
+ #pragma omp parallel firstprivate(ca)
+ #pragma omp parallel firstprivate(da)
+ #pragma omp parallel firstprivate(S2::S2s)
+ #pragma omp parallel firstprivate(S2::S2sc)
+ #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+ #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ #pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
+ foo();
+ #pragma omp parallel shared(i)
+ #pragma omp parallel firstprivate(i)
+ #pragma omp parallel firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/parallel_messages.cpp b/test/OpenMP/parallel_messages.cpp
new file mode 100644
index 000000000000..d991ccfc3806
--- /dev/null
+++ b/test/OpenMP/parallel_messages.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s
+
+void foo() {
+}
+
+#pragma omp parallel // expected-error {{unexpected OpenMP directive '#pragma omp parallel'}}
+
+int main(int argc, char **argv) {
+ #pragma omp parallel
+ #pragma omp parallel unknown() // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
+ foo();
+ L1:
+ foo();
+ #pragma omp parallel
+ ;
+ #pragma omp parallel
+ {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ argc++;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ switch(argc) {
+ case (0):
+ #pragma omp parallel
+ {
+ foo();
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }
+ default:
+ break;
+ }
+ }
+ #pragma omp parallel default(none)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ #pragma omp parallel
+ L2:
+ foo();
+ #pragma omp parallel
+ {
+ return 1; // expected-error {{cannot return from OpenMP region}}
+ }
+
+ [[]] // expected-error {{an attribute list cannot appear here}}
+ #pragma omp parallel
+ for (int n = 0; n < 100; ++n) {}
+
+ return 0;
+}
+
diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp
new file mode 100644
index 000000000000..2037d56daf0c
--- /dev/null
+++ b/test/OpenMP/parallel_private_messages.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ static float S2s; // expected-note {{predetermined as shared}}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 c; // expected-note {{predetermined as shared}}
+const S3 ca[5]; // expected-note {{predetermined as shared}}
+extern const int f; // expected-note {{predetermined as shared}}
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+int threadvar;
+#pragma omp threadprivate(threadvar) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{predetermined as shared}}
+ const int da[5] = { 0 }; // expected-note {{predetermined as shared}}
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp parallel private // expected-error {{expected '(' after 'private'}}
+ #pragma omp parallel private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel private () // expected-error {{expected expression}}
+ #pragma omp parallel private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ #pragma omp parallel private (argc argv) // expected-error {{expected ',' or ')' in 'private' clause}}
+ #pragma omp parallel private (S1) // expected-error {{'S1' does not refer to a value}}
+ #pragma omp parallel private (a, b, c, d, f) // expected-error {{a private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}}
+ #pragma omp parallel private (argv[1]) // expected-error {{expected variable name}}
+ #pragma omp parallel private(ba)
+ #pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}}
+ #pragma omp parallel private(da) // expected-error {{shared variable cannot be private}}
+ #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
+ #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+ #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+ #pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
+ foo();
+ #pragma omp parallel firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
+ foo();
+ #pragma omp parallel private(i)
+ #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}}
+ foo();
+ #pragma omp parallel firstprivate(i)
+ for (int k = 0; k < 10; ++k) {
+ #pragma omp parallel private(i)
+ foo();
+ }
+
+ return 0;
+}
diff --git a/test/OpenMP/parallel_shared_messages.cpp b/test/OpenMP/parallel_shared_messages.cpp
new file mode 100644
index 000000000000..211d392fe04e
--- /dev/null
+++ b/test/OpenMP/parallel_shared_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ S2(S2 &s2):a(s2.a) { }
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+ S3(S3 &s3):a(s3.a) { }
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+ S5(const S5 &s5):a(s5.a) { }
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = { 0 };
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+ #pragma omp parallel shared // expected-error {{expected '(' after 'shared'}}
+ #pragma omp parallel shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel shared () // expected-error {{expected expression}}
+ #pragma omp parallel shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel shared (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel shared (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ #pragma omp parallel shared (argc)
+ #pragma omp parallel shared (S1) // expected-error {{'S1' does not refer to a value}}
+ #pragma omp parallel shared (a, b, c, d, f)
+ #pragma omp parallel shared (argv[1]) // expected-error {{expected variable name}}
+ #pragma omp parallel shared(ba)
+ #pragma omp parallel shared(ca)
+ #pragma omp parallel shared(da)
+ #pragma omp parallel shared(e, g)
+ #pragma omp parallel shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+ #pragma omp parallel private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
+ foo();
+ #pragma omp parallel firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}}
+ foo();
+ #pragma omp parallel private(i)
+ #pragma omp parallel shared(i)
+ #pragma omp parallel shared(j)
+ foo();
+ #pragma omp parallel firstprivate(i)
+ #pragma omp parallel shared(i)
+ #pragma omp parallel shared(j)
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/predefined_macro.c b/test/OpenMP/predefined_macro.c
index cf6c0cc61188..3a8118620962 100644
--- a/test/OpenMP/predefined_macro.c
+++ b/test/OpenMP/predefined_macro.c
@@ -31,4 +31,3 @@
#error "_OPENMP macro is defined without -fopenmp option"
#endif // _OPENMP
#endif // FOPENMP
-
diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp
index deb829e92673..72bf6f4077eb 100644
--- a/test/OpenMP/threadprivate_ast_print.cpp
+++ b/test/OpenMP/threadprivate_ast_print.cpp
@@ -1,5 +1,12 @@
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print
// expected-no-diagnostics
+// FIXME: This test has been crashing since r186647.
+// REQUIRES: disabled
+
+#ifndef HEADER
+#define HEADER
struct St{
int a;
@@ -10,7 +17,7 @@ struct St1{
static int b;
// CHECK: static int b;
#pragma omp threadprivate(b)
-// CHECK-NEXT: #pragma omp threadprivate(b)
+// CHECK-NEXT: #pragma omp threadprivate(St1::b)
} d;
int a, b;
@@ -33,6 +40,15 @@ template <class T> T foo() {
//CHECK-NEXT: static T v;
//CHECK-NEXT: #pragma omp threadprivate(v)
+namespace ns{
+ int a;
+}
+// CHECK: namespace ns {
+// CHECK-NEXT: int a;
+// CHECK-NEXT: }
+#pragma omp threadprivate(ns::a)
+// CHECK-NEXT: #pragma omp threadprivate(ns::a)
+
int main () {
static int a;
// CHECK: static int a;
@@ -41,3 +57,5 @@ int main () {
a=2;
return (foo<int>());
}
+
+#endif
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index 0c448b2ef27e..4858549a7038 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s
#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}}
-#pragma omp threadprivate( // expected-error {{expected unqualified-id}}
-#pragma omp threadprivate() // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp threadprivate() // expected-error {{expected identifier}}
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
struct CompleteSt{
int a;
@@ -11,29 +11,29 @@ struct CompleteSt{
struct CompleteSt1{
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
int a;
-} d; // expected-note {{forward declaration of 'd'}}
+} d; // expected-note {{'d' defined here}}
-int a; // expected-note {{forward declaration of 'a'}}
+int a; // expected-note {{'a' defined here}}
#pragma omp threadprivate(a)
#pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}}
#pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
int foo() { // expected-note {{declared here}}
static int l;
-#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
return (a);
}
#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
-#pragma omp threadprivate(d))
+#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
int x, y;
-#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(y)), // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
-#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(d.a) // expected-error {{expected identifier}}
#pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}}
-int foa;
+int foa; // expected-note {{'foa' declared here}}
#pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
#pragma omp threadprivate(foo) // expected-error {{'foo' is not a global variable, static local variable or static data member}}
#pragma omp threadprivate (int a=2) // expected-error {{expected unqualified-id}}
@@ -41,22 +41,22 @@ int foa;
struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}}
extern IncompleteSt e;
-#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}}
+#pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}}
-int &f = a; // expected-note {{forward declaration of 'f'}}
+int &f = a; // expected-note {{'f' defined here}}
#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}}
class Class {
private:
int a; // expected-note {{declared here}}
- static int b;
+ static int b; // expected-note {{'b' declared here}}
Class() : a(0){}
public:
Class (int aaa) : a(aaa) {}
#pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}}
} g(10);
#pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}}
-#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (Class::b) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'Class::b' variable declaration}}
#pragma omp threadprivate (g)
namespace ns {
@@ -64,8 +64,8 @@ namespace ns {
#pragma omp threadprivate (m)
}
#pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}}
-#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}}
-#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'ns::m'}}
+#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'ns::m'}}
const int h = 12;
const volatile int i = 10;
@@ -84,26 +84,30 @@ class TempClass {
};
#pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}}
-static __thread int t; // expected-note {{forward declaration of 't'}}
+static __thread int t; // expected-note {{'t' defined here}}
#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
int o; // expected-note {{candidate found by name lookup is 'o'}}
+#pragma omp threadprivate (o)
namespace {
int o; // expected-note {{candidate found by name lookup is '<anonymous namespace>::o'}}
+#pragma omp threadprivate (o)
+#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '<anonymous namespace>::o'}}
}
#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
+#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}}
-int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}}
+int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
- int x, y = argc; // expected-note {{forward declaration of 'y'}}
+ int x, y = argc; // expected-note {{'y' defined here}}
static double d1;
static double d2;
- static double d3; // expected-note {{forward declaration of 'd3'}}
+ static double d3; // expected-note {{'d3' defined here}}
d.a = a;
d2++;
;
-#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(argc+y) // expected-error {{expected identifier}}
#pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}}
#pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}}
#pragma omp threadprivate(d1)
diff --git a/test/PCH/Inputs/chain-selectors2.h b/test/PCH/Inputs/chain-selectors2.h
index 973fc107e90e..d54244de617b 100644
--- a/test/PCH/Inputs/chain-selectors2.h
+++ b/test/PCH/Inputs/chain-selectors2.h
@@ -1,6 +1,6 @@
@interface Y
-(void)f;
- -(double)f2;
+ -(void)f2;
-(void)e;
@end
diff --git a/test/PCH/arc.m b/test/PCH/arc.m
index 64b390c30715..466b31705596 100644
--- a/test/PCH/arc.m
+++ b/test/PCH/arc.m
@@ -6,9 +6,9 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm-only %s
// Test error when pch's -fobjc-arc state is different.
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=ERR1 %s
+// RUN: not %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR1 %s
// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -x objective-c-header -o %t %S/Inputs/arc.h
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=ERR2 %s
+// RUN: not %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR2 %s
array0 a0;
array1 a1;
diff --git a/test/PCH/badpch.c b/test/PCH/badpch.c
index f34e3d6a158b..c302329aaae8 100644
--- a/test/PCH/badpch.c
+++ b/test/PCH/badpch.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -include-pch %S/Inputs/badpch-empty.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-EMPTY %s
-// RUN: %clang_cc1 -fsyntax-only -include-pch %S/Inputs/badpch-dir.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-DIR %s
+// RUN: not %clang_cc1 -fsyntax-only -include-pch %S/Inputs/badpch-empty.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-EMPTY %s
+// RUN: not %clang_cc1 -fsyntax-only -include-pch %S/Inputs/badpch-dir.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-DIR %s
// The purpose of this test is to verify that various invalid PCH files are
// reported as such.
diff --git a/test/PCH/chain-categories2.m b/test/PCH/chain-categories2.m
index f230bf934858..50eea2a5606f 100644
--- a/test/PCH/chain-categories2.m
+++ b/test/PCH/chain-categories2.m
@@ -45,6 +45,7 @@
#else
//===----------------------------------------------------------------------===//
+// expected-note@30 {{receiver is instance of class declared here}}
void f(I* i) {
[i meth]; // expected-warning {{not found}}
}
diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp
index 4b64f51143df..6e9c1743fbd7 100644
--- a/test/PCH/chain-cxx.cpp
+++ b/test/PCH/chain-cxx.cpp
@@ -6,6 +6,9 @@
// With PCH
// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+// With modules
+// RUN: %clang_cc1 -fsyntax-only -verify -fmodules %s -chain-include %s -chain-include %s
+
// expected-no-diagnostics
#ifndef HEADER1
diff --git a/test/PCH/chain-friend-instantiation.cpp b/test/PCH/chain-friend-instantiation.cpp
index 294d97911236..2f042a8341ec 100644
--- a/test/PCH/chain-friend-instantiation.cpp
+++ b/test/PCH/chain-friend-instantiation.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -ast-print -o - -chain-include %s -chain-include %s
+// RUN: %clang_cc1 %s -ast-print -o - -fmodules -chain-include %s -chain-include %s
#if !defined(PASS1)
#define PASS1
diff --git a/test/PCH/chain-selectors.m b/test/PCH/chain-selectors.m
index 7eae094e1513..f2bfc4b9d3df 100644
--- a/test/PCH/chain-selectors.m
+++ b/test/PCH/chain-selectors.m
@@ -18,9 +18,9 @@ void bar() {
// FIXME: Can't verify notes in headers
//[a f2];
- (void)@selector(x); // expected-warning {{unimplemented selector}}
- (void)@selector(y); // expected-warning {{unimplemented selector}}
- (void)@selector(e); // expected-warning {{unimplemented selector}}
+ (void)@selector(x); // expected-warning {{creating selector for nonexistent method 'x'}}
+ (void)@selector(y); // expected-warning {{creating selector for nonexistent method 'y'}}
+ (void)@selector(e); // expected-warning {{creating selector for nonexistent method 'e'}}
}
@implementation X (Blah)
diff --git a/test/PCH/check-deserializations.cpp b/test/PCH/check-deserializations.cpp
index 9f73c95c541e..e4dafb7f54af 100644
--- a/test/PCH/check-deserializations.cpp
+++ b/test/PCH/check-deserializations.cpp
@@ -1,20 +1,34 @@
-// RUN: %clang_cc1 -emit-pch -o %t %s
-// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -emit-llvm-only %s
+// RUN: %clang_cc1 -emit-pch -o %t.1 %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_keyfunc -error-on-deserialized-decl S3 -include-pch %t.1 -emit-pch -o %t.2 %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -error-on-deserialized-decl S3 -include-pch %t.2 -emit-llvm-only %s
-#ifndef HEADER
-#define HEADER
+#ifndef HEADER1
+#define HEADER1
// Header.
struct S1 {
- void S1_method(); // This should not be deserialized.
+ void S1_method();
virtual void S1_keyfunc();
};
+struct S3 {};
+
+struct S2 {
+ operator S3();
+};
+
+#elif !defined(HEADER2)
+#define HEADER2
+
+// Chained PCH.
+S1 *s1;
+S2 *s2;
#else
-// Using the header.
-void test(S1*) {
+// Using the headers.
+
+void test(S1*, S2*) {
}
#endif
diff --git a/test/PCH/cxx-friends.cpp b/test/PCH/cxx-friends.cpp
index f7d45cea8df4..9c75f92f34d6 100644
--- a/test/PCH/cxx-friends.cpp
+++ b/test/PCH/cxx-friends.cpp
@@ -3,7 +3,11 @@
// Test with pch.
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize
+
+// Test with modules.
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h -fmodules
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize -fmodules
// expected-no-diagnostics
@@ -21,3 +25,5 @@ public:
}
};
int k = PR12585::future_base::setter<int>().f();
+
+Lazy::S *p;
diff --git a/test/PCH/cxx-friends.h b/test/PCH/cxx-friends.h
index 05dcc9606636..2d20a4d26978 100644
--- a/test/PCH/cxx-friends.h
+++ b/test/PCH/cxx-friends.h
@@ -16,3 +16,28 @@ namespace PR12585 {
int k;
};
}
+
+namespace Lazy {
+ struct S {
+ friend void doNotDeserialize();
+ };
+}
+
+// Reduced testcase from libc++'s <valarray>. Used to crash with modules
+// enabled.
+namespace std {
+
+template <class T> struct valarray;
+
+template <class T> struct valarray {
+ valarray();
+ template <class U> friend struct valarray;
+ template <class U> friend U *begin(valarray<U> &v);
+};
+
+struct gslice {
+ valarray<int> size;
+ gslice() {}
+};
+
+}
diff --git a/test/PCH/cxx-member-init.cpp b/test/PCH/cxx-member-init.cpp
index 20594d532e33..78fd74425b84 100644
--- a/test/PCH/cxx-member-init.cpp
+++ b/test/PCH/cxx-member-init.cpp
@@ -13,6 +13,15 @@ struct S {
S *that = this;
};
template<typename T> struct X { T t {0}; };
+
+struct v_t { };
+
+struct m_t
+{
+ struct { v_t v; };
+ m_t() { }
+};
+
#endif
#ifdef SOURCE
@@ -20,6 +29,11 @@ S s;
struct E { explicit E(int); };
X<E> x;
+
+m_t *test() {
+ return new m_t;
+}
+
#elif HEADER
#undef HEADER
#define SOURCE
diff --git a/test/PCH/cxx-namespaces.cpp b/test/PCH/cxx-namespaces.cpp
index e0ff27c020c4..e0feaab6910a 100644
--- a/test/PCH/cxx-namespaces.cpp
+++ b/test/PCH/cxx-namespaces.cpp
@@ -3,10 +3,23 @@
// Test with pch.
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-namespaces.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -ast-dump -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
+
+// Test with modules.
+// RUN: %clang_cc1 -fmodules -x c++-header -emit-pch -o %t %S/cxx-namespaces.h
+// RUN: %clang_cc1 -fmodules -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fmodules -include-pch %t -fsyntax-only -ast-dump -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
// expected-no-diagnostics
void m() {
N::x = 0;
+ N::f();
}
+
+// namespace 'N' should contain only two declarations of 'f'.
+
+// CHECK: DeclarationName 'f'
+// CHECK-NEXT: |-Function {{.*}} 'f' 'void (
+// CHECK-NEXT: `-Function {{.*}} 'f' 'void (
diff --git a/test/PCH/cxx-namespaces.h b/test/PCH/cxx-namespaces.h
index f3389533d001..26d75a079d92 100644
--- a/test/PCH/cxx-namespaces.h
+++ b/test/PCH/cxx-namespaces.h
@@ -4,4 +4,7 @@ namespace N {
namespace {
int x;
}
+
+ void f();
+ void f(int);
}
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index 58c4c177fd21..e5ddd86e3802 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,13 +1,21 @@
// Test this without pch.
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
-// expected-no-diagnostics
+// Test with modules.
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
+
+// Test with pch and delayed template parsing.
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// CHECK: define weak_odr void @_ZN2S4IiE1mEv
// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
@@ -85,3 +93,18 @@ namespace rdar13135282 {
__mt_alloc<> mt = __mt_alloc<>();
}
}
+
+void CallDependentSpecializedFunc(DependentSpecializedFuncClass<int> &x) {
+ DependentSpecializedFunc(x);
+}
+
+namespace cyclic_module_load {
+ extern std::valarray<int> x;
+ std::valarray<int> y(x);
+}
+
+#ifndef NO_ERRORS
+// expected-error@cxx-templates.h:305 {{incomplete}}
+template int local_extern::f<int[]>(); // expected-note {{in instantiation of}}
+#endif
+template int local_extern::g<int[]>();
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index e672b0b38733..992f478e33e6 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -269,3 +269,45 @@ template<typename T> struct ContainsDoNotDeserialize2 {
};
template<typename T> int ContainsDoNotDeserialize<T>::doNotDeserialize = 0;
template<typename T> void ContainsDoNotDeserialize2<T>::doNotDeserialize() {}
+
+
+template<typename T> void DependentSpecializedFunc(T x) { x.foo(); }
+template<typename T> class DependentSpecializedFuncClass {
+ void foo() {}
+ friend void DependentSpecializedFunc<>(DependentSpecializedFuncClass);
+};
+
+namespace cyclic_module_load {
+ // Reduced from a libc++ modules crasher.
+ namespace std {
+ template<class> class mask_array;
+ template<class> class valarray {
+ public:
+ valarray(const valarray &v);
+ };
+
+ class gslice {
+ valarray<int> x;
+ valarray<int> stride() const { return x; }
+ };
+
+ template<class> class mask_array {
+ template<class> friend class valarray;
+ };
+ }
+}
+
+namespace local_extern {
+ template<typename T> int f() {
+ extern int arr[3];
+ {
+ extern T arr;
+ return sizeof(arr);
+ }
+ }
+ template<typename T> int g() {
+ extern int arr[3];
+ extern T arr;
+ return sizeof(arr);
+ }
+}
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index 938f36f2c279..ffdfccc6f47f 100644
--- a/test/PCH/cxx-traits.cpp
+++ b/test/PCH/cxx-traits.cpp
@@ -2,9 +2,11 @@
// RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
-// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
+#ifdef PCH
// expected-no-diagnostics
+#endif
bool _Is_pod_comparator = __is_pod<int>::__value;
bool _Is_empty_check = __is_empty<int>::__value;
diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h
index 8b62002789d6..836804ef2c88 100644
--- a/test/PCH/cxx-traits.h
+++ b/test/PCH/cxx-traits.h
@@ -1,12 +1,12 @@
// Header for PCH test cxx-traits.cpp
template<typename _Tp>
-struct __is_pod {
+struct __is_pod { // expected-warning {{keyword '__is_pod' will be treated as an identifier for the remainder of the translation unit}}
enum { __value };
};
template<typename _Tp>
-struct __is_empty {
+struct __is_empty { // expected-warning {{keyword '__is_empty' will be treated as an identifier for the remainder of the translation unit}}
enum { __value };
};
diff --git a/test/PCH/cxx-typeid.cpp b/test/PCH/cxx-typeid.cpp
index 534863af21b1..6e622206521c 100644
--- a/test/PCH/cxx-typeid.cpp
+++ b/test/PCH/cxx-typeid.cpp
@@ -1,8 +1,8 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-typeid.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %S/cxx-typeid.h -fsyntax-only -stdlib=libstdc++ -verify %s
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t.pch %S/cxx-typeid.h
-// RUN: %clang_cc1 -include-pch %t.pch -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++-header -emit-pch -stdlib=libstdc++ -o %t.pch %S/cxx-typeid.h
+// RUN: %clang_cc1 -include-pch %t.pch -fsyntax-only -stdlib=libstdc++ -verify %s
// expected-no-diagnostics
diff --git a/test/PCH/cxx11-lambdas.mm b/test/PCH/cxx11-lambdas.mm
index c00ec6380752..c4550517bb1e 100644
--- a/test/PCH/cxx11-lambdas.mm
+++ b/test/PCH/cxx11-lambdas.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++11 -emit-pch %s -o %t-cxx11
-// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++11 -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++1y -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++1y -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
#ifndef HEADER_INCLUDED
@@ -33,6 +33,11 @@ inline int to_block_pointer(int n) {
return block(17);
}
+template<typename T>
+int init_capture(T t) {
+ return [&, x(t)] { return sizeof(x); };
+}
+
#else
// CHECK-PRINT: T add_slowly
@@ -45,4 +50,8 @@ int add(int x, int y) {
// CHECK-PRINT: inline int add_int_slowly_twice
// CHECK-PRINT: lambda = [&] (int z)
+
+// CHECK-PRINT: init_capture
+// CHECK-PRINT: [&, x( t )]
+
#endif
diff --git a/test/PCH/cxx1y-deduced-return-type.cpp b/test/PCH/cxx1y-deduced-return-type.cpp
new file mode 100644
index 000000000000..a61dda21e7f9
--- /dev/null
+++ b/test/PCH/cxx1y-deduced-return-type.cpp
@@ -0,0 +1,34 @@
+// No PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -include %s -verify %s
+//
+// With chained PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t.a
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch %s -o %t.b
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s
+
+// expected-no-diagnostics
+
+#if !defined(HEADER1)
+#define HEADER1
+
+auto &f(int &);
+
+template<typename T> decltype(auto) g(T &t) {
+ return f(t);
+}
+
+#elif !defined(HEADER2)
+#define HEADER2
+
+// Ensure that this provides an update record for the type of HEADER1's 'f',
+// so that HEADER1's 'g' can successfully call it.
+auto &f(int &n) {
+ return n;
+}
+
+#else
+
+int n;
+int &k = g(n);
+
+#endif
diff --git a/test/PCH/cxx1y-init-captures.cpp b/test/PCH/cxx1y-init-captures.cpp
new file mode 100644
index 000000000000..3c8fc149d84b
--- /dev/null
+++ b/test/PCH/cxx1y-init-captures.cpp
@@ -0,0 +1,28 @@
+// No PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -verify %s
+//
+// With PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
+
+#ifndef HEADER
+#define HEADER
+
+auto counter = [a(0)] () mutable { return a++; };
+int x = counter();
+
+template<typename T> void f(T t) {
+ [t(t)] { int n = t; } ();
+}
+
+#else
+
+int y = counter();
+
+void g() {
+ f(0); // ok
+ // expected-error@15 {{lvalue of type 'const char *const'}}
+ f("foo"); // expected-note {{here}}
+}
+
+#endif
diff --git a/test/PCH/cxx1y-lambdas.mm b/test/PCH/cxx1y-lambdas.mm
new file mode 100644
index 000000000000..ee4a2ba3ecc9
--- /dev/null
+++ b/test/PCH/cxx1y-lambdas.mm
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++1y -emit-pch %s -o %t-cxx1y
+// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++1y -include-pch %t-cxx1y %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+template<typename T>
+T add_slowly(const T& x, const T &y) {
+ return [](auto z, int y = 0) { return z + y; }(5);
+};
+
+inline int add_int_slowly_twice(int x, int y) {
+ int i = add_slowly(x, y);
+ auto lambda = [](auto z) { return z + z; };
+ return i + lambda(y);
+}
+
+inline int sum_array(int n) {
+ auto lambda = [](auto N) -> int {
+ int sum = 0;
+ int array[5] = { 1, 2, 3, 4, 5};
+
+ for (unsigned I = 0; I < N; ++I)
+ sum += array[N];
+ return sum;
+ };
+
+ return lambda(n);
+}
+
+inline int to_block_pointer(int n) {
+ auto lambda = [=](int m) { return n + m; };
+ int (^block)(int) = lambda;
+ return block(17);
+}
+
+template<typename T>
+int init_capture(T t) {
+ return [&, x(t)] { return sizeof(x); };
+}
+
+#else
+
+// CHECK-PRINT: T add_slowly
+// CHECK-PRINT: return []
+template float add_slowly(const float&, const float&);
+
+int add(int x, int y) {
+ return add_int_slowly_twice(x, y) + sum_array(4) + to_block_pointer(5);
+}
+
+// CHECK-PRINT: inline int add_int_slowly_twice
+// CHECK-PRINT: lambda = [] ($auto-0-0 z
+
+// CHECK-PRINT: init_capture
+// CHECK-PRINT: [&, x( t )]
+
+#endif
diff --git a/test/PCH/cxx1y-variable-templates.cpp b/test/PCH/cxx1y-variable-templates.cpp
new file mode 100644
index 000000000000..77eeea22a23d
--- /dev/null
+++ b/test/PCH/cxx1y-variable-templates.cpp
@@ -0,0 +1,171 @@
+// No PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -include %s -verify %s -DNONPCH
+// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -include %s -verify %s -DNONPCH -DERROR
+//
+// With PCH:
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t.a -DHEADER1
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch %s -o %t.b -DHEADER2
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s -DHEADERUSE
+
+#ifndef ERROR
+// expected-no-diagnostics
+#endif
+
+#ifdef NONPCH
+#if !defined(HEADER1)
+#define HEADER1
+#undef HEADER2
+#undef HEADERUSE
+#elif !defined(HEADER2)
+#define HEADER2
+#undef HEADERUSE
+#else
+#define HEADERUSE
+#undef HEADER1
+#undef HEADER2
+#endif
+#endif
+
+
+// *** HEADER1: First header file
+#if defined(HEADER1) && !defined(HEADER2) && !defined(HEADERUSE)
+
+template<typename T> T var0a = T();
+template<typename T> extern T var0b;
+
+namespace join {
+ template<typename T> T va = T(100);
+ template<typename T> extern T vb;
+
+ namespace diff_types {
+#ifdef ERROR
+ template<typename T> extern float err0;
+ template<typename T> extern T err1;
+#endif
+ template<typename T> extern T def;
+ }
+
+}
+
+namespace spec {
+ template<typename T> constexpr T va = T(10);
+ template<> constexpr float va<float> = 1.5;
+ template constexpr int va<int>;
+
+ template<typename T> T vb = T();
+ template<> constexpr float vb<float> = 1.5;
+
+ template<typename T> T vc = T();
+
+ template<typename T> constexpr T vd = T(10);
+ template<typename T> T* vd<T*> = new T();
+}
+
+namespace spec_join1 {
+ template<typename T> T va = T(10);
+ template<> extern float va<float>;
+ extern template int va<int>;
+
+ template<typename T> T vb = T(10);
+ template<> extern float vb<float>;
+
+ template<typename T> T vc = T(10);
+
+ template<typename T> T vd = T(10);
+ template<typename T> extern T* vd<T*>;
+}
+
+#endif
+
+
+// *** HEADER2: Second header file -- including HEADER1
+#if defined(HEADER2) && !defined(HEADERUSE)
+
+namespace join {
+ template<typename T> extern T va;
+ template<> constexpr float va<float> = 2.5;
+
+ template<typename T> T vb = T(100);
+
+ namespace diff_types {
+#ifdef ERROR
+ template<typename T> extern T err0; // expected-error {{redefinition of 'err0' with a different type: 'T' vs 'float'}} // expected-note@42 {{previous definition is here}}
+ template<typename T> extern float err1; // expected-error {{redefinition of 'err1' with a different type: 'float' vs 'T'}} // expected-note@43 {{previous definition is here}}
+#endif
+ template<typename T> extern T def;
+ }
+}
+
+namespace spec_join1 {
+ template<typename T> extern T va;
+ template<> float va<float> = 1.5;
+ extern template int va<int>;
+
+ template<> float vb<float> = 1.5;
+ template int vb<int>;
+
+ template<> float vc<float> = 1.5;
+ template int vc<int>;
+
+ template<typename T> extern T vd;
+ template<typename T> T* vd<T*> = new T();
+}
+
+#endif
+
+// *** HEADERUSE: File using both header files -- including HEADER2
+#ifdef HEADERUSE
+
+template int var0a<int>;
+float fvara = var0a<float>;
+
+template<typename T> extern T var0a;
+
+template<typename T> T var0b = T();
+template int var0b<int>;
+float fvarb = var0b<float>;
+
+namespace join {
+ template const int va<const int>;
+ template<> const int va<int> = 50;
+ static_assert(va<float> == 2.5, "");
+ static_assert(va<int> == 50, "");
+
+ template<> constexpr float vb<float> = 2.5;
+ template const int vb<const int>;
+ static_assert(vb<float> == 2.5, "");
+ static_assert(vb<const int> == 100, "");
+
+ namespace diff_types {
+ template<typename T> T def = T();
+ }
+
+}
+
+namespace spec {
+ static_assert(va<float> == 1.5, "");
+ static_assert(va<int> == 10, "");
+
+ template<typename T> T* vb<T*> = new T();
+ int* intpb = vb<int*>;
+ static_assert(vb<float> == 1.5, "");
+
+ template<typename T> T* vc<T*> = new T();
+ template<> constexpr float vc<float> = 1.5;
+ int* intpc = vc<int*>;
+ static_assert(vc<float> == 1.5, "");
+
+ char* intpd = vd<char*>;
+}
+
+namespace spec_join1 {
+ template int va<int>;
+ int a = va<int>;
+
+ template<typename T> extern T vb;
+ int b = vb<int>;
+
+ int* intpb = vd<int*>;
+}
+
+#endif
diff --git a/test/PCH/debug-info-limited-struct.c b/test/PCH/debug-info-limited-struct.c
new file mode 100644
index 000000000000..9d0ed26f34cf
--- /dev/null
+++ b/test/PCH/debug-info-limited-struct.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-pch -o %t %S/debug-info-limited-struct.h
+// RUN: %clang_cc1 -include-pch %t -emit-llvm %s -g -o - | FileCheck %s
+
+// CHECK-DAG: [ DW_TAG_structure_type ] [foo] {{.*}} [def]
diff --git a/test/PCH/debug-info-limited-struct.h b/test/PCH/debug-info-limited-struct.h
new file mode 100644
index 000000000000..593e722ce9c0
--- /dev/null
+++ b/test/PCH/debug-info-limited-struct.h
@@ -0,0 +1,8 @@
+struct foo {
+ int i;
+};
+
+void func() {
+ struct foo *f;
+ f->i = 3;
+}
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
index d08b1f64edec..d6735a727a53 100644
--- a/test/PCH/exprs.h
+++ b/test/PCH/exprs.h
@@ -102,6 +102,10 @@ typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
// ShuffleVectorExpr
typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
+// ConvertVectorExpr
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef typeof(__builtin_convertvector(vec2, float2)) convert_expr;
+
// GenericSelectionExpr
typedef typeof(_Generic(i, char*: 0, int: 0., default: hello))
generic_selection_expr;
diff --git a/test/PCH/external-defs.c b/test/PCH/external-defs.c
index 5097859297a5..5c2582a9c361 100644
--- a/test/PCH/external-defs.c
+++ b/test/PCH/external-defs.c
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s
// RUN: grep "@x = common global i32 0" %t | count 1
-// RUN: grep "@z" %t | count 0
+// RUN: not grep "@z" %t
// RUN: grep "@x2 = global i32 19" %t | count 1
int x2 = 19;
diff --git a/test/PCH/floating-literal.c b/test/PCH/floating-literal.c
index 7bf10d4e7981..738e45a41517 100644
--- a/test/PCH/floating-literal.c
+++ b/test/PCH/floating-literal.c
@@ -7,12 +7,12 @@
// targets with 128-bit IEEE long doubles.
long double foo = 1.0E4000L;
-// CHECK: long double foo = 1.0E+4000L;
+// CHECK: long double foo = 1.00000000000000000000000000000000004E+4000L;
// Just as well check the others are still sane while we're here...
double bar = 1.0E300;
-// CHECK: double bar = 1.0E+300;
+// CHECK: double bar = 1.0000000000000001E+300;
float wibble = 1.0E40;
// CHECK: float wibble = 1.0E+40;
diff --git a/test/PCH/irgen-rdar13114142.mm b/test/PCH/irgen-rdar13114142.mm
index bd523c29cf32..7a9cfba942d8 100644
--- a/test/PCH/irgen-rdar13114142.mm
+++ b/test/PCH/irgen-rdar13114142.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -emit-pch -o %t.pch
-// RUN: %clang_cc1 %s -emit-llvm %s -include-pch %t.pch -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -include-pch %t.pch -o - | FileCheck %s
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/line-directive.c b/test/PCH/line-directive.c
index 4710c40d7234..7d59c62763c3 100644
--- a/test/PCH/line-directive.c
+++ b/test/PCH/line-directive.c
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/line-directive.h -fsyntax-only %s 2>&1|grep "25:5"
+// RUN: not %clang_cc1 -include %S/line-directive.h -fsyntax-only %s 2>&1|grep "25:5"
// Test with pch.
// RUN: %clang_cc1 -emit-pch -o %t %S/line-directive.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s 2>&1|grep "25:5"
+// RUN: not %clang_cc1 -include-pch %t -fsyntax-only %s 2>&1|grep "25:5"
double x; // expected-error{{redefinition of 'x' with a different type}}
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
index 4ad3fafff4d9..8ab38e1e9e98 100644
--- a/test/PCH/modified-header-error.c
+++ b/test/PCH/modified-header-error.c
@@ -4,7 +4,7 @@
// RUN: cp %s %t.dir/t.c
// RUN: %clang_cc1 -x c-header %t.dir/header1.h -emit-pch -o %t.pch
// RUN: echo >> %t.dir/header2.h
-// RUN: %clang_cc1 %t.dir/t.c -include-pch %t.pch -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %t.dir/t.c -include-pch %t.pch -fsyntax-only 2>&1 | FileCheck %s
#include "header2.h"
diff --git a/test/PCH/objc_container.m b/test/PCH/objc_container.m
index aafe6a96ab13..0f25d3252c68 100644
--- a/test/PCH/objc_container.m
+++ b/test/PCH/objc_container.m
@@ -4,8 +4,8 @@
// Test with pch.
// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_container.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
-// RUN: %clang_cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=PRINT %s
-// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+// RUN: %clang_cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-IR %s
// expected-no-diagnostics
diff --git a/test/PCH/objc_import.h b/test/PCH/objc_import.h
index 8af87ab25c7d..4646e16a2cdb 100644
--- a/test/PCH/objc_import.h
+++ b/test/PCH/objc_import.h
@@ -5,3 +5,14 @@
- (void)instMethod;
@end
+@class NewID1;
+@compatibility_alias OldID1 NewID1;
+@class OldID1;
+@class OldID1;
+
+@class NewID2;
+@compatibility_alias OldID2 NewID2;
+@class OldID2;
+@interface OldID2
+-(void)meth;
+@end
diff --git a/test/PCH/objc_import.m b/test/PCH/objc_import.m
index c7dd805b3e47..724c8221848b 100644
--- a/test/PCH/objc_import.m
+++ b/test/PCH/objc_import.m
@@ -15,3 +15,18 @@ void func() {
xx = [TestPCH alloc];
[xx instMethod];
}
+
+// rdar://14112291
+@class NewID1;
+void foo1(NewID1 *p);
+void bar1(OldID1 *p) {
+ foo1(p);
+}
+@class NewID2;
+void foo2(NewID2 *p) {
+ [p meth];
+}
+void bar2(OldID2 *p) {
+ foo2(p);
+ [p meth];
+}
diff --git a/test/PCH/objc_literals.m b/test/PCH/objc_literals.m
index b73c3bebb8c4..f96d4afe2aa0 100644
--- a/test/PCH/objc_literals.m
+++ b/test/PCH/objc_literals.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-pch -o %t %s
// RUN: %clang_cc1 -include-pch %t -verify %s
-// RUN: %clang_cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=PRINT %s
-// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+// RUN: %clang_cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-IR %s
// expected-no-diagnostics
@@ -44,18 +44,18 @@ static inline void test_numeric_literals() {
// CHECK-PRINT: id intlit = @17
// CHECK-IR: {{call.*17}}
id intlit = @17;
- // CHECK-PRINT: id floatlit = @17.45
+ // CHECK-PRINT: id floatlit = @17.449999999999999
// CHECK-IR: {{call.*1.745}}
id floatlit = @17.45;
}
static inline void test_array_literals() {
- // CHECK-PRINT: id arraylit = @[ @17, @17.45
+ // CHECK-PRINT: id arraylit = @[ @17, @17.449999999999999
id arraylit = @[@17, @17.45];
}
static inline void test_dictionary_literals() {
- // CHECK-PRINT: id dictlit = @{ @17 : {{@17.45[^,]*}}, @"hello" : @"world" };
+ // CHECK-PRINT: id dictlit = @{ @17 : {{@17.449999999999999[^,]*}}, @"hello" : @"world" };
id dictlit = @{@17 : @17.45, @"hello" : @"world" };
}
diff --git a/test/PCH/objc_literals.mm b/test/PCH/objc_literals.mm
index ef95294d7aa7..59f33815a2b8 100644
--- a/test/PCH/objc_literals.mm
+++ b/test/PCH/objc_literals.mm
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-pch -x objective-c++ -std=c++0x -o %t %s
// RUN: %clang_cc1 -include-pch %t -x objective-c++ -std=c++0x -verify %s
-// RUN: %clang_cc1 -include-pch %t -x objective-c++ -std=c++0x -ast-print %s | FileCheck -check-prefix=PRINT %s
-// RUN: %clang_cc1 -include-pch %t -x objective-c++ -std=c++0x -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+// RUN: %clang_cc1 -include-pch %t -x objective-c++ -std=c++0x -ast-print %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -include-pch %t -x objective-c++ -std=c++0x -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-IR %s
// expected-no-diagnostics
diff --git a/test/PCH/objcxx-ivar-class.mm b/test/PCH/objcxx-ivar-class.mm
index 821495747d46..a83d7e74d758 100644
--- a/test/PCH/objcxx-ivar-class.mm
+++ b/test/PCH/objcxx-ivar-class.mm
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/objcxx-ivar-class.h -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: not %clang_cc1 -include %S/objcxx-ivar-class.h -verify %s -emit-llvm -o - | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -x objective-c++-header -emit-pch -o %t %S/objcxx-ivar-class.h
-// RUN: %clang_cc1 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: not %clang_cc1 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// CHECK: [C position]
// CHECK: call {{.*}} @_ZN1SC1ERKS_
diff --git a/test/PCH/pch-dir.c b/test/PCH/pch-dir.c
index ae841ce0a7a4..2ac10ea56c92 100644
--- a/test/PCH/pch-dir.c
+++ b/test/PCH/pch-dir.c
@@ -3,14 +3,14 @@
// RUN: %clang -x c-header %S/pch-dir.h -DFOO=bar -o %t.h.gch/cbar.gch
// RUN: %clang -x c++-header -std=c++98 %S/pch-dir.h -o %t.h.gch/cpp.gch
// RUN: %clang -include %t.h -DFOO=foo -fsyntax-only %s -Xclang -print-stats 2> %t.clog
-// RUN: FileCheck -check-prefix=C %s < %t.clog
+// RUN: FileCheck -check-prefix=CHECK-C %s < %t.clog
// RUN: %clang -include %t.h -DFOO=bar -DBAR=bar -fsyntax-only %s -Xclang -ast-print > %t.cbarlog
-// RUN: FileCheck -check-prefix=CBAR %s < %t.cbarlog
+// RUN: FileCheck -check-prefix=CHECK-CBAR %s < %t.cbarlog
// RUN: %clang -x c++ -include %t.h -std=c++98 -fsyntax-only %s -Xclang -print-stats 2> %t.cpplog
-// RUN: FileCheck -check-prefix=CPP %s < %t.cpplog
+// RUN: FileCheck -check-prefix=CHECK-CPP %s < %t.cpplog
// RUN: not %clang -x c++ -std=c++11 -include %t.h -fsyntax-only %s 2> %t.cpp11log
-// RUN: FileCheck -check-prefix=CPP11 %s < %t.cpp11log
+// RUN: FileCheck -check-prefix=CHECK-CPP11 %s < %t.cpp11log
// CHECK-CBAR: int bar
int FOO;
diff --git a/test/PCH/pragma-diag-section.cpp b/test/PCH/pragma-diag-section.cpp
index 627156f15398..eea6bd73f546 100644
--- a/test/PCH/pragma-diag-section.cpp
+++ b/test/PCH/pragma-diag-section.cpp
@@ -1,20 +1,20 @@
// Test this without pch.
-// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -Wuninitialized
// Test with pch.
// RUN: %clang_cc1 %s -emit-pch -o %t
-// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only
+// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only -Wuninitialized
#ifndef HEADER
#define HEADER
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wtautological-compare"
+#pragma clang diagnostic ignored "-Wuninitialized"
template <typename T>
struct TS1 {
void m() {
- T a = 0;
- T b = a==a;
+ T a;
+ T b = a;
}
};
#pragma clang diagnostic pop
@@ -25,8 +25,10 @@ struct TS1 {
template <typename T>
struct TS2 {
void m() {
- T a = 0;
- T b = a==a; // expected-warning {{self-comparison always evaluates to true}} expected-note@39 {{in instantiation of member function}}
+ T a;
+ T b = a; // expected-warning {{variable 'a' is uninitialized}} \
+ expected-note@41 {{in instantiation of member function}} \
+ expected-note@28 {{initialize the variable 'a' to silence}}
}
};
diff --git a/test/PCH/pragma-weak.c b/test/PCH/pragma-weak.c
index 18b45c889d12..1a8724c35cd7 100644
--- a/test/PCH/pragma-weak.c
+++ b/test/PCH/pragma-weak.c
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/pragma-weak.h %s -verify -emit-llvm -o - | FileCheck %s
+// RUN: not %clang_cc1 -include %S/pragma-weak.h %s -verify -emit-llvm -o - | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -x c-header -emit-pch -o %t %S/pragma-weak.h
-// RUN: %clang_cc1 -include-pch %t %s -verify -emit-llvm -o - | FileCheck %s
+// RUN: not %clang_cc1 -include-pch %t %s -verify -emit-llvm -o - | FileCheck %s
// CHECK: @weakvar = weak global i32 0
int weakvar;
diff --git a/test/PCH/preamble.c b/test/PCH/preamble.c
index 6a61fa10ffa1..7344f54453eb 100644
--- a/test/PCH/preamble.c
+++ b/test/PCH/preamble.c
@@ -1,7 +1,7 @@
// Check that using the preamble option actually skips the preamble.
// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h -DFOO=f
-// RUN: %clang_cc1 -include-pch %t -preamble-bytes=317,1 -DFOO=f -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: not %clang_cc1 -include-pch %t -preamble-bytes=317,1 -DFOO=f -verify %s -emit-llvm -o - | FileCheck %s
float f(int); // Not an error, because we skip this via the preamble!
diff --git a/test/PCH/pth.c b/test/PCH/pth.c
index 1262f8aebd70..6f2e4fc7b53c 100644
--- a/test/PCH/pth.c
+++ b/test/PCH/pth.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o %t %S/pth.h
-// RUN: %clang_cc1 -triple i386-unknown-unknown -include-pth %t -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple i386-unknown-unknown -include-pth %t -fsyntax-only %s 2>&1 | FileCheck %s
#error This is the only diagnostic
// CHECK: This is the only diagnostic
-// CHECK: 1 error generated. \ No newline at end of file
+// CHECK: 1 error generated.
diff --git a/test/PCH/rdar10830559.cpp b/test/PCH/rdar10830559.cpp
index b9b643741d78..aa19da43a34e 100644
--- a/test/PCH/rdar10830559.cpp
+++ b/test/PCH/rdar10830559.cpp
@@ -8,7 +8,7 @@
// rdar://10830559
-#pragma ms_struct on
+//#pragma ms_struct on
template< typename T >
class Templated
diff --git a/test/PCH/remap-file-from-pch.cpp b/test/PCH/remap-file-from-pch.cpp
index 8b965cf11c34..017285385a0b 100644
--- a/test/PCH/remap-file-from-pch.cpp
+++ b/test/PCH/remap-file-from-pch.cpp
@@ -1,7 +1,7 @@
// %clang_cc1 -remap-file "%s;%S/Inputs/remapped-file" -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXIST %s
// RUN: %clang_cc1 -x c++-header %s.h -emit-pch -o %t.pch
-// RUN: %clang_cc1 %s -include-pch %t.pch -remap-file "%s.h;%s.remap.h" -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %s -include-pch %t.pch -remap-file "%s.h;%s.remap.h" -fsyntax-only 2>&1 | FileCheck %s
const char *str = STR;
int ge = zool;
diff --git a/test/Parser/DelayedTemplateParsing.cpp b/test/Parser/DelayedTemplateParsing.cpp
index 77b47239f4c8..73128c49f247 100644
--- a/test/Parser/DelayedTemplateParsing.cpp
+++ b/test/Parser/DelayedTemplateParsing.cpp
@@ -11,7 +11,8 @@ class A {
template <class T>
class B {
void foo4() { } // expected-note {{previous definition is here}} expected-note {{previous definition is here}}
- void foo4() { } // expected-error {{class member cannot be redeclared}} expected-error {{redefinition of 'foo4'}} expected-note {{previous definition is here}}
+ void foo4() { } // expected-error {{class member cannot be redeclared}} expected-error {{redefinition of 'foo4'}}
+ void foo5() { } // expected-note {{previous definition is here}}
friend void foo3() {
undeclared();
@@ -20,7 +21,7 @@ class B {
template <class T>
-void B<T>::foo4() {// expected-error {{redefinition of 'foo4'}}
+void B<T>::foo5() { // expected-error {{redefinition of 'foo5'}}
}
template <class T>
@@ -101,3 +102,22 @@ namespace rdar11700604 {
};
}
+namespace PR17334 {
+
+template <typename = void> struct ArrayRef {
+ constexpr ArrayRef() {}
+};
+template <typename = void> void CreateConstInBoundsGEP2_32() {
+ ArrayRef<> IdxList;
+}
+void LLVMBuildStructGEP() { CreateConstInBoundsGEP2_32(); }
+
+}
+
+namespace PR17661 {
+template <typename T>
+constexpr T Fun(T A) { return T(0); }
+
+constexpr int Var = Fun(20);
+}
+
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 35c63d4b552a..5e1139338b81 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -30,6 +30,20 @@ void __forceinline InterlockedBitTestAndSet (long *Base, long Bit)
};
#endif
}
+
+// Both inline and __forceinline is OK.
+inline void __forceinline pr8264() {
+}
+__forceinline void inline pr8264_1() {
+}
+void inline __forceinline pr8264_2() {
+}
+void __forceinline inline pr8264_3() {
+}
+// But duplicate __forceinline causes warning.
+void __forceinline __forceinline pr8264_4() { // expected-warning{{duplicate '__forceinline' declaration specifier}}
+}
+
_inline int foo99() { return 99; }
void test_ms_alignof_alias() {
@@ -105,3 +119,14 @@ __declspec() void quux( void ) {
struct S7 s;
int i = s.t; /* expected-warning {{'t' is deprecated}} */
}
+
+int * __sptr psp;
+int * __uptr pup;
+/* Either ordering is acceptable */
+int * __ptr32 __sptr psp32;
+int * __ptr32 __uptr pup32;
+int * __sptr __ptr64 psp64;
+int * __uptr __ptr64 pup64;
+
+/* Legal to have nested pointer attributes */
+int * __sptr * __ptr32 ppsp32;
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index d8a597a8cc5b..efb5c3ce1fdc 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -4,21 +4,21 @@
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
struct SA_Post{ SA_Post(); int attr; };
-[returnvalue:SA_Post( attr=1)]
+[returnvalue:SA_Post( attr=1)]
int foo1([SA_Post(attr=1)] void *param);
namespace {
- [returnvalue:SA_Post(attr=1)]
+ [returnvalue:SA_Post(attr=1)]
int foo2([SA_Post(attr=1)] void *param);
}
class T {
- [returnvalue:SA_Post(attr=1)]
+ [returnvalue:SA_Post(attr=1)]
int foo3([SA_Post(attr=1)] void *param);
};
extern "C" {
- [returnvalue:SA_Post(attr=1)]
+ [returnvalue:SA_Post(attr=1)]
int foo5([SA_Post(attr=1)] void *param);
}
@@ -32,7 +32,7 @@ public:
void uuidof_test1()
-{
+{
__uuidof(0); // expected-error {{you need to include <guiddef.h> before using the '__uuidof' operator}}
}
@@ -44,8 +44,8 @@ typedef struct _GUID
unsigned char Data4[8];
} GUID;
-struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-error {{'uuid' attribute requires parameter 1 to be a string}}
-struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{'uuid' attribute requires parameter 1 to be a string}}
+struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-error {{'uuid' attribute requires a string}}
+struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{'uuid' attribute requires a string}}
struct __declspec(uuid("0000000-0000-0000-1234-0000500000047")) uuid_attr_bad3 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("0000000-0000-0000-Z234-000000000047")) uuid_attr_bad4 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("000000000000-0000-1234-000000000047")) uuid_attr_bad5 { };// expected-error {{uuid attribute contains a malformed GUID}}
@@ -59,7 +59,7 @@ struct struct_without_uuid { };
struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
struct_with_uuid2;
-struct
+struct
struct_with_uuid2 {} ;
int uuid_sema_test()
@@ -72,6 +72,10 @@ int uuid_sema_test()
__uuidof(struct_without_uuid); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
__uuidof(struct_with_uuid*);
__uuidof(struct_without_uuid*); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
+ __uuidof(struct_with_uuid[1]);
+ __uuidof(struct_with_uuid*[1]); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
+ __uuidof(const struct_with_uuid[1][1]);
+ __uuidof(const struct_with_uuid*[1][1]); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
__uuidof(var_with_uuid);
__uuidof(var_without_uuid);// expected-error {{cannot call operator __uuidof on a type with no GUID}}
@@ -89,16 +93,16 @@ template <class T>
void template_uuid()
{
T expr;
-
+
__uuidof(T);
__uuidof(expr);
}
-template <class T, const GUID* g = &__uuidof(T)>
+template <class T, const GUID* g = &__uuidof(T)> // expected-note {{template parameter is declared here}}
class COM_CLASS_TEMPLATE { };
-typedef COM_CLASS_TEMPLATE<struct_with_uuid, &__uuidof(struct_with_uuid)> COM_TYPE_1;
+typedef COM_CLASS_TEMPLATE<struct_with_uuid, &*&__uuidof(struct_with_uuid)> COM_TYPE_1; // expected-warning {{non-type template argument containing a dereference operation is a Microsoft extension}}
typedef COM_CLASS_TEMPLATE<struct_with_uuid> COM_TYPE_2;
template <class T, const GUID& g>
@@ -112,8 +116,30 @@ typedef COM_CLASS_TEMPLATE_REF<struct_with_uuid, __uuidof(struct_with_uuid)> COM
}
struct __declspec(uuid("000000A0-0000-0000-C000-000000000049")) late_defined_uuid;
+COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg;
+
+COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> bad_template_arg; // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}}
+
+namespace PR16911 {
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid2;
+
+template <typename T, typename T2>
+struct thing {
+};
+
+struct empty {};
+struct inher : public thing<empty, uuid2> {};
-class CtorCall {
+struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
+const struct _GUID *w = &__uuidof(inher); // expected-error{{cannot call operator __uuidof on a type with no GUID}}
+const struct _GUID *x = &__uuidof(thing<uuid, inher>);
+const struct _GUID *y = &__uuidof(thing<uuid2, uuid>); // expected-error{{cannot call operator __uuidof on a type with multiple GUIDs}}
+thing<uuid2, uuid> thing_obj = thing<uuid2, uuid>();
+const struct _GUID *z = &__uuidof(thing_obj); // expected-error{{cannot call operator __uuidof on a type with multiple GUIDs}}
+}
+
+class CtorCall {
public:
CtorCall& operator=(const CtorCall& that);
@@ -136,7 +162,7 @@ public:
class Iterator {
};
};
-
+
template<class T>
class C2 {
typename C1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
@@ -149,7 +175,9 @@ void missing_template_keyword(){
-class AAAA { };
+class AAAA {
+ typedef int D;
+};
template <typename T>
class SimpleTemplate {};
@@ -160,7 +188,7 @@ void redundant_typename() {
typename AAAA a;// expected-warning {{expected a qualified name after 'typename'}}
t = 3;
-
+
typedef typename T* pointerT;// expected-warning {{expected a qualified name after 'typename'}}
typedef typename SimpleTemplate<int> templateT;// expected-warning {{expected a qualified name after 'typename'}}
@@ -171,6 +199,12 @@ void redundant_typename() {
int k = typename var;// expected-error {{expected a qualified name after 'typename'}}
}
+template <typename T>
+struct TypenameWrongPlace {
+ typename typedef T::D D;// expected-warning {{expected a qualified name after 'typename'}}
+};
+
+extern TypenameWrongPlace<AAAA> PR16925;
__interface MicrosoftInterface;
__interface MicrosoftInterface {
@@ -239,25 +273,25 @@ __if_not_exists(IF_EXISTS::Type_not) {
int __if_exists_init_list() {
int array1[] = {
- 0,
+ 0,
__if_exists(IF_EXISTS::Type) {2, }
3
};
int array2[] = {
- 0,
+ 0,
__if_exists(IF_EXISTS::Type_not) { this wont compile }
3
};
int array3[] = {
- 0,
+ 0,
__if_not_exists(IF_EXISTS::Type_not) {2, }
3
};
int array4[] = {
- 0,
+ 0,
__if_not_exists(IF_EXISTS::Type) { this wont compile }
3
};
@@ -297,10 +331,19 @@ class inline_definition_pure_spec {
virtual int f2() = 0;
};
+struct pure_virtual_dtor {
+ virtual ~pure_virtual_dtor() = 0;
+};
+pure_virtual_dtor::~pure_virtual_dtor() { }
+
+struct pure_virtual_dtor_inline {
+ virtual ~pure_virtual_dtor_inline() = 0 { }// expected-warning {{function definition with pure-specifier is a Microsoft extension}}
+};
+
int main () {
// Necessary to force instantiation in -fdelayed-template-parsing mode.
- test_late_defined_uuid<int>();
+ test_late_defined_uuid<int>();
redundant_typename<int>();
missing_template_keyword<int>();
}
diff --git a/test/Parser/PR11000.cpp b/test/Parser/PR11000.cpp
index 7dae99621bbb..8d235cdf0316 100644
--- a/test/Parser/PR11000.cpp
+++ b/test/Parser/PR11000.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -std=c++11 %s 2>&1 | FileCheck %s
// PR11000: Don't crash.
class tuple<>
diff --git a/test/Parser/altivec-csk-bool.c b/test/Parser/altivec-csk-bool.c
new file mode 100644
index 000000000000..ba6fa3b2f77b
--- /dev/null
+++ b/test/Parser/altivec-csk-bool.c
@@ -0,0 +1,14 @@
+// RUN: %clang -target powerpc64-unknown-linux-gnu -maltivec -fsyntax-only %s
+
+// PR16456: Verify that bool, true, false are treated as context-sensitive
+// keywords (and therefore available for use as identifiers) when in
+// Altivec mode.
+
+typedef enum {
+ false_value = 0,
+ true_value = 1
+} bool;
+
+#define true true_value
+#define false false_value
+
diff --git a/test/Parser/attr-availability.c b/test/Parser/attr-availability.c
index 0ed839177531..06bebbad5c59 100644
--- a/test/Parser/attr-availability.c
+++ b/test/Parser/attr-availability.c
@@ -18,6 +18,8 @@ void f5() __attribute__((availability(macosx,introduced=10.5), availability(ios,
void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{'unavailable' availability overrides all other availability information}}
+void f7() __attribute__((availability(macosx,message=L"wide"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+
// rdar://10095131
enum E{
gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal for optional message in 'availability' attribute}}
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index 347cb9c1bfbf..376ed2e7d2c9 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -58,7 +58,7 @@ void d2(void) __attribute__((noreturn)), d3(void) __attribute__((noreturn));
void __attribute__((returns_twice)) returns_twice_test();
int aligned(int);
-int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error {{expected ')'}}
+int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error 2{{expected ')'}} expected-note {{to match}} expected-warning {{does not declare anything}}
int __attribute__((mode(x aligned(16) )) missing_rparen_2; // expected-error {{expected ')'}}
int __attribute__((format(printf, 0 aligned(16) )) missing_rparen_3; // expected-error {{expected ')'}}
diff --git a/test/Parser/crash-report.c b/test/Parser/crash-report.c
index 42481aa7d003..6f3706299d1b 100644
--- a/test/Parser/crash-report.c
+++ b/test/Parser/crash-report.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s 2>&1 | FileCheck %s
+// RUN: not --crash %clang_cc1 %s 2>&1 | FileCheck %s
// REQUIRES: crash-recovery
#prag\
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 9b2b1af22f6e..be00e494fd53 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/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 -faltivec -fsyntax-only -verify -std=c++11 %s
__vector char vv_c;
__vector signed char vv_sc;
@@ -168,3 +168,7 @@ public:
__vector float xyzw;
__vector float abcd;
} __attribute__((vecreturn)); // expected-error {{the vecreturn attribute can only be used on a class or structure with one member, which must be a vector}}
+
+template<typename... Args> void PR16874() {
+ (void) (Args::foo()...); // expected-error {{expression contains unexpanded parameter pack 'Args'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+}
diff --git a/test/Parser/cxx-ambig-init-templ.cpp b/test/Parser/cxx-ambig-init-templ.cpp
new file mode 100644
index 000000000000..ac79f77e152d
--- /dev/null
+++ b/test/Parser/cxx-ambig-init-templ.cpp
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -Wno-uninitialized -std=c++11 -verify %s
+
+template<int> struct c { c(int) = delete; typedef void val; operator int() const; };
+
+int val;
+int foobar;
+struct S {
+ int k1 = a < b < c, d > ::val, e1;
+ int k2 = a < b, c < d > ::val, e2;
+ int k3 = b < a < c, d > ::val, e3;
+ int k4 = b < c, x, y = d > ::val, e4;
+ int k5 = T1 < b, &S::operator=(int); // expected-error {{extra qualification}}
+ int k6 = T2 < b, &S::operator= >::val;
+ int k7 = T1 < b, &S::operator>(int); // expected-error {{extra qualification}}
+ int k8 = T2 < b, &S::operator> >::val;
+ int k9 = T3 < a < b, c >> (d), e5 = 1 > (e4);
+ int k10 = 0 < T3 < a < b, c >> (d
+ ) // expected-error {{expected ';' at end of declaration}}
+ , a > (e4);
+ int k11 = 0 < 1, c<3>::*ptr;
+ int k12 = e < 0, int a<b<c>::* >(), e11;
+
+ void f1(
+ int k1 = a < b < c, d > ::val,
+ int k2 = b < a < c, d > ::val,
+ int k3 = b < c, int x = 0 > ::val,
+ int k4 = a < b, T3 < int > >(), // expected-error {{must be an expression}}
+ int k5 = a < b, c < d > ::val,
+ int k6 = a < b, c < d > (n) // expected-error {{undeclared identifier 'n'}}
+ );
+
+ void f2a(
+ // T3<int> here is a parameter type, so must be declared before it is used.
+ int k1 = c < b, T3 < int > x = 0 // expected-error {{unexpected end of default argument expression}}
+ );
+
+ template<typename, int=0> struct T3 { T3(int); operator int(); };
+
+ void f2b(
+ int k1 = c < b, T3 < int > x = 0 // ok
+ );
+
+ // This is a one-parameter function. Ensure we don't typo-correct it to
+ // int = a < b, c < foobar > ()
+ // ... which would be a function with two parameters.
+ int f3(int = a < b, c < goobar > ());
+ static constexpr int (S::*f3_test)(int) = &S::f3;
+
+ void f4(
+ int k1 = a<1,2>::val,
+ int missing_default // expected-error {{missing default argument on parameter}}
+ );
+
+ void f5(
+ int k1 = b < c,
+ int missing_default // expected-error {{missing default argument on parameter}}
+ );
+
+ void f6(
+ int k = b < c,
+ unsigned int (missing_default) // expected-error {{missing default argument on parameter}}
+ );
+
+ template<int, int=0> struct a { static const int val = 0; operator int(); }; // expected-note {{here}}
+ static const int b = 0, c = 1, d = 2, goobar = 3;
+ template<int, typename> struct e { operator int(); };
+
+ int mp1 = 0 < 1,
+ a<b<c,b<c>::*mp2,
+ mp3 = 0 > a<b<c>::val,
+ a<b<c,b<c>::*mp4 = 0,
+ a<b<c,b<c>::*mp5 {0},
+ a<b<c,b<c>::*mp6;
+
+ int np1 = e<0, int a<b<c,b<c>::*>();
+
+ static const int T1 = 4;
+ template<int, int &(S::*)(int)> struct T2 { static const int val = 0; };
+};
+
+namespace NoAnnotationTokens {
+ template<bool> struct Bool { Bool(int); };
+ static const bool in_class = false;
+
+ struct Test {
+ // Check we don't keep around a Bool<false> annotation token here.
+ int f(Bool<true> = X<Y, Bool<in_class> >(0));
+
+ // But it's OK if we do here.
+ int g(Bool<true> = Z<Y, Bool<in_class> = Bool<false>(0));
+
+ static const bool in_class = true;
+ template<int, typename U> using X = U;
+ static const int Y = 0, Z = 0;
+ };
+}
+
+namespace ImplicitInstantiation {
+ template<typename T> struct HasError { typename T::error error; }; // expected-error {{has no members}}
+
+ struct S {
+ // This triggers the instantiation of the outer HasError<int> during
+ // disambiguation, even though it uses the inner HasError<int>.
+ void f(int a = X<Y, HasError<int>::Z >()); // expected-note {{in instantiation of}}
+
+ template<typename, typename> struct X { operator int(); };
+ typedef int Y;
+ template<typename> struct HasError { typedef int Z; };
+ };
+
+ HasError<int> hei;
+}
+
+namespace CWG325 {
+ template <int A, typename B> struct T { static int i; operator int(); };
+ class C {
+ int Foo (int i = T<1, int>::i);
+ };
+
+ class D {
+ int Foo (int i = T<1, int>::i);
+ template <int A, typename B> struct T {static int i;};
+ };
+
+ const int a = 0;
+ typedef int b;
+ T<a,b> c;
+ struct E {
+ int n = T<a,b>(c);
+ };
+}
+
+namespace Operators {
+ struct Y {};
+ constexpr int operator,(const Y&, const Y&) { return 8; }
+ constexpr int operator>(const Y&, const Y&) { return 8; }
+ constexpr int operator<(const Y&, const Y&) { return 8; }
+ constexpr int operator>>(const Y&, const Y&) { return 8; }
+
+ struct X {
+ typedef int (*Fn)(const Y&, const Y&);
+
+ Fn a = operator,, b = operator<, c = operator>;
+ void f(Fn a = operator,, Fn b = operator<, Fn c = operator>);
+
+ int k1 = T1<0, operator<, operator>, operator<>::val, l1;
+ int k2 = T1<0, operator>, operator,, operator,>::val, l2;
+ int k3 = T2<0, operator,(Y{}, Y{}), operator<(Y{}, Y{})>::val, l3;
+ int k4 = T2<0, operator>(Y{}, Y{}), operator,(Y{}, Y{})>::val, l4;
+ int k5 = T3<0, operator>>>::val, l5;
+ int k6 = T4<0, T3<0, operator>>>>::val, l6;
+
+ template<int, Fn, Fn, Fn> struct T1 { enum { val }; };
+ template<int, int, int> struct T2 { enum { val }; };
+ template<int, Fn> struct T3 { enum { val }; };
+ template<int, typename T> struct T4 : T {};
+ };
+}
+
+namespace ElaboratedTypeSpecifiers {
+ struct S {
+ int f(int x = T<a, struct S>());
+ int g(int x = T<a, class __declspec() C>());
+ int h(int x = T<a, union __attribute__(()) U>());
+ int i(int x = T<a, enum E>());
+ int j(int x = T<a, struct S::template T<0, enum E>>());
+ template <int, typename> struct T { operator int(); };
+ static const int a = 0;
+ enum E {};
+ };
+}
diff --git a/test/Parser/cxx-attributes.cpp b/test/Parser/cxx-attributes.cpp
index 5ea0ce227595..6fd7f4f68a46 100644
--- a/test/Parser/cxx-attributes.cpp
+++ b/test/Parser/cxx-attributes.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
class c {
virtual void f1(const char* a, ...)
@@ -8,3 +7,16 @@ class c {
__attribute__ (( __format__(__printf__,2,3) )) {}
};
+template <typename T> class X {
+ template <typename S> void X<S>::f() __attribute__((locks_excluded())); // expected-error{{nested name specifier 'X<S>::' for declaration does not refer into a class, class template or class template partial specialization}} \
+ // expected-warning{{attribute locks_excluded ignored, because it is not attached to a declaration}}
+};
+
+namespace PR17666 {
+ const int A = 1;
+ typedef int __attribute__((__aligned__(A))) T1;
+ int check1[__alignof__(T1) == 1 ? 1 : -1];
+
+ typedef int __attribute__((aligned(int(1)))) T1;
+ typedef int __attribute__((aligned(int))) T2; // expected-error {{expected '(' for function-style cast}}
+}
diff --git a/test/Parser/cxx-class-template-specialization.cpp b/test/Parser/cxx-class-template-specialization.cpp
new file mode 100644
index 000000000000..f94a85964a78
--- /dev/null
+++ b/test/Parser/cxx-class-template-specialization.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+ template<typename T>
+ void f();
+};
+class A::f<int>;
+// expected-error@-1 {{identifier followed by '<' indicates a class template specialization but 'f' refers to a function template}}
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 41d305b17642..8c4c6175f5c5 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -108,9 +108,9 @@ template<class T>
class Class1;
class Class2 {
-} // no ;
+} // expected-error {{expected ';' after class}}
-typedef Class1<Class2> Type1; // expected-error {{cannot combine with previous 'class' declaration specifier}}
+typedef Class1<Class2> Type1;
// rdar : // 8307865
struct CodeCompleteConsumer {
@@ -187,6 +187,51 @@ namespace PR15017 {
// Ensure we produce at least some diagnostic for attributes in C++98.
[[]] struct S; // expected-error 2{{}}
+namespace test7 {
+ struct Foo {
+ void a();
+ void b();
+ };
+
+ void Foo::
+ // Comment!
+ a() {}
+
+
+ void Foo:: // expected-error {{expected unqualified-id}}
+ // Comment!
+}
+
+void test8() {
+ struct {} o;
+ // This used to crash.
+ (&o)->(); // expected-error{{expected unqualified-id}}
+}
+
+namespace PR5066 {
+ template<typename T> struct X {};
+ X<int N> x; // expected-error {{type-id cannot have a name}}
+
+ using T = int (*T)(); // expected-error {{type-id cannot have a name}} expected-warning {{C++11}}
+}
+
+namespace PR17255 {
+void foo() {
+ typename A::template B<>; // expected-error {{use of undeclared identifier 'A'}} \
+ // expected-error {{expected a qualified name after 'typename'}} \
+ // expected-warning {{'template' keyword outside of a template}}
+}
+}
+
+namespace PR17567 {
+ struct Foobar { // expected-note 2{{declared here}}
+ FooBar(); // expected-error {{missing return type for function 'FooBar'; did you mean the constructor name 'Foobar'?}}
+ ~FooBar(); // expected-error {{expected the class name after '~' to name a destructor}}
+ };
+ FooBar::FooBar() {} // expected-error {{undeclared}} expected-error {{missing return type}}
+ FooBar::~FooBar() {} // expected-error {{undeclared}} expected-error {{expected the class name}}
+}
+
// PR8380
extern "" // expected-error {{unknown linkage language}}
test6a { ;// expected-error {{C++ requires a type specifier for all declarations}} \
diff --git a/test/Parser/cxx-default-args.cpp b/test/Parser/cxx-default-args.cpp
index 7fe8474142ba..36abf0d8cb38 100644
--- a/test/Parser/cxx-default-args.cpp
+++ b/test/Parser/cxx-default-args.cpp
@@ -14,3 +14,20 @@ typedef struct Inst {
struct X {
void f(int x = 1:); // expected-error {{unexpected end of default argument expression}}
};
+
+// PR13657
+struct T {
+ template <typename A, typename B> struct T1 { enum {V};};
+ template <int A, int B> struct T2 { enum {V}; };
+ template <int, int> static int func(int);
+
+
+ void f1(T1<int, int> = T1<int, int>());
+ void f2(T1<int, double> = T1<int, double>(), T2<0, 5> = T2<0, 5>());
+ void f3(int a = T2<0, (T1<int, int>::V > 10) ? 5 : 6>::V, bool b = 4<5 );
+ void f4(bool a = 1 < 0, bool b = 2 > 0 );
+ void f5(bool a = 1 > T2<0, 0>::V, bool b = T1<int,int>::V < 3, int c = 0);
+ void f6(bool a = T2<0,3>::V < 4, bool b = 4 > T2<0,3>::V);
+ void f7(bool a = T1<int, bool>::V < 3);
+ void f8(int = func<0,1<2>(0), int = 1<0, T1<int,int>(int) = 0);
+};
diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp
index a13e7babc534..a3b89cc688bb 100644
--- a/test/Parser/cxx-friend.cpp
+++ b/test/Parser/cxx-friend.cpp
@@ -30,6 +30,10 @@ class B {
void f(A *a) { a->f(); }
};
+void bar() {} // expected-note {{previous definition is here}}
+class E {
+ friend void bar() {} // expected-error {{redefinition of 'bar'}}
+};
diff --git a/test/Parser/cxx-member-crash.cpp b/test/Parser/cxx-member-crash.cpp
index 2b31a608a583..65e70954e043 100644
--- a/test/Parser/cxx-member-crash.cpp
+++ b/test/Parser/cxx-member-crash.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1|FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
// <rdar://problem/9221993>
-// We only care to chek whether the compiler crashes; the actual
+// We only care to check whether the compiler crashes; the actual
// diagnostics are uninteresting.
// CHECK: 8 errors generated.
template<class _CharT> struct char_traits;
diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp
index 5c3906836c49..ff8c880a1849 100644
--- a/test/Parser/cxx-member-initializers.cpp
+++ b/test/Parser/cxx-member-initializers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct x {
x() : a(4) ; // expected-error {{expected '{'}}
@@ -11,5 +11,71 @@ struct y {
struct z {
int a;
- z() : a {} // expected-error {{expected '('}}
-};
+ z() : a {}
+}; // expected-error {{expected '{'}}
+
+namespace PR16480 {
+ template<int n> struct X {
+ X();
+ X(int);
+ };
+
+ struct A : X<0> {
+ A() : X<a<b>{0}.n>() {}
+
+ template<int> struct a {
+ int n;
+ };
+
+ static const int b = 1;
+ };
+
+ struct B : X<0> {
+ B() : X<a<b>{0} {}
+
+ static const int a = 0, b = 0;
+ };
+
+ template<int> struct a {
+ constexpr a(int) {}
+ constexpr operator int() const { return 0; }
+ };
+
+ struct C : X<0> {
+ C() : X<a<b>(0)>() {}
+
+ static const int b = 0;
+ };
+
+ struct D : X<0> {
+ D() : X<a<b>(0) {}
+
+ static const int a = 0, b = 0;
+ };
+
+ template<typename T> struct E : X<0> {
+ E(X<0>) : X<(0)>{} {}
+ E(X<1>) : X<int{}>{} {}
+ E(X<2>) : X<(0)>() {}
+ E(X<3>) : X<int{}>() {}
+ };
+
+ // FIXME: This should be valid in the union of C99 and C++11.
+ struct F : X<0> {
+ F() : X<A<T>().n + (T){}.n>{} {} // expected-error +{{}}
+
+ struct T { int n; };
+ template<typename> struct A { int n; };
+ }; // expected-error +{{}}
+
+ // FIXME: This is valid now, but may be made ill-formed by DR1607.
+ struct G : X<0> {
+ G() : X<0 && [](){return 0;}()>{} // expected-error +{{}}
+ }; // expected-error +{{}}
+
+ struct Errs : X<0> {
+ Errs(X<0>) : decltype X<0>() {} // expected-error {{expected '(' after 'decltype'}}
+ Errs(X<1>) : what is this () {} // expected-error {{expected '(' or '{'}}
+ Errs(X<2>) : decltype(X<0> // expected-note {{to match this '('}}
+ }; // expected-error {{expected ')'}}
+}
diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp
index afe318df7a1a..8bf2a4f78add 100644
--- a/test/Parser/cxx-template-argument.cpp
+++ b/test/Parser/cxx-template-argument.cpp
@@ -5,7 +5,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 {{expected '>'}}
+A<int x; // expected-error {{type-id cannot have a name}} expected-error {{expected '>'}}
// PR8912
template <bool> struct S {};
@@ -42,3 +42,66 @@ namespace PR13210 {
new C(); // expected-error {{requires template arguments}}
}
}
+
+// Don't emit spurious messages
+namespace pr16225add {
+
+ template<class T1, typename T2> struct Known { }; // expected-note 3 {{template is declared here}}
+ template<class T1, typename T2> struct X;
+ template<class T1, typename T2> struct ABC; // expected-note {{template is declared here}}
+ template<int N1, int N2> struct ABC2 {};
+
+ template<class T1, typename T2> struct foo :
+ UnknownBase<T1,T2> // expected-error {{unknown template name 'UnknownBase'}}
+ { };
+
+ template<class T1, typename T2> struct foo2 :
+ UnknownBase<T1,T2>, // expected-error {{unknown template name 'UnknownBase'}}
+ Known<T1> // expected-error {{too few template arguments for class template 'Known'}}
+ { };
+
+ template<class T1, typename T2> struct foo3 :
+ UnknownBase<T1,T2,ABC<T2,T1> > // expected-error {{unknown template name 'UnknownBase'}}
+ { };
+
+ template<class T1, typename T2> struct foo4 :
+ UnknownBase<T1,ABC<T2> >, // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{too few template arguments for class template 'ABC'}}
+ Known<T1> // expected-error {{too few template arguments for class template 'Known'}}
+ { };
+
+ template<class T1, typename T2> struct foo5 :
+ UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use '> >'}}
+ { };
+
+ template<class T1, typename T2> struct foo6 :
+ UnknownBase<T1,ABC<T2,T1>>, // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use '> >'}}
+ Known<T1> // expected-error {{too few template arguments for class template 'Known'}}
+ { };
+
+ template<class T1, typename T2, int N> struct foo7 :
+ UnknownBase<T1,T2,(N>1)> // expected-error {{unknown template name 'UnknownBase'}}
+ { };
+
+ template<class T1, typename T2> struct foo8 :
+ UnknownBase<X<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use '> >'}}
+ { };
+
+ template<class T1, typename T2> struct foo9 :
+ UnknownBase<Known<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use '> >'}}
+ { };
+
+ template<class T1, typename T2> struct foo10 :
+ UnknownBase<Known<int,int>,X<int,X<int,int>>> // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use '> >'}}
+ { };
+
+ template<int N1, int N2> struct foo11 :
+ UnknownBase<2<N1,N2<4> // expected-error {{unknown template name 'UnknownBase'}}
+ { };
+
+}
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 7e931a31fa2d..81269ce25416 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -85,6 +85,19 @@ struct shadow5 {
int T(int, float); // expected-error{{shadows}}
};
+template<typename T, // expected-note{{template parameter is declared here}}
+ T T> // expected-error{{declaration of 'T' shadows template parameter}}
+void shadow6();
+
+template<typename T, // expected-note{{template parameter is declared here}}
+ template<typename> class T> // expected-error{{declaration of 'T' shadows template parameter}}
+void shadow7();
+
+// PR8302
+template<template<typename> class T> struct shadow8 { // expected-note{{template parameter is declared here}}
+ template<template<typename> class T> struct inner; // expected-error{{declaration of 'T' shadows template parameter}}
+};
+
// Non-type template parameters in scope
template<int Size>
void f(int& i) {
@@ -103,6 +116,7 @@ void f2() {
// PR3844
template <> struct S<int> { }; // expected-error{{explicit specialization of non-template struct 'S'}}
+template <> union U<int> { }; // expected-error{{explicit specialization of non-template union 'U'}}
namespace PR6184 {
namespace N {
diff --git a/test/Parser/cxx-using-directive.cpp b/test/Parser/cxx-using-directive.cpp
index 9a1a6de89267..5efd991c8e7a 100644
--- a/test/Parser/cxx-using-directive.cpp
+++ b/test/Parser/cxx-using-directive.cpp
@@ -4,11 +4,11 @@ class A {};
namespace B {
namespace A {} // expected-note{{namespace '::B::A' defined here}} \
- // expected-note{{namespace 'B::A' defined here}}
+ // expected-note 2{{namespace 'B::A' defined here}}
using namespace A ;
}
-namespace C {}
+namespace C {} // expected-note{{namespace 'C' defined here}}
namespace D {
@@ -22,12 +22,13 @@ namespace D {
using namespace C ;
using namespace B::A ; // expected-error{{no namespace named 'A' in namespace 'D::B'; did you mean '::B::A'?}}
using namespace ::B::A ;
- using namespace ::D::C ; // expected-error{{expected namespace name}}
+ using namespace ::D::F ; // expected-error{{expected namespace name}}
+ using namespace ::D::C ; // expected-error{{no namespace named 'C' in namespace 'D'; did you mean simply 'C'?}}
}
using namespace ! ; // expected-error{{expected namespace name}}
using namespace A ; // expected-error{{no namespace named 'A'; did you mean 'B::A'?}}
-using namespace ::A // expected-error{{expected namespace name}} \
+using namespace ::A // expected-error{{no namespace named 'A' in the global namespace; did you mean 'B::A'?}} \
// expected-error{{expected ';' after namespace name}}
B ;
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 5e4e388a2645..b02add98457e 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -122,6 +122,24 @@ extern "C++" [[]] { } // 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 and methods}}
+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}}
+
+void bad_attributes_in_do_while() {
+ do {} while (
+ [[ns::i); // expected-error {{expected ']'}} \
+ // expected-note {{to match this '['}} \
+ // expected-error {{expected expression}}
+ do {} while (
+ [[a]b ns::i); // expected-error {{expected ']'}} \
+ // expected-note {{to match this '['}} \
+ // expected-error {{expected expression}}
+ do {} while (
+ [[ab]ab] ns::i); // expected-error {{an attribute list cannot appear here}}
+ do {} while ( // expected-note {{to match this '('}}
+ alignas(4 ns::i; // expected-note {{to match this '('}}
+} // expected-error 2{{expected ')'}} expected-error {{expected expression}}
+
[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
using T [[]] = int; // ok
template<typename T> using U [[]] = T;
@@ -281,3 +299,23 @@ int v5()[[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}}
[[attribute_declaration]]; // expected-warning {{unknown attribute 'attribute_declaration' ignored}}
[[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions and methods}}
[[carries_dependency]]; // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
+
+class A {
+ A([[gnu::unused]] int a);
+};
+A::A([[gnu::unused]] int a) {}
+
+namespace GccConst {
+ // GCC's tokenizer treats const and __const as the same token.
+ [[gnu::const]] int *f1();
+ [[gnu::__const]] int *f2();
+ void f(const int *);
+ void g() { f(f1()); f(f2()); }
+}
+
+namespace GccASan {
+ __attribute__((no_address_safety_analysis)) void f1();
+ __attribute__((no_sanitize_address)) void f2();
+ [[gnu::no_address_safety_analysis]] void f3();
+ [[gnu::no_sanitize_address]] void f4();
+}
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index e6cba726ab63..257c56c9ce98 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -73,3 +73,34 @@ enum E
[[]] e;
}
+
+namespace PR5066 {
+ using T = int (*f)(); // expected-error {{type-id cannot have a name}}
+ template<typename T> using U = int (*f)(); // expected-error {{type-id cannot have a name}}
+ auto f() -> int (*f)(); // expected-error {{type-id cannot have a name}}
+ auto g = []() -> int (*f)() {}; // expected-error {{type-id cannot have a name}}
+}
+
+namespace FinalOverride {
+ struct Base {
+ virtual void *f();
+ virtual void *g();
+ virtual void *h();
+ virtual void *i();
+ };
+ struct Derived : Base {
+ virtual auto f() -> void *final;
+ virtual auto g() -> void *override;
+ virtual auto h() -> void *final override;
+ virtual auto i() -> void *override final;
+ };
+}
+
+namespace UsingDeclAttrs {
+ using T __attribute__((aligned(1))) = int;
+ using T [[gnu::aligned(1)]] = int;
+ static_assert(alignof(T) == 1, "");
+
+ using [[gnu::aligned(1)]] T = int; // expected-error {{an attribute list cannot appear here}}
+ using T = int [[gnu::aligned(1)]]; // expected-error {{'aligned' attribute cannot be applied to types}}
+}
diff --git a/test/Parser/cxx0x-in-cxx98.cpp b/test/Parser/cxx0x-in-cxx98.cpp
index b4bda89d2781..724993811631 100644
--- a/test/Parser/cxx0x-in-cxx98.cpp
+++ b/test/Parser/cxx0x-in-cxx98.cpp
@@ -21,3 +21,10 @@ void NewBracedInitList() {
// A warning on this would be sufficient once we can handle it correctly.
new int {}; // expected-error {{}}
}
+
+struct Auto {
+ static int n;
+};
+auto Auto::n = 0; // expected-warning {{'auto' type specifier is a C++11 extension}}
+auto Auto::m = 0; // expected-error {{no member named 'm' in 'Auto'}}
+ // expected-warning@-1 {{'auto' type specifier is a C++11 extension}}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index 642c69a532ee..289d03c223b3 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -48,4 +48,20 @@ class C {
delete [] { return new int; } (); // expected-error{{expected expression}}
delete [&] { return new int; } (); // ok, lambda
}
+
+ // We support init-captures in C++11 as an extension.
+ int z;
+ void init_capture() {
+ [n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
+ [n{0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}}
+ [n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
+ [n = {0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}}
+ [a([&b = z]{})](){}; // expected-warning 2{{extension}}
+
+ int x = 4;
+ auto y = [&r = x, x = x + 1]() -> int { // expected-warning 2{{extension}}
+ r += 2;
+ return x + 2;
+ } ();
+ }
};
diff --git a/test/Parser/cxx0x-member-initializers.cpp b/test/Parser/cxx0x-member-initializers.cpp
index a324f974bcaf..43e99b133646 100644
--- a/test/Parser/cxx0x-member-initializers.cpp
+++ b/test/Parser/cxx0x-member-initializers.cpp
@@ -27,3 +27,13 @@ struct V1 {
int a, b;
V1() : a(), b{} {}
};
+
+template <typename, typename> struct T1 { enum {V};};
+template <int, int> struct T2 { enum {V};};
+struct A {
+ T1<int, int> a1 = T1<int, int>(), *a2 = new T1<int,int>;
+ T2<0,0> b1 = T2<0,0>(), b2 = T2<0,0>(), b3;
+ bool c1 = 1 < 2, c2 = 2 < 1, c3 = false;
+ bool d1 = T1<int, T1<int, int>>::V < 3, d2;
+ T1<int, int()> e = T1<int, int()>();
+};
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index 2f727a25bd7e..9374b58b1f24 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -76,4 +76,9 @@ void foo(int i) {
}
[[carries_dependency]] return; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+
+ {
+ [[ ]] // 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}}
+ }
}
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index f63b59f7caa6..210a8e2befc7 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -108,7 +108,8 @@ void test18() {
}
enum E1 { e1 }: // expected-error {{expected ';'}}
-struct EnumBitfield {
+struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}}
enum E2 { e2 } : 4; // ok
struct S { int n; }: // expected-error {{expected ';'}}
+
};
diff --git a/test/Parser/expressions.c b/test/Parser/expressions.c
index 0d1b6c945c5c..95d6fb354f3f 100644
--- a/test/Parser/expressions.c
+++ b/test/Parser/expressions.c
@@ -57,3 +57,13 @@ void test7() {
({} // expected-note {{to match}}
; // expected-error {{expected ')'}}
}
+
+// PR16992
+struct pr16992 { int x; };
+
+void func_16992 () {
+ int x1 = sizeof int; // expected-error {{expected parentheses around type name in sizeof expression}}
+ int x2 = sizeof struct pr16992; // expected-error {{expected parentheses around type name in sizeof expression}}
+ int x3 = __alignof int; // expected-error {{expected parentheses around type name in __alignof expression}}
+ int x4 = _Alignof int; // expected-error {{expected parentheses around type name in _Alignof expression}}
+}
diff --git a/test/Parser/objc-diag-width.mm b/test/Parser/objc-diag-width.mm
index 3929ba2b090e..eba7a847de39 100644
--- a/test/Parser/objc-diag-width.mm
+++ b/test/Parser/objc-diag-width.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %s 2>&1 | FileCheck %s
// Just shouldn't crash. -verify suppresses the crash, so don't use it.
// PR13417
diff --git a/test/Parser/objc-error-qualified-implementation.m b/test/Parser/objc-error-qualified-implementation.m
index 444fb5dab44c..8bbd50236027 100644
--- a/test/Parser/objc-error-qualified-implementation.m
+++ b/test/Parser/objc-error-qualified-implementation.m
@@ -19,3 +19,11 @@
@implementation K <P // expected-error {{@implementation declaration can not be protocol qualified}}
@end // expected-error {{expected '>'}}
+
+// rdar://13920026
+@implementation I (Cat) <P> // expected-error {{@implementation declaration can not be protocol qualified}}
+- (void) Meth {}
+@end
+
+@implementation I (Cat1) <P // expected-error {{@implementation declaration can not be protocol qualified}}
+@end // expected-error {{expected '>'}}
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
index fb90b16a971f..bef576a9d204 100644
--- a/test/Parser/objcxx0x-lambda-expressions.mm
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -Wno-c++1y-extensions -std=c++11 %s
class C {
+ id get(int);
void f() {
- int foo, bar;
+ int foo, bar, baz;
// fail to parse as a lambda introducer, so we get objc message parsing errors instead
[foo,+] {}; // expected-error {{expected expression}}
@@ -17,6 +18,25 @@ class C {
[foo,bar] () { return 3; };
[=,&foo] () {};
[this] () {};
+
+ [foo(bar)] () {};
+ [foo = bar] () {};
+ [foo{bar}] () {}; // expected-error {{<initializer_list>}}
+ [foo = {bar}] () {}; // expected-error {{<initializer_list>}}
+
+ [foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}}
+ [foo(bar), baz] () {}; // ok
+
+ [foo = bar baz]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}}
+
+ [get(bar) baz]; // expected-warning {{instance method '-baz'}}
+ [get(bar), baz]; // expected-error {{expected body of lambda}}
+
+ [foo = bar ++ baz]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}}
+ [foo = bar + baz]; // expected-error {{expected body of lambda}}
+ [foo = { bar, baz }]; // expected-error {{<initializer_list>}} expected-error {{expected body of lambda}}
+ [foo = { bar } baz ]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}}
+ [foo = { bar }, baz ]; // expected-error {{<initializer_list>}} expected-error {{expected body of lambda}}
}
};
diff --git a/test/Parser/parser_overflow.c b/test/Parser/parser_overflow.c
index 7a3d6516af4e..9514e808550a 100644
--- a/test/Parser/parser_overflow.c
+++ b/test/Parser/parser_overflow.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 %s -fsyntax-only -DHUGE 2>&1 | FileCheck %s
-// RUN: %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang_cc1 %s -fsyntax-only -fbracket-depth 299 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %s -fsyntax-only -DHUGE 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 %s -fsyntax-only -fbracket-depth 299 2>&1 | FileCheck %s
// RUN: %clang_cc1 %s -fsyntax-only -fbracket-depth 300
-// RUN: %clang %s -fsyntax-only -fbracket-depth=299 2>&1 | FileCheck %s
+// RUN: not %clang %s -fsyntax-only -fbracket-depth=299 2>&1 | FileCheck %s
// RUN: %clang %s -fsyntax-only -fbracket-depth=300
void foo(void) {
diff --git a/test/Parser/pragma-fp-contract.c b/test/Parser/pragma-fp-contract.c
index 568c0a0a88ba..c80c140ea71f 100644
--- a/test/Parser/pragma-fp-contract.c
+++ b/test/Parser/pragma-fp-contract.c
@@ -2,7 +2,7 @@
void f1(void) {
int x = 0;
-/* expected-error@+1 {{'#pragma fp_contract' should only appear at file scope or at the start of a compound expression}} */
+/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */
#pragma STDC FP_CONTRACT ON
}
diff --git a/test/Parser/pragma-weak.c b/test/Parser/pragma-weak.c
index 7e5740b48308..fd47dd8696b8 100644
--- a/test/Parser/pragma-weak.c
+++ b/test/Parser/pragma-weak.c
@@ -15,3 +15,30 @@ extern int z;
extern int a;
/* expected-warning {{extra tokens at end of '#pragma weak'}}*/ #pragma weak a b
/* expected-warning {{extra tokens at end of '#pragma weak'}}*/ #pragma weak a = x c
+
+
+void pragma_is_not_a_statement(int x)
+{
+ int t;
+
+ {
+ if (x)
+#pragma weak t
+ else // expected-error {{expected expression}}
+#pragma weak t
+ }
+
+ switch (x) {
+ case 1:
+#pragma weak t
+ } // expected-error {{expected statement}}
+ switch(x) {
+ default:
+#pragma weak t
+ } // expected-error {{expected statement}}
+
+label:
+#pragma weak t
+} // expected-error {{expected statement}}
+
+
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
index 41845fb29158..b5b09484ad9e 100644
--- a/test/Parser/recovery.cpp
+++ b/test/Parser/recovery.cpp
@@ -12,7 +12,7 @@ inline namespace Std { // expected-error {{cannot be reopened as inline}}
int x;
Std::Important y;
-extenr "C" { // expected-error {{did you mean the keyword 'extern'}}
+extenr "C" { // expected-error {{did you mean 'extern'}}
void f();
}
void g() {
@@ -35,11 +35,27 @@ constexpr int foo();
5int m = { l }, n = m; // expected-error {{unqualified-id}}
+namespace MissingBrace {
+ struct S { // expected-error {{missing '}' at end of definition of 'MissingBrace::S'}}
+ int f();
+ // };
+
+ namespace N { int g(); } // expected-note {{still within definition of 'MissingBrace::S' here}}
+
+ int k1 = S().h(); // expected-error {{no member named 'h' in 'MissingBrace::S'}}
+ int k2 = S().f() + N::g();
+
+ template<typename T> struct PR17949 { // expected-error {{missing '}' at end of definition of 'MissingBrace::PR17949'}}
+
+ namespace X { // expected-note {{still within definition of 'MissingBrace::PR17949' here}}
+ }
+}
+
namespace N {
int
} // expected-error {{unqualified-id}}
-strcut Uuuu { // expected-error {{did you mean the keyword 'struct'}} \
+strcut Uuuu { // expected-error {{did you mean 'struct'}} \
// expected-note {{'Uuuu' declared here}}
} *u[3];
uuuu v; // expected-error {{did you mean 'Uuuu'}}
@@ -50,3 +66,56 @@ struct Redefined { // expected-note {{previous}}
struct Redefined { // expected-error {{redefinition}}
Redefined() {}
};
+
+struct MissingSemi5;
+namespace N {
+ typedef int afterMissingSemi4;
+ extern MissingSemi5 afterMissingSemi5;
+}
+
+struct MissingSemi1 {} // expected-error {{expected ';' after struct}}
+static int afterMissingSemi1();
+
+class MissingSemi2 {} // expected-error {{expected ';' after class}}
+MissingSemi1 *afterMissingSemi2;
+
+enum MissingSemi3 {} // expected-error {{expected ';' after enum}}
+::MissingSemi1 afterMissingSemi3;
+
+extern N::afterMissingSemi4 afterMissingSemi4b;
+union MissingSemi4 { MissingSemi4(int); } // expected-error {{expected ';' after union}}
+N::afterMissingSemi4 (afterMissingSemi4b);
+
+int afterMissingSemi5b;
+struct MissingSemi5 { MissingSemi5(int); } // ok, no missing ';' here
+N::afterMissingSemi5 (afterMissingSemi5b);
+
+template<typename T> struct MissingSemiT {
+} // expected-error {{expected ';' after struct}}
+MissingSemiT<int> msi;
+
+struct MissingSemiInStruct {
+ struct Inner1 {} // expected-error {{expected ';' after struct}}
+ static MissingSemi5 ms1;
+
+ struct Inner2 {} // ok, no missing ';' here
+ static MissingSemi1;
+
+ struct Inner3 {} // expected-error {{expected ';' after struct}}
+ static MissingSemi5 *p;
+};
+
+void MissingSemiInFunction() {
+ struct Inner1 {} // expected-error {{expected ';' after struct}}
+ if (true) {}
+
+ // FIXME: It would be nice to at least warn on this.
+ struct Inner2 { Inner2(int); } // ok, no missing ';' here
+ k = l;
+
+ struct Inner3 {} // expected-error {{expected ';' after struct}}
+ Inner1 i1;
+
+ struct Inner4 {} // ok, no missing ';' here
+ Inner5;
+}
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
index 84ac0c899e55..63b580202af8 100644
--- a/test/Parser/switch-recovery.cpp
+++ b/test/Parser/switch-recovery.cpp
@@ -95,7 +95,7 @@ int test8( foo x ) {
}
// Stress test to make sure Clang doesn't crash.
-void test9(int x) {
+void test9(int x) { // expected-note {{'x' declared here}}
switch(x) {
case 1: return;
2: case; // expected-error {{expected 'case' keyword before expression}} \
@@ -104,8 +104,8 @@ void test9(int x) {
7: :x; // expected-error {{expected 'case' keyword before expression}} \
expected-error {{expected expression}}
8:: x; // expected-error {{expected ';' after expression}} \
- expected-error {{no member named 'x' in the global namespace}} \
- expected-warning {{expression result unused}}
+ expected-error {{no member named 'x' in the global namespace; did you mean simply 'x'?}} \
+ expected-warning 2 {{expression result unused}}
9:: :y; // expected-error {{expected ';' after expression}} \
expected-error {{expected unqualified-id}} \
expected-warning {{expression result unused}}
diff --git a/test/Preprocessor/_Pragma.c b/test/Preprocessor/_Pragma.c
index 0a83b149ff75..15725a422299 100644
--- a/test/Preprocessor/_Pragma.c
+++ b/test/Preprocessor/_Pragma.c
@@ -5,6 +5,9 @@ _Pragma ("GCC system_header") // expected-warning {{system_header ignored in ma
// rdar://6880630
_Pragma("#define macro") // expected-warning {{unknown pragma ignored}}
+_Pragma("") // expected-warning {{unknown pragma ignored}}
+_Pragma("message(\"foo \\\\\\\\ bar\")") // expected-warning {{foo \\ bar}}
+
#ifdef macro
#error #define invalid
#endif
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index 8bb8427c0d2d..9978f91e2605 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -1,28 +1,33 @@
// RUN: %clang -target aarch64-none-linux-gnu -x c -E -dM %s -o - | FileCheck %s
-// CHECK: __AARCH64EL__
-// CHECK-NOT: __AARCH_ADVSIMD_FP
-// CHECK-NOT: __AARCH_FEATURE_ADVSIMD
-// CHECK: __ARM_ACLE 101
+
+// CHECK: __AARCH64EL__ 1
+// CHECK: __ARM_64BIT_STATE 1
+// CHECK: __ARM_ACLE 200
+// CHECK: __ARM_ALIGN_MAX_STACK_PWR 4
// CHECK: __ARM_ARCH 8
+// CHECK: __ARM_ARCH_ISA_A64 1
// CHECK: __ARM_ARCH_PROFILE 'A'
// CHECK-NOT: __ARM_FEATURE_BIG_ENDIAN
// CHECK: __ARM_FEATURE_CLZ 1
+// CHECK-NOT: __ARM_FEATURE_CRYPTO 1
+// CHECK: __ARM_FEATURE_DIV 1
// CHECK: __ARM_FEATURE_FMA 1
-// CHECK: __ARM_FEATURE_LDREX 0xf
// CHECK: __ARM_FEATURE_UNALIGNED 1
// CHECK: __ARM_FP 0xe
-// CHECK-NOT: __ARM_FP_FAST
// CHECK: __ARM_FP16_FORMAT_IEEE 1
+// CHECK-NOT: __ARM_FP_FAST 1
// CHECK: __ARM_FP_FENV_ROUNDING 1
-// CHECK-NOT: __ARM_NEON_FP
-// CHECK-NOT: __ARM_NEON
-// CHECK: __ARM_SIZEOF_MINIMAL_ENUM 4
-// CHECK: __ARM_SIZEOF_WCHAR_T 4
-// CHECK: __aarch64__
+// CHECK-NOT: __ARM_NEON 1
+// CHECK-NOT: __ARM_NEON_FP 7
+// CHECK: __ARM_PCS_AAPCS64 1
+// CHECK-NOT: __ARM_SIZEOF_MINIMAL_ENUM 1
+// CHECK-NOT: __ARM_SIZEOF_WCHAR_T 2
+// RUN: %clang -target aarch64-none-linux-gnu -mfpu=crypto-neon-fp-armv8 -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-CRYPTO %s
+// CHECK-CRYPTO: __ARM_FEATURE_CRYPTO 1
// RUN: %clang -target aarch64-none-linux-gnu -ffast-math -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-FASTMATH %s
-// CHECK-FASTMATH: __ARM_FP_FAST
+// CHECK-FASTMATH: __ARM_FP_FAST 1
// RUN: %clang -target aarch64-none-linux-gnu -fshort-wchar -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SHORTWCHAR %s
// CHECK-SHORTWCHAR: __ARM_SIZEOF_WCHAR_T 2
@@ -30,3 +35,6 @@
// RUN: %clang -target aarch64-none-linux-gnu -fshort-enums -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SHORTENUMS %s
// CHECK-SHORTENUMS: __ARM_SIZEOF_MINIMAL_ENUM 1
+// RUN: %clang -target aarch64-none-linux-gnu -mfpu=neon -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-NEON %s
+// CHECK-NEON: __ARM_NEON 1
+// CHECK-NEON: __ARM_NEON_FP 7
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
new file mode 100644
index 000000000000..ae93a3da7c08
--- /dev/null
+++ b/test/Preprocessor/arm-target-features.c
@@ -0,0 +1,157 @@
+// RUN: %clang -target armv8a-none-linux-gnu -x c -E -dM %s -o - | FileCheck %s
+// CHECK: __ARMEL__ 1
+// CHECK: __ARM_ARCH 8
+// CHECK: __ARM_ARCH_8A__ 1
+// CHECK: __ARM_FEATURE_CRC32 1
+
+// RUN: %clang -target armv7a-none-linux-gnu -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-V7 %s
+// CHECK-V7: __ARMEL__ 1
+// CHECK-V7: __ARM_ARCH 7
+// CHECK-V7: __ARM_ARCH_7A__ 1
+// CHECK-NOT-V7: __ARM_FEATURE_CRC32
+
+// RUN: %clang -target armv8a -mfloat-abi=hard -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-BAREHF %s
+// CHECK-V8-BAREHF: __ARMEL__ 1
+// CHECK-V8-BAREHF: __ARM_ARCH 8
+// CHECK-V8-BAREHF: __ARM_ARCH_8A__ 1
+// CHECK-V8-BAREHF: __ARM_FEATURE_CRC32 1
+// CHECK-V8-BAREHF: __ARM_NEON__ 1
+// CHECK-V8-BAREHF: __VFP_FP__ 1
+
+// RUN: %clang -target armv8a -mfloat-abi=hard -mfpu=fp-armv8 -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-BAREHF-FP %s
+// CHECK-V8-BAREHF-FP-NOT: __ARM_NEON__ 1
+// CHECK-V8-BAREHF-FP: __VFP_FP__ 1
+
+// RUN: %clang -target armv8a -mfloat-abi=hard -mfpu=neon-fp-armv8 -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-BAREHF-NEON-FP %s
+// RUN: %clang -target armv8a -mfloat-abi=hard -mfpu=crypto-neon-fp-armv8 -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-BAREHF-NEON-FP %s
+// CHECK-V8-BAREHF-NEON-FP: __ARM_NEON__ 1
+// CHECK-V8-BAREHF-NEON-FP: __VFP_FP__ 1
+
+// RUN: %clang -target armv8a -mnocrc -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-NOCRC %s
+// CHECK-V8-NOCRC-NOT: __ARM_FEATURE_CRC32 1
+
+// Check that -mhwdiv works properly for armv8/thumbv8 (enabled by default).
+
+// RUN: %clang -target armv8 -x c -E -dM %s -o - | FileCheck --check-prefix=ARMV8 %s
+// ARMV8:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8 -mthumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBV8 %s
+// THUMBV8:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8-eabi -x c -E -dM %s -o - | FileCheck --check-prefix=ARMV8-EABI %s
+// ARMV8-EABI:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8-eabi -mthumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBV8-EABI %s
+// THUMBV8-EABI:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8 -mhwdiv=none -x c -E -dM %s -o - | FileCheck --check-prefix=NONEHWDIV-ARMV8 %s
+// NONEHWDIV-ARMV8-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv8 -mthumb -mhwdiv=none -x c -E -dM %s -o - | FileCheck --check-prefix=NONEHWDIV-THUMBV8 %s
+// NONEHWDIV-THUMBV8-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv8 -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-ARMV8 %s
+// THUMBHWDIV-ARMV8-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv8 -mthumb -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARMHWDIV-THUMBV8 %s
+// ARMHWDIV-THUMBV8-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv8a -x c -E -dM %s -o - | FileCheck --check-prefix=ARMV8A %s
+// ARMV8A:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8a -mthumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBV8A %s
+// THUMBV8A:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8a-eabi -x c -E -dM %s -o - | FileCheck --check-prefix=ARMV8A-EABI %s
+// ARMV8A-EABI:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8a-eabi -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBV8A-EABI %s
+// THUMBV8A-EABI:#define __ARM_ARCH_EXT_IDIV__ 1
+
+
+// Test that -mhwdiv has the right effect for a target CPU which has hwdiv enabled by default.
+// RUN: %clang -target armv7 -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-ARM %s
+// DEFAULTHWDIV-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-THUMB %s
+// DEFAULTHWDIV-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7 -mcpu=cortex-a15 -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARMHWDIV-ARM %s
+// ARMHWDIV-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a15 -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-THUMB %s
+// THUMBHWDIV-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target arm -mcpu=cortex-a15 -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-THUMBHWDIV-ARM %s
+// DEFAULTHWDIV-THUMBHWDIV-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mthumb -mcpu=cortex-a15 -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-ARMHWDIV-THUMB %s
+// DEFAULTHWDIV-ARMHWDIV-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mcpu=cortex-a15 -mhwdiv=none -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-NONEHWDIV-ARM %s
+// DEFAULTHWDIV-NONEHWDIV-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mthumb -mcpu=cortex-a15 -mhwdiv=none -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTHWDIV-NONEHWDIV-THUMB %s
+// DEFAULTHWDIV-NONEHWDIV-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// FIXME: add check for further predefines
+// Test whether predefines are as expected when targeting cortex-a5.
+// RUN: %clang -target armv7 -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5-ARM %s
+// A5-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5-THUMB %s
+// A5-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// Test whether predefines are as expected when targeting cortex-a8.
+// RUN: %clang -target armv7 -mcpu=cortex-a8 -x c -E -dM %s -o - | FileCheck --check-prefix=A8-ARM %s
+// A8-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a8 -x c -E -dM %s -o - | FileCheck --check-prefix=A8-THUMB %s
+// A8-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// Test whether predefines are as expected when targeting cortex-a9.
+// RUN: %clang -target armv7 -mcpu=cortex-a9 -x c -E -dM %s -o - | FileCheck --check-prefix=A9-ARM %s
+// A9-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a9 -x c -E -dM %s -o - | FileCheck --check-prefix=A9-THUMB %s
+// A9-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// Test whether predefines are as expected when targeting cortex-a15.
+// RUN: %clang -target armv7 -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=A15-ARM %s
+// A15-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=A15-THUMB %s
+// A15-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// Test whether predefines are as expected when targeting swift.
+// RUN: %clang -target armv7s -mcpu=swift -x c -E -dM %s -o - | FileCheck --check-prefix=SWIFT-ARM %s
+// SWIFT-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7s -mthumb -mcpu=swift -x c -E -dM %s -o - | FileCheck --check-prefix=SWIFT-THUMB %s
+// SWIFT-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// Test whether predefines are as expected when targeting cortex-a53.
+// RUN: %clang -target armv8 -mcpu=cortex-a53 -x c -E -dM %s -o - | FileCheck --check-prefix=A53-ARM %s
+// A53-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv8 -mthumb -mcpu=cortex-a53 -x c -E -dM %s -o - | FileCheck --check-prefix=A53-THUMB %s
+// A53-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// Test whether predefines are as expected when targeting cortex-r5.
+// RUN: %clang -target armv7 -mcpu=cortex-r5 -x c -E -dM %s -o - | FileCheck --check-prefix=R5-ARM %s
+// R5-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-r5 -x c -E -dM %s -o - | FileCheck --check-prefix=R5-THUMB %s
+// R5-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// Test whether predefines are as expected when targeting cortex-m0.
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m0 -x c -E -dM %s -o - | FileCheck --check-prefix=M0-THUMB %s
+// M0-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// Test whether predefines are as expected when targeting cortex-m3.
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m3 -x c -E -dM %s -o - | FileCheck --check-prefix=M3-THUMB %s
+// M3-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// Test whether predefines are as expected when targeting cortex-m4.
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m4 -x c -E -dM %s -o - | FileCheck --check-prefix=M4-THUMB %s
+// M4-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
diff --git a/test/Preprocessor/assembler-with-cpp.c b/test/Preprocessor/assembler-with-cpp.c
index a9c42940a310..f03cb06ea115 100644
--- a/test/Preprocessor/assembler-with-cpp.c
+++ b/test/Preprocessor/assembler-with-cpp.c
@@ -72,8 +72,15 @@
11: T11(b)
// CHECK-Identifiers-True: 11: #0
+// Universal character names can specify basic ascii and control characters
+12: \u0020\u0030\u0080\u0000
+// CHECK-Identifiers-False: 12: \u0020\u0030\u0080\u0000
// This should not crash
// rdar://8823139
# ##
// CHECK-Identifiers-False: # ##
+
+#define X(a) # # # 1
+X(1)
+// CHECK-Identifiers-False: # # # 1
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index 19d80468ab3f..5a2c300e6ee1 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -11,6 +11,7 @@
#if !__has_builtin(__builtin_huge_val) || \
!__has_builtin(__builtin_shufflevector) || \
+ !__has_builtin(__builtin_convertvector) || \
!__has_builtin(__builtin_trap) || \
!__has_builtin(__c11_atomic_init) || \
!__has_feature(attribute_analyzer_noreturn) || \
diff --git a/test/Preprocessor/has_attribute.c b/test/Preprocessor/has_attribute.c
index 711cf671cfea..555c2b3f9e22 100644
--- a/test/Preprocessor/has_attribute.c
+++ b/test/Preprocessor/has_attribute.c
@@ -34,3 +34,7 @@ int has_something_we_dont_have();
static int constFunction() __attribute__((const));
#endif
+// CHECK: has_no_volatile_attribute
+#if !__has_attribute(volatile)
+int has_no_volatile_attribute();
+#endif
diff --git a/test/Preprocessor/hash_line.c b/test/Preprocessor/hash_line.c
index 64edae0d9577..c4de9f04044e 100644
--- a/test/Preprocessor/hash_line.c
+++ b/test/Preprocessor/hash_line.c
@@ -1,11 +1,12 @@
// The 1 and # should not go on the same line.
// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
-// CHECK-NOT: 1{{.*}}#
// CHECK: {{^1$}}
-// CHECK-NOT: 1{{.*}}#
-// CHECK: {{^ #$}}
-// CHECK-NOT: 1{{.*}}#
-1
+// CHECK-NEXT: {{^ #$}}
+// CHECK-NEXT: {{^2$}}
+// CHECK-NEXT: {{^ #$}}
#define EMPTY
+#define IDENTITY(X) X
+1
EMPTY #
-
+2
+IDENTITY() #
diff --git a/test/Preprocessor/ifdef-recover.c b/test/Preprocessor/ifdef-recover.c
index 51d06d1f1b6e..3d652dc604d9 100644
--- a/test/Preprocessor/ifdef-recover.c
+++ b/test/Preprocessor/ifdef-recover.c
@@ -1,4 +1,4 @@
-/* RUN: %clang_cc1 -E %s 2>&1 >/dev/null | grep error: | count 3
+/* RUN: not %clang_cc1 -E %s 2>&1 >/dev/null | grep error: | count 3
*/
#ifdef
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 9671f7e23293..8486e94b3a73 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -49,6 +49,14 @@
// C99:#define __STRICT_ANSI__ 1
//
//
+// RUN: %clang_cc1 -std=c11 -E -dM < /dev/null | FileCheck -check-prefix C11 %s
+//
+// C11:#define __STDC_UTF_16__ 1
+// C11:#define __STDC_UTF_32__ 1
+// C11:#define __STDC_VERSION__ 201112L
+// C11:#define __STRICT_ANSI__ 1
+//
+//
// RUN: %clang_cc1 -E -dM < /dev/null | FileCheck -check-prefix COMMON %s
//
// COMMON:#define __CONSTANT_CFSTRINGS__ 1
@@ -144,7 +152,7 @@
// NONFRAGILE:#define __OBJC2__ 1
//
//
-// RUN: %clang_cc1 -O0 -E -dM < /dev/null | FileCheck -check-prefix O0 %s
+// RUN: %clang_cc1 -E -dM < /dev/null | FileCheck -check-prefix O0 %s
//
// O0:#define __NO_INLINE__ 1
// O0-NOT:#define __OPTIMIZE_SIZE__
@@ -504,6 +512,33 @@
// ARMEABIHARDFP:#define __arm 1
// ARMEABIHARDFP:#define __arm__ 1
+// RUN: %clang -target arm -arch armv7s -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target arm -arch armv6m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target arm -arch armv7m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target arm -arch armv7em -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target thumbv7-apple-darwin-eabi -arch armv7 -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// ARM-DARWIN-NO-EABI-NOT: #define __ARM_EABI__ 1
+
+// 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 --check-prefix=ARMHWDIV-ARM %s
+// ARMHWDIV-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target arm -mthumb -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-THUMB %s
+// THUMBHWDIV-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+
+// RUN: %clang -target arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-FALSE %s
+// ARM-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mthumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMB-FALSE %s
+// THUMB-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mhwdiv=thumb -x c -E -dM %s -o - | FileCheck --check-prefix=THUMBHWDIV-ARM-FALSE %s
+// THUMBHWDIV-ARM-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__
+
+// RUN: %clang -target arm -mthumb -mhwdiv=arm -x c -E -dM %s -o - | FileCheck --check-prefix=ARMHWDIV-THUMB-FALSE %s
+// ARMHWDIV-THUMB-FALSE-NOT:#define __ARM_ARCH_EXT_IDIV__
+
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-none-none < /dev/null | FileCheck -check-prefix I386 %s
//
@@ -701,6 +736,112 @@
// I386-LINUX:#define __i386__ 1
// I386-LINUX:#define i386 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd < /dev/null | FileCheck -check-prefix I386-NETBSD %s
+//
+// I386-NETBSD-NOT:#define _LP64
+// I386-NETBSD:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// I386-NETBSD:#define __CHAR16_TYPE__ unsigned short
+// I386-NETBSD:#define __CHAR32_TYPE__ unsigned int
+// I386-NETBSD:#define __CHAR_BIT__ 8
+// I386-NETBSD:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// I386-NETBSD:#define __DBL_DIG__ 15
+// I386-NETBSD:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// I386-NETBSD:#define __DBL_HAS_DENORM__ 1
+// I386-NETBSD:#define __DBL_HAS_INFINITY__ 1
+// I386-NETBSD:#define __DBL_HAS_QUIET_NAN__ 1
+// I386-NETBSD:#define __DBL_MANT_DIG__ 53
+// I386-NETBSD:#define __DBL_MAX_10_EXP__ 308
+// I386-NETBSD:#define __DBL_MAX_EXP__ 1024
+// I386-NETBSD:#define __DBL_MAX__ 1.7976931348623157e+308
+// I386-NETBSD:#define __DBL_MIN_10_EXP__ (-307)
+// I386-NETBSD:#define __DBL_MIN_EXP__ (-1021)
+// I386-NETBSD:#define __DBL_MIN__ 2.2250738585072014e-308
+// I386-NETBSD:#define __DECIMAL_DIG__ 21
+// I386-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// I386-NETBSD:#define __FLT_DIG__ 6
+// I386-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F
+// I386-NETBSD:#define __FLT_EVAL_METHOD__ 2
+// I386-NETBSD:#define __FLT_HAS_DENORM__ 1
+// I386-NETBSD:#define __FLT_HAS_INFINITY__ 1
+// I386-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1
+// I386-NETBSD:#define __FLT_MANT_DIG__ 24
+// I386-NETBSD:#define __FLT_MAX_10_EXP__ 38
+// I386-NETBSD:#define __FLT_MAX_EXP__ 128
+// I386-NETBSD:#define __FLT_MAX__ 3.40282347e+38F
+// I386-NETBSD:#define __FLT_MIN_10_EXP__ (-37)
+// I386-NETBSD:#define __FLT_MIN_EXP__ (-125)
+// I386-NETBSD:#define __FLT_MIN__ 1.17549435e-38F
+// I386-NETBSD:#define __FLT_RADIX__ 2
+// I386-NETBSD:#define __INT16_TYPE__ short
+// I386-NETBSD:#define __INT32_TYPE__ int
+// I386-NETBSD:#define __INT64_C_SUFFIX__ LL
+// I386-NETBSD:#define __INT64_TYPE__ long long int
+// I386-NETBSD:#define __INT8_TYPE__ char
+// I386-NETBSD:#define __INTMAX_MAX__ 9223372036854775807LL
+// I386-NETBSD:#define __INTMAX_TYPE__ long long int
+// I386-NETBSD:#define __INTMAX_WIDTH__ 64
+// I386-NETBSD:#define __INTPTR_TYPE__ int
+// I386-NETBSD:#define __INTPTR_WIDTH__ 32
+// I386-NETBSD:#define __INT_MAX__ 2147483647
+// I386-NETBSD:#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
+// I386-NETBSD:#define __LDBL_DIG__ 18
+// I386-NETBSD:#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
+// I386-NETBSD:#define __LDBL_HAS_DENORM__ 1
+// I386-NETBSD:#define __LDBL_HAS_INFINITY__ 1
+// I386-NETBSD:#define __LDBL_HAS_QUIET_NAN__ 1
+// I386-NETBSD:#define __LDBL_MANT_DIG__ 64
+// I386-NETBSD:#define __LDBL_MAX_10_EXP__ 4932
+// I386-NETBSD:#define __LDBL_MAX_EXP__ 16384
+// I386-NETBSD:#define __LDBL_MAX__ 1.18973149535723176502e+4932L
+// I386-NETBSD:#define __LDBL_MIN_10_EXP__ (-4931)
+// I386-NETBSD:#define __LDBL_MIN_EXP__ (-16381)
+// I386-NETBSD:#define __LDBL_MIN__ 3.36210314311209350626e-4932L
+// I386-NETBSD:#define __LITTLE_ENDIAN__ 1
+// I386-NETBSD:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// I386-NETBSD:#define __LONG_MAX__ 2147483647L
+// I386-NETBSD-NOT:#define __LP64__
+// I386-NETBSD:#define __NO_MATH_INLINES 1
+// I386-NETBSD:#define __POINTER_WIDTH__ 32
+// I386-NETBSD:#define __PTRDIFF_TYPE__ int
+// I386-NETBSD:#define __PTRDIFF_WIDTH__ 32
+// I386-NETBSD:#define __REGISTER_PREFIX__
+// I386-NETBSD:#define __SCHAR_MAX__ 127
+// I386-NETBSD:#define __SHRT_MAX__ 32767
+// I386-NETBSD:#define __SIG_ATOMIC_WIDTH__ 32
+// I386-NETBSD:#define __SIZEOF_DOUBLE__ 8
+// I386-NETBSD:#define __SIZEOF_FLOAT__ 4
+// I386-NETBSD:#define __SIZEOF_INT__ 4
+// I386-NETBSD:#define __SIZEOF_LONG_DOUBLE__ 12
+// I386-NETBSD:#define __SIZEOF_LONG_LONG__ 8
+// I386-NETBSD:#define __SIZEOF_LONG__ 4
+// I386-NETBSD:#define __SIZEOF_POINTER__ 4
+// I386-NETBSD:#define __SIZEOF_PTRDIFF_T__ 4
+// I386-NETBSD:#define __SIZEOF_SHORT__ 2
+// I386-NETBSD:#define __SIZEOF_SIZE_T__ 4
+// I386-NETBSD:#define __SIZEOF_WCHAR_T__ 4
+// I386-NETBSD:#define __SIZEOF_WINT_T__ 4
+// I386-NETBSD:#define __SIZE_MAX__ 4294967295U
+// I386-NETBSD:#define __SIZE_TYPE__ unsigned int
+// I386-NETBSD:#define __SIZE_WIDTH__ 32
+// I386-NETBSD:#define __UINTMAX_TYPE__ long long unsigned int
+// I386-NETBSD:#define __USER_LABEL_PREFIX__
+// I386-NETBSD:#define __WCHAR_MAX__ 2147483647
+// I386-NETBSD:#define __WCHAR_TYPE__ int
+// I386-NETBSD:#define __WCHAR_WIDTH__ 32
+// I386-NETBSD:#define __WINT_TYPE__ int
+// I386-NETBSD:#define __WINT_WIDTH__ 32
+// I386-NETBSD:#define __i386 1
+// I386-NETBSD:#define __i386__ 1
+// I386-NETBSD:#define i386 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd -target-feature +sse2 < /dev/null | FileCheck -check-prefix I386-NETBSD-SSE %s
+// I386-NETBSD-SSE:#define __FLT_EVAL_METHOD__ 0
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6 < /dev/null | FileCheck -check-prefix I386-NETBSD6 %s
+// I386-NETBSD6:#define __FLT_EVAL_METHOD__ 1
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6 -target-feature +sse2 < /dev/null | FileCheck -check-prefix I386-NETBSD6-SSE %s
+// I386-NETBSD6-SSE:#define __FLT_EVAL_METHOD__ 1
+
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips-none-none < /dev/null | FileCheck -check-prefix MIPS32BE %s
//
// MIPS32BE:#define MIPSEB 1
@@ -709,6 +850,7 @@
// MIPS32BE:#define _MIPSEB 1
// MIPS32BE:#define _MIPS_ARCH "mips32"
// MIPS32BE:#define _MIPS_ARCH_MIPS32 1
+// MIPS32BE:#define _MIPS_FPSET 16
// MIPS32BE:#define _MIPS_SIM _ABIO32
// MIPS32BE:#define _MIPS_SZINT 32
// MIPS32BE:#define _MIPS_SZLONG 32
@@ -813,6 +955,7 @@
// MIPS32BE:#define __llvm__ 1
// MIPS32BE:#define __mips 1
// MIPS32BE:#define __mips__ 1
+// MIPS32BE:#define __mips_fpr 32
// MIPS32BE:#define __mips_hard_float 1
// MIPS32BE:#define __mips_o32 1
// MIPS32BE:#define _mips 1
@@ -826,6 +969,7 @@
// MIPS32EL:#define _MIPSEL 1
// MIPS32EL:#define _MIPS_ARCH "mips32"
// MIPS32EL:#define _MIPS_ARCH_MIPS32 1
+// MIPS32EL:#define _MIPS_FPSET 16
// MIPS32EL:#define _MIPS_SIM _ABIO32
// MIPS32EL:#define _MIPS_SZINT 32
// MIPS32EL:#define _MIPS_SZLONG 32
@@ -927,6 +1071,7 @@
// MIPS32EL:#define __llvm__ 1
// MIPS32EL:#define __mips 1
// MIPS32EL:#define __mips__ 1
+// MIPS32EL:#define __mips_fpr 32
// MIPS32EL:#define __mips_hard_float 1
// MIPS32EL:#define __mips_o32 1
// MIPS32EL:#define _mips 1
@@ -940,6 +1085,7 @@
// MIPS64BE:#define _MIPSEB 1
// MIPS64BE:#define _MIPS_ARCH "mips64"
// MIPS64BE:#define _MIPS_ARCH_MIPS64 1
+// MIPS64BE:#define _MIPS_FPSET 32
// MIPS64BE:#define _MIPS_SIM _ABI64
// MIPS64BE:#define _MIPS_SZINT 32
// MIPS64BE:#define _MIPS_SZLONG 64
@@ -1043,6 +1189,7 @@
// MIPS64BE:#define __mips64 1
// MIPS64BE:#define __mips64__ 1
// MIPS64BE:#define __mips__ 1
+// MIPS64BE:#define __mips_fpr 64
// MIPS64BE:#define __mips_hard_float 1
// MIPS64BE:#define __mips_n64 1
// MIPS64BE:#define _mips 1
@@ -1056,6 +1203,7 @@
// MIPS64EL:#define _MIPSEL 1
// MIPS64EL:#define _MIPS_ARCH "mips64"
// MIPS64EL:#define _MIPS_ARCH_MIPS64 1
+// MIPS64EL:#define _MIPS_FPSET 32
// MIPS64EL:#define _MIPS_SIM _ABI64
// MIPS64EL:#define _MIPS_SZINT 32
// MIPS64EL:#define _MIPS_SZLONG 64
@@ -1159,6 +1307,7 @@
// MIPS64EL:#define __mips64 1
// MIPS64EL:#define __mips64__ 1
// MIPS64EL:#define __mips__ 1
+// MIPS64EL:#define __mips_fpr 64
// MIPS64EL:#define __mips_hard_float 1
// MIPS64EL:#define __mips_n64 1
// MIPS64EL:#define _mips 1
@@ -1224,6 +1373,46 @@
// MIPS-DSPR2:#define __mips_dsp_rev 2
// MIPS-DSPR2:#define __mips_dspr2 1
//
+// RUN: %clang_cc1 -target-feature +msa \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS-MSA %s
+// MIPS-MSA:#define __mips_msa 1
+//
+// RUN: %clang_cc1 -target-feature +nan2008 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS-NAN2008 %s
+// MIPS-NAN2008:#define __mips_nan2008 1
+//
+// RUN: %clang_cc1 -target-feature -fp64 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS32-MFP32 %s
+// MIPS32-MFP32:#define _MIPS_FPSET 16
+// MIPS32-MFP32:#define __mips_fpr 32
+//
+// RUN: %clang_cc1 -target-feature +fp64 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS32-MFP64 %s
+// MIPS32-MFP64:#define _MIPS_FPSET 32
+// MIPS32-MFP64:#define __mips_fpr 64
+//
+// RUN: %clang_cc1 -target-feature +single-float \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS32-MFP32SF %s
+// MIPS32-MFP32SF:#define _MIPS_FPSET 32
+// MIPS32-MFP32SF:#define __mips_fpr 32
+//
+// RUN: %clang_cc1 -target-feature +fp64 \
+// RUN: -E -dM -triple=mips64-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS64-MFP64 %s
+// MIPS64-MFP64:#define _MIPS_FPSET 32
+// MIPS64-MFP64:#define __mips_fpr 64
+//
+// RUN: %clang_cc1 -target-feature -fp64 -target-feature +single-float \
+// RUN: -E -dM -triple=mips64-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS64-NOMFP64 %s
+// MIPS64-NOMFP64:#define _MIPS_FPSET 32
+// MIPS64-NOMFP64:#define __mips_fpr 32
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -check-prefix MSP430 %s
//
// MSP430:#define MSP430 1
@@ -1265,10 +1454,10 @@
// MSP430:#define __INT32_C_SUFFIX__ L
// MSP430:#define __INT32_TYPE__ long int
// MSP430:#define __INT8_TYPE__ char
-// MSP430:#define __INTMAX_MAX__ 2147483647L
-// MSP430:#define __INTMAX_TYPE__ long int
-// MSP430:#define __INTMAX_WIDTH__ 32
-// MSP430:#define __INTPTR_TYPE__ short
+// MSP430:#define __INTMAX_MAX__ 9223372036854775807LL
+// MSP430:#define __INTMAX_TYPE__ long long int
+// MSP430:#define __INTMAX_WIDTH__ 64
+// MSP430:#define __INTPTR_TYPE__ int
// MSP430:#define __INTPTR_WIDTH__ 16
// MSP430:#define __INT_MAX__ 32767
// MSP430:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
@@ -1309,7 +1498,7 @@
// MSP430:#define __SIZE_MAX__ 65535U
// MSP430:#define __SIZE_TYPE__ unsigned int
// MSP430:#define __SIZE_WIDTH__ 16
-// MSP430:#define __UINTMAX_TYPE__ long unsigned int
+// MSP430:#define __UINTMAX_TYPE__ long long unsigned int
// MSP430:#define __USER_LABEL_PREFIX__ _
// MSP430:#define __WCHAR_MAX__ 32767
// MSP430:#define __WCHAR_TYPE__ int
@@ -1585,6 +1774,7 @@
// PPC603E:#define __NATURAL_ALIGNMENT__ 1
// PPC603E:#define __POINTER_WIDTH__ 32
// PPC603E:#define __POWERPC__ 1
+// PPC603E:#define __PPC__ 1
// PPC603E:#define __PTRDIFF_TYPE__ long int
// PPC603E:#define __PTRDIFF_WIDTH__ 32
// PPC603E:#define __REGISTER_PREFIX__
@@ -1694,6 +1884,8 @@
// PPC64:#define __NATURAL_ALIGNMENT__ 1
// PPC64:#define __POINTER_WIDTH__ 64
// PPC64:#define __POWERPC__ 1
+// PPC64:#define __PPC64__ 1
+// PPC64:#define __PPC__ 1
// PPC64:#define __PTRDIFF_TYPE__ long int
// PPC64:#define __PTRDIFF_WIDTH__ 64
// PPC64:#define __REGISTER_PREFIX__
@@ -1725,6 +1917,119 @@
// PPC64:#define __ppc64__ 1
// PPC64:#define __ppc__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-none-none -target-cpu pwr7 -fno-signed-char < /dev/null | FileCheck -check-prefix PPC64LE %s
+//
+// PPC64LE:#define _ARCH_PPC 1
+// PPC64LE:#define _ARCH_PPC64 1
+// PPC64LE:#define _ARCH_PPCGR 1
+// PPC64LE:#define _ARCH_PPCSQ 1
+// PPC64LE:#define _ARCH_PWR4 1
+// PPC64LE:#define _ARCH_PWR5 1
+// PPC64LE:#define _ARCH_PWR5X 1
+// PPC64LE:#define _ARCH_PWR6 1
+// PPC64LE:#define _ARCH_PWR6X 1
+// PPC64LE:#define _ARCH_PWR7 1
+// PPC64LE:#define _LITTLE_ENDIAN 1
+// PPC64LE:#define _LP64 1
+// PPC64LE:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// PPC64LE:#define __CHAR16_TYPE__ unsigned short
+// PPC64LE:#define __CHAR32_TYPE__ unsigned int
+// PPC64LE:#define __CHAR_BIT__ 8
+// PPC64LE:#define __CHAR_UNSIGNED__ 1
+// PPC64LE:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// PPC64LE:#define __DBL_DIG__ 15
+// PPC64LE:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// PPC64LE:#define __DBL_HAS_DENORM__ 1
+// PPC64LE:#define __DBL_HAS_INFINITY__ 1
+// PPC64LE:#define __DBL_HAS_QUIET_NAN__ 1
+// PPC64LE:#define __DBL_MANT_DIG__ 53
+// PPC64LE:#define __DBL_MAX_10_EXP__ 308
+// PPC64LE:#define __DBL_MAX_EXP__ 1024
+// PPC64LE:#define __DBL_MAX__ 1.7976931348623157e+308
+// PPC64LE:#define __DBL_MIN_10_EXP__ (-307)
+// PPC64LE:#define __DBL_MIN_EXP__ (-1021)
+// PPC64LE:#define __DBL_MIN__ 2.2250738585072014e-308
+// PPC64LE:#define __DECIMAL_DIG__ 33
+// PPC64LE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// PPC64LE:#define __FLT_DIG__ 6
+// PPC64LE:#define __FLT_EPSILON__ 1.19209290e-7F
+// PPC64LE:#define __FLT_EVAL_METHOD__ 0
+// PPC64LE:#define __FLT_HAS_DENORM__ 1
+// PPC64LE:#define __FLT_HAS_INFINITY__ 1
+// PPC64LE:#define __FLT_HAS_QUIET_NAN__ 1
+// PPC64LE:#define __FLT_MANT_DIG__ 24
+// PPC64LE:#define __FLT_MAX_10_EXP__ 38
+// PPC64LE:#define __FLT_MAX_EXP__ 128
+// PPC64LE:#define __FLT_MAX__ 3.40282347e+38F
+// PPC64LE:#define __FLT_MIN_10_EXP__ (-37)
+// PPC64LE:#define __FLT_MIN_EXP__ (-125)
+// PPC64LE:#define __FLT_MIN__ 1.17549435e-38F
+// PPC64LE:#define __FLT_RADIX__ 2
+// PPC64LE:#define __INT16_TYPE__ short
+// PPC64LE:#define __INT32_TYPE__ int
+// PPC64LE:#define __INT64_C_SUFFIX__ L
+// PPC64LE:#define __INT64_TYPE__ long int
+// PPC64LE:#define __INT8_TYPE__ char
+// PPC64LE:#define __INTMAX_MAX__ 9223372036854775807L
+// PPC64LE:#define __INTMAX_TYPE__ long int
+// PPC64LE:#define __INTMAX_WIDTH__ 64
+// PPC64LE:#define __INTPTR_TYPE__ long int
+// PPC64LE:#define __INTPTR_WIDTH__ 64
+// PPC64LE:#define __INT_MAX__ 2147483647
+// PPC64LE:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC64LE:#define __LDBL_DIG__ 31
+// PPC64LE:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
+// PPC64LE:#define __LDBL_HAS_DENORM__ 1
+// PPC64LE:#define __LDBL_HAS_INFINITY__ 1
+// PPC64LE:#define __LDBL_HAS_QUIET_NAN__ 1
+// PPC64LE:#define __LDBL_MANT_DIG__ 106
+// PPC64LE:#define __LDBL_MAX_10_EXP__ 308
+// PPC64LE:#define __LDBL_MAX_EXP__ 1024
+// PPC64LE:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// PPC64LE:#define __LDBL_MIN_10_EXP__ (-291)
+// PPC64LE:#define __LDBL_MIN_EXP__ (-968)
+// PPC64LE:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC64LE:#define __LITTLE_ENDIAN__ 1
+// PPC64LE:#define __LONG_DOUBLE_128__ 1
+// PPC64LE:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// PPC64LE:#define __LONG_MAX__ 9223372036854775807L
+// PPC64LE:#define __LP64__ 1
+// PPC64LE:#define __NATURAL_ALIGNMENT__ 1
+// PPC64LE:#define __POINTER_WIDTH__ 64
+// PPC64LE:#define __POWERPC__ 1
+// PPC64LE:#define __PPC64__ 1
+// PPC64LE:#define __PPC__ 1
+// PPC64LE:#define __PTRDIFF_TYPE__ long int
+// PPC64LE:#define __PTRDIFF_WIDTH__ 64
+// PPC64LE:#define __REGISTER_PREFIX__
+// PPC64LE:#define __SCHAR_MAX__ 127
+// PPC64LE:#define __SHRT_MAX__ 32767
+// PPC64LE:#define __SIG_ATOMIC_WIDTH__ 32
+// PPC64LE:#define __SIZEOF_DOUBLE__ 8
+// PPC64LE:#define __SIZEOF_FLOAT__ 4
+// PPC64LE:#define __SIZEOF_INT__ 4
+// PPC64LE:#define __SIZEOF_LONG_DOUBLE__ 16
+// PPC64LE:#define __SIZEOF_LONG_LONG__ 8
+// PPC64LE:#define __SIZEOF_LONG__ 8
+// PPC64LE:#define __SIZEOF_POINTER__ 8
+// PPC64LE:#define __SIZEOF_PTRDIFF_T__ 8
+// PPC64LE:#define __SIZEOF_SHORT__ 2
+// PPC64LE:#define __SIZEOF_SIZE_T__ 8
+// PPC64LE:#define __SIZEOF_WCHAR_T__ 4
+// PPC64LE:#define __SIZEOF_WINT_T__ 4
+// PPC64LE:#define __SIZE_MAX__ 18446744073709551615UL
+// PPC64LE:#define __SIZE_TYPE__ long unsigned int
+// PPC64LE:#define __SIZE_WIDTH__ 64
+// PPC64LE:#define __UINTMAX_TYPE__ long unsigned int
+// PPC64LE:#define __USER_LABEL_PREFIX__ _
+// PPC64LE:#define __WCHAR_MAX__ 2147483647
+// PPC64LE:#define __WCHAR_TYPE__ int
+// PPC64LE:#define __WCHAR_WIDTH__ 32
+// PPC64LE:#define __WINT_TYPE__ int
+// PPC64LE:#define __WINT_WIDTH__ 32
+// PPC64LE:#define __ppc64__ 1
+// PPC64LE:#define __ppc__ 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu a2q -fno-signed-char < /dev/null | FileCheck -check-prefix PPCA2Q %s
//
// PPCA2Q:#define _ARCH_A2 1
@@ -1957,6 +2262,8 @@
// PPC64-LINUX:#define __NATURAL_ALIGNMENT__ 1
// PPC64-LINUX:#define __POINTER_WIDTH__ 64
// PPC64-LINUX:#define __POWERPC__ 1
+// PPC64-LINUX:#define __PPC64__ 1
+// PPC64-LINUX:#define __PPC__ 1
// PPC64-LINUX:#define __PTRDIFF_TYPE__ long int
// PPC64-LINUX:#define __PTRDIFF_WIDTH__ 64
// PPC64-LINUX:#define __REGISTER_PREFIX__
@@ -2062,6 +2369,7 @@
// PPC:#define __NATURAL_ALIGNMENT__ 1
// PPC:#define __POINTER_WIDTH__ 32
// PPC:#define __POWERPC__ 1
+// PPC:#define __PPC__ 1
// PPC:#define __PTRDIFF_TYPE__ long int
// PPC:#define __PTRDIFF_WIDTH__ 32
// PPC:#define __REGISTER_PREFIX__
@@ -2163,6 +2471,7 @@
// PPC-LINUX:#define __NATURAL_ALIGNMENT__ 1
// PPC-LINUX:#define __POINTER_WIDTH__ 32
// PPC-LINUX:#define __POWERPC__ 1
+// PPC-LINUX:#define __PPC__ 1
// PPC-LINUX:#define __PTRDIFF_TYPE__ int
// PPC-LINUX:#define __PTRDIFF_WIDTH__ 32
// PPC-LINUX:#define __REGISTER_PREFIX__
@@ -2195,6 +2504,113 @@
// PPC-LINUX:#define __powerpc__ 1
// PPC-LINUX:#define __ppc__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-apple-darwin8 < /dev/null | FileCheck -check-prefix PPC-DARWIN %s
+//
+// PPC-DARWIN:#define _ARCH_PPC 1
+// PPC-DARWIN:#define _BIG_ENDIAN 1
+// PPC-DARWIN:#define __BIG_ENDIAN__ 1
+// PPC-DARWIN:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
+// PPC-DARWIN:#define __CHAR16_TYPE__ unsigned short
+// PPC-DARWIN:#define __CHAR32_TYPE__ unsigned int
+// PPC-DARWIN:#define __CHAR_BIT__ 8
+// PPC-DARWIN:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// PPC-DARWIN:#define __DBL_DIG__ 15
+// PPC-DARWIN:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// PPC-DARWIN:#define __DBL_HAS_DENORM__ 1
+// PPC-DARWIN:#define __DBL_HAS_INFINITY__ 1
+// PPC-DARWIN:#define __DBL_HAS_QUIET_NAN__ 1
+// PPC-DARWIN:#define __DBL_MANT_DIG__ 53
+// PPC-DARWIN:#define __DBL_MAX_10_EXP__ 308
+// PPC-DARWIN:#define __DBL_MAX_EXP__ 1024
+// PPC-DARWIN:#define __DBL_MAX__ 1.7976931348623157e+308
+// PPC-DARWIN:#define __DBL_MIN_10_EXP__ (-307)
+// PPC-DARWIN:#define __DBL_MIN_EXP__ (-1021)
+// PPC-DARWIN:#define __DBL_MIN__ 2.2250738585072014e-308
+// PPC-DARWIN:#define __DECIMAL_DIG__ 33
+// PPC-DARWIN:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// PPC-DARWIN:#define __FLT_DIG__ 6
+// PPC-DARWIN:#define __FLT_EPSILON__ 1.19209290e-7F
+// PPC-DARWIN:#define __FLT_EVAL_METHOD__ 0
+// PPC-DARWIN:#define __FLT_HAS_DENORM__ 1
+// PPC-DARWIN:#define __FLT_HAS_INFINITY__ 1
+// PPC-DARWIN:#define __FLT_HAS_QUIET_NAN__ 1
+// PPC-DARWIN:#define __FLT_MANT_DIG__ 24
+// PPC-DARWIN:#define __FLT_MAX_10_EXP__ 38
+// PPC-DARWIN:#define __FLT_MAX_EXP__ 128
+// PPC-DARWIN:#define __FLT_MAX__ 3.40282347e+38F
+// PPC-DARWIN:#define __FLT_MIN_10_EXP__ (-37)
+// PPC-DARWIN:#define __FLT_MIN_EXP__ (-125)
+// PPC-DARWIN:#define __FLT_MIN__ 1.17549435e-38F
+// PPC-DARWIN:#define __FLT_RADIX__ 2
+// PPC-DARWIN:#define __INT16_TYPE__ short
+// PPC-DARWIN:#define __INT32_TYPE__ int
+// PPC-DARWIN:#define __INT64_C_SUFFIX__ LL
+// PPC-DARWIN:#define __INT64_TYPE__ long long int
+// PPC-DARWIN:#define __INT8_TYPE__ char
+// PPC-DARWIN:#define __INTMAX_MAX__ 9223372036854775807LL
+// PPC-DARWIN:#define __INTMAX_TYPE__ long long int
+// PPC-DARWIN:#define __INTMAX_WIDTH__ 64
+// PPC-DARWIN:#define __INTPTR_TYPE__ long int
+// PPC-DARWIN:#define __INTPTR_WIDTH__ 32
+// PPC-DARWIN:#define __INT_MAX__ 2147483647
+// PPC-DARWIN:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC-DARWIN:#define __LDBL_DIG__ 31
+// PPC-DARWIN:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
+// PPC-DARWIN:#define __LDBL_HAS_DENORM__ 1
+// PPC-DARWIN:#define __LDBL_HAS_INFINITY__ 1
+// PPC-DARWIN:#define __LDBL_HAS_QUIET_NAN__ 1
+// PPC-DARWIN:#define __LDBL_MANT_DIG__ 106
+// PPC-DARWIN:#define __LDBL_MAX_10_EXP__ 308
+// PPC-DARWIN:#define __LDBL_MAX_EXP__ 1024
+// PPC-DARWIN:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// 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 __LONG_DOUBLE_128__ 1
+// PPC-DARWIN:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// PPC-DARWIN:#define __LONG_MAX__ 2147483647L
+// PPC-DARWIN:#define __MACH__ 1
+// PPC-DARWIN:#define __NATURAL_ALIGNMENT__ 1
+// PPC-DARWIN:#define __ORDER_BIG_ENDIAN__ 4321
+// PPC-DARWIN:#define __ORDER_LITTLE_ENDIAN__ 1234
+// PPC-DARWIN:#define __ORDER_PDP_ENDIAN__ 3412
+// PPC-DARWIN:#define __POINTER_WIDTH__ 32
+// PPC-DARWIN:#define __POWERPC__ 1
+// PPC-DARWIN:#define __PPC__ 1
+// PPC-DARWIN:#define __PTRDIFF_TYPE__ int
+// PPC-DARWIN:#define __PTRDIFF_WIDTH__ 32
+// PPC-DARWIN:#define __REGISTER_PREFIX__
+// PPC-DARWIN:#define __SCHAR_MAX__ 127
+// PPC-DARWIN:#define __SHRT_MAX__ 32767
+// PPC-DARWIN:#define __SIG_ATOMIC_WIDTH__ 32
+// PPC-DARWIN:#define __SIZEOF_DOUBLE__ 8
+// PPC-DARWIN:#define __SIZEOF_FLOAT__ 4
+// PPC-DARWIN:#define __SIZEOF_INT__ 4
+// PPC-DARWIN:#define __SIZEOF_LONG_DOUBLE__ 16
+// PPC-DARWIN:#define __SIZEOF_LONG_LONG__ 8
+// PPC-DARWIN:#define __SIZEOF_LONG__ 4
+// PPC-DARWIN:#define __SIZEOF_POINTER__ 4
+// PPC-DARWIN:#define __SIZEOF_PTRDIFF_T__ 4
+// PPC-DARWIN:#define __SIZEOF_SHORT__ 2
+// PPC-DARWIN:#define __SIZEOF_SIZE_T__ 4
+// PPC-DARWIN:#define __SIZEOF_WCHAR_T__ 4
+// PPC-DARWIN:#define __SIZEOF_WINT_T__ 4
+// PPC-DARWIN:#define __SIZE_MAX__ 4294967295UL
+// PPC-DARWIN:#define __SIZE_TYPE__ long unsigned int
+// PPC-DARWIN:#define __SIZE_WIDTH__ 32
+// PPC-DARWIN:#define __STDC_HOSTED__ 0
+// PPC-DARWIN:#define __STDC_VERSION__ 199901L
+// PPC-DARWIN:#define __STDC__ 1
+// PPC-DARWIN:#define __UINTMAX_TYPE__ long long unsigned int
+// PPC-DARWIN:#define __USER_LABEL_PREFIX__ _
+// PPC-DARWIN:#define __WCHAR_MAX__ 2147483647
+// PPC-DARWIN:#define __WCHAR_TYPE__ int
+// PPC-DARWIN:#define __WCHAR_WIDTH__ 32
+// PPC-DARWIN:#define __WINT_TYPE__ int
+// PPC-DARWIN:#define __WINT_WIDTH__ 32
+// PPC-DARWIN:#define __powerpc__ 1
+// PPC-DARWIN:#define __ppc__ 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=s390x-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix S390X %s
//
// S390X:#define __CHAR16_TYPE__ unsigned short
@@ -2688,9 +3104,141 @@
// X86_64-LINUX:#define __x86_64 1
// X86_64-LINUX:#define __x86_64__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-unknown-freebsd9.1 < /dev/null | FileCheck -check-prefix X86_64-FREEBSD %s
+//
+// X86_64-FREEBSD:#define __FreeBSD__ 9
+// X86_64-FREEBSD:#define __FreeBSD_cc_version 900001
+// X86_64-FREEBSD:#define __STDC_MB_MIGHT_NEQ_WC__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-netbsd < /dev/null | FileCheck -check-prefix X86_64-NETBSD %s
+//
+// X86_64-NETBSD:#define _LP64 1
+// X86_64-NETBSD:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// X86_64-NETBSD:#define __CHAR16_TYPE__ unsigned short
+// X86_64-NETBSD:#define __CHAR32_TYPE__ unsigned int
+// X86_64-NETBSD:#define __CHAR_BIT__ 8
+// X86_64-NETBSD:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// X86_64-NETBSD:#define __DBL_DIG__ 15
+// X86_64-NETBSD:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// X86_64-NETBSD:#define __DBL_HAS_DENORM__ 1
+// X86_64-NETBSD:#define __DBL_HAS_INFINITY__ 1
+// X86_64-NETBSD:#define __DBL_HAS_QUIET_NAN__ 1
+// X86_64-NETBSD:#define __DBL_MANT_DIG__ 53
+// X86_64-NETBSD:#define __DBL_MAX_10_EXP__ 308
+// X86_64-NETBSD:#define __DBL_MAX_EXP__ 1024
+// X86_64-NETBSD:#define __DBL_MAX__ 1.7976931348623157e+308
+// X86_64-NETBSD:#define __DBL_MIN_10_EXP__ (-307)
+// X86_64-NETBSD:#define __DBL_MIN_EXP__ (-1021)
+// X86_64-NETBSD:#define __DBL_MIN__ 2.2250738585072014e-308
+// X86_64-NETBSD:#define __DECIMAL_DIG__ 21
+// X86_64-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// X86_64-NETBSD:#define __FLT_DIG__ 6
+// X86_64-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F
+// X86_64-NETBSD:#define __FLT_EVAL_METHOD__ 0
+// X86_64-NETBSD:#define __FLT_HAS_DENORM__ 1
+// X86_64-NETBSD:#define __FLT_HAS_INFINITY__ 1
+// X86_64-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1
+// X86_64-NETBSD:#define __FLT_MANT_DIG__ 24
+// X86_64-NETBSD:#define __FLT_MAX_10_EXP__ 38
+// X86_64-NETBSD:#define __FLT_MAX_EXP__ 128
+// X86_64-NETBSD:#define __FLT_MAX__ 3.40282347e+38F
+// X86_64-NETBSD:#define __FLT_MIN_10_EXP__ (-37)
+// X86_64-NETBSD:#define __FLT_MIN_EXP__ (-125)
+// X86_64-NETBSD:#define __FLT_MIN__ 1.17549435e-38F
+// X86_64-NETBSD:#define __FLT_RADIX__ 2
+// X86_64-NETBSD:#define __INT16_TYPE__ short
+// X86_64-NETBSD:#define __INT32_TYPE__ int
+// X86_64-NETBSD:#define __INT64_C_SUFFIX__ L
+// X86_64-NETBSD:#define __INT64_TYPE__ long int
+// X86_64-NETBSD:#define __INT8_TYPE__ char
+// X86_64-NETBSD:#define __INTMAX_MAX__ 9223372036854775807L
+// X86_64-NETBSD:#define __INTMAX_TYPE__ long int
+// X86_64-NETBSD:#define __INTMAX_WIDTH__ 64
+// X86_64-NETBSD:#define __INTPTR_TYPE__ long int
+// X86_64-NETBSD:#define __INTPTR_WIDTH__ 64
+// X86_64-NETBSD:#define __INT_MAX__ 2147483647
+// X86_64-NETBSD:#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
+// X86_64-NETBSD:#define __LDBL_DIG__ 18
+// X86_64-NETBSD:#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
+// X86_64-NETBSD:#define __LDBL_HAS_DENORM__ 1
+// X86_64-NETBSD:#define __LDBL_HAS_INFINITY__ 1
+// X86_64-NETBSD:#define __LDBL_HAS_QUIET_NAN__ 1
+// X86_64-NETBSD:#define __LDBL_MANT_DIG__ 64
+// X86_64-NETBSD:#define __LDBL_MAX_10_EXP__ 4932
+// X86_64-NETBSD:#define __LDBL_MAX_EXP__ 16384
+// X86_64-NETBSD:#define __LDBL_MAX__ 1.18973149535723176502e+4932L
+// X86_64-NETBSD:#define __LDBL_MIN_10_EXP__ (-4931)
+// X86_64-NETBSD:#define __LDBL_MIN_EXP__ (-16381)
+// X86_64-NETBSD:#define __LDBL_MIN__ 3.36210314311209350626e-4932L
+// X86_64-NETBSD:#define __LITTLE_ENDIAN__ 1
+// X86_64-NETBSD:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// X86_64-NETBSD:#define __LONG_MAX__ 9223372036854775807L
+// X86_64-NETBSD:#define __LP64__ 1
+// X86_64-NETBSD:#define __MMX__ 1
+// X86_64-NETBSD:#define __NO_MATH_INLINES 1
+// X86_64-NETBSD:#define __POINTER_WIDTH__ 64
+// X86_64-NETBSD:#define __PTRDIFF_TYPE__ long int
+// X86_64-NETBSD:#define __PTRDIFF_WIDTH__ 64
+// X86_64-NETBSD:#define __REGISTER_PREFIX__
+// X86_64-NETBSD:#define __SCHAR_MAX__ 127
+// X86_64-NETBSD:#define __SHRT_MAX__ 32767
+// X86_64-NETBSD:#define __SIG_ATOMIC_WIDTH__ 32
+// X86_64-NETBSD:#define __SIZEOF_DOUBLE__ 8
+// X86_64-NETBSD:#define __SIZEOF_FLOAT__ 4
+// X86_64-NETBSD:#define __SIZEOF_INT__ 4
+// X86_64-NETBSD:#define __SIZEOF_LONG_DOUBLE__ 16
+// X86_64-NETBSD:#define __SIZEOF_LONG_LONG__ 8
+// X86_64-NETBSD:#define __SIZEOF_LONG__ 8
+// X86_64-NETBSD:#define __SIZEOF_POINTER__ 8
+// X86_64-NETBSD:#define __SIZEOF_PTRDIFF_T__ 8
+// X86_64-NETBSD:#define __SIZEOF_SHORT__ 2
+// X86_64-NETBSD:#define __SIZEOF_SIZE_T__ 8
+// X86_64-NETBSD:#define __SIZEOF_WCHAR_T__ 4
+// X86_64-NETBSD:#define __SIZEOF_WINT_T__ 4
+// X86_64-NETBSD:#define __SIZE_MAX__ 18446744073709551615UL
+// X86_64-NETBSD:#define __SIZE_TYPE__ long unsigned int
+// X86_64-NETBSD:#define __SIZE_WIDTH__ 64
+// X86_64-NETBSD:#define __SSE2_MATH__ 1
+// X86_64-NETBSD:#define __SSE2__ 1
+// X86_64-NETBSD:#define __SSE_MATH__ 1
+// X86_64-NETBSD:#define __SSE__ 1
+// X86_64-NETBSD:#define __UINTMAX_TYPE__ long unsigned int
+// X86_64-NETBSD:#define __USER_LABEL_PREFIX__
+// X86_64-NETBSD:#define __WCHAR_MAX__ 2147483647
+// X86_64-NETBSD:#define __WCHAR_TYPE__ int
+// X86_64-NETBSD:#define __WCHAR_WIDTH__ 32
+// X86_64-NETBSD:#define __WINT_TYPE__ int
+// X86_64-NETBSD:#define __WINT_WIDTH__ 32
+// X86_64-NETBSD:#define __amd64 1
+// X86_64-NETBSD:#define __amd64__ 1
+// X86_64-NETBSD:#define __x86_64 1
+// X86_64-NETBSD:#define __x86_64__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc64-none-none < /dev/null | FileCheck -check-prefix SPARCV9 %s
+// SPARCV9:#define __INT64_TYPE__ long int
+// SPARCV9:#define __INTMAX_TYPE__ long int
+// SPARCV9:#define __INTPTR_TYPE__ long int
+// SPARCV9:#define __LONG_MAX__ 9223372036854775807L
+// SPARCV9:#define __LP64__ 1
+// SPARCV9:#define __SIZEOF_LONG__ 8
+// SPARCV9:#define __SIZEOF_POINTER__ 8
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc64-none-openbsd < /dev/null | FileCheck -check-prefix SPARC64-OBSD %s
+// SPARC64-OBSD:#define __INT64_TYPE__ long long int
+// SPARC64-OBSD:#define __INTMAX_TYPE__ long long int
+// SPARC64-OBSD:#define __UINTMAX_TYPE__ long long unsigned int
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-pc-kfreebsd-gnu < /dev/null | FileCheck -check-prefix KFREEBSD-DEFINE %s
+// KFREEBSD-DEFINE:#define __FreeBSD_kernel__ 1
+// KFREEBSD-DEFINE:#define __GLIBC__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i686-pc-kfreebsd-gnu < /dev/null | FileCheck -check-prefix KFREEBSDI686-DEFINE %s
+// KFREEBSDI686-DEFINE:#define __FreeBSD_kernel__ 1
+// KFREEBSDI686-DEFINE:#define __GLIBC__ 1
+//
// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -fobjc-runtime=gcc -E -dM < /dev/null | FileCheck -check-prefix GNUSOURCE %s
// GNUSOURCE:#define _GNU_SOURCE 1
-//
+//
// RUN: %clang_cc1 -x c++ -std=c++98 -fno-rtti -E -dM < /dev/null | FileCheck -check-prefix NORTTI %s
// NORTTI: __GXX_ABI_VERSION
// NORTTI-NOT:#define __GXX_RTTI
@@ -2698,3 +3246,9 @@
//
// RUN: %clang_cc1 -triple arm-linux-androideabi -E -dM < /dev/null | FileCheck -check-prefix ANDROID %s
// ANDROID: __ANDROID__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-freebsd < /dev/null | FileCheck -check-prefix PPC64-FREEBSD %s
+// PPC64-FREEBSD-NOT: #define __LONG_DOUBLE_128__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=xcore-none-none < /dev/null | FileCheck -check-prefix XCORE %s
+// XCORE:#define __XS1B__ 1
diff --git a/test/Preprocessor/iwithprefix.c b/test/Preprocessor/iwithprefix.c
index c11f36e94b5a..59935ac1b8b5 100644
--- a/test/Preprocessor/iwithprefix.c
+++ b/test/Preprocessor/iwithprefix.c
@@ -4,13 +4,12 @@
// RUN: mkdir -p %t.tmps/first %t.tmps/second
// RUN: %clang_cc1 -triple x86_64-unknown-unknown \
// RUN: -iprefix %t.tmps/ -iwithprefix second \
-// RUN: -isystem %t.tmps/first -v 2> %t.out
-// RUN: cat %t.out
-// RUN: FileCheck < %t.out %s
+// RUN: -isystem %t.tmps/first -v %s 2> %t.out
+// RUN: FileCheck %s < %t.out
// CHECK: #include <...> search starts here:
// CHECK: {{.*}}.tmps/first
-// CHECK: /lib/clang/{{[.0-9]+}}/include
+// CHECK: {{/|\\}}lib{{/|\\}}clang{{/|\\}}{{[.0-9]+}}{{/|\\}}include
// CHECK: {{.*}}.tmps/second
// CHECK-NOT: {{.*}}.tmps
diff --git a/test/Preprocessor/line-directive-output.c b/test/Preprocessor/line-directive-output.c
index bd3ea949ebd9..5c0aef8b3219 100644
--- a/test/Preprocessor/line-directive-output.c
+++ b/test/Preprocessor/line-directive-output.c
@@ -73,3 +73,6 @@ extern int z;
# 42 "A.c"
# 44 "A.c"
# 49 "A.c"
+
+// CHECK: # 50 "a\n.c"
+# 50 "a\012.c"
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
index ea0a36fca358..0dd658f7f1a1 100644
--- a/test/Preprocessor/line-directive.c
+++ b/test/Preprocessor/line-directive.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:92:2: error: ABC'
-// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:93:2: error: DEF'
+// RUN: not %clang_cc1 -E %s 2>&1 | grep 'blonk.c:92:2: error: ABC'
+// RUN: not %clang_cc1 -E %s 2>&1 | grep 'blonk.c:93:2: error: DEF'
#line 'a' // expected-error {{#line directive requires a positive integer argument}}
#line 0 // expected-warning {{#line directive with zero argument is a GNU extension}}
diff --git a/test/Preprocessor/macro_backslash.c b/test/Preprocessor/macro_backslash.c
new file mode 100644
index 000000000000..76f5d41e734d
--- /dev/null
+++ b/test/Preprocessor/macro_backslash.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -E %s -Dfoo='bar\' | FileCheck %s
+// CHECK: TTA bar\ TTB
+TTA foo TTB
diff --git a/test/Preprocessor/macro_expand_empty.c b/test/Preprocessor/macro_expand_empty.c
new file mode 100644
index 000000000000..3fb6394dc9ea
--- /dev/null
+++ b/test/Preprocessor/macro_expand_empty.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+// Check that this doesn't crash
+
+#define IDENTITY1(x) x
+#define IDENTITY2(x) IDENTITY1(x) IDENTITY1(x) IDENTITY1(x) IDENTITY1(x)
+#define IDENTITY3(x) IDENTITY2(x) IDENTITY2(x) IDENTITY2(x) IDENTITY2(x)
+#define IDENTITY4(x) IDENTITY3(x) IDENTITY3(x) IDENTITY3(x) IDENTITY3(x)
+#define IDENTITY5(x) IDENTITY4(x) IDENTITY4(x) IDENTITY4(x) IDENTITY4(x)
+#define IDENTITY6(x) IDENTITY5(x) IDENTITY5(x) IDENTITY5(x) IDENTITY5(x)
+#define IDENTITY7(x) IDENTITY6(x) IDENTITY6(x) IDENTITY6(x) IDENTITY6(x)
+#define IDENTITY8(x) IDENTITY7(x) IDENTITY7(x) IDENTITY7(x) IDENTITY7(x)
+#define IDENTITY9(x) IDENTITY8(x) IDENTITY8(x) IDENTITY8(x) IDENTITY8(x)
+#define IDENTITY0(x) IDENTITY9(x) IDENTITY9(x) IDENTITY9(x) IDENTITY9(x)
+IDENTITY0()
diff --git a/test/Preprocessor/macro_fn.c b/test/Preprocessor/macro_fn.c
index fcdb90ad57d6..f21ef5197d44 100644
--- a/test/Preprocessor/macro_fn.c
+++ b/test/Preprocessor/macro_fn.c
@@ -13,7 +13,8 @@ zero(1, 2, 3); /* expected-error {{too many arguments provided to function-li
one() /* ok */
one(a)
-one(a,) /* expected-error {{too many arguments provided to function-like macro invocation}} */
+one(a,) /* expected-error {{too many arguments provided to function-like macro invocation}} \
+ expected-warning {{empty macro arguments are a C99 feature}}*/
one(a, b) /* expected-error {{too many arguments provided to function-like macro invocation}} */
two() /* expected-error {{too few arguments provided to function-like macro invocation}} */
@@ -25,7 +26,7 @@ two(
, /* expected-warning {{empty macro arguments are a C99 feature}} */
, /* expected-warning {{empty macro arguments are a C99 feature}} \
expected-error {{too many arguments provided to function-like macro invocation}} */
- )
+ ) /* expected-warning {{empty macro arguments are a C99 feature}} */
two(,) /* expected-warning 2 {{empty macro arguments are a C99 feature}} */
diff --git a/test/Preprocessor/macro_paste_bad.c b/test/Preprocessor/macro_paste_bad.c
index 0a028a44686e..ec10006ae3d7 100644
--- a/test/Preprocessor/macro_paste_bad.c
+++ b/test/Preprocessor/macro_paste_bad.c
@@ -32,3 +32,5 @@ XX // expected-error {{attempt to use a poisoned identifier}}
#define VA __VA_ ## ARGS__
int VA; // expected-warning {{__VA_ARGS__ can only appear in the expansion of a C99 variadic macro}}
+#define LOG_ON_ERROR(x) x ## #y; // expected-error {{'#' is not followed by a macro parameter}}
+LOG_ON_ERROR(0);
diff --git a/test/Preprocessor/macro_paste_bcpl_comment.c b/test/Preprocessor/macro_paste_bcpl_comment.c
index fd07b1f7f2fc..e915ca611cc5 100644
--- a/test/Preprocessor/macro_paste_bcpl_comment.c
+++ b/test/Preprocessor/macro_paste_bcpl_comment.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -Eonly 2>&1 | grep error
+// RUN: not %clang_cc1 %s -Eonly 2>&1 | grep error
#define COMM1 / ## /
COMM1
diff --git a/test/Preprocessor/macro_paste_empty.c b/test/Preprocessor/macro_paste_empty.c
index 2e26f1419573..e9b50f0e8e87 100644
--- a/test/Preprocessor/macro_paste_empty.c
+++ b/test/Preprocessor/macro_paste_empty.c
@@ -1,13 +1,17 @@
-// RUN: %clang_cc1 -E %s | grep 'a:Y'
-// RUN: %clang_cc1 -E %s | grep 'b:Y'
-// RUN: %clang_cc1 -E %s | grep 'c:YY'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#define FOO(X) X ## Y
a:FOO()
+// CHECK: a:Y
#define FOO2(X) Y ## X
b:FOO2()
+// CHECK: b:Y
#define FOO3(X) X ## Y ## X ## Y ## X ## X
c:FOO3()
+// CHECK: c:YY
+#define FOO4(X, Y) X ## Y
+d:FOO4(,FOO4(,))
+// CHECK: d:FOO4
diff --git a/test/Preprocessor/macro_paste_msextensions.c b/test/Preprocessor/macro_paste_msextensions.c
index c5b42130b8ea..afdcdbd493f0 100644
--- a/test/Preprocessor/macro_paste_msextensions.c
+++ b/test/Preprocessor/macro_paste_msextensions.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -P -E -fms-extensions %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -P -E -fms-extensions %s | FileCheck -strict-whitespace %s
// This horrible stuff should preprocess into (other than whitespace):
// int foo;
diff --git a/test/Preprocessor/macro_with_initializer_list.cpp b/test/Preprocessor/macro_with_initializer_list.cpp
new file mode 100644
index 000000000000..287eeb4a843c
--- /dev/null
+++ b/test/Preprocessor/macro_with_initializer_list.cpp
@@ -0,0 +1,182 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+namespace std {
+ template <class X>
+ class initializer_list {
+ public:
+ initializer_list();
+ };
+}
+
+class Foo {
+public:
+ Foo();
+ Foo(std::initializer_list<int>);
+ bool operator==(const Foo);
+ Foo operator+(const Foo);
+};
+
+#define EQ(x,y) (void)(x == y) // expected-note 6{{defined here}}
+void test_EQ() {
+ Foo F;
+ F = Foo{1,2};
+
+ EQ(F,F);
+ EQ(F,Foo());
+ EQ(F,Foo({1,2,3}));
+ EQ(Foo({1,2,3}),F);
+ EQ((Foo{1,2,3}),(Foo{1,2,3}));
+ EQ(F, F + F);
+ EQ(F, Foo({1,2,3}) + Foo({1,2,3}));
+ EQ(F, (Foo{1,2,3} + Foo{1,2,3}));
+
+ EQ(F,Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ EQ(Foo{1,2,3},F);
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ EQ(Foo{1,2,3},Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+
+ EQ(Foo{1,2,3} + Foo{1,2,3}, F);
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ EQ(F, Foo({1,2,3}) + Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ EQ(F, Foo{1,2,3} + Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{33:8-33:8}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{33:18-33:18}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{36:6-36:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{36:16-36:16}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:6-39:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:16-39:16}:")"
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:17-39:17}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:27-39:27}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{43:6-43:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{43:29-43:29}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{46:9-46:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{46:34-46:34}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{49:9-49:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{49:32-49:32}:")"
+
+#define NE(x,y) (void)(x != y) // expected-note 6{{defined here}}
+// Operator != isn't defined. This tests that the corrected macro arguments
+// are used in the macro expansion.
+void test_NE() {
+ Foo F;
+
+ NE(F,F);
+ // expected-error@-1 {{invalid operands}}
+ NE(F,Foo());
+ // expected-error@-1 {{invalid operands}}
+ NE(F,Foo({1,2,3}));
+ // expected-error@-1 {{invalid operands}}
+ NE((Foo{1,2,3}),(Foo{1,2,3}));
+ // expected-error@-1 {{invalid operands}}
+
+ NE(F,Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+ NE(Foo{1,2,3},F);
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+ NE(Foo{1,2,3},Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+
+ NE(Foo{1,2,3} + Foo{1,2,3}, F);
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+ NE(F, Foo({1,2,3}) + Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+ NE(F, Foo{1,2,3} + Foo{1,2,3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+ // expected-error@-3 {{invalid operands}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{89:8-89:8}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{89:18-89:18}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{93:6-93:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{93:16-93:16}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:6-97:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:16-97:16}:")"
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:17-97:17}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:27-97:27}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{102:6-102:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{102:29-102:29}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{106:9-106:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{106:34-106:34}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:9-110:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
+
+#define INIT(var, init) Foo var = init; // expected-note 3{{defined here}}
+// Can't use an initializer list as a macro argument. The commas in the list
+// will be interpretted as argument separaters and adding parenthesis will
+// make it no longer an initializer list.
+void test() {
+ INIT(a, Foo());
+ INIT(b, Foo({1, 2, 3}));
+ INIT(c, Foo());
+
+ INIT(d, Foo{1, 2, 3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-note@-2 {{parentheses are required}}
+
+ // Can't be fixed by parentheses.
+ INIT(e, {1, 2, 3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-error@-2 {{use of undeclared identifier}}
+ // expected-note@-3 {{cannot use initializer list at the beginning of a macro argument}}
+
+ // Can't be fixed by parentheses.
+ INIT(e, {1, 2, 3} + {1, 2, 3});
+ // expected-error@-1 {{too many arguments provided}}
+ // expected-error@-2 {{use of undeclared identifier}}
+ // expected-note@-3 {{cannot use initializer list at the beginning of a macro argument}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:11-145:11}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:23-145:23}:")"
+
+#define M(name,a,b,c,d,e,f,g,h,i,j,k,l) \
+ Foo name = a + b + c + d + e + f + g + h + i + j + k + l;
+// expected-note@-2 2{{defined here}}
+void test2() {
+ M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
+ Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
+
+ M(F2, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3},
+ Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3});
+ // expected-error@-2 {{too many arguments provided}}
+ // expected-note@-3 {{parentheses are required}}
+
+ M(F3, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3},
+ {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3});
+ // expected-error@-2 {{too many arguments provided}}
+ // expected-error@-3 {{use of undeclared identifier}}
+ // expected-note@-4 {{cannot use initializer list at the beginning of a macro argument}}
+}
diff --git a/test/Preprocessor/microsoft-ext.c b/test/Preprocessor/microsoft-ext.c
index ec10374a1d6a..b03f6775429a 100644
--- a/test/Preprocessor/microsoft-ext.c
+++ b/test/Preprocessor/microsoft-ext.c
@@ -22,3 +22,15 @@ class GMOCK_ACTION_CLASS_(name, value_params) {\
ACTION_TEMPLATE(InvokeArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(p0, p1));
+
+// This tests compatibility with behaviour needed for type_traits in VS2012
+// Test based on _VARIADIC_EXPAND_0X macros in xstddef of VS2012
+#define _COMMA ,
+
+#define MAKER(_arg1, _comma, _arg2) \
+ void func(_arg1 _comma _arg2) {}
+#define MAKE_FUNC(_makerP1, _makerP2, _arg1, _comma, _arg2) \
+ _makerP1##_makerP2(_arg1, _comma, _arg2)
+
+MAKE_FUNC(MAK, ER, int a, _COMMA, int b);
+// CHECK: void func(int a , int b) {}
diff --git a/test/Preprocessor/optimize.c b/test/Preprocessor/optimize.c
index 0167e70e0122..d7da1056ae46 100644
--- a/test/Preprocessor/optimize.c
+++ b/test/Preprocessor/optimize.c
@@ -9,7 +9,7 @@
#endif
#endif
-// RUN: %clang_cc1 -Eonly %s -DOPT_O0 -O0 -verify
+// RUN: %clang_cc1 -Eonly %s -DOPT_O0 -verify
#ifdef OPT_O0
// expected-no-diagnostics
#ifdef __OPTIMIZE__
diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c
index c0ddf74340ce..e30069c1c5e7 100644
--- a/test/Preprocessor/pragma_microsoft.c
+++ b/test/Preprocessor/pragma_microsoft.c
@@ -18,6 +18,11 @@
#pragma comment(user, "foo\abar\nbaz\tsome thing")
+#pragma detect_mismatch("test", "1")
+#pragma detect_mismatch() // expected-error {{expected string literal in pragma detect_mismatch}}
+#pragma detect_mismatch("test") // expected-error {{pragma detect_mismatch is malformed; it requires two comma-separated string literals}}
+#pragma detect_mismatch("test", 1) // expected-error {{expected string literal in pragma detect_mismatch}}
+#pragma detect_mismatch("test", BAR)
// __pragma
@@ -82,3 +87,31 @@ void g() {}
// Make sure that empty includes don't work
#pragma include_alias("", "foo.h") // expected-error {{empty filename}}
#pragma include_alias(<foo.h>, <>) // expected-error {{empty filename}}
+
+// Test that we ignore pragma warning.
+#pragma warning(push)
+#pragma warning(push, 1)
+#pragma warning(disable : 4705)
+#pragma warning(disable : 123 456 789 ; error : 321)
+#pragma warning(once : 321)
+#pragma warning(suppress : 321)
+#pragma warning(default : 321)
+#pragma warning(pop)
+
+#pragma warning(push, 0)
+// FIXME: We could probably support pushing warning level 0.
+#pragma warning(pop)
+
+#pragma warning // expected-warning {{expected '('}}
+#pragma warning( // expected-warning {{expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 2, 3, or 4}}
+#pragma warning() // expected-warning {{expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 2, 3, or 4}}
+#pragma warning(push 4) // expected-warning {{expected ')'}}
+#pragma warning(push // expected-warning {{expected ')'}}
+#pragma warning(push, 5) // expected-warning {{requires a level between 0 and 4}}
+#pragma warning(pop, 1) // expected-warning {{expected ')'}}
+#pragma warning(push, 1) asdf // expected-warning {{extra tokens at end of #pragma warning directive}}
+#pragma warning(disable 4705) // expected-warning {{expected ':'}}
+#pragma warning(disable : 0) // expected-warning {{expected a warning number}}
+#pragma warning(default 321) // expected-warning {{expected ':'}}
+#pragma warning(asdf : 321) // expected-warning {{expected 'push', 'pop'}}
+#pragma warning(push, -1) // expected-warning {{requires a level between 0 and 4}}
diff --git a/test/Preprocessor/pragma_microsoft.cpp b/test/Preprocessor/pragma_microsoft.cpp
new file mode 100644
index 000000000000..e097d69a208f
--- /dev/null
+++ b/test/Preprocessor/pragma_microsoft.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -fms-extensions
+
+#pragma warning(push, 4_D) // expected-warning {{requires a level between 0 and 4}}
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index d0125cd0ed5a..26298f9ada34 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -1,6 +1,3 @@
-// These tests are generated by running utils/generate_arch_predefine_tests.sh
-// to observe GCC's behavior (or some other system compiler's behavior).
-//
// Begin X86/GCC/Linux tests ----------------
//
// RUN: %clang -march=i386 -m32 -E -dM %s -o - 2>&1 \
@@ -10,7 +7,7 @@
// CHECK_I386_M32: #define __i386__ 1
// CHECK_I386_M32: #define __tune_i386__ 1
// CHECK_I386_M32: #define i386 1
-// RUN: %clang -march=i386 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=i386 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_I386_M64
// CHECK_I386_M64: error:
@@ -24,7 +21,7 @@
// CHECK_I486_M32: #define __i486__ 1
// CHECK_I486_M32: #define __tune_i486__ 1
// CHECK_I486_M32: #define i386 1
-// RUN: %clang -march=i486 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=i486 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_I486_M64
// CHECK_I486_M64: error:
@@ -41,7 +38,7 @@
// CHECK_I586_M32: #define __tune_i586__ 1
// CHECK_I586_M32: #define __tune_pentium__ 1
// CHECK_I586_M32: #define i386 1
-// RUN: %clang -march=i586 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=i586 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_I586_M64
// CHECK_I586_M64: error:
@@ -58,7 +55,7 @@
// CHECK_PENTIUM_M32: #define __tune_i586__ 1
// CHECK_PENTIUM_M32: #define __tune_pentium__ 1
// CHECK_PENTIUM_M32: #define i386 1
-// RUN: %clang -march=pentium -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M64
// CHECK_PENTIUM_M64: error:
@@ -78,7 +75,7 @@
// CHECK_PENTIUM_MMX_M32: #define __tune_pentium__ 1
// CHECK_PENTIUM_MMX_M32: #define __tune_pentium_mmx__ 1
// CHECK_PENTIUM_MMX_M32: #define i386 1
-// RUN: %clang -march=pentium-mmx -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium-mmx -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_MMX_M64
// CHECK_PENTIUM_MMX_M64: error:
@@ -93,7 +90,7 @@
// CHECK_WINCHIP_C6_M32: #define __i486__ 1
// CHECK_WINCHIP_C6_M32: #define __tune_i486__ 1
// CHECK_WINCHIP_C6_M32: #define i386 1
-// RUN: %clang -march=winchip-c6 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=winchip-c6 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP_C6_M64
// CHECK_WINCHIP_C6_M64: error:
@@ -109,7 +106,7 @@
// CHECK_WINCHIP2_M32: #define __i486__ 1
// CHECK_WINCHIP2_M32: #define __tune_i486__ 1
// CHECK_WINCHIP2_M32: #define i386 1
-// RUN: %clang -march=winchip2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=winchip2 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP2_M64
// CHECK_WINCHIP2_M64: error:
@@ -125,7 +122,7 @@
// CHECK_C3_M32: #define __i486__ 1
// CHECK_C3_M32: #define __tune_i486__ 1
// CHECK_C3_M32: #define i386 1
-// RUN: %clang -march=c3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=c3 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_C3_M64
// CHECK_C3_M64: error:
@@ -145,7 +142,7 @@
// CHECK_C3_2_M32: #define __tune_pentium2__ 1
// CHECK_C3_2_M32: #define __tune_pentiumpro__ 1
// CHECK_C3_2_M32: #define i386 1
-// RUN: %clang -march=c3-2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=c3-2 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_C3_2_M64
// CHECK_C3_2_M64: error:
@@ -160,7 +157,7 @@
// CHECK_I686_M32: #define __pentiumpro 1
// CHECK_I686_M32: #define __pentiumpro__ 1
// CHECK_I686_M32: #define i386 1
-// RUN: %clang -march=i686 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=i686 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_I686_M64
// CHECK_I686_M64: error:
@@ -177,7 +174,7 @@
// CHECK_PENTIUMPRO_M32: #define __tune_i686__ 1
// CHECK_PENTIUMPRO_M32: #define __tune_pentiumpro__ 1
// CHECK_PENTIUMPRO_M32: #define i386 1
-// RUN: %clang -march=pentiumpro -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentiumpro -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUMPRO_M64
// CHECK_PENTIUMPRO_M64: error:
@@ -196,7 +193,7 @@
// CHECK_PENTIUM2_M32: #define __tune_pentium2__ 1
// CHECK_PENTIUM2_M32: #define __tune_pentiumpro__ 1
// CHECK_PENTIUM2_M32: #define i386 1
-// RUN: %clang -march=pentium2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium2 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM2_M64
// CHECK_PENTIUM2_M64: error:
@@ -217,7 +214,7 @@
// CHECK_PENTIUM3_M32: #define __tune_pentium3__ 1
// CHECK_PENTIUM3_M32: #define __tune_pentiumpro__ 1
// CHECK_PENTIUM3_M32: #define i386 1
-// RUN: %clang -march=pentium3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium3 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3_M64
// CHECK_PENTIUM3_M64: error:
@@ -236,7 +233,7 @@
// CHECK_PENTIUM3M_M32: #define __tune_i686__ 1
// CHECK_PENTIUM3M_M32: #define __tune_pentiumpro__ 1
// CHECK_PENTIUM3M_M32: #define i386 1
-// RUN: %clang -march=pentium3m -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium3m -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3M_M64
// CHECK_PENTIUM3M_M64: error:
@@ -256,7 +253,7 @@
// CHECK_PENTIUM_M_M32: #define __tune_i686__ 1
// CHECK_PENTIUM_M_M32: #define __tune_pentiumpro__ 1
// CHECK_PENTIUM_M_M32: #define i386 1
-// RUN: %clang -march=pentium-m -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium-m -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M_M64
// CHECK_PENTIUM_M_M64: error:
@@ -273,7 +270,7 @@
// CHECK_PENTIUM4_M32: #define __pentium4__ 1
// CHECK_PENTIUM4_M32: #define __tune_pentium4__ 1
// CHECK_PENTIUM4_M32: #define i386 1
-// RUN: %clang -march=pentium4 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium4 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4_M64
// CHECK_PENTIUM4_M64: error:
@@ -290,7 +287,7 @@
// CHECK_PENTIUM4M_M32: #define __pentium4__ 1
// CHECK_PENTIUM4M_M32: #define __tune_pentium4__ 1
// CHECK_PENTIUM4M_M32: #define i386 1
-// RUN: %clang -march=pentium4m -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=pentium4m -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4M_M64
// CHECK_PENTIUM4M_M64: error:
@@ -308,7 +305,7 @@
// CHECK_PRESCOTT_M32: #define __nocona__ 1
// CHECK_PRESCOTT_M32: #define __tune_nocona__ 1
// CHECK_PRESCOTT_M32: #define i386 1
-// RUN: %clang -march=prescott -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=prescott -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_PRESCOTT_M64
// CHECK_PRESCOTT_M64: error:
@@ -509,6 +506,7 @@
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX2_M32
// CHECK_CORE_AVX2_M32: #define __AES__ 1
+// CHECK_CORE_AVX2_M32: #define __AVX2__ 1
// CHECK_CORE_AVX2_M32: #define __AVX__ 1
// CHECK_CORE_AVX2_M32: #define __BMI2__ 1
// CHECK_CORE_AVX2_M32: #define __BMI__ 1
@@ -536,6 +534,7 @@
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX2_M64
// CHECK_CORE_AVX2_M64: #define __AES__ 1
+// CHECK_CORE_AVX2_M64: #define __AVX2__ 1
// CHECK_CORE_AVX2_M64: #define __AVX__ 1
// CHECK_CORE_AVX2_M64: #define __BMI2__ 1
// CHECK_CORE_AVX2_M64: #define __BMI__ 1
@@ -563,6 +562,74 @@
// CHECK_CORE_AVX2_M64: #define __x86_64 1
// CHECK_CORE_AVX2_M64: #define __x86_64__ 1
//
+// RUN: %clang -march=knl -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_KNL_M32
+// CHECK_KNL_M32: #define __AES__ 1
+// CHECK_KNL_M32: #define __AVX2__ 1
+// CHECK_KNL_M32: #define __AVX512CD__ 1
+// CHECK_KNL_M32: #define __AVX512ER__ 1
+// CHECK_KNL_M32: #define __AVX512F__ 1
+// CHECK_KNL_M32: #define __AVX512PF__ 1
+// CHECK_KNL_M32: #define __AVX__ 1
+// CHECK_KNL_M32: #define __BMI2__ 1
+// CHECK_KNL_M32: #define __BMI__ 1
+// CHECK_KNL_M32: #define __F16C__ 1
+// CHECK_KNL_M32: #define __FMA__ 1
+// CHECK_KNL_M32: #define __LZCNT__ 1
+// CHECK_KNL_M32: #define __MMX__ 1
+// CHECK_KNL_M32: #define __PCLMUL__ 1
+// CHECK_KNL_M32: #define __POPCNT__ 1
+// CHECK_KNL_M32: #define __RDRND__ 1
+// CHECK_KNL_M32: #define __RTM__ 1
+// CHECK_KNL_M32: #define __SSE2__ 1
+// CHECK_KNL_M32: #define __SSE3__ 1
+// CHECK_KNL_M32: #define __SSE4_1__ 1
+// CHECK_KNL_M32: #define __SSE4_2__ 1
+// CHECK_KNL_M32: #define __SSE__ 1
+// CHECK_KNL_M32: #define __SSSE3__ 1
+// CHECK_KNL_M32: #define __i386 1
+// CHECK_KNL_M32: #define __i386__ 1
+// CHECK_KNL_M32: #define __knl 1
+// CHECK_KNL_M32: #define __knl__ 1
+// CHECK_KNL_M32: #define __tune_knl__ 1
+// CHECK_KNL_M32: #define i386 1
+// RUN: %clang -march=knl -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_KNL_M64
+// CHECK_KNL_M64: #define __AES__ 1
+// CHECK_KNL_M64: #define __AVX2__ 1
+// CHECK_KNL_M64: #define __AVX512CD__ 1
+// CHECK_KNL_M64: #define __AVX512ER__ 1
+// CHECK_KNL_M64: #define __AVX512F__ 1
+// CHECK_KNL_M64: #define __AVX512PF__ 1
+// CHECK_KNL_M64: #define __AVX__ 1
+// CHECK_KNL_M64: #define __BMI2__ 1
+// CHECK_KNL_M64: #define __BMI__ 1
+// CHECK_KNL_M64: #define __F16C__ 1
+// CHECK_KNL_M64: #define __FMA__ 1
+// CHECK_KNL_M64: #define __LZCNT__ 1
+// CHECK_KNL_M64: #define __MMX__ 1
+// CHECK_KNL_M64: #define __PCLMUL__ 1
+// CHECK_KNL_M64: #define __POPCNT__ 1
+// CHECK_KNL_M64: #define __RDRND__ 1
+// CHECK_KNL_M64: #define __RTM__ 1
+// CHECK_KNL_M64: #define __SSE2_MATH__ 1
+// CHECK_KNL_M64: #define __SSE2__ 1
+// CHECK_KNL_M64: #define __SSE3__ 1
+// CHECK_KNL_M64: #define __SSE4_1__ 1
+// CHECK_KNL_M64: #define __SSE4_2__ 1
+// CHECK_KNL_M64: #define __SSE_MATH__ 1
+// CHECK_KNL_M64: #define __SSE__ 1
+// CHECK_KNL_M64: #define __SSSE3__ 1
+// CHECK_KNL_M64: #define __amd64 1
+// CHECK_KNL_M64: #define __amd64__ 1
+// CHECK_KNL_M64: #define __knl 1
+// CHECK_KNL_M64: #define __knl__ 1
+// CHECK_KNL_M64: #define __tune_knl__ 1
+// CHECK_KNL_M64: #define __x86_64 1
+// CHECK_KNL_M64: #define __x86_64__ 1
+//
// RUN: %clang -march=atom -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATOM_M32
@@ -595,6 +662,42 @@
// CHECK_ATOM_M64: #define __x86_64 1
// CHECK_ATOM_M64: #define __x86_64__ 1
//
+// RUN: %clang -march=slm -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SLM_M32
+// CHECK_SLM_M32: #define __MMX__ 1
+// CHECK_SLM_M32: #define __SSE2__ 1
+// CHECK_SLM_M32: #define __SSE3__ 1
+// CHECK_SLM_M32: #define __SSE4_1__ 1
+// CHECK_SLM_M32: #define __SSE4_2__ 1
+// CHECK_SLM_M32: #define __SSE__ 1
+// CHECK_SLM_M32: #define __SSSE3__ 1
+// CHECK_SLM_M32: #define __i386 1
+// CHECK_SLM_M32: #define __i386__ 1
+// CHECK_SLM_M32: #define __slm 1
+// CHECK_SLM_M32: #define __slm__ 1
+// CHECK_SLM_M32: #define __tune_slm__ 1
+// CHECK_SLM_M32: #define i386 1
+// RUN: %clang -march=slm -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SLM_M64
+// CHECK_SLM_M64: #define __MMX__ 1
+// CHECK_SLM_M64: #define __SSE2_MATH__ 1
+// CHECK_SLM_M64: #define __SSE2__ 1
+// CHECK_SLM_M64: #define __SSE3__ 1
+// CHECK_SLM_M64: #define __SSE4_1__ 1
+// CHECK_SLM_M64: #define __SSE4_2__ 1
+// CHECK_SLM_M64: #define __SSE_MATH__ 1
+// CHECK_SLM_M64: #define __SSE__ 1
+// CHECK_SLM_M64: #define __SSSE3__ 1
+// CHECK_SLM_M64: #define __amd64 1
+// CHECK_SLM_M64: #define __amd64__ 1
+// CHECK_SLM_M64: #define __slm 1
+// CHECK_SLM_M64: #define __slm__ 1
+// CHECK_SLM_M64: #define __tune_slm__ 1
+// CHECK_SLM_M64: #define __x86_64 1
+// CHECK_SLM_M64: #define __x86_64__ 1
+//
// RUN: %clang -march=geode -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_GEODE_M32
@@ -607,7 +710,7 @@
// CHECK_GEODE_M32: #define __i386__ 1
// CHECK_GEODE_M32: #define __tune_geode__ 1
// CHECK_GEODE_M32: #define i386 1
-// RUN: %clang -march=geode -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=geode -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_GEODE_M64
// CHECK_GEODE_M64: error:
@@ -622,7 +725,7 @@
// CHECK_K6_M32: #define __k6__ 1
// CHECK_K6_M32: #define __tune_k6__ 1
// CHECK_K6_M32: #define i386 1
-// RUN: %clang -march=k6 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=k6 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_K6_M64
// CHECK_K6_M64: error:
@@ -640,7 +743,7 @@
// CHECK_K6_2_M32: #define __tune_k6_2__ 1
// CHECK_K6_2_M32: #define __tune_k6__ 1
// CHECK_K6_2_M32: #define i386 1
-// RUN: %clang -march=k6-2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=k6-2 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_K6_2_M64
// CHECK_K6_2_M64: error:
@@ -658,7 +761,7 @@
// CHECK_K6_3_M32: #define __tune_k6_3__ 1
// CHECK_K6_3_M32: #define __tune_k6__ 1
// CHECK_K6_3_M32: #define i386 1
-// RUN: %clang -march=k6-3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=k6-3 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_K6_3_M64
// CHECK_K6_3_M64: error:
@@ -675,7 +778,7 @@
// CHECK_ATHLON_M32: #define __i386__ 1
// CHECK_ATHLON_M32: #define __tune_athlon__ 1
// CHECK_ATHLON_M32: #define i386 1
-// RUN: %clang -march=athlon -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=athlon -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_M64
// CHECK_ATHLON_M64: error:
@@ -692,7 +795,7 @@
// CHECK_ATHLON_TBIRD_M32: #define __i386__ 1
// CHECK_ATHLON_TBIRD_M32: #define __tune_athlon__ 1
// CHECK_ATHLON_TBIRD_M32: #define i386 1
-// RUN: %clang -march=athlon-tbird -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=athlon-tbird -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_TBIRD_M64
// CHECK_ATHLON_TBIRD_M64: error:
@@ -712,7 +815,7 @@
// CHECK_ATHLON_4_M32: #define __tune_athlon__ 1
// CHECK_ATHLON_4_M32: #define __tune_athlon_sse__ 1
// CHECK_ATHLON_4_M32: #define i386 1
-// RUN: %clang -march=athlon-4 -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=athlon-4 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_4_M64
// CHECK_ATHLON_4_M64: error:
@@ -732,7 +835,7 @@
// CHECK_ATHLON_XP_M32: #define __tune_athlon__ 1
// CHECK_ATHLON_XP_M32: #define __tune_athlon_sse__ 1
// CHECK_ATHLON_XP_M32: #define i386 1
-// RUN: %clang -march=athlon-xp -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=athlon-xp -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_XP_M64
// CHECK_ATHLON_XP_M64: error:
@@ -752,7 +855,7 @@
// CHECK_ATHLON_MP_M32: #define __tune_athlon__ 1
// CHECK_ATHLON_MP_M32: #define __tune_athlon_sse__ 1
// CHECK_ATHLON_MP_M32: #define i386 1
-// RUN: %clang -march=athlon-mp -m64 -E -dM %s -o - 2>&1 \
+// RUN: not %clang -march=athlon-mp -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_MP_M64
// CHECK_ATHLON_MP_M64: error:
@@ -1060,6 +1163,7 @@
// CHECK_BTVER1_M32: #define __LZCNT__ 1
// CHECK_BTVER1_M32: #define __MMX__ 1
// CHECK_BTVER1_M32: #define __POPCNT__ 1
+// CHECK_BTVER1_M32: #define __PRFCHW__ 1
// CHECK_BTVER1_M32: #define __SSE2_MATH__ 1
// CHECK_BTVER1_M32: #define __SSE2__ 1
// CHECK_BTVER1_M32: #define __SSE3__ 1
@@ -1080,6 +1184,7 @@
// CHECK_BTVER1_M64: #define __LZCNT__ 1
// CHECK_BTVER1_M64: #define __MMX__ 1
// CHECK_BTVER1_M64: #define __POPCNT__ 1
+// CHECK_BTVER1_M64: #define __PRFCHW__ 1
// CHECK_BTVER1_M64: #define __SSE2_MATH__ 1
// CHECK_BTVER1_M64: #define __SSE2__ 1
// CHECK_BTVER1_M64: #define __SSE3__ 1
@@ -1104,6 +1209,7 @@
// CHECK_BTVER2_M32: #define __LZCNT__ 1
// CHECK_BTVER2_M32: #define __MMX__ 1
// CHECK_BTVER2_M32: #define __POPCNT__ 1
+// CHECK_BTVER2_M32: #define __PRFCHW__ 1
// CHECK_BTVER2_M32: #define __SSE2_MATH__ 1
// CHECK_BTVER2_M32: #define __SSE2__ 1
// CHECK_BTVER2_M32: #define __SSE3__ 1
@@ -1126,6 +1232,7 @@
// CHECK_BTVER2_M64: #define __LZCNT__ 1
// CHECK_BTVER2_M64: #define __MMX__ 1
// CHECK_BTVER2_M64: #define __POPCNT__ 1
+// CHECK_BTVER2_M64: #define __PRFCHW__ 1
// CHECK_BTVER2_M64: #define __SSE2_MATH__ 1
// CHECK_BTVER2_M64: #define __SSE2__ 1
// CHECK_BTVER2_M64: #define __SSE3__ 1
@@ -1152,6 +1259,7 @@
// CHECK_BDVER1_M32: #define __MMX__ 1
// CHECK_BDVER1_M32: #define __PCLMUL__ 1
// CHECK_BDVER1_M32: #define __POPCNT__ 1
+// CHECK_BDVER1_M32: #define __PRFCHW__ 1
// CHECK_BDVER1_M32: #define __SSE2_MATH__ 1
// CHECK_BDVER1_M32: #define __SSE2__ 1
// CHECK_BDVER1_M32: #define __SSE3__ 1
@@ -1179,6 +1287,7 @@
// CHECK_BDVER1_M64: #define __MMX__ 1
// CHECK_BDVER1_M64: #define __PCLMUL__ 1
// CHECK_BDVER1_M64: #define __POPCNT__ 1
+// CHECK_BDVER1_M64: #define __PRFCHW__ 1
// CHECK_BDVER1_M64: #define __SSE2_MATH__ 1
// CHECK_BDVER1_M64: #define __SSE2__ 1
// CHECK_BDVER1_M64: #define __SSE3__ 1
@@ -1211,6 +1320,7 @@
// CHECK_BDVER2_M32: #define __MMX__ 1
// CHECK_BDVER2_M32: #define __PCLMUL__ 1
// CHECK_BDVER2_M32: #define __POPCNT__ 1
+// CHECK_BDVER2_M32: #define __PRFCHW__ 1
// CHECK_BDVER2_M32: #define __SSE2_MATH__ 1
// CHECK_BDVER2_M32: #define __SSE2__ 1
// CHECK_BDVER2_M32: #define __SSE3__ 1
@@ -1220,6 +1330,7 @@
// CHECK_BDVER2_M32: #define __SSE_MATH__ 1
// CHECK_BDVER2_M32: #define __SSE__ 1
// CHECK_BDVER2_M32: #define __SSSE3__ 1
+// CHECK_BDVER2_M32: #define __TBM__ 1
// CHECK_BDVER2_M32: #define __XOP__ 1
// CHECK_BDVER2_M32: #define __bdver2 1
// CHECK_BDVER2_M32: #define __bdver2__ 1
@@ -1241,6 +1352,7 @@
// CHECK_BDVER2_M64: #define __MMX__ 1
// CHECK_BDVER2_M64: #define __PCLMUL__ 1
// CHECK_BDVER2_M64: #define __POPCNT__ 1
+// CHECK_BDVER2_M64: #define __PRFCHW__ 1
// CHECK_BDVER2_M64: #define __SSE2_MATH__ 1
// CHECK_BDVER2_M64: #define __SSE2__ 1
// CHECK_BDVER2_M64: #define __SSE3__ 1
@@ -1250,6 +1362,7 @@
// CHECK_BDVER2_M64: #define __SSE_MATH__ 1
// CHECK_BDVER2_M64: #define __SSE__ 1
// CHECK_BDVER2_M64: #define __SSSE3__ 1
+// CHECK_BDVER2_M64: #define __TBM__ 1
// CHECK_BDVER2_M64: #define __XOP__ 1
// CHECK_BDVER2_M64: #define __amd64 1
// CHECK_BDVER2_M64: #define __amd64__ 1
@@ -1258,5 +1371,78 @@
// CHECK_BDVER2_M64: #define __tune_bdver2__ 1
// CHECK_BDVER2_M64: #define __x86_64 1
// CHECK_BDVER2_M64: #define __x86_64__ 1
+// RUN: %clang -march=bdver3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BDVER3_M32
+// CHECK_BDVER3_M32-NOT: #define __3dNOW_A__ 1
+// CHECK_BDVER3_M32-NOT: #define __3dNOW__ 1
+// CHECK_BDVER3_M32: #define __AES__ 1
+// CHECK_BDVER3_M32: #define __AVX__ 1
+// CHECK_BDVER3_M32: #define __BMI__ 1
+// CHECK_BDVER3_M32: #define __F16C__ 1
+// CHECK_BDVER3_M32: #define __FMA4__ 1
+// CHECK_BDVER3_M32: #define __FMA__ 1
+// CHECK_BDVER3_M32: #define __LZCNT__ 1
+// CHECK_BDVER3_M32: #define __MMX__ 1
+// CHECK_BDVER3_M32: #define __PCLMUL__ 1
+// CHECK_BDVER3_M32: #define __POPCNT__ 1
+// CHECK_BDVER3_M32: #define __PRFCHW__ 1
+// CHECK_BDVER3_M32: #define __SSE2_MATH__ 1
+// CHECK_BDVER3_M32: #define __SSE2__ 1
+// CHECK_BDVER3_M32: #define __SSE3__ 1
+// CHECK_BDVER3_M32: #define __SSE4A__ 1
+// CHECK_BDVER3_M32: #define __SSE4_1__ 1
+// CHECK_BDVER3_M32: #define __SSE4_2__ 1
+// CHECK_BDVER3_M32: #define __SSE_MATH__ 1
+// CHECK_BDVER3_M32: #define __SSE__ 1
+// CHECK_BDVER3_M32: #define __SSSE3__ 1
+// CHECK_BDVER3_M32: #define __TBM__ 1
+// CHECK_BDVER3_M32: #define __XOP__ 1
+// CHECK_BDVER3_M32: #define __bdver3 1
+// CHECK_BDVER3_M32: #define __bdver3__ 1
+// CHECK_BDVER3_M32: #define __i386 1
+// CHECK_BDVER3_M32: #define __i386__ 1
+// CHECK_BDVER3_M32: #define __tune_bdver3__ 1
+// RUN: %clang -march=bdver3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BDVER3_M64
+// CHECK_BDVER3_M64-NOT: #define __3dNOW_A__ 1
+// CHECK_BDVER3_M64-NOT: #define __3dNOW__ 1
+// CHECK_BDVER3_M64: #define __AES__ 1
+// CHECK_BDVER3_M64: #define __AVX__ 1
+// CHECK_BDVER3_M64: #define __BMI__ 1
+// CHECK_BDVER3_M64: #define __F16C__ 1
+// CHECK_BDVER3_M64: #define __FMA4__ 1
+// CHECK_BDVER3_M64: #define __FMA__ 1
+// CHECK_BDVER3_M64: #define __LZCNT__ 1
+// CHECK_BDVER3_M64: #define __MMX__ 1
+// CHECK_BDVER3_M64: #define __PCLMUL__ 1
+// CHECK_BDVER3_M64: #define __POPCNT__ 1
+// CHECK_BDVER3_M64: #define __PRFCHW__ 1
+// CHECK_BDVER3_M64: #define __SSE2_MATH__ 1
+// CHECK_BDVER3_M64: #define __SSE2__ 1
+// CHECK_BDVER3_M64: #define __SSE3__ 1
+// CHECK_BDVER3_M64: #define __SSE4A__ 1
+// CHECK_BDVER3_M64: #define __SSE4_1__ 1
+// CHECK_BDVER3_M64: #define __SSE4_2__ 1
+// CHECK_BDVER3_M64: #define __SSE_MATH__ 1
+// CHECK_BDVER3_M64: #define __SSE__ 1
+// CHECK_BDVER3_M64: #define __SSSE3__ 1
+// CHECK_BDVER3_M64: #define __TBM__ 1
+// CHECK_BDVER3_M64: #define __XOP__ 1
+// CHECK_BDVER3_M64: #define __amd64 1
+// CHECK_BDVER3_M64: #define __amd64__ 1
+// CHECK_BDVER3_M64: #define __bdver3 1
+// CHECK_BDVER3_M64: #define __bdver3__ 1
+// CHECK_BDVER3_M64: #define __tune_bdver3__ 1
+// CHECK_BDVER3_M64: #define __x86_64 1
+// CHECK_BDVER3_M64: #define __x86_64__ 1
//
// End X86/GCC/Linux tests ------------------
+
+// Begin PPC/GCC/Linux tests ----------------
+// RUN: %clang -mvsx -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_PPC_VSX_M64
+//
+// CHECK_PPC_VSX_M64: #define __VSX__
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 94671f3335c3..11449f930ef1 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -44,3 +44,21 @@
// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple armv6 -target-cpu arm1136j-s \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_ARM
+// CHECK-SYNC_CAS_ARM: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK-SYNC_CAS_ARM: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK-SYNC_CAS_ARM: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK-SYNC_CAS_ARM: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple armv7 -target-cpu cortex-a8 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_ARMv7
+// CHECK-SYNC_CAS_ARMv7: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK-SYNC_CAS_ARMv7: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK-SYNC_CAS_ARMv7: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK-SYNC_CAS_ARMv7: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple armv6 -target-cpu cortex-m0 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_ARMv6
+// CHECK-SYNC_CAS_ARMv6-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index c3be05d97cd0..b92cfe7cf37a 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -213,6 +213,220 @@
// I386:INTMAX_C_(0) 0LL
// I386:UINTMAX_C_(0) 0ULL
//
+// RUN: %clang_cc1 -E -ffreestanding -triple=mips-none-none %s | FileCheck -check-prefix MIPS %s
+//
+// MIPS:typedef signed long long int int64_t;
+// MIPS:typedef unsigned long long int uint64_t;
+// MIPS:typedef int64_t int_least64_t;
+// MIPS:typedef uint64_t uint_least64_t;
+// MIPS:typedef int64_t int_fast64_t;
+// MIPS:typedef uint64_t uint_fast64_t;
+//
+// MIPS:typedef signed int int32_t;
+// MIPS:typedef unsigned int uint32_t;
+// MIPS:typedef int32_t int_least32_t;
+// MIPS:typedef uint32_t uint_least32_t;
+// MIPS:typedef int32_t int_fast32_t;
+// MIPS:typedef uint32_t uint_fast32_t;
+//
+// MIPS:typedef signed short int16_t;
+// MIPS:typedef unsigned short uint16_t;
+// MIPS:typedef int16_t int_least16_t;
+// MIPS:typedef uint16_t uint_least16_t;
+// MIPS:typedef int16_t int_fast16_t;
+// MIPS:typedef uint16_t uint_fast16_t;
+//
+// MIPS:typedef signed char int8_t;
+// MIPS:typedef unsigned char uint8_t;
+// MIPS:typedef int8_t int_least8_t;
+// MIPS:typedef uint8_t uint_least8_t;
+// 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 long int intmax_t;
+// MIPS:typedef long long unsigned int uintmax_t;
+//
+// MIPS:INT8_MAX_ 127
+// MIPS:INT8_MIN_ (-127 -1)
+// MIPS:UINT8_MAX_ 255
+// MIPS:INT_LEAST8_MIN_ (-127 -1)
+// MIPS:INT_LEAST8_MAX_ 127
+// MIPS:UINT_LEAST8_MAX_ 255
+// MIPS:INT_FAST8_MIN_ (-127 -1)
+// MIPS:INT_FAST8_MAX_ 127
+// MIPS:UINT_FAST8_MAX_ 255
+//
+// MIPS:INT16_MAX_ 32767
+// MIPS:INT16_MIN_ (-32767 -1)
+// MIPS:UINT16_MAX_ 65535
+// MIPS:INT_LEAST16_MIN_ (-32767 -1)
+// MIPS:INT_LEAST16_MAX_ 32767
+// MIPS:UINT_LEAST16_MAX_ 65535
+// MIPS:INT_FAST16_MIN_ (-32767 -1)
+// MIPS:INT_FAST16_MAX_ 32767
+// MIPS:UINT_FAST16_MAX_ 65535
+//
+// MIPS:INT32_MAX_ 2147483647
+// MIPS:INT32_MIN_ (-2147483647 -1)
+// MIPS:UINT32_MAX_ 4294967295U
+// MIPS:INT_LEAST32_MIN_ (-2147483647 -1)
+// MIPS:INT_LEAST32_MAX_ 2147483647
+// MIPS:UINT_LEAST32_MAX_ 4294967295U
+// MIPS:INT_FAST32_MIN_ (-2147483647 -1)
+// MIPS:INT_FAST32_MAX_ 2147483647
+// MIPS:UINT_FAST32_MAX_ 4294967295U
+//
+// MIPS:INT64_MAX_ 9223372036854775807LL
+// MIPS:INT64_MIN_ (-9223372036854775807LL -1)
+// MIPS:UINT64_MAX_ 18446744073709551615ULL
+// MIPS:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// MIPS:INT_LEAST64_MAX_ 9223372036854775807LL
+// MIPS:UINT_LEAST64_MAX_ 18446744073709551615ULL
+// MIPS:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// MIPS:INT_FAST64_MAX_ 9223372036854775807LL
+// MIPS:UINT_FAST64_MAX_ 18446744073709551615ULL
+//
+// MIPS:INTPTR_MIN_ (-2147483647 -1)
+// MIPS:INTPTR_MAX_ 2147483647
+// MIPS:UINTPTR_MAX_ 4294967295U
+// MIPS:PTRDIFF_MIN_ (-2147483647 -1)
+// MIPS:PTRDIFF_MAX_ 2147483647
+// MIPS:SIZE_MAX_ 4294967295U
+//
+// MIPS:INTMAX_MIN_ (-9223372036854775807LL -1)
+// MIPS:INTMAX_MAX_ 9223372036854775807LL
+// MIPS:UINTMAX_MAX_ 18446744073709551615ULL
+//
+// MIPS:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// MIPS:SIG_ATOMIC_MAX_ 2147483647
+// MIPS:WINT_MIN_ (-2147483647 -1)
+// MIPS:WINT_MAX_ 2147483647
+//
+// MIPS:WCHAR_MAX_ 2147483647
+// MIPS:WCHAR_MIN_ (-2147483647 -1)
+//
+// MIPS:INT8_C_(0) 0
+// MIPS:UINT8_C_(0) 0U
+// MIPS:INT16_C_(0) 0
+// MIPS:UINT16_C_(0) 0U
+// MIPS:INT32_C_(0) 0
+// MIPS:UINT32_C_(0) 0U
+// MIPS:INT64_C_(0) 0LL
+// MIPS:UINT64_C_(0) 0ULL
+//
+// MIPS:INTMAX_C_(0) 0LL
+// MIPS:UINTMAX_C_(0) 0ULL
+//
+// RUN: %clang_cc1 -E -ffreestanding -triple=mips64-none-none %s | FileCheck -check-prefix MIPS64 %s
+//
+// MIPS64:typedef signed long long int int64_t;
+// MIPS64:typedef unsigned long long int uint64_t;
+// MIPS64:typedef int64_t int_least64_t;
+// MIPS64:typedef uint64_t uint_least64_t;
+// MIPS64:typedef int64_t int_fast64_t;
+// MIPS64:typedef uint64_t uint_fast64_t;
+//
+// MIPS64:typedef signed int int32_t;
+// MIPS64:typedef unsigned int uint32_t;
+// MIPS64:typedef int32_t int_least32_t;
+// MIPS64:typedef uint32_t uint_least32_t;
+// MIPS64:typedef int32_t int_fast32_t;
+// MIPS64:typedef uint32_t uint_fast32_t;
+//
+// MIPS64:typedef signed short int16_t;
+// MIPS64:typedef unsigned short uint16_t;
+// MIPS64:typedef int16_t int_least16_t;
+// MIPS64:typedef uint16_t uint_least16_t;
+// MIPS64:typedef int16_t int_fast16_t;
+// MIPS64:typedef uint16_t uint_fast16_t;
+//
+// MIPS64:typedef signed char int8_t;
+// MIPS64:typedef unsigned char uint8_t;
+// MIPS64:typedef int8_t int_least8_t;
+// MIPS64:typedef uint8_t uint_least8_t;
+// 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 long int intmax_t;
+// MIPS64:typedef long long unsigned int uintmax_t;
+//
+// MIPS64:INT8_MAX_ 127
+// MIPS64:INT8_MIN_ (-127 -1)
+// MIPS64:UINT8_MAX_ 255
+// MIPS64:INT_LEAST8_MIN_ (-127 -1)
+// MIPS64:INT_LEAST8_MAX_ 127
+// MIPS64:UINT_LEAST8_MAX_ 255
+// MIPS64:INT_FAST8_MIN_ (-127 -1)
+// MIPS64:INT_FAST8_MAX_ 127
+// MIPS64:UINT_FAST8_MAX_ 255
+//
+// MIPS64:INT16_MAX_ 32767
+// MIPS64:INT16_MIN_ (-32767 -1)
+// MIPS64:UINT16_MAX_ 65535
+// MIPS64:INT_LEAST16_MIN_ (-32767 -1)
+// MIPS64:INT_LEAST16_MAX_ 32767
+// MIPS64:UINT_LEAST16_MAX_ 65535
+// MIPS64:INT_FAST16_MIN_ (-32767 -1)
+// MIPS64:INT_FAST16_MAX_ 32767
+// MIPS64:UINT_FAST16_MAX_ 65535
+//
+// MIPS64:INT32_MAX_ 2147483647
+// MIPS64:INT32_MIN_ (-2147483647 -1)
+// MIPS64:UINT32_MAX_ 4294967295U
+// MIPS64:INT_LEAST32_MIN_ (-2147483647 -1)
+// MIPS64:INT_LEAST32_MAX_ 2147483647
+// MIPS64:UINT_LEAST32_MAX_ 4294967295U
+// MIPS64:INT_FAST32_MIN_ (-2147483647 -1)
+// MIPS64:INT_FAST32_MAX_ 2147483647
+// MIPS64:UINT_FAST32_MAX_ 4294967295U
+//
+// MIPS64:INT64_MAX_ 9223372036854775807LL
+// MIPS64:INT64_MIN_ (-9223372036854775807LL -1)
+// MIPS64:UINT64_MAX_ 18446744073709551615ULL
+// MIPS64:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// MIPS64:INT_LEAST64_MAX_ 9223372036854775807LL
+// MIPS64:UINT_LEAST64_MAX_ 18446744073709551615ULL
+// MIPS64:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// MIPS64:INT_FAST64_MAX_ 9223372036854775807LL
+// MIPS64:UINT_FAST64_MAX_ 18446744073709551615ULL
+//
+// MIPS64:INTPTR_MIN_ (-9223372036854775807LL -1)
+// MIPS64:INTPTR_MAX_ 9223372036854775807LL
+// MIPS64:UINTPTR_MAX_ 18446744073709551615ULL
+// MIPS64:PTRDIFF_MIN_ (-9223372036854775807LL -1)
+// MIPS64:PTRDIFF_MAX_ 9223372036854775807LL
+// MIPS64:SIZE_MAX_ 18446744073709551615ULL
+//
+// MIPS64:INTMAX_MIN_ (-9223372036854775807LL -1)
+// MIPS64:INTMAX_MAX_ 9223372036854775807LL
+// MIPS64:UINTMAX_MAX_ 18446744073709551615ULL
+//
+// MIPS64:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// MIPS64:SIG_ATOMIC_MAX_ 2147483647
+// MIPS64:WINT_MIN_ (-2147483647 -1)
+// MIPS64:WINT_MAX_ 2147483647
+//
+// MIPS64:WCHAR_MAX_ 2147483647
+// MIPS64:WCHAR_MIN_ (-2147483647 -1)
+//
+// MIPS64:INT8_C_(0) 0
+// MIPS64:UINT8_C_(0) 0U
+// MIPS64:INT16_C_(0) 0
+// MIPS64:UINT16_C_(0) 0U
+// MIPS64:INT32_C_(0) 0
+// MIPS64:UINT32_C_(0) 0U
+// MIPS64:INT64_C_(0) 0LL
+// MIPS64:UINT64_C_(0) 0ULL
+//
+// MIPS64:INTMAX_C_(0) 0LL
+// MIPS64:UINTMAX_C_(0) 0ULL
+//
// RUN: %clang_cc1 -E -ffreestanding -triple=msp430-none-none %s | FileCheck -check-prefix MSP430 %s
//
// MSP430:typedef signed long int int32_t;
@@ -239,8 +453,8 @@
// MSP430:typedef int16_t intptr_t;
// MSP430:typedef uint16_t uintptr_t;
//
-// MSP430:typedef long int intmax_t;
-// MSP430:typedef long unsigned int uintmax_t;
+// MSP430:typedef long long int intmax_t;
+// MSP430:typedef long long unsigned int uintmax_t;
//
// MSP430:INT8_MAX_ 127
// MSP430:INT8_MIN_ (-127 -1)
@@ -289,9 +503,9 @@
// MSP430:PTRDIFF_MAX_ 32767
// MSP430:SIZE_MAX_ 65535
//
-// MSP430:INTMAX_MIN_ (-2147483647L -1)
-// MSP430:INTMAX_MAX_ 2147483647L
-// MSP430:UINTMAX_MAX_ 4294967295UL
+// MSP430:INTMAX_MIN_ (-9223372036854775807LL -1)
+// MSP430:INTMAX_MAX_ 9223372036854775807LL
+// MSP430:UINTMAX_MAX_ 18446744073709551615ULL
//
// MSP430:SIG_ATOMIC_MIN_ (-2147483647L -1)
// MSP430:SIG_ATOMIC_MAX_ 2147483647L
@@ -963,6 +1177,114 @@
// I386_MINGW32:WCHAR_MIN_ 0U
//
//
+// RUN: %clang_cc1 -E -ffreestanding -triple=xcore-none-none %s | FileCheck -check-prefix XCORE %s
+//
+// XCORE:typedef signed long long int int64_t;
+// XCORE:typedef unsigned long long int uint64_t;
+// XCORE:typedef int64_t int_least64_t;
+// XCORE:typedef uint64_t uint_least64_t;
+// XCORE:typedef int64_t int_fast64_t;
+// XCORE:typedef uint64_t uint_fast64_t;
+//
+// XCORE:typedef signed int int32_t;
+// XCORE:typedef unsigned int uint32_t;
+// XCORE:typedef int32_t int_least32_t;
+// XCORE:typedef uint32_t uint_least32_t;
+// XCORE:typedef int32_t int_fast32_t;
+// XCORE:typedef uint32_t uint_fast32_t;
+//
+// XCORE:typedef signed short int16_t;
+// XCORE:typedef unsigned short uint16_t;
+// XCORE:typedef int16_t int_least16_t;
+// XCORE:typedef uint16_t uint_least16_t;
+// XCORE:typedef int16_t int_fast16_t;
+// XCORE:typedef uint16_t uint_fast16_t;
+//
+// XCORE:typedef signed char int8_t;
+// XCORE:typedef unsigned char uint8_t;
+// XCORE:typedef int8_t int_least8_t;
+// XCORE:typedef uint8_t uint_least8_t;
+// 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 long long int intmax_t;
+// XCORE:typedef long long unsigned int uintmax_t;
+//
+// XCORE:INT8_MAX_ 127
+// XCORE:INT8_MIN_ (-127 -1)
+// XCORE:UINT8_MAX_ 255
+// XCORE:INT_LEAST8_MIN_ (-127 -1)
+// XCORE:INT_LEAST8_MAX_ 127
+// XCORE:UINT_LEAST8_MAX_ 255
+// XCORE:INT_FAST8_MIN_ (-127 -1)
+// XCORE:INT_FAST8_MAX_ 127
+// XCORE:UINT_FAST8_MAX_ 255
+//
+// XCORE:INT16_MAX_ 32767
+// XCORE:INT16_MIN_ (-32767 -1)
+// XCORE:UINT16_MAX_ 65535
+// XCORE:INT_LEAST16_MIN_ (-32767 -1)
+// XCORE:INT_LEAST16_MAX_ 32767
+// XCORE:UINT_LEAST16_MAX_ 65535
+// XCORE:INT_FAST16_MIN_ (-32767 -1)
+// XCORE:INT_FAST16_MAX_ 32767
+// XCORE:UINT_FAST16_MAX_ 65535
+//
+// XCORE:INT32_MAX_ 2147483647
+// XCORE:INT32_MIN_ (-2147483647 -1)
+// XCORE:UINT32_MAX_ 4294967295U
+// XCORE:INT_LEAST32_MIN_ (-2147483647 -1)
+// XCORE:INT_LEAST32_MAX_ 2147483647
+// XCORE:UINT_LEAST32_MAX_ 4294967295U
+// XCORE:INT_FAST32_MIN_ (-2147483647 -1)
+// XCORE:INT_FAST32_MAX_ 2147483647
+// XCORE:UINT_FAST32_MAX_ 4294967295U
+//
+// XCORE:INT64_MAX_ 9223372036854775807LL
+// XCORE:INT64_MIN_ (-9223372036854775807LL -1)
+// XCORE:UINT64_MAX_ 18446744073709551615ULL
+// XCORE:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// XCORE:INT_LEAST64_MAX_ 9223372036854775807LL
+// XCORE:UINT_LEAST64_MAX_ 18446744073709551615ULL
+// XCORE:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// XCORE:INT_FAST64_MAX_ 9223372036854775807LL
+// XCORE:UINT_FAST64_MAX_ 18446744073709551615ULL
+//
+// XCORE:INTPTR_MIN_ (-2147483647 -1)
+// XCORE:INTPTR_MAX_ 2147483647
+// XCORE:UINTPTR_MAX_ 4294967295U
+// XCORE:PTRDIFF_MIN_ (-2147483647 -1)
+// XCORE:PTRDIFF_MAX_ 2147483647
+// XCORE:SIZE_MAX_ 4294967295U
+//
+// XCORE:INTMAX_MIN_ (-9223372036854775807LL -1)
+// XCORE:INTMAX_MAX_ 9223372036854775807LL
+// XCORE:UINTMAX_MAX_ 18446744073709551615ULL
+//
+// XCORE:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// XCORE:SIG_ATOMIC_MAX_ 2147483647
+// XCORE:WINT_MIN_ 0U
+// XCORE:WINT_MAX_ 4294967295U
+//
+// XCORE:WCHAR_MAX_ 255U
+// XCORE:WCHAR_MIN_ 0
+//
+// XCORE:INT8_C_(0) 0
+// XCORE:UINT8_C_(0) 0U
+// XCORE:INT16_C_(0) 0
+// XCORE:UINT16_C_(0) 0U
+// XCORE:INT32_C_(0) 0
+// XCORE:UINT32_C_(0) 0U
+// XCORE:INT64_C_(0) 0LL
+// XCORE:UINT64_C_(0) 0ULL
+//
+// XCORE:INTMAX_C_(0) 0LL
+// XCORE:UINTMAX_C_(0) 0ULL
+//
+//
// stdint.h forms several macro definitions by pasting together identifiers
// to form names (eg. int32_t is formed from int ## 32 ## _t). The following
// case tests that these joining operations are performed correctly even if
diff --git a/test/Preprocessor/traditional-cpp.c b/test/Preprocessor/traditional-cpp.c
index 4c4633e03920..aa9f0f146e4c 100644
--- a/test/Preprocessor/traditional-cpp.c
+++ b/test/Preprocessor/traditional-cpp.c
@@ -3,9 +3,9 @@
* things like using /usr/bin/cpp to preprocess non-source files. */
/*
- RUN: %clang_cc1 -traditional-cpp %s -E -o %t
- RUN: FileCheck -strict-whitespace < %t %s
+ RUN: %clang_cc1 -traditional-cpp %s -E | FileCheck -strict-whitespace %s
RUN: %clang_cc1 -traditional-cpp %s -E -C | FileCheck -check-prefix=CHECK-COMMENTS %s
+ RUN: %clang_cc1 -traditional-cpp -x c++ %s -E | FileCheck -check-prefix=CHECK-CXX %s
*/
/* -traditional-cpp should eliminate all C89 comments. */
@@ -13,7 +13,9 @@
* CHECK-COMMENTS: {{^}}/* -traditional-cpp should eliminate all C89 comments. *{{/$}}
*/
+/* -traditional-cpp should only eliminate "//" comments in C++ mode. */
/* CHECK: {{^}}foo // bar{{$}}
+ * CHECK-CXX: {{^}}foo {{$}}
*/
foo // bar
@@ -88,3 +90,20 @@ a b c in skipped block
Preserve URLs: http://clang.llvm.org
/* CHECK: {{^}}Preserve URLs: http://clang.llvm.org{{$}}
*/
+
+/* The following tests ensure we ignore # and ## in macro bodies */
+
+#define FOO_NO_STRINGIFY(a) test(# a)
+FOO_NO_STRINGIFY(foobar)
+/* CHECK: {{^}}test(# foobar){{$}}
+ */
+
+#define FOO_NO_PASTE(a, b) test(b##a)
+FOO_NO_PASTE(foo,bar)
+/* CHECK {{^}}test(bar##foo){{$}}
+ */
+
+#define BAR_NO_STRINGIFY(a) test(#a)
+BAR_NO_STRINGIFY(foobar)
+/* CHECK: {{^}}test(#foobar){{$}}
+ */
diff --git a/test/Preprocessor/ucn-pp-identifier.c b/test/Preprocessor/ucn-pp-identifier.c
index 8616d40ec3f7..6936ed92cb59 100644
--- a/test/Preprocessor/ucn-pp-identifier.c
+++ b/test/Preprocessor/ucn-pp-identifier.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -pedantic -verify -Wundef
// RUN: %clang_cc1 %s -fsyntax-only -x c++ -pedantic -verify -Wundef
-// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -pedantic -Wundef 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 %s -fsyntax-only -std=c99 -pedantic -Wundef 2>&1 | FileCheck -strict-whitespace %s
#define \u00FC
#define a\u00FD() 0
diff --git a/test/Preprocessor/warn-macro-unused.c b/test/Preprocessor/warn-macro-unused.c
index c33aeb5df9d9..a305cc9966ad 100644
--- a/test/Preprocessor/warn-macro-unused.c
+++ b/test/Preprocessor/warn-macro-unused.c
@@ -2,6 +2,10 @@
#include "warn-macro-unused.h"
+# 1 "warn-macro-unused-fake-header.h" 1
+#define unused_from_fake_header
+# 5 "warn-macro-unused.c" 2
+
#define unused // expected-warning {{macro is not used}}
#define unused
unused
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
index ad7ee85eb234..751c8ae95853 100644
--- a/test/Preprocessor/x86_target_features.c
+++ b/test/Preprocessor/x86_target_features.c
@@ -1,32 +1,238 @@
-// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -x c -E -dM -o %t %s
-// RUN: grep '#define __SSE2_MATH__ 1' %t
-// RUN: grep '#define __SSE2__ 1' %t
-// RUN: grep '#define __SSE3__ 1' %t
-// RUN: grep '#define __SSE4_1__ 1' %t
-// RUN: grep '#define __SSE4_2__ 1' %t
-// RUN: grep '#define __SSE_MATH__ 1' %t
-// RUN: grep '#define __SSE__ 1' %t
-// RUN: grep '#define __SSSE3__ 1' %t
-
-// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -mno-sse2 -x c -E -dM -o %t %s
-// RUN: grep '#define __SSE2_MATH__ 1' %t | count 0
-// RUN: grep '#define __SSE2__ 1' %t | count 0
-// RUN: grep '#define __SSE3__ 1' %t | count 0
-// RUN: grep '#define __SSE4_1__ 1' %t | count 0
-// RUN: grep '#define __SSE4_2__ 1' %t | count 0
-// RUN: grep '#define __SSE_MATH__ 1' %t
-// RUN: grep '#define __SSE__ 1' %t
-// RUN: grep '#define __SSSE3__ 1' %t | count 0
-
-// RUN: %clang -target i386-unknown-unknown -march=pentium-m -x c -E -dM -o %t %s
-// RUN: grep '#define __SSE2_MATH__ 1' %t
-// RUN: grep '#define __SSE2__ 1' %t
-// RUN: grep '#define __SSE3__ 1' %t | count 0
-// RUN: grep '#define __SSE4_1__ 1' %t | count 0
-// RUN: grep '#define __SSE4_2__ 1' %t | count 0
-// RUN: grep '#define __SSE_MATH__ 1' %t
-// RUN: grep '#define __SSE__ 1' %t
-// RUN: grep '#define __SSSE3__ 1' %t | count 0
+// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -x c -E -dM -o - %s | FileCheck --check-prefix=SSE4 %s
+// SSE4: #define __SSE2_MATH__ 1
+// SSE4: #define __SSE2__ 1
+// SSE4: #define __SSE3__ 1
+// SSE4: #define __SSE4_1__ 1
+// SSE4: #define __SSE4_2__ 1
+// SSE4: #define __SSE_MATH__ 1
+// SSE4: #define __SSE__ 1
+// SSE4: #define __SSSE3__ 1
+// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -mno-sse2 -x c -E -dM -o - %s | FileCheck --check-prefix=SSE %s
+
+// SSE-NOT: #define __SSE2_MATH__ 1
+// SSE-NOT: #define __SSE2__ 1
+// SSE-NOT: #define __SSE3__ 1
+// SSE-NOT: #define __SSE4_1__ 1
+// SSE-NOT: #define __SSE4_2__ 1
+// SSE: #define __SSE_MATH__ 1
+// SSE: #define __SSE__ 1
+// SSE-NOT: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentium-m -x c -E -dM -o - %s | FileCheck --check-prefix=SSE2 %s
+
+// SSE2: #define __SSE2_MATH__ 1
+// SSE2: #define __SSE2__ 1
+// SSE2-NOT: #define __SSE3__ 1
+// SSE2-NOT: #define __SSE4_1__ 1
+// SSE2-NOT: #define __SSE4_2__ 1
+// SSE2: #define __SSE_MATH__ 1
+// SSE2: #define __SSE__ 1
+// SSE2-NOT: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentium-m -mno-sse -mavx -x c -E -dM -o - %s | FileCheck --check-prefix=AVX %s
+
+// AVX: #define __AVX__ 1
+// AVX: #define __SSE2_MATH__ 1
+// AVX: #define __SSE2__ 1
+// AVX: #define __SSE3__ 1
+// AVX: #define __SSE4_1__ 1
+// AVX: #define __SSE4_2__ 1
+// AVX: #define __SSE_MATH__ 1
+// AVX: #define __SSE__ 1
+// AVX: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentium-m -mxop -mno-avx -x c -E -dM -o - %s | FileCheck --check-prefix=SSE4A %s
+
+// SSE4A: #define __SSE2_MATH__ 1
+// SSE4A: #define __SSE2__ 1
+// SSE4A: #define __SSE3__ 1
+// SSE4A: #define __SSE4A__ 1
+// SSE4A: #define __SSE4_1__ 1
+// SSE4A: #define __SSE4_2__ 1
+// SSE4A: #define __SSE_MATH__ 1
+// SSE4A: #define __SSE__ 1
+// SSE4A: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512f -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512F %s
+
+// AVX512F: #define __AVX2__ 1
+// AVX512F: #define __AVX512F__ 1
+// AVX512F: #define __AVX__ 1
+// AVX512F: #define __SSE2_MATH__ 1
+// AVX512F: #define __SSE2__ 1
+// AVX512F: #define __SSE3__ 1
+// AVX512F: #define __SSE4_1__ 1
+// AVX512F: #define __SSE4_2__ 1
+// AVX512F: #define __SSE_MATH__ 1
+// AVX512F: #define __SSE__ 1
+// AVX512F: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512cd -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512CD %s
+
+// AVX512CD: #define __AVX2__ 1
+// AVX512CD: #define __AVX512CD__ 1
+// AVX512CD: #define __AVX512F__ 1
+// AVX512CD: #define __AVX__ 1
+// AVX512CD: #define __SSE2_MATH__ 1
+// AVX512CD: #define __SSE2__ 1
+// AVX512CD: #define __SSE3__ 1
+// AVX512CD: #define __SSE4_1__ 1
+// AVX512CD: #define __SSE4_2__ 1
+// AVX512CD: #define __SSE_MATH__ 1
+// AVX512CD: #define __SSE__ 1
+// AVX512CD: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512er -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512ER %s
+
+// AVX512ER: #define __AVX2__ 1
+// AVX512ER: #define __AVX512ER__ 1
+// AVX512ER: #define __AVX512F__ 1
+// AVX512ER: #define __AVX__ 1
+// AVX512ER: #define __SSE2_MATH__ 1
+// AVX512ER: #define __SSE2__ 1
+// AVX512ER: #define __SSE3__ 1
+// AVX512ER: #define __SSE4_1__ 1
+// AVX512ER: #define __SSE4_2__ 1
+// AVX512ER: #define __SSE_MATH__ 1
+// AVX512ER: #define __SSE__ 1
+// AVX512ER: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512pf -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512PF %s
+
+// AVX512PF: #define __AVX2__ 1
+// AVX512PF: #define __AVX512F__ 1
+// AVX512PF: #define __AVX512PF__ 1
+// AVX512PF: #define __AVX__ 1
+// AVX512PF: #define __SSE2_MATH__ 1
+// AVX512PF: #define __SSE2__ 1
+// AVX512PF: #define __SSE3__ 1
+// AVX512PF: #define __SSE4_1__ 1
+// AVX512PF: #define __SSE4_2__ 1
+// AVX512PF: #define __SSE_MATH__ 1
+// AVX512PF: #define __SSE__ 1
+// AVX512PF: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512pf -mno-avx512f -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512F2 %s
+
+// AVX512F2: #define __AVX2__ 1
+// AVX512F2-NOT: #define __AVX512F__ 1
+// AVX512F2-NOT: #define __AVX512PF__ 1
+// AVX512F2: #define __AVX__ 1
+// AVX512F2: #define __SSE2_MATH__ 1
+// AVX512F2: #define __SSE2__ 1
+// AVX512F2: #define __SSE3__ 1
+// AVX512F2: #define __SSE4_1__ 1
+// AVX512F2: #define __SSE4_2__ 1
+// AVX512F2: #define __SSE_MATH__ 1
+// AVX512F2: #define __SSE__ 1
+// AVX512F2: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -msse4.2 -x c -E -dM -o - %s | FileCheck --check-prefix=SSE42POPCNT %s
+
+// SSE42POPCNT: #define __POPCNT__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mno-popcnt -msse4.2 -x c -E -dM -o - %s | FileCheck --check-prefix=SSE42NOPOPCNT %s
+
+// SSE42NOPOPCNT-NOT: #define __POPCNT__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mpopcnt -mno-sse4.2 -x c -E -dM -o - %s | FileCheck --check-prefix=NOSSE42POPCNT %s
+
+// NOSSE42POPCNT: #define __POPCNT__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -msse -x c -E -dM -o - %s | FileCheck --check-prefix=SSEMMX %s
+
+// SSEMMX: #define __MMX__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -msse -mno-sse -x c -E -dM -o - %s | FileCheck --check-prefix=SSENOSSEMMX %s
+
+// SSENOSSEMMX-NOT: #define __MMX__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -msse -mno-mmx -x c -E -dM -o - %s | FileCheck --check-prefix=SSENOMMX %s
+
+// SSENOMMX-NOT: #define __MMX__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mf16c -x c -E -dM -o - %s | FileCheck --check-prefix=F16C %s
+
+// F16C: #define __AVX__ 1
+// F16C: #define __F16C__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mf16c -mno-avx -x c -E -dM -o - %s | FileCheck --check-prefix=F16CNOAVX %s
+
+// F16CNOAVX-NOT: #define __AVX__ 1
+// F16CNOAVX-NOT: #define __F16C__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -mpclmul -x c -E -dM -o - %s | FileCheck --check-prefix=PCLMUL %s
+
+// PCLMUL: #define __PCLMUL__ 1
+// PCLMUL: #define __SSE2__ 1
+// PCLMUL-NOT: #define __SSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -mpclmul -mno-sse2 -x c -E -dM -o - %s | FileCheck --check-prefix=PCLMULNOSSE2 %s
+
+// PCLMULNOSSE2-NOT: #define __PCLMUL__ 1
+// PCLMULNOSSE2-NOT: #define __SSE2__ 1
+// PCLMULNOSSE2-NOT: #define __SSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -maes -x c -E -dM -o - %s | FileCheck --check-prefix=AES %s
+
+// AES: #define __AES__ 1
+// AES: #define __SSE2__ 1
+// AES-NOT: #define __SSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -maes -mno-sse2 -x c -E -dM -o - %s | FileCheck --check-prefix=AESNOSSE2 %s
+
+// AESNOSSE2-NOT: #define __AES__ 1
+// AESNOSSE2-NOT: #define __SSE2__ 1
+// AESNOSSE2-NOT: #define __SSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -msha -x c -E -dM -o - %s | FileCheck --check-prefix=SHA %s
+
+// SHA: #define __SHA__ 1
+// SHA: #define __SSE2__ 1
+// SHA-NOT: #define __SSE3__ 1
+
+// run: %clang -target i386-unknown-unknown -march=pentiumpro -msha -mno-sha -x c -e -dm -o - %s | filecheck --check-prefix=SHANOSHA %s
+
+// SHANOSHA-NOT: #define __SHA__ 1
+// SHANOSHA-NOT: #define __SSE2__ 1
+
+// run: %clang -target i386-unknown-unknown -march=pentiumpro -msha -mno-sse2 -x c -e -dm -o - %s | filecheck --check-prefix=SHANOSSE2 %s
+
+// SHANOSSSE2-NOT: #define __SHA__ 1
+// SHANOSSSE2-NOT: #define __SSE2__ 1
+// SHANOSSSE2-NOT: #define __SSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mtbm -x c -E -dM -o - %s | FileCheck --check-prefix=TBM %s
+
+// TBM: #define __TBM__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=bdver2 -mno-tbm -x c -E -dM -o - %s | FileCheck --check-prefix=NOTBM %s
+
+// NOTBM-NOT: #define __TBM__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -mcx16 -x c -E -dM -o - %s | FileCheck --check-prefix=MCX16 %s
+
+// MCX16: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mprfchw -x c -E -dM -o - %s | FileCheck --check-prefix=PRFCHW %s
+
+// PRFCHW: #define __PRFCHW__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=btver2 -mno-prfchw -x c -E -dM -o - %s | FileCheck --check-prefix=NOPRFCHW %s
+
+// NOPRFCHW-NOT: #define __PRFCHW__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -m3dnow -x c -E -dM -o - %s | FileCheck --check-prefix=3DNOWPRFCHW %s
+
+// 3DNOWPRFCHW: #define __PRFCHW__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mno-prfchw -m3dnow -x c -E -dM -o - %s | FileCheck --check-prefix=3DNOWNOPRFCHW %s
+
+// 3DNOWNOPRFCHW-NOT: #define __PRFCHW__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mprfchw -mno-3dnow -x c -E -dM -o - %s | FileCheck --check-prefix=NO3DNOWPRFCHW %s
+
+// NO3DNOWPRFCHW: #define __PRFCHW__ 1
diff --git a/test/Rewriter/blockcast3.mm b/test/Rewriter/blockcast3.mm
index 697a465a9317..1d82609cfb56 100644
--- a/test/Rewriter/blockcast3.mm
+++ b/test/Rewriter/blockcast3.mm
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %t.mm -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o %t-modern-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-modern-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-modern-rw.cpp %s
// radar 7607781
typedef struct {
diff --git a/test/Rewriter/dllimport-typedef.c b/test/Rewriter/dllimport-typedef.c
index 72cea70cf2d6..97610ddb28e1 100644
--- a/test/Rewriter/dllimport-typedef.c
+++ b/test/Rewriter/dllimport-typedef.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s
-// RUN: %clang_cc1 -triple i686-pc-win32 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-POS %s
+// RUN: not %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s
+// RUN: not %clang_cc1 -triple i686-pc-win32 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-POS %s
// Do not report an error with including dllimport in the typedef when -fms-extensions is specified.
// Addresses <rdar://problem/7653870>.
diff --git a/test/Rewriter/inner-block-helper-funcs.mm b/test/Rewriter/inner-block-helper-funcs.mm
index fb565b6e30f3..92ef7e933615 100644
--- a/test/Rewriter/inner-block-helper-funcs.mm
+++ b/test/Rewriter/inner-block-helper-funcs.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// rdar://9846759
typedef void (^dispatch_block_t)(void);
diff --git a/test/Rewriter/line-generation-test.m b/test/Rewriter/line-generation-test.m
index dad7371eb165..0e666e1f5fbc 100644
--- a/test/Rewriter/line-generation-test.m
+++ b/test/Rewriter/line-generation-test.m
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang_cc1 -fms-extensions -rewrite-objc -g %t.mm -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LINE --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LINE --input-file=%t-rw.cpp %s
// RUN: %clang_cc1 -fms-extensions -rewrite-objc %t.mm -o %t-rwnog.cpp
-// RUN: FileCheck -check-prefix NOLINE --input-file=%t-rwnog.cpp %s
+// RUN: FileCheck -check-prefix CHECK-NOLINE --input-file=%t-rwnog.cpp %s
// rdar://13138170
__attribute__((objc_root_class)) @interface MyObject {
diff --git a/test/Rewriter/lit.local.cfg b/test/Rewriter/lit.local.cfg
new file mode 100644
index 000000000000..5bbc711c656d
--- /dev/null
+++ b/test/Rewriter/lit.local.cfg
@@ -0,0 +1,2 @@
+if config.root.clang_rewriter == 0:
+ config.unsupported = True
diff --git a/test/Rewriter/missing-dllimport.c b/test/Rewriter/missing-dllimport.c
index 1dfc04c5b80c..127989b0ed8a 100644
--- a/test/Rewriter/missing-dllimport.c
+++ b/test/Rewriter/missing-dllimport.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s
-// RUN: %clang_cc1 -triple i686-pc-win32 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-POS %s
+// RUN: not %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s
+// RUN: not %clang_cc1 -triple i686-pc-win32 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-POS %s
// Do not report that 'foo()' is redeclared without dllimport attribute with -fms-extensions
// specified. Addresses <rdar://problem/7653912>.
diff --git a/test/Rewriter/objc-modern-StretAPI-3.mm b/test/Rewriter/objc-modern-StretAPI-3.mm
new file mode 100644
index 000000000000..3ada56e939b0
--- /dev/null
+++ b/test/Rewriter/objc-modern-StretAPI-3.mm
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// rdar://14932320
+
+extern "C" void *sel_registerName(const char *);
+typedef unsigned long size_t;
+
+typedef struct {
+ unsigned long long x;
+ unsigned long long y;
+} myPoint;
+
+typedef struct {
+ unsigned long long x;
+ unsigned long long y;
+} allPoint;
+
+@interface Obj
++ (myPoint)foo;
++ (myPoint)foo : (int)Arg1 : (double)fArg;
++ (allPoint)fee;
+@end
+
+@implementation Obj
++ (allPoint)fee {
+ allPoint a;
+ a.x = a.y = 3;
+
+ return a;
+}
++ (myPoint)foo {
+ myPoint r;
+ r.x = 1;
+ r.y = 2;
+ return r;
+}
+
++ (myPoint)foo : (int)Arg1 : (double)fArg {
+ myPoint r;
+ return r;
+}
+@end
+
+myPoint Ret_myPoint() {
+ return [Obj foo];
+}
+
+allPoint Ret_allPoint() {
+ return [Obj fee];
+}
+
+myPoint Ret_myPoint1(int i, double d) {
+ return [Obj foo:i:d];
+}
+
+myPoint Ret_myPoint2() {
+ return [Obj foo];
+}
diff --git a/test/Rewriter/objc-modern-boxing.mm b/test/Rewriter/objc-modern-boxing.mm
index 4997c24961c2..40eeafbe293e 100644
--- a/test/Rewriter/objc-modern-boxing.mm
+++ b/test/Rewriter/objc-modern-boxing.mm
@@ -66,7 +66,7 @@ int main(int argc, const char *argv[]) {
// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), (42U));
// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), (42L));
// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), (42LL));
-// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.1415927F));
-// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535));
+// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.14159274F));
+// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535000001));
// CHECK: NSNumber *nsb = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)(b));
// CHECK: NSString *duplicateString = ((NSString *(*)(id, SEL, const char *))(void *)objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), (const char *)(strdup("Hello")));
diff --git a/test/Rewriter/objc-modern-fast-enumeration.mm b/test/Rewriter/objc-modern-fast-enumeration.mm
new file mode 100644
index 000000000000..460e79c91e99
--- /dev/null
+++ b/test/Rewriter/objc-modern-fast-enumeration.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -triple i686-pc-win32 -Werror -Wno-address-of-temporary -D"Class=struct objc_class *" -D"id=struct objc_object *" -D"SEL=void*" -U__declspec -D"__declspec(X)=" %t-rw.cpp -Wno-attributes
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-win32 -Werror -Wno-address-of-temporary -D_WIN64 -D"Class=struct objc_class *" -D"id=struct objc_object *" -D"SEL=void*" -U__declspec -D"__declspec(X)=" %t-rw.cpp -Wno-attributes
+// rdar://14913632
+
+extern "C" void *sel_registerName(const char *);
+
+void x() {
+ id y;
+ for (id a in y) {
+ }
+}
+
+// CHECK: #ifdef _WIN64
+// CHECK-NEXT: typedef unsigned long long _WIN_NSUInteger;
+// CHECK-NEXT: #else
+// CHECK-NEXT: typedef unsigned int _WIN_NSUInteger;
+// CHECK-NEXT: #endif
+// CHECK: _WIN_NSUInteger limit =
+// CHECK-NEXT: ((_WIN_NSUInteger (*) (id, SEL, struct __objcFastEnumerationState *, id *, _WIN_NSUInteger))(void *)objc_msgSend)
+// CHECK-NEXT: ((id)l_collection,
+// CHECK-NEXT: sel_registerName("countByEnumeratingWithState:objects:count:"),
+// CHECK-NEXT: &enumState, (id *)__rw_items, (_WIN_NSUInteger)16);
diff --git a/test/Rewriter/objc-modern-numeric-literal.mm b/test/Rewriter/objc-modern-numeric-literal.mm
index 5f63d8c52ad2..57f7ca2d9a3b 100644
--- a/test/Rewriter/objc-modern-numeric-literal.mm
+++ b/test/Rewriter/objc-modern-numeric-literal.mm
@@ -61,8 +61,8 @@ int main(int argc, const char *argv[]) {
// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), 42U);
// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), 42L);
// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), 42LL);
-// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), 3.1415927F);
-// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), 3.1415926535);
+// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), 3.14159274F);
+// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), 3.1415926535000001);
// CHECK: NSNumber *yesNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
// CHECK: NSNumber *noNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false);
// CHECK: NSNumber *trueNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
diff --git a/test/Rewriter/objc-modern-property-attributes.mm b/test/Rewriter/objc-modern-property-attributes.mm
index abebb2c0feff..f0d002caf61c 100644
--- a/test/Rewriter/objc-modern-property-attributes.mm
+++ b/test/Rewriter/objc-modern-property-attributes.mm
@@ -16,6 +16,10 @@ typedef void (^void_block_t)(void);
@property (copy) void_block_t completionBlock;
@property (retain) PropertyClass* Yblock;
+@property (readonly) PropertyClass* readonlyAttr;
+@property (readonly,copy) PropertyClass* readonlyCopyAttr;
+@property (readonly,retain) PropertyClass* readonlyRetainAttr;
+@property (readonly,retain,nonatomic) PropertyClass* readonlyNonatomicAttr;
@property (copy) id ID;
@end
@@ -25,6 +29,10 @@ typedef void (^void_block_t)(void);
@dynamic r; // attributes should be "Ti,D"
@synthesize completionBlock=__completion; // "T@?,C,V__completion"
@synthesize Yblock = YVAR; // "T@\"PropertyClass\",&,VYVAR"
+@synthesize readonlyAttr;
+@synthesize readonlyCopyAttr;
+@synthesize readonlyRetainAttr;
+@synthesize readonlyNonatomicAttr;
@synthesize ID; // "T@,C,VID"
@end
@@ -32,6 +40,10 @@ typedef void (^void_block_t)(void);
// CHECK: Ti,D
// CHECK: T@?,C,V__completion
// CHECK: T@\"PropertyClass\",&,VYVAR
+// CHECK: T@\"PropertyClass\",R,VreadonlyAttr
+// CHECK: T@\"PropertyClass\",R,C,VreadonlyCopyAttr
+// CHECK: T@\"PropertyClass\",R,&,VreadonlyRetainAttr
+// CHECK: T@\"PropertyClass\",R,&,N,VreadonlyNonatomicAttr
@interface Test @end
@interface Test (Category)
diff --git a/test/Rewriter/rewrite-cast-ivar-access.mm b/test/Rewriter/rewrite-cast-ivar-access.mm
index 4e50ff142a8c..d5c2796bcf34 100644
--- a/test/Rewriter/rewrite-cast-ivar-access.mm
+++ b/test/Rewriter/rewrite-cast-ivar-access.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// radar 7575882
@interface F {
diff --git a/test/Rewriter/rewrite-category-property.mm b/test/Rewriter/rewrite-category-property.mm
index 50ef4326e4e9..c0f530ecda37 100644
--- a/test/Rewriter/rewrite-category-property.mm
+++ b/test/Rewriter/rewrite-category-property.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// radar 7630636
@class Y, Z;
diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m
index 1d3cc57618ec..a783dfc26448 100644
--- a/test/Rewriter/rewrite-foreach-5.m
+++ b/test/Rewriter/rewrite-foreach-5.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=struct objc_object*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
void *sel_registerName(const char *);
void objc_enumerationMutation(id);
diff --git a/test/Rewriter/rewrite-foreach-6.m b/test/Rewriter/rewrite-foreach-6.m
index 5159d383e577..29d21afb61ff 100644
--- a/test/Rewriter/rewrite-foreach-6.m
+++ b/test/Rewriter/rewrite-foreach-6.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=struct objc_object*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar://5716356
// FIXME: Should be able to pipe into clang, but code is not
// yet correct for other reasons: rdar://5716940
diff --git a/test/Rewriter/rewrite-foreach-in-block.mm b/test/Rewriter/rewrite-foreach-in-block.mm
index 2c1023b0c706..4b2f37dc31b5 100644
--- a/test/Rewriter/rewrite-foreach-in-block.mm
+++ b/test/Rewriter/rewrite-foreach-in-block.mm
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
// rdar:// 9878420
typedef unsigned long size_t;
diff --git a/test/Rewriter/rewrite-foreach-protocol-id.m b/test/Rewriter/rewrite-foreach-protocol-id.m
index 5680110a524e..a9491f19ae73 100644
--- a/test/Rewriter/rewrite-foreach-protocol-id.m
+++ b/test/Rewriter/rewrite-foreach-protocol-id.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=struct objc_object*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar:// 9039342
void *sel_registerName(const char *);
diff --git a/test/Rewriter/rewrite-forward-class.mm b/test/Rewriter/rewrite-forward-class.mm
index 9f4e7e21e862..3d3ef3e6c9af 100644
--- a/test/Rewriter/rewrite-forward-class.mm
+++ b/test/Rewriter/rewrite-forward-class.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
extern "C" {
@@ -42,3 +42,14 @@ int I,J,K;
};
+// rdar://15027032
+@interface ISDPropertyChangeGroup
+@end
+
+@implementation ISDPropertyChangeGroup
+@class ISDClientState;
+- (id)lastModifiedGeneration : (ISDClientState *) obj
+{
+ return obj ;
+}
+@end
diff --git a/test/Rewriter/rewrite-interface-locals.mm b/test/Rewriter/rewrite-interface-locals.mm
new file mode 100644
index 000000000000..ef361051c198
--- /dev/null
+++ b/test/Rewriter/rewrite-interface-locals.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// rdar://15143875
+
+@class NSData, NSError;
+
+@interface Foo
+
+typedef void (^Callback)(NSData *data, NSError *error);
+
+- (void)doSomething:(NSData *)data callback:(Callback)callback;
+@end
+
+@implementation Foo
+
+- (void)doSomething:(NSData *)data callback:(Callback)callback {
+ callback(0, 0);
+}
+
+@end
diff --git a/test/Rewriter/rewrite-line-directive.m b/test/Rewriter/rewrite-line-directive.m
index 5c4e9574c111..ec50a83d3c19 100644
--- a/test/Rewriter/rewrite-line-directive.m
+++ b/test/Rewriter/rewrite-line-directive.m
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// RUN: %clang -g -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LPG --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LPG --input-file=%t-rw.cpp %s
// rdar://13138170
int z();
diff --git a/test/Rewriter/rewrite-message-expr.mm b/test/Rewriter/rewrite-message-expr.mm
index 72569cb8376f..04e27e5d44ae 100644
--- a/test/Rewriter/rewrite-message-expr.mm
+++ b/test/Rewriter/rewrite-message-expr.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// radar 7617047
@interface Baz
diff --git a/test/Rewriter/rewrite-modern-default-property-synthesis.mm b/test/Rewriter/rewrite-modern-default-property-synthesis.mm
index fd1a578f083f..f6fe510cba4b 100644
--- a/test/Rewriter/rewrite-modern-default-property-synthesis.mm
+++ b/test/Rewriter/rewrite-modern-default-property-synthesis.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -E %s -o %t.mm
-// RUN: %clang_cc1 -x objective-c++ -fms-extensions -fobjc-default-synthesize-properties -rewrite-objc %t.mm -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
// RUN: FileCheck --input-file=%t-rw.cpp %s
// RUN: %clang_cc1 -fsyntax-only -Werror -DSEL="void *" -Did="struct objc_object *" -Wno-attributes -Wno-address-of-temporary -U__declspec -D"__declspec(X)=" %t-rw.cpp
// rdar://11374235
diff --git a/test/Rewriter/rewrite-modern-synchronized.m b/test/Rewriter/rewrite-modern-synchronized.m
index e89533930388..17c8e9a4ad4f 100644
--- a/test/Rewriter/rewrite-modern-synchronized.m
+++ b/test/Rewriter/rewrite-modern-synchronized.m
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"Class=struct objc_class *" -D"__declspec(X)=" %t-rw.cpp
-typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
@@ -33,3 +32,15 @@ void test_sync_with_implicit_finally() {
return; // The rewriter knows how to generate code for implicit finally
}
}
+
+// rdar://14993814
+@interface NSObject @end
+
+@interface I : NSObject @end
+
+@implementation I
++ (void) Meth {
+@synchronized(self) {
+}
+}
+@end
diff --git a/test/Rewriter/rewrite-modern-typeof.mm b/test/Rewriter/rewrite-modern-typeof.mm
index a493c1184967..91e0b62fd588 100644
--- a/test/Rewriter/rewrite-modern-typeof.mm
+++ b/test/Rewriter/rewrite-modern-typeof.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Wno-attributes -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
typedef unsigned long size_t;
diff --git a/test/Rewriter/rewrite-typeof.mm b/test/Rewriter/rewrite-typeof.mm
index 02c36f88a569..f6790ea6d47b 100644
--- a/test/Rewriter/rewrite-typeof.mm
+++ b/test/Rewriter/rewrite-typeof.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp
-// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: FileCheck -check-prefix CHECK-LP --input-file=%t-rw.cpp %s
extern "C" {
extern "C" void *_Block_copy(const void *aBlock);
diff --git a/test/Sema/128bitfloat.cc b/test/Sema/128bitfloat.cc
new file mode 100644
index 000000000000..cb76dac96001
--- /dev/null
+++ b/test/Sema/128bitfloat.cc
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+#if !defined(__STRICT_ANSI__)
+__float128 f; // expected-error {{support for type '__float128' is not yet implemented}}
+// But this should work:
+template<typename> struct __is_floating_point_helper {};
+template<> struct __is_floating_point_helper<__float128> {};
+
+// FIXME: This could have a better diag.
+void g(int x, __float128 *y) {
+ x + *y; // expected-error {{invalid operands to binary expression ('int' and '__float128')}}
+}
+
+#else
+__float128 f; // expected-error {{unknown type name '__float128'}}
+template<typename> struct __is_floating_point_helper {};
+template<> struct __is_floating_point_helper<__float128> {}; // expected-error {{use of undeclared identifier '__float128'}}
+
+void g(int x, __float128 *y) { // expected-error {{unknown type name '__float128'}}
+ x + *y;
+}
+
+#endif
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c
index bb8e3d155e57..4272b2d1391e 100644
--- a/test/Sema/128bitint.c
+++ b/test/Sema/128bitint.c
@@ -16,10 +16,10 @@ __uint128_t b = (__uint128_t)-1;
__int128 i = (__int128)0;
unsigned __int128 u = (unsigned __int128)-1;
-long long SignedTooBig = 123456789012345678901234567890; // expected-warning {{integer constant is too large for its type}}
+long long SignedTooBig = 123456789012345678901234567890; // expected-error {{constant is larger than the largest unsigned integer type}}
__int128_t Signed128 = 123456789012345678901234567890i128;
long long Signed64 = 123456789012345678901234567890i128; // expected-warning {{implicit conversion from '__int128' to 'long long' changes value from 123456789012345678901234567890 to -4362896299872285998}}
-unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-warning {{integer constant is too large for its type}}
+unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-error {{constant is larger than the largest unsigned integer type}}
__uint128_t Unsigned128 = 123456789012345678901234567890Ui128;
unsigned long long Unsigned64 = 123456789012345678901234567890Ui128; // expected-warning {{implicit conversion from 'unsigned __int128' to 'unsigned long long' changes value from 123456789012345678901234567890 to 14083847773837265618}}
diff --git a/test/Sema/Inputs/ms-keyword-system-header.h b/test/Sema/Inputs/ms-keyword-system-header.h
new file mode 100644
index 000000000000..43a3db7a12ba
--- /dev/null
+++ b/test/Sema/Inputs/ms-keyword-system-header.h
@@ -0,0 +1,9 @@
+/* "System header" for testing GNU libc keyword conflict workarounds */
+
+typedef union {
+ union w *__uptr;
+#if defined(MS) && defined(NOT_SYSTEM)
+ // expected-warning@-2 {{keyword '__uptr' will be treated as an identifier here}}
+#endif
+ int *__iptr;
+} WS __attribute__((__transparent_union__));
diff --git a/test/Sema/MicrosoftCompatibility.cpp b/test/Sema/MicrosoftCompatibility.cpp
index 15c25586c47d..90a45dfaaf17 100644
--- a/test/Sema/MicrosoftCompatibility.cpp
+++ b/test/Sema/MicrosoftCompatibility.cpp
@@ -2,3 +2,9 @@
// PR15845
int foo(xxx); // expected-error{{unknown type name}}
+
+struct cls {
+ char *m;
+};
+
+char * cls::* __uptr wrong2 = &cls::m; // expected-error {{'__uptr' attribute cannot be used with pointers to members}}
diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c
index 5d7330e3f700..a6caf7acb8a8 100644
--- a/test/Sema/MicrosoftExtensions.c
+++ b/test/Sema/MicrosoftExtensions.c
@@ -76,6 +76,9 @@ void pointer_to_integral_type_conv(char* ptr) {
short sh = (short)ptr;
ch = (char)ptr;
sh = (short)ptr;
+
+ // This is valid ISO C.
+ _Bool b = (_Bool)ptr;
}
@@ -93,7 +96,7 @@ struct __declspec(deprecated) DS1 { int i; float f; }; // expected-note {{declar
#define MY_TEXT "This is also deprecated"
__declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {} // expected-note {{'Dfunc1' declared here}}
-struct __declspec(deprecated(123)) DS2 {}; // expected-error {{argument to deprecated attribute was not a string literal}}
+struct __declspec(deprecated(123)) DS2 {}; // expected-error {{'deprecated' attribute requires a string}}
void test( void ) {
e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
@@ -102,3 +105,32 @@ void test( void ) {
enum DE1 no; // no warning because E1 is not deprecated
}
+
+int __sptr wrong1; // expected-error {{'__sptr' attribute only applies to pointer arguments}}
+// The modifier must follow the asterisk
+int __sptr *wrong_psp; // expected-error {{'__sptr' attribute only applies to pointer arguments}}
+int * __sptr __uptr wrong2; // expected-error {{'__sptr' and '__uptr' attributes are not compatible}}
+int * __sptr __sptr wrong3; // expected-warning {{attribute '__sptr' is already applied}}
+
+// It is illegal to overload based on the type attribute.
+void ptr_func(int * __ptr32 i) {} // expected-note {{previous definition is here}}
+void ptr_func(int * __ptr64 i) {} // expected-error {{redefinition of 'ptr_func'}}
+
+// It is also illegal to overload based on the pointer type attribute.
+void ptr_func2(int * __sptr __ptr32 i) {} // expected-note {{previous definition is here}}
+void ptr_func2(int * __uptr __ptr32 i) {} // expected-error {{redefinition of 'ptr_func2'}}
+
+int * __sptr __ptr32 __sptr wrong4; // expected-warning {{attribute '__sptr' is already applied}}
+
+__ptr32 int *wrong5; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+int *wrong6 __ptr32; // expected-error {{expected ';' after top level declarator}} expected-warning {{declaration does not declare anything}}
+
+int * __ptr32 __ptr64 wrong7; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}}
+
+int * __ptr32 __ptr32 wrong8; // expected-warning {{attribute '__ptr32' is already applied}}
+
+int *(__ptr32 __sptr wrong9); // expected-error {{'__sptr' attribute only applies to pointer arguments}} // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+typedef int *T;
+T __ptr32 wrong10; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
diff --git a/test/Sema/aarch64-neon-vector-types.c b/test/Sema/aarch64-neon-vector-types.c
new file mode 100644
index 000000000000..894cf6de1b0c
--- /dev/null
+++ b/test/Sema/aarch64-neon-vector-types.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -triple aarch64-none-linux-gnu -target-feature +neon -fsyntax-only -verify
+
+typedef float float32_t;
+typedef unsigned char poly8_t;
+typedef unsigned short poly16_t;
+typedef unsigned long long uint64_t;
+
+// Define some valid Neon types.
+typedef __attribute__((neon_vector_type(2))) int int32x2_t;
+typedef __attribute__((neon_vector_type(4))) int int32x4_t;
+typedef __attribute__((neon_vector_type(1))) uint64_t uint64x1_t;
+typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t;
+typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t;
+typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
+typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
+typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
+
+// The attributes must have a single argument.
+typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{attribute takes one argument}}
+
+// The number of elements must be an ICE.
+typedef __attribute__((neon_vector_type(2.0))) int non_int_width; // expected-error{{attribute requires an integer constant}}
+
+// Only certain element types are allowed.
+typedef __attribute__((neon_vector_type(2))) double double_elt;
+typedef __attribute__((neon_vector_type(4))) void* ptr_elt; // expected-error{{invalid vector element type}}
+typedef __attribute__((neon_polyvector_type(4))) float32_t bad_poly_elt; // expected-error{{invalid vector element type}}
+struct aggr { signed char c; };
+typedef __attribute__((neon_vector_type(8))) struct aggr aggregate_elt; // expected-error{{invalid vector element type}}
+
+// The total vector size must be 64 or 128 bits.
+typedef __attribute__((neon_vector_type(1))) int int32x1_t; // expected-error{{Neon vector size must be 64 or 128 bits}}
+typedef __attribute__((neon_vector_type(3))) int int32x3_t; // expected-error{{Neon vector size must be 64 or 128 bits}}
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index 0ae3230a6189..4756af9d9528 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -65,3 +65,5 @@ void access_as_field()
(void) bar.as_field;
}
+typedef int PR4997 __attribute__((address_space(Foobar))); // expected-error {{use of undeclared identifier 'Foobar'}}
+__attribute__((address_space("12"))) int *i; // expected-error {{'address_space' attribute requires an integer constant}}
diff --git a/test/Sema/alias-redefinition.c b/test/Sema/alias-redefinition.c
new file mode 100644
index 000000000000..6c6ebf80250b
--- /dev/null
+++ b/test/Sema/alias-redefinition.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
+
+void f0() {}
+void fun0(void) __attribute((alias("f0")));
+
+void f1() {}
+void fun1() {} // expected-note {{previous definition}}
+void fun1(void) __attribute((alias("f1"))); // expected-error {{redefinition of 'fun1'}}
+
+void f2() {}
+void fun2(void) __attribute((alias("f2"))); // expected-note {{previous definition}}
+void fun2() {} // expected-error {{redefinition of 'fun2'}}
+
+void f3() {}
+void fun3(void) __attribute((alias("f3"))); // expected-note {{previous definition}}
+void fun3(void) __attribute((alias("f3"))); // expected-error {{redefinition of 'fun3'}}
+
+void f4() {}
+void fun4(void) __attribute((alias("f4")));
+void fun4(void);
+
+// FIXME: We should produce a special case error for this.
+void f5() {}
+void __attribute((alias("f5"))) fun5(void) {} // expected-error {{redefinition of 'fun5'}} // expected-note {{previous definition}}
+
+int v1;
+int var1 __attribute((alias("v1"))); // expected-note {{previous definition}}
+int var1 __attribute((alias("v1"))); // expected-error {{redefinition of 'var1'}}
+
+int v2;
+int var2 = 2; // expected-note {{previous definition}}
+int var2 __attribute((alias("v2"))); // expected-error {{redefinition of 'var2'}}
+
+int v3;
+int var3 __attribute((alias("v3"))); // expected-note {{previous definition}}
+int var3 = 2; // expected-error {{redefinition of 'var3'}}
+
+int v4;
+int var4; // expected-note {{previous definition}}
+int var4 __attribute((alias("v4"))); // expected-error {{alias definition of 'var4' after tentative definition}}
+
+int v5;
+int var5 __attribute((alias("v5"))); // expected-note {{previous definition}}
+int var5; // expected-error {{tentative definition of 'var5' after alias definition}}
diff --git a/test/Sema/align-x86-64.c b/test/Sema/align-x86-64.c
index 09bf63390f35..b34d85942d0e 100644
--- a/test/Sema/align-x86-64.c
+++ b/test/Sema/align-x86-64.c
@@ -1,16 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
// expected-no-diagnostics
-// PR5599
-
-void frob(void *);
-
-void foo(void) {
- float x[4];
- char y[__alignof__(x) == 16 ? 1 : -1];
- frob(y);
-}
-
// PR5637
typedef __attribute__((aligned(16))) struct {
diff --git a/test/Sema/alloc_size.c b/test/Sema/alloc_size.c
index 84f393204659..053323a9f11b 100644
--- a/test/Sema/alloc_size.c
+++ b/test/Sema/alloc_size.c
@@ -5,9 +5,9 @@ void* my_calloc(unsigned char, short) __attribute__((alloc_size(1,2)));
void* my_realloc(void*, unsigned) __attribute__((alloc_size(2)));
-void* fn1(int) __attribute__((alloc_size("xpto"))); // expected-error{{attribute requires integer constant}}
+void* fn1(int) __attribute__((alloc_size("xpto"))); // expected-error{{'alloc_size' attribute requires parameter 1 to be an integer constant}}
-void* fn2(void*) __attribute__((alloc_size(1))); // expected-error{{attribute requires integer constant}}
+void* fn2(void*) __attribute__((alloc_size(1))); // expected-error{{'alloc_size' attribute requires an integer constant}}
void* fn3(unsigned) __attribute__((alloc_size(0))); // expected-error{{attribute parameter 1 is out of bounds}}
void* fn4(unsigned) __attribute__((alloc_size(2))); // expected-error{{attribute parameter 1 is out of bounds}}
@@ -19,7 +19,7 @@ void* fn7(unsigned) __attribute__((alloc_size)); // expected-error {{attribute t
void *fn8(int, int) __attribute__((alloc_size(1, 1))); // OK
-void* fn9(unsigned) __attribute__((alloc_size(12345678901234567890123))); // expected-warning {{integer constant is too large for its type}} // expected-error {{attribute parameter 1 is out of bounds}}
+void* fn9(unsigned) __attribute__((alloc_size(12345678901234567890123))); // expected-error {{integer constant is larger than the largest unsigned integer type}} // expected-error {{attribute parameter 1 is out of bounds}}
void* fn10(size_t, size_t) __attribute__((alloc_size(1,2))); // expected-error{{redefinition of parameter}} \
// expected-error{{a parameter list without types is only allowed in a function definition}} \
diff --git a/test/Sema/annotate.c b/test/Sema/annotate.c
index ef878d4c9824..4a786d0a0163 100644
--- a/test/Sema/annotate.c
+++ b/test/Sema/annotate.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
-void __attribute__((annotate("foo"))) foo(float *a) {
+void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
- __attribute__((annotate(1))) int y; // expected-error {{argument to annotate attribute was not a string literal}}
- __attribute__((annotate("bar", 1))) int z; // expected-error {{attribute takes one argument}}
+ __attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}}
+ __attribute__((annotate("bar", 1))) int z; // expected-error {{'annotate' attribute takes one argument}}
int u = __builtin_annotation(z, (char*) 0); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}}
int v = __builtin_annotation(z, (char*) L"bar"); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}}
int w = __builtin_annotation(z, "foo");
diff --git a/test/Sema/arm-asm.c b/test/Sema/arm-asm.c
index 3fc0eeb7543a..e48718b0a2ac 100644
--- a/test/Sema/arm-asm.c
+++ b/test/Sema/arm-asm.c
@@ -5,3 +5,8 @@ void f (void) {
asm volatile ("lw (r1), %0[val]": "=&b"(Val)); // expected-error {{invalid output constraint '=&b' in asm}}
return;
}
+
+void test_64bit_r(void) {
+ long long foo = 0, bar = 0;
+ asm volatile("INST %0, %1" : "=r"(foo) : "r"(bar));
+}
diff --git a/test/Sema/arm-darwin-aapcs.cpp b/test/Sema/arm-darwin-aapcs.cpp
new file mode 100644
index 000000000000..1359a1dc15aa
--- /dev/null
+++ b/test/Sema/arm-darwin-aapcs.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple thumbv7-apple-ios -target-abi aapcs -verify -fsyntax-only
+// expected-no-diagnostics
+
+// ARM's AAPCS normally has size_t defined as unsigned int, but on Darwin
+// some embedded targets use AAPCS with the iOS header files, which define
+// size_t as unsigned long. Make sure that works.
+typedef unsigned long size_t;
+void* malloc(size_t);
+void* operator new(size_t size)
+{
+ return (malloc(size));
+}
diff --git a/test/Sema/arm-interrupt-attr.c b/test/Sema/arm-interrupt-attr.c
new file mode 100644
index 000000000000..b2cedc2e4d20
--- /dev/null
+++ b/test/Sema/arm-interrupt-attr.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -triple arm-apple-darwin -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}}
+
+__attribute__((interrupt("IRQ", 1))) void foo2() {} // expected-error {{attribute takes no more than 1 argument}}
+
+__attribute__((interrupt("IRQ"))) void foo3() {}
+__attribute__((interrupt("FIQ"))) void foo4() {}
+__attribute__((interrupt("SWI"))) void foo5() {}
+__attribute__((interrupt("ABORT"))) void foo6() {}
+__attribute__((interrupt("UNDEF"))) void foo7() {}
+
+__attribute__((interrupt)) void foo8() {}
+__attribute__((interrupt())) void foo9() {}
+__attribute__((interrupt(""))) void foo10() {}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index f92852f341b6..ae2c7425662b 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -226,7 +226,8 @@ void emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct is a GN
// expected-error{{initializer for aggregate with no elements}}
void noNamedInit() {
- struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}}
+ struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}} \
+// expected-warning {{struct without named members is a GNU extension}}
}
struct {int a; int:5;} noNamedImplicit[] = {1,2,3};
int noNamedImplicitCheck[sizeof(noNamedImplicit) == 3 * sizeof(*noNamedImplicit) ? 1 : -1];
diff --git a/test/Sema/array-size-64.c b/test/Sema/array-size-64.c
index f22e8e77d215..0e094bfa6bd7 100644
--- a/test/Sema/array-size-64.c
+++ b/test/Sema/array-size-64.c
@@ -2,6 +2,11 @@
void f() {
int a[2147483647U][2147483647U]; // expected-error{{array is too large}}
- int b[1073741825U - 1U][2147483647U];
- int c[18446744073709551615U/sizeof(int)/2];
+ int b[1073741825U - 1U][2147483647U]; // expected-error{{array is too large}}
}
+
+void pr8256 () {
+ typedef char a[1LL<<61]; // expected-error {{array is too large}}
+ typedef char b[(long long)sizeof(a)-1];
+}
+
diff --git a/test/Sema/atomic-expr.c b/test/Sema/atomic-expr.c
index ecc04c4c68d6..5602d545cc7f 100644
--- a/test/Sema/atomic-expr.c
+++ b/test/Sema/atomic-expr.c
@@ -45,3 +45,16 @@ void func_09 (int* xp) {
void func_10 (int* xp) {
*xp <<= data2;
}
+
+int func_11 (int x) {
+ return data1 == x;
+}
+
+int func_12 () {
+ return data1 < data2;
+}
+
+int func_13 (int x, unsigned y) {
+ return x ? data1 : y;
+}
+
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index b3daa0704dc9..c2d38e714bf2 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -86,8 +86,8 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
__c11_atomic_init(I, 5); // expected-error {{pointer to _Atomic}}
__c11_atomic_load(0); // expected-error {{too few arguments to function}}
__c11_atomic_load(0,0,0); // expected-error {{too many arguments to function}}
- __c11_atomic_store(0,0,0); // expected-error {{first argument to atomic builtin must be a pointer}}
- __c11_atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation must be a pointer to _Atomic}}
+ __c11_atomic_store(0,0,0); // expected-error {{address argument to atomic builtin must be a pointer}}
+ __c11_atomic_store((int*)0,0,0); // expected-error {{address argument to atomic operation must be a pointer to _Atomic}}
__c11_atomic_load(i, memory_order_seq_cst);
__c11_atomic_load(p, memory_order_seq_cst);
@@ -169,10 +169,16 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
(int)__atomic_clear(&flag, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
const _Atomic(int) const_atomic;
- __c11_atomic_init(&const_atomic, 0); // expected-error {{first argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
- __c11_atomic_store(&const_atomic, 0, memory_order_release); // expected-error {{first argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
- __c11_atomic_load(&const_atomic, memory_order_acquire); // expected-error {{first argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
+ __c11_atomic_init(&const_atomic, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
+ __c11_atomic_store(&const_atomic, 0, memory_order_release); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
+ __c11_atomic_load(&const_atomic, memory_order_acquire); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
}
_Atomic(int*) PR12527_a;
void PR12527() { int *b = PR12527_a; }
+
+void PR16931(int* x) { // expected-note {{passing argument to parameter 'x' here}}
+ typedef struct { _Atomic(_Bool) flag; } flag;
+ flag flagvar = { 0 };
+ PR16931(&flagvar); // expected-warning {{incompatible pointer types}}
+}
diff --git a/test/Sema/atomic-requires-library-error.c b/test/Sema/atomic-requires-library-error.c
new file mode 100644
index 000000000000..b0aa2783544b
--- /dev/null
+++ b/test/Sema/atomic-requires-library-error.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -verify
+// rdar://13973577
+
+struct foo {
+ int big[128];
+};
+struct bar {
+ char c[3];
+};
+
+struct bar smallThing;
+struct foo bigThing;
+_Atomic(struct foo) bigAtomic;
+
+void structAtomicStore() {
+ struct foo f = {0};
+ __c11_atomic_store(&bigAtomic, f, 5); // expected-error {{atomic store requires runtime support that is not available for this target}}
+
+ struct bar b = {0};
+ __atomic_store(&smallThing, &b, 5);
+
+ __atomic_store(&bigThing, &f, 5);
+}
+
+void structAtomicLoad() {
+ struct foo f = __c11_atomic_load(&bigAtomic, 5); // expected-error {{atomic load requires runtime support that is not available for this target}}
+ struct bar b;
+ __atomic_load(&smallThing, &b, 5);
+
+ __atomic_load(&bigThing, &f, 5);
+}
diff --git a/test/Sema/attr-alias-elf.c b/test/Sema/attr-alias-elf.c
new file mode 100644
index 000000000000..88bd7b70958b
--- /dev/null
+++ b/test/Sema/attr-alias-elf.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -fsyntax-only -verify -emit-llvm-only %s
+
+void f1(void) __attribute__((alias("g1")));
+void g1(void) {
+}
+
+void f2(void) __attribute__((alias("g2"))); // expected-error {{alias must point to a defined variable or function}}
+
+
+void f3(void) __attribute__((alias("g3"))); // expected-error {{alias must point to a defined variable or function}}
+void g3(void);
+
+
+void f4() __attribute__((alias("g4")));
+void g4() {}
+void h4() __attribute__((alias("f4")));
+
+void f5() __attribute__((alias("g5")));
+void h5() __attribute__((alias("f5")));
+void g5() {}
+
+void g6() {}
+void f6() __attribute__((alias("g6")));
+void h6() __attribute__((alias("f6")));
+
+void g7() {}
+void h7() __attribute__((alias("f7")));
+void f7() __attribute__((alias("g7")));
+
+void h8() __attribute__((alias("f8")));
+void g8() {}
+void f8() __attribute__((alias("g8")));
+
+void h9() __attribute__((alias("f9")));
+void f9() __attribute__((alias("g9")));
+void g9() {}
+
+void f10() __attribute__((alias("g10"))); // expected-error {{alias definition is part of a cycle}}
+void g10() __attribute__((alias("f10"))); // expected-error {{alias definition is part of a cycle}}
+
+// FIXME: This could be a bit better, h10 is not part of the cycle, it points
+// to it.
+void h10() __attribute__((alias("g10"))); // expected-error {{alias definition is part of a cycle}}
+
+extern int a1 __attribute__((alias("b1")));
+int b1 = 42;
+
+extern int a2 __attribute__((alias("b2"))); // expected-error {{alias must point to a defined variable or function}}
+
+extern int a3 __attribute__((alias("b3"))); // expected-error {{alias must point to a defined variable or function}}
+extern int b3;
+
+extern int a4 __attribute__((alias("b4"))); // expected-error {{alias must point to a defined variable or function}}
+typedef int b4;
diff --git a/test/Sema/attr-args.c b/test/Sema/attr-args.c
index 61358016fbe1..1981de522995 100644
--- a/test/Sema/attr-args.c
+++ b/test/Sema/attr-args.c
@@ -1,40 +1,14 @@
-// RUN: %clang_cc1 -DATTR=noreturn -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=always_inline -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=cdecl -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=const -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=fastcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=malloc -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=nothrow -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=stdcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=used -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=unused -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=weak -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-
-#define ATTR_DECL(a) __attribute__((ATTR(a)))
-
-int a;
-
-inline ATTR_DECL(a) void* foo(); // expected-error{{attribute takes no arguments}}
-
-
-
-// RUN: %clang_cc1 -DATTR=noreturn -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=always_inline -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=cdecl -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=const -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=fastcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=malloc -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=nothrow -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=stdcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=used -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=unused -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-// RUN: %clang_cc1 -DATTR=weak -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
-
-#define ATTR_DECL(a) __attribute__((ATTR(a)))
-
+// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only %s
int a;
-inline ATTR_DECL(a) void* foo(); // expected-error{{attribute takes no arguments}}
-
-
-
+inline __attribute__((noreturn(a))) void *f1(); // expected-error {{'noreturn' attribute takes no arguments}}
+inline __attribute__((always_inline(a))) void *f2(); // expected-error {{'always_inline' attribute takes no arguments}}
+inline __attribute__((cdecl(a))) void *f3(); // expected-error {{'cdecl' attribute takes no arguments}}
+inline __attribute__((const(a))) void *f4(); // expected-error {{'const' attribute takes no arguments}}
+inline __attribute__((fastcall(a))) void *f5(); // expected-error {{'fastcall' attribute takes no arguments}}
+inline __attribute__((malloc(a))) void *f5(); // expected-error {{'malloc' attribute takes no arguments}}
+inline __attribute__((nothrow(a))) void *f7(); // expected-error {{'nothrow' attribute takes no arguments}}
+inline __attribute__((stdcall(a))) void *f8(); // expected-error {{'stdcall' attribute takes no arguments}}
+inline __attribute__((used(a))) void *f9(); // expected-error {{'used' attribute takes no arguments}}
+inline __attribute__((unused(a))) void *f10(); // expected-error {{'unused' attribute takes no arguments}}
+inline __attribute__((weak(a))) void *f11(); // expected-error {{'weak' attribute takes no arguments}}
diff --git a/test/Sema/attr-bounded.c b/test/Sema/attr-bounded.c
new file mode 100644
index 000000000000..bf71fedf2d3f
--- /dev/null
+++ b/test/Sema/attr-bounded.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+// Make sure OpenBSD's bounded extension is accepted.
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+typedef struct FILE FILE;
+
+ssize_t read(int, void *, size_t)
+ __attribute__((__bounded__(__buffer__,2,3)));
+int readlink(const char *, char *, size_t)
+ __attribute__((__bounded__(__string__,2,3)));
+size_t fread(void *, size_t, size_t, FILE *)
+ __attribute__((__bounded__(__size__,1,3,2)));
+char *getwd(char *)
+ __attribute__((__bounded__(__minbytes__,1,1024))); \ No newline at end of file
diff --git a/test/Sema/attr-cleanup.c b/test/Sema/attr-cleanup.c
index 991822e402e0..f5cbc385c689 100644
--- a/test/Sema/attr-cleanup.c
+++ b/test/Sema/attr-cleanup.c
@@ -2,18 +2,18 @@
void c1(int *a);
-extern int g1 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
-int g2 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
-static int g3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
+extern int g1 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}}
+int g2 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}}
+static int g3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}}
void t1()
{
- int v1 __attribute((cleanup)); // expected-error {{attribute takes one argument}}
- int v2 __attribute((cleanup(1, 2))); // expected-error {{attribute takes one argument}}
-
- static int v3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
-
- int v4 __attribute((cleanup(h))); // expected-error {{'cleanup' argument 'h' not found}}
+ int v1 __attribute((cleanup)); // expected-error {{'cleanup' attribute takes one argument}}
+ int v2 __attribute((cleanup(1, 2))); // expected-error {{'cleanup' attribute takes one argument}}
+
+ static int v3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}}
+
+ int v4 __attribute((cleanup(h))); // expected-error {{use of undeclared identifier 'h'}}
int v5 __attribute((cleanup(c1)));
int v6 __attribute((cleanup(v3))); // expected-error {{'cleanup' argument 'v3' is not a function}}
@@ -42,3 +42,7 @@ void c5(void*) __attribute__((deprecated)); // expected-note{{'c5' declared her
void t5() {
int i __attribute__((cleanup(c5))); // expected-warning {{'c5' is deprecated}}
}
+
+void t6(void) {
+ int i __attribute__((cleanup((void *)0))); // expected-error {{'cleanup' argument is not a function}}
+}
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index 565be7ff5997..8124ab0ddd02 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -120,3 +120,7 @@ struct test22 {
foo_dep c, d __attribute((deprecated)); // expected-warning {{'foo_dep' is deprecated}}
__attribute((deprecated)) foo_dep e, f;
};
+
+typedef int test23_ty __attribute((deprecated)); // expected-note {{previous definition is here}}
+typedef int test23_ty; // expected-note {{'test23_ty' declared here}} expected-warning {{redefinition of typedef 'test23_ty' is a C11 feature}}
+test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}}
diff --git a/test/Sema/attr-endian.c b/test/Sema/attr-endian.c
new file mode 100644
index 000000000000..db24dafd4213
--- /dev/null
+++ b/test/Sema/attr-endian.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+int p1 __attribute__((endian(host))); // expected-warning {{unknown attribute 'endian' ignored}}
diff --git a/test/Sema/attr-format.c b/test/Sema/attr-format.c
index a223e08f5a48..21d9585a57e9 100644
--- a/test/Sema/attr-format.c
+++ b/test/Sema/attr-format.c
@@ -78,3 +78,5 @@ extern void gcc_cxxformat (const char *, ...)
__attribute__ ((__format__(__gcc_cxxdiag__, 1, 2)));
extern void gcc_tformat (const char *, ...)
__attribute__ ((__format__(__gcc_tdiag__, 1, 2)));
+
+const char *foo3(const char *format) __attribute__((format_arg("foo"))); // expected-error{{'format_arg' attribute requires parameter 1 to be an integer constant}}
diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c
index a89c8397e0a0..49e41d210d03 100644
--- a/test/Sema/attr-mode.c
+++ b/test/Sema/attr-mode.c
@@ -2,6 +2,8 @@
// RUN: -verify %s
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -DTEST_64BIT_X86 -fsyntax-only \
// RUN: -verify %s
+// RUN: %clang_cc1 -triple powerpc64-pc-linux-gnu -DTEST_64BIT_PPC64 -fsyntax-only \
+// RUN: -verify %s
typedef int i16_1 __attribute((mode(HI)));
int i16_1_test[sizeof(i16_1) == 2 ? 1 : -1];
@@ -11,11 +13,12 @@ int i16_2_test[sizeof(i16_1) == 2 ? 1 : -1];
typedef float f64 __attribute((mode(DF)));
int f64_test[sizeof(f64) == 8 ? 1 : -1];
-typedef int invalid_1 __attribute((mode)); // expected-error{{attribute requires unquoted parameter}}
-typedef int invalid_2 __attribute((mode())); // expected-error{{attribute requires unquoted parameter}}
+typedef int invalid_1 __attribute((mode)); // expected-error{{'mode' attribute takes one argument}}
+typedef int invalid_2 __attribute((mode())); // expected-error{{'mode' attribute takes one argument}}
typedef int invalid_3 __attribute((mode(II))); // expected-error{{unknown machine mode}}
typedef struct {int i,j,k;} invalid_4 __attribute((mode(SI))); // expected-error{{mode attribute only supported for integer and floating-point types}}
typedef float invalid_5 __attribute((mode(SI))); // expected-error{{type of machine mode does not match type of base type}}
+typedef int invalid_6 __attribute__((mode(12))); // expected-error{{'mode' attribute requires an identifier}}
typedef unsigned unwind_word __attribute((mode(unwind_word)));
@@ -24,7 +27,10 @@ int **__attribute((mode(QI)))* i32; // expected-error{{mode attribute}}
typedef _Complex double c32 __attribute((mode(SC)));
int c32_test[sizeof(c32) == 8 ? 1 : -1];
typedef _Complex float c64 __attribute((mode(DC)));
+
+#ifndef TEST_64BIT_PPC64 // Note, 'XC' mode is illegal for PPC64 machines.
typedef _Complex float c80 __attribute((mode(XC)));
+#endif
// PR6108: Correctly select 'long' built in type on 64-bit platforms for 64 bit
// modes. Also test other mode-based conversions.
@@ -56,6 +62,14 @@ void test_long_to_ui64(unsigned long long* y) { f_ui64_arg(y); }
#elif TEST_64BIT_X86
void test_long_to_i64(long* y) { f_i64_arg(y); }
void test_long_to_ui64(unsigned long* y) { f_ui64_arg(y); }
+typedef float f128ibm __attribute__ ((mode (TF))); // expected-error{{unsupported machine mode 'TF'}}
+#elif TEST_64BIT_PPC64
+typedef float f128ibm __attribute__ ((mode (TF)));
+typedef _Complex float c128ibm __attribute__ ((mode (TC)));
+void f_ft128_arg(long double *x);
+void f_ft128_complex_arg(_Complex long double *x);
+void test_TFtype(f128ibm *a) { f_ft128_arg (a); }
+void test_TCtype(c128ibm *a) { f_ft128_complex_arg (a); }
#else
#error Unknown test architecture.
#endif
diff --git a/test/Sema/attr-naked.c b/test/Sema/attr-naked.c
index d9fa5423d9ef..55c6b326ef15 100644
--- a/test/Sema/attr-naked.c
+++ b/test/Sema/attr-naked.c
@@ -2,11 +2,11 @@
int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}}
-__attribute__((naked)) int t0(void) {
+__attribute__((naked)) int t0(void) {
__asm__ volatile("mov r0, #0");
}
void t1() __attribute__((naked));
-void t2() __attribute__((naked(2))); // expected-error {{attribute takes no arguments}}
+void t2() __attribute__((naked(2))); // expected-error {{'naked' attribute takes no arguments}}
diff --git a/test/Sema/attr-nodebug.c b/test/Sema/attr-nodebug.c
index 3cc4088e4b3c..03ec49b850d6 100644
--- a/test/Sema/attr-nodebug.c
+++ b/test/Sema/attr-nodebug.c
@@ -4,8 +4,8 @@ int a __attribute__((nodebug));
void b() {
int b __attribute__((nodebug)); // expected-warning {{'nodebug' only applies to variables with static storage duration and functions}}
-}
+}
void t1() __attribute__((nodebug));
-void t2() __attribute__((nodebug(2))); // expected-error {{attribute takes no arguments}}
+void t2() __attribute__((nodebug(2))); // expected-error {{'nodebug' attribute takes no arguments}}
diff --git a/test/Sema/attr-noinline.c b/test/Sema/attr-noinline.c
index dfc88a8d8fcb..cadf9d6c186a 100644
--- a/test/Sema/attr-noinline.c
+++ b/test/Sema/attr-noinline.c
@@ -4,5 +4,5 @@ int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only
void t1() __attribute__((noinline));
-void t2() __attribute__((noinline(2))); // expected-error {{attribute takes no arguments}}
+void t2() __attribute__((noinline(2))); // expected-error {{'noinline' attribute takes no arguments}}
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index 5c643fff718d..dab571064a22 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -13,7 +13,7 @@ int f1() __attribute__((noreturn));
int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' only applies to function types; type here is 'int'}}
-int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute takes no arguments}}
+int f2() __attribute__((noreturn(1, 2))); // expected-error {{'noreturn' attribute takes no arguments}}
void f3() __attribute__((noreturn));
void f3() {
@@ -33,7 +33,7 @@ extern void f5 (unsigned long) __attribute__ ((__noreturn__));
void
f5 (unsigned long size)
{
-
+
}
// PR2461
@@ -41,4 +41,4 @@ __attribute__((noreturn)) void f(__attribute__((noreturn)) void (*x)(void)) {
x();
}
-typedef void (*Fun)(void) __attribute__ ((noreturn(2))); // expected-error {{attribute takes no arguments}}
+typedef void (*Fun)(void) __attribute__ ((noreturn(2))); // expected-error {{'noreturn' attribute takes no arguments}}
diff --git a/test/Sema/attr-ownership.c b/test/Sema/attr-ownership.c
new file mode 100644
index 000000000000..e31b429ef6ed
--- /dev/null
+++ b/test/Sema/attr-ownership.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -verify
+
+void f1(void) __attribute__((ownership_takes("foo"))); // expected-error {{'ownership_takes' attribute requires parameter 1 to be an identifier}}
+void *f2(void) __attribute__((ownership_returns(foo, 1, 2))); // expected-error {{attribute takes no more than 1 argument}}
+void f3(void) __attribute__((ownership_holds(foo, 1))); // expected-error {{'ownership_holds' attribute parameter 1 is out of bounds}}
+void *f4(void) __attribute__((ownership_returns(foo)));
+void f5(void) __attribute__((ownership_holds(foo))); // expected-error {{attribute takes at least 2 arguments}}
+void f6(void) __attribute__((ownership_holds(foo, 1, 2, 3))); // expected-error {{'ownership_holds' attribute parameter 1 is out of bounds}}
+void f7(void) __attribute__((ownership_takes(foo))); // expected-error {{attribute takes at least 2 arguments}}
+void f8(int *i, int *j, int k) __attribute__((ownership_holds(foo, 1, 2, 4))); // expected-error {{'ownership_holds' attribute parameter 3 is out of bounds}}
+
+int f9 __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to functions}}
+
+void f10(int i) __attribute__((ownership_holds(foo, 1))); // expected-error {{'ownership_holds' attribute only applies to pointer arguments}}
+void *f11(float i) __attribute__((ownership_returns(foo, 1))); // expected-error {{'ownership_returns' attribute only applies to integer arguments}}
+void *f12(float i, int k, int f, int *j) __attribute__((ownership_returns(foo, 4))); // expected-error {{'ownership_returns' attribute only applies to integer arguments}}
+
+void f13(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_takes(foo, 2)));
+void f14(int i, int j, int *k) __attribute__((ownership_holds(foo, 3))) __attribute__((ownership_takes(foo, 3))); // expected-error {{'ownership_holds' and 'ownership_takes' attributes are not compatible}}
diff --git a/test/Sema/attr-print.c b/test/Sema/attr-print.c
index 2659508e5625..b3bdfd72e645 100644
--- a/test/Sema/attr-print.c
+++ b/test/Sema/attr-print.c
@@ -13,9 +13,22 @@ void foo() __attribute__((const));
// CHECK: void bar() __attribute__((__const));
void bar() __attribute__((__const));
-// FIXME: Print these at a valid location for these attributes.
-// CHECK: int *p32 __ptr32;
+// CHECK: int * __ptr32 p32;
int * __ptr32 p32;
-// CHECK: int *p64 __ptr64;
+// CHECK: int * __ptr64 p64;
int * __ptr64 p64;
+
+// TODO: the Type Printer has no way to specify the order to print attributes
+// in, and so it currently always prints them in reverse order. Fix this.
+// CHECK: int * __ptr32 __uptr p32_2;
+int * __uptr __ptr32 p32_2;
+
+// CHECK: int * __ptr64 __sptr p64_2;
+int * __sptr __ptr64 p64_2;
+
+// CHECK: int * __ptr32 __uptr p32_3;
+int * __uptr __ptr32 p32_3;
+
+// CHECK: int * __sptr * __ptr32 ppsp32;
+int * __sptr * __ptr32 ppsp32;
diff --git a/test/Sema/attr-regparm.c b/test/Sema/attr-regparm.c
index ccd894e606d5..d50dd113f70f 100644
--- a/test/Sema/attr-regparm.c
+++ b/test/Sema/attr-regparm.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
__attribute((regparm(2))) int x0(void);
-__attribute((regparm(1.0))) int x1(void); // expected-error{{'regparm' attribute requires integer constant}}
+__attribute((regparm(1.0))) int x1(void); // expected-error{{'regparm' attribute requires an integer constant}}
__attribute((regparm(-1))) int x2(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
__attribute((regparm(5))) int x3(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
-__attribute((regparm(5,3))) int x4(void); // expected-error{{attribute takes one argument}}
+__attribute((regparm(5,3))) int x4(void); // expected-error{{'regparm' attribute takes one argument}}
void __attribute__((regparm(3))) x5(int);
void x5(int); // expected-note{{previous declaration is here}}
diff --git a/test/Sema/attr-returns-twice.c b/test/Sema/attr-returns-twice.c
index 13f53e36de79..aa32b243b106 100644
--- a/test/Sema/attr-returns-twice.c
+++ b/test/Sema/attr-returns-twice.c
@@ -7,6 +7,6 @@ __attribute__((returns_twice)) void t0(void) {
void t1() __attribute__((returns_twice));
-void t2() __attribute__((returns_twice(2))); // expected-error {{attribute takes no arguments}}
+void t2() __attribute__((returns_twice(2))); // expected-error {{'returns_twice' attribute takes no arguments}}
typedef void (*t3)(void) __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}
diff --git a/test/Sema/attr-section.c b/test/Sema/attr-section.c
index 69ca732517af..396892a1c5e9 100644
--- a/test/Sema/attr-section.c
+++ b/test/Sema/attr-section.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-apple-darwin9 %s
int x __attribute__((section(
- 42))); // expected-error {{argument to section attribute was not a string literal}}
+ 42))); // expected-error {{'section' attribute requires a string}}
// rdar://4341926
diff --git a/test/Sema/attr-tls_model.c b/test/Sema/attr-tls_model.c
index e184ebc82af0..c4f92f1f80de 100644
--- a/test/Sema/attr-tls_model.c
+++ b/test/Sema/attr-tls_model.c
@@ -9,6 +9,6 @@ int f() __attribute((tls_model("global-dynamic"))); // expected-error {{'tls_mod
int x __attribute((tls_model("global-dynamic"))); // expected-error {{'tls_model' attribute only applies to thread-local variables}}
static __thread int y __attribute((tls_model("global-dynamic"))); // no-warning
-static __thread int y __attribute((tls_model("local", "dynamic"))); // expected-error {{attribute takes one argument}}
-static __thread int y __attribute((tls_model(123))); // expected-error {{argument to tls_model attribute was not a string literal}}
+static __thread int y __attribute((tls_model("local", "dynamic"))); // expected-error {{'tls_model' attribute takes one argument}}
+static __thread int y __attribute((tls_model(123))); // expected-error {{'tls_model' attribute requires a string}}
static __thread int y __attribute((tls_model("foobar"))); // expected-error {{tls_model must be "global-dynamic", "local-dynamic", "initial-exec" or "local-exec"}}
diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c
index 97104960e5e4..ebdf945867fe 100644
--- a/test/Sema/attr-unavailable-message.c
+++ b/test/Sema/attr-unavailable-message.c
@@ -6,6 +6,11 @@ double dfoo(double) __attribute__((__unavailable__("NO LONGER"))); // expected-
void bar() __attribute__((__unavailable__)); // expected-note {{explicitly marked unavailable}}
+int quux(void) __attribute__((__unavailable__(12))); // expected-error {{'__unavailable__' attribute requires a string}}
+
+#define ACCEPTABLE "Use something else"
+int quux2(void) __attribute__((__unavailable__(ACCEPTABLE)));
+
void test_foo() {
int ir = foo(1); // expected-error {{'foo' is unavailable: USE IFOO INSTEAD}}
double dr = dfoo(1.0); // expected-error {{'dfoo' is unavailable: NO LONGER}}
@@ -32,13 +37,13 @@ enum foo {
a = 1, // expected-note {{declared here}}
b __attribute__((deprecated())) = 2, // expected-note {{declared here}}
c = 3
-}__attribute__((deprecated()));
+}__attribute__((deprecated()));
enum fee { // expected-note {{declaration has been explicitly marked unavailable here}}
r = 1, // expected-note {{declaration has been explicitly marked unavailable here}}
s = 2,
t = 3
-}__attribute__((unavailable()));
+}__attribute__((unavailable()));
enum fee f() { // expected-error {{'fee' is unavailable}}
int i = a; // expected-warning {{'a' is deprecated}}
diff --git a/test/Sema/attr-unused.c b/test/Sema/attr-unused.c
index 07c65cbd9aed..c0c7b9b97adb 100644
--- a/test/Sema/attr-unused.c
+++ b/test/Sema/attr-unused.c
@@ -9,7 +9,7 @@ int f1() __attribute__((unused));
int g0 __attribute__((unused));
-int f2() __attribute__((unused(1, 2))); // expected-error {{attribute takes no arguments}}
+int f2() __attribute__((unused(1, 2))); // expected-error {{'unused' attribute takes no arguments}}
struct Test0_unused {} __attribute__((unused));
struct Test0_not_unused {};
diff --git a/test/Sema/attr-visibility.c b/test/Sema/attr-visibility.c
index 7f7fd546f095..ed52ec2743f9 100644
--- a/test/Sema/attr-visibility.c
+++ b/test/Sema/attr-visibility.c
@@ -24,3 +24,5 @@ extern int test7 __attribute__((visibility("hidden"))); // expected-error {{visi
typedef int __attribute__((visibility("default"))) bar; // expected-warning {{'visibility' attribute ignored}}
int x __attribute__((type_visibility("default"))); // expected-error {{'type_visibility' attribute only applies to types and namespaces}}
+
+int PR17105 __attribute__((visibility(hidden))); // expected-error {{'visibility' attribute requires a string}}
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
index 5ee383eebb02..c6beead3915b 100644
--- a/test/Sema/block-args.c
+++ b/test/Sema/block-args.c
@@ -45,3 +45,14 @@ void test5_helper(void (^)(int, int[*]));
void test5(void) {
test5_helper(^(int n, int array[n]) {});
}
+
+// Reduced from a problem on platforms where va_list is an array.
+struct tag {
+ int x;
+};
+typedef struct tag array_ty[1];
+void test6(void) {
+ void (^block)(array_ty) = ^(array_ty arr) { };
+ array_ty arr;
+ block(arr);
+}
diff --git a/test/Sema/builtin-clear_cache.c b/test/Sema/builtin-clear_cache.c
new file mode 100644
index 000000000000..e21aad79d12a
--- /dev/null
+++ b/test/Sema/builtin-clear_cache.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple armv7-none-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+void __clear_cache(void *a, void *b) {}
diff --git a/test/Sema/builtins-aarch64.c b/test/Sema/builtins-aarch64.c
index 03e03343eb94..b0557532fab6 100644
--- a/test/Sema/builtins-aarch64.c
+++ b/test/Sema/builtins-aarch64.c
@@ -1,4 +1,9 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -DTEST1 -fsyntax-only -verify %s
+
+#ifdef TEST1
+void __clear_cache(void *start, void *end);
+#endif
void test_clear_cache_chars(char *start, char *end) {
__clear_cache(start, end);
diff --git a/test/Sema/builtins-arm-exclusive.c b/test/Sema/builtins-arm-exclusive.c
new file mode 100644
index 000000000000..8c784031142b
--- /dev/null
+++ b/test/Sema/builtins-arm-exclusive.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s
+
+struct Simple {
+ char a, b;
+};
+
+int test_ldrex(char *addr) {
+ int sum = 0;
+ sum += __builtin_arm_ldrex(addr);
+ sum += __builtin_arm_ldrex((short *)addr);
+ sum += __builtin_arm_ldrex((int *)addr);
+ sum += __builtin_arm_ldrex((long long *)addr);
+ sum += __builtin_arm_ldrex((float *)addr);
+ sum += __builtin_arm_ldrex((double *)addr);
+ sum += *__builtin_arm_ldrex((int **)addr);
+ sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
+ sum += __builtin_arm_ldrex((volatile char *)addr);
+ sum += __builtin_arm_ldrex((const volatile char *)addr);
+
+ // In principle this might be valid, but stick to ints and floats for scalar
+ // types at the moment.
+ sum += __builtin_arm_ldrex((struct Simple *)addr).a; // expected-error {{address argument to atomic builtin must be a pointer to}}
+
+ sum += __builtin_arm_ldrex((__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2,4 or 8 byte type}}
+
+ __builtin_arm_ldrex(); // expected-error {{too few arguments to function call}}
+ __builtin_arm_ldrex(1, 2); // expected-error {{too many arguments to function call}}
+ return sum;
+}
+
+int test_strex(char *addr) {
+ int res = 0;
+ struct Simple var = {0};
+ res |= __builtin_arm_strex(4, addr);
+ res |= __builtin_arm_strex(42, (short *)addr);
+ res |= __builtin_arm_strex(42, (int *)addr);
+ res |= __builtin_arm_strex(42, (long long *)addr);
+ res |= __builtin_arm_strex(2.71828f, (float *)addr);
+ res |= __builtin_arm_strex(3.14159, (double *)addr);
+ res |= __builtin_arm_strex(&var, (struct Simple **)addr);
+
+ res |= __builtin_arm_strex(42, (volatile char *)addr);
+ res |= __builtin_arm_strex(42, (char *const)addr);
+ res |= __builtin_arm_strex(42, (const char *)addr); // expected-warning {{passing 'const char *' to parameter of type 'volatile char *' discards qualifiers}}
+
+
+ res |= __builtin_arm_strex(var, (struct Simple *)addr); // expected-error {{address argument to atomic builtin must be a pointer to}}
+ res |= __builtin_arm_strex(var, (struct Simple **)addr); // expected-error {{passing 'struct Simple' to parameter of incompatible type 'struct Simple *'}}
+ res |= __builtin_arm_strex(&var, (struct Simple **)addr).a; // expected-error {{is not a structure or union}}
+
+ res |= __builtin_arm_strex(1, (__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2,4 or 8 byte type}}
+
+ __builtin_arm_strex(1); // expected-error {{too few arguments to function call}}
+ __builtin_arm_strex(1, 2, 3); // expected-error {{too many arguments to function call}}
+ return res;
+}
+
+void test_clrex() {
+ __builtin_arm_clrex();
+ __builtin_arm_clrex(1); // expected-error {{too many arguments to function call}}
+}
diff --git a/test/Sema/builtins-arm-strex-rettype.c b/test/Sema/builtins-arm-strex-rettype.c
new file mode 100644
index 000000000000..4ee96ce3277e
--- /dev/null
+++ b/test/Sema/builtins-arm-strex-rettype.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple thumbv7m-apple-darwin-eabi -ast-dump %s | FileCheck %s
+
+// CHECK: CallExpr {{.*}} 'int'
+
+void foo(int a, int *b) {
+ do {
+ } while (__builtin_arm_strex(a, b));
+}
diff --git a/test/Sema/builtins-arm.c b/test/Sema/builtins-arm.c
index 7b48af155ee8..3ac1da0aa93d 100644
--- a/test/Sema/builtins-arm.c
+++ b/test/Sema/builtins-arm.c
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify -DTEST0 %s
-// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify -DTEST1 %s
+// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple armv7 -target-abi apcs-gnu \
-// RUN: -fsyntax-only -verify -DTEST1 %s
+// RUN: -fsyntax-only -verify %s
-#ifdef TEST0
-void __clear_cache(char*, char*);
-#endif
+void f(void *a, void *b) {
+ __clear_cache(); // expected-error {{too few arguments to function call, expected 2, have 0}} // expected-note {{'__clear_cache' is a builtin with type 'void (void *, void *)}}
+ __clear_cache(a); // expected-error {{too few arguments to function call, expected 2, have 1}}
+ __clear_cache(a, b);
+}
-#ifdef TEST1
+void __clear_cache(char*, char*); // expected-error {{conflicting types for '__clear_cache'}}
void __clear_cache(void*, void*);
-#endif
#if defined(__ARM_PCS) || defined(__ARM_EABI__)
// va_list on ARM AAPCS is struct { void* __ap }.
diff --git a/test/Sema/builtins-gnu-mode.c b/test/Sema/builtins-gnu-mode.c
new file mode 100644
index 000000000000..718803eabe2a
--- /dev/null
+++ b/test/Sema/builtins-gnu-mode.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c99 %s
+// PR16138
+// expected-no-diagnostics
+
+int alloca;
+int stpcpy;
+int stpncpy;
+int strdup;
+int strndup;
+int index;
+int rindex;
+int bzero;
+int strcasecmp;
+int strncasecmp;
+int _exit;
+int vfork;
+int _setjmp;
+int __sigsetjmp;
+int sigsetjmp;
+int setjmp_syscall;
+int savectx;
+int qsetjmp;
+int getcontext;
+int _longjmp;
+int siglongjmp;
+int strlcpy;
+int strlcat;
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index d525ac012e11..8ca33c8e7527 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -2,7 +2,7 @@
// This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
int test1(float a, int b) {
- return __builtin_isless(a, b);
+ return __builtin_isless(a, b); // expected-note {{declared here}}
}
int test2(int a, int b) {
return __builtin_islessequal(a, b); // expected-error {{floating point type}}
@@ -191,3 +191,9 @@ void test18() {
ptr = __builtin___strlcpy_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
ptr = __builtin___strlcat_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
}
+
+void no_ms_builtins() {
+ __assume(1); // expected-warning {{implicit declaration}}
+ __noop(1); // expected-warning {{implicit declaration}}
+ __debugbreak(); // expected-warning {{implicit declaration}}
+}
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index a410a626edac..b746d383f306 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -90,7 +90,7 @@ void test16() {
printg("Hello, world!\n"); /* expected-warning {{implicit declaration of function 'printg'}} */
}
-struct x { int x,y[]; }; /* expected-warning {{Flexible array members are a C99-specific feature}} */
+struct x { int x,y[]; }; /* expected-warning {{flexible array members are a C99 feature}} */
/* Duplicated type-qualifiers aren't allowed by C90 */
const const int c_i; /* expected-warning {{duplicate 'const' declaration specifier}} */
@@ -116,3 +116,12 @@ long long ll1 = /* expected-warning {{'long long' is an extension when C99 mode
unsigned long long ull1 = /* expected-warning {{'long long' is an extension when C99 mode is not enabled}} */
42ULL; /* expected-warning {{'long long' is an extension when C99 mode is not enabled}} */
+struct Test17 { int a; };
+struct Test17 test17_aux(void);
+
+void test17(int v, int w) {
+ int a[2] = { v, w }; /* expected-warning {{initializer for aggregate is not a compile-time constant}} */
+ struct Test17 t0 = { v }; /* expected-warning {{initializer for aggregate is not a compile-time constant}} */
+ struct Test17 t1 = test17_aux(); /* this is allowed */
+}
+
diff --git a/test/Sema/callingconv-ms_abi.c b/test/Sema/callingconv-ms_abi.c
new file mode 100644
index 000000000000..64c5970adf1d
--- /dev/null
+++ b/test/Sema/callingconv-ms_abi.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-win32 %s
+
+void __attribute__((ms_abi)) foo(void);
+void (*pfoo)(void) = foo;
+
+void __attribute__((sysv_abi)) bar(void);
+void (*pbar)(void) = bar; // expected-warning{{incompatible pointer types}}
+
+void (__attribute__((sysv_abi)) *pfoo2)(void) = foo; // expected-warning{{incompatible pointer types}}
diff --git a/test/Sema/callingconv-sysv_abi.c b/test/Sema/callingconv-sysv_abi.c
new file mode 100644
index 000000000000..015357d054f7
--- /dev/null
+++ b/test/Sema/callingconv-sysv_abi.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
+
+void __attribute__((ms_abi)) foo(void);
+void (*pfoo)(void) = foo; // expected-warning{{incompatible pointer types}}
+
+void __attribute__((sysv_abi)) bar(void);
+void (*pbar)(void) = bar;
+
+void (__attribute__((ms_abi)) *pbar2)(void) = bar; // expected-warning{{incompatible pointer types}}
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index e487020c4c53..500c0fbfb275 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 %s -fsyntax-only -triple i386-unknown-unknown -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple i386-unknown-unknown -fms-compatibility -DWIN -verify
-void __attribute__((fastcall)) foo(float *a) {
+void __attribute__((fastcall)) foo(float *a) {
}
-void __attribute__((stdcall)) bar(float *a) {
+void __attribute__((stdcall)) bar(float *a) {
}
-void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute takes no arguments}}
+void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{'fastcall' attribute takes no arguments}}
}
void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use fastcall calling convention}}
@@ -15,12 +16,16 @@ void __attribute__((fastcall)) test0() { // expected-error {{function with no pr
void __attribute__((fastcall)) test1(void) {
}
-void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use fastcall calling convention}}
+void __attribute__((fastcall)) test2(int a, ...) { // expected-warning {{fastcall calling convention ignored on variadic function}}
+}
+void __attribute__((stdcall)) test3(int a, ...) { // expected-warning {{stdcall calling convention ignored on variadic function}}
+}
+void __attribute__((thiscall)) test4(int a, ...) { // expected-error {{variadic function cannot use thiscall calling convention}}
}
void __attribute__((cdecl)) ctest0() {}
-void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{attribute takes no arguments}}
+void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{'cdecl' attribute takes no arguments}}
void (__attribute__((fastcall)) *pfoo)(float*) = foo;
@@ -36,10 +41,11 @@ void (__attribute__((cdecl)) *pctest2)() = ctest2;
typedef void (__attribute__((fastcall)) *Handler) (float *);
Handler H = foo;
-int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{attribute takes one argument}}
-int __attribute__((pcs())) pcs2(void); // expected-error {{attribute takes one argument}}
-int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{attribute takes one argument}}
-int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires parameter 1 to be a string}}
+int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{'pcs' attribute takes one argument}}
+int __attribute__((pcs())) pcs2(void); // expected-error {{'pcs' attribute takes one argument}}
+int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{'pcs' attribute requires a string}} \
+ // expected-error {{invalid PCS type}}
+int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires a string}}
/* These are ignored because the target is i386 and not ARM */
int __attribute__((pcs("aapcs"))) pcs5(void); // expected-warning {{calling convention 'pcs' ignored for this target}}
int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // expected-warning {{calling convention 'pcs' ignored for this target}}
@@ -56,3 +62,7 @@ PROC __attribute__((cdecl)) ctest4(const char *x) {}
void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {}
+
+typedef void typedef_fun_t(int);
+typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}}
+void __attribute__((stdcall)) typedef_fun(int x) { } // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
diff --git a/test/Sema/captured-statements.c b/test/Sema/captured-statements.c
index 9285a7802d50..86e9273944bf 100644
--- a/test/Sema/captured-statements.c
+++ b/test/Sema/captured-statements.c
@@ -49,29 +49,29 @@ void test_nest() {
}
void test_nest_block() {
- __block int x;
+ __block int x; // expected-note {{'x' declared here}}
int y;
^{
int z;
#pragma clang __debug captured
{
- x = y; // OK
+ x = y; // expected-error{{__block variable 'x' cannot be captured in a captured statement}}
y = z; // expected-error{{variable is not assignable (missing __block type specifier)}}
z = y; // OK
}
}();
- __block int a;
+ __block int a; // expected-note 2 {{'a' declared here}}
int b;
#pragma clang __debug captured
{
__block int c;
int d;
^{
- a = b; // OK
- a = c; // OK
+ a = b; // expected-error{{__block variable 'a' cannot be captured in a captured statement}}
b = d; // OK - Consistent with block inside a lambda
- c = a; // OK
+ c = a; // expected-error{{__block variable 'a' cannot be captured in a captured statement}}
+ c = d; // OK
d = b; // expected-error{{variable is not assignable (missing __block type specifier)}}
}();
}
diff --git a/test/Sema/carbon.c b/test/Sema/carbon.c
index 045d72c86aed..0498116dd181 100644
--- a/test/Sema/carbon.c
+++ b/test/Sema/carbon.c
@@ -1,5 +1,4 @@
-// RUN: %clang -fsyntax-only %s -print-stats
+// RUN: %clang -fsyntax-only %s
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
-
diff --git a/test/Sema/cast.c b/test/Sema/cast.c
index 25ef1d03a4fe..7971163c12d0 100644
--- a/test/Sema/cast.c
+++ b/test/Sema/cast.c
@@ -54,6 +54,14 @@ void testInt(Int v) {
(void) (CDouble) v;
(void) (VoidPtr) v; // expected-warning{{cast to 'VoidPtr' (aka 'void *') from smaller integer type 'Int' (aka 'int')}}
(void) (CharPtr) v; // expected-warning{{cast to 'CharPtr' (aka 'char *') from smaller integer type 'Int' (aka 'int')}}
+
+ // Test that casts to void* can be controlled separately
+ // from other -Wint-to-pointer-cast warnings.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
+ (void) (VoidPtr) v; // no-warning
+ (void) (CharPtr) v; // expected-warning{{cast to 'CharPtr' (aka 'char *') from smaller integer type 'Int' (aka 'int')}}
+#pragma clang diagnostic pop
}
void testLong(Long v) {
diff --git a/test/Sema/constant-builtins-2.c b/test/Sema/constant-builtins-2.c
index 13d81fe13cbf..d2d221c5e12b 100644
--- a/test/Sema/constant-builtins-2.c
+++ b/test/Sema/constant-builtins-2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// Math stuff
@@ -37,10 +37,126 @@ float g16 = __builtin_copysign(1.0, -1.0);
double g17 = __builtin_copysignf(1.0f, -1.0f);
long double g18 = __builtin_copysignl(1.0L, -1.0L);
+char classify_nan [__builtin_fpclassify(+1, -1, -1, -1, -1, __builtin_nan(""))];
+char classify_snan [__builtin_fpclassify(+1, -1, -1, -1, -1, __builtin_nans(""))];
+char classify_inf [__builtin_fpclassify(-1, +1, -1, -1, -1, __builtin_inf())];
+char classify_neg_inf [__builtin_fpclassify(-1, +1, -1, -1, -1, -__builtin_inf())];
+char classify_normal [__builtin_fpclassify(-1, -1, +1, -1, -1, 1.539)];
+char classify_normal2 [__builtin_fpclassify(-1, -1, +1, -1, -1, 1e-307)];
+char classify_denorm [__builtin_fpclassify(-1, -1, -1, +1, -1, 1e-308)];
+char classify_denorm2 [__builtin_fpclassify(-1, -1, -1, +1, -1, -1e-308)];
+char classify_zero [__builtin_fpclassify(-1, -1, -1, -1, +1, 0.0)];
+char classify_neg_zero[__builtin_fpclassify(-1, -1, -1, -1, +1, -0.0)];
+
+char isinf_sign_noninf1[__builtin_isinf_sign(-0.0) == 0 ? 1 : -1];
+char isinf_sign_noninf2[__builtin_isinf_sign(1e307) == 0 ? 1 : -1];
+char isinf_sign_noninf3[__builtin_isinf_sign(__builtin_nan("")) == 0 ? 1 : -1];
+char isinf_sign_noninf4[__builtin_isinf_sign(-436.) == 0 ? 1 : -1];
+char isinf_sign_inf [__builtin_isinf_sign(__builtin_inf()) == 1 ? 1 : -1];
+char isinf_sign_neg_inf[__builtin_isinf_sign(-__builtin_inf()) == -1 ? 1 : -1];
+
+char isinf_inf_pos[__builtin_isinf(__builtin_inf()) ? 1 : -1];
+char isinf_pos [!__builtin_isinf(1.0) ? 1 : -1];
+char isinf_normf [!__builtin_isinf(1e-37f) ? 1 : -1];
+char isinf_denormf[!__builtin_isinf(1e-38f) ? 1 : -1];
+char isinf_norm [!__builtin_isinf(1e-307) ? 1 : -1];
+char isinf_denorm [!__builtin_isinf(1e-308) ? 1 : -1];
+char isinf_zero [!__builtin_isinf(0.0) ? 1 : -1];
+char isinf_negzero[!__builtin_isinf(-0.0) ? 1 : -1];
+char isinf_neg [!__builtin_isinf(-1.0) ? 1 : -1];
+char isinf_inf_neg[__builtin_isinf(-__builtin_inf()) ? 1 : -1];
+char isinf_nan [!__builtin_isinf(__builtin_nan("")) ? 1 : -1];
+char isinf_snan [!__builtin_isinf(__builtin_nans("")) ? 1 : -1];
+
+char isfinite_inf_pos[!__builtin_isfinite(__builtin_inf()) ? 1 : -1];
+char isfinite_pos [__builtin_isfinite(1.0) ? 1 : -1];
+char isfinite_normf [__builtin_isfinite(1e-37f) ? 1 : -1];
+char isfinite_denormf[__builtin_isfinite(1e-38f) ? 1 : -1];
+char isfinite_norm [__builtin_isfinite(1e-307) ? 1 : -1];
+char isfinite_denorm [__builtin_isfinite(1e-308) ? 1 : -1];
+char isfinite_zero [__builtin_isfinite(0.0) ? 1 : -1];
+char isfinite_negzero[__builtin_isfinite(-0.0) ? 1 : -1];
+char isfinite_neg [__builtin_isfinite(-1.0) ? 1 : -1];
+char isfinite_inf_neg[!__builtin_isfinite(-__builtin_inf()) ? 1 : -1];
+char isfinite_nan [!__builtin_isfinite(__builtin_nan("")) ? 1 : -1];
+char isfinite_snan [!__builtin_isfinite(__builtin_nans("")) ? 1 : -1];
+
+char isnan_inf_pos[!__builtin_isnan(__builtin_inf()) ? 1 : -1];
+char isnan_pos [!__builtin_isnan(1.0) ? 1 : -1];
+char isnan_normf [!__builtin_isnan(1e-37f) ? 1 : -1];
+char isnan_denormf[!__builtin_isnan(1e-38f) ? 1 : -1];
+char isnan_norm [!__builtin_isnan(1e-307) ? 1 : -1];
+char isnan_denorm [!__builtin_isnan(1e-308) ? 1 : -1];
+char isnan_zero [!__builtin_isnan(0.0) ? 1 : -1];
+char isnan_negzero[!__builtin_isnan(-0.0) ? 1 : -1];
+char isnan_neg [!__builtin_isnan(-1.0) ? 1 : -1];
+char isnan_inf_neg[!__builtin_isnan(-__builtin_inf()) ? 1 : -1];
+char isnan_nan [__builtin_isnan(__builtin_nan("")) ? 1 : -1];
+char isnan_snan [__builtin_isnan(__builtin_nans("")) ? 1 : -1];
+
+char isnormal_inf_pos[!__builtin_isnormal(__builtin_inf()) ? 1 : -1];
+char isnormal_pos [__builtin_isnormal(1.0) ? 1 : -1];
+char isnormal_normf [__builtin_isnormal(1e-37f) ? 1 : -1];
+char isnormal_denormf[!__builtin_isnormal(1e-38f) ? 1 : -1];
+char isnormal_norm [__builtin_isnormal(1e-307) ? 1 : -1];
+char isnormal_denorm [!__builtin_isnormal(1e-308) ? 1 : -1];
+char isnormal_zero [!__builtin_isnormal(0.0) ? 1 : -1];
+char isnormal_negzero[!__builtin_isnormal(-0.0) ? 1 : -1];
+char isnormal_neg [__builtin_isnormal(-1.0) ? 1 : -1];
+char isnormal_inf_neg[!__builtin_isnormal(-__builtin_inf()) ? 1 : -1];
+char isnormal_nan [!__builtin_isnormal(__builtin_nan("")) ? 1 : -1];
+char isnormal_snan [!__builtin_isnormal(__builtin_nans("")) ? 1 : -1];
+
//double g19 = __builtin_powi(2.0, 4);
//float g20 = __builtin_powif(2.0f, 4);
//long double g21 = __builtin_powil(2.0L, 4);
+#define BITSIZE(x) (sizeof(x) * 8)
+char g22[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1];
+char g23[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1];
+char g24[__builtin_clz(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
+int g25 = __builtin_clz(0); // expected-error {{not a compile-time constant}}
+char g26[__builtin_clzl(0xFL) == BITSIZE(long) - 4 ? 1 : -1];
+char g27[__builtin_clzll(0xFFLL) == BITSIZE(long long) - 8 ? 1 : -1];
+
+char g28[__builtin_ctz(1) == 0 ? 1 : -1];
+char g29[__builtin_ctz(8) == 3 ? 1 : -1];
+char g30[__builtin_ctz(1 << (BITSIZE(int) - 1)) == BITSIZE(int) - 1 ? 1 : -1];
+int g31 = __builtin_ctz(0); // expected-error {{not a compile-time constant}}
+char g32[__builtin_ctzl(0x10L) == 4 ? 1 : -1];
+char g33[__builtin_ctzll(0x100LL) == 8 ? 1 : -1];
+
+char g34[__builtin_popcount(0) == 0 ? 1 : -1];
+char g35[__builtin_popcount(0xF0F0) == 8 ? 1 : -1];
+char g36[__builtin_popcount(~0) == BITSIZE(int) ? 1 : -1];
+char g37[__builtin_popcount(~0L) == BITSIZE(int) ? 1 : -1];
+char g38[__builtin_popcountl(0L) == 0 ? 1 : -1];
+char g39[__builtin_popcountl(0xF0F0L) == 8 ? 1 : -1];
+char g40[__builtin_popcountl(~0L) == BITSIZE(long) ? 1 : -1];
+char g41[__builtin_popcountll(0LL) == 0 ? 1 : -1];
+char g42[__builtin_popcountll(0xF0F0LL) == 8 ? 1 : -1];
+char g43[__builtin_popcountll(~0LL) == BITSIZE(long long) ? 1 : -1];
+
+char g44[__builtin_parity(0) == 0 ? 1 : -1];
+char g45[__builtin_parity(0xb821) == 0 ? 1 : -1];
+char g46[__builtin_parity(0xb822) == 0 ? 1 : -1];
+char g47[__builtin_parity(0xb823) == 1 ? 1 : -1];
+char g48[__builtin_parity(0xb824) == 0 ? 1 : -1];
+char g49[__builtin_parity(0xb825) == 1 ? 1 : -1];
+char g50[__builtin_parity(0xb826) == 1 ? 1 : -1];
+char g51[__builtin_parity(~0) == 0 ? 1 : -1];
+char g52[__builtin_parityl(1L << (BITSIZE(long) - 1)) == 1 ? 1 : -1];
+char g53[__builtin_parityll(1LL << (BITSIZE(long long) - 1)) == 1 ? 1 : -1];
+
+char g54[__builtin_ffs(0) == 0 ? 1 : -1];
+char g55[__builtin_ffs(1) == 1 ? 1 : -1];
+char g56[__builtin_ffs(0xfbe71) == 1 ? 1 : -1];
+char g57[__builtin_ffs(0xfbe70) == 5 ? 1 : -1];
+char g58[__builtin_ffs(1U << (BITSIZE(int) - 1)) == BITSIZE(int) ? 1 : -1];
+char g59[__builtin_ffsl(0x10L) == 5 ? 1 : -1];
+char g60[__builtin_ffsll(0x100LL) == 9 ? 1 : -1];
+#undef BITSIZE
+
// GCC misc stuff
extern int f();
diff --git a/test/Sema/convertvector.c b/test/Sema/convertvector.c
new file mode 100644
index 000000000000..ccdd87f9e40c
--- /dev/null
+++ b/test/Sema/convertvector.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float vector8float __attribute__((__vector_size__(32)));
+
+vector8float foo1(vector4double x) {
+ return __builtin_convertvector(x, vector8float); // expected-error {{same number of elements}}
+}
+
+float foo2(vector4double x) {
+ return __builtin_convertvector(x, float); // expected-error {{must be a vector type}}
+}
+
+vector8float foo3(double x) {
+ return __builtin_convertvector(x, vector8float); // expected-error {{must be a vector}}
+}
+
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 30c009201cef..d810632eeea5 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -36,3 +36,16 @@ void test2() {}
struct test3s {
} // expected-error {{expected ';' after struct}}
typedef int test3g;
+
+// PR8264
+const const int pr8264_1 = 0; // expected-warning {{duplicate 'const' declaration specifier}}
+volatile volatile int pr8264_2; // expected-warning {{duplicate 'volatile' declaration specifier}}
+char * restrict restrict pr8264_3; // expected-warning {{duplicate 'restrict' declaration specifier}}
+
+extern extern int pr8264_4; // expected-warning {{duplicate 'extern' declaration specifier}}
+void pr8264_5() {
+ register register int x; // expected-warning {{duplicate 'register' declaration specifier}}
+}
+
+inline inline void pr8264_6() {} // expected-warning {{duplicate 'inline' declaration specifier}}
+_Noreturn _Noreturn void pr8264_7(); // expected-warning {{duplicate '_Noreturn' declaration specifier}}
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index c9a8482e85db..6630da67c5bd 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -137,7 +137,6 @@ void test() {
};
}
-// FIXME: How do we test that this initializes the long properly?
union { char c; long l; } u1 = { .l = 0xFFFF };
extern float global_float;
@@ -223,6 +222,55 @@ struct Enigma enigma = {
};
+/// PR16644
+typedef union {
+ struct {
+ int zero;
+ int one;
+ int two;
+ int three;
+ } a;
+ int b[4];
+} union_16644_t;
+
+union_16644_t union_16644_instance_0 =
+{
+ .b[0] = 0, // expected-note{{previous}}
+ .a.one = 1, // expected-warning{{overrides}} expected-note{{previous}}
+ .b[2] = 2, // expected-warning{{overrides}} expected-note{{previous}}
+ .a.three = 3, // expected-warning{{overrides}}
+};
+
+union_16644_t union_16644_instance_1 =
+{
+ .a.three = 13, // expected-note{{previous}}
+ .b[2] = 12, // expected-warning{{overrides}} expected-note{{previous}}
+ .a.one = 11, // expected-warning{{overrides}} expected-note{{previous}}
+ .b[0] = 10, // expected-warning{{overrides}}
+};
+
+union_16644_t union_16644_instance_2 =
+{
+ .a.one = 21, // expected-note{{previous}}
+ .b[1] = 20, // expected-warning{{overrides}}
+};
+
+union_16644_t union_16644_instance_3 =
+{
+ .b[1] = 30, // expected-note{{previous}}
+ .a = { // expected-warning{{overrides}}
+ .one = 31
+ }
+};
+
+union_16644_t union_16644_instance_4[2] =
+{
+ [0].a.one = 2,
+ [1].a.zero = 3,// expected-note{{previous}}
+ [0].a.zero = 5,
+ [1].b[1] = 4 // expected-warning{{overrides}}
+};
+
/// PR4073
/// Should use evaluate to fold aggressively and emit a warning if not an ice.
extern int crazy_x;
@@ -277,3 +325,19 @@ struct ds ds2 = { { {
.a = 0,
.b = 1 // expected-error{{field designator 'b' does not refer to any field}}
} } };
+
+// Check initializer override warnings overriding a character in a string
+struct overwrite_string_struct {
+ char L[6];
+ int M;
+} overwrite_string[] = {
+ { { "foo" }, 1 }, // expected-note {{previous initialization is here}}
+ [0].L[2] = 'x' // expected-warning{{initializer overrides prior initialization of this subobject}}
+};
+struct overwrite_string_struct2 {
+ char L[6];
+ int M;
+} overwrite_string2[] = {
+ { { "foo" }, 1 },
+ [0].L[4] = 'x' // no-warning
+ };
diff --git a/test/Sema/dllimport-dllexport.c b/test/Sema/dllimport-dllexport.c
index 00c9df594b6f..80810d696e8c 100644
--- a/test/Sema/dllimport-dllexport.c
+++ b/test/Sema/dllimport-dllexport.c
@@ -41,3 +41,8 @@ void __attribute__((dllexport)) foo13();
extern int foo14 __attribute__((dllexport));
extern int foo14 __attribute__((dllimport)); // expected-warning{{dllimport attribute ignored}}
+
+__declspec(dllimport) int foo15 = 54; // expected-warning{{'dllimport' attribute cannot be specified on a definition}}
+
+extern __declspec(dllimport) int foo17;
+int foo17 = 54; // expected-warning{{'dllimport' attribute cannot be specified on a definition}}
diff --git a/test/Sema/empty1.c b/test/Sema/empty1.c
new file mode 100644
index 000000000000..de922f775ef7
--- /dev/null
+++ b/test/Sema/empty1.c
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wc++-compat
+
+struct emp_1 { // expected-warning {{empty struct has size 0 in C, size 1 in C++}}
+};
+
+union emp_2 { // expected-warning {{empty union has size 0 in C, size 1 in C++}}
+};
+
+struct emp_3 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
+ int : 0;
+};
+
+union emp_4 { // expected-warning {{union has size 0 in C, size 1 in C++}}
+ int : 0;
+};
+
+struct emp_5 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
+ int : 0;
+ int : 0;
+};
+
+union emp_6 { // expected-warning {{union has size 0 in C, size 1 in C++}}
+ int : 0;
+ int : 0;
+};
+
+struct emp_7 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
+ struct emp_1 f1;
+};
+
+union emp_8 { // expected-warning {{union has size 0 in C, size 1 in C++}}
+ struct emp_1 f1;
+};
+
+struct emp_9 { // expected-warning {{struct has size 0 in C, non-zero size in C++}}
+ struct emp_1 f1;
+ union emp_2 f2;
+};
+
+// Checks for pointer subtraction (PR15683)
+struct emp_1 *func_1p(struct emp_1 *x) { return x - 5; }
+
+int func_1() {
+ struct emp_1 v[1];
+ return v - v; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_2(struct emp_1 *x) {
+ return 1 + x - x; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_3(struct emp_1 *x, struct emp_1 *y) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_4(struct emp_1 *x, const struct emp_1 *y) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_5(volatile struct emp_1 *x, const struct emp_1 *y) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_6() {
+ union emp_2 v[1];
+ return v - v; // expected-warning {{subtraction of pointers to type 'union emp_2' of zero size has undefined behavior}}
+}
+
+struct A; // expected-note {{forward declaration of 'struct A'}}
+
+int func_7(struct A *x, struct A *y) {
+ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct A'}}
+}
+
+int func_8(struct emp_1 (*x)[10], struct emp_1 (*y)[10]) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1 [10]' of zero size has undefined behavior}}
+}
+
+int func_9(struct emp_1 (*x)[], struct emp_1 (*y)[]) {
+ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct emp_1 []'}}
+}
+
+int func_10(int (*x)[0], int (*y)[0]) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}
+}
diff --git a/test/Sema/empty2.c b/test/Sema/empty2.c
new file mode 100644
index 000000000000..68da5a8ee8ac
--- /dev/null
+++ b/test/Sema/empty2.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+
+struct emp_1 { // expected-warning {{empty struct is a GNU extension}}
+};
+
+union emp_2 { // expected-warning {{empty union is a GNU extension}}
+};
+
+struct emp_3 { // expected-warning {{struct without named members is a GNU extension}}
+ int : 0;
+};
+
+union emp_4 { // expected-warning {{union without named members is a GNU extension}}
+ int : 0;
+};
+
+struct emp_5 { // expected-warning {{struct without named members is a GNU extension}}
+ int : 0;
+ int : 0;
+};
+
+union emp_6 { // expected-warning {{union without named members is a GNU extension}}
+ int : 0;
+ int : 0;
+};
+
+struct nonamed_1 { // expected-warning {{struct without named members is a GNU extension}}
+ int : 4;
+};
+
+union nonamed_2 { // expected-warning {{union without named members is a GNU extension}}
+ int : 4;
+};
+
+struct nonamed_3 { // expected-warning {{struct without named members is a GNU extension}}
+ int : 4;
+ unsigned int : 4;
+};
+
+union nonamed_4 { // expected-warning {{union without named members is a GNU extension}}
+ int : 4;
+ unsigned int : 4;
+};
diff --git a/test/Sema/enum-increment.c b/test/Sema/enum-increment.c
new file mode 100644
index 000000000000..baaa3489b958
--- /dev/null
+++ b/test/Sema/enum-increment.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+// expected-no-diagnostics
+enum A { A1, A2, A3 };
+typedef enum A A;
+void test() {
+ A a;
+ a++;
+ a--;
+ ++a;
+ --a;
+ a = a + 1;
+ a = a - 1;
+}
diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c
index 848ec1f106f6..66004b03ff8c 100644
--- a/test/Sema/ext_vector_casts.c
+++ b/test/Sema/ext_vector_casts.c
@@ -1,10 +1,13 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fno-lax-vector-conversions %s
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fsyntax-only -verify -fno-lax-vector-conversions %s
typedef __attribute__(( ext_vector_type(2) )) float float2;
typedef __attribute__(( ext_vector_type(4) )) int int4;
typedef __attribute__(( ext_vector_type(8) )) short short8;
typedef __attribute__(( ext_vector_type(4) )) float float4;
typedef float t3 __attribute__ ((vector_size (16)));
+typedef __typeof__(sizeof(int)) size_t;
+typedef unsigned long ulong2 __attribute__ ((ext_vector_type(2)));
+typedef size_t stride4 __attribute__((ext_vector_type(4)));
static void test() {
float2 vec2;
@@ -50,3 +53,24 @@ void inc(float2 f2) {
f2++; // expected-error{{cannot increment value of type 'float2'}}
__real f2; // expected-error{{invalid type 'float2' to __real operator}}
}
+
+typedef enum
+{
+ uchar_stride = 1,
+ uchar4_stride = 4,
+ ushort4_stride = 8,
+ short4_stride = 8,
+ uint4_stride = 16,
+ int4_stride = 16,
+ float4_stride = 16,
+} PixelByteStride;
+
+stride4 RDar15091442_get_stride4(int4 x, PixelByteStride pixelByteStride);
+stride4 RDar15091442_get_stride4(int4 x, PixelByteStride pixelByteStride)
+{
+ stride4 stride;
+ // This previously caused an assertion failure.
+ stride.lo = ((ulong2) x) * pixelByteStride; // no-warning
+ return stride;
+}
+
diff --git a/test/Sema/extern-redecl.c b/test/Sema/extern-redecl.c
index e9a4c571bd2d..6bdb66e07f55 100644
--- a/test/Sema/extern-redecl.c
+++ b/test/Sema/extern-redecl.c
@@ -62,3 +62,27 @@ void test5c() {
void *(*_malloc)() = &malloc;
float *(*_calloc)() = &calloc;
}
+
+void test6() {
+ extern int test6_array1[100];
+ extern int test6_array2[100];
+ void test6_fn1(int*);
+ void test6_fn2(int*);
+ {
+ // Types are only merged from visible declarations.
+ char test6_array2;
+ char test6_fn2;
+ {
+ extern int test6_array1[];
+ extern int test6_array2[];
+ (void)sizeof(test6_array1); // ok
+ (void)sizeof(test6_array2); // expected-error {{incomplete type}}
+
+ void test6_fn1();
+ void test6_fn2();
+ test6_fn1(1.2); // expected-error {{passing 'double' to parameter of incompatible type 'int *'}}
+ // FIXME: This is valid, but we should warn on it.
+ test6_fn2(1.2);
+ }
+ }
+}
diff --git a/test/Sema/format-strings-ms.c b/test/Sema/format-strings-ms.c
new file mode 100644
index 000000000000..b89ee421ced8
--- /dev/null
+++ b/test/Sema/format-strings-ms.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -pedantic %s
+
+int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void signed_test() {
+ short val = 30;
+ printf("val = %I64d\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type '__int64' (aka 'long long') but the argument has type 'short'}}
+ long long bigval = 30;
+ printf("val = %I32d\n", bigval); // expected-warning{{'I32' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
+ printf("val = %Id\n", bigval); // expected-warning{{'I' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
+}
+
+void unsigned_test() {
+ unsigned short val = 30;
+ printf("val = %I64u\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type 'unsigned __int64' (aka 'unsigned long long') but the argument has type 'unsigned short'}}
+ unsigned long long bigval = 30;
+ printf("val = %I32u\n", bigval); // expected-warning{{'I32' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
+ printf("val = %Iu\n", bigval); // expected-warning{{'I' length modifier is not supported by ISO C}} \
+ // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
+}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index ba1272148973..6da027e02c65 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -591,3 +591,13 @@ void test_qualifiers(volatile int *vip, const int *cip,
printf("%n", (ip_t)0); // No warning.
printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
}
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#pragma GCC diagnostic warning "-Wformat-security"
+// <rdar://problem/14178260>
+extern void test_format_security_extra_args(const char*, int, ...)
+ __attribute__((__format__(__printf__, 1, 3)));
+void test_format_security_pos(char* string) {
+ test_format_security_extra_args(string, 5); // expected-warning {{format string is not a string literal (potentially insecure)}}
+}
+#pragma GCC diagnostic warning "-Wformat-nonliteral"
diff --git a/test/Sema/freemain.c b/test/Sema/freemain.c
index eed644d483ac..ff000c62cc70 100644
--- a/test/Sema/freemain.c
+++ b/test/Sema/freemain.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// RUN: %clang_cc1 -triple i686-pc-openbsd -fsyntax-only -verify -ffreestanding %s
// Tests that -ffreestanding disables all special treatment of main().
diff --git a/test/Sema/function.c b/test/Sema/function.c
index bbf81a56cbb6..81d303c27f62 100644
--- a/test/Sema/function.c
+++ b/test/Sema/function.c
@@ -103,3 +103,13 @@ int func_e(int x) {
}
return x + 3;
}
+
+void decays(int a[3][3]); // expected-note {{passing argument to parameter 'a' here}}
+void no_decay(int (*a)[3]); // expected-note {{passing argument to parameter 'a' here}}
+
+void t22(int *ptr, int (*array)[3]) {
+ decays(ptr); // expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'int (*)[3]'}}
+ no_decay(ptr); // expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'int (*)[3]'}}
+ decays(array);
+ no_decay(array);
+}
diff --git a/test/Sema/gnu-flags.c b/test/Sema/gnu-flags.c
new file mode 100644
index 000000000000..e7588b7b371e
--- /dev/null
+++ b/test/Sema/gnu-flags.c
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wno-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \
+// RUN: -Wgnu-alignof-expression -Wgnu-case-range -Wgnu-complex-integer -Wgnu-conditional-omitted-operand \
+// RUN: -Wgnu-empty-initializer -Wgnu-label-as-value -Wgnu-statement-expression \
+// RUN: -Wgnu-compound-literal-initializer -Wgnu-flexible-array-initializer \
+// RUN: -Wgnu-redeclared-enum -Wgnu-folding-constant -Wgnu-empty-struct \
+// RUN: -Wgnu-union-cast -Wgnu-variable-sized-type-not-at-end
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \
+// RUN: -Wno-gnu-alignof-expression -Wno-gnu-case-range -Wno-gnu-complex-integer -Wno-gnu-conditional-omitted-operand \
+// RUN: -Wno-gnu-empty-initializer -Wno-gnu-label-as-value -Wno-gnu-statement-expression \
+// RUN: -Wno-gnu-compound-literal-initializer -Wno-gnu-flexible-array-initializer \
+// RUN: -Wno-gnu-redeclared-enum -Wno-gnu-folding-constant -Wno-gnu-empty-struct \
+// RUN: -Wno-gnu-union-cast -Wno-gnu-variable-sized-type-not-at-end
+// Additional disabled tests:
+// %clang_cc1 -fsyntax-only -verify %s -DALIGNOF -Wno-gnu -Wgnu-alignof-expression
+// %clang_cc1 -fsyntax-only -verify %s -DCASERANGE -Wno-gnu -Wgnu-case-range
+// %clang_cc1 -fsyntax-only -verify %s -DCOMPLEXINT -Wno-gnu -Wgnu-complex-integer
+// %clang_cc1 -fsyntax-only -verify %s -DOMITTEDOPERAND -Wno-gnu -Wgnu-conditional-omitted-operand
+// %clang_cc1 -fsyntax-only -verify %s -DEMPTYINIT -Wno-gnu -Wgnu-empty-initializer
+// %clang_cc1 -fsyntax-only -verify %s -DLABELVALUE -Wno-gnu -Wgnu-label-as-value
+// %clang_cc1 -fsyntax-only -verify %s -DSTATEMENTEXP -Wno-gnu -Wgnu-statement-expression
+// %clang_cc1 -fsyntax-only -verify %s -DCOMPOUNDLITERALINITIALIZER -Wno-gnu -Wgnu-compound-literal-initializer
+// %clang_cc1 -fsyntax-only -verify %s -DFLEXIBLEARRAYINITIALIZER -Wno-gnu -Wgnu-flexible-array-initializer
+// %clang_cc1 -fsyntax-only -verify %s -DREDECLAREDENUM -Wno-gnu -Wgnu-redeclared-enum
+// %clang_cc1 -fsyntax-only -verify %s -DUNIONCAST -Wno-gnu -Wgnu-union-cast
+// %clang_cc1 -fsyntax-only -verify %s -DVARIABLESIZEDTYPENOTATEND -Wno-gnu -Wgnu-variable-sized-type-not-at-end
+// %clang_cc1 -fsyntax-only -verify %s -DFOLDINGCONSTANT -Wno-gnu -Wgnu-folding-constant
+// %clang_cc1 -fsyntax-only -verify %s -DEMPTYSTRUCT -Wno-gnu -Wgnu-empty-struct
+
+#if NONE
+// expected-no-diagnostics
+#endif
+
+
+#if ALL || ALIGNOF
+// expected-warning@+4 {{'_Alignof' applied to an expression is a GNU extension}}
+#endif
+
+char align;
+_Static_assert(_Alignof(align) > 0, "align's alignment is wrong");
+
+
+#if ALL || CASERANGE
+// expected-warning@+5 {{use of GNU case range extension}}
+#endif
+
+void caserange(int x) {
+ switch (x) {
+ case 42 ... 44: ;
+ }
+}
+
+
+#if ALL || COMPLEXINT
+// expected-warning@+3 {{complex integer types are a GNU extension}}
+#endif
+
+_Complex short int complexint;
+
+
+#if ALL || OMITTEDOPERAND
+// expected-warning@+3 {{use of GNU ?: conditional expression extension, omitting middle operand}}
+#endif
+
+static const char* omittedoperand = (const char*)0 ?: "Null";
+
+
+#if ALL || EMPTYINIT
+// expected-warning@+3 {{use of GNU empty initializer extension}}
+#endif
+
+struct { int x; } emptyinit = {};
+
+
+#if ALL || LABELVALUE
+// expected-warning@+6 {{use of GNU address-of-label extension}}
+// expected-warning@+7 {{use of GNU indirect-goto extension}}
+#endif
+
+void labelvalue() {
+ void *ptr;
+ ptr = &&foo;
+foo:
+ goto *ptr;
+}
+
+
+#if ALL || STATEMENTEXP
+// expected-warning@+5 {{use of GNU statement expression extension}}
+#endif
+
+void statementexp()
+{
+ int a = ({ 1; });
+}
+
+
+#if ALL || COMPOUNDLITERALINITIALIZER
+// expected-warning@+4 {{initialization of an array of type 'int [5]' from a compound literal of type 'int [5]' is a GNU extension}}
+#endif
+
+typedef int int5[5];
+int cli[5] = (int[]){1, 2, 3, 4, 5};
+
+
+#if ALL || FLEXIBLEARRAYINITIALIZER
+// expected-note@+6 {{initialized flexible array member 'y' is here}}
+// expected-warning@+6 {{flexible array initialization is a GNU extension}}
+#endif
+
+struct fai {
+ int x;
+ int y[];
+} fai = { 1, { 2, 3, 4 } };
+
+
+#if ALL || FOLDINGCONSTANT
+// expected-warning@+5 {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
+// expected-warning@+7 {{variable length array folded to constant array as an extension}}
+#endif
+
+enum {
+ fic = (int)(0.75 * 1000 * 1000)
+};
+static const int size = 100;
+void foo(void) { int data[size]; }
+
+#if ALL || REDECLAREDENUM
+// expected-note@+4 {{previous definition is here}}
+// expected-warning@+8 {{redeclaration of already-defined enum 'RE' is a GNU extension}}
+#endif
+
+enum RE {
+ Val1,
+ Val2
+};
+
+enum RE;
+
+
+#if ALL || UNIONCAST
+// expected-warning@+4 {{cast to union type is a GNU extension}}
+#endif
+
+union uc { int i; unsigned : 3; };
+union uc w = (union uc)2;
+
+
+#if ALL || VARIABLESIZEDTYPENOTATEND
+// expected-warning@+8 {{field 'hdr' with variable sized type 'struct vst' not at the end of a struct or class is a GNU extension}}
+#endif
+
+struct vst {
+ short tag_type;
+ char tag_data[];
+};
+struct vstnae {
+ struct vst hdr;
+ char data;
+};
+
+
+#if ALL || EMPTYSTRUCT
+// expected-warning@+4 {{empty struct is a GNU extension}}
+// expected-warning@+4 {{struct without named members is a GNU extension}}
+#endif
+
+const struct {} es;
+struct {int:5;} swnm;
+
diff --git a/test/Sema/init.c b/test/Sema/init.c
index 81a665dc6297..4a5fc558c51b 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -157,3 +157,6 @@ int PR4386_zed() __attribute((weak));
typedef char strty[10];
struct vortexstruct { strty s; };
struct vortexstruct vortexvar = { "asdf" };
+
+typedef struct { uintptr_t x : 2; } StructWithBitfield;
+StructWithBitfield bitfieldvar = { (uintptr_t)&bitfieldvar }; // expected-error {{initializer element is not a compile-time constant}}
diff --git a/test/Sema/inline.c b/test/Sema/inline.c
index 496e282ecacd..8a3835b71ada 100644
--- a/test/Sema/inline.c
+++ b/test/Sema/inline.c
@@ -83,6 +83,19 @@ extern inline void defineStaticVarInExtern() {
static int y = 0; // ok
}
+// Check behavior of line markers.
+# 1 "XXX.h" 1
+inline int useStaticMainFileInLineMarker() { // expected-note 2 {{use 'static' to give inline function 'useStaticMainFileInLineMarker' internal linkage}}
+ staticFunction(); // expected-warning{{static function 'staticFunction' is used in an inline function with external linkage}}
+ return staticVar; // expected-warning{{static variable 'staticVar' is used in an inline function with external linkage}}
+}
+# 100 "inline.c" 2
+
+inline int useStaticMainFileAfterLineMarker() {
+ staticFunction(); // no-warning
+ return staticVar; // no-warning
+}
+
#endif
diff --git a/test/Sema/member-reference.c b/test/Sema/member-reference.c
index edbbea59ac87..8939fd515709 100644
--- a/test/Sema/member-reference.c
+++ b/test/Sema/member-reference.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
-// expected-no-diagnostics
struct simple { int i; };
@@ -19,3 +18,7 @@ void g(void) {
s->x = 1;
s->z = 2;
}
+
+int PR17762(struct simple c) {
+ return c->i; // expected-error {{member reference type 'struct simple' is not a pointer; maybe you meant to use '.'?}}
+}
diff --git a/test/Sema/mips16_attr_allowed.c b/test/Sema/mips16_attr_allowed.c
index 21a94e773f92..c712e902f5fb 100644
--- a/test/Sema/mips16_attr_allowed.c
+++ b/test/Sema/mips16_attr_allowed.c
@@ -2,22 +2,22 @@
void foo32();
void foo16();
-void __attribute__((nomips16)) foo32();
-void __attribute__((mips16)) foo16();
+void __attribute__((nomips16)) foo32();
+void __attribute__((mips16)) foo16();
-void __attribute__((nomips16)) foo32_();
-void __attribute__((mips16)) foo16_();
+void __attribute__((nomips16)) foo32_();
+void __attribute__((mips16)) foo16_();
void foo32_();
void foo16_();
-void foo32__() __attribute__((nomips16));
-void foo32__() __attribute__((mips16));
+void foo32__() __attribute__((nomips16));
+void foo32__() __attribute__((mips16));
-void foo32a() __attribute__((nomips16(xyz))) ; // expected-error {{attribute takes no arguments}}
-void __attribute__((mips16(xyz))) foo16a(); // expected-error {{attribute takes no arguments}}
+void foo32a() __attribute__((nomips16(0))) ; // expected-error {{'nomips16' attribute takes no arguments}}
+void __attribute__((mips16(1))) foo16a(); // expected-error {{'mips16' attribute takes no arguments}}
-void __attribute__((nomips16(1, 2))) foo32b(); // expected-error {{attribute takes no arguments}}
-void __attribute__((mips16(1, 2))) foo16b(); // expected-error {{attribute takes no arguments}}
+void __attribute__((nomips16(1, 2))) foo32b(); // expected-error {{'nomips16' attribute takes no arguments}}
+void __attribute__((mips16(1, 2))) foo16b(); // expected-error {{'mips16' attribute takes no arguments}}
__attribute((nomips16)) int a; // expected-error {{attribute only applies to functions}}
diff --git a/test/Sema/mrtd.c b/test/Sema/mrtd.c
new file mode 100644
index 000000000000..ba1720e8d7dc
--- /dev/null
+++ b/test/Sema/mrtd.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -DMRTD -mrtd -triple i386-unknown-unknown -verify %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -verify %s
+
+#ifndef MRTD
+// expected-note@+5 {{previous declaration is here}}
+// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
+// expected-note@+5 {{previous declaration is here}}
+// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
+#endif
+void nonvariadic1(int a, int b, int c);
+void __attribute__((stdcall)) nonvariadic1(int a, int b, int c);
+void nonvariadic2(int a, int b, int c);
+void __attribute__((stdcall)) nonvariadic2(int a, int b, int c) { }
+
+// expected-warning@+2 {{stdcall calling convention ignored on variadic function}}
+void variadic(int a, ...);
+void __attribute__((stdcall)) variadic(int a, ...);
+
+#ifdef MRTD
+// expected-note@+3 {{previous definition is here}}
+// expected-error@+3 {{redefinition of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}}
+#endif
+extern void (*a)(int, int);
+__attribute__((cdecl)) extern void (*a)(int, int);
+
+extern void (*b)(int, ...);
+__attribute__((cdecl)) extern void (*b)(int, ...);
+
+#ifndef MRTD
+// expected-note@+3 {{previous definition is here}}
+// expected-error@+3 {{redefinition of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}}
+#endif
+extern void (*c)(int, int);
+__attribute__((stdcall)) extern void (*c)(int, int);
+
+// expected-warning@+2 {{stdcall calling convention ignored on variadic function}}
+extern void (*d)(int, ...);
+__attribute__((stdcall)) extern void (*d)(int, ...);
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
index 1916d3463de5..69f234e5e9ae 100644
--- a/test/Sema/ms-inline-asm.c
+++ b/test/Sema/ms-inline-asm.c
@@ -1,4 +1,4 @@
-// REQUIRES: disabled
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fasm-blocks -Wno-microsoft -verify -fsyntax-only
void t1(void) {
@@ -13,22 +13,22 @@ void f() {
}
f();
__asm {
- mov eax, 1+=2 // expected-error 2 {{unknown token in expression}}
+ mov eax, 1+=2 // expected-error {{unknown token in expression}}
}
f();
__asm {
- mov eax, 1+++ // expected-error 2 {{unknown token in expression}}
+ mov eax, 1+++ // expected-error {{unknown token in expression}}
}
f();
__asm {
- mov eax, LENGTH bar // expected-error {{Unable to lookup expr!}}
+ mov eax, LENGTH bar // expected-error {{unable to lookup expression}}
}
f();
__asm {
- mov eax, SIZE bar // expected-error {{Unable to lookup expr!}}
+ mov eax, SIZE bar // expected-error {{unable to lookup expression}}
}
f();
__asm {
- mov eax, TYPE bar // expected-error {{Unable to lookup expr!}}
+ mov eax, TYPE bar // expected-error {{unable to lookup expression}}
}
}
diff --git a/test/Sema/ms-keyword-system-header.c b/test/Sema/ms-keyword-system-header.c
new file mode 100644
index 000000000000..b4ff5683cdfd
--- /dev/null
+++ b/test/Sema/ms-keyword-system-header.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fms-extensions -D MS -isystem %S/Inputs %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fms-extensions -D MS -Wno-keyword-compat -I %S/Inputs %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fms-extensions -D MS -D NOT_SYSTEM -I %S/Inputs %s -fsyntax-only -verify
+// RUN: %clang_cc1 -isystem %S/Inputs %s -fsyntax-only -verify
+
+// PR17824: GNU libc uses MS keyword __uptr as an identifier in C mode
+#include <ms-keyword-system-header.h>
+
+void fn() {
+ WS ws;
+ ws.__uptr = 0;
+#ifdef MS
+ // expected-error@-2 {{expected identifier}}
+#else
+ // expected-no-diagnostics
+#endif
+}
diff --git a/test/Sema/ms-wchar.c b/test/Sema/ms-wchar.c
new file mode 100644
index 000000000000..febaf283b338
--- /dev/null
+++ b/test/Sema/ms-wchar.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+// C++ mode with -fno-wchar works the same as C mode for wchar_t.
+// RUN: %clang_cc1 -x c++ -fno-wchar -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f(); // expected-error{{unknown type name 'wchar_t'}}
+
+// __wchar_t is available as an MS extension.
+__wchar_t g = L'a'; // expected-note {{previous}}
+
+// __wchar_t is a distinct type, separate from the target's integer type for wide chars.
+unsigned short g; // expected-error {{redefinition of 'g' with a different type: 'unsigned short' vs '__wchar_t'}}
+
+// The type of a wide string literal is actually not __wchar_t.
+__wchar_t s[] = L"Hello world!"; // expected-error-re {{array initializer must be an initializer list$}}
+
+// Do not suggest initializing with a string here, because it would not work.
+__wchar_t t[] = 1; // expected-error-re {{array initializer must be an initializer list$}}
diff --git a/test/Sema/ms_abi-sysv_abi.c b/test/Sema/ms_abi-sysv_abi.c
new file mode 100644
index 000000000000..35a5fad9ceb3
--- /dev/null
+++ b/test/Sema/ms_abi-sysv_abi.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
+
+// CC qualifier can be applied only to functions
+int __attribute__((ms_abi)) var1; // expected-warning{{'ms_abi' only applies to function types; type here is 'int'}}
+int __attribute__((sysv_abi)) var2; // expected-warning{{'sysv_abi' only applies to function types; type here is 'int'}}
+
+// Different CC qualifiers are not compatible
+// FIXME: Should say 'sysv_abi' instead of 'cdecl'
+void __attribute__((ms_abi, sysv_abi)) foo3(void); // expected-error{{cdecl and ms_abi attributes are not compatible}}
+void __attribute__((ms_abi)) foo4(); // expected-note{{previous declaration is here}}
+void __attribute__((sysv_abi)) foo4(void); // expected-error{{function declared 'cdecl' here was previously declared 'ms_abi'}}
+
+void bar(int i, int j) __attribute__((ms_abi, cdecl)); // expected-error{{cdecl and ms_abi attributes are not compatible}}
+void bar2(int i, int j) __attribute__((sysv_abi, cdecl)); // no-error
diff --git a/test/Sema/ms_bitfield_layout.c b/test/Sema/ms_bitfield_layout.c
new file mode 100644
index 000000000000..4a2076c1dbac
--- /dev/null
+++ b/test/Sema/ms_bitfield_layout.c
@@ -0,0 +1,243 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -cxx-abi microsoft -fdump-record-layouts %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -cxx-abi microsoft -fdump-record-layouts %s 2>/dev/null \
+// RUN: | FileCheck %s
+
+typedef struct A {
+ char x;
+ int a : 22;
+ int : 0;
+ int c : 10;
+ char b : 3;
+ char d: 4;
+ short y;
+} A;
+
+// CHECK: Type: struct A
+// CHECK: Size:128
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0, 32, 64, 64, 96, 99, 112]>
+
+typedef struct B {
+ char x;
+ int : 0;
+ short a : 4;
+ char y;
+} B;
+
+// CHECK: Type: struct B
+// CHECK: Size:48
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8, 16, 32]>
+
+typedef struct C {
+ char x;
+ short a : 4;
+ int : 0;
+ char y;
+} C;
+
+// CHECK: Type: struct C
+// CHECK: Size:64
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0, 16, 32, 32]>
+
+typedef struct D {
+ char x;
+ short : 0;
+ int : 0;
+ char y;
+} D;
+
+// CHECK: Type: struct D
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 8]>
+
+typedef union E {
+ char x;
+ long long a : 3;
+ int b : 3;
+ long long : 0;
+ short y;
+} E;
+
+// CHECK: Type: union E
+// CHECK: Size:64
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct F {
+ char x;
+ char a : 3;
+ char b : 3;
+ char c : 3;
+ short d : 6;
+ short e : 6;
+ short f : 6;
+ short g : 11;
+ short h : 11;
+ short i : 11;
+ short y;
+} F;
+
+// CHECK: Type: struct F
+// CHECK: Size:128
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8, 11, 16, 32, 38, 48, 64, 80, 96, 112]>
+
+typedef union G {
+ char x;
+ int a : 3;
+ int : 0;
+ long long : 0;
+ short y;
+} G;
+
+// CHECK: Type: union G
+// CHECK: Size:32
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct H {
+ unsigned short a : 1;
+ unsigned char : 0;
+ unsigned long : 0;
+ unsigned short c : 1;
+} H;
+
+// CHECK: Type: struct H
+// CHECK: Size:32
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 16, 16, 16]>
+
+#pragma pack(push, 1)
+
+typedef struct A1 {
+ char x;
+ int a : 22;
+ int : 0;
+ int c : 10;
+ char b : 3;
+ char d: 4;
+ short y;
+} A1;
+
+// CHECK: Type: struct A1
+// CHECK: Size:96
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 40, 40, 72, 75, 80]>
+
+typedef struct B1 {
+ char x;
+ int : 0;
+ short a : 4;
+ char y;
+} B1;
+
+// CHECK: Type: struct B1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 24]>
+
+typedef struct C1 {
+ char x;
+ short a : 4;
+ int : 0;
+ char y;
+} C1;
+
+// CHECK: Type: struct C1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 24, 24]>
+
+typedef struct D1 {
+ char x;
+ short : 0;
+ int : 0;
+ char y;
+} D1;
+
+// CHECK: Type: struct D1
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 8]>
+
+typedef union E1 {
+ char x;
+ long long a : 3;
+ int b : 3;
+ long long : 0;
+ short y;
+} E1;
+
+// CHECK: Type: union E1
+// CHECK: Size:64
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct F1 {
+ char x;
+ char a : 3;
+ char b : 3;
+ char c : 3;
+ short d : 6;
+ short e : 6;
+ short f : 6;
+ short g : 11;
+ short h : 11;
+ short i : 11;
+ short y;
+} F1;
+
+// CHECK: Type: struct F1
+// CHECK: Size:120
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 11, 16, 24, 30, 40, 56, 72, 88, 104]>
+
+typedef union G1 {
+ char x;
+ int a : 3;
+ int : 0;
+ long long : 0;
+ short y;
+} G1;
+
+// CHECK: Type: union G1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct H1 {
+ unsigned long a : 1;
+ unsigned char : 0;
+ unsigned long : 0;
+ unsigned long c : 1;
+} H1;
+
+// CHECK: Type: struct H1
+// CHECK: Size:64
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 32, 32, 32]>
+
+#pragma pack(pop)
+
+int x[
+sizeof(A ) +
+sizeof(B ) +
+sizeof(C ) +
+sizeof(D ) +
+sizeof(E ) +
+sizeof(F ) +
+sizeof(G ) +
+sizeof(H ) +
+sizeof(A1) +
+sizeof(B1) +
+sizeof(C1) +
+sizeof(D1) +
+sizeof(E1) +
+sizeof(F1) +
+sizeof(G1) +
+sizeof(H1) +
+0];
diff --git a/test/Sema/ms_class_layout.cpp b/test/Sema/ms_class_layout.cpp
index f48494733184..bb8052e12ec3 100644
--- a/test/Sema/ms_class_layout.cpp
+++ b/test/Sema/ms_class_layout.cpp
@@ -164,7 +164,7 @@ int main() {
// CHECK-NEXT: 0 | (D vftable pointer)
// CHECK-NEXT: 8 | double a
-// CHECK-NEXT: sizeof=16, dsize=16, align=8
+// CHECK-NEXT: sizeof=16, align=8
// CHECK-NEXT: nvsize=16, nvalign=8
// CHECK: %class.D = type { i32 (...)**, double }
@@ -173,7 +173,7 @@ int main() {
// CHECK-NEXT: 0 | (B vftable pointer)
// CHECK-NEXT: 4 | int b_field
-// CHECK-NEXT: sizeof=8, dsize=8, align=4
+// CHECK-NEXT: sizeof=8, align=4
// CHECK-NEXT: nvsize=8, nvalign=4
// CHECK: %class.B = type { i32 (...)**, i32 }
@@ -185,7 +185,7 @@ int main() {
// CHECK-NEXT: 8 | int a_field
// CHECK-NEXT: 12 | char one
-// CHECK-NEXT: sizeof=16, dsize=16, align=4
+// CHECK-NEXT: sizeof=16, align=4
// CHECK-NEXT: nvsize=16, nvalign=4
// CHECK: 0 | class C
@@ -207,7 +207,7 @@ int main() {
// CHECK-NEXT: 72 | int a_field
// CHECK-NEXT: 76 | char one
-// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: sizeof=80, align=8
// CHECK-NEXT: nvsize=64, nvalign=8
// CHECK: %class.A = type { %class.B, i32, i8 }
@@ -237,10 +237,10 @@ int main() {
// CHECK-NEXT: 88 | int a_field
// CHECK-NEXT: 92 | char one
-// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: sizeof=80, align=8
// CHECK-NEXT: nvsize=64, nvalign=8
-// CHECK: sizeof=96, dsize=96, align=8
+// CHECK: sizeof=96, align=8
// CHECK-NEXT: nvsize=96, nvalign=8
// CHECK: %struct.BaseStruct = type { double, float, %class.C }
@@ -267,18 +267,18 @@ int main() {
// CHECK-NEXT: 84 | int b_field
// CHECK-NEXT: 88 | int a_field
// CHECK-NEXT: 92 | char one
-// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: sizeof=80, align=8
// CHECK-NEXT: nvsize=64, nvalign=8
// CHECK: 96 | int x
-// CHECK-NEXT: sizeof=104, dsize=104, align=8
+// CHECK-NEXT: sizeof=104, align=8
// CHECK-NEXT: nvsize=104, nvalign=8
// CHECK: %struct.DerivedStruct = type { %struct.BaseStruct, i32 }
// CHECK: 0 | struct G
// CHECK-NEXT: 0 | int g_field
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | struct H
@@ -288,7 +288,7 @@ int main() {
// CHECK-NEXT: 8 | class D (virtual base)
// CHECK-NEXT: 8 | (D vftable pointer)
// CHECK-NEXT: 16 | double a
-// CHECK-NEXT: sizeof=24, dsize=24, align=8
+// CHECK-NEXT: sizeof=24, align=8
// CHECK-NEXT: nvsize=8, nvalign=4
// CHECK: %struct.H = type { %struct.G, i32*, %class.D }
@@ -300,7 +300,7 @@ int main() {
// CHECK-NEXT: 24 | class D (virtual base)
// CHECK-NEXT: 24 | (D vftable pointer)
// CHECK-NEXT: 32 | double a
-// CHECK-NEXT: sizeof=40, dsize=40, align=8
+// CHECK-NEXT: sizeof=40, align=8
// CHECK-NEXT: nvsize=24, nvalign=8
// CHECK: %struct.I = type { i32 (...)**, [4 x i8], i32*, double, %class.D }
@@ -308,12 +308,12 @@ int main() {
// CHECK: 0 | struct L
// CHECK-NEXT: 0 | int l
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | struct K
// CHECK-NEXT: 0 | int k
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | struct M
@@ -321,42 +321,42 @@ int main() {
// CHECK-NEXT: 4 | int m
// CHECK-NEXT: 8 | struct K (virtual base)
// CHECK-NEXT: 8 | int k
-// CHECK-NEXT: sizeof=12, dsize=12, align=4
+// CHECK-NEXT: sizeof=12, align=4
//CHECK: %struct.M = type { i32*, i32, %struct.K }
//CHECK: %struct.M.base = type { i32*, i32 }
// CHECK: 0 | struct N
+// CHECK-NEXT: 0 | (N vftable pointer)
// CHECK-NEXT: 4 | struct L (base)
// CHECK-NEXT: 4 | int l
// CHECK-NEXT: 8 | struct M (base)
// CHECK-NEXT: 8 | (M vbtable pointer)
// CHECK-NEXT: 12 | int m
-// CHECK-NEXT: 0 | (N vftable pointer)
// CHECK-NEXT: 16 | struct K (virtual base)
// CHECK-NEXT: 16 | int k
-// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: sizeof=20, align=4
// CHECK-NEXT: nvsize=16, nvalign=4
//CHECK: %struct.N = type { i32 (...)**, %struct.L, %struct.M.base, %struct.K }
-// FIXME: MSVC place struct H at offset 8.
// CHECK: 0 | struct O
-// CHECK-NEXT: 4 | struct H (base)
-// CHECK-NEXT: 4 | struct G (base)
-// CHECK-NEXT: 4 | int g_field
-// CHECK-NEXT: 8 | (H vbtable pointer)
-// CHECK-NEXT: 12 | struct G (base)
-// CHECK-NEXT: 12 | int g_field
// CHECK-NEXT: 0 | (O vftable pointer)
-// CHECK-NEXT: 16 | class D (virtual base)
-// CHECK-NEXT: 16 | (D vftable pointer)
-// CHECK-NEXT: 24 | double a
-// CHECK-NEXT: sizeof=32, dsize=32, align=8
-// CHECK-NEXT: nvsize=16, nvalign=4
+// CHECK-NEXT: 8 | struct H (base)
+// CHECK-NEXT: 8 | struct G (base)
+// CHECK-NEXT: 8 | int g_field
+// CHECK-NEXT: 12 | (H vbtable pointer)
+// CHECK-NEXT: 16 | struct G (base)
+// CHECK-NEXT: 16 | int g_field
+// CHECK-NEXT: 24 | class D (virtual base)
+// CHECK-NEXT: 24 | (D vftable pointer)
+// CHECK-NEXT: 32 | double a
+// CHECK-NEXT: | [sizeof=40, align=8
+// CHECK-NEXT: | nvsize=24, nvalign=8]
+
+// CHECK: struct.O = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8], %class.D }
+// CHECK: struct.O.base = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8] }
-//CHECK: %struct.O = type { i32 (...)**, %struct.H.base, %struct.G, %class.D }
-//CHECK: %struct.O.base = type { i32 (...)**, %struct.H.base, %struct.G }
// CHECK: 0 | struct P
// CHECK-NEXT: 0 | struct M (base)
@@ -367,20 +367,20 @@ int main() {
// CHECK-NEXT: 12 | int k
// CHECK-NEXT: 16 | struct L (virtual base)
// CHECK-NEXT: 16 | int l
-// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: sizeof=20, align=4
// CHECK-NEXT: nvsize=12, nvalign=4
//CHECK: %struct.P = type { %struct.M.base, i32, %struct.K, %struct.L }
// CHECK: 0 | struct R (empty)
-// CHECK-NEXT: sizeof=1, dsize=0, align=1
+// CHECK-NEXT: sizeof=1, align=1
// CHECK-NEXT: nvsize=0, nvalign=1
//CHECK: %struct.R = type { i8 }
// CHECK: 0 | struct f
// CHECK-NEXT: 0 | (f vftable pointer)
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | struct s
@@ -390,12 +390,12 @@ int main() {
// CHECK-NEXT: 12 | (vtordisp for vbase f)
// CHECK-NEXT: 16 | struct f (virtual base)
// CHECK-NEXT: 16 | (f vftable pointer)
-// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: sizeof=20, align=4
// CHECK-NEXT: nvsize=12, nvalign=4
// CHECK: 0 | class IA
// CHECK-NEXT: 0 | (IA vftable pointer)
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | class ICh
@@ -404,7 +404,7 @@ int main() {
// CHECK-NEXT: 8 | (vtordisp for vbase IA)
// CHECK-NEXT: 12 | class IA (virtual base)
// CHECK-NEXT: 12 | (IA vftable pointer)
-// CHECK-NEXT: sizeof=16, dsize=16, align=4
+// CHECK-NEXT: sizeof=16, align=4
// CHECK-NEXT: nvsize=8, nvalign=4
// CHECK: 0 | struct sd
@@ -424,7 +424,7 @@ int main() {
// CHECK-NEXT: 40 | class ICh (virtual base)
// CHECK-NEXT: 40 | (ICh vftable pointer)
// CHECK-NEXT: 44 | (ICh vbtable pointer)
-// CHECK-NEXT: sizeof=48, dsize=48, align=4
+// CHECK-NEXT: sizeof=48, align=4
// CHECK-NEXT: nvsize=12, nvalign=4
// CHECK: %struct.f = type { i32 (...)** }
@@ -435,14 +435,14 @@ int main() {
// CHECK: 0 | struct AV
// CHECK-NEXT: 0 | (AV vftable pointer)
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: 0 | struct BV
// CHECK-NEXT: 0 | struct AV (primary base)
// CHECK-NEXT: 0 | (AV vftable pointer)
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
@@ -452,7 +452,7 @@ int main() {
// CHECK-NEXT: 8 | struct BV (virtual base)
// CHECK-NEXT: 8 | struct AV (primary base)
// CHECK-NEXT: 8 | (AV vftable pointer)
-// CHECK-NEXT: sizeof=12, dsize=12, align=4
+// CHECK-NEXT: sizeof=12, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: %struct.AV = type { i32 (...)** }
@@ -464,7 +464,7 @@ int main() {
// CHECK-NEXT: 0 | struct BV (primary base)
// CHECK-NEXT: 0 | struct AV (primary base)
// CHECK-NEXT: 0 | (AV vftable pointer)
-// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: sizeof=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
// CHECK: %struct.DV = type { %struct.BV }
@@ -480,14 +480,14 @@ int main() {
// CHECK-NEXT: 12 | struct BV (virtual base)
// CHECK-NEXT: 12 | struct AV (primary base)
// CHECK-NEXT: 12 | (AV vftable pointer)
-// CHECK-NEXT: sizeof=16, dsize=16, align=4
+// CHECK-NEXT: sizeof=16, align=4
// CHECK-NEXT: nvsize=8, nvalign=4
// CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, [4 x i8], %struct.BV }
// CHECK: %struct.EV.base = type { %struct.DV, %struct.CV.base }
// Overriding a method means that all the vbases containing that
-// method need a vtordisp.
+// method need a vtordisp. Note: this code will cause an error in cl.exe.
namespace test1 {
struct A { virtual void foo(); };
struct B : A {};
@@ -503,6 +503,6 @@ namespace test1 {
// CHECK-NEXT: 16 | struct test1::B (virtual base)
// CHECK-NEXT: 16 | struct test1::A (primary base)
// CHECK-NEXT: 16 | (A vftable pointer)
-// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: sizeof=20, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
}
diff --git a/test/Sema/neon-vector-types-support.c b/test/Sema/neon-vector-types-support.c
new file mode 100644
index 000000000000..6bf8539e47bd
--- /dev/null
+++ b/test/Sema/neon-vector-types-support.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -triple armv7 -fsyntax-only -verify
+
+typedef __attribute__((neon_vector_type(2))) int int32x2_t; // expected-error{{'neon_vector_type' attribute is not supported for this target}}
+typedef __attribute__((neon_polyvector_type(16))) short poly8x16_t; // expected-error{{'neon_polyvector_type' attribute is not supported for this target}}
diff --git a/test/Sema/neon-vector-types.c b/test/Sema/neon-vector-types.c
index cbf013398a26..d8dd41225a32 100644
--- a/test/Sema/neon-vector-types.c
+++ b/test/Sema/neon-vector-types.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple armv7 -target-feature +neon -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple armv8 -target-feature +neon -fsyntax-only -verify
typedef float float32_t;
typedef signed char poly8_t;
@@ -16,10 +17,10 @@ typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
// The attributes must have a single argument.
-typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{attribute takes one argument}}
+typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{'neon_vector_type' attribute takes one argument}}
// The number of elements must be an ICE.
-typedef __attribute__((neon_vector_type(2.0))) int non_int_width; // expected-error{{attribute requires integer constant}}
+typedef __attribute__((neon_vector_type(2.0))) int non_int_width; // expected-error{{'neon_vector_type' attribute requires an integer constant}}
// Only certain element types are allowed.
typedef __attribute__((neon_vector_type(2))) double double_elt; // expected-error{{invalid vector element type}}
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
index cea8e3d0ddc4..4e6171160f64 100644
--- a/test/Sema/nonnull.c
+++ b/test/Sema/nonnull.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://9584012
typedef struct {
@@ -19,3 +19,4 @@ int main(void) {
Class_init(obj, "Hello World");
}
+void foo(const char *str) __attribute__((nonnull("foo"))); // expected-error{{'nonnull' attribute requires parameter 1 to be an integer constant}}
diff --git a/test/Sema/offsetof-64.c b/test/Sema/offsetof-64.c
new file mode 100644
index 000000000000..4a80dee2fc2f
--- /dev/null
+++ b/test/Sema/offsetof-64.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu
+
+// PR15216
+// Don't crash when taking computing the offset of structs with large arrays.
+const unsigned long Size = (1l << 60);
+
+struct Chunk1 {
+ char padding[Size];
+ char more_padding[1][Size];
+ char data;
+};
+
+int test1 = __builtin_offsetof(struct Chunk1, data);
+
+struct Chunk2 {
+ char padding[Size][Size][Size]; // expected-error 2{{array is too large}}
+ char data;
+};
+
+// FIXME: Remove this error when the constant evaluator learns to
+// ignore bad types.
+int test2 = __builtin_offsetof(struct Chunk2, data); // expected-error{{initializer element is not a compile-time constant}}
diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c
index 46fb515c7f2e..9e876ad5898e 100644
--- a/test/Sema/offsetof.c
+++ b/test/Sema/offsetof.c
@@ -69,3 +69,4 @@ int test4 = __builtin_offsetof(Array, array);
int test5() {
return __builtin_offsetof(Array, array[*(int*)0]); // expected-warning{{indirection of non-volatile null pointer}} expected-note{{__builtin_trap}}
}
+
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
index 5d39f15ec81f..b93c39fc1a2d 100644
--- a/test/Sema/overloadable.c
+++ b/test/Sema/overloadable.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute can only be applied to a function}}
+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}}
@@ -65,7 +66,22 @@ extern int __attribute__((overloadable)) f0(); // expected-error{{'overloadable'
typedef int f1_type();
f1_type __attribute__((overloadable)) f1; // expected-error{{'overloadable' function 'f1' must have a prototype}}
-void test() {
+void test() {
f0();
f1();
}
+
+void before_local_1(int) __attribute__((overloadable)); // expected-note {{here}}
+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_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_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_3(int) __attribute__((overloadable));
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index 300e58558867..b7f1b6e93aa5 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -118,5 +118,5 @@ void conditional_op(int x, int y, _Bool b) {
(void)(x % 2 ? 1 : 2); // no warning
}
-// RUN: %clang_cc1 -fsyntax-only -Wparentheses -Werror -fdiagnostics-show-option %s 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG
+// RUN: not %clang_cc1 -fsyntax-only -Wparentheses -Werror -fdiagnostics-show-option %s 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG
// CHECK-FLAG: error: using the result of an assignment as a condition without parentheses [-Werror,-Wparentheses]
diff --git a/test/Sema/pragma-weak.c b/test/Sema/pragma-weak.c
new file mode 100644
index 000000000000..c14125eac9f7
--- /dev/null
+++ b/test/Sema/pragma-weak.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
+
+void __both3(void);
+#pragma weak both3 = __both3 // expected-note {{previous definition}}
+void both3(void) __attribute((alias("__both3"))); // expected-error {{redefinition of 'both3'}}
+void __both3(void) {}
+
+void __a3(void) __attribute((noinline));
+#pragma weak a3 = __a3 // expected-note {{previous definition}}
+void a3(void) __attribute((alias("__a3"))); // expected-error {{redefinition of 'a3'}}
+void __a3(void) {}
diff --git a/test/Sema/string-init.c b/test/Sema/string-init.c
new file mode 100644
index 000000000000..96ee360e4452
--- /dev/null
+++ b/test/Sema/string-init.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -triple x86_64-pc-linux -verify %s
+
+// Note: these match the types specified by the target above.
+typedef int wchar_t;
+typedef unsigned short char16_t;
+typedef unsigned int char32_t;
+
+void f() {
+ char a1[] = "a"; // No error.
+ char a2[] = u8"a"; // No error.
+ char a3[] = u"a"; // expected-error{{initializing char array with wide string literal}}
+ char a4[] = U"a"; // expected-error{{initializing char array with wide string literal}}
+ char a5[] = L"a"; // expected-error{{initializing char array with wide string literal}}
+
+ wchar_t b1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ wchar_t b2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ wchar_t b3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ wchar_t b4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ wchar_t b5[] = L"a"; // No error.
+
+ char16_t c1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char16_t c2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char16_t c3[] = u"a"; // No error.
+ char16_t c4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ char16_t c5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+
+ char32_t d1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char32_t d2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char32_t d3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ char32_t d4[] = U"a"; // No error.
+ char32_t d5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+
+ int e1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ int e2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ int e3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ int e4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ int e5[] = L"a"; // No error.
+
+ long f1[] = "a"; // expected-error{{array initializer must be an initializer list}}
+ long f2[] = u8"a"; // expected-error{{array initializer must be an initializer list}}}
+ long f3[] = u"a"; // expected-error{{array initializer must be an initializer list}}
+ long f4[] = U"a"; // expected-error{{array initializer must be an initializer list}}
+ long f5[] = L"a"; // expected-error{{array initializer must be an initializer list}}
+}
+
+void g() {
+ char a[] = 1; // expected-error{{array initializer must be an initializer list or string literal}}
+ wchar_t b[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+ char16_t c[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+ char32_t d[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+}
diff --git a/test/Sema/string-plus-char.c b/test/Sema/string-plus-char.c
new file mode 100644
index 000000000000..322e8f5962be
--- /dev/null
+++ b/test/Sema/string-plus-char.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f(const char *s) {
+ char *str = 0;
+ char *str2 = str + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ const char *constStr = s + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ str = 'c' + str;// expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ // no-warning
+ char c = 'c';
+ str = str + c;
+ str = c + str;
+}
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 819e856ac8cb..8d3d74de7671 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -57,3 +57,12 @@ const struct test2 { // expected-warning {{'const' ignored on this declaration}}
inline struct test3 { // expected-error {{'inline' can only appear on functions}}
int x;
};
+
+struct hiding_1 {};
+struct hiding_2 {};
+void test_hiding() {
+ struct hiding_1 *hiding_1();
+ extern struct hiding_2 *hiding_2;
+ struct hiding_1 *p = hiding_1();
+ struct hiding_2 *q = hiding_2;
+}
diff --git a/test/Sema/thread-specifier.c b/test/Sema/thread-specifier.c
index 9d516e8f1413..bf1ce9e26e4a 100644
--- a/test/Sema/thread-specifier.c
+++ b/test/Sema/thread-specifier.c
@@ -2,8 +2,8 @@
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DGNU
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic %s -DC11 -D__thread=_Thread_local
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DC11 -D__thread=_Thread_local
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DCXX11 -D__thread=thread_local -std=c++11
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DC11 -D__thread=_Thread_local -std=c++11
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DCXX11 -D__thread=thread_local -std=c++11 -Wno-deprecated
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic -x c++ %s -DC11 -D__thread=_Thread_local -std=c++11 -Wno-deprecated
#ifdef __cplusplus
// In C++, we define __private_extern__ to extern.
diff --git a/test/Sema/types.c b/test/Sema/types.c
index d0637cca61a2..dac0bfe9fe82 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -64,3 +64,11 @@ void test(int i) {
void test2(int i) {
char c = (char __attribute__((may_alias))) i;
}
+
+// vector size too large
+int __attribute__ ((vector_size(8192))) x1; // expected-error {{vector size too large}}
+typedef int __attribute__ ((ext_vector_type(8192))) x2; // expected-error {{vector size too large}}
+
+// no support for vector enum type
+enum { e_2 } x3 __attribute__((vector_size(64))); // expected-error {{invalid vector element type}}
+
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
index 663d3d594758..5329c2e61c98 100644
--- a/test/Sema/varargs.c
+++ b/test/Sema/varargs.c
@@ -76,3 +76,10 @@ void f9(__builtin_va_list args)
(void)__builtin_va_arg(args, short); // expected-warning {{second argument to 'va_arg' is of promotable type 'short'}}
(void)__builtin_va_arg(args, char); // expected-warning {{second argument to 'va_arg' is of promotable type 'char'}}
}
+
+void f10(int a, ...) {
+ int i;
+ __builtin_va_list ap;
+ i = __builtin_va_start(ap, a); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ __builtin_va_end(ap);
+}
diff --git a/test/Sema/varargs.cpp b/test/Sema/varargs.cpp
new file mode 100644
index 000000000000..48a7b2fdf103
--- /dev/null
+++ b/test/Sema/varargs.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+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 {{'va_start' has undefined behavior with reference types}}
+}
diff --git a/test/Sema/vfprintf-valid-redecl.c b/test/Sema/vfprintf-valid-redecl.c
index 5c5ce8d12b00..8ed18786ab7e 100644
--- a/test/Sema/vfprintf-valid-redecl.c
+++ b/test/Sema/vfprintf-valid-redecl.c
@@ -1,7 +1,16 @@
// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify
+// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify -DPREDECLARE
// expected-no-diagnostics
-// PR4290
+#ifdef PREDECLARE
+// PR16344
+// Clang has defined 'vfprint' in builtin list. If the following line occurs before any other
+// `vfprintf' in this file, and we getPreviousDecl()->getTypeSourceInfo() on it, then we will
+// get a null pointer since the one in builtin list doesn't has valid TypeSourceInfo.
+int vfprintf(void) { return 0; }
+#endif
+
+// PR4290
// The following declaration is compatible with vfprintf, so we shouldn't
// warn.
int vfprintf();
diff --git a/test/Sema/warn-documentation-fixits.cpp b/test/Sema/warn-documentation-fixits.cpp
index a47b77637506..675d86c366db 100644
--- a/test/Sema/warn-documentation-fixits.cpp
+++ b/test/Sema/warn-documentation-fixits.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fcomment-block-commands=foobar -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// expected-warning@+1 {{parameter 'ZZZZZZZZZZ' not found in the function declaration}} expected-note@+1 {{did you mean 'a'?}}
/// \param ZZZZZZZZZZ Blah blah.
@@ -57,6 +57,24 @@ struct test_deprecated_6 {
/// \deprecated
void test_deprecated_9(int a);
+// rdar://12381408
+// expected-warning@+2 {{unknown command tag name 'retur'; did you mean 'return'?}}
+/// \brief testing fixit
+/// \retur int in FooBar
+int FooBar();
+
+// expected-warning@+1 {{unknown command tag name 'fooba'; did you mean 'foobar'?}}
+/// \fooba bbb IS_DOXYGEN_END
+int gorf();
+
+/// \t bbb IS_DOXYGEN_END
+int Bar();
+
+// expected-warning@+2 {{unknown command tag name 'encode'; did you mean 'endcode'?}}
+// expected-warning@+1 {{'\endcode' command does not terminate a verbatim text block}}
+/// \encode PR18051
+int PR18051();
+
// CHECK: fix-it:"{{.*}}":{5:12-5:22}:"a"
// CHECK: fix-it:"{{.*}}":{9:12-9:15}:"aaa"
// CHECK: fix-it:"{{.*}}":{13:13-13:23}:"T"
@@ -68,4 +86,6 @@ void test_deprecated_9(int a);
// CHECK: fix-it:"{{.*}}":{46:27-46:27}:" __attribute__((deprecated))"
// CHECK: fix-it:"{{.*}}":{50:27-50:27}:" __attribute__((deprecated))"
// CHECK: fix-it:"{{.*}}":{58:30-58:30}:" MY_ATTR_DEPRECATED"
-
+// CHECK: fix-it:"{{.*}}":{63:6-63:11}:"return"
+// CHECK: fix-it:"{{.*}}":{67:6-67:11}:"foobar"
+// CHECK: fix-it:"{{.*}}":{75:6-75:12}:"endcode"
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index b3ab0199dcb4..7166a4990945 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -136,37 +136,33 @@ int test_duplicate_brief2(int);
int test_duplicate_brief3(int);
-// expected-warning@+5 {{duplicated command '\return'}} expected-note@+1 {{previous command '\return' here}}
/// \return Aaa
///
/// Bbb
///
/// \return Ccc
-int test_duplicate_returns1(int);
+int test_multiple_returns1(int);
-// expected-warning@+5 {{duplicated command '\returns'}} expected-note@+1 {{previous command '\returns' here}}
/// \returns Aaa
///
/// Bbb
///
/// \returns Ccc
-int test_duplicate_returns2(int);
+int test_multiple_returns2(int);
-// expected-warning@+5 {{duplicated command '\result'}} expected-note@+1 {{previous command '\result' here}}
/// \result Aaa
///
/// Bbb
///
/// \result Ccc
-int test_duplicate_returns3(int);
+int test_multiple_returns3(int);
-// expected-warning@+5 {{duplicated command '\return'}} expected-note@+1 {{previous command '\returns' (an alias of '\return') here}}
/// \returns Aaa
///
/// Bbb
///
/// \return Ccc
-int test_duplicate_returns4(int);
+int test_multiple_returns4(int);
// expected-warning@+1 {{'\param' command used in a comment that is not attached to a function declaration}}
@@ -309,6 +305,22 @@ typedef test_param27 test_param28;
typedef unsigned int test_param29;
+/// \param aaa Aaa
+/// \param ... Vararg
+int test_vararg_param1(int aaa, ...);
+
+/// \param ... Vararg
+int test_vararg_param2(...);
+
+// expected-warning@+1 {{parameter '...' not found in the function declaration}} expected-note@+1 {{did you mean 'aaa'?}}
+/// \param ... Vararg
+int test_vararg_param3(int aaa);
+
+// expected-warning@+1 {{parameter '...' not found in the function declaration}}
+/// \param ... Vararg
+int test_vararg_param4();
+
+
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
/// \tparam T Aaa
int test_tparam1;
@@ -592,6 +604,25 @@ int test4; ///< \brief
///< \author Aaa
+class TestRelates {};
+
+/// \relates TestRelates
+/// \brief Aaa
+void test_relates_1();
+
+/// \related TestRelates
+/// \brief Aaa
+void test_relates_2();
+
+/// \relatesalso TestRelates
+/// \brief Aaa
+void test_relates_3();
+
+/// \relatedalso TestRelates
+/// \brief Aaa
+void test_relates_4();
+
+
// Check that we attach the comment to the declaration during parsing in the
// following cases. The test is based on the fact that we don't parse
// documentation comments that are not attached to anything.
@@ -950,3 +981,47 @@ class C1;
@struct S3;
*/
class S3;
+
+// rdar://14124702
+//----------------------------------------------------------------------
+/// @class Predicate Predicate.h "lldb/Host/Predicate.h"
+/// @brief A C++ wrapper class for providing threaded access to a value
+/// of type T.
+///
+/// A templatized class.
+/// specified values.
+//----------------------------------------------------------------------
+template <class T, class T1>
+class Predicate
+{
+};
+
+//----------------------------------------------------------------------
+/// @class Predicate<int, char> Predicate.h "lldb/Host/Predicate.h"
+/// @brief A C++ wrapper class for providing threaded access to a value
+/// of type T.
+///
+/// A template specilization class.
+//----------------------------------------------------------------------
+template<> class Predicate<int, char>
+{
+};
+
+//----------------------------------------------------------------------
+/// @class Predicate<T, int> Predicate.h "lldb/Host/Predicate.h"
+/// @brief A C++ wrapper class for providing threaded access to a value
+/// of type T.
+///
+/// A partial specialization template class.
+//----------------------------------------------------------------------
+template<class T> class Predicate<T, int>
+{
+};
+
+/*! @function test_function
+*/
+template <class T> T test_function (T arg);
+
+/*! @function test_function<int>
+*/
+template <> int test_function<int> (int arg);
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index 0737a8dedd03..5e95e2a1e8a2 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -172,3 +172,60 @@ struct S;
@struct S1 THIS IS IT
*/
@interface S1 @end
+
+// expected-warning@+1 {{unknown command tag name}}
+/// \t bbb IS_DOXYGEN_END
+int FooBar();
+
+// rdar://13836387
+/** \brief Module handling the incoming notifications from the system.
+ *
+ * This includes:
+ * - Network Reachability
+ * - Power State
+ * - Low Disk
+ */
+@interface BRC : NSObject
+- (void)removeReach:(NSObject*)observer;
+@end
+
+@implementation BRC : NSObject
+- (void)removeReach:(NSObject*)observer // expected-note {{previous declaration is here}}
+{
+}
+- (void)removeReach:(NSObject*)observer // expected-error {{duplicate declaration of method 'removeReach:'}}
+{
+}
+@end
+
+// rdar://13927330
+/// @class Asset <- '@class' may be used in a comment attached to a an interface declaration
+@interface Asset : NSObject
+@end
+
+// rdar://14024851 Check that this does not enter an infinite loop
+@interface rdar14024851
+-(void)meth; // expected-note {{declared here}}
+@end
+
+@implementation rdar14024851 // expected-warning {{method definition for 'meth' not found}} expected-note {{previous definition}}
+@end
+
+@implementation rdar14024851 // expected-error {{reimplementation}}
+/// \brief comment
+-(void)meth {}
+@end
+
+// rdar://14124644
+@interface test_vararg1
+/// @param[in] arg somthing
+/// @param[in] ... This is vararg
+- (void) VarArgMeth : (id)arg, ...;
+@end
+
+@implementation test_vararg1
+/// @param[in] arg somthing
+/// @param[in] ... This is vararg
+- (void) VarArgMeth : (id)arg, ... {}
+@end
+
diff --git a/test/Sema/warn-main-return-type.c b/test/Sema/warn-main-return-type.c
index bd7c59f2d390..c6f3a0c1011a 100644
--- a/test/Sema/warn-main-return-type.c
+++ b/test/Sema/warn-main-return-type.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
// expected-note@+1 5{{previous definition is here}}
int main() {
diff --git a/test/Sema/warn-main.c b/test/Sema/warn-main.c
index 8a4eafc1325c..58a6dfde108d 100644
--- a/test/Sema/warn-main.c
+++ b/test/Sema/warn-main.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
// expected-note@+1 2{{previous definition is here}}
int main() {
@@ -14,16 +14,14 @@ static int main() {
return 0;
}
-// expected-error@+3 {{redefinition of 'main'}}
-// expected-error@+2 {{'main' is not allowed to be declared inline}}
-// expected-note@+1 {{previous definition is here}}
+// expected-error@+2 {{redefinition of 'main'}}
+// expected-error@+1 {{'main' is not allowed to be declared inline}}
inline int main() {
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:8}:""
return 0;
}
-// expected-warning@+6 {{function 'main' declared 'noreturn' should not return}}
-// expected-error@+3 {{redefinition of 'main'}}
+// expected-warning@+5 {{function 'main' declared 'noreturn' should not return}}
// expected-warning@+2 {{'main' is not allowed to be declared _Noreturn}}
// expected-note@+1 {{remove '_Noreturn'}}
_Noreturn int main() {
diff --git a/test/Sema/warn-null.c b/test/Sema/warn-null.c
new file mode 100644
index 000000000000..28fb6a5f691c
--- /dev/null
+++ b/test/Sema/warn-null.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -verify
+
+// PR10837: Warn if a non-pointer-typed expression is folded to a null pointer
+int *p = 0;
+int *q = '\0'; // expected-warning{{expression which evaluates to zero treated as a null pointer constant}}
+int *r = (1 - 1); // expected-warning{{expression which evaluates to zero treated as a null pointer constant}}
+void f() {
+ p = 0;
+ q = '\0'; // expected-warning{{expression which evaluates to zero treated as a null pointer constant}}
+ r = 1 - 1; // expected-warning{{expression which evaluates to zero treated as a null pointer constant}}
+}
diff --git a/test/Sema/warn-outof-range-assign-enum.c b/test/Sema/warn-outof-range-assign-enum.c
index 2e79e66f49bd..43eea0cef41f 100644
--- a/test/Sema/warn-outof-range-assign-enum.c
+++ b/test/Sema/warn-outof-range-assign-enum.c
@@ -21,6 +21,18 @@ enum Test2 test2(enum Test2 *t) {
return 10; // expected-warning {{integer constant not in range of enumerated type 'enum Test2'}}
}
+// PR15069
+typedef enum
+{
+ a = 0
+} T;
+
+void f()
+{
+ T x = a;
+ x += 1; // expected-warning {{integer constant not in range of enumerated type}}
+}
+
int main() {
CCTestEnum test = 1; // expected-warning {{integer constant not in range of enumerated type 'CCTestEnum'}}
test = 600; // expected-warning {{integer constant not in range of enumerated type 'CCTestEnum'}}
diff --git a/test/Sema/warn-shadow-intrinsics.c b/test/Sema/warn-shadow-intrinsics.c
new file mode 100644
index 000000000000..b291426395c9
--- /dev/null
+++ b/test/Sema/warn-shadow-intrinsics.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-apple-macosx10.8.0 -fsyntax-only %s
+
+#include <emmintrin.h>
+
+// Test that using two macros from emmintrin do not cause a
+// useless -Wshadow warning.
+void rdar10679282() {
+ __m128i qf = _mm_setzero_si128();
+ qf = _mm_slli_si128(_mm_add_epi64(qf, _mm_srli_si128(qf, 8)), 8); // no-warning
+ (void) qf;
+}
diff --git a/test/Sema/warn-thread-safety-analysis.c b/test/Sema/warn-thread-safety-analysis.c
new file mode 100644
index 000000000000..1918aceee6da
--- /dev/null
+++ b/test/Sema/warn-thread-safety-analysis.c
@@ -0,0 +1,123 @@
+// RUN: %clang -fsyntax-only -verify -Wthread-safety -Wthread-safety-beta -fcxx-exceptions %s
+
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#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__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
+#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__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) \
+ __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+
+// Define the mutex struct.
+// Simplified only for test purpose.
+struct LOCKABLE Mutex {};
+
+struct Foo {
+ struct Mutex *mu_;
+};
+
+// Define mutex lock/unlock functions.
+void mutex_exclusive_lock(struct Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) {
+}
+
+void mutex_shared_lock(struct Mutex *mu) SHARED_LOCK_FUNCTION(mu) {
+}
+
+void mutex_unlock(struct Mutex *mu) UNLOCK_FUNCTION(mu) {
+}
+
+// Define global variables.
+struct Mutex mu1;
+struct Mutex mu2 ACQUIRED_AFTER(mu1);
+struct Foo foo_ = {&mu1};
+int a_ GUARDED_BY(foo_.mu_);
+int *b_ PT_GUARDED_BY(foo_.mu_) = &a_;
+int c_ GUARDED_VAR;
+int *d_ PT_GUARDED_VAR = &c_;
+
+// Define test functions.
+int Foo_fun1(int i) SHARED_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1) {
+ return i;
+}
+
+int Foo_fun2(int i) EXCLUSIVE_LOCKS_REQUIRED(mu2) SHARED_LOCKS_REQUIRED(mu1) {
+ return i;
+}
+
+int Foo_func3(int i) LOCKS_EXCLUDED(mu1, mu2) {
+ return i;
+}
+
+static int Bar_fun1(int i) EXCLUSIVE_LOCKS_REQUIRED(mu1) {
+ return i;
+}
+
+void set_value(int *a, int value) EXCLUSIVE_LOCKS_REQUIRED(foo_.mu_) {
+ *a = value;
+}
+
+int get_value(int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){
+ return *p;
+}
+
+int main() {
+
+ Foo_fun1(1); // expected-warning{{calling function 'Foo_fun1' requires shared lock on 'mu2'}} \
+ expected-warning{{calling function 'Foo_fun1' requires exclusive lock on 'mu1'}}
+
+ mutex_exclusive_lock(&mu1);
+ mutex_shared_lock(&mu2);
+ Foo_fun1(1);
+
+ mutex_shared_lock(&mu1); // expected-warning{{locking 'mu1' that is already locked}}
+ mutex_unlock(&mu1);
+ mutex_unlock(&mu2);
+ mutex_shared_lock(&mu1);
+ mutex_exclusive_lock(&mu2);
+ Foo_fun2(2);
+
+ mutex_unlock(&mu2);
+ mutex_unlock(&mu1);
+ mutex_exclusive_lock(&mu1);
+ Bar_fun1(3);
+ mutex_unlock(&mu1);
+
+ mutex_exclusive_lock(&mu1);
+ Foo_func3(4); // expected-warning{{cannot call function 'Foo_func3' while mutex 'mu1' is locked}}
+ mutex_unlock(&mu1);
+
+ Foo_func3(5);
+
+ set_value(&a_, 0); // expected-warning{{calling function 'setA' requires exclusive lock on 'foo_.mu_'}}
+ get_value(b_); // expected-warning{{calling function 'getB' requires shared lock on 'foo_.mu_'}}
+ mutex_exclusive_lock(foo_.mu_);
+ set_value(&a_, 1);
+ mutex_unlock(foo_.mu_);
+ mutex_shared_lock(foo_.mu_);
+ (void)(get_value(b_) == 1);
+ mutex_unlock(foo_.mu_);
+
+ c_ = 0; // expected-warning{{writing variable 'c_' requires locking any mutex exclusively}}
+ (void)(*d_ == 0); // expected-warning{{reading the value pointed to by 'd_' requires locking any mutex}}
+ mutex_exclusive_lock(foo_.mu_);
+ c_ = 1;
+ (void)(*d_ == 1);
+ mutex_unlock(foo_.mu_);
+
+ return 0;
+}
diff --git a/test/Sema/warn-type-safety.c b/test/Sema/warn-type-safety.c
index 4ac453d380bd..dfab8f8c818b 100644
--- a/test/Sema/warn-type-safety.c
+++ b/test/Sema/warn-type-safety.c
@@ -7,7 +7,7 @@ struct A {};
typedef struct A *MPI_Datatype;
int wrong1(void *buf, MPI_Datatype datatype)
- __attribute__(( pointer_with_type_tag )); // expected-error {{attribute requires parameter 1 to be an identifier}}
+ __attribute__(( pointer_with_type_tag )); // expected-error {{'pointer_with_type_tag' attribute requires parameter 1 to be an identifier}}
int wrong2(void *buf, MPI_Datatype datatype)
__attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}}
@@ -39,7 +39,7 @@ int wrong10(double buf, MPI_Datatype type)
extern struct A datatype_wrong1
- __attribute__(( type_tag_for_datatype )); // expected-error {{attribute requires parameter 1 to be an identifier}}
+ __attribute__(( type_tag_for_datatype )); // expected-error {{'type_tag_for_datatype' attribute requires parameter 1 to be an identifier}}
extern struct A datatype_wrong2
__attribute__(( type_tag_for_datatype(mpi,1,2) )); // expected-error {{expected a type}}
diff --git a/test/Sema/warn-unsequenced.c b/test/Sema/warn-unsequenced.c
new file mode 100644
index 000000000000..a14d3281662b
--- /dev/null
+++ b/test/Sema/warn-unsequenced.c
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Wno-unused %s
+
+int f(int, int);
+
+typedef struct A {
+ int x, y;
+} A;
+
+void test() {
+ int a;
+ int xs[10];
+ a + ++a; // expected-warning {{unsequenced modification and access to 'a'}}
+ a = ++a; // expected-warning {{multiple unsequenced modifications to 'a'}}
+ a + a++; // expected-warning {{unsequenced modification and access to 'a'}}
+ a = a++; // expected-warning {{multiple unsequenced modifications to 'a'}}
+ (a++, a++); // ok
+ ++a + ++a; // expected-warning {{multiple unsequenced modifications}}
+ a++ + a++; // expected-warning {{multiple unsequenced modifications}}
+ a = xs[++a]; // expected-warning {{multiple unsequenced modifications}}
+ a = xs[a++]; // expected-warning {{multiple unsequenced modifications}}
+ a = (++a, ++a); // expected-warning {{multiple unsequenced modifications}}
+ a = (a++, ++a); // expected-warning {{multiple unsequenced modifications}}
+ a = (a++, a++); // expected-warning {{multiple unsequenced modifications}}
+ f(a, a); // ok
+ f(a = 0, a); // expected-warning {{unsequenced modification and access}}
+ f(a, a += 0); // expected-warning {{unsequenced modification and access}}
+ f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
+ a = f(++a, 0); // ok
+ a = f(a++, 0); // ok
+ a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}
+
+ a = ++a; // expected-warning {{multiple unsequenced modifications}}
+ a += ++a; // expected-warning {{unsequenced modification and access}}
+
+ A agg1 = { a++, a++ }; // expected-warning {{multiple unsequenced modifications}}
+ A agg2 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}
+
+ (xs[2] && (a = 0)) + a; // ok
+ (0 && (a = 0)) + a; // ok
+ (1 && (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
+
+ (xs[3] || (a = 0)) + a; // ok
+ (0 || (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
+ (1 || (a = 0)) + a; // ok
+
+ (xs[4] ? a : ++a) + a; // ok
+ (0 ? a : ++a) + a; // expected-warning {{unsequenced modification and access}}
+ (1 ? a : ++a) + a; // ok
+ (xs[5] ? ++a : ++a) + a; // FIXME: warn here
+
+ (++a, xs[6] ? ++a : 0) + a; // FIXME: warn here
+
+ // Here, the read of the fourth 'a' might happen before or after the write to
+ // the second 'a'.
+ a += (a++, a) + a; // expected-warning {{unsequenced modification and access}}
+
+ int *p = xs;
+ a = *(a++, p); // ok
+ a = a++ && a; // ok
+
+ A *q = &agg1;
+ (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and access to 'q'}}
+
+ // This has undefined behavior if a == 0; otherwise, the side-effect of the
+ // increment is sequenced before the value computation of 'f(a, a)', which is
+ // sequenced before the value computation of the '&&', which is sequenced
+ // before the assignment. We treat the sequencing in '&&' as being
+ // unconditional.
+ a = a++ && f(a, a);
+
+ // This has undefined behavior if a != 0. FIXME: We should diagnose this.
+ (a && a++) + a;
+
+ (xs[7] && ++a) * (!xs[7] && ++a); // ok
+
+ xs[0] = (a = 1, a); // ok
+
+ xs[8] ? ++a + a++ : 0; // expected-warning {{multiple unsequenced modifications}}
+ xs[8] ? 0 : ++a + a++; // expected-warning {{multiple unsequenced modifications}}
+ xs[8] ? ++a : a++; // ok
+
+ xs[8] && (++a + a++); // expected-warning {{multiple unsequenced modifications}}
+ xs[8] || (++a + a++); // expected-warning {{multiple unsequenced modifications}}
+
+ (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
+ (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
+ (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // FIXME: warn here
+}
diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c
index a334e71e5067..013b925f89d8 100644
--- a/test/Sema/warn-unused-function.c
+++ b/test/Sema/warn-unused-function.c
@@ -12,10 +12,8 @@ int x = sizeof(f0());
static void f3();
extern void f3() { } // expected-warning{{unused}}
-// FIXME: This will trigger a warning when it should not.
-// Update once PR6281 is fixed.
-//inline static void f4();
-//void f4() { }
+inline static void f4();
+void f4() { } // expected-warning{{unused}}
static void __attribute__((used)) f5() {}
static void f6();
diff --git a/test/Sema/warn-unused-label.c b/test/Sema/warn-unused-label.c
index 48370a5fd641..4b1dbbf24692 100644
--- a/test/Sema/warn-unused-label.c
+++ b/test/Sema/warn-unused-label.c
@@ -9,3 +9,7 @@ void f() {
goto d;
return;
}
+
+void PR8455() {
+ L: __attribute__((unused)) return; // ok, no semicolon required
+}
diff --git a/test/Sema/warn-unused-parameters.c b/test/Sema/warn-unused-parameters.c
index af048e77e886..11db7300c5c4 100644
--- a/test/Sema/warn-unused-parameters.c
+++ b/test/Sema/warn-unused-parameters.c
@@ -22,7 +22,7 @@ static void achor() {};
// CHECK-unused: 1 warning generated
// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything %s 2>&1 | FileCheck -check-prefix=CHECK-everything %s
-// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything -Werror %s 2>&1 | FileCheck -check-prefix=CHECK-everything-error %s
+// RUN: not %clang_cc1 -fblocks -fsyntax-only -Weverything -Werror %s 2>&1 | FileCheck -check-prefix=CHECK-everything-error %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything -Wno-unused %s 2>&1 | FileCheck -check-prefix=CHECK-everything-no-unused %s
// CHECK-everything: 6 warnings generated
// CHECK-everything-error: 5 errors generated
diff --git a/test/Sema/warn-variable-not-needed.c b/test/Sema/warn-variable-not-needed.c
new file mode 100644
index 000000000000..472ac8298999
--- /dev/null
+++ b/test/Sema/warn-variable-not-needed.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+// expected-no-diagnostics
+
+static int a;
+int bar() {
+ extern int a;
+ return a;
+}
+static int a;
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
index 816245f3c041..13c2f5855d5e 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -19,6 +19,6 @@ int check_wchar_size[sizeof(*L"") == sizeof(wchar_t) ? 1 : -1];
void foo() {
WCHAR_T_TYPE t1[] = L"x";
wchar_t tab[] = L"x";
- WCHAR_T_TYPE t2[] = "x"; // expected-error {{initializer}}
- char t3[] = L"x"; // expected-error {{initializer}}
+ WCHAR_T_TYPE t2[] = "x"; // expected-error {{initializing wide char array with non-wide string literal}}
+ char t3[] = L"x"; // expected-error {{initializing char array with wide string literal}}
}
diff --git a/test/SemaCXX/Inputs/lit.local.cfg b/test/SemaCXX/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/SemaCXX/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/SemaCXX/Inputs/register.h b/test/SemaCXX/Inputs/register.h
new file mode 100644
index 000000000000..3c412eeb1205
--- /dev/null
+++ b/test/SemaCXX/Inputs/register.h
@@ -0,0 +1,5 @@
+#pragma GCC system_header
+#pragma once
+
+inline void f() { register int k; }
+#define to_int(x) ({ register int n = (x); n; })
diff --git a/test/SemaCXX/Inputs/warn-unused-variables.h b/test/SemaCXX/Inputs/warn-unused-variables.h
index 5fac45922c99..56990e0a33de 100644
--- a/test/SemaCXX/Inputs/warn-unused-variables.h
+++ b/test/SemaCXX/Inputs/warn-unused-variables.h
@@ -7,5 +7,7 @@ class A {};
class B {
static A a;
+ static A b;
+ static const int x = sizeof(b);
};
}
diff --git a/test/SemaCXX/MicrosoftCompatibility.cpp b/test/SemaCXX/MicrosoftCompatibility.cpp
index 6a48f36801bd..05037ac6a0d0 100644
--- a/test/SemaCXX/MicrosoftCompatibility.cpp
+++ b/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -178,3 +178,19 @@ namespace PR11791 {
del((void*)a); // expected-note {{in instantiation of function template specialization}}
}
}
+
+namespace IntToNullPtrConv {
+ struct Foo {
+ static const int ZERO = 0;
+ typedef void (Foo::*MemberFcnPtr)();
+ };
+
+ struct Bar {
+ const Foo::MemberFcnPtr pB;
+ };
+
+ Bar g_bar = { (Foo::MemberFcnPtr)Foo::ZERO };
+
+ template<int N> int *get_n() { return N; } // expected-warning {{expression which evaluates to zero treated as a null pointer constant}}
+ int *g_nullptr = get_n<0>(); // expected-note {{in instantiation of function template specialization}}
+}
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index ab3ff69f27be..c5b45a2905c8 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -167,8 +167,14 @@ void pointer_to_integral_type_conv(char* ptr) {
short sh = (short)ptr;
ch = (char)ptr;
sh = (short)ptr;
-}
+ // These are valid C++.
+ bool b = (bool)ptr;
+ b = static_cast<bool>(ptr);
+
+ // This is bad.
+ b = reinterpret_cast<bool>(ptr); // expected-error {{cast from pointer to smaller type 'bool' loses information}}
+}
namespace friend_as_a_forward_decl {
@@ -333,3 +339,74 @@ void TestSP9() {
c3.g(); // Overloaded incdec op operand
c3.h(); // Overloaded unary op operand
}
+
+union u {
+ int *i1;
+ int &i2; // expected-warning {{union member 'i2' has reference type 'int &', which is a Microsoft extension}}
+};
+
+// Property getter using reference.
+struct SP11 {
+ __declspec(property(get=GetV)) int V;
+ int _v;
+ int& GetV() { return _v; }
+ void UseV();
+ void TakePtr(int *) {}
+ void TakeRef(int &) {}
+ void TakeVal(int) {}
+};
+
+void SP11::UseV() {
+ TakePtr(&V);
+ TakeRef(V);
+ TakeVal(V);
+}
+
+struct StructWithUnnamedMember {
+ __declspec(property(get=GetV)) int : 10; // expected-error {{anonymous property is not supported}}
+};
+
+namespace rdar14250378 {
+ class Bar {};
+
+ namespace NyNamespace {
+ class Foo {
+ public:
+ Bar* EnsureBar();
+ };
+
+ class Baz : public Foo {
+ public:
+ friend class Bar;
+ };
+
+ Bar* Foo::EnsureBar() {
+ return 0;
+ }
+ }
+}
+
+// expected-error@+1 {{'sealed' keyword not permitted with interface types}}
+__interface InterfaceWithSealed sealed {
+};
+
+struct SomeBase {
+ virtual void OverrideMe();
+
+ // expected-note@+2 {{overridden virtual function is here}}
+ // expected-warning@+1 {{'sealed' keyword is a Microsoft extension}}
+ virtual void SealedFunction() sealed;
+};
+
+// expected-note@+2 {{'SealedType' declared here}}
+// expected-warning@+1 {{'sealed' keyword is a Microsoft extension}}
+struct SealedType sealed : SomeBase {
+ // expected-error@+1 {{declaration of 'SealedFunction' overrides a 'sealed' function}}
+ virtual void SealedFunction();
+
+ // expected-warning@+1 {{'override' keyword is a C++11 extension}}
+ virtual void OverrideMe() override;
+};
+
+// expected-error@+1 {{base 'SealedType' is marked 'sealed'}}
+struct InheritFromSealed : SealedType {};
diff --git a/test/SemaCXX/PR10447.cpp b/test/SemaCXX/PR10447.cpp
index 5ba74aaba36c..0c57177b872a 100644
--- a/test/SemaCXX/PR10447.cpp
+++ b/test/SemaCXX/PR10447.cpp
@@ -4,7 +4,7 @@
// PR12223
namespace test1 {
namespace N {
- extern "C" void f(struct S*);
+ extern "C" void f_test1(struct S*);
void g(S*);
}
namespace N {
@@ -17,7 +17,7 @@ namespace test1 {
// PR10447
namespace test2 {
extern "C" {
- void f(struct Bar*) { }
+ void f_test2(struct Bar*) { }
test2::Bar *ptr;
}
}
diff --git a/test/SemaCXX/PR12778.cpp b/test/SemaCXX/PR12778.cpp
new file mode 100644
index 000000000000..f4d25f3e8fc9
--- /dev/null
+++ b/test/SemaCXX/PR12778.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void operator delete() throw(void*); // expected-error{{'operator delete' must have at least one parameter}}
+void* allocate(int __n) {
+ return ::operator new(__n);
+}
+
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
index b475b57416c6..d6dc2e06062c 100644
--- a/test/SemaCXX/PR9572.cpp
+++ b/test/SemaCXX/PR9572.cpp
@@ -7,7 +7,7 @@ struct Foo : public Base { // expected-error {{base class 'Base' has private des
Foo();
};
struct Bar : public Foo {
- Bar() { } // expected-note {{implicit default destructor for 'Foo' first required here}}
+ Bar() { } // expected-note {{implicit destructor for 'Foo' first required here}}
};
struct Baz {
Foo f;
diff --git a/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp
index a0f503abe6c8..1c45581b32f9 100644
--- a/test/SemaCXX/__try.cpp
+++ b/test/SemaCXX/__try.cpp
@@ -57,3 +57,23 @@ int main()
}
return e;
}
+
+namespace PR17584 {
+template <typename>
+void Except() {
+ __try {
+ } __except(true) {
+ }
+}
+
+template <typename>
+void Finally() {
+ __try {
+ } __finally {
+ }
+}
+
+template void Except<void>();
+template void Finally<void>();
+
+}
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index e20a89009bd9..d7e2d0a3dcf9 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wabstract-vbase-init
#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
@@ -250,6 +250,13 @@ namespace test4 {
};
}
+namespace test5 {
+ struct A { A(int); virtual ~A() = 0; }; // expected-note {{pure virtual method}}
+ const A &a = 0; // expected-error {{abstract class}}
+ void f(const A &a = 0); // expected-error {{abstract class}}
+ void g() { f(0); } // expected-error {{abstract class}}
+}
+
// PR9247: Crash on invalid in clang::Sema::ActOnFinishCXXMemberSpecification
namespace pr9247 {
struct A {
@@ -273,3 +280,30 @@ namespace pr12658 {
foo(C(99)); // expected-error {{allocating an object of abstract class type 'pr12658::C'}}
}
}
+
+namespace pr16659 {
+ struct A {
+ A(int);
+ virtual void x() = 0; // expected-note {{unimplemented pure virtual method 'x' in 'RedundantInit'}}
+ };
+ struct B : virtual A {};
+ struct C : B {
+ C() : A(37) {}
+ void x() override {}
+ };
+
+ struct X {
+ friend class Z;
+ private:
+ X &operator=(const X&);
+ };
+ struct Y : virtual X { // expected-note {{::X' has an inaccessible copy assignment}}
+ virtual ~Y() = 0;
+ };
+ struct Z : Y {}; // expected-note {{::Y' has a deleted copy assignment}}
+ void f(Z &a, const Z &b) { a = b; } // expected-error {{copy assignment operator is implicitly deleted}}
+
+ struct RedundantInit : virtual A {
+ RedundantInit() : A(0) {} // expected-warning {{initializer for virtual base class 'pr16659::A' of abstract class 'RedundantInit' will never be used}}
+ };
+}
diff --git a/test/SemaCXX/access.cpp b/test/SemaCXX/access.cpp
index 50f2eff87bfb..5ccd418c1b76 100644
--- a/test/SemaCXX/access.cpp
+++ b/test/SemaCXX/access.cpp
@@ -26,9 +26,11 @@ private:
namespace test1 {
class A {
private:
- class X; // expected-note {{previously declared 'private' here}}
+ class X; // expected-note {{previously declared 'private' here}} \
+ // expected-note {{previous declaration is here}}
public:
- class X; // expected-error {{'X' redeclared with 'public' access}}
+ class X; // expected-error {{'X' redeclared with 'public' access}} \
+ // expected-warning {{class member cannot be redeclared}}
class X {};
};
}
@@ -106,3 +108,31 @@ namespace PR15209 {
}
}
}
+
+namespace PR7434 {
+ namespace comment0 {
+ template <typename T> struct X;
+ namespace N {
+ class Y {
+ template<typename T> friend struct X;
+ int t; // expected-note {{here}}
+ };
+ }
+ template<typename T> struct X {
+ X() { (void)N::Y().t; } // expected-error {{private}}
+ };
+ X<char> x;
+ }
+ namespace comment2 {
+ struct X;
+ namespace N {
+ class Y {
+ friend struct X;
+ int t; // expected-note {{here}}
+ };
+ }
+ struct X {
+ X() { (void)N::Y().t; } // expected-error {{private}}
+ };
+ }
+}
diff --git a/test/SemaCXX/addr-of-overloaded-function-casting.cpp b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
index cfd55eed81d5..784c8a000744 100644
--- a/test/SemaCXX/addr-of-overloaded-function-casting.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
@@ -4,8 +4,12 @@ void g();
void f(); // expected-note 9{{candidate function}}
void f(int); // expected-note 9{{candidate function}}
-template<class T> void t(T); // expected-note 6{{candidate function}}
-template<class T> void t(T*); // expected-note 6{{candidate function}}
+template <class T>
+void t(T); // expected-note 3{{candidate function}} \
+ // expected-note 3{{candidate template ignored: could not match 'void' against 'int'}}
+template <class T>
+void t(T *); // expected-note 3{{candidate function}} \
+ // expected-note 3{{candidate template ignored: could not match 'void' against 'int'}}
template<class T> void u(T);
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 096f74823a42..230a1eb994e1 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -57,11 +57,12 @@ struct B
struct C {
C &getC() {
- return makeAC; // expected-error{{reference to non-static member function must be called}}
+ return makeAC; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
- C &makeAC();
- const C &makeAC() const;
+ // FIXME: filter by const so we can unambiguously suggest '()' & point to just the one candidate, probably
+ C &makeAC(); // expected-note{{possible target for call}}
+ const C &makeAC() const; // expected-note{{possible target for call}}
static void f(); // expected-note{{candidate function}}
static void f(int); // expected-note{{candidate function}}
@@ -69,6 +70,32 @@ struct C {
void g() {
int (&fp)() = f; // expected-error{{address of overloaded function 'f' does not match required type 'int ()'}}
}
+
+ template<typename T>
+ void q1(int); // expected-note{{possible target for call}}
+ template<typename T>
+ void q2(T t = T()); // expected-note{{possible target for call}}
+ template<typename T>
+ void q3(); // expected-note{{possible target for call}}
+ template<typename T1, typename T2>
+ void q4(); // expected-note{{possible target for call}}
+ template<typename T1 = int> // expected-warning{{default template arguments for a function template are a C++11 extension}}
+ void q5(); // expected-note{{possible target for call}}
+
+ void h() {
+ // Do not suggest '()' since an int argument is required
+ q1<int>; // expected-error-re{{reference to non-static member function must be called$}}
+ // Suggest '()' since there's a default value for the only argument & the
+ // type argument is already provided
+ q2<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ // Suggest '()' since no arguments are required & the type argument is
+ // already provided
+ q3<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ // Do not suggest '()' since another type argument is required
+ q4<int>; // expected-error-re{{reference to non-static member function must be called$}}
+ // Suggest '()' since the type parameter has a default value
+ q5; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ }
};
// PR6886
@@ -208,3 +235,7 @@ namespace test1 {
void (Qualifiers::*X)() = &Dummy::N; // expected-error{{cannot initialize a variable of type 'void (test1::Qualifiers::*)()' with an rvalue of type 'void (test1::Dummy::*)()': different classes ('test1::Qualifiers' vs 'test1::Dummy')}}
}
+
+template <typename T> class PR16561 {
+ virtual bool f() { if (f) {} return false; } // expected-error {{reference to non-static member function must be called}}
+};
diff --git a/test/SemaCXX/alignment-of-derived-class.cpp b/test/SemaCXX/alignment-of-derived-class.cpp
new file mode 100644
index 000000000000..28c1fa9144b7
--- /dev/null
+++ b/test/SemaCXX/alignment-of-derived-class.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
+
+// Test that the alignment of a empty direct base class is correctly
+// inherited by the derived class.
+
+struct A {
+} __attribute__ ((aligned(16)));
+
+static_assert(__alignof(A) == 16, "A should be aligned to 16 bytes");
+
+struct B1 : public A {
+};
+
+static_assert(__alignof(B1) == 16, "B1 should be aligned to 16 bytes");
+
+struct B2 : public A {
+} __attribute__ ((aligned(2)));
+
+static_assert(__alignof(B2) == 16, "B2 should be aligned to 16 bytes");
+
+struct B3 : public A {
+} __attribute__ ((aligned(4)));
+
+static_assert(__alignof(B3) == 16, "B3 should be aligned to 16 bytes");
+
+struct B4 : public A {
+} __attribute__ ((aligned(8)));
+
+static_assert(__alignof(B4) == 16, "B4 should be aligned to 16 bytes");
+
+struct B5 : public A {
+} __attribute__ ((aligned(16)));
+
+static_assert(__alignof(B5) == 16, "B5 should be aligned to 16 bytes");
+
+struct B6 : public A {
+} __attribute__ ((aligned(32)));
+
+static_assert(__alignof(B6) == 32, "B6 should be aligned to 32 bytes");
+
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index d76fcf55c2d8..3e37d615bbcf 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -10,8 +10,8 @@ void test() {
static_assert(sizeof(char&) == 1, "bad size");
}
-void f(); // expected-note{{possible target for call}}
-void f(int); // expected-note{{possible target for call}}
+int f(); // expected-note{{possible target for call}}
+int f(int); // expected-note{{possible target for call}}
void g() {
sizeof(&f); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} \
// expected-warning{{expression result unused}}
diff --git a/test/SemaCXX/alignof.cpp b/test/SemaCXX/alignof.cpp
index a9de1ad07c9f..f0b89eef656d 100644
--- a/test/SemaCXX/alignof.cpp
+++ b/test/SemaCXX/alignof.cpp
@@ -9,7 +9,7 @@ struct S0 {
auto test2() -> char(&)[__alignof__(x)]; // expected-error {{invalid application of 'alignof' to a field of a class still being defined}}
};
-struct S1; // expected-note 5 {{forward declaration}}
+struct S1; // expected-note 6 {{forward declaration}}
extern S1 s1;
const int test3 = __alignof__(s1); // expected-error {{invalid application of 'alignof' to an incomplete type 'S1'}}
@@ -50,3 +50,15 @@ struct S4 {
static const int test1 = __alignof__(S0::x);
auto test2() -> char(&)[__alignof__(x)];
};
+
+// Regression test for asking for the alignment of a field within an invalid
+// record.
+struct S5 {
+ S1 s; // expected-error {{incomplete type}}
+ int x;
+};
+const int test8 = __alignof__(S5::x);
+
+long long int test14[2];
+
+static_assert(alignof(test14) == 8, "foo"); // expected-warning {{'alignof' applied to an expression is a GNU extension}}
diff --git a/test/SemaCXX/ambiguous-conversion-show-overload.cpp b/test/SemaCXX/ambiguous-conversion-show-overload.cpp
index 64296512ffd7..5cd26fc31aef 100644
--- a/test/SemaCXX/ambiguous-conversion-show-overload.cpp
+++ b/test/SemaCXX/ambiguous-conversion-show-overload.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -fno-caret-diagnostics %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fshow-overloads=best -fno-caret-diagnostics %s 2>&1 | FileCheck %s
struct S {
S(void*);
S(char*);
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 9c2cf24a83fc..fde27b049d88 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -197,3 +197,12 @@ namespace PR8326 {
Foo<int> baz;
}
+
+namespace PR16630 {
+ struct A { union { int x; float y; }; }; // expected-note {{member is declared here}}
+ struct B : private A { using A::x; } b; // expected-note 2 {{private}}
+ void foo () {
+ b.x = 10;
+ b.y = 0; // expected-error {{cannot cast 'struct B' to its private base class 'PR16630::A'}} expected-error {{'y' is a private member of 'PR16630::A'}}
+ }
+}
diff --git a/test/SemaCXX/ast-print.cpp b/test/SemaCXX/ast-print.cpp
index 921f7d8baaae..a1975b4ac264 100644
--- a/test/SemaCXX/ast-print.cpp
+++ b/test/SemaCXX/ast-print.cpp
@@ -103,6 +103,7 @@ int test11() {
struct DefaultArgClass
{
DefaultArgClass(int a = 1) {}
+ DefaultArgClass(int a, int b, int c = 1) {}
};
struct NoArgClass
@@ -124,6 +125,8 @@ struct ConstrWithCleanupsClass
// CHECK: test12
// CHECK-NEXT: DefaultArgClass useDefaultArg;
// CHECK-NEXT: DefaultArgClass overrideDefaultArg(1);
+// CHECK-NEXT: DefaultArgClass(1, 2);
+// CHECK-NEXT: DefaultArgClass(1, 2, 3);
// CHECK-NEXT: NoArgClass noArg;
// CHECK-NEXT: ConstrWithCleanupsClass cwcNoArg;
// CHECK-NEXT: ConstrWithCleanupsClass cwcOverrideArg(48);
@@ -131,6 +134,8 @@ struct ConstrWithCleanupsClass
void test12() {
DefaultArgClass useDefaultArg;
DefaultArgClass overrideDefaultArg(1);
+ DefaultArgClass tempWithDefaultArg = DefaultArgClass(1, 2);
+ DefaultArgClass tempWithExplictArg = DefaultArgClass(1, 2, 3);
NoArgClass noArg;
ConstrWithCleanupsClass cwcNoArg;
ConstrWithCleanupsClass cwcOverrideArg(48);
@@ -148,3 +153,14 @@ void test13() {
__c11_atomic_load(&i, 0);
}
+
+// CHECK: void test14() {
+// CHECK: struct X {
+// CHECK: union {
+// CHECK: int x;
+// CHECK: } x;
+// CHECK: };
+// CHECK: }
+void test14() {
+ struct X { union { int x; } x; };
+}
diff --git a/test/SemaCXX/attr-aligned.cpp b/test/SemaCXX/attr-aligned.cpp
new file mode 100644
index 000000000000..4b9c55f4c7dd
--- /dev/null
+++ b/test/SemaCXX/attr-aligned.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+typedef struct S1 { char c; } S1 __attribute__((aligned(8)));
+static_assert(alignof(S1) == 8, "attribute ignored");
+static_assert(alignof(struct S1) == 1, "attribute applied to original type");
+
+typedef struct __attribute__((aligned(8))) S2 { char c; } AS;
+static_assert(alignof(S2) == 8, "attribute not propagated");
+static_assert(alignof(struct S2) == 8, "attribute ignored");
+
+typedef struct __attribute__((aligned(4))) S3 {
+ char c;
+} S3 __attribute__((aligned(8)));
+static_assert(alignof(S3) == 8, "attribute ignored");
+static_assert(alignof(struct S3) == 4, "attribute clobbered");
diff --git a/test/SemaCXX/attr-cleanup-gcc.cpp b/test/SemaCXX/attr-cleanup-gcc.cpp
new file mode 100644
index 000000000000..daebbe66c8d0
--- /dev/null
+++ b/test/SemaCXX/attr-cleanup-gcc.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wgcc-compat
+
+namespace N {
+ void c1(int *a) {}
+}
+
+void c2(int *a) {}
+
+template <typename Ty>
+void c3(Ty *a) {}
+
+void t3() {
+ int v1 __attribute__((cleanup(N::c1))); // expected-warning {{GCC does not allow the 'cleanup' attribute argument to be anything other than a simple identifier}}
+ int v2 __attribute__((cleanup(c2)));
+ int v3 __attribute__((cleanup(c3<int>))); // expected-warning {{GCC does not allow the 'cleanup' attribute argument to be anything other than a simple identifier}}
+}
diff --git a/test/SemaCXX/attr-cleanup.cpp b/test/SemaCXX/attr-cleanup.cpp
new file mode 100644
index 000000000000..32d10683edeb
--- /dev/null
+++ b/test/SemaCXX/attr-cleanup.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-gcc-compat
+
+namespace N {
+ void c1(int *a) {}
+}
+
+class C {
+ static void c2(int *a) {} // expected-note {{implicitly declared private here}} expected-note {{implicitly declared private here}}
+};
+
+void t1() {
+ int v1 __attribute__((cleanup(N::c1)));
+ int v2 __attribute__((cleanup(N::c2))); // expected-error {{no member named 'c2' in namespace 'N'}}
+ int v3 __attribute__((cleanup(C::c2))); // expected-error {{'c2' is a private member of 'C'}}
+}
+
+class D : public C {
+ void t2() {
+ int v1 __attribute__((cleanup(c2))); // expected-error {{'c2' is a private member of 'C'}}
+ }
+};
+
+namespace E {
+ void c3(int *a) {} // expected-note {{candidate function}}
+ void c3() {} // expected-note {{candidate function}}
+ void t3() {
+ int v1 __attribute__((cleanup(c3))); // expected-error {{'c3' is not a single function}}
+ }
+}
diff --git a/test/SemaCXX/attr-common.cpp b/test/SemaCXX/attr-common.cpp
new file mode 100644
index 000000000000..58b30133f52f
--- /dev/null
+++ b/test/SemaCXX/attr-common.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+__attribute__((common)) int x; // expected-error {{common attribute is not supported in C++}}
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index e9276cd2d9ee..e24e12e50c4e 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -12,7 +12,7 @@ struct align_member {
};
void f(alignas(1) char c) { // expected-error {{'alignas' attribute cannot be applied to a function parameter}}
- alignas(1) register char k; // expected-error {{'alignas' attribute cannot be applied to a variable with 'register' storage class}}
+ alignas(1) register char k; // expected-error {{'alignas' attribute cannot be applied to a variable with 'register' storage class}} expected-warning {{deprecated}}
try {
} catch (alignas(4) int n) { // expected-error {{'alignas' attribute cannot be applied to a 'catch' variable}}
}
@@ -44,4 +44,4 @@ static_assert(alignof(align_class_temp_pack_type<short, int, long>) == alignof(l
static_assert(alignof(align_class_temp_pack_expr<8, 16, 32>) == 32, "template's alignment is wrong");
static_assert(alignof(outer<int,char>::inner<double,short>) == alignof(int) * alignof(double), "template's alignment is wrong");
-static_assert(alignof(int(int)) >= 1, "alignof(function) not positive"); // expected-warning{{invalid application of 'alignof' to a function type}}
+static_assert(alignof(int(int)) >= 1, "alignof(function) not positive"); // expected-error{{invalid application of 'alignof' to a function type}}
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index d09faf34d7a5..b3223f399799 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -244,3 +244,9 @@ namespace test7 {
X *x = new X; // expected-warning{{'operator new' is deprecated}} expected-warning{{'operator delete' is deprecated}}
}
}
+
+// rdar://problem/15044218
+typedef struct TDS {
+} TDS __attribute__((deprecated)); // expected-note {{'TDS' declared here}}
+TDS tds; // expected-warning {{'TDS' is deprecated}}
+struct TDS tds2; // no warning, attribute only applies to the typedef.
diff --git a/test/SemaCXX/attr-no-sanitize-address.cpp b/test/SemaCXX/attr-no-sanitize-address.cpp
index dc4d79758c16..f1803496fa55 100644
--- a/test/SemaCXX/attr-no-sanitize-address.cpp
+++ b/test/SemaCXX/attr-no-sanitize-address.cpp
@@ -9,7 +9,7 @@
void noanal_fun() NO_SANITIZE_ADDRESS;
void noanal_fun_args() __attribute__((no_sanitize_address(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'no_sanitize_address' attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_ADDRESS;
diff --git a/test/SemaCXX/attr-no-sanitize-memory.cpp b/test/SemaCXX/attr-no-sanitize-memory.cpp
index 84acdaca838f..d6eca1b69dc1 100644
--- a/test/SemaCXX/attr-no-sanitize-memory.cpp
+++ b/test/SemaCXX/attr-no-sanitize-memory.cpp
@@ -9,7 +9,7 @@
void noanal_fun() NO_SANITIZE_MEMORY;
void noanal_fun_args() __attribute__((no_sanitize_memory(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'no_sanitize_memory' attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_MEMORY;
diff --git a/test/SemaCXX/attr-no-sanitize-thread.cpp b/test/SemaCXX/attr-no-sanitize-thread.cpp
index 50960c42b931..d6372bceff8a 100644
--- a/test/SemaCXX/attr-no-sanitize-thread.cpp
+++ b/test/SemaCXX/attr-no-sanitize-thread.cpp
@@ -9,7 +9,7 @@
void noanal_fun() NO_SANITIZE_THREAD;
void noanal_fun_args() __attribute__((no_sanitize_thread(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'no_sanitize_thread' attribute takes no arguments}}
int noanal_testfn(int y) NO_SANITIZE_THREAD;
diff --git a/test/SemaCXX/attr-print.cpp b/test/SemaCXX/attr-print.cpp
index 2e7478904f12..a07eeff5646e 100644
--- a/test/SemaCXX/attr-print.cpp
+++ b/test/SemaCXX/attr-print.cpp
@@ -16,3 +16,9 @@ void bar() __attribute__((__const));
// FIXME: Print this with correct format and order.
// CHECK: void foo1() __attribute__((pure)) __attribute__((noinline));
void foo1() __attribute__((noinline, pure));
+
+// CHECK: typedef int Small1 __attribute__((mode(byte)));
+typedef int Small1 __attribute__((mode(byte)));
+
+// CHECK: int small __attribute__((mode(byte)));
+int small __attribute__((mode(byte)));
diff --git a/test/SemaCXX/attr-selectany.cpp b/test/SemaCXX/attr-selectany.cpp
new file mode 100644
index 000000000000..0f9776dbf5db
--- /dev/null
+++ b/test/SemaCXX/attr-selectany.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// MSVC produces similar diagnostics.
+
+__declspec(selectany) void foo() { } // expected-error{{'selectany' can only be applied to data items with external linkage}}
+
+__declspec(selectany) int x1 = 1;
+
+const __declspec(selectany) int x2 = 2; // expected-error{{'selectany' can only be applied to data items with external linkage}}
+
+extern const __declspec(selectany) int x3 = 3;
+
+extern const int x4;
+const __declspec(selectany) int x4 = 4;
+
+// MSDN says this is incorrect, but MSVC doesn't diagnose it.
+extern __declspec(selectany) int x5;
+
+static __declspec(selectany) int x6 = 2; // expected-error{{'selectany' can only be applied to data items with external linkage}}
+
+// FIXME: MSVC accepts this and makes x7 externally visible and comdat, but keep
+// it as internal and not weak/linkonce.
+static int x7; // expected-note{{previous definition}}
+extern __declspec(selectany) int x7; // expected-warning{{attribute declaration must precede definition}}
+
+int asdf() { return x7; }
+
+class X {
+ public:
+ X(int i) { i++; };
+ int i;
+};
+
+__declspec(selectany) X x(1);
diff --git a/test/SemaCXX/attr-used.cpp b/test/SemaCXX/attr-used.cpp
new file mode 100644
index 000000000000..9bae3edc7f8b
--- /dev/null
+++ b/test/SemaCXX/attr-used.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+extern char test1[] __attribute__((used)); // expected-warning {{used attribute ignored}}
+extern const char test2[] __attribute__((used)); // expected-warning {{used attribute ignored}}
+extern const char test3[] __attribute__((used)) = "";
diff --git a/test/SemaCXX/attr-weakref.cpp b/test/SemaCXX/attr-weakref.cpp
index f3d7a6241c91..0c3f1d20e7f7 100644
--- a/test/SemaCXX/attr-weakref.cpp
+++ b/test/SemaCXX/attr-weakref.cpp
@@ -32,3 +32,5 @@ int a9 __attribute__((weakref)); // expected-error {{weakref declaration of 'a9
static int a10();
int a10() __attribute__((weakref ("foo")));
+
+static int v __attribute__((weakref(a1), alias("foo"))); // expected-error {{'weakref' attribute requires a string}}
diff --git a/test/SemaCXX/blocks-1.cpp b/test/SemaCXX/blocks-1.cpp
index 02e9cac62ebe..e11fd92cf236 100644
--- a/test/SemaCXX/blocks-1.cpp
+++ b/test/SemaCXX/blocks-1.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++1y
extern "C" int exit(int);
@@ -57,3 +56,18 @@ namespace rdar11055105 {
foo(a);
};
}
+
+namespace LocalDecls {
+ void f() {
+ (void) ^{
+ extern int a; // expected-note {{previous}}
+ extern int b(); // expected-note {{previous}}
+ };
+ }
+ void g() {
+ (void) ^{
+ extern float a; // expected-error {{different type}}
+ extern float b(); // expected-error {{cannot be overloaded}}
+ };
+ }
+}
diff --git a/test/SemaCXX/bool.cpp b/test/SemaCXX/bool.cpp
index f027186735b3..69c011935781 100644
--- a/test/SemaCXX/bool.cpp
+++ b/test/SemaCXX/bool.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-constant-conversion %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-constant-conversion \
+// RUN: -Wno-deprecated -Wdeprecated-increment-bool %s
// Bool literals can be enum values.
enum {
diff --git a/test/SemaCXX/builtins.cpp b/test/SemaCXX/builtins.cpp
index 5d61690c16e5..69bdfa614517 100644
--- a/test/SemaCXX/builtins.cpp
+++ b/test/SemaCXX/builtins.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
typedef const struct __CFString * CFStringRef;
#define CFSTR __builtin___CFStringMakeConstantString
@@ -24,3 +24,23 @@ void f2() {
// pr14895
typedef __typeof(sizeof(int)) size_t;
extern "C" void *__builtin_alloca (size_t);
+
+namespace addressof {
+ struct S {} s;
+ static_assert(__builtin_addressof(s) == &s, "");
+
+ struct T { constexpr T *operator&() const { return nullptr; } int n; } t;
+ constexpr T *pt = __builtin_addressof(t);
+ static_assert(&pt->n == &t.n, "");
+
+ struct U { int n : 5; } u;
+ int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}}
+
+ S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}}
+}
+
+void no_ms_builtins() {
+ __assume(1); // expected-error {{use of undeclared}}
+ __noop(1); // expected-error {{use of undeclared}}
+ __debugbreak(); // expected-error {{use of undeclared}}
+}
diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp
index 13918dcf5ef6..7afcdd509f9d 100644
--- a/test/SemaCXX/c99.cpp
+++ b/test/SemaCXX/c99.cpp
@@ -2,7 +2,7 @@
void f1(int i[static 5]) { // expected-error{{C99}}
}
-struct Point { int x; int y; };
+struct Point { int x; int y; int z[]; }; // expected-warning{{flexible array members are a C99 feature}}
Point p1 = { .x = 17, // expected-warning{{designated initializers are a C99 feature}}
y: 25 }; // expected-warning{{designated initializers are a C99 feature}} \
diff --git a/test/SemaCXX/calling-conv-compat.cpp b/test/SemaCXX/calling-conv-compat.cpp
new file mode 100644
index 000000000000..2d52386add16
--- /dev/null
+++ b/test/SemaCXX/calling-conv-compat.cpp
@@ -0,0 +1,387 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fms-extensions -cxx-abi microsoft -verify -triple i686-pc-win32 %s
+
+// Pointers to free functions
+void free_func_default();
+void __cdecl free_func_cdecl();
+void __stdcall free_func_stdcall();
+void __fastcall free_func_fastcall();
+
+typedef void ( *fptr_default)();
+typedef void (__cdecl *fptr_cdecl)();
+typedef void (__stdcall *fptr_stdcall)();
+typedef void (__fastcall *fptr_fastcall)();
+
+// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+void cb_fptr_default(fptr_default ptr);
+// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+void cb_fptr_cdecl(fptr_cdecl ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
+void cb_fptr_stdcall(fptr_stdcall ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
+void cb_fptr_fastcall(fptr_fastcall ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
+void cb_fptr_const_default(const fptr_default ptr);
+
+void call_free_func() {
+ cb_fptr_default(free_func_default);
+ cb_fptr_default(free_func_cdecl);
+ cb_fptr_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
+ cb_fptr_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
+ cb_fptr_default(&free_func_default);
+ cb_fptr_default(&free_func_cdecl);
+ cb_fptr_default(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
+ cb_fptr_default(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
+
+ cb_fptr_cdecl(free_func_default);
+ cb_fptr_cdecl(free_func_cdecl);
+ cb_fptr_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
+ cb_fptr_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
+ cb_fptr_cdecl(&free_func_default);
+ cb_fptr_cdecl(&free_func_cdecl);
+ cb_fptr_cdecl(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
+ cb_fptr_cdecl(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
+
+ cb_fptr_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
+ cb_fptr_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
+ cb_fptr_stdcall(free_func_stdcall);
+ cb_fptr_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
+
+ cb_fptr_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
+ cb_fptr_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
+ cb_fptr_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
+ cb_fptr_fastcall(free_func_fastcall);
+
+ cb_fptr_const_default(free_func_default);
+ cb_fptr_const_default(free_func_cdecl);
+ cb_fptr_const_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
+ cb_fptr_const_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
+
+}
+
+// Pointers to variadic functions
+// variadic function can't declared stdcall or fastcall
+void free_func_variadic_default(int, ...);
+void __cdecl free_func_variadic_cdecl(int, ...);
+
+typedef void ( *fptr_variadic_default)(int, ...);
+typedef void (__cdecl *fptr_variadic_cdecl)(int, ...);
+
+void cb_fptr_variadic_default(fptr_variadic_default ptr);
+void cb_fptr_variadic_cdecl(fptr_variadic_cdecl ptr);
+
+void call_free_variadic_func() {
+ cb_fptr_variadic_default(free_func_variadic_default);
+ cb_fptr_variadic_default(free_func_variadic_cdecl);
+ cb_fptr_variadic_default(&free_func_variadic_default);
+ cb_fptr_variadic_default(&free_func_variadic_cdecl);
+
+ cb_fptr_variadic_cdecl(free_func_variadic_default);
+ cb_fptr_variadic_cdecl(free_func_variadic_cdecl);
+ cb_fptr_variadic_cdecl(&free_func_variadic_default);
+ cb_fptr_variadic_cdecl(&free_func_variadic_cdecl);
+}
+
+// References to functions
+typedef void ( &fref_default)();
+typedef void (__cdecl &fref_cdecl)();
+typedef void (__stdcall &fref_stdcall)();
+typedef void (__fastcall &fref_fastcall)();
+
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
+void cb_fref_default(fref_default ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
+void cb_fref_cdecl(fref_cdecl ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
+void cb_fref_stdcall(fref_stdcall ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
+void cb_fref_fastcall(fref_fastcall ptr);
+
+void call_free_func_ref() {
+ cb_fref_default(free_func_default);
+ cb_fref_default(free_func_cdecl);
+ cb_fref_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
+ cb_fref_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
+
+ cb_fref_cdecl(free_func_default);
+ cb_fref_cdecl(free_func_cdecl);
+ cb_fref_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
+ cb_fref_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
+
+ cb_fref_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
+ cb_fref_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
+ cb_fref_stdcall(free_func_stdcall);
+ cb_fref_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
+
+ cb_fref_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
+ cb_fref_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
+ cb_fref_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
+ cb_fref_fastcall(free_func_fastcall);
+}
+
+// References to variadic functions
+// variadic function can't declared stdcall or fastcall
+typedef void ( &fref_variadic_default)(int, ...);
+typedef void (__cdecl &fref_variadic_cdecl)(int, ...);
+
+void cb_fref_variadic_default(fptr_variadic_default ptr);
+void cb_fref_variadic_cdecl(fptr_variadic_cdecl ptr);
+
+void call_free_variadic_func_ref() {
+ cb_fref_variadic_default(free_func_variadic_default);
+ cb_fref_variadic_default(free_func_variadic_cdecl);
+
+ cb_fref_variadic_cdecl(free_func_variadic_default);
+ cb_fref_variadic_cdecl(free_func_variadic_cdecl);
+}
+
+// Pointers to members
+namespace NonVariadic {
+
+struct A {
+ void member_default();
+ void __cdecl member_cdecl();
+ void __thiscall member_thiscall();
+};
+
+struct B : public A {
+};
+
+struct C {
+ void member_default();
+ void __cdecl member_cdecl();
+ void __thiscall member_thiscall();
+};
+
+typedef void ( A::*memb_a_default)();
+typedef void (__cdecl A::*memb_a_cdecl)();
+typedef void (__thiscall A::*memb_a_thiscall)();
+typedef void ( B::*memb_b_default)();
+typedef void (__cdecl B::*memb_b_cdecl)();
+typedef void (__thiscall B::*memb_b_thiscall)();
+typedef void ( C::*memb_c_default)();
+typedef void (__cdecl C::*memb_c_cdecl)();
+typedef void (__thiscall C::*memb_c_thiscall)();
+
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_a_default(memb_a_default ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
+void cb_memb_a_cdecl(memb_a_cdecl ptr);
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_a_thiscall(memb_a_thiscall ptr);
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_b_default(memb_b_default ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
+void cb_memb_b_cdecl(memb_b_cdecl ptr);
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_b_thiscall(memb_b_thiscall ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_c_default(memb_c_default ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+void cb_memb_c_cdecl(memb_c_cdecl ptr);
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+void cb_memb_c_thiscall(memb_c_thiscall ptr);
+
+void call_member() {
+ cb_memb_a_default(&A::member_default);
+ cb_memb_a_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_default'}}
+ cb_memb_a_default(&A::member_thiscall);
+
+ cb_memb_a_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
+ cb_memb_a_cdecl(&A::member_cdecl);
+ cb_memb_a_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
+
+ cb_memb_a_thiscall(&A::member_default);
+ cb_memb_a_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_thiscall'}}
+ cb_memb_a_thiscall(&A::member_thiscall);
+}
+
+void call_member_inheritance() {
+ cb_memb_b_default(&A::member_default);
+ cb_memb_b_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_default'}}
+ cb_memb_b_default(&A::member_thiscall);
+ cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
+ cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
+ cb_memb_c_default(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
+
+ cb_memb_b_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
+ cb_memb_b_cdecl(&A::member_cdecl);
+ cb_memb_b_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
+ cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
+ cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
+ cb_memb_c_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
+
+ cb_memb_b_thiscall(&A::member_default);
+ cb_memb_b_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_thiscall'}}
+ cb_memb_b_thiscall(&A::member_thiscall);
+ cb_memb_c_thiscall(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
+ cb_memb_c_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
+ cb_memb_c_thiscall(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
+}
+} // end namespace NonVariadic
+
+namespace Variadic {
+struct A {
+ void member_default(int, ...);
+ void __cdecl member_cdecl(int, ...);
+ void __thiscall member_thiscall(int, ...); // expected-error {{variadic function cannot use thiscall calling convention}}
+};
+
+struct B : public A {
+};
+
+struct C {
+ void member_default(int, ...);
+ void __cdecl member_cdecl(int, ...);
+};
+
+typedef void ( A::*memb_a_default)(int, ...);
+typedef void (__cdecl A::*memb_a_cdecl)(int, ...);
+typedef void ( B::*memb_b_default)(int, ...);
+typedef void (__cdecl B::*memb_b_cdecl)(int, ...);
+typedef void ( C::*memb_c_default)(int, ...);
+typedef void (__cdecl C::*memb_c_cdecl)(int, ...);
+
+void cb_memb_a_default(memb_a_default ptr);
+void cb_memb_a_cdecl(memb_a_cdecl ptr);
+void cb_memb_b_default(memb_b_default ptr);
+void cb_memb_b_cdecl(memb_b_cdecl ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
+void cb_memb_c_default(memb_c_default ptr);
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
+void cb_memb_c_cdecl(memb_c_cdecl ptr);
+
+void call_member() {
+ cb_memb_a_default(&A::member_default);
+ cb_memb_a_default(&A::member_cdecl);
+
+ cb_memb_a_cdecl(&A::member_default);
+ cb_memb_a_cdecl(&A::member_cdecl);
+}
+
+void call_member_inheritance() {
+ cb_memb_b_default(&A::member_default);
+ cb_memb_b_default(&A::member_cdecl);
+ cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
+ cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
+
+ cb_memb_b_cdecl(&A::member_default);
+ cb_memb_b_cdecl(&A::member_cdecl);
+ cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
+ cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
+}
+} // end namespace Variadic
+
+namespace MultiChunkDecls {
+
+// Try to test declarators that have multiple DeclaratorChunks.
+struct A {
+ void __thiscall member_thiscall(int);
+};
+
+void (A::*return_mptr(short))(int) {
+ return &A::member_thiscall;
+}
+
+void (A::*(*return_fptr_mptr(char))(short))(int) {
+ return return_mptr;
+}
+
+typedef void (A::*mptr_t)(int);
+mptr_t __stdcall return_mptr_std(short) {
+ return &A::member_thiscall;
+}
+
+void (A::*(*return_fptr_std_mptr(char))(short))(int) {
+ return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'mptr_t (short) __attribute__((stdcall))'}}
+}
+
+void call_return() {
+ A o;
+ void (A::*(*fptr)(short))(int) = return_fptr_mptr('a');
+ void (A::*mptr)(int) = fptr(1);
+ (o.*mptr)(2);
+}
+
+} // end namespace MultiChunkDecls
+
+namespace MemberPointers {
+
+struct A {
+ void __thiscall method_thiscall();
+ void __cdecl method_cdecl();
+ void __stdcall method_stdcall();
+ void __fastcall method_fastcall();
+};
+
+void ( A::*mp1)() = &A::method_thiscall;
+void (__cdecl A::*mp2)() = &A::method_cdecl;
+void (__stdcall A::*mp3)() = &A::method_stdcall;
+void (__fastcall A::*mp4)() = &A::method_fastcall;
+
+// Use a typedef to form the member pointer and verify that cdecl is adjusted.
+typedef void ( fun_default)();
+typedef void (__cdecl fun_cdecl)();
+typedef void (__stdcall fun_stdcall)();
+typedef void (__fastcall fun_fastcall)();
+
+// FIXME: Adjust cdecl to thiscall when forming a member pointer.
+//fun_default A::*td1 = &A::method_thiscall;
+fun_cdecl A::*td2 = &A::method_cdecl;
+fun_stdcall A::*td3 = &A::method_stdcall;
+fun_fastcall A::*td4 = &A::method_fastcall;
+
+// Round trip the function type through a template, and verify that only cdecl
+// gets adjusted.
+template<typename Fn> struct X {
+ typedef Fn A::*p;
+};
+
+// FIXME: Adjust cdecl to thiscall when forming a member pointer.
+//X<void ()>::p tmpl1 = &A::method_thiscall;
+//X<void __cdecl ()>::p tmpl2 = &A::method_thiscall;
+X<void __stdcall ()>::p tmpl3 = &A::method_stdcall;
+X<void __fastcall ()>::p tmpl4 = &A::method_fastcall;
+
+} // end namespace MemberPointers
+
+// Test that lambdas that capture nothing convert to cdecl function pointers.
+namespace Lambdas {
+
+void pass_fptr_cdecl (void (__cdecl *fp)());
+void pass_fptr_stdcall (void (__stdcall *fp)()); // expected-note {{candidate function not viable}}
+void pass_fptr_fastcall(void (__fastcall *fp)()); // expected-note {{candidate function not viable}}
+
+void conversion_to_fptr() {
+ pass_fptr_cdecl ([]() { } );
+ pass_fptr_stdcall ([]() { } ); // expected-error {{no matching function for call}}
+ pass_fptr_fastcall([]() { } ); // expected-error {{no matching function for call}}
+}
+
+}
diff --git a/test/SemaCXX/captured-statements.cpp b/test/SemaCXX/captured-statements.cpp
index dbb18a7b6765..5fb686c3c913 100644
--- a/test/SemaCXX/captured-statements.cpp
+++ b/test/SemaCXX/captured-statements.cpp
@@ -164,3 +164,10 @@ void test_capture_variadic() {
(void)captured_sum(1, 2, 3); // OK
(void)captured_sum(1, 2, 3, 4, 5); // OK
}
+
+void test_capture_with_attributes() {
+ [[]] // expected-error {{an attribute list cannot appear here}}
+ #pragma clang __debug captured
+ {
+ }
+}
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
index 270f96831bd4..4d5abfdcfb1e 100644
--- a/test/SemaCXX/cast-conversion.cpp
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -16,8 +16,7 @@ struct B { // expected-note 3 {{candidate constructor (the implicit copy constru
int main () {
B(10); // expected-error {{no matching conversion for functional-style cast from 'int' to 'B'}}
(B)10; // expected-error {{no matching conversion for C-style cast from 'int' to 'B'}}
- static_cast<B>(10); // expected-error {{no matching conversion for static_cast from 'int' to 'B'}} \\
- // expected-warning {{expression result unused}}
+ static_cast<B>(10); // expected-error {{no matching conversion for static_cast from 'int' to 'B'}}
}
template<class T>
@@ -65,3 +64,18 @@ void *intToPointer4() {
void *intToPointer5(long l) {
return (void*)l;
}
+
+struct AmbiguousCast {
+ operator int(); // expected-note {{candidate function}}
+ operator unsigned int(); // expected-note {{candidate function}}
+};
+long long AmbiguousCastFunc(AmbiguousCast& a) {
+ return static_cast<long long>(a); // expected-error {{ambiguous conversion for static_cast from 'AmbiguousCast' to 'long long'}}
+}
+
+namespace PR16680 {
+ void f(int (*__pf)());
+ int g() {
+ f(reinterpret_cast<int>(0.0f)); // expected-error {{reinterpret_cast from 'float' to 'int' is not allowed}}
+ }
+}
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index 2cdca829ffb9..8344e6f49a67 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -98,3 +98,13 @@ namespace rdar13185264 {
union { void *a; };
};
}
+
+namespace PR16596 {
+ class A { public: virtual ~A(); };
+ typedef const A Foo;
+ void Apply(Foo processor);
+ struct Bar : public Foo {};
+ void Fetch() {
+ Apply(Bar());
+ }
+}
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
index f2ff9fcfd7c1..64c8ceba995e 100644
--- a/test/SemaCXX/class-layout.cpp
+++ b/test/SemaCXX/class-layout.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11
// expected-no-diagnostics
#define SA(n, p) int a##n[(p) ? 1 : -1]
@@ -103,3 +104,469 @@ struct H { G g; };
SA(0, sizeof(H) == 24);
}
+
+namespace PR16537 {
+namespace test1 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only {
+ char may_go_into_tail_padding;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test2 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11 __attribute__((aligned(16)));
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only {
+ char may_go_into_tail_padding;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test3 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct second_base {
+ char foo;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base {
+
+ };
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test4 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct second_base {
+ char foo;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base {
+ char may_go_into_tail_padding;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test5 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct pod_in_11_only2 {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct second_base {
+ pod_in_11_only2 two;
+ char foo;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base {
+ char may_go_into_tail_padding;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 32);
+}
+
+namespace test6 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct pod_in_11_only2 {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct second_base {
+ pod_in_11_only2 two;
+ char foo;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base {
+ char may_go_into_tail_padding;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 32);
+}
+
+namespace test7 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ pod_in_11_only pod12;
+ char tail_padding;
+ };
+
+ struct might_use_tail_padding : public tail_padded_pod_in_11_only {
+ char may_go_into_tail_padding;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 24);
+}
+
+namespace test8 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct another_layer {
+ tail_padded_pod_in_11_only pod;
+ char padding;
+ };
+
+ struct might_use_tail_padding : public another_layer {
+ char may_go_into_tail_padding;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 24);
+}
+
+namespace test9 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct tail_padded_pod_in_11_only {
+ pod_in_11_only pod11;
+ char tail_padding;
+ };
+
+ struct another_layer : tail_padded_pod_in_11_only {
+ };
+
+ struct might_use_tail_padding : public another_layer {
+ char may_go_into_tail_padding;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test10 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B {
+ char b;
+ };
+
+ struct C {
+ pod_in_11_only c;
+ char cpad;
+ };
+
+ struct D {
+ char d;
+ };
+
+ struct might_use_tail_padding : public A, public B, public C, public D {
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 32);
+}
+
+namespace test11 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B {
+ char b_pre;
+ pod_in_11_only b;
+ char bpad;
+ };
+
+ struct C {
+ char c_pre;
+ pod_in_11_only c;
+ char cpad;
+ };
+
+ struct D {
+ char d_pre;
+ pod_in_11_only d;
+ char dpad;
+ };
+
+ struct might_use_tail_padding : public A, public B, public C, public D {
+ char m;
+ };
+
+ SA(0, sizeof(might_use_tail_padding) == 88);
+}
+
+namespace test12 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a __attribute__((aligned(128)));
+ };
+
+ struct B {
+ char bpad;
+ };
+
+ struct C {
+ char cpad;
+ };
+
+ struct D {
+ char dpad;
+ };
+
+ struct might_use_tail_padding : public A, public B, public C, public D {
+ char m;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 128);
+}
+
+namespace test13 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B {
+ };
+
+ struct C {
+ char c_pre;
+ pod_in_11_only c;
+ char cpad;
+ };
+
+ struct D {
+ };
+
+ struct might_use_tail_padding : public A, public B, public C, public D {
+ char m;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 40);
+}
+
+namespace test14 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct might_use_tail_padding : public A {
+ struct {
+ int : 0;
+ } x;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test15 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct might_use_tail_padding : public A {
+ struct {
+ char a:1;
+ char b:2;
+ char c:2;
+ char d:2;
+ char e:1;
+ } x;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 16);
+}
+
+namespace test16 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B {
+ char bpod;
+ pod_in_11_only b;
+ char bpad;
+ };
+
+ struct C : public A, public B {
+ };
+
+ struct D : public C {
+ };
+
+ struct might_use_tail_padding : public D {
+ char m;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 40);
+}
+
+namespace test17 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a __attribute__((aligned(512)));
+ };
+
+ struct B {
+ char bpad;
+ pod_in_11_only foo;
+ char btail;
+ };
+
+ struct C {
+ char cpad;
+ };
+
+ struct D {
+ char dpad;
+ };
+
+ struct might_use_tail_padding : public A, public B, public C, public D {
+ char a;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 512);
+}
+
+namespace test18 {
+ struct pod_in_11_only {
+ private:
+ long long x;
+ };
+
+ struct A {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B {
+ char bpod;
+ pod_in_11_only b;
+ char bpad;
+ };
+
+ struct A1 {
+ pod_in_11_only a;
+ char apad;
+ };
+
+ struct B1 {
+ char bpod;
+ pod_in_11_only b;
+ char bpad;
+ };
+
+ struct C : public A, public B {
+ };
+
+ struct D : public A1, public B1 {
+ };
+
+ struct E : public D, public C {
+ };
+
+ struct F : public E {
+ };
+
+ struct might_use_tail_padding : public F {
+ char m;
+ };
+ SA(0, sizeof(might_use_tail_padding) == 80);
+}
+} // namespace PR16537
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 972a79bb6090..636f584cf625 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -126,12 +126,8 @@ struct S
// Don't crash on this bogus code.
namespace pr6629 {
- // TODO: most of these errors are spurious
template<class T1, class T2> struct foo :
- bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}} \
- // BOGUS expected-error {{expected '{' after base class list}} \
- // BOGUS expected-error {{expected ';' after struct}} \
- // BOGUS expected-error {{expected unqualified-id}}
+ bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}}
{ };
template<> struct foo<unknown,unknown> { // expected-error {{undeclared identifier 'unknown'}}
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index feb1ccb9a20d..8214f7899ecf 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -355,3 +355,70 @@ void test9(int x) {
};
(void)((E)x == 1);
}
+
+namespace templates {
+ template<class T> T max();
+
+ template<> constexpr int max<int>() { return 2147483647; };
+
+ template<typename T>
+ bool less_than_max(short num, T value) {
+ const T vmax = max<T>();
+ return (vmax >= num); // no warning
+ }
+
+ template<typename T>
+ bool less_than_max(short num) {
+ // This should trigger one warning on the template pattern, and not a
+ // warning per specialization.
+ return num < max<int>(); // expected-warning{{comparison of constant 2147483647 with expression of type 'short' is always true}}
+ }
+
+ void test10(short num, int x) {
+ less_than_max(num, x);
+ less_than_max<int>(num);
+ less_than_max<long>(num);
+ less_than_max<short>(num);
+ }
+
+ template<typename T>
+ inline bool less_than_zero(T num, T value) {
+ return num < 0; // no warning
+ }
+
+ template<typename T>
+ inline bool less_than_zero(unsigned num) {
+ // This should trigger one warning on the template pattern, and not a
+ // warning per specialization.
+ return num < 0; // expected-warning{{comparison of unsigned expression < 0 is always false}}
+ }
+
+ void test11(unsigned num) {
+ less_than_zero(num, num);
+ less_than_zero<int>(num);
+ less_than_zero<long>(num);
+ less_than_zero<short>(num);
+ }
+
+ template<unsigned n> bool compare(unsigned k) { return k >= n; }
+
+ void test12() {
+ compare<0>(42);
+ }
+
+ struct A { static int x; };
+ struct B { static int x; };
+ typedef A otherA;
+
+ template <typename T>
+ void testx() {
+ if (A::x == T::x && // no warning
+ A::x == otherA::x) // expected-warning{{self-comparison always evaluates to true}}
+ return;
+ }
+
+ void test13() {
+ testx<A>();
+ testx<B>();
+ }
+}
diff --git a/test/SemaCXX/complex-overload.cpp b/test/SemaCXX/complex-overload.cpp
index 719a850dbf77..1381968751af 100644
--- a/test/SemaCXX/complex-overload.cpp
+++ b/test/SemaCXX/complex-overload.cpp
@@ -42,9 +42,15 @@ void test_promote_or_convert2(float _Complex fc) {
int *cp = promote_or_convert2(fc);
}
-char *promote_or_convert3(int _Complex);
-int *promote_or_convert3(long _Complex);
+char *promote_or_convert3(int _Complex); // expected-note {{candidate}}
+int *promote_or_convert3(long _Complex); // expected-note {{candidate}}
void test_promote_or_convert3(short _Complex sc) {
- char *cp = promote_or_convert3(sc);
+ char *cp1 = promote_or_convert3(sc);
+ char *cp2 = promote_or_convert3(1i);
+ int *cp3 = promote_or_convert3(1il);
+ int *cp4 = promote_or_convert3(1ill); // expected-error {{ambiguous}}
}
+
+char &convert4(short _Complex);
+char &test_convert4 = convert4(1i);
diff --git a/test/SemaCXX/compound-literal.cpp b/test/SemaCXX/compound-literal.cpp
index 595747e40ce6..3fc61505dfee 100644
--- a/test/SemaCXX/compound-literal.cpp
+++ b/test/SemaCXX/compound-literal.cpp
@@ -76,3 +76,13 @@ namespace brace_initializers {
(void)(PrivateDtor){1, 2}; // expected-error {{temporary of type 'brace_initializers::PrivateDtor' has private destructor}}
}
}
+
+// This doesn't necessarily need to be an error, but CodeGen can't handle it
+// at the moment.
+int PR17415 = (int){PR17415}; // expected-error {{initializer element is not a compile-time constant}}
+
+// Make sure we accept this. (Not sure if we actually should... but we do
+// at the moment.)
+template<unsigned> struct Value { };
+template<typename T>
+int &check_narrowed(Value<sizeof((T){1.1})>);
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 692aaefc9d54..5abee4a3c4f8 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -81,6 +81,8 @@ void test()
i1 ? test() : test();
i1 = i1 ? throw 0 : 0;
i1 = i1 ? 0 : throw 0;
+ i1 = i1 ? (throw 0) : 0;
+ i1 = i1 ? 0 : (throw 0);
i1 ? 0 : test(); // expected-error {{right operand to ? is void, but left operand is of type 'int'}}
i1 ? test() : 0; // expected-error {{left operand to ? is void, but right operand is of type 'int'}}
(i1 ? throw 0 : i1) = 0; // expected-error {{expression is not assignable}}
diff --git a/test/SemaCXX/const-cast.cpp b/test/SemaCXX/const-cast.cpp
index 62851f81280f..1fe350d1977a 100644
--- a/test/SemaCXX/const-cast.cpp
+++ b/test/SemaCXX/const-cast.cpp
@@ -38,6 +38,7 @@ char ***good_const_cast_test(ccvpcvpp var)
f *fpp = const_cast<f*>(&fp);
int const A::* const A::*icapcap = 0;
int A::* A::* iapap = const_cast<int A::* A::*>(icapcap);
+ (void)const_cast<A&&>(A()); // expected-warning {{C++11}}
return var4;
}
@@ -60,5 +61,6 @@ short *bad_const_cast_test(char const *volatile *const volatile *var)
f fp2 = const_cast<f>(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}}
void (A::*mfn)() = 0;
(void)const_cast<void (A::*)()>(mfn); // expected-error {{const_cast to 'void (A::*)()', which is not a reference, pointer-to-object, or pointer-to-data-member}}
+ (void)const_cast<int&&>(0); // expected-error {{const_cast from rvalue to reference type 'int &&'}} expected-warning {{C++11}}
return **var3;
}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 09a9cb5dd8db..6724be7c8204 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment
+// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment
namespace StaticAssertFoldTest {
@@ -79,6 +79,11 @@ constexpr int **n6 = const_cast<int**>(&n3);
constexpr int n7 = **n5;
constexpr int n8 = **n6;
+// const_cast from prvalue to xvalue.
+struct A { int n; };
+constexpr int n9 = (const_cast<A&&>(A{123})).n;
+static_assert(n9 == 123, "");
+
}
namespace TemplateArgumentConversion {
@@ -339,6 +344,46 @@ static_assert(!same(4, 4), "");
static_assert(same(n, n), "");
static_assert(sameTemporary(9), "");
+struct A { int &&r; };
+struct B { A &&a1; A &&a2; };
+
+constexpr B b1 { { 1 }, { 2 } }; // expected-note {{temporary created here}}
+static_assert(&b1.a1 != &b1.a2, "");
+static_assert(&b1.a1.r != &b1.a2.r, ""); // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}
+
+constexpr B &&b2 { { 3 }, { 4 } }; // expected-note {{temporary created here}}
+static_assert(&b1 != &b2, "");
+static_assert(&b1.a1 != &b2.a1, ""); // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}
+
+constexpr thread_local B b3 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}
+void foo() {
+ constexpr static B b1 { { 1 }, { 2 } }; // ok
+ constexpr thread_local B b2 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}
+ 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}}
+static_assert(&b4 != &b2, "");
+
+// Proposed DR: copy-elision doesn't trigger lifetime extension.
+constexpr B b5 = B{ {0}, {0} }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}
+
+namespace NestedNonStatic {
+ // Proposed DR: for a reference constant expression to refer to a static
+ // storage duration temporary, that temporary must itself be initialized
+ // by a constant expression (a core constant expression is not enough).
+ struct A { int &&r; };
+ struct B { A &&a; };
+ constexpr B a = { A{0} }; // ok
+ constexpr B b = { A(A{0}) }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}
+}
+
+namespace FakeInitList {
+ struct init_list_3_ints { const int (&x)[3]; };
+ struct init_list_2_init_list_3_ints { const init_list_3_ints (&x)[2]; };
+ constexpr init_list_2_init_list_3_ints ils = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } };
+}
+
}
constexpr int strcmp_ce(const char *p, const char *q) {
@@ -572,7 +617,7 @@ struct E {
constexpr E() : p(&p) {}
void *p;
};
-constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{reference to temporary is not a constant expression}} expected-note {{temporary created here}}
+constexpr const E &e1 = E();
// This is a constant expression if we elide the copy constructor call, and
// is not a constant expression if we don't! But we do, so it is.
constexpr E e2 = E();
@@ -729,15 +774,22 @@ static_assert(&ok2 == pok2, "");
static_assert((Base2*)(Derived*)(Base*)pb1 == pok2, "");
static_assert((Derived*)(Base*)pb1 == (Derived*)pok2, "");
-constexpr Base *nullB = 42 - 6 * 7; // expected-warning {{expression which evaluates to zero treated as a null pointer constant of type 'Class::Base *const'}}
+// Core issue 903: we do not perform constant evaluation when checking for a
+// null pointer in C++11. Just check for an integer literal with value 0.
+constexpr Base *nullB = 42 - 6 * 7; // expected-error {{cannot initialize a variable of type 'Class::Base *const' with an rvalue of type 'int'}}
+constexpr Base *nullB1 = 0;
static_assert((Bottom*)nullB == 0, "");
static_assert((Derived*)nullB == 0, "");
static_assert((void*)(Bottom*)nullB == (void*)(Derived*)nullB, "");
-Base * nullB2 = '\0'; // expected-warning {{expression which evaluates to zero treated as a null pointer constant of type 'Class::Base *'}}
-Base * nullB3 = (0);
-// We suppress the warning in unevaluated contexts to workaround some gtest
-// behavior. Once this becomes an error this isn't a problem anymore.
-static_assert(nullB == (1 - 1), "");
+Base *nullB2 = '\0'; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'char'}}
+Base *nullB3 = (0);
+Base *nullB4 = false; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'bool'}}
+Base *nullB5 = ((0ULL));
+Base *nullB6 = 0.; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'double'}}
+enum Null { kNull };
+Base *nullB7 = kNull; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'Class::Null'}}
+static_assert(nullB1 == (1 - 1), ""); // expected-error {{comparison between pointer and integer}}
+
namespace ConversionOperators {
@@ -778,21 +830,26 @@ namespace Temporaries {
struct S {
constexpr S() {}
constexpr int f() const;
+ constexpr int g() const;
};
struct T : S {
constexpr T(int n) : S(), n(n) {}
int n;
};
constexpr int S::f() const {
- // 'this' must be the postfix-expression in a class member access expression,
- // so we can't just use
- // return static_cast<T*>(this)->n;
- return this->*(int(S::*))&T::n;
+ return static_cast<const T*>(this)->n; // expected-note {{cannot cast}}
+}
+constexpr int S::g() const {
+ // FIXME: Better diagnostic for this.
+ return this->*(int(S::*))&T::n; // expected-note {{subexpression}}
}
// The T temporary is implicitly cast to an S subobject, but we can recover the
// T full-object via a base-to-derived cast, or a derived-to-base-casted member
// pointer.
+static_assert(S().f(), ""); // expected-error {{constant expression}} expected-note {{in call to '&Temporaries::S()->f()'}}
+static_assert(S().g(), ""); // expected-error {{constant expression}} expected-note {{in call to '&Temporaries::S()->g()'}}
static_assert(T(3).f() == 3, "");
+static_assert(T(4).g() == 4, "");
constexpr int f(const S &s) {
return static_cast<const T&>(s).n;
@@ -1138,6 +1195,31 @@ namespace ComplexConstexpr {
static_assert(&__imag test6 == &__real test6 + 1, "");
}
+// _Atomic(T) is exactly like T for the purposes of constant expression
+// evaluation..
+namespace Atomic {
+ constexpr _Atomic int n = 3;
+
+ struct S { _Atomic(double) d; };
+ constexpr S s = { 0.5 };
+ constexpr double d1 = s.d;
+ constexpr double d2 = n;
+ constexpr _Atomic double d3 = n;
+
+ constexpr _Atomic(int) n2 = d3;
+ static_assert(d1 == 0.5, "");
+ static_assert(d3 == 3.0, "");
+
+ namespace PR16056 {
+ struct TestVar {
+ _Atomic(int) value;
+ constexpr TestVar(int value) : value(value) {}
+ };
+ constexpr TestVar testVar{-1};
+ static_assert(testVar.value == -1, "");
+ }
+}
+
namespace InstantiateCaseStmt {
template<int x> constexpr int f() { return x; }
template<int x> int g(int c) { switch(c) { case f<x>(): return 1; } return 0; }
@@ -1252,8 +1334,23 @@ struct Wrap {
constexpr const Wrap &g(const Wrap &w) { return w; }
constexpr int k2 = g({0}).value; // ok
-constexpr const int &i = 0; // expected-error {{constant expression}} expected-note {{temporary}} expected-note 2{{here}}
-constexpr const int j = i; // expected-error {{constant expression}} expected-note {{initializer of 'i' is not a constant expression}}
+// The temporary here has static storage duration, so we can bind a constexpr
+// reference to it.
+constexpr const int &i = 1;
+constexpr const int j = i;
+static_assert(j == 1, "");
+
+// The temporary here is not const, so it can't be read outside the expression
+// in which it was created (per the C++14 rules, which we use to avoid a C++11
+// defect).
+constexpr int &&k = 1; // expected-note {{temporary created here}}
+constexpr const int l = k; // expected-error {{constant expression}} expected-note {{read of temporary}}
+
+void f() {
+ // The temporary here has automatic storage duration, so we can't bind a
+ // constexpr reference to it.
+ constexpr const int &i = 1; // expected-error {{constant expression}} expected-note 2{{temporary}}
+}
}
@@ -1503,3 +1600,266 @@ namespace PR15884 {
// expected-note@-3 {{pointer to temporary is not a constant expression}}
// expected-note@-4 {{temporary created here}}
}
+
+namespace AfterError {
+ // FIXME: Suppress the 'no return statements' diagnostic if the body is invalid.
+ constexpr int error() { // expected-error {{no return statement}}
+ return foobar; // expected-error {{undeclared identifier}}
+ }
+ constexpr int k = error(); // expected-error {{must be initialized by a constant expression}}
+}
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ constexpr initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ constexpr size_t size() const {return __size_;}
+ constexpr const _E* begin() const {return __begin_;}
+ constexpr const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace InitializerList {
+ constexpr int sum(const int *b, const int *e) {
+ return b != e ? *b + sum(b+1, e) : 0;
+ }
+ constexpr int sum(std::initializer_list<int> ints) {
+ return sum(ints.begin(), ints.end());
+ }
+ static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
+}
+
+namespace StmtExpr {
+ struct A { int k; };
+ void f() {
+ static_assert(({ const int x = 5; x * 3; }) == 15, ""); // expected-warning {{extension}}
+ constexpr auto a = ({ A(); }); // expected-warning {{extension}}
+ }
+ constexpr int g(int k) {
+ return ({ // expected-warning {{extension}}
+ const int x = k;
+ x * x;
+ });
+ }
+ static_assert(g(123) == 15129, "");
+ constexpr int h() { // expected-error {{never produces a constant}}
+ return ({ // expected-warning {{extension}}
+ return 0; // expected-note {{not supported}}
+ 1;
+ });
+ }
+}
+
+namespace VirtualFromBase {
+ struct S1 {
+ virtual int f() const;
+ };
+ struct S2 {
+ virtual int f();
+ };
+ template <typename T> struct X : T {
+ constexpr X() {}
+ double d = 0.0;
+ constexpr int f() { return sizeof(T); } // expected-warning {{will not be implicitly 'const' in C++1y}}
+ };
+
+ // Virtual f(), not OK.
+ constexpr X<X<S1>> xxs1;
+ constexpr X<S1> *p = const_cast<X<X<S1>>*>(&xxs1);
+ static_assert(p->f() == sizeof(X<S1>), ""); // expected-error {{constant expression}} expected-note {{virtual function call}}
+
+ // Non-virtual f(), OK.
+ constexpr X<X<S2>> xxs2;
+ constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2);
+ static_assert(q->f() == sizeof(S2), "");
+}
+
+namespace ConstexprConstructorRecovery {
+ class X {
+ public:
+ enum E : short {
+ headers = 0x1,
+ middlefile = 0x2,
+ choices = 0x4
+ };
+ constexpr X() noexcept {};
+ protected:
+ E val{0}; // expected-error {{cannot initialize a member subobject of type 'ConstexprConstructorRecovery::X::E' with an rvalue of type 'int'}}
+ };
+ constexpr X x{};
+}
+
+namespace Lifetime {
+ void f() {
+ constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}} expected-warning {{not yet bound to a value}}
+ constexpr int m = m; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
+ }
+
+ constexpr int &get(int &&n) { return n; }
+ struct S {
+ int &&r; // expected-note 2{{declared here}}
+ int &s;
+ int t;
+ constexpr S() : r(0), s(get(0)), t(r) {} // expected-warning {{temporary}}
+ constexpr S(int) : r(0), s(get(0)), t(s) {} // expected-warning {{temporary}} expected-note {{read of object outside its lifetime}}
+ };
+ constexpr int k1 = S().t; // ok, int is lifetime-extended to end of constructor
+ constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}}
+}
+
+namespace Bitfields {
+ struct A {
+ bool b : 1;
+ unsigned u : 5;
+ int n : 5;
+ bool b2 : 3;
+ unsigned u2 : 74; // expected-warning {{exceeds the size of its type}}
+ int n2 : 81; // expected-warning {{exceeds the size of its type}}
+ };
+
+ constexpr A a = { false, 33, 31, false, 0xffffffff, 0x7fffffff }; // expected-warning 2{{truncation}}
+ static_assert(a.b == 0 && a.u == 1 && a.n == -1 && a.b2 == 0 &&
+ a.u2 + 1 == 0 && a.n2 == 0x7fffffff,
+ "bad truncation of bitfield values");
+
+ struct B {
+ int n : 3;
+ constexpr B(int k) : n(k) {}
+ };
+ static_assert(B(3).n == 3, "");
+ static_assert(B(4).n == -4, "");
+ static_assert(B(7).n == -1, "");
+ static_assert(B(8).n == 0, "");
+ static_assert(B(-1).n == -1, "");
+ static_assert(B(-8889).n == -1, "");
+
+ namespace PR16755 {
+ struct X {
+ int x : 1;
+ constexpr static int f(int x) {
+ return X{x}.x;
+ }
+ };
+ static_assert(X::f(3) == -1, "3 should truncate to -1");
+ }
+}
+
+namespace ZeroSizeTypes {
+ constexpr int (*p1)[0] = 0, (*p2)[0] = 0;
+ constexpr int k = p2 - p1;
+ // expected-error@-1 {{constexpr variable 'k' must be initialized by a constant expression}}
+ // expected-note@-2 {{subtraction of pointers to type 'int [0]' of zero size}}
+
+ int arr[5][0];
+ constexpr int f() { // expected-error {{never produces a constant expression}}
+ return &arr[3] - &arr[0]; // expected-note {{subtraction of pointers to type 'int [0]' of zero size}}
+ }
+}
+
+namespace BadDefaultInit {
+ template<int N> struct X { static const int n = N; };
+
+ struct A { // expected-note {{subexpression}}
+ int k = X<A().k>::n; // expected-error {{defaulted default constructor of 'A' cannot be used}} expected-error {{not a constant expression}} expected-note {{in call to 'A()'}}
+ };
+
+ // FIXME: The "constexpr constructor must initialize all members" diagnostic
+ // here is bogus (we discard the k(k) initializer because the parameter 'k'
+ // has been marked invalid).
+ struct B { // expected-note 2{{candidate}}
+ constexpr B( // expected-error {{must initialize all members}} expected-note {{candidate}}
+ int k = X<B().k>::n) : // expected-error {{no matching constructor}}
+ k(k) {}
+ int k; // expected-note {{not initialized}}
+ };
+}
+
+namespace NeverConstantTwoWays {
+ // If we see something non-constant but foldable followed by something
+ // non-constant and not foldable, we want the first diagnostic, not the
+ // second.
+ constexpr int f(int n) { // expected-error {{never produces a constant expression}}
+ return (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
+ 1 / 0 : // expected-warning {{division by zero}}
+ 0;
+ }
+
+ // FIXME: We should diagnose the cast to long here, not the division by zero.
+ constexpr int n = // expected-error {{must be initialized by a constant expression}}
+ (int *)(long)&n == &n ?
+ 1 / 0 : // expected-warning {{division by zero}} expected-note {{division by zero}}
+ 0;
+}
+
+namespace PR17800 {
+ struct A {
+ constexpr int operator()() const { return 0; }
+ };
+ template <typename ...T> constexpr int sink(T ...) {
+ return 0;
+ }
+ template <int ...N> constexpr int run() {
+ return sink(A()() + N ...);
+ }
+ constexpr int k = run<1, 2, 3>();
+}
+
+namespace BuiltinStrlen {
+ constexpr const char *a = "foo\0quux";
+ constexpr char b[] = "foo\0quux";
+ constexpr int f() { return 'u'; }
+ constexpr char c[] = { 'f', 'o', 'o', 0, 'q', f(), 'u', 'x', 0 };
+
+ static_assert(__builtin_strlen("foo") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux" + 4) == 4, "");
+
+ constexpr bool check(const char *p) {
+ return __builtin_strlen(p) == 3 &&
+ __builtin_strlen(p + 1) == 2 &&
+ __builtin_strlen(p + 2) == 1 &&
+ __builtin_strlen(p + 3) == 0 &&
+ __builtin_strlen(p + 4) == 4 &&
+ __builtin_strlen(p + 5) == 3 &&
+ __builtin_strlen(p + 6) == 2 &&
+ __builtin_strlen(p + 7) == 1 &&
+ __builtin_strlen(p + 8) == 0;
+ }
+
+ static_assert(check(a), "");
+ static_assert(check(b), "");
+ static_assert(check(c), "");
+
+ constexpr int over1 = __builtin_strlen(a + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+ constexpr int over2 = __builtin_strlen(b + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+ constexpr int over3 = __builtin_strlen(c + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+
+ constexpr int under1 = __builtin_strlen(a - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+ constexpr int under2 = __builtin_strlen(b - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+ constexpr int under3 = __builtin_strlen(c - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+
+ // FIXME: The diagnostic here could be better.
+ constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
+ constexpr int bad = __builtin_strlen(d); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+}
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index 60ec82062de5..521526ddba44 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -128,10 +128,10 @@ constexpr int namespace_alias() {
namespace assign {
constexpr int a = 0;
const int b = 0;
- int c = 0; // expected-note 2{{here}}
+ int c = 0; // expected-note {{here}}
constexpr void set(const int &a, int b) {
- const_cast<int&>(a) = b; // expected-note 2{{constant expression cannot modify an object that is visible outside that expression}}
+ const_cast<int&>(a) = b; // expected-note 3{{constant expression cannot modify an object that is visible outside that expression}}
}
constexpr int wrap(int a, int b) {
set(a, b);
@@ -140,7 +140,7 @@ namespace assign {
static_assert((set(a, 1), a) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(a, 1)'}}
static_assert((set(b, 1), b) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(b, 1)'}}
- static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{read of non-const variable 'c'}}
+ static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(c, 1)'}}
static_assert(wrap(a, 1) == 1, "");
static_assert(wrap(b, 1) == 1, "");
@@ -250,11 +250,12 @@ namespace lifetime {
}
namespace const_modify {
- constexpr int modify(int &n) { return n = 1; } // expected-note {{modification of object of const-qualified type 'const int'}}
+ constexpr int modify(int &n) { return n = 1; } // expected-note 2 {{modification of object of const-qualified type 'const int'}}
constexpr int test1() { int k = 0; return modify(k); }
- constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note {{in call}}
+ constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note 2 {{in call}}
static_assert(test1() == 1, "");
static_assert(test2() == 1, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int i = test2(); // expected-error {{constant expression}} expected-note {{in call}}
}
namespace null {
@@ -334,6 +335,99 @@ namespace incdec {
static_assert(incr(0) == 101, "");
}
+namespace compound_assign {
+ constexpr bool test_int() {
+ int a = 3;
+ a += 6;
+ if (a != 9) return false;
+ a -= 2;
+ if (a != 7) return false;
+ a *= 3;
+ if (a != 21) return false;
+ if (&(a /= 10) != &a) return false;
+ if (a != 2) return false;
+ a <<= 3;
+ if (a != 16) return false;
+ a %= 6;
+ if (a != 4) return false;
+ a >>= 1;
+ if (a != 2) return false;
+ a ^= 10;
+ if (a != 8) return false;
+ a |= 5;
+ if (a != 13) return false;
+ a &= 14;
+ if (a != 12) return false;
+ return true;
+ }
+ static_assert(test_int(), "");
+
+ constexpr bool test_float() {
+ float f = 123.;
+ f *= 2;
+ if (f != 246.) return false;
+ if ((f -= 0.5) != 245.5) return false;
+ if (f != 245.5) return false;
+ f /= 0.5;
+ if (f != 491.) return false;
+ f += -40;
+ if (f != 451.) return false;
+ return true;
+ }
+ static_assert(test_float(), "");
+
+ constexpr bool test_ptr() {
+ int arr[123] = {};
+ int *p = arr;
+ if ((p += 4) != &arr[4]) return false;
+ if (p != &arr[4]) return false;
+ p += -1;
+ if (p != &arr[3]) return false;
+ if ((p -= -10) != &arr[13]) return false;
+ if (p != &arr[13]) return false;
+ p -= 11;
+ if (p != &arr[2]) return false;
+ return true;
+ }
+ static_assert(test_ptr(), "");
+
+ template<typename T>
+ constexpr bool test_overflow() {
+ T a = 1;
+ while (a != a / 2)
+ a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }} expected-note {{floating point arithmetic produces an infinity}}
+ return true;
+ }
+
+ static_assert(test_overflow<int>(), ""); // expected-error {{constant}} expected-note {{call}}
+ static_assert(test_overflow<unsigned>(), ""); // ok, unsigned overflow is defined
+ static_assert(test_overflow<short>(), ""); // ok, short is promoted to int before multiplication
+ static_assert(test_overflow<unsigned short>(), ""); // ok
+ static_assert(test_overflow<unsigned long long>(), ""); // ok
+ static_assert(test_overflow<long long>(), ""); // expected-error {{constant}} expected-note {{call}}
+ static_assert(test_overflow<float>(), ""); // expected-error {{constant}} expected-note {{call}}
+
+ constexpr short test_promotion(short k) {
+ short s = k;
+ s *= s;
+ return s;
+ }
+ static_assert(test_promotion(100) == 10000, "");
+ static_assert(test_promotion(200) == -25536, "");
+ static_assert(test_promotion(256) == 0, "");
+
+ constexpr const char *test_bounds(const char *p, int o) {
+ return p += o; // expected-note {{element 5 of}} expected-note {{element -1 of}} expected-note {{element 1000 of}}
+ }
+ static_assert(test_bounds("foo", 0)[0] == 'f', "");
+ static_assert(test_bounds("foo", 3)[0] == 0, "");
+ static_assert(test_bounds("foo", 4)[-3] == 'o', "");
+ static_assert(test_bounds("foo" + 4, -4)[0] == 'f', "");
+ static_assert(test_bounds("foo", 5) != 0, ""); // expected-error {{constant}} expected-note {{call}}
+ static_assert(test_bounds("foo", -1) != 0, ""); // expected-error {{constant}} expected-note {{call}}
+ static_assert(test_bounds("foo", 1000) != 0, ""); // expected-error {{constant}} expected-note {{call}}
+}
+
namespace loops {
constexpr int fib_loop(int a) {
int f_k = 0, f_k_plus_one = 1;
@@ -407,7 +501,7 @@ namespace loops {
int arr[] = { 1, 2, 3, 4, 5 };
int sum = 0;
for (int x : arr)
- sum = sum + x;
+ sum += x;
return sum;
}
static_assert(range_for() == 15, "");
@@ -450,10 +544,370 @@ namespace loops {
array<int, 5> arr { 1, 2, 3, 4, 5 };
int sum = 0;
for (int k : arr) {
- sum = sum + k;
+ sum += k;
if (sum > 8) break;
}
return sum;
}
static_assert(range_for_2() == 10, "");
}
+
+namespace assignment_op {
+ struct A {
+ constexpr A() : n(5) {}
+ int n;
+ struct B {
+ int k = 1;
+ union U {
+ constexpr U() : y(4) {}
+ int x;
+ int y;
+ } u;
+ } b;
+ };
+ constexpr bool testA() {
+ A a, b;
+ a.n = 7;
+ a.b.u.y = 5;
+ b = a;
+ return b.n == 7 && b.b.u.y == 5 && b.b.k == 1;
+ }
+ static_assert(testA(), "");
+
+ struct B {
+ bool assigned = false;
+ constexpr B &operator=(const B&) {
+ assigned = true;
+ return *this;
+ }
+ };
+ struct C : B {
+ B b;
+ int n = 5;
+ };
+ constexpr bool testC() {
+ C c, d;
+ c.n = 7;
+ d = c;
+ c.n = 3;
+ return d.n == 7 && d.assigned && d.b.assigned;
+ }
+ static_assert(testC(), "");
+}
+
+namespace switch_stmt {
+ constexpr int f(char k) {
+ bool b = false;
+ int z = 6;
+ switch (k) {
+ return -1;
+ case 0:
+ if (false) {
+ case 1:
+ z = 1;
+ for (; b;) {
+ return 5;
+ while (0)
+ case 2: return 2;
+ case 7: z = 7;
+ do case 6: {
+ return z;
+ if (false)
+ case 3: return 3;
+ case 4: z = 4;
+ } while (1);
+ case 5: b = true;
+ case 9: z = 9;
+ }
+ return z;
+ } else if (false) case 8: z = 8;
+ else if (false) {
+ case 10:
+ z = -10;
+ break;
+ }
+ else z = 0;
+ return z;
+ default:
+ return -1;
+ }
+ return -z;
+ }
+ static_assert(f(0) == 0, "");
+ static_assert(f(1) == 1, "");
+ static_assert(f(2) == 2, "");
+ static_assert(f(3) == 3, "");
+ static_assert(f(4) == 4, "");
+ static_assert(f(5) == 5, "");
+ static_assert(f(6) == 6, "");
+ static_assert(f(7) == 7, "");
+ static_assert(f(8) == 8, "");
+ static_assert(f(9) == 9, "");
+ static_assert(f(10) == 10, "");
+
+ // Check that we can continue an outer loop from within a switch.
+ constexpr bool contin() {
+ for (int n = 0; n != 10; ++n) {
+ switch (n) {
+ case 0:
+ ++n;
+ continue;
+ case 1:
+ return false;
+ case 2:
+ return true;
+ }
+ }
+ return false;
+ }
+ static_assert(contin(), "");
+
+ constexpr bool switch_into_for() {
+ int n = 0;
+ switch (n) {
+ for (; n == 1; ++n) {
+ return n == 1;
+ case 0: ;
+ }
+ }
+ return false;
+ }
+ static_assert(switch_into_for(), "");
+
+ constexpr void duff_copy(char *a, const char *b, int n) {
+ switch ((n - 1) % 8 + 1) {
+ for ( ; n; n = (n - 1) & ~7) {
+ case 8: a[n-8] = b[n-8];
+ case 7: a[n-7] = b[n-7];
+ case 6: a[n-6] = b[n-6];
+ case 5: a[n-5] = b[n-5];
+ case 4: a[n-4] = b[n-4];
+ case 3: a[n-3] = b[n-3];
+ case 2: a[n-2] = b[n-2];
+ case 1: a[n-1] = b[n-1];
+ }
+ case 0: ;
+ }
+ }
+
+ constexpr bool test_copy(const char *str, int n) {
+ char buffer[16] = {};
+ duff_copy(buffer, str, n);
+ for (int i = 0; i != sizeof(buffer); ++i)
+ if (buffer[i] != (i < n ? str[i] : 0))
+ return false;
+ return true;
+ }
+ static_assert(test_copy("foo", 0), "");
+ static_assert(test_copy("foo", 1), "");
+ static_assert(test_copy("foo", 2), "");
+ static_assert(test_copy("hello world", 0), "");
+ static_assert(test_copy("hello world", 7), "");
+ static_assert(test_copy("hello world", 8), "");
+ static_assert(test_copy("hello world", 9), "");
+ static_assert(test_copy("hello world", 10), "");
+ static_assert(test_copy("hello world", 10), "");
+}
+
+namespace deduced_return_type {
+ constexpr auto f() { return 0; }
+ template<typename T> constexpr auto g(T t) { return t; }
+ static_assert(f() == 0, "");
+ static_assert(g(true), "");
+}
+
+namespace modify_temporary_during_construction {
+ struct A { int &&temporary; int x; int y; };
+ constexpr int f(int &r) { r *= 9; return r - 12; }
+ // FIXME: The 'uninitialized' warning here is bogus.
+ constexpr A a = { 6, f(a.temporary), a.temporary }; // expected-warning {{uninitialized}} expected-note {{temporary created here}}
+ static_assert(a.x == 42, "");
+ static_assert(a.y == 54, "");
+ constexpr int k = a.temporary++; // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}
+}
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ constexpr initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ constexpr size_t size() const {return __size_;}
+ constexpr const _E* begin() const {return __begin_;}
+ constexpr const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace InitializerList {
+ constexpr int sum(std::initializer_list<int> ints) {
+ int total = 0;
+ for (int n : ints) total += n;
+ return total;
+ }
+ static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
+}
+
+namespace StmtExpr {
+ constexpr int f(int k) {
+ switch (k) {
+ case 0:
+ return 0;
+
+ ({
+ case 1: // expected-note {{not supported}}
+ return 1;
+ });
+ }
+ }
+ static_assert(f(1) == 1, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+ constexpr int g() { // expected-error {{never produces a constant}}
+ return ({ int n; n; }); // expected-note {{object of type 'int' is not initialized}}
+ }
+
+ // FIXME: We should handle the void statement expression case.
+ constexpr int h() { // expected-error {{never produces a constant}}
+ ({ if (true) {} }); // expected-note {{not supported}}
+ return 0;
+ }
+}
+
+namespace VirtualFromBase {
+ struct S1 {
+ virtual int f() const;
+ };
+ struct S2 {
+ virtual int f();
+ };
+ template <typename T> struct X : T {
+ constexpr X() {}
+ double d = 0.0;
+ constexpr int f() { return sizeof(T); }
+ };
+
+ // Non-virtual f(), OK.
+ constexpr X<X<S1>> xxs1;
+ constexpr X<S1> *p = const_cast<X<X<S1>>*>(&xxs1);
+ static_assert(p->f() == sizeof(S1), "");
+
+ // Virtual f(), not OK.
+ constexpr X<X<S2>> xxs2;
+ constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2);
+ static_assert(q->f() == sizeof(X<S2>), ""); // expected-error {{constant expression}} expected-note {{virtual function call}}
+}
+
+namespace Lifetime {
+ constexpr int &get(int &&r) { return r; }
+ constexpr int f() {
+ int &r = get(123);
+ return r; // expected-note {{read of object outside its lifetime}}
+ }
+ static_assert(f() == 123, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+ constexpr int g() {
+ int *p = 0;
+ {
+ int n = 0;
+ p = &n;
+ n = 42;
+ }
+ *p = 123; // expected-note {{assignment to object outside its lifetime}}
+ return *p;
+ }
+ static_assert(g() == 42, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+ constexpr int h(int n) {
+ int *p[4] = {};
+ int &&r = 1;
+ p[0] = &r;
+ while (int a = 1) {
+ p[1] = &a;
+ for (int b = 1; int c = 1; ) {
+ p[2] = &b, p[3] = &c;
+ break;
+ }
+ break;
+ }
+ *p[n] = 0; // expected-note 3{{assignment to object outside its lifetime}}
+ return *p[n];
+ }
+ static_assert(h(0) == 0, ""); // ok, lifetime-extended
+ static_assert(h(1) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ static_assert(h(2) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ static_assert(h(3) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+ // FIXME: This function should be treated as non-constant.
+ constexpr void lifetime_versus_loops() {
+ int *p = 0;
+ for (int i = 0; i != 2; ++i) {
+ int *q = p;
+ int n = 0;
+ p = &n;
+ if (i)
+ // This modifies the 'n' from the previous iteration of the loop outside
+ // its lifetime.
+ ++*q;
+ }
+ }
+ static_assert((lifetime_versus_loops(), true), "");
+}
+
+namespace Bitfields {
+ struct A {
+ bool b : 3;
+ int n : 4;
+ unsigned u : 5;
+ };
+ constexpr bool test() {
+ A a {};
+ a.b += 2;
+ --a.n;
+ --a.u;
+ a.n = -a.n * 3;
+ return a.b == false && a.n == 3 && a.u == 31;
+ }
+ static_assert(test(), "");
+}
+
+namespace PR17615 {
+ struct A {
+ int &&r;
+ constexpr A(int &&r) : r(static_cast<int &&>(r)) {}
+ constexpr A() : A(0) {
+ (void)+r; // expected-note {{outside its lifetime}}
+ }
+ };
+ constexpr int k = A().r; // expected-error {{constant expression}} expected-note {{in call to}}
+}
+
+namespace PR17331 {
+ template<typename T, unsigned int N>
+ constexpr T sum(const T (&arr)[N]) {
+ T result = 0;
+ for (T i : arr)
+ result += i;
+ return result;
+ }
+
+ constexpr int ARR[] = { 1, 2, 3, 4, 5 };
+ static_assert(sum(ARR) == 15, "");
+}
diff --git a/test/SemaCXX/constexpr-backtrace-limit.cpp b/test/SemaCXX/constexpr-backtrace-limit.cpp
index 9c40eedabd08..64a26cf29992 100644
--- a/test/SemaCXX/constexpr-backtrace-limit.cpp
+++ b/test/SemaCXX/constexpr-backtrace-limit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 0 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST1
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 0 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST1
// TEST1: constant expression
// TEST1-NEXT: exceeded maximum depth of 4
// TEST1-NEXT: in call to 'recurse(2)'
@@ -6,21 +6,21 @@
// TEST1-NEXT: in call to 'recurse(4)'
// TEST1-NEXT: in call to 'recurse(5)'
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST2
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST2
// TEST2: constant expression
// TEST2-NEXT: exceeded maximum depth of 4
// TEST2-NEXT: in call to 'recurse(2)'
// TEST2-NEXT: skipping 2 calls
// TEST2-NEXT: in call to 'recurse(5)'
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
// TEST3: constant expression
// TEST3-NEXT: reinterpret_cast
// TEST3-NEXT: in call to 'recurse(0)'
// TEST3-NEXT: skipping 4 calls
// TEST3-NEXT: in call to 'recurse(5)'
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
// TEST4: constant expression
// TEST4-NEXT: reinterpret_cast
// TEST4-NEXT: in call to 'recurse(0)'
diff --git a/test/SemaCXX/constexpr-duffs-device.cpp b/test/SemaCXX/constexpr-duffs-device.cpp
new file mode 100644
index 000000000000..f77d989b9d36
--- /dev/null
+++ b/test/SemaCXX/constexpr-duffs-device.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+// expected-no-diagnostics
+constexpr void copy(const char *from, unsigned long count, char *to) {
+ unsigned long n = (count + 7) / 8;
+ switch(count % 8) {
+ case 0: do { *to++ = *from++;
+ case 7: *to++ = *from++;
+ case 6: *to++ = *from++;
+ case 5: *to++ = *from++;
+ case 4: *to++ = *from++;
+ case 3: *to++ = *from++;
+ case 2: *to++ = *from++;
+ case 1: *to++ = *from++;
+ } while(--n > 0);
+ }
+}
+
+struct S {
+ char stuff[14];
+ constexpr S() : stuff{} {
+ copy("Hello, world!", 14, stuff);
+ }
+};
+
+constexpr bool streq(const char *a, const char *b) {
+ while (*a && *a == *b) ++a, ++b;
+ return *a == *b;
+}
+
+static_assert(streq(S().stuff, "Hello, world!"), "should be same");
+static_assert(!streq(S().stuff, "Something else"), "should be different");
diff --git a/test/SemaCXX/constexpr-steps.cpp b/test/SemaCXX/constexpr-steps.cpp
new file mode 100644
index 000000000000..f7967eee9f78
--- /dev/null
+++ b/test/SemaCXX/constexpr-steps.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s -DMAX=1234 -fconstexpr-steps 1234
+// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s -DMAX=10 -fconstexpr-steps 10
+// RUN: %clang -std=c++1y -fsyntax-only -Xclang -verify %s -DMAX=12345 -fconstexpr-steps=12345
+
+// This takes a total of n + 4 steps according to our current rules:
+// - One for the compound-statement that is the function body
+// - One for the 'for' statement
+// - One for the 'int k = 0;' statement
+// - One for each of the n evaluations of the compound-statement in the 'for' body
+// - One for the 'return' statemnet
+constexpr bool steps(int n) {
+ for (int k = 0; k != n; ++k) {}
+ return true; // expected-note {{step limit}}
+}
+
+static_assert(steps((MAX - 4)), ""); // ok
+static_assert(steps((MAX - 3)), ""); // expected-error {{constant}} expected-note{{call}}
diff --git a/test/SemaCXX/constexpr-turing.cpp b/test/SemaCXX/constexpr-turing.cpp
index 07c04eff3083..75aefbf2ab7a 100644
--- a/test/SemaCXX/constexpr-turing.cpp
+++ b/test/SemaCXX/constexpr-turing.cpp
@@ -33,24 +33,24 @@ constexpr Tape move(const Tape &old, Dir dir) { return Tape(old, dir); }
// Run turing machine 'tm' on tape 'tape' from state 'state'. Return number of
// steps taken until halt.
constexpr unsigned run(const State *tm, const Tape &tape, unsigned state) {
- return state == halt ? 1 :
+ return state == halt ? 0 :
run(tm, move(update(tape, tm[state][tape.val].tape),
tm[state][tape.val].dir),
tm[state][tape.val].next) + 1;
}
-// 3-state busy beaver. 14 steps.
+// 3-state busy beaver. S(bb3) = 21.
constexpr State bb3[] = {
- { { true, R, 1 }, { true, L, 2 } },
- { { true, L, 0 }, { true, R, 1 } },
- { { true, L, 1 }, { true, R, halt } }
+ { { true, R, 1 }, { true, R, halt } },
+ { { true, L, 1 }, { false, R, 2 } },
+ { { true, L, 2 }, { true, L, 0 } }
};
-static_assert(run(bb3, Tape(), 0) == 14, "");
+static_assert(run(bb3, Tape(), 0) == 21, "");
-// 4-state busy beaver. 108 steps.
+// 4-state busy beaver. S(bb4) = 107.
constexpr State bb4[] = {
{ { true, R, 1 }, { true, L, 1 } },
{ { true, L, 0 }, { false, L, 2 } },
{ { true, R, halt }, { true, L, 3 } },
{ { true, R, 3 }, { false, R, 0 } } };
-static_assert(run(bb4, Tape(), 0) == 108, "");
+static_assert(run(bb4, Tape(), 0) == 107, "");
diff --git a/test/SemaCXX/constexpr-value-init.cpp b/test/SemaCXX/constexpr-value-init.cpp
index d137bd88db0b..e5b7db50eb65 100644
--- a/test/SemaCXX/constexpr-value-init.cpp
+++ b/test/SemaCXX/constexpr-value-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++11 -fsyntax-only -verify
struct A {
constexpr A() : a(b + 1), b(a + 1) {} // expected-note {{outside its lifetime}}
diff --git a/test/SemaCXX/conversion-delete-expr.cpp b/test/SemaCXX/conversion-delete-expr.cpp
index 0f298a819fa3..a1ddeb2689ad 100644
--- a/test/SemaCXX/conversion-delete-expr.cpp
+++ b/test/SemaCXX/conversion-delete-expr.cpp
@@ -2,11 +2,11 @@
// Test1
struct B {
- operator char *(); // expected-note {{candidate function}}
+ operator char *(); // expected-note {{conversion to pointer type}}
};
struct D : B {
- operator int *(); // expected-note {{candidate function}}
+ operator int *(); // expected-note {{conversion to pointer type}}
};
void f (D d)
@@ -30,11 +30,11 @@ void f1 (D1 d)
// Test3
struct B2 {
- operator const int *(); // expected-note {{candidate function}}
+ operator const int *(); // expected-note {{conversion to pointer type}}
};
struct D2 : B2 {
- operator int *(); // expected-note {{candidate function}}
+ operator int *(); // expected-note {{conversion to pointer type}}
};
void f2 (D2 d)
@@ -44,11 +44,11 @@ void f2 (D2 d)
// Test4
struct B3 {
- operator const int *(); // expected-note {{candidate function}}
+ operator const int *(); // expected-note {{conversion to pointer type}}
};
struct A3 {
- operator const int *(); // expected-note {{candidate function}}
+ operator const int *(); // expected-note {{conversion to pointer type}}
};
struct D3 : A3, B3 {
@@ -78,7 +78,7 @@ void f5(X1 x) { delete x; } // OK. In selecting a conversion to pointer functio
// Test7
struct Base {
- operator int*();
+ operator int*();
};
struct Derived : Base {
@@ -87,9 +87,9 @@ struct Derived : Base {
};
void foo6(const Derived cd, Derived d) {
- // overload resolution selects Derived::operator int*() const;
- delete cd;
- delete d;
+ // overload resolution selects Derived::operator int*() const;
+ delete cd;
+ delete d;
}
// Test8
@@ -104,6 +104,6 @@ struct DD : BB {
void foo7 (DD d)
{
- // OK. In selecting a conversion to pointer function, template convesions are skipped.
- delete d;
+ // OK. In selecting a conversion to pointer function, template convesions are skipped.
+ delete d;
}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 6fca0503ba72..7eaed54934b3 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
class X {
public:
operator bool();
@@ -11,6 +11,8 @@ public:
float g() {
return operator float(); // expected-error{{use of undeclared 'operator float'}}
}
+
+ static operator short(); // expected-error{{conversion function must be a non-static member function}}
};
operator int(); // expected-error{{conversion function must be a non-static member function}}
diff --git a/test/SemaCXX/conversion-incomplete-type.cpp b/test/SemaCXX/conversion-incomplete-type.cpp
new file mode 100644
index 000000000000..ebedd04047b9
--- /dev/null
+++ b/test/SemaCXX/conversion-incomplete-type.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct string {};
+
+class StringPiece; // expected-note {{forward declaration of 'StringPiece'}} \
+ // expected-note {{forward declaration of 'StringPiece'}}
+
+struct Test {
+ void expectStringPiece(const StringPiece& blah) {}; // expected-note {{passing argument to parameter 'blah' here}}
+
+ void test(const string& s) {
+ expectStringPiece(s); // expected-error {{no viable conversion from 'const string' to incomplete type 'const StringPiece'}}
+ }
+};
+
+struct TestStatic {
+ static void expectStringPiece(const StringPiece& blah) {}; // expected-note {{passing argument to parameter 'blah' here}}
+
+ static void test(const string& s) {
+ expectStringPiece(s); // expected-error {{no viable conversion from 'const string' to incomplete type 'const StringPiece'}}
+ }
+};
+
diff --git a/test/SemaCXX/crashes.cpp b/test/SemaCXX/crashes.cpp
index f5682bd74d92..0b15bb0386c2 100644
--- a/test/SemaCXX/crashes.cpp
+++ b/test/SemaCXX/crashes.cpp
@@ -171,3 +171,50 @@ namespace test3 {
int& x = dimenX.*sides;
}
}
+
+namespace pr16964 {
+ template<typename> struct bs {
+ bs();
+ static int* member();
+ member(); // expected-error{{C++ requires a type specifier for all declarations}}
+ static member(); // expected-error{{C++ requires a type specifier for all declarations}}
+ static int* member(int);
+ };
+
+ template<typename T> bs<T>::bs() { member; }
+
+ bs<int> test() {
+ return bs<int>();
+ }
+}
+
+namespace pr12791 {
+ template<class _Alloc> class allocator {};
+ template<class _CharT> struct char_traits;
+ struct input_iterator_tag {};
+ struct forward_iterator_tag : public input_iterator_tag {};
+
+ template<typename _CharT, typename _Traits, typename _Alloc> struct basic_string {
+ struct _Alloc_hider : _Alloc {};
+ mutable _Alloc_hider _M_dataplus;
+ template<class _InputIterator> basic_string(_InputIterator __beg, _InputIterator __end, const _Alloc& __a = _Alloc());
+ template<class _InIterator> static _CharT* _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, input_iterator_tag);
+ template<class _FwdIterator> static _CharT* _S_construct(_FwdIterator __beg, _FwdIterator __end, const _Alloc& __a, forward_iterator_tag);
+ static _CharT* _S_construct(size_type __req, _CharT __c, const _Alloc& __a); // expected-error{{unknown type name 'size_type'}}
+ };
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ template<typename _InputIterator>
+ basic_string<_CharT, _Traits, _Alloc>:: basic_string(_InputIterator __beg, _InputIterator __end, const _Alloc& __a)
+ : _M_dataplus(_S_construct(__beg, __end, __a), __a) {}
+
+ template<typename _CharT, typename _Traits = char_traits<_CharT>, typename _Alloc = allocator<_CharT> > struct basic_stringbuf {
+ typedef _CharT char_type;
+ typedef basic_string<char_type, _Traits, _Alloc> __string_type;
+ typedef typename __string_type::size_type __size_type;
+ __string_type str() const {__string_type((char_type*)0,(char_type*)0);}
+ };
+
+ template class basic_stringbuf<char>;
+}
+
diff --git a/test/SemaCXX/cxx0x-class.cpp b/test/SemaCXX/cxx0x-class.cpp
index 074591e7063c..2b1338f97fd7 100644
--- a/test/SemaCXX/cxx0x-class.cpp
+++ b/test/SemaCXX/cxx0x-class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-error=static-float-init %s
+// RUN: %clang_cc1 -Wno-uninitialized -fsyntax-only -verify -std=c++11 -Wno-error=static-float-init %s
int vs = 0;
diff --git a/test/SemaCXX/cxx0x-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp
index 123008aadd81..ffbd20fda373 100644
--- a/test/SemaCXX/cxx0x-compat.cpp
+++ b/test/SemaCXX/cxx0x-compat.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-compat -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++11-compat -verify %s
+
+#if __cplusplus < 201103L
namespace N {
template<typename T> void f(T) {} // expected-note 2{{here}}
@@ -37,3 +40,9 @@ void h(size_t foo, size_t bar) {
#define _x + 1
char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal suffix}}
+
+#else
+
+auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++1y}}
+
+#endif
diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
index f53ac6dff930..0e9a97d5bb07 100644
--- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp
+++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
@@ -4,7 +4,6 @@ struct one { char c[1]; };
struct two { char c[2]; };
namespace aggregate {
- // Direct list initialization does NOT allow braces to be elided!
struct S {
int ar[2];
struct T {
@@ -20,25 +19,25 @@ namespace aggregate {
};
void bracing() {
- S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 }; // no-error
- S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
- S s3{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
- S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
- S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 };
+ S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } };
+ S s3{ 1, 2, 3, 4, 5, 6 };
+ S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } };
+ S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} };
}
void bracing_new() {
- new S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
- new S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
- new S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
- new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ new S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } };
+ new S{ 1, 2, 3, 4, 5, 6 };
+ new S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } };
+ new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} };
}
void bracing_construct() {
- (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
- (void) S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
- (void) S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
- (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } };
+ (void) S{ 1, 2, 3, 4, 5, 6 };
+ (void) S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } };
+ (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} };
}
struct String {
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
index 283c32ac2efc..9096c8a1c2d5 100644
--- a/test/SemaCXX/cxx0x-initializer-references.cpp
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -36,10 +36,10 @@ namespace reference {
};
void call() {
- void f(const int&);
+ one f(const int&);
f({1});
- void g(int&); // expected-note {{passing argument}}
+ one g(int&); // expected-note {{passing argument}}
g({1}); // expected-error {{cannot bind to an initializer list temporary}}
int i = 0;
g({i});
@@ -97,3 +97,24 @@ namespace b7891773 {
int g(const ptr &);
int k = g({ f<int> });
}
+
+namespace inner_init {
+ struct A { int n; };
+ struct B { A &&r; };
+ B b1 { 0 }; // expected-error {{reference to type 'inner_init::A' could not bind to an rvalue of type 'int'}}
+ B b2 { { 0 } };
+ B b3 { { { 0 } } }; // expected-warning {{braces around scalar init}}
+
+ struct C { C(int); };
+ struct D { C &&r; };
+ D d1 { 0 }; // ok, 0 implicitly converts to C
+ D d2 { { 0 } }; // ok, { 0 } calls C(0)
+ D d3 { { { 0 } } }; // ok, { { 0 } } calls C({ 0 })
+ D d4 { { { { 0 } } } }; // expected-warning {{braces around scalar init}}
+
+ struct E { explicit E(int); }; // expected-note 2{{here}}
+ struct F { E &&r; };
+ F f1 { 0 }; // expected-error {{could not bind to an rvalue of type 'int'}}
+ F f2 { { 0 } }; // expected-error {{chosen constructor is explicit}}
+ F f3 { { { 0 } } }; // expected-error {{chosen constructor is explicit}}
+}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 88571d671b07..9d89cce67b38 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -144,7 +144,7 @@ namespace PR12119 {
template<typename T> void g(std::initializer_list<std::initializer_list<T>>);
void foo() {
- f({0, {1}});
+ f({0, {1}}); // expected-warning{{braces around scalar initializer}}
g({{0, 1}, {2, 3}});
std::initializer_list<int> il = {1, 2};
g({il, {2, 3}});
@@ -208,3 +208,25 @@ namespace init_list_deduction_failure {
void h() { g({f}); }
// expected-error@-1 {{no matching function for call to 'g'}}
}
+
+namespace deleted_copy {
+ struct X {
+ X(int i) {}
+ X(const X& x) = delete; // expected-note {{here}}
+ void operator=(const X& x) = delete;
+ };
+
+ std::initializer_list<X> x{1}; // expected-error {{invokes deleted constructor}}
+}
+
+namespace RefVersusInitList {
+ struct S {};
+ void f(const S &) = delete;
+ void f(std::initializer_list<S>);
+ void g(S s) { f({S()}); }
+}
+
+namespace PR18013 {
+ int f();
+ std::initializer_list<long (*)()> x = {f}; // expected-error {{cannot initialize an array element of type 'long (*const)()' with an lvalue of type 'int ()': different return type ('long' vs 'int')}}
+}
diff --git a/test/SemaCXX/cxx0x-nontrivial-union.cpp b/test/SemaCXX/cxx0x-nontrivial-union.cpp
index 0e4add84955e..db296bd57d71 100644
--- a/test/SemaCXX/cxx0x-nontrivial-union.cpp
+++ b/test/SemaCXX/cxx0x-nontrivial-union.cpp
@@ -122,3 +122,25 @@ namespace optional {
o2 = optional<non_trivial>();
}
}
+
+namespace pr16061 {
+ struct X { X(); };
+
+ template<typename T> struct Test1 {
+ union {
+ struct {
+ X x;
+ };
+ };
+ };
+
+ template<typename T> struct Test2 {
+ union {
+ struct { // expected-note {{default constructor of 'Test2<pr16061::X>' is implicitly deleted because variant field '' has a non-trivial default constructor}}
+ T x;
+ };
+ };
+ };
+
+ Test2<X> t2x; // expected-error {{call to implicitly-deleted default constructor of 'Test2<pr16061::X>'}}
+}
diff --git a/test/SemaCXX/cxx11-attr-print.cpp b/test/SemaCXX/cxx11-attr-print.cpp
index 19de5b5a640b..01325d3c8bf3 100644
--- a/test/SemaCXX/cxx11-attr-print.cpp
+++ b/test/SemaCXX/cxx11-attr-print.cpp
@@ -52,7 +52,7 @@ inline void f6() __attribute__((gnu_inline));
inline void f7 [[gnu::gnu_inline]] ();
// arguments printing
-// CHECK: __attribute__((format("printf", 2, 3)));
+// CHECK: __attribute__((format(printf, 2, 3)));
void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
// CHECK: int m __attribute__((aligned(4
@@ -75,3 +75,6 @@ template <typename T> struct S {
// CHECK: static int f() __attribute__((pure))
// CHECK: static int g() {{\[}}[gnu::pure]]
template struct S<int>;
+
+// CHECK: using Small2 {{\[}}[gnu::mode(byte)]] = int;
+using Small2 [[gnu::mode(byte)]] = int;
diff --git a/test/SemaCXX/cxx11-crashes.cpp b/test/SemaCXX/cxx11-crashes.cpp
index a4d4829f3fc2..bd51af1da2fa 100644
--- a/test/SemaCXX/cxx11-crashes.cpp
+++ b/test/SemaCXX/cxx11-crashes.cpp
@@ -70,9 +70,7 @@ namespace b6981007 {
for (auto x : s) {
// We used to attempt to evaluate the initializer of this variable,
// and crash because it has an undeduced type.
- // FIXME: We should set the loop variable to be invalid if we can't build
- // the loop, to suppress this follow-on error.
- const int &n(x); // expected-error {{could not bind to an lvalue of type 'auto'}}
+ const int &n(x);
}
}
}
diff --git a/test/SemaCXX/cxx11-gnu-attrs.cpp b/test/SemaCXX/cxx11-gnu-attrs.cpp
index def83a94ea2b..22d61a1978fb 100644
--- a/test/SemaCXX/cxx11-gnu-attrs.cpp
+++ b/test/SemaCXX/cxx11-gnu-attrs.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -cc1 -triple x86_64-unknown-unknown -std=c++11 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -verify %s
// Error cases.
@@ -11,8 +11,9 @@ int *[[gnu::unused]] attr_on_ptr;
// Valid cases.
+void aliasb [[gnu::alias("_Z6alias1v")]] ();
void alias1() {}
-void alias2 [[gnu::alias("_Z6alias1v")]] ();
+void aliasa [[gnu::alias("_Z6alias1v")]] ();
[[gnu::aligned(8)]] int aligned;
void aligned_fn [[gnu::aligned(32)]] ();
diff --git a/test/SemaCXX/cxx11-thread-local-print.cpp b/test/SemaCXX/cxx11-thread-local-print.cpp
index 9d9a82b7e6a4..1adafbda4905 100644
--- a/test/SemaCXX/cxx11-thread-local-print.cpp
+++ b/test/SemaCXX/cxx11-thread-local-print.cpp
@@ -7,3 +7,9 @@ __thread int gnu_tl;
_Thread_local int c11_tl;
thread_local int cxx11_tl;
+// CHECK: void foo() {
+// CHECK: thread_local int cxx11_tl;
+// CHECK: }
+void foo() {
+ thread_local int cxx11_tl;
+}
diff --git a/test/SemaCXX/cxx1y-array-runtime-bound.cpp b/test/SemaCXX/cxx1y-array-runtime-bound.cpp
deleted file mode 100644
index 1643adbe0b09..000000000000
--- a/test/SemaCXX/cxx1y-array-runtime-bound.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-// RUN: %clang_cc1 -std=c++1y %s -verify -triple=x86_64-linux-gnu -pedantic-errors
-
-// FIXME: many diagnostics here say 'variably modified type'.
-// catch this case and say 'array of runtime bound' instead.
-
-namespace std { struct type_info; }
-
-struct S {
- int arr[__SIZE_MAX__ / 32];
-};
-S s[32]; // expected-error {{array is too large}}
-
-int n;
-int a[n]; // expected-error {{not allowed at file scope}}
-
-struct T {
- int a[n]; // expected-error {{fields must have a constant size}}
- static int b[n]; // expected-error {{not allowed at file scope}}
-};
-
-int g(int n, int a[n]);
-
-template<typename T> struct X {};
-template<int N, int[N]> struct Y {};
-template<int[n]> struct Z {}; // expected-error {{of variably modified type}}
-
-int f(int n) {
- int arb[n]; // expected-note 3{{here}}
- [arb] {} (); // expected-error {{cannot be captured}}
-
- // FIXME: an array of runtime bound can be captured by reference.
- [&arb] { // expected-error {{cannot be captured}}
- // Capturing the array implicitly captures the bound, if we need it
- // in a range-based for loop.
- for (auto &n : arb) { } // expected-error {{cannot be captured}}
- } ();
-
- X<int[n]> x; // expected-error {{variably modified type}}
-
- int arb_neg[-1]; // expected-error {{negative size}}
- int arb_of_array[n][2];
- int arr[3] = { 1, 2, 3, 4 }; // expected-error {{excess elements}}
- char foo[4] = "fool"; // expected-error {{initializer-string for char array is too long}}
-
- static int not_auto1[n]; // expected-error {{can not have 'static'}}
- extern int not_auto2[n]; // expected-error {{can not have 'extern'}}
- // FIXME: say 'thread_local' not 'static'.
- thread_local int not_auto1[n]; // expected-error {{can not have 'static'}}
-
- // FIXME: these should all be invalid.
- auto &&ti1 = typeid(arb);
- auto &&ti2 = typeid(int[n]);
- auto &&so1 = sizeof(arb);
- auto &&so2 = sizeof(int[n]);
- auto *p = &arb;
- decltype(arb) arb2;
- int (*arbp)[n] = 0;
- const int (&arbr)[n] = arbr; // expected-warning {{not yet bound}}
- typedef int arbty[n];
- int array_of_arb[2][n];
-
- struct Dyn { Dyn() {} Dyn(int) {} ~Dyn() {} };
-
- // FIXME: these should be valid.
- int arb_dynamic[n] = { 1, 2, 3, 4 }; // expected-error {{may not be initialized}}
- Dyn dyn[n]; // expected-error {{non-POD}}
- Dyn dyn_init[n] = { 1, 2, 3, 4 }; // expected-error {{non-POD}}
-}
diff --git a/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp b/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
new file mode 100644
index 000000000000..58bbbb2a0442
--- /dev/null
+++ b/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
@@ -0,0 +1,177 @@
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y
+
+// Explicit member declarations behave as in C++11.
+
+namespace n3323_example {
+
+ template <class T> class zero_init {
+ public:
+ zero_init() : val(static_cast<T>(0)) {}
+ zero_init(T val) : val(val) {}
+
+ operator T &() { return val; } //@13
+ operator T() const { return val; } //@14
+
+ private:
+ T val;
+ };
+
+ void Delete() {
+ zero_init<int *> p;
+ p = new int(7);
+ delete p; //@23
+ delete (p + 0);
+ delete + p;
+ }
+
+ void Switch() {
+ zero_init<int> i;
+ i = 7;
+ switch (i) {} // @31
+ switch (i + 0) {}
+ switch (+i) {}
+ }
+}
+
+#ifdef CXX1Y
+#else
+//expected-error@23 {{ambiguous conversion of delete expression of type 'zero_init<int *>' to a pointer}}
+//expected-note@13 {{conversion to pointer type 'int *'}}
+//expected-note@14 {{conversion to pointer type 'int *'}}
+//expected-error@31 {{multiple conversions from switch condition type 'zero_init<int>' to an integral or enumeration type}}
+//expected-note@13 {{conversion to integral type 'int'}}
+//expected-note@14 {{conversion to integral type 'int'}}
+#endif
+
+namespace extended_examples {
+
+ struct A0 {
+ operator int(); // matching and viable
+ };
+
+ struct A1 {
+ operator int() &&; // matching and not viable
+ };
+
+ struct A2 {
+ operator float(); // not matching
+ };
+
+ struct A3 {
+ template<typename T> operator T(); // not matching (ambiguous anyway)
+ };
+
+ struct A4 {
+ template<typename T> operator int(); // not matching (ambiguous anyway)
+ };
+
+ struct B1 {
+ operator int() &&; // @70
+ operator int(); // @71 -- duplicate declaration with different qualifier is not allowed
+ };
+
+ struct B2 {
+ operator int() &&; // matching but not viable
+ operator float(); // not matching
+ };
+
+ void foo(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, B2 b2) {
+ switch (a0) {}
+ switch (a1) {} // @81 -- fails for different reasons
+ switch (a2) {} // @82
+ switch (a3) {} // @83
+ switch (a4) {} // @84
+ switch (b2) {} // @85 -- fails for different reasons
+ }
+}
+
+//expected-error@71 {{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&&'}}
+//expected-note@70 {{previous declaration is here}}
+//expected-error@82 {{statement requires expression of integer type ('extended_examples::A2' invalid)}}
+//expected-error@83 {{statement requires expression of integer type ('extended_examples::A3' invalid)}}
+//expected-error@84 {{statement requires expression of integer type ('extended_examples::A4' invalid)}}
+
+#ifdef CXX1Y
+//expected-error@81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}}
+//expected-error@85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}}
+#else
+//expected-error@81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}}
+//expected-error@85 {{cannot initialize object parameter of type 'extended_examples::B2' with an expression of type 'extended_examples::B2'}}
+#endif
+
+namespace extended_examples_cxx1y {
+
+ struct A1 { // leads to viable match in C++1y, and no viable match in C++11
+ operator int() &&; // matching but not viable
+ template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.100
+ };
+
+ struct A2 { // leads to ambiguity in C++1y, and no viable match in C++11
+ operator int() &&; // matching but not viable
+ template <typename T> operator int(); // In C++1y: matching but ambiguous (disambiguated by L.105).
+ };
+
+ struct B1 { // leads to one viable match in both cases
+ operator int(); // matching and viable
+ template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.110
+ };
+
+ struct B2 { // leads to one viable match in both cases
+ operator int(); // matching and viable
+ template <typename T> operator int(); // In C++1y: matching but ambiguous, since disambiguated by L.115
+ };
+
+ struct C { // leads to no match in both cases
+ operator float(); // not matching
+ template <typename T> operator T(); // In C++1y: not matching, nor viable.
+ };
+
+ struct D { // leads to viable match in C++1y, and no viable match in C++11
+ operator int() &&; // matching but not viable
+ operator float(); // not matching
+ template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.125
+ };
+
+
+ void foo(A1 a1, A2 a2, B1 b1, B2 b2, C c, D d) {
+ switch (a1) {} // @138 -- should presumably call templated conversion operator to convert to int.
+ switch (a2) {} // @139
+ switch (b1) {}
+ switch (b2) {}
+ switch (c) {} // @142
+ switch (d) {} // @143
+ }
+}
+
+//expected-error@142 {{statement requires expression of integer type ('extended_examples_cxx1y::C' invalid)}}
+
+#ifdef CXX1Y
+//expected-error@139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}}
+#else
+//expected-error@138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}}
+//expected-error@139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}}
+//expected-error@143 {{cannot initialize object parameter of type 'extended_examples_cxx1y::D' with an expression of type 'extended_examples_cxx1y::D'}}
+#endif
+
+namespace extended_examples_array_bounds {
+
+ typedef decltype(sizeof(int)) size_t;
+
+ struct Foo {
+ operator size_t(); // @162
+ operator unsigned short(); // @163
+ };
+
+ void bar() {
+ Foo x;
+ int *p = new int[x]; // @168
+ }
+}
+
+#ifdef CXX1Y
+#else
+//expected-error@168 {{ambiguous conversion of array size expression of type 'extended_examples_array_bounds::Foo' to an integral or enumeration type}}
+//expected-note@162 {{conversion to integral type 'size_t'}}
+//expected-note@163 {{conversion to integral type 'unsigned short' declared here}}
+#endif
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index f0146f88d686..d3308b3fd50b 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
auto f(); // expected-note {{previous}}
int f(); // expected-error {{differ only in their return type}}
@@ -112,7 +113,8 @@ namespace Templates {
int e = fwd_decl<int>(); // expected-error {{cannot be used before it is defined}}
template<typename T> auto fwd_decl() { return 0; }
int f = fwd_decl<int>();
- template<typename T> auto fwd_decl();
+ template <typename T>
+ auto fwd_decl(); // expected-note {{candidate template ignored: could not match 'auto ()' against 'int ()'}}
int g = fwd_decl<char>();
auto (*p)() = f1; // expected-error {{incompatible initializer}}
@@ -126,7 +128,8 @@ namespace Templates {
extern template int fwd_decl<char>(); // expected-error {{does not refer to a function template}}
int k2 = fwd_decl<char>();
- template<typename T> auto instantiate() { T::error; } // expected-error {{has no members}}
+ template <typename T> auto instantiate() { T::error; } // expected-error {{has no members}} \
+ // expected-note {{candidate template ignored: could not match 'auto ()' against 'void ()'}}
extern template auto instantiate<int>(); // ok
int k = instantiate<int>(); // expected-note {{in instantiation of}}
template<> auto instantiate<char>() {} // ok
@@ -157,7 +160,7 @@ namespace Templates {
double &mem_check4 = take_fn<double>(Outer<double>::arg_multi);
namespace Deduce1 {
- template<typename T> auto f() { return 0; } // expected-note {{candidate}}
+ template <typename T> auto f() { return 0; } // expected-note {{couldn't infer template argument 'T'}}
template<typename T> void g(T(*)()); // expected-note 2{{candidate}}
void h() {
auto p = f<int>;
@@ -170,7 +173,7 @@ namespace Templates {
}
namespace Deduce2 {
- template<typename T> auto f(int) { return 0; } // expected-note {{candidate}}
+ template <typename T> auto f(int) { return 0; } // expected-note {{couldn't infer template argument 'T'}}
template<typename T> void g(T(*)(int)); // expected-note 2{{candidate}}
void h() {
auto p = f<int>;
@@ -253,7 +256,7 @@ namespace DefaultedMethods {
auto operator=(const A&) = default; // expected-error {{must return 'DefaultedMethods::A &'}}
A &operator=(A&&); // expected-note {{previous}}
};
- auto A::operator=(A&&) = default; // expected-error {{differs from the declaration in the return type}}
+ auto A::operator=(A&&) = default; // expected-error {{return type of out-of-line definition of 'DefaultedMethods::A::operator=' differs from that in the declaration}}
}
namespace Constexpr {
@@ -295,7 +298,12 @@ namespace NoReturn {
auto f() {}
void (*p)() = &f;
+ auto f(); // ok
+
auto *g() {} // expected-error {{cannot deduce return type 'auto *' for function with no return statements}}
+
+ auto h() = delete; // expected-note {{explicitly deleted}}
+ auto x = h(); // expected-error {{call to deleted}}
}
namespace UseBeforeComplete {
@@ -317,7 +325,8 @@ namespace Redecl {
int f(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
decltype(auto) f(); // expected-error {{cannot be overloaded}}
- template<typename T> auto g(T t) { return t; } // expected-note {{candidate}}
+ template <typename T> auto g(T t) { return t; } // expected-note {{candidate}} \
+ // expected-note {{candidate function [with T = int]}}
template auto g(int);
template char g(char); // expected-error {{does not refer to a function}}
template<> auto g(double);
@@ -334,5 +343,136 @@ namespace ExplicitInstantiationDecl {
extern template auto f(int);
int (*p)(int) = f;
}
+namespace MemberTemplatesWithDeduction {
+ struct M {
+ template<class T> auto foo(T t) { return t; }
+ template<class T> auto operator()(T t) const { return t; }
+ template<class T> static __attribute__((unused)) int static_foo(T) {
+ return 5;
+ }
+ template<class T> operator T() { return T{}; }
+ operator auto() { return &static_foo<int>; }
+ };
+ struct N : M {
+ using M::foo;
+ using M::operator();
+ using M::static_foo;
+ using M::operator auto;
+ };
+
+ template <class T> int test() {
+ int i = T{}.foo(3);
+ T m = T{}.foo(M{});
+ int j = T{}(3);
+ M m2 = M{}(M{});
+ int k = T{}.static_foo(4);
+ int l = T::static_foo(5);
+ int l2 = T{};
+ struct X { };
+ X x = T{};
+ return 0;
+ }
+ int Minst = test<M>();
+ int Ninst = test<N>();
+
+}
+}
+
+namespace CurrentInstantiation {
+ // PR16875
+ template<typename T> struct S {
+ auto f() { return T(); }
+ int g() { return f(); }
+ auto h(bool b) {
+ if (b)
+ return T();
+ return h(true);
+ }
+ };
+ int k1 = S<int>().g();
+ int k2 = S<int>().h(false);
+
+ template<typename T> struct U {
+ #ifndef DELAYED_TEMPLATE_PARSING
+ auto f(); // expected-note {{here}}
+ int g() { return f(); } // expected-error {{cannot be used before it is defined}}
+ #else
+ auto f();
+ int g() { return f(); }
+ #endif
+ };
+ #ifndef DELAYED_TEMPLATE_PARSING
+ template int U<int>::g(); // expected-note {{in instantiation of}}
+ #else
+ template int U<int>::g();
+ #endif
+ template<typename T> auto U<T>::f() { return T(); }
+ template int U<short>::g(); // ok
+}
+
+namespace WithDefaultArgs {
+ template<typename U> struct A {
+ template<typename T = U> friend auto f(A) { return []{}; }
+ };
+ template<typename T> void f();
+ using T = decltype(f(A<int>()));
+ using T = decltype(f<int>(A<int>()));
+}
+
+namespace MultilevelDeduction {
+
+auto F() -> auto* { return (int*)0; }
+
+auto (*G())() -> int* { return F; }
+
+auto run = G();
+
+namespace Templated {
+template<class T>
+auto F(T t) -> auto* { return (T*)0; }
+
+template<class T>
+auto (*G(T t))(T) -> T* { return &F<T>; }
+
+
+template<class T>
+auto (*G2(T t))(T) -> auto* { return &F<T>; }
+
+auto run_int = G(1);
+auto run_char = G2('a');
+
+}
+}
+
+namespace rnk {
+extern "C" int puts(const char *s);
+template <typename T>
+auto foo(T x) -> decltype(x) {
+#ifdef DELAYED_TEMPLATE_PARSING
+ ::rnk::bar();
+#endif
+ return x;
+}
+void bar() { puts("bar"); }
+int main() { return foo(0); }
}
+
+namespace OverloadedOperators {
+ template<typename T> struct A {
+ auto operator()() { return T{}; }
+ auto operator[](int) { return T{}; }
+ auto operator+(int) { return T{}; }
+ auto operator+() { return T{}; }
+ friend auto operator-(A) { return T{}; }
+ friend auto operator-(A, A) { return T{}; }
+ };
+ void f(A<int> a) {
+ int b = a();
+ int c = a[0];
+ int d = a + 0;
+ int e = +a;
+ int f = -a;
+ int g = a - a;
+ }
+}
diff --git a/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
new file mode 100644
index 000000000000..8bd4f4242c1d
--- /dev/null
+++ b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -0,0 +1,1363 @@
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+constexpr int ODRUSE_SZ = sizeof(char);
+
+template<class T, int N>
+void f(T, const int (&)[N]) { }
+
+template<class T>
+void f(const T&, const int (&)[ODRUSE_SZ]) { }
+
+#define DEFINE_SELECTOR(x) \
+ int selector_ ## x[sizeof(x) == ODRUSE_SZ ? ODRUSE_SZ : ODRUSE_SZ + 5]
+
+#define F_CALL(x, a) f(x, selector_ ## a)
+
+// This is a risky assumption, because if an empty class gets captured by value
+// the lambda's size will still be '1'
+#define ASSERT_NO_CAPTURES(L) static_assert(sizeof(L) == 1, "size of closure with no captures must be 1")
+#define ASSERT_CLOSURE_SIZE_EXACT(L, N) static_assert(sizeof(L) == (N), "size of closure must be " #N)
+#define ASSERT_CLOSURE_SIZE(L, N) static_assert(sizeof(L) >= (N), "size of closure must be >=" #N)
+
+
+namespace sample {
+ struct X {
+ int i;
+ X(int i) : i(i) { }
+ };
+}
+
+namespace test_transformations_in_templates {
+template<class T> void foo(T t) {
+ auto L = [](auto a) { return a; };
+}
+template<class T> void foo2(T t) {
+ auto L = [](auto a) -> void {
+ auto M = [](char b) -> void {
+ auto N = [](auto c) -> void {
+ int selector[sizeof(c) == 1 ?
+ (sizeof(b) == 1 ? 1 : 2)
+ : 2
+ ]{};
+ };
+ N('a');
+ };
+ };
+ L(3.14);
+}
+
+void doit() {
+ foo(3);
+ foo('a');
+ foo2('A');
+}
+}
+
+namespace test_return_type_deduction {
+
+void doit() {
+
+ auto L = [](auto a, auto b) {
+ if ( a > b ) return a;
+ return b;
+ };
+ L(2, 4);
+ {
+ auto L2 = [](auto a, int i) {
+ return a + i;
+ };
+ L2(3.14, 2);
+ }
+ {
+ int a; //expected-note{{declared here}}
+ auto B = []() { return ^{ return a; }; }; //expected-error{{cannot be implicitly capture}}\
+ //expected-note{{begins here}}
+ //[](){ return ({int b = 5; return 'c'; 'x';}); };
+
+ //auto X = ^{ return a; };
+
+ //auto Y = []() -> auto { return 3; return 'c'; };
+
+ }
+}
+}
+
+
+namespace test_no_capture{
+void doit() {
+ const int x = 10; //expected-note{{declared here}}
+ {
+ // should not capture 'x' - variable undergoes lvalue-to-rvalue
+ auto L = [=](auto a) {
+ int y = x;
+ return a + y;
+ };
+ ASSERT_NO_CAPTURES(L);
+ }
+ {
+ // should not capture 'x' - even though certain instantiations require
+ auto L = [](auto a) { //expected-note{{begins here}}
+ DEFINE_SELECTOR(a);
+ F_CALL(x, a); //expected-error{{'x' cannot be implicitly captured}}
+ };
+ ASSERT_NO_CAPTURES(L);
+ L('s'); //expected-note{{in instantiation of}}
+ }
+ {
+ // Does not capture because no default capture in inner most lambda 'b'
+ auto L = [=](auto a) {
+ return [=](int p) {
+ return [](auto b) {
+ DEFINE_SELECTOR(a);
+ F_CALL(x, a);
+ return 0;
+ };
+ };
+ };
+ ASSERT_NO_CAPTURES(L);
+ }
+} // doit
+} // namespace
+
+namespace test_capture_of_potentially_evaluated_expression {
+void doit() {
+ const int x = 5;
+ {
+ auto L = [=](auto a) {
+ DEFINE_SELECTOR(a);
+ F_CALL(x, a);
+ };
+ static_assert(sizeof(L) == 4, "Must be captured");
+ }
+ {
+ int j = 0; //expected-note{{declared}}
+ auto L = [](auto a) { //expected-note{{begins here}}
+ return j + 1; //expected-error{{cannot be implicitly captured}}
+ };
+ }
+ {
+ const int x = 10;
+ auto L = [](auto a) {
+ //const int y = 20;
+ return [](int p) {
+ return [](auto b) {
+ DEFINE_SELECTOR(a);
+ F_CALL(x, a);
+ return 0;
+ };
+ };
+ };
+ auto M = L(3);
+ auto N = M(5);
+
+ }
+
+ { // if the nested capture does not implicitly or explicitly allow any captures
+ // nothing should capture - and instantiations will create errors if needed.
+ const int x = 0;
+ auto L = [=](auto a) { // <-- #A
+ const int y = 0;
+ return [](auto b) { // <-- #B
+ int c[sizeof(b)];
+ f(x, c);
+ f(y, c);
+ int i = x;
+ };
+ };
+ ASSERT_NO_CAPTURES(L);
+ auto M_int = L(2);
+ ASSERT_NO_CAPTURES(M_int);
+ }
+ { // Permutations of this example must be thoroughly tested!
+ const int x = 0;
+ sample::X cx{5};
+ auto L = [=](auto a) {
+ const int z = 3;
+ return [&,a](auto b) {
+ const int y = 5;
+ return [=](auto c) {
+ int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
+ f(x, d);
+ f(y, d);
+ f(z, d);
+ decltype(a) A = a;
+ decltype(b) B = b;
+ const int &i = cx.i;
+ };
+ };
+ };
+ auto M = L(3)(3.5);
+ M(3.14);
+ }
+}
+namespace Test_no_capture_of_clearly_no_odr_use {
+auto foo() {
+ const int x = 10;
+ auto L = [=](auto a) {
+ return [=](auto b) {
+ return [=](auto c) {
+ int A = x;
+ return A;
+ };
+ };
+ };
+ auto M = L(1);
+ auto N = M(2.14);
+ ASSERT_NO_CAPTURES(L);
+ ASSERT_NO_CAPTURES(N);
+
+ return 0;
+}
+}
+
+namespace Test_capture_of_odr_use_var {
+auto foo() {
+ const int x = 10;
+ auto L = [=](auto a) {
+ return [=](auto b) {
+ return [=](auto c) {
+ int A = x;
+ const int &i = x;
+ decltype(a) A2 = a;
+ return A;
+ };
+ };
+ };
+ auto M_int = L(1);
+ auto N_int_int = M_int(2);
+ ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
+ // M_int captures both a & x
+ ASSERT_CLOSURE_SIZE_EXACT(M_int, sizeof(x) + sizeof(int));
+ // N_int_int captures both a & x
+ ASSERT_CLOSURE_SIZE_EXACT(N_int_int, sizeof(x) + sizeof(int));
+ auto M_double = L(3.14);
+ ASSERT_CLOSURE_SIZE(M_double, sizeof(x) + sizeof(double));
+
+ return 0;
+}
+auto run = foo();
+}
+
+}
+namespace more_nested_captures_1 {
+template<class T> struct Y {
+ static void f(int, double, ...) { }
+ template<class R>
+ static void f(const int&, R, ...) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{declared here}}
+ auto L = [](auto a) {
+ return [=](auto b) {
+ return [=](auto c) {
+ f(x, c, b, a); //expected-error{{reference to local variable 'x'}}
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3.14);
+ N(5); //expected-note{{in instantiation of}}
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_1_1 {
+template<class T> struct Y {
+ static void f(int, double, ...) { }
+ template<class R>
+ static void f(const int&, R, ...) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{declared here}}
+ auto L = [](auto a) {
+ return [=](char b) {
+ return [=](auto c) {
+ f(x, c, b, a); //expected-error{{reference to local variable 'x'}}
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3.14);
+ N(5); //expected-note{{in instantiation of}}
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+namespace more_nested_captures_1_2 {
+template<class T> struct Y {
+ static void f(int, double, ...) { }
+ template<class R>
+ static void f(const int&, R, ...) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10;
+ auto L = [=](auto a) {
+ return [=](char b) {
+ return [=](auto c) {
+ f(x, c, b, a);
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3.14);
+ N(5);
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0);
+}
+
+namespace more_nested_captures_1_3 {
+template<class T> struct Y {
+ static void f(int, double, ...) { }
+ template<class R>
+ static void f(const int&, R, ...) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{declared here}}
+ auto L = [=](auto a) {
+ return [](auto b) {
+ const int y = 0;
+ return [=](auto c) {
+ f(x, c, b); //expected-error{{reference to local variable 'x'}}
+ f(y, b, c);
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3.14);
+ N(5); //expected-note{{in instantiation of}}
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_1_4 {
+template<class T> struct Y {
+ static void f(int, double, ...) { }
+ template<class R>
+ static void f(const int&, R, ...) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{declared here}}
+ auto L = [=](auto a) {
+ T t2{t};
+ return [](auto b) {
+ const int y = 0; //expected-note{{declared here}}
+ return [](auto c) { //expected-note 2{{lambda expression begins here}}
+ f(x, c); //expected-error{{variable 'x'}}
+ f(y, c); //expected-error{{variable 'y'}}
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N_char = M('b');
+ N_char(3.14);
+ auto N_double = M(3.14);
+ N_double(3.14);
+ N_char(3); //expected-note{{in instantiation of}}
+ }
+};
+Y<int> yi;
+int run = (yi.foo('a'), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_2 {
+template<class T> struct Y {
+ static void f(int, double) { }
+ template<class R>
+ static void f(const int&, R) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10;
+ auto L = [=](auto a) {
+ return [=](auto b) {
+ return [=](auto c) {
+ f(x, c);
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3);
+ N(3.14);
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0);
+
+}
+
+namespace more_nested_captures_3 {
+template<class T> struct Y {
+ static void f(int, double) { }
+ template<class R>
+ static void f(const int&, R) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{declared here}}
+ auto L = [](auto a) {
+ return [=](auto b) {
+ return [=](auto c) {
+ f(x, c); //expected-error{{reference to local variable 'x'}}
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3); //expected-note{{in instantiation of}}
+ N(3.14);
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+
+}
+
+namespace more_nested_captures_4 {
+template<class T> struct Y {
+ static void f(int, double) { }
+ template<class R>
+ static void f(const int&, R) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10; //expected-note{{'x' declared here}}
+ auto L = [](auto a) {
+ return [=](char b) {
+ return [=](auto c) {
+ f(x, c); //expected-error{{reference to local variable 'x'}}
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3); //expected-note{{in instantiation of}}
+ N(3.14);
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+
+}
+
+namespace more_nested_captures_5 {
+template<class T> struct Y {
+ static void f(int, double) { }
+ template<class R>
+ static void f(const int&, R) { }
+ template<class R>
+ void foo(R t) {
+ const int x = 10;
+ auto L = [=](auto a) {
+ return [=](char b) {
+ return [=](auto c) {
+ f(x, c);
+ return 0;
+ };
+ };
+ };
+ auto M = L(t);
+ auto N = M('b');
+ N(3);
+ N(3.14);
+ }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0);
+
+}
+
+namespace lambdas_in_NSDMIs {
+template<class T>
+ struct L {
+ T t{};
+ T t2 = ([](auto a) { return [](auto b) { return b; };})(t)(t);
+ T t3 = ([](auto a) { return a; })(t);
+ };
+ L<int> l;
+ int run = l.t2;
+}
+namespace test_nested_decltypes_in_trailing_return_types {
+int foo() {
+ auto L = [](auto a) {
+ return [](auto b, decltype(a) b2) -> decltype(a) {
+ return decltype(a){};
+ };
+ };
+ auto M = L(3.14);
+ M('a', 6.26);
+ return 0;
+}
+}
+
+namespace more_this_capture_1 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+ void foo() {
+ {
+ auto L = [=](auto a) {
+ f(a);
+ };
+ L(3);
+ L(3.13);
+ }
+ {
+ auto L = [](auto a) {
+ f(a); //expected-error{{this}}
+ };
+ L(3.13);
+ L(2); //expected-note{{in instantiation}}
+ }
+ }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](int i) {
+ return [=](auto b) {
+ f(b);
+ int x = i;
+ };
+ };
+ };
+ auto M = L(0.0);
+ auto N = M(3);
+ N(5.32); // OK
+ return 0;
+ }
+};
+int run = X{}.g();
+}
+namespace more_this_capture_1_1 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](int i) {
+ return [=](auto b) {
+ f(decltype(a){}); //expected-error{{this}}
+ int x = i;
+ };
+ };
+ };
+ auto M = L(0.0);
+ auto N = M(3);
+ N(5.32); // OK
+ L(3); // expected-note{{instantiation}}
+ return 0;
+ }
+};
+int run = X{}.g();
+}
+
+namespace more_this_capture_1_1_1 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](auto b) {
+ return [=](int i) {
+ f(b);
+ f(decltype(a){}); //expected-error{{this}}
+ };
+ };
+ };
+ auto M = L(0.0); // OK
+ auto N = M(3.3); //OK
+ auto M_int = L(0); //expected-note{{instantiation}}
+ return 0;
+ }
+};
+int run = X{}.g();
+}
+
+
+namespace more_this_capture_1_1_1_1 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](auto b) {
+ return [=](int i) {
+ f(b); //expected-error{{this}}
+ f(decltype(a){});
+ };
+ };
+ };
+ auto M_double = L(0.0); // OK
+ auto N = M_double(3); //expected-note{{instantiation}}
+
+ return 0;
+ }
+};
+int run = X{}.g();
+}
+
+namespace more_this_capture_2 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](int i) {
+ return [=](auto b) {
+ f(b); //expected-error{{'this' cannot}}
+ int x = i;
+ };
+ };
+ };
+ auto M = L(0.0);
+ auto N = M(3);
+ N(5); // NOT OK expected-note{{in instantiation of}}
+ return 0;
+ }
+};
+int run = X{}.g();
+}
+namespace diagnose_errors_early_in_generic_lambdas {
+
+int foo()
+{
+
+ { // This variable is used and must be caught early, do not need instantiation
+ const int x = 0; //expected-note{{declared}}
+ auto L = [](auto a) { //expected-note{{begins}}
+ const int &r = x; //expected-error{{variable}}
+ };
+ }
+ { // This variable is not used
+ const int x = 0;
+ auto L = [](auto a) {
+ int i = x;
+ };
+ }
+ {
+
+ const int x = 0; //expected-note{{declared}}
+ auto L = [=](auto a) { // <-- #A
+ const int y = 0;
+ return [](auto b) { //expected-note{{begins}}
+ int c[sizeof(b)];
+ f(x, c);
+ f(y, c);
+ int i = x;
+ // This use will always be an error regardless of instantatiation
+ // so diagnose this early.
+ const int &r = x; //expected-error{{variable}}
+ };
+ };
+
+ }
+ return 0;
+}
+
+int run = foo();
+}
+
+namespace generic_nongenerics_interleaved_1 {
+int foo() {
+ {
+ auto L = [](int a) {
+ int y = 10;
+ return [=](auto b) {
+ return a + y;
+ };
+ };
+ auto M = L(3);
+ M(5);
+ }
+ {
+ int x;
+ auto L = [](int a) {
+ int y = 10;
+ return [=](auto b) {
+ return a + y;
+ };
+ };
+ auto M = L(3);
+ M(5);
+ }
+ {
+ // FIXME: why are there 2 error messages here?
+ int x;
+ auto L = [](auto a) { //expected-note {{declared here}}
+ int y = 10; //expected-note {{declared here}}
+ return [](int b) { //expected-note 2{{expression begins here}}
+ return [=] (auto c) {
+ return a + y; //expected-error 2{{cannot be implicitly captured}}
+ };
+ };
+ };
+ }
+ {
+ int x;
+ auto L = [](auto a) {
+ int y = 10;
+ return [=](int b) {
+ return [=] (auto c) {
+ return a + y;
+ };
+ };
+ };
+ }
+ return 1;
+}
+
+int run = foo();
+}
+namespace dont_capture_refs_if_initialized_with_constant_expressions {
+
+auto foo(int i) {
+ // This is surprisingly not odr-used within the lambda!
+ static int j;
+ j = i;
+ int &ref_j = j;
+ return [](auto a) { return ref_j; }; // ok
+}
+
+template<class T>
+auto foo2(T t) {
+ // This is surprisingly not odr-used within the lambda!
+ static T j;
+ j = t;
+ T &ref_j = j;
+ return [](auto a) { return ref_j; }; // ok
+}
+
+int do_test() {
+ auto L = foo(3);
+ auto L_int = L(3);
+ auto L_char = L('a');
+ auto L1 = foo2(3.14);
+ auto L1_int = L1(3);
+ auto L1_char = L1('a');
+ return 0;
+}
+
+} // dont_capture_refs_if_initialized_with_constant_expressions
+
+namespace test_conversion_to_fptr {
+
+template<class T> struct X {
+
+ T (*fp)(T) = [](auto a) { return a; };
+
+};
+
+X<int> xi;
+
+template<class T>
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
+ fp(t);
+}
+
+int test() {
+{
+ auto L = [](auto a) { return a; };
+ int (*fp)(int) = L;
+ fp(5);
+ L(3);
+ char (*fc)(char) = L;
+ fc('b');
+ L('c');
+ double (*fd)(double) = L;
+ fd(3.14);
+ fd(6.26);
+ L(4.25);
+}
+{
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+ int (*fp)(int) = L;
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+{
+ int x = 5;
+ auto L = [=](auto b, char c = 'x') {
+ int i = x;
+ return [](auto a) ->decltype(a) { return a; };
+ };
+ int (*fp)(int) = L(8);
+ fp(5);
+ L(3);
+ char (*fc)(char) = L('a');
+ fc('b');
+ L('c');
+ double (*fd)(double) = L(3.14);
+ fd(3.14);
+ fd(6.26);
+
+}
+{
+ auto L = [=](auto b) {
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
+ };
+ int* (*fp)(int) = L(8);
+ fp(5);
+ L(3);
+ char* (*fc)(char) = L('a');
+ fc('b');
+ L('c');
+ double* (*fd)(double) = L(3.14);
+ fd(3.14);
+ fd(6.26);
+}
+{
+ auto L = [=](auto b) {
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
+ };
+ char* (*fp)(int) = L('8');
+ fp(5);
+ char* (*fc)(char) = L('a');
+ fc('b');
+ double* (*fi)(int) = L(3.14);
+ fi(5);
+ int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
+}
+
+{
+ auto L = [=](auto b) {
+ return [](auto a) {
+ return [=](auto c) {
+ return [](auto d) ->decltype(a + b + c + d) { return d; };
+ };
+ };
+ };
+ int (*fp)(int) = L('8')(3)(short{});
+ double (*fs)(char) = L(3.14)(short{})('4');
+}
+
+ fooT(3);
+ fooT('a');
+ fooT(3.14);
+ fooT("abcdefg");
+ return 0;
+}
+int run2 = test();
+
+}
+
+
+namespace this_capture {
+void f(char, int) { }
+template<class T>
+void f(T, const int&) { }
+
+struct X {
+ int x = 0;
+ void foo() {
+ auto L = [=](auto a) {
+ return [=](auto b) {
+ //f(a, x++);
+ x++;
+ };
+ };
+ L('a')(5);
+ L('b')(4);
+ L(3.14)('3');
+
+ }
+
+};
+
+int run = (X{}.foo(), 0);
+
+namespace this_capture_unresolvable {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto lam = [=](auto a) { f(a); }; // captures 'this'
+ lam(0); // ok.
+ lam(0.0); // ok.
+ return 0;
+ }
+ int g2() {
+ auto lam = [](auto a) { f(a); }; // expected-error{{'this'}}
+ lam(0); // expected-note{{in instantiation of}}
+ lam(0.0); // ok.
+ return 0;
+ }
+ double (*fd)(double) = [](auto a) { f(a); return a; };
+
+};
+
+int run = X{}.g();
+
+}
+
+namespace check_nsdmi_and_this_capture_of_member_functions {
+
+struct FunctorDouble {
+ template<class T> FunctorDouble(T t) { t(2.14); };
+};
+struct FunctorInt {
+ template<class T> FunctorInt(T t) { t(2); }; //expected-note{{in instantiation of}}
+};
+
+template<class T> struct YUnresolvable {
+ void f(int) { }
+ static void f(double) { }
+
+ T t = [](auto a) { f(a); return a; };
+ T t2 = [=](auto b) { f(b); return b; };
+};
+
+template<class T> struct YUnresolvable2 {
+ void f(int) { }
+ static void f(double) { }
+
+ T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}} \
+ //expected-note{{in instantiation of}}
+ T t2 = [=](auto b) { f(b); return b; };
+};
+
+
+YUnresolvable<FunctorDouble> yud;
+// This will cause an error since it call's with an int and calls a member function.
+YUnresolvable2<FunctorInt> yui;
+
+
+template<class T> struct YOnlyStatic {
+ static void f(double) { }
+
+ T t = [](auto a) { f(a); return a; };
+};
+YOnlyStatic<FunctorDouble> yos;
+template<class T> struct YOnlyNonStatic {
+ void f(int) { }
+
+ T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}}
+};
+
+
+}
+
+
+namespace check_nsdmi_and_this_capture_of_data_members {
+
+struct FunctorDouble {
+ template<class T> FunctorDouble(T t) { t(2.14); };
+};
+struct FunctorInt {
+ template<class T> FunctorInt(T t) { t(2); };
+};
+
+template<class T> struct YThisCapture {
+ const int x = 10;
+ static double d;
+ T t = [](auto a) { return x; }; //expected-error{{'this'}}
+ T t2 = [](auto b) { return d; };
+ T t3 = [this](auto a) {
+ return [=](auto b) {
+ return x;
+ };
+ };
+ T t4 = [=](auto a) {
+ return [=](auto b) {
+ return x;
+ };
+ };
+ T t5 = [](auto a) {
+ return [=](auto b) {
+ return x; //expected-error{{'this'}}
+ };
+ };
+};
+
+template<class T> double YThisCapture<T>::d = 3.14;
+
+
+}
+
+
+#ifdef DELAYED_TEMPLATE_PARSING
+template<class T> void foo_no_error(T t) {
+ auto L = []()
+ { return t; };
+}
+template<class T> void foo(T t) { //expected-note 2{{declared here}}
+ auto L = []() //expected-note 2{{begins here}}
+ { return t; }; //expected-error 2{{cannot be implicitly captured}}
+}
+template void foo(int); //expected-note{{in instantiation of}}
+
+#else
+
+template<class T> void foo(T t) { //expected-note{{declared here}}
+ auto L = []() //expected-note{{begins here}}
+ { return t; }; //expected-error{{cannot be implicitly captured}}
+}
+
+#endif
+}
+
+namespace no_this_capture_for_static {
+
+struct X {
+ static void f(double) { }
+
+ int g() {
+ auto lam = [=](auto a) { f(a); };
+ lam(0); // ok.
+ ASSERT_NO_CAPTURES(lam);
+ return 0;
+ }
+};
+
+int run = X{}.g();
+}
+
+namespace this_capture_for_non_static {
+
+struct X {
+ void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) { f(a); };
+ L(0);
+ auto L2 = [](auto a) { f(a); }; //expected-error {{cannot be implicitly captured}}
+ return 0;
+ }
+};
+
+int run = X{}.g();
+}
+
+namespace this_captures_with_num_args_disambiguation {
+
+struct X {
+ void f(int) { }
+ static void f(double, int i) { }
+ int g() {
+ auto lam = [](auto a) { f(a, a); };
+ lam(0);
+ return 0;
+ }
+};
+
+int run = X{}.g();
+}
+namespace enclosing_function_is_template_this_capture {
+// Only error if the instantiation tries to use the member function.
+struct X {
+ void f(int) { }
+ static void f(double) { }
+ template<class T>
+ int g(T t) {
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
+ L(t); // expected-note{{in instantiation of}}
+ return 0;
+ }
+};
+
+int run = X{}.g(0.0); // OK.
+int run2 = X{}.g(0); // expected-note{{in instantiation of}}
+
+
+}
+
+namespace enclosing_function_is_template_this_capture_2 {
+// This should error, even if not instantiated, since
+// this would need to be captured.
+struct X {
+ void f(int) { }
+ template<class T>
+ int g(T t) {
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
+ L(t);
+ return 0;
+ }
+};
+
+}
+
+
+namespace enclosing_function_is_template_this_capture_3 {
+// This should not error, this does not need to be captured.
+struct X {
+ static void f(int) { }
+ template<class T>
+ int g(T t) {
+ auto L = [](auto a) { f(a); };
+ L(t);
+ return 0;
+ }
+};
+
+int run = X{}.g(0.0); // OK.
+int run2 = X{}.g(0); // OK.
+
+}
+
+namespace nested_this_capture_1 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [this]() {
+ return [=](auto b) {
+ f(b);
+ };
+ };
+ };
+ auto M = L(0);
+ auto N = M();
+ N(5);
+ return 0;
+ }
+};
+
+int run = X{}.g();
+
+}
+
+
+namespace nested_this_capture_2 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [&]() {
+ return [=](auto b) {
+ f(b);
+ };
+ };
+ };
+ auto M = L(0);
+ auto N = M();
+ N(5);
+ N(3.14);
+ return 0;
+ }
+};
+
+int run = X{}.g();
+
+}
+
+namespace nested_this_capture_3_1 {
+struct X {
+ template<class T>
+ void f(int, T t) { }
+ template<class T>
+ static void f(double, T t) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [&](auto c) {
+ return [=](auto b) {
+ f(b, c);
+ };
+ };
+ };
+ auto M = L(0);
+ auto N = M('a');
+ N(5);
+ N(3.14);
+ return 0;
+ }
+};
+
+int run = X{}.g();
+
+}
+
+
+namespace nested_this_capture_3_2 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [=](auto a) {
+ return [](int i) {
+ return [=](auto b) {
+ f(b); //expected-error {{'this' cannot}}
+ int x = i;
+ };
+ };
+ };
+ auto M = L(0.0);
+ auto N = M(3);
+ N(5); //expected-note {{in instantiation of}}
+ N(3.14); // OK.
+ return 0;
+ }
+};
+
+int run = X{}.g();
+
+}
+
+namespace nested_this_capture_4 {
+struct X {
+ void f(int) { }
+ static void f(double) { }
+
+ int g() {
+ auto L = [](auto a) {
+ return [=](auto i) {
+ return [=](auto b) {
+ f(b); //expected-error {{'this' cannot}}
+ int x = i;
+ };
+ };
+ };
+ auto M = L(0.0);
+ auto N = M(3);
+ N(5); //expected-note {{in instantiation of}}
+ N(3.14); // OK.
+ return 0;
+ }
+};
+
+int run = X{}.g();
+
+}
+namespace capture_enclosing_function_parameters {
+
+
+inline auto foo(int x) {
+ int i = 10;
+ auto lambda = [=](auto z) { return x + z; };
+ return lambda;
+}
+
+int foo2() {
+ auto L = foo(3);
+ L(4);
+ L('a');
+ L(3.14);
+ return 0;
+}
+
+inline auto foo3(int x) {
+ int local = 1;
+ auto L = [=](auto a) {
+ int i = a[local];
+ return [=](auto b) mutable {
+ auto n = b;
+ return [&, n](auto c) mutable {
+ ++local;
+ return ++x;
+ };
+ };
+ };
+ auto M = L("foo-abc");
+ auto N = M("foo-def");
+ auto O = N("foo-ghi");
+
+ return L;
+}
+
+int main() {
+ auto L3 = foo3(3);
+ auto M3 = L3("L3-1");
+ auto N3 = M3("M3-1");
+ auto O3 = N3("N3-1");
+ N3("N3-2");
+ M3("M3-2");
+ M3("M3-3");
+ L3("L3-2");
+}
+} // end ns
+
+namespace capture_arrays {
+
+inline int sum_array(int n) {
+ int array2[5] = { 1, 2, 3, 4, 5};
+
+ auto L = [=](auto N) -> int {
+ int sum = 0;
+ int array[5] = { 1, 2, 3, 4, 5 };
+ sum += array2[sum];
+ sum += array2[N];
+ return 0;
+ };
+ L(2);
+ return L(n);
+}
+}
+
+namespace capture_non_odr_used_variable_because_named_in_instantiation_dependent_expressions {
+
+// even though 'x' is not odr-used, it should be captured.
+
+int test() {
+ const int x = 10;
+ auto L = [=](auto a) {
+ (void) +x + a;
+ };
+ ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
+}
+
+} //end ns
+#ifdef MS_EXTENSIONS
+namespace explicit_spec {
+template<class R> struct X {
+ template<class T> int foo(T t) {
+ auto L = [](auto a) { return a; };
+ L(&t);
+ return 0;
+ }
+
+ template<> int foo<char>(char c) { //expected-warning{{explicit specialization}}
+ const int x = 10;
+ auto LC = [](auto a) { return a; };
+ R r;
+ LC(&r);
+ auto L = [=](auto a) {
+ return [=](auto b) {
+ int d[sizeof(a)];
+ f(x, d);
+ };
+ };
+ auto M = L(1);
+
+ ASSERT_NO_CAPTURES(M);
+ return 0;
+ }
+
+};
+
+int run_char = X<int>{}.foo('a');
+int run_int = X<double>{}.foo(4);
+}
+
+#endif // MS_EXTENSIONS
+
diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp
new file mode 100644
index 000000000000..20e06f48a1ce
--- /dev/null
+++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -0,0 +1,908 @@
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+namespace explicit_call {
+int test() {
+ auto L = [](auto a) { return a; };
+ L.operator()(3);
+ L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
+ return 0;
+}
+} //end ns
+
+namespace test_conversion_to_fptr_2 {
+
+template<class T> struct X {
+
+ T (*fp)(T) = [](auto a) { return a; };
+
+};
+
+X<int> xi;
+
+template<class T>
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
+ fp(t);
+}
+
+int test() {
+{
+ auto L = [](auto a) { return a; };
+ int (*fp)(int) = L;
+ fp(5);
+ L(3);
+ char (*fc)(char) = L;
+ fc('b');
+ L('c');
+ double (*fd)(double) = L;
+ fd(3.14);
+ fd(6.26);
+ L(4.25);
+}
+{
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+ int (*fp)(int) = L;
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+{
+ int x = 5;
+ auto L = [=](auto b, char c = 'x') {
+ int i = x;
+ return [](auto a) ->decltype(a) { return a; };
+ };
+ int (*fp)(int) = L(8);
+ fp(5);
+ L(3);
+ char (*fc)(char) = L('a');
+ fc('b');
+ L('c');
+ double (*fd)(double) = L(3.14);
+ fd(3.14);
+ fd(6.26);
+
+}
+{
+ auto L = [=](auto b) {
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
+ };
+ int* (*fp)(int) = L(8);
+ fp(5);
+ L(3);
+ char* (*fc)(char) = L('a');
+ fc('b');
+ L('c');
+ double* (*fd)(double) = L(3.14);
+ fd(3.14);
+ fd(6.26);
+}
+{
+ auto L = [=](auto b) {
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
+ };
+ char* (*fp)(int) = L('8');
+ fp(5);
+ char* (*fc)(char) = L('a');
+ fc('b');
+ double* (*fi)(int) = L(3.14);
+ fi(5);
+ int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
+}
+
+{
+ auto L = [=](auto b) {
+ return [](auto a) {
+ return [=](auto c) {
+ return [](auto d) ->decltype(a + b + c + d) { return d; };
+ };
+ };
+ };
+ int (*fp)(int) = L('8')(3)(short{});
+ double (*fs)(char) = L(3.14)(short{})('4');
+}
+
+ fooT(3);
+ fooT('a');
+ fooT(3.14);
+ fooT("abcdefg");
+ return 0;
+}
+int run2 = test();
+
+}
+
+
+namespace test_conversion_to_fptr {
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { } // expected-note{{candidate}}
+void g(int (*)(int)) { } // #1 expected-note{{candidate}}
+void g(char (*)(char)) { } // #2 expected-note{{candidate}}
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int test() {
+{
+ auto glambda = [](auto a) { return a; };
+ glambda(1);
+ f1(glambda); // OK
+ f2(glambda); // expected-error{{no matching function}}
+ g(glambda); // expected-error{{call to 'g' is ambiguous}}
+ h(glambda); // OK: calls #3 since it is convertible from ID
+
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+
+}
+{
+
+ auto L = [](auto a) { return a; };
+ int (*fp)(int) = L;
+ fp(5);
+ L(3);
+ char (*fc)(char) = L;
+ fc('b');
+ L('c');
+ double (*fd)(double) = L;
+ fd(3.14);
+ fd(6.26);
+ L(4.25);
+}
+{
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+ int (*fp)(int) = L;
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+{
+ int* (*fp)(int*) = [](auto *a) -> auto* { return a; };
+ fp(0);
+}
+}
+
+namespace more_converion_to_ptr_to_function_tests {
+
+
+int test() {
+ {
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+ int (*fp2)(int) = [](auto b) -> int { return b; };
+ int (*fp3)(char) = [](auto c) -> int { return c; };
+ char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+ char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+
+ fp2(3);
+ fp3('\n');
+ fp3('a');
+ return 0;
+ }
+} // end test()
+
+template<class ... Ts> void vfun(Ts ... ) { }
+
+int variadic_test() {
+
+ int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+
+ int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+ return 2;
+}
+
+} // end ns
+
+namespace conversion_operator {
+void test() {
+ auto L = [](auto a) -> int { return a; };
+ int (*fp)(int) = L;
+ int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}}
+ int (&&fp3)(int) = [](auto a) { return a; }; // expected-error{{no viable conversion}}\
+ //expected-note{{candidate}}
+ }
+}
+}
+
+namespace return_type_deduction_ok {
+ auto l = [](auto a) ->auto { return a; }(2);
+ auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
+ auto l3 = [](auto a) { return a; }(2);
+
+}
+
+namespace generic_lambda_as_default_argument_ok {
+ void test(int i = [](auto a)->int { return a; }(3)) {
+ }
+}
+
+namespace nested_non_capturing_lambda_tests {
+template<class ... Ts> void print(Ts ...) { }
+int test() {
+{
+ auto L = [](auto a) {
+ return [](auto b) {
+ return b;
+ };
+ };
+ auto M = L(3);
+ M(4.15);
+ }
+{
+ int i = 10; //expected-note 3{{declared here}}
+ auto L = [](auto a) {
+ return [](auto b) { //expected-note 3{{begins here}}
+ i = b; //expected-error 3{{cannot be implicitly captured}}
+ return b;
+ };
+ };
+ auto M = L(3); //expected-note{{instantiation}}
+ M(4.15); //expected-note{{instantiation}}
+ }
+ {
+ int i = 10;
+ auto L = [](auto a) {
+ return [](auto b) {
+ b = sizeof(i); //ok
+ return b;
+ };
+ };
+ }
+ {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto b) ->decltype(a) {
+ print("b = ", b, "\n");
+ return b;
+ };
+ };
+ auto M = L(3);
+ M(4.15);
+ }
+
+{
+ auto L = [](auto a) ->decltype(a) {
+ print("a = ", a, "\n");
+ return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+ print("b = ", b, "\n");
+ return b;
+ };
+ };
+ auto M = L(3); //expected-note{{in instantiation of}}
+ }
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto ... b) ->decltype(a) {
+ print("b = ", b ..., "\n");
+ return 4;
+ };
+ };
+ auto M = L(3);
+ M(4.15, 3, "fv");
+}
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto ... b) ->decltype(a) {
+ print("b = ", b ..., "\n");
+ return 4;
+ };
+ };
+ auto M = L(3);
+ int (*fp)(double, int, const char*) = M;
+ fp(4.15, 3, "fv");
+}
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](char b) {
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ return 42;
+ };
+ };
+ };
+ L(4);
+ auto M = L(3);
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](decltype(a) b) {
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ return 42;
+ };
+ };
+ };
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+
+{
+ struct X {
+ static void foo(double d) { }
+ void test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return 42;
+ };
+ };
+ };
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ }
+};
+X x;
+x.test();
+}
+// Make sure we can escape the function
+{
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return 42;
+ };
+ };
+ };
+ return L;
+ }
+};
+ X x;
+ auto L = x.test();
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+{
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+};
+ X x;
+ auto L = x.test();
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = O;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+}
+} // end test()
+
+namespace wrapped_within_templates {
+
+namespace explicit_return {
+template<class T> int fooT(T t) {
+ auto L = [](auto a) -> void {
+ auto M = [](char b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof(a);
+ x = sizeof(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(decltype(a){});
+ };
+ };
+ L(t);
+ L(3.14);
+ return 0;
+}
+
+int run = fooT('a') + fooT(3.14);
+
+} // end explicit_return
+
+namespace implicit_return_deduction {
+template<class T> auto fooT(T t) {
+ auto L = [](auto a) {
+ auto M = [](char b) {
+ auto N = [](auto c) {
+ int x = 0;
+ x = sizeof(a);
+ x = sizeof(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(decltype(a){});
+ };
+ };
+ L(t);
+ L(3.14);
+ return 0;
+}
+
+int run = fooT('a') + fooT(3.14);
+
+template<class ... Ts> void print(Ts ... ts) { }
+
+template<class F, class ... Rest> using first = F;
+
+template<class ... Ts> auto fooV(Ts ... ts) {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) {
+ auto N = [](auto c) {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(first<Ts...>{});
+ };
+ M(a...);
+ print("a = ", a..., "\n");
+ };
+ L(L, ts...);
+ print("ts = ", ts..., "\n");
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+} //implicit_return_deduction
+
+
+} //wrapped_within_templates
+
+namespace at_ns_scope {
+ void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+auto L = test();
+auto L_test = L('4');
+auto M = L('3');
+auto M_test = M('a');
+auto N = M('x');
+auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+char (*np)(const char*, int, const char*, double, const char*, int) = O;
+auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+
+
+}
+
+namespace variadic_tests_1 {
+template<class ... Ts> void print(Ts ... ts) { }
+
+template<class F, class ... Rest> using FirstType = F;
+template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }
+
+template<class ... Ts> int fooV(Ts ... ts) {
+ auto L = [](auto ... a) -> void {
+ auto M = [](decltype(a) ... b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ };
+ M(a...);
+ print("a = ", a..., "\n");
+ };
+ L(L, ts...);
+ print("ts = ", ts..., "\n");
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+namespace more_variadic_1 {
+
+template<class ... Ts> int fooV(Ts ... ts) {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ };
+ M(a...);
+ return M;
+ };
+ auto M = L(L, ts...);
+ decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
+ void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
+
+ {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ return N;
+ };
+ M(a...);
+ return M;
+ };
+ auto M = L(L, ts...);
+ decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
+ fp(L, ts...);
+ decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
+ fp2 = fp(L, ts...);
+ void (*fp3)(char) = fp2(L, ts...);
+ fp3('a');
+ }
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+
+} //end ns more_variadic_1
+
+} // end ns variadic_tests_1
+
+namespace at_ns_scope_within_class_member {
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+};
+X x;
+auto L = x.test();
+auto L_test = L('4');
+auto M = L('3');
+auto M_test = M('a');
+auto N = M('x');
+auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+char (*np)(const char*, int, const char*, double, const char*, int) = O;
+auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+} //end at_ns_scope_within_class_member
+
+
+namespace at_ns_scope_within_class_template_member {
+ struct X {
+ static void foo(double d) { }
+ template<class T = int>
+ auto test(T = T{}) {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+
+};
+X x;
+auto L = x.test();
+auto L_test = L('4');
+auto M = L('3');
+auto M_test = M('a');
+auto N = M('x');
+auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+char (*np)(const char*, int, const char*, double, const char*, int) = O;
+auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+} //end at_ns_scope_within_class_member
+
+
+namespace nested_generic_lambdas_123 {
+void test() {
+ auto L = [](auto a) -> int {
+ auto M = [](auto b, decltype(a) b2) -> int {
+ return 1;
+ };
+ M(a, a);
+ };
+ L(3);
+}
+template<class T> void foo(T) {
+ auto L = [](auto a) { return a; };
+}
+template void foo(int);
+} // end ns nested_generic_lambdas_123
+
+namespace nested_fptr_235 {
+int test()
+{
+ auto L = [](auto b) {
+ return [](auto a) ->decltype(a) { return a; };
+ };
+ int (*fp)(int) = L(8);
+ fp(5);
+ L(3);
+ char (*fc)(char) = L('a');
+ fc('b');
+ L('c');
+ double (*fd)(double) = L(3.14);
+ fd(3.14);
+ fd(6.26);
+ return 0;
+}
+int run = test();
+}
+
+
+namespace fptr_with_decltype_return_type {
+template<class F, class ... Ts> using FirstType = F;
+template<class F, class ... Rest> F& FirstArg(F& f, Rest& ... r) { return f; };
+template<class ... Ts> auto vfun(Ts&& ... ts) {
+ print(ts...);
+ return FirstArg(ts...);
+}
+int test()
+{
+ {
+ auto L = [](auto ... As) {
+ return [](auto b) ->decltype(b) {
+ vfun([](decltype(As) a) -> decltype(a) { return a; } ...)(FirstType<decltype(As)...>{});
+ return decltype(b){};
+ };
+ };
+ auto LL = L(1, 'a', 3.14, "abc");
+ LL("dim");
+ }
+ return 0;
+}
+int run = test();
+}
+
+} // end ns nested_non_capturing_lambda_tests
+
+namespace PR17476 {
+struct string {
+ string(const char *__s) { }
+ string &operator+=(const string &__str) { return *this; }
+};
+
+template <class T>
+void finalizeDefaultAtomValues() {
+ auto startEnd = [](const char * sym) -> void {
+ string start("__");
+ start += sym;
+ };
+ startEnd("preinit_array");
+}
+
+void f() { finalizeDefaultAtomValues<char>(); }
+
+}
+
+namespace PR17476_variant {
+struct string {
+ string(const char *__s) { }
+ string &operator+=(const string &__str) { return *this; }
+};
+
+template <class T>
+void finalizeDefaultAtomValues() {
+ auto startEnd = [](const T *sym) -> void {
+ string start("__");
+ start += sym;
+ };
+ startEnd("preinit_array");
+}
+
+void f() { finalizeDefaultAtomValues<char>(); }
+
+}
+
+namespace PR17877_lambda_declcontext_and_get_cur_lambda_disconnect {
+
+
+template<class T> struct U {
+ int t = 0;
+};
+
+template<class T>
+struct V {
+ U<T> size() const { return U<T>{}; }
+};
+
+template<typename T>
+void Do() {
+ V<int> v{};
+ [=] { v.size(); };
+}
+
+}
+
+namespace inclass_lambdas_within_nested_classes {
+namespace ns1 {
+
+struct X1 {
+ struct X2 {
+ enum { E = [](auto i) { return i; }(3) }; //expected-error{{inside of a constant expression}}\
+ //expected-error{{not an integral constant}}
+ int L = ([] (int i) { return i; })(2);
+ void foo(int i = ([] (int i) { return i; })(2)) { }
+ int B : ([](int i) { return i; })(3); //expected-error{{inside of a constant expression}}\
+ //expected-error{{not an integral constant}}
+ int arr[([](int i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+ //expected-error{{must have a constant size}}
+ int (*fp)(int) = [](int i) { return i; };
+ void fooptr(int (*fp)(char) = [](char c) { return 0; }) { }
+ int L2 = ([](auto i) { return i; })(2);
+ void fooG(int i = ([] (auto i) { return i; })(2)) { }
+ int BG : ([](auto i) { return i; })(3); //expected-error{{inside of a constant expression}} \
+ //expected-error{{not an integral constant}}
+ int arrG[([](auto i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+ //expected-error{{must have a constant size}}
+ int (*fpG)(int) = [](auto i) { return i; };
+ void fooptrG(int (*fp)(char) = [](auto c) { return 0; }) { }
+ };
+};
+} //end ns
+
+namespace ns2 {
+struct X1 {
+ template<class T>
+ struct X2 {
+ int L = ([] (T i) { return i; })(2);
+ void foo(int i = ([] (int i) { return i; })(2)) { }
+ int B : ([](T i) { return i; })(3); //expected-error{{inside of a constant expression}}\
+ //expected-error{{not an integral constant}}
+ int arr[([](T i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+ //expected-error{{must have a constant size}}
+ int (*fp)(T) = [](T i) { return i; };
+ void fooptr(T (*fp)(char) = [](char c) { return 0; }) { }
+ int L2 = ([](auto i) { return i; })(2);
+ void fooG(T i = ([] (auto i) { return i; })(2)) { }
+ int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}
+ int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}}
+ int (*fpG)(T) = [](auto i) { return i; };
+ void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { }
+ template<class U = char> int fooG2(T (*fp)(U) = [](auto a) { return 0; }) { return 0; }
+ template<class U = char> int fooG3(T (*fp)(U) = [](auto a) { return 0; });
+ };
+};
+template<class T>
+template<class U>
+int X1::X2<T>::fooG3(T (*fp)(U)) { return 0; }
+X1::X2<int> x2; //expected-note 3{{in instantiation of}}
+int run1 = x2.fooG2();
+int run2 = x2.fooG3();
+} // end ns
+
+
+
+} //end ns inclass_lambdas_within_nested_classes \ No newline at end of file
diff --git a/test/SemaCXX/cxx1y-init-captures.cpp b/test/SemaCXX/cxx1y-init-captures.cpp
new file mode 100644
index 000000000000..2cb4d31ffc4b
--- /dev/null
+++ b/test/SemaCXX/cxx1y-init-captures.cpp
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -std=c++1y %s -verify -emit-llvm-only
+
+namespace variadic_expansion {
+ int f(int &, char &) { return 0; }
+ template<class ... Ts> char fv(Ts ... ts) { return 0; }
+ // FIXME: why do we get 2 error messages
+ template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
+ f([&a(t)]()->decltype(auto) {
+ return a;
+ }() ...);
+
+ auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
+ const int y = 10;
+ auto M = [x = y,
+ &z = y](T& ... t) { };
+ auto N = [x = y,
+ &z = y, n = f(t...),
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) {
+ fv([&a(t)]()->decltype(auto) {
+ return a;
+ }() ...);
+ };
+ auto N2 = [x = y, //expected-note3{{begins here}}
+ &z = y, n = f(t...),
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) {
+ fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+ return a;
+ }() ...);
+ };
+
+ }
+
+ void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
+}
+
+namespace odr_use_within_init_capture {
+
+int test() {
+
+ { // no captures
+ const int x = 10;
+ auto L = [z = x + 2](int a) {
+ auto M = [y = x - 2](char b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // should not capture
+ const int x = 10;
+ auto L = [&z = x](int a) {
+ return a;;
+ };
+
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) { //expected-note {{declared}}
+ return [](int b) { //expected-note {{begins}}
+ return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
+ return c;
+ };
+ };
+ };
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) {
+ return [=](int b) {
+ return [j = k](int c) {
+ return c;
+ };
+ };
+ };
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) {
+ return [k](int b) {
+ return [j = k](int c) {
+ return c;
+ };
+ };
+ };
+ }
+
+ return 0;
+}
+
+int run = test();
+
+}
+
+namespace odr_use_within_init_capture_template {
+
+template<class T = int>
+int test(T t = T{}) {
+
+ { // no captures
+ const T x = 10;
+ auto L = [z = x](char a) {
+ auto M = [y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // should not capture
+ const T x = 10;
+ auto L = [&z = x](T a) {
+ return a;;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10; //expected-note {{declared}}
+ auto L = [z = x](char a) { //expected-note {{begins}}
+ auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10;
+ auto L = [=,z = x](char a) {
+ auto M = [&y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10;
+ auto L = [x, z = x](char a) {
+ auto M = [&y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+ }
+ { // will need to capture x in outer lambda
+ const int x = 10; //expected-note 2{{declared}}
+ auto L = [z = x](char a) { //expected-note 2{{begins}}
+ auto M = [&y = x](T b) { //expected-error 2{{cannot be implicitly captured}}
+ return y;
+ };
+ return M;
+ };
+ }
+ {
+ // no captures
+ const T x = 10;
+ auto L = [z =
+ [z = x, &y = x](char a) { return z + y; }('a')](char a)
+ { return z; };
+
+ }
+
+ return 0;
+}
+
+int run = test(); //expected-note {{instantiation}}
+
+} \ No newline at end of file
diff --git a/test/SemaCXX/cxx1y-sized-deallocation.cpp b/test/SemaCXX/cxx1y-sized-deallocation.cpp
new file mode 100644
index 000000000000..81a8eeb6df93
--- /dev/null
+++ b/test/SemaCXX/cxx1y-sized-deallocation.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s -fsized-deallocation -fexceptions -fcxx-exceptions
+
+using size_t = decltype(sizeof(0));
+
+void f(void *p, void *q) {
+ // OK, implicitly declared.
+ operator delete(p, 8);
+ operator delete[](q, 12);
+ static_assert(noexcept(operator delete(p, 8)), "");
+ static_assert(noexcept(operator delete[](q, 12)), "");
+}
+
+void *operator new(size_t bad, size_t idea);
+struct S { S() { throw 0; } };
+void g() {
+ new (123) S; // expected-error {{'new' expression with placement arguments refers to non-placement 'operator delete'}}
+}
diff --git a/test/SemaCXX/cxx1y-user-defined-literals.cpp b/test/SemaCXX/cxx1y-user-defined-literals.cpp
new file mode 100644
index 000000000000..fa4ff03fad7f
--- /dev/null
+++ b/test/SemaCXX/cxx1y-user-defined-literals.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++1y %s -include %s -verify
+
+#ifndef INCLUDED
+#define INCLUDED
+
+#pragma clang system_header
+namespace std {
+ using size_t = decltype(sizeof(0));
+
+ struct duration {};
+ duration operator""ns(unsigned long long);
+ duration operator""us(unsigned long long);
+ duration operator""ms(unsigned long long);
+ duration operator""s(unsigned long long);
+ duration operator""min(unsigned long long);
+ duration operator""h(unsigned long long);
+
+ struct string {};
+ string operator""s(const char*, size_t);
+
+ template<typename T> struct complex {};
+ complex<float> operator""if(long double);
+ complex<float> operator""if(unsigned long long);
+ complex<double> operator""i(long double);
+ complex<double> operator""i(unsigned long long);
+ complex<long double> operator""il(long double);
+ complex<long double> operator""il(unsigned long long);
+}
+
+#else
+
+using namespace std;
+duration a = 1ns, b = 1us, c = 1ms, d = 1s, e = 1min, f = 1h;
+string s = "foo"s;
+char error = 'x's; // expected-error {{invalid suffix}} expected-error {{expected ';'}}
+
+int _1z = 1z; // expected-error {{invalid suffix}}
+int _1b = 1b; // expected-error {{invalid digit}}
+
+complex<float> cf1 = 1if, cf2 = 2.if, cf3 = 0x3if;
+complex<double> cd1 = 1i, cd2 = 2.i, cd3 = 0b0110101i;
+complex<long double> cld1 = 1il, cld2 = 2.il, cld3 = 0047il;
+
+#endif
diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
new file mode 100644
index 000000000000..94d0f16f06ed
--- /dev/null
+++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -0,0 +1,299 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s
+
+#define CONST const
+
+#ifdef PRECXX11
+#define static_assert(expr, msg) typedef int static_assert[(expr) ? 1 : -1];
+#endif
+
+class A {
+ template<typename T> CONST T wrong; // expected-error {{member 'wrong' declared as a template}}
+ template<typename T> CONST T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
+ template<typename T, typename T0> static CONST T right = T(100);
+ template<typename T> static CONST T right<T,int> = 5;
+ template<typename T> CONST int right<int,T>; // expected-error {{member 'right' declared as a template}}
+ template<typename T> CONST float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
+ template<> static CONST int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
+ template<> static CONST float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
+ template static CONST int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \
+ // expected-error {{explicit specialization of 'right' in class scope}}
+};
+
+namespace out_of_line {
+ class B0 {
+ template<typename T, typename T0> static CONST T right = T(100);
+ template<typename T> static CONST T right<T,int> = T(5);
+ };
+ template<> CONST int B0::right<int,int> = 7;
+ template CONST int B0::right<int,int>;
+ template<> CONST int B0::right<int,float>;
+ template CONST int B0::right<int,float>;
+
+ class B1 {
+ template<typename T, typename T0> static CONST T right;
+ template<typename T> static CONST T right<T,int>;
+ };
+ template<typename T, typename T0> CONST T B1::right = T(100);
+ template<typename T> CONST T B1::right<T,int> = T(5);
+
+ class B2 {
+ template<typename T, typename T0> static CONST T right = T(100); // expected-note {{previous definition is here}}
+ template<typename T> static CONST T right<T,int> = T(5); // expected-note {{previous definition is here}}
+ };
+ template<typename T, typename T0> CONST T B2::right = T(100); // expected-error {{redefinition of 'right'}}
+ template<typename T> CONST T B2::right<T,int> = T(5); // expected-error {{redefinition of 'right'}}
+
+ class B3 {
+ template<typename T, typename T0> static CONST T right = T(100);
+ template<typename T> static CONST T right<T,int> = T(5);
+ };
+ template<typename T, typename T0> CONST T B3::right;
+ template<typename T> CONST T B3::right<T,int>;
+
+ class B4 {
+ template<typename T, typename T0> static CONST T a;
+ template<typename T> static CONST T a<T,int> = T(100);
+ template<typename T, typename T0> static CONST T b = T(100);
+ template<typename T> static CONST T b<T,int>;
+ };
+ template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
+ template<typename T> CONST T B4::a<T,int>;
+ template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
+ template CONST int B4::a<int,int>;
+
+ template<typename T, typename T0> CONST T B4::b;
+ template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
+ template CONST int B4::b<int,char>;
+ template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
+}
+
+namespace non_const_init {
+ class A {
+ template<typename T> static T wrong_inst_undefined = T(10); // expected-note {{refers here}}
+ template<typename T> static T wrong_inst_defined = T(10); // expected-error {{non-const static data member must be initialized out of line}}
+ template<typename T> static T wrong_inst_out_of_line;
+ };
+
+ template const int A::wrong_inst_undefined<const int>; // expected-error {{undefined}}
+
+ template<typename T> T A::wrong_inst_defined;
+ template const int A::wrong_inst_defined<const int>;
+ template int A::wrong_inst_defined<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst_defined<int>' requested here}}
+
+ template<typename T> T A::wrong_inst_out_of_line = T(10);
+ template int A::wrong_inst_out_of_line<int>;
+
+ class B {
+ template<typename T> static T wrong_inst; // expected-note {{refers here}}
+ template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}} expected-note {{refers here}}
+
+ template<typename T> static T wrong_inst_fixed;
+ template<typename T> static T wrong_inst_fixed<T*>;
+ };
+ template int B::wrong_inst<int>; // expected-error {{undefined}}
+ // FIXME: It'd be better to produce the 'explicit instantiation of undefined
+ // template' diagnostic here, not the 'must be initialized out of line'
+ // diagnostic.
+ template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
+ template const int B::wrong_inst<const int*>; // expected-error {{undefined}}
+ template<typename T> T B::wrong_inst_fixed = T(100);
+ template int B::wrong_inst_fixed<int>;
+
+ class C {
+ template<typename T> static CONST T right_inst = T(10); // expected-note {{here}}
+ template<typename T> static CONST T right_inst<T*> = T(100); // expected-note {{here}}
+ };
+ template CONST int C::right_inst<int>; // expected-error {{undefined variable template}}
+ template CONST int C::right_inst<int*>; // expected-error {{undefined variable template}}
+
+ namespace pointers {
+
+ struct C0 {
+ template<typename U> static U Data;
+ template<typename U> static CONST U Data<U*> = U(); // expected-note {{here}}
+
+ template<typename U> static U Data2;
+ template<typename U> static CONST U Data2<U*> = U();
+ };
+ const int c0_test = C0::Data<int*>;
+ static_assert(c0_test == 0, "");
+ template const int C0::Data<int*>; // expected-error {{undefined}}
+
+ template<typename U> const U C0::Data2<U*>;
+ template const int C0::Data2<int*>;
+
+ struct C1a {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>; // Okay, with out-of-line definition
+ };
+ template<typename T> T* C1a::Data<T*> = new T();
+ template int* C1a::Data<int*>;
+
+ struct C1b {
+ template<typename U> static U Data;
+ template<typename U> static CONST U* Data<U*>; // Okay, with out-of-line definition
+ };
+ template<typename T> CONST T* C1b::Data<T*> = (T*)(0);
+ template CONST int* C1b::Data<int*>;
+
+ struct C2a {
+ template<typename U> static int Data;
+ template<typename U> static U* Data<U*> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
+ };
+ template int* C2a::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
+
+ struct C2b {
+ template<typename U> static int Data;
+ template<typename U> static U *const Data<U*> = (U*)(0); // expected-error {{static data member of type 'int *const'}}
+ };
+ template<typename U> U *const C2b::Data<U*>;
+ template int *const C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
+ }
+}
+
+#ifndef PRECXX11
+namespace constexpred {
+ class A {
+ template<typename T> constexpr T wrong; // expected-error {{member 'wrong' declared as a template}} \
+ // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
+ template<typename T> constexpr T wrong_init = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
+ template<typename T, typename T0> static constexpr T right = T(100);
+ template<typename T> static constexpr T right<T,int> = 5;
+ template<typename T> constexpr int right<int,T>; // expected-error {{member 'right' declared as a template}} \
+ // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
+ template<typename T> constexpr float right<float,T> = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
+ template<> static constexpr int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
+ template<> static constexpr float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
+ template static constexpr int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \
+ // expected-error {{explicit specialization of 'right' in class scope}}
+ };
+}
+#endif
+
+namespace in_class_template {
+
+ template<typename T>
+ class D0 {
+ template<typename U> static U Data; // expected-note {{here}}
+ template<typename U> static CONST U Data<U*> = U();
+ };
+ template CONST int D0<float>::Data<int*>;
+ template int D0<float>::Data<int>; // expected-error {{undefined}}
+ template<typename T> template<typename U> const U D0<T>::Data<U*>;
+
+ template<typename T>
+ class D1 {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>;
+ };
+ template<typename T>
+ template<typename U> U* D1<T>::Data<U*> = (U*)(0);
+ template int* D1<float>::Data<int*>; // expected-note {{previous}}
+ template int* D1<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
+
+ template<typename T>
+ class D2 {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>;
+ };
+ template<>
+ template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
+ template int* D2<float>::Data<int*>; // expected-note {{previous}}
+ template int* D2<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
+
+ template<typename T>
+ struct D3 {
+ template<typename U> static CONST U Data = U(100); // expected-note {{here}}
+ };
+ static_assert(D3<float>::Data<int> == 100, "");
+ template const char D3<float>::Data<char>; // expected-error {{undefined}}
+
+ namespace bug_files {
+ template<typename T>
+ class D0a {
+ template<typename U> static U Data;
+ template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}}
+ };
+ template<>
+ template<typename U> U D0a<float>::Data<U*> = U(100); // expected-error {{redefinition of 'Data'}}
+
+ // FIXME: We should accept this, and the corresponding case for class
+ // templates.
+ //
+ // [temp.class.spec.mfunc]/2: If the primary member template is explicitly
+ // specialized for a given specialization of the enclosing class template,
+ // the partial specializations of the member template are ignored
+ template<typename T>
+ class D1 {
+ template<typename U> static U Data;
+ template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}}
+ };
+ template<>
+ template<typename U> U D1<float>::Data = U(10);
+ template<>
+ template<typename U> U D1<float>::Data<U*> = U(100); // expected-error{{redefinition of 'Data'}}
+ }
+
+ namespace definition_after_outer_instantiation {
+ template<typename A> struct S {
+ template<typename B> static const int V1;
+ template<typename B> static const int V2;
+ };
+ template struct S<int>;
+ template<typename A> template<typename B> const int S<A>::V1 = 123;
+ template<typename A> template<typename B> const int S<A>::V2<B*> = 456;
+
+ static_assert(S<int>::V1<int> == 123, "");
+
+ // FIXME: The first and third case below possibly should be accepted. We're
+ // not picking up partial specializations added after the primary template
+ // is instantiated. This is kind of implied by [temp.class.spec.mfunc]/2,
+ // and matches our behavior for member class templates, but it's not clear
+ // that this is intentional. See PR17294 and core-24030.
+ static_assert(S<int>::V2<int*> == 456, ""); // FIXME expected-error {{}}
+ static_assert(S<int>::V2<int&> == 789, ""); // expected-error {{}}
+
+ template<typename A> template<typename B> const int S<A>::V2<B&> = 789;
+ static_assert(S<int>::V2<int&> == 789, ""); // FIXME expected-error {{}}
+
+ // All is OK if the partial specialization is declared before the implicit
+ // instantiation of the class template specialization.
+ static_assert(S<char>::V1<int> == 123, "");
+ static_assert(S<char>::V2<int*> == 456, "");
+ static_assert(S<char>::V2<int&> == 789, "");
+ }
+
+ namespace incomplete_array {
+ template<typename T> extern T var[];
+ template<typename T> T var[] = { 1, 2, 3 };
+ template<> char var<char>[] = "hello";
+ template<typename T> char var<T*>[] = "pointer";
+
+ static_assert(sizeof(var<int>) == 12, "");
+ static_assert(sizeof(var<char>) == 6, "");
+ static_assert(sizeof(var<void*>) == 8, "");
+
+ template<typename...> struct tuple;
+
+ template<typename T> struct A {
+ template<typename U> static T x[];
+ template<typename U> static T y[];
+
+ template<typename...U> static T y<tuple<U...> >[];
+ };
+
+ int *use_before_definition = A<int>::x<char>;
+ template<typename T> template<typename U> T A<T>::x[sizeof(U)];
+ static_assert(sizeof(A<int>::x<char>) == 4, "");
+
+ template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
+ static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, "");
+ }
+}
+
+namespace in_nested_classes {
+ // TODO:
+}
+
diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
new file mode 100644
index 000000000000..b6e8762f5d59
--- /dev/null
+++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
@@ -0,0 +1,434 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-c++11-extensions -Wno-c++1y-extensions %s -DPRECXX11
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s
+
+#ifdef PRECXX11
+ #define CONST const
+#else
+ #define CONST constexpr
+#endif
+
+template<typename T>
+T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+template<typename T>
+CONST T cpi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+template<typename T> extern CONST T vc;
+#ifndef PRECXX11
+// expected-error@-2 {{constexpr variable declaration must be a definition}}
+#endif
+
+namespace use_in_top_level_funcs {
+
+ void good() {
+ int ipi = pi<int>;
+ int icpi = cpi<int>;
+ double dpi = pi<double>;
+ double dcpi = cpi<double>;
+ }
+
+ void no_deduce() {
+ // template arguments are not deduced for uses of variable templates.
+ int ipi = pi; // expected-error {{cannot refer to variable template 'pi' without a template argument list}}
+ int icpi = cpi; // expected-error {{cannot refer to variable template 'cpi' without a template argument list}}
+ }
+
+ template<typename T>
+ T circular_area(T r) {
+ return pi<T> * r * r;
+ }
+
+ template<typename T>
+ CONST T const_circular_area(T r) {
+ return cpi<T> * r * r;
+ }
+
+ double use_circular_area(double r) {
+ CONST float t = const_circular_area(2.0) - 12;
+#ifndef PRECXX11
+ static_assert(const_circular_area(2) == 12, "");
+ CONST int test = (t > 0) && (t < 1);
+ static_assert(test, "");
+#endif
+ return circular_area(r);
+ }
+}
+
+namespace shadow {
+ void foo() {
+ int ipi0 = pi<int>;
+ int pi;
+ int a = pi;
+ int ipi = pi<int>; // expected-error {{expected '(' for function-style cast or type construction}} \
+ // expected-error {{expected expression}}
+ }
+}
+
+namespace odr_tmpl {
+ namespace pv_cvt {
+ int v; // expected-note {{previous definition is here}}
+ template<typename T> T v; // expected-error {{redefinition of 'v' as different kind of symbol}}
+ }
+ namespace pvt_cv {
+ template<typename T> T v; // expected-note {{previous definition is here}}
+ int v; // expected-error {{redefinition of 'v' as different kind of symbol}}
+ }
+ namespace pvt_cvt {
+ template<typename T> T v0; // expected-note {{previous definition is here}}
+ template<typename T> T v0; // expected-error {{redefinition of 'v0'}}
+
+ template<typename T> T v; // expected-note {{previous definition is here}}
+ template<typename T> int v; // expected-error {{redefinition of 'v'}}
+
+ template<typename T> int v1; // expected-note {{previous template declaration is here}}
+ template<int I> int v1; // expected-error {{template parameter has a different kind in template redeclaration}}
+ }
+ namespace pvt_use {
+ template<typename T> T v;
+ v = 10; // expected-error {{C++ requires a type specifier for all declarations}}
+ }
+
+ namespace pvt_diff_params {
+ // FIXME: (?) Redefinitions should simply be not allowed, whether the
+ // template parameters match or not. However, this current behaviour also
+ // matches that of class templates...
+ template<typename T, typename> T v; // expected-note 2{{previous template declaration is here}}
+ template<typename T> T v; // expected-error {{too few template parameters in template redeclaration}}
+ template<typename T, typename, typename> T v; // expected-error {{too many template parameters in template redeclaration}}
+ }
+
+ namespace pvt_extern {
+ template<typename T> T v = T();
+ template<typename T> extern T v; // redeclaration is allowed \
+ // expected-note {{previous definition is here}}
+ template<typename T> extern int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}}
+
+#ifndef PRECXX11
+ template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
+#endif
+
+ template<typename T> T var = T(); // expected-note {{previous definition is here}}
+ extern int var; // expected-error {{redefinition of 'var' as different kind of symbol}}
+ }
+
+#ifndef PRECXX11
+ namespace pvt_auto {
+ template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with type 'auto' requires an initializer}}
+ template<typename T> auto v1 = T(); // expected-note {{previous definition is here}}
+ template<typename T> int v1; // expected-error {{redefinition of 'v1' with a different type: 'int' vs 'auto'}}
+ template<typename T> auto v2 = T(); // expected-note {{previous definition is here}}
+ template<typename T> T v2; // expected-error {{redefinition of 'v2'}}
+ template<typename T> auto v3 = T(); // expected-note {{previous definition is here}}
+ template<typename T> extern T v3; // expected-error {{redefinition of 'v3' with a different type: 'T' vs 'auto'}}
+ template<typename T> auto v4 = T();
+ template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}}
+ }
+#endif
+
+}
+
+namespace explicit_instantiation {
+ template<typename T>
+ T pi0a = T(3.1415926535897932385); // expected-note {{variable template 'pi0a' declared here}}
+ template float pi0a<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0a' does not match expected type 'int'}}
+
+ template<typename T>
+ T pi0b = T(3.1415926535897932385); // expected-note {{variable template 'pi0b' declared here}}
+ template CONST int pi0b<int>; // expected-error {{type 'const int' of explicit instantiation of 'pi0b' does not match expected type 'int'}}
+
+ template<typename T>
+ T pi0c = T(3.1415926535897932385); // expected-note {{variable template 'pi0c' declared here}}
+ template int pi0c<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi0c' does not match expected type 'const int'}}
+
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+ template int pi0<int>; // expected-note {{previous explicit instantiation is here}}
+ template int pi0<int>; // expected-error {{duplicate explicit instantiation of 'pi0<int>'}}
+
+ template<typename T>
+ CONST T pi1a = T(3.1415926535897932385); // expected-note {{variable template 'pi1a' declared here}}
+ template int pi1a<int>; // expected-error {{type 'int' of explicit instantiation of 'pi1a' does not match expected type 'const int'}}
+
+ template<typename T>
+ CONST T pi1b = T(3.1415926535897932385); // expected-note {{variable template 'pi1b' declared here}}
+ template int pi1b<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi1b' does not match expected type 'const const int'}}
+
+ template<typename T>
+ CONST T pi1 = T(3.1415926535897932385);
+ template CONST int pi1<int>; // expected-note {{previous explicit instantiation is here}}
+ template CONST int pi1<int>; // expected-error {{duplicate explicit instantiation of 'pi1<int>'}}
+
+#ifndef PRECXX11
+ namespace auto_var {
+ template<typename T> auto var0 = T();
+ template auto var0<int>; // expected-error {{'auto' variable template instantiation is not allowed}}
+
+ template<typename T> auto var = T();
+ template int var<int>;
+ }
+#endif
+
+ template<typename=int> int missing_args; // expected-note {{here}}
+ template int missing_args; // expected-error {{must specify a template argument list}}
+
+ namespace extern_var {
+ // TODO:
+ }
+}
+
+namespace explicit_specialization {
+
+ namespace good {
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T>
+ CONST int pi2<T,int> = 2;
+
+ template<typename T>
+ CONST int pi2<int,T> = 3;
+
+ template<> CONST int pi2<int,int> = 4;
+
+#ifndef PRECXX11
+ void foo() {
+ static_assert(pi2<int,int> == 4, "");
+ static_assert(pi2<float,int> == 2, "");
+ static_assert(pi2<int,float> == 3, "");
+ static_assert(pi2<int,float> == pi2<int,double>, "");
+ static_assert(pi2<float,float> == 1, "");
+ static_assert(pi2<float,float> == pi2<float,double>, "");
+ }
+#endif
+ }
+
+ namespace ambiguous {
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T>
+ CONST int pi2<T,int> = 2; // expected-note {{partial specialization matches [with T = int]}}
+
+ template<typename T>
+ CONST int pi2<int,T> = 3; // expected-note {{partial specialization matches [with T = int]}}
+
+ void foo() {
+ int a = pi2<int,int>; // expected-error {{ambiguous partial specializations of 'pi2<int, int>'}}
+ }
+ }
+
+ namespace type_changes {
+
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template<> float pi0<int> = 10;
+ template<> int pi0<const int> = 10;
+
+ template<typename T>
+ T pi1 = T(3.1415926535897932385);
+ template<> CONST int pi1<int> = 10;
+
+ template<typename T>
+ T pi2 = T(3.1415926535897932385);
+ template<> int pi2<const int> = 10;
+
+ template<typename T>
+ CONST T pi4 = T(3.1415926535897932385);
+ template<> int pi4<int> = 10;
+ }
+
+ namespace redefinition {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template<> int pi0<int> = 10; // expected-note 3{{previous definition is here}}
+#ifndef PRECXX11
+// expected-note@-2 {{previous definition is here}}
+#endif
+ template<> int pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}}
+ template<> CONST int pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'const int' vs 'int'}}
+ template<> float pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'float' vs 'int'}}
+#ifndef PRECXX11
+ template<> auto pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}}
+#endif
+
+
+ template<typename T>
+ CONST T pi1 = T(3.1415926535897932385);
+
+ template<> CONST int pi1<int> = 10; // expected-note {{previous definition is here}}
+ template<> CONST int pi1<int> = 10; // expected-error {{redefinition of 'pi1<int>'}}
+ }
+
+ namespace before_instantiation {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385); // expected-note {{variable template 'pi0' declared here}}
+
+ template<> int pi0<int> = 10;
+ template int pi0<int>;
+ template float pi0<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0' does not match expected type}}
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T> CONST int pi2<T,int> = 2;
+ template CONST int pi2<int,int>;
+ }
+ namespace after_instantiation {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template int pi0<int>; // expected-note 2{{explicit instantiation first required here}}
+ template<> int pi0<int> = 10; // expected-error {{explicit specialization of 'pi0' after instantiation}}
+ template<> float pi0<int>; // expected-error {{explicit specialization of 'pi0' after instantiation}}
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template CONST int pi2<int,int>;
+ template<typename T> CONST int pi2<T,int> = 2;
+ }
+
+#ifndef PRECXX11
+ namespace auto_var {
+ template<typename T, typename> auto var0 = T();
+ template<typename T> auto var0<T,int> = T();
+ template<> auto var0<int,int> = 7;
+
+ template<typename T, typename> auto var = T();
+ template<typename T> T var<T,int> = T(5);
+ template<> int var<int,int> = 7;
+
+ void foo() {
+ int i0 = var0<int,int>;
+ int b = var<int,int>;
+ }
+ }
+#endif
+
+ namespace extern_var {
+ // TODO:
+ }
+
+ namespace diff_type {
+ // TODO:
+ template<typename T> T* var = new T();
+#ifndef PRECXX11
+ template<typename T> auto var<T*> = T(); // expected-note {{previous definition is here}}
+ template<typename T> T var<T*> = T(); // expected-error {{redefinition of 'var' with a different type: 'T' vs 'auto'}}
+#endif
+ }
+}
+
+namespace narrowing {
+ template<typename T> T v = {1234}; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 1234 to}}
+#ifndef PRECXX11
+ // expected-error@-2 {{constant expression evaluates to 1234 which cannot be narrowed to type 'char'}}\
+ // expected-note@-2 {{override this message by inserting an explicit cast}}
+#endif
+ int k = v<char>; // expected-note {{in instantiation of variable template specialization 'narrowing::v<char>' requested here}}
+}
+
+namespace use_in_structs {
+ // TODO:
+}
+
+namespace attributes {
+ // TODO:
+}
+
+#ifndef PRECXX11
+namespace arrays {
+ template<typename T>
+ T* arr = new T[10]{T(10), T(23)};
+
+ float f = 10.5;
+ template<> float* arr<float> = &f;
+
+ void bar() {
+ int *iarr = arr<int>;
+ iarr[0] = 1;
+ iarr[2] = 3;
+ iarr[6] = -2;
+
+ float ff = *arr<float>;
+ float nof = arr<float>[3]; // No bounds-check in C++
+ }
+}
+#endif
+
+namespace nested {
+
+ namespace n0a {
+ template<typename T>
+ T pi0a = T(3.1415926535897932385);
+ }
+
+ using namespace n0a;
+ int i0a = pi0a<int>;
+
+ template float pi0a<float>;
+ float f0a = pi0a<float>;
+
+ template<> double pi0a<double> = 5.2;
+ double d0a = pi0a<double>;
+
+ namespace n0b {
+ template<typename T>
+ T pi0b = T(3.1415926535897932385);
+ }
+
+ int i0b = n0b::pi0b<int>;
+
+ template float n0b::pi0b<float>;
+ float f0b = n0b::pi0b<float>;
+
+ template<> double n0b::pi0b<double> = 5.2;
+ double d0b = n0b::pi0b<double>;
+
+ namespace n1 {
+ template<typename T>
+ T pi1a = T(3.1415926535897932385);
+#ifndef PRECXX11
+// expected-note@-2 {{explicit instantiation refers here}}
+#endif
+
+ template<typename T>
+ T pi1b = T(3.1415926535897932385); // expected-note {{explicitly specialized declaration is here}}
+#ifndef PRECXX11
+// expected-note@-2 {{explicit instantiation refers here}}
+#endif
+ }
+
+ namespace use_n1a {
+ using namespace n1;
+ int i1 = pi1a<int>;
+
+ template float pi1a<float>;
+#ifndef PRECXX11
+// expected-error@-2 {{explicit instantiation of 'pi1a<float>' not in a namespace enclosing 'n1'}}
+#endif
+ float f1 = pi1a<float>;
+
+ template<> double pi1a<double> = 5.2; // expected-error {{no variable template matches specialization}}
+ double d1 = pi1a<double>;
+ }
+
+ namespace use_n1b {
+ int i1 = n1::pi1b<int>;
+
+ template float n1::pi1b<float>;
+#ifndef PRECXX11
+// expected-error@-2 {{explicit instantiation of 'pi1b<float>' not in a namespace enclosing 'n1'}}
+#endif
+ float f1 = n1::pi1b<float>;
+
+ template<> double n1::pi1b<double> = 5.2; // expected-error {{cannot define or redeclare 'pi1b' here because namespace 'use_n1b' does not enclose namespace 'n1'}} \
+ // expected-error {{variable template specialization of 'pi1b' must originally be declared in namespace 'n1'}}
+ double d1 = n1::pi1b<double>;
+ }
+}
+
diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp
index 208ea4ce9238..b74dcb4238ae 100644
--- a/test/SemaCXX/cxx98-compat-pedantic.cpp
+++ b/test/SemaCXX/cxx98-compat-pedantic.cpp
@@ -1,9 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat-pedantic -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat-pedantic -verify %s -DCXX1Y2
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror %s -DCXX1Y2
// 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 -Werror %s
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat-pedantic -verify %s -Wno-c++98-c++11-compat-pedantic -DCXX1Y2
+
// -Wc++98-compat-pedantic warns on C++11 features which we accept without a
// warning in C++98 mode.
@@ -30,7 +32,12 @@ void *FnVoidPtr = (void*)&dlsym; // expected-warning {{cast between pointer-to-f
struct ConvertToInt {
operator int();
};
-int *ArraySizeConversion = new int[ConvertToInt()]; // expected-warning {{implicit conversion from array size expression of type 'ConvertToInt' to integral type 'int' is incompatible with C++98}}
+int *ArraySizeConversion = new int[ConvertToInt()];
+#ifdef CXX1Y2
+// expected-warning@-2 {{implicit conversion from array size expression of type 'ConvertToInt' to integral type 'size_t' is incompatible with C++98}}
+#else
+// expected-warning@-4 {{implicit conversion from array size expression of type 'ConvertToInt' to integral type 'int' is incompatible with C++98}}
+#endif
template<typename T> class ExternTemplate {};
extern template class ExternTemplate<int>; // expected-warning {{extern templates are incompatible with C++98}}
@@ -44,8 +51,3 @@ int k = 0b1001;
#ifdef CXX1Y
// expected-warning@-2 {{binary integer literals are incompatible with C++ standards before C++1y}}
#endif
-
-void f(int n) { int a[n]; }
-#ifdef CXX1Y
-// expected-warning@-2 {{arrays of runtime bound are incompatible with C++ standards before C++1y}}
-#endif
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 7d36770f5d20..9690638ce025 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT
namespace std {
struct type_info;
@@ -73,7 +73,7 @@ int InitList(int i = {}) { // expected-warning {{generalized initializer lists a
Ctor c2 = { 3.0, 4l }; // expected-warning {{constructor call from initializer list is incompatible with C++98}}
InitListCtor ilc = { true, false }; // expected-warning {{initialization of initializer_list object is incompatible with C++98}}
const int &r = { 0 }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
- struct { int a; const int &r; } rr = { 0, {{0}} }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
+ struct { int a; const int &r; } rr = { 0, {0} }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
}
struct DelayedDefaultArgumentParseInitList {
@@ -147,16 +147,12 @@ bool no_except_expr = noexcept(1 + 1); // expected-warning {{noexcept expression
void *null = nullptr; // expected-warning {{'nullptr' is incompatible with C++98}}
static_assert(true, "!"); // expected-warning {{static_assert declarations are incompatible with C++98}}
-// FIXME: Reintroduce this test if support for inheriting constructors is
-// implemented.
-#if 0
struct InhCtorBase {
InhCtorBase(int);
};
struct InhCtorDerived : InhCtorBase {
- using InhCtorBase::InhCtorBase; // xpected-warning {{inheriting constructors are incompatible with C++98}}
+ using InhCtorBase::InhCtorBase; // expected-warning {{inheriting constructors are incompatible with C++98}}
};
-#endif
struct FriendMember {
static void MemberFn();
@@ -382,3 +378,79 @@ namespace rdar11736429 {
X x; // expected-warning{{union member 'x' with a non-trivial constructor is incompatible with C++98}}
};
}
+
+template<typename T> T var = T(10);
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T* var<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<> int var<int> = 10;
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template int var<int>;
+float fvar = var<float>;
+
+class A {
+ template<typename T> static T var = T(10);
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+ template<typename T> static T* var<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+};
+
+struct B { template<typename T> static T v; };
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T B::v = T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T* B::v<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<> int B::v<int> = 10;
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template int B::v<int>;
+float fsvar = B::v<float>;
+
+#ifdef CXX1YCOMPAT
+int digit_seps = 123'456; // expected-warning {{digit separators are incompatible with C++ standards before C++1y}}
+#endif
diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp
index 97780e41f0c4..c0f1e2e96a4d 100644
--- a/test/SemaCXX/dcl_ambig_res.cpp
+++ b/test/SemaCXX/dcl_ambig_res.cpp
@@ -44,9 +44,7 @@ S4<int(1)> y; // expected-error{{must be a type}}
void foo5()
{
(void)sizeof(int(1)); //expression
- // FIXME: should we make this an error rather than a warning?
- // (It affects SFINAE)
- (void)sizeof(int()); // expected-warning{{function type}}
+ (void)sizeof(int()); // expected-error{{function type}}
}
// [dcl.ambig.res]p6:
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 87fd2dad316c..8164b2bc91e7 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors -x objective-c++ %s
void f() {
int a;
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 4c635c1a2447..2d0c9cb4ffbe 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -26,4 +26,13 @@ int main() {
}
struct PR6139 { A (&x)[1]; };
-PR6139 x = {{A()}}; // expected-error{{non-const lvalue reference to type 'A [1]' cannot bind to a temporary of type 'A'}}
+PR6139 x = {{A()}}; // expected-error{{non-const lvalue reference to type 'A [1]' cannot bind to an initializer list temporary}}
+
+struct PR6139b { A (&x)[1]; };
+PR6139b y = {A()}; // expected-error{{non-const lvalue reference to type 'A [1]' cannot bind to a temporary of type 'A'}}
+
+namespace PR16502 {
+ struct A { int &&temporary; int x, y; };
+ int f();
+ const A &c = { 10, ++c.temporary };
+}
diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp
index 3175af7f1b07..9f1463245ba2 100644
--- a/test/SemaCXX/decl-microsoft-call-conv.cpp
+++ b/test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -1,21 +1,24 @@
// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -fms-extensions -verify %s
+typedef void void_fun_t();
+typedef void __cdecl cdecl_fun_t();
+
// Pointers to free functions
-void free_func_default();
-void __cdecl free_func_cdecl();
-void __stdcall free_func_stdcall(); // expected-note {{previous declaration is here}}
+void free_func_default(); // expected-note 2 {{previous declaration is here}}
+void __cdecl free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
+void __stdcall free_func_stdcall(); // expected-note 2 {{previous declaration is here}}
void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}}
-void __cdecl free_func_default(); // expected-note 2 {{previous declaration is here}}
+void __cdecl free_func_default();
void __stdcall free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void __fastcall free_func_default(); // expected-error {{function declared 'fastcall' here was previously declared without calling convention}}
-void free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
+void free_func_cdecl();
void __stdcall free_func_cdecl(); // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
void __fastcall free_func_cdecl(); // expected-error {{function declared 'fastcall' here was previously declared 'cdecl'}}
+void free_func_stdcall();
void __cdecl free_func_stdcall(); // expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}}
-void free_func_stdcall(); // expected-note {{previous declaration is here}}
void __fastcall free_func_stdcall(); // expected-error {{function declared 'fastcall' here was previously declared 'stdcall'}}
void __cdecl free_func_fastcall(); // expected-error {{function declared 'cdecl' here was previously declared 'fastcall'}}
@@ -29,6 +32,8 @@ void __cdecl free_func_default(int *);
void __thiscall free_func_cdecl(char *);
void __cdecl free_func_cdecl(double);
+typedef void void_fun_t();
+typedef void __cdecl cdecl_fun_t();
// Pointers to member functions
struct S {
@@ -38,10 +43,17 @@ struct S {
void __cdecl member_cdecl2(); // expected-note {{previous declaration is here}}
void __thiscall member_thiscall1();
void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
-
+
+ // Typedefs carrying the __cdecl convention are adjusted to __thiscall.
+ void_fun_t member_typedef_default; // expected-note {{previous declaration is here}}
+ cdecl_fun_t member_typedef_cdecl1; // expected-note {{previous declaration is here}}
+ cdecl_fun_t __cdecl member_typedef_cdecl2;
+ void_fun_t __stdcall member_typedef_stdcall;
+
// Static member functions can't be __thiscall
static void static_member_default1();
- static void static_member_default2(); // expected-note {{previous declaration is here}}
+ static void static_member_default2();
+ static void static_member_default3(); // expected-note {{previous declaration is here}}
static void __cdecl static_member_cdecl1();
static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}}
static void __stdcall static_member_stdcall1();
@@ -58,29 +70,124 @@ struct S {
void __cdecl S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __thiscall S::member_default2() {}
+void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
+void __cdecl S::member_typedef_cdecl1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
+void __cdecl S::member_typedef_cdecl2() {}
+void __stdcall S::member_typedef_stdcall() {}
+
void S::member_cdecl1() {}
void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}}
void S::member_thiscall1() {}
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
-void __cdecl S::static_member_default1() {}
-void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
+void S::static_member_default1() {}
+void __cdecl S::static_member_default2() {}
+void __stdcall S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void S::static_member_cdecl1() {}
void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
-void __cdecl S::member_variadic_default(int x, ...) {
- (void)x;
+void __cdecl S::member_variadic_default(int x, ...) { (void)x; }
+void S::member_variadic_cdecl(int x, ...) { (void)x; }
+
+void __cdecl S::static_member_variadic_default(int x, ...) { (void)x; }
+void S::static_member_variadic_cdecl(int x, ...) { (void)x; }
+
+// Declare a template using a calling convention.
+template <class CharT> inline int __cdecl mystrlen(const CharT *str) {
+ int i;
+ for (i = 0; str[i]; i++) { }
+ return i;
}
-void S::member_variadic_cdecl(int x, ...) {
- (void)x;
+extern int sse_strlen(const char *str);
+template <> inline int __cdecl mystrlen(const char *str) {
+ return sse_strlen(str);
+}
+void use_tmpl(const char *str, const int *ints) {
+ mystrlen(str);
+ mystrlen(ints);
+}
+
+struct MixedCCStaticOverload {
+ static void overloaded(int a);
+ static void __stdcall overloaded(short a);
+};
+
+void MixedCCStaticOverload::overloaded(int a) {}
+void MixedCCStaticOverload::overloaded(short a) {}
+
+// Friend function decls are cdecl by default, not thiscall. Friend method
+// decls should always be redeclarations, because the class cannot be
+// incomplete.
+struct FriendClass {
+ void friend_method() {}
+};
+void __stdcall friend_stdcall1() {}
+class MakeFriendDecls {
+ int x;
+ friend void FriendClass::friend_method();
+ friend void friend_default();
+ friend void friend_stdcall1();
+ friend void __stdcall friend_stdcall2();
+ friend void friend_stdcall3(); // expected-note {{previous declaration is here}}
+};
+void friend_default() {}
+void __stdcall friend_stdcall3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
+void __stdcall friend_stdcall2() {}
+
+// Test functions with multiple attributes.
+void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attribute(int x);
+void multi_attribute(int x) { __builtin_unreachable(); }
+
+
+// expected-error@+2 {{stdcall and cdecl attributes are not compatible}}
+// expected-error@+1 {{fastcall and cdecl attributes are not compatible}}
+void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x);
+
+template <typename T> void __stdcall StdcallTemplate(T) {}
+template <> void StdcallTemplate<int>(int) {}
+template <> void __stdcall StdcallTemplate<short>(short) {}
+
+// FIXME: Note the template, not the implicit instantiation.
+// expected-error@+2 {{function declared 'cdecl' here was previously declared 'stdcall}}
+// expected-note@+1 {{previous declaration is here}}
+template <> void __cdecl StdcallTemplate<long>(long) {}
+
+struct ExactlyInt {
+ template <typename T> static int cast_to_int(T) {
+ return T::this_is_not_an_int();
+ }
+};
+template <> inline int ExactlyInt::cast_to_int<int>(int x) { return x; }
+
+namespace test2 {
+ class foo {
+ template <typename T> void bar(T v);
+ };
+ extern template void foo::bar(const void *);
}
-void __cdecl S::static_member_variadic_default(int x, ...) {
- (void)x;
+namespace test3 {
+ struct foo {
+ typedef void bar();
+ };
+ bool zed(foo::bar *);
+ void bah() {}
+ void baz() { zed(bah); }
}
-void S::static_member_variadic_cdecl(int x, ...) {
- (void)x;
+
+namespace test4 {
+ class foo {
+ template <typename T> static void bar(T v);
+ };
+ extern template void foo::bar(const void *);
}
+namespace test5 {
+ template <class T>
+ class valarray {
+ void bar();
+ };
+ extern template void valarray<int>::bar();
+}
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index ccde3dcfb312..d6e85d285dd1 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -37,6 +37,14 @@ struct C {
// expected-error {{expected ')'}} expected-note {{to match this '('}}
};
+namespace PR16529 {
+ struct U {};
+ template <typename T> struct S {
+ static decltype(T{}, U{}) &f();
+ };
+ U &r = S<int>::f();
+}
+
template<typename>
class conditional {
};
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index 668c60036662..7ef6f7778529 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}} \
+class Base { // expected-error {{cannot define the implicit copy assignment operator for 'Base', because non-static reference member 'ref' can't use copy assignment operator}} \
// expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}}
int &ref; // expected-note {{declared here}} \
// expected-note{{reference member 'ref' will never be initialized}}
};
-class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}} \
+class X : Base { // // expected-error {{cannot define the implicit copy assignment operator for 'X', because non-static const member 'cint' can't use copy assignment operator}} \
// expected-note{{assignment operator for 'Base' first required here}}
public:
X();
@@ -73,7 +73,7 @@ void i() {
// Test5
-class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}}
+class E1 { // expected-error{{cannot define the implicit copy assignment operator for 'E1', because non-static const member 'a' can't use copy assignment operator}}
public:
const int a; // expected-note{{declared here}}
@@ -101,7 +101,7 @@ namespace ProtectedCheck {
X x;
};
- void f(Z z) { z = z; } // expected-note{{implicit default copy assignment operator}}
+ void f(Z z) { z = z; } // expected-note{{implicit copy assignment operator}}
}
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index c8c197e153d4..b661776b6ef5 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -21,7 +21,7 @@ struct X {
X(int);
};
-void j(X x = 17);
+void j(X x = 17); // expected-note{{'::j' declared here}}
struct Y { // expected-note 2{{candidate}}
explicit Y(int);
@@ -46,8 +46,13 @@ int l () {
int i () {
void j (int f = 4);
{
- void j (int f); // expected-note{{'j' declared here}}
- j(); // expected-error{{too few arguments to function call, single argument 'f' was not specified}}
+ void j (int f);
+ j(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::j'?}}
+ }
+ void jj (int f = 4);
+ {
+ void jj (int f); // expected-note{{'jj' declared here}}
+ jj(); // expected-error{{too few arguments to function call, single argument 'f' was not specified}}
}
}
diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp
new file mode 100644
index 000000000000..0335a80ffc5d
--- /dev/null
+++ b/test/SemaCXX/deprecated.cpp
@@ -0,0 +1,67 @@
+// 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++1y %s -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
+
+#include "Inputs/register.h"
+
+void f() throw();
+void g() throw(int);
+void h() throw(...);
+#if __cplusplus >= 201103L
+// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept' instead}}
+// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept(false)' instead}}
+// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept(false)' instead}}
+#endif
+
+void stuff() {
+ register int n;
+#if __cplusplus >= 201103L && !defined(NO_DEPRECATED_FLAGS)
+ // expected-warning@-2 {{'register' storage class specifier is deprecated}}
+#endif
+
+ register int m asm("rbx"); // no-warning
+
+ int k = to_int(n); // no-warning
+
+ bool b;
+ ++b; // expected-warning {{incrementing expression of type bool is deprecated}}
+
+ // FIXME: This is ill-formed in C++11.
+ char *p = "foo"; // expected-warning {{conversion from string literal to 'char *' is deprecated}}
+}
+
+struct S { int n; };
+struct T : private S {
+ S::n;
+#if __cplusplus < 201103L
+ // expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
+#else
+ // expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
+#endif
+};
+
+#if __cplusplus >= 201103L
+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}}
+
+ 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}}
+
+ 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}}
+}
+#endif
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index f3c6ab0b737f..e511be011662 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -363,3 +363,7 @@ namespace PR7900 {
(&b)->~A(); // expected-error{{destructor type 'PR7900::A' in object destruction expression does not match the type 'PR7900::B' of the object being destroyed}}
}
}
+
+namespace PR16892 {
+ auto p = &A::~A; // expected-error{{taking the address of a destructor}}
+}
diff --git a/test/SemaCXX/dynamic-cast.cpp b/test/SemaCXX/dynamic-cast.cpp
index b73e8c57b9f3..b605194ecd64 100644
--- a/test/SemaCXX/dynamic-cast.cpp
+++ b/test/SemaCXX/dynamic-cast.cpp
@@ -37,6 +37,8 @@ void basic_bad()
(void)dynamic_cast<Incomplete*>((A*)0); // expected-error {{'Incomplete' is an incomplete type}}
// incomplete -> ptr
(void)dynamic_cast<A*>((Incomplete*)0); // expected-error {{'Incomplete' is an incomplete type}}
+ // rvalue -> lvalue
+ (void)dynamic_cast<A&>(A()); // expected-error {{dynamic_cast from rvalue to reference type 'A &'}}
}
void same()
diff --git a/test/SemaCXX/enum-increment.cpp b/test/SemaCXX/enum-increment.cpp
new file mode 100644
index 000000000000..dc1a921852e6
--- /dev/null
+++ b/test/SemaCXX/enum-increment.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+
+enum A { A1, A2, A3 };
+void test() {
+ A a;
+ a++; // expected-error{{cannot increment expression of enum type 'A'}}
+ a--; // expected-error{{cannot decrement expression of enum type 'A'}}
+ ++a; // expected-error{{cannot increment expression of enum type 'A'}}
+ --a; // expected-error{{cannot decrement expression of enum type 'A'}}
+}
+
+enum B {B1, B2};
+inline B &operator++ (B &b) { b = B((int)b+1); return b; }
+inline B operator++ (B &b, int) { B ret = b; ++b; return b; }
+
+void foo(enum B b) { ++b; b++; }
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index d01000d22bb4..b4aad18b17c9 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -266,3 +266,33 @@ namespace PR15633 {
struct B { enum class E; };
template<typename T> enum class B::E { e }; // expected-error {{enumeration cannot be a template}}
}
+
+namespace PR16900 {
+ enum class A;
+ A f(A a) { return -a; } // expected-error {{invalid argument type 'PR16900::A' to unary expression}}
+}
+
+namespace rdar15124329 {
+ enum class B : bool { F, T };
+
+ const rdar15124329::B T1 = B::T;
+ typedef B C; const C T2 = B::T;
+
+ static_assert(T1 != B::F, "");
+ static_assert(T2 == B::T, "");
+}
+
+namespace PR18044 {
+ enum class E { a };
+
+ int E::e = 0; // expected-error {{does not refer into a class}}
+ void E::f() {} // expected-error {{does not refer into a class}}
+ struct E::S {}; // expected-error {{no struct named 'S'}}
+ struct T : E::S {}; // expected-error {{expected class name}}
+ enum E::E {}; // expected-error {{no enum named 'E'}}
+ int E::*p; // expected-error {{does not point into a class}}
+ using E::f; // expected-error {{no member named 'f'}}
+
+ using E::a; // ok!
+ E b = a;
+}
diff --git a/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp
index e9da38f558d3..7da9a96d6054 100644
--- a/test/SemaCXX/enum-unscoped-nonexistent.cpp
+++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp
@@ -6,7 +6,7 @@ struct Base {
template<typename T> struct S : Base {
enum E : int;
constexpr int f() const;
- constexpr int g() const; // expected-note {{declared here}}
+ constexpr int g() const;
void h();
};
template<> enum S<char>::E : int {}; // expected-note {{enum 'S<char>::E' was explicitly specialized here}}
@@ -23,7 +23,7 @@ static_assert(S<int>().f() == 1, "");
// The unqualified-id here names a member of the current instantiation, which
// bizarrely might not exist in some instantiations.
template<typename T> constexpr int S<T>::g() const { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}}
-static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}}
+static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}}
static_assert(S<short>().g() == 2, "");
static_assert(S<long>().g() == 8, "");
diff --git a/test/SemaCXX/err_init_conversion_failed.cpp b/test/SemaCXX/err_init_conversion_failed.cpp
new file mode 100644
index 000000000000..0652e7a9ea6a
--- /dev/null
+++ b/test/SemaCXX/err_init_conversion_failed.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void test0() {
+ char variable = (void)0;
+ // expected-error@-1{{cannot initialize a variable}}
+}
+
+void test1(int x = (void)0) {}
+ // expected-error@-1{{cannot initialize a parameter}}
+ // expected-note@-2{{here}}
+
+int test2() {
+ return (void)0;
+ // expected-error@-1{{cannot initialize return object}}
+}
+
+struct S4 {
+ S4() : x((void)0) {};
+ // expected-error@-1{{cannot initialize a member subobject}}
+ int x;
+};
+
+void test5() {
+ int foo[2] = {1, (void)0};
+ // expected-error@-1{{cannot initialize an array element}}
+}
+
+void test6() {
+ new int((void)0);
+ // expected-error@-1{{cannot initialize a new value}}
+}
+
+typedef short short2 __attribute__ ((__vector_size__ (2)));
+void test10() {
+ short2 V = { (void)0 };
+ // expected-error@-1{{cannot initialize a vector element}}
+}
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+void test14(const float2 in, const float2 out) {
+ const float4 V = (float4){ in, out };
+ // expected-error@-1{{cannot initialize a compound literal initializer}}
+}
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
index 5ce2cf19132c..1c4d7704511b 100644
--- a/test/SemaCXX/explicit.cpp
+++ b/test/SemaCXX/explicit.cpp
@@ -4,11 +4,11 @@ struct A {
A(int);
};
-struct B {
+struct B { // expected-note+ {{candidate}}
explicit B(int);
};
-B::B(int) { }
+B::B(int) { } // expected-note+ {{here}}
struct C {
void f(const A&);
@@ -18,6 +18,22 @@ struct C {
void f(C c) {
c.f(10);
}
+
+A a0 = 0;
+A a1(0);
+A &&a2 = 0;
+A &&a3(0);
+A a4{0};
+A &&a5 = {0};
+A &&a6{0};
+
+B b0 = 0; // expected-error {{no viable conversion}}
+B b1(0);
+B &&b2 = 0; // expected-error {{could not bind}}
+B &&b3(0); // expected-error {{could not bind}}
+B b4{0};
+B &&b5 = {0}; // expected-error {{chosen constructor is explicit}}
+B &&b6{0};
}
namespace Conversion {
@@ -40,12 +56,11 @@ namespace Conversion {
void testExplicit()
{
// Taken from 12.3.2p2
- class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Z' to 'const Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Z' to 'Y &&' for 1st argument}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Z' to 'const Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Z' to 'Y &&' for 1st argument}}
+ class X { X(); }; // expected-note+ {{candidate constructor}}
+ class Y { }; // expected-note+ {{candidate constructor (the implicit}}
struct Z {
+ explicit operator X() const;
explicit operator Y() const;
explicit operator int() const;
};
@@ -53,6 +68,7 @@ namespace Conversion {
Z z;
// 13.3.1.4p1 & 8.5p16:
Y y2 = z; // expected-error {{no viable conversion from 'Z' to 'Y'}}
+ Y y2b(z);
Y y3 = (Y)z;
Y y4 = Y(z);
Y y5 = static_cast<Y>(z);
@@ -63,7 +79,24 @@ namespace Conversion {
int i4(z);
// 13.3.1.6p1 & 8.5.3p5:
const Y& y6 = z; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
- const int& y7(z);
+ const int& y7 = z; // expected-error {{no viable conversion from 'Z' to 'const int'}}
+ const Y& y8(z);
+ const int& y9(z);
+
+ // Y is an aggregate, so aggregate-initialization is performed and the
+ // conversion function is not considered.
+ const Y y10{z}; // expected-error {{excess elements}}
+ const Y& y11{z}; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
+ const int& y12{z};
+
+ // X is not an aggregate, so constructors are considered.
+ // However, by 13.3.3.1/4, only standard conversion sequences and
+ // ellipsis conversion sequences are considered here, so this is not
+ // allowed.
+ // FIXME: It's not really clear that this is a sensible restriction for this
+ // case. g++ allows this, EDG does not.
+ const X x1{z}; // expected-error {{no matching constructor}}
+ const X& x2{z}; // expected-error {{no matching constructor}}
}
void testBool() {
@@ -119,6 +152,40 @@ namespace Conversion {
// 6.5.3:
for (;b;) {}
for (;n;) {}
+
+ // 13.3.1.5p1:
+ bool direct1(b);
+ bool direct2(n);
+ int direct3(b);
+ int direct4(n); // expected-error {{no viable conversion}}
+ const bool &direct5(b);
+ const bool &direct6(n);
+ const int &direct7(b);
+ const int &direct8(n); // expected-error {{no viable conversion}}
+ bool directList1{b};
+ bool directList2{n};
+ int directList3{b};
+ int directList4{n}; // expected-error {{no viable conversion}}
+ const bool &directList5{b};
+ const bool &directList6{n};
+ const int &directList7{b};
+ const int &directList8{n}; // expected-error {{no viable conversion}}
+ bool copy1 = b;
+ bool copy2 = n; // expected-error {{no viable conversion}}
+ int copy3 = b;
+ int copy4 = n; // expected-error {{no viable conversion}}
+ const bool &copy5 = b;
+ const bool &copy6 = n; // expected-error {{no viable conversion}}
+ const int &copy7 = b;
+ const int &copy8 = n; // expected-error {{no viable conversion}}
+ bool copyList1 = {b};
+ bool copyList2 = {n}; // expected-error {{no viable conversion}}
+ int copyList3 = {b};
+ int copyList4 = {n}; // expected-error {{no viable conversion}}
+ const bool &copyList5 = {b};
+ const bool &copyList6 = {n}; // expected-error {{no viable conversion}}
+ const int &copyList7 = {b};
+ const int &copyList8 = {n}; // expected-error {{no viable conversion}}
}
void testNew()
@@ -145,14 +212,14 @@ namespace Conversion {
operator int*();
};
struct NotPtr {
- explicit operator int*();
+ explicit operator int*(); // expected-note {{conversion}}
};
Ptr p;
NotPtr np;
delete p;
- delete np; // expected-error {{cannot delete expression of type 'NotPtr'}}
+ delete np; // expected-error {{converting delete expression from type 'NotPtr' to type 'int *' invokes an explicit conversion function}}
}
void testFunctionPointer()
@@ -173,3 +240,9 @@ namespace Conversion {
nfp(1); // expected-error {{type 'NotFP' does not provide a call operator}}
}
}
+
+namespace pr8264 {
+ struct Test {
+ explicit explicit Test(int x); // expected-warning{{duplicate 'explicit' declaration specifier}}
+ };
+}
diff --git a/test/SemaCXX/expression-traits.cpp b/test/SemaCXX/expression-traits.cpp
index 2767d4a159c7..3a00687f1125 100644
--- a/test/SemaCXX/expression-traits.cpp
+++ b/test/SemaCXX/expression-traits.cpp
@@ -189,12 +189,12 @@ struct Class : BaseClass
static int& NestedFuncTemplate() { return variable; } // expected-note{{possible target for call}}
template <class T>
- int& NestedMemfunTemplate() { return variable; }
+ int& NestedMemfunTemplate() { return variable; } // expected-note{{possible target for call}}
int operator*() const;
template <class T>
- int operator+(T) const;
+ int operator+(T) const; // expected-note{{possible target for call}}
int NonstaticMemberFunction();
static int StaticMemberFunction();
diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp
index c55b10d9d6e3..dfbf38667c5e 100644
--- a/test/SemaCXX/extern-c.cpp
+++ b/test/SemaCXX/extern-c.cpp
@@ -2,25 +2,25 @@
namespace test1 {
extern "C" {
- void f() {
- void test1_g(int); // expected-note {{previous declaration is here}}
+ void test1_f() {
+ void test1_g(int);
}
}
}
-int test1_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+int test1_g(int);
namespace test2 {
extern "C" {
- void f() {
- extern int test2_x; // expected-note {{previous definition is here}}
+ void test2_f() {
+ extern int test2_x; // expected-note {{declared with C language linkage here}}
}
}
}
-float test2_x; // expected-error {{redefinition of 'test2_x' with a different type: 'float' vs 'int'}}
+float test2_x; // expected-error {{declaration of 'test2_x' in global scope conflicts with declaration with C language linkage}}
namespace test3 {
extern "C" {
- void f() {
+ void test3_f() {
extern int test3_b; // expected-note {{previous definition is here}}
}
}
@@ -29,20 +29,40 @@ namespace test3 {
}
}
+namespace N {
+ extern "C" {
+ void test4_f() {
+ extern int test4_b; // expected-note {{declared with C language linkage here}}
+ }
+ }
+}
+static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
+
extern "C" {
- void test4_f() {
- extern int test4_b; // expected-note {{previous definition is here}}
+ void test4c_f() {
+ extern int test4_c; // expected-note {{previous}}
+ }
+}
+static float test4_c; // expected-error {{redefinition of 'test4_c' with a different type: 'float' vs 'int'}}
+
+namespace N {
+ extern "C" {
+ void test5_f() {
+ extern int test5_b; // expected-note {{declared with C language linkage here}}
+ }
}
}
-static float test4_b; // expected-error {{redefinition of 'test4_b' with a different type: 'float' vs 'int'}}
+extern "C" {
+ static float test5_b; // expected-error {{declaration of 'test5_b' in global scope conflicts with declaration with C language linkage}}
+}
extern "C" {
- void test5_f() {
- extern int test5_b; // expected-note {{previous definition is here}}
+ void test5c_f() {
+ extern int test5_c; // expected-note {{previous}}
}
}
extern "C" {
- static float test5_b; // expected-error {{redefinition of 'test5_b' with a different type: 'float' vs 'int'}}
+ static float test5_c; // expected-error {{redefinition of 'test5_c' with a different type: 'float' vs 'int'}}
}
extern "C" {
@@ -56,3 +76,131 @@ namespace foo {
extern float test6_b;
}
}
+
+namespace linkage {
+ namespace redecl {
+ extern "C" {
+ static void linkage_redecl();
+ static void linkage_redecl(int);
+ void linkage_redecl(); // ok, still not extern "C"
+ void linkage_redecl(int); // ok, still not extern "C"
+ void linkage_redecl(float); // expected-note {{previous}}
+ void linkage_redecl(double); // expected-error {{conflicting types}}
+ }
+ }
+ namespace from_outer {
+ void linkage_from_outer_1(); // expected-note {{previous}}
+ void linkage_from_outer_2(); // expected-note {{previous}}
+ extern "C" {
+ void linkage_from_outer_1(int);
+ void linkage_from_outer_1(); // expected-error {{different language linkage}}
+ void linkage_from_outer_2(); // expected-error {{different language linkage}}
+ }
+ }
+ namespace mixed {
+ extern "C" {
+ void linkage_mixed_1();
+ static void linkage_mixed_1(int);
+
+ static void linkage_mixed_2(int);
+ void linkage_mixed_2();
+ }
+ }
+ namespace across_scopes {
+ namespace X {
+ extern "C" void linkage_across_scopes_f() {
+ void linkage_across_scopes_g(); // expected-note {{previous}}
+ }
+ }
+ namespace Y {
+ extern "C" void linkage_across_scopes_g(int); // expected-error {{conflicting}}
+ }
+ }
+}
+
+int lookup_in_global_f; // expected-note {{here}}
+namespace lookup_in_global {
+ void lookup_in_global_f();
+ void lookup_in_global_g();
+ extern "C" {
+ void lookup_in_global_f(int); // expected-error {{conflicts with declaration in global scope}}
+ void lookup_in_global_g(int); // expected-note {{here}}
+ }
+}
+int lookup_in_global_g; // expected-error {{conflicts with declaration with C language linkage}}
+
+namespace N1 {
+ extern "C" int different_kind_1; // expected-note {{here}}
+ extern "C" void different_kind_2(); // expected-note {{here}}
+}
+namespace N2 {
+ extern "C" void different_kind_1(); // expected-error {{different kind of symbol}}
+ extern "C" int different_kind_2; // expected-error {{different kind of symbol}}
+}
+
+// We allow all these even though the standard says they are ill-formed.
+extern "C" {
+ struct stat {}; // expected-warning{{empty struct has size 0 in C, size 1 in C++}}
+ void stat(struct stat);
+}
+namespace X {
+ extern "C" {
+ void stat(struct ::stat);
+ }
+}
+int stat(int *p);
+void global_fn_vs_extern_c_var_1();
+namespace X {
+ extern "C" int global_fn_vs_extern_c_var_1;
+ extern "C" int global_fn_vs_extern_c_var_2;
+}
+void global_fn_vs_extern_c_var_2();
+void global_fn_vs_extern_c_fn_1();
+namespace X {
+ extern "C" int global_fn_vs_extern_c_fn_1(int);
+ extern "C" int global_fn_vs_extern_c_fn_2(int);
+}
+void global_fn_vs_extern_c_fn_2();
+extern "C" void name_with_using_decl_1(int);
+namespace using_decl {
+ void name_with_using_decl_1();
+ void name_with_using_decl_2();
+ void name_with_using_decl_3();
+}
+using using_decl::name_with_using_decl_1;
+using using_decl::name_with_using_decl_2;
+extern "C" void name_with_using_decl_2(int);
+extern "C" void name_with_using_decl_3(int);
+using using_decl::name_with_using_decl_3;
+
+// We do not allow a global variable and an extern "C" function to have the same
+// name, because such entities may have the same mangled name.
+int global_var_vs_extern_c_fn_1; // expected-note {{here}}
+namespace X {
+ extern "C" void global_var_vs_extern_c_fn_1(); // expected-error {{conflicts with declaration in global scope}}
+ extern "C" void global_var_vs_extern_c_fn_2(); // expected-note {{here}}
+}
+int global_var_vs_extern_c_fn_2; // expected-error {{conflicts with declaration with C language linkage}}
+int global_var_vs_extern_c_var_1; // expected-note {{here}}
+namespace X {
+ extern "C" double global_var_vs_extern_c_var_1; // expected-error {{conflicts with declaration in global scope}}
+ extern "C" double global_var_vs_extern_c_var_2; // expected-note {{here}}
+}
+int global_var_vs_extern_c_var_2; // expected-error {{conflicts with declaration with C language linkage}}
+
+template <class T> struct pr5065_n1 {};
+extern "C" {
+ union pr5065_1 {}; // expected-warning{{empty union has size 0 in C, size 1 in C++}}
+ struct pr5065_2 { int: 0; }; // expected-warning{{struct has size 0 in C, size 1 in C++}}
+ struct pr5065_3 {}; // expected-warning{{empty struct has size 0 in C, size 1 in C++}}
+ struct pr5065_4 { // expected-warning{{empty struct has size 0 in C, size 1 in C++}}
+ struct Inner {}; // expected-warning{{empty struct has size 0 in C, size 1 in C++}}
+ };
+ // These should not warn
+ class pr5065_n3 {};
+ pr5065_n1<int> pr5065_v;
+ struct pr5065_n4 { void m() {} };
+ struct pr5065_n5 : public pr5065_3 {};
+ struct pr5065_n6 : public virtual pr5065_3 {};
+}
+struct pr5065_n7 {};
diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp
index e6c3132801f8..f287711eeb6a 100644
--- a/test/SemaCXX/flexible-array-test.cpp
+++ b/test/SemaCXX/flexible-array-test.cpp
@@ -66,4 +66,8 @@ struct Storage : StorageBase {
int data[];
};
+struct VirtStorage : virtual StorageBase {
+ int data[]; // expected-error {{flexible array member 'data' not allowed in struct which has a virtual base class}}
+};
+
}
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 953c98b4c818..b3cf9c326421 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace value_range_detail {
template<typename T>
@@ -180,3 +180,32 @@ namespace test4 {
for (y : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}}
}
}
+
+namespace test5 {
+ // Test error-recovery.
+ void f() {
+ for (auto x : undeclared_identifier) // expected-error {{undeclared identifier}}
+ for (auto y : x->foo)
+ y->bar();
+ for (auto x : 123) // expected-error {{no viable 'begin'}}
+ x->foo();
+ }
+}
+
+namespace test6 {
+ void foo(int arr[]) { // expected-note {{declared here}}
+ for (auto i : arr) { }
+ // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'int []' is treated as pointer type 'int *'}}
+ }
+
+ struct vector {
+ int *begin() { return 0; }
+ int *end() { return 0; }
+ };
+
+ void foo(vector arr[]) { // expected-note {{declared here}}
+ // Don't suggest to dereference arr.
+ for (auto i : arr) { }
+ // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'test6::vector []' is treated as pointer type 'test6::vector *'}}
+ }
+}
diff --git a/test/SemaCXX/format-strings-0x.cpp b/test/SemaCXX/format-strings-0x.cpp
index 7b3aef1ee5da..7e41c7fdbf9d 100644
--- a/test/SemaCXX/format-strings-0x.cpp
+++ b/test/SemaCXX/format-strings-0x.cpp
@@ -24,4 +24,8 @@ void f(char **sp, float *fp) {
\u1234\U0010fffe
%d)foo" // expected-warning {{more '%' conversions than data arguments}}
);
+
+ printf("init list: %d", { 0 }); // expected-error {{cannot pass initializer list to variadic function; expected type from format string was 'int'}}
+ printf("void: %d", f(sp, fp)); // expected-error {{cannot pass expression of type 'void' to variadic function; expected type from format string was 'int'}}
+ printf(0, { 0 }); // expected-error {{cannot pass initializer list to variadic function}}
}
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index b401a06a7ecf..aed2ab2c7d0c 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -44,7 +44,7 @@ namespace test2 {
// PR5134
namespace test3 {
class Foo {
- friend const int getInt(int inInt = 0);
+ friend const int getInt(int inInt = 0) {}
};
}
@@ -134,7 +134,7 @@ namespace test6_3 {
namespace test7 {
extern "C" {
class X {
- friend int f() { return 42; }
+ friend int test7_f() { return 42; }
};
}
}
@@ -154,3 +154,137 @@ namespace test8 {
friend void B::f(); // expected-error {{cannot befriend target of using declaration}}
};
}
+
+// PR16423
+namespace test9 {
+ class C {
+ };
+ struct A {
+ friend void C::f(int, int, int) {} // expected-error {{no function named 'f' with type 'void (int, int, int)' was found in the specified scope}}
+ };
+}
+
+namespace test10 {
+ struct X {};
+ extern void f10_a();
+ extern void f10_a(X);
+ struct A {
+ friend void f10_a();
+ friend void f10_b();
+ friend void f10_c();
+ friend void f10_d();
+ friend void f10_a(X);
+ friend void f10_b(X);
+ friend void f10_c(X);
+ friend void f10_d(X);
+ };
+ extern void f10_b();
+ extern void f10_b(X);
+ struct B {
+ friend void f10_a();
+ friend void f10_b();
+ friend void f10_c();
+ friend void f10_d();
+ friend void f10_a(X);
+ friend void f10_b(X);
+ friend void f10_c(X);
+ friend void f10_d(X);
+ };
+ extern void f10_c();
+ extern void f10_c(X);
+
+ // FIXME: Give a better diagnostic for the case where a function exists but is
+ // not visible.
+ void g(X x) {
+ f10_a();
+ f10_b();
+ f10_c();
+ f10_d(); // expected-error {{undeclared identifier}}
+
+ ::test10::f10_a();
+ ::test10::f10_b();
+ ::test10::f10_c();
+ ::test10::f10_d(); // expected-error {{no member named 'f10_d'}}
+
+ f10_a(x);
+ f10_b(x);
+ f10_c(x);
+ f10_d(x); // PR16597: expected-error {{undeclared identifier}}
+
+ ::test10::f10_a(x);
+ ::test10::f10_b(x);
+ ::test10::f10_c(x);
+ ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}}
+ }
+
+ struct Y : X {
+ friend void f10_d();
+ friend void f10_d(X);
+ };
+
+ struct Z {
+ operator X();
+ friend void f10_d();
+ friend void f10_d(X);
+ };
+
+ void g(X x, Y y, Z z) {
+ f10_d(); // expected-error {{undeclared identifier}}
+ ::test10::f10_d(); // expected-error {{no member named 'f10_d'}}
+
+ // f10_d is visible to ADL in the second and third cases.
+ f10_d(x); // expected-error {{undeclared identifier}}
+ f10_d(y);
+ f10_d(z);
+
+ // No ADL here.
+ ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}}
+ ::test10::f10_d(y); // expected-error {{no type named 'f10_d'}}
+ ::test10::f10_d(z); // expected-error {{no type named 'f10_d'}}
+ }
+
+ void local_externs(X x, Y y) {
+ extern void f10_d();
+ extern void f10_d(X);
+ f10_d();
+ f10_d(x);
+ // FIXME: This lookup should fail, because the local extern declaration
+ // should suppress ADL.
+ f10_d(y);
+ {
+ int f10_d;
+ f10_d(); // expected-error {{not a function}}
+ f10_d(x); // expected-error {{not a function}}
+ f10_d(y); // expected-error {{not a function}}
+ }
+ }
+
+ void i(X x, Y y) {
+ f10_d(); // expected-error {{undeclared identifier}}
+ f10_d(x); // expected-error {{undeclared identifier}}
+ f10_d(y);
+ }
+
+ struct C {
+ friend void f10_d();
+ friend void f10_d(X);
+ };
+
+ void j(X x, Y y) {
+ f10_d(); // expected-error {{undeclared identifier}}
+ f10_d(x); // expected-error {{undeclared identifier}}
+ f10_d(y);
+ }
+
+ extern void f10_d();
+ extern void f10_d(X);
+ void k(X x, Y y, Z z) {
+ // All OK now.
+ f10_d();
+ f10_d(x);
+ ::test10::f10_d();
+ ::test10::f10_d(x);
+ ::test10::f10_d(y);
+ ::test10::f10_d(z);
+ }
+}
diff --git a/test/SemaCXX/function-pointer-arguments.cpp b/test/SemaCXX/function-pointer-arguments.cpp
new file mode 100644
index 000000000000..9f3fb0a4ec20
--- /dev/null
+++ b/test/SemaCXX/function-pointer-arguments.cpp
@@ -0,0 +1,52 @@
+//RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR16570 {
+ int f1(int, int);
+ int f2(const int, int);
+ int f3(int&, int);
+ int f4(const int&, int);
+
+ void good() {
+ int(*g1)(int, int) = f1;
+ int(*g2)(const int, int) = f1;
+ int(*g3)(volatile int, int) = f1;
+ int(*g4)(int, int) = f2;
+ int(*g5)(const int, int) = f2;
+ int(*g6)(volatile int, int) = f2;
+ int(*g7)(int&, int) = f3;
+ int(*g8)(const int&, int) = f4;
+ }
+
+ void bad() {
+ void (*g1)(int, int) = f1;
+ // expected-error@-1 {{different return type ('void' vs 'int'}}
+ const int (*g2)(int, int) = f1;
+ // expected-error@-1 {{different return type ('const int' vs 'int')}}
+
+ int (*g3)(char, int) = f1;
+ // expected-error@-1 {{type mismatch at 1st parameter ('char' vs 'int')}}
+ int (*g4)(int, char) = f1;
+ // expected-error@-1 {{type mismatch at 2nd parameter ('char' vs 'int')}}
+
+ int (*g5)(int) = f1;
+ // expected-error@-1 {{different number of parameters (1 vs 2)}}
+
+ int (*g6)(int, int, int) = f1;
+ // expected-error@-1 {{different number of parameters (3 vs 2)}}
+
+ int (*g7)(const int, char) = f1;
+ // expected-error@-1 {{type mismatch at 2nd parameter ('char' vs 'int')}}
+ int (*g8)(int, char) = f2;
+ // expected-error@-1 {{type mismatch at 2nd parameter ('char' vs 'int')}}
+ int (*g9)(const int&, char) = f3;
+ // expected-error@-1 {{type mismatch at 1st parameter ('const int &' vs 'int &')}}
+ int (*g10)(int&, char) = f4;
+ // expected-error@-1 {{type mismatch at 1st parameter ('int &' vs 'const int &')}}
+ }
+
+ typedef void (*F)(const char * __restrict__, int);
+ void g(const char *, unsigned);
+ F f = g;
+ // expected-error@-1 {{type mismatch at 2nd parameter ('int' vs 'unsigned int')}}
+
+}
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
index b9d1f23af402..2bc0d90cd627 100644
--- a/test/SemaCXX/function-redecl.cpp
+++ b/test/SemaCXX/function-redecl.cpp
@@ -4,22 +4,24 @@ int foo(int);
namespace N {
void f1() {
void foo(int); // okay
+ void bar(int); // expected-note 2{{previous declaration is here}}
}
- // FIXME: we shouldn't even need this declaration to detect errors
- // below.
- void foo(int); // expected-note{{previous declaration is here}}
+ void foo(int); // expected-note 2{{previous declaration is here}}
void f2() {
- int foo(int); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+ int foo(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+ int bar(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+ int baz(int); // expected-note {{previous declaration is here}}
{
int foo;
+ int bar;
+ int baz;
{
- // FIXME: should diagnose this because it's incompatible with
- // N::foo. However, name lookup isn't properly "skipping" the
- // "int foo" above.
- float foo(int);
+ float foo(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+ float bar(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+ float baz(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
}
}
}
diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp
index ccb57472925d..613ac9b200f1 100644
--- a/test/SemaCXX/function-type-qual.cpp
+++ b/test/SemaCXX/function-type-qual.cpp
@@ -29,3 +29,11 @@ cfn C::*mpg;
// Don't crash!
void (PR14171)() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+
+// Test template instantiation of decayed array types. Not really related to
+// type quals.
+template <typename T> void arrayDecay(const T a[]) { }
+void instantiateArrayDecay() {
+ int a[1];
+ arrayDecay(a);
+}
diff --git a/test/SemaCXX/gnu-flags.cpp b/test/SemaCXX/gnu-flags.cpp
new file mode 100644
index 000000000000..05770c53704e
--- /dev/null
+++ b/test/SemaCXX/gnu-flags.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wno-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \
+// RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \
+// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \
+// RUN: -Wgnu-empty-struct
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \
+// RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \
+// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \
+// RUN: -Wno-gnu-empty-struct
+// Additional disabled tests:
+// %clang_cc1 -fsyntax-only -verify %s -DANONYMOUSSTRUCT -Wno-gnu -Wgnu-anonymous-struct
+// %clang_cc1 -fsyntax-only -verify %s -DREDECLAREDCLASSMEMBER -Wno-gnu -Wredeclared-class-member
+// %clang_cc1 -fsyntax-only -verify %s -DFLEXIBLEARRAYUNIONMEMBER -Wno-gnu -Wgnu-flexible-array-union-member
+// %clang_cc1 -fsyntax-only -verify %s -DFOLDINGCONSTANT -Wno-gnu -Wgnu-folding-constant
+// %clang_cc1 -fsyntax-only -verify %s -DEMPTYSTRUCT -Wno-gnu -Wgnu-empty-struct
+
+#if NONE
+// expected-no-diagnostics
+#endif
+
+
+#if ALL || ANONYMOUSSTRUCT
+// expected-warning@+5 {{anonymous structs are a GNU extension}}
+#endif
+
+struct as {
+ int x;
+ struct {
+ int a;
+ float b;
+ };
+};
+
+
+#if ALL || REDECLAREDCLASSMEMBER
+// expected-note@+6 {{previous declaration is here}}
+// expected-warning@+6 {{class member cannot be redeclared}}
+#endif
+
+namespace rcm {
+ class A {
+ class X;
+ class X;
+ class X {};
+ };
+}
+
+
+#if ALL || FLEXIBLEARRAYUNIONMEMBER
+// expected-warning@+6 {{flexible array member 'c1' in a union is a GNU extension}}
+#endif
+
+struct faum {
+ int l;
+ union {
+ int c1[];
+ };
+};
+
+
+#if ALL || FOLDINGCONSTANT
+// expected-warning@+4 {{in-class initializer for static data member is not a constant expression; folding it to a constant is a GNU extension}}
+#endif
+
+struct fic {
+ static const int B = int(0.75 * 1000 * 1000);
+};
+
+
+#if ALL || EMPTYSTRUCT
+// expected-warning@+3 {{flexible array member 'a' in otherwise empty struct is a GNU extension}}
+#endif
+
+struct ofam {int a[];};
+
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index c80323ccd78a..39c6b1fc1320 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -16,7 +16,7 @@ void f() {
}
int a() {
- const int t=t; // expected-note {{declared here}}
+ const int t=t; // expected-note {{declared here}} expected-note {{read of object outside its lifetime}}
switch(1) { // expected-warning {{no case matching constant switch condition '1'}}
case t:; // expected-error {{not an integral constant expression}} expected-note {{initializer of 't' is not a constant expression}}
}
diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp
index f6082e5699cc..cd547f576459 100644
--- a/test/SemaCXX/implicit-virtual-member-functions.cpp
+++ b/test/SemaCXX/implicit-virtual-member-functions.cpp
@@ -9,7 +9,7 @@ struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
void operator delete (void *, int); // expected-note {{'operator delete' declared here}}
};
-void B::f() { // expected-note {{implicit default destructor for 'B' first required here}}
+void B::f() { // expected-note {{implicit destructor for 'B' first required here}}
}
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
@@ -17,13 +17,13 @@ struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
};
-C::C() { } // expected-note {{implicit default destructor for 'C' first required here}}
+C::C() { } // expected-note {{implicit destructor for 'C' first required here}}
struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
};
void f() {
- new D; // expected-note {{implicit default destructor for 'D' first required here}}
+ new D; // expected-note {{implicit destructor for 'D' first required here}}
}
diff --git a/test/SemaCXX/inherit.cpp b/test/SemaCXX/inherit.cpp
index a926c812514c..abeed9ab4755 100644
--- a/test/SemaCXX/inherit.cpp
+++ b/test/SemaCXX/inherit.cpp
@@ -30,3 +30,6 @@ typedef G_copy G_copy_3;
class H : G_copy, A, G_copy_2, // expected-error{{base class 'G_copy' (aka 'G') specified more than once as a direct base class}}
public G_copy_3 { }; // expected-error{{base class 'G_copy' (aka 'G') specified more than once as a direct base class}}
+
+struct J { char c; int i[]; };
+struct K : J { }; // expected-error{{base class 'J' has a flexible array member}}
diff --git a/test/SemaCXX/init-priority-attr.cpp b/test/SemaCXX/init-priority-attr.cpp
index 6facebf0d000..a91eb60ba96c 100644
--- a/test/SemaCXX/init-priority-attr.cpp
+++ b/test/SemaCXX/init-priority-attr.cpp
@@ -19,11 +19,11 @@ extern Two koo[];
Two foo __attribute__((init_priority(101))) ( 5, 6 );
-Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{attribute takes one argument}}
+Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{'init_priority' attribute takes one argument}}
Two coo[2] __attribute__((init_priority(3))); // expected-error {{init_priority attribute requires integer constant between 101 and 65535 inclusive}}
-Two koo[4] __attribute__((init_priority(1.13))); // expected-error {{'init_priority' attribute requires integer constant}}
+Two koo[4] __attribute__((init_priority(1.13))); // expected-error {{'init_priority' attribute requires an integer constant}}
Two func() __attribute__((init_priority(1001))); // expected-error {{can only use 'init_priority' attribute on file-scope definitions of objects of class type}}
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index a333f38530b3..e2904247c4b4 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++0x -Wno-unused-value -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -std=c++1y -Wno-unused-value -fsyntax-only -verify -fblocks %s
namespace std { class type_info; };
@@ -109,27 +110,30 @@ namespace PR12031 {
}
}
-namespace NullPtr {
+namespace Array {
int &f(int *p);
char &f(...);
void g() {
- int n = 0;
+ int n = -1;
[=] {
- char &k = f(n); // not a null pointer constant
+ int arr[n]; // VLA
} ();
- const int m = 0;
- [=] {
- int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ const int m = -1;
+ [] {
+ int arr[m]; // expected-error{{negative size}}
} ();
- [=] () -> bool {
- int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
- return &m == 0;
+ [&] {
+ int arr[m]; // expected-error{{negative size}}
+ } ();
+
+ [=] {
+ int arr[m]; // expected-error{{negative size}}
} ();
[m] {
- int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ int arr[m]; // expected-error{{negative size}}
} ();
}
}
@@ -240,3 +244,42 @@ namespace PR13854 {
namespace PR14518 {
auto f = [](void) { return __func__; }; // no-warning
}
+
+namespace PR16708 {
+ auto L = []() {
+ auto ret = 0;
+ return ret;
+ return 0;
+ };
+}
+
+namespace TypeDeduction {
+ struct S {};
+ void f() {
+ const S s {};
+ S &&t = [&] { return s; } ();
+#if __cplusplus <= 201103L
+ // expected-error@-2 {{drops qualifiers}}
+#else
+ S &&u = [&] () -> auto { return s; } ();
+#endif
+ }
+}
+
+
+namespace lambdas_in_NSDMIs {
+ template<class T>
+ struct L {
+ T t{};
+ T t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
+ };
+ L<int> l;
+
+ namespace non_template {
+ struct L {
+ int t = 0;
+ int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
+ };
+ L l;
+ }
+} \ No newline at end of file
diff --git a/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp b/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp
new file mode 100644
index 000000000000..17e1548ac50d
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify
+
+// This is a test for an egregious hack in Clang that works around
+// an issue with libstdc++-4.2's <tr1/hashtable> implementation.
+// The code in question returns 'false' from a function with a pointer
+// return type, which is ill-formed in C++11.
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+ namespace tr1 {
+ template<typename T> struct hashnode;
+ template<typename T> struct hashtable {
+ typedef hashnode<T> node;
+ node *find_node() {
+ // This is ill-formed in C++11, per core issue 903, but we accept
+ // it anyway in a system header.
+ return false;
+ }
+ };
+ }
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libstdcxx_pointer_return_false_hack.cpp"
+
+auto *test1 = std::tr1::hashtable<int>().find_node();
+
+void *test2() { return false; } // expected-error {{cannot initialize}}
+
+#endif
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
index 504df0d35c2d..1598d0e35a05 100644
--- a/test/SemaCXX/linkage-spec.cpp
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wretained-language-linkage -DW_RETAINED_LANGUAGE_LINKAGE %s
extern "C" {
extern "C" void f(int);
}
@@ -41,7 +42,7 @@ namespace pr5430 {
using namespace pr5430;
extern "C" void pr5430::func(void) { }
-// PR5404
+// PR5405
int f2(char *)
{
return 0;
@@ -55,6 +56,18 @@ extern "C"
}
}
+namespace PR5405 {
+ int f2b(char *) {
+ return 0;
+ }
+
+ extern "C" {
+ int f2b(int) {
+ return f2b((char *)0); // ok
+ }
+ }
+}
+
// PR6991
extern "C" typedef int (*PutcFunc_t)(int);
@@ -114,3 +127,49 @@ namespace pr14958 {
}
int js::ObjectClass;
}
+
+extern "C" void PR16167; // expected-error {{variable has incomplete type 'void'}}
+extern void PR16167_0; // expected-error {{variable has incomplete type 'void'}}
+
+// PR7927
+enum T_7927 {
+ E_7927
+};
+
+extern "C" void f_pr7927(int);
+
+namespace {
+ extern "C" void f_pr7927(int);
+
+ void foo_pr7927() {
+ f_pr7927(E_7927);
+ f_pr7927(0);
+ ::f_pr7927(E_7927);
+ ::f_pr7927(0);
+ }
+}
+
+void bar_pr7927() {
+ f_pr7927(E_7927);
+ f_pr7927(0);
+ ::f_pr7927(E_7927);
+ ::f_pr7927(0);
+}
+
+namespace PR17337 {
+ extern "C++" {
+ class Foo;
+ extern "C" int bar3(Foo *y);
+ class Foo {
+ int x;
+ friend int bar3(Foo *y);
+#ifdef W_RETAINED_LANGUAGE_LINKAGE
+// expected-note@-5 {{previous declaration is here}}
+// expected-warning@-3 {{retaining previous language linkage}}
+#endif
+ };
+ extern "C" int bar3(Foo *y) {
+ return y->x;
+ }
+ }
+}
diff --git a/test/SemaCXX/linkage2.cpp b/test/SemaCXX/linkage2.cpp
index 3cfa98138bab..075f5e70c247 100644
--- a/test/SemaCXX/linkage2.cpp
+++ b/test/SemaCXX/linkage2.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify -fmodules %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions -Wno-local-type-template-args %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions -Wno-local-type-template-args -fmodules %s
namespace test1 {
int x; // expected-note {{previous definition is here}}
@@ -65,7 +66,7 @@ namespace test6 {
get_future();
template <class _Rp>
struct shared_future<_Rp&> {
- shared_future(future<_Rp&>&& __f); // expected-warning {{rvalue references are a C++11 extension}}
+ shared_future(future<_Rp&>&& __f);
};
void f() {
typedef int T;
@@ -164,3 +165,51 @@ namespace test16 {
}
}
}
+
+namespace test17 {
+ namespace {
+ struct I {
+ };
+ }
+ template <typename T1, typename T2> void foo() {}
+ template <typename T, T x> void bar() {} // expected-note {{candidate function}}
+ inline void *g() {
+ struct L {
+ };
+ // foo<L, I>'s linkage should be the merge of UniqueExternalLinkage (or
+ // InternalLinkage in c++11) and VisibleNoLinkage. The correct answer is
+ // NoLinkage in both cases. This means that using foo<L, I> as a template
+ // argument should fail.
+ return reinterpret_cast<void*>(bar<typeof(foo<L, I>), foo<L, I> >); // expected-error {{reinterpret_cast cannot resolve overloaded function 'bar' to type 'void *}}
+ }
+ void h() {
+ g();
+ }
+}
+
+namespace test18 {
+ template <typename T> struct foo {
+ template <T *P> static void f() {}
+ static void *g() { return (void *)f<&x>; }
+ static T x;
+ };
+ template <typename T> T foo<T>::x;
+ inline void *f() {
+ struct S {
+ };
+ return foo<S>::g();
+ }
+ void *h() { return f(); }
+}
+
+extern "C" void pr16247_foo(int);
+static void pr16247_foo(double);
+void pr16247_foo(int) {}
+void pr16247_foo(double) {}
+
+namespace PR16247 {
+ extern "C" void pr16247_bar(int);
+ static void pr16247_bar(double);
+ void pr16247_bar(int) {}
+ void pr16247_bar(double) {}
+}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 515bcd43b2c0..239aecff815d 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -87,7 +87,7 @@ namespace test5 {
}
void test2(A &x) {
- x->A::foo<int>(); // expected-error {{'test5::A' is not a pointer}}
+ x->A::foo<int>(); // expected-error {{'test5::A' is not a pointer; maybe you meant to use '.'?}}
}
}
@@ -172,3 +172,55 @@ void f(int i) {
j = 0;
}
}
+
+namespace PR15045 {
+ class Cl0 {
+ public:
+ int a;
+ };
+
+ int f() {
+ Cl0 c;
+ return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}}
+ }
+
+ struct bar {
+ void func(); // expected-note {{'func' declared here}}
+ };
+
+ struct foo {
+ bar operator->(); // expected-note 2 {{'->' applied to return value of the operator->() declared here}}
+ };
+
+ template <class T> void call_func(T t) {
+ t->func(); // expected-error-re 2 {{member reference type 'PR15045::bar' is not a pointer$}} \
+ // expected-note {{did you mean to use '.' instead?}}
+ }
+
+ void test_arrow_on_non_pointer_records() {
+ bar e;
+ foo f;
+
+ // Show that recovery has happened by also triggering typo correction
+ e->Func(); // expected-error {{member reference type 'PR15045::bar' is not a pointer; maybe you meant to use '.'?}} \
+ // expected-error {{no member named 'Func' in 'PR15045::bar'; did you mean 'func'?}}
+
+ // Make sure a fixit isn't given in the case that the '->' isn't actually
+ // the problem (the problem is with the return value of an operator->).
+ f->func(); // expected-error-re {{member reference type 'PR15045::bar' is not a pointer$}}
+
+ call_func(e); // expected-note {{in instantiation of function template specialization 'PR15045::call_func<PR15045::bar>' requested here}}
+
+ call_func(f); // expected-note {{in instantiation of function template specialization 'PR15045::call_func<PR15045::foo>' requested here}}
+ }
+}
+
+namespace pr16676 {
+ struct S { int i; };
+ struct T { S* get_s(); };
+ int f(S* s) {
+ T t;
+ return t.get_s // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ .i; // expected-error {{member reference type 'pr16676::S *' is a pointer; maybe you meant to use '->'}}
+ }
+}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 19e8e7597e85..6e4fd5df5a08 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -89,3 +89,14 @@ namespace PR14838 {
const function &r; // expected-note {{reference member declared here}}
} af;
}
+
+namespace rdar14084171 {
+ struct Point { // expected-note 3 {{candidate constructor}}
+ double x;
+ double y;
+ };
+ struct Sprite {
+ Point location = Point(0,0); // expected-error {{no matching constructor for initialization of 'rdar14084171::Point'}}
+ };
+ void f(Sprite& x) { x = x; }
+}
diff --git a/test/SemaCXX/member-pointer-ms.cpp b/test/SemaCXX/member-pointer-ms.cpp
index 7dca12190584..aee8e2eca774 100644
--- a/test/SemaCXX/member-pointer-ms.cpp
+++ b/test/SemaCXX/member-pointer-ms.cpp
@@ -5,8 +5,6 @@
// 2012, which supports C++11 and static_assert. It should pass for both 64-bit
// and 32-bit x86.
//
-// expected-no-diagnostics
-
// Test the size of various member pointer combinations:
// - complete and incomplete
// - single, multiple, and virtual inheritance (and unspecified for incomplete)
@@ -165,3 +163,6 @@ struct MemPtrInTemplate {
int T::*data_ptr;
void (T::*func_ptr)();
};
+
+int Virtual::*CastTest = reinterpret_cast<int Virtual::*>(&AA::x);
+ // expected-error@-1 {{cannot reinterpret_cast from member pointer type}}
diff --git a/test/SemaCXX/microsoft-dtor-lookup.cpp b/test/SemaCXX/microsoft-dtor-lookup.cpp
new file mode 100644
index 000000000000..d264bab09bf7
--- /dev/null
+++ b/test/SemaCXX/microsoft-dtor-lookup.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi itanium -fsyntax-only %s
+// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -verify -DMSVC_ABI %s
+
+namespace Test1 {
+
+// Should be accepted under the Itanium ABI (first RUN line) but rejected
+// under the Microsoft ABI (second RUN line), as Microsoft ABI requires
+// operator delete() lookups to be done at all virtual destructor declaration
+// points.
+
+struct A {
+ void operator delete(void *); // expected-note {{member found by ambiguous name lookup}}
+};
+
+struct B {
+ void operator delete(void *); // expected-note {{member found by ambiguous name lookup}}
+};
+
+struct C : A, B {
+ ~C();
+};
+
+struct VC : A, B {
+ virtual ~VC(); // expected-error {{member 'operator delete' found in multiple base classes of different types}}
+};
+
+}
+
+namespace Test2 {
+
+// In the MSVC ABI, functions must destroy their aggregate arguments. foo
+// requires a dtor for B, but we can't implicitly define it because ~A is
+// private. bar should be able to call A's private dtor without error, even
+// though MSVC rejects bar.
+
+class A {
+private:
+ ~A(); // expected-note 2{{declared private here}}
+ int a;
+};
+
+struct B : public A { // expected-error {{base class 'Test2::A' has private destructor}}
+ int b;
+};
+
+struct C {
+ ~C();
+ int c;
+};
+
+struct D {
+ // D has a non-trivial implicit dtor that destroys C.
+ C o;
+};
+
+void foo(B b) { } // expected-note {{implicit destructor for 'Test2::B' first required here}}
+void bar(A a) { } // expected-error {{variable of type 'Test2::A' has private destructor}}
+void baz(D d) { } // no error
+
+}
+
+#ifdef MSVC_ABI
+namespace Test3 {
+
+class A {
+ A();
+ ~A(); // expected-note 2{{implicitly declared private here}}
+ friend void bar(A);
+ int a;
+};
+
+void bar(A a) { }
+void baz(A a) { } // expected-error {{variable of type 'Test3::A' has private destructor}}
+
+// MSVC accepts foo() but we reject it for consistency with Itanium. MSVC also
+// rejects this if A has a copy ctor or if we call A's ctor.
+void foo(A *a) {
+ bar(*a); // expected-error {{temporary of type 'Test3::A' has private destructor}}
+}
+}
+#endif
+
+namespace Test4 {
+// Don't try to access the dtor of an incomplete on a function declaration.
+class A;
+void foo(A a);
+}
diff --git a/test/SemaCXX/microsoft-new-delete.cpp b/test/SemaCXX/microsoft-new-delete.cpp
new file mode 100644
index 000000000000..e0d25dcd86f7
--- /dev/null
+++ b/test/SemaCXX/microsoft-new-delete.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+#include <stddef.h>
+
+struct arbitrary_t {} arbitrary;
+void *operator new(size_t size, arbitrary_t);
+
+void f() {
+ // Expect no error in MSVC compatibility mode
+ int *p = new(arbitrary) int[4];
+}
diff --git a/test/SemaCXX/missing-members.cpp b/test/SemaCXX/missing-members.cpp
index 529ba1023dcd..619bc61f2501 100644
--- a/test/SemaCXX/missing-members.cpp
+++ b/test/SemaCXX/missing-members.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
namespace A {
namespace B {
- class C { };
+ class C { }; // expected-note 2 {{'A::B::C' declared here}}
struct S { };
union U { };
}
@@ -19,8 +19,12 @@ namespace B {
void g() {
A::B::D::E; // expected-error {{no member named 'D' in namespace 'A::B'}}
- B::B::C::D; // expected-error {{no member named 'C' in 'B::B'}}
- ::C::D; // expected-error {{no member named 'C' in the global namespace}}
+ // FIXME: The typo corrections below should be suppressed since A::B::C
+ // doesn't have a member named D.
+ B::B::C::D; // expected-error {{no member named 'C' in 'B::B'; did you mean 'A::B::C'?}} \
+ // expected-error {{no member named 'D' in 'A::B::C'}}
+ ::C::D; // expected-error {{no member named 'C' in the global namespace; did you mean 'A::B::C'?}}\
+ // expected-error {{no member named 'D' in 'A::B::C'}}
}
int A::B::i = 10; // expected-error {{no member named 'i' in namespace 'A::B'}}
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index 40bcf45bca32..6195e0395515 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -19,7 +19,7 @@ namespace fizbin {
// expected-note{{'fizbin::nested::lessFoobar' declared here}}
class dummy { // expected-note 2 {{'fizbin::dummy' declared here}}
public:
- static bool moreFoobar() { return false; } // expected-note{{'moreFoobar' declared here}}
+ static bool morebar() { return false; } // expected-note{{'morebar' declared here}}
};
}
void Check() { // expected-note{{'Check' declared here}}
@@ -29,9 +29,9 @@ void Check() { // expected-note{{'Check' declared here}}
if (lessFoobar()) Double(7); // expected-error{{use of undeclared identifier 'lessFoobar'; did you mean 'fizbin::nested::lessFoobar'?}}
if (baztool::toFoobar()) Double(7); // expected-error{{use of undeclared identifier 'baztool'; did you mean 'fizbin::baztool'?}}
if (nested::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'nested'; did you mean 'fizbin::nested'?}}
- if (dummy::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}}
- if (dummy::mreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} \
- // expected-error{{no member named 'mreFoobar' in 'fizbin::dummy'; did you mean 'moreFoobar'?}}
+ if (dummy::morebar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}}
+ if (dummy::mrebar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} \
+ // expected-error{{no member named 'mrebar' in 'fizbin::dummy'; did you mean 'morebar'?}}
if (moFoobin()) Double(7); // expected-error{{use of undeclared identifier 'moFoobin'}}
}
diff --git a/test/SemaCXX/ms-overload-entry-point.cpp b/test/SemaCXX/ms-overload-entry-point.cpp
new file mode 100644
index 000000000000..67fed01f6317
--- /dev/null
+++ b/test/SemaCXX/ms-overload-entry-point.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+template <typename T>
+int wmain() { // expected-error{{'wmain' cannot be a template}}
+ return 0;
+}
+
+namespace {
+int WinMain(void) { return 0; }
+int WinMain(int) { return 0; }
+}
+
+void wWinMain(void) {} // expected-note{{previous definition is here}}
+void wWinMain(int) {} // expected-error{{conflicting types for 'wWinMain'}}
+
+int foo() {
+ wmain<void>(); // expected-error{{no matching function for call to 'wmain'}}
+ wmain<int>(); // expected-error{{no matching function for call to 'wmain'}}
+ WinMain();
+ return 0;
+}
diff --git a/test/SemaCXX/ms-wchar.cpp b/test/SemaCXX/ms-wchar.cpp
new file mode 100644
index 000000000000..878d8cadcebe
--- /dev/null
+++ b/test/SemaCXX/ms-wchar.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f();
+__wchar_t f(); // No error, wchar_t and __wchar_t are the same type.
+
+__wchar_t g = L'a';
+__wchar_t s[] = L"Hello world!";
+
+unsigned short t[] = L"Hello world!"; // expected-error{{array initializer must be an initializer list}}
+
+wchar_t u[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+__wchar_t v[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
diff --git a/test/SemaCXX/ms_struct.cpp b/test/SemaCXX/ms_struct.cpp
new file mode 100644
index 000000000000..37fa9a7c687c
--- /dev/null
+++ b/test/SemaCXX/ms_struct.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin9 -std=c++11 %s
+// expected-no-diagnostics
+
+#pragma ms_struct on
+
+struct A {
+ unsigned long a:4;
+ unsigned char b;
+};
+
+struct B : public A {
+ unsigned long c:16;
+ int d;
+ B();
+};
+
+static_assert(__builtin_offsetof(B, d) == 12,
+ "We can't allocate the bitfield into the padding under ms_struct"); \ No newline at end of file
diff --git a/test/SemaCXX/ms_wide_bitfield.cpp b/test/SemaCXX/ms_wide_bitfield.cpp
new file mode 100644
index 000000000000..d917390ef14c
--- /dev/null
+++ b/test/SemaCXX/ms_wide_bitfield.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -mms-bitfields -verify %s 2>&1
+
+struct A {
+ char a : 9; // expected-error{{size of bit-field 'a' (9 bits) exceeds size of its type (8 bits)}}
+ int b : 33; // expected-error{{size of bit-field 'b' (33 bits) exceeds size of its type (32 bits)}}
+ bool c : 9; // expected-error{{size of bit-field 'c' (9 bits) exceeds size of its type (8 bits)}}
+};
+
+int a[sizeof(A) == 1 ? 1 : -1];
diff --git a/test/SemaCXX/neon-vector-types.cpp b/test/SemaCXX/neon-vector-types.cpp
index 336fcd4f18d6..c2953d713b2a 100644
--- a/test/SemaCXX/neon-vector-types.cpp
+++ b/test/SemaCXX/neon-vector-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify "-triple" "thumbv7-apple-ios3.0.0" %s
+// RUN: %clang_cc1 -fsyntax-only -verify "-triple" "thumbv7-apple-ios3.0.0" -target-feature +neon %s
// rdar://9208404
typedef int MP4Err;
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 7239646d8d7e..df4f1b269d70 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify -fblocks %s
namespace A {
struct C {
static int cx;
@@ -50,6 +50,7 @@ namespace B {
void f1() {
void A::Af(); // expected-error {{definition or redeclaration of 'Af' not allowed inside a function}}
+ void (^x)() = ^{ void A::Af(); }; // expected-error {{definition or redeclaration of 'Af' not allowed inside a block}}
}
void f2() {
@@ -166,9 +167,7 @@ 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}}
-X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \
- // expected-error{{C++ requires a type specifier for all declarations}} \
- // expected-error{{only constructors take base initializers}}
+X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}}
struct foo_S {
static bool value;
@@ -260,7 +259,7 @@ namespace PR8159 {
namespace rdar7980179 {
class A { void f0(); }; // expected-note {{previous}}
- int A::f0() {} // expected-error {{out-of-line definition of 'rdar7980179::A::f0' differs from the declaration in the return type}}
+ int A::f0() {} // expected-error {{return type of out-of-line definition of 'rdar7980179::A::f0' differs}}
}
namespace alias = A;
@@ -297,3 +296,16 @@ namespace NS {
int foobar = a + longer_b; // expected-error {{use of undeclared identifier 'a'; did you mean 'NS::a'?}} \
// expected-error {{use of undeclared identifier 'longer_b'; did you mean 'NS::longer_b'?}}
}
+
+// <rdar://problem/13853540>
+namespace N {
+ struct X { };
+ namespace N {
+ struct Foo {
+ struct N::X *foo(); // expected-error{{no struct named 'X' in namespace 'N::N'}}
+ };
+ }
+}
+
+namespace TypedefNamespace { typedef int F; };
+TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{expected a class or namespace}}
diff --git a/test/SemaCXX/new-delete-0x.cpp b/test/SemaCXX/new-delete-0x.cpp
index 9e3b4928b141..a11392d5896c 100644
--- a/test/SemaCXX/new-delete-0x.cpp
+++ b/test/SemaCXX/new-delete-0x.cpp
@@ -21,7 +21,9 @@ void bad_news(int *ip)
auto s = new int*[[]{return 1;}()][2]; // expected-error {{expected ']'}}
// ... but not here:
auto t = new (int(*)[[]]); // expected-error {{an attribute list cannot appear here}}
- auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} expected-error {{variably modified type}}
+ auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} \
+ expected-error {{variably modified type}} \
+ expected-error {{a lambda expression may not appear inside of a constant expression}}
}
void good_deletes()
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 8b352954a331..7facd10ca5fc 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -18,6 +18,13 @@ struct V : U
{
};
+inline void operator delete(void *); // expected-warning {{replacement function 'operator delete' cannot be declared 'inline'}}
+
+__attribute__((used))
+inline void *operator new(size_t) { // no warning, due to __attribute__((used))
+ return 0;
+}
+
// PR5823
void* operator new(const size_t); // expected-note 2 {{candidate}}
void* operator new(size_t, int*); // expected-note 3 {{candidate}}
@@ -116,8 +123,8 @@ struct X1 {
};
struct X2 {
- operator int*(); // expected-note {{candidate function}}
- operator float*(); // expected-note {{candidate function}}
+ operator int*(); // expected-note {{conversion}}
+ operator float*(); // expected-note {{conversion}}
};
void test_delete_conv(X0 x0, X1 x1, X2 x2) {
@@ -209,7 +216,7 @@ struct X11 : X10 { // expected-error {{no suitable member 'operator delete' in '
};
void f() {
- X11 x11; // expected-note {{implicit default destructor for 'X11' first required here}}
+ X11 x11; // expected-note {{implicit destructor for 'X11' first required here}}
}
struct X12 {
@@ -394,7 +401,7 @@ namespace ArrayNewNeedsDtor {
struct A { A(); private: ~A(); }; // expected-note {{declared private here}}
struct B { B(); A a; }; // expected-error {{field of type 'ArrayNewNeedsDtor::A' has private destructor}}
B *test9() {
- return new B[5]; // expected-note {{implicit default destructor for 'ArrayNewNeedsDtor::B' first required here}}
+ return new B[5]; // expected-note {{implicit destructor for 'ArrayNewNeedsDtor::B' first required here}}
}
}
diff --git a/test/SemaCXX/no-rtti.cpp b/test/SemaCXX/no-rtti.cpp
index 75167050dca2..a171b3cde2c3 100644
--- a/test/SemaCXX/no-rtti.cpp
+++ b/test/SemaCXX/no-rtti.cpp
@@ -8,3 +8,22 @@ void f()
{
(void)typeid(int); // expected-error {{cannot use typeid with -fno-rtti}}
}
+
+namespace {
+struct A {
+ virtual ~A(){};
+};
+
+struct B : public A {
+ B() : A() {}
+};
+}
+
+bool isa_B(A *a) {
+ return dynamic_cast<B *>(a) != 0; // expected-error {{cannot use dynamic_cast with -fno-rtti}}
+}
+
+void* getMostDerived(A* a) {
+ // This cast does not use RTTI.
+ return dynamic_cast<void *>(a);
+}
diff --git a/test/SemaCXX/no-warn-unused-const-variables.cpp b/test/SemaCXX/no-warn-unused-const-variables.cpp
new file mode 100644
index 000000000000..c146ca04f832
--- /dev/null
+++ b/test/SemaCXX/no-warn-unused-const-variables.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wno-unused-const-variable -verify %s
+
+namespace {
+ int i = 0; // expected-warning {{unused variable 'i'}}
+ const int j = 0;;
+}
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index b49f63b98051..28798a4f8ce8 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -64,6 +64,9 @@ nullptr_t f(nullptr_t null)
(void)reinterpret_cast<uintptr_t>(nullptr);
(void)reinterpret_cast<uintptr_t>(*pn);
+ // You can't reinterpret_cast nullptr to any integer
+ (void)reinterpret_cast<char>(nullptr); // expected-error {{cast from pointer to smaller type 'char' loses information}}
+
int *ip = *pn;
if (*pn) { }
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index a5f5d347c282..e6069ac9c0a0 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -73,3 +73,13 @@ struct LtoRCheck {
};
int ltor = __builtin_offsetof(struct LtoRCheck, a[LtoRCheck().f]); // \
expected-error {{reference to non-static member function must be called}}
+
+namespace PR17578 {
+struct Base {
+ int Field;
+};
+struct Derived : virtual Base {
+ void Fun() { (void)__builtin_offsetof(Derived, Field); } // expected-warning {{offset of on non-POD type}} \
+ expected-error {{invalid application of 'offsetof' to a field of a virtual base}}
+};
+}
diff --git a/test/SemaCXX/operator-arrow-depth.cpp b/test/SemaCXX/operator-arrow-depth.cpp
new file mode 100644
index 000000000000..3e2ba8e45228
--- /dev/null
+++ b/test/SemaCXX/operator-arrow-depth.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DMAX=128 -foperator-arrow-depth 128
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DMAX=2 -foperator-arrow-depth 2
+// RUN: %clang -fsyntax-only -Xclang -verify %s -DMAX=10 -foperator-arrow-depth=10
+
+template<int N> struct B;
+template<int N> struct A {
+ B<N> operator->(); // expected-note +{{'operator->' declared here produces an object of type 'B<}}
+};
+template<int N> struct B {
+ A<N-1> operator->(); // expected-note +{{'operator->' declared here produces an object of type 'A<}}
+#if MAX != 2
+ // expected-note-re@-2 {{(skipping (120|2) 'operator->'s in backtrace)}}
+#endif
+};
+
+struct X { int n; };
+template<> struct B<1> {
+ X *operator->();
+};
+
+A<MAX/2> good;
+int n = good->n;
+
+B<MAX/2 + 1> bad;
+int m = bad->n; // expected-error-re {{use of 'operator->' on type 'B<(2|10|128) / 2 \+ 1>' would invoke a sequence of more than (2|10|128) 'operator->' calls}}
+ // expected-note@-1 {{use -foperator-arrow-depth=N to increase 'operator->' limit}}
diff --git a/test/SemaCXX/overload-decl.cpp b/test/SemaCXX/overload-decl.cpp
index 9bba47adfdda..fdb14cb173eb 100644
--- a/test/SemaCXX/overload-decl.cpp
+++ b/test/SemaCXX/overload-decl.cpp
@@ -26,8 +26,14 @@ class X {
void g(int, float); // expected-note {{previous declaration is here}}
int g(int, Float); // expected-error {{functions that differ only in their return type cannot be overloaded}}
- static void g(float);
+ static void g(float); // expected-note {{previous declaration is here}}
static void g(int); // expected-error {{static and non-static member functions with the same parameter types cannot be overloaded}}
+ static void g(float); // expected-error {{class member cannot be redeclared}}
+
+ void h(); // expected-note {{previous declaration is here}} \
+ expected-note {{previous declaration is here}}
+ void h() __restrict; // expected-error {{class member cannot be redeclared}} \
+ expected-error {{conflicting types for 'h'}}
};
int main() {} // expected-note {{previous definition is here}}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index e5b3fab33c8c..99105cb5b60b 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
class X { };
X operator+(X, X);
@@ -387,8 +387,8 @@ void test_lookup_through_using() {
namespace rdar9136502 {
struct X {
- int i();
- int i(int);
+ int i(); // expected-note{{possible target for call}}
+ int i(int); // expected-note{{possible target for call}}
};
struct Y {
@@ -396,7 +396,8 @@ namespace rdar9136502 {
};
void f(X x, Y y) {
- y << x.i; // expected-error{{reference to non-static member function must be called}}
+ y << x
+ .i; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
}
@@ -440,3 +441,14 @@ namespace test10 {
a[bar<float>];
}
}
+
+struct InvalidOperatorEquals {
+ InvalidOperatorEquals operator=() = delete; // expected-error {{overloaded 'operator=' must be a binary operator}}
+};
+
+namespace PR7681 {
+ template <typename PT1, typename PT2> class PointerUnion;
+ void foo(PointerUnion<int*, float*> &Result) {
+ Result = 1; // expected-error {{no viable overloaded '='}} // expected-note {{type 'PointerUnion<int *, float *>' is incomplete}}
+ }
+}
diff --git a/test/SemaCXX/parentheses.cpp b/test/SemaCXX/parentheses.cpp
new file mode 100644
index 000000000000..b430b25e5d68
--- /dev/null
+++ b/test/SemaCXX/parentheses.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify %s
+
+// PR16930, PR16727:
+template<class Foo>
+bool test(Foo f, int *array)
+{
+ return false && false || array[f.get()]; // expected-warning {{'&&' within '||'}} expected-note {{parentheses}}
+}
diff --git a/test/SemaCXX/pr13394-crash-on-invalid.cpp b/test/SemaCXX/pr13394-crash-on-invalid.cpp
index 413c52af858c..841e3c203402 100644
--- a/test/SemaCXX/pr13394-crash-on-invalid.cpp
+++ b/test/SemaCXX/pr13394-crash-on-invalid.cpp
@@ -9,8 +9,21 @@ namespace stretch_v1 {
namespace gatekeeper_v1 {
namespace gatekeeper_factory_v1 {
struct closure_t { // expected-note {{'closure_t' declared here}}
- gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean 'closure_t'?}}
+ gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean simply 'closure_t'?}}
};
}
- gatekeeper_v1::closure_t *x; // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1}}
+ // FIXME: Typo correction should remove the 'gatekeeper_v1::' name specifier
+ gatekeeper_v1::closure_t *x; // expected-error-re {{no type named 'closure_t' in namespace 'gatekeeper_v1'$}}
}
+
+namespace Foo {
+struct Base {
+ void Bar() {} // expected-note{{'Bar' declared here}}
+};
+}
+
+struct Derived : public Foo::Base {
+ void test() {
+ Foo::Bar(); // expected-error{{no member named 'Bar' in namespace 'Foo'; did you mean simply 'Bar'?}}
+ }
+};
diff --git a/test/SemaCXX/predefined-expr.cpp b/test/SemaCXX/predefined-expr.cpp
new file mode 100644
index 000000000000..257d44c60069
--- /dev/null
+++ b/test/SemaCXX/predefined-expr.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -std=c++1y -fblocks -fsyntax-only -verify %s
+// PR16946
+// expected-no-diagnostics
+
+auto foo() {
+ static_assert(sizeof(__func__) == 4, "foo");
+ static_assert(sizeof(__FUNCTION__) == 4, "foo");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "auto foo()");
+ return 0;
+}
+
+auto bar() -> decltype(42) {
+ static_assert(sizeof(__func__) == 4, "bar");
+ static_assert(sizeof(__FUNCTION__) == 4, "bar");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 10, "int bar()");
+ return 0;
+}
+
+// Within templates.
+template <typename T>
+int baz() {
+ static_assert(sizeof(__func__) == 4, "baz");
+ static_assert(sizeof(__FUNCTION__) == 4, "baz");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 20, "int baz() [T = int]");
+
+ []() {
+ static_assert(sizeof(__func__) == 11, "operator()");
+ static_assert(sizeof(__FUNCTION__) == 11, "operator()");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 50,
+ "auto baz()::<anonymous class>::operator()() const");
+ return 0;
+ }
+ ();
+
+ ^{
+ // FIXME: This is obviously wrong.
+ static_assert(sizeof(__func__) == 1, "__baz_block_invoke");
+ static_assert(sizeof(__FUNCTION__) == 1, "__baz_block_invoke");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__baz_block_invoke");
+ }
+ ();
+
+ #pragma clang __debug captured
+ {
+ static_assert(sizeof(__func__) == 4, "baz");
+ static_assert(sizeof(__FUNCTION__) == 4, "baz");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 20, "int baz() [T = int]");
+ }
+
+ return 0;
+}
+
+int main() {
+ static_assert(sizeof(__func__) == 5, "main");
+ static_assert(sizeof(__FUNCTION__) == 5, "main");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "int main()");
+
+ []() {
+ static_assert(sizeof(__func__) == 11, "operator()");
+ static_assert(sizeof(__FUNCTION__) == 11, "operator()");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 51,
+ "auto main()::<anonymous class>::operator()() const");
+ return 0;
+ }
+ ();
+
+ ^{
+ // FIXME: This is obviously wrong.
+ static_assert(sizeof(__func__) == 1, "__main_block_invoke");
+ static_assert(sizeof(__FUNCTION__) == 1, "__main_block_invoke");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__main_block_invoke");
+ }
+ ();
+
+ #pragma clang __debug captured
+ {
+ static_assert(sizeof(__func__) == 5, "main");
+ static_assert(sizeof(__FUNCTION__) == 5, "main");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "int main()");
+
+ #pragma clang __debug captured
+ {
+ static_assert(sizeof(__func__) == 5, "main");
+ static_assert(sizeof(__FUNCTION__) == 5, "main");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 11, "int main()");
+ }
+ }
+
+ []() {
+ #pragma clang __debug captured
+ {
+ static_assert(sizeof(__func__) == 11, "operator()");
+ static_assert(sizeof(__FUNCTION__) == 11, "operator()");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 51,
+ "auto main()::<anonymous class>::operator()() const");
+ }
+ }
+ ();
+
+ baz<int>();
+
+ return 0;
+}
diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp
index a14193cc7ac8..23164fa42f32 100644
--- a/test/SemaCXX/qualified-id-lookup.cpp
+++ b/test/SemaCXX/qualified-id-lookup.cpp
@@ -86,13 +86,13 @@ namespace a {
namespace a {
namespace a { // A1
namespace a { // A2
- int i; // expected-note{{'::a::a::a::i' declared here}}
+ int i; // expected-note{{'a::a::a::i' declared here}}
}
}
}
void test_a() {
- a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean '::a::a::a::i'?}}
+ a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean 'a::a::a::i'?}}
a::a::a::i = 4;
a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'$}}
}
@@ -149,6 +149,6 @@ namespace PR6830 {
}
namespace pr12339 {
- extern "C" void i;
+ extern "C" void i; // expected-error{{variable has incomplete type 'void'}}
pr12339::FOO // expected-error{{no type named 'FOO' in namespace 'pr12339'}}
} // expected-error{{expected unqualified-id}}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index 4f3dab0514b9..37fc2a856fd9 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -137,3 +137,10 @@ namespace PR8608 {
// The following crashed trying to recursively evaluate the LValue.
const int &do_not_crash = do_not_crash; // expected-warning{{reference 'do_not_crash' is not yet bound to a value when used within its own initialization}}
+
+namespace ExplicitRefInit {
+ // This is invalid: we can't copy-initialize an 'A' temporary using an
+ // explicit constructor.
+ struct A { explicit A(int); };
+ const A &a(0); // expected-error {{reference to type 'const ExplicitRefInit::A' could not bind to an rvalue of type 'int'}}
+}
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index de276ae3d3d6..90c9317ecdfb 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -276,6 +276,27 @@ namespace test15 {
}
namespace test16 {
+ struct S { int n; };
+ int f() {
+ goto x; // expected-error {{goto into protected scope}}
+ const S &s = S(); // expected-note {{jump bypasses variable initialization}}
+x: return s.n;
+ }
+}
+
+#if __cplusplus >= 201103L
+namespace test17 {
+ struct S { int get(); private: int n; };
+ int f() {
+ goto x; // expected-error {{goto into protected scope}}
+ S s = {}; // expected-note {{jump bypasses variable initialization}}
+x: return s.get();
+ }
+}
+#endif
+
+// This test must be last, because the error prohibits further jump diagnostics.
+namespace testInvalid {
Invalid inv; // expected-error {{unknown type name}}
// Make sure this doesn't assert.
void fn()
diff --git a/test/SemaCXX/self-comparison.cpp b/test/SemaCXX/self-comparison.cpp
new file mode 100644
index 000000000000..fb15ec843061
--- /dev/null
+++ b/test/SemaCXX/self-comparison.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int foo(int x) {
+ return x == x; // expected-warning {{self-comparison always evaluates to true}}
+}
+
+struct X {
+ bool operator==(const X &x);
+};
+
+struct A {
+ int x;
+ X x2;
+ int a[3];
+ int b[3];
+ bool f() { return x == x; } // expected-warning {{self-comparison always evaluates to true}}
+ bool g() { return x2 == x2; } // no-warning
+ bool h() { return a == b; } // expected-warning {{array comparison always evaluates to false}}
+ bool i() {
+ int c[3];
+ return a == c; // expected-warning {{array comparison always evaluates to false}}
+ }
+};
diff --git a/test/SemaCXX/static-data-member.cpp b/test/SemaCXX/static-data-member.cpp
new file mode 100644
index 000000000000..9fe87b1c1d3c
--- /dev/null
+++ b/test/SemaCXX/static-data-member.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -w %s
+
+struct ABC {
+ static double a;
+ static double b;
+ static double c;
+ static double d;
+ static double e;
+ static double f;
+};
+
+double ABC::a = 1.0;
+extern double ABC::b = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
+static double ABC::c = 1.0; // expected-error {{'static' can only be specified inside the class definition}}
+__private_extern__ double ABC::d = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
+auto double ABC::e = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
+register double ABC::f = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
diff --git a/test/SemaCXX/storage-class.cpp b/test/SemaCXX/storage-class.cpp
index 74121843e5e4..decf1e7ac362 100644
--- a/test/SemaCXX/storage-class.cpp
+++ b/test/SemaCXX/storage-class.cpp
@@ -4,4 +4,4 @@ extern int PR6495b = 42; // expected-warning{{'extern' variable has an initializ
extern const int PR6495c[] = {42,43,44};
extern struct Test1 {}; // expected-warning {{'extern' is not permitted on a declaration of a type}}
-extern "C" struct Test0 {}; // no warning
+extern "C" struct Test0 { int x; }; // no warning
diff --git a/test/SemaCXX/string-init.cpp b/test/SemaCXX/string-init.cpp
new file mode 100644
index 000000000000..7e62d1855aca
--- /dev/null
+++ b/test/SemaCXX/string-init.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+void f() {
+ char a1[] = "a"; // No error.
+ char a2[] = u8"a"; // No error.
+ char a3[] = u"a"; // expected-error{{initializing char array with wide string literal}}
+ char a4[] = U"a"; // expected-error{{initializing char array with wide string literal}}
+ char a5[] = L"a"; // expected-error{{initializing char array with wide string literal}}
+
+ wchar_t b1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ wchar_t b2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ wchar_t b3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ wchar_t b4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ wchar_t b5[] = L"a"; // No error.
+
+ char16_t c1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char16_t c2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char16_t c3[] = u"a"; // No error.
+ char16_t c4[] = U"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ char16_t c5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+
+ char32_t d1[] = "a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char32_t d2[] = u8"a"; // expected-error{{initializing wide char array with non-wide string literal}}
+ char32_t d3[] = u"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+ char32_t d4[] = U"a"; // No error.
+ char32_t d5[] = L"a"; // expected-error{{initializing wide char array with incompatible wide string literal}}
+
+ int e1[] = "a"; // expected-error{{array initializer must be an initializer list}}
+ int e2[] = u8"a"; // expected-error{{array initializer must be an initializer list}}
+ int e3[] = u"a"; // expected-error{{array initializer must be an initializer list}}
+ int e4[] = U"a"; // expected-error{{array initializer must be an initializer list}}
+ int e5[] = L"a"; // expected-error{{array initializer must be an initializer list}}
+}
+
+void g() {
+ char a[] = 1; // expected-error{{array initializer must be an initializer list or string literal}}
+ wchar_t b[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+ char16_t c[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+ char32_t d[] = 1; // expected-error{{array initializer must be an initializer list or wide string literal}}
+}
diff --git a/test/SemaCXX/string-plus-char.cpp b/test/SemaCXX/string-plus-char.cpp
new file mode 100644
index 000000000000..00a2c4550dc0
--- /dev/null
+++ b/test/SemaCXX/string-plus-char.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+class A {
+public:
+ A(): str() { }
+ A(const char *p) { }
+ A(char *p) : str(p + 'a') { } // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ A& operator+(const char *p) { return *this; }
+ A& operator+(char ch) { return *this; }
+ char * str;
+};
+
+void f(const char *s) {
+ A a = s + 'a'; // // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ a = a + s + 'b'; // no-warning
+
+ char *str = 0;
+ char *str2 = str + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ const char *constStr = s + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ str = 'c' + str;// expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ wchar_t *wstr;
+ wstr = wstr + L'c'; // expected-warning {{adding 'wchar_t' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ str2 = str + u'a'; // expected-warning {{adding 'char16_t' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ // no-warning
+ char c = 'c';
+ str = str + c;
+ str = c + str;
+}
diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp
index 5c59578d6eb5..e1b95ba8d63c 100644
--- a/test/SemaCXX/struct-class-redecl.cpp
+++ b/test/SemaCXX/struct-class-redecl.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -Wmismatched-tags %s 2>&1 | FileCheck %s
class X; // expected-note 2{{here}}
typedef struct X * X_t; // expected-warning{{previously declared}}
union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}
diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp
index 517faa9a696d..392dcd869802 100644
--- a/test/SemaCXX/switch.cpp
+++ b/test/SemaCXX/switch.cpp
@@ -85,3 +85,18 @@ void local_class(int n) {
}();
}
}
+
+namespace Conversion {
+ struct S {
+ explicit operator int(); // expected-note {{conversion}}
+ };
+ template<typename T> void f(T t) {
+ switch (t) { // expected-error {{explicit conversion}}
+ case 0:
+ return;
+ default:
+ break;
+ }
+ }
+ template void f(S); // expected-note {{instantiation of}}
+}
diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp
index bd601db2ac1d..f7e3433a7608 100644
--- a/test/SemaCXX/trailing-return-0x.cpp
+++ b/test/SemaCXX/trailing-return-0x.cpp
@@ -94,3 +94,11 @@ namespace DR1608 {
auto f() -> decltype((*this)[0]); // expected-error {{cannot be overloaded}}
};
}
+
+namespace PR16273 {
+ struct A {
+ template <int N> void f();
+ auto g()->decltype(this->f<0>());
+ };
+}
+
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index aa18ff4e67af..3e479215838e 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -308,6 +308,37 @@ void is_final()
{ int arr[F(__is_final(PotentiallyFinal<float>))]; }
}
+struct SealedClass sealed {
+};
+
+template<typename T>
+struct PotentiallySealed { };
+
+template<typename T>
+struct PotentiallySealed<T*> sealed { };
+
+template<>
+struct PotentiallySealed<int> sealed { };
+
+void is_sealed()
+{
+ { int arr[T(__is_sealed(SealedClass))]; }
+ { int arr[T(__is_sealed(PotentiallySealed<float*>))]; }
+ { int arr[T(__is_sealed(PotentiallySealed<int>))]; }
+
+ { int arr[F(__is_sealed(int))]; }
+ { int arr[F(__is_sealed(Union))]; }
+ { int arr[F(__is_sealed(Int))]; }
+ { int arr[F(__is_sealed(IntAr))]; }
+ { int arr[F(__is_sealed(UnionAr))]; }
+ { int arr[F(__is_sealed(Derives))]; }
+ { int arr[F(__is_sealed(ClassType))]; }
+ { int arr[F(__is_sealed(cvoid))]; }
+ { int arr[F(__is_sealed(IntArNB))]; }
+ { int arr[F(__is_sealed(HasAnonymousUnion))]; }
+ { int arr[F(__is_sealed(PotentiallyFinal<float>))]; }
+}
+
typedef HasVirt Polymorph;
struct InheritPolymorph : Polymorph {};
@@ -1072,6 +1103,9 @@ void is_trivially_copyable2()
int t31[F(__is_trivially_copyable(SuperNonTrivialStruct))];
int t32[F(__is_trivially_copyable(NonTCStruct))];
int t33[F(__is_trivially_copyable(ExtDefaulted))];
+
+ int t34[T(__is_trivially_copyable(const int))];
+ int t35[F(__is_trivially_copyable(volatile int))];
}
struct CStruct {
@@ -1244,14 +1278,14 @@ void has_trivial_default_constructor() {
void has_trivial_move_constructor() {
// n3376 12.8 [class.copy]/12
- // A copy/move constructor for class X is trivial if it is not
- // user-provided, its declared parameter type is the same as
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided, its declared parameter type is the same as
// if it had been implicitly declared, and if
- // — class X has no virtual functions (10.3) and no virtual
+ // - class X has no virtual functions (10.3) and no virtual
// base classes (10.1), and
- // — the constructor selected to copy/move each direct base
+ // - the constructor selected to copy/move each direct base
// class subobject is trivial, and
- // — for each non-static data member of X that is of class
+ // - for each non-static data member of X that is of class
// type (or array thereof), the constructor selected
// to copy/move that member is trivial;
// otherwise the copy/move constructor is non-trivial.
@@ -1445,14 +1479,14 @@ void has_nothrow_move_assign() {
void has_trivial_move_assign() {
// n3376 12.8 [class.copy]/25
- // A copy/move assignment operator for class X is trivial if it
- // is not user-provided, its declared parameter type is the same
+ // A copy/move assignment operator for class X is trivial if it
+ // is not user-provided, its declared parameter type is the same
// as if it had been implicitly declared, and if:
- // — class X has no virtual functions (10.3) and no virtual base
+ // - class X has no virtual functions (10.3) and no virtual base
// classes (10.1), and
- // — the assignment operator selected to copy/move each direct
+ // - the assignment operator selected to copy/move each direct
// base class subobject is trivial, and
- // — for each non-static data member of X that is of class type
+ // - for each non-static data member of X that is of class type
// (or array thereof), the assignment operator
// selected to copy/move that member is trivial;
{ int arr[T(__has_trivial_move_assign(Int))]; }
@@ -1571,7 +1605,7 @@ template<typename T> struct DerivedB : BaseA<T> { };
template<typename T> struct CrazyDerived : T { };
-class class_forward; // expected-note {{forward declaration of 'class_forward'}}
+class class_forward; // expected-note 2 {{forward declaration of 'class_forward'}}
template <typename Base, typename Derived>
void isBaseOfT() {
@@ -1770,6 +1804,8 @@ void is_trivial()
{ int arr[F(__is_trivial(cvoid))]; }
}
+template<typename T> struct TriviallyConstructibleTemplate {};
+
void trivial_checks()
{
{ int arr[T(__is_trivially_copyable(int))]; }
@@ -1848,6 +1884,11 @@ void trivial_checks()
{ int arr[F((__is_trivially_constructible(ExtDefaulted,
ExtDefaulted &&)))]; }
+ { int arr[T((__is_trivially_constructible(TriviallyConstructibleTemplate<int>)))]; }
+ { int arr[F((__is_trivially_constructible(class_forward)))]; } // expected-error {{incomplete type 'class_forward' used in type trait expression}}
+ { int arr[F((__is_trivially_constructible(class_forward[])))]; }
+ { int arr[F((__is_trivially_constructible(void)))]; }
+
{ int arr[T((__is_trivially_assignable(int&, int)))]; }
{ int arr[T((__is_trivially_assignable(int&, int&)))]; }
{ int arr[T((__is_trivially_assignable(int&, int&&)))]; }
diff --git a/test/SemaCXX/typo-correction-pt2.cpp b/test/SemaCXX/typo-correction-pt2.cpp
new file mode 100644
index 000000000000..525d11b0a67b
--- /dev/null
+++ b/test/SemaCXX/typo-correction-pt2.cpp
@@ -0,0 +1,201 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
+//
+// FIXME: This file is overflow from test/SemaCXX/typo-correction.cpp due to a
+// hard-coded limit of 20 different typo corrections Sema::CorrectTypo will
+// attempt within a single file (which is to avoid having very broken files take
+// minutes to finally be rejected by the parser).
+
+namespace bogus_keyword_suggestion {
+void test() {
+ status = "OK"; // expected-error-re {{use of undeclared identifier 'status'$}}
+ return status; // expected-error-re {{use of undeclared identifier 'status'$}}
+ }
+}
+
+namespace PR13387 {
+struct A {
+ void CreateFoo(float, float);
+ void CreateBar(float, float);
+};
+struct B : A {
+ using A::CreateFoo;
+ void CreateFoo(int, int);
+};
+void f(B &x) {
+ x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+}
+}
+
+struct DataStruct {void foo();};
+struct T {
+ DataStruct data_struct;
+ void f();
+};
+// should be void T::f();
+void f() {
+ data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}}
+}
+
+namespace PR12287 {
+class zif {
+ void nab(int);
+};
+void nab(); // expected-note{{'::PR12287::nab' declared here}}
+void zif::nab(int) {
+ nab(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::PR12287::nab'?}}
+}
+}
+
+namespace TemplateFunction {
+template <class T>
+void A(T) { } // expected-note {{'::TemplateFunction::A' declared here}}
+
+template <class T>
+void B(T) { } // expected-note {{'::TemplateFunction::B' declared here}}
+
+class Foo {
+ public:
+ void A(int, int) {}
+ void B() {}
+};
+
+void test(Foo F, int num) {
+ F.A(num); // expected-error {{too few arguments to function call, expected 2, have 1; did you mean '::TemplateFunction::A'?}}
+ F.B(num); // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}}
+}
+}
+namespace using_suggestion_val_dropped_specifier {
+void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
+namespace N { }
+using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
+}
+
+namespace class_member_typo_corrections {
+class Outer {
+public:
+ class Inner {}; // expected-note {{'Outer::Inner' declared here}}
+ Inner MyMethod(Inner arg);
+};
+
+Inner Outer::MyMethod(Inner arg) { // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}}
+ return Inner();
+}
+
+class Result {
+public:
+ enum ResultType {
+ ENTITY, // expected-note {{'Result::ENTITY' declared here}}
+ PREDICATE, // expected-note {{'Result::PREDICATE' declared here}}
+ LITERAL // expected-note {{'Result::LITERAL' declared here}}
+ };
+
+ ResultType type();
+};
+
+void test() {
+ Result result_cell;
+ switch (result_cell.type()) {
+ case ENTITY: // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}}
+ case LITERAL: // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}}
+ case PREDICAT: // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}}
+ break;
+ }
+}
+
+class Figure {
+ enum ResultType {
+ SQUARE,
+ TRIANGLE,
+ CIRCLE
+ };
+
+public:
+ ResultType type();
+};
+
+void testAccess() {
+ Figure obj;
+ switch (obj.type()) { // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
+ case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'$}}
+ case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'$}}
+ case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'$}}
+ break;
+ }
+}
+}
+
+long readline(const char *, char *, unsigned long);
+void assign_to_unknown_var() {
+ deadline_ = 1; // expected-error-re {{use of undeclared identifier 'deadline_'$}}
+}
+
+namespace no_ns_before_dot {
+namespace re2 {}
+void test() {
+ req.set_check(false); // expected-error-re {{use of undeclared identifier 'req'$}}
+}
+}
+
+namespace PR17394 {
+ class A {
+ protected:
+ long zzzzzzzzzz;
+ };
+ class B : private A {};
+ B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}
+}
+
+namespace correct_fields_in_member_funcs {
+struct S {
+ int my_member; // expected-note {{'my_member' declared here}}
+ void f() { my_menber = 1; } // expected-error {{use of undeclared identifier 'my_menber'; did you mean 'my_member'?}}
+};
+}
+
+namespace PR17019 {
+ template<class F>
+ struct evil {
+ evil(F de) { // expected-note {{'de' declared here}}
+ de_; // expected-error {{use of undeclared identifier 'de_'; did you mean 'de'?}} \
+ // expected-warning {{expression result unused}}
+ }
+ ~evil() {
+ de_->bar() // expected-error {{use of undeclared identifier 'de_'}}
+ }
+ };
+
+ void meow() {
+ evil<int> Q(0); // expected-note {{in instantiation of member function}}
+ }
+}
+
+namespace fix_class_name_qualifier {
+class MessageHeaders {};
+class MessageUtils {
+ public:
+ static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
+};
+
+void test() {
+ // No, we didn't mean to call MessageHeaders::MessageHeaders.
+ MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
+}
+}
+
+namespace PR18213 { // expected-note {{'PR18213' declared here}}
+struct WrapperInfo {
+ int i;
+};
+
+template <typename T> struct Wrappable {
+ static WrapperInfo kWrapperInfo;
+};
+
+// Note the space before "::PR18213" is intended and needed, as it highlights
+// the actual typo, which is the leading "::".
+// TODO: Suggest removing the "::" from "::PR18213" (the right correction)
+// instead of incorrectly suggesting dropping "PR18213::WrapperInfo::".
+template <>
+PR18213::WrapperInfo ::PR18213::Wrappable<int>::kWrapperInfo = { 0 }; // expected-error {{no member named 'PR18213' in 'PR18213::WrapperInfo'; did you mean simply 'PR18213'?}} \
+ // expected-error {{C++ requires a type specifier for all declarations}}
+}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index caa6355fe958..4047e6a18cee 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -1,4 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
+//
+// WARNING: Do not add more typo correction test cases to this file lest you run
+// afoul the hard-coded limit (escape hatch) of 20 different typos whose
+// correction was attempted by Sema::CorrectTypo
struct errc {
int v_;
@@ -213,10 +217,14 @@ namespace PR13051 {
operator bool() const;
};
- void f() {
- f(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
- f(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
- f(&S<int>::foo); // expected-error-re{{no member named 'foo' in 'PR13051::S<int>'$}}
+ void foo(); // expected-note{{'foo' declared here}}
+ void g(void(*)());
+ void g(bool(S<int>::*)() const);
+
+ void test() {
+ g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
+ g(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
+ g(&S<int>::foo); // expected-error{{no member named 'foo' in 'PR13051::S<int>'; did you mean simply 'foo'?}}
}
}
@@ -230,33 +238,67 @@ class foo { }; // expected-note{{'foo' declared here}}
class bar : boo { }; // expected-error{{unknown class name 'boo'; did you mean 'foo'?}}
}
-namespace bogus_keyword_suggestion {
-void test() {
- status = "OK"; // expected-error-re{{use of undeclared identifier 'status'$}}
- return status; // expected-error-re{{use of undeclared identifier 'status'$}}
- }
+namespace outer {
+ void somefunc(); // expected-note{{'::outer::somefunc' declared here}}
+ void somefunc(int, int); // expected-note{{'::outer::somefunc' declared here}}
+
+ namespace inner {
+ void somefunc(int) {
+ someFunc(); // expected-error{{use of undeclared identifier 'someFunc'; did you mean '::outer::somefunc'?}}
+ someFunc(1, 2); // expected-error{{use of undeclared identifier 'someFunc'; did you mean '::outer::somefunc'?}}
+ }
+ }
}
-namespace PR13387 {
-struct A {
- void CreateFoo(float, float); // expected-note {{'CreateFoo' declared here}}
- void CreateBar(float, float);
-};
-struct B : A {
- using A::CreateFoo;
- void CreateFoo(int, int);
-};
-void f(B &x) {
- x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+namespace b6956809_test1 {
+ struct A {};
+ struct B {};
+
+ struct S1 {
+ void method(A*); // no note here
+ void method(B*);
+ };
+
+ void test1() {
+ B b;
+ S1 s;
+ s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S1'; did you mean 'method'}}
+ }
+
+ struct S2 {
+ S2();
+ void method(A*) const; // expected-note{{candidate function not viable}}
+ private:
+ void method(B*); // expected-note{{candidate function not viable}}
+ };
+
+ void test2() {
+ B b;
+ const S2 s;
+ s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S2'; did you mean 'method'}} expected-error{{no matching member function for call to 'method'}}
+ }
}
+
+namespace b6956809_test2 {
+ template<typename T> struct Err { typename T::error n; }; // expected-error{{type 'void *' cannot be used prior to '::' because it has no members}}
+ struct S {
+ template<typename T> typename Err<T>::type method(T); // expected-note{{in instantiation of template class 'b6956809_test2::Err<void *>' requested here}} expected-note{{while substituting deduced template arguments into function template 'method' [with T = void *]}}
+ template<typename T> int method(T *);
+ };
+
+ void test() {
+ S s;
+ int k = s.methodd((void*)0); // expected-error{{no member named 'methodd' in 'b6956809_test2::S'; did you mean 'method'?}}
+ }
}
-struct DataStruct {void foo();};
-struct T {
- DataStruct data_struct;
- void f();
+// This test should have one correction, followed by an error without a
+// suggestion due to exceeding the maximum number of typos for which correction
+// is attempted.
+namespace CorrectTypo_has_reached_its_limit {
+int flibberdy(); // expected-note{{'flibberdy' declared here}}
+int no_correction() {
+ return hibberdy() + // expected-error{{use of undeclared identifier 'hibberdy'; did you mean 'flibberdy'?}}
+ gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'$}}
};
-// should be void T::f();
-void f() {
- data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}}
}
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 665cfe7e9118..4991ebee8b31 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -340,7 +340,10 @@ namespace {
};
struct E {
- int a, b, c;
+ int b = 1;
+ int c = 1;
+ int a; // This field needs to be last to prevent the cross field
+ // uninitialized warning.
E(char (*)[1]) : a(a ? b : c) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[2]) : a(b ? a : a) {} // expected-warning 2{{field 'a' is uninitialized when used here}}
E(char (*)[3]) : a(b ? (a) : c) {} // expected-warning {{field 'a' is uninitialized when used here}}
@@ -459,7 +462,7 @@ namespace in_class_initializers {
};
struct U {
- U() : a(b + 1), b(a + 1) {} // FIXME: Warn here.
+ U() : a(b + 1), b(a + 1) {} // expected-warning{{field 'b' is uninitialized when used here}}
int a = 42; // Note: because a and b are in the member initializer list, these initializers are ignored.
int b = 1;
};
@@ -484,7 +487,8 @@ namespace references {
}
struct T {
- T() : a(b), b(a) {} // FIXME: Warn here.
+ T() // expected-note{{during field initialization in this constructor}}
+ : a(b), b(a) {} // expected-warning{{reference 'b' is not yet bound to a value when used here}}
int &a, &b;
int &c = c; // expected-warning{{reference 'c' is not yet bound to a value when used here}}
};
@@ -523,3 +527,204 @@ namespace lambdas {
A a2([&] { return a2.x; }); // ok
}
}
+
+namespace record_fields {
+ struct A {
+ A() {}
+ A get();
+ static A num();
+ static A copy(A);
+ static A something(A&);
+ };
+
+ A ref(A&);
+ A const_ref(const A&);
+ A pointer(A*);
+ A normal(A);
+
+ struct B {
+ A a;
+ B(char (*)[1]) : a(a) {} // expected-warning {{uninitialized}}
+ B(char (*)[2]) : a(a.get()) {} // expected-warning {{uninitialized}}
+ B(char (*)[3]) : a(a.num()) {}
+ B(char (*)[4]) : a(a.copy(a)) {} // expected-warning {{uninitialized}}
+ B(char (*)[5]) : a(a.something(a)) {}
+ B(char (*)[6]) : a(ref(a)) {}
+ B(char (*)[7]) : a(const_ref(a)) {}
+ B(char (*)[8]) : a(pointer(&a)) {}
+ B(char (*)[9]) : a(normal(a)) {} // expected-warning {{uninitialized}}
+ };
+ struct C {
+ C() {} // expected-note4{{in this constructor}}
+ A a1 = a1; // expected-warning {{uninitialized}}
+ A a2 = a2.get(); // expected-warning {{uninitialized}}
+ A a3 = a3.num();
+ A a4 = a4.copy(a4); // expected-warning {{uninitialized}}
+ A a5 = a5.something(a5);
+ A a6 = ref(a6);
+ A a7 = const_ref(a7);
+ A a8 = pointer(&a8);
+ A a9 = normal(a9); // expected-warning {{uninitialized}}
+ };
+ struct D { // expected-note4{{in the implicit default constructor}}
+ A a1 = a1; // expected-warning {{uninitialized}}
+ A a2 = a2.get(); // expected-warning {{uninitialized}}
+ A a3 = a3.num();
+ A a4 = a4.copy(a4); // expected-warning {{uninitialized}}
+ A a5 = a5.something(a5);
+ A a6 = ref(a6);
+ A a7 = const_ref(a7);
+ A a8 = pointer(&a8);
+ A a9 = normal(a9); // expected-warning {{uninitialized}}
+ };
+ D d;
+ struct E {
+ A a1 = a1;
+ A a2 = a2.get();
+ A a3 = a3.num();
+ A a4 = a4.copy(a4);
+ A a5 = a5.something(a5);
+ A a6 = ref(a6);
+ A a7 = const_ref(a7);
+ A a8 = pointer(&a8);
+ A a9 = normal(a9);
+ };
+}
+
+namespace cross_field_warnings {
+ struct A {
+ int a, b;
+ A() {}
+ A(char (*)[1]) : b(a) {} // expected-warning{{field 'a' is uninitialized when used here}}
+ A(char (*)[2]) : a(b) {} // expected-warning{{field 'b' is uninitialized when used here}}
+ };
+
+ struct B {
+ int a = b; // expected-warning{{field 'b' is uninitialized when used here}}
+ int b;
+ B() {} // expected-note{{during field initialization in this constructor}}
+ };
+
+ struct C {
+ int a;
+ int b = a; // expected-warning{{field 'a' is uninitialized when used here}}
+ C(char (*)[1]) : a(5) {}
+ C(char (*)[2]) {} // expected-note{{during field initialization in this constructor}}
+ };
+
+ struct D {
+ int a;
+ int &b;
+ int &c = a;
+ int d = b;
+ D() : b(a) {}
+ };
+
+ struct E {
+ int a;
+ int get();
+ static int num();
+ E() {}
+ E(int) {}
+ };
+
+ struct F {
+ int a;
+ E e;
+ int b;
+ F(char (*)[1]) : a(e.get()) {} // expected-warning{{field 'e' is uninitialized when used here}}
+ F(char (*)[2]) : a(e.num()) {}
+ F(char (*)[3]) : e(a) {} // expected-warning{{field 'a' is uninitialized when used here}}
+ F(char (*)[4]) : a(4), e(a) {}
+ F(char (*)[5]) : e(b) {} // expected-warning{{field 'b' is uninitialized when used here}}
+ F(char (*)[6]) : e(b), b(4) {} // expected-warning{{field 'b' is uninitialized when used here}}
+ };
+
+ struct G {
+ G(const A&) {};
+ };
+
+ struct H {
+ A a1;
+ G g;
+ A a2;
+ H() : g(a1) {}
+ H(int) : g(a2) {}
+ };
+
+ struct I {
+ I(int*) {}
+ };
+
+ struct J : public I {
+ int *a;
+ int *b;
+ int c;
+ J() : I((a = new int(5))), b(a), c(*a) {}
+ };
+
+ struct K {
+ int a = (b = 5);
+ int b = b + 5;
+ };
+
+ struct L {
+ int a = (b = 5);
+ int b = b + 5; // expected-warning{{field 'b' is uninitialized when used here}}
+ L() : a(5) {} // expected-note{{during field initialization in this constructor}}
+ };
+
+ struct M { };
+
+ struct N : public M {
+ int a;
+ int b;
+ N() : b(a) { } // expected-warning{{field 'a' is uninitialized when used here}}
+ };
+
+ struct O {
+ int x = 42;
+ int get() { return x; }
+ };
+
+ struct P {
+ O o;
+ int x = o.get();
+ P() : x(o.get()) { }
+ };
+
+ struct Q {
+ int a;
+ int b;
+ int &c;
+ Q() :
+ a(c = 5), // expected-warning{{reference 'c' is not yet bound to a value when used here}}
+ b(c), // expected-warning{{reference 'c' is not yet bound to a value when used here}}
+ c(a) {}
+ };
+
+ struct R {
+ int a;
+ int b;
+ int c;
+ int d = a + b + c;
+ R() : a(c = 5), b(c), c(a) {}
+ };
+}
+
+namespace base_class {
+ struct A {
+ A (int) {}
+ };
+
+ struct B : public A {
+ int x;
+ B() : A(x) {} // expected-warning{{field 'x' is uninitialized when used here}}
+ };
+
+ struct C : public A {
+ int x;
+ int y;
+ C() : A(y = 4), x(y) {}
+ };
+}
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
index ce5972bf2dc5..f2c84df242ff 100644
--- a/test/SemaCXX/unknown-type-name.cpp
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -93,14 +93,14 @@ template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing
template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
-template<typename T> int junk1(T::junk); // expected-error{{declared as a template}}
+template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++1y extension}}
template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}}
template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
// FIXME: We can tell this was intended to be a function because it does not
// have a dependent nested name specifier.
-template<typename T> int i(T::type, int()); // expected-error{{variable 'i' declared as a template}}
+template<typename T> int i(T::type, int()); // expected-warning{{variable templates are a C++1y extension}}
// FIXME: We know which type specifier should have been specified here. Provide
// a fix-it to add 'typename A<T>::type'
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index ebe97f6cca0d..24d92f175c30 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -118,3 +118,45 @@ namespace foo
using ::foo::Class1::Function; // expected-error{{incomplete type 'foo::Class1' named in nested name specifier}}
};
}
+
+// Don't suggest non-typenames for positions requiring typenames.
+namespace using_suggestion_tyname_val {
+namespace N { void FFF() {} }
+using typename N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_tyname_val::N'}}
+}
+
+namespace using_suggestion_member_tyname_val {
+class CCC { public: void AAA() { } };
+class DDD : public CCC { public: using typename CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_tyname_val::CCC'}}
+}
+
+namespace using_suggestion_tyname_val_dropped_specifier {
+void FFF() {}
+namespace N { }
+using typename N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_tyname_val_dropped_specifier::N'}}
+}
+
+// Currently hints aren't provided to drop out the incorrect M::.
+namespace using_suggestion_ty_dropped_nested_specifier {
+namespace N {
+class AAA {}; // expected-note {{'N::AAA' declared here}}
+namespace M { }
+}
+using N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_nested_specifier::N::M'; did you mean 'N::AAA'?}}
+}
+
+namespace using_suggestion_tyname_ty_dropped_nested_specifier {
+namespace N {
+class AAA {}; // expected-note {{'N::AAA' declared here}}
+namespace M { }
+}
+using typename N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_nested_specifier::N::M'; did you mean 'N::AAA'?}}
+}
+
+namespace using_suggestion_val_dropped_nested_specifier {
+namespace N {
+void FFF() {} // expected-note {{'N::FFF' declared here}}
+namespace M { }
+}
+using N::M::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_nested_specifier::N::M'; did you mean 'N::FFF'?}}
+}
diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp
index 2f8abca02d6e..8314688bcbc7 100644
--- a/test/SemaCXX/using-decl-templates.cpp
+++ b/test/SemaCXX/using-decl-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T> struct A {
void f() { }
@@ -80,3 +80,15 @@ namespace PR10883 {
void foo(const Container& current); // expected-error {{unknown type name 'Container'}}
};
}
+
+template<typename T> class UsingTypenameNNS {
+ using typename T::X;
+ typename X::X x;
+};
+
+namespace aliastemplateinst {
+ template<typename T> struct A { };
+ template<typename T> using APtr = A<T*>; // expected-note{{previous use is here}}
+
+ template struct APtr<int>; // expected-error{{elaborated type refers to a non-tag type}}
+}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index da06d957180e..56dafc41f132 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -17,6 +17,10 @@ void t1()
g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
g(10, version);
+
+ void (*ptr)(int, ...) = g;
+ ptr(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
+ ptr(10, version);
}
void t2()
@@ -25,9 +29,17 @@ void t2()
c.g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
c.g(10, version);
-
+
+ void (C::*ptr)(int, ...) = &C::g;
+ (c.*ptr)(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
+ (c.*ptr)(10, version);
+
C::h(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
C::h(10, version);
+
+ void (*static_ptr)(int, ...) = &C::h;
+ static_ptr(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
+ static_ptr(10, version);
}
int (^block)(int, ...);
@@ -141,3 +153,39 @@ namespace t10 {
s(f);
}
}
+
+namespace t11 {
+ typedef void(*function_ptr)(int, ...);
+ typedef void(C::*member_ptr)(int, ...);
+ typedef void(^block_ptr)(int, ...);
+
+ function_ptr get_f_ptr();
+ member_ptr get_m_ptr();
+ block_ptr get_b_ptr();
+
+ function_ptr arr_f_ptr[5];
+ member_ptr arr_m_ptr[5];
+ block_ptr arr_b_ptr[5];
+
+ void test() {
+ C c(10);
+
+ (get_f_ptr())(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
+ (get_f_ptr())(10, version);
+
+ (c.*get_m_ptr())(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
+ (c.*get_m_ptr())(10, version);
+
+ (get_b_ptr())(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}}
+ (get_b_ptr())(10, version);
+
+ (arr_f_ptr[3])(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
+ (arr_f_ptr[3])(10, version);
+
+ (c.*arr_m_ptr[3])(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
+ (c.*arr_m_ptr[3])(10, version);
+
+ (arr_b_ptr[3])(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}}
+ (arr_b_ptr[3])(10, version);
+ }
+}
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index 4d2d064b32f1..7957c23e3e24 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -37,7 +37,7 @@ void f2_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
}
// Test the conditional operator with vector types.
-void conditional(bool Cond, char16 c16, longlong16 ll16, char16_e c16e,
+void conditional(bool Cond, char16 c16, longlong16 ll16, char16_e c16e,
longlong16_e ll16e) {
// Conditional operators with the same type.
__typeof__(Cond? c16 : c16) *c16p1 = &c16;
@@ -105,11 +105,11 @@ struct convertible_to { // expected-note 3 {{candidate function (the implicit co
operator T() const;
};
-void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16,
+void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16,
char16_e c16e, longlong16_e ll16e,
- convertible_to<char16> to_c16,
- convertible_to<longlong16> to_ll16,
- convertible_to<char16_e> to_c16e,
+ convertible_to<char16> to_c16,
+ convertible_to<longlong16> to_ll16,
+ convertible_to<char16_e> to_c16e,
convertible_to<longlong16_e> to_ll16e,
convertible_to<char16&> rto_c16,
convertible_to<char16_e&> rto_c16e) {
@@ -183,7 +183,7 @@ void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16,
(void)(Cond? to_c16 : to_c16e);
(void)(Cond? to_ll16e : to_ll16);
-
+
// These 2 are convertable with -flax-vector-conversions (default)
(void)(Cond? to_c16 : to_ll16);
(void)(Cond? to_c16e : to_ll16e);
@@ -278,3 +278,10 @@ void test_pseudo_dtor(fltx4 *f) {
(*f).~fltx4();
test_pseudo_dtor_tmpl(f);
}
+
+// PR16204
+typedef __attribute__((ext_vector_type(4))) int vi4;
+const int &reference_to_vec_element = vi4(1).x;
+
+// PR12649
+typedef bool bad __attribute__((__vector_size__(16))); // expected-error {{invalid vector element type 'bool'}}
diff --git a/test/SemaCXX/virtual-base-used.cpp b/test/SemaCXX/virtual-base-used.cpp
index d147b13f04fd..04518ce4d47b 100644
--- a/test/SemaCXX/virtual-base-used.cpp
+++ b/test/SemaCXX/virtual-base-used.cpp
@@ -13,19 +13,19 @@ struct D : public virtual B {
virtual void foo();
~D();
};
-void D::foo() { // expected-note {{implicit default destructor for 'B' first required here}}
+void D::foo() { // expected-note {{implicit destructor for 'B' first required here}}
}
struct E : public virtual A {
NoDestroy x; // expected-error {{field of type 'NoDestroy' has private destructor}}
};
-struct F : public E { // expected-note {{implicit default destructor for 'E' first required here}}
+struct F : public E { // expected-note {{implicit destructor for 'E' first required here}}
};
struct G : public virtual F {
virtual void foo();
~G();
};
-void G::foo() { // expected-note {{implicit default destructor for 'F' first required here}}
+void G::foo() { // expected-note {{implicit destructor for 'F' first required here}}
}
struct H : public virtual A {
@@ -38,5 +38,5 @@ struct J : public I {
virtual void foo();
~J();
};
-void J::foo() { // expected-note {{implicit default destructor for 'H' first required here}}
+void J::foo() { // expected-note {{implicit destructor for 'H' first required here}}
}
diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp
index 09a30b93605e..80ce0298ba98 100644
--- a/test/SemaCXX/virtual-member-functions-key-function.cpp
+++ b/test/SemaCXX/virtual-member-functions-key-function.cpp
@@ -4,7 +4,7 @@ struct A {
};
struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
- B() { } // expected-note {{implicit default destructor for 'B' first required here}}
+ B() { } // expected-note {{implicit destructor for 'B' first required here}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
};
@@ -14,7 +14,7 @@ struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}
void f() {
(void)new B;
- (void)new C; // expected-note {{implicit default destructor for 'C' first required here}}
+ (void)new C; // expected-note {{implicit destructor for 'C' first required here}}
}
// Make sure that the key-function computation is consistent when the
diff --git a/test/SemaCXX/virtual-override-x86.cpp b/test/SemaCXX/virtual-override-x86.cpp
index ad70d3f22437..75d8af3b3ea3 100644
--- a/test/SemaCXX/virtual-override-x86.cpp
+++ b/test/SemaCXX/virtual-override-x86.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11 -cxx-abi microsoft
namespace PR14339 {
class A {
@@ -28,6 +28,6 @@ namespace PR14339 {
class F : public E {
public:
- void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void ()') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}}
+ void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void () __attribute__((thiscall))') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}}
};
}
diff --git a/test/SemaCXX/virtuals.cpp b/test/SemaCXX/virtuals.cpp
index a340e9d86b65..6b8231d4e1e2 100644
--- a/test/SemaCXX/virtuals.cpp
+++ b/test/SemaCXX/virtuals.cpp
@@ -45,3 +45,9 @@ namespace rdar9670557 {
func *h = 0;
};
}
+
+namespace pr8264 {
+ struct Test {
+ virtual virtual void func(); // expected-warning {{duplicate 'virtual' declaration specifier}}
+ };
+}
diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp
new file mode 100644
index 000000000000..64fdc00dc516
--- /dev/null
+++ b/test/SemaCXX/warn-consumed-analysis.cpp
@@ -0,0 +1,795 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -fcxx-exceptions -std=c++11 %s
+
+// TODO: Switch to using macros for the expected warnings.
+
+#define CALLABLE_WHEN(...) __attribute__ ((callable_when(__VA_ARGS__)))
+#define CONSUMABLE(state) __attribute__ ((consumable(state)))
+#define PARAM_TYPESTATE(state) __attribute__ ((param_typestate(state)))
+#define RETURN_TYPESTATE(state) __attribute__ ((return_typestate(state)))
+#define SET_TYPESTATE(state) __attribute__ ((set_typestate(state)))
+#define TEST_TYPESTATE(state) __attribute__ ((test_typestate(state)))
+
+typedef decltype(nullptr) nullptr_t;
+
+template <typename T>
+class CONSUMABLE(unconsumed) ConsumableClass {
+ T var;
+
+public:
+ ConsumableClass();
+ ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed);
+ ConsumableClass(T val) RETURN_TYPESTATE(unconsumed);
+ ConsumableClass(ConsumableClass<T> &other);
+ ConsumableClass(ConsumableClass<T> &&other);
+
+ ConsumableClass<T>& operator=(ConsumableClass<T> &other);
+ ConsumableClass<T>& operator=(ConsumableClass<T> &&other);
+ ConsumableClass<T>& operator=(nullptr_t) SET_TYPESTATE(consumed);
+
+ template <typename U>
+ ConsumableClass<T>& operator=(ConsumableClass<U> &other);
+
+ template <typename U>
+ ConsumableClass<T>& operator=(ConsumableClass<U> &&other);
+
+ void operator()(int a) SET_TYPESTATE(consumed);
+ void operator*() const CALLABLE_WHEN("unconsumed");
+ void unconsumedCall() const CALLABLE_WHEN("unconsumed");
+ void callableWhenUnknown() const CALLABLE_WHEN("unconsumed", "unknown");
+
+ bool isValid() const TEST_TYPESTATE(unconsumed);
+ operator bool() const TEST_TYPESTATE(unconsumed);
+ bool operator!=(nullptr_t) const TEST_TYPESTATE(unconsumed);
+ bool operator==(nullptr_t) const TEST_TYPESTATE(consumed);
+
+ void constCall() const;
+ void nonconstCall();
+
+ void consume() SET_TYPESTATE(consumed);
+ void unconsume() SET_TYPESTATE(unconsumed);
+};
+
+class CONSUMABLE(unconsumed) DestructorTester {
+public:
+ DestructorTester() RETURN_TYPESTATE(unconsumed);
+ DestructorTester(int);
+
+ void operator*() CALLABLE_WHEN("unconsumed");
+
+ ~DestructorTester() CALLABLE_WHEN("consumed");
+};
+
+void baf0(const ConsumableClass<int> var);
+void baf1(const ConsumableClass<int> &var);
+void baf2(const ConsumableClass<int> *var);
+
+void baf3(ConsumableClass<int> var);
+void baf4(ConsumableClass<int> &var);
+void baf5(ConsumableClass<int> *var);
+void baf6(ConsumableClass<int> &&var);
+
+ConsumableClass<int> returnsUnconsumed() {
+ return ConsumableClass<int>(); // expected-warning {{return value not in expected state; expected 'unconsumed', observed 'consumed'}}
+}
+
+ConsumableClass<int> returnsConsumed() RETURN_TYPESTATE(consumed);
+ConsumableClass<int> returnsConsumed() {
+ return ConsumableClass<int>();
+}
+
+ConsumableClass<int> returnsUnknown() RETURN_TYPESTATE(unknown);
+
+void testInitialization() {
+ ConsumableClass<int> var0;
+ ConsumableClass<int> var1 = ConsumableClass<int>();
+
+ var0 = ConsumableClass<int>();
+
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ if (var0.isValid()) {
+ *var0;
+ *var1;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ }
+}
+
+void testDestruction() {
+ DestructorTester D0(42), D1(42);
+
+ *D0;
+ *D1;
+
+ DestructorTester D2;
+ *D2;
+
+ D0.~DestructorTester(); // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}}
+
+ return; // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} \
+ expected-warning {{invalid invocation of method '~DestructorTester' on object 'D1' while it is in the 'unconsumed' state}} \
+ expected-warning {{invalid invocation of method '~DestructorTester' on object 'D2' while it is in the 'unconsumed' state}}
+}
+
+void testTempValue() {
+ *ConsumableClass<int>(); // expected-warning {{invalid invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}}
+}
+
+void testSimpleRValueRefs() {
+ ConsumableClass<int> var0;
+ ConsumableClass<int> var1(42);
+
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1;
+
+ var0 = static_cast<ConsumableClass<int>&&>(var1);
+
+ *var0;
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+}
+
+void testIfStmt() {
+ ConsumableClass<int> var;
+
+ if (var.isValid()) {
+ *var;
+ } else {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+ }
+
+ if (!var.isValid()) {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+ } else {
+ *var;
+ }
+
+ if (var) {
+ // Empty
+ } else {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+ }
+
+ if (var != nullptr) {
+ // Empty
+ } else {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+ }
+
+ if (var == nullptr) {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+ } else {
+ // Empty
+ }
+}
+
+void testComplexConditionals0() {
+ ConsumableClass<int> var0, var1, var2;
+
+ if (var0 && var1) {
+ *var0;
+ *var1;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ if (var0 || var1) {
+ *var0;
+ *var1;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ if (var0 && !var1) {
+ *var0;
+ *var1;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ if (var0 || !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (!var0 && !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (!var0 || !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (!(var0 && var1)) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (!(var0 || var1)) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (var0 && var1 && var2) {
+ *var0;
+ *var1;
+ *var2;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}}
+ }
+
+#if 0
+ // FIXME: Get this test to pass.
+ if (var0 || var1 || var2) {
+ *var0;
+ *var1;
+ *var2;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}}
+ }
+#endif
+}
+
+void testComplexConditionals1() {
+ ConsumableClass<int> var0, var1, var2;
+
+ // Coerce all variables into the unknown state.
+ baf4(var0);
+ baf4(var1);
+ baf4(var2);
+
+ if (var0 && var1) {
+ *var0;
+ *var1;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ }
+
+ if (var0 || var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ if (var0 && !var1) {
+ *var0;
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ }
+
+ if (var0 || !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1;
+ }
+
+ if (!var0 && !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ }
+
+ if (!(var0 || var1)) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ }
+
+ if (!var0 || !var1) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (!(var0 && var1)) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+
+ } else {
+ *var0;
+ *var1;
+ }
+
+ if (var0 && var1 && var2) {
+ *var0;
+ *var1;
+ *var2;
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}}
+ }
+
+#if 0
+ // FIXME: Get this test to pass.
+ if (var0 || var1 || var2) {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}}
+ *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}}
+
+ } else {
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}}
+ }
+#endif
+}
+
+void testStateChangeInBranch() {
+ ConsumableClass<int> var;
+
+ // Make var enter the 'unknown' state.
+ baf4(var);
+
+ if (!var) {
+ var = ConsumableClass<int>(42);
+ }
+
+ *var;
+}
+
+void testFunctionParam(ConsumableClass<int> param) {
+
+ if (param.isValid()) {
+ *param;
+ } else {
+ *param;
+ }
+
+ param = nullptr;
+ *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}}
+}
+
+void testParamReturnTypestateCallee(bool cond, ConsumableClass<int> &Param RETURN_TYPESTATE(unconsumed)) { // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}}
+
+ if (cond) {
+ Param.consume();
+ return; // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}}
+ }
+
+ Param.consume();
+}
+
+void testParamReturnTypestateCaller() {
+ ConsumableClass<int> var;
+
+ testParamReturnTypestateCallee(true, var);
+
+ *var;
+}
+
+void testParamTypestateCallee(ConsumableClass<int> Param0 PARAM_TYPESTATE(consumed),
+ ConsumableClass<int> &Param1 PARAM_TYPESTATE(consumed)) {
+
+ *Param0; // expected-warning {{invalid invocation of method 'operator*' on object 'Param0' while it is in the 'consumed' state}}
+ *Param1; // expected-warning {{invalid invocation of method 'operator*' on object 'Param1' while it is in the 'consumed' state}}
+}
+
+void testParamTypestateCaller() {
+ ConsumableClass<int> Var0, Var1(42);
+
+ testParamTypestateCallee(Var0, Var1); // expected-warning {{argument not in expected state; expected 'consumed', observed 'unconsumed'}}
+}
+
+void baf3(ConsumableClass<int> var) {
+ *var;
+}
+
+void baf4(ConsumableClass<int> &var) {
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}}
+}
+
+void baf6(ConsumableClass<int> &&var) {
+ *var;
+}
+
+void testCallingConventions() {
+ ConsumableClass<int> var(42);
+
+ baf0(var);
+ *var;
+
+ baf1(var);
+ *var;
+
+ baf2(&var);
+ *var;
+
+ baf4(var);
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}}
+
+ var = ConsumableClass<int>(42);
+ baf5(&var);
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}}
+
+ var = ConsumableClass<int>(42);
+ baf6(static_cast<ConsumableClass<int>&&>(var));
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+}
+
+void testConstAndNonConstMemberFunctions() {
+ ConsumableClass<int> var(42);
+
+ var.constCall();
+ *var;
+
+ var.nonconstCall();
+ *var;
+}
+
+void testFunctionParam0(ConsumableClass<int> param) {
+ *param;
+}
+
+void testFunctionParam1(ConsumableClass<int> &param) {
+ *param; // expected-warning {{invalid invocation of method 'operator*' on object 'param' while it is in the 'unknown' state}}
+}
+
+void testReturnStates() {
+ ConsumableClass<int> var;
+
+ var = returnsUnconsumed();
+ *var;
+
+ var = returnsConsumed();
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+}
+
+void testCallableWhen() {
+ ConsumableClass<int> var(42);
+
+ *var;
+
+ baf4(var);
+
+ var.callableWhenUnknown();
+}
+
+void testMoveAsignmentish() {
+ ConsumableClass<int> var0;
+ ConsumableClass<long> var1(42);
+
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+ *var1;
+
+ var0 = static_cast<ConsumableClass<long>&&>(var1);
+
+ *var0;
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+
+ var1 = ConsumableClass<long>(42);
+ var1 = nullptr;
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+}
+
+void testConditionalMerge() {
+ ConsumableClass<int> var;
+
+ if (var.isValid()) {
+ // Empty
+ }
+
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+
+ if (var.isValid()) {
+ // Empty
+ } else {
+ // Empty
+ }
+
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+}
+
+void testSetTypestate() {
+ ConsumableClass<int> var(42);
+
+ *var;
+
+ var.consume();
+
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+
+ var.unconsume();
+
+ *var;
+}
+
+void testConsumes0() {
+ ConsumableClass<int> var(nullptr);
+
+ *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
+}
+
+void testConsumes1() {
+ ConsumableClass<int> var(42);
+
+ var.unconsumedCall();
+ var(6);
+
+ var.unconsumedCall(); // expected-warning {{invalid invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}}
+}
+
+void testUnreachableBlock() {
+ ConsumableClass<int> var(42);
+
+ if (var) {
+ *var;
+ } else {
+ *var;
+ }
+
+ *var;
+}
+
+
+void testForLoop1() {
+ ConsumableClass<int> var0, var1(42);
+
+ for (int i = 0; i < 10; ++i) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}}
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+
+ *var1;
+ var1.consume();
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+}
+
+void testWhileLoop1() {
+ int i = 10;
+
+ ConsumableClass<int> var0, var1(42);
+
+ while (i-- > 0) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}}
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+
+ *var1;
+ var1.consume();
+ *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
+ }
+
+ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
+}
+
+typedef const int*& IntegerPointerReference;
+void testIsRValueRefishAndCanonicalType(IntegerPointerReference a) {}
+
+namespace ContinueICETest {
+
+bool cond1();
+bool cond2();
+
+static void foo1() {
+ while (cond1()) {
+ if (cond2())
+ continue;
+ }
+}
+
+static void foo2() {
+ while (true) {
+ if (false)
+ continue;
+ }
+}
+
+class runtime_error
+{
+public:
+ virtual ~runtime_error();
+};
+
+void read(bool sf) {
+ while (sf) {
+ if(sf) throw runtime_error();
+ }
+}
+
+} // end namespace ContinueICETest
+
+
+namespace InitializerAssertionFailTest {
+
+class CONSUMABLE(unconsumed) Status {
+ int code;
+
+public:
+ Status() RETURN_TYPESTATE(consumed);
+ Status(int c) RETURN_TYPESTATE(unconsumed);
+
+ Status(const Status &other);
+ Status(Status &&other);
+
+ Status& operator=(const Status &other) CALLABLE_WHEN("unknown", "consumed");
+ Status& operator=(Status &&other) CALLABLE_WHEN("unknown", "consumed");
+
+ bool check() const SET_TYPESTATE(consumed);
+ void ignore() const SET_TYPESTATE(consumed);
+ // Status& markAsChecked() { return *this; }
+
+ void clear() CALLABLE_WHEN("unknown", "consumed") SET_TYPESTATE(consumed);
+
+ ~Status() CALLABLE_WHEN("unknown", "consumed");
+};
+
+
+bool cond();
+Status doSomething();
+void handleStatus(const Status& s RETURN_TYPESTATE(consumed));
+void handleStatusPtr(const Status* s);
+
+void testSimpleTemporaries0() {
+ doSomething(); // expected-warning {{invalid invocation of method '~Status' on a temporary object while it is in the 'unconsumed' state}}
+}
+
+void testSimpleTemporaries1() {
+ doSomething().ignore();
+}
+
+void testSimpleTemporaries2() {
+ handleStatus(doSomething());
+}
+
+void testSimpleTemporaries3() {
+ Status s = doSomething();
+} // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}}
+
+void testSimpleTemporaries4() {
+ Status s = doSomething();
+ s.check();
+}
+
+void testSimpleTemporaries5() {
+ Status s = doSomething();
+ s.clear(); // expected-warning {{invalid invocation of method 'clear' on object 's' while it is in the 'unconsumed' state}}
+}
+
+void testSimpleTemporaries6() {
+ Status s = doSomething();
+ handleStatus(s);
+}
+
+void testSimpleTemporaries7() {
+ Status s;
+ s = doSomething();
+} // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}}
+
+void testTemporariesWithConditionals0() {
+ int a;
+
+ Status s = doSomething();
+ if (cond()) a = 0;
+ else a = 1;
+} // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}}
+
+void testTemporariesWithConditionals1() {
+ int a;
+
+ Status s = doSomething();
+ if (cond()) a = 0;
+ else a = 1;
+ s.ignore();
+}
+
+void testTemporariesWithConditionals2() {
+ int a;
+
+ Status s = doSomething();
+ s.ignore();
+ if (cond()) a = 0;
+ else a = 1;
+}
+
+void testTemporariesWithConditionals3() {
+ Status s = doSomething();
+ if (cond()) {
+ s.check();
+ }
+}
+
+void testTemporariesAndConstructors0() {
+ Status s(doSomething());
+ s.check();
+}
+
+void testTemporariesAndConstructors1() {
+ // Test the copy constructor.
+
+ Status s1 = doSomething();
+ Status s2(s1);
+ s2.check();
+} // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+
+void testTemporariesAndConstructors2() {
+ // Test the move constructor.
+
+ Status s1 = doSomething();
+ Status s2(static_cast<Status&&>(s1));
+ s2.check();
+}
+
+void testTemporariesAndOperators0() {
+ // Test the assignment operator.
+
+ Status s1 = doSomething();
+ Status s2;
+ s2 = s1;
+ s2.check();
+} // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+
+void testTemporariesAndOperators1() {
+ // Test the move assignment operator.
+
+ Status s1 = doSomething();
+ Status s2;
+ s2 = static_cast<Status&&>(s1);
+ s2.check();
+}
+
+void testTemporariesAndOperators2() {
+ Status s1 = doSomething();
+ Status s2 = doSomething();
+ s1 = s2; // expected-warning {{invalid invocation of method 'operator=' on object 's1' while it is in the 'unconsumed' state}}
+ s1.check();
+ s2.check();
+}
+
+} // end namespace InitializerAssertionFailTest
+
diff --git a/test/SemaCXX/warn-consumed-parsing.cpp b/test/SemaCXX/warn-consumed-parsing.cpp
new file mode 100644
index 000000000000..0a91636ea949
--- /dev/null
+++ b/test/SemaCXX/warn-consumed-parsing.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s
+
+#define CALLABLE_WHEN(...) __attribute__ ((callable_when(__VA_ARGS__)))
+#define CONSUMABLE(state) __attribute__ ((consumable(state)))
+#define SET_TYPESTATE(state) __attribute__ ((set_typestate(state)))
+#define RETURN_TYPESTATE(state) __attribute__ ((return_typestate(state)))
+#define TEST_TYPESTATE(state) __attribute__ ((test_typestate(state)))
+
+// FIXME: This test is here because the warning is issued by the Consumed
+// analysis, not SemaDeclAttr. The analysis won't run after an error
+// has been issued. Once the attribute propagation for template
+// instantiation has been fixed, this can be moved somewhere else and the
+// definition can be removed.
+int returnTypestateForUnconsumable() RETURN_TYPESTATE(consumed); // expected-warning {{return state set for an unconsumable type 'int'}}
+int returnTypestateForUnconsumable() {
+ return 0;
+}
+
+class AttrTester0 {
+ void consumes() __attribute__ ((set_typestate())); // expected-error {{attribute takes one argument}}
+ bool testUnconsumed() __attribute__ ((test_typestate())); // expected-error {{attribute takes one argument}}
+ void callableWhen() __attribute__ ((callable_when())); // expected-error {{attribute takes at least 1 argument}}
+};
+
+int var0 SET_TYPESTATE(consumed); // expected-warning {{'set_typestate' attribute only applies to methods}}
+int var1 TEST_TYPESTATE(consumed); // expected-warning {{'test_typestate' attribute only applies to methods}}
+int var2 CALLABLE_WHEN("consumed"); // expected-warning {{'callable_when' attribute only applies to methods}}
+int var3 CONSUMABLE(consumed); // expected-warning {{'consumable' attribute only applies to classes}}
+int var4 RETURN_TYPESTATE(consumed); // expected-warning {{'return_typestate' attribute only applies to functions}}
+
+void function0() SET_TYPESTATE(consumed); // expected-warning {{'set_typestate' attribute only applies to methods}}
+void function1() TEST_TYPESTATE(consumed); // expected-warning {{'test_typestate' attribute only applies to methods}}
+void function2() CALLABLE_WHEN("consumed"); // expected-warning {{'callable_when' attribute only applies to methods}}
+void function3() CONSUMABLE(consumed); // expected-warning {{'consumable' attribute only applies to classes}}
+
+class CONSUMABLE(unknown) AttrTester1 {
+ void callableWhen0() CALLABLE_WHEN("unconsumed");
+ void callableWhen1() CALLABLE_WHEN(42); // expected-error {{'callable_when' attribute requires a string}}
+ void callableWhen2() CALLABLE_WHEN("foo"); // expected-warning {{'callable_when' attribute argument not supported: foo}}
+ void consumes() SET_TYPESTATE(consumed);
+ bool testUnconsumed() TEST_TYPESTATE(consumed);
+};
+
+AttrTester1 returnTypestateTester0() RETURN_TYPESTATE(not_a_state); // expected-warning {{'return_typestate' attribute argument not supported: 'not_a_state'}}
+AttrTester1 returnTypestateTester1() RETURN_TYPESTATE(42); // expected-error {{'return_typestate' attribute requires an identifier}}
+
+void returnTypestateTester2(AttrTester1 &Param RETURN_TYPESTATE(unconsumed));
+
+class AttrTester2 {
+ void callableWhen() CALLABLE_WHEN("unconsumed"); // expected-warning {{consumed analysis attribute is attached to member of class 'AttrTester2' which isn't marked as consumable}}
+ void consumes() SET_TYPESTATE(consumed); // expected-warning {{consumed analysis attribute is attached to member of class 'AttrTester2' which isn't marked as consumable}}
+ bool testUnconsumed() TEST_TYPESTATE(consumed); // expected-warning {{consumed analysis attribute is attached to member of class 'AttrTester2' which isn't marked as consumable}}
+};
+
+class CONSUMABLE(42) AttrTester3; // expected-error {{'consumable' attribute requires an identifier}}
diff --git a/test/SemaCXX/warn-dangling-field.cpp b/test/SemaCXX/warn-dangling-field.cpp
index 95f8c61ebb77..eb65bd06692c 100644
--- a/test/SemaCXX/warn-dangling-field.cpp
+++ b/test/SemaCXX/warn-dangling-field.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify -std=c++11 %s
struct X {
X(int);
@@ -35,3 +35,17 @@ template <typename T> struct S4 {
template struct S4<int>; // no warning from this instantiation
template struct S4<int&>; // expected-note {{in instantiation}}
+
+struct S5 {
+ const X &x; // expected-note {{here}}
+};
+S5 s5 = { 0 }; // ok, lifetime-extended
+
+struct S6 {
+ S5 s5; // expected-note {{here}}
+ S6() : s5 { 0 } {} // expected-warning {{binding reference subobject of member 's5' to a temporary}}
+};
+
+struct S7 : S5 {
+ S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
+};
diff --git a/test/SemaCXX/warn-div-or-rem-by-zero.cpp b/test/SemaCXX/warn-div-or-rem-by-zero.cpp
new file mode 100644
index 000000000000..44b877eb1bc4
--- /dev/null
+++ b/test/SemaCXX/warn-div-or-rem-by-zero.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++1y -verify %s
+
+void div() {
+ (void)(42 / 0); // expected-warning{{division by zero is undefined}}
+ (void)(42 / false); // expected-warning{{division by zero is undefined}}
+ (void)(42 / !1); // expected-warning{{division by zero is undefined}}
+ (void)(42 / (1 - 1)); // expected-warning{{division by zero is undefined}}
+ (void)(42 / !(1 + 1)); // expected-warning{{division by zero is undefined}}
+ (void)(42 / (int)(0.0)); // expected-warning{{division by zero is undefined}}
+}
+
+void rem() {
+ (void)(42 % 0); // expected-warning{{remainder by zero is undefined}}
+ (void)(42 % false); // expected-warning{{remainder by zero is undefined}}
+ (void)(42 % !1); // expected-warning{{remainder by zero is undefined}}
+ (void)(42 % (1 - 1)); // expected-warning{{remainder by zero is undefined}}
+ (void)(42 % !(1 + 1)); // expected-warning{{remainder by zero is undefined}}
+ (void)(42 % (int)(0.0)); // expected-warning{{remainder by zero is undefined}}
+}
diff --git a/test/SemaCXX/warn-empty-body.cpp b/test/SemaCXX/warn-empty-body.cpp
index d643cedf09cc..d3aaac1d8c36 100644
--- a/test/SemaCXX/warn-empty-body.cpp
+++ b/test/SemaCXX/warn-empty-body.cpp
@@ -269,3 +269,8 @@ void test_template_inst(int x) {
test_template<double>(x);
}
+#define IDENTITY(a) a
+void test7(int x, int y) {
+ if (x) IDENTITY(); // no-warning
+}
+
diff --git a/test/SemaCXX/warn-func-not-needed.cpp b/test/SemaCXX/warn-func-not-needed.cpp
index d51c17356632..65721f44f570 100644
--- a/test/SemaCXX/warn-func-not-needed.cpp
+++ b/test/SemaCXX/warn-func-not-needed.cpp
@@ -42,3 +42,12 @@ namespace test4 {
g<int>();
}
}
+
+namespace test4 {
+ static void func();
+ void bar() {
+ void func();
+ func();
+ }
+ static void func() {}
+}
diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp
index 6330958df703..f57f0de70812 100644
--- a/test/SemaCXX/warn-global-constructors.cpp
+++ b/test/SemaCXX/warn-global-constructors.cpp
@@ -95,3 +95,9 @@ namespace pr8095 {
static Bar b;
}
}
+
+namespace referencemember {
+ struct A { int &a; };
+ int a;
+ A b = { a };
+}
diff --git a/test/SemaCXX/warn-logical-not-compare.cpp b/test/SemaCXX/warn-logical-not-compare.cpp
new file mode 100644
index 000000000000..3ecce474f149
--- /dev/null
+++ b/test/SemaCXX/warn-logical-not-compare.cpp
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlogical-not-parentheses -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wlogical-not-parentheses -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+bool getBool();
+int getInt();
+
+bool test1(int i1, int i2, bool b1, bool b2) {
+ bool ret;
+
+ ret = !i1 == i2;
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{10:10-10:10}:"("
+ // CHECK: fix-it:"{{.*}}":{10:18-10:18}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{10:9-10:9}:"("
+ // CHECK: fix-it:"{{.*}}":{10:12-10:12}:")"
+
+ ret = !i1 != i2;
+ //expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{21:10-21:10}:"("
+ // CHECK: fix-it:"{{.*}}":{21:18-21:18}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{21:9-21:9}:"("
+ // CHECK: fix-it:"{{.*}}":{21:12-21:12}:")"
+
+ ret = !i1 < i2;
+ //expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{32:10-32:10}:"("
+ // CHECK: fix-it:"{{.*}}":{32:17-32:17}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{32:9-32:9}:"("
+ // CHECK: fix-it:"{{.*}}":{32:12-32:12}:")"
+
+ ret = !i1 > i2;
+ //expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{43:10-43:10}:"("
+ // CHECK: fix-it:"{{.*}}":{43:17-43:17}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{43:9-43:9}:"("
+ // CHECK: fix-it:"{{.*}}":{43:12-43:12}:")"
+
+ ret = !i1 <= i2;
+ //expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{54:10-54:10}:"("
+ // CHECK: fix-it:"{{.*}}":{54:18-54:18}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{54:9-54:9}:"("
+ // CHECK: fix-it:"{{.*}}":{54:12-54:12}:")"
+
+ ret = !i1 >= i2;
+ //expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{65:10-65:10}:"("
+ // CHECK: fix-it:"{{.*}}":{65:18-65:18}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{65:9-65:9}:"("
+ // CHECK: fix-it:"{{.*}}":{65:12-65:12}:")"
+
+ ret = i1 == i2;
+ ret = i1 != i2;
+ ret = i1 < i2;
+ ret = i1 > i2;
+ ret = i1 <= i2;
+ ret = i1 >= i2;
+
+ // Warning silenced by parens.
+ ret = (!i1) == i2;
+ ret = (!i1) != i2;
+ ret = (!i1) < i2;
+ ret = (!i1) > i2;
+ ret = (!i1) <= i2;
+ ret = (!i1) >= i2;
+
+ ret = !b1 == b2;
+ ret = !b1 != b2;
+ ret = !b1 < b2;
+ ret = !b1 > b2;
+ ret = !b1 <= b2;
+ ret = !b1 >= b2;
+
+ ret = !getInt() == i1;
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{98:10-98:10}:"("
+ // CHECK: fix-it:"{{.*}}":{98:24-98:24}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{98:9-98:9}:"("
+ // CHECK: fix-it:"{{.*}}":{98:18-98:18}:")"
+
+ ret = (!getInt()) == i1;
+ ret = !getBool() == b1;
+ return ret;
+}
+
+enum E {e1, e2};
+E getE();
+
+bool test2 (E e) {
+ bool ret;
+ ret = e == e1;
+ ret = e == getE();
+ ret = getE() == e1;
+ ret = getE() == getE();
+
+ ret = !e == e1;
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{124:10-124:10}:"("
+ // CHECK: fix-it:"{{.*}}":{124:17-124:17}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{124:9-124:9}:"("
+ // CHECK: fix-it:"{{.*}}":{124:11-124:11}:")"
+
+ ret = !e == getE();
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{135:10-135:10}:"("
+ // CHECK: fix-it:"{{.*}}":{135:21-135:21}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{135:9-135:9}:"("
+ // CHECK: fix-it:"{{.*}}":{135:11-135:11}:")"
+
+ ret = !getE() == e1;
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{146:10-146:10}:"("
+ // CHECK: fix-it:"{{.*}}":{146:22-146:22}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{146:9-146:9}:"("
+ // CHECK: fix-it:"{{.*}}":{146:16-146:16}:")"
+
+ ret = !getE() == getE();
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK: fix-it:"{{.*}}":{157:10-157:10}:"("
+ // CHECK: fix-it:"{{.*}}":{157:26-157:26}:")"
+ // CHECK: to silence this warning
+ // CHECK: fix-it:"{{.*}}":{157:9-157:9}:"("
+ // CHECK: fix-it:"{{.*}}":{157:16-157:16}:")"
+
+ ret = !(e == e1);
+ ret = !(e == getE());
+ ret = !(getE() == e1);
+ ret = !(getE() == getE());
+
+ ret = (!e) == e1;
+ ret = (!e) == getE();
+ ret = (!getE()) == e1;
+ ret = (!getE()) == getE();
+
+ return ret;
+}
+
+bool PR16673(int x) {
+ bool ret;
+ // Make sure we don't emit a fixit for the left paren, but not the right paren.
+#define X(x) x
+ ret = X(!x == 1 && 1);
+ // expected-warning@-1 {{logical not is only applied to the left hand side of this comparison}}
+ // expected-note@-2 {{add parentheses after the '!' to evaluate the comparison first}}
+ // expected-note@-3 {{add parentheses around left hand side expression to silence this warning}}
+ // CHECK: to evaluate the comparison first
+ // CHECK-NOT: fix-it
+ // CHECK: to silence this warning
+ // CHECK-NOT: fix-it
+ return ret;
+}
diff --git a/test/SemaCXX/warn-loop-analysis.cpp b/test/SemaCXX/warn-loop-analysis.cpp
index 627bc51d1b0f..c666c48fc017 100644
--- a/test/SemaCXX/warn-loop-analysis.cpp
+++ b/test/SemaCXX/warn-loop-analysis.cpp
@@ -152,3 +152,111 @@ void test6() {
for (;x6;);
for (;y;);
}
+
+void test7() {
+ int i;
+ for (;;i++) { // expected-note{{incremented here}}
+ if (true) test7();
+ i++; // expected-warning{{incremented both}}
+ }
+ for (;;i++) { // expected-note{{incremented here}}
+ if (true) break;
+ ++i; // expected-warning{{incremented both}}
+ }
+ for (;;++i) { // expected-note{{incremented here}}
+ while (true) return;
+ i++; // expected-warning{{incremented both}}
+ }
+ for (;;++i) { // expected-note{{incremented here}}
+ ++i; // expected-warning{{incremented both}}
+ }
+
+ for (;;i--) { // expected-note{{decremented here}}
+ if (true) test7();
+ i--; // expected-warning{{decremented both}}
+ }
+ for (;;i--) { // expected-note{{decremented here}}
+ if (true) break;
+ --i; // expected-warning{{decremented both}}
+ }
+ for (;;--i) { // expected-note{{decremented here}}
+ while (true) return;
+ i--; // expected-warning{{decremented both}}
+ }
+ for (;;--i) { // expected-note{{decremented here}}
+ --i; // expected-warning{{decremented both}}
+ }
+
+ // Don't warn when loop is only one statement.
+ for (;;++i)
+ i++;
+ for (;;--i)
+ --i;
+
+ // Don't warn when loop has continue statement.
+ for (;;i++) {
+ if (true) continue;
+ i++;
+ }
+ for (;;i--) {
+ if (true) continue;
+ i--;
+ }
+}
+
+struct iterator {
+ iterator operator++() { return *this; }
+ iterator operator++(int) { return *this; }
+ iterator operator--() { return *this; }
+ iterator operator--(int) { return *this; }
+};
+void test8() {
+ iterator i;
+ for (;;i++) { // expected-note{{incremented here}}
+ if (true) test7();
+ i++; // expected-warning{{incremented both}}
+ }
+ for (;;i++) { // expected-note{{incremented here}}
+ if (true) break;
+ ++i; // expected-warning{{incremented both}}
+ }
+ for (;;++i) { // expected-note{{incremented here}}
+ while (true) return;
+ i++; // expected-warning{{incremented both}}
+ }
+ for (;;++i) { // expected-note{{incremented here}}
+ ++i; // expected-warning{{incremented both}}
+ }
+
+ for (;;i--) { // expected-note{{decremented here}}
+ if (true) test7();
+ i--; // expected-warning{{decremented both}}
+ }
+ for (;;i--) { // expected-note{{decremented here}}
+ if (true) break;
+ --i; // expected-warning{{decremented both}}
+ }
+ for (;;--i) { // expected-note{{decremented here}}
+ while (true) return;
+ i--; // expected-warning{{decremented both}}
+ }
+ for (;;--i) { // expected-note{{decremented here}}
+ --i; // expected-warning{{decremented both}}
+ }
+
+ // Don't warn when loop is only one statement.
+ for (;;++i)
+ i++;
+ for (;;--i)
+ --i;
+
+ // Don't warn when loop has continue statement.
+ for (;;i++) {
+ if (true) continue;
+ i++;
+ }
+ for (;;i--) {
+ if (true) continue;
+ i--;
+ }
+}
diff --git a/test/SemaCXX/warn-member-not-needed.cpp b/test/SemaCXX/warn-member-not-needed.cpp
new file mode 100644
index 000000000000..61bb3488c611
--- /dev/null
+++ b/test/SemaCXX/warn-member-not-needed.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunneeded-member-function %s
+
+namespace {
+ class A {
+ void g() {} // expected-warning {{is not needed and will not be emitted}}
+ template <typename T>
+ void foo() {
+ g();
+ }
+ };
+}
diff --git a/test/SemaCXX/warn-missing-variable-declarations.cpp b/test/SemaCXX/warn-missing-variable-declarations.cpp
index 12af9735d1a9..ad23e0429bbd 100644
--- a/test/SemaCXX/warn-missing-variable-declarations.cpp
+++ b/test/SemaCXX/warn-missing-variable-declarations.cpp
@@ -41,3 +41,9 @@ int CGood1::MGood1;
namespace {
int mgood4;
}
+
+class C {
+ void test() {
+ static int x = 0; // no-warn
+ }
+};
diff --git a/test/SemaCXX/warn-reinterpret-base-class.cpp b/test/SemaCXX/warn-reinterpret-base-class.cpp
index 67902f7a90d8..36b8fda55306 100644
--- a/test/SemaCXX/warn-reinterpret-base-class.cpp
+++ b/test/SemaCXX/warn-reinterpret-base-class.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wreinterpret-base-class -Wno-unused-volatile-lvalue %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits -Wreinterpret-base-class -Wno-unused-volatile-lvalue %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits -Wreinterpret-base-class -Wno-unused-volatile-lvalue %s 2>&1 | FileCheck %s
// PR 13824
class A {
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index bc4b40ead73d..ce6250d6da90 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -11,8 +11,10 @@
#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
#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__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
#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__)))
@@ -33,6 +35,9 @@ class __attribute__((lockable)) Mutex {
bool TryLock() __attribute__((exclusive_trylock_function(true)));
bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+
+ void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
+ void AssertReaderHeld() ASSERT_SHARED_LOCK();
};
class __attribute__((scoped_lockable)) MutexLock {
@@ -75,6 +80,7 @@ public:
T* get() const { return ptr_; }
T* operator->() const { return ptr_; }
T& operator*() const { return *ptr_; }
+ T& operator[](int i) const { return ptr_[i]; }
private:
T* ptr_;
@@ -102,14 +108,14 @@ class MutexWrapper {
public:
Mutex mu;
int x __attribute__((guarded_by(mu)));
- void MyLock() __attribute__((exclusive_lock_function(mu)));
+ void MyLock() __attribute__((exclusive_lock_function(mu)));
};
MutexWrapper sls_mw;
void sls_fun_0() {
sls_mw.mu.Lock();
- sls_mw.x = 5;
+ sls_mw.x = 5;
sls_mw.mu.Unlock();
}
@@ -3069,44 +3075,6 @@ void Foo::test1() {
#endif
}
-
-void Foo::test2() {
-/* FIXME: these tests depend on changes to the CFG.
- *
- if (mu_.TryLock() && c) {
- a = 0;
- unlock();
- }
- else return;
-
- if (c && mu_.TryLock()) {
- a = 0;
- unlock();
- }
- else return;
-
- if (!(mu_.TryLock() && c))
- return;
- a = 0;
- unlock();
-
- if (!(c && mu_.TryLock()))
- return;
- a = 0;
- unlock();
-
- if (!(mu_.TryLock() == 0) && c) {
- a = 0;
- unlock();
- }
-
- if (!mu_.TryLock() || c)
- return;
- a = 0;
- unlock();
-*/
-}
-
} // end namespace TryLockEqTest
@@ -3985,3 +3953,364 @@ private:
} // end namespace LockUnlockFunctionTest
+
+namespace AssertHeldTest {
+
+class Foo {
+public:
+ int c;
+ int a GUARDED_BY(mu_);
+ Mutex mu_;
+
+ void test1() {
+ mu_.AssertHeld();
+ int b = a;
+ a = 0;
+ }
+
+ void test2() {
+ mu_.AssertReaderHeld();
+ int b = a;
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ }
+
+ void test3() {
+ if (c) {
+ mu_.AssertHeld();
+ }
+ else {
+ mu_.AssertHeld();
+ }
+ int b = a;
+ a = 0;
+ }
+
+ void test4() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ mu_.AssertHeld();
+ int b = a;
+ a = 0;
+ }
+
+ void test5() UNLOCK_FUNCTION(mu_) {
+ mu_.AssertHeld();
+ mu_.Unlock();
+ }
+
+ void test6() {
+ mu_.AssertHeld();
+ mu_.Unlock();
+ } // should this be a warning?
+
+ void test7() {
+ if (c) {
+ mu_.AssertHeld();
+ }
+ else {
+ mu_.Lock();
+ }
+ int b = a;
+ a = 0;
+ mu_.Unlock();
+ }
+
+ void test8() {
+ if (c) {
+ mu_.Lock();
+ }
+ else {
+ mu_.AssertHeld();
+ }
+ int b = a;
+ a = 0;
+ mu_.Unlock();
+ }
+
+ void test9() {
+ if (c) {
+ mu_.AssertHeld();
+ }
+ else {
+ mu_.Lock(); // expected-note {{mutex acquired here}}
+ }
+ } // expected-warning {{mutex 'mu_' is still locked at the end of function}}
+
+ void test10() {
+ if (c) {
+ mu_.Lock(); // expected-note {{mutex acquired here}}
+ }
+ else {
+ mu_.AssertHeld();
+ }
+ } // expected-warning {{mutex 'mu_' is still locked at the end of function}}
+
+ void assertMu() ASSERT_EXCLUSIVE_LOCK(mu_);
+
+ void test11() {
+ assertMu();
+ int b = a;
+ a = 0;
+ }
+};
+
+} // end namespace AssertHeldTest
+
+
+namespace LogicalConditionalTryLock {
+
+class Foo {
+public:
+ Mutex mu;
+ int a GUARDED_BY(mu);
+ bool c;
+
+ bool newc();
+
+ void test1() {
+ if (c && mu.TryLock()) {
+ a = 0;
+ mu.Unlock();
+ }
+ }
+
+ void test2() {
+ bool b = mu.TryLock();
+ if (c && b) {
+ a = 0;
+ mu.Unlock();
+ }
+ }
+
+ void test3() {
+ if (c || !mu.TryLock())
+ return;
+ a = 0;
+ mu.Unlock();
+ }
+
+ void test4() {
+ while (c && mu.TryLock()) {
+ a = 0;
+ c = newc();
+ mu.Unlock();
+ }
+ }
+
+ void test5() {
+ while (c) {
+ if (newc() || !mu.TryLock())
+ break;
+ a = 0;
+ mu.Unlock();
+ }
+ }
+
+ void test6() {
+ mu.Lock();
+ do {
+ a = 0;
+ mu.Unlock();
+ } while (newc() && mu.TryLock());
+ }
+
+ void test7() {
+ for (bool b = mu.TryLock(); c && b;) {
+ a = 0;
+ mu.Unlock();
+ }
+ }
+
+ void test8() {
+ if (c && newc() && mu.TryLock()) {
+ a = 0;
+ mu.Unlock();
+ }
+ }
+
+ void test9() {
+ if (!(c && newc() && mu.TryLock()))
+ return;
+ a = 0;
+ mu.Unlock();
+ }
+
+ void test10() {
+ if (!(c || !mu.TryLock())) {
+ a = 0;
+ mu.Unlock();
+ }
+ }
+};
+
+} // end namespace LogicalConditionalTryLock
+
+
+
+namespace PtGuardedByTest {
+
+void doSomething();
+
+class Cell {
+ public:
+ int a;
+};
+
+
+// This mainly duplicates earlier tests, but just to make sure...
+class PtGuardedBySanityTest {
+ Mutex mu1;
+ Mutex mu2;
+ int* a GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ Cell* c GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ int sa[10] GUARDED_BY(mu1);
+ Cell sc[10] GUARDED_BY(mu1);
+
+ void test1() {
+ mu1.Lock();
+ if (a == 0) doSomething(); // OK, we don't dereference.
+ a = 0;
+ c = 0;
+ if (sa[0] == 42) doSomething();
+ sa[0] = 57;
+ if (sc[0].a == 42) doSomething();
+ sc[0].a = 57;
+ mu1.Unlock();
+ }
+
+ void test2() {
+ mu1.ReaderLock();
+ if (*a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'a' requires locking 'mu2'}}
+ *a = 0; // expected-warning {{writing the value pointed to by 'a' requires locking 'mu2' exclusively}}
+
+ if (c->a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'c' requires locking 'mu2'}}
+ c->a = 0; // expected-warning {{writing the value pointed to by 'c' requires locking 'mu2' exclusively}}
+
+ if ((*c).a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'c' requires locking 'mu2'}}
+ (*c).a = 0; // expected-warning {{writing the value pointed to by 'c' requires locking 'mu2' exclusively}}
+
+ if (a[0] == 42) doSomething(); // expected-warning {{reading the value pointed to by 'a' requires locking 'mu2'}}
+ a[0] = 57; // expected-warning {{writing the value pointed to by 'a' requires locking 'mu2' exclusively}}
+ if (c[0].a == 42) doSomething(); // expected-warning {{reading the value pointed to by 'c' requires locking 'mu2'}}
+ c[0].a = 57; // expected-warning {{writing the value pointed to by 'c' requires locking 'mu2' exclusively}}
+ mu1.Unlock();
+ }
+
+ void test3() {
+ mu2.Lock();
+ if (*a == 0) doSomething(); // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+ *a = 0; // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+
+ if (c->a == 0) doSomething(); // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+ c->a = 0; // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+
+ if ((*c).a == 0) doSomething(); // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+ (*c).a = 0; // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+
+ if (a[0] == 42) doSomething(); // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+ a[0] = 57; // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+ if (c[0].a == 42) doSomething(); // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+ c[0].a = 57; // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+ mu2.Unlock();
+ }
+
+ void test4() { // Literal arrays
+ if (sa[0] == 42) doSomething(); // expected-warning {{reading variable 'sa' requires locking 'mu1'}}
+ sa[0] = 57; // expected-warning {{writing variable 'sa' requires locking 'mu1' exclusively}}
+ if (sc[0].a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ sc[0].a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+
+ if (*sa == 42) doSomething(); // expected-warning {{reading variable 'sa' requires locking 'mu1'}}
+ *sa = 57; // expected-warning {{writing variable 'sa' requires locking 'mu1' exclusively}}
+ if ((*sc).a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ (*sc).a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+ if (sc->a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ sc->a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+ }
+
+ void test5() {
+ mu1.ReaderLock(); // OK -- correct use.
+ mu2.Lock();
+ if (*a == 0) doSomething();
+ *a = 0;
+
+ if (c->a == 0) doSomething();
+ c->a = 0;
+
+ if ((*c).a == 0) doSomething();
+ (*c).a = 0;
+ mu2.Unlock();
+ mu1.Unlock();
+ }
+};
+
+
+class SmartPtr_PtGuardedBy_Test {
+ Mutex mu1;
+ Mutex mu2;
+ SmartPtr<int> sp GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ SmartPtr<Cell> sq GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+
+ void test1() {
+ mu1.ReaderLock();
+ mu2.Lock();
+
+ sp.get();
+ if (*sp == 0) doSomething();
+ *sp = 0;
+ sq->a = 0;
+
+ if (sp[0] == 0) doSomething();
+ sp[0] = 0;
+
+ mu2.Unlock();
+ mu1.Unlock();
+ }
+
+ void test2() {
+ mu2.Lock();
+
+ sp.get(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ if (*sp == 0) doSomething(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ *sp = 0; // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ sq->a = 0; // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+
+ if (sp[0] == 0) doSomething(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ sp[0] = 0; // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ if (sq[0].a == 0) doSomething(); // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+ sq[0].a = 0; // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+
+ mu2.Unlock();
+ }
+
+ void test3() {
+ mu1.Lock();
+
+ sp.get();
+ if (*sp == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ *sp = 0; // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ sq->a = 0; // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+
+ if (sp[0] == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ sp[0] = 0; // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ if (sq[0].a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+ sq[0].a = 0; // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+
+ mu1.Unlock();
+ }
+};
+
+} // end namespace PtGuardedByTest
+
+
+namespace NonMemberCalleeICETest {
+
+class A {
+ void Run() {
+ (RunHelper)(); // expected-warning {{calling function 'RunHelper' requires exclusive lock on 'M'}}
+ }
+
+ void RunHelper() __attribute__((exclusive_locks_required(M)));
+ Mutex M;
+};
+
+} // end namespace NonMemberCalleeICETest
+
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index df9415cf8601..1bd4e439b7b0 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -8,8 +8,10 @@
#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
#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__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
#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__)))
@@ -24,7 +26,15 @@
class LOCKABLE Mutex {
public:
- void Lock();
+ void Lock() EXCLUSIVE_LOCK_FUNCTION();
+ void ReaderLock() SHARED_LOCK_FUNCTION();
+ void Unlock() UNLOCK_FUNCTION();
+
+ bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
+
+ void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
+ void AssertReaderHeld() ASSERT_SHARED_LOCK();
};
class UnlockableMu{
@@ -93,7 +103,7 @@ class Bar {
void noanal_fun() NO_THREAD_SAFETY_ANALYSIS;
void noanal_fun_args() __attribute__((no_thread_safety_analysis(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'no_thread_safety_analysis' attribute takes no arguments}}
int noanal_testfn(int y) NO_THREAD_SAFETY_ANALYSIS;
@@ -132,13 +142,13 @@ void noanal_fun_params(int lvar NO_THREAD_SAFETY_ANALYSIS); // \
int gv_var_noargs GUARDED_VAR;
int gv_var_args __attribute__((guarded_var(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'guarded_var' attribute takes no arguments}}
class GVFoo {
private:
int gv_field_noargs GUARDED_VAR;
int gv_field_args __attribute__((guarded_var(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'guarded_var' attribute takes no arguments}}
};
class GUARDED_VAR GV { // \
@@ -178,7 +188,7 @@ class PGVFoo {
int field_noargs PT_GUARDED_VAR; // \
// expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
int *gv_field_args __attribute__((pt_guarded_var(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'pt_guarded_var' attribute takes no arguments}}
};
class PT_GUARDED_VAR PGV { // \
@@ -186,7 +196,7 @@ class PT_GUARDED_VAR PGV { // \
};
int *pgv_var_args __attribute__((pt_guarded_var(1))); // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'pt_guarded_var' attribute takes no arguments}}
void pgv_function() PT_GUARDED_VAR; // \
@@ -215,7 +225,7 @@ class LOCKABLE LTestClass {
};
class __attribute__((lockable (1))) LTestClass_args { // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'lockable' attribute takes no arguments}}
};
void l_test_function() LOCKABLE; // \
@@ -255,7 +265,7 @@ class SCOPED_LOCKABLE SLTestClass {
};
class __attribute__((scoped_lockable (1))) SLTestClass_args { // \
- // expected-error {{attribute takes no arguments}}
+ // expected-error {{'scoped_lockable' attribute takes no arguments}}
};
void sl_test_function() SCOPED_LOCKABLE; // \
@@ -297,16 +307,18 @@ void sl_function_params(int lvar SCOPED_LOCKABLE); // \
int gb_var_arg GUARDED_BY(mu1);
+int gb_non_ascii GUARDED_BY(L"wide"); // expected-warning {{ignoring 'guarded_by' attribute because its argument is invalid}}
+
int gb_var_args __attribute__((guarded_by(mu1, mu2))); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'guarded_by' attribute takes one argument}}
int gb_var_noargs __attribute__((guarded_by)); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'guarded_by' attribute takes one argument}}
class GBFoo {
private:
int gb_field_noargs __attribute__((guarded_by)); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'guarded_by' attribute takes one argument}}
int gb_field_args GUARDED_BY(mu1);
};
@@ -364,12 +376,12 @@ int gb_var_arg_bad_4 GUARDED_BY(umu); // \
//1. Check applied to the right types & argument number
int *pgb_var_noargs __attribute__((pt_guarded_by)); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'pt_guarded_by' attribute takes one argument}}
int *pgb_ptr_var_arg PT_GUARDED_BY(mu1);
int *pgb_ptr_var_args __attribute__((pt_guarded_by(mu1, mu2))); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'pt_guarded_by' attribute takes one argument}}
int pgb_var_args PT_GUARDED_BY(mu1); // \
// expected-warning {{'pt_guarded_by' only applies to pointer types; type here is 'int'}}
@@ -377,7 +389,7 @@ int pgb_var_args PT_GUARDED_BY(mu1); // \
class PGBFoo {
private:
int *pgb_field_noargs __attribute__((pt_guarded_by)); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'pt_guarded_by' attribute takes one argument}}
int *pgb_field_args PT_GUARDED_BY(mu1);
};
@@ -750,11 +762,11 @@ int etf_function_9() EXCLUSIVE_TRYLOCK_FUNCTION(true);
// illegal attribute arguments
int etf_function_bad_1() EXCLUSIVE_TRYLOCK_FUNCTION(mu1); // \
- // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
int etf_function_bad_2() EXCLUSIVE_TRYLOCK_FUNCTION("mu"); // \
- // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
int etf_function_bad_3() EXCLUSIVE_TRYLOCK_FUNCTION(muDoublePointer); // \
- // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
int etf_function_bad_4() EXCLUSIVE_TRYLOCK_FUNCTION(1, "mu"); // \
// expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}}
@@ -824,11 +836,11 @@ int stf_function_9() SHARED_TRYLOCK_FUNCTION(true);
// illegal attribute arguments
int stf_function_bad_1() SHARED_TRYLOCK_FUNCTION(mu1); // \
- // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
int stf_function_bad_2() SHARED_TRYLOCK_FUNCTION("mu"); // \
- // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
int stf_function_bad_3() SHARED_TRYLOCK_FUNCTION(muDoublePointer); // \
- // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+ // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
int stf_function_bad_4() SHARED_TRYLOCK_FUNCTION(1, "mu"); // \
// expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}}
@@ -921,12 +933,12 @@ int uf_function_bad_7() UNLOCK_FUNCTION(0); // \
// Takes exactly one argument, a var/field
void lr_function() __attribute__((lock_returned)); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'lock_returned' attribute takes one argument}}
void lr_function_arg() LOCK_RETURNED(mu1);
void lr_function_args() __attribute__((lock_returned(mu1, mu2))); // \
- // expected-error {{attribute takes one argument}}
+ // expected-error {{'lock_returned' attribute takes one argument}}
int lr_testfn(int y) LOCK_RETURNED(mu1);
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index f36300af4d38..dd071258e29d 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -62,8 +62,8 @@ void test5() {
struct S {
int mem;
} s;
- S &foor() __attribute__((noreturn));
- foor()
+ S &foonr() __attribute__((noreturn));
+ foonr()
.mem; // expected-warning {{will never be executed}}
}
diff --git a/test/SemaCXX/warn-unsequenced.cpp b/test/SemaCXX/warn-unsequenced.cpp
index c7acfca6db31..54e16a5e6d50 100644
--- a/test/SemaCXX/warn-unsequenced.cpp
+++ b/test/SemaCXX/warn-unsequenced.cpp
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-unused %s
-int f(int, int);
+int f(int, int = 0);
struct A {
int x, y;
};
struct S {
S(int, int);
+ int n;
};
void test() {
@@ -32,6 +33,9 @@ void test() {
f(a = 0, a); // expected-warning {{unsequenced modification and access}}
f(a, a += 0); // expected-warning {{unsequenced modification and access}}
f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
+ a = f(++a); // ok
+ a = f(a++); // ok
+ a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}
// Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
// is evaluated only once.
@@ -47,6 +51,12 @@ void test() {
S str2 = { a++, a++ }; // ok
S str3 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}
+ struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
+ a = S { ++a, a++ }.n; // ok
+ A { ++a, a++ }.x; // ok
+ a = A { ++a, a++ }.x; // expected-warning {{unsequenced modifications}}
+ A { ++a, a++ }.x + A { ++a, a++ }.y; // expected-warning {{unsequenced modifications}}
+
(xs[2] && (a = 0)) + a; // ok
(0 && (a = 0)) + a; // ok
(1 && (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
@@ -58,6 +68,8 @@ void test() {
(xs[4] ? a : ++a) + a; // ok
(0 ? a : ++a) + a; // expected-warning {{unsequenced modification and access}}
(1 ? a : ++a) + a; // ok
+ (0 ? a : a++) + a; // expected-warning {{unsequenced modification and access}}
+ (1 ? a : a++) + a; // ok
(xs[5] ? ++a : ++a) + a; // FIXME: warn here
(++a, xs[6] ? ++a : 0) + a; // expected-warning {{unsequenced modification and access}}
diff --git a/test/SemaCXX/warn-unused-attribute.cpp b/test/SemaCXX/warn-unused-attribute.cpp
new file mode 100644
index 000000000000..72f96eea0b31
--- /dev/null
+++ b/test/SemaCXX/warn-unused-attribute.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
+struct __attribute__((warn_unused)) Test
+{
+ Test();
+ ~Test();
+ void use();
+};
+
+struct TestNormal
+{
+ TestNormal();
+};
+
+int main()
+{
+ Test unused; // expected-warning {{unused variable 'unused'}}
+ Test used;
+ TestNormal normal;
+ used.use();
+}
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index 9fb601130d3b..b0af5b332270 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -1,6 +1,41 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-c++11-extensions -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++11 %s
+#ifdef HEADER
+
+static void headerstatic() {} // expected-warning{{unused}}
+static inline void headerstaticinline() {}
+
+namespace {
+ void headeranon() {} // expected-warning{{unused}}
+ inline void headerinlineanon() {}
+}
+
+namespace test7
+{
+ template<typename T>
+ static inline void foo(T) { }
+
+ // This should not emit an unused-function warning since it inherits
+ // the static storage type from the base template.
+ template<>
+ inline void foo(int) { }
+
+ // Partial specialization
+ template<typename T, typename U>
+ static inline void bar(T, U) { }
+
+ template<typename U>
+ inline void bar(int, U) { }
+
+ template<>
+ inline void bar(int, int) { }
+};
+
+#else
+#define HEADER
+#include "warn-unused-filescoped.cpp"
+
static void f1(); // expected-warning{{unused}}
namespace {
@@ -37,8 +72,10 @@ namespace {
void S::m3() { } // expected-warning{{unused}}
-static inline void f4() { }
-const unsigned int cx = 0;
+static inline void f4() { } // expected-warning{{unused}}
+const unsigned int cx = 0; // expected-warning{{unused}}
+const unsigned int cy = 0;
+int f5() { return cy; }
static int x1; // expected-warning{{unused}}
@@ -98,7 +135,7 @@ namespace test5 {
// FIXME: We should produce warnings for both of these.
static const int m = n;
int x = sizeof(m);
- static const double d = 0.0;
+ static const double d = 0.0; // expected-warning{{not needed and will not be emitted}}
int y = sizeof(d);
}
@@ -133,27 +170,6 @@ namespace test6 {
};
}
-namespace test7
-{
- template<typename T>
- static inline void foo(T) { }
-
- // This should not emit an unused-function warning since it inherits
- // the static storage type from the base template.
- template<>
- inline void foo(int) { }
-
- // Partial specialization
- template<typename T, typename U>
- static inline void bar(T, U) { }
-
- template<typename U>
- inline void bar(int, U) { }
-
- template<>
- inline void bar(int, int) { }
-};
-
namespace pr14776 {
namespace {
struct X {};
@@ -161,3 +177,20 @@ namespace pr14776 {
X a = X(); // expected-warning {{unused variable 'a'}}
auto b = X(); // expected-warning {{unused variable 'b'}}
}
+
+namespace UndefinedInternalStaticMember {
+ namespace {
+ struct X {
+ static const unsigned x = 3;
+ int y[x];
+ };
+ }
+}
+
+namespace test8 {
+static void func();
+void bar() { void func() __attribute__((used)); }
+static void func() {}
+}
+
+#endif
diff --git a/test/SemaCXX/warn-unused-private-field.cpp b/test/SemaCXX/warn-unused-private-field.cpp
index 661442db9e9d..932a7dcea1da 100644
--- a/test/SemaCXX/warn-unused-private-field.cpp
+++ b/test/SemaCXX/warn-unused-private-field.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++11 %s
class NotFullyDefined {
public:
diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp
index b0bf61f38180..581af09080db 100644
--- a/test/SemaCXX/warn-unused-result.cpp
+++ b/test/SemaCXX/warn-unused-result.cpp
@@ -78,3 +78,19 @@ void lazy() {
DoYetAnotherThing();
}
}
+
+namespace PR17587 {
+struct [[clang::warn_unused_result]] Status;
+
+struct Foo {
+ Status Bar();
+};
+
+struct Status {};
+
+void Bar() {
+ Foo f;
+ f.Bar(); // expected-warning {{ignoring return value}}
+};
+
+}
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index 072ee60f1f35..5e43d3ec0422 100644
--- a/test/SemaCXX/warn-unused-value.cpp
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -49,3 +49,23 @@ namespace test2 {
}
}
+namespace test3 {
+struct Used {
+ Used();
+ Used(int);
+ Used(int, int);
+};
+struct __attribute__((warn_unused)) Unused {
+ Unused();
+ Unused(int);
+ Unused(int, int);
+};
+void f() {
+ Used();
+ Used(1);
+ Used(1, 1);
+ Unused(); // expected-warning {{expression result unused}}
+ Unused(1); // expected-warning {{expression result unused}}
+ Unused(1, 1); // expected-warning {{expression result unused}}
+}
+}
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 00597f929b25..93d2f6f9563b 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -verify %s
template<typename T> void f() {
T t;
t = 17;
@@ -128,3 +128,26 @@ namespace ctor_with_cleanups {
}
#include "Inputs/warn-unused-variables.h"
+
+namespace PR8455 {
+ void f() {
+ A: // expected-warning {{unused label 'A'}}
+ __attribute__((unused)) int i; // attribute applies to variable
+ B: // attribute applies to label
+ __attribute__((unused)); int j; // expected-warning {{unused variable 'j'}}
+ }
+
+ void g() {
+ C: // unused label 'C' will not appear here because an error occurs
+ __attribute__((unused))
+ #pragma weak unused_local_static // expected-error {{expected ';' after __attribute__}}
+ ;
+ }
+
+ void h() {
+ D: // expected-warning {{unused label 'D'}}
+ #pragma weak unused_local_static
+ __attribute__((unused)) // expected-warning {{declaration does not declare anything}}
+ ;
+ }
+}
diff --git a/test/SemaCXX/warn-using-namespace-in-header.cpp b/test/SemaCXX/warn-using-namespace-in-header.cpp
index f68b99893aae..6b84e6e70a50 100644
--- a/test/SemaCXX/warn-using-namespace-in-header.cpp
+++ b/test/SemaCXX/warn-using-namespace-in-header.cpp
@@ -57,4 +57,13 @@ using namespace dont_warn;
// cc file.
USING_MACRO
+// Check behavior of line markers.
+namespace warn_header_with_line_marker {}
+# 1 "XXX.h" 1
+using namespace warn_header_with_line_marker; // expected-warning {{using namespace directive in global context in header}}
+# 70 "warn-using-namespace-in-header.cpp" 2
+
+namespace nowarn_after_line_marker {}
+using namespace nowarn_after_line_marker;
+
#endif
diff --git a/test/SemaCXX/writable-strings-deprecated.cpp b/test/SemaCXX/writable-strings-deprecated.cpp
index 829540149563..b8f605b63d66 100644
--- a/test/SemaCXX/writable-strings-deprecated.cpp
+++ b/test/SemaCXX/writable-strings-deprecated.cpp
@@ -1,11 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-writable-strings -verify %s
// RUN: %clang_cc1 -fsyntax-only -fwritable-strings -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-write-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Werror=c++11-compat -verify %s -DERROR
// rdar://8827606
char *fun(void)
{
return "foo";
+#ifdef ERROR
+ // expected-error@-2 {{deprecated}}
+#endif
}
void test(bool b)
diff --git a/test/SemaObjC/arc-bridged-cast.m b/test/SemaObjC/arc-bridged-cast.m
index b5ec36af3838..439d3821165d 100644
--- a/test/SemaObjC/arc-bridged-cast.m
+++ b/test/SemaObjC/arc-bridged-cast.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
typedef const void *CFTypeRef;
CFTypeRef CFBridgingRetain(id X);
diff --git a/test/SemaObjC/arc-cf.m b/test/SemaObjC/arc-cf.m
index 57547208c6c5..d71d274dfb81 100644
--- a/test/SemaObjC/arc-cf.m
+++ b/test/SemaObjC/arc-cf.m
@@ -45,3 +45,15 @@ void test2() {
x = (id) CFMakeString3(); // expected-error {{requires a bridged cast}} expected-note {{CFBridgingRelease call to transfer}}
x = (id) CFCreateString3(); // expected-error {{requires a bridged cast}} expected-note {{CFBridgingRelease call to transfer}}
}
+
+// rdar://14569171
+@interface NSString @end
+typedef signed int SInt32;
+#pragma clang arc_cf_code_audited begin
+extern SInt32 CFStringGetIntValue(CFStringRef str); // expected-note {{passing argument to parameter 'str' here}}
+#pragma clang arc_cf_code_audited end
+
+void test3() {
+ NSString* answer = @"42";
+ int ans = CFStringGetIntValue(answer); // expected-error {{incompatible pointer types passing retainable parameter of type 'NSString *__strong'to a CF function expecting 'CFStringRef'}}
+}
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
index cdf6cc64ff2d..903cea2a0e8a 100644
--- a/test/SemaObjC/arc-decls.m
+++ b/test/SemaObjC/arc-decls.m
@@ -99,3 +99,27 @@ void test7(void) {
I *y;
J **py = &y; // expected-error {{pointer to non-const type 'J *' with no explicit ownership}} expected-warning {{incompatible pointer types initializing}}
}
+
+void func(void) __attribute__((objc_ownership(none))); // expected-warning {{'objc_ownership' only applies to Objective-C object or block pointer types; type here is 'void (void)'}}
+struct __attribute__((objc_ownership(none))) S2 {}; // expected-error {{'objc_ownership' attribute only applies to variables}}
+@interface I2
+ @property __attribute__((objc_ownership(frob))) id i; // expected-warning {{'objc_ownership' attribute argument not supported: 'frob'}}
+@end
+
+// rdar://15304886
+@interface NSObject @end
+
+@interface ControllerClass : NSObject @end
+
+@interface SomeClassOwnedByController
+@property (readonly) ControllerClass *controller; // expected-note {{property declared here}}
+
+// rdar://15465916
+@property (readonly, weak) ControllerClass *weak_controller;
+@end
+
+@interface SomeClassOwnedByController ()
+@property (readwrite, weak) ControllerClass *controller; // expected-warning {{primary property declaration is implicitly strong while redeclaration in class extension is weak}}
+
+@property (readwrite, weak) ControllerClass *weak_controller;
+@end
diff --git a/test/SemaObjC/arc-dict-bridged-cast.m b/test/SemaObjC/arc-dict-bridged-cast.m
index ea648401af0c..e00c47fca393 100644
--- a/test/SemaObjC/arc-dict-bridged-cast.m
+++ b/test/SemaObjC/arc-dict-bridged-cast.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// rdar://11913153
typedef const struct __CFString * CFStringRef;
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
index b824b2a4565c..ed72e8c7d811 100644
--- a/test/SemaObjC/arc-property-lifetime.m
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-default-synthesize-properties -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-arc -verify -Wno-objc-root-class %s
// rdar://9340606
@interface Foo {
@@ -171,7 +171,12 @@ void foo(Baz *f) {
// rdar://11253688
@interface Boom
-@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods}}
+{
+ const void * innerPointerIvar __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods and properties}}
+}
+@property (readonly) Boom * NotInnerPointer __attribute__((objc_returns_inner_pointer)); // expected-warning {{'objc_returns_inner_pointer' attribute only applies to properties that return a non-retainable pointer}}
+- (Boom *) NotInnerPointerMethod __attribute__((objc_returns_inner_pointer)); // expected-warning {{'objc_returns_inner_pointer' attribute only applies to methods that return a non-retainable pointer}}
+@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer));
@end
@interface Foo2 {
@@ -182,3 +187,26 @@ void foo(Baz *f) {
@implementation Foo2
@end
+
+// rdar://13885083
+@interface NSObject
+-(id)init;
+@end
+
+typedef char BOOL;
+@interface Test13885083 : NSObject
+
+@property (nonatomic, assign) BOOL retain; // expected-error {{ARC forbids synthesis of 'retain'}}
+
+-(id)init;
+
+@end
+
+@implementation Test13885083
+-(id) init
+{
+ self = [super init];
+ return self;
+}
+@end
+
diff --git a/test/SemaObjC/arc-readonly-property-ivar-1.m b/test/SemaObjC/arc-readonly-property-ivar-1.m
index 418f90d38a8b..2b98f01e914f 100644
--- a/test/SemaObjC/arc-readonly-property-ivar-1.m
+++ b/test/SemaObjC/arc-readonly-property-ivar-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-default-synthesize-properties -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -fobjc-default-synthesize-properties -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// rdar:// 10558871
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
index b5d9002130d2..64df92a9afa9 100644
--- a/test/SemaObjC/arc-repeated-weak.mm
+++ b/test/SemaObjC/arc-repeated-weak.mm
@@ -410,3 +410,18 @@ void doubleLevelAccessIvar(Test *a, Test *b) {
use(a.strongProp.weakProp); // no-warning
}
+// rdar://13942025
+@interface X
+@end
+
+@implementation X
+- (int) warningAboutWeakVariableInsideTypeof {
+ __typeof__(self) __weak weakSelf = self;
+ ^(){
+ __typeof__(weakSelf) blockSelf = weakSelf;
+ use(blockSelf);
+ }();
+ return sizeof(weakSelf);
+}
+@end
+
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
index b9b5cc516dea..eab5f2ca746e 100644
--- a/test/SemaObjC/arc-unavailable-for-weakref.m
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -86,3 +86,7 @@ __attribute__((objc_arc_weak_reference_unavailable))
@implementation I2 // expected-note {{when implemented by class I2}}
@synthesize font = _font;
@end
+
+__attribute__((objc_arc_weak_reference_unavailable(1))) // expected-error {{'objc_arc_weak_reference_unavailable' attribute takes no arguments}}
+@interface I3
+@end
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index 1d4e42de649d..060af24fa0d9 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -84,14 +84,19 @@ void test1(A *a) {
// rdar://8861761
@interface B
--(id)alloc;
++ (id)alloc;
- (id)initWithInt: (int) i;
+- (id)myInit __attribute__((objc_method_family(init)));
+- (id)myBadInit __attribute__((objc_method_family(12))); // expected-error {{'objc_method_family' attribute requires parameter 1 to be an identifier}}
+
@end
void rdar8861761() {
B *o1 = [[B alloc] initWithInt:0];
B *o2 = [B alloc];
[o2 initWithInt:0]; // expected-warning {{expression result unused}}
+ B *o3 = [[B alloc] myInit];
+ [[B alloc] myInit]; // expected-warning {{expression result unused}}
}
// rdar://8925835
@@ -411,7 +416,7 @@ void test17(void) {
void test18(void) {
id x;
- [x test18]; // expected-error {{no known instance method for selector 'test18'}}
+ [x test18]; // expected-error {{instance method 'test18' not found ; did you mean 'test17'?}}
}
extern struct Test19 *test19a;
@@ -767,3 +772,13 @@ void test(NSArray *x) {
__strong NSMutableArray *y1 = x; // expected-warning {{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
PSNS y2 = x; // expected-warning {{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
}
+
+// rdar://15123684
+@class NSString;
+
+void foo(NSArray *array) {
+ for (NSString *string in array) {
+ for (string in @[@"blah", @"more blah", string]) { // expected-error {{selector element of type 'NSString *const __strong' cannot be a constant l-value}}
+ }
+ }
+}
diff --git a/test/SemaObjC/attr-objc-exception.m b/test/SemaObjC/attr-objc-exception.m
index b497271521e2..dd8ac573deed 100644
--- a/test/SemaObjC/attr-objc-exception.m
+++ b/test/SemaObjC/attr-objc-exception.m
@@ -8,9 +8,9 @@ __attribute__((__objc_exception__))
@end
-__attribute__((__objc_exception__)) // expected-error {{attribute may only be applied to an Objective-C interface}}
+__attribute__((__objc_exception__)) // expected-error {{'__objc_exception__' attribute only applies to Objective-C interfaces}}
int X;
-__attribute__((__objc_exception__)) // expected-error {{attribute may only be applied to an Objective-C interface}}
+__attribute__((__objc_exception__)) // expected-error {{'__objc_exception__' attribute only applies to Objective-C interfaces}}
void foo();
diff --git a/test/SemaObjC/attr-objc-gc.m b/test/SemaObjC/attr-objc-gc.m
index 9ca12c9315a1..827945c668cb 100644
--- a/test/SemaObjC/attr-objc-gc.m
+++ b/test/SemaObjC/attr-objc-gc.m
@@ -2,9 +2,9 @@
static id __attribute((objc_gc(weak))) a;
static id __attribute((objc_gc(strong))) b;
-static id __attribute((objc_gc())) c; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
-static id __attribute((objc_gc(123))) d; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
-static id __attribute((objc_gc(foo, 456))) e; // expected-error{{attribute takes one argument}}
+static id __attribute((objc_gc())) c; // expected-error{{'objc_gc' attribute requires a string}}
+static id __attribute((objc_gc(123))) d; // expected-error{{'objc_gc' attribute requires a string}}
+static id __attribute((objc_gc(foo, 456))) e; // expected-error{{'objc_gc' attribute takes one argument}}
static id __attribute((objc_gc(hello))) f; // expected-warning{{'objc_gc' attribute argument not supported: 'hello'}}
static int __attribute__((objc_gc(weak))) g; // expected-warning {{'objc_gc' only applies to pointer types; type here is 'int'}}
diff --git a/test/SemaObjC/attr-print.m b/test/SemaObjC/attr-print.m
new file mode 100644
index 000000000000..e3405d239e36
--- /dev/null
+++ b/test/SemaObjC/attr-print.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -fobjc-arc -ast-print | FileCheck %s
+
+__strong id x;
+id y;
+__strong id z;
+
+// CHECK: __strong id x;
+// CHECK-NOT: __strong id y;
+// CHECK: __strong id z;
diff --git a/test/SemaObjC/attr-root-class.m b/test/SemaObjC/attr-root-class.m
index 195cd663acda..6be1c09d4dc7 100644
--- a/test/SemaObjC/attr-root-class.m
+++ b/test/SemaObjC/attr-root-class.m
@@ -11,6 +11,10 @@ __attribute__((objc_root_class))
@implementation NonRootClass
@end
-__attribute__((objc_root_class)) static void nonClassDeclaration() // expected-error {{attribute may only be applied to an Objective-C interface}}
+__attribute__((objc_root_class)) static void nonClassDeclaration() // expected-error {{'objc_root_class' attribute only applies to Objective-C interfaces}}
{
}
+
+__attribute__((objc_root_class(1))) // expected-error {{'objc_root_class' attribute takes no arguments}}
+@interface I1
+@end
diff --git a/test/SemaObjC/bad-property-synthesis-crash.m b/test/SemaObjC/bad-property-synthesis-crash.m
index ea4e0045dc4b..94c680489d91 100644
--- a/test/SemaObjC/bad-property-synthesis-crash.m
+++ b/test/SemaObjC/bad-property-synthesis-crash.m
@@ -13,7 +13,7 @@
__what; // expected-error {{use of undeclared identifier}} \
// expected-warning {{expression result unused}}
}
-@synthesize what; // expected-note 2 {{'what' declared here}}
+@synthesize what; // expected-note {{'what' declared here}}
@end
@implementation Bar // expected-warning {{cannot find interface declaration for}}
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index b523e4c91635..d6681d051de1 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -86,9 +86,11 @@ typedef enum CStyleEnum (^cse_block_t)();
void testCStyleEnumInference(bool arg) {
cse_block_t a;
+ enum CStyleEnum value;
// No warnings here.
a = ^{ return getCSE(); };
+ a = ^{ return value; };
a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
return 1;
@@ -102,6 +104,7 @@ void testCStyleEnumInference(bool arg) {
// No warnings here.
a = ^{ if (arg) return CSE_Value; else return getCSE(); };
a = ^{ if (arg) return getCSE(); else return CSE_Value; };
+ a = ^{ if (arg) return value; else return CSE_Value; };
// These two blocks actually return 'int'
a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
@@ -118,6 +121,13 @@ void testCStyleEnumInference(bool arg) {
return 1;
};
+ a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
+ if (arg)
+ return 1;
+ else
+ return value; // expected-error {{return type 'enum CStyleEnum' must match previous return type 'int'}}
+ };
+
// rdar://13200889
extern void check_enum(void);
a = ^{
@@ -206,3 +216,8 @@ void testAnonymousEnumTypes(int arg) {
SB = ^{ if (arg) return TDFTE_Value; else return getTDFTE(); };
SB = ^{ if (arg) return getTDFTE(); else return TDFTE_Value; };
}
+
+static inline void inlinefunc() {
+ ^{}();
+}
+void inlinefunccaller() { inlinefunc(); }
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
index 3c45a2c73238..8927f3b52864 100644
--- a/test/SemaObjC/call-super-2.m
+++ b/test/SemaObjC/call-super-2.m
@@ -14,7 +14,7 @@ id objc_getClass(const char *s);
- (int) instance_func0;
@end
-@interface Derived: Object
+@interface Derived: Object // expected-note {{receiver is instance of class declared here}}
+ (int) class_func1;
+ (int) class_func2;
+ (int) class_func3;
@@ -35,7 +35,7 @@ id objc_getClass(const char *s);
@implementation Derived
+ (int) class_func1
{
- int i = (size_t)[self class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
+ int i = (size_t)[self class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id'); did you mean '+class_func}}
return i + (size_t)[super class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
}
+ (int) class_func2
@@ -68,7 +68,7 @@ id objc_getClass(const char *s);
}
- (int) instance_func1
{
- int i = (size_t)[self instance_func0]; // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id')}}
+ int i = (size_t)[self instance_func0]; // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id'); did you mean}}
return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0'}}
}
- (int) instance_func2
diff --git a/test/SemaObjC/class-def-test-1.m b/test/SemaObjC/class-def-test-1.m
index 0d114b99fb6d..7931cc3fdce4 100644
--- a/test/SemaObjC/class-def-test-1.m
+++ b/test/SemaObjC/class-def-test-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@protocol SUPER;
@@ -16,9 +16,10 @@ typedef int INTF; // expected-note {{previous definition is here}}
typedef int OBJECT; // expected-error {{redefinition of 'OBJECT' as different kind of symbol}}
-typedef int OBJECT2; // expected-note {{previous definition is here}}
+typedef int OBJECT2; // expected-note 2 {{previous definition is here}}
@interface INTF2 : OBJECT2 @end // expected-error {{redefinition of 'OBJECT2' as different kind of symbol}}
+@implementation INTF2 : OBJECT2 @end // expected-error {{redefinition of 'OBJECT2' as different kind of symbol}}
@protocol PROTO;
diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m
index 82868f8a1613..02fa86ec8d9e 100644
--- a/test/SemaObjC/compare-qualified-id.m
+++ b/test/SemaObjC/compare-qualified-id.m
@@ -12,7 +12,7 @@ typedef struct _NSZone NSZone;
typedef struct {} NSFastEnumerationState;
@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; @end
@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; @end
-@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end
+@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end // expected-note {{receiver is instance of class declared here}}
extern NSString * const NSTaskDidTerminateNotification;
@interface XCPropertyExpansionContext : NSObject <NSCopying> { // expected-note {{required for direct or indirect protocol 'NSCopying'}}
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index ec1305dbe8b3..049a095ce37c 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -33,7 +33,8 @@
@end
// No @interface declaration for DTFilterOutputStream3
-@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}}
+@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}} \
+ // expected-note {{receiver is instance of class declared here}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}}
self = nextOutputStream; // expected-warning {{assigning to 'DTFilterOutputStream3 *' from incompatible type 'id<DTOutputStreams>'}}
diff --git a/test/SemaObjC/conversion.m b/test/SemaObjC/conversion.m
new file mode 100644
index 000000000000..88a1a44b2177
--- /dev/null
+++ b/test/SemaObjC/conversion.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -Wconversion -fsyntax-only %s -verify
+
+typedef signed char BOOL;
+__attribute__((objc_root_class)) @interface RDar14415662
+@property (readonly) BOOL stuff;
+@property (readwrite) BOOL otherStuff;
+@end
+
+void radar14415662(RDar14415662 *f, char x, int y) {
+ f.otherStuff = !f.stuff; // no-warning
+ BOOL b = !f.stuff; // no-warning
+
+ // True positive to sanity check warning is working.
+ x = y; // expected-warning {{implicit conversion loses integer precision: 'int' to 'char'}}
+}
+
+
diff --git a/test/SemaObjC/dealloc.m b/test/SemaObjC/dealloc.m
index feafafd3753f..59218d2d0733 100644
--- a/test/SemaObjC/dealloc.m
+++ b/test/SemaObjC/dealloc.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// rdar://11987838
@protocol NSObject
diff --git a/test/SemaObjC/default-synthesize-1.m b/test/SemaObjC/default-synthesize-1.m
index 5aaca9a1c291..f9f2e72eaf94 100644
--- a/test/SemaObjC/default-synthesize-1.m
+++ b/test/SemaObjC/default-synthesize-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -Wobjc-missing-property-synthesis -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wobjc-missing-property-synthesis -verify -Wno-objc-root-class %s
// rdar://11295716
@interface NSObject
diff --git a/test/SemaObjC/default-synthesize-2.m b/test/SemaObjC/default-synthesize-2.m
index 20c045e60e06..1980b91dbe98 100644
--- a/test/SemaObjC/default-synthesize-2.m
+++ b/test/SemaObjC/default-synthesize-2.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://8843851
@interface StopAccessingIvarsDirectlyExample
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
index 82f968da0009..1c32665a2dd7 100644
--- a/test/SemaObjC/default-synthesize-3.m
+++ b/test/SemaObjC/default-synthesize-3.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
#if __has_attribute(objc_requires_property_definitions)
__attribute ((objc_requires_property_definitions))
@@ -111,3 +111,73 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{objc_requ
@implementation S
@end
+
+// rdar://14085456
+// No warning must be issued in this test.
+@interface ParentObject
+@end
+
+@protocol TestObject
+@property (readonly) int six;
+@end
+
+@interface TestObject : ParentObject <TestObject>
+@property int six;
+@end
+
+@implementation TestObject
+@synthesize six;
+@end
+
+// rdar://14094682
+// no warning in this test
+@interface ISAChallenge : NSObject {
+}
+
+@property (assign, readonly) int failureCount;
+@end
+
+@interface ISSAChallenge : ISAChallenge {
+ int _failureCount;
+}
+@property (assign, readwrite) int failureCount;
+@end
+
+@implementation ISAChallenge
+- (int)failureCount {
+ return 0;
+}
+@end
+
+@implementation ISSAChallenge
+
+@synthesize failureCount = _failureCount;
+@end
+
+__attribute ((objc_requires_property_definitions(1))) // expected-error {{'objc_requires_property_definitions' attribute takes no arguments}}
+@interface I1
+@end
+
+// rdar://15051465
+@protocol SubFooling
+ @property(nonatomic, readonly) id hoho; // expected-note 2 {{property declared here}}
+@end
+
+@protocol Fooing<SubFooling>
+ @property(nonatomic, readonly) id muahahaha; // expected-note 2 {{property declared here}}
+@end
+
+typedef NSObject<Fooing> FooObject;
+
+@interface Okay : NSObject<Fooing>
+@end
+
+@implementation Okay // expected-warning 2 {{auto property synthesis will not synthesize property declared in a protocol}}
+@end
+
+@interface Fail : FooObject
+@end
+
+@implementation Fail // expected-warning 2 {{auto property synthesis will not synthesize property declared in a protocol}}
+@end
+
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index e6ea0a5eafb3..dd16c1361d89 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface NSString @end
diff --git a/test/SemaObjC/deprecated-objc-introspection.m b/test/SemaObjC/deprecated-objc-introspection.m
index faaef254d596..4f7484145865 100644
--- a/test/SemaObjC/deprecated-objc-introspection.m
+++ b/test/SemaObjC/deprecated-objc-introspection.m
@@ -14,9 +14,11 @@ typedef struct objc_object {
id firstobj;
struct objc_class *isa;
}
+- (id)performSelector:(SEL)aSelector;;
@end
@interface Whatever : NSObject
+self;
+-(id)foo;
@end
static void func() {
@@ -94,4 +96,9 @@ void testBitmasking(NSObject *p) {
(void) (0x1 & ((NSUInteger) p)); // expected-warning {{bitmasking for introspection of Objective-C object pointers is strongly discouraged}}
(void) (((NSUInteger) p) ^ 0x1); // no-warning
(void) (0x1 ^ ((NSUInteger) p)); // no-warning
+ (void) (0x1 & ((NSUInteger) [p performSelector:@selector(foo)])); // expected-warning {{bitmasking for introspection of Objective-C object pointers is strongly discouraged}}
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-objc-pointer-introspection-performSelector"
+ (void) (0x1 & ((NSUInteger) [p performSelector:@selector(foo)])); // no-warning
+#pragma clang diagnostic pop
} \ No newline at end of file
diff --git a/test/SemaObjC/direct-synthesized-ivar-access.m b/test/SemaObjC/direct-synthesized-ivar-access.m
index a276a64913b3..7ec333723b66 100644
--- a/test/SemaObjC/direct-synthesized-ivar-access.m
+++ b/test/SemaObjC/direct-synthesized-ivar-access.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// rdar://8673791
// rdar://9943851
diff --git a/test/SemaObjC/error-outof-scope-property-use.m b/test/SemaObjC/error-outof-scope-property-use.m
index c69a4055df21..c480e2df0b7e 100644
--- a/test/SemaObjC/error-outof-scope-property-use.m
+++ b/test/SemaObjC/error-outof-scope-property-use.m
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://13178483
-@class NSMutableDictionary;
+@class NSMutableDictionary; // expected-note {{receiver is instance of class declared here}}
@interface LaunchdJobs
-@property (nonatomic,retain) NSMutableDictionary *uuids_jobs; // expected-note 2 {{'_uuids_jobs' declared here}}
+@property (nonatomic,retain) NSMutableDictionary *uuids_jobs; // expected-note {{'_uuids_jobs' declared here}}
@end
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
index d0e0f7b9e214..91ea2ec4e0d4 100644
--- a/test/SemaObjC/foreach.m
+++ b/test/SemaObjC/foreach.m
@@ -13,8 +13,8 @@ void f(NSArray *a) {
* and no diagnostics even in pedantic mode should happen.
* rdar://6814674
*/
- for (id thisKey in keys);
- for (id thisKey in keys);
+ for (id thisKey in keys); /* expected-warning {{unused variable 'thisKey'}} */
+ for (id thisKey in keys); /* expected-warning {{unused variable 'thisKey'}} */
}
/* // rdar://9072298 */
@@ -41,7 +41,7 @@ typedef struct {
int main ()
{
NSObject<NSFastEnumeration>* collection = ((void*)0);
- for (id thing in collection) { }
+ for (id thing in collection) { } /* expected-warning {{unused variable 'thing'}} */
return 0;
}
diff --git a/test/SemaObjC/format-arg-attribute.m b/test/SemaObjC/format-arg-attribute.m
index dede433f37a2..e770373a055b 100644
--- a/test/SemaObjC/format-arg-attribute.m
+++ b/test/SemaObjC/format-arg-attribute.m
@@ -1,17 +1,17 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -Werror -Wformat-nonliteral -verify -fsyntax-only %s
@class NSString;
extern NSString *fa2 (const NSString *) __attribute__((format_arg(1)));
extern NSString *fa3 (NSString *) __attribute__((format_arg(1)));
-extern void fc1 (const NSString *) __attribute__((format_arg)); // expected-error {{attribute takes one argument}}
-extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{attribute takes one argument}}
-extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{attribute takes one argument}}
+extern void fc1 (const NSString *) __attribute__((format_arg)); // expected-error {{'format_arg' attribute takes one argument}}
+extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{'format_arg' attribute takes one argument}}
+extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{'format_arg' attribute takes one argument}}
-struct s1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
-union u1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
-enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
+struct s1 { int i; } __attribute__((format_arg(1))); // expected-error {{'format_arg' attribute only applies to functions}}
+union u1 { int i; } __attribute__((format_arg(1))); // expected-error {{'format_arg' attribute only applies to functions}}
+enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-error {{'format_arg' attribute only applies to functions}}
extern NSString *ff3 (const NSString *) __attribute__((format_arg(3-2)));
extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{use of undeclared identifier 'foo'}}
@@ -25,3 +25,23 @@ extern NSString *fi2 (NSString *) __attribute__((format_arg(1)));
extern int fi3 (const NSString *) __attribute__((format_arg(1))); // expected-error {{function does not return NSString}}
extern NSString *fi4 (const NSString *) __attribute__((format_arg(1)));
extern NSString *fi5 (const NSString *) __attribute__((format_arg(1)));
+
+// rdar://15242010
+@interface NSString
++ (id)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+@end
+
+@interface NSBundle
+- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName __attribute__ ((format_arg(1)));
++ (NSBundle *)mainBundle;
+@end
+
+
+NSString* localizedFormat(NSString* string) __attribute__ ((format_arg(1)));
+
+int main()
+{
+ [NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"foo %d" value:@"bar %d" table:0], 42];
+
+ [NSString stringWithFormat:localizedFormat(@"foo %d"), 42];
+}
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index 849013022433..2667e3047aae 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -232,6 +232,8 @@ void testInvalidFormatArgument(NSDictionary *dict) {
// <rdar://problem/11825593>
void testByValueObjectInFormat(Foo *obj) {
printf("%d %d %d", 1L, *obj, 1L); // expected-error {{cannot pass object with interface type 'Foo' by value to variadic function; expected type from format string was 'int'}} expected-warning 2 {{format specifies type 'int' but the argument has type 'long'}}
+ printf("%!", *obj); // expected-error {{cannot pass object with interface type 'Foo' by value through variadic function}} expected-warning {{invalid conversion specifier}}
+ printf(0, *obj); // expected-error {{cannot pass object with interface type 'Foo' by value through variadic function}}
[Bar log2:@"%d", *obj]; // expected-error {{cannot pass object with interface type 'Foo' by value to variadic method; expected type from format string was 'int'}}
}
@@ -241,3 +243,8 @@ void testTypeOf(NSInteger dW, NSInteger dH) {
NSLog(@"dW %d dH %d",({ __typeof__(dW) __a = (dW); __a < 0 ? -__a : __a; }),({ __typeof__(dH) __a = (dH); __a < 0 ? -__a : __a; })); // expected-warning 2 {{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
}
+void testUnicode() {
+ NSLog(@"%C", 0x2022); // no-warning
+ NSLog(@"%C", 0x202200); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+}
+
diff --git a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
index 01fedec3cffe..c3efeba4f9ec 100644
--- a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
+++ b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-default-synthesize-properties %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://12958878
@interface NSObject @end
diff --git a/test/SemaObjC/iboutlet.m b/test/SemaObjC/iboutlet.m
index 01e1bfc13bea..3c7f9581e663 100644
--- a/test/SemaObjC/iboutlet.m
+++ b/test/SemaObjC/iboutlet.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -Wno-objc-root-class -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -Wno-objc-root-class -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -Wno-objc-root-class -verify %s
// rdar://11448209
#define READONLY readonly
diff --git a/test/SemaObjC/iboutletcollection-attr.m b/test/SemaObjC/iboutletcollection-attr.m
index 82cb96fbede7..f088ca32b6ad 100644
--- a/test/SemaObjC/iboutletcollection-attr.m
+++ b/test/SemaObjC/iboutletcollection-attr.m
@@ -18,15 +18,15 @@
typedef void *PV;
@interface BAD {
- __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute takes one argument}}
- __attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
- __attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' as argument of iboutletcollection attribute}}
+ __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{expected ')'}} expected-note {{to match}}
+ __attribute__((iboutletcollection(B))) id ivar2; // expected-error {{unknown type name 'B'}}
+ __attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' (aka 'void *') as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) void *ivar4; // expected-warning {{instance variable with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
__attribute__((iboutletcollection(int))) id ivar5; // expected-error {{type argument of iboutletcollection attribute cannot be a builtin type}}
__attribute__((iboutlet)) int ivar6; // expected-warning {{instance variable with 'iboutlet' attribute must be an object type}}
}
-@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute takes one argument}}
-@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
+@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{expected ')'}} expected-note {{to match}}
+@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{unknown type name 'B'}}
@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-warning {{property with 'iboutletcollection' attribute must be an object type (invalid 'int')}}
@end
@@ -41,3 +41,10 @@ typedef void *PV;
@property (nonatomic, strong)
__attribute__((iboutletcollection(RDar10296078_OtherClass<RDar10296078_Protocol>))) NSArray *stuff;
@end
+
+// rdar://14212998
+@class UILabel;
+@class NSArray;
+@interface OCTViewController
+@property (nonatomic, assign) __attribute__((iboutletcollection(UILabel))) NSArray *labels; // expected-warning {{IBOutletCollection properties should be copy/strong and not assign}}
+@end
diff --git a/test/SemaObjC/idiomatic-parentheses.m b/test/SemaObjC/idiomatic-parentheses.m
index 801db5944f10..c6281f0987de 100644
--- a/test/SemaObjC/idiomatic-parentheses.m
+++ b/test/SemaObjC/idiomatic-parentheses.m
@@ -9,6 +9,7 @@
}
- (id) init;
- (id) initWithInt: (int) i;
+- (id) myInit __attribute__((objc_method_family(init)));
- (void) iterate: (id) coll;
- (id) nextObject;
@property unsigned uid;
@@ -34,6 +35,12 @@
return self;
}
+- (id) myInit {
+ if (self = [self myInit]) {
+ }
+ return self;
+}
+
- (void) iterate: (id) coll {
id cur;
while (cur = [coll nextObject]) {
diff --git a/test/SemaObjC/instancetype.m b/test/SemaObjC/instancetype.m
index 8137964737e4..7811d3eba583 100644
--- a/test/SemaObjC/instancetype.m
+++ b/test/SemaObjC/instancetype.m
@@ -25,7 +25,7 @@
- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
@end
-@interface Subclass1 : Root
+@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}}
- (instancetype)initSubclass1;
- (void)methodOnSubclass1;
+ (instancetype)allocSubclass1;
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
index df9d8bac9077..938c8eb189a5 100644
--- a/test/SemaObjC/ivar-lookup.m
+++ b/test/SemaObjC/ivar-lookup.m
@@ -80,3 +80,77 @@ extern struct foo x;
int IVAR; // expected-error {{instance variable is already declared}}
}
@end
+
+// PR5984
+// rdar://14037151
+@interface Radar14037151 {
+ int myStatus;
+}
+- (int) test;
+@end
+
+@implementation Radar14037151
+- (int) test
+{
+ myStatus = 1; // works
+ __typeof(myStatus) __in; // works.
+ union U {
+ __typeof(myStatus) __in; // fails.
+ };
+ struct S {
+ __typeof(myStatus) __in; // fails.
+ struct S1 {
+ __typeof(myStatus) __in; // fails.
+ struct S {
+ __typeof(myStatus) __in; // fails.
+ };
+ };
+ };
+
+ return 0;
+}
+@end
+
+// rdar://14278560
+@class NSString, NSData, NSNumber;
+
+@interface NSObject
+{
+ Class isa;
+}
+@end
+
+@interface Foo
+{
+ int a;
+ NSString* b;
+ NSData* c;
+}
+@end
+
+@interface Bar : Foo
+@end
+
+@interface Bar () {
+ NSString *q_strong;
+ NSNumber *r_strong;
+ int d; // expected-note {{previous definition is here}}
+ NSString *e_strong; // expected-note {{previous definition is here}}
+ NSData *f_weak; // expected-note {{previous definition is here}}
+ int g; // expected-note 2 {{previous definition is here}}
+}
+@end
+
+@interface Bar () {
+ int g; // expected-note {{previous definition is here}} \
+ // expected-error {{instance variable is already declared}}
+}
+@end
+
+@implementation Bar {
+ int d; // expected-error {{instance variable is already declared}}
+ NSString *e_strong; // expected-error {{instance variable is already declared}}
+ NSData *f_weak; // expected-error {{instance variable is already declared}}
+ NSData *g; // expected-error 2 {{instance variable is already declared}}
+}
+@end
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
index 3115f5bd2332..2c2fb2f4618f 100644
--- a/test/SemaObjC/ivar-ref-misuse.m
+++ b/test/SemaObjC/ivar-ref-misuse.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
-@interface Sprite { // expected-note{{'Sprite' declared here}}
+@interface Sprite {
int sprite, spree;
int UseGlobalBar;
}
@@ -17,8 +17,7 @@ int UseGlobalBar;
+ (void)setFoo:(int)foo {
sprite = foo; // expected-error {{instance variable 'sprite' accessed in class method}}
spree = foo;
- Xsprite = foo; // expected-error {{unknown type name 'Xsprite'; did you mean 'Sprite'?}} \
- // expected-error{{expected identifier or '('}}
+ Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}}
UseGlobalBar = 10;
}
+ (void)setSprite:(int)sprite {
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index 40fa102f35d2..2c4d8066f604 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -107,7 +107,7 @@ void foo5(id p) {
// expected-warning {{instance method '-bar' not found}}
}
-@interface I1
+@interface I1 // expected-note {{receiver is instance of class declared here}}
-(void)unavail_meth __attribute__((unavailable)); // expected-note {{marked unavailable here}}
@end
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
index d44b53614aa4..ad67a34edb00 100644
--- a/test/SemaObjC/method-bad-param.m
+++ b/test/SemaObjC/method-bad-param.m
@@ -42,3 +42,17 @@ enum bogus; // expected-note {{forward declaration of 'enum bogus'}}
}
@end
+@interface arrayfun
+- (int[6])arrayRet; // expected-error {{function cannot return array type 'int [6]'}}
+- (int())funcRet; // expected-error {{function cannot return function type 'int ()'}}
+@end
+
+@interface qux
+- (void) my_method: (int)arg; // expected-note {{method 'my_method:' declared here}}
+@end
+
+// FIXME: The diagnostic and recovery here could probably be improved.
+@implementation qux // expected-warning {{method definition for 'my_method:' not found}}
+- (void) my_method: (int) { // expected-error {{expected identifier}}
+}
+@end
diff --git a/test/SemaObjC/method-conflict-2.m b/test/SemaObjC/method-conflict-2.m
index ec80a433cc77..47c3d6c2c23c 100644
--- a/test/SemaObjC/method-conflict-2.m
+++ b/test/SemaObjC/method-conflict-2.m
@@ -64,3 +64,52 @@ typedef long long int64_t;
return 0;
}
@end
+
+// rdar://14650159
+// Tests that property inherited indirectly from a nested protocol
+// is seen by the method implementation type matching logic before
+// method in super class is seen. This fixes the warning coming
+// out of that method mismatch.
+@interface NSObject (NSDict)
+- (void)setValue:(id)value;
+- (id)value;
+@end
+
+@protocol ProtocolWithValue
+@property (nonatomic) unsigned value;
+@end
+
+@protocol InterveningProtocol <ProtocolWithValue>
+@end
+
+@interface UsesProtocolWithValue : NSObject <ProtocolWithValue>
+@end
+
+@implementation UsesProtocolWithValue
+@synthesize value=_value;
+- (unsigned) value
+{
+ return _value;
+}
+- (void) setValue:(unsigned)value
+{
+ _value = value;
+}
+@end
+
+
+@interface UsesInterveningProtocol : NSObject <InterveningProtocol>
+@end
+
+@implementation UsesInterveningProtocol
+
+@synthesize value=_value;
+- (unsigned) value
+{
+ return _value;
+}
+- (void) setValue:(unsigned)value
+{
+ _value = value;
+}
+@end
diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m
index 22466f7dc342..792469b719c6 100644
--- a/test/SemaObjC/method-not-defined.m
+++ b/test/SemaObjC/method-not-defined.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface Foo
+@interface Foo // expected-note {{receiver is instance of class declared here}}
@end
void test() {
diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m
index 274e93660653..d230be5805be 100644
--- a/test/SemaObjC/method-sentinel-attr.m
+++ b/test/SemaObjC/method-sentinel-attr.m
@@ -10,7 +10,7 @@
- (void) foo5 : (int)x, ... __attribute__ ((__sentinel__(1))); // expected-note {{method has been explicitly marked sentinel here}}
- (void) foo6 : (int)x, ... __attribute__ ((__sentinel__(5))); // expected-note {{method has been explicitly marked sentinel here}}
- (void) foo7 : (int)x, ... __attribute__ ((__sentinel__(0))); // expected-note {{method has been explicitly marked sentinel here}}
-- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a"))); // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}}
+- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a"))); // expected-error {{'__sentinel__' attribute requires parameter 1 to be an integer constant}}
- (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1))); // expected-error {{'sentinel' parameter 1 less than zero}}
- (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1)));
- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3))); // expected-error {{attribute takes no more than 2 arguments}}
diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m
index f072981dc1bf..f235ab94d821 100644
--- a/test/SemaObjC/missing-atend-metadata.m
+++ b/test/SemaObjC/missing-atend-metadata.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
-@interface I0
+@interface I0 // expected-note {{receiver is instance of class declared here}}
@end
@implementation I0 // expected-note {{implementation started here}}
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
index b794eafc9ed7..ead222c3310b 100644
--- a/test/SemaObjC/nsobject-attribute.m
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef;
+typedef struct CGColor * __attribute__((NSObject(12))) Illegal; // expected-error {{'NSObject' attribute takes no arguments}}
+
static int count;
static CGColorRef tmp = 0;
diff --git a/test/SemaObjC/objc-array-literal.m b/test/SemaObjC/objc-array-literal.m
index 9f59316219c7..706207df7482 100644
--- a/test/SemaObjC/objc-array-literal.m
+++ b/test/SemaObjC/objc-array-literal.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://10111397
+// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-macosx10.9.0 -fobjc-runtime=macosx-fragile-10.9.0 -fobjc-subscripting-legacy-runtime -verify %s
+// rdar://15363492
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef unsigned long NSUInteger;
@@ -39,3 +41,17 @@ int main() {
const char *blah;
NSArray *array2 = @[blah]; // expected-error{{collection element of type 'const char *' is not an Objective-C object}}
}
+
+// rdar://14303083
+id Test14303083() {
+ id obj = @[ @"A", (@"B" @"C")];
+ return @[ @"A", @"B" @"C"]; // expected-warning {{concatenated NSString literal for an NSArray expression - possibly missing a comma}}
+}
+id radar15147688() {
+#define R15147688_A @"hello"
+#define R15147688_B "world"
+#define CONCATSTR R15147688_A R15147688_B
+ id x = @[ @"stuff", CONCATSTR ]; // no-warning
+ x = @[ @"stuff", @"hello" "world"]; // expected-warning {{concatenated NSString literal for an NSArray expression}}
+ return x;
+}
diff --git a/test/SemaObjC/objc-dictionary-literal.m b/test/SemaObjC/objc-dictionary-literal.m
index 0b6da4a77ba4..9d86d88bcbec 100644
--- a/test/SemaObjC/objc-dictionary-literal.m
+++ b/test/SemaObjC/objc-dictionary-literal.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://11062080
+// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-macosx10.9.0 -fobjc-runtime=macosx-fragile-10.9.0 -fobjc-subscripting-legacy-runtime -verify %s
+// rdar://15363492
@interface NSNumber
+ (NSNumber *)numberWithChar:(char)value;
diff --git a/test/SemaObjC/objcbridge-attribute.m b/test/SemaObjC/objcbridge-attribute.m
new file mode 100644
index 000000000000..2db2ff4929e8
--- /dev/null
+++ b/test/SemaObjC/objcbridge-attribute.m
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// rdar://15454846
+
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 2 {{declared here}}
+
+typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
+
+typedef struct __attribute__ ((objc_bridge)) __CFArray *CFArrayRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
+
+typedef void * __attribute__ ((objc_bridge(NSURL))) CFURLRef; // expected-error {{'objc_bridge' attribute only applies to struct or union}}
+
+typedef void * CFStringRef __attribute__ ((objc_bridge(NSString))); // expected-error {{'objc_bridge' attribute only applies to struct or union}}
+
+typedef struct __attribute__((objc_bridge(NSLocale, NSError))) __CFLocale *CFLocaleRef;// expected-error {{use of undeclared identifier 'NSError'}}
+
+typedef struct __CFData __attribute__((objc_bridge(NSData))) CFDataRef; // expected-error {{'objc_bridge' attribute only applies to struct or union}}
+
+typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary * CFDictionaryRef;
+
+typedef struct __CFSetRef * CFSetRef __attribute__((objc_bridge(NSSet))); // expected-error {{'objc_bridge' attribute only applies to struct or union}};
+
+typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) * CFUColorRef; // expected-error {{'objc_bridge' attribute only applies to struct or union}};
+
+typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) *CFUColor1Ref; // expected-error {{'objc_bridge' attribute only applies to struct or union}};
+
+typedef union __attribute__((objc_bridge(NSUColor))) __CFUPrimeColor XXX;
+typedef XXX *CFUColor2Ref;
+
+@interface I
+{
+ __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute only applies to struct or union}};
+}
+@end
+
+@protocol NSTesting @end
+@class NSString;
+
+typedef struct __attribute__((objc_bridge(NSTesting))) __CFError *CFTestingRef; // expected-note {{declared here}}
+
+id Test1(CFTestingRef cf) {
+ return (NSString *)cf; // expected-error {{CF object of type 'CFTestingRef' (aka 'struct __CFError *') is bridged to 'NSTesting', which is not an Objective-C class}}
+}
+
+typedef CFErrorRef CFErrorRef1;
+
+typedef CFErrorRef1 CFErrorRef2;
+
+@interface NSError @end
+
+@interface MyError : NSError
+@end
+
+@interface NSUColor @end
+
+@class NSString;
+
+void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
+ (void)(NSString *)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'NSString'}}
+ (void)(NSError *)cf; // okay
+ (void)(MyError*)cf; // okay,
+ (void)(NSUColor *)cf2; // okay
+ (void)(CFErrorRef)ns; // okay
+ (void)(CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
+ (void)(Class)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'Class'}}
+ (void)(CFErrorRef)c; // expected-warning {{'Class' cannot bridge to 'CFErrorRef'}}
+}
diff --git a/test/SemaObjC/overriding-property-in-class-extension.m b/test/SemaObjC/overriding-property-in-class-extension.m
index 77efd556928c..8c0e1b98a572 100644
--- a/test/SemaObjC/overriding-property-in-class-extension.m
+++ b/test/SemaObjC/overriding-property-in-class-extension.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Weverything %s
-// expected-no-diagnostics
// rdar://12103434
@class NSString;
@@ -8,7 +7,7 @@
@interface MyClass : NSObject
-@property (nonatomic, copy, readonly) NSString* name;
+@property (nonatomic, copy, readonly) NSString* name; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
@end
diff --git a/test/SemaObjC/property-5.m b/test/SemaObjC/property-5.m
index cd7cc2487acc..cf4f87392b6a 100644
--- a/test/SemaObjC/property-5.m
+++ b/test/SemaObjC/property-5.m
@@ -8,7 +8,7 @@
@interface MutableNSData : NSData @end
-@interface Base : NSData <P1>
+@interface Base : NSData <P1> // expected-note {{receiver is instance of class declared here}}
@property(readonly) id ref;
@property(readonly) Base *p_base;
@property(readonly) NSData *nsdata;
diff --git a/test/SemaObjC/property-ambiguous-synthesis.m b/test/SemaObjC/property-ambiguous-synthesis.m
new file mode 100644
index 000000000000..98f59450744c
--- /dev/null
+++ b/test/SemaObjC/property-ambiguous-synthesis.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://13075400
+
+@protocol FooAsID
+@property (copy) 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
+
+@protocol FooAsDouble
+@property double foo; // expected-warning 2 {{property of type 'double' was selected for synthesis}} \
+ // expected-note {{it could also be property of type 'double' declared here}}
+@end
+
+@protocol FooAsShort
+@property short foo; // expected-note {{it could also be property of type 'short' declared here}}
+@end
+
+@interface NSObject @end
+
+@interface AnObject : NSObject<FooAsDouble,FooAsID>
+@end
+
+@interface Sub : AnObject
+@end
+
+@implementation Sub
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+
+@interface AnotherObject : NSObject<FooAsDouble, FooAsID,FooAsDouble, FooAsID, FooAsDouble,FooAsID>
+@end
+
+@implementation AnotherObject
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+
+@interface YetAnotherObject : NSObject<FooAsID,FooAsShort, FooAsDouble,FooAsID, FooAsShort>
+@end
+
+@implementation YetAnotherObject
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+double func(YetAnotherObject *object) {
+ return [object foo]; // expected-error {{returning 'id' from a function with incompatible result type 'double'}}
+}
diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m
index 3788bc90ddf0..0e8c3fcd85df 100644
--- a/test/SemaObjC/property-category-1.m
+++ b/test/SemaObjC/property-category-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -disable-objc-default-synthesize-properties -Wno-objc-root-class %s
@interface Object
+ (id)new;
diff --git a/test/SemaObjC/property-choose-expr.m b/test/SemaObjC/property-choose-expr.m
new file mode 100644
index 000000000000..71265e5f8c20
--- /dev/null
+++ b/test/SemaObjC/property-choose-expr.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+@interface NSArray
+-(int)count;
+@end
+
+// <rdar://problem/14438917>
+char* f(NSArray *array) {
+ return _Generic(__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(array.count), void), 0.f, array.count),
+ unsigned int:"uint",
+ float:"void",
+ default: "ignored");
+}
diff --git a/test/SemaObjC/property-in-class-extension-1.m b/test/SemaObjC/property-in-class-extension-1.m
index ab461ef6c191..51837fd212ca 100644
--- a/test/SemaObjC/property-in-class-extension-1.m
+++ b/test/SemaObjC/property-in-class-extension-1.m
@@ -8,19 +8,20 @@
@property (nonatomic, readonly) NSString* addingMemoryModel;
-@property (nonatomic, copy, readonly) NSString* matchingMemoryModel;
+@property (nonatomic, copy, readonly) NSString* matchingMemoryModel; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
-@property (nonatomic, retain, readonly) NSString* addingNoNewMemoryModel;
+@property (nonatomic, retain, readonly) NSString* addingNoNewMemoryModel; // expected-warning {{property attributes 'readonly' and 'retain' are mutually exclusive}}
@property (readonly) NSString* none;
@property (readonly) NSString* none1;
-@property (assign, readonly) NSString* changeMemoryModel; // expected-note {{property declared here}}
+@property (assign, readonly) NSString* changeMemoryModel; // expected-note {{property declared here}} \
+ // expected-warning {{property attributes 'readonly' and 'assign' are mutually exclusive}}
@property (readonly) __weak id weak_prop;
@property (readonly) __weak id weak_prop1;
-@property (assign, readonly) NSString* assignProperty;
+@property (assign, readonly) NSString* assignProperty; // expected-warning {{property attributes 'readonly' and 'assign' are mutually exclusive}}
@property (readonly) NSString* readonlyProp;
diff --git a/test/SemaObjC/property-ownership-attr.m b/test/SemaObjC/property-ownership-attr.m
new file mode 100644
index 000000000000..f83c560acb3f
--- /dev/null
+++ b/test/SemaObjC/property-ownership-attr.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://15014468
+
+@protocol P
+ @property(readonly) id z;
+@end
+
+@interface Foo
+ @property (readonly) id x;
+@end
+
+@interface MutableFoo : Foo
+ @property (copy) id x;
+@end
+
+@interface Foo (Cat) <P>
+@property (copy) id z; // expected-warning {{'copy' attribute on property 'z' does not match the property inherited from 'P'}}
+@end
+
diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m
index 19a4432de619..2366f7326550 100644
--- a/test/SemaObjC/protocol-id-test-1.m
+++ b/test/SemaObjC/protocol-id-test-1.m
@@ -7,10 +7,10 @@
@protocol P
@end
-@interface INTF<P>
+@interface INTF<P> // expected-note {{receiver is instance of class declared here}}
- (void)IMeth;
@end
@implementation INTF
-- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}}
+- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{instance method '-Meth' not found (return type defaults to 'id'); did you mean '-IMeth'?}}
@end
diff --git a/test/SemaObjC/protocol-id-test-2.m b/test/SemaObjC/protocol-id-test-2.m
index 6bd2feeeaf1f..4c1befb97f62 100644
--- a/test/SemaObjC/protocol-id-test-2.m
+++ b/test/SemaObjC/protocol-id-test-2.m
@@ -8,5 +8,5 @@
@end
@implementation INTF
-- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}}
+- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{instance method '-Meth' not found (return type defaults to 'id'); did you mean '-IMeth'?}}
@end
diff --git a/test/SemaObjC/provisional-ivar-lookup.m b/test/SemaObjC/provisional-ivar-lookup.m
index 7460fc2e2067..a6276b816d76 100644
--- a/test/SemaObjC/provisional-ivar-lookup.m
+++ b/test/SemaObjC/provisional-ivar-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar:// 8565343
@interface Foo {
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
index 50aaf2da4d9e..547e83fd0135 100644
--- a/test/SemaObjC/related-result-type-inference.m
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -173,7 +173,7 @@ void test_inference() {
@interface Fail @end
@protocol X @end
@implementation Fail
-- (id<X>) initWithX
+- (id<X>) initWithX // expected-note {{compiler has implicitly changed method 'initWithX' return type}}
{
return (id)self; // expected-warning {{casting 'Fail *' to incompatible type 'id<X>'}}
}
@@ -184,3 +184,19 @@ void test_inference() {
@interface WeirdNSString : NSString
- (id)initWithCString:(const char*)string, void *blah;
@end
+
+
+// rdar://14121570
+@protocol PMFilterManager
+@end
+
+@interface UIViewController : NSObject
+@end
+
+@implementation UIViewController
++ (UIViewController<PMFilterManager> *)newFilterViewControllerForType // expected-note {{compiler has implicitly changed method 'newFilterViewControllerForType' return type}}
+{
+ UIViewController<PMFilterManager> *filterVC;
+ return filterVC; // expected-warning {{incompatible pointer types casting 'UIViewController *' to type 'UIViewController<PMFilterManager> *'}}
+}
+@end
diff --git a/test/SemaObjC/selector-3.m b/test/SemaObjC/selector-3.m
index f968aeb278c2..d782c784f1de 100644
--- a/test/SemaObjC/selector-3.m
+++ b/test/SemaObjC/selector-3.m
@@ -14,7 +14,7 @@
- (void) foo
{
SEL a,b,c;
- a = @selector(b1ar); // expected-warning {{unimplemented selector 'b1ar'}}
+ a = @selector(b1ar); // expected-warning {{creating selector for nonexistent method 'b1ar'}}
b = @selector(bar);
}
@end
@@ -25,7 +25,7 @@
SEL func()
{
- return @selector(length); // expected-warning {{unimplemented selector 'length'}}
+ return @selector(length); // expected-warning {{creating selector for nonexistent method 'length'}}
}
// rdar://9545564
@@ -69,7 +69,7 @@ extern SEL MySelector(SEL s);
@implementation INTF
- (void) Meth {
- if( [cnx respondsToSelector:MySelector(@selector( _setQueue: ))] ) // expected-warning {{unimplemented selector '_setQueue:'}}
+ if( [cnx respondsToSelector:MySelector(@selector( _setQueue: ))] ) // expected-warning {{creating selector for nonexistent method '_setQueue:'}}
{
}
@@ -81,3 +81,32 @@ extern SEL MySelector(SEL s);
}
}
@end
+
+// rdar://14007194
+@interface UxTechTest : NSObject
+- (int) invalidate : (id)Arg; // expected-warning {{multiple selectors named 'invalidate:' found}}
++ (int) C_invalidate : (int)arg; // expected-warning {{multiple selectors named 'C_invalidate:' found}}
+@end
+
+@interface UxTechTest(CAT)
+- (char) invalidate : (int)arg; // expected-note {{also found}}
++ (int) C_invalidate : (char)arg; // expected-note {{also found}}
+@end
+
+@interface NSPort : NSObject
+- (double) invalidate : (void*)Arg1; // expected-note {{also found}}
++ (int) C_invalidate : (id*)arg; // expected-note {{also found}}
+@end
+
+
+@interface USEText : NSPort
+- (int) invalidate : (int)arg; // expected-note {{also found}}
+@end
+
+@implementation USEText
+- (int) invalidate :(int) arg { return 0; }
+@end
+
+@interface USETextSub : USEText
+- (int) invalidate : (id)arg;
+@end
diff --git a/test/SemaObjC/self-comparison.m b/test/SemaObjC/self-comparison.m
new file mode 100644
index 000000000000..00137ee0b572
--- /dev/null
+++ b/test/SemaObjC/self-comparison.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+@interface A {
+ id xxx;
+}
+-(int)bar;
+@end
+@implementation A
+-(int)bar {
+ return xxx == xxx; // expected-warning {{self-comparison always evaluates to true}}
+}
+@end
diff --git a/test/SemaObjC/sign-conversion.m b/test/SemaObjC/sign-conversion.m
new file mode 100644
index 000000000000..584ea1920271
--- /dev/null
+++ b/test/SemaObjC/sign-conversion.m
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wsign-conversion %s
+// rdar://13855394
+
+typedef unsigned int NSUInteger;
+
+@interface NSObject
+- new;
+- (NSUInteger)hash;
+@end
+
+@interface X : NSObject
+@property NSUInteger uint;
+@end
+
+@interface NSArray : NSObject
+
+- (NSUInteger)count;
+- (id)objectAtIndex:(NSUInteger)index;
+- (id)objectAtIndexedSubscript:(NSUInteger)index;
+
+@end
+
+void foo() {
+ X *x = [X new];
+ signed int sint = -1;
+ [x setUint:sint]; // expected-warning {{implicit conversion changes signedness: 'int' to 'NSUInteger'}}
+ x.uint = sint; // expected-warning {{implicit conversion changes signedness: 'int' to 'NSUInteger'}}
+}
+
+// rdar://13855682
+void Test1() {
+signed int si = -1;
+NSArray *array;
+
+(void)((NSObject*)array[si]).hash; // expected-warning {{implicit conversion changes signedness: 'int' to 'NSUInteger'}}
+
+(void)[((NSObject*)array[si]) hash]; // expected-warning {{implicit conversion changes signedness: 'int' to 'NSUInteger'}}
+(void)array[si]; // expected-warning {{implicit conversion changes signedness: 'int' to 'NSUInteger'}}
+}
diff --git a/test/SemaObjC/super-class-protocol-conformance.m b/test/SemaObjC/super-class-protocol-conformance.m
index 32d5392ad4e0..1e2d56fe1d98 100644
--- a/test/SemaObjC/super-class-protocol-conformance.m
+++ b/test/SemaObjC/super-class-protocol-conformance.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -disable-objc-default-synthesize-properties %s
// rdar://7884086
@interface NSObject @end
diff --git a/test/SemaObjC/super-dealloc-attribute.m b/test/SemaObjC/super-dealloc-attribute.m
index 35f6dac9bf42..ecab109d3089 100644
--- a/test/SemaObjC/super-dealloc-attribute.m
+++ b/test/SemaObjC/super-dealloc-attribute.m
@@ -40,9 +40,9 @@
[super MyDealloc];
} // expected-warning {{method possibly missing a [super XXX] call}}
-- (void) MyDeallocMeth {} // No warning here.
+- (void) MyDeallocMeth {}
- (void) AnnotMyDeallocMeth{} // expected-warning {{method possibly missing a [super AnnotMyDeallocMeth] call}}
-- (void) AnnotMeth{}; // No warning here. Annotation is in its class.
+- (void) AnnotMeth{};
+ (void)registerClass:(id)name {} // expected-warning {{method possibly missing a [super registerClass:] call}}
@end
@@ -85,3 +85,48 @@
}
@end
+
+// rdar://14251387
+#define IBAction void)__attribute__((ibaction)
+
+@interface UIViewController @end
+
+@interface ViewController : UIViewController
+- (void) someMethodRequiringSuper NS_REQUIRES_SUPER;
+- (IBAction) someAction;
+- (IBAction) someActionRequiringSuper NS_REQUIRES_SUPER;
+@end
+
+
+@implementation ViewController
+- (void) someMethodRequiringSuper
+{
+}
+- (IBAction) someAction
+{
+}
+- (IBAction) someActionRequiringSuper
+{
+}
+@end
+
+// rdar://15385981
+@interface Barn
+- (void)openDoor __attribute__((objc_requires_super));
+@end
+
+@implementation Barn
+- (void) openDoor
+{
+ ;
+}
+@end
+
+@interface HorseBarn:Barn @end
+
+@implementation HorseBarn
+- (void) openDoor
+{
+ ;
+} // expected-warning {{method possibly missing a [super openDoor] call}}
+@end
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
index 4741d1b5a870..aa67f0af39dc 100644
--- a/test/SemaObjC/super-property-notation.m
+++ b/test/SemaObjC/super-property-notation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface B
+(int) classGetter;
diff --git a/test/SemaObjC/synth-provisional-ivars-1.m b/test/SemaObjC/synth-provisional-ivars-1.m
index 92a9d7165f13..39f474727b7b 100644
--- a/test/SemaObjC/synth-provisional-ivars-1.m
+++ b/test/SemaObjC/synth-provisional-ivars-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// rdar://8913053
diff --git a/test/SemaObjC/synth-provisional-ivars.m b/test/SemaObjC/synth-provisional-ivars.m
index 9d7abd566d7a..d2eb61a05697 100644
--- a/test/SemaObjC/synth-provisional-ivars.m
+++ b/test/SemaObjC/synth-provisional-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
int bar;
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
index 8c9d90587f4d..884a3caf0f64 100644
--- a/test/SemaObjC/synthesized-ivar.m
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I
{
}
diff --git a/test/SemaObjC/tentative-property-decl.m b/test/SemaObjC/tentative-property-decl.m
index f69ac6dace43..aa7df5294a8a 100644
--- a/test/SemaObjC/tentative-property-decl.m
+++ b/test/SemaObjC/tentative-property-decl.m
@@ -14,7 +14,7 @@
@class NSString;
@interface MyClass : Super
-@property(nonatomic, copy, readonly) NSString *prop;
+@property(nonatomic, copy, readonly) NSString *prop; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
@property(nonatomic, copy, readonly) id warnProp; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
@end
@@ -29,7 +29,7 @@
@protocol P
-@property(nonatomic, copy, readonly) NSString *prop;
+@property(nonatomic, copy, readonly) NSString *prop; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
@property(nonatomic, copy, readonly) id warnProp; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
@end
diff --git a/test/SemaObjC/unimplemented-protocol-prop.m b/test/SemaObjC/unimplemented-protocol-prop.m
index 1438cf595d1f..270d879a7c68 100644
--- a/test/SemaObjC/unimplemented-protocol-prop.m
+++ b/test/SemaObjC/unimplemented-protocol-prop.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -disable-objc-default-synthesize-properties %s
@protocol PROTOCOL0
@required
diff --git a/test/SemaObjC/unsued-backing-ivar-warning.m b/test/SemaObjC/unsued-backing-ivar-warning.m
new file mode 100644
index 000000000000..c07dea71a7e1
--- /dev/null
+++ b/test/SemaObjC/unsued-backing-ivar-warning.m
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-property-ivar -verify -Wno-objc-root-class %s
+// rdar://14989999
+
+@interface NSObject @end
+
+@interface Example : NSObject
+@property (nonatomic, copy) id t; // expected-note {{property declared here}}
+@property (nonatomic, copy) id u; // expected-note {{property declared here}}
+@property (nonatomic, copy) id v; // expected-note {{property declared here}}
+@property (nonatomic, copy) id w;
+@property (nonatomic, copy) id x; // expected-note {{property declared here}}
+@property (nonatomic, copy) id y; // expected-note {{property declared here}}
+@property (nonatomic, copy) id z;
+@property (nonatomic, copy) id ok;
+@end
+
+@implementation Example
+- (void) setX:(id)newX { // expected-warning {{ivar '_x' which backs the property is not referenced in this property's accessor}}
+ _y = newX;
+}
+- (id) y { // expected-warning {{ivar '_y' which backs the property is not referenced in this property's accessor}}
+ return _v;
+}
+
+- (void) setV:(id)newV { // expected-warning {{ivar '_v' which backs the property is not referenced in this property's accessor}}
+ _y = newV;
+}
+
+// No warning here because there is no backing ivar.
+// both setter/getter are user defined.
+- (void) setW:(id)newW {
+ _y = newW;
+}
+- (id) w {
+ return _v;
+}
+
+- (id) u { // expected-warning {{ivar '_u' which backs the property is not referenced in this property's accessor}}
+ return _v;
+}
+
+@synthesize ok = okIvar;
+- (void) setOk:(id)newOk {
+ okIvar = newOk;
+}
+
+@synthesize t = tIvar;
+- (void) setT:(id)newT { // expected-warning {{ivar 'tIvar' which backs the property is not referenced in this property's accessor}}
+ okIvar = newT;
+}
+@end
+
+// rdar://15473432
+typedef char BOOL;
+@interface CalDAVServerVersion {
+ BOOL _supportsTimeRangeFilterWithoutEndDate;
+}
+@property (nonatomic, readonly,nonatomic) BOOL supportsTimeRangeFilterWithoutEndDate;
+@end
+
+@interface CalDAVConcreteServerVersion : CalDAVServerVersion {
+}
+@end
+
+@interface CalendarServerVersion : CalDAVConcreteServerVersion
+@end
+
+@implementation CalDAVServerVersion
+@synthesize supportsTimeRangeFilterWithoutEndDate=_supportsTimeRangeFilterWithoutEndDate;
+@end
+
+@implementation CalendarServerVersion
+-(BOOL)supportsTimeRangeFilterWithoutEndDate {
+ return 0;
+}
+@end
diff --git a/test/SemaObjC/warn-direct-ivar-access.m b/test/SemaObjC/warn-direct-ivar-access.m
index 283a00faee8c..d34e5f1894d2 100644
--- a/test/SemaObjC/warn-direct-ivar-access.m
+++ b/test/SemaObjC/warn-direct-ivar-access.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -fobjc-default-synthesize-properties -Wdirect-ivar-access -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -Wdirect-ivar-access -verify -Wno-objc-root-class %s
// rdar://6505197
__attribute__((objc_root_class)) @interface MyObject {
diff --git a/test/SemaObjC/warn-implicit-atomic-property.m b/test/SemaObjC/warn-implicit-atomic-property.m
index 887a2862250a..7d5934f481b3 100644
--- a/test/SemaObjC/warn-implicit-atomic-property.m
+++ b/test/SemaObjC/warn-implicit-atomic-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -verify -Wno-objc-root-class %s
// rdar://8774580
@interface Super
diff --git a/test/SemaObjC/warn-missing-super.m b/test/SemaObjC/warn-missing-super.m
index e9769a9db176..e3f2f418ffff 100644
--- a/test/SemaObjC/warn-missing-super.m
+++ b/test/SemaObjC/warn-missing-super.m
@@ -53,6 +53,6 @@ __attribute__((objc_root_class))
// CHECK-GC-ONLY: warn-missing-super.m:26:1: warning: method possibly missing a [super finalize] call
// CHECK-GC-ONLY: 1 warning generated.
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
+// RUN: not %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
// CHECK-ARC: warn-missing-super.m:36:10: error: ARC forbids explicit message send of 'dealloc'
// CHECK-ARC: 1 error generated.
diff --git a/test/SemaObjC/warn-retain-block-property.m b/test/SemaObjC/warn-retain-block-property.m
index 45823e33b486..84cdd9ff419c 100644
--- a/test/SemaObjC/warn-retain-block-property.m
+++ b/test/SemaObjC/warn-retain-block-property.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -Wno-objc-root-class %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
+// RUN: not %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -Wno-objc-root-class %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
// rdar://9829425
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class %s 2>&1 | FileCheck %s
// rdar://11761511
extern void doSomething();
diff --git a/test/SemaObjCXX/abstract-class-type-ivar.mm b/test/SemaObjCXX/abstract-class-type-ivar.mm
index 990ba1c2abd5..aaf4eb83735c 100644
--- a/test/SemaObjCXX/abstract-class-type-ivar.mm
+++ b/test/SemaObjCXX/abstract-class-type-ivar.mm
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://12095239
+// rdar://14261999
class CppAbstractBase {
public:
@@ -16,11 +17,14 @@ class CppConcreteSub : public CppAbstractBase {
CppConcreteSub _concrete; // expected-error{{instance variable type 'CppConcreteSub' is an abstract class}}
}
- (CppAbstractBase*)abstract;
+@property (nonatomic, readonly) const CppConcreteSub Prop; // expected-note {{property declared here}}
@end
+
@implementation Objc
- (CppAbstractBase*)abstract {
return &_concrete;
}
+@synthesize Prop; // expected-error {{synthesized instance variable type 'const CppConcreteSub' is an abstract class}}
@end
class Cpp {
diff --git a/test/SemaObjCXX/arc-nsconsumed-errors.mm b/test/SemaObjCXX/arc-nsconsumed-errors.mm
index 10ae10d04988..c78d8a5f4add 100644
--- a/test/SemaObjCXX/arc-nsconsumed-errors.mm
+++ b/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -29,11 +29,12 @@ void releaser(__attribute__((ns_consumed)) id);
releaser_t r2 = releaser; // no-warning
template <typename T>
-void templateFunction(T) {} // expected-note {{candidate function}}
+void templateFunction(T) { } // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (id)'}} \
+ // expected-note {{candidate template ignored: failed template argument deduction}}
releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}}
template <typename T>
-void templateReleaser(__attribute__((ns_consumed)) T) {}
+void templateReleaser(__attribute__((ns_consumed)) T) { } // expected-note 2{{candidate template ignored: failed template argument deduction}}
releaser_t r4 = templateReleaser<id>; // no-warning
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
index ef68b94e7284..b3519b957372 100644
--- a/test/SemaObjCXX/arc-templates.mm
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -292,3 +292,13 @@ namespace rdar12367446 {
A<id()> value;
}
}
+
+namespace rdar14467941 {
+ template<typename T> int &takePtr(const T &);
+ template<typename T> float &takePtr(T * const &);
+
+ void testTakePtr(A *a) {
+ float &fr1 = takePtr(a);
+ float &fr2 = takePtr<A>(a);
+ }
+}
diff --git a/test/SemaObjCXX/contextual-convert-to-id.mm b/test/SemaObjCXX/contextual-convert-to-id.mm
new file mode 100644
index 000000000000..602d6c24a8d6
--- /dev/null
+++ b/test/SemaObjCXX/contextual-convert-to-id.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
+
+@interface A
+- knownMethod;
+@end
+
+@interface B
+- unknownMethod;
+@end
+
+template<typename T> struct RetainPtr {
+ explicit operator T*() const;
+};
+
+void methodCallToSpecific(RetainPtr<A> a) {
+ [a knownMethod];
+ [a unknownMethod]; // expected-warning{{'A' may not respond to 'unknownMethod'}}
+}
+
+struct Incomplete; // expected-note{{forward declaration}}
+
+void methodCallToIncomplete(Incomplete &incomplete) {
+ [incomplete knownMethod]; // expected-error{{incomplete receiver type 'Incomplete'}}
+}
+
+struct IdPtr {
+ explicit operator id() const;
+};
+
+void methodCallToId(IdPtr a) {
+ [a knownMethod];
+ [a unknownMethod];
+}
diff --git a/test/SemaObjCXX/exceptions.mm b/test/SemaObjCXX/exceptions.mm
new file mode 100644
index 000000000000..37e6def35b04
--- /dev/null
+++ b/test/SemaObjCXX/exceptions.mm
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin11 -fsyntax-only -verify %s
+
+@interface NSException @end
+
+namespace test0 {
+ void test() {
+ try {
+ } catch (NSException e) { // expected-error {{can't catch an Objective-C object by value}}
+ }
+ }
+}
diff --git a/test/SemaObjCXX/instancetype.mm b/test/SemaObjCXX/instancetype.mm
index bbf100ef0458..89ff2b4b0326 100644
--- a/test/SemaObjCXX/instancetype.mm
+++ b/test/SemaObjCXX/instancetype.mm
@@ -25,7 +25,7 @@
- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
@end
-@interface Subclass1 : Root
+@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}}
- (instancetype)initSubclass1;
- (void)methodOnSubclass1;
+ (instancetype)allocSubclass1;
diff --git a/test/SemaObjCXX/ivar-construct.mm b/test/SemaObjCXX/ivar-construct.mm
index a066fca3595a..473c0bf4b02d 100644
--- a/test/SemaObjCXX/ivar-construct.mm
+++ b/test/SemaObjCXX/ivar-construct.mm
@@ -12,7 +12,7 @@ struct X : T { }; // expected-error 2{{private destructor}}
struct Z; // expected-note{{forward declaration}}
@interface A {
- X<Y> x; // expected-note{{implicit default destructor}}
+ X<Y> x; // expected-note{{implicit destructor}}
Y y; // expected-error{{private destructor}}
}
@end
diff --git a/test/SemaObjCXX/microsoft-abi-byval.mm b/test/SemaObjCXX/microsoft-abi-byval.mm
new file mode 100644
index 000000000000..f0c4caa9e06d
--- /dev/null
+++ b/test/SemaObjCXX/microsoft-abi-byval.mm
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -cxx-abi microsoft -Wno-objc-root-class %s
+
+class Foo {
+ ~Foo(); // expected-note {{implicitly declared private here}}
+};
+
+@interface bar
+- (void) my_method: (Foo)arg;
+@end
+
+@implementation bar
+- (void) my_method: (Foo)arg { // expected-error {{variable of type 'Foo' has private destructor}}
+}
+@end
diff --git a/test/SemaObjCXX/missing-lhs-gun-extension.mm b/test/SemaObjCXX/missing-lhs-gun-extension.mm
new file mode 100644
index 000000000000..0b5c998bd755
--- /dev/null
+++ b/test/SemaObjCXX/missing-lhs-gun-extension.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
+// rdar://13749180
+
+@interface NSDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+- (int &) random;
+@end
+
+@class NSString;
+
+template <class T, class U = T> T tfoo(U x) { return x; }
+
+void func() {
+ NSDictionary* foo;
+ NSString* result = foo[@"bar"] ? : foo[@"baz"];
+
+ int (*fn)(int) = (&tfoo<int> ?: 0);
+
+ int x = 0;
+ const int &y = foo.random ?: x;
+}
diff --git a/test/SemaObjCXX/overload-1.mm b/test/SemaObjCXX/overload-1.mm
deleted file mode 100644
index fc17ca2be98d..000000000000
--- a/test/SemaObjCXX/overload-1.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-@protocol Proto1 @end
-
-@protocol Proto2 @end
-
-void f(id<Proto1> *) { } // expected-note {{previous definition is here}}
-
-void f(id<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
-
-void f(Class<Proto1> *) { } // expected-note {{previous definition is here}}
-
-void f(Class<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
-
-@interface I @end
-
-void f(I<Proto1> *) { } // expected-note {{previous definition is here}}
-
-void f(I<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
-
-@interface I1 @end
-
-void f1(I<Proto1> *) { }
-
-void f1(I1<Proto1, Proto2> *) { }
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index 6f24c59e3a73..bb94d9ed92c3 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -60,9 +60,8 @@ void test2(A** ap) {
bp = ap; // expected-warning{{incompatible pointer types assigning to 'B **' from 'A **'}}
}
-// FIXME: we should either allow overloading here or give a better diagnostic
-int& cv(A*); // expected-note {{previous declaration}} expected-note 2 {{not viable}}
-float& cv(const A*); // expected-error {{cannot be overloaded}}
+int& cv(A*);
+float& cv(const A*);
int& cv2(void*);
float& cv2(const void*);
@@ -70,22 +69,20 @@ float& cv2(const void*);
void cv_test(A* a, B* b, const A* ac, const B* bc) {
int &i1 = cv(a);
int &i2 = cv(b);
- float &f1 = cv(ac); // expected-error {{no matching function}}
- float &f2 = cv(bc); // expected-error {{no matching function}}
+ float &f1 = cv(ac);
+ float &f2 = cv(bc);
int& i3 = cv2(a);
float& f3 = cv2(ac);
}
-// We agree with GCC that these can't be overloaded.
-int& qualid(id<P0>); // expected-note {{previous declaration}} expected-note {{not viable}}
-float& qualid(id<P1>); // expected-error {{cannot be overloaded}}
+int& qualid(id<P0>);
+float& qualid(id<P1>);
void qualid_test(A *a, B *b, C *c) {
int& i1 = qualid(a);
int& i2 = qualid(b);
- // This doesn't work only because the overload was rejected above.
- float& f1 = qualid(c); // expected-error {{no matching function}}
+ float& f1 = qualid(c);
id<P0> p1 = 0;
p1 = 0;
diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm
index abd4db998bcc..7bb4fab3d3fd 100644
--- a/test/SemaObjCXX/properties.mm
+++ b/test/SemaObjCXX/properties.mm
@@ -164,3 +164,42 @@ namespace test10 {
(void) t.index[t.b];
}
}
+
+// <rdar://problem/14354144>
+@interface PropertyOfItself
+@property (readonly, nonatomic) PropertyOfItself x; // expected-error {{interface type cannot be statically allocated}}
+@end
+@implementation PropertyOfItself
+@synthesize x;
+@end
+
+// rdar://14654207
+struct CGSize {
+ double width;
+ double height;
+};
+typedef struct CGSize CGSize;
+
+struct CGRect {
+ CGSize origin;
+ CGSize size;
+};
+typedef struct CGRect CGRect;
+
+typedef CGRect NSRect;
+void HappySetFrame(NSRect frame) {}
+
+__attribute__((objc_root_class))
+@interface NSObject
+@property CGRect frame;
+@end
+
+@implementation NSObject
+- (void) nothing
+{
+ HappySetFrame({{0,0}, {13,14}});
+ [self setFrame: {{0,0}, {13,14}}];
+ self.frame = {{0,0}, {13,14}};
+ self.frame = (CGRect){{3,5}, {13,14}};
+}
+@end
diff --git a/test/SemaObjCXX/property-synthesis-error.mm b/test/SemaObjCXX/property-synthesis-error.mm
index b6ab85ccab0d..dcd40eb66f69 100644
--- a/test/SemaObjCXX/property-synthesis-error.mm
+++ b/test/SemaObjCXX/property-synthesis-error.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -fobjc-default-synthesize-properties %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar: //8550657
@interface NSArray @end
diff --git a/test/SemaOpenCL/endian-attr.cl b/test/SemaOpenCL/endian-attr.cl
index e851cdf90b3b..f77664310041 100644
--- a/test/SemaOpenCL/endian-attr.cl
+++ b/test/SemaOpenCL/endian-attr.cl
@@ -1,9 +1,3 @@
// RUN: %clang_cc1 -verify %s
-constant long a __attribute__((endian(host))) = 100;
-
-constant long b __attribute__((endian(device))) = 100;
-
-constant long c __attribute__((endian(none))) = 100; // expected-warning {{unknown endian 'none'}}
-
-void func() __attribute__((endian(host))); // expected-warning {{endian attribute only applies to variables}}
+constant long a __attribute__((endian(host))) = 100; // expected-warning {{unknown attribute 'endian' ignored}}
diff --git a/test/SemaOpenCL/event_t.cl b/test/SemaOpenCL/event_t.cl
index 06197d0c1796..5ab5c1011a62 100644
--- a/test/SemaOpenCL/event_t.cl
+++ b/test/SemaOpenCL/event_t.cl
@@ -8,10 +8,11 @@ constant struct evt_s {
void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}}
-void kernel ker(event_t argevt) { // expected-error {{the event_t type cannot be used to declare a kernel function argument}}
+void kernel ker(event_t argevt) { // expected-error {{'event_t' cannot be used as the type of a kernel parameter}}
event_t e;
constant event_t const_evt; // expected-error {{the event_t type can only be used with __private address space qualifier}}
foo(e);
foo(0);
foo(5); // expected-error {{passing 'int' to parameter of incompatible type 'event_t'}}
}
+
diff --git a/test/SemaOpenCL/invalid-kernel-attrs.cl b/test/SemaOpenCL/invalid-kernel-attrs.cl
index d242eaf69296..668dc2a54d00 100644
--- a/test/SemaOpenCL/invalid-kernel-attrs.cl
+++ b/test/SemaOpenCL/invalid-kernel-attrs.cl
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify %s
-kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{attribute takes one argument}}
+kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{'vec_type_hint' attribute takes one argument}}
kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
@@ -10,7 +10,7 @@ kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{
kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
-kernel __attribute__((work_group_size_hint(8,16,32,4))) void kernel6() {} //expected-error{{attribute requires exactly 3 arguments}}
+kernel __attribute__((work_group_size_hint(8,16,32,4))) void kernel6() {} //expected-error{{'work_group_size_hint' attribute requires exactly 3 arguments}}
kernel __attribute__((work_group_size_hint(1,2,3))) __attribute__((work_group_size_hint(3,2,1))) void kernel7() {} //expected-warning{{attribute 'work_group_size_hint' is already applied with different parameters}}
diff --git a/test/SemaOpenCL/invalid-kernel-parameters.cl b/test/SemaOpenCL/invalid-kernel-parameters.cl
new file mode 100644
index 000000000000..de32eae8821e
--- /dev/null
+++ b/test/SemaOpenCL/invalid-kernel-parameters.cl
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+
+// Disallowed: parameters with type
+// bool, half, size_t, ptrdiff_t, intptr_t, and uintptr_t
+// or a struct / union with any of these types in them
+
+// TODO: Ban int types, size_t, ptrdiff_t ...
+
+kernel void bool_arg(bool x) { } // expected-error{{'bool' cannot be used as the type of a kernel parameter}}
+
+kernel void half_arg(half x) { } // expected-error{{'half' cannot be used as the type of a kernel parameter}}
+
+typedef struct ContainsBool // expected-note{{within field of type 'ContainsBool' declared here}}
+{
+ bool x; // expected-note{{field of illegal type 'bool' declared here}}
+} ContainsBool;
+
+kernel void bool_in_struct_arg(ContainsBool x) { } // expected-error{{'ContainsBool' (aka 'struct ContainsBool') cannot be used as the type of a kernel parameter}}
+
+
+
+typedef struct FooImage2D // expected-note{{within field of type 'FooImage2D' declared here}}
+{
+ image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}}
+} FooImage2D;
+
+kernel void image_in_struct_arg(FooImage2D arg) { } // expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef struct Foo // expected-note{{within field of type 'Foo' declared here}}
+{
+ int* ptrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+} Foo;
+
+kernel void pointer_in_struct_arg(Foo arg) { } // expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef union FooUnion // expected-note{{within field of type 'FooUnion' declared here}}
+{
+ int* ptrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+} FooUnion;
+
+kernel void pointer_in_union_arg(FooUnion arg) { }// expected-error{{union kernel parameters may not contain pointers}}
+
+typedef struct NestedPointer // expected-note 2 {{within field of type 'NestedPointer' declared here}}
+{
+ int x;
+ struct InnerNestedPointer
+ {
+ int* ptrField; // expected-note 3 {{field of illegal pointer type 'int *' declared here}}
+ } inner; // expected-note 3 {{within field of type 'struct InnerNestedPointer' declared here}}
+} NestedPointer;
+
+kernel void pointer_in_nested_struct_arg(NestedPointer arg) { }// expected-error{{struct kernel parameters may not contain pointers}}
+
+struct NestedPointerComplex // expected-note{{within field of type 'NestedPointerComplex' declared here}}
+{
+ int foo;
+ float bar;
+
+ struct InnerNestedPointerComplex
+ {
+ int innerFoo;
+ int* innerPtrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+ } inner; // expected-note{{within field of type 'struct InnerNestedPointerComplex' declared here}}
+
+ float y;
+ float z[4];
+};
+
+kernel void pointer_in_nested_struct_arg_complex(struct NestedPointerComplex arg) { }// expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef struct NestedBool // expected-note 2 {{within field of type 'NestedBool' declared here}}
+{
+ int x;
+ struct InnerNestedBool
+ {
+ bool boolField; // expected-note 2 {{field of illegal type 'bool' declared here}}
+ } inner; // expected-note 2 {{within field of type 'struct InnerNestedBool' declared here}}
+} NestedBool;
+
+kernel void bool_in_nested_struct_arg(NestedBool arg) { } // expected-error{{'NestedBool' (aka 'struct NestedBool') cannot be used as the type of a kernel parameter}}
+
+// Warning emitted again for argument used in other kernel
+kernel void bool_in_nested_struct_arg_again(NestedBool arg) { } // expected-error{{'NestedBool' (aka 'struct NestedBool') cannot be used as the type of a kernel parameter}}
+
+
+// Check for note with a struct not defined inside the struct
+typedef struct NestedBool2Inner
+{
+ bool boolField; // expected-note{{field of illegal type 'bool' declared here}}
+} NestedBool2Inner;
+
+typedef struct NestedBool2 // expected-note{{within field of type 'NestedBool2' declared here}}
+{
+ int x;
+ NestedBool2Inner inner; // expected-note{{within field of type 'NestedBool2Inner' (aka 'struct NestedBool2Inner') declared here}}
+} NestedBool2;
+
+kernel void bool_in_nested_struct_2_arg(NestedBool2 arg) { } // expected-error{{'NestedBool2' (aka 'struct NestedBool2') cannot be used as the type of a kernel parameter}}
+
+
+struct InnerInner
+{
+ int* foo;
+ bool x;
+};
+
+struct Valid
+{
+ float c;
+ float d;
+};
+
+struct Inner
+{
+ struct Valid v;
+ struct InnerInner a;
+ struct Valid g;
+ struct InnerInner b;
+};
+
+struct AlsoUser // expected-note{{within field of type 'AlsoUser' declared here}}
+{
+ float x;
+ struct Valid valid1;
+ struct Valid valid2;
+ struct NestedPointer aaaa; // expected-note{{within field of type 'struct NestedPointer' declared here}}
+};
+
+kernel void pointer_in_nested_struct_arg_2(struct Valid valid, struct NestedPointer arg, struct AlsoUser also) { } // expected-error 2 {{struct kernel parameters may not contain pointers}}
diff --git a/test/SemaOpenCL/invalid-kernel.cl b/test/SemaOpenCL/invalid-kernel.cl
index fb8ce5876f93..c12bd8414e27 100644
--- a/test/SemaOpenCL/invalid-kernel.cl
+++ b/test/SemaOpenCL/invalid-kernel.cl
@@ -1,7 +1,15 @@
// RUN: %clang_cc1 -verify %s
-kernel void no_ptrptr(global int **i) { } // expected-error{{kernel argument cannot be declared as a pointer to a pointer}}
+kernel void no_ptrptr(global int **i) { } // expected-error{{kernel parameter cannot be declared as a pointer to a pointer}}
kernel int bar() { // expected-error {{kernel must have void return type}}
return 6;
}
+
+kernel void main() { // expected-error {{kernel cannot be called 'main'}}
+
+}
+
+int main() { // expected-error {{function cannot be called 'main'}}
+ return 0;
+}
diff --git a/test/SemaOpenCL/str_literals.cl b/test/SemaOpenCL/str_literals.cl
new file mode 100644
index 000000000000..da665c3fd130
--- /dev/null
+++ b/test/SemaOpenCL/str_literals.cl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -verify
+// expected-no-diagnostics
+
+constant char * __constant x = "hello world";
+
+void foo(__constant char * a) {
+
+}
+
+void bar() {
+ foo("hello world");
+ foo(x);
+}
diff --git a/test/SemaOpenCL/vector_inc_dec_ops.cl b/test/SemaOpenCL/vector_inc_dec_ops.cl
new file mode 100644
index 000000000000..c65bbcb5b749
--- /dev/null
+++ b/test/SemaOpenCL/vector_inc_dec_ops.cl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
+
+typedef __attribute__((ext_vector_type(2))) char char2;
+typedef __attribute__((ext_vector_type(4))) unsigned int uint4;
+typedef __attribute__((ext_vector_type(8))) long long8;
+
+void vectorIncrementDecrementOps()
+{
+ char2 A = (char2)(1);
+ uint4 B = (uint4)(1);
+ long8 C = (long8)(1);
+
+ A++;
+ --A;
+ B--;
+ ++B;
+ C++;
+}
diff --git a/test/SemaTemplate/alias-nested-nontag.cpp b/test/SemaTemplate/alias-nested-nontag.cpp
index 4b5226b26ebb..2d0f0874e5e7 100644
--- a/test/SemaTemplate/alias-nested-nontag.cpp
+++ b/test/SemaTemplate/alias-nested-nontag.cpp
@@ -2,5 +2,4 @@
template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}
struct U { static Id<int> V; };
-Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \
- expected-error {{C++ requires a type specifier}}
+Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}}
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
index 20ba6e0cb7bc..e7be184db3d6 100644
--- a/test/SemaTemplate/alias-templates.cpp
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -166,3 +166,38 @@ namespace PR13136 {
return 0;
}
}
+
+namespace PR16646 {
+ namespace test1 {
+ template <typename T> struct DefaultValue { const T value=0;};
+ template <typename ... Args> struct tuple {};
+ template <typename ... Args> using Zero = tuple<DefaultValue<Args> ...>;
+ template <typename ... Args> void f(const Zero<Args ...> &t);
+ void f() {
+ f(Zero<int,double,double>());
+ }
+ }
+
+ namespace test2 {
+ template<int x> struct X {};
+ template <template<int x> class temp> struct DefaultValue { const temp<0> value; };
+ template <typename ... Args> struct tuple {};
+ template <template<int x> class... Args> using Zero = tuple<DefaultValue<Args> ...>;
+ template <template<int x> class... Args> void f(const Zero<Args ...> &t);
+ void f() {
+ f(Zero<X,X,X>());
+ }
+ }
+}
+
+namespace PR16904 {
+ template <typename,typename>
+ struct base {
+ template <typename> struct derived;
+ };
+ // FIXME: The diagnostics here are terrible.
+ template <typename T, typename U, typename V>
+ using derived = base<T, U>::template derived<V>; // expected-error {{expected a type}} expected-error {{expected ';'}}
+ template <typename T, typename U, typename V>
+ using derived2 = ::PR16904::base<T, U>::template derived<V>; // expected-error {{expected a type}} expected-error {{expected ';'}}
+}
diff --git a/test/SemaTemplate/array-to-pointer-decay.cpp b/test/SemaTemplate/array-to-pointer-decay.cpp
index 26d277d7dc05..dcf090161040 100644
--- a/test/SemaTemplate/array-to-pointer-decay.cpp
+++ b/test/SemaTemplate/array-to-pointer-decay.cpp
@@ -24,3 +24,15 @@ template <typename Type> static bool sanitize() {
return !c->start;
}
bool closure = sanitize<int>();
+
+// PR16206
+typedef struct {
+ char x[4];
+} chars;
+
+chars getChars();
+void use(char *);
+
+void test() {
+ use(getChars().x);
+}
diff --git a/test/SemaTemplate/canonical-expr-type.cpp b/test/SemaTemplate/canonical-expr-type.cpp
index 7582df5e66aa..4770c4fa3ed6 100644
--- a/test/SemaTemplate/canonical-expr-type.cpp
+++ b/test/SemaTemplate/canonical-expr-type.cpp
@@ -22,14 +22,10 @@ void f0a(T x, __typeof__(f(N)) y) { } // expected-note{{previous}}
void f(int);
template<typename T, T N>
-void f0a(T x, __typeof__(f(N)) y) { } // expected-error{{redefinition}} \
- // expected-note{{previous}}
+void f0a(T x, __typeof__(f(N)) y) { } // expected-error{{redefinition}}
void f(float);
-template<typename T, T N>
-void f0a(T x, __typeof__(f(N)) y) { } // expected-error{{redefinition}}
-
// Test dependently-sized array canonicalization
template<typename T, int N, int M>
void f1(T (&array)[N + M]) { } // expected-note{{previous}}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index fe23d9241108..e65da2b312f6 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -50,7 +50,9 @@ void f() {
template<typename T> class X; // expected-error{{expression}}
}
-template<typename T> class X1 var; // expected-error{{declared as a template}}
+template<typename T> class X1 var; // expected-warning{{variable templates are a C++1y extension}} \
+ // expected-error {{variable has incomplete type 'class X1'}} \
+ // expected-note {{forward declaration of 'X1'}}
namespace M {
}
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
index 80c4aaf85601..95d6c23b9e98 100644
--- a/test/SemaTemplate/constexpr-instantiate.cpp
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -201,8 +201,8 @@ namespace NoInstantiationWhenSelectingOverload {
int n;
};
- void f(S);
- void f(int);
+ int f(S);
+ int f(int);
void g() { f(0); }
void h() { (void)sizeof(f(0)); }
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index 0714c5e51648..ff7421a910bd 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1| FileCheck %s
+// 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: 15 errors
+// CHECK: 16 errors
// PR7511
template<a>
@@ -110,3 +110,35 @@ namespace libcxx_test {
template <class T> struct B {};
__pointer_traits_element_type<B<int>, true>::type x;
}
+
+namespace PR14281_part1 {
+ template <class P, int> struct A;
+ template <class P> struct A<P, 1>;
+ template <template <class, int> class S, class T> struct A<S<T, 1>, 1> {
+ typedef char type;
+ };
+ template <class T, int i> struct B {};
+ A<B<int, 1>, 1>::type x;
+}
+
+namespace PR14281_part2 {
+ typedef decltype(nullptr) nullptr_t;
+ template <class P, nullptr_t> struct A;
+ template <class P> struct A<P, nullptr>;
+ template <template <class, nullptr_t> class S, class T> struct A<S<T, nullptr>, nullptr> {
+ typedef char type;
+ };
+ template <class T, nullptr_t i> struct B {};
+ A<B<int, nullptr>, nullptr>::type x;
+}
+
+namespace PR14281_part3 {
+ extern int some_decl;
+ template <class P, int*> struct A;
+ template <class P> struct A<P, &some_decl>;
+ template <template <class, int*> class S, class T> struct A<S<T, &some_decl>, &some_decl> {
+ typedef char type;
+ };
+ template <class T, int* i> struct B {};
+ A<B<int, &some_decl>, &some_decl>::type x;
+}
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index 4c815f655875..4cfd7a5843f0 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -25,3 +25,34 @@ void g1() {
float &fr = f1(15);
int &ir = f1(HasValue());
}
+
+namespace PR16689 {
+ template <typename T1, typename T2> class tuple {
+ public:
+ template <typename = T2>
+ constexpr tuple() {}
+ };
+ template <class X, class... Y> struct a : public X {
+ using X::X;
+ };
+ auto x = a<tuple<int, int> >();
+}
+
+namespace PR16975 {
+ template <typename...> struct is {
+ constexpr operator bool() const { return false; }
+ };
+
+ template <typename... Types>
+ struct bar {
+ template <typename T,
+ bool = is<Types...>()>
+ bar(T);
+ };
+
+ struct baz : public bar<> {
+ using bar::bar;
+ };
+
+ baz data{0};
+}
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index 6391369aa5c4..439a30392118 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -47,11 +47,13 @@ template<typename T> struct X1 { };
template<typename T>
struct X2 {
- template<typename U = typename X1<T>::type> // expected-error{{no type named}}
- struct Inner1 { };
+ template<typename U = typename X1<T>::type> // expected-error{{no type named 'type' in 'X1<int>'}} \
+ // expected-error{{no type named 'type' in 'X1<char>'}}
+ struct Inner1 { }; // expected-note{{template is declared here}}
- template<T Value = X1<T>::value> // expected-error{{no member named 'value'}}
- struct NonType1 { };
+ template<T Value = X1<T>::value> // expected-error{{no member named 'value' in 'X1<int>'}} \
+ // expected-error{{no member named 'value' in 'X1<char>'}}
+ struct NonType1 { }; // expected-note{{template is declared here}}
template<T Value>
struct Inner2 { };
@@ -67,17 +69,17 @@ struct X2 {
};
};
-X2<int> x2i;
+X2<int> x2i; // expected-note{{in instantiation of template class 'X2<int>' requested here}}
X2<int>::Inner1<float> x2iif;
-X2<int>::Inner1<> x2bad; // expected-note{{instantiation of default argument}}
+X2<int>::Inner1<> x2bad; // expected-error{{too few template arguments for class template 'Inner1'}}
X2<int>::NonType1<'a'> x2_nontype1;
-X2<int>::NonType1<> x2_nontype1_bad; // expected-note{{instantiation of default argument}}
+X2<int>::NonType1<> x2_nontype1_bad; // expected-error{{too few template arguments for class template 'NonType1'}}
// Check multi-level substitution into template type arguments
X2<int>::Inner3<float>::VeryInner<> vi;
-X2<char>::Inner3<int>::NonType2<> x2_deep_nontype;
+X2<char>::Inner3<int>::NonType2<> x2_deep_nontype; // expected-note{{in instantiation of template class 'X2<char>' requested here}}
template<typename T, typename U>
struct is_same { static const bool value = false; };
@@ -136,3 +138,24 @@ namespace PR9643 {
vector<int, allocator<int> > v = initializer<vector>(5);
}
}
+
+namespace PR16288 {
+ template<typename X>
+ struct S {
+ template<typename T = int, typename U> // expected-warning {{C++11}}
+ void f();
+ };
+ template<typename X>
+ template<typename T, typename U>
+ void S<X>::f() {}
+}
+
+namespace DR1635 {
+ template <class T> struct X {
+ template <class U = typename T::type> static void f(int) {} // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} \
+ // expected-warning {{C++11}}
+ static void f(...) {}
+ };
+
+ int g() { X<int>::f(0); } // expected-note {{in instantiation of template class 'DR1635::X<int>' requested here}}
+}
diff --git a/test/SemaTemplate/dependent-expr.cpp b/test/SemaTemplate/dependent-expr.cpp
index d75b0f3e3029..2c26ec53a0ae 100644
--- a/test/SemaTemplate/dependent-expr.cpp
+++ b/test/SemaTemplate/dependent-expr.cpp
@@ -72,3 +72,24 @@ namespace PR8795 {
return data[0];
}
}
+
+template<typename T> struct CastDependentIntToPointer {
+ static void* f() {
+ T *x;
+ return ((void*)(((unsigned long)(x)|0x1ul)));
+ }
+};
+
+// Regression test for crasher in r194540.
+namespace PR10837 {
+ typedef void t(int);
+ template<typename> struct A {
+ void f();
+ static t g;
+ };
+ t *p;
+ template<typename T> void A<T>::f() {
+ p = g;
+ }
+ template struct A<int>;
+}
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index fa47ef535815..4d4aafa918cb 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -354,7 +354,6 @@ namespace rdar12629723 {
struct A : public B { // expected-note{{'rdar12629723::X::A' declared here}}
virtual void foo() { }
};
- struct B;
struct D : T::foo { };
struct E : D { };
@@ -388,3 +387,15 @@ namespace PR14695_A { void PR14695_f(PR14695_X); } // expected-note {{'PR14695_f
template<typename T> void PR14695_g(T t) { PR14695_f(t); } // expected-error {{call to function 'PR14695_f' that is neither visible in the template definition nor found by argument-dependent lookup}}
using namespace PR14695_A;
template void PR14695_g(PR14695_X); // expected-note{{requested here}}
+
+namespace OperatorNew {
+ template<typename T> void f(T t) {
+ operator new(100, t); // expected-error{{call to function 'operator new' that is neither visible in the template definition nor found by argument-dependent lookup}}
+ // FIXME: This should give the same error.
+ new (t) int;
+ }
+ struct X {};
+};
+using size_t = decltype(sizeof(0));
+void *operator new(size_t, OperatorNew::X); // expected-note-re {{should be declared prior to the call site$}}
+template void OperatorNew::f(OperatorNew::X); // expected-note {{instantiation of}}
diff --git a/test/SemaTemplate/derived.cpp b/test/SemaTemplate/derived.cpp
index 7b91f9a3ed3f..ce20cea7dcc5 100644
--- a/test/SemaTemplate/derived.cpp
+++ b/test/SemaTemplate/derived.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T> class vector2 {};
template<typename T> class vector : vector2<T> {};
@@ -28,3 +29,26 @@ namespace rdar13267210 {
}
};
}
+
+namespace PR16292 {
+ class IncompleteClass; // expected-note{{forward declaration}}
+ class BaseClass {
+ IncompleteClass Foo; // expected-error{{field has incomplete type}}
+ };
+ template<class T> class DerivedClass : public BaseClass {};
+ void* p = new DerivedClass<void>;
+}
+
+namespace rdar14183893 {
+ class Typ { // expected-note {{not complete}}
+ Typ x; // expected-error {{incomplete type}}
+ };
+
+ template <unsigned C> class B : Typ {};
+ typedef B<0> TFP;
+
+ class A {
+ TFP m_p;
+ void Enable() { 0, A(); } // expected-warning {{unused}}
+ };
+}
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 6806c24a84eb..4e1af9ad1f96 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename A> class s0 {
@@ -76,3 +76,9 @@ namespace rdar13140795 {
Marshal<int>::gc();
}
}
+
+namespace PR16852 {
+ template<typename T> struct S { int a; T x; };
+ 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'}}
+}
diff --git a/test/SemaTemplate/exception-spec-crash.cpp b/test/SemaTemplate/exception-spec-crash.cpp
new file mode 100644
index 000000000000..4d9355974c9e
--- /dev/null
+++ b/test/SemaTemplate/exception-spec-crash.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s
+
+template <class _Tp> struct is_nothrow_move_constructible {
+ static const bool value = false;
+};
+
+template <class _Tp>
+class allocator;
+
+template <>
+class allocator<char> {};
+
+template <class _Allocator>
+class basic_string {
+ typedef _Allocator allocator_type;
+ basic_string(basic_string &&__str)
+ noexcept(is_nothrow_move_constructible<allocator_type>::value);
+};
+
+class Foo {
+ Foo(Foo &&) noexcept = default;
+#ifdef CXX_EXCEPTIONS
+// expected-error@-2 {{does not match the calculated}}
+#else
+// expected-no-diagnostics
+#endif
+ Foo &operator=(Foo &&) noexcept = default;
+ basic_string<allocator<char> > vectorFoo_;
+};
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index e3e77d082844..d04046462a04 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -15,9 +15,9 @@ struct X0 {
return x + 1; // expected-error{{invalid operands}}
}
T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
-
- template<typename U>
- T f0(T, U) { return T(); }
+
+ template <typename U> T f0(T, U) { return T(); } // expected-note {{candidate template ignored: could not match 'int (int, U)' against 'int (int) const'}} \
+ // expected-note {{candidate template ignored: could not match 'int' against 'int *'}}
};
template<typename T>
@@ -59,13 +59,14 @@ template int *X2::f1(int *); // okay
template void X2::f2(int *, int *); // expected-error{{ambiguous}}
-
-template<typename T> void print_type() { }
+template <typename T>
+void print_type() {} // expected-note {{candidate template ignored: could not match 'void ()' against 'void (float *)'}}
template void print_type<int>();
template void print_type<float>();
-template<typename T> void print_type(T*) { }
+template <typename T>
+void print_type(T *) {} // expected-note {{candidate template ignored: could not match 'void (int *)' against 'void (float *)'}}
template void print_type(int*);
template void print_type<int>(float*); // expected-error{{does not refer}}
@@ -94,7 +95,7 @@ namespace PR7622 {
template<typename,typename>
struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \
- // expected-error{{expected member name or ';' after declaration specifiers}}
+ // expected-error{{expected member name or ';' after declaration specifiers}}
template struct basic_streambuf<int>;
}
@@ -105,3 +106,46 @@ class TC1 {
void foo() { }
};
};
+
+namespace PR8020 {
+ template <typename T> struct X { X() {} };
+ template<> struct X<int> { X(); };
+ template X<int>::X() {} // expected-error{{function cannot be defined in an explicit instantiation}}
+}
+
+namespace PR10086 {
+ template void foobar(int i) {} // expected-error{{function cannot be defined in an explicit instantiation}}
+ int func() {
+ foobar(5);
+ }
+}
+
+namespace undefined_static_data_member {
+ template<typename T> struct A {
+ static int a; // expected-note {{here}}
+ template<typename U> static int b; // expected-note {{here}} expected-warning {{extension}}
+ };
+ struct B {
+ template<typename U> static int c; // expected-note {{here}} expected-warning {{extension}}
+ };
+
+ template int A<int>::a; // expected-error {{explicit instantiation of undefined static data member 'a' of class template 'undefined_static_data_member::A<int>'}}
+ template int A<int>::b<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::A<int>::b<int>'}}
+ template int B::c<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::B::c<int>'}}
+
+
+ template<typename T> struct C {
+ static int a;
+ template<typename U> static int b; // expected-warning {{extension}}
+ };
+ struct D {
+ template<typename U> static int c; // expected-warning {{extension}}
+ };
+ template<typename T> int C<T>::a;
+ template<typename T> template<typename U> int C<T>::b; // expected-warning {{extension}}
+ template<typename U> int D::c; // expected-warning {{extension}}
+
+ template int C<int>::a;
+ template int C<int>::b<int>;
+ template int D::c<int>;
+}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index 7fe6bf37d752..07d73894468f 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -19,3 +19,31 @@ namespace PR6161 {
};
numpunct<char>::~numpunct(); // expected-error{{expected the class name after '~' to name a destructor}}
}
+
+namespace PR12331 {
+ template<typename T> struct S {
+ struct U { static const int n = 5; };
+ enum E { e = U::n }; // expected-note {{implicit instantiation first required here}}
+ int arr[e];
+ };
+ template<> struct S<int>::U { static const int n = sizeof(int); }; // expected-error {{explicit specialization of 'U' after instantiation}}
+}
+
+namespace PR18246 {
+ template<typename T>
+ class Baz {
+ public:
+ template<int N> void bar();
+ };
+
+ template<typename T>
+ template<int N>
+ void Baz<T>::bar() {
+ }
+
+ // FIXME: Don't suggest the 'template<>' correction here, because this cannot
+ // be an explicit specialization.
+ template<typename T>
+ void Baz<T>::bar<0>() { // expected-error {{requires 'template<>'}}
+ }
+}
diff --git a/test/SemaTemplate/extension-sfinae.cpp b/test/SemaTemplate/extension-sfinae.cpp
new file mode 100644
index 000000000000..b745e0d9896f
--- /dev/null
+++ b/test/SemaTemplate/extension-sfinae.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify %s -pedantic-errors -DPEDANTIC
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify %s -Wno-c++11-narrowing
+
+namespace cce_narrowing {
+ decltype(short{123456}) a;
+#if PEDANTIC
+ // expected-error@-2 {{cannot be narrowed}} expected-note@-2 {{cast}}
+#endif
+
+ template<typename T> int f(decltype(T{123456})); // expected-note {{cannot be narrowed}}
+ int b = f<short>(0); // expected-error {{no match}}
+}
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 8a478777eb7e..e9b2b9b8e64e 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -232,16 +232,23 @@ namespace PR10660 {
}
namespace rdar11147355 {
- template <class T>
+ template <class T>
struct A {
template <class U> class B;
- template <class S> template <class U> friend class A<S>::B;
+ template <class S> template <class U> friend class A<S>::B; // expected-warning {{dependent nested name specifier 'A<S>::' for friend template declaration is not supported; ignoring this friend declaration}}
+ private:
+ int n; // expected-note {{here}}
};
-
+
template <class S> template <class U> class A<S>::B {
- };
-
+ public:
+ // FIXME: This should be permitted.
+ int f(A<S*> a) { return a.n; } // expected-error {{private}}
+ };
+
A<double>::B<double> ab;
+ A<double*> a;
+ int k = ab.f(a); // expected-note {{instantiation of}}
}
namespace RedeclUnrelated {
diff --git a/test/SemaTemplate/function-template-specialization-noreturn.cpp b/test/SemaTemplate/function-template-specialization-noreturn.cpp
new file mode 100644
index 000000000000..3e1f61855a50
--- /dev/null
+++ b/test/SemaTemplate/function-template-specialization-noreturn.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Split from function-template-specialization.cpp because the noreturn warning
+// requires analysis-based warnings, which the other errors in that test case
+// disable.
+
+template <int N> void __attribute__((noreturn)) f3() { __builtin_unreachable(); }
+template <> void f3<1>() { } // expected-warning {{function declared 'noreturn' should not return}}
diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp
index a0d41b205344..6327ff64c336 100644
--- a/test/SemaTemplate/function-template-specialization.cpp
+++ b/test/SemaTemplate/function-template-specialization.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<int N> void f0(int (&array)[N]);
+template <int N>
+void f0(int (&array)[N]); // expected-note {{candidate template ignored: could not match 'int' against 'char'}}
// Simple function template specialization (using overloading)
template<> void f0(int (&array)[1]);
@@ -46,3 +47,12 @@ namespace PR8295 {
template <typename T> void f(T t) {}
template <typename T> void f<T*>(T* t) {} // expected-error{{function template partial specialization is not allowed}}
}
+
+class Foo {
+ template<class T>
+ static void Bar(const T& input);
+
+ // Don't crash here.
+ template<>
+ static void Bar(const long& input) {} // expected-error{{explicit specialization of 'Bar' in class scope}}
+};
diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
index 97bf00303bbe..5f43ea2c27a1 100644
--- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
+++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
@@ -44,13 +44,14 @@ namespace dr1330_example {
A<int>().f(42);
}
+ struct S {
+ template<typename T>
+ static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \
+ // expected-note {{instantiation of exception spec}}
+ typedef decltype(f<S>()) X;
+ };
+
int test2() {
- struct S {
- template<typename T>
- static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \
- // expected-note {{instantiation of exception spec}}
- typedef decltype(f<S>()) X;
- };
S().f<S>(); // ok
S().f<int>(); // expected-note {{instantiation of exception spec}}
}
diff --git a/test/SemaTemplate/instantiate-expr-5.cpp b/test/SemaTemplate/instantiate-expr-5.cpp
index 13b7eae21fd4..c42c2a964dc2 100644
--- a/test/SemaTemplate/instantiate-expr-5.cpp
+++ b/test/SemaTemplate/instantiate-expr-5.cpp
@@ -36,3 +36,13 @@ namespace PR5880 {
template void test_anon_union<int>();
}
+
+namespace AddrOfClassMember {
+ template <typename T> struct S {
+ int n;
+ static void f() {
+ +T::n; // expected-error {{invalid use of member}}
+ }
+ };
+ void g() { S<S<int> >::f(); } // expected-note {{in instantiation of}}
+}
diff --git a/test/SemaTemplate/instantiate-function-params.cpp b/test/SemaTemplate/instantiate-function-params.cpp
index 54847e419086..5bfae537c04d 100644
--- a/test/SemaTemplate/instantiate-function-params.cpp
+++ b/test/SemaTemplate/instantiate-function-params.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i686-unknown-unknown -fsyntax-only -verify %s
// PR6619
template<bool C> struct if_c { };
@@ -81,10 +81,21 @@ namespace InstantiateFunctionTypedef {
template<typename T>
struct X {
typedef int functype(int, int);
- functype func;
+ functype func1;
+ __attribute__((noreturn)) functype func2;
+
+ typedef int stdfunctype(int, int) __attribute__((stdcall));
+ __attribute__((stdcall)) functype stdfunc1;
+ stdfunctype stdfunc2;
+
+ __attribute__((pcs("aapcs"))) functype pcsfunc; // expected-warning {{calling convention 'pcs' ignored for this target}}
};
void f(X<int> x) {
- (void)x.func(1, 2);
+ (void)x.func1(1, 2);
+ (void)x.func2(1, 2);
+ (void)x.stdfunc1(1, 2);
+ (void)x.stdfunc2(1, 2);
+ (void)x.pcsfunc(1, 2);
}
}
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index 6a1a57ca659e..22c70be3a8dc 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -118,3 +118,18 @@ namespace PR13064 {
template<typename T> struct C { T a = { 0 }; }; // expected-error{{explicit}}
C<A> c; // expected-note{{here}}
}
+
+namespace PR16903 {
+ // Make sure we properly instantiate list-initialization.
+ template<typename T>
+ void fun (T it) {
+ int m = 0;
+ for (int i = 0; i < 4; ++i, ++it){
+ m |= long{char{*it}};
+ }
+ }
+ int test() {
+ char in[4] = {0,0,0,0};
+ fun(in);
+ }
+}
diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp
index c151fbb9a5ba..2bf24c2188e6 100644
--- a/test/SemaTemplate/instantiate-local-class.cpp
+++ b/test/SemaTemplate/instantiate-local-class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
// expected-no-diagnostics
template<typename T>
void f0() {
@@ -66,3 +66,118 @@ namespace PR8801 {
template void foo<Y>();
}
+
+namespace TemplatePacksAndLambdas {
+ template <typename ...T> int g(T...);
+ struct S {
+ template <typename ...T> static void f(int f = g([]{ static T t; return ++t; }()...)) {}
+ };
+ void h() { S::f<int, int, int>(); }
+}
+
+namespace PR9685 {
+ template <class Thing> void forEach(Thing t) { t.func(); }
+
+ template <typename T> void doIt() {
+ struct Functor {
+ void func() { (void)i; }
+ int i;
+ };
+
+ forEach(Functor());
+ }
+
+ void call() {
+ doIt<int>();
+ }
+}
+
+namespace PR12702 {
+ struct S {
+ template <typename F> bool apply(F f) { return f(); }
+ };
+
+ template <typename> struct T {
+ void foo() {
+ struct F {
+ int x;
+
+ bool operator()() { return x == 0; }
+ };
+
+ S().apply(F());
+ }
+ };
+
+ void call() { T<int>().foo(); }
+}
+
+namespace PR17139 {
+ template <class T> void foo(const T &t) { t.foo(); }
+
+ template <class F> void bar(F *f) {
+ struct B {
+ F *fn;
+ void foo() const { fn(); }
+ } b = { f };
+ foo(b);
+ }
+
+ void go() {}
+
+ void test() { bar(go); }
+}
+
+namespace PR17740 {
+class C {
+public:
+ template <typename T> static void foo(T function);
+ template <typename T> static void bar(T function);
+ template <typename T> static void func(T function);
+};
+
+template <typename T> void C::foo(T function) { function(); }
+
+template <typename T> void C::bar(T function) {
+ foo([&function]() { function(); });
+}
+
+template <typename T> void C::func(T function) {
+ struct Struct {
+ T mFunction;
+
+ Struct(T function) : mFunction(function) {};
+
+ void operator()() {
+ mFunction();
+ };
+ };
+
+ bar(Struct(function));
+}
+
+void call() {
+ C::func([]() {});
+}
+}
+
+namespace PR14373 {
+ struct function {
+ template <typename _Functor> function(_Functor __f) { __f(); }
+ };
+ template <typename Func> function exec_func(Func f) {
+ struct functor {
+ functor(Func f) : func(f) {}
+ void operator()() const { func(); }
+ Func func;
+ };
+ return functor(f);
+ }
+ struct Type {
+ void operator()() const {}
+ };
+ int call() {
+ exec_func(Type());
+ return 0;
+ }
+}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 7b42a27d6b2c..3f49606b86e5 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -91,13 +91,11 @@ namespace test2 {
typedef int X;
};
typename Foo::X x;
- class Foo;
};
template class B<int>;
template <typename T> class C {
class Foo;
- class Foo;
};
template <typename T> class C<T>::Foo {
int x;
diff --git a/test/SemaTemplate/instantiate-member-pointers.cpp b/test/SemaTemplate/instantiate-member-pointers.cpp
index 0db90e3cbf12..4757870d13b7 100644
--- a/test/SemaTemplate/instantiate-member-pointers.cpp
+++ b/test/SemaTemplate/instantiate-member-pointers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct Y {
int x;
};
@@ -65,3 +65,10 @@ namespace ValueDepMemberPointer {
}
S<int> s;
}
+
+namespace PR18192 {
+ struct A { struct { int n; }; };
+ template<int A::*> struct X {};
+ constexpr int A::*p = &A::n;
+ X<p> x; // expected-error{{not a pointer to member constant}}
+}
diff --git a/test/SemaTemplate/instantiate-overload-candidates.cpp b/test/SemaTemplate/instantiate-overload-candidates.cpp
index 7542dbd8ab9b..6b156a20a4cb 100644
--- a/test/SemaTemplate/instantiate-overload-candidates.cpp
+++ b/test/SemaTemplate/instantiate-overload-candidates.cpp
@@ -26,7 +26,7 @@ template<typename T> struct X {
static T f() { T::error; } // expected-error {{has no members}}
static T f(bool);
};
-void (*p)() = &X<void>().f; // expected-note {{instantiation of}}
+void (*p)() = &X<void>::f; // expected-note {{instantiation of}}
namespace PR13098 {
struct A {
diff --git a/test/SemaTemplate/instantiate-partial-spec.cpp b/test/SemaTemplate/instantiate-partial-spec.cpp
new file mode 100644
index 000000000000..1e820e411ae3
--- /dev/null
+++ b/test/SemaTemplate/instantiate-partial-spec.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s
+// expected-no-diagnostics
+
+template<typename T> struct A {
+ template<typename U> struct B;
+ template<typename U> struct B<U*>;
+};
+template<typename T> template<typename U> struct A<T>::B<U*> {};
+template struct A<int>;
+A<int>::B<int*> b;
+
+
+template<typename T> struct B {
+ template<typename U> static const int var1;
+ template<typename U> static const int var1<U*>;
+
+ template<typename U> static const int var2;
+};
+template<typename T> template<typename U> const int B<T>::var1<U*> = 1;
+template<typename T> template<typename U> const int B<T>::var2<U*> = 1;
+template struct B<int>;
+int b_test1[B<int>::var1<int*>];
+int b_test2[B<int>::var2<int*>];
diff --git a/test/SemaTemplate/instantiate-using-decl.cpp b/test/SemaTemplate/instantiate-using-decl.cpp
index 1bfcb7a86508..a6a4ea0e0f6d 100644
--- a/test/SemaTemplate/instantiate-using-decl.cpp
+++ b/test/SemaTemplate/instantiate-using-decl.cpp
@@ -80,3 +80,27 @@ namespace test3 {
b.f1();
}
}
+
+namespace PR16936 {
+ // Make sure both using decls are properly considered for
+ // overload resolution.
+ template<class> struct A {
+ void access(int);
+ };
+ template<class> struct B {
+ void access();
+ };
+ template<class CELL> struct X : public A<CELL>, public B<CELL> {
+ using A<CELL>::access;
+ using B<CELL>::access;
+
+ void f() {
+ access(0);
+ }
+ };
+
+ void f() {
+ X<int> x;
+ x.f();
+ }
+}
diff --git a/test/SemaTemplate/local-member-templates.cpp b/test/SemaTemplate/local-member-templates.cpp
deleted file mode 100644
index 3cdf5df8d143..000000000000
--- a/test/SemaTemplate/local-member-templates.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-// RUN: %clang_cc1 -std=c++1y -verify %s
-// RUN: %clang_cc1 -std=c++1y -verify %s -fdelayed-template-parsing
-
-namespace nested_local_templates_1 {
-
-template <class T> struct Outer {
- template <class U> int outer_mem(T t, U u) {
- struct Inner {
- template <class V> int inner_mem(T t, U u, V v) {
- struct InnerInner {
- template <class W> int inner_inner_mem(W w, T t, U u, V v) {
- return 0;
- }
- };
- InnerInner().inner_inner_mem("abc", t, u, v);
- return 0;
- }
- };
- Inner i;
- i.inner_mem(t, u, 3.14);
- return 0;
- }
-
- template <class U> int outer_mem(T t, U *u);
-};
-
-template int Outer<int>::outer_mem(int, char);
-
-template <class T> template <class U> int Outer<T>::outer_mem(T t, U *u) {
- struct Inner {
- template <class V>
- int inner_mem(T t, U u, V v) { //expected-note{{candidate function}}
- struct InnerInner {
- template <class W> int inner_inner_mem(W w, T t, U u, V v) { return 0; }
- };
- InnerInner().inner_inner_mem("abc", t, u, v);
- return 0;
- }
- };
- Inner i;
- i.inner_mem(t, U{}, i);
- i.inner_mem(t, u, 3.14); //expected-error{{no matching member function for call to 'inner}}
- return 0;
-}
-
-template int Outer<int>::outer_mem(int, char *); //expected-note{{in instantiation of function}}
-
-} // end ns
-
-namespace nested_local_templates_2 {
-
-template <class T> struct Outer {
- template <class U> void outer_mem(T t, U u) {
- struct Inner {
- template <class V> struct InnerTemplateClass {
- template <class W>
- void itc_mem(T t, U u, V v, W w) { //expected-note{{candidate function}}
- struct InnerInnerInner {
- template <class X> void iii_mem(X x) {}
- };
- InnerInnerInner i;
- i.iii_mem("abc");
- }
- };
- };
- Inner i;
- typename Inner::template InnerTemplateClass<Inner> ii;
- ii.itc_mem(t, u, i, "jim");
- ii.itc_mem(t, u, 0, "abd"); //expected-error{{no matching member function}}
- }
-};
-
-template void
-Outer<int>::outer_mem(int, char); //expected-note{{in instantiation of}}
-
-}
diff --git a/test/SemaTemplate/lookup-dependent-bases.cpp b/test/SemaTemplate/lookup-dependent-bases.cpp
index 4fcfbd196407..61fca4a2a45f 100644
--- a/test/SemaTemplate/lookup-dependent-bases.cpp
+++ b/test/SemaTemplate/lookup-dependent-bases.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
// expected-no-diagnostics
class C {
diff --git a/test/SemaTemplate/ms-class-specialization-class-scope.cpp b/test/SemaTemplate/ms-class-specialization-class-scope.cpp
new file mode 100644
index 000000000000..3ebb1c9c555e
--- /dev/null
+++ b/test/SemaTemplate/ms-class-specialization-class-scope.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s -Wno-microsoft
+// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s -Wno-microsoft
+
+class A {
+public:
+ template<typename T> struct X { typedef int x; };
+
+ X<int>::x a; // expected-note {{implicit instantiation first required here}}
+
+ template<> struct X<int>; // expected-error {{explicit specialization of 'A::X<int>' after instantiation}}
+ template<> struct X<char>; // expected-note {{forward declaration}}
+
+ X<char>::x b; // expected-error {{incomplete type 'A::X<char>' named in nested name specifier}}
+
+ template<> struct X<double> {
+ typedef int y;
+ };
+
+ X<double>::y c;
+
+ template<> struct X<float> {}; // expected-note {{previous definition is here}}
+ template<> struct X<float> {}; // expected-error {{redefinition of 'A::X<float>'}}
+};
+
+A::X<void>::x axv;
+A::X<float>::x axf; // expected-error {{no type named 'x'}}
+
+template<class T> class B {
+public:
+ template<typename U> struct X { typedef int x; };
+
+ typename X<int>::x a; // expected-note {{implicit instantiation first required here}}
+
+ template<> struct X<int>; // expected-error {{explicit specialization of 'X<int>' after instantiation}}
+ template<> struct X<char>; // expected-note {{forward declaration}}
+
+ typename X<char>::x b; // expected-error {{incomplete type 'B<float>::X<char>' named in nested name specifier}}
+
+ template<> struct X<double> {
+ typedef int y;
+ };
+
+ typename X<double>::y c;
+
+ template<> struct X<float> {}; // expected-note {{previous definition is here}}
+ template<> struct X<T> {}; // expected-error {{redefinition of 'X<float>'}}
+};
+
+B<float> b; // expected-note {{in instantiation of}}
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index cb1a7f50b719..72ce056063ea 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -196,3 +196,43 @@ void f() {
}
} // namespace PR12701
+
+namespace PR16014 {
+
+struct A {
+ int a;
+ static int sa;
+};
+template <typename T> struct B : T {
+ int foo() { return a; }
+ int *bar() { return &a; }
+ int baz() { return T::a; }
+ int T::*qux() { return &T::a; }
+ static int T::*stuff() { return &T::a; }
+ static int stuff1() { return T::sa; }
+ static int *stuff2() { return &T::sa; }
+};
+
+template <typename T> struct C : T {
+ int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}}
+ int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}}
+ int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
+ int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
+ int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}}
+};
+
+template struct B<A>;
+template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::.*' requested here}}
+
+template <typename T> struct D : T {
+ struct Inner {
+ int foo() {
+ // FIXME: MSVC can find this in D's base T! Even worse, if ::sa exists,
+ // clang will use it instead.
+ return sa; // expected-error {{use of undeclared identifier 'sa'}}
+ }
+ };
+};
+template struct D<A>;
+
+}
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
index 47502536caf7..44cb82e95bbf 100644
--- a/test/SemaTemplate/nested-template.cpp
+++ b/test/SemaTemplate/nested-template.cpp
@@ -135,6 +135,7 @@ namespace PR10896 {
template<typename T>
T SomeField; // expected-error {{member 'SomeField' declared as a template}}
+ template<> int SomeField2; // expected-error {{extraneous 'template<>' in declaration of member 'SomeField2'}}
};
void g() {
diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp
index ad65397865ad..544d897e2449 100644
--- a/test/SemaTemplate/overload-candidates.cpp
+++ b/test/SemaTemplate/overload-candidates.cpp
@@ -79,3 +79,48 @@ void foo(NS2::array<A>); // expected-note{{candidate template ignored: could not
void test() {
foo(NS1::array<int>()); // expected-error{{no matching function for call to 'foo'}}
}
+
+namespace std {
+ template<bool, typename = void> struct enable_if {};
+ template<typename T> struct enable_if<true, T> { typedef T type; };
+
+ template<typename T, T V> struct integral_constant { static const T value = V; };
+ typedef integral_constant<bool, false> false_type;
+ typedef integral_constant<bool, true> true_type;
+};
+
+namespace PR15673 {
+ template<typename T>
+ struct a_trait : std::false_type {};
+
+ template<typename T,
+ typename Requires = typename std::enable_if<a_trait<T>::value>::type> // expected-warning {{C++11 extension}}
+ // expected-note@-1 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+ void foo() {}
+ void bar() { foo<int>(); } // expected-error {{no matching function for call to 'foo'}}
+
+
+ template<typename T>
+ struct some_trait : std::false_type {};
+
+ // FIXME: It would be nice to tunnel the 'disabled by enable_if' diagnostic through here.
+ template<typename T>
+ struct a_pony : std::enable_if<some_trait<T>::value> {};
+
+ template<typename T,
+ typename Requires = typename a_pony<T>::type> // expected-warning {{C++11 extension}}
+ // FIXME: The source location here is poor.
+ void baz() { } // expected-note {{candidate template ignored: substitution failure [with T = int]: no type named 'type' in 'PR15673::a_pony<int>'}}
+ void quux() { baz<int>(); } // expected-error {{no matching function for call to 'baz'}}
+
+
+ // FIXME: This note doesn't make it clear which candidate we rejected.
+ template <typename T>
+ using unicorns = typename std::enable_if<some_trait<T>::value>::type; // expected-warning {{C++11 extension}}
+ // expected-note@-1 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+
+ template<typename T,
+ typename Requires = unicorns<T> > // expected-warning {{C++11 extension}}
+ void wibble() {}
+ void wobble() { wibble<int>(); } // expected-error {{no matching function for call to 'wibble'}}
+}
diff --git a/test/SemaTemplate/recovery-crash.cpp b/test/SemaTemplate/recovery-crash.cpp
index 61e880bf5b03..78f6db40d5c8 100644
--- a/test/SemaTemplate/recovery-crash.cpp
+++ b/test/SemaTemplate/recovery-crash.cpp
@@ -16,3 +16,22 @@ void Test() {
B<int> b(0); // expected-note{{in instantiation of function template}}
}
+
+// Don't crash here.
+namespace PR16134 {
+ template <class P> struct S // expected-error {{expected ';'}}
+ template <> static S<Q>::f() // expected-error +{{}}
+}
+
+namespace PR16225 {
+ template <typename T> void f();
+ template<typename C> void g(C*) {
+ struct LocalStruct : UnknownBase<Mumble, C> { }; // expected-error {{unknown template name 'UnknownBase'}} \
+ // expected-error {{use of undeclared identifier 'Mumble'}}
+ f<LocalStruct>(); // expected-warning {{template argument uses local type 'LocalStruct'}}
+ }
+ struct S;
+ void h() {
+ g<S>(0); // expected-note {{in instantiation of function template specialization}}
+ }
+}
diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp
index 0c9bacca3edd..7fb16eb46745 100644
--- a/test/SemaTemplate/resolve-single-template-id.cpp
+++ b/test/SemaTemplate/resolve-single-template-id.cpp
@@ -33,7 +33,7 @@ int main()
oneT<int>; // expected-warning {{expression result unused}}
twoT<int>; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
typeid(oneT<int>); // expected-warning{{expression result unused}}
- sizeof(oneT<int>); // expected-warning {{expression result unused}}
+ sizeof(oneT<int>); // expected-error {{invalid application of 'sizeof' to a function type}}
sizeof(twoT<int>); //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
decltype(oneT<int>)* fun = 0;
@@ -74,7 +74,7 @@ int main()
}
struct rdar9108698 {
- template<typename> void f();
+ template<typename> void f(); // expected-note{{possible target for call}}
};
void test_rdar9108698(rdar9108698 x) {
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 24509524b294..8f6cc192fa8b 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -75,6 +75,9 @@ struct Z {
int int_member;
float float_member;
+ union {
+ int union_member;
+ };
};
template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}}
A6<&Z::foo> *a17_1;
@@ -88,6 +91,7 @@ A7<&Z::int_member> *a18_1;
A7c<&Z::int_member> *a18_2;
A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float Z::*' cannot be converted to a value of type 'int Z::*'}}
A7c<(&Z::int_member)> *a18_4; // expected-warning{{address non-type template argument cannot be surrounded by parentheses}}
+A7c<&Z::union_member> *a18_5;
template<unsigned char C> struct Overflow; // expected-note{{template parameter is declared here}}
@@ -252,16 +256,16 @@ namespace PR8372 {
namespace PR9227 {
template <bool B> struct enable_if_bool { };
- template <> struct enable_if_bool<true> { typedef int type; };
- void test_bool() { enable_if_bool<false>::type i; } // expected-error{{enable_if_bool<false>}}
+ template <> struct enable_if_bool<true> { typedef int type; }; // expected-note{{'enable_if_bool<true>::type' declared here}}
+ void test_bool() { enable_if_bool<false>::type i; } // expected-error{{enable_if_bool<false>'; did you mean 'enable_if_bool<true>::type'?}}
template <char C> struct enable_if_char { };
- template <> struct enable_if_char<'a'> { typedef int type; };
- void test_char_0() { enable_if_char<0>::type i; } // expected-error{{enable_if_char<'\x00'>}}
- void test_char_b() { enable_if_char<'b'>::type i; } // expected-error{{enable_if_char<'b'>}}
- void test_char_possibly_negative() { enable_if_char<'\x02'>::type i; } // expected-error{{enable_if_char<'\x02'>}}
- void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>}}
- void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>}}
+ template <> struct enable_if_char<'a'> { typedef int type; }; // expected-note 5{{'enable_if_char<'a'>::type' declared here}}
+ void test_char_0() { enable_if_char<0>::type i; } // expected-error{{enable_if_char<'\x00'>'; did you mean 'enable_if_char<'a'>::type'?}}
+ void test_char_b() { enable_if_char<'b'>::type i; } // expected-error{{enable_if_char<'b'>'; did you mean 'enable_if_char<'a'>::type'?}}
+ void test_char_possibly_negative() { enable_if_char<'\x02'>::type i; } // expected-error{{enable_if_char<'\x02'>'; did you mean 'enable_if_char<'a'>::type'?}}
+ void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>'; did you mean 'enable_if_char<'a'>::type'?}}
+ void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>'; did you mean 'enable_if_char<'a'>::type'?}}
}
namespace PR10579 {
@@ -346,3 +350,17 @@ namespace rdar13806270 {
};
void foo() {}
}
+
+namespace PR17696 {
+ struct a {
+ union {
+ int i;
+ };
+ };
+
+ template <int (a::*p)> struct b : a {
+ b() { this->*p = 0; }
+ };
+
+ b<&a::i> c; // okay
+}
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index c9ce1b694363..dec5dd37d484 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -60,3 +60,14 @@ template <typename Primitive, template <Primitive...> class F> // expected-warni
struct unbox_args {
typedef typename Primitive::template call<F> x;
};
+
+template <template <typename> class... Templates> // expected-warning {{variadic templates are a C++11 extension}}
+struct template_tuple {};
+template <typename T>
+struct identity {};
+template <template <typename> class... Templates> // expected-warning {{variadic templates are a C++11 extension}}
+template_tuple<Templates...> f7() {}
+
+void foo() {
+ f7<identity>();
+}
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index 974f66484ba1..439d8f836f9f 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -72,7 +72,7 @@ namespace PR7114 {
int f() { return B<int>::value; }
void test_typeid(B<float>::Inner bfi) {
- (void)typeid(bfi); // expected-note{{implicit default destructor}}
+ (void)typeid(bfi); // expected-note{{implicit destructor}}
}
template<typename T>
@@ -84,3 +84,15 @@ namespace PR7114 {
xi.f();
}
}
+
+namespace DynamicCast {
+ struct Y {};
+ template<typename T> struct X : virtual Y {
+ virtual void foo() { T x; } // expected-error {{variable has incomplete type 'void'}}
+ };
+ template<typename T> struct X2 : virtual Y {
+ virtual void foo() { T x; }
+ };
+ Y* f(X<void>* x) { return dynamic_cast<Y*>(x); } // expected-note {{in instantiation of member function 'DynamicCast::X<void>::foo' requested here}}
+ Y* f2(X<void>* x) { return dynamic_cast<Y*>(x); }
+}
diff --git a/test/Tooling/Inputs/lit.local.cfg b/test/Tooling/Inputs/lit.local.cfg
deleted file mode 100644
index e6f55eef7af5..000000000000
--- a/test/Tooling/Inputs/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes = []
diff --git a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
index 6b632b0a0d81..d7ec3f60ac7c 100644
--- a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
+++ b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
@@ -2,11 +2,15 @@
// RUN: mkdir -p %t/abc/def/ijk/qwe
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp"
-// RUN: PWD="%t/abc/def" clang-check "ijk/qwe/test.cpp" 2>&1 | FileCheck %s
+// RUN: ln -sf %t/abc/def %t/abc/def2
+// RUN: cd %t/abc/def2
+// RUN: not env PWD="%t/abc/def" clang-check "ijk/qwe/test.cpp" 2>&1 | FileCheck %s
// CHECK: C++ requires
+// CHECK: /abc/def/ijk/qwe/test.cpp
invalid;
// REQUIRES: shell
// PR15590
// XFAIL: win64
+// XFAIL: mingw
diff --git a/test/Tooling/auto-detect-from-source-parent.cpp b/test/Tooling/auto-detect-from-source-parent.cpp
index f1dbc0fa6743..5f27d5ab8051 100644
--- a/test/Tooling/auto-detect-from-source-parent.cpp
+++ b/test/Tooling/auto-detect-from-source-parent.cpp
@@ -2,7 +2,7 @@
// RUN: mkdir -p %t/abc/def/ijk/qwe
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp"
-// RUN: clang-check "%t/abc/def/ijk/qwe/test.cpp" 2>&1 | FileCheck %s
+// RUN: not clang-check "%t/abc/def/ijk/qwe/test.cpp" 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
diff --git a/test/Tooling/auto-detect-from-source.cpp b/test/Tooling/auto-detect-from-source.cpp
index 77e06e781c93..6ff39acdc8c2 100644
--- a/test/Tooling/auto-detect-from-source.cpp
+++ b/test/Tooling/auto-detect-from-source.cpp
@@ -2,7 +2,7 @@
// RUN: mkdir %t
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-check "%t/test.cpp" 2>&1 | FileCheck %s
+// RUN: not clang-check "%t/test.cpp" 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
diff --git a/test/Tooling/clang-check-analyzer.cpp b/test/Tooling/clang-check-analyzer.cpp
new file mode 100644
index 000000000000..16cf7ce603ba
--- /dev/null
+++ b/test/Tooling/clang-check-analyzer.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-check -analyze "%s" -- -c 2>&1 | FileCheck %s
+
+// CHECK: Dereference of null pointer
+int a(int *x) { if(x){} *x = 47; }
diff --git a/test/Tooling/clang-check-args.cpp b/test/Tooling/clang-check-args.cpp
index 66950ae10391..202b23711865 100644
--- a/test/Tooling/clang-check-args.cpp
+++ b/test/Tooling/clang-check-args.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-check "%s" -- -c 2>&1 | FileCheck %s
+// RUN: not clang-check "%s" -- -c 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
diff --git a/test/Tooling/clang-check-autodetect-dir.cpp b/test/Tooling/clang-check-autodetect-dir.cpp
index 39a0c386fe8e..8ef3f3d01734 100644
--- a/test/Tooling/clang-check-autodetect-dir.cpp
+++ b/test/Tooling/clang-check-autodetect-dir.cpp
@@ -2,7 +2,7 @@
// RUN: mkdir -p %t/abc/def
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-check -p "%t/abc/def" "%t/test.cpp" 2>&1|FileCheck %s
+// RUN: not clang-check -p "%t/abc/def" "%t/test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
// CHECK: C++ requires
diff --git a/test/Tooling/clang-check-builtin-headers.cpp b/test/Tooling/clang-check-builtin-headers.cpp
index ed2bea0d656d..76fc9c4b3d01 100644
--- a/test/Tooling/clang-check-builtin-headers.cpp
+++ b/test/Tooling/clang-check-builtin-headers.cpp
@@ -3,7 +3,7 @@
// Add a path that doesn't exist as argv[0] for the compile command line:
// RUN: echo '[{"directory":".","command":"/random/tool -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
+// RUN: not clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
#include <stddef.h>
diff --git a/test/Tooling/clang-check-chdir.cpp b/test/Tooling/clang-check-chdir.cpp
index c8113233fa25..fbe8a19aa152 100644
--- a/test/Tooling/clang-check-chdir.cpp
+++ b/test/Tooling/clang-check-chdir.cpp
@@ -5,7 +5,7 @@
// RUN: echo "[{\"directory\":\"%t\",\"command\":\"clang -c test.cpp -I.\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\//g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
// RUN: touch "%t/clang-check-test.h"
-// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
+// RUN: not clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
#include "clang-check-test.h"
diff --git a/test/Tooling/clang-check-extra-arg.cpp b/test/Tooling/clang-check-extra-arg.cpp
new file mode 100644
index 000000000000..f6715358453f
--- /dev/null
+++ b/test/Tooling/clang-check-extra-arg.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-check "%s" -extra-arg=-Wunimplemented-warning -extra-arg-before=-Wunimplemented-warning-before -- -c 2>&1 | FileCheck %s
+
+// CHECK: unknown warning option '-Wunimplemented-warning-before'
+// CHECK: unknown warning option '-Wunimplemented-warning'
+int a(){}
diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp
index 463ed40b3e50..d85b9b1ae472 100644
--- a/test/Tooling/clang-check-pwd.cpp
+++ b/test/Tooling/clang-check-pwd.cpp
@@ -2,12 +2,16 @@
// RUN: mkdir %t
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
-// RUN: PWD="%t" clang-check -p "%t" "test.cpp" 2>&1|FileCheck %s
+// RUN: ln -sf %t %t.foobar
+// RUN: cd %t
+// RUN: not env PWD="%t.foobar" clang-check -p "%t" "test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
// CHECK: C++ requires
+// CHECK: .foobar/test.cpp
invalid;
// REQUIRES: shell
// PR15590
// XFAIL: win64
+// XFAIL: mingw
diff --git a/test/Tooling/clang-check-rel-path.cpp b/test/Tooling/clang-check-rel-path.cpp
new file mode 100644
index 000000000000..23a9345b99b3
--- /dev/null
+++ b/test/Tooling/clang-check-rel-path.cpp
@@ -0,0 +1,10 @@
+// This block test a compilation database with files relative to the directory
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo '[{"directory":"%t","command":"clang++ -c test.cpp","file":"test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: not clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
+// FIXME: Make the above easier.
+
+// CHECK: C++ requires
+invalid;
diff --git a/test/Tooling/clang-check-strip-o.cpp b/test/Tooling/clang-check-strip-o.cpp
new file mode 100644
index 000000000000..e33367bea54b
--- /dev/null
+++ b/test/Tooling/clang-check-strip-o.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo '[{"directory":".","command":"clang++ -c %t/test.cpp -o foo -ofoo","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: not clang-check -p "%t" "%t/test.cpp" -extra-arg=-v 2>&1|FileCheck %s
+// FIXME: Make the above easier.
+
+// CHECK: Invocation
+// CHECK-NOT: {{ -v}}
+// CHECK: C++ requires
+invalid;
diff --git a/test/Tooling/clang-check.cpp b/test/Tooling/clang-check.cpp
index 56835b3bf986..e3fb49c41772 100644
--- a/test/Tooling/clang-check.cpp
+++ b/test/Tooling/clang-check.cpp
@@ -2,7 +2,7 @@
// RUN: mkdir %t
// RUN: echo '[{"directory":".","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
+// RUN: not clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
// CHECK: C++ requires
diff --git a/test/Tooling/ms-asm-no-target.cpp b/test/Tooling/ms-asm-no-target.cpp
new file mode 100644
index 000000000000..68930b159680
--- /dev/null
+++ b/test/Tooling/ms-asm-no-target.cpp
@@ -0,0 +1,13 @@
+// RUN: not clang-check "%s" -- -fasm-blocks -target x86_64-apple-darwin10 2>&1 | FileCheck -check-prefix=CHECK-X86 %s
+// RUN: not clang-check "%s" -- -fasm-blocks -target powerpc-apple-darwin10 2>&1 | FileCheck -check-prefix=CHECK-PPC %s
+
+// Test that we diagnose instead of crashing when the application hasn't
+// initialized LLVM targets supporting the MS-style inline asm parser.
+// Also test that the ordinary error is emitted on unsupported architectures.
+
+void Break() {
+ __asm { int 3 }
+}
+
+// CHECK-X86: error: MS-style inline assembly is not available
+// CHECK-PPC: error: Unsupported architecture 'powerpc' for MS-style inline assembly
diff --git a/test/Tooling/multi-jobs.cpp b/test/Tooling/multi-jobs.cpp
index 1e6bce113fd5..cef84439f0da 100644
--- a/test/Tooling/multi-jobs.cpp
+++ b/test/Tooling/multi-jobs.cpp
@@ -1,4 +1,7 @@
-// RUN: clang-check "%s" -- -no-integrated-as -c 2>&1 | FileCheck %s
+// RUN: not clang-check "%s" -- -no-integrated-as -c 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
+
+// MSVC targeted drivers (*-win32) are incapable of invoking external assembler.
+// XFAIL: win32
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
index d58337c8f799..f39fded3acc7 100644
--- a/test/Unit/lit.cfg
+++ b/test/Unit/lit.cfg
@@ -4,6 +4,9 @@
import os
+import lit.formats
+import lit.util
+
# name: The name of this test suite.
config.name = 'Clang-Unit'
@@ -43,9 +46,9 @@ if config.test_exec_root is None:
# out-of-tree build situation).
# Check for 'clang_unit_site_config' user parameter, and use that if available.
- site_cfg = lit.params.get('clang_unit_site_config', None)
+ site_cfg = lit_config.params.get('clang_unit_site_config', None)
if site_cfg and os.path.exists(site_cfg):
- lit.load_config(config, 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
@@ -58,7 +61,7 @@ if config.test_exec_root is None:
llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
if not llvm_config:
- lit.fatal('No site specific configuration available!')
+ 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()
@@ -70,16 +73,16 @@ if config.test_exec_root is None:
# 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.fatal('No site specific configuration available!')
+ 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.fatal('No site specific configuration available!')
+ lit_config.fatal('No site specific configuration available!')
# Okay, that worked. Notify the user of the automagic, and reconfigure.
- lit.note('using out-of-tree build at %r' % clang_obj_root)
- lit.load_config(config, site_cfg)
+ lit_config.note('using out-of-tree build at %r' % clang_obj_root)
+ lit_config.load_config(config, site_cfg)
raise SystemExit
# If necessary, point the dynamic loader at libLLVM.so.
diff --git a/test/Unit/lit.site.cfg.in b/test/Unit/lit.site.cfg.in
index 9f4d224eb655..a255cdce0de8 100644
--- a/test/Unit/lit.site.cfg.in
+++ b/test/Unit/lit.site.cfg.in
@@ -1,3 +1,5 @@
+import sys
+
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
@@ -15,12 +17,13 @@ config.target_triple = "@TARGET_TRIPLE@"
# parameters. This is used when we can't determine the tool dir at
# configuration time.
try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
- config.llvm_libs_dir = config.llvm_libs_dir % lit.params
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+ config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+ config.llvm_build_mode = config.llvm_build_mode % lit_config.params
+except KeyError:
+ e = sys.exc_info()[1]
key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
# Let the main config do the real work.
-lit.load_config(config, "@CLANG_SOURCE_DIR@/test/Unit/lit.cfg")
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/test/lit.cfg b/test/lit.cfg
index 6b0ad59c9f1f..19daa61a64ff 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -6,6 +6,8 @@ import re
import subprocess
import tempfile
+import lit.formats
+import lit.util
# Configuration file for the 'lit' test runner.
@@ -16,9 +18,9 @@ config.name = 'Clang'
if platform.system() == 'Windows':
# Seek sane tools in directories and set to $PATH.
path = getattr(config, 'lit_tools_dir', None)
- path = lit.getToolsPath(path,
- config.environment['PATH'],
- ['cmp.exe', 'grep.exe', 'sed.exe'])
+ 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']))
@@ -44,6 +46,11 @@ config.test_format = lit.formats.ShTest(execute_external)
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s']
+# 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__)
@@ -89,12 +96,12 @@ for name in possibly_dangerous_env_vars:
if clang_obj_root is not None:
llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
if not llvm_tools_dir:
- lit.fatal('No LLVM tools dir set!')
+ lit_config.fatal('No LLVM tools dir set!')
path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
config.environment['PATH'] = path
llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
if not llvm_libs_dir:
- lit.fatal('No LLVM libs dir set!')
+ lit_config.fatal('No LLVM libs dir set!')
path = os.path.pathsep.join((llvm_libs_dir,
config.environment.get('LD_LIBRARY_PATH','')))
config.environment['LD_LIBRARY_PATH'] = path
@@ -114,9 +121,9 @@ if config.test_exec_root is None:
# out-of-tree build situation).
# Check for 'clang_site_config' user parameter, and use that if available.
- site_cfg = lit.params.get('clang_site_config', None)
+ site_cfg = lit_config.params.get('clang_site_config', None)
if site_cfg and os.path.exists(site_cfg):
- lit.load_config(config, 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
@@ -130,7 +137,7 @@ if config.test_exec_root is None:
llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
if not llvm_config:
- lit.fatal('No site specific configuration available!')
+ 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()
@@ -142,17 +149,18 @@ if config.test_exec_root is None:
# 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.fatal('No site specific configuration available!')
+ 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.fatal('No site specific configuration available! You may need to '
- 'run "make test" in your Clang build directory.')
+ 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.note('using out-of-tree build at %r' % clang_obj_root)
- lit.load_config(config, site_cfg)
+ lit_config.note('using out-of-tree build at %r' % clang_obj_root)
+ lit_config.load_config(config, site_cfg)
raise SystemExit
###
@@ -174,14 +182,14 @@ def inferClang(PATH):
clang = lit.util.which('clang', PATH)
if not clang:
- lit.fatal("couldn't find 'clang' program, try setting "
- "CLANG in your environment")
+ 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.quiet:
- lit.note('using clang: %r' % config.clang)
+if not lit_config.quiet:
+ lit_config.note('using clang: %r' % config.clang)
# 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
@@ -192,15 +200,23 @@ def getClangBuiltinIncludeDir(clang):
cmd = subprocess.Popen([clang, '-print-file-name=include'],
stdout=subprocess.PIPE)
if not cmd.stdout:
- lit.fatal("Couldn't find the include dir for Clang ('%s')" % clang)
- return cmd.stdout.read().strip()
+ 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'))
config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s'
% (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 +
- ' -ccc-cxx '))
+ ' --driver-mode=g++ '))
config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') )
@@ -218,6 +234,12 @@ config.substitutions.append(
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'. ***""") )
###
@@ -232,17 +254,25 @@ if execute_external:
config.available_features.add('shell')
# Exclude MSYS due to transforming '/' to 'X:/mingwroot/'.
-if not platform.system() in ['Windows'] or lit.getBashPath() == '':
+if not platform.system() in ['Windows'] or not execute_external:
config.available_features.add('shell-preserves-root')
# ANSI escape sequences in non-dumb terminal
if platform.system() not in ['Windows']:
config.available_features.add('ansi-escape-sequences')
+# Native compilation: host arch == target arch
+if config.host_arch in config.target_triple:
+ config.available_features.add("native")
+
# 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(path.upper())
+ isInsensitive = os.path.exists(
+ os.path.join(
+ os.path.dirname(path),
+ os.path.basename(path).upper()
+ ))
os.close(handle)
os.remove(path)
return isInsensitive
@@ -272,6 +302,7 @@ def get_llc_props(tool):
# Parse the stdout to get the list of registered targets.
parse_targets = False
for line in cmd.stdout:
+ line = line.decode('ascii')
if parse_targets:
m = re.match( r'(.*) - ', line)
if m is not None:
@@ -291,7 +322,7 @@ llc_props = get_llc_props(os.path.join(llvm_tools_dir, 'llc'))
if len(llc_props['set_of_targets']) > 0:
config.available_features.update(llc_props['set_of_targets'])
else:
- lit.fatal('No Targets Registered with the LLVM Tools!')
+ lit_config.fatal('No Targets Registered with the LLVM Tools!')
if llc_props['enable_assertions']:
config.available_features.add('asserts')
@@ -305,3 +336,43 @@ if config.llvm_use_sanitizer == "Address":
if (config.llvm_use_sanitizer == "Memory" or
config.llvm_use_sanitizer == "MemoryWithOrigins"):
config.available_features.add("msan")
+
+# 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})
+
+# On Darwin, support relocatable SDKs by providing Clang with a
+# default system root path.
+if 'darwin' in config.target_triple:
+ try:
+ cmd = subprocess.Popen(['xcrun', '--show-sdk-path'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = cmd.communicate()
+ out = out.strip()
+ res = cmd.wait()
+ except OSError:
+ res = -1
+ if res == 0 and out:
+ sdk_path = out
+ lit_config.note('using SDKROOT: %r' % sdk_path)
+ config.environment['SDKROOT'] = sdk_path
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 23eb8e228cce..9a4fa33cdc1c 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -1,3 +1,5 @@
+import sys
+
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
@@ -8,15 +10,20 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
config.clang_obj_root = "@CLANG_BINARY_DIR@"
config.target_triple = "@TARGET_TRIPLE@"
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
+config.clang_arcmt = @ENABLE_CLANG_ARCMT@
+config.clang_staticanalyzer = @ENABLE_CLANG_STATIC_ANALYZER@
+config.clang_rewriter = @ENABLE_CLANG_REWRITER@
+config.host_arch = "@HOST_ARCH@"
# 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.
try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
- config.llvm_libs_dir = config.llvm_libs_dir % lit.params
-except KeyError,e:
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+ config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError:
+ e = sys.exc_info()[1]
key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
# Let the main config do the real work.
-lit.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg")
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg")
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index eb5e366cfd71..fef0adc62156 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,11 +1,18 @@
-add_subdirectory(libclang)
-add_subdirectory(c-index-test)
-add_subdirectory(arcmt-test)
-add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
-add_subdirectory(clang-check)
-add_subdirectory(clang-format)
+if(CLANG_ENABLE_REWRITER)
+ add_subdirectory(clang-format)
+endif()
+
+if(CLANG_ENABLE_ARCMT)
+ add_subdirectory(libclang)
+ add_subdirectory(c-index-test)
+ add_subdirectory(arcmt-test)
+ add_subdirectory(c-arcmt-test)
+endif()
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ add_subdirectory(clang-check)
+endif()
# We support checking out the clang-tools-extra repository into the 'extra'
# subdirectory. It contains tools developed as part of the Clang/LLVM project
diff --git a/tools/Makefile b/tools/Makefile
index b33c74d66e52..94032d20b032 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -11,15 +11,29 @@ CLANG_LEVEL := ..
include $(CLANG_LEVEL)/../../Makefile.config
-DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
- clang-check clang-format
+DIRS :=
+PARALLEL_DIRS := driver diagtool
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+ PARALLEL_DIRS += clang-format
+endif
+
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER), 1)
+ PARALLEL_DIRS += clang-check
+endif
+
+ifeq ($(ENABLE_CLANG_ARCMT), 1)
+ DIRS += libclang c-index-test c-arcmt-test
+ PARALLEL_DIRS += arcmt-test
+endif
# Recurse into the extra repository of tools if present.
-OPTIONAL_DIRS := extra
+OPTIONAL_PARALLEL_DIRS := extra
ifeq ($(BUILD_CLANG_ONLY),YES)
- DIRS := driver libclang c-index-test
- OPTIONAL_DIRS :=
+ DIRS := libclang c-index-test
+ PARALLEL_DIRS := driver
+ OPTIONAL_PARALLEL_DIRS :=
endif
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index 52898ceab7e2..4b9b8db0a0b0 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1
NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangARCMigrate.a clangRewriteCore.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a \
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 179a11561bd3..50426e3f4202 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -61,11 +61,11 @@ static llvm::cl::extrahelp extraHelp(
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
-llvm::sys::Path GetExecutablePath(const char *Argv0) {
+std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
- return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+ return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index 02b8ab7bd687..4a01c729c24b 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -21,7 +21,7 @@ NO_INSTALL = 1
# LINK_COMPONENTS before including Makefile.rules
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
# Note that 'USEDLIBS' must include all of the core clang libraries
# when -static is given to linker on cygming.
@@ -29,7 +29,7 @@ USEDLIBS = clang.a \
clangARCMigrate.a \
clangRewriteFrontend.a \
clangRewriteCore.a \
- clangFrontend.a clangDriver.a \
+ clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index d90dc6d95c3a..d850411f33e5 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -24,6 +24,6 @@ set_target_properties(c-index-test
# If libxml2 is available, make it available for c-index-test.
if (CLANG_HAVE_LIBXML)
- include_directories(${LIBXML2_INCLUDE_DIR})
+ include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
target_link_libraries(c-index-test ${LIBXML2_LIBRARIES})
endif()
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 7723115263ee..b38d654a3ac5 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -22,12 +22,12 @@ TOOL_NO_EXPORTS = 1
# LINK_COMPONENTS before including Makefile.rules
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
# Note that 'USEDLIBS' must include all of the core clang libraries
# when -static is given to linker on cygming.
USEDLIBS = clang.a \
- clangFormat.a clangRewriteCore.a \
+ clangIndex.a clangFormat.a clangRewriteCore.a \
clangFrontend.a clangDriver.a \
clangTooling.a \
clangSerialization.a clangParse.a clangSema.a \
@@ -37,4 +37,12 @@ USEDLIBS = clang.a \
include $(CLANG_LEVEL)/Makefile
LIBS += $(LIBXML2_LIBS)
+
+# Headers in $(LIBXML2_INC) should not be checked with clang's -Wdocumentation.
+# Use -isystem instead of -I then.
+# FIXME: Could autoconf detect clang or availability of -isystem?
+ifneq ($(findstring -Wdocumentation,$(OPTIMIZE_OPTION)),)
+CPPFLAGS += $(subst -I,-isystem ,$(LIBXML2_INC))
+else
CPPFLAGS += $(LIBXML2_INC)
+endif
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index e5752341679d..90a65282f4ca 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -694,10 +694,13 @@ static void PrintCursor(CXCursor Cursor,
printf(" (static)");
if (clang_CXXMethod_isVirtual(Cursor))
printf(" (virtual)");
-
+ if (clang_CXXMethod_isPureVirtual(Cursor))
+ printf(" (pure)");
if (clang_Cursor_isVariadic(Cursor))
printf(" (variadic)");
-
+ if (clang_Cursor_isObjCOptional(Cursor))
+ printf(" (@optional)");
+
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
CXType T =
clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
@@ -1157,6 +1160,7 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
CXClientData d) {
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
+ enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
PrintCursor(cursor, NULL);
PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
if (clang_isConstQualifiedType(T))
@@ -1165,6 +1169,10 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
printf(" volatile");
if (clang_isRestrictQualifiedType(T))
printf(" restrict");
+ if (RQ == CXRefQualifier_LValue)
+ printf(" lvalue-ref-qualifier");
+ if (RQ == CXRefQualifier_RValue)
+ printf(" rvalue-ref-qualifier");
/* Print the canonical type if it is different. */
{
CXType CT = clang_getCanonicalType(T);
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index e8d0d0a18abd..2070de37fcf5 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -14,6 +14,7 @@ target_link_libraries(clang-check
clangTooling
clangBasic
clangRewriteFrontend
+ clangStaticAnalyzerFrontend
)
install(TARGETS clang-check
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index bf4337486ad9..701db52334c6 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -17,10 +17,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
@@ -28,10 +28,12 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Option/OptTable.h"
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
+using namespace llvm::opt;
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp MoreHelp(
@@ -62,6 +64,9 @@ static cl::opt<bool> ASTPrint(
static cl::opt<std::string> ASTDumpFilter(
"ast-dump-filter",
cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)));
+static cl::opt<bool> Analyze(
+ "analyze",
+ cl::desc(Options->getOptionHelpText(options::OPT_analyze)));
static cl::opt<bool> Fixit(
"fixit",
@@ -70,6 +75,11 @@ static cl::opt<bool> FixWhatYouCan(
"fix-what-you-can",
cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)));
+static cl::list<std::string> ArgsAfter("extra-arg",
+ cl::desc("Additional argument to append to the compiler command line"));
+static cl::list<std::string> ArgsBefore("extra-arg-before",
+ cl::desc("Additional argument to prepend to the compiler command line"));
+
namespace {
// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
@@ -123,6 +133,39 @@ public:
}
};
+class InsertAdjuster: public clang::tooling::ArgumentsAdjuster {
+public:
+ enum Position { BEGIN, END };
+
+ InsertAdjuster(const CommandLineArguments &Extra, Position Pos)
+ : Extra(Extra), Pos(Pos) {
+ }
+
+ InsertAdjuster(const char *Extra, Position Pos)
+ : Extra(1, std::string(Extra)), Pos(Pos) {
+ }
+
+ virtual CommandLineArguments
+ Adjust(const CommandLineArguments &Args) LLVM_OVERRIDE {
+ CommandLineArguments Return(Args);
+
+ CommandLineArguments::iterator I;
+ if (Pos == END) {
+ I = Return.end();
+ } else {
+ I = Return.begin();
+ ++I; // To leave the program name in place
+ }
+
+ Return.insert(I, Extra.begin(), Extra.end());
+ return Return;
+ }
+
+private:
+ const CommandLineArguments Extra;
+ const Position Pos;
+};
+
} // namespace
// Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6.
@@ -147,8 +190,34 @@ int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
- if (Fixit)
- return Tool.run(newFrontendActionFactory<FixItAction>());
- clang_check::ClangCheckActionFactory Factory;
- return Tool.run(newFrontendActionFactory(&Factory));
+
+ // Clear adjusters because -fsyntax-only is inserted by the default chain.
+ Tool.clearArgumentsAdjusters();
+ Tool.appendArgumentsAdjuster(new ClangStripOutputAdjuster());
+ if (ArgsAfter.size() > 0) {
+ Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsAfter,
+ InsertAdjuster::END));
+ }
+ if (ArgsBefore.size() > 0) {
+ Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsBefore,
+ InsertAdjuster::BEGIN));
+ }
+
+ // Running the analyzer requires --analyze. Other modes can work with the
+ // -fsyntax-only option.
+ Tool.appendArgumentsAdjuster(new InsertAdjuster(
+ Analyze ? "--analyze" : "-fsyntax-only", InsertAdjuster::BEGIN));
+
+ clang_check::ClangCheckActionFactory CheckFactory;
+ FrontendActionFactory *FrontendFactory;
+
+ // Choose the correct factory based on the selected mode.
+ if (Analyze)
+ FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
+ else if (Fixit)
+ FrontendFactory = newFrontendActionFactory<FixItAction>();
+ else
+ FrontendFactory = newFrontendActionFactory(&CheckFactory);
+
+ return Tool.run(FrontendFactory);
}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
index 7d6505edc114..cf088d268930 100644
--- a/tools/clang-check/Makefile
+++ b/tools/clang-check/Makefile
@@ -15,10 +15,11 @@ TOOLNAME = clang-check
TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
- clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
- clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
- clangLex.a clangBasic.a
+ clangTooling.a clangParse.a clangSema.a \
+ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
+ clangStaticAnalyzerCore.a clangAnalysis.a clangRewriteFrontend.a \
+ clangRewriteCore.a clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/clang-format-vs/ClangFormat.sln b/tools/clang-format-vs/ClangFormat.sln
new file mode 100644
index 000000000000..d6b211fe506f
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangFormat", "ClangFormat\ClangFormat.csproj", "{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
new file mode 100644
index 000000000000..65ccaba0f181
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}</ProjectGuid>
+ <ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>LLVM.ClangFormat</RootNamespace>
+ <AssemblyName>ClangFormat</AssemblyName>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>4.0</OldToolsVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="Microsoft.VisualStudio.CoreUtility, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Editor, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.OLE.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop.10.0" />
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Shell.10.0">
+ <Private>false</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Text.Data, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Text.Logic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Text.UI, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Text.UI.Wpf, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Design" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq" />
+ </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>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="stdole">
+ <Guid>{00020430-0000-0000-C000-000000000046}</Guid>
+ <VersionMajor>2</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Guids.cs" />
+ <Compile Include="Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="GlobalSuppressions.cs" />
+ <Compile Include="ClangFormatPackage.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="PkgCmdID.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <EmbeddedResource Include="VSPackage.resx">
+ <MergeWithCTO>true</MergeWithCTO>
+ <ManifestResourceName>VSPackage</ManifestResourceName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Key.snk" />
+ <None Include="source.extension.vsixmanifest">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <VSCTCompile Include="ClangFormat.vsct">
+ <ResourceName>Menus.ctmenu</ResourceName>
+ </VSCTCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Resources\Images_32bit.bmp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="Resources\Package.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include=".NETFramework,Version=v4.0">
+ <Visible>False</Visible>
+ <ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 4.5</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <PropertyGroup>
+ <UseCodebase>true</UseCodebase>
+ </PropertyGroup>
+ <PropertyGroup>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets" Condition="false" />
+ <PropertyGroup>
+ <PreBuildEvent>if not exist $(ProjectDir)Key.snk (
+ "$(FrameworkSDKDir)Bin\NETFX 4.0 Tools\sn.exe" -k $(ProjectDir)Key.snk
+)</PreBuildEvent>
+ </PropertyGroup>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.vsct b/tools/clang-format-vs/ClangFormat/ClangFormat.vsct
new file mode 100644
index 000000000000..3e3e22e67d42
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.vsct
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ <!-- This is the file that defines the actual layout and type of the commands.
+ It is divided in different sections (e.g. command definition, command
+ placement, ...), with each defining a specific set of properties.
+ See the comment before each section for more details about how to
+ use it. -->
+
+ <!-- The VSCT compiler (the tool that translates this file into the binary
+ format that VisualStudio will consume) has the ability to run a preprocessor
+ on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
+ it is possible to define includes and macros with the same syntax used
+ in C++ files. Using this ability of the compiler here, we include some files
+ defining some of the constants that we will use inside the file. -->
+
+ <!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
+ <Extern href="stdidcmd.h"/>
+
+ <!--This header contains the command ids for the menus provided by the shell. -->
+ <Extern href="vsshlids.h"/>
+
+
+
+
+ <!--The Commands section is where we the commands, menus and menu groups are defined.
+ This section uses a Guid to identify the package that provides the command defined inside it. -->
+ <Commands package="guidClangFormatPkg">
+ <!-- Inside this section we have different sub-sections: one for the menus, another
+ for the menu groups, one for the buttons (the actual commands), one for the combos
+ and the last one for the bitmaps used. Each element is identified by a command id that
+ is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
+ called "command set" and is used to group different command inside a logically related
+ group; your package should define its own command set in order to avoid collisions
+ with command ids defined by other packages. -->
+
+
+ <!-- In this section you can define new menu groups. A menu group is a container for
+ other menus or buttons (commands); from a visual point of view you can see the
+ group as the part of a menu contained between two lines. The parent of a group
+ must be a menu. -->
+ <Groups>
+
+ <Group guid="guidClangFormatCmdSet" id="MyMenuGroup" priority="0x0600">
+ <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
+ </Group>
+
+
+
+ </Groups>
+
+ <!--Buttons section. -->
+ <!--This section defines the elements the user can interact with, like a menu command or a button
+ or combo box in a toolbar. -->
+ <Buttons>
+ <!--To define a menu group you have to specify its ID, the parent menu and its display priority.
+ The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
+ the CommandFlag node.
+ You can add more than one CommandFlag node e.g.:
+ <CommandFlag>DefaultInvisible</CommandFlag>
+ <CommandFlag>DynamicVisibility</CommandFlag>
+ If you do not want an image next to your command, remove the Icon node /> -->
+
+ <Button guid="guidClangFormatCmdSet" id="cmdidClangFormat" priority="0x0100" type="Button">
+ <Parent guid="guidClangFormatCmdSet" id="MyMenuGroup" />
+ <Icon guid="guidImages" id="bmpPic1" />
+ <Strings>
+ <ButtonText>ClangFormat</ButtonText>
+ </Strings>
+ </Button>
+
+
+
+ </Buttons>
+
+ <!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
+ <Bitmaps>
+ <!-- The bitmap id is defined in a way that is a little bit different from the others:
+ the declaration starts with a guid for the bitmap strip, then there is the resource id of the
+ bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
+ inside a button definition. An important aspect of this declaration is that the element id
+ must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
+ <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
+
+ </Bitmaps>
+
+ </Commands>
+
+
+ <KeyBindings>
+ <KeyBinding guid="guidClangFormatCmdSet" id="cmdidClangFormat" editor="guidTextEditor" key1="R" mod1="Control" key2="F" mod2="Control"/>
+ </KeyBindings>
+
+
+
+ <Symbols>
+ <!-- This is the package guid. -->
+ <GuidSymbol name="guidClangFormatPkg" value="{c5286038-25d3-4f65-83a8-51fa2df4a146}" />
+
+ <!-- This is the guid used to group the menu commands together -->
+ <GuidSymbol name="guidClangFormatCmdSet" value="{e39cbab1-0f96-4022-a2bc-da5a9db7eb78}">
+
+ <IDSymbol name="MyMenuGroup" value="0x1020" />
+ <IDSymbol name="cmdidClangFormat" value="0x0100" />
+ </GuidSymbol>
+
+ <GuidSymbol name="guidTextEditor" value="{8B382828-6202-11d1-8870-0000F87579D2}" />
+
+
+ <GuidSymbol name="guidImages" value="{6d53937b-9ae1-42e1-8849-d876dcdbad7b}" >
+ <IDSymbol name="bmpPic1" value="1" />
+ <IDSymbol name="bmpPic2" value="2" />
+ <IDSymbol name="bmpPicSearch" value="3" />
+ <IDSymbol name="bmpPicX" value="4" />
+ <IDSymbol name="bmpPicArrows" value="5" />
+ </GuidSymbol>
+ </Symbols>
+
+</CommandTable>
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
new file mode 100644
index 000000000000..797d46788578
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
@@ -0,0 +1,220 @@
+//===-- ClangFormatPackages.cs - VSPackage for clang-format ------*- C# -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class contains a VS extension package that runs clang-format over a
+// selection in a VS text editor.
+//
+//===----------------------------------------------------------------------===//
+
+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.ComponentModel;
+using System.ComponentModel.Design;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Xml.Linq;
+
+namespace LLVM.ClangFormat
+{
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [CLSCompliant(false), ComVisible(true)]
+ public class OptionPageGrid : DialogPage
+ {
+ private string style = "File";
+
+ [Category("LLVM/Clang")]
+ [DisplayName("Style")]
+ [Description("Coding style, currently supports:\n" +
+ " - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla').\n" +
+ " - 'File' to search for a YAML .clang-format or _clang-format\n" +
+ " configuration file.\n" +
+ " - A YAML configuration snippet.\n\n" +
+ "'File':\n" +
+ " Searches for a .clang-format or _clang-format configuration file\n" +
+ " in the source file's directory and its parents.\n\n" +
+ "YAML configuration snippet:\n" +
+ " The content of a .clang-format configuration file, as string.\n" +
+ " Example: '{BasedOnStyle: \"LLVM\", IndentWidth: 8}'\n\n" +
+ "See also: http://clang.llvm.org/docs/ClangFormatStyleOptions.html.")]
+ public string Style
+ {
+ get { return style; }
+ set { style = value; }
+ }
+ }
+
+ [PackageRegistration(UseManagedResourcesOnly = true)]
+ [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+ [ProvideMenuResource("Menus.ctmenu", 1)]
+ [Guid(GuidList.guidClangFormatPkgString)]
+ [ProvideOptionPage(typeof(OptionPageGrid), "LLVM/Clang", "ClangFormat", 0, 0, true)]
+ public sealed class ClangFormatPackage : Package
+ {
+ #region Package Members
+ protected override void Initialize()
+ {
+ base.Initialize();
+
+ var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
+ if (commandService != null)
+ {
+ var menuCommandID = new CommandID(GuidList.guidClangFormatCmdSet, (int)PkgCmdIDList.cmdidClangFormat);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
+ }
+ #endregion
+
+ private void MenuItemCallback(object sender, EventArgs args)
+ {
+ IWpfTextView view = GetCurrentView();
+ if (view == null)
+ // We're not in a text view.
+ return;
+ string text = view.TextBuffer.CurrentSnapshot.GetText();
+ int start = view.Selection.Start.Position.GetContainingLine().Start.Position;
+ int end = view.Selection.End.Position.GetContainingLine().End.Position;
+ int length = end - start;
+ // clang-format doesn't support formatting a range that starts at the end
+ // of the file.
+ if (start >= text.Length && text.Length > 0)
+ start = text.Length - 1;
+ string path = GetDocumentParent(view);
+ try
+ {
+ var root = XElement.Parse(RunClangFormat(text, start, length, path));
+ var edit = view.TextBuffer.CreateEdit();
+ foreach (XElement replacement in root.Descendants("replacement"))
+ {
+ var span = new Span(
+ int.Parse(replacement.Attribute("offset").Value),
+ int.Parse(replacement.Attribute("length").Value));
+ edit.Replace(span, replacement.Value);
+ }
+ edit.Apply();
+ }
+ catch (Exception e)
+ {
+ var uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
+ var id = Guid.Empty;
+ int result;
+ uiShell.ShowMessageBox(
+ 0, ref id,
+ "Error while running clang-format:",
+ e.Message,
+ string.Empty, 0,
+ OLEMSGBUTTON.OLEMSGBUTTON_OK,
+ OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
+ OLEMSGICON.OLEMSGICON_INFO,
+ 0, out result);
+ }
+ }
+
+ /// <summary>
+ /// Runs the given text through clang-format and returns the replacements as XML.
+ ///
+ /// Formats the text range starting at offset of the given length.
+ /// </summary>
+ private string RunClangFormat(string text, int offset, int length, string path)
+ {
+ System.Diagnostics.Process process = new System.Diagnostics.Process();
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.FileName = "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("\"", "\\\"");
+ process.StartInfo.Arguments = " -offset " + offset +
+ " -length " + length +
+ " -output-replacements-xml " +
+ " -style \"" + style + "\"";
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.RedirectStandardInput = true;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = true;
+ if (path != null)
+ process.StartInfo.WorkingDirectory = path;
+ // We have to be careful when communicating via standard input / output,
+ // as writes to the buffers will block until they are read from the other side.
+ // Thus, we:
+ // 1. Start the process - clang-format.exe will start to read the input from the
+ // standard input.
+ try
+ {
+ process.Start();
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Cannot execute " + process.StartInfo.FileName + ".\n\"" +
+ e.Message + "\".\nPlease make sure it is on the PATH.");
+ }
+ // 2. We write everything to the standard output - this cannot block, as clang-format
+ // reads the full standard input before analyzing it without writing anything to the
+ // standard output.
+ process.StandardInput.Write(text);
+ // 3. We notify clang-format that the input is done - after this point clang-format
+ // will start analyzing the input and eventually write the output.
+ process.StandardInput.Close();
+ // 4. We must read clang-format's output before waiting for it to exit; clang-format
+ // will close the channel by exiting.
+ string output = process.StandardOutput.ReadToEnd();
+ // 5. clang-format is done, wait until it is fully shut down.
+ process.WaitForExit();
+ if (process.ExitCode != 0)
+ {
+ // FIXME: If clang-format writes enough to the standard error stream to block,
+ // we will never reach this point; instead, read the standard error asynchronously.
+ throw new Exception(process.StandardError.ReadToEnd());
+ }
+ return output;
+ }
+
+ /// <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 GetDocumentParent(IWpfTextView view)
+ {
+ ITextDocument document;
+ if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
+ {
+ return Directory.GetParent(document.FilePath).ToString();
+ }
+ return null;
+ }
+ }
+}
diff --git a/tools/clang-format-vs/ClangFormat/GlobalSuppressions.cs b/tools/clang-format-vs/ClangFormat/GlobalSuppressions.cs
new file mode 100644
index 000000000000..175a74e291df
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/GlobalSuppressions.cs
@@ -0,0 +1,11 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project. Project-level
+// suppressions either have no target or are given a specific target
+// and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Error List, point to "Suppress Message(s)", and click "In Project
+// Suppression File". You do not need to add suppressions to this
+// file manually.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
diff --git a/tools/clang-format-vs/ClangFormat/Guids.cs b/tools/clang-format-vs/ClangFormat/Guids.cs
new file mode 100644
index 000000000000..c045224cd06b
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Guids.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace LLVM.ClangFormat
+{
+ static class GuidList
+ {
+ public const string guidClangFormatPkgString = "c5286038-25d3-4f65-83a8-51fa2df4a146";
+ public const string guidClangFormatCmdSetString = "e39cbab1-0f96-4022-a2bc-da5a9db7eb78";
+
+ public static readonly Guid guidClangFormatCmdSet = new Guid(guidClangFormatCmdSetString);
+ };
+} \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/PkgCmdID.cs b/tools/clang-format-vs/ClangFormat/PkgCmdID.cs
new file mode 100644
index 000000000000..bb6b4559a98d
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/PkgCmdID.cs
@@ -0,0 +1,7 @@
+namespace LLVM.ClangFormat
+{
+ static class PkgCmdIDList
+ {
+ public const uint cmdidClangFormat = 0x100;
+ };
+} \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs b/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000000..e6e4de488012
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ClangFormat")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("LLVM")]
+[assembly: AssemblyProduct("ClangFormat")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: CLSCompliant(false)]
+[assembly: NeutralResourcesLanguage("en-US")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/tools/clang-format-vs/ClangFormat/Resources.Designer.cs b/tools/clang-format-vs/ClangFormat/Resources.Designer.cs
new file mode 100644
index 000000000000..efec031e16e4
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Resources.Designer.cs
@@ -0,0 +1,64 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18408
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace LLVM.ClangFormat {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LLVM.ClangFormat.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ }
+}
diff --git a/tools/clang-format-vs/ClangFormat/Resources.resx b/tools/clang-format-vs/ClangFormat/Resources.resx
new file mode 100644
index 000000000000..352987aa07bc
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Resources.resx
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ VS SDK Notes: This resx file contains the resources that will be consumed directly by your package.
+ For example, if you chose to create a tool window, there is a resource with ID 'CanNotCreateWindow'. This
+ is used in VsPkg.cs to determine the string to show the user if there is an error when attempting to create
+ the tool window.
+
+ Resources that are accessed directly from your package *by Visual Studio* are stored in the VSPackage.resx
+ file.
+-->
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/Resources/Images_32bit.bmp b/tools/clang-format-vs/ClangFormat/Resources/Images_32bit.bmp
new file mode 100644
index 000000000000..2fa7ab009985
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Resources/Images_32bit.bmp
Binary files differ
diff --git a/tools/clang-format-vs/ClangFormat/Resources/Package.ico b/tools/clang-format-vs/ClangFormat/Resources/Package.ico
new file mode 100644
index 000000000000..ea3b23fe8d4b
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Resources/Package.ico
Binary files differ
diff --git a/tools/clang-format-vs/ClangFormat/VSPackage.resx b/tools/clang-format-vs/ClangFormat/VSPackage.resx
new file mode 100644
index 000000000000..81102d38a07a
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/VSPackage.resx
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ VS SDK Notes: This resx file contains the resources that will be consumed from your package by Visual Studio.
+ For example, Visual Studio will attempt to load resource '400' from this resource stream when it needs to
+ load your package's icon. Because Visual Studio will always look in the VSPackage.resources stream first for
+ resources it needs, you should put additional resources that Visual Studio will load directly into this resx
+ file.
+
+ Resources that you would like to access directly from your package in a strong-typed fashion should be stored
+ in Resources.resx or another resx file.
+-->
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="110" xml:space="preserve">
+ <value>ClangFormat</value>
+ </data>
+ <data name="112" xml:space="preserve">
+ <value>Formats code by calling the clang-format executable.</value>
+ </data>
+ <data name="400" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/source.extension.vsixmanifest b/tools/clang-format-vs/ClangFormat/source.extension.vsixmanifest
new file mode 100644
index 000000000000..39d30f0f15e9
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/source.extension.vsixmanifest
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+ <Identifier Id="20dbc914-1c7a-4992-b236-ef58b37850eb">
+ <Name>ClangFormat</Name>
+ <Author>LLVM</Author>
+ <Version>1.0</Version>
+ <Description xml:space="preserve">Information about my package</Description>
+ <Locale>1033</Locale>
+ <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>
+ </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>
diff --git a/tools/clang-format-vs/README.txt b/tools/clang-format-vs/README.txt
new file mode 100644
index 000000000000..6d4ebb39ead7
--- /dev/null
+++ b/tools/clang-format-vs/README.txt
@@ -0,0 +1,6 @@
+This directory contains a VSPackage project to generate a Visual Studio extension
+for clang-format.
+
+Build prerequisites are:
+- Visual Studio 2012 Professional
+- Visual Studio SDK (http://www.microsoft.com/en-us/download/details.aspx?id=30668)
diff --git a/tools/clang-format/CMakeLists.txt b/tools/clang-format/CMakeLists.txt
index c86a920841c6..7bb3fbf990b5 100644
--- a/tools/clang-format/CMakeLists.txt
+++ b/tools/clang-format/CMakeLists.txt
@@ -12,6 +12,10 @@ target_link_libraries(clang-format
clangRewriteFrontend
)
-install(TARGETS clang-format
- RUNTIME DESTINATION bin)
-
+install(TARGETS clang-format RUNTIME DESTINATION bin)
+install(PROGRAMS clang-format-bbedit.applescript DESTINATION share/clang)
+install(PROGRAMS clang-format-diff.py DESTINATION share/clang)
+install(PROGRAMS clang-format-sublime.py DESTINATION share/clang)
+install(PROGRAMS clang-format.el DESTINATION share/clang)
+install(PROGRAMS clang-format.py DESTINATION share/clang)
+install(PROGRAMS git-clang-format DESTINATION bin)
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index 57833edf0f31..768165b92e9d 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -20,32 +20,76 @@
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
+#include "llvm/ADT/StringMap.h"
using namespace llvm;
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+// Mark all our options with this category, everything else (except for -version
+// and -help) will be hidden.
+cl::OptionCategory ClangFormatCategory("Clang-format options");
+
static cl::list<unsigned>
-Offsets("offset", cl::desc("Format a range starting at this file offset. Can "
- "only be used with one input file."));
+ Offsets("offset",
+ cl::desc("Format a range starting at this byte offset.\n"
+ "Multiple ranges can be formatted by specifying\n"
+ "several -offset and -length pairs.\n"
+ "Can only be used with one input file."),
+ cl::cat(ClangFormatCategory));
static cl::list<unsigned>
-Lengths("length", cl::desc("Format a range of this length. "
- "When it's not specified, end of file is used. "
- "Can only be used with one input file."));
-static cl::opt<std::string> Style(
- "style",
- cl::desc("Coding style, currently supports: LLVM, Google, Chromium, Mozilla."),
- cl::init("LLVM"));
+ Lengths("length",
+ cl::desc("Format a range of this length (in bytes).\n"
+ "Multiple ranges can be formatted by specifying\n"
+ "several -offset and -length pairs.\n"
+ "When only a single -offset is specified without\n"
+ "-length, clang-format will format up to the end\n"
+ "of the file.\n"
+ "Can only be used with one input file."),
+ cl::cat(ClangFormatCategory));
+static cl::list<std::string>
+LineRanges("lines", cl::desc("<start line>:<end line> - format a range of\n"
+ "lines (both 1-based).\n"
+ "Multiple ranges can be formatted by specifying\n"
+ "several -lines arguments.\n"
+ "Can't be used with -offset and -length.\n"
+ "Can only be used with one input file."),
+ cl::cat(ClangFormatCategory));
+static cl::opt<std::string>
+ Style("style",
+ cl::desc(clang::format::StyleOptionHelpDescription),
+ cl::init("file"), cl::cat(ClangFormatCategory));
+
+static cl::opt<std::string>
+AssumeFilename("assume-filename",
+ cl::desc("When reading from stdin, clang-format assumes this\n"
+ "filename to look for a style config file (with\n"
+ "-style=file)."),
+ cl::cat(ClangFormatCategory));
+
static cl::opt<bool> Inplace("i",
- cl::desc("Inplace edit <file>s, if specified."));
+ cl::desc("Inplace edit <file>s, if specified."),
+ cl::cat(ClangFormatCategory));
-static cl::opt<bool> OutputXML(
- "output-replacements-xml", cl::desc("Output replacements as XML."));
+static cl::opt<bool> OutputXML("output-replacements-xml",
+ cl::desc("Output replacements as XML."),
+ cl::cat(ClangFormatCategory));
+static cl::opt<bool>
+ DumpConfig("dump-config",
+ cl::desc("Dump configuration options to stdout and exit.\n"
+ "Can be used with -style option."),
+ cl::cat(ClangFormatCategory));
+static cl::opt<unsigned>
+ Cursor("cursor",
+ cl::desc("The position of the cursor when invoking\n"
+ "clang-format from an editor integration"),
+ cl::init(0), cl::cat(ClangFormatCategory));
-static cl::list<std::string> FileNames(cl::Positional,
- cl::desc("[<file> ...]"));
+static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"),
+ cl::cat(ClangFormatCategory));
namespace clang {
namespace format {
@@ -59,34 +103,43 @@ static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
-static FormatStyle getStyle() {
- FormatStyle TheStyle = getGoogleStyle();
- if (Style == "LLVM")
- TheStyle = getLLVMStyle();
- else if (Style == "Chromium")
- TheStyle = getChromiumStyle();
- else if (Style == "Mozilla")
- TheStyle = getMozillaStyle();
- else if (Style != "Google")
- llvm::errs() << "Unknown style " << Style << ", using Google style.\n";
-
- return TheStyle;
+// Parses <start line>:<end line> input to a pair of line numbers.
+// Returns true on error.
+static bool parseLineRange(StringRef Input, unsigned &FromLine,
+ unsigned &ToLine) {
+ std::pair<StringRef, StringRef> LineRange = Input.split(':');
+ return LineRange.first.getAsInteger(0, FromLine) ||
+ LineRange.second.getAsInteger(0, ToLine);
}
-// Returns true on error.
-static bool format(std::string FileName) {
- FileManager Files((FileSystemOptions()));
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
- new DiagnosticOptions);
- SourceManager Sources(Diagnostics, Files);
- OwningPtr<MemoryBuffer> Code;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) {
- llvm::errs() << ec.message() << "\n";
- return true;
+static bool fillRanges(SourceManager &Sources, FileID ID,
+ const MemoryBuffer *Code,
+ std::vector<CharSourceRange> &Ranges) {
+ if (!LineRanges.empty()) {
+ if (!Offsets.empty() || !Lengths.empty()) {
+ llvm::errs() << "error: cannot use -lines with -offset/-length\n";
+ return true;
+ }
+
+ for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) {
+ unsigned FromLine, ToLine;
+ if (parseLineRange(LineRanges[i], FromLine, ToLine)) {
+ llvm::errs() << "error: invalid <start line>:<end line> pair\n";
+ return true;
+ }
+ if (FromLine > ToLine) {
+ llvm::errs() << "error: start line should be less than end line\n";
+ return true;
+ }
+ SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
+ SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
+ if (Start.isInvalid() || End.isInvalid())
+ return true;
+ Ranges.push_back(CharSourceRange::getCharRange(Start, End));
+ }
+ return false;
}
- FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
- Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts());
+
if (Offsets.empty())
Offsets.push_back(0);
if (Offsets.size() != Lengths.size() &&
@@ -95,7 +148,6 @@ static bool format(std::string FileName) {
<< "error: number of -offset and -length arguments must match.\n";
return true;
}
- std::vector<CharSourceRange> Ranges;
for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
if (Offsets[i] >= Code->getBufferSize()) {
llvm::errs() << "error: offset " << Offsets[i]
@@ -118,7 +170,33 @@ static bool format(std::string FileName) {
}
Ranges.push_back(CharSourceRange::getCharRange(Start, End));
}
- tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges);
+ return false;
+}
+
+// Returns true on error.
+static bool format(StringRef FileName) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager Sources(Diagnostics, Files);
+ OwningPtr<MemoryBuffer> Code;
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) {
+ llvm::errs() << ec.message() << "\n";
+ return true;
+ }
+ if (Code->getBufferSize() == 0)
+ return false; // Empty files are formatted correctly.
+ FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
+ std::vector<CharSourceRange> Ranges;
+ if (fillRanges(Sources, ID, Code.get(), Ranges))
+ return true;
+
+ FormatStyle FormatStyle =
+ getStyle(Style, (FileName == "-") ? AssumeFilename : FileName);
+ Lexer Lex(ID, Sources.getBuffer(ID), Sources,
+ getFormattingLangOpts(FormatStyle.Standard));
+ tooling::Replacements Replaces = reformat(FormatStyle, Lex, Sources, Ranges);
if (OutputXML) {
llvm::outs()
<< "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
@@ -135,19 +213,12 @@ static bool format(std::string FileName) {
Rewriter Rewrite(Sources, LangOptions());
tooling::applyAllReplacements(Replaces, Rewrite);
if (Inplace) {
- if (Replaces.size() == 0)
- return false; // Nothing changed, don't touch the file.
-
- std::string ErrorInfo;
- llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary);
- if (!ErrorInfo.empty()) {
- llvm::errs() << "Error while writing file: " << ErrorInfo << "\n";
+ if (Rewrite.overwriteChangedFiles())
return true;
- }
- Rewrite.getEditBuffer(ID).write(FileStream);
- FileStream.flush();
} else {
+ if (Cursor.getNumOccurrences() != 0)
+ outs() << "{ \"Cursor\": " << tooling::shiftedCodePosition(
+ Replaces, Cursor) << " }\n";
Rewrite.getEditBuffer(ID).write(outs());
}
}
@@ -159,18 +230,37 @@ static bool format(std::string FileName) {
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
+
+ // Hide unrelated options.
+ StringMap<cl::Option*> Options;
+ cl::getRegisteredOptions(Options);
+ for (StringMap<cl::Option *>::iterator I = Options.begin(), E = Options.end();
+ I != E; ++I) {
+ if (I->second->Category != &ClangFormatCategory && I->first() != "help" &&
+ I->first() != "version")
+ I->second->setHiddenFlag(cl::ReallyHidden);
+ }
+
cl::ParseCommandLineOptions(
argc, argv,
"A tool to format C/C++/Obj-C code.\n\n"
"If no arguments are specified, it formats the code from standard input\n"
"and writes the result to the standard output.\n"
- "If <file>s are given, it reformats the files. If -i is specified \n"
- "together with <file>s, the files are edited in-place. Otherwise, the \n"
+ "If <file>s are given, it reformats the files. If -i is specified\n"
+ "together with <file>s, the files are edited in-place. Otherwise, the\n"
"result is written to the standard output.\n");
if (Help)
cl::PrintHelpMessage();
+ if (DumpConfig) {
+ std::string Config =
+ clang::format::configurationAsText(clang::format::getStyle(
+ Style, FileNames.empty() ? AssumeFilename : FileNames[0]));
+ llvm::outs() << Config << "\n";
+ return 0;
+ }
+
bool Error = false;
switch (FileNames.size()) {
case 0:
@@ -180,8 +270,8 @@ int main(int argc, const char **argv) {
Error = clang::format::format(FileNames[0]);
break;
default:
- if (!Offsets.empty() || !Lengths.empty()) {
- llvm::errs() << "error: \"-offset\" and \"-length\" can only be used for "
+ if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) {
+ llvm::errs() << "error: -offset, -length and -lines can only be used for "
"single file.\n";
return 1;
}
diff --git a/tools/clang-format/Makefile b/tools/clang-format/Makefile
index d869267a76f6..4902244f8657 100644
--- a/tools/clang-format/Makefile
+++ b/tools/clang-format/Makefile
@@ -15,7 +15,7 @@ TOOLNAME = clang-format
TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
clangDriver.a clangParse.a clangSema.a clangAnalysis.a \
clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py
index 68b5113d92f6..60b8fb730dcb 100755
--- a/tools/clang-format/clang-format-diff.py
+++ b/tools/clang-format/clang-format-diff.py
@@ -17,13 +17,16 @@ This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git users:
- git diff -U0 HEAD^ | clang-format-diff.py -p1
+ git diff -U0 HEAD^ | clang-format-diff.py -p1 -i
"""
import argparse
+import difflib
import re
+import string
import subprocess
+import StringIO
import sys
@@ -31,67 +34,24 @@ import sys
binary = 'clang-format'
-def getOffsetLength(filename, line_number, line_count):
- """
- Calculates the field offset and length based on line number and count.
- """
- offset = 0
- length = 0
- with open(filename, 'r') as f:
- for line in f:
- if line_number > 1:
- offset += len(line)
- line_number -= 1
- elif line_count > 0:
- length += len(line)
- line_count -= 1
- else:
- break
- return offset, length
-
-
-def formatRange(r, style):
- """
- Formats range 'r' according to style 'style'.
- """
- filename, line_number, line_count = r
- # FIXME: Add other types containing C++/ObjC code.
- if not (filename.endswith(".cpp") or filename.endswith(".cc") or
- filename.endswith(".h")):
- return
-
- offset, length = getOffsetLength(filename, line_number, line_count)
- with open(filename, 'r') as f:
- text = f.read()
- command = [binary, '-offset', str(offset), '-length', str(length)]
- if style:
- command.extend(['-style', style])
- p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- stdin=subprocess.PIPE)
- stdout, stderr = p.communicate(input=text)
- if stderr:
- print stderr
- return
- if not stdout:
- print 'Segfault occurred while formatting', filename
- print 'Please report a bug on llvm.org/bugs.'
- return
- with open(filename, 'w') as f:
- f.write(stdout)
-
-
def main():
parser = argparse.ArgumentParser(description=
- 'Reformat changed lines in diff')
- parser.add_argument('-p', default=1,
+ 'Reformat changed lines in diff. Without -i '
+ 'option just output the diff that would be'
+ 'introduced.')
+ parser.add_argument('-i', action='store_true', default=False,
+ help='apply edits to files instead of displaying a diff')
+ parser.add_argument('-p', default=0,
help='strip the smallest prefix containing P slashes')
- parser.add_argument('-style',
- help='formatting style to apply (LLVM, Google, Chromium)')
+ parser.add_argument(
+ '-style',
+ help=
+ 'formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)')
args = parser.parse_args()
+ # Extract changed lines for each file.
filename = None
- ranges = []
-
+ lines_by_file = {}
for line in sys.stdin:
match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
if match:
@@ -99,18 +59,50 @@ def main():
if filename == None:
continue
+ # FIXME: Add other types containing C++/ObjC code.
+ if not (filename.endswith(".cpp") or filename.endswith(".cc") or
+ filename.endswith(".h")):
+ continue
+
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
if match:
+ start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
- ranges.append((filename, int(match.group(1)), line_count))
-
- # Reverse the ranges so that the reformatting does not influence file offsets.
- for r in reversed(ranges):
- # Do the actual formatting.
- formatRange(r, args.style)
-
+ if line_count == 0:
+ continue
+ end_line = start_line + line_count - 1;
+ lines_by_file.setdefault(filename, []).extend(
+ ['-lines', str(start_line) + ':' + str(end_line)])
+
+ # Reformat files containing changes in place.
+ for filename, lines in lines_by_file.iteritems():
+ command = [binary, filename]
+ if args.i:
+ command.append('-i')
+ command.extend(lines)
+ if args.style:
+ command.extend(['-style', args.style])
+ p = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if stderr:
+ print stderr
+ if p.returncode != 0:
+ sys.exit(p.returncode);
+
+ if not args.i:
+ with open(filename) as f:
+ code = f.readlines()
+ formatted_code = StringIO.StringIO(stdout).readlines()
+ diff = difflib.unified_diff(code, formatted_code,
+ filename, filename,
+ '(before formatting)', '(after formatting)')
+ diff_string = string.join(diff, '')
+ if len(diff_string) > 0:
+ print diff_string
if __name__ == '__main__':
main()
diff --git a/tools/clang-format/clang-format-sublime.py b/tools/clang-format/clang-format-sublime.py
new file mode 100644
index 000000000000..16ff56e502c6
--- /dev/null
+++ b/tools/clang-format/clang-format-sublime.py
@@ -0,0 +1,58 @@
+# This file is a minimal clang-format sublime-integration. To install:
+# - Change 'binary' if clang-format is not on the path (see below).
+# - Put this file into your sublime Packages directory, e.g. on Linux:
+# ~/.config/sublime-text-2/Packages/User/clang-format-sublime.py
+# - Add a key binding:
+# { "keys": ["ctrl+shift+c"], "command": "clang_format" },
+#
+# With this integration you can press the bound key and clang-format will
+# format the current lines and selections for all cursor positions. The lines
+# or regions are extended to the next bigger syntactic entities.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a formatting, just undo.
+
+from __future__ import print_function
+import sublime
+import sublime_plugin
+import subprocess
+
+# Change this to the full path if clang-format is not on the path.
+binary = 'clang-format'
+
+# Change this to format according to other formatting styles. See the output of
+# 'clang-format --help' for a list of supported styles. The default looks for
+# a '.clang-format' or '_clang-format' file to indicate the style that should be
+# used.
+style = 'file'
+
+class ClangFormatCommand(sublime_plugin.TextCommand):
+ def run(self, edit):
+ encoding = self.view.encoding()
+ if encoding == 'Undefined':
+ encoding = 'utf-8'
+ regions = []
+ command = [binary, '-style', style]
+ for region in self.view.sel():
+ regions.append(region)
+ region_offset = min(region.a, region.b)
+ region_length = abs(region.b - region.a)
+ command.extend(['-offset', str(region_offset),
+ '-length', str(region_length),
+ '-assume-filename', str(self.view.file_name())])
+ old_viewport_position = self.view.viewport_position()
+ buf = self.view.substr(sublime.Region(0, self.view.size()))
+ p = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ output, error = p.communicate(buf.encode(encoding))
+ if error:
+ print(error)
+ self.view.replace(
+ edit, sublime.Region(0, self.view.size()),
+ output.decode(encoding))
+ self.view.sel().clear()
+ for region in regions:
+ self.view.sel().add(region)
+ # FIXME: Without the 10ms delay, the viewport sometimes jumps.
+ sublime.set_timeout(lambda: self.view.set_viewport_position(
+ old_viewport_position, False), 10)
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index 2c5546b241cc..520a3e250cf5 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -7,25 +7,50 @@
;; (global-set-key [C-M-tab] 'clang-format-region)
;;
;; Depending on your configuration and coding style, you might need to modify
-;; 'style' and 'binary' below.
+;; 'style' in clang-format, below.
+
+(require 'json)
+
+;; *Location of the clang-format binary. If it is on your PATH, a full path name
+;; need not be specified.
+(defvar clang-format-binary "clang-format")
+
(defun clang-format-region ()
+ "Use clang-format to format the currently active region."
+ (interactive)
+ (let ((beg (if mark-active
+ (region-beginning)
+ (min (line-beginning-position) (1- (point-max)))))
+ (end (if mark-active
+ (region-end)
+ (line-end-position))))
+ (clang-format beg end)))
+
+(defun clang-format-buffer ()
+ "Use clang-format to format the current buffer."
(interactive)
+ (clang-format (point-min) (point-max)))
+(defun clang-format (begin end)
+ "Use clang-format to format the code between BEGIN and END."
(let* ((orig-windows (get-buffer-window-list (current-buffer)))
(orig-window-starts (mapcar #'window-start orig-windows))
(orig-point (point))
- (binary "clang-format")
- (style "LLVM"))
- (if mark-active
- (setq beg (region-beginning)
- end (region-end))
- (setq beg (min (line-beginning-position) (1- (point-max)))
- end (min (line-end-position) (1- (point-max)))))
- (call-process-region (point-min) (point-max) binary t t nil
- "-offset" (number-to-string (1- beg))
- "-length" (number-to-string (- end beg))
- "-style" style)
- (goto-char orig-point)
- (dotimes (index (length orig-windows))
- (set-window-start (nth index orig-windows)
- (nth index orig-window-starts)))))
+ (style "file"))
+ (unwind-protect
+ (call-process-region (point-min) (point-max) clang-format-binary
+ t (list t nil) nil
+ "-offset" (number-to-string (1- begin))
+ "-length" (number-to-string (- end begin))
+ "-cursor" (number-to-string (1- (point)))
+ "-assume-filename" (buffer-file-name)
+ "-style" style)
+ (goto-char (point-min))
+ (let ((json-output (json-read-from-string
+ (buffer-substring-no-properties
+ (point-min) (line-beginning-position 2)))))
+ (delete-region (point-min) (line-beginning-position 2))
+ (goto-char (1+ (cdr (assoc 'Cursor json-output))))
+ (dotimes (index (length orig-windows))
+ (set-window-start (nth index orig-windows)
+ (nth index orig-window-starts)))))))
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index d90c62a5bf68..f5a57569db07 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -17,31 +17,43 @@
# It operates on the current, potentially unsaved buffer and does not create
# or save any files. To revert a formatting, just undo.
-import vim
+import difflib
+import json
import subprocess
+import sys
+import vim
# Change this to the full path if clang-format is not on the path.
binary = 'clang-format'
-# Change this to format according to other formatting styles (see
-# clang-format -help)
-style = 'LLVM'
+# Change this to format according to other formatting styles. See the output of
+# 'clang-format --help' for a list of supported styles. The default looks for
+# a '.clang-format' or '_clang-format' file to indicate the style that should be
+# used.
+style = 'file'
# Get the current text.
buf = vim.current.buffer
-text = "\n".join(buf)
+text = '\n'.join(buf)
# Determine range to format.
-offset = int(vim.eval('line2byte(' +
- str(vim.current.range.start + 1) + ')')) - 1
-length = int(vim.eval('line2byte(' +
- str(vim.current.range.end + 2) + ')')) - offset - 2
+cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2
+lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1)
+
+# Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format.
+startupinfo = None
+if sys.platform.startswith('win32'):
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ startupinfo.wShowWindow = subprocess.SW_HIDE
# Call formatter.
-p = subprocess.Popen([binary, '-offset', str(offset), '-length', str(length),
- '-style', style],
+command = [binary, '-lines', lines, '-style', style, '-cursor', str(cursor)]
+if vim.current.buffer.name:
+ command.extend(['-assume-filename', vim.current.buffer.name])
+p = subprocess.Popen(command,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- stdin=subprocess.PIPE)
+ stdin=subprocess.PIPE, startupinfo=startupinfo)
stdout, stderr = p.communicate(input=text)
# If successful, replace buffer contents.
@@ -56,10 +68,12 @@ if stderr:
if not stdout:
print ('No output from clang-format (crashed?).\n' +
'Please report to bugs.llvm.org.')
-elif stdout != text:
+else:
lines = stdout.split('\n')
- for i in range(min(len(buf), len(lines))):
- buf[i] = lines[i]
- for line in lines[len(buf):]:
- buf.append(line)
- del buf[len(lines):]
+ output = json.loads(lines[0])
+ lines = lines[1:]
+ sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines)
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] is not 'equal':
+ vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
+ vim.command('goto %d' % (output['Cursor'] + 1))
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
new file mode 100755
index 000000000000..b0737ed03472
--- /dev/null
+++ b/tools/clang-format/git-clang-format
@@ -0,0 +1,481 @@
+#!/usr/bin/python
+#
+#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+clang-format git integration
+============================
+
+This file provides a clang-format integration for git. Put it somewhere in your
+path and ensure that it is executable. Then, "git clang-format" will invoke
+clang-format on the changes in current files or a specific commit.
+
+For further details, run:
+git clang-format -h
+
+Requires Python 2.7
+"""
+
+import argparse
+import collections
+import contextlib
+import errno
+import os
+import re
+import subprocess
+import sys
+
+usage = 'git clang-format [OPTIONS] [<commit>] [--] [<file>...]'
+
+desc = '''
+Run clang-format on all lines that differ between the working directory
+and <commit>, which defaults to HEAD. Changes are only applied to the working
+directory.
+
+The following git-config settings set the default of the corresponding option:
+ clangFormat.binary
+ clangFormat.commit
+ clangFormat.extension
+ clangFormat.style
+'''
+
+# Name of the temporary index file in which save the output of clang-format.
+# This file is created within the .git directory.
+temp_index_basename = 'clang-format-index'
+
+
+Range = collections.namedtuple('Range', 'start, count')
+
+
+def main():
+ config = load_git_config()
+
+ # In order to keep '--' yet allow options after positionals, we need to
+ # check for '--' ourselves. (Setting nargs='*' throws away the '--', while
+ # nargs=argparse.REMAINDER disallows options after positionals.)
+ argv = sys.argv[1:]
+ try:
+ idx = argv.index('--')
+ except ValueError:
+ dash_dash = []
+ else:
+ dash_dash = argv[idx:]
+ argv = argv[:idx]
+
+ default_extensions = ','.join([
+ # From clang/lib/Frontend/FrontendOptions.cpp, all lower case
+ 'c', 'h', # C
+ 'm', # ObjC
+ 'mm', # ObjC++
+ 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++
+ ])
+
+ p = argparse.ArgumentParser(
+ usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=desc)
+ p.add_argument('--binary',
+ default=config.get('clangformat.binary', 'clang-format'),
+ help='path to clang-format'),
+ p.add_argument('--commit',
+ default=config.get('clangformat.commit', 'HEAD'),
+ help='default commit to use if none is specified'),
+ p.add_argument('--diff', action='store_true',
+ help='print a diff instead of applying the changes')
+ p.add_argument('--extensions',
+ default=config.get('clangformat.extensions',
+ default_extensions),
+ help=('comma-separated list of file extensions to format, '
+ 'excluding the period and case-insensitive')),
+ p.add_argument('-f', '--force', action='store_true',
+ help='allow changes to unstaged files')
+ p.add_argument('-p', '--patch', action='store_true',
+ help='select hunks interactively')
+ p.add_argument('-q', '--quiet', action='count', default=0,
+ help='print less information')
+ p.add_argument('--style',
+ default=config.get('clangformat.style', None),
+ help='passed to clang-format'),
+ p.add_argument('-v', '--verbose', action='count', default=0,
+ help='print extra information')
+ # We gather all the remaining positional arguments into 'args' since we need
+ # to use some heuristics to determine whether or not <commit> was present.
+ # However, to print pretty messages, we make use of metavar and help.
+ p.add_argument('args', nargs='*', metavar='<commit>',
+ help='revision from which to compute the diff')
+ p.add_argument('ignored', nargs='*', metavar='<file>...',
+ help='if specified, only consider differences in these files')
+ opts = p.parse_args(argv)
+
+ opts.verbose -= opts.quiet
+ del opts.quiet
+
+ commit, files = interpret_args(opts.args, dash_dash, opts.commit)
+ changed_lines = compute_diff_and_extract_lines(commit, files)
+ if opts.verbose >= 1:
+ ignored_files = set(changed_lines)
+ filter_by_extension(changed_lines, opts.extensions.lower().split(','))
+ if opts.verbose >= 1:
+ ignored_files.difference_update(changed_lines)
+ if ignored_files:
+ print 'Ignoring changes in the following files (wrong extension):'
+ for filename in ignored_files:
+ print ' ', filename
+ if changed_lines:
+ print 'Running clang-format on the following files:'
+ for filename in changed_lines:
+ print ' ', filename
+ if not changed_lines:
+ print 'no modified files to format'
+ return
+ # The computed diff outputs absolute paths, so we must cd before accessing
+ # those files.
+ cd_to_toplevel()
+ old_tree = create_tree_from_workdir(changed_lines)
+ new_tree = run_clang_format_and_save_to_tree(changed_lines,
+ binary=opts.binary,
+ style=opts.style)
+ if opts.verbose >= 1:
+ print 'old tree:', old_tree
+ print 'new tree:', new_tree
+ if old_tree == new_tree:
+ if opts.verbose >= 0:
+ 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:'
+ for filename in changed_files:
+ print ' ', filename
+
+
+def load_git_config(non_string_options=None):
+ """Return the git configuration as a dictionary.
+
+ All options are assumed to be strings unless in `non_string_options`, in which
+ is a dictionary mapping option name (in lower case) to either "--bool" or
+ "--int"."""
+ if non_string_options is None:
+ non_string_options = {}
+ out = {}
+ for entry in run('git', 'config', '--list', '--null').split('\0'):
+ if entry:
+ name, value = entry.split('\n', 1)
+ if name in non_string_options:
+ value = run('git', 'config', non_string_options[name], name)
+ out[name] = value
+ return out
+
+
+def interpret_args(args, dash_dash, default_commit):
+ """Interpret `args` as "[commit] [--] [files...]" and return (commit, files).
+
+ It is assumed that "--" and everything that follows has been removed from
+ args and placed in `dash_dash`.
+
+ If "--" is present (i.e., `dash_dash` is non-empty), the argument to its
+ left (if present) is taken as commit. Otherwise, the first argument is
+ checked if it is a commit or a file. If commit is not given,
+ `default_commit` is used."""
+ if dash_dash:
+ if len(args) == 0:
+ commit = default_commit
+ elif len(args) > 1:
+ die('at most one commit allowed; %d given' % len(args))
+ else:
+ commit = args[0]
+ object_type = get_object_type(commit)
+ if object_type not in ('commit', 'tag'):
+ if object_type is None:
+ die("'%s' is not a commit" % commit)
+ else:
+ die("'%s' is a %s, but a commit was expected" % (commit, object_type))
+ files = dash_dash[1:]
+ elif args:
+ if disambiguate_revision(args[0]):
+ commit = args[0]
+ files = args[1:]
+ else:
+ commit = default_commit
+ files = args
+ else:
+ commit = default_commit
+ files = []
+ return commit, files
+
+
+def disambiguate_revision(value):
+ """Returns True if `value` is a revision, False if it is a file, or dies."""
+ # If `value` is ambiguous (neither a commit nor a file), the following
+ # command will die with an appropriate error message.
+ run('git', 'rev-parse', value, verbose=False)
+ object_type = get_object_type(value)
+ if object_type is None:
+ return False
+ if object_type in ('commit', 'tag'):
+ return True
+ die('`%s` is a %s, but a commit or filename was expected' %
+ (value, object_type))
+
+
+def get_object_type(value):
+ """Returns a string description of an object's type, or None if it is not
+ a valid git object."""
+ cmd = ['git', 'cat-file', '-t', value]
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ return None
+ return stdout.strip()
+
+
+def compute_diff_and_extract_lines(commit, files):
+ """Calls compute_diff() followed by extract_lines()."""
+ diff_process = compute_diff(commit, files)
+ changed_lines = extract_lines(diff_process.stdout)
+ diff_process.stdout.close()
+ diff_process.wait()
+ if diff_process.returncode != 0:
+ # Assume error was already printed to stderr.
+ sys.exit(2)
+ return changed_lines
+
+
+def compute_diff(commit, files):
+ """Return a subprocess object producing the diff from `commit`.
+
+ The return value's `stdin` file object will produce a patch with the
+ differences between the working directory and `commit`, filtered on `files`
+ (if non-empty). Zero context lines are used in the patch."""
+ cmd = ['git', 'diff-index', '-p', '-U0', commit, '--']
+ cmd.extend(files)
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ p.stdin.close()
+ return p
+
+
+def extract_lines(patch_file):
+ """Extract the changed lines in `patch_file`.
+
+ The return value is a dictionary mapping filename to a list of (start_line,
+ line_count) pairs.
+
+ The input must have been produced with ``-U0``, meaning unidiff format with
+ zero lines of context. The return value is a dict mapping filename to a
+ list of line `Range`s."""
+ matches = {}
+ for line in patch_file:
+ match = re.search(r'^\+\+\+\ [^/]+/(.*)', line)
+ if match:
+ filename = match.group(1).rstrip('\r\n')
+ match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line)
+ if match:
+ start_line = int(match.group(1))
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ if line_count > 0:
+ matches.setdefault(filename, []).append(Range(start_line, line_count))
+ return matches
+
+
+def filter_by_extension(dictionary, allowed_extensions):
+ """Delete every key in `dictionary` that doesn't have an allowed extension.
+
+ `allowed_extensions` must be a collection of lowercase file extensions,
+ excluding the period."""
+ allowed_extensions = frozenset(allowed_extensions)
+ for filename in dictionary.keys():
+ base_ext = filename.rsplit('.', 1)
+ if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
+ del dictionary[filename]
+
+
+def cd_to_toplevel():
+ """Change to the top level of the git repository."""
+ toplevel = run('git', 'rev-parse', '--show-toplevel')
+ os.chdir(toplevel)
+
+
+def create_tree_from_workdir(filenames):
+ """Create a new git tree with the given files from the working directory.
+
+ Returns the object ID (SHA-1) of the created tree."""
+ return create_tree(filenames, '--stdin')
+
+
+def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format',
+ style=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 index_info_generator():
+ for filename, line_ranges in changed_lines.iteritems():
+ mode = oct(os.stat(filename).st_mode)
+ blob_id = clang_format_to_blob(filename, line_ranges, binary=binary,
+ style=style)
+ yield '%s %s\t%s' % (mode, blob_id, filename)
+ return create_tree(index_info_generator(), '--index-info')
+
+
+def create_tree(input_lines, mode):
+ """Create a tree object from the given input.
+
+ If mode is '--stdin', it must be a list of filenames. If mode is
+ '--index-info' is must be a list of values suitable for "git update-index
+ --index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other mode
+ is invalid."""
+ assert mode in ('--stdin', '--index-info')
+ cmd = ['git', 'update-index', '--add', '-z', 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.close()
+ if p.wait() != 0:
+ die('`%s` failed' % ' '.join(cmd))
+ tree_id = run('git', 'write-tree')
+ return tree_id
+
+
+def clang_format_to_blob(filename, line_ranges, binary='clang-format',
+ style=None):
+ """Run clang-format on the given file and save the result to a git blob.
+
+ Returns the object ID (SHA-1) of the created blob."""
+ clang_format_cmd = [binary, filename]
+ if style:
+ clang_format_cmd.extend(['-style='+style])
+ clang_format_cmd.extend([
+ '-lines=%s:%s' % (start_line, start_line+line_count-1)
+ for start_line, line_count in line_ranges])
+ try:
+ clang_format = subprocess.Popen(clang_format_cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ die('cannot find executable "%s"' % binary)
+ else:
+ raise
+ clang_format.stdin.close()
+ hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin']
+ hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout,
+ stdout=subprocess.PIPE)
+ clang_format.stdout.close()
+ stdout = hash_object.communicate()[0]
+ if hash_object.returncode != 0:
+ die('`%s` failed' % ' '.join(hash_object_cmd))
+ if clang_format.wait() != 0:
+ die('`%s` failed' % ' '.join(clang_format_cmd))
+ return stdout.rstrip('\r\n')
+
+
+@contextlib.contextmanager
+def temporary_index_file(tree=None):
+ """Context manager for setting GIT_INDEX_FILE to a temporary file and deleting
+ the file afterward."""
+ index_path = create_temporary_index(tree)
+ old_index_path = os.environ.get('GIT_INDEX_FILE')
+ os.environ['GIT_INDEX_FILE'] = index_path
+ try:
+ yield
+ finally:
+ if old_index_path is None:
+ del os.environ['GIT_INDEX_FILE']
+ else:
+ os.environ['GIT_INDEX_FILE'] = old_index_path
+ os.remove(index_path)
+
+
+def create_temporary_index(tree=None):
+ """Create a temporary index file and return the created file's path.
+
+ If `tree` is not None, use that as the tree to read in. Otherwise, an
+ empty index is created."""
+ gitdir = run('git', 'rev-parse', '--git-dir')
+ path = os.path.join(gitdir, temp_index_basename)
+ if tree is None:
+ tree = '--empty'
+ run('git', 'read-tree', '--index-output='+path, tree)
+ return path
+
+
+def print_diff(old_tree, new_tree):
+ """Print the diff between the two trees to stdout."""
+ # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
+ # is expected to be viewed by the user, and only the former does nice things
+ # like color and pagination.
+ subprocess.check_call(['git', 'diff', old_tree, new_tree, '--'])
+
+
+def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
+ """Apply the changes in `new_tree` to the working directory.
+
+ Bails if there are local changes in those files and not `force`. If
+ `patch_mode`, runs `git checkout --patch` to select hunks interactively."""
+ changed_files = run('git', 'diff-tree', '-r', '-z', '--name-only', old_tree,
+ new_tree).rstrip('\0').split('\0')
+ 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.'
+ sys.exit(2)
+ if patch_mode:
+ # In patch mode, we could just as well create an index from the new tree
+ # and checkout from that, but then the user will be presented with a
+ # message saying "Discard ... from worktree". Instead, we use the old
+ # tree as the index and checkout from new_tree, which gives the slightly
+ # better message, "Apply ... to index and worktree". This is not quite
+ # right, since it won't be applied to the user's index, but oh well.
+ with temporary_index_file(old_tree):
+ subprocess.check_call(['git', 'checkout', '--patch', new_tree])
+ index_tree = old_tree
+ else:
+ with temporary_index_file(new_tree):
+ run('git', 'checkout-index', '-a', '-f')
+ return changed_files
+
+
+def run(*args, **kwargs):
+ stdin = kwargs.pop('stdin', '')
+ verbose = kwargs.pop('verbose', True)
+ strip = kwargs.pop('strip', True)
+ for name in kwargs:
+ raise TypeError("run() got an unexpected keyword argument '%s'" % name)
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ stdout, stderr = p.communicate(input=stdin)
+ if p.returncode == 0:
+ if stderr:
+ if verbose:
+ print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args)
+ print >>sys.stderr, stderr.rstrip()
+ if strip:
+ stdout = stdout.rstrip('\r\n')
+ return stdout
+ if verbose:
+ print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode)
+ if stderr:
+ print >>sys.stderr, stderr.rstrip()
+ sys.exit(2)
+
+
+def die(message):
+ print >>sys.stderr, 'error:', message
+ sys.exit(2)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/diagtool/DiagnosticNames.cpp b/tools/diagtool/DiagnosticNames.cpp
index 31f352414f90..155c62d80b2a 100644
--- a/tools/diagtool/DiagnosticNames.cpp
+++ b/tools/diagtool/DiagnosticNames.cpp
@@ -29,8 +29,7 @@ llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
// out of sync easily?
static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \
- CATEGORY) \
+ SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) \
{ #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
@@ -73,6 +72,26 @@ static const GroupRecord OptionTable[] = {
#undef GET_DIAG_TABLE
};
+llvm::StringRef GroupRecord::getName() const {
+ return StringRef(DiagGroupNames + NameOffset + 1, DiagGroupNames[NameOffset]);
+}
+
+GroupRecord::subgroup_iterator GroupRecord::subgroup_begin() const {
+ return DiagSubGroups + SubGroups;
+}
+
+GroupRecord::subgroup_iterator GroupRecord::subgroup_end() const {
+ return 0;
+}
+
+GroupRecord::diagnostics_iterator GroupRecord::diagnostics_begin() const {
+ return DiagArrays + Members;
+}
+
+GroupRecord::diagnostics_iterator GroupRecord::diagnostics_end() const {
+ return 0;
+}
+
llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
return llvm::makeArrayRef(OptionTable);
}
diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h
index 9a731587e5e0..a3321fa68175 100644
--- a/tools/diagtool/DiagnosticNames.h
+++ b/tools/diagtool/DiagnosticNames.h
@@ -35,17 +35,11 @@ namespace diagtool {
struct GroupRecord {
- // Be safe with the size of 'NameLen' because we don't statically check if
- // the size will fit in the field; the struct size won't decrease with a
- // shorter type anyway.
- size_t NameLen;
- const char *NameStr;
- const short *Members;
- const short *SubGroups;
-
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
- }
+ uint16_t NameOffset;
+ uint16_t Members;
+ uint16_t SubGroups;
+
+ llvm::StringRef getName() const;
template<typename RecordType>
class group_iterator {
@@ -90,23 +84,15 @@ namespace diagtool {
};
typedef group_iterator<GroupRecord> subgroup_iterator;
- subgroup_iterator subgroup_begin() const {
- return SubGroups;
- }
- subgroup_iterator subgroup_end() const {
- return 0;
- }
+ subgroup_iterator subgroup_begin() const;
+ subgroup_iterator subgroup_end() const;
typedef group_iterator<DiagnosticRecord> diagnostics_iterator;
- diagnostics_iterator diagnostics_begin() const {
- return Members;
- }
- diagnostics_iterator diagnostics_end() const {
- return 0;
- }
+ diagnostics_iterator diagnostics_begin() const;
+ diagnostics_iterator diagnostics_end() const;
- bool operator<(const GroupRecord &Other) const {
- return getName() < Other.getName();
+ bool operator<(llvm::StringRef Other) const {
+ return getName() < Other;
}
};
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
index 94f9c7663add..d49e976e6428 100644
--- a/tools/diagtool/Makefile
+++ b/tools/diagtool/Makefile
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS := 1
NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index 629817903040..fd548ef011bd 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -94,9 +94,13 @@ static int showGroup(llvm::raw_ostream &out, StringRef RootGroup,
bool FlagsOnly) {
ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
- GroupRecord Key = { RootGroup.size(), RootGroup.data(), 0, 0 };
+ if (RootGroup.size() > UINT16_MAX) {
+ llvm::errs() << "No such diagnostic group exists\n";
+ return 1;
+ }
+
const GroupRecord *Found =
- std::lower_bound(AllGroups.begin(), AllGroups.end(), Key);
+ std::lower_bound(AllGroups.begin(), AllGroups.end(), RootGroup);
if (Found == AllGroups.end() || Found->getName() != RootGroup) {
llvm::errs() << "No such diagnostic group exists\n";
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 97ac7a46c194..c94bc771e1d5 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -29,16 +29,31 @@ target_link_libraries(clang
clangLex
clangParse
clangEdit
- clangARCMigrate
- clangRewriteCore
- clangRewriteFrontend
clangSema
clangSerialization
- clangStaticAnalyzerFrontend
- clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
)
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ target_link_libraries(clang
+ clangStaticAnalyzerFrontend
+ clangStaticAnalyzerCheckers
+ clangStaticAnalyzerCore
+ )
+endif()
+
+if(CLANG_ENABLE_ARCMT)
+ target_link_libraries(clang
+ clangARCMigrate
+ )
+endif()
+
+if(CLANG_ENABLE_REWRITER)
+ target_link_libraries(clang
+ clangRewriteCore
+ clangRewriteFrontend
+ )
+endif()
+
set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
set_target_properties(clang PROPERTIES ENABLE_EXPORTS 1)
@@ -50,19 +65,59 @@ if(UNIX)
set(clang_binary "clang${CMAKE_EXECUTABLE_SUFFIX}")
else()
set(CLANGXX_LINK_OR_COPY copy)
- set(clang_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
+ set(clang_binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
endif()
# Create the clang++ symlink in the build directory.
-set(clang_pp "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
+set(clang_pp "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
add_custom_command(TARGET clang POST_BUILD
COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}")
set_property(DIRECTORY APPEND
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp})
+# Create the clang-cl symlink in the build directory.
+set(clang_cl "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/clang-cl${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_command(TARGET clang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_cl}")
+
+set_property(DIRECTORY APPEND
+ PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_cl})
+
install(TARGETS clang
RUNTIME DESTINATION bin)
-# Create the clang++ symlink at installation time.
+# Create the clang++ and clang-cl symlinks at installation time.
install(SCRIPT clang_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\")
+
+# Configure plist creation for OS X.
+set (TOOL_INFO_PLIST "Info.plist" CACHE STRING "Plist name")
+if (APPLE)
+ if (CLANG_VENDOR)
+ set(TOOL_INFO_NAME "${CLANG_VENDOR} clang")
+ else()
+ set(TOOL_INFO_NAME "clang")
+ endif()
+
+ set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}")
+ set(TOOL_INFO_VERSION "${CLANG_VERSION}")
+ if (LLVM_SUBMIT_VERSION)
+ set(TOOL_INFO_BUILD_VERSION
+ "${LLVM_SUBMIT_VERSION}.${LLVM_SUBMIT_SUBVERSION}")
+ endif()
+
+ set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
+ target_link_libraries(clang
+ "-Wl,-sectcreate,__TEXT,__info_plist,${TOOL_INFO_PLIST_OUT}")
+ configure_file("${TOOL_INFO_PLIST}.in" "${TOOL_INFO_PLIST_OUT}" @ONLY)
+
+ set(TOOL_INFO_UTI)
+ set(TOOL_INFO_NAME)
+ set(TOOL_INFO_VERSION)
+ set(TOOL_INFO_BUILD_VERSION)
+endif()
+
+if(CLANG_ORDER_FILE)
+ target_link_libraries(clang "-Wl,-order_file,${CLANG_ORDER_FILE}")
+endif()
+
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index cdf3b5248c31..f7a9f8f36e5e 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -30,7 +30,7 @@ TOOL_INFO_PLIST := Info.plist
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
- instrumentation ipo irreader linker selectiondag
+ instrumentation ipo irreader linker selectiondag option
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 35cf5b873510..5b3b5ad6500b 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -13,10 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
+#include "llvm/Option/Arg.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -26,6 +24,8 @@
#include "clang/FrontendTool/Utils.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/LinkAllPasses.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Signals.h"
@@ -34,6 +34,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
+using namespace llvm::opt;
//===----------------------------------------------------------------------===//
// Main driver
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 232ea2f6681a..31cd236b84ce 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -14,14 +14,12 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/CC1AsOptions.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -37,8 +35,12 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
@@ -55,6 +57,7 @@
using namespace clang;
using namespace clang::driver;
using namespace llvm;
+using namespace llvm::opt;
namespace {
@@ -181,7 +184,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Language Options
Opts.IncludePaths = Args->getAllArgValues(OPT_I);
Opts.NoInitialTextSection = Args->hasArg(OPT_n);
- Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
+ Opts.SaveTemporaryLabels = Args->hasArg(OPT_msave_temp_labels);
Opts.GenDwarfForAssembly = Args->hasArg(OPT_g);
Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags);
Opts.DwarfDebugProducer = Args->getLastArgValue(OPT_dwarf_debug_producer);
@@ -203,8 +206,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
}
}
Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
- if (Args->hasArg(OPT_fatal_warnings))
- Opts.LLVMArgs.push_back("-fatal-assembler-warnings");
Opts.OutputPath = Args->getLastArgValue(OPT_o);
if (Arg *A = Args->getLastArg(OPT_filetype)) {
StringRef Name = A->getValue();
@@ -224,14 +225,14 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.ShowVersion = Args->hasArg(OPT_version);
// Transliterate Options
- Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant,
- 0, Diags);
+ Opts.OutputAsmVariant =
+ getLastArgIntValue(*Args.get(), OPT_output_asm_variant, 0, Diags);
Opts.ShowEncoding = Args->hasArg(OPT_show_encoding);
Opts.ShowInst = Args->hasArg(OPT_show_inst);
// Assemble Options
- Opts.RelaxAll = Args->hasArg(OPT_relax_all);
- Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack);
+ Opts.RelaxAll = Args->hasArg(OPT_mrelax_all);
+ Opts.NoExecStack = Args->hasArg(OPT_mno_exec_stack);
return Success;
}
@@ -245,12 +246,12 @@ static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
// Make sure that the Out file gets unlinked from the disk if we get a
// SIGINT.
if (Opts.OutputPath != "-")
- sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath));
+ sys::RemoveFileOnSignal(Opts.OutputPath);
std::string Error;
raw_fd_ostream *Out =
- new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
- (Binary ? raw_fd_ostream::F_Binary : 0));
+ new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
+ (Binary ? sys::fs::F_Binary : sys::fs::F_None));
if (!Error.empty()) {
Diags.Report(diag::err_fe_unable_to_open_output)
<< Opts.OutputPath << Error;
@@ -287,12 +288,12 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// it later.
SrcMgr.setIncludeDirs(Opts.IncludePaths);
- OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple));
- assert(MAI && "Unable to create target asm info!");
-
OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
assert(MRI && "Unable to create target register info!");
+ OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple));
+ assert(MAI && "Unable to create target asm info!");
+
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
if (!Out)
@@ -301,7 +302,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
- MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
// FIXME: Assembler behavior can change with -static.
MOFI->InitMCObjectFileInfo(Opts.Triple,
Reloc::Default, CodeModel::Default, Ctx);
@@ -341,7 +342,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
- MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
+ MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
@@ -355,7 +356,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
- MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
+ Opts.CPU);
Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
CE, Opts.RelaxAll,
Opts.NoExecStack));
@@ -364,7 +366,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
*Str.get(), *MAI));
- OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
+ OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser, *MCII));
if (!TAP) {
Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
return false;
@@ -379,7 +381,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// Delete output on errors.
if (!Success && Opts.OutputPath != "-")
- sys::Path(Opts.OutputPath).eraseFromDisk();
+ sys::fs::remove(Opts.OutputPath);
return Success;
}
@@ -426,7 +428,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
// Honor -help.
if (Asm.ShowHelp) {
- OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
+ OwningPtr<OptTable> Opts(driver::createCC1AsOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
return 0;
}
diff --git a/tools/driver/clang_symlink.cmake b/tools/driver/clang_symlink.cmake
index c7341cb2fa61..c01259543c90 100644
--- a/tools/driver/clang_symlink.cmake
+++ b/tools/driver/clang_symlink.cmake
@@ -19,9 +19,25 @@ endif()
set(bindir "${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/")
set(clang "clang${EXECUTABLE_SUFFIX}")
set(clangxx "clang++${EXECUTABLE_SUFFIX}")
+set(clang_cl "clang-cl${EXECUTABLE_SUFFIX}")
+set(cl "cl${EXECUTABLE_SUFFIX}")
message("Creating clang++ executable based on ${clang}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clangxx}"
WORKING_DIRECTORY "${bindir}")
+
+message("Creating clang-cl executable based on ${clang}")
+
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clang_cl}"
+ WORKING_DIRECTORY "${bindir}")
+
+if (WIN32)
+ message("Creating cl executable based on ${clang}")
+
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "../msbuild-bin/${cl}"
+ WORKING_DIRECTORY "${bindir}")
+endif()
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 4c40da3080a2..3a6a09b77fc7 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -14,12 +14,9 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -28,6 +25,11 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
@@ -35,6 +37,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
@@ -45,15 +48,16 @@
#include "llvm/Support/system_error.h"
using namespace clang;
using namespace clang::driver;
+using namespace llvm::opt;
-llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
+std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
if (!CanonicalPrefixes)
- return llvm::sys::Path(Argv0);
+ return Argv0;
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *P = (void*) (intptr_t) GetExecutablePath;
- return llvm::sys::Path::GetMainExecutable(Argv0, P);
+ return llvm::sys::fs::getMainExecutable(Argv0, P);
}
static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
@@ -187,78 +191,6 @@ extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr);
-static void ExpandArgsFromBuf(const char *Arg,
- SmallVectorImpl<const char*> &ArgVector,
- std::set<std::string> &SavedStrings) {
- const char *FName = Arg + 1;
- OwningPtr<llvm::MemoryBuffer> MemBuf;
- if (llvm::MemoryBuffer::getFile(FName, MemBuf)) {
- ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
- return;
- }
-
- const char *Buf = MemBuf->getBufferStart();
- char InQuote = ' ';
- std::string CurArg;
-
- for (const char *P = Buf; ; ++P) {
- if (*P == '\0' || (isWhitespace(*P) && InQuote == ' ')) {
- if (!CurArg.empty()) {
-
- if (CurArg[0] != '@') {
- ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
- } else {
- ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
- }
-
- CurArg = "";
- }
- if (*P == '\0')
- break;
- else
- continue;
- }
-
- if (isWhitespace(*P)) {
- if (InQuote != ' ')
- CurArg.push_back(*P);
- continue;
- }
-
- if (*P == '"' || *P == '\'') {
- if (InQuote == *P)
- InQuote = ' ';
- else if (InQuote == ' ')
- InQuote = *P;
- else
- CurArg.push_back(*P);
- continue;
- }
-
- if (*P == '\\') {
- ++P;
- if (*P != '\0')
- CurArg.push_back(*P);
- continue;
- }
- CurArg.push_back(*P);
- }
-}
-
-static void ExpandArgv(int argc, const char **argv,
- SmallVectorImpl<const char*> &ArgVector,
- std::set<std::string> &SavedStrings) {
- for (int i = 0; i < argc; ++i) {
- const char *Arg = argv[i];
- if (Arg[0] != '@') {
- ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
- continue;
- }
-
- ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
- }
-}
-
static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
std::set<std::string> &SavedStrings,
Driver &TheDriver)
@@ -279,21 +211,24 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
// is gets added via -target as implicit first argument.
static const struct {
const char *Suffix;
- bool IsCXX;
- bool IsCPP;
+ const char *ModeFlag;
} suffixes [] = {
- { "clang", false, false },
- { "clang++", true, false },
- { "clang-c++", true, false },
- { "clang-cc", false, false },
- { "clang-cpp", false, true },
- { "clang-g++", true, false },
- { "clang-gcc", false, false },
- { "cc", false, false },
- { "cpp", false, true },
- { "++", true, false },
+ { "clang", 0 },
+ { "clang++", "--driver-mode=g++" },
+ { "clang-c++", "--driver-mode=g++" },
+ { "clang-cc", 0 },
+ { "clang-cpp", "--driver-mode=cpp" },
+ { "clang-g++", "--driver-mode=g++" },
+ { "clang-gcc", 0 },
+ { "clang-cl", "--driver-mode=cl" },
+ { "cc", 0 },
+ { "cpp", "--driver-mode=cpp" },
+ { "cl" , "--driver-mode=cl" },
+ { "++", "--driver-mode=g++" },
};
std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
+ toLowercase);
StringRef ProgNameRef(ProgName);
StringRef Prefix;
@@ -304,10 +239,11 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
if (ProgNameRef.endswith(suffixes[i].Suffix)) {
FoundMatch = true;
- if (suffixes[i].IsCXX)
- TheDriver.CCCIsCXX = true;
- if (suffixes[i].IsCPP)
- TheDriver.CCCIsCPP = true;
+ SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ if (suffixes[i].ModeFlag)
+ ArgVector.insert(it, suffixes[i].ModeFlag);
break;
}
}
@@ -334,20 +270,41 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
if (it != ArgVector.end())
++it;
- ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
- ArgVector.insert(it,
- SaveStringInSet(SavedStrings, std::string("-target")));
+ const char* Strings[] =
+ { SaveStringInSet(SavedStrings, std::string("-target")),
+ SaveStringInSet(SavedStrings, Prefix) };
+ ArgVector.insert(it, Strings, Strings + llvm::array_lengthof(Strings));
}
}
+namespace {
+ class StringSetSaver : public llvm::cl::StringSaver {
+ public:
+ StringSetSaver(std::set<std::string> &Storage) : Storage(Storage) {}
+ const char *SaveString(const char *Str) LLVM_OVERRIDE {
+ return SaveStringInSet(Storage, Str);
+ }
+ private:
+ std::set<std::string> &Storage;
+ };
+}
+
int main(int argc_, const char **argv_) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc_, argv_);
- std::set<std::string> SavedStrings;
- SmallVector<const char*, 256> argv;
+ SmallVector<const char *, 256> argv;
+ llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
+ llvm::error_code EC = llvm::sys::Process::GetArgumentVector(
+ argv, llvm::ArrayRef<const char *>(argv_, argc_), ArgAllocator);
+ if (EC) {
+ llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
+ return 1;
+ }
- ExpandArgv(argc_, argv_, argv, SavedStrings);
+ std::set<std::string> SavedStrings;
+ StringSetSaver Saver(SavedStrings);
+ llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv);
// Handle -cc1 integrated tools.
if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) {
@@ -378,36 +335,17 @@ int main(int argc_, const char **argv_) {
if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
// FIXME: Driver shouldn't take extra initial argument.
ApplyQAOverride(argv, OverrideStr, SavedStrings);
- } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
- // FIXME: Driver shouldn't take extra initial argument.
- std::vector<const char*> ExtraArgs;
-
- for (;;) {
- const char *Next = strchr(Cur, ',');
-
- if (Next) {
- ExtraArgs.push_back(SaveStringInSet(SavedStrings,
- std::string(Cur, Next)));
- Cur = Next + 1;
- } else {
- if (*Cur != '\0')
- ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur));
- break;
- }
- }
-
- argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
}
- llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
+ std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
{
- // Note that ParseDiagnosticArgs() uses the cc1 option table.
- OwningPtr<OptTable> CC1Opts(createDriverOptTable());
+ OwningPtr<OptTable> Opts(createDriverOptTable());
unsigned MissingArgIndex, MissingArgCount;
- OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(),
- MissingArgIndex, MissingArgCount));
+ OwningPtr<InputArgList> Args(Opts->ParseArgs(argv.begin()+1, argv.end(),
+ MissingArgIndex,
+ MissingArgCount));
// We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
// Any errors that would be diagnosed here will also be diagnosed later,
// when the DiagnosticsEngine actually exists.
@@ -417,14 +355,20 @@ int main(int argc_, const char **argv_) {
// DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
- DiagClient->setPrefix(llvm::sys::path::filename(Path.str()));
+
+ // If the clang binary happens to be named cl.exe for compatibility reasons,
+ // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
+ StringRef ExeBasename(llvm::sys::path::filename(Path));
+ if (ExeBasename.equals_lower("cl.exe"))
+ ExeBasename = "clang-cl.exe";
+ DiagClient->setPrefix(ExeBasename);
+
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
- Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
- "a.out", Diags);
+ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), "a.out", Diags);
// Attempt to find the original path used to invoke the driver, to determine
// the installed path. We do this manually, because we want to support that
@@ -434,10 +378,10 @@ int main(int argc_, const char **argv_) {
// Do a PATH lookup, if there are no directory components.
if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
- llvm::sys::Path Tmp = llvm::sys::Program::FindProgramByName(
+ std::string Tmp = llvm::sys::FindProgramByName(
llvm::sys::path::filename(InstalledPath.str()));
if (!Tmp.empty())
- InstalledPath = Tmp.str();
+ InstalledPath = Tmp;
}
llvm::sys::fs::make_absolute(InstalledPath);
InstalledPath = llvm::sys::path::parent_path(InstalledPath);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index a43c1ab7e459..f53e5c1c4951 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -22,13 +22,14 @@
#include "CXTranslationUnit.h"
#include "CXType.h"
#include "CursorVisitor.h"
-#include "SimpleFormatContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Index/CommentToXML.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PreprocessingRecord.h"
@@ -42,7 +43,6 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
-#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Signals.h"
@@ -68,8 +68,7 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) {
D->StringPool = new cxstring::CXStringPool();
D->Diagnostics = 0;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
- D->FormatContext = 0;
- D->FormatInMemoryUniqueId = 0;
+ D->CommentToXML = 0;
return D;
}
@@ -308,8 +307,8 @@ bool CursorVisitor::visitDeclsFromFileRegion(FileID File,
bool VisitedAtLeastOnce = false;
DeclContext *CurDC = 0;
- SmallVector<Decl *, 16>::iterator DIt = Decls.begin();
- for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
+ SmallVectorImpl<Decl *>::iterator DIt = Decls.begin();
+ for (SmallVectorImpl<Decl *>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
Decl *D = *DIt;
if (D->getSourceRange().isInvalid())
continue;
@@ -426,6 +425,9 @@ bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
continue;
PreprocessedEntity *PPE = *First;
+ if (!PPE)
+ continue;
+
if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
if (Visit(MakeMacroExpansionCursor(ME, TU)))
return true;
@@ -528,9 +530,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
- if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
- return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
- A->getInterfaceLoc(), TU));
+ if (const ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>())
+ return Visit(cxcursor::MakeCursorObjCClassRef(
+ ObjT->getInterface(),
+ A->getInterfaceLoc()->getTypeLoc().getLocStart(), TU));
}
// If pointing inside a macro definition, check if the token is an identifier
@@ -698,8 +701,9 @@ bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
return true;
// Visit the partial specialization arguments.
- const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten();
- for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I)
+ const ASTTemplateArgumentListInfo *Info = D->getTemplateArgsAsWritten();
+ const TemplateArgumentLoc *TemplateArgs = Info->getTemplateArgs();
+ for (unsigned I = 0, N = Info->NumTemplateArgs; I != N; ++I)
if (VisitTemplateArgumentLoc(TemplateArgs[I]))
return true;
@@ -743,18 +747,9 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
}
/// \brief Compare two base or member initializers based on their source order.
-static int CompareCXXCtorInitializers(const void* Xp, const void *Yp) {
- CXXCtorInitializer const * const *X
- = static_cast<CXXCtorInitializer const * const *>(Xp);
- CXXCtorInitializer const * const *Y
- = static_cast<CXXCtorInitializer const * const *>(Yp);
-
- if ((*X)->getSourceOrder() < (*Y)->getSourceOrder())
- return -1;
- else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder())
- return 1;
- else
- return 0;
+static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,
+ CXXCtorInitializer *const *Y) {
+ return (*X)->getSourceOrder() - (*Y)->getSourceOrder();
}
bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
@@ -1543,6 +1538,10 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
return false;
}
+bool CursorVisitor::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ return Visit(TL.getOriginalLoc());
+}
+
bool CursorVisitor::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
// Visit the template name.
@@ -1795,6 +1794,7 @@ public:
}
};
class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
+ friend class OMPClauseEnqueue;
VisitorWorkList &WL;
CXCursor Parent;
public:
@@ -1846,6 +1846,8 @@ public:
void VisitPseudoObjectExpr(const PseudoObjectExpr *E);
void VisitOpaqueValueExpr(const OpaqueValueExpr *E);
void VisitLambdaExpr(const LambdaExpr *E);
+ void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
+ void VisitOMPParallelDirective(const OMPParallelDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
@@ -1856,6 +1858,7 @@ private:
void AddDecl(const Decl *D, bool isFirst = true);
void AddTypeLoc(TypeSourceInfo *TI);
void EnqueueChildren(const Stmt *S);
+ void EnqueueChildren(const OMPClause *S);
};
} // end anonyous namespace
@@ -1904,6 +1907,52 @@ void EnqueueVisitor::EnqueueChildren(const Stmt *S) {
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
std::reverse(I, E);
}
+namespace {
+class OMPClauseEnqueue : public ConstOMPClauseVisitor<OMPClauseEnqueue> {
+ EnqueueVisitor *Visitor;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
+public:
+ OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(const Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
+
+template<typename T>
+void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_const_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ Visitor->AddStmt(*I);
+}
+
+void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseEnqueue::VisitOMPFirstprivateClause(
+ const OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+}
+}
+
+void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {
+ unsigned size = WL.size();
+ OMPClauseEnqueue Visitor(this);
+ Visitor.Visit(S);
+ if (size == WL.size())
+ return;
+ // Now reverse the entries we just added. This will match the DFS
+ // ordering performed by the worklist.
+ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
+ std::reverse(I, E);
+}
void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) {
WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent));
}
@@ -2027,7 +2076,6 @@ void EnqueueVisitor::VisitDeclStmt(const DeclStmt *S) {
}
void EnqueueVisitor::VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
AddStmt(E->getInit());
- typedef DesignatedInitExpr::Designator Designator;
for (DesignatedInitExpr::const_reverse_designators_iterator
D = E->designators_rbegin(), DEnd = E->designators_rend();
D != DEnd; ++D) {
@@ -2182,6 +2230,19 @@ void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
Visit(E->getSyntacticForm());
}
+void EnqueueVisitor::VisitOMPExecutableDirective(
+ const OMPExecutableDirective *D) {
+ EnqueueChildren(D);
+ for (ArrayRef<OMPClause *>::iterator I = D->clauses().begin(),
+ E = D->clauses().end();
+ I != E; ++I)
+ EnqueueChildren(*I);
+}
+
+void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -2198,8 +2259,7 @@ bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
while (!WL.empty()) {
// Dequeue the worklist item.
- VisitorJob LI = WL.back();
- WL.pop_back();
+ VisitorJob LI = WL.pop_back_val();
// Set the Parent field, then back to its old value once we're done.
SetParentRAII SetParent(Parent, StmtParent, LI.getParent());
@@ -2363,9 +2423,10 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
CEnd = E->explicit_capture_end();
C != CEnd; ++C) {
- if (C->capturesThis())
+ // FIXME: Lambda init-captures.
+ if (!C->capturesVariable())
continue;
-
+
if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
C->getLocation(),
TU)))
@@ -2481,10 +2542,6 @@ static void fatal_error_handler(void *user_data, const std::string& reason,
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
- // Disable pretty stack trace functionality, which will otherwise be a very
- // poor citizen of the world and set up all sorts of signal handlers.
- llvm::DisablePrettyStackTrace = true;
-
// We use crash recovery to make some of our APIs more reliable, implicitly
// enable it.
llvm::CrashRecoveryContext::Enable();
@@ -2540,9 +2597,13 @@ void clang_toggleCrashRecovery(unsigned isEnabled) {
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
const char *ast_filename) {
- if (!CIdx)
+ if (!CIdx || !ast_filename)
return 0;
+ LOG_FUNC_SECTION {
+ *Log << ast_filename;
+ }
+
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
FileSystemOptions FileSystemOpts;
@@ -2842,7 +2903,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete CTUnit->StringPool;
delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
- delete CTUnit->FormatContext;
+ delete CTUnit->CommentToXML;
delete CTUnit;
}
}
@@ -2995,15 +3056,12 @@ int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID) {
if (!file || !outID)
return 1;
-#ifdef LLVM_ON_WIN32
- return 1; // inodes not supported on windows.
-#else
FileEntry *FEnt = static_cast<FileEntry *>(file);
- outID->data[0] = FEnt->getDevice();
- outID->data[1] = FEnt->getInode();
+ const llvm::sys::fs::UniqueID &ID = FEnt->getUniqueID();
+ outID->data[0] = ID.getDevice();
+ outID->data[1] = ID.getFile();
outID->data[2] = FEnt->getModificationTime();
return 0;
-#endif
}
} // end: extern "C"
@@ -3289,6 +3347,10 @@ CXString clang_getCursorSpelling(CXCursor C) {
return cxstring::createDup(AA->getLabel());
}
+ if (C.kind == CXCursor_PackedAttr) {
+ return cxstring::createRef("packed");
+ }
+
return cxstring::createEmpty();
}
@@ -3706,6 +3768,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("attribute(annotate)");
case CXCursor_AsmLabelAttr:
return cxstring::createRef("asm label");
+ case CXCursor_PackedAttr:
+ return cxstring::createRef("attribute(packed)");
case CXCursor_PreprocessingDirective:
return cxstring::createRef("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -3754,6 +3818,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("CXXAccessSpecifier");
case CXCursor_ModuleImportDecl:
return cxstring::createRef("ModuleImport");
+ case CXCursor_OMPParallelDirective:
+ return cxstring::createRef("OMPParallelDirective");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -4111,6 +4177,12 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
+ if (clang_isAttribute(C.kind)) {
+ SourceLocation L
+ = cxcursor::getCursorAttr(C)->getLocation();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
if (!clang_isDeclaration(C.kind))
return clang_getNullLocation();
@@ -4521,7 +4593,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
}
- case Decl::Var: {
+ case Decl::Var:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization: {
// Ask the variable if it has a definition.
if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition())
return MakeCXCursor(Def, TU);
@@ -4543,6 +4617,13 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
}
+ case Decl::VarTemplate: {
+ if (VarDecl *Def =
+ cast<VarTemplateDecl>(D)->getTemplatedDecl()->getDefinition())
+ return MakeCXCursor(cast<VarDecl>(Def)->getDescribedVarTemplate(), TU);
+ return clang_getNullCursor();
+ }
+
case Decl::Using:
return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D),
D->getLocation(), TU);
@@ -5171,6 +5252,11 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
HasContextSensitiveKeywords = true;
}
}
+
+ // Don't override a property annotation with its getter/setter method.
+ if (cursor.kind == CXCursor_ObjCInstanceMethodDecl &&
+ parent.kind == CXCursor_ObjCPropertyDecl)
+ return CXChildVisit_Continue;
if (clang_isPreprocessing(cursor.kind)) {
// Items in the preprocessing record are kept separate from items in
@@ -5678,8 +5764,9 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
const Decl *D = cxcursor::getCursorDecl(cursor);
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
- switch (ND->getLinkage()) {
- case NoLinkage: return CXLinkage_NoLinkage;
+ switch (ND->getLinkageInternal()) {
+ case NoLinkage:
+ case VisibleNoLinkage: return CXLinkage_NoLinkage;
case InternalLinkage: return CXLinkage_Internal;
case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
case ExternalLinkage: return CXLinkage_External;
@@ -5743,25 +5830,33 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
}
extern "C" {
+
+static CXAvailabilityKind getCursorAvailabilityForDecl(const Decl *D) {
+ if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
+ return CXAvailability_Available;
-enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
- if (clang_isDeclaration(cursor.kind))
- if (const Decl *D = cxcursor::getCursorDecl(cursor)) {
- if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
- return CXAvailability_Available;
-
- switch (D->getAvailability()) {
- case AR_Available:
- case AR_NotYetIntroduced:
- return CXAvailability_Available;
+ switch (D->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
+ return getCursorAvailabilityForDecl(
+ cast<Decl>(EnumConst->getDeclContext()));
+ return CXAvailability_Available;
- case AR_Deprecated:
- return CXAvailability_Deprecated;
+ case AR_Deprecated:
+ return CXAvailability_Deprecated;
- case AR_Unavailable:
- return CXAvailability_NotAvailable;
- }
- }
+ case AR_Unavailable:
+ return CXAvailability_NotAvailable;
+ }
+
+ llvm_unreachable("Unknown availability kind!");
+}
+
+enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ if (const Decl *D = cxcursor::getCursorDecl(cursor))
+ return getCursorAvailabilityForDecl(D);
return CXAvailability_Available;
}
@@ -5785,34 +5880,20 @@ static CXVersion convertVersion(VersionTuple In) {
return Out;
}
-
-int clang_getCursorPlatformAvailability(CXCursor cursor,
- int *always_deprecated,
- CXString *deprecated_message,
- int *always_unavailable,
- CXString *unavailable_message,
- CXPlatformAvailability *availability,
- int availability_size) {
- if (always_deprecated)
- *always_deprecated = 0;
- if (deprecated_message)
- *deprecated_message = cxstring::createEmpty();
- if (always_unavailable)
- *always_unavailable = 0;
- if (unavailable_message)
- *unavailable_message = cxstring::createEmpty();
-
- if (!clang_isDeclaration(cursor.kind))
- return 0;
-
- const Decl *D = cxcursor::getCursorDecl(cursor);
- if (!D)
- return 0;
-
+
+static int getCursorPlatformAvailabilityForDecl(const Decl *D,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ bool HadAvailAttr = false;
int N = 0;
for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd;
++A) {
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ HadAvailAttr = true;
if (always_deprecated)
*always_deprecated = 1;
if (deprecated_message)
@@ -5821,6 +5902,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
}
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ HadAvailAttr = true;
if (always_unavailable)
*always_unavailable = 1;
if (unavailable_message) {
@@ -5830,6 +5912,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
}
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
+ HadAvailAttr = true;
if (N < availability_size) {
availability[N].Platform
= cxstring::createDup(Avail->getPlatform()->getName());
@@ -5842,9 +5925,51 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
++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;
}
+
+int clang_getCursorPlatformAvailability(CXCursor cursor,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ if (always_deprecated)
+ *always_deprecated = 0;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createEmpty();
+ if (always_unavailable)
+ *always_unavailable = 0;
+ if (unavailable_message)
+ *unavailable_message = cxstring::createEmpty();
+
+ if (!clang_isDeclaration(cursor.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (!D)
+ return 0;
+
+ return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
+ deprecated_message,
+ always_unavailable,
+ unavailable_message,
+ availability,
+ availability_size);
+}
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
clang_disposeString(availability->Platform);
@@ -5974,6 +6099,19 @@ unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) {
return Result;
}
+unsigned clang_Cursor_isObjCOptional(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = getCursorDecl(C);
+ if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ return PD->getPropertyImplementation() == ObjCPropertyDecl::Optional;
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getImplementationControl() == ObjCMethodDecl::Optional;
+
+ return 0;
+}
+
unsigned clang_Cursor_isVariadic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -6114,6 +6252,20 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU,
//===----------------------------------------------------------------------===//
extern "C" {
+unsigned clang_CXXMethod_isPureVirtual(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const CXXMethodDecl *Method = 0;
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast_or_null<FunctionTemplateDecl>(D))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast_or_null<CXXMethodDecl>(D);
+ return (Method && Method->isVirtual() && Method->isPure()) ? 1 : 0;
+}
+
unsigned clang_CXXMethod_isStatic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index f79de2909edd..865bb585b54d 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -27,10 +27,12 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Atomic.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
@@ -271,7 +273,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Temporary files that should be removed once we have finished
/// with the code-completion results.
- std::vector<llvm::sys::Path> TemporaryFiles;
+ std::vector<std::string> TemporaryFiles;
/// \brief Temporary buffers that will be deleted once we have finished with
/// the code-completion results.
@@ -340,7 +342,7 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
delete [] Results;
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
- TemporaryFiles[I].eraseFromDisk();
+ llvm::sys::fs::remove(TemporaryFiles[I]);
for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
delete TemporaryBuffers[I];
@@ -561,15 +563,13 @@ namespace {
AllocatedResults.Contexts = getContextsForContextKind(contextKind, S);
AllocatedResults.Selector = "";
- if (Context.getNumSelIdents() > 0) {
- for (unsigned i = 0; i < Context.getNumSelIdents(); i++) {
- IdentifierInfo *selIdent = Context.getSelIdents()[i];
- if (selIdent != NULL) {
- StringRef selectorString = Context.getSelIdents()[i]->getName();
- AllocatedResults.Selector += selectorString;
- }
- AllocatedResults.Selector += ":";
- }
+ ArrayRef<IdentifierInfo *> SelIdents = Context.getSelIdents();
+ for (ArrayRef<IdentifierInfo *>::iterator I = SelIdents.begin(),
+ E = SelIdents.end();
+ I != E; ++I) {
+ if (IdentifierInfo *selIdent = *I)
+ AllocatedResults.Selector += selIdent->getName();
+ AllocatedResults.Selector += ":";
}
QualType baseType = Context.getBaseType();
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index 2a55af57fc9d..c772dbbcb909 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -36,7 +36,7 @@ static void getTopOverriddenMethods(CXTranslationUnit TU,
return;
}
- for (SmallVector<CXCursor, 8>::iterator
+ for (SmallVectorImpl<CXCursor>::iterator
I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
}
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index a911ce5e952a..2b43c5b375f5 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -14,787 +14,13 @@
#include "CIndexer.h"
#include "CXCursor.h"
#include "CXString.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/Frontend/ASTUnit.h"
+#include "clang/Index/USRGeneration.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// USR generation.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class USRGenerator : public ConstDeclVisitor<USRGenerator> {
- OwningPtr<SmallString<128> > OwnedBuf;
- SmallVectorImpl<char> &Buf;
- llvm::raw_svector_ostream Out;
- bool IgnoreResults;
- ASTContext *Context;
- bool generatedLoc;
-
- llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;
-
-public:
- explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0)
- : OwnedBuf(extBuf ? 0 : new SmallString<128>()),
- Buf(extBuf ? *extBuf : *OwnedBuf.get()),
- Out(Buf),
- IgnoreResults(false),
- Context(Ctx),
- generatedLoc(false)
- {
- // Add the USR space prefix.
- Out << "c:";
- }
-
- StringRef str() {
- return Out.str();
- }
-
- USRGenerator* operator->() { return this; }
-
- template <typename T>
- llvm::raw_svector_ostream &operator<<(const T &x) {
- Out << x;
- return Out;
- }
-
- bool ignoreResults() const { return IgnoreResults; }
-
- // Visitation methods from generating USRs from AST elements.
- void VisitDeclContext(const DeclContext *D);
- void VisitFieldDecl(const FieldDecl *D);
- void VisitFunctionDecl(const FunctionDecl *D);
- void VisitNamedDecl(const NamedDecl *D);
- void VisitNamespaceDecl(const NamespaceDecl *D);
- void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
- void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
- void VisitClassTemplateDecl(const ClassTemplateDecl *D);
- void VisitObjCContainerDecl(const ObjCContainerDecl *CD);
- void VisitObjCMethodDecl(const ObjCMethodDecl *MD);
- void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
- void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
- void VisitTagDecl(const TagDecl *D);
- void VisitTypedefDecl(const TypedefDecl *D);
- void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
- void VisitVarDecl(const VarDecl *D);
- void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
- void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
- void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
- IgnoreResults = true;
- }
- void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
- IgnoreResults = true;
- }
- void VisitUsingDecl(const UsingDecl *D) {
- IgnoreResults = true;
- }
- void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
- IgnoreResults = true;
- }
- void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
- IgnoreResults = true;
- }
-
- /// Generate the string component containing the location of the
- /// declaration.
- bool GenLoc(const Decl *D);
-
- /// String generation methods used both by the visitation methods
- /// and from other clients that want to directly generate USRs. These
- /// methods do not construct complete USRs (which incorporate the parents
- /// of an AST element), but only the fragments concerning the AST element
- /// itself.
-
- /// Generate a USR for an Objective-C class.
- void GenObjCClass(StringRef cls);
- /// Generate a USR for an Objective-C class category.
- void GenObjCCategory(StringRef cls, StringRef cat);
- /// Generate a USR fragment for an Objective-C instance variable. The
- /// complete USR can be created by concatenating the USR for the
- /// encompassing class with this USR fragment.
- void GenObjCIvar(StringRef ivar);
- /// Generate a USR fragment for an Objective-C method.
- void GenObjCMethod(StringRef sel, bool isInstanceMethod);
- /// Generate a USR fragment for an Objective-C property.
- void GenObjCProperty(StringRef prop);
- /// Generate a USR for an Objective-C protocol.
- void GenObjCProtocol(StringRef prot);
-
- void VisitType(QualType T);
- void VisitTemplateParameterList(const TemplateParameterList *Params);
- void VisitTemplateName(TemplateName Name);
- void VisitTemplateArgument(const TemplateArgument &Arg);
-
- /// Emit a Decl's name using NamedDecl::printName() and return true if
- /// the decl had no name.
- bool EmitDeclName(const NamedDecl *D);
-};
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Generating USRs from ASTS.
-//===----------------------------------------------------------------------===//
-
-bool USRGenerator::EmitDeclName(const NamedDecl *D) {
- Out.flush();
- const unsigned startSize = Buf.size();
- D->printName(Out);
- Out.flush();
- const unsigned endSize = Buf.size();
- return startSize == endSize;
-}
-
-static inline bool ShouldGenerateLocation(const NamedDecl *D) {
- return D->getLinkage() != ExternalLinkage;
-}
-
-void USRGenerator::VisitDeclContext(const DeclContext *DC) {
- if (const NamedDecl *D = dyn_cast<NamedDecl>(DC))
- Visit(D);
-}
-
-void USRGenerator::VisitFieldDecl(const FieldDecl *D) {
- // The USR for an ivar declared in a class extension is based on the
- // ObjCInterfaceDecl, not the ObjCCategoryDecl.
- if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
- Visit(ID);
- else
- VisitDeclContext(D->getDeclContext());
- Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
- if (EmitDeclName(D)) {
- // Bit fields can be anonymous.
- IgnoreResults = true;
- return;
- }
-}
-
-void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
- if (ShouldGenerateLocation(D) && GenLoc(D))
- return;
-
- VisitDeclContext(D->getDeclContext());
- if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
- Out << "@FT@";
- VisitTemplateParameterList(FunTmpl->getTemplateParameters());
- } else
- Out << "@F@";
- D->printName(Out);
-
- ASTContext &Ctx = *Context;
- if (!Ctx.getLangOpts().CPlusPlus || D->isExternC())
- return;
-
- if (const TemplateArgumentList *
- SpecArgs = D->getTemplateSpecializationArgs()) {
- Out << '<';
- for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) {
- Out << '#';
- VisitTemplateArgument(SpecArgs->get(I));
- }
- Out << '>';
- }
-
- // Mangle in type information for the arguments.
- for (FunctionDecl::param_const_iterator I = D->param_begin(),
- E = D->param_end();
- I != E; ++I) {
- Out << '#';
- if (ParmVarDecl *PD = *I)
- VisitType(PD->getType());
- }
- if (D->isVariadic())
- Out << '.';
- Out << '#';
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->isStatic())
- Out << 'S';
- if (unsigned quals = MD->getTypeQualifiers())
- Out << (char)('0' + quals);
- }
-}
-
-void USRGenerator::VisitNamedDecl(const NamedDecl *D) {
- VisitDeclContext(D->getDeclContext());
- Out << "@";
-
- if (EmitDeclName(D)) {
- // The string can be empty if the declaration has no name; e.g., it is
- // the ParmDecl with no name for declaration of a function pointer type,
- // e.g.: void (*f)(void *);
- // In this case, don't generate a USR.
- IgnoreResults = true;
- }
-}
-
-void USRGenerator::VisitVarDecl(const VarDecl *D) {
- // VarDecls can be declared 'extern' within a function or method body,
- // but their enclosing DeclContext is the function, not the TU. We need
- // to check the storage class to correctly generate the USR.
- if (ShouldGenerateLocation(D) && GenLoc(D))
- return;
-
- VisitDeclContext(D->getDeclContext());
-
- // Variables always have simple names.
- StringRef s = D->getName();
-
- // The string can be empty if the declaration has no name; e.g., it is
- // the ParmDecl with no name for declaration of a function pointer type, e.g.:
- // void (*f)(void *);
- // In this case, don't generate a USR.
- if (s.empty())
- IgnoreResults = true;
- else
- Out << '@' << s;
-}
-
-void USRGenerator::VisitNonTypeTemplateParmDecl(
- const NonTypeTemplateParmDecl *D) {
- GenLoc(D);
- return;
-}
-
-void USRGenerator::VisitTemplateTemplateParmDecl(
- const TemplateTemplateParmDecl *D) {
- GenLoc(D);
- return;
-}
-
-void USRGenerator::VisitNamespaceDecl(const NamespaceDecl *D) {
- if (D->isAnonymousNamespace()) {
- Out << "@aN";
- return;
- }
-
- VisitDeclContext(D->getDeclContext());
- if (!IgnoreResults)
- Out << "@N@" << D->getName();
-}
-
-void USRGenerator::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
- VisitFunctionDecl(D->getTemplatedDecl());
-}
-
-void USRGenerator::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
- VisitTagDecl(D->getTemplatedDecl());
-}
-
-void USRGenerator::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
- VisitDeclContext(D->getDeclContext());
- if (!IgnoreResults)
- Out << "@NA@" << D->getName();
-}
-
-void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
- const DeclContext *container = D->getDeclContext();
- if (const ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {
- Visit(pd);
- }
- else {
- // The USR for a method declared in a class extension or category is based on
- // the ObjCInterfaceDecl, not the ObjCCategoryDecl.
- const ObjCInterfaceDecl *ID = D->getClassInterface();
- if (!ID) {
- IgnoreResults = true;
- return;
- }
- Visit(ID);
- }
- // Ideally we would use 'GenObjCMethod', but this is such a hot path
- // for Objective-C code that we don't want to use
- // DeclarationName::getAsString().
- Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
- DeclarationName N(D->getSelector());
- N.printName(Out);
-}
-
-void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
- switch (D->getKind()) {
- default:
- llvm_unreachable("Invalid ObjC container.");
- case Decl::ObjCInterface:
- case Decl::ObjCImplementation:
- GenObjCClass(D->getName());
- break;
- case Decl::ObjCCategory: {
- const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
- const ObjCInterfaceDecl *ID = CD->getClassInterface();
- if (!ID) {
- // Handle invalid code where the @interface might not
- // have been specified.
- // FIXME: We should be able to generate this USR even if the
- // @interface isn't available.
- IgnoreResults = true;
- return;
- }
- // Specially handle class extensions, which are anonymous categories.
- // We want to mangle in the location to uniquely distinguish them.
- if (CD->IsClassExtension()) {
- Out << "objc(ext)" << ID->getName() << '@';
- GenLoc(CD);
- }
- else
- GenObjCCategory(ID->getName(), CD->getName());
-
- break;
- }
- case Decl::ObjCCategoryImpl: {
- const ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
- const ObjCInterfaceDecl *ID = CD->getClassInterface();
- if (!ID) {
- // Handle invalid code where the @interface might not
- // have been specified.
- // FIXME: We should be able to generate this USR even if the
- // @interface isn't available.
- IgnoreResults = true;
- return;
- }
- GenObjCCategory(ID->getName(), CD->getName());
- break;
- }
- case Decl::ObjCProtocol:
- GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
- break;
- }
-}
-
-void USRGenerator::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
- // The USR for a property declared in a class extension or category is based
- // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
- if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
- Visit(ID);
- else
- Visit(cast<Decl>(D->getDeclContext()));
- GenObjCProperty(D->getName());
-}
-
-void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
- if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
- VisitObjCPropertyDecl(PD);
- return;
- }
-
- IgnoreResults = true;
-}
-
-void USRGenerator::VisitTagDecl(const TagDecl *D) {
- // Add the location of the tag decl to handle resolution across
- // translation units.
- if (ShouldGenerateLocation(D) && GenLoc(D))
- return;
-
- D = D->getCanonicalDecl();
- VisitDeclContext(D->getDeclContext());
-
- bool AlreadyStarted = false;
- if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
- if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) {
- AlreadyStarted = true;
-
- switch (D->getTagKind()) {
- case TTK_Interface:
- case TTK_Struct: Out << "@ST"; break;
- case TTK_Class: Out << "@CT"; break;
- case TTK_Union: Out << "@UT"; break;
- case TTK_Enum: llvm_unreachable("enum template");
- }
- VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
- } else if (const ClassTemplatePartialSpecializationDecl *PartialSpec
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) {
- AlreadyStarted = true;
-
- switch (D->getTagKind()) {
- case TTK_Interface:
- case TTK_Struct: Out << "@SP"; break;
- case TTK_Class: Out << "@CP"; break;
- case TTK_Union: Out << "@UP"; break;
- case TTK_Enum: llvm_unreachable("enum partial specialization");
- }
- VisitTemplateParameterList(PartialSpec->getTemplateParameters());
- }
- }
-
- if (!AlreadyStarted) {
- switch (D->getTagKind()) {
- case TTK_Interface:
- case TTK_Struct: Out << "@S"; break;
- case TTK_Class: Out << "@C"; break;
- case TTK_Union: Out << "@U"; break;
- case TTK_Enum: Out << "@E"; break;
- }
- }
-
- Out << '@';
- Out.flush();
- assert(Buf.size() > 0);
- const unsigned off = Buf.size() - 1;
-
- if (EmitDeclName(D)) {
- if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {
- Buf[off] = 'A';
- Out << '@' << *TD;
- }
- else
- Buf[off] = 'a';
- }
-
- // For a class template specialization, mangle the template arguments.
- if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
- const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
- Out << '>';
- for (unsigned I = 0, N = Args.size(); I != N; ++I) {
- Out << '#';
- VisitTemplateArgument(Args.get(I));
- }
- }
-}
-
-void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {
- if (ShouldGenerateLocation(D) && GenLoc(D))
- return;
- const DeclContext *DC = D->getDeclContext();
- if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
- Visit(DCN);
- Out << "@T@";
- Out << D->getName();
-}
-
-void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
- GenLoc(D);
- return;
-}
-
-bool USRGenerator::GenLoc(const Decl *D) {
- if (generatedLoc)
- return IgnoreResults;
- generatedLoc = true;
-
- // Guard against null declarations in invalid code.
- if (!D) {
- IgnoreResults = true;
- return true;
- }
-
- // Use the location of canonical decl.
- D = D->getCanonicalDecl();
-
- const SourceManager &SM = Context->getSourceManager();
- SourceLocation L = D->getLocStart();
- if (L.isInvalid()) {
- IgnoreResults = true;
- return true;
- }
- L = SM.getExpansionLoc(L);
- const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
- const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
- if (FE) {
- Out << llvm::sys::path::filename(FE->getName());
- }
- else {
- // This case really isn't interesting.
- IgnoreResults = true;
- return true;
- }
- // Use the offest into the FileID to represent the location. Using
- // a line/column can cause us to look back at the original source file,
- // which is expensive.
- Out << '@' << Decomposed.second;
- return IgnoreResults;
-}
-
-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
- // requirements for USRs might not be the same.
- ASTContext &Ctx = *Context;
-
- do {
- T = Ctx.getCanonicalType(T);
- Qualifiers Q = T.getQualifiers();
- unsigned qVal = 0;
- if (Q.hasConst())
- qVal |= 0x1;
- if (Q.hasVolatile())
- qVal |= 0x2;
- if (Q.hasRestrict())
- qVal |= 0x4;
- if(qVal)
- Out << ((char) ('0' + qVal));
-
- // Mangle in ObjC GC qualifiers?
-
- if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) {
- Out << 'P';
- T = Expansion->getPattern();
- }
-
- if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
- unsigned char c = '\0';
- switch (BT->getKind()) {
- case BuiltinType::Void:
- c = 'v'; break;
- case BuiltinType::Bool:
- c = 'b'; break;
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- c = 'c'; break;
- case BuiltinType::Char16:
- c = 'q'; break;
- case BuiltinType::Char32:
- c = 'w'; break;
- case BuiltinType::UShort:
- c = 's'; break;
- case BuiltinType::UInt:
- c = 'i'; break;
- case BuiltinType::ULong:
- c = 'l'; break;
- case BuiltinType::ULongLong:
- c = 'k'; break;
- case BuiltinType::UInt128:
- c = 'j'; break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- c = 'C'; break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- c = 'W'; break;
- case BuiltinType::Short:
- c = 'S'; break;
- case BuiltinType::Int:
- c = 'I'; break;
- case BuiltinType::Long:
- c = 'L'; break;
- case BuiltinType::LongLong:
- c = 'K'; break;
- case BuiltinType::Int128:
- c = 'J'; break;
- case BuiltinType::Half:
- c = 'h'; break;
- case BuiltinType::Float:
- c = 'f'; break;
- case BuiltinType::Double:
- c = 'd'; break;
- case BuiltinType::LongDouble:
- c = 'D'; break;
- case BuiltinType::NullPtr:
- c = 'n'; break;
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLSampler:
- IgnoreResults = true;
- return;
- case BuiltinType::ObjCId:
- c = 'o'; break;
- case BuiltinType::ObjCClass:
- c = 'O'; break;
- case BuiltinType::ObjCSel:
- c = 'e'; break;
- }
- Out << c;
- return;
- }
-
- // If we have already seen this (non-built-in) type, use a substitution
- // encoding.
- llvm::DenseMap<const Type *, unsigned>::iterator Substitution
- = TypeSubstitutions.find(T.getTypePtr());
- if (Substitution != TypeSubstitutions.end()) {
- Out << 'S' << Substitution->second << '_';
- return;
- } else {
- // Record this as a substitution.
- unsigned Number = TypeSubstitutions.size();
- TypeSubstitutions[T.getTypePtr()] = Number;
- }
-
- if (const PointerType *PT = T->getAs<PointerType>()) {
- Out << '*';
- T = PT->getPointeeType();
- continue;
- }
- if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
- Out << '&';
- T = RT->getPointeeType();
- continue;
- }
- if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
- Out << 'F';
- VisitType(FT->getResultType());
- for (FunctionProtoType::arg_type_iterator
- I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
- VisitType(*I);
- }
- if (FT->isVariadic())
- Out << '.';
- return;
- }
- if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
- Out << 'B';
- T = BT->getPointeeType();
- continue;
- }
- if (const ComplexType *CT = T->getAs<ComplexType>()) {
- Out << '<';
- T = CT->getElementType();
- continue;
- }
- if (const TagType *TT = T->getAs<TagType>()) {
- Out << '$';
- VisitTagDecl(TT->getDecl());
- return;
- }
- if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) {
- Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
- return;
- }
- if (const TemplateSpecializationType *Spec
- = T->getAs<TemplateSpecializationType>()) {
- Out << '>';
- VisitTemplateName(Spec->getTemplateName());
- Out << Spec->getNumArgs();
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- VisitTemplateArgument(Spec->getArg(I));
- return;
- }
-
- // Unhandled type.
- Out << ' ';
- break;
- } while (true);
-}
-
-void USRGenerator::VisitTemplateParameterList(
- const TemplateParameterList *Params) {
- if (!Params)
- return;
- Out << '>' << Params->size();
- for (TemplateParameterList::const_iterator P = Params->begin(),
- PEnd = Params->end();
- P != PEnd; ++P) {
- Out << '#';
- if (isa<TemplateTypeParmDecl>(*P)) {
- if (cast<TemplateTypeParmDecl>(*P)->isParameterPack())
- Out<< 'p';
- Out << 'T';
- continue;
- }
-
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
- if (NTTP->isParameterPack())
- Out << 'p';
- Out << 'N';
- VisitType(NTTP->getType());
- continue;
- }
-
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
- if (TTP->isParameterPack())
- Out << 'p';
- Out << 't';
- VisitTemplateParameterList(TTP->getTemplateParameters());
- }
-}
-
-void USRGenerator::VisitTemplateName(TemplateName Name) {
- if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(Template)) {
- Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
- return;
- }
-
- Visit(Template);
- return;
- }
-
- // FIXME: Visit dependent template names.
-}
-
-void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- break;
-
- case TemplateArgument::Declaration:
- Visit(Arg.getAsDecl());
- break;
-
- case TemplateArgument::NullPtr:
- break;
-
- case TemplateArgument::TemplateExpansion:
- Out << 'P'; // pack expansion of...
- // Fall through
- case TemplateArgument::Template:
- VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());
- break;
-
- case TemplateArgument::Expression:
- // FIXME: Visit expressions.
- break;
-
- case TemplateArgument::Pack:
- Out << 'p' << Arg.pack_size();
- for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end();
- P != PEnd; ++P)
- VisitTemplateArgument(*P);
- break;
-
- case TemplateArgument::Type:
- VisitType(Arg.getAsType());
- break;
-
- case TemplateArgument::Integral:
- Out << 'V';
- VisitType(Arg.getIntegralType());
- Out << Arg.getAsIntegral();
- break;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// General purpose USR generation methods.
-//===----------------------------------------------------------------------===//
-
-void USRGenerator::GenObjCClass(StringRef cls) {
- Out << "objc(cs)" << cls;
-}
-
-void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) {
- Out << "objc(cy)" << cls << '@' << cat;
-}
-
-void USRGenerator::GenObjCIvar(StringRef ivar) {
- Out << '@' << ivar;
-}
-
-void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) {
- Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
-}
-
-void USRGenerator::GenObjCProperty(StringRef prop) {
- Out << "(py)" << prop;
-}
-
-void USRGenerator::GenObjCProtocol(StringRef prot) {
- Out << "objc(pl)" << prot;
-}
+using namespace clang::index;
//===----------------------------------------------------------------------===//
// API hooks.
@@ -805,17 +31,7 @@ static inline StringRef extractUSRSuffix(StringRef s) {
}
bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
- // Don't generate USRs for things with invalid locations.
- if (!D || D->getLocStart().isInvalid())
- return true;
-
- USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(D);
-
- if (UG->ignoreResults())
- return true;
-
- return false;
+ return generateUSRForDecl(D, Buf);
}
extern "C" {
@@ -857,12 +73,10 @@ CXString clang_getCursorUSR(CXCursor C) {
if (!buf)
return cxstring::createEmpty();
- {
- USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(),
- &buf->Data);
- UG << "macro@"
- << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
- }
+ buf->Data += getUSRSpacePrefix();
+ buf->Data += "macro@";
+ buf->Data +=
+ cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
buf->Data.push_back('\0');
return createCXString(buf);
}
@@ -871,46 +85,52 @@ CXString clang_getCursorUSR(CXCursor C) {
}
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
- USRGenerator UG;
- UG << extractUSRSuffix(clang_getCString(classUSR));
- UG->GenObjCIvar(name);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ OS << extractUSRSuffix(clang_getCString(classUSR));
+ generateUSRForObjCIvar(name, OS);
+ return cxstring::createDup(OS.str());
}
CXString clang_constructUSR_ObjCMethod(const char *name,
unsigned isInstanceMethod,
CXString classUSR) {
- USRGenerator UG;
- UG << extractUSRSuffix(clang_getCString(classUSR));
- UG->GenObjCMethod(name, isInstanceMethod);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ OS << extractUSRSuffix(clang_getCString(classUSR));
+ generateUSRForObjCMethod(name, isInstanceMethod, OS);
+ return cxstring::createDup(OS.str());
}
CXString clang_constructUSR_ObjCClass(const char *name) {
- USRGenerator UG;
- UG->GenObjCClass(name);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ generateUSRForObjCClass(name, OS);
+ return cxstring::createDup(OS.str());
}
CXString clang_constructUSR_ObjCProtocol(const char *name) {
- USRGenerator UG;
- UG->GenObjCProtocol(name);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ generateUSRForObjCProtocol(name, OS);
+ return cxstring::createDup(OS.str());
}
CXString clang_constructUSR_ObjCCategory(const char *class_name,
const char *category_name) {
- USRGenerator UG;
- UG->GenObjCCategory(class_name, category_name);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ generateUSRForObjCCategory(class_name, category_name, OS);
+ return cxstring::createDup(OS.str());
}
CXString clang_constructUSR_ObjCProperty(const char *property,
CXString classUSR) {
- USRGenerator UG;
- UG << extractUSRSuffix(clang_getCString(classUSR));
- UG->GenObjCProperty(property);
- return cxstring::createDup(UG.str());
+ SmallString<128> Buf(getUSRSpacePrefix());
+ llvm::raw_svector_ostream OS(Buf);
+ OS << extractUSRSuffix(clang_getCString(classUSR));
+ generateUSRForObjCProperty(property, OS);
+ return cxstring::createDup(OS.str());
}
} // end extern "C"
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index d89e0a41984d..91154cc1c3a0 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -43,11 +43,13 @@
using namespace clang;
-std::string CIndexer::getClangResourcesPath() {
+const std::string &CIndexer::getClangResourcesPath() {
// Did we already compute the path?
if (!ResourcesPath.empty())
- return ResourcesPath.str();
-
+ return ResourcesPath;
+
+ SmallString<128> LibClangPath;
+
// Find the location where this library lives (libclang.dylib).
#ifdef LLVM_ON_WIN32
MEMORY_BASIC_INFORMATION mbi;
@@ -66,85 +68,20 @@ std::string CIndexer::getClangResourcesPath() {
#endif
#endif
- llvm::sys::Path LibClangPath(path);
- LibClangPath.eraseComponent();
+ LibClangPath += llvm::sys::path::parent_path(path);
#else
// This silly cast below avoids a C++ warning.
Dl_info info;
if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
llvm_unreachable("Call to dladdr() failed");
-
- llvm::sys::Path LibClangPath(info.dli_fname);
-
+
// We now have the CIndex directory, locate clang relative to it.
- LibClangPath.eraseComponent();
+ LibClangPath += llvm::sys::path::parent_path(info.dli_fname);
#endif
-
- LibClangPath.appendComponent("clang");
- LibClangPath.appendComponent(CLANG_VERSION_STRING);
-
- // Cache our result.
- ResourcesPath = LibClangPath;
- return LibClangPath.str();
-}
-static llvm::sys::Path GetTemporaryPath() {
- // FIXME: This is lame; sys::Path should provide this function (in particular,
- // it should know how to find the temporary files dir).
- std::string Error;
- const char *TmpDir = ::getenv("TMPDIR");
- if (!TmpDir)
- TmpDir = ::getenv("TEMP");
- if (!TmpDir)
- TmpDir = ::getenv("TMP");
- if (!TmpDir)
- TmpDir = "/tmp";
- llvm::sys::Path P(TmpDir);
- P.appendComponent("remap");
- if (P.makeUnique(false, &Error))
- return llvm::sys::Path("");
+ llvm::sys::path::append(LibClangPath, "clang", CLANG_VERSION_STRING);
- // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
- P.eraseFromDisk(false, 0);
-
- return P;
-}
-
-bool clang::RemapFiles(unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files,
- std::vector<std::string> &RemapArgs,
- std::vector<llvm::sys::Path> &TemporaryFiles) {
- for (unsigned i = 0; i != num_unsaved_files; ++i) {
- // Write the contents of this unsaved file into the temporary file.
- llvm::sys::Path SavedFile(GetTemporaryPath());
- if (SavedFile.empty())
- return true;
-
- std::string ErrorInfo;
- llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary);
- if (!ErrorInfo.empty())
- return true;
-
- OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
- OS.close();
- if (OS.has_error()) {
- SavedFile.eraseFromDisk();
- OS.clear_error();
- return true;
- }
-
- // Remap the file.
- std::string RemapArg = unsaved_files[i].Filename;
- RemapArg += ';';
- RemapArg += SavedFile.str();
- RemapArgs.push_back("-Xclang");
- RemapArgs.push_back("-remap-file");
- RemapArgs.push_back("-Xclang");
- RemapArgs.push_back(RemapArg);
- TemporaryFiles.push_back(SavedFile);
- }
-
- return false;
+ // Cache our result.
+ ResourcesPath = LibClangPath.str();
+ return ResourcesPath;
}
-
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 08162c563e95..95d8115a2eee 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -37,7 +37,7 @@ class CIndexer {
bool DisplayDiagnostics;
unsigned Options; // CXGlobalOptFlags.
- llvm::sys::Path ResourcesPath;
+ std::string ResourcesPath;
public:
CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false),
@@ -62,20 +62,9 @@ public:
}
/// \brief Get the path of the clang resource files.
- std::string getClangResourcesPath();
+ const std::string &getClangResourcesPath();
};
- /**
- * \brief Given a set of "unsaved" files, create temporary files and
- * construct the clang -cc1 argument list needed to perform the remapping.
- *
- * \returns true if an error occurred.
- */
- bool RemapFiles(unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files,
- std::vector<std::string> &RemapArgs,
- std::vector<llvm::sys::Path> &TemporaryFiles);
-
/// \brief Return the current size to request for "safety".
unsigned GetSafetyThreadStackSize();
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index c5a975b63760..b7bde694272c 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -39,11 +39,11 @@ set(SOURCES
Indexing.cpp
IndexingContext.cpp
IndexingContext.h
- SimpleFormatContext.h
../../include/clang-c/Index.h
)
set(LIBRARIES
+ clangIndex
clangARCMigrate
clangRewriteCore
clangRewriteFrontend
@@ -56,7 +56,6 @@ set(LIBRARIES
clangLex
clangTooling
clangBasic
- clangFormat
)
set(GENERATED_HEADERS
@@ -70,6 +69,8 @@ set(GENERATED_HEADERS
ClangStmtNodes
)
+set(EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libclang.exports)
+
if( LLVM_ENABLE_PIC )
set(SHARED_LIBRARY TRUE)
add_clang_library(libclang ${SOURCES})
@@ -92,11 +93,17 @@ if( LLVM_ENABLE_PIC )
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBCLANG_LINK_FLAGS
- "-Wl,-compatibility_version -Wl,1 -Wl,-dead_strip")
+ " -Wl,-compatibility_version -Wl,1 -Wl,-dead_strip")
+ if (DEFINED ${LLVM_SUBMIT_VERSION})
+ set(LIBCLANG_LINK_FLAGS
+ "${LIBCLANG_LINK_FLAGS} -Wl,-current_version -Wl,${LLVM_SUBMIT_VERSION}.${LLVM_SUBMIT_SUBVERSION}")
+ endif()
+
+ set_property(TARGET libclang APPEND_STRING PROPERTY
+ LINK_FLAGS ${LIBCLANG_LINK_FLAGS})
set_target_properties(libclang
PROPERTIES
- LINK_FLAGS "${LIBCLANG_LINK_FLAGS}"
- INSTALL_NAME_DIR "@executable_path/../lib")
+ INSTALL_NAME_DIR "@rpath")
endif()
@@ -105,7 +112,10 @@ else()
set(LIBCLANG_STATIC_TARGET_NAME libclang)
endif()
-if( NOT BUILD_SHARED_LIBS AND NOT WIN32 )
+option(LIBCLANG_BUILD_STATIC
+ "Build libclang as a static library (in addition to a shared one)" OFF)
+
+if( (NOT LLVM_ENABLE_PIC OR LIBCLANG_BUILD_STATIC) AND NOT WIN32 )
add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES})
target_link_libraries(${LIBCLANG_STATIC_TARGET_NAME} ${LIBRARIES})
add_dependencies(${LIBCLANG_STATIC_TARGET_NAME} ${GENERATED_HEADERS} clang-headers)
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 1c127e1589de..2c4f269f9e6e 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -15,17 +15,11 @@
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
-#include "SimpleFormatContext.h"
-#include "clang/AST/CommentCommandTraits.h"
-#include "clang/AST/CommentVisitor.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Format/Format.h"
-#include "clang/Lex/Lexer.h"
+#include "clang/Index/CommentToXML.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
#include <climits>
using namespace clang;
@@ -268,7 +262,7 @@ unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
- if (!PCC || !PCC->isParamIndexValid())
+ if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
return ParamCommandComment::InvalidParamIndex;
return PCC->getParamIndex();
@@ -350,499 +344,23 @@ CXString clang_VerbatimLineComment_getText(CXComment CXC) {
return cxstring::createRef(VLC->getText());
}
-} // end extern "C"
-
//===----------------------------------------------------------------------===//
-// Helpers for converting comment AST to HTML.
+// Converting comments to XML.
//===----------------------------------------------------------------------===//
-namespace {
-
-/// This comparison will sort parameters with valid index by index and
-/// invalid (unresolved) parameters last.
-class ParamCommandCommentCompareIndex {
-public:
- bool operator()(const ParamCommandComment *LHS,
- const ParamCommandComment *RHS) const {
- unsigned LHSIndex = UINT_MAX;
- unsigned RHSIndex = UINT_MAX;
- if (LHS->isParamIndexValid())
- LHSIndex = LHS->getParamIndex();
- if (RHS->isParamIndexValid())
- RHSIndex = RHS->getParamIndex();
-
- return LHSIndex < RHSIndex;
- }
-};
-
-/// This comparison will sort template parameters in the following order:
-/// \li real template parameters (depth = 1) in index order;
-/// \li all other names (depth > 1);
-/// \li unresolved names.
-class TParamCommandCommentComparePosition {
-public:
- bool operator()(const TParamCommandComment *LHS,
- const TParamCommandComment *RHS) const {
- // Sort unresolved names last.
- if (!LHS->isPositionValid())
- return false;
- if (!RHS->isPositionValid())
- return true;
-
- if (LHS->getDepth() > 1)
- return false;
- if (RHS->getDepth() > 1)
- return true;
-
- // Sort template parameters in index order.
- if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
- return LHS->getIndex(0) < RHS->getIndex(0);
-
- // Leave all other names in source order.
- return true;
- }
-};
-
-/// Separate parts of a FullComment.
-struct FullCommentParts {
- /// Take a full comment apart and initialize members accordingly.
- FullCommentParts(const FullComment *C,
- const CommandTraits &Traits);
-
- const BlockContentComment *Brief;
- const BlockContentComment *Headerfile;
- const ParagraphComment *FirstParagraph;
- const BlockCommandComment *Returns;
- SmallVector<const ParamCommandComment *, 8> Params;
- SmallVector<const TParamCommandComment *, 4> TParams;
- SmallVector<const BlockContentComment *, 8> MiscBlocks;
-};
-
-FullCommentParts::FullCommentParts(const FullComment *C,
- const CommandTraits &Traits) :
- Brief(NULL), Headerfile(NULL), FirstParagraph(NULL), Returns(NULL) {
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- const Comment *Child = *I;
- if (!Child)
- continue;
- switch (Child->getCommentKind()) {
- case Comment::NoCommentKind:
- continue;
-
- case Comment::ParagraphCommentKind: {
- const ParagraphComment *PC = cast<ParagraphComment>(Child);
- if (PC->isWhitespace())
- break;
- if (!FirstParagraph)
- FirstParagraph = PC;
-
- MiscBlocks.push_back(PC);
- break;
- }
-
- case Comment::BlockCommandCommentKind: {
- const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
- const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
- if (!Brief && Info->IsBriefCommand) {
- Brief = BCC;
- break;
- }
- if (!Headerfile && Info->IsHeaderfileCommand) {
- Headerfile = BCC;
- break;
- }
- if (!Returns && Info->IsReturnsCommand) {
- Returns = BCC;
- break;
- }
- MiscBlocks.push_back(BCC);
- break;
- }
-
- case Comment::ParamCommandCommentKind: {
- const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
- if (!PCC->hasParamName())
- break;
-
- if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
- break;
-
- Params.push_back(PCC);
- break;
- }
-
- case Comment::TParamCommandCommentKind: {
- const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
- if (!TPCC->hasParamName())
- break;
-
- if (!TPCC->hasNonWhitespaceParagraph())
- break;
-
- TParams.push_back(TPCC);
- break;
- }
-
- case Comment::VerbatimBlockCommentKind:
- MiscBlocks.push_back(cast<BlockCommandComment>(Child));
- break;
-
- case Comment::VerbatimLineCommentKind: {
- const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
- const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
- if (!Info->IsDeclarationCommand)
- MiscBlocks.push_back(VLC);
- break;
- }
-
- case Comment::TextCommentKind:
- case Comment::InlineCommandCommentKind:
- case Comment::HTMLStartTagCommentKind:
- case Comment::HTMLEndTagCommentKind:
- case Comment::VerbatimBlockLineCommentKind:
- case Comment::FullCommentKind:
- llvm_unreachable("AST node of this kind can't be a child of "
- "a FullComment");
- }
- }
-
- // Sort params in order they are declared in the function prototype.
- // Unresolved parameters are put at the end of the list in the same order
- // they were seen in the comment.
- std::stable_sort(Params.begin(), Params.end(),
- ParamCommandCommentCompareIndex());
-
- std::stable_sort(TParams.begin(), TParams.end(),
- TParamCommandCommentComparePosition());
-}
-
-void PrintHTMLStartTagComment(const HTMLStartTagComment *C,
- llvm::raw_svector_ostream &Result) {
- Result << "<" << C->getTagName();
-
- if (C->getNumAttrs() != 0) {
- for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
- Result << " ";
- const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
- Result << Attr.Name;
- if (!Attr.Value.empty())
- Result << "=\"" << Attr.Value << "\"";
- }
- }
-
- if (!C->isSelfClosing())
- Result << ">";
- else
- Result << "/>";
-}
-
-class CommentASTToHTMLConverter :
- public ConstCommentVisitor<CommentASTToHTMLConverter> {
-public:
- /// \param Str accumulator for HTML.
- CommentASTToHTMLConverter(const FullComment *FC,
- SmallVectorImpl<char> &Str,
- const CommandTraits &Traits) :
- FC(FC), Result(Str), Traits(Traits)
- { }
-
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
-
- void visitFullComment(const FullComment *C);
-
- // Helpers.
-
- /// Convert a paragraph that is not a block by itself (an argument to some
- /// command).
- void visitNonStandaloneParagraphComment(const ParagraphComment *C);
-
- void appendToResultWithHTMLEscaping(StringRef S);
-
-private:
- const FullComment *FC;
- /// Output stream for HTML.
- llvm::raw_svector_ostream Result;
-
- const CommandTraits &Traits;
-};
-} // end unnamed namespace
-
-void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
- appendToResultWithHTMLEscaping(C->getText());
-}
-
-void CommentASTToHTMLConverter::visitInlineCommandComment(
- const InlineCommandComment *C) {
- // Nothing to render if no arguments supplied.
- if (C->getNumArgs() == 0)
- return;
-
- // Nothing to render if argument is empty.
- StringRef Arg0 = C->getArgText(0);
- if (Arg0.empty())
- return;
-
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
- appendToResultWithHTMLEscaping(C->getArgText(i));
- Result << " ";
- }
- return;
-
- case InlineCommandComment::RenderBold:
- assert(C->getNumArgs() == 1);
- Result << "<b>";
- appendToResultWithHTMLEscaping(Arg0);
- Result << "</b>";
- return;
- case InlineCommandComment::RenderMonospaced:
- assert(C->getNumArgs() == 1);
- Result << "<tt>";
- appendToResultWithHTMLEscaping(Arg0);
- Result<< "</tt>";
- return;
- case InlineCommandComment::RenderEmphasized:
- assert(C->getNumArgs() == 1);
- Result << "<em>";
- appendToResultWithHTMLEscaping(Arg0);
- Result << "</em>";
- return;
- }
-}
-
-void CommentASTToHTMLConverter::visitHTMLStartTagComment(
- const HTMLStartTagComment *C) {
- PrintHTMLStartTagComment(C, Result);
-}
-
-void CommentASTToHTMLConverter::visitHTMLEndTagComment(
- const HTMLEndTagComment *C) {
- Result << "</" << C->getTagName() << ">";
-}
-
-void CommentASTToHTMLConverter::visitParagraphComment(
- const ParagraphComment *C) {
- if (C->isWhitespace())
- return;
-
- Result << "<p>";
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
- Result << "</p>";
-}
-
-void CommentASTToHTMLConverter::visitBlockCommandComment(
- const BlockCommandComment *C) {
- const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
- if (Info->IsBriefCommand) {
- Result << "<p class=\"para-brief\">";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</p>";
- return;
- }
- if (Info->IsReturnsCommand) {
- Result << "<p class=\"para-returns\">"
- "<span class=\"word-returns\">Returns</span> ";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</p>";
- return;
- }
- // We don't know anything about this command. Just render the paragraph.
- visit(C->getParagraph());
-}
-
-void CommentASTToHTMLConverter::visitParamCommandComment(
- const ParamCommandComment *C) {
- if (C->isParamIndexValid()) {
- Result << "<dt class=\"param-name-index-"
- << C->getParamIndex()
- << "\">";
- appendToResultWithHTMLEscaping(C->getParamName(FC));
- } else {
- Result << "<dt class=\"param-name-index-invalid\">";
- appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
- }
- Result << "</dt>";
-
- if (C->isParamIndexValid()) {
- Result << "<dd class=\"param-descr-index-"
- << C->getParamIndex()
- << "\">";
- } else
- Result << "<dd class=\"param-descr-index-invalid\">";
-
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</dd>";
-}
-
-void CommentASTToHTMLConverter::visitTParamCommandComment(
- const TParamCommandComment *C) {
- if (C->isPositionValid()) {
- if (C->getDepth() == 1)
- Result << "<dt class=\"tparam-name-index-"
- << C->getIndex(0)
- << "\">";
- else
- Result << "<dt class=\"tparam-name-index-other\">";
- appendToResultWithHTMLEscaping(C->getParamName(FC));
- } else {
- Result << "<dt class=\"tparam-name-index-invalid\">";
- appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
- }
-
- Result << "</dt>";
-
- if (C->isPositionValid()) {
- if (C->getDepth() == 1)
- Result << "<dd class=\"tparam-descr-index-"
- << C->getIndex(0)
- << "\">";
- else
- Result << "<dd class=\"tparam-descr-index-other\">";
- } else
- Result << "<dd class=\"tparam-descr-index-invalid\">";
-
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</dd>";
-}
-
-void CommentASTToHTMLConverter::visitVerbatimBlockComment(
- const VerbatimBlockComment *C) {
- unsigned NumLines = C->getNumLines();
- if (NumLines == 0)
- return;
-
- Result << "<pre>";
- for (unsigned i = 0; i != NumLines; ++i) {
- appendToResultWithHTMLEscaping(C->getText(i));
- if (i + 1 != NumLines)
- Result << '\n';
- }
- Result << "</pre>";
-}
-
-void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
- const VerbatimBlockLineComment *C) {
- llvm_unreachable("should not see this AST node");
-}
-
-void CommentASTToHTMLConverter::visitVerbatimLineComment(
- const VerbatimLineComment *C) {
- Result << "<pre>";
- appendToResultWithHTMLEscaping(C->getText());
- Result << "</pre>";
-}
-
-void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C, Traits);
-
- bool FirstParagraphIsBrief = false;
- if (Parts.Headerfile)
- visit(Parts.Headerfile);
- if (Parts.Brief)
- visit(Parts.Brief);
- else if (Parts.FirstParagraph) {
- Result << "<p class=\"para-brief\">";
- visitNonStandaloneParagraphComment(Parts.FirstParagraph);
- Result << "</p>";
- FirstParagraphIsBrief = true;
- }
-
- for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
- const Comment *C = Parts.MiscBlocks[i];
- if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
- continue;
- visit(C);
- }
-
- if (Parts.TParams.size() != 0) {
- Result << "<dl>";
- for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
- visit(Parts.TParams[i]);
- Result << "</dl>";
- }
-
- if (Parts.Params.size() != 0) {
- Result << "<dl>";
- for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
- visit(Parts.Params[i]);
- Result << "</dl>";
- }
-
- if (Parts.Returns)
- visit(Parts.Returns);
-
- Result.flush();
-}
-
-void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
- const ParagraphComment *C) {
- if (!C)
- return;
-
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
-}
-
-void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
- for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
- const char C = *I;
- switch (C) {
- case '&':
- Result << "&amp;";
- break;
- case '<':
- Result << "&lt;";
- break;
- case '>':
- Result << "&gt;";
- break;
- case '"':
- Result << "&quot;";
- break;
- case '\'':
- Result << "&#39;";
- break;
- case '/':
- Result << "&#47;";
- break;
- default:
- Result << C;
- break;
- }
- }
-}
-
-extern "C" {
-
CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
if (!HTC)
return cxstring::createNull();
- SmallString<128> HTML;
- CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
- Converter.visit(HTC);
- return cxstring::createDup(HTML.str());
+ CXTranslationUnit TU = CXC.TranslationUnit;
+ if (!TU->CommentToXML)
+ TU->CommentToXML = new clang::index::CommentToXMLConverter();
+
+ SmallString<128> Text;
+ TU->CommentToXML->convertHTMLTagNodeToText(
+ HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
+ return cxstring::createDup(Text.str());
}
CXString clang_FullComment_getAsHTML(CXComment CXC) {
@@ -850,596 +368,28 @@ CXString clang_FullComment_getAsHTML(CXComment CXC) {
if (!FC)
return cxstring::createNull();
+ CXTranslationUnit TU = CXC.TranslationUnit;
+ if (!TU->CommentToXML)
+ TU->CommentToXML = new clang::index::CommentToXMLConverter();
+
SmallString<1024> HTML;
- CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
- Converter.visit(FC);
+ TU->CommentToXML
+ ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
return cxstring::createDup(HTML.str());
}
-} // end extern "C"
-
-namespace {
-class CommentASTToXMLConverter :
- public ConstCommentVisitor<CommentASTToXMLConverter> {
-public:
- /// \param Str accumulator for XML.
- CommentASTToXMLConverter(const FullComment *FC,
- SmallVectorImpl<char> &Str,
- const CommandTraits &Traits,
- const SourceManager &SM,
- SimpleFormatContext &SFC,
- unsigned FUID) :
- FC(FC), Result(Str), Traits(Traits), SM(SM),
- FormatRewriterContext(SFC),
- FormatInMemoryUniqueId(FUID) { }
-
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
-
- void appendParagraphCommentWithKind(const ParagraphComment *C,
- StringRef Kind);
-
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
-
- void visitFullComment(const FullComment *C);
-
- // Helpers.
- void appendToResultWithXMLEscaping(StringRef S);
-
- void formatTextOfDeclaration(const DeclInfo *DI,
- SmallString<128> &Declaration);
-
-private:
- const FullComment *FC;
-
- /// Output stream for XML.
- llvm::raw_svector_ostream Result;
-
- const CommandTraits &Traits;
- const SourceManager &SM;
- SimpleFormatContext &FormatRewriterContext;
- unsigned FormatInMemoryUniqueId;
-};
-
-void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
- SmallVectorImpl<char> &Str) {
- ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
- const LangOptions &LangOpts = Context.getLangOpts();
- llvm::raw_svector_ostream OS(Str);
- PrintingPolicy PPolicy(LangOpts);
- PPolicy.PolishForDeclaration = true;
- PPolicy.TerseOutput = true;
- ThisDecl->CurrentDecl->print(OS, PPolicy,
- /*Indentation*/0, /*PrintInstantiation*/false);
-}
-
-void CommentASTToXMLConverter::formatTextOfDeclaration(
- const DeclInfo *DI,
- SmallString<128> &Declaration) {
- // FIXME. formatting API expects null terminated input string.
- // There might be more efficient way of doing this.
- std::string StringDecl = Declaration.str();
-
- // Formatter specific code.
- // Form a unique in memory buffer name.
- SmallString<128> filename;
- filename += "xmldecl";
- filename += llvm::utostr(FormatInMemoryUniqueId);
- filename += ".xd";
- FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
- SourceLocation Start =
- FormatRewriterContext.Sources.getLocForStartOfFile(ID).getLocWithOffset(0);
- unsigned Length = Declaration.size();
-
- std::vector<CharSourceRange>
- Ranges(1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
- ASTContext &Context = DI->CurrentDecl->getASTContext();
- const LangOptions &LangOpts = Context.getLangOpts();
- Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
- FormatRewriterContext.Sources, LangOpts);
- tooling::Replacements Replace =
- reformat(format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
- applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
- Declaration = FormatRewriterContext.getRewrittenText(ID);
-}
-
-} // end unnamed namespace
-
-void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
- appendToResultWithXMLEscaping(C->getText());
-}
-
-void CommentASTToXMLConverter::visitInlineCommandComment(const InlineCommandComment *C) {
- // Nothing to render if no arguments supplied.
- if (C->getNumArgs() == 0)
- return;
-
- // Nothing to render if argument is empty.
- StringRef Arg0 = C->getArgText(0);
- if (Arg0.empty())
- return;
-
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
- appendToResultWithXMLEscaping(C->getArgText(i));
- Result << " ";
- }
- return;
- case InlineCommandComment::RenderBold:
- assert(C->getNumArgs() == 1);
- Result << "<bold>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</bold>";
- return;
- case InlineCommandComment::RenderMonospaced:
- assert(C->getNumArgs() == 1);
- Result << "<monospaced>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</monospaced>";
- return;
- case InlineCommandComment::RenderEmphasized:
- assert(C->getNumArgs() == 1);
- Result << "<emphasized>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</emphasized>";
- return;
- }
-}
-
-void CommentASTToXMLConverter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
- Result << "<rawHTML><![CDATA[";
- PrintHTMLStartTagComment(C, Result);
- Result << "]]></rawHTML>";
-}
-
-void CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
-}
-
-void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
- appendParagraphCommentWithKind(C, StringRef());
-}
-
-void CommentASTToXMLConverter::appendParagraphCommentWithKind(
- const ParagraphComment *C,
- StringRef ParagraphKind) {
- if (C->isWhitespace())
- return;
-
- if (ParagraphKind.empty())
- Result << "<Para>";
- else
- Result << "<Para kind=\"" << ParagraphKind << "\">";
-
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
- Result << "</Para>";
-}
-
-void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandComment *C) {
- StringRef ParagraphKind;
-
- switch (C->getCommandID()) {
- case CommandTraits::KCI_attention:
- case CommandTraits::KCI_author:
- case CommandTraits::KCI_authors:
- case CommandTraits::KCI_bug:
- case CommandTraits::KCI_copyright:
- case CommandTraits::KCI_date:
- case CommandTraits::KCI_invariant:
- case CommandTraits::KCI_note:
- case CommandTraits::KCI_post:
- case CommandTraits::KCI_pre:
- case CommandTraits::KCI_remark:
- case CommandTraits::KCI_remarks:
- case CommandTraits::KCI_sa:
- case CommandTraits::KCI_see:
- case CommandTraits::KCI_since:
- case CommandTraits::KCI_todo:
- case CommandTraits::KCI_version:
- case CommandTraits::KCI_warning:
- ParagraphKind = C->getCommandName(Traits);
- default:
- break;
- }
-
- appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
-}
-
-void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
- Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->isParamIndexValid() ? C->getParamName(FC)
- : C->getParamNameAsWritten());
- Result << "</Name>";
-
- if (C->isParamIndexValid())
- Result << "<Index>" << C->getParamIndex() << "</Index>";
-
- Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
- switch (C->getDirection()) {
- case ParamCommandComment::In:
- Result << "in";
- break;
- case ParamCommandComment::Out:
- Result << "out";
- break;
- case ParamCommandComment::InOut:
- Result << "in,out";
- break;
- }
- Result << "</Direction><Discussion>";
- visit(C->getParagraph());
- Result << "</Discussion></Parameter>";
-}
-
-void CommentASTToXMLConverter::visitTParamCommandComment(
- const TParamCommandComment *C) {
- Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
- : C->getParamNameAsWritten());
- Result << "</Name>";
-
- if (C->isPositionValid() && C->getDepth() == 1) {
- Result << "<Index>" << C->getIndex(0) << "</Index>";
- }
-
- Result << "<Discussion>";
- visit(C->getParagraph());
- Result << "</Discussion></Parameter>";
-}
-
-void CommentASTToXMLConverter::visitVerbatimBlockComment(
- const VerbatimBlockComment *C) {
- unsigned NumLines = C->getNumLines();
- if (NumLines == 0)
- return;
-
- switch (C->getCommandID()) {
- case CommandTraits::KCI_code:
- Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
- break;
- default:
- Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
- break;
- }
- for (unsigned i = 0; i != NumLines; ++i) {
- appendToResultWithXMLEscaping(C->getText(i));
- if (i + 1 != NumLines)
- Result << '\n';
- }
- Result << "</Verbatim>";
-}
-
-void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
- const VerbatimBlockLineComment *C) {
- llvm_unreachable("should not see this AST node");
-}
-
-void CommentASTToXMLConverter::visitVerbatimLineComment(
- const VerbatimLineComment *C) {
- Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
- appendToResultWithXMLEscaping(C->getText());
- Result << "</Verbatim>";
-}
-
-void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C, Traits);
-
- const DeclInfo *DI = C->getDeclInfo();
- StringRef RootEndTag;
- if (DI) {
- switch (DI->getKind()) {
- case DeclInfo::OtherKind:
- RootEndTag = "</Other>";
- Result << "<Other";
- break;
- case DeclInfo::FunctionKind:
- RootEndTag = "</Function>";
- Result << "<Function";
- switch (DI->TemplateKind) {
- case DeclInfo::NotTemplate:
- break;
- case DeclInfo::Template:
- Result << " templateKind=\"template\"";
- break;
- case DeclInfo::TemplateSpecialization:
- Result << " templateKind=\"specialization\"";
- break;
- case DeclInfo::TemplatePartialSpecialization:
- llvm_unreachable("partial specializations of functions "
- "are not allowed in C++");
- }
- if (DI->IsInstanceMethod)
- Result << " isInstanceMethod=\"1\"";
- if (DI->IsClassMethod)
- Result << " isClassMethod=\"1\"";
- break;
- case DeclInfo::ClassKind:
- RootEndTag = "</Class>";
- Result << "<Class";
- switch (DI->TemplateKind) {
- case DeclInfo::NotTemplate:
- break;
- case DeclInfo::Template:
- Result << " templateKind=\"template\"";
- break;
- case DeclInfo::TemplateSpecialization:
- Result << " templateKind=\"specialization\"";
- break;
- case DeclInfo::TemplatePartialSpecialization:
- Result << " templateKind=\"partialSpecialization\"";
- break;
- }
- break;
- case DeclInfo::VariableKind:
- RootEndTag = "</Variable>";
- Result << "<Variable";
- break;
- case DeclInfo::NamespaceKind:
- RootEndTag = "</Namespace>";
- Result << "<Namespace";
- break;
- case DeclInfo::TypedefKind:
- RootEndTag = "</Typedef>";
- Result << "<Typedef";
- break;
- case DeclInfo::EnumKind:
- RootEndTag = "</Enum>";
- Result << "<Enum";
- break;
- }
-
- {
- // Print line and column number.
- SourceLocation Loc = DI->CurrentDecl->getLocation();
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
-
- if (!FID.isInvalid()) {
- if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
- Result << " file=\"";
- appendToResultWithXMLEscaping(FE->getName());
- Result << "\"";
- }
- Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
- << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
- << "\"";
- }
- }
-
- // Finish the root tag.
- Result << ">";
-
- bool FoundName = false;
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
- if (DeclarationName DeclName = ND->getDeclName()) {
- Result << "<Name>";
- std::string Name = DeclName.getAsString();
- appendToResultWithXMLEscaping(Name);
- FoundName = true;
- Result << "</Name>";
- }
- }
- if (!FoundName)
- Result << "<Name>&lt;anonymous&gt;</Name>";
-
- {
- // Print USR.
- SmallString<128> USR;
- cxcursor::getDeclCursorUSR(DI->CommentDecl, USR);
- if (!USR.empty()) {
- Result << "<USR>";
- appendToResultWithXMLEscaping(USR);
- Result << "</USR>";
- }
- }
- } else {
- // No DeclInfo -- just emit some root tag and name tag.
- RootEndTag = "</Other>";
- Result << "<Other><Name>unknown</Name>";
- }
-
- if (Parts.Headerfile) {
- Result << "<Headerfile>";
- visit(Parts.Headerfile);
- Result << "</Headerfile>";
- }
-
- {
- // Pretty-print the declaration.
- Result << "<Declaration>";
- SmallString<128> Declaration;
- getSourceTextOfDeclaration(DI, Declaration);
- formatTextOfDeclaration(DI, Declaration);
- appendToResultWithXMLEscaping(Declaration);
-
- Result << "</Declaration>";
- }
-
- bool FirstParagraphIsBrief = false;
- if (Parts.Brief) {
- Result << "<Abstract>";
- visit(Parts.Brief);
- Result << "</Abstract>";
- } else if (Parts.FirstParagraph) {
- Result << "<Abstract>";
- visit(Parts.FirstParagraph);
- Result << "</Abstract>";
- FirstParagraphIsBrief = true;
- }
-
- if (Parts.TParams.size() != 0) {
- Result << "<TemplateParameters>";
- for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
- visit(Parts.TParams[i]);
- Result << "</TemplateParameters>";
- }
-
- if (Parts.Params.size() != 0) {
- Result << "<Parameters>";
- for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
- visit(Parts.Params[i]);
- Result << "</Parameters>";
- }
-
- if (Parts.Returns) {
- Result << "<ResultDiscussion>";
- visit(Parts.Returns);
- Result << "</ResultDiscussion>";
- }
-
- if (DI->CommentDecl->hasAttrs()) {
- const AttrVec &Attrs = DI->CommentDecl->getAttrs();
- for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
- const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
- if (!AA) {
- if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
- if (DA->getMessage().empty())
- Result << "<Deprecated/>";
- else {
- Result << "<Deprecated>";
- appendToResultWithXMLEscaping(DA->getMessage());
- Result << "</Deprecated>";
- }
- }
- else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
- if (UA->getMessage().empty())
- Result << "<Unavailable/>";
- else {
- Result << "<Unavailable>";
- appendToResultWithXMLEscaping(UA->getMessage());
- Result << "</Unavailable>";
- }
- }
- continue;
- }
-
- // 'availability' attribute.
- Result << "<Availability";
- StringRef Distribution;
- if (AA->getPlatform()) {
- Distribution = AvailabilityAttr::getPrettyPlatformName(
- AA->getPlatform()->getName());
- if (Distribution.empty())
- Distribution = AA->getPlatform()->getName();
- }
- Result << " distribution=\"" << Distribution << "\">";
- VersionTuple IntroducedInVersion = AA->getIntroduced();
- if (!IntroducedInVersion.empty()) {
- Result << "<IntroducedInVersion>"
- << IntroducedInVersion.getAsString()
- << "</IntroducedInVersion>";
- }
- VersionTuple DeprecatedInVersion = AA->getDeprecated();
- if (!DeprecatedInVersion.empty()) {
- Result << "<DeprecatedInVersion>"
- << DeprecatedInVersion.getAsString()
- << "</DeprecatedInVersion>";
- }
- VersionTuple RemovedAfterVersion = AA->getObsoleted();
- if (!RemovedAfterVersion.empty()) {
- Result << "<RemovedAfterVersion>"
- << RemovedAfterVersion.getAsString()
- << "</RemovedAfterVersion>";
- }
- StringRef DeprecationSummary = AA->getMessage();
- if (!DeprecationSummary.empty()) {
- Result << "<DeprecationSummary>";
- appendToResultWithXMLEscaping(DeprecationSummary);
- Result << "</DeprecationSummary>";
- }
- if (AA->getUnavailable())
- Result << "<Unavailable/>";
- Result << "</Availability>";
- }
- }
-
- {
- bool StartTagEmitted = false;
- for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
- const Comment *C = Parts.MiscBlocks[i];
- if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
- continue;
- if (!StartTagEmitted) {
- Result << "<Discussion>";
- StartTagEmitted = true;
- }
- visit(C);
- }
- if (StartTagEmitted)
- Result << "</Discussion>";
- }
-
- Result << RootEndTag;
-
- Result.flush();
-}
-
-void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
- for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
- const char C = *I;
- switch (C) {
- case '&':
- Result << "&amp;";
- break;
- case '<':
- Result << "&lt;";
- break;
- case '>':
- Result << "&gt;";
- break;
- case '"':
- Result << "&quot;";
- break;
- case '\'':
- Result << "&apos;";
- break;
- default:
- Result << C;
- break;
- }
- }
-}
-
-extern "C" {
-
CXString clang_FullComment_getAsXML(CXComment CXC) {
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
if (!FC)
return cxstring::createNull();
- ASTContext &Context = FC->getDeclInfo()->CurrentDecl->getASTContext();
+
CXTranslationUnit TU = CXC.TranslationUnit;
- SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
-
- if (!TU->FormatContext) {
- TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
- } else if ((TU->FormatInMemoryUniqueId % 1000) == 0) {
- // Delete after some number of iterators, so the buffers don't grow
- // too large.
- delete TU->FormatContext;
- TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
- }
+ if (!TU->CommentToXML)
+ TU->CommentToXML = new clang::index::CommentToXMLConverter();
SmallString<1024> XML;
- CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM,
- *TU->FormatContext,
- TU->FormatInMemoryUniqueId++);
- Converter.visit(FC);
+ TU->CommentToXML
+ ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
return cxstring::createDup(XML.str());
}
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index 0780a65e76b6..1e2561d585ea 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -27,20 +27,20 @@ namespace comments {
namespace cxcomment {
-inline CXComment createCXComment(const comments::Comment *C,
- CXTranslationUnit TU) {
+static inline CXComment createCXComment(const comments::Comment *C,
+ CXTranslationUnit TU) {
CXComment Result;
Result.ASTNode = C;
Result.TranslationUnit = TU;
return Result;
}
-inline const comments::Comment *getASTNode(CXComment CXC) {
+static inline const comments::Comment *getASTNode(CXComment CXC) {
return static_cast<const comments::Comment *>(CXC.ASTNode);
}
template<typename T>
-inline const T *getASTNodeAs(CXComment CXC) {
+static inline const T *getASTNodeAs(CXComment CXC) {
const comments::Comment *C = getASTNode(CXC);
if (!C)
return NULL;
@@ -48,11 +48,11 @@ inline const T *getASTNodeAs(CXComment CXC) {
return dyn_cast<T>(C);
}
-inline ASTContext &getASTContext(CXComment CXC) {
+static inline ASTContext &getASTContext(CXComment CXC) {
return cxtu::getASTUnit(CXC.TranslationUnit)->getASTContext();
}
-inline comments::CommandTraits &getCommandTraits(CXComment CXC) {
+static inline comments::CommandTraits &getCommandTraits(CXComment CXC) {
return getASTContext(CXC).getCommentCommandTraits();
}
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
index e35ac27f7940..433caecd38a6 100644
--- a/tools/libclang/CXCompilationDatabase.cpp
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -1,6 +1,7 @@
#include "clang-c/CXCompilationDatabase.h"
#include "CXString.h"
#include "clang/Tooling/CompilationDatabase.h"
+#include <cstdio>
using namespace clang;
using namespace clang::tooling;
@@ -135,5 +136,41 @@ clang_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg)
return cxstring::createRef(Cmd->CommandLine[Arg].c_str());
}
+unsigned
+clang_CompileCommand_getNumMappedSources(CXCompileCommand CCmd)
+{
+ if (!CCmd)
+ return 0;
+
+ return static_cast<CompileCommand *>(CCmd)->MappedSources.size();
+}
+
+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());
+}
+
+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());
+}
} // end: extern "C"
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 2cdb71bb0224..c75c061cf4c3 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -18,6 +18,7 @@
#include "CXString.h"
#include "CXType.h"
#include "clang-c/Index.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -48,6 +49,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::Override: return CXCursor_CXXOverrideAttr;
case attr::Annotate: return CXCursor_AnnotateAttr;
case attr::AsmLabel: return CXCursor_AsmLabelAttr;
+ case attr::Packed: return CXCursor_PackedAttr;
}
return CXCursor_UnexposedAttr;
@@ -75,7 +77,7 @@ CXCursor cxcursor::MakeCXCursor(const Decl *D, CXTranslationUnit TU,
RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
SmallVector<SourceLocation, 16> SelLocs;
cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs);
- SmallVector<SourceLocation, 16>::iterator
+ SmallVectorImpl<SourceLocation>::iterator
I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
if (I != SelLocs.end())
SelectorIdIndex = I - SelLocs.begin();
@@ -216,6 +218,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass:
+ case Stmt::CXXStdInitializerListExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXUuidofExprClass:
case Stmt::ChooseExprClass:
@@ -231,6 +234,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
+ case Stmt::ConvertVectorExprClass:
case Stmt::UnaryExprOrTypeTraitExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::VAArgExprClass:
@@ -492,7 +496,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
SmallVector<SourceLocation, 16> SelLocs;
cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs);
- SmallVector<SourceLocation, 16>::iterator
+ SmallVectorImpl<SourceLocation>::iterator
I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
if (I != SelLocs.end())
SelectorIdIndex = I - SelLocs.begin();
@@ -504,6 +508,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::MSDependentExistsStmtClass:
K = CXCursor_UnexposedStmt;
break;
+ case Stmt::OMPParallelDirectiveClass:
+ K = CXCursor_OMPParallelDirective;
+ break;
+
}
CXCursor C = { K, 0, { Parent, S, TU } };
@@ -836,7 +844,7 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVector<const NamedDecl *, 8> OverDecls;
D->getASTContext().getOverriddenMethods(D, OverDecls);
- for (SmallVector<const NamedDecl *, 8>::iterator
+ for (SmallVectorImpl<const NamedDecl *>::iterator
I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) {
overridden.push_back(MakeCXCursor(*I, TU));
}
diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp
index b7c7622c66b2..73711772fc01 100644
--- a/tools/libclang/CXSourceLocation.cpp
+++ b/tools/libclang/CXSourceLocation.cpp
@@ -124,6 +124,8 @@ CXSourceLocation clang_getLocation(CXTranslationUnit TU,
unsigned column) {
if (!TU || !file)
return clang_getNullLocation();
+ if (line == 0 || column == 0)
+ return clang_getNullLocation();
LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
@@ -209,6 +211,17 @@ int clang_Location_isInSystemHeader(CXSourceLocation location) {
return SM.isInSystemHeader(Loc);
}
+int clang_Location_isFromMainFile(CXSourceLocation location) {
+ const SourceLocation Loc =
+ SourceLocation::getFromRawEncoding(location.int_data);
+ if (Loc.isInvalid())
+ return 0;
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ return SM.isWrittenInMainFile(Loc);
+}
+
void clang_getExpansionLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
@@ -255,7 +268,7 @@ void clang_getPresumedLocation(CXSourceLocation location,
CXString *filename,
unsigned *line,
unsigned *column) {
-
+
if (!isASTUnitSourceLocation(location)) {
// Other SourceLocation implementations do not support presumed locations
// at this time.
@@ -265,20 +278,22 @@ void clang_getPresumedLocation(CXSourceLocation location,
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
- if (!location.ptr_data[0] || Loc.isInvalid())
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
createNullLocation(filename, line, column);
- else {
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
-
- if (filename)
- *filename = cxstring::createRef(PreLoc.getFilename());
- if (line)
- *line = PreLoc.getLine();
- if (column)
- *column = PreLoc.getColumn();
+ return;
}
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager *>(location.ptr_data[0]);
+ PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
+ if (PreLoc.isInvalid()) {
+ createNullLocation(filename, line, column);
+ return;
+ }
+
+ if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
+ if (line) *line = PreLoc.getLine();
+ if (column) *column = PreLoc.getColumn();
}
void clang_getInstantiationLocation(CXSourceLocation location,
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index bdc171cff666..c0014c0c8f13 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -20,7 +20,9 @@
namespace clang {
class ASTUnit;
class CIndexer;
- class SimpleFormatContext;
+namespace index {
+class CommentToXMLConverter;
+} // namespace index
} // namespace clang
struct CXTranslationUnitImpl {
@@ -29,8 +31,7 @@ struct CXTranslationUnitImpl {
clang::cxstring::CXStringPool *StringPool;
void *Diagnostics;
void *OverridenCursorsPool;
- clang::SimpleFormatContext *FormatContext;
- unsigned FormatInMemoryUniqueId;
+ clang::index::CommentToXMLConverter *CommentToXML;
};
namespace clang {
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 148241597a33..1e2cb1898462 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -85,7 +85,11 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(FunctionNoProto);
TKCASE(FunctionProto);
TKCASE(ConstantArray);
+ TKCASE(IncompleteArray);
+ TKCASE(VariableArray);
+ TKCASE(DependentSizedArray);
TKCASE(Vector);
+ TKCASE(MemberPointer);
default:
return CXType_Unexposed;
}
@@ -107,6 +111,11 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
else if (Ctx.isObjCSelType(UnqualT))
TK = CXType_ObjCSel;
}
+
+ /* Handle decayed types as the original type */
+ if (const DecayedType *DT = T->getAs<DecayedType>()) {
+ return MakeCXType(DT->getOriginalType(), TU);
+ }
}
if (TK == CXType_Invalid)
TK = GetTypeKind(T);
@@ -357,6 +366,9 @@ CXType clang_getPointeeType(CXType CT) {
case Type::ObjCObjectPointer:
T = cast<ObjCObjectPointerType>(TP)->getPointeeType();
break;
+ case Type::MemberPointer:
+ T = cast<MemberPointerType>(TP)->getPointeeType();
+ break;
default:
T = QualType();
break;
@@ -466,7 +478,11 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(FunctionNoProto);
TKIND(FunctionProto);
TKIND(ConstantArray);
+ TKIND(IncompleteArray);
+ TKIND(VariableArray);
+ TKIND(DependentSizedArray);
TKIND(Vector);
+ TKIND(MemberPointer);
}
#undef TKIND
return cxstring::createRef(s);
@@ -498,12 +514,13 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
if (const FunctionType *FD = T->getAs<FunctionType>()) {
#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
switch (FD->getCallConv()) {
- TCALLINGCONV(Default);
TCALLINGCONV(C);
TCALLINGCONV(X86StdCall);
TCALLINGCONV(X86FastCall);
TCALLINGCONV(X86ThisCall);
TCALLINGCONV(X86Pascal);
+ TCALLINGCONV(X86_64Win64);
+ TCALLINGCONV(X86_64SysV);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
TCALLINGCONV(PnaclCall);
@@ -590,6 +607,15 @@ CXType clang_getElementType(CXType CT) {
case Type::ConstantArray:
ET = cast<ConstantArrayType> (TP)->getElementType();
break;
+ case Type::IncompleteArray:
+ ET = cast<IncompleteArrayType> (TP)->getElementType();
+ break;
+ case Type::VariableArray:
+ ET = cast<VariableArrayType> (TP)->getElementType();
+ break;
+ case Type::DependentSizedArray:
+ ET = cast<DependentSizedArrayType> (TP)->getElementType();
+ break;
case Type::Vector:
ET = cast<VectorType> (TP)->getElementType();
break;
@@ -633,6 +659,15 @@ CXType clang_getArrayElementType(CXType CT) {
case Type::ConstantArray:
ET = cast<ConstantArrayType> (TP)->getElementType();
break;
+ case Type::IncompleteArray:
+ ET = cast<IncompleteArrayType> (TP)->getElementType();
+ break;
+ case Type::VariableArray:
+ ET = cast<VariableArrayType> (TP)->getElementType();
+ break;
+ case Type::DependentSizedArray:
+ ET = cast<DependentSizedArrayType> (TP)->getElementType();
+ break;
default:
break;
}
@@ -677,6 +712,17 @@ long long clang_Type_getAlignOf(CXType T) {
return Ctx.getTypeAlignInChars(QT).getQuantity();
}
+CXType clang_Type_getClassType(CXType CT) {
+ QualType ET = QualType();
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP && TP->getTypeClass() == Type::MemberPointer) {
+ ET = QualType(cast<MemberPointerType> (TP)->getClass(), 0);
+ }
+ return MakeCXType(ET, GetTU(CT));
+}
+
long long clang_Type_getSizeOf(CXType T) {
if (T.kind == CXType_Invalid)
return CXTypeLayoutError_Invalid;
@@ -733,11 +779,13 @@ long long clang_Type_getOffsetOf(CXType PT, const char *S) {
return CXTypeLayoutError_Invalid;
const RecordDecl *RD =
dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));
- if (!RD)
+ if (!RD || RD->isInvalidDecl())
return CXTypeLayoutError_Invalid;
RD = RD->getDefinition();
if (!RD)
return CXTypeLayoutError_Incomplete;
+ if (RD->isInvalidDecl())
+ return CXTypeLayoutError_Invalid;
QualType RT = GetQualType(PT);
if (RT->isIncompleteType())
return CXTypeLayoutError_Incomplete;
@@ -768,6 +816,24 @@ long long clang_Type_getOffsetOf(CXType PT, const char *S) {
return CXTypeLayoutError_InvalidFieldName;
}
+enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T) {
+ QualType QT = GetQualType(T);
+ if (QT.isNull())
+ return CXRefQualifier_None;
+ const FunctionProtoType *FD = QT->getAs<FunctionProtoType>();
+ if (!FD)
+ return CXRefQualifier_None;
+ switch (FD->getRefQualifier()) {
+ case RQ_None:
+ return CXRefQualifier_None;
+ case RQ_LValue:
+ return CXRefQualifier_LValue;
+ case RQ_RValue:
+ return CXRefQualifier_RValue;
+ }
+ return CXRefQualifier_None;
+}
+
unsigned clang_Cursor_isBitField(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index 02ab885e62f0..e08a3461e822 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -153,9 +153,11 @@ public:
if (C.capturesThis())
return true;
- if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ if (C.capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(),
Parent, ParentDC);
+
+ // FIXME: Lambda init-captures.
return true;
}
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
index 756001c3c124..89feb96d48e7 100644
--- a/tools/libclang/IndexDecl.cpp
+++ b/tools/libclang/IndexDecl.cpp
@@ -22,6 +22,15 @@ public:
explicit IndexingDeclVisitor(IndexingContext &indexCtx)
: IndexCtx(indexCtx) { }
+ /// \brief Returns true if the given method has been defined explicitly by the
+ /// user.
+ static bool hasUserDefined(const ObjCMethodDecl *D,
+ const ObjCImplDecl *Container) {
+ const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
+ D->isInstanceMethod());
+ return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
+ }
+
void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = 0) {
if (!Parent) Parent = D;
@@ -234,12 +243,14 @@ public:
}
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
- if (MD->isPropertyAccessor())
+ if (MD->isPropertyAccessor() &&
+ !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
- if (MD->isPropertyAccessor())
+ if (MD->isPropertyAccessor() &&
+ !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 15786acb8b3b..99fcdb692add 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -31,6 +31,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
+#include <cstdio>
using namespace clang;
using namespace cxtu;
@@ -88,25 +89,23 @@ public:
/// #3 is identified as the location of "#ifdef CAKE"
///
class PPRegion {
- ino_t ino;
+ llvm::sys::fs::UniqueID UniqueID;
time_t ModTime;
- dev_t dev;
unsigned Offset;
public:
- PPRegion() : ino(), ModTime(), dev(), Offset() {}
- PPRegion(dev_t dev, ino_t ino, unsigned offset, time_t modTime)
- : ino(ino), ModTime(modTime), dev(dev), Offset(offset) {}
+ PPRegion() : UniqueID(0, 0), ModTime(), Offset() {}
+ PPRegion(llvm::sys::fs::UniqueID UniqueID, unsigned offset, time_t modTime)
+ : UniqueID(UniqueID), ModTime(modTime), Offset(offset) {}
- ino_t getIno() const { return ino; }
- dev_t getDev() const { return dev; }
+ const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
unsigned getOffset() const { return Offset; }
time_t getModTime() const { return ModTime; }
bool isInvalid() const { return *this == PPRegion(); }
friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) {
- return lhs.dev == rhs.dev && lhs.ino == rhs.ino &&
- lhs.Offset == rhs.Offset && lhs.ModTime == rhs.ModTime;
+ return lhs.UniqueID == rhs.UniqueID && lhs.Offset == rhs.Offset &&
+ lhs.ModTime == rhs.ModTime;
}
};
@@ -122,16 +121,17 @@ namespace llvm {
template <>
struct DenseMapInfo<PPRegion> {
static inline PPRegion getEmptyKey() {
- return PPRegion(0, 0, unsigned(-1), 0);
+ return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-1), 0);
}
static inline PPRegion getTombstoneKey() {
- return PPRegion(0, 0, unsigned(-2), 0);
+ return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-2), 0);
}
static unsigned getHashValue(const PPRegion &S) {
llvm::FoldingSetNodeID ID;
- ID.AddInteger(S.getIno());
- ID.AddInteger(S.getDev());
+ const llvm::sys::fs::UniqueID &UniqueID = S.getUniqueID();
+ ID.AddInteger(UniqueID.getFile());
+ ID.AddInteger(UniqueID.getDevice());
ID.AddInteger(S.getOffset());
ID.AddInteger(S.getModTime());
return ID.ComputeHash();
@@ -208,9 +208,10 @@ private:
PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) {
SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc);
if (RegionLoc.isInvalid()) {
- if (isParsedOnceInclude(FE))
- return PPRegion(FE->getDevice(), FE->getInode(), 0,
- FE->getModificationTime());
+ if (isParsedOnceInclude(FE)) {
+ const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
+ return PPRegion(ID, 0, FE->getModificationTime());
+ }
return PPRegion();
}
@@ -221,14 +222,15 @@ private:
llvm::tie(RegionFID, RegionOffset) = SM.getDecomposedLoc(RegionLoc);
if (RegionFID != FID) {
- if (isParsedOnceInclude(FE))
- return PPRegion(FE->getDevice(), FE->getInode(), 0,
- FE->getModificationTime());
+ if (isParsedOnceInclude(FE)) {
+ const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
+ return PPRegion(ID, 0, FE->getModificationTime());
+ }
return PPRegion();
}
- return PPRegion(FE->getDevice(), FE->getInode(), RegionOffset,
- FE->getModificationTime());
+ const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
+ return PPRegion(ID, RegionOffset, FE->getModificationTime());
}
bool isParsedOnceInclude(const FileEntry *FE) {
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index 14b430c7dc30..41ed6ea182f7 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -10,6 +10,7 @@
#include "IndexingContext.h"
#include "CIndexDiagnostic.h"
#include "CXTranslationUnit.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Frontend/ASTUnit.h"
@@ -93,17 +94,19 @@ AttrListInfo::AttrListInfo(const Decl *D, IndexingContext &IdxCtx)
const IBOutletCollectionAttr *
IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A);
+ SourceLocation InterfaceLocStart =
+ IBAttr->getInterfaceLoc()->getTypeLoc().getLocStart();
IBInfo.IBCollInfo.attrInfo = &IBInfo;
- IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(IBAttr->getInterfaceLoc());
+ IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(InterfaceLocStart);
IBInfo.IBCollInfo.objcClass = 0;
IBInfo.IBCollInfo.classCursor = clang_getNullCursor();
QualType Ty = IBAttr->getInterface();
- if (const ObjCInterfaceType *InterTy = Ty->getAs<ObjCInterfaceType>()) {
- if (const ObjCInterfaceDecl *InterD = InterTy->getInterface()) {
+ if (const ObjCObjectType *ObjectTy = Ty->getAs<ObjCObjectType>()) {
+ if (const ObjCInterfaceDecl *InterD = ObjectTy->getInterface()) {
IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA);
IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo;
- IBInfo.IBCollInfo.classCursor = MakeCursorObjCClassRef(InterD,
- IBAttr->getInterfaceLoc(), IdxCtx.CXTU);
+ IBInfo.IBCollInfo.classCursor =
+ MakeCursorObjCClassRef(InterD, InterfaceLocStart, IdxCtx.CXTU);
}
}
}
@@ -210,11 +213,13 @@ bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
return false;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
- switch (ND->getLinkage()) {
+ switch (ND->getFormalLinkage()) {
case NoLinkage:
+ case VisibleNoLinkage:
case InternalLinkage:
return true;
case UniqueExternalLinkage:
+ llvm_unreachable("Not a sema linkage");
case ExternalLinkage:
return false;
}
@@ -378,14 +383,14 @@ bool IndexingContext::handleFunction(const FunctionDecl *D) {
isContainer = false;
}
- DeclInfo DInfo(!D->isFirstDeclaration(), isDef, isContainer);
+ DeclInfo DInfo(!D->isFirstDecl(), isDef, isContainer);
if (isSkipped)
DInfo.flags |= CXIdxDeclFlag_Skipped;
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
bool IndexingContext::handleVar(const VarDecl *D) {
- DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(),
/*isContainer=*/false);
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
@@ -412,13 +417,13 @@ bool IndexingContext::handleTagDecl(const TagDecl *D) {
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(D))
return handleCXXRecordDecl(CXXRD, D);
- DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(),
D->isThisDeclarationADefinition());
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
bool IndexingContext::handleTypedefName(const TypedefNameDecl *D) {
- DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true,
+ DeclInfo DInfo(!D->isFirstDecl(), /*isDefinition=*/true,
/*isContainer=*/false);
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index 62873bedb27a..3437d55f0147 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -270,14 +270,6 @@ public:
}
};
-struct RefFileOccurence {
- const FileEntry *File;
- const Decl *Dcl;
-
- RefFileOccurence(const FileEntry *File, const Decl *Dcl)
- : File(File), Dcl(Dcl) { }
-};
-
class IndexingContext {
ASTContext *Ctx;
CXClientData ClientData;
@@ -294,6 +286,7 @@ class IndexingContext {
ContainerMapTy ContainerMap;
EntityMapTy EntityMap;
+ typedef std::pair<const FileEntry *, const Decl *> RefFileOccurence;
llvm::DenseSet<RefFileOccurence> RefFileOccurences;
std::deque<DeclGroupRef> TUDeclsInObjCContainer;
@@ -524,29 +517,3 @@ inline T *ScratchAlloc::allocate() {
}
}} // end clang::cxindex
-
-namespace llvm {
- /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and
- /// DenseSets.
- template <>
- struct DenseMapInfo<clang::cxindex::RefFileOccurence> {
- static inline clang::cxindex::RefFileOccurence getEmptyKey() {
- return clang::cxindex::RefFileOccurence(0, 0);
- }
-
- static inline clang::cxindex::RefFileOccurence getTombstoneKey() {
- return clang::cxindex::RefFileOccurence((const clang::FileEntry *)~0,
- (const clang::Decl *)~0);
- }
-
- static unsigned getHashValue(clang::cxindex::RefFileOccurence S) {
- typedef std::pair<const clang::FileEntry *, const clang::Decl *> PairTy;
- return DenseMapInfo<PairTy>::getHashValue(PairTy(S.File, S.Dcl));
- }
-
- static bool isEqual(clang::cxindex::RefFileOccurence LHS,
- clang::cxindex::RefFileOccurence RHS) {
- return LHS.File == RHS.File && LHS.Dcl == RHS.Dcl;
- }
- };
-}
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index f33f345f94f7..43ecbd14034c 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -16,21 +16,21 @@ LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
-USEDLIBS = clangFrontend.a clangDriver.a \
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a \
clangTooling.a \
clangSerialization.a \
clangParse.a clangSema.a \
clangARCMigrate.a clangRewriteFrontend.a clangRewriteCore.a \
clangAnalysis.a clangEdit.a \
clangAST.a clangLex.a clangBasic.a \
- clangFormat.a
+ clangFormat.a
include $(CLANG_LEVEL)/Makefile
# Add soname to the library.
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU))
- LDFLAGS += -Wl,-soname,lib$(LIBRARYNAME)$(SHLIBEXT)
+ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU GNU/kFreeBSD))
+ LLVMLibsOptions += -Wl,-soname,lib$(LIBRARYNAME)$(SHLIBEXT)
endif
##===----------------------------------------------------------------------===##
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index e45545ed1ad2..3ad5acbb041b 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -27,6 +27,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -394,6 +395,7 @@ private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
bool TraverseClassInstantiations(ClassTemplateDecl *D);
+ bool TraverseVariableInstantiations(VarTemplateDecl *D);
bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
@@ -404,6 +406,13 @@ private:
bool TraverseDeclContextHelper(DeclContext *DC);
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
+ bool TraverseOMPClause(OMPClause *C);
+#define OPENMP_CLAUSE(Name, Class) \
+ bool Visit##Class(Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
typedef SmallVector<Stmt *, 16> StmtsTy;
typedef SmallVector<StmtsTy *, 4> QueuesTy;
@@ -502,7 +511,7 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
}
}
- for (SmallVector<Stmt *, 8>::reverse_iterator
+ for (SmallVectorImpl<Stmt *>::reverse_iterator
RI = StmtsToEnqueu.rbegin(),
RE = StmtsToEnqueu.rend(); RI != RE; ++RI)
Queue.push_back(*RI);
@@ -786,6 +795,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
TRY_TO(TraverseType(T->getPointeeType()));
})
+DEF_TRAVERSE_TYPE(DecayedType, {
+ TRY_TO(TraverseType(T->getOriginalType()));
+ })
+
DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseType(T->getElementType()));
})
@@ -992,6 +1005,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
})
+DEF_TRAVERSE_TYPELOC(DecayedType, {
+ TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
+ })
+
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
@@ -1405,6 +1422,57 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
// it was instantiated, and thus should not be traversed.
})
+// A helper method for traversing the implicit instantiations of a
+// class template.
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseVariableInstantiations(
+ VarTemplateDecl *D) {
+ VarTemplateDecl::spec_iterator end = D->spec_end();
+ for (VarTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
+ VarTemplateSpecializationDecl *SD = *it;
+
+ switch (SD->getSpecializationKind()) {
+ // Visit the implicit instantiations with the requested pattern.
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ TRY_TO(TraverseDecl(SD));
+ break;
+
+ // We don't need to do anything on an explicit instantiation
+ // or explicit specialization because there will be an explicit
+ // node for it elsewhere.
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
+ break;
+ }
+ }
+
+ return true;
+}
+
+DEF_TRAVERSE_DECL(
+ VarTemplateDecl,
+ {
+ VarDecl *TempDecl = D->getTemplatedDecl();
+ TRY_TO(TraverseDecl(TempDecl));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+
+ // By default, we do not traverse the instantiations of
+ // variable templates since they do not appear in the user code. The
+ // following code optionally traverses them.
+ //
+ // We only traverse the variable instantiations when we see the canonical
+ // declaration of the template, to ensure we only visit them once.
+ if (getDerived().shouldVisitTemplateInstantiations() &&
+ D == D->getCanonicalDecl())
+ TRY_TO(TraverseVariableInstantiations(D));
+
+ // Note that getInstantiatedFromMemberTemplate() is just a link
+ // from a template instantiation back to the template from which
+ // it was instantiated, and thus should not be traversed.
+})
+
// A helper method for traversing the instantiations of a
// function while skipping its specializations.
template<typename Derived>
@@ -1582,7 +1650,8 @@ DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
}
// The args that remains unspecialized.
TRY_TO(TraverseTemplateArgumentLocsHelper(
- D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
+ D->getTemplateArgsAsWritten()->getTemplateArgs(),
+ D->getTemplateArgsAsWritten()->NumTemplateArgs));
// Don't need the ClassTemplatePartialSpecializationHelper, even
// though that's our parent class -- we already visit all the
@@ -1731,6 +1800,44 @@ DEF_TRAVERSE_DECL(VarDecl, {
TRY_TO(TraverseVarHelper(D));
})
+DEF_TRAVERSE_DECL(VarTemplateSpecializationDecl, {
+ // For implicit instantiations, we don't want to
+ // recurse at all, since the instatiated class isn't written in
+ // the source code anywhere.
+ if (TypeSourceInfo *TSI = D->getTypeAsWritten())
+ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+
+ if (!getDerived().shouldVisitTemplateInstantiations() &&
+ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ // Returning from here skips traversing the
+ // declaration context of the VarTemplateSpecializationDecl
+ // (embedded in the DEF_TRAVERSE_DECL() macro).
+ return true;
+})
+
+DEF_TRAVERSE_DECL(VarTemplatePartialSpecializationDecl,
+ {
+ // The partial specialization.
+ if (TemplateParameterList *TPL = D->getTemplateParameters()) {
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ }
+ // The args that remains unspecialized.
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ D->getTemplateArgsAsWritten()->getTemplateArgs(),
+ D->getTemplateArgsAsWritten()->NumTemplateArgs));
+
+ // Don't need the VarTemplatePartialSpecializationHelper, even
+ // though that's our parent class -- we already visit all the
+ // template args here.
+ TRY_TO(TraverseVarHelper(D));
+
+ // Instantiations will have been visited with the primary
+ // template.
+})
+
DEF_TRAVERSE_DECL(ImplicitParamDecl, {
TRY_TO(TraverseVarHelper(D));
})
@@ -2039,6 +2146,8 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
// Walk only the visible parts of lambda expressions.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
+ TRY_TO(WalkUpFromLambdaExpr(S));
+
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
@@ -2095,6 +2204,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
@@ -2132,6 +2242,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
DEF_TRAVERSE_STMT(ParenListExpr, { })
DEF_TRAVERSE_STMT(PredefinedExpr, { })
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
DEF_TRAVERSE_STMT(StmtExpr, { })
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@@ -2191,6 +2302,61 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
// Traverse OpenCL: AsType, Convert.
DEF_TRAVERSE_STMT(AsTypeExpr, { })
+// OpenMP directives.
+DEF_TRAVERSE_STMT(OMPParallelDirective, {
+ ArrayRef<OMPClause *> Clauses = S->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (!TraverseOMPClause(*I)) return false;
+})
+
+// OpenMP clauses.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
+ if (!C) return true;
+ switch (C->getClauseKind()) {
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: \
+ return getDerived().Visit##Class(static_cast<Class*>(C));
+#include "clang/Basic/OpenMPKinds.def"
+ default: break;
+ }
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ return true;
+}
+
+template<typename Derived>
+template<typename T>
+void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ TraverseStmt(*I);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
+ OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+ return true;
+}
+
// FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 0c9912e5202f..9bf26c979d29 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -2,6 +2,7 @@ clang_CXCursorSet_contains
clang_CXCursorSet_insert
clang_CXIndex_getGlobalOptions
clang_CXIndex_setGlobalOptions
+clang_CXXMethod_isPureVirtual
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_Cursor_getArgument
@@ -19,6 +20,7 @@ clang_Cursor_getReceiverType
clang_Cursor_isBitField
clang_Cursor_isDynamicCall
clang_Cursor_isNull
+clang_Cursor_isObjCOptional
clang_Cursor_isVariadic
clang_Cursor_getModule
clang_Module_getASTFile
@@ -59,8 +61,10 @@ clang_TParamCommandComment_isParamPositionValid
clang_TParamCommandComment_getDepth
clang_TParamCommandComment_getIndex
clang_Type_getAlignOf
+clang_Type_getClassType
clang_Type_getSizeOf
clang_Type_getOffsetOf
+clang_Type_getCXXRefQualifier
clang_VerbatimBlockLineComment_getText
clang_VerbatimLineComment_getText
clang_HTMLTagComment_getAsString
@@ -253,6 +257,7 @@ clang_isVirtualBase
clang_isVolatileQualifiedType
clang_loadDiagnostics
clang_Location_isInSystemHeader
+clang_Location_isFromMainFile
clang_parseTranslationUnit
clang_remap_dispose
clang_remap_getFilenames
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 60b0185e6fb1..b463ec041e66 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -325,11 +325,6 @@ sub Analyze {
my %CompileOptionMap = (
'-nostdinc' => 0,
- '-fblocks' => 0,
- '-fno-builtin' => 0,
- '-fobjc-gc-only' => 0,
- '-fobjc-gc' => 0,
- '-ffreestanding' => 0,
'-include' => 1,
'-idirafter' => 1,
'-imacros' => 1,
@@ -346,18 +341,16 @@ my %LinkerOptionMap = (
);
my %CompilerLinkerOptionMap = (
- '-fobjc-arc' => 0,
- '-fno-objc-arc' => 0,
- '-fobjc-abi-version' => 0, # This is really a 1 argument, but always has '='
- '-fobjc-legacy-dispatch' => 0,
+ '-Wwrite-strings' => 0,
+ '-ftrapv-handler' => 1, # specifically call out separated -f flag
'-mios-simulator-version-min' => 0, # This really has 1 argument, but always has '='
'-isysroot' => 1,
'-arch' => 1,
'-m32' => 0,
'-m64' => 0,
'-stdlib' => 0, # This is really a 1 argument, but always has '='
+ '-target' => 1,
'-v' => 0,
- '-fpascal-strings' => 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 '='
);
@@ -427,8 +420,8 @@ my %Uniqued;
# Forward arguments to gcc.
my $Status = system($Compiler,@ARGV);
-if (defined $ENV{'CCC_ANALYZER_LOG'}) {
- print "$Compiler @ARGV\n";
+if (defined $ENV{'CCC_ANALYZER_LOG'}) {
+ print STDERR "$Compiler @ARGV\n";
}
if ($Status) { exit($Status >> 8); }
@@ -453,8 +446,8 @@ if (!defined $OutputFormat) { $OutputFormat = "html"; }
# Determine the level of verbosity.
my $Verbose = 0;
-if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; }
-if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; }
+if (defined $ENV{'CCC_ANALYZER_VERBOSE'}) { $Verbose = 1; }
+if (defined $ENV{'CCC_ANALYZER_LOG'}) { $Verbose = 2; }
# Get the HTML output directory.
my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
@@ -491,10 +484,6 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
next;
}
- if ($Arg =~ /-m.*/) {
- push @CompileOpts,$Arg;
- next;
- }
# Handle the case where there isn't a space after -iquote
if ($Arg =~ /-iquote.*/) {
push @CompileOpts,$Arg;
@@ -556,6 +545,11 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
next;
}
+ if ($Arg =~ /-m.*/) {
+ push @CompileOpts,$Arg;
+ next;
+ }
+
# Language.
if ($Arg eq '-x') {
$Lang = $ARGV[$i+1];
@@ -574,6 +568,9 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
if ($Arg eq '-O') { push @LinkOpts,'-O1'; }
elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; }
else { push @LinkOpts,$Arg; }
+
+ # Must pass this along for the __OPTIMIZE__ macro
+ if ($Arg =~ /^-O/) { push @CompileOpts,$Arg; }
next;
}
@@ -582,12 +579,6 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
next;
}
-# if ($Arg =~ /^-f/) {
-# # FIXME: Not sure if the remaining -fxxxx options have no arguments.
-# push @CompileOpts,$Arg;
-# push @LinkOpts,$Arg; # FIXME: Not sure if these are link opts.
-# }
-
# Get the compiler/link mode.
if ($Arg =~ /^-F(.+)$/) {
my $Tmp = $Arg;
@@ -611,6 +602,12 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
next;
}
+ if ($Arg =~ /^-f/) {
+ push @CompileOpts,$Arg;
+ push @LinkOpts,$Arg;
+ next;
+ }
+
# Handle -Wno-. We don't care about extra warnings, but
# we should suppress ones that we don't want to see.
if ($Arg =~ /^-Wno-/) {
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 35f852e70b22..0f119f604986 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -32,7 +32,9 @@ my $TERM = $ENV{'TERM'};
my $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
and defined $ENV{'SCAN_BUILD_COLOR'});
-my $UserName = HtmlEscape(getpwuid($<) || 'unknown');
+# Portability: getpwuid is not implemented for Win32 (see Perl language
+# reference, perlport), use getlogin instead.
+my $UserName = HtmlEscape(getlogin() || getpwuid($<) || 'unknown');
my $HostName = HtmlEscape(hostname() || 'unknown');
my $CurrentDir = HtmlEscape(getcwd());
my $CurrentDirSuffix = basename($CurrentDir);
@@ -121,8 +123,7 @@ sub GetHTMLRunDir {
my $Dir = shift @_;
my $TmpMode = 0;
if (!defined $Dir) {
- $Dir = $ENV{'TMPDIR'};
- if (!defined $Dir) { $Dir = "/tmp"; }
+ $Dir = $ENV{'TMPDIR'} || $ENV{'TEMP'} || $ENV{'TMP'} || "/tmp";
$TmpMode = 1;
}
@@ -134,7 +135,13 @@ sub GetHTMLRunDir {
my $year = $CurrentTime[5] + 1900;
my $day = $CurrentTime[3];
my $month = $CurrentTime[4] + 1;
- my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
+ my $hour = $CurrentTime[2];
+ my $min = $CurrentTime[1];
+ my $sec = $CurrentTime[0];
+
+ my $TimeString = sprintf("%02d%02d%02d", $hour, $min, $sec);
+ my $DateString = sprintf("%d-%02d-%02d-%s-$$",
+ $year, $month, $day, $TimeString);
# Determine the run number.
my $RunNumber;
@@ -161,9 +168,11 @@ sub GetHTMLRunDir {
next if ($x[0] != $year);
next if ($x[1] != $month);
next if ($x[2] != $day);
+ next if ($x[3] != $TimeString);
+ next if ($x[4] != $$);
- if ($x[3] > $max) {
- $max = $x[3];
+ if ($x[5] > $max) {
+ $max = $x[5];
}
}
@@ -896,6 +905,9 @@ sub SetEnv {
}
}
+# The flag corresponding to the --override-compiler command line option.
+my $OverrideCompiler = 0;
+
sub RunXcodebuild {
my $Args = shift;
my $IgnoreErrors = shift;
@@ -910,7 +922,7 @@ sub RunXcodebuild {
# Detect the version of Xcode. If Xcode 4.6 or higher, use new
# in situ support for analyzer interposition without needed to override
# the compiler.
- open(DETECT_XCODE, "xcodebuild -version |") or
+ open(DETECT_XCODE, "-|", $Args->[0], "-version") or
die "error: cannot detect version of xcodebuild\n";
my $oldBehavior = 1;
@@ -928,6 +940,12 @@ sub RunXcodebuild {
}
close(DETECT_XCODE);
+ # If --override-compiler is explicitely requested, resort to the old
+ # behavior regardless of Xcode version.
+ if ($OverrideCompiler) {
+ $oldBehavior = 1;
+ }
+
if ($oldBehavior == 0) {
my $OutputDir = $Options->{"OUTPUT_DIR"};
my $CLANG = $Options->{"CLANG"};
@@ -976,16 +994,11 @@ sub RunBuildCommand {
my $CCAnalyzer = shift;
my $CXXAnalyzer = shift;
my $Options = shift;
-
- # Get only the part of the command after the last '/'.
- if ($Cmd =~ /\/([^\/]+)$/) {
- $Cmd = $1;
- }
-
- if ($Cmd eq "xcodebuild") {
+
+ if ($Cmd =~ /\bxcodebuild$/) {
return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options);
}
-
+
# Setup the environment.
SetEnv($Options);
@@ -1013,10 +1026,10 @@ sub RunBuildCommand {
shift @$Args;
unshift @$Args, $CXXAnalyzer;
}
- elsif ($IgnoreErrors) {
- if ($Cmd eq "make" or $Cmd eq "gmake") {
- AddIfNotPresent($Args, "CC=$CCAnalyzer");
- AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
+ elsif ($Cmd eq "make" or $Cmd eq "gmake") {
+ AddIfNotPresent($Args, "CC=$CCAnalyzer");
+ AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
+ if ($IgnoreErrors) {
AddIfNotPresent($Args,"-k");
AddIfNotPresent($Args,"-i");
}
@@ -1148,6 +1161,10 @@ ADVANCED OPTIONS:
Don't remove the build results directory even if no issues were reported.
+ --override-compiler
+ Always resort to the ccc-analyzer even when better interposition methods
+ are available.
+
CONTROLLING CHECKERS:
A default group of checkers are always run unless explicitly disabled.
@@ -1511,6 +1528,12 @@ while (@ARGV) {
$KeepEmpty = 1;
next;
}
+
+ if ($arg eq "--override-compiler") {
+ shift @ARGV;
+ $OverrideCompiler = 1;
+ next;
+ }
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
@@ -1589,13 +1612,17 @@ my $AbsRealBin = Cwd::realpath($RealBin);
my $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
my $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
-if (!defined $Cmd || ! -x $Cmd) {
+# Portability: use less strict but portable check -e (file exists) instead of
+# non-portable -x (file is executable). On some windows ports -x just checks
+# file extension to determine if a file is executable (see Perl language
+# reference, perlport)
+if (!defined $Cmd || ! -e $Cmd) {
$Cmd = "$AbsRealBin/ccc-analyzer";
- DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
+ DieDiag("'ccc-analyzer' does not exist at '$Cmd'\n") if(! -e $Cmd);
}
-if (!defined $CmdCXX || ! -x $CmdCXX) {
+if (!defined $CmdCXX || ! -e $CmdCXX) {
$CmdCXX = "$AbsRealBin/c++-analyzer";
- DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
+ DieDiag("'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -e $CmdCXX);
}
Diag("Using '$Clang' for static analysis\n");
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
new file mode 100644
index 000000000000..dd73b5220625
--- /dev/null
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -0,0 +1,114 @@
+//===- unittest/AST/ASTTypeTraits.cpp - AST type traits 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/AST/ASTTypeTraits.h"
+#include "gtest/gtest.h"
+#include "MatchVerifier.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace ast_type_traits {
+
+TEST(ASTNodeKind, NoKind) {
+ EXPECT_FALSE(ASTNodeKind().isBaseOf(ASTNodeKind()));
+ EXPECT_FALSE(ASTNodeKind().isSame(ASTNodeKind()));
+}
+
+template <typename T> static ASTNodeKind DNT() {
+ return ASTNodeKind::getFromNodeKind<T>();
+}
+
+TEST(ASTNodeKind, Bases) {
+ EXPECT_TRUE(DNT<Decl>().isBaseOf(DNT<VarDecl>()));
+ EXPECT_FALSE(DNT<Decl>().isSame(DNT<VarDecl>()));
+ EXPECT_FALSE(DNT<VarDecl>().isBaseOf(DNT<Decl>()));
+
+ EXPECT_TRUE(DNT<Decl>().isSame(DNT<Decl>()));
+}
+
+TEST(ASTNodeKind, SameBase) {
+ EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<CallExpr>()));
+ EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<BinaryOperator>()));
+ EXPECT_FALSE(DNT<CallExpr>().isBaseOf(DNT<BinaryOperator>()));
+ EXPECT_FALSE(DNT<BinaryOperator>().isBaseOf(DNT<CallExpr>()));
+}
+
+TEST(ASTNodeKind, DiffBase) {
+ EXPECT_FALSE(DNT<Expr>().isBaseOf(DNT<ArrayType>()));
+ EXPECT_FALSE(DNT<QualType>().isBaseOf(DNT<FunctionDecl>()));
+ EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>()));
+}
+
+struct Foo {};
+
+TEST(ASTNodeKind, UnknownKind) {
+ // We can construct one, but it is nowhere in the hierarchy.
+ EXPECT_FALSE(DNT<Foo>().isSame(DNT<Foo>()));
+}
+
+TEST(ASTNodeKind, Name) {
+ EXPECT_EQ("Decl", DNT<Decl>().asStringRef());
+ EXPECT_EQ("CallExpr", DNT<CallExpr>().asStringRef());
+ EXPECT_EQ("ConstantArrayType", DNT<ConstantArrayType>().asStringRef());
+ EXPECT_EQ("<None>", ASTNodeKind().asStringRef());
+}
+
+TEST(DynTypedNode, DeclSourceRange) {
+ RangeVerifier<DynTypedNode> Verifier;
+ Verifier.expectRange(1, 1, 1, 11);
+ EXPECT_TRUE(Verifier.match("void f() {}", decl()));
+}
+
+TEST(DynTypedNode, StmtSourceRange) {
+ RangeVerifier<DynTypedNode> Verifier;
+ Verifier.expectRange(1, 10, 1, 11);
+ EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
+}
+
+TEST(DynTypedNode, TypeLocSourceRange) {
+ RangeVerifier<DynTypedNode> Verifier;
+ Verifier.expectRange(1, 1, 1, 8);
+ EXPECT_TRUE(Verifier.match("void f() {}", typeLoc(loc(functionType()))));
+}
+
+TEST(DynTypedNode, NNSLocSourceRange) {
+ RangeVerifier<DynTypedNode> Verifier;
+ Verifier.expectRange(1, 33, 1, 34);
+ EXPECT_TRUE(Verifier.match("namespace N { typedef void T; } N::T f() {}",
+ nestedNameSpecifierLoc()));
+}
+
+TEST(DynTypedNode, DeclDump) {
+ DumpVerifier Verifier;
+ Verifier.expectSubstring("FunctionDecl");
+ EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
+}
+
+TEST(DynTypedNode, StmtDump) {
+ DumpVerifier Verifier;
+ Verifier.expectSubstring("CompoundStmt");
+ EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
+}
+
+TEST(DynTypedNode, DeclPrint) {
+ PrintVerifier Verifier;
+ Verifier.expectString("void f() {\n}\n\n");
+ EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
+}
+
+TEST(DynTypedNode, StmtPrint) {
+ PrintVerifier Verifier;
+ Verifier.expectString("{\n}\n");
+ EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
+}
+
+} // namespace ast_type_traits
+} // namespace clang
diff --git a/unittests/AST/ASTVectorTest.cpp b/unittests/AST/ASTVectorTest.cpp
new file mode 100644
index 000000000000..a92e86b3cd88
--- /dev/null
+++ b/unittests/AST/ASTVectorTest.cpp
@@ -0,0 +1,24 @@
+//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for the ASTVector container.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTVector.h"
+
+using namespace clang;
+
+LLVM_ATTRIBUTE_UNUSED void CompileTest() {
+ ASTContext *C = 0;
+ ASTVector<int> V;
+ V.insert(*C, V.begin(), 0);
+}
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index ad29428220bf..70f86d3c7301 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -1,8 +1,11 @@
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
+ ASTTypeTraitsTest.cpp
+ ASTVectorTest.cpp
CommentLexer.cpp
CommentParser.cpp
DeclPrinterTest.cpp
+ DeclTest.cpp
SourceLocationTest.cpp
StmtPrinterTest.cpp
)
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index d05fb58fafaa..f75c636e01dd 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -628,18 +628,43 @@ TEST_F(CommentParserTest, Basic3) {
}
}
-TEST_F(CommentParserTest, Paragraph1) {
+TEST_F(CommentParserTest, ParagraphSplitting1) {
const char *Sources[] = {
"// Aaa\n"
"//\n"
"// Bbb",
"// Aaa\n"
+ "// \n"
+ "// Bbb",
+
+ "// Aaa\n"
+ "//\t\n"
+ "// Bbb",
+
+ "// Aaa\n"
"//\n"
"//\n"
"// Bbb",
- };
+ "/**\n"
+ " Aaa\n"
+ "\n"
+ " Bbb\n"
+ "*/",
+
+ "/**\n"
+ " Aaa\n"
+ " \n"
+ " Bbb\n"
+ "*/",
+
+ "/**\n"
+ " Aaa\n"
+ "\t \n"
+ " Bbb\n"
+ "*/",
+ };
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
FullComment *FC = parseString(Sources[i]);
@@ -650,7 +675,7 @@ TEST_F(CommentParserTest, Paragraph1) {
}
}
-TEST_F(CommentParserTest, Paragraph2) {
+TEST_F(CommentParserTest, Paragraph1) {
const char *Source =
"// \\brief Aaa\n"
"//\n"
@@ -670,7 +695,7 @@ TEST_F(CommentParserTest, Paragraph2) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 2, " Bbb"));
}
-TEST_F(CommentParserTest, Paragraph3) {
+TEST_F(CommentParserTest, Paragraph2) {
const char *Source = "// \\brief \\author";
FullComment *FC = parseString(Source);
@@ -694,7 +719,7 @@ TEST_F(CommentParserTest, Paragraph3) {
}
}
-TEST_F(CommentParserTest, Paragraph4) {
+TEST_F(CommentParserTest, Paragraph3) {
const char *Source =
"// \\brief Aaa\n"
"// Bbb \\author\n"
diff --git a/unittests/AST/DeclTest.cpp b/unittests/AST/DeclTest.cpp
new file mode 100644
index 000000000000..c845da2ca607
--- /dev/null
+++ b/unittests/AST/DeclTest.cpp
@@ -0,0 +1,59 @@
+//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for Decl nodes in the AST.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+
+TEST(Decl, CleansUpAPValues) {
+ MatchFinder Finder;
+ llvm::OwningPtr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+
+ // This is a regression test for a memory leak in APValues for structs that
+ // allocate memory. This test only fails if run under valgrind with full leak
+ // checking enabled.
+ std::vector<std::string> Args(1, "-std=c++11");
+ Args.push_back("-fno-ms-extensions");
+ ASSERT_TRUE(runToolOnCodeWithArgs(
+ Factory->create(),
+ "struct X { int a; }; constexpr X x = { 42 };"
+ "union Y { constexpr Y(int a) : a(a) {} int a; }; constexpr Y y = { 42 };"
+ "constexpr int z[2] = { 42, 43 };"
+ "constexpr int __attribute__((vector_size(16))) v1 = {};"
+ "\n#ifdef __SIZEOF_INT128__\n"
+ "constexpr __uint128_t large_int = 0xffffffffffffffff;"
+ "constexpr __uint128_t small_int = 1;"
+ "\n#endif\n"
+ "constexpr double d1 = 42.42;"
+ "constexpr long double d2 = 42.42;"
+ "constexpr _Complex long double c1 = 42.0i;"
+ "constexpr _Complex long double c2 = 42.0;"
+ "template<int N> struct A : A<N-1> {};"
+ "template<> struct A<0> { int n; }; A<50> a;"
+ "constexpr int &r = a.n;"
+ "constexpr int A<50>::*p = &A<50>::n;"
+ "void f() { foo: bar: constexpr int k = __builtin_constant_p(0) ?"
+ " (char*)&&foo - (char*)&&bar : 0; }",
+ Args));
+
+ // FIXME: Once this test starts breaking we can test APValue::needsCleanup
+ // for ComplexInt.
+ ASSERT_FALSE(runToolOnCodeWithArgs(
+ Factory->create(),
+ "constexpr _Complex __uint128_t c = 0xffffffffffffffff;",
+ Args));
+}
diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile
index 4fb2f5b2b55a..0282d21fcf15 100644
--- a/unittests/AST/Makefile
+++ b/unittests/AST/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = AST
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangRewriteCore.a clangRewriteFrontend.a \
clangParse.a clangSema.a clangAnalysis.a \
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
index 7aa78860aa99..5a29cde22708 100644
--- a/unittests/AST/MatchVerifier.h
+++ b/unittests/AST/MatchVerifier.h
@@ -25,7 +25,7 @@
namespace clang {
namespace ast_matchers {
-enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_OpenCL };
+enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_CXX11, Lang_OpenCL };
/// \brief Base class for verifying some property of nodes found by a matcher.
template <typename NodeType>
@@ -34,12 +34,23 @@ public:
template <typename MatcherType>
testing::AssertionResult match(const std::string &Code,
const MatcherType &AMatcher) {
- return match(Code, AMatcher, Lang_CXX);
+ std::vector<std::string> Args;
+ return match(Code, AMatcher, Args, Lang_CXX);
}
template <typename MatcherType>
testing::AssertionResult match(const std::string &Code,
- const MatcherType &AMatcher, Language L);
+ const MatcherType &AMatcher,
+ Language L) {
+ std::vector<std::string> Args;
+ return match(Code, AMatcher, Args, L);
+ }
+
+ template <typename MatcherType>
+ testing::AssertionResult match(const std::string &Code,
+ const MatcherType &AMatcher,
+ std::vector<std::string>& Args,
+ Language L);
protected:
virtual void run(const MatchFinder::MatchResult &Result);
@@ -64,13 +75,13 @@ private:
/// verifier for the matched node.
template <typename NodeType> template <typename MatcherType>
testing::AssertionResult MatchVerifier<NodeType>::match(
- const std::string &Code, const MatcherType &AMatcher, Language L) {
+ const std::string &Code, const MatcherType &AMatcher,
+ std::vector<std::string>& Args, Language L) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);
OwningPtr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
- std::vector<std::string> Args;
StringRef FileName;
switch (L) {
case Lang_C:
@@ -85,6 +96,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
Args.push_back("-std=c++98");
FileName = "input.cc";
break;
+ case Lang_CXX11:
+ Args.push_back("-std=c++11");
+ FileName = "input.cc";
+ break;
case Lang_OpenCL:
FileName = "input.cl";
}
@@ -110,6 +125,20 @@ void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
}
}
+template <>
+inline void MatchVerifier<ast_type_traits::DynTypedNode>::run(
+ const MatchFinder::MatchResult &Result) {
+ BoundNodes::IDToNodeMap M = Result.Nodes.getMap();
+ BoundNodes::IDToNodeMap::const_iterator I = M.find("");
+ if (I == M.end()) {
+ setFailure("Node was not bound");
+ } else {
+ // Callback has been called, default to success.
+ setSuccess();
+ verify(Result, I->second);
+ }
+}
+
/// \brief Verify whether a node has the correct source location.
///
/// By default, Node.getSourceLocation() is checked. This can be changed
@@ -192,5 +221,59 @@ private:
unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
};
+/// \brief Verify whether a node's dump contains a given substring.
+class DumpVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
+public:
+ void expectSubstring(const std::string &Str) {
+ ExpectSubstring = Str;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result,
+ const ast_type_traits::DynTypedNode &Node) {
+ std::string DumpStr;
+ llvm::raw_string_ostream Dump(DumpStr);
+ Node.dump(Dump, *Result.SourceManager);
+
+ if (Dump.str().find(ExpectSubstring) == std::string::npos) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected dump substring <" << ExpectSubstring << ">, found <"
+ << Dump.str() << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+private:
+ std::string ExpectSubstring;
+};
+
+/// \brief Verify whether a node's pretty print matches a given string.
+class PrintVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
+public:
+ void expectString(const std::string &Str) {
+ ExpectString = Str;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result,
+ const ast_type_traits::DynTypedNode &Node) {
+ std::string PrintStr;
+ llvm::raw_string_ostream Print(PrintStr);
+ Node.print(Print, Result.Context->getPrintingPolicy());
+
+ if (Print.str() != ExpectString) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected pretty print <" << ExpectString << ">, found <"
+ << Print.str() << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+private:
+ std::string ExpectString;
+};
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index f6c0edc9271b..29156bc96ba6 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -155,5 +155,116 @@ TEST(InitListExpr, VectorLiteralInitListParens) {
"constant int2 i2 = (int2)(1, 2);", initListExpr(), Lang_OpenCL));
}
+class TemplateAngleBracketLocRangeVerifier : public RangeVerifier<TypeLoc> {
+protected:
+ virtual SourceRange getRange(const TypeLoc &Node) {
+ TemplateSpecializationTypeLoc T =
+ Node.getUnqualifiedLoc().castAs<TemplateSpecializationTypeLoc>();
+ assert(!T.isNull());
+ return SourceRange(T.getLAngleLoc(), T.getRAngleLoc());
+ }
+};
+
+TEST(TemplateSpecializationTypeLoc, AngleBracketLocations) {
+ TemplateAngleBracketLocRangeVerifier Verifier;
+ Verifier.expectRange(2, 8, 2, 10);
+ EXPECT_TRUE(Verifier.match(
+ "template<typename T> struct A {}; struct B{}; void f(\n"
+ "const A<B>&);",
+ loc(templateSpecializationType())));
+}
+
+TEST(CXXNewExpr, TypeParenRange) {
+ RangeVerifier<CXXNewExpr> Verifier;
+ Verifier.expectRange(1, 10, 1, 18);
+ EXPECT_TRUE(Verifier.match("int* a = new (int);", newExpr()));
+}
+
+class UnaryTransformTypeLocParensRangeVerifier : public RangeVerifier<TypeLoc> {
+protected:
+ virtual SourceRange getRange(const TypeLoc &Node) {
+ UnaryTransformTypeLoc T =
+ Node.getUnqualifiedLoc().castAs<UnaryTransformTypeLoc>();
+ assert(!T.isNull());
+ return SourceRange(T.getLParenLoc(), T.getRParenLoc());
+ }
+};
+
+TEST(UnaryTransformTypeLoc, ParensRange) {
+ UnaryTransformTypeLocParensRangeVerifier Verifier;
+ Verifier.expectRange(3, 26, 3, 28);
+ EXPECT_TRUE(Verifier.match(
+ "template <typename T>\n"
+ "struct S {\n"
+ "typedef __underlying_type(T) type;\n"
+ "};",
+ loc(unaryTransformType())));
+}
+
+TEST(CXXFunctionalCastExpr, SourceRange) {
+ RangeVerifier<CXXFunctionalCastExpr> Verifier;
+ Verifier.expectRange(2, 10, 2, 14);
+ EXPECT_TRUE(Verifier.match(
+ "int foo() {\n"
+ " return int{};\n"
+ "}",
+ functionalCastExpr(), Lang_CXX11));
+}
+
+TEST(CXXTemporaryObjectExpr, SourceRange) {
+ RangeVerifier<CXXTemporaryObjectExpr> Verifier;
+ Verifier.expectRange(2, 6, 2, 12);
+ EXPECT_TRUE(Verifier.match(
+ "struct A { A(int, int); };\n"
+ "A a( A{0, 0} );",
+ temporaryObjectExpr(), Lang_CXX11));
+}
+
+TEST(CXXUnresolvedConstructExpr, SourceRange) {
+ RangeVerifier<CXXUnresolvedConstructExpr> Verifier;
+ Verifier.expectRange(3, 10, 3, 12);
+ std::vector<std::string> Args;
+ Args.push_back("-fno-delayed-template-parsing");
+ EXPECT_TRUE(Verifier.match(
+ "template <typename U>\n"
+ "U foo() {\n"
+ " return U{};\n"
+ "}",
+ unresolvedConstructExpr(), Args, Lang_CXX11));
+}
+
+TEST(UsingDecl, SourceRange) {
+ RangeVerifier<UsingDecl> Verifier;
+ Verifier.expectRange(2, 22, 2, 25);
+ EXPECT_TRUE(Verifier.match(
+ "class B { protected: int i; };\n"
+ "class D : public B { B::i; };",
+ usingDecl()));
+}
+
+TEST(UnresolvedUsingValueDecl, SourceRange) {
+ RangeVerifier<UnresolvedUsingValueDecl> Verifier;
+ Verifier.expectRange(3, 3, 3, 6);
+ EXPECT_TRUE(Verifier.match(
+ "template <typename B>\n"
+ "class D : public B {\n"
+ " B::i;\n"
+ "};",
+ unresolvedUsingValueDecl()));
+}
+
+TEST(FriendDecl, InstantiationSourceRange) {
+ RangeVerifier<FriendDecl> Verifier;
+ Verifier.expectRange(4, 3, 4, 35);
+ EXPECT_TRUE(Verifier.match(
+ "template <typename T> class S;\n"
+ "template<class T> void operator+(S<T> x);\n"
+ "template<class T> struct S {\n"
+ " friend void operator+<>(S<T> src);\n"
+ "};\n"
+ "void test(S<double> s) { +s; }",
+ friendDecl(hasParent(recordDecl(isTemplateInstantiation())))));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index cfa53868ed29..cc13c01fec39 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -40,6 +40,18 @@ TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
}
#endif
+TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
+ MatchFinder Finder;
+ EXPECT_TRUE(Finder.addDynamicMatcher(decl(), NULL));
+ EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), NULL));
+ EXPECT_TRUE(Finder.addDynamicMatcher(constantArrayType(hasSize(42)), NULL));
+
+ // Do not accept non-toplevel matchers.
+ EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), NULL));
+ EXPECT_FALSE(Finder.addDynamicMatcher(hasSize(2), NULL));
+ EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), NULL));
+}
+
TEST(Decl, MatchesDeclarations) {
EXPECT_TRUE(notMatches("", decl(usingDecl())));
EXPECT_TRUE(matches("namespace x { class X {}; } using x::X;",
@@ -311,6 +323,12 @@ TEST(DeclarationMatcher, ClassIsDerived) {
EXPECT_TRUE(matches(
"class X {}; class Y : public X {};",
recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
+
+ EXPECT_TRUE(matches(
+ "template<typename T> class X {};"
+ "template<typename T> using Z = X<T>;"
+ "template <typename T> class Y : Z<T> {};",
+ recordDecl(isDerivedFrom(namedDecl(hasName("X"))))));
}
TEST(DeclarationMatcher, hasMethod) {
@@ -645,14 +663,22 @@ public:
: Id(Id), ExpectedCount(ExpectedCount), Count(0),
ExpectedName(ExpectedName) {}
- ~VerifyIdIsBoundTo() {
+ void onEndOfTranslationUnit() LLVM_OVERRIDE {
if (ExpectedCount != -1)
EXPECT_EQ(ExpectedCount, Count);
if (!ExpectedName.empty())
EXPECT_EQ(ExpectedName, Name);
+ Count = 0;
+ Name.clear();
+ }
+
+ ~VerifyIdIsBoundTo() {
+ EXPECT_EQ(0, Count);
+ EXPECT_EQ("", Name);
}
virtual bool run(const BoundNodes *Nodes) {
+ const BoundNodes::IDToNodeMap &M = Nodes->getMap();
if (Nodes->getNodeAs<T>(Id)) {
++Count;
if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
@@ -662,8 +688,13 @@ public:
llvm::raw_string_ostream OS(Name);
NNS->print(OS, PrintingPolicy(LangOptions()));
}
+ BoundNodes::IDToNodeMap::const_iterator I = M.find(Id);
+ EXPECT_NE(M.end(), I);
+ if (I != M.end())
+ EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>());
return true;
}
+ EXPECT_TRUE(M.count(Id) == 0 || M.find(Id)->second.template get<T>() == 0);
return false;
}
@@ -912,6 +943,15 @@ TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX))));
}
+TEST(HasTypeLoc, MatchesDeclaratorDecls) {
+ EXPECT_TRUE(matches("int x;",
+ varDecl(hasName("x"), hasTypeLoc(loc(asString("int"))))));
+
+ // Make sure we don't crash on implicit constructors.
+ EXPECT_TRUE(notMatches("class X {}; X x;",
+ declaratorDecl(hasTypeLoc(loc(asString("int"))))));
+}
+
TEST(Matcher, Call) {
// FIXME: Do we want to overload Call() to directly take
// Matcher<Decl>, too?
@@ -1346,8 +1386,12 @@ TEST(Matcher, References) {
ReferenceClassX));
EXPECT_TRUE(
matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX));
+ // The match here is on the implicit copy constructor code for
+ // class X, not on code 'X x = y'.
+ EXPECT_TRUE(
+ matches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
EXPECT_TRUE(
- notMatches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
+ notMatches("class X {}; extern X x;", ReferenceClassX));
EXPECT_TRUE(
notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
}
@@ -1452,6 +1496,16 @@ TEST(Matcher, MatchesClassTemplateSpecialization) {
classTemplateSpecializationDecl()));
}
+TEST(DeclaratorDecl, MatchesDeclaratorDecls) {
+ EXPECT_TRUE(matches("int x;", declaratorDecl()));
+ EXPECT_TRUE(notMatches("class A {};", declaratorDecl()));
+}
+
+TEST(ParmVarDecl, MatchesParmVars) {
+ EXPECT_TRUE(matches("void f(int x);", parmVarDecl()));
+ EXPECT_TRUE(notMatches("void f();", parmVarDecl()));
+}
+
TEST(Matcher, MatchesTypeTemplateArgument) {
EXPECT_TRUE(matches(
"template<typename T> struct B {};"
@@ -1507,6 +1561,13 @@ TEST(Matcher, MatchesVirtualMethod) {
methodDecl(isVirtual())));
}
+TEST(Matcher, MatchesConstMethod) {
+ EXPECT_TRUE(matches("struct A { void foo() const; };",
+ methodDecl(isConst())));
+ EXPECT_TRUE(notMatches("struct A { void foo(); };",
+ methodDecl(isConst())));
+}
+
TEST(Matcher, MatchesOverridingMethod) {
EXPECT_TRUE(matches("class X { virtual int f(); }; "
"class Y : public X { int f(); };",
@@ -1827,6 +1888,17 @@ TEST(Matcher, IntegerLiterals) {
EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
}
+TEST(Matcher, FloatLiterals) {
+ StatementMatcher HasFloatLiteral = floatLiteral();
+ EXPECT_TRUE(matches("float i = 10.0;", HasFloatLiteral));
+ EXPECT_TRUE(matches("float i = 10.0f;", HasFloatLiteral));
+ EXPECT_TRUE(matches("double i = 10.0;", HasFloatLiteral));
+ EXPECT_TRUE(matches("double i = 10.0L;", HasFloatLiteral));
+ EXPECT_TRUE(matches("double i = 1e10;", HasFloatLiteral));
+
+ EXPECT_TRUE(notMatches("float i = 10;", HasFloatLiteral));
+}
+
TEST(Matcher, NullPtrLiteral) {
EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr()));
}
@@ -2224,10 +2296,9 @@ TEST(AstMatcherPMacro, Works) {
}
AST_POLYMORPHIC_MATCHER_P(
- polymorphicHas, internal::Matcher<Decl>, AMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
- (llvm::is_same<NodeType, Stmt>::value),
- assert_node_type_is_accessible);
+ polymorphicHas,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(Decl, Stmt),
+ internal::Matcher<Decl>, AMatcher) {
return Finder->matchesChildOf(
Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
@@ -2917,6 +2988,37 @@ TEST(SwitchCase, MatchesSwitch) {
EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
}
+TEST(SwitchCase, MatchesEachCase) {
+ EXPECT_TRUE(notMatches("void x() { switch(42); }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(matches("void x() { switch(42) case 42:; }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void x() { if (1) switch(42) { case 42: switch (42) { default:; } } }",
+ ifStmt(has(switchStmt(forEachSwitchCase(defaultStmt()))))));
+ EXPECT_TRUE(matches("void x() { switch(42) { case 1+1: case 4:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(notMatches("void x() { switch(42) { case 1+1: case 2+2:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(notMatches("void x() { switch(42) { case 1 ... 2:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void x() { switch (42) { case 1: case 2: case 3: default:; } }",
+ switchStmt(forEachSwitchCase(caseStmt().bind("x"))),
+ new VerifyIdIsBoundTo<CaseStmt>("x", 3)));
+}
+
+TEST(ForEachConstructorInitializer, MatchesInitializers) {
+ EXPECT_TRUE(matches(
+ "struct X { X() : i(42), j(42) {} int i, j; };",
+ constructorDecl(forEachConstructorInitializer(ctorInitializer()))));
+}
+
TEST(ExceptionHandling, SimpleCases) {
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt()));
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt()));
@@ -2977,12 +3079,13 @@ TEST(ForEachDescendant, NestedForEachDescendant) {
recordDecl(hasName("A"), anyOf(m, forEachDescendant(m))),
new VerifyIdIsBoundTo<Decl>("x", "C")));
- // FIXME: This is not really a useful matcher, but the result is still
- // surprising (currently binds "A").
- //EXPECT_TRUE(matchAndVerifyResultTrue(
- // "class A { class B { class C {}; }; };",
- // recordDecl(hasName("A"), allOf(hasDescendant(m), anyOf(m, anything()))),
- // new VerifyIdIsBoundTo<Decl>("x", "C")));
+ // Check that a partial match of 'm' that binds 'x' in the
+ // first part of anyOf(m, anything()) will not overwrite the
+ // binding created by the earlier binding in the hasDescendant.
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("A"), allOf(hasDescendant(m), anyOf(m, anything()))),
+ new VerifyIdIsBoundTo<Decl>("x", "C")));
}
TEST(ForEachDescendant, BindsMultipleNodes) {
@@ -3002,6 +3105,117 @@ TEST(ForEachDescendant, BindsRecursiveCombinations) {
new VerifyIdIsBoundTo<FieldDecl>("f", 8)));
}
+TEST(ForEachDescendant, BindsCombinations) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { if(true) {} if (true) {} while (true) {} if (true) {} while "
+ "(true) {} }",
+ compoundStmt(forEachDescendant(ifStmt().bind("if")),
+ forEachDescendant(whileStmt().bind("while"))),
+ new VerifyIdIsBoundTo<IfStmt>("if", 6)));
+}
+
+TEST(Has, DoesNotDeleteBindings) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { int a; };", recordDecl(decl().bind("x"), has(fieldDecl())),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+}
+
+TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) {
+ // Those matchers cover all the cases where an inner matcher is called
+ // and there is not a 1:1 relationship between the match of the outer
+ // matcher and the match of the inner matcher.
+ // The pattern to look for is:
+ // ... return InnerMatcher.matches(...); ...
+ // In which case no special handling is needed.
+ //
+ // On the other hand, if there are multiple alternative matches
+ // (for example forEach*) or matches might be discarded (for example has*)
+ // the implementation must make sure that the discarded matches do not
+ // affect the bindings.
+ // When new such matchers are added, add a test here that:
+ // - matches a simple node, and binds it as the first thing in the matcher:
+ // recordDecl(decl().bind("x"), hasName("X")))
+ // - uses the matcher under test afterwards in a way that not the first
+ // alternative is matched; for anyOf, that means the first branch
+ // would need to return false; for hasAncestor, it means that not
+ // the direct parent matches the inner matcher.
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { int y; };",
+ recordDecl(
+ recordDecl().bind("x"), hasName("::X"),
+ anyOf(forEachDescendant(recordDecl(hasName("Y"))), anything())),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X {};", recordDecl(recordDecl().bind("x"), hasName("::X"),
+ anyOf(unless(anything()), anything())),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "template<typename T1, typename T2> class X {}; X<float, int> x;",
+ classTemplateSpecializationDecl(
+ decl().bind("x"),
+ hasAnyTemplateArgument(refersToType(asString("int")))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { void f(); void g(); };",
+ recordDecl(decl().bind("x"), hasMethod(hasName("g"))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { X() : a(1), b(2) {} double a; int b; };",
+ recordDecl(decl().bind("x"),
+ has(constructorDecl(
+ hasAnyConstructorInitializer(forField(hasName("b")))))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void x(int, int) { x(0, 42); }",
+ callExpr(expr().bind("x"), hasAnyArgument(integerLiteral(equals(42)))),
+ new VerifyIdIsBoundTo<Expr>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void x(int, int y) {}",
+ functionDecl(decl().bind("x"), hasAnyParameter(hasName("y"))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void x() { return; if (true) {} }",
+ functionDecl(decl().bind("x"),
+ has(compoundStmt(hasAnySubstatement(ifStmt())))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "namespace X { void b(int); void b(); }"
+ "using X::b;",
+ usingDecl(decl().bind("x"), hasAnyUsingShadowDecl(hasTargetDecl(
+ functionDecl(parameterCountIs(1))))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A{}; class B{}; class C : B, A {};",
+ recordDecl(decl().bind("x"), isDerivedFrom("::A")),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A{}; typedef A B; typedef A C; typedef A D;"
+ "class E : A {};",
+ recordDecl(decl().bind("x"), isDerivedFrom("C")),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B { void f() {} }; };",
+ functionDecl(decl().bind("x"), hasAncestor(recordDecl(hasName("::A")))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "template <typename T> struct A { struct B {"
+ " void f() { if(true) {} }"
+ "}; };"
+ "void t() { A<int>::B b; b.f(); }",
+ ifStmt(stmt().bind("x"), hasAncestor(recordDecl(hasName("::A")))),
+ new VerifyIdIsBoundTo<Stmt>("x", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A {};",
+ recordDecl(hasName("::A"), decl().bind("x"), unless(hasName("fooble"))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { A() : s(), i(42) {} const char *s; int i; };",
+ constructorDecl(hasName("::A::A"), decl().bind("x"),
+ forEachConstructorInitializer(forField(hasName("i")))),
+ new VerifyIdIsBoundTo<Decl>("x", 1)));
+}
+
TEST(ForEachDescendant, BindsCorrectNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { void f(); int i; };",
@@ -3900,6 +4114,128 @@ TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_TRUE(VerifyCallback.Called);
+
+ VerifyCallback.Called = false;
+ OwningPtr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ ASSERT_TRUE(AST.get());
+ Finder.matchAST(AST->getASTContext());
+ EXPECT_TRUE(VerifyCallback.Called);
+}
+
+class VerifyEndOfTranslationUnit : public MatchFinder::MatchCallback {
+public:
+ VerifyEndOfTranslationUnit() : Called(false) {}
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ EXPECT_FALSE(Called);
+ }
+ virtual void onEndOfTranslationUnit() {
+ Called = true;
+ }
+ bool Called;
+};
+
+TEST(MatchFinder, InterceptsEndOfTranslationUnit) {
+ MatchFinder Finder;
+ VerifyEndOfTranslationUnit VerifyCallback;
+ Finder.addMatcher(decl(), &VerifyCallback);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+ EXPECT_TRUE(VerifyCallback.Called);
+
+ VerifyCallback.Called = false;
+ OwningPtr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ ASSERT_TRUE(AST.get());
+ Finder.matchAST(AST->getASTContext());
+ EXPECT_TRUE(VerifyCallback.Called);
+}
+
+TEST(EqualsBoundNodeMatcher, QualType) {
+ EXPECT_TRUE(matches(
+ "int i = 1;", varDecl(hasType(qualType().bind("type")),
+ hasInitializer(ignoringParenImpCasts(
+ hasType(qualType(equalsBoundNode("type"))))))));
+ EXPECT_TRUE(notMatches("int i = 1.f;",
+ varDecl(hasType(qualType().bind("type")),
+ hasInitializer(ignoringParenImpCasts(hasType(
+ qualType(equalsBoundNode("type"))))))));
+}
+
+TEST(EqualsBoundNodeMatcher, NonMatchingTypes) {
+ EXPECT_TRUE(notMatches(
+ "int i = 1;", varDecl(namedDecl(hasName("i")).bind("name"),
+ hasInitializer(ignoringParenImpCasts(
+ hasType(qualType(equalsBoundNode("type"))))))));
+}
+
+TEST(EqualsBoundNodeMatcher, Stmt) {
+ EXPECT_TRUE(
+ matches("void f() { if(true) {} }",
+ stmt(allOf(ifStmt().bind("if"),
+ hasParent(stmt(has(stmt(equalsBoundNode("if")))))))));
+
+ EXPECT_TRUE(notMatches(
+ "void f() { if(true) { if (true) {} } }",
+ stmt(allOf(ifStmt().bind("if"), has(stmt(equalsBoundNode("if")))))));
+}
+
+TEST(EqualsBoundNodeMatcher, Decl) {
+ EXPECT_TRUE(matches(
+ "class X { class Y {}; };",
+ decl(allOf(recordDecl(hasName("::X::Y")).bind("record"),
+ hasParent(decl(has(decl(equalsBoundNode("record")))))))));
+
+ EXPECT_TRUE(notMatches("class X { class Y {}; };",
+ decl(allOf(recordDecl(hasName("::X")).bind("record"),
+ has(decl(equalsBoundNode("record")))))));
+}
+
+TEST(EqualsBoundNodeMatcher, Type) {
+ EXPECT_TRUE(matches(
+ "class X { int a; int b; };",
+ recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))));
+
+ EXPECT_TRUE(notMatches(
+ "class X { int a; double b; };",
+ recordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))));
+}
+
+TEST(EqualsBoundNodeMatcher, UsingForEachDescendant) {
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "int f() {"
+ " if (1) {"
+ " int i = 9;"
+ " }"
+ " int j = 10;"
+ " {"
+ " float k = 9.0;"
+ " }"
+ " return 0;"
+ "}",
+ // Look for variable declarations within functions whose type is the same
+ // as the function return type.
+ functionDecl(returns(qualType().bind("type")),
+ forEachDescendant(varDecl(hasType(
+ qualType(equalsBoundNode("type")))).bind("decl"))),
+ // Only i and j should match, not k.
+ new VerifyIdIsBoundTo<VarDecl>("decl", 2)));
+}
+
+TEST(EqualsBoundNodeMatcher, FiltersMatchedCombinations) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() {"
+ " int x;"
+ " double d;"
+ " x = d + x - d + x;"
+ "}",
+ functionDecl(
+ hasName("f"), forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d")))))),
+ new VerifyIdIsBoundTo<VarDecl>("d", 5)));
}
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 5fed85bb30bb..f5bcd37f112d 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -11,12 +11,14 @@
#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
namespace clang {
namespace ast_matchers {
+using clang::tooling::buildASTFromCodeWithArgs;
using clang::tooling::newFrontendActionFactory;
using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
@@ -26,6 +28,7 @@ public:
virtual ~BoundNodesCallback() {}
virtual bool run(const BoundNodes *BoundNodes) = 0;
virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
+ virtual void onEndOfTranslationUnit() {}
};
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
@@ -44,6 +47,11 @@ public:
}
}
+ void onEndOfTranslationUnit() LLVM_OVERRIDE {
+ if (FindResultReviewer)
+ FindResultReviewer->onEndOfTranslationUnit();
+ }
+
private:
bool *const Verified;
BoundNodesCallback *const FindResultReviewer;
@@ -54,15 +62,23 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
const T &AMatcher,
bool ExpectMatch,
llvm::StringRef CompileArg) {
- bool Found = false;
+ bool Found = false, DynamicFound = false;
MatchFinder Finder;
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
+ if (!Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &DynamicFound)))
+ return testing::AssertionFailure() << "Could not add dynamic matcher";
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, CompileArg);
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
+ if (Found != DynamicFound) {
+ return testing::AssertionFailure() << "Dynamic match result ("
+ << DynamicFound
+ << ") does not match static result ("
+ << Found << ")";
+ }
if (!Found && ExpectMatch) {
return testing::AssertionFailure()
<< "Could not find match in \"" << Code << "\"";
@@ -107,6 +123,21 @@ matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
return testing::AssertionFailure()
<< "Verified unexpected result in \"" << Code << "\"";
}
+
+ VerifiedResult = false;
+ OwningPtr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args));
+ if (!AST.get())
+ return testing::AssertionFailure() << "Parsing error in \"" << Code
+ << "\" while building AST";
+ Finder.matchAST(AST->getASTContext());
+ if (!VerifiedResult && ExpectResult) {
+ return testing::AssertionFailure()
+ << "Could not verify result in \"" << Code << "\" with AST";
+ } else if (VerifiedResult && !ExpectResult) {
+ return testing::AssertionFailure()
+ << "Verified unexpected result in \"" << Code << "\" with AST";
+ }
+
return testing::AssertionSuccess();
}
diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt
index 91feaac4d95b..862c6a0fd95c 100644
--- a/unittests/ASTMatchers/CMakeLists.txt
+++ b/unittests/ASTMatchers/CMakeLists.txt
@@ -11,3 +11,5 @@ add_clang_unittest(ASTMatchersTests
target_link_libraries(ASTMatchersTests
gtest gtest_main clangASTMatchers clangTooling)
+
+add_subdirectory(Dynamic)
diff --git a/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
new file mode 100644
index 000000000000..eb9fa549e118
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_clang_unittest(DynamicASTMatchersTests
+ VariantValueTest.cpp
+ ParserTest.cpp
+ RegistryTest.cpp)
+
+target_link_libraries(DynamicASTMatchersTests
+ gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling)
diff --git a/unittests/ASTMatchers/Dynamic/Makefile b/unittests/ASTMatchers/Dynamic/Makefile
new file mode 100644
index 000000000000..66b183c0e484
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/Makefile
@@ -0,0 +1,20 @@
+##===- unittests/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../../..
+
+TESTNAME = DynamicASTMatchers
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewriteCore.a clangRewriteFrontend.a clangParse.a clangSema.a \
+ clangAnalysis.a clangEdit.a clangAST.a clangASTMatchers.a \
+ clangLex.a clangBasic.a clangDynamicASTMatchers.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
new file mode 100644
index 000000000000..f19ec51ad70e
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -0,0 +1,238 @@
+//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+class MockSema : public Parser::Sema {
+public:
+ virtual ~MockSema() {}
+
+ uint64_t expectMatcher(StringRef MatcherName) {
+ ast_matchers::internal::Matcher<Stmt> M = stmt();
+ ExpectedMatchers.insert(std::make_pair(MatcherName, M));
+ return M.getID();
+ }
+
+ void parse(StringRef Code) {
+ Diagnostics Error;
+ VariantValue Value;
+ Parser::parseExpression(Code, this, &Value, &Error);
+ Values.push_back(Value);
+ Errors.push_back(Error.toStringFull());
+ }
+
+ VariantMatcher actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
+ Matchers.push_back(ToStore);
+ return VariantMatcher::SingleMatcher(
+ ExpectedMatchers.find(MatcherName)->second);
+ }
+
+ struct MatcherInfo {
+ StringRef MatcherName;
+ SourceRange NameRange;
+ std::vector<ParserValue> Args;
+ std::string BoundID;
+ };
+
+ std::vector<std::string> Errors;
+ std::vector<VariantValue> Values;
+ std::vector<MatcherInfo> Matchers;
+ std::map<std::string, ast_matchers::internal::Matcher<Stmt> >
+ ExpectedMatchers;
+};
+
+TEST(ParserTest, ParseUnsigned) {
+ MockSema Sema;
+ Sema.parse("0");
+ Sema.parse("123");
+ Sema.parse("0x1f");
+ Sema.parse("12345678901");
+ Sema.parse("1a1");
+ EXPECT_EQ(5U, Sema.Values.size());
+ 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]);
+}
+
+TEST(ParserTest, ParseString) {
+ MockSema Sema;
+ Sema.parse("\"Foo\"");
+ Sema.parse("\"\"");
+ Sema.parse("\"Baz");
+ EXPECT_EQ(3ULL, Sema.Values.size());
+ EXPECT_EQ("Foo", Sema.Values[0].getString());
+ EXPECT_EQ("", Sema.Values[1].getString());
+ EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]);
+}
+
+bool matchesRange(const SourceRange &Range, unsigned StartLine,
+ unsigned EndLine, unsigned StartColumn, unsigned EndColumn) {
+ EXPECT_EQ(StartLine, Range.Start.Line);
+ EXPECT_EQ(EndLine, Range.End.Line);
+ EXPECT_EQ(StartColumn, Range.Start.Column);
+ EXPECT_EQ(EndColumn, Range.End.Column);
+ return Range.Start.Line == StartLine && Range.End.Line == EndLine &&
+ Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
+}
+
+llvm::Optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) {
+ llvm::Optional<DynTypedMatcher> Result =
+ Value.getMatcher().getSingleMatcher();
+ EXPECT_TRUE(Result.hasValue());
+ return Result;
+}
+
+TEST(ParserTest, ParseMatcher) {
+ MockSema Sema;
+ const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");
+ const uint64_t ExpectedBar = Sema.expectMatcher("Bar");
+ const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");
+ Sema.parse(" Foo ( Bar ( 17), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") ");
+ for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) {
+ EXPECT_EQ("", Sema.Errors[i]);
+ }
+
+ EXPECT_EQ(1ULL, Sema.Values.size());
+ EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID());
+
+ EXPECT_EQ(3ULL, Sema.Matchers.size());
+ const MockSema::MatcherInfo Bar = Sema.Matchers[0];
+ EXPECT_EQ("Bar", Bar.MatcherName);
+ EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 17));
+ EXPECT_EQ(1ULL, Bar.Args.size());
+ EXPECT_EQ(17U, Bar.Args[0].Value.getUnsigned());
+
+ const MockSema::MatcherInfo Baz = Sema.Matchers[1];
+ EXPECT_EQ("Baz", Baz.MatcherName);
+ EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 19, 10));
+ EXPECT_EQ(1ULL, Baz.Args.size());
+ EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString());
+
+ const MockSema::MatcherInfo Foo = Sema.Matchers[2];
+ EXPECT_EQ("Foo", Foo.MatcherName);
+ EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
+ EXPECT_EQ(2ULL, Foo.Args.size());
+ EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID());
+ EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID());
+ EXPECT_EQ("Yo!", Foo.BoundID);
+}
+
+using ast_matchers::internal::Matcher;
+
+TEST(ParserTest, FullParserTest) {
+ Diagnostics Error;
+ llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
+ " hasOperatorName(\"+\"))))",
+ &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ Matcher<Decl> M = VarDecl->unconditionalConvertTo<Decl>();
+ EXPECT_TRUE(matches("int x = 1 + false;", M));
+ EXPECT_FALSE(matches("int x = true + 1;", M));
+ EXPECT_FALSE(matches("int x = 1 - false;", M));
+ EXPECT_FALSE(matches("int x = true - 1;", M));
+
+ llvm::Optional<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
+ "functionDecl(hasParameter(1, hasName(\"x\")))", &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ M = HasParameter->unconditionalConvertTo<Decl>();
+
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
+
+ EXPECT_TRUE(!Parser::parseMatcherExpression(
+ "hasInitializer(\n binaryOperator(hasLHS(\"A\")))",
+ &Error).hasValue());
+ EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
+ "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
+ "2:20: Error building matcher hasLHS.\n"
+ "2:27: Incorrect type for arg 1. "
+ "(Expected = Matcher<Expr>) != (Actual = String)",
+ Error.toStringFull());
+}
+
+std::string ParseWithError(StringRef Code) {
+ Diagnostics Error;
+ VariantValue Value;
+ Parser::parseExpression(Code, &Value, &Error);
+ return Error.toStringFull();
+}
+
+std::string ParseMatcherWithError(StringRef Code) {
+ Diagnostics Error;
+ Parser::parseMatcherExpression(Code, &Error);
+ return Error.toStringFull();
+}
+
+TEST(ParserTest, Errors) {
+ EXPECT_EQ(
+ "1:5: Error parsing matcher. Found token <123> while looking for '('.",
+ ParseWithError("Foo 123"));
+ EXPECT_EQ(
+ "1:9: Error parsing matcher. Found token <123> while looking for ','.",
+ ParseWithError("Foo(\"A\" 123)"));
+ EXPECT_EQ(
+ "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
+ ParseWithError("Foo("));
+ EXPECT_EQ("1:1: End of code found while looking for token.",
+ ParseWithError(""));
+ EXPECT_EQ("Input value is not a matcher expression.",
+ ParseMatcherWithError("\"A\""));
+ EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
+ "1:5: Invalid token <(> found when looking for a value.",
+ ParseWithError("Foo(("));
+ EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));
+ EXPECT_EQ("1:11: Malformed bind() expression.",
+ ParseWithError("isArrow().biind"));
+ EXPECT_EQ("1:15: Malformed bind() expression.",
+ ParseWithError("isArrow().bind"));
+ EXPECT_EQ("1:16: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(foo"));
+ EXPECT_EQ("1:21: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(\"foo\""));
+ EXPECT_EQ("1:1: Error building matcher isArrow.\n"
+ "1:1: Matcher does not support binding.",
+ ParseWithError("isArrow().bind(\"foo\")"));
+ EXPECT_EQ("Input value has unresolved overloaded type: "
+ "Matcher<DoStmt|ForStmt|WhileStmt>",
+ ParseMatcherWithError("hasBody(stmt())"));
+}
+
+TEST(ParserTest, OverloadErrors) {
+ EXPECT_EQ("1:1: Error building matcher callee.\n"
+ "1:8: Candidate 1: Incorrect type for arg 1. "
+ "(Expected = Matcher<Stmt>) != (Actual = String)\n"
+ "1:8: Candidate 2: Incorrect type for arg 1. "
+ "(Expected = Matcher<Decl>) != (Actual = String)",
+ ParseWithError("callee(\"A\")"));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
new file mode 100644
index 000000000000..e716484e207f
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -0,0 +1,347 @@
+//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using ast_matchers::internal::Matcher;
+
+class RegistryTest : public ::testing::Test {
+public:
+ std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
+ std::vector<ParserValue> Args(const VariantValue &Arg1) {
+ std::vector<ParserValue> Out(1);
+ Out[0].Value = Arg1;
+ return Out;
+ }
+ std::vector<ParserValue> Args(const VariantValue &Arg1,
+ const VariantValue &Arg2) {
+ std::vector<ParserValue> Out(2);
+ Out[0].Value = Arg1;
+ Out[1].Value = Arg2;
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out =
+ Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ const VariantValue &Arg1,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out = Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ const VariantValue &Arg1,
+ const VariantValue &Arg2,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out = Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+ Matcher<Stmt> IsArrowValue = constructMatcher(
+ "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
+ Matcher<Stmt> BoolValue =
+ constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
+
+ const std::string ClassSnippet = "struct Foo { int x; };\n"
+ "Foo *foo = new Foo;\n"
+ "int i = foo->x;\n";
+ const std::string BoolSnippet = "bool Foo = true;\n";
+
+ EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
+ EXPECT_TRUE(matches(BoolSnippet, BoolValue));
+ EXPECT_FALSE(matches(ClassSnippet, BoolValue));
+ EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
+}
+
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+ Matcher<Decl> Value = constructMatcher(
+ "namedDecl", constructMatcher("hasName", std::string("X")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("class X {};", Value));
+ EXPECT_FALSE(matches("int x;", Value));
+
+ Value = functionDecl(constructMatcher("parameterCountIs", 2)
+ .getTypedMatcher<FunctionDecl>());
+ EXPECT_TRUE(matches("void foo(int,int);", Value));
+ EXPECT_FALSE(matches("void foo(int);", Value));
+}
+
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+ Matcher<Decl> HasInitializerSimple = constructMatcher(
+ "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
+ .getTypedMatcher<Decl>();
+ Matcher<Decl> HasInitializerComplex = constructMatcher(
+ "varDecl",
+ constructMatcher("hasInitializer", constructMatcher("callExpr")))
+ .getTypedMatcher<Decl>();
+
+ std::string code = "int i;";
+ EXPECT_FALSE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
+
+ code = "int i = 1;";
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
+
+ code = "int y(); int i = y();";
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_TRUE(matches(code, HasInitializerComplex));
+
+ Matcher<Decl> HasParameter =
+ functionDecl(constructMatcher(
+ "hasParameter", 1, constructMatcher("hasName", std::string("x")))
+ .getTypedMatcher<FunctionDecl>());
+ EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
+ EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
+}
+
+TEST_F(RegistryTest, OverloadedMatchers) {
+ Matcher<Stmt> CallExpr0 = constructMatcher(
+ "callExpr",
+ constructMatcher("callee", constructMatcher("memberExpr",
+ constructMatcher("isArrow"))))
+ .getTypedMatcher<Stmt>();
+
+ Matcher<Stmt> CallExpr1 = constructMatcher(
+ "callExpr",
+ constructMatcher(
+ "callee",
+ constructMatcher("methodDecl",
+ constructMatcher("hasName", std::string("x")))))
+ .getTypedMatcher<Stmt>();
+
+ std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
+ EXPECT_FALSE(matches(Code, CallExpr0));
+ EXPECT_TRUE(matches(Code, CallExpr1));
+
+ Code = "class Z { public: void z() { this->z(); } };";
+ EXPECT_TRUE(matches(Code, CallExpr0));
+ EXPECT_FALSE(matches(Code, CallExpr1));
+}
+
+TEST_F(RegistryTest, PolymorphicMatchers) {
+ const VariantMatcher IsDefinition = constructMatcher("isDefinition");
+ Matcher<Decl> Var =
+ constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
+ Matcher<Decl> Class =
+ constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
+ Matcher<Decl> Func =
+ constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("int a;", Var));
+ EXPECT_FALSE(matches("extern int a;", Var));
+ EXPECT_TRUE(matches("class A {};", Class));
+ EXPECT_FALSE(matches("class A;", Class));
+ EXPECT_TRUE(matches("void f(){};", Func));
+ EXPECT_FALSE(matches("void f();", Func));
+
+ Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
+ Matcher<Decl> RecordDecl = constructMatcher(
+ "recordDecl", constructMatcher("hasName", std::string("Foo")),
+ VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
+
+ EXPECT_TRUE(matches("int Foo;", Anything));
+ EXPECT_TRUE(matches("class Foo {};", Anything));
+ EXPECT_TRUE(matches("void Foo(){};", Anything));
+ EXPECT_FALSE(matches("int Foo;", RecordDecl));
+ EXPECT_TRUE(matches("class Foo {};", RecordDecl));
+ EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
+
+ Matcher<Stmt> ConstructExpr = constructMatcher(
+ "constructExpr",
+ constructMatcher(
+ "hasDeclaration",
+ constructMatcher(
+ "methodDecl",
+ constructMatcher(
+ "ofClass", constructMatcher("hasName", std::string("Foo"))))))
+ .getTypedMatcher<Stmt>();
+ EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
+ EXPECT_TRUE(
+ matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
+}
+
+TEST_F(RegistryTest, TemplateArgument) {
+ Matcher<Decl> HasTemplateArgument = constructMatcher(
+ "classTemplateSpecializationDecl",
+ constructMatcher(
+ "hasAnyTemplateArgument",
+ constructMatcher("refersToType",
+ constructMatcher("asString", std::string("int")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
+ HasTemplateArgument));
+ EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
+ HasTemplateArgument));
+}
+
+TEST_F(RegistryTest, TypeTraversal) {
+ Matcher<Type> M = constructMatcher(
+ "pointerType",
+ constructMatcher("pointee", constructMatcher("isConstQualified"),
+ constructMatcher("isInteger"))).getTypedMatcher<Type>();
+ EXPECT_FALSE(matches("int *a;", M));
+ EXPECT_TRUE(matches("int const *b;", M));
+
+ M = constructMatcher(
+ "arrayType",
+ constructMatcher("hasElementType", constructMatcher("builtinType")))
+ .getTypedMatcher<Type>();
+ EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
+ EXPECT_TRUE(matches("int b[7];", M));
+}
+
+TEST_F(RegistryTest, CXXCtorInitializer) {
+ Matcher<Decl> CtorDecl = constructMatcher(
+ "constructorDecl",
+ constructMatcher(
+ "hasAnyConstructorInitializer",
+ constructMatcher("forField",
+ constructMatcher("hasName", std::string("foo")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
+ EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
+ EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
+}
+
+TEST_F(RegistryTest, Adaptative) {
+ Matcher<Decl> D = constructMatcher(
+ "recordDecl",
+ constructMatcher(
+ "has",
+ constructMatcher("recordDecl",
+ constructMatcher("hasName", std::string("X")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("class X {};", D));
+ EXPECT_TRUE(matches("class Y { class X {}; };", D));
+ EXPECT_FALSE(matches("class Y { class Z {}; };", D));
+
+ Matcher<Stmt> S = constructMatcher(
+ "forStmt",
+ constructMatcher(
+ "hasDescendant",
+ constructMatcher("varDecl",
+ constructMatcher("hasName", std::string("X")))))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
+ EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
+ EXPECT_FALSE(matches("void foo() { for(;;); }", S));
+ EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
+
+ S = constructMatcher(
+ "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
+ EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
+}
+
+TEST_F(RegistryTest, VariadicOp) {
+ Matcher<Decl> D = constructMatcher(
+ "anyOf",
+ constructMatcher("recordDecl",
+ constructMatcher("hasName", std::string("Foo"))),
+ constructMatcher("namedDecl",
+ constructMatcher("hasName", std::string("foo"))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_TRUE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+
+ D = constructMatcher(
+ "allOf", constructMatcher("recordDecl"),
+ constructMatcher(
+ "namedDecl",
+ constructMatcher("anyOf",
+ constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("hasName", std::string("Bar")))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_FALSE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+ EXPECT_TRUE(matches("class Bar{};", D));
+ EXPECT_FALSE(matches("class OtherBar{};", D));
+}
+
+TEST_F(RegistryTest, Errors) {
+ // Incorrect argument count.
+ OwningPtr<Diagnostics> Error(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
+ Error->toString());
+
+ // Bad argument type
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = String)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"),
+ constructMatcher("parameterCountIs", 3),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<FunctionDecl>)",
+ Error->toString());
+
+ // Bad argument type with variadic.
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
+ EXPECT_EQ(
+ "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher(
+ "recordDecl",
+ constructMatcher("allOf",
+ constructMatcher("isDerivedFrom", std::string("FOO")),
+ constructMatcher("isArrow")),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 1. "
+ "(Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
+ Error->toString());
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
new file mode 100644
index 000000000000..d2b8a58bc86b
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -0,0 +1,144 @@
+//===- unittest/ASTMatchers/Dynamic/VariantValueTest.cpp - VariantValue unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------------===//
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using ast_matchers::internal::DynTypedMatcher;
+using ast_matchers::internal::Matcher;
+
+TEST(VariantValueTest, Unsigned) {
+ const unsigned kUnsigned = 17;
+ VariantValue Value = kUnsigned;
+
+ EXPECT_TRUE(Value.isUnsigned());
+ EXPECT_EQ(kUnsigned, Value.getUnsigned());
+
+ EXPECT_FALSE(Value.isString());
+ EXPECT_FALSE(Value.isMatcher());
+}
+
+TEST(VariantValueTest, String) {
+ const ::std::string kString = "string";
+ VariantValue Value = kString;
+
+ EXPECT_TRUE(Value.isString());
+ EXPECT_EQ(kString, Value.getString());
+ EXPECT_EQ("String", Value.getTypeAsString());
+
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+}
+
+TEST(VariantValueTest, DynTypedMatcher) {
+ VariantValue Value = VariantMatcher::SingleMatcher(stmt());
+
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
+
+ // Can only convert to compatible matchers.
+ Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+
+ Value = VariantMatcher::SingleMatcher(ignoringImpCasts(expr()));
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Stmt>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Expr>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<IntegerLiteral>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<GotoStmt>());
+ EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
+}
+
+TEST(VariantValueTest, Assignment) {
+ VariantValue Value = std::string("A");
+ EXPECT_TRUE(Value.isString());
+ EXPECT_EQ("A", Value.getString());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("String", Value.getTypeAsString());
+
+ Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+
+ Value = 17;
+ EXPECT_TRUE(Value.isUnsigned());
+ EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isString());
+
+ Value = VariantValue();
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("Nothing", Value.getTypeAsString());
+}
+
+TEST(VariantValueTest, Matcher) {
+ EXPECT_TRUE(matches("class X {};", VariantValue(VariantMatcher::SingleMatcher(
+ recordDecl(hasName("X"))))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int x;", VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int foo() { return 1 + 1; }",
+ VariantValue(VariantMatcher::SingleMatcher(functionDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ // Can't get the wrong matcher.
+ EXPECT_FALSE(VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .hasTypedMatcher<Stmt>());
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(_MSC_VER)
+ // Trying to get the wrong matcher fails an assertion in Matcher<T>. We don't
+ // do this test when building with MSVC because its debug C runtime prints the
+ // assertion failure message as a wide string, which gtest doesn't understand.
+ EXPECT_DEATH(VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .getTypedMatcher<Stmt>(),
+ "hasTypedMatcher");
+#endif
+
+ EXPECT_FALSE(matches(
+ "int x;", VariantValue(VariantMatcher::SingleMatcher(functionDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_FALSE(
+ matches("int foo() { return 1 + 1; }",
+ VariantValue(VariantMatcher::SingleMatcher(declRefExpr()))
+ .getMatcher()
+ .getTypedMatcher<Stmt>()));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile
index 2abe6eeea5b8..dad300c04d32 100644
--- a/unittests/ASTMatchers/Makefile
+++ b/unittests/ASTMatchers/Makefile
@@ -9,9 +9,11 @@
CLANG_LEVEL = ../..
+PARALLEL_DIRS = Dynamic
+
TESTNAME = ASTMatchers
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangRewriteCore.a clangRewriteFrontend.a \
clangParse.a clangSema.a clangAnalysis.a \
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index a55fcbf76cf8..f8ce50d531e7 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -24,18 +24,15 @@ class FakeStatCache : public FileSystemStatCache {
private:
// Maps a file/directory path to its desired stat result. Anything
// not in this map is considered to not exist in the file system.
- llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
+ llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
- struct stat statBuf;
- memset(&statBuf, 0, sizeof(statBuf));
- statBuf.st_dev = 1;
-#ifndef _WIN32 // struct stat has no st_ino field on Windows.
- statBuf.st_ino = INode;
-#endif
- statBuf.st_mode = IsFile ? (0777 | S_IFREG) // a regular file
- : (0777 | S_IFDIR); // a directory
- StatCalls[Path] = statBuf;
+ FileData Data;
+ memset(&Data, 0, sizeof(FileData));
+ llvm::sys::fs::UniqueID ID(1, INode);
+ Data.UniqueID = ID;
+ Data.IsDirectory = !IsFile;
+ StatCalls[Path] = Data;
}
public:
@@ -50,10 +47,10 @@ public:
}
// Implement FileSystemStatCache::getStat().
- virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- bool isFile, int *FileDescriptor) {
+ virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ int *FileDescriptor) {
if (StatCalls.count(Path) != 0) {
- StatBuf = StatCalls[Path];
+ Data = StatCalls[Path];
return CacheExists;
}
@@ -125,6 +122,14 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
FakeStatCache *statCache = new FakeStatCache;
statCache->InjectDirectory("/tmp", 42);
statCache->InjectFile("/tmp/test", 43);
+
+#ifdef _WIN32
+ const char *DirName = "C:.";
+ const char *FileName = "C:test";
+ statCache->InjectDirectory(DirName, 44);
+ statCache->InjectFile(FileName, 45);
+#endif
+
manager.addStatCache(statCache);
const FileEntry *file = manager.getFile("/tmp/test");
@@ -134,6 +139,15 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
const DirectoryEntry *dir = file->getDir();
ASSERT_TRUE(dir != NULL);
EXPECT_STREQ("/tmp", dir->getName());
+
+#ifdef _WIN32
+ file = manager.getFile(FileName);
+ ASSERT_TRUE(file != NULL);
+
+ dir = file->getDir();
+ ASSERT_TRUE(dir != NULL);
+ EXPECT_STREQ(DirName, dir->getName());
+#endif
}
// getFile() returns non-NULL if a virtual file exists at the given path.
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index 8e7f4a0371af..d94cfe9c3fab 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -73,7 +73,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
&*Target);
Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
@@ -188,7 +188,7 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
&*Target);
Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
@@ -286,7 +286,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
&*Target);
Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 334ea4142242..479b36f84c5a 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -9,10 +9,15 @@ function(add_clang_unittest test_dirname)
add_unittest(ClangUnitTests ${test_dirname} ${ARGN})
endfunction()
-add_subdirectory(ASTMatchers)
-add_subdirectory(AST)
add_subdirectory(Basic)
add_subdirectory(Lex)
-add_subdirectory(Frontend)
-add_subdirectory(Tooling)
-add_subdirectory(Format)
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ add_subdirectory(Frontend)
+endif()
+if(CLANG_ENABLE_REWRITER)
+ add_subdirectory(ASTMatchers)
+ add_subdirectory(AST)
+ add_subdirectory(Tooling)
+ add_subdirectory(Format)
+ add_subdirectory(Sema)
+endif()
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 4c948e89e980..b6574c7503aa 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -10,7 +10,6 @@
#define DEBUG_TYPE "format-test"
#include "clang/Format/Format.h"
-#include "../Tooling/RewriterTestContext.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
@@ -23,21 +22,14 @@ protected:
std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length,
const FormatStyle &Style) {
DEBUG(llvm::errs() << "---\n");
- RewriterTestContext Context;
- FileID ID = Context.createInMemoryFile("input.cc", Code);
- SourceLocation Start =
- Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(Offset);
- std::vector<CharSourceRange> Ranges(
- 1,
- CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
- Lexer Lex(ID, Context.Sources.getBuffer(ID), Context.Sources,
- getFormattingLangOpts());
- tooling::Replacements Replace = reformat(
- Style, Lex, Context.Sources, Ranges, new IgnoringDiagConsumer());
- ReplacementCount = Replace.size();
- EXPECT_TRUE(applyAllReplacements(Replace, Context.Rewrite));
- DEBUG(llvm::errs() << "\n" << Context.getRewrittenText(ID) << "\n\n");
- return Context.getRewrittenText(ID);
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ ReplacementCount = Replaces.size();
+ std::string Result = applyAllReplacements(Code, Replaces);
+ EXPECT_NE("", Result);
+ DEBUG(llvm::errs() << "\n" << Result << "\n\n");
+ return Result;
}
std::string
@@ -75,7 +67,14 @@ protected:
JustReplacedNewline = false;
}
}
- return MessedUp;
+ std::string WithoutWhitespace;
+ if (MessedUp[0] != ' ')
+ WithoutWhitespace.push_back(MessedUp[0]);
+ for (unsigned i = 1, e = MessedUp.size(); i != e; ++i) {
+ if (MessedUp[i] != ' ' || MessedUp[i - 1] != ' ')
+ WithoutWhitespace.push_back(MessedUp[i]);
+ }
+ return WithoutWhitespace;
}
FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
@@ -112,20 +111,20 @@ TEST_F(FormatTest, MessUp) {
EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n"));
EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc"));
EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc"));
- EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
+ EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
}
//===----------------------------------------------------------------------===//
// Basic function tests.
//===----------------------------------------------------------------------===//
-TEST_F(FormatTest, DoesNotChangeCorrectlyFormatedCode) {
+TEST_F(FormatTest, DoesNotChangeCorrectlyFormattedCode) {
EXPECT_EQ(";", format(";"));
}
TEST_F(FormatTest, FormatsGlobalStatementsAt0) {
EXPECT_EQ("int i;", format(" int i;"));
- EXPECT_EQ("\nint i;", format(" \n\t \r int i;"));
+ EXPECT_EQ("\nint i;", format(" \n\t \v \f int i;"));
EXPECT_EQ("int i;\nint j;", format(" int i; int j;"));
EXPECT_EQ("int i;\nint j;", format(" int i;\n int j;"));
}
@@ -147,6 +146,7 @@ TEST_F(FormatTest, FormatsNestedCall) {
TEST_F(FormatTest, NestedNameSpecifiers) {
verifyFormat("vector< ::Type> v;");
verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())");
+ verifyFormat("static constexpr bool Bar = decltype(bar())::value;");
}
TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) {
@@ -201,6 +201,53 @@ TEST_F(FormatTest, RemovesWhitespaceWhenTriggeredOnEmptyLine) {
format("int a;\n \n\n int b;", 9, 0, getLLVMStyle()));
}
+TEST_F(FormatTest, RemovesEmptyLines) {
+ EXPECT_EQ("class C {\n"
+ " int i;\n"
+ "};",
+ format("class C {\n"
+ " int i;\n"
+ "\n"
+ "};"));
+
+ // Don't remove empty lines in more complex control statements.
+ EXPECT_EQ("void f() {\n"
+ " if (a) {\n"
+ " f();\n"
+ "\n"
+ " } else if (b) {\n"
+ " f();\n"
+ " }\n"
+ "}",
+ format("void f() {\n"
+ " if (a) {\n"
+ " f();\n"
+ "\n"
+ " } else if (b) {\n"
+ " f();\n"
+ "\n"
+ " }\n"
+ "\n"
+ "}"));
+
+ // FIXME: This is slightly inconsistent.
+ EXPECT_EQ("namespace {\n"
+ "int i;\n"
+ "}",
+ format("namespace {\n"
+ "int i;\n"
+ "\n"
+ "}"));
+ EXPECT_EQ("namespace {\n"
+ "int i;\n"
+ "\n"
+ "} // namespace",
+ format("namespace {\n"
+ "int i;\n"
+ "\n"
+ "} // namespace"));
+}
+
TEST_F(FormatTest, ReformatsMovedLines) {
EXPECT_EQ(
"template <typename T> T *getFETokenInfo() const {\n"
@@ -218,25 +265,31 @@ TEST_F(FormatTest, ReformatsMovedLines) {
// Tests for control statements.
//===----------------------------------------------------------------------===//
-TEST_F(FormatTest, FormatIfWithoutCompountStatement) {
+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();");
- FormatStyle AllowsMergedIf = getGoogleStyle();
+ FormatStyle AllowsMergedIf = getLLVMStyle();
AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
verifyFormat("if (a)\n"
" // comment\n"
" f();",
AllowsMergedIf);
+ verifyFormat("if (a)\n"
+ " ;",
+ AllowsMergedIf);
+ verifyFormat("if (a)\n"
+ " if (b) return;",
+ AllowsMergedIf);
- verifyFormat("if (a) // Can't merge this\n"
+ verifyFormat("if (a) // Can't merge this\n"
" f();\n",
AllowsMergedIf);
verifyFormat("if (a) /* still don't merge */\n"
" f();",
AllowsMergedIf);
- verifyFormat("if (a) { // Never merge this\n"
+ verifyFormat("if (a) { // Never merge this\n"
" f();\n"
"}",
AllowsMergedIf);
@@ -245,6 +298,10 @@ TEST_F(FormatTest, FormatIfWithoutCompountStatement) {
"}",
AllowsMergedIf);
+ EXPECT_EQ("if (a) return;", format("if(a)\nreturn;", 7, 1, AllowsMergedIf));
+ EXPECT_EQ("if (a) return; // comment",
+ format("if(a)\nreturn; // comment", 20, 1, AllowsMergedIf));
+
AllowsMergedIf.ColumnLimit = 14;
verifyFormat("if (a) return;", AllowsMergedIf);
verifyFormat("if (aaaaaaaaa)\n"
@@ -255,6 +312,29 @@ TEST_F(FormatTest, FormatIfWithoutCompountStatement) {
verifyFormat("if (a)\n return;", AllowsMergedIf);
}
+TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) {
+ FormatStyle AllowsMergedLoops = getLLVMStyle();
+ AllowsMergedLoops.AllowShortLoopsOnASingleLine = true;
+ verifyFormat("while (true) continue;", AllowsMergedLoops);
+ verifyFormat("for (;;) continue;", AllowsMergedLoops);
+ verifyFormat("for (int &v : vec) v *= 2;", AllowsMergedLoops);
+ verifyFormat("while (true)\n"
+ " ;",
+ AllowsMergedLoops);
+ verifyFormat("for (;;)\n"
+ " ;",
+ AllowsMergedLoops);
+ verifyFormat("for (;;)\n"
+ " for (;;) continue;",
+ AllowsMergedLoops);
+ verifyFormat("for (;;) // Can't merge this\n"
+ " continue;",
+ AllowsMergedLoops);
+ verifyFormat("for (;;) /* still don't merge */\n"
+ " continue;",
+ AllowsMergedLoops);
+}
+
TEST_F(FormatTest, ParseIfElse) {
verifyFormat("if (true)\n"
" if (true)\n"
@@ -279,6 +359,11 @@ TEST_F(FormatTest, ParseIfElse) {
"else {\n"
" i();\n"
"}");
+ verifyFormat("void f() {\n"
+ " if (a) {\n"
+ " } else {\n"
+ " }\n"
+ "}");
}
TEST_F(FormatTest, ElseIf) {
@@ -289,6 +374,13 @@ TEST_F(FormatTest, ElseIf) {
" g();\n"
"else\n"
" h();");
+ verifyFormat("if (a) {\n"
+ " f();\n"
+ "}\n"
+ "// or else ..\n"
+ "else {\n"
+ " g()\n"
+ "}");
}
TEST_F(FormatTest, FormatsForLoop) {
@@ -453,6 +545,10 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
" case a: \\\n"
" foo = b; \\\n"
" }", getLLVMStyleWithColumns(20));
+ verifyFormat("#define OPERATION_CASE(name) \\\n"
+ " case OP_name: \\\n"
+ " return operations::Operation##name\n",
+ getLLVMStyleWithColumns(40));
verifyGoogleFormat("switch (x) {\n"
" case 1:\n"
@@ -473,7 +569,40 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
" }\n"
"}");
verifyGoogleFormat("switch (test)\n"
- " ;");
+ " ;");
+
+ verifyGoogleFormat("#define OPERATION_CASE(name) \\\n"
+ " case OP_name: \\\n"
+ " return operations::Operation##name\n");
+ verifyGoogleFormat("Operation codeToOperation(OperationCode OpCode) {\n"
+ " // Get the correction operation class.\n"
+ " switch (OpCode) {\n"
+ " CASE(Add);\n"
+ " CASE(Subtract);\n"
+ " default:\n"
+ " return operations::Unknown;\n"
+ " }\n"
+ "#undef OPERATION_CASE\n"
+ "}");
+ verifyFormat("DEBUG({\n"
+ " switch (x) {\n"
+ " case A:\n"
+ " f();\n"
+ " break;\n"
+ " // On B:\n"
+ " case B:\n"
+ " g();\n"
+ " break;\n"
+ " }\n"
+ "});");
+}
+
+TEST_F(FormatTest, CaseRanges) {
+ verifyFormat("switch (x) {\n"
+ "case 'A' ... 'Z':\n"
+ "case 1 ... 5:\n"
+ " break;\n"
+ "}");
}
TEST_F(FormatTest, FormatsLabels) {
@@ -505,6 +634,9 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
verifyFormat("void f() {\n"
" // Doesn't do anything\n"
"}");
+ verifyFormat("SomeObject\n"
+ " // Calling someFunction on SomeObject\n"
+ " .someFunction();");
verifyFormat("void f(int i, // some comment (probably for i)\n"
" int j, // some comment (probably for j)\n"
" int k); // some comment (probably for k)");
@@ -543,6 +675,11 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
"#include \"a/b/c\" // comment");
verifyFormat("#include <a> // comment\n"
"#include <a/b/c> // comment");
+ EXPECT_EQ("#include \"a\" // comment\n"
+ "#include \"a/b/c\" // comment",
+ format("#include \\\n"
+ " \"a\" // comment\n"
+ "#include \"a/b/c\" // comment"));
verifyFormat("enum E {\n"
" // comment\n"
@@ -571,14 +708,17 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
format("void f() { // This does something ..\n"
" }\n"
"int a; // This is unrelated"));
- EXPECT_EQ("void f() { // This does something ..\n"
- "} // awesome..\n"
+ EXPECT_EQ("class C {\n"
+ " void f() { // This does something ..\n"
+ " } // awesome..\n"
"\n"
- "int a; // This is unrelated",
- format("void f() { // This does something ..\n"
+ " int a; // This is unrelated\n"
+ "};",
+ format("class C{void f() { // This does something ..\n"
" } // awesome..\n"
" \n"
- "int a; // This is unrelated"));
+ "int a; // This is unrelated\n"
+ "};"));
EXPECT_EQ("int i; // single line trailing comment",
format("int i;\\\n// single line trailing comment"));
@@ -598,7 +738,7 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
"};");
verifyGoogleFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaa); // 81 cols with this comment");
+ " aaaaaaaaaaaaaaaaaaaaaa); // 81_cols_with_this_comment");
EXPECT_EQ("D(a, {\n"
" // test\n"
" int a;\n"
@@ -607,6 +747,66 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
"// test\n"
"int a;\n"
"});"));
+
+ EXPECT_EQ("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine();",
+ format("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine();"));
+ EXPECT_EQ("lineWith(); // comment\n"
+ " // at start\n"
+ "otherLine();",
+ format("lineWith(); // comment\n"
+ " // at start\n"
+ "otherLine();"));
+
+ EXPECT_EQ("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("lineWith();\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("lineWith();\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("// first\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("// first\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("f();\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("f();\n"
+ "// first\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ verifyFormat("f(); // comment\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine();");
+ EXPECT_EQ("f(); // comment\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine();",
+ format("f(); // comment\n"
+ "// first\n"
+ " // at start\n"
+ "otherLine();"));
+ EXPECT_EQ("f(); // comment\n"
+ " // first\n"
+ "// at start\n"
+ "otherLine();",
+ format("f(); // comment\n"
+ " // first\n"
+ "// at start\n"
+ "otherLine();"));
}
TEST_F(FormatTest, CanFormatCommentsLocally) {
@@ -636,10 +836,12 @@ TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
EXPECT_EQ("int aaaaaaa, bbbbbbb; // comment",
format("int aaaaaaa, bbbbbbb; // comment ",
getLLVMStyleWithColumns(33)));
+ EXPECT_EQ("// comment\\\n", format("// comment\\\n \t \v \f "));
+ EXPECT_EQ("// comment \\\n", format("// comment \\\n \t \v \f "));
}
-TEST_F(FormatTest, UnderstandsMultiLineComments) {
- verifyFormat("f(/*test=*/ true);");
+TEST_F(FormatTest, UnderstandsBlockComments) {
+ verifyFormat("f(/*noSpaceAfterParameterNamingComment=*/true);");
EXPECT_EQ(
"f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
" bbbbbbbbbbbbbbbbbbbbbbbbb);",
@@ -650,6 +852,15 @@ TEST_F(FormatTest, UnderstandsMultiLineComments) {
" /* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);",
format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \n"
"/* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+ EXPECT_EQ(
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
+ "}",
+ format("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa ,\n"
+ " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
+ "}"));
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackParameters = false;
@@ -660,7 +871,7 @@ TEST_F(FormatTest, UnderstandsMultiLineComments) {
NoBinPacking);
}
-TEST_F(FormatTest, AlignsMultiLineComments) {
+TEST_F(FormatTest, AlignsBlockComments) {
EXPECT_EQ("/*\n"
" * Really multi-line\n"
" * comment.\n"
@@ -696,11 +907,49 @@ TEST_F(FormatTest, AlignsMultiLineComments) {
" 1.1.1. to keep the formatting.\n"
" */"));
EXPECT_EQ("/*\n"
- " Don't try to outdent if there's not enough inentation.\n"
- " */",
+ "Don't try to outdent if there's not enough indentation.\n"
+ "*/",
format(" /*\n"
- " Don't try to outdent if there's not enough inentation.\n"
+ " Don't try to outdent if there's not enough indentation.\n"
" */"));
+
+ EXPECT_EQ("int i; /* Comment with empty...\n"
+ " *\n"
+ " * line. */",
+ format("int i; /* Comment with empty...\n"
+ " *\n"
+ " * line. */"));
+}
+
+TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) {
+ EXPECT_EQ("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */",
+ format("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */"));
+ EXPECT_EQ(
+ "void ffffffffffff(\n"
+ " int aaaaaaaa, int bbbbbbbb,\n"
+ " int cccccccccccc) { /*\n"
+ " aaaaaaaaaa\n"
+ " aaaaaaaaaaaaa\n"
+ " bbbbbbbbbbbbbb\n"
+ " bbbbbbbbbb\n"
+ " */\n"
+ "}",
+ format("void ffffffffffff(int aaaaaaaa, int bbbbbbbb, int cccccccccccc)\n"
+ "{ /*\n"
+ " aaaaaaaaaa aaaaaaaaaaaaa\n"
+ " bbbbbbbbbbbbbb bbbbbbbbbb\n"
+ " */\n"
+ "}",
+ getLLVMStyleWithColumns(40)));
+}
+
+TEST_F(FormatTest, DontBreakNonTrailingBlockComments) {
+ EXPECT_EQ("void\n"
+ "ffffffffff(int aaaaa /* test */);",
+ format("void ffffffffff(int aaaaa /* test */);",
+ getLLVMStyleWithColumns(35)));
}
TEST_F(FormatTest, SplitsLongCxxComments) {
@@ -727,10 +976,20 @@ TEST_F(FormatTest, SplitsLongCxxComments) {
EXPECT_EQ("// Don't_touch_leading_whitespace",
format("// Don't_touch_leading_whitespace",
getLLVMStyleWithColumns(20)));
- EXPECT_EQ(
- "//Don't add leading\n"
- "//whitespace",
- format("//Don't add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// Add leading\n"
+ "// whitespace",
+ format("//Add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// whitespace", format("//whitespace", getLLVMStyle()));
+ EXPECT_EQ("// Even if it makes the line exceed the column\n"
+ "// limit",
+ format("//Even if it makes the line exceed the column limit",
+ getLLVMStyleWithColumns(51)));
+ EXPECT_EQ("//--But not here", format("//--But not here", getLLVMStyle()));
+
+ EXPECT_EQ("// aa bb cc dd",
+ format("// aa bb cc dd ",
+ getLLVMStyleWithColumns(15)));
+
EXPECT_EQ("// A comment before\n"
"// a macro\n"
"// definition\n"
@@ -738,6 +997,106 @@ TEST_F(FormatTest, SplitsLongCxxComments) {
format("// A comment before a macro definition\n"
"#define a b",
getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("void ffffff(int aaaaaaaaa, // wwww\n"
+ " int a, int bbb, // xxxxxxx\n"
+ " // yyyyyyyyy\n"
+ " int c, int d, int e) {}",
+ format("void ffffff(\n"
+ " int aaaaaaaaa, // wwww\n"
+ " int a,\n"
+ " int bbb, // xxxxxxx yyyyyyyyy\n"
+ " int c, int d, int e) {}",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ format("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "#define XXX // a b c d\n"
+ " // e f g h",
+ format("#define XXX // a b c d e f g h", getLLVMStyleWithColumns(22)));
+ EXPECT_EQ(
+ "#define XXX // q w e r\n"
+ " // t y u i",
+ format("#define XXX //q w e r t y u i", getLLVMStyleWithColumns(22)));
+}
+
+TEST_F(FormatTest, DontSplitLineCommentsWithEscapedNewlines) {
+ EXPECT_EQ("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ format("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ EXPECT_EQ("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ format("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ getLLVMStyleWithColumns(50)));
+ // FIXME: One day we might want to implement adjustment of leading whitespace
+ // of the consecutive lines in this kind of comment:
+ EXPECT_EQ("int\n"
+ "a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ format("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ getLLVMStyleWithColumns(49)));
+}
+
+TEST_F(FormatTest, PriorityOfCommentBreaking) {
+ EXPECT_EQ("if (xxx ==\n"
+ " yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxx == yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("if (xxxxxxxxxx ==\n"
+ " yyy && // aaaaaa bbbbbbbb cccc\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxxxxxxxxx == yyy && // aaaaaa bbbbbbbb cccc\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("if (xxxxxxxxxx &&\n"
+ " yyy || // aaaaaa bbbbbbbb cccc\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxxxxxxxxx && yyy || // aaaaaa bbbbbbbb cccc\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("fffffffff(&xxx, // aaaaaaaaaaaa\n"
+ " // bbbbbbbbbbb\n"
+ " zzz);",
+ format("fffffffff(&xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
+ " zzz);",
+ getLLVMStyleWithColumns(40)));
+}
+
+TEST_F(FormatTest, MultiLineCommentsInDefines) {
+ EXPECT_EQ("#define A(x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ format("#define A(x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ getLLVMStyleWithColumns(17)));
+ EXPECT_EQ("#define A( \\\n"
+ " x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ format("#define A( \\\n"
+ " x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ getLLVMStyleWithColumns(17)));
}
TEST_F(FormatTest, ParsesCommentsAdjacentToPPDirectives) {
@@ -858,7 +1217,8 @@ TEST_F(FormatTest, SplitsLongLinesInComments) {
" */", getLLVMStyleWithColumns(20)));
EXPECT_EQ("{\n"
" if (something) /* This is a\n"
- "long comment */\n"
+ " long\n"
+ " comment */\n"
" ;\n"
"}",
format("{\n"
@@ -866,6 +1226,48 @@ TEST_F(FormatTest, SplitsLongLinesInComments) {
" ;\n"
"}",
getLLVMStyleWithColumns(30)));
+
+ EXPECT_EQ("/* A comment before\n"
+ " * a macro\n"
+ " * definition */\n"
+ "#define a b",
+ format("/* A comment before a macro definition */\n"
+ "#define a b",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("/* some comment\n"
+ " * a comment\n"
+ "* that we break\n"
+ " * another comment\n"
+ "* we have to break\n"
+ "* a left comment\n"
+ " */",
+ format(" /* some comment\n"
+ " * a comment that we break\n"
+ " * another comment we have to break\n"
+ "* a left comment\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("/*\n"
+ "\n"
+ "\n"
+ " */\n",
+ format(" /* \n"
+ " \n"
+ " \n"
+ " */\n"));
+
+ EXPECT_EQ("/* a a */",
+ format("/* a a */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* a a bc */",
+ format("/* a a bc */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* aaa aaa\n"
+ " * aaaaa */",
+ format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* aaa aaa\n"
+ " * aaaaa */",
+ format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
}
TEST_F(FormatTest, SplitsLongLinesInCommentsInPreprocessor) {
@@ -923,11 +1325,11 @@ TEST_F(FormatTest, CommentsInStaticInitializers) {
" // comment for bb....\n"
" bbbbbbbbbbb, ccccccccccc };");
verifyGoogleFormat(
- "static SomeType type = { aaaaaaaaaaa, // comment for aa...\n"
- " bbbbbbbbbbb, ccccccccccc };");
- verifyGoogleFormat("static SomeType type = { aaaaaaaaaaa,\n"
- " // comment for bb....\n"
- " bbbbbbbbbbb, ccccccccccc };");
+ "static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+ verifyGoogleFormat("static SomeType type = {aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc};");
verifyFormat("S s = { { a, b, c }, // Group #1\n"
" { d, e, f }, // Group #2\n"
@@ -953,11 +1355,20 @@ TEST_F(FormatTest, CommentsInStaticInitializers) {
" // Comment after empty line\n"
" b\n"
"}"));
- EXPECT_EQ("S s = { a, b };", format("S s = {\n"
- " a,\n"
- "\n"
- " b\n"
- "};"));
+ EXPECT_EQ("S s = {\n"
+ " /* Some comment */\n"
+ " a,\n"
+ "\n"
+ " /* Comment after empty line */\n"
+ " b\n"
+ "}",
+ format("S s = {\n"
+ " /* Some comment */\n"
+ " a,\n"
+ " \n"
+ " /* Comment after empty line */\n"
+ " b\n"
+ "}"));
verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
" 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
" 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
@@ -965,12 +1376,150 @@ TEST_F(FormatTest, CommentsInStaticInitializers) {
"};");
}
+TEST_F(FormatTest, IgnoresIf0Contents) {
+ EXPECT_EQ("#if 0\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f() {}",
+ format("#if 0\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f( ) { }"));
+ EXPECT_EQ("#if false\n"
+ "void f( ) { }\n"
+ "#endif\n"
+ "void g() {}\n",
+ format("#if false\n"
+ "void f( ) { }\n"
+ "#endif\n"
+ "void g( ) { }\n"));
+ EXPECT_EQ("enum E {\n"
+ " One,\n"
+ " Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five\n"
+ "};",
+ format("enum E {\n"
+ " One,Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five};"));
+ EXPECT_EQ("enum F {\n"
+ " One,\n"
+ "#if 1\n"
+ " Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five\n"
+ "#endif\n"
+ "};",
+ format("enum F {\n"
+ "One,\n"
+ "#if 1\n"
+ "Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ "Five\n"
+ "#endif\n"
+ "};"));
+ EXPECT_EQ("enum G {\n"
+ " One,\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ " Three,\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum G {\n"
+ "One,\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum H {\n"
+ " One,\n"
+ "#if 0\n"
+ "#ifdef Q\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum H {\n"
+ "One,\n"
+ "#if 0\n"
+ "#ifdef Q\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum I {\n"
+ " One,\n"
+ "#if /* test */ 0 || 1\n"
+ "Two,\n"
+ "Three,\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum I {\n"
+ "One,\n"
+ "#if /* test */ 0 || 1\n"
+ "Two,\n"
+ "Three,\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum J {\n"
+ " One,\n"
+ "#if 0\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four,\n"
+ "#endif\n"
+ " Five\n"
+ "};",
+ format("enum J {\n"
+ "One,\n"
+ "#if 0\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four,\n"
+ "#endif\n"
+ "Five\n"
+ "};"));
+
+}
+
//===----------------------------------------------------------------------===//
// Tests for classes, namespaces, etc.
//===----------------------------------------------------------------------===//
TEST_F(FormatTest, DoesNotBreakSemiAfterClassDecl) {
- verifyFormat("class A {\n};");
+ verifyFormat("class A {};");
}
TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
@@ -1009,34 +1558,49 @@ TEST_F(FormatTest, SeparatesLogicalBlocks) {
"protected:\n"
"int h;\n"
"};"));
+ EXPECT_EQ("class A {\n"
+ "protected:\n"
+ "public:\n"
+ " void f();\n"
+ "};",
+ format("class A {\n"
+ "protected:\n"
+ "\n"
+ "public:\n"
+ "\n"
+ " void f();\n"
+ "};"));
}
TEST_F(FormatTest, FormatsClasses) {
- verifyFormat("class A : public B {\n};");
- verifyFormat("class A : public ::B {\n};");
+ verifyFormat("class A : public B {};");
+ verifyFormat("class A : public ::B {};");
verifyFormat(
"class AAAAAAAAAAAAAAAAAAAA : public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,\n"
- " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {\n"
- "};\n");
+ " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {};");
verifyFormat("class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
" : public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,\n"
- " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {\n"
- "};\n");
+ " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {};");
verifyFormat(
- "class A : public B, public C, public D, public E, public F, public G {\n"
- "};");
+ "class A : public B, public C, public D, public E, public F {};");
verifyFormat("class AAAAAAAAAAAA : public B,\n"
" public C,\n"
" public D,\n"
" public E,\n"
" public F,\n"
- " public G {\n"
- "};");
+ " public G {};");
verifyFormat("class\n"
- " ReallyReallyLongClassName {\n};",
+ " ReallyReallyLongClassName {\n"
+ " int i;\n"
+ "};",
getLLVMStyleWithColumns(32));
+ verifyFormat("struct aaaaaaaaaaaaa : public aaaaaaaaaaaaaaaaaaa< // break\n"
+ " aaaaaaaaaaaaaaaa> {};");
+ verifyFormat("struct aaaaaaaaaaaaaaaaaaaa\n"
+ " : public aaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaa> {};");
}
TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) {
@@ -1054,14 +1618,82 @@ TEST_F(FormatTest, FormatsEnum) {
" Four = (Zero && (One ^ Two)) | (One << Two),\n"
" Five = (One, Two, Three, Four, 5)\n"
"};");
- verifyFormat("enum Enum {\n"
- "};");
+ verifyGoogleFormat("enum {\n"
+ " Zero,\n"
+ " One = 1,\n"
+ " Two = One + 1,\n"
+ " Three = (One + Two),\n"
+ " Four = (Zero && (One ^ Two)) | (One << Two),\n"
+ " Five = (One, Two, Three, Four, 5)\n"
+ "};");
+ verifyFormat("enum Enum {};");
+ verifyFormat("enum {};");
+ verifyFormat("enum X E {} d;");
+ verifyFormat("enum __attribute__((...)) E {} d;");
+ verifyFormat("enum __declspec__((...)) E {} d;");
+ verifyFormat("enum X f() {\n a();\n return 42;\n}");
verifyFormat("enum {\n"
+ " Bar = Foo<int, int>::value\n"
+ "};");
+}
+
+TEST_F(FormatTest, FormatsEnumsWithErrors) {
+ verifyFormat("enum Type {\n"
+ " One = 0;\n" // These semicolons should be commas.
+ " Two = 1;\n"
+ "};");
+ verifyFormat("namespace n {\n"
+ "enum Type {\n"
+ " One,\n"
+ " Two,\n" // missing };
+ " int i;\n"
+ "}\n"
+ "void g() {}");
+}
+
+TEST_F(FormatTest, FormatsEnumStruct) {
+ verifyFormat("enum struct {\n"
+ " Zero,\n"
+ " One = 1,\n"
+ " Two = One + 1,\n"
+ " Three = (One + Two),\n"
+ " Four = (Zero && (One ^ Two)) | (One << Two),\n"
+ " Five = (One, Two, Three, Four, 5)\n"
+ "};");
+ verifyFormat("enum struct Enum {};");
+ verifyFormat("enum struct {};");
+ verifyFormat("enum struct X E {} d;");
+ verifyFormat("enum struct __attribute__((...)) E {} d;");
+ verifyFormat("enum struct __declspec__((...)) E {} d;");
+ verifyFormat("enum struct X f() {\n a();\n return 42;\n}");
+}
+
+TEST_F(FormatTest, FormatsEnumClass) {
+ verifyFormat("enum class {\n"
+ " Zero,\n"
+ " One = 1,\n"
+ " Two = One + 1,\n"
+ " Three = (One + Two),\n"
+ " Four = (Zero && (One ^ Two)) | (One << Two),\n"
+ " Five = (One, Two, Three, Four, 5)\n"
+ "};");
+ verifyFormat("enum class Enum {};");
+ verifyFormat("enum class {};");
+ verifyFormat("enum class X E {} d;");
+ verifyFormat("enum class __attribute__((...)) E {} d;");
+ verifyFormat("enum class __declspec__((...)) E {} d;");
+ verifyFormat("enum class X f() {\n a();\n return 42;\n}");
+}
+
+TEST_F(FormatTest, FormatsEnumTypes) {
+ verifyFormat("enum X : int {\n"
+ " A,\n"
+ " B\n"
+ "};");
+ verifyFormat("enum X : std::uint32_t {\n"
+ " A,\n"
+ " B\n"
"};");
- verifyFormat("enum X E {\n} d;");
- verifyFormat("enum __attribute__((...)) E {\n} d;");
- verifyFormat("enum __declspec__((...)) E {\n} d;");
- verifyFormat("enum X f() {\n a();\n return 42;\n}");
}
TEST_F(FormatTest, FormatsBitfields) {
@@ -1069,33 +1701,83 @@ TEST_F(FormatTest, FormatsBitfields) {
" unsigned sClass : 8;\n"
" unsigned ValueKind : 2;\n"
"};");
+ verifyFormat("struct A {\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa : 1,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb;\n"
+ "};");
}
TEST_F(FormatTest, FormatsNamespaces) {
verifyFormat("namespace some_namespace {\n"
- "class A {\n};\n"
+ "class A {};\n"
"void f() { f(); }\n"
"}");
verifyFormat("namespace {\n"
- "class A {\n};\n"
+ "class A {};\n"
"void f() { f(); }\n"
"}");
verifyFormat("inline namespace X {\n"
- "class A {\n};\n"
+ "class A {};\n"
"void f() { f(); }\n"
"}");
verifyFormat("using namespace some_namespace;\n"
- "class A {\n};\n"
+ "class A {};\n"
"void f() { f(); }");
// This code is more common than we thought; if we
// layout this correctly the semicolon will go into
// its own line, which is undesireable.
- verifyFormat("namespace {\n};");
+ verifyFormat("namespace {};");
verifyFormat("namespace {\n"
- "class A {\n"
- "};\n"
+ "class A {};\n"
"};");
+
+ verifyFormat("namespace {\n"
+ "int SomeVariable = 0; // comment\n"
+ "} // namespace");
+ EXPECT_EQ("#ifndef HEADER_GUARD\n"
+ "#define HEADER_GUARD\n"
+ "namespace my_namespace {\n"
+ "int i;\n"
+ "} // my_namespace\n"
+ "#endif // HEADER_GUARD",
+ format("#ifndef HEADER_GUARD\n"
+ " #define HEADER_GUARD\n"
+ " namespace my_namespace {\n"
+ "int i;\n"
+ "} // my_namespace\n"
+ "#endif // HEADER_GUARD"));
+
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceIndentation = FormatStyle::NI_All;
+ EXPECT_EQ("namespace out {\n"
+ " int i;\n"
+ " namespace in {\n"
+ " int i;\n"
+ " } // namespace\n"
+ "} // namespace",
+ format("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace\n"
+ "} // namespace",
+ Style));
+
+ Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ EXPECT_EQ("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ " int i;\n"
+ "} // namespace\n"
+ "} // namespace",
+ format("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace\n"
+ "} // namespace",
+ Style));
}
TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
@@ -1106,7 +1788,7 @@ TEST_F(FormatTest, FormatsInlineASM) {
"asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n"
" \"cpuid\\n\\t\"\n"
" \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n"
- " : \"=a\" (*rEAX), \"=S\" (*rEBX), \"=c\" (*rECX), \"=d\" (*rEDX)\n"
+ " : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n"
" : \"a\"(value));");
}
@@ -1152,22 +1834,46 @@ TEST_F(FormatTest, FormatObjCTryCatch) {
TEST_F(FormatTest, StaticInitializers) {
verifyFormat("static SomeClass SC = { 1, 'a' };");
- // FIXME: Format like enums if the static initializer does not fit on a line.
verifyFormat(
"static SomeClass WithALoooooooooooooooooooongName = {\n"
" 100000000, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
"};");
- verifyFormat(
- "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n"
- " looooooooooooooooooooooooooooooooooongname,\n"
- " looooooooooooooooooooooooooooooong };");
- // Allow bin-packing in static initializers as this would often lead to
- // terrible results, e.g.:
- verifyGoogleFormat(
- "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n"
- " looooooooooooooooooooooooooooooooooongname,\n"
- " looooooooooooooooooooooooooooooong };");
+ // Here, everything other than the "}" would fit on a line.
+ verifyFormat("static int LooooooooooooooooooooooooongVariable[1] = {\n"
+ " 100000000000000000000000\n"
+ "};");
+ EXPECT_EQ("S s = { a, b };", format("S s = {\n"
+ " a,\n"
+ "\n"
+ " b\n"
+ "};"));
+
+ // FIXME: This would fit into the column limit if we'd fit "{ {" on the first
+ // line. However, the formatting looks a bit off and this probably doesn't
+ // happen often in practice.
+ verifyFormat("static int Variable[1] = {\n"
+ " { 1000000000000000000000000000000000000 }\n"
+ "};",
+ getLLVMStyleWithColumns(40));
+}
+
+TEST_F(FormatTest, DesignatedInitializers) {
+ verifyFormat("const struct A a = { .a = 1, .b = 2 };");
+ verifyFormat("const struct A a = { .aaaaaaaaaa = 1,\n"
+ " .bbbbbbbbbb = 2,\n"
+ " .cccccccccc = 3,\n"
+ " .dddddddddd = 4,\n"
+ " .eeeeeeeeee = 5 };");
+ verifyFormat("const struct Aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa = {\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaa = 1,\n"
+ " .bbbbbbbbbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " .ccccccccccccccccccccccccccc = 3,\n"
+ " .ddddddddddddddddddddddddddd = 4,\n"
+ " .eeeeeeeeeeeeeeeeeeeeeeeeeee = 5\n"
+ "};");
+
+ verifyGoogleFormat("const struct A a = {.a = 1, .b = 2};");
}
TEST_F(FormatTest, NestedStaticInitializers) {
@@ -1180,11 +1886,10 @@ TEST_F(FormatTest, NestedStaticInitializers) {
" { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n"
" { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n"
"};");
- verifyGoogleFormat("somes Status::global_reps[3] = {\n"
- " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n"
- " { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n"
- " { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n"
- "};");
+ verifyGoogleFormat("SomeType Status::global_reps[3] = {\n"
+ " {kGlobalRef, OK_CODE, NULL, NULL, NULL},\n"
+ " {kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL},\n"
+ " {kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL}};");
verifyFormat(
"CGRect cg_rect = { { rect.fLeft, rect.fTop },\n"
" { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop"
@@ -1202,15 +1907,21 @@ TEST_F(FormatTest, NestedStaticInitializers) {
" 222222222222222222222222222222,\n"
" 333333333333333333333333333333 } },\n"
" { { 1, 2, 3 } }, { { 1, 2, 3 } } };");
+ verifyGoogleFormat(
+ "SomeArrayOfSomeType a = {\n"
+ " {{1, 2, 3}}, {{1, 2, 3}},\n"
+ " {{111111111111111111111111111111, 222222222222222222222222222222,\n"
+ " 333333333333333333333333333333}},\n"
+ " {{1, 2, 3}}, {{1, 2, 3}}};");
- // FIXME: We might at some point want to handle this similar to parameter
- // lists, where we have an option to put each on a single line.
verifyFormat(
"struct {\n"
" unsigned bit;\n"
" const char *const name;\n"
- "} kBitsToOs[] = { { kOsMac, \"Mac\" }, { kOsWin, \"Windows\" },\n"
- " { kOsLinux, \"Linux\" }, { kOsCrOS, \"Chrome OS\" } };");
+ "} kBitsToOs[] = { { kOsMac, \"Mac\" },\n"
+ " { kOsWin, \"Windows\" },\n"
+ " { kOsLinux, \"Linux\" },\n"
+ " { kOsCrOS, \"Chrome OS\" } };");
}
TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) {
@@ -1220,14 +1931,28 @@ TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) {
}
TEST_F(FormatTest, DoesNotBreakPureVirtualFunctionDefinition) {
- verifyFormat(
- "virtual void write(ELFWriter *writerrr,\n"
- " OwningPtr<FileOutputBuffer> &buffer) = 0;");
+ verifyFormat("virtual void write(ELFWriter *writerrr,\n"
+ " OwningPtr<FileOutputBuffer> &buffer) = 0;");
}
-TEST_F(FormatTest, LayoutUnknownPPDirective) {
- EXPECT_EQ("#123 \"A string literal\"",
+TEST_F(FormatTest, BreaksStringLiteralsOnlyInDefine) {
+ verifyFormat("# 1111 \"/aaaaaaaaa/aaaaaaaaaaaaaaaaaaa/aaaaaaaa.cpp\" 2 3",
+ getLLVMStyleWithColumns(40));
+ verifyFormat("#line 11111 \"/aaaaaaaaa/aaaaaaaaaaaaaaaaaaa/aaaaaaaa.cpp\"",
+ getLLVMStyleWithColumns(40));
+ EXPECT_EQ("#define Q \\\n"
+ " \"/aaaaaaaaa/aaaaaaaaaaaaaaaaaaa/\" \\\n"
+ " \"aaaaaaaa.cpp\"",
+ format("#define Q \"/aaaaaaaaa/aaaaaaaaaaaaaaaaaaa/aaaaaaaa.cpp\"",
+ getLLVMStyleWithColumns(40)));
+}
+
+TEST_F(FormatTest, UnderstandsLinePPDirective) {
+ EXPECT_EQ("# 123 \"A string literal\"",
format(" # 123 \"A string literal\""));
+}
+
+TEST_F(FormatTest, LayoutUnknownPPDirective) {
EXPECT_EQ("#;", format("#;"));
verifyFormat("#\n;\n;\n;");
}
@@ -1245,12 +1970,22 @@ TEST_F(FormatTest, EndOfFileEndsPPDirective) {
EXPECT_EQ("#define A B", format("# \\\n define \\\n A \\\n B"));
}
+TEST_F(FormatTest, DoesntRemoveUnknownTokens) {
+ verifyFormat("#define A \\x20");
+ verifyFormat("#define A \\ x20");
+ EXPECT_EQ("#define A \\ x20", format("#define A \\ x20"));
+ verifyFormat("#define A ''");
+ verifyFormat("#define A ''qqq");
+ verifyFormat("#define A `qqq");
+ verifyFormat("f(\"aaaa, bbbb, \"\\\"ccccc\\\"\");");
+}
+
TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {
verifyFormat("#define A(BB)", getLLVMStyleWithColumns(13));
verifyFormat("#define A( \\\n BB)", getLLVMStyleWithColumns(12));
verifyFormat("#define A( \\\n A, B)", getLLVMStyleWithColumns(12));
// FIXME: We never break before the macro name.
- verifyFormat("#define AA(\\\n B)", getLLVMStyleWithColumns(12));
+ verifyFormat("#define AA( \\\n B)", getLLVMStyleWithColumns(12));
verifyFormat("#define A A\n#define A A");
verifyFormat("#define A(X) A\n#define A A");
@@ -1289,9 +2024,29 @@ TEST_F(FormatTest, LayoutCodeInMacroDefinitions) {
TEST_F(FormatTest, LayoutRemainingTokens) { EXPECT_EQ("{}", format("{}")); }
-TEST_F(FormatTest, LayoutSingleUnwrappedLineInMacro) {
- EXPECT_EQ("# define A\\\n b;",
- format("# define A b;", 11, 2, getLLVMStyleWithColumns(11)));
+TEST_F(FormatTest, AlwaysFormatsEntireMacroDefinitions) {
+ EXPECT_EQ("int i;\n"
+ "#define A \\\n"
+ " int i; \\\n"
+ " int j\n"
+ "int k;",
+ format("int i;\n"
+ "#define A \\\n"
+ " int i ; \\\n"
+ " int j\n"
+ "int k;",
+ 8, 0, getGoogleStyle())); // 8: position of "#define".
+ EXPECT_EQ("int i;\n"
+ "#define A \\\n"
+ " int i; \\\n"
+ " int j\n"
+ "int k;",
+ format("int i;\n"
+ "#define A \\\n"
+ " int i ; \\\n"
+ " int j\n"
+ "int k;",
+ 45, 0, getGoogleStyle())); // 45: position of "j".
}
TEST_F(FormatTest, MacroDefinitionInsideStatement) {
@@ -1302,10 +2057,11 @@ TEST_F(FormatTest, MacroDefinitionInsideStatement) {
}
TEST_F(FormatTest, HashInMacroDefinition) {
+ EXPECT_EQ("#define A(c) L#c", format("#define A(c) L#c", getLLVMStyle()));
verifyFormat("#define A \\\n b #c;", getLLVMStyleWithColumns(11));
- verifyFormat("#define A \\\n"
- " { \\\n"
- " f(#c);\\\n"
+ verifyFormat("#define A \\\n"
+ " { \\\n"
+ " f(#c); \\\n"
" }",
getLLVMStyleWithColumns(11));
@@ -1351,24 +2107,59 @@ TEST_F(FormatTest, EmptyLinesInMacroDefinitions) {
TEST_F(FormatTest, MacroDefinitionsWithIncompleteCode) {
verifyFormat("#define A :");
-
- // FIXME: Improve formatting of case labels in macros.
verifyFormat("#define SOMECASES \\\n"
" case 1: \\\n"
" case 2\n",
getLLVMStyleWithColumns(20));
-
verifyFormat("#define A template <typename T>");
verifyFormat("#define STR(x) #x\n"
"f(STR(this_is_a_string_literal{));");
+ verifyFormat("#pragma omp threadprivate( \\\n"
+ " y)), // expected-warning",
+ getLLVMStyleWithColumns(28));
+}
+
+TEST_F(FormatTest, MacrosWithoutTrailingSemicolon) {
+ verifyFormat("SOME_TYPE_NAME abc;"); // Gated on the newline.
+ EXPECT_EQ("class A : public QObject {\n"
+ " Q_OBJECT\n"
+ "\n"
+ " A() {}\n"
+ "};",
+ format("class A : public QObject {\n"
+ " Q_OBJECT\n"
+ "\n"
+ " A() {\n}\n"
+ "} ;"));
+ EXPECT_EQ("SOME_MACRO\n"
+ "namespace {\n"
+ "void f();\n"
+ "}",
+ format("SOME_MACRO\n"
+ " namespace {\n"
+ "void f( );\n"
+ "}"));
+ // Only if the identifier contains at least 5 characters.
+ EXPECT_EQ("HTTP f();",
+ format("HTTP\nf();"));
+ EXPECT_EQ("MACRO\nf();",
+ format("MACRO\nf();"));
+ // Only if everything is upper case.
+ EXPECT_EQ("class A : public QObject {\n"
+ " Q_Object A() {}\n"
+ "};",
+ format("class A : public QObject {\n"
+ " Q_Object\n"
+ "\n"
+ " A() {\n}\n"
+ "} ;"));
}
TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
EXPECT_EQ("INITIALIZE_PASS_BEGIN(ScopDetection, \"polly-detect\")\n"
"INITIALIZE_AG_DEPENDENCY(AliasAnalysis)\n"
"INITIALIZE_PASS_DEPENDENCY(DominatorTree)\n"
- "class X {\n"
- "};\n"
+ "class X {};\n"
"INITIALIZE_PASS_END(ScopDetection, \"polly-detect\")\n"
"int *createScopDetectionPass() { return 0; }",
format(" INITIALIZE_PASS_BEGIN(ScopDetection, \"polly-detect\")\n"
@@ -1389,6 +2180,8 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
" IPC_MESSAGE_HANDLER(xxx, qqq)\n"
" IPC_END_MESSAGE_MAP()\n"
"}"));
+
+ // These must not be recognized as macros.
EXPECT_EQ("int q() {\n"
" f(x);\n"
" f(x) {}\n"
@@ -1472,6 +2265,13 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
"};"));
}
+TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
+ verifyFormat("#define A \\\n"
+ " f({ \\\n"
+ " g(); \\\n"
+ " });", getLLVMStyleWithColumns(11));
+}
+
TEST_F(FormatTest, IndentPreprocessorDirectivesAtZero) {
EXPECT_EQ("{\n {\n#define A\n }\n}", format("{{\n#define A\n}}"));
}
@@ -1487,10 +2287,15 @@ TEST_F(FormatTest, FormatUnbalancedStructuralElements) {
format("#define A } }\nint i;", getLLVMStyleWithColumns(11)));
}
-TEST_F(FormatTest, EscapedNewlineAtStartOfTokenInMacroDefinition) {
+TEST_F(FormatTest, EscapedNewlineAtStartOfToken) {
EXPECT_EQ(
"#define A \\\n int i; \\\n int j;",
format("#define A \\\nint i;\\\n int j;", getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("template <class T> f();", format("\\\ntemplate <class T> f();"));
+}
+
+TEST_F(FormatTest, NoEscapedNewlineHandlingInBlockComments) {
+ EXPECT_EQ("/* \\ \\ \\\n*/", format("\\\n/* \\ \\ \\\n*/"));
}
TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
@@ -1521,7 +2326,7 @@ TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
EXPECT_EQ("int\n"
"#define A\n"
" a;",
- format("int\n#define A\na;"));
+ format("int\n#define A\na;", getGoogleStyle()));
verifyFormat("functionCallTo(\n"
" someOtherFunction(\n"
" withSomeParameters, whichInSequence,\n"
@@ -1532,13 +2337,106 @@ TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
" andMoreParameters),\n"
" trailing);",
getLLVMStyleWithColumns(69));
+ verifyFormat("Foo::Foo()\n"
+ "#ifdef BAR\n"
+ " : baz(0)\n"
+ "#endif\n"
+ "{\n"
+ "}");
+ verifyFormat("void f() {\n"
+ " if (true)\n"
+ "#ifdef A\n"
+ " f(42);\n"
+ " x();\n"
+ "#else\n"
+ " g();\n"
+ " x();\n"
+ "#endif\n"
+ "}");
+ verifyFormat("void f(param1, param2,\n"
+ " param3,\n"
+ "#ifdef A\n"
+ " param4(param5,\n"
+ "#ifdef A1\n"
+ " param6,\n"
+ "#ifdef A2\n"
+ " param7),\n"
+ "#else\n"
+ " param8),\n"
+ " param9,\n"
+ "#endif\n"
+ " param10,\n"
+ "#endif\n"
+ " param11)\n"
+ "#else\n"
+ " param12)\n"
+ "#endif\n"
+ "{\n"
+ " x();\n"
+ "}",
+ getLLVMStyleWithColumns(28));
+ verifyFormat("#if 1\n"
+ "int i;");
+ verifyFormat(
+ "#if 1\n"
+ "#endif\n"
+ "#if 1\n"
+ "#else\n"
+ "#endif\n");
+ verifyFormat("DEBUG({\n"
+ " return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;\n"
+ "});\n"
+ "#if a\n"
+ "#else\n"
+ "#endif");
+}
+
+TEST_F(FormatTest, FormatsJoinedLinesOnSubsequentRuns) {
+ FormatStyle SingleLine = getLLVMStyle();
+ SingleLine.AllowShortIfStatementsOnASingleLine = true;
+ verifyFormat(
+ "#if 0\n"
+ "#elif 1\n"
+ "#endif\n"
+ "void foo() {\n"
+ " if (test) foo2();\n"
+ "}",
+ SingleLine);
}
TEST_F(FormatTest, LayoutBlockInsideParens) {
+ EXPECT_EQ("functionCall({ int i; });", format(" functionCall ( {int i;} );"));
+ EXPECT_EQ("functionCall({\n"
+ " int i;\n"
+ " int j;\n"
+ "});",
+ format(" functionCall ( {int i;int j;} );"));
EXPECT_EQ("functionCall({\n"
+ " int i;\n"
+ " int j;\n"
+ " },\n"
+ " aaaa, bbbb, cccc);",
+ format(" functionCall ( {int i;int j;}, aaaa, bbbb, cccc);"));
+ EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
+ format(" functionCall (aaaa, bbbb, {int i;});"));
+ EXPECT_EQ("functionCall(aaaa, bbbb, {\n"
" int i;\n"
+ " int j;\n"
"});",
- format(" functionCall ( {int i;} );"));
+ format(" functionCall (aaaa, bbbb, {int i;int j;});"));
+ EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
+ format(" functionCall (aaaa, bbbb, {int i;});"));
+ verifyFormat(
+ "Aaa({\n"
+ " int i; // break\n"
+ " },\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " ccccccccccccccccc));");
+ verifyFormat("DEBUG({\n"
+ " if (a)\n"
+ " f();\n"
+ "});");
}
TEST_F(FormatTest, LayoutBlockInsideStatement) {
@@ -1556,15 +2454,87 @@ TEST_F(FormatTest, LayoutNestedBlocks) {
" for (int i = 0; i < 10; ++i)\n"
" return;\n"
"}");
+ verifyFormat("call(parameter, {\n"
+ " something();\n"
+ " // Comment using all columns.\n"
+ " somethingelse();\n"
+ "});",
+ getLLVMStyleWithColumns(40));
+ EXPECT_EQ("call(parameter, {\n"
+ " something();\n"
+ " // Comment too\n"
+ " // looooooooooong.\n"
+ " somethingElse();\n"
+ "});",
+ format("call(parameter, {\n"
+ " something();\n"
+ " // Comment too looooooooooong.\n"
+ " somethingElse();\n"
+ "});",
+ getLLVMStyleWithColumns(29)));
+ EXPECT_EQ("DEBUG({ int i; });", format("DEBUG({ int i; });"));
+ EXPECT_EQ("DEBUG({ // comment\n"
+ " int i;\n"
+ "});",
+ format("DEBUG({ // comment\n"
+ "int i;\n"
+ "});"));
+ EXPECT_EQ("DEBUG({\n"
+ " int i;\n"
+ "\n"
+ " // comment\n"
+ " int j;\n"
+ "});",
+ format("DEBUG({\n"
+ " int i;\n"
+ "\n"
+ " // comment\n"
+ " int j;\n"
+ "});"));
+
+ verifyFormat("DEBUG({\n"
+ " if (a)\n"
+ " return;\n"
+ "});");
+ verifyGoogleFormat("DEBUG({\n"
+ " if (a) return;\n"
+ "});");
+ FormatStyle Style = getGoogleStyle();
+ Style.ColumnLimit = 45;
+ verifyFormat("Debug(aaaaa, {\n"
+ " if (aaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " return;\n"
+ " },\n"
+ " a);", Style);
+
+ EXPECT_EQ("Debug({\n"
+ " if (aaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " return;\n"
+ " },\n"
+ " a);",
+ format("Debug({\n"
+ " if (aaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " return;\n"
+ " },\n"
+ " a);",
+ 50, 1, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, IndividualStatementsOfNestedBlocks) {
+ EXPECT_EQ("DEBUG({\n"
+ " int i;\n"
+ " int j;\n"
+ "});",
+ format("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ 40, 1, getLLVMStyle()));
}
TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
EXPECT_EQ("{}", format("{}"));
-
- // Negative test for enum.
- verifyFormat("enum E {\n};");
-
- // Note that when there's a missing ';', we still join...
+ verifyFormat("enum E {};");
verifyFormat("enum E {}");
}
@@ -1572,30 +2542,23 @@ TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
// Line break tests.
//===----------------------------------------------------------------------===//
-TEST_F(FormatTest, FormatsFunctionDefinition) {
- verifyFormat("void f(int a, int b, int c, int d, int e, int f, int g,"
- " int h, int j, int f,\n"
- " int c, int ddddddddddddd) {}");
-}
-
-TEST_F(FormatTest, FormatsAwesomeMethodCall) {
- verifyFormat(
- "SomeLongMethodName(SomeReallyLongMethod(CallOtherReallyLongMethod(\n"
- " parameter, parameter, parameter)),\n"
- " SecondLongCall(parameter));");
-}
-
TEST_F(FormatTest, PreventConfusingIndents) {
verifyFormat(
+ "void f() {\n"
+ " SomeLongMethodName(SomeReallyLongMethod(CallOtherReallyLongMethod(\n"
+ " parameter, parameter, parameter)),\n"
+ " SecondLongCall(parameter));\n"
+ "}");
+ verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[\n"
- " aaaaaaaaaaaaaaaaaaaaaaaa[\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa],\n"
- " aaaaaaaaaaaaaaaaaaaaaaaa];");
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaa]];");
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n"
" aaaaaaaaaaaaaaaaaaaaaaaa<\n"
@@ -1606,6 +2569,75 @@ TEST_F(FormatTest, PreventConfusingIndents) {
" ddd);");
}
+TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
+ verifyFormat(
+ "bool aaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaa).aaaaaaaaaaaaaaaaaaa() ||\n"
+ " bbbbbbbb();");
+ verifyFormat("bool aaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa != bbbbbbbbbbbbbbbbbb &&\n"
+ " ccccccccc == ddddddddddd;");
+
+ verifyFormat("aaaaaa = aaaaaaa(aaaaaaa, // break\n"
+ " aaaaaa) &&\n"
+ " bbbbbb && cccccc;");
+ verifyFormat("aaaaaa = aaaaaaa(aaaaaaa, // break\n"
+ " aaaaaa) >>\n"
+ " bbbbbb;");
+ verifyFormat("Whitespaces.addUntouchableComment(\n"
+ " SourceMgr.getSpellingColumnNumber(\n"
+ " TheLine.Last->FormatTok.Tok.getLocation()) -\n"
+ " 1);");
+
+ verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " bbbbbbbbbbbbbbbbbb) && // aaaaaaaaaaaaaaaa\n"
+ " cccccc) {\n}");
+
+ // If the LHS of a comparison is not a binary expression itself, the
+ // additional linebreak confuses many people.
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) > 5) {\n"
+ "}");
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n"
+ "}");
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n"
+ "}");
+ // Even explicit parentheses stress the precedence enough to make the
+ // additional break unnecessary.
+ verifyFormat(
+ "if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n"
+ "}");
+ // This cases is borderline, but with the indentation it is still readable.
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaa) > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
+ "}",
+ getLLVMStyleWithColumns(75));
+
+ // If the LHS is a binary expression, we should still use the additional break
+ // as otherwise the formatting hides the operator precedence.
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==\n"
+ " 5) {\n"
+ "}");
+
+ FormatStyle OnePerLine = getLLVMStyle();
+ OnePerLine.BinPackParameters = false;
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}",
+ OnePerLine);
+}
+
TEST_F(FormatTest, ExpressionIndentation) {
verifyFormat("bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
@@ -1628,6 +2660,66 @@ TEST_F(FormatTest, ExpressionIndentation) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
+ verifyFormat("if () {\n"
+ "} else if (aaaaa && bbbbb > // break\n"
+ " ccccc) {\n"
+ "}");
+
+ // Presence of a trailing comment used to change indentation of b.
+ verifyFormat("return aaaaaaaaaaaaaaaaaaa +\n"
+ " b;\n"
+ "return aaaaaaaaaaaaaaaaaaa +\n"
+ " b; //",
+ getLLVMStyleWithColumns(30));
+}
+
+TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
+ // Not sure what the best system is here. Like this, the LHS can be found
+ // immediately above an operator (everything with the same or a higher
+ // indent). The RHS is aligned right of the operator and so compasses
+ // everything until something with the same indent as the operator is found.
+ // FIXME: Is this a good system?
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = true;
+ verifyFormat(
+ "bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " > ccccccccccccccccccccccccccccccccccccccccc;",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if () {\n"
+ "} else if (aaaaa && bbbbb // break\n"
+ " > ccccc) {\n"
+ "}",
+ Style);
+
+ // Forced by comments.
+ verifyFormat(
+ "unsigned ContentSize =\n"
+ " sizeof(int16_t) // DWARF ARange version number\n"
+ " + sizeof(int32_t) // Offset of CU in the .debug_info section\n"
+ " + sizeof(int8_t) // Pointer Size (in bytes)\n"
+ " + sizeof(int8_t); // Segment Size (in bytes)");
}
TEST_F(FormatTest, ConstructorInitializers) {
@@ -1667,6 +2759,13 @@ TEST_F(FormatTest, ConstructorInitializers) {
verifyFormat("Constructor(int Parameter = 0)\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaa(aaaaaaaaaaaaaaaaa) {}");
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbbbbb(b) {\n"
+ "}",
+ getLLVMStyleWithColumns(60));
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa(aaaa, aaaa)) {}");
// Here a line could be saved by splitting the second initializer onto two
// lines, but that is not desireable.
@@ -1723,6 +2822,53 @@ TEST_F(FormatTest, MemoizationTests) {
" aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(\n"
" aaaaa())))))))))))))))))))))))))))))))))))))));",
getLLVMStyleWithColumns(65));
+ verifyFormat(
+ "aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa))))))))))));",
+ getLLVMStyleWithColumns(65));
+ verifyFormat(
+ "a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(), a), a), a), a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a),\n"
+ " a)",
+ getLLVMStyleWithColumns(65));
// This test takes VERY long when memoization is broken.
FormatStyle OnePerLine = getLLVMStyle();
@@ -1753,22 +2899,29 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
// 1) break amongst arguments.
verifyFormat("Aaaaaaaaaaaaaa bbbbbbbbbbbbbb(Cccccccccccccc cccccccccccccc,\n"
" Cccccccccccccc cccccccccccccc);");
+ verifyFormat(
+ "template <class TemplateIt>\n"
+ "SomeReturnType SomeFunction(TemplateIt begin, TemplateIt end,\n"
+ " TemplateIt *stop) {}");
// 2) break after return type.
verifyFormat(
- "Aaaaaaaaaaaaaaaaaaaaaaaa\n"
- " bbbbbbbbbbbbbb(Cccccccccccccc cccccccccccccccccccccccccc);");
+ "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " bbbbbbbbbbbbbb(Cccccccccccccc cccccccccccccccccccccccccc);",
+ getGoogleStyle());
// 3) break after (.
verifyFormat(
"Aaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb(\n"
- " Cccccccccccccccccccccccccccccc cccccccccccccccccccccccccccccccc);");
+ " Cccccccccccccccccccccccccccccc cccccccccccccccccccccccccccccccc);",
+ getGoogleStyle());
// 4) break before after nested name specifiers.
verifyFormat(
"Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" SomeClasssssssssssssssssssssssssssssssssssssss::\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(Cccccccccccccc cccccccccc);");
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(Cccccccccccccc cccccccccc);",
+ getGoogleStyle());
// However, there are exceptions, if a sufficient amount of lines can be
// saved.
@@ -1780,10 +2933,11 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
" Cccccccccccccc cccccccccc,\n"
" Cccccccccccccc cccccccccc);");
verifyFormat(
- "Aaaaaaaaaaaaaaaaaa\n"
+ "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" bbbbbbbbbbb(Cccccccccccccc cccccccccc, Cccccccccccccc cccccccccc,\n"
" Cccccccccccccc cccccccccc, Cccccccccccccc cccccccccc,\n"
- " Cccccccccccccc cccccccccc, Cccccccccccccc cccccccccc);");
+ " Cccccccccccccc cccccccccc, Cccccccccccccc cccccccccc);",
+ getGoogleStyle());
verifyFormat(
"Aaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(Cccccccccccccc cccccccccc,\n"
" Cccccccccccccc cccccccccc,\n"
@@ -1803,6 +2957,85 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" bbbb bbbb);");
+
+ // Treat overloaded operators like other functions.
+ verifyFormat("SomeLoooooooooooooooooooooooooogType\n"
+ "operator>(const SomeLoooooooooooooooooooooooooogType &other);");
+ verifyFormat("SomeLoooooooooooooooooooooooooogType\n"
+ "operator>>(const SomeLooooooooooooooooooooooooogType &other);");
+ verifyGoogleFormat(
+ "SomeLoooooooooooooooooooooooooooooogType operator<<(\n"
+ " const SomeLooooooooogType &a, const SomeLooooooooogType &b);");
+}
+
+TEST_F(FormatTest, TrailingReturnType) {
+ verifyFormat("auto foo() -> int;\n");
+ verifyFormat("struct S {\n"
+ " auto bar() const -> int;\n"
+ "};");
+ verifyFormat("template <size_t Order, typename T>\n"
+ "auto load_img(const std::string &filename)\n"
+ " -> alias::tensor<Order, T, mem::tag::cpu> {}");
+
+ // Not trailing return types.
+ verifyFormat("void f() { auto a = b->c(); }");
+}
+
+TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
+ // Avoid breaking before trailing 'const' or other trailing annotations, if
+ // they are not function-like.
+ FormatStyle Style = getGoogleStyle();
+ Style.ColumnLimit = 47;
+ verifyFormat("void\n"
+ "someLongFunction(int someLongParameter) const {\n}",
+ getLLVMStyleWithColumns(47));
+ verifyFormat("LoooooongReturnType\n"
+ "someLoooooooongFunction() const {}",
+ getLLVMStyleWithColumns(47));
+ verifyFormat("LoooooongReturnType someLoooooooongFunction()\n"
+ " const {}",
+ Style);
+ verifyFormat("void SomeFunction(aaaaa aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaa aaaaaaaaaaaaaaaaaaaa) OVERRIDE;");
+ verifyFormat("void SomeFunction(aaaaa aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaa aaaaaaaaaaaaaaaaaaaa) OVERRIDE FINAL;");
+ verifyFormat("void SomeFunction(aaaaa aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaa aaaaaaaaaaaaaaaaaaaa) override final;");
+
+ // Unless this would lead to the first parameter being broken.
+ verifyFormat("void someLongFunction(int someLongParameter)\n"
+ " const {}",
+ getLLVMStyleWithColumns(46));
+ verifyFormat("void someLongFunction(int someLongParameter)\n"
+ " const {}",
+ Style);
+ verifyFormat("void SomeFunction(aaaaaaaaaa aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " LONG_AND_UGLY_ANNOTATION;");
+
+ // Breaking before function-like trailing annotations is fine to keep them
+ // close to their arguments.
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}");
+
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaa()\n"
+ " __attribute__((aaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " __attribute__((unused));");
+ verifyFormat(
+ "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " GUARDED_BY(aaaaaaaaaaaa);",
+ getGoogleStyle());
+ verifyFormat(
+ "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " GUARDED_BY(aaaaaaaaaaaa);",
+ getGoogleStyle());
}
TEST_F(FormatTest, BreaksDesireably) {
@@ -1842,9 +3075,15 @@ TEST_F(FormatTest, BreaksDesireably) {
"aaaaaa(aaa, new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
verifyFormat(
- "aaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ "aaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ // Indent consistently indenpendent of call expression.
+ verifyFormat("aaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbb.ccccccccccccccccc(\n"
+ " dddddddddddddddddddddddddddddd));\n"
+ "aaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(\n"
+ " dddddddddddddddddddddddddddddd));");
// This test case breaks on an incorrect memoization, i.e. an optimization not
// taking into account the StopAt value.
@@ -1859,6 +3098,20 @@ TEST_F(FormatTest, BreaksDesireably) {
" Line.Tokens[i - 1].Tok.isNot(tok::l_paren) &&\n"
" Line.Tokens[i - 1].Tok.isNot(tok::l_square);\n"
" }\n }\n}");
+
+ // Break on an outer level if there was a break on an inner level.
+ EXPECT_EQ("f(g(h(a, // comment\n"
+ " b, c),\n"
+ " d, e),\n"
+ " x, y);",
+ format("f(g(h(a, // comment\n"
+ " b, c), d, e), x, y);"));
+
+ // Prefer breaking similar line breaks.
+ verifyFormat(
+ "const int kTrackingOptions = NSTrackingMouseMoved |\n"
+ " NSTrackingMouseEnteredAndExited |\n"
+ " NSTrackingActiveAlways;");
}
TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
@@ -1882,8 +3135,10 @@ TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
verifyFormat("aaaaaaaaaaaaaaa(aaaaaaaaa, aaaaaaaaa, aaaaaaaaaaaaaaaaaaaaa)\n"
" .aaaaaaaaaaaaaaaaaa();",
NoBinPacking);
- verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaa);",
+ verifyFormat("void f() {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaa);\n"
+ "}",
NoBinPacking);
verifyFormat(
@@ -1916,48 +3171,104 @@ TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
" .aaaaaaa();\n"
"}",
NoBinPacking);
+ verifyFormat(
+ "template <class SomeType, class SomeOtherType>\n"
+ "SomeType SomeFunction(SomeType Type, SomeOtherType OtherType) {}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, AdaptiveOnePerLineFormatting) {
+ FormatStyle Style = getLLVMStyleWithColumns(15);
+ Style.ExperimentalAutoDetectBinPacking = true;
+ EXPECT_EQ("aaa(aaaa,\n"
+ " aaaa,\n"
+ " aaaa);\n"
+ "aaa(aaaa,\n"
+ " aaaa,\n"
+ " aaaa);",
+ format("aaa(aaaa,\n" // one-per-line
+ " aaaa,\n"
+ " aaaa );\n"
+ "aaa(aaaa, aaaa, aaaa);", // inconclusive
+ Style));
+ EXPECT_EQ("aaa(aaaa, aaaa,\n"
+ " aaaa);\n"
+ "aaa(aaaa, aaaa,\n"
+ " aaaa);",
+ format("aaa(aaaa, aaaa,\n" // bin-packed
+ " aaaa );\n"
+ "aaa(aaaa, aaaa, aaaa);", // inconclusive
+ Style));
}
TEST_F(FormatTest, FormatsBuilderPattern) {
verifyFormat(
"return llvm::StringSwitch<Reference::Kind>(name)\n"
" .StartsWith(\".eh_frame_hdr\", ORDER_EH_FRAMEHDR)\n"
- " .StartsWith(\".eh_frame\", ORDER_EH_FRAME).StartsWith(\".init\", ORDER_INIT)\n"
- " .StartsWith(\".fini\", ORDER_FINI).StartsWith(\".hash\", ORDER_HASH)\n"
+ " .StartsWith(\".eh_frame\", ORDER_EH_FRAME)\n"
+ " .StartsWith(\".init\", ORDER_INIT)\n"
+ " .StartsWith(\".fini\", ORDER_FINI)\n"
+ " .StartsWith(\".hash\", ORDER_HASH)\n"
" .Default(ORDER_TEXT);\n");
-
+
verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n"
" aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();");
verifyFormat(
- "aaaaaaa->aaaaaaa\n"
- " ->aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ "aaaaaaa->aaaaaaa->aaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" ->aaaaaaaa(aaaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n"
" aaaaaaaaaaaaaa);");
verifyFormat(
- "aaaaaaaaaaaaaaaaaaaaaaa *aaaaaaaaa = aaaaaa->aaaaaaaaaaaa()\n"
- " ->aaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
- " ->aaaaaaaaaaaaaaaaa();");
-}
+ "aaaaaaaaaaaaaaaaaaaaaaa *aaaaaaaaa =\n"
+ " aaaaaa->aaaaaaaaaaaa()\n"
+ " ->aaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " ->aaaaaaaaaaaaaaaaa();");
+ verifyGoogleFormat(
+ "void f() {\n"
+ " someo->Add((new util::filetools::Handler(dir))\n"
+ " ->OnEvent1(NewPermanentCallback(\n"
+ " this, &HandlerHolderClass::EventHandlerCBA))\n"
+ " ->OnEvent2(NewPermanentCallback(\n"
+ " this, &HandlerHolderClass::EventHandlerCBB))\n"
+ " ->OnEvent3(NewPermanentCallback(\n"
+ " this, &HandlerHolderClass::EventHandlerCBC))\n"
+ " ->OnEvent5(NewPermanentCallback(\n"
+ " this, &HandlerHolderClass::EventHandlerCBD))\n"
+ " ->OnEvent6(NewPermanentCallback(\n"
+ " this, &HandlerHolderClass::EventHandlerCBE)));\n"
+ "}");
-TEST_F(FormatTest, DoesNotBreakTrailingAnnotation) {
- verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
- " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
- verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
- " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
- verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
- " LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}");
verifyFormat(
- "void aaaaaaaaaaaaaaaaaa()\n"
- " __attribute__((aaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaa));");
- verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " __attribute__((unused));");
- verifyFormat(
- "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " GUARDED_BY(aaaaaaaaaaaa);");
+ "aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaa->aaaaaaaaaaaaaaaaaaaaaaaa()\n"
+ " ->aaaaaaaaaaaaaae(0)\n"
+ " ->aaaaaaaaaaaaaaa();");
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaa()\n"
+ " .has<bbbbbbbbbbbbbbbbbbbbb>();");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>();");
+
+ // Prefer not to break after empty parentheses.
+ verifyFormat("FirstToken->WhitespaceRange.getBegin().getLocWithOffset(\n"
+ " First->LastNewlineOffset);");
}
TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {
@@ -1990,8 +3301,12 @@ TEST_F(FormatTest, BreaksAfterAssignments) {
" Line.Tokens.front().Tok.getLo(), Line.Tokens.back().Tok.getLoc());");
verifyFormat(
- "aaaaaaaaaaaaaaaaaaaaaaaaaa aaaa = aaaaaaaaaaaaaa(0).aaaa()\n"
- " .aaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaaaaaaa);");
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa aaaa = aaaaaaaaaaaaaa(0).aaaa().aaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("unsigned OriginalStartColumn =\n"
+ " SourceMgr.getSpellingColumnNumber(\n"
+ " Current.FormatTok.getStartOfNonWhitespace()) -\n"
+ " 1;");
}
TEST_F(FormatTest, AlignsAfterAssignments) {
@@ -2007,9 +3322,10 @@ TEST_F(FormatTest, AlignsAfterAssignments) {
verifyFormat(
"int Result = (aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" aaaaaaaaaaaaaaaaaaaaaaaaa);");
- verifyFormat("double LooooooooooooooooooooooooongResult =\n"
- " aaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaa +\n"
- " aaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "double LooooooooooooooooooooooooongResult = aaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa;");
}
TEST_F(FormatTest, AlignsAfterReturn) {
@@ -2030,13 +3346,16 @@ TEST_F(FormatTest, AlignsAfterReturn) {
verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) &&\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat("return\n"
+ " // true if code is one of a or b.\n"
+ " code == a || code == b;");
}
TEST_F(FormatTest, BreaksConditionalExpressions) {
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
"aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
@@ -2048,6 +3367,10 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" aaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa ?: aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa);");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
@@ -2060,7 +3383,11 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaa);");
-
+ verifyFormat("aaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ?: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" ? aaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaa;");
@@ -2083,6 +3410,16 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" : TheLine * 2,\n"
" TheLine.InPPDirective, PreviousEndOfLineColumn);",
getLLVMStyleWithColumns(70));
+ verifyFormat("bool aaaaaa = aaaaaaaaaaaaa //\n"
+ " ? aaaaaaaaaaaaaaa\n"
+ " : bbbbbbbbbbbbbbb //\n"
+ " ? ccccccccccccccc\n"
+ " : ddddddddddddddd;");
+ verifyFormat("bool aaaaaa = aaaaaaaaaaaaa //\n"
+ " ? aaaaaaaaaaaaaaa\n"
+ " : (bbbbbbbbbbbbbbb //\n"
+ " ? ccccccccccccccc\n"
+ " : ddddddddddddddd);");
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackParameters = false;
@@ -2095,6 +3432,102 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" : aaaaaaaaaaaaaaa);\n"
"}",
NoBinPacking);
+ verifyFormat(
+ "void f() {\n"
+ " g(aaa,\n"
+ " aaaaaaaaaa == aaaaaaaaaa ? aaaa : aaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ?: aaaaaaaaaaaaaaa);\n"
+ "}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeTernaryOperators = false;
+ Style.ColumnLimit = 70;
+ verifyFormat(
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa ? aaaa(aaaaaa) :\n"
+ " aaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa ?: aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa);",
+ Style);
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat("aaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat("aaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?:\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ Style);
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ Style);
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaa;",
+ Style);
+ verifyFormat("f(aaaaaaaaaaaaaaaa == // force break\n"
+ " aaaaaaaaa ?\n"
+ " b :\n"
+ " c);",
+ Style);
+ verifyFormat(
+ "unsigned Indent =\n"
+ " format(TheLine.First, IndentForLevel[TheLine.Level] >= 0 ?\n"
+ " IndentForLevel[TheLine.Level] :\n"
+ " TheLine * 2,\n"
+ " TheLine.InPPDirective, PreviousEndOfLineColumn);",
+ Style);
+ verifyFormat("bool aaaaaa = aaaaaaaaaaaaa ? //\n"
+ " aaaaaaaaaaaaaaa :\n"
+ " bbbbbbbbbbbbbbb ? //\n"
+ " ccccccccccccccc :\n"
+ " ddddddddddddddd;",
+ Style);
+ verifyFormat("bool aaaaaa = aaaaaaaaaaaaa ? //\n"
+ " aaaaaaaaaaaaaaa :\n"
+ " (bbbbbbbbbbbbbbb ? //\n"
+ " ccccccccccccccc :\n"
+ " ddddddddddddddd);",
+ Style);
}
TEST_F(FormatTest, DeclarationsOfMultipleVariables) {
@@ -2118,9 +3551,10 @@ TEST_F(FormatTest, DeclarationsOfMultipleVariables) {
" ***c = ccccccccccccccccccc, ***d = ddddddddddddddd;");
// FIXME: If multiple variables are defined, the "*" needs to move to the new
// line. Also fix indent for breaking after the type, this looks bad.
- verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *\n"
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n"
- " *b = bbbbbbbbbbbbbbbbbbb;");
+ " *b = bbbbbbbbbbbbbbbbbbb;",
+ getGoogleStyle());
// Not ideal, but pointer-with-type does not allow much here.
verifyGoogleFormat(
@@ -2161,11 +3595,78 @@ TEST_F(FormatTest, AlignsStringLiterals) {
verifyFormat("a = a + \"a\"\n"
" \"a\"\n"
" \"a\";");
+ verifyFormat("f(\"a\", \"b\"\n"
+ " \"c\");");
verifyFormat(
"#define LL_FORMAT \"ll\"\n"
"printf(\"aaaaa: %d, bbbbbb: %\" LL_FORMAT \"d, cccccccc: %\" LL_FORMAT\n"
" \"d, ddddddddd: %\" LL_FORMAT \"d\");");
+
+ verifyFormat("#define A(X) \\\n"
+ " \"aaaaa\" #X \"bbbbbb\" \\\n"
+ " \"ccccc\"",
+ getLLVMStyleWithColumns(23));
+ verifyFormat("#define A \"def\"\n"
+ "f(\"abc\" A \"ghi\"\n"
+ " \"jkl\");");
+}
+
+TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) {
+ FormatStyle NoBreak = getLLVMStyle();
+ NoBreak.AlwaysBreakBeforeMultilineStrings = false;
+ FormatStyle Break = getLLVMStyle();
+ Break.AlwaysBreakBeforeMultilineStrings = true;
+ verifyFormat("aaaa = \"bbbb\"\n"
+ " \"cccc\";",
+ NoBreak);
+ verifyFormat("aaaa =\n"
+ " \"bbbb\"\n"
+ " \"cccc\";",
+ Break);
+ verifyFormat("aaaa(\"bbbb\"\n"
+ " \"cccc\");",
+ NoBreak);
+ verifyFormat("aaaa(\n"
+ " \"bbbb\"\n"
+ " \"cccc\");",
+ Break);
+ verifyFormat("aaaa(qqq, \"bbbb\"\n"
+ " \"cccc\");",
+ NoBreak);
+ verifyFormat("aaaa(qqq,\n"
+ " \"bbbb\"\n"
+ " \"cccc\");",
+ Break);
+
+ // Don't break if there is no column gain.
+ verifyFormat("f(\"aaaa\"\n"
+ " \"bbbb\");",
+ Break);
+
+ // Treat literals with escaped newlines like multi-line string literals.
+ EXPECT_EQ("x = \"a\\\n"
+ "b\\\n"
+ "c\";",
+ format("x = \"a\\\n"
+ "b\\\n"
+ "c\";",
+ NoBreak));
+ EXPECT_EQ("x =\n"
+ " \"a\\\n"
+ "b\\\n"
+ "c\";",
+ format("x = \"a\\\n"
+ "b\\\n"
+ "c\";",
+ Break));
+
+ // Exempt ObjC strings for now.
+ EXPECT_EQ("NSString *const kString = @\"aaaa\"\n"
+ " \"bbbb\";",
+ format("NSString *const kString = @\"aaaa\"\n"
+ "\"bbbb\";",
+ Break));
}
TEST_F(FormatTest, AlignsPipes) {
@@ -2189,12 +3690,15 @@ TEST_F(FormatTest, AlignsPipes) {
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
verifyFormat("return out << \"somepacket = {\\n\"\n"
- " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
- " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n"
- " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n"
- " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n"
+ " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
+ " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n"
+ " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n"
+ " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n"
" << \"}\";");
+ verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa;");
verifyFormat(
"llvm::outs() << \"aaaaaaaaaaaaaaaaa = \" << aaaaaaaaaaaaaaaaa\n"
" << \"bbbbbbbbbbbbbbbbb = \" << bbbbbbbbbbbbbbbbb\n"
@@ -2203,10 +3707,43 @@ TEST_F(FormatTest, AlignsPipes) {
" << \"eeeeeeeeeeeeeeeee = \" << eeeeeeeeeeeeeeeee;");
verifyFormat("llvm::outs() << aaaaaaaaaaaaaaaaaaaaaaaa << \"=\"\n"
" << bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat(
+ "void f() {\n"
+ " llvm::outs() << \"aaaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ "}");
+
+ // Breaking before the first "<<" is generally not desirable.
+ verifyFormat(
+ "llvm::errs()\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getLLVMStyleWithColumns(70));
+ verifyFormat("llvm::errs() << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getLLVMStyleWithColumns(70));
+
+ // But sometimes, breaking before the first "<<" is desirable.
+ verifyFormat("Diag(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb)\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat("SemaRef.Diag(Loc, diag::note_for_range_begin_end)\n"
+ " << BEF << IsTemplate << Description << E->getType();");
verifyFormat(
"llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+
+ // Incomplete string literal.
+ EXPECT_EQ("llvm::errs() << \"\n"
+ " << a;",
+ format("llvm::errs() << \"\n<<a;"));
}
TEST_F(FormatTest, UnderstandsEquals) {
@@ -2254,12 +3791,19 @@ TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) {
" .WillRepeatedly(Return(SomeValue));");
verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)]\n"
" .insert(ccccccccccccccccccccccc);");
+ verifyFormat("aaaaa(aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa).aaaaa(aaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("void f() {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa)->aaaaaaaaa());\n"
+ "}");
verifyFormat(
"aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
- " .aaaaaaaaaaaaaaa(\n"
- " aa(aaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+ " .aaaaaaaaaaaaaaa(aa(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa));");
verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
@@ -2294,11 +3838,23 @@ TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) {
" aaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
NoBinPacking);
+
+ // If there is a subsequent call, change to hanging indentation.
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa))\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa));");
}
TEST_F(FormatTest, WrapsTemplateDeclarations) {
verifyFormat("template <typename T>\n"
"virtual void loooooooooooongFunction(int Param1, int Param2);");
+ verifyFormat("template <typename T>\n"
+ "// T should be one of {A, B}.\n"
+ "virtual void loooooooooooongFunction(int Param1, int Param2);");
verifyFormat(
"template <typename T>\n"
"using comment_to_xml_conversion = comment_to_xml_conversion<T, int>;");
@@ -2325,8 +3881,39 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
"aaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa>(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
- verifyFormat("a<aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa>(\n"
- " a(aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa));");
+ verifyFormat("void f() {\n"
+ " a<aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa>(\n"
+ " a(aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa));\n"
+ "}");
+
+ verifyFormat("template <typename T> class C {};");
+ verifyFormat("template <typename T> void f();");
+ verifyFormat("template <typename T> void f() {}");
+ verifyFormat(
+ "aaaaaaaaaaaaa<aaaaaaaaaa, aaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> *aaaa =\n"
+ " new aaaaaaaaaaaaa<aaaaaaaaaa, aaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>(\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbb);",
+ getLLVMStyleWithColumns(72));
+
+ FormatStyle AlwaysBreak = getLLVMStyle();
+ AlwaysBreak.AlwaysBreakTemplateDeclarations = true;
+ verifyFormat("template <typename T>\nclass C {};", AlwaysBreak);
+ verifyFormat("template <typename T>\nvoid f();", AlwaysBreak);
+ verifyFormat("template <typename T>\nvoid f() {}", AlwaysBreak);
+ verifyFormat("void aaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbb>(\n"
+ " ccccccccccccccccccccccccccccccccccccccccccccccc);");
+ verifyFormat("template <template <typename> class Fooooooo,\n"
+ " template <typename> class Baaaaaaar>\n"
+ "struct C {};",
+ AlwaysBreak);
+ verifyFormat("template <typename T> // T can be A, B or C.\n"
+ "struct C {};",
+ AlwaysBreak);
}
TEST_F(FormatTest, WrapsAtNestedNameSpecifiers) {
@@ -2338,14 +3925,12 @@ TEST_F(FormatTest, WrapsAtNestedNameSpecifiers) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa());");
- // FIXME: Should we have an extra indent after the second break?
+ // FIXME: Should we have the extra indent after the second break?
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
- // FIXME: Look into whether we should indent 4 from the start or 4 from
- // "bbbbb..." here instead of what we are doing now.
verifyFormat(
"aaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb::\n"
" cccccccccccccccccccccccccccccccccccccccccccccc());");
@@ -2383,14 +3968,33 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyGoogleFormat("A<A<int> > a;");
verifyGoogleFormat("A<A<A<int> > > a;");
verifyGoogleFormat("A<A<A<A<int> > > > a;");
+ verifyGoogleFormat("A<::A<int>> a;");
+ verifyGoogleFormat("A<::A> a;");
+ verifyGoogleFormat("A< ::A> a;");
+ verifyGoogleFormat("A< ::A<int> > a;");
EXPECT_EQ("A<A<A<A>>> a;", format("A<A<A<A> >> a;", getGoogleStyle()));
EXPECT_EQ("A<A<A<A>>> a;", format("A<A<A<A>> > a;", getGoogleStyle()));
+ EXPECT_EQ("A<::A<int>> a;", format("A< ::A<int>> a;", getGoogleStyle()));
+ EXPECT_EQ("A<::A<int>> a;", format("A<::A<int> > a;", getGoogleStyle()));
verifyFormat("test >> a >> b;");
verifyFormat("test << a >> b;");
verifyFormat("f<int>();");
verifyFormat("template <typename T> void f() {}");
+
+ // Not template parameters.
+ verifyFormat("return a < b && c > d;");
+ verifyFormat("void f() {\n"
+ " while (a < b && c > d) {\n"
+ " }\n"
+ "}");
+ verifyFormat("template <typename... Types>\n"
+ "typename enable_if<0 < sizeof...(Types)>::type Foo() {}");
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaa);",
+ getLLVMStyleWithColumns(60));
}
TEST_F(FormatTest, UnderstandsBinaryOperators) {
@@ -2399,14 +4003,23 @@ TEST_F(FormatTest, UnderstandsBinaryOperators) {
TEST_F(FormatTest, UnderstandsPointersToMembers) {
verifyFormat("int A::*x;");
- // FIXME: Recognize pointers to member functions.
- //verifyFormat("int (S::*func)(void *);");
- verifyFormat("int(S::*func)(void *);");
- verifyFormat("(a->*f)();");
- verifyFormat("a->*x;");
- verifyFormat("(a.*f)();");
- verifyFormat("((*a).*f)();");
- verifyFormat("a.*x;");
+ verifyFormat("int (S::*func)(void *);");
+ verifyFormat("void f() { int (S::*func)(void *); }");
+ verifyFormat("typedef bool *(Class::*Member)() const;");
+ verifyFormat("void f() {\n"
+ " (a->*f)();\n"
+ " a->*x;\n"
+ " (a.*f)();\n"
+ " ((*a).*f)();\n"
+ " a.*x;\n"
+ "}");
+ verifyFormat("void f() {\n"
+ " (a->*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)(\n"
+ " aaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);\n"
+ "}");
+ FormatStyle Style = getLLVMStyle();
+ Style.PointerBindsToType = true;
+ verifyFormat("typedef bool* (Class::*Member)() const;", Style);
}
TEST_F(FormatTest, UnderstandsUnaryOperators) {
@@ -2427,9 +4040,9 @@ TEST_F(FormatTest, UnderstandsUnaryOperators) {
verifyFormat("a-- > b;");
verifyFormat("b ? -a : c;");
verifyFormat("n * sizeof char16;");
- verifyFormat("n * alignof char16;");
+ verifyFormat("n * alignof char16;", getGoogleStyle());
verifyFormat("sizeof(char);");
- verifyFormat("alignof(char);");
+ verifyFormat("alignof(char);", getGoogleStyle());
verifyFormat("return -1;");
verifyFormat("switch (a) {\n"
@@ -2447,7 +4060,19 @@ TEST_F(FormatTest, UnderstandsUnaryOperators) {
verifyFormat("int a = i /* confusing comment */++;");
}
-TEST_F(FormatTest, UndestandsOverloadedOperators) {
+TEST_F(FormatTest, IndentsRelativeToUnaryOperators) {
+ verifyFormat("if (!aaaaaaaaaa( // break\n"
+ " aaaaa)) {\n"
+ "}");
+ verifyFormat("aaaaaaaaaa(!aaaaaaaaaa( // break\n"
+ " aaaaa));");
+
+ // Only indent relative to unary operators if the expression is nested.
+ verifyFormat("*aaa = aaaaaaa( // break\n"
+ " bbbbbb);");
+}
+
+TEST_F(FormatTest, UnderstandsOverloadedOperators) {
verifyFormat("bool operator<();");
verifyFormat("bool operator>();");
verifyFormat("bool operator=();");
@@ -2468,6 +4093,8 @@ TEST_F(FormatTest, UndestandsOverloadedOperators) {
verifyFormat("void *operator new[](std::size_t size);");
verifyFormat("void operator delete(void *ptr);");
verifyFormat("void operator delete[](void *ptr);");
+ verifyFormat("template <typename AAAAAAA, typename BBBBBBB>\n"
+ "AAAAAAA operator/(const AAAAAAA &a, BBBBBBB &b);");
verifyFormat(
"ostream &operator<<(ostream &OutputStream,\n"
@@ -2480,6 +4107,9 @@ TEST_F(FormatTest, UndestandsOverloadedOperators) {
verifyGoogleFormat("operator void*();");
verifyGoogleFormat("operator SomeType<SomeType<int>>();");
+ verifyGoogleFormat("operator ::A();");
+
+ verifyFormat("using A::operator+;");
}
TEST_F(FormatTest, UnderstandsNewAndDelete) {
@@ -2529,12 +4159,14 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("return sizeof(int **);");
verifyIndependentOfContext("return sizeof(int ******);");
verifyIndependentOfContext("return (int **&)a;");
+ verifyIndependentOfContext("f((*PointerToArray)[10]);");
verifyFormat("void f(Type (*parameter)[10]) {}");
verifyGoogleFormat("return sizeof(int**);");
verifyIndependentOfContext("Type **A = static_cast<Type **>(P);");
verifyGoogleFormat("Type** A = static_cast<Type**>(P);");
- // FIXME: The newline is wrong.
- verifyFormat("auto a = [](int **&, int ***) {}\n;");
+ verifyFormat("auto a = [](int **&, int ***) {};");
+ verifyFormat("auto PointerBinding = [](const char *S) {};");
+ verifyFormat("typedef typeof(int(int, int)) *MyFunc;");
verifyIndependentOfContext("InvalidRegions[*R] = 0;");
@@ -2587,22 +4219,47 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("if (*b[i])");
verifyIndependentOfContext("if (int *a = (&b))");
verifyIndependentOfContext("while (int *a = &b)");
+ verifyIndependentOfContext("size = sizeof *a;");
verifyFormat("void f() {\n"
" for (const int &v : Values) {\n"
" }\n"
"}");
verifyFormat("for (int i = a * a; i < 10; ++i) {\n}");
verifyFormat("for (int i = 0; i < a * a; ++i) {\n}");
+ verifyGoogleFormat("for (int i = 0; i * 2 < z; i *= 2) {\n}");
+
+ verifyFormat("#define A (!a * b)");
+ verifyFormat("#define MACRO \\\n"
+ " int *i = a * b; \\\n"
+ " void f(a *b);",
+ getLLVMStyleWithColumns(19));
verifyIndependentOfContext("A = new SomeType *[Length];");
verifyIndependentOfContext("A = new SomeType *[Length]();");
+ verifyIndependentOfContext("T **t = new T *;");
+ verifyIndependentOfContext("T **t = new T *();");
verifyGoogleFormat("A = new SomeType* [Length]();");
verifyGoogleFormat("A = new SomeType* [Length];");
+ verifyGoogleFormat("T** t = new T*;");
+ verifyGoogleFormat("T** t = new T*();");
+
+ FormatStyle PointerLeft = getLLVMStyle();
+ PointerLeft.PointerBindsToType = true;
+ verifyFormat("delete *x;", PointerLeft);
+}
+
+TEST_F(FormatTest, UnderstandsAttributes) {
+ verifyFormat("SomeType s __attribute__((unused)) (InitValue);");
}
TEST_F(FormatTest, UnderstandsEllipsis) {
verifyFormat("int printf(const char *fmt, ...);");
verifyFormat("template <class... Ts> void Foo(Ts... ts) { Foo(ts...); }");
+ verifyFormat("template <class... Ts> void Foo(Ts *... ts) {}");
+
+ FormatStyle PointersLeft = getLLVMStyle();
+ PointersLeft.PointerBindsToType = true;
+ verifyFormat("template <class... Ts> void Foo(Ts*... ts) {}", PointersLeft);
}
TEST_F(FormatTest, AdaptivelyFormatsPointersAndReferences) {
@@ -2636,12 +4293,17 @@ TEST_F(FormatTest, UnderstandsRvalueReferences) {
verifyGoogleFormat("int f(int a, char&& b) {}");
verifyGoogleFormat("void f() { int&& a = b; }");
- // FIXME: These require somewhat deeper changes in template arguments
- // formatting.
- // verifyIndependentOfContext("A<int &&> a;");
- // verifyIndependentOfContext("A<int &&, int &&> a;");
- // verifyGoogleFormat("A<int&&> a;");
- // verifyGoogleFormat("A<int&&, int&&> a;");
+ verifyIndependentOfContext("A<int &&> a;");
+ verifyIndependentOfContext("A<int &&, int &&> a;");
+ verifyGoogleFormat("A<int&&> a;");
+ verifyGoogleFormat("A<int&&, int&&> a;");
+
+ // Not rvalue references:
+ verifyFormat("template <bool B, bool C> class A {\n"
+ " static_assert(B && C, \"Something is wrong\");\n"
+ "};");
+ verifyGoogleFormat("#define IF(a, b, c) if (a && (b == c))");
+ verifyGoogleFormat("#define WHILE(a, b, c) while (a && (b == c))");
}
TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
@@ -2657,10 +4319,33 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("Type *A = (Type *)P;");
verifyFormat("Type *A = (vector<Type *, int *>)P;");
verifyFormat("int a = (int)(2.0f);");
-
- // FIXME: These also need to be identified.
- verifyFormat("int a = (int) 2.0f;");
- verifyFormat("int a = (int) * b;");
+ verifyFormat("int a = (int)2.0f;");
+ verifyFormat("x[(int32)y];");
+ verifyFormat("x = (int32)y;");
+ verifyFormat("#define AA(X) sizeof(((X *)NULL)->a)");
+ verifyFormat("int a = (int)*b;");
+ verifyFormat("int a = (int)2.0f;");
+ verifyFormat("int a = (int)~0;");
+ verifyFormat("int a = (int)++a;");
+ verifyFormat("int a = (int)sizeof(int);");
+ verifyFormat("int a = (int)+2;");
+ verifyFormat("my_int a = (my_int)2.0f;");
+ verifyFormat("my_int a = (my_int)sizeof(int);");
+ verifyFormat("return (my_int)aaa;");
+ verifyFormat("#define x ((int)-1)");
+ verifyFormat("#define p(q) ((int *)&q)");
+
+ // FIXME: Without type knowledge, this can still fall apart miserably.
+ verifyFormat("void f() { my_int a = (my_int) * b; }");
+ verifyFormat("void f() { return P ? (my_int) * P : (my_int)0; }");
+ verifyFormat("my_int a = (my_int) ~0;");
+ verifyFormat("my_int a = (my_int)++ a;");
+ verifyFormat("my_int a = (my_int) + 2;");
+
+ // Don't break after a cast's
+ verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " (aaaaaaaaaaaaaaaaaaaaaaaaaa *)(aaaaaaaaaaaaaaaaaaaaaa +\n"
+ " bbbbbbbbbbbbbbbbbbbbbb);");
// These are not casts.
verifyFormat("void f(int *) {}");
@@ -2668,7 +4353,7 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("f(foo).b;");
verifyFormat("f(foo)(b);");
verifyFormat("f(foo)[b];");
- verifyFormat("[](foo) { return 4; }(bar)];");
+ verifyFormat("[](foo) { return 4; }(bar);");
verifyFormat("(*funptr)(foo)[4];");
verifyFormat("funptrs[4](foo)[4];");
verifyFormat("void f(int *);");
@@ -2679,44 +4364,76 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("void f(int i = (kValue) * kMask) {}");
verifyFormat("void f(int i = (kA * kB) & kMask) {}");
verifyFormat("int a = sizeof(int) * b;");
- verifyFormat("int a = alignof(int) * b;");
+ verifyFormat("int a = alignof(int) * b;", getGoogleStyle());
+ verifyFormat("template <> void f<int>(int i) SOME_ANNOTATION;");
+ verifyFormat("f(\"%\" SOME_MACRO(ll) \"d\");");
+ verifyFormat("aaaaa &operator=(const aaaaa &) LLVM_DELETED_FUNCTION;");
// These are not casts, but at some point were confused with casts.
verifyFormat("virtual void foo(int *) override;");
verifyFormat("virtual void foo(char &) const;");
verifyFormat("virtual void foo(int *a, char *) const;");
verifyFormat("int a = sizeof(int *) + b;");
- verifyFormat("int a = alignof(int *) + b;");
+ verifyFormat("int a = alignof(int *) + b;", getGoogleStyle());
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *foo = (aaaaaaaaaaaaaaaaa *)\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ // FIXME: The indentation here is not ideal.
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = (*cccccccccccccccc)\n"
+ " [dddddddddddddddddddddddddddddddddddddddddddddddddddddddd];");
}
TEST_F(FormatTest, FormatsFunctionTypes) {
verifyFormat("A<bool()> a;");
verifyFormat("A<SomeType()> a;");
- verifyFormat("A<void(*)(int, std::string)> a;");
+ verifyFormat("A<void (*)(int, std::string)> a;");
verifyFormat("A<void *(int)>;");
verifyFormat("void *(*a)(int *, SomeType *);");
-
- // FIXME: Inconsistent.
verifyFormat("int (*func)(void *);");
- verifyFormat("void f() { int(*func)(void *); }");
+ verifyFormat("void f() { int (*func)(void *); }");
+ verifyFormat("template <class CallbackClass>\n"
+ "using MyCallback = void (CallbackClass::*)(SomeObject *Data);");
verifyGoogleFormat("A<void*(int*, SomeType*)>;");
verifyGoogleFormat("void* (*a)(int);");
+ verifyGoogleFormat(
+ "template <class CallbackClass>\n"
+ "using MyCallback = void (CallbackClass::*)(SomeObject* Data);");
+
+ // Other constructs can look somewhat like function types:
+ verifyFormat("A<sizeof(*x)> a;");
+ verifyFormat("#define DEREF_AND_CALL_F(x) f(*x)");
+ verifyFormat("some_var = function(*some_pointer_var)[0];");
+ verifyFormat("void f() { function(*some_pointer_var)[0] = 10; }");
}
TEST_F(FormatTest, BreaksLongDeclarations) {
verifyFormat("typedef LoooooooooooooooooooooooooooooooooooooooongType\n"
- " AnotherNameForTheLongType;");
+ " AnotherNameForTheLongType;",
+ getGoogleStyle());
+ verifyFormat("typedef LongTemplateType<aaaaaaaaaaaaaaaaaaa()>\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getGoogleStyle());
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n"
- " LoooooooooooooooooooooooooooooooooooooooongVariable;");
+ " LoooooooooooooooooooooooooooooooooooooooongVariable;",
+ getGoogleStyle());
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType const\n"
+ " LoooooooooooooooooooooooooooooooooooooooongVariable;",
+ getGoogleStyle());
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n"
- " LoooooooooooooooooooooooooooooooongFunctionDeclaration();");
+ " LoooooooooooooooooooooooooooooooongFunctionDeclaration();",
+ getGoogleStyle());
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n"
"LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}");
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType const\n"
+ "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}");
// FIXME: Without the comment, this breaks after "(".
- verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType // break\n"
- " (*LoooooooooooooooooooooooooooongFunctionTypeVarialbe)();");
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType // break\n"
+ " (*LoooooooooooooooooooooooooooongFunctionTypeVarialbe)();",
+ getGoogleStyle());
verifyFormat("int *someFunction(int LoooooooooooooooooooongParam1,\n"
" int LoooooooooooooooooooongParam2) {}");
@@ -2731,10 +4448,14 @@ TEST_F(FormatTest, BreaksLongDeclarations) {
" ReallyReallyLongParameterName,\n"
" const SomeType<string, SomeOtherTemplateParameter> &\n"
" AnotherLongParameterName) {}");
- verifyFormat(
+ verifyFormat("template <typename A>\n"
+ "SomeLoooooooooooooooooooooongType<\n"
+ " typename some_namespace::SomeOtherType<A>::Type>\n"
+ "Function() {}");
+
+ verifyGoogleFormat(
"aaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaa<aaaaaaaaaaaaa, aaaaaaaaaaaa>\n"
" aaaaaaaaaaaaaaaaaaaaaaa;");
-
verifyGoogleFormat(
"TypeSpecDecl* TypeSpecDecl::Create(ASTContext& C, DeclContext* DC,\n"
" SourceLocation L) {}");
@@ -2750,6 +4471,22 @@ TEST_F(FormatTest, BreaksLongDeclarations) {
" int aaaaaaaaaaaaaaaaaaaaaaa);");
}
+TEST_F(FormatTest, FormatsArrays) {
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]\n"
+ " [bbbbbbbbbbbbbbbbbbbbbbbbb] = c;");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [a][bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = cccccccc;");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]\n"
+ " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;");
+ verifyFormat(
+ "llvm::outs() << \"aaaaaaaaaaaa: \"\n"
+ " << (*aaaaaaaiaaaaaaa)[aaaaaaaaaaaaaaaaaaaaaaaaa]\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
+}
+
TEST_F(FormatTest, LineStartsWithSpecialCharacter) {
verifyFormat("(a)->b();");
verifyFormat("--a;");
@@ -2764,14 +4501,20 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
"#include <a-a>\n"
"#include < path with space >\n"
"#include \"abc.h\" // this is included for ABC\n"
+ "#include \"some long include\" // with a comment\n"
"#include \"some very long include paaaaaaaaaaaaaaaaaaaaaaath\"",
getLLVMStyleWithColumns(35));
+ EXPECT_EQ("#include \"a.h\"", format("#include \"a.h\""));
+ EXPECT_EQ("#include <a>", format("#include<a>"));
verifyFormat("#import <string>");
verifyFormat("#import <a/b/c.h>");
verifyFormat("#import \"a/b/string\"");
verifyFormat("#import \"string.h\"");
verifyFormat("#import \"string.h\"");
+ verifyFormat("#if __has_include(<strstream>)\n"
+ "#include <strstream>\n"
+ "#endif");
}
//===----------------------------------------------------------------------===//
@@ -2813,7 +4556,10 @@ TEST_F(FormatTest, IncorrectCodeMissingSemicolon) {
" return\n"
"}",
format("void f ( ) { if ( a ) return }"));
- EXPECT_EQ("namespace N { void f() }", format("namespace N { void f() }"));
+ EXPECT_EQ("namespace N {\n"
+ "void f()\n"
+ "}",
+ format("namespace N { void f() }"));
EXPECT_EQ("namespace N {\n"
"void f() {}\n"
"void g()\n"
@@ -2874,20 +4620,22 @@ TEST_F(FormatTest, IncorrectCodeMissingParens) {
TEST_F(FormatTest, DoesNotTouchUnwrappedLinesWithErrors) {
verifyFormat("namespace {\n"
- "class Foo { Foo ( }; } // comment");
+ "class Foo { Foo (\n"
+ "};\n"
+ "} // comment");
}
TEST_F(FormatTest, IncorrectCodeErrorDetection) {
- EXPECT_EQ("{\n{}\n", format("{\n{\n}\n"));
+ EXPECT_EQ("{\n {}\n", format("{\n{\n}\n"));
EXPECT_EQ("{\n {}\n", format("{\n {\n}\n"));
EXPECT_EQ("{\n {}\n", format("{\n {\n }\n"));
- EXPECT_EQ("{\n {}\n }\n}\n", format("{\n {\n }\n }\n}\n"));
+ EXPECT_EQ("{\n {}\n}\n}\n", format("{\n {\n }\n }\n}\n"));
EXPECT_EQ("{\n"
- " {\n"
- " breakme(\n"
- " qwe);\n"
- "}\n",
+ " {\n"
+ " breakme(\n"
+ " qwe);\n"
+ " }\n",
format("{\n"
" {\n"
" breakme(qwe);\n"
@@ -2907,14 +4655,119 @@ TEST_F(FormatTest, LayoutBraceInitializersInReturnStatement) {
verifyFormat("return (a)(b) { 1, 2, 3 };");
}
-TEST_F(FormatTest, LayoutTokensFollowingBlockInParentheses) {
- // FIXME: This is bad, find a better and more generic solution.
+TEST_F(FormatTest, LayoutCxx11ConstructorBraceInitializers) {
+ verifyFormat("vector<int> x{ 1, 2, 3, 4 };");
+ verifyFormat("vector<T> x{ {}, {}, {}, {} };");
+ verifyFormat("f({ 1, 2 });");
+ verifyFormat("auto v = Foo{ 1 };");
+ verifyFormat("f({ 1, 2 }, { { 2, 3 }, { 4, 5 } }, c, { d });");
+ verifyFormat("Class::Class : member{ 1, 2, 3 } {}");
+ verifyFormat("new vector<int>{ 1, 2, 3 };");
+ verifyFormat("new int[3]{ 1, 2, 3 };");
+ verifyFormat("return { arg1, arg2 };");
+ verifyFormat("return { arg1, SomeType{ parameter } };");
+ verifyFormat("new T{ arg1, arg2 };");
+ verifyFormat("f(MyMap[{ composite, key }]);");
+ verifyFormat("class Class {\n"
+ " T member = { arg1, arg2 };\n"
+ "};");
+ verifyFormat(
+ "foo = aaaaaaaaaaa ? vector<int>{ aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa, aaaaa }\n"
+ " : vector<int>{ bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " bbbbbbbbbbbbbbbbbbbb, bbbbb };");
+ verifyFormat("DoSomethingWithVector({} /* No data */);");
+ verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });");
+ verifyFormat(
+ "someFunction(OtherParam, BracedList{\n"
+ " // comment 1 (Forcing interesting break)\n"
+ " param1, param2,\n"
+ " // comment 2\n"
+ " param3, param4\n"
+ " });");
+ verifyFormat(
+ "std::this_thread::sleep_for(\n"
+ " std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);");
+
+ FormatStyle NoSpaces = getLLVMStyle();
+ NoSpaces.Cpp11BracedListStyle = true;
+ verifyFormat("vector<int> x{1, 2, 3, 4};", NoSpaces);
+ verifyFormat("vector<T> x{{}, {}, {}, {}};", NoSpaces);
+ verifyFormat("f({1, 2});", NoSpaces);
+ verifyFormat("auto v = Foo{-1};", NoSpaces);
+ verifyFormat("f({1, 2}, {{2, 3}, {4, 5}}, c, {d});", NoSpaces);
+ verifyFormat("Class::Class : member{1, 2, 3} {}", NoSpaces);
+ verifyFormat("new vector<int>{1, 2, 3};", NoSpaces);
+ verifyFormat("new int[3]{1, 2, 3};", NoSpaces);
+ verifyFormat("return {arg1, arg2};", NoSpaces);
+ verifyFormat("return {arg1, SomeType{parameter}};", NoSpaces);
+ verifyFormat("new T{arg1, arg2};", NoSpaces);
+ verifyFormat("f(MyMap[{composite, key}]);", NoSpaces);
+ verifyFormat("class Class {\n"
+ " T member = {arg1, arg2};\n"
+ "};",
+ NoSpaces);
+ verifyFormat("Constructor::Constructor()\n"
+ " : some_value{ //\n"
+ " aaaaaaa //\n"
+ " } {}",
+ NoSpaces);
+}
+
+TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
+ verifyFormat("vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777 };");
+ verifyFormat("vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " // line comment\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555,\n"
+ " // line comment\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777 };");
verifyFormat(
- "Aaa({\n"
- " int i;\n"
- "},\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
- " ccccccccccccccccc));");
+ "vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, // comment\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777 };");
+ verifyFormat("static const uint16_t CallerSavedRegs64Bittttt[] = {\n"
+ " X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,\n"
+ " X86::R8, X86::R9, X86::R10, X86::R11, 0\n"
+ "};");
+ verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
+ " 1, 1, 1, 1 };",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
+ " 1, 1, 1, 1 };",
+ getLLVMStyleWithColumns(38));
+ verifyFormat("vector<int> aaaaaaaaaaaaaaaaaaaaaa = {\n"
+ " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n"
+ "};",
+ getLLVMStyleWithColumns(40));
+
+ // Trailing commas.
+ verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
+ " 1, 1, 1, 1, };",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
+ " 1, 1, 1, 1, //\n"
+ "};",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
+ " 1, 1, 1, 1,\n"
+ " /**/ /**/ };",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("return { { aaaaaaaaaaaaaaaaaaaaa },\n"
+ " { aaaaaaaaaaaaaaaaaaa },\n"
+ " { aaaaaaaaaaaaaaaaaaaaa },\n"
+ " { aaaaaaaaaaaaaaaaa } };",
+ getLLVMStyleWithColumns(60));
}
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
@@ -2930,6 +4783,11 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
" int a;\n"
"#error {\n"
"}");
+ verifyFormat("void f() {} // comment");
+ verifyFormat("void f() { int a; } // comment");
+ verifyFormat("void f() {\n"
+ "} // comment",
+ getLLVMStyleWithColumns(15));
verifyFormat("void f() { return 42; }", getLLVMStyleWithColumns(23));
verifyFormat("void f() {\n return 42;\n}", getLLVMStyleWithColumns(22));
@@ -2964,13 +4822,21 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
verifyFormat("class __attribute__(X) Z {\n} n;");
verifyFormat("class __declspec(X) Z {\n} n;");
verifyFormat("class A##B##C {\n} n;");
+ verifyFormat("class alignas(16) Z {\n} n;");
// Redefinition from nested context:
verifyFormat("class A::B::C {\n} n;");
// Template definitions.
+ verifyFormat(
+ "template <typename F>\n"
+ "Matcher(const Matcher<F> &Other,\n"
+ " typename enable_if_c<is_base_of<F, T>::value &&\n"
+ " !is_same<F, T>::value>::type * = 0)\n"
+ " : Implementation(new ImplicitCastMatcher<F>(Other)) {}");
+
// FIXME: This is still incorrectly handled at the formatter side.
- verifyFormat("template <> struct X < 15, i < 3 && 42 < 50 && 33<28> {\n};");
+ verifyFormat("template <> struct X < 15, i<3 && 42 < 50 && 33 < 28> {};");
// FIXME:
// This now gets parsed incorrectly as class definition.
@@ -2984,12 +4850,15 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
" f();\n");
// This is simply incomplete. Formatting is not important, but must not crash.
- verifyFormat("class A:");
+ verifyFormat("class A:");
}
TEST_F(FormatTest, DoNotInterfereWithErrorAndWarning) {
- verifyFormat("#error Leave all white!!!!! space* alone!\n");
- verifyFormat("#warning Leave all white!!!!! space* alone!\n");
+ EXPECT_EQ("#error Leave all white!!!!! space* alone!\n",
+ format("#error Leave all white!!!!! space* alone!\n"));
+ EXPECT_EQ(
+ "#warning Leave all white!!!!! space* alone!\n",
+ format("#warning Leave all white!!!!! space* alone!\n"));
EXPECT_EQ("#error 1", format(" # error 1"));
EXPECT_EQ("#warning 1", format(" # warning 1"));
}
@@ -3034,7 +4903,8 @@ TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
" if (true) continue;\n"
"#endif\n"
" // Comment\n"
- " if (true) continue;",
+ " if (true) continue;\n"
+ "}",
ShortMergedIf);
}
@@ -3062,7 +4932,7 @@ TEST_F(FormatTest, BlockComments) {
EXPECT_EQ("/* */ /* */ /* */\n/* */ /* */ /* */",
format("/* *//* */ /* */\n/* *//* */ /* */"));
EXPECT_EQ("/* */ a /* */ b;", format(" /* */ a/* */ b;"));
- EXPECT_EQ("#define A /*123*/\\\n"
+ EXPECT_EQ("#define A /*123*/ \\\n"
" b\n"
"/* */\n"
"someCall(\n"
@@ -3078,6 +4948,27 @@ TEST_F(FormatTest, BlockComments) {
format("#define A\n"
"/* */someCall(parameter);",
getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/*\n**\n*/", format("/*\n**\n*/"));
+ EXPECT_EQ("/*\n"
+ "*\n"
+ " * aaaaaa\n"
+ "*aaaaaa\n"
+ "*/",
+ format("/*\n"
+ "*\n"
+ " * aaaaaa aaaaaa\n"
+ "*/",
+ getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("/*\n"
+ "**\n"
+ "* aaaaaa\n"
+ "*aaaaaa\n"
+ "*/",
+ format("/*\n"
+ "**\n"
+ "* aaaaaa aaaaaa\n"
+ "*/",
+ getLLVMStyleWithColumns(10)));
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackParameters = false;
@@ -3109,6 +5000,35 @@ TEST_F(FormatTest, BlockComments) {
format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
"int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
"int cccccccccccccccccccccccccccccc; /* comment */\n"));
+
+ verifyFormat("void f(int * /* unused */) {}");
+
+ EXPECT_EQ("/*\n"
+ " **\n"
+ " */",
+ format("/*\n"
+ " **\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " *q\n"
+ " */",
+ format("/*\n"
+ " *q\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " * q\n"
+ " */",
+ format("/*\n"
+ " * q\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " **/",
+ format("/*\n"
+ " **/"));
+ EXPECT_EQ("/*\n"
+ " ***/",
+ format("/*\n"
+ " ***/"));
}
TEST_F(FormatTest, BlockCommentsInMacros) {
@@ -3132,6 +5052,30 @@ TEST_F(FormatTest, BlockCommentsInMacros) {
getLLVMStyleWithColumns(20)));
}
+TEST_F(FormatTest, BlockCommentsAtEndOfLine) {
+ EXPECT_EQ("a = {\n"
+ " 1111 /* */\n"
+ "};",
+ format("a = {1111 /* */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("a = {\n"
+ " 1111 /* */\n"
+ "};",
+ format("a = {1111 /* */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+
+ // FIXME: The formatting is still wrong here.
+ EXPECT_EQ("a = {\n"
+ " 1111 /* a\n"
+ " */\n"
+ "};",
+ format("a = {1111 /* a */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+}
+
TEST_F(FormatTest, IndentLineCommentsInStartOfBlockAtEndOfFile) {
// FIXME: This is not what we want...
verifyFormat("{\n"
@@ -3202,8 +5146,8 @@ TEST_F(FormatTest, FormatForObjectiveCMethodDecls) {
// protocol lists (but not for template classes):
//verifyFormat("- (void)setDelegate:(id <Protocol>)delegate;");
- verifyFormat("- (int(*)())foo:(int(*)())f;");
- verifyGoogleFormat("- (int(*)())foo:(int(*)())foo;");
+ verifyFormat("- (int (*)())foo:(int (*)())f;");
+ verifyGoogleFormat("- (int (*)())foo:(int (*)())foo;");
// If there's no return type (very rare in practice!), LLVM and Google style
// agree.
@@ -3386,6 +5330,10 @@ TEST_F(FormatTest, FormatObjCImplementation) {
verifyFormat("@implementation Foo (HackStuff)\n"
"+ (id)init {\n}\n"
"@end");
+ verifyFormat("@implementation ObjcClass\n"
+ "- (void)method;\n"
+ "{}\n"
+ "@end");
}
TEST_F(FormatTest, FormatObjCProtocol) {
@@ -3419,6 +5367,11 @@ TEST_F(FormatTest, FormatObjCProtocol) {
"@optional\n"
"@property(assign) int madProp;\n"
"@end\n");
+
+ verifyFormat("@property(nonatomic, assign, readonly)\n"
+ " int *looooooooooooooooooooooooooooongNumber;\n"
+ "@property(nonatomic, assign, readonly)\n"
+ " NSString *looooooooooooooooooooooooooooongName;");
}
TEST_F(FormatTest, FormatObjCMethodDeclarations) {
@@ -3449,7 +5402,7 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
verifyFormat("int a = ++[foo bar:baz];");
verifyFormat("int a = --[foo bar:baz];");
verifyFormat("int a = sizeof [foo bar:baz];");
- verifyFormat("int a = alignof [foo bar:baz];");
+ verifyFormat("int a = alignof [foo bar:baz];", getGoogleStyle());
verifyFormat("int a = &[foo bar:baz];");
verifyFormat("int a = *[foo bar:baz];");
// FIXME: Make casts work, without breaking f()[4].
@@ -3508,22 +5461,26 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
verifyFormat("throw [self errorFor:a];");
verifyFormat("@throw [self errorFor:a];");
+ verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];");
+ verifyFormat("[(id)foo bar:(id) ? baz : quux];");
+ verifyFormat("4 > 4 ? (id)a : (id)baz;");
+
// This tests that the formatter doesn't break after "backing" but before ":",
// which would be at 80 columns.
verifyFormat(
"void f() {\n"
" if ((self = [super initWithContentRect:contentRect\n"
- " styleMask:styleMask\n"
+ " styleMask:styleMask ?: otherMask\n"
" backing:NSBackingStoreBuffered\n"
" defer:YES]))");
verifyFormat(
"[foo checkThatBreakingAfterColonWorksOk:\n"
- " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
+ " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
verifyFormat("[myObj short:arg1 // Force line break\n"
- " longKeyword:arg2\n"
- " evenLongerKeyword:arg3\n"
+ " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n"
+ " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n"
" error:arg4];");
verifyFormat(
"void f() {\n"
@@ -3534,6 +5491,16 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
" backing:NSBackingStoreBuffered\n"
" defer:NO]);\n"
"}");
+ verifyFormat(
+ "void f() {\n"
+ " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " syeMask:NSBorderlessWindowMask\n"
+ " bking:NSBackingStoreBuffered\n"
+ " der:NO]);\n"
+ "}",
+ getLLVMStyleWithColumns(70));
verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
" with:contentsNativeView];");
@@ -3560,6 +5527,27 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
"scoped_nsobject<NSTextField> message(\n"
" // The frame will be fixed up when |-setMessageText:| is called.\n"
" [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);");
+ verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n"
+ " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n"
+ " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n"
+ " aaaa:bbb];");
+ verifyFormat("[self param:function( //\n"
+ " parameter)]");
+ verifyFormat(
+ "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
+ " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
+ " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];");
+
+ // Variadic parameters.
+ verifyFormat(
+ "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];");
+ verifyFormat(
+ "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];");
+ verifyFormat("[self // break\n"
+ " a:a\n"
+ " aaa:aaa];");
}
TEST_F(FormatTest, ObjCAt) {
@@ -3618,6 +5606,9 @@ TEST_F(FormatTest, ObjCSnippets) {
verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;");
verifyFormat("@property(assign, getter=isEditable) BOOL editable;");
verifyGoogleFormat("@property(assign, getter=isEditable) BOOL editable;");
+
+ verifyFormat("@import foo.bar;\n"
+ "@import baz;");
}
TEST_F(FormatTest, ObjCLiterals) {
@@ -3634,29 +5625,17 @@ TEST_F(FormatTest, ObjCLiterals) {
verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);");
verifyFormat("NSNumber *favoriteColor = @(Green);");
verifyFormat("NSString *path = @(getenv(\"PATH\"));");
+}
- verifyFormat("@[");
- verifyFormat("@[]");
- verifyFormat(
- "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
- verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
-
+TEST_F(FormatTest, ObjCDictLiterals) {
verifyFormat("@{");
verifyFormat("@{}");
verifyFormat("@{ @\"one\" : @1 }");
verifyFormat("return @{ @\"one\" : @1 };");
verifyFormat("@{ @\"one\" : @1, }");
- // FIXME: Breaking in cases where we think there's a structural error
- // showed that we're incorrectly parsing this code. We need to fix the
- // parsing here.
- verifyFormat("@{ @\"one\" : @\n"
- "{ @2 : @1 }\n"
- "}");
- verifyFormat("@{ @\"one\" : @\n"
- "{ @2 : @1 }\n"
- ",\n"
- "}");
+ verifyFormat("@{ @\"one\" : @{ @2 : @1 } }");
+ verifyFormat("@{ @\"one\" : @{ @2 : @1 }, }");
verifyFormat("@{ 1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2 }");
verifyFormat("[self setDict:@{}");
@@ -3667,10 +5646,67 @@ TEST_F(FormatTest, ObjCLiterals) {
verifyFormat(
"NSDictionary *settings = @{ AVEncoderKey : @(AVAudioQualityMax) };");
- // FIXME: Nested and multi-line array and dictionary literals need more work.
verifyFormat(
- "NSDictionary *d = @{ @\"nam\" : NSUserNam(), @\"dte\" : [NSDate date],\n"
- " @\"processInfo\" : [NSProcessInfo processInfo] };");
+ "NSDictionary *d = @{\n"
+ " @\"nam\" : NSUserNam(),\n"
+ " @\"dte\" : [NSDate date],\n"
+ " @\"processInfo\" : [NSProcessInfo processInfo]\n"
+ "};");
+ verifyFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
+ "regularFont,\n"
+ "};");
+ verifyGoogleFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
+ "regularFont,\n"
+ "};");
+
+ // We should try to be robust in case someone forgets the "@".
+ verifyFormat(
+ "NSDictionary *d = {\n"
+ " @\"nam\" : NSUserNam(),\n"
+ " @\"dte\" : [NSDate date],\n"
+ " @\"processInfo\" : [NSProcessInfo processInfo]\n"
+ "};");
+}
+
+TEST_F(FormatTest, ObjCArrayLiterals) {
+ verifyFormat("@[");
+ verifyFormat("@[]");
+ verifyFormat(
+ "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
+ verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
+ verifyFormat("NSArray *array = @[ [foo description] ];");
+
+ verifyFormat(
+ "NSArray *some_variable = @[\n"
+ " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\"\n"
+ "];");
+ verifyFormat("NSArray *some_variable = @[\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyGoogleFormat("NSArray *some_variable = @[\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\"\n"
+ "];");
+
+ // We should try to be robust in case someone forgets the "@".
+ verifyFormat("NSArray *some_variable = [\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
}
TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
@@ -3718,7 +5754,7 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
"a;\n"
"}\n"
"{\n"
- " b;\n"
+ " b; //\n"
"}\n"
"}",
format("{\n"
@@ -3726,15 +5762,15 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
"a;\n"
"}\n"
"{\n"
- " b;\n"
+ " b; //\n"
"}\n"
"}",
22, 2, getLLVMStyle()));
EXPECT_EQ(" {\n"
- " a;\n"
+ " a; //\n"
" }",
format(" {\n"
- "a;\n"
+ "a; //\n"
" }",
4, 2, getLLVMStyle()));
EXPECT_EQ("void f() {}\n"
@@ -3749,6 +5785,13 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
" // line 2\n"
" int b;",
35, 0, getLLVMStyle()));
+ EXPECT_EQ(" int a;\n"
+ " void\n"
+ " ffffff() {\n"
+ " }",
+ format(" int a;\n"
+ "void ffffff() {}",
+ 11, 0, getLLVMStyleWithColumns(11)));
}
TEST_F(FormatTest, BreakStringLiterals) {
@@ -3808,6 +5851,18 @@ TEST_F(FormatTest, BreakStringLiterals) {
format("variable = f(\"long string literal\", short, "
"loooooooooooooooooooong);",
getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("f(g(\"long string \"\n"
+ " \"literal\"),\n"
+ " b);",
+ format("f(g(\"long string literal\"), b);",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("f(g(\"long string \"\n"
+ " \"literal\",\n"
+ " a),\n"
+ " b);",
+ format("f(g(\"long string literal\", a), b);",
+ getLLVMStyleWithColumns(20)));
EXPECT_EQ(
"f(\"one two\".split(\n"
" variable));",
@@ -3842,6 +5897,53 @@ TEST_F(FormatTest, BreakStringLiterals) {
"\"slashes\"",
format("\"split/pathat/slashes\"", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ(
+ "\"split/\"\n"
+ "\"pathat/\"\n"
+ "\"slashes\"",
+ format("\"split/pathat/slashes\"", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("\"split at \"\n"
+ "\"spaces/at/\"\n"
+ "\"slashes.at.any$\"\n"
+ "\"non-alphanumeric%\"\n"
+ "\"1111111111characte\"\n"
+ "\"rs\"",
+ format("\"split at "
+ "spaces/at/"
+ "slashes.at."
+ "any$non-"
+ "alphanumeric%"
+ "1111111111characte"
+ "rs\"",
+ getLLVMStyleWithColumns(20)));
+
+ // Verify that splitting the strings understands
+ // Style::AlwaysBreakBeforeMultilineStrings.
+ EXPECT_EQ("aaaaaaaaaaaa(aaaaaaaaaaaaa,\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa \"\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa\");",
+ format("aaaaaaaaaaaa(aaaaaaaaaaaaa, \"aaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaaa\");",
+ getGoogleStyle()));
+ EXPECT_EQ("return \"aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa\";",
+ format("return \"aaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaaa\";",
+ getGoogleStyle()));
+ EXPECT_EQ("llvm::outs() << \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";",
+ format("llvm::outs() << "
+ "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaa\";"));
+ EXPECT_EQ("ffff(\n"
+ " {\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"});",
+ format("ffff({\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"});",
+ getGoogleStyle()));
+
FormatStyle AlignLeft = getLLVMStyleWithColumns(12);
AlignLeft.AlignEscapedNewlinesLeft = true;
EXPECT_EQ(
@@ -3852,6 +5954,177 @@ TEST_F(FormatTest, BreakStringLiterals) {
format("#define A \"some text other\";", AlignLeft));
}
+TEST_F(FormatTest, BreaksWideStringLiterals) {
+ EXPECT_EQ(
+ "u8\"utf8 string \"\n"
+ "u8\"literal\";",
+ format("u8\"utf8 string literal\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ(
+ "u\"utf16 string \"\n"
+ "u\"literal\";",
+ format("u\"utf16 string literal\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ(
+ "U\"utf32 string \"\n"
+ "U\"literal\";",
+ format("U\"utf32 string literal\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ("L\"wide string \"\n"
+ "L\"literal\";",
+ format("L\"wide string literal\";", getGoogleStyleWithColumns(16)));
+}
+
+TEST_F(FormatTest, BreaksRawStringLiterals) {
+ EXPECT_EQ("R\"x(raw )x\"\n"
+ "R\"x(literal)x\";",
+ format("R\"x(raw literal)x\";", getGoogleStyleWithColumns(15)));
+ EXPECT_EQ("uR\"x(raw )x\"\n"
+ "uR\"x(literal)x\";",
+ format("uR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ("u8R\"x(raw )x\"\n"
+ "u8R\"x(literal)x\";",
+ format("u8R\"x(raw literal)x\";", getGoogleStyleWithColumns(17)));
+ EXPECT_EQ("LR\"x(raw )x\"\n"
+ "LR\"x(literal)x\";",
+ format("LR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ("UR\"x(raw )x\"\n"
+ "UR\"x(literal)x\";",
+ format("UR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
+}
+
+TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) {
+ FormatStyle Style = getLLVMStyleWithColumns(20);
+ EXPECT_EQ(
+ "_T(\"aaaaaaaaaaaaaa\")\n"
+ "_T(\"aaaaaaaaaaaaaa\")\n"
+ "_T(\"aaaaaaaaaaaa\")",
+ format(" _T(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")", Style));
+ EXPECT_EQ("f(x, _T(\"aaaaaaaaa\")\n"
+ " _T(\"aaaaaa\"),\n"
+ " z);",
+ format("f(x, _T(\"aaaaaaaaaaaaaaa\"), z);", Style));
+
+ // FIXME: Handle embedded spaces in one iteration.
+ // EXPECT_EQ("_T(\"aaaaaaaaaaaaa\")\n"
+ // "_T(\"aaaaaaaaaaaaa\")\n"
+ // "_T(\"aaaaaaaaaaaaa\")\n"
+ // "_T(\"a\")",
+ // format(" _T ( \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" )",
+ // getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "_T ( \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" )",
+ format(" _T ( \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" )", Style));
+}
+
+TEST_F(FormatTest, DontSplitStringLiteralsWithEscapedNewlines) {
+ EXPECT_EQ(
+ "aaaaaaaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";",
+ format("aaaaaaaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";"));
+}
+
+TEST_F(FormatTest, CountsCharactersInMultilineRawStringLiterals) {
+ EXPECT_EQ("f(g(R\"x(raw literal)x\", a), b);",
+ format("f(g(R\"x(raw literal)x\", a), b);", getGoogleStyle()));
+ EXPECT_EQ("fffffffffff(g(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\",\n"
+ " a),\n"
+ " b);",
+ format("fffffffffff(g(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\", a), b);",
+ getGoogleStyleWithColumns(20)));
+ EXPECT_EQ("fffffffffff(\n"
+ " g(R\"x(qqq\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\",\n"
+ " a),\n"
+ " b);",
+ format("fffffffffff(g(R\"x(qqq\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\", a), b);",
+ getGoogleStyleWithColumns(20)));
+
+ EXPECT_EQ("fffffffffff(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\");",
+ format("fffffffffff(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\");",
+ getGoogleStyleWithColumns(20)));
+ EXPECT_EQ("fffffffffff(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\" +\n"
+ " bbbbbb);",
+ format("fffffffffff(R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\" + bbbbbb);",
+ getGoogleStyleWithColumns(20)));
+}
+
+TEST_F(FormatTest, SkipsUnknownStringLiterals) {
+ verifyFormat("string a = \"unterminated;");
+ EXPECT_EQ("function(\"unterminated,\n"
+ " OtherParameter);",
+ format("function( \"unterminated,\n"
+ " OtherParameter);"));
+}
+
+TEST_F(FormatTest, DoesNotTryToParseUDLiteralsInPreCpp11Code) {
+ EXPECT_EQ("#define x(_a) printf(\"foo\" _a);",
+ format("#define x(_a) printf(\"foo\"_a);", getLLVMStyle()));
+}
+
+TEST_F(FormatTest, BreakStringLiteralsBeforeUnbreakableTokenSequence) {
+ EXPECT_EQ("someFunction(\"aaabbbcccd\"\n"
+ " \"ddeeefff\");",
+ format("someFunction(\"aaabbbcccdddeeefff\");",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("someFunction1234567890(\n"
+ " \"aaabbbcccdddeeefff\");",
+ format("someFunction1234567890(\"aaabbbcccdddeeefff\");",
+ getLLVMStyleWithColumns(26)));
+ EXPECT_EQ("someFunction1234567890(\n"
+ " \"aaabbbcccdddeeeff\"\n"
+ " \"f\");",
+ format("someFunction1234567890(\"aaabbbcccdddeeefff\");",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("someFunction1234567890(\n"
+ " \"aaabbbcccdddeeeff\"\n"
+ " \"f\");",
+ format("someFunction1234567890(\"aaabbbcccdddeeefff\");",
+ getLLVMStyleWithColumns(24)));
+ EXPECT_EQ("someFunction(\"aaabbbcc \"\n"
+ " \"ddde \"\n"
+ " \"efff\");",
+ format("someFunction(\"aaabbbcc ddde efff\");",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("someFunction(\"aaabbbccc \"\n"
+ " \"ddeeefff\");",
+ format("someFunction(\"aaabbbccc ddeeefff\");",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("someFunction1234567890(\n"
+ " \"aaabb \"\n"
+ " \"cccdddeeefff\");",
+ format("someFunction1234567890(\"aaabb cccdddeeefff\");",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("#define A \\\n"
+ " string s = \\\n"
+ " \"123456789\" \\\n"
+ " \"0\"; \\\n"
+ " int i;",
+ format("#define A string s = \"1234567890\"; int i;",
+ getLLVMStyleWithColumns(20)));
+ // FIXME: Put additional penalties on breaking at non-whitespace locations.
+ EXPECT_EQ("someFunction(\"aaabbbcc \"\n"
+ " \"dddeeeff\"\n"
+ " \"f\");",
+ format("someFunction(\"aaabbbcc dddeeefff\");",
+ getLLVMStyleWithColumns(25)));
+}
+
TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) {
EXPECT_EQ("\"\\a\"",
format("\"\\a\"", getLLVMStyleWithColumns(3)));
@@ -3888,8 +6161,11 @@ TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) {
"\"00000000\"\n"
"\"1\"",
format("\"test\\000000000001\"", getLLVMStyleWithColumns(10)));
- EXPECT_EQ("R\"(\\x\\x00)\"\n",
- format("R\"(\\x\\x00)\"\n", getLLVMStyleWithColumns(7)));
+ // FIXME: We probably don't need to care about escape sequences in raw
+ // literals.
+ EXPECT_EQ("R\"(\\x)\"\n"
+ "R\"(\\x00)\"\n",
+ format("R\"(\\x\\x00)\"\n", getGoogleStyleWithColumns(7)));
}
TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) {
@@ -3899,12 +6175,1134 @@ TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) {
verifyFormat("if (foo)\n"
" return { forgot_closing_brace();\n"
"test();");
- verifyFormat("int a[] = { void forgot_closing_brace()\n"
- "{\n"
+ verifyFormat("int a[] = { void forgot_closing_brace() { f();\n"
+ "g();\n"
+ "}");
+}
+
+TEST_F(FormatTest, FormatsClosingBracesInEmptyNestedBlocks) {
+ verifyFormat("class X {\n"
+ " void f() {\n"
+ " }\n"
+ "};",
+ getLLVMStyleWithColumns(12));
+}
+
+TEST_F(FormatTest, ConfigurableIndentWidth) {
+ FormatStyle EightIndent = getLLVMStyleWithColumns(18);
+ EightIndent.IndentWidth = 8;
+ verifyFormat("void f() {\n"
+ " someFunction();\n"
+ " if (true) {\n"
+ " f();\n"
+ " }\n"
+ "}",
+ EightIndent);
+ verifyFormat("class X {\n"
+ " void f() {\n"
+ " }\n"
+ "};",
+ EightIndent);
+ verifyFormat("int x[] = {\n"
+ " call(),\n"
+ " call(),\n"
+ "};",
+ EightIndent);
+}
+
+TEST_F(FormatTest, ConfigurableFunctionDeclarationIndentAfterType) {
+ verifyFormat("void\n"
+ "f();",
+ getLLVMStyleWithColumns(8));
+}
+
+TEST_F(FormatTest, ConfigurableUseOfTab) {
+ FormatStyle Tab = getLLVMStyleWithColumns(42);
+ Tab.IndentWidth = 8;
+ Tab.UseTab = FormatStyle::UT_Always;
+ Tab.AlignEscapedNewlinesLeft = true;
+
+ EXPECT_EQ("if (aaaaaaaa && // q\n"
+ " bb)\t\t// w\n"
+ "\t;",
+ format("if (aaaaaaaa &&// q\n"
+ "bb)// w\n"
+ ";",
+ Tab));
+ EXPECT_EQ("if (aaa && bbb) // w\n"
+ "\t;",
+ format("if(aaa&&bbb)// w\n"
+ ";",
+ Tab));
+
+ verifyFormat("class X {\n"
+ "\tvoid f() {\n"
+ "\t\tsomeFunction(parameter1,\n"
+ "\t\t\t parameter2);\n"
+ "\t}\n"
+ "};",
+ Tab);
+ verifyFormat("#define A \\\n"
+ "\tvoid f() { \\\n"
+ "\t\tsomeFunction( \\\n"
+ "\t\t parameter1, \\\n"
+ "\t\t parameter2); \\\n"
+ "\t}",
+ Tab);
+ EXPECT_EQ("void f() {\n"
+ "\tf();\n"
+ "\tg();\n"
+ "}",
+ format("void f() {\n"
+ "\tf();\n"
+ "\tg();\n"
+ "}",
+ 0, 0, Tab));
+ EXPECT_EQ("void f() {\n"
+ "\tf();\n"
+ "\tg();\n"
+ "}",
+ format("void f() {\n"
+ "\tf();\n"
+ "\tg();\n"
+ "}",
+ 16, 0, Tab));
+ EXPECT_EQ("void f() {\n"
+ " \tf();\n"
+ "\tg();\n"
+ "}",
+ format("void f() {\n"
+ " \tf();\n"
+ " \tg();\n"
+ "}",
+ 21, 0, Tab));
+
+ Tab.TabWidth = 4;
+ Tab.IndentWidth = 8;
+ verifyFormat("class TabWidth4Indent8 {\n"
+ "\t\tvoid f() {\n"
+ "\t\t\t\tsomeFunction(parameter1,\n"
+ "\t\t\t\t\t\t\t parameter2);\n"
+ "\t\t}\n"
+ "};",
+ Tab);
+
+ Tab.TabWidth = 4;
+ Tab.IndentWidth = 4;
+ verifyFormat("class TabWidth4Indent4 {\n"
+ "\tvoid f() {\n"
+ "\t\tsomeFunction(parameter1,\n"
+ "\t\t\t\t\t parameter2);\n"
+ "\t}\n"
+ "};",
+ Tab);
+
+ Tab.TabWidth = 8;
+ Tab.IndentWidth = 4;
+ verifyFormat("class TabWidth8Indent4 {\n"
+ " void f() {\n"
+ "\tsomeFunction(parameter1,\n"
+ "\t\t parameter2);\n"
+ " }\n"
+ "};",
+ Tab);
+
+ Tab.TabWidth = 8;
+ Tab.IndentWidth = 8;
+ EXPECT_EQ("/*\n"
+ "\t a\t\tcomment\n"
+ "\t in multiple lines\n"
+ " */",
+ format(" /*\t \t \n"
+ " \t \t a\t\tcomment\t \t\n"
+ " \t \t in multiple lines\t\n"
+ " \t */",
+ Tab));
+
+ Tab.UseTab = FormatStyle::UT_ForIndentation;
+ verifyFormat("T t[] = {\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ "};",
+ Tab);
+ verifyFormat("enum A {\n"
+ "\ta1,\n"
+ "\ta2,\n"
+ "\ta3\n"
+ "};",
+ Tab);
+ EXPECT_EQ("if (aaaaaaaa && // q\n"
+ " bb) // w\n"
+ "\t;",
+ format("if (aaaaaaaa &&// q\n"
+ "bb)// w\n"
+ ";",
+ Tab));
+ verifyFormat("class X {\n"
+ "\tvoid f() {\n"
+ "\t\tsomeFunction(parameter1,\n"
+ "\t\t parameter2);\n"
+ "\t}\n"
+ "};",
+ Tab);
+ verifyFormat("{\n"
+ "\tQ({\n"
+ "\t\t int a;\n"
+ "\t\t someFunction(aaaaaaaaaa,\n"
+ "\t\t bbbbbbbbb);\n"
+ "\t },\n"
+ "\t p);\n"
+ "}",
+ Tab);
+ EXPECT_EQ("{\n"
+ "\t/* aaaa\n"
+ "\t bbbb */\n"
+ "}",
+ format("{\n"
+ "/* aaaa\n"
+ " bbbb */\n"
+ "}",
+ Tab));
+ EXPECT_EQ("{\n"
+ "\t/*\n"
+ "\t aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ "\t bbbbbbbbbbbbb\n"
+ "\t*/\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+ "*/\n"
+ "}",
+ Tab));
+ EXPECT_EQ("{\n"
+ "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ "\t// bbbbbbbbbbbbb\n"
+ "}",
+ format("{\n"
+ "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+ "}",
+ Tab));
+ EXPECT_EQ("{\n"
+ "\t/*\n"
+ "\t aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ "\t bbbbbbbbbbbbb\n"
+ "\t*/\n"
+ "}",
+ format("{\n"
+ "\t/*\n"
+ "\t aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+ "\t*/\n"
+ "}",
+ Tab));
+ EXPECT_EQ("{\n"
+ "\t/*\n"
+ "\n"
+ "\t*/\n"
+ "}",
+ format("{\n"
+ "\t/*\n"
+ "\n"
+ "\t*/\n"
+ "}",
+ Tab));
+ EXPECT_EQ("{\n"
+ "\t/*\n"
+ " asdf\n"
+ "\t*/\n"
+ "}",
+ format("{\n"
+ "\t/*\n"
+ " asdf\n"
+ "\t*/\n"
+ "}",
+ Tab));
+
+ Tab.UseTab = FormatStyle::UT_Never;
+ EXPECT_EQ("/*\n"
+ " a\t\tcomment\n"
+ " in multiple lines\n"
+ " */",
+ format(" /*\t \t \n"
+ " \t \t a\t\tcomment\t \t\n"
+ " \t \t in multiple lines\t\n"
+ " \t */",
+ Tab));
+ EXPECT_EQ("/* some\n"
+ " comment */",
+ format(" \t \t /* some\n"
+ " \t \t comment */",
+ Tab));
+ EXPECT_EQ("int a; /* some\n"
+ " comment */",
+ format(" \t \t int a; /* some\n"
+ " \t \t comment */",
+ Tab));
+
+ EXPECT_EQ("int a; /* some\n"
+ "comment */",
+ format(" \t \t int\ta; /* some\n"
+ " \t \t comment */",
+ Tab));
+ EXPECT_EQ("f(\"\t\t\"); /* some\n"
+ " comment */",
+ format(" \t \t f(\"\t\t\"); /* some\n"
+ " \t \t comment */",
+ Tab));
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " * Comment\n"
+ " */\n"
+ " int i;\n"
+ "}",
+ format("{\n"
+ "\t/*\n"
+ "\t * Comment\n"
+ "\t */\n"
+ "\t int i;\n"
+ "}"));
+}
+
+TEST_F(FormatTest, CalculatesOriginalColumn) {
+ EXPECT_EQ("\"qqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "q\"; /* some\n"
+ " comment */",
+ format(" \"qqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "q\"; /* some\n"
+ " comment */",
+ getLLVMStyle()));
+ EXPECT_EQ("// qqqqqqqqqqqqqqqqqqqqqqqqqq\n"
+ "/* some\n"
+ " comment */",
+ format("// qqqqqqqqqqqqqqqqqqqqqqqqqq\n"
+ " /* some\n"
+ " comment */",
+ getLLVMStyle()));
+ EXPECT_EQ("// qqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "qqq\n"
+ "/* some\n"
+ " comment */",
+ format("// qqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "qqq\n"
+ " /* some\n"
+ " comment */",
+ getLLVMStyle()));
+ EXPECT_EQ("inttt qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "wwww; /* some\n"
+ " comment */",
+ format(" inttt qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
+ "wwww; /* some\n"
+ " comment */",
+ getLLVMStyle()));
+}
+
+TEST_F(FormatTest, ConfigurableSpaceAfterControlStatementKeyword) {
+ FormatStyle NoSpace = getLLVMStyle();
+ NoSpace.SpaceAfterControlStatementKeyword = false;
+
+ verifyFormat("while(true)\n"
+ " continue;", NoSpace);
+ verifyFormat("for(;;)\n"
+ " continue;", NoSpace);
+ verifyFormat("if(true)\n"
" f();\n"
- " g();\n"
+ "else if(true)\n"
+ " f();", NoSpace);
+ verifyFormat("do {\n"
+ " do_something();\n"
+ "} while(something());", NoSpace);
+ verifyFormat("switch(x) {\n"
+ "default:\n"
+ " break;\n"
+ "}", NoSpace);
+}
+
+TEST_F(FormatTest, ConfigurableSpacesInParentheses) {
+ FormatStyle Spaces = getLLVMStyle();
+
+ Spaces.SpacesInParentheses = true;
+ verifyFormat("call( x, y, z );", Spaces);
+ verifyFormat("while ( (bool)1 )\n"
+ " continue;", Spaces);
+ verifyFormat("for ( ;; )\n"
+ " continue;", Spaces);
+ verifyFormat("if ( true )\n"
+ " f();\n"
+ "else if ( true )\n"
+ " f();", Spaces);
+ verifyFormat("do {\n"
+ " do_something( (int)i );\n"
+ "} while ( something() );", Spaces);
+ verifyFormat("switch ( x ) {\n"
+ "default:\n"
+ " break;\n"
+ "}", Spaces);
+
+ Spaces.SpacesInParentheses = false;
+ Spaces.SpacesInCStyleCastParentheses = true;
+ verifyFormat("Type *A = ( Type * )P;", Spaces);
+ verifyFormat("Type *A = ( vector<Type *, int *> )P;", Spaces);
+ verifyFormat("x = ( int32 )y;", Spaces);
+ verifyFormat("int a = ( int )(2.0f);", Spaces);
+ verifyFormat("#define AA(X) sizeof((( X * )NULL)->a)", Spaces);
+ verifyFormat("my_int a = ( my_int )sizeof(int);", Spaces);
+ verifyFormat("#define x (( int )-1)", Spaces);
+
+ Spaces.SpacesInParentheses = false;
+ Spaces.SpaceInEmptyParentheses = true;
+ verifyFormat("call(x, y, z);", Spaces);
+ verifyFormat("call( )", Spaces);
+
+ // Run the first set of tests again with
+ // Spaces.SpacesInParentheses = false,
+ // Spaces.SpaceInEmptyParentheses = true and
+ // Spaces.SpacesInCStyleCastParentheses = true
+ Spaces.SpacesInParentheses = false,
+ Spaces.SpaceInEmptyParentheses = true;
+ Spaces.SpacesInCStyleCastParentheses = true;
+ verifyFormat("call(x, y, z);", Spaces);
+ verifyFormat("while (( bool )1)\n"
+ " continue;", Spaces);
+ verifyFormat("for (;;)\n"
+ " continue;", Spaces);
+ verifyFormat("if (true)\n"
+ " f( );\n"
+ "else if (true)\n"
+ " f( );", Spaces);
+ verifyFormat("do {\n"
+ " do_something(( int )i);\n"
+ "} while (something( ));", Spaces);
+ verifyFormat("switch (x) {\n"
+ "default:\n"
+ " break;\n"
+ "}", Spaces);
+}
+
+TEST_F(FormatTest, ConfigurableSpaceBeforeAssignmentOperators) {
+ verifyFormat("int a = 5;");
+ verifyFormat("a += 42;");
+ verifyFormat("a or_eq 8;");
+
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpaceBeforeAssignmentOperators = false;
+ verifyFormat("int a= 5;", Spaces);
+ verifyFormat("a+= 42;", Spaces);
+ verifyFormat("a or_eq 8;", Spaces);
+}
+
+TEST_F(FormatTest, LinuxBraceBreaking) {
+ FormatStyle BreakBeforeBrace = getLLVMStyle();
+ BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux;
+ verifyFormat("namespace a\n"
+ "{\n"
+ "class A\n"
+ "{\n"
+ " void f()\n"
+ " {\n"
+ " if (true) {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ " void g()\n"
+ " {\n"
+ " return;\n"
+ " }\n"
+ "}\n"
+ "}",
+ BreakBeforeBrace);
+}
+
+TEST_F(FormatTest, StroustrupBraceBreaking) {
+ FormatStyle BreakBeforeBrace = getLLVMStyle();
+ BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ verifyFormat("namespace a {\n"
+ "class A {\n"
+ " void f()\n"
+ " {\n"
+ " if (true) {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ " void g()\n"
+ " {\n"
+ " return;\n"
+ " }\n"
+ "}\n"
+ "}",
+ BreakBeforeBrace);
+}
+
+TEST_F(FormatTest, AllmanBraceBreaking) {
+ FormatStyle BreakBeforeBrace = getLLVMStyle();
+ BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Allman;
+ verifyFormat("namespace a\n"
+ "{\n"
+ "class A\n"
+ "{\n"
+ " void f()\n"
+ " {\n"
+ " if (true)\n"
+ " {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ " void g()\n"
+ " {\n"
+ " return;\n"
+ " }\n"
+ "}\n"
+ "}",
+ BreakBeforeBrace);
+
+ verifyFormat("void f()\n"
+ "{\n"
+ " if (true)\n"
+ " {\n"
+ " a();\n"
+ " }\n"
+ " else if (false)\n"
+ " {\n"
+ " b();\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " c();\n"
+ " }\n"
+ "}\n",
+ BreakBeforeBrace);
+
+ verifyFormat("void f()\n"
+ "{\n"
+ " for (int i = 0; i < 10; ++i)\n"
+ " {\n"
+ " a();\n"
+ " }\n"
+ " while (false)\n"
+ " {\n"
+ " b();\n"
+ " }\n"
+ " do\n"
+ " {\n"
+ " c();\n"
+ " } while (false)\n"
+ "}\n",
+ BreakBeforeBrace);
+
+ verifyFormat("void f(int a)\n"
+ "{\n"
+ " switch (a)\n"
+ " {\n"
+ " case 0:\n"
+ " break;\n"
+ " case 1:\n"
+ " {\n"
+ " break;\n"
+ " }\n"
+ " case 2:\n"
+ " {\n"
+ " }\n"
+ " break;\n"
+ " default:\n"
+ " break;\n"
+ " }\n"
+ "}\n",
+ BreakBeforeBrace);
+
+ verifyFormat("enum X\n"
+ "{\n"
+ " Y = 0,\n"
+ "}\n",
+ BreakBeforeBrace);
+
+ FormatStyle BreakBeforeBraceShortIfs = BreakBeforeBrace;
+ BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true;
+ BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true;
+ verifyFormat("void f(bool b)\n"
+ "{\n"
+ " if (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"
+ " while (b)\n"
+ " {\n"
+ " return;\n"
+ " }\n"
+ "}\n",
+ BreakBeforeBraceShortIfs);
+}
+
+TEST_F(FormatTest, CatchExceptionReferenceBinding) {
+ verifyFormat("void f() {\n"
+ " try {\n"
+ " }\n"
+ " catch (const Exception &e) {\n"
+ " }\n"
+ "}\n",
+ getLLVMStyle());
+}
+
+TEST_F(FormatTest, UnderstandsPragmas) {
+ verifyFormat("#pragma omp reduction(| : var)");
+ verifyFormat("#pragma omp reduction(+ : var)");
+}
+
+bool allStylesEqual(ArrayRef<FormatStyle> Styles) {
+ for (size_t i = 1; i < Styles.size(); ++i)
+ if (!(Styles[0] == Styles[i]))
+ return false;
+ return true;
+}
+
+TEST_F(FormatTest, GetsPredefinedStyleByName) {
+ FormatStyle Styles[3];
+
+ Styles[0] = getLLVMStyle();
+ EXPECT_TRUE(getPredefinedStyle("LLVM", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("lLvM", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ Styles[0] = getGoogleStyle();
+ EXPECT_TRUE(getPredefinedStyle("Google", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("gOOgle", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ Styles[0] = getChromiumStyle();
+ EXPECT_TRUE(getPredefinedStyle("Chromium", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("cHRoMiUM", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ Styles[0] = getMozillaStyle();
+ EXPECT_TRUE(getPredefinedStyle("Mozilla", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("moZILla", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ Styles[0] = getWebKitStyle();
+ EXPECT_TRUE(getPredefinedStyle("WebKit", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("wEbKit", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ EXPECT_FALSE(getPredefinedStyle("qwerty", &Styles[0]));
+}
+
+TEST_F(FormatTest, ParsesConfiguration) {
+ FormatStyle Style = {};
+#define CHECK_PARSE(TEXT, FIELD, VALUE) \
+ EXPECT_NE(VALUE, Style.FIELD); \
+ EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \
+ EXPECT_EQ(VALUE, Style.FIELD)
+
+#define CHECK_PARSE_BOOL(FIELD) \
+ Style.FIELD = false; \
+ EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \
+ EXPECT_TRUE(Style.FIELD); \
+ EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \
+ EXPECT_FALSE(Style.FIELD);
+
+ CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
+ CHECK_PARSE_BOOL(AlignTrailingComments);
+ CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
+ CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
+ CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
+ CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations);
+ CHECK_PARSE_BOOL(BinPackParameters);
+ CHECK_PARSE_BOOL(BreakBeforeBinaryOperators);
+ CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
+ CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma);
+ CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
+ CHECK_PARSE_BOOL(DerivePointerBinding);
+ CHECK_PARSE_BOOL(IndentCaseLabels);
+ CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
+ CHECK_PARSE_BOOL(PointerBindsToType);
+ CHECK_PARSE_BOOL(Cpp11BracedListStyle);
+ CHECK_PARSE_BOOL(IndentFunctionDeclarationAfterType);
+ CHECK_PARSE_BOOL(SpacesInParentheses);
+ CHECK_PARSE_BOOL(SpacesInAngles);
+ CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
+ CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
+ CHECK_PARSE_BOOL(SpaceAfterControlStatementKeyword);
+ CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators);
+
+ CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234);
+ CHECK_PARSE("ConstructorInitializerIndentWidth: 1234",
+ ConstructorInitializerIndentWidth, 1234u);
+ CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u);
+ CHECK_PARSE("MaxEmptyLinesToKeep: 1234", MaxEmptyLinesToKeep, 1234u);
+ CHECK_PARSE("PenaltyBreakBeforeFirstCallParameter: 1234",
+ PenaltyBreakBeforeFirstCallParameter, 1234u);
+ CHECK_PARSE("PenaltyExcessCharacter: 1234", PenaltyExcessCharacter, 1234u);
+ CHECK_PARSE("PenaltyReturnTypeOnItsOwnLine: 1234",
+ PenaltyReturnTypeOnItsOwnLine, 1234u);
+ CHECK_PARSE("SpacesBeforeTrailingComments: 1234",
+ SpacesBeforeTrailingComments, 1234u);
+ CHECK_PARSE("IndentWidth: 32", IndentWidth, 32u);
+ CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u);
+
+ Style.Standard = FormatStyle::LS_Auto;
+ CHECK_PARSE("Standard: Cpp03", Standard, FormatStyle::LS_Cpp03);
+ CHECK_PARSE("Standard: Cpp11", Standard, FormatStyle::LS_Cpp11);
+ CHECK_PARSE("Standard: C++03", Standard, FormatStyle::LS_Cpp03);
+ CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11);
+ CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto);
+
+ Style.UseTab = FormatStyle::UT_ForIndentation;
+ CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never);
+ CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);
+ CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never);
+ CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
+ CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always);
+
+ Style.ColumnLimit = 123;
+ FormatStyle BaseStyle = getLLVMStyle();
+ CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit);
+ CHECK_PARSE("BasedOnStyle: LLVM\nColumnLimit: 1234", ColumnLimit, 1234u);
+
+ Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ CHECK_PARSE("BreakBeforeBraces: Attach", BreakBeforeBraces,
+ FormatStyle::BS_Attach);
+ CHECK_PARSE("BreakBeforeBraces: Linux", BreakBeforeBraces,
+ FormatStyle::BS_Linux);
+ CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces,
+ FormatStyle::BS_Stroustrup);
+
+ Style.NamespaceIndentation = FormatStyle::NI_All;
+ CHECK_PARSE("NamespaceIndentation: None", NamespaceIndentation,
+ FormatStyle::NI_None);
+ CHECK_PARSE("NamespaceIndentation: Inner", NamespaceIndentation,
+ FormatStyle::NI_Inner);
+ CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
+ FormatStyle::NI_All);
+
+#undef CHECK_PARSE
+#undef CHECK_PARSE_BOOL
+}
+
+TEST_F(FormatTest, ConfigurationRoundTripTest) {
+ FormatStyle Style = getLLVMStyle();
+ std::string YAML = configurationAsText(Style);
+ FormatStyle ParsedStyle = {};
+ EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle).value());
+ EXPECT_EQ(Style, ParsedStyle);
+}
+
+TEST_F(FormatTest, WorksFor8bitEncodings) {
+ EXPECT_EQ("\"\xce\xe4\xed\xe0\xe6\xe4\xfb \xe2 \"\n"
+ "\"\xf1\xf2\xf3\xe4\xb8\xed\xf3\xfe \"\n"
+ "\"\xe7\xe8\xec\xed\xfe\xfe \"\n"
+ "\"\xef\xee\xf0\xf3...\"",
+ format("\"\xce\xe4\xed\xe0\xe6\xe4\xfb \xe2 "
+ "\xf1\xf2\xf3\xe4\xb8\xed\xf3\xfe \xe7\xe8\xec\xed\xfe\xfe "
+ "\xef\xee\xf0\xf3...\"",
+ getLLVMStyleWithColumns(12)));
+}
+
+TEST_F(FormatTest, HandlesUTF8BOM) {
+ EXPECT_EQ("\xef\xbb\xbf", format("\xef\xbb\xbf"));
+ EXPECT_EQ("\xef\xbb\xbf#include <iostream>",
+ format("\xef\xbb\xbf#include <iostream>"));
+ EXPECT_EQ("\xef\xbb\xbf\n#include <iostream>",
+ format("\xef\xbb\xbf\n#include <iostream>"));
+}
+
+// FIXME: Encode Cyrillic and CJK characters below to appease MS compilers.
+#if !defined(_MSC_VER)
+
+TEST_F(FormatTest, CountsUTF8CharactersProperly) {
+ verifyFormat("\"Однажды в Ñтудёную зимнюю пору...\"",
+ getLLVMStyleWithColumns(35));
+ verifyFormat("\"一 二 三 å›› 五 å…­ 七 å…« ä¹ å\"",
+ getLLVMStyleWithColumns(31));
+ verifyFormat("// Однажды в Ñтудёную зимнюю пору...",
+ getLLVMStyleWithColumns(36));
+ verifyFormat("// 一 二 三 å›› 五 å…­ 七 å…« ä¹ å",
+ getLLVMStyleWithColumns(32));
+ verifyFormat("/* Однажды в Ñтудёную зимнюю пору... */",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("/* 一 二 三 å›› 五 å…­ 七 å…« ä¹ å */",
+ getLLVMStyleWithColumns(35));
+}
+
+TEST_F(FormatTest, SplitsUTF8Strings) {
+ EXPECT_EQ(
+ "\"Однажды, в \"\n"
+ "\"Ñтудёную \"\n"
+ "\"зимнюю \"\n"
+ "\"пору,\"",
+ format("\"Однажды, в Ñтудёную зимнюю пору,\"",
+ getLLVMStyleWithColumns(13)));
+ EXPECT_EQ("\"一 二 三 \"\n"
+ "\"四 五六 \"\n"
+ "\"七 å…« ä¹ \"\n"
+ "\"å\"",
+ format("\"一 二 三 å›› 五六 七 å…« ä¹ å\"",
+ getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("\"一\t二 \"\n"
+ "\"\t三 \"\n"
+ "\"四 五\t六 \"\n"
+ "\"\t七 \"\n"
+ "\"å…«ä¹å\tqq\"",
+ format("\"一\t二 \t三 å›› 五\tå…­ \t七 å…«ä¹å\tqq\"",
+ getLLVMStyleWithColumns(11)));
+}
+
+
+TEST_F(FormatTest, HandlesDoubleWidthCharsInMultiLineStrings) {
+ EXPECT_EQ("const char *sssss =\n"
+ " \"一二三四五六七八\\\n"
+ " ä¹ å\";",
+ format("const char *sssss = \"一二三四五六七八\\\n"
+ " ä¹ å\";",
+ getLLVMStyleWithColumns(30)));
+}
+
+TEST_F(FormatTest, SplitsUTF8LineComments) {
+ EXPECT_EQ("// Я из леÑу\n"
+ "// вышел; был\n"
+ "// Ñильный\n"
+ "// мороз.",
+ format("// Я из леÑу вышел; был Ñильный мороз.",
+ getLLVMStyleWithColumns(13)));
+ EXPECT_EQ("// 一二三\n"
+ "// 四五六七\n"
+ "// å…« ä¹\n"
+ "// å",
+ format("// 一二三 四五六七 å…« ä¹ å", getLLVMStyleWithColumns(9)));
+}
+
+TEST_F(FormatTest, SplitsUTF8BlockComments) {
+ EXPECT_EQ("/* ГлÑжу,\n"
+ " * поднимаетÑÑ\n"
+ " * медленно в\n"
+ " * гору\n"
+ " * Лошадка,\n"
+ " * везущаÑ\n"
+ " * хвороÑту\n"
+ " * воз. */",
+ format("/* ГлÑжу, поднимаетÑÑ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾ в гору\n"
+ " * Лошадка, Ð²ÐµÐ·ÑƒÑ‰Ð°Ñ Ñ…Ð²Ð¾Ñ€Ð¾Ñту воз. */",
+ getLLVMStyleWithColumns(13)));
+ EXPECT_EQ(
+ "/* 一二三\n"
+ " * 四五六七\n"
+ " * å…« ä¹\n"
+ " * å */",
+ format("/* 一二三 四五六七 å…« ä¹ å */", getLLVMStyleWithColumns(9)));
+ EXPECT_EQ("/* ð“£ð“®ð“¼ð“½ ð”£ð”¬ð”²ð”¯\n"
+ " * ð•“ð•ªð•¥ð•–\n"
+ " * ð–€ð•¿ð•±-🠠*/",
+ format("/* ð“£ð“®ð“¼ð“½ ð”£ð”¬ð”²ð”¯ ð•“ð•ªð•¥ð•– ð–€ð•¿ð•±-🠠*/", getLLVMStyleWithColumns(12)));
+}
+
+#endif // _MSC_VER
+
+TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
+ FormatStyle Style = getLLVMStyle();
+
+ Style.ConstructorInitializerIndentWidth = 4;
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ Style);
+
+ Style.ConstructorInitializerIndentWidth = 2;
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ Style);
+
+ Style.ConstructorInitializerIndentWidth = 0;
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ ": aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ Style);
+
+ Style.BreakConstructorInitializersBeforeComma = true;
+ Style.ConstructorInitializerIndentWidth = 4;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ " , b(b)\n"
+ " , c(c) {}",
+ Style);
+
+ Style.ConstructorInitializerIndentWidth = 2;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ " , b(b)\n"
+ " , c(c) {}",
+ Style);
+
+ Style.ConstructorInitializerIndentWidth = 0;
+ verifyFormat("SomeClass::Constructor()\n"
+ ": a(a)\n"
+ ", b(b)\n"
+ ", c(c) {}",
+ Style);
+
+ Style.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ Style.ConstructorInitializerIndentWidth = 4;
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa) {}",
+ Style);
+ Style.ConstructorInitializerIndentWidth = 4;
+ Style.ColumnLimit = 60;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : aaaaaaaa(aaaaaaaa)\n"
+ " , aaaaaaaa(aaaaaaaa)\n"
+ " , aaaaaaaa(aaaaaaaa) {}",
+ Style);
+}
+
+TEST_F(FormatTest, FormatsWithWebKitStyle) {
+ FormatStyle Style = getWebKitStyle();
+
+ // Don't indent in outer namespaces.
+ verifyFormat("namespace outer {\n"
+ "int i;\n"
+ "namespace inner {\n"
+ " int i;\n"
+ "} // namespace inner\n"
+ "} // namespace outer\n"
+ "namespace other_outer {\n"
+ "int i;\n"
+ "}",
+ Style);
+
+ // Don't indent case labels.
+ verifyFormat("switch (variable) {\n"
+ "case 1:\n"
+ "case 2:\n"
+ " doSomething();\n"
+ " break;\n"
+ "default:\n"
+ " ++variable;\n"
+ "}",
+ Style);
+
+ // Wrap before binary operators.
+ EXPECT_EQ(
+ "void f()\n"
+ "{\n"
+ " if (aaaaaaaaaaaaaaaa\n"
+ " && bbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " && (cccccccccccccccccccccccccc || dddddddddddddddddddd))\n"
+ " return;\n"
+ "}",
+ format(
+ "void f() {\n"
+ "if (aaaaaaaaaaaaaaaa\n"
+ "&& bbbbbbbbbbbbbbbbbbbbbbbb\n"
+ "&& (cccccccccccccccccccccccccc || dddddddddddddddddddd))\n"
+ "return;\n"
+ "}",
+ Style));
+
+ // Constructor initializers are formatted one per line with the "," on the
+ // new line.
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n"
+ " aaaaaaaaaaaaaa)\n"
+ " , aaaaaaaaaaaaaaaaaaaaaaa()\n{\n}",
+ Style);
+
+ // Access specifiers should be aligned left.
+ verifyFormat("class C {\n"
+ "public:\n"
+ " int i;\n"
+ "};",
+ Style);
+
+ // Do not align comments.
+ verifyFormat("int a; // Do not\n"
+ "double b; // align comments.",
+ Style);
+
+ // Accept input's line breaks.
+ EXPECT_EQ("if (aaaaaaaaaaaaaaa\n"
+ " || bbbbbbbbbbbbbbb) {\n"
+ " i++;\n"
+ "}",
+ format("if (aaaaaaaaaaaaaaa\n"
+ "|| bbbbbbbbbbbbbbb) { i++; }",
+ Style));
+ EXPECT_EQ("if (aaaaaaaaaaaaaaa || bbbbbbbbbbbbbbb) {\n"
+ " i++;\n"
+ "}",
+ format("if (aaaaaaaaaaaaaaa || bbbbbbbbbbbbbbb) { i++; }", Style));
+
+ // Don't automatically break all macro definitions (llvm.org/PR17842).
+ verifyFormat("#define aNumber 10", Style);
+ // However, generally keep the line breaks that the user authored.
+ EXPECT_EQ("#define aNumber \\\n"
+ " 10",
+ format("#define aNumber \\\n"
+ " 10",
+ Style));
+}
+
+TEST_F(FormatTest, FormatsProtocolBufferDefinitions) {
+ // It seems that clang-format can format protocol buffer definitions
+ // (see https://code.google.com/p/protobuf/).
+ verifyFormat("message SomeMessage {\n"
+ " required int32 field1 = 1;\n"
+ " optional string field2 = 2 [default = \"2\"]\n"
"}");
}
+TEST_F(FormatTest, FormatsLambdas) {
+ verifyFormat("int c = [b]() mutable {\n"
+ " return [&b] { return b++; }();\n"
+ "}();\n");
+ verifyFormat("int c = [&] {\n"
+ " [=] { return b++; }();\n"
+ "}();\n");
+ verifyFormat("int c = [&, &a, a] {\n"
+ " [=, c, &d] { return b++; }();\n"
+ "}();\n");
+ verifyFormat("int c = [&a, &a, a] {\n"
+ " [=, a, b, &c] { return b++; }();\n"
+ "}();\n");
+ verifyFormat("auto c = { [&a, &a, a] {\n"
+ " [=, a, b, &c] { return b++; }();\n"
+ "} }\n");
+ verifyFormat("auto c = { [&a, &a, a] { [=, a, b, &c] {}(); } }\n");
+ verifyFormat("void f() {\n"
+ " other(x.begin(), x.end(), [&](int, int) { return 1; });\n"
+ "}\n");
+ verifyFormat("void f() {\n"
+ " other(x.begin(), //\n"
+ " x.end(), //\n"
+ " [&](int, int) { return 1; });\n"
+ "}\n");
+
+ // Not lambdas.
+ verifyFormat("constexpr char hello[]{ \"hello\" };");
+ verifyFormat("double &operator[](int i) { return 0; }\n"
+ "int i;");
+}
+
+TEST_F(FormatTest, FormatsBlocks) {
+ // FIXME: Make whitespace formatting consistent. Ask a ObjC dev how
+ // it would ideally look.
+ verifyFormat("[operation setCompletionBlock:^{ [self onOperationDone]; }];");
+ verifyFormat("int i = {[operation setCompletionBlock : ^{ [self "
+ "onOperationDone]; }] };");
+}
+
+TEST_F(FormatTest, SupportsCRLF) {
+ EXPECT_EQ("int a;\r\n"
+ "int b;\r\n"
+ "int c;\r\n",
+ format("int a;\r\n"
+ " int b;\r\n"
+ " int c;\r\n",
+ getLLVMStyle()));
+ EXPECT_EQ("int a;\r\n"
+ "int b;\r\n"
+ "int c;\r\n",
+ format("int a;\r\n"
+ " int b;\n"
+ " int c;\r\n",
+ getLLVMStyle()));
+ EXPECT_EQ("int a;\n"
+ "int b;\n"
+ "int c;\n",
+ format("int a;\r\n"
+ " int b;\n"
+ " int c;\n",
+ getLLVMStyle()));
+ EXPECT_EQ("\"aaaaaaa \"\r\n"
+ "\"bbbbbbb\";\r\n",
+ format("\"aaaaaaa bbbbbbb\";\r\n", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("#define A \\\r\n"
+ " b; \\\r\n"
+ " c; \\\r\n"
+ " d;\r\n",
+ format("#define A \\\r\n"
+ " b; \\\r\n"
+ " c; d; \r\n",
+ getGoogleStyle()));
+
+ EXPECT_EQ("/*\r\n"
+ "multi line block comments\r\n"
+ "should not introduce\r\n"
+ "an extra carriage return\r\n"
+ "*/\r\n",
+ format("/*\r\n"
+ "multi line block comments\r\n"
+ "should not introduce\r\n"
+ "an extra carriage return\r\n"
+ "*/\r\n"));
+}
+
+TEST_F(FormatTest, MunchSemicolonAfterBlocks) {
+ verifyFormat("MY_CLASS(C) {\n"
+ " int i;\n"
+ " int j;\n"
+ "};");
+}
+
+TEST_F(FormatTest, ConfigurableContinuationIndentWidth) {
+ FormatStyle TwoIndent = getLLVMStyleWithColumns(15);
+ TwoIndent.ContinuationIndentWidth = 2;
+
+ EXPECT_EQ("int i =\n"
+ " longFunction(\n"
+ " arg);",
+ format("int i = longFunction(arg);", TwoIndent));
+
+ FormatStyle SixIndent = getLLVMStyleWithColumns(20);
+ SixIndent.ContinuationIndentWidth = 6;
+
+ EXPECT_EQ("int i =\n"
+ " longFunction(\n"
+ " arg);",
+ format("int i = longFunction(arg);", SixIndent));
+}
+
+TEST_F(FormatTest, SpacesInAngles) {
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpacesInAngles = true;
+
+ verifyFormat("static_cast< int >(arg);", Spaces);
+ verifyFormat("template < typename T0, typename T1 > void f() {}", Spaces);
+ verifyFormat("f< int, float >();", Spaces);
+ verifyFormat("template <> g() {}", Spaces);
+ verifyFormat("template < std::vector< int > > f() {}", Spaces);
+
+ Spaces.Standard = FormatStyle::LS_Cpp03;
+ Spaces.SpacesInAngles = true;
+ verifyFormat("A< A< int > >();", Spaces);
+
+ Spaces.SpacesInAngles = false;
+ verifyFormat("A<A<int> >();", Spaces);
+
+ Spaces.Standard = FormatStyle::LS_Cpp11;
+ Spaces.SpacesInAngles = true;
+ verifyFormat("A< A< int > >();", Spaces);
+
+ Spaces.SpacesInAngles = false;
+ verifyFormat("A<A<int>>();", Spaces);
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/Makefile b/unittests/Format/Makefile
index e9d0cbbbb4f6..7de127caafa2 100644
--- a/unittests/Format/Makefile
+++ b/unittests/Format/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = Format
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
clangDriver.a clangParse.a clangRewriteCore.a \
clangRewriteFrontend.a clangSema.a clangAnalysis.a clangEdit.a \
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index f61791bcc0a9..7de9fb4778b4 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = Frontend
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 78838c082981..cb3b9275dbdd 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -5,5 +5,5 @@ add_clang_unittest(LexTests
)
target_link_libraries(LexTests
- clangLex
+ clangLex clangParse clangSema
)
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index c9b1840e1c04..40ce928014d5 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -28,6 +28,20 @@ using namespace clang;
namespace {
+class VoidModuleLoader : public ModuleLoader {
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return ModuleLoadResult();
+ }
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
+};
+
// The test fixture.
class LexerTest : public ::testing::Test {
protected:
@@ -42,6 +56,48 @@ protected:
Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
}
+ std::vector<Token> CheckLex(StringRef Source,
+ ArrayRef<tok::TokenKind> ExpectedTokens) {
+ MemoryBuffer *buf = MemoryBuffer::getMemBuffer(Source);
+ (void) SourceMgr.createMainFileIDForMemBuffer(buf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
+ Target.getPtr());
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/ false,
+ /*DelayInitialization =*/ false);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ EXPECT_EQ(ExpectedTokens.size(), toks.size());
+ for (unsigned i = 0, e = ExpectedTokens.size(); i != e; ++i) {
+ EXPECT_EQ(ExpectedTokens[i], toks[i].getKind());
+ }
+
+ return toks;
+ }
+
+ std::string getSourceText(Token Begin, Token End) {
+ bool Invalid;
+ StringRef Str =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(SourceRange(
+ Begin.getLocation(), End.getLocation())),
+ SourceMgr, LangOpts, &Invalid);
+ if (Invalid)
+ return "<INVALID>";
+ return Str;
+ }
+
FileSystemOptions FileMgrOpts;
FileManager FileMgr;
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
@@ -52,65 +108,179 @@ protected:
IntrusiveRefCntPtr<TargetInfo> Target;
};
-class VoidModuleLoader : public ModuleLoader {
- virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
- return ModuleLoadResult();
- }
+TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
- virtual void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc,
- bool Complain) { }
-};
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(f(M(i)))",
+ ExpectedTokens);
+
+ EXPECT_EQ("M(i)", getSourceText(toks[2], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgumentForEndOfMacro) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(M(i) c)",
+ ExpectedTokens);
+
+ EXPECT_EQ("M(i)", getSourceText(toks[0], toks[0]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsInMacroArgumentForBeginOfMacro) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(c c M(i))",
+ ExpectedTokens);
+
+ EXPECT_EQ("c M(i)", getSourceText(toks[1], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsInMacroArgumentForEndOfMacro) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(M(i) c c)",
+ ExpectedTokens);
+
+ EXPECT_EQ("M(i) c", getSourceText(toks[0], toks[1]));
+}
+
+TEST_F(LexerTest, GetSourceTextInSeparateFnMacros) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(c M(i)) M(M(i) c)",
+ ExpectedTokens);
+
+ EXPECT_EQ("<INVALID>", getSourceText(toks[1], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextWorksAcrossTokenPastes) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "#define C(x) M(x##c)\n"
+ "M(f(C(i)))",
+ ExpectedTokens);
+
+ EXPECT_EQ("C(i)", getSourceText(toks[2], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsAcrossMultipleMacroCalls) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "f(M(M(i)))",
+ ExpectedTokens);
+ EXPECT_EQ("M(M(i))", getSourceText(toks[2], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextInMiddleOfMacroArgument) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "M(f(i))",
+ ExpectedTokens);
+ EXPECT_EQ("i", getSourceText(toks[2], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsAroundDifferentMacroCalls) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "#define C(x) x\n"
+ "f(C(M(i)))",
+ ExpectedTokens);
+ EXPECT_EQ("C(M(i))", getSourceText(toks[2], toks[2]));
+}
+
+TEST_F(LexerTest, GetSourceTextOnlyExpandsIfFirstTokenInMacro) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "#define C(x) c x\n"
+ "f(C(M(i)))",
+ ExpectedTokens);
+ EXPECT_EQ("M(i)", getSourceText(toks[3], toks[3]));
+}
+
+TEST_F(LexerTest, GetSourceTextExpandsRecursively) {
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::l_paren);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_paren);
+
+ std::vector<Token> toks = CheckLex("#define M(x) x\n"
+ "#define C(x) c M(x)\n"
+ "C(f(M(i)))",
+ ExpectedTokens);
+ EXPECT_EQ("M(i)", getSourceText(toks[3], toks[3]));
+}
TEST_F(LexerTest, LexAPI) {
- const char *source =
- "#define M(x) [x]\n"
- "#define N(x) x\n"
- "#define INN(x) x\n"
- "#define NOF1 INN(val)\n"
- "#define NOF2 val\n"
- "M(foo) N([bar])\n"
- "N(INN(val)) N(NOF1) N(NOF2) N(val)";
-
- MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
- (void)SourceMgr.createMainFileIDForMemBuffer(buf);
-
- VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
- Target.getPtr());
- Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
- SourceMgr, HeaderInfo, ModLoader,
- /*IILookup =*/ 0,
- /*OwnsHeaderSearch =*/false,
- /*DelayInitialization =*/ false);
- PP.EnterMainSourceFile();
-
- std::vector<Token> toks;
- while (1) {
- Token tok;
- PP.Lex(tok);
- if (tok.is(tok::eof))
- break;
- toks.push_back(tok);
- }
+ std::vector<tok::TokenKind> ExpectedTokens;
+ ExpectedTokens.push_back(tok::l_square);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_square);
+ ExpectedTokens.push_back(tok::l_square);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::r_square);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+ ExpectedTokens.push_back(tok::identifier);
+
+ std::vector<Token> toks = CheckLex("#define M(x) [x]\n"
+ "#define N(x) x\n"
+ "#define INN(x) x\n"
+ "#define NOF1 INN(val)\n"
+ "#define NOF2 val\n"
+ "M(foo) N([bar])\n"
+ "N(INN(val)) N(NOF1) N(NOF2) N(val)",
+ ExpectedTokens);
- // Make sure we got the tokens that we expected.
- ASSERT_EQ(10U, toks.size());
- ASSERT_EQ(tok::l_square, toks[0].getKind());
- ASSERT_EQ(tok::identifier, toks[1].getKind());
- ASSERT_EQ(tok::r_square, toks[2].getKind());
- ASSERT_EQ(tok::l_square, toks[3].getKind());
- ASSERT_EQ(tok::identifier, toks[4].getKind());
- ASSERT_EQ(tok::r_square, toks[5].getKind());
- ASSERT_EQ(tok::identifier, toks[6].getKind());
- ASSERT_EQ(tok::identifier, toks[7].getKind());
- ASSERT_EQ(tok::identifier, toks[8].getKind());
- ASSERT_EQ(tok::identifier, toks[9].getKind());
-
SourceLocation lsqrLoc = toks[0].getLocation();
SourceLocation idLoc = toks[1].getLocation();
SourceLocation rsqrLoc = toks[2].getLocation();
diff --git a/unittests/Lex/Makefile b/unittests/Lex/Makefile
index bb9c6bc3901d..fa233ce25f33 100644
--- a/unittests/Lex/Makefile
+++ b/unittests/Lex/Makefile
@@ -9,7 +9,8 @@
CLANG_LEVEL = ../..
TESTNAME = Lex
-LINK_COMPONENTS := support mc
-USEDLIBS = clangLex.a clangBasic.a
+LINK_COMPONENTS := mcparser support mc
+USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \
+ clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 36bd5f939591..9405a84024bd 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -18,8 +18,12 @@
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -77,6 +81,31 @@ public:
const Module* Imported;
};
+// Stub to collect data from PragmaOpenCLExtension callbacks.
+class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
+public:
+ typedef struct {
+ SmallString<16> Name;
+ unsigned State;
+ } CallbackParameters;
+
+ PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
+
+ void PragmaOpenCLExtension(
+ clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
+ clang::SourceLocation StateLoc, unsigned State) {
+ this->NameLoc = NameLoc;
+ this->Name = Name->getName();
+ this->StateLoc = StateLoc;
+ this->State = State;
+ };
+
+ SourceLocation NameLoc;
+ SmallString<16> Name;
+ SourceLocation StateLoc;
+ unsigned State;
+};
+
// PPCallbacks test fixture.
class PPCallbacksTest : public ::testing::Test {
protected:
@@ -133,7 +162,8 @@ protected:
VoidModuleLoader ModLoader;
IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
- HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr());
+ HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
+ Target.getPtr());
AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
@@ -159,6 +189,53 @@ protected:
// Callbacks have been executed at this point -- return filename range.
return Callbacks->FilenameRange;
}
+
+ PragmaOpenCLExtensionCallbacks::CallbackParameters
+ PragmaOpenCLExtensionCall(const char* SourceText) {
+ LangOptions OpenCLLangOpts;
+ OpenCLLangOpts.OpenCL = 1;
+
+ MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
+ (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
+ OpenCLLangOpts, Target.getPtr());
+
+ Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+
+ // parser actually sets correct pragma handlers for preprocessor
+ // according to LangOptions, so we init Parser to register opencl
+ // pragma handlers
+ ASTContext Context(OpenCLLangOpts, SourceMgr, Target.getPtr(),
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo(), 0);
+ ASTConsumer Consumer;
+ Sema S(PP, Context, Consumer);
+ Parser P(PP, S, false);
+ PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
+ PP.addPPCallbacks(Callbacks); // Takes ownership.
+
+ // Lex source text.
+ PP.EnterMainSourceFile();
+ while (true) {
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.is(tok::eof))
+ break;
+ }
+
+ PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
+ Callbacks->Name,
+ Callbacks->State
+ };
+ return RetVal;
+ }
};
TEST_F(PPCallbacksTest, QuotedFilename) {
@@ -247,4 +324,28 @@ TEST_F(PPCallbacksTest, TrigraphInMacro) {
ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
}
+TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
+ const char* Source =
+ "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
+
+ PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
+ PragmaOpenCLExtensionCall(Source);
+
+ ASSERT_EQ("cl_khr_fp64", Parameters.Name);
+ unsigned ExpectedState = 1;
+ ASSERT_EQ(ExpectedState, Parameters.State);
+}
+
+TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
+ const char* Source =
+ "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
+
+ PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
+ PragmaOpenCLExtensionCall(Source);
+
+ ASSERT_EQ("cl_khr_fp16", Parameters.Name);
+ unsigned ExpectedState = 0;
+ ASSERT_EQ(ExpectedState, Parameters.State);
+}
+
} // anonoymous namespace
diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 082eced2d854..58857fa5a133 100644
--- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -90,7 +90,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
Target.getPtr());
Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
diff --git a/unittests/Makefile b/unittests/Makefile
index e01a6ac463bb..d0dfe471d159 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -19,14 +19,10 @@ PARALLEL_DIRS = Basic Lex
include $(CLANG_LEVEL)/../..//Makefile.config
ifeq ($(ENABLE_CLANG_REWRITER),1)
-PARALLEL_DIRS += Format
+PARALLEL_DIRS += Format ASTMatchers AST Tooling Sema
endif
-ifeq ($(ENABLE_CLANG_REWRITER),1)
-PARALLEL_DIRS += ASTMatchers AST Tooling
-endif
-
-ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+ifeq ($(ENABLE_CLANG_ARCMT),1)
PARALLEL_DIRS += Frontend
endif
diff --git a/unittests/Sema/CMakeLists.txt b/unittests/Sema/CMakeLists.txt
new file mode 100644
index 000000000000..d491655d415a
--- /dev/null
+++ b/unittests/Sema/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_clang_unittest(SemaTests
+ ExternalSemaSourceTest.cpp
+ )
+
+target_link_libraries(SemaTests
+ clangAST clangASTMatchers clangTooling
+ )
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp
new file mode 100644
index 000000000000..e27d0cd1e397
--- /dev/null
+++ b/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -0,0 +1,266 @@
+//=== unittests/Sema/ExternalSemaSourceTest.cpp - ExternalSemaSource 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/ASTContext.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/TypoCorrection.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace clang::tooling;
+
+namespace {
+
+// \brief Counts the number of times MaybeDiagnoseMissingCompleteType
+// is called. Returns the result it was provided on creation.
+class CompleteTypeDiagnoser : public clang::ExternalSemaSource {
+public:
+ CompleteTypeDiagnoser(bool MockResult) : CallCount(0), Result(MockResult) {}
+
+ virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation L, QualType T) {
+ ++CallCount;
+ return Result;
+ }
+
+ int CallCount;
+ bool Result;
+};
+
+// \brief Counts the number of err_using_directive_member_suggest diagnostics
+// correcting from one namespace to another while still passing all diagnostics
+// along a chain of consumers.
+class NamespaceDiagnosticWatcher : public clang::DiagnosticConsumer {
+ DiagnosticConsumer *Chained;
+ std::string FromNS;
+ std::string ToNS;
+
+public:
+ NamespaceDiagnosticWatcher(StringRef From, StringRef To)
+ : Chained(NULL), FromNS(From), ToNS("'"), SeenCount(0) {
+ ToNS.append(To);
+ ToNS.append("'");
+ }
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ if (Chained)
+ Chained->HandleDiagnostic(DiagLevel, Info);
+ if (Info.getID() - 1 == diag::err_using_directive_member_suggest) {
+ const IdentifierInfo *Ident = Info.getArgIdentifier(0);
+ const std::string &CorrectedQuotedStr = Info.getArgStdStr(1);
+ if (Ident->getName() == FromNS && CorrectedQuotedStr == ToNS)
+ ++SeenCount;
+ }
+ }
+
+ virtual void clear() {
+ DiagnosticConsumer::clear();
+ if (Chained)
+ Chained->clear();
+ }
+
+ virtual bool IncludeInDiagnosticCounts() const {
+ if (Chained)
+ return Chained->IncludeInDiagnosticCounts();
+ return false;
+ }
+
+ NamespaceDiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) {
+ Chained = ToChain;
+ return this;
+ }
+
+ int SeenCount;
+};
+
+// \brief Always corrects a typo matching CorrectFrom with a new namespace
+// with the name CorrectTo.
+class NamespaceTypoProvider : public clang::ExternalSemaSource {
+ std::string CorrectFrom;
+ std::string CorrectTo;
+ Sema *CurrentSema;
+
+public:
+ NamespaceTypoProvider(StringRef From, StringRef To)
+ : CorrectFrom(From), CorrectTo(To), CurrentSema(NULL), CallCount(0) {}
+
+ virtual void InitializeSema(Sema &S) { CurrentSema = &S; }
+
+ virtual void ForgetSema() { CurrentSema = NULL; }
+
+ virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+ ++CallCount;
+ if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) {
+ DeclContext *DestContext = NULL;
+ ASTContext &Context = CurrentSema->getASTContext();
+ if (SS != NULL)
+ DestContext = CurrentSema->computeDeclContext(*SS, EnteringContext);
+ if (DestContext == NULL)
+ DestContext = Context.getTranslationUnitDecl();
+ IdentifierInfo *ToIdent =
+ CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo);
+ NamespaceDecl *NewNamespace =
+ NamespaceDecl::Create(Context, DestContext, false, Typo.getBeginLoc(),
+ Typo.getLoc(), ToIdent, NULL);
+ DestContext->addDecl(NewNamespace);
+ TypoCorrection Correction(ToIdent);
+ Correction.addCorrectionDecl(NewNamespace);
+ return Correction;
+ }
+ return TypoCorrection();
+ }
+
+ int CallCount;
+};
+
+// \brief Chains together a vector of NamespaceDiagnosticWatchers and
+// adds a vector of ExternalSemaSources to the CompilerInstance before
+// performing semantic analysis.
+class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
+ std::vector<NamespaceDiagnosticWatcher *> Watchers;
+ std::vector<clang::ExternalSemaSource *> Sources;
+ llvm::OwningPtr<DiagnosticConsumer> OwnedClient;
+
+protected:
+ virtual clang::ASTConsumer *
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef /* dummy */) {
+ return new clang::ASTConsumer();
+ }
+
+ virtual void ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ ASSERT_FALSE(CI.hasSema());
+ CI.createSema(getTranslationUnitKind(), NULL);
+ ASSERT_TRUE(CI.hasDiagnostics());
+ DiagnosticsEngine &Diagnostics = CI.getDiagnostics();
+ DiagnosticConsumer *Client = Diagnostics.getClient();
+ if (Diagnostics.ownsClient())
+ OwnedClient.reset(Diagnostics.takeClient());
+ for (size_t I = 0, E = Watchers.size(); I < E; ++I)
+ Client = Watchers[I]->Chain(Client);
+ Diagnostics.setClient(Client, false);
+ for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+ Sources[I]->InitializeSema(CI.getSema());
+ CI.getSema().addExternalSource(Sources[I]);
+ }
+ ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
+ CI.getFrontendOpts().SkipFunctionBodies);
+ }
+
+public:
+ void PushSource(clang::ExternalSemaSource *Source) {
+ Sources.push_back(Source);
+ }
+
+ void PushWatcher(NamespaceDiagnosticWatcher *Watcher) {
+ Watchers.push_back(Watcher);
+ }
+};
+
+// Make sure that the NamespaceDiagnosticWatcher is not miscounting.
+TEST(ExternalSemaSource, SanityCheck) {
+ llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ new ExternalSemaSourceInstaller);
+ NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+ Installer->PushWatcher(&Watcher);
+ std::vector<std::string> Args(1, "-std=c++11");
+ ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+ Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ ASSERT_EQ(0, Watcher.SeenCount);
+}
+
+// Check that when we add a NamespaceTypeProvider, we use that suggestion
+// instead of the usual suggestion we would use above.
+TEST(ExternalSemaSource, ExternalTypoCorrectionPrioritized) {
+ llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ new ExternalSemaSourceInstaller);
+ NamespaceTypoProvider Provider("AAB", "BBB");
+ NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+ Installer->PushSource(&Provider);
+ Installer->PushWatcher(&Watcher);
+ std::vector<std::string> Args(1, "-std=c++11");
+ ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+ Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ ASSERT_LE(0, Provider.CallCount);
+ ASSERT_EQ(1, Watcher.SeenCount);
+}
+
+// Check that we use the first successful TypoCorrection returned from an
+// ExternalSemaSource.
+TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) {
+ llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ new ExternalSemaSourceInstaller);
+ NamespaceTypoProvider First("XXX", "BBB");
+ NamespaceTypoProvider Second("AAB", "CCC");
+ NamespaceTypoProvider Third("AAB", "DDD");
+ NamespaceDiagnosticWatcher Watcher("AAB", "CCC");
+ Installer->PushSource(&First);
+ Installer->PushSource(&Second);
+ Installer->PushSource(&Third);
+ Installer->PushWatcher(&Watcher);
+ std::vector<std::string> Args(1, "-std=c++11");
+ ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+ Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ ASSERT_LE(1, First.CallCount);
+ ASSERT_LE(1, Second.CallCount);
+ ASSERT_EQ(0, Third.CallCount);
+ ASSERT_EQ(1, Watcher.SeenCount);
+}
+
+// We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise
+// solve the problem.
+TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) {
+ llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ new ExternalSemaSourceInstaller);
+ CompleteTypeDiagnoser Diagnoser(false);
+ Installer->PushSource(&Diagnoser);
+ std::vector<std::string> Args(1, "-std=c++11");
+ // This code hits the class template specialization/class member of a class
+ // template specialization checks in Sema::RequireCompleteTypeImpl.
+ ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+ Installer.take(),
+ "template <typename T> struct S { class C { }; }; S<char>::C SCInst;",
+ Args));
+ ASSERT_EQ(0, Diagnoser.CallCount);
+}
+
+// The first ExternalSemaSource where MaybeDiagnoseMissingCompleteType returns
+// true should be the last one called.
+TEST(ExternalSemaSource, FirstDiagnoserTaken) {
+ llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ new ExternalSemaSourceInstaller);
+ CompleteTypeDiagnoser First(false);
+ CompleteTypeDiagnoser Second(true);
+ CompleteTypeDiagnoser Third(true);
+ Installer->PushSource(&First);
+ Installer->PushSource(&Second);
+ Installer->PushSource(&Third);
+ std::vector<std::string> Args(1, "-std=c++11");
+ ASSERT_FALSE(clang::tooling::runToolOnCodeWithArgs(
+ Installer.take(), "class Incomplete; Incomplete IncompleteInstance;",
+ Args));
+ ASSERT_EQ(1, First.CallCount);
+ ASSERT_EQ(1, Second.CallCount);
+ ASSERT_EQ(0, Third.CallCount);
+}
+
+} // anonymous namespace
diff --git a/unittests/Sema/Makefile b/unittests/Sema/Makefile
new file mode 100644
index 000000000000..cd1d93df5b33
--- /dev/null
+++ b/unittests/Sema/Makefile
@@ -0,0 +1,19 @@
+##===- unittests/Sema/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = Sema
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewriteCore.a clangRewriteFrontend.a \
+ clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 245c0599d427..33d761700738 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_unittest(ToolingTests
RefactoringTest.cpp
RewriterTest.cpp
RefactoringCallbacksTest.cpp
+ ReplacementsYamlTest.cpp
)
target_link_libraries(ToolingTests
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index c453b056d257..c575dff209a7 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -14,7 +14,7 @@
#include "clang/Tooling/FileMatchTrie.h"
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
namespace clang {
@@ -450,18 +450,20 @@ TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
int Argc = 5;
- const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" };
+ const char *Argv[] = {
+ "1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4"
+ };
OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database);
+ ASSERT_TRUE(Database.isValid());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
ASSERT_EQ(".", Result[0].Directory);
std::vector<std::string> CommandLine;
CommandLine.push_back("clang-tool");
- CommandLine.push_back("3");
- CommandLine.push_back("4");
+ CommandLine.push_back("-DDEF3");
+ CommandLine.push_back("-DDEF4");
CommandLine.push_back("source");
ASSERT_EQ(CommandLine, Result[0].CommandLine);
EXPECT_EQ(2, Argc);
@@ -472,7 +474,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database);
+ ASSERT_TRUE(Database.isValid());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -484,5 +486,41 @@ TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
EXPECT_EQ(2, Argc);
}
+TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
+ const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"};
+ int Argc = sizeof(Argv) / sizeof(char*);
+ OwningPtr<FixedCompilationDatabase> Database(
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ ASSERT_TRUE(Database.isValid());
+ 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("-c");
+ Expected.push_back("-DDEF3");
+ Expected.push_back("source");
+ ASSERT_EQ(Expected, Result[0].CommandLine);
+ EXPECT_EQ(2, Argc);
+}
+
+TEST(ParseFixedCompilationDatabase, HandlesArgv0) {
+ const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"};
+ int Argc = sizeof(Argv) / sizeof(char*);
+ OwningPtr<FixedCompilationDatabase> Database(
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ ASSERT_TRUE(Database.isValid());
+ 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("source");
+ ASSERT_EQ(Expected, Result[0].CommandLine);
+ EXPECT_EQ(2, Argc);
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
index 06fdf88a2279..9d36f1fa3b4f 100644
--- a/unittests/Tooling/Makefile
+++ b/unittests/Tooling/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = Tooling
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangParse.a clangRewriteCore.a clangRewriteFrontend.a \
clangSema.a clangAnalysis.a clangEdit.a \
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 81be19003b2a..323476766e92 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -9,6 +9,8 @@
#include "TestVisitor.h"
+#include <stack>
+
namespace clang {
class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
@@ -35,6 +37,17 @@ public:
}
};
+class ParmVarDeclVisitorForImplicitCode :
+ public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
+public:
+ bool shouldVisitImplicitCode() const { return true; }
+
+ bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
+ Match(ParamVar->getNameAsString(), ParamVar->getLocStart());
+ return true;
+ }
+};
+
class CXXMemberCallVisitor
: public ExpectedLocationVisitor<CXXMemberCallVisitor> {
public:
@@ -79,6 +92,42 @@ public:
}
};
+class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
+public:
+ bool VisitLambdaExpr(LambdaExpr *Lambda) {
+ PendingBodies.push(Lambda);
+ Match("", Lambda->getIntroducerRange().getBegin());
+ return true;
+ }
+ /// For each call to VisitLambdaExpr, we expect a subsequent call (with
+ /// proper nesting) to TraverseLambdaBody.
+ bool TraverseLambdaBody(LambdaExpr *Lambda) {
+ EXPECT_FALSE(PendingBodies.empty());
+ EXPECT_EQ(PendingBodies.top(), Lambda);
+ PendingBodies.pop();
+ return TraverseStmt(Lambda->getBody());
+ }
+ /// Determine whether TraverseLambdaBody has been called for every call to
+ /// VisitLambdaExpr.
+ bool allBodiesHaveBeenTraversed() const {
+ return PendingBodies.empty();
+ }
+private:
+ std::stack<LambdaExpr *> PendingBodies;
+};
+
+// Matches the (optional) capture-default of a lambda-introducer.
+class LambdaDefaultCaptureVisitor
+ : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
+public:
+ bool VisitLambdaExpr(LambdaExpr *Lambda) {
+ if (Lambda->getCaptureDefault() != LCD_None) {
+ Match("", Lambda->getCaptureDefaultLoc());
+ }
+ return true;
+ }
+};
+
class TemplateArgumentLocTraverser
: public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
public:
@@ -106,6 +155,24 @@ public:
}
};
+// Test RAV visits parameter variable declaration of the implicit
+// copy assignment operator and implicit copy constructor.
+TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
+ ParmVarDeclVisitorForImplicitCode Visitor;
+ // Match parameter variable name of implicit copy assignment operator and
+ // implicit copy constructor.
+ // This parameter name does not have a valid IdentifierInfo, and shares
+ // same SourceLocation with its class declaration, so we match an empty name
+ // with the class' source location.
+ Visitor.ExpectMatch("", 1, 7);
+ Visitor.ExpectMatch("", 3, 7);
+ EXPECT_TRUE(Visitor.runOver(
+ "class X {};\n"
+ "void foo(X a, X b) {a = b;}\n"
+ "class Y {};\n"
+ "void bar(Y a) {Y b = a;}"));
+}
+
TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
TypeLocVisitor Visitor;
Visitor.ExpectMatch("class X", 1, 30);
@@ -150,7 +217,8 @@ TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
Visitor.ExpectMatch("x", 2, 30);
EXPECT_TRUE(Visitor.runOver(
"int x[5];\n"
- "void f() { for (int i : x) { x[0] = 1; } }"));
+ "void f() { for (int i : x) { x[0] = 1; } }",
+ DeclRefExprVisitor::Lang_CXX11));
}
TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
@@ -158,7 +226,8 @@ TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
Visitor.ExpectMatch("i", 2, 17);
EXPECT_TRUE(Visitor.runOver(
"int x[5];\n"
- "void f() { for (int i : x) {} }"));
+ "void f() { for (int i : x) {} }",
+ VarDeclVisitor::Lang_CXX11));
}
TEST(RecursiveASTVisitor, VisitsCallExpr) {
@@ -461,4 +530,51 @@ TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
TypeLocVisitor::Lang_C));
}
+TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
+ LambdaExprVisitor Visitor;
+ Visitor.ExpectMatch("", 1, 12);
+ EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
+ LambdaExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
+ LambdaExprVisitor Visitor;
+ EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
+ LambdaExprVisitor::Lang_CXX11));
+ EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
+}
+
+TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
+ LambdaDefaultCaptureVisitor Visitor;
+ Visitor.ExpectMatch("", 1, 20);
+ EXPECT_TRUE(Visitor.runOver("void f() { int a; [=]{a;}; }",
+ LambdaDefaultCaptureVisitor::Lang_CXX11));
+}
+
+// Checks for lambda classes that are not marked as implicitly-generated.
+// (There should be none.)
+class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
+public:
+ ClassVisitor() : SawNonImplicitLambdaClass(false) {}
+ bool VisitCXXRecordDecl(CXXRecordDecl* record) {
+ if (record->isLambda() && !record->isImplicit())
+ SawNonImplicitLambdaClass = true;
+ return true;
+ }
+
+ bool sawOnlyImplicitLambdaClasses() const {
+ return !SawNonImplicitLambdaClass;
+ }
+
+private:
+ bool SawNonImplicitLambdaClass;
+};
+
+TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
+ ClassVisitor Visitor;
+ EXPECT_TRUE(Visitor.runOver("auto lambda = []{};",
+ ClassVisitor::Lang_CXX11));
+ EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
+}
+
} // end namespace clang
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index 3e0d7280b1d3..8c7bfa1c767a 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -120,6 +120,21 @@ TEST_F(ReplacementTest, CanApplyReplacements) {
EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
}
+// FIXME: Remove this test case when Replacements is implemented as std::vector
+// instead of std::set. The other ReplacementTest tests will need to be updated
+// at that point as well.
+TEST_F(ReplacementTest, VectorCanApplyReplacements) {
+ FileID ID = Context.createInMemoryFile("input.cpp",
+ "line1\nline2\nline3\nline4");
+ std::vector<Replacement> Replaces;
+ Replaces.push_back(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
+ 5, "replaced"));
+ Replaces.push_back(
+ Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 5, "other"));
+ EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
+ EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
+}
+
TEST_F(ReplacementTest, SkipsDuplicateReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
@@ -151,37 +166,87 @@ TEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) {
EXPECT_EQ("z", Context.getRewrittenText(IDz));
}
+TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
+ Replacements Replaces;
+ Replaces.insert(Replacement("", 0, 1, ""));
+ Replaces.insert(Replacement("", 4, 3, " "));
+ // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
+ EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
+ EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
+ EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
+ EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
+ EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
+}
+
+// FIXME: Remove this test case when Replacements is implemented as std::vector
+// instead of std::set. The other ReplacementTest tests will need to be updated
+// at that point as well.
+TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) {
+ std::vector<Replacement> Replaces;
+ Replaces.push_back(Replacement("", 0, 1, ""));
+ Replaces.push_back(Replacement("", 4, 3, " "));
+ // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
+ EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
+ EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
+ EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
+ EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i;
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
+ EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
+}
+
+TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
+ Replacements Replaces;
+ Replaces.insert(Replacement("", 4, 0, "\"\n\""));
+ // Assume '"12345678"' is turned into '"1234"\n"5678"'.
+ EXPECT_EQ(4u, shiftedCodePosition(Replaces, 4)); // "123|5678"
+ EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "1234|678"
+}
+
class FlushRewrittenFilesTest : public ::testing::Test {
- public:
- FlushRewrittenFilesTest() {
- std::string ErrorInfo;
- TemporaryDirectory = llvm::sys::Path::GetTemporaryDirectory(&ErrorInfo);
- assert(ErrorInfo.empty());
- }
+public:
+ FlushRewrittenFilesTest() {}
~FlushRewrittenFilesTest() {
- std::string ErrorInfo;
- TemporaryDirectory.eraseFromDisk(true, &ErrorInfo);
- assert(ErrorInfo.empty());
+ for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
+ E = TemporaryFiles.end();
+ I != E; ++I) {
+ llvm::StringRef Name = I->second;
+ llvm::error_code EC = llvm::sys::fs::remove(Name);
+ (void)EC;
+ assert(!EC);
+ }
}
FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
- SmallString<1024> Path(TemporaryDirectory.str());
- llvm::sys::path::append(Path, Name);
- std::string ErrorInfo;
- llvm::raw_fd_ostream OutStream(Path.c_str(),
- ErrorInfo, llvm::raw_fd_ostream::F_Binary);
- assert(ErrorInfo.empty());
+ SmallString<1024> Path;
+ int FD;
+ llvm::error_code EC =
+ llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
+ assert(!EC);
+ (void)EC;
+
+ llvm::raw_fd_ostream OutStream(FD, true);
OutStream << Content;
OutStream.close();
const FileEntry *File = Context.Files.getFile(Path);
assert(File != NULL);
+
+ StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second;
+ assert(Found == Path);
+ (void)Found;
return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
}
std::string getFileContentFromDisk(llvm::StringRef Name) {
- SmallString<1024> Path(TemporaryDirectory.str());
- llvm::sys::path::append(Path, Name);
+ std::string Path = TemporaryFiles.lookup(Name);
+ assert(!Path.empty());
// We need to read directly from the FileManager without relaying through
// a FileEntry, as otherwise we'd read through an already opened file
// descriptor, which might not see the changes made.
@@ -190,7 +255,7 @@ class FlushRewrittenFilesTest : public ::testing::Test {
return Context.Files.getBufferForFile(Path, NULL)->getBuffer();
}
- llvm::sys::Path TemporaryDirectory;
+ llvm::StringMap<std::string> TemporaryFiles;
RewriterTestContext Context;
};
@@ -301,5 +366,97 @@ TEST(Replacement, TemplatedFunctionCall) {
expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
}
+TEST(Range, overlaps) {
+ EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
+ EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
+ EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
+ EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
+ EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
+ EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
+}
+
+TEST(Range, contains) {
+ EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
+ EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
+ EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
+ EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
+}
+
+TEST(DeduplicateTest, removesDuplicates) {
+ std::vector<Replacement> Input;
+ Input.push_back(Replacement("fileA", 50, 0, " foo "));
+ Input.push_back(Replacement("fileA", 10, 3, " bar "));
+ Input.push_back(Replacement("fileA", 10, 2, " bar ")); // Length differs
+ Input.push_back(Replacement("fileA", 9, 3, " bar ")); // Offset differs
+ Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
+ Input.push_back(Replacement("fileA", 51, 3, " bar "));
+ Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
+ Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
+ // differs!
+
+ std::vector<Replacement> Expected;
+ Expected.push_back(Replacement("fileA", 9, 3, " bar "));
+ Expected.push_back(Replacement("fileA", 10, 2, " bar "));
+ Expected.push_back(Replacement("fileA", 10, 3, " bar "));
+ Expected.push_back(Replacement("fileA", 50, 0, " foo "));
+ Expected.push_back(Replacement("fileA", 51, 3, " bar "));
+ Expected.push_back(Replacement("fileA", 51, 3, " moo "));
+ Expected.push_back(Replacement("fileB", 51, 3, " bar "));
+
+ std::vector<Range> Conflicts; // Ignored for this test
+ deduplicate(Input, Conflicts);
+
+ ASSERT_TRUE(Expected == Input);
+}
+
+TEST(DeduplicateTest, detectsConflicts) {
+ {
+ std::vector<Replacement> Input;
+ Input.push_back(Replacement("fileA", 0, 5, " foo "));
+ Input.push_back(Replacement("fileA", 0, 5, " foo ")); // Duplicate not a
+ // conflict.
+ Input.push_back(Replacement("fileA", 2, 6, " bar "));
+ Input.push_back(Replacement("fileA", 7, 3, " moo "));
+
+ std::vector<Range> Conflicts;
+ deduplicate(Input, Conflicts);
+
+ // One duplicate is removed and the remaining three items form one
+ // conflicted range.
+ ASSERT_EQ(3u, Input.size());
+ ASSERT_EQ(1u, Conflicts.size());
+ ASSERT_EQ(0u, Conflicts.front().getOffset());
+ ASSERT_EQ(3u, Conflicts.front().getLength());
+ }
+ {
+ std::vector<Replacement> Input;
+
+ // Expected sorted order is shown. It is the sorted order to which the
+ // returned conflict info refers to.
+ Input.push_back(Replacement("fileA", 0, 5, " foo ")); // 0
+ Input.push_back(Replacement("fileA", 5, 5, " bar ")); // 1
+ Input.push_back(Replacement("fileA", 6, 0, " bar ")); // 3
+ Input.push_back(Replacement("fileA", 5, 5, " moo ")); // 2
+ Input.push_back(Replacement("fileA", 7, 2, " bar ")); // 4
+ Input.push_back(Replacement("fileA", 15, 5, " golf ")); // 5
+ Input.push_back(Replacement("fileA", 16, 5, " bag ")); // 6
+ Input.push_back(Replacement("fileA", 10, 3, " club ")); // 7
+
+ // #3 is special in that it is completely contained by another conflicting
+ // Replacement. #4 ensures #3 hasn't messed up the conflicting range size.
+
+ std::vector<Range> Conflicts;
+ deduplicate(Input, Conflicts);
+
+ // No duplicates
+ ASSERT_EQ(8u, Input.size());
+ ASSERT_EQ(2u, Conflicts.size());
+ ASSERT_EQ(1u, Conflicts[0].getOffset());
+ ASSERT_EQ(4u, Conflicts[0].getLength());
+ ASSERT_EQ(6u, Conflicts[1].getOffset());
+ ASSERT_EQ(2u, Conflicts[1].getLength());
+ }
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Tooling/ReplacementsYamlTest.cpp b/unittests/Tooling/ReplacementsYamlTest.cpp
new file mode 100644
index 000000000000..a20dde76140b
--- /dev/null
+++ b/unittests/Tooling/ReplacementsYamlTest.cpp
@@ -0,0 +1,106 @@
+//===- unittests/Tooling/ReplacementsYamlTest.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 Replacements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang::tooling;
+
+TEST(ReplacementsYamlTest, serializesReplacements) {
+
+ TranslationUnitReplacements Doc;
+
+ Doc.MainSourceFile = "/path/to/source.cpp";
+ Doc.Context = "some context";
+ Doc.Replacements
+ .push_back(Replacement("/path/to/file1.h", 232, 56, "replacement #1"));
+ Doc.Replacements
+ .push_back(Replacement("/path/to/file2.h", 301, 2, "replacement #2"));
+
+ std::string YamlContent;
+ llvm::raw_string_ostream YamlContentStream(YamlContent);
+
+ yaml::Output YAML(YamlContentStream);
+ YAML << Doc;
+
+ // NOTE: If this test starts to fail for no obvious reason, check whitespace.
+ ASSERT_STREQ("---\n"
+ "MainSourceFile: /path/to/source.cpp\n"
+ "Context: some context\n"
+ "Replacements: \n" // Extra whitespace here!
+ " - FilePath: /path/to/file1.h\n"
+ " Offset: 232\n"
+ " Length: 56\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - FilePath: /path/to/file2.h\n"
+ " Offset: 301\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ "...\n",
+ YamlContentStream.str().c_str());
+}
+
+TEST(ReplacementsYamlTest, deserializesReplacements) {
+ std::string YamlContent = "---\n"
+ "MainSourceFile: /path/to/source.cpp\n"
+ "Context: some context\n"
+ "Replacements:\n"
+ " - FilePath: /path/to/file1.h\n"
+ " Offset: 232\n"
+ " Length: 56\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - FilePath: /path/to/file2.h\n"
+ " Offset: 301\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ "...\n";
+ TranslationUnitReplacements DocActual;
+ yaml::Input YAML(YamlContent);
+ YAML >> DocActual;
+ ASSERT_FALSE(YAML.error());
+ ASSERT_EQ(2u, DocActual.Replacements.size());
+ ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile);
+ ASSERT_EQ("some context", DocActual.Context);
+ ASSERT_EQ("/path/to/file1.h", DocActual.Replacements[0].getFilePath());
+ ASSERT_EQ(232u, DocActual.Replacements[0].getOffset());
+ ASSERT_EQ(56u, DocActual.Replacements[0].getLength());
+ ASSERT_EQ("replacement #1", DocActual.Replacements[0].getReplacementText());
+ ASSERT_EQ("/path/to/file2.h", DocActual.Replacements[1].getFilePath());
+ ASSERT_EQ(301u, DocActual.Replacements[1].getOffset());
+ ASSERT_EQ(2u, DocActual.Replacements[1].getLength());
+ ASSERT_EQ("replacement #2", DocActual.Replacements[1].getReplacementText());
+}
+
+TEST(ReplacementsYamlTest, deserializesWithoutContext) {
+ // Make sure a doc can be read without the context field.
+ std::string YamlContent = "---\n"
+ "MainSourceFile: /path/to/source.cpp\n"
+ "Replacements:\n"
+ " - FilePath: target_file.h\n"
+ " Offset: 1\n"
+ " Length: 10\n"
+ " ReplacementText: replacement\n"
+ "...\n";
+ TranslationUnitReplacements DocActual;
+ yaml::Input YAML(YamlContent);
+ YAML >> DocActual;
+ ASSERT_FALSE(YAML.error());
+ ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile);
+ ASSERT_EQ(1u, DocActual.Replacements.size());
+ ASSERT_EQ(std::string(), DocActual.Context);
+ ASSERT_EQ("target_file.h", DocActual.Replacements[0].getFilePath());
+ ASSERT_EQ(1u, DocActual.Replacements[0].getOffset());
+ ASSERT_EQ(10u, DocActual.Replacements[0].getLength());
+ ASSERT_EQ("replacement", DocActual.Replacements[0].getReplacementText());
+}
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index 13c42029fc7f..841cd0f9097b 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -45,12 +45,7 @@ class RewriterTestContext {
Diagnostics.setClient(&DiagnosticPrinter, false);
}
- ~RewriterTestContext() {
- if (!TemporaryDirectory.empty()) {
- uint32_t RemovedCount = 0;
- llvm::sys::fs::remove_all(TemporaryDirectory.str(), RemovedCount);
- }
- }
+ ~RewriterTestContext() {}
FileID createInMemoryFile(StringRef Name, StringRef Content) {
const llvm::MemoryBuffer *Source =
@@ -62,26 +57,25 @@ class RewriterTestContext {
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
+ // FIXME: this code is mostly a duplicate of
+ // unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it.
FileID createOnDiskFile(StringRef Name, StringRef Content) {
- if (TemporaryDirectory.empty()) {
- int FD;
- bool error =
- llvm::sys::fs::unique_file("rewriter-test-%%-%%-%%-%%/anchor", FD,
- TemporaryDirectory);
- assert(!error); (void)error;
- llvm::raw_fd_ostream Closer(FD, /*shouldClose=*/true);
- TemporaryDirectory = llvm::sys::path::parent_path(TemporaryDirectory);
- }
- SmallString<1024> Path(TemporaryDirectory);
- llvm::sys::path::append(Path, Name);
- std::string ErrorInfo;
- llvm::raw_fd_ostream OutStream(Path.c_str(),
- ErrorInfo, llvm::raw_fd_ostream::F_Binary);
- assert(ErrorInfo.empty());
+ SmallString<1024> Path;
+ int FD;
+ llvm::error_code EC =
+ llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
+ assert(!EC);
+ (void)EC;
+
+ llvm::raw_fd_ostream OutStream(FD, true);
OutStream << Content;
OutStream.close();
const FileEntry *File = Files.getFile(Path);
assert(File != NULL);
+
+ StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second;
+ assert(Found == Path);
+ (void)Found;
return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
}
@@ -101,8 +95,8 @@ class RewriterTestContext {
}
std::string getFileContentFromDisk(StringRef Name) {
- SmallString<1024> Path(TemporaryDirectory.str());
- llvm::sys::path::append(Path, Name);
+ std::string Path = TemporaryFiles.lookup(Name);
+ assert(!Path.empty());
// We need to read directly from the FileManager without relaying through
// a FileEntry, as otherwise we'd read through an already opened file
// descriptor, which might not see the changes made.
@@ -120,7 +114,7 @@ class RewriterTestContext {
Rewriter Rewrite;
// Will be set once on disk files are generated.
- SmallString<128> TemporaryDirectory;
+ llvm::StringMap<std::string> TemporaryFiles;
};
} // end namespace clang
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index ce3246a902f1..ec751c350e06 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -31,7 +31,7 @@ namespace clang {
/// This is a drop-in replacement for RecursiveASTVisitor itself, with the
/// additional capability of running it over a snippet of code.
///
-/// Visits template instantiations (but not implicit code) by default.
+/// Visits template instantiations and implicit code by default.
template <typename T>
class TestVisitor : public RecursiveASTVisitor<T> {
public:
@@ -39,14 +39,15 @@ public:
virtual ~TestVisitor() { }
- enum Language { Lang_C, Lang_CXX };
+ enum Language { Lang_C, Lang_CXX98, Lang_CXX11, Lang_CXX=Lang_CXX98 };
/// \brief Runs the current AST visitor over the given code.
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_CXX: Args.push_back("-std=c++98"); break;
+ case Lang_CXX98: Args.push_back("-std=c++98"); break;
+ case Lang_CXX11: Args.push_back("-std=c++11"); break;
}
return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
}
@@ -55,6 +56,10 @@ public:
return true;
}
+ bool shouldVisitImplicitCode() const {
+ return true;
+ }
+
protected:
virtual ASTFrontendAction* CreateTestAction() {
return new TestAction(this);
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index a9319f296120..2c4a8a7a1565 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -10,12 +10,14 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
+#include "llvm/ADT/STLExtras.h"
#include <string>
namespace clang {
@@ -83,6 +85,18 @@ class FindClassDeclXConsumer : public clang::ASTConsumer {
private:
bool *FoundClassDeclX;
};
+bool FindClassDeclX(ASTUnit *AST) {
+ for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
+ e = AST->top_level_end();
+ i != e; ++i) {
+ if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
+ if (Record->getName() == "X") {
+ return true;
+ }
+ }
+ }
+ return false;
+}
} // end namespace
TEST(runToolOnCode, FindsClassDecl) {
@@ -97,6 +111,16 @@ TEST(runToolOnCode, FindsClassDecl) {
EXPECT_FALSE(FoundClassDeclX);
}
+TEST(buildASTFromCode, FindsClassDecl) {
+ OwningPtr<ASTUnit> AST(buildASTFromCode("class X;"));
+ ASSERT_TRUE(AST.get());
+ EXPECT_TRUE(FindClassDeclX(AST.get()));
+
+ AST.reset(buildASTFromCode("class Y;"));
+ ASSERT_TRUE(AST.get());
+ EXPECT_FALSE(FindClassDeclX(AST.get()));
+}
+
TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
OwningPtr<FrontendActionFactory> Factory(
newFrontendActionFactory<SyntaxOnlyAction>());
@@ -119,32 +143,62 @@ TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
}
TEST(ToolInvocation, TestMapVirtualFile) {
- clang::FileManager Files((clang::FileSystemOptions()));
+ IntrusiveRefCntPtr<clang::FileManager> Files(
+ new clang::FileManager(clang::FileSystemOptions()));
std::vector<std::string> Args;
Args.push_back("tool-executable");
Args.push_back("-Idef");
Args.push_back("-fsyntax-only");
Args.push_back("test.cpp");
- clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files);
+ clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
+ Files.getPtr());
Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
Invocation.mapVirtualFile("def/abc", "\n");
EXPECT_TRUE(Invocation.run());
}
-struct VerifyEndCallback : public EndOfSourceFileCallback {
- VerifyEndCallback() : Called(0), Matched(false) {}
- virtual void run() {
- ++Called;
+TEST(ToolInvocation, TestVirtualModulesCompilation) {
+ // FIXME: Currently, this only tests that we don't exit with an error if a
+ // mapped module.map is found on the include path. In the future, expand this
+ // test to run a full modules enabled compilation, so we make sure we can
+ // rerun modules compilations with a virtual file system.
+ IntrusiveRefCntPtr<clang::FileManager> Files(
+ new clang::FileManager(clang::FileSystemOptions()));
+ std::vector<std::string> Args;
+ Args.push_back("tool-executable");
+ Args.push_back("-Idef");
+ Args.push_back("-fsyntax-only");
+ Args.push_back("test.cpp");
+ clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
+ Files.getPtr());
+ Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
+ Invocation.mapVirtualFile("def/abc", "\n");
+ // Add a module.map file in the include directory of our header, so we trigger
+ // the module.map header search logic.
+ Invocation.mapVirtualFile("def/module.map", "\n");
+ EXPECT_TRUE(Invocation.run());
+}
+
+struct VerifyEndCallback : public SourceFileCallbacks {
+ VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
+ virtual bool handleBeginSource(CompilerInstance &CI,
+ StringRef Filename) LLVM_OVERRIDE {
+ ++BeginCalled;
+ return true;
+ }
+ virtual void handleEndSource() {
+ ++EndCalled;
}
ASTConsumer *newASTConsumer() {
return new FindTopLevelDeclConsumer(&Matched);
}
- unsigned Called;
+ unsigned BeginCalled;
+ unsigned EndCalled;
bool Matched;
};
#if !defined(_WIN32)
-TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
+TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
VerifyEndCallback EndCallback;
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
@@ -159,7 +213,8 @@ TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
EXPECT_TRUE(EndCallback.Matched);
- EXPECT_EQ(2u, EndCallback.Called);
+ EXPECT_EQ(2u, EndCallback.BeginCalled);
+ EXPECT_EQ(2u, EndCallback.EndCalled);
}
#endif
@@ -186,5 +241,97 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
"int skipMeNot() { an_error_here }"));
}
+struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
+ bool &Found;
+ bool &Ran;
+
+ CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
+
+ virtual CommandLineArguments
+ Adjust(const CommandLineArguments &Args) LLVM_OVERRIDE {
+ Ran = true;
+ for (unsigned I = 0, E = Args.size(); I != E; ++I) {
+ if (Args[I] == "-fsyntax-only") {
+ Found = true;
+ break;
+ }
+ }
+ return Args;
+ }
+};
+
+TEST(ClangToolTest, ArgumentAdjusters) {
+ FixedCompilationDatabase Compilations("/", std::vector<std::string>());
+
+ ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
+ Tool.mapVirtualFile("/a.cc", "void a() {}");
+
+ bool Found = false;
+ bool Ran = false;
+ Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ EXPECT_TRUE(Ran);
+ EXPECT_TRUE(Found);
+
+ Ran = Found = false;
+ Tool.clearArgumentsAdjusters();
+ Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
+ Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ EXPECT_TRUE(Ran);
+ EXPECT_FALSE(Found);
+}
+
+#ifndef _WIN32
+TEST(ClangToolTest, BuildASTs) {
+ FixedCompilationDatabase Compilations("/", std::vector<std::string>());
+
+ std::vector<std::string> Sources;
+ Sources.push_back("/a.cc");
+ Sources.push_back("/b.cc");
+ ClangTool Tool(Compilations, Sources);
+
+ Tool.mapVirtualFile("/a.cc", "void a() {}");
+ Tool.mapVirtualFile("/b.cc", "void b() {}");
+
+ std::vector<ASTUnit *> ASTs;
+ EXPECT_EQ(0, Tool.buildASTs(ASTs));
+ EXPECT_EQ(2u, ASTs.size());
+
+ llvm::DeleteContainerPointers(ASTs);
+}
+
+struct TestDiagnosticConsumer : public DiagnosticConsumer {
+ TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ ++NumDiagnosticsSeen;
+ }
+ unsigned NumDiagnosticsSeen;
+};
+
+TEST(ClangToolTest, InjectDiagnosticConsumer) {
+ FixedCompilationDatabase Compilations("/", std::vector<std::string>());
+ ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
+ Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
+ TestDiagnosticConsumer Consumer;
+ Tool.setDiagnosticConsumer(&Consumer);
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
+}
+
+TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
+ FixedCompilationDatabase Compilations("/", std::vector<std::string>());
+ ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
+ Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
+ TestDiagnosticConsumer Consumer;
+ Tool.setDiagnosticConsumer(&Consumer);
+ std::vector<ASTUnit*> ASTs;
+ Tool.buildASTs(ASTs);
+ EXPECT_EQ(1u, ASTs.size());
+ EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
+}
+#endif
+
} // end namespace tooling
} // end namespace clang
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
index 62925e7adea0..4855f4893c9d 100755
--- a/utils/ABITest/ABITestGen.py
+++ b/utils/ABITest/ABITestGen.py
@@ -482,7 +482,7 @@ def main():
if not opts.useRandomSeed:
random.seed(opts.seed)
- # Contruct type generator
+ # Construct type generator
builtins = []
if opts.useBuiltins:
ints = []
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index a858a214b03d..29a1eedb7af8 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -9,6 +9,5 @@ add_tablegen(clang-tblgen CLANG
ClangDiagnosticsEmitter.cpp
ClangSACheckersEmitter.cpp
NeonEmitter.cpp
- OptParserEmitter.cpp
TableGen.cpp
)
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index eaf10a64a4f0..653d7b79e282 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
@@ -46,7 +47,7 @@ static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "GetLocalDeclAs<"
+ std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
- .Case("QualType", "getLocalType(F, Record[Idx++])")
+ .Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
.Case("Expr *", "ReadExpr(F)")
.Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
.Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)")
@@ -58,7 +59,8 @@ static std::string WritePCHRecord(StringRef type, StringRef name) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "AddDeclRef(" + std::string(name) +
", Record);\n")
- .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n")
+ .Case("TypeSourceInfo *",
+ "AddTypeSourceInfo(" + std::string(name) + ", Record);\n")
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
.Case("IdentifierInfo *",
"AddIdentifierRef(" + std::string(name) + ", Record);\n")
@@ -95,11 +97,12 @@ namespace {
class Argument {
std::string lowerName, upperName;
StringRef attrName;
+ bool isOpt;
public:
Argument(Record &Arg, StringRef Attr)
: lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
- attrName(Attr) {
+ attrName(Attr), isOpt(false) {
if (!lowerName.empty()) {
lowerName[0] = std::tolower(lowerName[0]);
upperName[0] = std::toupper(upperName[0]);
@@ -111,6 +114,9 @@ namespace {
StringRef getUpperName() const { return upperName; }
StringRef getAttrName() const { return attrName; }
+ bool isOptional() const { return isOpt; }
+ void setOptional(bool set) { isOpt = set; }
+
// These functions print the argument contents formatted in different ways.
virtual void writeAccessors(raw_ostream &OS) const = 0;
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
@@ -119,6 +125,7 @@ namespace {
virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
virtual void writeCtorBody(raw_ostream &OS) const {}
virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
+ virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0;
virtual void writeCtorParameters(raw_ostream &OS) const = 0;
virtual void writeDeclarations(raw_ostream &OS) const = 0;
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
@@ -128,6 +135,9 @@ namespace {
virtual void writeDump(raw_ostream &OS) const = 0;
virtual void writeDumpChildren(raw_ostream &OS) const {}
virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; }
+
+ virtual bool isEnumArg() const { return false; }
+ virtual bool isVariadicEnumArg() const { return false; }
};
class SimpleArgument : public Argument {
@@ -154,6 +164,9 @@ namespace {
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "()";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << type << " " << getUpperName();
}
@@ -173,10 +186,11 @@ namespace {
}
void writeValue(raw_ostream &OS) const {
if (type == "FunctionDecl *") {
- OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \"";
+ OS << "\" << get" << getUpperName()
+ << "()->getNameInfo().getAsString() << \"";
} else if (type == "IdentifierInfo *") {
OS << "\" << get" << getUpperName() << "()->getName() << \"";
- } else if (type == "QualType") {
+ } else if (type == "TypeSourceInfo *") {
OS << "\" << get" << getUpperName() << "().getAsString() << \"";
} else if (type == "SourceLocation") {
OS << "\" << get" << getUpperName() << "().getRawEncoding() << \"";
@@ -191,7 +205,7 @@ namespace {
} else if (type == "IdentifierInfo *") {
OS << " OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
- } else if (type == "QualType") {
+ } else if (type == "TypeSourceInfo *") {
OS << " OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
} else if (type == "SourceLocation") {
@@ -246,6 +260,9 @@ namespace {
<< getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
<< "Length])";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Length(0)," << getLowerName() << "(0)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "llvm::StringRef " << getUpperName();
}
@@ -347,6 +364,9 @@ namespace {
void writeCtorInitializers(raw_ostream &OS) const {
OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << "is" << getLowerName() << "Expr(false)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
}
@@ -440,6 +460,9 @@ namespace {
<< getLowerName() << "(new (Ctx, 16) " << getType() << "["
<< getLowerName() << "Size])";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Size(0), " << getLowerName() << "(0)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << getType() << " *" << getUpperName() << ", unsigned "
<< getUpperName() << "Size";
@@ -454,7 +477,7 @@ namespace {
<< ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
<< "Size);\n";
- OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
+ OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
std::string read = ReadPCHRecord(type);
OS << " " << getLowerName() << ".push_back(" << read << ");\n";
@@ -506,6 +529,8 @@ namespace {
assert(!uniques.empty());
}
+ bool isEnumArg() const { return true; }
+
void writeAccessors(raw_ostream &OS) const {
OS << " " << type << " get" << getUpperName() << "() const {\n";
OS << " return " << getLowerName() << ";\n";
@@ -520,6 +545,9 @@ namespace {
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "(" << type << "(0))";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << type << " " << getUpperName();
}
@@ -562,6 +590,109 @@ namespace {
}
OS << " }\n";
}
+
+ void writeConversion(raw_ostream &OS) const {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
+ OS << type << " &Out) {\n";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ OS << type << "> >(Val)\n";
+ for (size_t I = 0; I < enums.size(); ++I) {
+ OS << " .Case(\"" << values[I] << "\", ";
+ OS << getAttrName() << "Attr::" << enums[I] << ")\n";
+ }
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << " }\n";
+ }
+ };
+
+ class VariadicEnumArgument: public VariadicArgument {
+ std::string type, QualifiedTypeName;
+ std::vector<StringRef> values, enums, uniques;
+ public:
+ VariadicEnumArgument(Record &Arg, StringRef Attr)
+ : VariadicArgument(Arg, Attr, Arg.getValueAsString("Type")),
+ type(Arg.getValueAsString("Type")),
+ values(getValueAsListOfStrings(Arg, "Values")),
+ enums(getValueAsListOfStrings(Arg, "Enums")),
+ uniques(enums)
+ {
+ // Calculate the various enum values
+ std::sort(uniques.begin(), uniques.end());
+ uniques.erase(std::unique(uniques.begin(), uniques.end()), uniques.end());
+
+ QualifiedTypeName = getAttrName().str() + "Attr::" + type;
+
+ // FIXME: Emit a proper error
+ assert(!uniques.empty());
+ }
+
+ bool isVariadicEnumArg() const { return true; }
+
+ void writeDeclarations(raw_ostream &OS) const {
+ std::vector<StringRef>::const_iterator i = uniques.begin(),
+ e = uniques.end();
+ // The last one needs to not have a comma.
+ --e;
+
+ OS << "public:\n";
+ OS << " enum " << type << " {\n";
+ for (; i != e; ++i)
+ OS << " " << *i << ",\n";
+ OS << " " << *e << "\n";
+ OS << " };\n";
+ OS << "private:\n";
+
+ VariadicArgument::writeDeclarations(OS);
+ }
+ void writeDump(raw_ostream &OS) const {
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
+ << getLowerName() << "_end(); I != E; ++I) {\n";
+ OS << " switch(*I) {\n";
+ for (std::vector<StringRef>::const_iterator UI = uniques.begin(),
+ UE = uniques.end(); UI != UE; ++UI) {
+ OS << " case " << getAttrName() << "Attr::" << *UI << ":\n";
+ OS << " OS << \" " << *UI << "\";\n";
+ OS << " break;\n";
+ }
+ OS << " }\n";
+ OS << " }\n";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName()
+ << ";\n";
+ OS << " " << getLowerName() << ".reserve(" << getLowerName()
+ << "Size);\n";
+ OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
+ OS << " " << getLowerName() << ".push_back(" << "static_cast<"
+ << QualifiedTypeName << ">(Record[Idx++]));\n";
+ }
+ void writePCHWrite(raw_ostream &OS) const{
+ OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->"
+ << getLowerName() << "_end(); i != e; ++i)\n";
+ OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)");
+ }
+ void writeConversion(raw_ostream &OS) const {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
+ OS << type << " &Out) {\n";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ OS << type << "> >(Val)\n";
+ for (size_t I = 0; I < enums.size(); ++I) {
+ OS << " .Case(\"" << values[I] << "\", ";
+ OS << getAttrName() << "Attr::" << enums[I] << ")\n";
+ }
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << " }\n";
+ }
};
class VersionArgument : public Argument {
@@ -590,6 +721,9 @@ namespace {
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "()";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "VersionTuple " << getUpperName();
}
@@ -695,6 +829,29 @@ namespace {
<< "SA->" << getLowerName() << "_end()";
}
};
+
+ class TypeArgument : public SimpleArgument {
+ public:
+ TypeArgument(Record &Arg, StringRef Attr)
+ : SimpleArgument(Arg, Attr, "TypeSourceInfo *")
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " QualType get" << getUpperName() << "() const {\n";
+ OS << " return " << getLowerName() << "->getType();\n";
+ OS << " }";
+ OS << " " << getType() << " get" << getUpperName() << "Loc() const {\n";
+ OS << " return " << getLowerName() << ";\n";
+ OS << " }";
+ }
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "A->get" << getUpperName() << "Loc()";
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << " " << WritePCHRecord(
+ getType(), "SA->get" + std::string(getUpperName()) + "Loc()");
+ }
+ };
}
static Argument *createArgument(Record &Arg, StringRef Attr,
@@ -716,14 +873,15 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
"bool");
else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int");
else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr);
- else if (ArgName == "TypeArgument")
- Ptr = new SimpleArgument(Arg, Attr, "QualType");
+ else if (ArgName == "TypeArgument") Ptr = new TypeArgument(Arg, Attr);
else if (ArgName == "UnsignedArgument")
Ptr = new SimpleArgument(Arg, Attr, "unsigned");
else if (ArgName == "SourceLocArgument")
Ptr = new SimpleArgument(Arg, Attr, "SourceLocation");
else if (ArgName == "VariadicUnsignedArgument")
Ptr = new VariadicArgument(Arg, Attr, "unsigned");
+ else if (ArgName == "VariadicEnumArgument")
+ Ptr = new VariadicEnumArgument(Arg, Attr);
else if (ArgName == "VariadicExprArgument")
Ptr = new VariadicExprArgument(Arg, Attr);
else if (ArgName == "VersionArgument")
@@ -738,6 +896,10 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
break;
}
}
+
+ if (Ptr && Arg.getValueAsBit("Optional"))
+ Ptr->setOptional(true);
+
return Ptr;
}
@@ -892,7 +1054,15 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!R.getValueAsBit("ASTNode"))
continue;
- const std::string &SuperName = R.getSuperClasses().back()->getName();
+ const std::vector<Record *> Supers = R.getSuperClasses();
+ assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
+ std::string SuperName;
+ for (std::vector<Record *>::const_reverse_iterator I = Supers.rbegin(),
+ E = Supers.rend(); I != E; ++I) {
+ const Record &R = **I;
+ if (R.getName() != "TargetSpecificAttr" && SuperName.empty())
+ SuperName = R.getName();
+ }
OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
@@ -918,10 +1088,13 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n public:\n";
OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+ bool HasOpt = false;
for (ai = Args.begin(); ai != ae; ++ai) {
OS << " , ";
(*ai)->writeCtorParameters(OS);
OS << "\n";
+ if ((*ai)->isOptional())
+ HasOpt = true;
}
OS << " , ";
@@ -944,6 +1117,41 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " }\n\n";
+ // If there are optional arguments, write out a constructor that elides the
+ // optional arguments as well.
+ if (HasOpt) {
+ OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ if (!(*ai)->isOptional()) {
+ OS << " , ";
+ (*ai)->writeCtorParameters(OS);
+ OS << "\n";
+ }
+ }
+
+ OS << " , ";
+ OS << "unsigned SI = 0\n";
+
+ OS << " )\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << " , ";
+ (*ai)->writeCtorDefaultInitializers(OS);
+ OS << "\n";
+ }
+
+ OS << " {\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ if (!(*ai)->isOptional()) {
+ (*ai)->writeCtorBody(OS);
+ OS << "\n";
+ }
+ }
+ OS << " }\n\n";
+ }
+
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
OS << " virtual void printPretty(raw_ostream &OS,\n"
<< " const PrintingPolicy &Policy) const;\n";
@@ -953,6 +1161,14 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
for (ai = Args.begin(); ai != ae; ++ai) {
(*ai)->writeAccessors(OS);
OS << "\n\n";
+
+ if ((*ai)->isEnumArg()) {
+ EnumArgument *EA = (EnumArgument *)*ai;
+ EA->writeConversion(OS);
+ } else if ((*ai)->isVariadicEnumArg()) {
+ VariadicEnumArgument *VEA = (VariadicEnumArgument *)*ai;
+ VEA->writeConversion(OS);
+ }
}
OS << R.getValueAsString("AdditionalMembers");
@@ -971,44 +1187,69 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "#endif\n";
}
-// Emits the all-arguments-are-expressions property for attributes.
-void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("llvm::StringSwitch code to match attributes with "
- "expression arguments", OS);
+static bool isIdentifierArgument(Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(Arg->getSuperClasses().back()->getName())
+ .Case("IdentifierArgument", true)
+ .Case("EnumArgument", true)
+ .Default(false);
+}
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+/// \brief Emits the first-argument-is-type property for attributes.
+void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("llvm::StringSwitch code to match attributes with a "
+ "type argument", OS);
- for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record *>::iterator I = Attrs.begin(), E = Attrs.end();
I != E; ++I) {
Record &Attr = **I;
- // Determine whether the first argument is something that is always
- // an expression.
+ // Determine whether the first argument is a type.
std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args");
- if (Args.empty() || Args[0]->getSuperClasses().empty())
+ if (Args.empty())
continue;
- // Check whether this is one of the argument kinds that implies an
- // expression.
- // FIXME: Aligned is weird.
- if (!llvm::StringSwitch<bool>(Args[0]->getSuperClasses().back()->getName())
- .Case("AlignedArgument", true)
- .Case("BoolArgument", true)
- .Case("DefaultIntArgument", true)
- .Case("IntArgument", true)
- .Case("ExprArgument", true)
- .Case("UnsignedArgument", true)
- .Case("VariadicUnsignedArgument", true)
- .Case("VariadicExprArgument", true)
- .Default(false))
+ if (Args[0]->getSuperClasses().back()->getName() != "TypeArgument")
continue;
+ // All these spellings take a single type argument.
std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+ std::set<std::string> Emitted;
+ for (std::vector<Record*>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ if (Emitted.insert((*I)->getValueAsString("Name")).second)
+ OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
+ << "true" << ")\n";
+ }
+ }
+}
+
+// Emits the first-argument-is-identifier property for attributes.
+void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("llvm::StringSwitch code to match attributes with "
+ "an identifier argument", OS);
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &Attr = **I;
+
+ // Determine whether the first argument is an identifier.
+ std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args");
+ if (Args.empty() || !isIdentifierArgument(Args[0]))
+ continue;
+
+ // All these spellings take an identifier argument.
+ std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+ std::set<std::string> Emitted;
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
- OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
- << "true" << ")\n";
+ if (Emitted.insert((*I)->getValueAsString("Name")).second)
+ OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
+ << "true" << ")\n";
}
}
}
@@ -1094,13 +1335,13 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
" INHERITABLE_PARAM_ATTR(NAME)\n";
OS << "#endif\n\n";
- OS << "#ifndef MS_INHERITABLE_ATTR\n";
- OS << "#define MS_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
+ OS << "#ifndef MS_INHERITANCE_ATTR\n";
+ OS << "#define MS_INHERITANCE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
OS << "#endif\n\n";
- OS << "#ifndef LAST_MS_INHERITABLE_ATTR\n";
- OS << "#define LAST_MS_INHERITABLE_ATTR(NAME)"
- " MS_INHERITABLE_ATTR(NAME)\n";
+ OS << "#ifndef LAST_MS_INHERITANCE_ATTR\n";
+ OS << "#define LAST_MS_INHERITANCE_ATTR(NAME)"
+ " MS_INHERITANCE_ATTR(NAME)\n";
OS << "#endif\n\n";
Record *InhClass = Records.getClass("InheritableAttr");
@@ -1124,16 +1365,16 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
}
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
- EmitAttrList(OS, "MS_INHERITABLE_ATTR", MSInhAttrs);
+ EmitAttrList(OS, "MS_INHERITANCE_ATTR", MSInhAttrs);
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
EmitAttrList(OS, "ATTR", NonInhAttrs);
OS << "#undef LAST_ATTR\n";
OS << "#undef INHERITABLE_ATTR\n";
- OS << "#undef MS_INHERITABLE_ATTR\n";
+ OS << "#undef MS_INHERITANCE_ATTR\n";
OS << "#undef LAST_INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
- OS << "#undef LAST_MS_INHERITABLE_ATTR\n";
+ OS << "#undef LAST_MS_INHERITANCE_ATTR\n";
OS << "#undef ATTR\n";
}
@@ -1393,16 +1634,11 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
<< "} // end namespace clang\n";
}
-// Emits the list of parsed attributes.
-void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap;
- OS << "#ifndef PARSED_ATTR\n";
- OS << "#define PARSED_ATTR(NAME) NAME\n";
- OS << "#endif\n\n";
-
+static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) {
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
+ ParsedAttrMap R;
for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
I != E; ++I) {
Record &Attr = **I;
@@ -1419,16 +1655,69 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
std::string AttrName = (*I)->getValueAsString("Name");
StringRef Spelling = NormalizeAttrName(AttrName);
-
- OS << "PARSED_ATTR(" << Spelling << ")\n";
+ R.push_back(std::make_pair(Spelling.str(), &Attr));
}
} else {
StringRef AttrName = Attr.getName();
AttrName = NormalizeAttrName(AttrName);
- OS << "PARSED_ATTR(" << AttrName << ")\n";
+ R.push_back(std::make_pair(AttrName.str(), *I));
}
}
}
+ return R;
+}
+
+// Emits the list of parsed attributes.
+void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+
+ OS << "#ifndef PARSED_ATTR\n";
+ OS << "#define PARSED_ATTR(NAME) NAME\n";
+ OS << "#endif\n\n";
+
+ ParsedAttrMap Names = getParsedAttrList(Records);
+ for (ParsedAttrMap::iterator I = Names.begin(), E = Names.end(); I != E;
+ ++I) {
+ OS << "PARSED_ATTR(" << I->first << ")\n";
+ }
+}
+
+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.
+ std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
+ unsigned ArgCount = 0, OptCount = 0;
+ for (std::vector<Record *>::const_iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ const Record &Arg = **I;
+ Arg.getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
+ }
+ OS << ArgCount << ", " << OptCount;
+}
+
+/// Emits the parsed attribute helpers
+void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Parsed attribute helpers", OS);
+
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+
+ OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
+ for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E;
+ ++I) {
+ // We need to generate struct instances based off ParsedAttrInfo from
+ // AttributeList.cpp.
+ OS << " { ";
+ emitArgInfo(*I->second, OS);
+ OS << ", " << I->second->getValueAsBit("HasCustomParsing");
+ OS << " }";
+
+ if (I + 1 != E)
+ OS << ",";
+
+ OS << " // AT_" << I->first << "\n";
+ }
+ OS << "};\n\n";
}
// Emits the kind list of parsed attributes
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index cab1c2b9b269..857b22e2f0b8 100644
--- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -40,6 +40,7 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
<< Tag.getValueAsBit("IsReturnsCommand") << ", "
<< Tag.getValueAsBit("IsParamCommand") << ", "
<< Tag.getValueAsBit("IsTParamCommand") << ", "
+ << Tag.getValueAsBit("IsThrowsCommand") << ", "
<< Tag.getValueAsBit("IsDeprecatedCommand") << ", "
<< Tag.getValueAsBit("IsHeaderfileCommand") << ", "
<< Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index da15c934359f..db159d102cd8 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -24,6 +24,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringToOffsetTable.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
#include <cctype>
@@ -51,7 +52,7 @@ public:
Mapping[SubGroups[j]].push_back(DiagGroups[i]);
}
}
-
+
const std::vector<Record*> &getParents(const Record *Group) {
return Mapping[Group];
}
@@ -64,7 +65,7 @@ getCategoryFromDiagGroup(const Record *Group,
// If the DiagGroup has a category, return it.
std::string CatName = Group->getValueAsString("CategoryName");
if (!CatName.empty()) return CatName;
-
+
// The diag group may the subgroup of one or more other diagnostic groups,
// check these for a category as well.
const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
@@ -99,32 +100,32 @@ namespace {
public:
DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
DiagGroupParentMap ParentInfo(Records);
-
+
// The zero'th category is "".
CategoryStrings.push_back("");
CategoryIDs[""] = 0;
-
+
std::vector<Record*> Diags =
Records.getAllDerivedDefinitions("Diagnostic");
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
if (Category.empty()) continue; // Skip diags with no category.
-
+
unsigned &ID = CategoryIDs[Category];
if (ID != 0) continue; // Already seen.
-
+
ID = CategoryStrings.size();
CategoryStrings.push_back(Category);
}
}
-
+
unsigned getID(StringRef CategoryString) {
return CategoryIDs[CategoryString];
}
-
- typedef std::vector<std::string>::iterator iterator;
- iterator begin() { return CategoryStrings.begin(); }
- iterator end() { return CategoryStrings.end(); }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+ const_iterator begin() const { return CategoryStrings.begin(); }
+ const_iterator end() const { return CategoryStrings.end(); }
};
struct GroupInfo {
@@ -198,7 +199,7 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
}
-
+
// Assign unique ID numbers to the groups.
unsigned IDNo = 0;
for (std::map<std::string, GroupInfo>::iterator
@@ -505,7 +506,7 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record &R = *Diags[i];
-
+
// Check if this is an error that is accidentally in a warning
// group.
if (isError(R)) {
@@ -524,11 +525,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
OS << "DIAG(" << R.getName() << ", ";
OS << R.getValueAsDef("Class")->getName();
OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
-
+
// Description string.
OS << ", \"";
OS.write_escaped(R.getValueAsString("Text")) << '"';
-
+
// Warning associated with the diagnostic. This is stored as an index into
// the alphabetically sorted warning table.
if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
@@ -545,34 +546,21 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
OS << ", 0";
}
- // SFINAE bit
- if (R.getValueAsBit("SFINAE"))
+ // SFINAE response.
+ OS << ", " << R.getValueAsDef("SFINAE")->getName();
+
+ // Default warning has no Werror bit.
+ if (R.getValueAsBit("WarningNoWerror"))
OS << ", true";
else
OS << ", false";
- // Access control bit
- if (R.getValueAsBit("AccessControl"))
+ // Default warning show in system header bit.
+ if (R.getValueAsBit("WarningShowInSystemHeader"))
OS << ", true";
else
OS << ", false";
- // FIXME: This condition is just to avoid temporary revlock, it can be
- // removed.
- if (R.getValue("WarningNoWerror")) {
- // Default warning has no Werror bit.
- if (R.getValueAsBit("WarningNoWerror"))
- OS << ", true";
- else
- OS << ", false";
-
- // Default warning show in system header bit.
- if (R.getValueAsBit("WarningShowInSystemHeader"))
- OS << ", true";
- else
- OS << ", false";
- }
-
// Category number.
OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
OS << ")\n";
@@ -592,7 +580,7 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) {
enumName += isalnum(*I) ? *I : '_';
return enumName.str();
}
-
+
namespace clang {
void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
// Compute a mapping from a DiagGroup to all of its parents.
@@ -600,7 +588,7 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record*> Diags =
Records.getAllDerivedDefinitions("Diagnostic");
-
+
std::vector<Record*> DiagGroups
= Records.getAllDerivedDefinitions("DiagGroup");
@@ -619,14 +607,16 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
// that are mapped to.
OS << "\n#ifdef GET_DIAG_ARRAYS\n";
unsigned MaxLen = 0;
- for (std::map<std::string, GroupInfo>::iterator
+ OS << "static const int16_t DiagArrays[] = {\n"
+ << " /* Empty */ -1,\n";
+ for (std::map<std::string, GroupInfo>::const_iterator
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
MaxLen = std::max(MaxLen, (unsigned)I->first.size());
const bool IsPedantic = I->first == "pedantic";
- std::vector<const Record*> &V = I->second.DiagsInGroup;
+ const std::vector<const Record*> &V = I->second.DiagsInGroup;
if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
- OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
+ OS << " /* DiagArray" << I->second.IDNo << " */ ";
for (unsigned i = 0, e = V.size(); i != e; ++i)
OS << "diag::" << V[i]->getName() << ", ";
// Emit the diagnostics implicitly in "pedantic".
@@ -634,14 +624,22 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
}
- OS << "-1 };\n";
+ OS << "-1,\n";
}
-
+ }
+ OS << "};\n\n";
+
+ OS << "static const int16_t DiagSubGroups[] = {\n"
+ << " /* Empty */ -1,\n";
+ for (std::map<std::string, GroupInfo>::const_iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ const bool IsPedantic = I->first == "pedantic";
+
const std::vector<std::string> &SubGroups = I->second.SubGroups;
if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
- OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
+ OS << " /* DiagSubGroup" << I->second.IDNo << " */ ";
for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
- std::map<std::string, GroupInfo>::iterator RI =
+ std::map<std::string, GroupInfo>::const_iterator RI =
DiagsInGroup.find(SubGroups[i]);
assert(RI != DiagsInGroup.end() && "Referenced without existing?");
OS << RI->second.IDNo << ", ";
@@ -651,60 +649,86 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
const std::string &GroupName =
GroupsInPedantic[i]->getValueAsString("GroupName");
- std::map<std::string, GroupInfo>::iterator RI =
+ std::map<std::string, GroupInfo>::const_iterator RI =
DiagsInGroup.find(GroupName);
assert(RI != DiagsInGroup.end() && "Referenced without existing?");
OS << RI->second.IDNo << ", ";
}
}
- OS << "-1 };\n";
+ OS << "-1,\n";
}
}
+ OS << "};\n\n";
+
+ StringToOffsetTable GroupNames;
+ for (std::map<std::string, GroupInfo>::const_iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ // Store a pascal-style length byte at the beginning of the string.
+ std::string Name = char(I->first.size()) + I->first;
+ GroupNames.GetOrAddStringOffset(Name, false);
+ }
+
+ OS << "static const char DiagGroupNames[] = {\n";
+ GroupNames.EmitString(OS);
+ OS << "};\n\n";
+
OS << "#endif // GET_DIAG_ARRAYS\n\n";
-
+
// Emit the table now.
OS << "\n#ifdef GET_DIAG_TABLE\n";
- for (std::map<std::string, GroupInfo>::iterator
+ unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
+ for (std::map<std::string, GroupInfo>::const_iterator
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
// Group option string.
- OS << " { ";
- OS << I->first.size() << ", ";
- OS << "\"";
+ OS << " { /* ";
if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789!@#$%^*-+=:?")!=std::string::npos)
PrintFatalError("Invalid character in diagnostic group '" +
I->first + "'");
- OS.write_escaped(I->first) << "\","
- << std::string(MaxLen-I->first.size()+1, ' ');
+ OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' ');
+ // Store a pascal-style length byte at the beginning of the string.
+ std::string Name = char(I->first.size()) + I->first;
+ OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
// Special handling for 'pedantic'.
const bool IsPedantic = I->first == "pedantic";
// Diagnostics in the group.
- const bool hasDiags = !I->second.DiagsInGroup.empty() ||
+ const std::vector<const Record*> &V = I->second.DiagsInGroup;
+ const bool hasDiags = !V.empty() ||
(IsPedantic && !DiagsInPedantic.empty());
- if (!hasDiags)
- OS << "0, ";
- else
- OS << "DiagArray" << I->second.IDNo << ", ";
-
+ if (hasDiags) {
+ OS << "/* DiagArray" << I->second.IDNo << " */ "
+ << DiagArrayIndex << ", ";
+ if (IsPedantic)
+ DiagArrayIndex += DiagsInPedantic.size();
+ DiagArrayIndex += V.size() + 1;
+ } else {
+ OS << "/* Empty */ 0, ";
+ }
+
// Subgroups.
- const bool hasSubGroups = !I->second.SubGroups.empty() ||
+ const std::vector<std::string> &SubGroups = I->second.SubGroups;
+ const bool hasSubGroups = !SubGroups.empty() ||
(IsPedantic && !GroupsInPedantic.empty());
- if (!hasSubGroups)
- OS << 0;
- else
- OS << "DiagSubGroup" << I->second.IDNo;
+ if (hasSubGroups) {
+ OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex;
+ if (IsPedantic)
+ SubGroupIndex += GroupsInPedantic.size();
+ SubGroupIndex += SubGroups.size() + 1;
+ } else {
+ OS << "/* Empty */ 0";
+ }
OS << " },\n";
}
OS << "#endif // GET_DIAG_TABLE\n\n";
-
+
// Emit the category table next.
DiagCategoryIDMap CategoriesByID(Records);
OS << "\n#ifdef GET_CATEGORY_TABLE\n";
- for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
+ for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(),
E = CategoriesByID.end(); I != E; ++I)
OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
OS << "#endif // GET_CATEGORY_TABLE\n\n";
@@ -721,18 +745,18 @@ struct RecordIndexElement
RecordIndexElement() {}
explicit RecordIndexElement(Record const &R):
Name(R.getName()) {}
-
+
std::string Name;
};
struct RecordIndexElementSorter :
public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
-
+
bool operator()(RecordIndexElement const &Lhs,
RecordIndexElement const &Rhs) const {
return Lhs.Name < Rhs.Name;
}
-
+
};
} // end anonymous namespace.
@@ -741,19 +765,19 @@ namespace clang {
void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
const std::vector<Record*> &Diags =
Records.getAllDerivedDefinitions("Diagnostic");
-
+
std::vector<RecordIndexElement> Index;
Index.reserve(Diags.size());
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
- const Record &R = *(Diags[i]);
+ const Record &R = *(Diags[i]);
Index.push_back(RecordIndexElement(R));
}
-
+
std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
-
+
for (unsigned i = 0, e = Index.size(); i != e; ++i) {
const RecordIndexElement &R = Index[i];
-
+
OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
}
}
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 34b955e8e9d2..b0939c9d000c 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -40,31 +40,58 @@ enum OpKind {
OpUnavailable,
OpAdd,
OpAddl,
+ OpAddlHi,
OpAddw,
+ OpAddwHi,
OpSub,
OpSubl,
+ OpSublHi,
OpSubw,
+ OpSubwHi,
OpMul,
OpMla,
OpMlal,
+ OpMullHi,
+ OpMullHiN,
+ OpMlalHi,
+ OpMlalHiN,
OpMls,
OpMlsl,
+ OpMlslHi,
+ OpMlslHiN,
OpMulN,
OpMlaN,
OpMlsN,
+ OpFMlaN,
+ OpFMlsN,
OpMlalN,
OpMlslN,
OpMulLane,
+ OpMulXLane,
OpMullLane,
+ OpMullHiLane,
OpMlaLane,
OpMlsLane,
OpMlalLane,
+ OpMlalHiLane,
OpMlslLane,
+ OpMlslHiLane,
OpQDMullLane,
+ OpQDMullHiLane,
OpQDMlalLane,
+ OpQDMlalHiLane,
OpQDMlslLane,
+ OpQDMlslHiLane,
OpQDMulhLane,
OpQRDMulhLane,
+ OpFMSLane,
+ OpFMSLaneQ,
+ OpTrn1,
+ OpZip1,
+ OpUzp1,
+ OpTrn2,
+ OpZip2,
+ OpUzp2,
OpEq,
OpGe,
OpLe,
@@ -87,10 +114,49 @@ enum OpKind {
OpRev16,
OpRev32,
OpRev64,
+ OpXtnHi,
+ OpSqxtunHi,
+ OpQxtnHi,
+ OpFcvtnHi,
+ OpFcvtlHi,
+ OpFcvtxnHi,
OpReinterpret,
+ OpAddhnHi,
+ OpRAddhnHi,
+ OpSubhnHi,
+ OpRSubhnHi,
OpAbdl,
+ OpAbdlHi,
OpAba,
- OpAbal
+ OpAbal,
+ OpAbalHi,
+ OpQDMullHi,
+ OpQDMullHiN,
+ OpQDMlalHi,
+ OpQDMlalHiN,
+ OpQDMlslHi,
+ OpQDMlslHiN,
+ OpDiv,
+ OpLongHi,
+ OpNarrowHi,
+ OpMovlHi,
+ OpCopyLane,
+ OpCopyQLane,
+ OpCopyLaneQ,
+ OpScalarMulLane,
+ OpScalarMulLaneQ,
+ OpScalarMulXLane,
+ OpScalarMulXLaneQ,
+ OpScalarVMulXLane,
+ OpScalarVMulXLaneQ,
+ OpScalarQDMullLane,
+ OpScalarQDMullLaneQ,
+ OpScalarQDMulHiLane,
+ OpScalarQDMulHiLaneQ,
+ OpScalarQRDMulHiLane,
+ OpScalarQRDMulHiLaneQ,
+ OpScalarGetLane,
+ OpScalarSetLane
};
enum ClassKind {
@@ -126,8 +192,10 @@ public:
Int64,
Poly8,
Poly16,
+ Poly64,
Float16,
- Float32
+ Float32,
+ Float64
};
NeonTypeFlags(unsigned F) : Flags(F) {}
@@ -154,31 +222,58 @@ public:
OpMap["OP_UNAVAILABLE"] = OpUnavailable;
OpMap["OP_ADD"] = OpAdd;
OpMap["OP_ADDL"] = OpAddl;
+ OpMap["OP_ADDLHi"] = OpAddlHi;
OpMap["OP_ADDW"] = OpAddw;
+ OpMap["OP_ADDWHi"] = OpAddwHi;
OpMap["OP_SUB"] = OpSub;
OpMap["OP_SUBL"] = OpSubl;
+ OpMap["OP_SUBLHi"] = OpSublHi;
OpMap["OP_SUBW"] = OpSubw;
+ OpMap["OP_SUBWHi"] = OpSubwHi;
OpMap["OP_MUL"] = OpMul;
OpMap["OP_MLA"] = OpMla;
OpMap["OP_MLAL"] = OpMlal;
+ OpMap["OP_MULLHi"] = OpMullHi;
+ OpMap["OP_MULLHi_N"] = OpMullHiN;
+ OpMap["OP_MLALHi"] = OpMlalHi;
+ OpMap["OP_MLALHi_N"] = OpMlalHiN;
OpMap["OP_MLS"] = OpMls;
OpMap["OP_MLSL"] = OpMlsl;
+ OpMap["OP_MLSLHi"] = OpMlslHi;
+ OpMap["OP_MLSLHi_N"] = OpMlslHiN;
OpMap["OP_MUL_N"] = OpMulN;
OpMap["OP_MLA_N"] = OpMlaN;
OpMap["OP_MLS_N"] = OpMlsN;
+ OpMap["OP_FMLA_N"] = OpFMlaN;
+ OpMap["OP_FMLS_N"] = OpFMlsN;
OpMap["OP_MLAL_N"] = OpMlalN;
OpMap["OP_MLSL_N"] = OpMlslN;
OpMap["OP_MUL_LN"]= OpMulLane;
+ OpMap["OP_MULX_LN"]= OpMulXLane;
OpMap["OP_MULL_LN"] = OpMullLane;
+ OpMap["OP_MULLHi_LN"] = OpMullHiLane;
OpMap["OP_MLA_LN"]= OpMlaLane;
OpMap["OP_MLS_LN"]= OpMlsLane;
OpMap["OP_MLAL_LN"] = OpMlalLane;
+ OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
OpMap["OP_MLSL_LN"] = OpMlslLane;
+ OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
OpMap["OP_QDMULL_LN"] = OpQDMullLane;
+ OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
+ OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
+ OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
+ OpMap["OP_FMS_LN"] = OpFMSLane;
+ OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
+ OpMap["OP_TRN1"] = OpTrn1;
+ OpMap["OP_ZIP1"] = OpZip1;
+ OpMap["OP_UZP1"] = OpUzp1;
+ OpMap["OP_TRN2"] = OpTrn2;
+ OpMap["OP_ZIP2"] = OpZip2;
+ OpMap["OP_UZP2"] = OpUzp2;
OpMap["OP_EQ"] = OpEq;
OpMap["OP_GE"] = OpGe;
OpMap["OP_LE"] = OpLe;
@@ -201,10 +296,49 @@ public:
OpMap["OP_REV16"] = OpRev16;
OpMap["OP_REV32"] = OpRev32;
OpMap["OP_REV64"] = OpRev64;
+ OpMap["OP_XTN"] = OpXtnHi;
+ OpMap["OP_SQXTUN"] = OpSqxtunHi;
+ OpMap["OP_QXTN"] = OpQxtnHi;
+ OpMap["OP_VCVT_NA_HI"] = OpFcvtnHi;
+ OpMap["OP_VCVT_EX_HI"] = OpFcvtlHi;
+ OpMap["OP_VCVTX_HI"] = OpFcvtxnHi;
OpMap["OP_REINT"] = OpReinterpret;
+ OpMap["OP_ADDHNHi"] = OpAddhnHi;
+ OpMap["OP_RADDHNHi"] = OpRAddhnHi;
+ OpMap["OP_SUBHNHi"] = OpSubhnHi;
+ OpMap["OP_RSUBHNHi"] = OpRSubhnHi;
OpMap["OP_ABDL"] = OpAbdl;
+ OpMap["OP_ABDLHi"] = OpAbdlHi;
OpMap["OP_ABA"] = OpAba;
OpMap["OP_ABAL"] = OpAbal;
+ OpMap["OP_ABALHi"] = OpAbalHi;
+ OpMap["OP_QDMULLHi"] = OpQDMullHi;
+ OpMap["OP_QDMULLHi_N"] = OpQDMullHiN;
+ OpMap["OP_QDMLALHi"] = OpQDMlalHi;
+ OpMap["OP_QDMLALHi_N"] = OpQDMlalHiN;
+ OpMap["OP_QDMLSLHi"] = OpQDMlslHi;
+ OpMap["OP_QDMLSLHi_N"] = OpQDMlslHiN;
+ OpMap["OP_DIV"] = OpDiv;
+ OpMap["OP_LONG_HI"] = OpLongHi;
+ OpMap["OP_NARROW_HI"] = OpNarrowHi;
+ OpMap["OP_MOVL_HI"] = OpMovlHi;
+ OpMap["OP_COPY_LN"] = OpCopyLane;
+ OpMap["OP_COPYQ_LN"] = OpCopyQLane;
+ OpMap["OP_COPY_LNQ"] = OpCopyLaneQ;
+ OpMap["OP_SCALAR_MUL_LN"]= OpScalarMulLane;
+ OpMap["OP_SCALAR_MUL_LNQ"]= OpScalarMulLaneQ;
+ OpMap["OP_SCALAR_MULX_LN"]= OpScalarMulXLane;
+ OpMap["OP_SCALAR_MULX_LNQ"]= OpScalarMulXLaneQ;
+ OpMap["OP_SCALAR_VMULX_LN"]= OpScalarVMulXLane;
+ OpMap["OP_SCALAR_VMULX_LNQ"]= OpScalarVMulXLaneQ;
+ OpMap["OP_SCALAR_QDMULL_LN"] = OpScalarQDMullLane;
+ OpMap["OP_SCALAR_QDMULL_LNQ"] = OpScalarQDMullLaneQ;
+ OpMap["OP_SCALAR_QDMULH_LN"] = OpScalarQDMulHiLane;
+ OpMap["OP_SCALAR_QDMULH_LNQ"] = OpScalarQDMulHiLaneQ;
+ OpMap["OP_SCALAR_QRDMULH_LN"] = OpScalarQRDMulHiLane;
+ OpMap["OP_SCALAR_QRDMULH_LNQ"] = OpScalarQRDMulHiLaneQ;
+ OpMap["OP_SCALAR_GET_LN"] = OpScalarGetLane;
+ OpMap["OP_SCALAR_SET_LN"] = OpScalarSetLane;
Record *SI = R.getClass("SInst");
Record *II = R.getClass("IInst");
@@ -235,7 +369,18 @@ public:
void runTests(raw_ostream &o);
private:
- void emitIntrinsic(raw_ostream &OS, Record *R);
+ void emitIntrinsic(raw_ostream &OS, Record *R,
+ StringMap<ClassKind> &EmittedMap);
+ void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64GenBuiltinDef);
+ void genOverloadTypeCheckCode(raw_ostream &OS,
+ StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64TypeCheck);
+ void genIntrinsicRangeCheckCode(raw_ostream &OS,
+ StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64RangeCheck);
+ void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
+ bool isA64TestGen);
};
} // end anonymous namespace
@@ -249,7 +394,8 @@ static void ParseTypes(Record *r, std::string &s,
int len = 0;
for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
- if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
+ if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
+ || data[len] == 'H' || data[len] == 'S')
continue;
switch (data[len]) {
@@ -259,6 +405,7 @@ static void ParseTypes(Record *r, std::string &s,
case 'l':
case 'h':
case 'f':
+ case 'd':
break;
default:
PrintFatalError(r->getLoc(),
@@ -282,6 +429,8 @@ static char Widen(const char t) {
return 'l';
case 'h':
return 'f';
+ case 'f':
+ return 'd';
default:
PrintFatalError("unhandled type in widen!");
}
@@ -299,18 +448,46 @@ static char Narrow(const char t) {
return 'i';
case 'f':
return 'h';
+ case 'd':
+ return 'f';
default:
PrintFatalError("unhandled type in narrow!");
}
}
+static std::string GetNarrowTypestr(StringRef ty)
+{
+ std::string s;
+ for (size_t i = 0, end = ty.size(); i < end; i++) {
+ switch (ty[i]) {
+ case 's':
+ s += 'c';
+ break;
+ case 'i':
+ s += 's';
+ break;
+ case 'l':
+ s += 'i';
+ break;
+ default:
+ s += ty[i];
+ break;
+ }
+ }
+
+ return s;
+}
+
/// For a particular StringRef, return the base type code, and whether it has
/// the quad-vector, polynomial, or unsigned modifiers set.
static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
unsigned off = 0;
-
+ // ignore scalar.
+ if (ty[off] == 'S') {
+ ++off;
+ }
// remember quad.
- if (ty[off] == 'Q') {
+ if (ty[off] == 'Q' || ty[off] == 'H') {
quad = true;
++off;
}
@@ -342,27 +519,52 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
usgn = true;
}
break;
+ case 'b':
+ scal = true;
case 'u':
usgn = true;
poly = false;
if (type == 'f')
type = 'i';
+ if (type == 'd')
+ type = 'l';
break;
+ case '$':
+ scal = true;
case 'x':
usgn = false;
poly = false;
if (type == 'f')
type = 'i';
+ if (type == 'd')
+ type = 'l';
break;
+ case 'o':
+ scal = true;
+ type = 'd';
+ usgn = false;
+ break;
+ case 'y':
+ scal = true;
case 'f':
if (type == 'h')
quad = true;
type = 'f';
usgn = false;
break;
+ case 'F':
+ type = 'd';
+ usgn = false;
+ break;
case 'g':
quad = false;
break;
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'j':
+ quad = true;
+ break;
case 'w':
type = Widen(type);
quad = true;
@@ -379,6 +581,14 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
scal = true;
usgn = true;
break;
+ case 'z':
+ type = Narrow(type);
+ scal = true;
+ break;
+ case 'r':
+ type = Widen(type);
+ scal = true;
+ break;
case 's':
case 'a':
scal = true;
@@ -397,16 +607,28 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
if (type == 'h')
quad = false;
break;
+ case 'q':
+ type = Narrow(type);
+ quad = true;
+ break;
case 'e':
type = Narrow(type);
usgn = true;
break;
+ case 'm':
+ type = Narrow(type);
+ quad = false;
+ break;
default:
break;
}
return type;
}
+static bool IsMultiVecProto(const char p) {
+ return ((p >= '2' && p <= '4') || (p >= 'B' && p <= 'D'));
+}
+
/// TypeString - for a modifier and type, generate the name of the typedef for
/// that type. QUc -> uint8x8_t.
static std::string TypeString(const char mod, StringRef typestr) {
@@ -453,7 +675,7 @@ static std::string TypeString(const char mod, StringRef typestr) {
s += quad ? "x4" : "x2";
break;
case 'l':
- s += "int64";
+ s += (poly && !usgn)? "poly64" : "int64";
if (scal)
break;
s += quad ? "x2" : "x1";
@@ -470,15 +692,22 @@ static std::string TypeString(const char mod, StringRef typestr) {
break;
s += quad ? "x4" : "x2";
break;
+ case 'd':
+ s += "float64";
+ if (scal)
+ break;
+ s += quad ? "x2" : "x1";
+ break;
+
default:
PrintFatalError("unhandled type!");
}
- if (mod == '2')
+ if (mod == '2' || mod == 'B')
s += "x2";
- if (mod == '3')
+ if (mod == '3' || mod == 'C')
s += "x3";
- if (mod == '4')
+ if (mod == '4' || mod == 'D')
s += "x4";
// Append _t, finishing the type string typedef type.
@@ -527,7 +756,8 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
type = 's';
usgn = true;
}
- usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
+ usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
+ scal && type != 'f' && type != 'd');
if (scal) {
SmallString<128> s;
@@ -554,10 +784,12 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
// returning structs of 2, 3, or 4 vectors which are returned in a sret-like
// fashion, storing them to a pointer arg.
if (ret) {
- if (mod >= '2' && mod <= '4')
+ if (IsMultiVecProto(mod))
return "vv*"; // void result with void* first argument
if (mod == 'f' || (ck != ClassB && type == 'f'))
return quad ? "V4f" : "V2f";
+ if (mod == 'F' || (ck != ClassB && type == 'd'))
+ return quad ? "V2d" : "V1d";
if (ck != ClassB && type == 's')
return quad ? "V8s" : "V4s";
if (ck != ClassB && type == 'i')
@@ -569,15 +801,17 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
}
// Non-return array types are passed as individual vectors.
- if (mod == '2')
+ if (mod == '2' || mod == 'B')
return quad ? "V16ScV16Sc" : "V8ScV8Sc";
- if (mod == '3')
+ if (mod == '3' || mod == 'C')
return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
- if (mod == '4')
+ if (mod == '4' || mod == 'D')
return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
if (mod == 'f' || (ck != ClassB && type == 'f'))
return quad ? "V4f" : "V2f";
+ if (mod == 'F' || (ck != ClassB && type == 'd'))
+ return quad ? "V2d" : "V1d";
if (ck != ClassB && type == 's')
return quad ? "V8s" : "V4s";
if (ck != ClassB && type == 'i')
@@ -625,7 +859,7 @@ static void InstructionTypeCode(const StringRef &typeStr,
break;
case 'l':
switch (ck) {
- case ClassS: typeCode = usgn ? "u64" : "s64"; break;
+ case ClassS: typeCode = poly ? "p64" : usgn ? "u64" : "s64"; break;
case ClassI: typeCode = "i64"; break;
case ClassW: typeCode = "64"; break;
default: break;
@@ -647,17 +881,60 @@ static void InstructionTypeCode(const StringRef &typeStr,
default: break;
}
break;
+ case 'd':
+ switch (ck) {
+ case ClassS:
+ case ClassI:
+ typeCode += "f64";
+ break;
+ case ClassW:
+ PrintFatalError("unhandled type!");
+ default:
+ break;
+ }
+ break;
default:
PrintFatalError("unhandled type!");
}
}
+static char Insert_BHSD_Suffix(StringRef typestr){
+ unsigned off = 0;
+ if(typestr[off++] == 'S'){
+ while(typestr[off] == 'Q' || typestr[off] == 'H'||
+ typestr[off] == 'P' || typestr[off] == 'U')
+ ++off;
+ switch (typestr[off]){
+ default : break;
+ case 'c' : return 'b';
+ case 's' : return 'h';
+ case 'i' :
+ case 'f' : return 's';
+ case 'l' :
+ case 'd' : return 'd';
+ }
+ }
+ return 0;
+}
+
+static bool endsWith_xN(std::string const &name) {
+ if (name.length() > 3) {
+ if (name.compare(name.length() - 3, 3, "_x2") == 0 ||
+ name.compare(name.length() - 3, 3, "_x3") == 0 ||
+ name.compare(name.length() - 3, 3, "_x4") == 0)
+ return true;
+ }
+ return false;
+}
+
/// MangleName - Append a type or width suffix to a base neon function name,
-/// and insert a 'q' in the appropriate location if the operation works on
-/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
+/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
+/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
+/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
static std::string MangleName(const std::string &name, StringRef typestr,
ClassKind ck) {
- if (name == "vcvt_f32_f16")
+ if (name == "vcvt_f32_f16" || name == "vcvt_f32_f64" ||
+ name == "vcvt_f64_f32")
return name;
bool quad = false;
@@ -668,7 +945,11 @@ static std::string MangleName(const std::string &name, StringRef typestr,
std::string s = name;
if (typeCode.size() > 0) {
- s += "_" + typeCode;
+ // If the name is end with _xN (N = 2,3,4), insert the typeCode before _xN.
+ if (endsWith_xN(s))
+ s.insert(s.length() - 3, "_" + typeCode);
+ else
+ s += "_" + typeCode;
}
if (ck == ClassB)
@@ -676,9 +957,14 @@ static std::string MangleName(const std::string &name, StringRef typestr,
// Insert a 'q' before the first '_' character so that it ends up before
// _lane or _n on vector-scalar operations.
- if (quad) {
+ if (typestr.find("Q") != StringRef::npos) {
+ size_t pos = s.find('_');
+ s = s.insert(pos, "q");
+ }
+ char ins = Insert_BHSD_Suffix(typestr);
+ if(ins){
size_t pos = s.find('_');
- s = s.insert(pos, "q");
+ s = s.insert(pos, &ins, 1);
}
return s;
@@ -770,9 +1056,7 @@ GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
// a dup/lane instruction.
if (IsLDSTOne) {
if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
- RegisterSuffix += ", :" + OutTypeCode;
- } else if (OutTypeCode == "64") {
- RegisterSuffix += ", :64";
+ RegisterSuffix += ":" + OutTypeCode;
}
}
@@ -828,6 +1112,7 @@ static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
switch (Proto[i]) {
case 'u':
case 'f':
+ case 'F':
case 'd':
case 's':
case 'x':
@@ -840,6 +1125,7 @@ static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
NormedProto += 'q';
break;
case 'g':
+ case 'j':
case 'h':
case 'e':
NormedProto += 'd';
@@ -1158,7 +1444,8 @@ static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
}
// Generate the string "(argtype a, argtype b, ...)"
-static std::string GenArgs(const std::string &proto, StringRef typestr) {
+static std::string GenArgs(const std::string &proto, StringRef typestr,
+ const std::string &name) {
bool define = UseMacro(proto);
char arg = 'a';
@@ -1176,6 +1463,9 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) {
s += TypeString(proto[i], typestr) + " __";
}
s.push_back(arg);
+ //To avoid argument being multiple defined, add extra number for renaming.
+ if (name == "vcopy_lane" || name == "vcopy_laneq")
+ s.push_back('1');
if ((i + 1) < e)
s += ", ";
}
@@ -1186,7 +1476,8 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) {
// Macro arguments are not type-checked like inline function arguments, so
// assign them to local temporaries to get the right type checking.
-static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
+static std::string GenMacroLocals(const std::string &proto, StringRef typestr,
+ const std::string &name ) {
char arg = 'a';
std::string s;
bool generatedLocal = false;
@@ -1197,11 +1488,18 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
if (MacroArgUsedDirectly(proto, i))
continue;
generatedLocal = true;
+ bool extranumber = false;
+ if (name == "vcopy_lane" || name == "vcopy_laneq")
+ extranumber = true;
s += TypeString(proto[i], typestr) + " __";
s.push_back(arg);
+ if(extranumber)
+ s.push_back('1');
s += " = (";
s.push_back(arg);
+ if(extranumber)
+ s.push_back('1');
s += "); ";
}
@@ -1211,13 +1509,60 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
}
// Use the vmovl builtin to sign-extend or zero-extend a vector.
-static std::string Extend(StringRef typestr, const std::string &a) {
+static std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
+ std::string s, high;
+ high = h ? "_high" : "";
+ s = MangleName("vmovl" + high, typestr, ClassS);
+ s += "(" + a + ")";
+ return s;
+}
+
+// Get the high 64-bit part of a vector
+static std::string GetHigh(const std::string &a, StringRef typestr) {
std::string s;
- s = MangleName("vmovl", typestr, ClassS);
+ s = MangleName("vget_high", typestr, ClassS);
s += "(" + a + ")";
return s;
}
+// Gen operation with two operands and get high 64-bit for both of two operands.
+static std::string Gen2OpWith2High(StringRef typestr,
+ const std::string &op,
+ const std::string &a,
+ const std::string &b) {
+ std::string s;
+ std::string Op1 = GetHigh(a, typestr);
+ std::string Op2 = GetHigh(b, typestr);
+ s = MangleName(op, typestr, ClassS);
+ s += "(" + Op1 + ", " + Op2 + ");";
+ return s;
+}
+
+// Gen operation with three operands and get high 64-bit of the latter
+// two operands.
+static std::string Gen3OpWith2High(StringRef typestr,
+ const std::string &op,
+ const std::string &a,
+ const std::string &b,
+ const std::string &c) {
+ std::string s;
+ std::string Op1 = GetHigh(b, typestr);
+ std::string Op2 = GetHigh(c, typestr);
+ s = MangleName(op, typestr, ClassS);
+ s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
+ return s;
+}
+
+// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
+static std::string GenCombine(std::string typestr,
+ const std::string &a,
+ const std::string &b) {
+ std::string s;
+ s = MangleName("vcombine", typestr, ClassS);
+ s += "(" + a + ", " + b + ")";
+ return s;
+}
+
static std::string Duplicate(unsigned nElts, StringRef typestr,
const std::string &a) {
std::string s;
@@ -1242,6 +1587,15 @@ static std::string SplatLane(unsigned nElts, const std::string &vec,
return s;
}
+static std::string RemoveHigh(const std::string &name) {
+ std::string s = name;
+ std::size_t found = s.find("_high_");
+ if (found == std::string::npos)
+ PrintFatalError("name should contain \"_high_\" for high intrinsics");
+ s.replace(found, 5, "");
+ return s;
+}
+
static unsigned GetNumElements(StringRef typestr, bool &quad) {
quad = false;
bool dummy = false;
@@ -1254,6 +1608,9 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) {
case 'l': nElts = 1; break;
case 'h': nElts = 4; break;
case 'f': nElts = 2; break;
+ case 'd':
+ nElts = 1;
+ break;
default:
PrintFatalError("unhandled type!");
}
@@ -1262,8 +1619,8 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) {
}
// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
-static std::string GenOpString(OpKind op, const std::string &proto,
- StringRef typestr) {
+static std::string GenOpString(const std::string &name, OpKind op,
+ const std::string &proto, StringRef typestr) {
bool quad;
unsigned nElts = GetNumElements(typestr, quad);
bool define = UseMacro(proto);
@@ -1281,31 +1638,59 @@ static std::string GenOpString(OpKind op, const std::string &proto,
case OpAddl:
s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
break;
+ case OpAddlHi:
+ s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
+ break;
case OpAddw:
s += "__a + " + Extend(typestr, "__b") + ";";
break;
+ case OpAddwHi:
+ s += "__a + " + Extend(typestr, "__b", 1) + ";";
+ break;
case OpSub:
s += "__a - __b;";
break;
case OpSubl:
s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
break;
+ case OpSublHi:
+ s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
+ break;
case OpSubw:
s += "__a - " + Extend(typestr, "__b") + ";";
break;
+ case OpSubwHi:
+ s += "__a - " + Extend(typestr, "__b", 1) + ";";
+ break;
case OpMulN:
s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
break;
case OpMulLane:
s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
break;
+ case OpMulXLane:
+ s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
case OpMul:
s += "__a * __b;";
break;
+ case OpFMlaN:
+ s += MangleName("vfma", typestr, ClassS);
+ s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
+ break;
+ case OpFMlsN:
+ s += MangleName("vfms", typestr, ClassS);
+ s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
+ break;
case OpMullLane:
s += MangleName("vmull", typestr, ClassS) + "(__a, " +
SplatLane(nElts, "__b", "__c") + ");";
break;
+ case OpMullHiLane:
+ s += MangleName("vmull", typestr, ClassS) + "(" +
+ GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
+ break;
case OpMlaN:
s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
break;
@@ -1323,15 +1708,45 @@ static std::string GenOpString(OpKind op, const std::string &proto,
s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
SplatLane(nElts, "__c", "__d") + ");";
break;
+ case OpMlalHiLane:
+ s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
+ GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpMlal:
s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
break;
+ case OpMullHi:
+ s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
+ break;
+ case OpMullHiN:
+ s += MangleName("vmull_n", typestr, ClassS);
+ s += "(" + GetHigh("__a", typestr) + ", __b);";
+ return s;
+ case OpMlalHi:
+ s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
+ break;
+ case OpMlalHiN:
+ s += MangleName("vmlal_n", typestr, ClassS);
+ s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
+ return s;
case OpMlsN:
s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
break;
case OpMlsLane:
s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
break;
+ case OpFMSLane:
+ s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
+ s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
+ s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
+ s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
+ break;
+ case OpFMSLaneQ:
+ s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
+ s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
+ s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
+ s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
+ break;
case OpMls:
s += "__a - (__b * __c);";
break;
@@ -1343,21 +1758,44 @@ static std::string GenOpString(OpKind op, const std::string &proto,
s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
SplatLane(nElts, "__c", "__d") + ");";
break;
+ case OpMlslHiLane:
+ s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
+ GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpMlsl:
s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
break;
+ case OpMlslHi:
+ s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
+ break;
+ case OpMlslHiN:
+ s += MangleName("vmlsl_n", typestr, ClassS);
+ s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
+ break;
case OpQDMullLane:
s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
SplatLane(nElts, "__b", "__c") + ");";
break;
+ case OpQDMullHiLane:
+ s += MangleName("vqdmull", typestr, ClassS) + "(" +
+ GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
+ break;
case OpQDMlalLane:
s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
SplatLane(nElts, "__c", "__d") + ");";
break;
+ case OpQDMlalHiLane:
+ s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
+ GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpQDMlslLane:
s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
SplatLane(nElts, "__c", "__d") + ");";
break;
+ case OpQDMlslHiLane:
+ s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
+ GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpQDMulhLane:
s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
SplatLane(nElts, "__b", "__c") + ");";
@@ -1410,12 +1848,17 @@ static std::string GenOpString(OpKind op, const std::string &proto,
s += ", (int64x1_t)__b, 0, 1);";
break;
case OpHi:
- s += "(" + ts +
- ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);";
+ // nElts is for the result vector, so the source is twice that number.
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = nElts; i < nElts * 2; ++i)
+ s += ", " + utostr(i);
+ s+= ");";
break;
case OpLo:
- s += "(" + ts +
- ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);";
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = 0; i < nElts; ++i)
+ s += ", " + utostr(i);
+ s+= ");";
break;
case OpDup:
s += Duplicate(nElts, typestr, "__a") + ";";
@@ -1455,6 +1898,94 @@ static std::string GenOpString(OpKind op, const std::string &proto,
s += ");";
break;
}
+ case OpXtnHi: {
+ s = TypeString(proto[1], typestr) + " __a1 = " +
+ MangleName("vmovn", typestr, ClassS) + "(__b);\n " +
+ "return __builtin_shufflevector(__a, __a1";
+ for (unsigned i = 0; i < nElts * 4; ++i)
+ s += ", " + utostr(i);
+ s += ");";
+ break;
+ }
+ case OpSqxtunHi: {
+ s = TypeString(proto[1], typestr) + " __a1 = " +
+ MangleName("vqmovun", typestr, ClassS) + "(__b);\n " +
+ "return __builtin_shufflevector(__a, __a1";
+ for (unsigned i = 0; i < nElts * 4; ++i)
+ s += ", " + utostr(i);
+ s += ");";
+ break;
+ }
+ case OpQxtnHi: {
+ s = TypeString(proto[1], typestr) + " __a1 = " +
+ MangleName("vqmovn", typestr, ClassS) + "(__b);\n " +
+ "return __builtin_shufflevector(__a, __a1";
+ for (unsigned i = 0; i < nElts * 4; ++i)
+ s += ", " + utostr(i);
+ s += ");";
+ break;
+ }
+ case OpFcvtnHi: {
+ std::string FName = (nElts == 1) ? "vcvt_f32" : "vcvt_f16";
+ s = TypeString(proto[1], typestr) + " __a1 = " +
+ MangleName(FName, typestr, ClassS) + "(__b);\n " +
+ "return __builtin_shufflevector(__a, __a1";
+ for (unsigned i = 0; i < nElts * 4; ++i)
+ s += ", " + utostr(i);
+ s += ");";
+ break;
+ }
+ case OpFcvtlHi: {
+ std::string FName = (nElts == 2) ? "vcvt_f64" : "vcvt_f32";
+ s = TypeString('d', typestr) + " __a1 = " + GetHigh("__a", typestr) +
+ ";\n return " + MangleName(FName, typestr, ClassS) + "(__a1);";
+ break;
+ }
+ case OpFcvtxnHi: {
+ s = TypeString(proto[1], typestr) + " __a1 = " +
+ MangleName("vcvtx_f32", typestr, ClassS) + "(__b);\n " +
+ "return __builtin_shufflevector(__a, __a1";
+ for (unsigned i = 0; i < nElts * 4; ++i)
+ s += ", " + utostr(i);
+ s += ");";
+ break;
+ }
+ case OpUzp1:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = 0; i < nElts; i++)
+ s += ", " + utostr(2*i);
+ s += ");";
+ break;
+ case OpUzp2:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = 0; i < nElts; i++)
+ s += ", " + utostr(2*i+1);
+ s += ");";
+ break;
+ case OpZip1:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = 0; i < (nElts/2); i++)
+ s += ", " + utostr(i) + ", " + utostr(i+nElts);
+ s += ");";
+ break;
+ case OpZip2:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = nElts/2; i < nElts; i++)
+ s += ", " + utostr(i) + ", " + utostr(i+nElts);
+ s += ");";
+ break;
+ case OpTrn1:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = 0; i < (nElts/2); i++)
+ s += ", " + utostr(2*i) + ", " + utostr(2*i+nElts);
+ s += ");";
+ break;
+ case OpTrn2:
+ s += "__builtin_shufflevector(__a, __b";
+ for (unsigned i = 0; i < (nElts/2); i++)
+ s += ", " + utostr(2*i+1) + ", " + utostr(2*i+1+nElts);
+ s += ");";
+ break;
case OpAbdl: {
std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
if (typestr[0] != 'U') {
@@ -1468,23 +1999,247 @@ static std::string GenOpString(OpKind op, const std::string &proto,
}
break;
}
+ case OpAbdlHi:
+ s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
+ break;
+ case OpAddhnHi: {
+ std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
+ s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
+ s += ";";
+ break;
+ }
+ case OpRAddhnHi: {
+ std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
+ s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
+ s += ";";
+ break;
+ }
+ case OpSubhnHi: {
+ std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
+ s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
+ s += ";";
+ break;
+ }
+ case OpRSubhnHi: {
+ std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
+ s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
+ s += ";";
+ break;
+ }
case OpAba:
s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
break;
- case OpAbal: {
- s += "__a + ";
- std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)";
- if (typestr[0] != 'U') {
- // vabd results are always unsigned and must be zero-extended.
- std::string utype = "U" + typestr.str();
- s += "(" + TypeString(proto[0], typestr) + ")";
- abd = "(" + TypeString('d', utype) + ")" + abd;
- s += Extend(utype, abd) + ";";
+ case OpAbal:
+ s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
+ break;
+ case OpAbalHi:
+ s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
+ break;
+ case OpQDMullHi:
+ s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
+ break;
+ case OpQDMullHiN:
+ s += MangleName("vqdmull_n", typestr, ClassS);
+ s += "(" + GetHigh("__a", typestr) + ", __b);";
+ return s;
+ case OpQDMlalHi:
+ s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
+ break;
+ case OpQDMlalHiN:
+ s += MangleName("vqdmlal_n", typestr, ClassS);
+ s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
+ return s;
+ case OpQDMlslHi:
+ s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
+ break;
+ case OpQDMlslHiN:
+ s += MangleName("vqdmlsl_n", typestr, ClassS);
+ s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
+ return s;
+ case OpDiv:
+ s += "__a / __b;";
+ break;
+ case OpMovlHi: {
+ s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
+ MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
+ s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
+ s += "(__a1, 0);";
+ break;
+ }
+ case OpLongHi: {
+ // Another local variable __a1 is needed for calling a Macro,
+ // or using __a will have naming conflict when Macro expanding.
+ s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
+ MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
+ s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
+ "(__a1, __b);";
+ break;
+ }
+ case OpNarrowHi: {
+ s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
+ MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
+ break;
+ }
+ case OpCopyLane: {
+ s += TypeString('s', typestr) + " __c2 = " +
+ MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n " +
+ MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);";
+ break;
+ }
+ case OpCopyQLane: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __c2 = vget_lane_" + typeCode +
+ "(__c1, __d1); \\\n vsetq_lane_" + typeCode + "(__c2, __a1, __b1);";
+ break;
+ }
+ case OpCopyLaneQ: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __c2 = vgetq_lane_" + typeCode +
+ "(__c1, __d1); \\\n vset_lane_" + typeCode + "(__c2, __a1, __b1);";
+ break;
+ }
+ case OpScalarMulLane: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
+ "(__b, __c);\\\n __a * __d1;";
+ break;
+ }
+ case OpScalarMulLaneQ: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + typeCode +
+ "(__b, __c);\\\n __a * __d1;";
+ break;
+ }
+ case OpScalarMulXLane: {
+ bool dummy = false;
+ char type = ClassifyType(typestr, dummy, dummy, dummy);
+ if (type == 'f') type = 's';
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
+ "(__b, __c);\\\n vmulx" + type + "_" +
+ typeCode + "(__a, __d1);";
+ break;
+ }
+ case OpScalarMulXLaneQ: {
+ bool dummy = false;
+ char type = ClassifyType(typestr, dummy, dummy, dummy);
+ if (type == 'f') type = 's';
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vgetq_lane_" +
+ typeCode + "(__b, __c);\\\n vmulx" + type +
+ "_" + typeCode + "(__a, __d1);";
+ break;
+ }
+
+ case OpScalarVMulXLane: {
+ bool dummy = false;
+ char type = ClassifyType(typestr, dummy, dummy, dummy);
+ if (type == 'f') type = 's';
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vget_lane_" +
+ typeCode + "(__a, 0);\\\n" +
+ " " + TypeString('s', typestr) + " __e1 = vget_lane_" +
+ typeCode + "(__b, __c);\\\n" +
+ " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
+ typeCode + "(__d1, __e1);\\\n" +
+ " " + TypeString('d', typestr) + " __g1;\\\n" +
+ " vset_lane_" + typeCode + "(__f1, __g1, __c);";
+ break;
+ }
+
+ case OpScalarVMulXLaneQ: {
+ bool dummy = false;
+ char type = ClassifyType(typestr, dummy, dummy, dummy);
+ if (type == 'f') type = 's';
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += TypeString('s', typestr) + " __d1 = vget_lane_" +
+ typeCode + "(__a, 0);\\\n" +
+ " " + TypeString('s', typestr) + " __e1 = vgetq_lane_" +
+ typeCode + "(__b, __c);\\\n" +
+ " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
+ typeCode + "(__d1, __e1);\\\n" +
+ " " + TypeString('d', typestr) + " __g1;\\\n" +
+ " vset_lane_" + typeCode + "(__f1, __g1, 0);";
+ break;
+ }
+ case OpScalarQDMullLane: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
+ "vget_lane_" + typeCode + "(b, __c));";
+ break;
+ }
+ case OpScalarQDMullLaneQ: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
+ "vgetq_lane_" + typeCode + "(b, __c));";
+ break;
+ }
+ case OpScalarQDMulHiLane: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
+ "vget_lane_" + typeCode + "(__b, __c));";
+ break;
+ }
+ case OpScalarQDMulHiLaneQ: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
+ "vgetq_lane_" + typeCode + "(__b, __c));";
+ break;
+ }
+ case OpScalarQRDMulHiLane: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
+ "vget_lane_" + typeCode + "(__b, __c));";
+ break;
+ }
+ case OpScalarQRDMulHiLaneQ: {
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
+ "vgetq_lane_" + typeCode + "(__b, __c));";
+ break;
+ }
+ case OpScalarGetLane:{
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ if (quad) {
+ s += "int16x8_t __a1 = vreinterpretq_s16_f16(__a);\\\n";
+ s += " vgetq_lane_s16(__a1, __b);";
} else {
- s += Extend(typestr, abd) + ";";
+ s += "int16x4_t __a1 = vreinterpret_s16_f16(__a);\\\n";
+ s += " vget_lane_s16(__a1, __b);";
}
break;
}
+ case OpScalarSetLane:{
+ std::string typeCode = "";
+ InstructionTypeCode(typestr, ClassS, quad, typeCode);
+ s += "int16_t __a1 = (int16_t)__a;\\\n";
+ if (quad) {
+ s += " int16x8_t __b1 = vreinterpretq_s16_f16(b);\\\n";
+ s += " int16x8_t __b2 = vsetq_lane_s16(__a1, __b1, __c);\\\n";
+ s += " vreinterpretq_f16_s16(__b2);";
+ } else {
+ s += " int16x4_t __b1 = vreinterpret_s16_f16(b);\\\n";
+ s += " int16x4_t __b2 = vset_lane_s16(__a1, __b1, __c);\\\n";
+ s += " vreinterpret_f16_s16(__b2);";
+ }
+ break;
+ }
+
default:
PrintFatalError("unknown OpKind!");
}
@@ -1494,7 +2249,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
unsigned mod = proto[0];
- if (mod == 'v' || mod == 'f')
+ if (mod == 'v' || mod == 'f' || mod == 'F')
mod = proto[1];
bool quad = false;
@@ -1522,7 +2277,7 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
ET = NeonTypeFlags::Int32;
break;
case 'l':
- ET = NeonTypeFlags::Int64;
+ ET = poly ? NeonTypeFlags::Poly64 : NeonTypeFlags::Int64;
break;
case 'h':
ET = NeonTypeFlags::Float16;
@@ -1530,6 +2285,9 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
case 'f':
ET = NeonTypeFlags::Float32;
break;
+ case 'd':
+ ET = NeonTypeFlags::Float64;
+ break;
default:
PrintFatalError("unhandled type!");
}
@@ -1537,6 +2295,19 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
return Flags.getFlags();
}
+// We don't check 'a' in this function, because for builtin function the
+// argument matching to 'a' uses a vector type splatted from a scalar type.
+static bool ProtoHasScalar(const std::string proto)
+{
+ return (proto.find('s') != std::string::npos
+ || proto.find('z') != std::string::npos
+ || proto.find('r') != std::string::npos
+ || proto.find('b') != std::string::npos
+ || proto.find('$') != std::string::npos
+ || proto.find('y') != std::string::npos
+ || proto.find('o') != std::string::npos);
+}
+
// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
static std::string GenBuiltin(const std::string &name, const std::string &proto,
StringRef typestr, ClassKind ck) {
@@ -1544,14 +2315,14 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
// If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
// sret-like argument.
- bool sret = (proto[0] >= '2' && proto[0] <= '4');
+ bool sret = IsMultiVecProto(proto[0]);
bool define = UseMacro(proto);
// Check if the prototype has a scalar operand with the type of the vector
// elements. If not, bitcasting the args will take care of arg checking.
// The actual signedness etc. will be taken care of with special enums.
- if (proto.find('s') == std::string::npos)
+ if (!ProtoHasScalar(proto))
ck = ClassB;
if (proto[0] != 'v') {
@@ -1604,12 +2375,19 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
// Handle multiple-vector values specially, emitting each subvector as an
// argument to the __builtin.
+ unsigned NumOfVec = 0;
if (proto[i] >= '2' && proto[i] <= '4') {
+ NumOfVec = proto[i] - '0';
+ } else if (proto[i] >= 'B' && proto[i] <= 'D') {
+ NumOfVec = proto[i] - 'A' + 1;
+ }
+
+ if (NumOfVec > 0) {
// Check if an explicit cast is needed.
if (argType != 'c' || argPoly || argUsgn)
args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
- for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
+ for (unsigned vi = 0, ve = NumOfVec; vi != ve; ++vi) {
s += args + ".val[" + utostr(vi) + "]";
if ((vi + 1) < ve)
s += ", ";
@@ -1662,7 +2440,7 @@ static std::string GenBuiltinDef(const std::string &name,
// If all types are the same size, bitcasting the args will take care
// of arg checking. The actual signedness etc. will be taken care of with
// special enums.
- if (proto.find('s') == std::string::npos)
+ if (!ProtoHasScalar(proto))
ck = ClassB;
s += MangleName(name, typestr, ck);
@@ -1706,12 +2484,12 @@ static std::string GenIntrinsic(const std::string &name,
s += mangledName;
// Function arguments
- s += GenArgs(proto, inTypeStr);
+ s += GenArgs(proto, inTypeStr, name);
// Definition.
if (define) {
s += " __extension__ ({ \\\n ";
- s += GenMacroLocals(proto, inTypeStr);
+ s += GenMacroLocals(proto, inTypeStr, name);
} else if (kind == OpUnavailable) {
s += " __attribute__((unavailable));\n";
return s;
@@ -1719,7 +2497,7 @@ static std::string GenIntrinsic(const std::string &name,
s += " {\n ";
if (kind != OpNone)
- s += GenOpString(kind, proto, outTypeStr);
+ s += GenOpString(name, kind, proto, outTypeStr);
else
s += GenBuiltin(name, proto, outTypeStr, classKind);
if (define)
@@ -1773,7 +2551,7 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << "#ifndef __ARM_NEON_H\n";
OS << "#define __ARM_NEON_H\n\n";
- OS << "#ifndef __ARM_NEON__\n";
+ OS << "#if !defined(__ARM_NEON__) && !defined(__ARM_NEON)\n";
OS << "#error \"NEON support not enabled\"\n";
OS << "#endif\n\n";
@@ -1781,19 +2559,50 @@ void NeonEmitter::run(raw_ostream &OS) {
// Emit NEON-specific scalar typedefs.
OS << "typedef float float32_t;\n";
+ OS << "typedef __fp16 float16_t;\n";
+
+ OS << "#ifdef __aarch64__\n";
+ OS << "typedef double float64_t;\n";
+ OS << "#endif\n\n";
+
+ // For now, signedness of polynomial types depends on target
+ OS << "#ifdef __aarch64__\n";
+ OS << "typedef uint8_t poly8_t;\n";
+ OS << "typedef uint16_t poly16_t;\n";
+ OS << "typedef uint64_t poly64_t;\n";
+ OS << "#else\n";
OS << "typedef int8_t poly8_t;\n";
OS << "typedef int16_t poly16_t;\n";
- OS << "typedef uint16_t float16_t;\n";
+ OS << "#endif\n";
// Emit Neon vector typedefs.
- std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
+ std::string TypedefTypes(
+ "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl");
SmallVector<StringRef, 24> TDTypeVec;
ParseTypes(0, TypedefTypes, TDTypeVec);
// Emit vector typedefs.
+ bool isA64 = false;
+ bool preinsert;
+ bool postinsert;
for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
bool dummy, quad = false, poly = false;
- (void) ClassifyType(TDTypeVec[i], quad, poly, dummy);
+ char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
+ preinsert = false;
+ postinsert = false;
+
+ if (type == 'd' || (type == 'l' && poly)) {
+ preinsert = isA64? false: true;
+ isA64 = true;
+ } else {
+ postinsert = isA64? true: false;
+ isA64 = false;
+ }
+ if (postinsert)
+ OS << "#endif\n";
+ if (preinsert)
+ OS << "#ifdef __aarch64__\n";
+
if (poly)
OS << "typedef __attribute__((neon_polyvector_type(";
else
@@ -1806,50 +2615,130 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << TypeString('s', TDTypeVec[i]);
OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
+
}
+ postinsert = isA64? true: false;
+ if (postinsert)
+ OS << "#endif\n";
OS << "\n";
// Emit struct typedefs.
+ isA64 = false;
for (unsigned vi = 2; vi != 5; ++vi) {
for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
+ bool dummy, quad = false, poly = false;
+ char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
+ preinsert = false;
+ postinsert = false;
+
+ if (type == 'd' || (type == 'l' && poly)) {
+ preinsert = isA64? false: true;
+ isA64 = true;
+ } else {
+ postinsert = isA64? true: false;
+ isA64 = false;
+ }
+ if (postinsert)
+ OS << "#endif\n";
+ if (preinsert)
+ OS << "#ifdef __aarch64__\n";
+
std::string ts = TypeString('d', TDTypeVec[i]);
std::string vs = TypeString('0' + vi, TDTypeVec[i]);
OS << "typedef struct " << vs << " {\n";
OS << " " << ts << " val";
OS << "[" << utostr(vi) << "]";
OS << ";\n} ";
- OS << vs << ";\n\n";
+ OS << vs << ";\n";
+ OS << "\n";
}
}
+ postinsert = isA64? true: false;
+ if (postinsert)
+ OS << "#endif\n";
+ OS << "\n";
OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+ StringMap<ClassKind> EmittedMap;
+
// Emit vmovl, vmull and vabd intrinsics first so they can be used by other
// intrinsics. (Some of the saturating multiply instructions are also
// used to implement the corresponding "_lane" variants, but tablegen
// sorts the records into alphabetical order so that the "_lane" variants
// come after the intrinsics they use.)
- emitIntrinsic(OS, Records.getDef("VMOVL"));
- emitIntrinsic(OS, Records.getDef("VMULL"));
- emitIntrinsic(OS, Records.getDef("VABD"));
-
+ emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
+ emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
+ emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
+ emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
+
+ // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
+ // common intrinsics appear only once in the output stream.
+ // The check for uniquiness is done in emitIntrinsic.
+ // Emit ARM intrinsics.
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
- if (R->getName() != "VMOVL" &&
- R->getName() != "VMULL" &&
+
+ // Skip AArch64 intrinsics; they will be emitted at the end.
+ bool isA64 = R->getValueAsBit("isA64");
+ if (isA64)
+ continue;
+
+ if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
R->getName() != "VABD")
- emitIntrinsic(OS, R);
+ emitIntrinsic(OS, R, EmittedMap);
+ }
+
+ // Emit AArch64-specific intrinsics.
+ OS << "#ifdef __aarch64__\n";
+
+ emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
+ emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
+ emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
+
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+
+ // Skip ARM intrinsics already included above.
+ bool isA64 = R->getValueAsBit("isA64");
+ if (!isA64)
+ continue;
+
+ // Skip crypto temporarily, and will emit them all together at the end.
+ bool isCrypto = R->getValueAsBit("isCrypto");
+ if (isCrypto)
+ continue;
+
+ emitIntrinsic(OS, R, EmittedMap);
+ }
+
+ OS << "#ifdef __ARM_FEATURE_CRYPTO\n";
+
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+
+ // Skip crypto temporarily, and will emit them all together at the end.
+ bool isCrypto = R->getValueAsBit("isCrypto");
+ if (!isCrypto)
+ continue;
+
+ emitIntrinsic(OS, R, EmittedMap);
}
+
+ OS << "#endif\n\n";
+
+ OS << "#endif\n\n";
OS << "#undef __ai\n\n";
OS << "#endif /* __ARM_NEON_H */\n";
}
/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
-/// intrinsics specified by record R.
-void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
+/// intrinsics specified by record R checking for intrinsic uniqueness.
+void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
+ StringMap<ClassKind> &EmittedMap) {
std::string name = R->getValueAsString("Name");
std::string Proto = R->getValueAsString("Prototype");
std::string Types = R->getValueAsString("Types");
@@ -1876,12 +2765,20 @@ void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
(void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
if (srcti == ti || inQuad != outQuad)
continue;
- OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
- OpCast, ClassS);
+ std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
+ OpCast, ClassS);
+ if (EmittedMap.count(s))
+ continue;
+ EmittedMap[s] = ClassS;
+ OS << s;
}
} else {
- OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti],
- kind, classKind);
+ std::string s =
+ GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
+ if (EmittedMap.count(s))
+ continue;
+ EmittedMap[s] = classKind;
+ OS << s;
}
}
OS << "\n";
@@ -1902,6 +2799,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) {
case 'f':
case 'i':
return (2 << (int)quad) - 1;
+ case 'd':
case 'l':
return (1 << (int)quad) - 1;
default:
@@ -1909,56 +2807,198 @@ static unsigned RangeFromType(const char mod, StringRef typestr) {
}
}
-/// runHeader - Emit a file with sections defining:
-/// 1. the NEON section of BuiltinsARM.def.
-/// 2. the SemaChecking code for the type overload checking.
-/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
-void NeonEmitter::runHeader(raw_ostream &OS) {
- std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+static unsigned RangeScalarShiftImm(const char mod, StringRef typestr) {
+ // base type to get the type string for.
+ bool dummy = false;
+ char type = ClassifyType(typestr, dummy, dummy, dummy);
+ type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy);
+ switch (type) {
+ case 'c':
+ return 7;
+ case 'h':
+ case 's':
+ return 15;
+ case 'f':
+ case 'i':
+ return 31;
+ case 'd':
+ case 'l':
+ return 63;
+ default:
+ PrintFatalError("unhandled type!");
+ }
+}
+
+/// Generate the ARM and AArch64 intrinsic range checking code for
+/// shift/lane immediates, checking for unique declarations.
+void
+NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
+ StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64RangeCheck) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
StringMap<OpKind> EmittedMap;
- // Generate BuiltinsARM.def for NEON
- OS << "#ifdef GET_NEON_BUILTINS\n";
+ // Generate the intrinsic range checking code for shift/lane immediates.
+ if (isA64RangeCheck)
+ OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
+ else
+ OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
+
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
+
OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
if (k != OpNone)
continue;
+ std::string name = R->getValueAsString("Name");
std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+ std::string Rename = name + "@" + Proto;
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
continue;
- std::string Types = R->getValueAsString("Types");
+ // Functions which do not have an immediate do not need to have range
+ // checking code emitted.
+ size_t immPos = Proto.find('i');
+ if (immPos == std::string::npos)
+ continue;
+
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
PrintFatalError(R->getLoc(), "Builtin has no class kind");
- std::string name = R->getValueAsString("Name");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
+ if (!ProtoHasScalar(Proto))
+ ck = ClassB;
+
+ // Do not include AArch64 range checks if not generating code for AArch64.
+ bool isA64 = R->getValueAsBit("isA64");
+ if (!isA64RangeCheck && isA64)
+ continue;
+
+ // Include ARM range checks in AArch64 but only if ARM intrinsics are not
+ // redefined by AArch64 to handle new types.
+ if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
+ ClassKind &A64CK = A64IntrinsicMap[Rename];
+ if (A64CK == ck && ck != ClassNone)
+ continue;
+ }
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
- // Generate the BuiltinsARM.def declaration for this builtin, ensuring
- // that each unique BUILTIN() macro appears only once in the output
- // stream.
- std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
- if (EmittedMap.count(bd))
+ std::string namestr, shiftstr, rangestr;
+
+ if (R->getValueAsBit("isVCVT_N")) {
+ // VCVT between floating- and fixed-point values takes an immediate
+ // in the range [1, 32] for f32, or [1, 64] for f64.
+ ck = ClassB;
+ if (name.find("32") != std::string::npos)
+ rangestr = "l = 1; u = 31"; // upper bound = l + u
+ else if (name.find("64") != std::string::npos)
+ rangestr = "l = 1; u = 63";
+ else
+ PrintFatalError(R->getLoc(),
+ "Fixed point convert name should contains \"32\" or \"64\"");
+
+ } else if (R->getValueAsBit("isScalarShift")) {
+ // Right shifts have an 'r' in the name, left shifts do not. Convert
+ // instructions have the same bounds and right shifts.
+ if (name.find('r') != std::string::npos ||
+ name.find("cvt") != std::string::npos)
+ rangestr = "l = 1; ";
+
+ unsigned upBound = RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]);
+ // Narrow shift has half the upper bound
+ if (R->getValueAsBit("isScalarNarrowShift"))
+ upBound /= 2;
+
+ rangestr += "u = " + utostr(upBound);
+ } else if (R->getValueAsBit("isShift")) {
+ // Builtins which are overloaded by type will need to have their upper
+ // bound computed at Sema time based on the type constant.
+ shiftstr = ", true";
+
+ // Right shifts have an 'r' in the name, left shifts do not.
+ if (name.find('r') != std::string::npos)
+ rangestr = "l = 1; ";
+
+ rangestr += "u = RFT(TV" + shiftstr + ")";
+ } else {
+ // The immediate generally refers to a lane in the preceding argument.
+ assert(immPos > 0 && "unexpected immediate operand");
+ rangestr =
+ "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
+ }
+ // Make sure cases appear only once by uniquing them in a string map.
+ namestr = MangleName(name, TypeVec[ti], ck);
+ if (EmittedMap.count(namestr))
continue;
+ EmittedMap[namestr] = OpNone;
- EmittedMap[bd] = OpNone;
- OS << bd << "\n";
+ // Calculate the index of the immediate that should be range checked.
+ unsigned immidx = 0;
+
+ // Builtins that return a struct of multiple vectors have an extra
+ // leading arg for the struct return.
+ if (IsMultiVecProto(Proto[0]))
+ ++immidx;
+
+ // Add one to the index for each argument until we reach the immediate
+ // to be checked. Structs of vectors are passed as multiple arguments.
+ for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
+ switch (Proto[ii]) {
+ default:
+ immidx += 1;
+ break;
+ case '2':
+ case 'B':
+ immidx += 2;
+ break;
+ case '3':
+ case 'C':
+ immidx += 3;
+ break;
+ case '4':
+ case 'D':
+ immidx += 4;
+ break;
+ case 'i':
+ ie = ii + 1;
+ break;
+ }
+ }
+ if (isA64RangeCheck)
+ OS << "case AArch64::BI__builtin_neon_";
+ else
+ OS << "case ARM::BI__builtin_neon_";
+ OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
+ << rangestr << "; break;\n";
}
}
OS << "#endif\n\n";
+}
+
+/// Generate the ARM and AArch64 overloaded type checking code for
+/// SemaChecking.cpp, checking for unique builtin declarations.
+void
+NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
+ StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64TypeCheck) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ StringMap<OpKind> EmittedMap;
// Generate the overloaded type checking code for SemaChecking.cpp
- OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
+ if (isA64TypeCheck)
+ OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
+ else
+ OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
+
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
@@ -1968,7 +3008,8 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
std::string Proto = R->getValueAsString("Prototype");
std::string Types = R->getValueAsString("Types");
std::string name = R->getValueAsString("Name");
-
+ std::string Rename = name + "@" + Proto;
+
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
@@ -1976,7 +3017,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
// Functions which have a scalar argument cannot be overloaded, no need to
// check them if we are emitting the type checking code.
- if (Proto.find('s') != std::string::npos)
+ if (ProtoHasScalar(Proto))
continue;
SmallVector<StringRef, 16> TypeVec;
@@ -1985,6 +3026,21 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
if (R->getSuperClasses().size() < 2)
PrintFatalError(R->getLoc(), "Builtin has no class kind");
+ // Do not include AArch64 type checks if not generating code for AArch64.
+ bool isA64 = R->getValueAsBit("isA64");
+ if (!isA64TypeCheck && isA64)
+ continue;
+
+ // Include ARM type check in AArch64 but only if ARM intrinsics
+ // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
+ // redefined in AArch64 to handle an additional 2 x f64 type.
+ ClassKind ck = ClassMap[R->getSuperClasses()[1]];
+ if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
+ ClassKind &A64CK = A64IntrinsicMap[Rename];
+ if (A64CK == ck && ck != ClassNone)
+ continue;
+ }
+
int si = -1, qi = -1;
uint64_t mask = 0, qmask = 0;
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
@@ -2017,7 +3073,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
}
}
// For sret builtins, adjust the pointer argument index.
- if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
+ if (PtrArgNum >= 0 && IsMultiVecProto(Proto[0]))
PtrArgNum += 1;
// Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
@@ -2032,9 +3088,12 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
}
if (mask) {
- OS << "case ARM::BI__builtin_neon_"
- << MangleName(name, TypeVec[si], ClassB)
- << ": mask = " << "0x" << utohexstr(mask) << "ULL";
+ if (isA64TypeCheck)
+ OS << "case AArch64::BI__builtin_neon_";
+ else
+ OS << "case ARM::BI__builtin_neon_";
+ OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
+ << "0x" << utohexstr(mask) << "ULL";
if (PtrArgNum >= 0)
OS << "; PtrArgNum = " << PtrArgNum;
if (HasConstPtr)
@@ -2042,9 +3101,12 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
OS << "; break;\n";
}
if (qmask) {
- OS << "case ARM::BI__builtin_neon_"
- << MangleName(name, TypeVec[qi], ClassB)
- << ": mask = " << "0x" << utohexstr(qmask) << "ULL";
+ if (isA64TypeCheck)
+ OS << "case AArch64::BI__builtin_neon_";
+ else
+ OS << "case ARM::BI__builtin_neon_";
+ OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
+ << "0x" << utohexstr(qmask) << "ULL";
if (PtrArgNum >= 0)
OS << "; PtrArgNum = " << PtrArgNum;
if (HasConstPtr)
@@ -2053,31 +3115,38 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
}
}
OS << "#endif\n\n";
+}
+
+/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
+/// declaration of builtins, checking for unique builtin declarations.
+void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
+ StringMap<ClassKind> &A64IntrinsicMap,
+ bool isA64GenBuiltinDef) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ StringMap<OpKind> EmittedMap;
+
+ // Generate BuiltinsARM.def and BuiltinsAArch64.def
+ if (isA64GenBuiltinDef)
+ OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
+ else
+ OS << "#ifdef GET_NEON_BUILTINS\n";
- // Generate the intrinsic range checking code for shift/lane immediates.
- OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
-
OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
if (k != OpNone)
continue;
- std::string name = R->getValueAsString("Name");
std::string Proto = R->getValueAsString("Prototype");
- std::string Types = R->getValueAsString("Types");
+ std::string name = R->getValueAsString("Name");
+ std::string Rename = name + "@" + Proto;
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
continue;
- // Functions which do not have an immediate do not need to have range
- // checking code emitted.
- size_t immPos = Proto.find('i');
- if (immPos == std::string::npos)
- continue;
-
+ std::string Types = R->getValueAsString("Types");
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
@@ -2086,70 +3155,92 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
- for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
- std::string namestr, shiftstr, rangestr;
-
- if (R->getValueAsBit("isVCVT_N")) {
- // VCVT between floating- and fixed-point values takes an immediate
- // in the range 1 to 32.
- ck = ClassB;
- rangestr = "l = 1; u = 31"; // upper bound = l + u
- } else if (Proto.find('s') == std::string::npos) {
- // Builtins which are overloaded by type will need to have their upper
- // bound computed at Sema time based on the type constant.
- ck = ClassB;
- if (R->getValueAsBit("isShift")) {
- shiftstr = ", true";
+ // Do not include AArch64 BUILTIN() macros if not generating
+ // code for AArch64
+ bool isA64 = R->getValueAsBit("isA64");
+ if (!isA64GenBuiltinDef && isA64)
+ continue;
- // Right shifts have an 'r' in the name, left shifts do not.
- if (name.find('r') != std::string::npos)
- rangestr = "l = 1; ";
- }
- rangestr += "u = RFT(TV" + shiftstr + ")";
- } else {
- // The immediate generally refers to a lane in the preceding argument.
- assert(immPos > 0 && "unexpected immediate operand");
- rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti]));
- }
- // Make sure cases appear only once by uniquing them in a string map.
- namestr = MangleName(name, TypeVec[ti], ck);
- if (EmittedMap.count(namestr))
+ // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
+ // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
+ // redefined in AArch64 to handle an additional 2 x f64 type.
+ if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
+ ClassKind &A64CK = A64IntrinsicMap[Rename];
+ if (A64CK == ck && ck != ClassNone)
continue;
- EmittedMap[namestr] = OpNone;
-
- // Calculate the index of the immediate that should be range checked.
- unsigned immidx = 0;
+ }
- // Builtins that return a struct of multiple vectors have an extra
- // leading arg for the struct return.
- if (Proto[0] >= '2' && Proto[0] <= '4')
- ++immidx;
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ // Generate the declaration for this builtin, ensuring
+ // that each unique BUILTIN() macro appears only once in the output
+ // stream.
+ std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
+ if (EmittedMap.count(bd))
+ continue;
- // Add one to the index for each argument until we reach the immediate
- // to be checked. Structs of vectors are passed as multiple arguments.
- for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
- switch (Proto[ii]) {
- default: immidx += 1; break;
- case '2': immidx += 2; break;
- case '3': immidx += 3; break;
- case '4': immidx += 4; break;
- case 'i': ie = ii + 1; break;
- }
- }
- OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
- << ": i = " << immidx << "; " << rangestr << "; break;\n";
+ EmittedMap[bd] = OpNone;
+ OS << bd << "\n";
}
}
OS << "#endif\n\n";
}
+/// runHeader - Emit a file with sections defining:
+/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
+/// 2. the SemaChecking code for the type overload checking.
+/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
+void NeonEmitter::runHeader(raw_ostream &OS) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+
+ // build a map of AArch64 intriniscs to be used in uniqueness checks.
+ StringMap<ClassKind> A64IntrinsicMap;
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+
+ bool isA64 = R->getValueAsBit("isA64");
+ if (!isA64)
+ continue;
+
+ ClassKind CK = ClassNone;
+ if (R->getSuperClasses().size() >= 2)
+ CK = ClassMap[R->getSuperClasses()[1]];
+
+ std::string Name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Rename = Name + "@" + Proto;
+ if (A64IntrinsicMap.count(Rename))
+ continue;
+ A64IntrinsicMap[Rename] = CK;
+ }
+
+ // Generate BuiltinsARM.def for ARM
+ genBuiltinsDef(OS, A64IntrinsicMap, false);
+
+ // Generate BuiltinsAArch64.def for AArch64
+ genBuiltinsDef(OS, A64IntrinsicMap, true);
+
+ // Generate ARM overloaded type checking code for SemaChecking.cpp
+ genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
+
+ // Generate AArch64 overloaded type checking code for SemaChecking.cpp
+ genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
+
+ // Generate ARM range checking code for shift/lane immediates.
+ genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
+
+ // Generate the AArch64 range checking code for shift/lane immediates.
+ genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
+}
+
/// GenTest - Write out a test for the intrinsic specified by the name and
/// type strings, including the embedded patterns for FileCheck to match.
static std::string GenTest(const std::string &name,
const std::string &proto,
StringRef outTypeStr, StringRef inTypeStr,
bool isShift, bool isHiddenLOp,
- ClassKind ck, const std::string &InstName) {
+ ClassKind ck, const std::string &InstName,
+ bool isA64,
+ std::string & testFuncProto) {
assert(!proto.empty() && "");
std::string s;
@@ -2164,12 +3255,17 @@ static std::string GenTest(const std::string &name,
mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
}
+ // todo: GenerateChecksForIntrinsic does not generate CHECK
+ // for aarch64 instructions yet
std::vector<std::string> FileCheckPatterns;
- GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
- isHiddenLOp, FileCheckPatterns);
+ if (!isA64) {
+ GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
+ isHiddenLOp, FileCheckPatterns);
+ s+= "// CHECK_ARM: test_" + mangledName + "\n";
+ }
+ s += "// CHECK_AARCH64: test_" + mangledName + "\n";
// Emit the FileCheck patterns.
- s += "// CHECK: test_" + mangledName + "\n";
// If for any reason we do not want to emit a check, mangledInst
// will be the empty string.
if (FileCheckPatterns.size()) {
@@ -2177,23 +3273,27 @@ static std::string GenTest(const std::string &name,
e = FileCheckPatterns.end();
i != e;
++i) {
- s += "// CHECK: " + *i + "\n";
+ s += "// CHECK_ARM: " + *i + "\n";
}
}
// Emit the start of the test function.
- s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
+
+ testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
char arg = 'a';
std::string comma;
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
// Do not create arguments for values that must be immediate constants.
if (proto[i] == 'i')
continue;
- s += comma + TypeString(proto[i], inTypeStr) + " ";
- s.push_back(arg);
+ testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
+ testFuncProto.push_back(arg);
comma = ", ";
}
- s += ") {\n ";
+ testFuncProto += ")";
+
+ s+= testFuncProto;
+ s+= " {\n ";
if (proto[0] != 'v')
s += "return ";
@@ -2217,18 +3317,14 @@ static std::string GenTest(const std::string &name,
return s;
}
-/// runTests - Write out a complete set of tests for all of the Neon
-/// intrinsics.
-void NeonEmitter::runTests(raw_ostream &OS) {
- OS <<
- "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi apcs-gnu\\\n"
- "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
- "// RUN: | FileCheck %s\n"
- "\n"
- "#include <arm_neon.h>\n"
- "\n";
+/// Write out all intrinsic tests for the specified target, checking
+/// for intrinsic test uniqueness.
+void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
+ bool isA64GenTest) {
+ if (isA64GenTest)
+ OS << "#ifdef __aarch64__\n";
- std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
std::string name = R->getValueAsString("Name");
@@ -2237,6 +3333,12 @@ void NeonEmitter::runTests(raw_ostream &OS) {
bool isShift = R->getValueAsBit("isShift");
std::string InstName = R->getValueAsString("InstName");
bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
+ bool isA64 = R->getValueAsBit("isA64");
+
+ // do not include AArch64 intrinsic test if not generating
+ // code for AArch64
+ if (!isA64GenTest && isA64)
+ continue;
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
@@ -2256,16 +3358,56 @@ void NeonEmitter::runTests(raw_ostream &OS) {
(void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
if (srcti == ti || inQuad != outQuad)
continue;
- OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
- isShift, isHiddenLOp, ck, InstName);
+ std::string testFuncProto;
+ std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
+ isShift, isHiddenLOp, ck, InstName, isA64,
+ testFuncProto);
+ if (EmittedMap.count(testFuncProto))
+ continue;
+ EmittedMap[testFuncProto] = kind;
+ OS << s << "\n";
}
} else {
- OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti],
- isShift, isHiddenLOp, ck, InstName);
+ std::string testFuncProto;
+ std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
+ isHiddenLOp, ck, InstName, isA64, testFuncProto);
+ if (EmittedMap.count(testFuncProto))
+ continue;
+ EmittedMap[testFuncProto] = kind;
+ OS << s << "\n";
}
}
- OS << "\n";
}
+
+ if (isA64GenTest)
+ OS << "#endif\n";
+}
+/// runTests - Write out a complete set of tests for all of the Neon
+/// intrinsics.
+void NeonEmitter::runTests(raw_ostream &OS) {
+ OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
+ "apcs-gnu\\\n"
+ "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
+ "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
+ "\n"
+ "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
+ "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
+ "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
+ "\n"
+ "// REQUIRES: long_tests\n"
+ "\n"
+ "#include <arm_neon.h>\n"
+ "\n";
+
+ // ARM tests must be emitted before AArch64 tests to ensure
+ // tests for intrinsics that are common to ARM and AArch64
+ // appear only once in the output stream.
+ // The check for uniqueness is done in genTargetTest.
+ StringMap<OpKind> EmittedMap;
+
+ genTargetTest(OS, EmittedMap, false);
+
+ genTargetTest(OS, EmittedMap, true);
}
namespace clang {
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
deleted file mode 100644
index 0553b1f4806e..000000000000
--- a/utils/TableGen/OptParserEmitter.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/TableGen/TableGenBackend.h"
-#include <map>
-
-using namespace llvm;
-
-static int StrCmpOptionName(const char *A, const char *B) {
- char a = *A, b = *B;
- while (a == b) {
- if (a == '\0')
- return 0;
-
- a = *++A;
- b = *++B;
- }
-
- if (a == '\0') // A is a prefix of B.
- return 1;
- if (b == '\0') // B is a prefix of A.
- return -1;
-
- // Otherwise lexicographic.
- return (a < b) ? -1 : 1;
-}
-
-static int CompareOptionRecords(const void *Av, const void *Bv) {
- const Record *A = *(const Record*const*) Av;
- const Record *B = *(const Record*const*) Bv;
-
- // Sentinel options precede all others and are only ordered by precedence.
- bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
- bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
- if (ASent != BSent)
- return ASent ? -1 : 1;
-
- // Compare options by name, unless they are sentinels.
- if (!ASent)
- if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
- B->getValueAsString("Name").c_str()))
- return Cmp;
-
- if (!ASent) {
- std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
- std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes");
-
- for (std::vector<std::string>::const_iterator APre = APrefixes.begin(),
- AEPre = APrefixes.end(),
- BPre = BPrefixes.begin(),
- BEPre = BPrefixes.end();
- APre != AEPre &&
- BPre != BEPre;
- ++APre, ++BPre) {
- if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str()))
- return Cmp;
- }
- }
-
- // Then by the kind precedence;
- int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
- int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
- if (APrec == BPrec &&
- A->getValueAsListOfStrings("Prefixes") ==
- B->getValueAsListOfStrings("Prefixes")) {
- PrintError(A->getLoc(), Twine("Option is equivilent to"));
- PrintError(B->getLoc(), Twine("Other defined here"));
- PrintFatalError("Equivalent Options found.");
- }
- return APrec < BPrec ? -1 : 1;
-}
-
-static const std::string getOptionName(const Record &R) {
- // Use the record name unless EnumName is defined.
- if (isa<UnsetInit>(R.getValueInit("EnumName")))
- return R.getName();
-
- return R.getValueAsString("EnumName");
-}
-
-static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
- OS << '"';
- OS.write_escaped(Str);
- OS << '"';
- return OS;
-}
-
-/// OptParserEmitter - This tablegen backend takes an input .td file
-/// describing a list of options and emits a data structure for parsing and
-/// working with those options when given an input command line.
-namespace clang {
-void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
- // Get the option groups and options.
- const std::vector<Record*> &Groups =
- Records.getAllDerivedDefinitions("OptionGroup");
- std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
-
- if (GenDefs)
- emitSourceFileHeader("Option Parsing Definitions", OS);
- else
- emitSourceFileHeader("Option Parsing Table", OS);
-
- array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
- if (GenDefs) {
- // Generate prefix groups.
- typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
- typedef std::map<PrefixKeyT, std::string> PrefixesT;
- PrefixesT Prefixes;
- Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
- unsigned CurPrefix = 0;
- for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
- const Record &R = *Opts[i];
- std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
- PrefixKeyT prfkey(prf.begin(), prf.end());
- unsigned NewPrefix = CurPrefix + 1;
- if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
- Twine(NewPrefix)).str())).second)
- CurPrefix = NewPrefix;
- }
-
- OS << "#ifndef PREFIX\n";
- OS << "#error \"Define PREFIX prior to including this file!\"\n";
- OS << "#endif\n\n";
-
- // Dump prefixes.
- OS << "/////////\n";
- OS << "// Prefixes\n\n";
- OS << "#define COMMA ,\n";
- for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
- I != E; ++I) {
- OS << "PREFIX(";
-
- // Prefix name.
- OS << I->second;
-
- // Prefix values.
- OS << ", {";
- for (PrefixKeyT::const_iterator PI = I->first.begin(),
- PE = I->first.end(); PI != PE; ++PI) {
- OS << "\"" << *PI << "\" COMMA ";
- }
- OS << "0})\n";
- }
- OS << "#undef COMMA\n";
- OS << "\n";
-
- OS << "#ifndef OPTION\n";
- OS << "#error \"Define OPTION prior to including this file!\"\n";
- OS << "#endif\n\n";
-
- OS << "/////////\n";
- OS << "// Groups\n\n";
- for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
- const Record &R = *Groups[i];
-
- // Start a single option entry.
- OS << "OPTION(";
-
- // The option prefix;
- OS << "0";
-
- // The option string.
- OS << ", \"" << R.getValueAsString("Name") << '"';
-
- // The option identifier name.
- OS << ", "<< getOptionName(R);
-
- // The option kind.
- OS << ", Group";
-
- // The containing option group (if any).
- OS << ", ";
- if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
- OS << getOptionName(*DI->getDef());
- else
- OS << "INVALID";
-
- // The other option arguments (unused for groups).
- OS << ", INVALID, 0, 0";
-
- // The option help text.
- if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
- OS << ",\n";
- OS << " ";
- write_cstring(OS, R.getValueAsString("HelpText"));
- } else
- OS << ", 0";
-
- // The option meta-variable name (unused).
- OS << ", 0)\n";
- }
- OS << "\n";
-
- OS << "//////////\n";
- OS << "// Options\n\n";
- for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
- const Record &R = *Opts[i];
-
- // Start a single option entry.
- OS << "OPTION(";
-
- // The option prefix;
- std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
- OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
-
- // The option string.
- write_cstring(OS, R.getValueAsString("Name"));
-
- // The option identifier name.
- OS << ", "<< getOptionName(R);
-
- // The option kind.
- OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
-
- // The containing option group (if any).
- OS << ", ";
- if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
- OS << getOptionName(*DI->getDef());
- else
- OS << "INVALID";
-
- // The option alias (if any).
- OS << ", ";
- if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
- OS << getOptionName(*DI->getDef());
- else
- OS << "INVALID";
-
- // The option flags.
- const ListInit *LI = R.getValueAsListInit("Flags");
- if (LI->empty()) {
- OS << ", 0";
- } else {
- OS << ", ";
- for (unsigned i = 0, e = LI->size(); i != e; ++i) {
- if (i)
- OS << " | ";
- OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
- }
- }
-
- // The option parameter field.
- OS << ", " << R.getValueAsInt("NumArgs");
-
- // The option help text.
- if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
- OS << ",\n";
- OS << " ";
- write_cstring(OS, R.getValueAsString("HelpText"));
- } else
- OS << ", 0";
-
- // The option meta-variable name.
- OS << ", ";
- if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
- write_cstring(OS, R.getValueAsString("MetaVarName"));
- else
- OS << "0";
-
- OS << ")\n";
- }
- }
-}
-} // end namespace clang
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 12e1c47725e1..0e45d81d1af5 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -24,7 +24,8 @@ using namespace clang;
enum ActionType {
GenClangAttrClasses,
- GenClangAttrExprArgsList,
+ GenClangAttrIdentifierArgList,
+ GenClangAttrTypeArgList,
GenClangAttrImpl,
GenClangAttrList,
GenClangAttrPCHRead,
@@ -34,6 +35,7 @@ enum ActionType {
GenClangAttrLateParsedList,
GenClangAttrTemplateInstantiate,
GenClangAttrParsedAttrList,
+ GenClangAttrParsedAttrImpl,
GenClangAttrParsedAttrKinds,
GenClangAttrDump,
GenClangDiagsDefs,
@@ -48,108 +50,108 @@ enum ActionType {
GenClangCommentHTMLNamedCharacterReferences,
GenClangCommentCommandInfo,
GenClangCommentCommandList,
- GenOptParserDefs, GenOptParserImpl,
GenArmNeon,
GenArmNeonSema,
GenArmNeonTest
};
namespace {
- cl::opt<ActionType>
- Action(cl::desc("Action to perform:"),
- cl::values(clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
- "Generate option definitions"),
- clEnumValN(GenOptParserImpl, "gen-opt-parser-impl",
- "Generate option parser implementation"),
- clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
- "Generate clang attribute clases"),
- clEnumValN(GenClangAttrExprArgsList,
- "gen-clang-attr-expr-args-list",
- "Generate a clang attribute expression "
- "arguments list"),
- clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
- "Generate clang attribute implementations"),
- clEnumValN(GenClangAttrList, "gen-clang-attr-list",
- "Generate a clang attribute list"),
- clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
- "Generate clang PCH attribute reader"),
- clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
- "Generate clang PCH attribute writer"),
- clEnumValN(GenClangAttrSpellingList,
- "gen-clang-attr-spelling-list",
- "Generate a clang attribute spelling list"),
- clEnumValN(GenClangAttrSpellingListIndex,
- "gen-clang-attr-spelling-index",
- "Generate a clang attribute spelling index"),
- clEnumValN(GenClangAttrLateParsedList,
- "gen-clang-attr-late-parsed-list",
- "Generate a clang attribute LateParsed list"),
- clEnumValN(GenClangAttrTemplateInstantiate,
- "gen-clang-attr-template-instantiate",
- "Generate a clang template instantiate code"),
- clEnumValN(GenClangAttrParsedAttrList,
- "gen-clang-attr-parsed-attr-list",
- "Generate a clang parsed attribute list"),
- clEnumValN(GenClangAttrParsedAttrKinds,
- "gen-clang-attr-parsed-attr-kinds",
- "Generate a clang parsed attribute kinds"),
- clEnumValN(GenClangAttrDump, "gen-clang-attr-dump",
- "Generate clang attribute dumper"),
- clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
- "Generate Clang diagnostics definitions"),
- clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
- "Generate Clang diagnostic groups"),
- clEnumValN(GenClangDiagsIndexName,
- "gen-clang-diags-index-name",
- "Generate Clang diagnostic name index"),
- clEnumValN(GenClangCommentNodes, "gen-clang-comment-nodes",
- "Generate Clang AST comment nodes"),
- clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
- "Generate Clang AST declaration nodes"),
- clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
- "Generate Clang AST statement nodes"),
- clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
- "Generate Clang Static Analyzer checkers"),
- clEnumValN(GenClangCommentHTMLTags,
- "gen-clang-comment-html-tags",
- "Generate efficient matchers for HTML tag "
- "names that are used in documentation comments"),
- clEnumValN(GenClangCommentHTMLTagsProperties,
- "gen-clang-comment-html-tags-properties",
- "Generate efficient matchers for HTML tag "
- "properties"),
- clEnumValN(GenClangCommentHTMLNamedCharacterReferences,
- "gen-clang-comment-html-named-character-references",
- "Generate function to translate named character "
- "references to UTF-8 sequences"),
- clEnumValN(GenClangCommentCommandInfo,
- "gen-clang-comment-command-info",
- "Generate command properties for commands that "
- "are used in documentation comments"),
- clEnumValN(GenClangCommentCommandList,
- "gen-clang-comment-command-list",
- "Generate list of commands that are used in "
- "documentation comments"),
- clEnumValN(GenArmNeon, "gen-arm-neon",
- "Generate arm_neon.h for clang"),
- clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
- "Generate ARM NEON sema support for clang"),
- clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
- "Generate ARM NEON tests for clang"),
- clEnumValEnd));
+cl::opt<ActionType> Action(
+ cl::desc("Action to perform:"),
+ cl::values(
+ clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
+ "Generate clang attribute clases"),
+ clEnumValN(GenClangAttrIdentifierArgList,
+ "gen-clang-attr-identifier-arg-list",
+ "Generate a list of attributes that take an "
+ "identifier as their first argument"),
+ clEnumValN(GenClangAttrTypeArgList,
+ "gen-clang-attr-type-arg-list",
+ "Generate a list of attributes that take a type as their "
+ "first argument"),
+ clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
+ "Generate clang attribute implementations"),
+ clEnumValN(GenClangAttrList, "gen-clang-attr-list",
+ "Generate a clang attribute list"),
+ clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
+ "Generate clang PCH attribute reader"),
+ clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
+ "Generate clang PCH attribute writer"),
+ clEnumValN(GenClangAttrSpellingList, "gen-clang-attr-spelling-list",
+ "Generate a clang attribute spelling list"),
+ clEnumValN(GenClangAttrSpellingListIndex,
+ "gen-clang-attr-spelling-index",
+ "Generate a clang attribute spelling index"),
+ clEnumValN(GenClangAttrLateParsedList,
+ "gen-clang-attr-late-parsed-list",
+ "Generate a clang attribute LateParsed list"),
+ clEnumValN(GenClangAttrTemplateInstantiate,
+ "gen-clang-attr-template-instantiate",
+ "Generate a clang template instantiate code"),
+ clEnumValN(GenClangAttrParsedAttrList,
+ "gen-clang-attr-parsed-attr-list",
+ "Generate a clang parsed attribute list"),
+ clEnumValN(GenClangAttrParsedAttrImpl,
+ "gen-clang-attr-parsed-attr-impl",
+ "Generate the clang parsed attribute helpers"),
+ clEnumValN(GenClangAttrParsedAttrKinds,
+ "gen-clang-attr-parsed-attr-kinds",
+ "Generate a clang parsed attribute kinds"),
+ clEnumValN(GenClangAttrDump, "gen-clang-attr-dump",
+ "Generate clang attribute dumper"),
+ clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
+ "Generate Clang diagnostics definitions"),
+ clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
+ "Generate Clang diagnostic groups"),
+ clEnumValN(GenClangDiagsIndexName, "gen-clang-diags-index-name",
+ "Generate Clang diagnostic name index"),
+ clEnumValN(GenClangCommentNodes, "gen-clang-comment-nodes",
+ "Generate Clang AST comment nodes"),
+ clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
+ "Generate Clang AST declaration nodes"),
+ clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
+ "Generate Clang AST statement nodes"),
+ clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
+ "Generate Clang Static Analyzer checkers"),
+ clEnumValN(GenClangCommentHTMLTags, "gen-clang-comment-html-tags",
+ "Generate efficient matchers for HTML tag "
+ "names that are used in documentation comments"),
+ clEnumValN(GenClangCommentHTMLTagsProperties,
+ "gen-clang-comment-html-tags-properties",
+ "Generate efficient matchers for HTML tag "
+ "properties"),
+ clEnumValN(GenClangCommentHTMLNamedCharacterReferences,
+ "gen-clang-comment-html-named-character-references",
+ "Generate function to translate named character "
+ "references to UTF-8 sequences"),
+ clEnumValN(GenClangCommentCommandInfo, "gen-clang-comment-command-info",
+ "Generate command properties for commands that "
+ "are used in documentation comments"),
+ clEnumValN(GenClangCommentCommandList, "gen-clang-comment-command-list",
+ "Generate list of commands that are used in "
+ "documentation comments"),
+ clEnumValN(GenArmNeon, "gen-arm-neon", "Generate arm_neon.h for clang"),
+ clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
+ "Generate ARM NEON sema support for clang"),
+ clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
+ "Generate ARM NEON tests for clang"),
+ clEnumValEnd));
- cl::opt<std::string>
- ClangComponent("clang-component",
- cl::desc("Only use warnings from specified component"),
- cl::value_desc("component"), cl::Hidden);
+cl::opt<std::string>
+ClangComponent("clang-component",
+ cl::desc("Only use warnings from specified component"),
+ cl::value_desc("component"), cl::Hidden);
bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
switch (Action) {
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
- case GenClangAttrExprArgsList:
- EmitClangAttrExprArgsList(Records, OS);
+ case GenClangAttrIdentifierArgList:
+ EmitClangAttrIdentifierArgList(Records, OS);
+ break;
+ case GenClangAttrTypeArgList:
+ EmitClangAttrTypeArgList(Records, OS);
break;
case GenClangAttrImpl:
EmitClangAttrImpl(Records, OS);
@@ -178,6 +180,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrParsedAttrList:
EmitClangAttrParsedAttrList(Records, OS);
break;
+ case GenClangAttrParsedAttrImpl:
+ EmitClangAttrParsedAttrImpl(Records, OS);
+ break;
case GenClangAttrParsedAttrKinds:
EmitClangAttrParsedAttrKinds(Records, OS);
break;
@@ -221,12 +226,6 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangCommentCommandList:
EmitClangCommentCommandList(Records, OS);
break;
- case GenOptParserDefs:
- EmitOptParser(Records, OS, true);
- break;
- case GenOptParserImpl:
- EmitOptParser(Records, OS, false);
- break;
case GenArmNeon:
EmitNeon(Records, OS);
break;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 0ff33d775cc0..890428706061 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -30,7 +30,8 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
const std::string &N, const std::string &S);
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
-void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
@@ -40,6 +41,7 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS);
@@ -61,6 +63,4 @@ void EmitNeon(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS);
-void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs);
-
} // end namespace clang
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index e119155a9b46..51bc6e259378 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -208,10 +208,14 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " "
SBOptions += "--keep-empty "
+ # Always use ccc-analyze to ensure that we can locate the failures
+ # directory.
+ SBOptions += "--override-compiler "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
for Command in SBCommandFile:
+ Command = Command.strip()
# If using 'make', auto imply a -jX argument
# to speed up analysis. xcodebuild will
# automatically use the maximum number of cores.
@@ -410,8 +414,10 @@ def runCmpResults(Dir):
RefList = glob.glob(RefDir + "/*")
NewList = glob.glob(NewDir + "/*")
- # Log folders are also located in the results dir, so ignore them.
- RefList.remove(os.path.join(RefDir, LogFolderName))
+ # Log folders are also located in the results dir, so ignore them.
+ RefLogDir = os.path.join(RefDir, LogFolderName)
+ if RefLogDir in RefList:
+ RefList.remove(RefLogDir)
NewList.remove(os.path.join(NewDir, LogFolderName))
if len(RefList) == 0 or len(NewList) == 0:
diff --git a/utils/find-unused-diagnostics.sh b/utils/find-unused-diagnostics.sh
index c7fa01a9352b..cd48e6920fb8 100644
--- a/utils/find-unused-diagnostics.sh
+++ b/utils/find-unused-diagnostics.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# This script produces a list of all diagnostics that are defined
# in Diagnostic*.td files but not used in sources.
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
index a82495303124..2216176a1308 100644
--- a/www/analyzer/checker_dev_manual.html
+++ b/www/analyzer/checker_dev_manual.html
@@ -14,7 +14,7 @@
<div id="content">
-<h1 style="color:red">This Page Is Under Construction</h1>
+<h3 style="color:red">This Page Is Under Construction</h3>
<h1>Checker Developer Manual</h1>
@@ -33,15 +33,20 @@ for developer guidelines and send your questions and proposals to
<ul>
<li><a href="#start">Getting Started</a></li>
- <li><a href="#analyzer">Analyzer Overview</a></li>
+ <li><a href="#analyzer">Static Analyzer Overview</a>
+ <ul>
+ <li><a href="#interaction">Interaction with Checkers</a></li>
+ <li><a href="#values">Representing Values</a></li>
+ </ul></li>
<li><a href="#idea">Idea for a Checker</a></li>
<li><a href="#registration">Checker Registration</a></li>
- <li><a href="#skeleton">Checker Skeleton</a></li>
- <li><a href="#node">Exploded Node</a></li>
+ <li><a href="#events_callbacks">Events, Callbacks, and Checker Class Structure</a></li>
+ <li><a href="#extendingstates">Custom Program States</a></li>
<li><a href="#bugs">Bug Reports</a></li>
<li><a href="#ast">AST Visitors</a></li>
<li><a href="#testing">Testing</a></li>
- <li><a href="#commands">Useful Commands</a></li>
+ <li><a href="#commands">Useful Commands/Debugging Hints</a></li>
+ <li><a href="#additioninformation">Additional Sources of Information</a></li>
</ul>
<h2 id=start>Getting Started</h2>
@@ -108,7 +113,7 @@ for developer guidelines and send your questions and proposals to
<li><tt>GenericDataMap</tt> - constraints on symbolic values
</ul>
- <h3>Interaction with Checkers</h3>
+ <h3 id=interaction>Interaction with Checkers</h3>
Checkers are not merely passive receivers of the analyzer core changes - they
actively participate in the <tt>ProgramState</tt> construction through the
<tt>GenericDataMap</tt> which can be used to store the checker-defined part
@@ -119,7 +124,7 @@ for developer guidelines and send your questions and proposals to
in the predefined order; thus, calling all the checkers adds a chain to the
<tt>ExplodedGraph</tt>.
- <h3>Representing Values</h3>
+ <h3 id=values>Representing Values</h3>
During symbolic execution, <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SVal.html">SVal</a>
objects are used to represent the semantic evaluation of expressions.
They can represent things like concrete
@@ -132,7 +137,7 @@ for developer guidelines and send your questions and proposals to
number. In some cases, <tt>SVal</tt> is not a symbol, but it really should be
a symbolic value. This happens when the analyzer cannot reason about something
(yet). An example is floating point numbers. In such cases, the
- <tt>SVal</tt> will evaluate to <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1UnknownVal.html">UnknownVal<a>.
+ <tt>SVal</tt> will evaluate to <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1UnknownVal.html">UnknownVal</a>.
This represents a case that is outside the realm of the analyzer's reasoning
capabilities. <tt>SVals</tt> are value objects and their values can be viewed
using the <tt>.dump()</tt> method. Often they wrap persistent objects such as
@@ -201,6 +206,7 @@ values (e.g., the number 1).
Symbols<br>
FunctionalObjects are used throughout.
-->
+
<h2 id=idea>Idea for a Checker</h2>
Here are several questions which you should consider when evaluating your
checker idea:
@@ -223,61 +229,274 @@ values (e.g., the number 1).
bugs in the existing checkers.</li>
</ul>
+<p>Once an idea for a checker has been chosen, there are two key decisions that
+need to be made:
+ <ul>
+ <li> Which events the checker should be tracking. This is discussed in more
+ detail in the section <a href="#events_callbacks">Events, Callbacks, and
+ Checker Class Structure</a>.
+ <li> What checker-specific data needs to be stored as part of the program
+ state (if any). This should be minimized as much as possible. More detail about
+ implementing custom program state is given in section <a
+ href="#extendingstates">Custom Program States</a>.
+ </ul>
+
+
<h2 id=registration>Checker Registration</h2>
- All checker implementation files are located in <tt>clang/lib/StaticAnalyzer/Checkers</tt>
- folder. Follow the steps below to register a new checker with the analyzer.
+ All checker implementation files are located in
+ <tt>clang/lib/StaticAnalyzer/Checkers</tt> folder. The steps below describe
+ how the checker <tt>SimpleStreamChecker</tt>, which checks for misuses of
+ stream APIs, was registered with the analyzer.
+ Similar steps should be followed for a new checker.
<ol>
- <li>Create a new checker implementation file, for example <tt>./lib/StaticAnalyzer/Checkers/NewChecker.cpp</tt>
+ <li>A new checker implementation file, <tt>SimpleStreamChecker.cpp</tt>, was
+ created in the directory <tt>lib/StaticAnalyzer/Checkers</tt>.
+ <li>The following registration code was added to the implementation file:
<pre class="code_example">
-using namespace clang;
-using namespace ento;
+void ento::registerSimpleStreamChecker(CheckerManager &amp;mgr) {
+ mgr.registerChecker&lt;SimpleStreamChecker&gt();
+}
+</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
+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">
+let ParentPackage = UnixAlpha in {
+...
+def SimpleStreamChecker : Checker<"SimpleStream">,
+ HelpText<"Check for misuses of stream APIs">,
+ DescFile<"SimpleStreamChecker.cpp">;
+...
+} // end "alpha.unix"
+</pre>
+
+<li>The source code file was made visible to CMake by adding it to
+<tt>lib/StaticAnalyzer/Checkers/CMakeLists.txt</tt>.
+
+</ol>
+
+After adding a new checker to the analyzer, one can verify that the new checker
+was successfully added by seeing if it appears in the list of available checkers:
+<br> <tt><b>$clang -cc1 -analyzer-checker-help</b></tt>
+
+<h2 id=events_callbacks>Events, Callbacks, and Checker Class Structure</h2>
+
+<p> All checkers inherit from the <tt><a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1Checker.html">
+Checker</a></tt> template class; the template parameter(s) describe the type of
+events that the checker is interested in processing. The various types of events
+that are available are described in the file <a
+href="http://clang.llvm.org/doxygen/CheckerDocumentation_8cpp_source.html">
+CheckerDocumentation.cpp</a>
-namespace {
-class NewChecker: public Checker< check::PreStmt&lt;CallExpr> > {
+<p> For each event type requested, a corresponding callback function must be
+defined in the checker class (<a
+href="http://clang.llvm.org/doxygen/CheckerDocumentation_8cpp_source.html">
+CheckerDocumentation.cpp</a> shows the
+correct function name and signature for each event type).
+
+<p> As an example, consider <tt>SimpleStreamChecker</tt>. This checker needs to
+take action at the following times:
+
+<ul>
+<li>Before making a call to a function, check if the function is <tt>fclose</tt>.
+If so, check the parameter being passed.
+<li>After making a function call, check if the function is <tt>fopen</tt>. If
+so, process the return value.
+<li>When values go out of scope, check whether they are still-open file
+descriptors, and report a bug if so. In addition, remove any information about
+them from the program state in order to keep the state as small as possible.
+<li>When file pointers "escape" (are used in a way that the analyzer can no longer
+track them), mark them as such. This prevents false positives in the cases where
+the analyzer cannot be sure whether the file was closed or not.
+</ul>
+
+<p>These events that will be used for each of these actions are, respectively, <a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1check_1_1PreCall.html">PreCall</a>,
+<a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1check_1_1PostCall.html">PostCall</a>,
+<a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1check_1_1DeadSymbols.html">DeadSymbols</a>,
+and <a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1check_1_1PointerEscape.html">PointerEscape</a>.
+The high-level structure of the checker's class is thus:
+
+<pre class="code_example">
+class SimpleStreamChecker : public Checker&lt;check::PreCall,
+ check::PostCall,
+ check::DeadSymbols,
+ check::PointerEscape&gt; {
public:
- void checkPreStmt(const CallExpr *CE, CheckerContext &amp;Ctx) const {}
-}
-}
-void ento::registerNewChecker(CheckerManager &amp;mgr) {
- mgr.registerChecker&lt;NewChecker>();
-}
+
+ void checkPreCall(const CallEvent &amp;Call, CheckerContext &amp;C) const;
+
+ void checkPostCall(const CallEvent &amp;Call, CheckerContext &amp;C) const;
+
+ void checkDeadSymbols(SymbolReaper &amp;SR, CheckerContext &amp;C) const;
+
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &amp;Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
+};
+</pre>
+
+<h2 id=extendingstates>Custom Program States</h2>
+
+<p> Checkers often need to keep track of information specific to the checks they
+perform. However, since checkers have no guarantee about the order in which the
+program will be explored, or even that all possible paths will be explored, this
+state information cannot be kept within individual checkers. Therefore, if
+checkers need to store custom information, they need to add new categories of
+data to the <tt>ProgramState</tt>. The preferred way to do so is to use one of
+several macros designed for this purpose. They are:
+
+<ul>
+<li><a
+href="http://clang.llvm.org/doxygen/ProgramStateTrait_8h.html#ae4cddb54383cd702a045d7c61b009147">REGISTER_TRAIT_WITH_PROGRAMSTATE</a>:
+Used when the state information is a single value. The methods available for
+state types declared with this macro are <tt>get</tt>, <tt>set</tt>, and
+<tt>remove</tt>.
+<li><a
+href="http://clang.llvm.org/doxygen/CheckerContext_8h.html#aa27656fa0ce65b0d9ba12eb3c02e8be9">REGISTER_LIST_WITH_PROGRAMSTATE</a>:
+Used when the state information is a list of values. The methods available for
+state types declared with this macro are <tt>add</tt>, <tt>get</tt>,
+<tt>remove</tt>, and <tt>contains</tt>.
+<li><a
+href="http://clang.llvm.org/doxygen/CheckerContext_8h.html#ad90f9387b94b344eaaf499afec05f4d1">REGISTER_SET_WITH_PROGRAMSTATE</a>:
+Used when the state information is a set of values. The methods available for
+state types declared with this macro are <tt>add</tt>, <tt>get</tt>,
+<tt>remove</tt>, and <tt>contains</tt>.
+<li><a
+href="http://clang.llvm.org/doxygen/CheckerContext_8h.html#a6d1893bb8c18543337b6c363c1319fcf">REGISTER_MAP_WITH_PROGRAMSTATE</a>:
+Used when the state information is a map from a key to a value. The methods
+available for state types declared with this macro are <tt>add</tt>,
+<tt>set</tt>, <tt>get</tt>, <tt>remove</tt>, and <tt>contains</tt>.
+</ul>
+
+<p>All of these macros take as parameters the name to be used for the custom
+category of state information and the data type(s) to be used for storage. The
+data type(s) specified will become the parameter type and/or return type of the
+methods that manipulate the new category of state information. Each of these
+methods are templated with the name of the custom data type.
+
+<p>For example, a common case is the need to track data associated with a
+symbolic expression; a map type is the most logical way to implement this. The
+key for this map will be a pointer to a symbolic expression
+(<tt>SymbolRef</tt>). If the data type to be associated with the symbolic
+expression is an integer, then the custom category of state information would be
+declared as
+
+<pre class="code_example">
+REGISTER_MAP_WITH_PROGRAMSTATE(ExampleDataType, SymbolRef, int)
</pre>
-<li>Pick the package name for your checker and add the registration code to
-<tt>./lib/StaticAnalyzer/Checkers/Checkers.td</tt>. Note, all checkers should
-first be developed as experimental. Suppose our new checker performs security
-related checks, then we should add the following lines under
-<tt>SecurityExperimental</tt> package:
+The data would be accessed with the function
+
<pre class="code_example">
-let ParentPackage = SecurityExperimental in {
+ProgramStateRef state;
+SymbolRef Sym;
...
-def NewChecker : Checker<"NewChecker">,
- HelpText<"This text should give a short description of the checks performed.">,
- DescFile<"NewChecker.cpp">;
+int currentlValue = state-&gt;get&lt;ExampleDataType&gt;(Sym);
+</pre>
+
+and set with the function
+
+<pre class="code_example">
+ProgramStateRef state;
+SymbolRef Sym;
+int newValue;
...
-} // end "security.experimental"
+ProgramStateRef newState = state-&gt;set&lt;ExampleDataType&gt;(Sym, newValue);
</pre>
-<li>Make the source code file visible to CMake by adding it to
-<tt>./lib/StaticAnalyzer/Checkers/CMakeLists.txt</tt>.
+<p>In addition, the macros define a data type used for storing the data of the
+new data category; the name of this type is the name of the data category with
+"Ty" appended. For <tt>REGISTER_TRAIT_WITH_PROGRAMSTATE</tt>, this will simply
+be passed data type; for the other three macros, this will be a specialized
+version of the <a
+href="http://llvm.org/doxygen/classllvm_1_1ImmutableList.html">llvm::ImmutableList</a>,
+<a
+href="http://llvm.org/doxygen/classllvm_1_1ImmutableSet.html">llvm::ImmutableSet</a>,
+or <a
+href="http://llvm.org/doxygen/classllvm_1_1ImmutableMap.html">llvm::ImmutableMap</a>
+templated class. For the <tt>ExampleDataType</tt> example above, the type
+created would be equivalent to writing the declaration:
-<li>Compile and see your checker in the list of available checkers by running:<br>
-<tt><b>$clang -cc1 -analyzer-checker-help</b></tt>
-</ol>
-
+<pre class="code_example">
+typedef llvm::ImmutableMap&lt;SymbolRef, int&gt; ExampleDataTypeTy;
+</pre>
-<h2 id=skeleton>Checker Skeleton</h2>
- There are two main decisions you need to make:
- <ul>
- <li> Which events the checker should be tracking.
- See <a href="http://clang.llvm.org/doxygen/classento_1_1CheckerDocumentation.html">CheckerDocumentation</a>
- for the list of available checker callbacks.</li>
- <li> What data you want to store as part of the checker-specific program
- state. Try to minimize the checker state as much as possible. </li>
- </ul>
+<p>These macros will cover a majority of use cases; however, they still have a
+few limitations. They cannot be used inside namespaces (since they expand to
+contain top-level namespace references), and the data types that they define
+cannot be referenced from more than one file.
+<p>Note that <tt>ProgramStates</tt> are immutable; instead of modifying an existing
+one, functions that modify the state will return a copy of the previous state
+with the change applied. This updated state must be then provided to the
+analyzer core by calling the <tt>CheckerContext::addTransition</tt> function.
<h2 id=bugs>Bug Reports</h2>
+
+<p> When a checker detects a mistake in the analyzed code, it needs a way to
+report it to the analyzer core so that it can be displayed. The two classes used
+to construct this report are <tt><a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1BugType.html">BugType</a></tt>
+and <tt><a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1BugReport.html">
+BugReport</a></tt>.
+
+<p>
+<tt>BugType</tt>, as the name would suggest, represents a type of bug. The
+constructor for <tt>BugType</tt> takes two parameters: The name of the bug
+type, and the name of the category of the bug. These are used (e.g.) in the
+summary page generated by the scan-build tool.
+
+<P>
+ The <tt>BugReport</tt> class represents a specific occurrence of a bug. In
+ the most common case, three parameters are used to form a <tt>BugReport</tt>:
+<ol>
+<li>The type of bug, specified as an instance of the <tt>BugType</tt> class.
+<li>A short descriptive string. This is placed at the location of the bug in
+the detailed line-by-line output generated by scan-build.
+<li>The context in which the bug occurred. This includes both the location of
+the bug in the program and the program's state when the location is reached. These are
+both encapsulated in an <tt>ExplodedNode</tt>.
+</ol>
+
+<p>In order to obtain the correct <tt>ExplodedNode</tt>, a decision must be made
+as to whether or not analysis can continue along the current path. This decision
+is based on whether the detected bug is one that would prevent the program under
+analysis from continuing. For example, leaking of a resource should not stop
+analysis, as the program can continue to run after the leak. Dereferencing a
+null pointer, on the other hand, should stop analysis, as there is no way for
+the program to meaningfully continue after such an error.
+
+<p>If analysis can continue, then the most recent <tt>ExplodedNode</tt>
+generated by the checker can be passed to the <tt>BugReport</tt> constructor
+without additional modification. This <tt>ExplodedNode</tt> will be the one
+returned by the most recent call to <a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1CheckerContext.html#a264f48d97809707049689c37aa35af78">CheckerContext::addTransition</a>.
+If no transition has been performed during the current callback, the checker should call <a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1CheckerContext.html#a264f48d97809707049689c37aa35af78">CheckerContext::addTransition()</a>
+and use the returned node for bug reporting.
+
+<p>If analysis can not continue, then the current state should be transitioned
+into a so-called <i>sink node</i>, a node from which no further analysis will be
+performed. This is done by calling the <a
+href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1CheckerContext.html#adeea33a5a2bed190210c4a2bb807a6f0">
+CheckerContext::generateSink</a> function; this function is the same as the
+<tt>addTransition</tt> function, but marks the state as a sink node. Like
+<tt>addTransition</tt>, this returns an <tt>ExplodedNode</tt> with the updated
+state, which can then be passed to the <tt>BugReport</tt> constructor.
+
+<p>
+After a <tt>BugReport</tt> is created, it should be passed to the analyzer core
+by calling <a href = "http://clang.llvm.org/doxygen/classclang_1_1ento_1_1CheckerContext.html#ae7738af2cbfd1d713edec33d3203dff5">CheckerContext::emitReport</a>.
+
<h2 id=ast>AST Visitors</h2>
Some checks might not require path-sensitivity to be effective. Simple AST walk
might be sufficient. If that is the case, consider implementing a Clang
@@ -361,6 +580,31 @@ To dump AST of a method that the current <tt>ExplodedNode</tt> belongs to:
</li>
</ul>
+<h2 id=additioninformation>Additional Sources of Information</h2>
+
+Here are some additional resources that are useful when working on the Clang
+Static Analyzer:
+
+<ul>
+<li> <a href="http://clang.llvm.org/doxygen">Clang doxygen</a>. Contains
+up-to-date documentation about the APIs available in Clang. Relevant entries
+have been linked throughout this page. Also of use is the
+<a href="http://llvm.org/doxygen">LLVM doxygen</a>, when dealing with classes
+from LLVM.
+<li> The <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">
+cfe-dev mailing list</a>. This is the primary mailing list used for
+discussion of Clang development (including static code analysis). The
+<a href="http://lists.cs.uiuc.edu/pipermail/cfe-dev">archive</a> also contains
+a lot of information.
+<li> The "Building a Checker in 24 hours" presentation given at the <a
+href="http://llvm.org/devmtg/2012-11">November 2012 LLVM Developer's
+meeting</a>. Describes the construction of SimpleStreamChecker. <a
+href="http://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf">Slides</a>
+and <a
+href="http://llvm.org/devmtg/2012-11/videos/Zaks-Rose-Checker24Hours.mp4">video</a>
+are available.
+</ul>
+
</div>
</div>
</body>
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index 6f68fdb7d527..929d5200a3e7 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -54,7 +54,9 @@ table.options thead {
text-align:left;
border-top: 2px solid #cccccc;
border-bottom: 2px solid #cccccc;
- font-weight: bold; font-family: Verdana
+ font-weight: bold; font-family: Verdana;
+ table-layout: fixed;
+ width: 100%
}
table.options { border: 1px #cccccc solid }
table.options { border-collapse: collapse; border-spacing: 0px }
@@ -62,6 +64,7 @@ table.options { margin-left:0px; margin-top:20px; margin-bottom:20px }
table.options td { border-bottom: 1px #cccccc dotted }
table.options td { padding:5px; padding-left:8px; padding-right:8px }
table.options td { text-align:left; font-size:9pt }
+table.options col.option { width:207px }
table.checkers {
border: 1px #cccccc solid;
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 233a104cf123..5062622c8c91 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="https://attache.apple.com/AttacheWeb/dl?id=ATCdb3165f4406a4589b5878a22494c3b79">checker-274.tar.bz2</a></b> (built April 23, 2013)
+<b><a href="downloads/checker-275.tar.bz2">checker-275.tar.bz2</a></b> (built May 23, 2013)
diff --git a/www/analyzer/open_projects.html b/www/analyzer/open_projects.html
index c015b4866536..4a888adbb68c 100644
--- a/www/analyzer/open_projects.html
+++ b/www/analyzer/open_projects.html
@@ -31,7 +31,17 @@ mailing list</a> to notify other members of the community.</p>
not available during analysis. Modeling more of the widely used functions
(such as the members of <tt>std::string</tt>) will improve precision of the
analysis.
- <i>(Difficulty: Easy)</i><p>
+ <i>(Difficulty: Easy, ongoing)</i><p>
+ </li>
+
+ <li>Handle floating-point values.
+ <p>Currently, the analyzer treats all floating-point values as unknown.
+ However, we already have most of the infrastructure we need to handle
+ floats: RangeConstraintManager. This would involve adding a new SVal kind
+ for constant floats, generalizing the constraint manager to handle floats
+ and integers equally, and auditing existing code to make sure it doesn't
+ make untoward assumptions.
+ <i> (Difficulty: Medium)</i></p>
</li>
<li>Implement generalized loop execution modeling.
@@ -159,6 +169,11 @@ mailing list</a> to notify other members of the community.</p>
<i>(Difficulty: Easy)</i></p>
</li>
+ <li>Implement a BitwiseMaskingChecker to handle <a href="http://llvm.org/bugs/show_bug.cgi?id=16615">PR16615</a>.
+ <p>Symbolic expressions of the form <code>$sym &amp; CONSTANT</code> can range from 0 to <code>CONSTANT-</code>1 if CONSTANT is <code>2^n-1</code>, e.g. 0xFF (0b11111111), 0x7F (0b01111111), 0x3 (0b0011), 0xFFFF, etc. Even without handling general bitwise operations on symbols, we can at least bound the value of the resulting expression. Bonus points for handling masks followed by shifts, e.g. <code>($sym &amp; 0b1100) >> 2</code>.
+ <i>(Difficulty: Easy)</i></p>
+ </li>
+
<li>Implement iterators invalidation checker.
<p><i>(Difficulty: Easy)</i></p>
</li>
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
index c769541e70d8..ab8917c7cb46 100644
--- a/www/analyzer/potential_checkers.html
+++ b/www/analyzer/potential_checkers.html
@@ -183,6 +183,46 @@ void test(A *dst, A *src) {
</table>
+<!-- =============================== va_list =============================== -->
+<h3>va_list</h3>
+<table class="checkers">
+<col class="namedescr"><col class="example"><col class="progress">
+<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead>
+
+<tr><td><span class="name">valist.Uninitialized</span><br><br>
+Calls to the <code>va_arg</code>, <code>va_copy</code>, or
+<code>va_end</code> macro must happen after calling <code>va_start</code> and
+before calling <code>va_end</code>.
+</td><td><pre>
+#include &lt;stdarg.h&gt;
+
+void test(int x, ...) {
+ va_list args;
+ int y = va_arg(args, int); // warn
+ va_start(args, x);
+ va_end(args, x);
+ int z = va_arg(args, int); // warn
+}
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=16812">PR16811</a></td></tr>
+
+<tr><td><span class="name">valist.Unterminated</span><br><br>
+Every <code>va_start</code> must be matched by a <code>va_end</code>. A va_list
+can only be ended once.
+
+<i>This should be folded into the generalized "ownership checker" described on the <a href="open_projects.html">Open Projects</a> page.</i>
+</td><td><pre>
+#include &lt;stdarg.h&gt;
+
+void test(int x, ...) {
+ va_list args;
+ va_start(args, x);
+ int y = x + va_arg(args, int);
+ // missing va_end
+}
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=16812">PR16812</a></td></tr>
+
+</table>
+
<!-- ============================== exceptions ============================= -->
<h3>exceptions</h3>
<table class="checkers">
@@ -248,6 +288,32 @@ void test() {
</table>
+<!-- ============================== dead code ============================== -->
+<h3>dead code</h3>
+<table class="checkers">
+<col class="namedescr"><col class="example"><col class="progress">
+<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead>
+
+<tr><td><span class="name">deadcode.UnmodifiedVariable
+<br>(C, C++)</span><br><br>
+A variable is never modified but was not declared const and is not a reference.
+<br><br>
+<i>(opt-in checker)</i>
+</td><td><pre>
+extern int computeDelta();
+
+int foo(bool cond) {
+ int i = 0;
+ if (cond) {
+ const int delta = computeDelta();
+ // Forgot to modify 'i'.
+ }
+ return i;
+}
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=16890">PR16890</a></td></tr>
+
+</table>
+
<!-- ========================= undefined behavior ========================== -->
<h3>undefined behavior</h3>
<table class="checkers">
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 2d1660dcb52e..bc052bbec0af 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,18 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_275">checker-275</h4>
+<p><b>built:</b> May 23, 2013</br>
+ <b>download:</b> <a href="downloads/checker-275.tar.bz2">checker-275.tar.bz2</a></p>
+ <p><b>highlights:</b></p>
+ <ul>
+ <li>Xcode: Includes a new arrow layout algorithm for issue presentation within Xcode. The goal is for interprocedural bug reports to look cleaner and less busy (and easier to read). Feedback appreciated.</li>
+ <li>Xcode: Bugs that occur within header code (e.g., C++) are now reported within the callers in the main source file. For example, if you misuse a C++ function declared in a header the primary diagnostic will be in the caller (in the main source file). The full expanded path, however, will show the bug in the header code as well. These kind of cross-file issues are currently only support by Xcode, not the HTML output.</li>
+ <li>This build is built with LLVM's Link-Time Optimization (LTO), which should make it slightly faster.</li>
+ <li>LTO also reduces the download size (about 19% smaller than checker-274).</li>
+ <li>Many sundry fixes.</li>
+ </ul>
+
<h4 id="checker_274">checker-274</h4>
<p><b>built:</b> April 23, 2013</br>
<b>download:</b> <a href="https://attache.apple.com/AttacheWeb/dl?id=ATCdb3165f4406a4589b5878a22494c3b79">checker-274.tar.bz2</a></p>
@@ -40,8 +52,7 @@
</ul>
<h4 id="checker_272">checker-272</h4>
-<p><b>built:</b> March 1, 2013</br>
- <b>download:</b> <a href="https://attache.apple.com/AttacheWeb/dl?id=ATCbb91eedf8edf4c7388549be8f91e810d">checker-272.tar.bz2</a></p>
+<p><b>built:</b> March 1, 2013</p>
<p><b>highlights:</b></p>
<ul>
<li>Better modeling of C++ constructors:
@@ -56,8 +67,7 @@
</ul>
<h4 id="checker_271">checker-271</h4>
-<p><b>built:</b> February 8, 2013</br>
- <b>download:</b> <a href="http://bit.ly/1299Xt3">checker-271.tar.bz2</a></p>
+<p><b>built:</b> February 8, 2013</p>
<p><b>highlights:</b></p>
<ul>
<li>Faster analysis for <tt>scan-build xcodebuild</tt> when using Xcode 4.6 and higher:
@@ -72,8 +82,7 @@
</ul>
<h4 id="checker_270">checker-270</h4>
-<p><b>built:</b> January 4, 2013</br>
- <b>download:</b> <a href="http://bit.ly/13ekSoV">checker-270.tar.bz2</a></p>
+<p><b>built:</b> January 4, 2013</p>
<p><b>highlights:</b></p>
<ul>
<li>Major performance enhancements to speed up interprocedural analysis.</li>
@@ -81,8 +90,7 @@
</ul>
<h4 id="checker_269">checker-269</h4>
-<p><b>built:</b> September 25, 2012</br>
- <b>download:</b> <a href="http://bit.ly/USf8ge">checker-269.tar.bz2</a></p>
+<p><b>built:</b> September 25, 2012</p>
<p><b>highlights:</b></p>
<ul>
<li>Significantly improves interprocedural analysis for Objective-C.</li>
@@ -91,8 +99,7 @@
</ul>
<h4 id="checker_268">checker-268</h4>
-<p><b>built:</b> September 11, 2012</br>
- <b>download:</b> <a href="http://bit.ly/U75NOp">checker-268.tar.bz2</a></p>
+<p><b>built:</b> September 11, 2012</p>
<p><b>highlights:</b></p>
<ul>
@@ -104,22 +111,19 @@
these, and any other problems you encounter. When you encounter an issue, please <a href="/filing_bugs.html">file a bug report</a>.</p>
<h4 id="checker_267">checker-267</h4>
-<p><b>built:</b> June 1, 2012</br>
- <b>download:</b> <a href="http://bit.ly/OIdyI7">checker-267.tar.bz2</a></p>
+<p><b>built:</b> June 1, 2012</p>
<p><b>highlights:</b></p>
<p>Adds basic interprocedural analysis support for blocks.</p>
<h4 id="checker_266">checker-266</h4>
-<p><b>built:</b> May 23, 2012</br>
- <b>download:</b> <a href="http://bit.ly/LgtUWx">checker-266.tar.bz2</a></p>
+<p><b>built:</b> May 23, 2012</p>
<p><b>highlights:</b></p>
<p>Contains numerous stability fixes over checker-266, especially when analyzing C++11 code.</p>
<h4 id="checker_265">checker-265</h4>
-<p><b>built:</b> May 8, 2012</br>
- <b>download:</b> <a href="http://bit.ly/JceZBE">checker-265.tar.bz2</a></p>
+<p><b>built:</b> May 8, 2012</p>
<p><b>highlights:</b></p>
<p>This release contains a fix for a major crasher introduced in checker-264, and various refinements to
@@ -129,8 +133,7 @@ of sizeof expressions contained within its argument(s).</p>
<h4 id="checker_264">checker-264</h4>
-<p><b>built:</b> April 26, 2012</br>
- <b>download:</b> <a href="http://bit.ly/JATSI8">checker-264.tar.bz2</a></p>
+<p><b>built:</b> April 26, 2012</p>
<p><b>highlights:</b></p>
<p>This release contains misc. bug fixes and performance enhancements over checker-263, including
@@ -138,7 +141,7 @@ of sizeof expressions contained within its argument(s).</p>
<h4 id="checker_263">checker-263</h4>
-<p><b>built:</b> March 22, 2012</br>
+<p><b>built:</b> March 22, 2012</p>
<p><b>highlights:</b></p>
<ul>
@@ -147,7 +150,7 @@ of sizeof expressions contained within its argument(s).</p>
<h4 id="checker_262">checker-262</h4>
-<p><b>built: </b>March 15, 2012</br>
+<p><b>built: </b>March 15, 2012</p>
<p><b>highlights:</b></p>
<ul>
diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html
index 710fa0f4958f..9c4070b060d8 100644
--- a/www/analyzer/scan-build.html
+++ b/www/analyzer/scan-build.html
@@ -57,6 +57,7 @@ aforementioned hack fails to work.</p>
<li><a href="#scanbuild">Getting Started</a>
<ul>
<li><a href="#scanbuild_basicusage">Basic Usage</a></li>
+ <li><a href="#scanbuild_forwindowsusers">For Windows Users</a></li>
<li><a href="#scanbuild_otheroptions">Other Options</a></li>
<li><a href="#scanbuild_output">Output of scan-build</a></li>
</ul>
@@ -122,6 +123,14 @@ files:</p>
<p>This example causes the files <tt>t1.c</tt> and <tt>t2.c</tt> to be analyzed.
</p>
+<h3 id="scanbuild_forwindowsusers">For Windows Users</h3>
+
+<p>Windows users must have Perl installed to use scan-build. Currently scan-build
+is known to work with the msys perl port.</p>
+
+<p>scan-build.bat script allows you to launch scan-build in the same way as it described in the Basic Usage section above.
+All you need to be able to invoke scan-build from an arbitrary location is to add the path to scan-build to your PATH environment variable.</p>
+
<h3 id="scanbuild_otheroptions">Other Options</h3>
<p>As mentioned above, extra options can be passed to <tt>scan-build</tt>. These
@@ -135,6 +144,7 @@ options prefix the build command. For example:</p>
<p>Here is a subset of useful options:</p>
<table class="options">
+<colgroup><col class="option"><col class="description"></colgroup>
<thead><tr><td>Option</td><td>Description</td></tr></thead>
<tr><td><b>-o</b></td><td>Target directory for HTML report files. Subdirectories
@@ -155,7 +165,13 @@ second and third "-v" increases verbosity</b>, and is useful for filing bug
reports against the analyzer.</td></tr>
<tr><td><b>-V</b></td><td>View analysis results in a web browser when the build
-command completes.</td></tr> </table>
+command completes.</td></tr>
+
+<tr><td><b>--use-analyzer Xcode</b><br><i>or</i><br>
+<b>--use-analyzer [path to clang]</b></td><td><tt>scan-build</tt> uses the
+'clang' executable relative to itself for static analysis. One can override this
+behavior with this option by using the 'clang' packaged with Xcode (on OS X) or
+from the PATH.</p></td></tr> </table>
<p>A complete list of options can be obtained by running <tt>scan-build</tt>
with no arguments.</p>
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
new file mode 100644
index 000000000000..b38cc3a71693
--- /dev/null
+++ b/www/cxx_dr_status.html
@@ -0,0 +1,10593 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Clang - C++ Defect Report Status</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <style type="text/css">
+ .none { background-color: #FFCCCC }
+ .partial { background-color: #FFE0B0 }
+ .svn { background-color: #FFFF99 }
+ .full { background-color: #CCFF99 }
+ .na { background-color: #DDDDDD }
+ .open * { color: #AAAAAA }
+ //.open { filter: opacity(0.2) }
+ span:target { background-color: #FFFFBB; outline: #DDDD55 solid thin; }
+ th { background-color: #FFDDAA }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>C++ Defect Report Support in Clang</h1>
+<!--*************************************************************************-->
+<p>Last updated: $Date: 2013-12-03 08:40:27 +0100 (Tue, 03 Dec 2013) $</p>
+
+<h2 id="cxxdr">C++ defect report implementation status</h2>
+
+<p>This page tracks which C++ defect reports are implemented within Clang.</p>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Number</th>
+ <th>Status</th>
+ <th>Issue title</th>
+ <th>Available in Clang?</th>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1">1</a></td>
+ <td>TC1</td>
+ <td>What if two using-declarations refer to the same function but the declarations introduce different default-arguments?</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2">2</a></td>
+ <td>drafting</td>
+ <td>How can dependent names be used in member declarations that appear outside of the class template definition?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#3">3</a></td>
+ <td>NAD</td>
+ <td>The template compilation model rules render some explicit specialization declarations not visible during instantiation</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#4">4</a></td>
+ <td>CD1</td>
+ <td>Does extern "C" affect the linkage of function names with internal linkage?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#5">5</a></td>
+ <td>CD1</td>
+ <td>CV-qualifiers and type conversions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#6">6</a></td>
+ <td>open</td>
+ <td>Should the optimization that allows a class object to alias another object also allow the case of a parameter in an inline function to alias its argument?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#7">7</a></td>
+ <td>NAD</td>
+ <td>Can a class with a private virtual base class be derived from?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#8">8</a></td>
+ <td>CD1</td>
+ <td>Access to template arguments used in a function return type and in the nested name specifier</td>
+ <td class="full" align="center">Duplicate of 45</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#9">9</a></td>
+ <td>CD1</td>
+ <td>Clarification of access to base class members</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#10">10</a></td>
+ <td>CD1</td>
+ <td>Can a nested class access its own class name as a qualified name if it is a private member of the enclosing class?</td>
+ <td class="full" align="center">Duplicate of 45</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#11">11</a></td>
+ <td>CD1</td>
+ <td>How do the keywords typename/template interact with using-declarations?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#12">12</a></td>
+ <td>dup</td>
+ <td>Default arguments on different declarations for the same function and the Koenig lookup</td>
+ <td class="full" align="center">Superseded by 239</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#13">13</a></td>
+ <td>extension</td>
+ <td>extern "C" for Parameters of Function Templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#14">14</a></td>
+ <td>NAD</td>
+ <td>extern "C" functions and declarations in different namespaces</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#15">15</a></td>
+ <td>dup</td>
+ <td>Default arguments for parameters of function templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#16">16</a></td>
+ <td>CD1</td>
+ <td>Access to members of indirect private base classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#17">17</a></td>
+ <td>NAD</td>
+ <td>Footnote 99 should discuss the naming class when describing members that can be accessed from friends</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#18">18</a></td>
+ <td>NAD</td>
+ <td>f(TYPE) where TYPE is void should be allowed</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#19">19</a></td>
+ <td>NAD</td>
+ <td>Clarify protected member access</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#20">20</a></td>
+ <td>TC1</td>
+ <td>Some clarifications needed for 12.8 para 15</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#21">21</a></td>
+ <td>TC1</td>
+ <td>Can a default argument for a template parameter appear in a friend declaration?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#22">22</a></td>
+ <td>TC1</td>
+ <td>Template parameter with a default argument that refers to itself</td>
+ <td class="none" align="center">Superseded by 481</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#23">23</a></td>
+ <td>NAD</td>
+ <td>Some questions regarding partial ordering of function templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#24">24</a></td>
+ <td>TC1</td>
+ <td>Errors in examples in 14.7.3</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#25">25</a></td>
+ <td>TC1</td>
+ <td>Exception specifications and pointers to members</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#26">26</a></td>
+ <td>NAD</td>
+ <td>Copy constructors and default arguments</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#27">27</a></td>
+ <td>NAD</td>
+ <td>Overload ambiguities for builtin ?: prototypes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#28">28</a></td>
+ <td>CD1</td>
+ <td>'exit', 'signal' and static object destruction</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#29">29</a></td>
+ <td>CD1</td>
+ <td>Linkage of locally declared functions</td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#30">30</a></td>
+ <td>TC1</td>
+ <td>Valid uses of "<TT>::template</TT>"</td>
+ <td class="none" align="center">Superseded by 468 (C++11 onwards)</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#31">31</a></td>
+ <td>NAD</td>
+ <td>Looking up new/delete</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#32">32</a></td>
+ <td>TC1</td>
+ <td>Clarification of explicit instantiation of non-exported templates</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#33">33</a></td>
+ <td>TC1</td>
+ <td>Argument dependent lookup and overloaded functions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#34">34</a></td>
+ <td>NAD</td>
+ <td>Argument dependent lookup and points of instantiation</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#35">35</a></td>
+ <td>TC1</td>
+ <td>Definition of default-initialization</td>
+ <td class="full" align="center">Duplicate of 178</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#36">36</a></td>
+ <td>open</td>
+ <td><I>using-declaration</I>s in multiple-declaration contexts</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#37">37</a></td>
+ <td>NAD</td>
+ <td>When is uncaught_exception() true?</td>
+ <td class="none" align="center">Superseded by 475</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#38">38</a></td>
+ <td>TC1</td>
+ <td>Explicit template arguments and operator functions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#39">39</a></td>
+ <td>CD1</td>
+ <td>Conflicting ambiguity rules</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#40">40</a></td>
+ <td>TC1</td>
+ <td>Syntax of <I>declarator-id</I></td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#41">41</a></td>
+ <td>TC1</td>
+ <td>Clarification of lookup of names after declarator-id</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#42">42</a></td>
+ <td>NAD</td>
+ <td>Redefining names from base classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#43">43</a></td>
+ <td>TC1</td>
+ <td>Copying base classes (PODs) using memcpy</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#44">44</a></td>
+ <td>CD1</td>
+ <td>Member specializations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45">45</a></td>
+ <td>CD1</td>
+ <td>Access to nested classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#46">46</a></td>
+ <td>NAD</td>
+ <td>Explicit instantiation of member templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#47">47</a></td>
+ <td>NAD</td>
+ <td>Template friend issues</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48">48</a></td>
+ <td>TC1</td>
+ <td>Definitions of unused static members</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#49">49</a></td>
+ <td>TC1</td>
+ <td>Restriction on non-type, non-value template arguments</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#50">50</a></td>
+ <td>NAD</td>
+ <td>Converting pointer to incomplete type to same type</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#51">51</a></td>
+ <td>TC1</td>
+ <td>Overloading and user-defined conversions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#52">52</a></td>
+ <td>TC1</td>
+ <td>Non-static members, member selection and access checking</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#53">53</a></td>
+ <td>TC1</td>
+ <td>Lvalue-to-rvalue conversion before certain static_casts</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#54">54</a></td>
+ <td>CD1</td>
+ <td>Static_cast from private base to derived class</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#55">55</a></td>
+ <td>NAD</td>
+ <td>Adding/subtracting pointer and enumeration value</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#56">56</a></td>
+ <td>TC1</td>
+ <td>Redeclaring typedefs within classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#57">57</a></td>
+ <td>open</td>
+ <td>Empty unions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#58">58</a></td>
+ <td>CD1</td>
+ <td>Signedness of bit fields of enum type</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#59">59</a></td>
+ <td>TC1</td>
+ <td>Clarification of overloading and UDC to reference type</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#60">60</a></td>
+ <td>CD1</td>
+ <td>Reference binding and valid conversion sequences</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#61">61</a></td>
+ <td>NAD</td>
+ <td>Address of static member function "<TT>&amp;p-&gt;f</TT>"</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#62">62</a></td>
+ <td>CD1</td>
+ <td>Unnamed members of classes used as type parameters</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#63">63</a></td>
+ <td>CD1</td>
+ <td>Class instantiation from pointer conversion to void*, null and self</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#64">64</a></td>
+ <td>TC1</td>
+ <td>Partial ordering to disambiguate explicit specialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#65">65</a></td>
+ <td>TC1</td>
+ <td>Typo in default argument example</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#66">66</a></td>
+ <td>NAD</td>
+ <td>Visibility of default args vs overloads added after using-declaration</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#67">67</a></td>
+ <td>TC1</td>
+ <td>Evaluation of left side of object-expression</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#68">68</a></td>
+ <td>TC1</td>
+ <td>Grammar does not allow "friend class A&lt;int&gt;;"</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#69">69</a></td>
+ <td>TC1</td>
+ <td>Storage class specifiers on template declarations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#70">70</a></td>
+ <td>CD1</td>
+ <td>Is an array bound a nondeduced context?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#71">71</a></td>
+ <td>NAD</td>
+ <td>Incorrect cross reference</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#72">72</a></td>
+ <td>dup</td>
+ <td>Linkage and storage class specifiers for templates</td>
+ <td class="full" align="center">Duplicate of 69</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#73">73</a></td>
+ <td>TC1</td>
+ <td>Pointer equality</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#74">74</a></td>
+ <td>TC1</td>
+ <td>Enumeration value in direct-new-declarator</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#75">75</a></td>
+ <td>TC1</td>
+ <td>In-class initialized members must be const</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#76">76</a></td>
+ <td>TC1</td>
+ <td>Are const volatile variables considered "constant expressions"?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#77">77</a></td>
+ <td>CD1</td>
+ <td>The definition of friend does not allow nested classes to be friends</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#78">78</a></td>
+ <td>CD1</td>
+ <td>Section 8.5 paragraph 9 should state it only applies to non-static objects</td>
+ <td class="none" align="center">Superseded by ????</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#79">79</a></td>
+ <td>dup</td>
+ <td>Alignment and placement new</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#80">80</a></td>
+ <td>TC1</td>
+ <td>Class members with same name as class</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#81">81</a></td>
+ <td>NAD</td>
+ <td>Null pointers and C compatibility</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#82">82</a></td>
+ <td>dup</td>
+ <td>Definition of "using" a constant expression</td>
+ <td class="full" align="center">Duplicate of 48</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#83">83</a></td>
+ <td>TC1</td>
+ <td>Overloading and deprecated conversion of string literal</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84">84</a></td>
+ <td>TC1</td>
+ <td>Overloading and conversion loophole used by <TT>auto_ptr</TT></td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#85">85</a></td>
+ <td>TC1</td>
+ <td>Redeclaration of member class</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#86">86</a></td>
+ <td>CD1</td>
+ <td>Lifetime of temporaries in query expressions</td>
+ <td class="none" align="center">Duplicate of 446</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#87">87</a></td>
+ <td>CD1</td>
+ <td>Exception specifications on function parameters</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#88">88</a></td>
+ <td>NAD</td>
+ <td>Specialization of member constant templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#89">89</a></td>
+ <td>TC1</td>
+ <td>Object lifetime does not account for reference rebinding</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#90">90</a></td>
+ <td>TC1</td>
+ <td>Should the enclosing class be an "associated class" too?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#91">91</a></td>
+ <td>NAD</td>
+ <td>A union's associated types should include the union itself</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#92">92</a></td>
+ <td>extension</td>
+ <td>Should <I>exception-specification</I>s be part of the type system?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#93">93</a></td>
+ <td>TC1</td>
+ <td>Missing word in 3.8 <U>basic.life</U> paragraph 2</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#94">94</a></td>
+ <td>TC1</td>
+ <td>Inconsistencies in the descriptions of constant expressions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#95">95</a></td>
+ <td>NAD</td>
+ <td>Elaborated type specifiers referencing names declared in friend decls</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#96">96</a></td>
+ <td>FDIS</td>
+ <td>Syntactic disambiguation using the <TT>template</TT> keyword</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#97">97</a></td>
+ <td>NAD</td>
+ <td>Use of bool constants in integral constant expressions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#98">98</a></td>
+ <td>TC1</td>
+ <td>Branching into try block</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#99">99</a></td>
+ <td>NAD</td>
+ <td>Partial ordering, references and cv-qualifiers</td>
+ <td class="full" align="center">Superseded by 214</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#100">100</a></td>
+ <td>TC1</td>
+ <td>Clarify why string literals are not allowed as template arguments</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#101">101</a></td>
+ <td>TC1</td>
+ <td>Redeclaration of extern "C" names via using-declarations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#102">102</a></td>
+ <td>NAD</td>
+ <td>Operator lookup rules do not work well with parts of the library</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#103">103</a></td>
+ <td>TC1</td>
+ <td>Is it <I>extended-namespace-definition</I> or <I>extension-namespace-definition</I> ?</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#104">104</a></td>
+ <td>NAD</td>
+ <td>Destroying the exception temp when no handler is found</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#105">105</a></td>
+ <td>TC1</td>
+ <td>Meaning of "template function"</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#106">106</a></td>
+ <td>CD1</td>
+ <td>Creating references to references during template deduction/instantiation</td>
+ <td class="none" align="center">Superseded by 540</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#107">107</a></td>
+ <td>NAD</td>
+ <td>Linkage of operator functions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#108">108</a></td>
+ <td>TC1</td>
+ <td>Are classes nested in templates dependent?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#109">109</a></td>
+ <td>NAD</td>
+ <td>Allowing <TT>::template</TT> in <I>using-declaration</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#110">110</a></td>
+ <td>open</td>
+ <td>Can template functions and classes be declared in the same scope?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#111">111</a></td>
+ <td>NAD</td>
+ <td>Copy constructors and cv-qualifiers</td>
+ <td class="none" align="center">Duplicate of 535</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112">112</a></td>
+ <td>CD1</td>
+ <td>Array types and cv-qualifiers</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#113">113</a></td>
+ <td>CD1</td>
+ <td>Visibility of called function</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#114">114</a></td>
+ <td>NAD</td>
+ <td>Virtual overriding by template member function specializations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#115">115</a></td>
+ <td>CD1</td>
+ <td>Address of template-id</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#116">116</a></td>
+ <td>TC1</td>
+ <td>Equivalent and functionally-equivalent function templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#117">117</a></td>
+ <td>NAD</td>
+ <td>Timing of destruction of temporaries</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#118">118</a></td>
+ <td>CD1</td>
+ <td>Calls via pointers to virtual member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#119">119</a></td>
+ <td>CD1</td>
+ <td>Object lifetime and aggregate initialization</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#120">120</a></td>
+ <td>TC1</td>
+ <td>Nonexistent non-terminal <I>qualified-name</I></td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#121">121</a></td>
+ <td>TC1</td>
+ <td>Dependent type names with non-dependent <I>nested-name-specifier</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#122">122</a></td>
+ <td>CD1</td>
+ <td><I>template-id</I>s as <I>unqualified-id</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#123">123</a></td>
+ <td>TC1</td>
+ <td>Bad cross-reference</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#124">124</a></td>
+ <td>CD1</td>
+ <td>Lifetime of temporaries in default initialization of class arrays</td>
+ <td class="none" align="center">Duplicate of 201</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#125">125</a></td>
+ <td>CD1</td>
+ <td>Ambiguity in <TT>friend</TT> declaration syntax</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#126">126</a></td>
+ <td>TC1</td>
+ <td>Exception specifications and <TT>const</TT></td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#127">127</a></td>
+ <td>TC1</td>
+ <td>Ambiguity in description of matching deallocation function</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#128">128</a></td>
+ <td>TC1</td>
+ <td>Casting between enum types</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#129">129</a></td>
+ <td>DRWP</td>
+ <td>Stability of uninitialized auto variables</td>
+ <td class="none" align="center">Duplicate of 616</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#130">130</a></td>
+ <td>NAD</td>
+ <td>Sequence points and <I>new-expression</I>s</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#131">131</a></td>
+ <td>TC1</td>
+ <td>Typo in Lao characters</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#132">132</a></td>
+ <td>NAD</td>
+ <td>Local types and linkage</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#133">133</a></td>
+ <td>dup</td>
+ <td>Exception specifications and checking</td>
+ <td class="none" align="center">Duplicate of 87</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#134">134</a></td>
+ <td>TC1</td>
+ <td>Template classes and <I>declarator-id</I>s</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#135">135</a></td>
+ <td>TC1</td>
+ <td>Class type in in-class member function definitions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#136">136</a></td>
+ <td>CD1</td>
+ <td>Default arguments and friend declarations</td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#137">137</a></td>
+ <td>TC1</td>
+ <td><TT>static_cast</TT> of <I>cv</I> <TT>void*</TT></td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#138">138</a></td>
+ <td>drafting</td>
+ <td>Friend declaration name lookup</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#139">139</a></td>
+ <td>CD1</td>
+ <td>Error in <TT>friend</TT> lookup example</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#140">140</a></td>
+ <td>CD1</td>
+ <td>Agreement of parameter declarations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#141">141</a></td>
+ <td>CD1</td>
+ <td>Non-member function templates in member access expressions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#142">142</a></td>
+ <td>TC1</td>
+ <td>Injection-related errors in access example</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#143">143</a></td>
+ <td>CD1</td>
+ <td>Friends and Koenig lookup</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#144">144</a></td>
+ <td>open</td>
+ <td>Position of <TT>friend</TT> specifier</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#145">145</a></td>
+ <td>TC1</td>
+ <td>Deprecation of prefix <TT>++</TT></td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#146">146</a></td>
+ <td>open</td>
+ <td>Floating-point zero</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#147">147</a></td>
+ <td>TC1</td>
+ <td>Naming the constructor</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#148">148</a></td>
+ <td>TC1</td>
+ <td>POD classes and pointers to members</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#149">149</a></td>
+ <td>TC1</td>
+ <td>Accessibility and ambiguity</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#150">150</a></td>
+ <td>open</td>
+ <td>Template template parameters and default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#151">151</a></td>
+ <td>TC1</td>
+ <td>Terminology of zero-initialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#152">152</a></td>
+ <td>TC1</td>
+ <td><TT>explicit</TT> copy constructors</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#153">153</a></td>
+ <td>TC1</td>
+ <td>Misleading wording (rank of conversion)</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#154">154</a></td>
+ <td>NAD</td>
+ <td>Anonymous unions in unnamed namespaces</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#155">155</a></td>
+ <td>dup</td>
+ <td>Brace initializer for scalar</td>
+ <td class="none" align="center">Duplicate of 632</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#156">156</a></td>
+ <td>drafting</td>
+ <td>Name lookup for conversion functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#157">157</a></td>
+ <td>open</td>
+ <td>Omitted typedef declarator</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#158">158</a></td>
+ <td>CD1</td>
+ <td>Aliasing and qualification conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#159">159</a></td>
+ <td>TC1</td>
+ <td>Namespace qualification in declarators</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#160">160</a></td>
+ <td>CD1</td>
+ <td>Missing <TT>std::</TT> qualification</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#161">161</a></td>
+ <td>TC1</td>
+ <td>Access to protected nested type</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#162">162</a></td>
+ <td>CD1</td>
+ <td>(<TT>&amp;C::f)()</TT> with nonstatic members</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#163">163</a></td>
+ <td>TC1</td>
+ <td>Description of subaggregate initializer</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#164">164</a></td>
+ <td>TC1</td>
+ <td>Overlap between Koenig and normal lookup</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#165">165</a></td>
+ <td>NAD</td>
+ <td>Definitions of friends and block-scope externs</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#166">166</a></td>
+ <td>TC1</td>
+ <td>Friend declarations of <I>template-id</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#167">167</a></td>
+ <td>NAD</td>
+ <td>Deprecating static functions</td>
+ <td class="none" align="center">Superseded by 1012</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#168">168</a></td>
+ <td>NAD</td>
+ <td>C linkage for static member functions</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#169">169</a></td>
+ <td>NAD</td>
+ <td><I>template-id</I>s in <I>using-declaration</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#170">170</a></td>
+ <td>drafting</td>
+ <td>Pointer-to-member conversions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#171">171</a></td>
+ <td>TC1</td>
+ <td>Global namespace scope</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#172">172</a></td>
+ <td>CD1</td>
+ <td>Unsigned int as underlying type of enum</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#173">173</a></td>
+ <td>TC1</td>
+ <td>Constraints on execution character set</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#174">174</a></td>
+ <td>NAD</td>
+ <td>Undeprecating global static</td>
+ <td class="none" align="center">Superseded by 1012</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#175">175</a></td>
+ <td>CD1</td>
+ <td>Class name injection and base name access</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#176">176</a></td>
+ <td>TC1</td>
+ <td>Name injection and templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#177">177</a></td>
+ <td>CD1</td>
+ <td>Lvalues vs rvalues in copy-initialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#178">178</a></td>
+ <td>TC1</td>
+ <td>More on value-initialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#179">179</a></td>
+ <td>TC1</td>
+ <td>Function pointers and subtraction</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#180">180</a></td>
+ <td>CD1</td>
+ <td><TT>typename</TT> and elaborated types</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#181">181</a></td>
+ <td>TC1</td>
+ <td>Errors in template <I>template-parameter</I> example</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#182">182</a></td>
+ <td>NAD</td>
+ <td>Access checking on explicit specializations</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#183">183</a></td>
+ <td>TC1</td>
+ <td><TT>typename</TT> in explicit specializations</td>
+ <td class="none" align="center">Superseded by 382</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#184">184</a></td>
+ <td>CD1</td>
+ <td>Default arguments in template <I>template-parameter</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#185">185</a></td>
+ <td>TC1</td>
+ <td>"Named" temporaries and copy elision</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#186">186</a></td>
+ <td>open</td>
+ <td>Name hiding and template <I>template-parameter</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#187">187</a></td>
+ <td>TC1</td>
+ <td>Scope of template parameter names</td>
+ <td class="none" align="center">Superseded by 481</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#188">188</a></td>
+ <td>TC1</td>
+ <td>Comma operator and rvalue conversion</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#189">189</a></td>
+ <td>drafting</td>
+ <td>Definition of <I>operator</I> and <I>punctuator</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#190">190</a></td>
+ <td>TC1</td>
+ <td>Layout-compatible POD-struct types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#191">191</a></td>
+ <td>open</td>
+ <td>Name lookup does not handle complex nesting</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#192">192</a></td>
+ <td>drafting</td>
+ <td>Name lookup in parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#193">193</a></td>
+ <td>TC1</td>
+ <td>Order of destruction of local automatics of destructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#194">194</a></td>
+ <td>TC1</td>
+ <td>Identifying constructors</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195">195</a></td>
+ <td>CD1</td>
+ <td>Converting between function and object pointers</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#196">196</a></td>
+ <td>open</td>
+ <td>Arguments to deallocation functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197">197</a></td>
+ <td>CD1</td>
+ <td>Issues with two-stage lookup of dependent names</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#198">198</a></td>
+ <td>CD1</td>
+ <td>Definition of "use" in local and nested classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#199">199</a></td>
+ <td>CD1</td>
+ <td>Order of destruction of temporaries</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#200">200</a></td>
+ <td>dup</td>
+ <td>Partial ordering and explicit arguments</td>
+ <td class="full" align="center">Duplicate of 214</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#201">201</a></td>
+ <td>CD1</td>
+ <td>Order of destruction of temporaries in initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#202">202</a></td>
+ <td>TC1</td>
+ <td>Use of overloaded function name</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#203">203</a></td>
+ <td>extension</td>
+ <td>Type of address-of-member expression</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#204">204</a></td>
+ <td>CD1</td>
+ <td>Exported class templates</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#205">205</a></td>
+ <td>drafting</td>
+ <td>Templates and static data members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#206">206</a></td>
+ <td>TC1</td>
+ <td>Semantic constraints on non-dependent names</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#207">207</a></td>
+ <td>CD1</td>
+ <td><I>using-declaration</I>s and protected access</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#208">208</a></td>
+ <td>CD1</td>
+ <td>Rethrowing exceptions in nested handlers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#209">209</a></td>
+ <td>NAD</td>
+ <td>Must friend declaration names be
+accessible?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#210">210</a></td>
+ <td>TC1</td>
+ <td>What is the type matched by an exception handler?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#211">211</a></td>
+ <td>NAD</td>
+ <td>Constructors should not be allowed to return normally after an exception</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#212">212</a></td>
+ <td>drafting</td>
+ <td>Implicit instantiation is not described clearly enough</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#213">213</a></td>
+ <td>TC1</td>
+ <td>Lookup in dependent base classes</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#214">214</a></td>
+ <td>CD1</td>
+ <td>Partial ordering of function templates is underspecified</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#215">215</a></td>
+ <td>CD1</td>
+ <td>Template parameters are not allowed in <I>nested-name-specifier</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#216">216</a></td>
+ <td>CD1</td>
+ <td>Linkage of nameless class-scope enumeration types</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#217">217</a></td>
+ <td>TC1</td>
+ <td>Default arguments for non-template member functions of class templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#218">218</a></td>
+ <td>CD1</td>
+ <td>Specification of Koenig lookup</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#219">219</a></td>
+ <td>NAD</td>
+ <td>Cannot defend against destructors that throw exceptions</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#220">220</a></td>
+ <td>CD1</td>
+ <td>All deallocation functions should be required not to throw</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#221">221</a></td>
+ <td>CD1</td>
+ <td>Must compound assignment operators be member functions?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#222">222</a></td>
+ <td>CD1</td>
+ <td>Sequence points and lvalue-returning operators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#223">223</a></td>
+ <td>DRWP</td>
+ <td>The meaning of deprecation</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#224">224</a></td>
+ <td>CD1</td>
+ <td>Definition of dependent names</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#225">225</a></td>
+ <td>NAD</td>
+ <td>Koenig lookup and fundamental types</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226">226</a></td>
+ <td>CD1</td>
+ <td>Default template arguments for function templates</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#227">227</a></td>
+ <td>TC1</td>
+ <td>How many scopes in an <TT>if</TT> statement?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#228">228</a></td>
+ <td>CD1</td>
+ <td>Use of <TT>template</TT> keyword with non-member templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#229">229</a></td>
+ <td>NAD</td>
+ <td>Partial specialization of function templates</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#230">230</a></td>
+ <td>extension</td>
+ <td>Calls to pure virtual functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#231">231</a></td>
+ <td>NAD</td>
+ <td>Visibility of names after <I>using-directive</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232">232</a></td>
+ <td>drafting</td>
+ <td>Is indirection through a null pointer undefined behavior?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#233">233</a></td>
+ <td>open</td>
+ <td>References vs pointers in UDC overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#234">234</a></td>
+ <td>NAD</td>
+ <td>Reuse of base class subobjects</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#235">235</a></td>
+ <td>TC1</td>
+ <td>Assignment vs initialization</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#236">236</a></td>
+ <td>NAD</td>
+ <td>Explicit temporaries and integral constant expressions</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#237">237</a></td>
+ <td>CD1</td>
+ <td>Explicit instantiation and base class members</td>
+ <td class="none" align="center">Duplicate of 470</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#238">238</a></td>
+ <td>open</td>
+ <td>Precision and accuracy constraints on floating point</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#239">239</a></td>
+ <td>CD1</td>
+ <td>Footnote 116 and Koenig lookup</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#240">240</a></td>
+ <td>DRWP</td>
+ <td>Uninitialized values and undefined behavior</td>
+ <td class="none" align="center">Duplicate of 616</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#241">241</a></td>
+ <td>TC1</td>
+ <td>Error in example in 14.8.1</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#242">242</a></td>
+ <td>open</td>
+ <td>Interpretation of old-style casts</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#243">243</a></td>
+ <td>NAD</td>
+ <td>Weighting of conversion functions in direct-initialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#244">244</a></td>
+ <td>CD1</td>
+ <td>Destructor lookup</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#245">245</a></td>
+ <td>CD1</td>
+ <td>Name lookup in <I>elaborated-type-specifier</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#246">246</a></td>
+ <td>CD1</td>
+ <td>Jumps in <I>function-try-block</I> handlers</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#247">247</a></td>
+ <td>NAD</td>
+ <td>Pointer-to-member casts and function overload resolution</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#248">248</a></td>
+ <td>FDIS</td>
+ <td>Identifier characters</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#249">249</a></td>
+ <td>TC1</td>
+ <td>What is a member function template?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#250">250</a></td>
+ <td>TC1</td>
+ <td>Address of function template specialization with non-deduced template arguments</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#251">251</a></td>
+ <td>open</td>
+ <td>How many signed integer types are there?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#252">252</a></td>
+ <td>CD1</td>
+ <td>Looking up deallocation functions in virtual destructors</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253">253</a></td>
+ <td>drafting</td>
+ <td>Why must empty or fully-initialized const objects be initialized?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#254">254</a></td>
+ <td>CD1</td>
+ <td>Definitional problems with <I>elaborated-type-specifier</I>s</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#255">255</a></td>
+ <td>drafting</td>
+ <td>Placement deallocation functions and lookup ambiguity</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#256">256</a></td>
+ <td>CD1</td>
+ <td>Overflow in size calculations</td>
+ <td class="none" align="center">Duplicate of 624</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#257">257</a></td>
+ <td>CD2</td>
+ <td>Abstract base constructors and virtual base initialization</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#258">258</a></td>
+ <td>CD1</td>
+ <td><I>using-declaration</I>s and cv-qualifiers</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <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="full" align="center">Yes (C++11 onwards)</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#260">260</a></td>
+ <td>open</td>
+ <td>User-defined conversions and built-in <TT>operator=</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#261">261</a></td>
+ <td>CD1</td>
+ <td>When is a deallocation function "used?"</td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#262">262</a></td>
+ <td>CD1</td>
+ <td>Default arguments and ellipsis</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#263">263</a></td>
+ <td>CD1</td>
+ <td>Can a constructor be declared a friend?</td>
+ <td class="full" align="center">Yes</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#264">264</a></td>
+ <td>open</td>
+ <td>Unusable template constructors and conversion functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#265">265</a></td>
+ <td>dup</td>
+ <td>Destructors, exceptions, and deallocation</td>
+ <td class="none" align="center">Duplicate of 353</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#266">266</a></td>
+ <td>NAD</td>
+ <td>No grammar sentence symbol</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#267">267</a></td>
+ <td>open</td>
+ <td>Alignment requirement for <I>new-expression</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268">268</a></td>
+ <td>open</td>
+ <td>Macro name suppression in rescanned replacement text</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#269">269</a></td>
+ <td>NAD</td>
+ <td>Order of initialization of multiply-defined static data members
+of class templates</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#270">270</a></td>
+ <td>CD1</td>
+ <td>Order of initialization of static data members of class templates</td>
+ <td class="na" align="center">N/A</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#271">271</a></td>
+ <td>open</td>
+ <td>Explicit instantiation and template argument deduction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#272">272</a></td>
+ <td>CD1</td>
+ <td>Explicit destructor invocation and <I>qualified-id</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#273">273</a></td>
+ <td>CD1</td>
+ <td>POD classes and <TT>operator&amp;()</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#274">274</a></td>
+ <td>CD1</td>
+ <td>Cv-qualification and char-alias access to out-of-lifetime objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#275">275</a></td>
+ <td>CD1</td>
+ <td>Explicit instantiation/specialization and <I>using-directive</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#276">276</a></td>
+ <td>CD1</td>
+ <td>Order of destruction of parameters and temporaries</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#277">277</a></td>
+ <td>CD1</td>
+ <td>Zero-initialization of pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#278">278</a></td>
+ <td>open</td>
+ <td>External linkage and nameless entities</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#279">279</a></td>
+ <td>open</td>
+ <td>Correspondence of "names for linkage purposes"</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#280">280</a></td>
+ <td>CD1</td>
+ <td>Access and surrogate call functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#281">281</a></td>
+ <td>CD1</td>
+ <td><TT>inline</TT> specifier in <TT>friend</TT> declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#282">282</a></td>
+ <td>open</td>
+ <td>Namespace for <TT>extended_type_info</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#283">283</a></td>
+ <td>CD1</td>
+ <td>Template <I>type-parameter</I>s are not syntactically <I>type-name</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#284">284</a></td>
+ <td>CD1</td>
+ <td><I>qualified-id</I>s in class declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#285">285</a></td>
+ <td>NAD</td>
+ <td>Identifying a function template being specialized</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#286">286</a></td>
+ <td>CD1</td>
+ <td>Incorrect example in partial specialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287">287</a></td>
+ <td>drafting</td>
+ <td>Order dependencies in template instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#288">288</a></td>
+ <td>CD1</td>
+ <td>Misuse of "static type" in describing pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#289">289</a></td>
+ <td>CD1</td>
+ <td>Incomplete list of contexts requiring a complete type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#290">290</a></td>
+ <td>NAD</td>
+ <td>Should memcpy be allowed into a POD with a const member?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#291">291</a></td>
+ <td>CD1</td>
+ <td>Overload resolution needed when binding reference to class rvalue</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#292">292</a></td>
+ <td>DRWP</td>
+ <td>Deallocation on exception in <TT>new</TT> before arguments evaluated</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#293">293</a></td>
+ <td>open</td>
+ <td>Syntax of explicit instantiation/specialization too permissive</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#294">294</a></td>
+ <td>NAD</td>
+ <td>Can <TT>static_cast</TT> drop exception specifications?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#295">295</a></td>
+ <td>CD1</td>
+ <td>cv-qualifiers on function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#296">296</a></td>
+ <td>CD1</td>
+ <td>Can conversion functions be static?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#297">297</a></td>
+ <td>open</td>
+ <td>Which template does an explicit specialization specialize?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#298">298</a></td>
+ <td>CD1</td>
+ <td><TT>T::x</TT> when <TT>T</TT> is cv-qualified</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#299">299</a></td>
+ <td>CD1</td>
+ <td>Conversion on array bound expression in <TT>new</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#300">300</a></td>
+ <td>CD1</td>
+ <td>References to functions in template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#301">301</a></td>
+ <td>CD1</td>
+ <td>Syntax for <I>template-name</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#302">302</a></td>
+ <td>CD1</td>
+ <td>Value-initialization and generation of default constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#303">303</a></td>
+ <td>NAD</td>
+ <td>Integral promotions on bit-fields</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#304">304</a></td>
+ <td>TC1</td>
+ <td>Value-initialization of a reference</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#305">305</a></td>
+ <td>CD1</td>
+ <td>Name lookup in destructor call</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#306">306</a></td>
+ <td>CD1</td>
+ <td>Ambiguity by class name injection</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#307">307</a></td>
+ <td>NAD</td>
+ <td>Initialization of a virtual base class subobject</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#308">308</a></td>
+ <td>NAD</td>
+ <td>Catching exceptions with ambiguous base classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#309">309</a></td>
+ <td>CD1</td>
+ <td>Linkage of entities whose names are not simply identifiers, in introduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#310">310</a></td>
+ <td>open</td>
+ <td>Can function templates differing only in parameter cv-qualifiers be overloaded?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#311">311</a></td>
+ <td>NAD</td>
+ <td>Using qualified name to reopen nested namespace</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#312">312</a></td>
+ <td>DRWP</td>
+ <td>&#8220;use&#8221; of invalid pointer value not defined</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#313">313</a></td>
+ <td>dup</td>
+ <td>Class with single conversion function to integral as array size in <TT>new</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#314">314</a></td>
+ <td>drafting</td>
+ <td><TT>template</TT> in base class specifier</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#315">315</a></td>
+ <td>NAD</td>
+ <td>Is call of static member function through null pointer undefined?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#316">316</a></td>
+ <td>NAD</td>
+ <td>Injected-class-name of template used as template template parameter</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
+ <td>CD1</td>
+ <td>Can a function be declared inline after it has been called?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
+ <td>CD1</td>
+ <td><TT>struct A::A</TT> should not name the constructor of <TT>A</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#319">319</a></td>
+ <td>CD1</td>
+ <td>Use of names without linkage in declaring entities with linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#320">320</a></td>
+ <td>CD1</td>
+ <td>Question on copy constructor elision example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#321">321</a></td>
+ <td>dup</td>
+ <td>Associated classes and namespaces for argument-dependent lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#322">322</a></td>
+ <td>CD1</td>
+ <td>Deduction of reference conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#323">323</a></td>
+ <td>CD1</td>
+ <td>Where must <TT>export</TT> appear?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#324">324</a></td>
+ <td>CD1</td>
+ <td>Can "<TT>&amp;</TT>" be applied to assignment to bit-field?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325">325</a></td>
+ <td>drafting</td>
+ <td>When are default arguments parsed?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#326">326</a></td>
+ <td>CD1</td>
+ <td>Wording for definition of trivial constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#327">327</a></td>
+ <td>CD1</td>
+ <td>Use of "structure" without definition</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#328">328</a></td>
+ <td>CD1</td>
+ <td>Missing requirement that class member types be complete</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#329">329</a></td>
+ <td>CD1</td>
+ <td>Evaluation of friends of templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330">330</a></td>
+ <td>open</td>
+ <td>Qualification conversions and pointers to arrays of pointers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#331">331</a></td>
+ <td>CD1</td>
+ <td>Allowed copy constructor signatures</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#332">332</a></td>
+ <td>DRWP</td>
+ <td>cv-qualified <TT>void</TT> parameter types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#333">333</a></td>
+ <td>NAD</td>
+ <td>Ambiguous use of "declaration" in disambiguation section</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#334">334</a></td>
+ <td>NAD</td>
+ <td>Is a comma-expression dependent if its first operand is?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#335">335</a></td>
+ <td>CD1</td>
+ <td>Allowing <TT>export</TT> on template members of nontemplate classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#336">336</a></td>
+ <td>CD1</td>
+ <td>Explicit specialization examples are still incorrect</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#337">337</a></td>
+ <td>CD1</td>
+ <td>Attempt to create array of abtract type should cause deduction to fail</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#338">338</a></td>
+ <td>open</td>
+ <td>Enumerator name with linkage used as class name in other translation unit</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#339">339</a></td>
+ <td>CD1</td>
+ <td>Overload resolution in operand of <TT>sizeof</TT> in constant expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#340">340</a></td>
+ <td>NAD</td>
+ <td>Unclear wording in disambiguation section</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#341">341</a></td>
+ <td>FDIS</td>
+ <td><TT>extern "C"</TT> namespace member function versus global variable</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#342">342</a></td>
+ <td>DRWP</td>
+ <td>Terminology: "indirection" versus "dereference"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#343">343</a></td>
+ <td>open</td>
+ <td>Make <TT>template</TT> optional in contexts that require a type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#344">344</a></td>
+ <td>open</td>
+ <td>Naming destructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#345">345</a></td>
+ <td>CD1</td>
+ <td>Misleading comment on example in templates chapter</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#346">346</a></td>
+ <td>NAD</td>
+ <td>Typo in 15.4</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#347">347</a></td>
+ <td>NAD</td>
+ <td>Use of derived class name in defining base class nested class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#348">348</a></td>
+ <td>CD1</td>
+ <td><TT>delete</TT> and user-written deallocation functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#349">349</a></td>
+ <td>CD1</td>
+ <td>Template argument deduction for conversion functions and qualification conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#350">350</a></td>
+ <td>open</td>
+ <td><TT>signed char</TT> underlying representation for objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351">351</a></td>
+ <td>CD1</td>
+ <td>Sequence point error: unspecified or undefined?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#352">352</a></td>
+ <td>CD1</td>
+ <td>Nondeduced contexts</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#353">353</a></td>
+ <td>CD1</td>
+ <td>Is deallocation routine called if destructor throws exception in delete?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#354">354</a></td>
+ <td>CD1</td>
+ <td>Null as nontype template argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#355">355</a></td>
+ <td>FDIS</td>
+ <td>Global-scope <TT>::</TT> in <I>nested-name-specifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#356">356</a></td>
+ <td>NAD</td>
+ <td>Wording of behavior of generated copy constructor for scalar members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#357">357</a></td>
+ <td>CD1</td>
+ <td>Definition of signature should include name</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#358">358</a></td>
+ <td>NAD</td>
+ <td>Namespaces and extern "C"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#359">359</a></td>
+ <td>NAD</td>
+ <td>Type definition in anonymous union</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#360">360</a></td>
+ <td>open</td>
+ <td>Using-declaration that reduces access</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#361">361</a></td>
+ <td>open</td>
+ <td>Forward reference to default argument</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#362">362</a></td>
+ <td>CD1</td>
+ <td>Order of initialization in instantiation units</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#363">363</a></td>
+ <td>NAD</td>
+ <td>Initialization of class from self</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#364">364</a></td>
+ <td>CD1</td>
+ <td>Calling overloaded function with static in set, with no object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#365">365</a></td>
+ <td>open</td>
+ <td>Storage duration and temporaries</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#366">366</a></td>
+ <td>CD1</td>
+ <td>String literal allowed in integral constant expression?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#367">367</a></td>
+ <td>CD1</td>
+ <td><TT>throw</TT> operator allowed in constant expression?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#368">368</a></td>
+ <td>CD1</td>
+ <td>Uses of non-type parameters that should cause deduction to fail</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#369">369</a></td>
+ <td>drafting</td>
+ <td>Are <TT>new</TT>/<TT>delete</TT> identifiers or <I>preprocessing-op-or-punc</I>?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#370">370</a></td>
+ <td>CD1</td>
+ <td>Can <TT>#include &lt;...&gt;</TT> form be used other than for standard C++ headers?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#371">371</a></td>
+ <td>open</td>
+ <td>Interleaving of constructor calls</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#372">372</a></td>
+ <td>CD1</td>
+ <td>Is access granted by base class specifiers available in following base class specifiers?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#373">373</a></td>
+ <td>FDIS</td>
+ <td>Lookup on namespace qualified name in using-directive</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#374">374</a></td>
+ <td>CD2</td>
+ <td>Can explicit specialization outside namespace use qualified name?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#375">375</a></td>
+ <td>dup</td>
+ <td>Confusing example on lookup with <TT>typename</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#376">376</a></td>
+ <td>NAD</td>
+ <td>Class "definition" versus class "declaration"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#377">377</a></td>
+ <td>CD1</td>
+ <td>Enum whose enumerators will not fit in any integral type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#378">378</a></td>
+ <td>CD1</td>
+ <td>Wording that says temporaries are declared</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#379">379</a></td>
+ <td>CD1</td>
+ <td>Change "class declaration" to "class definition"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#380">380</a></td>
+ <td>open</td>
+ <td>Definition of "ambiguous base class" missing</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#381">381</a></td>
+ <td>CD1</td>
+ <td>Incorrect example of base class member lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#382">382</a></td>
+ <td>CD1</td>
+ <td>Allow <TT>typename</TT> outside of templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#383">383</a></td>
+ <td>CD1</td>
+ <td>Is a class with a declared but not defined destructor a POD?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#384">384</a></td>
+ <td>NAD</td>
+ <td>Argument-dependent lookup and operator functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#385">385</a></td>
+ <td>CD1</td>
+ <td>How does protected member check of 11.5 interact with using-declarations?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#386">386</a></td>
+ <td>drafting</td>
+ <td>Friend declaration of name brought in by <I>using-declaration</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#387">387</a></td>
+ <td>CD1</td>
+ <td>Errors in example in 14.6.5</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#388">388</a></td>
+ <td>DRWP</td>
+ <td>Catching base<TT>*&amp;</TT> from a throw of derived<TT>*</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#389">389</a></td>
+ <td>CD1</td>
+ <td>Unnamed types in entities with linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#390">390</a></td>
+ <td>CD1</td>
+ <td>Pure virtual must be defined when implicitly called</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#391">391</a></td>
+ <td>CD1</td>
+ <td>Require direct binding of short-lived references to rvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#392">392</a></td>
+ <td>CD1</td>
+ <td>Use of full expression lvalue before temporary destruction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#393">393</a></td>
+ <td>open</td>
+ <td>Pointer to array of unknown bound in template argument list in parameter</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#394">394</a></td>
+ <td>CD1</td>
+ <td><I>identifier-list</I> is never defined</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#395">395</a></td>
+ <td>NAD</td>
+ <td>Conversion operator template syntax</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#396">396</a></td>
+ <td>CD1</td>
+ <td>Misleading note regarding use of <TT>auto</TT> for disambiguation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#397">397</a></td>
+ <td>CD1</td>
+ <td>Same address for string literals from default arguments in inline functions?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#398">398</a></td>
+ <td>CD1</td>
+ <td>Ambiguous wording on naming a type in deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#399">399</a></td>
+ <td>drafting</td>
+ <td>Destructor lookup redux</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#400">400</a></td>
+ <td>CD1</td>
+ <td>Using-declarations and the "struct hack"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#401">401</a></td>
+ <td>CD1</td>
+ <td>When is access for template parameter default arguments checked?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#402">402</a></td>
+ <td>open</td>
+ <td>More on partial ordering of function templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#403">403</a></td>
+ <td>CD1</td>
+ <td>Reference to a type as a <I>template-id</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#404">404</a></td>
+ <td>CD1</td>
+ <td>Unclear reference to construction with non-trivial constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#405">405</a></td>
+ <td>open</td>
+ <td>Unqualified function name lookup</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#406">406</a></td>
+ <td>CD1</td>
+ <td>Static data member in class with name for linkage purposes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#407">407</a></td>
+ <td>FDIS</td>
+ <td>Named class with associated typedef: two names or one?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#408">408</a></td>
+ <td>CD2</td>
+ <td>sizeof applied to unknown-bound array static data member of template</td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#409">409</a></td>
+ <td>CD1</td>
+ <td>Obsolete paragraph missed by changes for issue 224</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#410">410</a></td>
+ <td>CD1</td>
+ <td>Paragraph missed in changes for issue 166</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#411">411</a></td>
+ <td>open</td>
+ <td>Use of universal-character-name in character versus string literals</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#412">412</a></td>
+ <td>NAD</td>
+ <td>Can a replacement allocation function be inline?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#413">413</a></td>
+ <td>CD1</td>
+ <td>Definition of "empty class"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#414">414</a></td>
+ <td>CD1</td>
+ <td>Multiple types found on destructor lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#415">415</a></td>
+ <td>CD1</td>
+ <td>Template deduction does not cause instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#416">416</a></td>
+ <td>CD1</td>
+ <td>Class must be complete to allow operator lookup?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#417">417</a></td>
+ <td>CD1</td>
+ <td>Using derived-class qualified name in out-of-class nested class definition</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#418">418</a></td>
+ <td>open</td>
+ <td>Imperfect wording on error on multiple default arguments on a called function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#419">419</a></td>
+ <td>open</td>
+ <td>Can cast to virtual base class be done on partially-constructed object?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#420">420</a></td>
+ <td>CD1</td>
+ <td>postfixexpression-&gt;scalar_type_dtor() inconsistent</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#421">421</a></td>
+ <td>CD1</td>
+ <td>Is rvalue.field an rvalue?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#422">422</a></td>
+ <td>NAD</td>
+ <td>Is a typedef redeclaration allowed with a template type that might be the same?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#423">423</a></td>
+ <td>NAD</td>
+ <td>Can a conversion be done on the left operand of a compound assignment?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#424">424</a></td>
+ <td>CD1</td>
+ <td>Wording problem with issue 56 resolution on redeclaring typedefs in class scope</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#425">425</a></td>
+ <td>CD1</td>
+ <td>Set of candidates for overloaded built-in operator with float operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#426">426</a></td>
+ <td>drafting</td>
+ <td>Identically-named variables, one internally and one externally linked, allowed?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#427">427</a></td>
+ <td>CD1</td>
+ <td><TT>static_cast</TT> ambiguity: conversion versus cast to derived</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#428">428</a></td>
+ <td>CD1</td>
+ <td>Mention of expression with reference type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#429">429</a></td>
+ <td>CD1</td>
+ <td>Matching deallocation function chosen based on syntax or signature?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#430">430</a></td>
+ <td>CD1</td>
+ <td>Ordering of expression evaluation in initializer list</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#431">431</a></td>
+ <td>FDIS</td>
+ <td>Defect in wording in 14.2</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#432">432</a></td>
+ <td>CD1</td>
+ <td>Is injected class name visible in base class specifier list?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#433">433</a></td>
+ <td>CD1</td>
+ <td>Do elaborated type specifiers in templates inject into enclosing namespace scope?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#434">434</a></td>
+ <td>NAD</td>
+ <td>Unclear suppression of standard conversions while binding reference to lvalue</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#435">435</a></td>
+ <td>NAD</td>
+ <td>Change "declararation or definition" to "declaration"</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#436">436</a></td>
+ <td>CD1</td>
+ <td>Problem in example in 9.6 paragraph 4</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#437">437</a></td>
+ <td>CD1</td>
+ <td>Is type of class allowed in member function exception specification?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#438">438</a></td>
+ <td>CD2</td>
+ <td>Possible flaw in wording for multiple accesses to object between sequence points</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#439">439</a></td>
+ <td>CD1</td>
+ <td>Guarantees on casting pointer back to cv-qualified version of original type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#440">440</a></td>
+ <td>open</td>
+ <td>Allow implicit pointer-to-member conversion on nontype template argument</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#441">441</a></td>
+ <td>CD1</td>
+ <td>Ordering of static reference initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#442">442</a></td>
+ <td>CD1</td>
+ <td>Incorrect use of null pointer constant in description of delete operator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#443">443</a></td>
+ <td>CD1</td>
+ <td>Wording nit in description of lifetime of temporaries</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#444">444</a></td>
+ <td>NAD</td>
+ <td>Overriding and the generated copy assignment operator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#445">445</a></td>
+ <td>NAD</td>
+ <td>Wording issue on friend declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#446">446</a></td>
+ <td>CD1</td>
+ <td>Does an lvalue-to-rvalue conversion on the "?" operator produce a temporary?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#447">447</a></td>
+ <td>CD1</td>
+ <td>Is offsetof type-dependent?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#448">448</a></td>
+ <td>FDIS</td>
+ <td>Set of template functions in call with dependent explicit argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#449">449</a></td>
+ <td>NAD</td>
+ <td>Consistency in use of hyphen with names of "non" entities</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#450">450</a></td>
+ <td>CD1</td>
+ <td>Binding a reference to const to a cv-qualified array rvalue</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#451">451</a></td>
+ <td>CD1</td>
+ <td>Expressions with invalid results and ill-formedness</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#452">452</a></td>
+ <td>CD1</td>
+ <td>Wording nit on description of <TT>this</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#453">453</a></td>
+ <td>drafting</td>
+ <td>References may only bind to &#8220;valid&#8221; objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#454">454</a></td>
+ <td>CD1</td>
+ <td>When is a definition of a static data member required?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#455">455</a></td>
+ <td>drafting</td>
+ <td>Partial ordering and non-deduced arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#456">456</a></td>
+ <td>NAD</td>
+ <td>Is initialized const int or const bool variable a null pointer constant?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#457">457</a></td>
+ <td>CD1</td>
+ <td>Wording nit on use of const variables in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#458">458</a></td>
+ <td>FDIS</td>
+ <td>Hiding of member template parameters by other members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#459">459</a></td>
+ <td>open</td>
+ <td>Hiding of template parameters by base class members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#460">460</a></td>
+ <td>CD1</td>
+ <td>Can a <I>using-declaration</I> name a namespace?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#461">461</a></td>
+ <td>NAD</td>
+ <td>Make <TT>asm</TT> conditionally-supported</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#462">462</a></td>
+ <td>DRWP</td>
+ <td>Lifetime of temporaries bound to comma expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#463">463</a></td>
+ <td>CD1</td>
+ <td><TT>reinterpret_cast&lt;T*&gt;(0)</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#464">464</a></td>
+ <td>CD1</td>
+ <td>Wording nit on lifetime of temporaries to which references are bound</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#465">465</a></td>
+ <td>NAD</td>
+ <td>May constructors of global objects call <TT>exit()</TT>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#466">466</a></td>
+ <td>CD1</td>
+ <td>cv-qualifiers on pseudo-destructor type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#467">467</a></td>
+ <td>NAD</td>
+ <td>Jump past initialization of local static variable</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#468">468</a></td>
+ <td>CD1</td>
+ <td>Allow <TT>::template</TT> outside of templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#469">469</a></td>
+ <td>NAD</td>
+ <td>Const template specializations and reference arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#470">470</a></td>
+ <td>CD1</td>
+ <td>Instantiation of members of an explicitly-instantiated class template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#471">471</a></td>
+ <td>NAD</td>
+ <td>Conflicting inherited access specifications</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#472">472</a></td>
+ <td>drafting</td>
+ <td>Casting across protected inheritance</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#473">473</a></td>
+ <td>open</td>
+ <td>Block-scope declarations of allocator functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#474">474</a></td>
+ <td>CD1</td>
+ <td>Block-scope <TT>extern</TT> declarations in namespace members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#475">475</a></td>
+ <td>FDIS</td>
+ <td>When is <TT>std::uncaught_exception()</TT> true? (take 2)</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#476">476</a></td>
+ <td>extension</td>
+ <td>Determining the buffer size for placement new</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#477">477</a></td>
+ <td>CD1</td>
+ <td>Can <TT>virtual</TT> appear in a <TT>friend</TT> declaration?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#478">478</a></td>
+ <td>NAD</td>
+ <td>May a function parameter be an array of an abstract class type?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#479">479</a></td>
+ <td>CD1</td>
+ <td>Copy elision in exception handling</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#480">480</a></td>
+ <td>CD1</td>
+ <td>Is a base of a virtual base also virtual?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#481">481</a></td>
+ <td>CD2</td>
+ <td>Scope of template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#482">482</a></td>
+ <td>DRWP</td>
+ <td>Qualified declarators in redeclarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#483">483</a></td>
+ <td>DRWP</td>
+ <td>Normative requirements on integral ranges</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#484">484</a></td>
+ <td>CD1</td>
+ <td>Can a <I>base-specifier</I> name a cv-qualified class type?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#485">485</a></td>
+ <td>CD1</td>
+ <td>What is a &#8220;name&#8221;?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#486">486</a></td>
+ <td>CD1</td>
+ <td>Invalid return types and template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#487">487</a></td>
+ <td>NAD</td>
+ <td>Operator overloading in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#488">488</a></td>
+ <td>CD1</td>
+ <td>Local types, overload resolution, and template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#489">489</a></td>
+ <td>NAD</td>
+ <td>Must member function templates be instantiated during overload resolution?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#490">490</a></td>
+ <td>CD2</td>
+ <td>Name lookup in friend declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#491">491</a></td>
+ <td>CD1</td>
+ <td>Initializers for empty-class aggregrate members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#492">492</a></td>
+ <td>CD1</td>
+ <td><TT>typeid</TT> constness inconsistent with example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#493">493</a></td>
+ <td>CD2</td>
+ <td>Type deduction from a <TT>bool</TT> context</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#494">494</a></td>
+ <td>CD1</td>
+ <td>Problems with the resolution of issue 45</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#495">495</a></td>
+ <td>CD2</td>
+ <td>Overload resolution with template and non-template conversion functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#496">496</a></td>
+ <td>DRWP</td>
+ <td>Is a volatile-qualified type really a POD?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#497">497</a></td>
+ <td>CD1</td>
+ <td>Missing required initialization in example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#498">498</a></td>
+ <td>open</td>
+ <td>Storage class specifiers in definitions of class members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#499">499</a></td>
+ <td>CD2</td>
+ <td>Throwing an array of unknown size</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#500">500</a></td>
+ <td>CD1</td>
+ <td>Access in <I>base-specifier</I>s of friend and nested classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#501">501</a></td>
+ <td>NAD</td>
+ <td>Visibility of friend declarations within the befriending class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#502">502</a></td>
+ <td>FDIS</td>
+ <td>Dependency of nested enumerations and enumerators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#503">503</a></td>
+ <td>open</td>
+ <td>Cv-qualified function types in template argument deduction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#504">504</a></td>
+ <td>open</td>
+ <td>Should use of a variable in its own initializer require a diagnostic?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#505">505</a></td>
+ <td>CD1</td>
+ <td>Conditionally-supported behavior for unknown character escapes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#506">506</a></td>
+ <td>CD1</td>
+ <td>Conditionally-supported behavior for non-POD objects passed to ellipsis</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#507">507</a></td>
+ <td>dup</td>
+ <td>Ambiguity assigning class object to built-in type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#508">508</a></td>
+ <td>FDIS</td>
+ <td>Non-constructed value-initialized objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#509">509</a></td>
+ <td>CD1</td>
+ <td>Dead code in the specification of default initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#510">510</a></td>
+ <td>CD1</td>
+ <td>Default initialization of POD classes?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#511">511</a></td>
+ <td>open</td>
+ <td>POD-structs with template assignment operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#512">512</a></td>
+ <td>NAD</td>
+ <td>Union members with user-declared non-default constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#513">513</a></td>
+ <td>CD1</td>
+ <td>Non-class &#8220;most-derived&#8221; objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#514">514</a></td>
+ <td>CD1</td>
+ <td>Is the initializer for a namespace member in the scope of the namespace?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515">515</a></td>
+ <td>CD1</td>
+ <td>Non-dependent references to base class members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#516">516</a></td>
+ <td>CD1</td>
+ <td>Use of <TT>signed</TT> in bit-field declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#517">517</a></td>
+ <td>CD1</td>
+ <td>Partial specialization following explicit instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#518">518</a></td>
+ <td>CD1</td>
+ <td>Trailing comma following <I>enumerator-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#519">519</a></td>
+ <td>CD1</td>
+ <td>Null pointer preservation in <TT>void*</TT> conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#520">520</a></td>
+ <td>CD1</td>
+ <td>Old-style casts between incomplete class types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#521">521</a></td>
+ <td>CD1</td>
+ <td>Requirements for exceptions thrown by allocation functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#522">522</a></td>
+ <td>CD1</td>
+ <td>Array-to-pointer decay in template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#523">523</a></td>
+ <td>open</td>
+ <td>Can a one-past-the-end pointer be invalidated by deleting an adjacent object?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#524">524</a></td>
+ <td>CD1</td>
+ <td>Can function-notation calls to operator functions be dependent?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#525">525</a></td>
+ <td>CD1</td>
+ <td>Missing <TT>*</TT> in example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#526">526</a></td>
+ <td>CD1</td>
+ <td>Confusing aspects in the specification of non-deduced contexts</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#527">527</a></td>
+ <td>CD2</td>
+ <td>Problems with linkage of types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#528">528</a></td>
+ <td>open</td>
+ <td>Why are incomplete class types not allowed with <TT>typeid</TT>?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#529">529</a></td>
+ <td>drafting</td>
+ <td>Use of <TT>template&lt;&gt;</TT> with &#8220;explicitly-specialized&#8221; class templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#530">530</a></td>
+ <td>CD1</td>
+ <td>Nontype template arguments in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#531">531</a></td>
+ <td>FDIS</td>
+ <td>Defining members of explicit specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532">532</a></td>
+ <td>FDIS</td>
+ <td>Member/nonmember operator template partial ordering</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#533">533</a></td>
+ <td>NAD</td>
+ <td>Special treatment for C-style header names</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#534">534</a></td>
+ <td>CD1</td>
+ <td><I>template-name</I>s and <I>operator-function-id</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#535">535</a></td>
+ <td>DRWP</td>
+ <td>Copy construction without a copy constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#536">536</a></td>
+ <td>drafting</td>
+ <td>Problems in the description of <I>id-expression</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#537">537</a></td>
+ <td>CD1</td>
+ <td>Definition of &#8220;signature&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#538">538</a></td>
+ <td>CD1</td>
+ <td>Definition and usage
+of <I>structure</I>, <I>POD-struct</I>, <I>POD-union</I>,
+and <I>POD class</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#539">539</a></td>
+ <td>DRWP</td>
+ <td>Constraints on <I>type-specifier-seq</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#540">540</a></td>
+ <td>CD1</td>
+ <td>Propagation of cv-qualifiers in reference-to-reference collapse</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#541">541</a></td>
+ <td>CD2</td>
+ <td>Dependent function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#542">542</a></td>
+ <td>CD2</td>
+ <td>Value initialization of arrays of POD-structs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#543">543</a></td>
+ <td>CD1</td>
+ <td>Value initialization and default constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#544">544</a></td>
+ <td>NAD</td>
+ <td>Base class lookup in explicit specialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#545">545</a></td>
+ <td>open</td>
+ <td>User-defined conversions and built-in operator overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#546">546</a></td>
+ <td>FDIS</td>
+ <td>Explicit instantiation of class template members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#547">547</a></td>
+ <td>FDIS</td>
+ <td>Partial specialization on member function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#548">548</a></td>
+ <td>dup</td>
+ <td><I>qualified-id</I>s in declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#549">549</a></td>
+ <td>drafting</td>
+ <td>Non-deducible parameters in partial specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#550">550</a></td>
+ <td>open</td>
+ <td>Pointer to array of unknown bound in parameter declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#551">551</a></td>
+ <td>CD1</td>
+ <td>When is <TT>inline</TT> permitted in an explicit instantiation?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#552">552</a></td>
+ <td>NAD</td>
+ <td>Use of <TT>typename</TT> in the type in a non-type <I>parameter-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#553">553</a></td>
+ <td>NAD</td>
+ <td>Problems with friend allocation and deallocation functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#554">554</a></td>
+ <td>drafting</td>
+ <td>Definition of &#8220;declarative region&#8221; and &#8220;scope&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#555">555</a></td>
+ <td>drafting</td>
+ <td>Pseudo-destructor name lookup</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#556">556</a></td>
+ <td>CD2</td>
+ <td>Conflicting requirements for acceptable aliasing</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#557">557</a></td>
+ <td>CD1</td>
+ <td>Does argument-dependent lookup cause template instantiation?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#558">558</a></td>
+ <td>CD1</td>
+ <td>Excluded characters in universal character names</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#559">559</a></td>
+ <td>CD1</td>
+ <td>Editing error in issue 382 resolution</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#560">560</a></td>
+ <td>drafting</td>
+ <td>Use of the <TT>typename</TT> keyword in return types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561">561</a></td>
+ <td>CD2</td>
+ <td>Internal linkage functions in dependent name lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#562">562</a></td>
+ <td>open</td>
+ <td><I>qualified-id</I>s in non-expression contexts</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#563">563</a></td>
+ <td>open</td>
+ <td>Linkage specification for objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#564">564</a></td>
+ <td>CD2</td>
+ <td>Agreement of language linkage or <I>linkage-specification</I>s?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#565">565</a></td>
+ <td>DRWP</td>
+ <td>Conflict rules for <I>using-declaration</I>s naming function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#566">566</a></td>
+ <td>NAD</td>
+ <td>Conversion of negative floating point values to integer type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#567">567</a></td>
+ <td>NAD</td>
+ <td>Can <TT>size_t</TT> and <TT>ptrdiff_t</TT> be larger than <TT>long</TT>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#568">568</a></td>
+ <td>CD1</td>
+ <td>Definition of POD is too strict</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#569">569</a></td>
+ <td>CD2</td>
+ <td>Spurious semicolons at namespace scope should be allowed</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#570">570</a></td>
+ <td>CD2</td>
+ <td>Are references subject to the ODR?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#571">571</a></td>
+ <td>CD2</td>
+ <td>References declared <TT>const</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#572">572</a></td>
+ <td>FDIS</td>
+ <td>Standard conversions for non-built-in types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#573">573</a></td>
+ <td>FDIS</td>
+ <td>Conversions between function pointers and <TT>void*</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#574">574</a></td>
+ <td>NAD</td>
+ <td>Definition of &#8220;copy assignment operator&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#575">575</a></td>
+ <td>FDIS</td>
+ <td>Criteria for deduction failure</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#576">576</a></td>
+ <td>CD2</td>
+ <td>Typedefs in function definitions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#577">577</a></td>
+ <td>DRWP</td>
+ <td><TT>void</TT> in an empty parameter list</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#578">578</a></td>
+ <td>open</td>
+ <td>Phase 1 replacement of characters with <I>universal-character-name</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#579">579</a></td>
+ <td>open</td>
+ <td>What is a &#8220;nested&#8221; <TT>&gt;</TT> or <TT>&gt;&gt;</TT>?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#580">580</a></td>
+ <td>FDIS</td>
+ <td>Access in <I>template-parameter</I>s of member and friend definitions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#581">581</a></td>
+ <td>open</td>
+ <td>Can a templated constructor be explicitly instantiated or specialized?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#582">582</a></td>
+ <td>CD1</td>
+ <td>Template conversion functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#583">583</a></td>
+ <td>DRWP</td>
+ <td>Relational pointer comparisons against the null pointer constant</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#584">584</a></td>
+ <td>NAD</td>
+ <td>Unions and aliasing</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#585">585</a></td>
+ <td>NAD</td>
+ <td>Friend template template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#586">586</a></td>
+ <td>NAD</td>
+ <td>Default <I>template-argument</I>s and template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#587">587</a></td>
+ <td>CD2</td>
+ <td>Lvalue operands of a conditional expression differing only in cv-qualification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#588">588</a></td>
+ <td>CD2</td>
+ <td>Searching dependent bases of classes local to function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#589">589</a></td>
+ <td>CD2</td>
+ <td>Direct binding of class and array rvalues in reference initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#590">590</a></td>
+ <td>FDIS</td>
+ <td>Nested classes and the &#8220;current instantiation&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#591">591</a></td>
+ <td>drafting</td>
+ <td>When a dependent base class is the current instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#592">592</a></td>
+ <td>CD1</td>
+ <td>Exceptions during construction of local static objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#593">593</a></td>
+ <td>NAD</td>
+ <td>Falling off the end of a destructor's <I>function-try-block</I> handler</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#594">594</a></td>
+ <td>CD1</td>
+ <td>Coordinating issues 119 and 404 with delegating constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <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="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#596">596</a></td>
+ <td>open</td>
+ <td>Replacing an exception object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#597">597</a></td>
+ <td>DRWP</td>
+ <td>Conversions applied to out-of-lifetime non-POD lvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#598">598</a></td>
+ <td>CD2</td>
+ <td>Associated namespaces of overloaded functions and function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#599">599</a></td>
+ <td>CD2</td>
+ <td>Deleting a null function pointer</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#600">600</a></td>
+ <td>open</td>
+ <td>Does access control apply to members or to names?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#601">601</a></td>
+ <td>CD2</td>
+ <td>Type of literals in preprocessing expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#602">602</a></td>
+ <td>FDIS</td>
+ <td>When is the injected-class-name of a class template a template?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#603">603</a></td>
+ <td>CD1</td>
+ <td>Type equivalence and unsigned overflow</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#604">604</a></td>
+ <td>CD2</td>
+ <td>Argument list for overload resolution in copy-initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#605">605</a></td>
+ <td>FDIS</td>
+ <td>Linkage of explicit specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#606">606</a></td>
+ <td>CD1</td>
+ <td>Template argument deduction for rvalue references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#607">607</a></td>
+ <td>open</td>
+ <td>Lookup of <I>mem-initializer-id</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#608">608</a></td>
+ <td>CD2</td>
+ <td>Determining the final overrider of a virtual function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#609">609</a></td>
+ <td>open</td>
+ <td>What is a &#8220;top-level&#8221; cv-qualifier?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#610">610</a></td>
+ <td>NAD</td>
+ <td>Computing the negative of <TT>0U</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#611">611</a></td>
+ <td>CD2</td>
+ <td>Zero-initializing references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#612">612</a></td>
+ <td>CD2</td>
+ <td>Requirements on a conforming implementation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#613">613</a></td>
+ <td>CD1</td>
+ <td>Unevaluated uses of non-static class members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614">614</a></td>
+ <td>CD1</td>
+ <td>Results of integer <TT>/</TT> and <TT>%</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#615">615</a></td>
+ <td>FDIS</td>
+ <td>Incorrect description of variables that can be initialized</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#616">616</a></td>
+ <td>DRWP</td>
+ <td>Definition of &#8220;indeterminate value&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#617">617</a></td>
+ <td>drafting</td>
+ <td>Lvalue-to-rvalue conversions of uninitialized <TT>char</TT> objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#618">618</a></td>
+ <td>CD2</td>
+ <td>Casts in preprocessor conditional expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#619">619</a></td>
+ <td>FDIS</td>
+ <td>Completeness of array types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#620">620</a></td>
+ <td>CD1</td>
+ <td>Declaration order in layout-compatible POD structs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#621">621</a></td>
+ <td>FDIS</td>
+ <td>Template argument deduction from function return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#622">622</a></td>
+ <td>extension</td>
+ <td>Relational comparisons of arbitrary pointers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#623">623</a></td>
+ <td>extension</td>
+ <td>Use of pointers to deallocated storage</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#624">624</a></td>
+ <td>CD1</td>
+ <td>Overflow in calculating size of allocation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#625">625</a></td>
+ <td>CD2</td>
+ <td>Use of <TT>auto</TT> as a <I>template-argument</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#626">626</a></td>
+ <td>CD2</td>
+ <td>Preprocessor string literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#627">627</a></td>
+ <td>NAD</td>
+ <td>Values behaving as types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#628">628</a></td>
+ <td>CD2</td>
+ <td>The values of an enumeration with no enumerator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#629">629</a></td>
+ <td>CD1</td>
+ <td><TT>auto</TT> parsing ambiguity</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#630">630</a></td>
+ <td>CD2</td>
+ <td>Equality of narrow and wide character values in the basic character set</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#631">631</a></td>
+ <td>DRWP</td>
+ <td>Jumping into a &#8220;then&#8221; clause</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#632">632</a></td>
+ <td>CD1</td>
+ <td>Brace-enclosed initializer for scalar member of aggregate</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#633">633</a></td>
+ <td>CD2</td>
+ <td>Specifications for variables that should also apply to references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#634">634</a></td>
+ <td>CD1</td>
+ <td>Conditionally-supported behavior for non-POD objects passed to ellipsis redux</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#635">635</a></td>
+ <td>NAD</td>
+ <td>Names of constructors and destructors of templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#636">636</a></td>
+ <td>drafting</td>
+ <td>Dynamic type of objects and aliasing</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637">637</a></td>
+ <td>CD1</td>
+ <td>Sequencing rules and example disagree</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#638">638</a></td>
+ <td>CD2</td>
+ <td>Explicit specialization and friendship</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#639">639</a></td>
+ <td>CD1</td>
+ <td>What makes side effects &#8220;different&#8221; from one another?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#640">640</a></td>
+ <td>open</td>
+ <td>Accessing destroyed local objects of static storage duration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#641">641</a></td>
+ <td>CD2</td>
+ <td>Overload resolution and conversion-to-same-type operators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#642">642</a></td>
+ <td>CD2</td>
+ <td>Definition and use of &#8220;block scope&#8221; and &#8220;local scope&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#643">643</a></td>
+ <td>NAD</td>
+ <td>Use of <TT>decltype</TT> in a class <I>member-specification</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#644">644</a></td>
+ <td>CD1</td>
+ <td>Should a trivial class type be a literal type?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#645">645</a></td>
+ <td>CD2</td>
+ <td>Are bit-field and non-bit-field members layout compatible?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#646">646</a></td>
+ <td>NAD</td>
+ <td>Can a class with a constexpr copy constructor be a literal type?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#647">647</a></td>
+ <td>CD1</td>
+ <td>Non-constexpr instances of constexpr constructor templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#648">648</a></td>
+ <td>CD1</td>
+ <td>Constant expressions in constexpr initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#649">649</a></td>
+ <td>CD1</td>
+ <td>Optionally ill-formed extended alignment requests</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#650">650</a></td>
+ <td>CD2</td>
+ <td>Order of destruction for temporaries bound to the returned value of a function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#651">651</a></td>
+ <td>CD1</td>
+ <td>Problems in <TT>decltype</TT> specification and examples</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#652">652</a></td>
+ <td>CD2</td>
+ <td>Compile-time evaluation of floating-point expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#653">653</a></td>
+ <td>CD2</td>
+ <td>Copy assignment of unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654">654</a></td>
+ <td>CD1</td>
+ <td>Conversions to and from <TT>nullptr_t</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#655">655</a></td>
+ <td>FDIS</td>
+ <td>Initialization not specified for forwarding constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#656">656</a></td>
+ <td>CD2</td>
+ <td>Direct binding to the result of a conversion operator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#657">657</a></td>
+ <td>CD2</td>
+ <td>Abstract class parameter in synthesized declaration</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#658">658</a></td>
+ <td>CD2</td>
+ <td>Defining <TT>reinterpret_cast</TT> for pointer types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#659">659</a></td>
+ <td>CD1</td>
+ <td>Alignment of function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#660">660</a></td>
+ <td>CD1</td>
+ <td>Unnamed scoped enumerations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#661">661</a></td>
+ <td>CD1</td>
+ <td>Semantics of arithmetic comparisons</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#662">662</a></td>
+ <td>NAD</td>
+ <td>Forming a pointer to a reference type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#663">663</a></td>
+ <td>CD1</td>
+ <td>Valid Cyrillic identifier characters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#664">664</a></td>
+ <td>CD2</td>
+ <td>Direct binding of references to non-class rvalue references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#665">665</a></td>
+ <td>CD2</td>
+ <td>Problems in the specification of <TT>dynamic_cast</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#666">666</a></td>
+ <td>CD1</td>
+ <td>Dependent <I>qualified-id</I>s without the <TT>typename</TT> keyword</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#667">667</a></td>
+ <td>CD2</td>
+ <td>Trivial special member functions that cannot be implicitly defined</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#668">668</a></td>
+ <td>CD2</td>
+ <td>Throwing an exception from the destructor of a local static object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#669">669</a></td>
+ <td>NAD</td>
+ <td>Confusing specification of the meaning of <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#670">670</a></td>
+ <td>open</td>
+ <td>Copy initialization via derived-to-base conversion in the second step</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#671">671</a></td>
+ <td>CD1</td>
+ <td>Explicit conversion from a scoped enumeration type to integral type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#672">672</a></td>
+ <td>CD2</td>
+ <td>Sequencing of initialization in <I>new-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#673">673</a></td>
+ <td>NAD</td>
+ <td>Injection of names from <I>elaborated-type-specifier</I>s in <TT>friend</TT> declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#674">674</a></td>
+ <td>FDIS</td>
+ <td>&#8220;matching specialization&#8221; for a friend declaration</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#675">675</a></td>
+ <td>DRWP</td>
+ <td>Signedness of bit-field with typedef or template parameter type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#676">676</a></td>
+ <td>FDIS</td>
+ <td><I>static_assert-declaration</I>s and general requirements for declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#677">677</a></td>
+ <td>CD1</td>
+ <td>Deleted <TT>operator delete</TT> and virtual destructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#678">678</a></td>
+ <td>FDIS</td>
+ <td>Language linkage of member function parameter types and the ODR</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#679">679</a></td>
+ <td>CD1</td>
+ <td>Equivalence of <I>template-id</I>s and operator function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#680">680</a></td>
+ <td>CD2</td>
+ <td>What is a move constructor?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#681">681</a></td>
+ <td>CD1</td>
+ <td>Restrictions on declarators with late-specified return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#682">682</a></td>
+ <td>drafting</td>
+ <td>Missing description of lookup of template aliases</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#683">683</a></td>
+ <td>CD1</td>
+ <td>Requirements for trivial subobject special functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#684">684</a></td>
+ <td>CD1</td>
+ <td>Constant expressions involving the address of an automatic variable</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#685">685</a></td>
+ <td>CD2</td>
+ <td>Integral promotion of enumeration ignores fixed underlying type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#686">686</a></td>
+ <td>CD1</td>
+ <td>Type declarations/definitions in <I>type-specifier-seq</I>s and <I>type-id</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#687">687</a></td>
+ <td>extension</td>
+ <td><TT>template</TT> keyword with <I>unqualified-id</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#688">688</a></td>
+ <td>CD1</td>
+ <td>Constexpr constructors and static initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#689">689</a></td>
+ <td>open</td>
+ <td>Maximum values of signed and unsigned integers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#690">690</a></td>
+ <td>CD2</td>
+ <td>The dynamic type of an rvalue reference</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#691">691</a></td>
+ <td>FDIS</td>
+ <td>Template parameter packs in class template partial specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#692">692</a></td>
+ <td>FDIS</td>
+ <td>Partial ordering of variadic class template partial specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#693">693</a></td>
+ <td>CD2</td>
+ <td>New string types and deprecated conversion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#694">694</a></td>
+ <td>FDIS</td>
+ <td>Zero- and value-initialization of union objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#695">695</a></td>
+ <td>CD2</td>
+ <td>Compile-time calculation errors in constexpr functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#696">696</a></td>
+ <td>FDIS</td>
+ <td>Use of block-scope constants in local classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#697">697</a></td>
+ <td>open</td>
+ <td>Deduction rules apply to more than functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#698">698</a></td>
+ <td>open</td>
+ <td>The definition of &#8220;sequenced before&#8221; is too narrow</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#699">699</a></td>
+ <td>CD2</td>
+ <td>Must constexpr member functions be defined in the class <I>member-specification</I>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#700">700</a></td>
+ <td>FDIS</td>
+ <td>Constexpr member functions of class templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#701">701</a></td>
+ <td>CD2</td>
+ <td>When is the array-to-pointer conversion applied?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#702">702</a></td>
+ <td>CD2</td>
+ <td>Preferring conversion to <TT>std::initializer_list</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#703">703</a></td>
+ <td>CD2</td>
+ <td>Narrowing for literals that cannot be exactly represented</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#704">704</a></td>
+ <td>CD2</td>
+ <td>To which <I>postfix-expression</I>s does overload resolution apply?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#705">705</a></td>
+ <td>CD2</td>
+ <td>Suppressing argument-dependent lookup via parentheses</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#706">706</a></td>
+ <td>NAD</td>
+ <td>Use of <TT>auto</TT> with rvalue references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#707">707</a></td>
+ <td>CD2</td>
+ <td>Undefined behavior in integral-to-floating conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#708">708</a></td>
+ <td>open</td>
+ <td>Partial specialization of member templates of class templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#709">709</a></td>
+ <td>FDIS</td>
+ <td>Enumeration names as <I>nested-name-specifier</I>s in deduction failure</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#710">710</a></td>
+ <td>CD2</td>
+ <td>Data races during construction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#711">711</a></td>
+ <td>CD2</td>
+ <td><TT>auto</TT> with <I>braced-init-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#712">712</a></td>
+ <td>DRWP</td>
+ <td>Are integer constant operands of a <I>conditional-expression</I> &#8220;used?&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#713">713</a></td>
+ <td>CD2</td>
+ <td>Unclear note about cv-qualified function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#714">714</a></td>
+ <td>CD2</td>
+ <td>Static const data members and <I>braced-init-list</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#715">715</a></td>
+ <td>CD2</td>
+ <td>Class member access constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#716">716</a></td>
+ <td>CD2</td>
+ <td>Specifications that should apply only to non-static union data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#717">717</a></td>
+ <td>CD2</td>
+ <td>Unintentional restrictions on the use of <TT>thread_local</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#718">718</a></td>
+ <td>open</td>
+ <td>Non-class, non-function friend declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#719">719</a></td>
+ <td>CD2</td>
+ <td>Specifications for <I>operator-function-id</I> that should also apply to <I>literal-operator-id</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#720">720</a></td>
+ <td>CD2</td>
+ <td>Need examples of <I>lambda-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#721">721</a></td>
+ <td>CD2</td>
+ <td>Where must a variable be initialized to be used in a constant expression?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#722">722</a></td>
+ <td>CD2</td>
+ <td>Can <TT>nullptr</TT> be passed to an ellipsis?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#726">726</a></td>
+ <td>CD2</td>
+ <td>Atomic and non-atomic objects in the memory model</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#727">727</a></td>
+ <td>open</td>
+ <td>In-class explicit specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#728">728</a></td>
+ <td>extension</td>
+ <td>Restrictions on local classes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#729">729</a></td>
+ <td>DRWP</td>
+ <td>Qualification conversions and handlers of reference-to-pointer type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#730">730</a></td>
+ <td>CD2</td>
+ <td>Explicit specializations of members of non-template classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#731">731</a></td>
+ <td>CD2</td>
+ <td>Omitted reference qualification of member function type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#732">732</a></td>
+ <td>CD2</td>
+ <td>Late-specified return types in function definitions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#733">733</a></td>
+ <td>NAD</td>
+ <td>Reference qualification of copy assignment operators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#734">734</a></td>
+ <td>CD2</td>
+ <td>Are unique addresses required for namespace-scope variables?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#735">735</a></td>
+ <td>CD2</td>
+ <td>Missing case in specification of safely-derived pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#736">736</a></td>
+ <td>NAD</td>
+ <td>Is the <TT>&amp;</TT> <I>ref-qualifier</I> needed?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#737">737</a></td>
+ <td>CD2</td>
+ <td>Uninitialized trailing characters in string initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#738">738</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> not permitted by the syntax of constructor declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#739">739</a></td>
+ <td>DRWP</td>
+ <td>Signedness of plain bit-fields</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#740">740</a></td>
+ <td>CD2</td>
+ <td>Incorrect note on data races</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#741">741</a></td>
+ <td>FDIS</td>
+ <td>&#8220;plain&#8221; <TT>long long</TT> bit-fields</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#742">742</a></td>
+ <td>open</td>
+ <td>Postfix increment/decrement with long bit-field operands</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#743">743</a></td>
+ <td>CD2</td>
+ <td>Use of <TT>decltype</TT> in a <I>nested-name-specifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#744">744</a></td>
+ <td>CD2</td>
+ <td>Matching template arguments with template template parameters with parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#745">745</a></td>
+ <td>open</td>
+ <td>Effect of ill-formedness resulting from <TT>#error</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#746">746</a></td>
+ <td>CD2</td>
+ <td>Use of <TT>auto</TT> in <I>new-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#747">747</a></td>
+ <td>dup</td>
+ <td>Access of protected base classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#749">749</a></td>
+ <td>CD2</td>
+ <td>References to function types with a <I>cv-qualifier</I> or <I>ref-qualifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#750">750</a></td>
+ <td>CD2</td>
+ <td>Implementation constraints on reference-only closure objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#751">751</a></td>
+ <td>CD2</td>
+ <td>Deriving from closure classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#752">752</a></td>
+ <td>CD2</td>
+ <td>Name lookup in nested <I>lambda-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#753">753</a></td>
+ <td>CD2</td>
+ <td>Array names in lambda capture sets</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#754">754</a></td>
+ <td>CD2</td>
+ <td>Lambda expressions in default arguments of block-scope function declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#755">755</a></td>
+ <td>extension</td>
+ <td>Generalized <I>lambda-capture</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#756">756</a></td>
+ <td>CD2</td>
+ <td>Dropping cv-qualification on members of closure objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#757">757</a></td>
+ <td>CD2</td>
+ <td>Types without linkage in declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#758">758</a></td>
+ <td>FDIS</td>
+ <td>Missing cases of declarations that are not definitions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#759">759</a></td>
+ <td>CD2</td>
+ <td>Destruction of closure objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#760">760</a></td>
+ <td>CD2</td>
+ <td><TT>this</TT> inside a nested class of a non-static member function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#761">761</a></td>
+ <td>CD2</td>
+ <td>Inferred return type of closure object call operator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#762">762</a></td>
+ <td>CD2</td>
+ <td>Name lookup in the <I>compound-statement</I> of a lambda expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#763">763</a></td>
+ <td>CD2</td>
+ <td>Is a closure object's <TT>operator()</TT> inline?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#764">764</a></td>
+ <td>CD2</td>
+ <td>Capturing unused variables in a lambda expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#765">765</a></td>
+ <td>CD2</td>
+ <td>Local types in inline functions with external linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#766">766</a></td>
+ <td>CD2</td>
+ <td>Where may lambda expressions appear?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#767">767</a></td>
+ <td>CD2</td>
+ <td><TT>void</TT> and other unnamed <I>lambda-parameter</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#768">768</a></td>
+ <td>CD2</td>
+ <td>Ellipsis in a lambda parameter list</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#769">769</a></td>
+ <td>CD2</td>
+ <td>Initialization of closure objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#770">770</a></td>
+ <td>CD2</td>
+ <td>Ambiguity in late-specified return type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#771">771</a></td>
+ <td>CD2</td>
+ <td>Move-construction of reference members of closure objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#772">772</a></td>
+ <td>CD2</td>
+ <td><I>capture-default</I> in lambdas in local default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773">773</a></td>
+ <td>FDIS</td>
+ <td>Parentheses in address non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#774">774</a></td>
+ <td>CD2</td>
+ <td>Can a closure class be a POD?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#775">775</a></td>
+ <td>CD2</td>
+ <td>Capturing references to functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#776">776</a></td>
+ <td>CD2</td>
+ <td>Delegating constructors, destructors, and <TT>std::exit</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#777">777</a></td>
+ <td>CD2</td>
+ <td>Default arguments and parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#778">778</a></td>
+ <td>FDIS</td>
+ <td>Template parameter packs in non-type template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#779">779</a></td>
+ <td>CD2</td>
+ <td>Rvalue reference members of closure objects?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#782">782</a></td>
+ <td>CD2</td>
+ <td>Lambda expressions and argument-dependent lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#783">783</a></td>
+ <td>open</td>
+ <td>Definition of &#8220;argument&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#784">784</a></td>
+ <td>FDIS</td>
+ <td>List of incompatibilities with the previous Standard</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#785">785</a></td>
+ <td>CD2</td>
+ <td>&#8220;Execution sequence&#8221; is inappropriate phraseology</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#786">786</a></td>
+ <td>CD2</td>
+ <td>Definition of &#8220;thread&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#787">787</a></td>
+ <td>CD2</td>
+ <td>Unnecessary lexical undefined behavior</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#788">788</a></td>
+ <td>CD2</td>
+ <td>Relationship between locale and values of the execution character set</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#789">789</a></td>
+ <td>CD2</td>
+ <td>Deprecating trigraphs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#790">790</a></td>
+ <td>CD2</td>
+ <td>Concatenation of raw and non-raw string literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#792">792</a></td>
+ <td>CD2</td>
+ <td>Effects of <TT>std::quick_exit</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#793">793</a></td>
+ <td>CD2</td>
+ <td>Use of class members during destruction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#794">794</a></td>
+ <td>extension</td>
+ <td>Base-derived conversion in member type of pointer-to-member conversion</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#795">795</a></td>
+ <td>NAD</td>
+ <td>Dependency of lambdas on <TT>&lt;functional&gt;</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#796">796</a></td>
+ <td>CD2</td>
+ <td>Lifetime of a closure object with members captured by reference</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#797">797</a></td>
+ <td>CD2</td>
+ <td>Converting a no-capture lambda to a function type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#798">798</a></td>
+ <td>FDIS</td>
+ <td>Overloaded subscript operator described in clause 5</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#799">799</a></td>
+ <td>CD2</td>
+ <td>Can <TT>reinterpret_cast</TT> be used to cast an operand to its own type?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#800">800</a></td>
+ <td>NAD</td>
+ <td>Safely-derived pointers and object pointers converted from function pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#801">801</a></td>
+ <td>CD2</td>
+ <td>Casting away constness in a cast to rvalue reference type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#803">803</a></td>
+ <td>CD2</td>
+ <td><TT>sizeof</TT> an enumeration type with a fixed underlying type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#804">804</a></td>
+ <td>CD2</td>
+ <td>Deducing the type in <TT>new auto(x)</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#805">805</a></td>
+ <td>CD2</td>
+ <td>Which exception to throw for overflow in array size calculation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#806">806</a></td>
+ <td>CD2</td>
+ <td>Enumeration types in integral constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#807">807</a></td>
+ <td>NAD</td>
+ <td><TT>typeid</TT> expressions in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#808">808</a></td>
+ <td>CD2</td>
+ <td>Non-type <I>decl-specifier</I>s versus max-munch</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#809">809</a></td>
+ <td>CD2</td>
+ <td>Deprecation of the <TT>register</TT> keyword</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#810">810</a></td>
+ <td>CD2</td>
+ <td>Block-scope <TT>thread_local</TT> variables should be implicitly <TT>static</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#811">811</a></td>
+ <td>CD2</td>
+ <td>Unclear implications of const-qualification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#812">812</a></td>
+ <td>CD2</td>
+ <td>Duplicate names in inline namespaces</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#813">813</a></td>
+ <td>open</td>
+ <td><TT>typename</TT> in a <I>using-declaration</I> with a non-dependent name</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#814">814</a></td>
+ <td>CD2</td>
+ <td>Attribute to indicate that a function throws nothing</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#815">815</a></td>
+ <td>CD2</td>
+ <td>Parameter pack expansion inside attributes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#816">816</a></td>
+ <td>CD2</td>
+ <td>Diagnosing violations of <TT>[[final]]</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#817">817</a></td>
+ <td>CD2</td>
+ <td>Meaning of <TT>[[final]]</TT> applied to a class definition</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#818">818</a></td>
+ <td>CD2</td>
+ <td>Function parameter packs in non-final positions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#819">819</a></td>
+ <td>NAD</td>
+ <td>Access control and deleted implicitly-declared special member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#820">820</a></td>
+ <td>CD2</td>
+ <td>Deprecation of <TT>export</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#822">822</a></td>
+ <td>extension</td>
+ <td>Additional contexts for template aliases</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#823">823</a></td>
+ <td>CD2</td>
+ <td>Literal types with constexpr conversions as non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#828">828</a></td>
+ <td>CD2</td>
+ <td>Destruction of exception objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#829">829</a></td>
+ <td>NAD</td>
+ <td>At what point is <TT>std::unexpected</TT> called?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#830">830</a></td>
+ <td>CD2</td>
+ <td>Deprecating exception specifications</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#831">831</a></td>
+ <td>CD2</td>
+ <td>Limit on recursively nested template instantiations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#832">832</a></td>
+ <td>CD2</td>
+ <td>Value of preprocessing numbers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#833">833</a></td>
+ <td>CD2</td>
+ <td>Explicit conversion of a scoped enumeration value to a floating type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#834">834</a></td>
+ <td>CD2</td>
+ <td>What is an &#8220;ordinary string literal&#8221;?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#835">835</a></td>
+ <td>CD2</td>
+ <td>Scoped enumerations and the &#8220;usual arithmetic conversions&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#836">836</a></td>
+ <td>NAD</td>
+ <td><TT>[[noreturn]]</TT> applied to function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#837">837</a></td>
+ <td>FDIS</td>
+ <td>Constexpr functions and <TT>return</TT> <I>braced-init-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#838">838</a></td>
+ <td>FDIS</td>
+ <td>Use of <TT>this</TT> in a <I>brace-or-equal-initializer</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#839">839</a></td>
+ <td>dup</td>
+ <td><TT>sizeof</TT> with opaque enumerations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#840">840</a></td>
+ <td>CD2</td>
+ <td>Rvalue references as nontype template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#842">842</a></td>
+ <td>CD2</td>
+ <td>Casting to rvalue reference type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#845">845</a></td>
+ <td>CD2</td>
+ <td>What is the &#8220;first declaration&#8221; of an explicit specialization?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#846">846</a></td>
+ <td>CD2</td>
+ <td>Rvalue references to functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#847">847</a></td>
+ <td>CD2</td>
+ <td>Error in rvalue reference deduction example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#850">850</a></td>
+ <td>CD2</td>
+ <td>Restrictions on use of non-static data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#852">852</a></td>
+ <td>open</td>
+ <td><I>using-declaration</I>s and dependent base classes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#853">853</a></td>
+ <td>CD2</td>
+ <td>Support for relaxed pointer safety</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#854">854</a></td>
+ <td>CD2</td>
+ <td>Left shift and unsigned extended types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#855">855</a></td>
+ <td>CD2</td>
+ <td>Incorrect comments in <I>braced-init-list</I> assignment example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#858">858</a></td>
+ <td>CD2</td>
+ <td>Example binding an rvalue reference to an lvalue</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#860">860</a></td>
+ <td>FDIS</td>
+ <td>Explicit qualification of constexpr member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#861">861</a></td>
+ <td>CD2</td>
+ <td>Unintended ambiguity in inline namespace lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#862">862</a></td>
+ <td>CD2</td>
+ <td>Undefined behavior with enumerator value overflow</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#863">863</a></td>
+ <td>CD2</td>
+ <td>Rvalue reference cast to incomplete type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#864">864</a></td>
+ <td>FDIS</td>
+ <td><I>braced-init-list</I> in the range-based <TT>for</TT> statement</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#865">865</a></td>
+ <td>CD2</td>
+ <td>Initializing a <TT>std::initializer_list</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#869">869</a></td>
+ <td>CD2</td>
+ <td>Uninitialized <TT>thread_local</TT> objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#872">872</a></td>
+ <td>CD2</td>
+ <td>Lexical issues with raw strings</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#873">873</a></td>
+ <td>FDIS</td>
+ <td>Deducing rvalue references in declarative contexts</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#874">874</a></td>
+ <td>CD2</td>
+ <td>Class-scope definitions of enumeration types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#876">876</a></td>
+ <td>CD2</td>
+ <td>Type references in rvalue reference deduction specification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#877">877</a></td>
+ <td>CD2</td>
+ <td>Viable functions and binding references to rvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#879">879</a></td>
+ <td>CD2</td>
+ <td>Missing built-in comparison operators for pointer types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#880">880</a></td>
+ <td>CD2</td>
+ <td>Built-in conditional operator for scoped enumerations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#882">882</a></td>
+ <td>CD2</td>
+ <td>Defining <TT>main</TT> as deleted</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#883">883</a></td>
+ <td>CD2</td>
+ <td><TT>std::memcpy</TT> vs <TT>std::memmove</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#884">884</a></td>
+ <td>CD2</td>
+ <td>Defining an explicitly-specialized static data member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#885">885</a></td>
+ <td>NAD</td>
+ <td>Partial ordering of function templates with unordered parameter pairs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#886">886</a></td>
+ <td>CD2</td>
+ <td>Member initializers and aggregates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#887">887</a></td>
+ <td>CD2</td>
+ <td>Move construction of thrown object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#888">888</a></td>
+ <td>CD2</td>
+ <td>Union member initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#891">891</a></td>
+ <td>CD2</td>
+ <td><TT>const_cast</TT> to rvalue reference from objectless rvalue</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#892">892</a></td>
+ <td>FDIS</td>
+ <td>Missing requirements for constexpr constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#893">893</a></td>
+ <td>NAD</td>
+ <td>Brace syntax for <I>enumerator-definition</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#896">896</a></td>
+ <td>CD2</td>
+ <td>Rvalue references and rvalue-reference conversion functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#897">897</a></td>
+ <td>open</td>
+ <td><TT>_Pragma</TT> and extended <I>string-literal</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#898">898</a></td>
+ <td>FDIS</td>
+ <td>Declarations in constexpr functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#899">899</a></td>
+ <td>CD2</td>
+ <td>Explicit conversion functions in direct class initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#900">900</a></td>
+ <td>NAD</td>
+ <td>Lifetime of temporaries in range-based <TT>for</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#901">901</a></td>
+ <td>drafting</td>
+ <td>Deleted <TT>operator delete</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#902">902</a></td>
+ <td>NAD</td>
+ <td>In-class initialization of non-constant static data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#903">903</a></td>
+ <td>DRWP</td>
+ <td>Value-dependent integral null pointer constants</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#904">904</a></td>
+ <td>CD2</td>
+ <td>Parameter packs in <I>lambda-capture</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#905">905</a></td>
+ <td>CD2</td>
+ <td>Explicit defaulted copy constructors and trivial copyability</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#906">906</a></td>
+ <td>CD2</td>
+ <td>Which special member functions can be defaulted?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#908">908</a></td>
+ <td>CD2</td>
+ <td>Deleted global allocation and deallocation functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#909">909</a></td>
+ <td>NAD</td>
+ <td>Old-style casts with conversion functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#910">910</a></td>
+ <td>CD2</td>
+ <td>Move constructors and implicitly-declared copy constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#912">912</a></td>
+ <td>DRWP</td>
+ <td>Character literals and <I>universal-character-name</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#913">913</a></td>
+ <td>CD2</td>
+ <td>Deduction rules for array- and function-type conversion functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#914">914</a></td>
+ <td>extension</td>
+ <td>Value-initialization of array types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#915">915</a></td>
+ <td>CD2</td>
+ <td>Deleted specializations of member function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#916">916</a></td>
+ <td>open</td>
+ <td>Does a reference type have a destructor?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#919">919</a></td>
+ <td>CD2</td>
+ <td>Contradictions regarding inline namespaces</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#920">920</a></td>
+ <td>CD2</td>
+ <td>Interaction of inline namespaces and <I>using-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#921">921</a></td>
+ <td>CD2</td>
+ <td>Unclear specification of inline namespaces</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#922">922</a></td>
+ <td>CD2</td>
+ <td>Implicit default constructor definitions and <TT>const</TT> variant members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#923">923</a></td>
+ <td>CD2</td>
+ <td>Inline explicit specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#924">924</a></td>
+ <td>FDIS</td>
+ <td><I>alias-declaration</I> as a class member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#925">925</a></td>
+ <td>open</td>
+ <td>Type of character literals in preprocessor expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#926">926</a></td>
+ <td>CD2</td>
+ <td>Inline unnamed namespaces</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#927">927</a></td>
+ <td>CD2</td>
+ <td>Implicitly-deleted default constructors and member initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#928">928</a></td>
+ <td>CD2</td>
+ <td>Defaulting a function that would be implicitly defined as deleted</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#929">929</a></td>
+ <td>CD2</td>
+ <td>What is a template alias?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#930">930</a></td>
+ <td>CD2</td>
+ <td><TT>alignof</TT> with incomplete array type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#931">931</a></td>
+ <td>CD2</td>
+ <td>Confusing reference to the length of a user-defined string literal</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#932">932</a></td>
+ <td>CD2</td>
+ <td>UCNs in closing delimiters of raw string literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#933">933</a></td>
+ <td>CD2</td>
+ <td>32-bit UCNs with 16-bit <TT>wchar_t</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#934">934</a></td>
+ <td>CD2</td>
+ <td>List-initialization of references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#935">935</a></td>
+ <td>CD2</td>
+ <td>Missing overloads for character types for user-defined literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#936">936</a></td>
+ <td>CD2</td>
+ <td>Array initialization with new string literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#937">937</a></td>
+ <td>NAD</td>
+ <td>Restrictions on values of template arguments in user-defined literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#938">938</a></td>
+ <td>FDIS</td>
+ <td>Initializer lists and array new</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#939">939</a></td>
+ <td>CD2</td>
+ <td>Explicitly checking virtual function overriding</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#940">940</a></td>
+ <td>CD2</td>
+ <td>Global anonymous unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#941">941</a></td>
+ <td>FDIS</td>
+ <td>Explicit specialization of deleted function template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#942">942</a></td>
+ <td>CD2</td>
+ <td>Is <TT>this</TT> an entity?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#943">943</a></td>
+ <td>open</td>
+ <td>Is <TT>T()</TT> a temporary?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#944">944</a></td>
+ <td>open</td>
+ <td><TT>reinterpret_cast</TT> for all types with the same size and alignment</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#945">945</a></td>
+ <td>FDIS</td>
+ <td>Use of <TT>this</TT> in a late-specified return type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#946">946</a></td>
+ <td>CD2</td>
+ <td>Order of destruction of local static objects and calls to <TT>std::atexit</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#947">947</a></td>
+ <td>extension</td>
+ <td>Deducing type template arguments from default function arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#948">948</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> in <I>condition</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#949">949</a></td>
+ <td>open</td>
+ <td>Requirements for freestanding implementations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#950">950</a></td>
+ <td>CD2</td>
+ <td>Use of <TT>decltype</TT> as a <I>class-name</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#951">951</a></td>
+ <td>CD2</td>
+ <td>Problems with <I>attribute-specifier</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#952">952</a></td>
+ <td>drafting</td>
+ <td>Insufficient description of &#8220;naming class&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#953">953</a></td>
+ <td>CD2</td>
+ <td>Rvalue references and function viability</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#954">954</a></td>
+ <td>open</td>
+ <td>Overload resolution of conversion operator templates with built-in types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#955">955</a></td>
+ <td>CD2</td>
+ <td>Can a closure type's <TT>operator()</TT> be virtual?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#956">956</a></td>
+ <td>CD2</td>
+ <td>Function prototype scope with late-specified return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#957">957</a></td>
+ <td>CD2</td>
+ <td>Alternative tokens and <I>attribute-token</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#958">958</a></td>
+ <td>NAD</td>
+ <td>Lambdas and <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#959">959</a></td>
+ <td>CD2</td>
+ <td>Alignment attribute for class and enumeration types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#960">960</a></td>
+ <td>CD2</td>
+ <td>Covariant functions and lvalue/rvalue references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#961">961</a></td>
+ <td>CD2</td>
+ <td>Overload resolution and conversion of <TT>std::nullptr_t</TT> to <TT>bool</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#962">962</a></td>
+ <td>CD2</td>
+ <td>Attributes appertaining to class and enum types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#963">963</a></td>
+ <td>CD2</td>
+ <td>Comparing <TT>nullptr</TT> with 0</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#964">964</a></td>
+ <td>FDIS</td>
+ <td>Incorrect description of when the lvalue-to-rvalue conversion applies</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#965">965</a></td>
+ <td>CD2</td>
+ <td>Limiting the applicability of the <TT>carries_dependency</TT> attribute</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#966">966</a></td>
+ <td>CD2</td>
+ <td>Nested types without linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#967">967</a></td>
+ <td>open</td>
+ <td>Exception specification of replacement allocation function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#968">968</a></td>
+ <td>CD2</td>
+ <td>Syntactic ambiguity of the attribute notation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#969">969</a></td>
+ <td>CD2</td>
+ <td>Explicit instantiation declarations of class template specializations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#970">970</a></td>
+ <td>CD2</td>
+ <td>Consistent use of &#8220;appertain&#8221; and &#8220;apply&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#971">971</a></td>
+ <td>FDIS</td>
+ <td>Incorrect treatment of <I>exception-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#972">972</a></td>
+ <td>FDIS</td>
+ <td>Allowing multiple <I>attribute-specifier</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#973">973</a></td>
+ <td>CD2</td>
+ <td>Function types in <I>exception-specification</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#974">974</a></td>
+ <td>DRWP</td>
+ <td>Default arguments for lambdas</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#975">975</a></td>
+ <td>DRWP</td>
+ <td>Restrictions on return type deduction for lambdas</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#976">976</a></td>
+ <td>CD2</td>
+ <td>Deduction for <TT>const T&amp;</TT> conversion operators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#977">977</a></td>
+ <td>DRWP</td>
+ <td>When is an enumeration type complete?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#978">978</a></td>
+ <td>CD2</td>
+ <td>Incorrect specification for copy initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#979">979</a></td>
+ <td>CD2</td>
+ <td>Position of <I>attribute-specifier</I> in declarator syntax</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#980">980</a></td>
+ <td>CD2</td>
+ <td>Explicit instantiation of a member of a class template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#981">981</a></td>
+ <td>FDIS</td>
+ <td>Constexpr constructor templates and literal types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#982">982</a></td>
+ <td>NAD</td>
+ <td>Initialization with an empty initializer list</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#983">983</a></td>
+ <td>CD2</td>
+ <td>Ambiguous pointer-to-member constant</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#984">984</a></td>
+ <td>CD2</td>
+ <td>&#8220;Deduced type&#8221; is unclear in <TT>auto</TT> type deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#985">985</a></td>
+ <td>FDIS</td>
+ <td>Alternative tokens and user-defined literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#986">986</a></td>
+ <td>CD2</td>
+ <td>Transitivity of <I>using-directive</I>s versus qualified lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#987">987</a></td>
+ <td>open</td>
+ <td>Which declarations introduce namespace members?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#988">988</a></td>
+ <td>CD2</td>
+ <td>Reference-to-reference collapsing with <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#989">989</a></td>
+ <td>CD2</td>
+ <td>Misplaced list-initialization example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990">990</a></td>
+ <td>CD2</td>
+ <td>Value initialization with multiple initializer-list constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#991">991</a></td>
+ <td>CD2</td>
+ <td>Reference parameters of constexpr functions and constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#992">992</a></td>
+ <td>NAD</td>
+ <td>Inheriting explicitness</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#993">993</a></td>
+ <td>FDIS</td>
+ <td>Freedom to perform instantiation at the end of the translation unit</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#994">994</a></td>
+ <td>FDIS</td>
+ <td><I>braced-init-list</I> as a default argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#995">995</a></td>
+ <td>CD2</td>
+ <td>Incorrect example for <I>using-declaration</I> and explicit instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#996">996</a></td>
+ <td>FDIS</td>
+ <td>Ambiguous partial specializations of member class templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#997">997</a></td>
+ <td>FDIS</td>
+ <td>Argument-dependent lookup and dependent function template parameter types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#998">998</a></td>
+ <td>dup</td>
+ <td>Function parameter transformations and template functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#999">999</a></td>
+ <td>CD2</td>
+ <td>&#8220;Implicit&#8221; or &#8220;implied&#8221; object argument/parameter?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1000">1000</a></td>
+ <td>CD2</td>
+ <td>Mistaking member typedefs for constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1001">1001</a></td>
+ <td>drafting</td>
+ <td>Parameter type adjustment in dependent parameter types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1002">1002</a></td>
+ <td>NAD</td>
+ <td>Pack expansion for function arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1003">1003</a></td>
+ <td>DRWP</td>
+ <td>Acceptable definitions of <TT>main</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1004">1004</a></td>
+ <td>FDIS</td>
+ <td>Injected-class-names as arguments for template template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1005">1005</a></td>
+ <td>NAD</td>
+ <td>Qualified name resolution in member functions of class templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1006">1006</a></td>
+ <td>FDIS</td>
+ <td><TT>std::nullptr_t</TT> as a non-type template parameter</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1007">1007</a></td>
+ <td>NAD</td>
+ <td>Protected access and pointers to members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1008">1008</a></td>
+ <td>extension</td>
+ <td>Querying the alignment of an object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1009">1009</a></td>
+ <td>FDIS</td>
+ <td>Missing cases in the <I>declarator-id</I> of a function template declaration</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1010">1010</a></td>
+ <td>CD2</td>
+ <td>Address of object with dynamic storage duration in constant expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1011">1011</a></td>
+ <td>FDIS</td>
+ <td>Standard conversions that cannot be inverted</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1012">1012</a></td>
+ <td>FDIS</td>
+ <td>Undeprecating <TT>static</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1013">1013</a></td>
+ <td>DRWP</td>
+ <td>Uninitialized <TT>std::nullptr_t</TT> objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1014">1014</a></td>
+ <td>NAD</td>
+ <td>Overload resolution between <TT>const T&amp;</TT> and <TT>T&amp;&amp;</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1015">1015</a></td>
+ <td>FDIS</td>
+ <td>Template arguments and argument-dependent lookup</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1016">1016</a></td>
+ <td>FDIS</td>
+ <td>Overloadable declarations, function templates, and references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1017">1017</a></td>
+ <td>FDIS</td>
+ <td>Member access transformation in unevaluated operands</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1018">1018</a></td>
+ <td>FDIS</td>
+ <td>Ambiguity between <I>simple-declaration</I> and <I>attribute-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1019">1019</a></td>
+ <td>dup</td>
+ <td>Dependent <I>simple-template-id</I>s in <I>base-specifier</I>s and <I>mem-initializer</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1020">1020</a></td>
+ <td>FDIS</td>
+ <td>Implicitly-defined copy constructors and explicit base class constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1021">1021</a></td>
+ <td>open</td>
+ <td>Definitions of namespace members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1022">1022</a></td>
+ <td>FDIS</td>
+ <td>Can an enumeration variable have values outside the values of the enumeration?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1023">1023</a></td>
+ <td>dup</td>
+ <td><TT>thread_local</TT> objects as non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1024">1024</a></td>
+ <td>DRWP</td>
+ <td>Limits on multicharacter literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1025">1025</a></td>
+ <td>FDIS</td>
+ <td>Use of a reference as a non-type template argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1026">1026</a></td>
+ <td>NAD</td>
+ <td>Cv-qualified non-class rvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1027">1027</a></td>
+ <td>drafting</td>
+ <td>Type consistency and reallocation of scalar types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1028">1028</a></td>
+ <td>open</td>
+ <td>Dependent names in non-defining declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1029">1029</a></td>
+ <td>FDIS</td>
+ <td>Type of a destructor call</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030">1030</a></td>
+ <td>FDIS</td>
+ <td>Evaluation order in <I>initializer-list</I>s used in aggregate initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1031">1031</a></td>
+ <td>FDIS</td>
+ <td>Optional elements in attributes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1032">1032</a></td>
+ <td>FDIS</td>
+ <td>Empty pack expansions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1033">1033</a></td>
+ <td>FDIS</td>
+ <td>Restrictions on alignment attributes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1034">1034</a></td>
+ <td>FDIS</td>
+ <td>Attributes for <TT>return</TT> statements in lambdas</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1035">1035</a></td>
+ <td>FDIS</td>
+ <td>Omitted and required <I>decl-specifier</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1036">1036</a></td>
+ <td>FDIS</td>
+ <td>Alignment attribute in an <I>exception-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1037">1037</a></td>
+ <td>FDIS</td>
+ <td>Requirements for operands of <I>delete-expression</I>s and deallocation functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1038">1038</a></td>
+ <td>open</td>
+ <td>Overload resolution of <TT>&amp;x.static_func</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1039">1039</a></td>
+ <td>dup</td>
+ <td>Coordinating C and C++ alignment specifications</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1040">1040</a></td>
+ <td>NAD</td>
+ <td>Memory model issues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1041">1041</a></td>
+ <td>dup</td>
+ <td><I>alias-declaration</I>s as class members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1042">1042</a></td>
+ <td>FDIS</td>
+ <td>Attributes in <I>alias-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1043">1043</a></td>
+ <td>FDIS</td>
+ <td>Qualified name lookup in the current instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1044">1044</a></td>
+ <td>FDIS</td>
+ <td>Point of declaration for an <I>alias-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1045">1045</a></td>
+ <td>NAD</td>
+ <td>Requiring explicit instantiation declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1046">1046</a></td>
+ <td>open</td>
+ <td>What is a &#8220;use&#8221; of a class specialization?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1047">1047</a></td>
+ <td>FDIS</td>
+ <td>When is <TT>typeid</TT> value-dependent?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1048">1048</a></td>
+ <td>extension</td>
+ <td><TT>auto</TT> deduction and lambda return type deduction.</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1049">1049</a></td>
+ <td>open</td>
+ <td>Copy elision through reference parameters of inline functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1050">1050</a></td>
+ <td>NAD</td>
+ <td>Effects of thread support on object lifetime</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1051">1051</a></td>
+ <td>FDIS</td>
+ <td>Reference members and generated copy constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1052">1052</a></td>
+ <td>dup</td>
+ <td><TT>const</TT> non-static data member and PODness</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1053">1053</a></td>
+ <td>NAD</td>
+ <td>Terminate vs undefined behavior for noexcept violation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1054">1054</a></td>
+ <td>FDIS</td>
+ <td>Lvalue-to-rvalue conversions in expression statements</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1055">1055</a></td>
+ <td>FDIS</td>
+ <td>Permissible uses of <TT>void</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1056">1056</a></td>
+ <td>FDIS</td>
+ <td>Template aliases, member definitions, and the current instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1057">1057</a></td>
+ <td>FDIS</td>
+ <td><TT>decltype</TT> and the current instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1058">1058</a></td>
+ <td>NAD</td>
+ <td>Reference binding of incompatible array types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1059">1059</a></td>
+ <td>DRWP</td>
+ <td>Cv-qualified array types (with rvalues)</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1060">1060</a></td>
+ <td>FDIS</td>
+ <td>Scoped enumerators in integral constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1061">1061</a></td>
+ <td>FDIS</td>
+ <td>Negative array bounds in a <I>new-expression</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1062">1062</a></td>
+ <td>FDIS</td>
+ <td>Syntax of <I>attribute-specifier</I>s in lambdas</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1063">1063</a></td>
+ <td>FDIS</td>
+ <td><TT>[[hiding]]</TT> with non-attribute declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1064">1064</a></td>
+ <td>FDIS</td>
+ <td>Defaulted move constructor for a union</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1065">1065</a></td>
+ <td>FDIS</td>
+ <td><TT>[[hiding]]</TT> with <TT>[[override]]</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1066">1066</a></td>
+ <td>FDIS</td>
+ <td>When is a copy/move assignment operator implicitly defined?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1067">1067</a></td>
+ <td>NAD</td>
+ <td><TT>[[hiding]]</TT>, <I>using-declaration</I>s, and multiple inheritance</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1068">1068</a></td>
+ <td>FDIS</td>
+ <td>Template aliases with default arguments and template parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1069">1069</a></td>
+ <td>FDIS</td>
+ <td>Incorrect function type with <I>trailing-return-type</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1070">1070</a></td>
+ <td>FDIS</td>
+ <td>Missing initializer clauses in aggregate initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1071">1071</a></td>
+ <td>FDIS</td>
+ <td>Literal class types and trivial default constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1072">1072</a></td>
+ <td>FDIS</td>
+ <td>Scoped enumerator with the same name as its containing class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1073">1073</a></td>
+ <td>FDIS</td>
+ <td>Merging <I>dynamic-exception-specification</I>s and <I>noexcept-specification</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1074">1074</a></td>
+ <td>FDIS</td>
+ <td>Value-dependent <I>noexcept-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1075">1075</a></td>
+ <td>FDIS</td>
+ <td>Grammar does not allow template alias in <I>type-name</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1076">1076</a></td>
+ <td>open</td>
+ <td>Value categories and lvalue temporaries</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1077">1077</a></td>
+ <td>extension</td>
+ <td>Explicit specializations in non-containing namespaces</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1078">1078</a></td>
+ <td>NAD</td>
+ <td>Narrowing and the usual arithmetic conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1079">1079</a></td>
+ <td>FDIS</td>
+ <td>Overload resolution involving aggregate initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1080">1080</a></td>
+ <td>FDIS</td>
+ <td>Confusing relationship between templates and copy constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1081">1081</a></td>
+ <td>FDIS</td>
+ <td>Defaulted destructor and unusable operator delete</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1082">1082</a></td>
+ <td>FDIS</td>
+ <td>Implicit copy function if subobject has none?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1083">1083</a></td>
+ <td>FDIS</td>
+ <td>Passing an object to ellipsis with non-trivial move constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1084">1084</a></td>
+ <td>NAD</td>
+ <td>Conditions for a deleted move function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1085">1085</a></td>
+ <td>NAD</td>
+ <td>Move assignment operators and virtual bases</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1086">1086</a></td>
+ <td>FDIS</td>
+ <td><TT>const_cast</TT> to rvalue reference to function type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1087">1087</a></td>
+ <td>FDIS</td>
+ <td>Additional applications of issue 899</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1088">1088</a></td>
+ <td>FDIS</td>
+ <td>Dependent non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1089">1089</a></td>
+ <td>drafting</td>
+ <td>Template parameters in member selections</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1090">1090</a></td>
+ <td>FDIS</td>
+ <td>Alignment of subobjects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1091">1091</a></td>
+ <td>FDIS</td>
+ <td>Inconsistent use of the term &#8220;object expression&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1092">1092</a></td>
+ <td>drafting</td>
+ <td>Cycles in overload resolution during instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1093">1093</a></td>
+ <td>DRWP</td>
+ <td>Value-initializing non-objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1094">1094</a></td>
+ <td>FDIS</td>
+ <td>Converting floating-point values to scoped enumeration types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1095">1095</a></td>
+ <td>FDIS</td>
+ <td>List-initialization of references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1096">1096</a></td>
+ <td>FDIS</td>
+ <td>Missing requirement for template definitions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1097">1097</a></td>
+ <td>NAD</td>
+ <td>Aggregate initialization of function parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1098">1098</a></td>
+ <td>FDIS</td>
+ <td>Pointer conversions in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1099">1099</a></td>
+ <td>FDIS</td>
+ <td>Infinite recursion in <TT>constexpr</TT> functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1100">1100</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> conversion functions and non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1101">1101</a></td>
+ <td>FDIS</td>
+ <td>Non-integral initialized static data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1102">1102</a></td>
+ <td>FDIS</td>
+ <td>Better example of undefined behavior</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1103">1103</a></td>
+ <td>FDIS</td>
+ <td>Reversion of phase 1 and 2 transformations in raw string literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1104">1104</a></td>
+ <td>FDIS</td>
+ <td>Global-scope template arguments vs the <TT>&lt;:</TT> digraph</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1105">1105</a></td>
+ <td>FDIS</td>
+ <td>Issues relating to TR 10176:2003</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1106">1106</a></td>
+ <td>FDIS</td>
+ <td>Need more detail in <TT>nullptr</TT> keyword description</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1107">1107</a></td>
+ <td>FDIS</td>
+ <td>Overload resolution for user-defined integer literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1108">1108</a></td>
+ <td>NAD</td>
+ <td>User-defined literals have not been implemented</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1109">1109</a></td>
+ <td>FDIS</td>
+ <td>When is &#8220;use&#8221; a reference to the ODR meaning?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1110">1110</a></td>
+ <td>NAD</td>
+ <td>Incomplete return type should be allowed in <TT>decltype</TT> operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1111">1111</a></td>
+ <td>FDIS</td>
+ <td>Remove dual-scope lookup of member template names</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1112">1112</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> variables should have internal linkage like <TT>const</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1113">1113</a></td>
+ <td>FDIS</td>
+ <td>Linkage of namespace member of unnamed namespace</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1114">1114</a></td>
+ <td>FDIS</td>
+ <td>Incorrect use of placement <TT>new</TT> in example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1115">1115</a></td>
+ <td>FDIS</td>
+ <td>C-compatible alignment specification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1116">1116</a></td>
+ <td>drafting</td>
+ <td>Aliasing of union members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1117">1117</a></td>
+ <td>FDIS</td>
+ <td>Incorrect note about xvalue member access expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1118">1118</a></td>
+ <td>NAD</td>
+ <td>Implicit lambda capture via explicit copy constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1119">1119</a></td>
+ <td>FDIS</td>
+ <td>Missing case in description of member access ambiguity</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1120">1120</a></td>
+ <td>FDIS</td>
+ <td><TT>reinterpret_cast</TT> and <TT>void*</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1121">1121</a></td>
+ <td>FDIS</td>
+ <td>Unnecessary ambiguity error in formation of pointer to member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1122">1122</a></td>
+ <td>FDIS</td>
+ <td>Circular definition of <TT>std::size_t</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1123">1123</a></td>
+ <td>FDIS</td>
+ <td>Destructors should be <TT>noexcept</TT> by default</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1124">1124</a></td>
+ <td>NAD</td>
+ <td>Error in description of value category of pointer-to-member expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1125">1125</a></td>
+ <td>FDIS</td>
+ <td>Unclear definition of &#8220;potential constant expression&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1126">1126</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> functions in <TT>const</TT> initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1127">1127</a></td>
+ <td>FDIS</td>
+ <td>Overload resolution in <TT>constexpr</TT> functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1128">1128</a></td>
+ <td>FDIS</td>
+ <td><I>attribute-specifier</I>s in <I>decl-specifier-seq</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1129">1129</a></td>
+ <td>FDIS</td>
+ <td>Default <TT>nothrow</TT> for <TT>constexpr</TT> functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1130">1130</a></td>
+ <td>FDIS</td>
+ <td>Function parameter type adjustments and <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1131">1131</a></td>
+ <td>FDIS</td>
+ <td>Template aliases in <I>elaborated-type-specifier</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1132">1132</a></td>
+ <td>NAD</td>
+ <td>Keyword vs attribute for <TT>noreturn</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1133">1133</a></td>
+ <td>FDIS</td>
+ <td>Keywords vs attributes for control of hiding and overriding</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1134">1134</a></td>
+ <td>FDIS</td>
+ <td>When is an explicitly-defaulted function defined?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1135">1135</a></td>
+ <td>FDIS</td>
+ <td>Explicitly-defaulted non-public special member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1136">1136</a></td>
+ <td>FDIS</td>
+ <td>Explicitly-defaulted explicit constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1137">1137</a></td>
+ <td>FDIS</td>
+ <td>Explicitly-defaulted virtual special member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1138">1138</a></td>
+ <td>FDIS</td>
+ <td>Rvalue-ness check for rvalue reference binding is wrong</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1139">1139</a></td>
+ <td>FDIS</td>
+ <td>Rvalue reference binding to scalar xvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1140">1140</a></td>
+ <td>FDIS</td>
+ <td>Incorrect redefinition of POD class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1141">1141</a></td>
+ <td>NAD</td>
+ <td>Non-static data member initializers have not been implemented</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1142">1142</a></td>
+ <td>FDIS</td>
+ <td><TT>friend</TT> declaration of member function of containing class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1143">1143</a></td>
+ <td>NAD</td>
+ <td>Move semantics for <TT>*this</TT> have not been implemented</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1144">1144</a></td>
+ <td>FDIS</td>
+ <td>Remove access declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1145">1145</a></td>
+ <td>FDIS</td>
+ <td>Defaulting and triviality</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1146">1146</a></td>
+ <td>FDIS</td>
+ <td><I>exception-specification</I>s of defaulted functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1147">1147</a></td>
+ <td>FDIS</td>
+ <td>Destructors should be default <TT>nothrow</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1148">1148</a></td>
+ <td>FDIS</td>
+ <td>Copy elision and move construction of function parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1149">1149</a></td>
+ <td>FDIS</td>
+ <td>Trivial non-public copy operators in subobjects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1150">1150</a></td>
+ <td>NAD</td>
+ <td>Inheriting constructors have not been implemented</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1151">1151</a></td>
+ <td>FDIS</td>
+ <td>Overload resolution with initializer-list and non-list constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1152">1152</a></td>
+ <td>FDIS</td>
+ <td>Rules for determining existence of implicit conversion sequence</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1153">1153</a></td>
+ <td>FDIS</td>
+ <td>Type matching in address of overloaded function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1154">1154</a></td>
+ <td>FDIS</td>
+ <td>Address of <TT>thread_local</TT> variable as non-type template argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1155">1155</a></td>
+ <td>FDIS</td>
+ <td>Internal-linkage non-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1156">1156</a></td>
+ <td>FDIS</td>
+ <td>Partial ordering in a non-call context</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1157">1157</a></td>
+ <td>open</td>
+ <td>Partial ordering of function templates is still underspecified</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1158">1158</a></td>
+ <td>FDIS</td>
+ <td>Recursive instantiation via alias template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1159">1159</a></td>
+ <td>FDIS</td>
+ <td>Class and enumeration definitions in template aliases</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1160">1160</a></td>
+ <td>FDIS</td>
+ <td>Definitions of template members and the current instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1161">1161</a></td>
+ <td>FDIS</td>
+ <td>Dependent <I>nested-name-specifier</I> in a pointer-to-member declarator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1162">1162</a></td>
+ <td>NAD</td>
+ <td>Dependent <I>elaborated-type-specifier</I>s in non-deduced contexts</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1163">1163</a></td>
+ <td>NAD</td>
+ <td><TT>extern template</TT> prevents inlining functions not marked <TT>inline</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1164">1164</a></td>
+ <td>FDIS</td>
+ <td>Partial ordering of <TT>f(T&amp;)</TT> and <TT>f(T&amp;&amp;)</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1165">1165</a></td>
+ <td>FDIS</td>
+ <td>Exceptions when destroying array elements</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1166">1166</a></td>
+ <td>FDIS</td>
+ <td><I>exception-declaration</I>s that do not declare objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1167">1167</a></td>
+ <td>FDIS</td>
+ <td><I>function-try-block</I>s for destructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1168">1168</a></td>
+ <td>FDIS</td>
+ <td>Additional reasons to call <TT>std::terminate</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1169">1169</a></td>
+ <td>FDIS</td>
+ <td>Missing feature macro for strict pointer safety</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">1170</a></td>
+ <td>FDIS</td>
+ <td>Access checking during template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1171">1171</a></td>
+ <td>FDIS</td>
+ <td>Partial stack unwinding with <TT>noexcept</TT> violation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1172">1172</a></td>
+ <td>drafting</td>
+ <td>&#8220;instantiation-dependent&#8221; constructs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1173">1173</a></td>
+ <td>FDIS</td>
+ <td>Unclear specification of effects of signal handling</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1174">1174</a></td>
+ <td>FDIS</td>
+ <td>When is a pure virtual function &#8220;used?&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1175">1175</a></td>
+ <td>FDIS</td>
+ <td>Disambiguating user-defined literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1176">1176</a></td>
+ <td>FDIS</td>
+ <td>Definition of release sequence</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1177">1177</a></td>
+ <td>FDIS</td>
+ <td>Intra-thread dependency-ordered-before</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1178">1178</a></td>
+ <td>FDIS</td>
+ <td>Deduction failure matching placement new</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1179">1179</a></td>
+ <td>NAD</td>
+ <td>Cv-qualification of non-type template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1180">1180</a></td>
+ <td>FDIS</td>
+ <td>Over-aligned class types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1181">1181</a></td>
+ <td>FDIS</td>
+ <td>What is a &#8220;built-in type?&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1182">1182</a></td>
+ <td>FDIS</td>
+ <td>Incorrect description of pack expansion syntax</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1183">1183</a></td>
+ <td>FDIS</td>
+ <td>Expansion of parameter packs in declarators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1184">1184</a></td>
+ <td>FDIS</td>
+ <td>Argument conversions to nondeduced parameter types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1185">1185</a></td>
+ <td>FDIS</td>
+ <td>Misleading description of language linkage and member function types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1186">1186</a></td>
+ <td>FDIS</td>
+ <td>Non-dependent <TT>constexpr</TT> violations in function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1187">1187</a></td>
+ <td>FDIS</td>
+ <td>Problems in initialization example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1188">1188</a></td>
+ <td>FDIS</td>
+ <td>Type punning in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1189">1189</a></td>
+ <td>FDIS</td>
+ <td>Address of distinct base class subobjects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1190">1190</a></td>
+ <td>FDIS</td>
+ <td>Operations on non-safely-derived pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1191">1191</a></td>
+ <td>FDIS</td>
+ <td>Deleted subobject destructors and implicitly-defined constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1192">1192</a></td>
+ <td>FDIS</td>
+ <td>Inadvertent change to ODR and templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1193">1193</a></td>
+ <td>FDIS</td>
+ <td>Use of address-constant pointers in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1194">1194</a></td>
+ <td>FDIS</td>
+ <td>Constexpr references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1195">1195</a></td>
+ <td>FDIS</td>
+ <td>References to non-literal types in constexpr functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1196">1196</a></td>
+ <td>FDIS</td>
+ <td>Definition required for explicit instantiation after explicit specialization?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1197">1197</a></td>
+ <td>FDIS</td>
+ <td>Constexpr arrays</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1198">1198</a></td>
+ <td>FDIS</td>
+ <td>Literal types and copy constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1199">1199</a></td>
+ <td>FDIS</td>
+ <td>Deleted constexpr functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1200">1200</a></td>
+ <td>open</td>
+ <td>Lookup rules for template parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1201">1201</a></td>
+ <td>FDIS</td>
+ <td>Are deleted and defaulted functions definitions?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1202">1202</a></td>
+ <td>FDIS</td>
+ <td>Calling virtual functions during destruction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1203">1203</a></td>
+ <td>dup</td>
+ <td>Misleading note regarding initialized static data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1204">1204</a></td>
+ <td>FDIS</td>
+ <td>Specifiers in a <I>for-range-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1205">1205</a></td>
+ <td>dup</td>
+ <td>Lvalue reference binding and function viability</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1206">1206</a></td>
+ <td>FDIS</td>
+ <td>Defining opaque enumeration members of class templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1207">1207</a></td>
+ <td>FDIS</td>
+ <td>Type of class member in <I>trailing-return-type</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1208">1208</a></td>
+ <td>FDIS</td>
+ <td>Explicit <TT>noexcept</TT> in defaulted definition</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1209">1209</a></td>
+ <td>open</td>
+ <td>Is a potentially-evaluated expression in a template definition a &#8220;use?&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1210">1210</a></td>
+ <td>FDIS</td>
+ <td>Injection of <I>elaborated-type-specifier</I> in enumeration scope</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1211">1211</a></td>
+ <td>drafting</td>
+ <td>Misaligned lvalues</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1212">1212</a></td>
+ <td>FDIS</td>
+ <td>Non-function-call xvalues and <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1213">1213</a></td>
+ <td>DRWP</td>
+ <td>Array subscripting and xvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1214">1214</a></td>
+ <td>FDIS</td>
+ <td>Kinds of initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1215">1215</a></td>
+ <td>FDIS</td>
+ <td>Definition of POD struct</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1216">1216</a></td>
+ <td>FDIS</td>
+ <td>Exceptions &#8220;allowed&#8221; by a <I>noexcept-specification</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1217">1217</a></td>
+ <td>NAD</td>
+ <td>Are deleted functions implicitly <TT>noexcept</TT>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1218">1218</a></td>
+ <td>FDIS</td>
+ <td>What is the &#8220;currently-handled exception&#8221; in a multi-threaded program?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1219">1219</a></td>
+ <td>FDIS</td>
+ <td>Non-static data member initializers in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1220">1220</a></td>
+ <td>FDIS</td>
+ <td>Looking up <I>conversion-type-id</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1221">1221</a></td>
+ <td>open</td>
+ <td>Partial ordering and reference collapsing</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1222">1222</a></td>
+ <td>NAD</td>
+ <td>Unnecessary restriction on <TT>auto</TT> array types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1223">1223</a></td>
+ <td>drafting</td>
+ <td>Syntactic disambiguation and <I>trailing-return-type</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1224">1224</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> defaulted copy constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1225">1225</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> constructors and virtual bases</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1226">1226</a></td>
+ <td>DRWP</td>
+ <td>Converting a <I>braced-init-list</I> default argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1227">1227</a></td>
+ <td>DRWP</td>
+ <td>Mixing immediate and non-immediate contexts in deduction failure</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1228">1228</a></td>
+ <td>NAD</td>
+ <td>Copy-list-initialization and <TT>explicit</TT> constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1229">1229</a></td>
+ <td>FDIS</td>
+ <td>Overload resolution with empty <I>braced-init-list</I> argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1230">1230</a></td>
+ <td>open</td>
+ <td>Confusing description of ambiguity of destructor name</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1231">1231</a></td>
+ <td>FDIS</td>
+ <td>Variadic templates requiring an empty pack expansion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1232">1232</a></td>
+ <td>FDIS</td>
+ <td>Creation of array temporaries using a <I>braced-init-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1233">1233</a></td>
+ <td>FDIS</td>
+ <td>Pack expansions and dependent calls</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1234">1234</a></td>
+ <td>FDIS</td>
+ <td><I>abstract-declarator</I> does not permit <TT>...</TT> after <I>ptr-operator</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1235">1235</a></td>
+ <td>FDIS</td>
+ <td>&#8220;Unused&#8221; ellipsis and default arguments in partial ordering</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1236">1236</a></td>
+ <td>FDIS</td>
+ <td>Inconsistently-interrelated examples</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1237">1237</a></td>
+ <td>FDIS</td>
+ <td>Deprecated implicit copy assignment in example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1238">1238</a></td>
+ <td>FDIS</td>
+ <td>Overloading ambiguity binding reference to function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1239">1239</a></td>
+ <td>FDIS</td>
+ <td>Hexadecimal floating-point literals vs user-defined literals</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1240">1240</a></td>
+ <td>FDIS</td>
+ <td><TT>constexpr</TT> defaulted constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1241">1241</a></td>
+ <td>FDIS</td>
+ <td>Which members does a destructor destroy?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1242">1242</a></td>
+ <td>FDIS</td>
+ <td>Initializing variant class members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1243">1243</a></td>
+ <td>FDIS</td>
+ <td>Misleading footnote regarding multiple-declarator declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1244">1244</a></td>
+ <td>FDIS</td>
+ <td>Equivalence of alias templates and class templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1245">1245</a></td>
+ <td>FDIS</td>
+ <td>Matching declarations involving <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1246">1246</a></td>
+ <td>FDIS</td>
+ <td>Non-deduced non-final parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1247">1247</a></td>
+ <td>drafting</td>
+ <td>Restriction on alias name appearing in <I>type-id</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1248">1248</a></td>
+ <td>open</td>
+ <td>Updating Annex C to C99</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1249">1249</a></td>
+ <td>drafting</td>
+ <td>Cv-qualification of nested lambda capture</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1250">1250</a></td>
+ <td>DRWP</td>
+ <td>Cv-qualification of incomplete virtual function return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1251">1251</a></td>
+ <td>DRWP</td>
+ <td>C compatibility: casting to unqualified <TT>void*</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1252">1252</a></td>
+ <td>drafting</td>
+ <td>Overloading member function templates based on dependent return type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1253">1253</a></td>
+ <td>drafting</td>
+ <td>Generic non-template members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1254">1254</a></td>
+ <td>NAD</td>
+ <td>odr-use vs template arguments and constexpr functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1255">1255</a></td>
+ <td>drafting</td>
+ <td>Definition problems with <TT>constexpr</TT> functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1256">1256</a></td>
+ <td>open</td>
+ <td>Unevaluated operands are not necessarily constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1257">1257</a></td>
+ <td>open</td>
+ <td>Instantiation via non-dependent references in uninstantiated templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1258">1258</a></td>
+ <td>drafting</td>
+ <td>&#8220;Instantiation context&#8221; differs from dependent lookup rules</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1259">1259</a></td>
+ <td>extension</td>
+ <td>Deleting a POD via a pointer to base</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1260">1260</a></td>
+ <td>DRWP</td>
+ <td>Incorrect use of term &#8220;overloaded&#8221; in description of odr-use</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1261">1261</a></td>
+ <td>DRWP</td>
+ <td>Explicit handling of cv-qualification with non-class prvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1262">1262</a></td>
+ <td>DRWP</td>
+ <td>Default template arguments and deduction failure</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1263">1263</a></td>
+ <td>NAD</td>
+ <td>Mismatch between rvalue reference binding and overload resolution</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1264">1264</a></td>
+ <td>DRWP</td>
+ <td>Use of <TT>this</TT> in <TT>constexpr</TT> constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1265">1265</a></td>
+ <td>DRWP</td>
+ <td>Mixed use of the <TT>auto</TT> specifier</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1266">1266</a></td>
+ <td>open</td>
+ <td><I>user-defined-integer-literal</I> overflow</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1267">1267</a></td>
+ <td>DRWP</td>
+ <td>Rvalue reference types in <I>exception-specification</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1268">1268</a></td>
+ <td>DRWP</td>
+ <td><TT>reinterpret_cast</TT> of an xvalue operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1269">1269</a></td>
+ <td>DRWP</td>
+ <td><TT>dynamic_cast</TT> of an xvalue operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270">1270</a></td>
+ <td>DRWP</td>
+ <td>Brace elision in array temporary initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1271">1271</a></td>
+ <td>drafting</td>
+ <td>Imprecise wording regarding dependent types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1272">1272</a></td>
+ <td>extension</td>
+ <td>Implicit definition of static data member of const literal type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1273">1273</a></td>
+ <td>NAD</td>
+ <td>Accessibility and function signatures</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1274">1274</a></td>
+ <td>drafting</td>
+ <td>Common nonterminal for <I>expression</I> and <I>braced-init-list</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1275">1275</a></td>
+ <td>DRWP</td>
+ <td>Incorrect comment in example of template parameter pack restriction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1276">1276</a></td>
+ <td>NAD</td>
+ <td>Reference to <TT>stdint.h</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1277">1277</a></td>
+ <td>NAD</td>
+ <td>Lax definition of <TT>intmax_t</TT> and <TT>uintmax_t</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1278">1278</a></td>
+ <td>drafting</td>
+ <td>Incorrect treatment of contrived object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1279">1279</a></td>
+ <td>drafting</td>
+ <td>Additional differences between C++ 2003 and C++ 2011</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1280">1280</a></td>
+ <td>NAD</td>
+ <td>Object reallocation and reference members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1281">1281</a></td>
+ <td>NAD</td>
+ <td>Virtual and dependent base classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1282">1282</a></td>
+ <td>DRWP</td>
+ <td>Underspecified destructor <I>exception-specification</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1283">1283</a></td>
+ <td>drafting</td>
+ <td>Static data members of classes with typedef name for linkage purposes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1284">1284</a></td>
+ <td>drafting</td>
+ <td>Should the lifetime of an array be independent of that of its elements?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1285">1285</a></td>
+ <td>open</td>
+ <td>Trivial destructors and object lifetime</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1286">1286</a></td>
+ <td>drafting</td>
+ <td>Equivalence of alias templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1287">1287</a></td>
+ <td>DR</td>
+ <td>Direct initialization vs &#8220;implicit&#8221; conversion in reference binding</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1288">1288</a></td>
+ <td>DRWP</td>
+ <td>Reference list initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1289">1289</a></td>
+ <td>NAD</td>
+ <td>Can an alias template name the current instantiation?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1290">1290</a></td>
+ <td>DRWP</td>
+ <td>Lifetime of the underlying array of an <TT>initializer_list</TT> member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1291">1291</a></td>
+ <td>drafting</td>
+ <td>Looking up a <I>conversion-type-id</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1292">1292</a></td>
+ <td>drafting</td>
+ <td>Dependent calls with <I>braced-init-list</I>s containing a pack expansion</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1293">1293</a></td>
+ <td>DRWP</td>
+ <td>String literals in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1294">1294</a></td>
+ <td>drafting</td>
+ <td>Side effects in dynamic/static initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1295">1295</a></td>
+ <td>DRWP</td>
+ <td>Binding a reference to an rvalue bit-field</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1296">1296</a></td>
+ <td>DRWP</td>
+ <td>Ill-formed template declarations (not just definitions)</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1297">1297</a></td>
+ <td>DRWP</td>
+ <td>Misplaced function <I>attribute-specifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1298">1298</a></td>
+ <td>DRWP</td>
+ <td>Incorrect example in overload resolution</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299">1299</a></td>
+ <td>drafting</td>
+ <td>&#8220;Temporary objects&#8221; vs &#8220;temporary expressions&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1300">1300</a></td>
+ <td>extension</td>
+ <td><TT>T()</TT> for array types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1301">1301</a></td>
+ <td>DRWP</td>
+ <td>Value initialization of union</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1302">1302</a></td>
+ <td>DRWP</td>
+ <td><TT>noexcept</TT> applied to expression of type <TT>void</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1303">1303</a></td>
+ <td>NAD</td>
+ <td>C language linkage for template with internal linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1304">1304</a></td>
+ <td>drafting</td>
+ <td>Omitted array bound with string initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1305">1305</a></td>
+ <td>DRWP</td>
+ <td><TT>alignof</TT> applied to array of unknown size</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1306">1306</a></td>
+ <td>DRWP</td>
+ <td>Modifying an object within a <TT>const</TT> member function</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1307">1307</a></td>
+ <td>DR</td>
+ <td>Overload resolution based on size of array <I>initializer-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1308">1308</a></td>
+ <td>DRWP</td>
+ <td>Completeness of class type within an <I>exception-specification</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1309">1309</a></td>
+ <td>drafting</td>
+ <td>Incorrect note regarding lookup of a member of the current instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1310">1310</a></td>
+ <td>DRWP</td>
+ <td>What is an &#8220;acceptable lookup result?&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1311">1311</a></td>
+ <td>DRWP</td>
+ <td>Volatile lvalues in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1312">1312</a></td>
+ <td>DRWP</td>
+ <td>Simulated <TT>reinterpret_cast</TT> in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1313">1313</a></td>
+ <td>DRWP</td>
+ <td>Undefined pointer arithmetic in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1314">1314</a></td>
+ <td>NAD</td>
+ <td>Pointer arithmetic within standard-layout objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1315">1315</a></td>
+ <td>drafting</td>
+ <td>Restrictions on non-type template arguments in partial specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1316">1316</a></td>
+ <td>NAD</td>
+ <td><TT>constexpr</TT> function requirements and class scope</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1317">1317</a></td>
+ <td>NAD</td>
+ <td>Unnamed scoped enumerations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1318">1318</a></td>
+ <td>DRWP</td>
+ <td>Syntactic ambiguities with <TT>final</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1319">1319</a></td>
+ <td>NAD</td>
+ <td>Error in pack expansion example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1320">1320</a></td>
+ <td>DRWP</td>
+ <td>Converting scoped enumerations to <TT>bool</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1321">1321</a></td>
+ <td>DRWP</td>
+ <td>Equivalency of dependent calls</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1322">1322</a></td>
+ <td>drafting</td>
+ <td>Function parameter type decay in templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1323">1323</a></td>
+ <td>NAD</td>
+ <td>Nonexistent nonterminal in <I>alignment-specifier</I> grammar</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1324">1324</a></td>
+ <td>DRWP</td>
+ <td>Value initialization and defaulted constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1325">1325</a></td>
+ <td>drafting</td>
+ <td>Omitted declarator in <TT>friend</TT> declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1326">1326</a></td>
+ <td>extension</td>
+ <td>Deducing an array bound from an <I>initializer-list</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1327">1327</a></td>
+ <td>DRWP</td>
+ <td><I>virt-specifier</I> in a defaulted definition</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1328">1328</a></td>
+ <td>DRWP</td>
+ <td>Conflict in reference binding vs overload resolution</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1329">1329</a></td>
+ <td>DRWP</td>
+ <td>Recursive deduction substitutions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1330">1330</a></td>
+ <td>DRWP</td>
+ <td>Delayed instantiation of <TT>noexcept</TT> specifiers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1331">1331</a></td>
+ <td>extension</td>
+ <td><TT>const</TT> mismatch with defaulted copy constructor</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1332">1332</a></td>
+ <td>drafting</td>
+ <td>Handling of invalid universal-character-names</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1333">1333</a></td>
+ <td>DRWP</td>
+ <td>Omission of <TT>const</TT> in a defaulted copy constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1334">1334</a></td>
+ <td>NAD</td>
+ <td>Layout compatibility and cv-qualification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1335">1335</a></td>
+ <td>drafting</td>
+ <td>Stringizing, extended characters, and universal-character-names</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1336">1336</a></td>
+ <td>DRWP</td>
+ <td>Definition of &#8220;converting constructor&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1337">1337</a></td>
+ <td>dup</td>
+ <td>Partial ordering and non-deduced parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1338">1338</a></td>
+ <td>drafting</td>
+ <td>Aliasing and allocation functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1339">1339</a></td>
+ <td>NAD</td>
+ <td>Parenthesized <I>braced-init-list</I> and arrays</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1340">1340</a></td>
+ <td>DRWP</td>
+ <td>Complete type in member pointer expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1341">1341</a></td>
+ <td>drafting</td>
+ <td>Bit-field initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1342">1342</a></td>
+ <td>drafting</td>
+ <td>Order of initialization with multiple declarators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1343">1343</a></td>
+ <td>drafting</td>
+ <td>Sequencing of non-class initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1344">1344</a></td>
+ <td>ready</td>
+ <td>Adding new special member functions to a class via default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1345">1345</a></td>
+ <td>DRWP</td>
+ <td>Initialization of anonymous union class members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1346">1346</a></td>
+ <td>DRWP</td>
+ <td><I>expression-list</I> initializers and the <TT>auto</TT> specifier</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
+ <td>DRWP</td>
+ <td>Consistency of <TT>auto</TT> in multiple-declarator declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1348">1348</a></td>
+ <td>drafting</td>
+ <td>Use of <TT>auto</TT> in a <I>trailing-return-type</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1349">1349</a></td>
+ <td>drafting</td>
+ <td>Consistency of alias template redeclarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1350">1350</a></td>
+ <td>DRWP</td>
+ <td>Incorrect exception specification for inherited constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1351">1351</a></td>
+ <td>review</td>
+ <td>Problems with implicitly-declared <I>exception-specification</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1352">1352</a></td>
+ <td>DRWP</td>
+ <td>Inconsistent class scope and completeness rules</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1353">1353</a></td>
+ <td>drafting</td>
+ <td>Array and variant members and deleted special member functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1354">1354</a></td>
+ <td>DRWP</td>
+ <td>Destructor exceptions for temporaries in noexcept expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1355">1355</a></td>
+ <td>DRWP</td>
+ <td>Aggregates and &#8220;user-provided&#8221; constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1356">1356</a></td>
+ <td>review</td>
+ <td>Exception specifications of copy assignment operators with virtual bases</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1357">1357</a></td>
+ <td>DRWP</td>
+ <td><I>brace-or-equal-initializer</I>s for function and typedef members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1358">1358</a></td>
+ <td>DRWP</td>
+ <td>Unintentionally ill-formed <TT>constexpr</TT> function template instances</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1359">1359</a></td>
+ <td>DRWP</td>
+ <td><TT>constexpr</TT> union constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1360">1360</a></td>
+ <td>drafting</td>
+ <td><TT>constexpr</TT> defaulted default constructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1361">1361</a></td>
+ <td>DRWP</td>
+ <td>Requirement on <I>brace-or-equal-initializer</I>s of literal types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1362">1362</a></td>
+ <td>DRWP</td>
+ <td>Complete type required for implicit conversion to <TT>T&amp;</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1363">1363</a></td>
+ <td>DRWP</td>
+ <td>Triviality vs multiple default constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1364">1364</a></td>
+ <td>DRWP</td>
+ <td><TT>constexpr</TT> function parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1365">1365</a></td>
+ <td>DRWP</td>
+ <td>Calling undefined <TT>constexpr</TT> functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1366">1366</a></td>
+ <td>DRWP</td>
+ <td>Deleted <TT>constexpr</TT> constructors and virtual base classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1367">1367</a></td>
+ <td>DRWP</td>
+ <td>Use of <TT>this</TT> in a constant expression</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1368">1368</a></td>
+ <td>DRWP</td>
+ <td>Value initialization and defaulted constructors (part 2)</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1369">1369</a></td>
+ <td>DRWP</td>
+ <td>Function invocation substitution of <TT>this</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1370">1370</a></td>
+ <td>DRWP</td>
+ <td><I>identifier-list</I> cannot contain ellipsis</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1371">1371</a></td>
+ <td>NAD</td>
+ <td>Deduction from <TT>T&amp;&amp;</TT> in return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1372">1372</a></td>
+ <td>DRWP</td>
+ <td>Cross-references incorrect in conversion function template argument deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1373">1373</a></td>
+ <td>dup</td>
+ <td>Overload resolution changes matching reference-binding changes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1374">1374</a></td>
+ <td>DRWP</td>
+ <td>Qualification conversion vs difference in reference binding</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1375">1375</a></td>
+ <td>DRWP</td>
+ <td>Reference to anonymous union?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1376">1376</a></td>
+ <td>ready</td>
+ <td><TT>static_cast</TT> of temporary to rvalue reference</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1377">1377</a></td>
+ <td>dup</td>
+ <td>Access declarations not mentioned in Annex C</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1378">1378</a></td>
+ <td>open</td>
+ <td>When is an instantiation required?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1379">1379</a></td>
+ <td>NAD</td>
+ <td>Is <TT>std::initializer_list</TT> an aggregate?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1380">1380</a></td>
+ <td>DRWP</td>
+ <td>Type definitions in <I>template-parameter</I> <I>parameter-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1381">1381</a></td>
+ <td>DRWP</td>
+ <td>Implicitly-declared special member functions and default <TT>nothrow</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1382">1382</a></td>
+ <td>DRWP</td>
+ <td>Dead code for constructor names</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1383">1383</a></td>
+ <td>DRWP</td>
+ <td>Clarifying discarded-value expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1384">1384</a></td>
+ <td>NAD</td>
+ <td><TT>reinterpret_cast</TT> in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1385">1385</a></td>
+ <td>DRWP</td>
+ <td>Syntactic forms of conversion functions for surrogate call functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1386">1386</a></td>
+ <td>NAD</td>
+ <td>Explicitly-specified partial argument list with multiple parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1387">1387</a></td>
+ <td>DRWP</td>
+ <td>Missing non-deduced context for <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1388">1388</a></td>
+ <td>DRWP</td>
+ <td>Missing non-deduced context following a function parameter pack</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1389">1389</a></td>
+ <td>NAD</td>
+ <td>Recursive reference in <I>trailing-return-type</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1390">1390</a></td>
+ <td>drafting</td>
+ <td>Dependency of alias template specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1391">1391</a></td>
+ <td>drafting</td>
+ <td>Conversions to parameter types with non deduced template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td>
+ <td>DRWP</td>
+ <td>Explicit conversion functions for references and non-references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1393">1393</a></td>
+ <td>extension</td>
+ <td>Pack expansions in <I>using-declaration</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1394">1394</a></td>
+ <td>DRWP</td>
+ <td>Incomplete types as parameters of deleted functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1395">1395</a></td>
+ <td>drafting</td>
+ <td>Partial ordering of variadic templates reconsidered</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1396">1396</a></td>
+ <td>drafting</td>
+ <td>Deferred instantiation and checking of non-static data member initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1397">1397</a></td>
+ <td>drafting</td>
+ <td>Class completeness in non-static data member initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1398">1398</a></td>
+ <td>DRWP</td>
+ <td>Non-type template parameters of type <TT>std::nullptr_t</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1399">1399</a></td>
+ <td>DRWP</td>
+ <td>Deduction with multiple function parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1400">1400</a></td>
+ <td>NAD</td>
+ <td>Function pointer equality</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1401">1401</a></td>
+ <td>DRWP</td>
+ <td>Similar types and reference compatibility</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1402">1402</a></td>
+ <td>DRWP</td>
+ <td>Move functions too often deleted</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1403">1403</a></td>
+ <td>open</td>
+ <td>Universal-character-names in comments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1404">1404</a></td>
+ <td>drafting</td>
+ <td>Object reallocation in unions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1405">1405</a></td>
+ <td>DRWP</td>
+ <td><TT>constexpr</TT> and mutable members of literal types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1406">1406</a></td>
+ <td>DRWP</td>
+ <td><I>ref-qualifier</I>s and added parameters of non-static member function templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1407">1407</a></td>
+ <td>NAD</td>
+ <td>Integral to <TT>bool</TT> conversion in converted constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1408">1408</a></td>
+ <td>DRWP</td>
+ <td>What is &#8220;the same aggregate initialization?&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1409">1409</a></td>
+ <td>DRWP</td>
+ <td>What is the second standard conversion sequence of a list-initialization sequence?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1410">1410</a></td>
+ <td>DRWP</td>
+ <td>Reference overload tiebreakers should apply to rvalue references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1411">1411</a></td>
+ <td>DRWP</td>
+ <td>More on global scope <TT>::</TT> in <I>nested-name-specifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1412">1412</a></td>
+ <td>DRWP</td>
+ <td>Problems in specifying pointer conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1413">1413</a></td>
+ <td>DRWP</td>
+ <td>Missing cases of value-dependency</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1414">1414</a></td>
+ <td>drafting</td>
+ <td>Binding an rvalue reference to a reference-unrelated lvalue</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1415">1415</a></td>
+ <td>DRWP</td>
+ <td>Missing prohibition of block-scope definition of <TT>extern</TT> object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1416">1416</a></td>
+ <td>DRWP</td>
+ <td>Function cv-qualifiers and <TT>typeid</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1417">1417</a></td>
+ <td>DR</td>
+ <td>Pointers/references to functions with cv-qualifiers or <I>ref-qualifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1418">1418</a></td>
+ <td>DRWP</td>
+ <td>Type of <TT>initializer_list</TT> backing array</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1419">1419</a></td>
+ <td>NAD</td>
+ <td>Evaluation order in aggregate initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1420">1420</a></td>
+ <td>NAD</td>
+ <td>Abstract final classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1421">1421</a></td>
+ <td>NAD</td>
+ <td>Full expressions and aggregate initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1422">1422</a></td>
+ <td>dup</td>
+ <td>Type of character literals containing universal-character-names</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1423">1423</a></td>
+ <td>DRWP</td>
+ <td>Convertibility of <TT>nullptr</TT> to <TT>bool</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1424">1424</a></td>
+ <td>DR</td>
+ <td>When must sub-object destructors be accessible?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1425">1425</a></td>
+ <td>DRWP</td>
+ <td>Base-class subobjects of standard-layout structs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1426">1426</a></td>
+ <td>extension</td>
+ <td>Allowing additional parameter types in defaulted functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1427">1427</a></td>
+ <td>NAD</td>
+ <td>Default constructor and deleted or inaccessible destructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1428">1428</a></td>
+ <td>DRWP</td>
+ <td>Dynamic const objects</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1429">1429</a></td>
+ <td>NAD</td>
+ <td>Scope of a member template's template parameter</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430">1430</a></td>
+ <td>drafting</td>
+ <td>Pack expansion into fixed alias template parameter list</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1431">1431</a></td>
+ <td>DRWP</td>
+ <td>Exceptions from other than <I>throw-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1432">1432</a></td>
+ <td>drafting</td>
+ <td>Newly-ambiguous variadic template expansions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1433">1433</a></td>
+ <td>extension</td>
+ <td><I>trailing-return-type</I> and point of declaration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1434">1434</a></td>
+ <td>NAD</td>
+ <td>Parenthesized <I>braced-init-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1435">1435</a></td>
+ <td>DRWP</td>
+ <td><I>template-id</I> as the declarator for a class template constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1436">1436</a></td>
+ <td>drafting</td>
+ <td>Interaction of constant expression changes with preprocessor expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1437">1437</a></td>
+ <td>DRWP</td>
+ <td><TT>alignas</TT> in <I>alias-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1438">1438</a></td>
+ <td>DRWP</td>
+ <td>Non-dereference use of invalid pointers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1439">1439</a></td>
+ <td>DRWP</td>
+ <td>Lookup and friend template declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1440">1440</a></td>
+ <td>DRWP</td>
+ <td>Acceptable <I>decltype-specifier</I>s used as <I>nested-name-specifier</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1441">1441</a></td>
+ <td>concurrency</td>
+ <td>Unclear wording for signal handler restrictions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442">1442</a></td>
+ <td>DRWP</td>
+ <td>Argument-dependent lookup in the range-based <TT>for</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1443">1443</a></td>
+ <td>NAD</td>
+ <td>Default arguments and non-static data members</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1444">1444</a></td>
+ <td>drafting</td>
+ <td>Type adjustments of non-type template parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1445">1445</a></td>
+ <td>dup</td>
+ <td>Argument-dependent lookup of <TT>begin</TT> and <TT>end</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1446">1446</a></td>
+ <td>drafting</td>
+ <td>Member function with no <I>ref-qualifier</I> and non-member function with rvalue reference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1447">1447</a></td>
+ <td>DRWP</td>
+ <td><TT>static_cast</TT> of bit-field lvalue to rvalue reference</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1448">1448</a></td>
+ <td>NAD</td>
+ <td>Integral values of type <TT>bool</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1449">1449</a></td>
+ <td>DRWP</td>
+ <td>Narrowing conversion of negative value to unsigned type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1450">1450</a></td>
+ <td>DRWP</td>
+ <td><TT>INT_MIN % -1</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1451">1451</a></td>
+ <td>extension</td>
+ <td>Objects with no linkage in non-type template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1452">1452</a></td>
+ <td>drafting</td>
+ <td>Value-initialized objects may be constants</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1453">1453</a></td>
+ <td>DRWP</td>
+ <td>Volatile members in literal classes?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1454">1454</a></td>
+ <td>DRWP</td>
+ <td>Passing constants through <TT>constexpr</TT> functions via references</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1455">1455</a></td>
+ <td>DRWP</td>
+ <td>Lvalue converted constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1456">1456</a></td>
+ <td>DRWP</td>
+ <td>Address constant expression designating the one-past-the-end address</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1457">1457</a></td>
+ <td>DRWP</td>
+ <td>Undefined behavior in left-shift</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1458">1458</a></td>
+ <td>DRWP</td>
+ <td>Address of incomplete type vs <TT>operator&amp;()</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1459">1459</a></td>
+ <td>open</td>
+ <td>Reference-binding tiebreakers in overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1460">1460</a></td>
+ <td>DR</td>
+ <td>What is an empty union?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1461">1461</a></td>
+ <td>extension</td>
+ <td>Narrowing conversions to bit-fields</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1462">1462</a></td>
+ <td>DRWP</td>
+ <td>Deduction failure vs &#8220;ill-formed, no diagnostic required&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1463">1463</a></td>
+ <td>extension</td>
+ <td><TT>extern "C"</TT> alias templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1464">1464</a></td>
+ <td>WP</td>
+ <td>Negative array bound in a <I>new-expression</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1465">1465</a></td>
+ <td>review</td>
+ <td><TT>noexcept</TT> and <TT>std::bad_array_new_length</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1466">1466</a></td>
+ <td>concurrency</td>
+ <td>Visible sequences of side effects are redundant</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467">1467</a></td>
+ <td>drafting</td>
+ <td>List-initialization of aggregate from same-type object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1468">1468</a></td>
+ <td>drafting</td>
+ <td><TT>typeid</TT>, overload resolution, and implicit lambda capture</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1469">1469</a></td>
+ <td>drafting</td>
+ <td>Omitted bound in array <I>new-expression</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1470">1470</a></td>
+ <td>NAD</td>
+ <td>Thread migration</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1471">1471</a></td>
+ <td>DRWP</td>
+ <td>Nested type of non-dependent base</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1472">1472</a></td>
+ <td>DRWP</td>
+ <td>odr-use of reference variables</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1473">1473</a></td>
+ <td>DRWP</td>
+ <td>Syntax of <I>literal-operator-id</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1474">1474</a></td>
+ <td>extension</td>
+ <td>User-defined literals and <TT>&lt;inttypes.h&gt;</TT> format macros</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1475">1475</a></td>
+ <td>DRWP</td>
+ <td>Errors in <TT>[[carries_dependency]]</TT> example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1476">1476</a></td>
+ <td>DRWP</td>
+ <td>Definition of user-defined type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1477">1477</a></td>
+ <td>DRWP</td>
+ <td>Definition of a <TT>friend</TT> outside its namespace</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1478">1478</a></td>
+ <td>drafting</td>
+ <td><TT>template</TT> keyword for dependent template template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1479">1479</a></td>
+ <td>DRWP</td>
+ <td>Literal operators and default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1480">1480</a></td>
+ <td>drafting</td>
+ <td>Constant initialization via non-constant temporary</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1481">1481</a></td>
+ <td>DRWP</td>
+ <td>Increment/decrement operators with reference parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1482">1482</a></td>
+ <td>DRWP</td>
+ <td>Point of declaration of enumeration</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1483">1483</a></td>
+ <td>NAD</td>
+ <td>Non-dependent <I>static_assert-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1484">1484</a></td>
+ <td>review</td>
+ <td>Unused local classes of function templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1485">1485</a></td>
+ <td>drafting</td>
+ <td>Out-of-class definition of member unscoped opaque enumeration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1486">1486</a></td>
+ <td>drafting</td>
+ <td>Base-derived conversion in member pointer deduction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1487">1487</a></td>
+ <td>DRWP</td>
+ <td>When are inheriting constructors declared?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1488">1488</a></td>
+ <td>drafting</td>
+ <td><I>abstract-pack-declarator</I>s in <I>type-id</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1489">1489</a></td>
+ <td>DRWP</td>
+ <td>Is value-initialization of an array constant initialization?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1490">1490</a></td>
+ <td>drafting</td>
+ <td>List-initialization from a string literal</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1491">1491</a></td>
+ <td>drafting</td>
+ <td>Move construction and rvalue reference members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1492">1492</a></td>
+ <td>drafting</td>
+ <td>Exception specifications on template destructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1493">1493</a></td>
+ <td>ready</td>
+ <td>Criteria for move-construction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1494">1494</a></td>
+ <td>DRWP</td>
+ <td>Temporary initialization for reference binding in list-initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1495">1495</a></td>
+ <td>DRWP</td>
+ <td>Partial specialization of variadic class template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1496">1496</a></td>
+ <td>drafting</td>
+ <td>Triviality with deleted and missing default constructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1497">1497</a></td>
+ <td>NAD</td>
+ <td>Aggregate initialization with parenthesized string literal</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1498">1498</a></td>
+ <td>dup</td>
+ <td>Lifetime of temporaries in range-based <TT>for</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1499">1499</a></td>
+ <td>drafting</td>
+ <td>Missing case for deleted move assignment operator</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1500">1500</a></td>
+ <td>open</td>
+ <td>Name lookup of dependent conversion function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1501">1501</a></td>
+ <td>NAD</td>
+ <td>Nested braces in list-initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1502">1502</a></td>
+ <td>DRWP</td>
+ <td>Value initialization of unions with member initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1503">1503</a></td>
+ <td>DRWP</td>
+ <td>Exceptions during copy to exception object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1504">1504</a></td>
+ <td>DRWP</td>
+ <td>Pointer arithmetic after derived-base conversion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1505">1505</a></td>
+ <td>dup</td>
+ <td>Direct binding of reference to temporary in list-initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1506">1506</a></td>
+ <td>DRWP</td>
+ <td>Value category of <TT>initializer_list</TT> object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1507">1507</a></td>
+ <td>DRWP</td>
+ <td>Value initialization with trivial inaccessible default constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1508">1508</a></td>
+ <td>DR</td>
+ <td>Template initializer-list constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1509">1509</a></td>
+ <td>DR</td>
+ <td>Definition of &#8220;non-template function&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1510">1510</a></td>
+ <td>DRWP</td>
+ <td>cv-qualified references via <TT>decltype</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1511">1511</a></td>
+ <td>DRWP</td>
+ <td><TT>const volatile</TT> variables and the one-definition rule</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1512">1512</a></td>
+ <td>DRWP</td>
+ <td>Pointer comparison vs qualification conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1513">1513</a></td>
+ <td>drafting</td>
+ <td><TT>initializer_list</TT> deduction failure</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1514">1514</a></td>
+ <td>DR</td>
+ <td>Ambiguity between enumeration definition and zero-length bit-field</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1515">1515</a></td>
+ <td>DRWP</td>
+ <td>Modulo 2<SUP><I>n</I></SUP> arithmetic for implicitly-unsigned types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1516">1516</a></td>
+ <td>DRWP</td>
+ <td>Definition of &#8220;virtual function call&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1517">1517</a></td>
+ <td>review</td>
+ <td>Unclear/missing description of behavior during construction/destruction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518">1518</a></td>
+ <td>drafting</td>
+ <td>Explicit default constructors and copy-list-initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1519">1519</a></td>
+ <td>extension</td>
+ <td>Conflicting default and variadic constructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1520">1520</a></td>
+ <td>NAD</td>
+ <td>Alias template specialization vs pack expansion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1521">1521</a></td>
+ <td>drafting</td>
+ <td><TT>T{</TT><I>expr</I><TT>}</TT> with reference types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1522">1522</a></td>
+ <td>DRWP</td>
+ <td>Access checking for <TT>initializer_list</TT> array initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1523">1523</a></td>
+ <td>drafting</td>
+ <td>Point of declaration in range-based <TT>for</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1524">1524</a></td>
+ <td>drafting</td>
+ <td>Incompletely-defined class template base</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1525">1525</a></td>
+ <td>NAD</td>
+ <td>Array bound inference in temporary array</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1526">1526</a></td>
+ <td>dup</td>
+ <td>Dependent-class lookup in the current instantiation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1527">1527</a></td>
+ <td>DRWP</td>
+ <td>Assignment from <I>braced-init-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1528">1528</a></td>
+ <td>DRWP</td>
+ <td>Repeated <I>cv-qualifier</I>s in declarators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1529">1529</a></td>
+ <td>drafting</td>
+ <td>Nomenclature for variable vs reference non-static data member</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1530">1530</a></td>
+ <td>drafting</td>
+ <td>Member access in out-of-lifetime objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1531">1531</a></td>
+ <td>DRWP</td>
+ <td>Definition of &#8220;access&#8221; (verb)</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1532">1532</a></td>
+ <td>DRWP</td>
+ <td>Explicit instantiation and member templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1533">1533</a></td>
+ <td>DRWP</td>
+ <td>Function pack expansion for member initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1534">1534</a></td>
+ <td>dup</td>
+ <td>cv-qualification of prvalue of type &#8220;array of class&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1535">1535</a></td>
+ <td>DRWP</td>
+ <td><TT>typeid</TT> in core constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1536">1536</a></td>
+ <td>drafting</td>
+ <td>Overload resolution with temporary from initializer list</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1537">1537</a></td>
+ <td>DRWP</td>
+ <td>Optional compile-time evaluation of constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1538">1538</a></td>
+ <td>DRWP</td>
+ <td>C-style cast in <I>braced-init-list</I> assignment</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1539">1539</a></td>
+ <td>DRWP</td>
+ <td>Definition of &#8220;character type&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1540">1540</a></td>
+ <td>NAD</td>
+ <td>Use of address constants in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1541">1541</a></td>
+ <td>DRWP</td>
+ <td><I>cv</I> <TT>void</TT> return types</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1542">1542</a></td>
+ <td>drafting</td>
+ <td>Compound assignment of <I>braced-init-list</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1543">1543</a></td>
+ <td>DRWP</td>
+ <td>Implicit conversion sequence for empty initializer list</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1544">1544</a></td>
+ <td>DRWP</td>
+ <td>Linkage of member of unnamed namespace</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1545">1545</a></td>
+ <td>drafting</td>
+ <td><TT>friend</TT> function templates defined in class templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1546">1546</a></td>
+ <td>NAD</td>
+ <td>Errors in function template default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1547">1547</a></td>
+ <td>NAD</td>
+ <td><TT>typename</TT> keyword in <I>alias-declaration</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1548">1548</a></td>
+ <td>drafting</td>
+ <td>Copy/move construction and conversion functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1549">1549</a></td>
+ <td>open</td>
+ <td>Overloaded comma operator with <TT>void</TT> operand</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1550">1550</a></td>
+ <td>DRWP</td>
+ <td>Parenthesized <I>throw-expression</I> operand of <I>conditional-expression</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1551">1551</a></td>
+ <td>DR</td>
+ <td>Wording problems in <I>using-declaration</I> specification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1552">1552</a></td>
+ <td>drafting</td>
+ <td><I>exception-specification</I>s and defaulted special member functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1553">1553</a></td>
+ <td>DRWP</td>
+ <td><TT>sizeof</TT> and xvalue bit-fields</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1554">1554</a></td>
+ <td>drafting</td>
+ <td>Access and alias templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555">1555</a></td>
+ <td>extension</td>
+ <td>Language linkage and function type compatibility</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1556">1556</a></td>
+ <td>DRWP</td>
+ <td>Constructors and explicit conversion functions in direct initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1557">1557</a></td>
+ <td>DRWP</td>
+ <td>Language linkage of converted lambda function pointer</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1558">1558</a></td>
+ <td>drafting</td>
+ <td>Unused arguments in alias template specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1559">1559</a></td>
+ <td>DRWP</td>
+ <td>String too long in initializer list of <I>new-expression</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1560">1560</a></td>
+ <td>DRWP</td>
+ <td>Gratuitous lvalue-to-rvalue conversion in <I>conditional-expression</I> with <I>throw-expression</I> operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1561">1561</a></td>
+ <td>extension</td>
+ <td>Aggregates with empty base classes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1562">1562</a></td>
+ <td>DR</td>
+ <td>Non-static data member initializers and union <I>ctor-initializer</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1563">1563</a></td>
+ <td>DRWP</td>
+ <td>List-initialization and overloaded function disambiguation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1564">1564</a></td>
+ <td>extension</td>
+ <td>Template argument deduction from an initializer list</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1565">1565</a></td>
+ <td>drafting</td>
+ <td>Copy elision and lifetime of <TT>initializer_list</TT> underlying array</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1566">1566</a></td>
+ <td>NAD</td>
+ <td>Should <TT>new std::initializer_list&lt;T&gt;</TT> be ill-formed?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1567">1567</a></td>
+ <td>DR</td>
+ <td>Inheriting constructors and copy/move constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1568">1568</a></td>
+ <td>dup</td>
+ <td>Temporary lifetime extension with intervening cast</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1569">1569</a></td>
+ <td>DR</td>
+ <td>Deducing a function parameter pack before ellipsis</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1570">1570</a></td>
+ <td>DR</td>
+ <td>Address of subobject as non-type template argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1571">1571</a></td>
+ <td>drafting</td>
+ <td>cv-qualification for indirect reference binding via conversion function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1572">1572</a></td>
+ <td>drafting</td>
+ <td>Incorrect example for rvalue reference binding via conversion function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1573">1573</a></td>
+ <td>drafting</td>
+ <td>Inherited constructor characteristics</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1574">1574</a></td>
+ <td>NAD</td>
+ <td>Explicitly-defaulted <TT>constexpr</TT> functions in wrapper templates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1575">1575</a></td>
+ <td>DR</td>
+ <td>Incorrect definition of &#8220;strict pointer safety&#8221;</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1576">1576</a></td>
+ <td>DR</td>
+ <td>Discarded-value volatile xvalues</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1577">1577</a></td>
+ <td>extension</td>
+ <td>Unnecessary restrictions on partial specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1578">1578</a></td>
+ <td>NAD</td>
+ <td>Value-initialization of aggregates</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1579">1579</a></td>
+ <td>ready</td>
+ <td>Return by converting move constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1580">1580</a></td>
+ <td>drafting</td>
+ <td>Default arguments in explicit instantiations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1581">1581</a></td>
+ <td>drafting</td>
+ <td>When are <TT>constexpr</TT> member functions defined?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1582">1582</a></td>
+ <td>drafting</td>
+ <td>Template default arguments and deduction failure</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1583">1583</a></td>
+ <td>DR</td>
+ <td>Incorrect example of unspecified behavior</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584">1584</a></td>
+ <td>review</td>
+ <td>Deducing function types from cv-qualified types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1585">1585</a></td>
+ <td>NAD</td>
+ <td>Value category of member access of rvalue reference member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1586">1586</a></td>
+ <td>drafting</td>
+ <td>Naming a destructor via <TT>decltype</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1587">1587</a></td>
+ <td>DR</td>
+ <td><TT>constexpr</TT> initialization and nested anonymous unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1588">1588</a></td>
+ <td>DRWP</td>
+ <td>Deducing cv-qualified <TT>auto</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1589">1589</a></td>
+ <td>drafting</td>
+ <td>Ambiguous ranking of list-initialization sequences</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1590">1590</a></td>
+ <td>review</td>
+ <td>Bypassing non-copy/move constructor copying</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1591">1591</a></td>
+ <td>drafting</td>
+ <td>Deducing array bound and element type from initializer list</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1592">1592</a></td>
+ <td>DR</td>
+ <td>When do template parameters match?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1593">1593</a></td>
+ <td>DR</td>
+ <td>&#8220;Parameter type&#8221; of special member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1594">1594</a></td>
+ <td>drafting</td>
+ <td>Lazy declaration of special members vs overload errors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1595">1595</a></td>
+ <td>DR</td>
+ <td>Constructors &#8220;involved in&#8221; subobject initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1596">1596</a></td>
+ <td>review</td>
+ <td>Non-array objects as <TT>array[1]</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1597">1597</a></td>
+ <td>WP</td>
+ <td>Misleading <TT>constexpr</TT> example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1598">1598</a></td>
+ <td>drafting</td>
+ <td>Criterion for equality of pointers to members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1599">1599</a></td>
+ <td>open</td>
+ <td>Lifetime of <TT>initializer_list</TT> underlying array</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1600">1600</a></td>
+ <td>review</td>
+ <td>Erroneous reference initialization in example</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1601">1601</a></td>
+ <td>DR</td>
+ <td>Promotion of enumeration with fixed underlying type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1602">1602</a></td>
+ <td>open</td>
+ <td>Linkage of specialization vs linkage of template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1603">1603</a></td>
+ <td>review</td>
+ <td>Errors resulting from giving unnamed namespaces internal linkage</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1604">1604</a></td>
+ <td>ready</td>
+ <td>Double temporaries in reference initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1605">1605</a></td>
+ <td>DRWP</td>
+ <td>Misleading parenthetical comment for explicit destructor call</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1606">1606</a></td>
+ <td>NAD</td>
+ <td><TT>sizeof</TT> closure class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1607">1607</a></td>
+ <td>ready</td>
+ <td>Lambdas in template parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1608">1608</a></td>
+ <td>DR</td>
+ <td>Operator lookup in trailing return type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1609">1609</a></td>
+ <td>open</td>
+ <td>Default arguments and function parameter packs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1610">1610</a></td>
+ <td>drafting</td>
+ <td>Cv-qualification in deduction of reference to array</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1611">1611</a></td>
+ <td>tentatively ready</td>
+ <td>Deleted default constructor for abstract class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1612">1612</a></td>
+ <td>ready</td>
+ <td>Implicit lambda capture and anonymous unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1613">1613</a></td>
+ <td>ready</td>
+ <td>Constant expressions and lambda capture</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1614">1614</a></td>
+ <td>review</td>
+ <td>Address of pure virtual function vs odr-use</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1615">1615</a></td>
+ <td>review</td>
+ <td>Alignment of types, variables, and members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1616">1616</a></td>
+ <td>drafting</td>
+ <td>Disambiguation parsing and template parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1617">1617</a></td>
+ <td>open</td>
+ <td><TT>alignas</TT> and non-defining declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1618">1618</a></td>
+ <td>DR</td>
+ <td>Gratuitously-unsigned underlying enum type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1619">1619</a></td>
+ <td>open</td>
+ <td>Definition of current instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1620">1620</a></td>
+ <td>open</td>
+ <td>User-defined literals and extended integer types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1621">1621</a></td>
+ <td>drafting</td>
+ <td>Member initializers in anonymous unions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1622">1622</a></td>
+ <td>drafting</td>
+ <td>Empty aggregate initializer for union</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1623">1623</a></td>
+ <td>drafting</td>
+ <td>Deleted default union constructor and member initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1624">1624</a></td>
+ <td>NAD</td>
+ <td>Destruction of union members with member initializers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1625">1625</a></td>
+ <td>open</td>
+ <td>Adding spaces between tokens in stringizing</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626">1626</a></td>
+ <td>drafting</td>
+ <td><TT>constexpr</TT> member functions in <I>brace-or-equal-initializer</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1627">1627</a></td>
+ <td>NAD</td>
+ <td>Agreement of dependent <TT>alignas</TT> specifiers</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1628">1628</a></td>
+ <td>open</td>
+ <td>Deallocation function templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1629">1629</a></td>
+ <td>drafting</td>
+ <td>Can a closure class be a literal type?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1630">1630</a></td>
+ <td>drafting</td>
+ <td>Multiple default constructor templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1631">1631</a></td>
+ <td>drafting</td>
+ <td>Incorrect overload resolution for single-element <I>initializer-list</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1632">1632</a></td>
+ <td>open</td>
+ <td>Lambda capture in member initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1633">1633</a></td>
+ <td>review</td>
+ <td>Copy-initialization in member initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1634">1634</a></td>
+ <td>drafting</td>
+ <td>Temporary storage duration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1635">1635</a></td>
+ <td>drafting</td>
+ <td>How similar are template default arguments to function default arguments?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1636">1636</a></td>
+ <td>drafting</td>
+ <td>Bits required for negative enumerator values</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1637">1637</a></td>
+ <td>NAD</td>
+ <td>Recursion in <TT>constexpr</TT> template default constructor</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1638">1638</a></td>
+ <td>drafting</td>
+ <td>Declaring an explicit specialization of a scoped enumeration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1639">1639</a></td>
+ <td>review</td>
+ <td><I>exception-specification</I>s and pointer/pointer-to-member expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1640">1640</a></td>
+ <td>drafting</td>
+ <td>Array of abstract instance of class template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1641">1641</a></td>
+ <td>NAD</td>
+ <td>Assignment in member initializer</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1642">1642</a></td>
+ <td>open</td>
+ <td>Missing requirements for prvalue operands</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1643">1643</a></td>
+ <td>extension</td>
+ <td>Default arguments for template parameter packs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1644">1644</a></td>
+ <td>open</td>
+ <td>Equivalent <I>exception-specification</I>s in function template declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1645">1645</a></td>
+ <td>drafting</td>
+ <td>Identical inheriting constructors via default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1646">1646</a></td>
+ <td>drafting</td>
+ <td><I>decltype-specifier</I>s, abstract classes, and deduction failure</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1647">1647</a></td>
+ <td>drafting</td>
+ <td>Type agreement of non-type template arguments in partial specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1648">1648</a></td>
+ <td>DR</td>
+ <td><TT>thread_local</TT> vs block extern declarations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1649">1649</a></td>
+ <td>DR</td>
+ <td>Error in the syntax of <I>mem-initializer-list</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1650">1650</a></td>
+ <td>open</td>
+ <td>Class prvalues in reference initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1651">1651</a></td>
+ <td>drafting</td>
+ <td>Lifetime extension of temporary via reference to subobject</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1652">1652</a></td>
+ <td>drafting</td>
+ <td>Object addresses in <TT>constexpr</TT> expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1653">1653</a></td>
+ <td>drafting</td>
+ <td>Removing deprecated increment of <TT>bool</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1654">1654</a></td>
+ <td>dup</td>
+ <td>Literal types and <TT>constexpr</TT> defaulted constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1655">1655</a></td>
+ <td>drafting</td>
+ <td>Line endings in raw string literals</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1656">1656</a></td>
+ <td>drafting</td>
+ <td>Encoding of numerically-escaped characters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1657">1657</a></td>
+ <td>extension</td>
+ <td>Attributes for namespaces and enumerators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1658">1658</a></td>
+ <td>drafting</td>
+ <td>Deleted default constructor for abstract class via destructor</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1659">1659</a></td>
+ <td>open</td>
+ <td>Initialization order of thread_local template static data members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1660">1660</a></td>
+ <td>open</td>
+ <td><I>member-declaration</I> requirements and unnamed bit-fields</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1661">1661</a></td>
+ <td>concurrency</td>
+ <td>Preservation of infinite loops</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1662">1662</a></td>
+ <td>ready</td>
+ <td>Capturing function parameter packs</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1663">1663</a></td>
+ <td>NAD</td>
+ <td>Capturing an empty pack expansion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1664">1664</a></td>
+ <td>ready</td>
+ <td>Argument-dependent lookup of lambdas used in default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1665">1665</a></td>
+ <td>drafting</td>
+ <td>Declaration matching in explicit instantiations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1666">1666</a></td>
+ <td>drafting</td>
+ <td>Address constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1667">1667</a></td>
+ <td>NAD</td>
+ <td>Function exiting via exception called by destructor during unwinding</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1668">1668</a></td>
+ <td>drafting</td>
+ <td>Parameter type determination still not clear enough</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1669">1669</a></td>
+ <td>drafting</td>
+ <td><TT>auto</TT> return type for <TT>main</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1670">1670</a></td>
+ <td>open</td>
+ <td><TT>auto</TT> as <I>conversion-type-id</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1671">1671</a></td>
+ <td>NAD</td>
+ <td>Unclear rules for deduction with cv-qualification</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1672">1672</a></td>
+ <td>drafting</td>
+ <td>Layout compatibility with multiple empty bases</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1673">1673</a></td>
+ <td>review</td>
+ <td>Clarifying overload resolution for the second step of copy-initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1674">1674</a></td>
+ <td>drafting</td>
+ <td>Return type deduction for address of function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1675">1675</a></td>
+ <td>ready</td>
+ <td>Size limit for automatic array object</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1676">1676</a></td>
+ <td>drafting</td>
+ <td><TT>auto</TT> return type for allocation and deallocation functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677">1677</a></td>
+ <td>drafting</td>
+ <td>Constant initialization via aggregate initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1678">1678</a></td>
+ <td>NAD</td>
+ <td>Naming the type of an array of runtime bound</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1679">1679</a></td>
+ <td>NAD</td>
+ <td>Range-based <TT>for</TT> and array of runtime bound</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1680">1680</a></td>
+ <td>drafting</td>
+ <td>Including <TT>&lt;initializer_list&gt;</TT> for range-based <TT>for</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1681">1681</a></td>
+ <td>ready</td>
+ <td><I>init-capture</I>s and nested lambdas</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1682">1682</a></td>
+ <td>open</td>
+ <td>Overly-restrictive rules on function templates as allocation functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1683">1683</a></td>
+ <td>review</td>
+ <td>Incorrect example after <TT>constexpr</TT> changes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1684">1684</a></td>
+ <td>drafting</td>
+ <td>Static <TT>constexpr</TT> member functions for non-literal classes</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1685">1685</a></td>
+ <td>review</td>
+ <td>Value category of <TT>noexcept</TT> expression</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1686">1686</a></td>
+ <td>review</td>
+ <td>Which variables are &#8220;explicitly declared <TT>const</TT>?&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1687">1687</a></td>
+ <td>drafting</td>
+ <td>Conversions of operands of built-in operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1688">1688</a></td>
+ <td>NAD</td>
+ <td>Volatile <TT>constexpr</TT> variables</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1689">1689</a></td>
+ <td>drafting</td>
+ <td>Syntactic nonterminal for operand of <TT>alignas</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1690">1690</a></td>
+ <td>ready</td>
+ <td>Associated namespace for local type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1691">1691</a></td>
+ <td>ready</td>
+ <td>Argument-dependent lookup and opaque enumerations</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1692">1692</a></td>
+ <td>ready</td>
+ <td>Associated namespaces of doubly-nested classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1693">1693</a></td>
+ <td>drafting</td>
+ <td>Superfluous semicolons in class definitions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1694">1694</a></td>
+ <td>review</td>
+ <td>Restriction on reference to temporary as a constant expression</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1695">1695</a></td>
+ <td>drafting</td>
+ <td>Lifetime extension via <I>init-capture</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1696">1696</a></td>
+ <td>open</td>
+ <td>Temporary lifetime and non-static data member initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1697">1697</a></td>
+ <td>drafting</td>
+ <td>Lifetime extension and copy elision</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1698">1698</a></td>
+ <td>open</td>
+ <td>Files ending in <TT>\</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1699">1699</a></td>
+ <td>drafting</td>
+ <td>Does befriending a class befriend its friends?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1700">1700</a></td>
+ <td>NAD</td>
+ <td>Does the special rvalue-reference deduction apply to alias templates?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701">1701</a></td>
+ <td>drafting</td>
+ <td>Array vs sequence in object representation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1702">1702</a></td>
+ <td>drafting</td>
+ <td>Rephrasing the definition of &#8220;anonymous union&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1703">1703</a></td>
+ <td>NAD</td>
+ <td>Language linkage of names of functions with internal linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1704">1704</a></td>
+ <td>drafting</td>
+ <td>Type checking in explicit instantiation of variable templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1705">1705</a></td>
+ <td>review</td>
+ <td>Unclear specification of &#8220;more specialized&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1706">1706</a></td>
+ <td>open</td>
+ <td><TT>alignas</TT> pack expansion syntax</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1707">1707</a></td>
+ <td>drafting</td>
+ <td><TT>template</TT> in <I>elaborated-type-specifier</I> without <I>nested-name-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1708">1708</a></td>
+ <td>drafting</td>
+ <td>overly-strict requirements for names with C language linkage</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1709">1709</a></td>
+ <td>drafting</td>
+ <td>Stringizing raw string literals containing newline</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1710">1710</a></td>
+ <td>drafting</td>
+ <td>Missing <TT>template</TT> keyword in <I>class-or-decltype</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1711">1711</a></td>
+ <td>open</td>
+ <td>Missing specification of variable template partial specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1712">1712</a></td>
+ <td>drafting</td>
+ <td><TT>constexpr</TT> variable template declarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">1713</a></td>
+ <td>open</td>
+ <td>Linkage of variable template specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1714">1714</a></td>
+ <td>drafting</td>
+ <td>odr-use of <TT>this</TT> from a local class</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1715">1715</a></td>
+ <td>drafting</td>
+ <td>Access and inherited constructor templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1716">1716</a></td>
+ <td>drafting</td>
+ <td>When are default arguments evaluated?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1717">1717</a></td>
+ <td>ready</td>
+ <td>Missing specification of type of binary literal</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1718">1718</a></td>
+ <td>open</td>
+ <td>Macro invocation spanning end-of-file</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1719">1719</a></td>
+ <td>open</td>
+ <td>Layout compatibility and cv-qualification revisited</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1720">1720</a></td>
+ <td>NAD</td>
+ <td>Macro invocation in <TT>#include</TT> directive</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1721">1721</a></td>
+ <td>drafting</td>
+ <td>Diagnosing ODR violations for static data members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1722">1722</a></td>
+ <td>drafting</td>
+ <td>Should lambda to function pointer conversion function be <TT>noexcept</TT>?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1723">1723</a></td>
+ <td>drafting</td>
+ <td>Multicharacter user-defined character literals</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1724">1724</a></td>
+ <td>drafting</td>
+ <td>Unclear rules for deduction failure</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1725">1725</a></td>
+ <td>NAD</td>
+ <td>Trailing return type with nested function declarator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1726">1726</a></td>
+ <td>drafting</td>
+ <td>Declarator operators and conversion function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1727">1727</a></td>
+ <td>NAD</td>
+ <td>Type of a specialization of a variable template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1728">1728</a></td>
+ <td>drafting</td>
+ <td>Type of an explicit instantiation of a variable template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1729">1729</a></td>
+ <td>drafting</td>
+ <td>Matching declarations and definitions of variable templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1730">1730</a></td>
+ <td>drafting</td>
+ <td>Can a variable template have an unnamed type?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1731">1731</a></td>
+ <td>NAD</td>
+ <td><TT>is_trivially_</TT><I>X</I> and definitions of special member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1732">1732</a></td>
+ <td>drafting</td>
+ <td>Defining types in <I>condition</I>s and range-based <TT>for</TT> statements</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1733">1733</a></td>
+ <td>drafting</td>
+ <td>Return type and value for <TT>operator=</TT> with <I>ref-qualifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1734">1734</a></td>
+ <td>drafting</td>
+ <td>Nontrivial deleted copy functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1735">1735</a></td>
+ <td>drafting</td>
+ <td>Out-of-range literals in <I>user-defined-literal</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1736">1736</a></td>
+ <td>drafting</td>
+ <td>Inheriting constructor templates in a local class</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1737">1737</a></td>
+ <td>drafting</td>
+ <td>Type dependence of call to a member of the current instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1738">1738</a></td>
+ <td>drafting</td>
+ <td>Explicit instantiation/specialization of inheriting constructor templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1739">1739</a></td>
+ <td>drafting</td>
+ <td>Conversion of floating point to enumeration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1740">1740</a></td>
+ <td>ready</td>
+ <td>Disambiguation of <TT>noexcept</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1741">1741</a></td>
+ <td>ready</td>
+ <td>odr-use of class object in lvalue-to-rvalue conversion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1742">1742</a></td>
+ <td>open</td>
+ <td><I>using-declaration</I>s and scoped enumerators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1743">1743</a></td>
+ <td>open</td>
+ <td><I>init-capture</I>s in nested lambdas</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1744">1744</a></td>
+ <td>open</td>
+ <td>Unordered initialization for variable template specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1745">1745</a></td>
+ <td>open</td>
+ <td><TT>thread_local constexpr</TT> variable</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1746">1746</a></td>
+ <td>open</td>
+ <td>Are volatile scalar types trivially copyable?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1747">1747</a></td>
+ <td>open</td>
+ <td>Constant initialization of reference to function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1748">1748</a></td>
+ <td>open</td>
+ <td>Placement new with a null pointer</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1749">1749</a></td>
+ <td>open</td>
+ <td>Confusing definition for constant initializer</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1750">1750</a></td>
+ <td>open</td>
+ <td>&#8220;Argument&#8221; vs &#8220;parameter&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1751">1751</a></td>
+ <td>open</td>
+ <td>Non-trivial operations vs non-trivial initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1752">1752</a></td>
+ <td>open</td>
+ <td>Right-recursion in <I>mem-initializer-list</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1753">1753</a></td>
+ <td>open</td>
+ <td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1754">1754</a></td>
+ <td>open</td>
+ <td>Declaration of partial specialization of static data member template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1755">1755</a></td>
+ <td>open</td>
+ <td>Out-of-class partial specializations of member templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1756">1756</a></td>
+ <td>open</td>
+ <td>Direct-list-initialization of a non-class object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1757">1757</a></td>
+ <td>open</td>
+ <td>Const integral subobjects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1758">1758</a></td>
+ <td>open</td>
+ <td>Explicit conversion in copy/move list initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1759">1759</a></td>
+ <td>drafting</td>
+ <td>UTF-8 code units in plain <TT>char</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1760">1760</a></td>
+ <td>ready</td>
+ <td>Access of member corresponding to <I>init-capture</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1761">1761</a></td>
+ <td>ready</td>
+ <td>Runtime check on size of automatic array</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1762">1762</a></td>
+ <td>ready</td>
+ <td>Reserved identifier used in <I>literal-operator-id</I> example</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1763">1763</a></td>
+ <td>open</td>
+ <td>Length mismatch in template type deduction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1764">1764</a></td>
+ <td>ready</td>
+ <td>Hiding of function from using-declaration by signature</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1765">1765</a></td>
+ <td>ready</td>
+ <td>Overflow of enumeration used as enumerator value</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1766">1766</a></td>
+ <td>open</td>
+ <td>Values outside the range of the values of an enumeration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1767">1767</a></td>
+ <td>ready</td>
+ <td>Scoped enumeration in a <TT>switch</TT> statement</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1768">1768</a></td>
+ <td>ready</td>
+ <td>Zero-element array of runtime bound</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1769">1769</a></td>
+ <td>review</td>
+ <td>Catching a base class of the exception object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1770">1770</a></td>
+ <td>ready</td>
+ <td>Type matching of non-type template parameters and arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1771">1771</a></td>
+ <td>open</td>
+ <td>Restricted lookup in <I>nested-name-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1772">1772</a></td>
+ <td>ready</td>
+ <td><TT>__func__</TT> in a lambda body</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1773">1773</a></td>
+ <td>ready</td>
+ <td>Out-of-lifetime lvalue-to-rvalue conversion</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1774">1774</a></td>
+ <td>open</td>
+ <td>Discrepancy between subobject destruction and stack unwinding</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1775">1775</a></td>
+ <td>ready</td>
+ <td>Undefined behavior of line splice in raw string literal</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1776">1776</a></td>
+ <td>open</td>
+ <td>Replacement of class objects containing reference members</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1777">1777</a></td>
+ <td>open</td>
+ <td>Empty pack expansion in <I>dynamic-exception-specification</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1778">1778</a></td>
+ <td>ready</td>
+ <td><I>exception-specification</I> in explicitly-defaulted functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1779">1779</a></td>
+ <td>open</td>
+ <td>Type dependency of <TT>__func__</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1780">1780</a></td>
+ <td>open</td>
+ <td>Explicit instantiation/specialization of generic lambda <TT>operator()</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1781">1781</a></td>
+ <td>open</td>
+ <td>Converting from <TT>nullptr_t</TT> to <TT>bool</TT> in overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1782">1782</a></td>
+ <td>open</td>
+ <td>Form of initialization for <TT>nullptr_t</TT> to <TT>bool</TT> conversion</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1783">1783</a></td>
+ <td>open</td>
+ <td>Why are virtual destructors non-trivial?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1784">1784</a></td>
+ <td>concurrency</td>
+ <td>Concurrent execution during static local initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1785">1785</a></td>
+ <td>open</td>
+ <td>Conflicting diagnostic requirements for template definitions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1786">1786</a></td>
+ <td>drafting</td>
+ <td>Effect of merging allocations on memory leakage</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1787">1787</a></td>
+ <td>drafting</td>
+ <td>Uninitialized <TT>unsigned char</TT> values</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1788">1788</a></td>
+ <td>open</td>
+ <td>Sized deallocation of array of non-class type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1789">1789</a></td>
+ <td>open</td>
+ <td>Array reference vs array decay in overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1790">1790</a></td>
+ <td>open</td>
+ <td>Ellipsis following function parameter pack</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1791">1791</a></td>
+ <td>open</td>
+ <td>Incorrect restrictions on <I>cv-qualifier-seq</I> and <I>ref-qualifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1792">1792</a></td>
+ <td>open</td>
+ <td>Incorrect example of explicit specialization of member enumeration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1793">1793</a></td>
+ <td>open</td>
+ <td><TT>thread_local</TT> in explicit specializations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1794">1794</a></td>
+ <td>open</td>
+ <td><TT>template</TT> keyword and alias templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1795">1795</a></td>
+ <td>open</td>
+ <td>Disambiguating <I>original-namespace-definition</I> and <I>extension-namespace-definition</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+</table>
+
+</div>
+</body>
+</html>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index ff6ec8a0ce23..d4c8878b6238 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -25,7 +25,7 @@
<!--*************************************************************************-->
<h1>C++98, C++11, and C++14 Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2013-05-21 02:28:07 +0200 (Tue, 21 May 2013) $</p>
+<p>Last updated: $Date: 2013-11-28 01:33:42 +0100 (Thu, 28 Nov 2013) $</p>
<h2 id="cxx98">C++98 implementation status</h2>
@@ -49,7 +49,7 @@ C++11 features accepted as extensions. You can use Clang in C++11 mode with the
with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++, but
patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
work with Clang in C++11 mode. Patches are also needed to make
-<a href="libstdc++4.6-clang11.patch">libstdc++-4.6</a>,
+<a href="libstdc++4.6-clang11.patch">libstdc++-4.6</a>
and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang
releases prior to version 3.2 in C++11 mode. <tt>thread_local</tt> support
currently requires g++-4.8's C++ runtime library.</p>
@@ -179,7 +179,7 @@ currently requires g++-4.8's C++ runtime library.</p>
<tr>
<td>Generalized attributes</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf">N2761</a></td>
- <td class="svn" align="center">Clang 3.3 <a href="#n2761">(1)</a></td>
+ <td class="full" align="center">Clang 3.3 <a href="#n2761">(1)</a></td>
</tr>
<tr>
<td>Generalized constant expressions</td>
@@ -189,7 +189,7 @@ currently requires g++-4.8's C++ runtime library.</p>
<tr>
<td>Alignment support</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf">N2341</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<!-- Skipped N1627: Conditionally-support behavior -->
<!-- Skipped N1727: Changing Undefined Behavior into Diagnosable Errors -->
@@ -201,7 +201,7 @@ currently requires g++-4.8's C++ runtime library.</p>
<tr>
<td>Inheriting constructors</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">N2540</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<tr>
<td>Explicit conversion operators</td>
@@ -308,7 +308,7 @@ currently requires g++-4.8's C++ runtime library.</p>
<tr>
<td>Sequence points</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html">N2239</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<tr>
<td>Atomic operations</td>
@@ -354,7 +354,7 @@ currently requires g++-4.8's C++ runtime library.</p>
<tr>
<td>Thread-local storage</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm">N2659</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<tr>
<td>Dynamic initialization and destruction with concurrency</td>
@@ -401,10 +401,10 @@ ABI-incompatible change.</span>
<h2 id="cxx14">C++1y implementation status</h2>
-<p>Clang is introducing support for the upcoming C++ language standard,
-provisionally named C++1y. The following table describes which C++1y features
-have been implemented in Clang and in which Clang version they became
-available.</p>
+<p>Clang implements all of the
+<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf">current draft</a>
+of the upcoming C++ language standard, provisionally named C++1y. The following
+table describes the Clang version in which each feature became available.</p>
<p>You can use Clang in C++1y mode with the <code>-std=c++1y</code> option.</p>
@@ -417,7 +417,7 @@ available.</p>
<tr>
<td>Tweak to certain C++ contextual conversions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3323.pdf">N3323</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Binary literals</td>
@@ -426,48 +426,93 @@ available.</p>
</tr>
<tr>
<td>decltype(auto)</td>
- <td rowspan=2 style="vertical-align:middle"><a href="http://isocpp.org/files/papers/N3638.html">N3638</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td rowspan=2 style="vertical-align:middle"><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3638.html">N3638</a></td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<tr>
<td>Return type deduction for normal functions</td>
- <td class="partial" align="center">Partial</td>
- </tr>
- <tr>
- <td>Runtime-sized arrays with automatic storage duration</td>
- <td><a href="http://isocpp.org/files/papers/N3639.html">N3639</a></td>
- <td class="partial" align="center">Partial</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Initialized lambda captures</td>
- <td><a href="http://isocpp.org/files/papers/N3648.html">N3648</a></td>
- <td class="none" align="center">No</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3648.html">N3648</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Generic lambdas</td>
- <td><a href="http://isocpp.org/files/papers/N3649.html">N3649</a></td>
- <td class="partial" align="center">
- No [<a href="https://github.com/faisalv/clang-glambda">WIP</a>]</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3649.html">N3649</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Variable templates</td>
- <td><a href="http://isocpp.org/files/papers/N3651.pdf">N3651</a></td>
- <td class="none" align="center">No</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3651.pdf">N3651</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Relaxing requirements on constexpr functions</td>
- <td><a href="http://isocpp.org/files/papers/N3652.html">N3652</a></td>
- <td class="partial" align="center">Partial</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html">N3652</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Member initializers and aggregates</td>
- <td><a href="http://isocpp.org/files/papers/N3653.html">N3653</a></td>
- <td class="svn" align="center">Clang 3.3</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html">N3653</a></td>
+ <td class="full" align="center">Clang 3.3</td>
</tr>
<tr>
<td>Clarifying memory allocation</td>
- <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html">-->N3664<!--</a>--></td>
- <td class="full" align="center">Yes</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html">N3664</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><tt>[[deprecated]]</tt> attribute</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html">N3760</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Single quotation mark as digit separator</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf">N3781</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>C++ Sized Deallocation</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3778.html">N3778</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+</table>
+
+<!--
+<h2 id="cxx17">C++1z implementation status</h2>
+
+<p>Clang implements none of the upcoming C++ language standard,
+provisionally named C++1z. The following table describes which C++1z features
+have been implemented in Clang and in which Clang version they became
+available.</p>
+
+<p>You can use Clang in C++1z mode with the <code>-std=c++1z</code> option.</p>
+-->
+
+<h2 id="ts">Technical specifications and standing documents</h2>
+
+<p>ISO C++ also publishes a number of documents describing additional language
+and library features that are not part of standard C++. The following table
+describes which language features have been implemented in Clang and in which
+Clang version they became available:</p>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Document</th>
+ <th>Latest draft</th>
+ <th>Available in Clang?</th>
+ </tr>
+ <tr>
+ <td>SD-6: SG10 feature test recommendations</td>
+ <td><a href="http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations">SD-6</a></td>
+ <td class="svn" align="center">SVN (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3745">N3745</a>)</td>
+ </tr>
+ <tr>
+ <td>[DRAFT TS] Array extensions (arrays of runtime bound)</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3820.html">N3820</a></td>
+ <td class="none" align="center">No</td>
</tr>
</table>
diff --git a/www/diagnostics.html b/www/diagnostics.html
index 84c6f8bc320c..bd9a89d62979 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -313,7 +313,7 @@ and also shows how some of the other pieces work in a bigger example.</p>
t.c:80:3: <span class="err">error:</span> invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
<span class="snip"> X = MYMAX(P, F);</span>
<span class="point"> ^~~~~~~~~~~</span>
- t.c:76:94: note: instantiated from:
+ t.c:76:94: note: expanded from:
<span class="snip">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a &lt; __b ? __b : __a; })</span>
<span class="point"> ~~~ ^ ~~~</span>
</pre>
@@ -326,10 +326,10 @@ implements the "wwopen" class of APIs):</p>
t.c:22:2: <span class="warn">warning:</span> type specifier missing, defaults to 'int'
<span class="snip"> ILPAD();</span>
<span class="point"> ^</span>
- t.c:17:17: note: instantiated from:
+ t.c:17:17: note: expanded from:
<span class="snip">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</span>
<span class="point"> ^</span>
- t.c:14:2: note: instantiated from:
+ t.c:14:2: note: expanded from:
<span class="snip"> register i; \</span>
<span class="point"> ^</span>
</pre>
diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status
new file mode 100755
index 000000000000..4750e1b2cbb0
--- /dev/null
+++ b/www/make_cxx_dr_status
@@ -0,0 +1,172 @@
+#! /usr/bin/env python
+import sys, os, re
+
+index = 'cwg_index.html'
+output = 'cxx_dr_status.html'
+dr_test_dir = '../test/CXX/drs'
+
+if len(sys.argv) == 1:
+ pass
+elif len(sys.argv) == 2:
+ index = sys.argv[1]
+else:
+ print >>sys.stderr, 'Usage: make_drs [<path to cwg_index.html>]'
+ sys.exit(1)
+
+class DR:
+ def __init__(self, section, issue, url, status, title):
+ self.section, self.issue, self.url, self.status, self.title = \
+ section, issue, url, status, title
+ def __repr__(self):
+ return '%s (%s): %s' % (self.issue, self.status, self.title)
+
+def parse(dr):
+ section, issue_link, status, title = [
+ col.split('>', 1)[1].split('</TD>')[0]
+ for col in dr.split('</TR>', 1)[0].split('<TD')[1:]
+ ]
+ _, url, issue = issue_link.split('"', 2)
+ url = url.strip()
+ issue = int(issue.split('>', 1)[1].split('<', 1)[0])
+ title = title.replace('<issue_title>', '').replace('</issue_title>', '').strip()
+ return DR(section, issue, url, status, title)
+
+status_re = re.compile(r'\bdr([0-9]+): (.*)')
+status_map = {}
+for test_cpp in os.listdir(dr_test_dir):
+ if not test_cpp.endswith('.cpp'):
+ continue
+ test_cpp = os.path.join(dr_test_dir, test_cpp)
+ found_any = False;
+ for match in re.finditer(status_re, file(test_cpp, 'r').read()):
+ status_map[int(match.group(1))] = match.group(2)
+ found_any = True
+ if not found_any:
+ print >> sys.stderr, "warning:%s: no '// dr123: foo' comments in this file" % test_cpp
+
+drs = sorted((parse(dr) for dr in file(index, 'r').read().split('<TR>')[2:]),
+ key = lambda dr: dr.issue)
+out_file = file(output, 'w')
+
+print >> out_file, '''\
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Clang - C++ Defect Report Status</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <style type="text/css">
+ .none { background-color: #FFCCCC }
+ .partial { background-color: #FFE0B0 }
+ .svn { background-color: #FFFF99 }
+ .full { background-color: #CCFF99 }
+ .na { background-color: #DDDDDD }
+ .open * { color: #AAAAAA }
+ //.open { filter: opacity(0.2) }
+ span:target { background-color: #FFFFBB; outline: #DDDD55 solid thin; }
+ th { background-color: #FFDDAA }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>C++ Defect Report Support in Clang</h1>
+<!--*************************************************************************-->
+<p>Last updated: $Date$</p>
+
+<h2 id="cxxdr">C++ defect report implementation status</h2>
+
+<p>This page tracks which C++ defect reports are implemented within Clang.</p>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Number</th>
+ <th>Status</th>
+ <th>Issue title</th>
+ <th>Available in Clang?</th>
+ </tr>'''
+
+def availability(issue):
+ status = status_map.get(issue, 'unknown')
+ avail_suffix = ''
+ if status.endswith(' c++11'):
+ status = status[:-6]
+ avail_suffix = ' (C++11 onwards)'
+ if status == 'unknown':
+ avail = 'Unknown'
+ avail_style = ' class="none"'
+ elif status == '3.4':
+ avail = 'SVN'
+ avail_style = ' class="svn"'
+ elif status in ('3.1', '3.2', '3.3'):
+ avail = 'Clang %s' % status
+ avail_style = ' class="full"'
+ elif status == 'yes':
+ avail = 'Yes'
+ avail_style = ' class="full"'
+ elif status == 'partial':
+ avail = 'Partial'
+ avail_style = ' class="partial"'
+ elif status == 'no':
+ avail = 'No'
+ avail_style = ' class="none"'
+ elif status == 'na':
+ avail = 'N/A'
+ avail_style = ' class="na"'
+ elif status.startswith('sup '):
+ dup = status.split(' ', 1)[1]
+ avail = 'Superseded by %s' % dup
+ try:
+ _, avail_style = availability(int(dup))
+ except:
+ print >>sys.stderr, "issue %s marked as sup %s" % (issue, dup)
+ avail_style = ' class="none"'
+ elif status.startswith('dup '):
+ dup = int(status.split(' ', 1)[1])
+ avail = 'Duplicate of %s' % dup
+ _, avail_style = availability(dup)
+ else:
+ assert False, 'unknown status %s for issue %s' % (status, dr.issue)
+ return (avail + avail_suffix, avail_style)
+
+count = {}
+for dr in drs:
+ if dr.status in ('concepts',):
+ # Yeah, cool story bro.
+ continue
+ if dr.status in ('open', 'concurrency', 'drafting', 'review', 'extension'):
+ # We may have to deal with these some day, but not yet.
+ row_style = ' class="open"'
+ avail = 'Not resolved'
+ avail_style = ''
+ assert dr.issue not in status_map, "have status for not-ready dr %s" % dr.issue
+ else:
+ row_style = ''
+ avail, avail_style = availability(dr.issue)
+ if not avail.startswith('Sup') and not avail.startswith('Dup'):
+ count[avail] = count.get(avail, 0) + 1
+
+ print >> out_file, '''\
+ <tr%s>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/%s">%s</a></td>
+ <td>%s</td>
+ <td>%s</td>
+ <td%s align="center">%s</td>
+ </tr>''' % (row_style, dr.url, dr.issue, dr.status, dr.title, avail_style,
+ avail)
+
+for status, num in count.items():
+ print "%s: %s" % (status, num)
+
+print >> out_file, '''\
+</table>
+
+</div>
+</body>
+</html>'''
diff --git a/www/menu.html.incl b/www/menu.html.incl
index 4a36614b909f..438299146856 100644
--- a/www/menu.html.incl
+++ b/www/menu.html.incl
@@ -2,7 +2,7 @@
<div>
<a href="http://llvm.org/">LLVM Home</a>
</div>
-
+
<div class="submenu">
<label>Clang Info</label>
<a href="/index.html">About</a>
@@ -23,13 +23,13 @@
<a href="/docs/InternalsManual.html">Clang&nbsp;Internals</a>
<a href="/hacking.html">Hacking on Clang</a>
</div>
-
+
<div class="submenu">
<label>Clang Tools</label>
<a href="http://clang-analyzer.llvm.org">Automatic Bug-Finding</a>
<a href="/docs/Tooling.html">Writing Clang Tools</a>
</div>
-
+
<div class="submenu">
<label>Communication</label>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-users">cfe-users List</a>
@@ -49,14 +49,14 @@
<div class="submenu">
<label>Quick Links</label>
- <a href="http://test.minormatter.com/~ddunbar/clang-cov/">Testing Coverage</a>
- <a href="http://test.minormatter.com/~ddunbar/references.html">Spec. References</a>
+ <a href="http://buildd-clang.debian.net/coverage/">Testing Coverage</a>
</div>
-
+
<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/2010-11/">November 2010</a>
+ <a href="http://llvm.org/devmtg/">LLVM events</a>
</div>
</div>
diff --git a/www/related.html b/www/related.html
index a1ff79b67de2..8191daabb17d 100644
--- a/www/related.html
+++ b/www/related.html
@@ -31,10 +31,7 @@
http://wiki.freebsd.org/BuildingFreeBSDWithClang</a>
</p>
<p>
- This is an effort to get FreeBSD to build with clang/llvm. Clang is a
- compiler built on the Low Level Virtual Machine compiler
- infrastructure. Both clang and llvm are released under a BSD like
- license.
+ This is an effort to get FreeBSD to build with clang/llvm.
</p>
</dd>
@@ -49,6 +46,42 @@
Notes on using Clang to build the Chromium web browser.
</p>
</dd>
+
+ <dt>Debian Clang Page</dt>
+ <dd>
+ <p>
+ <b>Sites:</b><br />
+ <a href="http://clang.debian.net/">http://clang.debian.net/</a><br />
+ <a href="http://wiki.debian.org/llvm-clang">
+ http://wiki.debian.org/llvm-clang</a>
+ </p>
+ <p>
+ Notes on using Clang to rebuild the whole Debian archive.
+ </p>
+ </dd>
+
+ <dt>Include what you use</dt>
+ <dd>
+ <p>
+ <b>Site:</b>
+ <a href="http://code.google.com/p/include-what-you-use/">http://code.google.com/p/include-what-you-use/</a>
+ </p>
+ <p>
+ Analyze #includes in C and C++ source files
+ </p>
+ </dd>
+
+ <dt>OCLint</dt>
+ <dd>
+ <p>
+ <b>Site:</b>
+ <a href="http://oclint.org/">http://oclint.org/</a>
+ </p>
+ <p>
+ OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code.
+ </p>
+ </dd>
+
</dl>
</div>
</body>